Настройка CAN шины на китайском микроконтроллере

В каждом автомобильном микроконтроллере есть CAN шина. Образно выражаясь CAN — это труба для чисел, CAN — это нервная система автомобиля. Именно по САN передаются сигналы от датчиков и команды к исполнительным механизмам агрегатов.
CAN — это двухпроводный, дифференциальный, последовательный, полудуплексный интерфейс для передачи бинарных данных между электронными платами (PCB). В качестве кабеля чаще всего применяют одну экранированную витую пару проводов с именами: CAN_L и CAN_H.
CAN определяет два уровня модели OSI-7 (стек сетевых протоколов): физический и канальный. То есть CAN определяет также и бинарную структуру пакета в кабеле. В пакете CAN фигурируют такие переменные, как ID пакета, 8 байт данных, длина пакета, 15 битная контрольная сумма, биты подтверждения ACK, начало и конец пакета.
В данном тексте представлен перевод даташита с английского на русский того фрагмента, который посвящен CAN модулю. Также даны некоторые поясняющие комментарии.
Цель данного текста — включить CAN трансивер на микроконтроллере FC7300F8MD. Научиться отправлять и принимать CAN‑classic пакеты.
Освоить два режима работы CAN MAC: Enhanced FIFO и Message Buffers.
Для пуска CAN на очередном незнакомом микроконтроллере вам потребуются вот эти утилиты.
Название | Справка |
DS View | Клиентская программа для логического анализатора DS Logic |
PCAN‑View | Клиентская программа для трансивера Peak‑CAN |
По теоретическим основам того, что такое CAN есть масса материалов. Тут же сделаю акцент на практических тонкостях.
Практическая часть
Аппаратная часть
Физика CAN трансивера представлена микросхемой TJA1051T/3. Это дифференциальная пара проводов. На конце каждого узла заложен резистор 120 Ом. Он нужен чтобы не было пере‑отражений в длинных линиях проводов.

В физической памяти CAN трансиверы мапятся вот на эти адреса:
экземпляр CAN | base address | NVIC num |
FLEXCAN0 | 4008_0000 h | 84 |
FLEXCAN1 | 4008_4000 h | 85 |
FLEXCAN2 | 4008_8000 h | 86 |
FLEXCAN3 | 4008_C000h | 87 |
FLEXCAN4 | 4009_0000 h | 88 |
FLEXCAN5 | 4048_0000 h | 89 |
FLEXCAN6 | 4048_4000 h | 90 |
FLEXCAN7 | 4048_8000 h | 91 |
FLEXCAN8 | 4048_C000h | 142 |
FLEXCAN9 | 4049_0000 h | 143 |
Enhanced FIFO
Чтобы активировать режим Enhanced FIFO надо в регистре ERFCR установить бит ERFEN=1.
В режиме Enhanced FIFO CAN трансивер может принимать до 12 разных CAN‑FD пакетов. То есть памяти там 792+ байт. Принимать можно как стандартные ID(11 bit) так и расширенные ID (29 bit). Сами пакеты окажутся в области памяти, которая имеет cмещение 0×2000 — 0×23BF (960 байт).
При приеме пакета в регистре ERFSR выстреливает бит ERFDA=1. При приеме WaterMark пакетов в регистре ERFSR выстреливает бит ERFWMI=1.
Аппаратная фильтрация ID
Чтобы снизить нагрузку на микроконтроллер придумали CAN фильтры. Это позволяет реже вызывать прерывания. Можно наложить аппаратные ограничения на принимаемые пакеты по значениям их ID. Называется это фильтрами.
Таким образом, ещё большее количество алгоритмической работы перекладывается с софта на железо. В FC7300 можно активировать до 32 фильтров. Фильтры прописываются по смещению 0×3000...0×3080 (128 байт). Количество настроенных фильтров надо прописать в битовых полях NFE и NEXIF регистра ERFCR. Фильтры для расширенных ID прописываются в памяти ERFFEL в первую очередь. Количество расширенных фильтров явно показано в битовом поле NEXIF регистра ERFCR. Количество стандартных фильтров вычисляется по сложной формуле
std_id_filter_element_cnt =(ERFCR.NFE+1)*2 — (ERFCR.NEXIF*2);
Вот так выглядит разметка 128 байт регистровой памяти 0×3000...0×3080 для CAN фильтров:

