diff --git a/examples/Tests/TGA_PRO_MEM2/PhysicalControls.cpp b/examples/Tests/TGA_PRO_MEM2/PhysicalControls.cpp index f61fc16..3ed1e89 100644 --- a/examples/Tests/TGA_PRO_MEM2/PhysicalControls.cpp +++ b/examples/Tests/TGA_PRO_MEM2/PhysicalControls.cpp @@ -72,15 +72,8 @@ void checkSwitch(unsigned id) ledHandle = led1Handle; } - if (controlPtr->isSwitchToggled(swHandle)) { - Serial.println(String("SW ") + swHandle + String("Pushed")); - mute = !mute; - if (mute) { codecPtr->setHeadphoneVolume(0.0f); } - else { codecPtr->setHeadphoneVolume(0.8f); } - } - - bool pressed = controlPtr->isSwitchHeld(swHandle); - controlPtr->setOutput(ledHandle, pressed); + bool pressed = controlPtr->isSwitchHeld(swHandle); + controlPtr->setOutput(ledHandle, pressed); } diff --git a/examples/Tests/TGA_PRO_MEM2/TGA_PRO_MEM2.ino b/examples/Tests/TGA_PRO_MEM2/TGA_PRO_MEM2.ino index 6ca392b..9b91d9c 100644 --- a/examples/Tests/TGA_PRO_MEM2/TGA_PRO_MEM2.ino +++ b/examples/Tests/TGA_PRO_MEM2/TGA_PRO_MEM2.ino @@ -1,3 +1,12 @@ +/************************************************************************* + * This demo is used for manufacturing tests on the TGA Pro Expansion + * Control Board. Pushing the buttons turns on the LEDs. Adjusting + * any know will adjust the volume. + * + * The latest copy of the BA Guitar library can be obtained from + * https://github.com/Blackaddr/BALibrary + * + */ #include #include #include @@ -38,14 +47,16 @@ void setup() { // Disable the audio codec first codec.disable(); + delay(100); AudioMemory(128); codec.enable(); codec.setHeadphoneVolume(0.8f); // Set headphone volume configPhysicalControls(controls, codec); -// if (uartTest()) { Serial.println("MIDI Ports testing PASSED!"); } -// if (spiTest(&spiMem0)) { Serial.println("SPI0 testing PASSED!");} -// if (spiTest(&spiMem1)) { Serial.println("SPI1 testing PASSED!");} + // Run the initial Midi connectivity and SPI memory tests. + if (uartTest()) { Serial.println("MIDI Ports testing PASSED!"); } + if (spiTest(&spiMem0)) { Serial.println("SPI0 testing PASSED!");} + if (spiTest(&spiMem1)) { Serial.println("SPI1 testing PASSED!");} } void loop() { @@ -55,5 +66,6 @@ void loop() { checkPot(2); checkSwitch(0); checkSwitch(1); + delay(10); } diff --git a/examples/Tests/TGA_PRO_MEM2_EXP/PhysicalControls.cpp b/examples/Tests/TGA_PRO_MEM2_EXP/PhysicalControls.cpp new file mode 100644 index 0000000..3ed1e89 --- /dev/null +++ b/examples/Tests/TGA_PRO_MEM2_EXP/PhysicalControls.cpp @@ -0,0 +1,79 @@ +#define TGA_PRO_EXPAND_REV2 + +#include "BALibrary.h" +using namespace BALibrary; + +constexpr int potCalibMin = 1; +constexpr int potCalibMax = 1018; +constexpr bool potSwapDirection = true; +int pot1Handle, pot2Handle, pot3Handle, sw1Handle, sw2Handle, led1Handle, led2Handle; +bool mute = false; +BAAudioControlWM8731 *codecPtr = nullptr; +BAPhysicalControls *controlPtr = nullptr; + +void configPhysicalControls(BAPhysicalControls &controls, BAAudioControlWM8731 &codec) +{ + // Setup the controls. The return value is the handle to use when checking for control changes, etc. + + // pushbuttons + sw1Handle = controls.addSwitch(BA_EXPAND_SW1_PIN); + sw2Handle = controls.addSwitch(BA_EXPAND_SW2_PIN); + // pots + pot1Handle = controls.addPot(BA_EXPAND_POT1_PIN, potCalibMin, potCalibMax, potSwapDirection); + pot2Handle = controls.addPot(BA_EXPAND_POT2_PIN, potCalibMin, potCalibMax, potSwapDirection); + pot3Handle = controls.addPot(BA_EXPAND_POT3_PIN, potCalibMin, potCalibMax, potSwapDirection); + // leds + led1Handle = controls.addOutput(BA_EXPAND_LED1_PIN); + led2Handle = controls.addOutput(BA_EXPAND_LED2_PIN); // will illuminate when pressing SW2 + + controlPtr = &controls; + codecPtr = &codec; +} + +void checkPot(unsigned id) +{ + float potValue; + unsigned handle; + switch(id) { + case 0 : + handle = pot1Handle; + break; + case 1 : + handle = pot2Handle; + break; + case 2 : + handle = pot3Handle; + break; + default : + handle = pot1Handle; + } + + if (controlPtr->checkPotValue(handle, potValue)) { + // Pot has changed + codecPtr->setHeadphoneVolume(potValue); + } +} + +void checkSwitch(unsigned id) +{ + unsigned swHandle; + unsigned ledHandle; + switch(id) { + case 0 : + swHandle = sw1Handle; + ledHandle = led1Handle; + break; + case 1 : + swHandle = sw2Handle; + ledHandle = led2Handle; + break; + default : + swHandle = sw1Handle; + ledHandle = led1Handle; + } + + bool pressed = controlPtr->isSwitchHeld(swHandle); + controlPtr->setOutput(ledHandle, pressed); +} + + diff --git a/examples/Tests/TGA_PRO_MEM2_EXP/TGA_PRO_MEM2_EXP.ino b/examples/Tests/TGA_PRO_MEM2_EXP/TGA_PRO_MEM2_EXP.ino new file mode 100644 index 0000000..9b91d9c --- /dev/null +++ b/examples/Tests/TGA_PRO_MEM2_EXP/TGA_PRO_MEM2_EXP.ino @@ -0,0 +1,71 @@ +/************************************************************************* + * This demo is used for manufacturing tests on the TGA Pro Expansion + * Control Board. Pushing the buttons turns on the LEDs. Adjusting + * any know will adjust the volume. + * + * The latest copy of the BA Guitar library can be obtained from + * https://github.com/Blackaddr/BALibrary + * + */ +#include +#include +#include + +#define TGA_PRO_EXPAND_REV2 +#include "BALibrary.h" + +using namespace BALibrary; + +AudioInputI2S i2sIn; +AudioOutputI2S i2sOut; + +// Audio Thru Connection +AudioConnection patch0(i2sIn,0, i2sOut, 0); +AudioConnection patch1(i2sIn,1, i2sOut, 1); + +BAAudioControlWM8731 codec; +BAGpio gpio; // access to User LED + +BASpiMemoryDMA spiMem0(SpiDeviceId::SPI_DEVICE0); +BASpiMemoryDMA spiMem1(SpiDeviceId::SPI_DEVICE1); + +// Create a control object using the number of switches, pots, encoders and outputs on the +// Blackaddr Audio Expansion Board. +BAPhysicalControls controls(BA_EXPAND_NUM_SW, BA_EXPAND_NUM_POT, BA_EXPAND_NUM_ENC, BA_EXPAND_NUM_LED); + +void configPhysicalControls(BAPhysicalControls &controls, BAAudioControlWM8731 &codec); +void checkPot(unsigned id); +void checkSwitch(unsigned id); +bool spiTest(BASpiMemoryDMA *mem); // returns true if passed +bool uartTest(); // returns true if passed + +void setup() { + Serial.begin(57600); + + spiMem0.begin(); + spiMem1.begin(); + + // Disable the audio codec first + codec.disable(); + delay(100); + AudioMemory(128); + codec.enable(); + codec.setHeadphoneVolume(0.8f); // Set headphone volume + configPhysicalControls(controls, codec); + + // Run the initial Midi connectivity and SPI memory tests. + if (uartTest()) { Serial.println("MIDI Ports testing PASSED!"); } + if (spiTest(&spiMem0)) { Serial.println("SPI0 testing PASSED!");} + if (spiTest(&spiMem1)) { Serial.println("SPI1 testing PASSED!");} +} + +void loop() { + // put your main code here, to run repeatedly: + checkPot(0); + checkPot(1); + checkPot(2); + checkSwitch(0); + checkSwitch(1); + + delay(10); +} diff --git a/examples/Tests/TGA_PRO_MEM2_EXP/UartTest.cpp b/examples/Tests/TGA_PRO_MEM2_EXP/UartTest.cpp new file mode 100644 index 0000000..0fb866b --- /dev/null +++ b/examples/Tests/TGA_PRO_MEM2_EXP/UartTest.cpp @@ -0,0 +1,86 @@ +#include "BAHardware.h" +#include "BASpiMemory.h" + +using namespace BALibrary; + +constexpr unsigned LOW_RATE = 2400; +constexpr unsigned MIDI_RATE = 31250; +constexpr unsigned HIGH_RATE = 250000; +constexpr unsigned TEST_TIME = 5; // 5 second test each + +static unsigned baudRate = LOW_RATE; // start with low speed +static uint8_t writeData = 0; +static unsigned loopCounter = 0; +static unsigned errorCount = 0; +static bool testFailed = false; +static bool testDone = false; +static unsigned testPhase = 0; // 0 for low speed, 1 for MIDI speed, 2 for high speed. + +bool uartTest(void) +{ + Serial1.begin(baudRate, SERIAL_8N1); + delay(100); + while(!Serial) {} + Serial.println(String("\nRunning MIDI Port speed test at ") + baudRate); + + // write the first data + Serial1.write(writeData); + + while(!testFailed && !testDone) { + + if (loopCounter >= (baudRate/4)) { // the divisor determines how long the test runs for + // next test + switch (testPhase) { + case 0 : + baudRate = MIDI_RATE; + break; + case 1 : + baudRate = HIGH_RATE; + break; + case 2 : + testDone = true; + } + + if (errorCount == 0) { Serial.println("TEST PASSED!"); } + else { + Serial.println("MIDI PORT TEST FAILED!"); + } + errorCount = 0; + testPhase++; + loopCounter = 0; + + if (!testDone) { + Serial.println(String("\nRunning MIDI Port speed test at ") + baudRate); + Serial1.begin(baudRate, SERIAL_8N1); + while (!Serial1) {} // wait for serial to be ready + } else { + Serial.println("MIDI PORT TEST DONE!\n"); + } + } + + // Wait for read data + if (Serial1.available()) { + uint8_t readData= Serial1.read(); + if (readData != writeData) { + Serial.println(String("ERROR: readData = ") + readData + String(" writeData = ") + writeData); + errorCount++; + } + + if ((loopCounter % (baudRate/64)) == 0) { // the divisor determines how often the period is printed + Serial.print("."); Serial.flush(); + } + + if (errorCount > 16) { + Serial.println("Halting test"); + testFailed = true; + } + + loopCounter++; + writeData++; + Serial1.write(writeData); + } + } + + return testFailed; +} + diff --git a/examples/Tests/TGA_PRO_MEM2_EXP/spiTest.cpp b/examples/Tests/TGA_PRO_MEM2_EXP/spiTest.cpp new file mode 100644 index 0000000..fce9b22 --- /dev/null +++ b/examples/Tests/TGA_PRO_MEM2_EXP/spiTest.cpp @@ -0,0 +1,125 @@ +#include +#include +#include "BAHardware.h" +#include "BASpiMemory.h" + +constexpr int NUM_TESTS = 12; +constexpr int NUM_BLOCK_WORDS = 128; +constexpr int mask0 = 0x5555; +constexpr int mask1 = 0xaaaa; + +//#define SANITY_CHECK + +using namespace BALibrary; + +int calcData(int spiAddress, int loopPhase, int maskPhase) +{ + int data; + + int phase = ((loopPhase << 1) + maskPhase) & 0x3; + switch(phase) + { + case 0 : + data = spiAddress ^ mask0; + break; + case 1: + data = spiAddress ^ mask1; + break; + case 2: + data = ~spiAddress ^ mask0; + break; + case 3: + data = ~spiAddress ^ mask1; + + } + return (data & 0xffff); +} + +bool spiTest(BASpiMemoryDMA *mem) +{ + int spiAddress = 0; + int spiErrorCount = 0; + + int maskPhase = 0; + int loopPhase = 0; + uint16_t memBlock[NUM_BLOCK_WORDS]; + uint16_t goldData[NUM_BLOCK_WORDS]; + + Serial.println("Starting SPI MEM Test"); + + for (int cnt = 0; cnt < NUM_TESTS; cnt++) { + + // Zero check + mem->zero16(0, SPI_MEM0_SIZE_BYTES / sizeof(uint16_t)); + while (mem->isWriteBusy()) {} + + for (spiAddress = 0; spiAddress <= SPI_MAX_ADDR; spiAddress += NUM_BLOCK_WORDS*sizeof(uint16_t)) { + mem->read16(spiAddress, memBlock, NUM_BLOCK_WORDS); + while (mem->isReadBusy()) {} + for (int i=0; i= 10) break; + } + } + if (spiErrorCount >= 10) break; + } + + //if (spiErrorCount == 0) { Serial.println(String("SPI MEMORY(") + cnt + String("): Zero test PASSED!")); } + if (spiErrorCount == 0) { Serial.print("."); Serial.flush(); } + if (spiErrorCount > 0) { Serial.println(String("SPI MEMORY(") + cnt + String("): Zero test FAILED, error count = ") + spiErrorCount); return false;} + + + // Write all test data to the memory + maskPhase = 0; + for (spiAddress = 0; spiAddress <= SPI_MAX_ADDR; spiAddress += NUM_BLOCK_WORDS*sizeof(uint16_t)) { + // Calculate the data for a block + for (int i=0; iwrite16(spiAddress, memBlock, NUM_BLOCK_WORDS); + while (mem->isWriteBusy()) {} + } + + // Read back the test data + spiErrorCount = 0; + spiAddress = 0; + maskPhase = 0; + + for (spiAddress = 0; spiAddress <= SPI_MAX_ADDR; spiAddress += NUM_BLOCK_WORDS*sizeof(uint16_t)) { + + mem->read16(spiAddress, memBlock, NUM_BLOCK_WORDS); + // Calculate the golden data for a block + for (int i=0; iisReadBusy()) {} // wait for the read to finish + + for (int i=0; i= 10) break; + } + + //if (spiErrorCount == 0) { Serial.println(String("SPI MEMORY(") + cnt + String("): Data test PASSED!")); } + if (spiErrorCount == 0) { Serial.print("."); Serial.flush(); } + if (spiErrorCount > 0) { Serial.println(String("SPI MEMORY(") + cnt + String("): Data test FAILED, error count = ") + spiErrorCount); return false;} + + loopPhase = (loopPhase+1) % 2; + } + return true; +} + diff --git a/src/BAPhysicalControls.h b/src/BAPhysicalControls.h index c436958..c8cac3c 100644 --- a/src/BAPhysicalControls.h +++ b/src/BAPhysicalControls.h @@ -24,7 +24,7 @@ #include #include -#include +#include namespace BALibrary { @@ -52,6 +52,27 @@ private: int m_val = 0; ///< store the value to support toggling }; +/// Convenience class for handling digital inputs. This wraps Bounce with the abilty +/// to invert the polarity of the pin. +class DigitalInput : public Bounce { +public: + /// Create an input where digital low is return true. Most switches ground when pressed. + DigitalInput() : m_isPolarityInverted(true) {} + /// Create an input and specify if input polarity is inverted. + /// @param isPolarityInverted when false, a high voltage on the pin returns true, 0V returns false. + DigitalInput(bool isPolarityInverted) : m_isPolarityInverted(isPolarityInverted) {} + /// Read the state of the pin according to the polarity + /// @returns true when the input should be interpreted as the switch is closed, else false. + bool read() { return Bounce::read() != m_isPolarityInverted; } // logical XOR to conditionally invert polarity + + /// Set whether the input pin polarity + /// @param polarity when true, a low voltage on the pin is considered true by read(), else false. + void setPolarityInverted(bool polarity) { m_isPolarityInverted = polarity; } + +private: + bool m_isPolarityInverted; +}; + /// Convenience class for handling an analog pot as a control. When calibrated, /// returns a float between 0.0 and 1.0. class Potentiometer { @@ -238,7 +259,7 @@ public: private: std::vector m_pots; ///< a vector of all added pots std::vector m_encoders; ///< a vector of all added encoders - std::vector m_switches; ///< a vector of all added switches + std::vector m_switches; ///< a vector of all added switches std::vector m_outputs; ///< a vector of all added outputs }; diff --git a/src/peripherals/BAPhysicalControls.cpp b/src/peripherals/BAPhysicalControls.cpp index c9f2eb2..4b45874 100644 --- a/src/peripherals/BAPhysicalControls.cpp +++ b/src/peripherals/BAPhysicalControls.cpp @@ -57,7 +57,10 @@ 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(pin, intervalMilliseconds);' + m_switches.emplace_back(); + m_switches.back().attach(pin); + m_switches.back().interval(10); pinMode(pin, INPUT); return m_switches.size()-1; } @@ -87,7 +90,7 @@ void BAPhysicalControls::setOutput(unsigned handle, int val) { void BAPhysicalControls::setOutput(unsigned handle, bool val) { if (handle >= m_outputs.size()) { return; } - unsigned value = val ? true : false; + unsigned value = val ? 1 : 0; m_outputs[handle].set(value); } @@ -116,7 +119,7 @@ bool BAPhysicalControls::checkPotValue(unsigned handle, float &value) { bool BAPhysicalControls::isSwitchToggled(unsigned handle) { if (handle >= m_switches.size()) { return 0; } // handle is greater than number of switches - Bounce &sw = m_switches[handle]; + DigitalInput &sw = m_switches[handle]; if (sw.update() && sw.fallingEdge()) { return true; @@ -128,8 +131,9 @@ bool BAPhysicalControls::isSwitchToggled(unsigned handle) { bool BAPhysicalControls::isSwitchHeld(unsigned handle) { if (handle >= m_switches.size()) { return 0; } // handle is greater than number of switches - Bounce &sw = m_switches[handle]; + DigitalInput &sw = m_switches[handle]; + sw.update(); if (sw.read()) { return true; } else { @@ -140,7 +144,7 @@ bool BAPhysicalControls::isSwitchHeld(unsigned handle) int BAPhysicalControls::getSwitchValue(unsigned handle) { if (handle >= m_switches.size()) { return 0; } // handle is greater than number of switches - Bounce &sw = m_switches[handle]; + DigitalInput &sw = m_switches[handle]; return sw.read(); }