a1a1a21 发表于 6 天前

基于 STM32G4 DMA+CRC 高效实现技巧:硬件加速校验,解放 CPU 负载

STM32 的硬件 CRC 外设可大幅提升校验运算速度,而 (https://www.eefocus.com/tag/DMA/)(直接[存储器](https://www.eefocus.com/tag/%E5%AD%98%E5%82%A8%E5%99%A8/)访问)能彻底解放 (https://www.eefocus.com/baike/1552575.html),二者结合可实现 “数据自动传输 + 硬件 CRC 计算” 的高效方案,核心价值在于 “无 CPU 干预的批量数据校验”,适用于通信数据校验、存储数据完整性验证等场景。本文基于 STM32G474,详解 DMA 配合 CRC 的实现原理、配置步骤与实战代码。

### 资料获取:[如何通过DMA配合CRC功能](https://shequ.stmicroelectronics.cn/thread-645394-1-6.html)

## 1. 核心优势:DMA+CRC 为何优于传统方案?

传统 CRC 计算依赖软件算法或单纯硬件 CRC,存在明显局限,而 DMA+CRC 组合实现双重优化:

| 方案类型         | 核心劣势                  | DMA + 硬件 CRC 优势                                             |
| -------------------- | ----------------------------- | ------------------------------------------------------------------- |
| 软件 CRC         | 运算速度慢,占用 CPU 资源   | 硬件 CRC 运算(最高 4 个 AHB 时钟 / 32 位数据),速度提升 10 倍 + |
| 硬件 CRC(无 DMA) | 需 CPU 手动传输数据,效率低 | DMA 自动完成数据从内存到 CRC 外设的传输,CPU 仅需配置和处理结果   |
| 适用场景         | 少量数据、低实时要求      | 批量数据(如数组、存储块)、高实时通信场景                        |

## 2. 实现原理:3 大关键可行性分析

### 2.1 时间可行性:DMA 传输与 CRC 计算时序匹配

* 单次 DMA 传输(Mem-to-Mem 模式)包含 “AHB 读 + AHB 写”,至少需 4 个 AHB 时钟周期。
* 硬件 CRC 计算耗时:8 位数据 1 个时钟、16 位 2 个时钟、32 位 4 个时钟,完全适配 DMA 传输时序,无需额外等待,可背靠背连续传输。

### 2.2 总线连接可行性:DMA 可直接访问 CRC 外设

* CRC 外设挂在 AHB1 [总线](https://www.eefocus.com/baike/1542179.html),DMA 作为 AHB 主设备,可通过[总线矩阵](https://www.eefocus.com/baike/1571955.html)直接访问内存(SRAM/FLASH)和 CRC 外设,[数据传输](https://www.eefocus.com/tag/%E6%95%B0%E6%8D%AE%E4%BC%A0%E8%BE%93/)无需 CPU 中转。

### 2.3 DMA 传输模式:Mem-to-Mem 模式适配 CRC 特性

* CRC 外设无触发 DMA 传输的信号,因此必须使用 DMA 的 “内存到内存(Mem-to-Mem)” 模式,由软件发起传输,传输完成后触发中断通知 CPU 读取结果。
* 注意:Mem-to-Mem 模式禁止使用循环模式(CIRC 位需清 0)。

## 3. 实战实现:STM32G474 完整步骤

以 NUCLEO-G474RE 为例,基于 STM32CubeMX+HAL 库实现,目标是对 114 个 32 位数据进行 CRC 校验。

### 3.1 第一步:STM32CubeMX 配置(核心步骤)

#### (1)激活 CRC 外设

* 进入 “Pinout & Configuration”→“Computing”→“CRC”,勾选 “Activated”。
* 基础参数配置:“Input Data Format” 设为 “Words”(32 位数据,可按需改为字节 / 半字),其余参数默认(多项式 0x04C11DB7,初始值 0xFFFFFFFF)。

#### (2)配置 DMA(Mem-to-Mem 模式)

* 进入 “System Core”→“DMA”,点击 “Add” 添加通道,选择 “MEMTOMEM”(内存到内存)。
* 配置参数:
* Mode:Normal(非循环模式,Mem-to-Mem 禁止循环)。
* Data Width:源 / 目标均设为 “Word”(与 CRC 输入格式匹配)。
* Src Memory:勾选 “Increment Address”(源数据地址递增)。
* Dst Memory:不勾选(CRC\_DR [寄存器](https://www.eefocus.com/baike/502591.html)地址固定,无需递增)。

#### (3)使能 DMA 中断

* 进入 “NVIC”→“DMA1 channel1 global interrupt”,勾选 “Ena(https://www.eefocus.com/tag/ble/)d”(传输完成后触发中断,读取 CRC 结果)。

#### (4)生成代码

* 点击 “Project Manager” 生成工程,CubeMX 会自动创建 CRC 和 DMA 句柄(如`hcrc`、`hdma_memtomem_dma1_channel1`)。

### 3.2 第二步:软件代码实现(关键部分)

#### (1)定义数据与预期结果

```
#define BUFFER_SIZE 114// 待校验数据长度
// 待校验32位数据数组
static const uint32_t aDataBuffer = {
    0x00001021, 0x20423063, 0x408450a5, /* ... 其余111个数据省略,完整数组见文档 ... */
    0x2e933eb2, 0x0ed11ef0
};
// 预期CRC结果(默认配置下)
const uint32_t uwExpectedCRCValue = 0x379E9F06;
uint32_t uwCRCValue = 0;// 存储实际CRC结果
```

#### (2)注册 DMA 传输完成回调函数

传输完成后通过中断读取 CRC 结果,需注册回调函数:

```
/**
* @brief DMA传输完成回调函数(读取CRC结果)
*/
static void DMA_CRC_TransferCpltCallback(DMA_HandleTypeDef *hdma) {
    if (hdma->Instance == DMA1_Channel1) {// 匹配配置的DMA通道
      uwCRCValue = hcrc.Instance->DR;// 读取CRC_DR寄存器的校验结果
    }
}
```

#### (3)初始化并启动 DMA+CRC

在`main`函数的`USER CODE BEGIN 2`区域添加代码:

```
// 1. 注册DMA传输完成回调函数
HAL_DMA_RegisterCallback(&hdma_memtomem_dma1_channel1,
                        HAL_DMA_XFER_CPLT_CB_ID,
                        DMA_CRC_TransferCpltCallback);

// 2. 重置CRC计算单元(初始化CRC_DR为初始值0xFFFFFFFF)
__HAL_CRC_DR_RESET(&hcrc);

// 3. 启动DMA传输:从aDataBuffer传输到CRC_DR,共BUFFER_SIZE个数据
HAL_DMA_Start_IT(&hdma_memtomem_dma1_channel1,
                (uint32_t)aDataBuffer,// 源地址:数据数组
                (uint32_t)&(hcrc.Instance->DR),// 目标地址:CRC数据寄存器
                BUFFER_SIZE);// 传输数据个数
```

### 3.3 第三步:结果验证

DMA 传输完成后,`uwCRCValue`会存储实际校验结果,可通过串口打印或[调试器](https://www.eefocus.com/baike/521722.html)验证是否与`uwExpectedCRCValue`一致:

```
// (可选)在主循环中打印结果
while (1) {
    if (uwCRCValue != 0) {// 若已获取CRC结果
      printf("实际CRC结果: 0x%08Xn", uwCRCValue);
      printf("预期CRC结果: 0x%08Xn", uwExpectedCRCValue);
      printf("校验结果: %sn", (uwCRCValue == uwExpectedCRCValue) ? "成功" : "失败");
      uwCRCValue = 0;// 重置,便于下次校验
      HAL_Delay(1000);
    }
    HAL_Delay(100);
}
```

## 4. 关键避坑指南

1. ​**DMA 模式限制**​:Mem-to-Mem 模式必须禁用循环模式(CubeMX 中 “Mode” 设为 Normal),否则传输无法终止。
2. ​**地址增量配置**​:CRC\_DR 寄存器地址固定,DMA 目标内存(Dst Memory)的 “Increment Address” 必须取消勾选。
3. ​**数据宽度匹配**​:CRC 输入数据格式(字节 / 半字 / 字)需与 DMA 的 “Data Width” 一致,否则会导致校验错误。
4. ​**CRC 重置**​:每次新校验前必须调用`__HAL_CRC_DR_RESET(&hcrc)`,确保初始值正确。

DMA + 硬件 CRC 的组合方案完美解决了传统校验 “速度慢、CPU 占用高” 的痛点,尤其适用于批量数据校验场景。通过 STM32CubeMX 的可视化配置 + 简洁的 HAL 库代码,可快速落地该方案。

页: [1]
查看完整版本: 基于 STM32G4 DMA+CRC 高效实现技巧:硬件加速校验,解放 CPU 负载