-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mixing SPI DMA and normal calls not working, no callback function for SPI DMA complete? #24
Comments
try these examples |
While the ZeroDMA examples were the first I found I am trying to use this one: void SPIClass::transfer(const void *txbuf, void *rxbuf, size_t count, bool block) { So this really is not a ZeroDMA issue but an issue with the new SAMD SPI class. |
yah we never used it, if you have ideas for how to fix please submit a PR :) |
@RudolphRiedel I think I also ran into the same issue. Like you said calling SPI.waitForTransfer() before making the next transfer addresses the issue, but makes DMA pointless. Not sure if this is exactly relevant to your use case, but as a workaround, instead of calling SPI.waitForTransfer() right after starting the transfer, I start a timer (in your case it would be for about 291us) and continue on with with other program logic and then call SPI.waitForTransfer() once the 291us has elapsed, which means SPI.waitForTransfer() should more-or-less return immediately (assuming your transfers all take about 291us). I think a cleaner solution, if feasible, would be to add a method SPI.isTransferComplete() that returns a status immediately (i.e., whether the transfer is complete), so the client code doesn't need to maintain any timing logic and is also robust to varying transfer times. |
@ladyada Well okay, this is not what I was hoping for as I am only supporting the use of Arduino but not using it myself. @rostamiz And there is no way to tell how much time the transfer will actually take, like I wrote, this is only my basic demo, actual projects need to send a lot more data, up to 4k. |
the SPI library just isn't designed for DMA... there's a benefit to having DMA used even if it blocks, because the inter-byte delays are removed. please use the zerodma library :) |
Okay, I'll check out ZeroDMA. |
it doesnt hardfault, we dont guarantee it solves all your life problems :D |
After some more fiddling and comparing the code back and forth with my bare metal implementation I got it working. I setup a write-only DMA transfer since this is what I need. But apparently this is different when using DMA, the whole buffer is still transferred just fine, otherwise I would have caught this sooner. I fixed it by switching of the the receiver before transmitting the block and switching it back on in the callback-function. void dma_callback(Adafruit_ZeroDMA dma) void EVE_start_dma_transfer(void) And this is exactly what is broken in https://github.com/adafruit/ArduinoCore-samd/blob/master/libraries/SPI/SPI.cpp as well. It works fine now and the time for a display-refresh went down from 291µs which included the SPI transfer to only 15µs for composing the buffer and sending it over SPI using DMA. |
So I had a glimpse at SPI.cpp to fix DMA for write-only transfers. As a workaround I allow the DMA to overwrite my output buffer with the incoming "data": Now only the issue of the SPI.waitForTransfer() beeing the only option to determine that DMA is done remains. |
I put in a pull-request for SPI.cpp with an added method isBusy() to allow for non-blocking polling of the DMA transfer status. |
I am trying to make use of the DMA feature for SPI with a Metro M4, are there any current examples for this?
SPI.transfer(&buffer, 0, 1234, false);
Or to be more precise, what I am actually using is:
SPI.transfer( ((uint8_t *) &EVE_dma_buffer[0])+1, 0, (((EVE_dma_buffer_index)*4)-1), false );
This works, but only once.
The following normal SPI.transfer() calls for single bytes seem to be working with DMA as well.
This is what it should look like, this is from before using DMA transfer:
And this is how it actually looks:
With this my program hangs, there is nothing else on the SPI and the LED is not blinking.
And without callback function it overall looks like this now:
From that I gather from https://github.com/adafruit/ArduinoCore-samd/blob/master/libraries/SPI/SPI.cpp the only option right now would be to call SPI.waitForTransfer()?
This makes DMA kind of pointless.
Without DMA it works fine for a while now:
But I would like to avoid blocking the CPU for this 291µs period, even more so as this is only from a very short and basic example of my FT81x/BT81x code library: https://github.com/RudolphRiedel/FT800-FT813
The text was updated successfully, but these errors were encountered: