This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Power save - UART disable

nrf52833, custom application based BLE Central Uart Project.

s140_nrf52_7.2.0

Our average Power use in the application is 1.5mAmps.  What is the proper way to manage the power

to the UART entering  power save(idle) mode?  And to restart the UART on wakeUp event?

Thanks,

Dan

void nrf_pwr_mgmt_run(void)
{
PWR_MGMT_FPU_SLEEP_PREPARE();
PWR_MGMT_SLEEP_LOCK_ACQUIRE();
PWR_MGMT_CPU_USAGE_MONITOR_SECTION_ENTER();
PWR_MGMT_DEBUG_PIN_SET();

// stop UART, and prepare IO for low power
// nrf_drv_uart_t tmp = NRF_DRV_UART_INSTANCE(0);
// nrf_drv_uart_uninit(&tmp);

// Wait for an event.
#ifdef SOFTDEVICE_PRESENT
if (nrf_sdh_is_enabled())
{
ret_code_t ret_code = sd_app_evt_wait();
ASSERT((ret_code == NRF_SUCCESS) || (ret_code == NRF_ERROR_SOFTDEVICE_NOT_ENABLED));
UNUSED_VARIABLE(ret_code);
}
else
#endif // SOFTDEVICE_PRESENT
{
// Wait for an event.
__WFE();
// Clear the internal event register.
__SEV();
__WFE();
}

// restart UART
uart_init();
PWR_MGMT_DEBUG_PIN_CLEAR();
PWR_MGMT_CPU_USAGE_MONITOR_SECTION_EXIT();
PWR_MGMT_SLEEP_LOCK_RELEASE();
}

  • Hi,

    If you're doing it that way then I would move the un initializing and re- initializing of the peripheral right outside of where nrf_pwr_mgtmt_run() is called, something like this:

    nrf_drv_uart_t tmp = NRF_DRV_UART_INSTANCE(0);
    nrf_drv_uart_uninit(&tmp);
    
    nrf_pwr_mgmt_run();
    
    uart_init();

    You might have to call the STOP task before un-initializing the module.

    regards

    Jared 

  • Hi Jared,

    thanks for the input.

    I am still having trouble getting the UART to re-initialize.  It does not restart?  Below is the code I am using to disable and restart the uart.

    After a restart, the PUT_Tx quickly fills and crashes.  It looks like the UART is not delivering any data and emptying the Tx fifo?

    /*******************************************************************************
    * Function Name : void cble_uart_deinit(void)
    * Description : de-init and power down the uart
    * Author : Dan P
    * Date : 02.23.2022
    * Input : None
    * Return : None
    *******************************************************************************/
    void cble_uart_init(void)
    {
    ret_code_t err_code;
    if (!s_initialized){

    app_uart_comm_params_t const comm_params =
    {
    .rx_pin_no = RX_PIN_NUMBER,
    .tx_pin_no = TX_PIN_NUMBER,
    .rts_pin_no = RTS_PIN_NUMBER, // assign as a gpio for use in low power control, assign to un-used pins.
    .cts_pin_no = CTS_PIN_NUMBER, // assign as a gpio for use in low power control, assign to un-used pins.
    .flow_control = APP_UART_FLOW_CONTROL_DISABLED,
    .use_parity = false,
    .baud_rate = UART_BAUDRATE_BAUDRATE_Baud115200
    };
    #if 0
    APP_UART_FIFO_INIT(&comm_params,
    UART_RX_BUF_SIZE,
    UART_TX_BUF_SIZE,
    uart_event_handler,
    APP_IRQ_PRIORITY_LOWEST,
    err_code);

    APP_ERROR_CHECK(err_code);
    #endif
    \
    buffers.rx_buf = rx_buf; \
    buffers.rx_buf_size = sizeof (rx_buf); \
    buffers.tx_buf = tx_buf; \
    buffers.tx_buf_size = sizeof (tx_buf); \
    err_code = app_uart_init(&comm_params, &buffers, uart_event_handle, APP_IRQ_PRIORITY_LOWEST); \
    APP_ERROR_CHECK(err_code);

    s_initialized = true;
    }
    }

    /*******************************************************************************
    * Function Name : void cble_uart_deinit(void)
    * Description : de-init and power down the uart
    * Author : Dan P
    * Date : 02.23.2022
    * Input : None
    * Return : None
    *******************************************************************************/
    void cble_uart_deinit(void)
    {
    if (s_initialized)
    {
    NRF_UARTE1->TASKS_STOPRX=1;
    NRF_UARTE1->TASKS_STOPTX=1;
    NRF_UARTE1->ENABLE=0;

    cble_uart_flush();
    app_uart_flush();
    cble_uart_close();

    *(volatile uint32_t *)0x40028FFC = 0; // Power down UARTE1
    *(volatile uint32_t *)0x40028FFC; //
    *(volatile uint32_t *)0x40028FFC = 1; // Power on UARTE1 so it is ready for next time

    s_initialized = false;
    }

    }

    Thanks,

    Dan

  • Hi Dan,

    1. Are you passing the correct uart event handler to the init function? In the #ifdef block you pass uart_event_handleR while to the init function you pass uart_event_handlE 
    2. You should wait for the peripheral to produce the TXSTOPPED event before proceeding after triggering the event. 
    3. Does cble_uart_close call app_uart_close()?

    regards

    Jared 

  • Hi Jared,

    I am still having a hard time getting the UART to restart after closing for sleep mode.  The UART works fine on initial power up nd only fails when it is closed during Idle periods.

    1.  To close the uart,  idle_state_handle(void), calls the cble_uart_deinit() before power management is run.

    cble_uart_deinit(void)

    If I dont call this, it works.

    /**@brief Function for handling the idle state (main loop).
     *
     * @details Handles any pending log operations, then sleeps until the next event occurs.
     */
    static void idle_state_handle(void)
    {
        if (NRF_LOG_PROCESS() == false)
        {
            cble_uart_deinit();
          
            // watchdog & failsafe state management
            nrf_pwr_mgmt_run();
        
            cble_uart_init();
            //NRF_LOG_INFO("RE-init UART");
        }
    }
    /*******************************************************************************
    *  Function Name  : uint32_t cble_uart_close(void)
    *  Description    : de-init and power down the uart 
    *  Author         : Dan P
    *  Date           : 02.23.2022
    *  Input          : None
    *  Return         : None
    *******************************************************************************/
    uint32_t cble_uart_close(void)
    {
        nrf_drv_uart_tx_abort(&cble_uart_inst);//cble_uart_inst);app_uart_inst
        nrf_drv_uart_rx_abort(&cble_uart_inst);//cble_uart_inst);app_uart_inst
        nrf_drv_uart_uninit(&cble_uart_inst);//cble_uart_inst);app_uart_inst
        s_initialized = false;
        return NRF_SUCCESS;
    }
    
    /*******************************************************************************
    *  Function Name  : void cble_uart_deinit(void)
    *  Description    : de-init and power down the uart 
    *  Author         : Dan P
    *  Date           : 02.23.2022
    *  Input          : None
    *  Return         : None
    *******************************************************************************/
    void cble_uart_init(void)
    {
        ret_code_t err_code;
        if (!s_initialized){
    
        app_uart_comm_params_t const comm_params =
        {
            .rx_pin_no    = RX_PIN_NUMBER,
            .tx_pin_no    = TX_PIN_NUMBER,
            .rts_pin_no   = RTS_PIN_NUMBER,  // assign as a gpio for use in low power control, assign to un-used pins.
            .cts_pin_no   = CTS_PIN_NUMBER,  // assign as a gpio for use in low power control, assign to un-used pins.
            .flow_control = APP_UART_FLOW_CONTROL_DISABLED,
            .use_parity   = false,
            .baud_rate    = UART_BAUDRATE_BAUDRATE_Baud115200
        };
    //#if 0
    //    APP_UART_FIFO_INIT(&comm_params,
    //                       UART_RX_BUF_SIZE,
    //                       UART_TX_BUF_SIZE,
    //                       uart_event_handler,
    //                       APP_IRQ_PRIORITY_LOWEST,
    //                       err_code);
    //
    //    APP_ERROR_CHECK(err_code);
    //#endif 
                                                                                                                         \
        buffers.rx_buf      = rx_buf;                                                              \
        buffers.rx_buf_size = sizeof (rx_buf);                                                     \
        buffers.tx_buf      = tx_buf;                                                              \
        buffers.tx_buf_size = sizeof (tx_buf);                                                     \
        err_code = app_uart_init(&comm_params, &buffers, uart_event_handle, APP_IRQ_PRIORITY_LOWEST);                  \
        APP_ERROR_CHECK(err_code);
        
    //    NRF_UARTE0->TASKS_STARTRX=1;
    //    NRF_UARTE0->TASKS_STARTTX=1;
    //    NRF_UARTE0->ENABLE=1;
        nrf_uarte_enable(NRF_UARTE1);
        NRF_UARTE1->TASKS_STARTRX=1;
        NRF_UARTE1->TASKS_STARTTX=1;
        NRF_UARTE1->ENABLE=1;
        nrf_uarte_enable(NRF_UARTE1);
         nrf_drv_uart_rx_enable(&cble_uart_inst);
        s_initialized = true;
    
    
        }
    }
    
    /*******************************************************************************
    *  Function Name  : void cble_uart_deinit(void)
    *  Description    : de-init and power down the uart 
    *  Author         : Dan P
    *  Date           : 02.23.2022
    *  Input          : None
    *  Return         : None
    *******************************************************************************/
    void cble_uart_deinit(void)
    {
        if (s_initialized)
        {
      //  NRF_UARTE0->TASKS_STOPRX=1;
      //    NRF_UARTE0->TASKS_STOPTX=1;
      //   NRF_UARTE0->ENABLE=0;
         
        NRF_UARTE1->TASKS_STOPRX=1;
        NRF_UARTE1->TASKS_STOPTX=1;
        NRF_UARTE1->ENABLE=0;
          
          cble_uart_flush();
          app_uart_flush();
          cble_uart_close();
          
     //UARTE0
    //       *(volatile uint32_t *)0x40002FFC = 0;
    //       *(volatile uint32_t *)0x40002FFC;
    //       *(volatile uint32_t *)0x40002FFC = 1;
    
    //UARTE1
        *(volatile uint32_t *)0x40028FFC = 0; // Power down UARTE1
        *(volatile uint32_t *)0x40028FFC;     //
        *(volatile uint32_t *)0x40028FFC = 1; // Power on UARTE1 so it is ready for next time
    
            s_initialized = false;
        }
    
    }

  • Hi Dan,

    Is the idle_state_handle() called in the main loop as in our examples? If so, then this is problematic as any interrupt would cause the program to wake-up and re-init the UART + endless calls to cble_uart_deinit from the main loop.

    If you're using the Softdevice then interrupts happen quite often in the program. This will cause multiple init and de-init routines to be scheduled and I guess the MCU isn't able to keep up. 

    Instead, try only initializing and de-initialize the UART peripheral before and after you're sending/receiving data. 

    regards
    Jared 

Related