Category: техника

Category was added automatically. Read all entries about "техника".

QuatCore

"МКО (Mil-Std1553) через UART", часть 2

Автомат Калашникова - устройство, превращающее стек в очередь (автора не знаю)

Мы торжественно написали заголовок, пора наполнять модуль содержанием!

В первую очередь, разберёмся с состояниями нашего конечного автомата.

Понятное дело, sIdle - "ожидание". В этом состоянии мы сидим, пока не получим командное слово, адресованное НАМ, не важно, корректно ли сочетание "приём/передача - подадрес - количество слов". Как только это случилось, переходим в состояние sReceive - получение слов данных. При этом информации из командного слова достаточно, чтобы знать, сколько слов ДАННЫХ должно прийти (могут вклиниться командные и ответные слова, если это "формат 3", но их мы отличим). Мы должны оставаться в состоянии sReceive, пока счётчик оставшихся слов не упадёт до нуля. Может оказаться, что изначально принять надо НОЛЬ слов (либо данные должны отправить МЫ, либо это одна из команд управления, не содержащая слова данных) - не страшно, мы можем с чистой совестью перейти в sReceive аж на ОДИН ТАКТ (40 наносекунд) и тут же пойти дальше.

Collapse )

На сегодня хватит... Ещё не всё реализовали, остаётся формирование "ошибки сообщения", и вообще ответного слова (про его содержание самую малость забыли!), корректную обработку команд управления, а также автоматическая проверка заголовков сообщений и CRC. Но не всё сразу, думаю сначала эту штуковину отладить, а потом уже потихоньку нарастить.
QuatCore

"МКО (Mil-Std1553) через UART", часть 1

Громко подумали, пора начать ковыряние.

Вообще, я очень надеюсь, что написанный сейчас модуль практически без изменений подойдёт для "нормального" МКО. Там, разве что, ещё логику резервирования надо будет продумать, когда два приёмника, два передатчика, и ответ надо посылать по той шине, по которой мы получили запрос.

Сейчас идея, что этот контроллер работает независимо от процессора, напрямую обращаясь к памяти. Это "Оконечное Устройство" (ОУ, оно же Remote Terminal), т.е оно само не может инициировать информационный обмен, только отвечать контроллеру шины (КШ, Bus Controller).

И сделаем "задел" для реализации по ГОСТ 52070-2003 задания адреса оконечного устройства с помощью перемычек, хотя на первое время они будут "виртуальными" внутри ПЛИС :)

Не буду пытаться сделать "универсальный модуль на все времена", потому как неизбежно получится что-то вроде 1895ВА2Т, на которую под 300 страниц документации, где ещё попробуй разберись! Реализую лишь те функции, что нужны мне конкретно в этом приборе.

Начинаем традиционно с заголовка, тут он очень упитанный:
module MilStdRemoteTerminalController (input clk,
		//интерфейс с приёмником МКО
		input [15:0] D, input RXisData, input DataValid,
		//интерфейс с передатчиком МКО
		output [15:0] Q, output TXisData, output start, input TxBusy,
		//интерфейс с оперативной памятью (малого объёма, около 1000 слов)
		output [MemWidth-1:0] Addr, input [15:0] MemIn, input MemReady, output MemWrReq, output MemRdReq,
		//интерфейс с часами реал времени
		output sync, input [15:0] TimeStamp,
		//интерфейс с адресной заглушкой
		input [4:0] OurAddr, input AddrParity);
		
parameter MemWidth = 8;




Collapse )

Нда, снова громко подумали, написав аж 15 строчек кода... Продолжение следует! Там уже возьмёмся всерьёз.
QuatCore

"МКО (Mil-Std1553) через UART", часть 0

Некая подготовительная работа, конечно, уже проведена, ровно для этого мы сделали 16-битные передатчик и приёмник UART: они не только удобнее согласуются с 16-битным процессором, отправляя по одному слову за раз, но и куда ближе к этому самому МКО (ГОСТ Р 52070-2003), не на физическом уровне конечно (там манчестерский код и безусловная гальваническая развязка через трансформатор), но на логических. А дальше просто "поменяю" приёмопередатчик, подключённый к ПЛИС, и будет мне счастье.

А то паять два устройства МКО, общающихся друг с другом как-то стрёмно: они вполне могут нормально заработать, обмениваться информацией, только это будет ни разу не МКО, а какой-то "свой диалект" :) Покупать на свои PCIную плату чего-то совсем не хочется, последний раз когда я спрашивал цену, озвучивали 66 000 рублей, и ещё не факт что физическому лицу продадут. Где-то на предприятии, может даже в отделе, должен лежать компьютер с установленной платкой МКО, но пока удобнее всё отлаживать "у себя", а за этот компьютер засесть, когда уже почти всё будет готово.

