STM32F4 I2C与DMA无法正常工作

时间:2017-12-07 23:08:10

标签: stm32 i2c dma

我正在使用一个STM32F4,我想与我的LSM303加速度计通信。为此,我使用I2C,只是使用I2C工作正常,但当我尝试使用DMA时,它停止工作。 当我使用HAL_I2C_Master_Transmit_DMA它工作,我得到了IRQHandler和。但是在那之后,我想使用HAL_I2C_Master_Receive_DMA,它说I2C的状态还没准备好...... 我读到I2C与STM32FX搞混了,但我不明白为什么没有DMA就能正常工作。

当它遇到Master_Transmit_DMA的回调I2C_DMAXferCplt时,它表示I2C_HandleTypeDef的CurrentState仍然等于HAL_I2C_STATE_BUSY_TX,因此它不会将状态恢复为READY。这就是为什么当我调用Master_Receive_DMA时它没有收到任何东西。

这是我的I2C init:

    void MX_I2C2_Init(void)
      {
          I2C_ST_INS.Instance = I2C2;
          I2C_ST_INS.Init.ClockSpeed = 400000;
           I2C_ST_INS.Init.DutyCycle = I2C_DUTYCYCLE_2;
           I2C_ST_INS.Init.OwnAddress1 = 0;
          I2C_ST_INS.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
          I2C_ST_INS.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED;
          I2C_ST_INS.Init.OwnAddress2 = 0;
          I2C_ST_INS.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED;
          I2C_ST_INS.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED;

          HAL_I2C_Init(&I2C_ST_INS);

        }

   void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
   {
          GPIO_InitTypeDef GPIO_InitStruct;
          if(i2cHandle->Instance==I2C1)
          {
              //Not useful for this post
          }
          else if(i2cHandle->Instance==I2C2)
          {

            GPIO_InitStruct.Pin = MASTER_IMUB_I2C_SDA_Pin|MASTER_IMUB_I2C_SCL_Pin;
            GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
            GPIO_InitStruct.Pull = GPIO_PULLUP;
            GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
            GPIO_InitStruct.Alternate = GPIO_AF4_I2C2;
            HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

        __HAL_RCC_I2C2_CLK_ENABLE();

            /* DMA controller clock enable */
            __HAL_RCC_DMA1_CLK_ENABLE();
            hdma_i2c2_rx.Instance = DMA1_Stream2;
            hdma_i2c2_rx.Init.Channel = DMA_CHANNEL_7;
            hdma_i2c2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
            hdma_i2c2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
            hdma_i2c2_rx.Init.MemInc = DMA_MINC_ENABLE;
            hdma_i2c2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
            hdma_i2c2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
            hdma_i2c2_rx.Init.Mode = DMA_NORMAL;
            hdma_i2c2_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
            hdma_i2c2_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
            hdma_i2c2_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
            hdma_i2c2_rx.Init.MemBurst = DMA_MBURST_SINGLE;
            hdma_i2c2_rx.Init.PeriphBurst = DMA_PBURST_SINGLE;
            if (HAL_DMA_Init(&hdma_i2c2_rx) != HAL_OK)
            {
              Error_Handler();
            }
            __HAL_LINKDMA(i2cHandle,hdmarx,hdma_i2c2_rx);

            HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 0, 0);
           HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn);


            hdma_i2c2_tx.Instance = DMA1_Stream7;
            hdma_i2c2_tx.Init.Channel = DMA_CHANNEL_7;
            hdma_i2c2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
            hdma_i2c2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
            hdma_i2c2_tx.Init.MemInc = DMA_MINC_ENABLE;
            hdma_i2c2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
            hdma_i2c2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
            hdma_i2c2_tx.Init.Mode = DMA_NORMAL;
            hdma_i2c2_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
            hdma_i2c2_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
            hdma_i2c2_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
            hdma_i2c2_tx.Init.MemBurst = DMA_MBURST_SINGLE;
            hdma_i2c2_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
            if (HAL_DMA_Init(&hdma_i2c2_tx) != HAL_OK)
            {
              Error_Handler();
            }

            __HAL_LINKDMA(i2cHandle,hdmatx,hdma_i2c2_tx);

           HAL_NVIC_SetPriority(DMA1_Stream7_IRQn, 0, 0);
           HAL_NVIC_EnableIRQ(DMA1_Stream7_IRQn);
          }
        }

当我使用带I2C的DMA时,你有什么想法吗?

谢谢,

维克多

3 个答案:

答案 0 :(得分:1)

当我在DMA中断之上启用I2C_event中断时,它为我工作,请参见下面的生成的代码和CubeMX配置

HAL_NVIC_SetPriority(I2C1_EV_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);

My CubeMX configuration, notice that the event interrupt is checked

选择DMA时,CubeMX不会自动检查I2C1事件全局中断,我认为应该这样做(意法半导体(STmicro)请解决此问题),因为我看不到没有它如何工作。

答案 1 :(得分:0)

我遇到了同样的问题。我已经通过降低频率来解决它。

ST勘误文件说,您必须将I2C频率降低到 88kHz 才能解决其他问题。

我知道它并不能解释为什么在阻塞模式下不会发生此错误,而是在DMA中发生此错误,但我希望它会有所帮助。

答案 2 :(得分:0)

我一直在 STM32F407 I2C1 上遇到相同的问题。

在搜索程序流程中的潜在错误之后,我发现函数HAL_I2C_Master_Transmit_DMA导致以下行:

dmaxferstatus = HAL_DMA_Start_IT(hi2c->hdmatx, (uint32_t)hi2c->pBuffPtr, (uint32_t)&hi2c->Instance->DR, hi2c->XferSize);

第一次传输后,它不会返回HAL_OK,这对于继续传输是必需的。

因此,我的解决方案是简单地中止传输完成后调用的回调函数中的前一个DMA中断。 HAL_I2C_Master_Receive_DMA可以暗示相同的含义。为了解决该问题,我在main.c中添加了以下回调函数:

void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
    if (hi2c->Instance==hi2c1.Instance)
    {
        HAL_DMA_Abort_IT(hi2c->hdmatx);
    }
}

void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
    if (hi2c->Instance==hi2c1.Instance)
    {
        HAL_DMA_Abort_IT(hi2c->hdmarx);
    }
}

请考虑这只是一种解决方法。如果有人发现,我想进一步了解此错误的根本原因。