- PVSM.RU - https://www.pvsm.ru -
Некоторое время назад у нас появился объект, где в техническом задании стояло требование: «Протокол Ethercat». В процессе поиска информации я полез на хабр и с удивлением обнаружил, что там разбора этого протокола нет. Да и вообще информация о нем довольно фрагментирована (забегая вперед — я просто не там искал). Проект мы сделали, а эта статья — для «более молодого меня», попытка сэкономить время кому-нибудь еще, кто собирается использовать или просто интересуется этим протоколом.
Единственный нюанс — я опишу довольно низкий уровень работы протокола (Data Layer в терминологии EtherCAT). Потому что именно он нам понадобился и им мы ограничились. Неописанными (пока?) останутся Application Layer протоколы типа CanOPEN-over-EtherCAT (CoE).

Уж это нагуглить легко, но для порядка скажу своими словами. EtherCAT – промышленная шина обмена с высокой пропускной способностью (100 Мбит/c) и скоростью реакции (единицы микросекунд для десятков устройств на одной линии разнесенных на десятки метров), использующая на низком уровне Ethernet, но при этом отличающаяся от обычной концепции Ethernet «вопрос-ответ».
Обычно в Ethernet порядок работы такой — устройство принимает пакет целиком, обрабатывает его, потом формирует и отсылает ответ. А EtherCAT работает так — устройство принимает пакет, и как только оно приняло заголовок (и поняло что это EtherCAT-пакет) оно начинает этот пакет отсылать дальше, в процессе отсылки заменяя те биты пакета в которых оно должно отослать информацию на нужные.
В результате мастер может отослать килобайтный пакет со скоростями для ста моторчиков и пустыми местами для ста датчиков, каждый из датчиков запишет в него свои данные а каждый моторчик прочитает свои, пакет вернется к мастеру и всё это займет примерно микросекунду. При этом мастер — обычный компьютер или микроконтроллер, а устройства соединены витой парой. Правда есть и подвох — хоть это и витая пара, а обычными свитчами топологию не организовать, а главное — мастером конечно может быть любой кто может отсылать UDP, а вот слейва обрабатывающего EtherCAT пакеты на ходу из обычного микроконтроллера не сделать. EtherCAT-слейв — специализированное устройство, и да — оно не может работать со всякими ARP и вообще отсылать и принимать произвольные пакеты. Только EtherCAT-пакеты.
В нашем случае и "слейв" и мастер были нашими устройствами, соответственно я даю рекомендации для нашего случая. Возможно, у Вас уже есть либо мастер либо слейв.
Когда мы стали искать на чем сделать слейва, мы нашли два легкодоступных варианта — микроконтроллеры Infineon XMC43004800 [1] и модули Microchip LAN9252 [2]. Мы выбрали первый (во многом из-за доступности отладочной платы), но как я теперь понимаю особой разницы что использовать нет — взаимодействие с модулем EtherCAT стандартизировано (об этом позже).
Так что для тех кто хочет пощупать EtherCAT вживую я рекомендую взять пару отладочных плат XMC4800 Relax EtherCAT Kit. Почему пару? Чтобы понять как работает топология эзеркада — с одной платой вроде бы всё просто, а вот две (и роутер или свитч) уже дают возможность для экспериментов.

Кроме слейва потребуется мастер.
Тут есть такие варианты:
Отслеживать что происходит можно обычным снифером WireShark [4]. Он и тип пакетов отображает, и содержимое, и время до микросекунд.
Ну и документация, куда же без нее. Кому-то, возможно, достаточно просто взгляда на код опенсорсной реализации, но я так и не смог самостоятельно разобраться во всех этих wkc2 и APWRw. Все прояснилось и встало на свои места когда я просмотрел один единственный файлик: EtherCAT_Communication_EN.pdf. Правда есть нюанс — с сайта ethercat.org его так просто не скачать. Надо получить членство в EtherCAT association. Правда вы можете попробовать его нагуглить, либо я могу его строго по секрету отправить его вам (лично я не подписывал NDA, но с Beckhoff переписывался мой коллега и вполне возможно от имени нашей фирмы он что-то подписывал), ну или стать таки членом этой ассоциации, это бесплатно.
Если что — данная статья в значительной мере является пересказом содержимого данного документа, схемы тоже взяты оттуда.
Да-да, как утверждается в документации, да и в нагугленных туторилалах случайные люди не могут делать устройств поддерживающих Ethercat, они должны стать членами ассоциации Ethercat [5]. После это они смогут скачать документацию и стандарты, а также получат свой уникальный Vendor ID. Причем членство бесплатно, надо просто написать им и ответить на пару вопросов о своей компании. https://ethercat.org/en/membership_application.html [6]
В итоге мы стали членами этой ассоциации и у нас есть свой VendorID! Правда польза от этого ограничилась вышеупомянутым файлом, даже VendorID мы в итоге не используем. Так что никто не мешает пользоваться протоколом и без этих формальностей — разве что "шашечек", т.е. формального соответствия стандарту EtherCAT не будет. Кому-то это важно, кому-то — нет.
С предварительными вопросами покончили, теперь собственно к протоколу. Логическая топология езеркат — шина. При этом физическая может быть и звездой и шиной и кольцом и разными комбинациями. Как это работает?
У любого езеркат устройства есть 4 порта, физически у большинства присутствует только 2 (port 0 и port 1). Они соединены вот так:

Словами: когда пакет приходит на порт, он отправляется на следующий порт (по часовой стрелке на картинке). Если этот следующий порт отключен он считается закороченным и пакет пойдет на следующий за ним. После порта 0 расположен ethercat processing unit, который собственно на лету подставляет данные устройства, в остальных случаях пакеты проходят без изменений.
К примеру, если соединить ethercat устройство с мастером одним патчкордом, который будет воткнут ну скажем в port0 слейва, то пакет придет в port 0, пройдет через ethercat processing unit, дальше пройдет по кругу и т.к. три других порта закрыты то вернется через port0 по патчкорду к мастеру.

Дальше мы можем соединить длинную цепочку таких устройств:

и как легко догадаться пакет пришедший первому устройству на port0 пройдет через модуль обработки и дальше в port1, оттуда к следующему устройству на port0 и так до конца цепочки, а т.к. в последнем будет открыт только один порт то он развернется и пройдет через все устройства назад, причем на обратном пути обработки пакета уже не будет (помните? обработчик находится после порта 0) и он будет просто пересылаться.
На фото я соединил мастера с двумя слейвами.

Пока всё просто? Ну да, я забыл сказать — Ethercat на самом деле довольно простой протокол.
Таким образом мы получили шину. Теперь как сделать "кольцо"? Последний слейв надо соединить с мастером. Один нюанс — у мастера должно быть два ethernet порта. Тогда пакеты будут доходить до последнего в цепочке устройства и вместо того чтобы разворачиваться и идти назад сразу уходить мастеру. Зачем это нужно? Ну, это сэкономит сколько-то наносекунд, и кроме того даст возможность работать при одном отказе: Сделали кольцо — пакеты ходят по кругу. Разорвали в любом месте провод или вырубили один из слейвов — у нас получилось две шины и по прежнему есть связь со всем устройствами (кроме вырубленного).
Тут надо сказать, что эта надежность не абсолютная. Например, если слейв сломать так, что физический разрыв кабеля детектироваться не будет, но при этом пакеты уходить не будут — он будет "кушать" пакеты приходящие что на порт1, что на порт 0 и сеть работать не будет. Более реальный вариант — воткнули провод из одного из устройств не в следующее устройство а в обычный свитч понятия не имеющий об этом вашем ethercat. В итоге разрыва кабеля нет, порт открыт и пакеты в него уходят, а назад уже не возвращаются.
В теории, мастер может посылать пакеты типа "4-му слейву закрыть выходной порт" и с их помощью "огородить" проблемное место, а учитывая скорость работы перебор вариантов много времени не займет, но лично мы так не пробовали.
Если нужна нормальная надежность, чтобы при отказе любого числа устройств связь с остальными не терялась, нужна топология "звезда". Обычным для Ethernet способом — воткнув все слейвы в один свитчроутер ее не организовать. Ведь у слейвов нет IP адреса по определению (они не умеют обрабатывать ARP пакеты), а MAC адрес у них в лучшем случае у всех одинаковый. На помощь приходят слейвы с 4 портами.
Проблема в том, что и у решений от infineon, и у модулей microchip портов только 2.

На картинке от ethercat — вот эти блоки с кучей палочек это соединенные друг с другом блоки Beckhoff с 4-мя ethercat портами:
https://www.beckhoff.com/ru/default.htm?ethercat/ek1100.htm [7]
https://www.beckhoff.com/ru/default.htm?ethercat/ek1122.htm [8]

