I'm developing a mpu6050 library for learning purposes. To do so, I am using an stm32 mcu and I have created functions to read and write to its registers. They are as follows:
static IOStatus_t Stm32f767zi_I2C_Write(uint8_t Address,uint32_t Size,uint8_t* DataPtr)
{
IOStatus_t Status = IO_SUCCESS;
HAL_StatusTypeDef HAL_Status;
uint8_t* WritePointer = (uint8_t*) malloc(Size+1);
memcpy(WritePointer,&Address,1);
memcpy(WritePointer+1,DataPtr,Size);
HAL_Status = HAL_I2C_Master_Transmit(&hi2c2, MPU6050_I2C_ADDRESS<<1, WritePointer, Size+1, 100);
free(WritePointer);
if (HAL_Status != HAL_OK)
{
Status = IO_FAILURE;
}
return Status;
}
static IOStatus_t Stm32f767zi_I2C_Read(uint8_t Address,uint32_t Size,uint8_t* DataPtr)
{
IOStatus_t Status = IO_SUCCESS;
HAL_StatusTypeDef HAL_Status;
HAL_Status = HAL_I2C_Master_Transmit(&hi2c2, MPU6050_I2C_ADDRESS<<1, &Address, 1, 100);
HAL_Delay(1);
if (HAL_Status == HAL_OK)
{
HAL_Status = HAL_I2C_Master_Receive(&hi2c2, MPU6050_I2C_ADDRESS<<1, DataPtr, Size, 100);
if (HAL_Status != HAL_OK)
{
Status = IO_FAILURE;
}
}
return Status;
}
Then I use this small code to test these functions:
uint8_t RxData;
uint8_t ID;
Stm32f767zi_I2C_Read(REG_WHO_AM_I,1,&ID);
Stm32f767zi_I2C_Write(REG_SAMPLE_RATE_DIVIDER,1,&ID);
Stm32f767zi_I2C_Read(REG_SAMPLE_RATE_DIVIDER,1,&RxData);
Reading the "who am i" register gives me the i2c address of the mpu6050, so I have proved that the reading function works fine. The write to the "sample rate divider" register however doesn't, as when I try to read the value back after having written to it i only get 0x00. I chose this register for writing tests since all its bits are settable. All HAL calls return HAL_OK so I think my requests are being acked by the slave?
What could cause this problem? How come I can read but not write? It's even more strange considering that I use HAL_I2C_Master_Transmit() successfully in the read function. Could the device be locked for writing in some way? I have confirmed that this register is read/write and (among other things) I have tried separating the call to HAL_I2C_Master_Transmit() into two different calls (one for each byte), but nothing seems to work. I have sent the same data through UART to verify that the pointers I use work and they do, so I really don't know what I'm missing here.
The timing diagram for a Single-Byte Write Sequence specified in the reference manual is:
Turns out yes, the device was "locked".
Mpu6050 has a "SLEEP" bit in its "PWR_MGMT_1" register that is set by default and prevents the registers from being written to.
Removing this bit before calling Stm32f767zi_I2C_Write(REG_SAMPLE_RATE_DIVIDER,1,&ID);
solved the problem for me