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

GPIOTE and SPI high power consumption on sleep

Hello everyone.

I am currently working on a device with some peripherals. I have SPI slaves and other sensors that I am monitoring using GPIOTE driver.

I noticed a consumption of 0.470mA while sleeping under the following circumstances:

  • Configure SPI1 as master using DMA
  • Make a simple exchange with the slave
  • Enable GPIOTE IN to detect an interrupt on a PIN
  • Go to sleep (sd_app_event_wait())
  • Use non deferred LOGs

Note that the residual consumption happens IF AND ONLY IF the exchange happens on SPI AND GPIOTE is enabled after this exchange. SPI code alone does not make that consumption to happen, neither that GPIOTE.

I am currently building a project to make it easier for you to reproduce so that I will share it here.

[EDIT] :

Here is a project code than can be placed in <SDK_root>/examples/peripheral

spi_and_gpiote.zip

To reproduce the issue:

  • flash a PCA10040 with the SPIS example (board A)
  • extract the zip file attached in the SDK, compile and/or load on another PCA10040 (board B)
  • Link both boards with SPI bus, connect respective PINs P0.03, P0.04, P0.28, P0.29 to one another
  • Cut the SB9 on the board B to hook current measures here
  • Start both boards: you will see no extra consumption
  • Push any button on the master board to trig the sent of a packet on SPI lines and watch the current rise and then lower to no less that 0.470uA

[/EDIT]

Configuration:

  • NRF52832
  • Softdevice S132
  • PCA10040 x2, consumption measured on the board that is the master, the second one runs the slave SPIS example from the SDK
  • SDK 12.1.0 (nRF5_SDK_12.1.0_0d23e2a)

Here is my current main:

int main(void)
{
    nrf_clock_lf_cfg_t clock_lf_cfg = NRF_CLOCK_LFCLKSRC;

    // Init GPIOTE driver
    APP_ERROR_CHECK(nrf_drv_gpiote_init());
    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_INFO("Start Silego BU project\r\n");
    // Initialize.
    APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false);

    // Initialize SoftDevice.
    SOFTDEVICE_HANDLER_INIT(&clock_lf_cfg, NULL);
    // - Buttons and leds
    buttons_leds_init();
    nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
    spi_config.ss_pin   = 29;
    spi_config.miso_pin = 28;
    spi_config.mosi_pin = 4;
    spi_config.sck_pin  = 3;
    APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler));

    // Exchange with SPI slave
    APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, m_tx_buf, m_length, m_rx_buf, m_length));

    #define PIN_TEST    23
    // Configure interrupt as rising edge...
    nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
    
    // ... and no pull action on the line
    in_config.pull = NRF_GPIO_PIN_PULLDOWN;
    //in_config.pull = NRF_GPIO_PIN_NOPULL;
    
    // Init GPIOTE with configuration on PINs
    APP_ERROR_CHECK(nrf_drv_gpiote_in_init(PIN_TEST, &in_config, silego_irq_handler));
    nrf_drv_gpiote_in_event_enable(PIN_TEST, true);

    // Enter main loop.
    for (;;)
    {
        NRF_LOG_DEBUG("EnterPWR MGT\r\n");
        APP_ERROR_CHECK(sd_app_evt_wait());
        NRF_LOG_DEBUG("Exit PWR MGT\r\n");
        LEDS_INVERT(BSP_LED_0);
    }
}
Parents
  • Just to elaborate

    See this question

    devzone.nordicsemi.com/.../

    Basically there is a problem with the nRF51 hardware, which requires the HF (16Mhz) oscillator to be running to in order for an interrupt on an individual pin to trigger an interrupt.

    So you need to use "Port mode" instead but calling

    GPIOTE_CONFIG_IN_SENSE_LOTOHI(false);
    

    This mode does not require the HF oscillator to run.

    However, in this mode, if you have more than on interrupt input pin, you need to read the value of the pin(s) inside the ISR to confirm which pin has caused the interrupt.

Reply
  • Just to elaborate

    See this question

    devzone.nordicsemi.com/.../

    Basically there is a problem with the nRF51 hardware, which requires the HF (16Mhz) oscillator to be running to in order for an interrupt on an individual pin to trigger an interrupt.

    So you need to use "Port mode" instead but calling

    GPIOTE_CONFIG_IN_SENSE_LOTOHI(false);
    

    This mode does not require the HF oscillator to run.

    However, in this mode, if you have more than on interrupt input pin, you need to read the value of the pin(s) inside the ISR to confirm which pin has caused the interrupt.

Children
  • Hello, thank you for your answer but I do not use nRF51 but nRF52. Is this hardware bug still present on this last chip? Moreover, if I am using GPIOTE alone I do not see any power consumption. It is really the combination of SPI and GPIOTE that causes the issue

  • AFIK the bug was fixed in the nRF52, but as it is such a small change to the code, I suggest you try it.

    If changing it does not fix the problem, there are several other options.

    1. Your SPI hardware is taking the power.
    2. Your SPI hardware is constantly generating interrupts.
    3. This problem is not actually related to the SPI
  • I highly doubt that the SPI hardware is at fault. I can reproduce the issue using PCA10040 and spis example as slave for SPI hardware. This example is just echoing back what I am sending and I am sending thing upon button push only. I don't believe that it is related to hardware but more as a combination of execution of the two drivers one after the other. Like SPI is activating an oscillator for clock generation and suspend its usage and then when GPIOTE comes into picture it uses it somehow and lives it running before going to sleep. I will try the port mode but I don't think that it will be a real solution for our whole system.

Related