I’ve spent some time on it today and double buffering with DMA is working well.
But it does not use a completion interrupt as we don’t have any code for that at the moment, as there are issues with callbacks to functions in C classes – though @victor_pv has been investigating callbacks and I’ve PM’ed him about this and I’m hoping he can help.
I added a new function to SPI called dmaSendAsync(), which returns immediately after the transfer has been started.
But, I also added a static flag to indicate if a transfer had already been started, and added code to the start of the function, which waits for completion of a transfer if one is in progress (as determined by the static flag)
The downside of this approach, is that I don’t know when a transfer has finished, so can’t time the 50uS Reset time.
However, as other people have already pointed out, the Reset time that is actually needed is only around 6uS, and the function call overhead and DMA tidy-up etc etc, plus the 8 byte of zeros that is send prior to the start of the real data, mean that I get around 12uS of unavoidable dead time between each transfer. So there is no need to add code to determine if enough Reset time has been allowed.
Actually, its taken several hours to get this working, because double buffering caused all sorts of strange effects when running the standard example like colorWipe()
I initially thought that I’d messed up the buffer pointers, or perhaps I was writing to the same buffer that was being etc etc
However after hours of trying to send all zeros or all ones etc to confirm that none of the above was happing….
I realised that the LED effects like colorWipe() do not build the data for the entire strip of leds (30 in my case), they often just modify 1 or 2 LEDs, and because I had 2 separate buffers, the effects were building on the data from the show() from 2 frames ago
E.g. colorWipe() of Red (0=off) looks like
OOOOOOOOOO
ROOOOOOOOO
RROOOOOOOO
RRROOOOOOO
RRRROOOOOO
Etc
But because I have 2 buffers I ended up with
OOOOOOOOOO (buffer 1 and 2 initial all off)
ROOOOOOOOO (buffer 2)
OROOOOOOOO (buffer 1 plus R in 2nd LED)
ROROOOOOOO (buffer 2 plus R in 3rd LED)
OROROOOOOO (buffer 1 plus R in 4nd LED)
etc
So I ended up with alternately flashing Red leds
Anyway, the solution is to copy the buffer each time its send via SPI. This does waste a bit of time, but I do the buffer copy after the dmaSendAsync has been called, so that its done in parallel with the data being sent to the LEDs
I could probably do the memory copy in DMA, but I think for small numbers of bytes e.g 30 LEDS = 272 bytes, that the setup time would probably not be worth it. And it could be better to code it in inline assembler.
BTW. I also made some speed improvements by making one LUT rather than 3 (R,G,B) LUTS as this allows for pointer incrementing when reading the encoded values as well as the output position
I’ve updated my github repo, and I’ve also added it to the Libmaple F1 core libraries, so if you want to try it, please download the latest version of the core from github