switch controller firmware + per-point switching spec
Прошивка STM32 (WeAct G431CB, тот же тулчейн, что у пульта тележки), которая стоит в разрыве триггерной петли между мастером и первым слейвом и переключает выходной ключ внутри частотной точки. Положение ключа — младший бит номера стадии, а период 2 нацело делит 4 стадии, поэтому чередование не рвётся на границе точки и контроллеру достаточно инвертировать ногу на каждый цикл триггера. Переключение по СПАДУ: спад означает «оцифровка закончилась», дальше идёт окно успокоения следующей стадии (~62 мкс при dwell_us=2), которого ключу хватает с запасом, и кольцо удерживать не надо. Один потерянный фронт инвертировал бы чётность навсегда и молча поменял антенны местами, поэтому контроллер распознаёт границу точки по длине паузы (между точками к успокоению добавляется перезагрузка регистров PLL) и принудительно ставит положение A — чётность чинится на каждой точке, а не раз на развёртку. Порог берётся как минимум паузы по скользящему окну с запасом, то есть подстраивается сам; отдельный провод-маркер начала развёртки не нужен. Задержку зеркалирования проверил по Sweep.vhd: мастер стартует оцифровку по своему TRIGGER_IN с конца кольца, то есть тоже после контроллера. Задержка общая для всех приборов и сокращается в отношении «приёмник/опорник» — фазовой ошибки не вносит, только чуть удлиняет развёртку. Собирается: RAM 13.9%, Flash 20.0%. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
# Контроллер выходного ключа
|
||||
|
||||
Прошивка STM32, которая переключает выходной СВЧ-ключ внутри частотной точки —
|
||||
вторая половина режима, описанного в [`../per_point_switching.md`](../per_point_switching.md).
|
||||
Плата и тулчейн те же, что у пульта тележки: WeAct STM32G431CB, PlatformIO.
|
||||
|
||||
## Подключение
|
||||
|
||||
```text
|
||||
мастер TRIGGER_OUT ──► PB0 [STM32] PB1 ──► слейв 1 TRIGGER_IN
|
||||
PB2 ──► управление обоими СВЧ-ключами
|
||||
PB5 ──► отладочный выход
|
||||
```
|
||||
|
||||
Контроллер встаёт **в разрыв** линии между мастером и первым слейвом, остальная
|
||||
часть кольца (слейв 1 → слейв 2 → мастер) не трогается. Это безопасно: в режиме
|
||||
`Mode::Trigger` прошивка LibreVNA уводит собственный STM32 прибора в Hi-Z на обеих
|
||||
триггерных линиях, так что и вход слейва, и выход мастера свободны.
|
||||
|
||||
Одна нога PB2 управляет **обоими** ключами (на порту 1 и на порту 2) — они ходят
|
||||
синхронно, и этого достаточно: нужное положение зависит только от номера стадии,
|
||||
а не от того, какой порт сейчас излучает. Если у ключа больше двух состояний,
|
||||
лишние входы замыкаются джампером.
|
||||
|
||||
Если положению A соответствует лог. 1, а не 0 — поменяйте `kSwitchActiveLow`
|
||||
в [`src/main.cpp`](src/main.cpp).
|
||||
|
||||
## Как это работает
|
||||
|
||||
Прибор измеряет каждую частоту в 4 стадии: порт 1 в положениях A и B ключа,
|
||||
затем порт 2 в тех же положениях. Положение ключа — это младший бит номера
|
||||
стадии, а период 2 нацело делит 4 стадии, поэтому нужная последовательность —
|
||||
непрерывное чередование `A B A B A B …`, не прерывающееся на границе точки.
|
||||
Контроллеру достаточно **инвертировать ногу на каждый цикл триггера**;
|
||||
абсолютный счётчик стадий не нужен.
|
||||
|
||||
Переключение делается по **спаду** триггера. Спад означает «оцифровка стадии
|
||||
закончилась»; сразу за ним прибор уходит в состояние успокоения следующей
|
||||
стадии, и это окно (`dwell_us` плюс собственная задержка PLL прибора, ~62 мкс
|
||||
при `dwell_us = 2`) целиком покрывает установление ключа. Переключение по фронту
|
||||
заставило бы удерживать кольцо на время установления и удлинило бы каждую стадию.
|
||||
|
||||
### Восстановление чётности
|
||||
|
||||
Чередование самодостаточно, но один пропущенный или лишний фронт инвертирует
|
||||
чётность навсегда и **молча** меняет антенны местами. Поэтому контроллер
|
||||
дополнительно распознаёт границу точки по длине паузы:
|
||||
|
||||
| Пауза | Длительность | Из чего состоит |
|
||||
|---|---|---|
|
||||
| между стадиями | базовая | только время успокоения |
|
||||
| между точками | базовая + | перезагрузка регистров PLL мастера |
|
||||
| между развёртками | базовая + + | ещё и работа хоста между свипами |
|
||||
|
||||
Пауза длиннее межстадийной означает, что следующий триггер начнёт стадию 0, то
|
||||
есть положение A. Контроллер выставляет A принудительно, независимо от
|
||||
накопленной чётности — то есть чинит рассинхрон на **каждой точке**, а не один
|
||||
раз на развёртку.
|
||||
|
||||
Порог подстраивается сам: межстадийная пауза — это минимальная регулярно
|
||||
повторяющаяся пауза, поэтому за порог берётся минимум по скользящему окну,
|
||||
умноженный на `kBoundaryFactorNum / kBoundaryFactorDen` (по умолчанию 1.5). Пока
|
||||
минимум не набран, восстановление молчит — чередование корректно и без него.
|
||||
|
||||
Множитель намеренно щедрый. Ложное срабатывание **посреди** точки испортит
|
||||
данные, а несрабатывание всего лишь отключит страховку. Если по отчёту видно,
|
||||
что границы не распознаются вообще (`point boundaries` близко к нулю при
|
||||
ненулевом `trigger cycles`), множитель можно снижать — но не ниже реального
|
||||
отношения межточечной паузы к межстадийной, которое видно там же в отчёте.
|
||||
|
||||
### Задержка
|
||||
|
||||
Зеркалирование занимает ~50 нс и на измерения не влияет: мастер стартует
|
||||
оцифровку по своему `TRIGGER_IN`, который приходит с конца кольца, то есть тоже
|
||||
после контроллера. Задержка общая для всех трёх приборов, взаимные сдвиги
|
||||
мастер/слейвы задаются только межFPGA-передачей, и в отношении
|
||||
«приёмник/опорник» она сокращается. Единственный эффект — развёртка длиннее на
|
||||
~2 × задержку × число стадий.
|
||||
|
||||
## Диагностика
|
||||
|
||||
**PB5** — импульс 2 мкс каждый раз, когда чётность пришлось **чинить**. В
|
||||
исправной системе эта нога молчит: предсказание чередованием уже даёт нужное
|
||||
положение на границе точки. Постоянные импульсы означают, что фронты теряются
|
||||
или порог распознавания границы занижен.
|
||||
|
||||
**PB2** — само положение ключа, смотрится осциллографом вместе с триггером: на
|
||||
одной частоте должно быть ровно 4 стадии и два полных периода `A B A B`.
|
||||
|
||||
**USB CDC (115200)** — отчёт печатается один раз, когда на линии триггера
|
||||
тишина дольше 200 мс, то есть когда развёртка остановлена. Во время работы
|
||||
печати нет: `Serial` блокирует зеркалирование, а пропущенные фронты сбили бы
|
||||
чётность. Ключевые строки:
|
||||
|
||||
```text
|
||||
parity corrections : 0 (ok) <- в норме всегда 0
|
||||
stages per point : 4 (ожидается 4), отклонений: 0
|
||||
inter-stage gap, us : 62
|
||||
boundary above, us : 93
|
||||
```
|
||||
|
||||
`stages per point` — самопроверка распознавания границ: если оно верное, между
|
||||
двумя границами всегда ровно 4 стадии. Любое другое число означает, что порог
|
||||
подобран неправильно.
|
||||
|
||||
## Сборка и прошивка
|
||||
|
||||
```bash
|
||||
cd device_firmware/switch_controller
|
||||
pio run # сборка
|
||||
pio run -t upload # прошить через ST-Link
|
||||
pio device monitor # отчёт по USB CDC
|
||||
```
|
||||
Reference in New Issue
Block a user