專注電子技術學習與研究
當前位置:單片機教程網(wǎng) >> STM32 >> 瀏覽文章

ucos 0S_CPU_A.ASM(STM32)

作者:佚名   來源:本站原創(chuàng)   點擊數(shù):  更新時間:2014年04月27日   【字體:

 IMPORT  OSRunning;參數(shù)指示內(nèi)核是否運行的布爾型變量

        IMPORT  OSPrioCur;參數(shù)當前任務的優(yōu)先級
        IMPORT  OSPrioHighRdy;參數(shù)優(yōu)先級最高任務的優(yōu)先級
        IMPORT  OSTCBCur;任務控制塊指針指向當前正在運行的任務
        IMPORT  OSTCBHighRdy;任務控制塊指針指向最高優(yōu)先級任務的任務控制塊
        IMPORT  OSIntNesting;參數(shù)保存中斷嵌套級
        IMPORT  OSIntExit;函數(shù)退出軟中斷進行任務切換
        IMPORT  OSTaskSwHook;勾函數(shù)任務切換時運行自己的函數(shù)
;IMPORT外部文件定義的引入供本文件使用(輸入)  
;下面是六個需要自己編寫的匯編函數(shù)
        EXPORT  OSStartHighRdy;運行優(yōu)先級最高的函數(shù)供OSstart調(diào)用               
        EXPORT  OSCtxSw;任務切換函數(shù)
        EXPORT  OSIntCtxSw;中斷結束時進行任務切換供OSintexit調(diào)用
EXPORT  OS_CPU_SR_Save;OS_ENTER_CRITICAL()進入臨界中斷
    EXPORT  OS_CPU_SR_Restore;OS_EXIT_CRITICAL()退出臨界中斷        
        EXPORT  PendSV_Handler;
;EXPORT本文件定義的供外部文件引用(輸出)   
     
NVIC_INT_CTRL   EQU     0xE000ED04  ; 中斷控制及狀態(tài)寄存器ICSR    P135
NVIC_SYSPRI2     EQU     0xE000ED22  ; 系統(tǒng)優(yōu)先級寄存器   P132*寫錯?ED22?好像兩個都可以
NVIC_PENDSV_PRI EQU     0xFFFF0000  ; PendSV中斷和系統(tǒng)節(jié)拍中斷
                                        ; (都為最低,0xff).
NVIC_PENDSVSET   EQU     0x10000000  ; 觸發(fā)軟件中斷的值.掛起PENDSV
 
 
PRESERVE8;保證8字節(jié)對齊 
AREA    |.text|, CODE, READONLY;只讀代碼
        THUMB;16位THUMB指令
    
           
 
;********************************************************************************************************
;                                   CRITICAL SECTION METHOD 3 FUNCTIONS
;
; Description: Disable/Enable interrupts by preserving the state of interrupts.  Generally speaking you
;              would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then
;              disable interrupts.  'cpu_sr' is allocated in all of uC/OS-II's functions that need to
;              disable interrupts.  You would restore the interrupt disable state by copying back 'cpu_sr'
;              into the CPU's status register.
;
; Prototypes :     OS_CPU_SR  OS_CPU_SR_Save(void);
;                  void       OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
;OS_CPU_SR 大小取決于CPU狀態(tài)寄存器大小32位
;
; Note(s)    : 1) These functions are used in general like this:
;
;                 void Task (void *p_arg)
;                 {
;                 #if OS_CRITICAL_METHOD == 3          
;                     OS_CPU_SR  cpu_sr;
;                 #endif
;
;                          :
;                          :
;                     OS_ENTER_CRITICAL();            
;                          :
;                          :
;                     OS_EXIT_CRITICAL();              
;                          :
;                          :
;                 }
;********************************************************************************************************
;0S_CPU_A.ASM(STM32)這倆個函數(shù)是進出中斷延用的就是防止任務切換時被意外打斷
;0S_CPU_A.ASM(STM32)沒啥特別的開關中斷返回。
OS_CPU_SR_Save
    MRS     R0, PRIMASK   ;讀取PRIMASK到R0,R0為返回值 
    CPSID   I ;PRIMASK=1,關中斷(NMI和硬件FAULT可以響應)屏蔽所有可屏蔽異常
    BX      LR    ;返回
 
OS_CPU_SR_Restore
    MSR     PRIMASK, R0   ;讀取R0到PRIMASK中,R0為參數(shù)
    BX      LR ;返回
 
 
;0S_CPU_A.ASM(STM32)這個函數(shù)是一開始啟動時用的,設置PENDSV優(yōu)先級最低,這樣只有在沒有其他異常(中斷,事件)運行下進行掛起。  
;PendSV可懸起系統(tǒng)調(diào)用確保任務切換不會打斷中斷
OSStartHighRdy
        LDR     R4, =NVIC_SYSPRI2      ; set the PendSV exception priority
        LDR     R5, =NVIC_PENDSV_PRI   ;設置系統(tǒng)服務優(yōu)先級為最低優(yōu)先級
        STR     R5, [R4]               ;只有在沒有其他異常的情況下才會觸發(fā)系統(tǒng)服務中斷進行上下文切換
;0S_CPU_A.ASM(STM32)R4寫零這樣第一次運行在PendSV_Handler中將調(diào)用nosave函數(shù),psp一開始為零如果保存psp-32將為不確定值,退出中斷后會跑飛。
        
        MOV     R4, #0                 ; set the PSP to 0 for initial context switch call
        MSR     PSP, R4                ;設置進程堆棧寄存器為0為初始化上下文切換指令
;0S_CPU_A.ASM(STM32)告訴系統(tǒng)ucos初始化完畢可以啟動了
        LDR     R4, =OSRunning         ; OSRunning = TRUE
        MOV     R5, #1                 ;
        STRB    R5, [R4]               ;STRB位傳送指令
 
;0S_CPU_A.ASM(STM32)STM32有PENDSV 任務切換是在PENDSV完成的,所以這里要觸發(fā)PENDSV                                      
        LDR     R4, =NVIC_INT_CTRL     ;rigger the PendSV exception (causes context switch)
        LDR     R5, =NVIC_PENDSVSET    ;懸起PENDSV觸發(fā)系統(tǒng)調(diào)用中斷進行任務調(diào)度
        STR     R5, [R4]
 
        CPSIE   I                      ;enable interrupts at processor level快速開中斷
 
;0S_CPU_A.ASM(STM32)這個函數(shù)就是告訴你出錯了,系統(tǒng)崩潰的都會到這里
OSStartHang
        B       OSStartHang            ;should never get here好吧,正常的程序是不會跑到這里的。
 
;0S_CPU_A.ASM(STM32)管他是中斷切換還是任務切換,要做的就是觸發(fā)PENDSV
OSCtxSw
PUSH    {R4, R5}                ;PUSH    {R4, R5,LR}   
        LDR     R4, =NVIC_INT_CTRL   ;觸發(fā)PendSV異常 (causes context switch)
        LDR     R5, =NVIC_PENDSVSET
        STR     R5, [R4]
POP     {R4, R5}                ;POP     {R4, R5,PC}改成這樣可以省略BX
        BX      LR
        ;BX跳轉(zhuǎn)并改變指令集
;
 
OSIntCtxSw
PUSH    {R4, R5}
        LDR     R4, =NVIC_INT_CTRL      ;觸發(fā)PendSV異常 (causes context switch)
        LDR     R5, =NVIC_PENDSVSET
        STR     R5, [R4]
POP     {R4, R5}
        BX      LR
        NOP
 
;0S_CPU_A.ASM(STM32)這個就是任務切換的地方了,不能被打斷,所以先關中斷
 
PendSV_Handler
    CPSID   I                                                   ; Prevent interruption         ;during context switch 關閉中斷防止在切換任務時打斷任務切換
;0S_CPU_A.ASM(STM32)硬件仿真的時候進中斷都是用MSP 所以保存還是有必要的。                                                         
    MRS     R0, PSP                                             ; PSP is process stack pointer 如 ;果在用PSP堆棧,則可以忽略保存寄存器,參考CM3權威中的雙堆棧-白菜注
    CBZ     R0, PendSV_Handler_Nosave                         ; Skip register save the first time
;0S_CPU_A.ASM(STM32)如果PSP的值為零則運行PendSV_Handler_Nosave
    SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack
;將PSP的值-32保存在R0 
    
    STM     R0, {R4-R11}                                        ;一個批量入棧操作將R4到R11全部保存在進程堆棧中地址保存在R0內(nèi)          
    ;MSR     MSP,R0                                             
    ;PUSH    {R4-R11}     
