USB микрофон на базе STM32F4-DISCOVERY

Ранее я уже писал о выводе звука через USB при помощи платы STM32F4-DISCOVERY. А вот реализация микрофона оказалась сложнее. В Интернете не удалось найти подобных проектов.
Самостоятельно несколько раз пробовал сделать USB-микрофон на этой плате, и вот, наконец, получилось.

Особенности использования микрофона STM32F4-DISCOVERY
На плате установлен цифровой микрофон MP45DT02. Он выдает данные в формате PDM. Данные от микрофона к контроллеру передаются через интерфейс I2S, являющийся разновидностью SPI (в данном случае это SPI2). Тактирование микрофона осуществляется через тот же I2S (в данном режиме I2S самостоятельно запрашивает данные от микрофона). Стоит отметить, что I2S использует тактовую частоту от собственного PLL, благодаря чему можно точно получать специфические аудиочастоты дискретизации, однако при этом нет синхронности с работой остальной периферии контроллера (если настроить какой-либо таймер и I2S на формирование одинаковых частот, то прерывания от них будут «плыть» относительно друг друга).

Работа с микрофоном у ST представлена в примере «audio playback and record» в файле «waverecorder.c». Пример достаточно запутанный, работа с I2S идет на прерываниях, так что я значительно переделал исходный файл.
Инициализация I2S идет в функции WaveRecorder_SPI_Init(uint32_t Freq). Данные от микрофона забираются пакетами по 16 бит (сам микрофон не передает числовых данных, он передает именно поток бит). Значение Freq определяет частоту передачи пакетов (тактовая частота будет в 16 раз выше). В документации указано, что тактовая частота микрофона должна быть выше 1 МГц, так что я выбрал частоту пакетов — 64 кГц.
Так как в модуль I2S контроллера рассчитан на работу только со стерео-потоком, а микрофон монофонический, то при настройке I2S внутри данной функции приходится указывать частоту в два раза меньше, чем требуется.

Данные от микрофона невозможно использовать напрямую, нужно проводить их фильтрацию и децимацию. ST в своем примере используют предварительно скомпилированную библиотеку libPDMFilter, которая содержит необходимый фильтр. Как мне показалось, этот фильтр работает не так, как указано в документации (AN3998) к нему, но свой фильтр реализовывать было бы достаточно проблематично.
У себя в проекте я настроил фильтр на выдачу данных на скорости 16 KSPS (используется коэффициент децимации 64). При этом для правильной работы фильтра на данной скорости в него требуется отправить 64 16-битных слова, а в результате он вернет 16 16-битных знаковых значений аудиоданных. Фильтр имеет возможность настраивать коэффициент усиления. Еще одна особенность фильтра — входные данные в него нужно предавать, предварительно поменяв в словах байты местами. Это несколько замедляет процесс фильтрации.

Для того, чтобы накопить 64 слова, я использовал DMA, работающий в режиме двойной буферизации. Запросы на передачу данных DMA создает модуль I2S. После заполнения одного из буферов, DMA формирует прерывание, в обработчике которого вызывается фильтр. Для хранения аудиоданных также выделено два буфера на 16 слов, в которые помещаются сформированные PCM данные.

В этом проекте я реализовал вывод данных с микрофона на имеющийся на плате аудиоЦАП, так что можно прослушивать звук с микрофона, подключив наушники к плате. Аудиоданные передаются на аудиоЦАП через другой модуль I2S, и другой канал DMA. Опять же, так как аудиоЦАП стереофонический, то перед отправкой в него данных с микрофона, каждое слово данных нужно продублировать (это делается в EVAL_AUDIO_TransferComplete_CallBack()).

Замечу, что при максимальном усилении микрофона (по документации максимум — 64, хотя у меня работало и 90) чувствительность микрофона очень велика.

Передача данных по USB
Для работы с USB используется библиотека от ST V2.1.0. В процессе экспериментов я перешел на библиотеку, взятую здесь.
В этой версии закомментированы некоторые участки кода (ищутся по коду "#ifdef original").
Дескрипторы я пробовал брать и по вышеуказанной ссылке, и из весьма полезной статьи lleeloo , и из AN295 от Silicon Labs.

Длительное время мне не удавалось заставить библиотеку работать — устройство виделось системой как микрофон, но не было вызовов Callback от используемой изохронной IN Endpoint, а именно оттуда нужно нужно запускать передачу данных.
В процессе экспериментов у меня вышло, что для того, чтобы USB правильно работал, нужно однократно выполнить передачу аудиоданных из SOF Callback (я делаю это при выборе системой активного интерфейса), после чего начинают генерироваться IN Callback. Но и при передаче данных есть особенность: перед началом каждой передачи нужно выполнять очистку FIFO данной конечной точки:

  DCD_EP_Flush(pdev,AUDIO_IN_EP);
  DCD_EP_Tx (pdev,AUDIO_IN_EP, (uint8_t*)(data), AUDIO_IN_PACKET);

