bouffalolab / bouffalo_sdk

BouffaloSDK is the IOT and MCU software development kit provided by the Bouffalo Lab Team, supports all the series of Bouffalo chips. Also it is the combination of bl_mcu_sdk and bl_iot_sdk
Apache License 2.0
349 stars 123 forks source link

deep sleep example #160

Closed beckmx closed 5 months ago

beckmx commented 1 year ago

hello @sakumisue, would you help me with an example for deep sleep mode? i was browsing the code but i dont find enough information on the sdk to invoke it

thanx a lot!

beckmx commented 1 year ago

I tested a BLE example but it drains the battery in 5 hours, a 3.7v 1200mah

Jatsekku commented 12 months ago

@beckmx Which MCU are you targgeting? I spent some time tinkering with hibernate core on BL702 so maybe I will be able to help

beckmx commented 12 months ago

I am using the bl616

Jatsekku commented 12 months ago

Okey, but maybe the HBN core is same or at least very similar to BL702's. Could you explain in details what problems are you facing and/or what are you trying to achieve?

beckmx commented 12 months ago

Sure, specifically talking about deep sleep i haven’t done anything really, but I created a BLE beacon which I want to deep sleep after broadcasting its bluetooth signal, should be the simplest way I believe

Jatsekku commented 12 months ago

Okey, by basing on sources from diffrent versions of SDKs (bl_iot_sdk and bl_mcu_sdk). I was able to enter deep sleep in this way (it's almost original version from bl_mcu_sdk v 1.45 if i remmber correctly):

`ATTR_TCM_SECTION void hibernate_enter(enum hibernateLevel hibernate_level) { uint32_t tmpVal;

/* disable interrupts */
portDISABLE_INTERRUPTS();

/* disable 32kHz clock*/
if (hibernate_level >= HIBERNATE_LEVEL_2)
    HBN_Power_Off_RC32K();
else
    HBN_Power_On_RC32K();

HBN_Power_Down_Flash(NULL);
/* SF io select from efuse value */
uint32_t flash_select = BL_RD_WORD(0x40007074);
if (((flash_select >> 26) & 7) == 0) {
    HBN_Set_Pad_23_28_Pullup();
}

/* Select RC32M */
GLB_Set_System_CLK(GLB_DLL_XTAL_NONE, GLB_SYS_CLK_RC32M);

/* power off xtal */
AON_Power_Off_XTAL();
GLB_Power_Off_DLL();
PDS_Power_Off_PLL();

/* HBN mode LDO level */
tmpVal = BL_RD_REG(HBN_BASE, HBN_CTL);
tmpVal = BL_SET_REG_BITS_VAL(tmpVal, HBN_LDO11_AON_VOUT_SEL, PM_HBN_LDO_LEVEL_DEFAULT);
tmpVal = BL_SET_REG_BITS_VAL(tmpVal, HBN_LDO11_RT_VOUT_SEL, PM_HBN_LDO_LEVEL_DEFAULT);
BL_WR_REG(HBN_BASE, HBN_CTL, tmpVal);

/* Set HBN flag */
BL_WR_REG(HBN_BASE, HBN_RSV0, HBN_STATUS_ENTER_FLAG);

tmpVal = BL_RD_REG(HBN_BASE, HBN_CTL);

/* Set HBN level, (HBN_PWRDN_HBN_RAM not use) */
switch (hibernate_level) {
    case HIBERNATE_LEVEL_0:
        tmpVal = BL_CLR_REG_BIT(tmpVal, HBN_PWRDN_HBN_CORE);
        tmpVal = BL_CLR_REG_BIT(tmpVal, HBN_PWRDN_HBN_RTC);
        break;

    case HIBERNATE_LEVEL_1:
        tmpVal = BL_SET_REG_BIT(tmpVal, HBN_PWRDN_HBN_CORE);
        tmpVal = BL_CLR_REG_BIT(tmpVal, HBN_PWRDN_HBN_RTC);
        break;

    case HIBERNATE_LEVEL_2:
        tmpVal = BL_SET_REG_BIT(tmpVal, HBN_PWRDN_HBN_CORE);
        tmpVal = BL_SET_REG_BIT(tmpVal, HBN_PWRDN_HBN_RTC);
        break;

    default:
        break;
}

/* Set power on option:0 for por reset twice for robust 1 for reset only once*/
tmpVal = BL_CLR_REG_BIT(tmpVal, HBN_PWR_ON_OPTION);
BL_WR_REG(HBN_BASE, HBN_CTL, tmpVal);

*(volatile uint8_t *)(CLIC_HART0_ADDR + CLIC_INTIP + HBN_OUT0_IRQn) = 0;
*(volatile uint8_t *)(CLIC_HART0_ADDR + CLIC_INTIP + HBN_OUT1_IRQn) = 0;

BL_WR_REG(HBN_BASE, HBN_IRQ_CLR, 0xffffffff);
BL_WR_REG(HBN_BASE, HBN_IRQ_CLR, 0);

/* Enable HBN mode */
tmpVal = BL_RD_REG(HBN_BASE, HBN_CTL);
tmpVal = BL_SET_REG_BIT(tmpVal, HBN_MODE);
BL_WR_REG(HBN_BASE, HBN_CTL, tmpVal);

while (1) {
    GLB_SW_POR_Reset();
}

}`

What kind of wakeup source (GPIO/RTC/ACOMP etc) do you need in your application? Oh and I don't think you can rely on Boufallo team right now. They are quite unresponsive recently and when I was mailing with them some time ago, the customer service said they are having problems with insufficient work force.

Jatsekku commented 12 months ago

Now, when you search the current repo using HBN_BASE phrase, you will find this particular function: https://github.com/bouffalolab/bouffalo_sdk/blob/c1a6aa7c46bd12393d43b50e520f7cda19005c37/drivers/soc/bl616/std/include/bl616_pm.h#L40 and that should be your starting point ;)

In case of any problems, don't hesitate to ask ;)

beckmx commented 12 months ago

interesting... so i imported that header blb616_pm.h and used pm_hbn_mode_enter(PM_HBN_LEVEL_0,3000); in my code and compiled :0 i will try later with a real device :)

