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
这一篇内容较多,也较难,日后如果有问题的地方,笔者再回来更新。好了,下篇再见!
上一篇: 解决linux下载github项目下载不下来,下载失败, 连接失败的问题
下一篇: 解决docker search mysql报Error response from daemon: Get “https://index.docker.io/v1/search?q=mysql&n
本文标签
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。