В штатном приборе приёмник МКО явно должен быть достаточно умным, чтобы хотя бы "отфильтровывать" все командные слова, адресованные "не нам". Уж больно их много: устройств сидит чуть ли не под завязку, 30 штук, и каждого по крайней мере 5 раз в секунду опрашивают, а то и побольше: отдельно выдача целевой информации и отдельно телеметрия. И если бы нам приходилось каждый раз отвлекать процессор на такую фигню, он бы точно запарывал каждый кадр изображения, там его отвлекать нельзя!

Я стал думать, насколько это легко, "отпарсить" весь поток информации и выделить адресованную "нам" и на некоторое время впал в полнейший ступор, как же нам слово данных от командного слова отличить?


Ведь в слове данных могут произвольные 16 бит лежать, чего бы им не совпасть с определённым командным словом? Получается, надо чётко прослеживать логику посылок, типа "вот сейчас была пауза, значит первое слово - командное, в нём было запрошено 32 слова данных (СД). Значит, сейчас отсчитываем 33 слова: сначала ответное, потом СД, а первое после них - это и будет следующее командное слово!" И всё бы хорошо, но стоит один раз ошибиться - и можно по "мусору" из слов данных очень долго строить соответствующие цепочки и отлавливать непонятно что. Чисто по паузам ориентироваться?

Потом вспомнил, где собака зарыта...

Collapse )

В общем, что-то начинает проглядываться. Вот думаю, может сделать-таки здесь DMA, причём приоритет всегда за процессором, а контроллер информационного обмена может и подождать пару тактов, всё-таки информационный обмен весьма нетороплив, одно слово за 20 мкс, это 500 тактов!

Была другая идейка, но возможно она слишком "толстая". Там пара модулей памяти воткнуты между процессором и этим контроллером. В первый модуль процессор может только записывать, в любое время, а контроллер может читать в любое время (память в ПЛИС двухпортовая). Второй модуль - всё наоборот, причём адреса "на запись" и "на чтение" по сути они делят. Например, процессор запишет по адресу "0" - тем самым передаст первое слово целевой информации. А прочитает по адресу "0" - получит первое слово полётного задания. Но с DMA можно сделать контроллер более "самостоятельным" - с дампом памяти он сам справится, не заставляя процессор чего-то готовить :)

Такие вот мысли вслух...
QuatCore

"Часы реального времени" для QuatCore

На мой приборчик должны каждые 100 мс прибывать сообщения "синхронизации со словом данных" по МКО (Mil-Std 1553), в которых будет передаваться число от 0 до 99, "номер текущего вычислительного такта". Просто по возрастанию, и после 99 последует 0. Тем самым, мы сможем обозначить время в интервале 10 секунд.

Получая кадр изображения, мы должны будем зафиксировать метку времени, когда он был получен (скорее даже "середину экспозиции", т.е какому моменту будут соответствовать те параметры сближения, что мы получили). По протоколу, это будет 16-битное число в формате UQ7.9, то есть беззнаковое с фиксированной запятой. Старшие 7 бит - это тот самый "номер вычислительного такта", от 0 до 99, но благодаря младшим битам можно будет отметить момент времени с точностью до ≈ 200 мкс, этого вполне достаточно, учитывая, что просто на считывания кадра с матричного фотоприёмника 1205ХВ014 будет уходить 10 мс, это при ПЛИС, "разогнанной" до 50 МГц (пока у меня 25 МГц), ну может 5 мс, если дойти до 100 МГц, и это уже предельное значение для этого фотоприёмника.

Вот думаю сделать отдельный модулёк, который будет вести счёт времени в этих 16 битах (используя обычную тактовую частоту), синхронизироваться по слову данных, а также отмечать момент получения кадра.

Collapse )

Как именно его "прикрутить" к остальному проекту - ближе к делу посмотрим. Не хочется из-за такой мелочи расширять мультиплексор шины данных QuatCore, он и так здоровенный. Лучше бы ближе к информационному обмену воткнуть...
QuatCore

"16-битный" приёмник UART - окончание

Где-то неделю назад мы попробовали сделать приёмник UART, который, получив один стартовый бит, пытался получить 2 байта подряд без дополнительной синхронизации. Когда передатчиком RS485 выступал дешёвый USB-"свисток" на основе CH340C без кварца, "не взлетело", на один бит мы "съехали" на втором байте.

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

