Всех приветствую, сегодняшняя статья будет целиком и полностью посвящена обзору протокола CAN. А в одной из следующих статей мы реализуем обмен данными по CAN на практике. Но не буду забегать вперед...
CAN (Controller Area Network) - это промышленный стандарт, позволяющий осуществить объединение в единую сеть различных узлов, механизмов, датчиков и т. п. Протокол является широковещательным, это значит, что все устройства в CAN-сети принимают все передаваемые по шине сигналы. Режим передачи данных - последовательный, при этом байты сообщений формируют кадры определенного вида. Структуру этих кадров данных мы также обязательно разберем в этой статье.
Основные характеристики протокола CAN:
- очень высокая надежность и защищенность
- каждое сообщение имеет свой собственный приоритет
- реализован механизм обнаружения ошибок
- автоматическая повторная отправка сообщений, которые были доставлены с ошибкой
- уже упомянутый широковещательный характер передачи данных
- возможность присутствия нескольких ведущих (master) устройств в одной сети
- широкий диапазон скоростей работы
- высокая устойчивость интерфейса к помехам
- кроме того, есть механизм обнаружения "сбойных" узлов с последующим удалением таких узлов из сети.
Первоначально стандарт был разработан для автомобильной промышленности. И занималась этим компания Bosch в 1980-х годах. Основная идея заключалась в том, чтобы уйти от использования огромного количества проводов, соединяющих многочисленные узлы автомобиля. И протокол CAN позволил этого достичь. С тех пор CAN является основным механизмом соединения устройств, узлов и датчиков автомобиля между собой. Помимо этого, интерфейс CAN активно используется в промышленной автоматизации, а также в системах "умного дома".
Давайте перейдем к физическому уровню протокола. В интернете можно найти много противоречивой информации на этот счет, но истина тут одна ) Стандарт CAN компании Bosch не регламентирует физический уровень передачи данных, поэтому могут использоваться абсолютно разные варианты, например, оптоволокно. На практике же чаще всего используется соединение посредством двухпроводной дифференциальной линии (витой пары). Ориентировочная максимальная длина линии для разных скоростей передачи данных составляет:
Скорость | Длина линии |
---|---|
1 Мбит/с | 50 м |
500 кбит/с | 100 м |
125 кбит/с | 500 м |
10 кбит/с | 5 км |
Важным условием работоспособности шины является наличие на концах витой пары согласующих резисторов, которые также называют терминаторами, с сопротивлением 120 Ом:
В отличие от многих других протоколов в CAN не рекомендуется описание битов данных как "логического нуля" и "логической единицы". Здесь используются понятия доминантный и рецессивный бит.
Важнейшим свойством является то, что если один из узлов сети хочет выставить на линии рецессивный бит, а другой доминантный, то в итоге на линии окажется доминантный бит. В общем-то отсюда и следует его название, от слова "доминировать" ) Очень хорошо этот процесс иллюстрирует пример с оптоволоконной линией. Как вы помните, в оптоволокне для передачи данных используется "свет", либо он есть (единица), либо его нет (ноль). При использовании в CAN-сети "свет" - доминантный бит, соответственно, отсутствие света или "темнота" - рецессивный.
Вспоминаем про важнейшее свойство передачи данных в сети. Пусть один узел выставляет на линии рецессивный бит, то есть "темноту". Второй узел, напротив, выставляет доминантный бит - "свет". В итоге на линии будет "свет", то есть доминантный бит, что в точности соответствует требованиям сети:
При использовании электрического сигнала устройство, желающее передать в линию доминантный бит, может подтянуть линию к земле. Это и приведет к тому, что на линии будет доминантный бит независимо от того, что выдают на линию другие участники коммуникации.
Это свойство используется для арбитража в сети CAN. Пусть несколько устройств хотят передать данные. Каждый из этих передатчиков сравнивает значение, которое он передает, со значением, фактически присутствующим на линии. В том случае, если передаваемое значение совпадает со считанным, устройство продолжает высылать свои данные. Если значения совпали у нескольких устройств, то все они продолжают передачу как ни в чем не бывало.
Продолжается это до того момента, когда значения станут различными. Если несколько устройств хотят передать рецессивный бит, а одно - доминантный, то в соответствии с правилом, которое мы обсудили выше, на линии окажется доминантный бит. В таком случае отправленные и считанные значения для устройств, пытающихся выдать на линию рецессивное состояние, не совпадут. В этом случае они должны прекратить передачу. А тот узел, который в этот момент передавал доминантный бит, продолжит свою работу. Доминирование в чистом виде )
Сигналы, которые передаются по витой паре, получили название CAN_H и CAN_L (High и Low). Доминантное состояние соответствует случаю, когда потенциал сигнала CAN_H выше потенциала CAN_L. Рецессивное - когда потенциалы равны (разница потенциалов не превышает допустимого отклонения, 0.5 В).
С этим вроде бы разобрались, давайте двигаться дальше! Пришло время определить, как биты объединяются в кадры. Протокол CAN определяет 4 вида кадров:
- Кадр данных (data frame)
- Кадр удаленного запроса (remote frame)
- Кадр перегрузки (overload frame)
- Кадр ошибки (error frame)
Для кадра данных возможны два варианта - базовый формат и расширенный. Вот так выглядит структура базового формата:
Поле | Длина | Описание |
---|---|---|
Начало кадра (SOF) | 1 бит | Начало передачи кадра |
Идентификатор (ID) | 11 бит | Идентификатор сообщения |
Запрос на передачу (RTR) | 1 бит | Доминантный бит |
Бит расширения идентификатора (IDE) | 1 бит | Бит определяет длину идентификатора, для базового формата - доминантный бит |
Зарезервированный бит | 1 бит | Зарезервировано |
Длина данных (DLC) | 4 бита | Количество байт данных |
Данные | 0 - 8 байт | Данные |
Контрольная сумма (CRC) | 15 бит | Контрольная сумма |
Разграничитель контрольной суммы | 1 бит | Рецессивный бит |
Промежуток подтверждения (ACK) | 1 бит | Для приемника - доминантный бит, для передатчика - рецессивный |
Разграничитель подтверждения | 1 бит | Рецессивный бит |
Конец кадра (EOF) | 7 бит | Все биты рецессивные |
А это структура расширенного:
Поле | Длина | Описание |
---|---|---|
Начало кадра (SOF) | 1 бит | Начало передачи кадра |
Идентификатор A (ID A) | 11 бит | Первая часть идентификатора |
Подмена запроса на передачу (SRR) | 1 бит | Рецессивный бит |
Бит расширения идентификатора (IDE) | 1 бит | Бит определяет длину идентификатора, для расширенного формата - рецессивный бит |
Идентификатор B (ID B) | 18 бит | Вторая часть идентификатора |
Запрос на передачу (RTR) | 1 бит | Доминантный бит |
Зарезервированные биты | 2 бита | Зарезервировано |
Длина данных (DLC) | 4 бита | Количество байт данных |
Данные | 0 - 8 байт | Данные |
Контрольная сумма (CRC) | 15 бит | Контрольная сумма |
Разграничитель контрольной суммы | 1 бит | Рецессивный бит |
Промежуток подтверждения (ACK) | 1 бит | Для приемника - доминантный бит, для передатчика - рецессивный |
Разграничитель подтверждения | 1 бит | Рецессивный бит |
Конец кадра (EOF) | 7 бит | Все биты рецессивные |
Результирующий идентификатор получается в результате объединения полей "Идентификатор A" и "Идентификатор B".
Кадр удаленного запроса (remote frame) представляет из себя кадр данных, описанный выше, но без поля данных и с рецессивным битом RTR. Он используется в случае, когда один узел хочет запросить данные у другого узла.
Кадр ошибки (error frame) передает устройство, обнаружившее ошибку в сети. Фрейм ошибки имеет наивысший приоритет и принимается всеми устройствами сети в обязательном порядке.
Кадр перегрузки (overload frame) используется очень редко. Его идея и назначение заключаются в том, что с его помощью устройство, которое в данный момент не может принять данные, запрашивает повторную передачу этих же данных.
Давайте вернемся чуть назад, к арбитражу данных, и рассмотрим, что это может означать на практике. Итак, несколько устройств начинают передачу сообщения, а точнее кадра данных. Передается бит начала кадра и затем начинается передача идентификатора сообщения. Как вы помните, приоритет будет у того устройства, которое будет передавать доминантный бит, в тот момент, когда все остальные будут передавать рецессивный. То есть чем "позже" среди битов идентификатора появится "рецессивный бит", тем выше будет его приоритет. Другими словами: более высокий приоритет при использовании интерфейса CAN имеют сообщения с меньшим значением идентификатора.
Первые два типа кадров - кадр данных и кадр удаленного запроса - отделяются от других кадров специальным межкадровым промежутком (паузой). А для фреймов ошибки и перегрузки предусмотрена передача без пауз, чтобы обеспечить их скорейшую обработку узлами сети.
Итак, что у нас на очереди теперь? Конечно же контроль ошибок - важнейший аспект работы протокола CAN. Стандарт предусматривает несколько механизмов:
- Во-первых, это контроль передачи битов - уровень сигнала в сети сравнивается с передаваемым для каждого бита.
- Второй механизм заключается в использовании дополнительных битов (stuffing bit). После передачи любых пяти одинаковых битов автоматически добавляется передача бита противоположного значения. Таким образом, при передаче шести одинаковых битов диагностируется ошибка stuffing'а. Этот механизм используется для кодирования всех полей фреймов данных и запроса. Исключением являются только поля промежутка подтверждения, разграничителя контрольной суммы и EOF.
- Стандартная процедура проверки контрольной суммы. Передатчик вычисляет контрольную сумму для текущего кадра и передает ее в линию. В свою очередь, приемник также вычисляет контрольную сумму для принимаемых данных и сравнивает ее с тем значением, которое было отправлено передатчиком. В случае не совпадения значений диагностируется ошибка CRC.
- Также выполняется контроль битов фрейма, которые должны иметь заранее определенное значение. В случае, если реальное значение не совпадает с тем, которое ожидается, возникает ошибка.
Благодаря всем этим механизмам, вероятность необнаружения ошибки является очень низкой, что, конечно же, не может не радовать 👍
Кроме того, если один из узлов обнаружил ошибку в сообщении, он сообщает об этом в сеть CAN при помощи фрейма ошибки. А поскольку сеть у нас широковещательная, то о возникновении ошибки становится известно всем участникам коммуникации. И если в сообщении была обнаружена ошибка, его передача будет осуществлена еще раз.
И на этом еще не все! Каждый узел может находиться в одном из трех состояний:
- Error Active
- Error Passive
- Bus Off
Протокол CAN предусматривает, что изначально, после старта, узел находится в первом из этих состояний - Error Active. Каждое устройство имеет два счетчика ошибок:
- Счетчик ошибок передачи
- Счетчик ошибок приема
Существуют определенные правила обслуживания этих счетчиков, которые сводятся к следующему. Передатчик, обнаруживший ошибку, увеличивает свой счетчик ошибок передачи быстрее, чем приемники увеличивают свои счетчики ошибок приема. Это связано с предположением, что при ошибке, вероятность того, что сбой произошел именно в передатчике, а не в приемнике, достаточно велика. На практике ошибка передачи увеличивает соответствующий счетчик на 8, а ошибка приема лишь на 1. При приеме или передаче корректного сообщения как счетчик ошибок передачи, так и счетчики ошибок приема уменьшаются на 1.
Если значение любого из этих двух счетчиков узла превысит значение 127, то узел переходит в состояние Error Passive. А если величина одного из счетчиков превысит 255, то узел перейдет в состояние Bus Off.
Разница между этими состояниями заключается в действиях узла при диагностировании ошибки:
- Узел в состоянии Error Active при обнаружении ошибки передает в шину Active Error Flags - 6 доминантных бит. Поскольку биты доминантные, то это сообщение нарушает обычную работу шины и поэтому все устройства сети также фиксируют возникновение ошибки.
- Узел в состоянии Error Passive при обнаружении ошибки передает в шину Passive Error Flags - 6 рецессивных бит, которые игнорируются всеми другими участниками обмена. Поэтому увеличивается только величина счетчика ошибок одного конкретного узла.
- И, наконец, узел в состоянии Bus Off ничего не передает в сеть - ни фреймы ошибок, ни фреймы данных, ни какие-либо другие.
Как видите, протокол CAN крайне интересен для изучения, надежен, безопасен, и удобен в использовании. И на этой позитивной ноте на сегодня заканчиваем, скоро займемся практической реализацией протокола, также поговорим о микросхемах и устройствах, обеспечивающих работу с CAN. Так что подписывайтесь на обновления, буду рад снова видеть вас на нашем сайте 🤝
Полезная статья! Спасибо, давно искал инфу про CAN
Спасибо!
А правильно ли Я понимаю что на физическом уровне CAN, RS485, Modbus ни чем не отличаются?
Добрый вечер!
RS485 - это стандарт, описывающий физический уровень передачи. То есть RS485 определяет как именно соединены устройства физически (витая пара). При этом RS485 не имеет отношения к тому, как передаются данные с точки зрения битов и байтов.
Modbus - это как раз протокол, определяющий порядок следования байт, то есть команды, которые устройства передают друг другу. И как раз Modbus чаще всего используется при передаче данных через RS485.
То есть физически два устройства соединены по RS485 - два сигнала, витая пара и т. д. И по этой витой паре передаются данные в соответствии с протоколом Modbus.
RS485 - это способ передачи, а Modbus - это язык передачи данных!
У Вас ошибка в статье. Надо убрать в расширенной структуре второй "Бит расширения идентификатора (IDE)". Исправьте, пожалуйста.
Большое спасибо!
Здравствуйте! В базовом кадре бит IDE рецессивный, т.е. "1", а в расширенном доминантный, т.е. "0". А у вас наоборот всё.
Доброго времени суток! Нет, для базового - доминантный, для расширенного - рецессивный.
Насколько я знаю, в CAN все наоборот: рецессивный бит соответствует высокому логическому уровню, а доминантный бит - низкому логическому уровню. Т.е. "свет" в ваших обсуждениях - это ноль, а "темнота" - единица
Добрый день!
В CAN по сути только одно требование - чтобы доминантный сигнал мог подавить рецессивный. Поэтому в контексте электрических сигналов, доминантный бит - низкий уровень. А в случае оптики - доминантный - "свет".
Cпасибо интересно. Обратился к этой статье в результате попытки адаптировать систему Lada Ride Select, на Икс Рей кросс, на котором данная система не была с завода. В результате установки переключателей и перепрошивки всего что перепрошивается , на переключателе 5 сек мигает светодиод и он гаснет, и на программаторе(не я подключаю) пишет ошибка чтения кадров. Однако даже после того как переключатель гаснет программатор показывает что шайбу вращаешь и вправо и в лево и что нажимаешь кнопку спорт. Может впаять резистор параллельно кан шине?
Извините но так и не понял как приёмный блок понимает, что сообщение адресовано ему и что в нём передаётся.
Первое поле ID пишут что это арбитражное поле и оно только для выбора приоритета вещания.
Здравствуйте! Как раз по полю ID приёмный блок и понимает, что это ему сообщение. А приоритет определится сам, исходя из значений ID. Приоритет нужен только когда несколько устройств передают одновременно. Т.е. такая ситуация: в сети CAN два устройства (разных). Передают в сеть сообщения. Первое устройство с ID 16#7E1, второе устройство с ID 16#7E2. Побитно эти цифры выглядят так:
ID1 0111 1110 0001
ID2 0111 1110 0010
В результате на шине окажется сообщение ID2 потому, что нулевой бит у ID2=0, а ноль имеет приоритет. (Передача ведётся справа налево, от младшего бита к старшему).
Каждое устройство имеет набор сообщений с разными ID. Нельзя иметь в одной сети CAN два одинаковых устройства. Иначе оба устройства будут транслировать сообщения с одинаковым ID. И понять от какого устройства это сообщение не возможно.
Спасибо за ответ, но всё равно не доходит). Получается нет мастеров и слейвов как к примеру в ModBus, а все галдят что хотят, но при этом слушают и как только своё узнали - тут же забирают? Нет какого-то общего организатора обмена, а заранее в каждый блок закладывается, что он передаёт и что принимает, а шину используют как общий вагон в метро... Ещё не пойму зачем арбитраж, когда есть физическая адресация блоков. Она же есть в автомобильном CAN? В промышленном то точно есть.
А говоришь, не доходит. Всё верно. Мастеров и слейвов нет. Да, в каждом блоке сообщения со своим идентификатором (ID). Потому и нельзя два одинаковых блока вешать на одну шину. Так нет же в CAN физической адресации блоков, потому нужен арбитраж. Я описал выше, когда два устройства передают пакеты, выиграет тот, который передаст ноль. У которого единица, тот замолчит. Это и есть арбитраж. Приведи пример, где видно, что в промышленном CAN есть адресация блоков? И как отличаются автомобильный CAN от промышленного? CAN это шина передачи данных, даже не шина, а протокол. Физическая шина здесь RS485. Есть расширение этой шины - CANOpen. Стандартная шина CAN имеет два стандарта: CAN 2.0A - здесь ID= 11 bit, CAN 2.0B - здесь ID= 29 bit. А адресация блоков если и есть, то для других целей.
Так то я пром электроник). Побежал глянул оборудование. Ну вот один станок с CAN и адресацией, см фото. Это немецкий производитель пром оборудования Motan. А остальные Siemens, Lenze, Schneider действительно без адресации, как-то всё это время и не задумывался...
Прошу не путать физический уровень и прикладной. CANOpen это прикладной, я-ля Modbus.
"Физическая шина здесь RS485" - совсем нет. то что дифференциальный сигнал, да. Уровни напряжений другие !
Суть ухвачена верно ) Вкратце распишу тоже, хотя в целом Сергей уже все описал.
ID привязан не к блоку, а к пакету. Допустим, в сети 10 блоков, один из них высылает данные с ID = 0x300, все блоки принимают это сообщение (физически шина одна и та же), далее софт внутри каждого из блоков анализирует, нужно ли выполнить обработку этого сообщения. То есть в каждый из блоков попадут все пакеты, а дальше уже либо аппаратно, либо программно будут фильтроваться и обрабатываться.
Из этого вытекает необходимость арбитража, поскольку блоки не синхронизированы между собой, в произвольный момент времени передачу могут начать несколько блоков одновременно. Тогда происходит, как описал Сергей выше - допустим, что два блока одновременно пытаются передавать пакеты, данные вываливаются в шину побитно, в какой-то момент биты сообщений различны, и таким образом определяется более приоритетное сообщение. Блок, который отправляет этот пакет продолжает отправку, блок, сообщение которого оказалось менее приоритетно, прекращает отправку и ожидает освобождения шины для повторной отправки этого же сообщения.
То есть необходимость арбитража вытекает из того, что физически шина одна, а блоков много. То есть грубо говоря ресурс один, а желающих им воспользоваться несколько. Допустим, дверь в вагоне метро одна, а одновременно зайти хотят 15 человек, сначала заходит самый сильный (или ловкий), затем остальные )
Спасибо за ответ! Ну т.е. захотелось мне сделать сеть из 10 блоков. И в каждый нужно сделать свой софт, что бы они все вместе понимали друг друга. Т.е. сторонний блок, не зная досконально весь проект - не подключить. Т.е. шина не стандартизованная что-ли получается? Тема в общем у меня возникал после установки автосигнализации Starline на автомобиль, посредством CAN. И вот начали возникать всякие глюки...
Наверно должны быть какие-то соглашения из серии "блок сигнализации отправляет пакет с таким-то ID", и разные реализации блока должны поддерживать это соглашение.
"ожидает освобождения шины для повторной отправки этого же сообщения". Если отключена функция "повтор передачи" (Automatic Retransmission, например, на STM32), то при потере арбитража и освобождения шины узел повторит отправку ?
Отправку не повторит, но ошибка будет диагностироваться, как с флагом, так и без. С Automatic Retransmission какой-то нюанс смутно припоминается, но что-то слишком смутно, потом напишу, если вспомню.
Арбитраж нужен в случае нескольких Master-устройств. А режим один Master и несколько Slave кто мешает организовать ? Есть же Remote Frame ! А адрес устройства как раз и закладывается в ID. В Slave настраиваешь фильтр только на свой адрес, а Master отправляет запросу поадресно каждому Slave-устройству.
В CAN как таковом нет понятий Master и Slave, собственно, в том числе из-за этого арбитраж и необходим. Топология сети - master'ы/slave'ы - это уже на уровнях выше при необходимости.
Нет. Нет в CAN мастера и слэйва. И нет адреса устройства. Есть сообщения, которые имеют ID (идентификационный номер).
ID1 окажется. он выиграет арбитраж на предпоследнем бите
"Передача ведётся справа налево, от младшего бита к старшему". Откуда такая информация ? Тогда бы нам пришлось всегда ID отображать зеркально ? Мы же этого не делаем.
Вот здесь спорить не буду. Не проверял такие тонкости. Слева направо или наоборот. Не знаю. Просто привык, что нумерация битов всегда с права на лево. Ну и думаю, что они и передаются от младшего к старшему. Кстати, вопрос интересный. Нужно бы разобраться.
Сегодня где-то прочитал, что передается MSB First (старшим битом вперед). Специально еще посмотрел. На диаграмме передачи показано старшим битом вперед все данные (поля) передаются. Тоже самое и для DLC-поля.
Здравствуйте, возникла такая проблема при использовании CAN1 и CAN2, оба интерфейса настроены на прием и передачу, Normal режим. Все время сваливаюсь в HALL_ERROR от HAL_CAN_GetRxMessage сообщение до этого отправляется. С чем может быть связана данная проблема. фильтры есть, хедер на прием и переду настроены корректно. Схемотехника на мк работает корректно, при использовании анализатора CAN1-CAN2 слушает и принимает, у него все ок. Плата stm32f407
место где сваливаюсь в ошибку
Вызов в main до этого
Приветствую! Сейчас в одном проекте использую тоже CAN1 и CAN2 и тоже на F407, вроде все стабильно. А внутри HAL_CAN_GetRxMessage() откуда ошибка вываливается?
как раз при проверке пустое ли FIFO
могу залить проект на яндекс диск и дать ссылку, если это поможет
по сути даже прерывание по приему не формируется и в callBack не попадаю
Да, как раз проект собирался спросить.
Ссылка на рабочий проект, https://disk.yandex.ru/d/LMdqvYssrL-LkA
до этого было сделано с помощью структуры файлик can.c
подумал что где-то накосячил, решил упростить и сделать все в main.c для того чтобы понять ошибку, не помогло
Так, ну функция ошибку возвращает потому что очередь пуста. А чтобы прием проверить предлагаю убрать из main'а все фильтры и отправку тоже убрать. В целом все в норме на первый взгляд, без фильтров колбэк должен срабатывать при приеме фрейма.
А да, в мейне еще опечатка:
hcan1 в HAL_CAN_Start().
при отправке данных на шину с помощью анализатора сами данные туда не попадают, и получается что CAN2 в ошибку и сваливается, колбэк по прежнему отдыхает
Проверил в своем проекте на STM32F407VG, по итогу так - конфигурация:
Отправка через CAN1:
Прием через колбэк:
Результат на скрине, короче функционирует, можно начать с этой базы для тестирования.
Электрически у меня: CAN1 > TJA1044 > CAN_H / CAN_L <CAN bus> CAN_H / CAN_L > TJA1044 > CAN2.
спасибо, пойду копать в глубь. будет решение поделюсь