nabbla (nabbla1) wrote,
nabbla
nabbla1

Categories:

Прерывания в QuatCore

В эту пятницу, когда перепаивал кабель, всё прошло немного не так гладко, как я написал. В первый раз, как я вставил новый кабель и подал питание - сообщение на ЖК-экранчике появилось, по UART пришло сообщение на компьютер "Начинаем работу". Но когда я запрашиваю изображение - в ответ тишина, ни одного байта не возвращается...

Пошевелил немного платку-переходник, на которой сидит АЦП - и далее всё заработало. У меня подозрение, что неконтакт в разъёме PBS 1x10, в который воткнут PLS 1x10 - они самые дешёвые китайские у меня, возможно самый крайний контачит не очень хорошо.

Но каждый раз "искать на ощупь" неисправность не хочется. Решил, что об отсутствии видеосигнала штуковина должна мне сообщать прямым текстом! И мне кажется, что самый простой способ это реализовать - сделать самое примитивное прерывание (interrupt)...


Можно было бы чуть изменить интерфейс между видеопроцессором и QuatCore: сейчас, когда мы запрашиваем GPUH / GPUL, а очередь результатов пуста, процессор останавливается до тех пор, пока этот самый результат не появится. Мы могли бы ввести ещё и таймаут, и поставить какой-то флаг (может, прямо флаг знака), свидетельствующий о нехорошей ситуации, но это требует проверять этот самый флаг каждый раз, когда мы запрашиваем данные с видеопроцессора, а это не раз и не два.

Причём опасность может представлять не только адреса GPUH / GPUL (а впоследствии и GPUPH / GPUPL) со стороны SrcAddr, но и адрес ACQ (Acquire) и TRK (Tracking) со стороны DestAddr. Они посылают новое задание на обработку, и если буфер входных заданий не переполнен - выполняются данные "команды" за один такт. Но если буфер заполнился - мы замираем в ожидании, когда же наконец хоть одна команда будет выполнена - и появится свободное место. Вот только, если у нас пропал видеосигнал - то и синхроимпульсы пропали, и мы можем ждать окончания работы до посинения.

Вставлять проверку на таймаут после каждой такой команды - как-то слишком жирно. Вставлять лишь "время от времени", в надежде, что худо-бедно "проскрипим" на таймаутах до этой проверки - вроде бы и можно, однако и здесь могут странные вещи произойти. Например, получая "мусор", процедура обнаружения точек их столько наобнаружит, что заполнит весь наш Heap (память для связанных списков) - и мы быстрее уйдём на Out Of Memory, из-за чего я начну искать, что же не так с моим алгоритмом, почему он так много точек обнаруживает, хотя на самом деле это тупо провод отошёл...

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

То есть, мы сейчас не будем стараться "сохранить контекст" (содержание регистров, в первую очередь PC, а также флагов) - нет такой необходимости!

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

Да, чтобы отобразить ошибку, неплохо бы УСПЕТЬ инициализировать Ethernet-контроллер (он даёт нам тактовую частоту, и нужно, чтобы он повысил её с 4 МГц до 25 МГц), и ещё инициализировать ЖК-экранчик (по крайней мере настроить его в 4-битный режим, т.к мы в своё время пожадничали на 4 лишних проводах :)) Но учитывая, что самое долгое в этом - подождать 1,5 миллисекунды на очистку ЖК-экранчика, думаю, достаточно будет сделать таймаут по синхроимпульсам хоть сколько-нибудь большим (1/10 секунды) - и тогда проблем не возникнет.

И ещё можно выбрать два варианта работы с прерыванием. Первый - запрос прерывания "нет сигнала" поступает непрерывно (интересная тавтология - непрерывное прерывание), и тогда нам нужно принять специальные меры, чтобы во время нашей обработки прерывания нас не отправляло на ПЕРВУЮ СТРОКУ этого обработчика! То есть, должен зажечься некий флаг "мы обрабатываем прерывание прямо сейчас, не трогайте нас!". Потом, по логике вещей, у нас могла бы быть возможность вернуться из этой обработки - и тогда флаг сбросится.

Второй вариант - самый простой по-моему - запрос прерывания длится ровно один такт, и следующий поступает ещё через 1/10 секунды, если сигнала по-прежнему нет. Как говорится, "дёшево и сердито"!

Давайте так и сделаем для начала. Глянем на модуль "QuatCore в сборе":


