Предисловие Прочитав множество увлекательных статей об интересных разработках для ПЛИС, таких как Тетрис , радиопередатчик И другой , я тоже загорелась идеей сделать что-нибудь для души.
Для этого я купил камеру.
OV7670 и совет по развитию ДЕ-1 от Terasic с чипом Cyclone II от Altera. Я поставил следующую задачу: вывести изображение с камеры на VGA-монитор.
Чтобы оправдать использование FPGA, я собираюсь сделать это на максимальной скорости камеры.
Должен отметить, что легче разобраться в этой работе помогут знания в области электроники: знание интерфейсов VGA и I2C, понимание работы памяти SDRAM и т.д.
Введение
Данная статья не исследование, это скорее отчет о проделанной работе, в котором я постарался показать основную идею и наиболее интересные и сложные на мой взгляд места.По сложности этот проект близок к «мигни светодиодом», но имеет огромный потенциал для расширения.
В проекте сознательно не используются готовые IP-ядра и стандартные интерфейсы, поскольку изначально проект планировался как рукописный.
Это также поможет вам немного выиграть с точки зрения ресурсов и производительности.
Надеюсь, эта статья будет интересна читателям, а желание увидеть себя на экране через «самодельную камеру» побудит их к изучению ПЛИС.
Отказ от ответственности В некоторых местах проекта архитектура и синтаксис кода могут быть неоптимальными.
Это связано с тем, что над проектом я работал в свободное время, и иногда между подходами были перерывы в несколько месяцев: старые мысли забывались, но появлялись новые.
Например, центральный автомат был сильно упрощен: от исходного монстра осталось только название «глобальный».
Перед публикацией я провел рефакторинг кода, но если будут обнаружены какие-то недостатки, просьба указать на них в комментариях.
Проблемы и решения
Чтобы понять, что нас ждет, давайте взглянем на «железо» и оценим, с какими проблемами мы столкнемся.Камера OV7670. Камера способна формировать изображения разрешением 640x480 пикселей с частотой 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. Поэтому мы будем использовать для хранения кадров SDRAM-память , расположенный отдельной микросхемой на плате DE-1. Это позволит нам организовать кадровый буфер для решения технической задачи и даст возможность попрактиковаться в написании контроллера SDRAM. Следующая задача вытекает из решения предыдущей.
При использовании памяти SDRAM в нашем проекте необходимо учитывать два важных момента: во-первых, память работает на высокой для нашей конструкции частоте 120 МГц, и мы сталкиваемся с новой проблемой — переносом данных из тактовой области камеры в SDRAM. часовой домен; во-вторых, для достижения максимальной производительности следует писать в SDRAM целыми транзакциями, которые называются пакетными.
Лучшим способом решения этих проблем является FIFO, организованный во встроенной памяти 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, то от возможности работы с отдельными числами можно отказаться, будем писать только пакетно.
В-третьих, не нужно думать об адресе, мы просто будем его инкрементировать после каждого пакета и сбрасывать в ноль в конце каждого кадра.
Получившийся граф переходов показан на рисунке 6.
Рис.
6 Контроллер запускается в состоянии ожидания.
Перед началом нормальной работы необходимо инициализировать микросхему памяти (состояние машины s0_MRS), после чего устанавливается флаг mode_flag, контроллер переходит в состояние ожидания, и мы можем записывать и читать данные.
Для этого от модуля fsm_global поступает команда на начало чтения или записи, мы открываем нужную колонку в выбранном банке (состояние s0_ACT), после чего должно произойти чтение или запись (состояния s0_WRIT, s0_READ).
К сожалению, одним пакетом нам не обойтись, глубина столбца в нашей микросхеме памяти составляет всего 256 16-битных слов, а нам нужно записать вектор длиной 640. Придется писать в 3 пакета.
, два по 256 и один по 128. Видно, что половина третьей Строка остаётся пустой, то есть ресурсы мы используем нерационально, но так как их недостатка у нас нет, я решил не усложнять машину и прийти смириться с этим.
Что касается адресов, то они имеют отдельные регистры для чтения и записи, которые инкрементируются перед каждым перебором.
Таким образом, чтобы записать вектор длиной 640, мы проходим по 640*4=1440 адресам.
Строб вертикальной синхронизации камеры или адреса VGA сбрасываются на ноль для записи и чтения соответственно.
Мы используем двойную буферизацию: пишем в один буфер из другого и читаем.
Для упрощения я поместил один буфер в банк 0, а второй в банк 1 микросхемы SDRAM. Банки чтения и записи меняются местами после окончания приема кадра с камеры.
На рис.
7 показаны временные диаграммы записи одного вектора.
Видно, что запись разделена на 3 части: после каждой части адрес инкрементируется, вся передача происходит под стробом cur_wr. Для чтения схема аналогична.
Рис.
7
На рисунке 8 показано, как данные с камеры записываются в SDRAM в сравнении со временем, необходимым для заполнения FIFO. Обратите внимание, что мы начинаем запись в SDRAM, не дожидаясь полного заполнения FIFO.
Рис.
8
модуль hvsync
Это один из двух модулей в этом проекте, написанных не мной.Я уже однажды реализовал подобный модуль; Мне не было интересно повторяться, поэтому я воспользовался отличным модулем, написанным авторами сайта.
В этом модуле нет ничего лишнего, он параметризуется и легко настраивается под любое разрешение экрана.
Я его практически не менял, лишь добавил FIFO, подключенный к контроллеру SDRAM, и разводку сигналов для него.
От FIFO идет шина, по которой задается объем записываемых в него данных; эта шина подключена к управляющей машине по аналогии со входом FIFO. Выход FIFO подключен к проводам, идущим к ЦАП.
модуль camera_configure
Изначально, вольничая с домашним проектом и не внимательно читая документацию, я хотел запустить камеру с настройками «по умолчанию», но оказалось, что без настроек OV7670 передает информацию в формате не RGB565, а в YUV422. Переписывать ничего не хотелось и я решил, что нужно все сделать с умом и нормально инициализировать камеру.Так как камера управляется по I2C, пришла в голову идея использовать NIOS. Запустить NIOS с коркой I2C с опенкором с полпинка не удалось, но случайно наткнулся на Verilog модуль инициализации и конкретно для OV7670. Он настолько легко интегрировался в код, что мне не пришлось практически ничего менять, я изменил только одну строчку: вместо RGB565 я активировал режим RGB444, так как на плате установлены 4-битные ЦАП.
На рисунке 9 представлена временная диаграмма программного сброса камеры записью числа 0x80 по адресу 0x12.
Рис.
9
Демонстрация результата
После того, как все модули написаны, соединяем их в топ-модуль, собираем в Quartus и можем протестировать.Видео демонстрирует результат. Время для съемки выбрал не очень удачное – закат и очень яркое солнце – на слишком яркие солнечные блики камера реагирует неадекватно.
Видно, что движущиеся объекты отображаются корректно, дерганий и шлейфов нет. Именно этого я и добился с помощью ПЛИС, которая позволяет с небольшими затратами обрабатывать все 30 (а возможности камеры больше) кадров в секунду.
Если говорить о четкости изображения, то могу сказать, что текст с листа А4 читается без каких-либо затруднений; к сожалению, фотографии с монитора получаются хуже, чем в реальности.
На рисунке 10 показан фрагмент листа А4 с документацией к камере.
"
Представленные видео и фото демонстрируют некоторые недостатки: первый с резкостью, второй с цветом.
Проблему с резкостью на видео я связываю с несовершенной фокусировкой.
Фокусировка на фотоаппарате регулируется механически путем вкручивания или выкручивания объектива, расположенного на резьбе.
Резьба пластиковая и имеет довольно большой люфт; даже небольшое встряхивание может ухудшить резкость.
Проблема с излишней зелено-желтизной белого листа, как мне кажется, связана с проблемой баланса белого: съемка производилась в помещении с освещением, далеким от естественного.
Также на цветовую ситуацию могут влиять настройки камеры.
Я с ним практически не экспериментировал, использовал как магическое число.
Заключение
Поставленная задача — вывод изображения с камеры OV7670 на VGA-монитор в реальном времени — решена.Если сравнить результат, полученный в этом проекте, с результатом, полученным другими разработчиками, использующими микроконтроллеры или Arduino, то можно увидеть, что они уступают в скорости отображения движущихся объектов.
По трудоемкости данный проект не превосходит аналогичные, выполненные с использованием микроконтроллера.
Человек с базовыми знаниями в области проектирования FPGA может реализовать это за несколько дней.
Проект имеет большой потенциал для расширения; есть возможность фильтровать полученное изображение, распознавать объекты и т.д. Конструкция на микросхеме Cyclone II занимает следующие ресурсы: LE - 745 (4%), бит памяти - 32768 (14%), PLL - 1 (25%).
), Embedded Multiplier — 0 (0%), — таким образом, у разработчиков еще достаточно ресурсов для реализации ваших идей.
Послесловие
Что дальше? В будущем планирую расширить проект, добавив обработку изображений в реальном времени с помощью матричные фильтры .Я выражаю свою благодарность ишевчук за консультацию по содержанию и оформлению статьи и моей девушке за проверку орфографии.
Плохие дубли Когда я включил его в первый раз, на экране монитора появились загадочные узоры.
Я долго думал, что может быть так.
В результате оказалось, что камера не в фокусе.
После того, как я покрутил линзу на объективе, все стало на свои места.
" alt="изображение"/>
При втором включении камера инициализировалась неправильно, в результате чего получилось неожиданное селфи.
"
Вы можете скачать исходный архив здесь (Я.
Диск) .
Теги: #FPGA #vga #OV7670 #verilog #FPGA
-
Защита Приложений В Эпоху Микросервисов
19 Oct, 24 -
Оптимизация Затрат С Помощью Amazon S3
19 Oct, 24 -
Блогеры Построили Дата-Центр За 60 Дней
19 Oct, 24