首页 > 编程语言 >freeRTOS源码解析4--tasks.c 7

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

时间:2024-10-05 20:22:12浏览次数:7  
标签:__ freeRTOS -- portNVIC 源码 SYSTICK BIT tick REG

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

 

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

标签:__,freeRTOS,--,portNVIC,源码,SYSTICK,BIT,tick,REG
From: https://www.cnblogs.com/freeManX1807/p/18442512

相关文章

  • 补题报告5
    背景2024-10-5做\(CSP-J\)复赛模拟,作补题报告。成绩\(T1\)\(AC\)\(T2\)\(40\)\(T3\)\(0\)\(T4\)\(0\)\(T1\)牛奶(\(milk\))经典\(T1\)赛时\(A\).概述要采购牛奶,有\(n\)种,每种有各自的\(a_i\)和\(b_i\),需要\(m\)盒,求最小花销思路题目描述中说,作为一只学......
  • 鸿蒙应用示例:镂空效果实现教程
    在鸿蒙系统中,为了给用户带来更加生动的视觉体验,我们可以使用不同的技术手段来实现图像和文字的镂空效果。本文将通过三个具体的示例来展示如何在鸿蒙系统中实现实心矩形镂空、实心圆镂空以及文字镂空的效果。示例代码//定义一个名为Index的应用入口组件@Entry@Componentstruct......
  • Spring Boot 三层架构开发模式入门
    在SpringBoot项目中,构建清晰、易于维护的代码结构至关重要。传统业务逻辑方式往往将所有代码混杂在一起,导致代码难以理解、修改和扩展。三层架构模式的出现正是为了解决这些问题,让我们深入了解它带来的改变。一、传统业务逻辑方式假设我们要实现一个简单的员工查询功能,传......
  • 消息队列面试01
    基础知识特点:(1)服务解耦:服务之间通过消息中介(如RabbitMQ、Kafka)进行通信,减少直接依赖。(2)异步处理:提高当前请求速度,代价是系统调用的降速,可能带来业务不一致。(3)削峰(流量控制):消息产生速度>消息消费速度(先把请求存起来)(4)增强系统可靠性:     I.MQ给consumerAC......
  • STM32F1系列 HAL&LL中文注释库 适用于STM32F101 103 105等MCU 1.8.5版本
    *******下有更多展示图片********由于本汉化不改变官方文件的内容与结构,文档内的链接和官方的营销信息,很多的资源站对内容有检测无法上传,同时考虑这云盘、那博客的限速、会员、账号要求。此文档挂于淘宝,价格:19.9元(GPT回血)说明:机器人自动发货,蓝奏云不限速下载,保证图文......
  • C++ 模板详解(一)
    C++模板模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。模板是一种对类型进行参数化的工具;通常有两种形式:函数模板和类模板;函数模板针对仅参数类型不同的函......
  • linux systemctl 指令
    一、由来历史上,Linux的启动一直采用init进程。下面的命令用来启动服务。$sudo/etc/init.d/apache2start#或者$serviceapache2start这种方法有两个缺点。一是启动时间长。init进程是串行启动,只有前一个进程启动完,才会启动下一个进程。二是启动脚本复杂。init进......
  • 软件工程师课程辅导
    Day1环境搭建下载vscode下载链接:https://pan.baidu.com/s/1Oo1TIrAKmlEuEfdn9EXgLQ?pwd=nkt9配置vscode的python开发环境教程:https://www.runoob.com/python3/python-vscode-setup.html安装Pycharm下载教程:https://blog.csdn.net/qq_44809707/article/details/1......
  • 团队训练记录2024.10.5
    这次double精度上卡了,赛时和学校强队差两题题目链接:https://codeforces.com/gym/104023/problemA.Dunai队友写的,答案在总冠军位人数和位置上冠军加非冠军人数最小取min?#include<bits/stdc++.h>#definetest(i)cout<<#i<<""<<i<<""<<endl;#defin......
  • [Javascript] Circular dependency
    Weoftenseecirculardependency,whyit'saproblem,whyweshouldavoiditandhwotoavoidit?  Let'sseeanyexamplefirst//main.jsimportAfrom"moduleA"//moduleA.jsimportBfrom"./moduleB"console.log("M......