CH582 CH583 FreeRTOS之Tickless低功耗管理實現(xiàn)

????前兩天在研究FreeRTOS的Tickless低功耗管理,使用的是CH582的板子,一直卡在portSUPPRESS_TICKS_AND_SLEEP()宏的實現(xiàn)上面。具體問題如下:

????使用LowPower_Halt休眠沒有問題,使用LowPower_Sleep休眠時,系統(tǒng)在切換任務時就直接卡B了。

????非常郁悶,嘗試了各種方法都不行,直到我看到這個:

????1667100237641.jpg

????也就是說CH58X系列的systick在休眠后是會復位配置和計數(shù)的,這不坑爹嘛!

????廢話不多少,上代碼。以下是portSUPPRESS_TICKS_AND_SLEEP()宏的具體實現(xiàn):

/*?Define?the?function?that?is?called?by?portSUPPRESS_TICKS_AND_SLEEP().?*/
void?vApplicationSleep(?uint32_t?xExpectedIdleTime?)?{
#if(defined(HAL_SLEEP))?&&?(HAL_SLEEP?==?TRUE)
????unsigned?long?ulLowPowerTimeBeforeSleep,?ulLowPowerTimeAfterSleep,?ulLowPowerTimeTotalSleep,?irq_status;
????eSleepModeStatus?eSleepStatus;
????uint32_t?time_sleep,?time_curr,?time;
????/*?Stop?the?timer?that?is?generating?the?tick?interrupt.?*/
????PFIC_DisableIRQ(RTC_IRQn);
????PFIC_DisableIRQ(SysTick_IRQn);
????SYS_DisableAllIrq(&irq_status);
????ulLowPowerTimeBeforeSleep?=?RTC_GetCycle32k();
????time?=?xExpectedIdleTime?*?32.768?+?ulLowPowerTimeBeforeSleep;
????if?(time?>=?RTC_TIMER_MAX_VALUE)?{
????????time?-=?RTC_TIMER_MAX_VALUE;
????}
????if?(time?<?WAKE_UP_RTC_MAX_TIME?+?32)?{
????????PFIC_EnableIRQ(SysTick_IRQn);
????????SYS_RecoverIrq(irq_status);
????????return;
????}
????time?-=?(WAKE_UP_RTC_MAX_TIME?+?32);
????time_curr?=?RTC_GetCycle32k();
????//?檢測睡眠時間
????if?(time?<?time_curr)?{
????????time_sleep?=?time?+?(RTC_TIMER_MAX_VALUE?-?time_curr);
????}?else?{
????????time_sleep?=?time?-?time_curr;
????}
????if?(time_sleep?>?(RTC_TIMER_MAX_VALUE?-?TMOS_TIME_VALID))?{
????????PFIC_EnableIRQ(SysTick_IRQn);
????????SYS_RecoverIrq(irq_status);
????????return;
????}
????/*?Ensure?it?is?still?ok?to?enter?the?sleep?mode.?*/
????eSleepStatus?=?eTaskConfirmSleepModeStatus();
????if(?eSleepStatus?==?eAbortSleep?)?{
????????PFIC_EnableIRQ(SysTick_IRQn);
????????SYS_RecoverIrq(irq_status);
????}
????else?{
????????if(?eSleepStatus?==?eNoTasksWaitingTimeout?)?{
????????????LowPower_Shutdown(0);
????????}
????????else?{
????????????RTC_SetTignTime(time);
????????????//PFIC_EnableIRQ(RTC_IRQn);
#if(DEBUG?==?Debug_UART1)?//?使用其他串口輸出打印信息需要修改這行代碼
??????????????while((R8_UART1_LSR?&?RB_LSR_TX_ALL_EMP)?==?0)?{
??????????????????__nop();
??????????????}
#endif
????????????//?LOW?POWER-sleep模式
????????????if(!(R8_RTC_FLAG_CTRL?&?RB_RTC_TRIG_FLAG))?{
????????????????LowPower_Sleep_Event(RB_PWR_RAM2K?|?RB_PWR_RAM30K?|?RB_PWR_XROM?|?RB_PWR_EXTEND?|?RB_PWR_CORE);
????????????????if(R8_RTC_FLAG_CTRL?&?RB_RTC_TRIG_FLAG)?{?//?注意如果使用了RTC以外的喚醒方式,需要注意此時32M晶振未穩(wěn)定
????????????????????R8_RTC_FLAG_CTRL?=?RB_RTC_TRIG_CLR;
????????????????????time?+=?WAKE_UP_RTC_MAX_TIME;
????????????????????if(time?>?0xA8C00000)?{
????????????????????????time?-=?0xA8C00000;
????????????????????}
????????????????????RTC_SetTignTime(time);
????????????????????LowPower_Idle_Event();
????????????????????R8_RTC_FLAG_CTRL?=?RB_RTC_TRIG_CLR;
????????????????}
????????????????HSECFG_Current(HSE_RCur_100);?//?降為額定電流(低功耗函數(shù)中提升了HSE偏置電流)
????????????????vPortSetupTimerInterrupt();???//?恢復SysTick配置
????????????}
????????????ulLowPowerTimeAfterSleep?=?RTC_GetCycle32k();
????????????if?(ulLowPowerTimeAfterSleep?<?ulLowPowerTimeBeforeSleep)?{
????????????????ulLowPowerTimeTotalSleep?=?ulLowPowerTimeAfterSleep?+?(RTC_TIMER_MAX_VALUE?-?ulLowPowerTimeBeforeSleep);
????????????}
????????????else?{
????????????????ulLowPowerTimeTotalSleep?=?ulLowPowerTimeAfterSleep?-?ulLowPowerTimeBeforeSleep;
????????????}
????????????ulLowPowerTimeTotalSleep?=?ulLowPowerTimeTotalSleep?*?1000?/?32768;
????????????vTaskStepTick(?ulLowPowerTimeTotalSleep?);
????????????//PRINT("ulLowPowerTimeTotalSleep?=?%d??xExpectedIdleTime=%d\n",?ulLowPowerTimeTotalSleep,?xExpectedIdleTime);
????????????//PRINT("xTickCount?=?%d\n",?xTaskGetTickCount());
????????}
????????SYS_RecoverIrq(irq_status);
????????PFIC_EnableIRQ(SysTick_IRQn);
????}
#endif
}


