nabbla (nabbla1) wrote,
nabbla
nabbla1

Categories:

"МКО через UART", часть 5, проверка командного слова

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

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



Речь идёт о моём конкретном приборчике, где из 30 доступных подадресов (00000 и 11111 - это "режим управления") используется только 10, 5 на приём и 5 на передачу. При этом старший бит подадреса играет роль бита чётности (сумма всех битов должна оказываться чётной), и подадреса брались по порядку:

0 0000  - подадрес режима управления,
1 0001 - FT (Flight Task) - полётное задание,
1 0010 - LT (Long rangeTarget) - параметры МДД,
0 0011 - ST (Short range Target) - параметры МБД,
1 0100 - AF (AFfine matrix) - матрица аффинного преобразования,
0 0101 - RA (RAw data) - прибор принимает «сырые данные»,
0 0110 - DA (DAta) - целевая информация,
1 0111 - не используем, т.к отличается  лишь 1 битом от КУ «11111»,
1 1000 - TM (TeleMetry) - телеметрическая информация,
0 1001 - IM (IMage) - передача изображения,
0 1010 - DU (DUmp) - передача дампа памяти,
1 1011 - не используем, т.к отличается лишь 1 битом от КУ «11111»,
0 1100 - RA (RAw data) - прибор передаёт «сырые данные»,
1 1101 - не используем, т.к отличается лишь 1 битом от КУ «11111»,
1 1110 - не используем, т.к отличается лишь 1 битом от КУ «11111».
0 1111 - не используем, т.к отличается лишь 1 битом от КУ «11111».


Тут можно очень долго искать закономерности. Например, во всех разрешённых (задействованных) подадресах используется РОВНО ДВЕ ЕДИНИЦЫ. Потому как из требования, чтобы сумма всех бит была чётной, вытекает либо НОЛЬ единиц (это режим управления), либо ДВЕ, либо ЧЕТЫРЕ. Но когда у нас четыре единицы, мы отличаемся всего одним битом от "11111", поэтому такие варианты мы забраковали все до единого!

И наверное, при реализации на "настоящих" логических элементах (AND, OR, XOR, NOT, NAND, NOR и пр) имело бы смысл нечто такое хитрое зашаманить. Но когда это ПЛИС, я могу заранее сказать, что определение правильности этих 5 бит потребует ровно 3 ЛЭ, если записать вот таким образом:

