4 second current spikes during sleep

Hello All,

I am getting these ~3.5mA current spikes very 4 seconds and I can't seem to figure what the cause of them is. some of the spikes have a single spike/pulse while other have multiple. please see the attached images. I have commented out everything except the while in the main function and no difference. I have also commented out the enabling of the DCDC and still the same issue. any help would be greatly appreciate. I have a feeling its in the project config setting but tried commenting out what I thought may be the cause but no change either. 

I am using a custom board with 52833 and nRF Connect SDK 2.0.0. the board does have other ICs(hall sensors) but I measured their consumption and had no spikes.

while (1) {
		//k_sleep(K_SECONDS(1));
		//k_msleep(500);
		
		__WFE();
}

my project config file



#CONFIG_DK_LIBRARY=y

# Config logger
CONFIG_LOG=n
CONFIG_USE_SEGGER_RTT=n
CONFIG_LOG_BACKEND_RTT=n
CONFIG_LOG_BACKEND_UART=n
CONFIG_LOG_DEFAULT_LEVEL=3
CONFIG_DEBUG_OPTIMIZATIONS=n
# CONFIG_LOG_MODE_IMMEDIATE=n


CONFIG_SERIAL=n
CONFIG_CONSOLE=n
CONFIG_UART_CONSOLE=n

# Config Bluetooth
CONFIG_BT=y
##CONFIG_BT_DEBUG_LOG=y
##CONFIG_BT_SMP=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DIS=y
CONFIG_BT_DIS_PNP=n
# CONFIG_BT_BAS=y
# CONFIG_BT_HRS=y
CONFIG_BT_DEVICE_NAME="XXX Sensor"
CONFIG_BT_DEVICE_APPEARANCE=0
#CONFIG_BT_DEVICE_APPEARANCE=833
CONFIG_BT_LL_SOFTDEVICE=y
CONFIG_BT_MAX_CONN=1
CONFIG_BT_GAP_PERIPHERAL_PREF_PARAMS=y
CONFIG_BT_PERIPHERAL_PREF_MIN_INT=40
CONFIG_BT_PERIPHERAL_PREF_MAX_INT=45

CONFIG_BT_BUF_ACL_RX_SIZE=251
CONFIG_BT_BUF_ACL_TX_SIZE=251
CONFIG_BT_L2CAP_TX_MTU=247
CONFIG_BT_CTLR_DATA_LENGTH_MAX=251
CONFIG_BT_BUF_ACL_TX_COUNT=10



# CONFIG_CLOCK_CONTROL_NRF_FORCE_ALT=y wh
CONFIG_CLOCK_CONTROL_NRF=y
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y
CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=n
# CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL is not set
# CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH is not set
# CONFIG_CLOCK_CONTROL_NRF_K32SRC_EXT_LOW_SWING is not set
# CONFIG_CLOCK_CONTROL_NRF_K32SRC_EXT_FULL_SWING is not set
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC_CALIBRATION=y
CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_LF_ALWAYS_ON=y
CONFIG_CLOCK_CONTROL_NRF_K32SRC_500PPM=y
CONFIG_GPIO_AS_PINRESET=n


CONFIG_GPIO=y
CONFIG_GPIO_NRFX=y
CONFIG_NRFX_GPIOTE=y
CONFIG_SPI=y

#CONFIG_ASSERT=y

#CONFIG_NRFX_PRS_BOX_2=y

# CONFIG_NRFX_TIMER0=y
CONFIG_NRFX_TIMER1=y
CONFIG_NRFX_TIMER2=y
CONFIG_NRFX_TIMER3=y
CONFIG_NRFX_TIMER4=y
CONFIG_NRFX_PPI=y
CONFIG_NRFX_GPIOTE_NUM_OF_EVT_HANDLERS=2
CONFIG_NRFX_SPIM0=y
CONFIG_NRFX_SPIM1=y
CONFIG_COUNTER=y
#CONFIG_COUNTER_TIMER1=y


CONFIG_NRFX_RTC2=y
CONFIG_NRFX_POWER=y




##CONFIG_PM=y
# Required to disable default behavior of deep sleep on timeout
##CONFIG_PM_DEVICE=y
#CONFIG_GPIO=y
# Optional select RAM retention (nRF52 only)
#CONFIG_APP_RETENTION=y








Parents
  • Hello, 

    Please set CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_MAX_SKIP=0 and then try to adjust the  CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_PERIOD setting to see if it affects the interval of your current spike. The 2nd screenshot looks could be showing the clock calibration event (The 32K RC oscillator is calibrated periodically against the HF crystal oscillator). 

    Best regards,

    Vidar

  • Hi Vidar,

    That seems to be it. I set the following

    CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_MAX_SKIP=0
    CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_PERIOD=2000
    and period did change accordingly. please see plot.
    So with that said, I have few questions. 
    1) will an external 32kHz crystal use less power? or
    2) Since we know our device will be operating in a fairly temp controlled environment, what do you think would be wise settings to minimize power consumption but not get some egregious clock drift? 
    for example, do the cal every x number of deg change if possible. what do you think that x should be
    or do it every x seconds(what do you think that x should be)
    your help is greatly appreciated.
    Regards,
    Wael
  • Hi Wael,

    Wael said:
    1) will an external 32kHz crystal use less power? or

    The internal RC oscillator will lead to a slightly higher average current for the following reasons: 

    1. The Bluetooth controller will need to increase its RADIO RX listening windows to compensate for the additional clock drift compared to the LF crystal oscillator.

    2. Requires periodic calibration,

    3. RC oscillator has a higher run current.

    You can estimate how much impact the clock source will have on your application (in terms of average power consumption) by using our online power profiler here:   

       Online Power Profiler for Bluetooth LE   

    Wael said:
    2) Since we know our device will be operating in a fairly temp controlled environment, what do you think would be wise settings to minimize power consumption but not get some egregious clock drift? 
    for example, do the cal every x number of deg change if possible. what do you think that x should be
    or do it every x seconds(what do you think that x should be)

    I think you can extend the interval to 8 seconds. From the PS:

    Regards,

    Vidar

