硬汉嵌入式论坛

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

[DMA] 我完成了PA0触发DMA采集挂在FMC下AD7606的功能

[复制链接]

5

主题

21

回帖

36

积分

新手上路

积分
36
发表于 前天 11:14 | 显示全部楼层 |阅读模式
我已经完成了这个功能,但是我是在自己的代码环境中写的代码,我的代码没有使用HAL库和LL库。是我自己写的所有驱动, 所以各位只能当作参考。不能直接使用。
AD7606 FMC+DMA 采集方案 — 正确配置与避坑指南
版本: Ver1.0 日期: 2026-06-25 作者: cuijunling 适用芯片: STM32H743IIT6 配套代码: ChipDriver/Src/ad7606_fmc.c 状态: 全部配置经 2026-06 实测验证(dump 寄存器值 + 示波器波形双重确认)

0. 本文档的定位
本文档记录 AD7606 DBM 双缓冲采集方案正确配置已踩过、必须避开的坑
旧文档 ad7606_fmc_driver.md 中有若干结论被本次调试推翻(主要是"EXTI0 无需中断即可触发 DMAMUX"、"FMC=200MHz/5ns"等),附录 A 列出了旧文档的错误纠正清单。两份文档冲突时,以本文档为准

1. 方案总览与信号链路1.1 架构TIM1_CH1(PA8) ──PWM──→ CONVST ──→ AD7606 开始转换                                      │                                 BUSY↓ (PA0)                                      │                          ┌───────────┴───────────┐                          │  EXTI0(下降沿, IT模式) │  ← 必须开中断! (见坑1)                          │  IRQ: 清 PR + 计数     │                          └───────────┬───────────┘                                      │  exti_exti0_it 锁存输出                                      ▼                          DMAMUX1 Request Generator 0                          SIG_ID=EXTI0, GPOL=下降沿                          GNBREQ=8                                      │  每次 BUSY↓ 产生 8 个 DMA 请求                                      ▼                          DMA Stream (DBM 双缓冲)                          DMAREQ_ID=1 (监听 RG0)                          PAR=FMC 0x60003000                          M0AR/M1AR = SDRAM Buf A/B                                      │                          8 次读 FMC → 8 通道数据                          NDTR→0 自动切换 A/B → TC 中断1.2 关键事实(每一条都实测过)
事实
值 / 说明

触发源AD7606 BUSY 下降沿 = 数据就绪
EXTI 信号
DMAMUX1 监听的是 exti_exti0_it(EXTI 锁存/PR 输出),不是引脚原始信号

必须开中断
是。否则 PR 挂着不清,RG0 永不触发(见坑1)

DMA 请求源
DMAREQ_ID = 1(DMAMUX1_REQ_GENERATOR0)

每次触发
RG0 产生 8 个 DMA 请求 = 读 8 个通道

数据通路
DMA1/DMA2 + DMAMUX1(不能用 BDMA,见 1.3)
1.3 为什么用 DMA1/DMA2 + DMAMUX1,不用 BDMA + DMAMUX2
AD7606 挂在 FMC(D1 域),缓冲区在 SDRAM(D1 域)。BDMA 只能访问 D3 域,读不到 FMC、写不进 SDRAM。所以数据通路必须走 DMA1/DMA2(挂 DMAMUX1)。
⚠️ 注意:ST 官方的 DMAMUX_RequestGen 例程和网上的 GIPO_DMA 例程用的是 BDMA + DMAMUX2,它的"EXTI0 无中断触发"模型不能照搬到 DMAMUX1(见坑1)。这是最容易踩的坑。

2. 已验证的正确配置(实测寄存器值)2.1 硬件接线
信号
STM32 引脚
功能

CONVSTPA8 / TIM1_CH1PWM 输出,周期启动转换
BUSY
PA0 / EXTI0
数据就绪(下降沿),触发 DMAMUX1 RG0

FMC_NE1
PD7
FMC 片选(AF12)

FMC_NOE
PD4
读使能(RD)

FMC_NWE
PD5
写使能

FMC_D0~D15
PJ0~PJ15 等
16-bit 数据总线

RESET / RANGE / OS0~2
见 board_init 配置
普通推挽 GPIO 输出
CONVST 实际由 bsp_timer 产生,PWM 在 PA8 上(debug 中监控的是 TIM1->CR1)。
2.2 BUSY 引脚(PA0)— 方案B:必须用 bsp_gpio_exti_initstatic void ad7606_fmc_config_busy_pin(AD7606_FMC_CONFIG *config){    EXTI_CONFIG exti_cfg;    exti_cfg.gpio_group = config->busy_port;      // GPIOA    exti_cfg.pin        = config->busy_pin;        // GPIO_Pin_0    exti_cfg.type       = EXTI_Trigger_Falling;    // BUSY↓ = 数据就绪    exti_cfg.priority   = 5;    exti_cfg.pull       = GPIO_PuPd_UP;    bsp_gpio_exti_init(&exti_cfg, ad7606_fmc_busy_exti_callback);}
bsp_gpio_exti_init 一步配齐:SYSCFG(PA0→EXTI0) + EXTI(IT 下降沿) + NVIC 使能 + 注册非空调调。回调 ad7606_fmc_busy_exti_callback 非空(仅计数),故 EXTI0_IRQHandler 清 PR 后调用它不会空指针(见坑2)。
⚠️ 不要用裸 bsp_exti_enable_* 宏 + 不开 NVIC 的旧写法。那是基于"EXTI0 无中断触发 DMAMUX1"的错误认知,实测不工作(见坑1)。
2.3 DMAMUX1 Request Generator 0(RG0)
实测 RGCR = 0x003D0106,字段分解(H7 真实位段,见坑4 的位段纠正):
字段
含义

SIG_ID4:06触发源 = EXTI0(DMAMUX1_REQ_GEN_EXTI0)
OIE
8
1
Overrun 中断使能(仅状态位,NVIC 未开)

GE
16
1
RG 使能(最后置位)

GPOL
18:17
10
下降沿

GNBREQ
23:19
7
产生 8 个请求(编码 = N-1)
配置顺序(改 RGCR 前必须先关 GE,最后再开):
bsp_dmamux1_disable_request_gen(rg);                  // 1. 先关 GEbsp_dmamux1_clear_flag_RGOx(...);                     // 2. 清历史 overrunbsp_dmamux1_set_request_signalID(rg, EXTI0);          // 3. SIG_ID=6bsp_dmamux1_set_request_gen_polarity(rg, FALLING);    // 4. GPOL=下降沿bsp_dmamux1_set_gen_request_Nb(rg, 8);                // 5. GNBREQ=8(宏内 N-1)bsp_dmamux1_set_overrun_enable(rg);                   // 6. OIEbsp_dmamux1_enable_request_gen(rg);                   // 7. 最后开 GE2.4 DMA Stream(DBM 双缓冲)
字段
说明

DMAREQ_ID(DMAMUX channel CCR)1监听 RG0 输出(DMAMUX1_REQ_GENERATOR0)
DIR
外设→内存
从 FMC 读

DBM
1
双缓冲,M0AR/M1AR 自动切换

MINC
1
内存地址自增

PSIZE/MSIZE
16-bit
AD7606 每路 16-bit

PL
Very High
最高优先级

TCIE
1
Buffer 填满触发 TC 中断

NDTR
buf_size/2
half-word 个数(16KB → 8192)
DMA stream 由 bsp_dma_init 动态分配(返回 index 0~15)。index 同时就是 DMAMUX1 通道号(sg_dma_stream[] 按 DMA1×8+DMA2×8 排列),bsp_dma_init 内部 DMAMUX1 + index 自动写到对应 channel CCR。
2.5 FMC 时序(BTR1)
实测 BTR1 = 0x02100323:
字段
含义

ADDSET3:03RD 高 ≈ 30ns(≥ AD7606 22ns)
ADDHLD
7:4
2
Mode A 下不生效

DATAST
15:8
3
RD 低 ≈ 30ns(≥ AD7606 21ns)

BUSTURN
19:16
0
连续读同 Bank,省去

CLKDIV
23:20
1
kernel clock 分频

ACCMOD
29:28
0
Mode A(异步)
AD7606 读时序下限:RD 低 ≥ 21ns、RD 高 ≥ 22ns。当前 30/30ns 有余量,不可再降到 2(20ns < 21ns 会读到错误数据)。
2.6 CONVST / PWM
bsp_timer_pwm_init(convst_channel=0, 1000us, 10% 占空) → PA8 输出 PWM 周期启动转换。采样率由 ad7606_fmc_start_record(freq) 设定,内部 bsp_timer_pwm_change_cycle 改周期。

3. 关键避坑要点(按严重程度排序)&#128308; 坑1(最致命)MAMUX1 的 EXTI0 必须开中断清 PR
现象:EXTI0 明明检测到 PA0 下降沿(dump PR1=1),但 DMA 不触发(NDTR 不减、PD7 无波形)。RG0 配置全对。
根因(ST 官方答复,community.st.com /td-p/219513):
  • DMAMUX1(D2 域)的 EXTI0 输入信号 = exti_exti0_it,是 EXTI 的锁存(PR)输出。PR 挂起期间持续为高,只有在中断里清 PR 才会拉低 → 这个下降沿被 RG0 的 GPOL=falling 捕获 → 触发 DMA。
  • DMAMUX2(D3 域,BDMA)的 EXTI0 输入 = exti_syscfg_exti0(引脚原始信号,自动清除),无需中断。GIPO_DMA 例程正是这套,所以从不清 PR 也能跑。
  • 旧设计"不开 NVIC、纯硬件触发"对 DMAMUX1 行不通R 一直挂着 → exti_exti0_it 无下降沿 → RG0 永不触发。
正确做法:用 bsp_gpio_exti_init 使能 EXTI0 NVIC,IRQ 清 PR(方案B)。代价:每 BUSY 下降沿进一次中断(10kHz = 1 万次/秒),中断体仅清 PR + 计数,开销可忽略。
调试判据:dump 中 busy_irq_cnt 持续增长 = 中断通了、清 PR 生效。
&#128992; 坑2:EXTI0_IRQHandler 空指针 HardFault
bsp_gpio.c 的 EXTI0_IRQHandler:
void EXTI0_IRQHandler(void) {    bsp_exti_clear_flag_0_31(EXTI_LINE_0);              // 清 PR    sg_exti_fun[0].Exit_Function((void *)EXTI_LINE_0);  // 直接调回调,无 NULL 检查!}
若使能 NVIC 却没注册回调,进中断就解引用空指针 → BLX 0x0 → HardFault(就是早先"进 ISR 挂死"的真因)。
正确做法:使能 NVIC 前必须经 bsp_gpio_exti_init 注册非空调调(方案B 注册了 ad7606_fmc_busy_exti_callback)。
&#128992; 坑3:sg_register_gpio 占用冲突导致静默失败
bsp_gpio_set_in_up_op 和 bsp_gpio_exti_init 都调 sg_register_gpio 占用引脚。若先调前者占了 PA0,后者内部的 sg_register_gpio(PA0) 会静默返回 false(不报错),导致回调没注册、NVIC 没开。
正确做法:config_busy_pin 里只调 bsp_gpio_exti_init(它内部会注册 PA0 + 配 GPIO),不要先调 bsp_gpio_set_in_up_op。
&#128993; 坑4MAMUX RGCR 位段别按老资料写
H7 的 DMAMUX_RGxCR 真实位段(20 个 H7 头文件一致,GPOL_Pos=17、GNBREQ_Pos=19):
SIG_ID[4:0]   OIE[8]   GE[16]   GPOL[18:17]   GNBREQ[23:19]
旧文档写的 GPOL[17:16]、GNBREQ[20:16] 是错的(那是别的系列/笔误)。BSP 宏 DMAMUX_RGxCR_GPOL_Pos=17 等已正确,直接用宏即可,不要手填位段。
&#128993; 坑5:OF0=0 不代表"RG0 没被触发"
RGSR.OF0 是 Overrun 标志(触发太密、请求没被及时取走才置位),不是"触发过"标志。DMA 正常服务请求时 OF0 永远是 0。
真判据:NDTR 是否递减。NDTR 不减 = DMA 没收到请求 = RG0 没产生请求(或 DMA 没响应)。别被 OF0=0 误导成"没触发"。
&#128994; 坑6verflow 持续涨 = 应用层没消费 buffer
dump 里 ovf 贴着 tc 涨(TC 时上一个 buffer 还没被释放)。这是应用层没调 ad7606_fmc_get_dbm_buffer → 处理 → ad7606_fmc_release_dbm_buffer 的消费循环。和 DMA 触发无关,但数据其实没被用起来。

4. FMC 时序与时钟真相(实测)4.1 时钟链(2026-06 实测寄存器值)HSE ──→ PLL1 (M=18, N=192, P=2) ──→ PLL1P ≈ 133MHz (SYSCLK)                                          │                                     D1CPRE /2 (D1CFGR=0x48)                                          ▼                                     HCLK3 ≈ 66MHz (T = 15ns)                                          │                          FMCSEL=0 (D1CCIPR, PLL2R case 被注释没切)                                          ▼                                     FMC kernel = HCLK3 ≈ 66MHz
PLL2 配置异常慢(N=120,M=33,R=3 → PLL2_R≈30MHz),但 FMCSEL=0 没用它,不影响 AD7606。这是 [memory: sdram-debug-status] 里 "LL2 diff pending" 的来源,属遗留问题,与采集无关。
4.2 单次 FMC 读周期
Mode A 异步读 ≈ (ADDSET + DATAST + 同步开销) 个 kernel 周期:
当前: (3 + 3 + 2) × 15ns ≈ 120ns/读8 读 ≈ 1us  ← 与示波器实测一致4.3 优化空间(谨慎)
当前
提 HCLK3 到 240MHz 后

HCLK366MHz (15ns)240MHz (4.17ns)
单次读
~120ns
~33ns

8 读
~1us
~270ns

BTR 是否要改
否(3/3 已最优)
否(仍满足 AD7606 21/22ns)
但提 HCLK3 是系统级大改:CPU、SDRAM、所有外设波特率全变,需重新验证整板。当前 10kHz 采样下 1us 占空才 1%,不建议为此动系统时钟。等采样率冲 100kHz+ 再考虑。

5. 调试方法5.1 ad7606_fmc_debug_dump() 判据表
start_record() 之后调用 ad7606_fmc_debug_dump(),按表从上往下看,第一项异常的就是断点:
打印项
正常值
异常含义
断点位置

PA0采样 高电平=NN 在 0~2000 跳动0 或 2000信号没进 PA0(短接/虚焊)
[EXTI] PR1 line0
0(中断清掉)
一直=1
没进中断清 PR(坑1)

[ISR] busy_irq_cnt
持续增长
0
NVIC 没开 / 回调空指针(坑2/3)

[SYSCFG] EXTICR1 src
0(PA)
≠0
PA0 没路由到 EXTI0

[DMAMUX] RGSR OF0
(参考)
OF0 不是触发判据(坑5)

[DMAMUX] ch? DMAREQ_ID
1
≠1
DMA 监听错请求源

DMA NDTR
递减
恒定
RG0 没触发 / DMA 没启动

[FMC] BTR1
0x02100323
别的值
BTR 没写入(检查 FMCEN 时序)

[RCC] FMCSEL
0
FMC=HCLK3(坑6)

PD7 波形
每次触发 8 脉冲
上游某一环断了
5.2 分段调试技巧(无 AD7606 硬件时)
把 PA8(CONVST PWM)用杜邦短接到 PA0(BUSY),用 PWM 边沿模拟 BUSY 下降沿,可单独验证 EXTI0 → RG0 → DMA → FMC 链路,不必接真实 AD7606。
注意:此时读的是悬空 FMC,数据无意义,只验证时序链路(NDTR 递减、PD7 波形)。接回真实 AD7606 后才能验证数据正确性。
5.3 验证数据正确性(必须做)
FMC 时序压太狠的典型失败是波形还在、数据已采错。给 AD7606 某路输已知直流电压,确认 8 路读数换算正确,才算配置真 OK。

6. 当前工作配置快照(2026-06-25 实测)

采样率10 kHz(boot 测试)
8 读耗时
~1us(示波器实测)

占空
1%(1us / 100us 周期)

DMA stream
index 0(DMA1_Stream0)

DMAREQ_ID
1

RG0 RGCR
0x003D0106

FMC BTR1
0x02100323

HCLK3
~66MHz

FMCSEL
0(FMC=HCLK3)

busy_irq_cnt
随采样率增长

数据正确性
待接真实 AD7606 验证
结论:当前配置在 HCLK3=66MHz 下已是 BTR 能做到的最快,数据时序合规。1us 是时钟决定的正常结果,非故障。无需进一步优化(除非提系统时钟)。
附录 A:关联资料

回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
123189
QQ
发表于 前天 16:35 | 显示全部楼层
谢谢分享

点评

唉, 你不分享的更多嘛。  详情 回复 发表于 前天 16:49
回复

使用道具 举报

5

主题

21

回帖

36

积分

新手上路

积分
36
 楼主| 发表于 前天 16:49 | 显示全部楼层

唉, 你不分享的更多嘛。
回复

使用道具 举报

12

主题

485

回帖

521

积分

金牌会员

积分
521
发表于 前天 21:27 | 显示全部楼层
格式有点乱,动网不支持markdown,

点评

你把内容复制下来,然后存储到本地文档,命名.md格式,用vscod打开,效果就很好了 。  详情 回复 发表于 13 小时前
回复

使用道具 举报

3

主题

31

回帖

40

积分

新手上路

积分
40
发表于 昨天 06:45 | 显示全部楼层
牛啊 谢谢分享
回复

使用道具 举报

5

主题

21

回帖

36

积分

新手上路

积分
36
 楼主| 发表于 13 小时前 | 显示全部楼层
fxyc87 发表于 2026-6-25 21:27
格式有点乱,动网不支持markdown,

你把内容复制下来,然后存储到本地文档,命名.md格式,用vscod打开,效果就很好了 。
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-6-27 22:57 , Processed in 0.935252 second(s), 26 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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