Collapse )



Работает!

Сначала передаёт в байтовом режиме "ПрЮвет", затем начинает давать "дамп памяти" в 16-битном режиме (см 16-битный передатчик UART-окончание), а потом просто ждёт 16-битной посылки и тут же ретранслирует её назад.

Как видно, если я действительно посылаю 2 символа, ровно они и возвращаются. Попытался послать 3 символа - получил мусор, это нормально, передатчик макета начал посылку, пока ещё не окончилась передача с компьютера, вот и вышла коллизия.

А вот когда я послал 1 байт - не получил никакого ответа, зато на следующие 2 байта получил ровно их, т.е "восстановление" от случайно переданного байта действительно работает.

Неплохо: теперь я смогу "малой кровью" посылать на свой макет "исходные данные", матрицу аффинного преобразования и пр., не заморачиваясь на "склеивание" байтов в слова.

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

Счётчик в кодах Грея - окончание

Начало, продолжение

Осталось за малым: всё-таки реализовать "обычный режим", где дойдя до крайнего значения, счётчик сразу перескакивает в начальное, без хитрого реверса, который мы наблюдали вчера. А ещё сделать разрешение работы clk_en и вход синхронной загрузки. И проверить, что всё работает и при другом количестве бит.

Collapse )

Проверим для начала работу clk_en и режим "без реверса":


Всё верно: пока clk_en=0, вообще ничего не делаем, потом приступаем. Дойдя до 8 = 4'b1000, сразу переключаемся в 0 = 4'b0000, и повторяем всё то же самое, как ни в чём не бывало.

Теперь ещё опробуем синхронную загрузку:


Видно, что dummy, вместо того, чтобы переключиться в очередной раз, стал равным "чётности" поступившего значения E = 4'1110, т.е 1. И как видно, счёт продолжился в правильном направлении, что не может не радовать.

И глянем Width=8. Увы, отсинтезировалось оно в 25 ЛЭ, слишком много на мой вкус. Ну хорошо, не смог один бит вместить в 1 ЛЭ, вместил в 2 ЛЭ, это было бы 16, плюс "фиктивный бит" dummy, это 17. Плюс логика "горизонтального XOR" между 8 значениями - это ещё 3 ЛЭ, итого 20. Как так-то?? Но хотя бы работает правильно:

И предельная частота для моей ПЛИС 5576ХС4Т: 76,92 МГц, худо-бедно.

Главного достигли: получили параметризуемый модуль. Можно задавать Width от 3 и вверх. Вообще, могли бы сюда включить очередной generate, чтобы отдельно рассмотреть случаи 1 и 2, "оставим это читателю в качестве упражнения".

Остаётся вопрос: а нафига вообще он нужен? Ну, я хочу с ним один опыт провернуть, но возможно чуть позже...
QuatCore

Счётчик в кодах Грея - продолжение

Начало здесь.

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

Чтобы сообразить, как он работает, сначала вспомним, как работает самый обычный двоичный счётчик:

0000
0001
0010
0011
0100
0101
0110
0111
1000
...


Самая простая разновидность - это "счётчик пульсаций", он же "асинхронный счётчик", он же ripple counter. Самый младший бит переключается по фронту тактовой частоты, а каждый следующий бит переключается ровно тогда, когда ПРЕДЫДУЩИЙ БИТ переключается с единички на нолик. Если взглянуть на ряд чисел выше, увидим ровно такую закономерность.

Но на ПЛИС делать такие счётчики крайне не рекомендуется, там используют СИНХРОННЫЙ счётчик. Смысл в том, что каждому биту "заранее сообщается", должен ли он переключиться по ближайшему фронту тактовой частоты.

Младшему биту всегда надо переключаться. Следующему за ним - только когда в младшем бите единичка. Это значит, по фронту произойдёт перенос, поэтому и нам надо переключиться. Предпоследнему биту (из нашего примера) надо переключиться, если два младших бита единичных, только тогда произойдёт перенос в наш бит, и так далее. Если использовать D-триггеры, получим такую вот схему:


Collapse )



Ну красота же! Видно, что на каждом такте переключается только один выход. Здесь я не стал делать специальный код для старшего бита, в результате дойдя до последнего значения 1000, счётчик "развернулся задом наперёд", став проходить те же 16 позиций в обратную сторону!

