samedi 25 juillet 2020

Synchronization requirements for DMA

Let me tell you a story:

I have two buffers setup, to do what is called ping ponging. I have a DMA system pointing to each of the buffers.

The system is setup such that the DMA is writing data to one buffer, while an interrupt processes the data in the other buffer.

That would look something like this:

#include <atomic>
#include <array>
#include <algorithm>

using buf_t = std::array<std::uint32_t, 32>;

std::array<buf_t,2> ping_pong;

/*
 * In this example I am just going to push the data to a "peripheral"
 */
#define PORT (*(volatile std::uint32_t*)0x1234)


void handle_data(buf_t const& data)
{
    std::for_each(std::begin(data),std::end(data), [](auto x){
        PORT = x;
    });
}

void isr1(void)
{
    std::atomic_thread_fence(std::memory_order::memory_order_acquire);
    handle_data(ping_pong[0]);
}
void isr2(void)
{
    std::atomic_thread_fence(std::memory_order::memory_order_acquire);
    handle_data(ping_pong[1]);
}

Now my questions are this:

Is this defined behavior? What is preventing the compiler from getting rid of any access to ping_pong, because it cannot see the stuff that sets it?

At least with the current gcc compiler it seems to work: godbolt

Aucun commentaire:

Enregistrer un commentaire