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

【安富莱】【RTX操作系统教程】第9章 任务运行在特权级或...

[复制链接]
baiyongbin2009 发布时间:2016-1-23 17:18
第9章      任务运行在特权级或非特权级模式
    本章教程为大家讲解RTX运行模式的一个重要知识点,特权级模式和非特权级模式,有些资料或者书籍将非特权级模式称为用户模式。
    本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407。
9.1 RTX任务特权级知识点说明
9.2 RTX任务特权等级深入认识
9.3 实验例程说明
9.4         总结
9.1  RTX任务特权级知识点说明
    对于初学者只需记住本小节的知识点即可,如果要深入的了解还是需要花些时间去研究下Cortex-M3或者M4权威指南。
    对于使用Cortex-M3或者M4内核的芯片来说,RTX操作系统可以让任务运行在特权级或者非特权级模式,这两种模式是M3或者M4内核本身所具有的特性。
    在特权级模式下,用户可以访问和配置系统控制寄存器,比如NVIC中断控制器。然而,如果是在非特权级模式下,系统控制寄存器是不允许访问的,一旦访问将导致硬件异常。
Unprivileged:
    非特权级,起到保护用户任务的作用,防止用户可以在任意任务中访问和修改系统寄存器,操作不当会造成系统崩溃。
Privileged:
    特权级,这种模式下用户可以在任意任务中对系统控制寄存器的访问和修改。
    有了这点基础的认识之后,还有以下四个疑问有待解决。

4 D" Q5 t- o" r

+ O! c5 A1 ]3 U/ m& b9 G
9.1.1      非特权级模式下那些寄存器不可访问
    对于Cortex-M3或者M4内核来说,所有的核心外设寄存器都是只能在特权级下才可以访问,那些又是核心外设寄存器呢,对于STM32来说需要大家看编程手册,如下这些核心外设所有的寄存器都需要在特权级下才可以访问:
9.1.png
                              
    核心外设主要是MPU,NVIC,SCB和STK四个单元。一些初学者要问了,你又是如何知道这些内核外设的寄存器要在特权级下才可以访问?答案就在这里,我们可以任意打开一个寄存器:
                           
9.2.png

: B3 ~( ^. W3 H( ?4 X* j7 p$ [) z$ ]
9.3.png
关于MPU,NVIC,SCB和STK四个单元的其它寄存器是否需要在特权级下才可以访问,大家可以按照我上面说的方法进行查看。
    除了核心外设寄存器以外,M3/M4内核的特殊功能寄存器也是不能在非特权级下访问的,特殊功能寄存器主要包括以下寄存器:
1.  程序状态寄存器组(PSRs或曰xPSR)
2.  中断屏蔽寄存器组(PRIMASK, FAULTMASK,以及BASEPRI)
3.  控制寄存器(CONTROL)
    对于参考手册上面所说的SPI,USART,USB等所有外设寄存器都是可以在非特权级下进行访问的。
6 x/ }2 W  r$ W& L1 I8 n. i
4 l5 ]. n5 s* L! l
9.1.2      非特权级模式下核心外设寄存器如何初始化
如果用户将RTX操作系统的任务设置在非特权级模式下运行,那么核心外设寄存器应该放在哪里进行初始化呢,主要有以下两种方法:
1.  使用SVC(Supervisor Call)软中断,这个在第19章有详细讲解。
2.  在初始化和开启RTX多任务前做核心外设的初始化。

8 P) n. B: d# H7 ?. p6 G6 d

* o8 W$ o1 m% i
9.1.3     Cortex-M3或者M4内核如何切换两种模式
    Cortex-M3/M4中的特殊功能寄存器包括:
1.  程序状态寄存器组(PSRs或曰xPSR)
2.  中断屏蔽寄存器组(PRIMASK, FAULTMASK,以及BASEPRI)
3.  控制寄存器(CONTROL)
    其中控制寄存器CONTROL是用来设置特权级和非特权级切换的,CONTROL寄存器定义如下:
9.4.png
CONTROL[0]
    仅当在特权级下操作时才允许写该位。一旦进入了用户级,唯一返回特权级的途径,就是触发一个软中断,再由服务例程改写该位。
CONTROL寄存器也是通过MRS和MSR指令来操作的:
    MRS   R0,    CONTROL
    MSR   CONTROL, R0

