硬汉嵌入式论坛

 找回密码
 立即注册
查看: 252|回复: 8
收起左侧

[DMA] PA0 触发 DMA传输的重大进步

[复制链接]

4

主题

19

回帖

31

积分

新手上路

积分
31
发表于 前天 06:50 | 显示全部楼层 |阅读模式
今天成功的将官方的PA0触发DMA传输的代码改造并跑通了,只不过官方使用的是BDMA,但是原理应该都是一样的。 具体的总结,我就直接把AI的文档贴在这里。
这样距离我完全不用CPU干预,自动采集AD7606数据的功能,更近一步了

# STM32H7 PA0触发DMA传输项目文档

## 项目概述

本项目实现了基于PA0引脚上升沿触发的BDMA自动传输,无需CPU干预。每个触发传输8个半字到GPIOH->ODR,实现PH10引脚的自动翻转。

## 硬件配置

### 主控芯片

- **型号**: STM32H743xx
- **系统时钟**: 400MHz (CPU), 200MHz (HCLK)

### 引脚配置

| 引脚 | 功能 | 配置 | 说明 |
|------|------|------|------|
| PA0 | 输入 | GPIO_MODE_IT_RISING | DMA触发源,上升沿触发 |
| PA8 | 输出 | TIM1_CH1 (AF1) | PWM输出,用于测试触发 |
| PH10 | 输出 | GPIO_OUTPUT_PP | 红色LED,DMA控制翻转 |
| PH11 | 输出 | GPIO_OUTPUT_PP | 绿色LED(备用) |
| PH12 | 输出 | GPIO_OUTPUT_PP | 蓝色LED(备用) |
| PD7 | 输出 | GPIO_OUTPUT_PP | DMA完成指示 |
| PA9 | 输出 | USART1_TX (AF7) | UART发送,调试输出 |
| PA10 | 输入 | USART1_RX (AF7) | UART接收 |

## DMA配置详解

### BDMA Channel 0配置

```c
DMA_Handle.Instance = BDMA_Channel0;
DMA_Handle.Init.Request = BDMA_REQUEST_GENERATOR0;
DMA_Handle.Init.Direction = DMA_MEMORY_TO_PERIPH;
DMA_Handle.Init.PeriphInc = DMA_PINC_DISABLE;
DMA_Handle.Init.MemInc = DMA_MINC_ENABLE;
DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;  // 16位
DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;     // 16位
DMA_Handle.Init.Mode = DMA_CIRCULAR;
DMA_Handle.Init.Priority = DMA_PRIORITY_LOW;
DMA_Handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
```

### DMAMUX请求生成器配置

```c
dmamux_ReqGenParams.SignalID = HAL_DMAMUX2_REQ_GEN_EXTI0;  // EXTI0信号
dmamux_ReqGenParams.Polarity = HAL_DMAMUX_REQ_GEN_RISING;   // 上升沿
dmamux_ReqGenParams.RequestNumber = 8;                      // 每次触发8个请求
```

### 缓冲区配置

```c
// 位于D3 SRAM (0x38000000),BDMA只能访问D3域
const uint16_t SRC_Buffer_LED1_Toggle[128] = {
    0, LED_RED_PIN, 0, LED_RED_PIN, ...  // 交替模式,64对
};
```

### DMA传输启动

```c
HAL_DMA_Start_IT(&DMA_Handle,
                 (uint32_t)SRC_Buffer_LED1_Toggle,  // 源地址
                 (uint32_t)&GPIOH->ODR,              // 目标地址
                 128);                               // 传输128个半字
```

## 工作原理

### 时序图

```
PWM (PA8):     ┐     ┐     ┐     ┐     ┐     ┐
               │     │     │     │     │     │
               └─────┘     └─────┘     └─────┘
               100us  100us  100us  100us  100us

触发 (PA0):    ┐     ┐     ┐     ┐     ┐     ┐
               │     │     │     │     │     │
               └─────┘     └─────┘     └─────┘

DMA传输:      [0-7] [8-15] [16-23] [24-31] ...
               8个半字 8个半字 8个半字

PH10:          ×8    ×8    ×8    ×8
               快速   快速   快速   快速
               翻转   翻转   翻转   翻转

PD7:                              ┐
                                 ┌┘
                               └─ 16次触发后翻转
```

### 数据流程

1. **PA0上升沿** → EXTI0检测到
2. **EXTI0信号** → DMAMUX请求生成器
3. **RequestNumber=8** → 生成8个DMA请求
4. **BDMA传输** → 从D3 SRAM读取8个半字
5. **写入GPIOH->ODR** → PH10翻转8次
6. **16次触发后** → 128个半字传输完成 → TC中断 → PD7翻转

## 关键配置要点

### 1. D3 SRAM要求

BDMA只能访问D3域的SRAM和外设:

- **D3 SRAM**: 0x38000000 - 0x3800FFFF (64KB)
- **D3外设**: 0x58000000 - 0x5800FFFF

链接脚本必须定义`.RAM_D3`段:

```scatter
RW_IRAM4 0x38000000 0x00010000  {
    .RAM_D3 (+RW +ZI)
}
```

### 2. DMAMUX RequestNumber

`RequestNumber`参数控制每个触发信号生成的DMA请求数量:

- `RequestNumber = 8`: 每个PA0上升沿传输8个半字
- `RequestNumber = 1`: 每个PA0上升沿传输1个半字

### 3. 循环模式

`DMA_CIRCULAR`模式下:

- 传输完128个半字后自动从缓冲区开头重新开始
- TC中断在每个完整周期结束时触发

### 4. 中断配置

```c
HAL_DMA_RegisterCallback(&DMA_Handle, HAL_DMA_XFER_CPLT_CB_ID, HAL_TransferComplete);
HAL_NVIC_SetPriority(BDMA_Channel0_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(BDMA_Channel0_IRQn);
```

## PWM测试配置 (可选)

PA8输出PWM用于自动测试,连接PA8到PA0:

```c
TIM1时钟: 200MHz
ARR: 19999 (200MHz / 20000 = 10kHz)
CCR1: 2000 (10%占空比)
```

## UART调试输出

UART1配置用于调试:

- **波特率**: 2000000 (2Mbps)
- **数据位**: 8
- **停止位**: 1
- **校验**: 无

启动时自动输出DMA寄存器信息,便于调试。

## DMA寄存器说明

### BDMA Channel 0寄存器

| 寄存器 | 地址 | 说明 |
|--------|------|------|
| CR | 0x58005400 | 控制寄存器 |
| NDTR | 0x58005404 | 剩余传输数量 |
| PAR | 0x58005408 | 外设地址 |
| M0AR | 0x5800540C | 内存0地址 |

### DMAMUX2寄存器

| 寄存器 | 说明 |
|--------|------|
| RGCR0 | 请求生成器0控制寄存器 |
| SIG_ID | 信号ID (EXTI0) |
| NBREQ | 请求数量 (RequestNumber) |
| GPolarity | 极性 (0=上升沿, 1=下降沿) |
| GE | 使能位 |

## 实际应用:AD7606数据采集

本项目可作为AD7606数据采集的参考。AD7606通过FMC SRAM接口连接,需要修改:

### 修改点

1. **触发源**: PA0改为AD7606 BUSY信号(下降沿触发)
2. **触发方式**: 修改`Polarity`为下降沿
3. **数据源**: 从FMC SRAM地址读取,而非D3 SRAM缓冲区
4. **缓冲区**: 扩大到8192 * 2字节
5. **双缓冲**: 实现两个缓冲区交替使用

### 下降沿触发配置

```c
dmamux_ReqGenParams.SignalID = HAL_DMAMUX2_REQ_GEN_EXTI0;
dmamux_ReqGenParams.Polarity = HAL_DMAMUX_REQ_GEN_FALLING;  // 改为下降沿
dmamux_ReqGenParams.RequestNumber = 8;
```

## 故障排查

### 问题:DMA传输不工作

**检查清单:**

1. GPIOH时钟是否使能?
2. 缓冲区是否在D3 SRAM (0x38000000)?
3. 链接脚本是否定义了.RAM_D3段?
4. EXTI0是否正确配置为上升沿触发?
5. DMAMUX请求生成器是否使能?

### 问题:传输完成中断不触发

**检查清单:**

1. BDMA Channel 0中断是否使能?
2. TC回调是否正确注册?
3. NVIC优先级是否配置?
4. 传输计数(NDTR)是否递减到0?

## 编译说明

- **IDE**: Keil MDK-ARM
- **编译器**: ARM Compiler 6 (ARMCLANG)
- **目标**: STM32H743xx

完全重新编译项目以确保链接脚本更改生效。

## 文件结构

```
GIPO_DMA/
├── Core/
│   ├── Inc/
│   │   └── main.h
│   └── Src/
│       └── main.c
├── MDK-ARM/
│   └── GIPO_DMA/
│       ├── GIPO_DMA.uvprojx
│       └── GIPO_DMA.sct
├── Drivers/
│   ├── CMSIS/
│   └── STM32H7xx_HAL_Driver/
└── readme.txt
```

## 寄存器的输出值

```
==============================================
DMA Register Dump
=================

=== DMA Handle ===
Instance:        0x58025408
ErrorCode:       0x00000000
State:           2

=== BDMA Channel 0 Registers ===
CNDTR (0x5802540C):  0x00000010
CPAR (0x58025410):   0x58021C14
CM0AR (0x58025414):  0x38000000

=== BDMA Interrupt Status ===
ISR (0x58025400):   0x00000005
GIF0: 1, TCIF0: 0, HTIF0: 1, TEIF0: 0

=== DMAMUX2 Request Generator ===
DMAMUX2 Base:   0x58025800
(RGCR0 at offset 0x100)

=== Buffer Info ===
Buffer Address:  0x38000000
Buffer Size:     128 half-words (256 bytes)
Target Address:  0x58021C14 (GPIOH->ODR)
GPIOH_BASE:      0x58021C00

=== Trigger Configuration ===
Trigger: PA0 (EXTI0 Rising Edge)
DMAMUX: EXTI0 -> BDMA Channel0
RequestNumber: 8 (8 half-words per trigger)
Total Transfers: 128 (16 triggers per complete cycle)
=====================================================
```
## 参考资料

- STM32H743xx Reference Manual
- STM32H7 HAL Driver User Manual
- AN4031: DMA controller introduction



回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
123158
QQ
发表于 前天 10:43 | 显示全部楼层
谢谢楼主分享。

回复

使用道具 举报

1

主题

55

回帖

58

积分

初级会员

积分
58
发表于 前天 11:17 | 显示全部楼层
外部引脚触发DMA  触发主要用在什什么样的场景呢
回复

使用道具 举报

1

主题

55

回帖

58

积分

初级会员

积分
58
发表于 前天 11:17 | 显示全部楼层
外部引脚触发DMA  触发主要用在什什么样的场景呢
回复

使用道具 举报

3

主题

127

回帖

136

积分

初级会员

积分
136
发表于 前天 11:30 | 显示全部楼层
可以外部控制转换速率吧,或者同步采样?
回复

使用道具 举报

3

主题

127

回帖

136

积分

初级会员

积分
136
发表于 前天 11:30 | 显示全部楼层
可以外部控制转换速率吧,或者同步采样?
回复

使用道具 举报

12

主题

482

回帖

518

积分

金牌会员

积分
518
发表于 前天 12:04 | 显示全部楼层
加油,关注中
回复

使用道具 举报

4

主题

19

回帖

31

积分

新手上路

积分
31
 楼主| 发表于 昨天 06:12 | 显示全部楼层
AD7606的busy控制DMA从FMC接口采集数据,有三个好处
1. 整个过程不需要CPU的操作,只有在采集满一个内存后才会调用一次传输完成中断,通知CPU。
2. AD7606可以由外部信号进行驱动,CPU只做采集,能做到多个采集板的同步,交错采集。
3. 可以适应高速采集,据我推算1Msps的采集速率应该是没有问题的。
回复

使用道具 举报

1

主题

14

回帖

17

积分

新手上路

积分
17
发表于 昨天 11:02 | 显示全部楼层
我记得我之前好像调过PA0触发dma干活,但是没调通,用其他方案去触发dma去了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2026-6-24 03:38 , Processed in 0.265291 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表