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

【安富莱STM32F407之uCOS-III教程】第9章 μCOS-III系统移植文...

[复制链接]
baiyongbin2009 发布时间:2014-12-22 16:52
本帖最后由 baiyongbin2009 于 2014-12-22 16:54 编辑

特别说明:
1.  本教程是安富莱电子原创。
2.  安富莱STM32F407开发板资料已经全部开源,开源地址:地址链接

3.  当前共配套300多个实例,4套用户手册。

第9章  μCOS-III系统移植文件详解

    本期教程主要主要跟大家讲解μCOS-III系统的官方移植文件,理解这几个移植文件很重要,如果这几个文件理解的比较深入的话,对于后面学习源码大有裨益。这几个文件主要就是实现任务切换的功能,关于任务切换咱们在前面几期已经详细讲解了工作原理(没有看的同学一定要看第4章和第5章,要不理解学习本章教程依然吃力),本期教程就是结合前面讲解,进一步讲解μCOS-III中任务切换实现的原理。
    9.1 移植文件
    9.2 os_cpu.h文件讲解
    9.3 os_cpu_c.c文件讲解
    9.4 os_cpu_a.asm文件讲解
    9.5 总结
9.1  移植文件
    官方提供的uCOS-III,uC-LIB,uC-CPU文件中都有Ports文件夹,咱们主要关心的是uCOS-III中的Ports文件夹。Ports文件夹中含有如下三个版本的移植文档:
9.1.png

    RealView就是用MDK编译器的移植文件,其余两个文件夹中的移植文件是用IAR和GUN的。咱们就以RealView中的移植文件为例跟大家详细的讲解下。RealView中的文件如下:
9.2.png

    os_cpu.h,os_cpu_c.c,os_cpu_a.asm这三个文件在移植过程中最重要,下面主要的就是把这三个文件中的内容详细讲解一下。
9.1  os_cpu.h文件讲解
    此头文件的内容比较少,下面就将里面的内容说明一下
9.2.1      宏定义
  1. #ifdef   OS_CPU_GLOBALS
  2. #define  OS_CPU_EXT
  3. #else
  4. #define  OS_CPU_EXT  extern   
  5. #endif

  6. /*
  7. *********************************************************************************************************
  8. *                                               MACROS
  9. *********************************************************************************************************
  10. */

  11. #define  OS_TASK_SW()               OSCtxSw()
复制代码

  l  由于工程中没有声明OS_CPU_GLOBALS,所以使用的都是#define  OS_CPU_EXT  extern源码的头文件中使用OS_CPU_EXT的地方很多,大家要记住这个的含义。
  l  #define OS_TASK_SW()     OSCtxSw()
    这个是任务级的任务切换函数,后面还有个中断级的任务切换。函数实体在os_cpu_a.asm文件中。此函数的主要功能就是实现任务的切换。
  1. /*
  2. *********************************************************************************************************
  3. *                              OS TICK INTERRUPT PRIORITY CONFIGURATION
  4. *
  5. * Note(s) : (1) For systems that don't need any high, real-time priority interrupts; the tick interrupt
  6. *               should be configured as the highest priority interrupt but won't adversely affect system
  7. *               operations.
  8. *
  9. *           (2) For systems that need one or more high, real-time interrupts; these should be configured
  10. *               higher than the tick interrupt which MAY delay execution of the tick interrupt.
  11. *
  12. *               (a) If the higher priority interrupts do NOT continually consume CPU cycles but only
  13. *                   occasionally delay tick interrupts, then the real-time interrupts can successfully
  14. *                   handle their intermittent/periodic events with the system not losing tick interrupts
  15. *                   but only increasing the jitter.
  16. *
  17. *               (b) If the higher priority interrupts consume enough CPU cycles to continually delay the
  18. *                   tick interrupt, then the CPU/system is most likely over-burdened & can't be expected
  19. *                   to handle all its interrupts/tasks. The system time reference gets compromised as a
  20. *                   result of losing tick interrupts.
  21. *********************************************************************************************************
  22. */

  23. #define  OS_CPU_CFG_SYSTICK_PRIO           0u
复制代码
l OS_CPU_CFG_SYSTICK_PRIO 用于配制嘀嗒定时器的优先级。关于嘀嗒定时器优先级的配置还是很讲究的,也就是上面注释所写的。
  Ø 对于那些不需要高优先级中断的系统,嘀嗒定时器中断要配置成最高优先级的中断,但是不能影响系统操作。
  Ø 如果系统中多个高优先级的中断,而且优先级比嘀嗒定时器的优先级高,那么就可能会延迟嘀嗒定时器中断。
    u 如果高优先级的中断不会持续的占有CPU,只是偶尔的延迟嘀嗒定时器中断,那么实时中断可以间歇性或者周期性的处理系统事件而不丢失嘀嗒定时器中断,只是增加抖动(因为高优先级中断的执行会抢占嘀嗒定时器中断的执行或者高优先级中断执行的时候嘀嗒定时器中断会一直得不到执行从而造成嘀嗒定时器中断在执行时间上的抖动)。
    u 如果高优先级的任务长时间的占有CPU时间会造成系统超负荷运行,而不能执行嘀嗒定时器中断,任务也不能得到及时的执行。这种情况可以认为系统丢失了几次嘀嗒定时器的执行。

收藏 评论11 发布时间:2014-12-22 16:52

举报

11个回答
baiyongbin2009 回答时间:2014-12-22 16:58:09
本帖最后由 baiyongbin2009 于 2014-12-22 17:00 编辑

(续)9.2  os_cpu.h文件讲解

