2020-6-7 23:34| 发布者: admin| 查看: 1891| 评论: 0|原作者: 火柴棍
最近做一个物联网的项目,由于功能比较多,为了简化程序逻辑,所以使用了FreeRTOS操作系统,MCU为STM32L431。FreeRTOS的源码只实现了sleep级别低功耗模式(需要定义#define configUSE_TICKLESS_IDLE 1),此模式只有CPU停止运行,功耗有几个mA电流。STOP模式2是MCU能被一些外设唤醒的最低功耗模式。但是MCU一但进入STOP模式2,只有LSI和LSE时钟能开启,其余时钟均关闭,FreeRTOS时间片管理所使用的SYSTICK定时器使用的时钟为系统时钟或者系统时钟的8分频,在STOP2模式下系统时钟是关闭的,所以SYSTICK在STOP2模式下会停止运行,那么FreeRTOS的时间片管理会出错。 大部分所采用的方法是将FreeRTOS时间片管理使用的SYSTICK定时器改为RTC Timer或Lp Timer实现,因为RTC AWU Timer和Lp Timer可选择LSE或LSI作为时钟源,在STOP2模式下依然可以运行,这样就能保证FreeRTOS的时间片管理不会出错。我刚开始尝试使用RTC AWU Timer替换SYSTICK Timer,但是发现操作RTC AWU Timer的寄存器步骤繁琐,操作之前需要失能保护,操作之后需要使能保护,还有其它一些繁琐的操作,我就想改为由Lp Timer实现,操作相对简单一些。在我修改时,我也在翻看STM32Cube_FW_L4_V1.13.0\Projects中的例程,打开了B-L475E-IOT01A文件夹,接着又点开了Applications看到了FreeRTOS,我点开了FreeRTOS文件夹看到了FreeRTOS_LowPower_LPTIM文件名,顿时有种想哭的感觉,也好后悔没有早点看到这个例程,这不正是我想要的吗?在低功耗模式下通过Lp Timer来实现FreeRTOS的时间片管理,然后我打开工程仔细研究了一番,此例程的FreeRTOS API封装是CMSIS_V1版本,低功耗模式为STOP1,使用了LPTIM1作为FreeRTOS的时间片管理定时器,选择LSE(32.768kHz)作为时钟源,1分频,系统的Tick周期为1ms,LPTIM1的自动重装周期值设为32即可,并且HAL库的HAL_IncTick()也是通过LPTIM1来实现。有一个关键点需要了解一下,FreeRTOS系统进入Sleep模式的最大Tick数(xMaximumPossibleSuppressedTicks),换言之FreeRTOS最多睡多久就必须被唤醒,根据定义: static const uint32_t ulReloadValueForOneSec = LSE_VALUE; xMaximumPossibleSuppressedTicks = (portMAX_16_BIT_NUMBER * configTICK_RATE_HZ) / ulReloadValueForOneSec; LSE_ALUE的值为32768U,那么xMaximumPossibleSuppressedTicks=(0xFFFF*1000)/32768=1999,最多1999个Tick,1个Tick的周期为1ms,那就是1.999秒,那么FreeRTOS一次最多睡1.999秒就会被唤醒然后重装LPTIM1的计数值。如果需要让FreeRTOS一次睡的时间更久,可以修改void InitTick (uint32_t TickPriority)函数中LptimHandle.Init.Clock.Prescaler 的值,分频越大xMaximumPossibleSuppressedTicks越大,不能操作LPTIM_PRESCALER_DIV16,不然Tick周期会超过1ms。如果修改了LptimHandle.Init.Clock.Prescaler的值,那么需要修改以下4个定义值: #define PeriodValue (uint32_t) (32) #define PulseValue (uint32_t) (16) static const uint32_t ulReloadValueForOneTick = (LSE_VALUE / configTICK_RATE_HZ); static const uint32_t ulReloadValueForOneSec = LSE_VALUE; 几分频就再除以几,xMaximumPossibleSuppressedTicks的最终值就是1999*分频数。 移植说明: 如果工程使用的FreeRTOS API封装为CMSIS_V1版本,那么将以下文件移到工程: low_power_tick_management_LPTIM.c stm32l4xx_timebase_lptim.c stm32l4xx_timebase_lptim.h 并定义定义#define configUSE_TICKLESS_IDLE 2 如果要进入STOP2模式,可修改void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )函数中的HAL_PWREx_EnterSTOP1Mode(PWR_STOPENTRY_WFI);为HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI); 我的项目使用的FreeRTOS API封装为CMSIS_V2,移植时除了以上几点,还需要修改一些内容。 low_power_tick_management_LPTIM.c 可参考如下代码:
stm32l4xx_timebase_lptim.c 可参考如下代码:
stm32l4xx_timebase_lptim.h 可参考如下代码:
我的项目LPTIM1的时钟源为LSI,二分频。 STM32Cube_FW_L4_V1.13.0网盘链接:链接:https://pan.baidu.com/s/1FmC5umQaWGGC9iA4vT6IxA 技术交流群 STM32MP1:861926625 ESP8266:476685983 |