OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 9190|回复: 7

FreeRTOS睡眠滴答定时器问题

[复制链接]

1

主题

7

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2018-8-27
在线时间
9 小时
发表于 2020-12-31 17:44:41 | 显示全部楼层 |阅读模式
10金钱
图片的代码在函数vPortSuppressTicksAndSleep里,请问下为什么要给滴答定时器先设置个重载值然后启动,再马上恢复原本的重载值?
1609407792(1).png
1609407728(1).png

最佳答案

查看完整内容[请看2#楼]

破案,由于滴答定时器当前值只能写0,于是通过把当前值写0,并且在重载值里写入你真正想给当前值的数值,然后一开启定时器后,当前值立马会给重载值给设置进去
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

1

主题

7

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2018-8-27
在线时间
9 小时
 楼主| 发表于 2020-12-31 17:44:42 | 显示全部楼层
破案,由于滴答定时器当前值只能写0,于是通过把当前值写0,并且在重载值里写入你真正想给当前值的数值,然后一开启定时器后,当前值立马会给重载值给设置进去
回复

使用道具 举报

1

主题

7

帖子

0

精华

新手上路

积分
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 */
回复

使用道具 举报

1

主题

7

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2018-8-27
在线时间
9 小时
 楼主| 发表于 2021-1-4 15:43:16 | 显示全部楼层
本帖最后由 chzdeyouxiang 于 2021-1-5 15:28 编辑

      
回复

使用道具 举报

1

主题

7

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2018-8-27
在线时间
9 小时
 楼主| 发表于 2021-1-4 16:01:32 | 显示全部楼层
本帖最后由 chzdeyouxiang 于 2021-1-5 15:28 编辑

         
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2021-1-5 01:30:37 | 显示全部楼层
帮顶
回复

使用道具 举报

28

主题

113

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1472
金钱
1472
注册时间
2021-8-10
在线时间
271 小时
发表于 2022-3-19 10:52:29 | 显示全部楼层
楼主的意思是不是,在某个计数周期内,我给当前值写0,然后再给重载值附上一个我需要的值,这时候开启,倒计时的值就是我们那个赋予的新值了???
回复

使用道具 举报

1

主题

7

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2018-8-27
在线时间
9 小时
 楼主| 发表于 2023-3-25 18:25:34 | 显示全部楼层
橘子汁真好喝 发表于 2022-3-19 10:52
楼主的意思是不是,在某个计数周期内,我给当前值写0,然后再给重载值附上一个我需要的值,这时候开启,倒 ...

是的。。。。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-22 17:16

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表