Files
OptoTest/README.md
Razvalyaev f56595f767 добавлены дефайны для теста разводки оптики
запущено все на s3
скорректированны пины и шим на s3
2026-08-11 21:43:43 +03:00

248 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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` и могут быть изменены до сборки.
Сейчас в `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 с целым делителем. На ESP32-S3 используется отдельный аппаратный MCPWM со счётчиком 40 МГц и произвольным целым периодом.
### 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
```
Полоса прогресса учитывает номер частоты и десять измерительных участков внутри неё. Например, диапазон из 11 частот даёт 110 последовательных позиций прогресса.
В Serial также выводятся:
- каждое распознанное нажатие START/MODE и текущее состояние автомата;
- вход, изменение и сохранение каждого пункта меню;
- загрузка, проверка и сохранение NVS;
- запуск/остановка PWM и реальные параметры LEDC;
- начало этапа, число отбрасываемых периодов и параметры измерительного окна;
- все действия ESP-NOW, peer, session/stage/sequence, ACK и повторы;
- статистика этапа, первый плохой период и итоговая причина завершения;
- все строки, которые были бы показаны на OLED.
Во время строгого измерительного окна отдельные импульсы намеренно не печатаются: они проверяются потоково, а итоговая статистика выводится после окна. Это предотвращает влияние Serial на точность и переполнение очереди RMT. Журнал действий включён параметрами в `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 READY` радиоприём работает периодически: окно 20 мс каждые 100 мс. Master во время поиска посылает серию `DISCOVER` каждые 20 мс. После обнаружения Master Slave автоматически включает непрерывный приём на всю тестовую сессию, а после завершения возвращается к периодическому режиму. Параметры задаются `SLAVE_LISTEN_WINDOW_MS`, `SLAVE_LISTEN_INTERVAL_MS` и `DISCOVERY_RETRY_INTERVAL_MS` в `Config.h`.
**GPIO ESP32 допускают только логические уровни 0…3.3 В.** Не подавайте 5 В на `GPIO_RX`; применяйте согласование уровня. Если оптический приёмник инвертирует сигнал, установите:
```cpp
#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.
### Энергосбережение
В ожидании процессор работает на 80 МГц, во время теста и связанной MASTER/SLAVE-сессии — на 160 МГц. После тайм-аута бездействия в `IDLE`, `MENU`, `FINISHED` или `SLAVE READY` OLED выключается, а ESP переходит в короткие циклы light sleep. Экран и текущее состояние сохраняются. При использовании встроенного USB Serial/JTAG для следующей прошивки может потребоваться ручной вход в загрузчик кнопкой BOOT.
START и MODE будят устройство. Пробуждающее нажатие намеренно не выполняет действие и полностью игнорируется до отпускания кнопки; действие выполняет только следующее нажатие. Принятый `DISCOVER` также немедленно выводит Slave из энергосбережения. Тайм-аут задаётся `IDLE_POWER_SAVE_TIMEOUT_MS` в `Config.h`.
## Настройка диапазона
START и END выбираются из отдельных массивов `START_FREQ_OPTIONS_HZ` и `END_FREQ_OPTIONS_HZ` в `Config.h` и зацикливаются независимо. Полный список точных частот заранее рассчитан для XTAL 40 МГц, целого делителя LEDC и таймера 1…14 бит и записан в `TEST_FREQUENCIES_HZ`. Сохранённые индексы всегда проверяются; после изменения массивов повреждённая/несовместимая настройка не приводит к выходу за границы.
Отдельной настройки STEP нет: тест начинается с выбранной START, проходит все соседние достижимые точки из полного списка и заканчивается на выбранной END.
`ALL` пересчитывается после изменения START, END или TEST TIME и отображается с точностью до целой секунды. Для каждой точки учитывается:
```text
max(TEST_TIME, periods / RX_PROCESSING_PERIODS_PER_SECOND)
+ ожидание заполнения RMT-пакета × 10
+ PWM_SETTLE_CYCLES / actualFrequency × 10
+ OLED_PROGRESS_UPDATE_MS × 11
```
`TEST TIME` — это чистое время выборки сигнала, а не полная длительность этапа. На высоких частотах полная длительность заметно возрастает из-за проверки каждого периода. Расчёт использует консервативную производительность 300 тысяч периодов в секунду, полученную из реального журнала ESP32-C3.
## Строгая проверка
После каждой перенастройки PWM приёмник:
1. выбирает максимальную допустимую частоту RMT 20, 40 или 80 МГц с учётом частоты и duty;
2. отбрасывает ровно `PWM_SETTLE_CYCLES` полных периодов;
3. очищает статистику;
4. проверяет все полные периоды десяти участков TEST TIME и между ними показывает промежуточный результат.
Настройка точности `1%` использует фактический допуск `1,25%`, соответствующий одному такту RMT 80 МГц на частоте сигнала 1 МГц.
Незавершённый период в начале и конце окна не учитывается. Период, пересекающий границу повторов, не теряется. Для каждого периода отдельно вычисляются частота и duty; средние используются только для диагностики. Любой один выход за допуск немедленно завершает всю проверку.
Причины: `NO SIGNAL`, `PERIOD OUT`, `DUTY OUT`, `EXTRA EDGE`, `GLITCH`, `LOST EDGE`, `DATA LOSS ERROR`, `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=AGAIN`. Ошибка: `FAIL AT ...` и точная причина.
## Проверка проекта
Целевая версия проекта — Arduino-ESP32 3.3.10. В доступной среде исходный код дополнительно собран Arduino CLI с установленным Arduino-ESP32 3.3.0:
| Target | Arduino-ESP32 | Flash | RAM | Результат |
|---|---:|---:|---:|---|
| ESP32-C3 | 3.3.0 | 1,049,316 B (80%) | 44,312 B (13%) | PASS |
| ESP32-S3 | 3.3.0 | 980,407 B (74%) | 53,456 B (16%) | PASS |
Локальные unit-тесты: `core tests: PASS`, `button tests: PASS`. Они покрывают неделимый диапазон, END без дубля, ALL, границы допусков, немедленный FAIL, resolution, checksum настроек, CRC протокола и отсутствие short после long.
Физическое оборудование в этой среде недоступно, поэтому реальные оптические фронты, RMT DMA под длительной нагрузкой, дальность ESP-NOW и электрическая совместимость должны быть проверены на ваших платах. Сборка и программные тесты не выдаются за аппаратный тест.