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

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

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

OS 可以利用它“缓期执行”一个异常——直到其它重要的任务完成后才执行动 作。悬起 PendSV 的方法是:手工往 NVIC的 PendSV悬起寄存器中写 1。悬起后,如果优先级不够 高,则将缓期等待执行。
PendSV的典型使用场合是在上下文切换时(在不同任务之间切换)。例如,一个系统中有两个就绪的任务,上下文切换被触发的场合可以是:
! Y. O9 y: x6 z# M% ~0 E1、执行一个系统调用
% X; W7 a4 u0 z$ K4 W' U% W" W6 e2、系统滴答定时器(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_PendSVHandler9 w: G$ H: j  }" }3 y/ `8 z3 L
  2.     CPSID I ; 关中断
    0 @0 [; e2 D2 |: s2 ]
  3.     ;保存上文
    " ^# p6 F8 W( d2 T# f0 c0 X/ }
  4.     ;....................... 9 K) P* H" b* ?& }( X' w$ X
  5.     ;切换下文
    6 ^6 g. q8 b. |; q: t
  6.     CPSIE I ;开中断$ W5 d( ~$ b5 g" }' S: ^
  7.     BX LR ;异常返回
复制代码
, b$ `2 ?0 J0 g2 R
它在异常一开始就关闭了中端,结束时开启中断,中间的代码为临界区代码,即不可被中断的操作。PendSV异常是任务切换的堆栈部分的核心,由他来完成上下文切换。PendSV的操作也很简单,主要有设置优先级和触发异常两部分:
  1. NVIC_INT_CTRL EQU 0xE000ED04 ; 中断控制寄存器
    $ l' g' ^. p) U
  2. NVIC_SYSPRI14 EQU 0xE000ED22 ; 系统优先级寄存器(优先级14).
    4 H) l8 t6 O  g5 F8 X9 ]
  3. NVIC_PENDSV_PRI EQU 0xFF ; PendSV优先级(最低). NVIC_PENDSVSET EQU 0x10000000 ; PendSV触发值! W. m& m* U# t' M0 M: }( }4 C, {
  4. ' M9 Q1 C' ^* }) J) d: s9 F* P" G7 \
  5. ; 设置PendSV的异常中断优先级. g6 g& `; P+ `' e

  6. % I' b0 I% k  s& A7 P2 u0 R) G
  7. LDR R0, =NVIC_SYSPRI14 ( ~/ @4 p: m+ W# U- ]
  8. LDR R1, =NVIC_PENDSV_PRI
    5 R6 [  n. N* n5 Q1 \
  9. STRB R1, [R0] ; 触发PendSV异常; |' l7 L' P$ `( y8 c
  10. LDR R0, =NVIC_INT_CTRL 8 d. {4 e) M4 f: c- ~
  11. LDR R1, =NVIC_PENDSVSET
    : M) s0 d( ^" q3 i# U
  12. STR R1, [R0]
复制代码

5 E! [% [. O' q) s6 O
二、堆栈操作
Cortex M4有两个堆栈寄存器,主堆栈指针(MSP)与进程堆栈指针(PSP),而且任一时刻只能使用其中的一个。MSP为复位后缺省使用的堆栈指针,异常永远使用MSP,如果手动开启PSP,那么线程使用PSP,否则也使用MSP。怎么开启PSP?
  1. MSR     PSP, R0                                             ; Load PSP with new process SP9 ~$ ]7 f3 m1 e" L) P' T9 R% H
  2.     ORR     LR, LR, #0x04                                   ; Ensure exception return uses process stack
复制代码
) M" ^4 `' X7 C3 Z
很容易就看出来了,置LR的位2为1,那么异常返回后,线程使用PSP。
写OS首先要将内存分配搞明白,单片机内存本来就很小,所以我们当然要斤斤计较一下。在OS运行之前,我们首先要初始化MSP和PSP,
  1. EXTERN  OS_CPU_ExceptStkBase
    . y& f0 T! X/ {" p! a
  2.    ;PSP清零,作为首次上下文切换的标志
      f0 L# P& `2 K7 |' L" [. }2 Z
  3.    MOVS    R0, #0
    % k2 L! n- B9 [! _. y8 `
  4.    MSR     PSP, R0
    7 d2 t5 P2 G! T0 L' }1 K; D: Z
  5.    ;将MSP设为我们为其分配的内存地址
    , q% X4 Z& ]2 a9 P
  6.    LDR     R0, =OS_CPU_ExceptStkBase  I8 z0 f7 m' M) F) D7 w
  7.    LDR     R1, [R0]
    9 [. ], b$ Y. Q) Z
  8.    MSR     MSP, R1
复制代码
0 ?0 b! F* t* q6 w
然后就是PendSV上下文切换中的堆栈操作了,如果不使用FPU,则进入异常自动压栈xPSR,PC,LR,R12,R0-R3,我们还要把R4-R11入栈。如果开启了FPU,自动压栈的寄存器还有S0-S15,还需吧S16-S31压栈。
  1. MRS     R0, PSP
    ' W! F6 o, a; z! B# s: n
  2.     SUBS   R0, R0, #0x20        ;压入R4-R115 V& B& r1 s' L, t+ V
  3.     STM     R0, {R4-R11}
    $ R) M/ n$ j7 @! N! ~

  4. ( n- k8 V& Q( c8 M
  5.     LDR     R1, =Cur_TCB_Point    ;当前任务的指针6 A0 j; l! s6 i5 J+ \; i0 L
  6.     LDR     R1, [R1]& {6 P5 ^; z& ?) e
  7.     STR     R0, [R1]            ; 更新任务堆栈指针
复制代码

0 o! g7 n/ h9 a1 w4 l- C9 d
出栈类似,但要注意顺序
  1. LDR     R1, =TCB_Point    ;要切换的任务指针% x; P$ [+ `: M8 P7 f4 j  W
  2.     LDR     R2, [R1]
    ; p. W2 ]# a% f6 I6 P% o0 i. {
  3.     LDR     R0, [R2]          ; R0为要切换的任务堆栈地址& t' E7 @. c: p' k# x+ Y0 \
  4.   
    6 D( `( ~! h  Z. @8 e- D, s' a
  5.     LDM     R0, {R4-R11}     ; 弹出R4-R117 B2 N# X7 g( ?
  6.     ADDS    R0, R0, #0x20( D0 @- u: q( X3 h
  7. 1 `3 [+ p6 J- F" A
  8.     MSR     PSP, R0        ;更新PSP
复制代码
# D* B' i! o: j0 d  ]: j
三、OS实战
新建os_port.asm文件,内容如下:
  1. NVIC_INT_CTRL   EQU     0xE000ED04                              ; Interrupt control state register.% S1 z, P/ j; z2 Q
  2. NVIC_SYSPRI14   EQU     0xE000ED22                              ; System priority register (priority 14).4 C6 h0 k6 M7 M2 y. h4 i3 J
  3. NVIC_PENDSV_PRI EQU           0xFF                              ; PendSV priority value (lowest)./ f# {! j# p+ `' o6 c" |
  4. NVIC_PENDSVSET  EQU     0x10000000                              ; Value to trigger PendSV exception.
    5 |$ w: h6 p! c! _3 Z

  5. + @1 e& l" j" V: o# R" ?) f
  6.   RSEG CODE:CODE:NOROOT(2)8 X% N4 w" v. `7 G6 T
  7.   THUMB
    % p0 i. P  B  e+ J  z
  8. / w4 ?& ?2 {9 r; a) t

  9. 0 ~- z+ U7 G! j
  10.   EXTERN  g_OS_CPU_ExceptStkBase
    . I8 e! F6 V2 }* [+ N: s1 b$ o% S+ R
  11.   ) x% g5 E- |2 ?1 n
  12.   EXTERN  g_OS_Tcb_CurP  n8 ^4 C0 _9 \' z5 X5 W9 Y
  13.   EXTERN  g_OS_Tcb_HighRdyP- }- Z7 t- U  k# ?0 I" P; _
  14. ! \& C9 d$ q: v7 W# R4 p
  15.   PUBLIC OSStart_Asm
    7 C& _" b- W. E& G* g$ O3 }
  16.   PUBLIC PendSV_Handler+ Y( d2 t1 f  @$ J( K
  17.   PUBLIC OSCtxSw
    + |# \. k2 s( F2 x% [" @

  18. 3 T7 N+ W$ u* J7 a
  19. OSCtxSw) f% c- ?$ i4 o9 v5 q# i) [9 T5 s
  20.     LDR     R0, =NVIC_INT_CTRL
    5 D% N6 k* }9 t$ e0 Q! g
  21.     LDR     R1, =NVIC_PENDSVSET7 {. }% D: m8 n1 [* X+ n& F
  22.     STR     R1, [R0]
    + K( Z' Q! U& Y2 f$ f. ?
  23.     BX      LR                                                ; Enable interrupts at processor level  |9 O" |) m6 H% G% A) v" m7 n7 O
  24. & {2 [! c1 s. ?
  25. OSStart_Asm
    2 G0 j- @8 d+ h" i. P, z
  26.     LDR     R0, =NVIC_SYSPRI14                                  ; Set the PendSV exception priority
    4 r- F! W+ D1 l" ~
  27.     LDR     R1, =NVIC_PENDSV_PRI3 t, o2 c8 [' ^7 F% M
  28.     STRB    R1, [R0]
    ) j6 c0 U$ l6 w" X: @8 w
  29. % z# X8 P8 `9 |7 ~) Y
  30.     MOVS    R0, #0                                              ; Set the PSP to 0 for initial context switch call
    " Z5 R# J1 N8 D6 z; T
  31.     MSR     PSP, R0$ U. I- N1 ]$ O8 e
  32. + c# R2 F5 g8 i3 @+ [  q8 m
  33.     LDR     R0, =g_OS_CPU_ExceptStkBase                           ; Initialize the MSP to the OS_CPU_ExceptStkBase: h4 u  _, u$ w; q
  34.     LDR     R1, [R0]0 V# E3 j# ^2 {' `* \& L
  35.     MSR     MSP, R1   
    ' ]" J# p9 A1 O5 o
  36. ( g4 k, X! j+ @% v  l% n/ E! F$ n4 O
  37.     LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)
    & B$ A7 O+ f9 V# _
  38.     LDR     R1, =NVIC_PENDSVSET
    % j, v* _% X( T
  39.     STR     R1, [R0]
    & ]$ p& |4 D$ F8 Q/ o  D7 s% v9 S

  40. 0 i4 }2 T1 \1 l2 ~
  41.     CPSIE   I                                                   ; Enable interrupts at processor level8 l: B. o2 l& X! w

  42. ) t0 C8 j9 I( \5 H- g
  43. OSStartHang2 e; T' w  k" T. v
  44.     B       OSStartHang                                         ; Should never get here4 ]% m; p+ S$ F5 `  S& M: Z
  45.     - _* l& x. Q8 p
  46.    
    0 |% ]/ B0 M6 _) {$ `
  47. 4 |. }! Y% a: \0 n& |
  48. PendSV_Handler
    & ]$ D' ~$ _0 ?; a  Q/ }4 K2 ?
  49.     CPSID   I                                                   ; Prevent interruption during context switch5 Z# X" H' v0 l  q9 ?6 p, s) h/ A
  50.     MRS     R0, PSP                                             ; PSP is process stack pointer
    1 \  r1 ?& {" c7 F* j- H! T
  51.     CBZ     R0, OS_CPU_PendSVHandler_nosave                     ; Skip register save the first time1 k5 h, h2 A; p1 y; _, N
  52.    % J- V/ c0 m" x5 f& j: G  u, F
  53.     SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack. f2 f3 G6 \- X
  54.     STM     R0, {R4-R11}/ f! O2 E+ U- x' Z% t# @
  55.   C0 S9 j) ]& k* E/ g7 `3 c
  56.     LDR     R1, =g_OS_Tcb_CurP                                       ; OSTCBCur->OSTCBStkPtr = SP;) `' j' i. }# S' C" X" K* F0 y6 Q
  57.     LDR     R1, [R1]- J- H- M% r; T1 d7 ~6 ?# }+ P
  58.     STR     R0, [R1]                                            ; R0 is SP of process being switched out/ |4 s, L  R# |/ p7 o: M: i2 Z
  59. 2 y  e, Y6 E  a; _) X" e
  60.                                                                 ; At this point, entire context of process has been saved9 `; q* O+ J$ R4 t8 B; i
  61. OS_CPU_PendSVHandler_nosave
    9 C* _! k/ \& M
  62.     LDR     R0, =g_OS_Tcb_CurP                                       ; OSTCBCur  = OSTCBHighRdy;
    6 s* }, e2 ~- _4 u& F7 H  K+ |
  63.     LDR     R1, =g_OS_Tcb_HighRdyP# g; i  Q: Y+ g- x4 l4 d; j" x
  64.     LDR     R2, [R1]
    ( n9 A# Z8 ]2 U: k* W, h4 |
  65.     STR     R2, [R0]
    " h2 `7 m9 N* v; m, B
  66. ) K4 m1 ]  g4 h; V7 o" ]
  67.     LDR     R0, [R2]                                       ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
    : h+ r" g- V5 z3 h+ Q& n. \: ?  b
  68.   ' B" M! ~: E3 K
  69.     LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack
    & S1 L9 K$ L3 Q# z
  70.     ADDS    R0, R0, #0x205 i% N1 X9 l! G6 I  t5 f
  71.             * R; o6 f( L' J$ a6 u
  72.     MSR     PSP, R0                                             ; Load PSP with new process SP" e4 U: u* x& V6 l4 x0 O
  73.     ORR     LR, LR, #0x04                                       ; Ensure exception return uses process stack& r& v- q$ x- P% P1 \+ d7 f
  74.     / W8 a. W7 F% s: g* o) Z# n' [) P
  75.     CPSIE   I
    / @  u7 e: A4 L, k
  76.     BX      LR                                                  ; Exception return will restore remaining context
    - o) o3 a- S( q
  77.   
    - D: |5 K; L  M! Q0 |  H  b
  78.     END
复制代码

9 K7 Q) l1 y. P. t
main.c内容如下:
  1. #include "stdio.h"
    # M) }# m$ u: x* @
  2. #define OS_EXCEPT_STK_SIZE 1024+ Q+ }6 e2 e: E  C
  3. #define TASK_1_STK_SIZE 1024
    : Y# k- W6 M' Z& l8 s* \
  4. #define TASK_2_STK_SIZE 10249 U- ]# j9 S+ K, c* C6 i- A/ f
  5.   @) Y, S$ _$ I/ Q/ H0 s  R
  6. typedef unsigned int OS_STK;# l  x8 x5 w# U1 z$ c3 L# U
  7. typedef void (*OS_TASK)(void);; i4 `; w+ o: [
  8. * U  N; e4 Y$ j: l
  9. typedef struct OS_TCB
    5 y" K* w9 M( C/ I6 A0 J$ W$ i4 E
  10. {
    ; k7 W& p! E9 L, ^2 \5 m% o
  11.   OS_STK *StkAddr;# g% z- R- m& I9 [
  12. }OS_TCB,*OS_TCBP;
    4 _! w; b, e- C* g3 |; `
  13. 1 B! G. [$ v; _5 c5 L2 W

  14. 3 |1 E; z: V6 c
  15. OS_TCBP g_OS_Tcb_CurP;
    5 H5 g. r/ O3 G2 z0 \6 ]$ J4 N) G& B9 s
  16. OS_TCBP g_OS_Tcb_HighRdyP;( }# F/ a# F- M5 g' R' [

  17. / U. P  u, F; i+ l
  18. static OS_STK OS_CPU_ExceptStk[OS_EXCEPT_STK_SIZE];9 o# v& u4 m; f. ]- v/ i- T
  19. OS_STK *g_OS_CPU_ExceptStkBase;
    ! U+ G: {0 O% B& G; H; Q

  20. ! v2 ^9 _% m6 m6 l$ t; W- v
  21. static OS_TCB TCB_1;
    9 a" B% Y$ m. c( w/ V1 v
  22. static OS_TCB TCB_2;) ]# b7 e* K: B: D0 R
  23. static OS_STK TASK_1_STK[TASK_1_STK_SIZE];
    ) F( ~. l( B8 X1 Q
  24. static OS_STK TASK_2_STK[TASK_2_STK_SIZE];
    , J) r/ i2 H1 N1 k# R

  25. ' ]6 d# X5 B6 w- I& g( F8 O
  26. extern void OSStart_Asm(void);
    % {2 d; C/ s/ W4 l
  27. extern void OSCtxSw(void);2 J1 c7 ?! c2 y: h. S. t# O
  28. ; D1 g  n! R5 P1 _0 O; o( S* E8 s
  29. void Task_Switch()
    - t4 `6 m% }* z1 c3 N
  30. {
    . b) K5 ^8 \2 \2 g4 f
  31.   if(g_OS_Tcb_CurP == &TCB_1)
      s9 ~9 N, }  v, F0 i
  32.     g_OS_Tcb_HighRdyP=&TCB_2;
    9 }1 Y% ]7 T- x( b7 Z
  33.   else
    - b& H7 z3 |3 F6 |! Z' O
  34.     g_OS_Tcb_HighRdyP=&TCB_1;2 S8 H  X9 u; E/ S6 H
  35. 7 X% j0 G6 @, T" G
  36.   OSCtxSw();$ n) W$ O# p* a0 T. u
  37. }8 O1 y$ k  [) r; o
  38. / h+ K2 Z$ n3 ~4 y

  39. - u, y6 h, k- [! L: E9 q$ O7 ]; {) w
  40. void task_1()- G# v5 Q3 G4 h4 c6 S
  41. {$ O( @4 ^: M# O5 q' @0 ^$ t
  42.   printf("Task 1 Running!!!\n");
    # a' L- P0 [1 ~4 N& G
  43.   Task_Switch();
    ! h, {5 p" Q! r
  44.   printf("Task 1 Running!!!\n");
    , o1 J3 y  G4 |9 G9 K
  45.   Task_Switch();; X9 D9 [) w" Z
  46. }9 M- g0 o% m# f+ i( G" l0 w
  47. 9 G8 F( C* ]2 Y" g
  48. void task_2()
    7 V, K1 O) L* v% ]( z3 W7 P2 f' z
  49. {0 E, ~, C- J% g3 J) B4 T
  50.   
    0 `8 U) t# v$ E- F0 b  ]) I+ I  ]
  51.   printf("Task 2 Running!!!\n");
    " b4 q& r) `8 \3 T  r- P3 [
  52.   Task_Switch();1 `/ I: \; n  h6 n
  53.   printf("Task 2 Running!!!\n");2 a& {& ]' H! _( {: ]9 U
  54.   Task_Switch();+ m( i9 Z* t! l* e- Q
  55. }" B  Q" ]1 ]' ?$ T1 H$ U
  56. 5 {5 v# i* R/ X! j8 }/ s$ N% n" [3 a
  57. void Task_End(void)
    . @1 a: J1 J6 n. Z, L2 {
  58. {: J4 Y( U' _% x3 {
  59.   printf("Task End\n");
    7 k  N- n- D' h2 ~! [
  60.   while(1)
    + r0 [6 ?5 E: p9 U! X* w
  61.   {}
    $ {6 w* Q5 P. ?
  62. }5 G- ^9 G, Z' @4 }- X! e$ y! D0 i
  63. : a4 \4 f: G$ D, ^* ]' m
  64. void Task_Create(OS_TCB *tcb,OS_TASK task,OS_STK *stk)
    3 b4 e% {6 D. S4 ~1 J3 o# k$ w4 s
  65. {+ v6 v0 B! E. N
  66.     OS_STK  *p_stk;
    # ~" f6 k! z6 T( |- w7 x7 t7 _
  67.     p_stk      = stk;0 n* I7 F5 M4 a6 y( j6 y% D% B
  68.     p_stk      = (OS_STK *)((OS_STK)(p_stk) & 0xFFFFFFF8u);
    ; X, n+ W* U/ x+ s! G
  69.    
    9 {8 G. Q* C. K& M0 J% Q
  70.     *(--p_stk) = (OS_STK)0x01000000uL;                          //xPSR: @- b* J' D2 K5 y% m5 R% K
  71.     *(--p_stk) = (OS_STK)task;                                  // Entry Point
    % |/ [& Q2 d2 J4 I4 c. Y' Q1 F
  72.     *(--p_stk) = (OS_STK)Task_End;                                     // R14 (LR)/ j: g. I' l. @4 w
  73.     *(--p_stk) = (OS_STK)0x12121212uL;                          // R12
    0 m* j9 n- E1 h$ o
  74.     *(--p_stk) = (OS_STK)0x03030303uL;                          // R37 \& b- E1 S, s( w+ J6 y9 ?
  75.     *(--p_stk) = (OS_STK)0x02020202uL;                          // R2
    6 d( _) r9 H( `4 Y: D. a
  76.     *(--p_stk) = (OS_STK)0x01010101uL;                          // R1
    / V* E0 p  L8 K: M
  77.     *(--p_stk) = (OS_STK)0x00000000u;                           // R0
    9 Y; V6 w0 T9 F7 ~0 E
  78.    
    + Y5 w1 a- ]. j
  79.     *(--p_stk) = (OS_STK)0x11111111uL;                          // R119 I& F/ t, r6 a' w* v
  80.     *(--p_stk) = (OS_STK)0x10101010uL;                          // R105 k" G+ r4 |* Y& {5 x: N
  81.     *(--p_stk) = (OS_STK)0x09090909uL;                          // R93 S% S/ Q% C& m8 f# ^, V. j7 b
  82.     *(--p_stk) = (OS_STK)0x08080808uL;                          // R8
    5 E3 G( W& u! }8 G3 a
  83.     *(--p_stk) = (OS_STK)0x07070707uL;                          // R7
    . T& w: R" m8 v& m& ^- e* J% \5 h
  84.     *(--p_stk) = (OS_STK)0x06060606uL;                          // R64 @7 `# {6 I0 N
  85.     *(--p_stk) = (OS_STK)0x05050505uL;                          // R5
    8 O" _9 s% O6 O- l8 J( _: J
  86.     *(--p_stk) = (OS_STK)0x04040404uL;                          // R4
    # Q& ?: w) m! D; {
  87.     % g% Q# L. a1 X# g) E
  88.     tcb->StkAddr=p_stk;& V8 K8 G4 v, z: s  s* x8 ]
  89. }
    ) U! m/ W$ c, P
  90. , G* C9 B9 `4 x0 T
  91. * K# k, Q& s4 x$ B! g# `2 a3 h
  92. int main()/ l2 b8 l! ?& D- y0 y- l) }
  93. {
    : l1 D# t* M; e) z, L) L4 O
  94.   
    4 O8 A+ B+ x: q3 l9 l0 n4 O. z9 `+ ?
  95.   g_OS_CPU_ExceptStkBase = OS_CPU_ExceptStk + OS_EXCEPT_STK_SIZE - 1;
    3 h' M, w9 Y* u
  96.   / {6 r9 m5 v( P, a6 K( K9 H6 m
  97.   Task_Create(&TCB_1,task_1,&TASK_1_STK[TASK_1_STK_SIZE-1]);
    0 x8 n: {) {+ F" f2 U6 n2 y
  98.   Task_Create(&TCB_2,task_2,&TASK_2_STK[TASK_1_STK_SIZE-1]);
    3 y; w5 L+ W, `+ a* }; `1 E0 X
  99.    
    " z! G7 q- P. J, P6 `
  100.   g_OS_Tcb_HighRdyP=&TCB_1;
    : ?/ S/ p9 z& M
  101.   & l" I7 x) t" F* y8 A) O
  102.   OSStart_Asm();
    ) s9 T+ _. J  M# a; c3 ]( J! H
  103.   / ^3 L. O: u  s! s; n; W1 U/ O) r
  104.   return 0;
    . k! O  T  x* j+ x2 _
  105. }
复制代码

" t" m9 {% e3 k+ X6 S( a& N7 `
编译下载并调试:

+ L, a/ |# c& K3 X4 A7 r. a6 l( c
02143746-b3794508e0a644a09cf863ef3da935ed.jpg

2 i0 C. v7 \. s" Y! B9 ]+ P! d
在此处设置断点
此时寄存器的值,可以看到R4-R11正是我们给的值,单步运行几次,可以看到进入了我们的任务task_1或task_2,任务里打印信息,然后调用Task_Switch进行切换,OSCtxSw触发PendSV异常。
9 `6 V, q& T1 R4 g
02143747-3c53018b89dc48bb97ef1b9761c698ca.png
) ]5 X1 A& {1 N: s8 L2 `4 M
IO输出如下:

( n0 ?. c  ?. X0 Z. U
02143748-2d79fed2fb1e43c2bb90024f7679b5bd.jpg
7 f4 v& N: _  H& M0 O  T
至此我们成功实现了使用PenSV进行两个任务的互相切换。之后,我们使用使用SysTick实现比较完整的多任务切换。

+ L- @" `- X2 X4 F8 _3 M
收藏 评论0 发布时间:2022-1-16 18:03

举报

0个回答

所属标签

相似分享

官网相关资源

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