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

@ -38,7 +38,7 @@ BASpiMemory spiMem0(SpiDeviceId::SPI_DEVICE0);
unsigned long t=0;
// SPI stuff
int spiAddress0 = 0;
unsigned spiAddress0 = 0;
uint16_t spiData0 = 0xABCD;
int spiErrorCount0 = 0;
@ -52,9 +52,11 @@ void setup() {
MIDI.begin(MIDI_CHANNEL_OMNI);
Serial.begin(57600);
while (!Serial) {}
while (!Serial) { yield(); }
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
codecControl.disable();
delay(100);
@ -98,7 +100,7 @@ void loop() {
// Write test data to the SPI Memory 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) {
//Serial.print("Writing to ");
//Serial.println(spiAddress0, HEX);
@ -117,7 +119,7 @@ void loop() {
spiAddress0 = 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) {
// Serial.print("Reading ");
// Serial.print(spiAddress0, HEX);
@ -205,4 +207,3 @@ void loop() {
gpio.toggleLed();
}

@ -57,8 +57,13 @@ void setup() {
MIDI.begin(MIDI_CHANNEL_OMNI);
Serial.begin(57600);
while (!Serial) { yield(); }
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
codecControl.disable();
delay(100);
@ -103,7 +108,7 @@ void loop() {
// Write test data to the SPI Memory 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) {
//Serial.print("Writing to ");
//Serial.println(spiAddress0, HEX);
@ -122,7 +127,7 @@ void loop() {
spiAddress0 = 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) {
// Serial.print("Reading ");
// Serial.print(spiAddress0, HEX);
@ -159,7 +164,7 @@ void loop() {
// Write test data to the SPI Memory 1
//////////////////////////////////////////////////////////////////
maskPhase = 0;
for (spiAddress1=0; spiAddress1 <= SPI_MAX_ADDR; spiAddress1+=2) {
for (spiAddress1=0; spiAddress1 <= BAHardwareConfig.getSpiMemMaxAddr(1); spiAddress1+=2) {
if ((spiAddress1 % 32768) == 0) {
//Serial.print("Writing to ");
//Serial.println(spiAddress1, HEX);
@ -178,7 +183,7 @@ void loop() {
spiAddress1 = 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) {
//Serial.print("Reading ");
//Serial.print(spiAddress1, HEX);
@ -264,4 +269,3 @@ void loop() {
gpio.toggleLed();
}

@ -82,6 +82,7 @@ void setup() {
// If using external memory request request memory from the manager
// for the slot
#ifdef USE_EXT
SPI_MEM0_1M();
Serial.println("Using EXTERNAL memory");
// We have to request memory be allocated to our slot.
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
* 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 "BAEffects.h"
@ -99,6 +96,9 @@ void setup() {
Serial.begin(57600); // Start the serial port
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.
// pushbuttons
bypassHandle = controls.addSwitch(BA_EXPAND_SW1_PIN); // will be used for bypass control

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

@ -101,13 +101,15 @@ delay(100);
AudioMemory(128);
delay(5);
SPI_MEM0_1M(); // Configure the SPI memory size
// Enable the codec
Serial.println("Enabling codec...\n");
codec.enable();
delay(100);
// 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);
// Setup MIDI
@ -192,4 +194,3 @@ void loop() {
// }
}

@ -100,6 +100,7 @@ delay(100);
delay(100); // wait a bit for serial to be available
Serial.begin(57600); // Start the serial port
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.
// pushbuttons
@ -117,13 +118,15 @@ delay(100);
codec.disable();
AudioMemory(128);
SPI_MEM0_1M(); // set the Spi memory size
// Enable the codec
Serial.println("Enabling codec...\n");
codec.enable();
codec.setHeadphoneVolume(1.0f); // Max headphone volume
// 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
// by BAPhysicalControls
@ -223,4 +226,3 @@ void loop() {
loopCount++;
}

@ -31,7 +31,6 @@ BAAudioControlWM8731 codec;
// YOU MUST USE TEENSYDUINO 1.41 or greater
// 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
AudioEffectTremolo tremolo;

@ -18,8 +18,6 @@
* Using the Serial Montitor, send 'u' and 'd' characters to increase or decrease
* 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 "BAEffects.h"
@ -76,6 +74,8 @@ void setup() {
Serial.begin(57600); // Start the serial port
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.
// pushbuttons
bypassHandle = controls.addSwitch(BA_EXPAND_SW1_PIN); // will be used for bypass control

@ -11,7 +11,7 @@
*/
constexpr unsigned LOW_RATE = 2400;
constexpr unsigned MIDI_RATE = 31250;
constexpr unsigned HIGH_RATE = 250000;
constexpr unsigned HIGH_RATE = 230400;
constexpr unsigned TEST_TIME = 5; // 5 second test each
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);
}
constexpr size_t TEST_END = SPI_MAX_ADDR;
size_t SPI_MAX_ADDR;
;
void setup() {
Serial.begin(57600);
while (!Serial) {}
while (!Serial) { yield(); }
delay(5);
SPI_MEM0_1M();
SPI_MAX_ADDR = BAHardwareConfig.getSpiMemMaxAddr(MemSelect::MEM0);
Serial.println("Enabling SPI, testing MEM0");
spiMem0.begin();
}
@ -82,7 +86,7 @@ bool spi8BitTest(void) {
Serial.println("\nStarting 8-bit test Write/Read");
while (spiPhase < 4) {
spiAddress = 0;
while (spiAddress < TEST_END) {
while (spiAddress <= SPI_MAX_ADDR) {
// fill the write data buffer
switch (spiPhase) {
@ -117,7 +121,7 @@ bool spi8BitTest(void) {
// Read back the data using 8-bit transfers
spiAddress = 0;
while (spiAddress < TEST_END) {
while (spiAddress <= SPI_MAX_ADDR) {
// generate the golden data
switch (spiPhase) {
case 0 :
@ -165,7 +169,7 @@ bool spi8BitTest(void) {
// Clear the memory
spiAddress = 0;
memset(src8, 0, DMA_SIZE);
while (spiAddress < SPI_MAX_ADDR) {
while (spiAddress <= SPI_MAX_ADDR) {
// Send the DMA transfer
spiMem0.zero(spiAddress, DMA_SIZE);
// wait until write is done
@ -175,7 +179,7 @@ bool spi8BitTest(void) {
// Check the memory is clear
spiAddress = 0;
while (spiAddress < SPI_MAX_ADDR) {
while (spiAddress <= SPI_MAX_ADDR) {
// Read back the DMA data
spiMem0.read(spiAddress, dest8, DMA_SIZE);
// wait until read is done
@ -201,7 +205,7 @@ bool spi16BitTest(void) {
Serial.println("\nStarting 16-bit test");
while (spiPhase < 4) {
spiAddress = 0;
while (spiAddress < SPI_MAX_ADDR) {
while (spiAddress <= SPI_MAX_ADDR) {
// fill the write data buffer
switch (spiPhase) {
@ -236,7 +240,7 @@ bool spi16BitTest(void) {
// Read back the data using 8-bit transfers
spiAddress = 0;
while (spiAddress < SPI_MAX_ADDR) {
while (spiAddress <= SPI_MAX_ADDR) {
// generate the golden data
switch (spiPhase) {
case 0 :
@ -283,7 +287,7 @@ bool spi16BitTest(void) {
// Clear the memory
spiAddress = 0;
memset(src16, 0, DMA_SIZE);
while (spiAddress < SPI_MAX_ADDR) {
while (spiAddress <= SPI_MAX_ADDR) {
// Send the DMA transfer
spiMem0.zero16(spiAddress, NUM_DATA);
// wait until write is done
@ -293,7 +297,7 @@ bool spi16BitTest(void) {
// Check the memory is clear
spiAddress = 0;
while (spiAddress < SPI_MAX_ADDR) {
while (spiAddress <= SPI_MAX_ADDR) {
// Read back the DMA data
spiMem0.read16(spiAddress, dest16, NUM_DATA);
// wait until read is done
@ -313,4 +317,3 @@ void loop() {
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);
}
constexpr size_t TEST_END = SPI_MAX_ADDR;
size_t SPI_MAX_ADDR = 0;
void setup() {
Serial.begin(57600);
while (!Serial) {}
while (!Serial) { yield(); }
delay(5);
SPI_MEM1_1M();
SPI_MAX_ADDR = BAHardwareConfig.getSpiMemMaxAddr(MemSelect::MEM1);
Serial.println("Enabling SPI, testing MEM1");
spiMem1.begin();
}
@ -81,7 +84,7 @@ bool spi8BitTest(void) {
Serial.println("\nStarting 8-bit test Write/Read");
while (spiPhase < 4) {
spiAddress = 0;
while (spiAddress < TEST_END) {
while (spiAddress <= SPI_MAX_ADDR) {
// fill the write data buffer
switch (spiPhase) {
@ -116,7 +119,7 @@ bool spi8BitTest(void) {
// Read back the data using 8-bit transfers
spiAddress = 0;
while (spiAddress < TEST_END) {
while (spiAddress <= SPI_MAX_ADDR) {
// generate the golden data
switch (spiPhase) {
case 0 :
@ -164,7 +167,7 @@ bool spi8BitTest(void) {
// Clear the memory
spiAddress = 0;
memset(src8, 0, DMA_SIZE);
while (spiAddress < SPI_MAX_ADDR) {
while (spiAddress <= SPI_MAX_ADDR) {
// Send the DMA transfer
spiMem1.zero(spiAddress, DMA_SIZE);
// wait until write is done
@ -174,7 +177,7 @@ bool spi8BitTest(void) {
// Check the memory is clear
spiAddress = 0;
while (spiAddress < SPI_MAX_ADDR) {
while (spiAddress <= SPI_MAX_ADDR) {
// Read back the DMA data
spiMem1.read(spiAddress, dest8, DMA_SIZE);
// wait until read is done
@ -200,7 +203,7 @@ bool spi16BitTest(void) {
Serial.println("\nStarting 16-bit test");
while (spiPhase < 4) {
spiAddress = 0;
while (spiAddress < SPI_MAX_ADDR) {
while (spiAddress <= SPI_MAX_ADDR) {
// fill the write data buffer
switch (spiPhase) {
@ -235,7 +238,7 @@ bool spi16BitTest(void) {
// Read back the data using 8-bit transfers
spiAddress = 0;
while (spiAddress < SPI_MAX_ADDR) {
while (spiAddress <= SPI_MAX_ADDR) {
// generate the golden data
switch (spiPhase) {
case 0 :
@ -282,7 +285,7 @@ bool spi16BitTest(void) {
// Clear the memory
spiAddress = 0;
memset(src16, 0, DMA_SIZE);
while (spiAddress < SPI_MAX_ADDR) {
while (spiAddress <= SPI_MAX_ADDR) {
// Send the DMA transfer
spiMem1.zero16(spiAddress, NUM_DATA);
// wait until write is done
@ -292,7 +295,7 @@ bool spi16BitTest(void) {
// Check the memory is clear
spiAddress = 0;
while (spiAddress < SPI_MAX_ADDR) {
while (spiAddress <= SPI_MAX_ADDR) {
// Read back the DMA data
spiMem1.read16(spiAddress, dest16, NUM_DATA);
// wait until read is done
@ -312,4 +315,3 @@ void loop() {
while(true) {}
}

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

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

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

@ -12,6 +12,8 @@ constexpr int mask1 = 0xaaaa;
using namespace BALibrary;
size_t SPI_MAX_ADDR = 0;
int calcData(int spiAddress, int loopPhase, int maskPhase)
{
int data;
@ -35,7 +37,7 @@ int calcData(int spiAddress, int loopPhase, int maskPhase)
return (data & 0xffff);
}
bool spiTest(BASpiMemoryDMA *mem)
bool spiTest(BASpiMemory *mem)
{
int spiAddress = 0;
int spiErrorCount = 0;
@ -45,7 +47,10 @@ bool spiTest(BASpiMemoryDMA *mem)
uint16_t memBlock[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++) {
@ -122,4 +127,3 @@ bool spiTest(BASpiMemoryDMA *mem)
}
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)
#######################################
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)
#######################################
BAHardwareConfig KEYWORD1
#######################################
# Constants (LITERAL1)

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

@ -45,12 +45,12 @@ public:
/// Specifiy which external 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
/// @param type specify which memory to use
/// @param delayLengthMs maximum delay length in milliseconds
BAAudioEffectDelayExternal(BALibrary::MemSelect type, float delayLengthMs);
BAAudioEffectDelayExternal(BALibrary::MemSelect mem, float delayLengthMs);
virtual ~BAAudioEffectDelayExternal();
/// 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
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 write(uint32_t address, uint32_t count, const int16_t *data);
void zero(uint32_t address, uint32_t count);
@ -79,7 +82,6 @@ private:
static unsigned m_allocated[2];
audio_block_t *m_inputQueueArray[1];
BALibrary::MemSelect m_mem;
SPIClass *m_spi = nullptr;
int m_spiChannel = 0;
int m_misoPin = 0;

@ -32,19 +32,164 @@
*****************************************************************************/
namespace BALibrary {
// uncomment the line that corresponds to your hardware
//#define TGA_PRO_REVA
#if (!defined(TGA_PRO_REVA) && !defined(TGA_PRO_REVB))
#define TGA_PRO_REVA
#endif
// In your Arudino .ino file, use #defines for your TGA Pro revision and options
// to correctly configure your hardware
#define TGA_PRO_REVA(x) BALibrary::BAHardwareConfig.m_tgaBoard = TgaBoard::REV_A ///< Macro for specifying REV A of the TGA Pro
#define TGA_PRO_REVB(x) BALibrary::BAHardwareConfig.m_tgaBoard = TgaBoard::REV_B ///< Macro for specifying REV B of the TGA Pro
#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 {
GPIO0 = 2,
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;
enum MemSelect : unsigned {
MEM0 = 0, ///< SPI RAM MEM0
MEM1 = 1 ///< SPI RAM MEM1
};
#elif defined(__IMXRT1062__) // T4.0
constexpr uint8_t USR_LED_ID = 2; ///< Teensy IO number for the user LED.
/**************************************************************************//**
* Set the maximum address (byte-based) in the external SPI memories
*****************************************************************************/
constexpr size_t MEM_MAX_ADDR[NUM_MEM_SLOTS] = { 131071, 131071 };
// SPI0 pinouts
constexpr uint8_t SPI0_SCK_PIN = 13;
constexpr uint8_t SPI0_CS_PIN = 10;
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,
/**************************************************************************//**
* General Purpose SPI Interfaces
*****************************************************************************/
enum class SpiDeviceId : unsigned {
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);
GPIO4 = 17,
GPIO5 = 16,
GPIO6 = 15,
GPIO7 = 14,
constexpr size_t SPI_MEM1_SIZE_BYTES = 131072;
constexpr size_t SPI_MEM1_MAX_AUDIO_SAMPLES = SPI_MEM1_SIZE_BYTES/sizeof(int16_t);
TP1 = 9,
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
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
#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_SW = 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_LED1_PIN = 4; // 4_SDA2_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
} // namespace BALibrary
#endif /* __BALIBRARY_BAHARDWARE_H */

@ -26,6 +26,8 @@
#include <Encoder.h>
#include <Bounce2.h>
#include "Arduino.h"
namespace BALibrary {
constexpr bool SWAP_DIRECTION = true; ///< Use when specifying direction should be swapped
@ -132,12 +134,27 @@ public:
void adjustCalibrationThreshold(float thresholdFactor);
/// 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
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);
/// 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
/// involves prompts over the Serial port.
/// @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_maxCalibration; ///< stores the max pot 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%
unsigned m_minCalibrationThresholded; ///< stores the min 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_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.
@ -306,8 +328,6 @@ private:
std::vector<DigitalOutput> m_outputs; ///< a vector of all added outputs
};
} // BALibrary
#endif /* __BAPHYSICALCONTROLS_H */

@ -23,6 +23,7 @@
#ifndef __BALIBRARY_BASPIMEMORY_H
#define __BALIBRARY_BASPIMEMORY_H
#include <cstdint>
#include <SPI.h>
#include <DmaSpi.h>
@ -33,7 +34,7 @@ namespace BALibrary {
/**************************************************************************//**
* 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
* 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).
/// @details default is 20 Mhz
/// @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)
/// @param memDeviceId specify which MEM to control with SpiDeviceId.
/// @param speedHz specify the desired speed in Hz.
@ -111,16 +112,39 @@ public:
/// @returns true if initialized, false if not yet initialized
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:
SPIClass *m_spi = nullptr;
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
SPISettings m_settings; // the Wire settings for this SPI port
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 {
public:
BASpiMemoryDMA() = delete;
@ -181,11 +205,11 @@ public:
/// Check if a DMA write is in progress
/// @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
/// @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
/// @param dest pointer to the destination
@ -214,6 +238,7 @@ private:
void m_setSpiCmdAddr(int command, size_t address, uint8_t *dest);
};
#endif // BASpiMemoryDMA declaration
} /* namespace BALibrary */

@ -12,6 +12,11 @@
#include "DMAChannel.h"
#include <core_pins.h>
//#include <core_cm7.h>
#include <arm_math.h>
//#define DEBUG_DMASPI 1
/** \brief Specifies the desired CS suppression
**/
@ -152,7 +157,6 @@ class ActiveLowChipSelect1 : public AbstractChipSelect
#endif
//#define DEBUG_DMASPI 1
#if defined(DEBUG_DMASPI)
#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();}
// finishCurrentTransfer is called from rxISR_()
static void finishCurrentTransfer()
{
DMASPI_PRINT((" inside finishCurrentTransfer()\n"));
if (m_pCurrentTransfer->m_pSelect != nullptr)
{
m_pCurrentTransfer->m_pSelect->deselect(m_pCurrentTransfer->m_transferType);
@ -581,12 +587,12 @@ class AbstractDmaSpi
{
if (m_pNextTransfer == nullptr)
{
DMASPI_PRINT(("DmaSpi::beginNextTransfer: no pending transfer\n"));
DMASPI_PRINT(("DmaSpi::beginPendingTransfer: no pending transfer\n"));
return;
}
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_pNextTransfer = m_pNextTransfer->m_pNext;
if (m_pNextTransfer == nullptr)
@ -600,6 +606,7 @@ class AbstractDmaSpi
{
// real data sink
DMASPI_PRINT((" real sink\n"));
arm_dcache_flush_delete((void *)m_pCurrentTransfer->m_pDest, m_pCurrentTransfer->m_transferCount);
rxChannel_()->destinationBuffer(m_pCurrentTransfer->m_pDest,
m_pCurrentTransfer->m_transferCount);
}
@ -616,6 +623,7 @@ class AbstractDmaSpi
{
// real data source
DMASPI_PRINT((" real source\n"));
arm_dcache_flush_delete((void *)m_pCurrentTransfer->m_pSource, m_pCurrentTransfer->m_transferCount);
txChannel_()->sourceBuffer(m_pCurrentTransfer->m_pSource,
m_pCurrentTransfer->m_transferCount);
}
@ -627,6 +635,7 @@ class AbstractDmaSpi
txChannel_()->transferCount(m_pCurrentTransfer->m_transferCount);
}
DMASPI_PRINT(("calling pre_cs() "));
pre_cs();
// Select Chip
@ -639,6 +648,7 @@ class AbstractDmaSpi
m_Spi.beginTransaction(SPISettings());
}
DMASPI_PRINT(("calling 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>
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>
{
@ -677,24 +697,136 @@ public:
static void begin_setup_txChannel_impl()
{
txChannel_()->disable();
txChannel_()->destination((volatile uint8_t&)SPI0_PUSHR);
txChannel_()->destination((volatile uint8_t&)IMXRT_LPSPI4_S.TDR);
txChannel_()->disableOnCompletion();
txChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_TX);
txChannel_()->triggerAtHardwareEvent(DMAMUX_SOURCE_LPSPI4_TX);
//txChannel_()->triggerAtTransfersOf(*rxChannel_);
}
static void begin_setup_rxChannel_impl()
{
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_()->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_()->interruptAtCompletion();
}
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;
}
@ -706,8 +838,8 @@ public:
static void post_finishCurrentTransfer_impl()
{
SPI0_RSER = 0;
SPI0_SR = 0xFF0F0000;
SPI0_RSER = 0; //DSPI DMA/Interrupt Request Select and Enable Register
SPI0_SR = 0xFF0F0000; // DSPI status register clear flags, same as above
}
private:
@ -715,6 +847,7 @@ private:
extern DmaSpi0 DMASPI0;
#if defined(__MK66FX1M0__)
class DmaSpi1 : public AbstractDmaSpi<DmaSpi1, SPIClass, SPI1>

@ -203,6 +203,7 @@ public:
private:
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
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
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);
}
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)
{
// 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(1)
{
}
@ -62,11 +50,13 @@ ExternalSramManager::~ExternalSramManager()
size_t ExternalSramManager::availableMemory(BALibrary::MemSelect mem)
{
if (!m_configured) { m_configure(); }
return m_memConfig[mem].totalAvailable;
}
bool ExternalSramManager::requestMemory(ExtMemSlot *slot, float delayMilliseconds, BALibrary::MemSelect mem, bool useDma)
{
if (!m_configured) { m_configure(); }
// convert the time to numer of samples
size_t delayLengthInt = (size_t)((delayMilliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f);
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)
{
if (!m_configured) { m_configure(); }
if (m_memConfig[mem].totalAvailable >= sizeBytes) {
Serial.println(String("Configuring a slot for mem ") + mem);
// 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "BAHardware.h"
#include "BAAudioEffectDelayExternal.h"
using namespace BALibrary;
@ -26,36 +26,26 @@ namespace BAEffects {
#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};
BAAudioEffectDelayExternal::BAAudioEffectDelayExternal()
: AudioStream(1, m_inputQueueArray)
{
initialize(MemSelect::MEM0);
m_mem = MemSelect::MEM0;
}
BAAudioEffectDelayExternal::BAAudioEffectDelayExternal(MemSelect mem)
: 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)
{
unsigned delayLengthInt = (delayLengthMs*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f;
initialize(type, delayLengthInt);
m_mem = mem;
m_requestedDelayLength = delayLengthInt;
}
BAAudioEffectDelayExternal::~BAAudioEffectDelayExternal()
@ -65,6 +55,8 @@ BAAudioEffectDelayExternal::~BAAudioEffectDelayExternal()
void BAAudioEffectDelayExternal::delay(uint8_t channel, float milliseconds) {
if (!m_configured) { initialize(); }
if (channel >= 8) return;
if (milliseconds < 0.0) milliseconds = 0.0;
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) {
if (!m_configured) { initialize(); }
if (channel >= 8) return;
uint8_t mask = m_activeMask & ~(1<<channel);
m_activeMask = mask;
@ -86,12 +81,21 @@ void BAAudioEffectDelayExternal::disable(uint8_t channel) {
void BAAudioEffectDelayExternal::update(void)
{
audio_block_t *block;
uint32_t n, channel, read_offset;
// grab incoming data and put it into the memory
block = receiveReadOnly();
if (!m_configured) {
if (block) {
transmit(block);
release(block);
return;
} else { return; }
}
if (block) {
if (m_headOffset + AUDIO_BLOCK_SAMPLES <= m_memoryLength) {
// a single write is enough
@ -146,25 +150,25 @@ void BAAudioEffectDelayExternal::update(void)
unsigned BAAudioEffectDelayExternal::m_allocated[2] = {0, 0};
void BAAudioEffectDelayExternal::initialize(MemSelect mem, unsigned delayLength)
void BAAudioEffectDelayExternal::initialize(void)
{
unsigned samples = 0;
unsigned memsize, avail;
unsigned memsize = 0, avail = 0;
m_activeMask = 0;
m_headOffset = 0;
m_mem = mem;
//m_mem = mem;
switch (mem) {
switch (m_mem) {
case MemSelect::MEM0 :
{
memsize = Mem0Config.memSize;
memsize = BAHardwareConfig.getSpiMemSizeBytes(m_mem) / sizeof(int16_t);
m_spi = &SPI;
m_spiChannel = 0;
m_misoPin = Mem0Config.misoPin;
m_mosiPin = Mem0Config.mosiPin;
m_sckPin = Mem0Config.sckPin;
m_csPin = Mem0Config.csPin;
m_misoPin = SPI0_MISO_PIN;
m_mosiPin = SPI0_MOSI_PIN;
m_sckPin = SPI0_SCK_PIN;
m_csPin = SPI0_CS_PIN;
m_spi->setMOSI(m_mosiPin);
m_spi->setMISO(m_misoPin);
@ -175,13 +179,13 @@ void BAAudioEffectDelayExternal::initialize(MemSelect mem, unsigned delayLength)
case MemSelect::MEM1 :
{
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
memsize = Mem1Config.memSize;
memsize = BAHardwareConfig.getSpiMemSizeBytes(m_mem) / sizeof(int16_t);
m_spi = &SPI1;
m_spiChannel = 1;
m_misoPin = Mem1Config.misoPin;
m_mosiPin = Mem1Config.mosiPin;
m_sckPin = Mem1Config.sckPin;
m_csPin = Mem1Config.csPin;
m_misoPin = SPI1_MISO_PIN;
m_mosiPin = SPI1_MOSI_PIN;
m_sckPin = SPI1_SCK_PIN;
m_csPin = SPI1_CS_PIN;
m_spi->setMOSI(m_mosiPin);
m_spi->setMISO(m_misoPin);
@ -196,14 +200,15 @@ void BAAudioEffectDelayExternal::initialize(MemSelect mem, unsigned delayLength)
pinMode(m_csPin, OUTPUT);
digitalWriteFast(m_csPin, HIGH);
avail = memsize - m_allocated[mem];
avail = memsize - m_allocated[m_mem];
if (delayLength > avail) samples = avail;
m_memoryStart = m_allocated[mem];
m_allocated[mem] += samples;
if (m_requestedDelayLength > avail) samples = avail;
m_memoryStart = m_allocated[m_mem];
m_allocated[m_mem] += samples;
m_memoryLength = samples;
zero(0, m_memoryLength);
m_configured = true;
}

@ -19,6 +19,7 @@
*/
#include <Wire.h>
#include "BAHardware.h"
#include "BAAudioControlWM8731.h"
namespace BALibrary {
@ -132,9 +133,12 @@ BAAudioControlWM8731::~BAAudioControlWM8731()
// Powerdown and disable the codec
void BAAudioControlWM8731::disable(void)
{
//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
regArray[WM8731_REG_POWERDOWN] |= 0x10;
@ -155,9 +159,13 @@ void BAAudioControlWM8731::enable(void)
disable(); // disable first in case it was already powered up
//Serial.println("Enabling codec");
if (m_wireStarted == false) { Wire.begin(); m_wireStarted = true; }
// Sequence from WAN0111.pdf
if (m_wireStarted == false) {
Wire.begin();
m_wireStarted = true;
}
setOutputStrength();
// Sequence from WAN0111.pdf
// Begin configuring the codec
resetCodec();
delay(100); // wait for reset
@ -199,9 +207,6 @@ void BAAudioControlWM8731::enable(void)
regArray[WM8731_REG_POWERDOWN] = 0x02;
delay(500); // wait for output to power up
//Serial.println("Done codec config");
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.write((reg << 1) | ((val >> 8) & 1));
Wire.write(val & 0xFF);
if (byte error = Wire.endTransmission() ) {
(void)error; // supress warning about unused variable
//Serial.println(String("Wire::Error: ") + error + String(" retrying..."));
byte error = Wire.endTransmission();
if (error) {
Serial.println(String("Wire::Error: ") + error + String(" retrying..."));
} else {
done = true;
//Serial.println("Wire::SUCCESS!");
@ -380,4 +385,17 @@ bool BAAudioControlWM8731::write(unsigned int reg, unsigned int val)
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 */

@ -57,7 +57,6 @@ unsigned BAPhysicalControls::addRotary(uint8_t pin1, uint8_t pin2, bool swapDire
}
unsigned BAPhysicalControls::addSwitch(uint8_t pin, unsigned long intervalMilliseconds) {
//m_switches.emplace_back(pin, intervalMilliseconds);'
m_switches.emplace_back();
m_switches.back().attach(pin);
m_switches.back().interval(10);
@ -240,22 +239,35 @@ void Potentiometer::setFeedbackFitlerValue(float fitlerValue)
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
// constrain it within the calibration values, them map it to the desired range.
val = constrain(val, m_minCalibration, m_maxCalibration);
// 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) {
newValue = false;
// Apply a hysteresis check
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; }
else if (valFilter > m_maxCalibrationThresholded) { value = 1.0f; }
else {
@ -265,7 +277,8 @@ bool Potentiometer::getValue(float &value) {
if (m_swapDirection) {
value = 1.0f - value;
}
return newValue;
return true;
}
int Potentiometer::getRawValue() {
@ -293,6 +306,16 @@ void Potentiometer::setCalibrationValues(unsigned min, unsigned max, bool swapDi
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) {
Calib calib;

@ -17,23 +17,24 @@
* 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 "Arduino.h"
#include "BASpiMemory.h"
namespace BALibrary {
// MEM0 Settings
constexpr int SPI_CS_MEM0 = 15;
constexpr int SPI_MOSI_MEM0 = 7;
constexpr int SPI_MISO_MEM0 = 8;
constexpr int SPI_SCK_MEM0 = 14;
constexpr int SPI_CS_MEM0 = SPI0_CS_PIN;
constexpr int SPI_MOSI_MEM0 = SPI0_MOSI_PIN;
constexpr int SPI_MISO_MEM0 = SPI0_MISO_PIN;
constexpr int SPI_SCK_MEM0 = SPI0_SCK_PIN;
#if defined(SPI1_AVAILABLE)
// MEM1 Settings
constexpr int SPI_CS_MEM1 = 31;
constexpr int SPI_MOSI_MEM1 = 21;
constexpr int SPI_MISO_MEM1 = 5;
constexpr int SPI_SCK_MEM1 = 20;
constexpr int SPI_CS_MEM1 = SPI1_CS_PIN;
constexpr int SPI_MOSI_MEM1 = SPI1_MOSI_PIN;
constexpr int SPI_MISO_MEM1 = SPI1_MISO_PIN;
constexpr int SPI_SCK_MEM1 = SPI1_SCK_PIN;
#endif
// SPI Constants
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 MAX_DMA_XFER_SIZE = 0x4000;
BASpiMemory::BASpiMemory(SpiDeviceId memDeviceId)
{
m_memDeviceId = memDeviceId;
@ -71,6 +73,7 @@ void BASpiMemory::begin()
m_spi->setMISO(SPI_MISO_MEM0);
m_spi->setSCK(SPI_SCK_MEM0);
m_spi->begin();
m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM0).DIE_BOUNDARY;
break;
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
@ -81,6 +84,7 @@ void BASpiMemory::begin()
m_spi->setMISO(SPI_MISO_MEM1);
m_spi->setSCK(SPI_SCK_MEM1);
m_spi->begin();
m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM1).DIE_BOUNDARY;
break;
#endif
@ -112,105 +116,207 @@ void BASpiMemory::write(size_t address, uint8_t data)
digitalWrite(m_csPin, HIGH);
}
// Single address write
// Sequential write
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);
digitalWrite(m_csPin, LOW);
m_spi->transfer(SPI_WRITE_CMD);
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 < numBytes; i++) {
m_spi->transfer(*dataPtr++);
}
m_spi->transfer16((SPI_WRITE_CMD << 8) | (address >> 16) );
m_spi->transfer16(address & 0xFFFF);
m_spi->transfer16(data);
m_spi->endTransaction();
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);
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_1_MASK) >> SPI_ADDR_1_SHIFT);
m_spi->transfer((address & SPI_ADDR_0_MASK));
for (size_t i=0; i < numBytes; i++) {
m_spi->transfer(0);
}
data = m_spi->transfer(0);
m_spi->endTransaction();
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);
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(data);
data = m_spi->transfer16(0);
m_spi->endTransaction();
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);
digitalWrite(m_csPin, LOW);
m_spi->transfer16((SPI_WRITE_CMD << 8) | (address >> 16) );
m_spi->transfer16(address & 0xFFFF);
m_spi->transfer(SPI_WRITE_CMD);
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++) {
m_spi->transfer16(*dataPtr++);
for (size_t i=0; i < numBytes; i++) {
m_spi->transfer(*dataPtr++);
}
m_spi->endTransaction();
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);
digitalWrite(m_csPin, LOW);
m_spi->transfer16((SPI_WRITE_CMD << 8) | (address >> 16) );
m_spi->transfer16(address & 0xFFFF);
for (size_t i=0; i<numWords; i++) {
m_spi->transfer16(0);
m_spi->transfer16(*dataPtr++);
}
m_spi->endTransaction();
digitalWrite(m_csPin, HIGH);
Serial.println("DONE!");
}
// single address read
uint8_t BASpiMemory::read(size_t address)
void BASpiMemory::m_rawZero(size_t address, size_t numBytes)
{
int data;
m_spi->beginTransaction(m_settings);
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_1_MASK) >> SPI_ADDR_1_SHIFT);
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();
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;
@ -229,24 +335,8 @@ void BASpiMemory::read(size_t address, uint8_t *dest, size_t numBytes)
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;
m_spi->beginTransaction(m_settings);
digitalWrite(m_csPin, LOW);
@ -261,6 +351,9 @@ void BASpiMemory::read16(size_t address, uint16_t *dest, size_t numWords)
digitalWrite(m_csPin, HIGH);
}
#if defined (__IMXRT1062__)
//#if 0
#else
/////////////////////////////////////////////////////////////////////////////
// BASpiMemoryDMA
/////////////////////////////////////////////////////////////////////////////
@ -342,8 +435,8 @@ void BASpiMemoryDMA::begin(void)
m_spi->setMISO(SPI_MISO_MEM0);
m_spi->setSCK(SPI_SCK_MEM0);
m_spi->begin();
//m_spiDma = &DMASPI0;
m_spiDma = new DmaSpiGeneric();
m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM0).DIE_BOUNDARY;
break;
#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->begin();
m_spiDma = new DmaSpiGeneric(1);
//m_spiDma = &DMASPI1;
m_dieBoundary = BAHardwareConfig.getSpiMemoryDefinition(MemSelect::MEM1).DIE_BOUNDARY;
break;
#endif
@ -366,7 +459,6 @@ void BASpiMemoryDMA::begin(void)
m_spiDma->begin();
m_spiDma->start();
m_started = true;
}
@ -380,14 +472,16 @@ void BASpiMemoryDMA::write(size_t address, uint8_t *src, size_t numBytes)
size_t bytesRemaining = numBytes;
uint8_t *srcPtr = src;
size_t nextAddress = address;
while (bytesRemaining > 0) {
m_txXferCount = min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE));
while ( m_txTransfer[1].busy()) {} // wait until not busy
m_txXferCount = m_bytesToXfer(nextAddress, min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE))); // check for die boundary
while ( m_txTransfer[1].busy() || m_txTransfer[0].busy()) { yield(); } // wait until not busy
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_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_spiDma->registerTransfer(m_txTransfer[0]);
bytesRemaining -= m_txXferCount;
@ -401,15 +495,23 @@ void BASpiMemoryDMA::zero(size_t address, size_t numBytes)
{
size_t bytesRemaining = numBytes;
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) {
m_txXferCount = min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE));
while ( m_txTransfer[1].busy()) {} // wait until not busy
m_txXferCount = m_bytesToXfer(nextAddress, min(bytesRemaining, static_cast<size_t>(MAX_DMA_XFER_SIZE))); // check for die boundary
while ( m_txTransfer[1].busy()) { yield(); } // wait until not busy
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_spiDma->registerTransfer(m_txTransfer[1]);
while ( m_txTransfer[0].busy()) {} // wait until not busy
m_txTransfer[0] = DmaSpi::Transfer(nullptr, m_txXferCount, nullptr, 0, m_cs, TransferType::NO_START_CS);
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(zeroBuffer, m_txXferCount, nullptr, 0, m_cs, TransferType::NO_START_CS);
m_spiDma->registerTransfer(m_txTransfer[0]);
bytesRemaining -= 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;
size_t nextAddress = address;
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_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_spiDma->registerTransfer(m_rxTransfer[0]);
@ -467,5 +570,6 @@ bool BASpiMemoryDMA::isReadBusy(void) const
{
return (m_rxTransfer[0].busy() or m_rxTransfer[1].busy());
}
#endif // BASpiMemoryDMA definition
} /* namespace BALibrary */

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

Loading…
Cancel
Save