В рамках данной статьи мы подробно рассмотрим как построить Bluetooth-колонку на базе микроконтроллера ESP32 и стерео аудиомодуля с цифро-аналоговым преобразователем (ЦАП) модели PCM5102, используя среду программирования Espressif IDE и фреймворк ESP-IDF.
Содержание
- Описание аудиомодуля ЦАП PCM5102
- Схема подключения PCM5102 к ESP32
- Подготовка проекта в Espressif IDE ESP-IDF
- Как прошить микроконтроллер ESP32 в среде Espressif IDE
- Проверка работоспособности Bluetooth-колонки
По мере освоения микроконтроллера ESP32 сложность реализуемых задач постепенно возрастает. И в какой-то момент приходит понимание, что возможностей среды разработки Platform IO или Arduino IDE не хватает для реализации относительно сложных задач. Например, разработка беспроводной колонки с применением технологии Bluetooth.
В сети Интернет есть множество статей, в которых предлагается использовать библиотеку pschatzmann/ESP32-A2DP как ключевую для реализации данной задачи на фреймворке Arduino. Однако, при работе с этой библиотекой постоянно возникали какие-то сложности или конфликтные ситуации, из-за чего код не компилировался.
При попытке использования среды Platform IO и фреймворка ESP-IDF также не удавалось добиться успешной компиляции кода, поскольку требовались дополнительные и не совсем очевидные настройки среды.
В качестве эксперимента было принято решение попробовать написать прошивку для Bluetooth-колонки в среде программирования Espressif IDE и фреймворке ESP-IDF.
Практически каждая современная беспроводная колонка является устройством, которое работает на стандарте A2DP (Advanced Audio Distribution Profile).
A2DP — это профиль Bluetooth, разработанный для передачи высококачественного стереоаудиопотока между устройствами. Он позволяет передавать музыку и другие аудиоданные с одного устройства (например, смартфона, компьютера или MP3-плеера) на беспроводные наушники, колонки или автомобильную аудиосистему.
Основные особенности A2DP:
— поддерживает стереозвук (моно также возможно, но редко используется);
— использует кодек сжатия для передачи аудио (например, SBC, AAC, aptX, LDAC);
— работает в одностороннем режиме (от источника к приемнику);
— обеспечивает достаточно низкую задержку (зависит от кодека).
Описание аудиомодуля ЦАП PCM5102
PCM5102 — это микросхема стерео аудиодекодера, разработанный компанией Texas Instruments, предназначенная для воспроизведения аудиосигнала с высоким качеством звучания. Декодер обладает 24-битным цифро-аналоговым преобразователем и I2S-интерфейсом, а также поддерживает частоту дискретизации до 384 кГц. При этом микросхема потребляет ток максимум 10…12 мА при напряжении питания 3,3 В, что делает её идеальной для применения в портативных аудиосистемах.
Ниже представлены основные параметры декодера:
Модуль имеет встроенные средства фильтрации и обработки сигнала:
— встроенный фильтр верхних частот (HPF) для удаления смещения по постоянному току;
— деэмперсизация (DEMP) для подавления высокочастотного шума;
— Soft Mute для плавного отключения звука без щелчков.
Для более удобной экспериментальной работы декодер продаётся в составе готовых модулей в виде печатной платы, на которой распаяна микросхема в корпусе TSSOP-20 с полной обвязкой, штыревыми выводами и гнездом mini jack 3,5 mm:
Таблица назначения выводов платы PCM5102:
Также рядом с гнездом mini jack 3,5 mm расположена гребёнка на 3 контакта, предназначенные для подачи аудиосигнала на вход внешнего усилителя звука:
— L (LEFT): левый канал
— G (GND): общий провод («земля»)
— R (RIGHT): правый канал
Схема подключения PCM5102 к ESP32
Для работы с аудиодекодером используется аппаратный I2S-интерфейс на отладочной плате NodeMCU-32S (38 pin), которая построена на базе модуля ESP-WROOM-32. Ниже представлена таблица и схема подключения PCM5102 к отладочной плате, а также фотография собранного макета:
Подготовка проекта в среде Espressif IDE ESP-IDF
После установки среды программирования Espressif IDE и фреймворка ESP-IDF на рабочем столе ОС Windows появится три ярлыка:

Перед началом работы запустите командную строку ESP-IDF 5.3 CMD, чтобы «прописались» переменные окружения IDF_PATH и IDF_TOOLS_PATH в системе. Дело в том, что по умолчанию переменные назначаются временно на период сессии работы операционной системы. То есть, если Вы завершите работу операционной системы (выключите компьютер), то всё сбрасывается. Вновь включили — снова «прописывайте переменные».

Теперь запускаем среду разработки Espressif IDE, кликая по соответствующему ярлыку:

Откроется стартовая страница:
Создадим новый проект, выбрав из выпадающего меню «File» (в верхнем левом углу окна) пункты New –> Espressif IDF Project:
Откроется соответствующее окно для создания нового проекта:
Для удобства пользователей разработчики программного обеспечения предусмотрели возможность использовать в качестве шаблона уже готовые проекты. В частности, задача по созданию беспроводного аудиопроигрывателя также имеет свой шаблон: a2dp_sink.
Чтобы его выбрать, нужно выполнить несколько шагов:
1) установить галочку «Create a project using one of the templates». Откроется доступ к дереву директорий с шаблонами;
2) раскрыть папку «bluetooth»;
3) раскрыть папку «bluedroid»;
4) раскрыть папку «classic_bt»;
5) выбрать шаблон «a2dp_sink»;
6) убрать галочку «Use default location» и выбрать удобную для Вас директорию. Рекомендуется создать внутри штатной директорию свою папку под данный проект. После чего поставить галочку «Use default location», поскольку иначе проджект-мастер блокирует кнопку «Finish»
7) сменить имя «Project name» на какое-нибудь иное, чтобы не было конфликта с шаблоном;
8) завершить процесс нажатием кнопки «Finish».
Проект сформируется и откроется окно среды разработки:

