Skip to main content
shane mattner
Senior
July 8, 2020
Solved

STM32MP1: I2C timeout on M4 core

  • July 8, 2020
  • 1 reply
  • 1175 views

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

This topic has been closed for replies.
Best answer by TDK

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?

1 reply

TDK
TDKBest answer
Super User
July 9, 2020

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""."
shane mattner
Senior
July 9, 2020

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