9.2.2      时间戳配置
  1. /*
  2. *********************************************************************************************************
  3. *                                       TIMESTAMP CONFIGURATION
  4. *
  5. * Note(s) : (1) OS_TS_GET() is generally defined as CPU_TS_Get32() to allow CPU timestamp timer to be of
  6. *               any data type size.
  7. *
  8. *           (2) For architectures that provide 32-bit or higher precision free running counters
  9. *               (i.e. cycle count registers):
  10. *
  11. *               (a) OS_TS_GET() may be defined as CPU_TS_TmrRd() to improve performance when retrieving
  12. *                   the timestamp.
  13. *
  14. *               (b) CPU_TS_TmrRd() MUST be configured to be greater or equal to 32-bits to avoid
  15. *                   truncation of TS.
  16. *********************************************************************************************************
  17. */

  18. #if      OS_CFG_TS_EN == 1u
  19. #define  OS_TS_GET()               (CPU_TS)CPU_TS_TmrRd() /* See Note #2a.                     */
  20. #else
  21. #define  OS_TS_GET()               (CPU_TS)0u
  22. #endif

  23. #if (CPU_CFG_TS_32_EN    == DEF_ENABLED) && \
  24.     (CPU_CFG_TS_TMR_SIZE  < CPU_WORD_SIZE_32)
  25.                                                    /* CPU_CFG_TS_TMR_SIZE MUST be >= 32-bit (see Note #2b).  */
  26. #error  "cpu_cfg.h, CPU_CFG_TS_TMR_SIZE MUST be >= CPU_WORD_SIZE_32"
  27. #endif
复制代码

l OS_CFG_TS_EN在函数os_cfg.h里面进行了宏定义:
#defineOS_CFG_TS_EN                    1u   //用于使能或者禁止时间戳,这里1表示使能        
//时间戳,0表示禁止时间戳
       下面重点说一下函数CPU_TS_TmrRd(),相对来说此函数比较的重要。这个函数在μCOS-III中主要用于任务利用率的测量,和信号量、邮箱、事件标志组等执行时间的测量。这个函数不属于μCOS-III源码部分,确切的说应该是属于μC/CPU。此函数的内容需要用户根据自己使用的处理器进行实现,以提供更高精度的时间基准,至少要高于系统的时钟节拍精度,这样才能获得更准确的函数执行时间和任务利用率的测量。使用这个函数前需要先做初始化(在文件bsp.c里面):
  1. /*
  2. *********************************************************************************************************
  3. *                                          CPU_TS_TmrInit()
  4. *
  5. * Description : Initialize & start CPU timestamp timer.
  6. *
  7. * Argument(s) : none.
  8. *
  9. * Return(s)   : none.
  10. *
  11. * Caller(s)   : CPU_TS_Init().
  12. *
  13. *               This function is an INTERNAL CPU module function & MUST be implemented by application/
  14. *               BSP function(s) [see Note #1] but MUST NOT be called by application function(s).
  15. *
  16. * Note(s)     : (1) CPU_TS_TmrInit() is an application/BSP function that MUST be defined by the developer
  17. *                   if either of the following CPU features is enabled :
  18. *
  19. *                   (a) CPU timestamps
  20. *                   (b) CPU interrupts disabled time measurements
  21. *
  22. *                   See 'cpu_cfg.h  CPU TIMESTAMP CONFIGURATION  Note #1'
  23. *                     & 'cpu_cfg.h  CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION  Note #1a'.
  24. *
  25. *               (2) (a) Timer count values MUST be returned via word-size-configurable 'CPU_TS_TMR'
  26. *                       data type.
  27. *
  28. *                       (1) If timer has more bits, truncate timer values' higher-order bits greater
  29. *                           than the configured 'CPU_TS_TMR' timestamp timer data type word size.
  30. *
  31. *                       (2) Since the timer MUST NOT have less bits than the configured 'CPU_TS_TMR'
  32. *                           timestamp timer data type word size; 'CPU_CFG_TS_TMR_SIZE' MUST be
  33. *                           configured so that ALL bits in 'CPU_TS_TMR' data type are significant.
  34. *
  35. *                           In other words, if timer size is not a binary-multiple of 8-bit octets
  36. *                           (e.g. 20-bits or even 24-bits), then the next lower, binary-multiple
  37. *                           octet word size SHOULD be configured (e.g. to 16-bits).  However, the
  38. *                           minimum supported word size for CPU timestamp timers is 8-bits.
  39. *
  40. *                       See also 'cpu_cfg.h   CPU TIMESTAMP CONFIGURATION  Note #2'
  41. *                              & 'cpu_core.h  CPU TIMESTAMP DATA TYPES     Note #1'.
  42. *
  43. *                   (b) Timer SHOULD be an 'up'  counter whose values increase with each time count.
  44. *
  45. *                   (c) When applicable, timer period SHOULD be less than the typical measured time
  46. *                       but MUST be less than the maximum measured time; otherwise, timer resolution
  47. *                       inadequate to measure desired times.
  48. *
  49. *                   See also 'CPU_TS_TmrRd()  Note #2'.
  50. *********************************************************************************************************
  51. */

  52. #if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
  53. void  CPU_TS_TmrInit (void)
  54. {
  55.     CPU_INT32U  fclk_freq;


  56.     fclk_freq = BSP_CPU_ClkFreq();

  57.     BSP_REG_DEM_CR     |= (CPU_INT32U)BSP_BIT_DEM_CR_TRCENA;   /* Enable Cortex-M4's DWT CYCCNT reg.  */
  58.     BSP_REG_DWT_CYCCNT  = (CPU_INT32U)0u;
  59.     BSP_REG_DWT_CR     |= (CPU_INT32U)BSP_BIT_DWT_CR_CYCCNTENA;

  60.     CPU_TS_TmrFreqSet((CPU_TS_TMR_FREQ)fclk_freq);
  61. }
  62. #endif
