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

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

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

OS 可以利用它“缓期执行”一个异常——直到其它重要的任务完成后才执行动 作。悬起 PendSV 的方法是:手工往 NVIC的 PendSV悬起寄存器中写 1。悬起后,如果优先级不够 高,则将缓期等待执行。
PendSV的典型使用场合是在上下文切换时(在不同任务之间切换)。例如,一个系统中有两个就绪的任务,上下文切换被触发的场合可以是:
7 d- L; b( L. [: @/ w1、执行一个系统调用/ x' R4 E: t$ E. H' [* g3 e* b
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_PendSVHandler
    3 b3 R# m1 V0 k4 R: \- S* Z) e3 }. E
  2.     CPSID I ; 关中断$ p* b5 p5 x- y  r! `& G
  3.     ;保存上文 $ R, C1 V& N$ A1 [) O  p! E
  4.     ;....................... , [- ^+ D- j( R1 P  Q
  5.     ;切换下文 8 t( Z( b6 S& [0 }( `: I3 }! h
  6.     CPSIE I ;开中断
    # Y7 `" Q9 U' T. R# f7 v
  7.     BX LR ;异常返回
复制代码
& m, }* x0 C2 @. S# Q& n
它在异常一开始就关闭了中端,结束时开启中断,中间的代码为临界区代码,即不可被中断的操作。PendSV异常是任务切换的堆栈部分的核心,由他来完成上下文切换。PendSV的操作也很简单,主要有设置优先级和触发异常两部分:
  1. NVIC_INT_CTRL EQU 0xE000ED04 ; 中断控制寄存器/ a  i/ [" P5 s" p
  2. NVIC_SYSPRI14 EQU 0xE000ED22 ; 系统优先级寄存器(优先级14). ) b. ~2 T$ a8 t& v1 N8 u* g
  3. NVIC_PENDSV_PRI EQU 0xFF ; PendSV优先级(最低). NVIC_PENDSVSET EQU 0x10000000 ; PendSV触发值, {4 ^( [/ z. n3 [3 k+ V
  4. " m8 w8 h, \9 G- t; ~6 e' @
  5. ; 设置PendSV的异常中断优先级
    ; e! V- u) c/ _/ }6 B- o9 ?! H

  6. 2 l: C- E6 L  t* n( m0 P
  7. LDR R0, =NVIC_SYSPRI14 ) E. X: ^/ t9 [# T
  8. LDR R1, =NVIC_PENDSV_PRI # i* n) E) H# c1 q
  9. STRB R1, [R0] ; 触发PendSV异常
    & |8 x: o) ?% @; P+ Y( i& X1 f( U
  10. LDR R0, =NVIC_INT_CTRL ) {( u$ v& Y9 j5 [4 v( w: \) N5 P2 p
  11. LDR R1, =NVIC_PENDSVSET
    4 u6 u" q, Y" p# k, `, }: p8 j
  12. STR R1, [R0]
复制代码

: h0 n; p: h2 T8 X9 t1 T
二、堆栈操作
Cortex M4有两个堆栈寄存器,主堆栈指针(MSP)与进程堆栈指针(PSP),而且任一时刻只能使用其中的一个。MSP为复位后缺省使用的堆栈指针,异常永远使用MSP,如果手动开启PSP,那么线程使用PSP,否则也使用MSP。怎么开启PSP?
  1. MSR     PSP, R0                                             ; Load PSP with new process SP
    ; [9 s3 C, m0 \  |2 X
  2.     ORR     LR, LR, #0x04                                   ; Ensure exception return uses process stack
复制代码

' A3 ~) X* T  e* E% H. n9 z- R. K
很容易就看出来了,置LR的位2为1,那么异常返回后,线程使用PSP。
写OS首先要将内存分配搞明白,单片机内存本来就很小,所以我们当然要斤斤计较一下。在OS运行之前,我们首先要初始化MSP和PSP,
  1. EXTERN  OS_CPU_ExceptStkBase) J; N% b* m# x0 i0 o0 O! ~3 a
  2.    ;PSP清零,作为首次上下文切换的标志
    " M4 q. P- A8 r" \9 d: j" E- i
  3.    MOVS    R0, #0
    + _+ A! F3 ?3 ]
  4.    MSR     PSP, R0
    % i  u: n* m2 ?4 v, f
  5.    ;将MSP设为我们为其分配的内存地址0 B2 V+ W+ W, M; V
  6.    LDR     R0, =OS_CPU_ExceptStkBase
    ; P* t" `7 p5 G0 @. D; }
  7.    LDR     R1, [R0]) J9 @. c, r1 M' t. y" d# W
  8.    MSR     MSP, R1
复制代码

* T: U" ?, j" ^
然后就是PendSV上下文切换中的堆栈操作了,如果不使用FPU,则进入异常自动压栈xPSR,PC,LR,R12,R0-R3,我们还要把R4-R11入栈。如果开启了FPU,自动压栈的寄存器还有S0-S15,还需吧S16-S31压栈。
  1. MRS     R0, PSP
    8 L$ r0 |7 Z$ d7 V* q) S
  2.     SUBS   R0, R0, #0x20        ;压入R4-R116 Z) z6 }8 Q7 S# u. ^" A9 C/ Z
  3.     STM     R0, {R4-R11}
    4 i# I2 i6 M0 x& l5 J0 o7 k2 t6 {
  4. 6 m% |5 e! Z( ~, Q/ E. [7 u
  5.     LDR     R1, =Cur_TCB_Point    ;当前任务的指针
    ! _4 h" k7 X0 L1 Z! q4 B* o: Z, f
  6.     LDR     R1, [R1]
    8 R1 s9 J6 @* n4 v
  7.     STR     R0, [R1]            ; 更新任务堆栈指针
复制代码
5 ^* d% Y6 y$ P- P; C
出栈类似,但要注意顺序
  1. LDR     R1, =TCB_Point    ;要切换的任务指针
    % O2 g1 E: x6 ?6 d1 g  c5 _
  2.     LDR     R2, [R1]
    * g2 c9 r4 w: u5 X& Z. a2 F9 O. V
  3.     LDR     R0, [R2]          ; R0为要切换的任务堆栈地址- B( L' o" l; u
  4.   * F2 f+ x. W+ I, K. D
  5.     LDM     R0, {R4-R11}     ; 弹出R4-R11& g# a3 p$ q& H' A
  6.     ADDS    R0, R0, #0x20/ l2 @1 y6 i9 e5 o

  7. ! Z4 f7 M# d: _. d; G7 B
  8.     MSR     PSP, R0        ;更新PSP
复制代码
* D' K( M! m! o- J+ K
三、OS实战
新建os_port.asm文件,内容如下:
  1. NVIC_INT_CTRL   EQU     0xE000ED04                              ; Interrupt control state register." l1 t; \0 i/ W
  2. NVIC_SYSPRI14   EQU     0xE000ED22                              ; System priority register (priority 14).
      V- R3 W: e- ~. A
  3. NVIC_PENDSV_PRI EQU           0xFF                              ; PendSV priority value (lowest).9 j- k- Y: A  [8 T
  4. NVIC_PENDSVSET  EQU     0x10000000                              ; Value to trigger PendSV exception.
    ! {8 P# |! Z$ r0 \( c( t. P

  5. 5 r) V! J0 y8 |5 J' ^7 i
  6.   RSEG CODE:CODE:NOROOT(2)
    4 b+ j9 {) a, J
  7.   THUMB
    8 V/ U5 b& q4 H4 G- ]* \: a" p

  8. 1 R! S+ g0 K+ \4 s7 @) D$ X) ~, v

  9. ' d$ f- c. j% Z9 d" f* a
  10.   EXTERN  g_OS_CPU_ExceptStkBase8 r) x8 Z6 I6 ~  M
  11.   
    / q/ ]/ @5 V# s; N$ Z3 e
  12.   EXTERN  g_OS_Tcb_CurP. e7 [0 Z* n; k- f2 M7 M/ ^3 b' X
  13.   EXTERN  g_OS_Tcb_HighRdyP, h1 n4 p- X* Y% `- d
  14. ( c& B" l& {' F& r- `; d9 c( E
  15.   PUBLIC OSStart_Asm: ?* g4 S4 ?) ~* u4 v' Y' G/ q
  16.   PUBLIC PendSV_Handler
    & ?( x! I! A3 g. d# u
  17.   PUBLIC OSCtxSw
    ' |' w9 V  J- N7 t2 L" v$ L

  18. 7 I4 B2 B: m# H" K& B
  19. OSCtxSw
    1 Z2 v+ S$ z3 {" }: D
  20.     LDR     R0, =NVIC_INT_CTRL
    $ h; M; \% b  X# F3 N
  21.     LDR     R1, =NVIC_PENDSVSET
    # Q6 K4 d  t5 y, @/ Q; H0 @8 E
  22.     STR     R1, [R0]0 g& l- A" i( b8 W
  23.     BX      LR                                                ; Enable interrupts at processor level
    0 j2 z" ^$ H! R, H

  24. 6 U2 S! @' g; T& ~/ U7 B- T
  25. OSStart_Asm$ t. e0 x0 \9 d( v, h
  26.     LDR     R0, =NVIC_SYSPRI14                                  ; Set the PendSV exception priority6 A3 C% x4 J  _2 w! r2 Z
  27.     LDR     R1, =NVIC_PENDSV_PRI
      H' f* [4 l' o, x# m1 v
  28.     STRB    R1, [R0]! `# K+ T2 s! ?
  29. ( D+ T. g) ?$ y1 D3 Q; D
  30.     MOVS    R0, #0                                              ; Set the PSP to 0 for initial context switch call) W& k. N- z& _9 n
  31.     MSR     PSP, R0- b8 g& B% n8 H& N# u1 T3 F& j$ L

  32. : j0 U8 I* r  S
  33.     LDR     R0, =g_OS_CPU_ExceptStkBase                           ; Initialize the MSP to the OS_CPU_ExceptStkBase
    3 [) S+ `, z% t2 @
  34.     LDR     R1, [R0]
      {/ u5 D& R4 s3 A
  35.     MSR     MSP, R1   
    ! n4 P5 g5 D% h# F* E# x3 n! G

  36. 0 x% ~2 t2 R; X6 T/ ?" h, L6 P& b
  37.     LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)
    ( F6 C) g; Y! e  [7 Q' Z
  38.     LDR     R1, =NVIC_PENDSVSET
    5 K" I  J" s9 m
  39.     STR     R1, [R0]
    # ^3 M/ J* K5 W" t/ `& @
  40. ( r/ y& g6 b: v1 v: J
  41.     CPSIE   I                                                   ; Enable interrupts at processor level' z$ A% }7 I3 p3 H' e8 M
  42. ) }& L  ?5 t  T3 l7 c8 |
  43. OSStartHang8 c6 U% k# q8 i; b9 Z; j
  44.     B       OSStartHang                                         ; Should never get here
    $ X( L8 v# U: d9 c4 R
  45.    
    - f: f: }" ]  p4 A1 m% j- G
  46.       s  x% g& I; R, C; V9 X4 {

  47. 7 z# w9 g3 c6 w
  48. PendSV_Handler) {( F- [' P  e2 P7 p" ^! c$ Z7 Z
  49.     CPSID   I                                                   ; Prevent interruption during context switch$ m7 j+ D4 {$ U, y
  50.     MRS     R0, PSP                                             ; PSP is process stack pointer
      R# A4 E8 i, G- r
  51.     CBZ     R0, OS_CPU_PendSVHandler_nosave                     ; Skip register save the first time
    - K5 m; G* K) P2 d
  52.    
    $ V1 K9 ?/ i0 ?5 A5 f) H2 ?
  53.     SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack6 e3 R9 K( t* `0 X4 G. b. G% d
  54.     STM     R0, {R4-R11}9 E+ c$ S3 X2 p8 o4 o
  55. ; M) w7 Y. ]! k" K+ `
  56.     LDR     R1, =g_OS_Tcb_CurP                                       ; OSTCBCur->OSTCBStkPtr = SP;
    & q1 V" |7 K" ?. X- [2 w, C$ d
  57.     LDR     R1, [R1]
      V% @! {* e9 Y- L" _9 G
  58.     STR     R0, [R1]                                            ; R0 is SP of process being switched out+ @* P  D6 i5 Y  o) }4 w0 t! T9 f

  59. 4 |& w( `6 e: v% `5 H
  60.                                                                 ; At this point, entire context of process has been saved4 b" Y2 s" A! U4 s
  61. OS_CPU_PendSVHandler_nosave" H" d4 w% w5 {$ o, Y) @
  62.     LDR     R0, =g_OS_Tcb_CurP                                       ; OSTCBCur  = OSTCBHighRdy;
    1 q, D& P4 U7 i3 }& a4 x9 H+ a
  63.     LDR     R1, =g_OS_Tcb_HighRdyP! w; P% T7 T3 Z( y3 d, A' L0 y( H
  64.     LDR     R2, [R1]
    / L$ J  D8 {) }- g$ o
  65.     STR     R2, [R0]
    / Y& U1 R; _$ \: c8 T8 r
  66. - S( d+ M4 u. Z' h. q4 C$ I: A
  67.     LDR     R0, [R2]                                       ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;% p( o; \$ q$ ^+ B+ ?; @1 l; I
  68.   ' R$ \0 l1 I/ P' _
  69.     LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack
    2 R% Q* t2 E. Y% r' D
  70.     ADDS    R0, R0, #0x20
    ( x5 N+ I& U) d/ v0 D& i5 m& p
  71.             
    9 P& U* ?) T+ H: G! u7 w; `+ F) u
  72.     MSR     PSP, R0                                             ; Load PSP with new process SP
    - j' J, g  x0 I& A- ]; K  }
  73.     ORR     LR, LR, #0x04                                       ; Ensure exception return uses process stack
    ) ?0 o) h( Y* r$ S
  74.    
    9 j) N  D- }! \/ @0 u4 k) H9 z5 E
  75.     CPSIE   I
    & \$ }" m8 ~1 s% x0 H4 D' h
  76.     BX      LR                                                  ; Exception return will restore remaining context8 q/ Z1 v# d. f! a9 q2 @: x
  77.   
    9 W8 ~- U" a% }
  78.     END
复制代码
- @; s) a( i! c4 j
main.c内容如下:
  1. #include "stdio.h"
    0 q" U4 U& _6 T; X; G
  2. #define OS_EXCEPT_STK_SIZE 10244 I. j) ~6 l6 b+ N7 }3 A
  3. #define TASK_1_STK_SIZE 1024
    # ]1 a: D6 s2 r, d
  4. #define TASK_2_STK_SIZE 1024
    5 d+ i: U% ^- X+ L  f+ a2 i
  5. : c& @& q, k( c' U6 W; l7 u7 j
  6. typedef unsigned int OS_STK;; t7 q" V, _4 g2 v
  7. typedef void (*OS_TASK)(void);
      v8 \6 l4 k0 U& n* |
  8. ' i8 p- W, G6 w
  9. typedef struct OS_TCB
    % a) q+ o& K( z9 M5 P
  10. {
    ' k2 o4 }) M  h+ ^3 Y6 e( Y( m/ c
  11.   OS_STK *StkAddr;
    ! q+ ~/ K4 H% Z3 u+ B
  12. }OS_TCB,*OS_TCBP;
    % ^4 p, f, p! X3 G' E$ h

  13. & X  h' M% f1 F1 b( n, `  Z
  14. 0 Y# E5 t" P6 o) V0 s: `; ~( f
  15. OS_TCBP g_OS_Tcb_CurP; % f, K! |/ o% `  G
  16. OS_TCBP g_OS_Tcb_HighRdyP;2 D& f% ^/ I. f
  17. " I/ R: v+ s# S
  18. static OS_STK OS_CPU_ExceptStk[OS_EXCEPT_STK_SIZE];4 Z* H! m8 q' m3 X4 L
  19. OS_STK *g_OS_CPU_ExceptStkBase;7 Q; E3 e6 X+ O6 [# |8 J
  20. ' i# c( G" N! X: A# B7 L1 E
  21. static OS_TCB TCB_1;
    ; O2 }- y/ s3 X
  22. static OS_TCB TCB_2;
    4 Z4 u" b/ ^$ B: e+ z7 r
  23. static OS_STK TASK_1_STK[TASK_1_STK_SIZE];
    ( W, O0 d2 l' M* i! i5 [0 J- o
  24. static OS_STK TASK_2_STK[TASK_2_STK_SIZE];1 q# _/ q$ H  O- C3 ~) c

  25. ) v7 ]% n* p3 m- `% W, }2 C6 j
  26. extern void OSStart_Asm(void);
    " X7 k0 \7 y5 j6 B- |/ q: }7 `
  27. extern void OSCtxSw(void);
    0 o9 f7 ~: b7 z6 q+ e  E: U* H) p
  28.   G1 q! n4 F- e0 s
  29. void Task_Switch()# a" ^  p4 ]! T0 E' @6 k
  30. {
    ( U. [+ y' t! M/ K: a* Z9 P
  31.   if(g_OS_Tcb_CurP == &TCB_1)( V8 L$ ?! N; ?" a$ N) }0 J6 n+ J
  32.     g_OS_Tcb_HighRdyP=&TCB_2;* \1 s! y0 d' h' B. Y/ y
  33.   else
    2 s  T. Z8 n  I% ?% v
  34.     g_OS_Tcb_HighRdyP=&TCB_1;9 _1 @  q8 K8 `( z: A- c

  35. 3 F& v# c5 Q) W8 D; n& v, `
  36.   OSCtxSw();
    9 H; s% e. z+ k5 S9 Q6 _
  37. }+ q/ K, v7 i6 H( {2 v
  38.   A  W% N% s/ E  w
  39.   D8 N. ]5 q( i9 b  a$ }
  40. void task_1()
    6 P) c& _& S  z# T( u# s# g' Y
  41. {
    ! P" y& O* x5 b  i7 p7 {+ l
  42.   printf("Task 1 Running!!!\n");5 @2 Y; k# K# E; Q+ h- q; ~
  43.   Task_Switch();2 f$ `) B, C  @# M4 |7 ?) e
  44.   printf("Task 1 Running!!!\n");
    , G% f4 J/ T$ Z
  45.   Task_Switch();
    5 y- \4 P9 Z9 q# i
  46. }4 H3 \1 q" U3 W" ?

  47. 0 q7 B  }' W/ o1 ?
  48. void task_2()7 ~& `# l: a9 Y
  49. {
    * W4 c' {& Q! Y' h" o3 \( H
  50.   
    ! L; N3 z0 ?2 Y% G8 T: o
  51.   printf("Task 2 Running!!!\n");0 R" h0 ]2 M4 f# M' i) m5 n
  52.   Task_Switch();
    - u' A3 o9 z6 j" D7 C, ^
  53.   printf("Task 2 Running!!!\n");
    4 w0 n8 Q3 z' D) t
  54.   Task_Switch();' i0 G* J8 r5 F7 s+ ~
  55. }, q; a9 T: u' m0 e* l

  56.   ~0 f+ z, v) l/ ~5 F2 z
  57. void Task_End(void)8 ]- Y. S" D8 d5 i( m  E
  58. {/ Z) d, e1 V( X, u9 s* r
  59.   printf("Task End\n");
    # E3 ^, O0 P9 }: G1 g) G
  60.   while(1)
    % E9 V: A1 t5 R6 [4 K
  61.   {}
    0 |" k9 \5 s" r" Q% h+ W
  62. }. n6 E; e; e$ ]5 m- N

  63. 8 p; `! U8 `- o- @. q
  64. void Task_Create(OS_TCB *tcb,OS_TASK task,OS_STK *stk)
    - x. P& |- o9 _
  65. {
    8 u9 L5 @# n% G. J" ^7 @5 q
  66.     OS_STK  *p_stk;
    ) k- j- K0 k  ]4 D* g
  67.     p_stk      = stk;
    - |* \+ K5 m" {8 S: T  w
  68.     p_stk      = (OS_STK *)((OS_STK)(p_stk) & 0xFFFFFFF8u);) n& h5 R0 z8 z3 m5 q8 }- @. O0 a
  69.     & k9 P% g7 c: A: _
  70.     *(--p_stk) = (OS_STK)0x01000000uL;                          //xPSR: C& p/ @) _/ Z5 P" y. a
  71.     *(--p_stk) = (OS_STK)task;                                  // Entry Point
    : u& i7 p, P- P+ t
  72.     *(--p_stk) = (OS_STK)Task_End;                                     // R14 (LR)3 S  q% q- W. p8 X# ~
  73.     *(--p_stk) = (OS_STK)0x12121212uL;                          // R12! w2 D8 ~9 j! F3 f, e/ c: l
  74.     *(--p_stk) = (OS_STK)0x03030303uL;                          // R3, t& x( S" g4 c# t. w. W5 \
  75.     *(--p_stk) = (OS_STK)0x02020202uL;                          // R23 R0 H; `  i+ S  @4 m! P& X8 o' _" p; t; X
  76.     *(--p_stk) = (OS_STK)0x01010101uL;                          // R1
    6 I6 n+ @3 R! U( N/ L' _
  77.     *(--p_stk) = (OS_STK)0x00000000u;                           // R0
    # g( N' N5 }  ~& i; U8 n
  78.    
    7 z: R' Z3 F; A! I, ^( u! Y
  79.     *(--p_stk) = (OS_STK)0x11111111uL;                          // R11
    9 M) l3 t- R" v8 w
  80.     *(--p_stk) = (OS_STK)0x10101010uL;                          // R10( }, m3 e1 N: `9 r! Q
  81.     *(--p_stk) = (OS_STK)0x09090909uL;                          // R9! I  ~- i" k4 f- E4 ^5 }6 D
  82.     *(--p_stk) = (OS_STK)0x08080808uL;                          // R85 e; K$ v$ ^( p  V/ g7 l( g
  83.     *(--p_stk) = (OS_STK)0x07070707uL;                          // R7
    7 g$ [" f6 K( d3 `7 |5 m* X
  84.     *(--p_stk) = (OS_STK)0x06060606uL;                          // R6( k0 y! ^& A. I. Q+ M
  85.     *(--p_stk) = (OS_STK)0x05050505uL;                          // R5: G9 k5 A7 `" X1 |" |
  86.     *(--p_stk) = (OS_STK)0x04040404uL;                          // R4, D. R7 ?  F# F0 L
  87.    
    * X2 \6 H; ]+ M4 ~% o
  88.     tcb->StkAddr=p_stk;
    ( ~5 r5 o# t, v% j# N
  89. }
    # o1 v$ M0 P! ]

  90. 6 X7 A% y" ]$ b2 }
  91. ) q8 o+ o6 N( q
  92. int main()" o1 ]! `5 n% u- H% S
  93. {
    8 w" e7 }6 A6 Y0 d
  94.   & Q+ y0 i0 w7 q2 \) z& ^
  95.   g_OS_CPU_ExceptStkBase = OS_CPU_ExceptStk + OS_EXCEPT_STK_SIZE - 1;5 G- N# }9 s: N6 }3 a; _# `3 h/ V% D# c
  96.   " h# K9 E* D  n/ N& g4 W) ~
  97.   Task_Create(&TCB_1,task_1,&TASK_1_STK[TASK_1_STK_SIZE-1]);. @. c  t6 P' n/ X! U% n
  98.   Task_Create(&TCB_2,task_2,&TASK_2_STK[TASK_1_STK_SIZE-1]);
    + j/ E+ H3 H: h, l+ p- ?- _: j
  99.    
    3 O! W+ f+ d" A3 j! d
  100.   g_OS_Tcb_HighRdyP=&TCB_1;- l) O5 }4 n; P: ^6 U
  101.   
    6 _$ u  e: Q2 |0 k! @
  102.   OSStart_Asm();, Q3 z" w7 T6 Y8 i8 H
  103.   
    * i- ?7 r4 O4 i3 A6 b  {
  104.   return 0;
    ! a% M7 g3 `2 C% v: |0 [3 t" x# c) B
  105. }
复制代码
. [6 l8 H# r9 A5 D6 x9 q2 Z
编译下载并调试:
0 u/ r* y5 |: Q( h4 g+ _3 F
02143746-b3794508e0a644a09cf863ef3da935ed.jpg
/ V0 g  Q9 f8 f8 N0 A
在此处设置断点
此时寄存器的值,可以看到R4-R11正是我们给的值,单步运行几次,可以看到进入了我们的任务task_1或task_2,任务里打印信息,然后调用Task_Switch进行切换,OSCtxSw触发PendSV异常。

6 z3 _9 E! X# [! P, M" F3 a- E7 p
02143747-3c53018b89dc48bb97ef1b9761c698ca.png
' H3 G6 n7 v: s- B
IO输出如下:

& |- b# {$ ~% X
02143748-2d79fed2fb1e43c2bb90024f7679b5bd.jpg
. ~7 u; j+ h+ E  G1 G0 E
至此我们成功实现了使用PenSV进行两个任务的互相切换。之后,我们使用使用SysTick实现比较完整的多任务切换。

- B' U3 K  x5 Y/ F) V
收藏 评论0 发布时间:2022-1-16 18:03

举报

0个回答

所属标签

相似分享

官网相关资源

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