Искажение при воспроизведении звука ESP32 I2S с внешним DA C для частоты дискретизации выше 20 кбит / с - PullRequest
0 голосов
/ 01 апреля 2020

Аппаратное обеспечение: ESP32 DevKitV1, коммутационная плата PCM5102, адаптер SD-карты.
Программное обеспечение: Arduino framework.

В течение некоторого времени я борюсь с воспроизведением звука с использованием I2S DA C, внешнего по отношению к ESP32. , Проблема в том, что я могу играть без искажений только на низких частотах дискретизации, то есть ниже 20 кбит / с. Я изучал документацию https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/i2s.html и многие другие источники, но силле это не удалось исправить.

Функция конфигурации I2S:

esp_err_t I2Smixer::i2sConfig(int bclkPin, int lrckPin, int dinPin, int sample_rate)
{
    // i2s configuration: Tx to ext DAC, 2's complement 16-bit PCM, mono,
    const i2s_config_t i2s_config = {
        .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_CHANNEL_MONO), // only tx, external DAC
        .sample_rate = sample_rate,
        .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
        .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, // single channel
                                                      // .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
        .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL3, // highest interrupt priority that can be handeled in c
        .dma_buf_count = 128, //16,
        .dma_buf_len = 128, // 64
        .use_apll = false,
        .tx_desc_auto_clear = true};

    const i2s_pin_config_t pin_config = {
        .bck_io_num = bclkPin,           //this is BCK pin
        .ws_io_num = lrckPin,            // this is LRCK pin
        .data_out_num = dinPin,          // this is DATA output pin
        .data_in_num = I2S_PIN_NO_CHANGE // Not used
    };
    esp_err_t ret1 = i2s_driver_install((i2s_port_t)i2s_num, &i2s_config, 0, NULL);
    esp_err_t ret2 = i2s_set_pin((i2s_port_t)i2s_num, &pin_config);
    esp_err_t ret3 = i2s_set_sample_rates((i2s_port_t)i2s_num, sample_rate);
    // i2s_adc_disable((i2s_port_t)i2s_num);
    // esp_err_t ret3 =  rtc_clk_apll_enable(1, 15, 8, 5, 6);

    return ret1 + ret2 + ret3;
}

Волновой файл, созданный в 16-битном моно PCM, в формате 44,1 кГц, открывается:

File sample_file = SD.open("/test.wav")

В основном l oop сэмплы передаются в драйвер I2S.

esp_err_t I2Smixer::loop()
{
    esp_err_t ret1 = ESP_OK, ret2 = ESP_OK;
    int32_t output = 0;

        if (sample_file.available())
        {
            if (sample_file.size() - sample_file.position() > 2) // bytes left
            {
                int16_t tmp; // 16 bits signed PCM assumed
                sample_file.read((uint8_t *)&tmp, 2);
                output =(int32_t)tmp;
            }
            else
            {
                sample_file.close(); 
            }
        }

    size_t i2s_bytes_write;
    int16_t int16_t_output = (int16_t)output;
    ret1 = i2s_write((i2s_port_t)i2s_num, &int16_t_output, 2, &i2s_bytes_write, portMAX_DELAY);
    if (i2s_bytes_write != 2)
        ret2 = ESP_FAIL;

    return ret1 + ret2;
}

Это прекрасно работает для частот выборки до 20 кПа / с. Для частоты дискретизации 32k или 44.1k возникают сильные искажения. Я подозреваю, что это вызвано буфером I2S DMA Tx. Если количество буферов DMA (dma_buf_count) и длина буфера (dma_buf_len) увеличены, то звук сначала воспроизводится нормально. Впоследствии, спустя короткое время, искажение снова появляется. Я не могу измерить этот короткий промежуток времени, может быть, около секунды, но я заметил, что это зависит от dma_buf_count и dma_buf_len.

Кроме того, я попытался увеличить частоту процессора до 240 МГц, без улучшений. Далее я попытался воспроизвести файл из SPIFSS, без улучшений.

У меня сейчас нет идей, кто-нибудь тоже сталкивался с этой проблемой?

1 Ответ

0 голосов
/ 14 апреля 2020

Чтение одного образца за раз и передача его в драйвер I 2 S не будет наиболее эффективным использованием драйвера. Вы используете только 2 байта в каждом 128-байтовом буфере DMA. Это оставляет только один период выборки до pu sh следующей выборки до того, как буфер DMA будет «истощен».

Считайте файл в 128-байтовых (64 выборочных) фрагментах и ​​запишите весь фрагмент в I 2 S для эффективного использования прямого доступа к памяти.

В зависимости от реализации файловой системы может быть немного эффективнее использовать более крупные фрагменты, которые симпатизируют c носителю файловой системы, размеру сектора и буферизации DMA.

...