#include <WProgram.h>
#include "DMAChannel.h"
#include "SPI.h"
/** Hardware setup:
plain Teensy 3.1 with DOUT connected to DIN
nothing else
**/
/** buffers to send from and to receive to **/
#define DMASIZE 1000
uint8_t src[DMASIZE];
volatile uint8_t dest[DMASIZE];
/** The DMA channel objects **/
DMAChannel txChannel;
DMAChannel rxChannel;
/** for timing checks **/
elapsedMicros txTime;
uint32_t fillTime;
uint32_t totalTime;
/** supposed to be called when the Tx DMA is done **/
void txComplete()
{
txChannel.clearInterrupt(); // we need this to not get any more ISR calls
fillTime = txTime;
}
/** supposed to be called when the Rx DMA is done **/
void rxComplete()
{
rxChannel.clearInterrupt(); // we need this to not get any more ISR calls
totalTime = txTime;
}
/** Wait for and consume a keypress over USB **/
void waitForKeyPress()
{
Serial.println("\nPress a key to continue\n");
while(!Serial.available());
while(Serial.available())
{
Serial.read();
}
}
void dumpBuffer(const volatile uint8_t* buf, const char* prefix)
{
Serial.print(prefix);
for (size_t i = 0; i < DMASIZE; i++)
{
Serial.printf("0x%02x ", buf[i]);
}
Serial.print('\n');
}
/** Compare the buffers and print the destination contents if there's a mismatch **/
void compareBuffers()
{
int n = memcmp((const void*)src, (const void*)dest, DMASIZE);
if (n == 0)
{
Serial.println("src and dest match");
}
else
{
Serial.println("src and dest don't match");
dumpBuffer(src, " src: " );
dumpBuffer(dest, "dest: ");
}
}
void setup()
{
waitForKeyPress();
Serial.println("Hi!");
/** Prepare source and destination **/
for (size_t i = 0; i < DMASIZE; i++)
{
src[i] = i;
}
memset((void*)dest, 0x00, DMASIZE);
Serial.println("Buffers are prepared");Serial.flush();
/** set up SPI **/
SPISettings spiSettings;
SPI.begin();
// transmit 10 bytes and measure time to get a feel of how long that takes
SPI.beginTransaction(spiSettings);
elapsedMicros us;
for (size_t i = 0; i < DMASIZE; i++)
{
dest[i] = SPI.transfer(src[i]);
}
uint32_t t = us;
Serial.print("Time for non-DMA transfer: ");Serial.print(t);Serial.println("us");
SPI.endTransaction();
compareBuffers();
waitForKeyPress();
txTime = elapsedMicros();
/** Prepare the SPI for DMA operation **/
SPI.beginTransaction(spiSettings);
SPI0_SR = 0xFF0F0000;
SPI0_RSER = 0;
SPI0_RSER = SPI_RSER_RFDF_RE | SPI_RSER_RFDF_DIRS | SPI_RSER_TFFF_RE | SPI_RSER_TFFF_DIRS;
Serial.println("SPI is prepared for DMA"); Serial.flush();
// /** set up a DMA channel for transmitting src to the SPI **/
txChannel.sourceBuffer(src, DMASIZE);
txChannel.destination((volatile uint8_t&)SPI0_PUSHR);
txChannel.disableOnCompletion();
txChannel.triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_TX);
txChannel.attachInterrupt(txComplete);
txChannel.interruptAtCompletion();
Serial.println("Tx DMA channel is prepared"); Serial.flush();
/** set up a DMA channel for receiving from the SPI to dest **/
rxChannel.source((volatile uint8_t&)SPI0_POPR);
rxChannel.destinationBuffer((volatile uint8_t*)dest, DMASIZE);
rxChannel.disableOnCompletion();
rxChannel.triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_RX);
rxChannel.attachInterrupt(rxComplete);
rxChannel.interruptAtCompletion();
Serial.println("Rx DMA channel is prepared"); Serial.flush();
memset((void*)dest, 0x00, DMASIZE);
Serial.println("\nStarting DMA transfer");
t = txTime;
Serial.print("DMA Setup time: ");Serial.print(t);Serial.println(" us");Serial.flush();
txTime = elapsedMicros();
rxChannel.enable();
txChannel.enable();
while(!rxChannel.complete())
{
}
Serial.println("Finished DMA transfer");
Serial.print("SPI FIFO fill time: ");Serial.print(fillTime);Serial.println(" us");Serial.flush();
Serial.print("Total transfer time: ");Serial.print(totalTime);Serial.println(" us");Serial.flush();
compareBuffers();
SPI.endTransaction();
SPI.end();
pinMode(LED_BUILTIN, OUTPUT);
}
void loop()
{
digitalWriteFast(LED_BUILTIN, true);
delay(500);
digitalWriteFast(LED_BUILTIN, false);
delay(500);
}