Первым делом поправим файл CMakeLists.txt, который можно найти в дереве файлов в левой части окна. Открываем этот файл. Выделяем все строки и комментируем их, нажав комбинацию клавиш Ctrl + 7:
Необходимо вставить и сохранить (Ctrl + S) несколько иной код, подключающий необходимые библиотеки при сборке:
idf_component_register(
SRCS "bt_app_av.c"
"bt_app_core.c"
"main.c"
INCLUDE_DIRS "."
PRIV_REQUIRES
bt
nvs_flash
esp_ringbuf
esp_driver_i2s
driver
)
# Подключение компонентов из примера A2DP
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/bluedroid/classic_bt/bt_a2dp_sink/components)
Далее открываем главный файл с кодом программы main.c, тоже выделяем все строки и комментируем посредством комбинации клавиш Ctrl + 7:
Вставляем в файл код, представленный и подробно прокомментированный ниже. А потом сохранить, нажав комбинацию кнопок Ctrl + S:
#include "freertos/FreeRTOS.h" // FreeRTOS ядро
#include "freertos/task.h" // FreeRTOS задачи
#include "esp_system.h" // Основные системные функции ESP-IDF
#include "esp_log.h" // Логирование
#include "esp_bt.h" // Bluetooth базовые функции
#include "esp_bt_main.h" // Основная инициализация Bluetooth
#include "esp_a2dp_api.h" // A2DP профиль Bluetooth для аудио
#include "esp_bt_device.h" // Управление Bluetooth устройством
#include "esp_gap_bt_api.h" // GAP профиль Bluetooth (видимость, соединения)
#include "driver/i2s.h" // Драйвер I2S (для аудио передачи)
// Тег для логов
static const char *TAG = "BT_SPEAKER";
// Конфигурация I2S пинов и параметров
#define I2S_NUM (0) // Используем I2S порт 0
#define I2S_SAMPLE_RATE (44100) // Частота дискретизации 44.1kHz (CD качество)
#define I2S_BCK_IO (26) // Пин для BCK (битовый такт)
#define I2S_WS_IO (25) // Пин для WS (word select)
#define I2S_DO_IO (22) // Пин для передачи данных (Data Out)
// Функция настройки и запуска I2S драйвера
void i2s_driver_setup(void)
{
// Конфигурация I2S
const i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX, // Режим мастер и передача
.sample_rate = I2S_SAMPLE_RATE, // Частота дискретизации
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // 16 бит на сэмпл
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // Стерео (правый и левый канал)
.communication_format = I2S_COMM_FORMAT_I2S, // Формат I2S
.intr_alloc_flags = 0, // Флаги прерываний (0 - по умолчанию)
.dma_buf_count = 8, // Количество DMA буферов
.dma_buf_len = 64, // Длина каждого DMA буфера
.use_apll = false, // Не использовать APLL
.tx_desc_auto_clear = true, // Автоочистка дескрипторов передачи при ошибках
};
// Конфигурация пинов I2S
const i2s_pin_config_t pin_config = {
.bck_io_num = I2S_BCK_IO, // Пин BCK
.ws_io_num = I2S_WS_IO, // Пин WS
.data_out_num = I2S_DO_IO, // Пин передачи данных
.data_in_num = I2S_PIN_NO_CHANGE // Приём данных не используется
};
// Устанавливаем драйвер I2S с конфигурацией
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
// Назначаем пины для I2S
i2s_set_pin(I2S_NUM, &pin_config);
// Очищаем DMA буфер, чтобы не было мусорных данных
i2s_zero_dma_buffer(I2S_NUM);
}
// Коллбек функция для получения PCM аудиоданных по Bluetooth A2DP
void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len)
{
size_t written = 0; // Количество реально записанных байт
// Записываем полученные данные в I2S для воспроизведения
// portMAX_DELAY — ждать, если буфер занят
i2s_write(I2S_NUM, data, len, &written, portMAX_DELAY);
}
// Коллбек для обработки событий Bluetooth A2DP
void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
{
switch (event) {
case ESP_A2D_CONNECTION_STATE_EVT:
// Событие изменения состояния соединения
ESP_LOGI(TAG, "Bluetooth device %sconnected",
param->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED ? "" : "dis");
break;
case ESP_A2D_AUDIO_STATE_EVT:
// Событие изменения состояния аудио (старт/стоп)
ESP_LOGI(TAG, "Audio state: %d", param->audio_stat.state);
break;
default:
// Другие события игнорируем
break;
}
}
// Главная функция приложения
void app_main()
{
// Логируем начало инициализации I2S
ESP_LOGI(TAG, "Инициализация I2S");
i2s_driver_setup(); // Настраиваем I2S
// Логируем начало инициализации Bluetooth
ESP_LOGI(TAG, "Инициализация Bluetooth");
// Освобождаем память BLE, так как используем только Classic BT
esp_bt_controller_mem_release(ESP_BT_MODE_BLE);
// Получаем конфигурацию Bluetooth контроллера по умолчанию
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
// Инициализируем Bluetooth контроллер
esp_bt_controller_init(&bt_cfg);
// Включаем Bluetooth Classic
esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT);
// Инициализируем и запускаем стек Bluedroid
esp_bluedroid_init();
esp_bluedroid_enable();
// Регистрируем коллбеки для A2DP профиля
esp_a2d_register_callback(&bt_app_a2d_cb); // События A2DP
esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb); // Получение аудиоданных
esp_a2d_sink_init(); // Инициализация A2DP sink (приёмник)
// Устанавливаем имя Bluetooth устройства (будет видно другим устройствам)
esp_bt_gap_set_device_name("ESP32_SPEAKER");
// Разрешаем устройству быть обнаруживаемым и подключаемым
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
// Логируем, что устройство готово к работе
ESP_LOGI(TAG, "Bluetooth колонка готова!");
}
Видно, что многие строчки кода, относящиеся к I2S-интерфейсу, подчёркнуты красным. Попробуем выполнить сборку кода, выбрав в меню «Project» пункт «Build Project»:
Компиляция может выполняться достаточно долго: от 30 секунд до нескольких минут, в зависимости от размера кода и степени изменений относительно предыдущей компиляции:

