ICM-20948’s Magnetometer (AK09916) Not Accessible Via ICM-20948’s I2C Master

Hi,

I purchased a ICM-20948 breakout board (https://www.sparkfun.com/products/15335) and I am using breadboard and jumper wires to hook it up to Nucleo - L476RG STM32 development board (https://www.digikey.com/en/products/det … RG/5347711) for development and prototyping. I am basing my code on https://github.com/sparkfun/SparkFun_IC … inoLibrary to setup Accel, Gyro and Mag and read raw sensor data. I am able to read Accel and Gyro raw data successfully and also if I bypass I2C Master feature in ICM-20948 I can even directly communicate and read raw data from onboard AK09916 magnetometer using my MCU.

Now I want to use the I2C Master feature in ICM-20948 such that ICM20948 reads data from AK09916 and I can then use my MCU to read all sensor data from ICM20948. I have tried disabling the I2C Master bypass and following the code at https://github.com/sparkfun/SparkFun_IC … 8_C.c#L169 to setup SLV4 but no matter what I do I can’t seem to make ICM20948 communicate with AK09916 to read it’s ID. When I try to read WIA2 register of AK09916 using ICM-20948 I only get 0x00. What could I be doing incorrectly?

Thanks,

N

I started with the Arduino Pro Mini, the ICM-20948 sensor and Sparkfun’s library, and had no problems at all collecting data, calibrating all the sensors, and putting everything together in a Mahony fusion filter package.

It did took an afternoon of work, though. https://github.com/jremington/ICM_20948-AHRS

Ok so this is what I have tried so far

These are my register definitions

/////////////////ALL THE IMPORTANT REGISTERS//////////////////////
static const uint8_t ICM20946_ADDR_W = 0xD2;
static const uint8_t ICM20946_ADDR_R = 0xD3;
static const uint8_t USRBANK_SEL_REG = 0x7F;
static const uint8_t USRBANK_REG_VAL[4] = {0x00, 0x10, 0x20, 0x30};


////////////////IMPORTANT USER BANK 0 REGISTERS///////////////////
static const uint8_t UB0_WHOAMI_REG = 0x00;
static const uint8_t UB0_USER_CTRL = 0x03;
static const uint8_t UB0_LP_CONFIG = 0x05;
static const uint8_t UB0_PWR_MGMT_1 = 0x06;
static const uint8_t UB0_PWR_MGMT_2 = 0x07;
static const uint8_t UB0_INT_PIN_CFG = 0x0F;
static const uint8_t UB0_I2C_MST_STATUS = 0x17;
static const uint8_t UB0_INT_STATUS_1 = 0x1A;
static const uint8_t UB0_ACCEL_XOUT_H = 0x2D;
static const uint8_t UB0_EXT_SLV_SENS_DATA_00 = 0x3B;
////////////////IMPORTANT USER BANK 0 REGISTERS///////////////////

////////////////IMPORTANT USER BANK 2 REGISTERS///////////////////
static const uint8_t UB2_GYRO_SMPLRT_DIV = 0x00;
static const uint8_t UB2_GYRO_CONFIG_1 = 0x01;
static const uint8_t UB2_ACCEL_SMPLRT_DIV_1 = 0x10;
static const uint8_t UB2_ACCEL_SMPLRT_DIV_2 = 0x11;
static const uint8_t UB2_ACCEL_CONFIG = 0x14;
////////////////IMPORTANT USER BANK 2 REGISTERS///////////////////

////////////////IMPORTANT USER BANK 3 REGISTERS///////////////////
static const uint8_t UB3_I2C_MST_CTRL = 0x01;
static const uint8_t UB3_I2C_SLV0_ADDR = 0x03;
static const uint8_t UB3_I2C_SLV0_REG = 0x04;
static const uint8_t UB3_I2C_SLV0_CTRL = 0x05;
static const uint8_t UB3_I2C_SLV0_DO = 0x06;
static const uint8_t UB3_I2C_SLV4_ADDR = 0x13;
static const uint8_t UB3_I2C_SLV4_REG = 0x14;
static const uint8_t UB3_I2C_SLV4_CTRL = 0x15;
static const uint8_t UB3_I2C_SLV4_DO = 0x16;
static const uint8_t UB3_I2C_SLV4_DI = 0x17;
////////////////IMPORTANT USER BANK 3 REGISTERS///////////////////

/////////////////MAGNETOMETER REGISTERS///////////////////////////
static const uint8_t AK09916_ADDR = 0x0C;
static const uint8_t AK09916_WIA1 = 0x00;
static const uint8_t AK09916_WIA2 = 0x01;
static const uint8_t AK09916_ST1 = 0x10;
static const uint8_t AK09916_CNTL2 = 0x31;
static const uint8_t AK09916_CNTL3 = 0x32;
static const uint8_t AK09916_READ_MASK = 0x01;
static const uint8_t AK09916_WRITE_MASK = 0x00;
static const uint8_t I2CMASTER_READ_MASK = 0x80;
static const uint8_t I2CMASTER_WRITE_MASK = 0x00;
/////////////////MAGNETOMETER REGISTERS///////////////////////////

These are my mag config and mag read start function

bool Icm20948ConfigMag(I2C_HandleTypeDef *hi2c){
	HAL_StatusTypeDef ret_;
	bool success = true;
	uint8_t tmp;

	// Disable I2C Master Passthrough
	success &= Ic20948DisableI2cMstPassThrough(hi2c);

	//Enable I2C Master
	success &= Ic20948EnableI2cMst(hi2c);

	//Reset I2C Master
//	success &= Ic20948ResetI2cMst(hi2c);

	// Configure I2C Master
	tmp = 0x17;
	Icm20948ChangeRegBank(hi2c, 3);
	ret_ = Icm20948Write(hi2c, ICM20946_ADDR_W, UB3_I2C_MST_CTRL, (uint8_t *)&tmp, 1, icm_i2c_wait_time_ms_);
	success &= (ret_ == HAL_OK);

	//Reset Mag
	tmp = 0x01;
	success &= Icm20948Slv4ReadWriteByte(hi2c, AK09916_CNTL3, false, (uint8_t *)&tmp);

	// Verify MAG ID
	success &= Icm20948Slv4ReadWriteByte(hi2c, AK09916_WIA2, true, (uint8_t *)&tmp);
	if(tmp != 0x09){
		return false;
	}

	// Setup mag to read continuously at 100Hz
	tmp = 0x08;
	success &= Icm20948Slv4ReadWriteByte(hi2c, AK09916_CNTL2, false, (uint8_t *)&tmp);
	HAL_Delay(5);
	return success;

}

bool Icm20948StartSlv0MagRead(I2C_HandleTypeDef *hi2c){
	uint8_t tmp;
	HAL_StatusTypeDef ret_;
	bool success = true;

	//Configure SLV0 to read data from mag
	tmp = (I2CMASTER_READ_MASK | AK09916_ADDR);
	Icm20948ChangeRegBank(hi2c, 3);
	ret_ = Icm20948Write(hi2c, ICM20946_ADDR_W, UB3_I2C_SLV0_ADDR, (uint8_t *)&tmp, 1, icm_i2c_wait_time_ms_);
	success &= (ret_ == HAL_OK);
	HAL_Delay(1);

	tmp = AK09916_ST1;
	ret_ = Icm20948Write(hi2c, ICM20946_ADDR_W, UB3_I2C_SLV0_REG, (uint8_t *)&tmp, 1, icm_i2c_wait_time_ms_);
	success &= (ret_ == HAL_OK);
	HAL_Delay(1);

	// Start the txn
	tmp = 0x89;
	ret_ = Icm20948Write(hi2c, ICM20946_ADDR_W, UB3_I2C_SLV0_CTRL, (uint8_t *)&tmp, 1, icm_i2c_wait_time_ms_);
	success &= (ret_ == HAL_OK);
	HAL_Delay(10);


	return success;
}

bool Icm20948Slv4ReadWriteByte(I2C_HandleTypeDef *hi2c, uint8_t reg, bool read, uint8_t *pData){
	uint8_t tmp;
	bool success = true;
	HAL_StatusTypeDef ret_;

	// Write mag address to SLV4_ADDR
	tmp = (((read) ? I2CMASTER_READ_MASK : I2CMASTER_WRITE_MASK) | AK09916_ADDR);
	Icm20948ChangeRegBank(hi2c, 3);
	ret_ = Icm20948Write(hi2c, ICM20946_ADDR_W, UB3_I2C_SLV4_ADDR, (uint8_t *)&tmp, 1, icm_i2c_wait_time_ms_);
	success &= (ret_ == HAL_OK);

	// Write mag register to write to and the data to write;
	ret_ = Icm20948Write(hi2c, ICM20946_ADDR_W, UB3_I2C_SLV4_REG, (uint8_t *)&reg, 1, icm_i2c_wait_time_ms_);
	success &= (ret_ == HAL_OK);

	if(!read){
		ret_ = Icm20948Write(hi2c, ICM20946_ADDR_W, UB3_I2C_SLV4_DO, pData, 1, icm_i2c_wait_time_ms_);
		success &= (ret_ == HAL_OK);
	}

	// Start the txn
	tmp = 0x80;
	ret_ = Icm20948Write(hi2c, ICM20946_ADDR_W, UB3_I2C_SLV4_CTRL, (uint8_t *)&tmp, 1, icm_i2c_wait_time_ms_);
	success &= (ret_ == HAL_OK);
	HAL_Delay(10);

	Icm20948ChangeRegBank(hi2c, 0);
	ret_ = Icm20948Read(hi2c, ICM20946_ADDR_R, UB0_I2C_MST_STATUS, (uint8_t *)&tmp, 1, icm_i2c_wait_time_ms_);
	success &= (ret_ == HAL_OK);

	//Make sure the txn was complete
	if(tmp != 0x40){
		return false;
	}

	if(read){
		Icm20948ChangeRegBank(hi2c, 3);
		ret_ = Icm20948Read(hi2c, ICM20946_ADDR_R, UB3_I2C_SLV4_DI, pData, 1, icm_i2c_wait_time_ms_);
		success &= (ret_ == HAL_OK);
	}

	return success;
}

bool Icm20948Init(I2C_HandleTypeDef *hi2c){
	bool success = true;
	if(Icm20948TestConnection(hi2c)){
		success = success & Icm20948SwReset(hi2c);
		success = success & Icm20948ConfigAccels(hi2c);
		success = success & Icm20948ConfigGyros(hi2c);
		success = success & Icm20948ConfigMag(hi2c);
		success = success & Icm20948StartSlv0MagRead(hi2c);
		success = success & Icm20948SetSampleMode(hi2c);

		if(success){
			return true;
		}else{
			return false;
		}
	}

	return false;
}

Now I am able to read the Mag ID but when I start reading the mag value is stuck at the start value and every start has different value. I feel like the I2C Master read is not running continuously. Any insights?

So got it working by moving the Mag initialization before setting the sampling mode and also setting the I2C Master Mode to duty cycle. Not exactly sure why this works but atleast this unblocks me.