Многополосный усилитель с цифровым DSP и i2S усилительными модулями.

В этом руководстве вы узнаете, как использовать протокол связи I2S для передачи цифровых звуковых сигналов для записи и визуализации данных микрофона и воспроизведения музыки из внутренней памяти, а также с внешней SD-карты.

Мы также сравним разные микроконтроллеры и увидим, почему мы предпочитаем микроконтроллер ESP32 для наших проектов I2S.

Зачем нам нужен протокол I2S?

Если мы хотим воспроизвести цифровой аудиофайл с помощью платы микроконтроллера, мы должны рассмотреть всю цепочку цифрового аудио. Следующий схематический рисунок показывает, как аудиофайл сохраняется на SD-карте и считывается с платы микроконтроллера. Затем плата подключается к динамику через цифровой контакт и землю.

В моем случае у меня есть образец аудиофайла с частотой дискретизации 44,1 кГц, стереоформатом и глубиной звука 16 бит. На нашей стороне ввода, где мы хотим прочитать музыкальный файл, у нас нет проблем, потому что соединение SPI достаточно быстрое, чтобы качество не ухудшалось во время передачи.

Но со стороны выхода мы должны преобразовать цифровой сигнал в аналоговый сигнал. Это делается с помощью цифро-аналогового преобразователя (ЦАП). В зависимости от используемого микроконтроллера возникают разные проблемы:

  • Arduino и ESP8266
    : платы Arduino, а также ESP8266 в целом не имеют внутреннего ЦАП, и поэтому вам придется создавать ЦАП с внешними компонентами.
  • ESP32
    : ESP32 имеет внутренний ЦАП для создания аналогового выходного сигнала, однако ЦАП имеет только 8-битное разрешение. Поскольку у нас есть 16-битный входной сигнал, мы немного потеряем качество.

Но как мы можем преобразовать цифровые данные из файла WAVE в динамик? Решением этой проблемы является протокол связи I2S, который поддерживает от 4 до 32 бит данных на выборку. Чтобы сделать нашу жизнь еще проще, мы используем коммутационную плату для аудио MAX98357 I2S. Но сначала мы углубимся в протокол связи I2S.

Как я гонял I2S по обычному патчкорду Fast Ethernet CAT5

Накрывшее меня разочарование было неожиданным. Как так? При массе восторгов от способа передачи информации по этой чудесной шине, о приросте качества звучания, и прочих положительных моментах не оказалось ни одного законченного схемного решения уровня «корпус источника» — «корпус ЦАП».

А так как транспорт у меня это ПК с выводом по USB, то именно решение «корпус» — «корпус» самый оптимальный вариант. Да и на рынке все чаще стали появляться вполне высококачественные решения USB-транспортов с выходом I2S TTL. В общем нужно продумать линк, позволяющий гнать I2S от транспорта до ЦАП в TTL формате, да еще и с гальваноразвязкой. Вообще для подобных целей технически грамотно было бы использовать шину LVDS, но кроме явных плюсов в виде большого расстояния передачи, симметричных линий, имеем и свои минусы — дороговизна и труднодоставаемость микросхем приемопередатчиков, необходимость использования специальных разъемов, отсутствие гальваноразвязки.

Мне же нужно расстояние на более полуметра, но вот как это организовать? Сразу же в голове нарисовалась картина: куча экранированных проводов, позолоченный разъем. Ах да! Разъем! Поиск как обычно дал «массу вариантов». Кто-то использовал DB-9 — разъем от СОМ порта ПК. Но моя «личная неприязнь» к нему как к разъему не позволила остановиться на этом решении.

А что применяют иностранцы в своих вариантах USB-транспортов? Недолгий поиск и есть ответ — RG45. Восьмиконтактный пластиковый обжимной разъем, применяющийся в сетевой инфраструктуре стандарта Fast Ethernet (100BASE-T)! Четыре изолированных витых пары! — Шикарно!- сказал я. — Ага!- сказал поисковик — А распиновка? — Давай, попробуй. «I2S pinout», «RG45 I2S» и еще тридцать два варианта. — Нету? — Да ты искать не умеешь! И правда не умею. Так как из всего найденного «фабричного» интересными было два варианта — Northstar DAC Model 192 MKII и Terralink X, решено было остановиться на них.