i guess, it's just like a blocking function if i understand it correctly? and then takes where it left? or resets the mcu? what was your experience there, i will post my results tomorrow

Jatsekku commented 12 months ago

In case of deep sleep, it disables most of peripherals and almost turning off the MCU (sleep_level defines how many of them will be disable, i.e. deepest one let you wake-up MCU only from particular set of GPIOs). it's resetting the MCU after wake-up, I'm using "ATTR_HBN_NOINIT_SECTION" macro to preserve some state between wake-ups. There are some options with jump to specific address after wake-up and ram retention as well but I didn't investigate this deep enough.

sakumisu commented 10 months ago

Right, just call these api will work for deep sleep with pds and hbn, if you use others like acomp or gpio, should do some other configurations. We will push code for you for reference.

beckmx commented 10 months ago

Thank you @sakumisu i am using Bluetooth so I am okay with an example to restart when it comes back from hbn

sakumisu commented 10 months ago

Have done

beckmx commented 10 months ago

I tried the RTC deep sleep and works wonderfully, i even could make it work with a cr2450, but it only worked once, but worked :)

JF002 commented 10 months ago

Hi @sakumisu ! I've just tried the new HBN and PDS examples. I tried hbn_rtc and pds_rtc. In both cases, the MCU seems to reset completely at wake up, after 1s.

However, if I understand correctly, PDS should allow to resume the execution of the firmware without a reset of the MCU, right? I tried changing the PDS level to lower values, but in those cases, the MCU would never wake up.

Would you like to explain the differences between HBN, PDS and the levels?

Thanks!

sakumisu commented 10 months ago

Hi @sakumisu ! I've just tried the new HBN and PDS examples. I tried hbn_rtc and pds_rtc. In both cases, the MCU seems to reset completely at wake up, after 1s.

