之前说过了硬件层次的降低功耗,stm32中通过tickless降低功耗的方法等(ma级),但是功耗还是不够低。在使用stm32L476单片机过程中发现有更多的低功耗模式,和时钟选择。由于系统需要低功耗,但是同时对实时性要求也很高(快速唤醒),在低功耗的时候,串口通讯还要及时,定时器还要工作。基于这种需求,最终选择了stm32L系列的stop2模式。(stop2+LPUART+LPTIM1+RTC)

stop2模式下,sRAM中的数据不会丢失,同时LSE,LSI时钟不会关闭,支持多种的唤醒方式,目前这里使用RTC唤醒,LPTIM唤醒和LPUART。

这种方式下,最重要的就是要考虑好1.时钟如何配置,2.进入stop2模式前配置好唤醒源的初始化3.唤醒后的时钟恢复4.最重要的还有当我们进入stop2后,主时钟都会关闭,那么睡眠后的这段时间就会丢失,当唤醒后,重新进入低功耗就会出现任务调度异常,如何找回这段时间是成功的关键。

在实现之前,我们一般都会找些参考程序,st官方提供了RTC唤醒和LPUART唤醒stop2模式的历程

STM32Cube_FW_L4_V1.14.0\Projects\NUCLEO-L476RG\Examples\PWR\PWR_STOP2_RTC

STM32Cube_FW_L4_V1.14.0\Projects\NUCLEO-L476RG\Examples_LL\LPUART\LPUART_WakeUpFromStop2

但是都是不带系统的,但是我们一般实现一个项目,使用裸机前后台任务操作用于多任务的处理是比较麻烦的,这里添加了FreeRTOS实时系统。

将官方代码移植到系统中,单独的通过RTC唤醒是没有问题的,单独的通过LPUART也是没问题,但是结合到一块就出现问题了,分析,在RTC的配置中,

tick_sleep = ((uint32_t)prvGetExpectedIdleTime());

HAL_RTCEx_DeactivateWakeUpTimer(&RTCHandle);//配置RTC唤醒

HAL_RTCEx_SetWakeUpTimer_IT(&RTCHandle,tick_sleep*2,RTC_WAKEUPCLOCK_RTCCLK_DIV16)

通过系统自带的函数,动态的计算出到下个任务的时间,也就是可睡眠的时间,然后设置到RTC中,此时的睡眠时间是可知的,睡眠是不影响任务调度的。但是加入LPUART的唤醒后,调度上就会变得复杂,因为不知道你的串口唤醒什么时候来,来了之后就会恢复时钟,此时的调度就会出错了。现象也确实如此,定义了两个任务,一个串口任务,一个1s周期性开灯任务,引入LPUART唤醒后,灯的闪动就出现了异常,也就是影响了系统调度时间。

一.时钟分配

时钟的分配,是低功耗里很关键的一步。如何设置?

1.这里面有几个比较关键的地方,RTC使用的是LSI  32Khz的时钟,当然也可以使用LSE,这里只要将RTC与相应的时钟关联好,同时RTC初始时,将分频初始化好,不然唤醒时间就会不准,RTC时间如何计算可参考这个博客

https://blog.csdn.net/qingwufeiyang12346/article/details/80686350

注意我们的LSI是32K,他的里面是用的别的型号,时钟不同。

2.我们主时钟使用的MSI,最大48M,使用HSI也可以,但是HSI只能到16M,这里使用48M原因和唤醒时间还有一定关系。官方资料说,在48MHz的MSI下,能够1us唤醒。

注意不要使用HSE时钟(没用过)。同时系统中需要手动配置唤醒之后的时钟 LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_MSI);

3.LPUART选用LSE 不能选用PCLK,因为低功耗后会被关闭,但是注意选用LSE,波特率最大仅支持到9600,再大的话会出现丢数据情况(一般丢首字节)。

4.唤醒后,要恢复stop2睡眠时停掉的时钟,不然不能正常使用。

