Skip to content

Instantly share code, notes, and snippets.

@newdigate
Created April 5, 2021 11:44
Show Gist options
  • Save newdigate/109280f4f67463b5226b3c9afb4f0882 to your computer and use it in GitHub Desktop.
Save newdigate/109280f4f67463b5226b3c9afb4f0882 to your computer and use it in GitHub Desktop.
#include <Audio.h>
#include <ST7735_t3.h> // Hardware-specific library
#include <ResponsiveAnalogRead.h>
#include "teensy_eurorack.h"
#include "output_spi.h"
#include "ScopeView.h"
ST7735_t3 TFT = ST7735_t3(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
// GUItool: begin automatically generated code
AudioInputTDM tdm; //xy=210.11108779907227,555.4443893432617
AudioOutputSPI ad7606; //xy=253.8888282775879,242.22220611572266
AudioRecordQueue audioRecordQueue9; //xy=551.6665954589844,622.2221488952637
AudioRecordQueue audioRecordQueue7; //xy=553.8888320922852,354.444393157959
AudioRecordQueue audioRecordQueue10; //xy=553.888916015625,655.5554962158203
AudioRecordQueue audioRecordQueue11; //xy=553.8889541625977,688.8888387680054
AudioRecordQueue audioRecordQueue8; //xy=556.1110382080078,391.11108016967773
AudioRecordQueue audioRecordQueue12; //xy=555.0000762939453,722.2222347259521
AudioRecordQueue audioRecordQueue13; //xy=554.9999313354492,756.6666603088379
AudioRecordQueue audioRecordQueue14; //xy=554.9999313354492,792.2221641540527
AudioRecordQueue audioRecordQueue6; //xy=557.2220993041992,308.8888530731201
AudioRecordQueue audioRecordQueue5; //xy=564.9999771118164,256.66662406921387
AudioRecordQueue audioRecordQueue3; //xy=567.2221984863281,176.6666259765625
AudioRecordQueue audioRecordQueue4; //xy=569.4443359375,217.77774238586426
AudioRecordQueue audioRecordQueue1; //xy=570.5554885864258,97.77776336669922
AudioRecordQueue audioRecordQueue2; //xy=572.7776794433594,134.4444284439087
AudioSynthWaveformSine sine10; //xy=751.1111102634006,491.11109627617725
AudioSynthWaveformSine sine13; //xy=753.3333324856228,603.3333184983995
AudioSynthWaveformSine sine15; //xy=753.3333625793457,683.3333053588867
AudioSynthWaveformSine sine16; //xy=753.3333587646484,722.2221755981445
AudioSynthWaveformSine sine12; //xy=754.4444435967339,559.9999851650662
AudioSynthWaveformSine sine9; //xy=757.7777769300673,453.33331849839954
AudioSynthWaveformSine sine14; //xy=757.7777862548828,644.4443759918213
AudioSynthWaveformSine sine11; //xy=758.8888880411783,525.5555407206217
AudioSynthWaveformSine sine1; //xy=766.9999732971191,97.77776336669922
AudioSynthWaveformSine sine2; //xy=766.999927520752,133.3333683013916
AudioSynthWaveformSine sine8; //xy=769.2221870422363,356.66664123535156
AudioSynthWaveformSine sine3; //xy=770.3332901000977,172.22220039367676
AudioSynthWaveformSine sine5; //xy=770.3332672119141,248.88892650604248
AudioSynthWaveformSine sine6; //xy=770.3332710266113,284.4444122314453
AudioSynthWaveformSine sine7; //xy=770.3332138061523,318.8888273239136
AudioSynthWaveformSine sine4; //xy=772.5555877685547,210.00000286102295
AudioSynthWaveformDc dc1; //xy=226,901
AudioSynthWaveformDc dc2; //xy=226,946
AudioSynthWaveformDc dc3; //xy=227,995
AudioSynthWaveformDc dc4; //xy=229,1039
AudioRecordQueue queue4; //xy=534,1040
AudioRecordQueue queue1; //xy=550,902
AudioRecordQueue queue2; //xy=551,945
AudioRecordQueue queue3; //xy=560,989
AudioOutputTDM tdm2; //xy=1037.8889694213867,542.1110763549805
AudioConnection patchCord1(tdm, 0, audioRecordQueue9, 0);
AudioConnection patchCord2(tdm, 2, audioRecordQueue10, 0);
AudioConnection patchCord3(tdm, 4, audioRecordQueue11, 0);
AudioConnection patchCord4(tdm, 6, audioRecordQueue12, 0);
AudioConnection patchCord5(tdm, 8, audioRecordQueue13, 0);
AudioConnection patchCord6(tdm, 10, audioRecordQueue14, 0);
AudioConnection patchCord7(ad7606, 0, audioRecordQueue1, 0);
AudioConnection patchCord8(ad7606, 1, audioRecordQueue2, 0);
AudioConnection patchCord9(ad7606, 2, audioRecordQueue3, 0);
AudioConnection patchCord10(ad7606, 3, audioRecordQueue4, 0);
AudioConnection patchCord11(ad7606, 4, audioRecordQueue5, 0);
AudioConnection patchCord12(ad7606, 5, audioRecordQueue6, 0);
AudioConnection patchCord13(ad7606, 6, audioRecordQueue7, 0);
AudioConnection patchCord14(ad7606, 7, audioRecordQueue8, 0);
AudioConnection patchCord15(sine10, 0, tdm2, 2);
AudioConnection patchCord16(sine13, 0, tdm2, 8);
AudioConnection patchCord17(sine15, 0, tdm2, 12);
AudioConnection patchCord18(sine16, 0, tdm2, 14);
AudioConnection patchCord19(sine12, 0, tdm2, 6);
AudioConnection patchCord20(sine9, 0, tdm2, 0);
AudioConnection patchCord21(sine14, 0, tdm2, 10);
AudioConnection patchCord22(sine11, 0, tdm2, 4);
AudioConnection patchCord23(sine1, 0, ad7606, 0);
AudioConnection patchCord24(sine2, 0, ad7606, 1);
AudioConnection patchCord25(sine8, 0, ad7606, 7);
AudioConnection patchCord26(sine3, 0, ad7606, 2);
AudioConnection patchCord27(sine5, 0, ad7606, 4);
AudioConnection patchCord28(sine6, 0, ad7606, 5);
AudioConnection patchCord29(sine7, 0, ad7606, 6);
AudioConnection patchCord30(sine4, 0, ad7606, 3);
AudioConnection patchCord31(dc1, queue1);
AudioConnection patchCord32(dc2, queue2);
AudioConnection patchCord33(dc3, queue3);
AudioConnection patchCord34(dc4, queue4);
AudioControlCS42448 cs42448_1; //xy=553.4443435668945,831.111083984375
// GUItool: end automatically generated code
uint16_t colors[8] = {ST7735_GREEN,ST7735_RED,ST7735_BLUE,ST7735_CYAN,ST7735_MAGENTA,ST7735_YELLOW,0xFFAA,ST7735_WHITE};
ScopeView scopeViewCV1 = ScopeView(TFT, audioRecordQueue1, colors[0], (int16_t)ST7735_BLACK, 64);
ScopeView scopeViewCV2 = ScopeView(TFT, audioRecordQueue2, colors[1], (int16_t)ST7735_BLACK, 64);
ScopeView scopeViewCV3 = ScopeView(TFT, audioRecordQueue3, colors[2], (int16_t)ST7735_BLACK, 64);
ScopeView scopeViewCV4 = ScopeView(TFT, audioRecordQueue4, colors[3], (int16_t)ST7735_BLACK, 64);
ScopeView scopeViewCV5 = ScopeView(TFT, audioRecordQueue5, colors[4], (int16_t)ST7735_BLACK, 64);
ScopeView scopeViewCV6 = ScopeView(TFT, audioRecordQueue6, colors[5], (int16_t)ST7735_BLACK, 64);
ScopeView scopeViewCV7 = ScopeView(TFT, audioRecordQueue7, colors[6], (int16_t)ST7735_BLACK, 64);
ScopeView scopeViewCV8 = ScopeView(TFT, audioRecordQueue8, colors[7], (int16_t)ST7735_BLACK, 64);
ScopeView scopeViewAudio1 = ScopeView(TFT, audioRecordQueue9, colors[0], (int16_t)ST7735_BLACK, 64);
ScopeView scopeViewAudio2 = ScopeView(TFT, audioRecordQueue10, colors[1], (int16_t)ST7735_BLACK, 64);
ScopeView scopeViewAudio3 = ScopeView(TFT, audioRecordQueue11, colors[2], (int16_t)ST7735_BLACK, 64);
ScopeView scopeViewAudio4 = ScopeView(TFT, audioRecordQueue12, colors[3], (int16_t)ST7735_BLACK, 64);
ScopeView scopeViewAudio5 = ScopeView(TFT, audioRecordQueue13, colors[4], (int16_t)ST7735_BLACK, 64);
ScopeView scopeViewAudio6 = ScopeView(TFT, audioRecordQueue14, colors[5], (int16_t)ST7735_BLACK, 64);
ScopeView scopeViewPot1 = ScopeView(TFT, queue1, colors[2], (int16_t)ST7735_BLACK, 64);
ScopeView scopeViewPot2 = ScopeView(TFT, queue2, colors[3], (int16_t)ST7735_BLACK, 64);
ScopeView scopeViewPot3 = ScopeView(TFT, queue3, colors[4], (int16_t)ST7735_BLACK, 64);
ScopeView scopeViewPot4 = ScopeView(TFT, queue4, colors[5], (int16_t)ST7735_BLACK, 64);
ResponsiveAnalogRead analogPot1(TEENSY_EURORACK_PIN_POT1, true, 1.0);
ResponsiveAnalogRead analogPot2(TEENSY_EURORACK_PIN_POT2, true, 1.0);
ResponsiveAnalogRead analogPot3(TEENSY_EURORACK_PIN_POT3, true, 1.0);
ResponsiveAnalogRead analogPot4(TEENSY_EURORACK_PIN_POT4, true, 1.0);
unsigned long start_time;
void setup() {
pinMode(TEENSY_EURORACK_PIN_POT1, INPUT_DISABLE);
pinMode(TEENSY_EURORACK_PIN_POT2, INPUT_DISABLE);
pinMode(TEENSY_EURORACK_PIN_POT3, INPUT_DISABLE);
pinMode(TEENSY_EURORACK_PIN_POT4, INPUT_DISABLE);
analogReadResolution(12);
analogPot1.enableEdgeSnap();
analogPot1.setAnalogResolution(4096);
analogPot2.enableEdgeSnap();
analogPot2.setAnalogResolution(4096);
analogPot3.enableEdgeSnap();
analogPot3.setAnalogResolution(4096);
analogPot4.enableEdgeSnap();
analogPot4.setAnalogResolution(4096);
Serial.begin(9600);
//while(!Serial) {
// delay(1);
//}
AudioNoInterrupts();
AudioMemory(160);
cs42448_1.enable();
cs42448_1.volume(1);
AudioInterrupts(); // enable, both tones will start together
TFT.initR(INITR_144GREENTAB);
TFT.setRotation(3);
TFT.fillScreen(ST7735_BLACK);
TFT.useFrameBuffer(true);
TFT.updateScreenAsync(true);
//noInterrupts();
sine8.frequency(1000);
sine8.amplitude(0.7);
sine7.frequency(AUDIO_SAMPLE_RATE_EXACT/128.0);
sine7.amplitude(0.7);
sine6.frequency(AUDIO_SAMPLE_RATE_EXACT*2.0/128.0);
sine6.amplitude(0.7);
sine5.frequency(AUDIO_SAMPLE_RATE_EXACT*0.5/128.0);
sine5.amplitude(0.7);
sine4.frequency(AUDIO_SAMPLE_RATE_EXACT*4.0/128.0);
sine4.amplitude(0.7);
sine3.frequency(AUDIO_SAMPLE_RATE_EXACT*8.0/128.0);
sine3.amplitude(0.7);
sine2.frequency(AUDIO_SAMPLE_RATE_EXACT*0.25/128.0);
sine2.amplitude(0.7);
sine1.frequency(AUDIO_SAMPLE_RATE_EXACT*0.125/128.0);
sine1.amplitude(0.7);
sine9.frequency(AUDIO_SAMPLE_RATE_EXACT*12.0/128.0);
sine9.amplitude(0.7);
sine10.frequency(AUDIO_SAMPLE_RATE_EXACT*6.0/128.0);
sine10.amplitude(0.7);
sine11.frequency(250);
sine11.amplitude(0.7);
sine12.frequency(100);
sine12.amplitude(0.7);
sine13.frequency(125);
sine13.amplitude(0.7);
sine14.frequency(750);
sine14.amplitude(0.7);
sine15.frequency(4000);
sine15.amplitude(0.7);
sine16.frequency(1500);
sine16.amplitude(0.7);
audioRecordQueue1.begin();
audioRecordQueue2.begin();
audioRecordQueue3.begin();
audioRecordQueue4.begin();
audioRecordQueue5.begin();
audioRecordQueue6.begin();
audioRecordQueue7.begin();
audioRecordQueue8.begin();
audioRecordQueue9.begin();
audioRecordQueue10.begin();
audioRecordQueue11.begin();
audioRecordQueue12.begin();
audioRecordQueue13.begin();
audioRecordQueue14.begin();
queue1.begin();
queue2.begin();
queue3.begin();
queue4.begin();
dc1.amplitude(0.5, 1);
dc1.amplitude(-0.5, 1);
dc1.amplitude(0.25, 1);
dc1.amplitude(-0.25, 1);
//interrupts();
start_time = millis();
}
char timestring[] = " ";
void updateTFTTime(char *oldString, char *newString, bool rerender) {
int c=0;
if (!rerender) {
int len1 = strlen(oldString);
int len2 = strlen(newString);
while(oldString[c] == newString[c] && c < len1 && c < len2 ){
c++;
}
}
TFT.setCursor(c * 6,0);
TFT.setTextColor(ST7735_BLACK);
TFT.print( (char * ) (oldString + c));
TFT.setCursor(c * 6,0);
TFT.setTextColor(ST7735_WHITE);
TFT.print( (char * ) (newString + c));
}
unsigned count = 0, count2 = 0;
void loop() {
if (count % 20 == 0) {
scopeViewCV1.checkForUpdateBuffer();
scopeViewCV2.checkForUpdateBuffer();
scopeViewCV3.checkForUpdateBuffer();
scopeViewCV4.checkForUpdateBuffer();
scopeViewCV5.checkForUpdateBuffer();
scopeViewCV6.checkForUpdateBuffer();
scopeViewCV7.checkForUpdateBuffer();
scopeViewCV8.checkForUpdateBuffer();
scopeViewAudio1.checkForUpdateBuffer();
scopeViewAudio2.checkForUpdateBuffer();
scopeViewAudio3.checkForUpdateBuffer();
scopeViewAudio4.checkForUpdateBuffer();
scopeViewAudio5.checkForUpdateBuffer();
scopeViewAudio6.checkForUpdateBuffer();
scopeViewPot1.checkForUpdateBuffer();
scopeViewPot2.checkForUpdateBuffer();
scopeViewPot3.checkForUpdateBuffer();
scopeViewPot4.checkForUpdateBuffer();
scopeViewCV1.undrawScope();
scopeViewCV2.undrawScope();
scopeViewCV3.undrawScope();
scopeViewCV4.undrawScope();
scopeViewCV5.undrawScope();
scopeViewCV6.undrawScope();
scopeViewCV7.undrawScope();
scopeViewCV8.undrawScope();
scopeViewAudio1.undrawScope();
scopeViewAudio2.undrawScope();
scopeViewAudio3.undrawScope();
scopeViewAudio4.undrawScope();
scopeViewAudio5.undrawScope();
scopeViewAudio6.undrawScope();
scopeViewPot1.undrawScope();
scopeViewPot2.undrawScope();
scopeViewPot3.undrawScope();
scopeViewPot4.undrawScope();
scopeViewCV1.drawScope();
scopeViewCV2.drawScope();
scopeViewCV3.drawScope();
scopeViewCV4.drawScope();
scopeViewCV5.drawScope();
scopeViewCV6.drawScope();
scopeViewCV7.drawScope();
scopeViewCV8.drawScope();
scopeViewAudio1.drawScope();
scopeViewAudio2.drawScope();
scopeViewAudio3.drawScope();
scopeViewAudio4.drawScope();
scopeViewAudio5.drawScope();
scopeViewAudio6.drawScope();
scopeViewPot1.drawScope();
scopeViewPot2.drawScope();
scopeViewPot3.drawScope();
scopeViewPot4.drawScope();
//TFT.updateScreen();
}
if (audioRecordQueue1.available() > 2) {
audioRecordQueue1.end();
while (audioRecordQueue1.available() > 2) {
audioRecordQueue1.readBuffer();
audioRecordQueue1.freeBuffer();
}
audioRecordQueue1.begin();
}
if (audioRecordQueue2.available() > 2) {
audioRecordQueue2.end();
while (audioRecordQueue2.available() > 2) {
audioRecordQueue2.readBuffer();
audioRecordQueue2.freeBuffer();
}
audioRecordQueue2.begin();
}
if (audioRecordQueue3.available() > 2) {
audioRecordQueue3.end();
while (audioRecordQueue3.available() > 2) {
audioRecordQueue3.readBuffer();
audioRecordQueue3.freeBuffer();
}
audioRecordQueue3.begin();
}
if (audioRecordQueue4.available() > 2) {
audioRecordQueue4.end();
while (audioRecordQueue4.available() > 2) {
audioRecordQueue4.readBuffer();
audioRecordQueue4.freeBuffer();
}
audioRecordQueue4.begin();
}
if (audioRecordQueue5.available() > 2) {
audioRecordQueue5.end();
while (audioRecordQueue5.available() > 2) {
audioRecordQueue5.readBuffer();
audioRecordQueue5.freeBuffer();
}
audioRecordQueue5.begin();
}
if (audioRecordQueue6.available() > 2) {
audioRecordQueue6.end();
while (audioRecordQueue6.available() > 2) {
audioRecordQueue6.readBuffer();
audioRecordQueue6.freeBuffer();
}
audioRecordQueue6.begin();
}
if (audioRecordQueue7.available() > 2) {
audioRecordQueue7.end();
while (audioRecordQueue7.available() > 2) {
audioRecordQueue7.readBuffer();
audioRecordQueue7.freeBuffer();
}
audioRecordQueue7.begin();
}
if (audioRecordQueue8.available() > 2) {
audioRecordQueue8.end();
while (audioRecordQueue8.available() > 2) {
audioRecordQueue8.readBuffer();
audioRecordQueue8.freeBuffer();
}
audioRecordQueue8.begin();
}
if (audioRecordQueue9.available() > 2) {
audioRecordQueue9.end();
while (audioRecordQueue9.available() > 2) {
audioRecordQueue9.readBuffer();
audioRecordQueue9.freeBuffer();
}
audioRecordQueue9.begin();
}
if (audioRecordQueue10.available() > 2) {
audioRecordQueue10.end();
while (audioRecordQueue10.available() > 2) {
audioRecordQueue10.readBuffer();
audioRecordQueue10.freeBuffer();
}
audioRecordQueue10.begin();
}
if (audioRecordQueue11.available() > 2) {
audioRecordQueue11.end();
while (audioRecordQueue11.available() > 2) {
audioRecordQueue11.readBuffer();
audioRecordQueue11.freeBuffer();
}
audioRecordQueue11.begin();
}
if (audioRecordQueue12.available() > 2) {
audioRecordQueue12.end();
while (audioRecordQueue12.available() > 2) {
audioRecordQueue12.readBuffer();
audioRecordQueue12.freeBuffer();
}
audioRecordQueue12.begin();
}
if (audioRecordQueue13.available() > 2) {
audioRecordQueue13.end();
while (audioRecordQueue13.available() > 2) {
audioRecordQueue13.readBuffer();
audioRecordQueue13.freeBuffer();
}
audioRecordQueue13.begin();
}
if (audioRecordQueue14.available() > 2) {
audioRecordQueue14.end();
while (audioRecordQueue14.available() > 2) {
audioRecordQueue14.readBuffer();
audioRecordQueue14.freeBuffer();
}
audioRecordQueue14.begin();
}
if (queue1.available() > 2) {
queue1.end();
while (queue1.available() > 2) {
queue1.readBuffer();
queue1.freeBuffer();
}
queue1.begin();
}
if (queue2.available() > 2) {
queue2.end();
while (queue2.available() > 2) {
queue2.readBuffer();
queue2.freeBuffer();
}
queue2.begin();
}
if (queue3.available() > 2) {
queue3.end();
while (queue3.available() > 2) {
queue3.readBuffer();
queue3.freeBuffer();
}
queue3.begin();
}
if (queue4.available() > 2) {
queue4.end();
while (queue4.available() > 2) {
queue4.readBuffer();
queue4.freeBuffer();
}
queue4.begin();
}
if (count % 20000 == 0) {
analogPot1.update();
analogPot2.update();
analogPot3.update();
analogPot4.update();
// if the responsive value has change, print out 'changed'
if(analogPot1.hasChanged()) {
float ff = (analogPot1.getValue()/2048.0) - 1.0f;
dc1.amplitude(ff, 10);
}
if(analogPot2.hasChanged()) {
float ff = (analogPot2.getValue()/2048.0) - 1.0f;
dc2.amplitude(ff, 10);
}
if(analogPot3.hasChanged()) {
float ff = (analogPot3.getValue()/2048.0) - 1.0f;
dc3.amplitude(ff, 10);
}
if(analogPot4.hasChanged()) {
float ff = (analogPot4.getValue()/2048.0) - 1.0f;
dc4.amplitude(ff, 10);
}
}
//delayMicroseconds(100);
count++;
if (count % 10000 == 0) {
unsigned long newmillis = millis() - start_time;
count2++;
unsigned long days = newmillis / (1000 * 60 * 60 * 24);
unsigned long remainer = newmillis - (days * 1000 * 60 * 60 * 24);
unsigned long hours = remainer / (1000 * 60 * 60);
remainer = remainer - (hours * 1000 * 60 * 60);
unsigned long minutes = remainer / (1000 * 60);
remainer = remainer - (minutes * 1000 * 60);
unsigned long seconds = remainer / 1000;
remainer = remainer - (seconds * 1000);
//tft.fillScreen(ST7735_BLACK);
char newtimestring[] = " ";
int n = sprintf(newtimestring, "%2u:%2u:%2u:%2u.%u", days, hours, minutes, seconds, remainer / 100);
bool fullUpdate = count2 % 100 == 0;
if (fullUpdate) {
Serial.print(timestring);
Serial.print(" ");
Serial.print(count2/100);
Serial.print(" all=");
Serial.print(AudioProcessorUsage());
Serial.print(",");
Serial.print(AudioProcessorUsageMax());
Serial.print(" ");
Serial.print("Memory: ");
Serial.print(AudioMemoryUsage());
Serial.print(",");
Serial.print(AudioMemoryUsageMax());
Serial.print(" ");
Serial.print("Free Mem: ");
Serial.print(memfree());
Serial.println();
}
updateTFTTime(timestring, newtimestring, fullUpdate);
memcpy(timestring, newtimestring, strlen(newtimestring) );
}
}
//
// Created by Moolet on 18/03/2021.
//
#include "output_spi.h"
/* Audio Library for Teensy 3.X
* Copyright (c) 2017, Paul Stoffregen, [email protected]
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "SPI.h"
#if !defined(KINETISL)
#include "memcpy_audio.h"
#include "utility/imxrt_hw.h"
#define AD7607_BUSY 3
#define AD7607_START_CONVERSION 5
#define AD7607_CHIP_SELECT 36
#define AD7607_RESET 35
#define AD7607_RANGE_SELECT 37
#define DA_SYNC 38
#define MOSI_PIN 26
#define MISO_PIN 39
#define SCK_PIN 27
#define LRCLK_CPY 40
/* AD5754R Register Map */
#define AD5754R_REG_RANGE_SELECT 0x01 // Output range select register
/* AD5754R Channel Address */
#define AD5754R_DAC_ALL 0x04 // All four DACs
/* AD5754R Range Bits */
#define AD5754R_BIPOLAR_10_RANGE 0x04 // -10...+10(V)
audio_block_t * AudioOutputSPI::block_input[8] = {
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
};
bool AudioOutputSPI::update_responsibility = false;
DMAChannel AudioOutputSPI::dmatx(false);
DMAChannel AudioOutputSPI::dmarx(false);
//DMAMEM
__attribute__((aligned(32)))
uint32_t zeros[AUDIO_BLOCK_SAMPLES/2];
//DMAMEM
__attribute__((aligned(32)))
uint8_t tdm_tx_buffer[32 * 4];
volatile uint16_t AudioOutputSPI::_readIndex = 0;
volatile uint16_t AudioOutputSPI::_writeIndex = 0;
volatile bool AudioOutputSPI::_resetReceived = false;
audio_block_t *AudioOutputSPI::prev[8] = {
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
};
//DMAMEM
__attribute__((aligned(32)))
volatile uint8_t AudioOutputSPI::rxbuf[32] = {0};
audio_block_t * AudioOutputSPI::block_incoming[8] = {
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
};
audio_block_t * AudioOutputSPI::block_write[8] = {
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
};
static const uint32_t zero_level = (0xFFFF / 2)+1;
void setClockDivider_noInline(uint32_t clk)
{
static const uint32_t clk_sel[4] = {
664615384, // PLL3 PFD1
720000000, // PLL3 PFD0
528000000, // PLL2
396000000}; // PLL2 PFD2
uint32_t cbcmr = CCM_CBCMR;
uint32_t clkhz = clk_sel[(cbcmr >> 4) & 0x03] / (((cbcmr >> 26 ) & 0x07 ) + 1); // LPSPI peripheral clock
uint32_t d, div;
d = clk ? clkhz/clk : clkhz;
if (d && clkhz/d > clk) d++;
if (d > 257) d= 257; // max div
if (d > 2) {
div = d-2;
} else {
div =0;
}
uint32_t ccr = LPSPI_CCR_SCKDIV(div) | LPSPI_CCR_DBT(div/2) | LPSPI_CCR_PCSSCK(div/2);
//Serial.printf("SPI.setClockDivider_noInline CCR:%x TCR:%x\n", _ccr, port().TCR);
IMXRT_LPSPI3_S.CR = 0;
IMXRT_LPSPI3_S.CFGR1 = LPSPI_CFGR1_MASTER | LPSPI_CFGR1_SAMPLE;
IMXRT_LPSPI3_S.CCR = ccr;
IMXRT_LPSPI3_S.CR = LPSPI_CR_MEN;
}
void AudioOutputSPI::begin(void)
{
Serial.begin(9600);
pinMode( DA_SYNC, OUTPUT);
digitalWrite( DA_SYNC, HIGH);
pinMode( AD7607_CHIP_SELECT, OUTPUT);
digitalWriteFast( AD7607_CHIP_SELECT, HIGH);
pinMode( AD7607_START_CONVERSION, OUTPUT);
digitalWriteFast( AD7607_START_CONVERSION, HIGH);
pinMode( AD7607_RESET, OUTPUT);
digitalWrite( AD7607_RESET, LOW);
pinMode( AD7607_RANGE_SELECT, OUTPUT);
digitalWrite( AD7607_RANGE_SELECT, HIGH);
pinMode( LRCLK_CPY, INPUT);
delayMicroseconds(10);
SPI1.begin();
digitalWrite(DA_SYNC, LOW);
SPI1.beginTransaction(SPISettings());
uint8_t configureDac[] = {
0,
0,
0x10,
0x00,
0x0f,
0x10,
0x00,
0x0f
};
SPI1.transfer(configureDac, 8);
SPI1.endTransaction();
digitalWrite(DA_SYNC, HIGH);
delayMicroseconds(10);
// Set voltage range for DAC0, DAC1;
digitalWrite(DA_SYNC, LOW);
uint8_t configureDacVoltageRange[] = {
0,
0,
(AD5754R_REG_RANGE_SELECT << 3) + AD5754R_DAC_ALL,
0x00,
AD5754R_BIPOLAR_10_RANGE,
(AD5754R_REG_RANGE_SELECT << 3) + AD5754R_DAC_ALL,
0x00,
AD5754R_BIPOLAR_10_RANGE
};
SPI1.beginTransaction(SPISettings());
SPI1.transfer(configureDacVoltageRange, 8);
SPI1.endTransaction();
digitalWrite(DA_SYNC, HIGH);
delayMicroseconds(10);
for (int i=0; i < 8; i++) {
block_input[i] = nullptr;
}
memset(zeros, 0, sizeof(zeros));
memset(tdm_tx_buffer, 0, sizeof(tdm_tx_buffer));
dmatx.begin(true); // Allocate the DMA channel first
dmatx.disable();
dmatx.sourceBuffer(tdm_tx_buffer, 32);
dmatx.transferSize(4);
dmatx.transferCount(8);
dmatx.destination((volatile uint32_t &)IMXRT_LPSPI3_S.TDR);
dmatx.triggerAtHardwareEvent(DMAMUX_SOURCE_LPSPI3_TX);
dmatx.disableOnCompletion();
dmatx.interruptAtCompletion();
dmatx.attachInterrupt(tx_complete_isr);
dmarx.begin(true); // allocate the DMA channel first
dmarx.disable();
dmarx.destinationBuffer(rxbuf, 32);
dmarx.source((volatile uint32_t &)IMXRT_LPSPI3_S.RDR);
dmarx.transferSize(4);
dmarx.transferCount(8);
dmarx.triggerAtHardwareEvent(DMAMUX_SOURCE_LPSPI3_RX);
dmarx.disableOnCompletion();
dmarx.attachInterrupt(rx_complete_isr);
dmarx.interruptAtCompletion();
for (uint8_t count=0; count<4; count++) {
tdm_tx_buffer[(count*8)+3] = 0;
tdm_tx_buffer[(count*8)+2] = 0;
tdm_tx_buffer[(count*8)+1] = count; //DAC0, channel=count
tdm_tx_buffer[(count*8)+0] = 0xFF;//(block_input[count*2] != NULL) ? block_input[count*2]->data[_readIndex] >> 8 : zero_level;
tdm_tx_buffer[(count*8)+7] = 0xFF;//(block_input[count*2] != NULL) ? block_input[count*2]->data[_readIndex] & 0xff : zero_level;
tdm_tx_buffer[(count*8)+6] = count; //DAC1, channel=count
tdm_tx_buffer[(count*8)+5] = 0xFF;//(block_input[count*2+1] != NULL) ? block_input[count*2+1]->data[_readIndex] >> 8 : zero_level;
tdm_tx_buffer[(count*8)+4] = 0xFF;//(block_input[count*2+1] != NULL) ? block_input[count*2+1]->data[_readIndex] & 0xff : zero_level;
//DAC1, channel=count
}
SPI1.setSCK(SCK_PIN);
SPI1.setMOSI(MOSI_PIN);
SPI1.setMISO(MISO_PIN);
SPI1.setCS(DA_SYNC);
SPI1.begin();
IMXRT_LPSPI3_S.TCR = (IMXRT_LPSPI3_S.TCR & ~(LPSPI_TCR_FRAMESZ(7))) | LPSPI_TCR_FRAMESZ(63) ; // Change framesize to 64 bits
setClockDivider_noInline(30000000);
digitalWriteFast(AD7607_START_CONVERSION, LOW);
digitalWriteFast(AD7607_START_CONVERSION, HIGH);
attachInterrupt(digitalPinToInterrupt(LRCLK_CPY),timer,RISING);
// https://forum.pjrc.com/threads/65229-Setting-up-custom-I2S-communication
//attachInterruptVector(IRQ_SAI1, timer);
//NVIC_ENABLE_IRQ(IRQ_SAI1);
//I2S1_TCSR |= 1<<12; // start generating TX FIFO interrupts
NVIC_SET_PRIORITY(IRQ_LPSPI3, 5);
NVIC_SET_PRIORITY(IRQ_DMA_CH0 + dmatx.channel, 10);
NVIC_SET_PRIORITY(IRQ_DMA_CH0 + dmarx.channel, 2);
NVIC_SET_PRIORITY(IRQ_GPIO6789, 1);
for (int i = 0; i < 8; i++) {
block_write[i] = allocate();
if (block_write[i] == nullptr) {
for (int j = 0; j < i; j++) {
release(block_write[j]);
}
//memset(new_block, 0, sizeof(new_block));
break;
}
}
}
void AudioOutputSPI::rx_complete_isr(void) {
dmarx.clearInterrupt();
for (int i = 0; i < 8; i++) {
if (block_write[i] != NULL) {
block_write[i]->data[_writeIndex] = ((rxbuf[i*2+1] << 8) + rxbuf[i*2]);
}
}
_writeIndex++;
if (_writeIndex == 128) {
memcpy(block_incoming, block_write, sizeof(block_incoming));
//for (int i=0; 0 < 8; i++)
// block_incoming[i] = block_write[i];
audio_block_t *new_block[8];
// allocate 8 new blocks. If any fails, allocate none
for (int i = 0; i < 8; i++) {
new_block[i] = allocate();
if (new_block[i] == nullptr) {
for (int j = 0; j < i; j++) {
release(new_block[j]);
}
memset(new_block, 0, sizeof(new_block));
break;
}
}
// __disable_irq();
memcpy(block_write, new_block, sizeof(block_write));
_writeIndex = 0;
// __enable_irq();
}
digitalWrite(AD7607_START_CONVERSION, LOW);
digitalWrite(AD7607_START_CONVERSION, HIGH);
dmarx.TCD->SOFF = 0;
}
void AudioOutputSPI::tx_complete_isr(void)
{
digitalWriteFast(AD7607_CHIP_SELECT, HIGH);
dmatx.clearInterrupt();
//while (IMXRT_LPSPI3_S.FSR & 0x1f);//FIFO Status register: wait until fifo is complete
while (IMXRT_LPSPI3_S.SR & LPSPI_SR_MBF); //Status Register: wait until Module Busy flag is cleared
//delayNanoseconds(20);
_readIndex++;
if (_readIndex >= 128 && _resetReceived) {
_readIndex = 0;
for (unsigned int i=0; i < 8; i++) {
if (prev[i]) {
release(prev[i]);
prev[i] = nullptr;
}
}
_resetReceived = false;
}
}
void AudioOutputSPI::update(void)
{
unsigned int i, j;
audio_block_t *out_block[8];
__disable_irq();
memcpy(out_block, block_incoming, sizeof(out_block));
for (i=0; i < 8; i++) {
prev[i] = block_input[i];
block_input[i] = receiveReadOnly(i);
}
_resetReceived = true;
__enable_irq();
if (out_block[0] != nullptr) {
// if we got 1 block, all 16 are filled
for (i = 0; i < 8; i++) {
transmit(out_block[i], i);
release(out_block[i]);
}
}
/*
for (i=0; i < 8; i++) {
if (prev[i]) release(prev[i]);
}
*/
}
void AudioOutputSPI::timer(void) {
const uint16_t readIndex = _readIndex;
if (readIndex < 128) {
for (uint8_t count = 0; count < 4; count++) {
//DAC0, channel=count
uint8_t doubleCount = count * 2;
audio_block_t *block = (_resetReceived) ? prev[doubleCount] : block_input[doubleCount];
uint16_t value = (block != NULL) ? block->data[readIndex] + zero_level : zero_level;
tdm_tx_buffer[(count * 8) + 0] = value >> 8;
tdm_tx_buffer[(count * 8) + 7] = value & 0xff;
//tdm_tx_buffer[(count * 8) + 0] = readIndex >> 8;
//tdm_tx_buffer[(count * 8) + 7] = readIndex & 0xff;
//DAC1, channel=count
uint8_t doubleCountPlusOne = count * 2 + 1;
audio_block_t *block2 = (_resetReceived) ? prev[doubleCountPlusOne] : block_input[doubleCountPlusOne];
uint16_t value2 = (block2 != NULL) ? block2->data[readIndex] + zero_level : zero_level;
tdm_tx_buffer[(count * 8) + 5] = value2 >> 8;
tdm_tx_buffer[(count * 8) + 4] = value2 & 0xff;
//tdm_tx_buffer[(count * 8) + 5] = readIndex >> 8;
//tdm_tx_buffer[(count * 8) + 4] = readIndex & 0xff;
//DAC1, channel=count
}
//IMXRT_LPSPI3_S.TCR = (IMXRT_LPSPI3_S.TCR & ~(LPSPI_TCR_FRAMESZ(7))) | LPSPI_TCR_FRAMESZ(63); // Change framesize to 48 bits
//IMXRT_LPSPI3_S.FCR = 0;
IMXRT_LPSPI3_S.DER = LPSPI_DER_TDDE | LPSPI_DER_RDDE; //DMA Enable register: enable DMA on TX
IMXRT_LPSPI3_S.SR = 0x3f00; // status register: clear out all of the other status...
dmarx.enable();
dmatx.enable();
digitalWriteFast(AD7607_CHIP_SELECT, LOW);
}
}
#endif
//
// Created by Moolet on 18/03/2021.
//
#ifndef TEENSYAUDIOSPISHAREDLIBRARY_OUTPUT_SPI_H
#define TEENSYAUDIOSPISHAREDLIBRARY_OUTPUT_SPI_H
#include "Arduino.h"
#include "AudioStream.h"
#include "DMAChannel.h"
class AudioOutputSPI : public AudioStream
{
public:
AudioOutputSPI(void) : AudioStream(8, inputQueueArray) { begin(); }
virtual void update(void);
void begin(void);
protected:
static audio_block_t *block_input[8];
static audio_block_t *block_incoming[8];
static audio_block_t *block_write[8];
static bool update_responsibility;
static DMAChannel dmatx;
static DMAChannel dmarx;
static void tx_complete_isr(void);
static void rx_complete_isr(void);
static void timer(void);
static volatile uint16_t _readIndex;
static volatile uint16_t _writeIndex;
static volatile bool _resetReceived;
private:
audio_block_t *inputQueueArray[8];
static audio_block_t *prev[8];
static volatile uint8_t rxbuf[32];
};
#endif //TEENSYAUDIOSPISHAREDLIBRARY_OUTPUT_SPI_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment