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

【经验分享】STM32 OS PendSV与堆栈操作

[复制链接]
STMCU小助手 发布时间:2022-1-16 18:03
一、什么是PendSV
PendSV是可悬起异常,如果我们把它配置最低优先级,那么如果同时有多个异常被触发,它会在其他异常执行完毕后再执行,而且任何异常都可以中断它。更详细的内容在《Cortex-M3 权威指南》里有介绍,下面我摘抄了一段。

OS 可以利用它“缓期执行”一个异常——直到其它重要的任务完成后才执行动 作。悬起 PendSV 的方法是:手工往 NVIC的 PendSV悬起寄存器中写 1。悬起后,如果优先级不够 高,则将缓期等待执行。
PendSV的典型使用场合是在上下文切换时(在不同任务之间切换)。例如,一个系统中有两个就绪的任务,上下文切换被触发的场合可以是:* D7 p" u4 |' ^' Z( X/ I% ]
1、执行一个系统调用" x; Y" {% d0 W" h# [7 p, Q0 W
2、系统滴答定时器(SYSTICK)中断,(轮转调度中需要)
让我们举个简单的例子来辅助理解。假设有这么一个系统,里面有两个就绪的任务,并且通过SysTick异常启动上下文切换。但若在产生 SysTick 异常时正在响应一个中断,则 SysTick异常会抢占其 ISR。在这种情况下,OS是不能执行上下文切换的,否则将使中断请求被延迟,而且在真实系统中延迟时间还往往不可预知——任何有一丁点实时要求的系统都决不能容忍这 种事。因此,在 CM3 中也是严禁没商量——如果 OS 在某中断活跃时尝试切入线程模式,将触犯用法fault异常。
为解决此问题,早期的 OS 大多会检测当前是否有中断在活跃中,只有在无任何中断需要响应 时,才执行上下文切换(切换期间无法响应中断)。然而,这种方法的弊端在于,它可以把任务切 换动作拖延很久(因为如果抢占了 IRQ,则本次 SysTick在执行后不得作上下文切换,只能等待下 一次SysTick异常),尤其是当某中断源的频率和SysTick异常的频率比较接近时,会发生“共振”, 使上下文切换迟迟不能进行。现在好了,PendSV来完美解决这个问题了。PendSV异常会自动延迟上下文切换的请求,直到 其它的 ISR都完成了处理后才放行。为实现这个机制,需要把 PendSV编程为最低优先级的异常。如果 OS检测到某 IRQ正在活动并且被 SysTick抢占,它将悬起一个 PendSV异常,以便缓期执行 上下文切换。
使用 PendSV 控制上下文切换个中事件的流水账记录如下:
1. 任务 A呼叫 SVC来请求任务切换(例如,等待某些工作完成)
2. OS接收到请求,做好上下文切换的准备,并且悬起一个 PendSV异常。
3. 当 CPU退出 SVC后,它立即进入 PendSV,从而执行上下文切换。
4. 当 PendSV执行完毕后,将返回到任务 B,同时进入线程模式。
5. 发生了一个中断,并且中断服务程序开始执行
6. 在 ISR执行过程中,发生 SysTick异常,并且抢占了该 ISR。
7. OS执行必要的操作,然后悬起 PendSV异常以作好上下文切换的准备。
8. 当 SysTick退出后,回到先前被抢占的 ISR中,ISR继续执行
9. ISR执行完毕并退出后,PendSV服务例程开始执行,并且在里面执行上下文切换
10. 当 PendSV执行完毕后,回到任务 A,同时系统再次进入线程模式。

我们在uCOS的PendSV的处理代码中可以看到:
  1. OS_CPU_PendSVHandler5 x) V# N$ W0 t! p# i& e: m
  2.     CPSID I ; 关中断
    # h; [  G9 L1 T' a
  3.     ;保存上文
    " T( Z( Z$ F8 x1 n2 K: ]: L
  4.     ;....................... 3 d. R: C" q' P0 F3 w' u4 d8 i
  5.     ;切换下文
      O( e+ ^0 q. ?" M4 Q3 n
  6.     CPSIE I ;开中断0 Q' s! u, a( Y
  7.     BX LR ;异常返回
复制代码
3 |' w9 |( k& d
它在异常一开始就关闭了中端,结束时开启中断,中间的代码为临界区代码,即不可被中断的操作。PendSV异常是任务切换的堆栈部分的核心,由他来完成上下文切换。PendSV的操作也很简单,主要有设置优先级和触发异常两部分:
  1. NVIC_INT_CTRL EQU 0xE000ED04 ; 中断控制寄存器; R" j' F: H9 ^% [6 |, r
  2. NVIC_SYSPRI14 EQU 0xE000ED22 ; 系统优先级寄存器(优先级14).
    ; y7 A0 s3 V5 L0 C9 f; Y, Q4 j
  3. NVIC_PENDSV_PRI EQU 0xFF ; PendSV优先级(最低). NVIC_PENDSVSET EQU 0x10000000 ; PendSV触发值$ }1 a$ c, c6 Z& f9 b
  4. " A4 O) [1 f* C" ^
  5. ; 设置PendSV的异常中断优先级
    7 Y: z. W% p4 i) F5 C
  6. 4 Q) L/ f  w; h
  7. LDR R0, =NVIC_SYSPRI14
    ' G9 A" g  {) {. Z% T( c+ ?7 Z/ G
  8. LDR R1, =NVIC_PENDSV_PRI
    0 @; O( u/ a* _
  9. STRB R1, [R0] ; 触发PendSV异常
    5 K* V5 K% X0 m5 Z0 T! u
  10. LDR R0, =NVIC_INT_CTRL ( G# m  J; ^. n
  11. LDR R1, =NVIC_PENDSVSET " B6 b. R1 ^8 \
  12. STR R1, [R0]
复制代码
+ x8 Z: d) B* V
二、堆栈操作
Cortex M4有两个堆栈寄存器,主堆栈指针(MSP)与进程堆栈指针(PSP),而且任一时刻只能使用其中的一个。MSP为复位后缺省使用的堆栈指针,异常永远使用MSP,如果手动开启PSP,那么线程使用PSP,否则也使用MSP。怎么开启PSP?
  1. MSR     PSP, R0                                             ; Load PSP with new process SP% i; h# A5 s+ V8 J7 i0 s2 c
  2.     ORR     LR, LR, #0x04                                   ; Ensure exception return uses process stack
复制代码

# Q1 D3 i/ X6 [# S( S0 Y" q0 u
很容易就看出来了,置LR的位2为1,那么异常返回后,线程使用PSP。
写OS首先要将内存分配搞明白,单片机内存本来就很小,所以我们当然要斤斤计较一下。在OS运行之前,我们首先要初始化MSP和PSP,
  1. EXTERN  OS_CPU_ExceptStkBase
    8 W% O+ `4 u1 F* j
  2.    ;PSP清零,作为首次上下文切换的标志
    ( {: I$ X0 M3 f' J+ p
  3.    MOVS    R0, #0
    $ b; r0 i4 k" p6 C4 T+ @8 b: b
  4.    MSR     PSP, R0
    0 t8 p! H' q6 @7 ?! ?
  5.    ;将MSP设为我们为其分配的内存地址
    , s+ p$ j/ w0 b6 N
  6.    LDR     R0, =OS_CPU_ExceptStkBase
    6 H0 {! t+ ]+ O5 O; m
  7.    LDR     R1, [R0]' Q3 v# M" p0 c
  8.    MSR     MSP, R1
复制代码

4 g$ x) t; W" n: e
然后就是PendSV上下文切换中的堆栈操作了,如果不使用FPU,则进入异常自动压栈xPSR,PC,LR,R12,R0-R3,我们还要把R4-R11入栈。如果开启了FPU,自动压栈的寄存器还有S0-S15,还需吧S16-S31压栈。
  1. MRS     R0, PSP
    . j5 l0 ?( W! g
  2.     SUBS   R0, R0, #0x20        ;压入R4-R11* d7 h# i3 |* s& I" Z1 J( Y1 `# _
  3.     STM     R0, {R4-R11}
    6 N$ [2 }6 a% {' |( w# b" X
  4. " D  C3 j' q6 j9 N4 n$ Y# u
  5.     LDR     R1, =Cur_TCB_Point    ;当前任务的指针
    - v1 G" V, g& B1 Z
  6.     LDR     R1, [R1]( ^  B: P  A9 F) @7 I6 e; S
  7.     STR     R0, [R1]            ; 更新任务堆栈指针
复制代码

3 R# t7 \  o" O
出栈类似,但要注意顺序
  1. LDR     R1, =TCB_Point    ;要切换的任务指针
    ) p) M0 V) [# W/ V1 D! [3 R0 ^
  2.     LDR     R2, [R1]
    8 _' b9 e( C/ l# B3 {+ ]1 |  J2 q
  3.     LDR     R0, [R2]          ; R0为要切换的任务堆栈地址
    + [8 l" z5 z, x. ^9 I' l& c
  4.   $ |! h- o* H  d
  5.     LDM     R0, {R4-R11}     ; 弹出R4-R11. H; T* H  ^0 O
  6.     ADDS    R0, R0, #0x20$ p% C& b. k  a+ i9 R7 J
  7. ; k% p# c. n/ y) S9 D3 D# P, q; p% }  e2 \
  8.     MSR     PSP, R0        ;更新PSP
复制代码
4 J+ ]# B" b0 a* _9 y
三、OS实战
新建os_port.asm文件,内容如下:
  1. NVIC_INT_CTRL   EQU     0xE000ED04                              ; Interrupt control state register.; @, }( j. {/ Q/ A" I
  2. NVIC_SYSPRI14   EQU     0xE000ED22                              ; System priority register (priority 14).
    & A$ G7 b6 Y* U/ ], i
  3. NVIC_PENDSV_PRI EQU           0xFF                              ; PendSV priority value (lowest).
    + T0 |# O* d1 X8 ~) T4 ?
  4. NVIC_PENDSVSET  EQU     0x10000000                              ; Value to trigger PendSV exception.
    - K4 P  W- L- O- ^; ~3 I% F# Q

  5. 9 W% U( s& r$ g& A8 z
  6.   RSEG CODE:CODE:NOROOT(2)
    ' ~. {& d$ V/ }9 x
  7.   THUMB
    ! v. j* l' z8 m+ M4 l5 M) D
  8. 7 ~1 w& E4 {9 g

  9. + q: j$ W6 a+ p( [
  10.   EXTERN  g_OS_CPU_ExceptStkBase
    7 ~& c  c% t6 @+ q( K% N3 \
  11.   
    - W  W. A( }7 b8 a
  12.   EXTERN  g_OS_Tcb_CurP
    # j: [% f( v* A" r2 T( h
  13.   EXTERN  g_OS_Tcb_HighRdyP
    * w6 V% ]; q6 _' E' c! @: @& h
  14. 9 t; f/ W' p) Z$ z! E
  15.   PUBLIC OSStart_Asm
    * w% Y! {0 L5 M3 @
  16.   PUBLIC PendSV_Handler
    3 u, |, d; i7 H  G! B
  17.   PUBLIC OSCtxSw
    1 A% w0 O9 }% W. ^# b
  18. , P/ ]- F& S# {; \8 ]2 Y/ h
  19. OSCtxSw
    * u& Z8 W5 a2 k7 s0 ]% C
  20.     LDR     R0, =NVIC_INT_CTRL
    # k  a5 R5 B2 s" [
  21.     LDR     R1, =NVIC_PENDSVSET
    6 O0 B) C+ H9 i
  22.     STR     R1, [R0]
    + k" [- K) ]* a9 a/ N
  23.     BX      LR                                                ; Enable interrupts at processor level  e( C+ M# W3 O8 R$ c' d, A2 Q# F+ l
  24. ( |/ Z+ n, N# a+ Q' S* g1 I1 i
  25. OSStart_Asm
    0 o% j3 n; M$ M" }
  26.     LDR     R0, =NVIC_SYSPRI14                                  ; Set the PendSV exception priority: j" R2 s; I% i" e! ~! m
  27.     LDR     R1, =NVIC_PENDSV_PRI) s' B6 {8 @8 ~2 N
  28.     STRB    R1, [R0]
    2 T. N( k$ F3 q/ r  {- i6 }8 T

  29. ! f  C) G3 Q# N
  30.     MOVS    R0, #0                                              ; Set the PSP to 0 for initial context switch call: L2 O4 T6 G: o. W3 F; N5 @0 y1 u
  31.     MSR     PSP, R0$ O- Y/ i  n. ~1 a. w
  32. * J# U$ I& y: [) ~! n
  33.     LDR     R0, =g_OS_CPU_ExceptStkBase                           ; Initialize the MSP to the OS_CPU_ExceptStkBase
    ; L- ?7 J6 G% Q+ p2 {7 q8 N4 W
  34.     LDR     R1, [R0]6 L8 h- F6 r7 g, @+ V' j
  35.     MSR     MSP, R1      B- P8 `+ W& I% X3 F
  36. # M* A  j9 ^! b3 d, i
  37.     LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)
    " K1 `& G& W2 p0 u8 b& z
  38.     LDR     R1, =NVIC_PENDSVSET
    7 v% ?+ ~) \# B: U( r
  39.     STR     R1, [R0]4 Z$ l5 w$ u% ?& x

  40. : |/ j  E5 P! O/ i" }( v
  41.     CPSIE   I                                                   ; Enable interrupts at processor level- m+ b% d  a7 P* b! E8 P  C. J2 B

  42. * z/ y/ j+ U0 _, O
  43. OSStartHang
    5 k" L5 r' h$ C" E
  44.     B       OSStartHang                                         ; Should never get here6 T5 U2 j+ T/ n- T* B6 H6 s  R5 j. q
  45.     2 |  H/ W0 d( g2 p- T# h% T4 O8 S
  46.    
    , h# y4 A# L  T8 P* a! T. v1 B. ^
  47. $ H& u) g6 f+ l% J& o) N+ b8 R' Z
  48. PendSV_Handler
    , i& r  V  n" P( y# t% b7 F
  49.     CPSID   I                                                   ; Prevent interruption during context switch
    . c8 Y9 }9 J; W( j' f, ~
  50.     MRS     R0, PSP                                             ; PSP is process stack pointer
    & M, a5 N$ {1 B  T) n+ j3 G
  51.     CBZ     R0, OS_CPU_PendSVHandler_nosave                     ; Skip register save the first time3 u1 L0 `, S; X+ N( I
  52.    1 h. q6 B% u, R: m8 u9 A3 D
  53.     SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack
    8 R# j/ @# A  e0 O& W: h; _4 d- |
  54.     STM     R0, {R4-R11}9 Q$ k& j2 u  S1 m+ D

  55. ! _; W3 u# `% a$ @+ s) A
  56.     LDR     R1, =g_OS_Tcb_CurP                                       ; OSTCBCur->OSTCBStkPtr = SP;% Z$ N5 W% b: S- L& f: s5 F: Y) y
  57.     LDR     R1, [R1]
    7 J, C( a1 e3 n8 c2 u/ ^' g( \
  58.     STR     R0, [R1]                                            ; R0 is SP of process being switched out- n; B/ Q! W( F4 D
  59. 5 Q: T  Y. f7 j# g  b
  60.                                                                 ; At this point, entire context of process has been saved) M  n6 o+ x4 V- {$ ^- F" m% y6 Q
  61. OS_CPU_PendSVHandler_nosave
    . r5 r% n- |. P: Z# s. u; N
  62.     LDR     R0, =g_OS_Tcb_CurP                                       ; OSTCBCur  = OSTCBHighRdy;. P2 M' X, w3 k" W) `' o
  63.     LDR     R1, =g_OS_Tcb_HighRdyP* i) r, M( O* n; G/ W
  64.     LDR     R2, [R1]
    - t/ K$ {8 {. A9 V& g  r3 f; M
  65.     STR     R2, [R0]( ?7 K6 Y1 F/ `" D3 \. ^1 D) ^# S0 J
  66. 1 u1 h% [7 I/ v7 J- Q$ m
  67.     LDR     R0, [R2]                                       ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;# h- S3 C) V4 o- _
  68.   
    ! Z+ m, w* z' F
  69.     LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack
    1 B' q% o# Y" R) @- j! t
  70.     ADDS    R0, R0, #0x203 Y9 @  M/ {- b) }5 Q
  71.             
    / p) O$ W* a2 E+ a
  72.     MSR     PSP, R0                                             ; Load PSP with new process SP7 C6 E7 o/ _0 C* R/ i/ j6 n( B( q
  73.     ORR     LR, LR, #0x04                                       ; Ensure exception return uses process stack' x! u: N1 c4 \1 h/ p  j+ S) ^
  74.     + e0 L* U6 Z1 q( P; V
  75.     CPSIE   I
    2 \$ O" }! P2 S
  76.     BX      LR                                                  ; Exception return will restore remaining context% ?' X4 u8 Q9 \7 L: j5 ?; P- U
  77.   # _( {9 P% `/ ?
  78.     END
复制代码
8 o) k# e  M& ^: t6 P9 z
main.c内容如下:
  1. #include "stdio.h"# t' c8 d4 ?# `% q
  2. #define OS_EXCEPT_STK_SIZE 1024" \! A5 Z2 G7 i9 D
  3. #define TASK_1_STK_SIZE 1024
    : R+ _& g! i# }% w. `
  4. #define TASK_2_STK_SIZE 10244 w& u0 F' P$ l5 \5 b5 s
  5. 0 C, E2 e6 I3 h7 d+ Z& F
  6. typedef unsigned int OS_STK;: ~  {! j9 C- S+ F6 m& B
  7. typedef void (*OS_TASK)(void);
    ! c9 C6 s0 u* d5 U
  8. ; W6 r' m7 M2 f3 K! B9 }
  9. typedef struct OS_TCB" R* w; s  D# \4 V* H, d2 G
  10. {" a" c1 V' C& M9 Y
  11.   OS_STK *StkAddr;
    4 w" X  g5 r+ z1 s6 X
  12. }OS_TCB,*OS_TCBP;
    4 G0 c7 `7 ~1 {& f4 ~9 O) J* I
  13. * w3 H! w' [' b* f+ v

  14. " x8 o# [8 }2 D% h2 i0 o
  15. OS_TCBP g_OS_Tcb_CurP; : r& ^( G* V+ d  g3 J0 h
  16. OS_TCBP g_OS_Tcb_HighRdyP;* V! Z* \: W  }; l% ^
  17. 9 G; k$ p5 r! c3 y
  18. static OS_STK OS_CPU_ExceptStk[OS_EXCEPT_STK_SIZE];- [6 H4 F5 K% M) s1 x; E  o
  19. OS_STK *g_OS_CPU_ExceptStkBase;1 `! a8 A0 L* x* H
  20. 9 B  V( \6 w' `  j3 C
  21. static OS_TCB TCB_1;! A3 a2 C$ Z  O, S# |  k/ Y% H; X1 V2 `- c
  22. static OS_TCB TCB_2;# w9 ]* z1 J  m7 J: ^6 ^
  23. static OS_STK TASK_1_STK[TASK_1_STK_SIZE];& `7 C3 J8 y5 B( l+ b2 z' p: n( Z) p- I
  24. static OS_STK TASK_2_STK[TASK_2_STK_SIZE];! k. Z2 J: d4 F6 B2 Y; T

  25. 8 S7 ~) T4 W7 ?3 b
  26. extern void OSStart_Asm(void);$ N3 h6 `& ^1 \8 c( R) N4 Q
  27. extern void OSCtxSw(void);* o- s" N: c. w5 C- h

  28. . q& r" U8 |8 T
  29. void Task_Switch()
    ; h4 a3 G5 c6 f/ j* U6 j) R1 L( Z3 c
  30. {& r7 G& E' i, \9 ]' w' ]
  31.   if(g_OS_Tcb_CurP == &TCB_1)2 x- t- L. {, J0 r+ S6 L6 \8 `
  32.     g_OS_Tcb_HighRdyP=&TCB_2;: ^( p5 Q9 v9 K+ g
  33.   else
    7 \% @. m- U# K4 U
  34.     g_OS_Tcb_HighRdyP=&TCB_1;( r8 d* [7 u1 [, g% a( ^* t
  35. ' X" n. h: j/ T& J
  36.   OSCtxSw();
    7 q7 h: ?& g! V; t+ K! a
  37. }
    ' n4 D$ J" }3 w2 y3 B5 D' [; w6 P/ Y

  38. ' L# x( p- N4 L& i5 v
  39. $ R- \+ G! D4 W, ^! X  |9 R) u& j* ]
  40. void task_1()0 h) x( _- x& t' {: C; ?
  41. {- X1 ?- x& C, r  F1 D( t
  42.   printf("Task 1 Running!!!\n");
    ! o0 R& r. h* h# c2 _: {
  43.   Task_Switch();, s# V, I5 s7 {; a
  44.   printf("Task 1 Running!!!\n");
    + p% T2 D* t) a% |; g& q
  45.   Task_Switch();
    ! x, I8 y$ w: ^( F
  46. }
    - ~) |" t& K. g! s* N
  47. 9 H9 M2 ?3 W4 G; P4 M2 Q/ ]& r( j
  48. void task_2()
    / b# l, K5 c4 H  y  s' ?  A
  49. {8 J; q6 [8 q; m1 I0 H) ^
  50.   
    . U' F. [: W5 \4 c5 q$ `1 E
  51.   printf("Task 2 Running!!!\n");
    * i2 u3 K( M% z+ H9 s
  52.   Task_Switch();$ }. M" k2 ~+ Q8 K, X' y4 P2 R% D$ c
  53.   printf("Task 2 Running!!!\n");9 E- O2 T/ R! c3 U6 r; Q
  54.   Task_Switch();
    * U5 R3 a8 z3 R5 |
  55. }
    3 |$ M, E- O% O8 \5 O4 f$ o
  56. % w" ?6 U" Z! [" @' b- ~2 U
  57. void Task_End(void)
    5 m- }! X% }+ f" ~, \9 m  b
  58. {% X: F, q0 T1 G1 m
  59.   printf("Task End\n");
    * I" I7 I3 I# {: t* S
  60.   while(1)
    3 q0 `4 E+ ?: L. ^8 U2 S
  61.   {}5 F/ ^: b8 ^! j: A5 f
  62. }
    / i! b7 @' N( {8 ]9 I4 |6 n) D

  63. 5 _2 ]7 }8 [& C8 e% z( A
  64. void Task_Create(OS_TCB *tcb,OS_TASK task,OS_STK *stk). u# z! m- p1 M! h. G. `; d
  65. {( @$ {1 s3 o, u1 D( r
  66.     OS_STK  *p_stk;
    * q) }. [( b: _% Q# u
  67.     p_stk      = stk;
    , j& s1 M; {/ Y$ d9 O
  68.     p_stk      = (OS_STK *)((OS_STK)(p_stk) & 0xFFFFFFF8u);$ w5 w; H- {% P" e  J
  69.     # J: }+ D+ H3 \5 C0 m
  70.     *(--p_stk) = (OS_STK)0x01000000uL;                          //xPSR+ w* s0 Z! q+ e, {7 D' M- [
  71.     *(--p_stk) = (OS_STK)task;                                  // Entry Point4 j7 K) J+ C$ G/ V* e
  72.     *(--p_stk) = (OS_STK)Task_End;                                     // R14 (LR)
    0 T1 L8 G6 D  F8 W) ], Q
  73.     *(--p_stk) = (OS_STK)0x12121212uL;                          // R12' Z' C& x+ Y' K  z; I; I( m
  74.     *(--p_stk) = (OS_STK)0x03030303uL;                          // R30 c$ a7 j" F7 V0 v4 u7 ?
  75.     *(--p_stk) = (OS_STK)0x02020202uL;                          // R22 B( R  R/ \* u
  76.     *(--p_stk) = (OS_STK)0x01010101uL;                          // R1
    . U1 A5 G1 O6 O0 e0 i
  77.     *(--p_stk) = (OS_STK)0x00000000u;                           // R01 l6 o* ^8 q* l1 m1 N8 ?( Q
  78.    
    # B' r  p# v% K- z( P
  79.     *(--p_stk) = (OS_STK)0x11111111uL;                          // R11
    0 A3 M) O/ b; Y, X* g  y. p
  80.     *(--p_stk) = (OS_STK)0x10101010uL;                          // R10- W# L" |! x( v
  81.     *(--p_stk) = (OS_STK)0x09090909uL;                          // R9
    / g+ F2 l$ ~5 U% U9 g
  82.     *(--p_stk) = (OS_STK)0x08080808uL;                          // R8
    - j  B# X8 x7 s; e  Y5 @
  83.     *(--p_stk) = (OS_STK)0x07070707uL;                          // R7; v  U% O- e: B; t  O  Q
  84.     *(--p_stk) = (OS_STK)0x06060606uL;                          // R6' y% m# V$ U! g0 G7 s! i/ m2 Z
  85.     *(--p_stk) = (OS_STK)0x05050505uL;                          // R5
    ! {% v% l2 w1 |. [  U5 C+ N  A
  86.     *(--p_stk) = (OS_STK)0x04040404uL;                          // R4, F3 C! o$ ^/ e' W) ~7 M
  87.     9 M, \( V9 L5 B. F& O' _2 k! {8 a
  88.     tcb->StkAddr=p_stk;- X5 e9 d# m5 D
  89. }
      x3 u" d6 u2 l: p9 K) @: y
  90. & D6 r* @' _# X% U3 i& I7 f6 P4 j2 u

  91. 2 A) `1 \4 T+ ~& v
  92. int main()
    / _, O9 J, _# W) C% J+ X
  93. {
    4 Q9 m; d7 I1 d* \, h% t' M
  94.     l& o2 M0 p' P) u6 L
  95.   g_OS_CPU_ExceptStkBase = OS_CPU_ExceptStk + OS_EXCEPT_STK_SIZE - 1;5 h. @0 \& J0 A8 f, g- |
  96.   
    ( `) o4 V8 g% t- `8 j5 z
  97.   Task_Create(&TCB_1,task_1,&TASK_1_STK[TASK_1_STK_SIZE-1]);
    . p) f/ v6 b4 D) {3 n
  98.   Task_Create(&TCB_2,task_2,&TASK_2_STK[TASK_1_STK_SIZE-1]);  A3 ^- \* ^" `% u  j
  99.    
    ( p: }6 x2 U1 {; r. ?1 N
  100.   g_OS_Tcb_HighRdyP=&TCB_1;
    + p" q; f1 J7 `5 x4 ^
  101.   
    $ G9 x) N$ f. v$ J
  102.   OSStart_Asm();
    & v. `: Z7 ?0 }( d. l6 X9 F+ A
  103.   
    4 Y2 \9 b' a$ F$ n3 w
  104.   return 0;: j: P/ m/ ^! I  V" Z$ L
  105. }
复制代码

* Z2 W4 Q" k- S. K* n
编译下载并调试:

6 e! B5 A% M0 f# f  z
02143746-b3794508e0a644a09cf863ef3da935ed.jpg

5 Y: {0 s' I6 v8 a) O/ E' U
在此处设置断点
此时寄存器的值,可以看到R4-R11正是我们给的值,单步运行几次,可以看到进入了我们的任务task_1或task_2,任务里打印信息,然后调用Task_Switch进行切换,OSCtxSw触发PendSV异常。
% q, e, U6 [" m7 S
02143747-3c53018b89dc48bb97ef1b9761c698ca.png
5 @/ D8 H! c2 m* b$ \/ [- g
IO输出如下:

. f9 D/ [, n9 X/ T$ `0 [* X8 g' u) D4 d
02143748-2d79fed2fb1e43c2bb90024f7679b5bd.jpg
! Z2 ]% V% v, O3 `
至此我们成功实现了使用PenSV进行两个任务的互相切换。之后,我们使用使用SysTick实现比较完整的多任务切换。

" N+ K- a- x0 B; V0 A
收藏 评论0 发布时间:2022-1-16 18:03

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版