nabbla (nabbla1) wrote,
nabbla
nabbla1

Categories:

Селектор синхроимпульсов на ПЛИС

Итак, детектор синхроимпульсов мы уже сделали - он показывает те участки сигнала, где уровень опускается существенно ниже уровня чёрного. Остаётся из этого сигнала ("комбинированного синхроимпульса") получить чёткие кадровые и строчные импульсы. Модуль, который этим займётся, мы обзовём селектором синхроимпульсов, хотя у меня он назван SyncSeparator, поскольку SyncSelector был более старым модулем, объединяющим два этих этапа (детектирование и селектирование). Он совсем простой, состоит из одного реверсивного счётчика и пары регистров.




Вот его код:

module SoftcoreSyncSeparator (input clk, input CompositeSync, output new_row, output new_frame, output DVertSync);

reg Composite_z = 1'b0;
always @(posedge clk)
	Composite_z <= CompositeSync;

assign new_row = CompositeSync & (~Composite_z); //=1 for strictly 1 clock pulse on rising edge of CompositeSync


//to find vert sync, we must integrate CompositeSync. When it is sufficiently longer than hor. pulse, it means only one :)
wire IntegratorSaturated;
wire [8:0] IntegOut;

lpm_counter Integrator (.clock (clk),
			.updown (CompositeSync),
			.cnt_en (~IntegratorSaturated),
			.cout (IntegratorSaturated),
			.Q (IntegOut));
defparam
	Integrator.lpm_port_updown = "PORT_USED",
	Integrator.lpm_type = "LPM_COUNTER",
	Integrator.lpm_width = 9;
	
wire VertSync = IntegOut[8] | IntegOut[7];

reg rVertSync = 1'b0;
always @(posedge clk)
	rVertSync <= VertSync;
	
assign new_frame = VertSync & (~rVertSync);

assign DVertSync = VertSync;

endmodule



Для дальнейшей работы используются выходы new_row ("новая строка") и new_frame ("новый кадр"). На каждом из них появляется импульс длительностью в один такт при наступлении каждого из этих событий.

Но отлавливать такой импульс на осциллограмме не очень приятно, уж больно короткий, поэтому мы также вывели "отладочный" выход DVertSync (Debug Vertical Sync, кадровый синхроимпульс для отладки).

С формированием new_row всё просто: мы задерживаем вход CompositeSync на один такт, и затем new_row должна устанавливаться в единичку в одном-единственном случае: когда на CompositeSync уже единица, а на Composite_z (задержанный на такт) - пока ещё нолик. Старый добрый метод, мы так же делали, чтобы сформировать единичный импульс из нажатия на кнопку.

Ну и остаётся разобраться с кадровым импульсом. Его мы получаем с помощью интегрирования, в некоторой вариации. Мы ввели реверсивный "насыщаемый" счётчик в 9 бит.

Если на входе ноль, то производится счёт "вниз", если только мы уже не дошли до упора. Если на входе единичка, производится счёт "вверх", если только не упёрлись в потолок. Чтобы добиться "насыщаемости", мы на вход разрешения счёта подаём инвертированный выход переноса, который в реверсивном счётчике "комбинаторно" переключается с детектирования "всех единиц" (при счёте вверх) к "всем нулям" (при счёте вниз).

Ну а дальше мы опять делаем "упрощённый компаратор" - проверяем, чтобы хоть один из двух старших битов был единичным, то есть, реагируем на значения выше 128. Единица на проводе VertSync возникнет, если синхроимпульс длится 128 тактов подряд, или 5,12 мкс (для тактовой частоты 25 МГц).

Таким образом, самые длинные строчные синхроимпульсы (4,7..4,9 мкс в CVBS) не вызовут срабатывания, тогда как все кадровые синхроимпульсы из форматов AHD (16,7 мкс), TVI (32,3 мкс), CVI (21,7 мкс) и CVBS (27,3 мкс) - вызовут срабатывание уже до первого "зубца" ("врезки"). См кадровая развёртка в аналоговых сигналах высокой чёткости.

Осталось проверить, не будет ли возникать несколько кадровых импульсов подряд. Именно чтобы предотвратить это, мы сделали счётчик 9-битным (от 0 до 511), хотя срабатывание регистрируем уже на значении 128. Самым проблемным является формат AHD, у которого импульс длится 16,7 мкс, а "врезка" - 10 мкс. За первый импульс счётчик добежит до значения 417. Затем последует "врезка" длительностью 10 мкс, за которую счётчик спустится до значения 167. Если бы мы сделали счётчик 8-битным, то дойдя до 255, он бы уже сбросился до значения 5 (!!!). Затем, во время следующего импульса в 16,7 мкс, счётчик уже дойдёт до насыщения, 512, а во время "врезки" в 10 мкс, опустится до значения 262 - и дальше мы выходим в установившийся режим, и синхроимпульс длится положенные 2,5 строки.

