2018-10-30 06:21 AM
Hi there! I am actually fighting again i2c communication on the B-L072Z-LRWAN1 evaluation board (STM32L072CZ). Basically I would like to interface a NXP MMA8652 accelerometer over the I2C bus. I was able to do that (get the "who am I" register, get x/y/z acceleration values) with an Arduino board but could not get it properly run on the ST. I can actually see the 100kHz SCL/SDA on the scope but the accelerometer only answers 0xff to all requests.
I used CubeMX to set the board, (I2C base freq is 2,048MHz), and based my code on the "I2C_TwoBoards_AdvComIT" example from ST.
The code is pretty simple, IT based.
Init:
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x00000708;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
Read:
uint8_t MMA8652_read(uint8_t address)
{
uint8_t aTransferRequest[2];
// Ask
// ##-5- Master sends read request for slave ##############################
do
{
if(HAL_I2C_Master_Transmit_IT(&hi2c1, (uint16_t)I2C_ADDRESS, (uint8_t*)&address, 1)!= HAL_OK)
{
Error_Handler();
}
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
{
}
}
while(HAL_I2C_GetError(&hi2c1) == HAL_I2C_ERROR_AF);
// Get
//##-7- Master receives aRxBuffer from slave #############################
do
{
if(HAL_I2C_Master_Receive_IT(&hi2c1, (uint16_t)I2C_ADDRESS, (uint8_t*)aTransferRequest, 1)!= HAL_OK)
{
Error_Handler();
}
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
{
}
}
while(HAL_I2C_GetError(&hi2c1) == HAL_I2C_ERROR_AF);
return aTransferRequest[0];
}
Here is the "detect accelerometer" function: the MMA8652 (address 0x1D) has a "who_am_i" register (address 0x0D) that should contains 0x4A.
From Arduino:
From the ST:
Did I miss something?
Thanks!
Bezac
Solved! Go to Solution.
2019-04-24 12:59 AM
Ouch! I cannot believe how lot I let this unsolved!
Long story short: the device (slave) actually has multiple byte read capability. It uses repeated start condition (generally "SR") and thus requires the *sequential* transmit function :
do
{
if(HAL_I2C_Master_Sequential_Transmit_IT(&Handle, (uint16_t)I2C_ADDRESS, (uint8_t*)aTxBuffer, 2, I2C_FIRST_FRAME)!= HAL_OK)
Error_Handler();
while (HAL_I2C_GetState(&Handle) != HAL_I2C_STATE_READY)
;
}
while(HAL_I2C_GetError(&Handle) == HAL_I2C_ERROR_AF);
That's all folk!
2018-10-30 08:50 AM
Just to add that PB8/9 are used (so alternate function 4):
/**I2C1 GPIO Configuration
PB9 ------> I2C1_SDA
PB8 ------> I2C1_SCL
*/
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
2018-10-30 02:05 PM
Got an I2C 128x64 OLED running off the LRWAN1-DISCO here, not using the IT variety.
From the scope it looks like the address has been shifted correctly on the ST implementation, ie I2C_ADDR =(0x1D << 1)
2018-10-31 01:51 AM
Thanks for the input Clive, the I2C address is indeed configured as you mentioned: (0x1D << 1). The data are not acknowledged when it is different, that actually shows that my i2C device is alive! Good to know.
It's now quite sure that the way to communicate, i.e. the way i2c is configured on the ST side, is to be ajusted.
Just in case, I gave a try with polling function (avoiding IT) and the result is (of course) similar. It is slightly faster though, which is hard to understand.
I am quite surprise of this long delay between pointing the register (in the previous scope-view: Write_1D, register 0D) and the request (Read_1D, Get_FF). This should actually be as fast as with the Arduino... I switched compiler options to size optimisation and no debug, the "delay" is shorter but still >200us. What's wrong here?
2019-04-24 12:59 AM
Ouch! I cannot believe how lot I let this unsolved!
Long story short: the device (slave) actually has multiple byte read capability. It uses repeated start condition (generally "SR") and thus requires the *sequential* transmit function :
do
{
if(HAL_I2C_Master_Sequential_Transmit_IT(&Handle, (uint16_t)I2C_ADDRESS, (uint8_t*)aTxBuffer, 2, I2C_FIRST_FRAME)!= HAL_OK)
Error_Handler();
while (HAL_I2C_GetState(&Handle) != HAL_I2C_STATE_READY)
;
}
while(HAL_I2C_GetError(&Handle) == HAL_I2C_ERROR_AF);
That's all folk!