Дисплеи, датчики и прочие функциональные узлы, управляемые МК.
Ответить

Пакетный протокол обмена данными между МК и ПК

Пн окт 25, 2010 15:34:17

На форуме частенько поднимается тема обмена данными между устройством на микроконтроллере и "большим" ПК. Я решил поделиться своими наработками в этой области и опубликовал описание и исходники своего протокола, который использую в различных устройствах. Это некий симбиоз из разных протоколов, которые мне доводилось видеть.

Возможна работа в режиме точка-точка и в сети. Протокол синхронный, каждое сообщение подтверждается, т.е. арбитраж при работе в сети осуществляется на уровне пакетов. Возможна отправка пакета конкретному устройству и широковещательная (адрес 0x00).

Данные передаются в текстовом виде, есть проверка целостности (CRC8).

Выложенные исходники на Си для MSP430F2x со стороны контроллера и на C# для большого брата.
Код очень легко переносится на любою платформу (достаточно откорректировать обработчики прерываний по приему и передаче байта).

Ссылка на статью: http://www.levap.ru/2010/10/paketnyj-pr ... a-dannymi/

Буду рад услышать отзывы!
А если кто портанет на другую платформу - с радостью выложу исходники в том же месте.

Re: Пакетный протокол обмена данными между МК и ПК

Пн ноя 01, 2010 12:36:01

Самое свежее описание протокола WAKE с примерами я выложил здесь: http://digit-el.com/files/open/wake/wake.html
В скором будущем планирую добавить туда новую реализацию WAKE на Си для микроконтроллеров, а также модули на С++ для PC с примером приложения.

Re: Пакетный протокол обмена данными между МК и ПК

Пн ноя 01, 2010 13:00:57

Леонид Иванович, вы ли это ?! Очень рад ! :beer:

Re: Пакетный протокол обмена данными между МК и ПК

Пн ноя 01, 2010 13:16:41

Это я. Тоже рад :)

Re: Пакетный протокол обмена данными между МК и ПК

Вт ноя 02, 2010 10:42:26

Liv писал(а):Самое свежее описание протокола WAKE с примерами я выложил здесь: http://digit-el.com/files/open/wake/wake.html
В скором будущем планирую добавить туда новую реализацию WAKE на Си для микроконтроллеров, а также модули на С++ для PC с примером приложения.

Заменил ссылку в статье. У меня тоже есть некоторые идеи по модернизации протокола в части реализации асинхронных сообщений при связи типа точка-точка.

Re: Пакетный протокол обмена данными между МК и ПК

Вт ноя 02, 2010 11:17:56

У меня изменения логики коснулись пакета CMD_ERR, который передается подчиненным устройством при ошибке приема пакета. Так делать нельзя, потому что в случае наличия помех все устройства сети начинают передавать этот пакет, и возникает коллизия. Посылать CMD_ERR можно только в том случае, если адрес правильно распознан подчиненным устройством. Поэтому ничего передавать не нужно в случае:
-> ошибки фрейма FE
-> ошибки стаффинга
Вообще, всё больше склоняюсь к тому, что в случае ошибки приема пакета подчиненное устройство просто должно молчать. Т.е. ничего не передавать в случае:
-> ошибки формата коды команды (старший бит = 1)
-> ошибки длины пакета
-> ошибки CRC

Использование коллективного вызова в сетях невозможно, так как ответ будт передавать все устройства сразу. Адрес 0 не передается в пакете, он предназначен для работы точка - точка. Можно реализовать еще один адрес коллективного вызова, например, 1. При обращении по этому адресу устройства не передают ответа. Очевидно, что так передавать можно только команды управления, а не запроса данных. Результат выполнения команды, как вариант, можно запросить отдельной командой у каждого устройства. Не знаю, стоит ли такое делать.

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

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

Формирование и разбор пакетов планирую вынести из обработчиков прерываний UART, так как длительные обработчики мешают основной задаче в некоторых критичных случаях.

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

По умолчанию устанавливать в модулях адрес 0x7F, по которому и будет производиться поиск и назначаться адрес вновь подключенному к сети устройству. Использовать для раздачи адресов коллективный вызов нельзя, так как он не позволит добавлять новые устройства к уже имеющейся сети, а потребует начальной стадии раздачи аресов по одному.

Ну и надо бы в описании разложить протокол на уровни OSI, да вот времени не хватает.

