Введение
PCM5102A – широко известная микросхема производства Texas Instruments, которая представляет собой цифро-аналоговый преобразователь (ЦАП), позволяющий воспроизводить музыку с качеством до 384kHz/32bit. Интернет практически наводнен проектами на основе PCM5102A и микросхем фирмы Espressif в качестве управляющего контроллера, потому как последние позволяют подключать ЦАП, имеют высокую тактовую частоту (160-240 МГц), обладают большим объемом оперативной памяти и приличным объемом флэш-памяти. Все это в совокупности дает возможность довольно просто реализовать потоковое веб-радио:
ESP32-WROOM-32 и ESP32-WROVER:
- WiFi радио — KaRadio32
- WiFi Web радио на ESP32 — Karadio
- KaRadio + Smalody = Love
- ESP32 I2S Internet Radio. Full Tutorial & explanation of I2S
ESP8266:
Wemos D1 Mini:
Основные недостатки всех этих проектов:
- они все практически одинаковые и делают одно и то же;
- используют удивительную по возможностям микросхему PCM5102A, чтобы играть MP3;
- зависят от интернета;
- невозможно питать от сети совместно с усилителем от одного источника питания, потому что нет развязки земель.
Тем не менее, существуют и более интересные проекты. Например, плеер на основе Sipeed Longan Nano и PCM5102A, который играет файлы .WAV с SD-карты. В данном случае задействованы все возможности платы прототипирования: дисплей и встроенная SD-карта, а PCM5102A используется для воспроизведения звука без потерь.
Я решил реализовать нечто подобное на основе платы ESP32, но играть с SD-карты более удобный и распространенный FLAC, используя шину I2S. Кроме того, я решил добавить развязку земель на основе широко известного модуля Mornsun B0505S.
В качестве справочных материалов использовались следующие статьи:
- MP3 на ESP32. Музыка и звуки с SD карты. Тестируем PCM5102A и MAX98357A
- I2S Sound Tutorial for ESP32
- ESP32: Guide for MicroSD Card Module using Arduino IDE
- Интернет-радио ESP32 на декодере I2S PCM5102
В этих статьях описано, как подключить к ESP32 модули SD-карты и PCM5102A, и использовать их.
Существуют две основные библиотеки для связи ESP32 и PCM5102A по шине I2S:
Я использовал вторую, потому что в ней есть драйвер FLAC.
Предупреждение
Разработку любого устройства можно вести двумя способами: делать много прототипов, не особо думая (метод проб и ошибок), или много думать, но делать мало прототипов. В данном случае я пошел первым путем, потому что решил расслабиться и сделать этот проект легко и "по фану", не особо заморачиваясь с затратами и не напрягая мозг, глубоко не прорабатывая. В итоге я в любом случае получил бесценный опыт и знания, которые теперь получите и вы, если дочитаете эту статью.
Развязка и обвязка
Ранее я сделал standalone вариант модуля земляной развязки в KiCad. Может быть кому-то пригодится. На фото он совместно с усилителем TDA2822.
Я использовал китайский клон модуля Mornsun B0505S noname-производителя K-CUT. В реальности на выходе без нагрузки он выдает не 5В, а 5,24В. В этом нет ничего страшного, так как все равно питание платы TTGO T-Display и PCM5102A идет через понижающие преобразователи до 3,3В.
Обвязку модуля я сделал на основе серьезных исследований, результаты которых сейчас недоступны в связи с известными событиями. Тем не менее, я успел сделать pdf-копию статьи. Конкретно был реализован нижний вариант обвязки, представленный на следующем изображении.
Для обвязки использовалась индуктивность на 20 мГн (1,5 А, 0805), так как на 6,6 мГн просто не было в наличии, и я взял наиболее близкую к ней. Использовались хорошие конденсаторы JB с низким импедансом (1000 мкФ, 25В) и китайская подделка Nichicon (22 мкФ, 25В). Прибор GM328A показал, что он пригоден к использованию. Также был использован хороший китайский клеммник из немагнитного материала (скорее всего какая-то латунь или бронза).
Терзания
Изначально идея была в том, чтобы использовать максимально подходящее для реализации проекта устройство. У меня были аж две платы прототипирования LilyGo TTGO T-Display с TFT-экраном, но в них отсутствует встроенный модуль для SD-карты, что и привело к фатальным результатам.
В качестве модуля SD-карты использовался вот такой малогабаритный и дешевый модуль, который питается от 3,3В.
Также использовалась вот такая реализация модуля PCM5102A:
Для питания TTGO T-Display и остальных модулей был применен регулируемый источник питания SK35L (понижайщий/повышающий). В условиях городской квартиры подобные источники питания очень удобны.
Этапы производства платы, за исключением самых первых - печати дорожек на глянцевой фотобумаге, зачистки фольгированного стеклотекстолита от окисла шкуркой и переноса на него тонера с фотобумаги с помощью утюга, представлены на рисунке. Я подобное выкладываю в последний раз, и больше никогда такое снимать не буду.
После сборки все выглядело как-то так.
Первая проблема, с которой я столкнулся после сборки устройства: нет питания. Оказалось, что я перепутал вход земляной развязки с ее выходом и установил клеммник подачи питания на выходе. На изображении ниже представлен уже исправленный вариант схемы.
На следующем фото представлены последствия, к которым приводят подобного рода ошибки. Вернее, способ их исправления.
По схеме также видно, что плата TTGO T-Display питается от ноги 5V, которая является ни чем иным, как VCC или VDD, поскольку это вообще-то вход для нерегулируемого питания. После исправления дорожек на плате с помощью проводов загорелась красная лампочка питания на PCM5102A, но TTGO T-Display так и не стартанула. При этом она спокойно заводилась от разъема USB typeC. Я уж было подумал, что отвалилось что-то из обвязки платы, но все-таки решил погуглить. Оказалось, что проблема в нецелевом использовании вывода GPIO12, который был мной переопределен для подключения SD-карты по шине SPI.
Здесь я вынужден прерваться и объяснить

То есть SCK, MISO, MOSI общие, а CS для каждого подключенного к шине устройства индивидуальный.
По идее, для случаев встроенных дисплеев, разработчиками предусмотрено два варианта выводов подключения к SPI – VSPI и HSPI. VSPI – это Virtual SPI. Где-то глубоко внутри платы дисплей подключен к микроконтроллеру, и этих выводов мы не видим. А вот выводы для HSPI у нас есть – это GPIO25 (SCK), GPIO26 (MOSI), GPIO27 (MISO) и практически произвольный CS. Проблема в том, что на этих же выводах GPIO25, GPIO26 и GPIO27 у нас висит и шина I2S, к которой подключается PCM5102A. Поэтому и понадобился ремаппинг.
Непосредственно переопределение осуществлялось с помощью библиотеки esp32-micro-sdcard.
Если вы неправильно подключите провода в SPI, то Serial port вам выдаст что-то типа:
rst:0x10 (RTCWDT_RTC_RESET),boot:0x33 (SPI_FAST_FLASH_BOOT)
flash read err, 1000
ets_main.c 371
ets Jun 8 2016 00:22:57
Продолжим. В руководстве Espressif SD Pull-up Requirements написано, что существует-таки "Conflicts Between Bootstrap and SDIO on DAT2". А DAT2 – это и есть GPIO number 12, вот оно и не запускалось.
Тогда я решил уже обстоятельно погуглить и наткнулся вот на такое руководство ESP32 Pinout Reference: Which GPIO pins should you use?, в котором очень доходчиво написано, почему я не прав, а именно, что далеко не все отверстия предназначены для того, чтобы в них что-то вводить.
После этого я пошел традиционным путем и получил что-то подобное представленному на вышеприведенной электрической схеме. Было много радости, когда плата запустилась, и когда на экране возник первый "Hello world". Только вот после включения SD-карты по переопределенной HSPI, экран ни в какую не обновлялся. И тогда я понял, почему свою новую плату TTGO T-Display-GD32 разработчики из LilyGo сделали уже со слотом для SD-карты.
Очень жалко, что, в свое время, я эту плату не купил.
Исправление
По вышеизложенным причинам было решено пойти еще более классическим путем и использовать проверенные временем компоненты. Плата TTGO T-Display была заменена на плату ESP32-DevKitC, а в качестве дисплея был использован SSD1306 (OLED).

