cancel
Showing results for 
Search instead for 
Did you mean: 

AS5600 I2C Communication

V.D.T:
Associate

Hi.

I am trying to communicate with AS5600 Position Sensor. We are using I2C communication for this purpose. Using STM32F439ZIT6 chip , running chip at 168 MHZ clock. 

We are sommunicating with the sensor at Fast mode 400000 speed. Connection seems OK while there is no problem. But somehow when HAL turns error we lose alot of time to recover. At our main loop our cycle goes up to 50 ms ( tickresult)  while trying to recover. Can you help me what I am doing wrong and what could be the source of this time loss.

 

 

HAL_StatusTypeDef I2C_ResetBus(I2C_HandleTypeDef* hi2c)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // Configure SCL and SDA as GPIO outputs
    GPIO_InitStruct.Pin = MOTOR_SDA_Pin | MOTOR_SCL_Pin; // SCL and SDA pins
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    HAL_GPIO_Init(MOTOR_SCL_GPIO_Port, &GPIO_InitStruct); // GPIO port B

    // Generate 9 clock pulses to release any stuck slave device
    for (int i = 0; i < 9; i++) {
        HAL_GPIO_WritePin(MOTOR_SCL_GPIO_Port, MOTOR_SCL_Pin, GPIO_PIN_SET); // SCL high
        delay_us(10);
        HAL_GPIO_WritePin(MOTOR_SCL_GPIO_Port, MOTOR_SCL_Pin, GPIO_PIN_RESET); // SCL low
        delay_us(10);
    }

    // Generate a STOP condition
    HAL_GPIO_WritePin(MOTOR_SDA_GPIO_Port, MOTOR_SDA_Pin, GPIO_PIN_RESET); // SDA low
    delay_us(10);
    HAL_GPIO_WritePin(MOTOR_SCL_GPIO_Port, MOTOR_SCL_Pin, GPIO_PIN_SET); // SCL high
    delay_us(10);
    HAL_GPIO_WritePin(MOTOR_SDA_GPIO_Port, MOTOR_SDA_Pin, GPIO_PIN_SET); // SDA high
    delay_us(10);

    // Reconfigure SCL and SDA as I2C pins
    GPIO_InitStruct.Pin = MOTOR_SDA_Pin | MOTOR_SCL_Pin; // SCL and SDA pins
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; // I2C alternate function

    HAL_GPIO_Init(MOTOR_SCL_GPIO_Port, &GPIO_InitStruct); // GPIO port B

    // Reinitialize the I2C peripheral
    return HAL_I2C_Init(hi2c);
}
HAL_StatusTypeDef AS5600_get_angle(AS5600_TypeDef* const handle, uint16_t* const angle)
{
    uint8_t data[2] = {0};
    HAL_StatusTypeDef status = HAL_I2C_Mem_Read(handle->i2c_handle, AS5600_SHIFTED_SLAVE_ADDRESS, AS5600_REGISTER_ANGLE_HIGH, I2C_MEMADD_SIZE_8BIT, data, 2, handle->i2c_timeout);


    // If the I2C bus is busy, attempt recovery and retry
    if (status == HAL_BUSY) {
        // Attempt to reset the I2C bus
        if (I2C_ResetBus(handle->i2c_handle) != HAL_OK) {
            // If reset fails, return an error
            return HAL_ERROR;
        }

        // Retry reading after resetting the bus
        status = HAL_I2C_Mem_Read(handle->i2c_handle, AS5600_SHIFTED_SLAVE_ADDRESS, AS5600_REGISTER_ANGLE_HIGH, I2C_MEMADD_SIZE_8BIT, data, 2, handle->i2c_timeout);

    }


    // Check for other error statuses
    if (status != HAL_OK) {
        return status;
    }

    // If successful, compute the angle
    *angle = ((data[0] << 8) | data[1]);
    return HAL_OK;
}
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

	  tick1 = HAL_GetTick();


	  AS5600_get_angle(&as5600_instance, &angle);


	  tick2 = HAL_GetTick();

	  tickresult = tick2 - tick1;
  }

 

 

I also tried to implement  IT for non blocking comm. But somehow it performs worse than blocking comm.

Here is what I did

 

volatile uint8_t i2c_transfer_complete = 0; 
uint8_t data[2] = {0};                     
HAL_StatusTypeDef AS5600_get_angle(AS5600_TypeDef* const handle, uint16_t* const angle)
{
    HAL_StatusTypeDef status;

    // Start the non-blocking I2C read operation
    status = HAL_I2C_Mem_Read_IT(handle->i2c_handle, 
                                 AS5600_SHIFTED_SLAVE_ADDRESS, 
                                 AS5600_REGISTER_ANGLE_HIGH, 
                                 I2C_MEMADD_SIZE_8BIT, 
                                 data, 
                                 2);

    if (status != HAL_OK)
    {
        return status; // Return if the read operation fails
    }

    // Wait for the transfer to complete
    uint32_t start_time = HAL_GetTick();
    while (!i2c_transfer_complete)
    {
        // Add a 3ms timeout to prevent infinite looping
        if ((HAL_GetTick() - start_time) > 3)
        {
            return HAL_TIMEOUT;
        }
    }

    // Reset the completion flag for the next operation
    i2c_transfer_complete = 0;

    // Process the received data
    *angle = ((data[0] << 8) | data[1]);

    return HAL_OK;
}

 

 

 

void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
    if (hi2c->Instance == I2C1) 
    {
        i2c_transfer_complete = 1; // Mark transfer as complete
    }
}

 

 

 

void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
{
    if (hi2c->Instance == I2C1) 
    {
        // Optionally reset the I2C bus if needed
        I2C_ResetBus(hi2c);

    }
}

 

 

Thanks.

 

 

0 REPLIES 0