cancel
Showing results for 
Search instead for 
Did you mean: 

I2C errors and interrupts

Mttjcksn
Associate III

Hi there,

I'm using the STM32H7 to talk to a CS2000 clock chip over I2C. I'm using interrupt mode.

I'm just trying to read the chip's ID register for starters. Despite the CS2000 ACKing the first 'setup write' byte, it won't write the second byte (with the register address). The peripheral also just reports as busy from that point onwards, and neither the error or event interrupts are triggered.

I used CubeMX to set it up, but here's my code:

I2C Init:

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 = 0x306062D1;
  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();
  }
  /** 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 */
 
}

Interrupts:

void I2C1_EV_IRQHandler(void)
{
  /* USER CODE BEGIN I2C1_EV_IRQn 0 */
 
  /* USER CODE END I2C1_EV_IRQn 0 */
  HAL_I2C_EV_IRQHandler(&hi2c1);
  /* USER CODE BEGIN I2C1_EV_IRQn 1 */
 
  /* USER CODE END I2C1_EV_IRQn 1 */
}
 
/**
  * @brief This function handles I2C1 error interrupt.
  */
void I2C1_ER_IRQHandler(void)
{
  /* USER CODE BEGIN I2C1_ER_IRQn 0 */
 
  /* USER CODE END I2C1_ER_IRQn 0 */
  HAL_I2C_ER_IRQHandler(&hi2c1);
  /* USER CODE BEGIN I2C1_ER_IRQn 1 */
 
  /* USER CODE END I2C1_ER_IRQn 1 */
}

Trying to read the ID:

uint8_t tx_buff[3] = {CS2000_REG_ID, 0, 0};
	uint8_t rx_buff[3] = {0, 0, 0};
 
 
	/* Check the device ID */
 
    if(HAL_I2C_Master_Transmit_IT(&hi2c1, CS2000_I2C_ADDRESS, (uint8_t*)tx_buff, 1)!= HAL_OK)
    {
      /* Error_Handler() function is called when error occurs. */
      Error_Handler();
    }
 
    /* Wait for data to be sent */
    while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY);
 
 
    if(HAL_I2C_Master_Receive_IT(&hi2c1, CS2000_I2C_ADDRESS, (uint8_t *)rx_buff, 1) != HAL_OK)
    {
      /* Error_Handler() function is called when error occurs. */
      Error_Handler();
    }
 
    /* Wait until data has been received */
    while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)
    {
    }

In the errata it mentions spurious errors, but that would generate an interrupt, which I'm not seeing. The state of the peripheral is always 'BUSY_TX'

Any ideas?

Cheers!

2 REPLIES 2
Mttjcksn
Associate III

Well, I managed to get it working by setting the interrupt priority to 0. The problem is that I'm using FreeRTOS, and the interrupt will need to use the FreeRTOS functions, so the interrupt must not have a priority higher than 5.

Does anybody have any experience with this issue?

Thanks

S.Ma
Principal

This seems to be OS specifics, surely the OS uses MCU resources such as timeslice, etc.. and there should be a OS manual on how not to screw what's running.

If you don't care about speed, just implement as a first step a GPIO bit bang I2C master bus. As master control the clock, even if the bus is paused by interrupt, it won't be causing any issue. Then, once your application and slave device is working, either you optimize and burn time on the HW I2C, or move forward.