Reply
  • Hi Wael,

    Wael said:
    1) will an external 32kHz crystal use less power? or

    The internal RC oscillator will lead to a slightly higher average current for the following reasons: 

    1. The Bluetooth controller will need to increase its RADIO RX listening windows to compensate for the additional clock drift compared to the LF crystal oscillator.

    2. Requires periodic calibration,

    3. RC oscillator has a higher run current.

    You can estimate how much impact the clock source will have on your application (in terms of average power consumption) by using our online power profiler here:   

       Online Power Profiler for Bluetooth LE   

    Wael said:
    2) Since we know our device will be operating in a fairly temp controlled environment, what do you think would be wise settings to minimize power consumption but not get some egregious clock drift? 
    for example, do the cal every x number of deg change if possible. what do you think that x should be
    or do it every x seconds(what do you think that x should be)

    I think you can extend the interval to 8 seconds. From the PS:

    Regards,

    Vidar

Children
  • Hi Vidar,

    Thank you for your reply. this makes complete sense. I now have another power consumption issue. My app does the following using PPI, SPIM, GPIOTE, and timers

    the PPI configuration is as follow:

    1) Upon receiving a GPIOTE trigger from an IMU(every 8.3 seconds), read its data (this is operating on a dedicated spi bus, SPIM0)

    2) write a dummy read command to an FRAM IC to wake it up from hibernate state (SPIM1 bus)

    3) trigger timer for 8ms from the start of the FRAM SPIM transaction(step 2)(period for FRAM to become stable from hibernate state)

    4) write the WREN(write enable) command to the FRAM upon completion of the 8ms timer

    5) write the (write command, address, data) to the FRAM

    6) write the hibernate command to the FRAM

    the multiple writes(aside from step 5) can NOT be combined as the bus CS pin needs to be toggled for the memory chip to accept the commands.

    to do this, I used 2 spi buses and 4 timers(one timer mode for the 8ms delay and 4 counters)

    In sum, my code works exactly as described and verified using oscilloscope. 

    my issue is after the first PPI transaction is triggered, something is consuming power and/or is staying on. has between 650 and 850us periods. please see the first plot below. Note: approx. 200uA of the 600uA is from my external peripherals on the board. 

    the 2nd plot shows this issue does not exist prior to the first PPI transaction. 

    I do not think its a timer issue. I have read that the EasyDMA does consume ~1.5mA but that should only be during transmission. and the frequency of these pulses do not correlate to any SPI transaction. I have not been able to isolate the cause of this and your time and effort would be greatly appreciated.

    Regards,

    Wael

  • Hi Wael,

    Could you please try to use a GPIOTE PORT event to detect when the IMU's interrupt line is asserted and trigger the SPI task from your app instead of using PPI? You should see a lower floor current when using GPIOTE PORT event compared to when you have IN events enabled.

    [153] GPIOTE: GPIOTE with low-power latency setting does not register IN events in System ON IDLE

    Regards,

    Vidar

  • Hi Vidar,

    Thank you for your suggestion, but I am not using the 5340 which is what your link, I am using 52833 and SDK 2.0.0.

    with that said, here is my function that initializes the GPIOTE pin

    void configure_imu_int1_gpiote(void)
    {
        nrfx_err_t err = NRFX_SUCCESS;
    
         __ASSERT (!nrfx_gpiote_is_init(),"nrfx_gpiote_is_init Failed");
        
        static const nrfx_gpiote_input_config_t input_config = {
    		.pull = NRF_GPIO_PIN_PULLDOWN,
    	};
    
    	const nrfx_gpiote_trigger_config_t trigger_config = {
    		.trigger = NRFX_GPIOTE_TRIGGER_LOTOHI,
    		.p_in_channel = NULL, //&in_channel,
    	};
    
        err = nrfx_gpiote_input_configure(IMU_INT1_PIN,
    					  &input_config,
    					  &trigger_config,
    					  NULL);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("Failed to nrfx_gpiote_input_configure, error: 0x%08X", err);
    		return;
    	}
    
        //nrfx_gpiote_in_event_enable(IMU_INT1_PIN, false);
        nrfx_gpiote_trigger_enable(IMU_INT1_PIN, false);
    }

    I am NOT using IN Event per my configuration. Please note this power issue only happens after all configurations and ONLY after the IMU int pin is triggered. so after power on for approx 8 seconds, the current level is as expected. only after the int trigger this issue happens. again, this issue is driving me crazy and eating lots of my time. any other suggestions please? as always, your help is greatly appreciated.

    Regards,

    here is some of my code

    timers setup

    static const nrfx_timer_t m_imu_acq_cnt_timer = NRFX_TIMER_INSTANCE(1);
    static const nrfx_timer_t m_fram_hibernate_delay_timer = NRFX_TIMER_INSTANCE(2);
    static const nrfx_timer_t m_fram_spim_start_cnt_timer = NRFX_TIMER_INSTANCE(3);
    static const nrfx_timer_t m_fram_spim_end_cnt_timer = NRFX_TIMER_INSTANCE(4);
    
    
    void configure_imu_ppi_timer(void)
    {
        nrfx_err_t err = NRFX_SUCCESS;
    
    
        // configure imu/ppi timer
        nrfx_timer_config_t timer_cfg_0 = NRFX_TIMER_DEFAULT_CONFIG;
        timer_cfg_0.mode = NRF_TIMER_MODE_LOW_POWER_COUNTER; //NRF_TIMER_MODE_COUNTER;
        //IRQ_DIRECT_CONNECT(TIMER1_IRQn, 0, nrfx_timer_1_irq_handler, 0);
    
        IRQ_CONNECT(DT_IRQN(DT_NODELABEL(timer1)), 
    		    DT_IRQ(DT_NODELABEL(timer1), priority),
    		    nrfx_isr, nrfx_timer_1_irq_handler, 0);
    
        if(!nrfx_timer_is_enabled(&m_imu_acq_cnt_timer)) {
            err = nrfx_timer_init(&m_imu_acq_cnt_timer,
                                        &timer_cfg_0,
                                        imu_ppi_timer_event_handler);    
            if (err != NRFX_SUCCESS) {
    		    LOG_ERR("nrf_drv_timer_init error: %08x", err);
    		    return;
    	    }                              
        }
    
        nrfx_timer_extended_compare(&m_imu_acq_cnt_timer,
                                       NRF_TIMER_CC_CHANNEL0,
                                       1 /*IMU_SPIM_TRANSFER_COUNT*/,
                                       NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, 
                                       true);
    
        if(!nrfx_timer_is_enabled(&m_imu_acq_cnt_timer))
            nrfx_timer_enable(&m_imu_acq_cnt_timer);    
    }

    void configure_fram_ppi_timer()
    {
        nrfx_err_t err = NRFX_SUCCESS;
    
        IRQ_CONNECT(DT_IRQN(DT_NODELABEL(timer2)), 
    		    DT_IRQ(DT_NODELABEL(timer2), priority),
    		    nrfx_isr, nrfx_timer_2_irq_handler, 0);
    
        // the fram hibernate timer ~6ms
        nrfx_timer_config_t timer_cfg_1 = NRFX_TIMER_DEFAULT_CONFIG;
        timer_cfg_1.mode = NRF_TIMER_MODE_TIMER;
        timer_cfg_1.frequency = NRF_TIMER_FREQ_31250Hz;
        //timer_cfg_1.bit_width = NRF_TIMER_BIT_WIDTH_32;
    
        if(!nrfx_timer_is_enabled(&m_fram_hibernate_delay_timer)) {
            err = nrfx_timer_init(&m_fram_hibernate_delay_timer,
                                        &timer_cfg_1,
                                        fram_ppi_timer_event_handler);    
            if (err != NRFX_SUCCESS) {
    		    LOG_ERR("nrf_drv_timer_init error: %08x", err);
    		    return;
    	    }                              
        }
        uint32_t ticks = nrfx_timer_ms_to_ticks(&m_fram_hibernate_delay_timer, 8);
        nrfx_timer_extended_compare(&m_fram_hibernate_delay_timer,
                                       NRF_TIMER_CC_CHANNEL2,
                                       ticks,
                                       (NRF_TIMER_SHORT_COMPARE2_CLEAR_MASK | NRF_TIMER_SHORT_COMPARE2_STOP_MASK), 
                                       false);    
    
        nrfx_timer_clear(&m_fram_hibernate_delay_timer);
        //  if(!nrfx_timer_is_enabled(&m_fram_hibernate_delay_timer))
        //  {
        //     nrfx_timer_enable(&m_fram_hibernate_delay_timer);
        //     nrfx_timer_pause(&m_fram_hibernate_delay_timer);
        //     nrfx_timer_clear(&m_fram_hibernate_delay_timer);
        //  }
    
        IRQ_CONNECT(DT_IRQN(DT_NODELABEL(timer3)), 
    		    DT_IRQ(DT_NODELABEL(timer3), priority),
    		    nrfx_isr, nrfx_timer_3_irq_handler, 0);
    
        // configure fram spim start count ppi timer
        nrfx_timer_config_t timer_cfg_2 = NRFX_TIMER_DEFAULT_CONFIG;
        timer_cfg_2.mode = NRF_TIMER_MODE_LOW_POWER_COUNTER; //NRF_TIMER_MODE_COUNTER;
        if(!nrfx_timer_is_enabled(&m_fram_spim_start_cnt_timer)) {
            err = nrfx_timer_init(&m_fram_spim_start_cnt_timer,
                                        &timer_cfg_2,
                                        fram_spim_start_count_ppi_timer_event_handler);    
            if (err != NRFX_SUCCESS) {
    		    LOG_ERR("nrf_drv_timer_init error: %08x", err);
    		    return;
    	    }                              
        }
        nrfx_timer_compare(&m_fram_spim_start_cnt_timer,
                                       NRF_TIMER_CC_CHANNEL0,
                                       1 /*FRAM_SPIM_TRANSFER_COUNT*/, 
                                       true);
    
        nrfx_timer_compare(&m_fram_spim_start_cnt_timer,
                                       NRF_TIMER_CC_CHANNEL1,
                                       2 /*FRAM_SPIM_TRANSFER_COUNT*/, 
                                       true);
    
        nrfx_timer_compare(&m_fram_spim_start_cnt_timer,
                                       NRF_TIMER_CC_CHANNEL2,
                                       3 /*FRAM_SPIM_TRANSFER_COUNT*/, 
                                       true);
        nrfx_timer_extended_compare(&m_fram_spim_start_cnt_timer,
                                       NRF_TIMER_CC_CHANNEL3,
                                       4 /*FRAM_SPIM_TRANSFER_COUNT*/, 
                                       NRF_TIMER_SHORT_COMPARE3_CLEAR_MASK,
                                       true);                               
    
        if(!nrfx_timer_is_enabled(&m_fram_spim_start_cnt_timer))
            nrfx_timer_enable(&m_fram_spim_start_cnt_timer);  
    
        nrfx_timer_clear(&m_fram_spim_start_cnt_timer);
    
        IRQ_CONNECT(DT_IRQN(DT_NODELABEL(timer4)), 
    		    DT_IRQ(DT_NODELABEL(timer4), priority),
    		    nrfx_isr, nrfx_timer_4_irq_handler, 0);
    
        // configure fram spim end count ppi timer
        nrfx_timer_config_t timer_cfg_3 = NRFX_TIMER_DEFAULT_CONFIG;
        timer_cfg_3.mode = NRF_TIMER_MODE_LOW_POWER_COUNTER; //NRF_TIMER_MODE_COUNTER;
        if(!nrfx_timer_is_enabled(&m_fram_spim_end_cnt_timer)) {
            err = nrfx_timer_init(&m_fram_spim_end_cnt_timer,
                                        &timer_cfg_3,
                                        fram_spim_end_count_ppi_timer_event_handler);    
            if (err != NRFX_SUCCESS) {
    		    LOG_ERR("nrf_drv_timer_init error: %08x", err);
    		    return;
    	    }                              
        }
        // we start the 3rd FRAM write
        nrfx_timer_compare(&m_fram_spim_end_cnt_timer,
                                       NRF_TIMER_CC_CHANNEL0,
                                       2 /*SPIM END EVENT COUNT*/,  
                                       false);
        // we start the 4th FRAM write
        nrfx_timer_compare(&m_fram_spim_end_cnt_timer,
                                       NRF_TIMER_CC_CHANNEL1,
                                       3 /*SPIM END EVENT COUNT*/,
                                       false);
        // we want to clear the timer on the end of the 4th spim end 
         nrfx_timer_extended_compare(&m_fram_spim_end_cnt_timer,
                                       NRF_TIMER_CC_CHANNEL2,
                                       4 /*SPIM END EVENT COUNT*/,
                                       NRF_TIMER_SHORT_COMPARE2_CLEAR_MASK,  
                                       false);
                                 
        if(!nrfx_timer_is_enabled(&m_fram_spim_end_cnt_timer))
            nrfx_timer_enable(&m_fram_spim_end_cnt_timer);     
    
        nrfx_timer_clear(&m_fram_spim_end_cnt_timer); 
    
    }

    void fram_spim_start_count_ppi_timer_event_handler(nrf_timer_event_t event_type, void * p_context)
    {
        uint32_t timer_value = 0;
        uint8_t CMD_WRITE_ENABLE;
        uint8_t CMD_HIBERNATE;
    
        if(event_type == NRF_TIMER_EVENT_COMPARE0) // for 2nd fram write
        {
            timer_value = nrfx_timer_capture_get(&m_fram_spim_start_cnt_timer, NRF_TIMER_CC_CHANNEL0);
            CMD_WRITE_ENABLE = ENUM_TO_UINT8(FRAM_CMD_WRITE_ENABLE);
            spim1_fram.p_reg->TXD.PTR = (uint32_t)&CMD_WRITE_ENABLE;
            spim1_fram.p_reg->TXD.MAXCNT = 1;
            spim1_fram.p_reg->RXD.MAXCNT = 0; 
           // LOG_INF("Setup for 2nd fram write.........");
    
            //nrfx_timer_clear(&m_imu_acq_cnt_timer);
            // LOG_HEXDUMP_INF(IMU_Recv_ArrayList->buffer,364,"received FIFO Data");
        }
        else if(event_type == NRF_TIMER_EVENT_COMPARE1) // for 3rd fram write
        {
            timer_value = nrfx_timer_capture_get(&m_fram_spim_start_cnt_timer, NRF_TIMER_CC_CHANNEL1);
            IMU_RX_BUFFER[0] = ENUM_TO_UINT8(FRAM_CMD_WRITE_DATA);
            IMU_RX_BUFFER[1] = (m_current_fram_addr & 0x00FF0000) >> 16;
            IMU_RX_BUFFER[2] = (m_current_fram_addr & 0x0000FF00) >> 8;
            IMU_RX_BUFFER[3] = (m_current_fram_addr & 0x000000FF);
    
            m_current_fram_addr += ADL_MODE_BUFFER_IMU_RXD_SIZE;
    
            spim1_fram.p_reg->TXD.PTR = (uint32_t)&IMU_RX_BUFFER;
            spim1_fram.p_reg->TXD.MAXCNT = ADL_MODE_BUFFER_IMU_RXD_SIZE + 4;
            spim1_fram.p_reg->RXD.MAXCNT = 0;
           // LOG_INF("Setup for 3rd fram write.........");
        }
        else if(event_type == NRF_TIMER_EVENT_COMPARE2) // for 4th fram write
        {
            timer_value = nrfx_timer_capture_get(&m_fram_spim_start_cnt_timer, NRF_TIMER_CC_CHANNEL2);
            CMD_HIBERNATE = ENUM_TO_UINT8(FRAM_CMD_HIBERNATE);
            spim1_fram.p_reg->TXD.PTR = (uint32_t)&CMD_HIBERNATE;
            spim1_fram.p_reg->TXD.MAXCNT = 1;
            spim1_fram.p_reg->RXD.MAXCNT = 0; 
           // LOG_INF("Setup for 4th fram write.........");
        }
        else if(event_type == NRF_TIMER_EVENT_COMPARE3) // for 1st fram write
        {
            timer_value = nrfx_timer_capture_get(&m_fram_spim_start_cnt_timer, NRF_TIMER_CC_CHANNEL3);
          //  nrfx_timer_clear(&m_fram_spim_start_cnt_timer);
            spim1_fram.p_reg->TXD.PTR = (uint32_t)&FRAM_ADL_TX_ArrayList;
            spim1_fram.p_reg->TXD.MAXCNT = 4;
            spim1_fram.p_reg->RXD.MAXCNT = 0; 
            //LOG_INF("Setup for 1st fram write.........");
        }
        else
            LOG_INF("Unknown timer event...............");
    }
    void fram_spim_end_count_ppi_timer_event_handler(nrf_timer_event_t event_type, void * p_context)
    {
        if(event_type == NRF_TIMER_EVENT_COMPARE0) // the 3rd spim end trigger
        {
            LOG_INF("2nd spim end trigger.........");
        }
        else if(event_type == NRF_TIMER_EVENT_COMPARE1) // the 3rd spim end trigger
        {
            //nrfx_timer_clear(&m_fram_spim_end_cnt_timer);
            LOG_INF("3rd spim end trigger.........");
        }
        else
            LOG_INF("Undefind FRAM SPIM End Count Event Type.........");
    }

    void setup_ADL_mode_imu_ppi_spi_transfer(void)
    {
        nrfx_err_t err = NRFX_SUCCESS;
      
        // IMU SPI setup
        spim0_imu.p_reg->TXD.LIST = SPIM_TXD_LIST_LIST_ArrayList;
        spim0_imu.p_reg->RXD.LIST = SPIM_RXD_LIST_LIST_ArrayList;
        spim0_imu.p_reg->TXD.MAXCNT = ADL_MODE_BUFFER_IMU_TXD_SIZE;
        spim0_imu.p_reg->RXD.MAXCNT = ADL_MODE_BUFFER_IMU_RXD_SIZE; 
        nrfx_spim_xfer_desc_t imu_xfer = NRFX_SPIM_XFER_TRX((uint8_t*)IMU_ChannelSwitch_ArrayList,
                                                                            ADL_MODE_BUFFER_IMU_TXD_SIZE,
                                                                            (uint8_t*)&IMU_RX_BUFFER[4],
                                                                            ADL_MODE_BUFFER_IMU_RXD_SIZE);
    
        uint32_t flags = (NRFX_SPIM_FLAG_HOLD_XFER
                          |NRFX_SPIM_FLAG_TX_POSTINC
                          |NRFX_SPIM_FLAG_RX_POSTINC
                          |NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER
                          |NRFX_SPIM_FLAG_REPEATED_XFER);
                          
        err = nrfx_spim_xfer(&spim0_imu, &imu_xfer, flags);
        if (err != NRFX_SUCCESS) {
            LOG_INF("nrfx_spim_xfer error: %08x", err);
    		LOG_ERR("nrfx_spim_xfer error: %08x", err);
    		return;
    	}
    }
    
    void setup_ADL_mode_fram_ppi_spi_transfer(void)
    {
        nrfx_err_t err = NRFX_SUCCESS;
      
        uint32_t flags = (NRFX_SPIM_FLAG_HOLD_XFER
                          |NRFX_SPIM_FLAG_TX_POSTINC
                          |NRFX_SPIM_FLAG_RX_POSTINC
                          |NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER
                          |NRFX_SPIM_FLAG_REPEATED_XFER);
                          
        // FRAM SPI setup
        spim1_fram.p_reg->TXD.LIST = SPIM_TXD_LIST_LIST_ArrayList;
        spim1_fram.p_reg->RXD.LIST = SPIM_RXD_LIST_LIST_ArrayList;
        spim1_fram.p_reg->TXD.MAXCNT = 4;
        spim1_fram.p_reg->RXD.MAXCNT = 0; 
        nrfx_spim_xfer_desc_t fram_xfer = NRFX_SPIM_XFER_TRX((uint8_t*)FRAM_ADL_TX_ArrayList,
                                                                            4,
                                                                            NULL,
                                                                            0);                  
        err = nrfx_spim_xfer(&spim1_fram, &fram_xfer, flags);
        if (err != NRFX_SUCCESS) {
            LOG_INF("nrfx_spim_xfer error: %08x", err);
    		LOG_ERR("nrfx_spim_xfer error: %08x", err);
    		return;
    	}
    }

    void start_ADL_mode_acq()
    {
        //setup_imu_ppi_spi_transfer();
        setup_ADL_mode_imu_ppi_spi_transfer();
        setup_ADL_mode_fram_ppi_spi_transfer();
    	nrfx_ppi_group_enable(imu_trigger_group);
        
        // k_timer_stop(&m_start_imu_conv_timer_id);
        // k_timer_start(&m_start_imu_conv_timer_id, K_MSEC(1010), K_NO_WAIT);
        LOG_INF("started ADL Mode Acquisition...............");
    }
    
    void ADL_mode_ppi_init(void)
    {
        nrfx_err_t err = NRFX_SUCCESS;
    
        nrf_ppi_channel_t imu_int1_trigger_ppi_channel;
        nrf_ppi_channel_t imu_count_ppi_channel;
        nrf_ppi_channel_t imu_trigger_disable_channel;
        nrf_ppi_channel_t fram_spim_end_trigger_ppi_channel;
        nrf_ppi_channel_t fram_spim_start_trigger_ppi_channel;
        nrf_ppi_channel_t fram_hibernate_timer_ppi_channel;
        nrf_ppi_channel_t fram_spim_start_count_ppi_channel;
        nrf_ppi_channel_t fram_spim_end_count_ppi_channel;
    
        nrf_ppi_channel_t fram_1st_write_ppi_channel;
        nrf_ppi_channel_t fram_2nd_write_ppi_channel;
        nrf_ppi_channel_t fram_3rd_write_ppi_channel;
        nrf_ppi_channel_t fram_4th_write_ppi_channel;
    
        uint32_t imu_int1_trigger_pin_evt_addr;
        uint32_t imu_spim_start_task_addr;
        uint32_t imu_spim_end_evt_addr;
        uint32_t timer_count_task_addr;
        uint32_t timer_cc_event_addr;
        uint32_t group_imu_disable_task_addr;
        
        uint32_t imu_ss_pin_toggle_task_addr;
        uint32_t fram_timer_spim_start_count_task_addr;
        uint32_t fram_timer_spim_end_count_task_addr;
        uint32_t fram_timer_spim_start_cc1_event_addr;
        uint32_t fram_timer_spim_end_cc2_event_addr;
        uint32_t fram_timer_spim_end_cc3_event_addr;
       
        uint32_t fram_spim_start_task_addr;
        uint32_t fram_spim_end_evt_addr;
        uint32_t fram_spim_started_evt_addr;
        uint32_t fram_ss_pin_toggle_task_addr;
        // uint32_t group_fram_disable_task_addr;
    
        uint32_t fram_hibernate_timer_start_task_addr;
        uint32_t fram_hibernate_timer_cc_evt_addr;   
    
        err = nrfx_ppi_channel_alloc(&imu_int1_trigger_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_alloc error: %08x", err);
    		return;
    	}
    
        // this ppi channel will toggle the fram spim cs at the end of the transaction to the fram
        err = nrfx_ppi_channel_alloc(&fram_spim_end_trigger_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_alloc error: %08x", err);
    		return;
    	}
        
        err = nrfx_ppi_channel_alloc(&fram_spim_start_trigger_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_alloc error: %08x", err);
    		return;
    	}
        
        err = nrfx_ppi_channel_alloc(&fram_hibernate_timer_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_alloc error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_alloc(&imu_count_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_alloc error: %08x", err);
    		return;
    	}  
        err = nrfx_ppi_channel_alloc(&fram_spim_start_count_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_alloc error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_alloc(&fram_spim_end_count_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_alloc error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_alloc(&fram_1st_write_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_alloc error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_alloc(&fram_2nd_write_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_alloc error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_alloc(&fram_3rd_write_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_alloc error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_alloc(&fram_4th_write_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_alloc error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_alloc(&imu_trigger_disable_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_alloc error: %08x", err);
    		return;
    	}
    
        err = nrfx_ppi_group_alloc(&imu_trigger_group);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_group_alloc error: %08x", err);
    		return;
    	}
    
        imu_int1_trigger_pin_evt_addr   = nrfx_gpiote_in_event_addr_get(IMU_INT1_PIN);
        imu_spim_start_task_addr        = nrf_spim_task_address_get(spim0_imu.p_reg, NRF_SPIM_TASK_START);
        imu_spim_end_evt_addr           = nrf_spim_event_address_get(spim0_imu.p_reg, NRF_SPIM_EVENT_END);
        timer_count_task_addr       = nrfx_timer_task_address_get(&m_imu_acq_cnt_timer, NRF_TIMER_TASK_COUNT);
        timer_cc_event_addr         = nrfx_timer_compare_event_address_get(&m_imu_acq_cnt_timer, NRF_TIMER_CC_CHANNEL0);
        // group_disable_task_addr = (uint32_t) nrf_ppi_task_group_disable_address_get(trigger_group);
        group_imu_disable_task_addr = (uint32_t) nrfx_ppi_task_addr_group_disable_get(imu_trigger_group);
        
        fram_spim_start_task_addr    = nrf_spim_task_address_get(spim1_fram.p_reg, NRF_SPIM_TASK_START); 
        fram_spim_end_evt_addr       = nrf_spim_event_address_get(spim1_fram.p_reg, NRF_SPIM_EVENT_END);
        fram_spim_started_evt_addr   = nrf_spim_event_address_get(spim1_fram.p_reg, NRF_SPIM_EVENT_STARTED);
     //   group_fram_disable_task_addr = (uint32_t) nrfx_ppi_task_addr_group_disable_get(fram_trigger_group);
        
        fram_hibernate_timer_start_task_addr = nrfx_timer_task_address_get(&m_fram_hibernate_delay_timer, NRF_TIMER_TASK_START);
        fram_hibernate_timer_cc_evt_addr     = nrfx_timer_compare_event_address_get(&m_fram_hibernate_delay_timer, NRF_TIMER_CC_CHANNEL2);
    
        fram_timer_spim_start_count_task_addr = nrfx_timer_task_address_get(&m_fram_spim_start_cnt_timer, NRF_TIMER_TASK_COUNT);
        fram_timer_spim_end_count_task_addr = nrfx_timer_task_address_get(&m_fram_spim_end_cnt_timer, NRF_TIMER_TASK_COUNT);
    
        //fram_timer_spim_start_cc1_event_addr         = nrfx_timer_compare_event_address_get(&m_fram_spim_start_cnt_timer, NRF_TIMER_CC_CHANNEL0);
        fram_timer_spim_end_cc2_event_addr         = nrfx_timer_compare_event_address_get(&m_fram_spim_end_cnt_timer, NRF_TIMER_CC_CHANNEL0);
        fram_timer_spim_end_cc3_event_addr         = nrfx_timer_compare_event_address_get(&m_fram_spim_end_cnt_timer, NRF_TIMER_CC_CHANNEL1);
    
        // IMU SS
        // The SS pin will be driven by a GPIOTE task.
        // have the ppi spim start/end event control the slave select       
        nrfx_gpiote_out_config_t imu_ss_pin_config = NRFX_GPIOTE_CONFIG_OUT_TASK_TOGGLE(true);
        err = nrfx_gpiote_out_init(IMU_CS_PIN, &imu_ss_pin_config);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_gpiote_out_init error: %08x", err);
    		return;
    	}
        imu_ss_pin_toggle_task_addr = nrfx_gpiote_out_task_addr_get(IMU_CS_PIN);
    
        // FRAM SS
        // The SS pin will be driven by a GPIOTE task.
        // have the ppi spim start/end event control the slave select   
        nrfx_gpiote_out_config_t fram_ss_pin_config = NRFX_GPIOTE_CONFIG_OUT_TASK_TOGGLE(true);
        err = nrfx_gpiote_out_init(FRAM_CS_PIN, &fram_ss_pin_config);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_gpiote_out_init error: %08x", err);
    		return;
    	}
        fram_ss_pin_toggle_task_addr = nrfx_gpiote_out_task_addr_get(FRAM_CS_PIN);
    
        // this channel will trigger the imu spim task off the imu int1 pin event 
        err = nrfx_ppi_channel_assign(imu_int1_trigger_ppi_channel,
                                              imu_int1_trigger_pin_evt_addr,
                                              imu_spim_start_task_addr);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_assign error: %08x", err);
    		return;
    	}
    
        // fork the imu ss pin off of the start(to assert) of imu spim channel
        err = nrfx_ppi_channel_fork_assign(imu_int1_trigger_ppi_channel, imu_ss_pin_toggle_task_addr);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_fork_assign error: %08x", err);
    		return;
    	}
    
        err = nrfx_ppi_channel_assign(imu_count_ppi_channel,
                                              imu_spim_end_evt_addr,
                                              timer_count_task_addr);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_assign error: %08x", err);
    		return;
    	}
        // fork the imu ss pin off of the end of imu spim channel(to de-assert))
        err = nrfx_ppi_channel_fork_assign(imu_count_ppi_channel, imu_ss_pin_toggle_task_addr);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_fork_assign error: %08x", err);
    		return;
    	}
     ////////   
        // first FRAM write. dummy read instruction. toggle ss pin, start spi, toggle ss pin  
        err = nrfx_ppi_channel_assign(fram_1st_write_ppi_channel,
                                              imu_spim_end_evt_addr,
                                              fram_spim_start_task_addr);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_assign error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_assign(fram_spim_start_trigger_ppi_channel,
                                              fram_spim_started_evt_addr,
                                              fram_ss_pin_toggle_task_addr);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_assign error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_assign(fram_spim_end_trigger_ppi_channel,
                                              fram_spim_end_evt_addr,
                                              fram_ss_pin_toggle_task_addr);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_assign error: %08x", err);
    		return;
    	}
        
        // count the FRAM SPI writes off of the SPI start
        err = nrfx_ppi_channel_assign(fram_spim_start_count_ppi_channel,
                                              fram_spim_started_evt_addr,
                                              fram_timer_spim_start_count_task_addr);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_assign error: %08x", err);
    		return;
    	} 
        err = nrfx_ppi_channel_assign(fram_spim_end_count_ppi_channel,
                                              fram_spim_end_evt_addr,
                                              fram_timer_spim_end_count_task_addr);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_assign error: %08x", err);
    		return;
    	}
       
        // start the FRAM hibernate timer off of the IMU SPI end Event
        err = nrfx_ppi_channel_assign(fram_hibernate_timer_ppi_channel,
                                              imu_spim_end_evt_addr,
                                              fram_hibernate_timer_start_task_addr);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_assign error: %08x", err);
    		return;
    	}
        // now we want to start the 2nd, 3rd and 4th FRAM SPI transactions
        // we start the 2nd off of the end of te hibernate timer
        err = nrfx_ppi_channel_assign(fram_2nd_write_ppi_channel,
                                              fram_hibernate_timer_cc_evt_addr,
                                              fram_spim_start_task_addr);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_assign error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_assign(fram_3rd_write_ppi_channel,
                                              fram_timer_spim_end_cc2_event_addr,
                                              fram_spim_start_task_addr);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_assign error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_assign(fram_4th_write_ppi_channel,
                                              fram_timer_spim_end_cc3_event_addr,
                                              fram_spim_start_task_addr);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_assign error: %08x", err);
    		return;
    	}
    
        err = nrfx_ppi_channel_enable(fram_spim_start_trigger_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_enable error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_enable(fram_spim_end_trigger_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_enable error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_enable(imu_count_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_enable error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_enable(fram_spim_start_count_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_enable error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_enable(fram_spim_end_count_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_enable error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_enable(fram_1st_write_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_enable error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_enable(fram_2nd_write_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_enable error: %08x", err);
    		return;
    	}
        err = nrfx_ppi_channel_enable(fram_3rd_write_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_enable error: %08x", err);
    		return;
    	}
         err = nrfx_ppi_channel_enable(fram_4th_write_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_enable error: %08x", err);
    		return;
    	}
        
        err = nrfx_ppi_channel_enable(fram_hibernate_timer_ppi_channel);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_enable error: %08x", err);
    		return;
    	}
     
        err = nrfx_ppi_channel_assign(imu_trigger_disable_channel,
                                              timer_cc_event_addr,
                                              group_imu_disable_task_addr);
        if (err != NRFX_SUCCESS) {
    		LOG_ERR("nrfx_ppi_channel_assign error: %08x", err);
    		return;
    	}
        // err = nrfx_ppi_channel_assign(fram_trigger_disable_channel,
        //                                       timer_fram_cc_event_addr,
        //                                       group_fram_disable_task_addr);
        // if (err != NRFX_SUCCESS) {
    	// 	LOG_ERR("nrfx_ppi_channel_assign error: %08x", err);
    	// 	return;
    	// }
    
      
    //    err_code = nrfx_ppi_channel_enable(trigger_ppi_channel);
    //    APP_ERROR_CHECK(err_code);
     
    //     err = nrfx_ppi_channel_enable(imu_trigger_disable_channel);
    //     if (err != NRFX_SUCCESS) {
    // 		LOG_ERR("nrfx_ppi_channel_enable error: %08x", err);
    // 		return;
    // 	}
        
        // disable for testing
        // err = nrfx_ppi_channel_enable(fram_trigger_disable_channel);
        // if (err != NRFX_SUCCESS) {
    	// 	LOG_ERR("nrfx_ppi_channel_enable error: %08x", err);
    	// 	return;
    	// }
    
        nrfx_ppi_channel_include_in_group(imu_int1_trigger_ppi_channel, imu_trigger_group);
        // nrfx_ppi_channel_include_in_group(fram_spim_trigger_ppi_channel, fram_trigger_group);
        // nrfx_ppi_channel_include_in_group(fram_spim_end_trigger_ppi_channel, fram_trigger_group);
        
    //    nrf_ppi_group_enable(trigger_group);
    
        nrfx_gpiote_out_task_enable(IMU_CS_PIN);  
        nrfx_gpiote_out_task_enable(FRAM_CS_PIN); 
    }

  • Hi Wael,

    Sorry, I thought you were using the nRF5340 for some reason. A current draw in the 5-600 uA range on the nRF52 series usually indicates that a peripheral keep requesting the 16 MHz clock. For instance, a running TIMER instance. However, this should have led to a more constant draw, not like the waveform shown in your screenshot.

    The DMA current is closer to 2 mA with VDD @ 1.8 v. But as you said, this current should only be seen during transmissions when the CPU is idle.   

    Either way, to try narrow down the problem, could try to issue the TIMER SHUTDOWN tasks for your timers after the transaction is complete by calling nrfx_timer_disable(). Also, is it possible to power off the IMU and FRAM IC (make sure you do not have any floating inputs if you do this)?  

    Best regards,

    Vidar

  • hi Vidar,

    thanks for the reply. I did try TIMER SHUTDOWN and that did not work. what did work was the following:

    // nRF52833 Revision 2 Errata
    // [246] System: Intermittent extra current consumption when going to sleep
    // Extra current consumption in the range of 350 µA when in System On Idle.
    // A high-speed peripheral (CPU for example) accesses a RAM block which is being accessed by
    // a low-speed peripheral through the DMA bus, with a specific timing, and the high-speed peripheral has
    // higher priority than the low-speed peripheral.
    // NOTE: Workaround consequences: Up to 40 µA current increase when the 16 MHz clock is used.
    *(volatile uint32_t *)0x4007AC84ul = 0x00000002ul;
    I placed that line of code in my main function and the current went back down close to what's expected. still need to figure out where about 20uA is going.
    having said that, I now have the issue where if I increase my FRAM SPIM frequency to anything above 1 MHz, the PPI logic does not work. IMU SPIM frequency is set to 8 MHz. recall that the IMU and FRAM are on separate buses. recall, my app does the following using PPI

    the PPI configuration is as follow:

    1) Upon receiving a GPIOTE trigger from an IMU(every 8.3 seconds), read its data (this is operating on a dedicated spi bus, SPIM0) (~3500 bytes)

    2) write a dummy read command to an FRAM IC to wake it up from hibernate state (SPIM1 bus)(4 bytes)

    3) trigger timer for 8ms from the start of the FRAM SPIM transaction(step 2)(8ms is the period for FRAM to become stable from hibernate state)

    4) write the WREN(write enable) command(1 Byte) to the FRAM upon completion of the 8ms timer

    5) write the (write command, address, data) to the FRAM(~3500 bytes)

    6) write the hibernate command to the FRAM(1 byte)

    so when the FRAM SPIM freq=1 MHz, everything looks good and I can see things operating as expected on a scope.
    when I change the freq. to say 2 MHz or more, it does everything as expected with the exception of step 5. it only writes ONE byte. its seems as though the fram_spim_start_count_ppi_timer_event_handler is not getting executed on when the count=2(to setup for the 3rd FRAM write) to update the SPIM ptr and tx/rx parameters. I am assuming the 2nd spi transaction(which is one byte) got executed so fast that the spi parameters never get updated for the next transaction. Not sure on how to handle this issue. I need the speed to save on power. any thoughts and/or hints? As always, your help would be greatly appreciated. 
    Regards,
    Wael
Related