Перейти к основному содержимому

Анализатор HandTap

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

Окно HandTap

Расположение элементов

Окно разделено на три области:

  • Верхний график (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 выполняется следующая последовательность:

  1. Отключение CPU1 и CPU2 — в регистре Mode_config (адрес 71) сбрасываются биты CPU1_en и CPU2_en.
  2. Настройка разделяемой RAM — в регистре AFE_config (адрес 70) устанавливается SHRD_RAM = 1, SHRD_CPU2 = 0.
  3. Загрузка программы — в программную память CPU1 (адреса 512–1023) загружается скомпилированная ассемблерная программа handtap_asm/cpu1_data.hex.
  4. Включение CPU1 — в регистре Mode_config устанавливается бит CPU1_en.

Выключение (OFF)

При нажатии кнопки OFF:

  1. В регистре Mode_config сбрасывается бит CPU1_en — CPU1 останавливается.
предупреждение

При выключении режима HandTap микросхема остаётся с отключённым CPU. Для восстановления штатной работы необходимо перезагрузить микросхему или вручную загрузить рабочие программы CPU.

Процесс захвата данных

После нажатия Loading... выполняется циклический опрос:

  1. Значение Threshold записывается в регистр 763 микросхемы.
  2. Из регистра 760 считывается начальное значение счётчика actionHandValue.
  3. Циклически отправляется команда READ_HANDTAP (0x0E) на МК (контроллер LED Console) с параметрами:
    • actionHandValue — инкрементируемый счётчик для синхронизации;
    • address — адрес блока данных (биты 2:0), флаг Trig (бит 3), флаг H2 (бит 4).
  4. МК записывает эти параметры в регистры микросхемы 760–761 и ожидает готовности, опрашивая регистр 748 (флаг готовности CPU1).
  5. После готовности МК считывает 384 16-битных слова из трёх областей разделяемой RAM:
    • 128 слов с адреса 608;
    • 128 слов с адреса 768;
    • 128 слов с адреса 1280.
  6. Данные передаются на ПК, где декодируются: пары 14-битных слов объединяются в 28-битные значения, переставляются в хронологическом порядке (итого 128 отсчётов) и разбираются на поля в соответствии с выбранным адресом блока.

Адреса блоков данных

Поле Addr определяет, какие данные считываются из конвертера HAND. Адресация соответствует команде микровычислителя SET_A_HAND (подробнее в разделе CPU):

AddrБлокПоля на графике
0Coord (Координата)FullAngle (28 бит)
1SinCos (АЦП)Wca (12 бит, зн.), BScos, ex_shifted, Wsa (12 бит, зн.), BSsin, ex_ref
2OutVirtSinVirtualS (13 бит, зн.), ex_recovered_S, BSsin_V (13 бит, зн.), ex_recovered_90dgr_S
3ErrAmpMetricAmp_metric (12 бит), Err_metric (16 бит, зн.)
4Vel (Скорость)FullVel (28 бит, зн.)
5PhiModelPhiC (14 бит, зн.), PhiS (14 бит, зн.)
6OutVirtCosVirtualC (13 бит, зн.), ex_recovered_C, BScos_V (13 бит, зн.), ex_recovered_90dgr_C
7Stat (Статус)STAT (16 бит)

Многоразрядные поля (размер > 1 бит) отображаются на верхнем графике Values. Одноразрядные поля — на нижнем графике Signals со смещением +2 по оси Y для визуального разделения.

Режим синхронизации (Trig)

При установленном флаге Trig программа CPU1 перед захватом данных ожидает отрицательный фронт сигнала возбуждения EXI. Это позволяет привязать осциллограмму к определённой фазе сигнала возбуждения и анализировать поведение контура синхронно с ним.

Без флага Trig захват начинается немедленно после получения команды от МК.

Типичное использование

  1. Подключите микросхему и убедитесь в связи (Test Board → Find IC).
  2. Откройте вкладку HandTap.
  3. Нажмите ON — загрузится программа захвата в CPU1.
  4. Выберите канал H1 или H2.
  5. В раскрывающемся списке Addr выберите «1 - Wca, BScos, ex_shifted, Wsa, BSsin, ex_ref» для просмотра сигналов Sin/Cos АЦП.
  6. При необходимости включите Trig для синхронизации от возбуждения.
  7. Нажмите Loading... — начнётся захват и отображение данных.
  8. Используйте курсор (клик на графике) для точного отсчёта значений.
  9. Для просмотра других данных выберите другой адрес в списке Addr: 0 — координата, 4 — скорость, 3 — метрики ошибки и т.д.
  10. По окончании нажмите 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-константы
230CONST_50 = 0x50 (80) — смещение второго блока захвата в буфере
231CONST_7F = 0x7F (127) — количество отсчётов второго блока
235PREV_EX_REF — предыдущее значение бита EXI (для детектирования фронта)
236TO_OUT_READY — флаг готовности данных (отображается в регистре IC 748)
237BUFFERED_SPI_0 — буфер предыдущего значения SPI_0 (для детектирования новой команды)
248SPI_0 — слово 0 данных SPI от МК (счётчик actionHandValue)
249SPI_1 — слово 1 данных SPI (адрес + флаги Trig/H2)
251SPI_3 / num_wait_samples — слово 3 (число тактов ожидания между отсчётами, регистр IC 763)
252HAND1_L — младшие 14 бит данных HAND1
253HAND1_H — старшие 14 бит данных HAND1
254HAND2_L — младшие 14 бит данных HAND2
255HAND2_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:00x07addrАдрес блока данных конвертера (команда SET_A_HAND)
40x10H2Выбор канала: 0 = HAND1, 1 = HAND2
30x08TrigРежим синхронизации (обрабатывается на следующем шаге)

Команда 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 └───────────────┘
  1. ПК отправляет команду READ_HANDTAP (0x0E) на МК с параметрами: actionHandValue + адрес/флаги.
  2. МК записывает параметры через SPI в регистры IC 760–761.
  3. CPU1 (работает программа cpu1_com.asm) обнаруживает изменение SPI_0, декодирует параметры, при необходимости ждёт фронт EXI, захватывает 192 отсчёта в разделяемую RAM, записывает actionHandValue в регистр 748.
  4. МК опрашивает регистр 748, обнаруживает совпадение флага готовности, считывает 384 слова (128 × 3 региона) из разделяемой RAM.
  5. МК отправляет 384 слова на ПК через USB CDC.
  6. ПК декодирует данные и отображает на графиках HandTap.