350 likes | 538 Views
Porting uC/OS-II to XSBase255. Presenter:Wytai. Date:06/04. Outline. Introduction Porting overview OS_CPU.h OS_CPU_A.asm OS_CPU_C.c Conclusion. Introduction. Preparation uC/OS-II source code http://www.micrium.com/ V.2.86 Porting file http://www.micrium.com/ V.1.50 ADS or GNU
E N D
Porting uC/OS-II to XSBase255 Presenter:Wytai Date:06/04 /
Outline • Introduction • Porting overview • OS_CPU.h • OS_CPU_A.asm • OS_CPU_C.c • Conclusion /
Introduction • Preparation • uC/OS-II source code http://www.micrium.com/ • V.2.86 • Porting file http://www.micrium.com/ • V.1.50 • ADS or GNU • Hardware • XSBase255 • Hardware Spec • Compiler Spec • ARM assembly knowing /
Introduction • Porting = bootloader + OS • Bootloader • Initialize hardware, vectors, memory, stack, register value • There are two ways • 分開成兩個檔案(bin),bootloader裡面要設定OS Image存放的位址(OS入口),需要兩者一致方可成功啟動OS • 合成一個bin檔,在bootloader執行完以後,透過跳轉__main進入OS入口 /
Introduction • Hardware limit • 處理器的C 編譯器能產生可重入程式碼。 • 用C 語言就可以打開和關閉中斷。 • 處理器支援中斷,並且能產生定時中斷(通常在10 至100Hz 之間)。 • 處理器支援能夠容納一定數量的資料的硬體堆疊(可能是幾千位元組)。 • 處理器有將堆疊指標和其他CPU 暫存器讀出和存儲到堆疊或記憶體中的指令。 • Ex • Motorola 6805 : 4,5 /
Overview /
Overview • OS_CPU.h • Define some reg value and datatype • OS_CPU_A.asm • OSStartHighRdy() • OSCtwSw() • OSTickISR() • OSIntCtxSw() • OS_CPU_C.c • OSTaskStkInit()、OSTaskCreateHook()、OSTaskDelHook()、OSTaskSwHook()、OSTaskStatHook()、OSTimeTickHook() /
OS_CPU.h • Compiler dependent(請查看compiler手冊) • typedef unsigned char BOOLEAN; • typedef unsigned char INT8U; • typedef signed char INT8S; • typedef unsigned short INT16U; • typedef signed short INT16S; • typedef unsigned int INT32U; • typedef signed int INT32S; • typedef float FP32; • typedef double FP64; • typedef unsigned int OS_STK; /
OS_CPU.h • Processor dependent • #define OS_ENTER_CRITICAL() • {cpu_sr = OS_CPU_SR_Save();} • #define OS_EXIT_CRITICAL() • {OS_CPU_SR_Restore(cpu_sr);} • #define OS_STK_GROWTH 1 • #define OS_TASK_SW() OSCtxSw() /
OS_CPU_A.asm • 一般寫完bootloader後,常要觀察其與OS搭配後,是否可以順利進入OS • 為了往後可以測試task context switch 是否成功,因此建立2個task,不同的priority,分別進行不同動作,例如輸出不同字元(FFUART)或是使不同的led燈亮起(GPIO) • taskA priority 5 並在while迴圈中加入OStimedly • taskB priority 10並在while迴圈中加入OStimedly /
OS_CPU_A.asm • OSStartHighRdy() • 由於Osstart()後,會去執行schedule,並且挑出最高priority的task執行 • Pseudocode • void OSStartHighRdy (void) • { • Call user definable OSTaskSwHook(); • Get the stack pointer of the task to resume: • Stack pointer = OSTCBHighRdy->OSTCBStkPtr; • OSRunning = TRUE; • Restore all processor registers from the new task's stack; • Execute a return from interrupt instruction; • } /
OS_CPU_A.asm • OSStartHighRdy • Call user definable OSTaskSwHook(); • BL OSTaskSwHook • Stack pointer = OSTCBHighRdy->OSTCBStkPtr; • LDR R4, = OSTCBHighRdy • LDR R4, [R4] • LDR SP, [R4] • OSRunning = TRUE; • LDR R4, = OSRunning • MOV R5, #1 • STRB R5, [R4] /
OS_CPU_A.asm • Restore all processor registers from the new task's stack; • LDMFD SP!, {R4} • MSR CPSR_cxsf, R4 • Execute a return from interrupt instruction; • LDMFD SP!,{R0-R12, LR, PC} • 若是此函式完成後 • 可以觀察到taskA的動作 • 若是沒有預期動作,則表示先前的準備工作尚未全部完成 • Ex.bootloader、OS_CPU.h…… /
OS_CPU_A.asm • OSCtxSw() • 若是目前task ready queue中有更高priority的task,則使用此函式將目前正在執行的task與之交換 • Pseudo code • void OSCtxSw(void) • { • 保存處理器暫存器; • 將當前task 的堆疊指標保存到當前task 的OS_TCB 中: • OSTCBCur->OSTCBStkPtr = Stack pointer; • 呼叫使用者定義的OSTaskSwHook(); • OSTCBCur = OSTCBHighRdy; • OSPrioCur = OSPrioHighRdy; • 得到需要恢復的task 的堆疊指標: • Stack pointer = OSTCBHighRdy->OSTCBStkPtr; • 將所有處理器暫存器從新task 的堆疊中恢復出來; • 執行中斷返回指令; • } /
OS_CPU_A.asm • OSCtxSw • 保存處理器暫存器; • STR LR, [SP, #-4]! • STMFD SP!, {R0-R12, LR} • MRS R4, CPSR • STR R4, [SP, #-4]! • OSTCBCur->OSTCBStkPtr = Stack pointer; • LDR R4, =OSTCBCur • LDR R4, [R4] • STR SP, [R4] /
OS_CPU_A.asm • 呼叫使用者定義的OSTaskSwHook(); • BL OSTaskSwHook • OSTCBCur = OSTCBHighRdy; • LDR R4, = OSTCBCur • LDR R5, = OSTCBHighRdy • LDR R5, [R5] • STR R5, [R4] • OSPrioCur = OSTCBHighRdy; • LDR R4, = OSPrioCur • LDR R5, = OSTCBHighRdy • LDR R5, [R5] • STR R5, [R4] /
OS_CPU_A.asm • Stack pointer = OSTCBHighRdy->OSTCBStkPtr; • LDR R4, = OSTCBHighRdy • LDR R4, [R4] • LDR SP, [R4] • 將所有處理器暫存器從新task 的堆疊中恢復出來; • 執行中斷返回指令; • LDMFD SP!, {R4} • MSR CPSR_cxsf, R4 • LDMFD SP!,{R0-R12, LR, PC} • 此函式成功,則在taskA動作結束後,taskB會隨之動作 /
OS_CPU_A.asm • OSTickISR() • 此函式用來決定一個tick所需要的clock數,來實現time delay和系統時間前進的功能 • 而運行此函式還必須要初始化timer interrupt,此動作規定在OSStart()後較不會發生問題 • void main(void) • { • . • OSInit(); . • /* 應用程式初始化程式碼... */ • /* ... 呼叫OSTaskCreate() 建立至少一個task */ • . • 允許tick interrupt; /* 千萬不要在這裏允許! */ • . • OSStart(); /* 開始多工排程 */ • } /
OS_CPU_A.asm • 初始化timer interrupt的動作最好在priority最高的task中運行,如此可保證在OSStart()後緊接執行,不會有OS運行狀態不明的情形發生 • There are two ways • 專屬的task,運行後利用uC/OS-ii中的函示將該task lock,不再執行 • 在目前最高的priority的task中,初始的地方運行(不是在while迴圈中) /
OS_CPU_A.asm • Timer Registers • OSCR – 自動遞增的計數器 • OSMR0-3– 4個match的reg,一旦與OSCR match就發生中斷 • OIER– 當OSMR == OSCR時,允許OSSR設置flag • OSSR– 當OSMR == OSCR時,在對應的地方設置flag • Timerinitial • OSMRx=xxx • OSSR=0xffffffff • OIER = OIER_EO • OSCR = 0 or OSCR = OSCR + time interval /
OS_CPU_A.asm • Interrupt control • ICPR – 表示目前系統正發生中斷 • ICMR– 用來mask對應的中斷位元 • ICLP– 用來決定中斷是IRQ或是FIQ • ICIP– 標記發生IRQ的device • ICFP– 標記發生FIQ的device • Initial • ICMR 使之不mask OSMRx(對應位元 = 1) • ICLR 使之決定IRQ或是FIQ /
OS_CPU_A.asm • Pseudo Code • void OSTickISR(void) • { • 保存處理器暫存器; • 呼叫OSIntEnter() 或者直接將OSIntNesting 加1; • 呼叫OSTimeTick(); • 呼叫OSIntExit(); • 恢復處理器暫存器; • 執行中斷返回指令; • } /
OS_CPU_A.asm • Assumption • 皆已初始化timer和interrupt • 會自動去決定下一次tick應該在何時發生 • OSMR = OSCR + interval • OSSR 清除 /
OS_CPU_A.asm • OSTickISR • 保存處理器暫存器; • 呼叫OSIntEnter() 或者直接將OSIntNesting 加1; • BL OSIntEnter • 呼叫OSTimeTick(); • BL OSTimeTick • 呼叫OSIntExit(); • BL OSIntExit • 恢復處理器暫存器; • 執行中斷返回指令; • 此函式完成後,可以在此函式中加入輸出,若是此書出可以依照interval持續到來,表示成功 /
OS_CPU_A.asm • LDR R11, =osTimer_OSSR • MOV R4, #0xf • STR R4, [R11] • ;//enable timer interrupt • LDR R4, =int_ICMR • MOV R5, #0x04000000 • STR R5, [R4] • LDR R6, =osTimer_OSMR0 • LDR R7, =ChkTimeInterval • LDR R8, =osTimer_OSCR • LDR R9, [R8] • ADD R7, R7, R9 ;// OSCR + interval • STR R7, [R6] /
OS_CPU_A.asm • OSIntCtxSw() • 為了能在ISR中直接進行task切換,若是利用原本的方式,需要結束ISR後回到原本的task,再進行OSCtxSw,如此反應上較慢,稍不realtime • There are two ways • 調整SP到適當的位置 • 在此函式中僅設置旗標,離開OSIntExit後才根據旗標決定是否進行task 切換 /
OS_CPU_A.asm • Assumption • 在進行ISR之前就已將目前的狀態、data push進stack • OSIntCtxSw所處的mode最好與task執行的mode一致 /
OS_CPU_A.asm • Pseudo code • void OSIntCtxSw(void) • { • 調整SP • 將當前task 的堆疊指標保存到當前task 的OS_TCB 中: • OSTCBCur->OSTCBStkPtr = Stack pointer; • 呼叫使用者定義的OSTaskSwHook(); • OSTCBCur = OSTCBHighRdy; • OSPrioCur = OSPrioHighRdy; • 得到需要恢復的task 的堆疊指標: • Stack pointer = OSTCBHighRdy->OSTCBStkPtr; • 將所有處理器暫存器從新task 的堆疊中恢復出來; • 執行中斷返回指令; • } /
OS_CPU_A.asm • OSIntCtxSw • 由於僅有第一行與OSCtxSw不相同,因此在切換mode之後,可以直接呼叫OSCtxSw • SP調整 • 由於每個mode下都有各自的stack,並且在access其他mode的data會受到限制,加上每個task都有各自的stack,因此,mode和stack的關係要十分清楚,否則此處調整SP會有極大的機率造成錯誤 /
OS_CPU_A.asm • 若是要利用第2種方法(設旗標) • 則在OSIntCtxSw中 • 保存處理器暫存器; • LDR R4, =needCtxSw • MOV R5, #0x1 • STR R5, [R4] • 將所有處理器暫存器從新task 的堆疊中恢復出來; • 執行中斷返回指令; • 在TickISR中(在OSIntExit之後) • LDR R4, =needCtxSw • LDR R4, [R4] • CMP R4, #1 • BEQ OSCtxSw /
OS_CPU_C.c • OSTaskStkInit()、OSTaskCreateHook()、OSTaskDelHook()、OSTaskSwHook()、OSTaskStatHook()、OSTimeTickHook() • Hook主要用來進行功能擴展 • OSTaskStkInit() • 對於task stack進行初始化動作 /
Conclusion • OS_CPU.h 須查閱spec,並且在porting過程中需不斷加上新的變數值或是新的函式 • Bootloader在porting過程中也需要修改,例如加入新的handler以及加入新的中斷向量 • OSIntCtxSw 和 OSTickISR與暫存器的設置有關 • Mode • Stack /
Q & A • Thanks /