1. 程式人生 > 其它 >(轉載) freertos任務切換xPortPendSVHandler

(轉載) freertos任務切換xPortPendSVHandler

版權宣告:本文為CSDN博主「John.Ma」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/u011727389/article/details/84547586

FreeRTOS版本:FreeRTOS V8.2.3

 1 void xPortPendSVHandler( void )
 2 {
 3     /* This is a naked function. */
 4  
 5         /*__asm__(彙編語句模板: 輸出部分: 輸入部分: 破壞描述部分)
 6         /*共四個部分:彙編語句模板,輸出部分,輸入部分,破壞描述部分,各部分使用":"格開,
7 /*彙編語句模板必不可少,其他三部分可選,如果使用了後面的部分,而前面部分為空, 8 /*也需要用":"格開,相應部分內容為空. __asm volatile("...." : : "i"());破壞描述部分沒 9 /*用,i表示立即數,官方文件網址 10      /*https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html 11 */ 12 __asm volatile 13 ( 14 " mrs r0, psp \n" //
將psp值放到r0,此時sp得值為msp 15 " isb \n" 16 " \n" 17 " ldr r3, pxCurrentTCBConst \n" /* Get the location of the current TCB. */ 18 //將pxCurrentTCBConst標籤(指標變數pxCurrentTCB的記憶體地址為&pxCurrentTCB或者到map看)放到r3,此時r3=&pxCurrentTCB
19 " ldr r2, [r3] \n" //將r3暫存器值作為指標取內容存到r2,此時r2儲存的為任務控制塊首地址 20 " \n" 21 " stmdb r0!, {r4-r11} \n" /* Save the remaining registers. */ 22 //r0暫存器地址減去4在將r11-r4依次入棧r0(此時r0為程式棧psp地址)-4地址後 23 " str r0, [r2] \n" /* Save the new top of stack into the first member of the TCB. */ 24 //將r0(psp)值放到r2內容(pxCurrentTCBConst)所指的地址 25 " \n" 26 " stmdb sp!, {r3, r14} \n" //sp暫存器地址減去4在將r14,r3依次入棧sp-4地址後 27 " mov r0, %0 \n" //獲取中斷優先順序到r0,%0對應後面的configMAX_SYSCALL_INTERRUPT_PRIORITY 28 " msr basepri, r0 \n" //遮蔽低於優先順序的中斷 29 " bl vTaskSwitchContext \n" //跳到任務切換c函式,找到下一個任務控制塊 30 " mov r0, #0 \n" 31 " msr basepri, r0 \n" //開中斷 32 " dmia sp!, {r3, r14} \n" //從sp中取出r3,r14 33 " \n" /* Restore the context, including the critical nesting count. */ 34 " ldr r1, [r3] \n" //將r3(存放的是任務控制塊指標變數的地址&pxCurrentTCB)暫存器內容作為地址取內容放到r1(此時r1為新的任務控制塊地址) 35 " ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. */ 36 //將r1暫存器內容作為地址取內容放到r0(此時r0為新任務的pxTopOfStack) 37 " ldmia r0!, {r4-r11} \n" /* Pop the registers. */ 38 //將新的任務堆疊頂指標出堆疊到r4-r11 39 " msr psp, r0 \n" //將新的任務堆疊頂指標放到psp 40 " isb \n" 41 " bx r14 \n" //之後硬體會自動把PC指標出堆疊(因為此時psp為新任務的堆疊頂指標所以出堆疊也是新任務的暫存器) 42 " \n" 43 " .align 2 \n" 44 "pxCurrentTCBConst: .word pxCurrentTCB \n" 45 ::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY) 46 ); 47 }

 

               圖1 兩個任務切換時堆疊儲存分佈情況

 

                 圖2 由任務2(task2)切換到任務1(idle)暫存器及記憶體變化

 

其中memory1列的是棧頂指標開始往上增長對應圖1就是壓棧方向儲存情況,結合圖1可以看出xPSR、PC指標的值,切換的過程是先將任務2的堆疊儲存,找到要切換的任務1的任務控制塊,將堆疊指標更新到psp中,然後出棧時,硬體會自動出棧R0-R3、R12、LR、PC、xPSR暫存器(此時出棧暫存器psp內容已經是任務1的內容了)任務切換完成後出棧PC指標就更新為切換後的任務函式值
————————————————