# Optical Channel / Gate Driver Tester — ESP32-C3 / ESP32-S3 Полностью рабочий Arduino IDE-проект для строгой проверки оптического цифрового канала. Устройство формирует PWM на выбранной частоте, последовательно уменьшает длительность импульса по заданному списку и проверяет ответ канала: частоту и длительность импульса. Поддерживаются роли `SOLO`, `MASTER` и `SLAVE`; роли выбираются только вручную. ## Что реализовано - неблокирующий конечный автомат без `pulseIn()` и длинных `delay()`; - общие для оптического и драйверного тестов частота PWM и диапазон импульсов; - четыре рабочих режима: `SOLO OPTICAL`, `SOLO DRIVER` (только S3), `MASTER OPTICAL`, `SLAVE OPTICAL`; - настраиваемый для теста драйвера код `HH`, `HL`, `LH`, `LL`; в тесте оптики полярность входного сигнала определяется автоматически; - аппаратные LEDC (C3) и MCPWM (S3) с расчётом реально получившихся частоты и длительности импульса; - Arduino-ESP32 3.3.10: на S3 два аппаратных канала MCPWM Capture из отдельной группы фиксируют RISING и FALLING в независимых регистрах общего 32-битного таймера 80 МГц; - безопасный fallback для старых Arduino-ESP32 3.x через GPIO edge ISR и аппаратный CPU cycle counter (верхний предел при этом автоматически ограничен 100 кГц); - отбрасывание ровно `PWM_SETTLE_CYCLES` полных периодов; - потоковая статистика без хранения всех периодов; - немедленный FAIL по первому отдельному импульсу или периоду вне допуска; - десять измерительных участков на каждой длительности импульса с промежуточным отображением результата; - ESP-NOW discovery, handshake, CRC, session/stage/sequence, ACK, повторы и защита от старых пакетов; - SSD1306 128×32: каждый экран всегда состоит ровно из двух строк; - две кнопки, debounce, long press и repeat; после long press ложный short click не создаётся; - Preferences/NVS с версией структуры, checksum, проверкой индексов и восстановлением defaults; - работа через Serial при отсутствующем OLED; - безопасное выключение PWM при PASS, FAIL, ABORT и потере связи. - полный журнал действий в Serial с временными метками; OLED необязателен. ## Файлы Arduino sketch находится в каталоге `OpticalChannelTester`: - `OpticalChannelTester.ino` — стандартная точка входа Arduino IDE; - `Config.h` — GPIO, тайм-ауты, пределы и все пользовательские массивы; - `Core.*` — последовательность длительностей, ALL, допуски, статистика; - `Buttons.*` — автомат двух кнопок; - `SettingsStore.*` — NVS; - `Display.*` — OLED и компактное форматирование; - `Log.*` — журнал действий и Serial-зеркало интерфейса; - `Pwm.*` — LEDC / MCPWM; - `Receiver.*` — MCPWM Capture на S3 / совместимый GPIO fallback; - `Measurement.*` — строгая проверка периодов; - `Protocol.*`, `Radio.*` — ESP-NOW; - `App.*` — общий конечный автомат SOLO/MASTER/SLAVE. ## Требования Arduino IDE Проверенная конфигурация: - Arduino IDE 2.x; - пакет плат **esp32 by Espressif Systems 3.3.10**; - **Adafruit GFX Library 1.12.1**; - **Adafruit SSD1306 2.5.15**; - Adafruit BusIO устанавливается Library Manager как зависимость. В Arduino IDE откройте `OpticalChannelTester/OpticalChannelTester.ino`. Не переносите один `.ino` отдельно: остальные вкладки являются частью скетча. Для C3 выберите подходящую плату ESP32-C3, например `ESP32C3 Dev Module`. Для S3 — `ESP32S3 Dev Module`. Затем выберите порт и нажмите Verify/Upload. ## GPIO Все назначения находятся в начале `Config.h` и могут быть изменены до сборки. Сейчас в `Config.h` включён `#define MAKETKA`. В этом профиле используются следующие назначения: | Сигнал | ESP32-C3 | ESP32-S3 | |---|---:|---:| | PWM output | GPIO 3 | GPIO 12 | | Optical RX input | GPIO 4 | GPIO 13 | | START | GPIO 1 | GPIO 10 | | MODE | GPIO 0 | GPIO 9 | | OLED SDA | GPIO 6 | GPIO 44 | | OLED SCL | GPIO 7 | GPIO 1 | Если закомментировать `#define MAKETKA`, включается профиль производственной PCB: | Сигнал | ESP32-C3 | ESP32-S3 | |---|---:|---:| | PWM output | GPIO 3 | GPIO 12 | | Optical RX input | GPIO 4 | GPIO 13 | | START | GPIO 10 | GPIO 4 | | MODE | GPIO 20 | GPIO 5 | | VBAT | GPIO 2 | GPIO 11 | | Analog RX | GPIO 0 | GPIO 9 | | OLED SDA | GPIO 6 | GPIO 44 | | OLED SCL | GPIO 7 | GPIO 1 | Оба профиля рассчитаны на установку S3 с совмещением контактов `5V` и `GND` с модулем C3. Номера GPIO S3 выбраны по тому же физическому ряду разъёма, а не по совпадению номера GPIO. На ESP32-C3 PWM формируется через LEDC с аппаратным дробным делителем Q10.8. На ESP32-S3 используется отдельный MCPWM со счётчиком 20 МГц: это позволяет формировать 500 Гц в пределах 16-битного счётчика и сохраняет шаг импульса 50 нс. `TX_LIGHT_ON_GPIO_LEVEL` задаёт постоянное свойство схемы: какой физический уровень `PIN_TX` включает свет. Для приведённой схемы с SN75451 это `HIGH`. Пользовательский код света не изменяет это соответствие. При остановке PWM прошивка выдаёт `TX_LIGHT_OFF_GPIO_LEVEL`. Перед началом точки проверяется, что фактические частота и длительность укладываются в выбранную точность. ### OLED Подключите SSD1306 128×32: `VCC → 3.3 V`, `GND → GND`, `SDA/SCL` по таблице. Адрес по умолчанию `0x3C`. Если OLED не отвечает, тест продолжает работать и пишет диагностику в Serial 115200. ### Работа вообще без OLED OLED можно не подключать. Откройте Serial Monitor на **115200 baud**: каждый экран всегда дублируется одной строкой вида: ```text [ 1250][UI ] MODE: SOLO | START=RUN ``` Полоса прогресса учитывает номер длительности импульса и десять измерительных участков внутри неё. В Serial также выводятся: - каждое распознанное нажатие START/MODE и текущее состояние автомата; - вход, изменение и сохранение каждого пункта меню; - загрузка, проверка и сохранение NVS; - запуск/остановка PWM и реальные параметры LEDC; - начало этапа, число отбрасываемых периодов и параметры измерительного окна; - все действия ESP-NOW, peer, session/stage/sequence, ACK и повторы; - статистика этапа, первый плохой период и итоговая причина завершения; - все строки, которые были бы показаны на OLED. Во время строгого измерительного окна отдельные импульсы намеренно не печатаются: они проверяются потоково, а итоговая статистика выводится после окна. Это предотвращает влияние Serial на точность и переполнение очереди аппаратных фронтов. Журнал действий включён параметрами в `Config.h`: ```cpp constexpr bool SERIAL_ACTION_LOG = true; constexpr bool SERIAL_LOG_TIMESTAMPS = true; ``` ### Кнопки По умолчанию задано: ```cpp #define BUTTON_ACTIVE_LEVEL LOW ``` Поэтому каждая кнопка подключается между своим GPIO и GND, а прошивка автоматически включает `INPUT_PULLUP`. Если установить `BUTTON_ACTIVE_LEVEL HIGH`, подключайте кнопку между GPIO и 3.3 V; автоматически будет использован `INPUT_PULLDOWN`. Других изменений логики не требуется. ## Подключение сигнала ### SOLO ```text ESP GPIO_PWM -> вход передатчика оптического канала выход приёмника оптического канала -> ESP GPIO_RX GND ESP -> GND входной/выходной электроники (если канал не гальванически развязан) ``` ### MASTER / SLAVE ```text MASTER GPIO_PWM -> вход передатчика проверяемого канала выход приёмника проверяемого канала -> SLAVE GPIO_RX MASTER <~~~~ ESP-NOW Wi-Fi channel 6 ~~~~> SLAVE ``` На обеих ESP должны совпадать `ESPNOW_WIFI_CHANNEL` и версия прошивки. Slave сначала переводится в `SLAVE READY` кнопкой START, затем START нажимается на Master. Пока бодрствующий Slave находится в `SLAVE READY`, радиоприём работает периодически: окно 20 мс каждые 100 мс, а собственный оптический передатчик Slave выключен. При переходе Slave в light sleep ESP-NOW и Wi-Fi полностью отключаются, поэтому радиопакет не может его разбудить. Master во время поиска посылает серию `DISCOVER` каждые 20 мс и одновременно переключает реальный свет ON/OFF каждые `OPTICAL_WAKE_HALF_PERIOD_MS`. Изменение уровня на оптическом входе пробуждает Slave через GPIO; после этого Slave запускает ESP-NOW и принимает повторяемый `DISCOVER`. **GPIO ESP32 допускают только логические уровни 0…3.3 В.** Не подавайте 5 В на `GPIO_RX`; применяйте согласование уровня. Полярность выхода оптического приёмника задаётся однозначно его активным уровнем: Физический уровень выхода приёмника при включённом свете задаёт `RX_LIGHT_ON_GPIO_LEVEL`. Код `HH/HL/LH/LL` используется только тестом драйвера. В тесте оптики приёмник сравнивает первые интервалы с ожидаемой длительностью и автоматически выбирает фактически пришедшую полярность; при заполнении 50% выбор стороны не меняет измеренную длительность. ## Управление В ожидании на S3: - MODE short: `SOLO ОПТИКА → SOLO ДРАЙВЕР → MASTER ОПТИКА → SLAVE ОПТИКА`; - MODE long: открыть настройки; - START short: начать тест; - START long во время теста: ABORT, PWM немедленно выключается. В настройках: - MODE short: следующий параметр; - MODE long: проверить диапазон, сохранить один раз в NVS и выйти; - START short: следующее значение; - START long: предыдущее значение, затем autorepeat при удержании. Удержание обеих кнопок минимум 1.5 с при включении восстанавливает defaults. ### Энергосбережение В ожидании процессор работает на 80 МГц, во время теста и связанной MASTER/SLAVE-сессии — на 160 МГц. В тесте оптики активный импульс передатчика всегда соответствует свету ON и не зависит от настройки уровней. В `SOLO ДРАЙВЕР`, Slave, при остановленном PWM и во сне свет всегда принудительно выключен: драйвер не может остаться включённым после теста. После тайм-аута бездействия в `IDLE`, `FINISHED` или `SLAVE READY` OLED выключается, а ESP переходит в непрерывный light sleep без периодических таймерных пробуждений. START и MODE будят устройство. Первое, пробуждающее нажатие не выполняет действие и полностью подавляется до отпускания кнопки; действие выполняет только следующее нажатие. Оптический wake-сигнал также немедленно выводит Slave из энергосбережения. Тайм-аут задаётся `IDLE_POWER_SAVE_TIMEOUT_MS` в `Config.h`. ## Настройки теста Меню содержит шесть общих параметров: 1. частота ШИМ из `PWM_FREQUENCY_OPTIONS_HZ`; 2. максимальная длительность импульса из отдельного `MAX_PULSE_OPTIONS_NS`; 3. минимальная длительность импульса из отдельного `MIN_PULSE_OPTIONS_NS`; 4. точность; 5. время выборки. 6. код света `HH`, `HL`, `LH`, `LL` — только для теста драйвера. Экран активного уровня: ```text АКТ. УРОВЕНЬ: HL TX:H, RX:L ``` В тесте драйвера первая буква задаёт активное состояние света TX, вторая — активное состояние света RX. Буквы никогда не обозначают уровни GPIO. Для 1SP0635, у которого управление выполняется светом ON, а ACK передаётся светом OFF, типичен `HL`. В режимах оптики этот пункт показывает `АВТО`, кнопки не изменяют сохранённый код, а входная полярность определяется по принятому PWM. Тест работает на одной выбранной частоте и проходит длительности из списка от максимальной к минимальной. Значения, равные периоду или превышающие его, автоматически исключаются при выборе частоты. На S3 минимальная длительность ограничивается расчётной точностью генератора и MCPWM Capture 80 МГц: длинная пауза не снижает точность короткого импульса. Меню не позволяет задать точку, которой аппаратно не хватает выбранного допуска. Сохранённые индексы и их сочетания проверяются и приводятся к допустимому диапазону. MAX и MIN имеют независимые массивы и независимые индексы. Сам тест проходит отдельный полный список `TEST_PULSE_WIDTHS_NS`. Все пункты меню зациклены: после последнего допустимого значения выбирается первое, а при движении назад перед первым выбирается последнее. `ALL` пересчитывается после изменения частоты, границ импульса или времени выборки и отображается с точностью до целой секунды. Для каждой точки учитывается: ```text max(TEST_TIME, periods / RX_PROCESSING_PERIODS_PER_SECOND) + PWM_SETTLE_CYCLES / actualFrequency × 10 + OLED_PROGRESS_UPDATE_MS × 11 ``` `TEST TIME` — это чистое время выборки сигнала, а не полная длительность этапа. На высоких частотах полная длительность заметно возрастает из-за проверки каждого периода. Расчёт использует консервативную производительность 300 тысяч периодов в секунду. ## Строгая проверка В тесте оптики после каждой перенастройки PWM приёмник: 1. автоматически определяет фактически пришедшую полярность Rx; отдельные каналы MCPWM Capture S3 фиксируют RISING и FALLING в независимых регистрах общего 32-битного таймера 80 МГц; 2. отбрасывает ровно `PWM_SETTLE_CYCLES` полных периодов; 3. очищает статистику; 4. непрерывно держит MCPWM Capture включённым на всём измерительном этапе, проверяет каждый полный импульс ровно один раз и на десяти границах TEST TIME показывает промежуточный результат; границы прогресса не останавливают capture и не выбрасывают пересекающий их импульс. Между длительностями сначала останавливается PWM, затем capture, поэтому очистка очереди не пересекается с ISR. Каждый полный период и каждый активный импульс проверяются отдельно с выбранным относительным допуском 1%, 2%, 5% или 10%. Поэтому единичное искажение не растворяется в среднем остальных импульсов. После трёх начальных фронтов приёмник работает как простой автомат чередующихся интервалов «импульс — пауза»: тип последующих фронтов не используется, а лишний или потерянный фронт превращается в конкретный `PULSE OUT` или `PERIOD OUT`, не в абстрактный `GLITCH`. Для одного измерения допускается только коррекция на один такт приёмного таймера в сторону заданного значения — это неизбежная неопределённость фиксации фронта. Если после неё конкретная частота или длительность остаётся вне допуска, тест немедленно завершается ошибкой. Накопленное среднее используется только для строк `F:..., P:...` и итогового журнала. Переполнение очереди фронтов немедленно даёт `DATA LOSS ERROR`. Во время этапа OLED показывает заданную точку и измеренный ответ, например: ```text TEST: 2kHz, 2us F:2.000k, P:2.00u ``` При ошибке сохраняется прежний двухстрочный стиль с конкретным значением, вышедшим за допуск: ```text СБОЙ: 2kHz, 200us ИМПУЛЬС: 300.01u ``` В MASTER/SLAVE передаются выбранная и фактическая длительность импульса и измеренный результат. На принимающей стороне полярность Rx определяется автоматически. Незавершённый период в начале и конце временного участка не учитывается. Общая статистика и отображаемое среднее по всем принятым полным периодам этапа сохраняются, но решение PASS/FAIL принимается по каждому импульсу отдельно. Причины: `NO SIGNAL`, `PERIOD OUT`, `DUTY OUT` (в интерфейсе — ошибка длительности импульса), `EXTRA EDGE`, `GLITCH`, `LOST EDGE`, `DATA LOSS ERROR`, `LINK LOST`, `UNSUPPORTED`, `RESOLUTION`, `ABORTED`. ## Тест драйвера — только ESP32-S3 В `SOLO ДРАЙВЕР` используются те же частота, MAX/MIN, точность и время точки. Для драйверного теста минимальная выбираемая длительность входного импульса — 2 мкс. При переключении из оптического режима сохранённое значение меньше 2 мкс автоматически заменяется на 2 мкс. Частота, MAX, MIN и время точки остаются общими настраиваемыми параметрами. Фронты `PIN_RX` и конец каждого импульса `PIN_TX` фиксируются аппаратным MCPWM Capture по общему 80-МГц таймеру с шагом 12,5 нс. Начало TX восстанавливается от аппаратно захваченного конца и фактической длительности, запрограммированной в MCPWM. Период выдаётся анализатору с задержкой в один цикл: следующий захваченный TX гарантирует, что оба 700-нс фронта предыдущего ACK уже находятся в аппаратном буфере. Для каждого фронта TX ожидается активный ответ RX. Паспортные 250 нс до начала ACK и 700 нс его длительности используются как справочные величины, но не как условие PASS/FAIL: задержки тестовой передающей и принимающей оптики могут их сдвигать. Если полный импульс ответа присутствует, ACK считается принятым. Каждый RX сопоставляется с ближайшим предшествующим фронтом TX. Поэтому при пропуске одного ответа ACK следующего фронта не может быть ошибочно приписан пропущенному фронту с задержкой, равной длительности входного импульса плюс D. На OLED в режиме драйвера первая строка показывает параметры текущей точки `ТЕСТ: частота, импульс`, а вторая — измеренную задержку от фронта TX до начала ответа и длительность ответа в формате `D: ..., P: ...`. Отсутствие начала ответа до предела 2 мкс даёт `НЕТ ОТВЕТА ACK`; проверка выполняется сразу для первого пропущенного фронта, без ожидания конца всей выборки. Отдельный импульс статуса драйвера и ответ, остающийся активным дольше 1,5 мкс, считаются `АВАРИЯ ДРАЙВЕРА`. Для каждого проверяемого фронта TX всегда требуется отдельный полный ACK. При включении MCPWM Capture первый TX-импульс может уже идти: его конец будет захвачен, но начало ACK могло произойти раньше включения периферии. Поэтому два первых восстановленных периода используются только для синхронизации и освобождения отложенных событий независимых каналов фронтов. Проверка начинается с третьего периода; при 500 Гц это добавляет 4 мс, а не ожидание общего тайм-аута. Время каждой точки делится на 10 равных подвыборок. Во время подвыборки OLED и Serial не обновляются. После каждой подвыборки захват и PWM останавливаются, на OLED выводятся накопленные `D` и `P` и прогресс, затем та же точка автоматически продолжается. Это исключает потерю короткого RX-фронта из-за I2C-обновления дисплея. После успешного завершения последней точки OLED показывает `ТЕСТ ПРОЙДЕН`, а во второй строке сохраняет итоговые накопленные значения `D` и `P`. При ошибке русская локализация не использует английские фразы `FAIL AT`, `TEST`, `FREQ OUT` или `PULSE OUT`. Первая строка показывает причину по-русски, вторая — `T` (время от вызвавшего аварию фронта TX до начала аварийного RX-импульса), `D` (задержку ошибочного ответа, если она определима) и `P` (длительность ошибочного RX-импульса). Для отсутствующего ACK значение `P` выводится как `---`. Точные значения в наносекундах дополнительно записываются в Serial-журнал. Подключение ESP32-S3 к работающему USB-хосту запрещает переход в light sleep, даже если COM-порт закрыт и обмена Serial нет. Краткие пропадания USB SOF фильтруются в течение 5 секунд. Кабель или зарядник только с питанием, без линий D+/D−, программно определить невозможно без отдельного входа контроля VBUS. Тест идёт от MAX к MIN и останавливается на первой длительности, при которой драйвер перестал отвечать корректно. Это определяет границу распознавания входа, но не доказывает, что напряжение VGE успело полностью открыть IGBT. ### Пределы - C3 и S3: настраиваемый строгий предел до 1 МГц; - выше строгого аппаратного предела выдаётся `UNSUPPORTED`, ослабленной проверки нет; - комбинации, для которых PWM или аппаратный capture не дают выбранную точность, отсекаются ещё в меню; повторная проверка перед стартом остаётся защитой от аппаратного сбоя. Реальный предел зависит от конкретной платы, разводки, формы фронтов, Wi-Fi нагрузки и оптического оборудования. Начинайте проверку с 2 кГц и импульсов 200…2 мкс. ## Первый запуск SOLO 1. Соберите схему SOLO и ещё раз убедитесь, что на `GPIO_RX` не бывает напряжения выше 3.3 В. 2. Откройте Serial Monitor на 115200 baud. 3. Включите плату. На OLED должно быть `MODE: SOLO` / `START=RUN`. 4. Если выбран другой режим, коротко нажимайте MODE до SOLO. 5. Для первого опыта оставьте defaults: 2 кГц, импульсы 200…2 мкс, accuracy 5%. Полярность Rx определяется автоматически. 6. Коротко нажмите START. 7. Serial покажет запрошенные и фактические параметры PWM, список длительностей, ALL и статистику каждой точки. 8. Успех: `ТЕСТ ПРОЙДЕН`. Ошибка: русская причина и строка таймингов. ## Проверка проекта Целевая версия проекта — Arduino-ESP32 3.3.10. В доступной среде исходный код собран Arduino CLI с этой версией: | Target | Arduino-ESP32 | Flash | RAM | Результат | |---|---:|---:|---:|---| | ESP32-C3 | 3.3.10 | 1,045,075 B (79%) | 41,012 B (12%) | PASS | | ESP32-S3 | 3.3.10 | 976,233 B (74%) | 49,812 B (15%) | PASS | Физическое оборудование в этой среде недоступно, поэтому реальные оптические фронты, MCPWM Capture под длительной нагрузкой, дальность ESP-NOW и электрическая совместимость должны быть проверены на ваших платах. Сборка и программные тесты не выдаются за аппаратный тест.