Files
digital_microphone/README.md
T
nikit3s 668c0564e9 Порядок CIC 3 вместо 4: аккумуляторы шире 18 бит не работают в кристалле
Тракт молча отдавал нули: CIC с 26-битными аккумуляторами в железе не считает,
хотя синтез, трассировка, тайминг и симуляция чистые. Порог найден перебором на
плате с приёмом по UART: 26, 24 и 20 бит мертвы, 18, 16 и 10 работают.

Порядок 3 требует ровно 18 бит вместо 24 и попадает в рабочую область.
Характеристики от этого стали лучше: подавление в задерживании 76 дБ вместо 72,
сворачиваемых полос 92 дБ вместо 77, полоса та же 0.032 дБ. Коэффициенты ФНЧ
пересчитаны под sinc^3, сдвиг выхода уменьшен до 13 -- усиление CIC теперь
50^3, и коэффициенты по-прежнему укладываются в 18 бит.

Сброс по включению убран: он тоже убивает тракт, проверено прошивкой в обе
стороны. Маяк светодиода вынесен в условную генерацию, чтобы его широкий
счётчик не собирался в рабочем режиме.

Проверено на плате: 1481 кадр за 6 с, 74050 отсчётов, CRC без ошибок,
STATUS чистый, на входе живой звук.
2026-08-18 12:06:43 +03:00

180 lines
11 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^3 /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^3, децимация 50 | до 62.5 кГц, без умножителей, аккумуляторы 18 бит |
| ФНЧ | 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 Гц | 76 дБ |
| подавление сворачиваемых полос | 92 дБ |
Спад CIC в полосе не компенсируется отдельным звеном: он задан прямо в желаемой
АЧХ при расчёте ФНЧ, поэтому смена порядка CIC требует только перезапуска
генератора коэффициентов.
Порядок 3, а не 4, выбран не из соображений АЧХ — характеристики с ним даже
лучше — а по ограничению кристалла, см. ниже.
Коэффициенты и разрядности лежат в `src/fir_coefs_pkg.vhd`, файл генерируется:
```bash
py -3 tools/gen_fir_coefs.py
```
## Шкала
Постоянная `'1'` на выводе данных микрофона даёт полную шкалу 24 бит
(код 8 388 596). Отсюда шкала выхода — 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 | на внешний мост, ПЛИС -> ПК | G5 | 22 |
| LED | индикация | E8 | 17 |
| MIC_CLK | тактирование микрофона, 3.125 МГц | J11 | 33 |
| MIC_DAT | однобитный поток PDM | J10 | 35 |
| MIC_SEL | вывод SELECT микрофона | K7 | 34 |
UART идёт на внешний мост, посаженный на гребёнку: встроенный BL616 ограничен
по скорости. Его цепи, если понадобятся, — C3 (`FPGA_UART_TX`, контакт 21) и
B3 (`FPGA_UART_RX`, контакт 19).
Микрофон сидит в банке 7, а VCCIO банков 6/7 на этой плате подаётся снаружи
через контакты 29 и 31 гребёнки — без 3.3 В на них выводы микрофона не работают.
Питание самого микрофона 1.65...3.6 В.
`MIC_SEL` прошивка держит в `'0'`: микрофон выставляет бит по спаду MIC_CLK,
выборка идёт в середине низкой фазы. Если вывод SELECT посажен на питание
платой, поменять `SEL_HIGH` в `Top.vhd` на `'1'` — точка выборки переедет сама.
## Два ограничения кристалла, добытые на железе
Оба проявляются одинаково: синтез и трассировка проходят без замечаний, тайминг
чистый, симуляция верная, а в кристалле тракт молча отдаёт нули.
**Разрядность аккумуляторов CIC не выше 18 бит.** Проверено перебором на плате
с приёмом по UART: 26, 24 и 20 бит — тракт мёртв, 18, 16 и 10 бит — работает.
Отсюда порядок 3: требуется `ORDER*log2(DECIM)+1`, для 3 и 50 это ровно 18, для
4 было бы 24. На аккумулятор ФНЧ (40 бит) ограничение не распространяется — он
проверен на железе и считает верно.
**Сброс по включению ставить нельзя.** Добавление счётчика, держащего `rst_n`
в нуле первые 256 тактов, убивает тракт целиком. С константой `'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: 649 LUT/ALU (3%), 461 регистр (2%), 4 BSRAM (8%), 1 DSP (4%).
Тайминг сходится с запасом, но полагаться на него как на признак исправности
нельзя — см. раздел про ограничения кристалла выше.
## Состав
| Файл | Назначение |
|:--|:--|
| `src/Top.vhd` | верхний уровень: только экземпляры и связи |
| `src/pdm_rx.vhd` | тактирование микрофона и выборка бита в нужной фазе |
| `src/cic_decim.vhd` | CIC sinc^3, децимация 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`), так что просмотр
и запись не могут разойтись.