2016-11-17 09:22 AM
Hello
In stm32L1 Cube lib 1.6. In the interrupt handling of a transfer complete on i2c in slave mode with DMA, the HAL_DMA_IRQHandler(...) calls XferCpltCallback(...) which points to I2C_DMAXferCplt (...). This is the function:static void I2C_DMAXferCplt(DMA_HandleTypeDef* hdma) {
I2C_HandleTypeDef* hi2c = (I2C_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent;
if ((hi2c->State == HAL_I2C_STATE_BUSY_TX) || ((hi2c->State == HAL_I2C_STATE_BUSY_RX) && (hi2c->Mode == HAL_I2C_MODE_SLAVE))) {
/* Disable DMA Request */
CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN);
hi2c->XferCount = 0U;
/* Enable EVT and ERR interrupt */
__HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR);
} else {
/* Disable Acknowledge */
CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);
/* Generate Stop */
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
/* Disable Last DMA */
CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_LAST);
/* Disable DMA Request */
CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN);
hi2c->XferCount = 0U;
/* Check if Errors has been detected during transfer */
if (hi2c->ErrorCode != HAL_I2C_ERROR_NONE) {
HAL_I2C_ErrorCallback(hi2c);
} else {
hi2c->State = HAL_I2C_STATE_READY;
if (hi2c->Mode == HAL_I2C_MODE_MEM) {
hi2c->Mode = HAL_I2C_MODE_NONE;
HAL_I2C_MemRxCpltCallback(hi2c);
} else {
hi2c->Mode = HAL_I2C_MODE_NONE;
HAL_I2C_MasterRxCpltCallback(hi2c);
}
}
}
}
In the discussed context, hi2c->state is HAL_I2C_STATE_BUSY_TX .
What I think to be a bug is that, in this case, the hi2c->state is not modified by
the function while the transfer has completed.
Is suspect that the code should more look like this:
static void I2C_DMAXferCplt(DMA_HandleTypeDef* hdma) {
I2C_HandleTypeDef* hi2c = (I2C_HandleTypeDef*) ((DMA_HandleTypeDef*) hdma)->Parent;
if ((hi2c->State == HAL_I2C_STATE_BUSY_TX) || ((hi2c->State == HAL_I2C_STATE_BUSY_RX) && (hi2c->Mode == HAL_I2C_MODE_SLAVE))) {
/* Disable DMA Request */
CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN);
hi2c->XferCount = 0U;
/* Enable EVT and ERR interrupt */
__HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR);
} else {
/* Disable Acknowledge */
CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);
/* Generate Stop */
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
/* Disable Last DMA */
CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_LAST);
/* Disable DMA Request */
CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN);
hi2c->XferCount = 0U;
}
/* Check if Errors has been detected during transfer */
if (hi2c->ErrorCode != HAL_I2C_ERROR_NONE) {
HAL_I2C_ErrorCallback(hi2c);
} else {
hi2c->State = HAL_I2C_STATE_READY;
if (hi2c->Mode == HAL_I2C_MODE_MEM) {
hi2c->Mode = HAL_I2C_MODE_NONE;
HAL_I2C_MemRxCpltCallback(hi2c);
} else {
hi2c->Mode = HAL_I2C_MODE_NONE;
HAL_I2C_MasterRxCpltCallback(hi2c);
}
}
}
What do you think about it?
Regards
Julien
#dma #stm32l1 #i2c