二.如何将stop2唤醒和睡眠等操作加入到FreeRtos中?

st提供的历程中一般都是裸机操作,那么怎么加入到freertos中,在之前也说过,freeRtos低功耗原理上是在空闲任务的时候进入睡眠,任务调度的时候进行唤醒,空闲时间越长,肯定功耗就越低。我们需要参考freeRtos提供的tickless机制。

1.freeRTos功耗实现思路

在FreeRTOSConfig.h中打开#define configUSE_TICKLESS_IDLE 1

此时的tickless功耗模式就启动了,tickless中大概的实体函数是vPortSuppressTicksAndSleep()大体思路是这样的:

当处理器进入空闲任务后,关闭系统时钟(关闭滴答定时器中断),当其他中断发生或者其他任务需要处理的时候,处理器唤醒,因为关闭了系统时钟,需要补上这段时间(它使用了滴答定时器实现),通过一些机制得到低功耗模式的执行时间,唤醒后进行时间补偿,实现准确唤醒。

同时为了更低功耗,还做了一些接口,用于用户补充。

#define configPRE_SLEEP_PROCESSING(x) RTOS_PreSleepProcessing(x)//进入低功耗睡眠之前的第一个函数

#define configPOST_SLEEP_PROCESSING(x) RTOS_PostSleepProcessing(x)//低功耗唤醒后的第一个函数

这里面实现用户自己的函数,如降频,关中断,关外设等操作。

2.当我们使用RTC睡眠的时候

vPortSuppressTicksAndSleep不做修改,RTOS_PreSleepProcessing(x)进行睡眠操作(配置RTC唤醒,设置唤醒时间,进入stop2模式)

void OS_PreSleepProcessing(uint32_t *ulExpectedIdleTime)
{*ulExpectedIdleTime = 0;  //屏蔽掉默认的wfi指令执行方式,防止系统滴答唤醒tick_sleep = ((uint32_t)prvGetExpectedIdleTime()); 获取睡眠时间if(tick_sleep > 2) //判断是否进入低功耗{vTaskSuspendAll(); //挂起调度器HAL_RTCEx_DeactivateWakeUpTimer(&RTCHandle);//配置RTC唤醒HAL_RTCEx_SetWakeUpTimer_IT(&RTCHandle, tick_sleep*2,             RTC_WAKEUPCLOCK_RTCCLK_DIV16);EnterSTOP2Mode(); //进入低功耗}
}void EnterSTOP2Mode(void)
{LL_PWR_SetPowerMode(LL_PWR_MODE_STOP2);LL_LPM_EnableDeepSleep();  __WFI();
}RTOS_PostSleepProcessing(x)进行唤醒操作(从新配置时钟)
void OS_PostSleepProcessing(uint32_t *ulExpectedIdleTime)
{xTaskResumeAll(); //恢复调度器SYSCLKConfig_STOP();//恢复时钟
}void SYSCLKConfig_STOP(void)
{RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};RCC_OscInitTypeDef RCC_OscInitStruct = {0};uint32_t pFLatency = 0;/* Enable Power Control clock */__HAL_RCC_PWR_CLK_ENABLE();/* Get the Oscillators configuration according to the internal RCC registers */HAL_RCC_GetOscConfig(&RCC_OscInitStruct);/* Enable PLL */RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_NONE;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){}/* Get the Clocks configuration according to the internal RCC registers */HAL_RCC_GetClockConfig(&RCC_ClkInitStruct, &pFLatency);/* Select PLL as system clock source and keep HCLK, PCLK1 and PCLK2 clocks dividers as before */RCC_ClkInitStruct.ClockType     = RCC_CLOCKTYPE_SYSCLK;RCC_ClkInitStruct.SYSCLKSource  = RCC_SYSCLKSOURCE_PLLCLK;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, pFLatency) != HAL_OK){}}

现象倒是正常,因为使用freeRTOS的获取可睡眠的时间,但是我们LPUART等外设唤醒时间不确定,同时stop模式下滴答时钟是停止的,运行肯定是有问题的。

