您的位置:首页 > 其它

ucosii在stm32上的移植详解4

2013-04-17 15:21 417 查看
作者:michaelyue526

来自:/article/9546358.html

详解3中有一个问题还没解释,就是stm32f10x_it.c中已经有SysTick中断函数的定义SysTick_Handler(),为什么官方版非要弄个OS_CPU_SysTickHandler()。答案就在启动文件上,一般我们自己开发基于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_hd.s作为启动文件的,那该怎么在这个文件中设置OS_CPU_SysTickHandler呢,事实上在startup_stm32f10x_hd.s文件中,PendSV中断向量名为PendSV_Handler,所以只需用OS_CPU_PendSVHandler把所有出现PendSV_Handler的地方替换掉就可以了。

那么为什么OS_CPU_SysTickHandler不用这种方式处理呢,这样也就不用注释os_cpu.c中的OS_CPU_SysTickHandler(),这主要是基于两个原因:

1. startup_stm32f10x_hd.s尽量少该,能不改就不改。

2. 如果保留OS_CPU_SysTickHandler(),在以后开发过程中,改动OS_CPU_SysTickHandler()中的内容可能性是非常大的,如果一不小把该文件其他部分改了造成了问题,这个bug就非常难查了,所以我一般移植好后就把ucosii的这些文件设置为只读。

对于上面的原因1,一开始移植时,我曾做过在PendSV_Handler()中调用OS_CPU_PendSVHandler(),后来发现这样不行,这是为什么呢?问题出在LR寄存器上。

PendSV_Handler()

{

OS_CPU_PendSVHandler();

}

汇编出来的代码会是这样:

PendSV_Handler PROC

PUSH {r4,lr}

BL OS_CPU_PendSVHandler

POP {r4,pc}

ENDP

这样在进入OS_CPU_PendSVHandler之后,LR寄存器中存放的是指令POP {r4,pc}的地址+1。在OS_CPU_PendSVHandler中的ORR LR, LR, #0x04就不会起作用,也就无法使用PSP,移植因此失败。其实在AN-1018.pdf的3.04.06中也有强调OS_CPU_PendSVHandler必须被放置在中断向量表中。一开始我也没注意。

到这里移植的大部分工作都做完了,下面剩下的就是把工程配置好,SysTick中断处理好。

在工程中建立ucosii组,把ucosii下的文件都加进该组。这里别忘了把os_cpu_a.asm加入。

在工程的Options中,c/c++选项卡的Include Paths中添加.\src\ucosii\src;.\src\ucosii\port。

编译工程,会发现缺少app_cfg.h和os_cfg.h文件,app_cfg.h是用来配置应用软件的,主要是任务的优先级和堆栈大小,中断优先级等信息。目前还没有基于ucosii开发应用软件,所以只需在include文件夹中创建一个空的app_cfg.h文件即可。os_cfg.h是用来配置ucosii系统的。拷贝Micrium\Software\EvalBoards\ST\STM3210B-EVAL\RVMDK\OS-Probe\os_cfg.h到template\include,对其做如下修改:

#define OS_APP_HOOKS_EN 0

#define OS_DEBUG_EN 0

#define OS_EVENT_MULTI_EN 0

#define OS_SCHED_LOCK_EN 0

#define OS_TICK_STEP_EN 0

#define OS_TASK_CHANGE_PRIO_EN 0

#define OS_TASK_QUERY_EN 0

#define OS_TASK_STAT_EN 0

#define OS_TASK_STAT_STK_CHK_EN 0

#define OS_TASK_SUSPEND_EN 0

#define OS_FLAG_EN 0

#define OS_MBOX_EN 0

#define OS_TIME_DLY_HMSM_EN 0

#define OS_TIME_DLY_RESUME_EN 0

#define OS_TIME_GET_SET_EN 0

#define OS_TIME_TICK_HOOK_EN 0

所做的修改主要是把一些功能给去掉,减少内核大小,也利于调试。等移植完成后,如果需要该功能,再做开启。

接下来就剩下处理好SysTick中断和启动任务了。SysTick是系统的“心跳”,本质上来说就是一个定时器。先把原来main.c中的内容删除,添加如下代码:

#include "ucos_ii.h"

#include "stm32f10x.h"

static OS_STK startup_task_stk[STARTUP_TASK_STK_SIZE];

static void systick_init(void)

{

RCC_ClocksTypeDef rcc_clocks;

RCC_GetClocksFreq(&rcc_clocks);

SysTick_Config(rcc_clocks.HCLK_Frequency / OS_TICKS_PER_SEC);

}

static void startup_task(void *p_arg)

{

systick_init(); /* Initialize the SysTick. */

#if (OS_TASK_STAT_EN > 0)

OSStatInit(); /* Determine CPU capacity. */

#endif

/* TODO: create application tasks here */

OSTaskDel(OS_PRIO_SELF);

}

int main(void)

{

OSInit();

OSTaskCreate(startup_task, (void *)0,

&startup_task_stk[STARTUP_TASK_STK_SIZE - 1],

STARTUP_TASK_PRIO);

OSStart();

return 0;

}

systick_init()用来初始化并启动SysTick定时器。

RCC_GetClocksFreq()用来获取系统时钟。

SysTick_Config()初始化并使能SysTick定时器。

这里要注意的是OS_TICKS_PER_SEC,它是每秒钟的ticks数,如果为1000,就是1s中1000个ticks,也就是说1ms就会产生一个SysTick中断。系统的时间片为1ms。

在邵老师的书中3.11节已有明确说明,必须在调用OSStart()之后,才能开启时钟节拍器(SysTick)。一般会把它放在第一个任务(启动任务)中。

startup_task()用来创建其他应用任务,创建完其他任务后,就会自己删除自己。

文件中的STARTUP_TASK_STK_SIZE,STARTUP_TASK_PRIO需要在app_cfg.h中定义。代码如下:

/* task priority */

#define STARTUP_TASK_PRIO 4

/* task stack size */

#define STARTUP_TASK_STK_SIZE 80

在stm32f10x_it.c中,还需要添加SysTick中断的处理代码:

void SysTick_Handler(void)

{

OSIntEnter();

OSTimeTick();

OSIntExit();

}

这个代码是仿照OS_CPU_SysTickHandler()中代码的,在邵老师书的3.11节亦有说明。这里就不解释。

至此ucosii在stm32上的移植已全部完成。

转载请注明出处:http://blog.csdn.net/lbl1234
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: