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:
@@ -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 должны совпасть с тем, что даёт старый режим —
|
||||
|
||||
Reference in New Issue
Block a user