STM32
直播中

陈燕

7年用户 1084经验值
私信 关注
[问答]

移植UCOSII操作系统的过程中都做了哪些工作

在UCOSII移植过程中有哪些重要文件呢?
移植UCOSII的过程中都做了哪些工作?

回帖(1)

杜茂仁

2021-11-30 15:53:19
1、滴答定时器SysTick

滴答定时器是一个24位的倒计数定时器,当计到0时,将从RELOAD寄存器中自动重装载定时器初值,只要不把它在systick控制以及状态寄存器中的使能位清零,就将永久不息。systick的最大使命,就是定期地产生异常请求作为系统的时基。OS都需要这种“滴答”来推动任务和时间的管理
我们在移植UCOSII的过程中就要使用滴答定时器来作为系统时钟,首先就是对滴答定时器的设置,主要是设置它的定时周期,在delay_init()函数中完成滴答定时器设置,delay_init()函数代码如下。





其中红色代码部分就是在使用UCOSII时配置systick的代码,如果SYSTEM_SUPPORT_UCOS被定义了就说明使用了UCOS操作系统,那么我们就需要配置systick。首先要根据UCOSII中的定义的OS_TICKS_PER_SEC来计算出systick的装载值reload开启systick中断将reload值写进systick的LOAD寄存器中,最后开启systick。
开启systick后还要编写systick的中断服务函数SysTick_Handler(),函数代码如下,同样也采用了条件编译。










2、os_cpu.a.asm文件详解






上面代码分为两部分,上半部分使用IMPORT来定义,下半部分使用EXPORT来定义。IMPORT定义表示这是一个外部变量的标号,不是在本程序定义的(可以理解为导入);EXPORT定义表示这些函数是在本文件中定义的,供其他文件调用(可以理解为导出)。





EQU和C语言中的#define一样,定义一个宏。NVIC_INT_CTRL为中断控制寄存器,地址为0xE000ED04;NVIC_SYSPRI2为系统优先级寄存器,地址为0xE000ED22;NVIC_PENDSV_PRI为PendSv和systick的中断优先级,这里为0xFFFF,都为最低优先级;NVIC_PENDSVSET可以触发软件中断,通过给中断控制寄存器(NVIC_INT_CTRL)的bit28写1来触发软件中断,因此NVIC_PENDSVSET为0x10000000.





OS_CPU_SR_Save和OS_CPU_SR_Restore是开关中断的汇编代码,通过给PRIMASK写1来关中断,写0来打开中断。这里也可以使用CPS指令来快速的开关中断,我们在OS_CPU_SR_Save中就使用了CPSID I来关中断。





OSStartHighRdy是由OSStart()调用,用来开启多任务的,如果多任务开启失败的话就会进入OSStartHang。





OSCtxSw和OSIntCtxSw这两个是用来做任务切换的,这两个看起来都是一样的,其实他们都只是触发一个PendSv中断,具体的切换过程在PendSv中断服务函数里面进行。这两个函数看起来一样,但他们的意义是不同的,OSCtxSw是任务级切换,比如从任务A切换到任务B,OSIntCtxSw是中断级切换,是从中断退出时切换到一个任务中,从中断切换到任务时,CPU的寄存器入栈工作已经完成,无需做第二次。










上面的汇编代码才是真正的任务切换程序,在每行代码后面都有详细的注释,为了更好的理解我们对代码打标号的地方重点讲解一下。
① 如果PSP为0的话说明是第一次做任务切换,而任务创建的时候会调用堆栈初始化函数OSTaskStkInit()来初始化堆栈,在初始化的过程中做了入栈处理,所以这里就不需要在做入栈处理,直接跳转到PendSv_Handler_Nosave.
② 此时SP指向的就是要运行的最高优先级的任务。
③ 因为进入中断使用的是MSP,而退出中断的时候使用的是PSP,因此这里需要将LR的位2置1.
在UCOSII移植的时候说过要屏蔽stm32f10x.it.c文件中的PendSv_Handler()中断服务函数,原因就是我们在os_cpu_a.asm中重新定义了PendSv_Handler()函数,我们有时候在移植的时候可能会发现有OS_CPU_PendSVHandler这样的函数,其实就是官方移植使用到的,具体作用和PendSv_Handler一样都是PendSv的中断服务函数,不过ST官方启动文件startup_stm32f10x.hd.s中定义的PendSv中断服务函数为PendSv_Handler,所以说如果要使用OS_CPU_PendSVHandler作为PendSv的中断服务函数就需要修改启动文件startup_stm32f10x_hd.s中的中断向量表。
3、os_cpu.h文件详解






上面代码主要是定义了一些数据类型,在这里我们一定要注意OS_STK这个数据类型,我们在定义任务堆栈的时候就是定义OS_STK类型的,这是一个32的数据类型,按字节来算的话实际堆栈大小是我们定义的4倍










上面代码中我们定义了堆栈的增长方向,任务级切换的宏定义OS_TASK_SW。如果OS_CRITICAL_METHOD被定义为3的话那么进出临界段的宏定义分别为OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL(),他们都是由汇编编写的。
4、os_cpu_c.c文件详解

os_cpu_c.c文件里面主要定义了几个钩子函数,这里我们就不具体讲解这些钩子函数了,我们主要来看一下OSTaskStkInit()这个函数,OSTaskStkInit()是堆栈初始化函数,该函数代码如下。





堆栈初始化函数OSTaskStkInit()是由任务创建函数OSTaskCreate()和OSTaskCreateExt()这两个函数调用的,用于在创建任务的时候初始化堆栈,从上面的代码中可以看出就是在任务堆栈中保存寄存器的值
这里一定要注意入栈的顺序,硬件会自动将FPSCR, xPSR, PC, LR, R12, R0-R3这些寄存器入栈,这几个寄存器的入栈顺序我们在讲Stack frame的时候已经讲了。剩下的R4-R11就需要我们手动入栈了
关于这几个文件的详细内容,参考源码。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分