Почему у меня нет звука с моего ESP32, используя фреймворк esp-idf?

Вопрос или проблема

Я надеюсь заставить мой raspiaudio muse proto воспроизводить синусоиду для тестирования, но я слышу только очень слабое пульсационное звучание, которое даже не соответствует ожидаемому выходу.

Вот весь код:

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "driver/i2s.h"
#include <math.h>
#include <vector>
#include <sstream>

#define I2S_BCLK    5
#define I2S_LRC    25
#define I2S_DOUT   26
#define I2S_DIN    35

/** Это необходимо, чтобы компоновщик нашел точку входа в прошивку */
extern "C" {
    void app_main(void);
}

#define SAMPLE_RATE     (44100)
const i2s_port_t I2S_NUM = I2S_NUM_0;
#define PI              (3.14159265)
#define FREQUENCY       (440)
#define SAMPLES         (SAMPLE_RATE / FREQUENCY)

typedef std::vector<int16_t> VectorBuffer;

VectorBuffer generate_sine_wave(
    float sample_rate_Hz,
    float duration_s = 1.0f,
    float frequency = 440.0f,
    float amplitude = 1.0f
) {
    const auto samples_count = (int)(sample_rate_Hz * duration_s * 2);
    VectorBuffer buffer(samples_count);

    for (int i = 0; i < samples_count - 1; i++) {
        const auto sample = (int16_t)(amplitude * sin((2 * PI * i * frequency) / sample_rate_Hz));
        buffer.at(i) = sample;
        buffer.at(i + 1) = sample;
    }

    return buffer;
}

// Должен воспроизводить ноту F полсекунды каждую секунду
void i2s_task(void *pvParameter) {
    while (1) {
        auto buffer = generate_sine_wave(
            SAMPLE_RATE,
            1.0f,
            440.0f,
            floor(INT16_MAX / 3)
        );

        ESP_LOGI("I2S_TASK", "Воспроизведение синусоиды из %d выборок", buffer.size());

        size_t bytes_written;

        for (;;) {
            if (buffer.empty()) {
                ESP_LOGD("I2S_TASK", "Буфер пуст, хорошо.");
                break;
            }

            esp_err_t e = i2s_write(I2S_NUM, buffer.data(), std::fmin(buffer.size(), 1024), &bytes_written, portMAX_DELAY);
            if (e != ESP_OK) {
                ESP_LOGE("I2S_TASK", "Ошибка записи в I2S: %d", e);
                break;
            }

            if (bytes_written == 0) {
                // этого не должно происходить
                ESP_LOGE("I2S_TASK", "Не записано байтов");
                break;
            }

            ESP_LOGI("I2S_TASK", "Записано %d байтов", bytes_written);

            /* Удалить слишком подробное логирование
            std::ostringstream oss;
            for (int i = 0; i < bytes_written; i++) {
                oss << buffer.at(i) << " ";
            }
            ESP_LOGD("I2S_TASK", "Буфер: %s", oss.str().c_str());
            // */
            buffer.erase(buffer.begin(), buffer.begin() + bytes_written);
        };

        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void hello_task(void *pvParameter) {
    while (1) {
        ESP_LOGI("HELLO_TASK", "привет");
        vTaskDelay(500 / portTICK_PERIOD_MS);
    }
}

void app_main() {
    // Конфигурация UART
    const uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE
    };

    uart_param_config(UART_NUM_0, &uart_config);
    uart_driver_install(UART_NUM_0, 1024 * 2, 0, 0, NULL, 0);

    const auto mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX);

    // Конфигурация I2S
    i2s_config_t i2s_config = {
        mode,
        .sample_rate = SAMPLE_RATE,
        .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
        .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
        .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S | I2S_COMM_FORMAT_STAND_MSB),
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
        .dma_buf_count = 3,
        .dma_buf_len = 1024,
        .use_apll = false,
        .tx_desc_auto_clear = true,
        .fixed_mclk = -1,
        .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT,
        .bits_per_chan = I2S_BITS_PER_CHAN_16BIT,
    };

    // Конфигурация вывода I2S
    i2s_pin_config_t pin_config = {
        .bck_io_num = I2S_BCLK,
        .ws_io_num = I2S_LRC,
        .data_out_num = I2S_DOUT,
        .data_in_num = I2S_DIN, // по умолчанию Copilot был: I2S_PIN_NO_CHANGE // может быть 35 https://github.com/RASPIAUDIO/Simple_Bluetooth_Speaker_ESP32/blob/884c7f3700ec92dcf000dca75934860833559df7/speaker/speaker.ino#L171
    };

    // Установка и запуск драйвера I2S
    const auto e_i = i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
    if (e_i != ESP_OK) {
        ESP_LOGE("APP_MAIN", "Ошибка установки драйвера I2S: %d", e_i);
        return;
    }

    const auto e_p = i2s_set_pin(I2S_NUM, &pin_config);
    if (e_p != ESP_OK) {
        ESP_LOGE("APP_MAIN", "Ошибка настройки вывода I2S: %d", e_p);
        return;
    }

    const auto e_s = i2s_start(I2S_NUM);
    if (e_s != ESP_OK) {
        ESP_LOGE("APP_MAIN", "Ошибка запуска I2S: %d", e_s);
        return;
    }

    // Создание задачи hello_task
    xTaskCreate(&hello_task, "hello_task", 2048, NULL, 5, NULL);

    // Создание задачи i2s_task
    xTaskCreate(&i2s_task, "i2s_task", 2048, NULL, 5, NULL);
}

