|
|
@@ -0,0 +1,390 @@
|
|
|
+# Red Pitaya: деплой, запуск и работа со спектрометром
|
|
|
+
|
|
|
+Связка из трёх частей:
|
|
|
+
|
|
|
+| Часть | Где работает | Что делает |
|
|
|
+|---|---|---|
|
|
|
+| `spec_server` ([spec_server.c](spec_server.c)) | Red Pitaya (ARM, root) | Отображает регистры ПЛИС по `0x43000000`, слушает TCP-порт **5001**, принимает текстовые команды построчно |
|
|
|
+| `spec_client.py` | ПК | Оболочка / прогон `.spec`-файлов; та же копия лежит в `spectrometer_service/mserv00/bin/` для Django |
|
|
|
+| Django-сервис `mserv00` | ПК | REST API измерения; `RedPitayaEngine` вызывает `spec_client.py --run <файл>` вместо HackRF |
|
|
|
+
|
|
|
+Адрес платы в инструкции — `169.254.156.186` (link-local, плата подключена кабелем напрямую в ПК; Windows сама выдаёт себе адрес из `169.254.0.0/16`, DHCP не нужен). Логин `root`, пароль по умолчанию `root`.
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 1. Прошивка ПЛИС
|
|
|
+
|
|
|
+На плате (по ssh, от root):
|
|
|
+
|
|
|
+```sh
|
|
|
+fpgautil -b system_wrapper3.bit.bin -f Full
|
|
|
+cat /sys/class/fpga_manager/fpga0/state # должно быть: operating
|
|
|
+```
|
|
|
+
|
|
|
+Что важно:
|
|
|
+
|
|
|
+- Нужен именно `.bit.bin` (после bootgen), а не `.bit`.
|
|
|
+- Прошивка **не переживает перезагрузку** платы: после каждого reboot — повторить.
|
|
|
+- Если `spec_server` уже запущен — остановить его (Ctrl+C) **до** перепрошивки, потом запустить снова.
|
|
|
+- Не открывать штатный веб-интерфейс Red Pitaya, пока работаете с сервером: его приложения грузят в ПЛИС свою прошивку.
|
|
|
+
|
|
|
+## 2. Перенос исходников на плату (WinSCP)
|
|
|
+
|
|
|
+WinSCP → New Session:
|
|
|
+
|
|
|
+- File protocol: **SCP** (или SFTP)
|
|
|
+- Host name: `169.254.156.186`, port `22`
|
|
|
+- User name: `root`, password: `root`
|
|
|
+
|
|
|
+Скопировать в `/root/` на плате:
|
|
|
+
|
|
|
+- `rp_apps/spec_server.c`
|
|
|
+- `rp_apps/Makefile`
|
|
|
+- `system_wrapper3.bit.bin` (если ещё не на плате)
|
|
|
+
|
|
|
+## 3. Сборка на плате
|
|
|
+
|
|
|
+```sh
|
|
|
+ssh root@169.254.156.186
|
|
|
+cd /root
|
|
|
+make
|
|
|
+```
|
|
|
+
|
|
|
+## 4. Запуск сервера
|
|
|
+
|
|
|
+```sh
|
|
|
+./spec_server --bind 169.254.156.186
|
|
|
+```
|
|
|
+
|
|
|
+Ожидаемый вывод:
|
|
|
+
|
|
|
+```
|
|
|
+spec_server: /dev/mem 0x43000000 отображён, слушаю 169.254.156.186:5001
|
|
|
+```
|
|
|
+
|
|
|
+Дальше сервер печатает подключения/отключения клиентов. Останов — Ctrl+C. Обслуживается **один клиент за раз** (второй ждёт в очереди `accept`, пока первый не отключится).
|
|
|
+
|
|
|
+Параметры (все необязательны):
|
|
|
+
|
|
|
+| Ключ | По умолчанию | Смысл |
|
|
|
+|---|---|---|
|
|
|
+| `--bind <ip>` | `0.0.0.0` | На каком адресе слушать |
|
|
|
+| `--port <N>` | `5001` | TCP-порт |
|
|
|
+| `--base <адрес>` | `0x43000000` | База регистров в AXI |
|
|
|
+| `--dev <файл>` | `/dev/mem` | Что отображать; обычный файл на 4 КБ даёт «стенд без платы» |
|
|
|
+| `--force` | — | Не проверять состояние `fpga_manager` (опасно) |
|
|
|
+
|
|
|
+Чтобы сервер жил после закрытия ssh-сессии:
|
|
|
+
|
|
|
+```sh
|
|
|
+nohup ./spec_server --bind 169.254.156.186 > spec_server.log 2>&1 &
|
|
|
+```
|
|
|
+
|
|
|
+## 5а. Клиент: интерактивная оболочка
|
|
|
+
|
|
|
+На ПК (Python 3, сторонних пакетов не нужно):
|
|
|
+
|
|
|
+```sh
|
|
|
+cd rp_apps
|
|
|
+python spec_client.py --host 169.254.156.186
|
|
|
+```
|
|
|
+
|
|
|
+```
|
|
|
+OK spec_server, база 0x43000000, help — список команд
|
|
|
+help — команды сервера, ? — команды клиента
|
|
|
+spec> status
|
|
|
+OK status=0x08 busy=0 last_valid=0 buf_valid=0 ready=1 overflow=0 seq_busy=0 seq_len=0
|
|
|
+spec> set freq 2500000
|
|
|
+OK inc=0x051eb852 (2500000.0 Гц)
|
|
|
+spec> pulse 20 2500000 0x0002
|
|
|
+...
|
|
|
+spec> quit
|
|
|
+```
|
|
|
+
|
|
|
+`help` — список команд сервера, `?` — команд клиента, `? set` — справка по конкретной. Всё, что оболочка не знает сама, уходит на сервер как есть. Ответ сервера всегда одна строка: `OK ...` либо `ERR ...`.
|
|
|
+
|
|
|
+Одна команда без входа в оболочку:
|
|
|
+
|
|
|
+```sh
|
|
|
+python spec_client.py --host 169.254.156.186 status
|
|
|
+```
|
|
|
+
|
|
|
+Ключи: `--port` (5001), `--timeout` (5 с).
|
|
|
+
|
|
|
+## 5б. Клиент: прогон файла последовательности
|
|
|
+
|
|
|
+```sh
|
|
|
+python spec_client.py --host 169.254.156.186 --run test_sequence.spec
|
|
|
+```
|
|
|
+
|
|
|
+Файл исполняется построчно; пустые строки и всё после `#` игнорируются. Каждая строка печатается с именем файла, номером и ответом. По умолчанию прогон **останавливается на первой ошибке**; `-k` — продолжать до конца. Код возврата: `0` — без ошибок, `1` — были.
|
|
|
+
|
|
|
+Готовые файлы:
|
|
|
+
|
|
|
+- [test_sequence.spec](test_sequence.spec) — полный проверочный прогон: TTL, РЧ, цепочки с `waitbuf`, три сценария с аппаратным секвенсором, `seqabort`. Должен пройти без единой ошибки.
|
|
|
+- [test_contracts.spec](test_contracts.spec) — намеренно ошибочные команды, проверка отказов. Гонять с `-k`, ненулевой код возврата — норма.
|
|
|
+
|
|
|
+## 5в. Django-сервис с `RedPitayaEngine`
|
|
|
+
|
|
|
+### Запуск сервиса
|
|
|
+
|
|
|
+```bat
|
|
|
+cd spectrometer_service\mserv00
|
|
|
+autorun_default_venv.bat :: первый раз: создаёт mvenv, ставит зависимости
|
|
|
+autorun_default.bat :: далее
|
|
|
+```
|
|
|
+
|
|
|
+Что делают батники: убивают старый `pico-tcp.exe`, активируют venv, `pip install -r requirements.txt`, запускают `bin\pico-tcp.exe` (TCP-сервер Picoscope на порту 5003) и `python manage.py runserver` (порт 8000).
|
|
|
+
|
|
|
+```bat
|
|
|
+python -m venv mvenv
|
|
|
+mvenv\Scripts\activate.bat
|
|
|
+pip install -r requirements.txt
|
|
|
+python manage.py migrate
|
|
|
+python manage.py createsuperuser :: AddDevices.bat ждёт specadmin/specadmin
|
|
|
+AddDevices.bat :: один раз: завести устройства в БД
|
|
|
+start bin\pico-tcp.exe
|
|
|
+python manage.py runserver
|
|
|
+```
|
|
|
+
|
|
|
+Важно: `runserver` должен быть запущен **из активированного venv** и из каталога `mserv00` — движок вызывает `python bin\spec_client.py` через `PATH`, а пути к `.spec`-файлам разрешаются относительно текущего каталога процесса.
|
|
|
+
|
|
|
+### Отличия `RedPitayaEngine` от `DefaultEngine`
|
|
|
+
|
|
|
+Движок выбирается полем `"engine"` в `info` при `POST /api/measure/` ([engine.py:793](../spectrometer_service/mserv00/spectrometer/engine.py#L793)).
|
|
|
+
|
|
|
+| | `DefaultEngine` | `RedPitayaEngine` |
|
|
|
+|---|---|---|
|
|
|
+| Передатчик | HackRF через `bin\hackrftrans00.exe -t <file> -f <freq> -s <srate> -a <ampl> -x <gain>` | Red Pitaya: `python bin\spec_client.py --host 169.254.156.186 --run <file>` |
|
|
|
+| `isdr.file` | `.bin` с IQ-отсчётами | **путь к `.spec`-файлу** (абсолютный или относительно `mserv00`) |
|
|
|
+| `isdr.freq`, `srate`, `ampl`, `gain` | Передаются в HackRF | **Игнорируются** — несущая, амплитуда и т. д. задаются командами `set` внутри `.spec` |
|
|
|
+| Адрес платы | — | Зашит в [engine.py:666-668](../spectrometer_service/mserv00/spectrometer/engine.py#L666-L668) (`rp_sdr(..., ip='169.254.156.186')`); другой адрес — править там |
|
|
|
+| Синхронизатор (Arduino DuePP, `Sync.exe`) | `syncUp` → `syncWait` перед каждым измерением, триггер АЦП от Arduino | **Не используется вовсе**: ни `syncUp`, ни `syncWait`, COM-порт не открывается. Триггер АЦП должен приходить **с TTL-линии Red Pitaya** |
|
|
|
+| Блок `isync` в JSON | Обязателен | Обязателен (сериализатор требует), но содержимое не используется — оставьте как в шаблоне |
|
|
|
+| Порядок в одном измерении | sync → ADC arm → 1 с → HackRF | ADC arm (`adc_interface.start` в отдельном потоке) → **1 с** → прогон `.spec` → ожидание АЦП → запись данных |
|
|
|
+| Усреднение | `iadc.averaging` повторов | То же: `.spec` прогоняется **`averaging` раз целиком**, между повторами пауза `averaging_delay` с |
|
|
|
+| Градиенты (`igrax/y/z`) | одинаково | одинаково |
|
|
|
+
|
|
|
+### Пример запроса
|
|
|
+
|
|
|
+Взять [templates/template_post.json](../spectrometer_service/templates/template_post.json), поменять `engine` и `isdr`:
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "info": {
|
|
|
+ "infostr": "fid_rp",
|
|
|
+ "engine": "RedPitayaEngine",
|
|
|
+ "time": null,
|
|
|
+ "iadc": {
|
|
|
+ "device_model": "PS4000A",
|
|
|
+ "srate": 80000000, "points": [1000],
|
|
|
+ "n_channels": 2, "channel_ranges": [8, 8],
|
|
|
+ "n_triggers": 1, "averaging": 4, "averaging_delay": 1.0,
|
|
|
+ "trigger_channel": 0, "trig_direction": 0, "threshold": 5000,
|
|
|
+ "auto_measure_time": 10000, "enabled": true
|
|
|
+ },
|
|
|
+ "isync": { "device_model": "DuePP", "file": "test.xml", "port": 7 }, # плевать, но что-то должно стоять
|
|
|
+ "isdr": {
|
|
|
+ "device_model": "RP",
|
|
|
+ "srate": 100000, "freq": 100000, "ampl": true, "gain": 35, # плевать, но что-то должно стоять
|
|
|
+ "file": "C:\\Work\\lowfield_mri_programs\\rp_apps\\fid.spec"
|
|
|
+ },
|
|
|
+ "igrax": { "device_model": "GRU", "ip": "127.0.0.1", "file": "test.txt", "enabled": false },
|
|
|
+ "igray": { "device_model": "GRU", "ip": "127.0.0.1", "file": "test.txt", "enabled": false },
|
|
|
+ "igraz": { "device_model": "GRU", "ip": "127.0.0.1", "file": "test.txt", "enabled": false }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+```sh
|
|
|
+curl -u specadmin:specadmin -H "Content-Type: application/json" -d @post.json http://localhost:8000/api/measure/
|
|
|
+# -> {"status":"created","measurement_id":N,...}
|
|
|
+curl -u specadmin:specadmin http://localhost:8000/api/measure/N/state/ # статус
|
|
|
+curl -u specadmin:specadmin http://localhost:8000/api/measure/N/data/ # данные (base64 int16)
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Команды спектрометра
|
|
|
+
|
|
|
+### Модель
|
|
|
+
|
|
|
+Единица работы тракта — **событие**. `start` ставит событие в очередь; когда до него доходит очередь, на `dur` мкс поднимаются TTL-линии из `mask`, и — если это `start rf` — одновременно излучается РЧ-импульс: несущая `freq`, начальная фаза `phase`, форма огибающей `env` (таблица `id` 0..3, амплитуда `scale`), длительность `pulse`. События идут строго друг за другом, без зазоров. Глубина очереди — три события (буфер + слот + идущее).
|
|
|
+
|
|
|
+Параметры задаются `set`-командами **до** `start` и действуют на все последующие события, пока их не поменяют. Сервер держит теневую копию параметров (`params`), поскольку регистры ПЛИС только на запись.
|
|
|
+
|
|
|
+Пауза между импульсами — это тоже событие: `set mask 0x0000`, `set dur <мкс>`, `start ttl`.
|
|
|
+
|
|
|
+### Команды сервера
|
|
|
+
|
|
|
+| Команда | Описание |
|
|
|
+|---|---|
|
|
|
+| `status` | `busy` — событие идёт; `buf_valid` — команда ещё в буфере (параметры не защёлкнуты); `ready` — очередь примет команду; `overflow` — команда отвергнута (липкий!); `seq_busy` — секвенсор играет; `seq_len` — слов загружено |
|
|
|
+| `params` | Теневые параметры живого тракта |
|
|
|
+| `defaults` | Сброс: `dur=1000`, `mask=0`, `freq=2.5 МГц`, `phase=0`, `step=0x400` (≈524 мкс), `env 0 8191` |
|
|
|
+| `set dur <мкс>` | Длительность окна TTL, целое > 0 |
|
|
|
+| `set mask <0..0xFFFF>` | Какие из 16 TTL-линий подняты в окне |
|
|
|
+| `set freq <Гц>` | Несущая РЧ, `0 < f < 62.5e6` (Найквист при 125 МГц) |
|
|
|
+| `set inc <32 бита>` | То же, сырой фазовый инкремент |
|
|
|
+| `set phase <град>` | Начальная фаза несущей (любое число, берётся по модулю 360) |
|
|
|
+| `set pulse <мкс>` | Длительность огибающей; предел ≈ 536 870 мкс |
|
|
|
+| `set step <32 бита>` | То же, сырой шаг Q16.16 по таблице огибающей (0 запрещён — бесконечное излучение) |
|
|
|
+| `set env <id 0..3> <scale 0..16383>` | Форма огибающей и амплитуда. **`scale ≤ 8191`**, выше — переполнение и искажение формы |
|
|
|
+| `start ttl` | Событие только с TTL |
|
|
|
+| `start rf` | Событие с TTL и РЧ. Требование: огибающая не длиннее окна (`pulse ≤ dur`), иначе `ERR` |
|
|
|
+| `seqbegin` | Начать загрузку программы в секвенсор: все дальнейшие `set/start/op/defaults` пишутся в BRAM (до 16384 слов), а не в тракт |
|
|
|
+| `seqend` | Закончить загрузку, вернуться в живой режим |
|
|
|
+| `seqrun [N]` | Проиграть загруженную программу (все слова или первые N) на 125 МГц без участия сети |
|
|
|
+| `seqabort` | Немедленно прекратить выдачу слов (текущее событие доиграет) |
|
|
|
+| `op <код> <параметр>` | Сырая команда без проверок |
|
|
|
+| `peek <смещ.>` / `poke <смещ.> <знач.>` | Прямое чтение/запись регистра (`0x00` OPCODE, `0x04` PARAM, `0x08` STATUS) |
|
|
|
+| `help`, `quit` | |
|
|
|
+
|
|
|
+### Привязка бит маски к пинам
|
|
|
+
|
|
|
+TTL-линии выведены на разъём **E1** платы (STEMlab 125-14 Gen 2): ряд `DIO*_P` и ряд `DIO*_N`. Бит в `set mask` → пин:
|
|
|
+
|
|
|
+| Бит | Пин E1 | | Бит | Пин E1 |
|
|
|
+|---|---|---|---|---|
|
|
|
+| `0x0002` | DIO0_P | | `0x0200` | DIO0_N |
|
|
|
+| `0x0004` | DIO1_P (?) | | `0x0400` | DIO1_N |
|
|
|
+| `0x0004` | DIO2_P (?) | | `0x0800` | DIO2_N |
|
|
|
+| `0x0008` | DIO3_P | | `0x1000` | DIO3_N |
|
|
|
+| `0x0010` | DIO4_P | | `0x2000` | DIO4_N |
|
|
|
+| `0x0020` | DIO5_P | | `0x4000` | DIO5_N |
|
|
|
+| `0x0040` | DIO6_P | | `0x8000` | DIO6_N |
|
|
|
+| `0x0080` | DIO7_P | | ? | DIO7_N (не работает, причина не выяснена) |
|
|
|
+
|
|
|
+Что пока не проверено:
|
|
|
+
|
|
|
+- `DIO1_P` и `DIO2_P` — по текущим наблюдениям оба отзываются на `0x0004`; какой бит на самом деле у каждого — уточнить.
|
|
|
+- `DIO7_N` — не удалось получить сигнал ни на одном бите.
|
|
|
+- Биты `0x0001` и `0x0100` в таблице не заняты.
|
|
|
+
|
|
|
+Примеры: `set mask 0x0002` — только DIO0_P; `set mask 0x0082` — DIO0_P + DIO7_P; `set mask 0xFFFF` — все линии.
|
|
|
+
|
|
|
+### Директивы клиента (работают в оболочке и в `.spec`)
|
|
|
+
|
|
|
+| Директива | Описание |
|
|
|
+|---|---|
|
|
|
+| `echo <текст>` | Напечатать (заголовок раздела в файле) |
|
|
|
+| `wait <мс>` | Пауза на ПК |
|
|
|
+| `waitidle [мс]` | Ждать `busy=0` — все события доиграли (по умолчанию 5000 мс) |
|
|
|
+| `waitbuf [мс]` | Ждать `buf_valid=0` — команда ушла из буфера в тракт, параметры защёлкнуты (1000 мс) |
|
|
|
+| `waitseq [мс]` | Ждать `seq_busy=0` — секвенсор выдал все слова (1000 мс). Не значит, что последнее событие доиграло: после `waitseq` нужен ещё `waitidle` |
|
|
|
+| `run [-k] <файл>` | Выполнить файл вживую (вложенность до 8) |
|
|
|
+| `load <файл>` | Тот же файл, но обернуть в `seqbegin … seqend` — загрузить в секвенсор, не исполняя. Внутри такого файла `wait*` бессмысленны |
|
|
|
+| `pulse <мкс> [Гц] [маска]` | Составная: `set dur` (×1.2), `set pulse`, `set freq`, `set mask`, `start rf` |
|
|
|
+| `connect [хост [порт]]` | Переподключиться |
|
|
|
+
|
|
|
+### Живой режим против секвенсора
|
|
|
+
|
|
|
+**Живой режим** — каждая строка идёт по сети. `mask` и `dur` защёлкиваются только в момент, когда `start` доходит до `ttl_controller`. Если поменять их, пока предыдущий `start` лежит в буфере (`buf_valid=1`), уже поставленное событие уедет с новой маской. Поэтому между звеньями цепочки в живом режиме — **`waitbuf`**, а не `wait`:
|
|
|
+
|
|
|
+```
|
|
|
+set dur 20
|
|
|
+set mask 0xFFFF
|
|
|
+set pulse 10
|
|
|
+start rf
|
|
|
+waitbuf 1000 # дождаться, пока старт защёлкнул mask/dur
|
|
|
+set dur 50
|
|
|
+set mask 0x0000
|
|
|
+start ttl
|
|
|
+waitbuf 1000
|
|
|
+```
|
|
|
+
|
|
|
+**Секвенсор** — вся программа сначала кладётся в BRAM (`seqbegin … seqend`), потом `seqrun` играет её на 125 МГц. Между словами нет сетевого окна, гонка невозможна, `waitbuf` внутри не нужен. Тайминги детерминированы — для реальных последовательностей использовать именно этот режим. Все контракты проверяются при загрузке так же, как вживую (`ERR` на `start rf` с длинной огибающей вылетит на этапе `load`).
|
|
|
+
|
|
|
+`seq_len` в `status` знает только сервер: после его перезапуска счётчик обнуляется, хотя BRAM на плате не тронута — тогда `seqrun N` с явным числом слов.
|
|
|
+
|
|
|
+### Пример:
|
|
|
+
|
|
|
+```
|
|
|
+seqbegin
|
|
|
+defaults
|
|
|
+set freq 2500000 # несущая 2.5 МГц
|
|
|
+set env 0 8191 # огибающая №0, максимальная амплитуда
|
|
|
+
|
|
|
+# 90°: 20 мкс РЧ в окне 30 мкс, ключ ТХ поднят
|
|
|
+set dur 30
|
|
|
+set mask 0x0002
|
|
|
+set phase 0
|
|
|
+set pulse 20
|
|
|
+start rf
|
|
|
+
|
|
|
+# τ = 500 мкс тишины (событие без линий)
|
|
|
+set dur 500
|
|
|
+set mask 0x0000
|
|
|
+start ttl
|
|
|
+
|
|
|
+# 180°: 40 мкс, фаза 90°
|
|
|
+set dur 50
|
|
|
+set mask 0x0002
|
|
|
+set phase 90
|
|
|
+set pulse 40
|
|
|
+start rf
|
|
|
+
|
|
|
+# пауза до эха, затем строб АЦП (линия 0) на время приёма
|
|
|
+set dur 450
|
|
|
+set mask 0x0000
|
|
|
+start ttl
|
|
|
+
|
|
|
+set dur 1000
|
|
|
+set mask 0x0001
|
|
|
+start ttl
|
|
|
+seqend
|
|
|
+
|
|
|
+status # seq_len=22
|
|
|
+seqrun
|
|
|
+waitseq 1000 # секвенсор выдал все слова
|
|
|
+waitidle 5000 # последнее событие (окно приёма) доиграло
|
|
|
+status # busy=0 overflow=0 — успех
|
|
|
+
|
|
|
+defaults
|
|
|
+```
|
|
|
+
|
|
|
+Тот же файл можно разнести: тело программы (без `seqbegin/seqend/seqrun/wait*`) — в `se_prog.spec`, а обёртка:
|
|
|
+
|
|
|
+```
|
|
|
+# se_run.spec
|
|
|
+load se_prog.spec
|
|
|
+seqrun
|
|
|
+waitseq 1000
|
|
|
+waitidle 5000
|
|
|
+status
|
|
|
+```
|
|
|
+
|
|
|
+### Пример: одиночный импульс вживую (FID)
|
|
|
+
|
|
|
+```
|
|
|
+# fid.spec — строб АЦП, затем один РЧ-импульс. Живой режим.
|
|
|
+defaults
|
|
|
+set freq 2500000
|
|
|
+set env 0 8191
|
|
|
+
|
|
|
+set dur 10
|
|
|
+set mask 0x0001 # строб на триггерный вход АЦП
|
|
|
+start ttl
|
|
|
+waitbuf 1000
|
|
|
+
|
|
|
+set dur 30
|
|
|
+set mask 0x0002
|
|
|
+set pulse 20
|
|
|
+start rf
|
|
|
+waitidle 5000
|
|
|
+status
|
|
|
+```
|
|
|
+
|
|
|
+### Типичные `ERR` и что они значат
|
|
|
+
|
|
|
+| Ответ | Причина |
|
|
|
+|---|---|
|
|
|
+| `огибающая … длиннее окна TTL … (контракт 2)` | `pulse > dur` перед `start rf` — увеличить `dur` или укоротить `pulse` |
|
|
|
+| `set step: … нуль = бесконечное излучение (контракт 1)` | `step 0` / слишком длинный `pulse` |
|
|
|
+| `set freq: нужно 0 < f < 62500000 Гц` | Выше Найквиста |
|
|
|
+| `set env: id 0..3, scale 0..16383` | Вне диапазона |
|
|
|
+| `очередь занята (ready=0, buf_valid=1)` | Три события уже в очереди — добавить `waitbuf`/`waitidle` |
|
|
|
+| `команда отвергнута, поднят overflow` | Очередь переполнилась на стороне ПЛИС; флаг липкий — перезагрузить битстрим (п. 1) |
|
|
|
+| `последовательность заполнена (16384 слов)` | Программа не влезает в BRAM |
|
|
|
+| `seqrun: нечего играть (0 слов)` | Не было `seqbegin … seqend` (или сервер перезапущен — задать `seqrun N`) |
|
|
|
+| `fpga_manager в состоянии '…', а не 'operating'` (при старте сервера) | Битстрим не загружен — п. 1 |
|