- C 91.4%
- C++ 5.3%
- Python 2.8%
- CMake 0.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
- Tvp5150.hpp: полноценный C++-класс (конструктор-инициализатор, capture, доступ к кадру в PSRAM data/width/height/size/frame, copyTo, scaleToWidth/scale, release, ok/hasFrame/standard/detectStandard). Только TVP5150/захват, без UART. - логику захвата не меняли — класс оборачивает C-ядро - grab_best_field: минимальный перебор (до 3) — первый полный кадр, рваные отсекаются - TOP_TRIM: фикс. срез верхних VBI-строк (стабильная высота) - README.md (для людей) + CLAUDE.md (модель интеграции для ИИ) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
| .vscode | ||
| components | ||
| src | ||
| tools | ||
| .DS_Store | ||
| .gitignore | ||
| best_width.png | ||
| CLAUDE.md | ||
| CMakeLists.txt | ||
| final.png | ||
| ntsc.png | ||
| pal.png | ||
| partitions.csv | ||
| platformio.ini | ||
| README.md | ||
| sdkconfig.defaults | ||
| sdkconfig.mem-info | ||
| todo.md | ||
tvp5150_cap — захват CVBS‑видео на ESP32‑S3 + TVP5150
Библиотека для оцифровки аналогового видео (композитный сигнал CVBS, PAL/NTSC) на ESP32‑S3 через декодер TVP5150AM1 и встроенный модуль LCD_CAM. По команде захватывает один кадр, отдаёт его как grayscale‑изображение в PSRAM и умеет масштабировать под нужную ширину (например, под термопечатающую головку).
Целевой сценарий: снять кадр с медицинского/промышленного видеовыхода (УЗИ, эндоскоп, камера) по нажатию и подготовить к печати или передаче.
Как это работает
CVBS (аналог) → TVP5150AM1 → DVP 8 бит (D0..D7 + VSYNC + HSYNC + PCLK)
→ LCD_CAM (ESP32‑S3) → YUV422 в PSRAM → берём Y (яркость) → grayscale
- TVP5150 декодирует композит в цифровой поток YUV 4:2:2 (27 МГц, 8 бит).
- LCD_CAM принимает поток в VH‑режиме (окно кадра задают HSYNC/VSYNC).
- DMA пишет во внутреннюю SRAM, затем копируется в PSRAM (bounce‑режим — без этого на 27 МГц прямой DMA в PSRAM срывается и нижняя половина кадра идёт шумом).
- Из YUV берётся только Y (яркость) → 8‑битный grayscale.
- Захват выровнен программно: автоопределение фазы Y, детект горизонтальной синхры по тёмной полосе, отсев неполных полей, срез служебных VBI‑строк сверху.
Результат: стабильный кадр ~702×572, чистый сверху донизу.
Требования к железу
| Сигнал | Назначение | Пример GPIO |
|---|---|---|
| SDA / SCL | I2C (SCCB) к TVP5150 | 1 / 2 |
| VSYNC | кадровая синхра | 6 |
| HSYNC (HREF) | строчная синхра | 7 |
| PCLK | пиксельный клок 27 МГц | 13 |
| D0..D7 | данные | 15,16,17,18,8,9,10,11 |
- Нужен ESP32‑S3 с PSRAM (octal, 8 МБ) — кадр не влезает во внутреннюю RAM.
- PCLK = 27 МГц на джамперах склонен звенеть. При «плывущих» строках — последовательный резистор 33–47 Ω в разрыв линии PCLK у пина ESP.
- HSYNC обязателен: без твёрдого HSYNC камера не собирает кадр (таймауты).
Замечание по стандартам. Конкретный протестированный модуль (DL‑968) устойчиво лочится только в PAL (рег 0x28 = 0x04). NTSC поддержан в коде, но на этом железе декодер в нём не захватывался. Стандарт форсируется в
begin().
API (C++)
Класс отвечает только за TVP5150 и захват кадра — никакого UART/USB/сети внутри. Передачу готового кадра (печать/отправка) делает вызывающий код.
#include "Tvp5150.hpp"
Tvp5150::Pins pins = {
.sda=1, .scl=2, .vsync=6, .href=7, .pclk=13,
.d0=15,.d1=16,.d2=17,.d3=18,.d4=8,.d5=9,.d6=10,.d7=11,
};
Tvp5150 cam(pins, Tvp5150::Standard::PAL); // конструктор: I2C + LCD_CAM + буфер PSRAM
if (!cam.ok()) { /* ошибка инициализации */ }
if (cam.capture()) { // снять один корректный кадр в PSRAM
const uint8_t* img = cam.data(); // grayscale 8 бит, cam.width()×cam.height()
// ... передать img на печать ...
cam.release(); // освободить под следующий захват
}
Методы Tvp5150
| Метод | Назначение |
|---|---|
Tvp5150(const Pins&, Standard = PAL) |
конструктор: инициализация чипа, LCD_CAM, буфер PSRAM |
Tvp5150() + begin(pins, std) |
отложенная инициализация |
bool ok() |
инициализация прошла успешно |
bool capture() |
захватить один корректный кадр в PSRAM; true — готов |
bool hasFrame() |
есть ли валидный захваченный кадр |
const uint8_t* data() |
указатель на grayscale‑буфер в PSRAM |
int width() / height() / size_t size() |
геометрия и размер кадра (байт) |
Frame frame() |
всё разом: .gray .width .height .standard |
size_t copyTo(dst, cap) |
скопировать кадр в свой буфер (своя область PSRAM) |
bool scaleToWidth(dst, width, outHeight) |
масштаб под ширину (термоголовка) с сохранением пропорций |
bool scale(dst, w, h) |
масштаб в произвольный размер |
void release() |
освободить буфер под следующий захват |
Standard standard() / detectStandard() |
активный / определить стандарт |
Кадр (data()/frame().gray) принадлежит драйверу и валиден между capture()==true
и release(). Нужно хранить дольше — copyTo() в свой буфер.
C‑API
Тот же функционал доступен как plain‑C (tvp5150_cap.h): tvp5150_init,
capture_frame, get_frame_buffer, frame_scale_to_width, release_frame_buffer.
Класс — тонкая обёртка над ними.
Подготовка под термопечать
static uint8_t* printBuf; // ширина_головки * макс_высота, в PSRAM
int printH = 0;
if (cam.capture()) {
cam.scaleToWidth(printBuf, 1284 /*px головки*/, printH);
// printBuf[printH][1284] — построчно в термоголовку
cam.release();
}
Сборка
PlatformIO + ESP‑IDF. Компонент лежит в components/tvp5150_cap, рядом вшит
components/esp32-camera с правками под TVP5150 (дискретная синхра, FRAMESIZE,
bounce‑DMA). Пример использования — src/demo.c.
pio run -t upload # прошить
pio device monitor # логи (USB‑JTAG)
Инструмент tools/cvbs_save.py принимает кадр по UART и сохраняет PNG/RAW
(захват по пробелу в окне скрипта или по кнопке BOOT).