По сути, видеопроцессор трогать и не будем - он-то честно ждёт VSync и HSync. Лучше поставим отдельным модулем таймер наподобие Watchdog ("сторожевой пёс"), который начинает считать с нуля, надеется досчитать до упора (когда и выдаст прерывание), но приходящий сигнал VSync вечно сбивает его раньше времени!

Что-нибудь такое:

module VideoSignalWatchDog (input clk, input ce, input VSync, output NMI);

parameter CounterWidth = 16;

lpm_counter WDT (	.clock (clk),
			.clk_en (ce),
			.sclr (VSync | NMI),
			.cout (NMI));
defparam
	WDT.lpm_type = "LPM_COUNTER",
	WDT.lpm_direction = "UP",
	WDT.lpm_port_updown = "PORT_UNUSED",
	WDT.lpm_width = CounterWidth;

endmodule


На ce (Clock Enable) подадим выход ceo (Clock Enable - Output) от ШИМ-контроллера, который формирует сигнал "джойстика" на камеру, тупо чтобы сэкономить 5 бит делителя частоты.

А дальше всё просто. По каждому ce счётчик прибавляет единичку. Когда он дойдёт до конца, сформируется сигнал переноса, который и даст нам прерывание Non-Maskable Interrupt, и он же сразу же сбросит счётчик. Не сделай мы этого - NMI продержался бы 32 такта, пока не придёт следующий ce, а так - ровно 1 такт, как мы и хотим.

Но при нормальном ходе вещей счётчик не будет успевать дойти до предела - его непрерывно будет сбрасывать VSync.

Синтезируется эта хреновина в 18 ЛЭ.
Вообще, тут можно было бы ещё с всевозможными делителями поразвлекаться. У нас здесь много мест, где интервал надо выдержать "плюс-минус лапоть". Например, в модуле ЖК-экранчика есть счётчик, отмеряющий 1,5 мс, уходящие на очистку экрана. Он включается только при подаче соответствующей команды - и досчитывает до упора. Но так-то нас бы устроил интервал от 1,5 до 3 мс, а в таком случае можно было бы иметь просто генератор одиночных импульсов каждые 1,5 мс (не привязанный к ЖК-экрану), и ожидать ДВА импульса от него. Первый непонятно когда придёт (сколько пройдёт времени между подачей команды и его получением), зато до второго точно пройдёт 1,5 мс - готово! И тогда те же 1,5 мс могли бы сюда поступать на Watchdog, чтобы не городить длиннющие счётчики повсюду. Но пока лениво...

Далее, заглянем внутрь модуля FastUltimateQuatCore (когда-то был просто QuatCore, приставка Fast говорит о разгоне с 4 МГц до 25 МГц, а приставка Ultimate - об отказе от относительных адресов и замене "непосредственных значений" -64..+63 на 128 произвольных 16-битных констант. Старые версии тоже ещё сохранились на всякий случай), это непосредственно ядро:


"На этом уровне" тоже делать особо нечего - тут мы просто добавим новый вход NMI и пустим его аккурат в модуль QuatCoreUltimateFastPC (Program Counter), вот его потроха:


Самое простое и, вероятно, логичное - поставить адрес обработчика прерывания в QuatCoreCallTable.v, благо, эта таблица и так "собирается" компилятором! И останется только подвести туда вход NMI, а ещё соединить его по "ИЛИ" с выходом QuatCorePCisFuncCall - тогда прерывание будет работать так же, как вызов функции!

Правда, у нас вызов функции состоит из двух половинок. Одна из них - команда CALL0..CALLF из SrcAddr, заставляет прыгнуть по одному из 16 адресов занесённых в таблицу, и в то же время выдать на шину данных текущее значения счётчика инструкций PC (по сути, адрес возврата). Это у нас сработает. Но если мы всё-таки хотим возвращаться из процедуры, нужна вторая половинка, обычно [SP++], чтобы адрес возврата занести из шины данных в стек. В принципе, у нас есть шанс когда-нибудь дать такую функциональность и прерываниям. Для этого нужно подрихтовать буфер DestAddr из QuatCodeCodeROMwStall - сейчас он просто задерживает на один такт DestAddr, а тут, в случае возникновения прерывания, взамен "защёлкнет" ту же самую [SP++]. Но пока нам это не нужно :)