Вот пример реальной конфигурации после инициализации SDK функциями:
I, ExtFiltElem:2
I, CAN1,ERFFEL,Offset:0x3000
+------+------------
|FltEl | dword
+------+------------
| 0 | 0x072a23a4
| 1 | 0x1fffffff
| 2 | 0x012aaaaa
| 3 | 0x1fffffff
| 4 | 0x03ff07ff
| 5 | 0x001c07ff
| 6 | 0x000a07ff
| 7 | 0x000b07ff
I, ExtFiltElem:2
+-----+------------+-----+--------+----------------------------------------------------------------
|FltEl| Dword |FSCH | FSCH | Decipher
+-----+------------+-----+--------+----------------------------------------------------------------
| 4 | 0x03ff07ff | 0 | MskFlt | STD_ID_FILTER:0x3ff,STD_ID_MASK:0x7ff,RTR_MASK:0,RTR_FILTER:0,
| 5 | 0x001c07ff | 0 | MskFlt | STD_ID_FILTER:0x1c,STD_ID_MASK:0x7ff,RTR_MASK:0,RTR_FILTER:0,
| 6 | 0x000a07ff | 0 | MskFlt | STD_ID_FILTER:0xa,STD_ID_MASK:0x7ff,RTR_MASK:0,RTR_FILTER:0,
| 7 | 0x000b07ff | 0 | MskFlt | STD_ID_FILTER:0xb,STD_ID_MASK:0x7ff,RTR_MASK:0,RTR_FILTER:0,
ExtFiltElem:2
+------+--------------------+-----+--------+-----------------------------------------------------------------------
|FltEl | qword |FSCH | FSCH | Decipher
+------+--------------------+-----+--------+-----------------------------------------------------------------------
| 0 | 0xA4232A07FFFFFF1F | 0 | MskFlt | EXT_ID_FILTER:0x072A23A4,EXT_ID_MASK:0x1FFFFFFF,RTR_MASK:0,RTR_FILTER:0,
| 1 | 0xAAAA2A01FFFFFF1F | 0 | MskFlt | EXT_ID_FILTER:0x012AAAAA,EXT_ID_MASK:0x1FFFFFFF,RTR_MASK:0,RTR_FILTER:0,
Фильтр можно задать шестью способами. Каждый фильтр конфигурируется либо 4 мя байтами, либо 8-ю байтами. Есть фильтр, который просто пропускает два ID, есть фильтр, который пропускает все ID в интервале чисел. Есть фильтр, который пропускает ID по бинарной маске.

SDK от вендора безальтернативно устанавливает именно нулевой фильтр. То есть filter + mask.
(ID[n] = STD ID filter [n]) or (STD ID Mask[n] =0) for each bit n from 0 to 10
По сути вы указываете значение ID который надо принимать и бинарной маской указываете какие биты в ID могут меняться (неважные биты). Если вся маска 3FF, то фактически отдельный CAN фильтр задает только один ID и можно принять только 32 ID пакета.
Если вы хотите принимать ну просто всё‑всё‑всё, то надо лишь обнулить маску. Это по сути пустой регистр ERFEEL.
При работе с CAN фильтрами по сути возникает две задачи: разрешить конкретный CAN ID и запретить конкретный CAN ID. Соответственно первое ограничение делается по нулевому фильтру( фильтр и маска). Фильтр это сам ID, а маска — это сплошные FF‑ки. Условие на запрет ID делается по интервальному фильтру. Допустим вы хотите запретить прием ID=55. Это можно сделать если сделать ID_FILTER1=56 ID_FILTER2=54. Получится ID_FILTER1<= ID <= ID_FILTER2. В случае с 55 условие вырождается в 56 <= ID и ID <= 54. После сортировки ID <= 54 и 56 <= ID.
Программная часть
Алгоритм включения CAN
Что же надо сделать чтобы в микроконтроллере заработал CAN трансивер? Как завести CAN‑трансивер?
Настроить GPIO
Настроить GPIO на CAN. Надо переключиться на альтернативную функцию. Это делается регистрами PINMUX. Подать тактирование на соответствующий GPIO порт.
GPIO | Dir | MCU pin | Function | Pin Mux |
PE22 | out | 158 | CAN0_RX | 4 |
PE21 | In | 157 | CAN0_TX | 4 |