С остальными форматами всё куда проще: у них куда длиннее сами импульсы (за один такой счётчик доходит "до насыщения") и заметно более коротки "врезки".

Такой модуль занимает 15 ЛЭ, что вместе с 27 ЛЭ предыдущего модуля даёт 42 ЛЭ - весьма терпимо, как по мне. Зато теперь нам не нужно кровь из носу 5 вольт, микросхема LM1881 и вся обвязка к ней (фильтрующие конденсаторы, входной разделительный конденсатор, согласование уровней между 5 вольтами и 3,3 вольтами периферии ПЛИС). Если ПЛИС не забита совсем уж "под завязку", то такое исполнение я считаю предпочтительным.

Предыдущий модуль по результатам сегодняшних экспериментов предлагаю ещё слегка доработать. Вместо LeakLevel=7 ставим LeakLevel=6 - как-то я слегка позабыл, что конденсатора у нас ДВА, по прямому и инверсному входу, и перезаряжаются ОБА. Заодно и 1 ЛЭ экономим - счётчик-то укорачивается!

И второе: вместо строки
CompositeSync <= (~DiodeClosed) | (DiodeClosed & (~Dnew[7]) & (~Dnew[6]) & (~Dnew[5]) & (~Dnew[4]));


пишем:

CompositeSync <= (~DiodeClosed) | (DiodeClosed & (~Dnew[7]) * (~Dnew[6]) & (~Dnew[5]));


тоже упрощая схему (одним входом меньше) и увеличивая порог срабатывания с 64 мВ до 128 мВ.

После этого всё работает как положено, даже когда вся схема "на соплях" и опутана проводами осциллографа, втыкнута в компьютер по USB Blaster'у и так далее. Всё-таки развёртка обязана быть "неубиваемой"...

Для обычного сигнала (CVBS) получаем осциллограмму в начале поста. Как и обещалось, мы обнаруживаем кадровый синхроимпульс ещё до первого "зубца" ("врезки"). Картинка очень стабильная, видно только как чередуются чётные и нечётные кадры (полстроки то ПЕРЕД кадровым импульсом, то ПОСЛЕ). Изобразим также комбинированные и кадровые синхроимпульсы на одной осциллограмме:


Можно поспорить, что часть из этого мы за строчные синхроимпульсы воспринимать не должны, но главное, что они ВСЕГДА воспринимаются, так что дальше лишь вопрос настройки счётчика - сколько импульсов пропустить в начале и сколько в конце.


Так оно выглядит в формате CVI:


Оба синхросигнала:


Формат AHD:


Оба синхросигнала:


Формат TVI:


Оба синхросигнала:



Ну и для успокоения совести надо посмотреть "издалека", в масштабе десятков-сотен миллисекунд - не пропускаются ли целые кадры?








Все на месте, и никогда не пропадают.

Ну и закрытие камеры рукой ("черные" кадры) с последующим открытием ("перенасыщенные" кадры) кадровую развёртку не сбивает ни разу. Оно, в принципе, логично - к тому времени уже проходит сколько-то "погашенных" строк, так что погоды уже не делает.


Всё, теперь мы пришли практически к тому же цифровому интерфейсу, который дают фотоприёмные матрицы со старым добрым "параллельным" выходом - это и есть шина данных, по которой передаётся по пикселю за раз, плюс сигналы строчной и кадровой синхронизации. Таким выходом обладают многие матрицы фирмы Omnivision (хотя сейчас они очень агрессивно переходят на мерзопакостный MIPI CSI), да и отечественная радстойкая 1205ХВ014 обладает чем-то подобным, только "на стероидах" (два выхода, по 12 бит на пиксель).

Так что дальнейшая обработка видео будет применима для любой камеры на входе - и аналоговой, и цифровой.
Tags: ПЛИС, работа, странные девайсы
Subscribe

  • Нахождение двух самых отдалённых точек

    Пока компьютер долго и упорно мучал симуляцию, я пытался написать на ассемблере алгоритм захвата на ближней дистанции. А сейчас на этом коде можно…

  • Слишком общительный счётчик

    Вчера я чуть поторопился отсинтезировать проект,параметры не поменял: RomWidth = 8 вместо 7, RamWidth = 9 вместо 8, и ещё EnableByteAccess=1, чтобы…

  • Балансируем конвейер QuatCore

    В пятницу у нас всё замечательно сработало на симуляции, первые 16 миллисекунд полёт нормальный. А вот прошить весь проект на ПЛИС и попробовать "в…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments