Category: авто

Category was added automatically. Read all entries about "авто".

QuatCore

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

До сих пор у меня передатчик UART подсоединялся к 16-битной шине данных процессора, но брал из неё только младшие 8 бит, остальные игнорировал. Для передачи текстовой информации самое то, особенно с появлением байтового режима доступа к памяти. Но вот передавать 16-битные данные становится очень большой проблемой. Для дампа памяти ещё нашлось решение, как раз-таки через байтовый режим прочитать сначала все старшие байты, потом все младшие, а уже на компьютере их "склеить", но тоже костыль, что ни говори.

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

То есть, я хочу, чтобы одна команда OUT, когда источником выбран UART, передавала бы два байта подряд. Какой сначала - старший или младший (endianness пресловутый) - это на наше усмотрение, главное потом на принимающей стороне не ошибиться.

Вроде бы халявная задача, а чего-то сегодня полдня соображал "как лучше" это сделать...

Collapse )

Завтра попробуем запустить. Сегодня ждал приезда заказчиков из РКК Энергия, приехал по такому случаю с утра, а оказалось, они так и не приедут, узнал об этом где-то час назад. Чего-то утром гораздо хуже мне соображается. Куда-то совсем не в ту степь полез, и только к 16:55 понял, как надо :) А тут уж и уходить пора.
QuatCore

Оба алгоритма захвата - в загрузочный сектор! (512 байт)

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

Всего они заняли 254 слова кода, или 508 байт, то есть по-прежнему влезли в один блок внутренней памяти ПЛИС (БВП, он же EAB, Embedded Array Block). Ровно в той ПЛИС, которую я мучаю, 5576ХС4Т, таких блоков 24 штуки, а в той, куда хотелось бы вписаться, 5576ХС6Т (дофига радстойкая, в т.ч к тяжёлым заряженным частицам) - их всего 10.

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

Итого уже 40% доступной памяти для ХС6Т мы заняли, а ещё алгоритм сопровождения нужен! Он довольно-таки "мерзопакостный"...

Collapse )

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


Ярко-зелёным показаны 4 точки, после того как их идентифицировали. В этот раз наиболее удобным мне показался порядок МБД-МДД2-МДД1-МДД3.

Синим выделен вектор с общей "экспонентой" 9, т.е значения X (от 0 до 2), Y, Z (от -1 до +1) нужно домножить на 29-1 = 256 метра.

Имеем X = 0x9591 = 38289 = 1,168 (в формате Q1.15). Умножаем на 256 - и выходит 299,13 метров.
Далее, Y = 0x0031 = 49 = 0,00149 (в формате Q1.15). Умножаем на 256 - выходит 38 сантиметров. Похоже, я и тут пожадничал в 4 раза (чтобы точность не потерять раньше времени), на самом деле должно быть 9,5 см "сдвиг вправо", т.к смотрим мы "левым глазом", а летим прямо по курсу.

И наконец, Z = 0xFE3D = -451 = -0,0138 (в формате Q1.15). Умножаем на 64 (помня, что "пожадничали") и получаем -0,881 метра. Это мы сейчас установили "началом координат мишени" центр стыковочного узла, но прибор закреплён на те самые 0,881 метра ВЫШЕ, вот и воспринимает картинку как сдвинутую вниз.

Кватернион (выделен фиолетовым) вообще получился единичным, т.е выражающий нулевой поворот. Да, так и должно быть, идём "прямой наводкой".

Это у нас работа по модельным данным, я макет мишени дальней дистанции так и не собрал до сих пор, всё с ближней дистанцией возился. По модельным данным оно приятно - всё совпадает :)
QuatCore

Алг. ближней дистанции, вычисление крена

Всех с прошедшими первомаем, днём радио и днём Победы!

А мы продолжим ковырять штуку... В общем-то, я говорил, что после вычисления аффинного преобразования (матрица 2х2 и вектор 1х2) дальше уже всё готово. Так примерно и есть, но мы чуть поменяли то, в каких регистрах что лежит, и не хочется грубо всё переопределять перед уже написанным кодом, лучше этот код чуточку подрихтовать, и посмотреть свежим взором, нельзя ли его улучшить?

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

Collapse )

Теперь программа "ближней дистанции" компилится в 157 слов кода (314 байт), вышли-таки на 8-битную адресацию ПЗУ, ну ничего не поделаешь, сложный алгоритм всё-таки. И сейчас посмотрим на симуляции, правильно ли всё работает.
QuatCore

Баг воспроизведён!

Запустил свой многострадальный алгоритм обнаружения на симуляции, с полноценной картинкой 1024х720 - и ровно в том же месте словил ту самую ошибку, UFLO (исчерпание заданий GPU). Это хорошо, значит, сейчас можно будет её рассмотреть "под микроскопом".



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


Только закончили отправлять задания по этой строке и теперь начали запрашивать результаты. Синхроимпульс прошёл около 30 тактов назад, сейчас идёт "полочка". Поэтому ждём.

Collapse )

Да, не ожидал такой ошибки, всё думал либо на недостаточное время обработки, то ли на глюк в программе, но никак не на ошибку АЛУ, которая там сидела и ждала своего часа СВЫШЕ ГОДА! Ну что ж, теперь первые 8 мс симуляции (а дальше я не делал) проходят правильно.

Сейчас попробую снова "в железе", может сейчас оно возьмёт и сделается от начала до конца?
QuatCore

Алг. обнаружения под новый АЛУ

Возвращаемся к нашим баранам, к алгоритму обнаружения ярких пятен на изображении В РЕАЛЬНОМ ВРЕМЕНИ. Когда последний раз его мучали на симуляции (на уменьшенном изображении всего с одним пятном), он тупо не успел обработать данные и вовремя не отправил задания видеопроцессору. Проблема в том, что начни обрабатывать настоящую мишень на минимальной дальности 0,5 метра и при самом неудачном ракурсе, когда 4 пятна встанут в ряд - и времени там не хватит точно также.

Поэтому ещё на 2 недели отвлёкся - дорабатывал АЛУ и потом отлаживал его. И теперь, прежде чем испытать алгоритм обнаружения, хочу "оптимизировать" его под новый АЛУ, переставить местами команды (где это допустимо) так, чтобы процессор максимально "распараллеливался" - пока АЛУ думает о своём, остальной процессор может шуровать в памяти, общаться с видеопроцессором и т.д.

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

Collapse )

В общем, ничего особенно не сделали, по мелочи. Но хоть вспомнили, что за зверь.

Испытания новой АЛУ, нахождение крена

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

;состояние регистров к этому моменту
;X = AffineMat (константная матрица 3х4, чтобы посчитать преобр)
;Y = Points2D
;Z = Matrix (матрица 2х2 и вектор 1х2, пока не AfTransf)
;i=j=k=0
;Inv неизвестен
;C, Acc - пофиг наверное
FindRoll	proc
	;нам понадобятся [Z]+[Z+3] и [Z+1]-[Z+2]
		Y		QuatY 	;в этом кватернионе построим,используя Y/Z значения как временные
					;(потом они занулятся)
					;а можно Y вместо X, если надо
		i		1
		j		3
@@sico:		Acc		[Z+i]
		Inv		i
		PM		[Z+i^j]
		[Y+i]		Acc
		iLOOP		@@sico
	
;теперь наших друзей надо отнормировать, причём динамический диапазон очень велик
;максимум 13 итераций, давайте столько и делать...
;здесь у нас появляется беззнаковое число, без него получалось бы очень грустно	

		CALL NormSiCo

;здесь у нас i=j=k=Inv=0
	
;теперь синус-косинус превращаем в кватернион, то есть в синус-косинус половинного угла
;если co>0, то
;QuatX = (1+abs(co))/2,
;QuatY = si/2
;в противном случае
;QuatX = si/2,
;QuatY = (1+abs(co))/2
	
;сейчас X = AffineMat (матрица 3х4, уже неактуальна)
;Y = QuatY (компоненты co / si),
;Z = Matrix (матрица 2х2 и вектор 1х2, к ним ещё вернёмся)
;i=j=k=Inv=0
					
		ABS		[Y+k]			
		DIV2		Acc
		ADD		16384

	;флаг S (sign) сейчас показывает знак co, что для нас очень полезно
		JGE		@@skip
		i		1		;выходит i=S
@@skip:		X		QuatA
		[X+i]		Acc
		j		1
		DIV2		[Y+1]
		Y		QuatA
		[X+i^j]		Acc		;по сути, Y+(~S)
		CALL		NormSiCo	;подготовили первые 2 компонента кватерниона
					
	;сейчас X=Y=QuatA (2 компоненты кватерниона),
	;Z = Matrix
	;теперь помножаем две матрицы, одна в явном виде - Matrix (Z)
	;вторая - задана неявно, в виде co / si (в QuatY)
	;результат идет в AfTransf
	;здесь i=1, k неизвестен, j=0, Inv=0
		Y		QuatY
		X		AfTransf	;сюда результат складируем
		i		1	;номер строки результата, и строки co/si
@@i_loop:	k		1	;номер столбца результата, и столбца AfTransf
@@k_loop:	j		1	;номер столбца co/si и строки AfTransf
		ZAcc		RoundZero	;обнулить до 1/2 мл. разр
@@j_loop:	C		[Y+i^j]	
		FMPM		[Z+2j+k]
		jLOOP		@@j_loop
		[X+2i+k]	Acc
		kLOOP		@@k_loop
		iLOOP		@@i_loop

	;здесь у нас i=j=k=0
	;теперь у нас должна получиться матрица, включающая в себя масштаб и ракурс (ужатие вдоль некоторой оси), но не крен...
	;ещё кватернион подчистим - по Y,Z может лежать всякий мусор
		[Y+k]		0
		[Y+1]		0
	FindRoll	endp


Как обычно, сначала прикинем, как можно этот код "оптимизировать" под новое АЛУ, не увеличивая его размера, и сравним выполнение на старом и новом АЛУ.

Collapse )

Что ж, целых две ошибки обнаружили - обе исправили. Выполнение самую чуточку ускорилось, и то хлеб.

Следующая часть: измерение масштаба.
QuatCore

Алгоритм обнаружения на симуляции (4)

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

Оказалось: нет, явно что-то не то!



Обведённое сверху число - номер строки изображения, согласно программе. Снизу - согласно генератору тестового изображения. Они отличаются на 3, и это нехорошо: они вообще-то должны совпадать, но мы с количеством верхних строчек чуть запутались, поэтому у нас с самого начала было расхождение на 2:



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

Надо в этом разобраться...

Collapse )

Вот так вот, времени тупо не хватило!

Да, мы молодцы - сразу же начали с наихудшего случая - дистанции 0,5 метра, и такое "удачное" расположение мишени, что она влезает вся. В результате у нас самые крупные пятна, чуть ли не 120х120 пикселей, из-за чего и приходится довольно много пикселей "перемалывать" силами QuatCore.

Сейчас, наверное, на симуляции увеличу время back porch, чтобы посмотреть - "а если тактов хватает - то всё будет правильно". А там видно будет. Но сначала придётся вернуться к бумажкам...
QuatCore

Опять алгоритм обнаружения

Достал он меня, но надо доделывать, всё остальное фактически готово.

В прошлый раз, неделю назад, остановились на том, что компилятор неправильно воспринимал литералы с отрицательным знаком, например "Nil EQU -32768", из-за чего у нас не устанавливался правильно флаг TaskPending (о том, что мы ещё не отправили задания по предыдущему пятну), и всё рушилось.

Но когда компилятор поправили, программа снова не заработала нормально "в железе", приводя к "сбоям синхронизации", а под конец - опять к "исчерпанию заданий GPU". Поэтому ничего не остаётся, как запустить подправленную программу на симуляции и посмотреть, что там происходит.

Такая у нас картинка, 128х128, ч/б (1 бит):
Simulation1.png

и мы в порыве оптимизма начинаем со строки 14 (0x0E). Если начало прошло точно также, как прежде, у нас должно быть одно обнаруженное пятно (61;11) диаметром 3, и выданы задания на отрезки [0;59], [60;62], [63;127] и HSync. Сейчас поглядим, так ли это?



Collapse )
Ещё одной ошибкой меньше, но какая-то пакость там ещё осталась...
QuatCore

Алгоритм обнаружения на симуляции

На удивление долго эту симуляцию получал - сразу несколько подводных камней выползло. Уже не раз и не два замечаю: Quartus очень легкомысленно относится к инициализации регистров! Иногда инициализирует как написано - а зачастую НЕТ. Вот и сейчас, в первый раз процессор тупо "не запустился" - вижу, что висит SrcStall=1 и DestStall=1 - да так и висит, и мы остаёмся в PC=0 до скончания времён. Стал искать, каким образом так получилось, повтыкал побольше "выводов" - и тут-то всё запустилось как надо!

Потом пришлось вспоминать "особенность" моего модуля FastFreqDivider. Всем он хорош, но при "первом включении" отсчитывает больше, чем надо. И в генераторе тестового изображения он "превзошёл сам себя" - там было задано количество ПОЛЕЗНЫХ строк изображения: 128, и ещё 28 строк сверху (как в реальном сигнале CVI) и 10 строк снизу. Я посчитал, сколько времени должен занять один кадр - 2,67 мс, и задал время симуляции в 4 мс. Какое же было моё удивление, когда к окончанию отрезка первый кадр так и не закончился, и кадровый синхроимпульс не пришёл!

Оказалось: у меня для формирования кадровых синхроимпульсов стоит этот самый несчастный FastFreqDivider, для деления в 166 раз в нём используется 8-битный счётчик, который первый раз успевает досчитать до 256! Вот поэтому и выходит вместо 2,67 мс уже 4,12 мс - вот оно и вышло.

Теперь вот я забыл, как работает регистрация кадрового синхроимпульса, как так выходит, что только после СТРОЧНОГО импульса, идущего за кадровым, у нас хоть что-то сдвинулось с места:
QuatCoreAndGPU_for_simul.png

Collapse )

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

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

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

Алгоритм обнаружения, "барабанная дробь"

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


Как-то так. Яркость 3 вполне подходящая. Не забываем теперь добавить строку "IR 3" ближе к началу программы обнаружения точек.

Далее, надо вспомнить, что позавчера мы "поигрались" с регистрами i,j,k - до этого чуть ли не год мы их не трогали, держали 5-битными, а тут решили k уменьшить до 3 бит, чтобы на нём сделать регулировку яркости, а i - вообще до 1 бита, потому что он нам был не нужен. Сейчас всё вернём на 5 бит - не будем пока жадничать!

Запуск - и...
Collapse )