У всего остального найденного было что-то не совсем вменяемое, включая фантомное питание +5В. Ну и информации о соединительном кабеле, применяемом с этими устройствами тоже не смог найти. Ну в общем то раскладка Terralink меня устраивала, так как окзалось, что она попарно совпадала с распиновкой стандартного патчкорда.

Протокол связи I2S

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

  1. 3-проводное соединение I2S
  2. Сетевые компоненты I2S
  3. Временная диаграмма I2S

В следующей таблице показано, какие платы имеют интерфейс I2S, а какие нет.

Имеет интерфейс I2SНе имеет интерфейса I2S
ArduinoПлаты Arduino Arduino Due, Arduino MKR Zero, Arduino MKR1000 WiFiс микроконтроллером ATmega328P, такие как Arduino Uno или Arduino Nano.
ESPESP8266 ESP32

Из таблицы видно, что только некоторые специальные платы Arduino имеют интерфейс I2S, но не наиболее используемые платы, такие как Arduino Uno. Также все платы ESP8266 и ESP32 поддерживают интерфейс I2S, поэтому я рекомендую использовать для этого руководства плату на базе микроконтроллера ESP8266 или ESP32. В моем случае я использую микроконтроллер ESP32, потому что библиотеки, которые мы используем, поддерживают ESP32 лучше, чем ESP8266, по моему опыту.

I2S и эпоха цифрового аудио

Растущая коллекция общепринятых электротехнических аббревиатур временами может быть немного ошеломляющей; и я не удивлюсь, если вы несколько раз видели термин «I2S» и просто предполагали, что это была просто опечатка в аббревиатуре «I2C».

Между этими двумя протоколами действительно существует определенная связь. Оба были первоначально разработаны компанией Philips Semiconductors (теперь NXP), и названия обоих начинаются с «I2», потому что они предназначены для связи между микросхемами (англ. аббревиатура «IC»). Однако I2S появился после I2C, и, если I2C является универсальным интерфейсом, I2S предназначен для передачи аудиоданных – «S» в названии означает «sound» (звук).

I2S был создан в 1980-х годах, когда цифра начала свое завоевание рынка потребительских аудиосистем. Заявленная цель создания I2S – облегчение разработки аудиоэлектроники при помощи стандартизированного интерфейса для передачи цифровых данных между АЦП, ЦАП, цифровыми фильтрами, цифровыми сигнальными процессорами и другими типами интегральных микросхем, используемых в аудиосистемах. По сути, это двухканальный протокол, потому что он был разработан для стереофонического звука.

3-проводное соединение I2S

Протокол I2S использует для связи три провода.

Последовательные часы (SCK)

, также называемые линией битовых часов (
BCLK
), используются для получения всех компонентов в одном цикле. Частота тактовых импульсов последовательного интерфейса определяется следующим образом:
Частота = Частота дискретизации * Количество бит на канал * Количество каналов.
Для моего WAVE-файла, который я использую в этом руководстве, мы уже знаем следующие переменные:

  • Частота дискретизации: 44,1 кГц
  • Бит на канал: 16
  • Количество каналов: 2

Следовательно, тактовая частота последовательного интерфейса составляет 44,1 кГц * 16 * 2 = 1,411 МГц.

Вторая линия протокола связи I2S

— это провод
выбора слова (Word Select — WS)
или выбора кадра (
Frame Select — FS
), который различает левый или правый канал.

  • Если WS = 0 → используется канал 1 (левый канал)
  • Если WS = 1 → используется канал 2 (правый канал)

Последний провод

— это
линия последовательных данных (Serial Data — SD)
, по которой полезная нагрузка передается с двумя дополнениями. Важно, чтобы старший бит передавался первым (сначала MSB), потому что передатчик и приемник могут иметь разную длину слова. Следовательно, ни передатчик, ни приемник не должны знать, сколько битов передается. Но что произойдет, если длина слова между передатчиком и приемником не совпадает?

  • Если WS приемника > WS передатчика → слово усекается (младшие значащие биты данных устанавливаются в 0)
  • Если WS приемника < WS передатчика → биты после LSB игнорируются

