|
首先從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燈出現閃爍的話就大功告成了!
|
|