Что касается ASCII версии протокола, то я вижу лишь одно преимущество - уходит необходимость стафинга. Но ценой двойной избыточности. То, что пакеты можно просматривать стандартной терминалкой, не считаю преимуществом, так как в этом не возникает необходимости. Даже тестер протокола WAKE я перестал использовать после того, как были отлажены библиотечные функции приема-передачи пакетов. В сложных пакетах вручную интерпретировать данные очень трудно. А если сделать отладочную программу-интерпретатор, то ей будет всё равно, ASCII протокол, или нет.

А что Вы иеете в виду под асинхронными сообщениями?

Re: Пакетный протокол обмена данными между МК и ПК

Вт ноя 02, 2010 12:08:41

Liv писал(а):Вообще, всё больше склоняюсь к тому, что в случае ошибки приема пакета подчиненное устройство просто должно молчать. Т.е. ничего не передавать в случае:
-> ошибки формата коды команды (старший бит = 1)
-> ошибки длины пакета
-> ошибки CRC

У меня сейчас так и сделано. Битые пакеты просто игнорируются. Отсутствие отклика от клиентского устройства (по таймауту) является само по себе индикацией проблемы связи.

Liv писал(а):Использование коллективного вызова в сетях невозможно, так как ответ будт передавать все устройства сразу. Адрес 0 не передается в пакете, он предназначен для работы точка - точка. Можно реализовать еще один адрес коллективного вызова, например, 1. При обращении по этому адресу устройства не передают ответа. Очевидно, что так передавать можно только команды управления, а не запроса данных. Результат выполнения команды, как вариант, можно запросить отдельной командой у каждого устройства. Не знаю, стоит ли такое делать.

В моей логике именно так и подразумевалось - для широковещательных запросов ответ не передается. Т.е. эти сообщения не имеют подтверждения.

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

У меня сделано табличное вычисление CRC. Объем флеш-памяти в современных МК более чем достаточен для этого. Плюс, я вынес вычисление контрольной суммы из прерывания - как-то не правильно это.

Liv писал(а):Формирование и разбор пакетов планирую вынести из обработчиков прерываний UART, так как длительные обработчики мешают основной задаче в некоторых критичных случаях.

Это правильно. Я сейчас вообще делаю вариант с использованием кольцевого буфера, где в прерывании будет выполняться единственная задача - push или pop. А разбор пакета будет идти отдельным процессом (я использую scmRTOS в этом проекте).

Liv писал(а):А что Вы иеете в виду под асинхронными сообщениями?

Аналог PDO сообщений в CANopen. Когда подчиненное устройство может самостоятельно инициировать передачу пакета. Это позволяет избежать поллинга в ситуациях, когда необходим постоянный контроль какого-либо параметра. Но это, конечно, для сети не подходит, только для соединения точка-точка.

Re: Пакетный протокол обмена данными между МК и ПК

Вт ноя 02, 2010 12:57:58

Pavel V. писал(а):В моей логике именно так и подразумевалось - для широковещательных запросов ответ не передается. Т.е. эти сообщения не имеют подтверждения.


У меня адрес 0 является, скорее, не широковещательным, а выделенным адресом для связи точка-точка. Нулевой адрес вообще не передается в пакете, что уменьшает избыточность при связи точка-точка. А вот широковещательного адреса, когда устройства не передают ответа, пока в WAKE нет, думаю добавить.

Pavel V. писал(а):У меня сделано табличное вычисление CRC. Объем флеш-памяти в современных МК более чем достаточен для этого. Плюс, я вынес вычисление контрольной суммы из прерывания - как-то не правильно это.


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

Pavel V. писал(а):Я сейчас вообще делаю вариант с использованием кольцевого буфера, где в прерывании будет выполняться единственная задача - push или pop. А разбор пакета будет идти отдельным процессом (я использую scmRTOS в этом проекте).


При наличии уникального маркера начала пакета не видно необходимости в кольцевом буфере. Начало пакета всегда может помещаться в начало буфера. Анализ символа начала пакета - минимальная работа, вполне можно делать и в прерывании. Конец пакета тоже несложно определить в прерывании, и только после этого дать знать о приеме пакета процессу разбора. Хотя, конечно, можно и всю работу поручить процессу.

Pavel V. писал(а):Когда подчиненное устройство может самостоятельно инициировать передачу пакета. Это позволяет избежать поллинга в ситуациях, когда необходим постоянный контроль какого-либо параметра. Но это, конечно, для сети не подходит, только для соединения точка-точка.


Такой подход требует иной поддержки со стороны PC, нарушается вся структура. К тому же, как быть с коллизиями при полудуплексной связи, например, RS-485? Это весьма значительная часть применений протокола.