FreeRTOS也确实支持vPortSuppressTicksAndSleep的重构

#define configUSE_TICKLESS_IDLE 2 允许重构。

那么滴答时钟改用LPTIM来记录补偿时间???重构下vPortSuppressTicksAndSleep??

直接用LPTIM作为滴答时钟,这样的思路应该也是可以的,但是不知道咋替换为滴答时钟啊??

三.结论:

1.Stop 2 模式基于 Cortex-M4 深度睡眠模式与外设时钟门控。在 Stop 2 模式下, Vcore 域中的所有时钟都会停止, PLL、 MSI、 HSI16 和 HSE 振荡器也被禁止。一些带有唤醒功能(I2C3 和 LPUART)的外设可以开启 HSI16 以获取帧,如果该帧不是唤醒帧,也可以在接收到帧后关闭 HSI16。SRAM1、 SRAM2、 SRAM3 和寄存器内容将保留,所有 I/O 引脚的状态与运行模式下相同。

2.根据手册可知,Stop 2 模式会关闭系统时钟,当前的OS Tick 基于内核的 Systick 定时器。那么在系统时钟停止后,OS Tick 也会停止,对于某些依赖 OS Tick 的应用,在进入 Stop 2 模式,又被中断唤醒后,就会出现问题,因此需要在系统唤醒后,对 OS Tick 进行补偿。Stop 2 模式下,绝大多数外设都停止工作,仅低功耗定时器 1(LP_TIM1)选择 LSI 作为时钟源后,仍然能正常运行,所以选择 LP_TIM1 作为 Stop 2 模式的时间补偿定时器。

3.接下来通过LP_TIM1进行睡眠时间的获取,确实获取到了,但是又该如何将补偿到时钟源中,那就直接赋值给系统时钟吧。但是在再次睡眠时,freertos自带的获取下个任务时间的函数却出错了,说明这么恢复系统时钟还不太对。

整体思路应该是对的,但是卡死在这了,后来想了想如果串口中断频繁触发,从stop2模式不断恢复,功耗也会受影响,决定将两种情况区分开来,如果当前一段时间可以睡眠就stop2+RTC唤醒,如果此阶段有必要串口接收就LPRUN低功耗模式或者sleep等其他系统时钟不停止的模式,实现多种模式的切换。不同的情况切换为不同的低功耗方式。

我的stm32l476的板子,48MHZ系统时钟 sleep模式下功耗在3ma左右。stop模式下在1ma以内,通过测试发现大部分的功耗就是在时钟这块。(freeRTos中只开启了一个闪灯任务,周期1s)

注:一般在低功耗的应用中,我们常会将管脚进行下拉操作,防止漏电流,但是要注意硬件和软件的匹配。假如当串口加了下拉电阻,你配置的时候却配置为上拉输出,此时就会导致一部分不必要的电量损失。

在满足性能的情况下想要实现更低的功耗,不继续整看来是不行啊,还好弄出来了,使用没问题,但是稳定性还要验证,核心的几个函数标出来。

1.系统时钟配置(就是上面cubmx框图的配置)

