找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3618|回复: 0
打印 上一主题 下一主题
收起左侧

STM32移植uCOS-II笔记

[复制链接]
跳转到指定楼层
楼主
ID:85681 发表于 2015-7-15 02:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
首先从st公司的网站下载最新的stm32标准外设库3.5 ,再从micrium网站上下载官方移植版本(编译器使用ARM/Keil的,V2.86版本,V2.85有问题),然后就是我们MDK建立工程了,工程结构组织如下:

其中  uCOSII_core 是uCOS的内核文件,与平台无关,所以无需修改。
在移植
uCOS-II时我们只需要关注  uCOSII_port 中三个文件和stm32f10x_it.c就可以了:
第一个文件就是 os_cpu.h
1.  
定义与编译器相关的数据类型,无需修改
typedef unsigned char   BOOLEAN;

typedef unsigned char    INT8U;                    /* Unsigned  8 bit quantity                           */
typedef signed   char      INT8S;                    /* Signed    8 bit quantity                           */
typedef unsigned short  INT16U;                   /* Unsigned 16 bit quantity                           */
typedef signed   short     INT16S;                   /* Signed   16 bit quantity                           */
typedef unsigned int       INT32U;                   /* Unsigned 32 bit quantity                           */
typedef signed   int         INT32S;                   /* Signed   32 bit quantity                           */
typedef float                     FP32;                     /* Single precision floating point                    */
typedef double                FP64;                     /* Double precision floating point                    */
typedef unsigned int      OS_STK;                   /* Each stack entry is 32-bit wide                    */
typedef unsigned int      OS_CPU_SR;                /* Define size of CPU status register (PSR = 32 bits) */

2.  因为CM3是32位宽的,所以OS_STK(堆栈的数据类型)被类型重定义为unsigned int。  因为CM3的状态寄存器(xPSR)是32位宽的,因此OS_CPU_SR被类型重定义为unsigned int。OS_CPU_SR是在OS_CRITICAL_METHOD方法3中保存cpu状态寄存器用的。在CM3中,移植OS_ENTER_CRITICAL(),OS_EXIT_CRITICAL()选方法3是最合适的。
#define  OS_CRITICAL_METHOD   3
typedef unsigned int OS_STK;
  typedef unsigned int OS_CPU_SR;

3.  μC/OS-II定义了三种方法关闭和打开中断 (OS_CRITICAL_METHED=1,2,3),通常情况下,我们都是选用的方法3,这里定义了两个宏来禁止和允许中断
#if OS_CRITICAL_METHOD == 3
#define  OS_ENTER_CRITICAL()  {cpu_sr = OS_CPU_SR_Save();}
#define  OS_EXIT_CRITICAL()      {OS_CPU_SR_Restore(cpu_sr);}
#endif     
具体定义宏OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL(),其中OS_CPU_SR_Save() //关中断
和OS_CPU_SR_Restore() //开中断
是用汇编代码写的,代码在os_cpu_a.asm中。

4.  
定义栈的增长方向
#define  OS_STK_GROWTH        1
置OS_STK_GROWTH为0,表示堆栈从下往上增长;置OS_STK_GROWTH为1,表示堆栈从上往下增长。

5.  
定义OS_TASK_SW()宏,任务级上下文切换
#define  OS_TASK_SW()         OSCtxSw()
任务级上下文切换(即任务切换)调用宏定义OS_TASK_SW()。因为上下文切换跟处理器有密切关系,OS_TASK_SW()实质上是调用汇编函数OSCtxSW() ,它在os_cpu_a.asm 文件中定义。

6.  注释掉如下函数,并添加void  PendSV_Handler(void)的函数声明
#if OS_CRITICAL_METHOD == 3                    
OS_CPU_SR  OS_CPU_SR_Save(void);
void       OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
#endif


void       OSCtxSw(void);
void       OSIntCtxSw(void);
void       OSStartHighRdy(void);
void       PendSV_Handler(void);


// void         OS_CPU_PendSVHandler(void);                                             
// void         OS_CPU_SysTickHandler(void);
// void         OS_CPU_SysTickInit(void);                                                
// INT32U     OS_CPU_SysTickClkFreq(void);
申明几个函数,这里要注意最后四个函数需要注释掉,为什么呢?  
OS_CPU_SysTickHandler()定义在os_cpu_c.c中,是SysTick中断的中断处理函数,而stm32f10x_it.c,中已经有该中断函数的定义SysTick_Handler(),这里也就不需要了。
OS_CPU_SysTickInit()定义在os_cpu_c.c中,用于初始化SysTick定时器,它依赖于OS_CPU_SysTickClkFreq(),而此函数我们自己会实现,所以注释掉。  
OS_CPU_SysTickClkFreq()定义在BSP.C (Micrium\Software\EvalBoards)中,而本文移植中并未用到BSP.C,后面我们会自己实现,因此可以把它注释掉。
OS_CPU_PendSVHandler()在启动文件上,一般我们自己开发基于stm32芯片的软件,都会使用标准外设库CMSIS中提供的启动文件,而官方移植的启动文件却是自己写的,在两个文件init.s,vectors.s中 (Micrium\Software\EvalBoards\ST\STM3210B-EVAL\RVMDK)。init.s负责进入main(),vectors.s设置中断向量。OS_CPU_SysTickHandler和OS_CPU_PendSVHandler就是在vectors.s中被设置的。  我的移植是使用标准外设库CMSIS中startup_stm32f10x_md.s作为启动文件的,那该怎么在这个文件中设置OS_CPU_SysTickHandler呢,事实上在startup_stm32f10x_md .s文件中,PendSV中断向量名为PendSV_Handler,所以只需用PendSV_Handler把所有出现OS_CPU_PendSVHandler 的地方替换掉就可以了。
我们有提到在
startup_stm32f10x_md .s中我们有定义PendSV_Handler,其中PendSV_Handler函数在我们CM3中也有实现,就在stm32f10x_it.c和stm32f10x_it.h中,现在我们选择使用uCOS的PendSV_Handler函数,所以应该将stm32f10x_it.c和stm32f10x_it.h中的PendSV_Handler函数注释起来。



