云计算百科
云计算领域专业知识百科平台

【嵌入式外设精学】Day15|DMA:半满全满、乒乓、为什么丢数

【嵌入式外设精学】Day15|DMA:半满全满、乒乓、为什么丢数

今天解决:采集为什么尾部不对?如何让 CPU 不跟数据抢着跑?


目录

  • 问题 2. 原理 3. 代码 4. 误区 5. 自测 6. 答案

  • 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. 自测

  • N=1024,HT 和 TC 各处理多少?
  • 乒乓解决什么问题?

  • 6. 答案

  • 各 512。
  • 明确“这一半归 CPU、那一半归 DMA”,避免写读冲突和撕裂。

  • 作者:shuifanyu 标签:DMA 乒乓 采集

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 【嵌入式外设精学】Day15|DMA:半满全满、乒乓、为什么丢数
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!