From a3a4fd4fb4f76b51b3fe2c5c7e6fff9d3e0aec0b Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sun, 1 Jun 2025 01:09:35 +0200 Subject: [PATCH] The beginnings of codec.h --- soundcube-firmware/codec.h | 14 ++ soundcube-firmware/soundcube-firmware.ino | 2 + soundcube-i2s-test/codec.h | 238 ++++++++++++++++++++++ soundcube-i2s-test/soundcube-i2s-test.ino | 60 ++---- 4 files changed, 276 insertions(+), 38 deletions(-) create mode 100644 soundcube-firmware/codec.h create mode 100644 soundcube-i2s-test/codec.h diff --git a/soundcube-firmware/codec.h b/soundcube-firmware/codec.h new file mode 100644 index 0000000..14ed3bb --- /dev/null +++ b/soundcube-firmware/codec.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +class TLV320AIC3104{ + + public: + TLV320AIC3104(){} + TLV320AIC3104(TwoWire &wire) : i2c(wire) {} + + private: + TwoWire *i2c; + +}; \ No newline at end of file diff --git a/soundcube-firmware/soundcube-firmware.ino b/soundcube-firmware/soundcube-firmware.ino index 0ed741a..1585e3e 100644 --- a/soundcube-firmware/soundcube-firmware.ino +++ b/soundcube-firmware/soundcube-firmware.ino @@ -8,6 +8,8 @@ #include #include #include +#include "codec.h" + #define HAPTIC 1 #define AURAL 1 diff --git a/soundcube-i2s-test/codec.h b/soundcube-i2s-test/codec.h new file mode 100644 index 0000000..8b67957 --- /dev/null +++ b/soundcube-i2s-test/codec.h @@ -0,0 +1,238 @@ +#include +#pragma once + +#include + +struct CodecSettings{ + public: + + virtual void get() = 0; + + void write(){ + selectPage(page); + cw(reg, get()); + } + + void selectPage(int page){ + cw(0x00, page); + } + + void cw(unsigned char first, unsigned char second){ + Wire1.beginTransmission(i2c_address); + Wire1.write(first); + Wire1.write(second); + int result = Wire1.endTransmission(); + if(debug){ + Serial.print(i2c_address, HEX); + Serial.print(" "); + Serial.print(first, HEX); + Serial.print(" "); + Serial.print(second, HEX); + Serial.print(" : "); + if(result == 0) { + Serial.println("OK"); + } else { + Serial.print("ERROR: "); + Serial.println(result); + } + } + delay(5); + } + + void cr(unsigned char first, uint8_t &result, size_t len){ + Wire1.beginTransmission(i2c_address); + Wire1.write(first); // set register for read + Wire1.endTransmission(false); // false to not release the line + + Wire1.requestFrom(i2c_address, len, true); + + Wire1.readBytes(result, len); + + if(debug){ + Serial.print(first, HEX); + Serial.print(" "); + + for (int i = 0; i < len; i++) { + Serial.print(result[i], HEX); + Serial.print(" "); + Serial.println(result[i], BIN); + } + } + } +}; + +struct ClockSettings1 : public CodecSettings{ + uint8_t page = 0x00; + uint8_t reg = 0x04; + + enum PLLRange{ + PLL_HIGH = 0b01000000, + PLL_LOW = 0b00000000 + }; + + enum PLLInputClock{ + PLL_IN_MCLK = 0b00000000, + PLL_IN_BCLK = 0b00000100, + PLL_IN_GPIO = 0b00001000, + PLL_IN_DIN = 0b00001100 + }; + + enum CodecInputClock{ + CODEC_IN_MCLK = 0b00000000, + CODEC_IN_BCLK = 0b00000001, + CODEC_IN_GPIO = 0b00000010, + CODEC_IN_PLL = 0b00000011 + }; + + PLLRange pll_range = PLL_LOW; + PLLInputClock pll_input_clock = PLL_IN_MCLK; + CodecInputClock codec_input_clock = CODEC_IN_MCLK; + + uint8_t get(){ + return pll_range | pll_input_clock | codec_input_clock; + } +}; + +class TLV320AIC3204_Settings{ + + public: + + static ClockSettings1 clock_settings_1; + +}; + +class TLV320AIC3204{ + + public: + TLV320AIC3204(){i2c = &Wire} + TLV320AIC3204(TwoWire &wire) : i2c(&wire) {} + + uint8_t i2c_address = 0x18; + + void init(); + + void softReset(); // 0x00 0x01 + void hardReset(); // reset pin + + void powerUp(); // power up + + void setClockMultiplexer(ClockSettings1::PLLRange range, ClockSettings1::PLLInputClock pll_input, ClockSettings1::CodecInputClock codec_input) { + settings.clock_settings_1.pll_range = range; + settings.clock_settings_1.pll_input_clock = pll_input; + settings.clock_settings_1.codec_input_clock = codec_input; + settings.clock_settings_1.write(); + } + + void setADCParameters(int nadc, int madc, int osr); + void setDACParameters(int madc, int nadc, int osr); + + void setMicPgaGain(int gainLeft, int gainRight); // 0 - 47.5dB in 0.5dB steps + void setMicPgaGainL(int gain); + void setMicPgaGainR(int gain); + + void setLineOutVolume(int volumeLeft, int volumeRight); + void setLineOutVolumeL(int volume); + void setLineOutVolumeR(int volume); + + bool debug = false; + + private: + TwoWire *i2c; + + TLV320AIC3204_Settings settings; + + + + +}; + + +/* + // GENERAL + cw(0x00, 0x00); // select page 0 + cw(0x01, 0x01); // soft reset + cw(0x1b, 0b00000000); // select I2S with 16 bit word length + cw(0x1d, 0b00000000); // disable loopback + + // POWER and CM + cw(0x00, 0x01); // select page 1 + cw(0x01, 0b00001000); // disable weak (crude) AVdd connection to DVdd + cw(0x02, 0b00000001); // enable internal AVdd LDO and enable analog blocks + cw(0x09, 0b00001100); // power up LOL, LOR, power down MAL, MAR, HPL, HPR + cw(0x0a, 0b00001000); // set full chip CM to 0.75V + cw(0x47, 0b00110011); // analog input quick charge time 1.6ms + + // ROUTING + cw(0x00, 0x01); // select page 1 + cw(0x34, 0b10000000); // LEFT MICPGA P route IN1L to LEFT_P with 40k input impedance + //cw(0x36, 0b11000000); // LEFT MICPGA M route CM to LEFT_M with 20k input impedance + //cw(0x36, 0b00000011); // LEFT MICPGA M route CM to LEFT_M with 20k input impedance + cw(0x37, 0b10000000); // RIGHT MICPGA P route IN1R to RIGHT_P with 20k input impedance + //cw(0x39, 0b11000000); // RIGHT MICPGA M route CM to RIGHT_M with 20k input impedance + //cw(0x39, 0b00000011); // RIGHT MICPGA M route CM to RIGHT_M with 20k input impedance + cw(0x3a, 0b00111100); // connect IN2, IN3 weakly to CM + + // GAIN + cw(0x00, 0x01); // select page 1 + cw(0x3b, 0b00000000); // unmute left MICPGA, set gain to 0db + cw(0x3c, 0b00000000); // unmute right MICPGA, set gain to 0db + + // VOLUME + cw(0x00, 0x01); // select page 1 + cw(0x16, 0b01110101); // MUTE IN1L to HPL + cw(0x17, 0b01110101); // MUTE IN1R to HPR + + // ADC + cw(0x00, 0x00); // select page 0 + cw(0x12, 0x81); // NADC 1 + cw(0x13, 0x82); // MADC 2 + cw(0x14, 0b10000000); // OSR ADC 128 + //cw(0x14, 0b01000000); // OSR ADC 128 + cw(0x3d, 0b00000001); // ADC PRB_R3 = 11, PRB_R2 = 10, PRB_R1 = 01 + + cw(0x00, 0x01); // select page 1 + cw(0x3d, 0b00000000); // ADC PTM_R4 + + // DAC + cw(0x00, 0x00); // select page 0 + cw(0x0b, 0x81); // NDAC 1 + cw(0x0c, 0x82); // MDAC 2 + cw(0x0d, 0x00); // OSR DAC 128 + cw(0x0e, 0x80); // OSR DAC 128 + cw(0x1b, 0b00000000); // word length 16bits + cw(0x3c, 0b00000001); // PRB_P3 + + cw(0x00, 0x01); // select page 1 + cw(0x7b, 0b00000001); // set REF charging time to 40ms + + // ROUTING + cw(0x00, 0x01); // select page 1 + cw(0x0e, 0b00001000); // left DAC reconstruction filter routed to LOL + cw(0x0f, 0b00001000); // right DAC reconstruction filter routed to LOR + cw(0x03, 0b00000000); // DAC PTM_P3/4 + cw(0x04, 0b00000000); // DAC PTM_P3/4 + + // LO GAIN + cw(0x00, 0x01); + cw(0x12, 0b00000001); // LOL gain 0dB + cw(0x13, 0b00000001); // LOR gain 0dB + + // POWER UP + // ADC + cw(0x00, 0x00); // select page 0 + cw(0x51, 0b11000000); // power up ADC + cw(0x52, 0b00000000); // unmute ADC + cw(0x3f, 0b11010100); // power up and route left digital audio to left dac channel and right to right + cw(0x40, 0x00); // unmute DAC digital volume + + // DAC VOLUME 0b00000000 = 0dB, 10000001 = -63.5dB, 0b00110000 = +24dB + cw(0x00, 0x00); // select page 0 + cw(0x41, 0b11111001); // LEFT + cw(0x42, 0b11111001); // RIGHT + + // ADC VOLUME 0b1101000 = -12dB, 0b00000000 = 0dB, 0b0101000 = +20dB + cw(0x00, 0x00); // select page 0 + cw(0x53, 0b01110000); // LEFT + cw(0x54, 0b01110000); // RIGHT + +*/ \ 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 c760646..cbdb0cc 100644 --- a/soundcube-i2s-test/soundcube-i2s-test.ino +++ b/soundcube-i2s-test/soundcube-i2s-test.ino @@ -7,21 +7,33 @@ I2S i2s(INPUT_PULLUP); -#define SIZE 256 +#define SIZE 16 +#define ECHO 192000 int16_t buffer[SIZE]; +int16_t buffer2[ECHO]; int16_t volume = 0; size_t count; +size_t tape_write = 0; void codec_transmit() { for(int i = 0; i < count; i++){ - buffer[i] *= -1; + buffer2[tape_write] = buffer[i]; + tape_write++; + if(tape_write == ECHO) tape_write = 0; + + int tape_read = tape_write + 1; + if(tape_read < 0) tape_read += ECHO; + buffer[i] += buffer2[tape_read % ECHO]; } i2s.write((const uint8_t *)&buffer, count * sizeof(int16_t)); } void codec_receive(){ count = i2s.read((uint8_t *)&buffer, SIZE * sizeof(int16_t)) * sizeof(uint32_t) / sizeof(int16_t); + for(int i = 0; i < count; i++){ + buffer[i] *= -1; + } } void cw(unsigned char first, unsigned char second){ @@ -99,11 +111,11 @@ void setup() { // ROUTING cw(0x00, 0x01); // select page 1 - cw(0x34, 0b11000000); // LEFT MICPGA P route IN1L to LEFT_P with 40k input impedance - cw(0x36, 0b11000000); // LEFT MICPGA M route CM to LEFT_M with 20k input impedance + cw(0x34, 0b10000000); // LEFT MICPGA P route IN1L to LEFT_P with 40k input impedance + //cw(0x36, 0b11000000); // LEFT MICPGA M route CM to LEFT_M with 20k input impedance //cw(0x36, 0b00000011); // LEFT MICPGA M route CM to LEFT_M with 20k input impedance - cw(0x37, 0b11000000); // RIGHT MICPGA P route IN1R to RIGHT_P with 20k input impedance - cw(0x39, 0b11000000); // RIGHT MICPGA M route CM to RIGHT_M with 20k input impedance + cw(0x37, 0b10000000); // RIGHT MICPGA P route IN1R to RIGHT_P with 20k input impedance + //cw(0x39, 0b11000000); // RIGHT MICPGA M route CM to RIGHT_M with 20k input impedance //cw(0x39, 0b00000011); // RIGHT MICPGA M route CM to RIGHT_M with 20k input impedance cw(0x3a, 0b00111100); // connect IN2, IN3 weakly to CM @@ -123,7 +135,7 @@ void setup() { cw(0x13, 0x82); // MADC 2 cw(0x14, 0b10000000); // OSR ADC 128 //cw(0x14, 0b01000000); // OSR ADC 128 - cw(0x3d, 0b00000010); // ADC PRB_R3 = 11, PRB_R2 = 10, PRB_R1 = 01 + cw(0x3d, 0b00000001); // ADC PRB_R3 = 11, PRB_R2 = 10, PRB_R1 = 01 cw(0x00, 0x01); // select page 1 cw(0x3d, 0b00000000); // ADC PTM_R4 @@ -135,7 +147,7 @@ void setup() { cw(0x0d, 0x00); // OSR DAC 128 cw(0x0e, 0x80); // OSR DAC 128 cw(0x1b, 0b00000000); // word length 16bits - cw(0x3c, 0b00000011); // PRB_P3 + cw(0x3c, 0b00000001); // PRB_P3 cw(0x00, 0x01); // select page 1 cw(0x7b, 0b00000001); // set REF charging time to 40ms @@ -200,39 +212,11 @@ void setup() { } } + int32_t last = 0; int frame = 0; + void loop() { - int16_t l, r; - //i2s.read16(&l, &r); - - // float sine_pos = (2.0f * M_PI * 1000.0f * (float)frame) / (float)48000; - // l = (int16_t)(sin(sine_pos) * 8192.0f); - // r = l; - - //i2s.write16(l*-1, r*-1); - - // volume += l + r; - // if(millis() - last > 1000){ - // Serial.println(volume); - // volume = 0; - // last = millis(); - - // // STATUS FLAGS - // Serial.println("CODEC STATUS"); - // cw(0x00, 0x00); // select page 0 - // Serial.println("ADC Flags"); - // cr(0x24, 1); - // Serial.println("DAC Flags"); - // cr(0x25, 1); - // Serial.println("P0_42 - Sticky Flags"); - // cr(0x2A, 1); - // Serial.println("P0_43 - Interrupt Flags"); - // cr(0x2B, 1); - // Serial.println("P0_44 - Sticky Flags"); - // cr(0x2C, 1); - - // } frame++; if(frame == 48000) frame = 0; }