重點是休眠喚醒后,需要調用vPortSetupTimerInterrupt()恢復SysTick配置。

1


參考最新的代碼,把SysTick計數(shù)值也更新了,同時修復了休眠時間太短的時候異常的問題:

/*?Define?the?function?that?is?called?by?portSUPPRESS_TICKS_AND_SLEEP().?*/
__HIGH_CODE
void?vApplicationSleep(?uint32_t?xExpectedIdleTime?)?{
#if(defined(HAL_SLEEP))?&&?(HAL_SLEEP?==?TRUE)
????unsigned?long?ulLowPowerTimeBeforeSleep,?ulLowPowerTimeAfterSleep,?ulLowPowerTimeTotalSleep,?irq_status;
????eSleepModeStatus?eSleepStatus;
????uint32_t?time_sleep,?time_curr,?time;
????uint64_t?sysTick_cnt?=?0;
????/*?Stop?the?timer?that?is?generating?the?tick?interrupt.?*/
????PFIC_DisableIRQ(RTC_IRQn);
????SYS_DisableAllIrq(&irq_status);
????sysTick_cnt?=?SysTick->CNT;
????ulLowPowerTimeBeforeSleep?=?RTC_GetCycle32k();
????time?=?xExpectedIdleTime?*?(32768.0?/?configTICK_RATE_HZ)?+?ulLowPowerTimeBeforeSleep;
????if?(time?>=?RTC_TIMER_MAX_VALUE)?{
????????time?-=?RTC_TIMER_MAX_VALUE;
????}
????if?(time?<?WAKE_UP_RTC_MAX_TIME?+?1)?{
????????SYS_RecoverIrq(irq_status);
????????return;
????}
????time?-=?(WAKE_UP_RTC_MAX_TIME?+?1);
????time_curr?=?RTC_GetCycle32k();
????//?檢測睡眠時間
????if?(time?<?time_curr)?{
????????time_sleep?=?time?+?(RTC_TIMER_MAX_VALUE?-?time_curr);
????}?else?{
????????time_sleep?=?time?-?time_curr;
????}
????if?(?(time_sleep?>?(RTC_TIMER_MAX_VALUE?-?TMOS_TIME_VALID))?||?(time_sleep?<?SLEEP_RTC_MIN_TIME))?{
????????SYS_RecoverIrq(irq_status);
????????return;
????}
????/*?Ensure?it?is?still?ok?to?enter?the?sleep?mode.?*/
????eSleepStatus?=?eTaskConfirmSleepModeStatus();
????if(?eSleepStatus?==?eAbortSleep?)?{
????????SYS_RecoverIrq(irq_status);
????}
????else?{
????????if(?eSleepStatus?==?eNoTasksWaitingTimeout?)?{
????????????LowPower_Shutdown(0);
????????}
????????else?{
????????????R8_RTC_FLAG_CTRL?=?RB_RTC_TRIG_CLR;
????????????RTC_SetTignTime(time);
#if(DEBUG?==?Debug_UART1)?//?使用其他串口輸出打印信息需要修改這行代碼
??????????????while((R8_UART1_LSR?&?RB_LSR_TX_ALL_EMP)?==?0)?{
??????????????????__nop();
??????????????}
#endif
????????????//?LOW?POWER-sleep模式
????????????if(!(R8_RTC_FLAG_CTRL?&?RB_RTC_TRIG_FLAG))?{
????????????????LowPower_Sleep_Event(RB_PWR_RAM2K?|?RB_PWR_RAM30K?|?RB_PWR_EXTEND);
????????????????if(R8_RTC_FLAG_CTRL?&?RB_RTC_TRIG_FLAG)?{?//?注意如果使用了RTC以外的喚醒方式,需要注意此時32M晶振未穩(wěn)定
????????????????????R8_RTC_FLAG_CTRL?=?RB_RTC_TRIG_CLR;
????????????????????time?+=?WAKE_UP_RTC_MAX_TIME;
????????????????????if(time?>?0xA8C00000)?{
????????????????????????time?-=?0xA8C00000;
????????????????????}
????????????????????RTC_SetTignTime(time);
????????????????????LowPower_Idle_Event();
????????????????????R8_RTC_FLAG_CTRL?=?RB_RTC_TRIG_CLR;
????????????????}
????????????????HSECFG_Current(HSE_RCur_100);?//?降為額定電流(低功耗函數(shù)中提升了HSE偏置電流)
????????????????SysTick->CNT?=?sysTick_cnt;???//?恢復SysTick計數(shù)
????????????????//?恢復SysTick配置
????????????????PFIC_SetPriority(SWI_IRQn,?0xf0);
????????????????PFIC_SetPriority(SysTick_IRQn,?0xf0);
????????????????SysTick->CMP?=?(configCPU_CLOCK_HZ?/?configTICK_RATE_HZ)?-?1;?/*?set?reload?register?*/
????????????????SysTick->CTLR?=?SysTick_CTLR_INIT?|
????????????????????????????????SysTick_CTLR_STRE?|
????????????????????????????????SysTick_CTLR_STCLK?|
????????????????????????????????SysTick_CTLR_STIE?|
????????????????????????????????SysTick_CTLR_STE;
????????????}
????????????else?{
????????????????R8_RTC_FLAG_CTRL?=?RB_RTC_TRIG_CLR;
????????????}
????????????ulLowPowerTimeAfterSleep?=?RTC_GetCycle32k();
????????????if?(ulLowPowerTimeAfterSleep?<?ulLowPowerTimeBeforeSleep)?{
????????????????ulLowPowerTimeTotalSleep?=?ulLowPowerTimeAfterSleep?+?(RTC_TIMER_MAX_VALUE?-?ulLowPowerTimeBeforeSleep);
????????????}
????????????else?{
????????????????ulLowPowerTimeTotalSleep?=?ulLowPowerTimeAfterSleep?-?ulLowPowerTimeBeforeSleep;
????????????}
????????????ulLowPowerTimeTotalSleep?=?ulLowPowerTimeTotalSleep?*?(configTICK_RATE_HZ?/?32768.0);
????????????vTaskStepTick(?ulLowPowerTimeTotalSleep?);
????????}
????????SYS_RecoverIrq(irq_status);
????}
#endif
}



只有登錄才能回復,可以選擇微信賬號登錄

国产91精品新入口,国产成人综合网在线播放,九热这里只有精品,本道在线观看,美女视频a美女视频,韩国美女激情视频,日本美女pvp视频