Пока что "ручками" добавим новый вход в QuatCoreCallTable, а также вставим OR2 и вход NMI. Вот что получается:


Теперь протащим проводок уровнем выше:


И ещё уровнем выше, где и поставим нашего "сторожевого пса":


Тут видно ещё два сигнала, "напрашивающиеся" на прерывания, это OFLO (Overflow), когда переполнилась очередь результатов видеопроцессора, т.е наш алгоритм "зашивается", не успевает вовремя обработать приходящие данные - и часть просто пропадает, и UFLO (Underflow), когда видеопроцессор выполнил все задания, а новых не поступило. Это опять же означает, что наш алгоритм не успевает обработать предыдущие строки - и не успел вовремя дать задания на последующие. Когда-то я хотел через RS-триггер эти штуки выводить на светодиоды, но теперь они все внутри корпуса, наружу только ЖК-экранчик и UART, так что правильнее опять же через процессор их "протянуть". Но не прямо сейчас...

И наконец, выходим на "самый высокий уровень", где весь процессор, видеопроцессор и периферия превратились в один "квадратик":


Самое "грязное" место, где торчит куча всяких "отладочных" проводов, типа LCD_data[0] и LCD_data[1]. Там были провода от 0 до 7, но из жадности мы сделали шлейф только от 4 до 7, а от 0 до 3 остались "для отладки" - подключать осциллограф и смотреть какие-то интересующие места.

По крайней мере, синтез по-прежнему проходит успешно, в 1367 ЛЭ на всё про всё: ядро, видеопроцессор, селектор синхроимпульсов с БИХ-фильтром перед ним, контроллеры UART, SPI, ЖК-экранчика и SRAM, и даже ШИМ для управления экранным меню камеры, и ещё немножко мусора вроде светодиода мигающего раз в секунду, хотя его уже никто не видит.

Ладно, на этой ПЛИС, 5576ХС4Т, есть 9984 ЛЭ - можно пока ещё не жадничать :)


На этом аппаратная часть выполнена. Осталось дописать программу, а также компилятор, чтобы он, увидев метку NMI, понял: "мы хотим использовать это прерывание" - и соответствующим образом сформировал QuatCoreCallTable.v...
Tags: ПЛИС, программки, работа, странные девайсы
Subscribe

  • Лестница для самых жадных

    В эти выходные побывал на даче, после 3-недельной "самоизоляции". Забавно, как будто зима началась! Особенно грязные галоши остались на улице, в…

  • Возвращаемся к макету

    Очень давно макетом видеоизмерителя параметров сближения не занимался: сначала "громко думал" по поводу измерения его положения на аппарате, а потом…

  • Минутка живописи

    В процессе разгребания содержимого квартиры (после нескольких ремонтов) дошёл, наконец, и до картин. В кои-то веки их повесил. Куда их вешать -…

  • Костыль ноутбуку и кабели Франкенштейна (это не я!)

    Продолжаю разгребать хлам, накопившийся за много лет, раз уж всё равно на карантине сижу. Довольно продуктивный день: починил ноутбук (грубо, но…

  • Атомный файлсервер, убитые петухи и харакири андроида

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

  • Ещё про яркий светильник и ИБП

    Всё-таки применил лежащее дома барахло наиболее простым образом: А ещё наконец-то замерял температуру теплоотвода яркого светильника на кухне,…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 10 comments

  • Лестница для самых жадных

    В эти выходные побывал на даче, после 3-недельной "самоизоляции". Забавно, как будто зима началась! Особенно грязные галоши остались на улице, в…

  • Возвращаемся к макету

    Очень давно макетом видеоизмерителя параметров сближения не занимался: сначала "громко думал" по поводу измерения его положения на аппарате, а потом…

  • Минутка живописи

    В процессе разгребания содержимого квартиры (после нескольких ремонтов) дошёл, наконец, и до картин. В кои-то веки их повесил. Куда их вешать -…

  • Костыль ноутбуку и кабели Франкенштейна (это не я!)

    Продолжаю разгребать хлам, накопившийся за много лет, раз уж всё равно на карантине сижу. Довольно продуктивный день: починил ноутбук (грубо, но…

  • Атомный файлсервер, убитые петухи и харакири андроида

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

  • Ещё про яркий светильник и ИБП

    Всё-таки применил лежащее дома барахло наиболее простым образом: А ещё наконец-то замерял температуру теплоотвода яркого светильника на кухне,…