Убедиться что конфиг GPIO применился

Подать тактирование
В микроконтроллере FC7300 можно тактировать CAN MAC от одного из двух источников.
Mux | CLKSRC | Название шины | Частота |
0 | The CAN engine clock source is the oscillator clock. | Functional bus clock | 24 000 000 |
1 | The CAN engine clock source is the peripheral clock | BUS_CLK |
на схеме это выглядит так

Я стартовал от шины Functional bus clock 24MHz.

Второе тактирование высокочастотное. Оно потребуется для режима CAN‑FD. В CAN‑FD просто высокая битовая скорость и чтобы добиться необходимой разрядности приходится повышать частоту тактирования CAN‑MAC. Тактирование включается функцией PCC_SetPcc с нужными аргументами.
Включить прерывания
Активировать маскированные прерывания глобально. То есть в принципе разрешить прерывания на ARM Cortex M7 микроконтроллере. Это делается CMSIS функцией __enable_irq().
Активировать CAN прерывания.
Так как работа происходит на ARM Cortex‑M7 процессоре, то надо активировать номера NVIC, которые соответствуют нужному экземпляру CAN‑трансивера. Это можно сделать функцией NVIC_EnableIRQ. Надо установить приоритет CAN прерываний
CANx | NVIC # | Обработчик прерываний |
CAN0 | 84 | CAN0_IRQHandler |
CAN1 | 85 | CAN1_IRQHandler |
CAN2 | 86 | CAN2_IRQHandler |
CAN3 | 87 | CAN3_IRQHandler |
CAN4 | 88 | CAN4_IRQHandler |
CAN5 | 89 | CAN5_IRQHandler |
CAN6 | 90 | CAN6_IRQHandler |
CAN7 | 91 | CAN7_IRQHandler |
CAN8 | 142 | CAN8_IRQHandler |
CAN9 | 143 | CAN9_IRQHandler |
Обработчики прерываний
Надо определить обработчики прерываний для CAN. Первоначально они определены в startup коде. Есть заводской обработчик прерываний из SDK. Внутри обработчика CAN прерываний происходит следующие шаги:
1–Читается ECR регистр. Анализируется ошибки приема и отправки
2–Проверяются флаги mailbox, которые условно сконфигурированы для отправки. В случае взведенных флагов вызываются callBack функции
3–Проверяются флаги mailbox, которые условно сконфигурированы для отправки. В случае взведенных флагов вызываются формирование принятого пакета из RAM памяти MailBox и вызывается callBack функции.
4–Производится сброс флага того mailbox который выскочил.
5–Прерывание должно каждый раз вызывать ту или иную callBack функцию.
Настроить битовую скорость шины.
Это самый ответственный этап. Без нужной битовой скорости CAN трансивер просто заклинит в бесконечно вызываемом прерывании. CAN трансиверы каждый бит делят на четыре части (сегмента). Сегмент синхронизации, всегда имеет длину в один квант, используется для синхронизации тактов. Ожидается, что здесь будет иметь место фронт бита, когда данные изменяются на шине. Сегмент распространения необходим для компенсации задержки в линиях шины. Фазовые сегменты могут быть укорочены (фазовый сегмент 1) или удлинены (фазовый сегмент 2), если необходимо поддерживать синхронизацию тактов.

Битовая скорость задается регистром FLEXCAN_CTRL1
Битовое поле | размер | Segment | Макс | интервал битов |
PRESDIV | 8 | пред‑делитель для Tq | 255 | 24–31 |
RJW | 2 | Synchronization | 3 | 22–23 |
PROPSEG | 3 | Propagation | 7 | 0–2 |
PSEG1 | 3 | Phase 1 | 7 | 19–21 |
PSEG2 | 3 | Phase 2 | 7 | 16–18 |
Чтобы уменьшить погрешность установки периода бита надо уменьшать продолжительность временного кванта (то есть. Tq). Образно, увеличивать гранулярность. Для этого надо увеличивать значение пред делителя PRESDIV.