复制代码
  Ø 这个函数不需要用户调用,用户可以通过调用函数CPU_Init();(在文件cpu_core.c里面)来调用这个函数。
  Ø 这里时基的实现是使用Cortex-M3/M4中自带的时钟周期计数器,关于时钟周期计数器的知识,大家需要查阅相关的技术手册进行了解,这里只需要知道每计数一次就是一个时钟周期,比如主频是168MHz的话,那么时钟周期就是1/168000000秒。除了μCOS-III是使用的时钟周期计数器作为时基以外,embOS也是使用的这个计数器作为时基。FreeRTOS是用的定时器做的时基。
  Ø 关于此函数的其它信息,需要大家看一下上面的英文说明,看看了解一下即可。




baiyongbin2009 回答时间:2014-12-22 16:59:18

(续)9.2.2  时间戳配置

说完了时间戳的初始化,下面说一下时钟周期计数器时间的读取,相关的函数还是位于bsp.c文件里面。
  1. /*
  2. *********************************************************************************************************
  3. * CPU_TS_TmrRd()
  4. *
  5. * Description : Get current CPU timestamp timer count value.
  6. *
  7. * Argument(s) : none.
  8. *
  9. * Return(s) : Timestamp timer count (see Notes #2a & #2b).
  10. *
  11. * Caller(s) : CPU_TS_Init(),
  12. * CPU_TS_Get32(),
  13. * CPU_TS_Get64(),
  14. * CPU_IntDisMeasStart(),
  15. * CPU_IntDisMeasStop().
  16. *
  17. * This function is an INTERNAL CPU module function & MUST be implemented by application/
  18. * BSP function(s) [see Note #1] but SHOULD NOT be called by application function(s).
  19. *
  20. * Note(s) : (1) CPU_TS_TmrRd() is an application/BSP function that MUST be defined by the developer
  21. * if either of the following CPU features is enabled :
  22. *
  23. * (a) CPU timestamps
  24. * (b) CPU interrupts disabled time measurements
  25. *
  26. * See 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #1'
  27. * & 'cpu_cfg.h CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION Note #1a'.
  28. *
  29. * (2) (a) Timer count values MUST be returned via word-size-configurable 'CPU_TS_TMR'
  30. * data type.
  31. *
  32. * (1) If timer has more bits, truncate timer values' higher-order bits greater
  33. * than the configured 'CPU_TS_TMR' timestamp timer data type word size.
  34. *
  35. * (2) Since the timer MUST NOT have less bits than the configured 'CPU_TS_TMR'
  36. * timestamp timer data type word size; 'CPU_CFG_TS_TMR_SIZE' MUST be
  37. * configured so that ALL bits in 'CPU_TS_TMR' data type are significant.
  38. *
  39. * In other words, if timer size is not a binary-multiple of 8-bit octets
  40. * (e.g. 20-bits or even 24-bits), then the next lower, binary-multiple
  41. * octet word size SHOULD be configured (e.g. to 16-bits). However, the
  42. * minimum supported word size for CPU timestamp timers is 8-bits.
  43. *
  44. * See also 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #2'
  45. * & 'cpu_core.h CPU TIMESTAMP DATA TYPES Note #1'.
  46. *
  47. * (b) Timer SHOULD be an 'up' counter whose values increase with each time count.
  48. *
  49. * (1) If timer is a 'down' counter whose values decrease with each time count,
  50. * then the returned timer value MUST be ones-complemented.
  51. *
  52. * (c) (1) When applicable, the amount of time measured by CPU timestamps is
  53. * calculated by either of the following equations :
  54. *
  55. * (A) Time measured = Number timer counts * Timer period
  56. *
  57. * where
  58. *
  59. * Number timer counts Number of timer counts measured
  60. * Timer period Timer's period in some units of
  61. * (fractional) seconds
  62. * Time measured Amount of time measured, in same
  63. * units of (fractional) seconds
  64. * as the Timer period
  65. *
  66. * Number timer counts
  67. * (B) Time measured = ---------------------
  68. * Timer frequency
  69. *
  70. * where
  71. *
  72. * Number timer counts Number of timer counts measured
  73. * Timer frequency Timer's frequency in some units
  74. * of counts per second
  75. * Time measured Amount of time measured, in seconds
  76. *
  77. * (2) Timer period SHOULD be less than the typical measured time but MUST be less
  78. * than the maximum measured time; otherwise, timer resolution inadequate to
  79. * measure desired times.
  80. *********************************************************************************************************
  81. */

  82. #if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
  83. CPU_TS_TMR CPU_TS_TmrRd (void)
  84. {
  85. CPU_TS_TMR ts_tmr_cnts;


  86. ts_tmr_cnts = (CPU_TS_TMR)BSP_REG_DWT_CYCCNT;

  87. return (ts_tmr_cnts);
  88. }
  89. #endif

  90. /*
  91. *********************************************************************************************************
  92. * CPU_TSxx_to_uSec()
  93. *
  94. * Description : Convert a 32-/64-bit CPU timestamp from timer counts to microseconds.
  95. *
  96. * Argument(s) : ts_cnts CPU timestamp (in timestamp timer counts [see Note #2aA]).
  97. *
  98. * Return(s) : Converted CPU timestamp (in microseconds [see Note #2aD]).
  99. *
  100. * Caller(s) : Application.
  101. *
  102. * This function is an (optional) CPU module application programming interface (API)
  103. * function which MAY be implemented by application/BSP function(s) [see Note #1] &
  104. * MAY be called by application function(s).
  105. *
  106. * Note(s) : (1) CPU_TS32_to_uSec()/CPU_TS64_to_uSec() are application/BSP functions that MAY be
  107. * optionally defined by the developer when either of the following CPU features is
  108. * enabled :
  109. *
  110. * (a) CPU timestamps
  111. * (b) CPU interrupts disabled time measurements
  112. *
  113. * See 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #1'
  114. * & 'cpu_cfg.h CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION Note #1a'.
  115. *
  116. * (2) (a) The amount of time measured by CPU timestamps is calculated by either of
  117. * the following equations :
  118. *
  119. * 10^6 microseconds
  120. * (1) Time measured = Number timer counts * ------------------- * Timer period
  121. * 1 second
  122. *
  123. * Number timer counts 10^6 microseconds
  124. * (2) Time measured = --------------------- * -------------------
  125. * Timer frequency 1 second
  126. *
  127. * where
  128. *
  129. * (A) Number timer counts Number of timer counts measured
  130. * (B) Timer frequency Timer's frequency in some units
  131. * of counts per second
  132. * (C) Timer period Timer's period in some units of
  133. * (fractional) seconds
  134. * (D) Time measured Amount of time measured,
  135. * in microseconds
  136. *
  137. * (b) Timer period SHOULD be less than the typical measured time but MUST be less
  138. * than the maximum measured time; otherwise, timer resolution inadequate to
  139. * measure desired times.
  140. *
  141. * (c) Specific implementations may convert any number of CPU_TS32 or CPU_TS64 bits
  142. * -- up to 32 or 64, respectively -- into microseconds.
  143. *********************************************************************************************************
  144. */

  145. #if (CPU_CFG_TS_32_EN == DEF_ENABLED)
  146. CPU_INT64U CPU_TS32_to_uSec (CPU_TS32 ts_cnts)
  147. {
  148. CPU_INT64U ts_us;
  149. CPU_INT64U fclk_freq;


  150. fclk_freq = BSP_CPU_ClkFreq();
  151. ts_us = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);

  152. return (ts_us);
  153. }
  154. #endif


  155. #if (CPU_CFG_TS_64_EN == DEF_ENABLED)
  156. CPU_INT64U CPU_TS64_to_uSec (CPU_TS64 ts_cnts)
  157. {
  158. CPU_INT64U ts_us;
  159. CPU_INT64U fclk_freq;


  160. fclk_freq = BSP_CPU_ClkFreq();
  161. ts_us = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);

  162. return (ts_us);
  163. }
  164. #endif
复制代码
    从上面的函数可以看出时钟周期计数器时间的获取还是很容易的,直接读取相应寄存器就能获得当前的计数。下面的两个函数CPU_TS32_to_uSec和CPU_TS32_to_uSec用于将时钟周期的数值转换成us为单位。函数还是很容易看懂,上面的英文说明反倒搞得挺复杂,大家读读了解些即可。

baiyongbin2009 回答时间:2014-12-22 17:01:20
9.2.3      函数声明
  1. /*
  2. *********************************************************************************************************
  3. *                                          GLOBAL VARIABLES
  4. *********************************************************************************************************
  5. */

  6. OS_CPU_EXT  CPU_STK  *OS_CPU_ExceptStkBase;

  7. /*
  8. *********************************************************************************************************
  9. *                                         FUNCTION PROTOTYPES
  10. *********************************************************************************************************
  11. */

  12. void  OSCtxSw              (void);
  13. void  OSIntCtxSw           (void);
  14. void  OSStartHighRdy       (void);

  15. void  OS_CPU_PendSVHandler (void);


  16. void  OS_CPU_SysTickHandler(void);
  17. void  OS_CPU_SysTickInit   (CPU_INT32U  cnts);
复制代码

l *OS_CPU_ExceptStkBase  异常堆栈指针,后面讲源码的时候在跟大家讲。
l  void  OSCtxSw              (void);
    void OSIntCtxSw           (void);
    void OSStartHighRdy       (void);
    void OS_CPU_PendSVHandler (void);
这四个函数在文件os_cpu_a.asm里面,主要用于实现任务切换。
l  void  OS_CPU_SysTickHandler(void);
    void  OS_CPU_SysTickInit   (CPU_INT32U cnts);
这两个函数的实体在文件os_cpu_c.c文件里面。

baiyongbin2009 回答时间:2014-12-22 17:05:35
本帖最后由 baiyongbin2009 于 2014-12-22 17:11 编辑

9.3  os_cpu_c.c文件讲解
    这文件里面主要是一些钩子函数,任务堆栈初始化和嘀嗒定时器的初始化。下面就详细的把这三个部分说明一下。
9.3.1      钩子函数
    钩子函数的主要功能就是扩展函数的功能,用户可以根据自己的需要往里面添加相关的测试函数,这个文件里面的钩子函数一共有个,下面就分别的讲解下。
  1. /*
  2. *********************************************************************************************************
  3. *                                           IDLE TASK HOOK
  4. *
  5. * Description: This function is called by the idle task.  This hook has been added to allow you to do
  6. *              such things as STOP the CPU to conserve power.
  7. *
  8. * Arguments  : None.
  9. *
  10. * Note(s)    : None.
  11. *********************************************************************************************************
  12. */

  13. void  OSIdleTaskHook (void)
  14. {
  15. #if OS_CFG_APP_HOOKS_EN > 0u
  16.     if (OS_AppIdleTaskHookPtr != (OS_APP_HOOK_VOID)0) {
  17.         (*OS_AppIdleTaskHookPtr)();
  18.     }
  19. #endif
  20. }
复制代码
l OSIdleTaskHook是空闲任务的钩子函数
    此函数被空闲任务调用,用户可以通过函数指针变量*OS_AppIdleTaskHookPtr指向用户设计的函数来实现用户所想实现的任务。这个函数主要用于实现低功耗。
  1. /*
  2. *********************************************************************************************************
  3. *                                       OS INITIALIZATION HOOK
  4. *
  5. * Description: This function is called by OSInit() at the beginning of OSInit().
  6. *
  7. * Arguments  : None.
  8. *
  9. * Note(s)    : None.
  10. *********************************************************************************************************
  11. */

  12. void  OSInitHook (void)
  13. {
  14.                                                 /* 8-byte align the ISR stack.     */   
  15.     OS_CPU_ExceptStkBase = (CPU_STK *)(OSCfg_ISRStkBasePtr + OSCfg_ISRStkSize);
  16.     OS_CPU_ExceptStkBase = (CPU_STK *)((CPU_STK)(OS_CPU_ExceptStkBase) & 0xFFFFFFF8);
  17. }
复制代码
l OSInitHook是OS初始化的钩子函数
    这个函数主要用于获取异常堆栈的基地址。这里这特别注意:这个异常堆栈是用于MSP(主堆栈空间),这样可以很方便的查询主堆栈的使用情况。针对Cortex-M4/M3内核的MCU,在使用RTOS的情况下,主堆栈主要用在中断服务程序中。
  1. /*
  2. *********************************************************************************************************
  3. *                                         STATISTIC TASK HOOK
  4. *
  5. * Description: This function is called every second by uC/OS-III's statistics task.  This allows your
  6. *              application to add functionality to the statistics task.
  7. *
  8. * Arguments  : None.
  9. *
  10. * Note(s)    : None.
  11. *********************************************************************************************************
  12. */

  13. void  OSStatTaskHook (void)
  14. {
  15. #if OS_CFG_APP_HOOKS_EN > 0u
  16.     if (OS_AppStatTaskHookPtr != (OS_APP_HOOK_VOID)0) {
  17.         (*OS_AppStatTaskHookPtr)();
  18.     }
  19. #endif
  20. }
复制代码
l OSStatTaskHook是统计任务的钩子函数
    使用方法和前面的空闲任务钩子函数一样。
  1. /*
  2. *********************************************************************************************************
  3. *                                          TASK CREATION HOOK
  4. *
  5. * Description: This function is called when a task is created.
  6. *
  7. * Arguments  : p_tcb        Pointer to the task control block of the task being created.
  8. *
  9. * Note(s)    : None.
  10. *********************************************************************************************************
  11. */

  12. void  OSTaskCreateHook (OS_TCB  *p_tcb)
  13. {
  14. #if OS_CFG_APP_HOOKS_EN > 0u
  15.     if (OS_AppTaskCreateHookPtr != (OS_APP_HOOK_TCB)0) {
  16.         (*OS_AppTaskCreateHookPtr)(p_tcb);
  17.     }
  18. #else
  19.     (void)p_tcb;                                            /* Prevent compiler warning                               */
  20. #endif
  21. }
复制代码
l OSTaskCreateHook是创建任务时的钩子函数
    使用方法和前面的空闲任务钩子函数基本一样,只是多了个函数参数。
  1. /*
  2. *********************************************************************************************************
  3. *                                           TASK DELETION HOOK
  4. *
  5. * Description: This function is called when a task is deleted.
  6. *
  7. * Arguments  : p_tcb        Pointer to the task control block of the task being deleted.
  8. *
  9. * Note(s)    : None.
  10. *********************************************************************************************************
  11. */

  12. void  OSTaskDelHook (OS_TCB  *p_tcb)
  13. {
  14. #if OS_CFG_APP_HOOKS_EN > 0u
  15.     if (OS_AppTaskDelHookPtr != (OS_APP_HOOK_TCB)0) {
  16.         (*OS_AppTaskDelHookPtr)(p_tcb);
  17.     }
  18. #else
  19.     (void)p_tcb;                                            /* Prevent compiler warning                               */
  20. #endif
  21. }
复制代码
l OSTaskDelHook 是任务删除的钩子函数
    使用方法和前面的创建任务钩子函数一样。

baiyongbin2009 回答时间:2014-12-22 17:10:44
(续)9.3.1  钩子函数
  1. /*
  2. *********************************************************************************************************
  3. *                                            TASK RETURN HOOK
  4. *
  5. * Description: This function is called if a task accidentally returns.  In other words, a task should
  6. *              either be an infinite loop or delete itself when done.
  7. *
  8. * Arguments  : p_tcb        Pointer to the task control block of the task that is returning.
  9. *
  10. * Note(s)    : None.
  11. *********************************************************************************************************
  12. */

  13. void  OSTaskReturnHook (OS_TCB  *p_tcb)
  14. {
  15. #if OS_CFG_APP_HOOKS_EN > 0u
  16.     if (OS_AppTaskReturnHookPtr != (OS_APP_HOOK_TCB)0) {
  17.         (*OS_AppTaskReturnHookPtr)(p_tcb);
  18.     }
  19. #else
  20.     (void)p_tcb;                                            /* Prevent compiler warning                               */
  21. #endif
  22. }