Без них топологию звезда не сделать, а стоят они не космических конечно денег, но все-таки подороже обычных ethernet switch. Наверное можно их сделать самим на ПЛИС, но это задача не для нашей конторы (во всяком случае пока).
Раз уж затронули тему обычных свитчейроутеров. С их точки зрения Ethercat пакет — пакет с broadcast целевым MAC адресом, так что они просто разошлют его по всем подключенным портам. Когда к свитчу подключено два слейва или мастер и слейв — все будет ок (свитч будет играть роль просто патчкорда), если подключить, скажем, мастера вместе с двумя слейвами или одного слейв — дело плохо, связи не будет.
С точки зрения программы, slave устроен типичным для микроконтроллеров способом — есть некая область памяти, мы можем ее читать и писать в нее. В случае с Infineon она маппится на адресное пространство МК, в случае с микрочипом к ней надо обращаться по SPI. Первые 4 килобайта (до 0x1000) — регистры, имеют специальное назначение описанное в стандарте ethercat, дальше идет пользовательская память где будут оказываться те данные которые пришли от мастера и куда надо помещать те данные которые к мастеру уходят.
Конкретно на XMC4800 этой пользовательской памяти 8 килобайт

Интересно что к этой памяти (а значит и настраивать все параметры обмена с помощью регистров) может обращаться как микроконтроллер слейва, так и мастер посылая EtherCAT пакеты. Логично что одновременный доступ двумя сторонами чреват гонками данных, но о том как это решено чуть позже.
Регистры описаны в даташите (в моем случае в даташите на XMC), упомяну самые интересные:
Отвлечемся ненадолго от слейва и вернемся к мастеру. От мастера требуется формировать ethercat пакеты заданной структуры и обрабатывать их когда они вернулись от слейва.
Пакеты имеют следующую структуру:

Как видим, пакеты могут иметь либо специализированный формат (тип пакета не TCP и не UDP, а 0x88A4), либо находиться внутри UDP пакета. С точки зрения слейва UDP заголовок просто ничего не значащие байты (адресация слейвов происходит уже внутри ethercat пакета), но зато он позволяет работать с Ethercat пакетами с компьютера — вместо каких-то низкоуровневых пакетов мы формируем и обрабатываем старые добрые UDP датаграммы.
Внутри идет заголовок и энное количество датаграмм:

Каждая датаграмма состоит из заголовка, основной части и важной штуки называемой Working counter (WKC).

Wkc — счетчик слейвов обработавших эту датаграмму. Когда датаграмма проходит через слейва, он инкрементирует wkc если читал ее данные и инкрементирует wkc если писал в нее данные (так что если он и читал и писал данные в одну и ту же датаграмму то wkc будет инкрементирован дважды). Можно, например, послать BRD датаграмму "прочитать нулевой байт" и по счетчику wkc понять сколько всего устройств находится на линии.
Итак, Cmd. Команды называются буквенными аббревиатурами из двух частей. Числовых кодов я никогда и не знал. BRD есть BRD.
| Первая часть аббревиатуры | Расшифровка |
|---|---|
| APxx | Топологическая адресация. ADP содержит "минус индекс слейва к которому обращаемся". Почему минус? Потому что каждый слейв будет инкрементировать это поле, и тот слейв к которому в этом поле придет 0x0000 обработает датаграмму. |
| FPxx | Физическая адресация. Ответит тот слейв у которого STATION_ADR совпадет с полем ADP |
| Bxx | Широковещательный пакет. Ответят все слейвы. Ах да, если отвечает несколько слейвов, результат получается логическим OR от их значений. Ну т.е. мастер отправляет в данных нули, а слейвы могут только заменять в пакете данные на единички но не сбрасывать в 0 |
| Lxx | Логическая адресация. Подробнее про нее рассказажу в разделе FMMU, но в этом случае в поле адреса находится 32-битный адрес, а слейвы в зависимости от своих настроек пишут или читают данные. Именно этими пакетами идет собственно опрос сотни моторчиков одним пакетом. |
| Вторая часть аббревиатуры | Расшифровка |
|---|---|
| xxRD | Чтение. Выбранные слейвы пишут данные в пакет (а мастер читает) |
| xxWR | Запись. Мастер записал данные, а выбранные слейвы их читают |
| xxRW | Чтение И запись. Кроме как в виде LRW выглядит как-то глупо, слейв сначала прочитает данные а потом запишет туда же. А вот с логической адресацией это наоборот основной тип датаграмм. |
| xxRMW | Один пишет остальные читают. Тот слейв у которого ADP совпал (см. расшифровку первых половин команд) запишет туда данные, а остальные будут читать. Учитывая что есть LRW не слишком полезная штука. |
EtherCAT решает возможные проблемы одновременного доступа к памяти (со стороны МК и со стороны пришедшего по сети пакета) с помощью концепции SyncManagerов.
SyncManager (SM) — специальный блок в модуле ethercat слейва, которому мы указываем на область адресов памяти слейва и он устанавливает особый режим доступа к этой памяти.
Управляются регистрами начиная с 0x800. Каждый SM имеет 8 регистров, т.е. 0x800-0x807 задают SM1, 0x808-0x80F задают SM2 и так далее. Всего у XMC4800 8 SyncManagerов.
В зависимости от настройки бывают двух типов — mailbox и буфер. Кроме того они могут быть настроены на запись либо на чтение. Картинки из презентации поясняют их довольно очевидно, но чтоб не передирать совсем внаглую распишу словами.
Mailbox — предназначены для организации своих протоколов вопрос-ответ поверх ethercat. Один пишет другой ждет, потом другой читает первый ждет.
Buffered — для обмена быстроменяющимися данными. Один все время пишет а второй читает последнюю согласованную копию.
Рассмотрю еще одну концепцию Ethercat, которая обеспечивает магию команд LRW. Это Fieldbus Memory Management Unit (FMMU). Она совсем простая. Проще SyncManagerов, да. Мы просто указываем область памяти в пространстве слейва, какому логическому адресу она соответствует и флаг пишет туда слейв или читает оттуда. Ах да, адресуется она с точностью до бита а не до байта, так что не повторяйте моей ошибки, если хотите работать с целым числом байтов, то StartBit ставьте 0, а EndBit — 7.
Если взять пример про который я сказал в самом начала, когда мы одной командой прочитали данные сотни датчиков и дали уставки сотне моторчиков. На каждом из датчиков мы используем FMMU0 установив логический адрес в 0x1000 (ну или где мы храним показания датчика), а логический адрес в 0x12345678+4*номер датчика, размер 4 байта, ну и направление READ. На каждом из моторчиков мы используем FMMU0 установив логический адрес в 0x1000 (ну или где мы будем хранить уставку скорости), а логический адрес в 0x12345678+400+4*номер моторчика, ну и направление WRITE. Теперь мастер может отправить один LRW пакет с логическим адресом 0x12345678, размером 800 байт, во вторую половину которого он запишет все уставки. А по приходу ответа прочитает из первой половины данные всех датчиков. Теоретически, моторчики могут даже читать данные которые отправил датчик, если находятся после него в топологии (так называемый slave2slave communication), но мы таким не заморачивались.
Разумеется, одно устройство может использовать несколько FMMU чтобы и писать и читать данные, ну и стоит настроить SyncManagerы на соответствующие адреса.
В EtherCAT заботливые Beckhoff положили еще много всяких наворотов. Например EEPROM который должен быть в каждом устройстве и который позволит мастеру настроить любой слейв и сохранить настройки. Граф переходов AL_STATUS, который будет гарантировать что слейв успел прочитать перед запуском обмена EEPROM и что мастер инициализировал выходы слейва нормальными значениями. CanOPEN-over-EtherCAT(CoE) который дает мастеру возможность узнать что этот слейв умеет и какие у него есть входывыходы. Ethernet-over-EtherCAT(EoE) и Files-over-EtherCAT (FoE) чтобы пересылать разное всякое. Бинарные ESI-файлы c тем самым VendorID и на редкость глючной утилитой их генерации. Синхронизация времени до наносекунд. Мы обошлись без всего этого в нашем проекте, поэтому я не готов о них подробно рассказывать, но основы EtherCAT я, надеюсь, изложил.
Автор: Андрей Коновод
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie-mikrokontrollerov/356375
Ссылки в тексте:
[1] микроконтроллеры Infineon XMC43004800: https://www.infineon.com/cms/en/product/promopages/xmc4300_4800-EtherCAT
[2] модули Microchip LAN9252: https://www.microchip.com/wwwproducts/en/LAN9252
[3] https://github.com/OpenEtherCATsociety/SOEM: https://github.com/OpenEtherCATsociety/SOEM
[4] WireShark: https://www.wireshark.org/
[5] ассоциации Ethercat: https://ethercat.org/en/membership_benefits.html
[6] https://ethercat.org/en/membership_application.html: https://ethercat.org/en/membership_application.html
[7] https://www.beckhoff.com/ru/default.htm?ethercat/ek1100.htm: https://www.beckhoff.com/ru/default.htm?ethercat/ek1100.htm
[8] https://www.beckhoff.com/ru/default.htm?ethercat/ek1122.htm: https://www.beckhoff.com/ru/default.htm?ethercat/ek1122.htm
[9] Источник: https://habr.com/ru/post/516624/?utm_source=habrahabr&utm_medium=rss&utm_campaign=516624
Нажмите здесь для печати.