Второй момент. Как выбрать натуральные числа для sync, prop, seg1,seg2? С математической точки зрения, сумму N четырьмя натуральными числами можно составить C(N — 1, 3) = (N — 1)(N — 2)(N — 3) / 6 способами, где C(n, k) = n! / k!(n‑k)!
Сумма | Количество способов составить сумму 4 мя слагаемыми. |
4 | 1 |
5 | 4 |
6 | 10 |
7 | 20 |
8 | 35 |
9 | 56 |
10 | 84 |
11 | 120 |
12 | 165 |
13 | 220 |
Уровни шины выбираются на границе между фазовым сегментом 1 и фазовым сегментом 2. Поэтому при настройке битовой скорости любого CAN драйвера вам надо будет из одного числа (желаемая битовая скорость), так или иначе вычислить 4 числа, которые непосредственно влияют на результирующую битовую скорость. Выбор этих четырех чисел — самое неясное при работе CAN. Драйверы от вендора судя по коду делают какие то сложнейшие математический вычисления чтобы сформировать массив.
uint32_t can_segment_to_main_pre_scaler(const CanSegmentInfo_t* const Segment) {
uint32_t bit_prescaler = 0;
if(Segment) {
uint32_t bit_dur_tq = 0;
bit_dur_tq += Segment->synchronization;
bit_dur_tq += Segment->propagation;
bit_dur_tq += Segment->phase_1;
bit_dur_tq += Segment->phase_2;
bit_prescaler = (Segment->prescaler) * bit_dur_tq;
}
return bit_prescaler;
}
uint32_t can_time_seg_to_bit_rate(const uint32_t clk_freq_hz,
const CanSegmentInfo_t* const Segment) {
uint32_t bit_rate_real = 0;
if(Segment) {
uint32_t prescaler = can_segment_to_main_pre_scaler(Segment);
LOG_DEBUG(CAN, "MainPcs:%u", prescaler);
if(prescaler) {
bit_rate_real = clk_freq_hz / prescaler;
}
}
return bit_rate_real;
}
bool can_segment_info_calc_custom(uint32_t bus_freq_hz,
uint32_t baud_rate_hz,
CanSegmentInfo_t* const FoundSegment) {
bool res = false;
LOG_INFO(CAN, "Bus:%u Hz,BitRate:%u Hz", bus_freq_hz, baud_rate_hz);
uint32_t cnt = 0;
uint32_t min_err = INT_MAX;
CanSegmentInfo_t SegmentBest = {0};
if(FoundSegment) {
bool spot_segment = false;
uint32_t presdiv = 0;
for(presdiv = 1; presdiv <= 256; presdiv++) {
uint32_t resync = 0;
for(resync = 1; resync <= 4; resync++) {
uint32_t propseg = 0;
for(propseg = 1; propseg <= 8; propseg++) {
uint32_t seg1 = 0;
for(seg1 = 1; seg1 <= 8; seg1++) {
uint32_t seg2 = 0;
for(seg2 = 1; seg2 <= 8; seg2++) {
CanSegmentInfo_t Segment = {0};
Segment.prescaler = presdiv;
Segment.synchronization = resync;
Segment.propagation = propseg;
Segment.phase_1 = seg1;
Segment.phase_2 = seg2;
res = can_is_valid_segment(&Segment);
if(res) {
uint32_t cur_rate = can_time_seg_to_bit_rate(bus_freq_hz,
&Segment);
uint32_t diff = math_calc_abs(baud_rate_hz,
cur_rate);
if(diff < min_err) {
min_err = diff;
SegmentBest = Segment;
spot_segment = true;
cnt++;
LOG_INFO(CAN, "N:%u,Spot:Err:%7u Hz,%10s",
cnt, diff,
CanSegmentInfoToStr(&SegmentBest));
}
}
}
}
}
}
}
res = false;
uint32_t baud_rate_hz = 0;
if(spot_segment) {
*FoundSegment = SegmentBest;
baud_rate_hz = can_time_seg_to_bit_rate(bus_freq_hz,
&SegmentBest);
res = true;
}
float bit_duration_s = 1.0 / ((float)baud_rate_hz);
LOG_INFO(CAN, "BitTime:%s s", FloatBigToStr(bit_duration_s));
}
return res;
}Большинство CAN‑трансиверов также предоставляют возможность делать ADC выборку три раза в течение одного бита. В этом случае выборка происходит на границах двух квантов, которые предшествуют точке выборки. Финальное значение бита определяется электрическим голосованием внутри цифровых логических цепей CAN‑трансивера. Называется это мажорирование сигналов.
Определить SDK CallBack
Определить CallBack функции для обработчиков прерываний. SDK от вендора построена так что надо определить CallBack функции и присвоить их указатели в Handler структуру.
Определить message buffer для CAN
Один из режимов работы CAN это так называемые message buffer. Они же mail box. Они определяются в RAM памяти, которая вмонтированна прямо в регистры CAN MAC. Надо каждому mail box назначить направление его работы. Тут может быть три варианта: прием, отправка или оба. Надо выставить биты маски. У каждого mailBox есть свой отдельный бит в регистре FLEXCAN_IMASK1.

