nabbla (nabbla1) wrote,
nabbla
nabbla1

Categories:

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

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


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

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


Вот его код:
`include "math.v"

module QuatCore16bitUARTtx (input clk, input is16bit, input st, input [15:0] DataBus, output txd, output busy, output isTX);

	parameter CLKfreq = 4_000_000;
	parameter BAUDrate = 1_000_000;

	localparam sIdle 	=	5'b00000;
	localparam sStart0	=	5'b01100;
	localparam sB0	    	=	5'b01101;
	localparam sB1		=	5'b01110;
	localparam sB2		=	5'b01111;
	localparam sB3		=	5'b10000;
	localparam sB4		=	5'b10001;
	localparam sB5		=	5'b10010;
	localparam sB6		=	5'b10011;
	localparam sB7		=	5'b10100;
	localparam sStop0	= 	5'b10101;
	localparam sStart1	=	5'b10110;
	localparam sB8		=	5'b10111;
	localparam sB9		=	5'b11000;
	localparam sBA		=	5'b11001;
	localparam sBB		=	5'b11010;
	localparam sBC		=	5'b11011;
	localparam sBD		=	5'b11100;
	localparam sBE		=	5'b11101;
	localparam sBF		=	5'b11110;
	localparam sStop1	=	5'b11111;

	wire [4:0] State;
	wire isStopState;
	wire isIdle = (~State[4]) & (~State[3]); //shortcut as not all states are used
	
	wire DoStart = st & isIdle;
	wire ce; 	//count enable
	reg r_ce = 1'b0;
	reg r_set = 1'b0;
	always @(posedge clk) begin
		r_ce <= ce;
		r_set <= ce | DoStart | isIdle;
	end
	
	wire [4:0] InitValue = is16bit? sStart0 : sStart1;
	
	lpm_counter StateMachine (
				.clock (clk),
				.cnt_en (r_ce),
				.data (InitValue),
				.sload (DoStart),
				.q (State),
				.cout (isStopState) );
	defparam
		StateMachine.lpm_direction = "UP",
		StateMachine.lpm_port_updown = "PORT_UNUSED",
		StateMachine.lpm_type = "LPM_COUNTER",
		StateMachine.lpm_width = 5;

	localparam DividerBits = `CLOG2(((CLKfreq + BAUDrate / 2) / BAUDrate - 1));
	localparam Limit = (CLKfreq + BAUDrate / 2) / BAUDrate - 2;
	localparam UpLimit = (1 << DividerBits) - 1 - Limit;

	lpm_counter Divider (
				.clock (clk),
				.sset (r_set),
				.cout (ce) );
  defparam
    Divider.lpm_direction = "UP",
    Divider.lpm_port_updown = "PORT_UNUSED",
    Divider.lpm_type = "LPM_COUNTER",
    Divider.lpm_width = DividerBits,
    Divider.lpm_svalue = UpLimit;    
							
	reg [18:0] ShiftReg = 19'b1111_1111_11_1111_1111_1;
	assign txd = ShiftReg[0];

	assign busy = st & (~isIdle);
	assign isTX = ~isIdle;

