per-point switching: hardware bring-up, profiles, protocol doc

Verified on the bench that the modified master bitstream excites in every stage
and the RF switch routes: 16 traces per sweep, 62 dB between the two switch
positions of one master port, 9.9k measurements/s. Adds the built master image,
two run profiles, a verification script and librevna_protocol.md, and drops the
stale prototype driver copy that the firmware tree still carried.
This commit is contained in:
Ayzen
2026-09-15 14:41:54 +03:00
parent 3f6cfc9108
commit 62c0266a6b
30 changed files with 1392 additions and 2863 deletions
+87 -9
View File
@@ -12,6 +12,10 @@
когерентности: все 16 комбинаций снимаются в пределах ~0.4 мс на одной частоте
вместо разброса в сотни миллисекунд между развёртками.
Базовое устройство протокола, поверх которого всё это работает (кадр, типы
пакетов, `SweepSettings`, разбор `VNADatapoint`) — в
[librevna_protocol.md](librevna_protocol.md).
## Раскладка стадий
| Стадия | Порт мастера | Ключ | Выход |
@@ -33,8 +37,10 @@
## Контракт по проводу
Хост уже отправляет это (см. `build_sweep_settings_payload`), прошивка должна
считать. Слово стадий в `SweepSettings` (16 бит, смещение 25 в payload):
Хост отправляет это в `build_sweep_settings_payload`, прошивка читает — обе
стороны реализованы. Слово стадий в `SweepSettings` (16 бит, смещение 25 в
payload из 31 байта; раскладку payload целиком см.
[librevna_protocol.md](librevna_protocol.md)):
| Биты | Поле | Значение в этом режиме |
|---|---|---|
@@ -155,6 +161,70 @@ ghdl -a --std=93 Sweep.vhd Test_Sweep.vhd && ghdl -r --std=93 Test_Sweep
VHDL держите в чистом ASCII: GHDL отвергает не-ASCII символы даже в комментариях.
### Проверено на железе 2026-09-11
Мастер прошит `combined_per_point_switching.vnafw`, контроллер врезан в петлю,
ВЧ-ключ **не** подключён. Скрипт
[`per_point_switching_check.py`](../python_app/scripts/per_point_switching_check.py)
снял 8 коллекций по 16 трасс:
```text
выход 0: -71.5 дБ выходы 0 и 1: расхождение 0.5 дБ
выход 1: -72.0 дБ выходы 2 и 3: расхождение 1.3 дБ
выход 2: -70.6 дБ
выход 3: -71.9 дБ
```
Что именно этим доказано:
- **Битстрим в приборе доработанный.** Со стоковым сравнением «стадия равна
порт-стадии» излучали бы только стадии 0 и 2, а выходы 1 и 3 провалились бы в
шум. Здесь все четыре на одном уровне.
- **Петля триггера с контроллером замкнута.** При `syncMode = 3` мастер семплирует
по вернувшемуся триггеру, так что без исправного зеркалирования в STM32 данных
не было бы вовсе.
- **Выходы попарно совпадают**, как и должно быть при отключённом ключе: обе его
позиции — физически один путь.
Считать фронты для этой проверки **бессмысленно**: поле `stages` стоковое, сток
тоже отработает четыре стадии на точку, просто без стимула в 1 и 3.
Межстадийная пауза, измеренная контроллером, — **62 мкс**, ровно `dwell_us = 2`
плюс 60 мкс собственного успокоения PLL прибора. Но распознавание границ точек по
длине паузы работает плохо, коэффициент 1.5 оказался мал — подробности и цифры в
[README контроллера](switch_controller/README.md). На переключение это не влияет.
### Проверено с подключённым ВЧ-ключом, 30–200 МГц
Профиль `run_config_examples/run_config_librevna_multi_per_point_lowband.example.json`:
30–200 МГц, IFBW 50 кГц, 201 точка. Диапазон выбран выше
`HW::BandSwitchFrequency = 25 МГц` — ниже неё прибор уходит на путь Si5351 через
I2C, останавливает развёртку и даёт нерегулярные длинные паузы. Верхняя граница
200 МГц лежит в полосе осциллографа, поэтому стимул видно напрямую.
Медиана `|S21|` по трём повторам, дБ:
| вход | выход 0 (A) | выход 1 (B) | выход 2 (A) | выход 3 (B) |
|---|---|---|---|---|
| 0 | **−5.4** | −77.1 | −69.8 | −78.0 |
| 1 | −69.2 | −68.9 | −69.0 | −69.1 |
| 2 | −77.1 | −77.7 | −76.4 | −77.9 |
| 3 | −73.6 | −73.8 | −72.8 | −73.5 |
Подключён был один тракт — вход 0 в выход 0. Разница между двумя положениями
одного и того же порта мастера (выходы 0 и 1) составила **72 дБ**: в положении A
сигнал идёт в подключённый кабель, в положении B — в открытый порт. Это и есть
прямое доказательство, что ключ переключается по стадиям. Повторяемость
0.0–1.8 дБ, на сигнальном тракте 0.0 дБ.
**Ограничение по IFBW.** При `if_bandwidth_hz = 1000` прибор воспроизводимо
падает: `LIBUSB_ERROR_IO`, затем устройства отваливаются с шины
(`LIBUSB_ERROR_NO_DEVICE`). Ограничения по числу отсчётов тут нет — 800 отсчётов
против предела 8191, — так что причина, вероятно, в возросшей скважности
источника (при 1 кГц он включён 94% времени против 24% при 50 кГц) и, значит, в
среднем токе. IFBW 5, 10, 20 и 50 кГц собираются нормально. **Штатным считать
50 кГц**, ниже 5 кГц не опускаться без проверки питания приборов.
## Прошивка STM32 LibreVNA
Сделано, собирается. Для самих стадий менять было нечего: `stageCnt` уже считается
@@ -198,9 +268,10 @@ STM32 прибора в Hi-Z на обеих линиях (`GPIO_MODE_INPUT`, `N
границе точки. Спад означает «оцифровка закончилась», дальше идёт окно
успокоения следующей стадии (~62 мкс при `dwell_us = 2`), которого ключу
хватает с огромным запасом.
3. **Одна нога на оба ключа.** Нужное положение зависит только от номера стадии,
а не от того, какой порт излучает, поэтому ключи на порту 1 и порту 2 ходят
синхронно.
3. **По ноге на каждый ключ, но ходят они синхронно.** Нужное положение зависит
только от номера стадии, а не от того, какой порт излучает. PB2 управляет
ключом выходного порта 1, PB6 — порта 2; оба вывода на порту B, поэтому
переключаются одной записью в `BSRR`, то есть строго одновременно.
Страховка от сбоя чётности: один потерянный фронт инвертирует чередование
навсегда и молча меняет антенны местами. Контроллер распознаёт границу точки по
@@ -273,11 +344,17 @@ make BINPATH="<путь к arm-none-eabi из CubeIDE>/tools/bin" -j4
### 3. Упаковка .vnafw
Готовый образ уже лежит в репозитории:
`multi_libreVNA_firmware/combined_per_point_switching.vnafw`, хеш в
`reproduce/SHA256SUMS`. Пересобрать:
```bash
cd multi_libreVNA_firmware/reproduce/LibreVNA
cd multi_libreVNA_firmware/reproduce/LibreVNA/Software/VNA_embedded
make BUILD_DIR=build_per_point_switching # НЕ в build/: там эталон
cd ../..
python3 AssembleFirmware.py \
--bitstream FPGA/VNA/top_master_per_point_switching.bin \
--mcu Software/VNA_embedded/build/VNA_embedded.bin \
--mcu Software/VNA_embedded/build_per_point_switching/VNA_embedded.bin \
--output ../combined_per_point_switching.vnafw
```
@@ -300,8 +377,9 @@ GUI сам разложит битстрим и прошивку MCU.
(`stimulus_switch_positions: 1`) работает как раньше — включать переключение.
Порядок проверки на стенде:
1. Осциллографом на PB2 и PB5 контроллера: на одной частоте четыре стадии и два
периода `A B A B`, PB5 молчит.
1. Осциллографом на PB2, PB6 и PB5 контроллера: на одной частоте четыре стадии и
два периода `A B A B`, PB2 и PB6 меняются одновременно и в одну сторону, PB5
молчит.
2. По USB CDC контроллера (развёртку остановить): `parity corrections : 0` и
`stages per point : 4`.
3. Сверить трейсы: выходы 0 и 1 должны совпасть с тем, что даёт старый режим —