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

About implementing Errata 89

Hello,

I am using the SPIM module to communicate the NRF52832 with a sensor, every time it generates an interrupt - which is generated with a frequency of 25Hz. For the interruption I am using the GPIOTE. Between the sensor readings, when an interrupt is generated, I put the microcontroller in sleep mode with sd_app_evt_wait. The problem is that I have a much higher consumption than expected, since there are consumption peaks of around 400uA. I have already checked the pull of the MISO pin and disabled everything that was possible possible to isolate the problem.

So, I figured it would probably be related to Errata 89, but I had doubts when implementing the workarround.

#define SPI_INSTANCE  2                                                

static const nrf_drv_spi_t hspi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);   
static volatile bool spi_xfer_done = 0;

void spi_event_handler(nrf_drv_spi_evt_t const * p_event,
                       void *                    p_context)
{
    spi_xfer_done = true;
}

void spi_init(void)
{
    nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
    
    APP_ERROR_CHECK(nrf_drv_spi_init(&hspi, &spi_config, spi_event_handler, NULL));
    
    nrf_drv_spi_uninit(&hspi); 
    
    *(volatile uint32_t *)0x40023FFC = 0;
    *(volatile uint32_t *)0x40023FFC;
    *(volatile uint32_t *)0x40023FFC = 1;
    
    nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
    
    APP_ERROR_CHECK(nrf_drv_spi_init(&hspi, &spi_config, spi_event_handler, NULL));
}

void spi_read(void)
{
    spi_xfer_done = false;
    nrf_drv_spi_transfer(&hspi, spi.buff, 0, spi.buff, spi.size);
    while (!spi_xfer_done);
}


void spi_write(void)
{
    spi_xfer_done = false;
    nrf_drv_spi_transfer(&hspi, spi.buff, spi.size, spi.buff, 0);
    while (!spi_xfer_done);
}

void spi_write_read(uint8_t *pTxData, uint8_t *pRxData, uint16_t Size)
{
    spi_xfer_done = false;
    nrf_drv_spi_transfer(&hspi, pTxData, Size, pRxData, Size);
    while (!spi_xfer_done);
}

Is initializing SPI this way enough for the workarround to work?

Beside that, I tried to use just the SPI, without the DMA. But it also didn't reduce the consume.  Is it expected? 

Parents
  • Hi,

    I'm not sure if errata 89 is relevant here if you only see peeks at 400 uA. This errata normally gives a static and constant current draw of 400 uA, event after uninitializing the serial interfaces. I'm also not sure if the workaround will have any effect if you initialize the serial peripheral right after the uninitialization again. 

    Could you post a graph of the current consumption if you have this available? If you could also post your full project, that would help us determine what could cause the excessive current draw.

    Best regards,
    Jørgen

Reply
  • Hi,

    I'm not sure if errata 89 is relevant here if you only see peeks at 400 uA. This errata normally gives a static and constant current draw of 400 uA, event after uninitializing the serial interfaces. I'm also not sure if the workaround will have any effect if you initialize the serial peripheral right after the uninitialization again. 

    Could you post a graph of the current consumption if you have this available? If you could also post your full project, that would help us determine what could cause the excessive current draw.

    Best regards,
    Jørgen

Children
  • Hello, thanks for the reply!

    I managed to reproduce the behavior of Errata 89 and verified what you said, the consumption is static at around 400 uA, which is not my case.

    The graph of consumption follows, the resolution is not so good, but you can see that this consumption of 400uA occurs in peaks. I also put a graph with a sign that indicates when the CPU is on (high) and when it is in sleep (low) together with the SPI clock signal. Thus, I understand that consumption peaks only happen when the sensor is read. When I remove the reading from the accelerometer, the consumption is static at 10uA, which is expected by the consumption of the sensor when it is turned on.


    (Each mark on the time axis is one second)



    (zoomed)


    In addition, here is the relevant part of the code that was missing. If I comment this line "bsp_accel_read(& accel_array);", the consumption goes to the expected and the consumption peaks disappear. So, I believe it is related to SPI.


    void setup(void) 
    {
        log_init();
        uint32_t err_code = NRF_SUCCESS;
        err_code          = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
    
        app_timer_init();
        bsp_ble_stack_init();
    
        spi_init();
        i2c_init();
        i2c2_init();
    
        bsp_init();
        bsp_light_sensor_power_down();
        bsp_light_sensor2_power_down();
        i2c_disable();
        i2c2_disable();
        flash_power_down();
    
        rtc_init();
        rtc_set_time(calendar_to_epoch(&time_init));
    }
    
    uint8_t LIS3DH_FastReadReg(uint8_t Reg, uint8_t pRxData[])
    {
    	uint8_t tx_data[10] = {Reg | BIT_7 | BIT_6, 0,0,0,0,0,0,0,0,0};
            bsp_gpio_accel_cs_low();
            spi_write_read(tx_data, pRxData, 7);
            bsp_gpio_accel_cs_high();
    }
    
    __inline static void bsp_accel_read(int16_t array[])
    { 
    	uint8_t sub_array[10];
    	LIS3DH_FastReadReg(LIS3DH_OUT_X_L, sub_array);
    
    	array[0] = (((int16_t)sub_array[1]) | (int16_t)(sub_array[2]<<8));
    	array[1] = (((int16_t)sub_array[3]) | (int16_t)(sub_array[4]<<8));
    	array[2] = (((int16_t)sub_array[5]) | (int16_t)(sub_array[6]<<8));
    }
    
    void loop(void) 
    {  
      bsp_gpio_state_high();
    
      if (bsp_accel_get_irq_flag()) {
        bsp_accel_clear_irq_flag();
        bsp_accel_read(&accel_array);
      }
    
        // Power Management 
       __set_FPSCR(__get_FPSCR() & ~(FPU_EXCEPTION_MASK));      
       (void) __get_FPSCR();
       NVIC_ClearPendingIRQ(FPU_IRQn);
       bsp_gpio_state_low();
       APP_ERROR_CHECK(sd_app_evt_wait());
    }
    
    int main(void)
    
    {
        setup();
        
        bsp_print_log("Starting system's tasks\n");
    
        while (1) 
        {
            loop();
        }
    }

  • I guess this is because you keep the CPU awake while you wait for the SPI transfer to finish. Try replacing while (!spi_xfer_done) in spi_write_read(), etc., with the following:

    while (!spi_xfer_done)
    {
        __WFE();
    }

    This will put the CPU in sleep mode while the transfer completes. When the transfer is completed, the CPU will be woken by the interrupt from the SPI peripheral.

Related