However, if I understand correctly, PDS should allow to resume the execution of the firmware without a reset of the MCU, right? I tried changing the PDS level to lower values, but in those cases, the MCU would never wake up.

Would you like to explain the differences between HBN, PDS and the levels?

Thanks!

Only pds level 1 can run without reset, but level1 has high power dissipation, so we only suggest you to use pds15 in bl616.

Jatsekku commented 10 months ago

BTW, due to the fact that this thread is quite active, can we have a example with RAM retention?

JF002 commented 10 months ago

Only pds level 1 can run without reset, but level1 has high power dissipation, so we only suggest you to use pds15 in bl616.

What would be the power usage of the BL616 in PDS15 vs PDS1? And do I need to do anything special for the PDS1 mode to work? It doesn't seem to wake up at all in my tests.

sakumisu commented 10 months ago

BTW, due to the fact that this thread is quite active, can we have a example with RAM retention?

Can you describe more? Only variables in ram retention or other else?

sakumisu commented 10 months ago

Only pds level 1 can run without reset, but level1 has high power dissipation, so we only suggest you to use pds15 in bl616.

What would be the power usage of the BL616 in PDS15 vs PDS1? And do I need to do anything special for the PDS1 mode to work? It doesn't seem to wake up at all in my tests.

You should call pm_pds_irq_register before enter pds mode. See comments in Line 627.

beckmx commented 10 months ago

Hello @sakumisu I noticed something wierd with the latest commits, I have this BLE code acting as a beacon, I have a task that is putting the bl616 into hbn mode (following the examples), in this first set of commits where the examples were introduced, this code was restarting correctly, with the latest changes, it hangs when stopping bluetooth:

void go_hbn(void *pvParameters) {
    const TickType_t xDelay = 50 / portTICK_PERIOD_MS; 
 while (1) {
    //turning off advertising from zephyr
    vTaskDelay(xDelay);
    int ret = set_adv_enable(false);
    if (ret) {
        printf("Restart adv fail. \r\n");<-----looks like it fails here
    }
    vTaskDelay(xDelay);
    printf("Bluetooth turned off.\r\n");
    bt_disable();<----hangs here
    vTaskDelay(xDelay);
    printf("Going to sleep.\r\n");
    #if (PM_PDS_LDO_LEVEL_DEFAULT == 8)
    printf("Going to sleep_0.\r\n");
    printf("hbn_pattern:0x%08x\r\n",*((volatile uint32_t *)0x20010300));

    hal_pm_ldo11_use_ext_dcdc();

    bl_lp_hbn_init(0,0,1,0);
    bl_lp_hbn_enter(&hbn_test_cfg);
    #else
    printf("Going to sleep_1.\r\n");
        /* Wake up every 10 seconds by hb0 */
        pm_hbn_mode_enter(PM_HBN_LEVEL_0, 32768*180);
    #endif

  }
}

int main(void)
{
    board_init();
    configASSERT((configMAX_PRIORITIES > 4));

    uart0 = bflb_device_get_by_name("uart0");
    shell_init_with_task(uart0);
    printf("Configuring bt");
    btblecontroller_em_config();

    // /* Init rf */
    printf("Configuring RF");
    if (0 != rfparam_init(0, NULL, 0)) {
        printf("PHY RF init failed!\r\n");
        return 0;
    }
    printf("Configuring bt controller");
    btble_controller_init(configMAX_PRIORITIES - 1);
    hci_driver_init();
    bt_addr_le_t ble_addr = { BT_ADDR_LE_RANDOM, addr };
    bt_id_create(&ble_addr, NULL);
    bt_enable(bt_enable_cb);

    printf("Beacon started succesfully!");
    xTaskCreate(go_hbn, "go_hbn", 1024, NULL, 1, NULL);
    vTaskStartScheduler();
    // create a freertos task to repeat every 5 seconds
    while (1) {
        /* code */
    }

    return 0;
}