always @(posedge clk) if (DoStart | r_ce)
		ShiftReg <= DoStart? {DataBus[15:8],2'b01, DataBus[7:0], 1'b0} : {1'b1, ShiftReg[18:1]};

endmodule


Появился ещё один вход, is16bit. Когда на нём 1, будем передавать 2 байта подряд (все 16 бит с шины данных), а если 0 - то только 1, младший байт.

Как видно, "командоаппарат" разжирел немного, до 5 бит, и если раньше запуск происходил с помощью входа sset (synchronous set - загрузить константу, указанную в параметре svalue), то теперь с помощью sload, а значение поступает на вход data. Оно как раз и выбирается входом is16bit.

При указанных параметрах (тактовая частота 4 МГц, скорость передачи 1 МБит/с, я такие задавал, чтобы удобно смотреть на симуляции, не слишком много проматывать) этот модуль синтезируется в 36 ЛЭ, из них 28 используют регистры. Неплохо, мне кажется.

Выбор режима производится с помощью команды SIO (Select I/O) - до сих пор мы использовали два бита, чтобы выбрать периферийное устройство: UART, SPI или LCD, и ещё два бита, чтобы выбрать одно из устройств SPI: Ethernet, SD-карточку или медленный АЦП. Теперь добавляется пятый бит, определяющий режим UART: байты или 16-битные слова. Задаём новую константу в файле QuatCoreConsts.inc:

;константы для аргументов QuatCore
;можно было бы их в сам компилятор "зашить", но пущай так
.data ;костыль нашего компилятора - он ищет EQU только в сегменте данных

;устройства ввода-вывода. Выбор производится командой SIO
UART		EQU	0
LCD		EQU	1
ETH		EQU	2
SD		EQU	10
ADC		EQU	14

;для передачи 16-битного слова каждой командой OUT
WORD_UART 	EQU 	16

;константы, которыми можно инициализировать аккумулятор, командой ZAcc
MinusThreeHalf	EQU	0
MinusOne	EQU	1
ThreeHalf	EQU	2
RoundZero	EQU	3


Затем я дописал в программу ShortRangeAffine.asm (в которой теперь оба алгоритма захвата - дальней и ближней дистанции) такие "отладочные" строки:

; и давайте выдадим результаты
; но сначала для теста - обычный байтовый режим
	OUT	'П'
	OUT	'р'
	OUT	'Ю'
	OUT	'в'
	OUT	'е'
	OUT	'т'
	SIO	WORD_UART
	SP	Points2D
	i	23		
@@show:	OUT	[SP++]
	iLOOP	@@show


Хотел убедиться, что байтовый режим мы не "запороли" (это же совсем не очевидно, что он останется как был - модуль заметно отличается), для чего выдали старое доброе "ПрЮвет". А потом уже переключились на 16-битный режим и решили выдать 24 слова: сначала координаты 8 точек (это уже 16), затем вектор параллельного переноса и, наконец, кватернион взаимной ориентации (на данный момент: кватернион КРЕНА).

Точнее, первый раз я не смог правильно посчитать число слов: почему-то 8 точек принял за 8 слов, и получилось у меня 16 в общей сложности. Попробовал запустить - и получил совсем коротенькое сообщение, приведённое в самом верху. В байтовом режиме всё было выведено правильно, вот только в 16-битный мы так и не переключились!

К счастью, "все ходы записаны" - я сразу нашёл, что это компилятор оказал нам медвежью услугу. Он "знал", что команда SIO принимает только младшие 4 бита, и чтобы не плодить сущностей (непосредственные значения в одноимённую таблицу), заменила WORD_UART = 16 нулём, т.к младшие 4 бита у них совпадают.

Ага, нужно поменять конфиг, описание команды SIO:

  object TQuatCoreCommand
    Key = 'SIO'
    Code = 16
    Mask = 240
    DataMask = 31
    Description = 'Selects I/O device'
    Place = [cpDest]
    Resources = [crIO]
    DataType = dtNumeric
  end


Нужно было просто поменять DataMask с 15 на 31, т.е "добавить ещё один бит". Компилируем ещё раз, и получаем результат подлиннее, обведённый красным. Тут уже после строчки "ПрЮвет" пришло ровно 32 байта, т.е действительно по 2 за раз. В конце видим последовательность "00 80 00 00", повторённую 4 раза. Это X-координата 0x8000 и Y-координата 0x0000, и разумеется у нас младший байт пошёл первым, а старший байт последним, "чтоб никто не догадался". Эта метка 0x8000 должна была означать "эту точку мы не обнаружили", её я сам поставил в память:

Fx0:        00    53
Fy0:        01    -7
Fx1:        02    480
Fy1:        03    -30
Fx2:        04    -539
Fy2:        05    -302
Fx3:        06    400
Fy3:        07    -997
Fx4:        08    -32768
Fy4:        09    ????
Fx5:        0A   -32768
Fy5:        0B   ????
Fx6:        0C   -32768
Fy6:        0D   ????
Fx7:        0E   -32768
Fy7:        0F   ????
Exp:        10   ????
Tx:         11   ????
Ty:         12   ????
Tz:         13   ????
QuatA:      14   ????
QuatX:      15   ????
QuatY:      16   ????
QuatZ:      17   ????


Так что всё очень похоже на правду.

Наконец, сообразив, что мы далеко не всё вывели, что хотели, я расширил число слов до 24 - и получил результат, обведённый синим.


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

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


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

А вот что за "мусор" внизу возник - ни малейшего понятия... Наверное, опять USB Blaster "шалит", а там посмотрим.
Tags: ПЛИС, программки, работа, странные девайсы
Subscribe

  • Так есть ли толк в ковариационной матрице?

    Задался этим вопросом применительно к своему прибору чуть более 2 недель назад. Рыл носом землю с попеременным успехом ( раз, два, три, четыре),…

  • Big Data, чтоб их ... (4)

    Наконец-то стряхнул пыль с компьютерной модели сближения, добавил в неё код, чтобы мы могли определить интересующие нас точки, и выписать…

  • Потёмкинская деревня - 2

    В ноябре 2020 года нужно было сделать скриншот несуществующей программы рабочего места под несуществующий прибор, чтобы добавить его в документацию.…

  • Великая Октябрьская резня бензопилой

    Сегодня прокатился прочистить Абрамцевскую просеку. Как обычно, с приключениями. Выезжал на велосипеде, а вернулся на самокате. Первый раз по этим…

  • Очередная несуразность в единицах измерения

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

  • Big Data, чтоб их... (3)

    "В предыдущих сериях": мой прибор выдаёт 6 значений: 3 координаты и 3 угла, т.е все 6 степеней свободы твёрдого тела. Причём ошибки измерения этих 6…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments