stm32f103 I2C DMA方式使用失败

作者尝试使用DMA方式提升STM32硬件I2C的性能,但在实际操作中遇到问题。主要表现为HAL_I2C_Master_Transmit_DMA与HAL_I2C_Master_Receive_DMA函数调用时出现总线繁忙的情况,以及HAL_I2C_Mem_Read_DMA无法正确读取值。已检查中断设置并确认逻辑分析仪显示数据已发送。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

正常使用STM32硬件I2C没有问题,本想尝试更好的方法比如DMA方式,却失败了。

这个问题已经看了两天了,思路也有很多,但都没能解决问题

1.该开的中断都已经开启比如DMA通道的中断,I2C事件中断都开启。

2.调用        

ret[4] = HAL_I2C_Master_Transmit_DMA(&hi2c1, Buf[4], Buf+6, 1);
i2cState = HAL_I2C_Master_Receive_DMA(&hi2c1, Buf[4], &ret[7], 1);

第二次读总是会返回BUSY,就是说还没发送完的感觉,但从逻辑分析仪上看是发送完了的。

3.还有HAL_I2C_Mem_Read_DMA调用这个接口,从逻辑分析仪上看波形,读取的寄存器的值都是对的,但传进去的参数却还是没有读到正确的值。


HAL库的版本也更新到最新的1.6.0

官方HAL库的文档也看过了,都没有帮助


暂时先放弃了,以后有时间再看,先记录下。

### STM32F103 I2C 使用 DMA 进行数据传输 对于STM32F103系列微控制器,在实现I2C通信时采用DMA可以显著提高效率并减少CPU负载。通过配置DMA来处理I2C的数据发送和接收操作,能够使系统更加高效稳定。 #### 配置I2C外设 为了启用DMA功能支持下的I2C通讯,首先需要初始化相应的硬件资源: - 启用必要的时钟源 - 设置GPIO引脚为AF模式,并连接到对应的I2C信号线(SCL, SDA) - 初始化I2C外设参数,包括波特率、地址格式等设置[^1] ```c // 开启APB1总线上I2C与时钟门控 __HAL_RCC_I2C1_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); // GPIO初始化结构体定义 GPIO_InitTypeDef GPIO_InitStruct = {0}; // PB8 -> I2C1_SCL; PB9 -> I2C1_SDA GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); // I2C初始化结构体定义 I2C_HandleTypeDef hi2c1; hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK){ // 错误处理... } ``` #### 配置DMA用于I2C传输 接下来就是配置DMA以配合I2C完成批量数据交换的任务: - 创建DMA句柄并与指定的流/通道关联起来 - 设定好缓冲区指针以及要传送字节数量的信息给DMA控制器 - 将DMA请求映射至特定事件触发条件之上以便启动自动化的数据搬运过程 ```c // 定义DMA句柄 DMA_HandleTypeDef hdma_i2c1_tx; DMA_HandleTypeDef hdma_i2c1_rx; // TX DMA Stream Configuration hdma_i2c1_tx.Instance = DMA1_Channel6; hdma_i2c1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_i2c1_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_i2c1_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_i2c1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_i2c1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_i2c1_tx.Init.Mode = DMA_NORMAL; hdma_i2c1_tx.Init.Priority = DMA_PRIORITY_LOW; if(HAL_DMA_Init(&hdma_i2c1_tx)!= HAL_OK){ // 错误处理... } // RX DMA Stream Configuration hdma_i2c1_rx.Instance = DMA1_Channel7; hdma_i2c1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_i2c1_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_i2c1_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_i2c1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_i2c1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_i2c1_rx.Init.Mode = DMA_NORMAL; hdma_i2c1_rx.Init.Priority = DMA_PRIORITY_LOW; if(HAL_DMA_Init(&hdma_i2c1_rx)!= HAL_OK){ // 错误处理... } // 关联DMAI2C实例 __HAL_LINKDMA(&hi2c1, hdmatx, hdma_i2c1_tx); __HAL_LINKDMA(&hi2c1, hdmarx, hdma_i2c1_rx); ``` #### 实现基于DMAI2C读写函数 最后一步是编写实际的应用程序逻辑部分,这里提供了一个简单的例子展示如何利用上述配置好的接口来进行带DMA加速特性的I2C设备访问操作: ```c uint8_t buffer[256]; // 数据缓存区 void WriteToSlave(uint8_t* data, uint16_t length){ if(HAL_I2C_Master_Transmit_DMA(&hi2c1, SLAVE_ADDR<<1, data, length) != HAL_OK){ // 发送失败后的错误处理机制 } } void ReadFromSlave(uint8_t* data, uint16_t length){ if(HAL_I2C_Master_Receive_DMA(&hi2c1, SLAVE_ADDR<<1, data, length) != HAL_OK){ // 接收失败后的错误处理机制 } } ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值