;0S_CPU_A.ASM(STM32) STM     R0, {R4-R11}   可以用上面兩句代替。上面一段把準備被切掉的函數(shù)的寄存器R4-R7都保存了。
;0S_CPU_A.ASM(STM32) 因為其他寄存器都是自動保存的所以不要管。
LDR     R1, =OSTCBCur                                       ; OSTCBCur->OSTCBStkPtr = SP
;將OSTCBCur指針的地址保存在R1中
    LDR     R1, [R1]
;從R1中的地址處讀數(shù)據(jù)讀到得就是OSTCBCur指針存儲在R1中 
    STR     R0, [R1]  ; R0 is SP of process being switched out  R0是當前進程堆棧的PSP指針即即將被切換任務的進程的PSP指針
;將R0中的數(shù)據(jù)(即PSP-32的值)存放在OSTCBCur指針指向的地址中
 
                                                                ; At this point, entire context of process has been saved
;0S_CPU_A.ASM(STM32)到這里進程的所有內(nèi)容都保存完畢保存了,包括R4-R11的值和舊的任務堆棧的PSP地址
;0S_CPU_A.ASM(STM32)這里郁悶了我好久,原來匯編沒有跳轉(zhuǎn)指令會按代碼順序一直運行下去。只要有運行PENDSV HANDLER,一定會運行NOSAVE.仿真時候發(fā)現(xiàn)的。
;0S_CPU_A.ASM(STM32)這里要調(diào)用一個C函數(shù),為了防止LR在C函數(shù)中被改必須要保存下。
PendSV_Handler_Nosave
    PUSH    {LR}                                               ; Save LR exc_return value
;將R14壓棧                                                  ;保存回調(diào)地址                               
    LDR     R0, =OSTaskSwHook                                   ; OSTaskSwHook();
;取勾函數(shù)名所在的地址
    BLX     R0
;0S_CPU_A.ASM(STM32)BLX 帶鏈接跳轉(zhuǎn)并切換指令集 用戶代碼都是ARM代碼
    POP     {R14}
    ;出棧
;0S_CPU_A.ASM(STM32)這一塊完成任務優(yōu)先級的變換,運行什么任務是OS判斷這個值決定的了。我之前一直以為這里會跳到將要
;0S_CPU_A.ASM(STM32)運行的任務
    LDR     R0, =OSPrioCur                                      ; OSPrioCur = OSPrioHighRdy
;將參數(shù)OSPrioCur的地址存在R0中  
    LDR     R1, =OSPrioHighRdy
;將參數(shù)OSPrioHighRdy的地址存放在R1中
    LDRB    R2, [R1]                                            ;R2中保存OSPrioHighRdy的值
;把R1地址中的數(shù)據(jù)取出來存在R2中
    STRB    R2, [R0]
    ;把R2中的數(shù)據(jù)存到R0地址對應的內(nèi)存空間
;0S_CPU_A.ASM(STM32)任務換了任務控制塊也要換了
    LDR     R0, =OSTCBCur                                       ; OSTCBCur  = OSTCBHighRdy;
    LDR     R1, =OSTCBHighRdy
    LDR     R2, [R1]                                            ;R2中保存的是OSTCBHighRdy這個指針
    STR     R2, [R0]
    ;同上
;0S_CPU_A.ASM(STM32)新的任務,有新的進程堆棧
    LDR     R0, [R2]                                            ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
;將R2地址中的數(shù)據(jù)存到R0中OSTCBHighRdy這個指針(將要運行任務的指針)
;0S_CPU_A.ASM(STM32)恢復新任務進程堆棧的值。
    LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack
                                                          ;將R4-R11寄存器的值恢復到新進程的堆棧下
   ;POP{R4-R11}                                                 
   ;可以用這句替換上句
    ADDS    R0, R0, #0x20                                       ;+32得到新的PSP地址                        
    MSR     PSP, R0                                             ; Load PSP with new process SP
;0S_CPU_A.ASM(STM32)最后把PSP指向新的堆棧位置
;0S_CPU_A.ASM(STM32)到這里又把PSP指針,和R4-R7重新恢復了                                                          ;0S_CPU_A.ASM(STM32)下面這句應該是為了防止意外吧,正常退出都會用PSP堆棧 
    ORR     LR, LR, #0x04                                       ; Ensure exception return uses process stack
;將LR的第二位置為1并保存到LR確保返回使用進程堆棧。
;0S_CPU_A.ASM(STM32)結束了,開中斷吧
    CPSIE   I                                                   ; 開中斷
;0S_CPU_A.ASM(STM32)記得跳轉(zhuǎn)
    BX      LR                                                  ; Exception return will restore remaining context
 
 end  
關閉窗口

相關文章