Re: Пакетный протокол обмена данными между МК и ПК

Вт ноя 02, 2010 14:04:06

Liv писал(а):У меня адрес 0 является, скорее, не широковещательным, а выделенным адресом для связи точка-точка. Нулевой адрес вообще не передается в пакете, что уменьшает избыточность при связи точка-точка. А вот широковещательного адреса, когда устройства не передают ответа, пока в WAKE нет, думаю добавить.

Адрес 0xFF - как в TCP/IP :)

Liv писал(а):Я по своей бедности работаю с маленькими процессорами, поэтому табличное вычисление CRC не делал. Хотя в будущей реализации для AVR планирую добавить. Из прерывания тоже по максимуму всё вынесу.

При первоначальной реализации, когда вычисление контрольной суммы производилось в прерывании, у меня наблюдались потери символов (при высокой скорости UART). Ну и чисто идеологически не правильно нагружать обработчики прерываний.

Liv писал(а):Такой подход требует иной поддержки со стороны PC, нарушается вся структура. К тому же, как быть с коллизиями при полудуплексной связи, например, RS-485? Это весьма значительная часть применений протокола.

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

Re: Пакетный протокол обмена данными между МК и ПК

Вт ноя 02, 2010 15:47:19

Liv писал(а):... табличное вычисление CRC не делал. Хотя в будущей реализации для AVR планирую добавить.
И здесь здравствуйте!

Может, ну его, табличное? Для AVR, по крайней мере. У них же нет возможности за один мах зачитать слово из таблицы, в результате табличный 16-битный CRC в зависимости от реализации (на асме с выровненными по границе 256 байт полутаблицами или на С «ну как легло») займёт грубо 15+-3 цикла, а быстрый нетабличный метод — где-то от 20 до 25. Разница ощутимая, но что одно, что другое гораздо быстрее цикла по битам. И разница в десяток тактов на байт частично теряется во всех остальных затратах на байт — начиная от разбора SLIP и заканчивая push/pop в обработчике прерывания.
Я давно для себя решил, что «побитный» метод не имеет никаких преимуществ — длина кода не настолько меньше «быстрого нетабличного», чтобы это что-то весило, а для ухода на табличный нужно ну очень за скоростью гнаться.

«Быстрый нетабличный» для выглядит приблизительно так (выписано с оглядкой на 8-битник, для 16-битника выглядит ещё красивее, CRC_SPACE для 51-ых могло оказатья idata/xdata):
Код:
uint16_t calc_crc(void CRC_SPACE * array, CRC_LEN len)
{
    uint8_t carry;
    uint8_t CRC_SPACE *ptr = (uint8_t CRC_SPACE *) array;
    uint8_t crcbuf_lo = 0;
    uint8_t crcbuf_hi = 0;

    while(len--)   {
        carry = crcbuf_hi ^ *ptr++;
        carry = carry ^ (uint8_t) (carry >> 4);
        crcbuf_hi = crcbuf_lo ^ (uint8_t) (carry << 4) ^ (uint8_t) (carry >> 3);
        crcbuf_lo = carry ^ (uint8_t) (carry << 5);
    }

    return ((uint16_t) crcbuf_hi << 8) | crcbuf_lo;
}
Конкретный вид кода (и время тела цила) зависят от полинома.
Хорошо это дело опиcано было у ... Альтеры в аппноте по вычислению CRC — с картинками, пояснющими как из заданного полинома получить вот такой код, только там он на AHDL был. Могу поискать, это апнота времён MAX+II 7.x.
В avr-libc в <util/crc16.h> есть inline-функции c asm-ядром для нескольких полиномов.

Liv писал(а):При наличии уникального маркера начала пакета не видно необходимости в кольцевом буфере. Начало пакета всегда может помещаться в начало буфера.
+1
Liv писал(а):Анализ символа начала пакета - минимальная работа, вполне можно делать и в прерывании. Конец пакета тоже несложно определить в прерывании, и только после этого дать знать о приеме пакета процессу разбора. Хотя, конечно, можно и всю работу поручить процессу.
С выносом из прерывания, на мой взгляд, тоже без фанатизма надо. Разбор SLIP-овской подстановки байтов вполне может сидеть в прерывании, использование не кольцевого буфера, а буфера пакета этому способствует. А уже потом отдавать наверх, пусть там CRC сверяют, то-сё.

