
Originally Posted by
KurtE
@Blackaddr - yes you might say I was a bit involved in the beta...
Put simply if you, do something like malloc a tx and rx buffer, initialize the tx buffer and setup your tx and rx DMAChannels to point to these two buffers and do a DMA operation, and then look at the returned data in rx buffer, you may find that stuff you put into the TX Buffer was not what was sent over the MOSI pin, and the data returned on the MISO pin may not be what you see when you look at it with your program.
Why? The upper 512KB of memory (OCRAM) is cached. The normal processor instructions work through the cache, while DMA works directly with the actual contents stored in memory, which if the Cache has not flushed its updated values to memory or retrieved updated values from memory when those have changed, they will be different...
There are ways to force these two cases: TX case: arm_dcache_flush(write_data, count); RX case: arm_dcache_delete(retbuf, count)
Thanks KurtE, I was not aware of that particular transfer() function, I'll go look into it. As for the the cache issue, should not the pointers to the buffers be volatile? In fact, shouldn't this be enforced by the transfer signature?
Code:
// Since DMA will work directly on system memory, not the cache contents DMA buffer must be declared volatile.
bool transfer(const volatile void *txBuffer, volatile void *rxBuffer, size_t count, EventResponderRef event_responder);
When I look at the DmaSpi.h implementation I see that the signature is partially correct. The RX buffer is volatile, the source buffer is const, but not volatile. As you rightly point out, if you setup a DMA channel to use a particular TX buffer address, then you modify the buffer contents before triggering the DMA write, the buffer contents might still in cache and not flushed out to memory.
Code:
Transfer(const uint8_t* pSource = nullptr, // this should be volatile as well
const uint16_t& transferCount = 0,
volatile uint8_t* pDest = nullptr, // this is correctly specified as volatile
const uint8_t& fill = 0,
AbstractChipSelect* cs = nullptr
)