I have a proof of concept of using DMA to do a SPI block write on the ZERO. I couldn't quite get the syntax right for the address of the SPI data register, so I did something ugly. I haven't run it with a SPI device, but have hooked it up to logic analyzer to confirm SPI CLK and MOSI data. Initial sketch is github. It only uses one DMA channel to do the transmit. You would need two channels for concurrent send/receive. Data rate is close to SPI CLK speed.
here are data rates (megabits/sec mbs) for SPI.transfer() in a loop versus DMA transfer of 1024 bytes.
For comparison, here are SPI+DMA results for other MCUs.
EDIT:
Extended sketch to use two DMA channels, so you can do read, write, transfer. github site updated. Stable up to 8mhz, some strangeness at 12 mhz when mixing DMA SPI with standard SPI? TODO.
This is a great proof of concept for DMA. I found that the last few bits of each SPI transfer using DMA was getting cut off. I added a 25 micro Second delay before bringing the Slave Select high solved the issue. I take it up to a clock speed of 12MHz without any noticeable issues.
@ dlabun : are you shure the problem doesn't come from your system? I use this code to transfer 256 bytes buffer in continuous and I miss no data. I've even checked with my scope to see what the signal is looking like.
The whole point of DMA is to handle the transfer without further assistance.
You can use the DMA_COMPLETE interrupt to disable your Chip-Select.
You can be using the CPU for unrelated processing.
Ok, you know how long the transfer will be, but simply delaying for this time is no better than polling the transfer in software without DMA. You can not do anything else.
Incidentally, the official SPI.transfer() method is cr*p. The underlying SERCOM can achieve full speed SPI. But there are a few "anomalies".
From what I can see on my scope the Slave Select is rising just slightly faster than the last bit ending. It's very close, but the Slave Select beats out the SPI transmission just about every time. It could merely be an electrical issue with my board.
Dave brings up valid points, I am going to see if I can implement using DMA_COMPLETE.
david_prentice:
Incidentally, the official SPI.transfer() method is cr*p. The underlying SERCOM can achieve full speed SPI. But there are a few "anomalies".
David, do you mean that the Arduino SPI lib is the limiting element that constrain SPI to 12MHz, and that using sercom only, we can achieve higher speed?
Yes, it is a problem with the SPI lib. You would think that SPI.transfer(char *string) would work without gaps like Serial.write(char *string) does with the UART.
However, the obvious solution does not seem to work properly. There is something odd going on. I will post a few examples later.
I have another question about this code : how to reset everything (DMA register) to initial state (state of register before use of this code), without resetting the board?
Maybe something like a DMA.end() function...
By the way, I'm using a library wrap up for this code, see attached document.
I have a STM32F103, and I want to use it as an interfacing circuit to transfer the data of two SPI's to a computer via USB 2.
After my explorations, I found that it is not possible to transfer this amount of data( each SPI have a frequency about 2 MHz) without a DMA activation.
Anyone can help me? I don't know how to use DMA on STM at all:( I am even not familiar with the code of USB 2.
Looking forward for your answers,
Thanks in advance,
Ava