Hi, I thought I had DMA/SPI on the Teensy 3.1 working however noticed some graphics glitches that went away if I used any of the other SPI options I have including Teensy FIFO without DMA.
After sending several pages of bitmap data to an 1306 OLED I noticed the last few (3-4) bytes are usually garbled and get missed out.
If I send X bytes one at a time it works but sending via a buffer seems to have a problem.
I basically adapted some of this from a previous post :-
Notice after the enable it just runs off and starts the transfer but it doesn't check if it's complete.
I have a function that checks... that seems to almost work. I suspect now it waits for the DMA to finish but it may still have 1 - 4 bytes in the SPI FIFO. Seems very coincidental the number of bytes "missing" is anywhere 0 - 4 bytes by the looks.
The function that's mainly working is (note a lot of the setup code usually outside main loop... but bought in while trying to resolve problem) :-
** I put a small delay before disabling CS and it "worked" as it gave it enough time to complete the last few bytes. Just need a way to determine this in code.
After sending several pages of bitmap data to an 1306 OLED I noticed the last few (3-4) bytes are usually garbled and get missed out.
If I send X bytes one at a time it works but sending via a buffer seems to have a problem.
I basically adapted some of this from a previous post :-
Code:
#include "DMAChannel.h"
DMAChannel dmachannel;
uint8_t data[256];
void setup() {
// Setup the SPI clocks and pin configurations
SPI.begin();
// Setup SPI for DMA transfer
SPI0_SR = 0xFF0F0000;
SPI0_RSER = 0x00;
SPI0_RSER = SPI_RSER_TFFF_RE | SPI_RSER_TFFF_DIRS; // Make sure SPI triggers a DMA transfer after each transmit
dmachannel.sourceBuffer(data, 256); // The data for which we wish to transmit and it's length
dmachannel.destination((volatile uint8_t&)SPI0_PUSHR); // Move data into the SPI FIFO register
dmachannel.triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_TX); // Only transfer data once the previous byte has been transmited (This is to ensure all bytes are sent)
dmachannel.disableOnCompletion(); // Stop after transmitting all 256 bytes
dmachannel.enable(); // Begin transmit
}
void loop() {
// put your main code here, to run repeatedly:
}
Notice after the enable it just runs off and starts the transfer but it doesn't check if it's complete.
I have a function that checks... that seems to almost work. I suspect now it waits for the DMA to finish but it may still have 1 - 4 bytes in the SPI FIFO. Seems very coincidental the number of bytes "missing" is anywhere 0 - 4 bytes by the looks.
Code:
__INLINE__ void cDMA_spi_send_do_wait_buffer()
{
while (!DMAtx.complete()) { } // wait for dma
// now need to wait for last bytes of SPI to finish
//delayMicroseconds(5);
SPI0_RSER = 0;
SPI0_SR = 0xFF0F0000;
}
The function that's mainly working is (note a lot of the setup code usually outside main loop... but bought in while trying to resolve problem) :-
Code:
__INLINE__ void cDMA_spi_send(void *buf, uint32_t n) // this allows for buffers larger than what DMA usually can handle by breaking them down
{
uint8_t *buff = (uint8_t *)buf;
while (n)
{
uint32_t bytes = (n <= 1024) ? n : 1024; // need find the actual max... when have the rest working
DMAtx.destination((volatile uint8_t &)SPI0_PUSHR);
DMAtx.triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_TX);
DMAtx.disableOnCompletion();
SPI0_SR = 0xFF0F0000;
SPI0_RSER = SPI_RSER_RFDF_RE | SPI_RSER_RFDF_DIRS | SPI_RSER_TFFF_RE | SPI_RSER_TFFF_DIRS;
DMAtx.sourceBuffer((volatile const uint8_t *)buff, bytes);
DMAtx.enable(); // go!
n -= bytes;
buff += bytes;
cDMA_spi_send_do_wait_buffer();
}
}
** I put a small delay before disabling CS and it "worked" as it gave it enough time to complete the last few bytes. Just need a way to determine this in code.