毕业设计之路(9)-ucosi操作系统移植到STM32
来源:互联网 发布:现在的淘宝店好做吗 编辑:程序博客网 时间:2024/05/17 20:34
这个工作主要是根据网友的经验资料来学习移植的。总的来说需要下面几个参考资料。
ARM Cortex-m3权威指南
官方移植文档资料
网友移植成功经验资料
这三种资料在我的资源上传里面都能找到。
我在官网上下的是官方已经移植好的到STM32F103评估板的资料,很多部分已经实现了,所以需要改动的地方很少,不同的地方可以参考第三种网友移植成功经验资料,里面有详细说明。我下的是ucosii2.86版本。
下面说说移植过程:
移植主要涉及到两个源文件,os_cpu_c.c和os_cpu_a.asm,os_cpu.h。其他文件是ucosii核心文件,不需要修改。还有两个配置文件app_cfg.h和os_cfg.h。
整个文件框架构成图如下,用的是IAR。
这就是对照上面的说明而设置的目录结构。
下面谈主要移植的部分。主要集中在os_cpu_a.asm这个文件中,os_cpu.h主要涉及到一些宏的配置。os_cpu_c.c中主要有一个函数必须写出,就是堆栈初始化函数。
先说os_cpu.h中需要注意的地方。
下面是开关中断的宏
#define OS_CRITICAL_METHOD 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
CM3堆栈方向高到底递减,设置为1,还有一个任务切换的宏。
#define OS_STK_GROWTH 1 /* Stack grows from HIGH to LOW memory on ARM */#define OS_TASK_SW() OSCtxSw()
还有几个关于systick的函数需要注释掉,下面的os_cpu_c.c会说道原因。
// /* See OS_CPU_C.C *///void OS_CPU_SysTickHandler(void);//void OS_CPU_SysTickInit(void);//// /* See BSP.C *///INT32U OS_CPU_SysTickClkFreq(void);
看os_cpu_c.c。
里面有些函数是钩子函数,根据需要写。如果不需要可以不写。
下面是堆栈初始化函数。
/*********************************************************************************************************** INITIALIZE A TASK'S STACK** Description: This function is called by either OSTaskCreate() or OSTaskCreateExt() to initialize the* stack frame of the task being created. This function is highly processor specific.** Arguments : task is a pointer to the task code** p_arg is a pointer to a user supplied data area that will be passed to the task* when the task first executes.** ptos is a pointer to the top of stack. It is assumed that 'ptos' points to* a 'free' entry on the task stack. If OS_STK_GROWTH is set to 1 then* 'ptos' will contain the HIGHEST valid address of the stack. Similarly, if* OS_STK_GROWTH is set to 0, the 'ptos' will contains the LOWEST valid address* of the stack.** opt specifies options that can be used to alter the behavior of OSTaskStkInit().* (see uCOS_II.H for OS_TASK_OPT_xxx).** Returns : Always returns the location of the new top-of-stack once the processor registers have* been placed on the stack in the proper order.** Note(s) : 1) Interrupts are enabled when your task starts executing.* 2) All tasks run in Thread mode, using process stack.**********************************************************************************************************/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);}
因为CM3支持的堆栈地址是从高到低递减的,所以里面都是--。而且CM3中断自动入栈顺序为xPSR,PC,R14,R12,R3~R0,这个可以参考CM3权威指南。所以放在前面。后面R11~R4需要我们手动入栈。最后返回栈顶指针。
OS_CPU_C.c中还有一些东西需要我们注释掉,因为官方的资料是根据评估板来写的,如果移植到我们有STM32固件库的平台上,则需要做些改变,这是参考网友移植经验知道的。这些需要注释掉的东西主要是跟systic这个定时器有关。
下面是需要注释掉的地方。
//void OS_CPU_SysTickInit (void)//{// INT32U cnts;////// cnts = OS_CPU_SysTickClkFreq() / OS_TICKS_PER_SEC;//// OS_CPU_CM3_NVIC_ST_RELOAD = (cnts - 1);// /* Enable timer. */// OS_CPU_CM3_NVIC_ST_CTRL |= OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC | OS_CPU_CM3_NVIC_ST_CTRL_ENABLE;// /* Enable timer interrupt. */// OS_CPU_CM3_NVIC_ST_CTRL |= OS_CPU_CM3_NVIC_ST_CTRL_INTEN;//}
//void OS_CPU_SysTickHandler (void)//{// OS_CPU_SR cpu_sr;////// OS_ENTER_CRITICAL(); /* Tell uC/OS-II that we are starting an ISR */// OSIntNesting++;// OS_EXIT_CRITICAL();//// OSTimeTick(); /* Call uC/OS-II's OSTimeTick() *///// OSIntExit(); /* Tell uC/OS-II that we are leaving the ISR *///}
//#define OS_CPU_CM3_NVIC_ST_CTRL (*((volatile INT32U *)0xE000E010)) /* SysTick Ctrl & Status Reg. *///#define OS_CPU_CM3_NVIC_ST_RELOAD (*((volatile INT32U *)0xE000E014)) /* SysTick Reload Value Reg. *///#define OS_CPU_CM3_NVIC_ST_CURRENT (*((volatile INT32U *)0xE000E018)) /* SysTick Current Value Reg. *///#define OS_CPU_CM3_NVIC_ST_CAL (*((volatile INT32U *)0xE000E01C)) /* SysTick Cal Value Reg. */////#define OS_CPU_CM3_NVIC_ST_CTRL_COUNT 0x00010000 /* Count flag. *///#define OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC 0x00000004 /* Clock Source. *///#define OS_CPU_CM3_NVIC_ST_CTRL_INTEN 0x00000002 /* Interrupt enable. *///#define OS_CPU_CM3_NVIC_ST_CTRL_ENABLE 0x00000001 /* Counter mode. */
os_cpu.c.c中需要注意到的地方差不多就是这些了。
下面是os_cpu_a.asm.这里面的东西最多了,也相对难理解,这就需要仔细看CM3权威指南这个资料了。
这是上面开关中断宏的汇编语言实现。
OS_CPU_SR_Save MRS R0, PRIMASK ; Set prio int mask to mask all (except faults) CPSID I BX LROS_CPU_SR_Restore MSR PRIMASK, R0 BX LR
启动最高优先级函数,只调用一次,在OSStart()中被调用。
;********************************************************************************************************; START MULTITASKING; void OSStartHighRdy(void);; Note(s) : 1) This function triggers a PendSV exception (essentially, causes a context switch) to cause; the first task to start.;; 2) OSStartHighRdy() MUST:; a) Setup PendSV exception priority to lowest;; b) Set initial PSP to 0, to tell context switcher this is first run;; c) Set OSRunning to TRUE;; d) Trigger PendSV exception;; e) Enable interrupts (tasks will run with interrupts enabled).;********************************************************************************************************OSStartHighRdy LDR R0, =NVIC_SYSPRI14 ; Set the PendSV exception priority LDR R1, =NVIC_PENDSV_PRI STRB R1, [R0] MOVS R0, #0 ; Set the PSP to 0 for initial context switch call MSR PSP, R0 LDR R0, =OSRunning ; OSRunning = TRUE MOVS R1, #1 STRB R1, [R0] LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch) LDR R1, =NVIC_PENDSVSET STR R1, [R0] CPSIE I ; Enable interrupts at processor levelOSStartHang B OSStartHang ; Should never get here
主要是手动悬起PendSV中断,设置OSRunning为1,然后开启中断之后好进入PendSV中断处理函数中进行任务切换,开始运行ucosii。PendSV这个是需要掌握的,才能理解CM3是如何实现操作系统的管理的。
下面是两个任务切换函数,一个是任务级间切换,一个是中断与任务间切换,虽然代码相同,但意义不同,这主要就跟上面说道的PendSV中断有关了。因为这个中断的存在,我们的任务切换中实现的主要工作就是触发PendSV中断,让这个中断去处理任务切换相关细节。
;********************************************************************************************************; PERFORM A CONTEXT SWITCH (From task level); void OSCtxSw(void);; Note(s) : 1) OSCtxSw() is called when OS wants to perform a task context switch. This function; triggers the PendSV exception which is where the real work is done.;********************************************************************************************************OSCtxSw LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch) LDR R1, =NVIC_PENDSVSET STR R1, [R0] BX LR;********************************************************************************************************; PERFORM A CONTEXT SWITCH (From interrupt level); void OSIntCtxSw(void);; Notes: 1) OSIntCtxSw() is called by OSIntExit() when it determines a context switch is needed as; the result of an interrupt. This function simply triggers a PendSV exception which will; be handled when there are no more interrupts active and interrupts are enabled.;********************************************************************************************************OSIntCtxSw LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch) LDR R1, =NVIC_PENDSVSET STR R1, [R0] BX LR
下面就是非常重要的PendSV中断处理函数了。
;********************************************************************************************************; HANDLE PendSV EXCEPTION; void OS_CPU_PendSVHandler(void);; Note(s) : 1) PendSV is used to cause a context switch. This is a recommended method for performing; context switches with Cortex-M3. This is because the Cortex-M3 auto-saves half of the; processor context on any exception, and restores same on return from exception. So only; saving of R4-R11 is required and fixing up the stack pointers. Using the PendSV exception; this way means that context saving and restoring is identical whether it is initiated from; a thread or occurs due to an interrupt or exception.;; 2) Pseudo-code is:; a) Get the process SP, if 0 then skip (goto d) the saving part (first context switch);; b) Save remaining regs r4-r11 on process stack;; c) Save the process SP in its TCB, OSTCBCur->OSTCBStkPtr = SP;; d) Call OSTaskSwHook();; e) Get current high priority, OSPrioCur = OSPrioHighRdy;; f) Get current ready thread TCB, OSTCBCur = OSTCBHighRdy;; g) Get new process SP from TCB, SP = OSTCBHighRdy->OSTCBStkPtr;; h) Restore R4-R11 from new process stack;; i) Perform exception return which will restore remaining context.;; 3) On entry into PendSV handler:; a) The following have been saved on the process stack (by processor):; xPSR, PC, LR, R12, R0-R3; b) Processor mode is switched to Handler mode (from Thread mode); c) Stack is Main stack (switched from Process stack); d) OSTCBCur points to the OS_TCB of the task to suspend; OSTCBHighRdy points to the OS_TCB of the task to resume;; 4) Since PendSV is set to lowest priority in the system (by OSStartHighRdy() above), we; know that it will only be run when no other exception or interrupt is active, and; therefore safe to assume that context being switched out was using the process stack (PSP).;********************************************************************************************************OS_CPU_PendSVHandler CPSID I ; Prevent interruption during context switch MRS R0, PSP ; PSP is process stack pointer CBZ R0, OS_CPU_PendSVHandler_nosave ; Skip register save the first time SUBS R0, R0, #0x20 ; Save remaining regs r4-11 on process stack STM R0, {R4-R11} LDR R1, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP; LDR R1, [R1] STR R0, [R1] ; R0 is SP of process being switched out ; At this point, entire context of process has been savedOS_CPU_PendSVHandler_nosave PUSH {R14} ; Save LR exc_return value LDR R0, =OSTaskSwHook ; OSTaskSwHook(); BLX R0 POP {R14} LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy; LDR R1, =OSPrioHighRdy LDRB R2, [R1] STRB R2, [R0] LDR R0, =OSTCBCur ; OSTCBCur = OSTCBHighRdy; LDR R1, =OSTCBHighRdy LDR R2, [R1] STR R2, [R0] LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr; LDM R0, {R4-R11} ; Restore r4-11 from new process stack ADDS R0, R0, #0x20 MSR PSP, R0 ; Load PSP with new process SP ORR LR, LR, #0x04 ; Ensure exception return uses process stack CPSIE I BX LR ; Exception return will restore remaining context END
下面的说的就是上面忽略的部分systick,作为操作系统的心脏,我们需要自己来组织这个中断。
在STM32库中的终端处理文件stm32f10x_it.c中有个Systick_Handler()函数,在里面添加处理。
/** * @brief This function handles SysTick Handler. * @param None * @retval None */void SysTick_Handler(void){OSIntEnter();OSTimeTick();OSIntExit();}
在主函数main.c中添加systick初始化函数
static void Systick_init(void){RCC_ClocksTypeDef rcc_clocks;RCC_GetClocksFreq(&rcc_clocks);SysTick_Config(rcc_clocks.HCLK_Frequency / OS_TICKS_PER_SEC);}
最后还有一个需要改动的就是要把STM32启动文件中的所有PendSV_Handler替换成OS_CPU_ PendSVHandler,因为UCOS默认移植文件中使用的是OS_CPU_ PendSVHandler。
- 毕业设计之路(9)-ucosi操作系统移植到STM32
- ucosi操作系统移植到STM32
- ucfs 移植到stm32
- FreeRTOS移植到STM32
- UC_COS移植到STM32
- stm32+CC3000移植到ucosii之外部中断服务函数
- MQTT客户端移植到STM32
- STM32到GD32移植攻略
- 12864移植到STM32平台
- stm32移植ecos,移植ucgui到ecos
- stm32 之 ucosii移植 手记
- Basic脚本解释器移植到STM32
- 单片机脚本语言-移植lua到stm32-MDK
- Basic脚本解释器移植到STM32
- ucosii移植到STM32-F0/F1/F2~~~~~~~~~
- CanOpen协议【CanFestival】移植到STM32
- 将Lua解释器移植到STM32
- uC/OS-III到STM32移植
- sizeof()于strlen()函数的区别
- 细说Cookie
- linux 下文件的路径
- Html/Jsp常用的页面跳转方法
- UVA11995----数据结构水题
- 毕业设计之路(9)-ucosi操作系统移植到STM32
- 配置和启用VPN远程访问服务
- Spring MVC的工作机制
- Linux下删除大量小文件
- (转)Android游戏开发之处理音乐与音效太鼓达人游戏原理(二十一)
- Flex中處理窗口大小變化
- IOS开发(5)之UISegmentedControl控件
- 两个简单例子揭示makefile中“=”和“:=”的区别
- c++开发小技巧