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

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

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

OS 可以利用它“缓期执行”一个异常——直到其它重要的任务完成后才执行动 作。悬起 PendSV 的方法是:手工往 NVIC的 PendSV悬起寄存器中写 1。悬起后,如果优先级不够 高,则将缓期等待执行。
PendSV的典型使用场合是在上下文切换时(在不同任务之间切换)。例如,一个系统中有两个就绪的任务,上下文切换被触发的场合可以是:* V! j! {  f! _' {
1、执行一个系统调用5 \0 N4 Z$ J" y1 S! f: N  X
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
    * C4 b/ \" ?! _* }" n3 S
  2.     CPSID I ; 关中断6 |* h3 Q1 L/ u& C* ~% i
  3.     ;保存上文 1 _4 q6 b3 K8 m/ E
  4.     ;.......................
    ( ?7 l' U8 H0 F
  5.     ;切换下文
    ) |. ^5 h9 l4 V  L* X+ @
  6.     CPSIE I ;开中断
    ' q" J; m; h% r% l) _
  7.     BX LR ;异常返回
复制代码

( g; W+ k9 x2 h# V
它在异常一开始就关闭了中端,结束时开启中断,中间的代码为临界区代码,即不可被中断的操作。PendSV异常是任务切换的堆栈部分的核心,由他来完成上下文切换。PendSV的操作也很简单,主要有设置优先级和触发异常两部分:
  1. NVIC_INT_CTRL EQU 0xE000ED04 ; 中断控制寄存器
    - w& k) l+ Q0 G7 t2 `! l
  2. NVIC_SYSPRI14 EQU 0xE000ED22 ; 系统优先级寄存器(优先级14). 9 \8 E# s, U2 u4 u. R/ V7 H
  3. NVIC_PENDSV_PRI EQU 0xFF ; PendSV优先级(最低). NVIC_PENDSVSET EQU 0x10000000 ; PendSV触发值
    ) V% h$ q& Q4 k8 ]

  4. ' E3 {7 P! C9 z! W( |/ Y& B3 a
  5. ; 设置PendSV的异常中断优先级
    . A0 ?& }  H) p: W- j
  6. ; u& E; w( Y; b. g0 }- R+ s
  7. LDR R0, =NVIC_SYSPRI14 4 y5 a7 l( _3 {8 a6 h+ [/ H
  8. LDR R1, =NVIC_PENDSV_PRI
    - I, {. ^' k9 k4 ]
  9. STRB R1, [R0] ; 触发PendSV异常
    . L. {" o2 v4 o; {1 f
  10. LDR R0, =NVIC_INT_CTRL
    8 \  i5 U" p3 h4 @. Z3 T, D
  11. LDR R1, =NVIC_PENDSVSET
    & B- q: Y' m; S. I( r
  12. STR R1, [R0]
复制代码
' f. @5 j+ A1 w
二、堆栈操作
Cortex M4有两个堆栈寄存器,主堆栈指针(MSP)与进程堆栈指针(PSP),而且任一时刻只能使用其中的一个。MSP为复位后缺省使用的堆栈指针,异常永远使用MSP,如果手动开启PSP,那么线程使用PSP,否则也使用MSP。怎么开启PSP?
  1. MSR     PSP, R0                                             ; Load PSP with new process SP
    ! M1 l  Q. @' ?1 }; m! ?
  2.     ORR     LR, LR, #0x04                                   ; Ensure exception return uses process stack
复制代码
8 v4 r. V2 \8 G& C: w6 I/ h
很容易就看出来了,置LR的位2为1,那么异常返回后,线程使用PSP。
写OS首先要将内存分配搞明白,单片机内存本来就很小,所以我们当然要斤斤计较一下。在OS运行之前,我们首先要初始化MSP和PSP,
  1. EXTERN  OS_CPU_ExceptStkBase
    ! V& Q4 |* n: [& `; A2 i5 A
  2.    ;PSP清零,作为首次上下文切换的标志
    8 {: G1 V: A6 T5 f# ^; w4 f# |8 z
  3.    MOVS    R0, #0 ; {5 Z) Q  Z- s" W
  4.    MSR     PSP, R0
    . _: W: h& l' D! P3 Q' ~2 L
  5.    ;将MSP设为我们为其分配的内存地址* ?) L' G/ c& k" W; h$ j" p
  6.    LDR     R0, =OS_CPU_ExceptStkBase
    1 S) }. F5 `" e' R) o- I# c. z
  7.    LDR     R1, [R0]2 H5 D. x( J+ e# v: e7 M
  8.    MSR     MSP, R1
复制代码
4 {% Q4 `9 f' l1 i5 y6 i
然后就是PendSV上下文切换中的堆栈操作了,如果不使用FPU,则进入异常自动压栈xPSR,PC,LR,R12,R0-R3,我们还要把R4-R11入栈。如果开启了FPU,自动压栈的寄存器还有S0-S15,还需吧S16-S31压栈。
  1. MRS     R0, PSP* Q  }7 X" x/ z& x' x
  2.     SUBS   R0, R0, #0x20        ;压入R4-R11
    6 y# T' z. G* s- _, S
  3.     STM     R0, {R4-R11}  O* Q! q2 R: o8 H) a& k

  4. 3 n  M, n- G0 c6 Z' R# ~; m8 ?
  5.     LDR     R1, =Cur_TCB_Point    ;当前任务的指针
    / Q8 O" p! k5 q
  6.     LDR     R1, [R1]
    5 @2 ?7 k& O& {) d1 o6 H2 A
  7.     STR     R0, [R1]            ; 更新任务堆栈指针
复制代码

6 U7 j4 w* l+ ^' @2 F5 `* M' z
出栈类似,但要注意顺序
  1. LDR     R1, =TCB_Point    ;要切换的任务指针" O7 L% P. g4 E9 {& E# y1 M: o
  2.     LDR     R2, [R1]" {; q0 V) _3 j- x
  3.     LDR     R0, [R2]          ; R0为要切换的任务堆栈地址/ c7 g. c& B# M& t1 ?* S
  4.   3 r" t; V% T  o/ y
  5.     LDM     R0, {R4-R11}     ; 弹出R4-R11
      E5 x, p7 o' X6 s3 y. d4 X& I
  6.     ADDS    R0, R0, #0x207 H0 B, L! ^" Y. I* a: M6 g% ^
  7. 3 I& l! l1 o8 ?! z4 g1 z
  8.     MSR     PSP, R0        ;更新PSP
复制代码

# S0 i; k: S; c: a
三、OS实战
新建os_port.asm文件,内容如下:
  1. NVIC_INT_CTRL   EQU     0xE000ED04                              ; Interrupt control state register.; ^0 r" b; }; F; P, f% F' `
  2. NVIC_SYSPRI14   EQU     0xE000ED22                              ; System priority register (priority 14).8 C9 J9 Q  j3 b; M% h
  3. NVIC_PENDSV_PRI EQU           0xFF                              ; PendSV priority value (lowest).6 Z: y3 M' A6 M! O% l. Z
  4. NVIC_PENDSVSET  EQU     0x10000000                              ; Value to trigger PendSV exception.
    ! f$ f: H2 g& P% x+ d1 F

  5. * T; o2 U* t& V, n
  6.   RSEG CODE:CODE:NOROOT(2)5 m4 P  b. C$ I7 ?* @. c: N; l8 ?: R
  7.   THUMB
    * R& q! @! H" ^2 P. G

  8. % u+ ^6 K' r5 s/ M" ^6 v
  9. 0 M" v! q5 \: a4 G9 p5 ^1 T
  10.   EXTERN  g_OS_CPU_ExceptStkBase
    : p' ?1 x% T" X- i- H3 E1 |
  11.   7 W: ?( D' B( Z
  12.   EXTERN  g_OS_Tcb_CurP3 s2 e. K- S# x8 i+ c. B
  13.   EXTERN  g_OS_Tcb_HighRdyP
    * w0 n3 s* J1 {' x9 ~

  14. ; K' ]  @5 O& B! G% f
  15.   PUBLIC OSStart_Asm
    : l  P% Z; M) \- u* z
  16.   PUBLIC PendSV_Handler
    . k) t) T/ o. p. c8 S' ]. r" b
  17.   PUBLIC OSCtxSw
    ! ?( u* g# S0 S
  18. & z9 z: Z5 s. i! S% l
  19. OSCtxSw) r" \6 S, C" V& w( l  z8 Q/ v: i
  20.     LDR     R0, =NVIC_INT_CTRL1 L4 D! y8 |% Z- I8 H; y
  21.     LDR     R1, =NVIC_PENDSVSET
    ; ], E) V2 a  d) v" O
  22.     STR     R1, [R0]2 ^/ y) D; t% n
  23.     BX      LR                                                ; Enable interrupts at processor level2 P* F& E; f' @6 j, x0 F
  24. , m+ U1 o  W! h/ d$ P5 R& I
  25. OSStart_Asm' m6 |# G4 H$ F2 a3 G4 P/ k8 a
  26.     LDR     R0, =NVIC_SYSPRI14                                  ; Set the PendSV exception priority
    , {$ E: n2 }0 o$ b, K
  27.     LDR     R1, =NVIC_PENDSV_PRI- h' Q! Q( x3 P( {  g
  28.     STRB    R1, [R0]
    : r( |- N% A- }2 O

  29. 7 o2 v5 s( g8 A( h) [7 B
  30.     MOVS    R0, #0                                              ; Set the PSP to 0 for initial context switch call
    % k, H2 f0 H; S
  31.     MSR     PSP, R0
    ; M* D- i: f% J8 n8 S
  32. ! u( l, ~3 B9 t1 }# ^. l+ G8 Y0 `
  33.     LDR     R0, =g_OS_CPU_ExceptStkBase                           ; Initialize the MSP to the OS_CPU_ExceptStkBase: `, o# E/ ?- f! {9 r6 M; K" Z
  34.     LDR     R1, [R0]7 `' `* F. _$ J/ J
  35.     MSR     MSP, R1   
    ; n2 W' Y* V3 {- r
  36. - M# R5 A! X; o1 i; ~
  37.     LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)
    , G1 ?; T1 A9 K+ l9 @
  38.     LDR     R1, =NVIC_PENDSVSET1 o+ U# C; m* t& c- k5 `
  39.     STR     R1, [R0]
    6 c) n  g% b5 c" `' X7 D' i

  40. * U+ S  V: }, w! C  A. t" h3 _$ [
  41.     CPSIE   I                                                   ; Enable interrupts at processor level
    4 e7 f9 V0 r  B& R# r

  42. 2 p4 P- ]9 ?  I" k+ h" S* h5 W
  43. OSStartHang
    5 e; x8 L. |2 D. R
  44.     B       OSStartHang                                         ; Should never get here8 a1 T& B: n8 ~0 a' R# I+ ?6 [
  45.    
    + G8 e$ y9 T; p! q) }* Z
  46.     . z6 U0 d6 _  w: c; z$ Y

  47. " B2 r6 e6 N5 W. |
  48. PendSV_Handler! z" Y' r/ c- x5 n5 h% s+ q0 k* _
  49.     CPSID   I                                                   ; Prevent interruption during context switch  L2 D1 \# ]7 G: Q
  50.     MRS     R0, PSP                                             ; PSP is process stack pointer
    $ S1 |7 ~9 H. O; q( H  ]6 m
  51.     CBZ     R0, OS_CPU_PendSVHandler_nosave                     ; Skip register save the first time
    1 G: e% F0 `/ v/ s+ H- [
  52.      _( F4 f% N* I" {6 y
  53.     SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack
    / `4 B% i" w' z" v) l' H/ }+ y
  54.     STM     R0, {R4-R11}
    . R1 Z7 P) H- `% {4 B4 c

  55. . w3 N" O9 Z0 X3 z+ j
  56.     LDR     R1, =g_OS_Tcb_CurP                                       ; OSTCBCur->OSTCBStkPtr = SP;
    . d" y( e8 w( {! B/ k
  57.     LDR     R1, [R1]
    5 _+ t0 ^$ f' @/ e' @
  58.     STR     R0, [R1]                                            ; R0 is SP of process being switched out
    & S) X$ q+ n  C* Z

  59. , n8 }+ R) |! b" C
  60.                                                                 ; At this point, entire context of process has been saved
    1 z! x* K4 j$ G  ~1 N: V
  61. OS_CPU_PendSVHandler_nosave
    , R6 w+ ?+ M9 ?6 W
  62.     LDR     R0, =g_OS_Tcb_CurP                                       ; OSTCBCur  = OSTCBHighRdy;
    * F1 A5 Y; f$ ?
  63.     LDR     R1, =g_OS_Tcb_HighRdyP
    ) i+ R# A) Q+ z% j" D
  64.     LDR     R2, [R1]
    " C5 D/ O& q1 P& C- P9 w: f
  65.     STR     R2, [R0]
    8 t$ m) [# w* {

  66. . K1 ]0 Q0 M) A1 ]% S) B& }) A; r3 T; l/ s
  67.     LDR     R0, [R2]                                       ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
    % g6 Y2 A9 h% z; _' Z3 X% z
  68.   
    7 f. s! t( r; i
  69.     LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack( b# T  ]; U6 Y
  70.     ADDS    R0, R0, #0x20  @2 o; D& K6 `3 T
  71.             
    9 k* U  U7 B4 |- C/ S2 d
  72.     MSR     PSP, R0                                             ; Load PSP with new process SP( F! i  Y0 _* E  M+ {# g! }
  73.     ORR     LR, LR, #0x04                                       ; Ensure exception return uses process stack  P$ r9 s" T. ?6 O  I, I! T  _8 A
  74.    
    . k8 v. i4 H3 p4 s2 ?+ Z' Y
  75.     CPSIE   I" j- |, B( ?% y( U' i: S5 j! T9 N& d
  76.     BX      LR                                                  ; Exception return will restore remaining context
    7 q7 o8 v- E9 K( v
  77.   ' o- E! H$ F( d9 I
  78.     END
复制代码
  X7 W; o! @  W0 n, q
main.c内容如下:
  1. #include "stdio.h"5 j0 t; ^! Z' `+ H: W( \8 {: X
  2. #define OS_EXCEPT_STK_SIZE 1024$ F  ?: J) Y+ u5 F
  3. #define TASK_1_STK_SIZE 1024
    " x% W- N& [% k. j; {' v! e
  4. #define TASK_2_STK_SIZE 1024$ Q' d! a* n# C/ |" ~
  5. * H; H1 r% V! P7 q6 r* @5 N. m2 V/ d
  6. typedef unsigned int OS_STK;& x. g% N- ^/ u. N- E
  7. typedef void (*OS_TASK)(void);; }. X8 g0 I% I0 p2 S( J

  8. 8 |. G- P& M7 [( n& \: }- F
  9. typedef struct OS_TCB  M8 E! _5 i. O/ B5 n8 a
  10. {
    * P. U) P" |' p( R1 S6 M5 a
  11.   OS_STK *StkAddr;
    5 T3 ]6 e# {9 L3 f" U( [9 [
  12. }OS_TCB,*OS_TCBP;6 k0 H+ ~5 b* N1 N+ C

  13. . z( L. @+ v7 e

  14. 1 S3 }9 N8 C# B0 r& E6 k( b" S+ w
  15. OS_TCBP g_OS_Tcb_CurP; ( i+ E' b2 M$ i$ e8 p
  16. OS_TCBP g_OS_Tcb_HighRdyP;  a$ ]( [, `9 k1 j0 J" T

  17. 0 A& d, q/ Z+ t. K- A) U/ d* ~9 U
  18. static OS_STK OS_CPU_ExceptStk[OS_EXCEPT_STK_SIZE];$ {3 w/ a; [- z
  19. OS_STK *g_OS_CPU_ExceptStkBase;
    / P- t; ]; j: B; V

  20. , E, y. f6 `" S- G* r
  21. static OS_TCB TCB_1;
      [3 O0 p; z. M8 H  z
  22. static OS_TCB TCB_2;
    ; j& E9 Z( g6 c4 s+ h6 X! Y
  23. static OS_STK TASK_1_STK[TASK_1_STK_SIZE];0 I9 P$ z* C9 H8 M5 `* {6 n
  24. static OS_STK TASK_2_STK[TASK_2_STK_SIZE];
    * h8 e1 U4 u8 ?* ~+ L1 n1 }$ r) b
  25. ( j" ^, p6 C8 d' E9 C6 `. X$ c4 ~( v
  26. extern void OSStart_Asm(void);+ L& t8 R' v, U' y1 M+ I! I' i
  27. extern void OSCtxSw(void);
    - k: g+ D8 Q1 B' {
  28. " v: N+ x7 j' O( }; Q8 T
  29. void Task_Switch()
    2 d( Z3 o! ^) X; W( Z
  30. {1 H% f# ]: `/ `" G; Q4 r. ]0 }
  31.   if(g_OS_Tcb_CurP == &TCB_1)
    : ]9 X2 H4 v. A8 J0 E
  32.     g_OS_Tcb_HighRdyP=&TCB_2;
    7 b% c1 v7 h1 C8 B) L$ ^1 d
  33.   else! H8 G% r4 n7 {+ c5 ~
  34.     g_OS_Tcb_HighRdyP=&TCB_1;  ^6 ?1 L' H* X; }' S, Y0 d* Z/ n
  35. - k+ c8 [, m- v$ y/ P! |
  36.   OSCtxSw();5 M* @1 C! J" }
  37. }- ^) N5 k8 C! h' s  h) n# u$ J# j- U
  38. - H- v. @! I/ p; c4 R% c" r
  39. / G$ d/ u9 m5 a4 f" s5 d
  40. void task_1()
    4 [0 ?. U* i0 C. `
  41. {
    ' c  V2 M! g! a1 E" f
  42.   printf("Task 1 Running!!!\n");3 v& f& l6 H* a6 l
  43.   Task_Switch();
    ( X' w! n5 b. g- N
  44.   printf("Task 1 Running!!!\n");$ P- O" V: n% V
  45.   Task_Switch();
    & r! n# E, y4 c) U5 Z
  46. }
    ) O% D. c( V0 Z7 @. d! w; |
  47. 3 r$ k4 Q+ F$ \- Y& i
  48. void task_2()
    9 g" z  c; e0 [5 e9 Z9 `
  49. {
      q0 J7 f  o  l0 g+ {
  50.   5 Y3 ?9 G% J% P
  51.   printf("Task 2 Running!!!\n");
    ' X) M! c5 n8 t* P
  52.   Task_Switch();6 w5 A/ X6 T: \/ N
  53.   printf("Task 2 Running!!!\n");
    1 \. y" g0 t( h' P$ K
  54.   Task_Switch();" |' g3 ?7 N5 ^5 v
  55. }. S. A( y1 |  m2 s

  56. + ~$ F" r7 i5 n  \
  57. void Task_End(void)
      [6 }1 c$ G3 ~5 N6 i, C
  58. {: A2 c+ I; ~; k
  59.   printf("Task End\n");
    ' @6 R# {2 K8 |6 x1 a
  60.   while(1)
    0 p; U) l* g" A
  61.   {}+ y" q5 w1 o9 Z
  62. }, h7 W* `/ Q# y' u
  63. ' [1 ?/ D7 l" b+ O+ y
  64. void Task_Create(OS_TCB *tcb,OS_TASK task,OS_STK *stk)
    * b0 d3 g4 @+ ~1 x
  65. {
    ! M: w6 h* @  ?1 {5 E+ ^2 N
  66.     OS_STK  *p_stk;1 X3 {5 @% c1 m5 p1 ]1 r
  67.     p_stk      = stk;
    8 s/ K7 f& j" W, K# d
  68.     p_stk      = (OS_STK *)((OS_STK)(p_stk) & 0xFFFFFFF8u);9 u+ B2 f' I2 \. z) Y4 H0 g
  69.     / g. m- g  m6 i* g5 H) s
  70.     *(--p_stk) = (OS_STK)0x01000000uL;                          //xPSR
    " ~: p3 g( L! j- h
  71.     *(--p_stk) = (OS_STK)task;                                  // Entry Point
    / w& n! J% z8 \- U) ], B6 f
  72.     *(--p_stk) = (OS_STK)Task_End;                                     // R14 (LR)
    $ a4 y& R# w" [
  73.     *(--p_stk) = (OS_STK)0x12121212uL;                          // R12" v9 C% M5 ~$ ]( `3 Z6 E
  74.     *(--p_stk) = (OS_STK)0x03030303uL;                          // R3
    9 h, W6 q4 q" l- B) W
  75.     *(--p_stk) = (OS_STK)0x02020202uL;                          // R2' K' r, r, t7 }) A
  76.     *(--p_stk) = (OS_STK)0x01010101uL;                          // R1
    + u5 j$ g! Y" O! y! h6 p4 N
  77.     *(--p_stk) = (OS_STK)0x00000000u;                           // R0( S, J5 H% ?8 _) m" W& D& {$ ^
  78.     / Z  Y7 u4 }) X3 F% J
  79.     *(--p_stk) = (OS_STK)0x11111111uL;                          // R11' \: g3 s4 q) D' l2 R$ N
  80.     *(--p_stk) = (OS_STK)0x10101010uL;                          // R10
      X% ]' M+ K& Z% \
  81.     *(--p_stk) = (OS_STK)0x09090909uL;                          // R9( U+ r; O- s# c/ b& i5 n, f
  82.     *(--p_stk) = (OS_STK)0x08080808uL;                          // R8) w4 @; ?/ n9 I( a2 X6 G7 W
  83.     *(--p_stk) = (OS_STK)0x07070707uL;                          // R7" y" A" ]" j7 [% ?
  84.     *(--p_stk) = (OS_STK)0x06060606uL;                          // R6
    0 s+ h3 K/ J( ?- V& v( y/ h
  85.     *(--p_stk) = (OS_STK)0x05050505uL;                          // R5
    % j! }3 q; Z7 \/ b
  86.     *(--p_stk) = (OS_STK)0x04040404uL;                          // R44 z7 a! Y( x) O: H6 ]1 `
  87.    
    $ P# R8 R* ?8 T
  88.     tcb->StkAddr=p_stk;
    7 N6 m/ T* s# W- O8 l
  89. }
    . q  R2 u" ]( J5 c. q0 J

  90. 7 \- ?8 }. B+ N/ X& F( L

  91. ! v7 m5 T; i" S6 A3 R; D1 l
  92. int main()
    , N) @7 P3 `% q* b8 M" Q* M
  93. {8 P- B3 y+ w/ x
  94.   
    ; _5 I- F( x; F" s  b3 i$ x  Y
  95.   g_OS_CPU_ExceptStkBase = OS_CPU_ExceptStk + OS_EXCEPT_STK_SIZE - 1;
    $ k' H; `9 [2 h* _1 a
  96.   1 x9 v) G2 c; K$ Z
  97.   Task_Create(&TCB_1,task_1,&TASK_1_STK[TASK_1_STK_SIZE-1]);0 a8 p: B" \; Y
  98.   Task_Create(&TCB_2,task_2,&TASK_2_STK[TASK_1_STK_SIZE-1]);
    ) R2 [  L) E0 ~
  99.     % [. {$ e. {! I( [
  100.   g_OS_Tcb_HighRdyP=&TCB_1;
    ! l) R% i5 E: _1 w. p2 y
  101.   
    : N/ V# ~- c" U* `. N* T  @
  102.   OSStart_Asm();8 P) U2 [4 E' x
  103.   6 h0 j' h5 Q/ n) D
  104.   return 0;
    - w9 M, d9 n% p/ D6 ^' J5 A
  105. }
复制代码
* D. c! U, I2 a# |" |. X0 P
编译下载并调试:

. j8 k" ~+ ~7 j" r6 c5 z9 u  X
02143746-b3794508e0a644a09cf863ef3da935ed.jpg

# `, T+ V4 L' s7 D# T
在此处设置断点
此时寄存器的值,可以看到R4-R11正是我们给的值,单步运行几次,可以看到进入了我们的任务task_1或task_2,任务里打印信息,然后调用Task_Switch进行切换,OSCtxSw触发PendSV异常。
/ K! N; i" d/ ?6 y$ M. U& E7 d7 k* l
02143747-3c53018b89dc48bb97ef1b9761c698ca.png

* M2 g( w( s. Z2 ^4 V, g/ |9 ~
IO输出如下:

5 C# |9 J! o2 c3 {0 [+ U! Y
02143748-2d79fed2fb1e43c2bb90024f7679b5bd.jpg

7 j  l" T) D% |- i+ K
至此我们成功实现了使用PenSV进行两个任务的互相切换。之后,我们使用使用SysTick实现比较完整的多任务切换。

' z7 \) s! X/ P4 X. m
收藏 评论0 发布时间:2022-1-16 18:03

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版