void SystemClock_Config(void)
{LL_FLASH_SetLatency(LL_FLASH_LATENCY_2);if(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_2){Error_Handler();}LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);LL_RCC_LSI_Enable();/* Wait till LSI is ready */while(LL_RCC_LSI_IsReady() != 1){}LL_RCC_MSI_Enable();/* Wait till MSI is ready */while(LL_RCC_MSI_IsReady() != 1){}LL_RCC_MSI_EnablePLLMode();LL_RCC_MSI_EnableRangeSelection();LL_RCC_MSI_SetRange(LL_RCC_MSIRANGE_6);LL_RCC_MSI_SetCalibTrimming(0);LL_PWR_EnableBkUpAccess();LL_RCC_ForceBackupDomainReset();LL_RCC_ReleaseBackupDomainReset();LL_RCC_LSE_SetDriveCapability(LL_RCC_LSEDRIVE_LOW);LL_RCC_LSE_Enable();/* Wait till LSE is ready */while(LL_RCC_LSE_IsReady() != 1){}LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSI);LL_RCC_EnableRTC();LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_MSI, LL_RCC_PLLM_DIV_1, 24, LL_RCC_PLLR_DIV_2);LL_RCC_PLL_EnableDomain_SYS();LL_RCC_PLL_Enable();/* Wait till PLL is ready */while(LL_RCC_PLL_IsReady() != 1){}LL_RCC_PLLSAI1_ConfigDomain_48M(LL_RCC_PLLSOURCE_MSI, LL_RCC_PLLM_DIV_1, 24,     LL_RCC_PLLSAI1Q_DIV_2);LL_RCC_PLLSAI1_EnableDomain_48M();LL_RCC_PLLSAI1_Enable();/* Wait till PLLSAI1 is ready */while(LL_RCC_PLLSAI1_IsReady() != 1){}LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);/* Wait till System clock is ready */while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL){}LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);LL_SetSystemCoreClock(48000000);LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_LSE);LL_RCC_SetI2CClockSource(LL_RCC_I2C2_CLKSOURCE_PCLK1);LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM1_CLKSOURCE_LSI);LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_LSI);LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1);LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_SYSCLK);
}

2.用户唤醒的RTC的配置

void SystemPower_Config(void)
{/* Configure RTC */RTCHandle.Instance = RTC;RTCHandle.Init.HourFormat = RTC_HOURFORMAT_24;RTCHandle.Init.AsynchPrediv = RTC_ASYNCH_PREDIV;RTCHandle.Init.SynchPrediv = RTC_SYNCH_PREDIV;RTCHandle.Init.OutPut = RTC_OUTPUT_DISABLE;RTCHandle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;RTCHandle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;if( HAL_RTC_Init(&RTCHandle) != HAL_OK){/* Initialization Error */}
}

stm32l4xx_hal_msp.c添加代码

void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{RCC_OscInitTypeDef RCC_OscInitStruct;RCC_PeriphCLKInitTypeDef  PeriphClkInitStruct;/*##-1- Configure the RTC clock source ######################################*//* -a- Enable LSI Oscillator */RCC_OscInitStruct.OscillatorType =  RCC_OSCILLATORTYPE_LSI;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;RCC_OscInitStruct.LSIState = RCC_LSI_ON;if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){while(1);}/* -b- Select LSI as RTC clock source */PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;if(HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK){ while(1);}/*##-2- Enable the RTC peripheral Clock ####################################*//* Enable RTC Clock */__HAL_RCC_RTC_ENABLE();/*##-3- Configure the NVIC for RTC Alarm ###################################*/HAL_NVIC_SetPriority(RTC_WKUP_IRQn, 0x0, 0);HAL_NVIC_EnableIRQ(RTC_WKUP_IRQn);
}/*** @brief RTC MSP De-Initialization *        This function freeze the hardware resources used in this example:*          - Disable the Peripheral's clock* @param hrtc: RTC handle pointer* @retval None*/
void HAL_RTC_MspDeInit(RTC_HandleTypeDef *hrtc)
{/*##-1- Reset peripherals ##################################################*/__HAL_RCC_RTC_DISABLE();
}
void HAL_MspInit(void)
{/* USER CODE BEGIN MspInit 0 *//* USER CODE END MspInit 0 */__HAL_RCC_SYSCFG_CLK_ENABLE();__HAL_RCC_PWR_CLK_ENABLE();/* System interrupt init*//* USER CODE BEGIN MspInit 1 *//* USER CODE END MspInit 1 */
}

3.核心的功耗操作,及时钟的恢复

