nabbla (nabbla1) wrote,
nabbla
nabbla1

Categories:

16-битный полудуплексный UART, тестируем

В прошлый раз мы его вроде как написали, теперь пора проверить. Попробуем взять "с нахрапу" и сразу присоединим его к модулю CRC, вообще не задумываясь (вытащили 8-битный модуль, поставили 16-битный, только ширину шины поменяли):


Синтезируется в 68 ЛЭ, при 48 регистрах - очень "плотно" :) Предельная частота 68,97 МГц, меня устраивает (у меня 25 МГц пока).

Далее, для этого модуля "UART+CRC" создаём схемотехнический символ и кидаем две штуки на "тестовую схему":


(проверяем, что один как надо передаст, а второй корректно примет)

Запускаем синтез - и получаем очень нехорошее предупреждение:



Все остальные-фигня:
- Ignored locations or region assignments to following nodes - это о том, что у меня расписано, куда подключается АЦП, куда кнопочки, куда светодиодики, куда UART из "виртуального COM-порта", и пр., а теперь я назначил "верхним уровнем" схему, которой ничего этого не нужно! Нормальная ситуация.
- Clock setting "ETH_CLK_Global" is unassigned - поскольку на ПЛИС заведено аж две тактовые частоты, я прописал обе. Первую "традиционно" назвал clk, и раньше указывал на ней 80 МГц. Вторую - ETH_CLK_Global, т.к идёт она из Ethernet-контроллера. Потом, заметив, что во всех модулях у меня обычный clk, который только "на верхнем уровне" присоединён к ETH_CLK_Global (25 МГц) вместо clk (80 МГц), обе частоты указал как 25 МГц. Когда я запускаю на синтез лишь кусочек схемы, он меня предупреждает: заявлено о двух тактовых частотах, но используется только одна!
- Found invalid timing assignments - по сути повторение предыдущего предупреждения.

А вот "No output dependent on input pin D[15]" - это криминал! Мы же собираемся все 16 бит передавать, а потом принимать, смотреть на выходе Q! Значит, что-то у нас категорически неправильно.

Что интересно, при синтезе одного лишь модуля HalfDuplexUART16bit такого предупреждения нет. При синтезе его вместе с CRC (что мы назвали модулем HalfDuplexUART16bitwCRC) тоже предупреждения нет! А когда их два соединено в тестовой схеме - предупреждение появляется.

Посмотрим ещё раз пристально на наш сдвиговый регистр:
always @(posedge clk) if (isIdle? startTX : ce) begin
	SR[18] <= (startTX & isIdle)? D[15] : rxd;
	SR[17:1] <= (startTX & isIdle)? {D[14:8],2'b01,D[7:0]} : SR[17:2];
	//SR[0] <= (startTX & isIdle)? 1'b0 : (isCRC & (State[3:1] != 3'b111))? CRC_bit : SR[1];
	SR[0] <= (startTX & isIdle)? 1'b0 : (isCRC &~& State[3:1])? CRC_bit : SR[1];
end


Тут ошибка: в SR[17:1] (вторая строчка) во время сдвига попадает SR[17:2], а SR[18] остаётся "сам по себе". Но он был "виден" на выходе Q модуля, и только на тестовой схеме мы этот Q ПЕРЕДАТЧИКА оставили висеть в воздухе, из-за чего предупреждение и сработало в итоге.

Исправление простое:
SR[17:1] <= (startTX & isIdle)? {D[14:8],2'b01,D[7:0]} : SR[18:2];


Предупреждение исчезло, уже радость.

Попробуем передать слово 0x1234, классика жанра:


Почти всё правильно, только сигнал HasOutput выдаётся дважды: когда был принят первый байт, и затем когда был принят второй. Смотрим логическое выражение:

assign HasOutput = isStopState & ce & rxd & ~RW;


Ну да, с чего бы ему первый байт от второго отличать. Надо вот так:
assign HasOutput = isStopState & ce & rxd & ~RW & isSecondByte;


И получаем такую "осциллограмму":


Небольшой "выброс" всё равно остался по окончании приёма первого байта, приблизим его:


Совсем крохотный, из-за того, что isSecondByte устанавливается в единицу чуточку быстрее, чем переключается состояние из sStop в sIdle. Но до фронта тактового импульса оно, разумеется, устанавливается в ноль. Вот как выглядит НАСТОЯЩИЙ импульс HasOutput:


Давайте ещё следом передадим 0x5678:


А теперь ещё CRC, для начала сгенерированный "автоматом":


По крайней мере, CRC_error в единицу не "зажигается". Получили значение 0x0784. На crccalc.com ничего похожего нет, потому как сейчас мы отправляем с младшего бита по старший бит каждого СЛОВА (16 бит), а затем со старшего бита по младший бит самого CRC, который затем интерпретируется "задом наперёд". Как будто бы это reflection in, reflection out, но только не по байтам, а по словам.

Что ж, давайте ручками. Если записать слева направо, какие биты заходят в CRC, выходит:
0010 1100 0100 1000 0001 1110 0110 1010 = 0x2C481E6A


CRC-16 XModem для такой последовательности посчитает 0x21E0 = 0010 0001 1110 0000. Если её обратить, получается

0000 0111 1000 0100 = 0x0784. Да, это оно.

Второй вариант: меняем местами байты попарно, т.е вместо 0x12345678, выходит 0x34127856. Вбиваем в crccalc.com, и там в графе CRC16/KERMIT получаем 0x0784 те же самые. Что меня несколько удивило: похоже входной reflection идёт по байтам, а выходной - всего слова целиком :)

Для очистки совести попробуем передать неверный CRC, вместо 0x0784 пусть будет 0x1784:


Да, теперь ошибка "зажглась", работает.


Как будто бы работает. Теперь ещё протокольный контроллер МКО (к которому вместо МКО пока что прикрутили UART) доработать, чтобы CRC проверял (давал управляющие сигналы на модуль HalfDuplexUART16bitwCRC) - и пора бы уже на реальное железо перебираться, смотреть, что там получается. А потом ещё написать простенький DMA, чтобы протокольный контроллер и процессор одну память делили на двоих (с приоритетом процессора) - и золотой ключик у меня в кармане.

Уже ведь можно в РКК Энергию попасть, у меня QR-код есть и справка с круглой печатью от врача, и треугольной и прямоугольной печатями из регистратуры :)
Tags: ПЛИС, работа, странные девайсы
Subscribe

Recent Posts from This Journal

  • Тестируем 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 

  • 2 comments