cancel
Showing results for 
Search instead for 
Did you mean: 

STM32MP1: I2C timeout on M4 core

shane mattner
Associate III

Hardware: STM32MP157C-DK2, VL6180 breakout from Sparkfun

Software: CubeMX IDE (1.3.0), buildroot (following the guide from Bootlin here)

I'm trying to use the M4 core to communicate with an I2C sensor. I successfully talked with the sensor on the Linux side so I'm confident the wiring and hardware is good.

I edited the DTS to enable the m4_i2c5 per the example provided by ST.

&m4_i2c5 {
         pinctrl-names = "rproc_default";
         pinctrl-0 = <&i2c5_pins_a>;
         status = "okay";
};

I've also tried many variations of the following, with and without pinctrl statements:

&i2c5 {
       status = "disabled";
};
 
&m4_i2c5 {
      status = "okay";
};

From CubeMX IDE:

Main initialization and while(1):

/* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C5_Init();
  /* USER CODE BEGIN 2 */
	gpio_init_structure.Pin = GPIO_PIN_7 ;
	gpio_init_structure.Mode  = GPIO_MODE_OUTPUT_PP;
	gpio_init_structure.Pull  = GPIO_PULLUP;
	gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	HAL_GPIO_Init(GPIOH, &gpio_init_structure);
	HAL_GPIO_WritePin(GPIOH,GPIO_PIN_7,GPIO_PIN_SET);
 
 
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
	  HAL_Delay(1000);
	  HAL_GPIO_TogglePin(GPIOH, GPIO_PIN_7);
	  scan_i2c(&hi2c5, i2c_addresses);
 
  }
  /* USER CODE END 3 */
}

I2C initialization code generated by CubeMX:

static void MX_I2C5_Init(void)
{
 
  /* USER CODE BEGIN I2C5_Init 0 */
 
  /* USER CODE END I2C5_Init 0 */
 
  /* USER CODE BEGIN I2C5_Init 1 */
 
  /* USER CODE END I2C5_Init 1 */
  hi2c5.Instance = I2C5;
  hi2c5.Init.Timing = 0x40505874;
  hi2c5.Init.OwnAddress1 = 0;
  hi2c5.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c5.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c5.Init.OwnAddress2 = 0;
  hi2c5.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
  hi2c5.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c5.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c5) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Analogue filter 
  */
  if (HAL_I2CEx_ConfigAnalogFilter(&hi2c5, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Digital filter 
  */
  if (HAL_I2CEx_ConfigDigitalFilter(&hi2c5, 0) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C5_Init 2 */
 
  /* USER CODE END I2C5_Init 2 */
 
}

Function scanning for I2C devices (confirmed working with F0 Nucleo board):

void scan_i2c(I2C_HandleTypeDef *hi2c, uint8_t * addr)
{
	uint8_t t_count=0;
    for (int i=1; i<128; i++)
    {
    	HAL_StatusTypeDef result = HAL_I2C_IsDeviceReady(hi2c, (uint16_t)(i<<1), 2, 2);
		if (result == HAL_OK){
			addr[t_count] = i;
			t_count++;
		}
    }
}

Here is the ...IsDeviceReady()chunk that I timeout on:

HAL_StatusTypeDef HAL_I2C_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout)
{
  uint32_t tickstart;
 
  __IO uint32_t I2C_Trials = 0UL;
 
  FlagStatus tmp1;
  FlagStatus tmp2;
 
  if (hi2c->State == HAL_I2C_STATE_READY)
  {
    if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) == SET)
    {
      return HAL_BUSY;
    }
 
    /* Process Locked */
    __HAL_LOCK(hi2c);
 
    hi2c->State = HAL_I2C_STATE_BUSY;
    hi2c->ErrorCode = HAL_I2C_ERROR_NONE;
 
    do
    {
      /* Generate Start */
      hi2c->Instance->CR2 = I2C_GENERATE_START(hi2c->Init.AddressingMode, DevAddress);
 
      /* No need to Check TC flag, with AUTOEND mode the stop is automatically generated */
      /* Wait until STOPF flag is set or a NACK flag is set*/
      tickstart = HAL_GetTick();
 
      tmp1 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF);
      tmp2 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF);
 
      while ((tmp1 == RESET) && (tmp2 == RESET))
      {
        if (Timeout != HAL_MAX_DELAY)
        {
          if (((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
          {
            /* Update I2C state */
            hi2c->State = HAL_I2C_STATE_READY;
 
            /* Update I2C error code */
            hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;
 
            /* Process Unlocked */
            __HAL_UNLOCK(hi2c);
 
            return HAL_ERROR;
          }
        }

Any suggestions would be appreciated. From trying to get LD7 to blink I see that CubeMX is not taking care of all initialization. Could I need to do some manual initialization of the I2C5 peripheral?

Thank you

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

Do clocks get enabled and pins initialized correctly in HAL_I2C_MspInit?

A timeout could mean the SCL line is being held low. Can you verify the bus is free?

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

View solution in original post

2 REPLIES 2
TDK
Guru

Do clocks get enabled and pins initialized correctly in HAL_I2C_MspInit?

A timeout could mean the SCL line is being held low. Can you verify the bus is free?

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

Solved.

The problem was that CubeMX chose A1/Z1 for I2C5, whereas the pins I'm actually using are A11/A12. After remapping the pins in CubeMX I can see the sensor on the I2C bus. I was thinking that the A7 core was taking care of pin selection because in the DTS I called out certain pins. Apparently that is not the case.

Thanks for the response. Chalk up another win for following basic directions 🙂