На изображении подписано неправильно - это не ESP32-DevKit V1 DoIt (30 pin), а именно ESP32-DevKitC (38 pin). У использованной мной платы была одна особенность: китаец припаял штыревые вилки не просто криво, а с радиусом гиба (все штырьки смотрели в разные стороны), поэтому они просто не влезали в розетки на плате. Мне пришлось выпаивать обе штыревые вилки и припаивать новые, качественные, из фосфористой бронзы, а главное - ровно. Поэтому я всегда вам рекомендую заказывать платы с неприпаянными вилками. Китайцы ровно их припаивать не умеют в принципе. Я таких плат заказывал минимум 5 штук - все пришли криво паянными, но тут был особый случай, как будто на зло он так припаял.
ESP32-DevKitC я взял, потому что там есть все нужные шины, исполненные НЕЗАВИСИМО: SPI, I2S и I2C (для подключения SSD1306, SPI-варианта у меня не было).
К сожалению, замена компонентов не лучшим образом отразилась на габаритах FLAC-плеера, но он все так же влезал на стандартную печатную плату 100x70.
После производства вариант номер 2 выглядел как-то так:
В итоге я решил заменить HSPI на VSPI для SD-карты, в соответствии с вот этим руководством.
Это положительным образом сказалось на возможности загрузки кода в плату – теперь не было необходимости нажимать кнопку boot.
Итоговая электрическая схема выглядит вот так.
А задняя часть платы должна выглядеть вот так.
В ходе разработки электрической схемы в KiCad 6 мне пришлось создать два компонента: для PCM5102A и для модуля SD-карты, потому что в интернете их не оказалось.
Мой проект KiCad 6 также содержит следующие полезные либы:
Еще один важный момент. Часть кода внутри loop() из примера PlayFLAC-SD-SPDIF не работает должным образом – плеер сразу перескакивает на "Playback form SD card done", хотя файлы с SD-карты видит.
В тестовой прошивке, которую я написал, плеер сначала определяет тип SD-карты и отображает его на дисплее, а в цикле показывает имена дорожек, которые он играет в данный момент.
В последовательный порт при этом пишется следующее:
Start
[E][vfs_api.cpp:22] open(): File system is not mounted
SD Card Type: SDHC
SD Card Size: 7663MB
initialisation done.
Listing directory: /
FILE: /ff-16b-2c-44100hz.flac SIZE: 22405489
flac has been detected
Sourse is open!
Playing '/ff-16b-2c-44100hz.flac' from SD card...
+0 0x3ffb1e28
FILE: /gs-16b-2c-44100hz.flac SIZE: 1336528
flac has been detected
Sourse is open!
Playing '/gs-16b-2c-44100hz.flac' from SD card...
Исходный код прошивки написан на Arduino Framework и предельно понятен, поэтому я не вижу смысла его комментировать. Писать все это на ESP-IDF не было никакого смысла, потому что, во-первых, нет библиотек, а во-вторых столько времени.
Музыкальные примеры в формате FLAC были взяты отсюда, как и рекомендует автор библиотеки earlephilhower/ESP8266Audio.
Максимальное энергопотребление плеера составляет 128 мА. Ясно, что при таком потреблении его следует питать от сети совместно с усилителем.
Далее можно будет подключить динамики, усилитель и насладиться звуком.
Поучение
Что я понял из этой истории.
- Работа с чистым микроконтроллером гораздо проще, потому что есть мануал на микроконтроллер, которому можно строго следовать. В этих мануалах бывают ошибки, но чаще всего о них уже известно, и правильное решение можно найти в интернете. Что наделали в своей плате ее разработчики известно только им, и до известных глюков и несовместимостей можно добраться только опытным путем.
- Лучше сразу использовать полноценную плату прототипирования с большим количеством выводов, а не всякие урезанные Wemos D1 Mini ESP32 или вышеупомянутые TTGO T-Display. Разработчики объединяют выводы и шины, в результате, к примеру, наличие встроенного дисплея только мешает, занимая шину SPI, к которой больше ничего не подключишь. Возможно есть способ это сделать, но я его не нашел.
- Авторы свободных библиотек часто ошибаются, и код из примеров может быть нерабочим.
Ссылки на проект:
Проект platformIO
Скомпилированная прошивка лежит в devkitc_pcm5102_sd_fs\.pio\build\esp32dev\firmware.bin
Проект KiCad 6
Становитесь автором сайта, публикуйте собственные статьи, описания самоделок с оплатой за текст. Подробнее здесь.