void OS_PreSleepProcessing(uint32_t *ulExpectedIdleTime)
{*ulExpectedIdleTime = 0;  //屏蔽掉默认的wfi指令执行方式if(g_stopmode_flag){tick_sleep = ((uint32_t)prvGetExpectedIdleTime());if(tick_sleep > 4) //判断是否进入低功耗{LPUART_PrepareToStopMode();//配置串口唤醒HAL_RTCEx_DeactivateWakeUpTimer(&RTCHandle);//配置RTC唤醒HAL_RTCEx_SetWakeUpTimer_IT(&RTCHandle, (tick_sleep)*2,     RTC_WAKEUPCLOCK_RTCCLK_DIV16);// Wakeup Time Base = 16 /(~32.000KHz) = ~0.5 mscount_start(); //重置计数tick_sys_old = xTaskGetTickCount();HAL_PWREx_EnterSTOP1Mode(PWR_STOPENTRY_WFI);//进入低功耗g_stopmode_start_flag = 1;}}}
void OS_PostSleepProcessing(uint32_t *ulExpectedIdleTime)
{time_count_sys =  LL_LPTIM_GetCounter(LPTIM2)+4;count_stop();if(g_stopmode_flag && g_stopmode_start_flag){g_stopmode_start_flag = 0;if(time_count_sys == tick_sleep){//表示为RTC唤醒rtc_wakeup_flag =1;}SYSCLKConfig_STOP();//恢复时钟}}
//时钟的恢复,要和配置对应,怎么配置的怎么恢复
void SYSCLKConfig_STOP(void)
{RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};RCC_OscInitTypeDef RCC_OscInitStruct = {0};uint32_t pFLatency = 0;/* Enable Power Control clock */__HAL_RCC_PWR_CLK_ENABLE();/* Get the Oscillators configuration according to the internal RCC registers */HAL_RCC_GetOscConfig(&RCC_OscInitStruct);/* Enable PLL */RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_NONE;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){}/* Get the Clocks configuration according to the internal RCC registers */HAL_RCC_GetClockConfig(&RCC_ClkInitStruct, &pFLatency);/* Select PLL as system clock source and keep HCLK, PCLK1 and PCLK2 clocks dividers as         before */RCC_ClkInitStruct.ClockType     = RCC_CLOCKTYPE_SYSCLK;RCC_ClkInitStruct.SYSCLKSource  = RCC_SYSCLKSOURCE_PLLCLK;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, pFLatency) != HAL_OK){}
}

4.tickless函数里的操作,也可以直接从新生成一个函数,我是直接基于tickless改的。只添加了两处

