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
Аналогичная тема работы со звуком, но передачей по безпроводной вафле и осмысленным приложением результатов
Распознавание речи на STM32F4-Discovery http://habrahabr.ru/post/146501/
Я дивлюсь маленькой коробочкой, управляющей голосом женщинами за рулём… «Поверните налево...., поверните направо...»
Может начать делать что то говорящее и указующее по дому?
«Пошла на кухню...., у тебя молоко убежало...»
Распознавание речи на STM32F4-Discovery http://habrahabr.ru/post/146501/
Я дивлюсь маленькой коробочкой, управляющей голосом женщинами за рулём… «Поверните налево...., поверните направо...»
Может начать делать что то говорящее и указующее по дому?
«Пошла на кухню...., у тебя молоко убежало...»
Вот 2 варианта PDM_Filter:
* оригинальный на ассемблере и без закладки на проверку процессора (переписан для поддержки hardfloat)
* и FIR-фильтр на С, делающий то-же самое, но с фиксируемым набором коэффициентов
github.com/piratfm/codec2_m4f/tree/master/lib/PDM_filter
* оригинальный на ассемблере и без закладки на проверку процессора (переписан для поддержки hardfloat)
* и FIR-фильтр на С, делающий то-же самое, но с фиксируемым набором коэффициентов
github.com/piratfm/codec2_m4f/tree/master/lib/PDM_filter
Здравствуйте! Подскажите можно переделать данный проект, чтобы организовать прием через микрофон, подключенный к аудио разъему?
кстати, обнулять там ничего не надо, это все оттого, что на изохронных конечных точках фильтр четности пакета неотключаемый
надо в прерывании IsoIncomplete отлавливать четность текущего кадра, инвертировать ее (т.к. для микрофона данные изохронной КТ опрашиваются каждый кадр и при Full Speed четность у них чередуется DATA0 DATA1 и т.д.) и в SOF'е при совпадении «нужной» четности и четности текущего кадра данные в конечную точку IN отсылать
Почему в SOF'е? Потому, что при отсылке данных в КТ в ее фильтр четности запишется четность текущего кадра (правильная). Еще фишка в том, что отсылаем данных сколько есть (КТ IN должна быть асинхронная)
надо в прерывании IsoIncomplete отлавливать четность текущего кадра, инвертировать ее (т.к. для микрофона данные изохронной КТ опрашиваются каждый кадр и при Full Speed четность у них чередуется DATA0 DATA1 и т.д.) и в SOF'е при совпадении «нужной» четности и четности текущего кадра данные в конечную точку IN отсылать
Почему в SOF'е? Потому, что при отсылке данных в КТ в ее фильтр четности запишется четность текущего кадра (правильная). Еще фишка в том, что отсылаем данных сколько есть (КТ IN должна быть асинхронная)
Добрый вечер! А если я использую ацп?
Задача состоит в том, чтобы подключить пьезик или микрофон, и прянятый сигнал отправлять на комп, там принимать на Labview и строить спектр
Задача состоит в том, чтобы подключить пьезик или микрофон, и прянятый сигнал отправлять на комп, там принимать на Labview и строить спектр
Почему нельзя использовать обычную звуковую карту (USB/PCI/другую)?
Но если очень нужно, микрофон можно и к АЦП STM32 подключить — we.easyelectronics.ru/AVR/zapis-zvuka.html
Но если очень нужно, микрофон можно и к АЦП STM32 подключить — we.easyelectronics.ru/AVR/zapis-zvuka.html
Комментарии (25)
RSS свернуть / развернуть