per-point switching: FPGA and LibreVNA MCU changes

FPGA мастера: порт излучает не в одной стадии, а в блоке подряд идущих —
младшие SUBSTAGE_BITS бит счётчика стадий стали положением выходного ключа,
старшие выбирают порт. Вынесено в функцию port_excites в Sweep.vhd, новое поле
приезжает из свободных битов 8:6 регистра SweepSetup через SPIConfig и top.vhd.

Совместимость со стоком строгая: при SUBSTAGE_BITS=0 сдвиг нулевой, а
добавленная проверка "порт-стадия выше последней" ничего не меняет, потому что
счётчик стадий и так пробегает только 0..STAGES. Ручной режим и анализатор
спектра, где STAGES=0, ведут себя ровно как раньше.

MCU: у SetupSweep добавлен параметр substage_bits со значением по умолчанию 0,
поэтому вызовы из Manual.cpp и SpectrumAnalyzer.cpp не тронуты. VNA.cpp берёт
ширину под-стадии из port3Stage — порта 3 у этого железа нет, поле свободно, и
формат пакета не меняется.

Проверено: GHDL анализирует все три VHDL-файла чисто; новый самопроверяющийся
Test_Sweep.vhd прогоняет четыре сценария (сток, два положения, приёмник без
излучения, четыре положения) и проверен мутацией — с возвращённым стоковым
сравнением сценарии с под-стадиями падают. Обе сборки MCU собираются без ошибок.
Битовые позиции сверены сквозь всю цепочку: хост шлёт port3Stage=1 в слове
0x243, MCU пишет регистр 0x7041, FPGA читает SUBSTAGE_BITS=1.

Слейвы перепрошивать не нужно: им шлётся порт-стадия 7, которая со счётчиком
0..3 не совпадает и в стоковом сравнении.

Исходники теперь опережают лежащие рядом бинарники — предупреждение добавлено в
начало reproduce/README.md, хеш README в SHA256SUMS обновлён. Порядок ввода в
строй расписан в per_point_switching.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ayzen
2026-09-09 22:06:23 +03:00
co-authored by Claude Opus 5
parent 0db3dbe295
commit 7d1879ad79
10 changed files with 504 additions and 51 deletions
@@ -3,6 +3,21 @@
Здесь всё, что нужно, чтобы пересобрать прошивки из [`device_firmware/`](../) с нуля.
Проект лежит целиком — не патч, а полное дерево с уже внесёнными доработками.
> **Исходники опережают бинарники.** В дерево внесено переключение стимула
> внутри частотной точки (см. [`../../per_point_switching.md`](../../per_point_switching.md)),
> а лежащие рядом `.vnafw`, `extracted/` и `build*/` — это ПРЕДЫДУЩАЯ прошивка,
> собранная до этой доработки и сейчас залитая в приборы. Поэтому:
>
> * `./build.sh` без аргументов по-прежнему даёт побайтовое совпадение — он
> только переупаковывает готовые `.bin`, не трогая исходники;
> * `./build.sh --stm32` и любая сборка FPGA дадут **другие** бинарники, уже с
> новой логикой — это ожидаемо, а не поломка;
> * исходники, из которых собраны текущие `.vnafw`, лежат в git-коммите
> `d2338ff`.
>
> После сборки и проверки на железе обновите `.vnafw`, `extracted/`, `build*/`
> и `SHA256SUMS`, и этот блок можно будет убрать.
## Что где
```
@@ -70,7 +85,11 @@ tail -c +341737 combined.vnafw | head -c 85004 > VNA_embedded.bin # STM32
## Отличия от апстрима v1.6.5
Всего 12 файлов. Всё остальное дерево совпадает с апстримом байт в байт.
Аппаратный триггер и external-LO slave — 13 файлов (не 12: в списке не значился
`PC_Application/LibreVNA-GUI/Traces/trace.cpp`, правка в GUI, к прошивкам
отношения не имеющая). Переключение стимула внутри точки добавило ещё 5
изменённых файлов и один новый. Всё остальное дерево совпадает с апстримом байт
в байт.
### STM32 — поддержка аппаратного триггера (это и есть съём без USB)
@@ -117,6 +136,39 @@ tail -c +341737 combined.vnafw | head -c 85004 > VNA_embedded.bin # STM32
Новые файлы: `BuildConfig.vhd`, `BuildConfig_external_lo_slave.vhd`,
`VNA_external_lo_slave.xise`; в `VNA.xise` добавлена ссылка на `BuildConfig.vhd`.
### Переключение стимула внутри частотной точки
Внесено позже остального, бинарников рядом ещё нет (см. блок в начале файла).
Полное описание — [`../../per_point_switching.md`](../../per_point_switching.md).
**`FPGA/VNA/Sweep.vhd`** — порт излучает не в одной стадии, а в БЛОКЕ подряд
идущих: младшие `SUBSTAGE_BITS` бит счётчика стадий стали положением выходного
ключа, старшие выбирают порт. Вынесено в функцию `port_excites`. Значение
порт-стадии выше последней никогда не совпадает — так хост глушит излучение
слейвов, посылая им 7.
**`FPGA/VNA/SPIConfig.vhd`**, **`FPGA/VNA/top.vhd`** — новый вход `SUBSTAGE_BITS`
из свободных битов 8:6 регистра `SweepSetup` (адрес 6) и его проброс в `Sweep`.
**`Application/Drivers/FPGA/FPGA.{hpp,cpp}`** — у `SetupSweep` добавлен параметр
`substage_bits` со значением по умолчанию 0, чтобы вызовы из ручного режима и
анализатора спектра не менялись.
**`Application/VNA.cpp`** — ширина под-стадии берётся из `port3Stage`: у этого
железа нет порта 3, поле свободно, и его переиспользование не меняет формат
пакета.
**При `SUBSTAGE_BITS = 0` логика бит в бит совпадает с апстримом** — это
проверено симуляцией.
Новый файл `FPGA/VNA/Test_Sweep.vhd` — самопроверяющийся тестбенч на четыре
сценария (сток, два положения ключа, приёмник без излучения, четыре положения).
В проект ISE не добавлен, на сборку не влияет. Запуск любым VHDL-симулятором:
```bash
ghdl -a --std=93 Sweep.vhd Test_Sweep.vhd && ghdl -r --std=93 Test_Sweep
```
### Прочее
**`AssembleFirmware.py`** — переписан: добавлены `--bitstream`, `--mcu`, `--output`