cancel
Showing results for 
Search instead for 
Did you mean: 

Trouble setting I2C device registers

CGrov.1
Associate II

I am using an STM32L476 to run an MMC5983MA magnetometer and a LIS2HH12 accelerometer, using I2C. The devices are initialised using the STM cube generated code, then the registers are set, and then checked. When I check the accelerometer registers, they are read back correctly, but the magnetometer registers always return 0x97 which is the device address with the R/W bit high. I've checked the write command signal using a scope, and both the accelerometer and magnetometer are sending the correct waveforms. The accelerometer read waveform gives the correct result, but the magnetometer returns the device's read address instead of data.

Write to magnetometer code:

void set_MAG_Regs(){
	printf("\n\r");
	printf("Setting Mag Registers... \n\r");
	int i=0, err=0;//error counter
 
 
 
	for(i=0; i<4; i++){
 
	uint8_t reg_addr[] = {0x09,0x0A,0x0B,0x0C};
	uint8_t reg_data[] = {0x29,0x00,0xBA,0x00};
 
	if(HAL_I2C_Mem_Write(&hi2c1,Comp_Addr,reg_addr[i], sizeof(uint8_t) ,(uint8_t*)&reg_data[i] ,sizeof(uint8_t), HAL_MAX_DELAY) != HAL_OK){
				Error_Handler();
				printf("Error Setting Mag Register %d \n\r", i);
				err++;
			}
	if(err==0){
		 printf("Magnetometer Register %d set \n\r", i);
		}
	}
 
if(err == 0){
	printf("All Magnetometer Registers Set \n\r \n\r");
} else if(err==4) {
	printf("Failed to set all Mag Registers \n\r");
}
 
	printf("\n\r");
 
}

To check the magnetometer registers I use:

void check_mag_regs(){
 
	for(int i=0; i<4;i++){
		uint8_t reg_adr[4] = {0x09, 0x0A, 0x0B, 0x0C};
		uint8_t value[4];
		if (HAL_I2C_Mem_Read(&hi2c1, Comp_Addr , reg_adr[i], sizeof(uint8_t),&value[i], sizeof(uint8_t), HAL_MAX_DELAY) != HAL_OK){//(uint8_t*)(&data_name[i])
						printf("Could not check mag register \n\r");
					}
 
 
		printf(" mag reg %d: %d\n\r", i, value[i]);
	}
 
 
}

I wonder if I am actually writing the magnetometers address with R/W bit high, into the registers rather than the data I want?

4 REPLIES 4
TDK
Guru

If the waveforms on the I2C wires are correct, doesn't that mean the issue is with the magnetometer? Or with your understanding of how it operates?

Or are you saying the scope trace shows values different from what HAL_I2C_Mem_Read returns?

You're passing sizeof(uint8_t) as the address size, which happens to work here but only because I2C_MEMADD_SIZE_8BIT == 1.

If you feel a post has answered your question, please click "Accept as Solution".
CGrov.1
Associate II

I think you are right, I might not fully understand how it operates. I am fairly confident that the magnetometer is functioning correctly because I am able to establish and I2C connection and read the device ID. When writing to the magnetometer registers it follows the form ([slave address R/W bit low] : [ control register address] : [data written]) with each section being 9 bits long. This is exactly the same as the accelerometer which I know is functioning correctly. To read the data it follows the form ([ slave address R/W bit low] : [ data register address] : [ Slave address R/W bit high] : [ data read]). These are the waveforms I have been observing on the scope.

My understanding was that the I2C protocol was fairly universal, so both slave devices should follow the same form to read and write to them. I haven't spotted anything in the DS for either device, what could the difference be?

Also, is there a better way than passing sizeof(uint8_t)? I was thinking that would be the size of the address, but should I just put 1 instead?

TDK
Guru

> is there a better way than passing sizeof(uint8_t)? 

You should put I2C_MEMADD_SIZE_8BIT.

If you feel a post has answered your question, please click "Accept as Solution".