В случае с вытесняющей ОС так и вообще — тот процесс, которому делегируется работа, для всех менее приоритетных процессов неотличим от прерывания — так зачем выносить в процесс? Стоит сокращать суммарное время работы прерывания и процесса. Переключать процессы по каждому байту — это на одни переключения контекста потратить больше времени, чем нужно для разбора SLIP и даже подсчёта CRC.
Если есть принципиально *) более приоритетные процессы, тот тут стоит думать. Но я склонен часть протокола уносить в прерывания, процессу отдавать (у процесса брать) пакет, а более мелкую работу делать в прерываниях.

*) «принципиально» — это не просто формально больше приоритет, в случае scmRTOS только потому, что у неё нельзя создать две задачи одинакового приоритета, а действительно она должна отпихивать в сторон все эти протоколы и делать своё дело. Но и тогда нет смысла выносить из прерываия в коммуникационный процесс то, что занимает время, сравнимое со временем переключения.

Re: Пакетный протокол обмена данными между МК и ПК

Вт ноя 02, 2010 16:17:28

Pavel V. писал(а):Адрес 0xFF - как в TCP/IP :)


Ну примерно :) Только WAKE столько не адресует.

Pavel V. писал(а):При первоначальной реализации, когда вычисление контрольной суммы производилось в прерывании, у меня наблюдались потери символов (при высокой скорости UART).


У меня при вычислении CRC в прерывании обычным методом AVR на 16 МГц тянет скорость обмена до 500 кБод.

Pavel V. писал(а):Но как раз такой частный случай мне сейчас подвернулся :) Необходимо обеспечить очень быструю реакцию на событие, произошедшее на ведомом устройстве, и решение вопроса поллингом кажется некрасивым.


Бывают такие задачи. Но тут может всё испортить ОС, к примеру, если юзер поцарапанный сидюк в привод засунет :)

avreal писал(а):И здесь здравствуйте!


Здравствуйте! Убежал сюда от излишней сложности.

avreal писал(а):Может, ну его, табличное? ... «Быстрый нетабличный» для выглядит приблизительно так


Спасибо за алгоритм! Я человек очень ограниченный, пользуюсь очень небольшим подмножеством каких бы то ни было вещей, таких методов вычисления CRC не знал. А для CRC-8 это тоже выгоднее?

avreal писал(а):Разбор SLIP-овской подстановки байтов вполне может сидеть в прерывании, использование не кольцевого буфера, а буфера пакета этому способствует.


Именно! Иначе буфер нужен вдвое больше, а с ОЗУ всегда очень сильный напряг.

avreal писал(а):В случае с вытесняющей ОС


Это уже из другой жизни. Никаких готовых ОС не знаю, применяю структуру программы с основным циклом, немного похожую на кооперативную ОС. В редком проекте требуется выполнять параллельно сложные процессы. А если требуется, ну его такого проекта!

Re: Пакетный протокол обмена данными между МК и ПК

Вт ноя 02, 2010 19:18:01

Интересуюсь протоколами от Pavel V. и Liv.

Примеров бы побольше(от простых до сложных).

Re: Пакетный протокол обмена данными между МК и ПК

Ср ноя 03, 2010 00:31:03

Для каких задач и платформ Вас интересуют примеры? Опишите свою задачу, возможно, что-то подобное найдется.

Re: Пакетный протокол обмена данными между МК и ПК

Ср ноя 03, 2010 11:00:35

Интересуюсь протоколом от Liv (WAKE).
Прочитал много информации о RS-485.
У меня вопрос: Возможно ли общения устройств (кол. около 20 шт.) между собой а не по указке от MASTERA какое устройство может сейчас работать в сети?
На данный момент планирую организовать это таким способом:
Когда устройство готово передать пакет оно слушает сеть (линию). Как только сеть освободилась устройство, какое то время еще слушает сеть и только потом занимает сеть на передачу.

Re: Пакетный протокол обмена данными между МК и ПК

Ср ноя 03, 2010 11:12:54

YKolomiets писал(а):Интересуюсь протоколом от Liv (WAKE).
Прочитал много информации о RS-485.
У меня вопрос: Возможно ли общения устройств (кол. около 20 шт.) между собой а не по указке от MASTERA какое устройство может сейчас работать в сети?
На данный момент планирую организовать это таким способом:
Когда устройство готово передать пакет оно слушает сеть (линию). Как только сеть освободилась устройство, какое то время еще слушает сеть и только потом занимает сеть на передачу.

В Вашем случае я бы советовал посмотреть в сторону CAN.

Re: Пакетный протокол обмена данными между МК и ПК