__weak void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ){uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements, ulSysTickCTRL;TickType_t xModifiableIdleTime;/* Make sure the SysTick reload value does not overflow the counter. */if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ){xExpectedIdleTime = xMaximumPossibleSuppressedTicks;}/* Stop the SysTick momentarily.  The time the SysTick is stopped foris accounted for as best it can be, but using the tickless mode willinevitably result in some tiny drift of the time maintained by thekernel with respect to calendar time. */portNVIC_SYSTICK_CTRL_REG &= ~portNVIC_SYSTICK_ENABLE_BIT;/* Calculate the reload value required to wait xExpectedIdleTimetick periods.  -1 is used because this code will execute part waythrough one of the tick periods. */ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );if( ulReloadValue > ulStoppedTimerCompensation ){ulReloadValue -= ulStoppedTimerCompensation;}/* Enter a critical section but don't use the taskENTER_CRITICAL()method as that will mask interrupts that should exit sleep mode. */__disable_interrupt();__DSB();__ISB();/* If a context switch is pending or a task is waiting for the schedulerto be unsuspended then abandon the low power entry. */if( eTaskConfirmSleepModeStatus() == eAbortSleep ){/* Restart from whatever is left in the count register to completethis tick period. */portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;/* Restart SysTick. */portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;/* Reset the reload register to the value required for normal tickperiods. */portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;/* Re-enable interrupts - see comments above __disable_interrupt()call above. */__enable_interrupt();}else{/* Set the new reload value. */portNVIC_SYSTICK_LOAD_REG = ulReloadValue;/* Clear the SysTick count flag and set the count value back tozero. */portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;/* Restart SysTick. */portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;/* Sleep until something happens.  configPRE_SLEEP_PROCESSING() canset its parameter to 0 to indicate that its implementation containsits own wait for interrupt or wait for event instruction, and so wfishould not be executed again.  However, the original expected idletime variable must remain unmodified, so a copy is taken. */xModifiableIdleTime = xExpectedIdleTime;configPRE_SLEEP_PROCESSING( xModifiableIdleTime );if( xModifiableIdleTime > 0 ){__DSB();__WFI();__ISB();}configPOST_SLEEP_PROCESSING( xExpectedIdleTime );/* Stop SysTick.  Again, the time the SysTick is stopped for isaccounted for as best it can be, but using the tickless mode willinevitably result in some tiny drift of the time maintained by thekernel with respect to calendar time. */ulSysTickCTRL = portNVIC_SYSTICK_CTRL_REG;portNVIC_SYSTICK_CTRL_REG = ( ulSysTickCTRL & ~portNVIC_SYSTICK_ENABLE_BIT );/* Re-enable interrupts - see comments above __disable_interrupt()call above. */__enable_interrupt();if( ( ulSysTickCTRL & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 || (rtc_wakeup_flag ==1)){uint32_t ulCalculatedLoadValue;rtc_wakeup_flag = 0;if(g_stopmode_flag)  //1.这里是新添加的{ulCompleteTickPeriods = time_count_sys;}else{/* The tick interrupt has already executed, and the SysTickcount reloaded with ulReloadValue.  Reset theportNVIC_SYSTICK_LOAD_REG with whatever remains of this tickperiod. */ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );/* Don't allow a tiny value, or values that have somehowunderflowed because the post sleep hook did somethingthat took too long. */if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) ){ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL );}portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;/* The tick interrupt handler will already have pended the tickprocessing in the kernel.  As the pending tick will beprocessed as soon as this function exits, the tick valuemaintained by the tick is stepped forward by one less than thetime spent waiting. */ulCompleteTickPeriods = xExpectedIdleTime - 1UL;}}else{/* Something other than the tick interrupt ended the sleep.Work out how long the sleep lasted rounded to complete tickperiods (not the ulReload value which accounted for partticks). *///ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;if(g_stopmode_flag) //2.这里是新添加的{ulCompletedSysTickDecrements = time_count_sys;}else{ulCompletedSysTickDecrements = ( xExpectedIdleTime * ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;}/* How many complete tick periods passed while the processorwas waiting? */ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;/* The reload value is set to whatever fraction of a single tickperiod remains. */portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1UL ) * ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;}/* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REGagain, then set portNVIC_SYSTICK_LOAD_REG back to its standardvalue.  The critical section is used to ensure the tick interruptcan only execute once in the case that the reload register is nearzero. */portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;portENTER_CRITICAL();{portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT;vTaskStepTick( ulCompleteTickPeriods );portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;}portEXIT_CRITICAL();}}

5.stm32L476在freeRTOS下使用低功耗相关推荐

  1. 【STM8L】Active-Halt模式下的低功耗

      大家好,我是小政.本篇文章我将针对STM8L Active-halt模式下的低功耗进行详细的讲解,让准备做低功耗产品的小伙伴能够更好的理解在STM8L低功耗模式下运行,低功耗模式主要在各类仪器仪表 ...

  2. 正点原子FreeRTOS(下)

    目录 第十六章FreeRTOS 事件标志组 16.1 事件标志组简介 16.2 创建事件标志组 16.3 设置事件位 16.4 获取事件标志组值 16.5 等待指定的事件位 16.6 事件标志组实验 ...

  3. Linux卸载蓝牙模块,Linux 下调试低功耗蓝牙的笔记

    蓝牙4.0版本推出了低功耗规范,简称BLE (Bluetooth Low Energy),很多小型设备,例如小米手环,都是使用低功耗蓝牙.要与这类模块连接,主设备的蓝牙模块必须支持低功耗,例如inte ...

  4. stm32基于FreeRtos下的电阻触摸屏简易计算器

    先上代码: void Draw_Keyboard_Layout(void) {LCD_ShowString(5,25,200,16,16,"Power by Vincent-NJW" ...

  5. Cube添加FreeRTOS 下

    使用百问网的STM32F103MINI开发板完成下面实验. 1.编写添加的任务函数. void StartMyTask(void *argument) {uint8_t rx_data[200] = ...

  6. 串口服务器通讯中断不流畅,在FreeRTOS下串口中断不正常工作,一中断就死机为何?...

    CPU: UC3A0512 AVR32Studio 2.1.1 + Tool 2.1.6 中断处理程序如下: 问题描述: 系统跑FreeRTOS系统,开几个任务. 运行正常. 但串口有数据进来的时候立 ...

  7. win10下pyqt5低功耗蓝牙系列一:开发环境搭建

    1.序言 之前在网上搜索关于python实现低功耗蓝牙(BLE)的案例,基本都是让安装pybluez等之类的工具,实测发现基本行不通,具体原因也不记得了,折腾了将近一个星期时间.这两天看Qt的QtBl ...

  8. FreeRTOS学习笔记——互斥型信号量

    来自:http://blog.csdn.net/xukai871105/article/details/43456985 0.前言 在嵌入式操作系统中互斥型信号量是任务间资源保护的重要手段.下面结合一 ...

  9. FreeRTOS CortexM3 M4中断优先级设置总结

    前言 本文将说明在FreeRTOS嵌入式操作系统中,如何设置STM32 Cortex M3和M4系列MCU的中断优先级. 总结 [1]STM32L1系列,STM32F1系列,STM32F4系列,设置N ...

  10. 6.stm32 低功耗设计--总结

    一 . 需求分析阶段 1.1 引入 随着近几年电子产品的高速发展,出现了各式各样的便携式产品,他们的发展趋势必将是更小.更轻,功能更强大.那么在产品的开发过程中,需要在满足需求中性能指标后,尽可能的优 ...

最新文章

  1. js实现下拉框三级级联
  2. 第二节课作业150206309
  3. 各种没有由来的问题,干!
  4. MAUI 移植 Xamarin.Forms 自定义渲染器
  5. java三大框架实现任务调度——IRemindService
  6. vector和list容器有哪些区别
  7. WF4.0 基础篇 (二十九) WorkflowInspectionServices
  8. 7-11 玩转二叉树 (25 分)
  9. l2-029 特立独行的幸福 (25分)_霜降后盆栽幸福树,调整4个地方,不用再怕掉叶子了...
  10. 如何从手机上做风控,设备指纹如何下手?
  11. python怎么读文件-python怎么读json文件
  12. MyBatis 处理长字段(long varchar)
  13. [转载] python画柱状图-Python绘制精美图表之双柱形图
  14. Yasm的作用及NASM详解
  15. 神经计算棒是什么_这是太棒了
  16. 分布式光伏运维服务器,户用分布式光伏电站运维指导手册——运维及安全
  17. 开发必备的最高100个 Flutter 开源精品项目
  18. HEVC学习笔记(二)整体介绍
  19. 解决Android 8.1 获取不到wifi名称
  20. DC/DC转换器设计中接地线的布线技巧

热门文章

  1. 贪心算法解决汽车加油问题
  2. deviceOrientation简介
  3. C语言每日一练——第74天:黑与白问题
  4. Java集合框架详解笔记及其代码
  5. android控制音量大小,Android AudioTrack音量控制笔记总结
  6. Android手机玩8086汇编
  7. 最快的 Hexo 博客搭建方法
  8. webview出现图片加载异常 Mixed Content: The page at 'https
  9. arm 开发环境搭建-基于QEMU和Docker
  10. 太阳系各大行星运行轨迹