复制代码
l OSTaskReturnHook是任务返回的钩子函数
    这个函数的使用方面和前面的创建任务钩子函数是一样的。在RTOS中,任务必须得是超级循环的形式,如果任务只执行一次或者任务中有返回函数,系统就会调用异常返回函数将这个任务挂起或者删除(用户可以自行配置)。在异常返回函数中调用钩子函数。
  1. /*
  2. *********************************************************************************************************
  3. *                                           TASK SWITCH HOOK
  4. *
  5. * Description: This function is called when a task switch is performed.  This allows you to perform other
  6. *              operations during a context switch.
  7. *
  8. * Arguments  : None.
  9. *
  10. * Note(s)    : 1) Interrupts are disabled during this call.
  11. *              2) It is assumed that the global pointer 'OSTCBHighRdyPtr' points to the TCB of the task
  12. *                 that will be 'switched in' (i.e. the highest priority task) and, 'OSTCBCurPtr' points
  13. *                 to the task being switched out (i.e. the preempted task).
  14. *********************************************************************************************************
  15. */

  16. void  OSTaskSwHook (void)
  17. {
  18. #if OS_CFG_TASK_PROFILE_EN > 0u
  19.     CPU_TS  ts;
  20. #endif
  21. #ifdef  CPU_CFG_INT_DIS_MEAS_EN
  22.     CPU_TS  int_dis_time;
  23. #endif



  24. #if OS_CFG_APP_HOOKS_EN > 0u
  25.     if (OS_AppTaskSwHookPtr != (OS_APP_HOOK_VOID)0) {
  26.         (*OS_AppTaskSwHookPtr)();
  27.     }
  28. #endif

  29. #if OS_CFG_TASK_PROFILE_EN > 0u
  30.     ts = OS_TS_GET();
  31.     if (OSTCBCurPtr != OSTCBHighRdyPtr) {
  32.         OSTCBCurPtr->CyclesDelta  = ts - OSTCBCurPtr->CyclesStart;
  33.         OSTCBCurPtr->CyclesTotal += (OS_CYCLES)OSTCBCurPtr->CyclesDelta;
  34.     }

  35.     OSTCBHighRdyPtr->CyclesStart = ts;
  36. #endif

  37. #ifdef  CPU_CFG_INT_DIS_MEAS_EN
  38.     int_dis_time = CPU_IntDisMeasMaxCurReset();  /* Keep track of per-task interrupt disable time  */
  39.     if (OSTCBCurPtr->IntDisTimeMax < int_dis_time) {
  40.         OSTCBCurPtr->IntDisTimeMax = int_dis_time;
  41.     }
  42. #endif

  43. #if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
  44.                                                /* Keep track of per-task scheduler lock time    */
  45.     if (OSTCBCurPtr->SchedLockTimeMax < OSSchedLockTimeMaxCur) {
  46.         OSTCBCurPtr->SchedLockTimeMax = OSSchedLockTimeMaxCur;
  47.     }
  48.     OSSchedLockTimeMaxCur = (CPU_TS)0;         /* Reset the per-task value                     */
  49. #endif
  50. }
复制代码
l OSTaskSwHook 是任务切换的钩子函数
    这个函数里面也有用到函数指针,使用方法和前面的函数是一样的。函数里面还有一些执行时间的测量,这些内容会在后面源码讲解的时候再跟大家分析。
  1. /*
  2. *********************************************************************************************************
  3. *                                              TICK HOOK
  4. *
  5. * Description: This function is called every tick.
  6. *
  7. * Arguments  : None.
  8. *
  9. * Note(s)    : 1) This function is assumed to be called from the Tick ISR.
  10. *********************************************************************************************************
  11. */

  12. void  OSTimeTickHook (void)
  13. {
  14. #if OS_CFG_APP_HOOKS_EN > 0u
  15.     if (OS_AppTimeTickHookPtr != (OS_APP_HOOK_VOID)0) {
  16.         (*OS_AppTimeTickHookPtr)();
  17.     }
  18. #endif
  19. }
复制代码
l OSTimeTickHook 是嘀嗒定时器钩子函数
    这个函数的用法和前面的函数一样,被嘀嗒定时器中断服务程序所调用。

baiyongbin2009 回答时间:2014-12-22 17:12:27
9.3.2      嘀嗒定时器配置
    关于嘀嗒定时器在V5开发板用户手册第10章:SysTick实验里面有详细的讲解。这里就不再详细的赘述了,这里特别注意咱们已经在前面的os_cpu.h文件里面配置了嘀嗒定时器的优先级为0,也就是最高优先级。
  1. /*
  2. *********************************************************************************************************
  3. *                                          SYS TICK HANDLER
  4. *
  5. * Description: Handle the system tick (SysTick) interrupt, which is used to generate the uC/OS-II tick
  6. *              interrupt.
  7. *
  8. * Arguments  : None.
  9. *
  10. * Note(s)    : 1) This function MUST be placed on entry 15 of the Cortex-M3 vector table.
  11. *********************************************************************************************************
  12. */

  13. void  OS_CPU_SysTickHandler (void)
  14. {
  15.     CPU_SR_ALLOC();


  16.     CPU_CRITICAL_ENTER();
  17.     OSIntNestingCtr++;                                      /* Tell uC/OS-III that we are starting an ISR             */
  18.     CPU_CRITICAL_EXIT();

  19.     OSTimeTick();                                           /* Call uC/OS-III's OSTimeTick()                          */

  20.     OSIntExit();                                            /* Tell uC/OS-III that we are leaving the ISR             */
  21. }

  22. /*
  23. *********************************************************************************************************
  24. *                                         INITIALIZE SYS TICK
  25. *
  26. * Description: Initialize the SysTick.
  27. *
  28. * Arguments  : cnts         Number of SysTick counts between two OS tick interrupts.
  29. *
  30. * Note(s)    : 1) This function MUST be called after OSStart() & after processor initialization.
  31. *********************************************************************************************************
  32. */

  33. void  OS_CPU_SysTickInit (CPU_INT32U  cnts)
  34. {
  35.     CPU_INT32U  prio;


  36.     CPU_REG_NVIC_ST_RELOAD = cnts - 1u;

  37.                                                             /* Set SysTick handler prio.                              */
  38.     prio                   = CPU_REG_NVIC_SHPRI3;
  39.     prio                  &= DEF_BIT_FIELD(24, 0);
  40.     prio                  |= DEF_BIT_MASK(OS_CPU_CFG_SYSTICK_PRIO, 24);

  41.     CPU_REG_NVIC_SHPRI3    = prio;

  42.                                                             /* Enable timer.                                          */
  43.     CPU_REG_NVIC_ST_CTRL  |= CPU_REG_NVIC_ST_CTRL_CLKSOURCE |
  44.                              CPU_REG_NVIC_ST_CTRL_ENABLE;
  45.                                                             /* Enable timer interrupt.                                */
  46.     CPU_REG_NVIC_ST_CTRL  |= CPU_REG_NVIC_ST_CTRL_TICKINT;
  47. }
