Add teensy4 support (#9)

* T4 SPI DMA is a work in progress

* Final checkin for T4 support before hardware release
pull/10/head
Blackaddr Audio 5 years ago committed by GitHub
parent 5ee7688e5d
commit b6a94c4bf2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      examples/Basic/BA1_TGA_Pro_NOMEM_demo/BA1_TGA_Pro_NOMEM_demo.ino
  2. 11
      examples/Basic/BA2_TGA_Pro_1MEM/BA2_TGA_Pro_1MEM.ino
  3. 14
      examples/Basic/BA3_TGA_Pro_2MEM/BA3_TGA_Pro_2MEM.ino
  4. 1
      examples/Delay/AnalogDelayDemo/AnalogDelayDemo.ino
  5. 6
      examples/Delay/AnalogDelayDemoExpansion/AnalogDelayDemoExpansion.ino
  6. 9
      examples/Delay/ExternalDelayDemo/ExternalDelayDemo.ino
  7. 5
      examples/Delay/SoundOnSoundDemo/SoundOnSoundDemo.ino
  8. 6
      examples/Delay/SoundOnSoundExpansionDemo/SoundOnSoundExpansionDemo.ino
  9. 1
      examples/Modulation/TemoloDemo/TemoloDemo.ino
  10. 4
      examples/Modulation/TremoloDemoExpansion/TremoloDemoExpansion.ino
  11. 2
      examples/Tests/BaudrateTest/BaudrateTest.ino
  12. 25
      examples/Tests/DMA_MEM0_test/DMA_MEM0_test.ino
  13. 24
      examples/Tests/DMA_MEM1_test/DMA_MEM1_test.ino
  14. 7
      examples/Tests/TGA_PRO_MEM2_EXP/PhysicalControls.cpp
  15. 19
      examples/Tests/TGA_PRO_MEM2_EXP/TGA_PRO_MEM2_EXP.ino
  16. 5
      examples/Tests/TGA_PRO_MEM2_EXP/UartTest.cpp
  17. 10
      examples/Tests/TGA_PRO_MEM2_EXP/spiTest.cpp
  18. 11
      keywords.txt
  19. 4
      src/BAAudioControlWM8731.h
  20. 10
      src/BAAudioEffectDelayExternal.h
  21. 263
      src/BAHardware.h
  22. 28
      src/BAPhysicalControls.h
  23. 33
      src/BASpiMemory.h
  24. 155
      src/DmaSpi.h
  25. 1
      src/LibMemoryManagement.h
  26. 2
      src/common/AudioDelay.cpp
  27. 99
      src/common/BAHardware.cpp
  28. 31
      src/common/ExternalSramManager.cpp
  29. 73
      src/effects/AudioEffectDelayExternal.cpp
  30. 38
      src/peripherals/BAAudioControlWM8731.cpp
  31. 39
      src/peripherals/BAPhysicalControls.cpp
  32. 258
      src/peripherals/BASpiMemory.cpp
  33. 4
      src/peripherals/DmaSpi.cpp

@ -8,8 +8,6 @@
* This demo will provide an audio passthrough, as well as exercise the * This demo will provide an audio passthrough, as well as exercise the
* MIDI interface. * MIDI interface.
* *
* It can optionally exercise the SPI MEM0 if installed on the TGA Pro board.
*
*/ */
#include <Wire.h> #include <Wire.h>
#include <Audio.h> #include <Audio.h>
@ -37,6 +35,7 @@ void setup() {
MIDI.begin(MIDI_CHANNEL_OMNI); MIDI.begin(MIDI_CHANNEL_OMNI);
Serial.begin(57600); Serial.begin(57600);
delay(5); delay(5);
while (!Serial) { yield(); }
// If the codec was already powered up (due to reboot) power itd own first // If the codec was already powered up (due to reboot) power itd own first
codecControl.disable(); codecControl.disable();
@ -105,4 +104,3 @@ void loop() {
gpio.toggleLed(); gpio.toggleLed();
} }

@ -38,7 +38,7 @@ BASpiMemory spiMem0(SpiDeviceId::SPI_DEVICE0);
unsigned long t=0; unsigned long t=0;
// SPI stuff // SPI stuff
int spiAddress0 = 0; unsigned spiAddress0 = 0;
uint16_t spiData0 = 0xABCD; uint16_t spiData0 = 0xABCD;
int spiErrorCount0 = 0; int spiErrorCount0 = 0;
@ -52,9 +52,11 @@ void setup() {
MIDI.begin(MIDI_CHANNEL_OMNI); MIDI.begin(MIDI_CHANNEL_OMNI);
Serial.begin(57600); Serial.begin(57600);
while (!Serial) {} while (!Serial) { yield(); }
delay(5); delay(5);
SPI_MEM0_1M(); // Set the Spi memory size to 1Mbit
// If the codec was already powered up (due to reboot) power itd own first // If the codec was already powered up (due to reboot) power itd own first
codecControl.disable(); codecControl.disable();
delay(100); delay(100);
@ -98,7 +100,7 @@ void loop() {
// Write test data to the SPI Memory 0 // Write test data to the SPI Memory 0
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
maskPhase = 0; maskPhase = 0;
for (spiAddress0=0; spiAddress0 <= SPI_MAX_ADDR; spiAddress0=spiAddress0+2) { for (spiAddress0=0; spiAddress0 <= BAHardwareConfig.getSpiMemMaxAddr(0); spiAddress0=spiAddress0+2) {
if ((spiAddress0 % 32768) == 0) { if ((spiAddress0 % 32768) == 0) {
//Serial.print("Writing to "); //Serial.print("Writing to ");
//Serial.println(spiAddress0, HEX); //Serial.println(spiAddress0, HEX);
@ -117,7 +119,7 @@ void loop() {
spiAddress0 = 0; spiAddress0 = 0;
maskPhase = 0; maskPhase = 0;
for (spiAddress0=0; spiAddress0 <= SPI_MAX_ADDR; spiAddress0=spiAddress0+2) { for (spiAddress0=0; spiAddress0 <= BAHardwareConfig.getSpiMemMaxAddr(0); spiAddress0=spiAddress0+2) {
if ((spiAddress0 % 32768) == 0) { if ((spiAddress0 % 32768) == 0) {
// Serial.print("Reading "); // Serial.print("Reading ");
// Serial.print(spiAddress0, HEX); // Serial.print(spiAddress0, HEX);
@ -205,4 +207,3 @@ void loop() {
gpio.toggleLed(); gpio.toggleLed();
} }

@ -57,8 +57,13 @@ void setup() {
MIDI.begin(MIDI_CHANNEL_OMNI); MIDI.begin(MIDI_CHANNEL_OMNI);
Serial.begin(57600); Serial.begin(57600);
while (!Serial) { yield(); }
delay(5); delay(5);
// Set the SPI memory sizes
SPI_MEM0_1M();
SPI_MEM1_1M();
// If the codec was already powered up (due to reboot) power itd own first // If the codec was already powered up (due to reboot) power itd own first
codecControl.disable(); codecControl.disable();
delay(100); delay(100);
@ -103,7 +108,7 @@ void loop() {
// Write test data to the SPI Memory 0 // Write test data to the SPI Memory 0
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
maskPhase = 0; maskPhase = 0;
for (spiAddress0=0; spiAddress0 <= SPI_MAX_ADDR; spiAddress0=spiAddress0+2) { for (spiAddress0=0; spiAddress0 <= BAHardwareConfig.getSpiMemMaxAddr(0); spiAddress0=spiAddress0+2) {
if ((spiAddress0 % 32768) == 0) { if ((spiAddress0 % 32768) == 0) {
//Serial.print("Writing to "); //Serial.print("Writing to ");
//Serial.println(spiAddress0, HEX); //Serial.println(spiAddress0, HEX);
@ -122,7 +127,7 @@ void loop() {
spiAddress0 = 0; spiAddress0 = 0;
maskPhase = 0; maskPhase = 0;
for (spiAddress0=0; spiAddress0 <= SPI_MAX_ADDR; spiAddress0=spiAddress0+2) { for (spiAddress0=0; spiAddress0 <= BAHardwareConfig.getSpiMemMaxAddr(0); spiAddress0=spiAddress0+2) {
if ((spiAddress0 % 32768) == 0) { if ((spiAddress0 % 32768) == 0) {
// Serial.print("Reading "); // Serial.print("Reading ");
// Serial.print(spiAddress0, HEX); // Serial.print(spiAddress0, HEX);
@ -159,7 +164,7 @@ void loop() {
// Write test data to the SPI Memory 1 // Write test data to the SPI Memory 1
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
maskPhase = 0; maskPhase = 0;
for (spiAddress1=0; spiAddress1 <= SPI_MAX_ADDR; spiAddress1+=2) { for (spiAddress1=0; spiAddress1 <= BAHardwareConfig.getSpiMemMaxAddr(1); spiAddress1+=2) {
if ((spiAddress1 % 32768) == 0) { if ((spiAddress1 % 32768) == 0) {
//Serial.print("Writing to "); //Serial.print("Writing to ");
//Serial.println(spiAddress1, HEX); //Serial.println(spiAddress1, HEX);
@ -178,7 +183,7 @@ void loop() {
spiAddress1 = 0; spiAddress1 = 0;
maskPhase = 0; maskPhase = 0;
for (spiAddress1=0; spiAddress1 <= SPI_MAX_ADDR; spiAddress1+=2) { for (spiAddress1=0; spiAddress1 <= BAHardwareConfig.getSpiMemMaxAddr(1); spiAddress1+=2) {
if ((spiAddress1 % 32768) == 0) { if ((spiAddress1 % 32768) == 0) {
//Serial.print("Reading "); //Serial.print("Reading ");
//Serial.print(spiAddress1, HEX); //Serial.print(spiAddress1, HEX);
@ -264,4 +269,3 @@ void loop() {
gpio.toggleLed(); gpio.toggleLed();
} }

@ -82,6 +82,7 @@ void setup() {
// If using external memory request request memory from the manager // If using external memory request request memory from the manager
// for the slot // for the slot
#ifdef USE_EXT #ifdef USE_EXT
SPI_MEM0_1M();
Serial.println("Using EXTERNAL memory"); Serial.println("Using EXTERNAL memory");
// We have to request memory be allocated to our slot. // We have to request memory be allocated to our slot.
externalSram.requestMemory(&delaySlot, 500.0f, MemSelect::MEM0, true); externalSram.requestMemory(&delaySlot, 500.0f, MemSelect::MEM0, true);

@ -22,9 +22,6 @@
* Using the Serial Montitor, send 'u' and 'd' characters to increase or decrease * Using the Serial Montitor, send 'u' and 'd' characters to increase or decrease
* the headphone volume between values of 0 and 9. * the headphone volume between values of 0 and 9.
*/ */
#define TGA_PRO_REVB // Set which hardware revision of the TGA Pro we're using
#define TGA_PRO_EXPAND_REV2 // pull in the pin definitions for the Blackaddr Audio Expansion Board.
#include "BALibrary.h" #include "BALibrary.h"
#include "BAEffects.h" #include "BAEffects.h"
@ -99,6 +96,9 @@ void setup() {
Serial.begin(57600); // Start the serial port Serial.begin(57600); // Start the serial port
delay(100); delay(100);
// Configure the hardware
SPI_MEM0_1M();
// Setup the controls. The return value is the handle to use when checking for control changes, etc. // Setup the controls. The return value is the handle to use when checking for control changes, etc.
// pushbuttons // pushbuttons
bypassHandle = controls.addSwitch(BA_EXPAND_SW1_PIN); // will be used for bypass control bypassHandle = controls.addSwitch(BA_EXPAND_SW1_PIN); // will be used for bypass control

@ -22,6 +22,7 @@ AudioInputI2S i2sIn;
AudioOutputI2S i2sOut; AudioOutputI2S i2sOut;
BAAudioControlWM8731 codecControl; BAAudioControlWM8731 codecControl;
//AudioEffectDelayExternal longDelay;
BAAudioEffectDelayExternal longDelay(MemSelect::MEM0); // comment this line to use MEM1 BAAudioEffectDelayExternal longDelay(MemSelect::MEM0); // comment this line to use MEM1
//BAAudioEffectDelayExternal longDelay(MemSelect::MEM1); // and uncomment this one to use MEM1 //BAAudioEffectDelayExternal longDelay(MemSelect::MEM1); // and uncomment this one to use MEM1
AudioMixer4 delayOutMixerA, delayOutMixerB, delayMixer; AudioMixer4 delayOutMixerA, delayOutMixerB, delayMixer;
@ -49,12 +50,16 @@ AudioConnection outputRight(delayMixer, 0, i2sOut, 1);
void setup() { void setup() {
Serial.begin(57600); Serial.begin(57600);
AudioMemory(128); while(!Serial) { yield(); }
AudioMemory(64);
delay(100); delay(500);
Serial.println(String("Starting...\n")); Serial.println(String("Starting...\n"));
delay(100); delay(100);
SPI_MEM0_1M(); // set the SPI MEM0 memory size
// SPI_MEM1_1M(); // set the MEM1 memory aize
Serial.println("Enabling codec...\n"); Serial.println("Enabling codec...\n");
codecControl.enable(); codecControl.enable();
delay(100); delay(100);

@ -101,13 +101,15 @@ delay(100);
AudioMemory(128); AudioMemory(128);
delay(5); delay(5);
SPI_MEM0_1M(); // Configure the SPI memory size
// Enable the codec // Enable the codec
Serial.println("Enabling codec...\n"); Serial.println("Enabling codec...\n");
codec.enable(); codec.enable();
delay(100); delay(100);
// We have to request memory be allocated to our slot. // We have to request memory be allocated to our slot.
externalSram.requestMemory(&delaySlot, SPI_MEM0_SIZE_BYTES, MemSelect::MEM0, true); externalSram.requestMemory(&delaySlot, BAHardwareConfig.getSpiMemSizeBytes(MemSelect::MEM0), MemSelect::MEM0, true);
//externalSram.requestMemory(&delaySlot, 50.0f, MemSelect::MEM0, true); //externalSram.requestMemory(&delaySlot, 50.0f, MemSelect::MEM0, true);
// Setup MIDI // Setup MIDI
@ -192,4 +194,3 @@ void loop() {
// } // }
} }

@ -100,6 +100,7 @@ delay(100);
delay(100); // wait a bit for serial to be available delay(100); // wait a bit for serial to be available
Serial.begin(57600); // Start the serial port Serial.begin(57600); // Start the serial port
delay(100); // wait a bit for serial to be available delay(100); // wait a bit for serial to be available
BAHardwareConfig.set(MemSelect::MEM0, SPI_MEMORY_1M);
// Setup the controls. The return value is the handle to use when checking for control changes, etc. // Setup the controls. The return value is the handle to use when checking for control changes, etc.
// pushbuttons // pushbuttons
@ -117,13 +118,15 @@ delay(100);
codec.disable(); codec.disable();
AudioMemory(128); AudioMemory(128);
SPI_MEM0_1M(); // set the Spi memory size
// Enable the codec // Enable the codec
Serial.println("Enabling codec...\n"); Serial.println("Enabling codec...\n");
codec.enable(); codec.enable();
codec.setHeadphoneVolume(1.0f); // Max headphone volume codec.setHeadphoneVolume(1.0f); // Max headphone volume
// We have to request memory be allocated to our slot. // We have to request memory be allocated to our slot.
externalSram.requestMemory(&delaySlot, SPI_MEM0_SIZE_BYTES, MemSelect::MEM0, true); externalSram.requestMemory(&delaySlot, BAHardwareConfig.getSpiMemSizeBytes(MemSelect::MEM0), MemSelect::MEM0, true);
// Configure the LED to indicate the gate status, this is controlled directly by SOS effect, not by // Configure the LED to indicate the gate status, this is controlled directly by SOS effect, not by
// by BAPhysicalControls // by BAPhysicalControls
@ -223,4 +226,3 @@ void loop() {
loopCount++; loopCount++;
} }

@ -31,7 +31,6 @@ BAAudioControlWM8731 codec;
// YOU MUST USE TEENSYDUINO 1.41 or greater // YOU MUST USE TEENSYDUINO 1.41 or greater
// YOU MUST COMPILE THIS DEMO USING Serial + Midi // YOU MUST COMPILE THIS DEMO USING Serial + Midi
//#define USE_EXT // uncomment this line to use External MEM0
#define MIDI_DEBUG // uncomment to see raw MIDI info in terminal #define MIDI_DEBUG // uncomment to see raw MIDI info in terminal
AudioEffectTremolo tremolo; AudioEffectTremolo tremolo;

@ -18,8 +18,6 @@
* Using the Serial Montitor, send 'u' and 'd' characters to increase or decrease * Using the Serial Montitor, send 'u' and 'd' characters to increase or decrease
* the headphone volume between values of 0 and 9. * the headphone volume between values of 0 and 9.
*/ */
#define TGA_PRO_REVB // Set which hardware revision of the TGA Pro we're using
#define TGA_PRO_EXPAND_REV2 // pull in the pin definitions for the Blackaddr Audio Expansion Board.
#include "BALibrary.h" #include "BALibrary.h"
#include "BAEffects.h" #include "BAEffects.h"
@ -76,6 +74,8 @@ void setup() {
Serial.begin(57600); // Start the serial port Serial.begin(57600); // Start the serial port
delay(100); delay(100);
TGA_PRO_EXPAND_REV2(); // Configure the expansion board revision
// Setup the controls. The return value is the handle to use when checking for control changes, etc. // Setup the controls. The return value is the handle to use when checking for control changes, etc.
// pushbuttons // pushbuttons
bypassHandle = controls.addSwitch(BA_EXPAND_SW1_PIN); // will be used for bypass control bypassHandle = controls.addSwitch(BA_EXPAND_SW1_PIN); // will be used for bypass control

@ -11,7 +11,7 @@
*/ */
constexpr unsigned LOW_RATE = 2400; constexpr unsigned LOW_RATE = 2400;
constexpr unsigned MIDI_RATE = 31250; constexpr unsigned MIDI_RATE = 31250;
constexpr unsigned HIGH_RATE = 250000; constexpr unsigned HIGH_RATE = 230400;
constexpr unsigned TEST_TIME = 5; // 5 second test each constexpr unsigned TEST_TIME = 5; // 5 second test each
unsigned baudRate = LOW_RATE; // start with low speed unsigned baudRate = LOW_RATE; // start with low speed

@ -55,14 +55,18 @@ bool compareBuffers16(uint16_t *a, uint16_t *b, size_t numWords)
return compareBuffers(reinterpret_cast<uint8_t *>(a), reinterpret_cast<uint8_t*>(b), sizeof(uint16_t)*numWords); return compareBuffers(reinterpret_cast<uint8_t *>(a), reinterpret_cast<uint8_t*>(b), sizeof(uint16_t)*numWords);
} }
constexpr size_t TEST_END = SPI_MAX_ADDR; size_t SPI_MAX_ADDR;
;
void setup() { void setup() {
Serial.begin(57600); Serial.begin(57600);
while (!Serial) {} while (!Serial) { yield(); }
delay(5); delay(5);
SPI_MEM0_1M();
SPI_MAX_ADDR = BAHardwareConfig.getSpiMemMaxAddr(MemSelect::MEM0);
Serial.println("Enabling SPI, testing MEM0"); Serial.println("Enabling SPI, testing MEM0");
spiMem0.begin(); spiMem0.begin();
} }
@ -82,7 +86,7 @@ bool spi8BitTest(void) {
Serial.println("\nStarting 8-bit test Write/Read"); Serial.println("\nStarting 8-bit test Write/Read");
while (spiPhase < 4) { while (spiPhase < 4) {
spiAddress = 0; spiAddress = 0;
while (spiAddress < TEST_END) { while (spiAddress <= SPI_MAX_ADDR) {
// fill the write data buffer // fill the write data buffer
switch (spiPhase) { switch (spiPhase) {
@ -117,7 +121,7 @@ bool spi8BitTest(void) {
// Read back the data using 8-bit transfers // Read back the data using 8-bit transfers
spiAddress = 0; spiAddress = 0;
while (spiAddress < TEST_END) { while (spiAddress <= SPI_MAX_ADDR) {
// generate the golden data // generate the golden data
switch (spiPhase) { switch (spiPhase) {
case 0 : case 0 :
@ -165,7 +169,7 @@ bool spi8BitTest(void) {
// Clear the memory // Clear the memory
spiAddress = 0; spiAddress = 0;
memset(src8, 0, DMA_SIZE); memset(src8, 0, DMA_SIZE);
while (spiAddress < SPI_MAX_ADDR) { while (spiAddress <= SPI_MAX_ADDR) {
// Send the DMA transfer // Send the DMA transfer
spiMem0.zero(spiAddress, DMA_SIZE); spiMem0.zero(spiAddress, DMA_SIZE);
// wait until write is done // wait until write is done
@ -175,7 +179,7 @@ bool spi8BitTest(void) {
// Check the memory is clear // Check the memory is clear
spiAddress = 0; spiAddress = 0;
while (spiAddress < SPI_MAX_ADDR) { while (spiAddress <= SPI_MAX_ADDR) {
// Read back the DMA data // Read back the DMA data
spiMem0.read(spiAddress, dest8, DMA_SIZE); spiMem0.read(spiAddress, dest8, DMA_SIZE);
// wait until read is done // wait until read is done
@ -201,7 +205,7 @@ bool spi16BitTest(void) {
Serial.println("\nStarting 16-bit test"); Serial.println("\nStarting 16-bit test");
while (spiPhase < 4) { while (spiPhase < 4) {
spiAddress = 0; spiAddress = 0;
while (spiAddress < SPI_MAX_ADDR) { while (spiAddress <= SPI_MAX_ADDR) {
// fill the write data buffer // fill the write data buffer
switch (spiPhase) { switch (spiPhase) {
@ -236,7 +240,7 @@ bool spi16BitTest(void) {
// Read back the data using 8-bit transfers // Read back the data using 8-bit transfers
spiAddress = 0; spiAddress = 0;
while (spiAddress < SPI_MAX_ADDR) { while (spiAddress <= SPI_MAX_ADDR) {
// generate the golden data // generate the golden data
switch (spiPhase) { switch (spiPhase) {
case 0 : case 0 :
@ -283,7 +287,7 @@ bool spi16BitTest(void) {
// Clear the memory // Clear the memory
spiAddress = 0; spiAddress = 0;
memset(src16, 0, DMA_SIZE); memset(src16, 0, DMA_SIZE);
while (spiAddress < SPI_MAX_ADDR) { while (spiAddress <= SPI_MAX_ADDR) {
// Send the DMA transfer // Send the DMA transfer
spiMem0.zero16(spiAddress, NUM_DATA); spiMem0.zero16(spiAddress, NUM_DATA);
// wait until write is done // wait until write is done
@ -293,7 +297,7 @@ bool spi16BitTest(void) {
// Check the memory is clear // Check the memory is clear
spiAddress = 0; spiAddress = 0;
while (spiAddress < SPI_MAX_ADDR) { while (spiAddress <= SPI_MAX_ADDR) {
// Read back the DMA data // Read back the DMA data
spiMem0.read16(spiAddress, dest16, NUM_DATA); spiMem0.read16(spiAddress, dest16, NUM_DATA);
// wait until read is done // wait until read is done
@ -313,4 +317,3 @@ void loop() {
while(true) {} while(true) {}
} }

@ -54,14 +54,17 @@ bool compareBuffers16(uint16_t *a, uint16_t *b, size_t numWords)
return compareBuffers(reinterpret_cast<uint8_t *>(a), reinterpret_cast<uint8_t*>(b), sizeof(uint16_t)*numWords); return compareBuffers(reinterpret_cast<uint8_t *>(a), reinterpret_cast<uint8_t*>(b), sizeof(uint16_t)*numWords);
} }
constexpr size_t TEST_END = SPI_MAX_ADDR; size_t SPI_MAX_ADDR = 0;
void setup() { void setup() {
Serial.begin(57600); Serial.begin(57600);
while (!Serial) {} while (!Serial) { yield(); }
delay(5); delay(5);
SPI_MEM1_1M();
SPI_MAX_ADDR = BAHardwareConfig.getSpiMemMaxAddr(MemSelect::MEM1);
Serial.println("Enabling SPI, testing MEM1"); Serial.println("Enabling SPI, testing MEM1");
spiMem1.begin(); spiMem1.begin();
} }
@ -81,7 +84,7 @@ bool spi8BitTest(void) {
Serial.println("\nStarting 8-bit test Write/Read"); Serial.println("\nStarting 8-bit test Write/Read");
while (spiPhase < 4) { while (spiPhase < 4) {
spiAddress = 0; spiAddress = 0;
while (spiAddress < TEST_END) { while (spiAddress <= SPI_MAX_ADDR) {
// fill the write data buffer // fill the write data buffer
switch (spiPhase) { switch (spiPhase) {
@ -116,7 +119,7 @@ bool spi8BitTest(void) {
// Read back the data using 8-bit transfers // Read back the data using 8-bit transfers
spiAddress = 0; spiAddress = 0;
while (spiAddress < TEST_END) { while (spiAddress <= SPI_MAX_ADDR) {
// generate the golden data // generate the golden data
switch (spiPhase) { switch (spiPhase) {
case 0 : case 0 :
@ -164,7 +167,7 @@ bool spi8BitTest(void) {
// Clear the memory // Clear the memory
spiAddress = 0; spiAddress = 0;
memset(src8, 0, DMA_SIZE); memset(src8, 0, DMA_SIZE);
while (spiAddress < SPI_MAX_ADDR) { while (spiAddress <= SPI_MAX_ADDR) {
// Send the DMA transfer // Send the DMA transfer
spiMem1.zero(spiAddress, DMA_SIZE); spiMem1.zero(spiAddress, DMA_SIZE);
// wait until write is done // wait until write is done
@ -174,7 +177,7 @@ bool spi8BitTest(void) {
// Check the memory is clear // Check the memory is clear
spiAddress = 0; spiAddress = 0;
while (spiAddress < SPI_MAX_ADDR) { while (spiAddress <= SPI_MAX_ADDR) {
// Read back the DMA data // Read back the DMA data
spiMem1.read(spiAddress, dest8, DMA_SIZE); spiMem1.read(spiAddress, dest8, DMA_SIZE);
// wait until read is done // wait until read is done
@ -200,7 +203,7 @@ bool spi16BitTest(void) {
Serial.println("\nStarting 16-bit test"); Serial.println("\nStarting 16-bit test");
while (spiPhase < 4) { while (spiPhase < 4) {
spiAddress = 0; spiAddress = 0;
while (spiAddress < SPI_MAX_ADDR) { while (spiAddress <= SPI_MAX_ADDR) {
// fill the write data buffer // fill the write data buffer
switch (spiPhase) { switch (spiPhase) {
@ -235,7 +238,7 @@ bool spi16BitTest(void) {
// Read back the data using 8-bit transfers // Read back the data using 8-bit transfers
spiAddress = 0; spiAddress = 0;
while (spiAddress < SPI_MAX_ADDR) { while (spiAddress <= SPI_MAX_ADDR) {
// generate the golden data // generate the golden data
switch (spiPhase) { switch (spiPhase) {
case 0 : case 0 :
@ -282,7 +285,7 @@ bool spi16BitTest(void) {
// Clear the memory // Clear the memory
spiAddress = 0; spiAddress = 0;
memset(src16, 0, DMA_SIZE); memset(src16, 0, DMA_SIZE);
while (spiAddress < SPI_MAX_ADDR) { while (spiAddress <= SPI_MAX_ADDR) {
// Send the DMA transfer // Send the DMA transfer
spiMem1.zero16(spiAddress, NUM_DATA); spiMem1.zero16(spiAddress, NUM_DATA);
// wait until write is done // wait until write is done
@ -292,7 +295,7 @@ bool spi16BitTest(void) {
// Check the memory is clear // Check the memory is clear
spiAddress = 0; spiAddress = 0;
while (spiAddress < SPI_MAX_ADDR) { while (spiAddress <= SPI_MAX_ADDR) {
// Read back the DMA data // Read back the DMA data
spiMem1.read16(spiAddress, dest16, NUM_DATA); spiMem1.read16(spiAddress, dest16, NUM_DATA);
// wait until read is done // wait until read is done
@ -312,4 +315,3 @@ void loop() {
while(true) {} while(true) {}
} }

@ -3,8 +3,8 @@
#include "BALibrary.h" #include "BALibrary.h"
using namespace BALibrary; using namespace BALibrary;
constexpr int potCalibMin = 1; constexpr int potCalibMin = 8;
constexpr int potCalibMax = 1018; constexpr int potCalibMax = 1016;
constexpr bool potSwapDirection = true; constexpr bool potSwapDirection = true;
int pot1Handle, pot2Handle, pot3Handle, sw1Handle, sw2Handle, led1Handle, led2Handle; int pot1Handle, pot2Handle, pot3Handle, sw1Handle, sw2Handle, led1Handle, led2Handle;
bool mute = false; bool mute = false;
@ -51,6 +51,7 @@ void checkPot(unsigned id)
if (controlPtr->checkPotValue(handle, potValue)) { if (controlPtr->checkPotValue(handle, potValue)) {
// Pot has changed // Pot has changed
codecPtr->setHeadphoneVolume(potValue); codecPtr->setHeadphoneVolume(potValue);
Serial.println(String("POT") + id + String(" value: ") + potValue);
} }
} }
@ -79,5 +80,3 @@ void checkSwitch(unsigned id)
bool pressed = controlPtr->isSwitchHeld(swHandle); bool pressed = controlPtr->isSwitchHeld(swHandle);
controlPtr->setOutput(ledHandle, pressed); controlPtr->setOutput(ledHandle, pressed);
} }

@ -42,13 +42,11 @@
* *
*/ */
//#define RUN_MIDI_TEST // Uncomment this line to skip the MIDI test. #define RUN_MIDI_TEST // Uncomment this line to run the MIDI test.
//#define RUN_MEMO_TEST // Uncomment this line to skip the MEM0 test. #define RUN_MEMO_TEST // Uncomment this line to run the MEM0 test.
//#define RUN_MEM1_TEST // (Teensy 3.5/3/6 only!) Comment out or delete this line to skip the MEM1 test. //#define RUN_MEM1_TEST // (Teensy 3.5/3/6 only!) Uncomment this line to run the MEM1 test.
#include <Audio.h> #include <Audio.h>
#define TGA_PRO_EXPAND_REV2
#include "BALibrary.h" #include "BALibrary.h"
using namespace BALibrary; using namespace BALibrary;
@ -67,7 +65,7 @@ BAGpio gpio; // access to User LED
BASpiMemoryDMA spiMem0(SpiDeviceId::SPI_DEVICE0); BASpiMemoryDMA spiMem0(SpiDeviceId::SPI_DEVICE0);
#endif #endif
#if defined(RUN_MEM1_TEST) #if defined(RUN_MEM1_TEST) && !defined(__IMXRT1062__) // SPI1 not supported on T4.0
BASpiMemoryDMA spiMem1(SpiDeviceId::SPI_DEVICE1); BASpiMemoryDMA spiMem1(SpiDeviceId::SPI_DEVICE1);
#endif #endif
@ -78,13 +76,14 @@ BAPhysicalControls controls(BA_EXPAND_NUM_SW, BA_EXPAND_NUM_POT, BA_EXPAND_NUM_E
void configPhysicalControls(BAPhysicalControls &controls, BAAudioControlWM8731 &codec); void configPhysicalControls(BAPhysicalControls &controls, BAAudioControlWM8731 &codec);
void checkPot(unsigned id); void checkPot(unsigned id);
void checkSwitch(unsigned id); void checkSwitch(unsigned id);
bool spiTest(BASpiMemoryDMA *mem); // returns true if passed bool spiTest(BASpiMemory *mem); // returns true if passed
bool uartTest(); // returns true if passed bool uartTest(); // returns true if passed
unsigned loopCounter = 0; unsigned loopCounter = 0;
void setup() { void setup() {
Serial.begin(57600); Serial.begin(57600);
while (!Serial) { yield(); }
delay(500); delay(500);
// Disable the audio codec first // Disable the audio codec first
@ -101,11 +100,13 @@ void setup() {
#endif #endif
#if defined(RUN_MEMO_TEST) #if defined(RUN_MEMO_TEST)
SPI_MEM0_1M();
spiMem0.begin(); delay(10); spiMem0.begin(); delay(10);
if (spiTest(&spiMem0)) { Serial.println("SPI0 testing PASSED!");} if (spiTest(&spiMem0)) { Serial.println("SPI0 testing PASSED!");}
#endif #endif
#if defined(RUN_MEM1_TEST) #if defined(RUN_MEM1_TEST) && !defined(__IMXRT1062__)
SPI_MEM1_1M();
spiMem1.begin(); delay(10); spiMem1.begin(); delay(10);
if (spiTest(&spiMem1)) { Serial.println("SPI1 testing PASSED!");} if (spiTest(&spiMem1)) { Serial.println("SPI1 testing PASSED!");}
#endif #endif
@ -121,7 +122,7 @@ void loop() {
checkSwitch(0); checkSwitch(0);
checkSwitch(1); checkSwitch(1);
delay(10); delay(20);
loopCounter++; loopCounter++;
if ((loopCounter % 100) == 0) { if ((loopCounter % 100) == 0) {
gpio.toggleLed(); gpio.toggleLed();

@ -4,7 +4,7 @@
using namespace BALibrary; using namespace BALibrary;
constexpr unsigned MIDI_RATE = 31250; constexpr unsigned MIDI_RATE = 31250;
constexpr unsigned HIGH_RATE = 250000; constexpr unsigned HIGH_RATE = 230400;
constexpr unsigned TEST_TIME = 5; // 5 second test each constexpr unsigned TEST_TIME = 5; // 5 second test each
static unsigned baudRate = MIDI_RATE; // start with low speed static unsigned baudRate = MIDI_RATE; // start with low speed
@ -58,7 +58,7 @@ bool uartTest(void)
if (Serial1.available()) { if (Serial1.available()) {
uint8_t readData= Serial1.read(); uint8_t readData= Serial1.read();
if (readData != writeData) { if (readData != writeData) {
Serial.println(String("ERROR: readData = ") + readData + String(" writeData = ") + writeData); Serial.println(String("MIDI ERROR: readData = ") + readData + String(" writeData = ") + writeData);
errorCount++; errorCount++;
} }
@ -79,4 +79,3 @@ bool uartTest(void)
return testFailed; return testFailed;
} }

@ -12,6 +12,8 @@ constexpr int mask1 = 0xaaaa;
using namespace BALibrary; using namespace BALibrary;
size_t SPI_MAX_ADDR = 0;
int calcData(int spiAddress, int loopPhase, int maskPhase) int calcData(int spiAddress, int loopPhase, int maskPhase)
{ {
int data; int data;
@ -35,7 +37,7 @@ int calcData(int spiAddress, int loopPhase, int maskPhase)
return (data & 0xffff); return (data & 0xffff);
} }
bool spiTest(BASpiMemoryDMA *mem) bool spiTest(BASpiMemory *mem)
{ {
int spiAddress = 0; int spiAddress = 0;
int spiErrorCount = 0; int spiErrorCount = 0;
@ -45,7 +47,10 @@ bool spiTest(BASpiMemoryDMA *mem)
uint16_t memBlock[NUM_BLOCK_WORDS]; uint16_t memBlock[NUM_BLOCK_WORDS];
uint16_t goldData[NUM_BLOCK_WORDS]; uint16_t goldData[NUM_BLOCK_WORDS];
Serial.println("Starting SPI MEM Test"); SPI_MAX_ADDR = BAHardwareConfig.getSpiMemMaxAddr(0); // assume for this test both memories are the same size so use MEM0
const size_t SPI_MEM0_SIZE_BYTES = BAHardwareConfig.getSpiMemSizeBytes(0);
Serial.println(String("Starting SPI MEM Test of ") + SPI_MEM0_SIZE_BYTES + String(" bytes"));
for (int cnt = 0; cnt < NUM_TESTS; cnt++) { for (int cnt = 0; cnt < NUM_TESTS; cnt++) {
@ -122,4 +127,3 @@ bool spiTest(BASpiMemoryDMA *mem)
} }
return true; return true;
} }

@ -1,5 +1,5 @@
####################################### #######################################
# Syntax Coloring Map For ExampleLibrary # Syntax Coloring Map For BALibrary
####################################### #######################################
####################################### #######################################
@ -15,11 +15,18 @@ BAAudioEffectDelayExternal KEYWORD1
# Methods and Functions (KEYWORD2) # Methods and Functions (KEYWORD2)
####################################### #######################################
doSomething KEYWORD2 TGA_PRO_REVA KEYWORD2
TGA_PRO_REVB KEYWORD2
TGA_PRO_EXPAND_REV2 KEYWORD2
SPI_MEM0_1M KEYWORD2
SPI_MEM0_4M KEYWORD2
SPI_MEM1_1M KEYWORD2
SPI_MEM1_4M KEYWORD2
####################################### #######################################
# Instances (KEYWORD2) # Instances (KEYWORD2)
####################################### #######################################
BAHardwareConfig KEYWORD1
####################################### #######################################
# Constants (LITERAL1) # Constants (LITERAL1)

@ -123,9 +123,13 @@ protected:
private: private:
// low-level write command // low-level write command
bool write(unsigned int reg, unsigned int val); bool write(unsigned int reg, unsigned int val);
// resets the internal shadow register array // resets the internal shadow register array
void resetInternalReg(void); void resetInternalReg(void);
// Sets pullups, slew rate and drive strength
void setOutputStrength(void);
bool m_wireStarted = false; bool m_wireStarted = false;
}; };

@ -45,12 +45,12 @@ public:
/// Specifiy which external memory to use /// Specifiy which external memory to use
/// @param type specify which memory to use /// @param type specify which memory to use
BAAudioEffectDelayExternal(BALibrary::MemSelect type); BAAudioEffectDelayExternal(BALibrary::MemSelect mem);
/// Specify external memory, and how much of the memory to use /// Specify external memory, and how much of the memory to use
/// @param type specify which memory to use /// @param type specify which memory to use
/// @param delayLengthMs maximum delay length in milliseconds /// @param delayLengthMs maximum delay length in milliseconds
BAAudioEffectDelayExternal(BALibrary::MemSelect type, float delayLengthMs); BAAudioEffectDelayExternal(BALibrary::MemSelect mem, float delayLengthMs);
virtual ~BAAudioEffectDelayExternal(); virtual ~BAAudioEffectDelayExternal();
/// set the actual amount of delay on a given delay tap /// set the actual amount of delay on a given delay tap
@ -67,7 +67,10 @@ public:
static unsigned m_usingSPICount[2]; // internal use for all instances static unsigned m_usingSPICount[2]; // internal use for all instances
private: private:
void initialize(BALibrary::MemSelect mem, unsigned delayLength = 1e6); bool m_configured = false;
unsigned m_requestedDelayLength = 1e6;
BALibrary::MemSelect m_mem = BALibrary::MemSelect::MEM0;
void initialize(void);
void read(uint32_t address, uint32_t count, int16_t *data); void read(uint32_t address, uint32_t count, int16_t *data);
void write(uint32_t address, uint32_t count, const int16_t *data); void write(uint32_t address, uint32_t count, const int16_t *data);
void zero(uint32_t address, uint32_t count); void zero(uint32_t address, uint32_t count);
@ -79,7 +82,6 @@ private:
static unsigned m_allocated[2]; static unsigned m_allocated[2];
audio_block_t *m_inputQueueArray[1]; audio_block_t *m_inputQueueArray[1];
BALibrary::MemSelect m_mem;
SPIClass *m_spi = nullptr; SPIClass *m_spi = nullptr;
int m_spiChannel = 0; int m_spiChannel = 0;
int m_misoPin = 0; int m_misoPin = 0;

@ -32,19 +32,164 @@
*****************************************************************************/ *****************************************************************************/
namespace BALibrary { namespace BALibrary {
// uncomment the line that corresponds to your hardware // In your Arudino .ino file, use #defines for your TGA Pro revision and options
//#define TGA_PRO_REVA // to correctly configure your hardware
#if (!defined(TGA_PRO_REVA) && !defined(TGA_PRO_REVB)) #define TGA_PRO_REVA(x) BALibrary::BAHardwareConfig.m_tgaBoard = TgaBoard::REV_A ///< Macro for specifying REV A of the TGA Pro
#define TGA_PRO_REVA #define TGA_PRO_REVB(x) BALibrary::BAHardwareConfig.m_tgaBoard = TgaBoard::REV_B ///< Macro for specifying REV B of the TGA Pro
#endif #define TGA_PRO_EXPAND_REV2(x) BALibrary::BAHardwareConfig.m_expansionBoard = ExpansionBoard::REV_1 ///< Macro for specifying REV 1 of the Expansion Board
#define SPI_MEM0_1M(x) BALibrary::BAHardwareConfig.m_spiMem0 = SPI_MEMORY_1M ///< Macro for specifying MEM0 is 1Mbit
#define SPI_MEM0_4M(x) BALibrary::BAHardwareConfig.m_spiMem0 = SPI_MEMORY_4M ///< Macro for specifying MEM1 is 4Mbit
#define SPI_MEM1_1M(x) BALibrary::BAHardwareConfig.m_spiMem1 = SPI_MEMORY_1M ///< Macro for specifying MEM0 is 1Mbit
#define SPI_MEM1_4M(x) BALibrary::BAHardwareConfig.m_spiMem1 = SPI_MEMORY_4M ///< Macro for specifying MEM1 is 1Mbit
/******************************************************************************
* Hardware Configuration
*****************************************************************************/
/// enum to specify the TGA Board revision
enum class TgaBoard : unsigned {
REV_A = 0, ///< indicates using REV A of the TGA Pro
REV_B ///< indicates using REV B of the TGA Pro
};
#if defined(TGA_PRO_REVA) || defined(TGA_PRO_REVB) /// enum to specify the TGA Pro Expansion Board revision
enum class ExpansionBoard : unsigned {
NO_EXPANSION = 0, ///< default, indicates no expansion board is present
REV_1, ///< indicates using REV 1 of the Expansion Board
REV_2 ///< indicates using REV 2 of the Expansion Board
};
constexpr uint8_t USR_LED_ID = 16; ///< Teensy IO number for the user LED. /// enum to specify SPI memory dize
enum class SpiMemorySize : unsigned {
NO_MEMORY = 0, ///< default, indicates no SPI memory installed
MEM_1M, ///< indicates 1Mbit memory is installed
MEM_4M ///< indicates 4Mbit memory is installed
};
constexpr unsigned NUM_MEM_SLOTS = 2; ///< The TGA Pro has two SPI ports for memory
/// enum to specify MEM0 or MEM1
enum MemSelect : unsigned {
MEM0 = 0, ///< SPI RAM MEM0
MEM1 = 1 ///< SPI RAM MEM1
};
/******************************************************************************
* SPI Memory Definitions
*****************************************************************************/
/// stores Spi memory size information
struct SpiMemoryDefinition {
size_t MEM_SIZE_BYTES;
size_t DIE_BOUNDARY;
};
/// Settings for 4Mbit SPI MEM
constexpr SpiMemoryDefinition SPI_MEMORY_4M = {
.MEM_SIZE_BYTES = 524288,
.DIE_BOUNDARY = 262144
};
/// Settings for 1Mbit SPI MEM
constexpr SpiMemoryDefinition SPI_MEMORY_1M = {
.MEM_SIZE_BYTES = 131072,
.DIE_BOUNDARY = 0
};
/// Settings for No memory
constexpr SpiMemoryDefinition SPI_MEMORY_NONE = {
.MEM_SIZE_BYTES = 0,
.DIE_BOUNDARY = 0
};
/******************************************************************************
* General Purpose SPI Interfaces
*****************************************************************************/
/// enum to specify which SPI port is being used
enum class SpiDeviceId : unsigned {
SPI_DEVICE0 = 0, ///< Arduino SPI device
SPI_DEVICE1 = 1 ///< Arduino SPI1 device
};
/**************************************************************************//** /**************************************************************************//**
* GPIOs and Testpoints are accessed via enumerated class constants. * BAHardware is a global object that holds hardware configuration options for
* board revisions and ordering options. It is created automatically, and only
* one is present. For configuration, the MACROS specified at the top of
* BAHardware.h should be used.
*****************************************************************************/ *****************************************************************************/
class BAHardware {
public:
BAHardware() = default; ///< default constructor
/// sets the TGA Pro board revision
/// @param tgaBoard enum to specify board revision
void set(TgaBoard tgaBoard);
/// get the configured TGA Pro board revision
/// @returns enum for the board revision
TgaBoard getTgaBoard(void);
/// sets the Expansion board revision
/// @param expansionBoard enum to specify the expansion board revision
void set(ExpansionBoard expansionBoard);
/// get the configured Expansion Board revision
/// @returns enum for the board revision
ExpansionBoard getExpansionBoard(void);
/// sets the configured size of a SPI memory
/// @param memSelect specifies which memory device you are configuring
/// @param spiMem specifies the memory definition provide (Size, etc.)
void set(MemSelect memSelect, SpiMemoryDefinition spiMem);
/// gets the memory definition for a given memory device
/// @param mem enum to specify memory device to query
SpiMemoryDefinition getSpiMemoryDefinition(MemSelect mem);
/// get the size of the given memory in bytes, defaults to MEM0
/// @param memSelect enum specifies the memory to query
/// @returns size in bytes
size_t getSpiMemSizeBytes(MemSelect memSelect = MemSelect::MEM0);
/// get the size of the given memory in bytes, defaults to MEM0
/// @param memIndex unsigned specifies the memory to query
/// @returns size in bytes
size_t getSpiMemSizeBytes(unsigned memIndex);
/// get the maximum address in a given memory, defaults to MEM0
/// @param memSelect enum specifies the memory to query
/// @returns the last valid address location in the memory
size_t getSpiMemMaxAddr (MemSelect memSelect = MemSelect::MEM0);
/// get the maximum address in a given memory, defaults to MEM0
/// @param memIndex unsigned specifies the memory to query
/// @returns the last valid address location in the memory
size_t getSpiMemMaxAddr (unsigned memIndex);
TgaBoard m_tgaBoard = TgaBoard::REV_B; ///< stores the configured TGA Pro revision
ExpansionBoard m_expansionBoard = ExpansionBoard::NO_EXPANSION; ///< stores the configured Expansion Board revision
SpiMemoryDefinition m_spiMem0 = SPI_MEMORY_NONE; ///< stores the definition for MEM0
SpiMemoryDefinition m_spiMem1 = SPI_MEMORY_NONE; ///< stores the definition for MEM1
};
extern BAHardware BAHardwareConfig; ///< external definition of global configuration class object
/**************************************************************************//**
* Teensy 3.6/3.5 Hardware Pinout
*****************************************************************************/
#if defined(__MK66FX1M0__) || defined(__MK64FX512__) // T3.6 or T3.5
constexpr uint8_t USR_LED_ID = 16; ///< Teensy IO number for the user LED.
// SPI0 and SPI1 pinouts
constexpr uint8_t SPI0_SCK_PIN = 14;
constexpr uint8_t SPI0_CS_PIN = 15;
constexpr uint8_t SPI0_MISO_PIN = 8;
constexpr uint8_t SPI0_MOSI_PIN = 7;
#define SPI1_AVAILABLE
constexpr uint8_t SPI1_SCK_PIN = 20;
constexpr uint8_t SPI1_CS_PIN = 31;
constexpr uint8_t SPI1_MISO_PIN = 5;
constexpr uint8_t SPI1_MOSI_PIN = 21;
// GPIOs and Testpoints are accessed via enumerated class constants.
enum class GPIO : uint8_t { enum class GPIO : uint8_t {
GPIO0 = 2, GPIO0 = 2,
GPIO1 = 3, GPIO1 = 3,
@ -61,46 +206,77 @@ enum class GPIO : uint8_t {
}; };
/**************************************************************************//** /**************************************************************************//**
* Optionally installed SPI RAM * Teensy 4.0 Hardware Settings
*****************************************************************************/ *****************************************************************************/
constexpr unsigned NUM_MEM_SLOTS = 2; #elif defined(__IMXRT1062__) // T4.0
enum MemSelect : unsigned { constexpr uint8_t USR_LED_ID = 2; ///< Teensy IO number for the user LED.
MEM0 = 0, ///< SPI RAM MEM0
MEM1 = 1 ///< SPI RAM MEM1
};
/**************************************************************************//** // SPI0 pinouts
* Set the maximum address (byte-based) in the external SPI memories constexpr uint8_t SPI0_SCK_PIN = 13;
*****************************************************************************/ constexpr uint8_t SPI0_CS_PIN = 10;
constexpr size_t MEM_MAX_ADDR[NUM_MEM_SLOTS] = { 131071, 131071 }; constexpr uint8_t SPI0_MISO_PIN = 12;
constexpr uint8_t SPI0_MOSI_PIN = 11;
// GPIOs and Testpoints are accessed via enumerated class constants.
enum class GPIO : uint8_t {
GPIO0 = 3,
GPIO1 = 4,
GPIO2 = 5,
GPIO3 = 6,
/**************************************************************************//** GPIO4 = 17,
* General Purpose SPI Interfaces GPIO5 = 16,
*****************************************************************************/ GPIO6 = 15,
enum class SpiDeviceId : unsigned { GPIO7 = 14,
SPI_DEVICE0 = 0, ///< Arduino SPI device
SPI_DEVICE1 = 1 ///< Arduino SPI1 device
};
constexpr int SPI_MAX_ADDR = 131071; ///< Max address size per chip
constexpr size_t SPI_MEM0_SIZE_BYTES = 131072;
constexpr size_t SPI_MEM0_MAX_AUDIO_SAMPLES = SPI_MEM0_SIZE_BYTES/sizeof(int16_t);
constexpr size_t SPI_MEM1_SIZE_BYTES = 131072; TP1 = 9,
constexpr size_t SPI_MEM1_MAX_AUDIO_SAMPLES = SPI_MEM1_SIZE_BYTES/sizeof(int16_t); TP2 = 22
};
#define SCL_PAD_CTRL IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_00
#define SDA_PAD_CTRL IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_01
constexpr uint32_t SCL_SDA_PAD_CFG = 0xF808;
#define MCLK_PAD_CTRL IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_09
#define BCLK_PAD_CTRL IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_10
#define LRCLK_PAD_CTRL IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_11
#define DAC_PAD_CTRL IOMUXC_SW_PAD_CTL_PAD_GPIO_B1_01
constexpr uint32_t I2S_PAD_CFG = 0x0008;
/**************************************************************************//**
* DEFAULT Teensy 3.2 Hardware Settings
*****************************************************************************/
#else #else
constexpr uint8_t USR_LED_ID = 16; ///< Teensy IO number for the user LED.
// SPI0 and SPI1 pinouts
constexpr uint8_t SPI0_SCK_PIN = 14;
constexpr uint8_t SPI0_CS_PIN = 15;
constexpr uint8_t SPI0_MISO_PIN = 8;
constexpr uint8_t SPI0_MOSI_PIN = 7;
// GPIOs and Testpoints are accessed via enumerated class constants.
enum class GPIO : uint8_t {
GPIO0 = 2,
GPIO1 = 3,
GPIO2 = 4,
GPIO3 = 6,
#error "No hardware declared" GPIO4 = 12,
GPIO5 = 32,
GPIO6 = 27,
GPIO7 = 28,
TP1 = 34,
TP2 = 33
};
#endif #endif
#if defined (TGA_PRO_EXPAND_REV2)
/**************************************************************************//** /**************************************************************************//**
* Blackaddr Audio Expansion Board * Blackaddr Audio Expansion Board Pin Configuration
*****************************************************************************/ *****************************************************************************/
#if defined(__MK66FX1M0__) || defined(__MK64FX512__) // T3.6 or T3.5
// Teensy 3.6 Pinout
constexpr unsigned BA_EXPAND_NUM_POT = 3; constexpr unsigned BA_EXPAND_NUM_POT = 3;
constexpr unsigned BA_EXPAND_NUM_SW = 2; constexpr unsigned BA_EXPAND_NUM_SW = 2;
constexpr unsigned BA_EXPAND_NUM_LED = 2; constexpr unsigned BA_EXPAND_NUM_LED = 2;
@ -113,9 +289,28 @@ constexpr uint8_t BA_EXPAND_SW1_PIN = 2; // 2)PWM
constexpr uint8_t BA_EXPAND_SW2_PIN = 3; // 3_SCL2_PWM constexpr uint8_t BA_EXPAND_SW2_PIN = 3; // 3_SCL2_PWM
constexpr uint8_t BA_EXPAND_LED1_PIN = 4; // 4_SDA2_PWM constexpr uint8_t BA_EXPAND_LED1_PIN = 4; // 4_SDA2_PWM
constexpr uint8_t BA_EXPAND_LED2_PIN = 6; // 6_PWM constexpr uint8_t BA_EXPAND_LED2_PIN = 6; // 6_PWM
#elif defined(__IMXRT1062__)
// Teensy 4.0 pinout
constexpr unsigned BA_EXPAND_NUM_POT = 3;
constexpr unsigned BA_EXPAND_NUM_SW = 2;
constexpr unsigned BA_EXPAND_NUM_LED = 2;
constexpr unsigned BA_EXPAND_NUM_ENC = 0;
constexpr uint8_t BA_EXPAND_POT1_PIN = A0; // 14_A0_TX3_SPDIFOUT
constexpr uint8_t BA_EXPAND_POT2_PIN = A1; // 15_A1_RX3_SPDIFIN
constexpr uint8_t BA_EXPAND_POT3_PIN = A2; // 16_A2_RX4_SCL1
constexpr uint8_t BA_EXPAND_SW1_PIN = 3; // 3_LRCLK2
constexpr uint8_t BA_EXPAND_SW2_PIN = 4; // 4_BCLK2
constexpr uint8_t BA_EXPAND_LED1_PIN = 5; // 5_IN2
constexpr uint8_t BA_EXPAND_LED2_PIN = 6; // 6_OUT1D
#else
#warning Your processor is not yet supported in BALibrary
#endif #endif
} // namespace BALibrary } // namespace BALibrary
#endif /* __BALIBRARY_BAHARDWARE_H */ #endif /* __BALIBRARY_BAHARDWARE_H */

@ -26,6 +26,8 @@
#include <Encoder.h> #include <Encoder.h>
#include <Bounce2.h> #include <Bounce2.h>
#include "Arduino.h"
namespace BALibrary { namespace BALibrary {
constexpr bool SWAP_DIRECTION = true; ///< Use when specifying direction should be swapped constexpr bool SWAP_DIRECTION = true; ///< Use when specifying direction should be swapped
@ -132,12 +134,27 @@ public:
void adjustCalibrationThreshold(float thresholdFactor); void adjustCalibrationThreshold(float thresholdFactor);
/// Set the amount of feedback in the IIR filter used to smooth the pot readings /// Set the amount of feedback in the IIR filter used to smooth the pot readings
/// @details actual filter reponse deptnds on the rate you call getValue() /// @details actual filter response depends on the rate you call getValue()
/// @param filterValue typical values are 0.80f to 0.95f /// @param filterValue typical values are 0.80f to 0.95f
void setFeedbackFitlerValue(float fitlerValue); void setFeedbackFitlerValue(float fitlerValue);
/// Set the calibration values for the pots
/// @param min analog pot reading for min value
/// @param max analog pot reading for max value
/// @param swapDirection when true min and max are reversed. (Depends on physical pot orientation)
void setCalibrationValues(unsigned min, unsigned max, bool swapDirection); void setCalibrationValues(unsigned min, unsigned max, bool swapDirection);
/// Sets a MINIMUM sampling interval for the pot in milliseconds.
/// @details When making a call to getValue(), if the time since the last reading is
/// less than this interval, a new reading will not be taken.
/// @param intervalMs the desired minimum sampling interval in milliseconds
void setSamplingIntervalMs(unsigned intervalMs);
/// Sets the minimum change between previous reading and new reading to be considered valid.
/// @details Increasing this value will help remove noise. Default is 8.
/// @param changeThreshold new change threshold for ADC
void setChangeThreshold(float changeThreshold);
/// Call this static function before creating the object to obtain calibration data. The sequence /// Call this static function before creating the object to obtain calibration data. The sequence
/// involves prompts over the Serial port. /// involves prompts over the Serial port.
/// @details E.g. call Potentiometer::calibrate(PIN). See BAExpansionCalibrate.ino in the library examples. /// @details E.g. call Potentiometer::calibrate(PIN). See BAExpansionCalibrate.ino in the library examples.
@ -151,11 +168,16 @@ private:
unsigned m_minCalibration; ///< stores the min pot value unsigned m_minCalibration; ///< stores the min pot value
unsigned m_maxCalibration; ///< stores the max pot value unsigned m_maxCalibration; ///< stores the max pot value
unsigned m_lastValue = 0; ///< stores previous value unsigned m_lastValue = 0; ///< stores previous value
float m_feedbackFitlerValue = 0.9f; ///< feedback value for POT filter float m_feedbackFitlerValue = 0.8f; ///< feedback value for POT filter
float m_thresholdFactor = 0.05f; ///< threshold factor causes values pot to saturate faster at the limits, default is 5% float m_thresholdFactor = 0.05f; ///< threshold factor causes values pot to saturate faster at the limits, default is 5%
unsigned m_minCalibrationThresholded; ///< stores the min pot value after thresholding unsigned m_minCalibrationThresholded; ///< stores the min pot value after thresholding
unsigned m_maxCalibrationThresholded; ///< stores the max pot value after thresholding unsigned m_maxCalibrationThresholded; ///< stores the max pot value after thresholding
unsigned m_rangeThresholded; ///< stores the range of max - min after thresholding unsigned m_rangeThresholded; ///< stores the range of max - min after thresholding
unsigned m_changeThreshold = 8; ///< a new reading must change by this amount to be valid
unsigned m_lastValidValue = 0; ///< stores previous value
unsigned m_samplingIntervalMs = 20; ///< the sampling interval in milliseconds
elapsedMillis m_timerMs; ///< special Teensy variable that tracks time
}; };
/// Convenience class for rotary (quadrature) encoders. Uses Arduino Encoder under the hood. /// Convenience class for rotary (quadrature) encoders. Uses Arduino Encoder under the hood.
@ -306,8 +328,6 @@ private:
std::vector<DigitalOutput> m_outputs; ///< a vector of all added outputs std::vector<DigitalOutput> m_outputs; ///< a vector of all added outputs
}; };
} // BALibrary } // BALibrary
#endif /* __BAPHYSICALCONTROLS_H */ #endif /* __BAPHYSICALCONTROLS_H */

@ -23,6 +23,7 @@
#ifndef __BALIBRARY_BASPIMEMORY_H #ifndef __BALIBRARY_BASPIMEMORY_H
#define __BALIBRARY_BASPIMEMORY_H #define __BALIBRARY_BASPIMEMORY_H
#include <cstdint>
#include <SPI.h> #include <SPI.h>
#include <DmaSpi.h> #include <DmaSpi.h>
@ -33,7 +34,7 @@ namespace BALibrary {
/**************************************************************************//** /**************************************************************************//**
* This wrapper class uses the Arduino SPI (Wire) library to access the SPI ram. * This wrapper class uses the Arduino SPI (Wire) library to access the SPI ram.
* @details The purpose of this class is primilary for functional testing since * @details The purpose of this class is primarily for functional testing since
* it currently support single-word access. High performance access should be * it currently support single-word access. High performance access should be
* done using DMA techniques in the Teensy library. * done using DMA techniques in the Teensy library.
*****************************************************************************/ *****************************************************************************/
@ -43,7 +44,7 @@ public:
/// Create an object to control either MEM0 (via SPI1) or MEM1 (via SPI2). /// Create an object to control either MEM0 (via SPI1) or MEM1 (via SPI2).
/// @details default is 20 Mhz /// @details default is 20 Mhz
/// @param memDeviceId specify which MEM to control with SpiDeviceId. /// @param memDeviceId specify which MEM to control with SpiDeviceId.
BASpiMemory(SpiDeviceId memDeviceId); BASpiMemory(SpiDeviceId memDeviceId = SpiDeviceId::SPI_DEVICE0);
/// Create an object to control either MEM0 (via SPI1) or MEM1 (via SPI2) /// Create an object to control either MEM0 (via SPI1) or MEM1 (via SPI2)
/// @param memDeviceId specify which MEM to control with SpiDeviceId. /// @param memDeviceId specify which MEM to control with SpiDeviceId.
/// @param speedHz specify the desired speed in Hz. /// @param speedHz specify the desired speed in Hz.
@ -111,16 +112,39 @@ public:
/// @returns true if initialized, false if not yet initialized /// @returns true if initialized, false if not yet initialized
bool isStarted() const { return m_started; } bool isStarted() const { return m_started; }
/// Dummy function for non-DMA writes
virtual bool isWriteBusy() const { return false; }
/// Dummy function for non-DMA reads
virtual bool isReadBusy() const { return false; }
protected: protected:
SPIClass *m_spi = nullptr; SPIClass *m_spi = nullptr;
SpiDeviceId m_memDeviceId; // the MEM device being control with this instance SpiDeviceId m_memDeviceId; // the MEM device being control with this instance
uint8_t m_csPin; // the IO pin number for the CS on the controlled SPI device uint8_t m_csPin; // the IO pin number for the CS on the controlled SPI device
SPISettings m_settings; // the Wire settings for this SPI port SPISettings m_settings; // the Wire settings for this SPI port
bool m_started = false; bool m_started = false;
size_t m_dieBoundary; // the address at which a SPI memory die rollsover
size_t m_bytesToXfer(size_t address, size_t numBytes);
void m_rawWrite (size_t address, uint8_t *src, size_t numBytes); // raw function for writing bytes
void m_rawZero (size_t address, size_t numBytes); // raw function for zeroing memory
void m_rawRead (size_t address, uint8_t *dest, size_t numBytes); // raw function for reading bytes
void m_rawWrite16(size_t address, uint16_t *src, size_t numBytes); // raw function for writing words
void m_rawZero16 (size_t address, size_t numBytes); // raw function for zeroing memory words
void m_rawRead16 (size_t address, uint16_t *dest, size_t numBytes); // raw function for reading words
}; };
#if defined (__IMXRT1062__)
//#if 0
using BASpiMemoryDMA = BASpiMemory;
#else
/**************************************************************************//**
* This wrapper class uses the Arduino SPI (Wire) library to access the SPI ram
* via DMA.
*****************************************************************************/
class BASpiMemoryDMA : public BASpiMemory { class BASpiMemoryDMA : public BASpiMemory {
public: public:
BASpiMemoryDMA() = delete; BASpiMemoryDMA() = delete;
@ -181,11 +205,11 @@ public:
/// Check if a DMA write is in progress /// Check if a DMA write is in progress
/// @returns true if a write DMA is in progress, else false /// @returns true if a write DMA is in progress, else false
bool isWriteBusy() const; bool isWriteBusy() const override;
/// Check if a DMA read is in progress /// Check if a DMA read is in progress
/// @returns true if a read DMA is in progress, else false /// @returns true if a read DMA is in progress, else false
bool isReadBusy() const; bool isReadBusy() const override;
/// Readout the 8-bit contents of the DMA storage buffer to the specified destination /// Readout the 8-bit contents of the DMA storage buffer to the specified destination
/// @param dest pointer to the destination /// @param dest pointer to the destination
@ -214,6 +238,7 @@ private:
void m_setSpiCmdAddr(int command, size_t address, uint8_t *dest); void m_setSpiCmdAddr(int command, size_t address, uint8_t *dest);
}; };
#endif // BASpiMemoryDMA declaration
} /* namespace BALibrary */ } /* namespace BALibrary */

@ -12,6 +12,11 @@
#include "DMAChannel.h" #include "DMAChannel.h"
#include <core_pins.h> #include <core_pins.h>
//#include <core_cm7.h>
#include <arm_math.h>
//#define DEBUG_DMASPI 1
/** \brief Specifies the desired CS suppression /** \brief Specifies the desired CS suppression
**/ **/
@ -152,7 +157,6 @@ class ActiveLowChipSelect1 : public AbstractChipSelect
#endif #endif
//#define DEBUG_DMASPI 1
#if defined(DEBUG_DMASPI) #if defined(DEBUG_DMASPI)
#define DMASPI_PRINT(x) do {Serial.printf x ; Serial.flush();} while (0); #define DMASPI_PRINT(x) do {Serial.printf x ; Serial.flush();} while (0);
@ -488,8 +492,10 @@ class AbstractDmaSpi
static void post_finishCurrentTransfer() {DMASPI_INSTANCE::post_finishCurrentTransfer_impl();} static void post_finishCurrentTransfer() {DMASPI_INSTANCE::post_finishCurrentTransfer_impl();}
// finishCurrentTransfer is called from rxISR_()
static void finishCurrentTransfer() static void finishCurrentTransfer()
{ {
DMASPI_PRINT((" inside finishCurrentTransfer()\n"));
if (m_pCurrentTransfer->m_pSelect != nullptr) if (m_pCurrentTransfer->m_pSelect != nullptr)
{ {
m_pCurrentTransfer->m_pSelect->deselect(m_pCurrentTransfer->m_transferType); m_pCurrentTransfer->m_pSelect->deselect(m_pCurrentTransfer->m_transferType);
@ -581,12 +587,12 @@ class AbstractDmaSpi
{ {
if (m_pNextTransfer == nullptr) if (m_pNextTransfer == nullptr)
{ {
DMASPI_PRINT(("DmaSpi::beginNextTransfer: no pending transfer\n")); DMASPI_PRINT(("DmaSpi::beginPendingTransfer: no pending transfer\n"));
return; return;
} }
m_pCurrentTransfer = m_pNextTransfer; m_pCurrentTransfer = m_pNextTransfer;
DMASPI_PRINT(("DmaSpi::beginNextTransfer: starting transfer @ %p\n", m_pCurrentTransfer)); DMASPI_PRINT(("DmaSpi::beginPendingTransfer: starting transfer @ %p\n", m_pCurrentTransfer));
m_pCurrentTransfer->m_state = Transfer::State::inProgress; m_pCurrentTransfer->m_state = Transfer::State::inProgress;
m_pNextTransfer = m_pNextTransfer->m_pNext; m_pNextTransfer = m_pNextTransfer->m_pNext;
if (m_pNextTransfer == nullptr) if (m_pNextTransfer == nullptr)
@ -600,6 +606,7 @@ class AbstractDmaSpi
{ {
// real data sink // real data sink
DMASPI_PRINT((" real sink\n")); DMASPI_PRINT((" real sink\n"));
arm_dcache_flush_delete((void *)m_pCurrentTransfer->m_pDest, m_pCurrentTransfer->m_transferCount);
rxChannel_()->destinationBuffer(m_pCurrentTransfer->m_pDest, rxChannel_()->destinationBuffer(m_pCurrentTransfer->m_pDest,
m_pCurrentTransfer->m_transferCount); m_pCurrentTransfer->m_transferCount);
} }
@ -616,6 +623,7 @@ class AbstractDmaSpi
{ {
// real data source // real data source
DMASPI_PRINT((" real source\n")); DMASPI_PRINT((" real source\n"));
arm_dcache_flush_delete((void *)m_pCurrentTransfer->m_pSource, m_pCurrentTransfer->m_transferCount);
txChannel_()->sourceBuffer(m_pCurrentTransfer->m_pSource, txChannel_()->sourceBuffer(m_pCurrentTransfer->m_pSource,
m_pCurrentTransfer->m_transferCount); m_pCurrentTransfer->m_transferCount);
} }
@ -627,6 +635,7 @@ class AbstractDmaSpi
txChannel_()->transferCount(m_pCurrentTransfer->m_transferCount); txChannel_()->transferCount(m_pCurrentTransfer->m_transferCount);
} }
DMASPI_PRINT(("calling pre_cs() "));
pre_cs(); pre_cs();
// Select Chip // Select Chip
@ -639,6 +648,7 @@ class AbstractDmaSpi
m_Spi.beginTransaction(SPISettings()); m_Spi.beginTransaction(SPISettings());
} }
DMASPI_PRINT(("calling post_cs() "));
post_cs(); post_cs();
} }
@ -669,7 +679,17 @@ typename AbstractDmaSpi<DMASPI_INSTANCE, SPICLASS, m_Spi>::Transfer* volatile Ab
template<typename DMASPI_INSTANCE, typename SPICLASS, SPICLASS& m_Spi> template<typename DMASPI_INSTANCE, typename SPICLASS, SPICLASS& m_Spi>
volatile uint8_t AbstractDmaSpi<DMASPI_INSTANCE, SPICLASS, m_Spi>::m_devNull = 0; volatile uint8_t AbstractDmaSpi<DMASPI_INSTANCE, SPICLASS, m_Spi>::m_devNull = 0;
#if defined(KINETISK) //void dump_dma(DMAChannel *dmabc)
//{
// Serial.printf("%x %x:", (uint32_t)dmabc, (uint32_t)dmabc->TCD);
//
// Serial.printf("SA:%x SO:%d AT:%x NB:%x SL:%d DA:%x DO: %d CI:%x DL:%x CS:%x BI:%x\n", (uint32_t)dmabc->TCD->SADDR,
// dmabc->TCD->SOFF, dmabc->TCD->ATTR, dmabc->TCD->NBYTES, dmabc->TCD->SLAST, (uint32_t)dmabc->TCD->DADDR,
// dmabc->TCD->DOFF, dmabc->TCD->CITER, dmabc->TCD->DLASTSGA, dmabc->TCD->CSR, dmabc->TCD->BITER);
// Serial.flush();
//}
#if defined(__IMXRT1062__) // T4.0
class DmaSpi0 : public AbstractDmaSpi<DmaSpi0, SPIClass, SPI> class DmaSpi0 : public AbstractDmaSpi<DmaSpi0, SPIClass, SPI>
{ {
@ -677,24 +697,136 @@ public:
static void begin_setup_txChannel_impl() static void begin_setup_txChannel_impl()
{ {
txChannel_()->disable(); txChannel_()->disable();
txChannel_()->destination((volatile uint8_t&)SPI0_PUSHR); txChannel_()->destination((volatile uint8_t&)IMXRT_LPSPI4_S.TDR);
txChannel_()->disableOnCompletion(); txChannel_()->disableOnCompletion();
txChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_TX); txChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_LPSPI4_TX);
//txChannel_()->triggerAtTransfersOf(*rxChannel_);
} }
static void begin_setup_rxChannel_impl() static void begin_setup_rxChannel_impl()
{ {
rxChannel_()->disable(); rxChannel_()->disable();
rxChannel_()->source((volatile uint8_t&)SPI0_POPR); rxChannel_()->source((volatile uint8_t&)IMXRT_LPSPI4_S.RDR); // POPR is the receive fifo register for the SPI
rxChannel_()->disableOnCompletion(); rxChannel_()->disableOnCompletion();
rxChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_RX); rxChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_LPSPI4_RX); // The DMA RX id for MT66 is 14
rxChannel_()->attachInterrupt(rxIsr_);
rxChannel_()->interruptAtCompletion();
}
static void pre_cs_impl()
{
if (LPSPI4_SR & 0x1800) {
DMASPI_PRINT(("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!ERROR SR reg is %08X\n", LPSPI4_SR));
}
DMASPI_PRINT(("********************************************CHECK SR reg is %08X\n", LPSPI4_SR));
IMXRT_LPSPI4_S.TCR = (IMXRT_LPSPI4_S.TCR & ~(LPSPI_TCR_FRAMESZ(31))) | LPSPI_TCR_FRAMESZ(7);
IMXRT_LPSPI4_S.FCR = 0;
//IMXRT_LPSPI4_S.CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF;
IMXRT_LPSPI4_S.CR = LPSPI_CR_MEN; // I had to add the enable otherwise it wont' work
// Lets try to output the first byte to make sure that we are in 8 bit mode...
IMXRT_LPSPI4_S.DER = LPSPI_DER_TDDE | LPSPI_DER_RDDE; //enable DMA on both TX and RX
IMXRT_LPSPI4_S.SR = 0x3f00; // clear out all of the other status...
// if (m_pCurrentTransfer->m_pSource) {
// arm_dcache_flush((void *)m_pCurrentTransfer->m_pSource, m_pCurrentTransfer->m_transferCount);
// }
}
// static void pre_cs_impl()
// {
//
// //LPSPI4_PARAM = LPSPI4_PARAM;
// //LPSPI4_PARAM = 0x0404;
// //DMASPI_PRINT(("!!!!!!!!!!!!!!!!!!!!!PARAM reg is %08X\n", LPSPI4_PARAM));
// txChannel_()->TCD->ATTR_SRC = 0; //Make sure set for 8 bit mode...
// txChannel_()->TCD->SLAST = 0; // Finish with it pointing to next location
// rxChannel_()->TCD->ATTR_DST = 0; //Make sure set for 8 bit mode...
// rxChannel_()->TCD->DLASTSGA = 0;
//
// //DMASPI_PRINT(("STATUS SR reg is %08X\n", LPSPI4_SR));
// if (LPSPI4_SR & 0x1800) {
// DMASPI_PRINT(("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!ERROR SR reg is %08X\n", LPSPI4_SR));
// }
// LPSPI4_SR = 0x3f00; // clear various error and status flags
// DMASPI_PRINT(("********************************************CHECK SR reg is %08X\n", LPSPI4_SR));
//
// LPSPI4_TCR = (LPSPI4_TCR & ~(LPSPI_TCR_FRAMESZ(31))) | LPSPI_TCR_FRAMESZ(7); // Set the FRAMESZ to 7 for 8-bit frame size
// LPSPI4_FCR = 0; // set watermarks to zero, this ensures ready flag is set whenever fifo is not empty
//
// LPSPI4_CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF; //enable module and reset both FIFOs
// LPSPI4_DER = LPSPI_DER_TDDE | LPSPI_DER_RDDE; // enable DMA on both TX and RX
// }
static void post_cs_impl()
{
rxChannel_()->enable();
txChannel_()->enable();
DMASPI_PRINT(("Done post_cs_impl()\n"));
}
static void post_finishCurrentTransfer_impl()
{
IMXRT_LPSPI4_S.FCR = LPSPI_FCR_TXWATER(15); // _spi_fcr_save; // restore the FSR status...
IMXRT_LPSPI4_S.DER = 0; // DMA no longer doing TX (or RX)
IMXRT_LPSPI4_S.CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF; // actually clear both...
IMXRT_LPSPI4_S.SR = 0x3f00; // clear out all of the other status...
// if (m_pCurrentTransfer->m_pDest) {
// arm_dcache_delete((void *)m_pCurrentTransfer->m_pDest, m_pCurrentTransfer->m_transferCount);
// }
}
// static void post_finishCurrentTransfer_impl()
// {
// //LPSPI4_FCR = LPSPI_FCR_TXWATER(15); // restore FSR status
// LPSPI4_DER = 0; // DMA no longer doing TX or RX
// LPSPI4_CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF; //enable module and reset both FIFOs
// LPSPI4_SR = 0x3f00; // clear out all the other statuses
// }
private:
};
extern DmaSpi0 DMASPI0;
#elif defined(KINETISK)
class DmaSpi0 : public AbstractDmaSpi<DmaSpi0, SPIClass, SPI>
{
public:
static void begin_setup_txChannel_impl()
{
txChannel_()->disable();
txChannel_()->destination((volatile uint8_t&)SPI0_PUSHR); // PUSHR is the transmit fifo register for the SPI
txChannel_()->disableOnCompletion();
txChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_TX); // The DMA TX id for MT66 is 15
}
static void begin_setup_rxChannel_impl()
{
rxChannel_()->disable();
rxChannel_()->source((volatile uint8_t&)SPI0_POPR); // POPR is the receive fifo register for the SPI
rxChannel_()->disableOnCompletion();
rxChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_RX); // The DMA RX id for MT66 is 14
rxChannel_()->attachInterrupt(rxIsr_); rxChannel_()->attachInterrupt(rxIsr_);
rxChannel_()->interruptAtCompletion(); rxChannel_()->interruptAtCompletion();
} }
static void pre_cs_impl() static void pre_cs_impl()
{ {
SPI0_SR = 0xFF0F0000; SPI0_SR = 0xFF0F0000; // Clear various flags including Transfer complete, TXRX Status, End of Queue, Transmit FIFO underflow, Transmit FIFO Fill, Rx FIFO overflow, Rx fifo drain
// Request Select Enable Register
// RFDF_RE Rx fifo drain request enable, enables the RFDF flag in SPI0_SR
// RFDF_DIRS Rx fifo drain selects DMA request instead of interrupt request
// TFFF_RE Transmit Fifo fill request enable
// TFFF_DIRS Transmit fifo fill selct DMA instead of interrupt
SPI0_RSER = SPI_RSER_RFDF_RE | SPI_RSER_RFDF_DIRS | SPI_RSER_TFFF_RE | SPI_RSER_TFFF_DIRS; SPI0_RSER = SPI_RSER_RFDF_RE | SPI_RSER_RFDF_DIRS | SPI_RSER_TFFF_RE | SPI_RSER_TFFF_DIRS;
} }
@ -706,8 +838,8 @@ public:
static void post_finishCurrentTransfer_impl() static void post_finishCurrentTransfer_impl()
{ {
SPI0_RSER = 0; SPI0_RSER = 0; //DSPI DMA/Interrupt Request Select and Enable Register
SPI0_SR = 0xFF0F0000; SPI0_SR = 0xFF0F0000; // DSPI status register clear flags, same as above
} }
private: private:
@ -715,6 +847,7 @@ private:
extern DmaSpi0 DMASPI0; extern DmaSpi0 DMASPI0;
#if defined(__MK66FX1M0__) #if defined(__MK66FX1M0__)
class DmaSpi1 : public AbstractDmaSpi<DmaSpi1, SPIClass, SPI1> class DmaSpi1 : public AbstractDmaSpi<DmaSpi1, SPIClass, SPI1>

@ -203,6 +203,7 @@ public:
private: private:
static bool m_configured; ///< there should only be one instance of ExternalSramManager in the whole project static bool m_configured; ///< there should only be one instance of ExternalSramManager in the whole project
static MemConfig m_memConfig[BALibrary::NUM_MEM_SLOTS]; ///< store the configuration information for each external memory static MemConfig m_memConfig[BALibrary::NUM_MEM_SLOTS]; ///< store the configuration information for each external memory
void m_configure(void); ///< configure the memory manager
}; };

@ -203,7 +203,7 @@ bool AudioDelay::interpolateDelay(int16_t *extendedSourceBuffer, int16_t *destBu
} }
/// @todo optimize this later /// @todo optimize this later
for (int i=0; i<numSamples; i++) { for (unsigned i=0; i<numSamples; i++) {
destBuffer[i] = ((frac1*extendedSourceBuffer[i]) >> 16) + ((frac2*extendedSourceBuffer[i+1]) >> 16); destBuffer[i] = ((frac1*extendedSourceBuffer[i]) >> 16) + ((frac2*extendedSourceBuffer[i+1]) >> 16);
} }
return true; return true;

@ -0,0 +1,99 @@
/*
* ParameterAutomation.cpp
*
* Created on: October 23, 2019
* Author: slascos
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "BAHardware.h"
namespace BALibrary {
BAHardware BAHardwareConfig; // create the global configuration struct
void BAHardware::set(TgaBoard tgaBoard)
{
m_tgaBoard = tgaBoard;
}
TgaBoard BAHardware::getTgaBoard(void)
{
return m_tgaBoard;
}
void BAHardware::set(ExpansionBoard expansionBoard)
{
m_expansionBoard = expansionBoard;
}
ExpansionBoard BAHardware::getExpansionBoard(void)
{
return m_expansionBoard;
}
void BAHardware::set(MemSelect memSelect, SpiMemoryDefinition spiMem)
{
switch(memSelect) {
case MemSelect::MEM0 : m_spiMem0 = spiMem; break;
case MemSelect::MEM1 : m_spiMem1 = spiMem; break;
default :
break;
}
}
SpiMemoryDefinition BAHardware::getSpiMemoryDefinition(MemSelect memSelect)
{
switch(memSelect) {
case MemSelect::MEM0 : return m_spiMem0; break;
case MemSelect::MEM1 : return m_spiMem1; break;
default :
return m_spiMem0;
}
}
size_t BAHardware::getSpiMemSizeBytes(unsigned memIndex)
{
size_t sizeBytes = 0;
switch(memIndex) {
case 0 : sizeBytes = m_spiMem0.MEM_SIZE_BYTES; break;
case 1 : sizeBytes = m_spiMem1.MEM_SIZE_BYTES; break;
default : break;
}
return sizeBytes;
}
size_t BAHardware::getSpiMemSizeBytes(MemSelect memSelect)
{
size_t sizeBytes = 0;
unsigned memIndex = static_cast<unsigned>(memSelect);
switch(memIndex) {
case 0 : sizeBytes = m_spiMem0.MEM_SIZE_BYTES; break;
case 1 : sizeBytes = m_spiMem1.MEM_SIZE_BYTES; break;
default : break;
}
return sizeBytes;
}
size_t BAHardware::getSpiMemMaxAddr(unsigned memIndex)
{
return getSpiMemSizeBytes(memIndex)-1;
}
size_t BAHardware::getSpiMemMaxAddr(MemSelect memSelect)
{
return getSpiMemSizeBytes(memSelect)-1;
}
}

@ -34,21 +34,9 @@ MemConfig ExternalSramManager::m_memConfig[BALibrary::NUM_MEM_SLOTS];
ExternalSramManager::ExternalSramManager(unsigned numMemories) ExternalSramManager::ExternalSramManager(unsigned numMemories)
{ {
// Initialize the static memory configuration structs
if (!m_configured) {
for (unsigned i=0; i < NUM_MEM_SLOTS; i++) {
m_memConfig[i].size = MEM_MAX_ADDR[i]+1;
m_memConfig[i].totalAvailable = MEM_MAX_ADDR[i]+1;
m_memConfig[i].nextAvailable = 0;
m_memConfig[i].m_spi = nullptr;
}
m_configured = true;
}
} }
ExternalSramManager::ExternalSramManager() ExternalSramManager::ExternalSramManager()
: ExternalSramManager(1)
{ {
} }
@ -62,11 +50,13 @@ ExternalSramManager::~ExternalSramManager()
size_t ExternalSramManager::availableMemory(BALibrary::MemSelect mem) size_t ExternalSramManager::availableMemory(BALibrary::MemSelect mem)
{ {
if (!m_configured) { m_configure(); }
return m_memConfig[mem].totalAvailable; return m_memConfig[mem].totalAvailable;
} }
bool ExternalSramManager::requestMemory(ExtMemSlot *slot, float delayMilliseconds, BALibrary::MemSelect mem, bool useDma) bool ExternalSramManager::requestMemory(ExtMemSlot *slot, float delayMilliseconds, BALibrary::MemSelect mem, bool useDma)
{ {
if (!m_configured) { m_configure(); }
// convert the time to numer of samples // convert the time to numer of samples
size_t delayLengthInt = (size_t)((delayMilliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f); size_t delayLengthInt = (size_t)((delayMilliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f);
return requestMemory(slot, delayLengthInt * sizeof(int16_t), mem, useDma); return requestMemory(slot, delayLengthInt * sizeof(int16_t), mem, useDma);
@ -75,6 +65,8 @@ bool ExternalSramManager::requestMemory(ExtMemSlot *slot, float delayMillisecond
bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BALibrary::MemSelect mem, bool useDma) bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BALibrary::MemSelect mem, bool useDma)
{ {
if (!m_configured) { m_configure(); }
if (m_memConfig[mem].totalAvailable >= sizeBytes) { if (m_memConfig[mem].totalAvailable >= sizeBytes) {
Serial.println(String("Configuring a slot for mem ") + mem); Serial.println(String("Configuring a slot for mem ") + mem);
// there is enough available memory for this request // there is enough available memory for this request
@ -118,5 +110,20 @@ bool ExternalSramManager::requestMemory(ExtMemSlot *slot, size_t sizeBytes, BALi
} }
} }
void ExternalSramManager::m_configure(void)
{
// Initialize the static memory configuration structs
if (!m_configured) {
for (unsigned i=0; i < NUM_MEM_SLOTS; i++) {
m_memConfig[i].size = BAHardwareConfig.getSpiMemSizeBytes(i);
m_memConfig[i].totalAvailable = BAHardwareConfig.getSpiMemSizeBytes(i);
m_memConfig[i].nextAvailable = 0;
m_memConfig[i].m_spi = nullptr;
}
m_configured = true;
}
}
} }

@ -17,7 +17,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "BAHardware.h"
#include "BAAudioEffectDelayExternal.h" #include "BAAudioEffectDelayExternal.h"
using namespace BALibrary; using namespace BALibrary;
@ -26,36 +26,26 @@ namespace BAEffects {
#define SPISETTING SPISettings(20000000, MSBFIRST, SPI_MODE0) #define SPISETTING SPISettings(20000000, MSBFIRST, SPI_MODE0)
struct MemSpiConfig {
unsigned mosiPin;
unsigned misoPin;
unsigned sckPin;
unsigned csPin;
unsigned memSize;
};
constexpr MemSpiConfig Mem0Config = {7, 8, 14, 15, 65536 };
constexpr MemSpiConfig Mem1Config = {21, 5, 20, 31, 65536 };
unsigned BAAudioEffectDelayExternal::m_usingSPICount[2] = {0,0}; unsigned BAAudioEffectDelayExternal::m_usingSPICount[2] = {0,0};
BAAudioEffectDelayExternal::BAAudioEffectDelayExternal() BAAudioEffectDelayExternal::BAAudioEffectDelayExternal()
: AudioStream(1, m_inputQueueArray) : AudioStream(1, m_inputQueueArray)
{ {
initialize(MemSelect::MEM0); m_mem = MemSelect::MEM0;
} }
BAAudioEffectDelayExternal::BAAudioEffectDelayExternal(MemSelect mem) BAAudioEffectDelayExternal::BAAudioEffectDelayExternal(MemSelect mem)
: AudioStream(1, m_inputQueueArray) : AudioStream(1, m_inputQueueArray)
{ {
initialize(mem); m_mem = mem;
} }
BAAudioEffectDelayExternal::BAAudioEffectDelayExternal(BALibrary::MemSelect type, float delayLengthMs) BAAudioEffectDelayExternal::BAAudioEffectDelayExternal(BALibrary::MemSelect mem, float delayLengthMs)
: AudioStream(1, m_inputQueueArray) : AudioStream(1, m_inputQueueArray)
{ {
unsigned delayLengthInt = (delayLengthMs*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f; unsigned delayLengthInt = (delayLengthMs*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f;
initialize(type, delayLengthInt); m_mem = mem;
m_requestedDelayLength = delayLengthInt;
} }
BAAudioEffectDelayExternal::~BAAudioEffectDelayExternal() BAAudioEffectDelayExternal::~BAAudioEffectDelayExternal()
@ -65,6 +55,8 @@ BAAudioEffectDelayExternal::~BAAudioEffectDelayExternal()
void BAAudioEffectDelayExternal::delay(uint8_t channel, float milliseconds) { void BAAudioEffectDelayExternal::delay(uint8_t channel, float milliseconds) {
if (!m_configured) { initialize(); }
if (channel >= 8) return; if (channel >= 8) return;
if (milliseconds < 0.0) milliseconds = 0.0; if (milliseconds < 0.0) milliseconds = 0.0;
uint32_t n = (milliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f; uint32_t n = (milliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f;
@ -78,6 +70,9 @@ void BAAudioEffectDelayExternal::delay(uint8_t channel, float milliseconds) {
} }
void BAAudioEffectDelayExternal::disable(uint8_t channel) { void BAAudioEffectDelayExternal::disable(uint8_t channel) {
if (!m_configured) { initialize(); }
if (channel >= 8) return; if (channel >= 8) return;
uint8_t mask = m_activeMask & ~(1<<channel); uint8_t mask = m_activeMask & ~(1<<channel);
m_activeMask = mask; m_activeMask = mask;
@ -86,12 +81,21 @@ void BAAudioEffectDelayExternal::disable(uint8_t channel) {
void BAAudioEffectDelayExternal::update(void) void BAAudioEffectDelayExternal::update(void)
{ {
audio_block_t *block; audio_block_t *block;
uint32_t n, channel, read_offset; uint32_t n, channel, read_offset;
// grab incoming data and put it into the memory // grab incoming data and put it into the memory
block = receiveReadOnly(); block = receiveReadOnly();
if (!m_configured) {
if (block) {
transmit(block);
release(block);
return;
} else { return; }
}
if (block) { if (block) {
if (m_headOffset + AUDIO_BLOCK_SAMPLES <= m_memoryLength) { if (m_headOffset + AUDIO_BLOCK_SAMPLES <= m_memoryLength) {
// a single write is enough // a single write is enough
@ -146,25 +150,25 @@ void BAAudioEffectDelayExternal::update(void)
unsigned BAAudioEffectDelayExternal::m_allocated[2] = {0, 0}; unsigned BAAudioEffectDelayExternal::m_allocated[2] = {0, 0};
void BAAudioEffectDelayExternal::initialize(MemSelect mem, unsigned delayLength) void BAAudioEffectDelayExternal::initialize(void)
{ {
unsigned samples = 0; unsigned samples = 0;
unsigned memsize, avail; unsigned memsize = 0, avail = 0;
m_activeMask = 0; m_activeMask = 0;
m_headOffset = 0; m_headOffset = 0;
m_mem = mem; //m_mem = mem;
switch (mem) { switch (m_mem) {
case MemSelect::MEM0 : case MemSelect::MEM0 :
{ {
memsize = Mem0Config.memSize; memsize = BAHardwareConfig.getSpiMemSizeBytes(m_mem) / sizeof(int16_t);
m_spi = &SPI; m_spi = &SPI;
m_spiChannel = 0; m_spiChannel = 0;
m_misoPin = Mem0Config.misoPin; m_misoPin = SPI0_MISO_PIN;
m_mosiPin = Mem0Config.mosiPin; m_mosiPin = SPI0_MOSI_PIN;
m_sckPin = Mem0Config.sckPin; m_sckPin = SPI0_SCK_PIN;
m_csPin = Mem0Config.csPin; m_csPin = SPI0_CS_PIN;
m_spi->setMOSI(m_mosiPin); m_spi->setMOSI(m_mosiPin);
m_spi->setMISO(m_misoPin); m_spi->setMISO(m_misoPin);
@ -175,13 +179,13 @@ void BAAudioEffectDelayExternal::initialize(MemSelect mem, unsigned delayLength)
case MemSelect::MEM1 : case MemSelect::MEM1 :
{ {
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) #if defined(__MK64FX512__) || defined(__MK66FX1M0__)
memsize = Mem1Config.memSize; memsize = BAHardwareConfig.getSpiMemSizeBytes(m_mem) / sizeof(int16_t);
m_spi = &SPI1; m_spi = &SPI1;
m_spiChannel = 1; m_spiChannel = 1;
m_misoPin = Mem1Config.misoPin; m_misoPin = SPI1_MISO_PIN;
m_mosiPin = Mem1Config.mosiPin; m_mosiPin = SPI1_MOSI_PIN;
m_sckPin = Mem1Config.sckPin; m_sckPin = SPI1_SCK_PIN;
m_csPin = Mem1Config.csPin; m_csPin = SPI1_CS_PIN;
m_spi->setMOSI(m_mosiPin); m_spi->setMOSI(m_mosiPin);
m_spi->setMISO(m_misoPin); m_spi->setMISO(m_misoPin);
@ -196,14 +200,15 @@ void BAAudioEffectDelayExternal::initialize(MemSelect mem, unsigned delayLength)
pinMode(m_csPin, OUTPUT); pinMode(m_csPin, OUTPUT);
digitalWriteFast(m_csPin, HIGH); digitalWriteFast(m_csPin, HIGH);
avail = memsize - m_allocated[mem]; avail = memsize - m_allocated[m_mem];
if (delayLength > avail) samples = avail; if (m_requestedDelayLength > avail) samples = avail;
m_memoryStart = m_allocated[mem]; m_memoryStart = m_allocated[m_mem];
m_allocated[mem] += samples; m_allocated[m_mem] += samples;
m_memoryLength = samples; m_memoryLength = samples;
zero(0, m_memoryLength); zero(0, m_memoryLength);
m_configured = true;
} }

@ -19,6 +19,7 @@
*/ */
#include <Wire.h> #include <Wire.h>
#include "BAHardware.h"
#include "BAAudioControlWM8731.h" #include "BAAudioControlWM8731.h"
namespace BALibrary { namespace BALibrary {
@ -132,9 +133,12 @@ BAAudioControlWM8731::~BAAudioControlWM8731()
// Powerdown and disable the codec // Powerdown and disable the codec
void BAAudioControlWM8731::disable(void) void BAAudioControlWM8731::disable(void)
{ {
//Serial.println("Disabling codec"); //Serial.println("Disabling codec");
if (m_wireStarted == false) { Wire.begin(); m_wireStarted = true; } if (m_wireStarted == false) {
Wire.begin();
m_wireStarted = true;
}
setOutputStrength();
// set OUTPD to '1' (powerdown), which is bit 4 // set OUTPD to '1' (powerdown), which is bit 4
regArray[WM8731_REG_POWERDOWN] |= 0x10; regArray[WM8731_REG_POWERDOWN] |= 0x10;
@ -155,9 +159,13 @@ void BAAudioControlWM8731::enable(void)
disable(); // disable first in case it was already powered up disable(); // disable first in case it was already powered up
//Serial.println("Enabling codec"); //Serial.println("Enabling codec");
if (m_wireStarted == false) { Wire.begin(); m_wireStarted = true; } if (m_wireStarted == false) {
// Sequence from WAN0111.pdf Wire.begin();
m_wireStarted = true;
}
setOutputStrength();
// Sequence from WAN0111.pdf
// Begin configuring the codec // Begin configuring the codec
resetCodec(); resetCodec();
delay(100); // wait for reset delay(100); // wait for reset
@ -199,9 +207,6 @@ void BAAudioControlWM8731::enable(void)
regArray[WM8731_REG_POWERDOWN] = 0x02; regArray[WM8731_REG_POWERDOWN] = 0x02;
delay(500); // wait for output to power up delay(500); // wait for output to power up
//Serial.println("Done codec config");
delay(100); // wait for mute ramp delay(100); // wait for mute ramp
} }
@ -368,9 +373,9 @@ bool BAAudioControlWM8731::write(unsigned int reg, unsigned int val)
Wire.beginTransmission(WM8731_I2C_ADDR); Wire.beginTransmission(WM8731_I2C_ADDR);
Wire.write((reg << 1) | ((val >> 8) & 1)); Wire.write((reg << 1) | ((val >> 8) & 1));
Wire.write(val & 0xFF); Wire.write(val & 0xFF);
if (byte error = Wire.endTransmission() ) { byte error = Wire.endTransmission();
(void)error; // supress warning about unused variable if (error) {
//Serial.println(String("Wire::Error: ") + error + String(" retrying...")); Serial.println(String("Wire::Error: ") + error + String(" retrying..."));
} else { } else {
done = true; done = true;
//Serial.println("Wire::SUCCESS!"); //Serial.println("Wire::SUCCESS!");
@ -380,4 +385,17 @@ bool BAAudioControlWM8731::write(unsigned int reg, unsigned int val)
return true; return true;
} }
void BAAudioControlWM8731::setOutputStrength(void)
{
#if defined(__IMXRT1062__)
// The T4 requires the pads be configured with correct pullups and drive strength
SCL_PAD_CTRL = SCL_SDA_PAD_CFG;
SDA_PAD_CTRL = SCL_SDA_PAD_CFG;
MCLK_PAD_CTRL = I2S_PAD_CFG;
BCLK_PAD_CTRL = I2S_PAD_CFG;
LRCLK_PAD_CTRL = I2S_PAD_CFG;
DAC_PAD_CTRL = I2S_PAD_CFG;
#endif
}
} /* namespace BALibrary */ } /* namespace BALibrary */

@ -57,7 +57,6 @@ unsigned BAPhysicalControls::addRotary(uint8_t pin1, uint8_t pin2, bool swapDire
} }
unsigned BAPhysicalControls::addSwitch(uint8_t pin, unsigned long intervalMilliseconds) { unsigned BAPhysicalControls::addSwitch(uint8_t pin, unsigned long intervalMilliseconds) {
//m_switches.emplace_back(pin, intervalMilliseconds);'
m_switches.emplace_back(); m_switches.emplace_back();
m_switches.back().attach(pin); m_switches.back().attach(pin);
m_switches.back().interval(10); m_switches.back().interval(10);
@ -240,22 +239,35 @@ void Potentiometer::setFeedbackFitlerValue(float fitlerValue)
bool Potentiometer::getValue(float &value) { bool Potentiometer::getValue(float &value) {
bool newValue = true; // Check if the minimum sampling time has elapsed
if (m_timerMs < m_samplingIntervalMs) {
return false;
}
m_timerMs = 0; // reset the sampling timer
unsigned val = analogRead(m_pin); // read the raw value unsigned val = analogRead(m_pin); // read the raw value
// constrain it within the calibration values, them map it to the desired range. // constrain it within the calibration values, them map it to the desired range.
val = constrain(val, m_minCalibration, m_maxCalibration); val = constrain(val, m_minCalibration, m_maxCalibration);
// Use an IIR filter to smooth out the noise in the pot readings // Use an IIR filter to smooth out the noise in the pot readings
unsigned valFilter = static_cast<unsigned>( (1.0f - m_feedbackFitlerValue)*val + (m_feedbackFitlerValue*m_lastValue)); unsigned valFilter = static_cast<int>( (1.0f - m_feedbackFitlerValue)*val + (m_feedbackFitlerValue*m_lastValue));
m_lastValue = valFilter;
if (valFilter == m_lastValue) { // Apply a hysteresis check
newValue = false; if (valFilter == m_lastValidValue) { // check if value hasn't changed
return false;
} }
m_lastValue = valFilter; if (abs((int)valFilter - (int)m_lastValidValue) < m_changeThreshold) {
// The value has not exceeded the change threshold. Suppress the change only if it's not
// near the limits. This is necessary to ensure the limits can be reached.
if ( (valFilter < m_maxCalibrationThresholded) && (valFilter > m_minCalibrationThresholded)) {
return false;
}
}
m_lastValidValue = m_lastValue;
// // Convert the integer reading to a float value range 0.0 to 1.0f
if (valFilter < m_minCalibrationThresholded) { value = 0.0f; } if (valFilter < m_minCalibrationThresholded) { value = 0.0f; }
else if (valFilter > m_maxCalibrationThresholded) { value = 1.0f; } else if (valFilter > m_maxCalibrationThresholded) { value = 1.0f; }
else { else {
@ -265,7 +277,8 @@ bool Potentiometer::getValue(float &value) {
if (m_swapDirection) { if (m_swapDirection) {
value = 1.0f - value; value = 1.0f - value;
} }
return newValue;
return true;
} }
int Potentiometer::getRawValue() { int Potentiometer::getRawValue() {
@ -293,6 +306,16 @@ void Potentiometer::setCalibrationValues(unsigned min, unsigned max, bool swapDi
adjustCalibrationThreshold(m_thresholdFactor); adjustCalibrationThreshold(m_thresholdFactor);
} }
void Potentiometer::setSamplingIntervalMs(unsigned intervalMs)
{
m_samplingIntervalMs = intervalMs;
}
void Potentiometer::setChangeThreshold(float changeThreshold)
{
m_changeThreshold = changeThreshold;
}
Potentiometer::Calib Potentiometer::calibrate(uint8_t pin) { Potentiometer::Calib Potentiometer::calibrate(uint8_t pin) {
Calib calib; Calib calib;

@ -17,23 +17,24 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Arduino.h" #include "Arduino.h"
#include "BASpiMemory.h" #include "BASpiMemory.h"
namespace BALibrary { namespace BALibrary {
// MEM0 Settings // MEM0 Settings
constexpr int SPI_CS_MEM0 = 15; constexpr int SPI_CS_MEM0 = SPI0_CS_PIN;
constexpr int SPI_MOSI_MEM0 = 7; constexpr int SPI_MOSI_MEM0 = SPI0_MOSI_PIN;
constexpr int SPI_MISO_MEM0 = 8; constexpr int SPI_MISO_MEM0 = SPI0_MISO_PIN;
constexpr int SPI_SCK_MEM0 = 14; constexpr int SPI_SCK_MEM0 = SPI0_SCK_PIN;
#if defined(SPI1_AVAILABLE)
// MEM1 Settings // MEM1 Settings
constexpr int SPI_CS_MEM1 = 31; constexpr int SPI_CS_MEM1 = SPI1_CS_PIN;
constexpr int SPI_MOSI_MEM1 = 21; constexpr int SPI_MOSI_MEM1 = SPI1_MOSI_PIN;
constexpr int SPI_MISO_MEM1 = 5; constexpr int SPI_MISO_MEM1 = SPI1_MISO_PIN;
constexpr int SPI_SCK_MEM1 = 20; constexpr int SPI_SCK_MEM1 = SPI1_SCK_PIN;
#endif
// SPI Constants // SPI Constants
constexpr int SPI_WRITE_MODE_REG = 0x1; constexpr int SPI_WRITE_MODE_REG = 0x1;
@ -48,6 +49,7 @@ constexpr int SPI_ADDR_0_MASK = 0x0000FF;
constexpr int CMD_ADDRESS_SIZE = 4; constexpr int CMD_ADDRESS_SIZE = 4;
constexpr int MAX_DMA_XFER_SIZE = 0x4000; constexpr int MAX_DMA_XFER_SIZE = 0x4000;
BASpiMemory::BASpiMemory(SpiDeviceId memDeviceId) BASpiMemory::BASpiMemory(SpiDeviceId memDeviceId)
{ {
m_memDeviceId = memDeviceId; m_memDeviceId = memDeviceId;
@ -71,6 +73,7 @@ void BASpiMemory::begin()
m_spi->setMISO(SPI_MISO_MEM0); m_spi->setMISO(SPI_MISO_MEM0);
m_spi->setSCK(SPI_SCK_MEM0); m_spi->setSCK(SPI_SCK_MEM0);
m_spi->begin(); m_spi->begin();
m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM0).DIE_BOUNDARY;
break; break;
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) #if defined(__MK64FX512__) || defined(__MK66FX1M0__)
@ -81,6 +84,7 @@ void BASpiMemory::begin()
m_spi->setMISO(SPI_MISO_MEM1); m_spi->setMISO(SPI_MISO_MEM1);
m_spi->setSCK(SPI_SCK_MEM1); m_spi->setSCK(SPI_SCK_MEM1);
m_spi->begin(); m_spi->begin();
m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM1).DIE_BOUNDARY;
break; break;
#endif #endif
@ -112,105 +116,207 @@ void BASpiMemory::write(size_t address, uint8_t data)
digitalWrite(m_csPin, HIGH); digitalWrite(m_csPin, HIGH);
} }
// Single address write // Sequential write
void BASpiMemory::write(size_t address, uint8_t *src, size_t numBytes) void BASpiMemory::write(size_t address, uint8_t *src, size_t numBytes)
{ {
uint8_t *dataPtr = src; // Check if this burst will cross the die boundary
while (numBytes > 0) {
size_t bytesToWrite = m_bytesToXfer(address, numBytes);
m_rawWrite(address, src, bytesToWrite);
address += bytesToWrite;
numBytes -= bytesToWrite;
src += bytesToWrite;
}
}
void BASpiMemory::zero(size_t address, size_t numBytes)
{
// Check if this burst will cross the die boundary
while (numBytes > 0) {
size_t bytesToWrite = m_bytesToXfer(address, numBytes);
m_rawZero(address, bytesToWrite);
address += bytesToWrite;
numBytes -= bytesToWrite;
}
}
void BASpiMemory::write16(size_t address, uint16_t data)
{
m_spi->beginTransaction(m_settings); m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW); digitalWrite(m_csPin, LOW);
m_spi->transfer(SPI_WRITE_CMD); m_spi->transfer16((SPI_WRITE_CMD << 8) | (address >> 16) );
m_spi->transfer((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT); m_spi->transfer16(address & 0xFFFF);
m_spi->transfer((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT); m_spi->transfer16(data);
m_spi->transfer((address & SPI_ADDR_0_MASK));
for (size_t i=0; i < numBytes; i++) {
m_spi->transfer(*dataPtr++);
}
m_spi->endTransaction(); m_spi->endTransaction();
digitalWrite(m_csPin, HIGH); digitalWrite(m_csPin, HIGH);
} }
void BASpiMemory::write16(size_t address, uint16_t *src, size_t numWords)
{
// Check if this burst will cross the die boundary
size_t numBytes = numWords * sizeof(uint16_t);
while (numBytes > 0) {
size_t bytesToWrite = m_bytesToXfer(address, numBytes);
size_t wordsToWrite = bytesToWrite / sizeof(uint16_t);
m_rawWrite16(address, src, wordsToWrite);
address += bytesToWrite;
numBytes -= bytesToWrite;
src += wordsToWrite;
}
}
void BASpiMemory::zero16(size_t address, size_t numWords)
{
// Check if this burst will cross the die boundary
size_t numBytes = numWords * sizeof(uint16_t);
while (numBytes > 0) {
size_t bytesToWrite = m_bytesToXfer(address, numBytes);
size_t wordsToWrite = bytesToWrite / sizeof(uint16_t);
m_rawZero16(address, wordsToWrite);
address += bytesToWrite;
numBytes -= bytesToWrite;
}
}
void BASpiMemory::zero(size_t address, size_t numBytes) // single address read
uint8_t BASpiMemory::read(size_t address)
{ {
int data;
m_spi->beginTransaction(m_settings); m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW); digitalWrite(m_csPin, LOW);
m_spi->transfer(SPI_WRITE_CMD); m_spi->transfer(SPI_READ_CMD);
m_spi->transfer((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT); m_spi->transfer((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT);
m_spi->transfer((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT); m_spi->transfer((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT);
m_spi->transfer((address & SPI_ADDR_0_MASK)); m_spi->transfer((address & SPI_ADDR_0_MASK));
data = m_spi->transfer(0);
for (size_t i=0; i < numBytes; i++) {
m_spi->transfer(0);
}
m_spi->endTransaction(); m_spi->endTransaction();
digitalWrite(m_csPin, HIGH); digitalWrite(m_csPin, HIGH);
return data;
} }
void BASpiMemory::write16(size_t address, uint16_t data) void BASpiMemory::read(size_t address, uint8_t *dest, size_t numBytes)
{
// Check if this burst will cross the die boundary
while (numBytes > 0) {
size_t bytesToRead = m_bytesToXfer(address, numBytes);
m_rawRead(address, dest, bytesToRead);
address += bytesToRead;
numBytes -= bytesToRead;
dest += bytesToRead;
}
}
uint16_t BASpiMemory::read16(size_t address)
{ {
uint16_t data;
m_spi->beginTransaction(m_settings); m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW); digitalWrite(m_csPin, LOW);
m_spi->transfer16((SPI_WRITE_CMD << 8) | (address >> 16) ); m_spi->transfer16((SPI_READ_CMD << 8) | (address >> 16) );
m_spi->transfer16(address & 0xFFFF); m_spi->transfer16(address & 0xFFFF);
m_spi->transfer16(data); data = m_spi->transfer16(0);
m_spi->endTransaction(); m_spi->endTransaction();
digitalWrite(m_csPin, HIGH); digitalWrite(m_csPin, HIGH);
return data;
} }
void BASpiMemory::write16(size_t address, uint16_t *src, size_t numWords) void BASpiMemory::read16(size_t address, uint16_t *dest, size_t numWords)
{ {
uint16_t *dataPtr = src; // Check if this burst will cross the die boundary
size_t numBytes = numWords * sizeof(uint16_t);
while (numBytes > 0) {
size_t bytesToRead = m_bytesToXfer(address, numBytes);
size_t wordsToRead = bytesToRead / sizeof(uint16_t);
m_rawRead16(address, dest, wordsToRead);
address += bytesToRead;
numBytes -= bytesToRead;
dest += wordsToRead;
}
}
// PRIVATE FUNCTIONS
size_t BASpiMemory::m_bytesToXfer(size_t address, size_t numBytes)
{
// Check if this burst will cross the die boundary
size_t bytesToXfer = numBytes;
if (m_dieBoundary) {
if ((address < m_dieBoundary) && (address+numBytes > m_dieBoundary)) {
// split into two xfers
bytesToXfer = m_dieBoundary-address;
}
}
return bytesToXfer;
}
void BASpiMemory::m_rawWrite(size_t address, uint8_t *src, size_t numBytes)
{
uint8_t *dataPtr = src;
m_spi->beginTransaction(m_settings); m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW); digitalWrite(m_csPin, LOW);
m_spi->transfer16((SPI_WRITE_CMD << 8) | (address >> 16) ); m_spi->transfer(SPI_WRITE_CMD);
m_spi->transfer16(address & 0xFFFF); m_spi->transfer((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT);
m_spi->transfer((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT);
m_spi->transfer((address & SPI_ADDR_0_MASK));
for (size_t i=0; i<numWords; i++) { for (size_t i=0; i < numBytes; i++) {
m_spi->transfer16(*dataPtr++); m_spi->transfer(*dataPtr++);
} }
m_spi->endTransaction(); m_spi->endTransaction();
digitalWrite(m_csPin, HIGH); digitalWrite(m_csPin, HIGH);
} }
void BASpiMemory::zero16(size_t address, size_t numWords) void BASpiMemory::m_rawWrite16(size_t address, uint16_t *src, size_t numWords)
{ {
uint16_t *dataPtr = src;
m_spi->beginTransaction(m_settings); m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW); digitalWrite(m_csPin, LOW);
m_spi->transfer16((SPI_WRITE_CMD << 8) | (address >> 16) ); m_spi->transfer16((SPI_WRITE_CMD << 8) | (address >> 16) );
m_spi->transfer16(address & 0xFFFF); m_spi->transfer16(address & 0xFFFF);
for (size_t i=0; i<numWords; i++) { for (size_t i=0; i<numWords; i++) {
m_spi->transfer16(0); m_spi->transfer16(*dataPtr++);
} }
m_spi->endTransaction(); m_spi->endTransaction();
digitalWrite(m_csPin, HIGH); digitalWrite(m_csPin, HIGH);
Serial.println("DONE!");
} }
// single address read void BASpiMemory::m_rawZero(size_t address, size_t numBytes)
uint8_t BASpiMemory::read(size_t address)
{ {
int data;
m_spi->beginTransaction(m_settings); m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW); digitalWrite(m_csPin, LOW);
m_spi->transfer(SPI_READ_CMD); m_spi->transfer(SPI_WRITE_CMD);
m_spi->transfer((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT); m_spi->transfer((address & SPI_ADDR_2_MASK) >> SPI_ADDR_2_SHIFT);
m_spi->transfer((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT); m_spi->transfer((address & SPI_ADDR_1_MASK) >> SPI_ADDR_1_SHIFT);
m_spi->transfer((address & SPI_ADDR_0_MASK)); m_spi->transfer((address & SPI_ADDR_0_MASK));
data = m_spi->transfer(0);
for (size_t i=0; i < numBytes; i++) {
m_spi->transfer(0);
}
m_spi->endTransaction(); m_spi->endTransaction();
digitalWrite(m_csPin, HIGH); digitalWrite(m_csPin, HIGH);
return data;
} }
void BASpiMemory::m_rawZero16(size_t address, size_t numWords)
{
m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW);
m_spi->transfer16((SPI_WRITE_CMD << 8) | (address >> 16) );
m_spi->transfer16(address & 0xFFFF);
void BASpiMemory::read(size_t address, uint8_t *dest, size_t numBytes) for (size_t i=0; i<numWords; i++) {
m_spi->transfer16(0);
}
m_spi->endTransaction();
digitalWrite(m_csPin, HIGH);
}
void BASpiMemory::m_rawRead(size_t address, uint8_t *dest, size_t numBytes)
{ {
uint8_t *dataPtr = dest; uint8_t *dataPtr = dest;
@ -229,24 +335,8 @@ void BASpiMemory::read(size_t address, uint8_t *dest, size_t numBytes)
digitalWrite(m_csPin, HIGH); digitalWrite(m_csPin, HIGH);
} }
uint16_t BASpiMemory::read16(size_t address) void BASpiMemory::m_rawRead16(size_t address, uint16_t *dest, size_t numWords)
{ {
uint16_t data;
m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW);
m_spi->transfer16((SPI_READ_CMD << 8) | (address >> 16) );
m_spi->transfer16(address & 0xFFFF);
data = m_spi->transfer16(0);
m_spi->endTransaction();
digitalWrite(m_csPin, HIGH);
return data;
}
void BASpiMemory::read16(size_t address, uint16_t *dest, size_t numWords)
{
uint16_t *dataPtr = dest; uint16_t *dataPtr = dest;
m_spi->beginTransaction(m_settings); m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW); digitalWrite(m_csPin, LOW);
@ -261,6 +351,9 @@ void BASpiMemory::read16(size_t address, uint16_t *dest, size_t numWords)
digitalWrite(m_csPin, HIGH); digitalWrite(m_csPin, HIGH);
} }
#if defined (__IMXRT1062__)
//#if 0
#else
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// BASpiMemoryDMA // BASpiMemoryDMA
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -342,8 +435,8 @@ void BASpiMemoryDMA::begin(void)
m_spi->setMISO(SPI_MISO_MEM0); m_spi->setMISO(SPI_MISO_MEM0);
m_spi->setSCK(SPI_SCK_MEM0); m_spi->setSCK(SPI_SCK_MEM0);
m_spi->begin(); m_spi->begin();
//m_spiDma = &DMASPI0;
m_spiDma = new DmaSpiGeneric(); m_spiDma = new DmaSpiGeneric();
m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM0).DIE_BOUNDARY;
break; break;
#if defined(__MK66FX1M0__) // DMA on SPI1 is only supported on T3.6 #if defined(__MK66FX1M0__) // DMA on SPI1 is only supported on T3.6
@ -355,7 +448,7 @@ void BASpiMemoryDMA::begin(void)
m_spi->setSCK(SPI_SCK_MEM1); m_spi->setSCK(SPI_SCK_MEM1);
m_spi->begin(); m_spi->begin();
m_spiDma = new DmaSpiGeneric(1); m_spiDma = new DmaSpiGeneric(1);
//m_spiDma = &DMASPI1; m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM1).DIE_BOUNDARY;
break; break;
#endif #endif
@ -366,7 +459,6 @@ void BASpiMemoryDMA::begin(void)
m_spiDma->begin(); m_spiDma->begin();
m_spiDma->start(); m_spiDma->start();
m_started = true; m_started = true;
} }
@ -380,14 +472,16 @@ void BASpiMemoryDMA::write(size_t address, uint8_t *src, size_t numBytes)
size_t bytesRemaining = numBytes; size_t bytesRemaining = numBytes;
uint8_t *srcPtr = src; uint8_t *srcPtr = src;
size_t nextAddress = address; size_t nextAddress = address;
while (bytesRemaining > 0) { while (bytesRemaining > 0) {
m_txXferCount = min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE)); m_txXferCount = m_bytesToXfer(nextAddress, min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE))); // check for die boundary
while ( m_txTransfer[1].busy()) {} // wait until not busy
while ( m_txTransfer[1].busy() || m_txTransfer[0].busy()) { yield(); } // wait until not busy
m_setSpiCmdAddr(SPI_WRITE_CMD, nextAddress, m_txCommandBuffer); m_setSpiCmdAddr(SPI_WRITE_CMD, nextAddress, m_txCommandBuffer);
m_txTransfer[1] = DmaSpi::Transfer(m_txCommandBuffer, CMD_ADDRESS_SIZE, nullptr, 0, m_cs, TransferType::NO_END_CS); m_txTransfer[1] = DmaSpi::Transfer(m_txCommandBuffer, CMD_ADDRESS_SIZE, nullptr, 0, m_cs, TransferType::NO_END_CS);
m_spiDma->registerTransfer(m_txTransfer[1]); m_spiDma->registerTransfer(m_txTransfer[1]);
while ( m_txTransfer[0].busy()) {} // wait until not busy while ( m_txTransfer[0].busy() || m_txTransfer[1].busy()) { yield(); } // wait until not busy
m_txTransfer[0] = DmaSpi::Transfer(srcPtr, m_txXferCount, nullptr, 0, m_cs, TransferType::NO_START_CS); m_txTransfer[0] = DmaSpi::Transfer(srcPtr, m_txXferCount, nullptr, 0, m_cs, TransferType::NO_START_CS);
m_spiDma->registerTransfer(m_txTransfer[0]); m_spiDma->registerTransfer(m_txTransfer[0]);
bytesRemaining -= m_txXferCount; bytesRemaining -= m_txXferCount;
@ -401,15 +495,23 @@ void BASpiMemoryDMA::zero(size_t address, size_t numBytes)
{ {
size_t bytesRemaining = numBytes; size_t bytesRemaining = numBytes;
size_t nextAddress = address; size_t nextAddress = address;
/// TODO: Why can't the T4 zero the memory when a NULLPTR is passed? It seems to write a constant random value.
/// Perhaps there is somewhere we can set a fill value?
uint8_t zeroBuffer[MAX_DMA_XFER_SIZE];
memset(zeroBuffer, 0, MAX_DMA_XFER_SIZE);
while (bytesRemaining > 0) { while (bytesRemaining > 0) {
m_txXferCount = min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE)); m_txXferCount = m_bytesToXfer(nextAddress, min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE))); // check for die boundary
while ( m_txTransfer[1].busy()) {} // wait until not busy
while ( m_txTransfer[1].busy()) { yield(); } // wait until not busy
m_setSpiCmdAddr(SPI_WRITE_CMD, nextAddress, m_txCommandBuffer); m_setSpiCmdAddr(SPI_WRITE_CMD, nextAddress, m_txCommandBuffer);
m_txTransfer[1] = DmaSpi::Transfer(m_txCommandBuffer, CMD_ADDRESS_SIZE, nullptr, 0, m_cs, TransferType::NO_END_CS); m_txTransfer[1] = DmaSpi::Transfer(m_txCommandBuffer, CMD_ADDRESS_SIZE, nullptr, 0, m_cs, TransferType::NO_END_CS);
m_spiDma->registerTransfer(m_txTransfer[1]); m_spiDma->registerTransfer(m_txTransfer[1]);
while ( m_txTransfer[0].busy()) {} // wait until not busy while ( m_txTransfer[0].busy()) { yield(); } // wait until not busy
m_txTransfer[0] = DmaSpi::Transfer(nullptr, m_txXferCount, nullptr, 0, m_cs, TransferType::NO_START_CS); //m_txTransfer[0] = DmaSpi::Transfer(nullptr, m_txXferCount, nullptr, 0, m_cs, TransferType::NO_START_CS);
m_txTransfer[0] = DmaSpi::Transfer(zeroBuffer, m_txXferCount, nullptr, 0, m_cs, TransferType::NO_START_CS);
m_spiDma->registerTransfer(m_txTransfer[0]); m_spiDma->registerTransfer(m_txTransfer[0]);
bytesRemaining -= m_txXferCount; bytesRemaining -= m_txXferCount;
nextAddress += m_txXferCount; nextAddress += m_txXferCount;
@ -434,14 +536,15 @@ void BASpiMemoryDMA::read(size_t address, uint8_t *dest, size_t numBytes)
uint8_t *destPtr = dest; uint8_t *destPtr = dest;
size_t nextAddress = address; size_t nextAddress = address;
while (bytesRemaining > 0) { while (bytesRemaining > 0) {
m_setSpiCmdAddr(SPI_READ_CMD, nextAddress, m_rxCommandBuffer); m_rxXferCount = m_bytesToXfer(nextAddress, min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE))); // check for die boundary
while ( m_rxTransfer[1].busy()) {} m_setSpiCmdAddr(SPI_READ_CMD, nextAddress, m_rxCommandBuffer);
while ( m_rxTransfer[1].busy() || m_rxTransfer[0].busy()) { yield(); }
m_rxTransfer[1] = DmaSpi::Transfer(m_rxCommandBuffer, CMD_ADDRESS_SIZE, nullptr, 0, m_cs, TransferType::NO_END_CS); m_rxTransfer[1] = DmaSpi::Transfer(m_rxCommandBuffer, CMD_ADDRESS_SIZE, nullptr, 0, m_cs, TransferType::NO_END_CS);
m_spiDma->registerTransfer(m_rxTransfer[1]); m_spiDma->registerTransfer(m_rxTransfer[1]);
m_rxXferCount = min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE));
while ( m_rxTransfer[0].busy()) {} while ( m_rxTransfer[0].busy() || m_rxTransfer[1].busy()) { yield(); }
m_rxTransfer[0] = DmaSpi::Transfer(nullptr, m_rxXferCount, destPtr, 0, m_cs, TransferType::NO_START_CS); m_rxTransfer[0] = DmaSpi::Transfer(nullptr, m_rxXferCount, destPtr, 0, m_cs, TransferType::NO_START_CS);
m_spiDma->registerTransfer(m_rxTransfer[0]); m_spiDma->registerTransfer(m_rxTransfer[0]);
@ -467,5 +570,6 @@ bool BASpiMemoryDMA::isReadBusy(void) const
{ {
return (m_rxTransfer[0].busy() or m_rxTransfer[1].busy()); return (m_rxTransfer[0].busy() or m_rxTransfer[1].busy());
} }
#endif // BASpiMemoryDMA definition
} /* namespace BALibrary */ } /* namespace BALibrary */

@ -1,6 +1,8 @@
#include "DmaSpi.h" #include "DmaSpi.h"
#if defined(KINETISK) #if defined(__IMXRT1062__) // T4.0
DmaSpi0 DMASPI0;
#elif defined(KINETISK)
DmaSpi0 DMASPI0; DmaSpi0 DMASPI0;
#if defined(__MK66FX1M0__) #if defined(__MK66FX1M0__)
DmaSpi1 DMASPI1; DmaSpi1 DMASPI1;

Loading…
Cancel
Save