Итак, в чём же была проблема? Нужно по параллельному интерфейсу передавать данные. Желательно достаточно быстро - со скоростью несколько мегагерц. Есть несколько линий данных (4-8-12 бит) и несколько линий управления:
- CLK - Тактовый сигнал. Показывает, в какой момент контроллер экранчика может данне с линии забирать.
- ~CS - Выбор чипа. Когда сигнал на этой линии 0 - экран знает, что обращаются сейчас именно к нему.
- LE - Защёлкнуть данные в буфере (то есть переместить в буфер отображения).
- OE - Вывод из буфера на экран. Чем дольше у нас будет сигнал OE в состоянии логической единицы, тем контрастнее будет изображение на экране e-ink.
Вот. Самое, что неприятное - на каждое состояние линий данных и управления надо два состояния клока - считывание идёт контроллером экрана по спадающему фронту тактового сигнала (был высокий уровень, а стал низкий). А данные надо бы передавать по DMA - без прямого нашего вмешателльства. То есть сказать ему - передавай то-то и то-то туда-то и в таком-то количестве. И забыть, чтобы можно было заниматься другими хорошими и полезными вещами.
И если дублировать каждое состояние управляющих линий по два раза - с своим состоянием клока, память будет расходоваться жутко неэкономно, да и процессор "ня" нам не скажет - ему ж это формировать бы ещё пришлось.
Но можно сделать по-иному, используя два канала DMA.
Если настроить таймер на три порога срабатывания, первое из которых вызовет установку данных на линиях, второе - инверсию тактового сигнала, а третье на мгновение позже сбросит таймер в начальное состояние (чтобы не было проблем с DMA, сброс вынесен отдельно).
А работа будет происходить таким образом:
1. Инициализируем каналы.
Первый настроен на запись в порт ввода/вывода данных, причём зацепляет он и линии управления - CLK и ~CS. LE и OE могут быть и на ином порту - они будут управляться отдельно. Он будет записывать очередную порцию данных в порт, например, при значении таймера 5.
Второй настроен на запись в регистр сброса отдельных битов в порту (он должен только сбросить тактовый сигнал, не трогая остальные). Его значение таймера - 9. Тогда он и сработает.
А сброс будет происходить при значении таймера, например, 10 - нечего процессорное время разбазаривать и ставить больше.
2. Запустим оба канала DMA. Запустим таймер.
Таймер начнёт тикать...
1... 2... 3... 4... 5...
Оп-па, первый канал учуял своё значение и записал данные в порт, установив при этом и тактовый сигнал в 1. Указатель буфера сместился на следующий элемент - для следующей записи, счётчик уменьшился на единицу.
6... 7... 8... 9...
Уня, второй канал учуял сигнал - сбросил клок в 0. При этом контроллер экрана это учуял (смену уровня с 1 в 0) и записал данные с линии себе в память. А таймер тикает и дальше.
10...
Теперь таймер сам учуял, что настало время обнуляться. Дальше таймер сбросится и отправка всех данных таким же макаром будет повторена нужное число раз.
Вот примерная картинка сего:
И на осциллографе:
Внизу большая "полка" перед пачкой - это запускающий синхроимпульс для осциллографа. Что-то вроде: "Щас будем бяку слать, ты там смотри, не проморгай".
*Осциллограф няша же - вот как можно вообще без него обходиться? Надо мне бы добыть цифровой, пусть и самый дешёвый ^^"*
По завершении выскочит прерывание от DMA - отправка завершена, мол, "Всё готово, насяльника, што будьма делать?".
Так и скажем - таймер усыпи да скажи контроллеру, что пора бы защёлкнуть данные в буфер отображения да рисовать их на экран. А для этого надо последовательно выдать чиби-импульс LE и более длинный OE.
Опять же, подобную операцию можно скинуть на DMA, а самим вручную перекачать данные в этот момент (пока они заняты общением с контроллером экрана) с внешней памяти (карты памяти) в буфер отображения, откуда DMA будет отправлять уже следующую строку растра...
DMA шустрый, так что особо париться по поводу двух буферов не стоит - писать можно в тот же буфер, DMA всё успеет отправить до нас и мы ему не помешаем =)
Конечно, проблем было больше - то DMA портил первые импульсы, превращая их в нечто непонятное, то несколько импульсов мы недосчитывались, если делали частоту чересчур высокой... Но проблемы все разрешились =)
Первыми импульсами можно посылать нули - типа, мы ещё не начали. Нули он на фоне нуля он испортить при всём старании не сумеет =D
А DMA за это время успеет прийти в себя и начнёт отправлять дальше всё корректно.