在TMOS系统中手动管理休眠

目录

以CH58x、CH59x为例,使用电池供电的应用,多数会选用Sleep或Shutdown等级的休眠,那么至少要有RTC或是GPIO唤醒中的其中一种手段唤醒MCU(BAT低电压唤醒取决于VIO33引脚上的电压,不是代码能够控制的,暂且排开)。

在BLE代码中,为了让BLE协议栈能够在休眠期间及时唤醒发包,维持BLE的连接,一般是建议在BLE工程中启用HAL_SLEEP,让协议栈管理休眠,协议栈会利用RTC唤醒来安排低功耗;如果用户对逻辑把握准确,BLE使用频次不高,也是可以参考PM代码中的休眠,自行管理休眠的。

比如某个应用中,蓝牙MCU不需要循环工作,再等待外部信号时才需要工作,故不由RTC唤醒,只由外部GPIO信号唤醒;蓝牙MCU醒来后跑BLE,期间MCU全速工作不休眠,通信完后才休眠,等待下一次外部GPIO信号唤醒;要求MCU不能复位,RAM要保持供电。此时可以参考下方代码块安排休眠。

下列代码是测试时偷懒,在MCU.c的HAL_ProcessEvent中新增了事件,注意MCU.c是EVT公用文件,此处修改会影响其他工程。

/*****其他事件*****/
if(events & HAL_TEST_EVENT)     //主循环、GPIO中断中的flag控制启用该事件
    {
        tmos_start_task(halTaskID, HAL_SLEEP_EVENT, MS1_TO_SYSTEM_TIME(2000));  // 模拟一定时间后sleep休眠

        uint8_t  initial_advertising_enable = FALSE;        //关广播
        GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initial_advertising_enable);

        tmos_stop_task(halTaskID, HAL_REG_INIT_EVENT);  //默认2分钟一次的校准先暂停
        //为了更好掌握代码逻辑,建议所有TMOS事件在此暂停,唤醒后再安排事件。

        return events ^ HAL_TEST_EVENT;
    }

    if(events & HAL_SLEEP_EVENT)    //MCU在此事件中休眠和唤醒,唤醒后立即校准RF,再开蓝牙广播
    {
        sys_safe_access_enable();
        R8_CK32K_CONFIG &= ~(RB_CLK_INT32K_PON | RB_CLK_XT32K_PON); //关闭32K晶振电源,更省电
        sys_safe_access_disable();

        LowPower_Sleep(RB_PWR_RAM24K | RB_PWR_RAM2K); //保留24+2K的SRAM的供电

        sys_safe_access_enable();
        R8_CK32K_CONFIG |= RB_CLK_INT32K_PON;       //32K电源打开,供TMOS系统使用
        sys_safe_access_disable();

        HSECFG_Current(HSE_RCur_100);                 // 降为额定电流(低功耗函数中提升了HSE偏置电流)

        DelayMs(5);     //这里建议给一定的延时,延时足够到下方的打印能正常就好
        PRINT("wake.. \n");

        tmos_set_event(halTaskID, HAL_REG_INIT_EVENT);      //先校准RF,再开广播
        tmos_start_task(halTaskID, HAL_ADV_START_EVENT, 80);

        return events ^ HAL_SLEEP_EVENT;
    }

    if(events & HAL_ADV_START_EVENT)    //唤醒且RC校准后开广播
    {
        uint8_t  initial_advertising_enable = TRUE;        //开广播
        GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initial_advertising_enable);
        return events ^ HAL_ADV_START_EVENT;
    }
/****其他事件***/

GPIO唤醒的代码可以直接参考PM中的配置,本次测试用了PB4作为唤醒引脚。

/********GPIO唤醒的配置,加在主函数初始化中********/
    GPIOB_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_PU);
    GPIOB_ITModeCfg(GPIO_Pin_4, GPIO_ITMode_FallEdge); // 下降沿唤醒
    PFIC_EnableIRQ(GPIO_B_IRQn);
    PWR_PeriphWakeUpCfg(ENABLE, RB_SLP_GPIO_WAKE, Long_Delay);
/******************************************/

/*********************************************************************
 * @fn      Main_Circulation
 *
 * @brief   主循环
 *
 * @return  none
 */
__HIGH_CODE
__attribute__((noinline))
void Main_Circulation()
{
    while(1)
    {
        TMOS_SystemProcess();
        if(flag_gpio_int){        //根据GPIO中置的标志变量来安排事件
            flag_gpio_int = 0;
            tmos_start_task(halTaskID, HAL_TEST_EVENT, 160);
            PRINT("main_flag\n");
        }
    }
}

/*********************************************************************
 * @fn      GPIOA_IRQHandler
 *
 * @brief   GPIOA中断函数
 *
 * @return  none
 */
__INTERRUPT
__HIGH_CODE
void GPIOB_IRQHandler(void)
{
    static uint8_t int_num = 0;    //按一下PB4休眠,再按一下唤醒

    GPIOB_ClearITFlagBit(GPIO_Pin_4);
    if(!int_num){
        flag_gpio_int = 1;    //置标志,主循环中查标志并安排事件
        int_num = 1;
    }
    else {
        int_num = 0;
    }
} 

 

posted @ 2023-08-31 15:36  JayWell  阅读(714)  评论(2编辑  收藏  举报