第二个文件就是 os_cpu_c.c
1.   ucosii移植时需要我们写10个相当简单的C函数。
OSInitHookBegin()
OSInitHookEnd()
OSTaskCreateHook()
OSTaskDelHook()
OSTaskIdleHook()
OSTaskStatHook()
OSTaskStkInit()
OSTaskSwHook()
OSTCBInitHook()
OSTimeTickHook()
这些函数除了OSTaskStkInit(),都是一些hook函数。这些hook函数如果不使能的话,都不会用上,也都比较简单,看看就应该明白了,所以就不介绍.
OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt)
{
    OS_STK *stk;
    (void)opt;                                   /* 'opt' is not used, prevent warning                 */
    stk       = ptos;                            /* Load stack pointer                                 */
                                                       /* Registers stacked as if auto-saved on exception    */
    *(stk)    = (INT32U)0x01000000L;             /* xPSR                                               */
    *(--stk)  = (INT32U)task;                    /* Entry Point                                        */
    *(--stk)  = (INT32U)0xFFFFFFFEL;           /* R14 (LR) (init value will cause fault if ever used)*/
    *(--stk)  = (INT32U)0x12121212L;             /* R12                                                */
    *(--stk)  = (INT32U)0x03030303L;             /* R3                                                 */
    *(--stk)  = (INT32U)0x02020202L;             /* R2                                                 */
    *(--stk)  = (INT32U)0x01010101L;             /* R1                                                 */
    *(--stk)  = (INT32U)p_arg;                         /* R0 : argument                                      */
                                                                       /* Remaining registers saved on process stack         */
    *(--stk)  = (INT32U)0x11111111L;             /* R11                                                */
    *(--stk)  = (INT32U)0x10101010L;             /* R10                                                */
    *(--stk)  = (INT32U)0x09090909L;             /* R9                                                 */
    *(--stk)  = (INT32U)0x08080808L;             /* R8                                                 */
    *(--stk)  = (INT32U)0x07070707L;             /* R7                                                 */
    *(--stk)  = (INT32U)0x06060606L;             /* R6                                                 */
    *(--stk)  = (INT32U)0x05050505L;             /* R5                                                 */
    *(--stk)  = (INT32U)0x04040404L;             /* R4                                                 */


    return (stk);
}
xPSR,PC,LR,R12,R3-R0被自动保存到栈中的,R11-R4如果需要保存,只能手工保存。因此OSTaskStkInit()的工作就是在任务自己的栈中保存cpu的所有寄存器。这些值里R1-R12都没什么意义,这里用相应的数字代号(如R1用0x01010101)主要是方便调试.
其他的几个函数都可以空着,例如:
#if (OS_CPU_HOOKS_EN > 0) && (OS_TASK_SW_HOOK_EN > 0)
void  OSTaskSwHook (void)
{
#if OS_APP_HOOKS_EN > 0
    App_TaskSwHook();
#endif
}
#endif

2. 注释掉其中的一些内容
把OS_CPU_SysTickHandler(), OS_CPU_SysTickInit()注释掉。  

把上面这些宏定义也注释掉,因为它们都用于OS_CPU_SysTickHandler(),  OS_CPU_SysTickInit()。

第三个文件就是我们前面提到过的
os_cpu_a.asm
在os_cpu_a.asm中定义了4个与处理器相关的汇编函数,我们是从micrium网站上下载官方移植版本,所以其中的函数都已经实现了,如果需要了解的可以参照 《Cortex-M3权威指南》。
我们在注释掉os_cpu.h中的OS_CPU_PendSVHandler() 提到需用PendSV_Handler把所有出现OS_CPU_PendSVHandler 的地方替换掉,而这些需要替换掉的内容就在os_cpu_a.asm中,只需将下面的地方替换就好了


第四个文件就是我们的 stm32f10x_it.c
在前面修改os_cpu.h 文件时注释过一个
OS_CPU_SysTickHandler()是因为这个函数是提供系统时钟中断的,而在我们CM3中已经有了自己的系统时钟中断函数,就是 stm32f10x_it.c 的void SysTick_Handler(void),在这里只需要把OS_CPU_SysTickHandler() 的内容复制给SysTick_Handler()即可(记得把头文件包含进来 ):



到这里为止我们的移植就算是完成了,接下来任务就是在app.c文件中实现我们的测试程序了
#include "includes.h"


static OS_STK task_led1_stk[LED1_TASK_STK_SIZE];


static void systick_init(void)
{
RCC_ClocksTypeDef rcc_clock;
RCC_GetClocksFreq(&rcc_clock);
SysTick_Config(rcc_clock.HCLK_Frequency/OS_TICKS_PER_SEC);
}


void LED1_Tast(void *p_arg)
{
p_arg=p_arg;


while(1)
{
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_RESET);
OSTimeDlyHMSM(0, 0,1,0);
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET);
OSTimeDlyHMSM(0, 0,1,0);
}

int main(void)
{
BSP_Init();
OSInit();
systick_init();
OSTaskCreate(LED1_Tast,( void *)0,&task_led1_stk[LED1_TASK_STK_SIZE-1],LED1_TASK_PRIO);
OSStart();
return 0;
}

如果LED灯出现闪烁的话就大功告成了!








分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表