nabbla (nabbla1) wrote,
nabbla
nabbla1

Categories:

"МКО через UART", часть 8 - CRC

Наличие контрольной суммы CRC (Cyclic Redundancy Code) также не является частью ГОСТ 52070-2003, это дополнительное требование конкретно в нашем протоколе информационного обмена.

На самом деле, можно было и какую-нибудь другую контрольную сумму впихнуть, но мне захотелось CRC, именно исходя из лёгкости его реализации на ПЛИС. Как ни странно, при аппаратной реализации он куда приятнее, чем какая-нибудь "сумма слов по модулю, близкому к 65536" (Fletcher, Adler), или "сумма слов с битом переноса, прибавляемым к младшему разряду" (контрольная сумма заголовка IPv4), и даже самой простой 16-битной контрольной сумме (когда все слова складываются, и берутся только 16 бит результата) CRC даст фору, оказываясь вдвое компактнее!

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

Для протокола я нарисовал такую хреновину:



В первую очередь, мне хоть здесь не хотелось изобретать велосипед - выбрать один из устоявшихся вариантов CRC.

Принципиально, чтобы биты подавались на обработку от старшего к младшему, поскольку именно в таком порядке они передаются в МКО (Mil-Std 1553). Но и получившееся значение CRC должно выдаваться по биту от старшего к младшему, чтобы с тем же успехом можно было его подать на передатчик. Как ни странно, именно такая работа наиболее естественна для CRC, и обозначается как "no input reflection, no output reflection".

Далее, регистр CRC иногда инициализируют ненулевым значением. Мотивируется это тем, что если инициализировать их просто нулём, то до тех пор, пока на вход будут поступать нули, значение CRC меняться не будет, и таким образом он не сможет отследить нули на входе! И наверное, где-то это действительно нехорошо. Но как это может повредить нам, я не особо представляю: первым словом всё равно идёт заголовок массива, и так уж вышло, что нулевым он не бывает. Если заголовок массива неверен, дальше мы заведомо принимать сообщение не будем! Зато, инициализация нулями самая простая, я решил сделать именно так.

Не вижу никакого смысла в XOR результата с какой-нибудь константой, этого я тоже не стал делать.

И наконец, нужно было выбрать какой-нибудь многочлен (говоря русским языком, полином), и я взял тупо самый популярный, который используют в десятках различных CRC: x16+x12+x5+1. Другая форма записи: 0x1021, это 16-битное значение переводим в двоичное: 0001_0000_0010_0001, единичка в разряде с номером n означает наличие xn в выражении, здесь n=0 - младший разряд, n=15 - старший, а наличие x16 считается само собой разумеющимся.

Всё вместе это даёт нам CRC-16 "XModem"! Вполне себе известная вещь, и я могу сверяться, к примеру, с этим сайтом: https://crccalc.com

Выше показано, как можно формировать данный код на ПЛИС.

Если мы ведём передачу, то во время передачи ответного слова нам нужно установить CRC_en = 0 и затем 16 раз подряд "мигнуть" clk_en=1. Удобнее всего, если каждый переданный бит сообщения будет давать clk_en=1, наверняка мы сообразим, куда подключиться :) На вход D могут поступать передаваемые биты ответного слова - нам сейчас вообще пофиг!

За эти 16 тактов регистры CRC все обнулятся, поскольку вся эта цепочка будет работать просто как сдвиговый регистр.

Затем, когда начнут передаваться слова данных, мы устанавливаем CRC_en = 1, и каждый уходящий на шину бит должен также приходить на вход D, и в этот момент появляться clk_en = 1. С каждым приходящим битом значение всех регистров будет изменяться.

Наконец, когда мы начнём отправлять слово данных CRC, нужно будет подключить к приёмопередатчику выход Q этой схемы, и снова устанавливается CRC_en=0. Во время отправления очередного бита нужно будет подавать clk_en=1, чтобы на выход Q "вдвинуть" следующее значение. 16 бит, ушедших в приёмопередатчик - это и будет наш CRC.

При работе на приём, мы устанавливаем CRC_en = 0, пока принимаем командное слово (а точнее, произвольное слово, находясь в состоянии sIdle). Когда приходит очередной бит, выставляется clk_en=1, и к окончанию этого слова у нас регистр полностью обнулится.

Затем, когда мы поняли, что сейчас пойдут слова данных, адресованные нам, выставляем CRC_en = 1, на вход D идут данные с приёмника, бит за битом, и приход каждого сопровождается импульсом clk_en=1 на один такт.

И когда начинает идти последнее слово, то, в котором содержится CRC, мы ничего не меняем - пущай себе идёт. При этом, если всё передано верно, на входной элемент XOR (исключающее ИЛИ) будет поступать два одинаковых сигнала, давая на выходе НОЛЬ, и покуда это так, вся схема будет работать как сдвиговый регистр, тем самым подавая на выход (и на нижний вход XOR) биты CRC один за другим.

Если в конце мы получим все нули, это будет означать: CRC сходится! Наверное, имеет смысл поставить RS-триггер, на который поступает выход с первого элемента XOR. Перед финальным словом он будет сбрасываться, а единичкой с выхода - устанавливаться. Тогда его выход будет служить индикацией правильности CRC.

При реализации через UART у нас возникают проблемы, ведь там данные отправляются младшим битом вперёд! Думаю, что не буду усердствовать - пущай идут как идут, получится зеркальное отражение как входных данных для CRC, так и выходных, то есть Input reflection, Output reflection. С тем же начальным значением 0x0000 и полиномом 0x1021, это даст нам CRC "Kermit", который также можно посчитать на https://crccalc.com


Продолжение следует... Вообще, мне очень хочется сделать совмещённый модуль на приём и передачу, специально для RS485. Когда-то давно я такое делал, но маленьким был, надо попробовать ещё разок, и теперь на 16 бит и с "заделом" под CRC.
Tags: ПЛИС, работа, странные девайсы
Subscribe

Recent Posts from This Journal

  • Лестница для самых жадных

    В эти выходные побывал на даче, после 3-недельной "самоизоляции". Забавно, как будто зима началась! Особенно грязные галоши остались на улице, в…

  • Возвращаемся к макету

    Очень давно макетом видеоизмерителя параметров сближения не занимался: сначала "громко думал" по поводу измерения его положения на аппарате, а потом…

  • Минутка живописи

    В процессе разгребания содержимого квартиры (после нескольких ремонтов) дошёл, наконец, и до картин. В кои-то веки их повесил. Куда их вешать -…

  • Костыль ноутбуку и кабели Франкенштейна (это не я!)

    Продолжаю разгребать хлам, накопившийся за много лет, раз уж всё равно на карантине сижу. Довольно продуктивный день: починил ноутбук (грубо, но…

  • Атомный файлсервер, убитые петухи и харакири андроида

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

  • Ещё про яркий светильник и ИБП

    Всё-таки применил лежащее дома барахло наиболее простым образом: А ещё наконец-то замерял температуру теплоотвода яркого светильника на кухне,…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments