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

nRF52840 UART0 sleep current behavior

I have a custom board built around the nRF52840, which spends most of its life sleeping.  I'm able to achieve ~3uA current draw when it is sleeping, but I've recently started running into corner cases where the current draw is much higher.  I suspect that it is an issue with UART0.

As a specific example, if I disable UART0 and the other peripherals before going to sleep, I hit 3uA.  However, if I transmit on the UART just before disabling it, I see ~620uA of current in sleep.  Waiting on nrfx_uarte_tx_in_progress() and using delays does not seem to resolve the issue.

Here's a stripped down version of my code.  The "printf("Going to sleep...\r\n");" is the offending line.  If I comment that out, the sleep current is ok.  Any idea how to fix this?

int main(void)
{
    int32_t r;
    
    // Initialize HW peripherals
    r = HWC_UartInit();
    if(r) SC_printf("HWC_UartInit: failed to initialize (%i)\r\n", r);
    
    printf("Going to sleep...\r\n");

    // Uninitialize UART
    HWC_UartDeinit();
      
    __SEV();    // Send an event (guarantees an event is set)
    __WFE();    // Will wake up immediately, clearing the event
    __WFE();    // This will put the device to sleep for realzies

    // Reinitialize the UART
    HWC_UartInit();
    
    SC_printf("Awake again...\r\n");
        
    while(1);
}

int32_t HWC_UartInit()
{
    nrfx_uarte_config_t uartConfig = NRFX_UARTE_DEFAULT_CONFIG;

    uartConfig.pseltxd = PIN_UART_TX;
    uartConfig.pselrxd = PIN_UART_RX;
    uartConfig.hwfc = NRF_UARTE_HWFC_DISABLED;
    uartConfig.parity = NRF_UARTE_PARITY_EXCLUDED;
    uartConfig.baudrate = NRF_UARTE_BAUDRATE_115200;
    
    nrfx_err_t e = nrfx_uarte_init(&uartInstance, &uartConfig, HWC_UartEventHandle);
    if(NRFX_SUCCESS==e) e = nrfx_uarte_rx(&uartInstance, &rxByte, 1);
    
    return NRFX_SUCCESS == e ? 0 : -1;
}

void HWC_UartDeinit()
{
    nrfx_uarte_rx_abort(&uartInstance);
    nrfx_uarte_uninit(&uartInstance);
    
    // Need to restart UARTE0 to reduce power.  This may be related to an erratum.
    // devzone.nordicsemi.com/.../184882
    *(volatile uint32_t *)0x40002FFC = 0;
    *(volatile uint32_t *)0x40002FFC;
    *(volatile uint32_t *)0x40002FFC = 1;
}

Parents Reply Children
  • Thanks for your feedback.  I tried the TX and RX abort suggestions, but they did not work.  I can also confirm that I'm using UART0.

    I've been struggling to be able to consistently repeat the issue, and I think I might have landed on a way to reproduce.  The key seems to be tied to using the bootloader with a soft device.  Using the setup and code described below, I've found that the ~620uA issue appears when I'm both using the bootloader AND printing to the UART before sleep.  If I remove the UART printf OR ditch the bootloader and load the app directly to address 0x00, then the sleep current is ~3uA.

    Here's my hardware setup:

    • nRF52840 USB dongle
    • SB1 jumpered
    • SB2 cut
    • 3.0V applied to VDD_nRF
    • UART TX - P0.26
    • UART RX - P0.22

    Software setup:

    • 15.3 SDK
    • Using example bootloader: secure_bootloader_ble_s140_pca10056 - nrf52840_xxaa_s140
    • Loading S140 soft device
    • IAR 8.40, full optimization
    • Loading code at address 0x26000
    • All code contained in main.c:

    #include <stdbool.h>
    #include <stdint.h>
    #include <string.h>
    #include <stdlib.h>
    
    #include "nordic_common.h"
    #include "nrf_gpio.h"
    #include "nrfx.h"
    #include "nrfx_clock.h"
    #include "nrfx_uarte.h"
    #include "nrfx_systick.h"
    
    #define PIN_UART_TX         NRF_GPIO_PIN_MAP(0,26)
    #define PIN_UART_RX         NRF_GPIO_PIN_MAP(0,22)
    
    uint8_t rxByte;
    nrfx_uarte_t uartInstance = NRFX_UARTE_INSTANCE(0);
    
    int fputc(int ch, FILE *f)
    {
        while(nrfx_uarte_tx_in_progress(&uartInstance)); 
        nrfx_uarte_tx(&uartInstance, (uint8_t *)&ch, 1);
        return ch;
    }
    
    static void ClockEventHandler(nrfx_clock_evt_type_t event)
    {
        
    }
    
    static void UartEventHandler(nrfx_uarte_event_t const * p_event, void *p_context)
    {
        if(NRFX_UARTE_EVT_RX_DONE == p_event->type) {
            nrfx_uarte_rx(&uartInstance, &rxByte, 1);
        } else if(NRFX_UARTE_EVT_TX_DONE == p_event->type) {
            // do nothing
        } else if(NRFX_UARTE_EVT_ERROR == p_event->type) {
            nrfx_uarte_rx(&uartInstance, &rxByte, 1);
        }
    }
    
    void ClockInit()
    {
        nrfx_clock_enable();
        
        ret_code_t err_code = nrfx_clock_init(ClockEventHandler);
        ASSERT((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_MODULE_ALREADY_INITIALIZED));
    
        nrfx_clock_hfclk_start();
        while (!nrfx_clock_hfclk_is_running());
    
        nrfx_clock_lfclk_start();
        while (!nrfx_clock_lfclk_is_running());
        
        nrfx_systick_init();
    }
    
    int32_t UartInit()
    {
        nrfx_uarte_config_t uartConfig = NRFX_UARTE_DEFAULT_CONFIG;
    
        uartConfig.pseltxd = PIN_UART_TX;
        uartConfig.pselrxd = PIN_UART_RX;
        uartConfig.hwfc = NRF_UARTE_HWFC_DISABLED;
        uartConfig.parity = NRF_UARTE_PARITY_EXCLUDED;
        uartConfig.baudrate = NRF_UARTE_BAUDRATE_115200;
        
        nrfx_err_t e = nrfx_uarte_init(&uartInstance, &uartConfig, UartEventHandler);
        if(NRFX_SUCCESS==e) e = nrfx_uarte_rx(&uartInstance, &rxByte, 1);
        
        return NRFX_SUCCESS == e ? 0 : -1; 
    }
    
    void UartDeinit()
    {
        nrfx_uarte_rx_abort(&uartInstance);
        nrfx_uarte_uninit(&uartInstance);
        
        *(volatile uint32_t *)0x40002FFC = 0;
        *(volatile uint32_t *)0x40002FFC;
        *(volatile uint32_t *)0x40002FFC = 1;
    }
    
    
    int main(void)
    {
        UartInit();
    
        // Commenting out these 4 lines fixes the sleep current issue
        printf("Going to sleep...\r\n");
        while(nrfx_uarte_tx_in_progress(&uartInstance)); 
        nrfx_uarte_tx_abort(&uartInstance);
        nrfx_uarte_rx_abort(&uartInstance);
        
        UartDeinit();
        
        __SEV();
        __WFE();
        __WFE();
        
        UartInit();
        
        printf("Awake again!\r\n");
            
        while(1);
    }
    
    
    
    

Related