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

Excessive power usage when using i2c/twi

Hi

We are developing a project where we are using a peripheral over i2c, specifically a lis3dh accelerometer. However we have encountered a problem and would be really grateful for any help you could provide.

Whenever we start to read or write to the i2c bus we are seeing excessive power usage on the order of several hundred micro-amperes. This excessive power usage also occurs if we try to use the accelerometer via the lis2dh driver.

I tried applying the fix from errata 89 to see if that helped, but that caused a crash in the nrf twi driver with the message: "<err> i2c_nrfx_twi: Error on I2C line occurred for message 0"

The hardware we are using is an nrf5832, and we are using the nrf connect sdk v2.4.99

Because of we are running on a board with other peripherals that need to be configured I can unfortunately not attach a complete build-able project, but I've isolated the problem to the below line of code, marked with a comment:

#define LIS3DH_REG_INT1SRC 0x31
#define I2C0_LABEL DT_LABEL(DT_NODELABEL(i2c0))

#define LIS3DH_I2C_ADDRESS (0x19) // SA0 pulled high

const struct device *g_i2c_dev;



static uint8_t accReadRegister(uint8_t address)
{

	struct i2c_msg msgs[2];

	/* Setup I2C messages */

	/* Send the address to read */
	msgs[0].buf = &address;
	msgs[0].len = 1U;
	msgs[0].flags = I2C_MSG_WRITE;

	/* Read from device. RESTART as neededm and STOP after this. */
	uint8_t data[55];
	msgs[1].buf = data;
	msgs[1].len = 2U;
	msgs[1].flags = I2C_MSG_READ | I2C_MSG_RESTART | I2C_MSG_STOP;

	int read_succ = i2c_transfer(g_i2c_dev, &msgs[0], 2, LIS3DH_I2C_ADDRESS);
	__ASSERT(read_succ == 0, "read from accel failed");

	//k_sleep(K_MSEC(100)); // For some reason necessary

	return 0;
}

int main(void)
{

	//Important that accelerometer is completely powered
	k_sleep(K_MSEC(10));

	g_i2c_dev = device_get_binding(I2C0_LABEL);
	// not needed, trigger without or without these lines
	uint32_t i2c_cfg = I2C_SPEED_SET(I2C_SPEED_STANDARD) | I2C_MODE_MASTER;
	int conf_i2c_ret = i2c_configure(g_i2c_dev, i2c_cfg);
	__ASSERT(conf_i2c_ret == 0, "failed to configure i2c");
	// end not needed
	accReadRegister(LIS3DH_REG_INT1SRC); //this line triggers the problem, a write also triggers it
	while(true){
		k_sleep(K_MSEC(100));
	}
	return;
}


The relevant part of the prj.conf

# accelerometer
CONFIG_I2C=y
CONFIG_PM_DEVICE=y
CONFIG_DEVICE_POWER_MANAGEMENT=y
CONFIG_PM_DEVICE_IDLE=y

Parents
  • Hi

    Can you specify just how large the excess current consumption you see is? If it's ~400uA it does indeed seem like the erratum 89 is what's causing this, but it should be implemented for nRF52832 projects in the nRFConnect SDK from C:\...\NCS_FOLDER\vx.x.x\modules\hal\nordic\nrfx\mdk\nrf52_erratas.h. If it seems like this is it, please try implementing the fix as it is done in nrf52_erratas.h instead of how it's described in the Infocenter, as that's the workaround how it should be used in the nRF5 SDK.

    Best regards,

    Simon

Reply
  • Hi

    Can you specify just how large the excess current consumption you see is? If it's ~400uA it does indeed seem like the erratum 89 is what's causing this, but it should be implemented for nRF52832 projects in the nRFConnect SDK from C:\...\NCS_FOLDER\vx.x.x\modules\hal\nordic\nrfx\mdk\nrf52_erratas.h. If it seems like this is it, please try implementing the fix as it is done in nrf52_erratas.h instead of how it's described in the Infocenter, as that's the workaround how it should be used in the nRF5 SDK.

    Best regards,

    Simon

Children
  • Hi

    Thanks for taking the time to look at this.

    The excess current consumption is about ~270microamps

    As you asked I have now checked and the above errata code is executed and returns true. It had/has no effect on the excess current.

    My understanding is that the i2c bus will use about ~200microamps when active. Could it be that it never goes in-active after having transmitted the data? If so what is the correct way to tell it to do so?

    Best Regards
    Poorp

  • Edit: I was mistaken with my previous information, updated the post with the correct information

    We've managed to narrow down the problem further. But I'm not sure why we're seeing the behavior we're seeing,

    The problem only occurs if we configure i2c, write or read from it, AND setup a pin interrupt on one of the gpioe to trigger on an edge.

    That is if we set the trigger to GPIO_INT_LEVEL_LOW, instead of e.g GPIO_INT_EDGE_FALLING, the problem does not occur.
    I don't believe that it is caused by interference triggering the interrupt, because I added a print statement to the example code interrupt (see "triggered" below) and that doesn't get triggered except e.g when the button is pushed.

    What particular pin the interrupt is configured for doesn't seem to matter, we've tried pin 25, 29 and 6 all with the same effect. Pin 25 is connected to a button, and 29 and 6 are not connected on our board.

    static void trigger_reset_polling(const struct device *dev, struct gpio_callback *cb,
    		    uint32_t pins)
    {
    	LOG_INF("triggered");
    }
    
    
    void reset_init(void)
    {
    	reset_button_dev = device_get_binding(RESET_LABEL);
    	__ASSERT(reset_button_dev != NULL, "error device not found");
    
    	int const conf_ret = gpio_pin_configure(reset_button_dev, RESET_PIN, GPIO_INPUT | RESET_FLAGS);
    	__ASSERT(conf_ret == 0, "Failed to configure pin, error: %d", conf_ret);
    
    	int const inter_ret = gpio_pin_interrupt_configure(reset_button_dev,
    					   RESET_PIN,
    					   GPIO_INT_EDGE_FALLING);
    	__ASSERT(inter_ret == 0, "Failed to configure interrupt");
    
    	gpio_init_callback(&reset_cb_data, trigger_reset_polling, BIT(RESET_PIN));
    	gpio_add_callback(reset_button_dev, &reset_cb_data);
    	LOG_DBG("Set up button at %s pin %d\n", RESET_LABEL, RESET_PIN);
    
    	k_work_init(&detect_reset_work, detect_reset);
    }

Related