В результате сборка завершилась с предупреждениями в количестве 3 штук. При этом 0 ошибок:
Тем не менее, мы всё же посмотрим, какие предупреждения компилятор объявил:
Эти предупреждения говорят о следующем:
— устаревший драйвер для аналого-цифрового преобразователя (АЦП);
— устаревшая библиотека для I2S-интерфейса;
— устаревшее значение константы I2S_COMM_FORMAT_I2S.
Для нас неактуальность драйвера АЦП не имеет значения, поэтому пропустим данное замечание.
А вот для решения вопроса с устаревшей библиотекой I2S нужно внести некоторые правки в настройки проекта.
Дело в том, что в установленном фреймворке ESP-IDF 5.3.1 актуальной версией библиотеки для I2S-интерфейса является driver/i2s_std. Но в нашем коде используется более ранняя версия — driver/i2s. Чтобы решить этот конфликт, в настройках нужно включить опцию «Suppress legacy driver deprecated warning». Для этого следует открыть меню настройки конфигурации sdkconfig, который размещён в дереве файлов слева. Когда проджект-мастер сформировал пространство для работы, sdkconfig изначально не появился в дереве файлов. Только после первой компиляции он создаётся:
Кликаем два раза, и откроется SDK Configuration:
Далее выполняем 3 простых шага:
1) в поисковой строке пишем «I2S», чтобы быстрее найти нужный пункт;
2) выбираем пункт «Legacy I2S Driver Configuration»;
3) ставим галочку напротив «Suppress legacy driver deprecated warning».
После этого сохраняем изменения, нажав комбинацию клавиш Ctrl + S.
Попробуем выполнить пересборку (Project –> Build Project или щелкнуть по пиктограмме в виде молотка в верхнем левом углу окна):
Как видим, компиляция прошла успешно, а предупреждений стало на 1 меньше. Остались вопросы касательно драйвера АЦП и устаревшей версии переменной:
Но так как мы приняли использовать устаревшую версию драйвера для I2S, то оставим всё как есть.
Как прошить микроконтроллер ESP32 в среде Espressif IDE
Переходим к процессу прошивки микроконтроллера. Подключаем отладочную плату к компьютеру через USB-кабель (настоятельно рекомендуется использовать кабель длиной не более 1 метра). Также уточните, что драйвер для USB-UART преобразователя у Вас установлен на компьютер, и определите, какой COM-порт назначен для отладочной платы:

Далее открываем терминал (пиктограмма указана красной стрелкой) и выбираем нужный последовательный порт:
Теперь нужно уточнить порт для целевого устройства (target), нажав на пиктограмму в виде шестерёнки и тоже выбрать COM-порт:
Итак, можно приступить непосредственно к прошивке, нажав кнопку “Run” справа от “молоточка” в верхнем левом углу окна:
Процесс занимает несколько секунд, прогресс отображается в мониторе порта. Нажимать кнопку сброса на отладочной плате не нужно (в отличие от PlatformIO).
Проверка работоспособности Bluetooth-колонки
Как только загрузка кода успешно завершится, устройство начинает работу. Берём смартфон, включаем Bluetooth и сканируем доступные устройства. Должно быть видно «ESP32_SPEAKER» (название можно менять в коде программы):
Выбираем устройство и подключаемся к нему:
При успешном сопряжении устройство будет иметь пометку «Используется»:

Теперь запускаем на смартфоне какой-нибудь проигрыватель (приложение на самом смартфоне или какой-либо веб-сервис) и воспроизводим аудиотрек:
В наушниках должна быть слышна музыка.
Заключение
В рамках этого эксперимента наглядно рассмотрен практический пример создания основы для беспроводного аудиопроигрывателя на базе микроконтроллера ESP32 и аудиомодуля PCM5102.
Использование среды программирования Espressif IDE и фреймворка ESP-IDF обеспечивает более гибкий и профессиональный подход к разработке по сравнению с Arduino IDE или Platform IO, хотя и требует дополнительных настроек.

























