Вопрос или проблема
Я надеюсь заставить мой 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 может быть вызвана несколькими факторами. Рассмотрим основные причины и возможные решения, чтобы помочь вам эффективно справиться с ситуацией.
Основные причины низкого уровня звука
-
Неправильные параметры генерации звука:
- В вашем коде для генерации синусоиды используется
floor(INT16_MAX / 3)
в качестве амплитуды. Хотя это значение может быть допустимо, возможно, вам стоит попробовать установить амплитуду ближе кINT16_MAX
для обеспечения более громкого звука. Например:floor(INT16_MAX);
- В вашем коде для генерации синусоиды используется
-
Программная ошибка в
generate_sine_wave
:- Ваша реализация функции
generate_sine_wave
создает два одинаковых значения подряд. Это может привести к несоответствию с ожиданиями. Попробуйте изменить:buffer.at(i) = sample; buffer.at(i + 1) = sample;
На:
buffer.at(i) = sample;
- Ваша реализация функции
-
Настройки I2S:
- Проверьте настройки конфигурации I2S в вашем коде. Убедитесь, что вы используете соответствующий формат передачи данных (например, I2S_COMM_FORMAT_STAND_I2S или I2S_COMM_FORMAT_STAND_MSB). Также убедитесь, что используемые вами пины (BCLK, LRC, DOUT) соответствуют выводам вашего устройства.
-
Кодировка и управление потоком:
- Вам необходимо убедиться, что обработка потоков данных осуществляется корректно. Советуем добавить дополнительное логирование, чтобы убеждаться в том, что данные отправляются на выход.
Пример добавления логирования
Попробуйте расширить логирование внутри цикла отправки данных в i2s_task
, чтобы лучше понять, какие данные на самом деле отправляются, и как обрабатываются ошибки.
Тестирование звука
Убедитесь также в следующем:
-
Подключение: Проверьте правильность подключения DAC или усилителя колонки к ESP32. Проверьте все соединения и убедитесь, что они надежные.
-
Частота выборки: Убедитесь, что ваш код генерирует звук на частоте выборки, поддерживаемой вашим оборудованием. В большинстве случаев 44.1 кГц (44100 Гц) будет приемлемым значением.
-
Проигрывание другого звука: Попробуйте проиграть другой звуковой файл или генерировать другой тон, чтобы исключить возможность аппаратной неисправности.
Заключение
В вашем случае причина отсутствия звука может заключаться как в программной ошибке, так и в неправильных настройках оборудования. Пробуя указанные рекомендации и корректируя код, вы сможете добиться нужного результата. В случае дальнейших сложностей предложите детали о том, что вы уже проверяли, и какие изменения в коде вносили.