#include #include // Sparrow mic pins (ICS-43434, I2S): // MIC_SCK -> GPIO18 (bit clock / bclk / sck) // MIC_WS -> GPIO20 (word select / ws / LRCLK) // MIC_SD -> GPIO19 (data from mic -> esp din) // // From Sparrow README pin table. (MIC_WS=GPIO20, MIC_SCK=GPIO18, MIC_SD=GPIO19) // // We'll set dout = -1 because Sparrow is only listening, not transmitting audio out. static I2SClass I2S; // recording config static const uint32_t SAMPLE_RATE_HZ = 16000; static const size_t RECORD_SECONDS = 1; // 1-second clips // We'll get 16k samples/sec * 2 bytes/sample = 32000 bytes + WAV header per clip. void setupI2SMic() { // Attach pins: setPins(bclk, ws, dout, din=-1, mclk=-1) I2S.setPins( 18, // bclk / SCK 20, // ws / LRCLK -1, // dout not used (speaker out) 19, // din (mic data line) -1 // mclk not used ); // Start I2S in standard mode @16kHz. // begin(mode, rate, bits_per_sample, slot_mode) // We ask for 32-bit slots stereo here, then we'll configure RX to give us 16-bit mono. // Why: ICS-43434 outputs a single channel in I2S format where the left slot contains mic data. :contentReference[oaicite:5]{index=5} // We'll downconvert with configureRX(..., I2S_RX_TRANSFORM_32_TO_16) bool ok = I2S.begin( I2S_MODE_STD, SAMPLE_RATE_HZ, I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_STEREO ); if(!ok){ Serial.println("ERR I2S.begin failed"); } // configureRX(rate, bits_cfg, ch, transform) // We'll request 32-bit/stereo from the bus, then have the driver transform samples // to 16-bit mono for us. ok = I2S.configureRX( SAMPLE_RATE_HZ, I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_STEREO, I2S_RX_TRANSFORM_32_TO_16 ); if(!ok){ Serial.println("ERR I2S.configureRX failed"); } } // Record N seconds of audio into RAM as a WAV buffer using recordWAV(). // This gives us a pointer + size. We then push that over Serial. void recordAndSend(const char *label) { size_t wav_size = 0; uint8_t *wav_buf = I2S.recordWAV(RECORD_SECONDS, &wav_size); if(!wav_buf || wav_size == 0){ Serial.println("ERR recordWAV failed"); return; } // Send header line so host knows what's coming. Serial.printf("CHUNK %s %u\n", label, (unsigned)wav_size); // Send raw WAV bytes (binary). Serial.write(wav_buf, wav_size); // newline then END so host knows it's done. Serial.print("\nEND\n"); // free buffer from recordWAV free(wav_buf); } void setup() { Serial.begin(115200); delay(2000); // allow USB CDC to settle, ESP32-C6 can reset on open setupI2SMic(); Serial.println("# Sparrow voice dataset recorder ready."); Serial.println("# Send 'hello' or 'other' on its own line."); } void loop() { // check if PC sent us a command static String cmd; while(Serial.available()){ char c = Serial.read(); if(c == '\n' || c == '\r'){ if(cmd.length() > 0){ if(cmd == "hello"){ recordAndSend("hello"); } else { // treat anything not "hello" as negative/background class recordAndSend("other"); } cmd = ""; } } else { cmd += c; } } delay(5); }