以原子方式交换指针以在 C 中实现双缓冲

Swap pointers atomically to implement double buffering in C

我有一个 cortex M3 系统,它在通过 DMA 提供的数据缓冲区上执行一些代码。有 3 个缓冲区:1 个用于 DMA 的连续流,1 个用于在 50% 点和 100% 复制流数据,另一个用于存储要操作的副本。

一旦缓冲区填满一半,ISR 就会复制缓冲区的第一半,当缓冲区完全填满时再复制第二半。

当第一个缓冲区的下半部分再次流入时,我将第二个缓冲区和第三个缓冲区交换,并对最近填充的数据进行操作。我的担心来自指针交换。这将导致 1 条加载指令和 2 条存储指令。如果发生 ISR,我可能会以内存泄漏 and/or 数据丢失而告终。是否有一种原子方式来交换这些指针?我想避免丢弃数据并在 DMA 再次满时等待下一次迭代,并避免禁用中断。

另外关于中断和数据丢失,假设有一个音频流,并且对流进行的处理跟不上输入速率。我们会丢弃数据吗?它与以太网控制器或 USB 控制器等类似吗?我很好奇这个问题在其他系统中是如何解决的。

你真的开始处理每个 DMA 填充的第一个缓冲区上的数据,还是只是将数据(根据 memcpy() 我从你的描述假设)复制到其他缓冲区,无论是什么原因将它们全部复制。

为什么要在某个地方以 50%/100% 的比例复制,然后有另一个缓冲区“存储要操作的副本”。

特别是,当您按照 memcpy() 进行复制时,您甚至可以在 CPU 上放置更多的复制 activity,并且剩下更少的 CPU 资源实际处理数据本身。

也许您甚至可以配置传入的 DMA 以将数据放置在适当的双缓冲存储器中。或者,如果您确实需要复制,请设置一个新的 DMA 来执行此操作。

要更新指针,请在周围设置专属区域,例如锁定中断。

void Handler() {
    
    enter_exarea_0();
    // --- Exclusive Area0 start ---
    // .. switch pointers 
    // --- Exclusive Area0 end ---
    exit_exarea_0();
    // activity
}

void enter_exarea_0() {
    // Disable All Interrupts or up to a certain interrupt lock level
}
void exit_exarea_0() {
    // Enable All interrupts or decrease the interrupt lock level
}

如果你太慢,这有点取决于数据。

您可以停止处理当前 frame/data 并开始处理下一个,因此,您可能只处理了 50% 或 70%,例如如果每一帧都有 1000 个样本 x/y 的数组,也许你在最后放了一些 x/y 个样本。

或者您完成 frame/data 处理并由于较新的可用帧而跳过较旧的可用帧。或者 DMA 刚刚覆盖了一个未处理的帧,例如如果每一帧都是一张图片,您可能会丢失一系列图片的完整图片。