From d5ea2377f9a1b82f40874fe3742fe0700d7e67f1 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 23 Jun 2025 01:41:46 +0200 Subject: [PATCH] ringbuffer with DMA memcpy, but i2s is broken --- soundcube-firmware/ringbuffer.h | 33 ++- soundcube-firmware/soundcube-firmware.ino | 294 +++++++++++----------- soundcube-firmware/wavestream.h | 24 +- 3 files changed, 198 insertions(+), 153 deletions(-) diff --git a/soundcube-firmware/ringbuffer.h b/soundcube-firmware/ringbuffer.h index 3bf1349..9e8eff7 100644 --- a/soundcube-firmware/ringbuffer.h +++ b/soundcube-firmware/ringbuffer.h @@ -1,6 +1,5 @@ #pragma once -template class RingBuffer{ public: RingBuffer() {} @@ -11,10 +10,10 @@ class RingBuffer{ } void begin(){ - buffer = new T[bufferSize]; + buffer = new int16_t[bufferSize]; } - bool push(T data){ + bool push(int16_t data){ if(counter < bufferSize){ buffer[write] = data; write++; // % bufferSize; @@ -25,8 +24,8 @@ class RingBuffer{ return false; } - T pop(){ - T retval = 0; + int16_t pop(){ + int16_t retval = 0; if(counter > 0) { counter--; retval = buffer[read]; @@ -36,6 +35,28 @@ class RingBuffer{ return retval; } + void pushDMA(int32_t *source){ + if(counter < bufferSize){ + rp2040.memcpyDMA(&buffer[write], source, 4); + write += 2; // % bufferSize; + if(write == bufferSize) write = 0; + counter += 2; + } + } + + void* getWritePointer(){ + return &buffer[write]; + } + + void popDMA(int32_t *target){ + if(counter > 0) { + counter -= 2; + rp2040.memcpyDMA(target, &buffer[read], 4); + read += 2; + if(read == bufferSize) read = 0; + } + } + bool isEmpty(){ return counter == 0; } @@ -53,5 +74,5 @@ class RingBuffer{ int counter = 0; int write = 0; int read = 0; - volatile T *buffer; + int16_t *buffer; }; diff --git a/soundcube-firmware/soundcube-firmware.ino b/soundcube-firmware/soundcube-firmware.ino index a2d6b7f..d60a030 100644 --- a/soundcube-firmware/soundcube-firmware.ino +++ b/soundcube-firmware/soundcube-firmware.ino @@ -5,8 +5,10 @@ #include #include +#define FASTLED_FORCE_SOFTWARE_SPI #include -#include + +//#include #include #include #include @@ -20,15 +22,15 @@ bool core1_disable_systick = true; #define AURAL 1 #define UI_SAMPLERATE 22050 -#define BUFFERSIZE 64 +#define BUFFERSIZE 32 #define NSTREAMS 16 +I2S i2s(INPUT_PULLUP); + int16_t buffer[BUFFERSIZE]; WaveStream stream[NSTREAMS]; -I2S i2s(INPUT_PULLUP); - TLV320AIC3204 codec; TCA9555 TCA(0x20, &Wire1); @@ -36,7 +38,10 @@ AS5600 ENC(&Wire1); DAC8552 dac(9, &SPI1); -PWMAudio ui_snd(8); +//PWMAudio ui_snd(8); + +CRGB ui_leds[74]; +CRGB edge_leds[11]; enum STATE {BANK, SAMPLE, SEQUENCE, CTEMPO}; STATE state = BANK; @@ -60,9 +65,6 @@ int selected_sample = 0; uint32_t lastTime = 0; int32_t position = 0; -CRGB ui_leds[74]; -CRGB edge_leds[11]; - volatile bool setup0_finished = false; volatile bool setup1_finished = false; @@ -76,6 +78,7 @@ volatile bool streams_loaded = false; bool speakerToggle = false; bool sd_card_detected = false; +volatile bool i2s_ready = false; volatile bool codec_ready = false; volatile bool config_loaded = false; @@ -164,11 +167,18 @@ size_t count; size_t tape_write = 0; void codec_transmit() { - for(int i = 0; i < count; i++){ - for(int k = 0; k < NSTREAMS; k++){ - int16_t sample = 0; - sample = stream[k].get(); - buffer[i] += sample >> 2; + for(int i = 0; i < count; i+=2){ + if(streams_loaded){ + for(int k = 0; k < NSTREAMS; k++){ + int32_t twosamples; + stream[k].wavefile.buffer.popDMA(&twosamples); + + int16_t sample_l = sample_l = twosamples >> 16; + int16_t sample_r = sample_r = twosamples & 0xFFFF; + + buffer[i] += sample_l >> 3; + buffer[i+1] += sample_r >> 3; + } } } i2s.write((const uint8_t *)&buffer, count * sizeof(int16_t)); @@ -181,33 +191,33 @@ void codec_receive(){ } } -void pwm_audio_callback() { - while (ui_snd.availableForWrite()) { - if(ui_click || ui_beep) { - if(ui_beep) { - ui_snd.write(ui_beep_snd[counter]); - counter++; - if(counter == beep_length) { - counter = 0; - ui_beep = false; - } - continue; - } - if(ui_click) { - ui_snd.write(ui_click_snd[counter]); - counter++; - if(counter == click_length) { - counter = 0; - ui_click = false; - } - } - } else { - digitalWrite(7, LOW); - ui_snd.write(0); - counter = 0; - } - } -} +// void pwm_audio_callback() { +// while (ui_snd.availableForWrite()) { +// if(ui_click || ui_beep) { +// if(ui_beep) { +// ui_snd.write(ui_beep_snd[counter]); +// counter++; +// if(counter == beep_length) { +// counter = 0; +// ui_beep = false; +// } +// continue; +// } +// if(ui_click) { +// ui_snd.write(ui_click_snd[counter]); +// counter++; +// if(counter == click_length) { +// counter = 0; +// ui_click = false; +// } +// } +// } else { +// digitalWrite(7, LOW); +// ui_snd.write(0); +// counter = 0; +// } +// } +// } bool load_ui_sounds(const char* file, int16_t *buffer, uint16_t &length){ if(SD.exists(file)) { @@ -326,18 +336,23 @@ Vibration vibration; // -------------------------------------------- SETUP 0 void setup() { - Serial.begin(); - delay(500); - i2s.setSysClk(48000); - i2s.onTransmit(codec_transmit); - i2s.onReceive(codec_receive); + + Serial.begin(); + + while(!codec_ready){ + Serial.println("0: Waiting for codec"); + delay(250); + } + + // i2s.onTransmit(codec_transmit); + // i2s.onReceive(codec_receive); i2s.setDOUT(15); i2s.setDIN(14); i2s.setBCLK(16); // Note: LRCLK = BCLK + 1 i2s.setMCLK(18); - i2s.setMCLKmult(512); // 256 = 12.288.000Hz 512 = 25Mhz + i2s.setMCLKmult(512); // 256 = 12.288.000Hz 512 = 25MHz i2s.swapClocks(); i2s.setFrequency(48000); @@ -345,6 +360,16 @@ void setup() { i2s.setBuffers(6, BUFFERSIZE * sizeof(int16_t) / sizeof(uint32_t)); + if(!i2s.begin(48000)){ + Serial.println("0: I2S error!"); + while(100); + } + Serial.println("0: I2S OK"); + + delay(100); + + i2s_ready = true; + pinMode(12, OUTPUT); // speaker enable l pinMode(13, OUTPUT); // speaker enable r speaker(false); @@ -361,10 +386,10 @@ void setup() { if(sdInitialized) loadConfiguration(config); - if(sdInitialized){ - load_ui_sounds("/ui/click.wav", ui_click_snd, click_length); - load_ui_sounds("/ui/beep.wav", ui_beep_snd, beep_length); - } + // if(sdInitialized){ + // load_ui_sounds("/ui/click.wav", ui_click_snd, click_length); + // load_ui_sounds("/ui/beep.wav", ui_beep_snd, beep_length); + // } config_loaded = true; @@ -378,24 +403,8 @@ void setup() { } } - while(!codec_ready){ - delay(250); - Serial.println("0: Waiting for codec"); - } - - if(!i2s.begin(48000)){ - Serial.println("0: I2S error!"); - while(100); - } - Serial.println("0: I2S OK"); - - Serial.print("0: STARTUP COMPLETE"); - digitalWrite(6, HIGH); - delay(25); - digitalWrite(6, LOW); - delay(50); digitalWrite(6, HIGH); delay(25); digitalWrite(6, LOW); @@ -403,12 +412,33 @@ void setup() { } void setup1(){ + Serial.print("1: ENABLE I2S MCLK: "); + pinMode(19, OUTPUT); // MCLK enable + digitalWrite(19, HIGH); // enable MCLK + Serial.println("SUCCESS"); + delay(100); + + Serial.print("1: ENABLE CODEC: "); + pinMode(20, OUTPUT); // CODEC reset (enable) + digitalWrite(20, HIGH); + Serial.println("SUCCESS"); + delay(100); + Serial.print("1: STARTUP"); - Serial.print("1: INIT LEDS: "); - FastLED.addLeds(edge_leds, 11); - FastLED.addLeds(ui_leds, 74); + Serial.print("1: INIT WIRE: "); + Wire1.setSDA(2); + Wire1.setSCL(3); + Wire1.begin(); Serial.println("SUCCESS"); + delay(100); + + Serial.print("1: INIT CODEC: "); + codec.begin(&Wire1); + Serial.println("SUCCESS"); + delay(500); + + codec_ready = true; Serial.print("1: INIT SPI: "); SPI1.setSCK(10); @@ -420,12 +450,11 @@ void setup1(){ dac.begin(); Serial.println("SUCCESS"); - Serial.print("1: INIT WIRE: "); - Wire1.setSDA(2); - Wire1.setSCL(3); - Wire1.begin(); - Serial.println("SUCCESS"); - delay(100); + + while(!config_loaded){ + delay(250); + Serial.println("1: Waiting for config"); + } Serial.print("1: INIT TCA: "); TCA.begin(); @@ -444,44 +473,30 @@ void setup1(){ ENC.resetCumulativePosition(); Serial.println("SUCCESS"); - while(!config_loaded){ - delay(250); - Serial.println("1: Waiting for config"); - } - - Serial.print("1: ENABLE I2S MCLK: "); - pinMode(19, OUTPUT); // MCLK enable - digitalWrite(19, HIGH); // enable MCLK - Serial.println("SUCCESS"); - delay(10); - - Serial.print("1: ENABLE CODEC: "); - pinMode(20, OUTPUT); // CODEC reset (enable) - digitalWrite(20, HIGH); - Serial.println("SUCCESS"); - delay(10); - - Serial.print("1: INIT CODEC: "); - codec.begin(&Wire1); - Serial.println("SUCCESS"); - delay(100); pinMode(6, OUTPUT); // Vibration Motor pinMode(7, OUTPUT); // UI Amp Enable - ui_snd.onTransmit(pwm_audio_callback); - ui_snd.begin(UI_SAMPLERATE); + //ui_snd.onTransmit(pwm_audio_callback); + //ui_snd.begin(UI_SAMPLERATE); digitalWrite(7, LOW); // UI amp off + Serial.print("1: INIT LEDS: "); + FastLED.addLeds(edge_leds, 11); + FastLED.addLeds(ui_leds, 74); + Serial.println("SUCCESS"); + Serial.print("1: STARTUP COMPLETE"); - codec_ready = true; setup1_finished = true; + digitalWrite(6, HIGH); + delay(25); + digitalWrite(6, LOW); } uint32_t last = 0; -int bar = 0; -int bar_old = -1; +volatile int bar = 0; +volatile int bar_old = -1; int set_bar = 0; int16_t angle = 0; int32_t position_last = 0; @@ -490,7 +505,7 @@ int16_t encdelta_raw = 0; int16_t encdeltadiv = 512; void loop1() { - if(setup0_finished && setup0_finished){ + if(setup0_finished && setup1_finished){ position = ENC.getCumulativePosition(); angle = ENC.readAngle(); encdelta_raw += (position - position_last); @@ -514,13 +529,6 @@ void loop1() { // Serial.print(" \t"); // Serial.println(encdelta); - uint32_t delta_bpm = floor((60000 / config.bpm) / 16); - - if(millis() - last >= delta_bpm) { - bar = (bar + 1) % 16; - last = millis(); - } - sd_card_detected = !digitalRead(21); edge_leds[8] = sd_card_detected ? CRGB(0,10,0) : CRGB(10,0,0); @@ -709,19 +717,6 @@ void loop1() { } - if(bar != bar_old){ - if(steps[bar].len > 0) { - steps[bar].trigger(); - Serial.print("trigger "); - Serial.println(bar); - } - } - - // // set active LED ring LED - // for(int i = 0; i < active_led_ring; i++){ - // ui_leds[lut_ring_ccw[i]] = CRGB(config.ring_color.r, config.ring_color.g, config.ring_color.b); - // } - FastLED.show(); if(buttonChanged){ @@ -730,8 +725,6 @@ void loop1() { } } - //delay(20); // wait 1ms - bar_old = bar; vibration.update(); position_last = position; delay(1); @@ -741,34 +734,51 @@ void loop1() { void loop(){ if(setup1_finished && setup0_finished){ - // int16_t l, r; - // i2s.read16(&l, &r); - // for(int k = 0; k < NSTREAMS; k++){ - // int16_t sample_l = 0; - // int16_t sample_r = 0; - // sample_l = stream[k].get(); - // sample_r = stream[k].get(); - // l += sample_l >> 2; - // r += sample_r >> 2; - // } - // i2s.write16(l, r); - // i2s.flush(); - // //Serial.println(sc); - // // Serial.print(" "); - // // Serial.print(l); - // // Serial.print(" "); - // // Serial.println(r); + uint32_t delta_bpm = floor((60000 / config.bpm) / 16); + uint32_t delta = millis() - last; + + if(delta >= delta_bpm) { + bar = (bar + 1) % 16; + if(steps[bar].len > 0) { + steps[bar].trigger(); + // Serial.print("trigger "); + // Serial.println(bar); + } + + // Serial.print(delta_bpm); + // Serial.print(" "); + // Serial.println(delta); + + last = millis(); + } if(streams_loaded) { for(int i = 0; i < NSTREAMS; i++){ stream[i].stream(); } } + int16_t sample_l = 0; + int16_t sample_r = 0; + + if(streams_loaded){ + for(int k = 0; k < NSTREAMS; k++){ + sample_l += stream[k].get() >> 2; + sample_r += stream[k].get() >> 2; + } + } + + int16_t l = 0, r = 0; + //i2s.read16(&l, &r); + l += sample_l; + r += sample_r; + i2s.write16(l, r); if(i2s.getOverflow()) Serial.println("overflow"); if(i2s.getUnderflow()) Serial.println("underflow"); - //sc++; + + bar_old = bar; + } } diff --git a/soundcube-firmware/wavestream.h b/soundcube-firmware/wavestream.h index 374fb2b..3aaf539 100644 --- a/soundcube-firmware/wavestream.h +++ b/soundcube-firmware/wavestream.h @@ -78,6 +78,7 @@ struct WaveFile{ uint8_t samplebyte[blockalign]; file.read(samplebyte, blockalign); + if(!file.available() && loop) file.seek(44, SeekSet); if(!file.available() && !loop) { file.seek(44, SeekSet); @@ -91,6 +92,19 @@ struct WaveFile{ return true; } + bool readblockDMA(){ + void *bufferStart = buffer.getWritePointer(); + + file.read((uint8_t*)bufferStart, 4); + + if(!file.available() && loop) file.seek(44, SeekSet); + if(!file.available() && !loop) { + file.seek(44, SeekSet); + return false; + } + return true; + } + int16_t get(){ return buffer.pop(); } @@ -111,7 +125,7 @@ struct WaveFile{ uint16_t blockalign = 0; uint16_t bitspersample = 0; - RingBuffer buffer; + RingBuffer buffer; }; class WaveStream{ @@ -119,7 +133,7 @@ class WaveStream{ WaveStream(){} void begin(){ - wavefile.buffer.setSize(8000); + wavefile.buffer.setSize(1024); wavefile.buffer.begin(); } @@ -145,10 +159,10 @@ class WaveStream{ void stream(){ if(!wavefile.buffer.isFull() && playing){ int cnt = 0; - while (!wavefile.buffer.isFull() && cnt < 6000) { - bool ok = wavefile.readblock(); + while (!wavefile.buffer.isFull() && cnt < 1024) { + bool ok = wavefile.readblockDMA(); if(!ok) playing = false; - cnt++; + cnt += 2; } } }