diff --git a/cores/arduino/stm32/twi.c b/cores/arduino/stm32/twi.c index ccd633fb40..82ab7df28d 100644 --- a/cores/arduino/stm32/twi.c +++ b/cores/arduino/stm32/twi.c @@ -75,6 +75,8 @@ #define SLAVE_MODE_TRANSMIT 0 #define SLAVE_MODE_RECEIVE 1 +#define SLAVE_MODE_LISTEN 2 + /** * @} @@ -261,7 +263,12 @@ void i2c_custom_init(i2c_t *obj, i2c_timing_e timing, uint32_t addressingMode, u handle->Init.Timing = timing; #else handle->Init.ClockSpeed = timing; - handle->Init.DutyCycle = I2C_DUTYCYCLE_2; + /* Standard mode (sm) is up to 100kHz, then it's Fast mode (fm) */ + /* In fast mode duty cyble bit must be set in CCR register */ + if(timing > 100000) + handle->Init.DutyCycle = I2C_DUTYCYCLE_16_9; + else + handle->Init.DutyCycle = I2C_DUTYCYCLE_2; #endif handle->Init.OwnAddress1 = ownAddress; handle->Init.OwnAddress2 = 0xFF; @@ -283,6 +290,9 @@ void i2c_custom_init(i2c_t *obj, i2c_timing_e timing, uint32_t addressingMode, u HAL_I2C_Init(handle); obj->isMaster = master; + /* Initialize default values */ + obj->slaveRxNbData = 0; + obj->slaveMode = SLAVE_MODE_LISTEN; } /** @@ -326,6 +336,12 @@ void i2c_setTiming(i2c_t *obj, uint32_t frequency) obj->handle.Init.Timing = f; #else obj->handle.Init.ClockSpeed = f; + /* Standard mode (sm) is up to 100kHz, then it's Fast mode (fm) */ + /* In fast mode duty cyble bit must be set in CCR register */ + if(frequency > 100000) + obj->handle.Init.DutyCycle = I2C_DUTYCYCLE_16_9; + else + obj->handle.Init.DutyCycle = I2C_DUTYCYCLE_2; #endif /* else if(frequency <= 600000) @@ -395,9 +411,10 @@ i2c_status_e i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint16_t size) // Check the communication status for(i = 0; i < size; i++) { obj->i2cTxRxBuffer[i] = *(data+i); - obj->i2cTxRxBufferSize++; } + obj->i2cTxRxBufferSize = size; + return I2C_OK; } @@ -509,8 +526,6 @@ void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, ui if(AddrMatchCode == hi2c->Init.OwnAddress1) { if(TransferDirection == I2C_DIRECTION_RECEIVE) { - - obj->i2cTxRxBufferSize = 0; obj->slaveMode = SLAVE_MODE_TRANSMIT; if(obj->i2c_onSlaveTransmit != NULL) { @@ -519,9 +534,12 @@ void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, ui HAL_I2C_Slave_Sequential_Transmit_IT(hi2c, obj->i2cTxRxBuffer, obj->i2cTxRxBufferSize, I2C_LAST_FRAME); } else { + obj->slaveRxNbData = 0; obj->slaveMode = SLAVE_MODE_RECEIVE; - HAL_I2C_Slave_Sequential_Receive_IT(hi2c, obj->i2cTxRxBuffer, - I2C_TXRX_BUFFER_SIZE, I2C_LAST_FRAME); + /* We don't know in advance how many bytes will be sent by master so + * we'll fetch one by one until master ends the sequence */ + HAL_I2C_Slave_Sequential_Receive_IT(hi2c, &(obj->i2cTxRxBuffer[obj->slaveRxNbData]), + 1, I2C_NEXT_FRAME); } } } @@ -534,19 +552,56 @@ void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, ui */ void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c) { - uint8_t nbData = 0; i2c_t *obj = get_i2c_obj(hi2c); + /* Previous master transaction now ended, so inform upper layer if needed + * then prepare for listening to next request */ if((obj->i2c_onSlaveReceive != NULL) && (obj->slaveMode == SLAVE_MODE_RECEIVE)) { - nbData = I2C_TXRX_BUFFER_SIZE - obj->handle.XferSize; - if(nbData != 0) { - obj->i2c_onSlaveReceive(obj->i2cTxRxBuffer, nbData); + if(obj->slaveRxNbData != 0) { + obj->i2c_onSlaveReceive(obj->i2cTxRxBuffer, obj->slaveRxNbData); } } + obj->slaveMode = SLAVE_MODE_LISTEN; + obj->slaveRxNbData = 0; HAL_I2C_EnableListen_IT(hi2c); } +/** + * @brief Slave RX complete callback + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c) +{ + i2c_t *obj = get_i2c_obj(hi2c); + /* One more byte was received, store it then prepare next */ + if(obj->slaveRxNbData < I2C_TXRX_BUFFER_SIZE) { + obj->slaveRxNbData++; + } else { + printf("ERROR: I2C Slave RX overflow\n"); + } + /* Restart interrupt mode for next Byte */ + if(obj->slaveMode == SLAVE_MODE_RECEIVE) { + HAL_I2C_Slave_Sequential_Receive_IT(hi2c, &(obj->i2cTxRxBuffer[obj->slaveRxNbData]), + 1, I2C_NEXT_FRAME); + } +} + +/** + * @brief Slave TX complete callback + * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains + * the configuration information for the specified I2C. + * @retval None + */ +void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c) +{ + i2c_t *obj = get_i2c_obj(hi2c); + /* Reset transmit buffer size */ + obj->i2cTxRxBufferSize = 0; +} + /** * @brief I2C error callback. * @note In master mode, the callback is not used because the error is reported diff --git a/cores/arduino/stm32/twi.h b/cores/arduino/stm32/twi.h index 809ac36d95..c347e872a8 100644 --- a/cores/arduino/stm32/twi.h +++ b/cores/arduino/stm32/twi.h @@ -91,12 +91,13 @@ struct i2c_s { #if !defined(STM32F0xx) && !defined(STM32L0xx) IRQn_Type irqER; #endif //!defined(STM32F0xx) && !defined(STM32L0xx) - uint8_t slaveMode; + volatile uint8_t slaveMode; uint8_t isMaster; + volatile int slaveRxNbData; // Number of accumulated bytes received in Slave mode void (*i2c_onSlaveReceive)(uint8_t *, int); void (*i2c_onSlaveTransmit)(void); - uint8_t i2cTxRxBuffer[I2C_TXRX_BUFFER_SIZE]; - uint8_t i2cTxRxBufferSize; + volatile uint8_t i2cTxRxBuffer[I2C_TXRX_BUFFER_SIZE]; + volatile uint8_t i2cTxRxBufferSize; }; ///@brief I2C state