NRF52832 Current Consumption Problem

/**********************  DRIVER FOR SPI CONTROLLER  **********************

   Filename:     Serialize.c
   Description:  This files is aimed at giving a basic example of
				 SPI Controller to drive the SPI serial interface.

   Version:    0.2
   Date:       Decemb. 2011
   Authors:    Micron S.r.l. Arzano (Napoli)


   THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
   EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTY
   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
   AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
   PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
   REPAIR OR CORRECTION.
   
********************************************************************************

*******************************************************************************/
#include "Serialize.h"
#define BUFFERSIZE 128
const nrf_drv_timer_t SPI_CNT = NRF_DRV_TIMER_INSTANCE(1);
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(0); 
nrf_ppi_channel_t timer_ppi_channel1, timer_ppi_channel2, spi_ppi_channel1, spi_ppi_channel2;
nrf_ppi_channel_group_t spi_ppi_group; 

volatile bool spi_xfer_done;
/* this function is called only from Serialize_SPI() */

static uint8_t n_transfer;
static bool transfer_done = false;
void spi_cnt_enable(void);
void spi_cnt_disable(void);
void spi_cnt_init(void);

void spi_cnt_event_handler(nrf_timer_event_t event_type, void* p_context)
{
    switch (event_type)
    {
        case NRF_TIMER_EVENT_COMPARE1:
//						nrf_spim_shorts_disable(spi.p_registers, NRF_SPIM_SHORT_END_START_MASK);
            spi_cnt_disable();
            break;
				
        default:
            //Do nothing.
            break;
    }
}

void spi_cnt_init()
{
		if(!spi_cnt_initialised)
		{
			nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
	
			APP_ERROR_CHECK(nrf_drv_timer_init(&SPI_CNT, &timer_cfg, spi_cnt_event_handler)); 
			nrf_drv_timer_compare( &SPI_CNT, NRF_TIMER_CC_CHANNEL0, 0, true);
			nrf_drv_timer_compare( &SPI_CNT, NRF_TIMER_CC_CHANNEL1, 0, true);
			
			uint32_t timer_cnt_task   = nrf_drv_timer_task_address_get(&SPI_CNT, NRF_TIMER_TASK_COUNT);
			uint32_t spi_start_task   = nrf_drv_spi_task_address_get(&spi, NRF_SPIM_TASK_START);
				
			uint32_t timer_comp1_event =  nrf_drv_timer_event_address_get(&SPI_CNT,NRF_TIMER_EVENT_COMPARE0); 
			uint32_t timer_comp2_event =  nrf_drv_timer_event_address_get(&SPI_CNT,NRF_TIMER_EVENT_COMPARE1); 
			uint32_t spi_end_event     =  nrf_drv_spi_event_address_get(&spi, NRF_SPIM_EVENT_END);			
			
			APP_ERROR_CHECK(nrf_drv_ppi_channel_alloc(&timer_ppi_channel1));
			APP_ERROR_CHECK(nrf_drv_ppi_channel_alloc(&spi_ppi_channel1));
			APP_ERROR_CHECK(nrf_drv_ppi_channel_alloc(&spi_ppi_channel2));
			APP_ERROR_CHECK(nrf_drv_ppi_group_alloc(&spi_ppi_group));
			
			uint32_t ppi_disable_task = nrf_drv_ppi_task_addr_group_disable_get(spi_ppi_group);
			
			nrf_drv_ppi_channel_include_in_group(spi_ppi_channel2,spi_ppi_group);

			APP_ERROR_CHECK(nrf_drv_ppi_channel_assign(spi_ppi_channel1, spi_end_event, timer_cnt_task));
			APP_ERROR_CHECK(nrf_drv_ppi_channel_assign(spi_ppi_channel2, spi_end_event, spi_start_task));
			
			APP_ERROR_CHECK(nrf_drv_ppi_channel_assign(timer_ppi_channel1, timer_comp1_event, ppi_disable_task));
			spi_cnt_initialised = true;
		}
}
	
