Анализатор HandTap
Окно HandTap (вкладка в нижней панели) предназначено для диагностики работы контуров отслеживания микросхемы. В режиме HandTap микровычислитель CPU1 перезагружается специальной программой, которая захватывает данные конвертера HAND1 или HAND2 и передаёт их на ПК для отображения в виде осциллограмм.

Расположение элементов
Окно разделено на три области:
- Верхний график (Values) — отображение многоразрядных числовых сигналов (например, sin, cos, координата, скорость). По горизонтали — номер отсчёта, по вертикали — значение.
- Панель управления — строка с кнопками и настройками (см. ниже).
- Нижний график (Signals) — отображение одноразрядных цифровых сигналов (например,
exi,exi_recovered).
На обоих графиках доступен курсор: клик левой кнопкой устанавливает вертикальную пунктирную линию, на пересечении которой с каждым сигналом отображается кружок и числовое значение. Правый клик убирает курсор.
Органы управления
| Элемент | Назначение |
|---|---|
| ON / OFF | Включение/выключение режима HandTap. Кнопка работает как toggle — при нажатии ON выполняется процедура включения (см. ниже), кнопка меняет текст на OFF. Повторное нажатие выключает режим. |
| H1 / H2 | Переключатель радиокнопок — выбор канала конвертера: HAND1 или HAND2. |
| Addr | Раскрывающийся список (0–7) для выбора адреса блока данных. Каждый пункт показывает номер адреса и список сигналов через запятую (например, «1 - Wca, BScos, ex_shifted, Wsa, BSsin, ex_ref»). Выбранный адрес определяет, какие поля будут декодированы из захваченных отсчётов (см. таблицу «Адреса блоков данных»). По умолчанию — 1 (SinCos). |
| Y | Текстовое поле, диапазон оси Y верхнего графика (± значение). По умолчанию — 2000. |
| Scale | Флажок авто-масштабирования оси Y. При установке диапазон определяется автоматически по амплитуде данных, поле Y становится недоступным. |
| Trig | Флажок режима синхронизации по возбуждению (triggered). При установке захват начинается от отрицательного фронта сигнала EXI (возбуждение). Без флага — захват выполняется немедленно. |
| Threshold | Спиннер (0–99), количество тактов ожидания между отсчётами. Записывается в регистр 763 перед началом цикла чтения. |
| Loading... / Stop | Запуск/остановка циклического чтения данных. При нажатии Loading... начинается непрерывный захват и обновление графиков. Кнопка меняет текст на Stop. |
Включение и выключение режима
Включение (ON)
При нажатии кнопки ON выполняется следующая последовательность:
- Отключение CPU1 и CPU2 — в регистре Mode_config (адрес 71) сбрасываются биты
CPU1_enиCPU2_en. - Настройка разделяемой RAM — в регистре AFE_config (адрес 70) устанавливается
SHRD_RAM = 1,SHRD_CPU2 = 0. - Загрузка программы — в программную память CPU1 (адреса 512–1023) загружается скомпилированная ассемблерная программа
handtap_asm/cpu1_data.hex. - Включение CPU1 — в регистре Mode_config устанавливается бит
CPU1_en.
Выключение (OFF)
При нажатии кнопки OFF:
- В регистре Mode_config сбрасывается бит
CPU1_en— CPU1 останавливается.
При выключении режима HandTap микросхема остаётся с отключённым CPU. Для восстановления штатной работы необходимо перезагрузить микросхему или вручную загрузить рабочие программы CPU.
Процесс захвата данных
После нажатия Loading... выполняется циклический опрос:
- Значение Threshold записывается в регистр 763 микросхемы.
- Из регистра 760 считывается начальное значение счётчика
actionHandValue. - Циклически отправляется команда
READ_HANDTAP(0x0E) на МК (контроллер LED Console) с параметрами:actionHandValue— инкрементируемый счётчик для синхронизации;address— адрес блока данных (биты 2:0), флаг Trig (бит 3), флаг H2 (бит 4).
- МК записывает эти параметры в регистры микросхемы 760–761 и ожидает готовности, опрашивая регистр 748 (флаг готовности CPU1).
- После готовности МК считывает 384 16-битных слова из трёх областей разделяемой RAM:
- 128 слов с адреса 608;
- 128 слов с адреса 768;
- 128 слов с адреса 1280.
- Данные передаются на ПК, где декодируются: пары 14-битных слов объединяются в 28-битные значения, переставляются в хронологическом порядке (итого 128 отсчётов) и разбираются на поля в соответствии с выбранным адресом блока.
Адреса блоков данных
Поле Addr определяет, какие данные считываются из конвертера HAND. Адресация соответствует команде микровычислителя SET_A_HAND (подробнее в разделе CPU):
| Addr | Блок | Поля на графике |
|---|---|---|
| 0 | Coord (Координата) | FullAngle (28 бит) |
| 1 | SinCos (АЦП) | Wca (12 бит, зн.), BScos, ex_shifted, Wsa (12 бит, зн.), BSsin, ex_ref |
| 2 | OutVirtSin | VirtualS (13 бит, зн.), ex_recovered_S, BSsin_V (13 бит, зн.), ex_recovered_90dgr_S |
| 3 | ErrAmpMetric | Amp_metric (12 бит), Err_metric (16 бит, зн.) |
| 4 | Vel (Скорость) | FullVel (28 бит, зн.) |
| 5 | PhiModel | PhiC (14 бит, зн.), PhiS (14 бит, зн.) |
| 6 | OutVirtCos | VirtualC (13 бит, зн.), ex_recovered_C, BScos_V (13 бит, зн.), ex_recovered_90dgr_C |
| 7 | Stat (Статус) | STAT (16 бит) |
Многоразрядные поля (размер > 1 бит) отображаются на верхнем графике Values. Одноразрядные поля — на нижнем графике Signals со смещением +2 по оси Y для визуального разделения.
Режим синхронизации (Trig)
При установленном флаге Trig программа CPU1 перед захватом данных ожидает отрицательный фронт сигнала возбуждения EXI. Это позволяет привязать осциллограмму к определённой фазе сигнала возбуждения и анализировать поведение контура синхронно с ним.
Без флага Trig захват начинается немедленно после получения команды от МК.
Типичное использование
- Подключите микросхему и убедитесь в связи (Test Board → Find IC).
- Откройте вкладку HandTap.
- Нажмите ON — загрузится программа захвата в CPU1.
- Выберите канал H1 или H2.
- В раскрывающемся списке Addr выберите «1 - Wca, BScos, ex_shifted, Wsa, BSsin, ex_ref» для просмотра сигналов Sin/Cos АЦП.
- При необходимости включите Trig для синхронизации от возбуждения.
- Нажмите Loading... — начнётся захват и отображение данных.
- Используйте курсор (клик на графике) для точного отсчёта значений.
- Для просмотра других данных выберите другой адрес в списке Addr: 0 — координата, 4 — скорость, 3 — метрики ошибки и т.д.
- По окончании нажмите Stop, затем OFF для выхода из режима HandTap.
Программа CPU1 режима HandTap
При включении режима HandTap в программную память CPU1 загружается специальная программа из файла handtap_asm/cpu1_data.hex. Программа работает в бесконечном цикле, ожидая команды от МК через SPI и выполняя захват данных конвертера HAND в разделяемую RAM. Исходный текст программы — файл cpu1_com.asm.
Карта памяти CPU1
Программа использует следующее распределение памяти (адреса указаны в 14-битных словах):
| Адреса | Назначение |
|---|---|
| 0–95 | Программная память (код cpu1_com.asm) |
| 96–223 | Буфер захвата TAPBUF_0 (128 слов = 256 байт) — для данных первого блока |
| 224–229 | Зарезервировано / ROM-константы |
| 230 | CONST_50 = 0x50 (80) — смещение второго блока захвата в буфере |
| 231 | CONST_7F = 0x7F (127) — количество отсчётов второго блока |
| 235 | PREV_EX_REF — предыдущее значение бита EXI (для детектирования фронта) |
| 236 | TO_OUT_READY — флаг готовности данных (отображается в регистре IC 748) |
| 237 | BUFFERED_SPI_0 — буфер предыдущего значения SPI_0 (для детектирования новой команды) |
| 248 | SPI_0 — слово 0 данных SPI от МК (счётчик actionHandValue) |
| 249 | SPI_1 — слово 1 данных SPI (адрес + флаги Trig/H2) |
| 251 | SPI_3 / num_wait_samples — слово 3 (число тактов ожидания между отсчётами, регистр IC 763) |
| 252 | HAND1_L — младшие 14 бит данных HAND1 |
| 253 | HAND1_H — старшие 14 бит данных HAND1 |
| 254 | HAND2_L — младшие 14 бит данных HAND2 |
| 255 | HAND2_H — старшие 14 бит данных HAND2 |
Буфер захвата TAPBUF_0 отображается в разделяемую RAM микросхемы и доступен для чтения МК через SPI:
- Первый блок (64 отсчёта × 2 слова = 128 слов) — адреса IC 608–735
- Второй блок (128 отсчётов × 2 слова = 256 слов) — размещается начиная со смещения 80 в буфере, читается как два региона: 768–895 и 1280–1407
Алгоритм работы программы
Программа выполняется в бесконечном цикле. Ниже описан каждый этап:
1. Ожидание команды SPI
WAIT_SPI_START_LOOP:
LOAD SPI_0 R0 // Читаем текущее значение SPI_0
LOAD BUFFERED_SPI_0 R1 // Читаем предыдущее значение
EQUAL WAIT_SPI_START_LOOP R0 R1 // Если совпадают — команда ещё не поступила, ждём
STORE BUFFERED_SPI_0 R0 // Запоминаем новое значение
CPU1 опрашивает регистр SPI_0 (адрес 248), сравнивая его с ранее сохранённым значением. Когда МК записывает через SPI новое значение actionHandValue (регистр IC 760), оно появляется в SPI_0 микровычислителя. Изменение SPI_0 означает поступление новой команды.
2. Декодирование параметров
LOAD SPI_1 R0 // Читаем слово параметров (регистр IC 761)
CONST 7 R2
ANL R2 R0 // R0 = SPI_1 & 0x07 — адрес блока данных (0–7)
HFIX R0 // Устанавливаем адрес чтения HAND
LOAD SPI_1 R0
CONST 16 R2
ANL R2 R0 // R0 = SPI_1 & 0x10 — флаг H2
EQUAL0 HANDLER0_PROC R0 // Если H2=0 → HAND1, иначе → HAND2
JUMP HANDLER1_PROC
Из SPI_1 (регистр IC 761) извлекаются два параметра:
| Бит | Маска | Флаг | Назначение |
|---|---|---|---|
| 2:0 | 0x07 | addr | Адрес блока данных конвертера (команда SET_A_HAND) |
| 4 | 0x10 | H2 | Выбор канала: 0 = HAND1, 1 = HAND2 |
| 3 | 0x08 | Trig | Режим синхронизации (обрабатывается на следующем шаге) |
Команда HFIX загружает адрес в мультиплексор конвертера, определяя, какие данные (координата, sin/cos, скорость и т.д.) будут выдаваться через HAND при каждом вызове WAIT_OWN_HAND.
В зависимости от флага H2 программа переходит к одному из двух идентичных обработчиков — для HAND1 (HANDLER0_PROC) или HAND2 (HANDLER1_PROC).
3. Ожидание синхронизации (режим Trig)
Если в параметрах установлен бит Trig (0x08), программа ожидает отрицательный фронт сигнала возбуждения EXI:
LOAD SPI_1 R0
CONST 8 R2
ANL R0 R2 // Проверяем бит Trig
EQUAL0 EXIT_WAIT_NEG R2 // Trig не установлен — пропускаем ожидание
CONST 1 R0 // Маска бита EXI (бит 0 в HAND1_L)
WAIT_NEG_LOOP:
LOAD32 HAND1_L R1 // Читаем младшее слово HAND1
ANL R0 R1 // Выделяем бит EXI
LOAD PREV_EX_REF R2 // Загружаем предыдущее значение
STORE PREV_EX_REF R1 // Сохраняем текущее значение
SUB R2 R1 // R1 = prev - current
EQUAL EXIT_WAIT_NEG R0 R1 // Если prev=1, current=0 → R1=1 → переход обнаружен
JUMP WAIT_NEG_LOOP
Бит EXI (сигнал возбуждения) передаётся в бите 0 младшего слова данных HAND. Программа запоминает предыдущее значение бита и сравнивает с текущим. Когда предыдущее = 1, а текущее = 0 — обнаружен отрицательный фронт. Это точка, от которой начинается захват данных.
Если флаг Trig не установлен — захват начинается немедленно.
4. Захват первого блока (64 отсчёта)
EXIT_WAIT_NEG:
CONST 0 R0 // Начальный адрес в буфере
CONST 63 R1 // Количество отсчётов − 1 (0..63)
LOOP:
MOVE R0 R3
ADD R1 R3 // R3 = адрес в буфере + текущий индекс
CFIX1 R3 // Преобразуем в адрес записи в разделяемую RAM
LOAD num_wait_samples R4 // Загружаем задержку из SPI_3 (регистр IC 763)
WAIT0_SAMPLES:
WAIT_OWN_HAND // Ожидаем обновление данных от конвертера
DJNZ WAIT0_SAMPLES R4 // Декремент R4, если не 0 — ждём ещё
LOAD32 HAND1_L R3 // Читаем 28-битное значение HAND
CSTORE32 TAPBUF_0 R3 // Записываем 32 бит в буфер (2 × 14 бит)
DJNZ LOOP R1 // Следующий отсчёт
Первый блок захватывает 64 отсчёта (индексы 0–63), записывая их последовательно в буфер TAPBUF_0 начиная с адреса 0. Команда CSTORE32 записывает 32-битное значение как два 14-битных слова (младшее и старшее) в разделяемую RAM.
Между отсчётами программа выполняет num_wait_samples (значение поля Threshold, регистр IC 763) циклов ожидания WAIT_OWN_HAND, задавая временной интервал между точками захвата.
5. Захват второго блока (128 отсчётов)
LOAD CONST_50 R0 // Смещение = 80 (0x50)
LOAD CONST_7F R1 // Количество отсчётов − 1 (0..127)
LOOP2:
MOVE R0 R3
ADD R1 R3 // R3 = 80 + текущий индекс
CFIX1 R3
LOAD num_wait_samples R4
WAIT1_SAMPLES:
WAIT_OWN_HAND
DJNZ WAIT1_SAMPLES R4
LOAD32 HAND1_L R3
CSTORE32 TAPBUF_0 R3
DJNZ LOOP2 R1
Второй блок захватывает 128 отсчётов (индексы 80–207), записывая их в буфер начиная со смещения 80. Общее количество захваченных отсчётов: 64 + 128 = 192 (384 14-битных слова).
Разделение на два блока связано с ограничением адресации команды CFIX1 — адрес должен вычисляться как база + индекс, при этом первый блок размещается с начала буфера (индексы 0–63), а второй — со смещением 80. Между блоками остаётся «пропуск» в 16 слов (адреса 64–79), которые не заполняются.
6. Сигнализация готовности
LOAD BUFFERED_SPI_0 R0 // Загружаем полученный actionHandValue
STORE TO_OUT_READY R0 // Записываем в регистр IC 748 — данные готовы
JUMP WAIT_SPI_START_LOOP // Возвращаемся к ожиданию следующей команды
После завершения захвата программа записывает полученное значение actionHandValue в регистр TO_OUT_READY (отображается как регистр IC 748). МК, периодически опрашивая этот регистр, обнаруживает совпадение с отправленным значением — это сигнал о том, что CPU1 завершил захват и данные в разделяемой RAM готовы для чтения.
Взаимодействие CPU1, МК и ПК — полная диаграмма
┌──────────┐ READ_HANDTAP ┌──────────────┐ SPI write ┌───────────────┐
│ ПК │ ──────────────► │ МК (ESP32) │ ───────────► │ IC (FPGA) │
│ (Java) │ (USB CDC) │ LED Console │ (760-761) │ │
│ │ ◄────────────── │ │ ◄─────────── │ CPU1 │
│ │ 384 слов │ │ poll 748 │ (handtap │
│ │ (USB CDC) │ │ read 608, │ asm prog) │
└──────────┘ └──────────────┘ 768, 1280 └───────────────┘
- ПК отправляет команду
READ_HANDTAP(0x0E) на МК с параметрами:actionHandValue+ адрес/флаги. - МК записывает параметры через SPI в регистры IC 760–761.
- CPU1 (работает программа
cpu1_com.asm) обнаруживает изменениеSPI_0, декодирует параметры, при необходимости ждёт фронт EXI, захватывает 192 отсчёта в разделяемую RAM, записываетactionHandValueв регистр 748. - МК опрашивает регистр 748, обнаруживает совпадение флага готовности, считывает 384 слова (128 × 3 региона) из разделяемой RAM.
- МК отправляет 384 слова на ПК через USB CDC.
- ПК декодирует данные и отображает на графиках HandTap.