Пятница, 19.04.2024, 05:12
Вы вошли как Гость | Группа "Гости"Приветствую Вас Гость | RSS
Главная | Каталог статей | Мой профиль | Регистрация | Выход | Вход
Обитель RC-инженера
Форма входа
Меню сайта

Категории раздела
Программирование микроконтроллеров AVR [6]
Программирование микроконтроллеров STM32 [1]
Программирование ПЛИС Altera [1]
Разное [1]
Статьи на различную тематику
Самодельные системы управления моделями [0]

Друзья сайта

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Главная » Статьи » Программирование микроконтроллеров AVR

Генерация видеосигнала при помощи контроллеров AVR. Часть 3. Генерация синхроимпульсов на ассемблере
Прошло немного времени, и я вновь почувствовал в себе силы и желание продолжить статью про генерацию видеосигнала силами AVR микроконтроллеров.

У нас уже есть устройство которое может генерировать электрические сигналы для телевизора, мы написали тестовые программы которые генерируют простейшие изображения на экране.
Что нам не хватает ?  А не хватает в первую очередь стабильности генерируемых длительностей сигналов, помните заломы вертикальной линии ?
второе, нам необходимо генерировать динамичное содержимое - иначе зачем мы все это затеяли,
ну и третье - желательно одновременно с генерацией изображения еще и делать какую то полезную работу - иначе нам просто нечего выводить на экран - выводить статические картинки надоест очень быстро

Итак, в прошлой части статьи мы определили длительности сигналов необходимые для генерации кадровой синхронизирующей последовательности

как ее генерировать?
Есть несколько вариантов, и все они реализуемы на языке ассемблера:
Вариант 1:
Делаем генерацию вручную, считаем по тактам сколько длиться тот или иной цикл задержки и выдаем значения в порты ввода вывода..
Нужно сознаться что данный вариант решения будет достаточно сложным - нужно будет написать огромное количество циклов, подпрограмм.. плюс ко всему какие либо изменения в генерируемых импульсах требовали бы пересчета и внесения коррекций в подпрограммы, циклы.. в общем я бы не взялся писать такую реализацию..

Вариант 2:
Делаем генерацию синхросигналов при помощи таймера !
У нас есть 16ти битный таймер T1, который мы можем запустить с тактовой частотой процессора в 16 мгц.
Тогда один такт таймера будет отмерять временной промежуток в 1\16000000=0.0625 мкс
В синхропоследовательностях минимальный промежуток который мы должны выдавать на телевизор это 2.35 мкс
в тактах таймера это будет: 2.35/0.0625=37.6=38 тактов!
остальные импульсы большей длительности

Причем самое важное что мы генерацию импульса можем возложить полностью на таймер T1, так как у него есть специальный вывод OC1A который может сам изменять свое значение по совпадению значения текущего счетчика TCNT1 со значением регистра сравнения OCR1A
Очень важно, что сигнал на OC1A будет изменяться без кода ! автоматически как только значения в регистре TCNT1 которое увеличивается на 1 с каждым тактом таймера совпадет со значением OCR1A.

 Так же не менее для нас важна возможность задания сброса значения счетчика TCNT1 после его совпадения с OCR1A, ведь как только значение на выходе OC1A изменилось начинается отсчет нового периода, и нам не придется высчитывать задержки из-за выполняемого кода

Далее, напрашивается решение с записью всех нужных длительностей сигналов в массив с последовательной выборкой значений и записью их в OCR1A при каждом прерывании по совпадению TCNT1=OCR1A

В общем то простой алгоритм,

напишем инициализацию таймера:


В инициализации отмечу важный момент: установку первоначального значения вывода OC1A,  так как в нашем случае фаза сигнала не менее важна чем интервалы между сменой фаз

Согласитесь все достаточно просто и локанично (а еще я всегда пишу более менее подробные комментарии)

Теперь то ради чего мы все это настраивали - генерация кадровых синхроимпульсов:





Алгоритм проще некуда!
Берем из переменной avrtv_ksiN  номер генерируемой фазы сигнала
если этот номер менее 32 (у нас 32 фазы генерируемого импульса от 0..31) - то загружаем значение задержки и выходим из прерывания в ожидании следующего прерывания с заданной нами задержкой

а теперь сформируем массив значений импульсов синхронизации (вы помните какие импульсы должны быть и в каком порядке следовать?):


Каждая фаза импульса закодирована двумя байтами H (старшим) и L (младшим)
Соответственно фаза Z - это уровень синхроимпульса (0 вольт), фаза B - это уровень черного  (0.3 вольта)

И отдельно, мы определяем константы фаз импульсов:



Длительность короткого импульса я увеличил до 4 мс - в принципе есть возможность уменьшить до 2.75 мкс - быстродействия генерирующего прерывания хватит, но на всех протестированных мною телевизорах длительность в 4 мкс работала стабильно, поэтому я пока остановился на такой длительности.

После генерации серии коротких, длинных, коротких импульсов мы начинаем генерацию  строк изображения. А строка изображения всегда начинается со строчного синхроимпульса длинной в 4.7 мкс (вы это должны были узнать из второй части статьи)
Для этого мы введем переменную avrtv_phase которая будет флагом необходимости передачи ССИ когда переменная равна нулю - будем генерировать ССИ, иначе выдаем данные строки



Соответственно, если в прошлом прерывании передавали строчный СИ, то в повторном заходе передаем строку, это длительность уровня черного-белого 64 мкс - 4.7 мкс = 59.3 мкс


теперь нам опять нужно спланировать вывод информации в строках кадра.
Всего у нас в кадре 288 строк изображения, но
после вывода кадровой синхронизирующей последовательности обязательно выдать не менее 17 пустых строк (см. вторую часть статьи), потом, нам для вывода 28 строк символов по 8 точек нужно будет вывести 28 * 8 = 224 строки изображения.. и потом опять вывести пустые строки. до общего количества строк.

Чтобы не высчитывать на калькуляторе я переложил эту работу на компилятор:


первая константа - количество пустых строк до изображения
вторая константа - количество пустых строк после изображения
третья константа - количество строк изображения

Соответственно для того чтобы считать какой блок строк (пустые до, изображения, пустые после) мы выдаем - мы заводим еще одну переменную:

 
Теперь код в котором генерируются строки изображения :

Теперь интересный момент - переход к выдаче данных строки.
Сначала я хотел делать программную задержку в 8 мкс перед началом генерации строки изображения, но в этом случае код становился сложноватым, плюс ко всему из-за возможных задержек в 1-5 тактов при входе в прерывание изображение строки могло быть сдвинуто на 1-2 пиксела по горизонтали от прошлых строк (пиксел на телевизоре строиться за 2 такта в 16 мгц, следовательно 4 такта задержки при входе в прерывание - 2 точки по горизонтали сдвига)

Выход нашелся можно сказать сам собой: запустим на счетчике T1 сравнение по регистру OCR1B, в который и загрузим ожидаемую длительность в 8 мкс. Я специально написал тестовую программу которая проверила - при настройках таймера CTC top=OCR1A и включенных прерываниях, можно использовать и прерывания по совпадению по регистру OCR1B, при этом сброса регистра TCNT1
cчетчика не происходит. Главное следить чтобы значение OCR1B было меньше OCR1A иначе условие TCNT1=OCR1B не будет выполнено ни разу, так как TCNT1 будет сбрасываться в ноль при каждом совпадении с OCR1A. В нашей реализации OCR1A (59.3 мкс) всегда больше OCR1B (8 мкс).


Внимательные наверное заметили еще одну тонкость: дело в том что после того как мы включили прерывания по OCR1B мы разрешили прерывания (хотя сами находимся в прерывании) и затем подали команду sleep - которой остановили процессор до возникновения прерывания, причем ждем мы прерывания по OCR1B=TCNT1
данная конструкция необходима потому что мы точно знаем что возникшее прерывание по OCR1B будет каждый раз прерывать команду sleep - и соответственно у нас не будет расхождений по моменту начала выдачи строк..
В момент генерации прерывания все прерывания запрещаются, командой sei мы явно показали что нас можно (и нам даже нужно!) прерывать...

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