Организация контроллера [ править | править код ]

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

Первая часть — сам контроллер со входами. Для работы ему нужен генератор тактовой частоты, который выдает события канала прямого доступа. Прием-передача звука может осуществляться не микропроцессором, а каналом прямого доступа, специальным процессором для ввода-вывода данных. Этот канал прямого доступа нуждается в событиях начала считывания данных регистров приема или передачи данных в регистры передаточные.

Вторая часть — регистры интерфейса, предусмотрены следующие их типы:

  1. Регистры флагов прерывания;
  2. Регистр разрешения прерываний от того или иного источника (по числу флагов прерывания или по числу разрядов регистра разрешения прерываний)
  3. Регистр управления, в котором задаются режимы работы контроллера;
  4. Регистр генератора частоты выборки, в котором можно задавать тактовый сигнал и его частоту для битовой синхронизации — если данные принимаются, то регистр записывает эти данные и те могут быть подсчитаны программно;
  5. Два регистра приема данных;
  6. Регистры передачи данных по каналам, в которых могут быть два 32-х битовых регистра, передаваемых последовательно.

Сигналы прерывания говорят о том, какие события возникли внутри контроллера и нуждаются в обработке. Существуют две группы прерываний: первая есть прерывания, связанные с приемом и передачей данных и событий, вторая — связанные с обработкой и генерацией тактовых сигналов. Она вырабатывает сигналы для канала прямого доступа и контроллера прерываний.

Если устройство пассивное (играет роль ведомого), то сигналы поступают извне в синхронизатор. В одном случае он принимает и усиливает, переформировывает тактовые сигналы, делая из плавных по контуру в четкие и резкие. В другом случае он выдает сигнал синхронизации во внешнее устройство. Сигналы блока, отвечающего за разрешение или запрещение работы, формируются по состоянию бита в регистре управления.

Обработчик прерываний сперва производит чтение регистра флагов прерываний для их последующего сброса. Далее читает или записывает данных в регистры данных I²S, если не используется канал прямого доступа. После этого происходит возврат из прерывания.

Конфигурационные опции задают для синхронизатора полярность битовой и кадровой синхронизации. Эти данные помогают синхронизатору выбрать режим работы звукового интерфейса.

Приём данных [ править | править код ]

Последовательный приёмник четко фиксирует уровни сигналов, которые тактируются синхронизатором. Далее эти данные побитно поступают по линии принимаемых данных в регистр сдвига, который синхронизирует данные от синхронизатора. После того, как регистр сдвига запомнится, он переписывается в буфер регистра приёма. Размер разрядности регистра сдвига задается длиной слова. После того, как буфер регистра регистрирует принятые данные, может произойти расширение знака. Так как заведомо используется формат с фиксированной запятой, надо расширить знак до 32-х разрядов, получив 12 разрядов данных. Старший разряд полученных данных распространяется во все старшие разряды регистра, чтобы было правильное число, представленное в дробном формате.

Сетевые компоненты I2S

Если есть несколько компонентов I2S, подключенных друг к другу, я называю это сетью I2S. Компоненты сети имеют разные имена, а также разные функции. На следующем рисунке показаны три разные сети, которые я опишу.

На первом изображении у нас есть передатчик, а также приемник. Передатчиком может быть плата ESP NodeMCU, а приемником — плата аудиоразъема I2S, которую мы описываем в следующем разделе. Также у нас есть три провода для подключения устройств I2S.

В этом первом случае передатчик является ведущим, потому что ведущий управляет последовательными линиями синхронизации (SCK) и линиями выбора слова (WS). На втором рисунке мы видим обратное, потому что получатель сообщений I2S также может быть ведущим. Следовательно, линии SCK и WS начинаются от приемника и заканчиваются на передатчике.

На третьем рисунке показано, что внешний контроллер также может быть ведущим устройством, которое генерирует SCK и WS. Контроллер подключен к узлам в сети.

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

Отлично, но какой аудиоинтерфейс мне купить?

На рынке есть аудиоинтерфейсы на любой бюджет, от менее 100 долларов до нескольких тысяч ваших с трудом заработанных денег. Будьте реалистичны в отношении того, что вы планируете делать с точки зрения аудио. Нужны ли вам восемь входов/выходов, если вы будете играть только со своим уке, когда достаточно двух входов/выходов? С другой стороны, если вы уверены, что в следующем году вы будете записывать живые сессии с вашим джем-трио с каджоном/флейтой/гитарой, то четыре входа/выхода дадут вам возможность для роста.

Другой фактор, о котором следует помнить, — это прогресс. Порты устаревают, операционные системы развиваются, а технологии улучшают производительность устройств. Ожидайте, что ваш аудиоинтерфейс проработает около 5-7 лет, прежде чем в него постучатся гремлины несовместимости (порты firewire, кто-нибудь?).

Определите, что вам нужно от аудиоинтерфейса, определите бюджет и проведите исследование.

Удачной записи!

Временная диаграмма I2S

Чтобы лучше понять поведение, а также функциональность протокола связи I2S, мы взглянем на следующую временную диаграмму I2S.

На временной диаграмме вы видите все три линии: SCK, WS и SD. Сначала у нас есть наши последовательные часы, которые имеют частоту дискретизации * бит на канал * количество каналов. В нашем примере 1,411 МГц. Второй канал — это строка выбора слова, которая изменяется от 1 для правого звукового канала до 0 для левого канала.

Из строки последовательных данных мы видим, что данные отправляются в каждом тактовом цикле на заднем фронте (красная пунктирная линия) → от HIGH до LOW. Для связи I2S также можно отправлять данные при изменении с НИЗКОГО на ВЫСОКИЙ.

Также мы видим, что строка WS изменяется за один такт до того, как будет передан самый старший бит (MSB). Это дает получателю время сохранить предыдущее слово и очистить входной регистр для следующего слова. MSB отправляется, когда SCK изменяется после изменения WS.

Тактовое питание [ править | править код ]

Существует схема, которая отвечает за подачу тактового питания на устройство. Для этого в ней предусмотрен читальный регистр, то есть регистр конфигурации затворов тактового питания. Если подать ноль, то его значение станет единицей и сигнал пойдет. Если будет единица, то произойдет затвор, другими словами тактовое питание при единице на устройство подаваться не будет. Имеются две формулы — тактовая и кадровая синхронизация. В каждой из них берется частота, которая поступает в первый тактовый сигнал и делится на то число раз, которое задано в регистре делителя тактовой частоты или в регистре делителя кадровой частоты.

Плата MAX98357 I2S Audio Breakout

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

  • Декодер
    из сигнала I2S в аналоговый сигнал, потому что динамики работают только с аналоговыми сигналами.
  • Усилитель
    увеличивает мощность аналогового сигнала для увеличения интенсивности звука.

MAX98357 — это входной усилитель с цифровой импульсно-кодовой модуляцией (PCM), который декодирует сигнал I2S в аналоговый сигнал с помощью цифроаналогового преобразователя (DAC), а также имеет встроенный усилитель. На следующем рисунке показана упрощенная блок-схема из таблицы MAX98357.

Исходное изображение

Из блок-схемы MAX98357 вы видите, что сначала сигнал I2S преобразуется в аналоговый сигнал через ЦАП, а послесловия усиливаются усилителем с заранее заданной регулировкой усиления.

В чем разница между аудиоинтерфейсом и звуковой картой?

Это звучит так, как будто речь идет о настройках для шутки про Mac/PC, но на самом деле это отличный вопрос. По сути, звуковая карта и аудиоинтерфейс выполняют одну и ту же работу — преобразование аналоговых сигналов в цифровые и обратно. Но звуковые карты устанавливаются внутри, а аудиоинтерфейсы — снаружи. Кроме того, аудиоинтерфейсы обеспечивают больший контроль над качеством звука, предлагая такие возможности, как аналоговые входы линейного уровня, входы XLR, фантомное питание для конденсаторного микрофона и возможность записи нескольких инструментов одновременно.

