AnsweredAssumed Answered

Possible bug in Cube Lib 1.6 with I2C / DMA

Question asked by JulienD on Nov 17, 2016
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

Outcomes