void spi_cnt_enable()
{
		APP_ERROR_CHECK(nrf_drv_ppi_channel_enable(timer_ppi_channel1));
		APP_ERROR_CHECK(nrf_drv_ppi_channel_enable(spi_ppi_channel1));
		APP_ERROR_CHECK(nrf_drv_ppi_channel_enable(spi_ppi_channel2));
		APP_ERROR_CHECK(nrf_drv_ppi_group_enable(spi_ppi_group));
		nrf_drv_timer_enable( &SPI_CNT );
//		nrf_spim_shorts_enable(spi.p_registers, NRF_SPIM_SHORT_END_START_MASK);
		transfer_done = false;
		nrf_gpio_pin_clear(ss_pin);
		
}

void spi_cnt_disable()
{
		nrf_gpio_pin_set(ss_pin);
//		nrf_spim_task_trigger(spi.p_registers,NRF_SPIM_TASK_STOP);
		APP_ERROR_CHECK(nrf_drv_ppi_channel_disable(timer_ppi_channel1));
		APP_ERROR_CHECK(nrf_drv_ppi_channel_disable(spi_ppi_channel1));
		APP_ERROR_CHECK(nrf_drv_ppi_channel_disable(spi_ppi_channel2));
		APP_ERROR_CHECK(nrf_drv_ppi_group_disable(spi_ppi_group));
		nrf_drv_timer_disable( &SPI_CNT );
		transfer_done = true;
}

/*******************************************************************************
     SPI Controller Init  
	 
Function:        SpiCtlInit()
Arguments:       There is no argument for this function
Return Values:   Return SpiSuccess
Description:     This function has to be called at the beginnning to configure 
				 the port.   

******************************************************************************/

void spi_event_handler(nrf_drv_spi_evt_t const * p_event)
{		
		switch (p_event->type)
		{
			case NRF_DRV_SPI_EVENT_DONE:
			{
				spi_xfer_done = true;	
				break;				
			}
		}
}

void spi_init(uint8_t pins[])   // Setting up Spi 
{	
		if(!spi_initialised)
		{
			*(volatile uint32_t *)0x40003FFC = 1;
			spi_cnt_init();
			nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
			spi_config.sck_pin   = SPIM0_SCK_PIN;
			spi_config.miso_pin  = SPIM0_MISO_PIN;
			spi_config.mosi_pin  = SPIM0_MOSI_PIN;
			spi_config.frequency = freq;
			APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler));
			NRF_GPIO->PIN_CNF[SPIM0_SCK_PIN] = (NRF_GPIO->PIN_CNF[SPIM0_SCK_PIN] & ~GPIO_PIN_CNF_DRIVE_Msk) | ( ( GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos ) & GPIO_PIN_CNF_DRIVE_Msk ); 
			NRF_GPIO->PIN_CNF[SPIM0_MISO_PIN] = (NRF_GPIO->PIN_CNF[SPIM0_MISO_PIN] & ~GPIO_PIN_CNF_DRIVE_Msk) | ( ( GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos ) & GPIO_PIN_CNF_DRIVE_Msk ); 
			NRF_GPIO->PIN_CNF[SPIM0_MOSI_PIN] = (NRF_GPIO->PIN_CNF[SPIM0_MOSI_PIN] & ~GPIO_PIN_CNF_DRIVE_Msk) | ( ( GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos ) & GPIO_PIN_CNF_DRIVE_Msk ); 
			
			memcpy(ss_pins, pins, NDEVICES);
			for( uint8_t i=0; i<sizeof(ss_pins); i++)
			{
				nrf_gpio_cfg_output(ss_pins[i]);
				nrf_gpio_pin_set(ss_pins[i]);
			}
			spi_initialised = true;
		}
}

void spi_unit(void)
{
	if(spi_initialised)
	{
		nrf_drv_spi_uninit(&spi);
		*(volatile uint32_t *)0x40003FFC = 0;
		spi_initialised = false;
		nrf_gpio_cfg_default(SPIM0_SCK_PIN);
		nrf_gpio_cfg_default(SPIM0_MISO_PIN);
		nrf_gpio_cfg_default(SPIM0_MOSI_PIN);
		nrf_gpio_cfg_default(SPIM0_SS_NAND_PIN);
		for( uint8_t i=0; i<2; i++)
		{
			nrf_gpio_cfg_output(ss_pins[i]);
			nrf_gpio_pin_set(ss_pins[i]);
		}

	}
}

void spi_set_freq(nrf_drv_spi_frequency_t freq_in)
{
	freq = freq_in;
}


void spi_change(uint8_t pin)
{
		ss_pin = pin;
}

/******************************************************************************* 
Function:     Serialize(const CharStream* char_stream_send, 
					CharStream* char_stream_recv, 
					SpiMasterConfigOptions optBefore,
					SpiMasterConfigOptions optAfter
				) 
Arguments:    char_stream_send, the char stream to be sent from the SPI master to
              the Flash memory, usually contains instruction, address, and data to be 
              programmed.
              char_stream_recv, the char stream to be received from the Flash memory
              to the SPI master, usually contains data to be read from the memory.
              optBefore, configurations of the SPI master before any transfer/receive
              optAfter, configurations of the SPI after any transfer/receive
Return Values:TRUE
Description:  This function can be used to encapsulate a complete transfer/receive 
              operation
Pseudo Code:
   Step 1  : perform pre-transfer configuration
   Step 2  : perform transfer/ receive 
   Step 3  : perform post-transfer configuration
*******************************************************************************/ 
SPI_STATUS Serialize_SPI(uint8_t* tx_buf, 
               uint16_t tx_len,
							 uint8_t* rx_buf,
							 uint16_t rx_len,
							 bool deselect)
                
{	
		if( tx_len > BUFFERSIZE )
		{
			Serialize_SPI_Write_Long( tx_buf, tx_len);
		}else if( rx_len > BUFFERSIZE )
		{
			Serialize_SPI_Read_Long( rx_buf, rx_len);
		}else{
			spi_init(ss_pins);
			uint8_t total_len; 
			if(rx_len > 0)
			{
				total_len = rx_len + tx_len;
			}else{
				total_len = 0;
			}

			memset(rx_buf, 0xAA, total_len);
			spi_xfer_done = false;
			
			nrf_gpio_pin_clear(ss_pin);
			APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, tx_buf, tx_len, rx_buf, total_len));
			while(!spi_xfer_done)
			{
					__WFE();
			}
			if(deselect)
			{
				nrf_gpio_pin_set(ss_pin);
				spi_unit();
			}
			memcpy(rx_buf, rx_buf+tx_len, rx_len); 
		}
		return RetSpiSuccess;
}

SPI_STATUS Serialize_SPI_Write_Long(uint8_t* tx_buf,uint16_t tx_len)
                
{
  spi_init(ss_pins);
	//SEGGER_RTT_printf(0, "length: %d\r\n", total_len );		
	//SEGGER_RTT_printf(0, "Buffer Size: %d\r\n", BUFFERSIZE ); 
	n_transfer = ceil((double)tx_len/BUFFERSIZE);			// Number of frames to transfer = total length/ buffer size
	//NRF_LOG_INFO("Length: %d\r\n", tx_len );
	//NRF_LOG_INFO("Total No tranfers: %d\r\n", n_transfer );
	//NRF_LOG_FLUSH();
	uint8_t tx_array[PAGE_SIZE];      // 2D array buffer
	//NRF_LOG_INFO("Total Size: %d\r\n", BUFFERSIZE*n_transfer*sizeof(uint8_t) );
	//NRF_LOG_FLUSH();
	
	memset(tx_array, 0xAA, BUFFERSIZE*n_transfer);
	//NRF_LOG_HEXDUMP_INFO( tx_array, 10);
	memcpy(tx_array, tx_buf, tx_len);
	//NRF_LOG_HEXDUMP_INFO( tx_array, 100);
	SPI_CNT.p_reg->CC[NRF_TIMER_CC_CHANNEL0] = n_transfer-1;
	SPI_CNT.p_reg->CC[NRF_TIMER_CC_CHANNEL1] = n_transfer;
	
	nrf_drv_spi_xfer_desc_t spi_xfer_NAND_desc = NRF_DRV_SPI_XFER_TX( tx_array , BUFFERSIZE);  
	

	
	uint32_t flags = 	NRF_DRV_SPI_FLAG_HOLD_XFER |
                    NRF_DRV_SPI_FLAG_REPEATED_XFER |
                    NRF_DRV_SPI_FLAG_TX_POSTINC |
                    NRF_DRV_SPI_FLAG_NO_XFER_EVT_HANDLER;
																												
	APP_ERROR_CHECK(nrf_drv_spi_xfer(&spi, &spi_xfer_NAND_desc, flags));  //Start transfer with Tx postinc flag
	
	spi_cnt_enable();
	
	nrf_spim_task_trigger(spi.p_registers, NRF_SPIM_TASK_START);
	
	
	while(!transfer_done)
	{	
			__WFE();
	}
	spi_unit();
	//NRF_LOG_HEXDUMP_INFO( &tx_array[0], 10);
	
	
	return RetSpiSuccess;
}