Вот и вся генерация синхроимпульсов и позиционирование выводимых строк на экране телевизора. Надеюсь Вам все понятно и не кажется сложным.

Теперь можно переходить к следующей  части:
Генерация видеосигнала при помощи контроллеров AVR. Часть 4. Генерация изображения в строке

p.s. скачать исходник библиотеки можно из форума http://vg.ucoz.ru/forum/9-18-1

Категория: Программирование микроконтроллеров AVR | Добавил: ВитГо (04.09.2012)
Просмотров: 5612 | Комментарии: 6 | Теги: avr, Signal, видеосигнал, COMPOSITE, tv | Рейтинг: 0.0/0
Всего комментариев: 6
5 Сергей  
0
Виталий. А что вы думаеете об использовании в этом проекте ATMega328, ATMega644?
И ещё не могу понять... Если данные об выводимом изображении хранятся в видеопамяти, то бишь в RAM, то как часто можно обновлять эти данные? Вот например, контроллер вывел все данные видеопамяти по SPI на телек, за какое время это происходит, за один кадр? Во время формирования КСИ меняем содержимое видеопамяти и через сколько кадров нужно обновлять? Если к примеру есть данные которые контроллер принимает по UART, потом их надо вывести на экран...
Я пока ещё не во всём разобрался....

6 ВитГо  
0
я думаю что 328 мега будет хорошим вариантом - легкий, паябельный корпус !
мега 64х - выиграет за счет объема оперативной памяти

телевизор не хранит данные изображения, поэтому на него изображение нужно выдавать непрерывно :-)
фактически выдача кадра занимает время около 20 мс, после чего все повторяется заново

библиотека вывода на телевизор не зря написана на прерываниях - в основной программе вы можете делать любые действия с видеобуфером.. единственное ограничение библиотеки - это запрет на использование прерываний - в том виде как сделан проект выложенный на сайте - использовать прерывания нельзя - и вы должны принимать данные по uart проверяя флаги, а не используя прерывания.
больше ограничений нет - и вы можете обновлять изображение в любой момент (не обязательно дожидаться момента когда библиотека выводит пустые строки синхронизации)

вопросы конечно же можно писать на форуме..

4 Сергей  
0
Пардон, Виталий. Спасибо, почитаем

1 Сергей  
0
Виктор, снимаю шляпу. Сами во всём разобрались да ещё такие статьи толковые написали. Я пока не вдавался во все тонкости, но буду постепенно раскуривать ваш материал.
Хочу выводить инфу на VGA. Хотелось бы знать, будет ли продолжение? Как реализован знакогенератор?
Спасибо вам

2 ВитГо  
0
Я не Виктор, Я - Виталий :-)

Чтобы разобраться скачайте саму библиотеку, исходники с комментариями...

Знакогенератор там тоже есть..

Организация простая:
Символы у нас строятся ГОРИЗОНТАЛЬНЫМИ линиями (в отличие от LCD которые рисуются вертикальными линиями). Каждая линия - 1 байт (8 точек)

Знакогенератор строиться так:
256 байт первых линий символа
256 байт вторых линий символа
256 байт третьих линий символа
....
256 байт восьмых линий символа

Это сделано для того чтобы не терять время на вычисление адреса знакогенерирующего байта символа при выводе строки..

надо бы прогу написать какую нить чтобы обычный знакогенератор крутить можно было, а то очень много программ есть которые делают символы для LCD (с вертикально выводимыми байтами символа) а вот для CRT - как то путевых программ нет..
конкретно проблема этого знакогенератора - это помоему DOS кодировка русских букв, а хотелось бы WIN1251 (чтобы не заниматься перекодировкой в исходниках)

p.s. допишу статью там будет про вывод строки.

3 ВитГо  
0
кстати про сигнал VGA можно посмотреть здесь

и помоему монитор сам генерирует синхроимпульсы..

p.s. если найду где нить монитор то напишу статью и про VGA (у меня дома только ноуты :-)

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]

Copyright MyCorp © 2024
Сделать бесплатный сайт с uCoz