Optical Channel Tester — ESP32-C3 / ESP32-S3

Полностью рабочий Arduino IDE-проект для строгой проверки оптического цифрового канала. Устройство формирует PWM аппаратным LEDC, пропускает его через проверяемый канал и проверяет каждый завершённый период отдельно: частоту и заполнение. Поддерживаются роли SOLO, MASTER и SLAVE; роли выбираются только вручную.

Что реализовано

  • неблокирующий конечный автомат без pulseIn() и длинных delay();
  • аппаратный LEDC с расчётом реально получившихся частоты, разрядности и duty;
  • Arduino-ESP32 3.3.10: потоковый аппаратный RMT RX (partial RX), ping-pong на C3 и DMA на S3;
  • безопасный 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;
  • Receiver.* — RMT RX / совместимый fallback;
  • Measurement.* — строгая проверка периодов;
  • Protocol.*, Radio.* — ESP-NOW;
  • App.* — общий конечный автомат SOLO/MASTER/SLAVE.

Каталог tests содержит локальные unit-тесты чистой логики и автомата кнопок.

Требования 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 и могут быть изменены до сборки.

Сигнал ESP32-C3 ESP32-S3
PWM output GPIO 3 GPIO 4
Optical RX input GPIO 4 GPIO 5
START GPIO 0 GPIO 6
MODE GPIO 1 GPIO 7
OLED SDA GPIO 6 GPIO 8
OLED SCL GPIO 7 GPIO 9

OLED

Подключите SSD1306 128×32: VCC → 3.3 V, GND → GND, SDA/SCL по таблице. Адрес по умолчанию 0x3C. Если OLED не отвечает, тест продолжает работать и пишет диагностику в Serial 115200.

Работа вообще без OLED

OLED можно не подключать. Откройте Serial Monitor на 115200 baud: каждый экран всегда дублируется одной строкой вида:

[      1250][UI      ] MODE: SOLO | START=RUN

В Serial также выводятся:

  • каждое распознанное нажатие START/MODE и текущее состояние автомата;
  • вход, изменение и сохранение каждого пункта меню;
  • загрузка, проверка и сохранение NVS;
  • запуск/остановка PWM и реальные параметры LEDC;
  • начало этапа, число отбрасываемых периодов и параметры измерительного окна;
  • все действия ESP-NOW, peer, session/stage/sequence, ACK и повторы;
  • статистика этапа, первый плохой период и итоговая причина завершения;
  • все строки, которые были бы показаны на OLED.

Во время строгого измерительного окна отдельные импульсы намеренно не печатаются: они проверяются потоково, а итоговая статистика выводится после окна. Это предотвращает влияние Serial на точность и переполнение очереди RMT. Журнал действий включён параметрами в Config.h:

constexpr bool SERIAL_ACTION_LOG = true;
constexpr bool SERIAL_LOG_TIMESTAMPS = true;

Кнопки

По умолчанию задано:

#define BUTTON_ACTIVE_LEVEL LOW

Поэтому каждая кнопка подключается между своим GPIO и GND, а прошивка автоматически включает INPUT_PULLUP.

Если установить BUTTON_ACTIVE_LEVEL HIGH, подключайте кнопку между GPIO и 3.3 V; автоматически будет использован INPUT_PULLDOWN. Других изменений логики не требуется.

Подключение сигнала

SOLO

ESP GPIO_PWM -> вход передатчика оптического канала
выход приёмника оптического канала -> ESP GPIO_RX
GND ESP -> GND входной/выходной электроники (если канал не гальванически развязан)

MASTER / SLAVE

MASTER GPIO_PWM -> вход передатчика проверяемого канала
выход приёмника проверяемого канала -> SLAVE GPIO_RX
MASTER <~~~~ ESP-NOW Wi-Fi channel 6 ~~~~> SLAVE

На обеих ESP должны совпадать ESPNOW_WIFI_CHANNEL и версия прошивки. Slave сначала переводится в SLAVE READY кнопкой START, затем START нажимается на Master.

GPIO ESP32 допускают только логические уровни 0…3.3 В. Не подавайте 5 В на GPIO_RX; применяйте согласование уровня. Если оптический приёмник инвертирует сигнал, установите:

#define RX_SIGNAL_INVERTED true

Управление

В ожидании:

  • MODE short: SOLO → MASTER → SLAVE → SOLO, выбранная роль сохраняется;
  • MODE long: открыть настройки;
  • START short: начать тест;
  • START long во время теста: ABORT, PWM немедленно выключается.

В настройках:

  • MODE short: следующий параметр;
  • MODE long: проверить диапазон, сохранить один раз в NVS и выйти;
  • START short: следующее значение;
  • START long: предыдущее значение, затем autorepeat при удержании.

Удержание обеих кнопок минимум 1.5 с при включении восстанавливает defaults.

Настройка диапазона

Редактируйте отдельные constexpr-массивы в Config.h. Начальная и конечная частоты намеренно находятся в разных массивах. Сохранённые индексы всегда проверяются; после изменения массивов повреждённая/несовместимая настройка не приводит к выходу за границы.

Последовательность всегда начинается точно с START, идёт с STEP и завершается точно END. Например, 100…1000 с шагом 300 даёт 100, 400, 700, 1000. Конечная точка не дублируется, вычисления выполняются через 64-битные промежуточные значения.

ALL пересчитывается после изменения START, END, STEP, TEST TIME или REPEATS. Частота каждой точки предварительно запрашивается у LEDC с duty=0 (на выходе остаётся безопасный уровень), поэтому в расчёте используется фактически достижимая частота. Для каждой точки учитывается:

PWM_SETTLE_CYCLES / actualFrequency + TEST_TIME * REPEATS

Строгая проверка

После каждой перенастройки PWM приёмник:

  1. отбрасывает ровно PWM_SETTLE_CYCLES полных периодов;
  2. очищает статистику;
  3. непрерывно проверяет все полные периоды всех повторов.

Незавершённый период в начале и конце окна не учитывается. Период, пересекающий границу повторов, не теряется. Для каждого периода отдельно вычисляются частота и duty; средние используются только для диагностики. Любой один выход за допуск немедленно завершает всю проверку.

Причины: NO SIGNAL, PERIOD OUT, DUTY OUT, EXTRA EDGE, GLITCH, LOST EDGE, TOO FEW PERIODS, LINK LOST, UNSUPPORTED, RESOLUTION, ABORTED.

Пределы

  • C3: гарантированный проектный диапазон до 10 кГц; настраиваемый строгий предел по умолчанию 100 кГц;
  • S3: строгий предел до 1 МГц только при рабочем RMT DMA;
  • выше строгого аппаратного предела выдаётся UNSUPPORTED, ослабленной проверки нет;
  • комбинации, для которых LEDC или RX timer не дают выбранную точность, завершаются RESOLUTION до запуска заведомо неверного теста.

Реальный предел зависит от конкретной платы, разводки, формы фронтов, Wi-Fi нагрузки и оптического оборудования. Начинайте проверку с 100 Гц…10 кГц.

Первый запуск SOLO

  1. Соберите схему SOLO и ещё раз убедитесь, что на GPIO_RX не бывает напряжения выше 3.3 В.
  2. Откройте Serial Monitor на 115200 baud.
  3. Включите плату. На OLED должно быть MODE: SOLO / START=RUN.
  4. Если выбран другой режим, коротко нажимайте MODE до SOLO.
  5. Для первого опыта оставьте defaults: 100 Гц…10 кГц, duty 50%, accuracy 5%.
  6. Коротко нажмите START.
  7. Serial покажет запрошенные и фактические параметры LEDC, список частот, ALL и статистику каждой точки.
  8. Успех: PASS ... / START=REPEAT. Ошибка: FAIL AT ... и точная причина.

Проверка проекта

Финальный исходный код собран Arduino CLI, использующим тот же builder, что и Arduino IDE:

Target Arduino-ESP32 Flash RAM Результат
ESP32-C3 3.3.10 1,025,021 B (78%) 45,380 B (13%) PASS
ESP32-S3 3.3.10 950,608 B (72%) 48,620 B (14%) PASS

Локальные unit-тесты: core tests: PASS, button tests: PASS. Они покрывают неделимый диапазон, END без дубля, ALL, границы допусков, немедленный FAIL, resolution, checksum настроек, CRC протокола и отсутствие short после long.

Физическое оборудование в этой среде недоступно, поэтому реальные оптические фронты, RMT DMA под длительной нагрузкой, дальность ESP-NOW и электрическая совместимость должны быть проверены на ваших платах. Сборка и программные тесты не выдаются за аппаратный тест.

Description
Прога на ESP32 для тестирования оптики
Readme 42 MiB
Languages
C++ 86.3%
Pascal 10.1%
C 1.8%
Python 1.8%