В физической памяти CAN трансиверы мапится вот на эти адреса:
экземпляр CAN | base address | NVIC num |
FLEXCAN0 | 4008_0000 h | 84 |
FLEXCAN1 | 4008_4000 h | 85 |
FLEXCAN2 | 4008_8000 h | 86 |
FLEXCAN3 | 4008_C000h | 87 |
FLEXCAN4 | 4009_0000 h | 88 |
FLEXCAN5 | 4048_0000 h | 89 |
FLEXCAN6 | 4048_4000 h | 90 |
FLEXCAN7 | 4048_8000 h | 91 |
FLEXCAN8 | 4048_C000h | 142 |
FLEXCAN9 | 4049_0000 h | 143 |
В случае CAN‑Classic каждый MB имеет размер 16 байт.

page 1376
Определить параметры NVRAM для CAN.
Битовую скорость CAN трансивера лучше хранить в NVRAM. Так вы сможете переконфигурировать трансивер без пересборки всей прошивки.

В качестве reference конфига привожу вот этот dump. На этой карте регистров CAN0 точно работает.
CAN0,Base:0x40080000
Base:0x40080000,Cnt:45
+-----+--------------------+-------+------------+-------------------------------------------+
| N | Name |offset | ValHex | ValBin |
+-----+--------------------+-------+------------+-------------------------------------------
| 1 | MCR | 0x000 | 0x00a3101f | 0b0000_0000_1010_0011_0001_0000_0001_1111
| 2 | TIMER | 0x008 | 0x0000dbd8 | 0b0000_0000_0000_0000_1101_1011_1101_1000
| 3 | RXMGMASK | 0x010 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 4 | RX14MASK | 0x014 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 5 | RX15MASK | 0x018 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 6 | IMASK1 | 0x028 | 0xffffffff | 0b1111_1111_1111_1111_1111_1111_1111_1111
| 7 | IFLAG1 | 0x030 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 8 | CRCR | 0x044 | 0x00040f95 | 0b0000_0000_0000_0100_0000_1111_1001_0101
| 9 | RXFGMASK | 0x048 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 10 | RXFIR | 0x04c | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 11 | CBT | 0x050 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 12 | MECR | 0xae0 | 0x800c0080 | 0b1000_0000_0000_1100_0000_0000_1000_0000
| 13 | WU_MTC | 0xb08 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 14 | FLT_ID1 | 0xb0c | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 15 | FLT_DLC | 0xb10 | 0x00000008 | 0b0000_0000_0000_0000_0000_0000_0000_1000
| 16 | PL1_LO | 0xb14 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 17 | PL1_HI | 0xb18 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 18 | FLT_ID2_IDMASK | 0xb1c | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 19 | PL2_PLMASK_LO | 0xb20 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 20 | PL2_PLMASK_HI | 0xb24 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 21 | EPRS | 0xbf0 | 0x00000003 | 0b0000_0000_0000_0000_0000_0000_0000_0011
| 22 | ENCBT | 0xbf4 | 0x0000700e | 0b0000_0000_0000_0000_0111_0000_0000_1110
| 23 | EDCBT | 0xbf8 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 24 | ETDC | 0xbfc | 0x00010000 | 0b0000_0000_0000_0001_0000_0000_0000_0000
| 25 | ECR | 0x01c | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 26 | ESR1 | 0x020 | 0x00040080 | 0b0000_0000_0000_0100_0000_0000_1000_0000
| 27 | ESR2 | 0x038 | 0x00006000 | 0b0000_0000_0000_0000_0110_0000_0000_0000
| 28 | ERRIAR | 0xae4 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 29 | ERRIDPR | 0xae8 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 30 | ERRIPPR | 0xaec | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 31 | RERRAR | 0xaf0 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 32 | RERRDR | 0xaf4 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 33 | RERRSYNR | 0xaf8 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 34 | ERRSR | 0xafc | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 35 | FDCTRL | 0xc00 | 0x80000000 | 0b1000_0000_0000_0000_0000_0000_0000_0000|
| 36 | FDCBT | 0xc04 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 37 | FDCRC | 0xc08 | 0x04000f95 | 0b0000_0100_0000_0000_0000_1111_1001_0101
| 38 | ERFCR | 0xc0c | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 39 | ERFIER | 0xc10 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 40 | ERFSR | 0xc14 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000
| 41 | CTRL1 | 0x004 | 0x0000cc40 | 0b0000_0000_0000_0000_1100_1100_0100_0000
| 42 | CTRL2 | 0x034 | 0xd0a03000 | 0b1101_0000_1010_0000_0011_0000_0000_0000
| 43 | CTRL1_PN | 0xb00 | 0x00000100 | 0b0000_0000_0000_0000_0000_0001_0000_0000
| 44 | CTRL2_PN | 0xb04 | 0x00000000 | 0b0000_0000_0000_0000_0000_0000_0000_0000Алгоритм отправки CAN пакета
1) Сбросить бит флага для mailBox в регистре iFlag1.
2) Активировать прерывания для того MB из которого вы собрались производить отправку
3) Сбросить MB
4) Убедиться что MB сброшен. CODE показывает transmitted или aborted
5) Сбросить флаг прерывания
6) Прописать в MB ID
7) Прописать в MB данные которые следует отправить
8) Сконфигурировать тип адреса
9) Прописать размер данных
10) Прописать тип пакета: CAN‑Classic или CAN‑FD
11) В случае с CAN‑FD прописать надо ли переключать битовую скорость.
12) Дать отмашку на отправку пакета из MB прописать в битовое поле CODE константу 0xC.
После этих простых действий CAN MAС возьмет в оборот пакет из этого MB и станет пробовать его отправить его в шину до тех пор пока не появится шанс это сделать.
Отправка всегда происходит через MB. С приемом пакетов же могут быть варианты.
Алгоритм приема CAN пакета.
Принимать пакеты можно двумя механизмами: через MailBox и через Enhanced FIFO. В случае с MB всё просто. Увидели флаг в регистре IFLAG1 и выгребли данные из соответствующего этому биту MB.
В случае с Enhanced FIFO можно игнорировать регистр IFLAG1, а опрашивать статусные биты ERFDA, ERFWMI и ERFF регистра ERFSR. Вот справка.
переменная | бит | назначение |
ERFWMI | 29 | Принято больше чем watermark пакетов |
ERFOVF | 30 | FIFO принятых пакетов переполнено. Это 12 пакетов. |
ERFF | 16 | FIFO принятых пакетов заполнено. Это 12 пакетов. |
ERFDA | 28 | В FIFO лежит по крайней мере 1 пакет |
В случае появления данных надо перекопировать из адреса 0×2000 данные в какую‑н структуру в RAM памяти. Составить принятый пакет.
Алгоритм отработки прерываний CAN‑трансивера
Вот сработало CAN прерывание. Например CAN3_IRQHandler. Если ничего не делать, то это прерывание будет вызываться снова и снова при этом полностью блокируя суперцикл в функции main.
‑По имени прерывания мы определим адрес конкретного трансивера в физической памяти.
‑Пробежаться по всем битам регистра IFLAG1. Тут каждому MB посвящен отдельный бит в регистре.
‑SDK устроена так, что определение причины прерывания (прием или отправка) разруливается программно при помощи глобальной переменной‑маски. Разработчики SDK решили в инициализации первые N MB условно определены на отправку — последние на прием. Поэтому в обработчике прерываний при выстреливание MB c индексом i можно понять, что вызывать:TxDoneCallBack или RxDoneCallBack.
‑Вызвать TxDoneCallBack для этого MB. Имеет смысл установить переменную‑flag tx_done=1. Так модульный тест сможет узнать и понять, что CAN пакет в самом деле отправился, а не застрял где‑то в недрах сложного SDK.
‑Вызвать RxDoneCallBack для этого MB.
‑Сбросить бит в регистре IFLAG1, чтобы отключить прерывание от этого конкретного MB. Дать понять MAC что мы уже обработали это событие.
‑В случае с Enhanced FIFO для приема надо опрашивать биты ERFDA, ERFWMI, ERFF регистра ERFSR.
‑В случае появления данных надо выгрести из адреса 0×2000 данные и скомпоновать принятый пакет.
Можно и вовсе работать с CAN без прерываний. Вместо этого просто вызвать в main супер цикле функцию void FLEXCAN_PollingProcess(FLEXCAN_HandleType *pCanHandle).
Опрос статусных регистров CAN‑трансивера
Для понимания сути происходящего в супер цикле прошивки имеет смысл опрашивать основные статусные регистры CAN‑трансивера и отслеживать возможные сбои в работе всей приемо‑передающей аппаратуры. Отслеживать надо все read‑only (RO ) поля в карте регистров CAN MAC‑а.
Register | offset | Register Name |
FLEXCAN_ECR | 1Ch | Error Counter Register |
FLEXCAN_ESR1 | 20 h | Error and Status 1 Register |
FLEXCAN_ESR2 | 38 h | Error and Status 2 Register |
FLEXCAN_CRCR | 44 h | CRC Register |
FLEXCAN_RERRAR | AF0h | Error Report Address Register |
FLEXCAN_RERRDR | AF4h | Error Report Data Register |
FLEXCAN_FDCRC | C08h | CAN FD CRC Register |
FLEXCAN_ERFSR | C14h | Enhanced Rx FIFO Status Register |
Еще имеет смысл добавить периодическую процедуру watchdog, чтобы раз в 3–5 секунд проверять, что с CAN трансивером все в порядке. Что трансивер не отвалился от шины, случайно свалившись, в freeze режим. Что Receive Error Counter не увеличились. Что не переполнился Rx FIFO, что не выстреливает событие рассинхрона между отправленными битами и прочитанными битами, что не произошло событие bus‑off. Что не произошло события нарушения CRC, нарушение бит стаффинга, ошибки кадра и прочих нежелательных событий. В случае появления там аварийных значений, сигнализировать об этом в UART или вовсе перезагрузиться.
CAN‑драйвер это не просто послать и принять пакетик. CAN‑драйвер это еще и про самодиагностику, про самовосстановление после аварий, про непрерывное поддержание системы в ресурсном состоянии.
Отладка
Невозможно отлаживать CAN через CAN, если CAN еще не настроен и не включен. Поэтому такие вещи, как CAN надо отлаживать через UART. Это и очевидно. Для этого запущен интерфейс командной строки поверх UART специально для того, чтобы отлаживать CAN. Удалось наладить прием CAN пакетов на стороне микроконтроллера.

