STM32F4 I2C 与 DMA 不工作

Vic*_*uet 5 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 初始化:

    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);
          }
        }
Run Code Online (Sandbox Code Playgroud)

您知道为什么当我将 DMA 与 I2C 结合使用时它不起作用吗?

谢谢,

胜利者

小智 5

当我在 DMA 中断之上启用 I2C_event 中断时,它对我有用,请参阅下面的生成代码和 CubeMX 配置

HAL_NVIC_SetPriority(I2C1_EV_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
Run Code Online (Sandbox Code Playgroud)

我的CubeMX配置,注意检查了事件中断

选择 DMA 时,CubeMX 不会自动检查 I2C1 事件全局中断,我认为它应该(STmicro 请修复此问题),因为我不知道没有它它如何工作。


小智 1

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

ST Errata 文档指出您必须将 I2C 频率降低至88kHz才能解决其他一些问题。

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