SPI_STATUS Serialize_SPI_Read_Long(uint8_t* rx_buf,uint16_t rx_len)
{
  spi_init(ss_pins);
	n_transfer = ceil((double)rx_len/BUFFERSIZE);			// Number of frames to transfer = total length/ buffer size
//	NRF_LOG_INFO("N:%d",n_transfer);
//	NRF_LOG_FLUSH();
	uint8_t rx_array[PAGE_SIZE];

	SPI_CNT.p_reg->CC[NRF_TIMER_CC_CHANNEL0] = n_transfer-1;
	SPI_CNT.p_reg->CC[NRF_TIMER_CC_CHANNEL1] = n_transfer;
	
	nrf_drv_spi_xfer_desc_t spi_xfer_NAND_desc = NRF_DRV_SPI_XFER_RX( rx_array , BUFFERSIZE);  
	
	uint32_t flags = 	NRF_DRV_SPI_FLAG_HOLD_XFER |
                    NRF_DRV_SPI_FLAG_REPEATED_XFER |
                    NRF_DRV_SPI_FLAG_RX_POSTINC |
                    NRF_DRV_SPI_FLAG_NO_XFER_EVT_HANDLER;
																												
	APP_ERROR_CHECK(nrf_drv_spi_xfer(&spi, &spi_xfer_NAND_desc, flags));  //Start transfer with Rx postinc flag
	
	spi_cnt_enable();
	
	nrf_spim_task_trigger(spi.p_registers, NRF_SPIM_TASK_START);
	
	
	while(!transfer_done)
	{
			__WFE();
	}
	spi_unit();
	memcpy(rx_buf, rx_array, rx_len);
//NRF_LOG_HEXDUMP_INFO( rx_array, 10);
//NRF_LOG_FLUSH();	

	
	return RetSpiSuccess;
}

Hi I have been doing some current consumption measurements using Nordic's Power Profile Kit 2.

The device I am measuring is a custom BLE device that uses the ADC to sample @ 256Hz,  reads data from an accelerometer (MC3672)

when the data ready pin goes from high to low ( gpiote ) and writes to a NAND flash every 2 seconds. 

The problem I am having is there is an increase in current just before the accelerometer pulls on the interrupt pin, I can not work out what is causing

this. All other currents are accounted for apart from this one.

Would anyone be able to shed some light on what might be causing this?

Thanks!.

////////////////Edit 

The problem may be related to SPI, as the current seems to increase roughly 20ms after a SPI transaction.

(shown below). 

   

I am using PPIs and a timer to do long SPI transfers . ( please see attached )

  • Hello,

    It is not clear to me at this point in time what causes these bumps occcuring every 60ms (ish?).

    If your three main suspects are the ADC, radio or SPI, I suggest you try to disable one at the time, and see whether the bumps disappear. 

    You aren't using any LEDs or something in your application at approximately every 60ms?

    Are you running this on an nRF52832 DK, or do you have some other custom HW? Are you measuring only the current on the nRF52832 chip, or are the external chips being powered from the nRF as well?

    Best regards,

    Edvin

Related