wiki:tnh:variable_length_i2c_slave_on_stm32_stm32l451
Table of Contents
STM32 I2C Slave dirty trick
Context
The STM32L451 HAL doesn't directly support variable length message RX/TX.
Default HAL behavior
The defaut behavior is described in the GraphViz render.
Modification
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode) { /* Slave matched his address */ if (TransferDirection != 0) { /* I2C Transmit buffer */ CSKB_I2C_Dir = I2C_TX; // Save in a global the current direction uint8_t framesize = (CSKB_I2C_NXT_FrameSize == 0) ? I2C_BUFFER_SIZE : CSKB_I2C_NXT_FrameSize; if (HAL_I2C_Slave_Seq_Transmit_IT(hi2c, (uint8_t *)CSKB_I2C_TX_BUFFER, framesize, I2C_FIRST_AND_LAST_FRAME) != HAL_OK) { /* Transfer error in transmission process */ Error_Handler(); } } else { CSKB_I2C_Dir = I2C_RX; // Save in a global the current direction /* I2C Receive on the rx buffer BUT we don't know the size beforehand */ if (HAL_I2C_Slave_Seq_Receive_IT(hi2c, (uint8_t *)CSKB_I2C_RX_BUFFER, I2C_BUFFER_SIZE, I2C_FIRST_AND_LAST_FRAME) != HAL_OK) { /* Transfer error in reception process */ Error_Handler(); } } }
Once we have those information we can try to use the final callback to handle everything we need.
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c) { /* Handling here incomplete RX/TX with dirty hack */ if (CSKB_I2C_Dir == I2C_TX) { CSKB_I2C_TX_Complete = 1; CSKB_I2C_TX_Size = (CSKB_I2C_NXT_FrameSize == 0) ? I2C_BUFFER_SIZE - hi2c->XferSize : CSKB_I2C_NXT_FrameSize - hi2c->XferSize; } else if (CSKB_I2C_Dir == I2C_RX) { CSKB_I2C_RX_Complete = 1; CSKB_I2C_RX_Size = I2C_BUFFER_SIZE - hi2c->XferSize; } CSKB_I2C_Dir = I2C_NONE; }
For some reason it appears that XferSize member of the I2C handle has the remaining count of byte (starting from the buffer size declared while calling HAL_I2C_Slave_Seq_Receive_IT or HAL_I2C_Slave_Seq_Transmit_IT);
wiki/tnh/variable_length_i2c_slave_on_stm32_stm32l451.txt · Last modified: 2022/09/11 09:36 by f4ihx