. {% A1 v5 E' w4 H

4 L( K) \+ R+ J7 E4 F6 c3 N* l
9.1.4     RTX任务特权等级的设置方法
    RTX任务特权等级的设置方法比较简单,查看RTX系统的配置向导,如下图9.1所示:
9.5.png
图9.1 RTX配置向导
Run in privileged mode
    此参数就是用来设置特权级和非特权级的,选上单选框表示使能任务工作在特权级模式,取消单选框表示任务工作在非特权级模式。

  W7 n5 T$ T: `
赞 收藏 3 评论5 发布时间:2016-1-23 17:18

举报

5个回答
baiyongbin2009 回答时间:2016-1-23 17:30:16
9.2  RTX任务特权等级深入认识
    本小节的知识点对于初学者来说比较难理解,需要积累了一定的经验后才能更好的理解,不过还是建议读一读。
    深入了解Cortex-M3/M4内核的特权等级就不得不说说两种操作模式,Cortex-M3/M4支持两种操作模式,两种操作模式分别是:
Handlermode,中断模式,简单的说就是指的异常服务程序是处在中断模式。
Threadmode,线程模式,简单的说就是异常服务程序以外的程序都是处在线程模式。
    Cortex-M3/M4内核实现这两种操作的目的就是区分普通应用程序的代码和异常服务程序。下面是两种操作模式和两种特权等级的关系:
9.6.png
中断和异常的区别
    在 ARM 编程领域中,凡是打断程序顺序执行的事件,都被称为异常(exception)。除了外部中断外,当有指令执行了“非法操作”, 或者访问被禁的内存区间,因各种错误产生的 fault, 以及不可屏蔽中断发生时,都会打断程序的执行,这些情况统称为异常。在不严格的上下文中,异常与中断也可以混用。另外,程序代码也可以主动请求进入异常状态的(常用于系统调用)。
5 l# g1 }: V( t3 G
    当处理器处在线程状态下时,既可以使用特权级,也可以使用用户级;另一方面,handler模式总是特权级的。在系统复位后,处理器进入线程模式+特权级。
    在特权级下的代码可以通过置位CONTROL[0]来进入用户级。而不管是任何原因产生了任何异常,处理器都将以特权级来运行其服务例程,异常返回后,系统将回到产生异常时所处的级别。用户级下的代码不能再试图修改CONTROL[0]来回到特权级。它必须通过一个异常handler,由那个异常handler来修改CONTROL[0],才能在返回到线程模式后拿到特权级。下图是特权级线程模式和用户级线程模式的切换图:
                              
9.7.png
一些简单的应用程序是不需要用户级线程模式的,如下图所示:
9.8.png
    把代码按特权级和用户级分开对待,有利于使CM3/CM4的架构更加安全和健壮。例如,当某个用户程序代码出问题时,不会让它成为害群之马,因为用户级的代码是禁止写特殊功能寄存器和NVIC中断寄存器的。另外,如果还配有MPU,保护力度就更大,甚至可以阻止用户代码访问不属于它的内存区域。
    为了避免系统堆栈因应用程序的错误使用而毁坏,我们可以给应用程序专门配一个堆栈,不让它共享操作系统内核的堆栈。在这个管理制度下,运行在线程模式的用户代码使用PSP,而异常服务例程则使用MSP。这两个堆栈指针的切换是智能全自动的,就在异常服务的始末由硬件处理。
    如前所述,特权等级和堆栈指针的选择均由CONTROL负责。当CONTROL[0]=0时,在异常处理的始末,只发生了处理器模式的转换,如下图所示。
9.9.png    
    但若CONTROL[0]=1(线程模式+用户级),则在中断响应的始末,处理器模式和特权等极都要发生变化,如下图所示。
9.10.png
    CONTROL[0]只有在特权级下才能访问。用户级的程序如想进入特权级,通常都是使用一条“系统服务呼叫指令(SVC)”来触发“SVC异常”,该异常的服务例程可以视具体情况而修改CONTROL[0]。
           关于操作模式和特权级就跟大家说这么多,后面讲解RTX任务切换时再详述(此章节在后期RTX教程升级版本时再配套)。
: H0 O. D; @$ n  o; M  t* I0 Z
baiyongbin2009 回答时间:2016-1-23 17:48:27
9.3  实验例程说明
" w' R& G, p; L  @
; }+ K1 s' |9 R& U" T
9.3.1     STM32F103开发板实验
配套例子:
    V4-404_RTX实验_任务运行在用户模式(非特权级)
实验目的:
    1. 学习RTX的任务运行在用户模式的设置方法
实验内容:
    1. K1按键按下,串口打印。
     2. K2键按下,设置NVIC分组,从而导致系统进入到硬件异常HardFault_Handler。
    3. 各个任务实现的功能如下:
       AppTaskUserIF任务   :按键消息处理。  
       AppTaskLED任务     :LED闪烁。
       AppTaskMsgPro任务 :消息处理,这里用作LED闪烁。
       AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX配置:
    RTX配置向导详情如下:
9.11.png
                              
Task Configuration
(1)Number of concurrent running tasks
         允许创建4个任务,实际创建了如下四个任务
                      AppTaskUserIF任务   :按键消息处理。
                      AppTaskLED任务     :LED闪烁。
                      AppTaskMsgPro任务 :消息处理,这里是用作LED闪烁。
                      AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
(2)Number of tasks with user-provided stack
        创建的4个任务都是采用自定义堆栈方式。
(3)Run in privileged mode
        设置RTX任务运行在非特权级,即用户模式。
RTX任务调试信息:
9.12.png
程序设计:
任务栈大小分配:
staticuint64_t AppTaskUserIFStk[512/8];   /* 任务栈 */
staticuint64_t AppTaskLEDStk[256/8];      /* 任务栈 */
staticuint64_t AppTaskMsgProStk[512/8];  /* 任务栈 */
staticuint64_t AppTaskStartStk[512/8];     /* 任务栈 */
将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
系统栈大小分配:
9.13.png
RTX初始化:
  1. /*9 w- H% A% U5 i' T; i' D% Z: g
  2. *********************************************************************************************************! M6 V0 a! a; u3 p0 S
  3. *    函 数 名: main
    - a7 `7 `) M  m1 P
  4. *    功能说明: 标准c程序入口。) w' a7 x  {3 ~" M: b8 [1 J7 A
  5. *    形    参: 无
    $ [2 i) l5 m$ T9 `" Y0 C* `1 i3 G
  6. *    返 回 值: 无3 q( `  d9 y4 z/ A
  7. *********************************************************************************************************
    - O" i" h) Z: Q9 @
  8. */, f4 ]$ r: p, a* \+ o& t: v
  9. int main (void)
      ~! ]. ?- ?5 }0 o! X& f( {8 @' ]
  10. {   ) R7 i7 G2 _  H( S) I; v
  11.      /* 初始化外设 */; t9 q" ]' r* f" O: J1 b" {
  12.      bsp_Init();. V0 U/ A% N% m+ N9 f+ S
  13.    
    * V6 E3 j' L  S, K5 [, n
  14.      /* 创建启动任务 */7 r) O4 j0 K0 _) I7 i# Q
  15.      os_sys_init_user (AppTaskStart,             /* 任务函数 */% \0 k! Z/ q5 n0 C! h* i, T( D2 s$ s
  16.                        4,                        /* 任务优先级 */8 [. A3 b9 i9 F' D
  17.                        &AppTaskStartStk,         /* 任务栈 */
    : D! k; Z' B0 b+ G7 [( J
  18.                        sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */
    : d5 x/ a" |- p9 p* \
  19.      while(1);$ ~9 I2 m5 Q, t0 _% `
  20. }
复制代码

& ^2 Z4 A) b  {7 E0 H
RTX任务创建:
  1. /*
    : a1 q8 \- {6 m% Z
  2. *********************************************************************************************************
    1 E% m) B! ]2 Y: k7 V. r. }+ R* |
  3. *    函 数 名: AppTaskCreate
    & Y2 g; t/ S, _( }) I) v# f) v# h
  4. *    功能说明: 创建应用任务
    . ^+ _5 _1 Y( I* K( W$ K% n
  5. *    形    参: 无' B" G3 H  r9 X/ ]- j: |! ~1 ~
  6. *    返 回 值: 无& a" l3 M& p; F$ Y. L2 |
  7. *********************************************************************************************************8 i' i( Z& r+ S) W2 }) _
  8. */+ o8 L; Q- s  ?, s" ~2 ?
  9. static void AppTaskCreate (void)3 o7 h# e6 Y6 y) S. X
  10. {
    $ b0 a1 H: K4 L
  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */
    9 i3 a- B4 ~1 P2 ^% _) Q) a
  12.                                            1,                         /* 任务优先级 */
    ) o$ [6 C9 x; B" e& u
  13.                                            &AppTaskUserIFStk,         /* 任务栈 */& K. i3 G  X" e' A7 e# b; A
  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */
    6 g8 s) C0 R/ {+ P
  15.     , k$ }& y, n- H* g" B
  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */2 c* ~0 a' f' }
  17.                                         2,                       /* 任务优先级 */& [% ]: a2 q$ }7 I  }
  18.                                         &AppTaskLEDStk,          /* 任务栈 */8 U1 ^5 }1 o# B& P+ x
  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */6 D3 v5 F8 L1 c9 t+ m0 v/ Z  I) B# ?
  20.    
    - d+ v3 y/ \0 [8 B" I6 H
  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */1 P; ~) j8 N6 a. u8 Q$ R
  22.                                            3,                         /* 任务优先级 */
    $ Q: e4 s6 z/ L2 c
  23.                                            &AppTaskMsgProStk,         /* 任务栈 */5 A( W+ y0 ~' x. E5 p5 [1 l& L3 T
  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */9 n9 l6 S9 y) m) [
  25. }
