cancel
Showing results for 
Search instead for 
Did you mean: 

Problem setting registers on I2C slave device

CGrov.1
Associate II

I've read through a couple other posts but haven't fount anything that helps me. I am trying to set some registers on a MMC5883 digital magnetometer and can't seem to write to the correct registers. I initialized I2C1 using the graphical Device Configuration Tool, the slave 7-bit address is 0x30. I have PB7 as SDA and PB6 as SCL.

When I go through the debugger the error seems to be at the "status = HAL …." line, as it never returns HAL_OK.

void set_MAG_Regs(){
 
	printf("setting mag slave registers... \n\r");
	HAL_StatusTypeDef status = HAL_OK;
	int i = 0;
	int data [3] = {0x08, 0x03, 0x01};//array of data to set registers
	int addr [3] = {0x08, 0x09, 0x0A};// array data location
 
	 int *register_value;//points to data[]
	 int *register_pointer;//points to addr []
	 register_value = &data[i];
	 register_pointer = &addr[i];
 
	for (i=0; i<4; i++){
 
	status = HAL_I2C_Mem_Write(&hi2c1, 0x30, (uint16_t)register_pointer, I2C_MEMADD_SIZE_16BIT,(uint8_t*)(&register_value), 2, HAL_MAX_DELAY);
 
	if (status != HAL_OK){
			//error handling
				Error_Handler();
				printf("Device failed to set registers \n\r");
		}
 
	i++;
 
	}
 
 
}

8 REPLIES 8
JoniS
Senior

try

status = HAL_I2C_Mem_Write(&hi2c1, (0x30 >> 1), (uint16_t)register_pointer, I2C_MEMADD_SIZE_16BIT,(uint8_t*)(&register_value), 2, HAL_MAX_DELAY);

i cant remember the exact reasoning behind it, but from the time i once used i2c, i believe you had to right shift 8bit value once to get the 7bit address correct.

CGrov.1
Associate II

That didn't solve it unfortunately. I did get an error that says "cast from pointer to integer of different size" and indicates the (uint16_t)register_pointer. I changed it to (uint32_t) and it seems to have gotten rid of the error but it's still not writing to registers.

S.Ma
Principal

Test this

uint8_t ID = 0x00;
uint8_t SlvAdr = 0x60; // if this doesn't work, try 0x60>>1
uint8_t SubAdr = 0x2F;
 
while(ID!=0x0C) {
status = HAL_I2C_Mem_Read(&hi2c1, SlvAdr, &SubAdr, I2C_MEMADD_SIZE_8BIT,(uint8_t*)(&ID), 1, HAL_MAX_DELAY);
};
 

CGrov.1
Associate II

That seems to work! If I understand that code correctly, its reading the data in register 0x2F from device 0x60 and storing it in ID. if I print the value stored in ID I get 536969155. What is the device 0x60? and what does this test?

Seb
ST Employee

The spec says the slave address is 0x60 (8 bit). Sometime functions require only 7 bits, so 0x30.

the slave use a 8 bit sub address. at location 0x2F you can read the chip ID which is expected to be 0x0C

You should exit the loop only when the device is detected correctly.

When you write or read 16 bit data, remember the first byte is LSB. (see datasheet).

CGrov.1
Associate II

Ahhh ok,I see what its doing now. In that case it is still not working, I thought it had solved that particular issue as it was returning HAL_OK. But it never actually exits that while loop so it must not be reading the chip ID correctly.

I added a line printf( "ID: %d \n\r", ID); inside the while loop to see what was being stored in ID, it only prints the decimal number 97.

I also get an error: "passing argument 3 of 'HAL_I2C_Mem_Read' makes integer from pointer without a cast", which corresponds to "&SubAdr".

   status = HAL_I2C_Mem_Read(&hi2c1, SlvAdr, &SubAdr, I2C_MEMADD_SIZE_8BIT, (uint8_t*)(&ID), 1, HAL_MAX_DELAY);
                                             

S.Ma
Principal

The HAL function headers are out of my head, so here consider it just pseudo code, guidance.

I use a different I2C implementation which is more generic and easier to understand, hence the poor memory on these HAL_I2C functions.

CGrov.1
Associate II

OK! thanks for your help. I've realized that the test is returning the device address rather than the device ID so I'm looking into that.

Can I ask what the more generic and easier method is?