Прочитав много увлекательных статей об интересных разработках под FPGA, таких как тетрис, радиопередатчик и другие, я тоже загорелся идеей сделать что-нибудь для души. Для этой цели мной была приобретена камера OV7670 и отладочная плата DE-1 фирмы Terasic с чипом Cyclone II фирмы Altera. Задачу поставил следующую: вывести изображение с камеры на VGA монитор. Для того, чтобы оправдать использование FPGA, я собираюсь сделать это на максимальной для камеры скорости. Должен отметить, что легче понять эту работу помогут знания в области электроники: знания интерфейсов VGA и I2C, представление о SDRAM памяти и т.п.
Введение
Данная статья не является исследованием, это, скорее, отчет о проделанной работе, в котором я постарался показать основную идею и наиболее интересные и сложные на мой взгляд места. По сложности этот проект следует за «поморгать светодиодом», но имеет огромный потенциал к расширению. В проекте намеренно не используются готовые IP-ядра и стандартные интерфейсы, так как проект изначально планировался как рукописный. Также это поможет немного выиграть по ресурсам и быстродействию. Надеюсь, эта статья будет интересна читателям, а желание увидеть себя на экране через «самодельную камеру» сподвигнет к изучению FPGA.
Посылка с taobao.com. OV7670 модуль камеры. Проверка работоспособности. Видео от клиента.
Дискламер
В некоторых местах проекта архитектура и синтаксис кода могут быть не оптимальны. Это связанно с тем, что реализацией проекта я занимался в свободное время, и между подходами иногда были перерывы в несколько месяцев: старые мысли забывались, но появлялись новые. Так, например, сильно был упрощен центральный автомат: от первоначального монстра осталось лишь название «global». Перед публикацией я провел рефакторинг кода, но если будут обнаружены недостатки, прошу указать на них в комментариях.
Проблемы и способы их решения
Для того чтобы понимать, что нас ждет, взглянем на железо и оценим, с какими проблемами нам предстоит столкнуться. Камера OV7670. Камера способна выдавать изображение разрешением 640х480 точек с частотой 30 кадров в секунду в формате RGB565. Для работы камеры необходимо подавать на нее клок частотой 24 МГц. Камера передает пользователю данные по 8 битной шине, а также стробы синхронизации VSYNC и HSYNC. Временные диаграммы работы камеры представлены на рисунке 1.
Рис.1
Информация о цвете передается за 2 такта побайтно. Упаковка данных в байты представлена на рисунке 2.
Рис.2
VGA монитор. VGA это аналоговый сигнал, поэтому подавать цифровые данные на его вход не получится. Но на борту DE-1 имеются 4-х разрядные ЦАП, их мы и задействуем для преобразования цифрового сигнала в аналоговый. VGA с разрешением 640х480 имеет частоту обновления 60 кадров в секунду. Необходимо выставлять данные на ЦАП с частотой 25.175 МГц, а также формировать стробы синхронизации VSYNC и HSYNC.
Тайминги для VGA можно посмотреть здесь.
Становится ясно, что частота поступления данных с камеры и частота вывода данных на монитор отличаются, что исключает возможность прямого подключения. Выход из этой ситуации — использование кадрового буфера.
Выделим в памяти две равные области: в одну будет записываться текущий кадр с камеры, а из второй извлекаться предыдущий, после окончания записываемого кадра буферы меняются местами. Для хранения одного кадра требуется 640*480*16 = 4.915*10^6 бит, что гораздо больше имеющейся на борту Cyclone II памяти on-chip. Поэтому будем использовать для хранения кадров память SDRAM, расположенную отдельным чипом на плате DE-1. Это позволит нам организовать фрейм буфер для решения технической задачи и даст возможность потренироваться в написании контроллера SDRAM.
Следующая проблема вытекает из решения предыдущей. При использовании памяти SDRAM в нашем проекте необходимо учитывать два важных момента: во-первых, работает память на высокой для нашего дизайна частоте 120 МГц и перед нами появляется новая проблема — передача данных из клокового домена камеры в клоковый домен SDRAM; во-вторых, для достижения максимального быстродействия писать в SDRAM следует целыми транзакциями, которые называются burst. Для решения этих проблем наилучшим способом подходит FIFO, организованное в on-chip памяти FPGA. Основная идея такова: камера на низкой частоте заполняет FIFO, после чего контроллер SDRAM считывает данные на высокой частоте и сразу одной транзакцией записывает их в память.
Вывод данных на монитор организован то такому же принципу. Данные из SDRAM записываются в FIFO, а затем извлекаются на частоте 25 МГц для подачи на ЦАП. После опустошения FIFO операция повторяется.
Самой мелкой проблемой является то, что настройки камеры «из коробки» нас не устраивают, и необходимо их изменить. Самый важный момент, камера выдает данные в формате YUV422, и необходимо поменять его на RGB444. Для обращения к внутренним регистрам OV7670 необходимо будет описать модуль передатчика I2C.
Теперь можно сказать, какие модули нам придётся реализовать, и какие задачи они будут решать.
- cam_wrp – модуль принимает данные с камеры и записывает их во входное FIFO;
- hvsync – модуль вырабатывает стробы для VGA, принимает данные из SDRAM, записывает их во входное FIFO и по стробу подает на ЦАП;
- sdram_cntr – контроллер SDRAM;
- FSM_global – автомат управления;
- camera_configure – модуль конфигурации и управления камерой.
Рис.3
Рассмотрим подробнее каждый из модулей.
Модуль cam_wrp
Один из самых простых модулей. Его задача в момент действия строба hsync камеры принимать последовательно по два байта, формировать из них одно двухбайтовое слово и записывать его в FIFO. По сигналу от SDRAM контроллера передать ему все содержимое FIFO.
Для «упаковки» 2-х последовательных байт в одно слово используем сигнал wr_fifo, который инвертируем по клоку (делим частоту на 2). Когда этот сигнал в логической 1, записываем данные в младший байт, когда в логическом 0 — в старший. Также используем wr_fifo, как сигнал записи в FIFO. Кроме шины данных из FIFO выведена шина, на которую выставляется число записанных в него данных.
Эта шина подключена к автомату управления. На рисунке 4 представлена временная диаграмма «упаковки» байт в двухбайтовые слова.
Рис.4
Модуль FSM_global
Модуль имеет весьма пафосное название, на деле это несложный автомат всего на 4 состояния, но выполняет он очень важную функцию. Отслеживая сигнал готовности sd_ready SDRAM контроллера, наполненность входного и выходного FIFO, автомат выдает в команды SDRAM контроллеру забрать данные из входного или записать в выходное FIFO. Чтение и запись происходят несколько раньше, чем FIFO полностью заполнится или опустошится. Необходима правильно выбрать уровень заполненности FIFO, чтобы операции с FIFO на высокой частоте не закончились раньше, чем на низкой, — это гарантированно приведет к ошибкам. В части, посвященной SDRAM контроллеру, я приведу рисунок, иллюстрирующий эту особенность.
Модуль SDRAM_contr
Контроллеров SDRAM написано уже много, изобретать велосипед в очередной раз не хотелось, поэтому я решил изобрести велосипед на гусеничном ходу. А именно, SDRAM контроллер, заточенный под этот конкретный проект. Это упростит управление и чуть-чуть ускорит работу. Граф переходов автомата для полноценного SDRAM контроллера представлен на рисунке 5.
Рис.5
Подумаем, что мы сможем из него исключить.
Во-первых, не будем рефрешить данные. Это допущение абсолютно точно не подойдет для контроллера общего назначения, но в нашем случае мы задействуем одну и ту же область памяти, постоянно обращаясь к ней. Данные не будут успевать деградировать.
Во-вторых, так как мы всегда будем записывать и считывать данные вектором длиной 640, можно отказаться от возможности работы с отдельными числами, будем писать только burst.
В-третьих, не надо думать над адресом, мы просто будем инкрементировать его после каждого burst и обнулять в конце каждого кадра. Получившийся граф переходов представлен на рисунке 6.
Рис.6
Стартует контроллер в состоянии idle. Перед началом нормальной работы необходимо провести инициализацию микросхемы памяти (состояние автомата s0_MRS), после чего выставляется флаг mode_flag, контроллер переходит в состояние ожидания, и мы можем записывать и считывать данные.
Для этого из модуля fsm_global поступает команда начала чтения или записи, открываем необходимый столбец в выбранном банке (состояние s0_ACT), и далее должно происходить чтение или запись (состояния s0_WRIT, s0_READ). К сожалению, обойтись одним burst не выйдет, глубина столбца в нашем чипе памяти всего 256 16-ти битных слов, а нам необходимо записывать вектор длиной 640. Придется писать за 3 burst, два по 256 и одни на 128. Видно, что половина третьей строки остается пустой, то есть мы нерационально используем ресурсы, но так как недостатка в них у нас нет, я решил не усложнять автомат и смириться с этим.
Что касается адресов, для них выделены разные регистры для чтения и записи, которые инкрементируются перед каждым bust. Таким образом, для записи вектора длиной 640 мы проходим 640*4=1440 адресов. Стробом вертикальной синхронизации камеры или VGA адреса обнуляются для записи и чтения соответственно.
Как подключить модуль камеры OV7670 к Arduino
Транслируем изображение в реальном времени с помощью модуля камеры OV7670 на 1,8-дюймовый TFT ЖК-экран с помощью Arduino IDE.
Шаг 1. О проекте
В этом уроке мы покажем как отображать видео-поток с модуля камеры OV7670 на 1,8-дюймовый TFT ЖК-экран с помощью Arduino. OV7670 — самый доступный модуль камеры, который можно использовать с Arduino, поэтому вы можете использовать его во многих проектах.
VGA-модуль. Камера для Arduino
Модуль видеокамеры предназначен для работы в составе электронного фотоаппарата, приборов видеотрансляции и видеозаписи. Информация на выходе модуля представляется в цифровом виде. VGA-модуль OV7670 300KP совместим с различными микроконтроллерами. Высокая чувствительность позволяет работать в условиях низкой освещенности.
По шине управления можно настроить качество изображения, формат данных и режим передачи. Особенности модуля позволяют автоматически поддерживать высокое качество изображения путем уменьшения или устранения зашумленности, выравнивания баланса цвета, повышения четкости изображения, установки оптимальной насыщенности, контрастности, гаммы и оттенка изображения. Эти особенности прибора OV7670 300KP позволяют его применять в системах видеонаблюдения входящих в комплексы “умный дом”, охранные системы. Малый вес устройства позволяет устанавливать его на автоматические аэросистемы и различные подвижные платформы. Энтузиастами ведутся разработки в области определения расстояний до препятствия с помощью двух камер.
Характеристики
Питание
напряжение
диапазон 5,5 – 3,3 В
номинальное 3,3 В
потребляемая мощность 60 мВт
ток в режиме сна менее 20 мкА
Уровень напряжения лог. 1 на контактах сигналов в диапазоне 2,5 – 3 В
Интерфейсы OV7670 300KP: SCCB совместим с I2C и параллельный 8 линий
Чувствительность 1,3 В (люкс-секунда)
Отношение сигнал-шум 46 db
VGA-модуль имеет динамический диапазон 52 db
Темновой ток 12 мВ/с при 60 ° С
Разрешающая способность 0,3 мегапиксель
максимальная 640 х 480 точек
минимальная 40 x 30 точек
Развертка по строкам
Поддерживается масштабирование изображения
Форматы передачи цвета: RGB565, RGB555, RGB444, YUV/YCbCr 4:2:2, GRB 4:2:2, Raw RGB Data
Максимальная скорость передачи 30 кадр/с
Размер объектива 1/6 »
Угол обзора 25 °
Методы автокоррекции: AEC, AGC, AWB, ABF, ABLC
Автокомпенсация помехи 50, 60 Гц
Прогрессивный режим просмотра
Электронная экспозиция от одной линии до 510
Температура окружающего воздуха во время работы OV7670 300KP
рекомендуемая от 0 до 50 °С
предельная от –30 до 70 °C
Размер пикселя 3,6 x 3,6 мкм
Вес 12 г
Особенности
Для OV7670 существуют множество настроек. Программируется качество изображения, формат данных и режим передачи. Обработка изображения настраивается записью данных в специальные регистры микросхемы OV7670 с помощью интерфейса Serial Camera Control Bus (SCCB) – аналог шины I2C. Частота дискретизации 30 кадров в секунду соответствует стандарту VGA. Скорость передачи кадров устанавливается программно.
Также доступны форматы: QVGA 320х240, CIF 352х240, QCIF 176×144. Разрешающая способность может принудительно снижаться до 40×30 точек.
Данные о цвете передаются с помощью установленной программистом кодировки. Используются два основных типа кодирования YCbCr и RGB, который имеет три варианта: RGB565, RGB555, RGB444. Здесь цифры означают количество бит на один цвет. Например, RGB565 это 5 бит на красный, 6 бит на зеленый и 5 бит на синий. В случае кодировки RGB для передачи данных о цвете пикселя потребуется 2 байта.
Передача кодировки цвета YCbCr сложнее.
По умолчанию установлен формат VGA 640х480. 30 кадров, 480 строк. На выходе HREF сигнал с частотой 14,4 кГц. Частота обусловлена параметрами изображения 30 кадров х 480 строк = 14400 Гц.
Схема и компоненты
Изображение объектов, находящихся перед объективом камеры для Arduino, фокусируется на поверхности микросхемы OV7670, расположенной на плате под объективом. Микросхема U1 преобразует фотоинформацию в цифровой вид и обеспечивает передачу данных по интерфейсу. Для питания микросхемы на плате смонтированы два интегральных стабилизатора напряжений 2,8 и 1,8 вольт. В схему устройства входит несколько пассивных компонентов, обеспечивающих работу стабилизаторов и светочувствительной микросхемы.
Контакты и сигналы
Контакт | Тип | Сигнал |
3V3 | питание | |
GND | общий провод | |
SIO_C | вход | такт интерфейса SCCB управления камерой |
SIO_D | вход-выход | данные интерфейса SCCB управления камерой |
VSYNC | выход | кадровая синхронизация |
HREF | выход | строчная синхронизация |
PCLK | выход | такт передачи байта из параллельного порта D0–D7 |
XCLK | вход | главный такт для работы OV7670 |
D7–D0 | выходы | параллельный видеовыход |
RESET | вход | сброс лог. 0 |
PWDN | вход | включение лог. 0 и выключение лог. 1 камеры |
Наилучшее подключение прибора – непосредственная установка вилки соединителя в розетку основного модуля прибора видеонаблюдения. Частоты сигналов могут доходить до 24 МГц. В связи с этим линии подключения модуля видеокамеры выполняются в соответствии с требованиям к высокочастотным соединениям. Среди них главное требование выполнять соединения как можно более короткими проводниками.
Напряжение питания микроконтроллеров выше предельного напряжения сигналов модуля. Для обеспечения соответствия уровней сигналов МК и VGA-модуля необходимо устанавливать согласующие цепи. Для входа SIO_C необходимо сделать резисторный делитель напряжения для выполнения требования по максимальному уровню входного сигнала модуля видеокамеры.
Для контакта SIO_D так сделать нельзя, он является двунаправленной линией. К счастью, Arduino имеет встроенную поддержку протокола I2C с рабочим напряжением 3,5 В на контактах A4 SDA и A5 SCL. Величину резисторов делителей нужно подбирать. Другой вариант согласования уровней SIO_D и SIO_C – установка на этих линиях резисторов подтяжки к питанию 3,3 В сопротивлением 3,3 кОм.
Обмен данными с камерой по шине I2C возможен, если подана тактовая частота на вход XCLK. Рекомендуемая частота этого сигнала 24 МГц. Используя в качестве источника сигнала 8 МГц, микроконтроллер и установив в МС OV7670 умножение частоты на 3, получим требуемые 24 МГц. При напряжении питания генератора 5 В тактовый сигнал XCLK подается через согласующий резисторный делитель напряжения из одинаковых резисторов 4,7 кОм.
Видеоинтерфейс модуля OV7670 300KP использует синхроимпульсы по кадрам VSYNC, по строкам HREF и по пикселям PCLK. Данные пикселя, представляющие собой закодированную информацию о его цвете, передаются по параллельному интерфейсу D7–D0 по тактам PCLK. Для передачи данных о цвете используются 2 байта, отправляемые по очереди.
Расположение бит кодировки цвета RGB565 в двух байтах.
Расположение бит кодировки цвета RGB555 в двух байтах.
Расположение бит в трех видах кодировок цвета в двух байтах.
Диаграмма сигналов несущих информацию о цвете.
Проверка работоспособности
Подать питание на VGA-модуль величиной 3,3 В. Подать на вход XCLK меандр частотой 24 МГц используя изложенные выше рекомендации. С помощью осциллографа убедиться в наличии сигналов на выходах: PCLK – 24 МГц, VSYNC – 30 Гц, HREF – 14,4 кГц, на D0–D7 должны быть видны информационные посылки. Если камера для Arduino формирует перечисленные сигналы, значит она работоспособна.
Программирование
Камера для arduino использует стандартную библиотеку Wire. Программа для чтения регистров OV7670 https://github.com/PavelTorgashov/Arduino/tree/master/OV7670
Источник: arduino-kit.ru