详解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上的移植已悉数完结。