High Sleep Current (450ua) on NRF52 after starting SPI

10 Nov 2018

Hi

Having issue with high sleep current after starting SPI channel. If i start the SPI, read a sensor and then sleep using Thread::wait, i get unusually high sleep current, as if the high speed clock is still running.

Why is this, do i need to shut down the SPI first, and if so how do i do this as the SPI class has no function for this?

Same is also true with I2C.

Thanks

B

12 Nov 2018

Any input for this one, it seems many other are having the same issue....

04 Jan 2019

Hey,

I have faced a similar issue. I was using I2C and the sleep current wouldn't go below 400uA.

You can try calling this, before you go to sleep

Stop high frequency clock

NRF_CLOCK->TASKS_HFCLKSTOP = 1;

I was also uninitializing the I2C. The I2C class doesn't have any function for this, so I used the Nordic SDK function.

Disable I2C before sleep

nrf_drv_twi_disable(&nordic_nrf5_instance[0]);
    nrf_drv_twi_uninit(&nordic_nrf5_instance[0]);
   //  This is according to the device errata
    *(volatile uint32_t *)0x40003FFC = 0;
    *(volatile uint32_t *)0x40003FFC;
    *(volatile uint32_t *)0x40003FFC = 1;

You may need to change a little things in the Source code to get this working.

I wasn't using SPI in my project, so don't have much idea about that, but probably something like this can be done with SPI too.

04 Jan 2019

Hi Ashish

Thanks for this, but have tried and still end up with 450ua draw in sleep. :(

Only fix i can find is to system_reset() and then sleep, which is hacky as hell.

Do i just need to include #include "nrf_soc.h" to use those uninit calls?

04 Jan 2019

Ben S wrote:

Hi Ashish

Thanks for this, but have tried and still end up with 450ua draw in sleep. :(

Only fix i can find is to system_reset() and then sleep, which is hacky as hell.

Do i just need to include #include "nrf_soc.h" to use those uninit calls?

Hey Ben,

To use these uninit functions, you will have to do one small change inside the "i2c_api.c" file.

Inside you will find

static const nrf_drv_twi_t nordic_nrf5_instance[2] = { NRF_DRV_TWI_INSTANCE(0), NRF_DRV_TWI_INSTANCE(1) };

You will have to remove the static keyword, so that you can use these instances in your application. It should look like this.

const nrf_drv_twi_t nordic_nrf5_instance[2] = { NRF_DRV_TWI_INSTANCE(0), NRF_DRV_TWI_INSTANCE(1) };

Inside the main file, where you will call these uninit functions, make an extern variable .

extern const nrf_drv_twi_t nordic_nrf5_instance[2];

If you are using only one I2C instance in your application, you will most probably be using the instance 0. The uninit functions in the comment above will work then. In case you are using more I2C instances, then you will have to change to instance 1 in those functions. And in that case the three lines after that will change

    *(volatile uint32_t *)0x40004FFC = 0;
    *(volatile uint32_t *)0x40004FFC;
    *(volatile uint32_t *)0x40004FFC = 1;
04 Jan 2019

DigitalIn spi_pin1(PN_SPI_MOSI, PullNone); DigitalIn spi_pin2(PN_SPI_MISO, PullNone); DigitalIn spi_pin3(PN_SPI_CLK, PullNone); DigitalIn spi_pin4(PN_SPI_CS0, PullNone); DigitalIn spi_pin5(PN_SPI_CS1, PullNone);

This seems to do the trick at killing the 450ua if i do this before sleep.

04 Jan 2019

Ben S wrote:

DigitalIn spi_pin1(PN_SPI_MOSI, PullNone); DigitalIn spi_pin2(PN_SPI_MISO, PullNone); DigitalIn spi_pin3(PN_SPI_CLK, PullNone); DigitalIn spi_pin4(PN_SPI_CS0, PullNone); DigitalIn spi_pin5(PN_SPI_CS1, PullNone);

This seems to do the trick at killing the 450ua if i do this before sleep.

This is one of the things that the uninit function will do, reinitialising the GPIO pins.

04 Jan 2019

Ah I see that makes sense thank you.

On a similar subject, getting the same issue whenever I initialised the Serial, sleep current is blown out of the water, is there a similar fix for that?

04 Jan 2019

You can try by uninitializing the UART peripheral.

Look for "serial_api.c" file. Change the following line by removing the static keyword.

static NRF_UARTE_Type *nordic_nrf5_uart_register[UART_ENABLED_COUNT] = {
    NRF_UARTE0,
#if UART1_ENABLED
    NRF_UARTE1,
#endif
};

Then make an extern variable in the main.c file.

extern NRF_UARTE_Type *nordic_nrf5_uart_register[0];

Then call this uninit function.

    nrf_uarte_disable(nordic_nrf5_uart_register[0]);
    uart_pins_to_default(nordic_nrf5_uart_register[0]);

This is the implementation for the uart_pins_to_default function.

void uart_pins_to_default(NRF_UARTE_Type * p_reg)
{
    uint32_t txd;
    uint32_t rxd;
    uint32_t rts;
    uint32_t cts;

    txd = nrf_uarte_tx_pin_get(p_reg);
    rxd = nrf_uarte_rx_pin_get(p_reg);
    rts = nrf_uarte_rts_pin_get(p_reg);
    cts = nrf_uarte_cts_pin_get(p_reg);
    nrf_uarte_txrx_pins_disconnect(p_reg);
    nrf_uarte_hwfc_pins_disconnect(p_reg);

    if (txd != NRF_UARTE_PSEL_DISCONNECTED)
    {
        nrf_gpio_cfg_default(txd);
    }
    if (rxd != NRF_UARTE_PSEL_DISCONNECTED)
    {
        nrf_gpio_cfg_default(rxd);
    }
    if (cts != NRF_UARTE_PSEL_DISCONNECTED)
    {
        nrf_gpio_cfg_default(cts);
    }
    if (rts != NRF_UARTE_PSEL_DISCONNECTED)
    {
        nrf_gpio_cfg_default(rts);
    }
}

You may need to include this.

#include "nrf_drv_uart.h"

What this is doing is basically disabling the UARTE0 and then resetting the pins to their default state. Which is what the uninit function does.

I haven't tested this myself, but hopefully this should solve the problem.

08 Jan 2019

I need to use the online compiler (long story) so can't use that fix,

But what i can seem to do is manually configure the uart up and down, and get good results.

UP NRF_UART0->PSELTXD = PN_UART_TX; NRF_UART0->PSELRXD = PN_UART_RX; NRF_UART0->CONFIG = (UART_CONFIG_PARITY_Excluded << UART_CONFIG_PARITY_Pos) | UART_CONFIG_HWFC_Disabled; NRF_UART0->BAUDRATE = NRF_UARTE_BAUDRATE_115200; NRF_UART0->ENABLE = UART_ENABLE_ENABLE_Enabled; NRF_UART0->EVENTS_RXDRDY = 0x0UL; NRF_UART0->EVENTS_TXDRDY = 0x0UL; NRF_UART0->TASKS_STARTRX = 0x1UL; NRF_UART0->TASKS_STARTTX = 0x1UL; NRF_UART0->INTENSET = UART_INTENSET_RXDRDY_Msk; NVIC_ClearPendingIRQ(UART0_IRQn); NVIC_SetPriority(UART0_IRQn, 3); NVIC_EnableIRQ(UART0_IRQn);

DOWN NVIC_DisableIRQ(UART0_IRQn); NRF_UART0->INTENCLR = UART_INTENCLR_RXDRDY_Msk; NRF_UART0->TASKS_STOPRX = 0x1UL; NRF_UART0->TASKS_STOPTX = 0x1UL; NRF_UART0->ENABLE = UART_ENABLE_ENABLE_Disabled; NRF_UART0->PSELTXD = 0xFFFFFFFF; NRF_UART0->PSELRXD = 0xFFFFFFFF; NRF_UART0->PSELRTS = 0xFFFFFFFF; NRF_UART0->PSELCTS = 0xFFFFFFFF;

And this gives low 5ua sleep current at sleep. However it means I cannot use printf or scanf etc, i have to manual read or write to the buffers :(

11 Jan 2019

This is according to the device errata

  • (volatile uint32_t *)0x40003FFC = 0;
  • (volatile uint32_t *)0x40003FFC;
  • (volatile uint32_t *)0x40003FFC = 1;

saved the day for me. I am using offline exported make-gcc mbed project. Thank you. Peter

16 Apr 2019

This seems to fix the sleep problem.

  *(volatile uint32_t *)0x40003FFC = 0;
    *(volatile uint32_t *)0x40003FFC;
    *(volatile uint32_t *)0x40003FFC = 1;

But I don't have any idea how to reinitialize i2c to make it work again? Any ideas?