Files
digital_microphone/README.md
T
nikit3s df179829bf UART на C3: G5 никуда не подключён
На Dock-плате приёмник встроенного моста BL616 заведён на C3 (IOB56B,
подписан FPGA_UART_TX, контакт 21 гребёнки, банк 4 с фиксированными 3.3 В).
G5 -- это просто контакт 22, он годится только для внешнего моста, посаженного
на гребёнку. Прошивка исправно передавала кадры в неподключённый вывод,
отсюда полное отсутствие байт на ПК при живом тракте.

В README распиновка дополнена номерами контактов гребёнки и заметкой про
VCCIO6/7, которое на этой плате подаётся снаружи.
2026-08-17 18:01:01 +03:00

161 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Цифровой микрофон 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`, файл генерируется:
```bash
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 не входит: он нужен приёмнику для ресинхронизации до того, как тот
начнёт что-либо считать.
## Распиновка
| Цепь | Назначение | Пин ПЛИС | Контакт J1 |
|:--|:--|:--:|:--:|
| clk_50m | тактовый генератор платы, 50 МГц | E2 | — |
| UART_TX | на встроенный мост BL616, ПЛИС -> ПК | **C3** | 21 |
| LED | индикация | E8 | 17 |
| MIC_CLK | тактирование микрофона, 3.125 МГц | J11 | 33 |
| MIC_DAT | однобитный поток PDM | J10 | 35 |
| MIC_SEL | вывод SELECT микрофона | K7 | 34 |
C3 (IOB56B) — это то, что на Dock-плате подписано `FPGA_UART_TX` и заведено на
приёмник моста BL616, банк 4 с фиксированными 3.3 В. Обычный контакт гребёнки
для UART не годится: мост туда не смотрит. Под внешний мост, посаженный прямо
на гребёнку, вывод меняется на нужный контакт.
Микрофон сидит в банке 7, а VCCIO банков 6/7 на этой плате подаётся снаружи
через контакты 29 и 31 гребёнки — без 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)
```bash
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 мс, поэтому в каждом режиме
кадры читаются до первого сошедшегося.
## Запись с железа
```bash
py -3 tools/uart_capture.py --list
```
```bash
py -3 tools/uart_capture.py --port COM5 --seconds 10 --out test1
```
Получаются `test1.raw` (весь поток как пришёл, для отладки канала),
`test1.bin` (только отсчёты, читается `read_24bit_bin()`) и `test1.log`.
Кадр с несошедшейся CRC отбрасывается, пропуск по FRAME_CNT добивается нулями,
чтобы не сдвинулась ось времени.
## Живой просмотр
```bash
py -3 tools/uart_live.py --port COM10
```
Осциллограмма в долях шкалы, спектр в dBFS и счётчики кадров в реальном
времени. Управление кнопками внизу окна, те же действия — клавишами `r`, `a`,
`d`, `s`, `f`, выход `q`.
Запись встроена в просмотр по необходимости: COM-порт держит один процесс, и
запустить `uart_capture.py` на том же порту параллельно нельзя. Разбор кадров у
обоих инструментов общий (`FrameParser` в `uart_capture.py`), так что просмотр
и запись не могут разойтись.