新手上路
- 积分
- 41
- 金钱
- 41
- 注册时间
- 2018-8-27
- 在线时间
- 9 小时
|
楼主 |
发表于 2021-1-4 15:41:35
|
显示全部楼层
补上源函数
1 #if configUSE_TICKLESS_IDLE == 1
2
3 __weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
4 {
5 uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL;
6 TickType_t xModifiableIdleTime;
7
8 /* Make sure the SysTick reload value does not overflow the counter. */
确保滴答定时器的reload值不会溢出,也就是不能超过滴答定时器最大计数值。 9 if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ) 【1】见后
10 {
11 xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
12 }
13
14 /* Stop the SysTick momentarily. The time the SysTick is stopped for
15 is accounted for as best it can be, but using the tickless mode will
16 inevitably result in some tiny drift of the time maintained by the
17 kernel with respect to calendar time. */ 停止滴答定时器
18 portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;
19
20 /* Calculate the reload value required to wait xExpectedIdleTime
21 tick periods. -1 is used because this code will execute part way
22 through one of the tick periods. */
23 根据参数xExpectIdleTime来计算滴答定时器的重载值,进入低功耗之后,计时由滴答定时器计算。 ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG(寄存器) + ( ulTimerCountsForOneTick(一个节拍多少个时钟) * ( xExpectedIdleTime - 1UL ) );
24 if( ulReloadValue > ulStoppedTimerCompensation ) 【2】补偿时间,见后
25 {
26 ulReloadValue -= ulStoppedTimerCompensation;
27 }
28
29 /* Enter a critical section but don't use the taskENTER_CRITICAL()
30 method as that will mask interrupts that should exit sleep mode. */
31 __disable_irq(); 【3】设置PRIMASK关闭中断
32 __dsb( portSY_FULL_READ_WRITE );
33 __isb( portSY_FULL_READ_WRITE );
34
35 /* If a context switch is pending or a task is waiting for the scheduler
36 to be unsuspended then abandon the low power entry. */ 确认是否可以进入低功耗模式
37 if( eTaskConfirmSleepModeStatus() == eAbortSleep ) 【4】函数见后
38 {
39 /* Restart from whatever is left in the count register to complete
40 this tick period. */ 不能进入低功耗模式,重启滴答定时器,恢复滴答运行
41 portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;
42
43 /* Restart SysTick. */
44 portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
45
46 /* Reset the reload register to the value required for normal tick
47 periods. */
48 portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
49
50 /* Re-enable interrupts - see comments above __disable_irq() call
51 above. */
52 __enable_irq(); 恢复中断设置
53 }
54 else
55 { 可以进入低功耗模式,设置滴答定时器
56 /* Set the new reload value. */
57 portNVIC_SYSTICK_LOAD_REG = ulReloadValue; 刚刚在【2】处算的时间值,赋给滴答定时器
58
59 /* Clear the SysTick count flag and set the count value back to
60 zero. */
61 portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
62
63 /* Restart SysTick. */
64 portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
65
66 /* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
67 set its parameter to 0 to indicate that its implementation contains
68 its own wait for interrupt or wait for event instruction, and so wfi
69 should not be executed again. However, the original expected idle
70 time variable must remain unmodified, so a copy is taken. */
71 xModifiableIdleTime = xExpectedIdleTime;
72 configPRE_SLEEP_PROCESSING( xModifiableIdleTime ); 【5】见后
73 if( xModifiableIdleTime > 0 )
74 {
75 __dsb( portSY_FULL_READ_WRITE );
76 __wfi(); 使用__WFI指令,进入睡眠模式。http://www.keil.com/support/man/ ... hr1359125004400.htm
77 __isb( portSY_FULL_READ_WRITE );
78 } 当代码执行到这里,说明已经退出了低功耗模式!!!
79 configPOST_SLEEP_PROCESSING( xExpectedIdleTime ); 【5】见后
80
81 /* Stop SysTick. Again, the time the SysTick is stopped for is
82 accounted for as best it can be, but using the tickless mode will
83 inevitably result in some tiny drift of the time maintained by the
84 kernel with respect to calendar time. */ 停止滴答定时器
85 ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG; 读取滴答定时器控制和状态寄存器
86 portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT );
87
88 /* Re-enable interrupts - see comments above __disable_irq() call
89 above. */
90 __enable_irq();
91 判断导致退出低功耗的是,外部中断,还是滴答定时器计时时间到了
92 if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) 不同的唤醒方式,对应的“系统时间补偿值”(单位是时钟节拍)是不同的。
93 {
94 uint32_t ulCalculatedLoadValue;
95
96 /* The tick interrupt has already executed, and the SysTick
97 count reloaded with ulReloadValue. Reset the
98 portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick
99 period. */
100 ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );
101
102 /* Don't allow a tiny value, or values that have somehow
103 underflowed because the post sleep hook did something
104 that took too long. */
105 if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) )
106 {
107 ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );
108 }
109
110 portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;
111
112 /* The tick interrupt handler will already have pended the tick
113 processing in the kernel. As the pending tick will be
114 processed as soon as this function exits, the tick value
115 maintained by the tick is stepped forward by one less than the
116 time spent waiting. */
117 ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
118 }
119 else 外部中断唤醒的,需要进行时间补偿
120 {
121 /* Something other than the tick interrupt ended the sleep.
122 Work out how long the sleep lasted rounded to complete tick
123 periods (not the ulReload value which accounted for part
124 ticks). */
125 ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;
126
127 /* How many complete tick periods passed while the processor
128 was waiting? */
129 ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
130
131 /* The reload value is set to whatever fraction of a single tick
132 period remains. */
133 portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;
134 }
135
136 /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG
137 again, then set portNVIC_SYSTICK_LOAD_REG back to its standard
138 value. The critical section is used to ensure the tick interrupt
139 can only execute once in the case that the reload register is near
140 zero. */ 重新启动滴答定时器,重载值设置为正常值。
141 portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
142 portENTER_CRITICAL();
143 {
144 portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;
145 vTaskStepTick( ulCompleteTickPeriods ); 【6】给系统时钟节拍进行补偿,函数见后
146 portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;
147 }
148 portEXIT_CRITICAL();
149 }
150 }
151
152 #endif /* #if configUSE_TICKLESS_IDLE */ |
|