os_cpu.h,os_cpu_c.c,os_cpu_a.asm这三个文件在移植过程中最重要,下面主要的就是把这三个文件中的内容详细讲解一下。
9.2 os_cpu.h文件讲解
此头文件的内容比较少,下面就将里面的内容说明一下
9.2.1 宏定义
- #ifdef OS_CPU_GLOBALS
- #define OS_CPU_EXT
- #else
- #define OS_CPU_EXT extern
- #endif
-
- /*
- *********************************************************************************************************
- * MACROS
- *********************************************************************************************************
- */
-
- #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文件中。此函数的主要功能就是实现任务的切换。
- /*
- *********************************************************************************************************
- * OS tiCK INTERRUPT PRIORITY CONFIGURATION
- *
- * Note(s) : (1) For systems that don't need any high, real-time priority interrupts; the tick interrupt
- * should be configured as the highest priority interrupt but won't adversely affect system
- * operations.
- *
- * (2) For systems that need one or more high, real-time interrupts; these should be configured
- * higher than the tick interrupt which MAY delay execution of the tick interrupt.
- *
- * (a) If the higher priority interrupts do NOT continually consume CPU cycles but only
- * occasionally delay tick interrupts, then the real-time interrupts can successfully
- * handle their intermittent/periodic events with the system not losing tick interrupts
- * but only increasing the jitter.
- *
- * (b) If the higher priority interrupts consume enough CPU cycles to continually delay the
- * tick interrupt, then the CPU/system is most likely over-burdened & can't be expected
- * to handle all its interrupts/tasks. The system time reference gets compromised as a
- * result of losing tick interrupts.
- *********************************************************************************************************
- */
-
- #define OS_CPU_CFG_SYSTICK_PRIO 0u
复制代码
l OS_CPU_CFG_SYSTICK_PRIO 用于配制嘀嗒定时器的优先级。关于嘀嗒定时器优先级的配置还是很讲究的,也就是上面注释所写的。
Ø 对于那些不需要高优先级中断的系统,嘀嗒定时器中断要配置成最高优先级的中断,但是不能影响系统操作。
Ø 如果系统中多个高优先级的中断,而且优先级比嘀嗒定时器的优先级高,那么就可能会延迟嘀嗒定时器中断。
u 如果高优先级的中断不会持续的占有CPU,只是偶尔的延迟嘀嗒定时器中断,那么实时中断可以间歇性或者周期性的处理系统事件而不丢失嘀嗒定时器中断,只是增加抖动(因为高优先级中断的执行会抢占嘀嗒定时器中断的执行或者高优先级中断执行的时候嘀嗒定时器中断会一直得不到执行从而造成嘀嗒定时器中断在执行时间上的抖动)。
u 如果高优先级的任务长时间的占有CPU时间会造成系统超负荷运行,而不能执行嘀嗒定时器中断,任务也不能得到及时的执行。这种情况可以认为系统丢失了几次嘀嗒定时器的执行。
9.2.2 时间戳配置
- /*
- *********************************************************************************************************
- * TIMESTAMP CONFIGURATION
- *
- * Note(s) : (1) OS_TS_GET() is generally defined as CPU_TS_Get32() to allow CPU timestamp timer to be of
- * any data type size.
- *
- * (2) For architectures that provide 32-bit or higher precision free running counters
- * (i.e. cycle count registers):
- *
- * (a) OS_TS_GET() may be defined as CPU_TS_TmrRd() to improve performance when retrieving
- * the timestamp.
- *
- * (b) CPU_TS_TmrRd() MUST be configured to be greater or equal to 32-bits to avoid
- * truncation of TS.
- *********************************************************************************************************
- */
-
- #if OS_CFG_TS_EN == 1u
- #define OS_TS_GET() (CPU_TS)CPU_TS_TmrRd() /* See Note #2a. */
- #else
- #define OS_TS_GET() (CPU_TS)0u
- #endif
-
- #if (CPU_CFG_TS_32_EN == DEF_ENABLED) &&
- (CPU_CFG_TS_TMR_SIZE < CPU_WORD_SIZE_32)
- /* CPU_CFG_TS_TMR_SIZE MUST be >= 32-bit (see Note #2b). */
- #error "cpu_cfg.h, CPU_CFG_TS_TMR_SIZE MUST be >= CPU_WORD_SIZE_32"
- #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里面):
- /*
- *********************************************************************************************************
- * CPU_TS_TmrInit()
- *
- * Description : Initialize & start CPU timestamp timer.
- *
- * Argument(s) : none.
- *
- * Return(s) : none.
- *
- * Caller(s) : CPU_TS_Init().
- *
- * This function is an INTERNAL CPU module function & MUST be implemented by application/
- * BSP function(s) [see Note #1] but MUST NOT be called by application function(s).
- *
- * Note(s) : (1) CPU_TS_TmrInit() is an application/BSP function that MUST be defined by the developer
- * if either of the following CPU features is enabled :
- *
- * (a) CPU timestamps
- * (b) CPU interrupts disabled time measurements
- *
- * See 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #1'
- * & 'cpu_cfg.h CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION Note #1a'.
- *
- * (2) (a) Timer count values MUST be returned via word-size-configurable 'CPU_TS_TMR'
- * data type.
- *
- * (1) If timer has more bits, truncate timer values' higher-order bits greater
- * than the configured 'CPU_TS_TMR' timestamp timer data type word size.
- *
- * (2) Since the timer MUST NOT have less bits than the configured 'CPU_TS_TMR'
- * timestamp timer data type word size; 'CPU_CFG_TS_TMR_SIZE' MUST be
- * configured so that ALL bits in 'CPU_TS_TMR' data type are significant.
- *
- * In other words, if timer size is not a binary-multiple of 8-bit octets
- * (e.g. 20-bits or even 24-bits), then the next lower, binary-multiple
- * octet word size SHOULD be configured (e.g. to 16-bits). However, the
- * minimum supported word size for CPU timestamp timers is 8-bits.
- *
- * See also 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #2'
- * & 'cpu_core.h CPU TIMESTAMP DATA TYPES Note #1'.
- *
- * (b) Timer SHOULD be an 'up' counter whose values increase with each time count.
- *
- * (c) When applicable, timer period SHOULD be less than the typical measured time
- * but MUST be less than the maximum measured time; otherwise, timer resolution
- * inadequate to measure desired times.
- *
- * See also 'CPU_TS_TmrRd() Note #2'.
- *********************************************************************************************************
- */
-
- #if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
- void CPU_TS_TmrInit (void)
- {
- CPU_INT32U fclk_freq;
-
-
- fclk_freq = BSP_CPU_ClkFreq();
-
- BSP_REG_DEM_CR |= (CPU_INT32U)BSP_BIT_DEM_CR_TRCENA; /* Enable Cortex-M4's DWT CYCCNT reg. */
- BSP_REG_DWT_CYCCNT = (CPU_INT32U)0u;
- BSP_REG_DWT_CR |= (CPU_INT32U)BSP_BIT_DWT_CR_CYCCNTENA;
-
- CPU_TS_TmrFreqSet((CPU_TS_TMR_FREQ)fclk_freq);
- }
- #endif
复制代码
Ø 这个函数不需要用户调用,用户可以通过调用函数CPU_Init();(在文件cpu_core.c里面)来调用这个函数。
Ø 这里时基的实现是使用Cortex-M3/M4中自带的时钟周期计数器,关于时钟周期计数器的知识,大家需要查阅相关的技术手册进行了解,这里只需要知道每计数一次就是一个时钟周期,比如主频是168MHz的话,那么时钟周期就是1/168000000秒。除了μCOS-III是使用的时钟周期计数器作为时基以外,embOS也是使用的这个计数器作为时基。FreeRTOS是用的定时器做的时基。
Ø 关于此函数的其它信息,需要大家看一下上面的英文说明,看看了解一下即可。
说完了时间戳的初始化,下面说一下时钟周期计数器时间的读取,相关的函数还是位于bsp.c文件里面。
- /*
- *********************************************************************************************************
- * CPU_TS_TmrRd()
- *
- * Description : Get current CPU timestamp timer count value.
- *
- * Argument(s) : none.
- *
- * Return(s) : Timestamp timer count (see Notes #2a & #2b).
- *
- * Caller(s) : CPU_TS_Init(),
- * CPU_TS_Get32(),
- * CPU_TS_Get64(),
- * CPU_IntDisMeasStart(),
- * CPU_IntDisMeasStop().
- *
- * This function is an INTERNAL CPU module function & MUST be implemented by application/
- * BSP function(s) [see Note #1] but SHOULD NOT be called by application function(s).
- *
- * Note(s) : (1) CPU_TS_TmrRd() is an application/BSP function that MUST be defined by the developer
- * if either of the following CPU features is enabled :
- *
- * (a) CPU timestamps
- * (b) CPU interrupts disabled time measurements
- *
- * See 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #1'
- * & 'cpu_cfg.h CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION Note #1a'.
- *
- * (2) (a) Timer count values MUST be returned via word-size-configurable 'CPU_TS_TMR'
- * data type.
- *
- * (1) If timer has more bits, truncate timer values' higher-order bits greater
- * than the configured 'CPU_TS_TMR' timestamp timer data type word size.
- *
- * (2) Since the timer MUST NOT have less bits than the configured 'CPU_TS_TMR'
- * timestamp timer data type word size; 'CPU_CFG_TS_TMR_SIZE' MUST be
- * configured so that ALL bits in 'CPU_TS_TMR' data type are significant.
- *
- * In other words, if timer size is not a binary-multiple of 8-bit octets
- * (e.g. 20-bits or even 24-bits), then the next lower, binary-multiple
- * octet word size SHOULD be configured (e.g. to 16-bits). However, the
- * minimum supported word size for CPU timestamp timers is 8-bits.
- *
- * See also 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #2'
- * & 'cpu_core.h CPU TIMESTAMP DATA TYPES Note #1'.
- *
- * (b) Timer SHOULD be an 'up' counter whose values increase with each time count.
- *
- * (1) If timer is a 'down' counter whose values decrease with each time count,
- * then the returned timer value MUST be ones-complemented.
- *
- * (c) (1) When applicable, the amount of time measured by CPU timestamps is
- * calculated by either of the following equations :
- *
- * (A) Time measured = Number timer counts * Timer period
- *
- * where
- *
- * Number timer counts Number of timer counts measured
- * Timer period Timer's period in some units of
- * (fractional) seconds
- * Time measured Amount of time measured, in same
- * units of (fractional) seconds
- * as the Timer period
- *
- * Number timer counts
- * (B) Time measured = ---------------------
- * Timer frequency
- *
- * where
- *
- * Number timer counts Number of timer counts measured
- * Timer frequency Timer's frequency in some units
- * of counts per second
- * Time measured Amount of time measured, in seconds
- *
- * (2) Timer period SHOULD be less than the typical measured time but MUST be less
- * than the maximum measured time; otherwise, timer resolution inadequate to
- * measure desired times.
- *********************************************************************************************************
- */
-
- #if (CPU_CFG_TS_TMR_EN == DEF_ENABLED)
- CPU_TS_TMR CPU_TS_TmrRd (void)
- {
- CPU_TS_TMR ts_tmr_cnts;
-
-
- ts_tmr_cnts = (CPU_TS_TMR)BSP_REG_DWT_CYCCNT;
-
- return (ts_tmr_cnts);
- }
- #endif
-
- /*
- *********************************************************************************************************
- * CPU_TSxx_to_uSec()
- *
- * Description : Convert a 32-/64-bit CPU timestamp from timer counts to microseconds.
- *
- * Argument(s) : ts_cnts CPU timestamp (in timestamp timer counts [see Note #2aA]).
- *
- * Return(s) : Converted CPU timestamp (in microseconds [see Note #2aD]).
- *
- * Caller(s) : Application.
- *
- * This function is an (optional) CPU module application programming interface (API)
- * function which MAY be implemented by application/BSP function(s) [see Note #1] &
- * MAY be called by application function(s).
- *
- * Note(s) : (1) CPU_TS32_to_uSec()/CPU_TS64_to_uSec() are application/BSP functions that MAY be
- * optionally defined by the developer when either of the following CPU features is
- * enabled :
- *
- * (a) CPU timestamps
- * (b) CPU interrupts disabled time measurements
- *
- * See 'cpu_cfg.h CPU TIMESTAMP CONFIGURATION Note #1'
- * & 'cpu_cfg.h CPU INTERRUPTS DISABLED TIME MEASUREMENT CONFIGURATION Note #1a'.
- *
- * (2) (a) The amount of time measured by CPU timestamps is calculated by either of
- * the following equations :
- *
- * 10^6 microseconds
- * (1) Time measured = Number timer counts * ------------------- * Timer period
- * 1 second
- *
- * Number timer counts 10^6 microseconds
- * (2) Time measured = --------------------- * -------------------
- * Timer frequency 1 second
- *
- * where
- *
- * (A) Number timer counts Number of timer counts measured
- * (B) Timer frequency Timer's frequency in some units
- * of counts per second
- * (C) Timer period Timer's period in some units of
- * (fractional) seconds
- * (D) Time measured Amount of time measured,
- * in microseconds
- *
- * (b) Timer period SHOULD be less than the typical measured time but MUST be less
- * than the maximum measured time; otherwise, timer resolution inadequate to
- * measure desired times.
- *
- * (c) Specific implementations may convert any number of CPU_TS32 or CPU_TS64 bits
- * -- up to 32 or 64, respectively -- into microseconds.
- *********************************************************************************************************
- */
-
- #if (CPU_CFG_TS_32_EN == DEF_ENABLED)
- CPU_INT64U CPU_TS32_to_uSec (CPU_TS32 ts_cnts)
- {
- CPU_INT64U ts_us;
- CPU_INT64U fclk_freq;
-
-
- fclk_freq = BSP_CPU_ClkFreq();
- ts_us = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);
-
- return (ts_us);
- }
- #endif
-
-
- #if (CPU_CFG_TS_64_EN == DEF_ENABLED)
- CPU_INT64U CPU_TS64_to_uSec (CPU_TS64 ts_cnts)
- {
- CPU_INT64U ts_us;
- CPU_INT64U fclk_freq;
-
-
- fclk_freq = BSP_CPU_ClkFreq();
- ts_us = ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);
-
- return (ts_us);
- }
- #endif
复制代码
从上面的函数可以看出时钟周期计数器时间的获取还是很容易的,直接读取相应寄存器就能获得当前的计数。下面的两个函数CPU_TS32_to_uSec和CPU_TS32_to_uSec用于将时钟周期的数值转换成us为单位。函数还是很容易看懂,上面的英文说明反倒搞得挺复杂,大家读读了解些即可。
9.2.3 函数声明
- /*
- *********************************************************************************************************
- * GLOBAL VARIABLES
- *********************************************************************************************************
- */
- OS_CPU_EXT CPU_STK *OS_CPU_ExceptStkBase;
- /*
- *********************************************************************************************************
- * FUNCTION PROTOTYPES
- *********************************************************************************************************
- */
- void OSCtxSw (void);
- void OSIntCtxSw (void);
- void OSStartHighRdy (void);
- void OS_CPU_PendSVHandler (void);
- void OS_CPU_SysTickHandler(void);
- 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文件里面。
9.3 os_cpu_c.c文件讲解
这文件里面主要是一些钩子函数,任务堆栈初始化和嘀嗒定时器的初始化。下面就详细的把这三个部分说明一下。
9.3.1 钩子函数 钩子函数的主要功能就是扩展函数的功能,用户可以根据自己的需要往里面添加相关的测试函数,这个文件里面的钩子函数一共有个,下面就分别的讲解下。
- /*
- *********************************************************************************************************
- * IDLE TASK HOOK
- *
- * Description: This function is called by the idle task. This hook has been added to allow you to do
- * such things as STOP the CPU to conserve power.
- *
- * Arguments : None.
- *
- * Note(s) : None.
- *********************************************************************************************************
- */
-
- void OSIdleTaskHook (void)
- {
- #if OS_CFG_APP_HOOKS_EN > 0u
- if (OS_AppIdleTaskHookPtr != (OS_APP_HOOK_VOID)0) {
- (*OS_AppIdleTaskHookPtr)();
- }
- #endif
- }
复制代码
l OSIdleTaskHook是空闲任务的钩子函数
此函数被空闲任务调用,用户可以通过函数指针变量*OS_AppIdleTaskHookPtr指向用户设计的函数来实现用户所想实现的任务。这个函数主要用于实现低功耗。
- /*
- *********************************************************************************************************
- * OS INITIALIZATION HOOK
- *
- * Description: This function is called by OSInit() at the beginning of OSInit().
- *
- * Arguments : None.
- *
- * Note(s) : None.
- *********************************************************************************************************
- */
-
- void OSInitHook (void)
- {
- /* 8-byte align the ISR stack. */
- OS_CPU_ExceptStkBase = (CPU_STK *)(OSCfg_ISRStkBasePtr + OSCfg_ISRStkSize);
- OS_CPU_ExceptStkBase = (CPU_STK *)((CPU_STK)(OS_CPU_ExceptStkBase) & 0xFFFFFFF8);
- }
复制代码
l OSInitHook是OS初始化的钩子函数
这个函数主要用于获取异常堆栈的基地址。这里这特别注意:这个异常堆栈是用于MSP(主堆栈空间),这样可以很方便的查询主堆栈的使用情况。针对Cortex-M4/M3内核的MCU,在使用RTOS的情况下,主堆栈主要用在中断服务程序中。
- /*
- *********************************************************************************************************
- * STATISTIC TASK HOOK
- *
- * Description: This function is called every second by uC/OS-III's statistics task. This allows your
- * application to add functionality to the statistics task.
- *
- * Arguments : None.
- *
- * Note(s) : None.
- *********************************************************************************************************
- */
-
- void OSStatTaskHook (void)
- {
- #if OS_CFG_APP_HOOKS_EN > 0u
- if (OS_AppStatTaskHookPtr != (OS_APP_HOOK_VOID)0) {
- (*OS_AppStatTaskHookPtr)();
- }
- #endif
- }
复制代码
l OSStatTaskHook是统计任务的钩子函数
使用方法和前面的空闲任务钩子函数一样。
- /*
- *********************************************************************************************************
- * TASK CREATION HOOK
- *
- * Description: This function is called when a task is created.
- *
- * Arguments : p_tcb Pointer to the task control block of the task being created.
- *
- * Note(s) : None.
- *********************************************************************************************************
- */
-
- void OSTaskCreateHook (OS_TCB *p_tcb)
- {
- #if OS_CFG_APP_HOOKS_EN > 0u
- if (OS_AppTaskCreateHookPtr != (OS_APP_HOOK_TCB)0) {
- (*OS_AppTaskCreateHookPtr)(p_tcb);
- }
- #else
- (void)p_tcb; /* Prevent compiler warning */
- #endif
- }
复制代码
l OSTaskCreateHook是创建任务时的钩子函数
使用方法和前面的空闲任务钩子函数基本一样,只是多了个函数参数。
- /*
- *********************************************************************************************************
- * TASK DELETION HOOK
- *
- * Description: This function is called when a task is deleted.
- *
- * Arguments : p_tcb Pointer to the task control block of the task being deleted.
- *
- * Note(s) : None.
- *********************************************************************************************************
- */
-
- void OSTaskDelHook (OS_TCB *p_tcb)
- {
- #if OS_CFG_APP_HOOKS_EN > 0u
- if (OS_AppTaskDelHookPtr != (OS_APP_HOOK_TCB)0) {
- (*OS_AppTaskDelHookPtr)(p_tcb);
- }
- #else
- (void)p_tcb; /* Prevent compiler warning */
- #endif
- }
复制代码
l OSTaskDelHook 是任务删除的钩子函数
使用方法和前面的创建任务钩子函数一样。
- /*
- *********************************************************************************************************
- * TASK RETURN HOOK
- *
- * Description: This function is called if a task accidentally returns. In other words, a task should
- * either be an infinite loop or delete itself when done.
- *
- * Arguments : p_tcb Pointer to the task control block of the task that is returning.
- *
- * Note(s) : None.
- *********************************************************************************************************
- */
-
- void OSTaskReturnHook (OS_TCB *p_tcb)
- {
- #if OS_CFG_APP_HOOKS_EN > 0u
- if (OS_AppTaskReturnHookPtr != (OS_APP_HOOK_TCB)0) {
- (*OS_AppTaskReturnHookPtr)(p_tcb);
- }
- #else
- (void)p_tcb; /* Prevent compiler warning */
- #endif
- }
复制代码
l OSTaskReturnHook是任务返回的钩子函数
这个函数的使用方面和前面的创建任务钩子函数是一样的。在RTOS中,任务必须得是超级循环的形式,如果任务只执行一次或者任务中有返回函数,系统就会调用异常返回函数将这个任务挂起或者删除(用户可以自行配置)。在异常返回函数中调用钩子函数。
- /*
- *********************************************************************************************************
- * TASK SWITCH HOOK
- *
- * Description: This function is called when a task switch is performed. This allows you to perform other
- * operations during a context switch.
- *
- * Arguments : None.
- *
- * Note(s) : 1) Interrupts are disabled during this call.
- * 2) It is assumed that the global pointer 'OSTCBHighRdyPtr' points to the TCB of the task
- * that will be 'switched in' (i.e. the highest priority task) and, 'OSTCBCurPtr' points
- * to the task being switched out (i.e. the preempted task).
- *********************************************************************************************************
- */
-
- void OSTaskSwHook (void)
- {
- #if OS_CFG_TASK_PROFILE_EN > 0u
- CPU_TS ts;
- #endif
- #ifdef CPU_CFG_INT_DIS_MEAS_EN
- CPU_TS int_dis_time;
- #endif
-
-
-
- #if OS_CFG_APP_HOOKS_EN > 0u
- if (OS_AppTaskSwHookPtr != (OS_APP_HOOK_VOID)0) {
- (*OS_AppTaskSwHookPtr)();
- }
- #endif
-
- #if OS_CFG_TASK_PROFILE_EN > 0u
- ts = OS_TS_GET();
- if (OSTCBCurPtr != OSTCBHighRdyPtr) {
- OSTCBCurPtr->CyclesDelta = ts - OSTCBCurPtr->CyclesStart;
- OSTCBCurPtr->CyclesTotal += (OS_CYCLES)OSTCBCurPtr->CyclesDelta;
- }
-
- OSTCBHighRdyPtr->CyclesStart = ts;
- #endif
-
- #ifdef CPU_CFG_INT_DIS_MEAS_EN
- int_dis_time = CPU_IntDisMeasMaxCurReset(); /* Keep track of per-task interrupt disable time */
- if (OSTCBCurPtr->IntDisTimeMax < int_dis_time) {
- OSTCBCurPtr->IntDisTimeMax = int_dis_time;
- }
- #endif
-
- #if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
- /* Keep track of per-task scheduler lock time */
- if (OSTCBCurPtr->SchedLockTimeMax < OSSchedLockTimeMaxCur) {
- OSTCBCurPtr->SchedLockTimeMax = OSSchedLockTimeMaxCur;
- }
- OSSchedLockTimeMaxCur = (CPU_TS)0; /* Reset the per-task value */
- #endif
- }
复制代码
l OSTaskSwHook 是任务切换的钩子函数
这个函数里面也有用到函数指针,使用方法和前面的函数是一样的。函数里面还有一些执行时间的测量,这些内容会在后面源码讲解的时候再跟大家分析。
- /*
- *********************************************************************************************************
- * TICK HOOK
- *
- * Description: This function is called every tick.
- *
- * Arguments : None.
- *
- * Note(s) : 1) This function is assumed to be called from the Tick ISR.
- *********************************************************************************************************
- */
-
- void OSTimeTickHook (void)
- {
- #if OS_CFG_APP_HOOKS_EN > 0u
- if (OS_AppTimeTickHookPtr != (OS_APP_HOOK_VOID)0) {
- (*OS_AppTimeTickHookPtr)();
- }
- #endif
- }
复制代码
l OSTimeTickHook 是嘀嗒定时器钩子函数
这个函数的用法和前面的函数一样,被嘀嗒定时器中断服务程序所调用。
9.3.2 嘀嗒定时器配置 关于嘀嗒定时器在V5
开发板用户手册第10章:SysTick实验里面有详细的讲解。这里就不再详细的赘述了,这里特别注意咱们已经在前面的os_cpu.h文件里面配置了嘀嗒定时器的优先级为0,也就是最高优先级。
- /*
- *********************************************************************************************************
- * SYS TICK HANDLER
- *
- * Description: Handle the system tick (SysTick) interrupt, which is used to generate the uC/OS-II tick
- * interrupt.
- *
- * Arguments : None.
- *
- * Note(s) : 1) This function MUST be placed on entry 15 of the Cortex-M3 vector table.
- *********************************************************************************************************
- */
-
- void OS_CPU_SysTickHandler (void)
- {
- CPU_SR_ALLOC();
-
-
- CPU_CRITICAL_ENTER();
- OSIntNestingCtr++; /* Tell uC/OS-III that we are starting an ISR */
- CPU_CRITICAL_EXIT();
-
- OSTimeTick(); /* Call uC/OS-III's OSTimeTick() */
-
- OSIntExit(); /* Tell uC/OS-III that we are leaving the ISR */
- }
-
- /*
- *********************************************************************************************************
- * INITIALIZE SYS TICK
- *
- * Description: Initialize the SysTick.
- *
- * Arguments : cnts Number of SysTick counts between two OS tick interrupts.
- *
- * Note(s) : 1) This function MUST be called after OSStart() & after processor initialization.
- *********************************************************************************************************
- */
-
- void OS_CPU_SysTickInit (CPU_INT32U cnts)
- {
- CPU_INT32U prio;
-
-
- CPU_REG_NVIC_ST_RELOAD = cnts - 1u;
-
- /* Set SysTick handler prio. */
- prio = CPU_REG_NVIC_SHPRI3;
- prio &= DEF_BIT_FIELD(24, 0);
- prio |= DEF_BIT_MASK(OS_CPU_CFG_SYSTICK_PRIO, 24);
-
- CPU_REG_NVIC_SHPRI3 = prio;
-
- /* Enable timer. */
- CPU_REG_NVIC_ST_CTRL |= CPU_REG_NVIC_ST_CTRL_CLKSOURCE |
- CPU_REG_NVIC_ST_CTRL_ENABLE;
- /* Enable timer interrupt. */
- CPU_REG_NVIC_ST_CTRL |= CPU_REG_NVIC_ST_CTRL_TICKINT;
- }
复制代码
9.3.3 任务堆栈初始化 每个任务创建时都会调用这个函数,主要用于初始化任务的堆栈,以便于第一次切换到各个任务时能正确的切换(特别注意这句话,用心体会)。
- /*
- **********************************************************************************************************
- * INITIALIZE A TASK'S STACK
- *
- * Description: This function is called by OS_Task_Create() or OSTaskCreateExt() to initialize the stack
- * frame of the task being created. This function is highly processor specific.
- *
- * Arguments : p_task Pointer to the task entry point address.
- *
- * p_arg Pointer to a user supplied data area that will be passed to the task
- * when the task first executes.
- *
- * p_stk_base Pointer to the base address of the stack.
- *
- * stk_size Size of the stack, in number of CPU_STK elements.
- *
- * opt Options used to alter the behavior of OS_Task_StkInit().
- * (see OS.H for OS_TASK_OPT_xxx).
- *
- * Returns : Always returns the location of the new top-of-stack' once the processor registers have
- * been placed on the stack in the proper order.
- *
- * Note(s) : 1) Interrupts are enabled when task starts executing.
- *
- * 2) All tasks run in Thread mode, using process stack.
- **********************************************************************************************************
- */
-
- CPU_STK *OSTaskStkInit (OS_TASK_PTR p_task,
- void *p_arg,
- CPU_STK *p_stk_base,
- CPU_STK *p_stk_limit,
- CPU_STK_SIZE stk_size,
- OS_OPT opt)
- {
- CPU_STK *p_stk;
-
-
- (void)opt; /* Prevent compiler warning */
-
- p_stk = &p_stk_base[stk_size]; /* Load stack pointer */
- /* Align the stack to 8-bytes. */
- p_stk = (CPU_STK *)((CPU_STK)(p_stk) & 0xFFFFFFF8);
- /* Registers stacked as if auto-saved on exception */
- *--p_stk = (CPU_STK)0x01000000u; /* xPSR */
- *--p_stk = (CPU_STK)p_task; /* Entry Point */
- *--p_stk = (CPU_STK)OS_TaskReturn; /* R14 (LR) */
- *--p_stk = (CPU_STK)0x12121212u; /* R12 */
- *--p_stk = (CPU_STK)0x03030303u; /* R3 */
- *--p_stk = (CPU_STK)0x02020202u; /* R2 */
- *--p_stk = (CPU_STK)p_stk_limit; /* R1 */
- *--p_stk = (CPU_STK)p_arg; /* R0 : argument */
- /* Remaining registers saved on process stack */
- *--p_stk = (CPU_STK)0x11111111u; /* R11 */
- *--p_stk = (CPU_STK)0x10101010u; /* R10 */
- *--p_stk = (CPU_STK)0x09090909u; /* R9 */
- *--p_stk = (CPU_STK)0x08080808u; /* R8 */
- *--p_stk = (CPU_STK)0x07070707u; /* R7 */
- *--p_stk = (CPU_STK)0x06060606u; /* R6 */
- *--p_stk = (CPU_STK)0x05050505u; /* R5 */
- *--p_stk = (CPU_STK)0x04040404u; /* R4 */
-
- return (p_stk);
- }
复制代码
看似简单的初始化,信息量还是很大的。
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],那么堆栈初始化后寄存器在堆栈中的排列如下:
0