cancel
Showing results for 
Search instead for 
Did you mean: 

I2C slave hangs randomly after many transactions

YPear.1
Associate II

STM32L432

I'm using interrupt mode HAL driver and the i2c slave responses successfully for many transactions but then will randomly hang. Here is the code I'm using, its fairly simple.

volatile uint8_t i2cbuf[2] = {0, 0};
 
static void MX_I2C1_Init(void)
{
 
  /* USER CODE BEGIN I2C1_Init 0 */
 
  /* USER CODE END I2C1_Init 0 */
 
  /* USER CODE BEGIN I2C1_Init 1 */
 
  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.Timing = 0x10909CEC;
  hi2c1.Init.OwnAddress1 = 84;
  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();
  }
  /** Configure Analogue filter
  */
  if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Digital filter
  */
  if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C1_Init 2 */
 
  /* USER CODE END I2C1_Init 2 */
}
 
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
{
  i2cbuf[0]++;
  i2cbuf[1]++;
  if (hi2c->Instance == I2C1)
  {
    if (HAL_I2C_Slave_Seq_Transmit_IT(hi2c, (uint8_t *)i2cbuf, 2, I2C_LAST_FRAME) != HAL_OK)
    {
    }
  }
}
 
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
{
  HAL_I2C_EnableListen_IT(hi2c);
}
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
{
  uint32_t err = HAL_I2C_GetError(hi2c);
  if (err != HAL_I2C_ERROR_NONE)
  {
    printf("error=%x\n", err);
    i2c_reinit();
  }
}
 
 
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_I2C1_Init();
  HAL_I2C_EnableListen_IT(&hi2c1);
  while(1){
  }
}

Any suggestions? The i2c slave's only required operation is to transmit 2 bytes

Also the i2c bus is low after the slave hangs

6 REPLIES 6
Bubbles
ST Employee

Hi @YPear.1​ ,

if SCL is held low, it may indicate clock stretching.

Slaves are using clock stretching to gain time to respond masters.

Use debugger and check I2C register flags and the hi2c structure to see what's going on.

J

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

YPear.1
Associate II

Clock stretching is enabled, but the slave does not have to stretch forever. As you can tell, the code is pretty simple but eventually hangs after a few hundred transactions.

YPear.1
Associate II

In polling mode, the slave does not hang this just affects IT mode.

Hi @YPear.1​ ,

yes, there should be a timeout set on stretching.

But when you enable debug interface and peek at the state when the hang appears, you should see what's the handle state and what's the state of the I2C IP registers. It should be pretty straightforward from there. I know from experience the HAL based IT operation can be very reliable when all corners are covered.

J

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

You are saying if I set a clock stretch timeout this will fix the problem?

There doesn't seem to be a way through the HAL to limit how long clock stretching can occur.