Есть идеи?

Ответ или решение

Проблема отсутствия звука на ESP32 при использовании фреймворка ESP-IDF может быть вызвана несколькими факторами. Рассмотрим основные причины и возможные решения, чтобы помочь вам эффективно справиться с ситуацией.

Основные причины низкого уровня звука

  1. Неправильные параметры генерации звука:

    • В вашем коде для генерации синусоиды используется floor(INT16_MAX / 3) в качестве амплитуды. Хотя это значение может быть допустимо, возможно, вам стоит попробовать установить амплитуду ближе к INT16_MAX для обеспечения более громкого звука. Например:
      floor(INT16_MAX);
  2. Программная ошибка в generate_sine_wave:

    • Ваша реализация функции generate_sine_wave создает два одинаковых значения подряд. Это может привести к несоответствию с ожиданиями. Попробуйте изменить:
      buffer.at(i) = sample;
      buffer.at(i + 1) = sample;

      На:

      buffer.at(i) = sample;
  3. Настройки I2S:

    • Проверьте настройки конфигурации I2S в вашем коде. Убедитесь, что вы используете соответствующий формат передачи данных (например, I2S_COMM_FORMAT_STAND_I2S или I2S_COMM_FORMAT_STAND_MSB). Также убедитесь, что используемые вами пины (BCLK, LRC, DOUT) соответствуют выводам вашего устройства.
  4. Кодировка и управление потоком:

    • Вам необходимо убедиться, что обработка потоков данных осуществляется корректно. Советуем добавить дополнительное логирование, чтобы убеждаться в том, что данные отправляются на выход.

Пример добавления логирования

Попробуйте расширить логирование внутри цикла отправки данных в i2s_task, чтобы лучше понять, какие данные на самом деле отправляются, и как обрабатываются ошибки.

Тестирование звука

Убедитесь также в следующем:

  • Подключение: Проверьте правильность подключения DAC или усилителя колонки к ESP32. Проверьте все соединения и убедитесь, что они надежные.

  • Частота выборки: Убедитесь, что ваш код генерирует звук на частоте выборки, поддерживаемой вашим оборудованием. В большинстве случаев 44.1 кГц (44100 Гц) будет приемлемым значением.

  • Проигрывание другого звука: Попробуйте проиграть другой звуковой файл или генерировать другой тон, чтобы исключить возможность аппаратной неисправности.

Заключение

В вашем случае причина отсутствия звука может заключаться как в программной ошибке, так и в неправильных настройках оборудования. Пробуя указанные рекомендации и корректируя код, вы сможете добиться нужного результата. В случае дальнейших сложностей предложите детали о том, что вы уже проверяли, и какие изменения в коде вносили.

Оцените материал
Добавить комментарий

Капча загружается...