cancel
Showing results for 
Search instead for 
Did you mean: 

Why does I2C get stuck with HAL_BUSY state?

JBond.1
Senior

Hi, I am trying to read MPU6050 FIFO data with STM32F103C8T6 after I get an interrupt from MPU6050. All works well at start, but after some time I2C gets stuck with HAL_BUSY state and never recovers from it. Here is my code:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  uint16_t count = MPU6050_GetFIFOCount(); // uses HAL_I2C_Mem_Read
  if (count == MPU6050_DMP_PACKET_SIZE)
  {
    // uses HAL_I2C_Mem_Read_DMA non-blocking to read 28 bytes
    HAL_I2C_Mem_Read_DMA(&hi2c1, MPU6050_ADDRESS, MPU6050_RA_FIFO_R_W, 1, fifoBuffer, MPU6050_DMP_PACKET_SIZE);
  }
  else if (count > MPU6050_DMP_PACKET_SIZE)
  {
    MPU6050_ResetFIFO(); // uses HAL_I2C_Mem_Write
  }
}

Am I doing something wrong? What could be causing I2C get stuck with HAL_BUSY state and never recover?

4 REPLIES 4
TDK
Guru

Is this the only function where you call HAL_I2C_*? Doing so from the main thread as well as in interrupts will eventually fail.

It is generally bad form to call blocking functions within an interrupt, although it's not necessarily causing any issues.

You should be checking for a HAL_OK return value from these functions, especially if you're having issues.

How do you ensure the transaction started by HAL_I2C_Mem_Read_DMA is completed before the next call to HAL_I2C_*?

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

I don't call HAL_I2C_* after interrupt setup.

If I would call HAL_I2C_* again while HAL_I2C_Mem_Read_DMA isn't finished I would expect it would be HAL_BUSY, but after several attempts (when HAL_I2C_Mem_Read_DMA finaly finishes) it would succeed with HAL_OK. But in my example status HAL_BUSY never clears. Its HAL_BUSY forever.

I would like to do it on interrupt, because on my main thread I am doing longer tasks like writing to file, so it could lose some data from MPU6050 if main thread is busy. If I shouldn't do blocking tasks on interrupts what would be the better solution in my case?

I have found another solution, which seem to reinitialize I2C. Also I have reduced sample rate coming from MPU6050. Does this code still have flaws?

#define SAMPLE_RATE 8
static uint8_t SampleCount = SAMPLE_RATE;
 
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  // read only every 8 (SAMPLE_RATE) interrupt to reduce load
  if (SampleCount >= SAMPLE_RATE)
  {
    uint16_t count;
    // uses HAL_I2C_Mem_Read to get count
    if (ReadWord(MPU6050_ADDRESS, MPU6050_RA_FIFO_COUNTH, &count) == HAL_OK)
    {
      if (count == MPU6050_DMP_PACKET_SIZE)
      {
        // uses HAL_I2C_Mem_Read_DMA non-blocking to read 28 bytes
        HAL_I2C_Mem_Read_DMA(&hi2c1, MPU6050_ADDRESS, MPU6050_RA_FIFO_R_W, 1, fifoBuffer, MPU6050_DMP_PACKET_SIZE);
        SampleCount = 0;
      }
      else if (count > MPU6050_DMP_PACKET_SIZE)
      {
        // uses HAL_I2C_Mem_Write to reset FIFO
        WriteByte(MPU6050_ADDRESS, MPU6050_RA_USER_CTRL, 0xC4);
        SampleCount = 0;
      }
    }
    else
    {
      // reinit I2C if HAL_I2C_Mem_Read did not get HAL_OK
      HAL_I2C_DeInit(&hi2c1);
      HAL_I2C_Init(&hi2c1);
      SampleCount = 0;
    }
  }
  else
  {
    // skip interrupt
    SampleCount++;
  }
}

Also how to check if HAL_I2C_Mem_Read_DMA has finished work?

Is this might be caused by DMA I2C_DMAXferCplt which might be not called?

For some reason MPU6050 does not send data?