Спецификация платы Audio Breakout Board MAX98357

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

Adafruit MAX98357A или SparkFun MAX98357AЗначение
Диапазон напряжения питания2,7… 5,5 В
Выходная мощность3,2 Вт на 4 Ом при 5 В 1,8 Вт на 8 Ом при 5 В
Выбор выходного каналавлево, вправо или влево / 2 + вправо / 2 (по умолчанию)
Частота дискретизации8 кГц… 96 кГц
Разрешение выборки16/32 бит
Ток покоя2,4 мА
Усилитель классаD
Коэффициент усиления3 дБ… 15 дБ (по умолчанию: 9 дБ)
Требуются часы памяти (MCLK)?Нет

Рабочее напряжение MAX98357 составляет от 2,7 В до 5,5 В. Поэтому вы можете запитать микроконтроллер с платой на базе Arduino (5 В) или ESP (3,3 В). Выходная мощность составляет 3,2 Вт для динамика с сопротивлением 4 Ом и 1,8 Вт для динамика с сопротивлением 8 Ом.

Конфигурация платы по умолчанию — «моно», то есть левый и правый сигналы объединяются вместе для управления одним динамиком. Если вы хотите переключиться на стереозвук, вам нужно разрезать моно-перемычку на плате и припаять стерео соединение для левого или правого канала.

Частота дискретизации MAX98357 находится в диапазоне от 8 кГц до 96 кГц, поэтому музыка в нашем примере с частотой дискретизации 44,1 кГц идеально подходит для этой частоты дискретизации. Разрешение выборки составляет 16 или 32 бита, а ток покоя очень низкий — 2,4 мА.

Поскольку усилитель использует широтно-импульсную модуляцию для управления выходными устройствами, он относится к усилителю класса D. Коэффициент усиления усилителя составляет от 3 дБ до 15 дБ с коэффициентом усиления по умолчанию 9 дБ. В следующей таблице показано, как изменить коэффициент усиления. Ключевым моментом является то, что вывод усиления должен быть подключен к другим выводам, чтобы изменить коэффициент усиления.

УсилениеПодключение контакта GAIN
15 дБПодключен к GND через резистор 100 кОм
12 дБПодключен к GND
9 дББез подключения (по умолчанию)
6 дБПри подключении к VDD / Vin
3 дБПодключен к VDD / Vin через резистор 100 кОм

Типы аудиоинтерфейсов

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

USB

Аудиоинтерфейсы USB подходят для подкастеров и сольных исполнителей/композиторов, которым обычно нужно записывать только один источник за раз и слышать, что выходит из их DAW.

Firewire/Thunderbolt

Более мощные аудиоинтерфейсы с интерфейсами usb, firewire и thunderbolt, как правило, имеют больше входных и выходных опций и могут лучше справляться с задержками благодаря более высокой пропускной способности сигнала.

Какой аудиоинтерфейс подходит?

Выбор аудиоинтерфейса USB, Firewire или Thunderbolt зависит от портов вашего компьютера и от того, как вы будете его использовать. Если вы планируете записывать несколько каналов одновременно (например, полную ударную установку), вам лучше выбрать разъем с более высокой пропускной способностью, например Firewire или Thunderbolt. Если же вы будете просто напевать под свой шедевр, то USB будет вполне достаточно.

Как записывать и визуализировать данные с помощью микрофона I2S

В первом примере мы начинаем записывать и визуализировать звуковые данные с микроконтроллера микрофона I2S SPH0645 от adafruit. В этом примере мы используем микроконтроллер ESP32 NodeMCU.

На следующем рисунке показана проводка между ESP32 NodeMCU и коммутационной платой SPH0645.

Важно подключать микроконтроллер I2S только к выводу 3,3 В. Следующий код Arduino визуализирует аналоговые звуковые данные в последовательном плоттере Arduino.

