diff --git a/bios.cpp b/bios.cpp index 89a7683..d3dbdab 100644 --- a/bios.cpp +++ b/bios.cpp @@ -8,7 +8,6 @@ #include "cpu.h" #ifdef TEENSYDUINO -#include #include #include "teensy-paddles.h" extern Bounce resetButtonDebouncer; @@ -303,7 +302,7 @@ uint8_t BIOS::GetAction(int8_t selection) #endif ) { #ifdef TEENSYDUINO - threads.delay(10); + delay(10); #else usleep(100); #endif @@ -315,7 +314,7 @@ uint8_t BIOS::GetAction(int8_t selection) // wait until it's no longer pressed while (resetButtonDebouncer.read() == HIGH) ; - threads.delay(100); // wait long enough for it to debounce + delay(100); // wait long enough for it to debounce // then return an exit code return ACT_EXIT; } diff --git a/globals.h b/globals.h index d340f73..e995cc2 100644 --- a/globals.h +++ b/globals.h @@ -55,9 +55,4 @@ extern bool g_invertPaddleY; extern char debugBuf[255]; -#ifdef TEENSYDUINO -#include -extern Threads::Mutex spi_lock; -#endif - #endif diff --git a/teensy/fscompat.h b/teensy/fscompat.h index 9b944f5..0fc0830 100644 --- a/teensy/fscompat.h +++ b/teensy/fscompat.h @@ -9,7 +9,6 @@ #include "globals.h" #include -#include #define open(path, flags, perms) g_filemanager->openFile(path) #define close(filedes) g_filemanager->closeFile(filedes) @@ -17,9 +16,8 @@ #define read(filedes,buf,nbyte) g_filemanager->read(filedes,buf,nbyte) #define lseek(filedes,offset,whence) g_filemanager->lseek(filedes,offset,whence) -Threads::Mutex serlock; static char fsbuf[200]; -#define printf(x, ...) {sprintf(fsbuf, x, ##__VA_ARGS__); serlock.lock(); Serial.println(fsbuf); Serial.flush(); Serial.send_now(); serlock.unlock();} -#define fprintf(f, x, ...) {sprintf(fsbuf, x, ##__VA_ARGS__); serlock.lock(); Serial.println(fsbuf); Serial.flush(); Serial.send_now(); serlock.lock();} -#define perror(x) {serlock.lock();Serial.println(x);Serial.flush(); Serial.send_now(); serlock.unlock();} +#define printf(x, ...) {sprintf(fsbuf, x, ##__VA_ARGS__); Serial.println(fsbuf); Serial.flush(); Serial.send_now();} +#define fprintf(f, x, ...) {sprintf(fsbuf, x, ##__VA_ARGS__); Serial.println(fsbuf); Serial.flush(); Serial.send_now();} +#define perror(x) {Serial.println(x);Serial.flush(); Serial.send_now();} diff --git a/teensy/teensy-filemanager.cpp b/teensy/teensy-filemanager.cpp index 8871bed..405c599 100644 --- a/teensy/teensy-filemanager.cpp +++ b/teensy/teensy-filemanager.cpp @@ -2,11 +2,8 @@ #include #include "teensy-filemanager.h" #include // strcpy -#include #include "teensy-println.h" -Threads::Mutex fslock; - TeensyFileManager::TeensyFileManager() { numCached = 0; @@ -23,8 +20,6 @@ TeensyFileManager::~TeensyFileManager() int8_t TeensyFileManager::openFile(const char *name) { - Threads::Scope locker(fslock); - if (cacheFd != -1) { cacheFile.close(); cacheFd = -1; @@ -56,7 +51,6 @@ int8_t TeensyFileManager::openFile(const char *name) void TeensyFileManager::closeFile(int8_t fd) { - Threads::Scope locker(fslock); if (cacheFd != -1) { cacheFile.close(); cacheFd = -1; @@ -92,8 +86,6 @@ void TeensyFileManager::closeDir() // suffix may be comma-separated int16_t TeensyFileManager::readDir(const char *where, const char *suffix, char *outputFN, int16_t startIdx, uint16_t maxlen) { - Threads::Scope locker(fslock); - // First entry is always "../" if we're in a subdir of the root if (startIdx == 0 || !outerDir) { if (outerDir) @@ -220,7 +212,6 @@ void TeensyFileManager::seekToEnd(int8_t fd) int TeensyFileManager::write(int8_t fd, const void *buf, int nbyte) { - Threads::Scope locker(fslock); // open, seek, write, close. if (fd < 0 || fd >= numCached) { return -1; @@ -249,7 +240,6 @@ int TeensyFileManager::write(int8_t fd, const void *buf, int nbyte) int TeensyFileManager::read(int8_t fd, void *buf, int nbyte) { - Threads::Scope locker(fslock); // open, seek, read, close. if (fd < 0 || fd >= numCached) { return -1; @@ -276,7 +266,6 @@ int TeensyFileManager::read(int8_t fd, void *buf, int nbyte) int TeensyFileManager::lseek(int8_t fd, int offset, int whence) { - Threads::Scope locker(fslock); if (whence == SEEK_CUR && offset == 0) { return fileSeekPositions[fd]; } diff --git a/teensy/teensy-println.cpp b/teensy/teensy-println.cpp index a073ce4..8c0b368 100644 --- a/teensy/teensy-println.cpp +++ b/teensy/teensy-println.cpp @@ -3,12 +3,12 @@ namespace arduino_preprocessor_is_buggy { bool serialavailable() { - Threads::Scope locker(getSerialLock()); + // Threads::Scope locker(getSerialLock()); return Serial.available(); } char serialgetch() { - Threads::Scope locker(getSerialLock()); + // Threads::Scope locker(getSerialLock()); return Serial.read(); } diff --git a/teensy/teensy-println.h b/teensy/teensy-println.h index 3e8cdf8..3ccca27 100644 --- a/teensy/teensy-println.h +++ b/teensy/teensy-println.h @@ -1,6 +1,5 @@ #include #include -#include // cf. https://forum.pjrc.com/threads/41504-Teensy-3-x-multithreading-library-first-release/page6 @@ -12,10 +11,12 @@ namespace arduino_preprocessor_is_buggy { // used for suppressing compiler warnings template void silence(T&&) {}; + /* inline Threads::Mutex& getSerialLock() { static Threads::Mutex serial_lock; return serial_lock; } + */ bool serialavailable(); char serialgetch(); @@ -29,12 +30,12 @@ namespace arduino_preprocessor_is_buggy { } template void print(args_t... params) { - Threads::Scope locker(getSerialLock()); + // Threads::Scope locker(getSerialLock()); silence(expand{ (print_fwd(params), 42)... }); } template void println(args_t... params) { - Threads::Scope locker(getSerialLock()); + // Threads::Scope locker(getSerialLock()); silence(expand{ (print_fwd(params), 42)... }); Serial.println(); Serial.flush(); diff --git a/teensy/teensy-speaker.cpp b/teensy/teensy-speaker.cpp index 8380697..c66a4ec 100644 --- a/teensy/teensy-speaker.cpp +++ b/teensy/teensy-speaker.cpp @@ -1,28 +1,49 @@ #include -#include #include "teensy-speaker.h" #include "teensy-println.h" -#include +#include +#include + +TeensyAudio audioDriver; +//AudioMixer4 mixer2; //xy=280,253 +AudioMixer4 mixer1; //xy=280,175 +AudioOutputI2S i2s; //xy=452,189 + +AudioConnection patchCord1(audioDriver, 0, mixer1, 0); +//AudioConnection patchCord2(audioDriver, 0, mixer2, 0); +//AudioConnection patchCord3(mixer2, 0, i2s, 1); +AudioConnection patchCord4(mixer1, 0, i2s, 0); +//const float t_ampx = 0.8; +//const int t_lox = 10; +//const int t_hix = 22000; +//const float t_timex = 10; // Length of time for the sweep in seconds #include "globals.h" -I2CDevice dac = I2CDevice(Master, 0x60, _BIG_ENDIAN); +//#define BUFSIZE 4096 +//EXTMEM uint32_t toggleBuffer[BUFSIZE]; // cycle counts at which state toggles +//uint16_t headptr, tailptr; -Threads::Mutex togmutex; -#define BUFSIZE 4096 -EXTMEM uint32_t toggleBuffer[BUFSIZE]; // cycle counts at which state toggles -uint16_t headptr, tailptr; -uint32_t lastCycleCount, toggleAtCycle; +// Ring buffer that we fill with 44.1kHz data +#define RINGBUFSIZE 4096 +EXTMEM short sampleRingBuffer[RINGBUFSIZE]; +volatile uint16_t sampleHeadPtr = 0; +volatile uint16_t sampleTailPtr = 0; +volatile uint32_t lastFilledTime = 0; + +volatile uint32_t lastSampleNum = 0; + +bool toggleState = false; // How many cycles do we run the audio behind? Needs to be more than our bulk // cycle count. -#define CYCLEDELAY 100 +//#define CYCLEDELAY 100 TeensySpeaker::TeensySpeaker(uint8_t sda, uint8_t scl) : PhysicalSpeaker() { toggleState = false; mixerValue = numMixed = 0; - Master.begin(1000000); // 100000 or 400000 or 1000000 + AudioMemory(8); } TeensySpeaker::~TeensySpeaker() @@ -31,18 +52,40 @@ TeensySpeaker::~TeensySpeaker() void TeensySpeaker::begin() { - lastCycleCount = g_cpu->cycles; + mixer1.gain(0, 0.5f); // left channel + + lastFilledTime = g_cpu->cycles; + sampleHeadPtr = sampleTailPtr = 0; toggleState = false; - memset(toggleBuffer, 0, sizeof(toggleBuffer)); - headptr = tailptr = 0; + // memset(toggleBuffer, 0, sizeof(toggleBuffer)); + // headptr = tailptr = 0; + lastSampleNum = 0; } void TeensySpeaker::toggle(uint32_t c) { - Threads::Scope lock(togmutex); - // Queue the speaker toggle time; maintainSpeaker will pick it up - toggleBuffer[tailptr++] = c; tailptr %= BUFSIZE; - + // Figure out when the last time was that we put data in the audio buffer; + // then figure out how many audio buffer cycles we have to fill from that + // CPU time to this one. +#if 1 + __disable_irq(); + + // We expect to have filled to this cycle number... + uint32_t expectedCycleNumber = (float)c * (float)AUDIO_SAMPLE_RATE_EXACT / (float)g_speed; + + // and we have filled to cycle number lastFilledTime. So how many do we need? + uint32_t audioBufferSamples = expectedCycleNumber - lastFilledTime; + + if (audioBufferSamples > RINGBUFSIZE) + audioBufferSamples = RINGBUFSIZE; + for (int i=0; icycles - CYCLEDELAY; - // And then find any events that should have happened, accounting for them: - togmutex.lock(); while (headptr != tailptr) { if (curTime >= toggleBuffer[headptr]) { toggleState = !toggleState; @@ -80,11 +111,7 @@ void TeensySpeaker::maintainSpeaker() break; } } - togmutex.unlock(); - - // Now we can safely update the DAC based on the current toggleState - uint16_t v = (toggleState ? 0xFFF : 0x000); - // dac.write((uint8_t) ((v >> 8) & 0xFF), (uint8_t) (v & 0xFF), true); +#endif } void TeensySpeaker::beginMixing() @@ -97,3 +124,54 @@ void TeensySpeaker::mixOutput(uint8_t v) // unused } +void TeensyAudio::update(void) +{ + audio_block_t *block; + short *bp; + + // Grab a block and we'll fill it up. It needs AUDIO_BLOCK_SAMPLES short values + // (which is 128 on the Teensy 4). + block = allocate(); + if (block) { + bp = block->data; +#if 1 + uint32_t underflow = 0; + for (int i=0; icycles; + } else { + lastFilledTime = 0; + } + // FIXME: + // lastSampleNum = 0; + } +#endif +} diff --git a/teensy/teensy-speaker.h b/teensy/teensy-speaker.h index ef0ad86..a7a98e7 100644 --- a/teensy/teensy-speaker.h +++ b/teensy/teensy-speaker.h @@ -1,11 +1,19 @@ #ifndef __TEENSY_SPEAKER_H #define __TEENSY_SPEAKER_H +#include #include "physicalspeaker.h" #include #define SAMPLERATE 44100 +class TeensyAudio : public AudioStream { + public: + TeensyAudio(void) : AudioStream(0, NULL) {} + + virtual void update(void); +}; + class TeensySpeaker : public PhysicalSpeaker { public: TeensySpeaker(uint8_t sda, uint8_t scl); @@ -21,7 +29,7 @@ class TeensySpeaker : public PhysicalSpeaker { virtual void mixOutput(uint8_t v); private: - bool toggleState; + // bool toggleState; uint32_t mixerValue; uint8_t numMixed; diff --git a/teensy/teensy.ino b/teensy/teensy.ino index b477090..9490792 100644 --- a/teensy/teensy.ino +++ b/teensy/teensy.ino @@ -1,7 +1,7 @@ #include +#include #include #include -#include #include #include "bios.h" #include "cpu.h" @@ -16,7 +16,7 @@ #include "teensy-prefs.h" #include "teensy-println.h" -#define DEBUG_TIMING +//#define DEBUG_TIMING #define THREADED if (1) @@ -69,7 +69,7 @@ void onKeyrelease(int unicode) void setup() { Serial.begin(230400); -#if 0 +#if 1 // Wait for USB serial connection before booting while debugging while (!Serial) { yield(); @@ -165,9 +165,9 @@ void setup() println("free-running"); Serial.flush(); - threads.setMicroTimer(); // use a 100uS timer instead of a 1mS timer +// threads.setMicroTimer(); // use a 100uS timer instead of a 1mS timer // threads.setSliceMicros(5); - threads.addThread(runDebouncer); +// threads.addThread(runDebouncer); } // FIXME: move these memory-related functions elsewhere... @@ -228,43 +228,13 @@ void biosInterrupt() g_keyboard->maintainKeyboard(); } -void runSpeaker(uint32_t now) -{ - static uint32_t spk_nextResetMicros = 0; - static uint32_t spk_refreshCount = 0; - static uint32_t spk_microsAtStart = micros(); - static uint32_t spk_microsForNext = 0; - - THREADED { - if (now >= spk_microsForNext) { - spk_refreshCount++; - spk_microsForNext = spk_microsAtStart + ((float)1000000.0*((float)spk_refreshCount/(float)SAMPLERATE)); - ((TeensySpeaker *)g_speaker)->maintainSpeaker(); - } - - if (now >= spk_nextResetMicros) { -#ifdef DEBUG_TIMING - float pct = (100.0 * (float)spk_refreshCount) / (float)SAMPLERATE; - sprintf(debugBuf, "Speaker running at %f%% [%lu]", pct, spk_refreshCount); - println(debugBuf); -#endif - - spk_microsAtStart = now; - spk_refreshCount = 0; - spk_nextResetMicros = spk_microsAtStart + 1000000; - spk_microsForNext = spk_microsAtStart + ((float)1000000.0*((float)spk_refreshCount/(float)SAMPLERATE)); - } - - } -} - void runMaintenance(uint32_t now) { static uint32_t nextRuntime = 0; THREADED { if (now >= nextRuntime) { - nextRuntime = now + 100000000; // FIXME: what's a good time here + nextRuntime = now + 100000; // FIXME: what's a good time here? 1/10 sec? if (!resetButtonDebouncer.read()) { // This is the BIOS interrupt. We immediately act on it. @@ -334,7 +304,8 @@ void runDebouncer() nextRuntime = millis() + 10; resetButtonDebouncer.update(); } else { - threads.yield(); + yield(); +// threads.yield(); } } } @@ -373,7 +344,6 @@ void loop() uint32_t now = micros(); runCPU(now); runDisplay(now); - runSpeaker(now); runMaintenance(now); }