复制代码

* Z/ w8 X2 v3 k6 M% C
四个RTX任务的实现:
  1. /*5 v. f& L, Z; {6 l; ?- V5 g
  2. *********************************************************************************************************
    , I0 U1 W* O, k' H
  3. *    函 数 名: AppTaskUserIF
    7 |* Q2 a7 U, t" i6 D
  4. *    功能说明: 按键消息处理     7 A- _2 ~6 p7 M# d, }+ P
  5. *    形    参: 无2 q0 E" x3 \- x* }+ Y. x
  6. *    返 回 值: 无
    ) b) @5 h5 y/ ~/ R9 l) S( ~
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
    - j8 v8 i8 |  i7 e, f% R
  8. *********************************************************************************************************( H; u( g. O8 p- x- x
  9. */
    & X" m; }: |% t* F# Q
  10. __task void AppTaskUserIF(void)  u3 M' N" N# I" \
  11. {+ {; ?% G% G+ M# o
  12.      uint8_t ucKeyCode;7 T" A# U: M; @* [# n
  13. # m" L0 n* C5 g# K7 x0 l- |! c/ \
  14.     while(1)
    , S7 M$ ~) F* z! W
  15.     {. I2 a8 A2 y# S: r. i0 `
  16.          ucKeyCode = bsp_GetKey();9 \, u$ \& a3 @, }/ Y$ m6 V
  17.         
    % Q; X" D' b; C8 r8 ~1 C9 J% u: a
  18.          if (ucKeyCode != KEY_NONE)" ^  _! M) C& L  @& f4 M: L! P
  19.          {
    ' `) S" n- ?* q# N& k! V" N
  20.               switch (ucKeyCode)$ [6 m8 Z+ e9 c5 V5 L% T  ?
  21.               {
    . e% E0 C+ b0 x- I- V
  22.                    /* K1键按下,打印调试说明 */
    & y3 B4 U+ N+ T
  23.                    case KEY_DOWN_K1:4 x- R5 I9 V7 B% S2 p8 p5 w' g
  24.                        printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");1 `* @5 X- R) R* b
  25.                        break;  , Z& E3 ]" M$ f

  26. 0 H5 m- X9 [. x' r; ~' u
  27.                    /* K2键按下,非特权级模式下设置NVIC分组,从而导致系统进入到硬件异常HardFault_Handler */
    % |# ?; Y$ L# n! q. {5 ^& q5 o
  28.                    case KEY_DOWN_K2:
    % j: W( x% x+ o4 [- L
  29.                        printf("K2键按下,非特权级模式下设置NVIC分组,从而导致系统进入到硬件异常
    ! u0 I( Z- Y& T" Y3 u2 o  v
  30. HardFault_Handler\r\n");2 V( ~0 G$ y; g# U) y6 F, B
  31.                        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);; R; G8 M; n' K( p, q
  32.                        break;9 t2 ~; k3 P% A) p2 Z# I

  33. # Q* y* ^# @1 T5 X6 I( x
  34.                    /* 其他的键值不处理 */
    * }+ }: X1 f  f; ~) I  w
  35.                    default:                    1 ?' s3 j6 x4 v7 {5 f$ {
  36.                        break;
    , Q1 i( m9 w. _: Q% n  X6 e. ]
  37.               }& K$ k" i2 d  p/ ~2 g. F" R6 q# s
  38.          }+ [8 P0 P- j& V! I/ c/ U+ L
  39.         " a% M% ]" R! u# {
  40.          os_dly_wait(20);$ p' Y' o( n. V& n4 J+ h  ?
  41.      }) k4 `) M( I* G9 F4 J- `
  42. }
    ; G/ @+ f0 W) Q$ o8 N: @

  43.   x7 e( P+ `* |
  44. /*/ X, l5 B" {4 g+ W5 m/ l
  45. *********************************************************************************************************
    , ^! i% Q* s/ W8 F5 R7 C( f
  46. *    函 数 名: AppTaskLED3 K( M7 Y' `# U* N: J* m
  47. *    功能说明: LED闪烁。
    & M  Z' Q+ D' e5 P
  48. *    形    参: 无
    3 f% t0 X) n. {# Z
  49. *    返 回 值: 无5 r7 [) ?, Y  u& R4 y4 N! d; Y& `& o
  50. *   优 先 级: 2
    & P3 @, x) V* p
  51. *********************************************************************************************************! y" s# \7 E7 w: c/ \1 {
  52. */4 }% J* c1 Y  i- w* O. Y
  53. __task void AppTaskLED(void)  ^# ?) z& ~& @' @
  54. {+ A. y2 j  l; L  H& M. |) F0 v) r! e
  55.      const uint16_t usFrequency = 200; /* 延迟周期 */$ J' Q/ U0 g. s$ l2 v. M1 O
  56.    
    3 }; I; E9 Y7 a" F
  57.      /* 设置延迟周期 */) L. ~4 B& N) x, D# y' q0 _
  58.      os_itv_set(usFrequency);
    * z9 H; b+ e* c2 G: J( X# I! T
  59.    
    - g2 e' |2 Q4 [! @- ?: F' ^
  60.     while(1)
    0 v5 @/ ^# V  y  N
  61.     {* i2 C$ A) y% M  l7 G$ m. m
  62.          bsp_LedToggle(2);
    4 x" d. G! E! O! |; @# \6 Z8 k
  63.          bsp_LedToggle(3);/ t; D5 [7 }! s1 z) F5 v
  64. ! B, q0 f7 S4 T# g, |
  65.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/$ \, y$ o: w3 T$ y  |; G1 ~
  66.          os_itv_wait();
    ; \" D  W6 U; g  I" Z0 o
  67.     }
    ! w, f0 P8 x! a2 U
  68. }
    ! e5 F/ f: S% Z/ r, P. L# A
  69. + t2 X! g% b2 g. Z
  70. /*) N) K0 L! S# C5 H
  71. *********************************************************************************************************8 A* ]* v- n$ X5 K, E8 R% O
  72. *    函 数 名: AppTaskMsgPro- {4 A7 x) B/ g6 y( e% l
  73. *    功能说明: 消息处理,这里用作LED闪烁/ Z# M" _' s" E
  74. *    形    参: 无# _) Z; ^* H/ D7 ]% l, c1 }) U3 W
  75. *    返 回 值: 无
    8 J# v1 _& U. ?0 }+ k/ W
  76. *   优 先 级: 3 " N( a+ V) l) X8 X+ w" ^
  77. *********************************************************************************************************8 [! n+ y) R) U
  78. */9 J3 Z; `6 E" Y; a1 p' |
  79. __task void AppTaskMsgPro(void)! l" Q; p/ O+ m" O+ \) X+ s- v$ ^
  80. {  h- k! x$ E0 x
  81.      const uint16_t usFrequency = 500; /* 延迟周期 */- @$ D+ L: B" u
  82.     " B$ P/ n) [& j3 }2 {( B
  83.      /* 设置延迟周期 */' s8 q( E: G. V$ c1 ?
  84.      os_itv_set(usFrequency);
    ' Q  }6 t1 R) [" T; j6 C
  85.    
    " v# u9 s3 W; V5 O. @
  86.      while(1)
    / q" b  h: k( g5 j
  87.      {& ]+ H2 g- z0 e0 n5 e, m% g
  88.          bsp_LedToggle(1);
    + k. @6 |' b1 }
  89.          bsp_LedToggle(4);
    ' X( J( j2 J, t; I* V9 G+ t
  90. % H; O2 z# f: h
  91.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/7 V8 _" ~* @3 c8 |- I1 Z$ R; P8 E
  92.          os_itv_wait();
      Z% j* N( Y" {/ l: n! W
  93.      }   
    / t6 g7 X$ k9 @$ M2 z3 r
  94. }; D! X$ |" s% ^4 I, S

  95. , [/ [: `1 z- V( x4 ]' E/ ?# f8 P
  96. /*/ D2 R1 ]) ~1 u7 a- @- U7 s
  97. *********************************************************************************************************" [5 ?# i) f, Q# J$ t$ J4 H
  98. *    函 数 名: AppTaskStart
    6 @* U; I" i" A% z3 \
  99. *    功能说明: 启动任务,也就是最高优先级任务。这里实现按键扫描。  W* Z  s3 v( C
  100. *    形    参: 无
    9 U' L0 n$ M5 u2 j( h' y& r  i$ ~5 T6 @
  101. *    返 回 值: 无
    ( D& n* s! x/ s
  102. *   优 先 级: 4 4 J( f% d* T; d( K! K0 U; Y, O
  103. *********************************************************************************************************# u8 H% i4 e7 M  O* U
  104. */+ R+ ?  U& a, B" Q% W4 h  x; I
  105. __task void AppTaskStart(void)
    3 ]1 H' Y0 h( T1 E8 x
  106. {
    ; g4 F0 S. X$ Z3 K0 l
  107.      /* 创建任务 */
    & x% ^6 a1 R8 o
  108.      AppTaskCreate();$ X7 V8 h5 x( P7 I. b# d0 l4 L
  109.     ( t( W- g- l6 C2 S' e7 Q$ f
  110.     while(1)& M* r; w, o' e. S7 b$ {
  111.     {
    ( Q/ O, W+ I4 F* P; u( N6 G$ G4 ~
  112.          /* 按键扫描 */
    - Q9 G7 T+ q3 y% [; L; g' M
  113.          bsp_KeyScan();# k  \% R3 k$ x  L) G, A2 s2 m1 i
  114.         os_dly_wait(10);
    0 I- E3 W8 I6 Q
  115.     }
    ' y% w9 s1 o, A- {: _
  116. }
复制代码
6 q* Y: e) G2 v. J) }' X- G
3 v( m' }. S( y/ Y6 F! w
baiyongbin2009 回答时间:2016-1-23 18:00:25
9.3.2     STM32F407开发板实验
配套例子:
    V5-404_RTX实验_任务运行在用户模式(非特权级)
实验目的:
    1. 学习RTX的任务运行在用户模式的设置方法
实验内容:
    1. K1按键按下,串口打印。
    2. K2键按下,设置NVIC分组,从而导致系统进入到硬件异常HardFault_Handler。
    3. 各个任务实现的功能如下:
      AppTaskUserIF任务  :按键消息处理。
      AppTaskLED任务     :LED闪烁。
      AppTaskMsgPro任务 :消息处理,这里用作LED闪烁。
      AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX配置:
    RTX配置向导详情如下:
9.14.png
                              
Task Configuration
(1)Number of concurrent running tasks
        允许创建4个任务,实际创建了如下四个任务
                     AppTaskUserIF任务   :按键消息处理。
                     AppTaskLED任务     :LED闪烁。
                     AppTaskMsgPro任务 :消息处理,这里是用作LED闪烁。
                     AppTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
(2)Number of tasks with user-provided stack
    创建的4个任务都是采用自定义堆栈方式。
(3) Run in privileged mode
    设置RTX任务运行在非特权级,即用户模式。

$ Y8 V; w9 t; ~- j1 ~1 U
RTX任务调试信息:
9.15.png
程序设计:
任务栈大小分配:
    staticuint64_t AppTaskUserIFStk[512/8];   /* 任务栈 */
    staticuint64_t AppTaskLEDStk[256/8];      /* 任务栈 */
    staticuint64_t AppTaskMsgProStk[512/8];  /* 任务栈 */
    staticuint64_t AppTaskStartStk[512/8];     /* 任务栈 */
    将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
系统栈大小分配:
9.16.png
RTX初始化:
  1. /*
    - U2 w6 c. T; M9 g4 l
  2. *********************************************************************************************************- Z1 Z8 ?/ i, a% Q3 D
  3. *    函 数 名: main
    $ k) t" m7 T  @! w' }' p$ r
  4. *    功能说明: 标准c程序入口。
    ) C4 i8 r* I( S  C# u* x
  5. *    形    参: 无
    8 g" \/ e; Y( Q: p, @  h  Y
  6. *    返 回 值: 无
    3 f. L1 L: D! ]
  7. *********************************************************************************************************
      ~0 p1 {9 s" S$ L% G
  8. */7 F% K, J6 A/ H6 h# g' s: ?
  9. int main (void)* U3 S5 }/ i9 I
  10. {   ; u8 L6 B6 H; j0 A* c/ Z
  11.      /* 初始化外设 */* h6 k5 P" D3 P" a1 A: j$ J
  12.      bsp_Init();# w- ]) `7 \& C
  13.    
    & `7 S) ?# n8 Y' k/ D5 L0 Z% G
  14.      /* 创建启动任务 */
    0 @: \) e2 A; ^3 q3 D6 z% B6 [* I
  15.      os_sys_init_user (AppTaskStart,             /* 任务函数 */8 o  g% U' k) F! x# Y- {
  16.                        4,                        /* 任务优先级 */2 s1 f$ f9 [  x) W2 C  [
  17.                        &AppTaskStartStk,         /* 任务栈 */
    , s" u! c8 {. M  C1 s0 ^! @. n' W
  18.                        sizeof(AppTaskStartStk)); /* 任务栈大小,单位字节数 */+ P# [9 a. f; S. Z1 Y# {. W
  19.      while(1);" n' t5 }$ S1 Z- d$ ^. W
  20. }
复制代码

$ h' M+ a: n7 U0 M* G# ~
RTX任务创建:
  1. /*
    0 e: l' l. a9 F+ z. ?
  2. *********************************************************************************************************) l2 A( F+ k1 }% s
  3. *    函 数 名: AppTaskCreate; ~* n) e2 a$ T
  4. *    功能说明: 创建应用任务  D, u3 O* s% W. R5 a3 M9 {- G
  5. *    形    参: 无
    ( [2 E# g9 c# C. B3 T
  6. *    返 回 值: 无0 C' Z& }# Z" V  M
  7. *********************************************************************************************************
    % B8 s* Y9 A  s" b: p0 P
  8. */
    ) G# b" j5 l8 E; J; W, V! c* p
  9. static void AppTaskCreate (void)) K; N0 Y" B0 s
  10. {
    2 v! U7 J4 B7 j
  11.      HandleTaskUserIF = os_tsk_create_user(AppTaskUserIF,             /* 任务函数 */5 c& c# b9 }: T7 D+ A) i
  12.                                            1,                         /* 任务优先级 */* m4 G) W: X2 A6 O& e1 a
  13.                                            &AppTaskUserIFStk,         /* 任务栈 */$ X# ^+ y! n* ?+ f
  14.                                            sizeof(AppTaskUserIFStk)); /* 任务栈大小,单位字节数 */' x# H* l+ }# ?4 Y3 \! D" U
  15.    
    2 W) ^+ P0 ]! g( X, ~( M
  16.      HandleTaskLED = os_tsk_create_user(AppTaskLED,              /* 任务函数 */: A) u9 Z( _% H. q! U( r4 F; u
  17.                                         2,                       /* 任务优先级 */! x% H/ A$ t. d$ y' q& E
  18.                                         &AppTaskLEDStk,          /* 任务栈 *// M6 m" k3 d4 a* n' F, T
  19.                                         sizeof(AppTaskLEDStk));  /* 任务栈大小,单位字节数 */" X: F0 |9 n) I: b! z7 N
  20.    
    0 T+ h& s. `" R# E: N3 R8 Q
  21.      HandleTaskMsgPro = os_tsk_create_user(AppTaskMsgPro,             /* 任务函数 */2 P- i  x- x, Q% b% A& o+ `* n
  22.                                            3,                         /* 任务优先级 */
    0 l# [4 u# U  ]
  23.                                            &AppTaskMsgProStk,         /* 任务栈 */
    8 s6 w+ r) T) l( S* E
  24.                                            sizeof(AppTaskMsgProStk)); /* 任务栈大小,单位字节数 */
    # a3 Q$ O1 _" @& Z8 x+ p9 Z7 T
  25. }
复制代码

$ z- l! k9 I) N
四个RTX任务的实现:
  1. /*
    6 r" H1 J9 C* z/ V) c" d( W
  2. ********************************************************************************************************** n$ c% l6 [6 X& L! Q# Y. M
  3. *    函 数 名: AppTaskUserIF
    0 z# h: V9 `# p: O; O3 }
  4. *    功能说明: 按键消息处理     
    8 W; r  ^# p( |
  5. *    形    参: 无
    $ O8 x0 P1 \' H- e5 o( B7 G) K7 H4 T- q
  6. *    返 回 值: 无& ]0 S; R6 ?1 r0 M
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
    9 U' y" W# x+ r+ w5 n
  8. *********************************************************************************************************
    3 \$ _3 n( ?' t  a, @% V
  9. *// {. a2 p8 M& a3 B. s7 |
  10. __task void AppTaskUserIF(void)
      ~6 {# m+ q( L+ ^0 B# D6 R! }
  11. {( C; G& [2 r: o# _8 F2 |
  12.      uint8_t ucKeyCode;' D5 Z' b2 @! Q2 l

  13. ( n2 E* g% {. z1 z$ s/ o- v, F
  14.     while(1)4 i0 v9 ]8 N) b" O! _* D0 v0 G# I
  15.     {
    * f3 g' g1 ~+ _3 R0 Z  L
  16.          ucKeyCode = bsp_GetKey();
    / z  p. ?& t4 \" p) q, [; U( g4 T' T
  17.         
    9 m. V& ^) j, @6 W. x
  18.          if (ucKeyCode != KEY_NONE)
    , p3 k) n( a+ @% n  R2 |
  19.          {
    2 u; D- v5 ~2 q9 P
  20.               switch (ucKeyCode)
    4 Y/ X; _5 K# A2 `' v7 U7 S5 h
  21.               {6 i1 k5 k8 |# R5 K" L- F& b: F- A5 `
  22.                    /* K1键按下,打印调试说明 *// V. p: J0 n/ E3 t
  23.                    case KEY_DOWN_K1:- e/ G- t4 Q- c; Y  S
  24.                        printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");; P! j2 `$ X; p* J9 w% h0 h
  25.                        break;  
    ' b7 z$ ~( H) R. n, b( @  i

  26. ' J2 D  d0 [- ^8 J' I: i4 A6 B: q# q
  27.                    /* K2键按下,非特权级模式下设置NVIC分组,从而导致系统进入到硬件异常HardFault_Handler */7 p. q) m$ Q/ Y
  28.                    case KEY_DOWN_K2:
    % ^! i2 [* k) R/ W" N
  29.                        printf("K2键按下,非特权级模式下设置NVIC分组,从而导致系统进入到硬件异常! Y- Z" P/ Y$ A' A$ b: z% T
  30. HardFault_Handler\r\n");
    - u; f2 K4 B, B' r0 y7 g" X
  31.                        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
    ) p( V, A- c: p% _0 {: U
  32.                        break;4 x( o) T( h1 N7 ^# m

  33. / D% v2 P% D# }2 I
  34.                    /* 其他的键值不处理 */0 `5 t8 {' l2 x2 Z" n
  35.                    default:                    
    3 b3 A" W' O, |1 U' \  c
  36.                        break;9 ^1 x3 ^: _2 ~8 J& p# L; }6 _+ c
  37.               }6 y% I2 |5 W4 u  M& ]- h) r
  38.          }
    2 f% s3 Q  p; d4 S7 V
  39.         
    ; M. L( ]5 H- }  b" y! w
  40.          os_dly_wait(20);2 C' d% w4 o  Z, x. U
  41.      }
      F" V- q# m- J' u% Q' L
  42. }* S0 [. R5 Y2 q$ }+ H3 V

  43. 6 H% t9 B; \' v! M  V9 V
  44. /*, ]8 z9 l) H* y2 T# V7 H0 _; `
  45. *********************************************************************************************************9 ]8 _2 M8 ?# @6 P2 t$ X" \/ j' [
  46. *    函 数 名: AppTaskLED. H3 l2 M9 z8 F& K
  47. *    功能说明: LED闪烁。  t; n; j: `# ^8 t
  48. *    形    参: 无
    : m' S" U/ ^9 {3 M4 ^' N' `
  49. *    返 回 值: 无& e+ V) d; b9 Q4 e/ M
  50. *   优 先 级: 2 % f  x& B& w! J& X2 r! l
  51. *********************************************************************************************************7 B/ O! U) @% W* @
  52. */- |6 h0 R" F9 V3 q
  53. __task void AppTaskLED(void)
    - |, v! ^* U, J
  54. {3 |  V, M* a, C/ l$ }0 m4 _* R
  55.      const uint16_t usFrequency = 200; /* 延迟周期 */! e; d4 c& t  ?
  56.     + M4 s* n8 h* b3 S7 V- u
  57.      /* 设置延迟周期 */1 Q8 U) D! S+ H! n' C
  58.      os_itv_set(usFrequency);8 V1 Y, f/ Q6 M! V: T. }2 b
  59.    
    $ I6 }2 m+ i4 P' M; a  I7 X
  60.     while(1)
    , J9 R( c* i2 u& C
  61.     {# N: V9 X( n9 K& g* L2 ?
  62.          bsp_LedToggle(2);
    3 c4 L  B8 Y6 l/ @- Y  n9 s/ s
  63.          bsp_LedToggle(3);- R: Z$ T2 C. b: ^4 C( o$ W$ d* r" C& p
  64. % {! x) {( d: A  S; h) O. [2 q
  65.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/
    ( G) |, Q" P. \  m" H9 l
  66.           os_itv_wait();. Z6 [* e% s) h+ T2 q: u
  67.     }6 a4 k5 ~- X8 a
  68. }
    3 ?6 O  A2 r' p/ s5 V9 E' C

  69. & M& {3 R7 f8 J, ^1 ]" j
  70. /*$ q8 B8 O5 K9 f: @
  71. *********************************************************************************************************1 E( a9 v" D4 m) |; r/ F
  72. *    函 数 名: AppTaskMsgPro
    , q2 R4 z& ^. K- z7 D
  73. *    功能说明: 消息处理,这里用作LED闪烁
    4 C9 X' e" |- o" L0 _& b/ x8 ]
  74. *    形    参: 无8 v2 b1 P0 A$ L- t
  75. *    返 回 值: 无5 t1 M! h( Q) m0 e* c4 z
  76. *   优 先 级: 3
    " f+ @1 V9 p$ O* \" y. l
  77. *********************************************************************************************************9 N9 Q2 J. Z/ L8 @4 ]! S( r
  78. */( J2 q+ y) L; T/ [( O5 X
  79. __task void AppTaskMsgPro(void)% x8 l5 \2 n+ k, ]) `+ ^" \, L
  80. {' j% H# W: K1 K/ ]/ O
  81.      const uint16_t usFrequency = 500; /* 延迟周期 */
    . b! M+ |* j* v) X8 a
  82.    
    / g% p6 a! l: E6 m
  83.      /* 设置延迟周期 */
    3 M/ j* b! t; ^. s# I- q# x. ^
  84.      os_itv_set(usFrequency);
    0 T5 d0 e3 K" l* b1 q
  85.    
    $ W8 p6 _$ u6 N, X2 [
  86.      while(1)  k# A# v- n6 u1 y
  87.      {# X0 v3 b3 n# }4 u3 p4 j/ Y
  88.          bsp_LedToggle(1);
    ) d( F0 s  E! _7 w3 `
  89.          bsp_LedToggle(4);
    ; o3 R5 }3 O/ J$ U

  90. 0 \7 V5 b7 B% f9 i4 k" x% X
  91.          /* os_itv_wait是绝对延迟,os_dly_wait是相对延迟。*/, T2 l" g: r. r  G5 f4 E% g
  92.          os_itv_wait();
    0 l; G2 `$ _8 N# m
  93.      }   9 b$ @- ~0 r8 g  R
  94. }6 }* o! \3 R# w' n3 J
  95. ! F) [  \: I" l3 K, A3 Z
  96. /*
    + b) j  \3 L; j- o5 o' W! ?+ F
  97. *********************************************************************************************************
    . m8 ?7 _6 U" S! `6 ^
  98. *    函 数 名: AppTaskStart
    ; p' t3 P/ x8 ~" {
  99. *    功能说明: 启动任务,也就是最高优先级任务。这里实现按键扫描。& J- [0 Q1 S4 Q6 ?/ L: {" e' {
  100. *    形    参: 无; v8 r, X* D4 S! }  G9 X
  101. *    返 回 值: 无
    0 E9 H- Y7 z% j. `. n8 ~0 C
  102. *   优 先 级: 4
    0 T9 ?0 Q6 y/ X
  103. *********************************************************************************************************7 \5 v3 i, E) M1 R  w* e5 {: b
  104. */
    ; m, i/ n" U; K3 E
  105. __task void AppTaskStart(void)7 F, e0 L* L9 J: `. r
  106. {" p1 y, K+ u) A: ]
  107.      /* 创建任务 */" A( N. S; a- Z) ~
  108.      AppTaskCreate();
    ; p7 }5 c$ J2 t, A6 h1 ^' M, W
  109.     8 A3 M* J! ?) j7 b7 }! R0 y
  110.     while(1)
    7 W- O6 ?8 V% m
  111.     {
    7 G# ?, y" O3 k& k" _! g3 y$ W) g
  112.          /* 按键扫描 */: j: h! l# a, `( f# N$ J* d
  113.          bsp_KeyScan();
    6 }) y- h6 W9 f
  114.         os_dly_wait(10);
    - {$ h$ n* A( ?6 _% {0 ]2 r. G
  115.     }2 `+ T# E1 o8 k+ e5 F# P' |6 `
  116. }
复制代码
$ t3 f9 E- `8 M% t% a
! P* `& k  r! e3 X3 {# j& ~
baiyongbin2009 回答时间:2016-1-23 18:01:08
9.4  总结
    对于初学者来说,容易在特权级和非特权级的地方出错。如果以前没有这方面基础的话,理解的时候还稍困难些,不急,慢慢来,完全的理解也需要一个循序渐进的过程。
) w4 n( U# j3 g( `- p1 V" ]
回到未来~ 回答时间:2016-1-24 20:56:54
感谢分析,详细的帖子!虽然没用过安福来……
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版