复制代码

baiyongbin2009 回答时间:2014-12-22 17:13:46
9.3.3      任务堆栈初始化
    每个任务创建时都会调用这个函数,主要用于初始化任务的堆栈,以便于第一次切换到各个任务时能正确的切换(特别注意这句话,用心体会)。
  1. /*
  2. **********************************************************************************************************
  3. *                                       INITIALIZE A TASK'S STACK
  4. *
  5. * Description: This function is called by OS_Task_Create() or OSTaskCreateExt() to initialize the stack
  6. *              frame of the task being created. This function is highly processor specific.
  7. *
  8. * Arguments  : p_task       Pointer to the task entry point address.
  9. *
  10. *              p_arg        Pointer to a user supplied data area that will be passed to the task
  11. *                               when the task first executes.
  12. *
  13. *              p_stk_base   Pointer to the base address of the stack.
  14. *
  15. *              stk_size     Size of the stack, in number of CPU_STK elements.
  16. *
  17. *              opt          Options used to alter the behavior of OS_Task_StkInit().
  18. *                            (see OS.H for OS_TASK_OPT_xxx).
  19. *
  20. * Returns    : Always returns the location of the new top-of-stack' once the processor registers have
  21. *              been placed on the stack in the proper order.
  22. *
  23. * Note(s)    : 1) Interrupts are enabled when task starts executing.
  24. *
  25. *              2) All tasks run in Thread mode, using process stack.
  26. **********************************************************************************************************
  27. */

  28. CPU_STK  *OSTaskStkInit (OS_TASK_PTR    p_task,
  29.                          void          *p_arg,
  30.                          CPU_STK       *p_stk_base,
  31.                          CPU_STK       *p_stk_limit,
  32.                          CPU_STK_SIZE   stk_size,
  33.                          OS_OPT         opt)
  34. {
  35.     CPU_STK  *p_stk;


  36.     (void)opt;                             /* Prevent compiler warning                               */

  37.     p_stk = &p_stk_base[stk_size];         /* Load stack pointer                                     */
  38.                                            /* Align the stack to 8-bytes.                            */
  39.     p_stk = (CPU_STK *)((CPU_STK)(p_stk) & 0xFFFFFFF8);
  40.                                            /* Registers stacked as if auto-saved on exception        */
  41.     *--p_stk = (CPU_STK)0x01000000u;       /* xPSR                                                   */
  42.     *--p_stk = (CPU_STK)p_task;            /* Entry Point                                            */
  43.     *--p_stk = (CPU_STK)OS_TaskReturn;     /* R14 (LR)                                               */
  44.     *--p_stk = (CPU_STK)0x12121212u;       /* R12                                                    */
  45.     *--p_stk = (CPU_STK)0x03030303u;       /* R3                                                     */
  46.     *--p_stk = (CPU_STK)0x02020202u;       /* R2                                                     */
  47.     *--p_stk = (CPU_STK)p_stk_limit;       /* R1                                                     */
  48.     *--p_stk = (CPU_STK)p_arg;               /* R0 : argument                                          */
  49.                                              /* Remaining registers saved on process stack             */
  50.     *--p_stk = (CPU_STK)0x11111111u;         /* R11                                                    */
  51.     *--p_stk = (CPU_STK)0x10101010u;         /* R10                                                    */
  52.     *--p_stk = (CPU_STK)0x09090909u;         /* R9                                                     */
  53.     *--p_stk = (CPU_STK)0x08080808u;         /* R8                                                     */
  54.     *--p_stk = (CPU_STK)0x07070707u;         /* R7                                                     */
  55.     *--p_stk = (CPU_STK)0x06060606u;         /* R6                                                     */
  56.     *--p_stk = (CPU_STK)0x05050505u;         /* R5                                                     */
  57.     *--p_stk = (CPU_STK)0x04040404u;         /* R4                                                     */

  58.     return (p_stk);
  59. }
复制代码
    看似简单的初始化,信息量还是很大的。
  l 任务堆栈空间的8字节对齐。
  l 任务堆栈的初始化顺序,先是自动入栈的8个寄存器xPSR、PC、LR、R14、R12、R3、R2、R1、R0,然后是手动入栈的8个寄存器R4-R11。
  l 由于M4内核的堆栈生长方向是向下生长的满栈,所以初始化的时候先获得任务堆栈的末地址,然后依次递减存储这些寄存器。
  l 特别注意这句初始化:*--p_stk = (CPU_STK)OS_TaskReturn; 它的作用就是防止用户写的任务不是超级循环,而出现任务返回的情况,如果任务返回的话就会返回到OS_TaskReturn这个函数里面。
    假如任务1的堆栈控件是uint32_t  stack[1024],那么堆栈初始化后寄存器在堆栈中的排列如下:
9.3.png

baiyongbin2009 回答时间:2014-12-22 17:15:35
本帖最后由 baiyongbin2009 于 2014-12-22 17:17 编辑

9.4  os_cpu_a.asm文件讲解
    这个文件中函数的主要作用是实现任务切换,如果大家第5章的教程学懂了,这里面的函数要简单很多,μCOS-III中没有使用到SVC,只是使用了PendSV。所以大家只需懂得PendSV的使用即可。
9.4.1      开启多任务
NVIC_INT_CTRL   EQU     0xE000ED04                              ; Interruptcontrol state register.
NVIC_SYSPRI14   EQU     0xE000ED22                              ; System priorityregister (priority 14).
NVIC_PENDSV_PRI EQU          0xFF                              ; PendSV priority value (lowest).
NVIC_PENDSVSET  EQU     0x10000000                              ; Value totrigger PendSV exception.

;********************************************************************************************************
;                                        START MULTITASKING
;                                     void OSStartHighRdy(void)
;
; Note(s) : 1) This function triggers a PendSV exception (essentially,causes a context switch) to cause
;              the first task tostart.
;
;           2) OSStartHighRdy()MUST:
;              a) Setup PendSVexception priority to lowest;
;              b) Set initial PSP to0, to tell context switcher this is first run;
;              c) Set the main stackto OS_CPU_ExceptStkBase
;              d) Trigger PendSVexception;
;              e) Enable interrupts(tasks will run with interrupts enabled).
;********************************************************************************************************

OSStartHighRdy
    LDR     R0, =NVIC_SYSPRI14                          ; Set the PendSVexception priority
    LDR     R1, =NVIC_PENDSV_PRI
    STRB    R1, [R0]

    MOVS    R0, #0                                      ; Set the PSP to 0 forinitial context switch call
    MSR     PSP, R0

    LDR     R0, =OS_CPU_ExceptStkBase                   ; Initialize the MSP to theOS_CPU_ExceptStkBase
    LDR     R1, [R0]
    MSR     MSP, R1   

    LDR     R0, =NVIC_INT_CTRL                          ; Trigger the PendSVexception (causes context switch)
    LDR     R1, =NVIC_PENDSVSET
    STR     R1, [R0]

    CPSIE   I                                           ;Enable interrupts at processor level

OSStartHang
    B       OSStartHang                                 ; Should never get here

下面说一下上面的汇编代码都实现了什么操作。
l LDR     R0, =NVIC_SYSPRI14                             
    LDR     R1, =NVIC_PENDSV_PRI
    STRB    R1, [R0]
    这三段代码的主要功能设置PendSV,这里将其设置位最低优先级,为什么要设置位最低优先级?在前面的教程中已经说得很清楚了,这里就不再赘述了。

l MOVS    R0, #0                                       
    MSR     PSP, R0
    设置PSP = 0,是告诉具体的任务切换程序(OS_CPU_PendSVHandler()),这是第一次任务切换。做过切换后PSP就不会为0了,后面讲OS_CPU_PendSVHandler()时会看到。

l LDR     R0, =OS_CPU_ExceptStkBase                 
    LDR     R1, [R0]
    MSR     MSP,R1   
    设置MSP = OS_CPU_ExceptStkBase,开启多任务后MSP主要用于中断服务程序。

l LDR     R0, =NVIC_INT_CTRL                                
    LDR     R1,=NVIC_PENDSVSET
    STR     R1, [R0]
    这里是使能PendSV中断。

l CPSIE   I                                                
    OSStartHang
    B      OSStartHang  
    这里主要是使能全局中断,使能后如果没有其它高优先级的中断需要执行,就会立即响应PendSV中断。所以说如果程序运行到了B    OSStartHang,说明多任务启动失败了。

baiyongbin2009 回答时间:2014-12-22 17:18:05
9.4.2      任务切换使能
    主要有两个任务切换的函数,一个是任务级的任务切换,另一个是中断级的任务切换。这两个函数都只是使能PendSV中断,任务切换的实际工作是在PendSV中完成的。
  1. ;********************************************************************************************************
  2. ;                       PERFORM A CONTEXT SWITCH (From task level) - OSCtxSw()
  3. ;
  4. ; Note(s) : 1) OSCtxSw() is called when OS wants to perform a task context switch.  This function
  5. ;              triggers the PendSV exception which is where the real work is done.
  6. ;********************************************************************************************************

  7. OSCtxSw
  8.     LDR     R0, =NVIC_INT_CTRL                           ; Trigger the PendSV exception (causes context switch)
  9.     LDR     R1, =NVIC_PENDSVSET
  10.     STR     R1, [R0]
  11.     BX      LR

  12. ;********************************************************************************************************
  13. ;                   PERFORM A CONTEXT SWITCH (From interrupt level) - OSIntCtxSw()
  14. ;
  15. ; Note(s) : 1) OSIntCtxSw() is called by OSIntExit() when it determines a context switch is needed as
  16. ;              the result of an interrupt.  This function simply triggers a PendSV exception which will
  17. ;              be handled when there are no more interrupts active and interrupts are enabled.
  18. ;********************************************************************************************************

  19. OSIntCtxSw
  20.     LDR     R0, =NVIC_INT_CTRL                          ; Trigger the PendSV exception (causes context switch)
  21.     LDR     R1, =NVIC_PENDSVSET
  22.     STR     R1, [R0]
  23.     BX      LR
复制代码


12下一页

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

官网相关资源

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