I am using LSM6DSOX IMU sensor INT detection with NRF52-DK and have extra 400µA (PPK2 used) on my setup.
After a few days of nightmares I finally found that this is related to Errata 89. The documentation says that there is a workaround, but I can't figure out how to use it. Could you point out where I should put this code to get rid of the 400µA ? should I apply the workaround on every read/write operation?
...
#include "nrf_drv_twi.h"
#include "nrf_drv_gpiote.h"
#include "lsm6dsox_reg.h"
/* TWI instance, ID. and address for LSM6DSOX */
#define TWI_INSTANCE_ID 0
#define TWI_SDA_PIN 26
#define TWI_SCL_PIN 27
#define LSM6DSOX_INT_PIN 12
#define LSM6DSOX_INT_LED LED_1
#define LSM6DSOX_ADRRESS 0x6B
static stmdev_ctx_t dev_ctx;
static
const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);
void i2c_init(void);
int32_t i2c_LSM6DSOX_write(void * handle, uint8_t reg, uint8_t * bufp, uint16_t len);
int32_t i2c_LSM6DSOX_read(void * handle, uint8_t reg, uint8_t * bufp, uint16_t len);
/**@brief Function for initializing power management.
*/
static void power_management_init(void) {
ret_code_t err_code;
err_code = nrf_pwr_mgmt_init();
APP_ERROR_CHECK(err_code);
}
/**@brief Function for handling the idle state (main loop).
*
* @details If there is no pending log operation, then sleep until next the next event occurs.
*/
static void idle_state_handle(void) {
nrf_pwr_mgmt_run();
}
void LSM6DSOX_int_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
nrf_drv_gpiote_out_toggle(LSM6DSOX_INT_LED);
uint8_t MLC[8] = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00
};
//lsm6dsox_mlc_out_get(&dev_ctx, MLC);
}
/**
* @brief Function for configuring: LSM6DSOX_INT_PIN pin for input, LSM6DSOX_INT_LED pin for output,
* and configures GPIOTE to give an interrupt on pin change.
*/
static void gpio_init(void) {
ret_code_t err_code;
err_code = nrf_drv_gpiote_init();
APP_ERROR_CHECK(err_code);
nrf_drv_gpiote_out_config_t out_config = GPIOTE_CONFIG_OUT_SIMPLE(false);
err_code = nrf_drv_gpiote_out_init(LSM6DSOX_INT_LED, & out_config);
APP_ERROR_CHECK(err_code);
nrf_drv_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_TOGGLE(true);
err_code = nrf_drv_gpiote_in_init(LSM6DSOX_INT_PIN, & in_config, LSM6DSOX_int_pin_handler);
APP_ERROR_CHECK(err_code);
nrf_drv_gpiote_in_event_enable(LSM6DSOX_INT_PIN, true);
}
int main(void) {
power_management_init();
/*
ble_stack_init();
advertising_init();
advertising_start();
*/
i2c_init();
gpio_init();
/*
* Initialize mems driver interface
*/
dev_ctx.write_reg = i2c_LSM6DSOX_write;
dev_ctx.read_reg = i2c_LSM6DSOX_read;
dev_ctx.handle = NULL;
/* Check device ID */
uint8_t whoamI = 0;
lsm6dsox_device_id_get( & dev_ctx, & whoamI);
if (whoamI == LSM6DSOX_ID) {
...
}
for (;;) {
idle_state_handle();
}
}
/**
* @brief Function for i2c bus init.
*
* @param none
*
*/
void i2c_init() {
ret_code_t err_code;
const nrf_drv_twi_config_t twi_config = {
.scl = TWI_SCL_PIN,
.sda = TWI_SDA_PIN,
.frequency = (nrf_drv_twi_frequency_t) NRF_TWI_FREQ_400K,
.interrupt_priority = APP_IRQ_PRIORITY_LOW,
.clear_bus_init = true
};
err_code = nrf_drv_twi_init( & m_twi, & twi_config, NULL, NULL);
APP_ERROR_CHECK(err_code);
nrf_drv_twi_enable( & m_twi);
nrf_drv_twi_disable( & m_twi);
nrf_drv_twi_uninit( & m_twi);
// Nordic work around to prevent burning excess power due to chip errata
// Use 0x400043FFC for TWI0. TODO: here right?
*(volatile uint32_t * ) 0x400043FFC = 0;
*(volatile uint32_t * ) 0x400043FFC;
*(volatile uint32_t * ) 0x400043FFC = 1;
err_code = nrf_drv_twi_init( & m_twi, & twi_config, NULL, NULL);
APP_ERROR_CHECK(err_code);
nrf_drv_twi_enable( & m_twi);
}
/**
* @brief Write generic device register (LSM6DSOX requirement)
*
* @param handle customizable argument. In this case is used in
* order to select the correct sensor bus handler.
* @param reg register to write
* @param bufp pointer to data to write in register reg
* @param len number of consecutive register to write
*
* @retval status: 0 means no Error
*/
int32_t i2c_LSM6DSOX_write(void * handle, uint8_t reg, uint8_t * bufp, uint16_t len) {
while (nrf_drv_twi_is_busy( & m_twi)) {}
uint8_t reg_tmp[100] = {
0
};
reg_tmp[0] = reg;
memcpy( & (reg_tmp[1]), bufp, len);
uint32_t status = nrf_drv_twi_tx( & m_twi, LSM6DSOX_ADRRESS, reg_tmp, len + 1, false);
if (status != NRF_SUCCESS) {
return status;
}
status = nrf_drv_twi_tx( & m_twi, LSM6DSOX_ADRRESS, & (reg_tmp[0]), 1, true);
if (status != NRF_SUCCESS) {
return status;
}
// TODO: Nordic Errata 89 workaround here?
return status;
}
/**
* @brief Read generic device register (LSM6DSOX requirement)
*
* @param handle customizable argument. In this case is used in
* order to select the correct sensor bus handler.
* @param reg register to read
* @param bufp pointer to buffer that store the data read
* @param len number of consecutive register to read
*
* @retval status: 0 means no Error
*/
int32_t i2c_LSM6DSOX_read(void * handle, uint8_t reg, uint8_t * bufp, uint16_t len) {
uint8_t preg = reg;
uint32_t status = nrf_drv_twi_tx( & m_twi, LSM6DSOX_ADRRESS, & preg, 1, true);
if (status != NRF_SUCCESS) {
return status;
}
status = nrf_drv_twi_rx( & m_twi, LSM6DSOX_ADRRESS, bufp, len);
if (status != NRF_SUCCESS) {
return status;
}
// TODO: Nordic Errata 89 workaround here?
return status;
}