├── old ├── _old_esp32_dac_covox_very_simple.ino ├── bak.esp32_dac_covox_very_simple.ino ├── esp32_dss_timing_test1.ino ├── readme.md ├── esp32_dac_covox_stereo.ino ├── oldgarbage.md ├── _old_esp32_dac_covox.ino ├── _old_esp32pico_dac_covox.ino ├── bak.eitoimikunbugi2.0.2ssa_dss_i2s_0.003b.ino ├── dss_test2.ino ├── dss_test3.ino ├── _old_esp32pico_i2s_covox.ino ├── esp32_i2s_covox3_1.0.6.ino ├── _old_esp32pico_i2s_covox_audio-tools.ino ├── esp32_i2s_test_1.0.6.ino ├── esp32_i2s_covox5_2.0.6.ino ├── esp32_i2s_fifo_dss_test1.ino ├── bak.old.covox_i2s_0.002b.ino ├── esp32_i2s_covox4_2.0.6.ino ├── esp32_i2s_covox3_2.0.6.ino ├── testi1.ino ├── old_covox_i2s_40kHz.ino ├── esp32_i2s_dac_timing_test1.ino ├── covox_i2s_40kHz.ino ├── test3.ino ├── bak.old.dss_i2s_0.002b.ino ├── bak.esp32_i2s_dss4_2.0.6.ino ├── _old_esp32pico_i2s_dss.ino ├── dss_test4.ino ├── test2_new.ino ├── esp32_i2s_dss3_1.0.6.ino ├── esp32_i2s_dss4_2.0.6.ino ├── test_first_try_with_pure_esp-idf.c ├── test2.c ├── covox_simple_ESP-IDF-v5.0.x.ino ├── test2.ino ├── _old_esp32pico_i2s_covox-dss.ino ├── _old_esp32_i2s_covox-stereo.ino ├── test3.c ├── test4.c ├── esp32pico_i2s_covox-stereo_test.ino └── arduino-ide_esp32_i2s_covox-dss-stereo.ino └── README.md /old/_old_esp32_dac_covox_very_simple.ino: -------------------------------------------------------------------------------- 1 | // ESP32 internal dac out: Pin 25 / GND (500ohm, 10uF -> OUT+ / 500ohm, 0,1uF -> GND) 2 | 3 | void setup() { 4 | pinMode(16, INPUT); //LPT: 2 (D0) 5 | pinMode(17, INPUT); // 3 (D1) 6 | pinMode(18, INPUT); // 4 (D2) 7 | pinMode(19, INPUT); // 5 (D3) 8 | pinMode(4, INPUT); // 6 (D4) 9 | pinMode(21, INPUT); // 7 (D5) 10 | pinMode(22, INPUT); // 8 (D6) 11 | pinMode(23, INPUT); // 9 (D7) 12 | // GND 13 | 14 | dacWrite(25, 0x80); 15 | } 16 | 17 | void loop() { 18 | uint32_t r = REG_READ(GPIO_IN_REG); 19 | uint8_t value = (r >> 16) | (r & B10000); 20 | dacWrite(26, value); // ~34us? why so slow? output rate is only about 30kHz... 21 | } 22 | -------------------------------------------------------------------------------- /old/bak.esp32_dac_covox_very_simple.ino: -------------------------------------------------------------------------------- 1 | // ESP32 internal dac out: Pin 25 / GND (500ohm, 10uF -> OUT+ / 500ohm, 0,1uF -> GND) 2 | 3 | #include "soc/rtc_wdt.h" 4 | 5 | void setup() { 6 | pinMode(16, INPUT); //LPT: 2 (D0) 7 | pinMode(17, INPUT); // 3 (D1) 8 | pinMode(18, INPUT); // 4 (D2) 9 | pinMode(19, INPUT); // 5 (D3) 10 | pinMode(4, INPUT); // 6 (D4) 11 | pinMode(21, INPUT); // 7 (D5) 12 | pinMode(22, INPUT); // 8 (D6) 13 | pinMode(23, INPUT); // 9 (D7) 14 | // GND 15 | 16 | rtc_wdt_protect_off(); 17 | rtc_wdt_disable(); 18 | } 19 | 20 | void loop() { 21 | noInterrupts(); 22 | while (1) { 23 | int32_t gpio = REG_READ(GPIO_IN_REG); 24 | uint8_t value = (gpio >> 12); 25 | dacWrite(25, value); // ~34us? why so slow? output rate is only about 30kHz... 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /old/esp32_dss_timing_test1.ino: -------------------------------------------------------------------------------- 1 | #include "driver/ledc.h" 2 | 3 | ledc_timer_config_t ledc_timer = { 4 | .speed_mode = LEDC_HIGH_SPEED_MODE, 5 | .duty_resolution = LEDC_TIMER_2_BIT, 6 | .timer_num = LEDC_TIMER_0, 7 | .freq_hz = 7000 8 | }; 9 | 10 | ledc_channel_config_t ledc_channel = { 11 | .gpio_num = 18, 12 | .speed_mode = LEDC_HIGH_SPEED_MODE, 13 | .channel = LEDC_CHANNEL_0, 14 | .timer_sel = LEDC_TIMER_0, 15 | .duty = 2 16 | }; 17 | 18 | volatile uint32_t isr_count; 19 | 20 | void IRAM_ATTR isr() { 21 | isr_count++; 22 | } 23 | 24 | void setup() { 25 | Serial.begin(115200); 26 | while(!Serial); 27 | 28 | ledc_timer_config(&ledc_timer); 29 | ledc_channel_config(&ledc_channel); 30 | 31 | attachInterrupt(18, isr, FALLING); 32 | } 33 | 34 | void loop() { 35 | 36 | static uint32_t old_time, new_time, old_isr_count; 37 | new_time = millis(); 38 | if ( new_time > old_time ) { 39 | uint32_t new_isr_count = isr_count; 40 | Serial.println(new_isr_count-old_isr_count); 41 | old_time += 1000; 42 | old_isr_count = new_isr_count; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /old/readme.md: -------------------------------------------------------------------------------- 1 | ## old pinout: 2 | 3 | ESP32 | LPT (D25) 4 | --- | --- 5 | **Covox:** | 6 | IO13 ⚪ | 2 (D0) 7 | IO14 🐺 | 3 (D1) 8 | IO27 🟡 | 4 (D2) 9 | IO26 🟤 | 5 (D3) 10 | IO9* 🔵 | 6 (D4) 11 | IO10* 🟣 | 7 (D5) 12 | IO18 🌸 | 8 (D6) 13 | IO23 🟢 | 9 (D7) 14 | GND ⚫ | GND (18-25) 15 | **DSS:** | 16 | IO19 ⚪ | 17 (FIFOCLK) (Select Printer_) (PC->DSS) 17 | IO22 🐺 | 10 (FIFOFULL) (ACK) (DSS->PC) 18 | **Stereo-In-1:** | 19 | IO4 🟤 | 1 (Strobe_) (channel select PC->Covox) 20 |   | resistor between IO4 and 5V for external pullup (I have 2.15kohm, 4.7kohm might work too) 21 | **ESP32:** | **I2S DAC:** 22 | 5V 🔴 | Vin (use 5V if possible, more stable) 23 | GND ⚫ | Ground 24 | IO5 🟤 | WCLK 25 | IO33 🟡 | BLCK 26 | IO32 🟢 | DATA 27 | GND | SCK (if GY-PCM5102) 28 | 29 | #### Solve to Compaq Contura 430C (486, 100MHz) problem with stereo-in-1 (random crackling) 30 | - https://www.retrospace.net/download/Compaq%20LTE%20Elite%204-75CX%20Drivers%20and%20Utilities/ 31 | - sp1630.exe, "EPP Support Utility Version 2.00 Rev. A", eppbios.sys (copy EPPBIOS.SYS to C:\CPQDOS\) 32 | - sp2158.exe, "Parallel Port Configuration 1.00 A", setport.exe (copy SETPORT.EXE to C:\CPQDOS\) 33 | 34 | config.sys: 35 | ``` 36 | DEVICEHIGH=C:\CPQDOS\EPPBIOS.SYS 37 | ``` 38 | autoexec.bat: 39 | ``` 40 | C:\CPQDOS\SETPORT.EXE 3 41 | ``` 42 | -------------------------------------------------------------------------------- /old/esp32_dac_covox_stereo.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | volatile uint32_t totalTimerInterruptCounter = 0; 4 | 5 | void IRAM_ATTR isr_sample() { 6 | /*uint32_t r = REG_READ(GPIO_IN_REG); 7 | uint8_t s = (r >> 16) | (r & B10000); 8 | dac_output_voltage(DAC_CHANNEL_2, s);*/ 9 | totalTimerInterruptCounter++; 10 | } 11 | 12 | static void core0_task(void *args) { 13 | /*hw_timer_t * timer = NULL; 14 | timer = timerBegin(0, 80, true); // 80 (using 80 as the prescaler value), we will get a signal with a 1 MHz frequency that will increment the timer counter 1 000 000 times per second. 15 | timerAttachInterrupt(timer, &isr_sample, true); 16 | timerAlarmWrite(timer, 10, true); // 10 -> 100kHz 17 | timerAlarmEnable(timer);*/ 18 | attachInterrupt(34, isr_sample, FALLING); 19 | //attachInterrupt(34, isr_sample, CHANGE); 20 | while (1) { 21 | vTaskDelay(pdMS_TO_TICKS(500)); 22 | } 23 | } 24 | 25 | void setup() { 26 | Serial.begin(115200); 27 | while(!Serial); 28 | 29 | pinMode(16, INPUT); //LPT: 2 (D0) 30 | pinMode(17, INPUT); // 3 (D1) 31 | pinMode(18, INPUT); // 4 (D2) 32 | pinMode(19, INPUT); // 5 (D3) 33 | pinMode(4, INPUT); // 6 (D4) 34 | pinMode(21, INPUT); // 7 (D5) 35 | pinMode(22, INPUT); // 8 (D6) 36 | pinMode(23, INPUT); // 9 (D7) 37 | // GND 38 | pinMode(34, INPUT); // 1 (Strobe_) (channel select) 39 | 40 | dac_output_enable(DAC_CHANNEL_1); 41 | dac_output_voltage(DAC_CHANNEL_1, 0x80); 42 | dac_output_enable(DAC_CHANNEL_2); 43 | dac_output_voltage(DAC_CHANNEL_2, 0x80); 44 | 45 | xTaskCreatePinnedToCore(core0_task, "core0_task", 4096, NULL, 5, NULL, 0); 46 | } 47 | 48 | void loop() { 49 | 50 | static uint32_t old_time, new_time, old_totalTimerInterruptCounter, new_totalTimerInterruptCounter; 51 | new_time = millis(); 52 | if ( (new_time-old_time) > 1000 ) { 53 | 54 | new_totalTimerInterruptCounter = totalTimerInterruptCounter; 55 | Serial.println(new_totalTimerInterruptCounter - old_totalTimerInterruptCounter); // 100100??? 56 | old_totalTimerInterruptCounter = new_totalTimerInterruptCounter; 57 | 58 | old_time = new_time; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /old/oldgarbage.md: -------------------------------------------------------------------------------- 1 | ## Old garbage 2 | 3 | ### ASM 4 | ``` 5 | C:\Users\lehti\AppData\Local\Arduino15\packages\esp32\tools\xtensa-esp32-elf-gcc\esp-2021r2-patch5-8.4.0\bin\xtensa-esp32-elf-objdump.exe -S C:\Users\lehti\OneDrive\Documents\Arduino\esp32pico_i2s_covox-dss\build\esp32.esp32.esp32\esp32pico_i2s_covox-dss.ino.elf > c:\temp\koe.txt 6 | ``` 7 | 8 | 9 | ESP32 DAC output: 25, GND 10 | 11 | (to filter DC out put e.g. 10uF capacitor between 25 and out+. to filter noise put 560ohm resistor between 25 and 10uF capacitor and 0.01...0.1uF capacitor between 560ohm and gnd) 12 | 13 | (if signal is too high, make resistor divider with two resistor (e.g. 2kohm)) 14 | 15 | Old pinout was IO12..IO19 16 | 17 | NOTICE! 18 | At the moment (7.12.2022, newest ESP32 Adruino IDE board 2.0.5) I cannot get internal DAC to work. Workaround: I use ESP32 Arduino IDE board 1.0.6. 19 | 20 | Problems 21 | Commander Keen Dreams doesn't detect this DSS. Why? 22 | Reorganize pins. ESP32 doesn't boot cleanly when connected. Is IO14 and IO15 problem? 23 | 24 | ESP32 is 5V tolerant? https://www.qworqs.com/2021/05/19/are-the-esp32-and-esp8266-5v-tolerant-yes-they-officially-are/ 25 | 26 | And actually there is no 5V from LPT. https://www.epanorama.net/circuits/lptpower.html 27 | 28 | Disable WDT: https://www.esp32.com/viewtopic.php?p=62582 29 | 30 | ``` 31 | GPIO_IN_REG GPIO 0-31 input register 0x3FF4403C RO 32 | GPIO_IN1_REG GPIO 32-39 input register 0x3FF44040 RO 33 | ``` 34 | 35 | Note that the I/O GPIO pads are 0-19, 21-23, 25-27, 32-39, while the output GPIOs are 0-19, 21-23, 25-27, 32-33. GPIO pads 34-39 are input-only. 36 | 37 | ``` 38 | // .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT 39 | buf[i] = (0x80<<24) | (s<<8); // IO26 = 0x80, IO25 = sample 40 | ``` 41 | - ESP32-PICO-KIT with ESP32-PICO-D4 or ESP32 dev board or Wemos D1 mini ESP32 42 | 43 | (for ESP32 internal DAC: Mono 2.5W Class D Audio Amplifier - PAM8302) 44 | 45 | ``` 46 | [speaker] 47 | lpt_dac = disney, covox, ston1, (or none/off) 48 | ``` 49 | 50 | ESP32 | amplifier 51 | --- | --- 52 | (**Amplifier:**) | 53 | 5V | 2-5VDD 54 | GND | Ground 55 | IO25 | Audio In- 56 | IO26 | Audio In+ 57 | 58 | https://emojipedia.org/ 59 | 🔴🟢🟤🟡⚪🔵🟣🟠🌸🐺⚫ 60 | -------------------------------------------------------------------------------- /old/_old_esp32_dac_covox.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | volatile uint32_t totalTimerInterruptCounter = 0; 4 | 5 | void IRAM_ATTR isr_sample() { 6 | uint32_t r1 = REG_READ(GPIO_IN_REG); 7 | uint32_t r2 = REG_READ(GPIO_IN_REG); 8 | uint32_t r3 = REG_READ(GPIO_IN_REG); 9 | uint8_t s1 = (r1 >> 16) | (r1 & B10000); 10 | uint8_t s2 = (r2 >> 16) | (r2 & B10000); 11 | uint8_t s3 = (r3 >> 16) | (r3 & B10000); 12 | if (s1 != s2) s1 = s3; 13 | dac_output_voltage(DAC_CHANNEL_2, s1); 14 | totalTimerInterruptCounter++; 15 | } 16 | 17 | static void core0_task(void *args) { 18 | hw_timer_t * timer = NULL; 19 | timer = timerBegin(0, 80, true); // 80 (using 80 as the prescaler value), we will get a signal with a 1 MHz frequency that will increment the timer counter 1 000 000 times per second. 20 | timerAttachInterrupt(timer, &isr_sample, true); 21 | timerAlarmWrite(timer, 10, true); // 10 -> 100kHz 22 | timerAlarmEnable(timer); 23 | while (1) { 24 | vTaskDelay(pdMS_TO_TICKS(500)); 25 | } 26 | } 27 | 28 | void setup() { 29 | /*Serial.begin(115200); 30 | while(!Serial);*/ 31 | 32 | pinMode(16, INPUT); //LPT: 2 (D0) 33 | pinMode(17, INPUT); // 3 (D1) 34 | pinMode(18, INPUT); // 4 (D2) 35 | pinMode(19, INPUT); // 5 (D3) 36 | pinMode(4, INPUT); // 6 (D4) 37 | pinMode(21, INPUT); // 7 (D5) 38 | pinMode(22, INPUT); // 8 (D6) 39 | pinMode(23, INPUT); // 9 (D7) 40 | // GND 41 | dac_output_enable(DAC_CHANNEL_1); 42 | dac_output_voltage(DAC_CHANNEL_1, 0x80); 43 | dac_output_enable(DAC_CHANNEL_2); 44 | dac_output_voltage(DAC_CHANNEL_2, 0x80); 45 | 46 | xTaskCreatePinnedToCore(core0_task, "core0_task", 4096, NULL, 5, NULL, 0); 47 | } 48 | 49 | void loop() { 50 | 51 | /*static uint32_t old_time, new_time, old_totalTimerInterruptCounter, new_totalTimerInterruptCounter; 52 | new_time = millis(); 53 | if ( (new_time-old_time) > 1000 ) { 54 | 55 | new_totalTimerInterruptCounter = totalTimerInterruptCounter; 56 | Serial.println(new_totalTimerInterruptCounter - old_totalTimerInterruptCounter); // 100100??? 57 | old_totalTimerInterruptCounter = new_totalTimerInterruptCounter; 58 | 59 | old_time = new_time; 60 | }*/ 61 | } 62 | -------------------------------------------------------------------------------- /old/_old_esp32pico_dac_covox.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | volatile uint32_t totalTimerInterruptCounter = 0; 4 | volatile uint8_t conflictCounter = 0; 5 | 6 | void IRAM_ATTR isr_sample() { 7 | uint8_t s1 = REG_READ(GPIO_IN1_REG); 8 | uint8_t s2 = REG_READ(GPIO_IN1_REG); 9 | uint8_t s3 = REG_READ(GPIO_IN1_REG); 10 | if (s1 != s2) { s1 = s3; conflictCounter++; } 11 | dac_output_voltage(DAC_CHANNEL_2, s1); 12 | //dac_output_voltage(DAC_CHANNEL_2, REG_READ(GPIO_IN1_REG)); 13 | totalTimerInterruptCounter++; 14 | } 15 | 16 | static void core0_task(void *args) { 17 | hw_timer_t * timer = NULL; 18 | timer = timerBegin(0, 80, true); // 80 (using 80 as the prescaler value), we will get a signal with a 1 MHz frequency that will increment the timer counter 1 000 000 times per second. 19 | timerAttachInterrupt(timer, &isr_sample, true); 20 | timerAlarmWrite(timer, 10, true); // 10 -> 100kHz 21 | timerAlarmEnable(timer); 22 | while (1) { 23 | vTaskDelay(pdMS_TO_TICKS(500)); 24 | } 25 | } 26 | 27 | void setup() { 28 | Serial.begin(115200); 29 | while(!Serial); 30 | 31 | pinMode(32, INPUT); //LPT: 2 (D0) 32 | pinMode(33, INPUT); // 3 (D1) 33 | pinMode(34, INPUT); // 4 (D2) 34 | pinMode(35, INPUT); // 5 (D3) 35 | pinMode(36, INPUT); // 6 (D4) 36 | pinMode(37, INPUT); // 7 (D5) 37 | pinMode(38, INPUT); // 8 (D6) 38 | pinMode(39, INPUT); // 9 (D7) 39 | // GND 40 | dac_output_enable(DAC_CHANNEL_1); 41 | dac_output_voltage(DAC_CHANNEL_1, 0x80); 42 | dac_output_enable(DAC_CHANNEL_2); 43 | dac_output_voltage(DAC_CHANNEL_2, 0x80); 44 | 45 | xTaskCreatePinnedToCore(core0_task, "core0_task", 4096, NULL, 5, NULL, 0); 46 | } 47 | 48 | void loop() { 49 | 50 | static uint32_t old_time, new_time, old_totalTimerInterruptCounter, new_totalTimerInterruptCounter; 51 | new_time = millis(); 52 | if ( (new_time-old_time) > 1000 ) { 53 | //new_totalTimerInterruptCounter = totalTimerInterruptCounter; 54 | //Serial.println(new_totalTimerInterruptCounter - old_totalTimerInterruptCounter); // 100100??? 55 | //old_totalTimerInterruptCounter = new_totalTimerInterruptCounter; 56 | Serial.println(conflictCounter); 57 | old_time = new_time; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /old/bak.eitoimikunbugi2.0.2ssa_dss_i2s_0.003b.ino: -------------------------------------------------------------------------------- 1 | // ESP32 has DAC on GPIO pins 25 and 26 2 | 3 | #include 4 | 5 | #define FIFOFULL 22 6 | #define FIFOCLK 21 7 | 8 | hw_timer_t * timer = NULL; 9 | 10 | volatile uint8_t fifo_buf[32]; 11 | volatile uint32_t totalTimerInterruptCounter = 0; 12 | volatile uint32_t totalFifoInterruptCounter = 0; 13 | volatile uint8_t front = 0; 14 | volatile uint8_t back = 0; 15 | #define fsize ((uint8_t)(back-front)) // 0-16 16 | 17 | void IRAM_ATTR isr_fifo() { 18 | uint8_t s = (REG_READ(GPIO_IN_REG) >> 12); // read lpt-port state as quick as possible after interrupt is triggered 19 | if (fsize == 15) digitalWrite(FIFOFULL, HIGH); // buffer will be full, rise the full flag 20 | if (fsize < 16) fifo_buf[(back++)&31] = s; // if there is free space in buffer, put sample to buffer 21 | totalFifoInterruptCounter++; 22 | } 23 | 24 | void IRAM_ATTR onTimer() { 25 | uint8_t s; 26 | if (fsize > 0) s = fifo_buf[(front++)&31]; else s = 0x80; // if fifo is empty, play silence (128/0x80) 27 | I2S.write(((uint16_t)s)<<8); // Right channel 28 | I2S.write(0x80<<8); // Left channel // "silence" 29 | totalTimerInterruptCounter++; 30 | if (fsize < 16) digitalWrite(FIFOFULL, LOW); // if there is any free space in buffer, lower the full flag 31 | } 32 | 33 | //------------------------------------------------------------------------------------------------------------------------ 34 | 35 | void setup() { 36 | pinMode(12, INPUT); //LPT: 2 (D0) 37 | pinMode(13, INPUT); // 3 (D1) 38 | pinMode(14, INPUT); // 4 (D2) 39 | pinMode(15, INPUT); // 5 (D3) 40 | pinMode(16, INPUT); // 6 (D4) 41 | pinMode(17, INPUT); // 7 (D5) 42 | pinMode(18, INPUT); // 8 (D6) 43 | pinMode(19, INPUT); // 9 (D7) 44 | // GND 45 | pinMode(21, INPUT); // fifoclock, 17 (Select Printer_) (PC->DSS) 46 | pinMode(22, OUTPUT); digitalWrite(22, LOW); // fifofull, 10 (ACK) (DSS->PC) 47 | pinMode(23, OUTPUT); digitalWrite(23, HIGH); // 5V 48 | pinMode(32, OUTPUT); digitalWrite(32, LOW); // GND 49 | 50 | Serial.begin(115200); 51 | while(Serial.available()); 52 | Serial.println(); Serial.print("--- (compilation date: "); Serial.print(__DATE__); Serial.print(" "); Serial.print(__TIME__); Serial.println(") ---"); 53 | 54 | I2S.begin(ADC_DAC_MODE, 7000, 16); 55 | 56 | timer = timerBegin(0, 3, true); // 3 = prescaler 57 | timerAttachInterrupt(timer, &onTimer, true); 58 | timerAlarmWrite(timer, 3808, true); 59 | // with prescaler 3 and count 3808 internal DAC buffer is fully syncronized with timer interrupt at 7kHz. 60 | timerAlarmEnable(timer); 61 | 62 | // "The rising edge of the pulse on Pin 17 from the printer interface is used to clock data into the FIFO" 63 | attachInterrupt(21, isr_fifo, RISING); 64 | } 65 | 66 | 67 | uint32_t oldtime = 0, newtime = 0; 68 | 69 | void loop() { 70 | 71 | newtime = micros(); 72 | if ( (newtime-oldtime) > 10000 ) { 73 | Serial.println(I2S.availableForWrite()); 74 | oldtime = newtime; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /old/dss_test2.ino: -------------------------------------------------------------------------------- 1 | #include "driver/i2s.h" 2 | 3 | static const i2s_port_t i2s_num = I2S_NUM_0; 4 | 5 | uint32_t buf[16]; 6 | uint8_t vbuf[16]; 7 | uint32_t oldtime = 0, newtime = 0; 8 | 9 | volatile uint32_t totalInterruptCounter = 0; 10 | volatile uint32_t totalSamplesPlayed = 0; 11 | volatile uint8_t fifo_idx = 0; 12 | volatile uint8_t fifofull = 0; 13 | 14 | #define FIFOFULL 22 15 | #define FIFOCLK 21 16 | 17 | void IRAM_ATTR isr_fifo() { 18 | uint8_t value = (REG_READ(GPIO_IN_REG) >> 12); 19 | buf[fifo_idx++] = (value<<24) | (value<<8); 20 | if (fifo_idx > 15) { 21 | digitalWrite(FIFOFULL, HIGH); 22 | fifofull = 1; 23 | } 24 | totalInterruptCounter++; 25 | } 26 | 27 | static const i2s_config_t i2s_config = { 28 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), 29 | .sample_rate = 7000, 30 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 31 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 32 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_MSB), 33 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority = 1 34 | .dma_buf_count = 8, // 8 buffers 35 | .dma_buf_len = 32, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 36 | .use_apll = 0, 37 | .tx_desc_auto_clear = true, 38 | .fixed_mclk = -1 39 | }; 40 | 41 | //------------------------------------------------------------------------------------------------------------------------ 42 | 43 | void setup() { 44 | pinMode(12, INPUT); //LPT: 2 (D0) 45 | pinMode(13, INPUT); // 3 (D1) 46 | pinMode(14, INPUT); // 4 (D2) 47 | pinMode(15, INPUT); // 5 (D3) 48 | pinMode(16, INPUT); // 6 (D4) 49 | pinMode(17, INPUT); // 7 (D5) 50 | pinMode(18, INPUT); // 8 (D6) 51 | pinMode(19, INPUT); // 9 (D7) 52 | // GND 53 | pinMode(23, OUTPUT); digitalWrite(23, HIGH); 54 | pinMode(21, INPUT); // fifoclock, 17 (Select Printer_) (PC->DSS) 55 | pinMode(22, OUTPUT); digitalWrite(22, LOW); // fifofull, 10 (ACK) (DSS->PC) 56 | 57 | Serial.begin(115200); 58 | while(Serial.available()); 59 | Serial.println("alku"); 60 | 61 | i2s_driver_install(i2s_num, &i2s_config, 0, NULL); 62 | //i2s_set_pin(i2s_num, &pin_config); 63 | i2s_set_pin(i2s_num, NULL); 64 | 65 | attachInterrupt(21, isr_fifo, RISING); 66 | 67 | Serial.println("setup():n loppu"); 68 | } 69 | 70 | uint8_t idx = 0; 71 | 72 | void loop() { 73 | 74 | // 1sample = 142,857us (7kHz), full buffer 1/7000*16 = 2,2857ms 75 | 76 | newtime = micros(); 77 | if ((newtime-oldtime)>1000000) { 78 | Serial.print(micros()); Serial.print(" "); Serial.print(totalSamplesPlayed); Serial.print(" "); Serial.println(totalInterruptCounter); 79 | totalSamplesPlayed = 0; 80 | oldtime = newtime; 81 | } 82 | 83 | size_t bytesWritten; 84 | //i2s_write(i2s_num, &buf, idx*4, &bytesWritten, portMAX_DELAY); 85 | delayMicroseconds(140); 86 | if (fifo_idx) { 87 | i2s_write(i2s_num, &buf, 4*fifo_idx, &bytesWritten, portMAX_DELAY); 88 | fifo_idx = 0; 89 | //i2s_write(i2s_num, &buf[fifo_idx--], 4, &bytesWritten, portMAX_DELAY); 90 | digitalWrite(FIFOFULL, LOW); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /old/dss_test3.ino: -------------------------------------------------------------------------------- 1 | #include "driver/i2s.h" 2 | 3 | static const i2s_port_t i2s_num = I2S_NUM_0; 4 | 5 | uint32_t buf[16]; 6 | uint8_t vbuf[16]; 7 | uint32_t oldtime = 0, newtime = 0; 8 | 9 | volatile uint32_t totalInterruptCounter = 0; 10 | volatile uint32_t totalSamplesPlayed = 0; 11 | volatile uint8_t fifo_idx = 0; 12 | volatile uint8_t fifofull = 0; 13 | 14 | #define FIFOFULL 22 15 | #define FIFOCLK 21 16 | 17 | void IRAM_ATTR isr_fifo() { 18 | uint8_t value = (REG_READ(GPIO_IN_REG) >> 12); 19 | buf[fifo_idx++] = (value<<24) | (value<<8); 20 | if (fifo_idx > 15) { 21 | digitalWrite(FIFOFULL, HIGH); 22 | fifofull = 1; 23 | } 24 | totalInterruptCounter++; 25 | } 26 | 27 | static const i2s_config_t i2s_config = { 28 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), 29 | .sample_rate = 7000, 30 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 31 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 32 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_MSB), 33 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority = 1 34 | .dma_buf_count = 4, // 8 buffers 35 | .dma_buf_len = 16, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 36 | .use_apll = 0, 37 | .tx_desc_auto_clear = true, 38 | .fixed_mclk = -1 39 | }; 40 | 41 | //------------------------------------------------------------------------------------------------------------------------ 42 | 43 | void setup() { 44 | pinMode(12, INPUT); //LPT: 2 (D0) 45 | pinMode(13, INPUT); // 3 (D1) 46 | pinMode(14, INPUT); // 4 (D2) 47 | pinMode(15, INPUT); // 5 (D3) 48 | pinMode(16, INPUT); // 6 (D4) 49 | pinMode(17, INPUT); // 7 (D5) 50 | pinMode(18, INPUT); // 8 (D6) 51 | pinMode(19, INPUT); // 9 (D7) 52 | // GND 53 | pinMode(23, OUTPUT); digitalWrite(23, HIGH); 54 | pinMode(21, INPUT); // fifoclock, 17 (Select Printer_) (PC->DSS) 55 | pinMode(22, OUTPUT); digitalWrite(22, LOW); // fifofull, 10 (ACK) (DSS->PC) 56 | 57 | Serial.begin(115200); 58 | while(Serial.available()); 59 | Serial.println("alku"); 60 | 61 | i2s_driver_install(i2s_num, &i2s_config, 0, NULL); 62 | //i2s_set_pin(i2s_num, &pin_config); 63 | i2s_set_pin(i2s_num, NULL); 64 | 65 | attachInterrupt(21, isr_fifo, RISING); 66 | 67 | Serial.println("setup():n loppu"); 68 | } 69 | 70 | void loop() { 71 | 72 | // 1sample = 142,857us (7kHz), full buffer 1/7000*16 = 2,2857ms 73 | 74 | /*newtime = micros(); 75 | if ((newtime-oldtime)>1000000) { 76 | Serial.print(micros()); Serial.print(" "); Serial.print(totalSamplesPlayed); Serial.print(" "); Serial.println(totalInterruptCounter); 77 | totalSamplesPlayed = 0; 78 | oldtime = newtime; 79 | }*/ 80 | 81 | size_t bytesWritten; 82 | //i2s_write(i2s_num, &buf, idx*4, &bytesWritten, portMAX_DELAY); 83 | delayMicroseconds(140); 84 | if (fifo_idx) { 85 | i2s_write(i2s_num, &buf, 4*fifo_idx, &bytesWritten, portMAX_DELAY); 86 | //if (fifofull) { delayMicroseconds(140); fifofull = 0; } 87 | fifo_idx = 0; 88 | //i2s_write(i2s_num, &buf[fifo_idx--], 4, &bytesWritten, portMAX_DELAY); 89 | digitalWrite(FIFOFULL, LOW); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /old/_old_esp32pico_i2s_covox.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define I2S_WS 19 4 | #define I2S_SCK 22 5 | #define I2S_SD 21 6 | #define SAMPLE_RATE 96000 7 | 8 | #define bufferLen 1024 9 | int32_t sBuffer[bufferLen]; 10 | 11 | volatile uint32_t totalTimerInterruptCounter = 0; 12 | volatile uint32_t conflictCounter = 0; 13 | volatile uint8_t buffer_full = 0; 14 | 15 | const i2s_config_t i2s_config = { 16 | .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_TX ), 17 | .sample_rate = SAMPLE_RATE, 18 | .bits_per_sample = i2s_bits_per_sample_t(16), 19 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 20 | .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S), 21 | .intr_alloc_flags = 0, 22 | .dma_buf_count = 2, 23 | .dma_buf_len = bufferLen, 24 | .use_apll = false 25 | }; 26 | 27 | const i2s_pin_config_t pin_config = { 28 | .bck_io_num = I2S_SCK, 29 | .ws_io_num = I2S_WS, 30 | .data_out_num = I2S_SD 31 | }; 32 | 33 | void IRAM_ATTR isr_sample() { 34 | uint8_t s1 = REG_READ(GPIO_IN1_REG); 35 | uint8_t s2 = REG_READ(GPIO_IN1_REG); 36 | uint8_t s3 = REG_READ(GPIO_IN1_REG); 37 | if (s1 != s2) { s1 = s3; conflictCounter++; } 38 | uint16_t out = (s1 - 128) << 6; 39 | uint16_t i = totalTimerInterruptCounter & 1023; 40 | sBuffer[i] = (out << 16) | out; 41 | if (i == 511) buffer_full = 1; 42 | if (i == 1023) buffer_full = 2; 43 | totalTimerInterruptCounter++; 44 | } 45 | 46 | static void core0_task(void *args) { 47 | attachInterrupt(I2S_WS, isr_sample, RISING); 48 | while (1) { 49 | vTaskDelay(pdMS_TO_TICKS(500)); 50 | } 51 | } 52 | 53 | void setup() { 54 | Serial.begin(115200); 55 | while(!Serial); 56 | 57 | pinMode(32, INPUT); //LPT: 2 (D0) 58 | pinMode(33, INPUT); // 3 (D1) 59 | pinMode(34, INPUT); // 4 (D2) 60 | pinMode(35, INPUT); // 5 (D3) 61 | pinMode(36, INPUT); // 6 (D4) 62 | pinMode(37, INPUT); // 7 (D5) 63 | pinMode(38, INPUT); // 8 (D6) 64 | pinMode(39, INPUT); // 9 (D7) 65 | // GND 66 | 67 | i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); 68 | i2s_set_pin(I2S_NUM_0, &pin_config); 69 | i2s_start(I2S_NUM_0); 70 | 71 | xTaskCreatePinnedToCore(core0_task, "core0_task", 4096, NULL, 5, NULL, 0); 72 | } 73 | 74 | void loop() { 75 | 76 | static uint32_t byteswritten = 0, totalSamplesPlayed = 0; 77 | esp_err_t result; 78 | 79 | if (buffer_full) { 80 | size_t bytesWritten; 81 | if (buffer_full == 1) { 82 | result = i2s_write(I2S_NUM_0, &sBuffer[0], sizeof(sBuffer)/2, &bytesWritten, portMAX_DELAY); 83 | } 84 | if (buffer_full == 2) { 85 | result = i2s_write(I2S_NUM_0, &sBuffer[512], sizeof(sBuffer)/2, &bytesWritten, portMAX_DELAY); 86 | } 87 | if (result != ESP_OK) Serial.println("error in i2s_write"); 88 | totalSamplesPlayed += bytesWritten/4; 89 | buffer_full = 0; 90 | } 91 | 92 | static uint32_t old_time, new_time, old_totalTimerInterruptCounter, new_totalTimerInterruptCounter; 93 | new_time = millis(); 94 | if ( (new_time-old_time) > 1000 ) { 95 | //new_totalTimerInterruptCounter = totalTimerInterruptCounter; 96 | //Serial.println(new_totalTimerInterruptCounter - old_totalTimerInterruptCounter); // 100100??? 97 | //old_totalTimerInterruptCounter = new_totalTimerInterruptCounter; 98 | //Serial.println(conflictCounter); 99 | Serial.println(totalSamplesPlayed); 100 | old_time = new_time; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /old/esp32_i2s_covox3_1.0.6.ino: -------------------------------------------------------------------------------- 1 | // Arduino IDE 1.8.19, ESP32 1.0.6 2 | 3 | #include "driver/i2s.h" 4 | 5 | static const i2s_port_t i2s_num = I2S_NUM_0; 6 | 7 | uint32_t buf[1024]; 8 | hw_timer_t * timer = NULL; 9 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 10 | volatile uint32_t totalTimerInterruptCounter = 0; 11 | volatile uint8_t buffer_full = 0; 12 | uint32_t totalSamplesPlayed = 0; 13 | 14 | void IRAM_ATTR onTimer() { 15 | uint8_t s1 = (REG_READ(GPIO_IN_REG) >> 12); 16 | uint8_t s2 = (REG_READ(GPIO_IN_REG) >> 12); 17 | uint8_t s3 = (REG_READ(GPIO_IN_REG) >> 12); 18 | uint8_t value; 19 | if (s1 == s2) 20 | value = s2; 21 | else 22 | value = s3; 23 | uint16_t i = totalTimerInterruptCounter & 1023; 24 | // buf[i] = (value<<24) | (value<<8); 25 | buf[i] = (0x80<<24) | (value<<8); 26 | if (i == 511) buffer_full = 1; 27 | if (i == 1023) buffer_full = 2; 28 | totalTimerInterruptCounter++; 29 | } 30 | 31 | static const i2s_config_t i2s_config = { 32 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), 33 | .sample_rate = 100000, 34 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 35 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 36 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_MSB), 37 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority 38 | .dma_buf_count = 4, // 8 buffers 39 | .dma_buf_len = 512, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 40 | .use_apll = 0, 41 | .tx_desc_auto_clear = true, 42 | .fixed_mclk = -1 43 | }; 44 | 45 | //------------------------------------------------------------------------------------------------------------------------ 46 | 47 | void setup() { 48 | pinMode(12, INPUT); //LPT: 2 (D0) 49 | pinMode(13, INPUT); // 3 (D1) 50 | pinMode(14, INPUT); // 4 (D2) 51 | pinMode(15, INPUT); // 5 (D3) 52 | pinMode(16, INPUT); // 6 (D4) 53 | pinMode(17, INPUT); // 7 (D5) 54 | pinMode(18, INPUT); // 8 (D6) 55 | pinMode(19, INPUT); // 9 (D7) 56 | // GND 57 | pinMode(32, OUTPUT); digitalWrite(32, LOW); // GND 58 | 59 | Serial.begin(115200); 60 | while(Serial.available()); 61 | Serial.println("start"); 62 | 63 | i2s_driver_install(i2s_num, &i2s_config, 0, NULL); 64 | i2s_set_pin(i2s_num, NULL); 65 | 66 | timer = timerBegin(0, 80, true); // 80 (using 80 as the prescaler value), we will get a signal with a 1 MHz frequency that will increment the timer counter 1 000 000 times per second. 67 | timerAttachInterrupt(timer, &onTimer, true); 68 | timerAlarmWrite(timer, 10, true); // 10 -> 100kHz 69 | Serial.println("ennen timerin enablointia"); 70 | timerAlarmEnable(timer); 71 | 72 | Serial.println("end of setup()"); 73 | } 74 | 75 | uint32_t oldtime = 0, newtime = 0; 76 | uint32_t oldintcount = 0, newintcount = 0; 77 | 78 | void loop() { 79 | if (buffer_full) { 80 | size_t bytesWritten; 81 | if (buffer_full == 1) i2s_write(i2s_num, &buf[0], sizeof(buf)/2, &bytesWritten, 100); 82 | if (buffer_full == 2) i2s_write(i2s_num, &buf[512], sizeof(buf)/2, &bytesWritten, 100); 83 | totalSamplesPlayed += bytesWritten/4; 84 | buffer_full = 0; 85 | } 86 | 87 | newtime = micros(); 88 | newintcount = totalTimerInterruptCounter; 89 | if ( (newtime-oldtime) > 10000 ) { 90 | uint32_t ints = newintcount - oldintcount; 91 | //Serial.println(totalInterruptCounter-totalSamplesPlayed); 92 | oldtime = newtime; 93 | oldintcount = newintcount; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /old/_old_esp32pico_i2s_covox_audio-tools.ino: -------------------------------------------------------------------------------- 1 | #include "AudioTools.h" 2 | 3 | #define I2S_WS 19 4 | #define I2S_SCK 22 5 | #define I2S_SD 21 6 | #define SAMPLE_RATE 96000 7 | //#define SAMPLE_RATE 32000 8 | 9 | I2SStream i2s; // final output of decoded stream 10 | VolumeStream volume(i2s); 11 | 12 | #define bufferLen 1024 13 | int32_t sBuffer[bufferLen]; 14 | 15 | volatile uint32_t totalTimerInterruptCounter = 0; 16 | volatile uint32_t conflictCounter = 0; 17 | volatile uint8_t buffer_full = 0; 18 | 19 | void IRAM_ATTR isr_sample() { 20 | uint8_t s1 = REG_READ(GPIO_IN1_REG); 21 | uint8_t s2 = REG_READ(GPIO_IN1_REG); 22 | uint8_t s3 = REG_READ(GPIO_IN1_REG); 23 | if (s1 != s2) { s1 = s3; conflictCounter++; } 24 | //int16_t out = 32767-(s1 << 6); 25 | //uint16_t out = 32767-(s1 << 6); 26 | uint16_t out = 32767-(s1 << 8); 27 | uint16_t i = totalTimerInterruptCounter & 1023; 28 | sBuffer[i] = (out << 16) | out; 29 | if (i == 511) buffer_full = 1; 30 | if (i == 1023) buffer_full = 2; 31 | totalTimerInterruptCounter++; 32 | } 33 | 34 | static void core0_task(void *args) { 35 | attachInterrupt(I2S_WS, isr_sample, RISING); 36 | while (1) { 37 | vTaskDelay(pdMS_TO_TICKS(500)); 38 | } 39 | } 40 | 41 | void setup() { 42 | Serial.begin(115200); 43 | while(!Serial); 44 | 45 | pinMode(32, INPUT); //LPT: 2 (D0) 46 | pinMode(33, INPUT); // 3 (D1) 47 | pinMode(34, INPUT); // 4 (D2) 48 | pinMode(35, INPUT); // 5 (D3) 49 | pinMode(36, INPUT); // 6 (D4) 50 | pinMode(37, INPUT); // 7 (D5) 51 | pinMode(38, INPUT); // 8 (D6) 52 | pinMode(39, INPUT); // 9 (D7) 53 | // GND 54 | 55 | // setup i2s 56 | auto config = i2s.defaultConfig(TX_MODE); 57 | config.sample_rate = SAMPLE_RATE; 58 | config.channels = 2; 59 | config.bits_per_sample = sizeof(int16_t)*8; 60 | config.pin_ws = 19; 61 | config.pin_bck = 22; 62 | config.pin_data = 21; 63 | i2s.begin(config); 64 | 65 | volume.begin(config); // we need to provide the bits_per_sample and channels 66 | volume.setVolume(0.3); 67 | 68 | xTaskCreatePinnedToCore(core0_task, "core0_task", 4096, NULL, 5, NULL, 0); 69 | } 70 | 71 | void loop() { 72 | 73 | static uint32_t byteswritten = 0, totalSamplesPlayed = 0; 74 | esp_err_t result; 75 | 76 | if (buffer_full) { 77 | size_t bytesWritten; 78 | if (buffer_full == 1) { 79 | //result = i2s_write(I2S_NUM_0, &sBuffer[0], sizeof(sBuffer)/2, &bytesWritten, portMAX_DELAY); 80 | //size_t bytesWritten = i2s.write((uint8_t*)&sBuffer[0], sizeof(sBuffer)/2); 81 | size_t bytesWritten = volume.write((uint8_t*)&sBuffer[0], sizeof(sBuffer)/2); 82 | } 83 | if (buffer_full == 2) { 84 | //result = i2s_write(I2S_NUM_0, &sBuffer[512], sizeof(sBuffer)/2, &bytesWritten, portMAX_DELAY); 85 | //size_t bytesWritten = i2s.write((uint8_t*)&sBuffer[512], sizeof(sBuffer)/2); 86 | size_t bytesWritten = volume.write((uint8_t*)&sBuffer[512], sizeof(sBuffer)/2); 87 | } 88 | if (result != ESP_OK) Serial.println("error in i2s_write"); 89 | totalSamplesPlayed += bytesWritten/4; 90 | buffer_full = 0; 91 | } 92 | 93 | static uint32_t old_time, new_time, old_totalTimerInterruptCounter, new_totalTimerInterruptCounter; 94 | new_time = millis(); 95 | if ( (new_time-old_time) > 1000 ) { 96 | //new_totalTimerInterruptCounter = totalTimerInterruptCounter; 97 | //Serial.println(new_totalTimerInterruptCounter - old_totalTimerInterruptCounter); // 100100??? 98 | //old_totalTimerInterruptCounter = new_totalTimerInterruptCounter; 99 | //Serial.println(conflictCounter); 100 | Serial.println(totalSamplesPlayed); 101 | old_time = new_time; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /old/esp32_i2s_test_1.0.6.ino: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | ESP32 Audio DAC Test by TMRh20 - 2020 4 | A simple test using i2S to feed the onboard DAC of ESP32 5 | 6 | */ 7 | 8 | /************************************/ 9 | #include "driver/i2s.h" 10 | 11 | const uint32_t numSamples = 32; 12 | 13 | // Buffer for a sine wave 14 | uint8_t dacBuffer[numSamples]; 15 | 16 | // Boolean variable to control audio output based on Serial input 17 | bool outputAudio = false; 18 | /************************************/ 19 | // Function to load data into the sine wave buffer 20 | void sineSetup(); 21 | /************************************/ 22 | 23 | void setup() { 24 | 25 | Serial.begin(115200); 26 | Serial.println("ESP32 Audio DAC Test"); 27 | sineSetup(); 28 | 29 | // Set the I2S peripheral to MASTER, TX (DAC Output), using built in DAC 30 | i2s_mode_t myMode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN); 31 | 32 | // This configures the i2s peripheral, configure as necessary... 33 | i2s_config_t i2s_cfg = { 34 | .mode = (i2s_mode_t)myMode, 35 | .sample_rate = 32000, // The format of the signal using ADC_BUILT_IN 36 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB 37 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 38 | .communication_format = I2S_COMM_FORMAT_I2S_LSB, 39 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, 40 | .dma_buf_count = 4, 41 | .dma_buf_len = numSamples, 42 | .use_apll = false, 43 | .tx_desc_auto_clear = false, 44 | .fixed_mclk = 0 45 | }; 46 | 47 | i2s_driver_install(I2S_NUM_0, &i2s_cfg, 0, NULL); 48 | 49 | i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); 50 | i2s_set_clk(I2S_NUM_0, 32000, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO); 51 | i2s_stop(I2S_NUM_0); 52 | } 53 | 54 | /************************************/ 55 | 56 | void loop() { 57 | 58 | if (outputAudio) { 59 | size_t bytesWritten = 0; 60 | //esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, size_t src_bits, size_t aim_bits, size_t *bytes_written, TickType_t ticks_to_wait); 61 | i2s_write_expand(I2S_NUM_0, &dacBuffer[0], numSamples, 8, 16, &bytesWritten, 500 / portTICK_PERIOD_MS); 62 | } 63 | 64 | if (Serial.available()) { 65 | char c = Serial.read(); 66 | if (c == '1') { 67 | outputAudio = !outputAudio; 68 | if (outputAudio) { 69 | Serial.println("Enable Output"); 70 | sineSetup(); 71 | i2s_start(I2S_NUM_0); 72 | } else { 73 | Serial.println("Disable Output"); 74 | i2s_stop(I2S_NUM_0); 75 | } 76 | }else{ 77 | if(c == '2'){ 78 | //audioPlay(); 79 | } 80 | } 81 | } 82 | //loadBuffer(); 83 | } 84 | 85 | /************************************/ 86 | 87 | void sineSetup() { 88 | 89 | dacBuffer[0] = 0x40; 90 | dacBuffer[1] = 0x4c; 91 | dacBuffer[2] = 0x58; 92 | dacBuffer[3] = 0x63; 93 | dacBuffer[4] = 0x6c; 94 | dacBuffer[5] = 0x74; 95 | dacBuffer[6] = 0x7a; 96 | dacBuffer[7] = 0x7e; 97 | dacBuffer[8] = 0x7f; 98 | dacBuffer[9] = 0x7e; 99 | dacBuffer[10] = 0x7a; 100 | dacBuffer[11] = 0x74; 101 | dacBuffer[12] = 0x6c; 102 | dacBuffer[13] = 0x63; 103 | dacBuffer[14] = 0x58; 104 | dacBuffer[15] = 0x4c; 105 | dacBuffer[16] = 0x40; 106 | dacBuffer[17] = 0x33; 107 | dacBuffer[18] = 0x27; 108 | dacBuffer[19] = 0x1c; 109 | dacBuffer[20] = 0x13; 110 | dacBuffer[21] = 0xb; 111 | dacBuffer[22] = 0x5; 112 | dacBuffer[23] = 0x1; 113 | dacBuffer[24] = 0x0; 114 | dacBuffer[25] = 0x1; 115 | dacBuffer[26] = 0x5; 116 | dacBuffer[27] = 0xb; 117 | dacBuffer[28] = 0x13; 118 | dacBuffer[29] = 0x1c; 119 | dacBuffer[30] = 0x27; 120 | dacBuffer[31] = 0x33; 121 | } 122 | -------------------------------------------------------------------------------- /old/esp32_i2s_covox5_2.0.6.ino: -------------------------------------------------------------------------------- 1 | // Arduino IDE 2.0.3, ESP32 2.0.6 (based on ESP-IDF 4.4.3) 2 | 3 | #include "driver/i2s.h" 4 | 5 | uint32_t buf[1024]; // same memory never accessed location same time from interrupt and mainloop, so no need for volatile 6 | volatile uint8_t buffer_full = 0; 7 | volatile uint32_t totalTimerInterruptCounter = 0; 8 | uint32_t totalSamplesPlayed = 0; 9 | 10 | void IRAM_ATTR isr_sample() { 11 | uint32_t r1 = REG_READ(GPIO_IN_REG); 12 | uint32_t r2 = REG_READ(GPIO_IN_REG); 13 | uint32_t r3 = REG_READ(GPIO_IN_REG); 14 | uint8_t s1 = (r1 >> 16) | (r1 & B10000); 15 | uint8_t s2 = (r2 >> 16) | (r2 & B10000); 16 | uint8_t s3 = (r3 >> 16) | (r3 & B10000); 17 | uint8_t value; 18 | if (s1 == s2) 19 | value = s2; 20 | else 21 | value = s3; 22 | uint16_t i = totalTimerInterruptCounter & 1023; 23 | buf[i] = (0x80<<24) | (value<<8); 24 | if (i == 511) buffer_full = 1; 25 | if (i == 1023) buffer_full = 2; 26 | totalTimerInterruptCounter++; 27 | } 28 | 29 | static void core0_task(void *args) { 30 | hw_timer_t * timer = NULL; 31 | timer = timerBegin(0, 80, true); // 80 (using 80 as the prescaler value), we will get a signal with a 1 MHz frequency that will increment the timer counter 1 000 000 times per second. 32 | timerAttachInterrupt(timer, &isr_sample, true); 33 | timerAlarmWrite(timer, 10, true); // 10 -> 100kHz 34 | timerAlarmEnable(timer); 35 | while (1) { 36 | vTaskDelay(pdMS_TO_TICKS(500)); 37 | } 38 | } 39 | 40 | static const i2s_config_t i2s_config = { 41 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), 42 | .sample_rate = 100000, 43 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 44 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 45 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_LSB), 46 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority 47 | .dma_buf_count = 4, // 8 buffers 48 | .dma_buf_len = 512, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 49 | .use_apll = 0, 50 | .tx_desc_auto_clear = true, 51 | .fixed_mclk = -1 52 | }; 53 | 54 | //------------------------------------------------------------------------------------------------------------------------ 55 | 56 | void setup() { 57 | pinMode(16, INPUT); //LPT: 2 (D0) 58 | pinMode(17, INPUT); // 3 (D1) 59 | pinMode(18, INPUT); // 4 (D2) 60 | pinMode(19, INPUT); // 5 (D3) 61 | pinMode(4, INPUT); // 6 (D4) 62 | pinMode(21, INPUT); // 7 (D5) 63 | pinMode(22, INPUT); // 8 (D6) 64 | pinMode(23, INPUT); // 9 (D7) 65 | // GND 66 | 67 | /*Serial.begin(115200); 68 | while(Serial.available()); 69 | Serial.println("start");*/ 70 | 71 | i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); 72 | i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); 73 | 74 | xTaskCreatePinnedToCore(core0_task, "core0_task", 4096, NULL, 5, NULL, 0); 75 | } 76 | 77 | uint32_t oldtime = 0, newtime = 0; 78 | uint32_t oldintcount = 0, newintcount = 0; 79 | 80 | void loop() { 81 | if (buffer_full) { 82 | size_t bytesWritten; 83 | if (buffer_full == 1) i2s_write(I2S_NUM_0, &buf[0], sizeof(buf)/2, &bytesWritten, 100); 84 | if (buffer_full == 2) i2s_write(I2S_NUM_0, &buf[512], sizeof(buf)/2, &bytesWritten, 100); 85 | totalSamplesPlayed += bytesWritten/4; 86 | buffer_full = 0; 87 | } 88 | 89 | /*newtime = micros(); 90 | newintcount = totalTimerInterruptCounter; 91 | if ( (newtime-oldtime) > 10000 ) { 92 | uint32_t ints = newintcount - oldintcount; 93 | //Serial.println(totalInterruptCounter-totalSamplesPlayed); 94 | Serial.println(buf[0]); 95 | oldtime = newtime; 96 | oldintcount = newintcount; 97 | }*/ 98 | 99 | } 100 | -------------------------------------------------------------------------------- /old/esp32_i2s_fifo_dss_test1.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "driver/ledc.h" 3 | 4 | #define SAMPLE_RATE 28000 5 | 6 | #define BUFFER_SIZE 1024 7 | int32_t I2S_buffer[BUFFER_SIZE*2]; 8 | const int32_t* buf1 = &I2S_buffer[0]; 9 | const int32_t* buf2 = &I2S_buffer[BUFFER_SIZE]; 10 | #define BUFFER_SIZE_IN_BYTES BUFFER_SIZE*4 11 | volatile uint8_t buffer_full = 0; 12 | volatile uint32_t samples_in = 0; 13 | volatile uint32_t isr_count = 0; 14 | 15 | ledc_timer_config_t ledc_timer = { 16 | .speed_mode = LEDC_HIGH_SPEED_MODE, 17 | .duty_resolution = LEDC_TIMER_2_BIT, 18 | .timer_num = LEDC_TIMER_0, 19 | .freq_hz = 7000 20 | }; 21 | 22 | ledc_channel_config_t ledc_channel = { 23 | .gpio_num = 18, 24 | .speed_mode = LEDC_HIGH_SPEED_MODE, 25 | .channel = LEDC_CHANNEL_0, 26 | .timer_sel = LEDC_TIMER_0, 27 | .duty = 2 28 | }; 29 | 30 | static const i2s_config_t i2s_config_dac = { 31 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), 32 | .sample_rate = SAMPLE_RATE, 33 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 34 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 35 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_LSB), 36 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority 37 | .dma_buf_count = 2, // 2 buffers 38 | .dma_buf_len = BUFFER_SIZE, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 39 | .use_apll = false, 40 | .tx_desc_auto_clear = true, 41 | .fixed_mclk = -1 42 | }; 43 | 44 | volatile uint32_t wscount; 45 | 46 | void IRAM_ATTR isr_sample() { 47 | static int32_t buffer_ptr = 0; 48 | //read sample 49 | //uint32_t r = REG_READ(GPIO_IN_REG); 50 | //uint8_t s = (r >> 16) | (r & B10000); 51 | //uint32_t out = (0x80<<24) | (s<<8); 52 | uint32_t out = 0; 53 | I2S_buffer[buffer_ptr++] = out; 54 | I2S_buffer[buffer_ptr++] = out; 55 | I2S_buffer[buffer_ptr++] = out; 56 | I2S_buffer[buffer_ptr++] = out; 57 | buffer_ptr = buffer_ptr & 1023; 58 | //buffer_ptr = (buffer_ptr + 1) & 1023; 59 | if (buffer_ptr == BUFFER_SIZE) buffer_full = 1; 60 | if (buffer_ptr == 0) buffer_full = 2; 61 | //samples_in++; 62 | samples_in += 4; 63 | isr_count++; 64 | } 65 | 66 | void setup() { 67 | /* 68 | pinMode(16, INPUT); //LPT: 2 (D0) 69 | pinMode(17, INPUT); // 3 (D1) 70 | pinMode(18, INPUT); // 4 (D2) 71 | pinMode(19, INPUT); // 5 (D3) 72 | pinMode(4, INPUT); // 6 (D4) 73 | pinMode(21, INPUT); // 7 (D5) 74 | pinMode(22, INPUT); // 8 (D6) 75 | pinMode(23, INPUT); // 9 (D7) 76 | */ 77 | Serial.begin(115200); 78 | while(!Serial); 79 | 80 | i2s_driver_install(I2S_NUM_0, &i2s_config_dac, 0, NULL); 81 | i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); 82 | 83 | ledc_timer_config(&ledc_timer); 84 | ledc_channel_config(&ledc_channel); 85 | 86 | attachInterrupt(18, isr_sample, RISING); 87 | 88 | } 89 | 90 | void loop() { 91 | 92 | size_t bytesOut; 93 | esp_err_t result; 94 | static uint32_t byteswritten = 0; 95 | 96 | if (buffer_full) { 97 | if (buffer_full == 1) result = i2s_write(I2S_NUM_0, buf1, BUFFER_SIZE_IN_BYTES, &bytesOut, portMAX_DELAY); 98 | if (buffer_full == 2) result = i2s_write(I2S_NUM_0, buf2, BUFFER_SIZE_IN_BYTES, &bytesOut, portMAX_DELAY); 99 | if (result != ESP_OK) Serial.println("error in i2s_write"); 100 | buffer_full = 0; 101 | byteswritten += bytesOut; 102 | } 103 | 104 | static uint32_t old_time, new_time, old_isr_count; 105 | new_time = millis(); 106 | if ( new_time > old_time ) { 107 | uint32_t new_isr_count = isr_count; 108 | Serial.println(new_isr_count - old_isr_count); 109 | old_isr_count = new_isr_count; 110 | Serial.println(samples_in-(byteswritten/4)); 111 | old_time += 1000; 112 | } 113 | //delay(10); 114 | } 115 | -------------------------------------------------------------------------------- /old/bak.old.covox_i2s_0.002b.ino: -------------------------------------------------------------------------------- 1 | // Arduino IDE 1.8.19, ESP32 1.0.6 2 | 3 | #include "driver/i2s.h" 4 | 5 | static const i2s_port_t i2s_num = I2S_NUM_0; 6 | 7 | uint32_t buf[1024]; 8 | hw_timer_t * timer = NULL; 9 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 10 | volatile uint32_t totalInterruptCounter = 0; 11 | volatile uint8_t buffer_full = 0; 12 | uint32_t totalSamplesPlayed = 0; 13 | 14 | void IRAM_ATTR onTimer() { 15 | uint8_t s1 = (REG_READ(GPIO_IN_REG) >> 12); 16 | uint8_t s2 = (REG_READ(GPIO_IN_REG) >> 12); 17 | uint8_t s3 = (REG_READ(GPIO_IN_REG) >> 12); 18 | uint8_t value; 19 | if (s1 == s2) 20 | value = s2; 21 | else 22 | value = s3; 23 | uint16_t i = totalInterruptCounter & 1023; 24 | buf[i] = (value<<24) | (value<<8); 25 | if (i == 511) buffer_full = 1; 26 | if (i == 1023) buffer_full = 2; 27 | //portENTER_CRITICAL_ISR(&timerMux); 28 | totalInterruptCounter++; 29 | //portEXIT_CRITICAL_ISR(&timerMux); 30 | } 31 | 32 | static const i2s_config_t i2s_config = { 33 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), 34 | .sample_rate = 100000, 35 | //.sample_rate = 7000, 36 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 37 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 38 | //.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), 39 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_MSB), 40 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority 41 | .dma_buf_count = 4, // 8 buffers 42 | .dma_buf_len = 512, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 43 | .use_apll = 0, 44 | .tx_desc_auto_clear = true, 45 | .fixed_mclk = -1 46 | }; 47 | 48 | //------------------------------------------------------------------------------------------------------------------------ 49 | 50 | void setup() { 51 | pinMode(12, INPUT); //LPT: 2 (D0) 52 | pinMode(13, INPUT); // 3 (D1) 53 | pinMode(14, INPUT); // 4 (D2) 54 | pinMode(15, INPUT); // 5 (D3) 55 | pinMode(16, INPUT); // 6 (D4) 56 | pinMode(17, INPUT); // 7 (D5) 57 | pinMode(18, INPUT); // 8 (D6) 58 | pinMode(19, INPUT); // 9 (D7) 59 | // GND 60 | pinMode(32, OUTPUT); digitalWrite(32, LOW); // GND 61 | 62 | Serial.begin(115200); 63 | while(Serial.available()); 64 | Serial.println("start"); 65 | 66 | i2s_driver_install(i2s_num, &i2s_config, 0, NULL); 67 | //i2s_set_pin(i2s_num, &pin_config); 68 | i2s_set_pin(i2s_num, NULL); 69 | 70 | timer = timerBegin(0, 80, true); // 80 (using 80 as the prescaler value), we will get a signal with a 1 MHz frequency that will increment the timer counter 1 000 000 times per second. 71 | //timer = timerBegin(0, 3, true); 72 | timerAttachInterrupt(timer, &onTimer, true); 73 | timerAlarmWrite(timer, 10, true); // 10 -> 100kHz 74 | //timerAlarmWrite(timer, 3808, true); 75 | Serial.println("ennen timerin enablointia"); 76 | timerAlarmEnable(timer); 77 | 78 | Serial.println("end of setup()"); 79 | } 80 | 81 | uint32_t oldtime = 0, newtime = 0; 82 | uint32_t oldintcount = 0, newintcount = 0; 83 | 84 | void loop() { 85 | if (buffer_full) { 86 | size_t bytesWritten; 87 | if (buffer_full == 1) i2s_write(i2s_num, &buf[0], sizeof(buf)/2, &bytesWritten, 100); 88 | if (buffer_full == 2) i2s_write(i2s_num, &buf[512], sizeof(buf)/2, &bytesWritten, 100); 89 | totalSamplesPlayed += bytesWritten/4; 90 | buffer_full = 0; 91 | } 92 | 93 | newtime = micros(); 94 | newintcount = totalInterruptCounter; 95 | if ( (newtime-oldtime) > 10000 ) { 96 | uint32_t ints = newintcount - oldintcount; 97 | //Serial.println(totalInterruptCounter-totalSamplesPlayed); 98 | oldtime = newtime; 99 | oldintcount = newintcount; 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /old/esp32_i2s_covox4_2.0.6.ino: -------------------------------------------------------------------------------- 1 | // Arduino IDE 2.0.3, ESP32 2.0.6 (based on ESP-IDF 4.4.3) 2 | 3 | #include "driver/i2s.h" 4 | 5 | static const i2s_port_t i2s_num = I2S_NUM_0; 6 | 7 | uint32_t buf[1024]; 8 | hw_timer_t * timer = NULL; 9 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 10 | volatile uint32_t totalTimerInterruptCounter = 0; 11 | volatile uint8_t buffer_full = 0; 12 | uint32_t totalSamplesPlayed = 0; 13 | 14 | void IRAM_ATTR onTimer() { 15 | uint32_t r1 = REG_READ(GPIO_IN_REG); 16 | uint32_t r2 = REG_READ(GPIO_IN_REG); 17 | uint32_t r3 = REG_READ(GPIO_IN_REG); 18 | uint8_t s1 = (r1 >> 16) | (r1 & B10000); 19 | uint8_t s2 = (r2 >> 16) | (r2 & B10000); 20 | uint8_t s3 = (r3 >> 16) | (r3 & B10000); 21 | uint8_t value; 22 | if (s1 == s2) 23 | value = s2; 24 | else 25 | value = s3; 26 | uint16_t i = totalTimerInterruptCounter & 1023; 27 | // buf[i] = (value<<24) | (value<<8); 28 | buf[i] = (0x80<<24) | (value<<8); 29 | if (i == 511) buffer_full = 1; 30 | if (i == 1023) buffer_full = 2; 31 | totalTimerInterruptCounter++; 32 | } 33 | 34 | static const i2s_config_t i2s_config = { 35 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), 36 | .sample_rate = 100000, 37 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 38 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 39 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_LSB), 40 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority 41 | .dma_buf_count = 4, // 8 buffers 42 | .dma_buf_len = 512, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 43 | .use_apll = 0, 44 | .tx_desc_auto_clear = true, 45 | .fixed_mclk = -1 46 | }; 47 | 48 | //------------------------------------------------------------------------------------------------------------------------ 49 | 50 | void setup() { 51 | pinMode(16, INPUT); //LPT: 2 (D0) 52 | pinMode(17, INPUT); // 3 (D1) 53 | pinMode(18, INPUT); // 4 (D2) 54 | pinMode(19, INPUT); // 5 (D3) 55 | pinMode(4, INPUT); // 6 (D4) 56 | pinMode(21, INPUT); // 7 (D5) 57 | pinMode(22, INPUT); // 8 (D6) 58 | pinMode(23, INPUT); // 9 (D7) 59 | // GND 60 | // pinMode(32, OUTPUT); digitalWrite(32, LOW); // GND 61 | 62 | Serial.begin(115200); 63 | while(Serial.available()); 64 | Serial.println("start"); 65 | 66 | i2s_driver_install(i2s_num, &i2s_config, 0, NULL); 67 | i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); 68 | 69 | timer = timerBegin(0, 80, true); // 80 (using 80 as the prescaler value), we will get a signal with a 1 MHz frequency that will increment the timer counter 1 000 000 times per second. 70 | timerAttachInterrupt(timer, &onTimer, true); 71 | timerAlarmWrite(timer, 10, true); // 10 -> 100kHz 72 | Serial.println("ennen timerin enablointia"); 73 | timerAlarmEnable(timer); 74 | 75 | Serial.println("end of setup()"); 76 | } 77 | 78 | uint32_t oldtime = 0, newtime = 0; 79 | uint32_t oldintcount = 0, newintcount = 0; 80 | 81 | void loop() { 82 | if (buffer_full) { 83 | size_t bytesWritten; 84 | if (buffer_full == 1) i2s_write(i2s_num, &buf[0], sizeof(buf)/2, &bytesWritten, 100); 85 | if (buffer_full == 2) i2s_write(i2s_num, &buf[512], sizeof(buf)/2, &bytesWritten, 100); 86 | totalSamplesPlayed += bytesWritten/4; 87 | buffer_full = 0; 88 | } 89 | 90 | newtime = micros(); 91 | newintcount = totalTimerInterruptCounter; 92 | if ( (newtime-oldtime) > 10000 ) { 93 | uint32_t ints = newintcount - oldintcount; 94 | //Serial.println(totalInterruptCounter-totalSamplesPlayed); 95 | Serial.println(buf[0]); 96 | oldtime = newtime; 97 | oldintcount = newintcount; 98 | } 99 | 100 | /*uint32_t r = REG_READ(GPIO_IN_REG); 101 | uint8_t s = (r >> 16) | (r&B10000); 102 | Serial.println(s,BIN); 103 | delay(500);*/ 104 | } 105 | -------------------------------------------------------------------------------- /old/esp32_i2s_covox3_2.0.6.ino: -------------------------------------------------------------------------------- 1 | // Arduino IDE 1.8.19, ESP32 1.0.6 2 | 3 | #include "driver/i2s.h" 4 | 5 | static const i2s_port_t i2s_num = I2S_NUM_0; 6 | 7 | uint32_t buf[1024]; 8 | hw_timer_t * timer = NULL; 9 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 10 | volatile uint32_t totalTimerInterruptCounter = 0; 11 | volatile uint8_t buffer_full = 0; 12 | uint32_t totalSamplesPlayed = 0; 13 | 14 | void IRAM_ATTR onTimer() { 15 | uint8_t s1 = (REG_READ(GPIO_IN_REG) >> 12); 16 | uint8_t s2 = (REG_READ(GPIO_IN_REG) >> 12); 17 | uint8_t s3 = (REG_READ(GPIO_IN_REG) >> 12); 18 | uint8_t value; 19 | if (s1 == s2) 20 | value = s2; 21 | else 22 | value = s3; 23 | uint16_t i = totalTimerInterruptCounter & 1023; 24 | // buf[i] = (value<<24) | (value<<8); 25 | buf[i] = (0x80<<24) | (value<<8); 26 | if (i == 511) buffer_full = 1; 27 | if (i == 1023) buffer_full = 2; 28 | totalTimerInterruptCounter++; 29 | } 30 | 31 | static const i2s_config_t i2s_config = { 32 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), 33 | .sample_rate = 100000, 34 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 35 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 36 | //.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_MSB), 37 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_LSB), 38 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority 39 | .dma_buf_count = 4, // 8 buffers 40 | .dma_buf_len = 512, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 41 | /*.use_apll = false, 42 | .tx_desc_auto_clear = false, 43 | .fixed_mclk = 0*/ 44 | .use_apll = 0, 45 | .tx_desc_auto_clear = true, 46 | .fixed_mclk = -1 47 | }; 48 | 49 | //------------------------------------------------------------------------------------------------------------------------ 50 | 51 | void setup() { 52 | pinMode(12, INPUT); //LPT: 2 (D0) 53 | pinMode(13, INPUT); // 3 (D1) 54 | pinMode(14, INPUT); // 4 (D2) 55 | pinMode(15, INPUT); // 5 (D3) 56 | pinMode(16, INPUT); // 6 (D4) 57 | pinMode(17, INPUT); // 7 (D5) 58 | pinMode(18, INPUT); // 8 (D6) 59 | pinMode(19, INPUT); // 9 (D7) 60 | // GND 61 | pinMode(32, OUTPUT); digitalWrite(32, LOW); // GND 62 | 63 | Serial.begin(115200); 64 | while(Serial.available()); 65 | Serial.println("start"); 66 | 67 | i2s_driver_install(i2s_num, &i2s_config, 0, NULL); 68 | //i2s_set_pin(i2s_num, NULL); 69 | i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); 70 | /*i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); 71 | i2s_set_clk(I2S_NUM_0, 100000, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO); 72 | i2s_start(I2S_NUM_0);*/ 73 | 74 | timer = timerBegin(0, 80, true); // 80 (using 80 as the prescaler value), we will get a signal with a 1 MHz frequency that will increment the timer counter 1 000 000 times per second. 75 | timerAttachInterrupt(timer, &onTimer, true); 76 | timerAlarmWrite(timer, 10, true); // 10 -> 100kHz 77 | Serial.println("ennen timerin enablointia"); 78 | timerAlarmEnable(timer); 79 | 80 | Serial.println("end of setup()"); 81 | } 82 | 83 | uint32_t oldtime = 0, newtime = 0; 84 | uint32_t oldintcount = 0, newintcount = 0; 85 | 86 | void loop() { 87 | if (buffer_full) { 88 | size_t bytesWritten; 89 | if (buffer_full == 1) i2s_write(i2s_num, &buf[0], sizeof(buf)/2, &bytesWritten, 100); 90 | if (buffer_full == 2) i2s_write(i2s_num, &buf[512], sizeof(buf)/2, &bytesWritten, 100); 91 | totalSamplesPlayed += bytesWritten/4; 92 | buffer_full = 0; 93 | } 94 | 95 | newtime = micros(); 96 | newintcount = totalTimerInterruptCounter; 97 | if ( (newtime-oldtime) > 10000 ) { 98 | uint32_t ints = newintcount - oldintcount; 99 | //Serial.println(totalInterruptCounter-totalSamplesPlayed); 100 | oldtime = newtime; 101 | oldintcount = newintcount; 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /old/testi1.ino: -------------------------------------------------------------------------------- 1 | // As we're using an 8 bit value for the DAC 0-255 (256 parts) that means for us 2 | // there are 256 'bits' to a complete circle not 360 (as in degrees) or even 2PI Radians 3 | // (There are 2*PI Radians in a circle and computers love to work in Radians!) 4 | // The computer works in radians for SIN, COSINE etc. so we must convert our 0 -255 value 5 | // to radians, the comments in the code show this. 6 | 7 | #include "soc/rtc_wdt.h" 8 | 9 | volatile uint8_t interruptCounter = 0; 10 | volatile uint32_t totalInterruptCounter = 0; 11 | 12 | volatile int SineValues[256]; // an array to store our values for sine 13 | 14 | hw_timer_t * timer = NULL; 15 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 16 | 17 | void IRAM_ATTR onTimer() { 18 | portENTER_CRITICAL_ISR(&timerMux); 19 | interruptCounter++; 20 | totalInterruptCounter++; 21 | portEXIT_CRITICAL_ISR(&timerMux); 22 | 23 | int32_t gpio = REG_READ(GPIO_IN_REG); 24 | uint8_t value = (gpio >> 12); 25 | dacWrite(25, value); 26 | 27 | //dacWrite(25, SineValues[interruptCounter]); 28 | 29 | } 30 | 31 | 32 | void setup() 33 | { 34 | Serial.begin(115200); 35 | while(Serial.available()); 36 | 37 | Serial.println("alku"); 38 | 39 | /*pinMode(12, INPUT_PULLUP); 40 | pinMode(13, INPUT_PULLUP); 41 | pinMode(14, INPUT_PULLUP); 42 | pinMode(15, INPUT_PULLUP); 43 | pinMode(16, INPUT_PULLUP); 44 | pinMode(17, INPUT_PULLUP); 45 | pinMode(18, INPUT_PULLUP); 46 | pinMode(19, INPUT_PULLUP);*/ 47 | pinMode(12, INPUT); 48 | pinMode(13, INPUT); 49 | pinMode(14, INPUT); 50 | pinMode(15, INPUT); 51 | pinMode(16, INPUT); 52 | pinMode(17, INPUT); 53 | pinMode(18, INPUT); 54 | pinMode(19, INPUT); 55 | float ConversionFactor=(2*PI)/256; // convert my 0-255 bits in a circle to radians 56 | // there are 2 x PI radians in a circle hence the 2*PI 57 | // Then divide by 256 to get the value in radians 58 | // for one of my 0-255 bits. 59 | float RadAngle; // Angle in Radians 60 | for(int MyAngle=0;MyAngle<256;MyAngle++) { 61 | RadAngle=MyAngle*ConversionFactor*4; // 8 bit angle converted to radians 62 | SineValues[MyAngle]=(sin(RadAngle)*127)+128; // get the sine of this angle and 'shift' up so 63 | } 64 | 65 | 66 | /*timer = timerBegin(0, 80, true); // 80 (using 80 as the prescaler value), we will get a signal with a 1 MHz frequency that will increment the timer counter 1 000 000 times per second. 67 | timerAttachInterrupt(timer, &onTimer, true); 68 | timerAlarmWrite(timer, 50, true); // 1MHz / 50 = 20kHz // 1MHz / 20 = 50kHz //1MHz / 100 = 10kHz? 69 | Serial.println("ennen timerin enablointia"); 70 | timerAlarmEnable(timer);*/ 71 | 72 | rtc_wdt_protect_off(); 73 | rtc_wdt_disable(); 74 | 75 | Serial.println("setupin loppu"); 76 | } 77 | 78 | uint8_t i = 0; 79 | 80 | void loop() 81 | { 82 | noInterrupts(); 83 | while (1) { 84 | int32_t gpio = REG_READ(GPIO_IN_REG); 85 | uint8_t value = (gpio >> 12); 86 | dacWrite(25, value); 87 | } 88 | //for(int i=0;i<256;i++) 89 | // dacWrite(25,SineValues[i++]); 90 | 91 | /*int t1, t2; 92 | t1 = micros(); 93 | for (int c=0; c<1000; c++) dacWrite(25, 0); 94 | t2 = micros(); 95 | Serial.println(t2-t1);*/ 96 | /*uint32_t value = totalInterruptCounter; 97 | if ( value > 20000 ) { 98 | Serial.print("Total number: "); 99 | Serial.println(value); 100 | portENTER_CRITICAL(&timerMux); 101 | totalInterruptCounter = 0; 102 | portEXIT_CRITICAL(&timerMux); 103 | }*/ 104 | //Serial.println(totalInterruptCounter); 105 | // delay(1000); 106 | /*if (interruptCounter > 0) { 107 | 108 | portENTER_CRITICAL(&timerMux); 109 | interruptCounter--; 110 | portEXIT_CRITICAL(&timerMux); 111 | 112 | totalInterruptCounter++; 113 | 114 | Serial.print("An interrupt as occurred. Total number: "); 115 | Serial.println(totalInterruptCounter); 116 | 117 | }*/ 118 | 119 | /*uint32_t gpio = REG_READ(GPIO_IN_REG); 120 | uint8_t value = (gpio >> 12); 121 | Serial.println(value); 122 | delay(50);*/ 123 | /*uint32_t gpio = REG_READ(GPIO_IN_REG); 124 | Serial.println(gpio, BIN); 125 | delay(50);*/ 126 | 127 | } 128 | -------------------------------------------------------------------------------- /old/old_covox_i2s_40kHz.ino: -------------------------------------------------------------------------------- 1 | #include "driver/i2s.h" 2 | 3 | static const i2s_port_t i2s_num = I2S_NUM_0; 4 | 5 | TaskHandle_t Task1; 6 | hw_timer_t * timer = NULL; 7 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 8 | 9 | uint32_t buf[1024]; 10 | volatile uint32_t totalInterruptCounter = 0; 11 | volatile uint8_t buffer_full = 0; 12 | uint32_t totalSamplesPlayed = 0; 13 | 14 | void IRAM_ATTR onTimer() { 15 | uint8_t s1 = (REG_READ(GPIO_IN_REG) >> 12); 16 | uint8_t s2 = (REG_READ(GPIO_IN_REG) >> 12); 17 | uint8_t s3 = (REG_READ(GPIO_IN_REG) >> 12); 18 | uint8_t value; 19 | if (s1 == s2) 20 | value = s2; 21 | else 22 | value = s3; 23 | uint16_t i = totalInterruptCounter & 1023; 24 | buf[i] = (value<<24) | (value<<8); 25 | if (i == 511) buffer_full = 1; 26 | if (i == 1023) buffer_full = 2; 27 | //portENTER_CRITICAL_ISR(&timerMux); 28 | totalInterruptCounter++; 29 | //portEXIT_CRITICAL_ISR(&timerMux); 30 | } 31 | 32 | static const i2s_config_t i2s_config = { 33 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), 34 | .sample_rate = 40000, 35 | //.sample_rate = 7000, 36 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 37 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 38 | //.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), 39 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_MSB), 40 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority 41 | .dma_buf_count = 4, // 8 buffers 42 | .dma_buf_len = 512, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 43 | .use_apll = 0, 44 | .tx_desc_auto_clear = true, 45 | .fixed_mclk = -1 46 | }; 47 | 48 | //------------------------------------------------------------------------------------------------------------------------ 49 | 50 | void setup() { 51 | pinMode(12, INPUT); //LPT: 2 (D0) 52 | pinMode(13, INPUT); // 3 (D1) 53 | pinMode(14, INPUT); // 4 (D2) 54 | pinMode(15, INPUT); // 5 (D3) 55 | pinMode(16, INPUT); // 6 (D4) 56 | pinMode(17, INPUT); // 7 (D5) 57 | pinMode(18, INPUT); // 8 (D6) 58 | pinMode(19, INPUT); // 9 (D7) 59 | // GND 60 | pinMode(32, OUTPUT); digitalWrite(32, LOW); // GND 61 | 62 | Serial.begin(115200); 63 | while(Serial.available()); 64 | Serial.println("start"); 65 | 66 | i2s_driver_install(i2s_num, &i2s_config, 0, NULL); 67 | //i2s_set_pin(i2s_num, &pin_config); 68 | i2s_set_pin(i2s_num, NULL); 69 | 70 | //timer = timerBegin(0, 2, true); // 80 (using 80 as the prescaler value), we will get a signal with a 1 MHz frequency that will increment the timer counter 1 000 000 times per second. 71 | timer = timerBegin(0, 2, true); // 0,1,2 kertoimet sama asia? 0 ei toimi? 72 | timerAttachInterrupt(timer, &onTimer, true); 73 | //timerAlarmWrite(timer, 604, true); // 44kHz 3: 800/700 laskee, 600 nousee 4, 610 laskee 4, 605 laskee alle 1, 604 nousee alle 1 74 | //timerAlarmWrite(timer, 907, true); // 44kHz 2/1: 905/906 nousee alle 1, 907 vähenee alle 1 75 | timerAlarmWrite(timer, 997, true); // 40kHz 2: 997 spot on! 76 | //timerAlarmWrite(timer, 3808, true); 77 | //timerAlarmWrite(timer, 3808, true); 78 | 79 | Serial.println("before enabling timer"); 80 | timerAlarmEnable(timer); 81 | 82 | Serial.println("end of setup()"); 83 | } 84 | 85 | uint32_t oldtime = 0, newtime = 0; 86 | uint32_t oldintcount = 0, newintcount = 0; 87 | 88 | void loop() { 89 | if (buffer_full) { 90 | size_t bytesWritten; 91 | if (buffer_full == 1) i2s_write(i2s_num, &buf[0], sizeof(buf)/2, &bytesWritten, 100); 92 | if (buffer_full == 2) i2s_write(i2s_num, &buf[512], sizeof(buf)/2, &bytesWritten, 100); 93 | //i2s_write(i2s_num, &buf[0], sizeof(buf)/2, &bytesWritten, portMAX_DELAY); 94 | totalSamplesPlayed += bytesWritten/4; 95 | buffer_full = 0; 96 | } 97 | 98 | newtime = micros(); 99 | newintcount = totalInterruptCounter; 100 | if ( (newtime-oldtime) > 10000 ) { 101 | uint32_t ints = newintcount - oldintcount; 102 | //Serial.println(samples_count); 103 | //Serial.println(totalInterruptCounter-totalSamplesPlayed); 104 | oldtime = newtime; 105 | oldintcount = newintcount; 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /old/esp32_i2s_dac_timing_test1.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define I2S_WS 33 4 | #define I2S_SD 23 5 | #define I2S_SCK 32 6 | //#define SAMPLE_RATE 7000 7 | #define SAMPLE_RATE 48000 8 | 9 | #define bufferLen 1024 10 | int16_t sBuffer[bufferLen]; 11 | 12 | const i2s_config_t i2s_config = { 13 | .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX ), 14 | .sample_rate = SAMPLE_RATE, 15 | .bits_per_sample = i2s_bits_per_sample_t(16), 16 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 17 | .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S), 18 | .intr_alloc_flags = 0, 19 | .dma_buf_count = 8, 20 | .dma_buf_len = bufferLen, 21 | .use_apll = false 22 | }; 23 | 24 | const i2s_pin_config_t pin_config = { 25 | .bck_io_num = I2S_SCK, 26 | .ws_io_num = I2S_WS, 27 | .data_out_num = -1, //I2S_SD_tx, 28 | .data_in_num = I2S_SD 29 | }; 30 | 31 | static const i2s_config_t i2s_config_dac = { 32 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), 33 | .sample_rate = SAMPLE_RATE, 34 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 35 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 36 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_LSB), 37 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority 38 | .dma_buf_count = 8, // 8 buffers 39 | .dma_buf_len = bufferLen, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 40 | .use_apll = false, 41 | .tx_desc_auto_clear = true, 42 | .fixed_mclk = -1 43 | }; 44 | 45 | volatile uint32_t wscount; 46 | 47 | void IRAM_ATTR isr_ws() { 48 | wscount++; 49 | } 50 | 51 | //static QueueHandle_t i2s_event_queue_dac; 52 | 53 | void setup() { 54 | Serial.begin(115200); 55 | while(!Serial); 56 | 57 | i2s_driver_install(I2S_NUM_1, &i2s_config, 0, NULL); 58 | i2s_set_pin(I2S_NUM_1, &pin_config); 59 | i2s_start(I2S_NUM_1); 60 | 61 | i2s_driver_install(I2S_NUM_0, &i2s_config_dac, 0, NULL); 62 | //i2s_driver_install(I2S_NUM_0, &i2s_config_dac, 10, &i2s_event_queue_dac); 63 | i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); 64 | 65 | attachInterrupt(I2S_WS, isr_ws, RISING); 66 | 67 | } 68 | 69 | void loop() { 70 | 71 | size_t bytesIn, bytesOut; 72 | static uint32_t bytesread = 0, byteswritten = 0; 73 | esp_err_t result; 74 | 75 | /*result = i2s_read(I2S_NUM_1, &sBuffer, bufferLen, &bytesIn, portMAX_DELAY); 76 | //result = i2s_read(I2S_NUM_1, &sBuffer, bufferLen, &bytesIn, 1); 77 | if (result != ESP_OK) Serial.println("error in i2s_read"); 78 | bytesread += bytesIn;*/ 79 | 80 | /*result = i2s_write(I2S_NUM_0, &sBuffer, bufferLen, &bytesOut, portMAX_DELAY); 81 | i2s_event_t i2s_event; 82 | if (xQueueReceive(i2s_event_queue_dac, &i2s_event, portMAX_DELAY) != pdFALSE) { 83 | if (i2s_event.type == I2S_EVENT_TX_Q_OVF) Serial.println("*TX_Q_OVF*"); 84 | if (i2s_event.type == I2S_EVENT_TX_DONE) Serial.println("*TX_DONE*"); 85 | }*/ 86 | 87 | //result = i2s_write(I2S_NUM_0, &sBuffer, bytesIn, &bytesOut, portMAX_DELAY); 88 | //result = i2s_write(I2S_NUM_0, &sBuffer, bytesIn, &bytesOut, 1); 89 | result = i2s_write(I2S_NUM_0, &sBuffer, bufferLen, &bytesOut, portMAX_DELAY); 90 | if (result != ESP_OK) Serial.println("error in i2s_write"); 91 | byteswritten += bytesOut; 92 | 93 | static uint32_t old_time, new_time, old_samplecnt_dac, old_samplecnt_i2s, old_samplecnt_i2s_isr; 94 | new_time = millis(); 95 | if ( (new_time-old_time) > 1000 ) { 96 | //Serial.println(bytesread-byteswritten); 97 | //Serial.println(bytesread-(wscount*4)); 98 | //Serial.println((wscount*4)-byteswritten); 99 | /*Serial.print("dac: "); Serial.println((byteswritten - old_samplecnt_dac)/4); 100 | old_samplecnt_dac = byteswritten; 101 | Serial.print("i2s: "); Serial.println((bytesread - old_samplecnt_i2s)/4); 102 | old_samplecnt_i2s = bytesread; 103 | Serial.print("i2s_isr: "); Serial.println(((wscount*4) - old_samplecnt_i2s_isr)/4); 104 | old_samplecnt_i2s_isr = (wscount*4);*/ 105 | 106 | //Serial.print("i2s: "); Serial.println(bytesread); 107 | //Serial.print("i2s_isr: "); Serial.println(wscount*4); 108 | //Serial.println(bytesread-(wscount*4)); // vakio 109 | Serial.println(byteswritten-(wscount*4)); // ei vakio :( (3-4s välein 1samplen heitto; dac on nopeampi kuin i2s)(apll kääntää tilanteen) 110 | 111 | //Serial.println(wscount); 112 | old_time = new_time; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /old/covox_i2s_40kHz.ino: -------------------------------------------------------------------------------- 1 | 2 | #include "driver/i2s.h" 3 | 4 | static const i2s_port_t i2s_num = I2S_NUM_0; 5 | 6 | uint32_t buf[1024]; 7 | hw_timer_t * timer = NULL; 8 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 9 | volatile uint32_t totalInterruptCounter = 0; 10 | volatile uint8_t buffer_full = 0; 11 | uint32_t totalSamplesPlayed = 0; 12 | 13 | void IRAM_ATTR onTimer() { 14 | uint8_t s1 = (REG_READ(GPIO_IN_REG) >> 12); 15 | uint8_t s2 = (REG_READ(GPIO_IN_REG) >> 12); 16 | uint8_t s3 = (REG_READ(GPIO_IN_REG) >> 12); 17 | uint8_t value; 18 | if (s1 == s2) 19 | value = s2; 20 | else 21 | value = s3; 22 | uint16_t i = totalInterruptCounter & 1023; 23 | //buf[i] = (value<<24) | (value<<8); 24 | int16_t sample = value - 128; 25 | //int16_t sample = (value - 128)<<8; 26 | buf[i] = (sample<<24) | (sample<<8); 27 | //buf[i] = (sample<<16) | (sample<<0); 28 | //buf[i] = (value<<16) | (value<<0); 29 | if (i == 511) buffer_full = 1; 30 | if (i == 1023) buffer_full = 2; 31 | //portENTER_CRITICAL_ISR(&timerMux); 32 | totalInterruptCounter++; 33 | //portEXIT_CRITICAL_ISR(&timerMux); 34 | } 35 | 36 | static const i2s_config_t i2s_config = { 37 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), 38 | .sample_rate = 40000, 39 | //.sample_rate = 7000, 40 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 41 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 42 | .communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_I2S, 43 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority 44 | .dma_buf_count = 4, // 8 buffers 45 | .dma_buf_len = 512, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 46 | .use_apll = 0, 47 | .tx_desc_auto_clear = true, 48 | .fixed_mclk = -1 49 | }; 50 | 51 | static const i2s_pin_config_t pin_config = { 52 | .bck_io_num = 26,//26, // The bit clock connectiom, goes to pin 27 of ESP32 53 | .ws_io_num = 25,//25, // Word select, also known as word select or left right clock 54 | .data_out_num = 27,//22, // Data out from the ESP32, connect to DIN on 38357A 55 | .data_in_num = I2S_PIN_NO_CHANGE // we are not interested in I2S data into the ESP32 56 | }; 57 | 58 | //------------------------------------------------------------------------------------------------------------------------ 59 | 60 | void setup() { 61 | pinMode(12, INPUT); //LPT: 2 (D0) 62 | pinMode(13, INPUT); // 3 (D1) 63 | pinMode(14, INPUT); // 4 (D2) 64 | pinMode(15, INPUT); // 5 (D3) 65 | pinMode(16, INPUT); // 6 (D4) 66 | pinMode(17, INPUT); // 7 (D5) 67 | pinMode(18, INPUT); // 8 (D6) 68 | pinMode(19, INPUT); // 9 (D7) 69 | // GND 70 | pinMode(32, OUTPUT); digitalWrite(32, LOW); // GND 71 | 72 | Serial.begin(115200); 73 | while(Serial.available()); 74 | Serial.println("start"); 75 | 76 | i2s_driver_install(i2s_num, &i2s_config, 0, NULL); 77 | i2s_set_pin(i2s_num, &pin_config); 78 | //i2s_set_pin(i2s_num, NULL); 79 | 80 | timer = timerBegin(0, 80, true); // 80 (using 80 as the prescaler value), we will get a signal with a 1 MHz frequency that will increment the timer counter 1 000 000 times per second. 81 | //timer = timerBegin(0, 3, true); 82 | timerAttachInterrupt(timer, &onTimer, true); 83 | timerAlarmWrite(timer, 25, true); // 25 -> 40kHz, 50 -> 20kHz, 10 -> 100kHz 84 | //timerAlarmWrite(timer, 3808, true); 85 | Serial.println("ennen timerin enablointia"); 86 | timerAlarmEnable(timer); 87 | 88 | Serial.println("end of setup()"); 89 | } 90 | 91 | uint32_t oldtime = 0, newtime = 0; 92 | uint32_t oldintcount = 0, newintcount = 0; 93 | 94 | void loop() { 95 | if (buffer_full) { 96 | size_t bytesWritten; 97 | if (buffer_full == 1) i2s_write(i2s_num, &buf[0], sizeof(buf)/2, &bytesWritten, 100); 98 | if (buffer_full == 2) i2s_write(i2s_num, &buf[512], sizeof(buf)/2, &bytesWritten, 100); 99 | totalSamplesPlayed += bytesWritten/4; 100 | buffer_full = 0; 101 | } 102 | 103 | newtime = micros(); 104 | newintcount = totalInterruptCounter; 105 | if ( (newtime-oldtime) > 10000 ) { 106 | uint32_t ints = newintcount - oldintcount; 107 | //Serial.println(totalInterruptCounter-totalSamplesPlayed); 108 | oldtime = newtime; 109 | oldintcount = newintcount; 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /old/test3.ino: -------------------------------------------------------------------------------- 1 | #include "driver/i2s.h" 2 | 3 | static const i2s_port_t i2s_num = I2S_NUM_0; 4 | 5 | uint32_t buf[4096]; 6 | 7 | hw_timer_t * timer = NULL; 8 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 9 | 10 | volatile uint32_t totalInterruptCounter = 0; 11 | uint32_t totalSamplesPlayed = 0; 12 | 13 | void IRAM_ATTR onTimer() { 14 | int8_t s1 = (REG_READ(GPIO_IN_REG) >> 12); 15 | int8_t s2 = (REG_READ(GPIO_IN_REG) >> 12); 16 | int8_t s3 = (REG_READ(GPIO_IN_REG) >> 12); 17 | uint8_t value; 18 | if (s1 == s2) 19 | value = s2; 20 | else 21 | value = s3; 22 | uint16_t i = totalInterruptCounter & 4095; // 0-2047 23 | buf[i] = (value<<24) | (value<<8); 24 | 25 | //portENTER_CRITICAL_ISR(&timerMux); 26 | totalInterruptCounter++; 27 | //portEXIT_CRITICAL_ISR(&timerMux); 28 | } 29 | 30 | static const i2s_config_t i2s_config = { 31 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), 32 | //.sample_rate = 44100, 33 | .sample_rate = 100000, 34 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 35 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 36 | //.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), 37 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_MSB), 38 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority = 1 39 | .dma_buf_count = 8, // 8 buffers 40 | .dma_buf_len = 1024, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 41 | .use_apll = 0, 42 | .tx_desc_auto_clear = true, 43 | .fixed_mclk = -1 44 | }; 45 | 46 | //------------------------------------------------------------------------------------------------------------------------ 47 | 48 | 49 | void setup() { 50 | pinMode(12, INPUT); //LPT: 2 (D0) 51 | pinMode(13, INPUT); // 3 (D1) 52 | pinMode(14, INPUT); // 4 (D2) 53 | pinMode(15, INPUT); // 5 (D3) 54 | pinMode(16, INPUT); // 6 (D4) 55 | pinMode(17, INPUT); // 7 (D5) 56 | pinMode(18, INPUT); // 8 (D6) 57 | pinMode(19, INPUT); // 9 (D7) 58 | // GND 59 | 60 | Serial.begin(115200); 61 | while(Serial.available()); 62 | Serial.println("alku"); 63 | 64 | timer = timerBegin(0, 80, true); // 80 (using 80 as the prescaler value), we will get a signal with a 1 MHz frequency that will increment the timer counter 1 000 000 times per second. 65 | timerAttachInterrupt(timer, &onTimer, true); 66 | timerAlarmWrite(timer, 10, true); // 25 -> 40kHz, 1MHz / 50 = 20kHz // 1MHz / 20 = 50kHz //1MHz / 100 = 10kHz? // 16 -> 62.5kHz 67 | Serial.println("ennen timerin enablointia"); 68 | timerAlarmEnable(timer); 69 | delay(500); 70 | 71 | i2s_driver_install(i2s_num, &i2s_config, 0, NULL); 72 | //i2s_set_pin(i2s_num, &pin_config); 73 | i2s_set_pin(i2s_num, NULL); 74 | 75 | Serial.println("setup():n loppu"); 76 | } 77 | 78 | 79 | 80 | void loop() 81 | { 82 | 83 | size_t bytesWritten; 84 | //portENTER_CRITICAL(&timerMux); 85 | uint32_t i = totalInterruptCounter; 86 | //portEXIT_CRITICAL(&timerMux); 87 | uint16_t c = i & 4095; // 0-4095 88 | uint16_t b = sizeof(buf)/4; // frames per buffer 89 | uint32_t t1 = micros(); 90 | if (c < 1024) 91 | i2s_write(i2s_num, &buf[2048], b, &bytesWritten, portMAX_DELAY); 92 | else if (c < 2048) 93 | i2s_write(i2s_num, &buf[3072], b, &bytesWritten, portMAX_DELAY); 94 | else if (c < 3071) 95 | i2s_write(i2s_num, &buf[0], b, &bytesWritten, portMAX_DELAY); 96 | else 97 | i2s_write(i2s_num, &buf[1024], b, &bytesWritten, portMAX_DELAY); 98 | uint32_t t2 = micros(); 99 | 100 | if (bytesWritten != b) { 101 | Serial.println("VIRHE!"); 102 | delay(1000); 103 | } 104 | totalSamplesPlayed += bytesWritten/4; 105 | //totalSamplesPlayed += 256; 106 | Serial.print("t: "); Serial.print(t2-t1); Serial.print(" I-S: "); Serial.println(totalInterruptCounter-totalSamplesPlayed); 107 | //Serial.print("B: "); Serial.print(bytesWritten); Serial.print(" I: "); Serial.print(totalInterruptCounter); Serial.print(" S: ");Serial.println(totalSamplesPlayed); 108 | //Serial.print("B: "); Serial.print(bytesWritten); Serial.print(" I: "); Serial.print(totalInterruptCounter); Serial.print(" S: ");Serial.println(totalSamplesPlayed); 109 | //Serial.print("B: "); Serial.print(bytesWritten); Serial.print(" I-S: "); Serial.println(totalInterruptCounter-totalSamplesPlayed+100); 110 | //Serial.print("b: "); Serial.print(b); Serial.print(" I-S: "); Serial.println(totalInterruptCounter-totalSamplesPlayed); 111 | //Serial.println(totalInterruptCounter-totalSamplesPlayed); 112 | 113 | } 114 | -------------------------------------------------------------------------------- /old/bak.old.dss_i2s_0.002b.ino: -------------------------------------------------------------------------------- 1 | // Arduino IDE 1.8.19, ESP32 1.0.6 2 | 3 | #include "driver/i2s.h" 4 | 5 | static const i2s_port_t i2s_num = I2S_NUM_0; 6 | 7 | #define FIFOFULL 22 8 | #define FIFOCLK 21 9 | 10 | uint32_t buf[512]; 11 | hw_timer_t * timer = NULL; 12 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 13 | volatile uint32_t totalInterruptCounter = 0; 14 | volatile uint32_t totalFifoInterruptCounter = 0; 15 | volatile uint8_t buffer_full = 0; 16 | volatile uint8_t front = 0; 17 | volatile uint8_t back = 0; 18 | volatile uint8_t fifo_buf[256]; 19 | uint32_t totalSamplesPlayed = 0; 20 | #define fsize ((uint8_t)(back-front)) // 0-16 21 | 22 | void IRAM_ATTR isr_fifo() { 23 | if (fsize < 16) fifo_buf[back++] = (REG_READ(GPIO_IN_REG) >> 12); 24 | if (fsize > 15) digitalWrite(FIFOFULL, HIGH); 25 | totalFifoInterruptCounter++; 26 | //portENTER_CRITICAL_ISR(&timerMux); 27 | //portEXIT_CRITICAL_ISR(&timerMux); 28 | } 29 | 30 | void IRAM_ATTR onTimer() { 31 | uint8_t s; 32 | if (fsize > 0) s = fifo_buf[front++]; else s = 128; 33 | if (fsize < 15) digitalWrite(FIFOFULL, LOW); 34 | uint16_t i = totalInterruptCounter & 511; 35 | buf[i] = (s<<24) | (s<<8); 36 | if (i == 255) buffer_full = 1; 37 | if (i == 511) buffer_full = 2; 38 | totalInterruptCounter++; 39 | } 40 | 41 | static const i2s_config_t i2s_config = { 42 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), 43 | .sample_rate = 7000, 44 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 45 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 46 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_MSB), 47 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority 48 | .dma_buf_count = 2, // 8 buffers 49 | .dma_buf_len = 256, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 50 | .use_apll = 0, 51 | .tx_desc_auto_clear = true, 52 | .fixed_mclk = -1 53 | }; 54 | 55 | //------------------------------------------------------------------------------------------------------------------------ 56 | 57 | void setup() { 58 | pinMode(12, INPUT); //LPT: 2 (D0) 59 | pinMode(13, INPUT); // 3 (D1) 60 | pinMode(14, INPUT); // 4 (D2) 61 | pinMode(15, INPUT); // 5 (D3) 62 | pinMode(16, INPUT); // 6 (D4) 63 | pinMode(17, INPUT); // 7 (D5) 64 | pinMode(18, INPUT); // 8 (D6) 65 | pinMode(19, INPUT); // 9 (D7) 66 | // GND 67 | pinMode(21, INPUT); // fifoclock, 17 (Select Printer_) (PC->DSS) 68 | pinMode(22, OUTPUT); digitalWrite(22, LOW); // fifofull, 10 (ACK) (DSS->PC) 69 | pinMode(23, OUTPUT); digitalWrite(23, HIGH); // 5V 70 | pinMode(32, OUTPUT); digitalWrite(32, LOW); // GND 71 | 72 | Serial.begin(115200); 73 | while(Serial.available()); 74 | Serial.println("start"); 75 | 76 | i2s_driver_install(i2s_num, &i2s_config, 0, NULL); 77 | //i2s_set_pin(i2s_num, &pin_config); 78 | i2s_set_pin(i2s_num, NULL); 79 | 80 | timer = timerBegin(0, 3, true); // 1 = prescaler 81 | timerAttachInterrupt(timer, &onTimer, true); 82 | timerAlarmWrite(timer, 3808, true); // 80 000 000 / 11 428 = 7000.350018...kHz, 80 000 000 / 11 429 = 6999.7375...kHz 83 | //prescaler 1 & count 1000 -> 39903...39904, (2:lla sama?!), pre3&c1000->26633, 11429 -> 3499, 84 | //pre3&c3805->7005..7006, pre3&c3810->6996..6997, pre3&3809->6998..6999 85 | //pre3&c3809 puskuri tyhjenee ehkä 1 sample per sekuntti. 86 | //pre3&c3808 puskuri pysyy synkissä 7kHz:n DAC:n kanssa!!! 87 | Serial.println("before timer enable"); 88 | timerAlarmEnable(timer); 89 | 90 | attachInterrupt(21, isr_fifo, RISING); 91 | //attachInterrupt(21, isr_fifo, FALLING); 92 | 93 | Serial.println("end of setup()"); 94 | } 95 | 96 | 97 | uint32_t oldtime = 0, newtime = 0; 98 | 99 | void loop() { 100 | 101 | if (buffer_full) { 102 | size_t bytesWritten; 103 | if (buffer_full == 1) i2s_write(i2s_num, &buf[0], sizeof(buf)/2, &bytesWritten, 100); 104 | if (buffer_full == 2) i2s_write(i2s_num, &buf[256], sizeof(buf)/2, &bytesWritten, 100); 105 | totalSamplesPlayed += bytesWritten/4; 106 | buffer_full = 0; 107 | //Serial.print(front); Serial.print(" "); Serial.println(back); 108 | } 109 | 110 | newtime = micros(); 111 | //if ( (newtime-oldtime) > 1000000 ) { 112 | if ( (newtime-oldtime) > 10000 ) { 113 | //Serial.println(totalInterruptCounter-totalSamplesPlayed); 114 | //Serial.println(fsize); 115 | oldtime = newtime; 116 | //for (int i = 0; i < 100; i++) Serial.println((uint8_t)(buf[i] >> 8)); 117 | //Serial.print(front); Serial.print(" "); Serial.println(back); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /old/bak.esp32_i2s_dss4_2.0.6.ino: -------------------------------------------------------------------------------- 1 | // Arduino IDE 2.0.3, ESP32 2.0.6 (based ESP-IDF 4.4.3) 2 | 3 | /*#include "soc/rtc_wdt.h" 4 | #include "soc/timer_group_struct.h" 5 | #include "soc/timer_group_reg.h"*/ 6 | 7 | #define FIFOFULL 32 // fifofull, 10 (ACK) (DSS->PC) 8 | #define FIFOCLK 35 // fifoclock, 17 (Select Printer_) (PC->DSS) 9 | 10 | hw_timer_t * timer = NULL; 11 | volatile uint8_t buf[256]; 12 | volatile uint8_t front = 0; 13 | volatile uint8_t back = 0; 14 | volatile uint32_t samples_played = 0; 15 | volatile uint32_t samples_not_played = 0; 16 | volatile uint32_t totalFifoInterruptCounter = 0; 17 | 18 | #define fcnt ((uint8_t)(back-front)) // 0-16 19 | 20 | void IRAM_ATTR onTimer() { 21 | if (fcnt == 0) { // fifo empty 22 | samples_not_played++; 23 | return; 24 | } 25 | uint8_t s = buf[front++]; // koska sampleja fifossa, soita sample ja päivitä pointteri 26 | digitalWrite(FIFOFULL, LOW); // there is now at least one place free in buffer, lower the full flag 27 | //uint32_t value = (0x80 << 24) | (s << 8); 28 | dacWrite(26, s); 29 | samples_played++; 30 | } 31 | 32 | /*static void dac_output_task(void *args) 33 | { 34 | while (1) { 35 | const TickType_t xDelay = 240000000/7000; 36 | vTaskDelay(xDelay); //240 000 000 / 7 000 = 34 285,714 37 | if (fcnt == 0) { // fifo empty 38 | samples_not_played++; 39 | continue; 40 | } 41 | uint8_t s = buf[front++]; // koska sampleja fifossa, soita sample ja päivitä pointteri 42 | digitalWrite(FIFOFULL, LOW); // there is now at least one place free in buffer, lower the full flag 43 | uint32_t value = (0x80 << 24) | (s << 8); 44 | dacWrite(26, value); 45 | 46 | //dacWrite(26, value); 47 | samples_played++; 48 | //vTaskDelay(pdMS_TO_TICKS(500)); 49 | //const TickType_t xDelay = 240000000/7000; 50 | //vTaskDelay(xDelay); //240 000 000 / 7 000 = 34 285,714 51 | //vTaskDelay(34286); //240 000 000 / 7 000 = 34 285,714 52 | //ei delayta jos samplea ei soitettu? 53 | 54 | } 55 | }*/ 56 | 57 | void IRAM_ATTR isr_fifo() { 58 | // tulee sample 59 | totalFifoInterruptCounter++; 60 | if (fcnt == 16) return; 61 | uint32_t r = REG_READ(GPIO_IN_REG); 62 | uint8_t s = (r >> 16) | (r & B10000); 63 | buf[back++] = s; // if there is free space in buffer, put sample to buffer 64 | if (fcnt == 16) { 65 | digitalWrite(FIFOFULL, HIGH); // buffer full, rise the full flag 66 | //return; 67 | } 68 | } 69 | 70 | 71 | //------------------------------------------------------------------------------------------------------------------------ 72 | 73 | void setup() { 74 | pinMode(16, INPUT); //LPT: 2 (D0) 75 | pinMode(17, INPUT); // 3 (D1) 76 | pinMode(18, INPUT); // 4 (D2) 77 | pinMode(19, INPUT); // 5 (D3) 78 | pinMode(4, INPUT); // 6 (D4) 79 | pinMode(21, INPUT); // 7 (D5) 80 | pinMode(22, INPUT); // 8 (D6) 81 | pinMode(23, INPUT); // 9 (D7) 82 | // GND 83 | pinMode(FIFOCLK, INPUT); // fifoclock, 17 (Select Printer_) (PC->DSS) 84 | pinMode(FIFOFULL, OUTPUT); digitalWrite(FIFOFULL, LOW); // fifofull, 10 (ACK) (DSS->PC) 85 | 86 | Serial.begin(115200); 87 | while(Serial.available()); 88 | Serial.println(); Serial.print("--- (compilation date: "); Serial.print(__DATE__); Serial.print(" "); Serial.print(__TIME__); Serial.println(") ---"); 89 | 90 | //uint32_t t1 = portGET_RUN_TIME_COUNTER_VALUE(); 91 | dacWrite(25, 0x80); dacWrite(26, 0x80); 92 | 93 | //xTaskCreatePinnedToCore(dac_output_task, "dac_chan0_output_task", 4096, NULL, 5, NULL, 0); 94 | //Serial.print("setup() running on core "); Serial.println(xPortGetCoreID()); 95 | 96 | timer = timerBegin(0, 3, true); // 3 = prescaler 97 | timerAttachInterrupt(timer, &onTimer, true); 98 | timerAlarmWrite(timer, 3808, true); 99 | // with prescaler 3 and count 3808 internal DAC buffer is fully syncronized with timer interrupt at 7kHz. 100 | timerAlarmEnable(timer); 101 | 102 | // "The rising edge of the pulse on Pin 17 from the printer interface is used to clock data into the FIFO" 103 | attachInterrupt(FIFOCLK, isr_fifo, RISING); 104 | 105 | } 106 | 107 | 108 | uint32_t oldtime = 0, newtime = 0; 109 | 110 | void loop() { 111 | 112 | /*newtime = micros(); 113 | if ( (newtime-oldtime) > 1000000 ) { 114 | //Serial.print(totalTimerInterruptCounter-totalSamplesPlayed); Serial.print(" / "); 115 | Serial.print(totalFifoInterruptCounter); Serial.print(" / "); Serial.println(samples_played); 116 | oldtime = newtime; 117 | }*/ 118 | 119 | Serial.print(totalFifoInterruptCounter); Serial.print(" / "); Serial.print(samples_played); Serial.print(" / "); Serial.println(samples_not_played); 120 | for (int i=0; i<256; i++) { Serial.print(buf[i]); Serial.print(" "); } Serial.println(); 121 | delay(1000); 122 | 123 | } 124 | -------------------------------------------------------------------------------- /old/_old_esp32pico_i2s_dss.ino: -------------------------------------------------------------------------------- 1 | #include "driver/i2s.h" 2 | 3 | #define FIFOFULL 10 // fifofull, 10 (ACK) (DSS->PC) 4 | #define FIFOCLK 9 // fifoclock, 17 (Select Printer_) (PC->DSS) 5 | #define I2S_WS 19 6 | #define I2S_SCK 22 7 | #define I2S_SD 21 8 | #define SAMPLE_RATE 14000 9 | 10 | #define VOLUME 5 // 0 min, 8 max 11 | 12 | uint32_t buf[256]; 13 | volatile uint32_t totalTimerInterruptCounter = 0; 14 | volatile uint32_t totalFifoInterruptCounter = 0; 15 | volatile uint8_t buffer_full = 0; 16 | volatile uint8_t front = 0; 17 | volatile uint8_t back = 0; 18 | volatile uint8_t fifo_buf[256]; 19 | 20 | volatile uint32_t cycles; 21 | 22 | uint32_t totalSamplesPlayed = 0; 23 | #define fcnt ((uint8_t)(back-front)) // 0-16 24 | 25 | // "The rising edge of the pulse on Pin 17 from the printer interface is used to clock data into the FIFO" 26 | // this could be optimized little more: rely on samples comes in bursts. calculate how much there is free space in fifo and fill that and then rise fifofull 27 | // whis could be done even with unrolling while with case-command 28 | static void core0_task(void *args) { 29 | disableCore0WDT(); 30 | disableLoopWDT(); 31 | while (1) { 32 | while (!(REG_READ(GPIO_IN_REG) & (1< 0) { 46 | uint16_t s = (fifo_buf[front++]-128) << VOLUME; 47 | out = (s << 16) | s ; 48 | } else out = 0; 49 | if (fcnt < 16) GPIO.out_w1tc = ((uint32_t)1 << FIFOFULL); //digitalWrite(FIFOFULL, LOW); 50 | } 51 | buf[i] = out; 52 | if (i == 127) buffer_full = 1; 53 | if (i == 255) buffer_full = 2; 54 | totalTimerInterruptCounter++; 55 | } 56 | 57 | const i2s_config_t i2s_config = { 58 | .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_TX), 59 | .sample_rate = SAMPLE_RATE, 60 | .bits_per_sample = i2s_bits_per_sample_t(16), 61 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 62 | .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S), 63 | .intr_alloc_flags = 0, 64 | .dma_buf_count = 2, 65 | .dma_buf_len = 256, 66 | .use_apll = false 67 | }; 68 | 69 | const i2s_pin_config_t pin_config = { 70 | .bck_io_num = I2S_SCK, 71 | .ws_io_num = I2S_WS, 72 | .data_out_num = I2S_SD 73 | }; 74 | 75 | //------------------------------------------------------------------------------------------------------------------------ 76 | 77 | void setup() { 78 | pinMode(32, INPUT); //LPT: 2 (D0) 79 | pinMode(33, INPUT); // 3 (D1) 80 | pinMode(34, INPUT); // 4 (D2) 81 | pinMode(35, INPUT); // 5 (D3) 82 | pinMode(36, INPUT); // 6 (D4) 83 | pinMode(37, INPUT); // 7 (D5) 84 | pinMode(38, INPUT); // 8 (D6) 85 | pinMode(39, INPUT); // 9 (D7) 86 | // GND 87 | 88 | pinMode(FIFOCLK, INPUT); // fifoclock, 17 (Select Printer_) (PC->DSS) 89 | pinMode(FIFOFULL, OUTPUT); digitalWrite(FIFOFULL, LOW); // fifofull, 10 (ACK) (DSS->PC) 90 | 91 | Serial.begin(115200); 92 | while(Serial.available()); 93 | Serial.println(); Serial.print("--- (compilation date: "); Serial.print(__DATE__); Serial.print(" "); Serial.print(__TIME__); Serial.println(") ---"); 94 | 95 | i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); 96 | i2s_set_pin(I2S_NUM_0, &pin_config); 97 | i2s_start(I2S_NUM_0); 98 | 99 | xTaskCreatePinnedToCore(core0_task, "core0_task", 4096, NULL, 5, NULL, 0); 100 | attachInterrupt(I2S_WS, isr_sample, RISING); // handles i2s samples 101 | } 102 | 103 | 104 | void loop() { 105 | if (buffer_full) { 106 | size_t bytesWritten; 107 | if (buffer_full == 1) { 108 | i2s_write(I2S_NUM_0, &buf[0], sizeof(buf)/2, &bytesWritten, portMAX_DELAY); 109 | } 110 | if (buffer_full == 2) { 111 | i2s_write(I2S_NUM_0, &buf[128], sizeof(buf)/2, &bytesWritten, portMAX_DELAY); 112 | } 113 | totalSamplesPlayed += bytesWritten/4; 114 | buffer_full = 0; 115 | } 116 | 117 | static uint32_t oldtime = 0, newtime = 0; 118 | newtime = micros(); 119 | if ( (newtime-oldtime) > 50000 ) { 120 | //Serial.print(totalTimerInterruptCounter*4-totalSamplesPlayed); Serial.print(" / "); Serial.println(totalFifoInterruptCounter); 121 | Serial.println(totalSamplesPlayed); 122 | //Serial.print(cycles); Serial.print(" "); Serial.println(totalSamplesPlayed); 123 | oldtime = newtime; 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /old/dss_test4.ino: -------------------------------------------------------------------------------- 1 | #include "driver/i2s.h" 2 | 3 | static const i2s_port_t i2s_num = I2S_NUM_0; 4 | 5 | #define FIFOFULL 22 6 | #define FIFOCLK 21 7 | 8 | uint32_t buf[1024]; 9 | hw_timer_t * timer = NULL; 10 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 11 | volatile uint32_t totalInterruptCounter = 0; 12 | volatile uint32_t totalFifoInterruptCounter = 0; 13 | volatile uint8_t buffer_full = 0; 14 | volatile int8_t fifo_idx = 0; 15 | //volatile uint8_t fifo_first = 0; 16 | //volatile uint8_t fifo_last = 0; 17 | volatile uint8_t fifo_buf[16]; 18 | uint32_t totalSamplesPlayed = 0; 19 | 20 | void IRAM_ATTR isr_fifo() { 21 | portENTER_CRITICAL_ISR(&timerMux); 22 | if (fifo_idx < 16) fifo_buf[fifo_idx++] = (REG_READ(GPIO_IN_REG) >> 12); 23 | if (fifo_idx > 15) digitalWrite(FIFOFULL, HIGH); 24 | totalFifoInterruptCounter++; 25 | portEXIT_CRITICAL_ISR(&timerMux); 26 | } 27 | 28 | void IRAM_ATTR onTimer() { 29 | portENTER_CRITICAL_ISR(&timerMux); 30 | int8_t s; 31 | if (fifo_idx > 0) 32 | s = fifo_buf[--fifo_idx]; 33 | else 34 | s = 128; 35 | uint16_t i = totalInterruptCounter & 1023; 36 | buf[i] = (s<<24) | (s<<8); 37 | if (i == 511) buffer_full = 1; 38 | if (i == 1023) buffer_full = 2; 39 | if (fifo_idx < 14) digitalWrite(FIFOFULL, LOW); 40 | //portENTER_CRITICAL_ISR(&timerMux); 41 | totalInterruptCounter++; 42 | //portEXIT_CRITICAL_ISR(&timerMux); 43 | portEXIT_CRITICAL_ISR(&timerMux); 44 | } 45 | 46 | static const i2s_config_t i2s_config = { 47 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), 48 | .sample_rate = 7000, 49 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 50 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 51 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_MSB), 52 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority 53 | .dma_buf_count = 8, // 8 buffers 54 | .dma_buf_len = 512, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 55 | .use_apll = 0, 56 | .tx_desc_auto_clear = true, 57 | .fixed_mclk = -1 58 | }; 59 | 60 | //------------------------------------------------------------------------------------------------------------------------ 61 | 62 | void setup() { 63 | pinMode(12, INPUT); //LPT: 2 (D0) 64 | pinMode(13, INPUT); // 3 (D1) 65 | pinMode(14, INPUT); // 4 (D2) 66 | pinMode(15, INPUT); // 5 (D3) 67 | pinMode(16, INPUT); // 6 (D4) 68 | pinMode(17, INPUT); // 7 (D5) 69 | pinMode(18, INPUT); // 8 (D6) 70 | pinMode(19, INPUT); // 9 (D7) 71 | // GND 72 | pinMode(21, INPUT); // fifoclock, 17 (Select Printer_) (PC->DSS) 73 | pinMode(22, OUTPUT); digitalWrite(22, LOW); // fifofull, 10 (ACK) (DSS->PC) 74 | pinMode(23, OUTPUT); digitalWrite(23, HIGH); // 5V 75 | pinMode(32, OUTPUT); digitalWrite(32, LOW); // GND 76 | 77 | Serial.begin(115200); 78 | while(Serial.available()); 79 | Serial.println("alku"); 80 | 81 | i2s_driver_install(i2s_num, &i2s_config, 0, NULL); 82 | //i2s_set_pin(i2s_num, &pin_config); 83 | i2s_set_pin(i2s_num, NULL); 84 | 85 | timer = timerBegin(0, 3, true); // 1 = prescaler 86 | timerAttachInterrupt(timer, &onTimer, true); 87 | timerAlarmWrite(timer, 3808, true); // 80 000 000 / 11 428 = 7000.350018...kHz, 80 000 000 / 11 429 = 6999.7375...kHz 88 | //prescaler 1 & count 1000 -> 39903...39904, (2:lla sama?!), pre3&c1000->26633, 11429 -> 3499, 89 | //pre3&c3805->7005..7006, pre3&c3810->6996..6997, pre3&3809->6998..6999 90 | //pre3&c3809 puskuri tyhjenee ehkä 1 sample per sekuntti. 91 | //pre3&c3808 puskuri pysyy synkissä 7kHz:n DAC:n kanssa!!! 92 | Serial.println("ennen timerin enablointia"); 93 | timerAlarmEnable(timer); 94 | 95 | attachInterrupt(21, isr_fifo, RISING); 96 | 97 | Serial.println("setup():n loppu"); 98 | } 99 | 100 | 101 | uint32_t oldtime = 0, newtime = 0; 102 | uint32_t oldintcount = 0, newintcount = 0; 103 | 104 | void loop() { 105 | 106 | if (buffer_full) { 107 | size_t bytesWritten; 108 | //uint32_t i = totalInterruptCounter; 109 | //uint16_t c = i & 1023; 110 | if (buffer_full == 1) i2s_write(i2s_num, &buf[0], sizeof(buf)/2, &bytesWritten, 100); 111 | if (buffer_full == 2) i2s_write(i2s_num, &buf[512], sizeof(buf)/2, &bytesWritten, 100); 112 | totalSamplesPlayed += bytesWritten/4; 113 | buffer_full = 0; 114 | } 115 | 116 | newtime = micros(); 117 | newintcount = totalInterruptCounter; 118 | //if ( (newtime-oldtime) > 1000000 ) { 119 | if ( (newtime-oldtime) > 10000 ) { 120 | uint32_t ints = newintcount - oldintcount; 121 | //Serial.println(ints); 122 | Serial.print(totalFifoInterruptCounter); Serial.print(" "); Serial.println(fifo_idx); 123 | oldtime = newtime; 124 | oldintcount = newintcount; 125 | } 126 | //Serial.print("B: "); Serial.print(bytesWritten); Serial.print(" I-S: "); Serial.println(totalInterruptCounter-totalSamplesPlayed+100); 127 | //Serial.println(totalInterruptCounter-totalSamplesPlayed+100); 128 | } 129 | -------------------------------------------------------------------------------- /old/test2_new.ino: -------------------------------------------------------------------------------- 1 | #include "driver/i2s.h" 2 | 3 | static const i2s_port_t i2s_num = I2S_NUM_0; 4 | 5 | //TaskHandle_t m_i2sWriterTaskHandle; 6 | //QueueHandle_t m_i2sQueue; 7 | 8 | uint32_t buf[4096]; 9 | //uint32_t buf[1024]; 10 | 11 | hw_timer_t * timer = NULL; 12 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 13 | volatile uint32_t totalInterruptCounter = 0; 14 | uint32_t totalSamplesPlayed = 0; 15 | 16 | void IRAM_ATTR onTimer() { 17 | 18 | int32_t gpio = REG_READ(GPIO_IN_REG); 19 | uint8_t value = (gpio >> 12); 20 | //uint16_t i = totalInterruptCounter & 4095; // 0-2047 21 | uint16_t i = totalInterruptCounter & 4095; // 0-2047 22 | uint32_t o = (value<<24) | (value<<8); 23 | 24 | portENTER_CRITICAL_ISR(&timerMux); 25 | buf[i] = o; 26 | totalInterruptCounter++; 27 | portEXIT_CRITICAL_ISR(&timerMux); 28 | } 29 | 30 | static const i2s_config_t i2s_config = { 31 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), 32 | //.sample_rate = 44100, 33 | .sample_rate = 100000, 34 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 35 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 36 | //.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), 37 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_MSB), 38 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority = 1 39 | .dma_buf_count = 8, // 8 buffers 40 | .dma_buf_len = 1024, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 41 | .use_apll = 0, 42 | .tx_desc_auto_clear = true, 43 | .fixed_mclk = -1 44 | }; 45 | 46 | //------------------------------------------------------------------------------------------------------------------------ 47 | 48 | 49 | void setup() { 50 | pinMode(12, INPUT); //LPT: 2 (D0) 51 | pinMode(13, INPUT); // 3 (D1) 52 | pinMode(14, INPUT); // 4 (D2) 53 | pinMode(15, INPUT); // 5 (D3) 54 | pinMode(16, INPUT); // 6 (D4) 55 | pinMode(17, INPUT); // 7 (D5) 56 | pinMode(18, INPUT); // 8 (D6) 57 | pinMode(19, INPUT); // 9 (D7) 58 | // GND 59 | 60 | Serial.begin(115200); 61 | while(Serial.available()); 62 | Serial.println("alku"); 63 | 64 | 65 | //xTaskCreate(i2sWriterTask, "i2s Writer Task", 4096, NULL, 1, &m_i2sWriterTaskHandle); 66 | 67 | //timer = timerBegin(0, 80, true); // 80 (using 80 as the prescaler value), we will get a signal with a 1 MHz frequency that will increment the timer counter 1 000 000 times per second. 68 | timer = timerBegin(0, 80, true); // 80 (using 80 as the prescaler value), we will get a signal with a 1 MHz frequency that will increment the timer counter 1 000 000 times per second. 69 | timerAttachInterrupt(timer, &onTimer, true); 70 | timerAlarmWrite(timer, 10, true); // 25 -> 40kHz, 1MHz / 50 = 20kHz // 1MHz / 20 = 50kHz //1MHz / 100 = 10kHz? // 16 -> 62.5kHz 71 | //timerAlarmWrite(timer, 23, true); // 1MHz / 44100 = ~23, 1MHz / 50 = 20kHz // 1MHz / 20 = 50kHz //1MHz / 100 = 10kHz? 72 | Serial.println("ennen timerin enablointia"); 73 | timerAlarmEnable(timer); 74 | delay(500); 75 | 76 | //static QueueHandle_t i2s_event_queue; 77 | i2s_driver_install(i2s_num, &i2s_config, 0, NULL); 78 | //i2s_driver_install(i2s_num, &i2s_config, 10, &i2s_event_queue); 79 | //i2s_set_pin(i2s_num, &pin_config); 80 | i2s_set_pin(i2s_num, NULL); 81 | 82 | Serial.println("setup():n loppu"); 83 | } 84 | 85 | 86 | 87 | void loop() 88 | { 89 | 90 | size_t bytesWritten; 91 | portENTER_CRITICAL(&timerMux); 92 | uint32_t i = totalInterruptCounter; 93 | portEXIT_CRITICAL(&timerMux); 94 | uint16_t c = i & 4095; // 0-2047 95 | uint16_t b = sizeof(buf)/4; 96 | if (c < 1024) 97 | i2s_write(i2s_num, &buf[2048], b, &bytesWritten, portMAX_DELAY); 98 | else if (c < 2048) 99 | i2s_write(i2s_num, &buf[3072], b, &bytesWritten, portMAX_DELAY); 100 | else if (c < 3071) 101 | i2s_write(i2s_num, &buf[0], b, &bytesWritten, portMAX_DELAY); 102 | else 103 | i2s_write(i2s_num, &buf[1024], b, &bytesWritten, portMAX_DELAY); 104 | //totalSamplesPlayed += sizeof(buf)/2; 105 | if (bytesWritten != b) { 106 | Serial.println("VIRHE!"); 107 | delay(1000); 108 | } 109 | totalSamplesPlayed += bytesWritten/4; 110 | //totalSamplesPlayed += 256; 111 | //Serial.print("B: "); Serial.print(bytesWritten); Serial.print(" I: "); Serial.print(totalInterruptCounter); Serial.print(" S: ");Serial.println(totalSamplesPlayed); 112 | //Serial.print("B: "); Serial.print(bytesWritten); Serial.print(" I: "); Serial.print(totalInterruptCounter); Serial.print(" S: ");Serial.println(totalSamplesPlayed); 113 | //Serial.print("B: "); Serial.print(bytesWritten); Serial.print(" I-S: "); Serial.println(totalInterruptCounter-totalSamplesPlayed+100); 114 | Serial.print("b: "); Serial.print(b); Serial.print(" I-S: "); Serial.println(totalInterruptCounter-totalSamplesPlayed); 115 | //Serial.println(totalInterruptCounter-totalSamplesPlayed); 116 | 117 | } 118 | -------------------------------------------------------------------------------- /old/esp32_i2s_dss3_1.0.6.ino: -------------------------------------------------------------------------------- 1 | // Arduino IDE 1.8.19, ESP32 1.0.6 2 | 3 | #include "driver/i2s.h" 4 | 5 | /*#define write_sample(__sample) \ 6 | size_t __bytesWritten = 0; \ 7 | uint8_t __s[2]; \ 8 | __s[0] = __sample; \ 9 | __s[1] = 0x80; \ 10 | uint8_t __neutral = 0x80; \ 11 | i2s_write_expand(I2S_NUM_0, &__neutral, 1, 8, 16, &__bytesWritten, portMAX_DELAY)*/ 12 | 13 | #define FIFOFULL 22 14 | #define FIFOCLK 21 15 | 16 | hw_timer_t * timer = NULL; 17 | uint32_t buf[256]; 18 | volatile uint32_t totalTimerInterruptCounter = 0; 19 | volatile uint32_t totalFifoInterruptCounter = 0; 20 | volatile uint8_t buffer_full = 0; 21 | volatile uint8_t front = 0; 22 | volatile uint8_t back = 0; 23 | volatile uint8_t fifo_buf[256]; 24 | uint32_t totalSamplesPlayed = 0; 25 | #define fsize ((uint8_t)(back-front)) // 0-16 26 | 27 | void IRAM_ATTR isr_fifo() { 28 | uint8_t s = (REG_READ(GPIO_IN_REG) >> 12); // read lpt-port state as quick as possible after interrupt is triggered 29 | if (fsize == 15) digitalWrite(FIFOFULL, HIGH); // buffer will be full, rise the full flag 30 | if (fsize < 16) fifo_buf[back++] = s; // if there is free space in buffer, put sample to buffer 31 | totalFifoInterruptCounter++; 32 | } 33 | 34 | void IRAM_ATTR onTimer() { 35 | uint8_t s; 36 | if (fsize > 0) s = fifo_buf[front++]; else s = 0x80; // if fifo is empty, play silence (128/0x80) 37 | //write_sample(s); 38 | //I2S.write(((uint16_t)s)<<8); // Right channel 39 | //I2S.write(0x80<<8); // Left channel // "silence" 40 | uint16_t i = totalTimerInterruptCounter & 255; 41 | //buf[i] = (s<<24) | (s<<8); 42 | buf[i] = (0x80<<24) | (s<<8); 43 | if (i == 127) buffer_full = 1; 44 | if (i == 255) buffer_full = 2; 45 | totalTimerInterruptCounter++; 46 | if (fsize < 16) digitalWrite(FIFOFULL, LOW); // if there is any free space in buffer, lower the full flag 47 | } 48 | 49 | static const i2s_config_t i2s_config = { 50 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), 51 | .sample_rate = 7000, 52 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 53 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 54 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_MSB), 55 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority 56 | .dma_buf_count = 2, // 2 buffers 57 | .dma_buf_len = 256, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 58 | .use_apll = 0, 59 | .tx_desc_auto_clear = true, 60 | .fixed_mclk = -1 61 | }; 62 | 63 | //------------------------------------------------------------------------------------------------------------------------ 64 | 65 | void setup() { 66 | pinMode(12, INPUT); //LPT: 2 (D0) 67 | pinMode(13, INPUT); // 3 (D1) 68 | pinMode(14, INPUT); // 4 (D2) 69 | pinMode(15, INPUT); // 5 (D3) 70 | pinMode(16, INPUT); // 6 (D4) 71 | pinMode(17, INPUT); // 7 (D5) 72 | pinMode(18, INPUT); // 8 (D6) 73 | pinMode(19, INPUT); // 9 (D7) 74 | // GND 75 | pinMode(21, INPUT); // fifoclock, 17 (Select Printer_) (PC->DSS) 76 | pinMode(22, OUTPUT); digitalWrite(22, LOW); // fifofull, 10 (ACK) (DSS->PC) 77 | pinMode(23, OUTPUT); digitalWrite(23, HIGH); // 5V 78 | pinMode(32, OUTPUT); digitalWrite(32, LOW); // GND 79 | 80 | Serial.begin(115200); 81 | while(Serial.available()); 82 | Serial.println(); Serial.print("--- (compilation date: "); Serial.print(__DATE__); Serial.print(" "); Serial.print(__TIME__); Serial.println(") ---"); 83 | 84 | i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); 85 | i2s_set_pin(I2S_NUM_0, NULL); 86 | //i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); 87 | 88 | /*uint8_t empty[256]; 89 | for (int i=0; i< 256; i++) empty[i] = 0x80; 90 | size_t bytesWritten = 0; 91 | i2s_write_expand(I2S_NUM_0, empty, 256, 8, 16, &bytesWritten, 500 / portTICK_PERIOD_MS); 92 | Serial.println(bytesWritten);*/ 93 | //i2s_write_expand(I2S_NUM_1, empty, 256, 8, 16, &bytesWritten, 500 / portTICK_PERIOD_MS); 94 | 95 | timer = timerBegin(0, 3, true); // 3 = prescaler 96 | timerAttachInterrupt(timer, &onTimer, true); 97 | timerAlarmWrite(timer, 3808, true); 98 | // with prescaler 3 and count 3808 internal DAC buffer is fully syncronized with timer interrupt at 7kHz. 99 | timerAlarmEnable(timer); 100 | 101 | // "The rising edge of the pulse on Pin 17 from the printer interface is used to clock data into the FIFO" 102 | attachInterrupt(21, isr_fifo, RISING); 103 | 104 | } 105 | 106 | 107 | uint32_t oldtime = 0, newtime = 0; 108 | 109 | void loop() { 110 | 111 | if (buffer_full) { 112 | size_t bytesWritten; 113 | if (buffer_full == 1) i2s_write(I2S_NUM_0, &buf[0], sizeof(buf)/2, &bytesWritten, portMAX_DELAY); 114 | if (buffer_full == 2) i2s_write(I2S_NUM_0, &buf[128], sizeof(buf)/2, &bytesWritten, portMAX_DELAY); 115 | totalSamplesPlayed += bytesWritten/4; 116 | buffer_full = 0; 117 | //Serial.print(front); Serial.print(" "); Serial.println(back); 118 | } 119 | 120 | newtime = micros(); 121 | if ( (newtime-oldtime) > 50000 ) { 122 | Serial.print(totalTimerInterruptCounter-totalSamplesPlayed); Serial.print(" / "); 123 | Serial.println(totalFifoInterruptCounter); 124 | oldtime = newtime; 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /old/esp32_i2s_dss4_2.0.6.ino: -------------------------------------------------------------------------------- 1 | // DOESN'T WORK FULLY! I THINK THAT ESP32 SPEED IS NOT ENOUGH FOR FIFO EMULATION! 2 | 3 | // Arduino IDE 2.0.3, ESP32 2.0.6 (based on ESP-IDF 4.4.3) 4 | 5 | #include "driver/i2s.h" 6 | 7 | #define FIFOFULL 32 // fifofull, 10 (ACK) (DSS->PC) 8 | #define FIFOCLK 35 // fifoclock, 17 (Select Printer_) (PC->DSS) 9 | 10 | hw_timer_t * timer = NULL; 11 | volatile uint8_t buf[256]; 12 | uint32_t outbuf[512]; 13 | volatile uint32_t totalTimerInterruptCounter = 0; 14 | volatile uint32_t totalFifoInterruptCounter = 0; 15 | volatile uint8_t buffer_full = 0; 16 | volatile uint8_t front = 0; 17 | volatile uint8_t back = 0; 18 | volatile uint8_t fifo_buf[256]; 19 | 20 | uint32_t totalSamplesPlayed = 0; 21 | #define fcnt ((uint8_t)(back-front)) // 0-16 22 | 23 | void IRAM_ATTR isr_fifo() { 24 | if (fcnt == 15) digitalWrite(FIFOFULL, HIGH); // buffer will be full, rise the full flag 25 | totalFifoInterruptCounter++; 26 | if (fcnt == 16) return; // if full, return 27 | uint32_t r = REG_READ(GPIO_IN_REG); 28 | uint8_t s = (r >> 16) | (r & B10000); 29 | fifo_buf[back++] = s; // put sample to buffer 30 | } 31 | 32 | static void core0_task(void *args) { 33 | attachInterrupt(FIFOCLK, isr_fifo, RISING); 34 | while (1) { 35 | vTaskDelay(pdMS_TO_TICKS(500)); 36 | } 37 | } 38 | 39 | /*void IRAM_ATTR isr_fifo() { 40 | totalFifoInterruptCounter++; 41 | if (fcnt == 16) return; // if full, return 42 | uint32_t r = REG_READ(GPIO_IN_REG); 43 | uint8_t s = (r >> 16) | (r & B10000); 44 | fifo_buf[back++] = s; // put sample to buffer 45 | if (fcnt == 16) digitalWrite(FIFOFULL, HIGH); // buffer is full, rise the full flag 46 | }*/ 47 | 48 | void IRAM_ATTR onTimer() { 49 | uint8_t s; 50 | if (fcnt == 0) s = 0x80; else s = fifo_buf[front++]; // if fifo is empty, play silence (128/0x80) 51 | digitalWrite(FIFOFULL, LOW); // there must be at least one free slot in fifo at this point 52 | uint16_t i = totalTimerInterruptCounter & 255; 53 | buf[i] = s; 54 | if (i == 127) buffer_full = 1; 55 | if (i == 255) buffer_full = 2; 56 | totalTimerInterruptCounter++; 57 | } 58 | 59 | static const i2s_config_t i2s_config = { 60 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), 61 | .sample_rate = 28000, 62 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 63 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 64 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_LSB), 65 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority 66 | .dma_buf_count = 2, // 2 buffers 67 | .dma_buf_len = 256, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 68 | .use_apll = 0, 69 | .tx_desc_auto_clear = true, 70 | .fixed_mclk = -1 71 | }; 72 | 73 | //------------------------------------------------------------------------------------------------------------------------ 74 | 75 | void setup() { 76 | pinMode(16, INPUT); //LPT: 2 (D0) 77 | pinMode(17, INPUT); // 3 (D1) 78 | pinMode(18, INPUT); // 4 (D2) 79 | pinMode(19, INPUT); // 5 (D3) 80 | pinMode(4, INPUT); // 6 (D4) 81 | pinMode(21, INPUT); // 7 (D5) 82 | pinMode(22, INPUT); // 8 (D6) 83 | pinMode(23, INPUT); // 9 (D7) 84 | // GND 85 | pinMode(FIFOCLK, INPUT); // fifoclock, 17 (Select Printer_) (PC->DSS) 86 | pinMode(FIFOFULL, OUTPUT); digitalWrite(FIFOFULL, LOW); // fifofull, 10 (ACK) (DSS->PC) 87 | 88 | Serial.begin(115200); 89 | while(Serial.available()); 90 | Serial.println(); Serial.print("--- (compilation date: "); Serial.print(__DATE__); Serial.print(" "); Serial.print(__TIME__); Serial.println(") ---"); 91 | 92 | i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); 93 | i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); 94 | 95 | timer = timerBegin(0, 4, true); // 4 = prescaler 96 | timerAttachInterrupt(timer, &onTimer, true); 97 | timerAlarmWrite(timer, 2856, true); //sampleja tulee ihan hitusen enemmän kuin mitä i2s ehtii syödä // 2857 4 7000.350017500875 98 | timerAlarmEnable(timer); 99 | 100 | xTaskCreatePinnedToCore(core0_task, "core0_task", 4096, NULL, 5, NULL, 0); 101 | // "The rising edge of the pulse on Pin 17 from the printer interface is used to clock data into the FIFO" 102 | //attachInterrupt(FIFOCLK, isr_fifo, RISING); 103 | 104 | } 105 | 106 | 107 | uint32_t oldtime = 0, newtime = 0; 108 | 109 | void loop() { 110 | 111 | if (buffer_full) { 112 | size_t bytesWritten; 113 | if (buffer_full == 1) { 114 | for (int i=0; i<128; i++) { uint32_t s = (0x80<<24) | (buf[i]<<8); outbuf[i*4] = s; outbuf[i*4+1] = s; outbuf[i*4+2] = s; outbuf[i*4+3] = s; } 115 | //i2s_write(I2S_NUM_0, &outbuf[0], sizeof(outbuf), &bytesWritten, portMAX_DELAY); 116 | i2s_write(I2S_NUM_0, &outbuf[0], sizeof(outbuf), &bytesWritten, 10); 117 | } 118 | if (buffer_full == 2) { 119 | for (int i=0; i<128; i++) { uint32_t s = (0x80<<24) | (buf[i+128]<<8); outbuf[i*4] = s; outbuf[i*4+1] = s; outbuf[i*4+2] = s; outbuf[i*4+3] = s; } 120 | //i2s_write(I2S_NUM_0, &outbuf[0], sizeof(outbuf), &bytesWritten, portMAX_DELAY); 121 | i2s_write(I2S_NUM_0, &outbuf[0], sizeof(outbuf), &bytesWritten, 10); 122 | } 123 | totalSamplesPlayed += bytesWritten/4; 124 | buffer_full = 0; 125 | } 126 | 127 | /*Serial.print(totalFifoInterruptCounter); Serial.print(" / "); Serial.print(samples_played); Serial.print(" / "); Serial.println(samples_not_played); 128 | for (int i=0; i<256; i++) { Serial.print(buf[i]); Serial.print(" "); } Serial.println(); 129 | delay(1000);*/ 130 | 131 | newtime = micros(); 132 | if ( (newtime-oldtime) > 50000 ) { 133 | Serial.print(totalTimerInterruptCounter*4-totalSamplesPlayed); Serial.print(" / "); Serial.println(totalFifoInterruptCounter); 134 | oldtime = newtime; 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /old/test_first_try_with_pure_esp-idf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "freertos/FreeRTOS.h" 3 | #include "freertos/task.h" 4 | #include "driver/i2s.h" 5 | #include "driver/gpio.h" 6 | #include "esp_system.h" 7 | #include "esp_log.h" 8 | #include "soc/rtc.h" 9 | #include "hal/gpio_hal.h" 10 | 11 | 12 | #define VOLUME 4 // 0 min, 8 max 13 | #define DEBUG 14 | //#define EXTRA_GND 26 15 | 16 | #define D0 13 // white 17 | #define D1 14 // grey 18 | #define D2 27 // yellow 19 | #define D3 26 // brown 20 | #define D4 9 // blue 21 | #define D5 10 // purple 22 | #define D6 18 // pink 23 | #define D7 23 // green 24 | //#define FIFOFULL 10 // fifofull, 10 (ACK) (DSS->PC) 25 | //#define FIFOCLK 9 // fifoclock, 17 (Select Printer_) (PC->DSS) 26 | //#define STEREO_CHANNEL_SELECT 25 27 | 28 | #define SIZE_OF_DSS_BUF_IN_BYTES 256*4 29 | #define CONVERT_GPIOREG_TO_SAMPLE(r) (uint8_t)((((r>>D0)&1)<<0) | (((r>>D1)&1)<<1) | (((r>>D2)&1)<<2) | (((r>>D3)&1)<<3) | (((r>>D4)&1)<<4) | (((r>>D5)&1)<<5) | (((r>>D6)&1)<<6) | (((r>>D7)&1)<<7)) 30 | TaskHandle_t myTaskHandle = NULL; 31 | 32 | #define SAMPLE_RATE (96000) 33 | #define I2S_NUM (0) 34 | #define I2S_BCK_IO (GPIO_NUM_33) //4) 35 | #define I2S_WS_IO (GPIO_NUM_5) 36 | #define I2S_DO_IO (GPIO_NUM_32) //18) 37 | #define I2S_DI_IO (-1) 38 | 39 | static const char* TAG = "mcgurk_DSS_system"; 40 | 41 | uint32_t buf[1024]; 42 | volatile uint32_t totalTaskCounter = 0; 43 | volatile uint32_t totalSampleCounter = 0; 44 | uint32_t totalSamplesPlayed = 0; 45 | volatile uint8_t buffer_full = 0; 46 | //volatile uint8_t front = 0; 47 | //volatile uint8_t back = 0; 48 | volatile uint8_t fifo_buf[256]; 49 | //volatile uint32_t cycles; 50 | //#define fcnt ((uint8_t)(back-front)) // 0-16 51 | 52 | /* 53 | ESP_LOGI(TAG, "write data"); 54 | i2s_write(I2S_NUM, samples_data, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, &i2s_bytes_write, 100); 55 | 56 | free(samples_data); 57 | }*/ 58 | 59 | void core1_task( void * pvParameters ) { 60 | while(1) { 61 | printf("core1_task running on core: %i\n", xPortGetCoreID()); 62 | /*register uint32_t a; 63 | do { a = REG_READ(GPIO_IN_REG); } while (!(a & (1< 0) { 77 | uint32_t g = fifo_buf[front++]; 78 | uint16_t s = (CONVERT_GPIOREG_TO_SAMPLE(g)-128) << VOLUME; 79 | out = (s << 16) | s; 80 | } else out = 0; 81 | if (fcnt < 16) GPIO.out_w1tc = ((uint32_t)1 << FIFOFULL); //digitalWrite(FIFOFULL, LOW); 82 | }*/ 83 | uint32_t reg = REG_READ(GPIO_IN_REG); 84 | uint16_t s = (CONVERT_GPIOREG_TO_SAMPLE(reg)-128) << VOLUME; 85 | uint16_t i = totalSampleCounter & 1023; 86 | out = (s << 16) | s; 87 | buf[i] = out; 88 | //if (i == 127) buffer_full = 1; 89 | //if (i == 255) buffer_full = 2; 90 | if (i == 511) buffer_full = 1; 91 | if (i == 1023) buffer_full = 2; 92 | totalSampleCounter++; 93 | } 94 | 95 | 96 | #define PIN_TO_INPUT(pin) \ 97 | gpio_reset_pin(pin); \ 98 | gpio_pad_select_gpio(pin); \ 99 | gpio_set_direction(pin, GPIO_MODE_INPUT); \ 100 | gpio_pulldown_dis(pin); \ 101 | gpio_pullup_dis(pin); 102 | 103 | void app_main(void) 104 | { 105 | 106 | i2s_config_t i2s_config = { 107 | .mode = I2S_MODE_MASTER | I2S_MODE_TX, 108 | .sample_rate = SAMPLE_RATE, 109 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 110 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 111 | .communication_format = I2S_COMM_FORMAT_STAND_I2S, //I2S_COMM_FORMAT_STAND_MSB, 112 | .dma_buf_count = 2, 113 | .dma_buf_len = 256, 114 | .use_apll = false, 115 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1 116 | }; 117 | i2s_pin_config_t pin_config = { 118 | .mck_io_num = 0, //I2S_PIN_NO_CHANGE, 119 | .bck_io_num = I2S_BCK_IO, 120 | .ws_io_num = I2S_WS_IO, 121 | .data_out_num = I2S_DO_IO, 122 | .data_in_num = I2S_DI_IO //Not used 123 | }; 124 | i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); 125 | i2s_set_pin(I2S_NUM, &pin_config); 126 | 127 | printf("setup running on core: %i\n", xPortGetCoreID()); 128 | xTaskCreatePinnedToCore(core1_task, "Core1_Task", 4096, NULL,10, &myTaskHandle, 1); 129 | 130 | //ESP_LOGI(TAG, "set clock"); 131 | //i2s_set_clk(I2S_NUM, SAMPLE_RATE, 16, 2); 132 | //ESP_LOGI(TAG, "write data"); 133 | 134 | PIN_TO_INPUT(D0); PIN_TO_INPUT(D1); PIN_TO_INPUT(D2); PIN_TO_INPUT(D3); PIN_TO_INPUT(D4); PIN_TO_INPUT(D5); PIN_TO_INPUT(D6); PIN_TO_INPUT(D7); 135 | 136 | gpio_install_isr_service(0); 137 | gpio_set_intr_type(I2S_WS_IO, GPIO_INTR_POSEDGE); 138 | gpio_isr_handler_add(I2S_WS_IO, isr_dssfifo, NULL); 139 | gpio_hal_context_t gpiohal; 140 | gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); 141 | gpio_hal_input_enable(&gpiohal, I2S_WS_IO); 142 | 143 | ESP_LOGI(TAG, "log test"); 144 | 145 | while (1) { 146 | 147 | if (buffer_full) { 148 | size_t i2s_bytes_write; 149 | //if (buffer_full == 1) i2s_write(I2S_NUM_0, &buf[0], SIZE_OF_DSS_BUF_IN_BYTES/2, &i2s_bytes_write, portMAX_DELAY); 150 | //if (buffer_full == 2) i2s_write(I2S_NUM_0, &buf[128], SIZE_OF_DSS_BUF_IN_BYTES/2, &i2s_bytes_write, portMAX_DELAY); 151 | if (buffer_full == 1) i2s_write(I2S_NUM_0, &buf[0], 512*4, &i2s_bytes_write, portMAX_DELAY); 152 | if (buffer_full == 2) i2s_write(I2S_NUM_0, &buf[512], 512*4, &i2s_bytes_write, portMAX_DELAY); 153 | buffer_full = 0; 154 | totalSamplesPlayed += i2s_bytes_write/4; 155 | } 156 | 157 | // debug: 158 | static uint32_t oldtime = 0, newtime = 0; 159 | newtime = xthal_get_ccount(); 160 | if ( (newtime - oldtime) < 2000000000L ) { //newtime > oldtime ) { 161 | rtc_cpu_freq_config_t conf; 162 | rtc_clk_cpu_freq_get_config(&conf); 163 | printf("main core: %i, cpu speed: %u, cycles: %u, ",xPortGetCoreID(), conf.freq_mhz, xthal_get_ccount()); 164 | printf("totalSampleCounter: %u, ", totalSampleCounter); 165 | printf("totalSamplesPlayed: %u, ", totalSamplesPlayed); 166 | printf("difference: %u\n", totalSampleCounter-totalSamplesPlayed); 167 | oldtime += 240000000L; 168 | } 169 | 170 | vTaskDelay(1); 171 | //vTaskDelay(1000/portTICK_RATE_MS); 172 | 173 | } 174 | 175 | } 176 | -------------------------------------------------------------------------------- /old/test2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "freertos/FreeRTOS.h" 3 | #include "freertos/task.h" 4 | #include "driver/i2s.h" 5 | #include "driver/gpio.h" 6 | #include "esp_system.h" 7 | #include "esp_log.h" 8 | #include "soc/rtc.h" 9 | #include "hal/gpio_hal.h" 10 | 11 | 12 | #define VOLUME 4 // 0 min, 8 max 13 | #define DEBUG 14 | //#define EXTRA_GND 26 15 | 16 | #define D0 13 // white 17 | #define D1 14 // grey 18 | #define D2 27 // yellow 19 | #define D3 26 // brown 20 | #define D4 9 // blue 21 | #define D5 10 // purple 22 | #define D6 18 // pink 23 | #define D7 23 // green 24 | #define FIFOCLK 19 // fifoclock, 17 (Select Printer_) (PC->DSS) 25 | #define FIFOFULL 22 // fifofull, 10 (ACK) (DSS->PC) 26 | //#define STEREO_CHANNEL_SELECT 4 27 | //#define STEREO_CHANNEL_SELECT_PULLUP 25 28 | 29 | #define SIZE_OF_DSS_BUF_IN_BYTES 256*4 30 | #define CONVERT_GPIOREG_TO_SAMPLE(r) (uint8_t)((((r>>D0)&1)<<0) | (((r>>D1)&1)<<1) | (((r>>D2)&1)<<2) | (((r>>D3)&1)<<3) | (((r>>D4)&1)<<4) | (((r>>D5)&1)<<5) | (((r>>D6)&1)<<6) | (((r>>D7)&1)<<7)) 31 | TaskHandle_t myTaskHandle = NULL; 32 | 33 | #define SAMPLE_RATE (14000) // 96000) 34 | #define I2S_NUM (0) 35 | #define I2S_BCK_IO (GPIO_NUM_33) //4) 36 | #define I2S_WS_IO (GPIO_NUM_5) 37 | #define I2S_DO_IO (GPIO_NUM_32) //18) 38 | #define I2S_DI_IO (-1) 39 | 40 | static const char* TAG = "mcgurk_DSS_system"; 41 | 42 | uint32_t buf[1024]; 43 | volatile uint32_t totalTaskCounter = 0; 44 | volatile uint32_t totalSampleCounter = 0; 45 | uint32_t totalSamplesPlayed = 0; 46 | volatile uint8_t buffer_full = 0; 47 | volatile uint8_t front = 0; 48 | volatile uint8_t back = 0; 49 | volatile uint32_t fifo_buf[256]; 50 | #define fcnt ((uint8_t)(back-front)) // 0-16 51 | 52 | void core1_task( void * pvParameters ) { 53 | //printf("core1_task running on core: %i\n", xPortGetCoreID()); 54 | //portDISABLE_INTERRUPTS(); 55 | while(1) { 56 | register uint32_t a; 57 | do { a = REG_READ(GPIO_IN_REG); } while (!(a & (1< 0) { 73 | uint32_t reg = fifo_buf[front++]; 74 | uint16_t s = (CONVERT_GPIOREG_TO_SAMPLE(reg)-128) << VOLUME; 75 | out = (s << 16) | s; 76 | } else out = 0; 77 | if (fcnt < 16) GPIO.out_w1tc = ((uint32_t)1 << FIFOFULL); //digitalWrite(FIFOFULL, LOW); 78 | } 79 | buf[i] = out; 80 | if (i == 127) buffer_full = 1; 81 | if (i == 255) buffer_full = 2; 82 | /*uint32_t reg = REG_READ(GPIO_IN_REG); 83 | uint16_t s = (CONVERT_GPIOREG_TO_SAMPLE(reg)-128) << VOLUME; 84 | uint16_t i = totalSampleCounter & 1023; 85 | out = (s << 16) | s; 86 | buf[i] = out; 87 | if (i == 511) buffer_full = 1; 88 | if (i == 1023) buffer_full = 2;*/ 89 | totalSampleCounter++; 90 | } 91 | 92 | 93 | #define PIN_TO_INPUT(pin) \ 94 | gpio_reset_pin(pin); \ 95 | gpio_pad_select_gpio(pin); \ 96 | gpio_set_direction(pin, GPIO_MODE_INPUT); \ 97 | gpio_pulldown_dis(pin); \ 98 | gpio_pullup_dis(pin); 99 | 100 | #define PIN_TO_OUTPUT(pin) \ 101 | gpio_reset_pin(pin); \ 102 | gpio_pad_select_gpio(pin); \ 103 | gpio_set_direction(pin, GPIO_MODE_OUTPUT); 104 | 105 | void app_main(void) 106 | { 107 | 108 | i2s_config_t i2s_config = { 109 | .mode = I2S_MODE_MASTER | I2S_MODE_TX, 110 | .sample_rate = SAMPLE_RATE, 111 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 112 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 113 | .communication_format = I2S_COMM_FORMAT_STAND_I2S, //I2S_COMM_FORMAT_STAND_MSB, 114 | .dma_buf_count = 2, 115 | .dma_buf_len = 256, 116 | .use_apll = false, 117 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1 118 | }; 119 | i2s_pin_config_t pin_config = { 120 | .mck_io_num = 0, //I2S_PIN_NO_CHANGE, 121 | .bck_io_num = I2S_BCK_IO, 122 | .ws_io_num = I2S_WS_IO, 123 | .data_out_num = I2S_DO_IO, 124 | .data_in_num = I2S_DI_IO //Not used 125 | }; 126 | i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); 127 | i2s_set_pin(I2S_NUM, &pin_config); 128 | 129 | printf("setup running on core: %i\n", xPortGetCoreID()); 130 | xTaskCreatePinnedToCore(core1_task, "Core1_Task", 4096, NULL,10, &myTaskHandle, 1); 131 | 132 | //ESP_LOGI(TAG, "set clock"); 133 | //i2s_set_clk(I2S_NUM, SAMPLE_RATE, 16, 2); 134 | //ESP_LOGI(TAG, "write data"); 135 | //for (int i = 0; i< 100; i++) fifo_buf[i]=i; 136 | 137 | PIN_TO_INPUT(D0); PIN_TO_INPUT(D1); PIN_TO_INPUT(D2); PIN_TO_INPUT(D3); PIN_TO_INPUT(D4); PIN_TO_INPUT(D5); PIN_TO_INPUT(D6); PIN_TO_INPUT(D7); 138 | PIN_TO_INPUT(FIFOCLK); PIN_TO_OUTPUT(FIFOFULL); gpio_set_level(FIFOFULL, 0); 139 | 140 | gpio_install_isr_service(0); 141 | gpio_set_intr_type(I2S_WS_IO, GPIO_INTR_POSEDGE); 142 | gpio_isr_handler_add(I2S_WS_IO, isr_dssfifo, NULL); 143 | gpio_hal_context_t gpiohal; 144 | gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); 145 | gpio_hal_input_enable(&gpiohal, I2S_WS_IO); 146 | 147 | ESP_LOGI(TAG, "log test"); 148 | 149 | while (1) { 150 | 151 | if (buffer_full) { 152 | size_t i2s_bytes_write; 153 | if (buffer_full == 1) i2s_write(I2S_NUM_0, &buf[0], SIZE_OF_DSS_BUF_IN_BYTES/2, &i2s_bytes_write, portMAX_DELAY); 154 | if (buffer_full == 2) i2s_write(I2S_NUM_0, &buf[128], SIZE_OF_DSS_BUF_IN_BYTES/2, &i2s_bytes_write, portMAX_DELAY); 155 | //if (buffer_full == 1) i2s_write(I2S_NUM_0, &buf[0], 512*4, &i2s_bytes_write, portMAX_DELAY); 156 | //if (buffer_full == 2) i2s_write(I2S_NUM_0, &buf[512], 512*4, &i2s_bytes_write, portMAX_DELAY); 157 | buffer_full = 0; 158 | totalSamplesPlayed += i2s_bytes_write/4; 159 | } 160 | 161 | // debug: 162 | static uint32_t oldtime = 0, newtime = 0; 163 | newtime = xthal_get_ccount(); 164 | if ( (newtime - oldtime) < 2000000000L ) { //newtime > oldtime ) { 165 | rtc_cpu_freq_config_t conf; 166 | rtc_clk_cpu_freq_get_config(&conf); 167 | printf("main core: %i, cpu speed: %u, cycles: %u, ",xPortGetCoreID(), conf.freq_mhz, xthal_get_ccount()); 168 | printf("totalTaskCounter: %u, ", totalTaskCounter); 169 | printf("totalSampleCounter: %u, ", totalSampleCounter); 170 | printf("totalSamplesPlayed: %u, ", totalSamplesPlayed); 171 | printf("difference: %u\n", totalSampleCounter-totalSamplesPlayed); 172 | //for (int i = 0; i< 100; i++) printf("%i,", fifo_buf[i]); 173 | //for (int i = 0; i< 100; i++) printf("%i,", CONVERT_GPIOREG_TO_SAMPLE(fifo_buf[i])); 174 | //for (int i = 0; i< 20; i++) printf("%i,", buf[i]&255); 175 | printf("\n"); 176 | oldtime += 240000000L; 177 | } 178 | 179 | vTaskDelay(1); 180 | //vTaskDelay(1000/portTICK_RATE_MS); 181 | 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /old/covox_simple_ESP-IDF-v5.0.x.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Covox implementation for ESP-IDF 5.0.2, ESP32-PICO-KIT and GY-PCM5102 by McGurk 3 | 4 | https://dl.espressif.com/dl/esp-idf/ 5 | ESP-IDF v5.0.2 - Offline Installer (768MB) / esp-idf-tools-setup-offline-5.0.2.exe 6 | 7 | https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2s.html 8 | https://www.ti.com/lit/ds/symlink/pcm5102.pdf 9 | https://github.com/espressif/esp-idf/blob/master/components/driver/i2s/include/driver/i2s_std.h 10 | https://github.com/espressif/esp-idf/blob/master/components/driver/i2s/include/driver/i2s_common.h 11 | 12 | New: Espressif IDF Project 13 | Name: covox_simple 14 | Target: ESP32 15 | Component config -> ESP System settings: 16 | CPU frequency: 240MHz (default: 160MHz) 17 | Also watch CPU1 tick interrupt: off (default on) 18 | Watch CPU1 Idle Task: off (default on) 19 | Component config -> FreeRTOS -> Tick rate: 1000 (default 100) 20 | */ 21 | 22 | #include "freertos/FreeRTOS.h" // task.h 23 | #include "freertos/task.h" // vTaskDelay() 24 | #include "soc/gpio_reg.h" // GPIO_IN_REG 25 | #include "rom/gpio.h" // gpio_pad_select_gpio 26 | #include "hal/gpio_hal.h" // gpio_hal_context_t 27 | #include "esp_log.h" // ESP_LOGI 28 | #include "esp_timer.h" // esp_timer_get_time 29 | #include "soc/rtc.h" // rtc_cpu_freq_config_t 30 | #include "driver/i2s_std.h" // I2S 31 | #include "driver/gpio.h" // I2S 32 | 33 | #define uint32_t unsigned int 34 | #define int32_t int 35 | 36 | #define VOLUME 8 // 0 min, 8 max 37 | #define DEBUG 38 | 39 | #define D0 13 // white 40 | #define D1 14 // grey 41 | #define D2 27 // yellow 42 | #define D3 26 // brown 43 | #define D4 9 // blue 44 | #define D5 10 // purple 45 | #define D6 18 // pink 46 | #define D7 23 // green 47 | 48 | i2s_chan_handle_t tx_handle; 49 | #define I2S_BCK_IO (GPIO_NUM_33) 50 | #define I2S_WS_IO (GPIO_NUM_5) 51 | #define I2S_DO_IO (GPIO_NUM_32) 52 | 53 | #define CONVERT_GPIOREG_TO_SAMPLE(r) (uint8_t)((((r>>D0)&1)<<0) | (((r>>D1)&1)<<1) | (((r>>D2)&1)<<2) | (((r>>D3)&1)<<3) | (((r>>D4)&1)<<4) | (((r>>D5)&1)<<5) | (((r>>D6)&1)<<6) | (((r>>D7)&1)<<7)) 54 | 55 | #define SAMPLE_RATE_COVOX (96000) 56 | 57 | static const char* TAG = "mcgurk_Covox_system"; 58 | 59 | TaskHandle_t myTaskHandle = NULL; 60 | uint32_t buf[2048]; 61 | volatile uint32_t totalTaskCounter = 0; 62 | volatile uint32_t totalSampleCounter = 0; 63 | uint32_t totalSamplesPlayed = 0; 64 | volatile uint8_t buffer_full = 0; 65 | 66 | /* Setting the configurations, the slot configuration and clock configuration can be generated by the macros 67 | * These two helper macros are defined in 'i2s_std.h' which can only be used in STD mode. 68 | * They can help to specify the slot and clock configurations for initialization or updating */ 69 | i2s_std_config_t std_cfg = { 70 | //.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE_COVOX), 71 | //.slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO), 72 | .clk_cfg = { 73 | .sample_rate_hz = SAMPLE_RATE_COVOX, 74 | .clk_src = I2S_CLK_SRC_APLL, 75 | .mclk_multiple = I2S_MCLK_MULTIPLE_256, 76 | }, 77 | .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO), 78 | .gpio_cfg = { 79 | .mclk = I2S_GPIO_UNUSED, 80 | .bclk = I2S_BCK_IO, 81 | .ws = I2S_WS_IO, 82 | .dout = I2S_DO_IO, 83 | .din = I2S_GPIO_UNUSED, 84 | .invert_flags = { 85 | .mclk_inv = false, 86 | .bclk_inv = false, 87 | .ws_inv = false, 88 | }, 89 | }, 90 | }; 91 | 92 | void core1_task( void * pvParameters ) { 93 | portDISABLE_INTERRUPTS(); 94 | while(1) { 95 | register uint32_t a; 96 | do { 97 | a = REG_READ(GPIO_IN_REG); 98 | } while (!(a & (1<> 12); 21 | uint16_t i = totalInterruptCounter & 2047; // 0-2047 22 | buf[i] = (value<<24) | (value<<8); 23 | } 24 | 25 | volatile uint8_t semaphore = 0; 26 | 27 | /*static const i2s_config_t i2s_config = { 28 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX), 29 | .sample_rate = 44100, 30 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 31 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 32 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), 33 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority 34 | .dma_buf_count = 8, // 8 buffers 35 | .dma_buf_len = 1024, // 1K per buffer, so 8K of buffer space 36 | .use_apll=0, 37 | .tx_desc_auto_clear= true, 38 | .fixed_mclk=-1 39 | }; 40 | 41 | static const i2s_pin_config_t pin_config = { 42 | .bck_io_num = 27, // The bit clock connectiom, goes to pin 27 of ESP32 43 | .ws_io_num = 26, // Word select, also known as word select or left right clock 44 | .data_out_num = 25, // Data out from the ESP32, connect to DIN on 38357A 45 | .data_in_num = I2S_PIN_NO_CHANGE // we are not interested in I2S data into the ESP32 46 | };*/ 47 | 48 | /*static const i2s_config_t i2s_config = { 49 | .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, 50 | .sample_rate = 44100, 51 | .bits_per_sample = 16, // the DAC module will only take the 8bits from MSB 52 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 53 | .intr_alloc_flags = 0, // default interrupt priority 54 | .dma_desc_num = 8, 55 | .dma_frame_num = 64, 56 | .use_apll = false 57 | };*/ 58 | 59 | /*static const i2s_config_t i2s_config = { 60 | .mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN, 61 | //.mode = I2S_MODE_MASTER | I2S_MODE_TX, // only TX 62 | .sample_rate = 44100, 63 | .bits_per_sample = 16, 64 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // 2-channels 65 | //.communication_format = I2S_COMM_FORMAT_STAND_MSB, 66 | .dma_buf_count = 6, 67 | .dma_buf_len = 60, 68 | .intr_alloc_flags = 0, // default interrupt priority 69 | .tx_desc_auto_clear = true // auto clear tx descriptor on underflow 70 | };*/ 71 | 72 | static const i2s_config_t i2s_config = { 73 | .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN), 74 | //.sample_rate = 44100, 75 | .sample_rate = 100000, 76 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 77 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 78 | //.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), 79 | .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S_MSB), 80 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority 81 | .dma_buf_count = 8, // 8 buffers 82 | .dma_buf_len = 512, // Number of frames for one-time sampling. The frame here means the total data from all the channels in a WS cycle 83 | .use_apll = 0, 84 | .tx_desc_auto_clear = true, 85 | .fixed_mclk = -1 86 | }; 87 | 88 | //------------------------------------------------------------------------------------------------------------------------ 89 | 90 | /*void i2sWriterTask(void *param) 91 | { 92 | size_t bytesWritten; 93 | while (true) 94 | { 95 | // wait for some data to be requested 96 | i2s_event_t evt; 97 | if (xQueueReceive(m_i2sQueue, &evt, portMAX_DELAY) == pdPASS) 98 | { 99 | if (evt.type == I2S_EVENT_TX_DONE) // I2S DMA finish sent 1 buffer 100 | { 101 | //i2s_write(I2S_NUM_0, sawTooth + buffer_position, availableSamples * 2, &bytesWritten, portMAX_DELAY); 102 | i2s_write(I2S_NUM_0, buf, sizeof(buf), &bytesWritten, portMAX_DELAY); 103 | Serial.println(micros()); 104 | semaphore = 1; 105 | } 106 | } 107 | } 108 | }*/ 109 | 110 | void setup() { 111 | pinMode(12, INPUT); //LPT: 2 (D0) 112 | pinMode(13, INPUT); // 3 (D1) 113 | pinMode(14, INPUT); // 4 (D2) 114 | pinMode(15, INPUT); // 5 (D3) 115 | pinMode(16, INPUT); // 6 (D4) 116 | pinMode(17, INPUT); // 7 (D5) 117 | pinMode(18, INPUT); // 8 (D6) 118 | pinMode(19, INPUT); // 9 (D7) 119 | // GND 120 | 121 | Serial.begin(115200); 122 | while(Serial.available()); 123 | Serial.println("alku"); 124 | 125 | static QueueHandle_t i2s_event_queue; 126 | i2s_driver_install(i2s_num, &i2s_config, 0, NULL); 127 | //i2s_driver_install(i2s_num, &i2s_config, 10, &i2s_event_queue); 128 | //i2s_set_pin(i2s_num, &pin_config); 129 | i2s_set_pin(i2s_num, NULL); 130 | 131 | //xTaskCreate(i2sWriterTask, "i2s Writer Task", 4096, NULL, 1, &m_i2sWriterTaskHandle); 132 | 133 | timer = timerBegin(0, 80, true); // 80 (using 80 as the prescaler value), we will get a signal with a 1 MHz frequency that will increment the timer counter 1 000 000 times per second. 134 | timerAttachInterrupt(timer, &onTimer, true); 135 | timerAlarmWrite(timer, 10, true); // 25 -> 40kHz, 1MHz / 50 = 20kHz // 1MHz / 20 = 50kHz //1MHz / 100 = 10kHz? // 16 -> 62.5kHz 136 | //timerAlarmWrite(timer, 23, true); // 1MHz / 44100 = ~23, 1MHz / 50 = 20kHz // 1MHz / 20 = 50kHz //1MHz / 100 = 10kHz? 137 | Serial.println("ennen timerin enablointia"); 138 | timerAlarmEnable(timer); 139 | 140 | Serial.println("setup():n loppu"); 141 | } 142 | 143 | 144 | 145 | void loop() 146 | { 147 | /*for (int i=0; i < 1*1024; i++) { 148 | uint8_t c = (REG_READ(GPIO_IN_REG) >> 12); 149 | buf[i] = (c<<24) | (c<<8); 150 | delayMicroseconds(20); 151 | }*/ 152 | //while (semaphore == 0) yield(); 153 | //semaphore = 0; 154 | //Serial.println(micros()); 155 | size_t bytesWritten; 156 | //i2s_write(i2s_num, &buf, sizeof(buf), &BytesWritten, portMAX_DELAY); 157 | //i2s_write(i2s_num, &buf, sizeof(buf), &BytesWritten, 100); 158 | //portENTER_CRITICAL(&timerMux); 159 | uint32_t i = totalInterruptCounter; 160 | //portEXIT_CRITICAL(&timerMux); 161 | uint16_t c = i & 2047; // 0-2047 162 | if (c < 511) 163 | i2s_write(i2s_num, &buf[1024], sizeof(buf)/4, &bytesWritten, portMAX_DELAY); 164 | else if (c < 1023) 165 | i2s_write(i2s_num, &buf[1536], sizeof(buf)/4, &bytesWritten, portMAX_DELAY); 166 | else if (c < 1535) 167 | i2s_write(i2s_num, &buf[0], sizeof(buf)/4, &bytesWritten, portMAX_DELAY); 168 | else 169 | i2s_write(i2s_num, &buf[512], sizeof(buf)/4, &bytesWritten, portMAX_DELAY); 170 | //totalSamplesPlayed += sizeof(buf)/2; 171 | totalSamplesPlayed += 512; 172 | //Serial.print("B: "); Serial.print(bytesWritten); Serial.print(" I: "); Serial.print(totalInterruptCounter); Serial.print(" S: ");Serial.println(totalSamplesPlayed); 173 | //Serial.print("B: "); Serial.print(bytesWritten); Serial.print(" I: "); Serial.print(totalInterruptCounter); Serial.print(" S: ");Serial.println(totalSamplesPlayed); 174 | //Serial.print("B: "); Serial.print(bytesWritten); Serial.print(" I-S: "); Serial.println(totalInterruptCounter-totalSamplesPlayed+100); 175 | //Serial.print("c: "); Serial.print(c); Serial.print(" I-S: "); Serial.println(totalInterruptCounter-totalSamplesPlayed+100); 176 | /* //static uint8_t value = 0; 177 | uint8_t value = (REG_READ(GPIO_IN_REG) >> 12); 178 | uint32_t Value32Bit = (((uint32_t)value)<<24) | (((uint32_t)value)<<8); 179 | //i2s_write(i2s_num, &Value32Bit, 4, &BytesWritten, 100); 180 | i2s_write(i2s_num, &Value32Bit, 4, &BytesWritten, portMAX_DELAY); 181 | //i2s_write(i2s_num, &Value32Bit, 4, &BytesWritten, 0); 182 | //delayMicroseconds(20); //44100kHz -> 0,000022675736*/ 183 | 184 | } 185 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | (update 31.3.2025: "McDSS_esp-idf_v5.1.1.c" works with ESP-IDF v5.4) 2 | 3 | # McGurk-Covox/DSS/StereoOn1-System (McDSS) 4 | Parallel/LPT-port soundcard using microcontroller. Supports Covox Speech Thing/Intersound MDO, Disney Sound Source (DSS) and Stereo-on-1 DAC. 5 | 6 | Thread at Vogons: https://www.vogons.org/viewtopic.php?f=62&t=93225 7 | 8 | ## Parts 9 | 10 | - ESP32-PICO-KIT (if other ESP32 is used, modify pins) 11 | - I2S DAC (e.g. PCM5102A/GY-PCM5102 or I2S DAC amplifier MAX98357A) 12 | 13 | ## New wiring (ESP-IDF 5.1.1) 14 | 15 | ESP32 | LPT (D25) 16 | --- | --- 17 | **Covox:** | 18 | IO18 🟤 | 2 (D0) 19 | IO19 🟠 | 3 (D1) 20 | IO27 🔵 | 4 (D2) 21 | IO21 🟢 | 5 (D3) 22 | IO22 🟡 | 6 (D4) 23 | IO23 🔴 | 7 (D5) 24 | IO13 🔘 | 8 (D6) 25 | IO14 🟣 | 9 (D7) 26 | GND ⚫ | GND (18-25) 27 | **DSS:** | 28 | IO9 ⚪ | 17 (FIFOCLK) (Select Printer_) (PC->DSS) 29 | IO10 ⚫ | 10 (FIFOFULL) (ACK) (DSS->PC) 30 | **Stereo-on-1:** | 31 | IO4 ⚪ | 1 (Strobe_) (channel select PC->Covox) 32 |   | resistor between IO4 and 5V for external pullup (I have 2.15kohm, 4.7kohm might work too) 33 | **ESP32:** | **I2S DAC:** 34 | 5V 🔴 | Vin (use 5V if possible, more stable) 35 | GND ⚫ | Ground 36 | IO25 🟢 | DATA 37 | IO32 🟡 | BLCK 38 | IO26 🟤 | WCLK (must be GPIO 0-31) 39 | GND | SCK (if GY-PCM5102) 40 | 41 | \* = IO9 and IO10 is only usable with ESP32-PICO-KIT (ESP32-PICO-D4) (with ESP32-WROOM-32 use 16 and 17) 42 | 43 | ## ESP-IDF settings 44 | ``` 45 | Component config -> ESP System settings: 46 | CPU frequency: 240MHz (default: 160MHz) 47 | Also watch CPU1 tick interrupt: off (default on) 48 | Watch CPU1 Idle Task: off (default on) 49 | Component config -> FreeRTOS -> Tick rate: 1000 (default 100) 50 | Serial flasher config -> Flash size: 4MB (default 2MB) 51 | ``` 52 | 53 | ## Links 54 | - https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf 55 | - https://randomnerdtutorials.com/esp32-pinout-reference-gpios/ 56 | - https://www.weigu.lu/microcontroller/tips_tricks/esp32_tips_tricks/index.html 57 | - https://www.mischianti.org/wp-content/uploads/2020/11/ESP32-DOIT-DEV-KIT-v1-pinout-mischianti.png 58 | - https://www.mischianti.org/wp-content/uploads/2021/07/ESP32-DEV-KIT-DevKitC-v4-pinout-mischianti.png 59 | - [https://docs.espressif.com/projects/esp-idf/en/latest/esp32/_images/esp32-pico-kit-v4-pinout.png](https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32/_images/esp32-pico-kit-v4-pinout.png) 60 | - https://europe1.discourse-cdn.com/arduino/optimized/4X/2/3/1/2319cb54d8691ab1d1ba749b7992710217dcacf2_2_500x500.jpeg 61 | - Adafruit Mono 2.5W Class D Audio Amplifier - PAM8302: https://www.adafruit.com/product/2130 62 | - ESP32 DAC: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/dac.html 63 | - Xtensa® Instruction Set Architecture (ISA) Reference Manual: https://0x04.net/~mwk/doc/xtensa.pdf 64 | - Is ESP32 5v tolerant? https://voodoo.business/2021/05/19/are-the-esp32-and-esp8266-5v-tolerant-yes-they-officially-are/ 65 | - https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/memory-types.html 66 | - https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2s.html 67 | - PCM5102: https://www.ti.com/lit/ds/symlink/pcm5100a.pdf 68 | - DSS/Covox exclusive games? https://www.vogons.org/viewtopic.php?t=57885 69 | - LPT: https://www.epanorama.net/circuits/lptpower.html 70 | - LPT: https://www.edaboard.com/threads/parallel-port-max-current-sink-output.49356/ 71 | 72 | Looks like zeropoint is 128 (0x80). Tested with Hocus Pocus (Covox) and Wolfenstein 3D (DSS). 73 | 74 | ## Covox Speech Thing / Intersound MDO / LPT DAC 75 | - https://en.wikipedia.org/wiki/Covox_Speech_Thing 76 | - https://www.vgmpf.com/Wiki/index.php?title=Intersound_MDO 77 | - Covox supported games: https://www.mobygames.com/attributes/attribute/43/ 78 | - Intersound MDO supported games: https://www.mobygames.com/attributes/attribute/1860/ 79 | 80 | ## Disney Sound Source (DSS) 81 | 82 | #### ESP32 83 | - Cannot use interrupts, they are too slow. Dedicate another core for bitbanging FIFOCLK signal. 84 | - https://github.com/MacLeod-D/ESp32-Fast-external-IRQs 85 | - Use I2S WCLK for unload buffer interrupt 86 | - DAC doesn't work with 7kHz so double samples to 14kHz 87 | 88 | #### Links 89 | - DSS supported games: https://www.mobygames.com/attribute/sheet/attributeId,44 90 | - Miles Sound System (MSS) DSS patch: https://www.vogons.org/viewtopic.php?t=69539 91 | - Disney Sound Source driver for Win3x, Win9x, WinNT 4: http://www.vogonsdrivers.com/getfile.php?fileid=1680&menustate=0 92 | - DSS Programmers Guide: https://archive.org/details/dss-programmers-guide/page/n1/mode/2up 93 | - Reversing the Disney Sound Source: https://www.vogons.org/viewtopic.php?f=62&t=42250&start=140 94 | - DIY DSS: https://www.vogons.org/viewtopic.php?p=474360#p474360 95 | - Vogons Disney Sound Source with FIFO-buffer ICs: https://www.vogons.org/viewtopic.php?p=405296#p405296 96 | 97 | #### DSS checks 98 | - Dungeon Master DSS detection: https://www.vogons.org/viewtopic.php?t=40751 99 | - Wolfenstein 3D: writes 32 samples to FIFO and checks that FIFOFULL pin activates 100 | - Commander Keen in Keen Dreams (KDreams): v1.0 detects DSS. 33 sample interrupts comes trough. Notice: DSS is not actually supported at all in the game. 101 | 102 | ## Stereo-on-1 103 | - 2,15kohm between gpio and 5V. Channelselect signal is very fast (weak) and pullup is crucial for operation. 104 | - Crystal Dream by Triton: https://www.pouet.net/prod.php?which=463 (LPT pin 1) 105 | - Crystal Dream 2 by Triton: https://www.pouet.net/prod.php?which=462 106 | - Inertia Player 1.22: https://www.pouet.net/prod.php?which=29208 107 | - Dual Module Player 3.01: https://files.scene.org/browse/resources/music/players/ 108 | - Fast Tracker II (2.09) 109 | - Galaxy Music Player (GLX) v2.12 by Trial: https://www.pouet.net/prod.php?which=73182 (I couldn't get this to work in stereo) 110 | - https://datasheet.octopart.com/PM7528HP-Analog-Devices-datasheet-11801523.pdf 111 | - http://loboris.eu/ESP32/Xtensa%20Instruction%20Set%20Architecture.pdf 112 | - https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf 113 | - Problem in autodetection: after stereo player (iplay, dmp, crystal dreams) DSS-enable signal (LPT pin17) stays up. To get back to normal covox you have to start DSS-program or some other means drop DSS-enable signal down. 114 | - My Covox (Stereo-On-1) LPT Stereo DAC - home made sound card: https://www.vogons.org/viewtopic.php?t=30139 115 | - Covox in Stereo on one LPT Port - LPTSND X2 (Prototype): https://www.vogons.org/viewtopic.php?t=83891 116 | - Problem with ESP32 GPIO reading: https://github.com/espressif/arduino-esp32/issues/4172 117 | - Compaq Contura 430C (486@100MHz) doesn't work with default LPT bios-settings. Set LPT port to EPP in bios settings to get Stereo-on-1 to work. 118 | 119 | # Misc stuff 120 | 121 | ### DOSBox 122 | ``` 123 | [speaker] 124 | disney=true 125 | ``` 126 | 127 | ### Dual Module Player (DMP) 128 | ``` 129 | dmp -c6 -p378 -s44100 -q song.mod # covox 130 | dmp -c12 -p378 -s30000 -q song.mod # stereo-in-one 131 | or 132 | SET DMP=-c12 -p378 -s30000 -q 133 | ``` 134 | 135 | ### FastDoom 136 | - https://github.com/viti95/FastDoom 137 | - You need wad file from shareware or retail version 138 | - To get music (with fx) from Covox/DSS, you need music as raw files. There is OGG-files in Steam version, but you may find some Doom ogg-files with google also. You see filenames and how to convert ogg files to raw files from this script: https://github.com/viti95/FastDoom/blob/master/SCRIPTS/PCMconvert/convert.sh 139 | - PCM Music format is unsigned 8-bit PCM, and supports 11025, 22050 or 44100 Hz frequencies. 140 | - With Covox: Convert ogg to raw in same samplerate as you are selected from fdsetup. Notice that this also affects to minimum memory requirements (whole raw-file must fit to memory at once) 141 | 142 | 143 | 144 | ### Create utility to get LPT pin 17 (fifoclk / dss power on) to low with DOS debug-command 145 | Press enter after every line (also when there is empty line). 146 | ``` 147 | C:\>debug 148 | n pin17.com ; filename 149 | a100 ; assemble to address :0100 150 | mov dx,37a ; 37Ah = LPT control pins port 151 | in al,dx ; read current state from port 152 | or al,8 ; bit 4 high -> pin 17 low ("and al,F7" would get it to high) 153 | out dx,al ; write new state to port 154 | ret ; return to DOS 155 | ; end assembler mode with empty line 156 | rcx ; give how many bytes to write in cx register 157 | 8 ; 8 bytes to write 158 | w ; write file 159 | q ; quit 160 | ``` 161 | -------------------------------------------------------------------------------- /old/_old_esp32pico_i2s_covox-dss.ino: -------------------------------------------------------------------------------- 1 | #include "driver/i2s.h" 2 | //#include "rom/rtc.h" 3 | 4 | #define FIFOCLK 9 // fifoclock, 17 (Select Printer_) (PC->DSS) 5 | #define FIFOFULL 10 // fifofull, 10 (ACK) (DSS->PC) 6 | #define I2S_WS 19 7 | #define I2S_SCK 22 8 | #define I2S_SD 21 9 | #define SAMPLE_RATE_DSS 14000 10 | #define SAMPLE_RATE_COVOX 96000 11 | 12 | #define VOLUME 4 // 0 min, 8 max 13 | 14 | #define SIZE_OF_DSS_BUF_IN_BYTES 256*4 15 | #define SIZE_OF_COVOX_BUF_IN_BYTES 1024*4 16 | 17 | enum MODE { NONE = 0, COVOX = 1, DSS = 2, STEREO = 3 }; 18 | 19 | uint32_t buf[1024]; 20 | volatile uint32_t totalSampleCounter = 0; 21 | volatile uint32_t totalFifoInterruptCounter = 0; 22 | volatile uint8_t buffer_full = 0; 23 | volatile uint8_t front = 0; 24 | volatile uint8_t back = 0; 25 | volatile uint8_t fifo_buf[256]; 26 | volatile MODE mode = NONE; 27 | 28 | uint32_t totalSamplesPlayed = 0; 29 | #define fcnt ((uint8_t)(back-front)) // 0-16 30 | 31 | void IRAM_ATTR isr_sample_covox() { 32 | uint8_t s1 = REG_READ(GPIO_IN1_REG); 33 | uint8_t s2 = REG_READ(GPIO_IN1_REG); 34 | uint8_t s3 = REG_READ(GPIO_IN1_REG); 35 | if (s1 != s2) s1 = s3; 36 | uint16_t out = (s1 - 128) << VOLUME; 37 | uint16_t i = totalSampleCounter & 1023; 38 | buf[i] = (out << 16) | out; 39 | if (i == 511) buffer_full = 1; 40 | if (i == 1023) buffer_full = 2; 41 | totalSampleCounter++; 42 | } 43 | 44 | void IRAM_ATTR isr_sample_dss() { 45 | static uint32_t out = 0; 46 | uint16_t i = totalSampleCounter & 255; 47 | if (i&1) {// read new "out" only every other time 48 | if (fcnt > 0) { 49 | uint16_t s = (fifo_buf[front++]-128) << VOLUME; 50 | out = (s << 16) | s ; 51 | } else out = 0; 52 | if (fcnt < 16) GPIO.out_w1tc = ((uint32_t)1 << FIFOFULL); //digitalWrite(FIFOFULL, LOW); 53 | } 54 | buf[i] = out; 55 | if (i == 127) buffer_full = 1; 56 | if (i == 255) buffer_full = 2; 57 | totalSampleCounter++; 58 | } 59 | 60 | static void core0_task_covox(void *args) { // actually this runs in core1 61 | attachInterrupt(I2S_WS, isr_sample_covox, RISING); 62 | while (1) { 63 | vTaskDelay(10); 64 | } 65 | } 66 | 67 | // "The rising edge of the pulse on Pin 17 from the printer interface is used to clock data into the FIFO" 68 | // this could be optimized little more: rely on samples comes in bursts. calculate how much there is free space in fifo and fill that and then rise fifofull 69 | // whis could be done even with unrolling while with case-command 70 | static void core0_task_dss(void *args) { 71 | disableCore0WDT(); 72 | disableLoopWDT(); 73 | while (1) { 74 | while (!(REG_READ(GPIO_IN_REG) & (1<DSS) 118 | pinMode(FIFOFULL, OUTPUT); digitalWrite(FIFOFULL, LOW); // fifofull, 10 (ACK) (DSS->PC) 119 | 120 | /*Serial.begin(115200); 121 | while(Serial.available()); 122 | Serial.println(); Serial.print("--- (compilation date: "); Serial.print(__DATE__); Serial.print(" "); Serial.print(__TIME__); Serial.println(") ---"); 123 | */ 124 | 125 | i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); 126 | i2s_set_pin(I2S_NUM_0, &pin_config); 127 | 128 | change_mode(COVOX); 129 | //delay(1000); change_mode(DSS); 130 | //if (rtc_get_reset_reason(0) == 12) change_mode(DSS); else change_mode(COVOX); 131 | } 132 | 133 | void change_mode(MODE new_mode) { 134 | MODE old_mode = mode; 135 | if (new_mode == old_mode) return; 136 | mode = NONE; 137 | 138 | for (int i = 0; i < 1024; i++) buf[i] = 0; 139 | for (int i = 0; i < 256; i++) fifo_buf[i] = 0; 140 | front = 0; back = 0; 141 | totalSampleCounter = 0; 142 | buffer_full = 0; 143 | 144 | switch (old_mode) { //disable current mode 145 | case COVOX: 146 | vTaskDelete(task_handle_covox); //disable task 147 | detachInterrupt(I2S_WS); //disable i2s interrupt 148 | i2s_stop(I2S_NUM_0); //stop i2s 149 | break; 150 | case DSS: 151 | vTaskDelete(task_handle_dss); //disable task 152 | detachInterrupt(I2S_WS); //disable i2s interrupt 153 | i2s_stop(I2S_NUM_0); //stop i2s 154 | break; 155 | default: 156 | break; 157 | } 158 | 159 | switch (new_mode) { 160 | case COVOX: //dss -> covox 161 | // I don't like this much... if I put COVOX to core0, DSS doesn't work after COVOX without crackling. so I must use core1 to COVOX: 162 | xTaskCreatePinnedToCore(core0_task_covox, "core0_task_covox", 4096, NULL, 5, &task_handle_covox, 1); // create task_handle_covox (creates I2S_WS interrupt) 163 | i2s_set_sample_rates(I2S_NUM_0, SAMPLE_RATE_COVOX); // set sample rate 164 | i2s_start(I2S_NUM_0); // start i2s_covox 165 | break; 166 | case DSS: // covox -> dss 167 | i2s_set_sample_rates(I2S_NUM_0, SAMPLE_RATE_DSS); // set sample rate 168 | i2s_start(I2S_NUM_0); // start i2s_dss 169 | xTaskCreatePinnedToCore(core0_task_dss, "core0_task_dss", 4096, NULL, 5, &task_handle_dss, 0); // create task_handle_dss 170 | attachInterrupt(I2S_WS, isr_sample_dss, RISING); // handles i2s samples 171 | break; 172 | default: 173 | break; 174 | } 175 | 176 | mode = new_mode; 177 | } 178 | 179 | void loop() { 180 | 181 | if ((mode == COVOX) && buffer_full) { 182 | esp_err_t result; 183 | size_t bytesWritten; 184 | if (buffer_full == 1) { 185 | result = i2s_write(I2S_NUM_0, &buf[0], SIZE_OF_COVOX_BUF_IN_BYTES/2, &bytesWritten, portMAX_DELAY); 186 | } 187 | if (buffer_full == 2) { 188 | result = i2s_write(I2S_NUM_0, &buf[512], SIZE_OF_COVOX_BUF_IN_BYTES/2, &bytesWritten, portMAX_DELAY); 189 | } 190 | if (result != ESP_OK) Serial.println("error in i2s_write (covox)"); 191 | totalSamplesPlayed += bytesWritten/4; 192 | buffer_full = 0; 193 | } // COVOX 194 | 195 | if ((mode == DSS) && buffer_full) { 196 | esp_err_t result; 197 | size_t bytesWritten; 198 | if (buffer_full == 1) { 199 | result = i2s_write(I2S_NUM_0, &buf[0], SIZE_OF_DSS_BUF_IN_BYTES/2, &bytesWritten, portMAX_DELAY); 200 | } 201 | if (buffer_full == 2) { 202 | result = i2s_write(I2S_NUM_0, &buf[128], SIZE_OF_DSS_BUF_IN_BYTES/2, &bytesWritten, portMAX_DELAY); 203 | } 204 | if (result != ESP_OK) Serial.println("error in i2s_write (dss)"); 205 | totalSamplesPlayed += bytesWritten/4; 206 | buffer_full = 0; 207 | } // DSS 208 | 209 | /*static uint32_t oldtime = 0, newtime = 0; 210 | newtime = micros(); 211 | if ( (newtime-oldtime) > 100000 ) { 212 | //Serial.print(totalSampleCounter*4-totalSamplesPlayed); Serial.print(" / "); Serial.println(totalFifoInterruptCounter); 213 | Serial.print(mode); Serial.print(" "); Serial.print(modeA); Serial.print(" "); Serial.print(modeB); Serial.print(" "); Serial.println(totalSamplesPlayed); 214 | //Serial.print(cycles); Serial.print(" "); Serial.println(totalSamplesPlayed); 215 | oldtime = newtime; 216 | }*/ 217 | 218 | static uint32_t dss_detect = 0; 219 | if (mode == DSS) if (REG_READ(GPIO_IN_REG) & (1< 1000) change_mode(COVOX); 221 | //if (mode != DSS) if (REG_READ(GPIO_IN_REG) & (1<>D0)&1)<<0) | (((r>>D1)&1)<<1) | (((r>>D2)&1)<<2) | (((r>>D3)&1)<<3) | (((r>>D4)&1)<<4) | (((r>>D5)&1)<<5) | (((r>>D6)&1)<<6) | (((r>>D7)&1)<<7)) 20 | 21 | #define VOLUME 4 // 0 min, 8 max 22 | 23 | #define SIZE_OF_COVOX_BUF_IN_BYTES 2048*4 24 | 25 | uint32_t buf[2048]; 26 | volatile uint32_t totalSampleCounter = 0; 27 | volatile uint32_t totalChannelInterruptCounter = 0; 28 | volatile uint8_t buffer_full = 0; 29 | uint32_t totalSamplesPlayed = 0; 30 | volatile uint32_t left = 0, right = 0; 31 | volatile uint32_t cycles = 0; 32 | 33 | void IRAM_ATTR isr_sample_covox_stereo() { 34 | //uint16_t out_left = (left - 128) << VOLUME; 35 | //uint16_t out_right = (right - 128) << VOLUME; 36 | uint32_t l = left, r = right; 37 | uint16_t out_left = (CONVERT_GPIOREG_TO_SAMPLE(l)-128) << VOLUME; 38 | uint16_t out_right = (CONVERT_GPIOREG_TO_SAMPLE(r)-128) << VOLUME; 39 | //uint16_t out_left = 0, out_right = 0; 40 | uint16_t i = totalSampleCounter & 2047; 41 | buf[i] = (out_right << 16) | out_left; 42 | if (i == 1023) buffer_full = 1; 43 | if (i == 2047) buffer_full = 2; 44 | totalSampleCounter++; 45 | } 46 | 47 | // PM7528HP: DAC A inverted, DAC B not inverted 48 | static void core0_task_covox_stereo(void *args) { 49 | disableCore0WDT(); 50 | disableLoopWDT(); 51 | while (1) { 52 | //do { a = REG_READ(GPIO_IN_REG); } while (!(a&(1< 100000 ) { 201 | //if ( (newtime-oldtime) > 1000000 ) { 202 | if ( newtime > oldtime ) { 203 | //Serial.print(totalSampleCounter*4-totalSamplesPlayed); Serial.print(" / "); Serial.println(totalFifoInterruptCounter); 204 | //Serial.print(mode); Serial.print(" "); Serial.print(modeA); Serial.print(" "); Serial.print(modeB); Serial.print(" "); Serial.println(totalSamplesPlayed); 205 | //Serial.println(totalChannelInterruptCounter-last); last = totalChannelInterruptCounter; 206 | //Serial.println(millis()); 207 | //Serial.println(cycles); 208 | drawing = 1; 209 | for (uint32_t i = 0; i < 150; i++) { 210 | //Serial.print((s[i] >> STEREO_CHANNEL_SELECT)&1); Serial.print(" "); Serial.println(i/50.0); 211 | //Serial.print((sin(i/5.0)+1.0)/2.0); Serial.print(" "); Serial.println(i/50.0); 212 | Serial.print((s[i] >> STEREO_CHANNEL_SELECT)&1); 213 | } 214 | Serial.println(); 215 | drawing = 0; 216 | oldtime += 100000;//oldtime = newtime; 217 | }*/ 218 | /*if (cnt != oldcnt) { 219 | //for (uint32_t i = 0; i < 150; i++) Serial.print((s[i] >> STEREO_CHANNEL_SELECT)&1); 220 | Serial.print(" "); Serial.println(cnt); 221 | oldcnt = cnt; 222 | }*/ 223 | 224 | } 225 | -------------------------------------------------------------------------------- /old/test3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "freertos/FreeRTOS.h" 3 | #include "freertos/task.h" 4 | #include "driver/i2s.h" 5 | #include "driver/gpio.h" 6 | #include "esp_system.h" 7 | #include "esp_log.h" 8 | #include "soc/rtc.h" 9 | #include "hal/gpio_hal.h" 10 | 11 | 12 | #define VOLUME 4 // 0 min, 8 max 13 | #define DEBUG 14 | //#define EXTRA_GND 26 15 | 16 | #define D0 13 // white 17 | #define D1 14 // grey 18 | #define D2 27 // yellow 19 | #define D3 26 // brown 20 | #define D4 9 // blue 21 | #define D5 10 // purple 22 | #define D6 18 // pink 23 | #define D7 23 // green 24 | 25 | #define I2S_BCK_IO (GPIO_NUM_33) //4) 26 | #define I2S_WS_IO (GPIO_NUM_5) 27 | #define I2S_DO_IO (GPIO_NUM_32) //18) 28 | 29 | #define FIFOCLK 19 // fifoclock, 17 (Select Printer_) (PC->DSS) 30 | #define FIFOFULL 22 // fifofull, 10 (ACK) (DSS->PC) 31 | 32 | //#define STEREO_CHANNEL_SELECT 4 33 | //#define STEREO_CHANNEL_SELECT_PULLUP 25 34 | 35 | #define GPIO_DSS 2 36 | 37 | #define SIZE_OF_DSS_BUF_IN_BYTES 256*4 38 | #define CONVERT_GPIOREG_TO_SAMPLE(r) (uint8_t)((((r>>D0)&1)<<0) | (((r>>D1)&1)<<1) | (((r>>D2)&1)<<2) | (((r>>D3)&1)<<3) | (((r>>D4)&1)<<4) | (((r>>D5)&1)<<5) | (((r>>D6)&1)<<6) | (((r>>D7)&1)<<7)) 39 | TaskHandle_t myTaskHandle = NULL; 40 | 41 | #define SAMPLE_RATE_DSS (14000) 42 | #define SAMPLE_RATE_COVOX (96000) 43 | #define I2S_NUM (0) 44 | #define I2S_DI_IO (-1) 45 | 46 | static const char* TAG = "mcgurk_DSS_system"; 47 | 48 | enum MODE { NONE = 0, COVOX = 1, DSS = 2, STEREO = 3 }; 49 | enum MODE mode = NONE; 50 | 51 | uint32_t buf[1024]; 52 | volatile uint32_t totalTaskCounter = 0; 53 | volatile uint32_t totalSampleCounter = 0; 54 | uint32_t totalSamplesPlayed = 0; 55 | volatile uint8_t buffer_full = 0; 56 | volatile uint8_t front = 0; 57 | volatile uint8_t back = 0; 58 | volatile uint32_t fifo_buf[256]; 59 | #define fcnt ((uint8_t)(back-front)) // 0-16 60 | volatile uint8_t debug = 0; 61 | 62 | #define BOOL_DSS (REG_READ(GPIO_IN_REG)&(1 << GPIO_DSS)) 63 | 64 | void dss_routine(void) { 65 | while(1) { 66 | register uint32_t a; 67 | do { a = REG_READ(GPIO_IN_REG); } while (!(a & (1< 0) { 98 | uint32_t reg = fifo_buf[front++]; 99 | uint16_t s = (CONVERT_GPIOREG_TO_SAMPLE(reg)-128) << VOLUME; 100 | out = (s << 16) | s; 101 | } else out = 0; 102 | if (fcnt < 16) GPIO.out_w1tc = ((uint32_t)1 << FIFOFULL); //digitalWrite(FIFOFULL, LOW); 103 | } 104 | buf[i] = out; 105 | if (i == 127) buffer_full = 1; 106 | if (i == 255) buffer_full = 2; 107 | totalSampleCounter++; 108 | /*uint32_t reg = REG_READ(GPIO_IN_REG); 109 | uint16_t s = (CONVERT_GPIOREG_TO_SAMPLE(reg)-128) << VOLUME; 110 | uint16_t i = totalSampleCounter & 1023; 111 | out = (s << 16) | s; 112 | buf[i] = out; 113 | if (i == 511) buffer_full = 1; 114 | if (i == 1023) buffer_full = 2;*/ 115 | } 116 | 117 | 118 | void change_mode(enum MODE new_mode) { 119 | enum MODE old_mode = mode; 120 | if (new_mode == old_mode) return; 121 | mode = NONE; 122 | 123 | for (int i = 0; i < sizeof(buf)/sizeof(uint32_t); i++) buf[i] = 0; 124 | for (int i = 0; i < sizeof(fifo_buf)/sizeof(uint32_t); i++) fifo_buf[i] = 0; 125 | front = 0; back = 0; 126 | totalSampleCounter = 0; 127 | buffer_full = 0; 128 | 129 | switch (old_mode) { //disable current mode 130 | case COVOX: 131 | //vTaskDelete(task_handle_covox); //disable task 132 | //detachInterrupt(I2S_WS); //disable i2s interrupt 133 | i2s_stop(I2S_NUM_0); //stop i2s 134 | break; 135 | case DSS: 136 | gpio_set_level(GPIO_DSS, 0); 137 | //vTaskDelete(task_handle_dss); //disable task 138 | //detachInterrupt(I2S_WS); //disable i2s interrupt 139 | i2s_stop(I2S_NUM_0); //stop i2s 140 | break; 141 | case STEREO: 142 | //vTaskDelete(task_handle_stereo); //disable task 143 | //detachInterrupt(I2S_WS); //disable i2s interrupt 144 | i2s_stop(I2S_NUM_0); //stop i2s 145 | break; 146 | default: 147 | break; 148 | } 149 | 150 | switch (new_mode) { 151 | case COVOX: //dss -> covox 152 | // I don't like this much... if I put COVOX to core0, DSS doesn't work after COVOX without crackling. so I must use core1 to COVOX: 153 | //xTaskCreatePinnedToCore(core0_task_covox, "core0_task_covox", 4096, NULL, 5, &task_handle_covox, 1); // create task_handle_covox (creates I2S_WS interrupt) 154 | i2s_set_sample_rates(I2S_NUM_0, SAMPLE_RATE_COVOX); // set sample rate 155 | i2s_start(I2S_NUM_0); 156 | break; 157 | case DSS: // covox -> dss 158 | i2s_set_sample_rates(I2S_NUM_0, SAMPLE_RATE_DSS); // set sample rate 159 | i2s_start(I2S_NUM_0); 160 | //xTaskCreatePinnedToCore(core0_task_dss, "core0_task_dss", 4096, NULL, 5, &task_handle_dss, 0); // create task_handle_dss 161 | //attachInterrupt(I2S_WS, isr_sample_dss, RISING); // handles i2s samples 162 | gpio_set_level(GPIO_DSS, 1); 163 | break; 164 | case STEREO: 165 | i2s_set_sample_rates(I2S_NUM_0, SAMPLE_RATE_COVOX); // set sample rate 166 | i2s_start(I2S_NUM_0); 167 | //xTaskCreatePinnedToCore(core0_task_stereo, "core0_task_stereo", 4096, NULL, 5, &task_handle_stereo, 0); 168 | //attachInterrupt(I2S_WS, isr_sample_stereo, RISING); 169 | //pinMode(STEREO_CHANNEL_SELECT_PULLUP, OUTPUT); digitalWrite(STEREO_CHANNEL_SELECT_PULLUP, HIGH); 170 | break; 171 | default: 172 | break; 173 | } 174 | 175 | mode = new_mode; 176 | printf("New mode!: %i", mode); 177 | } 178 | 179 | #define PIN_TO_INPUT(pin) \ 180 | gpio_reset_pin(pin); \ 181 | gpio_pad_select_gpio(pin); \ 182 | gpio_set_direction(pin, GPIO_MODE_INPUT); \ 183 | gpio_pulldown_dis(pin); \ 184 | gpio_pullup_dis(pin); 185 | 186 | #define PIN_TO_OUTPUT(pin) \ 187 | gpio_reset_pin(pin); \ 188 | gpio_pad_select_gpio(pin); \ 189 | gpio_set_direction(pin, GPIO_MODE_OUTPUT); 190 | 191 | #define ms_to_cycles(a) 160000000L/1000L*a 192 | #define cycles xthal_get_ccount 193 | 194 | void app_main(void) 195 | { 196 | 197 | i2s_config_t i2s_config = { 198 | .mode = I2S_MODE_MASTER | I2S_MODE_TX, 199 | .sample_rate = SAMPLE_RATE_DSS, 200 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 201 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 202 | .communication_format = I2S_COMM_FORMAT_STAND_I2S, //I2S_COMM_FORMAT_STAND_MSB, 203 | .dma_buf_count = 2, 204 | .dma_buf_len = 256, 205 | .use_apll = false, 206 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1 207 | }; 208 | i2s_pin_config_t pin_config = { 209 | .mck_io_num = I2S_PIN_NO_CHANGE, 210 | .bck_io_num = I2S_BCK_IO, 211 | .ws_io_num = I2S_WS_IO, 212 | .data_out_num = I2S_DO_IO, 213 | .data_in_num = I2S_DI_IO //Not used 214 | }; 215 | i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); 216 | i2s_set_pin(I2S_NUM, &pin_config); 217 | 218 | printf("setup running on core: %i\n", xPortGetCoreID()); 219 | xTaskCreatePinnedToCore(core1_task, "Core1_Task", 4096, NULL,10, &myTaskHandle, 1); 220 | 221 | //ESP_LOGI(TAG, "set clock"); 222 | //i2s_set_clk(I2S_NUM, SAMPLE_RATE, 16, 2); 223 | //ESP_LOGI(TAG, "write data"); 224 | //for (int i = 0; i< 100; i++) fifo_buf[i]=i; 225 | 226 | PIN_TO_INPUT(D0); PIN_TO_INPUT(D1); PIN_TO_INPUT(D2); PIN_TO_INPUT(D3); PIN_TO_INPUT(D4); PIN_TO_INPUT(D5); PIN_TO_INPUT(D6); PIN_TO_INPUT(D7); 227 | PIN_TO_INPUT(FIFOCLK); PIN_TO_OUTPUT(FIFOFULL); gpio_set_level(FIFOFULL, 0); 228 | //PIN_TO_OUTPUT(GPIO_DSS); gpio_set_level(GPIO_DSS, 0); 229 | 230 | gpio_install_isr_service(0); 231 | gpio_set_intr_type(I2S_WS_IO, GPIO_INTR_POSEDGE); 232 | gpio_isr_handler_add(I2S_WS_IO, isr_dssfifo, NULL); 233 | gpio_hal_context_t gpiohal; gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); 234 | gpio_hal_input_enable(&gpiohal, I2S_WS_IO); 235 | //gpio_hal_input_enable(&gpiohal, GPIO_DSS); 236 | 237 | ESP_LOGI(TAG, "log test"); 238 | 239 | //change_mode(DSS); 240 | //i2s_set_clk(I2S_NUM, SAMPLE_RATE_DSS, 16, 2); 241 | mode = DSS; 242 | 243 | while (1) { 244 | 245 | size_t i2s_bytes_write; 246 | //if ((mode == DSS) & buffer_full) { 247 | if (buffer_full) { 248 | if (buffer_full == 1) i2s_write(I2S_NUM_0, &buf[0], SIZE_OF_DSS_BUF_IN_BYTES/2, &i2s_bytes_write, portMAX_DELAY); 249 | if (buffer_full == 2) i2s_write(I2S_NUM_0, &buf[128], SIZE_OF_DSS_BUF_IN_BYTES/2, &i2s_bytes_write, portMAX_DELAY); 250 | buffer_full = 0; 251 | totalSamplesPlayed += i2s_bytes_write/4; 252 | } 253 | /*if ((mode != DSS) & buffer_full) { 254 | if (buffer_full == 1) i2s_write(I2S_NUM_0, &buf[0], 512*4, &i2s_bytes_write, portMAX_DELAY); 255 | if (buffer_full == 2) i2s_write(I2S_NUM_0, &buf[512], 512*4, &i2s_bytes_write, portMAX_DELAY); 256 | buffer_full = 0; 257 | totalSamplesPlayed += i2s_bytes_write/4; 258 | }*/ 259 | 260 | // debug: 261 | static uint32_t oldtime = 0, newtime = 0; 262 | newtime = xthal_get_ccount(); 263 | if ( (newtime - oldtime) < 2000000000L ) { 264 | rtc_cpu_freq_config_t conf; 265 | rtc_clk_cpu_freq_get_config(&conf); 266 | printf("main core: %i, cpu speed: %u, cycles: %u, ",xPortGetCoreID(), conf.freq_mhz, xthal_get_ccount()); 267 | printf("totalTaskCounter: %u, ", totalTaskCounter); 268 | printf("totalSampleCounter: %u, ", totalSampleCounter); 269 | printf("totalSamplesPlayed: %u, ", totalSamplesPlayed); 270 | printf("difference: %u\n", totalSampleCounter-totalSamplesPlayed); 271 | //for (int i = 0; i< 100; i++) printf("%i,", fifo_buf[i]); 272 | //for (int i = 0; i< 100; i++) printf("%i,", CONVERT_GPIOREG_TO_SAMPLE(fifo_buf[i])); 273 | //for (int i = 0; i< 20; i++) printf("%i,", buf[i]&255); 274 | //printf("\n"); 275 | oldtime += ms_to_cycles(1000); 276 | 277 | /*static uint8_t test = 0; 278 | test ^= 0xff; 279 | gpio_set_level(BIT_DSS, test); 280 | printf("%i\n", debug);*/ 281 | } 282 | 283 | //if (mode != STEREO) { // don't autodetect COVOX or DSS in STEREO-mode 284 | /*static uint32_t dss_detect = 0; 285 | //if (REG_READ(GPIO_IN_REG) & (1< ms_to_cycles(1000)) change_mode(COVOX); 288 | if (mode != DSS) if (REG_READ(GPIO_IN_REG) & (1< 2 | #include "freertos/FreeRTOS.h" 3 | #include "freertos/task.h" 4 | #include "driver/i2s.h" 5 | #include "driver/gpio.h" 6 | #include "esp_system.h" 7 | #include "esp_log.h" 8 | #include "soc/rtc.h" 9 | #include "hal/gpio_hal.h" 10 | 11 | 12 | #define VOLUME 4 // 0 min, 8 max 13 | #define DEBUG 14 | //#define EXTRA_GND 26 15 | 16 | #define D0 13 // white 17 | #define D1 14 // grey 18 | #define D2 27 // yellow 19 | #define D3 26 // brown 20 | #define D4 9 // blue 21 | #define D5 10 // purple 22 | #define D6 18 // pink 23 | #define D7 23 // green 24 | 25 | #define I2S_BCK_IO (GPIO_NUM_33) //4) 26 | #define I2S_WS_IO (GPIO_NUM_5) 27 | #define I2S_DO_IO (GPIO_NUM_32) //18) 28 | 29 | #define FIFOCLK 19 // fifoclock, 17 (Select Printer_) (PC->DSS) 30 | #define FIFOFULL 22 // fifofull, 10 (ACK) (DSS->PC) 31 | 32 | //#define STEREO_CHANNEL_SELECT 4 33 | //#define STEREO_CHANNEL_SELECT_PULLUP 25 34 | 35 | #define GPIO_DSS 2 36 | 37 | #define SIZE_OF_DSS_BUF_IN_BYTES 256*4 38 | #define CONVERT_GPIOREG_TO_SAMPLE(r) (uint8_t)((((r>>D0)&1)<<0) | (((r>>D1)&1)<<1) | (((r>>D2)&1)<<2) | (((r>>D3)&1)<<3) | (((r>>D4)&1)<<4) | (((r>>D5)&1)<<5) | (((r>>D6)&1)<<6) | (((r>>D7)&1)<<7)) 39 | TaskHandle_t myTaskHandle = NULL; 40 | 41 | #define SAMPLE_RATE_DSS (14000) 42 | #define SAMPLE_RATE_COVOX (96000) 43 | #define I2S_NUM (0) 44 | #define I2S_DI_IO (-1) 45 | 46 | static const char* TAG = "mcgurk_DSS_system"; 47 | 48 | enum MODE { NONE = 0, COVOX = 1, DSS = 2, STEREO = 3 }; 49 | uint32_t mode = NONE; 50 | 51 | uint32_t buf[1024]; 52 | volatile uint32_t totalTaskCounter = 0; 53 | volatile uint32_t totalSampleCounter = 0; 54 | uint32_t totalSamplesPlayed = 0; 55 | volatile uint8_t buffer_full = 0; 56 | volatile uint8_t front = 0; 57 | volatile uint8_t back = 0; 58 | volatile uint32_t fifo_buf[256]; 59 | #define fcnt ((uint8_t)(back-front)) // 0-16 60 | volatile uint32_t debug = 0; 61 | 62 | #define BOOL_DSS (REG_READ(GPIO_IN_REG)&(1 << GPIO_DSS)) 63 | 64 | i2s_config_t i2s_config_covox = { 65 | .mode = I2S_MODE_MASTER | I2S_MODE_TX, 66 | .sample_rate = SAMPLE_RATE_COVOX, 67 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 68 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 69 | .communication_format = I2S_COMM_FORMAT_STAND_I2S, 70 | .dma_buf_count = 4, 71 | .dma_buf_len = 512, 72 | .use_apll = false, 73 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1 74 | }; 75 | 76 | i2s_config_t i2s_config_dss = { 77 | .mode = I2S_MODE_MASTER | I2S_MODE_TX, 78 | .sample_rate = SAMPLE_RATE_DSS, 79 | .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, 80 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 81 | .communication_format = I2S_COMM_FORMAT_STAND_I2S, 82 | .dma_buf_count = 2, 83 | .dma_buf_len = 128, 84 | .use_apll = false, 85 | .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1 86 | }; 87 | 88 | i2s_pin_config_t pin_config = { 89 | .mck_io_num = I2S_PIN_NO_CHANGE, 90 | .bck_io_num = I2S_BCK_IO, 91 | .ws_io_num = I2S_WS_IO, 92 | .data_out_num = I2S_DO_IO, 93 | .data_in_num = I2S_DI_IO //Not used 94 | }; 95 | 96 | void dss_routine(void) { 97 | while(1) { 98 | register uint32_t a; 99 | do { a = REG_READ(GPIO_IN_REG); if ( !BOOL_DSS ) return; } while (!(a & (1< 0) { 145 | uint32_t reg = fifo_buf[front++]; 146 | uint16_t s = (CONVERT_GPIOREG_TO_SAMPLE(reg)-128) << VOLUME; 147 | out = (s << 16) | s; 148 | } else out = 0; 149 | if (fcnt < 16) GPIO.out_w1tc = ((uint32_t)1 << FIFOFULL); //digitalWrite(FIFOFULL, LOW); 150 | } 151 | buf[i] = out; 152 | if (i == 127) buffer_full = 1; 153 | if (i == 255) buffer_full = 2; 154 | totalSampleCounter++; 155 | } 156 | 157 | 158 | void change_mode(uint32_t new_mode) { 159 | uint32_t old_mode = mode; 160 | if (new_mode == old_mode) return; 161 | mode = NONE; 162 | 163 | for (int i = 0; i < sizeof(buf)/sizeof(uint32_t); i++) buf[i] = 0; 164 | for (int i = 0; i < sizeof(fifo_buf)/sizeof(uint32_t); i++) fifo_buf[i] = 0; 165 | front = 0; back = 0; 166 | totalSampleCounter = 0; 167 | buffer_full = 0; 168 | 169 | switch (old_mode) { //disable current mode 170 | case COVOX: 171 | gpio_isr_handler_remove(I2S_WS_IO); 172 | //vTaskDelete(task_handle_covox); //disable task 173 | //detachInterrupt(I2S_WS); //disable i2s interrupt 174 | //i2s_stop(I2S_NUM_0); //stop i2s 175 | i2s_driver_uninstall(I2S_NUM_0); 176 | break; 177 | case DSS: 178 | gpio_set_level(GPIO_DSS, 0); 179 | gpio_isr_handler_remove(I2S_WS_IO); 180 | //vTaskDelete(task_handle_dss); //disable task 181 | //detachInterrupt(I2S_WS); //disable i2s interrupt 182 | i2s_stop(I2S_NUM_0); //stop i2s 183 | i2s_driver_uninstall(I2S_NUM_0); 184 | break; 185 | case STEREO: 186 | //vTaskDelete(task_handle_stereo); //disable task 187 | //detachInterrupt(I2S_WS); //disable i2s interrupt 188 | i2s_stop(I2S_NUM_0); //stop i2s 189 | break; 190 | default: 191 | break; 192 | } 193 | 194 | switch (new_mode) { 195 | case COVOX: //dss -> covox 196 | // I don't like this much... if I put COVOX to core0, DSS doesn't work after COVOX without crackling. so I must use core1 to COVOX: 197 | //xTaskCreatePinnedToCore(core0_task_covox, "core0_task_covox", 4096, NULL, 5, &task_handle_covox, 1); // create task_handle_covox (creates I2S_WS interrupt) 198 | i2s_driver_install(I2S_NUM, &i2s_config_covox, 0, NULL); 199 | i2s_set_pin(I2S_NUM, &pin_config); 200 | //i2s_set_sample_rates(I2S_NUM_0, SAMPLE_RATE_COVOX); // set sample rate 201 | //i2s_start(I2S_NUM_0); 202 | gpio_isr_handler_add(I2S_WS_IO, isr_sample_covox, NULL); 203 | break; 204 | case DSS: // covox -> dss 205 | i2s_driver_install(I2S_NUM, &i2s_config_dss, 0, NULL); 206 | i2s_set_pin(I2S_NUM, &pin_config); 207 | //i2s_set_sample_rates(I2S_NUM_0, SAMPLE_RATE_DSS); // set sample rate 208 | //i2s_start(I2S_NUM_0); 209 | //xTaskCreatePinnedToCore(core0_task_dss, "core0_task_dss", 4096, NULL, 5, &task_handle_dss, 0); // create task_handle_dss 210 | //attachInterrupt(I2S_WS, isr_sample_dss, RISING); // handles i2s samples 211 | gpio_isr_handler_add(I2S_WS_IO, isr_dssfifo, NULL); 212 | gpio_set_level(GPIO_DSS, 1); 213 | break; 214 | case STEREO: 215 | i2s_set_sample_rates(I2S_NUM_0, SAMPLE_RATE_COVOX); // set sample rate 216 | i2s_start(I2S_NUM_0); 217 | //xTaskCreatePinnedToCore(core0_task_stereo, "core0_task_stereo", 4096, NULL, 5, &task_handle_stereo, 0); 218 | //attachInterrupt(I2S_WS, isr_sample_stereo, RISING); 219 | //pinMode(STEREO_CHANNEL_SELECT_PULLUP, OUTPUT); digitalWrite(STEREO_CHANNEL_SELECT_PULLUP, HIGH); 220 | break; 221 | default: 222 | break; 223 | } 224 | 225 | gpio_hal_context_t gpiohal; gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); 226 | gpio_hal_input_enable(&gpiohal, I2S_WS_IO); 227 | mode = new_mode; 228 | printf("New mode!: %i\n", mode); 229 | } 230 | 231 | #define PIN_TO_INPUT(pin) \ 232 | gpio_reset_pin(pin); \ 233 | gpio_pad_select_gpio(pin); \ 234 | gpio_set_direction(pin, GPIO_MODE_INPUT); \ 235 | gpio_pulldown_dis(pin); \ 236 | gpio_pullup_dis(pin); 237 | 238 | #define PIN_TO_OUTPUT(pin) \ 239 | gpio_reset_pin(pin); \ 240 | gpio_pad_select_gpio(pin); \ 241 | gpio_set_direction(pin, GPIO_MODE_OUTPUT); 242 | 243 | #define ms_to_cycles(a) 160000000L/1000L*a 244 | #define cycles xthal_get_ccount 245 | 246 | void app_main(void) 247 | { 248 | 249 | 250 | //i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); 251 | //i2s_set_pin(I2S_NUM, &pin_config); 252 | 253 | printf("setup running on core: %i\n", xPortGetCoreID()); 254 | xTaskCreatePinnedToCore(core1_task, "Core1_Task", 4096, NULL,10, &myTaskHandle, 1); 255 | 256 | //ESP_LOGI(TAG, "set clock"); 257 | //i2s_set_clk(I2S_NUM, SAMPLE_RATE, 16, 2); 258 | //ESP_LOGI(TAG, "write data"); 259 | //for (int i = 0; i< 100; i++) fifo_buf[i]=i; 260 | 261 | PIN_TO_INPUT(D0); PIN_TO_INPUT(D1); PIN_TO_INPUT(D2); PIN_TO_INPUT(D3); PIN_TO_INPUT(D4); PIN_TO_INPUT(D5); PIN_TO_INPUT(D6); PIN_TO_INPUT(D7); 262 | PIN_TO_INPUT(FIFOCLK); PIN_TO_OUTPUT(FIFOFULL); gpio_set_level(FIFOFULL, 0); 263 | PIN_TO_OUTPUT(GPIO_DSS); gpio_set_level(GPIO_DSS, 0); 264 | 265 | gpio_install_isr_service(0); 266 | gpio_set_intr_type(I2S_WS_IO, GPIO_INTR_POSEDGE); 267 | //gpio_isr_handler_add(I2S_WS_IO, isr_dssfifo, NULL); 268 | gpio_hal_context_t gpiohal; gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); 269 | //gpio_hal_input_enable(&gpiohal, I2S_WS_IO); 270 | gpio_hal_input_enable(&gpiohal, GPIO_DSS); 271 | 272 | ESP_LOGI(TAG, "log test"); 273 | 274 | //change_mode(DSS); 275 | //i2s_set_clk(I2S_NUM, SAMPLE_RATE_DSS, 16, 2); 276 | //mode = DSS; 277 | change_mode(COVOX); 278 | 279 | while (1) { 280 | 281 | size_t i2s_bytes_write; 282 | if ((mode == DSS) && buffer_full) { 283 | //if (buffer_full) { 284 | if (buffer_full == 1) i2s_write(I2S_NUM_0, &buf[0], SIZE_OF_DSS_BUF_IN_BYTES/2, &i2s_bytes_write, portMAX_DELAY); 285 | if (buffer_full == 2) i2s_write(I2S_NUM_0, &buf[128], SIZE_OF_DSS_BUF_IN_BYTES/2, &i2s_bytes_write, portMAX_DELAY); 286 | buffer_full = 0; 287 | totalSamplesPlayed += i2s_bytes_write/4; 288 | } 289 | if ((mode != DSS) && buffer_full) { 290 | if (buffer_full == 1) i2s_write(I2S_NUM_0, &buf[0], 512*4, &i2s_bytes_write, portMAX_DELAY); 291 | if (buffer_full == 2) i2s_write(I2S_NUM_0, &buf[512], 512*4, &i2s_bytes_write, portMAX_DELAY); 292 | buffer_full = 0; 293 | totalSamplesPlayed += i2s_bytes_write/4; 294 | } 295 | 296 | // debug: 297 | static uint32_t oldtime = 0, newtime = 0; 298 | newtime = xthal_get_ccount(); 299 | if ( (newtime - oldtime) < 2000000000L ) { 300 | rtc_cpu_freq_config_t conf; 301 | rtc_clk_cpu_freq_get_config(&conf); 302 | //printf("main core: %i, cpu speed: %u, cycles: %u, ",xPortGetCoreID(), conf.freq_mhz, xthal_get_ccount()); 303 | printf("main core: %i, cpu speed: %u, ",xPortGetCoreID(), conf.freq_mhz); 304 | printf("debug: %u, ", debug); 305 | printf("BOOL_DSS: %u, ", BOOL_DSS); 306 | printf("totalTaskCounter: %u, ", totalTaskCounter); 307 | printf("totalSampleCounter: %u, ", totalSampleCounter); 308 | printf("totalSamplesPlayed: %u, ", totalSamplesPlayed); 309 | printf("difference: %u\n", totalSampleCounter-totalSamplesPlayed); 310 | //for (int i = 0; i< 100; i++) printf("%i,", fifo_buf[i]); 311 | //for (int i = 0; i< 100; i++) printf("%i,", CONVERT_GPIOREG_TO_SAMPLE(fifo_buf[i])); 312 | //for (int i = 0; i< 20; i++) printf("%i,", buf[i]&255); 313 | //printf("\n"); 314 | oldtime += ms_to_cycles(1000); 315 | 316 | /*static uint8_t test = 0; 317 | test ^= 0xff; 318 | gpio_set_level(BIT_DSS, test); 319 | printf("%i\n", debug);*/ 320 | } 321 | 322 | //if (mode != STEREO) { // don't autodetect COVOX or DSS in STEREO-mode 323 | static uint32_t dss_detect = 0; 324 | //if (REG_READ(GPIO_IN_REG) & (1< ms_to_cycles(1000)) change_mode(COVOX); 327 | if (mode != DSS) if (REG_READ(GPIO_IN_REG) & (1<>D0)&1)<<0) | (((r>>D1)&1)<<1) | (((r>>D2)&1)<<2) | (((r>>D3)&1)<<3) | (((r>>D4)&1)<<4) | (((r>>D5)&1)<<5) | (((r>>D6)&1)<<6) | (((r>>D7)&1)<<7)) 20 | 21 | #define VOLUME 4 // 0 min, 8 max 22 | 23 | #define SIZE_OF_COVOX_BUF_IN_BYTES 2048*4 24 | 25 | uint32_t buf[2048]; 26 | volatile uint32_t totalSampleCounter = 0; 27 | volatile uint32_t totalChannelInterruptCounter = 0; 28 | volatile uint8_t buffer_full = 0; 29 | uint32_t totalSamplesPlayed = 0; 30 | volatile uint32_t left = 0, right = 0; 31 | volatile uint32_t cycles = 0; 32 | 33 | void IRAM_ATTR isr_sample_covox_stereo() { 34 | //uint16_t out_left = (left - 128) << VOLUME; 35 | //uint16_t out_right = (right - 128) << VOLUME; 36 | uint32_t l = left, r = right; 37 | uint16_t out_left = (CONVERT_GPIOREG_TO_SAMPLE(l)-128) << VOLUME; 38 | uint16_t out_right = (CONVERT_GPIOREG_TO_SAMPLE(r)-128) << VOLUME; 39 | //uint16_t out_left = 0, out_right = 0; 40 | uint16_t i = totalSampleCounter & 2047; 41 | buf[i] = (out_right << 16) | out_left; 42 | if (i == 1023) buffer_full = 1; 43 | if (i == 2047) buffer_full = 2; 44 | totalSampleCounter++; 45 | } 46 | 47 | /*static void core0_task_covox_stereo(void *args) { 48 | disableCore0WDT(); 49 | disableLoopWDT(); 50 | while (1) { 51 | while (!(REG_READ(GPIO_IN_REG) & (1< 100000 ) { 261 | //if ( (newtime-oldtime) > 1000000 ) { 262 | if ( newtime > oldtime ) { 263 | //Serial.print(totalSampleCounter*4-totalSamplesPlayed); Serial.print(" / "); Serial.println(totalFifoInterruptCounter); 264 | //Serial.print(mode); Serial.print(" "); Serial.print(modeA); Serial.print(" "); Serial.print(modeB); Serial.print(" "); Serial.println(totalSamplesPlayed); 265 | //Serial.println(totalChannelInterruptCounter-last); last = totalChannelInterruptCounter; 266 | //Serial.println(millis()); 267 | Serial.println(cycles); 268 | oldtime += 100000;//oldtime = newtime; 269 | }*/ 270 | 271 | } 272 | -------------------------------------------------------------------------------- /old/arduino-ide_esp32_i2s_covox-dss-stereo.ino: -------------------------------------------------------------------------------- 1 | // Not perfect sollution for Stereo-in-1. Interrupts cannot be disabled permanently in Arduino IDE. 2 | // Covox and DSS should work 3 | 4 | #include "driver/i2s.h" 5 | #include "rom/rtc.h" 6 | 7 | #define VOLUME 4 // 0 min, 8 max 8 | #define DEBUG 9 | //#define EXTRA_GND 26 10 | 11 | //COVOX 12 | #define D0 13 // white 13 | #define D1 14 // grey 14 | #define D2 27 // yellow 15 | #define D3 26 // brown 16 | #define D4 9 // blue 17 | #define D5 10 // purple 18 | #define D6 18 // pink 19 | #define D7 23 // green 20 | #define CONVERT_GPIOREG_TO_SAMPLE(r) (uint8_t)((((r>>D0)&1)<<0) | (((r>>D1)&1)<<1) | (((r>>D2)&1)<<2) | (((r>>D3)&1)<<3) | (((r>>D4)&1)<<4) | (((r>>D5)&1)<<5) | (((r>>D6)&1)<<6) | (((r>>D7)&1)<<7)) 21 | #define STEREO_CHANNEL_SELECT 4 22 | 23 | //DSS 24 | #define FIFOCLK 19 // fifoclock, 17 (Select Printer_) (PC->DSS) 25 | #define FIFOFULL 22 // fifofull, 10 (ACK) (DSS->PC) 26 | #define SIZE_OF_DSS_BUF_IN_BYTES 256*4 27 | 28 | // I2S: 29 | #define I2S_WS 5 30 | #define I2S_SCK 33 31 | #define I2S_SD 32 32 | #define SAMPLE_RATE_DSS 14000 33 | #define SAMPLE_RATE_COVOX 96000 34 | 35 | enum MODE { NONE = 0, COVOX = 1, DSS = 2, STEREO = 3 }; 36 | 37 | uint32_t buf[1024]; 38 | #define SIZE_OF_COVOX_BUF_IN_BYTES sizeof(buf) 39 | volatile uint32_t totalSampleCounter = 0; 40 | volatile uint32_t totalFifoInterruptCounter = 0; 41 | volatile uint32_t totalStereoTaskCounter = 0; 42 | volatile uint32_t buffer_full = 0; 43 | volatile uint8_t front = 0; 44 | volatile uint8_t back = 0; 45 | volatile uint32_t fifo_buf[256]; 46 | MODE mode = NONE; 47 | uint32_t totalSamplesPlayed = 0; 48 | TaskHandle_t task_handle_dss = NULL; 49 | TaskHandle_t task_handle_covox = NULL; 50 | volatile uint32_t left = 0, right = 0; 51 | 52 | #define fcnt ((uint8_t)(back-front)) // 0-16 53 | 54 | void IRAM_ATTR isr_sample_covox() { 55 | uint32_t s1 = REG_READ(GPIO_IN_REG); 56 | uint32_t s2 = REG_READ(GPIO_IN_REG); 57 | uint32_t s3 = REG_READ(GPIO_IN_REG); 58 | if (s1 != s2) s1 = s3; 59 | uint16_t out = (CONVERT_GPIOREG_TO_SAMPLE(s1) - 128) << VOLUME; 60 | uint16_t i = totalSampleCounter & 1023; 61 | buf[i] = (out << 16) | out; 62 | if (i == 511) buffer_full = 1; 63 | if (i == 1023) buffer_full = 2; 64 | totalSampleCounter++; 65 | } 66 | 67 | static void core0_task_covox(void *args) { // actually this runs in core1 68 | attachInterrupt(I2S_WS, isr_sample_covox, RISING); 69 | while (1) { 70 | vTaskDelay(10); 71 | } 72 | } 73 | 74 | 75 | void IRAM_ATTR isr_sample_dss() { 76 | static uint32_t out = 0; 77 | uint16_t i = totalSampleCounter & 255; 78 | if (i&1) {// read new "out" only every other time 79 | if (fcnt > 0) { 80 | uint32_t g = fifo_buf[front++]; 81 | uint16_t s = (CONVERT_GPIOREG_TO_SAMPLE(g)-128) << VOLUME; 82 | out = (s << 16) | s; 83 | } else out = 0; 84 | if (fcnt < 16) GPIO.out_w1tc = ((uint32_t)1 << FIFOFULL); //digitalWrite(FIFOFULL, LOW); 85 | } 86 | buf[i] = out; 87 | if (i == 127) buffer_full = 1; 88 | if (i == 255) buffer_full = 2; 89 | totalSampleCounter++; 90 | } 91 | 92 | // "The rising edge of the pulse on Pin 17 from the printer interface is used to clock data into the FIFO" 93 | // this could be optimized little more: rely on samples comes in bursts. calculate how much there is free space in fifo and fill that and then rise fifofull 94 | // whis could be done even with unrolling while with case-command 95 | static void core0_task_dss(void *args) { 96 | disableCore0WDT(); 97 | disableLoopWDT(); 98 | while (1) { 99 | while (!(REG_READ(GPIO_IN_REG) & (1< covox 242 | // I don't like this much... if I put COVOX to core0, DSS doesn't work after COVOX without crackling. so I must use core1 to COVOX: 243 | xTaskCreatePinnedToCore(core0_task_covox, "core0_task_covox", 4096, NULL, 5, &task_handle_covox, 1); // create task_handle_covox (creates I2S_WS interrupt) 244 | i2s_set_sample_rates(I2S_NUM_0, SAMPLE_RATE_COVOX); // set sample rate 245 | i2s_start(I2S_NUM_0); 246 | attachInterrupt(STEREO_CHANNEL_SELECT, isr_channelselect, RISING); // STEREO COVOX detection 247 | break; 248 | case DSS: // covox -> dss 249 | i2s_set_sample_rates(I2S_NUM_0, SAMPLE_RATE_DSS); // set sample rate 250 | i2s_start(I2S_NUM_0); 251 | xTaskCreatePinnedToCore(core0_task_dss, "core0_task_dss", 4096, NULL, 5, &task_handle_dss, 0); // create task_handle_dss 252 | attachInterrupt(I2S_WS, isr_sample_dss, RISING); // handles i2s samples 253 | break; 254 | case STEREO: 255 | i2s_set_sample_rates(I2S_NUM_0, SAMPLE_RATE_COVOX); // set sample rate 256 | i2s_start(I2S_NUM_0); 257 | xTaskCreatePinnedToCore(core0_task_covox_stereo, "core0_task_covox_stereo", 4096, NULL, 5, NULL, 0); 258 | attachInterrupt(I2S_WS, isr_sample_covox_stereo, RISING); 259 | break; 260 | default: 261 | break; 262 | } 263 | 264 | mode = new_mode; 265 | #ifdef DEBUG 266 | Serial.print("New mode!: "); Serial.println(mode); 267 | #endif 268 | } 269 | 270 | //------------------------------------------------------------------------------------------------------------------------ 271 | 272 | 273 | void setup() { 274 | pinMode(D0, INPUT); //LPT: 2 (D0) 275 | pinMode(D1, INPUT); // 3 (D1) 276 | pinMode(D2, INPUT); // 4 (D2) 277 | pinMode(D3, INPUT); // 5 (D3) 278 | pinMode(D4, INPUT); // 6 (D4) 279 | pinMode(D5, INPUT); // 7 (D5) 280 | pinMode(D6, INPUT); // 8 (D6) 281 | pinMode(D7, INPUT); // 9 (D7) 282 | // GND 283 | 284 | pinMode(FIFOCLK, INPUT); // fifoclock, 17 (Select Printer_) (PC->DSS) 285 | pinMode(FIFOFULL, OUTPUT); digitalWrite(FIFOFULL, LOW); // fifofull, 10 (ACK) (DSS->PC) 286 | pinMode(STEREO_CHANNEL_SELECT, INPUT_PULLUP); // LPT pin 1 (_strobe) 287 | //pinMode(EXTRA_GND, OUTPUT); digitalWrite(EXTRA_GND, LOW); // just another GND 288 | 289 | #ifdef DEBUG 290 | Serial.begin(115200); 291 | while(Serial.available()); 292 | Serial.println(); Serial.print("--- (compilation date: "); Serial.print(__DATE__); Serial.print(" "); Serial.print(__TIME__); Serial.println(") ---"); 293 | #endif 294 | 295 | i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); 296 | i2s_set_pin(I2S_NUM_0, &pin_config); 297 | 298 | if (rtc_get_reset_reason(0) == 5) { // STEREO COVOX 299 | change_mode(STEREO); 300 | } else { 301 | change_mode(COVOX); 302 | } 303 | 304 | } 305 | 306 | 307 | void loop() { 308 | 309 | if ((mode == COVOX || mode == STEREO) && buffer_full) { 310 | esp_err_t result; 311 | size_t bytesWritten; 312 | if (buffer_full == 1) { 313 | result = i2s_write(I2S_NUM_0, &buf[0], SIZE_OF_COVOX_BUF_IN_BYTES/2, &bytesWritten, portMAX_DELAY); 314 | } 315 | if (buffer_full == 2) { 316 | result = i2s_write(I2S_NUM_0, &buf[512], SIZE_OF_COVOX_BUF_IN_BYTES/2, &bytesWritten, portMAX_DELAY); 317 | } 318 | if (result != ESP_OK) Serial.println("error in i2s_write (covox)"); 319 | totalSamplesPlayed += bytesWritten/4; 320 | buffer_full = 0; 321 | } // COVOX 322 | 323 | if ((mode == DSS) && buffer_full) { 324 | esp_err_t result; 325 | size_t bytesWritten; 326 | if (buffer_full == 1) { 327 | result = i2s_write(I2S_NUM_0, &buf[0], SIZE_OF_DSS_BUF_IN_BYTES/2, &bytesWritten, portMAX_DELAY); 328 | } 329 | if (buffer_full == 2) { 330 | result = i2s_write(I2S_NUM_0, &buf[128], SIZE_OF_DSS_BUF_IN_BYTES/2, &bytesWritten, portMAX_DELAY); 331 | } 332 | if (result != ESP_OK) Serial.println("error in i2s_write (dss)"); 333 | totalSamplesPlayed += bytesWritten/4; 334 | buffer_full = 0; 335 | } // DSS 336 | 337 | #ifdef DEBUG 338 | static uint32_t oldtime = 0, newtime = 0, last = 0, oldcnt = 1111; 339 | newtime = micros(); 340 | //if ( (newtime-oldtime) > 100000 ) { 341 | //if ( (newtime-oldtime) > 1000000 ) { 342 | if ( newtime > oldtime ) { 343 | //Serial.print(totalSampleCounter*4-totalSamplesPlayed); Serial.print(" / "); Serial.println(totalFifoInterruptCounter); 344 | //Serial.print(mode); Serial.print(" "); Serial.print(modeA); Serial.print(" "); Serial.print(modeB); Serial.print(" "); Serial.println(totalSamplesPlayed); 345 | //Serial.println(totalChannelInterruptCounter-last); last = totalChannelInterruptCounter; 346 | //Serial.println(millis()); 347 | Serial.print(millis()); Serial.print(" "); Serial.print(totalSampleCounter); Serial.print(" "); Serial.print(totalStereoTaskCounter); Serial.print(" "); Serial.println(mode); 348 | //Serial.print(millis()); Serial.print(" "); Serial.print(back); Serial.print(" "); Serial.print(front); Serial.print(" "); Serial.print(totalFifoInterruptCounter); Serial.print(" "); Serial.println(debug); 349 | oldtime += 1000000;//oldtime = newtime; 350 | } 351 | #endif 352 | 353 | if (mode != STEREO) { // don't autodetect COVOX or DSS in STEREO-mode 354 | static uint32_t dss_detect = 0; 355 | if (mode == DSS) if (REG_READ(GPIO_IN_REG) & (1< 1000) change_mode(COVOX); 357 | //if (mode != DSS) if (REG_READ(GPIO_IN_REG) & (1<