【嵌入式外设精学】Day15|DMA:半满全满、乒乓、为什么丢数
今天解决:采集为什么尾部不对?如何让 CPU 不跟数据抢着跑?
目录
1. 问题
- ADC/串口配了 DMA 仍丢数
- 处理慢一点,缓冲里的数据就花掉
2. 原理
2.1 DMA 干什么
外设和内存之间直接搬数据,CPU 不用一个个字节去搬,只处理结果。
2.2 丢数的本质
缓冲是循环写的。CPU 处理比 DMA 写得慢 → 旧数据还没用完就被覆盖。
2.3 乒乓(半区处理)
把大缓冲分成前后两半:
| 半满(HT) | DMA 在写后半,CPU 处理前半 |
| 全满(TC) | DMA 回头写前半,CPU 处理后半 |
同一时间,每半只属于一个人,就不会互相踩。
2.4 时间条件(用话记)
处理半区的最坏时间 < 填满半区的时间(还要留调度余量)。 做不到就:加大缓冲、降低采样率、加快算法。
3. 代码示例
#include "stm32f4xx.h"
#include <stdint.h>
#define N 1024u
static uint16_t buf[N];
typedef enum { EVT_NONE, EVT_HALF, EVT_FULL } evt_t;
static volatile evt_t evt = EVT_NONE;
void DMA1_Stream0_IRQHandler(void)
{
if (DMA_GetITStatus(DMA1_Stream0, DMA_IT_HTIF0) != RESET) {
DMA_ClearITPendingBit(DMA1_Stream0, DMA_IT_HTIF0);
evt = EVT_HALF;
}
if (DMA_GetITStatus(DMA1_Stream0, DMA_IT_TCIF0) != RESET) {
DMA_ClearITPendingBit(DMA1_Stream0, DMA_IT_TCIF0);
evt = EVT_FULL;
}
}
void process_half(uint16_t *p, uint32_t n)
{
/* 滤波/FFT/统计… */
(void)p; (void)n;
}
void app_dma_poll(void)
{
evt_t e = evt;
if (e == EVT_NONE) {
return;
}
evt = EVT_NONE;
if (e == EVT_HALF) {
process_half(&buf[0], N / 2u);
} else {
process_half(&buf[N / 2u], N / 2u);
}
}
4. 常见误区
| DMA 就永远不会丢 | 处理跟不上仍会覆盖 |
| 缓冲越小越好 | 太小来不及处理 |
| 运行中随便改 DMA 寄存器 | 先停通道再改 |
| 只开全满中断 | 用 HT/TC 乒乓更稳 |
5. 自测
6. 答案
作者:shuifanyu 标签:DMA 乒乓 采集
网硕互联帮助中心







评论前必须登录!
注册