#include «driver/i2s.h» const i2s_port_t I2S_PORT = I2S_NUM_0; void setup() { Serial.begin(115200); esp_err_t err; // The I2S config as per the example const i2s_config_t i2s_config = { .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX), // Receive, not transfer .sample_rate = 16000, // 16KHz .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, // could only get it to work with 32bits .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT, // use right channel .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // Interrupt level 1 .dma_buf_count = 4, // number of buffers .dma_buf_len = 8 // 8 samples per buffer (minimum) }; // The pin config as per the setup const i2s_pin_config_t pin_config = { .bck_io_num = 26, // Serial Clock (SCK) .ws_io_num = 25, // Word Select (WS) .data_out_num = I2S_PIN_NO_CHANGE, // not used (only for speakers) .data_in_num = 33 // Serial Data (SD) }; // Configuring the I2S driver and pins. // This function must be called before any I2S driver read/write operations. err = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); if (err != ESP_OK) { Serial.printf(«Failed installing driver: %d\n», err); while (true); } err = i2s_set_pin(I2S_PORT, &pin_config); if (err != ESP_OK) { Serial.printf(«Failed setting pin: %d\n», err); while (true); } Serial.println(«I2S driver installed.»); } void loop() { // Read a single sample and log it for the Serial Plotter. int32_t sample = 0; int bytes_read = i2s_pop_sample(I2S_PORT, (char *)&sample, portMAX_DELAY); // no timeout if (bytes_read > 0) { Serial.println(sample); } }

В первой строке мы включаем библиотеку I2S для ESP32 и определяем используемую структуру выводов I2S, потому что только GPIO25 и GPIO26 подключены к внутреннему 8-битному ЦАП, что также показано в распиновке ESP32.

В функции настройки мы устанавливаем скорость передачи 115200, которая должна соответствовать скорости передачи в последовательном плоттере Arduino IDE, где мы отображаем аналоговые звуковые данные.

Если мы получим какую-либо ошибку во время выполнения кода, мы можем получить доступ к ошибке с помощью переменной err.

Следующим шагом в коде Arduino является определение структуры связи I2S. Устанавливаем следующие настройки:

  • установите режим I2S на RX для получения данных I2S
  • используйте частоту дискретизации по умолчанию 16 кГц
  • установите бит на выборку равным 32, а не 16
  • мы используем только правый канал микрофона
  • мы используем 4 буфера, каждый длиной 8

После того, как мы установили структуру связи I2S, мы определяем контакты, которые используются на ESP32 NodeMCU для связи. В моем случае я выбираю:

  • Последовательные часы (SCK) = 26
  • Выбор слова (WS) = 25
  • Последовательные данные (SD) = 33
  • В следующем разделе настраиваются драйвер и контакты I2S. Поскольку эта часть кода глубоко погружается во внутренние функции ESP32, мы пропускаем объяснение этого раздела.

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

На следующем рисунке показан аналоговый выход последовательного монитора, когда я проигрываю музыку со своего компьютера, и микрофон слушает.

Нужен ли мне аудиоинтерфейс?

Ответ на этот вопрос зависит от того, как вы создаете музыку и, в некоторой степени, от того, какую музыку вы создаете. Если, например, вы работаете исключительно в EDM, и все, что вы создаете, основано исключительно на сэмплах и программных инструментах (и вам удобно работать только с миксами для наушников), то стереовыхода встроенной звуковой карты, поставляемой с вашим компьютером, будет вполне достаточно.

Совсем другое дело, если ваши музыкальные приключения связаны с записью звука. Допустим, вы автор-исполнитель и планируете записывать вокал с помощью микрофона или хотите смахнуть пыль со своего старого верного Fender Strat, чтобы отбарабанить рифф, вам понадобится способ перенести звук в компьютер. Если вы хотите записывать оба инструмента одновременно, вам понадобятся два входа для записи отдельных дорожек.

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

Как воспроизводить музыку из внутренней памяти ESP32

Во втором примере мы хотим воспроизводить музыку через динамик. Звуковые данные хранятся в виде массива во внутренней RAM ESP32. Мы используем плату аудиоразъема MAX98357 I2S для преобразования цифрового сигнала в аналоговый. Поэтому мы используем протокол I2S для вывода цифровых звуковых данных без потери качества.

На следующем рисунке показана проводка между ESP32 NodeMCU, коммутационной платой MAX98357 I2S и динамиком.

