mirror of
https://github.com/markqvist/RNode_Firmware.git
synced 2026-04-27 22:35:36 +00:00
Microphone on I2S_NUM_0 (PDM hardware constraint), speaker moved to I2S_NUM_1. Both init at boot, shut down before deep sleep. Mic provides raw audio read and RMS level measurement. Boot beep disabled (speaker confirmed working).
82 lines
2.3 KiB
C
82 lines
2.3 KiB
C
// SPM1423 PDM Microphone Driver — Minimal audio input for T-Watch Ultra
|
|
// PDM input on I2S_NUM_0 (hardware constraint for PDM on ESP32-S3)
|
|
|
|
#ifndef MICROPHONE_H
|
|
#define MICROPHONE_H
|
|
|
|
#if BOARD_MODEL == BOARD_TWATCH_ULT
|
|
|
|
#include "driver/i2s.h"
|
|
|
|
#define MIC_CLK_PIN 17 // PDM clock (WS pin in I2S terms)
|
|
#define MIC_DAT_PIN 18 // PDM data input
|
|
#define MIC_I2S_PORT I2S_NUM_0 // PDM only works on I2S0
|
|
#define MIC_SAMPLE_RATE 16000 // 16kHz max for PDM mic
|
|
#define MIC_BUF_SIZE 1024
|
|
|
|
static bool mic_ready = false;
|
|
|
|
bool mic_init() {
|
|
i2s_config_t i2s_config = {};
|
|
i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM);
|
|
i2s_config.sample_rate = MIC_SAMPLE_RATE;
|
|
i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
|
|
i2s_config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT;
|
|
i2s_config.communication_format = I2S_COMM_FORMAT_STAND_PCM_SHORT;
|
|
i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1;
|
|
i2s_config.dma_buf_count = 6;
|
|
i2s_config.dma_buf_len = 512;
|
|
i2s_config.use_apll = true;
|
|
|
|
i2s_pin_config_t pin_config = {};
|
|
pin_config.bck_io_num = I2S_PIN_NO_CHANGE;
|
|
pin_config.ws_io_num = MIC_CLK_PIN;
|
|
pin_config.data_out_num = I2S_PIN_NO_CHANGE;
|
|
pin_config.data_in_num = MIC_DAT_PIN;
|
|
pin_config.mck_io_num = I2S_PIN_NO_CHANGE;
|
|
|
|
if (i2s_driver_install(MIC_I2S_PORT, &i2s_config, 0, NULL) != ESP_OK) {
|
|
return false;
|
|
}
|
|
if (i2s_set_pin(MIC_I2S_PORT, &pin_config) != ESP_OK) {
|
|
i2s_driver_uninstall(MIC_I2S_PORT);
|
|
return false;
|
|
}
|
|
|
|
mic_ready = true;
|
|
return true;
|
|
}
|
|
|
|
void mic_end() {
|
|
if (mic_ready) {
|
|
i2s_driver_uninstall(MIC_I2S_PORT);
|
|
mic_ready = false;
|
|
}
|
|
}
|
|
|
|
// Read raw audio samples into buffer. Returns bytes read.
|
|
size_t mic_read(int16_t *buf, size_t samples) {
|
|
if (!mic_ready) return 0;
|
|
size_t bytes_read = 0;
|
|
i2s_read(MIC_I2S_PORT, buf, samples * sizeof(int16_t), &bytes_read, portMAX_DELAY);
|
|
return bytes_read / sizeof(int16_t);
|
|
}
|
|
|
|
// Get current audio level (RMS of a short sample). Returns 0-32767.
|
|
uint16_t mic_level() {
|
|
if (!mic_ready) return 0;
|
|
|
|
int16_t buf[256];
|
|
size_t samples = mic_read(buf, 256);
|
|
if (samples == 0) return 0;
|
|
|
|
uint64_t sum_sq = 0;
|
|
for (size_t i = 0; i < samples; i++) {
|
|
int32_t s = buf[i];
|
|
sum_sq += s * s;
|
|
}
|
|
return (uint16_t)sqrt((double)sum_sq / samples);
|
|
}
|
|
|
|
#endif // BOARD_MODEL == BOARD_TWATCH_ULT
|
|
#endif // MICROPHONE_H
|