你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【安富莱STM32F407之uCOS-III教程】第9章 μCOS-III系统移植文...

[复制链接]
baiyongbin2009 发布时间:2014-12-22 16:52
阅读主题, 点击返回1楼
收藏 评论11 发布时间:2014-12-22 16:52
11个回答
baiyongbin2009 回答时间:2014-12-22 17:19:38
9.4.3      PendSV中断
    关于PendSV中断,我们在第4章和第5章已经非常详细的讲解了,这里主要是给大家分析一下任务切换的处理过程,这个中断函数的前面有英文的注释说的非常好,大家有必要看一下。
  1. ;********************************************************************************************************
  2. ;                                       HANDLE PendSV EXCEPTION
  3. ;                                   void OS_CPU_PendSVHandler(void)
  4. ;
  5. ; Note(s) : 1) PendSV is used to cause a context switch.  This is a recommended method for performing
  6. ;              context switches with Cortex-M3.  This is because the Cortex-M3 auto-saves half of the
  7. ;              processor context on any exception, and restores same on return from exception.  So only
  8. ;              saving of R4-R11 is required and fixing up the stack pointers.  Using the PendSV exception
  9. ;              this way means that context saving and restoring is identical whether it is initiated from
  10. ;              a thread or occurs due to an interrupt or exception.
  11. ;
  12. ;           2) Pseudo-code is:
  13. ;              a) Get the process SP, if 0 then skip (goto d) the saving part (first context switch);
  14. ;              b) Save remaining regs r4-r11 on process stack;
  15. ;              c) Save the process SP in its TCB, OSTCBCurPtr->OSTCBStkPtr = SP;
  16. ;              d) Call OSTaskSwHook();
  17. ;              e) Get current high priority, OSPrioCur = OSPrioHighRdy;
  18. ;              f) Get current ready thread TCB, OSTCBCurPtr = OSTCBHighRdyPtr;
  19. ;              g) Get new process SP from TCB, SP = OSTCBHighRdyPtr->OSTCBStkPtr;
  20. ;              h) Restore R4-R11 from new process stack;
  21. ;              i) Perform exception return which will restore remaining context.
  22. ;
  23. ;           3) On entry into PendSV handler:
  24. ;              a) The following have been saved on the process stack (by processor):
  25. ;                 xPSR, PC, LR, R12, R0-R3
  26. ;              b) Processor mode is switched to Handler mode (from Thread mode)
  27. ;              c) Stack is Main stack (switched from Process stack)
  28. ;              d) OSTCBCurPtr      points to the OS_TCB of the task to suspend
  29. ;                 OSTCBHighRdyPtr  points to the OS_TCB of the task to resume
  30. ;
  31. ;           4) Since PendSV is set to lowest priority in the system (by OSStartHighRdy() above), we
  32. ;              know that it will only be run when no other exception or interrupt is active, and
  33. ;              therefore safe to assume that context being switched out was using the process stack (PSP).
  34. ;********************************************************************************************************

  35. OS_CPU_PendSVHandler
  36.     CPSID   I                                           ; Prevent interruption during context switch
  37.     MRS     R0, PSP                                     ; PSP is process stack pointer
  38.     CBZ     R0, OS_CPU_PendSVHandler_nosave             ; Skip register save the first time

  39.     SUBS    R0, R0, #0x20                               ; Save remaining regs r4-11 on process stack
  40.     STM     R0, {R4-R11}

  41.     LDR     R1, =OSTCBCurPtr                            ; OSTCBCurPtr->OSTCBStkPtr = SP;
  42.     LDR     R1, [R1]
  43.     STR     R0, [R1]                                     ; R0 is SP of process being switched out

  44.                                                      ; At this point, entire context of process has been saved
  45. OS_CPU_PendSVHandler_nosave
  46.     PUSH    {R14}                                               ; Save LR exc_return value
  47.     LDR     R0, =OSTaskSwHook                                   ; OSTaskSwHook();
  48.     BLX     R0
  49.     POP     {R14}

  50.     LDR     R0, =OSPrioCur                                      ; OSPrioCur   = OSPrioHighRdy;
  51.     LDR     R1, =OSPrioHighRdy
  52.     LDRB    R2, [R1]
  53.     STRB    R2, [R0]

  54.     LDR     R0, =OSTCBCurPtr                                    ; OSTCBCurPtr = OSTCBHighRdyPtr;
  55.     LDR     R1, =OSTCBHighRdyPtr
  56.     LDR     R2, [R1]
  57.     STR     R2, [R0]

  58.     LDR     R0, [R2]                                            ; R0 is new process SP; SP = OSTCBHighRdyPtr->StkPtr;
  59.     LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack
  60.     ADDS    R0, R0, #0x20
  61.     MSR     PSP, R0                                             ; Load PSP with new process SP
  62.     ORR     LR, LR, #0x04                                       ; Ensure exception return uses process stack
  63.     CPSIE   I
  64.     BX      LR                                                  ; Exception return will restore remaining context

  65.     END
