This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How to close UART to save power for nRF52810

Hi,

I'm using SDK v14.2 and s112_5.1.0 for nRF52810 basing on the ble_app_uart example. Now we use the uart to communicate with external MCU. Also we want to close uart to save power when there is no data transmitting. I have used the BSP module to configure a gpio to control the UART, enable the UART when the gpio level is low, disable the UART when the gpio level is high. But if I enabled or disable UART in the bsp_event_handler, it couldn't be successful and it would stop running. Is there any problem with the function? Could you give me some advice how to do is better?

Enabled UART:

void app_uart_open(void){
uint32_t                     err_code;
const app_uart_comm_params_t  comm_params =
{
    .rx_pin_no    = RX_PIN_NUMBER,
    .tx_pin_no    = TX_PIN_NUMBER,
    .rts_pin_no   = RTS_PIN_NUMBER,
    .cts_pin_no   = CTS_PIN_NUMBER,
    .flow_control = APP_UART_FLOW_CONTROL_DISABLED,
    .use_parity   = false,
    .baud_rate    = UARTE_BAUDRATE_BAUDRATE_Baud9600
};

APP_UART_FIFO_INIT(&comm_params,
                   UART_RX_BUF_SIZE,
                   UART_TX_BUF_SIZE,
                   uart_event_handle,
                   APP_IRQ_PRIORITY_LOWEST,
                   err_code);
APP_ERROR_CHECK(err_code);}

Disabled UART:

uint32_t app_uart_close(void){
nrf_drv_uart_uninit(&app_uart_inst);
return NRF_SUCCESS;}

BSP event:

void bsp_event_handler(bsp_event_t event){
switch (event)
{
    case BSP_EVENT_UART_SLEEP:			
	app_uart_close();									
        break;

    case BSP_EVENT_UART_WORK:
    app_uart_open();																							
        break;
}}
Parents
  • Are you using the logger module with UART as backend and without deferred logging? It could be a problem related to my comment from January 11th here. nrf_drv_uart_uninit () is trying to print messages to the logger module, and if you do this over UART I figure that you might get stuck if you call it from the interrupt context of the bsp_event_handler. app_uart_open() will also end up in an error handler if you try to call it more than once without successfully calling nrf_drv_uart_uninit() in between. It could help to either:

    1. Increase the interrupt priority of the UART to e.g. APP_IRQ_PRIORITY_HIGH.
    2. Move your calls to app_uart_close() and app_uart_open() into your maint context.
    3. Use deferred logging and flush the message with NRF_LOG_FLUSH() in your main context. Logger documentation.
Reply
  • Are you using the logger module with UART as backend and without deferred logging? It could be a problem related to my comment from January 11th here. nrf_drv_uart_uninit () is trying to print messages to the logger module, and if you do this over UART I figure that you might get stuck if you call it from the interrupt context of the bsp_event_handler. app_uart_open() will also end up in an error handler if you try to call it more than once without successfully calling nrf_drv_uart_uninit() in between. It could help to either:

    1. Increase the interrupt priority of the UART to e.g. APP_IRQ_PRIORITY_HIGH.
    2. Move your calls to app_uart_close() and app_uart_open() into your maint context.
    3. Use deferred logging and flush the message with NRF_LOG_FLUSH() in your main context. Logger documentation.
Children
  • Hi Martin, I'm not sure I have got what you mean. Firstly, I have increase the interrupt priority of the UART to APP_IRQ_PRIORITY_HIGH. Then I have a global variable uart_status. I set uart_status=1 in the BSP_EVENT_UART_SLEEP event while uart_status=2 in the BSP_EVENT_UART_WORk event. The two dunction app_uart_close() and app_uart_open() would be called in the main context and NRF_LOG_FLUSH() also would be called before enable or disable the UART as follow:

    static uint8_t uart_status = 0;
    void handle_uart_sta(void){
    	switch(uart_status)
    	{
    		case 1:
    						uart_status = 0;
    						NRF_LOG_FLUSH();
    						app_uart_close();
    		break;
    		case 2:
    						uart_status = 0;
    						NRF_LOG_FLUSH();							
    		        app_uart_open();
    		break;				}		}
    

    In the main context:

        for (;;){
        UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
        power_manage();
        handle_uart_sta();
       }
    

    However, the problem have not been solved.

  • It seems like you have done what I was thinking.

    Can you try to declare uart_status as 'volatile'?

    Have you tried debugging by the way? Do you know where things stop?

  • I have declared uart_status as 'volatile'. Also I use NRF_UARTE0->ENABLE = 8; and NRF_UARTE0->ENABLE = 0; to instead of app_uart_open() and app_uart_close(). I could see the current and it's 2.6uA when disable UART while it's about 650uA when enabled UART. UART could send data after it's enabled. But once use PC to send the UART more than two times, it would get stuck and stop running at the app_error_fault_handler function. That's to say, UART couldn't receive any data after enabled. Could you help me have a test on the ble_app_uart example? Thanks very much.

    This link text is my complete project. I use P0.31 to generate the high or low level to enabled or disable UART.

  • Can you give me a step-by-step instruction showing what I should do to reproduce your problem?

  • You could flash it to nRF52810 then it would runs and it would print "Application start" through UART. After that, you could give a high or low level by hand to P0.31. This should work fine. If you use UART terminal on the PC to send data to nRF52810, then give a high or low level by hand, you could see the problem.

Related