diff --git a/build/devices/esp32/targets/m5stack_cores3/manifest.json b/build/devices/esp32/targets/m5stack_cores3/manifest.json index 93f4f618a..c606c7b9f 100644 --- a/build/devices/esp32/targets/m5stack_cores3/manifest.json +++ b/build/devices/esp32/targets/m5stack_cores3/manifest.json @@ -10,10 +10,12 @@ "include": [ "$(MODDABLE)/modules/io/manifest.json", "$(MODDABLE)/modules/io/audioout/manifest.json", + "$(MODDABLE)/modules/io/audioin/manifest.json", "$(MODDABLE)/modules/drivers/ili9341/manifest.json", "$(MODDABLE)/modules/drivers/sensors/ft6206/manifest.json", "$(MODDABLE)/modules/drivers/peripherals/axp2101/manifest.json", - "$(MODDABLE)/modules/drivers/peripherals/bm8563/manifest.json" + "$(MODDABLE)/modules/drivers/peripherals/bm8563/manifest.json", + "$(MODDABLE)/modules/drivers/peripherals/es7210/manifest.json" ], "config": { "screen": "ili9341", @@ -114,13 +116,16 @@ } }, "audioIn": { - "sampleRate": 11025, + "sampleRate": 16000, "bitsPerSample": 16, + "numChannels": 2, "i2s": { + "num": 1, "bck_pin": 34, "lr_pin": 33, "datain": 14, - "pdm": 1 + "pdm": 0, + "slot": "(I2S_STD_SLOT_LEFT | I2S_STD_SLOT_RIGHT)" } }, "camera": { diff --git a/build/devices/esp32/targets/m5stack_cores3/setup-target.js b/build/devices/esp32/targets/m5stack_cores3/setup-target.js index 4c4b67b89..d389d8c3e 100644 --- a/build/devices/esp32/targets/m5stack_cores3/setup-target.js +++ b/build/devices/esp32/targets/m5stack_cores3/setup-target.js @@ -23,6 +23,7 @@ import config from "mc/config"; import Timer from "timer"; import AXP2101 from "embedded:peripheral/Power/axp2101"; +import ES7210 from "embedded:peripheral/Audio/es7210"; import AudioOut from "embedded:io/audio/out"; const state = { @@ -67,6 +68,15 @@ export default function (done) { // power globalThis.power = new Power({sensor: { ...device.I2C.internal, io: device.io.SMBus }}); globalThis.amp = new AW88298({sensor: { ...device.I2C.internal, io: device.io.SMBus }}); + + // microphone ADC + try { + globalThis.mic = new ES7210({sensor: { ...device.I2C.internal, io: device.io.SMBus }}); + globalThis.mic.initialize(); + } catch (e) { + trace("ES7210 microphone initialization failed: " + e + "\n"); + globalThis.mic = undefined; + } // start-up sound if (config.startupSound) { diff --git a/modules/drivers/peripherals/es7210/es7210.js b/modules/drivers/peripherals/es7210/es7210.js new file mode 100644 index 000000000..dbde6a2eb --- /dev/null +++ b/modules/drivers/peripherals/es7210/es7210.js @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024 Moddable Tech, Inc. + * + * This file is part of the Moddable SDK Runtime. + * + * The Moddable SDK Runtime is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Moddable SDK Runtime is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the Moddable SDK Runtime. If not, see . + * + */ + +/** + * ES7210 ADC driver for M5Stack CoreS3 microphone + * Based on M5Unified implementation + */ +class ES7210 { + #io; + + constructor(options) { + this.#io = new options.sensor.io({ + hz: 400_000, + address: 0x40, + ...options.sensor + }); + } + + readByte(address) { + return this.#io.readUint8(address); + } + + writeByte(address, value) { + return this.#io.writeUint8(address, value); + } + + /** + * Initialize ES7210 for M5Stack CoreS3 + * Configuration based on M5Unified _microphone_enabled_cb_cores3 + */ + initialize() { + // Reset + try { + this.writeByte(0x00, 0xFF); // RESET_CTL + } catch (e) { + throw new Error("ES7210 not responding on I2C"); + } + + // ES7210 register initialization sequence from M5Unified + const initSequence = [ + { reg: 0x00, value: 0x41 }, // RESET_CTL + { reg: 0x01, value: 0x1f }, // CLK_ON_OFF + { reg: 0x06, value: 0x00 }, // DIGITAL_PDN + { reg: 0x07, value: 0x20 }, // ADC_OSR + { reg: 0x08, value: 0x10 }, // MODE_CFG + { reg: 0x09, value: 0x30 }, // TCT0_CHPINI + { reg: 0x0A, value: 0x30 }, // TCT1_CHPINI + { reg: 0x20, value: 0x0a }, // ADC34_HPF2 + { reg: 0x21, value: 0x2a }, // ADC34_HPF1 + { reg: 0x22, value: 0x0a }, // ADC12_HPF2 + { reg: 0x23, value: 0x2a }, // ADC12_HPF1 + { reg: 0x02, value: 0xC1 }, + { reg: 0x04, value: 0x01 }, + { reg: 0x05, value: 0x00 }, + { reg: 0x11, value: 0x60 }, + { reg: 0x40, value: 0x42 }, // ANALOG_SYS + { reg: 0x41, value: 0x70 }, // MICBIAS12 + { reg: 0x42, value: 0x70 }, // MICBIAS34 + { reg: 0x43, value: 0x1B }, // MIC1_GAIN + { reg: 0x44, value: 0x1B }, // MIC2_GAIN + { reg: 0x45, value: 0x00 }, // MIC3_GAIN + { reg: 0x46, value: 0x00 }, // MIC4_GAIN + { reg: 0x47, value: 0x00 }, // MIC1_LP + { reg: 0x48, value: 0x00 }, // MIC2_LP + { reg: 0x49, value: 0x00 }, // MIC3_LP + { reg: 0x4A, value: 0x00 }, // MIC4_LP + { reg: 0x4B, value: 0x00 }, // MIC12_PDN + { reg: 0x4C, value: 0xFF }, // MIC34_PDN + { reg: 0x01, value: 0x14 }, // CLK_ON_OFF + ]; + + for (const {reg, value} of initSequence) { + this.writeByte(reg, value); + } + } + + /** + * Power down ES7210 + */ + powerDown() { + this.writeByte(0x00, 0xFF); // RESET_CTL + } +} + +export default ES7210; diff --git a/modules/drivers/peripherals/es7210/manifest.json b/modules/drivers/peripherals/es7210/manifest.json new file mode 100644 index 000000000..e8302d20d --- /dev/null +++ b/modules/drivers/peripherals/es7210/manifest.json @@ -0,0 +1,8 @@ +{ + "modules": { + "embedded:peripheral/Audio/es7210": "./es7210" + }, + "preload": [ + "embedded:peripheral/Audio/es7210" + ] +} diff --git a/modules/io/audioin/esp32/audioin.c b/modules/io/audioin/esp32/audioin.c index 33cd67d44..9bc82517d 100644 --- a/modules/io/audioin/esp32/audioin.c +++ b/modules/io/audioin/esp32/audioin.c @@ -518,7 +518,7 @@ void audioInLoop(void *pvParameter) #else i2s_std_config_t rx_std_cfg = { .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(input->sampleRate), - .slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_MONO), + .slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, (input->numChannels == 2) ? I2S_SLOT_MODE_STEREO : I2S_SLOT_MODE_MONO), .gpio_cfg = { .mclk = I2S_GPIO_UNUSED, .bclk = MODDEF_AUDIOIN_I2S_BCK_PIN, @@ -532,7 +532,7 @@ void audioInLoop(void *pvParameter) } } }; - rx_std_cfg.slot_cfg.slot_mask = I2S_STD_SLOT_RIGHT; //@@ + rx_std_cfg.slot_cfg.slot_mask = MODDEF_AUDIOIN_I2S_SLOT; err = i2s_channel_init_std_mode(input->handle, &rx_std_cfg); if (err) {