#include <Arduino.h>
#define I2S_XSMT 15
#define I2S_DOUT 16
#define I2S_BCLK 17
#define I2S_LRCLK 18
#define TONE_FREQ 440.0f
#define SAMPLE_RATE 44100
// ultra-szybkie makra rejestrowe dla ESP32-S3 (kompatybilne z Arduino 3.x)
#define BCK_HIGH() (*(volatile uint32_t *)(0x60004008) = (1 << I2S_BCLK)) // GPIO_OUT_W1TS_REG
#define BCK_LOW() (*(volatile uint32_t *)(0x6000400C) = (1 << I2S_BCLK)) // GPIO_OUT_W1TC_REG
#define LRCK_HIGH() (*(volatile uint32_t *)(0x60004008) = (1 << I2S_LRCLK))
#define LRCK_LOW() (*(volatile uint32_t *)(0x6000400C) = (1 << I2S_LRCLK))
#define DOUT_HIGH() (*(volatile uint32_t *)(0x60004008) = (1 << I2S_DOUT))
#define DOUT_LOW() (*(volatile uint32_t *)(0x6000400C) = (1 << I2S_DOUT))
void setup() {
Serial.begin(115200);
delay(500);
Serial.println("=========================================");
Serial.println("PCM5102A FAST REGISTER-BASED I2S EMULATOR");
Serial.println("=========================================");
pinMode(I2S_BCLK, OUTPUT);
pinMode(I2S_LRCLK, OUTPUT);
pinMode(I2S_DOUT, OUTPUT);
pinMode(I2S_XSMT, OUTPUT);
digitalWrite(I2S_BCLK, LOW);
digitalWrite(I2S_LRCLK, HIGH);
digitalWrite(I2S_DOUT, LOW);
digitalWrite(I2S_XSMT, HIGH); // Odciszenie DAC
Serial.println("START SZYBKIEJ EMULACJI (REGISTER BIT-BANGING)...");
}
void sendI2SSampleFast(int16_t left, int16_t right) {
// ---- KANAŁ LEWY (LRCK = LOW) ----
LRCK_LOW();
DOUT_LOW(); // Jawne wymuszenie stanu niskiego na bicie opóźnienia MSB
// Bit 1: Opóźnienie protokołu Philips (1-bit delay)
BCK_HIGH();
BCK_LOW();
// Bity 2 do 17: Wysyłanie 16 bitów właściwych danych (od MSB do LSB)
for (int b = 15; b >= 0; b--) {
if ((left >> b) & 1) { DOUT_HIGH(); } else { DOUT_LOW(); }
BCK_HIGH();
BCK_LOW();
}
// Bity 18 do 32: Dopełnienie zerami (Padding) dla 32-bitowego slotu
DOUT_LOW();
for (int b = 0; b < 15; b++) {
BCK_HIGH();
BCK_LOW();
}
// ---- KANAŁ PRAWY (LRCK = HIGH) ----
LRCK_HIGH();
DOUT_LOW(); // KOREKTA: Jawne zabezpieczenie stanu niskiego przed pierwszym taktem BCK drugiego kanału
// Bit 1: Opóźnienie protokołu Philips (1-bit delay)
BCK_HIGH();
BCK_LOW();
// Bity 2 do 17: Wysyłanie 16 bitów danych prawego kanału
for (int b = 15; b >= 0; b--) {
if ((right >> b) & 1) { DOUT_HIGH(); } else { DOUT_LOW(); }
BCK_HIGH();
BCK_LOW();
}
// Bity 18 do 32: Dopełnienie zerami (Padding) dla 32-bitowego slotu
DOUT_LOW();
for (int b = 0; b < 15; b++) {
BCK_HIGH();
BCK_LOW();
}
}
void loop() {
static float phase = 0.0f;
static uint32_t sampleCounter = 0;
static uint32_t lastReport = 0;
int16_t currentSample = (int16_t)(sinf(phase) * 15000.0f);
phase += 2.0f * PI * TONE_FREQ / SAMPLE_RATE;
if (phase >= 2.0f * PI) phase -= 2.0f * PI;
sendI2SSampleFast(currentSample, currentSample);
sampleCounter++;
if (millis() - lastReport >= 1000) {
lastReport = millis();
Serial.printf("[ESP32-S3] Generowanie aktywne. Wysłano próbki: %lu\n", (unsigned long)sampleCounter);
}
}