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

【RT-Thread内核实现与应用开发实战指南】读书笔记三

[复制链接]
andeyqi 发布时间:2019-1-3 11:16
本帖最后由 andeyqi 于 2019-1-3 13:07 编辑

阅读《RT-Thread内核实现与应用开发实战指南》阅读 rt_hw_context_switch函数源码时对其中的 rt_thread_switch_interrupt_flag 的用途不是很理解,代码如下:
  1. rt_hw_context_switch_interrupt:
  2. rt_hw_context_switch:
  3.     /* set rt_thread_switch_interrupt_flag to 1 */
  4.     LDR     r2, =rt_thread_switch_interrupt_flag
  5.     LDR     r3, [r2]
  6.     CMP     r3, #1
  7.     BEQ     _reswitch
  8.     MOV     r3, #1
  9.     STR     r3, [r2]

  10.     LDR     r2, =rt_interrupt_from_thread   /* set rt_interrupt_from_thread */
  11.     STR     r0, [r2]

  12. _reswitch:
  13.     LDR     r2, =rt_interrupt_to_thread     /* set rt_interrupt_to_thread */
  14.     STR     r1, [r2]

  15.     LDR r0, =NVIC_INT_CTRL              /* trigger the PendSV exception (causes context switch) */
  16.     LDR r1, =NVIC_PENDSVSET
  17.     STR r1, [r0]
  18.     BX  LR
复制代码
上述汇编代码等同如下的C代码:
  1. void rt_hw_context_switch_interrupt(rt_uint32_t from, rt_uint32_t to)
  2. {
  3.     if (rt_thread_switch_interrupt_flag != 1)
  4.     {
  5.         rt_thread_switch_interrupt_flag = 1;
  6.         rt_interrupt_from_thread        = from;
  7.     }
  8.     rt_interrupt_to_thread = to;
  9. }
复制代码
rt_thread_switch_interrupt_flag != 1时更新线程切换的form线程,否则不更新。rt_thread_switch_interrupt_flag值会在PendSV_Handler中清零,rt_hw_context_switch_interrupt中置1,初始状态为0
  1. /* r0 --> switch from thread stack
  2. * r1 --> switch to thread stack
  3. * psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
  4. */
  5. .global PendSV_Handler
  6. .type PendSV_Handler, %function
  7. PendSV_Handler:
  8.     /* disable interrupt to protect context switch */
  9.     MRS r2, PRIMASK
  10.     CPSID   I

  11.     /* get rt_thread_switch_interrupt_flag */
  12.     LDR r0, =rt_thread_switch_interrupt_flag
  13.     LDR r1, [r0]
  14.     CBZ r1, pendsv_exit         /* pendsv already handled */

  15.     /* clear rt_thread_switch_interrupt_flag to 0 */
  16.     MOV r1, #0x00
  17.     STR r1, [r0]

  18.     LDR r0, =rt_interrupt_from_thread
  19.     LDR r1, [r0]
  20.     CBZ r1, switch_to_thread    /* skip register save at the first time */

  21.     MRS r1, psp                 /* get from thread stack pointer */
  22.    
  23. #if defined (__VFP_FP__) && !defined(__SOFTFP__)
  24.     TST     lr, #0x10           /* if(!EXC_RETURN[4]) */
  25.     VSTMDBEQ r1!, {d8 - d15}    /* push FPU register s16~s31 */
  26. #endif
  27.    
  28.     STMFD   r1!, {r4 - r11}     /* push r4 - r11 register */

  29. #if defined (__VFP_FP__) && !defined(__SOFTFP__)
  30.     MOV     r4, #0x00           /* flag = 0 */

  31.     TST     lr, #0x10           /* if(!EXC_RETURN[4]) */
  32.     MOVEQ   r4, #0x01           /* flag = 1 */

  33.     STMFD   r1!, {r4}           /* push flag */
  34. #endif

  35.     LDR r0, [r0]
  36.     STR r1, [r0]                /* update from thread stack pointer */

  37. switch_to_thread:
  38.     LDR r1, =rt_interrupt_to_thread
  39.     LDR r1, [r1]
  40.     LDR r1, [r1]                /* load thread stack pointer */

  41. #if defined (__VFP_FP__) && !defined(__SOFTFP__)
  42.     LDMFD   r1!, {r3}           /* pop flag */
  43. #endif

  44.     LDMFD   r1!, {r4 - r11}     /* pop r4 - r11 register */

  45. #if defined (__VFP_FP__) && !defined(__SOFTFP__)
  46.     CMP     r3,  #0             /* if(flag_r3 != 0) */
  47.     VLDMIANE  r1!, {d8 - d15}   /* pop FPU register s16~s31 */
  48. #endif

  49.     MSR psp, r1                 /* update stack pointer */

  50. #if defined (__VFP_FP__) && !defined(__SOFTFP__)
  51.     ORR     lr, lr, #0x10       /* lr |=  (1 << 4), clean FPCA. */
  52.     CMP     r3,  #0             /* if(flag_r3 != 0) */
  53.     BICNE   lr, lr, #0x10       /* lr &= ~(1 << 4), set FPCA. */
  54. #endif

  55. pendsv_exit:
  56.     /* restore interrupt */
  57.     MSR PRIMASK, r2

  58.     ORR lr, lr, #0x04
  59.     BX  lr
复制代码
按照正常的函数调用流程,schedule  -》 rt_hw_context_switch  -》PendSV_Handler  rt_thread_switch_interrupt_flag值应该都为0,除非在rt_hw_context_switch  和 PendSV_Handler   之间再次调用rt_hw_context_switch   rt_thread_switch_interrupt_flag值会为1。
在网上找到了想要的答案:

只要是“硬件”入栈 PendSV,那么就说明有 schedule 发生了,这时候被换出的线程被保存在了 from_thread 那个变量里,to_thread 变量存储的是要换进来的线程,并且 flag = 1。如果在硬件入栈的时候发生中断,那么, cortex-m3 会在入栈之后执行高优先级的中断(必然不是 PendSV),而挂起 PendSV。假设在此中断例程中调用了 schedule,那么它看到 flag == 1 了,就不会再去保存旧的线程地址到 from_thread 了,原因很简单,旧的线程始终没变~然后 PendSV 里对 flag 做的跳转保证了 PendSV 只执行一次。

rt_thread_switch_interrupt_flag 标志的作用就是,前一次PendSV_Handler 被打断的情况下,再次进行线程上下文切换的话,不更新rt_interrupt_from_thread线程相关的内容,只更新rt_interrupt_to_thread线程线程内容。



在网上找到了这个问题的资料,链接如下(可能需要梯子),访问不了的话可以参见附件:
http://groups.google.com/forum/#!msg/rt-thread-cnusers/v_MDGup3G8Q/gxq8J6QUVX0J



rtt进程上下文切换.zip (1.39 MB, 下载次数: 1)
收藏 评论1 发布时间:2019-1-3 11:16

举报

1个回答
zhdzhd-174422 回答时间:2019-1-3 16:44:07
不错,顶一个,楼主加油!

所属标签

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 手机版