Генерик LED_SRC переключает индикацию между стробами ФНЧ, CIC и PDM. По умолчанию рабочий режим, поведение не меняется.
Цифровой микрофон SPH9855 на Tang Primer 25K
Прошивка принимает поток PDM с микрофона SPH9855LM4H-C, приводит его к 24 бит / 12 500 Гц и отдаёт отсчёты кадрами по UART.
MIC_CLK 3.125 МГц -> CIC sinc^4 /50 -> 62.5 кГц -> ФНЧ /5 -> 12 500 Гц -> кадры по 50 отсчётов -> UART 921600.
Тактирование и частоты
| Параметр | Значение | Обоснование |
|---|---|---|
| Системный клок | 50 МГц (E2) | генератор платы |
| MIC_CLK | 3.125 МГц = 50/16 | Normal mode микрофона 1.1...4.8 МГц |
| CIC | sinc^4, децимация 50 | до 62.5 кГц, без умножителей |
| ФНЧ | 221 отвод, децимация 5 | до 12 500 Гц |
| Выходная ЧД | 12 500 Гц | |
| UART | 921600, 8N1 | 157 байт на кадр, 250 кадров/с, 39.25 кБ/с (43% канала) |
Делитель 16 выбран не произвольно: чтобы обойтись без PLL, частота PDM должна быть 50 МГц / N, а чтобы децимация до 12 500 Гц была целой, N обязан делить 4000. Из подходящих делителей 16 даёт самую высокую частоту в пределах Normal mode, то есть наибольшее передискретизирование (250).
Дециматор
Двухступенчатый, потому что одного CIC мало: его нули стоят на кратных 12.5 кГц, и в рабочей полосе он подавил бы сворачиваемые участки только на ~24 дБ. Поэтому CIC снимает поток до 62.5 кГц, а всю избирательность даёт ФНЧ.
| Показатель | Значение |
|---|---|
| неравномерность полосы 0...5000 Гц | 0.032 дБ |
| подавление от 6250 Гц | 72 дБ |
| подавление сворачиваемых полос | 77 дБ |
Спад CIC в полосе (до 0.36 дБ на краю) не компенсируется отдельным звеном: он задан прямо в желаемой АЧХ при расчёте ФНЧ.
Коэффициенты и разрядности лежат в src/fir_coefs_pkg.vhd, файл генерируется:
py -3 tools/gen_fir_coefs.py
Шкала
Постоянная '1' на выводе данных микрофона даёт полную шкалу 24 бит
(код 8 388 567). Отсюда шкала выхода — dBFS, ровно та, в которой микрофон
специфицирован. Вольт в тракте нет, V_REF в приёмных скриптах не нужен.
Формат кадра UART
| Поле | Байт | Описание |
|---|---|---|
| SYNC | 2 | A5 5A |
| FRAME_CNT | 2 | uint16 BE, инкремент на кадр |
| STATUS | 1 | бит0 — переполнение FIFO, бит1 — насыщение дециматора |
| DATA | 150 | 50 отсчётов x 24 бита, MSB first |
| CRC16 | 2 | CCITT, poly 0x1021, init 0xFFFF, по FRAME_CNT..DATA |
SYNC в CRC не входит: он нужен приёмнику для ресинхронизации до того, как тот начнёт что-либо считать.
Распиновка
| Цепь | Назначение | Пин ПЛИС |
|---|---|---|
| clk_50m | тактовый генератор платы | E2 |
| uart_tx | UART на внешний мост, ПЛИС -> ПК | G5 |
| led0 | светодиод | E8 |
| MIC_CLK | тактирование микрофона, 3.125 МГц | при разводке |
| MIC_DAT | однобитный поток PDM | при разводке |
| MIC_SEL | вывод SELECT микрофона | при разводке |
Выводы микрофона в src/DigMic.cst закомментированы, номера подставляются при
разводке. Банк 3.3 В, питание микрофона 1.65...3.6 В.
MIC_SEL прошивка держит в '0': микрофон выставляет бит по спаду MIC_CLK,
выборка идёт в середине низкой фазы. Если вывод SELECT посажен на питание
платой, поменять SEL_HIGH в Top.vhd на '1' — точка выборки переедет сама.
Сборка
Выводы clk (E2) и LED (E8) на этом корпусе сидят на двойных функциях
(SSPI/CPU и READY), поэтому в свойствах проекта их надо разрешить как обычные
выводы, иначе размещение падает с PR2017. В IDE это флажки CPU, SSPI и READY,
в gw_sh -- set_option -use_cpu_as_gpio 1 -use_sspi_as_gpio 1 -use_ready_as_gpio 1.
Занято на GW5A-25: 778 LUT/ALU (4%), 616 регистров (3%), 5 BSRAM (9%), 1 DSP (4%). Fmax 164 МГц при требуемых 50, нарушений установки и удержания нет.
Состав
| Файл | Назначение |
|---|---|
src/Top.vhd |
верхний уровень: только экземпляры и связи |
src/pdm_rx.vhd |
тактирование микрофона и выборка бита в нужной фазе |
src/cic_decim.vhd |
CIC sinc^4, децимация 50 |
src/fir_decim.vhd |
ФНЧ с децимацией 5, последовательная свёртка |
src/fir_coefs_pkg.vhd |
коэффициенты ФНЧ, генерируется |
src/fifo_top.vhd |
буфер отсчётов, заглушка под IP-ядро Gowin |
src/Packets_creator.vhd |
сборка кадра с CRC-16 |
src/UART.vhd |
передатчик |
src/led_status.vhd |
индикация частотой мигания |
src/DigMic.cst |
привязка выводов |
tb/pdm_mic_model.vhd |
поведенческая модель PDM-микрофона |
tb/tb_top.vhd |
сквозной тест: модель -> ПЛИС -> UART -> разбор кадра |
tools/gen_fir_coefs.py |
расчёт коэффициентов ФНЧ |
tools/uart_capture.py |
приём кадров, запись .raw и .bin |
tools/uart_live.py |
живой просмотр: осциллограмма, спектр, счётчики |
Симуляция (GHDL)
mkdir -p build && ghdl -a --std=08 --workdir=build src/fifo_top.vhd src/UART.vhd src/led_status.vhd src/pdm_rx.vhd src/cic_decim.vhd src/fir_coefs_pkg.vhd src/fir_decim.vhd src/Packets_creator.vhd src/Top.vhd tb/pdm_mic_model.vhd tb/tb_top.vhd && ghdl -e --std=08 --workdir=build -o build/tb_top tb_top && build/tb_top --stop-time=400ms
Модель прогоняет четыре режима. Три из них дают точно вычислимый ответ:
постоянные '1' и '0' — плюс и минус полная шкала, чередование 1010 —
ровно ноль (эта частота попадает в нуль АЧХ CIC). Четвёртый — синус, у него
проверяется размах. Тракт настраивается около 10 мс, поэтому в каждом режиме
кадры читаются до первого сошедшегося.
Запись с железа
py -3 tools/uart_capture.py --list
py -3 tools/uart_capture.py --port COM5 --seconds 10 --out test1
Получаются test1.raw (весь поток как пришёл, для отладки канала),
test1.bin (только отсчёты, читается read_24bit_bin()) и test1.log.
Кадр с несошедшейся CRC отбрасывается, пропуск по FRAME_CNT добивается нулями,
чтобы не сдвинулась ось времени.
Живой просмотр
py -3 tools/uart_live.py --port COM10
Осциллограмма в долях шкалы, спектр в dBFS и счётчики кадров в реальном
времени. Управление кнопками внизу окна, те же действия — клавишами r, a,
d, s, f, выход q.
Запись встроена в просмотр по необходимости: COM-порт держит один процесс, и
запустить uart_capture.py на том же порту параллельно нельзя. Разбор кадров у
обоих инструментов общий (FrameParser в uart_capture.py), так что просмотр
и запись не могут разойтись.