# Воспроизведение прошивок LibreVNA Здесь всё, что нужно, чтобы пересобрать прошивки из [`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`, и этот блок можно будет убрать. ## Что где ``` reproduce/ ├── LibreVNA/ полный проект: апстрим v1.6.5 + доработки master/slave │ ├── Software/VNA_embedded/ прошивка STM32G431CBUx (CubeIDE + Makefile) │ │ ├── build/ собранный мастер (VNA_embedded.bin/.elf/.map) │ │ └── build_external_lo_slave/ собранный slave │ ├── FPGA/VNA/ VHDL-проект под Xilinx ISE 14.7 │ │ ├── top_master.bin битстрим мастера ← из combined.vnafw │ │ ├── top_external_lo_slave.bin битстрим slave │ │ └── top.bin СТОКОВЫЙ апстримный, не наш (см. ниже) │ └── AssembleFirmware.py упаковщик .vnafw ├── extracted/ секции, вынутые из готовых .vnafw ├── build.sh пересборка + сверка с эталоном └── SHA256SUMS эталонные хеши (sha256sum -c SHA256SUMS) ``` Из `LibreVNA/` исключены только `.git` (снапшот с одним коммитом `init`, истории правок в нём нет) и `.venv`. ## Железо и версии | | | |---|---| | MCU | STM32G431CBUx, Cortex-M4, 128 КБ флеш / 32 КБ RAM | | Линкер | `STM32G431CBUX_FLASH.ld`, образ с `0x08000000` | | FPGA | Xilinx, битстрим 341 712 Б, проект под ISE 14.7 | | Версия ПО | FW 1.6.5, `HW_REVISION='B'` (задано в Makefile) | | Тулчейн STM32 | STM32CubeIDE 1.17.0, gcc arm-none-eabi **12.3.1** | | Апстрим | github.com/jankae/LibreVNA, тег **v1.6.5** | ## Две сборки Различие мастер/slave — **один флаг**, отдельных веток кода нет. | | STM32 | FPGA | |---|---|---| | мастер | `make` (`EXTERNAL_MASTER_LO_SLAVE=0`) | проект `VNA.xise` → `BuildConfig.vhd` (`false`) | | slave | `make EXTERNAL_MASTER_LO_SLAVE=1` | `VNA_external_lo_slave.xise` → `BuildConfig_external_lo_slave.vhd` (`true`) | Два `.xise` отличаются ровно одной строкой — каким из двух `BuildConfig` подключаться. ## Формат .vnafw Заголовок 24 байта, little-endian (см. `AssembleFirmware.py`): | Смещение | Поле | |---|---| | 0x00 | магия `VNA!` | | 0x04 | смещение FPGA-битстрима (всегда 24) | | 0x08 | размер FPGA-битстрима | | 0x0C | смещение прошивки MCU (= 24 + размер FPGA) | | 0x10 | размер прошивки MCU | | 0x14 | CRC32 по (битстрим + прошивка MCU), начальное значение `0xFFFFFFFF` | Дальше подряд битстрим и прошивка MCU, хвост добит нулями до кратности 256. Разложить готовый файл на части: ```bash tail -c +25 combined.vnafw | head -c 341712 > top.bin # FPGA tail -c +341737 combined.vnafw | head -c 85004 > VNA_embedded.bin # STM32 ``` ## Отличия от апстрима v1.6.5 Аппаратный триггер и external-LO slave — 13 файлов (не 12: в списке не значился `PC_Application/LibreVNA-GUI/Traces/trace.cpp`, правка в GUI, к прошивкам отношения не имеющая). Переключение стимула внутри точки добавило ещё 5 изменённых файлов и один новый. Всё остальное дерево совпадает с апстримом байт в байт. ### STM32 — поддержка аппаратного триггера (это и есть съём без USB) **`Application/Trigger.cpp`** (+45/−3) — главное изменение, работает в **обеих** сборках. В апстриме `Trigger::Init()` только вешал EXTI на `FPGA_TRIGGER_OUT`, а `FPGA_TRIGGER_IN` всегда оставался выходом STM (триггер эмулировался по USB). Добавлены `ConfigureInputPin()` / `ConfigureOutputMonitorPin()`, которые в режиме `Mode::Trigger` (`syncMode = 3`) убирают STM с обеих линий: * `FPGA_TRIGGER_IN` → вход без подтяжки: линию гонит внешняя триггер-петля, а не STM; * `FPGA_TRIGGER_OUT` → вход без подтяжки, EXTI снимается: FPGA драйвит линию напрямую на второе устройство. В остальных режимах поведение прежнее. Конфигурация пинов теперь вызывается и из `Trigger::SetMode()`, а не только при инициализации. **`Application/Hardware.cpp`** (+29/−2) — в `HW::SetIdle()` вместо `Trigger::SetInput(false)` теперь `Trigger::SetMode(Trigger::Mode::Off)` (безусловно, обе сборки). Остальное под `#if EXTERNAL_MASTER_LO_SLAVE`: гасится Si5351-канал LO1, LO1 не инициализируется как PLL, статус LO1 всегда «locked», температура LO1 = 0. **`Application/VNA.cpp`** (+33/−6) — вынесены `UpdateLO1ReferenceClock()` / `DisableLO1ReferenceClock()`; в slave-сборке `VNA::Setup()` отклоняет свип, если `syncMode != Trigger` или `syncMaster != 0`. Плюс безусловный багфикс: клампы `points` и `dwell_time` применялись к старому `settings` вместо нового `s`. **`Application/App.cpp`** (+28/−1) — только под `#if EXTERNAL_MASTER_LO_SLAVE`: slave отвечает `Nack` на `ManualControl`, `Generator`, `SpectrumAnalyzerSettings` и на свипы, не проходящие `ExternalLOSlaveSweepSupported()`. Также `SweepSettings` теперь отвечает `Nack`, если `VNA::Setup()` вернул false. **`Application/Hardware.hpp`** (+3) — дефолт `EXTERNAL_MASTER_LO_SLAVE 0`. **`Makefile`** (+2) — `EXTERNAL_MASTER_LO_SLAVE ?= 0` и проброс в `-D`. ### FPGA — глушение LO1 в slave **`FPGA/VNA/top.vhd`** (+14/−8) — подключён `use work.BuildConfig.all`, заведены сигналы `SPI_LO1_CE` / `SPI_LO1_RF_EN`, и под `EXTERNAL_MASTER_LO_SLAVE` глушатся `LO1_RF_EN`, `LO1_CE`, `LO1_CLK`, `LO1_MOSI`, `LO1_LE`; `plls_locked` перестаёт ждать захвата LO, `lo_unlocked` фиксируется в `'0'`. Все правки — под этим флагом. **При `false` логика полностью совпадает с апстримом.** Новые файлы: `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` (в апстриме пути зашиты жёстко). Формат выходного файла не менялся. ## Пересборка ### Только упаковка .vnafw — самое быстрое ```bash cd device_firmware/reproduce ./build.sh ``` Берёт готовые `.bin` из `LibreVNA/` и собирает обе прошивки в `out/`, затем сверяет с эталонами. **Даёт побайтовое совпадение** с `device_firmware/*.vnafw` — проверено. ### STM32 из исходников ```bash ./build.sh --stm32 ``` или вручную: ```bash cd LibreVNA/Software/VNA_embedded BIN='C:/ST/STM32CubeIDE_1.17.0/STM32CubeIDE/plugins/com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.12.3.rel1.win32_1.1.0.202410251130/tools/bin' make BINPATH="$BIN" -j4 # мастер make BINPATH="$BIN" -j4 EXTERNAL_MASTER_LO_SLAVE=1 BUILD_DIR=build_external_lo_slave ``` `BINPATH` обязателен: по умолчанию в Makefile стоит `/usr/bin`, под Windows это не сработает. `make.exe` берите из CubeIDE (`...externaltools.make.win32.../tools/bin`). ### FPGA — только вручную, в Xilinx ISE 14.7 ISE стоит в виртуалке VirtualBox `ISE_14.7_VIRTUAL_MACHINE`; её общая папка — хостовая `C:\shared`, внутри гостя это `/home/ise/shared`. 1. Скопировать `LibreVNA/FPGA` в `C:\shared\LibreVNA\FPGA`. 2. В ISE открыть нужный проект: * мастер — `/home/ise/shared/LibreVNA/FPGA/VNA/VNA.xise` * slave — `.../VNA_external_lo_slave.xise` 3. Process → **Generate Programming File**. 4. Результат — `top.bit` и `top.bin` в каталоге проекта. Оба проекта пишут в один и тот же `top.bin`, поэтому **последняя сборка затирает предыдущую** — забирайте файл сразу и переименовывайте (`top_master.bin` / `top_external_lo_slave.bin`). Именно так и потерялся исходный мастер-битстрим: slave-сборка от 20.04 перезаписала его. ## Что воспроизводится побайтово | | | |---|---| | `.vnafw` из готовых `.bin` | **да** — проверено, обе прошивки совпали с `device_firmware/` | | STM32 из исходников | **да** — проверено, обе сборки (мастер `ba729999…`, slave `56654a03…`) совпали побайтово на тулчейне CubeIDE 1.17.0 / gcc 12.3.1 | | FPGA-битстрим из ISE | **нет** — place & route недетерминирован, плюс timestamp внутри битстрима. Логика идентична, файл будет другой | Поэтому мастер-битстрим сохранён отдельно: `extracted/master_fpga.bin` и `LibreVNA/FPGA/VNA/top_master.bin`. Больше **нигде** на машине его нет — он существовал только внутри `combined.vnafw`. Внимание: `LibreVNA/FPGA/VNA/top.bin` — это **стоковый апстримный** битстрим (тот же, что в официальном релизе v1.6.5), а не наш мастер. Не перепутайте при упаковке. ## Откуда что собрано | `.vnafw` | FPGA-битстрим | STM32 | |---|---|---| | `combined.vnafw` | `top_master.bin` (только из этого файла) | `build/VNA_embedded.bin` | | `combined_external_lo_slave.vnafw` | `top_external_lo_slave.bin` | `build_external_lo_slave/VNA_embedded.bin` | ## Прошивка устройства Штатным LibreVNA-GUI: **Device → Firmware Update**, скармливать `.vnafw` целиком — GUI сам разложит битстрим и прошивку MCU. Отдельный `master_stm32.bin` нужен, только если шить STM напрямую через ST-Link/DFU на `0x08000000`. ## Проверка целостности ```bash cd device_firmware/reproduce sha256sum -c SHA256SUMS ```