Отправка тоже работает. Вот так легко и не принужденно из CLI можно инициировать отправку произвольного пакета в CAN. Видно как клиентская утилита PCAN‑View приняла этот пакет.

Если подключиться к MCU пину CAN_RX, то структуру самого CAN пакета можно даже увидеть логическим анализатором DS‑logic.

Обзор средств аппаратной отладки CAN
Для наладки CAN на незнакомом микроконтроллере вам потребуется какой‑то CAN‑преобразователь, подключенный к PC. Существует серия устройств‑переходников для подключения CAN устройств через USB к компьютерам. Вот перечень широко распространенных вариантов для USB‑CAN переходников.
№ | Переходник | Software |
1 | SYS TEC USB‑CANmodul1 | CANinterpreter Lite for USB‑CANmodul |
2 | USBCAN‑II C | ECAN Tools |
3 | Peak CAN | PCAN‑View |
4 | USB2CANFD_V1 | СanGaroo |
Результат
Удалось научиться включать и пользоваться CAN модулем на микроконтроллерах семейства FlagShip. Удалось отправлять и принимать CAN classic пакеты.
Аббревиатура | Пояснение |
CAN | Controller Area Network |
ECU | electronic control unit |
SDK | Software Development Kit |
MB | Message Buffers (Mail Box) |
MAC | medium access control |
CHI | Controller Host Interface |
PHY | physical layer |
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.