Ср ноя 03, 2010 12:42:08

YKolomiets писал(а):Возможно ли общения устройств (кол. около 20 шт.) между собой а не по указке от MASTERA


Протокол WAKE мультимастерный режим не поддерживает.

Re: Пакетный протокол обмена данными между МК и ПК

Ср ноя 03, 2010 14:46:31

Тогда объясните пожалуйста (разложите по полочкам).
CAN решает проблему передачи двух устройств по битном арбитражем. То есть у кого в посылке оказался «0» (прим. устройство Х - 11011, устройство У - 11101) тот и передает дальше (передает устройство Х). Из этого выходит что каждое устройство которое начало передачу осуществляет прослушивания линии в течении передачи всего пакета (передали бит слушаем линию и т. д.).
Может ли устройство У начать передачу в момент когда устройство Х передало уже половину своего пакета?
По поводу адресации: в протоколе CAN нет адресации, и максимально можно передать 8-мь байт данных, каждый из которых содержит 8 бит (DATA FIELD) .
Каким способом я могу обратится к определенному устройству?
Пример: в сети находится 3-ри устройства, которые контролируют напряжение. Как мне из них выделить одно устройство.

Re: Пакетный протокол обмена данными между МК и ПК

Чт ноя 04, 2010 09:09:14

Рекомендую прочитать: http://can.marathon.ru/can-protocols/canbus/canintro

Кадр CAN содержит несколько полей помимо поля данных (которое действительно длиной 8 байт). Арбитраж осуществляется по идентификатору (11-битному или 29-битному). Если устройство выигрывает арбитраж, оно передает кадр целиком.

Поле арбитража CAN-кадра используется в CAN для разрешения коллизий доступа к шине методом не деструктивного арбитража. Суть метода не деструктивного арбитража заключается в следующем. В случае, когда несколько контроллеров начинают одновременную передачу CAN кадра в сеть, каждый из них сравнивает, бит, который собирается передать на шину с битом, который пытается передать на шину конкурирующий контроллер. Если значения этих битов равны, оба контроллера передают следующий бит. И так происходит до тех пор, пока значения передаваемых битов не окажутся различными. Теперь контроллер, который передавал логический ноль (более приоритетный сигнал) будет продолжать передачу, а другой (другие) контроллер прервёт свою передачу до того времени, пока шина вновь не освободится. Конечно, если шина в данный момент занята, то контроллер не начнет передачу до момента её освобождения.

Re: Пакетный протокол обмена данными между МК и ПК

Чт ноя 04, 2010 11:04:55

Спасибо большое за ссылку.
Перед тем как задавать вопросы эту ссылку я читал.
Объясните пожалуйста ситуацию: в сети CAN подключено 10шт. устройств. Из них 3шт. работают по контролю напряжения. Как получить данные одного из них?
В моем понимании устройство Х которое хочет получить данные от устройства У (таких устройств в сети еще 2шт. У1,У2) в поле кадра (DATA FIELD) должны присутствовать данные (команда, запрос) которые понимает только устройство У.

Re: Пакетный протокол обмена данными между МК и ПК

Чт ноя 04, 2010 11:57:19

YKolomiets писал(а):Спасибо большое за ссылку.
Перед тем как задавать вопросы эту ссылку я читал.
Объясните пожалуйста ситуацию: в сети CAN подключено 10шт. устройств. Из них 3шт. работают по контролю напряжения. Как получить данные одного из них?
В моем понимании устройство Х которое хочет получить данные от устройства У (таких устройств в сети еще 2шт. У1,У2) в поле кадра (DATA FIELD) должны присутствовать данные (команда, запрос) которые понимает только устройство У.

Шина CAN сама по себе обычно не используется, есть ряд протоколов высокого уровня, которые работают поверх нее.
Например, протокол CANopen, его стандартизацией занимается организация под названием CAN in Automation. Конкретно реализацию протокола (Application Layer) описывает документ CiA 301 (он доступен для скачивания на сайте). Там же есть документы, описывающие разные "профили" для устройств. Например, CiA 401 (модуль ввода-вывода), CiA 402 (двигатели) и т.п. Их очень много.

Обычно, когда делают устройство CANopen, в нем реализовывают один из профилей, который соответствует данному типу устройств.

Я несколько лет занимался устройствами CANopen. Если будут вопросы - с радостью отвечу, но лучше в новой теме.

Самая известная opensource реализация протокола - CAN Festival.

Со стороны мастера там совсем все просто.
Ответить