From 8cbf292373b51546c2845ce2d2c7dde9009f09b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Tue, 29 Nov 2022 17:19:10 +0100 Subject: [PATCH] WIP: add digital audio. Needs a proto change, so checking in generated files for now. # Conflicts: # src/mesh/generated/localonly.pb.h # src/mesh/generated/module_config.pb.h --- src/mesh/generated/localonly.pb.h | 2 +- src/mesh/generated/module_config.pb.h | 75 +++++++----------- src/modules/esp32/AudioModule.cpp | 110 ++++++++++++++++++-------- src/modules/esp32/AudioModule.h | 1 + 4 files changed, 109 insertions(+), 79 deletions(-) diff --git a/src/mesh/generated/localonly.pb.h b/src/mesh/generated/localonly.pb.h index c154a98db..44d923839 100644 --- a/src/mesh/generated/localonly.pb.h +++ b/src/mesh/generated/localonly.pb.h @@ -151,7 +151,7 @@ extern const pb_msgdesc_t LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define LocalConfig_size 387 -#define LocalModuleConfig_size 376 +#define LocalModuleConfig_size 385 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/module_config.pb.h b/src/mesh/generated/module_config.pb.h index 47f410a5c..3747452c7 100644 --- a/src/mesh/generated/module_config.pb.h +++ b/src/mesh/generated/module_config.pb.h @@ -63,12 +63,14 @@ typedef enum _ModuleConfig_CannedMessageConfig_InputEventChar { /* Struct definitions */ typedef struct _ModuleConfig_AudioConfig { bool codec2_enabled; - uint8_t ptt_pin; + uint32_t mic_chan; + uint32_t amp_pin; + uint32_t ptt_pin; ModuleConfig_AudioConfig_Audio_Baud bitrate; - uint8_t i2s_ws; - uint8_t i2s_sd; - uint8_t i2s_din; - uint8_t i2s_sck; + uint32_t i2s_ws; + uint32_t i2s_sd; + uint32_t i2s_din; + uint32_t i2s_sck; } ModuleConfig_AudioConfig; typedef struct _ModuleConfig_CannedMessageConfig { @@ -93,13 +95,6 @@ typedef struct _ModuleConfig_ExternalNotificationConfig { bool alert_message; bool alert_bell; bool use_pwm; - uint8_t output_vibra; - uint8_t output_buzzer; - bool alert_message_vibra; - bool alert_message_buzzer; - bool alert_bell_vibra; - bool alert_bell_buzzer; - uint16_t nag_timeout; } ModuleConfig_ExternalNotificationConfig; typedef struct _ModuleConfig_MQTTConfig { @@ -192,18 +187,18 @@ extern "C" { /* Initializer values for message structs */ #define ModuleConfig_init_default {0, {ModuleConfig_MQTTConfig_init_default}} #define ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0} -#define ModuleConfig_AudioConfig_init_default {0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0} +#define ModuleConfig_AudioConfig_init_default {0, 0, 0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0} #define ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN} -#define ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0} #define ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0} #define ModuleConfig_RangeTestConfig_init_default {0, 0, 0} #define ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0} #define ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} #define ModuleConfig_init_zero {0, {ModuleConfig_MQTTConfig_init_zero}} #define ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0} -#define ModuleConfig_AudioConfig_init_zero {0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0} +#define ModuleConfig_AudioConfig_init_zero {0, 0, 0, 0, _ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0} #define ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN} -#define ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0} #define ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0} #define ModuleConfig_RangeTestConfig_init_zero {0, 0, 0} #define ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0} @@ -211,12 +206,14 @@ extern "C" { /* Field tags (for use in manual encoding/decoding) */ #define ModuleConfig_AudioConfig_codec2_enabled_tag 1 -#define ModuleConfig_AudioConfig_ptt_pin_tag 2 -#define ModuleConfig_AudioConfig_bitrate_tag 3 -#define ModuleConfig_AudioConfig_i2s_ws_tag 4 -#define ModuleConfig_AudioConfig_i2s_sd_tag 5 -#define ModuleConfig_AudioConfig_i2s_din_tag 6 -#define ModuleConfig_AudioConfig_i2s_sck_tag 7 +#define ModuleConfig_AudioConfig_mic_chan_tag 2 +#define ModuleConfig_AudioConfig_amp_pin_tag 3 +#define ModuleConfig_AudioConfig_ptt_pin_tag 4 +#define ModuleConfig_AudioConfig_bitrate_tag 5 +#define ModuleConfig_AudioConfig_i2s_ws_tag 6 +#define ModuleConfig_AudioConfig_i2s_sd_tag 7 +#define ModuleConfig_AudioConfig_i2s_din_tag 8 +#define ModuleConfig_AudioConfig_i2s_sck_tag 9 #define ModuleConfig_CannedMessageConfig_rotary1_enabled_tag 1 #define ModuleConfig_CannedMessageConfig_inputbroker_pin_a_tag 2 #define ModuleConfig_CannedMessageConfig_inputbroker_pin_b_tag 3 @@ -235,13 +232,6 @@ extern "C" { #define ModuleConfig_ExternalNotificationConfig_alert_message_tag 5 #define ModuleConfig_ExternalNotificationConfig_alert_bell_tag 6 #define ModuleConfig_ExternalNotificationConfig_use_pwm_tag 7 -#define ModuleConfig_ExternalNotificationConfig_output_vibra_tag 8 -#define ModuleConfig_ExternalNotificationConfig_output_buzzer_tag 9 -#define ModuleConfig_ExternalNotificationConfig_alert_message_vibra_tag 10 -#define ModuleConfig_ExternalNotificationConfig_alert_message_buzzer_tag 11 -#define ModuleConfig_ExternalNotificationConfig_alert_bell_vibra_tag 12 -#define ModuleConfig_ExternalNotificationConfig_alert_bell_buzzer_tag 13 -#define ModuleConfig_ExternalNotificationConfig_nag_timeout_tag 14 #define ModuleConfig_MQTTConfig_enabled_tag 1 #define ModuleConfig_MQTTConfig_address_tag 2 #define ModuleConfig_MQTTConfig_username_tag 3 @@ -310,12 +300,14 @@ X(a, STATIC, SINGULAR, BOOL, json_enabled, 6) #define ModuleConfig_AudioConfig_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, BOOL, codec2_enabled, 1) \ -X(a, STATIC, SINGULAR, UINT32, ptt_pin, 2) \ -X(a, STATIC, SINGULAR, UENUM, bitrate, 3) \ -X(a, STATIC, SINGULAR, UINT32, i2s_ws, 4) \ -X(a, STATIC, SINGULAR, UINT32, i2s_sd, 5) \ -X(a, STATIC, SINGULAR, UINT32, i2s_din, 6) \ -X(a, STATIC, SINGULAR, UINT32, i2s_sck, 7) +X(a, STATIC, SINGULAR, UINT32, mic_chan, 2) \ +X(a, STATIC, SINGULAR, UINT32, amp_pin, 3) \ +X(a, STATIC, SINGULAR, UINT32, ptt_pin, 4) \ +X(a, STATIC, SINGULAR, UENUM, bitrate, 5) \ +X(a, STATIC, SINGULAR, UINT32, i2s_ws, 6) \ +X(a, STATIC, SINGULAR, UINT32, i2s_sd, 7) \ +X(a, STATIC, SINGULAR, UINT32, i2s_din, 8) \ +X(a, STATIC, SINGULAR, UINT32, i2s_sck, 9) #define ModuleConfig_AudioConfig_CALLBACK NULL #define ModuleConfig_AudioConfig_DEFAULT NULL @@ -337,14 +329,7 @@ X(a, STATIC, SINGULAR, UINT32, output, 3) \ X(a, STATIC, SINGULAR, BOOL, active, 4) \ X(a, STATIC, SINGULAR, BOOL, alert_message, 5) \ X(a, STATIC, SINGULAR, BOOL, alert_bell, 6) \ -X(a, STATIC, SINGULAR, BOOL, use_pwm, 7) \ -X(a, STATIC, SINGULAR, UINT32, output_vibra, 8) \ -X(a, STATIC, SINGULAR, UINT32, output_buzzer, 9) \ -X(a, STATIC, SINGULAR, BOOL, alert_message_vibra, 10) \ -X(a, STATIC, SINGULAR, BOOL, alert_message_buzzer, 11) \ -X(a, STATIC, SINGULAR, BOOL, alert_bell_vibra, 12) \ -X(a, STATIC, SINGULAR, BOOL, alert_bell_buzzer, 13) \ -X(a, STATIC, SINGULAR, UINT32, nag_timeout, 14) +X(a, STATIC, SINGULAR, BOOL, use_pwm, 7) #define ModuleConfig_ExternalNotificationConfig_CALLBACK NULL #define ModuleConfig_ExternalNotificationConfig_DEFAULT NULL @@ -410,9 +395,9 @@ extern const pb_msgdesc_t ModuleConfig_CannedMessageConfig_msg; #define ModuleConfig_CannedMessageConfig_fields &ModuleConfig_CannedMessageConfig_msg /* Maximum encoded size of messages (where known) */ -#define ModuleConfig_AudioConfig_size 19 +#define ModuleConfig_AudioConfig_size 46 #define ModuleConfig_CannedMessageConfig_size 49 -#define ModuleConfig_ExternalNotificationConfig_size 40 +#define ModuleConfig_ExternalNotificationConfig_size 22 #define ModuleConfig_MQTTConfig_size 169 #define ModuleConfig_RangeTestConfig_size 10 #define ModuleConfig_SerialConfig_size 26 diff --git a/src/modules/esp32/AudioModule.cpp b/src/modules/esp32/AudioModule.cpp index 959366dec..0c02251b0 100644 --- a/src/modules/esp32/AudioModule.cpp +++ b/src/modules/esp32/AudioModule.cpp @@ -42,6 +42,14 @@ #define AAMP 14 #define PTT_PIN 39 +// #define I2S_WS 13 +// #define I2S_SD 15 +// #define I2S_SIN 2 +// #define I2S_SCK 14 + +// Use I2S Processor 0 +#define I2S_PORT I2S_NUM_0 + #define AUDIO_MODULE_RX_BUFFER 128 #define AUDIO_MODULE_DATA_MAX Constants_DATA_PAYLOAD_LEN #define AUDIO_MODULE_MODE ModuleConfig_AudioConfig_Audio_Baud_CODEC2_700 @@ -88,7 +96,7 @@ int IRAM_ATTR local_adc1_read(int channel) { IRAM_ATTR void am_onTimer() { portENTER_CRITICAL_ISR(&timerMux); //Enter crital code without interruptions - if (radio_state == RadioState::tx) { + if ((radio_state == RadioState::tx) && (!moduleConfig.audio.i2s_sd)) { adc_buffer[adc_buffer_index++] = (16 * local_adc1_read(mic_chan)) - 32768; //If you want to test with a 1KHz tone, comment the line above and descomment the three lines below @@ -108,15 +116,15 @@ IRAM_ATTR void am_onTimer() if (xHigherPriorityTaskWoken) portYIELD_FROM_ISR(); } - } else if (radio_state == RadioState::rx) { - + } else if ((radio_state == RadioState::rx) && (!moduleConfig.audio.i2s_din) { + // ESP32-S3 does not have DAC support +#if !defined(CONFIG_IDF_TARGET_ESP32S3) int16_t v; //Get a value from audio_fifo and convert it to 0 - 255 to play it in the ADC if (audio_fifo.get(&v)) rx_raw_audio_value = (uint8_t)((v + 32768) / 256); - // comment out for now, S3 does not have Hardware-DAC. Consider I2S instead. -#if !CONFIG_IDF_TARGET_ESP32S3 + dacWrite(moduleConfig.audio.amp_pin ? moduleConfig.audio.amp_pin : AAMP, rx_raw_audio_value); #endif } @@ -180,41 +188,77 @@ int32_t AudioModule::runOnce() { if ((moduleConfig.audio.codec2_enabled) && (myRegion->audioPermitted)) { if (firstTime) { - DEBUG_MSG("--- Initializing ADC on Channel %u\n", moduleConfig.audio.mic_chan ? moduleConfig.audio.mic_chan : AMIC); + // if we have I2S_SD defined, take samples from digital mic. I2S_DIN means digital output to amp. + if (moduleConfig.audio.i2s_sd || moduleConfig.audio.i2s_din) { + // Set up I2S Processor configuration. This will produce 16bit samples instead of 12 from the ADC + DEBUG_MSG("--- Initializing I2S for input\n"); + i2s_config_t i2s_config = { + .mode = (i2s_mode_t)(I2S_MODE_MASTER | (moduleConfig.audio.i2s_sd ? I2S_MODE_RX : 0) | (moduleConfig.audio.i2s_din ? I2S_MODE_TX : 0)), + .sample_rate = 8000, + .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), + .intr_alloc_flags = 0, + .dma_buf_count = 8, + .dma_buf_len = ADC_BUFFER_SIZE, + .use_apll = false, + .tx_desc_auto_clear = true, + .fixed_mclk = 0 + }; + i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); - mic_chan = moduleConfig.audio.mic_chan ? (adc1_channel_t)(int)moduleConfig.audio.mic_chan : (adc1_channel_t)AMIC; - adc1_config_width(ADC_WIDTH_12Bit); - adc1_config_channel_atten(mic_chan, ADC_ATTEN_DB_6); - adc1_get_raw(mic_chan); + const i2s_pin_config_t pin_config = { + .bck_io_num = moduleConfig.audio.i2s_sck, + .ws_io_num = moduleConfig.audio.i2s_ws, + .data_out_num = moduleConfig.audio.i2s_din ? moduleConfig.audio.i2s_din : I2S_PIN_NO_CHANGE, + .data_in_num = moduleConfig.audio.i2s_sd ? moduleConfig.audio.i2s_sd : I2S_PIN_NO_CHANGE + }; + i2s_set_pin(I2S_PORT, &pin_config); + + i2s_start(I2S_PORT); + } + + if (!moduleConfig.audio.i2s_sd) { + DEBUG_MSG("--- Initializing ADC on Channel %u\n", moduleConfig.audio.mic_chan ? moduleConfig.audio.mic_chan : AMIC); + mic_chan = moduleConfig.audio.mic_chan ? (adc1_channel_t)(int)moduleConfig.audio.mic_chan : (adc1_channel_t)AMIC; + adc1_config_width(ADC_WIDTH_12Bit); + adc1_config_channel_atten(mic_chan, ADC_ATTEN_DB_6); + adc1_get_raw(mic_chan); + } radio_state = RadioState::rx; - // Start a timer at 8kHz to sample the ADC and play the audio on the DAC. - uint32_t cpufreq = getCpuFrequencyMhz(); - switch (cpufreq){ - case 160: - adcTimer = timerBegin(3, 1000, true); // 160 MHz / 1000 = 160KHz - break; - case 240: - adcTimer = timerBegin(3, 1500, true); // 240 MHz / 1500 = 160KHz - break; - case 320: - adcTimer = timerBegin(3, 2000, true); // 320 MHz / 2000 = 160KHz - break; - case 80: - default: - adcTimer = timerBegin(3, 500, true); // 80 MHz / 500 = 160KHz - break; + if ((!moduleConfig.audio.i2s_sd) || (!moduleConfig.audio.i2s_din)) { + // Start a timer at 8kHz to sample the ADC and play the audio on the DAC, but only if we have analogue audio to process + uint32_t cpufreq = getCpuFrequencyMhz(); + switch (cpufreq){ + case 160: + adcTimer = timerBegin(3, 1000, true); // 160 MHz / 1000 = 160KHz + break; + case 240: + adcTimer = timerBegin(3, 1500, true); // 240 MHz / 1500 = 160KHz + break; + case 320: + adcTimer = timerBegin(3, 2000, true); // 320 MHz / 2000 = 160KHz + break; + case 80: + default: + adcTimer = timerBegin(3, 500, true); // 80 MHz / 500 = 160KHz + break; + } + DEBUG_MSG("--- Timer CPU Frequency: %u MHz\n", cpufreq); + timerAttachInterrupt(adcTimer, &am_onTimer, false); + timerAlarmWrite(adcTimer, 20, true); // Interrupts when counter == 20, 8.000 times a second + timerAlarmEnable(adcTimer); } - DEBUG_MSG("--- Timer CPU Frequency: %u MHz\n", cpufreq); - timerAttachInterrupt(adcTimer, &am_onTimer, false); - timerAlarmWrite(adcTimer, 20, true); // Interrupts when counter == 20, 8.000 times a second - timerAlarmEnable(adcTimer); - - DEBUG_MSG("--- Initializing DAC on Pin %u\n", moduleConfig.audio.amp_pin ? moduleConfig.audio.amp_pin : AAMP); - DEBUG_MSG("--- Initializing PTT on Pin %u\n", moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN); + // setup analogue DAC only if we don't use I2S for output. This is not available on ESP32-S3 +#if !defined(CONFIG_IDF_TARGET_ESP32S3) + if (moduleConfig.audio.i2s_din) + DEBUG_MSG("--- Initializing DAC on Pin %u\n", moduleConfig.audio.amp_pin ? moduleConfig.audio.amp_pin : AAMP); +#endif // Configure PTT input + DEBUG_MSG("--- Initializing PTT on Pin %u\n", moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN); pinMode(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN, INPUT); firstTime = false; diff --git a/src/modules/esp32/AudioModule.h b/src/modules/esp32/AudioModule.h index 16705a141..b30e82bc2 100644 --- a/src/modules/esp32/AudioModule.h +++ b/src/modules/esp32/AudioModule.h @@ -6,6 +6,7 @@ #if defined(ARCH_ESP32) #include "NodeDB.h" #include +#include #include #include #include