Остаётся добавить несколько полезных входов: clk_en, sload и D, а также ввести "обычную" версию кода Грея, когда после 1000 всё-таки наступает 0000, и цикл в точности повторяется.

Изучать AHDL, чтобы вместить счётчик в N бит в N ЛЭ я уж не буду пока. Как-нибудь потом :)
QuatCore

Счётчик в кодах Грея

Очередная шлея под хвост попала. В принципе, мне такие счётчики ВОТПРЯМЩАС не нужны, так, "идейки" всякие бредовые, но вот захотелось. Вообще, я тут "на чемоданах сижу", вот-вот на поезд в Питер, за фотоприёмными матрицами, и чем-то серьёзным в это время заниматься все равно не получается.

Так вот, я с удивлением обнаруживаю, что готового библиотечного модуля счётчика в кодах Грея от Альтеры/Интела нет (по кр. мере под Flex10k), и "гугление" (точнее DuckDuckGo - "кряканье?") практически ничего не дало. Есть видюшки от вездесущих индийцев, где они на примере счётчиков Грея объясняют, как разрабатывается конечный автомат, но там 2-3 бита всего, и как "автоматически" расширить на большее - непонятно. Несколько раз натыкался на модули, где выходы ОБЫЧНОГО БИНАРНОГО СЧЁТЧИКА преобразовывались в коды Грея, либо ещё веселее - в регистре хранился текущий выход в коде Грея, он преобразовывался в бинарный, прибавлялась единичка, результат назад в Грея - и на вход этого регистра. Мазохисты, блин!



Сколько-нибудь полезная информация нашлась на сайте Интела, в виде сгрызенных им обломков сайта Альтеры. А именно, предлагался модуль 8-битного счётчика Грея на VHDL, а ещё некий Application Brief 135, подсказывающий, как можно очень эффективно реализовать такой счётчик на Flex 8000, на языке AHDL, альтеровский язык, позволяющий залезть в "потроха" логических элементов и напрямую указать, что и как там коммутировать. Вот только это должен был быть комментарий к файлу, который нужно было достать через BBS, по указанному телефону. 1994 год, чо :) Без файла не шибко понятно, что к чему.

Так что самое время предложить свою параметризуемую реализацию такого счётчика, но сначала чуть расскажу, что это вообще такое и для чего нужно.

Collapse )

Продолжение следует...
QuatCore

"16-битный" приёмник UART

Чуть-чуть "размялись" на передатчике (раз, два) - теперь задача посложнее, заставить приёмник UART выдавать на шину сразу по 16 бит данных. Принимать всегда сложнее, чем передавать, поскольку неизвестно точно, как себя будет вести передатчик. Может варьироваться скорость передачи, неизвестно, в какой момент эта передача начинается, да и не возбраняется компьютеру (или кто там ещё будет данные посылать) делать паузу между байтами, произвольной длительности, сам по себе UART это разрешает.

Сейчас немножко посмотрел на осциллографе, как работает USB-RS485 хренька за 300 рублей, на основе чипа CH341. Как оказалось, он НИКАКИХ ПАУЗ между байтами НЕ ДЕЛАЕТ. Его просишь передать "посылку" - и она идёт сплошняком. Кажется, что и здесь можно не заморачиваться и представить два байта как одну посылку, посередине которой располагаются стоповый и стартовый биты. Но здесь это чревато: скорость передачи должна довольно точно поддерживаться и соответствовать номиналу, иначе получим сбои синхронизации...

Collapse )

Что ж, по крайней мере с дешёвым переходником USB-RS485 эта хрень правильно работать не желает. Придётся сделать чуточку сложнее. Продолжение следует...
QuatCore

"16-битный" передатчик UART - окончание

Сегодня на удивление быстро с этой штукой разобрался:


Ну как, то есть я уверен, что UART работает правильно, что на 8 битах, что на 16, но почему-то алгоритм в этот раз точки в другом порядке расставил, и при попытке посчитать параметры сближения, получил крен 180° (!) и дальность меньше чем надо.

Ладно, с этим скоро разберёмся, посмотрю историю коммитов, что же я там поломал в последний раз, и нафига. А сначала подробности про UART.
Collapse )

"Ложная тревога": забыли в проекте "для железа" выставить параметр ijkEnabled=1, "включающий" одноимённую команду. А в данных алгоритмах она теперь вовсю используется, удобная вещь!

После очередного синтеза уже получил что надо:


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

А вот что за "мусор" внизу возник - ни малейшего понятия... Наверное, опять USB Blaster "шалит", а там посмотрим.