Особых программных сложностей при передаче звука нет — в IN Callback у меня просто вызывается передача данных из того буфера, который был заполнен при последнем вызове фильтра.

Ссылка на проект (для IAR 6.30): github.com/iliasam/STM32F4_USB_MICROPHONE
  • +7
  • 11 ноября 2014, 22:38
  • citizen
  • 1
Файлы в топике: STM32F4_USB_MICROPHONE.zip

Комментарии (25)

RSS свернуть / развернуть
Прицепи проект к посту.
0
  • avatar
  • Vga
  • 12 ноября 2014, 02:38
Добавил.
0
Аналогичная тема работы со звуком, но передачей по безпроводной вафле и осмысленным приложением результатов
Распознавание речи на STM32F4-Discovery http://habrahabr.ru/post/146501/
Я дивлюсь маленькой коробочкой, управляющей голосом женщинами за рулём… «Поверните налево...., поверните направо...»
Может начать делать что то говорящее и указующее по дому?
«Пошла на кухню...., у тебя молоко убежало...»
0
проект скачал, порт под CooCox не за горами :-)
0
У CooCox есть недостаток — все пути в проекте абсолютные, так что если скопировать проект на другой компьютер, то он не заработает. Так что не вижу особого смысла в выкладывании такого проекта.
0
нормально все переносится, у вас неправильная информация относительно кокоса.
+1
У coocox есть недостаток — непонимание происходящего. Галочки поставил, а что там делается- ХЗ
0
на работе пользуем только как среду (без либ) и проблем подобных нет ;)
0
Выложите пример записанного звука
0
0
Вот 2 варианта PDM_Filter:
* оригинальный на ассемблере и без закладки на проверку процессора (переписан для поддержки hardfloat)
* и FIR-фильтр на С, делающий то-же самое, но с фиксируемым набором коэффициентов
github.com/piratfm/codec2_m4f/tree/master/lib/PDM_filter
+1
Большое спасибо! Скажите, а чем может быть вызвана еле заметная задержка при аудио стриминге?
0
Здравствуйте! Подскажите можно переделать данный проект, чтобы организовать прием через микрофон, подключенный к аудио разъему?
0
Аудио разъем на STM32F4-Discovery предназначен только для вывода звука.
0
Спасибо
0
к дискавери внешний i2s кодек можно прицепить спокойно
0
кстати, обнулять там ничего не надо, это все оттого, что на изохронных конечных точках фильтр четности пакета неотключаемый
надо в прерывании IsoIncomplete отлавливать четность текущего кадра, инвертировать ее (т.к. для микрофона данные изохронной КТ опрашиваются каждый кадр и при Full Speed четность у них чередуется DATA0 DATA1 и т.д.) и в SOF'е при совпадении «нужной» четности и четности текущего кадра данные в конечную точку IN отсылать
Почему в SOF'е? Потому, что при отсылке данных в КТ в ее фильтр четности запишется четность текущего кадра (правильная). Еще фишка в том, что отсылаем данных сколько есть (КТ IN должна быть асинхронная)
+1
Спасибо за комментарий, надо будет попробовать переделать код.
0
Это я полный дуплекс делал в хоббийном проекте своем…
0
Добрый вечер! А если я использую ацп?
Задача состоит в том, чтобы подключить пьезик или микрофон, и прянятый сигнал отправлять на комп, там принимать на Labview и строить спектр
0
Нет никакой разницы, откуда берутся цифровые данные, которые отправляются в конечную точку. Аналогично, настраиваете АЦП, DMA, возможно еще таймер, как источник частоты дискретизации. Будет работать.
0
Почему нельзя использовать обычную звуковую карту (USB/PCI/другую)?
Но если очень нужно, микрофон можно и к АЦП STM32 подключить — we.easyelectronics.ru/AVR/zapis-zvuka.html
0
Препод в универе так требует, я предлагал звуковую карту… требует на STM32, чтобы уже в магистратуре сделать портативное устройство. Спасибо, будем учиться
0
Есть у STM32 один косячок, но я его пока не буду озвучивать, интересно, наткнетесь вы на него или это я тупой.
0
Я энергетик. С мк связался недавно и еще совсем зеленый-тупой :) Надеюсь косячок не застанет врасплох
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.