freeRTOS源码解析4--tasks.c 7

cnblogs 2024-10-06 08:15:00 阅读 83

4.2.20 空闲任务调用1--prvCheckTasksWaitingTermination

删除所有终止的任务, 释放资源。简单描述就是清空xTasksWaitingTermination列表,释放资源,递减uxCurrentNumberOfTasks和uxDeletedTasksWaitingCleanUp。

接口:

static void prvCheckTasksWaitingTermination( void )

接口代码如下:

1 static void prvCheckTasksWaitingTermination( void )

2 {

3 /** THIS FUNCTION IS CALLED FROM THE RTOS IDLE TASK **/

4

5 #if ( INCLUDE_vTaskDelete == 1 )

6 {

7 TCB_t * pxTCB;

8

9 /* uxDeletedTasksWaitingCleanUp is used to prevent taskENTER_CRITICAL()

10 * being called too often in the idle task. */

11 while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U )

12 {

13 #if ( configNUMBER_OF_CORES == 1 )

14 {

15 taskENTER_CRITICAL();

16 {

17 {

18 /* 从终止列表中取出任务 */

19 pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );

20 /* 将任务从终止列表中移出 */

21 ( void ) uxListRemove( &( pxTCB->xStateListItem ) );

22 --uxCurrentNumberOfTasks;

23 --uxDeletedTasksWaitingCleanUp;

24 }

25 }

26 taskEXIT_CRITICAL();

27

28 prvDeleteTCB( pxTCB ); // 释放任务资源

29 }

30 #endif /* #if( configNUMBER_OF_CORES == 1 ) */

31 }

32 }

33 #endif /* INCLUDE_vTaskDelete */

34 }

prvCheckTasksWaitingTermination

4.2.21空闲任务调用2--prvGetExpectedIdleTime

这个用于低功耗,主要作用是获取期望睡眠的tick时间。

接口:

static TickType_t prvGetExpectedIdleTime( void )

返回:实际返回的是最近唤醒任务的剩余tick数,即最多能够睡眠这么多tick数后就要苏醒了,因为有任务延迟结束需要唤醒了。

接口代码如下:

1 static TickType_t prvGetExpectedIdleTime( void )

2 {

3 TickType_t xReturn;

4 UBaseType_t uxHigherPriorityReadyTasks = pdFALSE;

5

6 /* uxHigherPriorityReadyTasks takes care of the case where

7 * configUSE_PREEMPTION is 0, so there may be tasks above the idle priority

8 * task that are in the Ready state, even though the idle task is

9 * running. */

10 /* uxHigherPriorityReadyTasks用于configUSE_PREEMPTION为0的情况, 因为有可能

11 * 存在空闲任务在运行时, 也有高于空闲任务优先级的任务处于就绪态。如果是抢占

12 * 式的调度的话, 则不可能会有更高优先级的任务就绪, 否则根本轮不到空闲任务

13 * 运行。 */

14 #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )

15 {

16 if( uxTopReadyPriority > tskIDLE_PRIORITY )

17 {

18 uxHigherPriorityReadyTasks = pdTRUE;

19 }

20 }

21 #else

22 {

23 const UBaseType_t uxLeastSignificantBit = ( UBaseType_t ) 0x01;

24

25 /* When port optimised task selection is used the uxTopReadyPriority

26 * variable is used as a bit map. If bits other than the least

27 * significant bit are set then there are tasks that have a priority

28 * above the idle priority that are in the Ready state. This takes

29 * care of the case where the co-operative scheduler is in use. */

30 if( uxTopReadyPriority > uxLeastSignificantBit )

31 {

32 uxHigherPriorityReadyTasks = pdTRUE;

33 }

34 }

35 #endif /* if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) */

36

37 /* 这里一样, 抢占式的话当前任务就是空闲任务, 所以下面的判断除了最后的else,

38 * 其他都只有非抢占式的才有可能进, 抢占式的就直接看最后的else即可。 */

39 if( pxCurrentTCB->uxPriority > tskIDLE_PRIORITY )

40 {

41 xReturn = 0;

42 }

43 else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1U )

44 {

45 /* There are other idle priority tasks in the ready state. If

46 * time slicing is used then the very next tick interrupt must be

47 * processed. */

48 /* 和空闲任务同优先级的话, 应该也是先运行其他任务最后运行空闲任务 */

49 xReturn = 0;

50 }

51 else if( uxHigherPriorityReadyTasks != pdFALSE )

52 {

53 /* There are tasks in the Ready state that have a priority above the

54 * idle priority. This path can only be reached if

55 * configUSE_PREEMPTION is 0. */

56 xReturn = 0;

57 }

58 else

59 {

60 /* 这里算出来的值是最近唤醒的任务的剩余tick数 */

61 xReturn = xNextTaskUnblockTime;

62 xReturn -= xTickCount;

63 }

64

65 return xReturn;

66 }

prvGetExpectedIdleTime

4.2.22 空闲任务调用3--vPortSuppressTicksAndSleep

这个接口就是用于进入低功耗模式的,由于这个和具体的平台相关,所以定义在port.c中,这里只看cortex-m3和m4核的代码。

这个接口个人认为非常复杂,里面有一些计算流程本人也不是很明白,还需要以后反复开发和阅读才能理解。

接口:

__weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )

__weak:如果没有__weak修饰的相同接口定义了,则用新定义的接口,否则就使用该接口,类似与多态,需要编译器支持,非c标准。

参数1:xExpectedIdleTime,4.2.21的接口计算返回的tick数。

前置接口1:eSleepModeStatus eTaskConfirmSleepModeStatus( void ),用于确定是否真的需要进入低功耗模式。

返回:eSleepModeStatus,eAbortSleep:不进入,eStandardSleep:进入但休眠时间不高于xExpectedIdleTime,eNoTasksWaitingTimeout:进入但只能依靠外部中断唤醒。

1 eSleepModeStatus eTaskConfirmSleepModeStatus( void )

2 {

3 #if ( INCLUDE_vTaskSuspend == 1 )

4 /* The idle task exists in addition to the application tasks. */

5 const UBaseType_t uxNonApplicationTasks = configNUMBER_OF_CORES;

6 #endif /* INCLUDE_vTaskSuspend */

7

8 eSleepModeStatus eReturn = eStandardSleep;

9

10 /* This function must be called from a critical section. */

11

12 /* 此时调度器暂停, 有必要检查一下是否有任务就绪了, 或者调度延迟了,

13 * 或者有tick中断处理被延迟了 */

14 if( listCURRENT_LIST_LENGTH( &xPendingReadyList ) != 0U )

15 {

16 /* A task was made ready while the scheduler was suspended. */

17 eReturn = eAbortSleep;

18 }

19 else if( xYieldPendings[ portGET_CORE_ID() ] != pdFALSE )

20 {

21 /* A yield was pended while the scheduler was suspended. */

22 eReturn = eAbortSleep;

23 }

24 else if( xPendedTicks != 0U )

25 {

26 /* A tick interrupt has already occurred but was held pending

27 * because the scheduler is suspended. */

28 eReturn = eAbortSleep;

29 }

30

31 #if ( INCLUDE_vTaskSuspend == 1 )

32 else if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )

33 {

34 /* If all the tasks are in the suspended list (which might mean they

35 * have an infinite block time rather than actually being suspended)

36 * then it is safe to turn all clocks off and just wait for external

37 * interrupts. */

38 /* 如果所有的任务都在挂起列表中(即使是那些等待事件且无限延迟的任务有),

39 * 那么可以停止时钟并等待外部中断 */

40 eReturn = eNoTasksWaitingTimeout;

41 }

42 #endif /* INCLUDE_vTaskSuspend */

43 else

44 {

45 mtCOVERAGE_TEST_MARKER();

46 }

47

48 return eReturn;

49 }

前置接口2:void vTaskStepTick( TickType_t xTicksToJump )

参数:xTicksToJump--休眠的tick数,用于更新xTickCount值。

1 void vTaskStepTick( TickType_t xTicksToJump )

2 {

3 TickType_t xUpdatedTickCount;

4

5 /* Correct the tick count value after a period during which the tick

6 * was suppressed. Note this does *not* call the tick hook function for

7 * each stepped tick. */

8 xUpdatedTickCount = xTickCount + xTicksToJump;

9 configASSERT( xUpdatedTickCount <= xNextTaskUnblockTime );

10

11 if( xUpdatedTickCount == xNextTaskUnblockTime )

12 {

13 /* Arrange for xTickCount to reach xNextTaskUnblockTime in

14 * xTaskIncrementTick() when the scheduler resumes. This ensures

15 * that any delayed tasks are resumed at the correct time. */

16 /* 有任务到达唤醒时间了, 使xPendedTicks自增, 让xTaskIncrementTick()

17 * 接口去实现任务的唤醒 */

18 configASSERT( uxSchedulerSuspended != ( UBaseType_t ) 0U );

19 configASSERT( xTicksToJump != ( TickType_t ) 0 );

20

21 /* Prevent the tick interrupt modifying xPendedTicks simultaneously. */

22 taskENTER_CRITICAL();

23 {

24 xPendedTicks++;

25 }

26 taskEXIT_CRITICAL();

27 xTicksToJump--; // xPendedTicks已自增了, xTicksToJump就需要少算一个

28 }

29 else

30 {

31 mtCOVERAGE_TEST_MARKER();

32 }

33

34 // 更新xTickCount值

35 xTickCount += xTicksToJump;

36 }

系统滴答时钟的几个寄存器需要展示一下:

接口代码如下:

1 __weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )

2 {

3 uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickDecrementsLeft;

4 TickType_t xModifiableIdleTime;

5

6 /* Make sure the SysTick reload value does not overflow the counter. */

7 /* xMaximumPossibleSuppressedTicks是最多可以休眠的tick数, 在

8 * vPortSetupTimerInterrupt中有初始化。 */

9 if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )

10 {

11 xExpectedIdleTime = xMaximumPossibleSuppressedTicks;

12 }

13

14 /* Enter a critical section but don't use the taskENTER_CRITICAL()

15 * method as that will mask interrupts that should exit sleep mode. */

16 /* taskENTER_CRITICAL()接口修改的是basepri, 而__disable_irq()修改的是

17 * primask, 不然某些中断被屏蔽后这些中断触发就无法退出休眠模式了. */

18 __disable_irq();

19 __dsb( portSY_FULL_READ_WRITE );

20 __isb( portSY_FULL_READ_WRITE );

21

22 /* If a context switch is pending or a task is waiting for the scheduler

23 * to be unsuspended then abandon the low power entry. */

24 /* 检查是否真的需要进入低功耗 */

25 if( eTaskConfirmSleepModeStatus() == eAbortSleep )

26 {

27 /* Re-enable interrupts - see comments above the __disable_irq()

28 * call above. */

29 __enable_irq();

30 }

31 else

32 {

33 /* Stop the SysTick momentarily. The time the SysTick is stopped for

34 * is accounted for as best it can be, but using the tickless mode will

35 * inevitably result in some tiny drift of the time maintained by the

36 * kernel with respect to calendar time. */

37 /* SysTick停止时间会计入总时长, 使用无滴答模式会导致内核时间与日历时间

38 * 存在微小偏差. */

39 /* portNVIC_SYSTICK_CTRL_REG: 0xE000E010, SYSTICK Control and Status Register.

40 * portNVIC_SYSTICK_CLK_BIT_CONFIG: ( 1UL << 2UL ),

41 * portNVIC_SYSTICK_INT_BIT: ( 1UL << 1UL ), *0xE000E010=0x06.

42 * 即使用内部时钟, 使能该中断并禁止systick, 可以按自己需求修改, 但bit0不能置位 */

43 portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT_CONFIG | portNVIC_SYSTICK_INT_BIT );

44

45 /* Use the SysTick current-value register to determine the number of

46 * SysTick decrements remaining until the next tick interrupt. If the

47 * current-value register is zero, then there are actually

48 * ulTimerCountsForOneTick decrements remaining, not zero, because the

49 * SysTick requests the interrupt when decrementing from 1 to 0. */

50 /* portNVIC_SYSTICK_CURRENT_VALUE_REG: 0xE000E018, 跟定时器计数的寄存器差不多. */

51 ulSysTickDecrementsLeft = portNVIC_SYSTICK_CURRENT_VALUE_REG;

52

53 if( ulSysTickDecrementsLeft == 0 )

54 {

55 ulSysTickDecrementsLeft = ulTimerCountsForOneTick;

56 }

57

58 /* Calculate the reload value required to wait xExpectedIdleTime

59 * tick periods. -1 is used because this code normally executes part

60 * way through the first tick period. But if the SysTick IRQ is now

61 * pending, then clear the IRQ, suppressing the first tick, and correct

62 * the reload value to reflect that the second tick period is already

63 * underway. The expected idle time is always at least two ticks. */

64 /* 计算重载的计数值, 这里分两种情况: 1、第一个tick中断未到, 计数已到一定值,

65 * 2、第一个tick中断已触发, 但处于pend态, 第二个tick计数已到一定值,

66 * 无论哪种情况都需要减去一个tick数, 再计算剩下的tick的计数值. */

67 ulReloadValue = ulSysTickDecrementsLeft + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );

68

69 /* 如果tick中断已pend了, 就清除中断, 再减去一个tick的计数值(即上面计算的值

70 * 多算了一个tick计数值), 这样计算出来的休眠时间就比较准确. */

71 if( ( portNVIC_INT_CTRL_REG & portNVIC_PEND_SYSTICK_SET_BIT ) != 0 )

72 {

73 portNVIC_INT_CTRL_REG = portNVIC_PEND_SYSTICK_CLEAR_BIT;

74 ulReloadValue -= ulTimerCountsForOneTick;

75 }

76

77 /* 这是一个补偿值, 即停止tick中断后, 执行到这一条语句的大致tick计数值,

78 * 这需要根据自己的工程去估算, 在vPortSetupTimerInterrupt中去修改. */

79 if( ulReloadValue > ulStoppedTimerCompensation )

80 {

81 ulReloadValue -= ulStoppedTimerCompensation;

82 }

83

84 /* Set the new reload value. */

85 /* portNVIC_SYSTICK_LOAD_REG: 0xE000E014, 重载寄存器, 从这个值减到0就触发tick中断 */

86 portNVIC_SYSTICK_LOAD_REG = ulReloadValue;

87

88 /* Clear the SysTick count flag and set the count value back to

89 * zero. */

90 /* 清除当前计数值, 一旦启动系统时钟, 这个寄存器的值就变成reload的值,

91 * 再递减至0, 然后触发中断. */

92 portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;

93

94 /* Restart SysTick. 使能系统定时器 */

95 portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;

96

97 /* Sleep until something happens. configPRE_SLEEP_PROCESSING() can

98 * set its parameter to 0 to indicate that its implementation contains

99 * its own wait for interrupt or wait for event instruction, and so wfi

100 * should not be executed again. However, the original expected idle

101 * time variable must remain unmodified, so a copy is taken. */

102 /* configPRE_SLEEP_PROCESSING()可以自己实现休眠等待, 并将xModifiableIdleTime

103 * 设置成0, 则表示已经完成了休眠, 系统就不会执行wfi指令. */

104 xModifiableIdleTime = xExpectedIdleTime;

105 configPRE_SLEEP_PROCESSING( xModifiableIdleTime );

106

107 if( xModifiableIdleTime > 0 )

108 {

109 __dsb( portSY_FULL_READ_WRITE );

110 __wfi(); // 等待中断指令, 即进入休眠模式

111 __isb( portSY_FULL_READ_WRITE );

112 }

113

114 /* 到这里休眠就结束了, 和之前的configPRE_SLEEP_PROCESSING

115 * 是一对, 表示用户自己实现的休眠和结束 */

116 configPOST_SLEEP_PROCESSING( xExpectedIdleTime );

117

118 /* Re-enable interrupts to allow the interrupt that brought the MCU

119 * out of sleep mode to execute immediately. See comments above

120 * the __disable_irq() call above. */

121 /* 使能中断, 将会立即进入中断处理例程, 可能是外部中断也可能是tick中断. */

122 __enable_irq();

123 __dsb( portSY_FULL_READ_WRITE );

124 __isb( portSY_FULL_READ_WRITE );

125

126 /* Disable interrupts again because the clock is about to be stopped

127 * and interrupts that execute while the clock is stopped will increase

128 * any slippage between the time maintained by the RTOS and calendar

129 * time. */

130 /* 后面要再次处理系统tick值, 如果期间出现中断的话, 会导致RTOS维护的时间

131 * 和日历时间出现偏差, 所以直接禁止中断可以防止这种偏差出现 */

132 __disable_irq();

133 __dsb( portSY_FULL_READ_WRITE );

134 __isb( portSY_FULL_READ_WRITE );

135

136 /* Disable the SysTick clock without reading the

137 * portNVIC_SYSTICK_CTRL_REG register to ensure the

138 * portNVIC_SYSTICK_COUNT_FLAG_BIT is not cleared if it is set. Again,

139 * the time the SysTick is stopped for is accounted for as best it can

140 * be, but using the tickless mode will inevitably result in some tiny

141 * drift of the time maintained by the kernel with respect to calendar

142 * time */

143 /* *0xE000E010=0x06, 与前面功效一样, 主要用于禁止systick.

144 * 虽然下面进一步校准了tick值, 但使用低功耗模式不可避免得会导致系统时钟

145 * 和日历时钟出现细微的偏差 */

146 portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT_CONFIG | portNVIC_SYSTICK_INT_BIT );

147

148 /* Determine whether the SysTick has already counted to zero. */

149 /* 检查tick计数是否有减到0, bit16是读清的 */

150 if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )

151 {

152 uint32_t ulCalculatedLoadValue;

153

154 /* The tick interrupt ended the sleep (or is now pending), and

155 * a new tick period has started. Reset portNVIC_SYSTICK_LOAD_REG

156 * with whatever remains of the new tick period. */

157 /* 需要恢复原先的tick计数, 所以需要减去目前已经计的数(休眠中触发

158 * tick中断后的时长), ulCalculatedLoadValue的值就是恢复后的计数值

159 * 需要继续计的剩下的值, 注意这里是已经减到0, 又重新开始倒计时了.

160 * 简单的假设, 原先一个tick需要500, 即499, 休眠总数是800, 这次休眠

161 * 了900, 那么当前计数寄存器的值就是700, 800-700=100, 那么当前一个

162 * tick需要计的剩下的数就是499-100=399, 这样就像是在休眠时tick仍在

163 * 计数一样, 虽然实际休眠时tick被禁止了 */

164 ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );

165

166 /* Don't allow a tiny value, or values that have somehow

167 * underflowed because the post sleep hook did something

168 * that took too long or because the SysTick current-value register

169 * is zero. */

170 /* 处理下ulCalculatedLoadValue值可能溢出的问题, 因为ulReloadValue必然是大于

171 * 一个tick的计数值, 而如果唤醒的中断处理了太长时间, 或者用户的hook执行了太

172 * 长时间导致当前计数值正好为0或变得特别小, 那么计算的值就会溢出(减出负数).

173 * 如果小于ulStoppedTimerCompensation, 则正好减去了当前处理的时间(大约). */

174 if( ( ulCalculatedLoadValue <= ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )

175 {

176 ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );

177 }

178

179 /* 重载计数值 */

180 portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;

181

182 /* As the pending tick will be processed as soon as this

183 * function exits, the tick value maintained by the tick is stepped

184 * forward by one less than the time spent waiting. */

185 /* 休眠前已经少算了一个tick, 如果是pend了, 在函数退出后会立即处理 */

186 ulCompleteTickPeriods = xExpectedIdleTime - 1UL;

187 }

188 else

189 {

190 /* Something other than the tick interrupt ended the sleep. */

191

192 /* Use the SysTick current-value register to determine the

193 * number of SysTick decrements remaining until the expected idle

194 * time would have ended. */

195 /* 不是tick中断唤醒的, 计算思路就相对简单一些 */

196 ulSysTickDecrementsLeft = portNVIC_SYSTICK_CURRENT_VALUE_REG;

197 #if ( portNVIC_SYSTICK_CLK_BIT_CONFIG != portNVIC_SYSTICK_CLK_BIT )

198 {

199 /* If the SysTick is not using the core clock, the current-

200 * value register might still be zero here. In that case, the

201 * SysTick didn't load from the reload register, and there are

202 * ulReloadValue decrements remaining in the expected idle

203 * time, not zero. */

204 /* tick使用非内核时钟的特殊处理, 暂时不是很理解 */

205 if( ulSysTickDecrementsLeft == 0 )

206 {

207 ulSysTickDecrementsLeft = ulReloadValue;

208 }

209 }

210 #endif /* portNVIC_SYSTICK_CLK_BIT_CONFIG */

211

212 /* Work out how long the sleep lasted rounded to complete tick

213 * periods (not the ulReload value which accounted for part

214 * ticks). */

215 /* 再次假设, 原先一个tick需要500, 休眠总数是900(2个tick), 这次休眠300

216 * 那么ulCompletedSysTickDecrements=(2*500)-(900-300)=400 */

217 ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - ulSysTickDecrementsLeft;

218

219 /* How many complete tick periods passed while the processor

220 * was waiting? */

221 /* ulCompleteTickPeriods = 400 / 500 = 0 */

222 ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;

223

224 /* The reload value is set to whatever fraction of a single tick

225 * period remains. */

226 /* 结果 = (0+1)*500-400=100. 简单计算下, 休眠总数是900, 说明睡眠前的当前值是400,

227 * 已经计数了100, 这次休眠300, 总计是400, 即还剩下100. 结果是相符的, 关键是这个

228 * 算法是怎么得来的, 我一时也不是很清楚, 但是结果是准确的 */

229 portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;

230 }

231

232 /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG again,

233 * then set portNVIC_SYSTICK_LOAD_REG back to its standard value. If

234 * the SysTick is not using the core clock, temporarily configure it to

235 * use the core clock. This configuration forces the SysTick to load

236 * from portNVIC_SYSTICK_LOAD_REG immediately instead of at the next

237 * cycle of the other clock. Then portNVIC_SYSTICK_LOAD_REG is ready

238 * to receive the standard value immediately. */

239 /* 这里当前计数寄存器的值已经更新了, 所以再设置reload值是安全的 */

240 portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;

241 portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;

242 #if ( portNVIC_SYSTICK_CLK_BIT_CONFIG == portNVIC_SYSTICK_CLK_BIT )

243 {

244 portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;

245 }

246 #else

247 {

248 /* The temporary usage of the core clock has served its purpose,

249 * as described above. Resume usage of the other clock. */

250 portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT;

251

252 if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 )

253 {

254 /* The partial tick period already ended. Be sure the SysTick

255 * counts it only once. */

256 portNVIC_SYSTICK_CURRENT_VALUE_REG = 0;

257 }

258

259 portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;

260 portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT_CONFIG | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT;

261 }

262 #endif /* portNVIC_SYSTICK_CLK_BIT_CONFIG */

263

264 /* Step the tick to account for any tick periods that elapsed. */

265 vTaskStepTick( ulCompleteTickPeriods );

266

267 /* Exit with interrupts enabled. */

268 __enable_irq();

269 }

270 }

vPortSuppressTicksAndSleep

这一篇内容较多,也较难,日后如果有问题的地方,笔者再回来更新。好了,下篇再见!



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。