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); }
View more
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; }
View more

 

 

 

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.

 

 

1 REPLY 1
Pavel A.
Super User

Can you help me what I am doing wrong and what could be the source of this time loss.

The source of the time loss obviously is the I2C communication error which has to be recovered.

So you have to find the nature of the error: some error on the device side (it does not ACK when expected etc.), or it can be a glitch on I2C wires and so on. This is difficult to "debug" remotely without instruments.

Unfortunately, simplicity and "cheapness" of I2C electrical interface relays the cost to the higher software levels. In the worst case you'll have to double the sensor, together with its I2C interface (connect them to different I2C controllers).