Для кода Arduino мы используем библиотеку ESP8266Audio от Earle F. Philhower. Чтобы включить эту библиотеку в ваш Arduino, выполните 4 шага:

  1. Загрузите папку github в виде zip-файла
  2. разархивируйте загруженную папку
  3. переименуйте распакованную папку в ESP8266Audio
  4. скопируйте папку в путь к вашей библиотеке IDE Arduino (в моем случае: C:\Users\chris\Documents\Arduino\libraries)

Мы используем следующий код Arduino из примеров библиотеки для воспроизведения музыки из внутренней памяти.

#include «AudioGeneratorAAC.h» #include «AudioOutputI2S.h» #include «AudioFileSourcePROGMEM.h» #include «sampleaac.h» AudioFileSourcePROGMEM *in; AudioGeneratorAAC *aac; AudioOutputI2S *out; void setup() { Serial.begin(115200); in = new AudioFileSourcePROGMEM(sampleaac, sizeof(sampleaac)); aac = new AudioGeneratorAAC(); out = new AudioOutputI2S(); out -> SetGain(0.125); out -> SetPinout(26, 25, 22); aac->begin(in, out); } void loop() { if (aac->isRunning()) { aac->loop(); } else { aac -> stop(); Serial.printf(«Sound Generator\n»); delay(1000); } }

В первых строках мы добавляем следующие заголовочные файлы из библиотеки ESP8266Audio:

  • AudioGeneratorAAC: генератор аудиовыхода с использованием декодера Helix AAC.
  • AudioOutputI2S: базовый класс для интерфейсного порта I2S
  • AudioFileSourcePROGMEM: сохранить «файл» как массив PROGMEM и использовать его как данные источника звука.
  • sampleaac: заголовочный файл, в котором аудиофайл хранится в виде массива

Цифровые звуковые данные хранятся в заголовочном файле sampleaac. Чтобы загрузить код Arduino с файлом заголовка в EPS32, важно, чтобы Arduino (файл .ino) и заголовок (файл .h) находились в одной папке.

После того, как мы включили файлы заголовков библиотеки ESP8266Audio, мы даем для первых трех включенных файлов переменные, содержащие ссылки на классы этих файлов.

В функции настройки мы устанавливаем скорость передачи 115200 бод и инициализируем файлы заголовков. Для AudioFileSourcePROGMEM мы определяем, что образец аудиофайла находится в файле sampleaac с размером содержащего его массива.

Объект AudioOutputI2S имеет разные функции. Мы используем функцию SetGain, чтобы уменьшить громкость динамика, и определяем распиновку с помощью функции SetPinout. В моем случае я выбираю следующую распиновку по умолчанию:

  • Последовательные часы (SCK) = 26
  • Выбор слова (WS) = 25
  • Последовательные данные (SD) = 22

Но не стесняйтесь выбирать другие цифровые выводы микроконтроллера EPS32.

Последним шагом функции настройки является подключение входных звуковых данных из внутренней памяти программы к аудиовыходу I2S с помощью AudioGeneratorAAC.

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

Как воспроизвести файл WAVE на ESP32 с внешней SD-карты

В нашем последнем проекте мы хотим воспроизвести WAVE-файл, который я упомянул в начале этого руководства, через ESP32 NodeMCU и динамик. Поскольку ESP32 должен читать файл WAVE и пересылать цифровой аудиосигнал на MAX98357A, мы должны использовать SD-карту с файлом WAVE на ней. Вы также можете использовать файл MP3 вместо файла WAVE.

На следующем рисунке показано подключение ESP32 NodeMCU к модулю карты (Micro) SD, MAX98357A и динамику. На картинке вы видите, что вам нужно изменить контакт DIN MAX98357A, по сравнению со вторым проектом.

Прежде чем мы погрузимся в код Arduino, мы должны подготовить (Micro) SD-карту. Файловая система должна быть FAT16 или FAT32. В зависимости от модуля SD-карты для SD-карты существует ограничение в 32 ГБ. Я использую карту micro SD объемом 32 ГБ, отформатированную как FAT32, и копирую файл WAVE без папки на SD-карту.

Для этого проекта мы используем библиотеку ESP32-audioI2S Arduino от schreibfaul1. Вы можете скачать библиотеку в виде zip-файла с её страницы на GitHub. Поскольку библиотека имеет имя audio, а в Arduino уже существует библиотека с таким же именем, мы включаем библиотеку через IDE Arduino:

  1. Откройте IDE Arduino.
  2. Перейдите к (см. Следующий рисунок): Скетч → Подключить библиотеку → Добавить .ZIP библиотеку…
  3. Выберите загруженную библиотеку

Скрипт Arduino основан на примере скрипта schreibfaul1, но я сократил скрипт оставив только части, необходимые для воспроизведения файла WAVE, и удалил все части для потоковой передачи WiFi.

#include «Audio.h» #include «SD.h» #include «FS.h» // Digital I/O used #define SD_CS 5 #define SPI_MOSI 23 #define SPI_MISO 19 #define SPI_SCK 18 #define I2S_DOUT 25 #define I2S_BCLK 27 #define I2S_LRC 26 Audio audio; void setup() { pinMode(SD_CS, OUTPUT); digitalWrite(SD_CS, HIGH); SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI); Serial.begin(115200); SD.begin(SD_CS); audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); audio.setVolume(10); // 0…21 audio.connecttoFS(SD, «Ensoniq-ZR-76-01-Dope-77.wav»); } void loop() { audio.loop(); } // optional void audio_info(const char *info) { Serial.print(«info «); Serial.println(info); } void audio_id3data(const char *info) { //id3 metadata Serial.print(«id3data «); Serial.println(info); } void audio_eof_mp3(const char *info) { //end of file Serial.print(«eof_mp3 «); Serial.println(info); } void audio_showstation(const char *info) { Serial.print(«station «); Serial.println(info); } void audio_showstreaminfo(const char *info) { Serial.print(«streaminfo «); Serial.println(info); } void audio_showstreamtitle(const char *info) { Serial.print(«streamtitle «); Serial.println(info); } void audio_bitrate(const char *info) { Serial.print(«bitrate «); Serial.println(info); } void audio_commercial(const char *info) { //duration in sec Serial.print(«commercial «); Serial.println(info); } void audio_icyurl(const char *info) { //homepage Serial.print(«icyurl «); Serial.println(info); } void audio_lasthost(const char *info) { //stream URL played Serial.print(«lasthost «); Serial.println(info); } void audio_eof_speech(const char *info) { Serial.print(«eof_speech «); Serial.println(info); }

В первой части сценария Arduino для ESP32 мы включаем все библиотеки и определяем контакты, которые используются для подключения ESP32 NodeMCU к MAX98357A и модулю SD-карты.

После инициализации объекта Audio с именем «audio» вызывается функция настройки. В функции настройки определяются контакты и SPI-соединение для связи с SD-картой. Скорость передачи установлена 115200, и объект SD-карты также инициализируется.

Для объекта audio устанавливаем распиновку, и уменьшаем громкость звука до 10. Вы можете регулировать громкость звука от 0 до 21. Последняя часть функции настройки — это подключение входов и выходов в этом примере. Поэтому мы связываем аудиообъект с объектом SD-карты и определяем путь к WAVE-файлу. Если вы помещаете звуковой файл в папку, вам необходимо скопировать весь путь к звуковому файлу с косой чертой («/»).

В функции цикла нам нужно только перебрать предварительно сконфигурированный аудио объект для воспроизведения музыки.

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

В первой части этой статьи я вычислил частоту для тактовой частоты последовательного порта 44,1 кГц * 16 * 2 = 1,411 МГц. Теперь я хочу доказать, что частота I2S-соединения (последовательных часов SCK) между ESP32 и MAX98357A составляет 1,411 МГц. Поэтому я подключил линию CLK к своему USB-осциллографу и добавил измерение частоты.

На следующем рисунке видно, что мои расчеты верны и частота составляет 1,411 МГц.

Рейтинг
( 2 оценки, среднее 5 из 5 )
Понравилась статья? Поделиться с друзьями:
Для любых предложений по сайту: [email protected]