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

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

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

OS 可以利用它“缓期执行”一个异常——直到其它重要的任务完成后才执行动 作。悬起 PendSV 的方法是:手工往 NVIC的 PendSV悬起寄存器中写 1。悬起后,如果优先级不够 高,则将缓期等待执行。
PendSV的典型使用场合是在上下文切换时(在不同任务之间切换)。例如,一个系统中有两个就绪的任务,上下文切换被触发的场合可以是:
$ F5 x9 F5 ]2 z) s9 E1 q, H1、执行一个系统调用
1 r3 K# A. c: Q' x+ L  C2、系统滴答定时器(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_PendSVHandler
    9 m+ H+ p. z$ o8 ^
  2.     CPSID I ; 关中断
    2 K6 P4 u, i1 t
  3.     ;保存上文 / N. F& Y. V. M( m
  4.     ;.......................
    1 }. e4 Q' w( T" p2 A- u
  5.     ;切换下文
    ; L) H/ J) ]0 H4 m5 j: J
  6.     CPSIE I ;开中断
    ( V/ m2 q$ t! q; Q
  7.     BX LR ;异常返回
复制代码
  n4 _! C+ I; K( O1 |  f
它在异常一开始就关闭了中端,结束时开启中断,中间的代码为临界区代码,即不可被中断的操作。PendSV异常是任务切换的堆栈部分的核心,由他来完成上下文切换。PendSV的操作也很简单,主要有设置优先级和触发异常两部分:
  1. NVIC_INT_CTRL EQU 0xE000ED04 ; 中断控制寄存器$ B( K& n9 |$ ]! J6 t% }6 F
  2. NVIC_SYSPRI14 EQU 0xE000ED22 ; 系统优先级寄存器(优先级14).
    0 \/ h5 k" M# B1 t; o
  3. NVIC_PENDSV_PRI EQU 0xFF ; PendSV优先级(最低). NVIC_PENDSVSET EQU 0x10000000 ; PendSV触发值
    " ^' s8 \$ p6 m9 k& h+ T9 O

  4. 4 f& K1 R) F' v8 A" S$ y
  5. ; 设置PendSV的异常中断优先级
    ! Z" f& V% _! ^8 |3 n

  6. 9 l8 ?$ u+ E( ^5 s0 X# j
  7. LDR R0, =NVIC_SYSPRI14 / O0 d7 M: d# P' f5 Q0 Q) ]8 o
  8. LDR R1, =NVIC_PENDSV_PRI
    5 |; R' a5 O3 W3 n9 m4 b: O
  9. STRB R1, [R0] ; 触发PendSV异常
    , m5 e; H& D# C$ W) i% n4 s& _
  10. LDR R0, =NVIC_INT_CTRL
    5 N; J4 Y$ j: g- V* b
  11. LDR R1, =NVIC_PENDSVSET ' v! a0 C7 P3 `- ]* y" O
  12. STR R1, [R0]
复制代码
0 o0 t9 L6 b- q" `' D& ?
二、堆栈操作
Cortex M4有两个堆栈寄存器,主堆栈指针(MSP)与进程堆栈指针(PSP),而且任一时刻只能使用其中的一个。MSP为复位后缺省使用的堆栈指针,异常永远使用MSP,如果手动开启PSP,那么线程使用PSP,否则也使用MSP。怎么开启PSP?
  1. MSR     PSP, R0                                             ; Load PSP with new process SP! k8 o. [, ?" A8 k
  2.     ORR     LR, LR, #0x04                                   ; Ensure exception return uses process stack
复制代码
, K4 _* _1 D) j6 ~( t
很容易就看出来了,置LR的位2为1,那么异常返回后,线程使用PSP。
写OS首先要将内存分配搞明白,单片机内存本来就很小,所以我们当然要斤斤计较一下。在OS运行之前,我们首先要初始化MSP和PSP,
  1. EXTERN  OS_CPU_ExceptStkBase
    " @. A" I( H1 ?
  2.    ;PSP清零,作为首次上下文切换的标志" [0 n& [5 l' x8 T  H& x) J
  3.    MOVS    R0, #0 $ c: {, k+ `+ W3 Y( m
  4.    MSR     PSP, R0. a+ m% y, r- ?# _% Z
  5.    ;将MSP设为我们为其分配的内存地址  @# L5 Y6 n3 U% U$ l% i
  6.    LDR     R0, =OS_CPU_ExceptStkBase
    ; e, ]4 J; o& N4 Z% W
  7.    LDR     R1, [R0]8 z$ E5 S$ x. j  ]% H) _8 h) j; c2 x
  8.    MSR     MSP, R1
