有幾種方法可以將模擬音頻數據輸入到ESP32中。
- 直接從內置的模數轉換器(ADC)讀取
- 這對於一次性讀取很有用,但不適用於高采樣率。
- 使用I2S通過DMA讀取內置ADC
- 適用於模擬麥克風,例如MAX4466和MAX9814
- 使用I2S直接從I2S兼容外設讀取
- 對於SPH0645LM4H,INPM441,ICS43432和ICS43434等麥克風有用
直接從ADC讀取
ESP32上有兩個內置ADC,ADC1和ADC2。
ADC1具有8個通道:
| 渠道 | 通用輸入輸出 | 渠道 | 通用輸入輸出 |
|---|---|---|---|
| ADC1_CHANNEL_0 | GPIO36 | ADC1_CHANNEL_4 | GPIO32 |
| ADC1_CHANNEL_1 | GPIO37 | ADC1_CHANNEL_5 | GPIO33 |
| ADC1_CHANNEL_2 | GPIO38 | ADC1_CHANNEL_6 | GPIO34 |
| ADC1_CHANNEL_3 | GPIO39 | ADC1_CHANNEL_7 | GPIO35 |
ADC2有10個通道:
| 渠道 | 通用輸入輸出 | 渠道 | 通用輸入輸出 |
|---|---|---|---|
| ADC2_CHANNEL_0 | GPIO4 | ADC2_CHANNEL_5 | GPIO12 |
| ADC2_CHANNEL_1 | GPIO0 | ADC2_CHANNEL_6 | GPIO14 |
| ADC2_CHANNEL_2 | GPIO2 | ADC2_CHANNEL_7 | GPIO27 |
| ADC2_CHANNEL_3 | GPIO15 | ADC2_CHANNEL_8 | GPIO25 |
| ADC2_CHANNEL_4 | GPIO13 | ADC2_CHANNEL_9 | GPIO26 |
盡管有一些限制-WiFi子系統也使用ADC2,並且某些引腳還用於控制啟動行為的捆綁引腳。這意味着在項目中堅持使用ADC1是最安全的。
從ADC讀取非常簡單-您可以使用Arduino函數或直接使用Espressif函數:
// read using Arduino int sample = analogRead(35) // read using Espressif int sample = adc1_get_raw(ADC1_CHANNEL_7);
ESP32 ADC非常不准確,如果您想獲得准確的讀數,可以使用校准設置。現在,這些操作大多在工廠完成,因此您的ESP32應該已經具有一些校准設置。也可以手動校准ADC。
要讀取校准值,請使用以下代碼,它將為您提供以毫伏為單位的值。這兩個調用adc1_config_width和adc1_config_channel_atten是至關重要的,因為校准特性需要匹配ADC配置。
// calibration values for the adc #define DEFAULT_VREF 1100 esp_adc_cal_characteristics_t *adc_chars; //Range 0-4096 adc1_config_width(ADC_WIDTH_BIT_12); // full voltage range adc1_config_channel_atten(ADC1_CHANNEL_7, ADC_ATTEN_DB_11); // get the ADC characteristics esp_adc_cal_characterize( ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_chars); // read a sample from the ADC int sample = adc1_get_raw(ADC1_CHANNEL_7); // get the calibrated value int milliVolts = esp_adc_cal_raw_to_voltage(sample, adc_chars);
使用I2S和DMA的高速ADC采樣
直接使用ADC可以進行低頻和一次性采樣。為了采樣高質量的音頻數據,您將需要以16-40KHz的頻率采樣。您可以使用計時器來執行此操作,但這並不是ESP32的CPU資源的最佳用途。
更好的方法是使用內置的I2S外設將ADC的樣本直接讀取到內存中。
這是使用I2S讀取內置ADC的基本設置。
i2s_config_t i2s_config = { .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN), .sample_rate = 40000, .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, .communication_format = I2S_COMM_FORMAT_I2S_LSB, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 2, .dma_buf_len = 1024, .use_apll = false, .tx_desc_auto_clear = false, .fixed_mclk = 0}; //install and start i2s driver i2s_driver_install(I2S_NUM_0, &i2s_config, 4, &i2s_queue); //init ADC pad i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_7); // enable the ADC i2s_adc_enable(I2S_NUM_0); // start a task to read samples from I2S TaskHandle_t readerTaskHandle; xTaskCreatePinnedToCore(readerTask, "Reader Task", 8192, this, 1, &readerTaskHandle, 0);
然后,您可以使用以下任務從ADC讀取樣本:
void readerTask(void *param) { I2SSampler *sampler = (I2SSampler *)param; while (true) { // wait for some data to arrive on the queue i2s_event_t evt; if (xQueueReceive(sampler->i2s_queue, &evt, portMAX_DELAY) == pdPASS) { if (evt.type == I2S_EVENT_RX_DONE) { size_t bytesRead = 0; do { // try and fill up our audio buffer size_t bytesToRead = (ADC_SAMPLES_COUNT - sampler->audioBufferPos) * 2; void *bufferPosition = (void *)(sampler->currentAudioBuffer + sampler->audioBufferPos); // read from i2s i2s_read(I2S_NUM_0, bufferPosition, bytesToRead, &bytesRead, 10 / portTICK_PERIOD_MS); sampler->audioBufferPos += bytesRead / 2; if (sampler->audioBufferPos == ADC_SAMPLES_COUNT) { // do something with the sample - e.g. notify another task to do some processing } } while (bytesRead > 0); } } } }
閱讀完樣本后,您可以執行所需的任何處理,I2S外設將在后台繼續將樣本從ADC讀取到DMA緩沖區中。
MA4466的接線非常簡單,只需將VCC連接至3v3,將GND連接至GND,將Out連接至與您要從其采樣的ADC通道相對應的GPIO引腳。

嘗試MAX9814的方法相同-您也可以通過將增益引腳連接至VCC或GND來發揮MAX9814的增益。

原文地址:https://blog.cmgresearch.com/2020/09/12/esp32-audio-input.html
