19. Шина CAN
Шина для связи между устройствами, а не между микросхемами на одной плате. Родилась в автомобилях и осталась там же, плюс промышленная автоматика: всё, где узлы разнесены на метры, вокруг помехи, а сообщение обязано дойти.
Как это называется в документации
Оригинал Перевод transceiver приёмопередатчик, трансивер dominant / recessive bit доминантный / рецессивный бит arbitration арбитраж identifier идентификатор сообщения mailbox почтовый ящик передачи receive FIFO очередь приёма acceptance filter фильтр приёма bit timing битовый тайминг sample point точка выборки bus-off отключение от шины по ошибкам loopback mode режим самопроверки
19.1 Чем она отличается от всего остального
Нет ведущего. Любой узел может начать передачу в любой момент. Конфликты разрешаются арбитражем, а не расписанием.
Адресуется сообщение, а не устройство. В кадре нет получателя — есть идентификатор темы: «обороты двигателя», «состояние двери». Кто хочет, тот и слушает. Добавить новый узел можно, не трогая существующие.
Дифференциальная пара. Два провода с противофазными сигналами. Помеха наводится на оба одинаково и вычитается — отсюда устойчивость на длинных линиях в электрически грязной среде.
Контроль ошибок встроен в железо. Контрольная сумма, подтверждение приёма, автоматический повтор при сбое — всё это делает контроллер сам.
19.2 ⚠️ Трансивер обязателен
Микроконтроллер нельзя подключить к шине CAN напрямую. Его выводы дают обычные логические уровни, а шина работает дифференциальной парой с уровнями другого стандарта.
Между ними ставится трансивер — отдельная микросхема:
| Трансивер | Питание |
|---|---|
| SN65HVD230 | 3,3 В — удобно для STM32 |
| MCP2551, TJA1050 | 5 В — нужен согласователь уровней или толерантные выводы |
Терминаторы. На обоих концах линии — резисторы 120 Ом. Не два где попало, а именно на концах: они гасят отражения. Один резистор или три вместо двух — и связь работает через раз, тем хуже, чем длиннее линия. Многие готовые модули имеют терминатор на плате и перемычку для его отключения; на промежуточных узлах его надо снимать.
19.3 Арбитраж: почему выигрывает меньший идентификатор
Логика шины устроена так, что ноль доминирует над единицей: если один узел передаёт ноль, а другой единицу, на линии будет ноль.
Отсюда весь арбитраж. Начав передачу одновременно, узлы выдают свои идентификаторы бит за битом и одновременно слушают линию. Как только узел видит, что передал единицу, а на линии ноль, — он понимает, что проиграл, и молча замолкает. Победитель даже не знает, что был конфликт, и продолжает передачу без задержки.
Практический вывод: меньший идентификатор — выше приоритет. Распределяя номера сообщений, срочные вещи вроде аварийных сигналов получают младшие номера, телеметрию отправляют в старшие.
Так выглядит арбитраж двух узлов, начавших передачу одновременно, — на экране анализатора, подключённого к выходам обоих контроллеров и к шине:
19.4 Битовый тайминг
Самая техничная часть настройки. Каждый бит делится на кванты времени:
бит = 1 (синхронизация) + TS1 + TS2 квантов
скорость = частота шины / (BRP × (1 + TS1 + TS2))
Значение считывается на границе между TS1 и TS2 — это точка выборки.
Её положение важно: слишком рано — не успеет установиться уровень на длинной
линии, слишком поздно — не останется запаса на рассинхронизацию.
Рекомендуемое значение — около 87,5 % длины бита.
Пример для 500 кбит/с при 36 МГц:
BRP = 9, TS1 = 6, TS2 = 1 → 8 квантов на бит
36 000 000 / (9 × 8) = 500 000 бит/с
точка выборки = (1 + 6) / 8 = 87,5 %
Другие ходовые скорости от той же тактовой:
| Скорость | BRP |
Квантов |
|---|---|---|
| 1 Мбит/с | 4 | 9 |
| 500 кбит/с | 9 | 8 |
| 250 кбит/с | 18 | 8 |
| 125 кбит/с | 36 | 8 |
Регистр BTR пишется только в режиме инициализации, а после сброса блок
ещё и спит (бит SLEEP в MCR). Порядок такой:
CAN1->MCR &= ~CAN_MCR_SLEEP; /* после сброса блок спит */
CAN1->MCR |= CAN_MCR_INRQ; /* режим инициализации: BTR пишется только в нём */
for (timeout = 100000u; !(CAN1->MSR & CAN_MSR_INAK); timeout--) {
if (timeout == 0u) {
return 1u;
}
}
CAN1->BTR = ((CAN_BRP - 1u) << 0)
| ((CAN_TS1 - 1u) << 16)
| ((CAN_TS2 - 1u) << 20)
| ((CAN_SJW - 1u) << 24);
CAN1->MCR &= ~CAN_MCR_INRQ; /* выход: ждёт 11 рецессивных бит подряд на RX */
for (timeout = 100000u; CAN1->MSR & CAN_MSR_INAK; timeout--) {
if (timeout == 0u) {
return 2u; /* на RX нет рецессивного уровня */
}
}
Второе ожидание кончается, только когда на RX пройдут 11 рецессивных бит подряд. Если там ноль — трансивер не запитан или не подключён, выбран не тот вывод (у F103 CAN по умолчанию на PA11 и PA12, после ремапа — на PB8 и PB9), — без тайм-аута программа повиснет здесь навсегда.
⚠️ Все поля кодируются как «значение минус один». Хотите
TS1= 6 квантов — записываете 5. Забыли вычесть — получите другую скорость и связь, которая не работает, хотя формула вроде посчитана верно.
Вкладка «CAN» в калькуляторах приложения подбирает BRP, TS1 и TS2 под
скорость и такт, показывает точку выборки и слово BTR уже с вычтенными
единицами; свои поля можно проверить там же.
⚠️ Скорость должна совпадать у всех узлов точно. В отличие от UART, где допустима погрешность в пару процентов, здесь расхождение приводит к ошибкам кадров и уходу узла с шины.
Насколько точно — считают из тайминга. Допуск частоты каждого узла —
меньшее из двух чисел: Δf ≤ TS2 / (2 · (13 · N − TS2)) и
Δf ≤ SJW / (20 · N), где N — квантов на бит, а SJW — на сколько квантов
узел подстраивает бит по фронту: от 1 до 4 и не больше TS2 (в примере — 1).
Первая формула — для TS2 не длиннее TS1, как здесь. Для примера
(8 квантов, TS2 = 1, SJW = 1) это 1 / 206 = 0,49 % и 1 / 160 = 0,63 %:
каждому узлу — не хуже 0,49 %. Внутренний генератор HSI с его ±1 % этого
не даёт — CAN тактуют от кварца.
19.5 Фильтры приёма
На загруженной шине сообщений сотни в секунду, и разбирать их все программно расточительно. Контроллер умеет отсеивать ненужное аппаратно: до того, как процессор о них узнает.
Фильтр работает в одном из двух режимов:
- по маске — принимать всё, что совпадает по значимым битам («любое сообщение с идентификатором, начинающимся на 0x1»);
- по списку — принимать только перечисленные идентификаторы.
void can1_filter_accept_all(void)
{
CAN1->FMR |= CAN_FMR_FINIT; /* фильтры в режим настройки */
CAN1->FA1R &= ~(1u << 0); /* банк выключить на время правки */
CAN1->FS1R |= (1u << 0); /* один 32-битный фильтр */
CAN1->FM1R &= ~(1u << 0); /* режим маски */
CAN1->sFilterRegister[0].FR1 = 0; /* идентификатор — любой */
CAN1->sFilterRegister[0].FR2 = 0; /* маска нулевая: всё равно */
CAN1->FFA1R &= ~(1u << 0); /* складывать в очередь 0 */
CAN1->FA1R |= (1u << 0); /* банк включить */
CAN1->FMR &= ~CAN_FMR_FINIT;
}
⚠️ Без настроенного фильтра не принимается ничего. Это первое, на чём спотыкаются: передача работает, а приём молчит. Контроллер по умолчанию отвергает все сообщения, и «пропускать всё» надо задать явно.
19.6 Передача
Три почтовых ящика на передачу: можно поставить в очередь три сообщения, дальше ждать. Приём складывается в две очереди по три сообщения.
uint8_t can1_send(uint16_t id, const uint8_t *data, uint8_t len)
{
uint8_t box;
if (len > 8u) {
return 1u; /* в кадр помещается максимум 8 байт */
}
if (CAN1->TSR & CAN_TSR_TME0) box = 0u;
else if (CAN1->TSR & CAN_TSR_TME1) box = 1u;
else if (CAN1->TSR & CAN_TSR_TME2) box = 2u;
else return 2u; /* все заняты */
CAN1->sTxMailBox[box].TIR = ((uint32_t)id << 21); /* 11-битный номер */
CAN1->sTxMailBox[box].TDTR = len;
/* ... данные в TDLR и TDHR ... */
CAN1->sTxMailBox[box].TIR |= CAN_TI0R_TXRQ; /* запрос передачи */
return 0u;
}
Восемь байт на кадр — жёсткое ограничение классического CAN. Больше данных разбивают на несколько сообщений, а для передачи длинных блоков существуют протоколы поверх шины.
19.7 Ошибки и уход с шины
Контроллер ведёт счётчики ошибок передачи и приёма. Логика такая:
| Состояние | Что означает |
|---|---|
| активный | всё в порядке, узел сообщает об ошибках нормально |
| пассивный | ошибок накопилось много, узел ведёт себя осторожнее |
| bus-off | ошибок слишком много, узел отключён от шины |
Уход в bus-off — защита шины от неисправного узла: сломанный передатчик не должен парализовать всех остальных. Восстановление либо ручное, либо автоматическое — если включён соответствующий бит:
CAN1->MCR |= CAN_MCR_ABOM; /* восстанавливаться автоматически */
Самая частая ловушка у новичка — одинокий узел на шине. Передатчик
ждёт подтверждения приёма хотя бы от одного слушателя; если на линии больше
никого нет, подтверждения не будет. Счётчик ошибок передачи дорастает
до 128, и узел становится пассивным. Дальше по правилам стандарта ошибка
подтверждения у пассивного передатчика счётчик не растит: в bus-off узел
не уходит, а повторяет кадр без конца. Нужна однократная попытка — бит
NART в CAN_MCR (без автоповтора). В bus-off уводят настоящие ошибки:
разная скорость узлов, перепутанные CANH и CANL, нет терминаторов.
Отсюда полезный режим самопроверки (loopback): контроллер слушает собственные передачи и сам себе подтверждает приём. Позволяет отлаживать код и проверять тайминг, имея одну плату и вообще без трансивера.
19.8 ⚠️ Особенность F103: CAN и USB не уживаются
У STM32F103 контроллеры CAN и USB делят общую память для буферов сообщений — 512 байт. Одновременно работать они не могут: используется либо один, либо другой.
На BluePill это ощутимо: разъём USB там разведён, и если проект задуман с USB‑интерфейсом, CAN придётся исключить, и наоборот. У линии подключения F105/F107 эта проблема решена — там контроллеры независимы, как и у F4.
19.9 Грабли
Нет трансивера. Прямое подключение к шине не работает и может повредить выводы.
Неверные терминаторы. Ровно два по 120 Ом, ровно на концах линии.
Поля тайминга не уменьшены на единицу. Скорость получается другой.
Не настроен фильтр. Приём молчит при работающей передаче.
Одинокий узел повторяет кадр без конца. Нет второго участника, некому подтвердить приём: узел пассивный, но не в bus-off. Для отладки — режим самопроверки.
Скорости узлов не совпадают. CAN не прощает расхождения так, как UART.
CAN и USB одновременно на F103. Не заработает, память общая.
Земля не соединена. Дифференциальная пара помогает от помех, но общий потенциал всё равно нужен.
19.10 Итоги
- CAN связывает устройства, а не микросхемы: дифференциальная пара, устойчивость к помехам, аппаратный контроль ошибок.
- Трансивер обязателен, терминаторы 120 Ом — ровно два, на концах линии.
- Адресуется сообщение, а не получатель; меньший идентификатор имеет более высокий приоритет.
- Битовый тайминг задаётся квантами, точка выборки — около 87,5 %; все поля кодируются со смещением на единицу.
- Без явно настроенного фильтра приём не работает.
- В кадр помещается максимум 8 байт.
- Одинокий узел на шине не уходит в bus-off, а становится пассивным и повторяет кадр без конца — для отладки есть режим самопроверки, работающий без трансивера.
- У F103 CAN и USB используют общую память и одновременно недоступны.
Дальше: раздел 19а «CAN FD на FDCAN: 64 байта, две скорости, память сообщений».