复制代码
* T7 r' U' t/ g9 a  R& E
然后就是PendSV上下文切换中的堆栈操作了,如果不使用FPU,则进入异常自动压栈xPSR,PC,LR,R12,R0-R3,我们还要把R4-R11入栈。如果开启了FPU,自动压栈的寄存器还有S0-S15,还需吧S16-S31压栈。
  1. MRS     R0, PSP- K$ o7 g) v1 M6 y' u5 }
  2.     SUBS   R0, R0, #0x20        ;压入R4-R11
    0 c8 s" l; G: t  R+ E7 q: |
  3.     STM     R0, {R4-R11}. A# B! i+ S( d
  4. - `, W4 R! |8 w0 W- l9 M( e
  5.     LDR     R1, =Cur_TCB_Point    ;当前任务的指针
    1 q" _" C" p6 Q: Z
  6.     LDR     R1, [R1]. ^/ {& P9 ]( A
  7.     STR     R0, [R1]            ; 更新任务堆栈指针
复制代码

% @& D4 N% T# E/ n" k
出栈类似,但要注意顺序
  1. LDR     R1, =TCB_Point    ;要切换的任务指针
    / ^3 [0 E+ H" L3 Q8 t( \2 x- [
  2.     LDR     R2, [R1]
      g: y2 U! p7 |1 J
  3.     LDR     R0, [R2]          ; R0为要切换的任务堆栈地址4 W+ K; b  b; P1 \
  4.   
    2 x8 ]6 S0 [* _3 G" ?+ t
  5.     LDM     R0, {R4-R11}     ; 弹出R4-R118 a: w' R( ^5 r3 k& M
  6.     ADDS    R0, R0, #0x20
    - Y3 w: s1 E* ]; O/ a( T2 ~
  7. % f, }4 G  ^& g* H9 s5 ^
  8.     MSR     PSP, R0        ;更新PSP
复制代码

) k' D) ^7 K6 U/ O* A
三、OS实战
新建os_port.asm文件,内容如下:
  1. NVIC_INT_CTRL   EQU     0xE000ED04                              ; Interrupt control state register.8 k/ @4 ?2 n% E1 P  t5 T
  2. NVIC_SYSPRI14   EQU     0xE000ED22                              ; System priority register (priority 14).0 T+ \9 L; d! Q
  3. NVIC_PENDSV_PRI EQU           0xFF                              ; PendSV priority value (lowest).
    5 r' m1 m) [6 v! [' ~
  4. NVIC_PENDSVSET  EQU     0x10000000                              ; Value to trigger PendSV exception.
    2 b8 ]' t+ E* O) |: z1 q; L

  5. , _) k1 A" w+ f- m5 r0 Z
  6.   RSEG CODE:CODE:NOROOT(2)$ U  g2 h' S! A
  7.   THUMB
    + x. @5 M/ l! n/ i1 q
  8. 2 h, y' O5 h$ r! Q/ ~- ^

  9. ( }& D( v& W  u+ G# t, K2 M
  10.   EXTERN  g_OS_CPU_ExceptStkBase
    * ^: e0 U0 M' O
  11.   2 }' E& Y8 [) k0 x0 z
  12.   EXTERN  g_OS_Tcb_CurP0 N5 G' J5 ]: S" r, Q' Z
  13.   EXTERN  g_OS_Tcb_HighRdyP
    + D) t/ D* h; h% U8 d4 ?
  14. 1 [3 k- I# h& B, \6 M
  15.   PUBLIC OSStart_Asm* [! }/ k9 s8 L, p6 W  c
  16.   PUBLIC PendSV_Handler* g3 M3 Q7 l7 `7 [
  17.   PUBLIC OSCtxSw1 E5 E4 @0 |$ A8 r! i0 f

  18. # c! T- t5 D" W4 N* R! W
  19. OSCtxSw
    8 v8 c! D. a8 `
  20.     LDR     R0, =NVIC_INT_CTRL6 T% k# E1 |  P3 B* f
  21.     LDR     R1, =NVIC_PENDSVSET
    * k! |. j( z. S; x+ m3 N  e0 Z
  22.     STR     R1, [R0]
    , h: w- [# ?% [' U1 F% ~
  23.     BX      LR                                                ; Enable interrupts at processor level
    2 a3 E  h, R& i
  24. 8 @, n4 [, w" ~. K( T0 D/ o
  25. OSStart_Asm! U' y0 u* J' D6 z& T
  26.     LDR     R0, =NVIC_SYSPRI14                                  ; Set the PendSV exception priority
    7 f0 O1 c2 x% A# F2 v( K
  27.     LDR     R1, =NVIC_PENDSV_PRI
    4 U1 E* a6 U6 X4 s+ R, Z; ^. e
  28.     STRB    R1, [R0]9 p' T% G; F: H9 u1 v7 F  ^9 ?
  29.   z2 t6 N0 ?) n9 N3 X" ]! g/ r/ o8 |
  30.     MOVS    R0, #0                                              ; Set the PSP to 0 for initial context switch call
    / k; f  d; ]; }- m
  31.     MSR     PSP, R0! [) G) ]7 o# a* a: o
  32. 7 b! x8 ]( E+ V) h$ Q+ u: Y
  33.     LDR     R0, =g_OS_CPU_ExceptStkBase                           ; Initialize the MSP to the OS_CPU_ExceptStkBase
    / E1 M: V5 n2 Q4 p* J. e
  34.     LDR     R1, [R0]
    / }# T& I8 N  d$ s+ [3 y9 l' A( ?
  35.     MSR     MSP, R1    6 @! S: S/ ^! v1 K6 N' ?7 b. [6 q/ @

  36. 1 d3 S' x/ Z$ z5 q  I6 H# R
  37.     LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)( Z7 Y& H# Z! x! V( F6 }$ ?
  38.     LDR     R1, =NVIC_PENDSVSET
    2 i, Y1 s& D' e2 a# m# B
  39.     STR     R1, [R0]
    ) S  q9 p/ @$ z1 s; ~3 y: X
  40. 7 p! O0 V3 T$ v( q$ [2 K5 Q
  41.     CPSIE   I                                                   ; Enable interrupts at processor level9 z: v$ g8 h- M/ O* F, A

  42. 2 f! S0 q! \# x
  43. OSStartHang
    # t3 m9 z" p; Y1 {- J
  44.     B       OSStartHang                                         ; Should never get here
    + I' P6 j  Z; G5 u; S1 A; w
  45.    
    1 @1 A, A  X) {- @: T; P
  46.    
    7 j, {3 c; x" J# _& _, T
  47. ( R7 {; `4 c, |# Y4 C
  48. PendSV_Handler
    6 ~/ Q* s7 W+ Y+ P+ H" U9 t
  49.     CPSID   I                                                   ; Prevent interruption during context switch( a8 x6 N' E8 g* n9 m8 U4 c3 Y+ X' n
  50.     MRS     R0, PSP                                             ; PSP is process stack pointer* Z9 ^9 D/ X5 h% D& k) N6 j7 P4 [
  51.     CBZ     R0, OS_CPU_PendSVHandler_nosave                     ; Skip register save the first time. A$ m3 r9 G2 W* I- f; j9 h
  52.    ! o4 [4 `# O, w5 ~* R5 s- p* o# g
  53.     SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack4 `% [4 [7 i5 A% z7 z: h
  54.     STM     R0, {R4-R11}
    ( p( ]( p$ L4 V1 t
  55. - ?5 R* _, I, t" \; k
  56.     LDR     R1, =g_OS_Tcb_CurP                                       ; OSTCBCur->OSTCBStkPtr = SP;
    $ f4 t3 M- {! c" G6 J2 ~7 G8 c
  57.     LDR     R1, [R1]
    # H6 g5 D% d- {: H. b4 L2 ?& H! b8 `
  58.     STR     R0, [R1]                                            ; R0 is SP of process being switched out' D# m4 D% q8 f  |& |

  59.   m% D8 V" _- u" Y0 [1 i
  60.                                                                 ; At this point, entire context of process has been saved. u) ~' g: ?9 e& @! P; ~6 U# ]
  61. OS_CPU_PendSVHandler_nosave8 o; O! d: H" r5 @2 C1 A0 C% ?
  62.     LDR     R0, =g_OS_Tcb_CurP                                       ; OSTCBCur  = OSTCBHighRdy;
    # G( J) r  [) T5 H: @% c1 `; x
  63.     LDR     R1, =g_OS_Tcb_HighRdyP
    - W. U; c! `# d& Y' t0 C4 z
  64.     LDR     R2, [R1]
    2 w. v: E& j, z. h3 O! C
  65.     STR     R2, [R0]' b) S6 T- K% I5 {

  66. 1 `+ X4 ^0 _, o  H( }0 ]! q. O
  67.     LDR     R0, [R2]                                       ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
    - n' o4 _* E. C2 O  F
  68.   0 ^; Y% V1 N* }: X
  69.     LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack
    , D5 }2 z. z0 R
  70.     ADDS    R0, R0, #0x20% N8 r8 c. x! H$ ]6 }3 G
  71.             
    " Z+ r! r) m' j* b# g4 W0 D
  72.     MSR     PSP, R0                                             ; Load PSP with new process SP
    8 |6 s! D( R: V! T2 P) o
  73.     ORR     LR, LR, #0x04                                       ; Ensure exception return uses process stack; `- w; I$ S9 v
  74.     ! A3 W7 R0 j9 z3 d+ l
  75.     CPSIE   I2 c9 D; @) P5 ?; y7 [- z& D3 [
  76.     BX      LR                                                  ; Exception return will restore remaining context
    ! z8 i$ o# D5 ^: }
  77.   9 p$ T; I$ q. C3 V' K& I7 ~! k. S
  78.     END
复制代码

: Y6 \& c" J5 Q
main.c内容如下:
  1. #include "stdio.h"8 n$ C- t) Q4 \* L
  2. #define OS_EXCEPT_STK_SIZE 1024
      O. @5 G7 n+ g5 c2 g, ^9 P
  3. #define TASK_1_STK_SIZE 1024
    ) n& W) o* x  x
  4. #define TASK_2_STK_SIZE 1024
    2 e. p# m* O( F  K, ?' h

  5. + E  W2 @/ v$ u( Q3 x
  6. typedef unsigned int OS_STK;% g8 |* b9 \4 [% }' D* j$ _  w
  7. typedef void (*OS_TASK)(void);  W1 [4 p8 n: L- Q2 w

  8. . y& t8 i6 R! B1 Q
  9. typedef struct OS_TCB" k" s" B& H5 N! b
  10. {
    ; S& c* ]4 e9 j  \9 E# j( \; d
  11.   OS_STK *StkAddr;# ?2 Z4 n& A0 {1 `, }, U
  12. }OS_TCB,*OS_TCBP;. C' k5 E5 z( O4 X' |6 t0 v
  13. ' R4 o5 R4 v1 T3 j7 E9 ?
  14. + O7 L5 |" b* e4 V# S6 L' m" [
  15. OS_TCBP g_OS_Tcb_CurP; / ^7 ^0 w0 L; ^  K) {
  16. OS_TCBP g_OS_Tcb_HighRdyP;
    ' I# S5 |1 [5 m  n8 ^

  17.   w5 N4 X1 n# s, f3 v+ u: S5 ]4 u
  18. static OS_STK OS_CPU_ExceptStk[OS_EXCEPT_STK_SIZE];/ x/ Y5 B5 X+ i2 b! h7 \
  19. OS_STK *g_OS_CPU_ExceptStkBase;( z% k7 D3 y7 n+ h# `; v3 F
  20. ! Z7 [- O! M% H3 C  V, G7 i! m
  21. static OS_TCB TCB_1;" Z# s" F3 F: T
  22. static OS_TCB TCB_2;* K. v( O) Y% O# l
  23. static OS_STK TASK_1_STK[TASK_1_STK_SIZE];3 T: P8 J, ^( y5 v
  24. static OS_STK TASK_2_STK[TASK_2_STK_SIZE];
    ; O% @, i: M+ l( i& z& b

  25. * k# X0 V3 h; U! E- ^6 d6 ]) D
  26. extern void OSStart_Asm(void);
    3 _& C, ]7 [# v1 J& l) ]9 o
  27. extern void OSCtxSw(void);- f6 T, F8 [' B3 b+ J5 h3 ]) p1 |, |

  28. % x+ ?  t) n/ \0 d
  29. void Task_Switch()6 T8 |) `" Z: |8 f& m$ A
  30. {
    # e/ }4 a" k0 u0 R
  31.   if(g_OS_Tcb_CurP == &TCB_1)
    6 t+ E0 j. _# S, A7 h7 r
  32.     g_OS_Tcb_HighRdyP=&TCB_2;
    2 H9 x! D% L+ }# I
  33.   else
    2 U/ V1 h' u0 ?  K
  34.     g_OS_Tcb_HighRdyP=&TCB_1;; q" ~4 W% y0 W" z

  35. . B( v, {2 n* E
  36.   OSCtxSw();- l$ x# c% d3 T4 @6 T3 _# R! j
  37. }
    % }) z' W) f+ U$ D$ S9 s6 W

  38. 1 {. I. e5 V) M4 D
  39. ) {3 C1 U& r) @8 D6 ^
  40. void task_1()
    & l+ W; m' J) z- z
  41. {
    ! v2 ~0 x2 }- h7 k$ N: `. u- L
  42.   printf("Task 1 Running!!!\n");
    + L$ K1 {4 W% c9 A
  43.   Task_Switch();
    , l5 x& ^+ g$ b7 c6 W
  44.   printf("Task 1 Running!!!\n");
    7 W3 K* v# d3 q; m+ j
  45.   Task_Switch();
    ; Y6 s+ F0 O/ q4 G6 o# J
  46. }. J- m, ]# @" p% g/ Y. F! V4 \! n

  47. ; D8 R+ d0 [  L9 }) H
  48. void task_2()4 j; V5 S1 s) Q
  49. {3 z' Q) c1 |0 R7 x0 U
  50.   
    . G" U  p. r9 z5 z$ A) B# m
  51.   printf("Task 2 Running!!!\n");
    % P$ A6 a; I* J6 }4 D3 d
  52.   Task_Switch();. H, ], m/ o; P. P+ F; U) Y
  53.   printf("Task 2 Running!!!\n");
    % F* ^+ F* @: T6 O( h5 e5 v8 }  v1 j
  54.   Task_Switch();
    4 z8 i% ?) B/ t5 I# U
  55. }
    0 z, C, @$ l1 f# r8 f! V$ c  P$ @; ~
  56. & A0 L8 ~# w  l6 J3 B; K2 U6 Y
  57. void Task_End(void)1 }3 c% [' E, s3 N# m( M% O' x
  58. {$ F2 X; j: ], h: E$ m# ~9 J- T# v8 y
  59.   printf("Task End\n");
    - `4 E1 \0 H. s+ l
  60.   while(1)
    % _" e* @  j6 G! ~. T5 t
  61.   {}# Y+ x& y# p: i$ T1 }0 l
  62. }
    1 {" d0 X; s: E1 R2 q

  63. * K! [/ Y9 }$ Q  i8 K/ f
  64. void Task_Create(OS_TCB *tcb,OS_TASK task,OS_STK *stk)
    & q6 b9 E, J2 f8 F
  65. {; ^8 M7 a* m% Z9 G4 O9 \5 a
  66.     OS_STK  *p_stk;& d8 f9 Y( H* X( K0 a1 z
  67.     p_stk      = stk;
    , W7 k  ^, x# c/ h7 C) `) K3 x# W9 f
  68.     p_stk      = (OS_STK *)((OS_STK)(p_stk) & 0xFFFFFFF8u);# e3 K# Q- S8 c2 V
  69.    
    / w( a$ G6 D' v: W; z
  70.     *(--p_stk) = (OS_STK)0x01000000uL;                          //xPSR
    / q# E+ O2 P# [3 O; c
  71.     *(--p_stk) = (OS_STK)task;                                  // Entry Point
    ( U2 W6 [4 z/ Y) a, K
  72.     *(--p_stk) = (OS_STK)Task_End;                                     // R14 (LR)
    * g  |+ u7 o5 T3 |4 p
  73.     *(--p_stk) = (OS_STK)0x12121212uL;                          // R125 `# i' Q/ |2 M6 ]6 x
  74.     *(--p_stk) = (OS_STK)0x03030303uL;                          // R3. Q# m# t% d4 z' G" m
  75.     *(--p_stk) = (OS_STK)0x02020202uL;                          // R24 ?8 D  C. J# v7 d
  76.     *(--p_stk) = (OS_STK)0x01010101uL;                          // R17 f' l6 s) a' E$ Q
  77.     *(--p_stk) = (OS_STK)0x00000000u;                           // R0
    : p) w; m( @( F) a% O# E
  78.     & l! d3 t- O/ [" Y* H9 Y& [
  79.     *(--p_stk) = (OS_STK)0x11111111uL;                          // R11
    , K0 M+ ~7 _# u) w7 M$ e$ |
  80.     *(--p_stk) = (OS_STK)0x10101010uL;                          // R10
    , p# d# A" a0 d: F7 ~: M
  81.     *(--p_stk) = (OS_STK)0x09090909uL;                          // R9& ?1 J( A2 s. ]# R6 U' G1 W
  82.     *(--p_stk) = (OS_STK)0x08080808uL;                          // R8
    1 Q2 e, N+ r/ x/ p" _" G, U$ @
  83.     *(--p_stk) = (OS_STK)0x07070707uL;                          // R7
    0 \2 F" f$ {- R$ F- N: ?5 r
  84.     *(--p_stk) = (OS_STK)0x06060606uL;                          // R6
    . J8 ?' H; a  [4 ^5 M) e
  85.     *(--p_stk) = (OS_STK)0x05050505uL;                          // R5
    : s/ T4 j% ]' O. i7 M  `
  86.     *(--p_stk) = (OS_STK)0x04040404uL;                          // R4" C& X' f) P, \
  87.     + Z1 Z" E6 |8 e1 N' c& V
  88.     tcb->StkAddr=p_stk;' ?2 A4 I& L; N; i; H8 q
  89. }
    4 r1 ~& Z. U/ L& I9 h3 D5 N# v

  90. $ ?' u* z6 S9 M: g: H9 M; ^

  91. ( v5 v! f1 U5 {; O+ G, S/ e7 O* v; \
  92. int main()
    , f9 _, ?' L- l8 j
  93. {  \7 O, T% u; d  a* T0 m
  94.   
    3 q- i0 d) R( ]; |' Y
  95.   g_OS_CPU_ExceptStkBase = OS_CPU_ExceptStk + OS_EXCEPT_STK_SIZE - 1;
    ; N5 ~# r) f  j1 l7 |/ a& O
  96.   
    , k5 Q8 l! K0 |. ]4 ]$ y' g
  97.   Task_Create(&TCB_1,task_1,&TASK_1_STK[TASK_1_STK_SIZE-1]);, E; r0 d# p# t6 [
  98.   Task_Create(&TCB_2,task_2,&TASK_2_STK[TASK_1_STK_SIZE-1]);
    5 f0 C3 L( D3 I; z2 k# Z8 `/ u* }
  99.     5 `7 c( }" a3 K( E
  100.   g_OS_Tcb_HighRdyP=&TCB_1;9 f8 H1 l3 C4 W
  101.   : a8 b2 o+ w) G, O" T
  102.   OSStart_Asm();. ^% _; X: o, o' F
  103.   
    " L7 D: ^- |( E0 T. P3 E& k  r5 N  B
  104.   return 0;
    + Y7 ]/ ?8 v; T  t
  105. }
复制代码

# m% l; |; T, ]
编译下载并调试:

# Q6 u+ p% r! {; m
02143746-b3794508e0a644a09cf863ef3da935ed.jpg

4 |' f' q1 P9 E% p
在此处设置断点
此时寄存器的值,可以看到R4-R11正是我们给的值,单步运行几次,可以看到进入了我们的任务task_1或task_2,任务里打印信息,然后调用Task_Switch进行切换,OSCtxSw触发PendSV异常。

! m$ I% H" Q9 V& e
02143747-3c53018b89dc48bb97ef1b9761c698ca.png

' S( c0 b0 d+ [  e' x
IO输出如下:

2 ^9 T1 e6 d( O) W* @. M1 V; m' a
02143748-2d79fed2fb1e43c2bb90024f7679b5bd.jpg
. K$ O: X9 U6 H8 E+ _
至此我们成功实现了使用PenSV进行两个任务的互相切换。之后,我们使用使用SysTick实现比较完整的多任务切换。

- s8 {. ^# B. i8 l" W" h
收藏 评论0 发布时间:2022-1-16 18:03

举报

0个回答

所属标签

相似分享

官网相关资源

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