当前位置: 首页 > news >正文

第 4 章:串口驱动进阶——GPDMA + Idle 中断实现变长数据流接收

在第 3 章,我们通过 RIF 拿到了 UART7 的“所有权”。现在,我们要实现一个工业级的串口驱动。

为什么不用简单的HAL_UART_Receive_IT?因为在多核通讯或读取 IMU 数据时,数据长度往往是不固定的。频繁的字节中断会拖累 M33 的实时性,而简单的 DMA 传输又无法感知数据何时结束。

本章实战方案:利用 STM32MP257 全新的GPDMA (General Purpose DMA)结合 UART 的Idle Line(空闲总线)检测,实现一个“零拷贝、非阻塞、变长接收”的串口框架。


4.1 核心原理:为什么是 GPDMA + Idle?

  1. GPDMA:MP257 的 DMA 架构与传统 STM32 不同,它是基于通道索引和链接列表的,效率更高。

  2. Idle Line:当串口线路上超过一个字节的时间没有新数据时,硬件会自动触发 IDLE 中断。

  3. 组合拳:DMA 负责默默地把数据搬运到 RAM,IDLE 中断负责大喊一声:“报告 M33,这阵子数据传完了,请处理!”


4.2 实战:配置 GPDMA 接收通道

在 MP257 中,GPDMA 必须先进行 RIF 配置(如第 3 章所述),然后初始化。

UART_HandleTypeDef huart7;
DMA_HandleTypeDef hdma_uart7_rx;

void MX_UART7_DMA_Init(void) {
__HAL_RCC_GPDMA1_CLK_ENABLE();

// 配置 GPDMA1 Channel 0
hdma_uart7_rx.Instance = GPDMA1_Channel0;
hdma_uart7_rx.Init.Request = GPDMA1_REQUEST_UART7_RX; // 请求源
hdma_uart7_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_uart7_rx.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
hdma_uart7_rx.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
hdma_uart7_rx.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
hdma_uart7_rx.Init.Mode = DMA_NORMAL; // 建议用 Normal 模式,每次 IDLE 后重置

HAL_DMA_Init(&hdma_uart7_rx);
__HAL_LINKDMA(&huart7, hdmarx, hdma_uart7_rx);
}

4.3 实战:UART7 的初始化与 IDLE 中断开启

void MX_UART7_Init(void) {
huart7.Instance = UART7;
huart7.Init.BaudRate = 115200;
huart7.Init.WordLength = UART_WORDLENGTH_8B;
huart7.Init.StopBits = UART_STOPBITS_1;
huart7.Init.Parity = UART_PARITY_NONE;
huart7.Init.Mode = UART_MODE_TX_RX;
huart7.Init.HwFlowCtl = UART_HWCONTROL_NONE;

if (HAL_UART_Init(&huart7) != HAL_OK) {
Error_Handler();
}

// 重点:开启 IDLE 空闲中断
__HAL_UART_ENABLE_IT(&huart7, UART_IT_IDLE);

// 启动 DMA 接收(预设一个足够大的缓冲区)
HAL_UART_Receive_DMA(&huart7, rx_buffer, RX_BUF_SIZE);
}

4.4 深度实战:中断服务函数 (ISR) 的逻辑实现

这是整章的灵魂。在stm32mp2xx_it.c中,我们需要处理UART7_IRQHandler

#define RX_BUF_SIZE 512
uint8_t rx_buffer[RX_BUF_SIZE];

void UART7_IRQHandler(void) {
// 检查是否是 IDLE 中断
if (__HAL_UART_GET_FLAG(&huart7, UART_FLAG_IDLE)) {
__HAL_UART_CLEAR_IDLEFLAG(&huart7); // 必须手动清除

// 核心逻辑:计算接收了多少字节
// 剩余长度 = RX_BUF_SIZE - DMA 当前传输剩余值
uint32_t remaining = __HAL_DMA_GET_COUNTER(&hdma_uart7_rx);
uint32_t length = RX_BUF_SIZE - remaining;

// 停止当前 DMA 传输,处理数据
HAL_UART_DMAStop(&huart7);

// --- 处理接收到的数据 ---
// 例如:Process_Data(rx_buffer, length);
// 此处打印收到的字节数(实战中建议使用无锁队列转发)
printf("Received %ld bytes via DMA+IDLE\r\n", length);

// 再次开启 DMA,准备下一次接收
HAL_UART_Receive_DMA(&huart7, rx_buffer, RX_BUF_SIZE);
}
HAL_UART_IRQHandler(&huart7);
}

4.5 性能优化:如何做到“不丢包”?

在工业实战中,如果在处理Process_Data时串口又有新数据进来,DMA 还没开启,就会丢包。

进阶技巧:双缓冲区 (Double Buffering)

  1. 定义两个缓冲区Buf_ABuf_B

  2. DMA 指向Buf_A

  3. IDLE 中断触发后,立即将 DMA 指向Buf_B

  4. M33 在后台慢慢处理Buf_A的内容。 这样两个核/两个任务之间就形成了一个简单的乒乓切换,极大地提高了吞吐量。


4.6 部署与验证

  1. 接线:连接开发板的调试 Type-C(ST-Link 虚拟串口)。

  2. 发送测试:使用串口助手(如 Mobaxterm)发送一串很长的、长度随机的字符串。

  3. 结果:观察 M33 串口输出,它应该能精准报出每一帧数据的长度,并原样打印或处理。


4.7 避坑指南 (Debug Tips)

  • 陷阱 1:DMA 传输过快。如果波特率极高且数据连续,IDLE 中断可能来不及触发。此时应结合DMA 半完成中断 (HT)来处理。

  • 陷阱 2:RIF 权限不够。再次检查 GPDMA 对应的通道是否已经在 RIMC 中划归给 M33。

  • 陷阱 3:Cache 一致性。如果你开启了 M33 的 Data Cache,DMA 把数据搬到 RAM 后,CPU 读取的可能是 Cache 里的旧数据。

    • 解决:在处理数据前调用SCB_InvalidateDCache_by_Addr(rx_buffer, RX_BUF_SIZE);


总结:我们现在拥有了一个高效的串口“进出口”。M33 已经可以稳定地与外界(如 PC 或未来的 Linux 侧应用)交换数据。

http://www.jsqmd.com/news/393041/

相关文章:

  • SpringBoot+Vue MES生产制造执行系统管理平台源码【适合毕设/课设/学习】Java+MySQL
  • 企业级web汽车销售系统管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】
  • 2026年太原小店区优质日托班深度评测与选择指南 - 2026年企业推荐榜
  • 【2025最新】基于SpringBoot+Vue的安康学院新型冠状病毒肺炎疫情防控专题网站管理系统源码+MyBatis+MySQL
  • 【2025最新】基于SpringBoot+Vue的社团服务系统管理系统源码+MyBatis+MySQL
  • AI原生应用性能优化:上下文窗口缓存策略全解析
  • 编写高性能 Java 代码的最佳实践
  • MySQL索引优化:B+树原理与实战技巧
  • 如果再写 for 循环,我就锤自己!
  • Java SpringBoot+Vue3+MyBatis 社团服务系统系统源码|前后端分离+MySQL数据库
  • Kafka 副本机制
  • 【2025最新】基于SpringBoot+Vue的Web教师个人成果管理系统管理系统源码+MyBatis+MySQL
  • C++学习(3)(if 字符串 枚举类型)
  • 未来之窗昭和仙君(七十五)未来之窗硬件交互等到进程对话框—东方仙盟练气
  • SpringBoot2.x 官方推荐缓存框架-Caffeine高性能设计剖析
  • 前后端分离精品水果线上销售网站系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程
  • 拥抱 Java 8 并行流:执行速度飞起
  • 【毕业设计】SpringBoot+Vue+MySQL 安康学院新型冠状病毒肺炎疫情防控专题网站平台源码+数据库+论文+部署文档
  • SpringBoot+Vue 企业信息管理系统管理平台源码【适合毕设/课设/学习】Java+MySQL
  • Java SpringBoot+Vue3+MyBatis 小区物业智能卡管理设计与实现系统源码|前后端分离+MySQL数据库
  • 深入探讨OpenOCD与J-Link的动态链接问题
  • 阜阳智能伸缩门定制指南:2026年Q1优选厂商深度解析 - 2026年企业推荐榜
  • 时间序列数据的两年平均分析
  • 盘点开发中那些常用的 MySQL 优化
  • 深入解析Excel季度数据汇总
  • 深入探讨Solidity编译器的元数据差异
  • SpringBoot+Vue 无人超市管理系统管理平台源码【适合毕设/课设/学习】Java+MySQL
  • 2026年阜阳软床供应商综合实力深度解析与推荐 - 2026年企业推荐榜
  • 基于SpringBoot+Vue的Web教师个人成果管理系统管理系统设计与实现【Java+MySQL+MyBatis完整源码】
  • 自制便携收音机