复制代码
    这里PendSV中断的主要作用就是保存当前任务的现场,恢复下一个任务的寄存器,从而切换到下一个任务中执行程序,并保证退出PendSV后使用的是PSP (任务堆栈指针)。下面先把这些汇编代码解释一下:
  1. OS_CPU_PendSVHandler                       ;xPSR, PC, LR, R12, R0-R3已自动保存入栈
  2. CPSID   I                                  ;任务切换期间需要关中断
  3. MRS     R0, PSP                            ;R0 = PSP
  4. CBZ     R0, OS_CPU_PendSVHandler_nosave    ;如果PSP==0跳转到OS_CPU_PendSVHandler_nosave去执行 在多任务
  5. ;的初始化时PSP被初始化为0,表示任务是第一次运行,不需要压栈

  6. /********************************将当前的任务寄存器入栈*********************************************/
  7. SUBS    R0, R0, #0x20        ;R0 -= 0x20 保存R4-R11到任务堆栈 共32个字节            
  8. STM     R0, {R4-R11}         ;压栈R4-R11
  9. LDR     R1, =OSTCBCur        ;获取OSTCBCur->OSTCBStkPtr,
  10. ;OSTCBStkPtr是OSTCBCur 中的第一个变量                           
  11. LDR     R1, [R1]             ;R1 = *R1 (R1 = OSTCBCur)
  12. STR     R0, [R1]             ;*R1 = R0 (*OSTCBCur = SP)
  13.                              ;将当前任务的堆栈保存到自己的任务控制块
  14. ;OSTCBCur->OSTCBStkPtr = PSP
  15. ;程序运行此位置,已经保存了当前任务的寄存器。
  16.                            
  17. OS_CPU_PendSVHandler_nosave
  18. PUSH    {R14}                ;R14 入栈
  19. LDR     R0, =OSTaskSwHook    ;OSTaskSwHook(); R0 = &OSTaskSwHook
  20. BLX     R0                   ;调用OSTaskSwHook()
  21. POP     {R14}                ;恢复R14

  22. /********************************加载要执行任务的寄存器*********************************************/
  23. LDR     R0, =OSPrioCur      ;R0 = &OSPrioCur
  24. LDR     R1, =OSPrioHighRdy  ;R1 = &OSPrioHighRdy
  25. LDRB    R2, [R1]            ;R2 = *R1
  26. STRB    R2, [R0]            ;*R0 = R2
  27.                             ;上面这四句函数的功能就是OSPrioCur = OSPrioHighRdy

  28. LDR     R0, =OSTCBCur       ;R0 = &OSTCBCur
  29. LDR     R1, =OSTCBHighRdy   ;R1 = &OSTCBHighRdy
  30. LDR     R2, [R1]            ;R2 = *R1
  31. STR     R2, [R0]            ;*R0 = R2
  32. ;上面这四句函数的功能就是OSTCBCur = OSTCBHighRdy

  33. LDR     R0, [R2]            ;R0 = *R2 也就是R0 = OSTCBHighRdy又因为SP = OSTCBHighRdy->OSTCBStkPtr
  34.                             ;这条指令的含义就是R0=PSP。
  35. LDM     R0, {R4-R11}        ;从任务堆栈恢复R4-R11
  36. ADDS    R0, R0, #0x20       ;调整R0 += 0x20
  37. MSR     PSP, R0             ;PSP = R0
  38. ORR     LR, LR, #0x04     ; 确保LR位2为1,返回后使用进程堆栈PSP
  39. CPSIE   I                 ; 开中断
  40. BX      LR                ; 中断返回,剩下的8个寄存器会自动的出栈。
  41. END
复制代码
    为了帮助大家更好的理解这个过程,这里举一个简单的例子:
  l 第一步:开始多任务后,系统就会从咱们上面说的OSStartHighRdy进入到PendSV中断,进入中断前使用的是MSP,也就是说自动入栈的8个寄存器被压入到MSP所指向的堆栈空间。
  l 第二步:进入中断后开始MSP(因为中断程序中只能使用MSP,而不能使用PSP)。由于是第一次进入执行PendSV,剩下的8个需要手动入栈的寄存器不需要执行入栈操作(为什么不需要入栈操作? 因为第一次执行PendSV前的函数只是μCOS-III的初始化,而不是需要执行的任务,所以现场不需要保存)。
  l 第三步:获得当前需要执行的最高优先级任务A后,程序就会从任务A的堆栈空间恢复需要手动入栈的8个寄存器R4-R11,在退出PendSV后,剩下的8个寄存器内容会自动得到恢复。由于前面初始化任务堆栈的时候,已经指定了任务的地址,所以这时就能正确的切换到任务A中。
  l 第四步:当任务A被挂起或者其它的原因,系统再次进入到PendSV中断,进入中断前自动入栈的8个寄存器已经被保存到任务A的堆栈空间,进入中断后再将剩余8个需要手动入栈的8个寄存器推入任务A的堆栈空间,并保存PSP到任务A的TCB控制块,剩下执行的操作就和第三步相同了,获取另一个需要执行的高优先级任务B。初学的同学一定要不这个过程分析透,并牢记。这个过程很重要,要不任务怎么切换的都不知道。

baiyongbin2009 回答时间:2014-12-22 17:20:39
9.5  总结
    希望初学的同学将文章所讲的三个文件自行分析一下,特别是PendSV中断函数的内容。本期教程的内容理解透了,对于后面学习源码大有裨益。

参考资料:
1.       www.micrium.com

12

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似分享

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版