跳转至

TinyMeasurement · 实时采集处理 · DMA 双缓冲 — 设计说明

应用层实际采集链

flowchart TB
    T[定时器回调] --> N[通知生产者]
    N --> S[读取 ADXL355]
    S --> B[加锁写入活动缓冲]
    B --> F{缓冲已满?}
    F -->|是| R[标记就绪并切换缓冲]
    R --> C[通知消费者处理与输出]
    F -->|否| N

实现由定时器回调通知生产者任务;生产者唤醒后读取 ADXL355 加速度与温度,将样本写入缓冲区,再通知消费者处理。缓冲切换与共享状态通过锁协调。应用层采样触发不是“DMA 完成中断”;底层 SPI 驱动是否使用 DMA 是另一个层次。

下方旧示意图保留为原设计记录。双缓冲和任务分工帮助重叠采集与处理,但任务仍共享内存、总线、锁和网络资源,不能据此保证无抖动或最高吞吐。验证时应记录实际采样间隔、丢样/覆盖数量、缓冲占用和网络发送耗时。

源码 / Source

DMA + Double Buffer — 双缓冲乒乓切换,DMA 协助搬数据

DMA(直接内存访问)在后台自动将传感器数据搬入缓冲区,CPU 无需逐字节搬运。双缓冲(乒乓)帮助重叠采集与处理。

算法直觉

DMA 为什么快?

普通方式:CPU 每次从传感器读数据都要执行指令 → 占用 CPU 时间。

DMA 方式:设置好 DMA 后,DMA 控制器自动从 SPI/I2C 总线读数据写入内存,应用层仍由 CPU 发起读取并管理缓冲;底层传输可由 DMA 协助。

双缓冲(乒乓缓冲)

设想两个桶 A 和 B:

展开历史 DMA 示意(不代表当前触发链)
DMA 往 A 装水(写数据) → A 满后 DMA 切换到 B
CPU 处理 A(读数据)    → CPU 处理完等 B 满
DMA 往 B 装水          → B 满后 DMA 切回 A
CPU 处理 B             → CPU 处理完等 A 满

双缓冲允许生产者写入与消费者处理重叠。若处理或读取赶不上采样速率,仍会发生等待、覆盖或丢样。

数据流

展开历史 DMA 示意(不代表当前触发链)
DMA 传输完成中断
    ↓
缓冲 A 满 → 通知 Consumer 任务
    ↓
DMA 自动切换到缓冲 B(乒乓切换)
Consumer 从缓冲 A 读取数据并处理
    ↓
Consumer 处理完 → 等待下一次中断

API 参考

// 配置宏
#define TINY_MEASUREMENT_RT_DMA_DB_BUFFER_SIZE 512  // 每个缓冲的样本数

注意事项

什么时候选 DMA + Double Buffer?

当 Producer-Consumer 的环形缓冲区丢样太多时升级到这里。在实际负载下比较读取时延和丢样情况,再判断双缓冲是否改善吞吐。

DMA 需要硬件支持

核对 ADXL355 的 SPI 总线初始化与实际驱动配置,再判断是否启用了底层 DMA。

双缓冲 = 2 × buffer_size × 28 bytes

两个 512 样本的缓冲需要约 28 KB。这是历史内存估计;按 2 * buffer_size * sizeof(rt_process_sample_t) 核对目标构建,还需计入锁、任务栈与队列。