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

Power consumption related to TWIM

I recently had the need to communicate with a device over I2C. I'm using the nRF52 as the master. Everything works fine, but power is a concern. I am putting the processor into the ON low power mode. Currently, I'm typically running at around 120 uA, as measured with a Current Ranger. I'm measuring the current at the external power input to the PCA10040 board (P21). I wrote my own I2C driver, as I have with all my drivers.

I have a timer (RTC) that periodically (3-30 seconds, depending on various factors) initiates a communication with the external part over the TWIM interface. The actual communication exchange takes no longer than 60 ms at 400 KHz bus speed. I'm switching this external part on and off using a GPIO pin around the exchange. The first exchange happens 10 seconds after power up.

Before the first communication, my current consumption is about 120 uA. After the first communication, the power consumption is about 400 or so uA higher and it remains there. It certainly seems like after turning on the TWIM instance and then turning it off, it is not returning to the same state. I'm turning the TWIM on and off using the ENABLE register.

Is there something I need to do with the EasyDMA that I need to know about? I'll post a couple of code snippets.

//======================================================================
/*!
@brief	Enable the I2C.
@details
This function controls the functioning of the I2C. The I2C must be disabled
before changing any configuration parameters. It may also be disabled for
minimizing power consumption.

@param	i2c		Identifies the I2C.
@param	enable	TRUE to enable the I2C.

@author	John Heaney
@test	03/14/2020 Unit Test: UNTESTED
*/
void I2cEnable(I2cEnum i2c, BOOL enable)
{
	NRF_TWIM_Type *	i2cBaseReg;
	UINT32			enableValue;

	//The register used to enable either the master or slave is the same, but the
	// value used is different.
	enableValue = I2cIsMaster(i2c)	? TWIM_ENABLE_ENABLE_Enabled
									: TWIS_ENABLE_ENABLE_Enabled;

	i2cBaseReg = I2cGetBaseRegister(i2c);

	i2cBaseReg->ENABLE = enable ? enableValue : TWIM_ENABLE_ENABLE_Disabled;
}

//======================================================================
/*!
@brief	IRQ handler for I2C.
@detail
Each I2C interface has an interrupt vector. This is a common handler for all
of them. The parameter identifies the specific instance, which can be directly
related to a I2cEnum.

@param systemID	Idenfier (ordinal number) for the I2C interrupt source.

@author	John Heaney
@test	05/07/2020 Unit Test: UNTESTED
*/
static void irq_handler(UINT8 systemID)
{
	I2cEnum			i2c;
	NRF_TWIM_Type *	i2cBaseReg;
	ErrorCodeEnum	errCode;
	UINT32			i2cError;
	EventData		eventData;

	//Go from the systemID to its base register.
	i2c = i2cReferences[systemID];
	i2cBaseReg = I2cGetBaseRegister(i2c);

	//Check for errors first.
	if (i2cBaseReg->EVENTS_ERROR)
	{
		i2cBaseReg->EVENTS_ERROR = 0;

		i2cError = i2cBaseReg->ERRORSRC;
		if (TWIM_ERRORSRC_OVERRUN_Msk & i2cError)
		{
			errCode	= I2C_ERROR_OVERRUN;
		}
		else if (TWIM_ERRORSRC_ANACK_Msk & i2cError)
		{
			i2cBaseReg->ERRORSRC = TWIM_ERRORSRC_ANACK_Msk;
			errCode	= I2C_ERROR_ADDR_NAK;
		}
		else if (TWIM_ERRORSRC_DNACK_Msk & i2cError)
		{
			i2cBaseReg->ERRORSRC = TWIM_ERRORSRC_DNACK_Msk;
			errCode	= I2C_ERROR_DATA_NAK;
		}
		else
		{
			errCode		= I2C_ERROR_UNKNOWN;
			i2cError	= ERROR_DATA_DEFAULT;
		}
		ErrorSetErrorWithData(errCode, (ErrorCodeData)i2cError);

		//Issue a stop after any errors.
		i2cBaseReg->TASKS_STOP = 1;
	}

	//Check for being done. Every interaction ends with a STOP.
	if (i2cBaseReg->EVENTS_STOPPED)
	{
		i2cBaseReg->EVENTS_STOPPED		= 0;

		//Event data is number of bytes transmitted. Determine the mode and which
		// amount to look at by looking at how the SHORTS register has been configured.
		eventData = TWIM_SHORTS_LASTRX_STOP_Msk == i2cBaseReg->SHORTS
			? i2cBaseReg->RXD.AMOUNT
			: i2cBaseReg->TXD.AMOUNT;

		//Handle the result in the main context.
		EventPostWithData(I2cGetDoneEvent(i2c), TASK_ANY, eventData);

		//These are initialized at the start of each communication, but it doesn't
		// hurt to clean up at the end.
		i2cBaseReg->EVENTS_RXSTARTED	= 0;
		i2cBaseReg->EVENTS_TXSTARTED	= 0;
		i2cBaseReg->EVENTS_LASTRX		= 0;
		i2cBaseReg->EVENTS_LASTTX		= 0;
		i2cBaseReg->SHORTS				= 0;

		//All done with the interface. Power it down.
		I2cEnable(i2c, FALSE);
	}
}

Parents Reply Children
Related