// Teensy 4.0 Program to test high speed DMA from memory and GPIO2 to memory. //
#include <Arduino.h>
#include "DMAChannel.h"
#define Print_Verbose 1 // If 1, print verbose raw buffer data
#define VERBOSE_SIZE 1024 // Number of values to print: first 32, then 1 every 32nd sample
#define BUFFER_SIZE 10000 // Total buffer size in 32 bit words for samples
#define TRANSFER_SIZE 10000 // Transfer size in 32 bit words
float Start_Time = 0; // Measure time spent in transfer (us)
float End_Time = 0;
float Elapsed_Time_Float = 0; // End Time - Start Time (us)
float Time_per_Copy_Float = 0; // (ns)
float Transfer_Size_Float = 0; // Points
// DMA buffer
static uint32_t srcBuffer[BUFFER_SIZE] __attribute__((section(".dtcm"), aligned(32)));
static uint32_t destBuffer[BUFFER_SIZE] __attribute__((section(".dtcm"), aligned(32)));
// Completion flag
volatile bool transferComplete = false;
// DMA channel
DMAChannel dma;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
// Initialize serial
Serial.begin(115200);
// Print banner
Serial.print("\n\n\n\n\n\n\n\n******** Direct DMA Tests from Memery and GPIO to Memory *******\n");
/***** Transfer of sequential numbers from memory to memory. *****/
Serial.printf("\n Transfer of %d 32 bit words from srcBuffer to destBuffer.", TRANSFER_SIZE);
Serial.println(" Source: srcBuffer array index; Destination prefilled with 0xDEADFEEDs");
// Initialize buffers sequential values and constant 0xDEADFEEDs
for (int i = 0; i < BUFFER_SIZE; i++) {
srcBuffer[i] = i;
destBuffer[i] = 0xDEADFEED;
}
// Initialize DMA memory to memory transfer
dma.begin(true);
dma.sourceBuffer(srcBuffer, BUFFER_SIZE); // BUFFER_SIZE doesn't appear to make a difference
// Flush source cache - may be needed to not keep copying old stuff
arm_dcache_flush_delete(srcBuffer, sizeof(srcBuffer));
Capture_and_Analyze();
/***** Transfer of GPIO2_PSR to memory. *****/
Serial.printf("\n Transfer of %d 32 bit words from GPIO2_PSR to destBuffer:", TRANSFER_SIZE);
Serial.println(" Source: GPIO2_PSR; Destination prefilled with 0xDEADFEEDs");
// Load srcBuffer with constant length random numbers and destBuffer with 0xDEADFEEDs
for (int i = 0; i < BUFFER_SIZE; i++) {
destBuffer[i] = 0xDEADFEED;
}
// Initialize DMA fpr GPIO2 transfer. PSR = "Pin State Register". Do NOT use GPIO_DR as it is really for output.
dma.begin(true);
dma.sourceBuffer(&GPIO2_PSR, BUFFER_SIZE); // BUFFER_SIZE doesn't appear to make a difference
dma.TCD->SOFF = 0; // Don't increment source address for GPIO
// Do it!
Capture_and_Analyze(); // Analysis has been stripped out to save space. ;-)
/***** End *****/
Serial.print("\nTests Complete.\n\n");
}
// ISR for DMA completion
void dma_complete_isr(void) {
transferComplete = true;
dma.clearInterrupt();
}
#define DMA_CHANNEL 0 // Choose DMA Channel 0
// Capture and printout of some values, no analysis.
void Capture_and_Analyze() {
arm_dcache_flush_delete(destBuffer, sizeof(destBuffer)); // Flush destination cache - needed to force copy
dma.destinationBuffer(destBuffer, TRANSFER_SIZE * 4); // Must be 4x?
dma.transferSize(4); // 4 bytes (32-bit)
dma.disableOnCompletion();
dma.attachInterrupt(dma_complete_isr); // ISR diables DMA
dma.interruptAtCompletion();
dma.triggerContinuously();
Serial.print("\n Starting DMA transfer. ");
transferComplete = false;
Start_Time = micros(); // Wait for completion or timeout
dma.enable(); // Do it!
while (!transferComplete) {
if ((micros() - Start_Time) > 10000) {
Serial.printf(">>>>>>>> DMA TRANSFER TIMED OUT <<<<<<<<\n");
return;
}
}
End_Time = micros();
// Display transfer time, time/copy, and copy frequency
Serial.printf("Elapsed Time: ");
Elapsed_Time_Float = End_Time - Start_Time;
Serial.print(Elapsed_Time_Float);
Serial.printf(" Microseconds; Time per Copy: ");
Transfer_Size_Float = TRANSFER_SIZE;
Serial.print(Time_per_Copy_Float = (1000 * Elapsed_Time_Float) / Transfer_Size_Float);
Serial.printf(" ns; Transfer Rate: ");
Serial.print(1000 / Time_per_Copy_Float);
Serial.printf(" MW/s.\n");
#if Print_Verbose == 1
// Display the raw captured data in a readable format
Serial.printf("\n Sample Value\n --------------------\n");
// Print each sample with pin data bit values
for (uint32_t i = 0; i < VERBOSE_SIZE; i++) {
// Only print first 32 samples, then every 32nd sample to avoid flooding serial
if (i < 32 || i % 32 == 0) {
uint32_t value = destBuffer[i];
Serial.printf(" %4d 0x%08X\n", i, value); // Print sample number and raw hex value
}
// Print a summary message if we're skipping a lot of data
if (i == 32) {
Serial.println(" ... (printing every 32nd sample) ...");
}
}
#endif
}
// Show activity using LED_BUILTIN indicating that code hasn't crashed totally
void loop() {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
delay(100);
}