From 559d92e526d5de7a7df172d7e2ba5d7701c37dff Mon Sep 17 00:00:00 2001 From: Sebastian Kujas Date: Tue, 27 May 2025 13:13:29 +0200 Subject: [PATCH] alpha build --- .gitignore | 1 + soundcube-firmware/soundcube-firmware.ino | 375 +++++++++++----------- soundcube-i2s-test/soundcube-i2s-test.ino | 250 +++++++-------- 3 files changed, 316 insertions(+), 310 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build diff --git a/soundcube-firmware/soundcube-firmware.ino b/soundcube-firmware/soundcube-firmware.ino index b63eb20..693b52f 100644 --- a/soundcube-firmware/soundcube-firmware.ino +++ b/soundcube-firmware/soundcube-firmware.ino @@ -1,186 +1,191 @@ -#include -#include -#include -#include -#include - -#define HAPTIC 0 -#define AURAL 0 -#define UI_SAMPLERATE 22050 - -I2S i2s(INPUT_PULLUP); - -TCA9555 TCA(0x20, &Wire1); -AS5600 ENC(&Wire1); - -PWMAudio ui_snd(8); - -enum BUTTON {CVINL, CVINR, INL, INR, OUTR, OUTL, CVOUTR, CVOUTL, RIGHT, LEFT, SELECT, DEBUG1, DEBUG2, DEBUG3}; - -Adafruit_NeoPixel edge_pixels(8, 4, NEO_GRB + NEO_KHZ800); -Adafruit_NeoPixel ui_pixels(72, 5, NEO_GRB + NEO_KHZ800); - -volatile bool flag = false; -volatile bool click = false; -volatile bool amp = false; - -int counter = 0; - -bool buttons[16] = {false}; - -int16_t beep[UI_SAMPLERATE]; - -void pwm_audio_callback() { - while (ui_snd.availableForWrite()) { - if(click) { - ui_snd.write(beep[counter]); - } else { - ui_snd.write(0); - } - counter++; - if(counter == UI_SAMPLERATE) counter = 0; - } -} - -void tca_irq() { - flag = true; -} - -void setup() { - - for(int i = 0; i < UI_SAMPLERATE; i++){ - float sine_pos = (2.0f * M_PI * 8000.0f * (float)i) / (float)UI_SAMPLERATE; - beep[i] = (int16_t)(sin(sine_pos) * 8000.0f); - } - - Serial.begin(); - delay(2000); - - Serial.println("INIT WIRE"); - Wire1.setSDA(2); - Wire1.setSCL(3); - Wire1.begin(); - Serial.println("SUCCESS"); - - Serial.println("INIT TCA"); - TCA.begin(); - TCA.pinMode16(0xFFFF); - TCA.setPolarity16(0x0000); - Serial.println("SUCCESS"); - - Serial.println("INIT INTERRUPT"); - pinMode(1, INPUT_PULLUP); - attachInterrupt(digitalPinToInterrupt(1), tca_irq, FALLING); - Serial.println("SUCCESS"); - - // Rotary Encoder - ENC.begin(4); // set direction pin. - - pinMode(6, OUTPUT); // Vibration Motor - pinMode(7, OUTPUT); // UI Amp Enable - - ui_snd.onTransmit(pwm_audio_callback); - ui_snd.begin(UI_SAMPLERATE); - - digitalWrite(7, LOW); - - edge_pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) - ui_pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) - - // i2s.setDOUT(14); - // i2s.setDIN(15); - // i2s.setBCLK(16); // - // i2s.swapClocks(); - // i2s.setMCLK(18); - // i2s.setBitsPerSample(16); - // i2s.setFrequency(48000); - // i2s.setSysClk(48000); - // i2s.begin(); - - // while (1) { - // int16_t l, r; - // i2s.read16(&l, &r); - // i2s.write16(l, r); - // } -} -int active = 0; -uint32_t lastTime = 0; -int32_t position = 0; - -void loop() { - edge_pixels.clear(); // Set all pixel colors to 'off' - ui_pixels.clear(); // Set all pixel colors to 'off' - - position = ENC.getCumulativePosition(); - - // if (millis() - lastTime >= 100) - // { - // lastTime = millis(); - // Serial.print(ENC.getCumulativePosition()); - // Serial.print("\t"); - // Serial.println(ENC.getRevolutions()); - // } - - for (int i = 0; i < 48; i++) { - ui_pixels.setPixelColor(i + 3, edge_pixels.Color(0, 0, 0)); - } - - if (flag) { - int val = TCA.read16(); - Serial.println(val, BIN); - - for(int i = 0; i < 16; i++){ - buttons[i] = ~(val >> i) & 0x01; - Serial.print(buttons[i]); - Serial.print(" "); - } - Serial.println(); - - flag = false; - if (HAPTIC) { - digitalWrite(6, HIGH); - } - if (AURAL) { - digitalWrite(7, HIGH); - click = true; - delay(50); - click = false; - digitalWrite(7, LOW); - } - if(HAPTIC){ - if(!AURAL) delay(50); - digitalWrite(6, LOW); - } - for (int i = 0; i < 48; i++) { - ui_pixels.setPixelColor(i + 3, edge_pixels.Color(0, 15, 0)); - } - if(buttons[RIGHT]) active++; - if(buttons[LEFT]) active--; - if(active == 13) active = 0; - if(active == -1) active = 12; - } - // 11111110 11111111 button right - - // EDGE LEDs - for (int i = 0; i < 8; i++) { - edge_pixels.setPixelColor(i, edge_pixels.Color(15, 15, 15)); - } - - // Rotary button LEDs - ui_pixels.setPixelColor(0, edge_pixels.Color(0, 0, 15)); - ui_pixels.setPixelColor(1, edge_pixels.Color(0, 0, 15)); - ui_pixels.setPixelColor(2, edge_pixels.Color(0, 0, 15)); - - for (int i = 0; i < 13; i++) { - ui_pixels.setPixelColor(i + 3 + 48 + 4, edge_pixels.Color(0, 0, 0)); - } - - ui_pixels.setPixelColor(active + 3 + 48 + 4, edge_pixels.Color(255, 255, 255)); - - // put your main code here, to run repeatedly: - - edge_pixels.show(); // Set all pixel colors to 'off' - ui_pixels.show(); // Set all pixel colors to 'off' - - delay(1); +#include +#include +#include +#include +#include + +#define HAPTIC 1 +#define AURAL 1 +#define UI_SAMPLERATE 22050 + +I2S i2s(INPUT_PULLUP); + +TCA9555 TCA(0x20, &Wire1); +AS5600 ENC(&Wire1); + +PWMAudio ui_snd(8); + +enum BUTTON {CVINL, CVINR, INL, INR, OUTR, OUTL, CVOUTR, CVOUTL, RIGHT, LEFT, SELECT, DEBUG1, DEBUG2, DEBUG3}; + +Adafruit_NeoPixel edge_pixels(8, 4, NEO_GRB + NEO_KHZ800); +Adafruit_NeoPixel ui_pixels(72, 5, NEO_GRB + NEO_KHZ800); + +volatile bool flag = false; +volatile bool click = false; +volatile bool amp = false; + +int counter = 0; + +bool buttons[16] = {false}; + +int16_t beep[UI_SAMPLERATE]; + +void pwm_audio_callback() { + while (ui_snd.availableForWrite()) { + if(click) { + ui_snd.write(beep[counter]); + } else { + ui_snd.write(0); + } + counter++; + if(counter == UI_SAMPLERATE) counter = 0; + } +} + +void tca_irq() { + flag = true; +} + +void setup() { + + for(int i = 0; i < UI_SAMPLERATE; i++){ + float sine_pos = (2.0f * M_PI * 8000.0f * (float)i) / (float)UI_SAMPLERATE; + beep[i] = (int16_t)(sin(sine_pos) * 8000.0f); + } + + Serial.begin(); + delay(2000); + + Serial.println("INIT WIRE"); + Wire1.setSDA(2); + Wire1.setSCL(3); + Wire1.begin(); + Serial.println("SUCCESS"); + + Serial.println("INIT TCA"); + TCA.begin(); + TCA.pinMode16(0xFFFF); + TCA.setPolarity16(0x0000); + Serial.println("SUCCESS"); + + Serial.println("INIT INTERRUPT"); + pinMode(1, INPUT_PULLUP); + attachInterrupt(digitalPinToInterrupt(1), tca_irq, FALLING); + Serial.println("SUCCESS"); + + // Rotary Encoder + ENC.begin(); // set direction pin. + ENC.setDirection(AS5600_COUNTERCLOCK_WISE); + + pinMode(6, OUTPUT); // Vibration Motor + pinMode(7, OUTPUT); // UI Amp Enable + + ui_snd.onTransmit(pwm_audio_callback); + ui_snd.begin(UI_SAMPLERATE); + + digitalWrite(7, LOW); + + edge_pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) + ui_pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) + + // i2s.setDOUT(14); + // i2s.setDIN(15); + // i2s.setBCLK(16); // + // i2s.swapClocks(); + // i2s.setMCLK(18); + // i2s.setBitsPerSample(16); + // i2s.setFrequency(48000); + // i2s.setSysClk(48000); + // i2s.begin(); + + // while (1) { + // int16_t l, r; + // i2s.read16(&l, &r); + // i2s.write16(l, r); + // } +} +int active = 0; +int active_led_ring = 0; + +uint32_t lastTime = 0; +int32_t position = 0; + +void loop() { + edge_pixels.clear(); // Set all pixel colors to 'off' + ui_pixels.clear(); // Set all pixel colors to 'off' + + position = ENC.getCumulativePosition(); + + // if (millis() - lastTime >= 100) + // { + // lastTime = millis(); + // Serial.print(ENC.getCumulativePosition()); + // Serial.print("\t"); + // Serial.println(ENC.getRevolutions()); + // } + + for (int i = 0; i < 48; i++) { + ui_pixels.setPixelColor(i + 3, edge_pixels.Color(0, 0, 0)); + } + + if (flag) { + int val = TCA.read16(); + Serial.println(val, BIN); + + for(int i = 0; i < 16; i++){ + buttons[i] = ~(val >> i) & 0x01; + Serial.print(buttons[i]); + Serial.print(" "); + } + Serial.println(); + + flag = false; + if (HAPTIC) { + digitalWrite(6, HIGH); + } + if (AURAL) { + digitalWrite(7, HIGH); + click = true; + delay(50); + click = false; + digitalWrite(7, LOW); + } + if(HAPTIC){ + if(!AURAL) delay(50); + digitalWrite(6, LOW); + } + for (int i = 0; i < 48; i++) { + ui_pixels.setPixelColor(i + 3, edge_pixels.Color(0, 15, 0)); + } + if(buttons[RIGHT]) active++; + if(buttons[LEFT]) active--; + if(active == 13) active = 0; + if(active == -1) active = 12; + } + // 11111110 11111111 button right + + // EDGE LEDs + for (int i = 0; i < 8; i++) { + edge_pixels.setPixelColor(i, edge_pixels.Color(15, 15, 15)); + } + + // Rotary button LEDs + ui_pixels.setPixelColor(0, edge_pixels.Color(0, 0, 15)); + ui_pixels.setPixelColor(1, edge_pixels.Color(0, 0, 15)); + ui_pixels.setPixelColor(2, edge_pixels.Color(0, 0, 15)); + + for (int i = 0; i < 13; i++) { + ui_pixels.setPixelColor(i + 3 + 48 + 4, edge_pixels.Color(0, 0, 0)); + } + + ui_pixels.setPixelColor(active + 3 + 48 + 4, edge_pixels.Color(255, 255, 255)); + + active_led_ring = abs((position / 256) % 48); + ui_pixels.setPixelColor(active_led_ring + 3, edge_pixels.Color(255, 255, 255)); + // put your main code here, to run repeatedly: + + edge_pixels.show(); // Set all pixel colors to 'off' + ui_pixels.show(); // Set all pixel colors to 'off' + + delay(1); } \ No newline at end of file diff --git a/soundcube-i2s-test/soundcube-i2s-test.ino b/soundcube-i2s-test/soundcube-i2s-test.ino index 4fff2c3..5dfaa1c 100644 --- a/soundcube-i2s-test/soundcube-i2s-test.ino +++ b/soundcube-i2s-test/soundcube-i2s-test.ino @@ -1,125 +1,125 @@ -/* - I2S bi-directional input and output buffered loopback example - Released to the Public Domain by Cooper Dalrymple -*/ -#include -#include - -I2S i2s(INPUT_PULLUP); - -#define SIZE 256 -int16_t buffer[SIZE]; - -void cw(char first, char second){ - Wire1.beginTransmission(0x18); - Wire1.write(first); - Wire1.write(second); - Wire1.endTransmission(); - delay(5); -} - -void setup() { - Serial.begin(115200); - - delay(1000); - - Wire1.setSDA(2); - Wire1.setSCL(3); - Wire1.begin(); - - delay(1000); - - // GENERAL - cw(0x00, 0x00); - cw(0x01, 0x01); - cw(0x1b, 0x10); // select I2S - - // ADC - cw(0x00, 0x00); // select page 0 - //cw(0x01, 0x01); // soft reset - cw(0x12, 0x87); // NADC 7 - cw(0x13, 0x82); // MADC 2 - cw(0x14, 0x80); // OSR ADC 128 - cw(0x3d, 0x01); // ADC PRB_R1 - - cw(0x00, 0x01); // select page 1 - cw(0x01, 0x08); // disable crude AVdd - cw(0x02, 0x01); // enable internal AVdd LDO - cw(0x0a, 0x0B); // set input CM to 0.9V and LO to 1.65V - cw(0x3d, 0x00); // ADC PTM_R4 - cw(0x34, 0x80); // route IN1L to LEFT_P with 20k input impedance - cw(0x36, 0x80); // route CM to LEFT_M with 20k input impedance - cw(0x37, 0x80); // route IN1R to RIGHT_P with 20k input impedance - cw(0x39, 0x80); // route CM to RIGHT_M with 20k input impedance - cw(0x3b, 0x0c); // unmute left MICPGA - cw(0x3c, 0x0c); // unmute right MICPGA - - cw(0x00, 0x00); // select page 0 - cw(0x51, 0xc0); // power up ADC - cw(0x51, 0x00); // unmute ADC digital volume control - - // DAC - cw(0x00, 0x00); // select page 0 - //cw(0x01, 0x01); // software reset - cw(0x0b, 0x82); // NDAC 2 - cw(0x0c, 0x87); // MDAC 7 - cw(0x0d, 0x00); // OSR DAC 128 - cw(0x0e, 0x80); // OSR DAC 128 - cw(0x1b, 0x10); // world length 20bits PTM_P4 (highest performance) - cw(0x3c, 0x08); // PRB_P8 - - cw(0x00, 0x01); // select page 1 - //cw(0x01, 0x08); // disable internal crude avdd - //cw(0x02, 0x01); // enable AVdd LDO - cw(0x7b, 0x01); // set REF charging time to 40ms - //cw(0x14, 0x25); // set HP soft stepping for anti pop - //cw(0x0a, 0x0B); // set input CM to 0.9V and LO to 1.65V - cw(0x0e, 0x08); // left DAC reconstruction filter routed to LOL - cw(0x0f, 0x08); // right DAC reconstruction filter routed to LOR - cw(0x03, 0x00); // DAC PTM_P3/4 - cw(0x04, 0x00); // DAC PTM_P3/4 - cw(0x12, 0x00); // LOL gain 0dB - cw(0x13, 0x00); // LOR gain 0dB - delay(1000); - - cw(0x00, 0x00); // select page 0 - cw(0x3f, 0xd6); // power up and route left digital audio to left dac channel and right to right - cw(0x40, 0x00); // unmute DAC digital volume - - - pinMode(19, OUTPUT); // MCLK enable - pinMode(20, OUTPUT); // CODEC reset - - i2s.setSysClk(48000); - - i2s.setDOUT(14); - i2s.setDIN(15); - i2s.setBCLK(16); // Note: LRCLK = BCLK + 1 - i2s.setMCLK(18); - i2s.swapClocks(); - i2s.setBitsPerSample(16); - i2s.setFrequency(48000); - i2s.setMCLKmult(128); // 6144000Hz 6.144MHz - - i2s.setBuffers(6, SIZE * sizeof(int16_t) / sizeof(uint32_t)); - - digitalWrite(19, HIGH); // enable MCLK - digitalWrite(20, HIGH); - i2s.begin(); - - size_t count, index; - while (1) { - count = i2s.read((uint8_t *)&buffer, SIZE * sizeof(int16_t)) * sizeof(uint32_t) / sizeof(int16_t); - index = 0; - while (index < count) { - // Reduce volume by half - buffer[index++] >>= 1; // right - buffer[index++] >>= 1; // left - } - i2s.write((const uint8_t *)&buffer, count * sizeof(int16_t)); - } -} - -void loop() { - /* Nothing here */ -} +/* + I2S bi-directional input and output buffered loopback example + Released to the Public Domain by Cooper Dalrymple +*/ +#include +#include + +I2S i2s(INPUT_PULLUP); + +#define SIZE 256 +int16_t buffer[SIZE]; + +void cw(char first, char second){ + Wire1.beginTransmission(0x18); + Wire1.write(first); + Wire1.write(second); + Wire1.endTransmission(); + delay(5); +} + +void setup() { + Serial.begin(115200); + + delay(1000); + + Wire1.setSDA(2); + Wire1.setSCL(3); + Wire1.begin(); + + delay(1000); + + // GENERAL + cw(0x00, 0x00); + cw(0x01, 0x01); + cw(0x1b, 0x10); // select I2S + + // ADC + cw(0x00, 0x00); // select page 0 + //cw(0x01, 0x01); // soft reset + cw(0x12, 0x87); // NADC 7 + cw(0x13, 0x82); // MADC 2 + cw(0x14, 0x80); // OSR ADC 128 + cw(0x3d, 0x01); // ADC PRB_R1 + + cw(0x00, 0x01); // select page 1 + cw(0x01, 0x08); // disable crude AVdd + cw(0x02, 0x01); // enable internal AVdd LDO + cw(0x0a, 0x0B); // set input CM to 0.9V and LO to 1.65V + cw(0x3d, 0x00); // ADC PTM_R4 + cw(0x34, 0x80); // route IN1L to LEFT_P with 20k input impedance + cw(0x36, 0x80); // route CM to LEFT_M with 20k input impedance + cw(0x37, 0x80); // route IN1R to RIGHT_P with 20k input impedance + cw(0x39, 0x80); // route CM to RIGHT_M with 20k input impedance + cw(0x3b, 0x0c); // unmute left MICPGA + cw(0x3c, 0x0c); // unmute right MICPGA + + cw(0x00, 0x00); // select page 0 + cw(0x51, 0xc0); // power up ADC + cw(0x51, 0x00); // unmute ADC digital volume control + + // DAC + cw(0x00, 0x00); // select page 0 + //cw(0x01, 0x01); // software reset + cw(0x0b, 0x82); // NDAC 2 + cw(0x0c, 0x87); // MDAC 7 + cw(0x0d, 0x00); // OSR DAC 128 + cw(0x0e, 0x80); // OSR DAC 128 + cw(0x1b, 0x10); // world length 20bits PTM_P4 (highest performance) + cw(0x3c, 0x08); // PRB_P8 + + cw(0x00, 0x01); // select page 1 + //cw(0x01, 0x08); // disable internal crude avdd + //cw(0x02, 0x01); // enable AVdd LDO + cw(0x7b, 0x01); // set REF charging time to 40ms + //cw(0x14, 0x25); // set HP soft stepping for anti pop + //cw(0x0a, 0x0B); // set input CM to 0.9V and LO to 1.65V + cw(0x0e, 0x08); // left DAC reconstruction filter routed to LOL + cw(0x0f, 0x08); // right DAC reconstruction filter routed to LOR + cw(0x03, 0x00); // DAC PTM_P3/4 + cw(0x04, 0x00); // DAC PTM_P3/4 + cw(0x12, 0x00); // LOL gain 0dB + cw(0x13, 0x00); // LOR gain 0dB + delay(1000); + + cw(0x00, 0x00); // select page 0 + cw(0x3f, 0xd6); // power up and route left digital audio to left dac channel and right to right + cw(0x40, 0x00); // unmute DAC digital volume + + + pinMode(19, OUTPUT); // MCLK enable + pinMode(20, OUTPUT); // CODEC reset + + i2s.setSysClk(48000); + + i2s.setDOUT(14); + i2s.setDIN(15); + i2s.setBCLK(16); // Note: LRCLK = BCLK + 1 + i2s.setMCLK(18); + i2s.swapClocks(); + i2s.setBitsPerSample(16); + i2s.setFrequency(48000); + i2s.setMCLKmult(128); // 6144000Hz 6.144MHz + + i2s.setBuffers(6, SIZE * sizeof(int16_t) / sizeof(uint32_t)); + + digitalWrite(19, HIGH); // enable MCLK + digitalWrite(20, HIGH); + i2s.begin(); + + size_t count, index; + while (1) { + count = i2s.read((uint8_t *)&buffer, SIZE * sizeof(int16_t)) * sizeof(uint32_t) / sizeof(int16_t); + index = 0; + while (index < count) { + // Reduce volume by half + buffer[index++] >>= 1; // right + buffer[index++] >>= 1; // left + } + i2s.write((const uint8_t *)&buffer, count * sizeof(int16_t)); + } +} + +void loop() { + /* Nothing here */ +}