You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32 HAL库中如何用DMA循环模式执行I2C_Mem_Read_DMA读取MPU9250?

能否用HAL_I2C_Mem_Read_DMA实现MPU9250的DMA循环读取?

不能直接通过HAL_I2C_Mem_Read_DMA实现DMA循环读取,原因和解决方案如下:

问题根源

  1. HAL_I2C_Mem_Read_DMA的设计限制:这个函数本质是完成单次I2C内存读取事务——先通过TX DMA发送目标寄存器地址,再切换到RX DMA接收数据。事务完成后,HAL库会自动停止DMA通道并调用回调函数,即使你配置了DMA循环模式,也会被HAL的逻辑覆盖。
  2. 配置对象错误:你设置的是hdma_i2c1_tx.Init.Mode = DMA_CIRCULAR;,但HAL_I2C_Mem_Read_DMA的接收阶段使用的是RX DMA通道,这个配置对接收过程的DMA模式没有影响。

可行解决方案

方案一:利用回调函数模拟循环读取

这是最贴合HAL库框架的做法,在每次读取完成的回调中重新启动DMA读取:

  • 确保RX DMA通道配置为DMA_NORMAL模式(不需要循环,靠回调触发下一次读取)
  • 实现HAL_I2C_MemRxCpltCallback回调函数:
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
    if(hi2c->Instance == I2C1)
    {
        // 此处处理刚读取到的mpu9250_rawdata数据
        // 重新启动DMA读取,实现循环
        HAL_I2C_Mem_Read_DMA(&hi2c1, I2C_SLV_ADDR << 1, ACCEL_XOUT_H_ADDR, I2C_MEMADD_SIZE_8BIT, mpu9250_rawdata, 14);
    }
}

方案二:手动操作寄存器实现真循环DMA读取

绕开HAL库的单次事务限制,直接控制I2C和DMA寄存器:

  1. 确保MPU9250的寄存器自动递增功能开启(默认开启,可通过USER_CTRL寄存器确认)
  2. 先手动发送一次目标寄存器地址(阻塞模式即可),告诉MPU9250后续读取的起始位置
  3. 配置RX DMA通道为DMA_CIRCULAR模式,然后启动I2C DMA接收:
// 手动发送寄存器地址(阻塞模式,仅执行一次)
HAL_I2C_Mem_Write(&hi2c1, I2C_SLV_ADDR << 1, ACCEL_XOUT_H_ADDR, I2C_MEMADD_SIZE_8BIT, NULL, 0, HAL_MAX_DELAY);

// 重新配置RX DMA为循环模式
hdma_i2c1_rx.Init.Mode = DMA_CIRCULAR;
HAL_DMA_Init(&hdma_i2c1_rx);

// 启动循环DMA接收
HAL_I2C_Receive_DMA(&hi2c1, mpu9250_rawdata, 14);

这种方式下,DMA会持续循环接收14字节数据,每次都会从MPU9250的当前寄存器地址(自动递增到起始地址)开始读取,完全由硬件自动完成,不需要软件触发。

内容的提问来源于stack exchange,提问作者Frog

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 07:13:23