module VIPSsubaddrError (input [4:0] subAddr, output isError);
	wire [3:0] lsb = subAddr [3:0];
	wire Senior0 = 	(lsb == 4'b0001) |
			(lsb == 4'b0010) |
			(lsb == 4'b0100) |
			(lsb == 4'b0111) |
			(lsb == 4'b1000) |
			(lsb == 4'b1011) |
			(lsb == 4'b1101) |
			(lsb == 4'b1110) |
			(lsb == 4'b1111);
					
	wire Senior1 = 	(lsb == 4'b0000) |
			(lsb == 4'b0011) |
			(lsb == 4'b0101) |
			(lsb == 4'b0110) |
			(lsb == 4'b0111) |
			(lsb == 4'b1001) |
			(lsb == 4'b1010) |
			(lsb == 4'b1011) |
			(lsb == 4'b1100) |
			(lsb == 4'b1101) |
			(lsb == 4'b1110);
					
	assign isError = subAddr[4]? Senior1 : Senior0;
	
endmodule


Один логический элемент выясняет, корректны ли младшие 4 бита при условии, что старший (senior) равен нулю. Второй - корректны ли они при условии, что старший равен единице. Наконец, третий коммутирует на выход либо первого, либо второго в зависимости от старшего бита.

Мы как бы пользуемся тем, что в одном логическом элементе ПЛИС можно задать любую функцию от 4 бит.

Странно, что сам квартус не способен прийти к такой реализации, если ему то же самое задать хоть чуточку более отвлечённо. Я попробовал вот так:

assign isError =(subAddr != 5'b0_0000) &	//команды управления
		(subAddr != 5'b0_0011) &	//ST, Short range Target
		(subAddr != 5'b0_0101) &	//RA, RAw sata (принимаем с соседнего прибора)
		(subAddr != 5'b0_0110) &	//DA, DAta (целевая информация)
		(subAddr != 5'b0_1001) &	//IM, IMage
		(subAddr != 5'b0_1010) &	//DU, DUmp
		(subAddr != 5'b0_1100) &	//RA, RAw data (передаём на соседний прибор)
		(subAddr != 5'b1_0001) &	//FT, Flight Task
		(subAddr != 5'b1_0010) &	//LT, Long range Target
		(subAddr != 5'b1_0100) &	//AF, AFfine matrix
		(subAddr != 5'b1_1000) &	//TM, TeleMetry
		(subAddr != 5'b1_1111);		//команды управления (другой вариант


5 ЛЭ и всё тут. А наоборот, "показать глубинную суть вещей":

	wire [2:0] BitSum = subAddr[4] + subAddr[3] + subAddr[2] + subAddr[1] + subAddr[0];
	
	assign isError = (BitSum == 4) | (BitSum == 3) | (BitSum == 1);


а так и вовсе 6 ЛЭ.

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

Добавим этот отдельный модулёк в контроллер МКО:
wire isSubAddrError;
VIPSsubaddrError ErrDetection (
	.subAddr (curWordSubAddr),
	.isError (isSubAddrError));


Далее, нужно ещё совместить подадрес с признаком "приём/передача". Это мы уже выписывали:
//соответствие приёма/передачи подадресу					
wire isTransmitReceiveError = (curWordSubAddr[3] | curWordSubAddr[2] & curWordSubAddr[1]) ^ curWordDoTransmit;


Это касается "обычных команд". С командами управления данное выражение не справляется. С ними можно было бы также провести полнейший разбор, только в этот раз в сочетаниях "приём/передача" и "число СД / КУ", но этого я пока не хочу. В общем-то, меня больше всего пугает, если неверной командой будут затёрты области памяти, где лежат важные данные. В случае "обычных команд" это весьма вероятно: не сделай ограничений - будет доступ ко всему килобайту, и "затираться" может до 32 слов за раз. Но даже при нынешней реализации, команды управления в самом худшем случае запишут нам ОДНО слово либо по адресу 0x000, либо 0x1E0. Можем эти два слова оставить "жертвенными", и дело с концом.

Тогда сделаем как-то так:
wire isTransmitReceiveError = ((curWordSubAddr[3] | curWordSubAddr[2] & curWordSubAddr[1]) ^ curWordDoTransmit) & (~isServiceCommand);
wire isCWerror = isSubAddrError | isTransmitReceiveError;


CW значит Command Word, то есть проверяем корректность командного слова "как целое".

И теперь сделаем защёлкивание ошибки по приёму командного слова:

always @(posedge clk) if (isIdle)
	MessageError <= isCWerror;


Как и раньше, не стали "придираться": действительно ли пришло слово, и оно командное, и адресовано нам. Последнее значение, защёлкнутое при переходе из sIdle в sReceive, будет ВЕРНЫМ, а что шло до того - не важно.

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

assign MemWrReq = DataValid & RXisData & State[0] & (~MessageError);


Пока остановимся и проверим, что получилось.

По крайней мере, это безобразие синтезируется. Если брать вместе с "адресной заглушкой", часами реального времени, "фиктивным" передатчиком и модулем памяти, выходит 144 ЛЭ. Без проверок на ошибки было 138 ЛЭ, нормально, жить можно. Максимальная допустимая частота 74,63 МГц, сойдёт, сейчас у меня вообще 25 МГц тактовая.

Для начала запускаем уже имеющуюся симуляцию, где мы посылали полётное задание, а потом запросили 1 слово телеметрии, 32 слова изображения и 24 слова "целевой информации", где посерединке сидит метка времени. Всё в порядке, ничего не изменилось, в том числе запись в память прошла успешно.

Теперь опробуем послать всякую хрень:


Запросили одно слово данных с подадресов 0_0001 и 0_0010 - оба раза получили "отлуп" - только ответное слово с признаком "ошибка в сообщении", а слово данных передавать не стали.

А теперь возьмём вполне себе корректный подадрес 1_1000 ("телеметрия"), но попытаемся записать туда 4 слова, вместо того, чтобы прочитать:


Да, наш драндулет воспитанный. Он дождался, пока ему передадут "обещанные" 4 слова: BEEF, F00D, CAFE и FACE (начал вспоминать HexSpeak), и только после этого выслал ответное слово с признаком "ошибка в сообщении". Напомню, ответное слово без ошибок у нас 0x3000 (когда адрес устройства 6), а с наличием ошибки: 0x3400.

Дамп памяти показывает, что телеметрия переписана не была, см. адрес 0x100:


И ещё давайте поглядим на широковещательные команды. Передадим "параметры мишени дальней дистанции", но СРАЗУ ВСЕМ. Это лишено смысла, но логикой разрешено :)



Дождались получения 4 слов, и только после этого ушли в sIdle, при этом никакого ответа мы не дали, всё верно, на групповые сообщения отвечать нельзя! Ну и посмотрим, записались ли данные:


Ага, всё на месте.


Я доволен, провели практически полное покрытие кода - всё работает. Осталось ещё с командами управления разобраться, это уже завтра.
Tags: ПЛИС, работа, странные девайсы
Subscribe

  • Тестируем atan1 на QuatCore

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

  • Формулы приведения, что б их... (и atan на ТРЁХ умножениях)

    Формулу арктангенса на 4 умножениях ещё немножко оптимизировал с помощью алгоритма Ремеза: Ошибка уменьшилась с 4,9 до 4,65 угловой секунды, и…

  • Алгоритм Ремеза в экселе

    Вот и до него руки дошли, причина станет ясна в следующем посте. Изучать чужие библиотеки было лениво (в том же BOOSTе сам чёрт ногу сломит), писать…

  • atan на ЧЕТЫРЁХ умножениях

    Мишка такой человек — ему обязательно надо, чтоб от всего была польза. Когда у него бывают лишние деньги, он идёт в магазин и покупает какую-нибудь…

  • Ай да Пафнутий Львович!

    Решил ещё немного поковыряться со своим арктангенсом. Хотел применить алгоритм Ремеза, но начал с узлов Чебышёва. И для начала со своего "линейного…

  • atan(y/x) на двух умножениях!

    Чего-то никак меня не отпустит эта тема, всё кажется, что есть очень простой и эффективный метод, надо только его найти! Сейчас вот такое…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments