Однажды передо мной встала задача разработать встраиваемую систему, в которой бы данные могли передаваться между узлами c максимальной надежностью. Тогда то я впервые и узнал о CAN.
В этой статье я хотел бы рассказать вкратце рассказать о том, что такое CAN и о своем опыте работы с ним. Возможно люди, которые занимаются разработкой встраиваемых систем, прочитав мою статью, заинтересуются этим стандартом, если он еще не попадал в их поле зрения. Тем более, что контроллеры CAN в настоящее время присутствуют на многих микроконтроллерах.
CAN (Controller Area Network) — это стандарт, созданный компанией Bosсh для сетей, используемых в автоматизации и промышленности. Стандарт нашел широкое применение в промышленном производстве, технологиях «умного дома», а так же в автомобилестроении. Очень хорошо подходит для связывания различных датчиков и управляющих устройств в единую сеть.
Как правило, CAN-сеть это сеть типа «шина», в которой все узлы могут передавать и принимать данные.
Она обладает небольшой скоростью, но высокой надежностью.
Далее я хочу поверхностно описать стандарт и рассказать об использовании такой сети на практике.
Стандарт
Стандарт описывает канальный уровень и базовые требования к физическому уровню.
Главное в физическом уровне — это требование возможности передачи бита как "доминантного" и "рецессивного". Доминантный сигнал считается единицей, а рецессивный — нулем. Основное требование — при передаче доминантного и рецессивного сигнала одновременно, всем узлам должен прийти доминантный сигнал. На этом принципе основан механизм арбитража. Из этого следует, что для передачи могут использоваться разные среды, однако на практике чаще всего используют дифференциальную пару.
Передача в сети происходит кадрами. В стандарте существуют два типа кадров: базовый и расширенный.
Базовый кадр содержит 11 битовый идентификатор, а расширенный — 29 битовый. Кадр так же содержит бит запроса на передачу, информацию о длине передаваемых данных и сами данные. Они могут занимать от 0 до 8 байт в кадре. Так же кадр содержит некоторую служебную информацию, но для программиста она не принципиальна, поскольку её добавление реализовано аппаратно в контроллере сети.
Изначально идентификаторы не привязаны к какому либо узлу и характеризуют именно сообщение, а не отправителя и получателя. Идентификаторы так же показывают приоритетность сообщения. Приоритет определяется доминантными битами в идентификаторе. Так 10000000000 приоритетнее чем 01000000000.
Главным достоинством CAN является его надежность. В нём используется механизм разрешения коллизий (в отличие от механизма обнаружения коллизий в Ethernet), что позволяет не терять пропускную способность из-за коллизий.
Его суть заключается в том, что каждый узел слушает сеть и, если она свободна, может начать передачу. При этом, он продолжает слушать сеть. Если при посылке рецессивного бита принимается доминантный, значит одновременно с этим узлом начал передачу другой узел с более высоким приоритетом. В этом случае передача прекращается.
Помимо этого используются механизмы обнаружения ошибок, такие как контроль передачи, дополняющие биты, использование контрольной суммы и проверка значений полей. Разработчики оценивают вероятность невыявления ошибки передачи как 4,7×10-11.
Данный стандарт не описывает протоколы верхнего уровня, поэтому было создано несколько реализаций, как коммерческих, так и открытых.
Наиболее известные из них:
— CANopen
— DeviceNet
— CAN Kingdom
Эту и даже более подробную информацию о стандарте легко найти в интернете, поэтому я наконец приступаю к описанию CANopen.
CANopen
Как я уже писал, однажды мне потребовалось создать надежную сеть из микроконтроллеров. После рассмотрения возможных вариантов было решено остановиться на сети CAN. В качестве протокола верхнего уровня был выбран CANopen и его реализация — CANopenNode, поскольку она является открытой и простой в портировании на нужное мне устройство. CANopenNode лицензирован под LGPL.
Основные моменты протокола CANopen:
— протокол работает со стандартными идентификаторами. Сеть может содержать до 127 узлов.
— каждому узлу выдается уникальный номер в сети.
— протокол не требует обязательного наличия мастера сети (однако существуют возможности, которые доступны только одному узлу в сети, который условно можно назвать мастером)
— OD (Object Dictionary ) — словарь объектов. Содержит отсортированный список переменных, доступ к которым можно получить по сети с помощью SDO.
— SDO (Service Data Objects) — механизм доступа к словарю объектов. Для доступа к объектам узла сети на этом узле должен быть запущен так называемый SDO-сервер. В сети может быть только один SDO-клиент, условно называемый мастером, который может получать данные от любого из серверов.
— PDO (Process Data Objects) — объекты для быстрого взаимодействия между узлами. Могут содержать до 8 байт данных и передаются в одном кадре. Для каждого PDO выделяется свой идентификатор (в определенном диапозоне). PDO условно делятся на входящие (RPDO) и исходящие (TPDO). Изначально предполагается, что каждый узел будет иметь по 4 RPDO и 4 TPDO, однако их можно перераспределить между узлами вплоть до того, что один узел будет иметь возможность принимать и передавать до 512 PDO. Однако в этом случае на другие узлы идентификаторов не хватит.
PDO могут посылаться по таймеру, по наступлению определенного события либо по прямому запросу на посылку из управляющей программы.
— NMT (Network Management) — менеджер сети. Сообщения этого типа могут переводить узлы в разные состояния (инициализация, рабочее, предрабочее, остановленное), а так же с их помощью обеспечивается контроль работы сети — механизм heartbeat.
— Heartbeat — переводится как сердцебиение. Суть механизма заключается в том, что каждый узел передает в сеть определенное сообщение, уникальное для каждого узла (ID получается путем прибавления номера узла в сети к определенному числу). Любой узел, который хочет узнать, по прежнему ли ему доступны узлы с определенными id должен просто принимать и обрабатывать эти сообщения. Сообщения от неинтересных для него узлов могут игнорироваться.
— Emergency message — в протоколе предусмотрена посылка сообщений об аварийных ситуациях.
— EDS (Electronic Data Sheets) — специальные текстовые файлы, позволяющие настроить словарь объектов. Существуют программы, помогающие в генерации таких файлов.
CANopenNode
CANopenNode — открытая реализация протокола CANopen, написанная на чистом С для использования в микроконтроллерах.
Теперь я опишу особенности, с которыми мне пришлось столкнуться при работе с CANopenNode.
1. Я использовал 32-битный контроллер, а CANopenNode изначально написан для 8/16 битных. Из-за этого в одном месте таймер сходил с ума, поскольку вместо того, чтобы переполниться и, как следствие, обнулиться, он продолжал расти и в механизме хартбита выдавалась ошибка о том, что поголовно все узлы превысили время ожидания нового хартбита.
2. Моя задача предполагала, что я могу передавать большие объемы данных. При этом несколько контроллеров могли передавать эти данные, а остальные — получать. Пришлось отказаться от механизма SDO (поскольку в нем только один контроллер имел бы возможность посылать данные с размером больше чем 8 байт) и написать свою собтвенную надстройку, которая использовала первые два байта PDO в виде управляющей информации.
3. Решение из пункта два привело к тому, что мне потребовалось однозначно определять участников взаимодействия, что возможно сделать только с помощью идентификаторов.
Это был, пожалуй, самый тонкий момент в работе. Было решено ограничить количество «мастеров» четырьмя штуками. Эти четыре узла получали 127 PDO на вход и на выход. А остальные узлы работали с 4 входящими и исходящими PDO. При чем, идентификаторы PDO были распределены так, что узлы-«ведомые» имели по одному исходящему сообщению, каждое из которых читал только определенный «мастер» и по одному входящему сообщению от каждого «мастера». Мастера же соответственно имели по одному каналу для обращения лично к любому из «ведомых» и точно знали, кто из них обращается к нему.
Эта концепция была сложнее всего, так как даже на форумах, где люди работают с CAN, бытует мнение, будто CANopen нельзя настроить подобным образом.
4. Настройка идентификаторов в данном протоколе происходит в коде. Более того, от неё зависят id узлов, которые будет читать и принимать конкретный узел. Поэтому смена id на ходу представляется сложной для данного протокола и требует дополнительных усилий.
В виде заключения
В конце концов, я пришел к выводу, что данный протокол не совсем хорошо ложится на мою задачу и что мне придется написать свою реализацию. Однако, за время, которое я провел, разбираясь с этим протоколом, я намного лучше понял принципы работы с сетью CAN. Если Вам нужно быстро получить работающее приложение, использующее все преимущества надежной доставки, если Вы хотите, чтобы Ваше приложение было совместимо со многими уже существующими системами, если Вам нужны готовые средства отладки CAN-сети, то CANopen — это очень хороший выбор.
Я с удовольствием отвечу на любые вопросы, принимаю критику и дополнения, а так же могу подробнее остановиться на каких-либо моментах, если кому-нибудь это будет интересно.
Спасибо Вам за внимание!
Ссылки на некоторые ресурсы, связанные с CAN
www.can-cia.org/ — (англ.) международная организация CAN in Automation.
sourceforge.net/projects/canopennode/ — (англ.) проект CANopenNode
Автор: GreyM