Some background info about my problem:
- I have an external device that is constantly giving me data through SPI
- I handle SPI reads with DMA from userspace, as kernel based solutions (already implemented and my own driver) turned out to have too much latency sometimes - see this question
- the data format is: one byte "header" that indicates presence of data, and - if header is non-zero - 256 byte data chunk follows
- if header byte turns out to be 0, there is no data chunk whatsoever, and I need to check following byte, if it is also 0, then the next one, etc, until I find non-zero byte - then I know I have 256 bytes of data following
- I receive data from my SPI device into one of several buffers (for now it's two), when I finish writing to one buffer then I start filling next one, after the last one is filled I'm going back to the first
- to further process my data and separate useful bytes from header bytes, I need to copy 256 bytes data chunks from device buffer into some separate buffer (processing data in the same input buffer would be risky, as I may not keep up with processing the data and end up with it being overwritten)
First thing I tried was simple CPU-side copying, and it works, but uses relatively lot of CPU time. I was thinking about using DMA for that, but I have a few worries:
- Although target address data could always be nicely aligned to 256 bytes, the same couldn't be said about source addresses, which - because of header bytes - would not allow start of every data part of consecutive batch to be power-of-two aligned (in fact, very few such data batches would be nicely aligned at all). In BCM2835 ARM Peripheral documentation it is stated that:
The DMA can deal with byte aligned transfers and will minimise bus traffic by buffering and packing misaligned accesses
but I'm not sure if this means that source and/or destination address might not be aligned to some power of two amount of bytes.
I'm also not sure how to interpret SRC_WIDTH and DEST_WIDTH in DMA Transfer Information. Looks like I can choose either 4 or 16 bytes to be read / written at once? But why set it up separately for source and destination? I mean, if I do, for example, 128 bit reads, can I do 32-bit writes? Does it make any sense? And most importantly, should I go for higher read/write widths, or does it not impact performance?
In DMA Transfer Information I can also set something called BURST_LENGTH. This is something I don't quite understand, because burst is said not to be working in all scenarios? And that setting up too many burst bytes may stack and effectively stall consecutive memory transfer operations? So how should I set burst so that I can achieve best performance without it backfiring in any way?
DMA transfers require source and target memory to be given as bus addresses. As I understand, there are two ways of achieving this:
- to allocate some memory on GPU through VC Mailbox and retrieve physical and bus addresses from it
- or to find out how particular part of virtual memory maps to physical one, and retrieve bus address from physical
But it looks like first approach is generally more advised because in this way I can obtain non-cached memory. It seems like cached memory is not very DMA friendly, but is it, really? I mean - in my scenario, I would first copy my data from one buffer to another, and only then access output buffer on CPU side, so it not being cached at the time would not be a big deal, would it?
I'd be grateful for any tips and information, I'm not that experienced with using RPI's DMA engine.