cancel
Showing results for 
Search instead for 
Did you mean: 

Problem configuring I2C on CMWX1ZZABZ (that is to say STM32L072CZ) for accelerometer MMA8652.

Bezac
Associate II

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:

0690X000006CHg9QAG.png

From the ST:

0690X000006CHgEQAW.png

Did I miss something?

Thanks!

Bezac

1 ACCEPTED SOLUTION

Accepted Solutions
Bezac
Associate II

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!

View solution in original post

4 REPLIES 4
Bezac
Associate II

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);

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)

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Bezac
Associate II

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?

Bezac
Associate II

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!