АО «БАЙКАЛ ЭЛЕКТРОНИКС», ИНН: 7707767484
АО «БАЙКАЛ ЭЛЕКТРОНИКС» оставляет за собой право вносить любые изменения в настоящий документ без дополнительного уведомления.
Работа с контроллером CAN FD
Скачать PDF ⬇️ AppNote_CAN-FD_v1.pdf
Микроконтроллер BE-U1000 Рекомендации по использованию Работа с контроллером CAN FD
ID документа: U1000#943 Версия: 1.0 Дата: 27.08.2026
Введение
В этом документе представлена подробная информация, примеры и разъяснения по работе с контроллером CAN FD микроконтроллера BE-U1000 (далее – МК).
Документ снабжен примерами кода на языке Си.
Для ознакомления с общей информацией о МК обратитесь к «BE-U1000. Краткое описание» и «BE-U1000. Руководство пользователя».
Для ознакомления с характеристиками МК обратитесь к «BE-U1000. Техническая спецификация» и «BE-U1000. Reference Manual».
Условные обозначения, термины и сокращения
В документе используются условные обозначения, сокращения и термины, указанные в таблице ниже.
Таблица 1 – Сокращения и термины
| Обозначение | Расшифровка |
|---|---|
| АФ | Альтернативная функция. Функция, назначаемая с помощью регистров CRU. |
| МК | Микроконтроллер BE-U1000. |
| ПК | Управляющий персональный компьютер. |
| CAN | Controller Area Network (местная контроллерная сеть) – промышленный стандарт последовательной передачи данных, используемый для объединения устройств в единую сеть. |
| CAN FD | Controller Area Network with Flexible Data-Rate (сеть контроллеров с изменяемой скоростью передачи данных) – расширение классического протокола CAN, обеспечивающее более высокую скорость передачи данных. |
| CLIC | Core-Local Interrupt Controller – специализированный контроллер прерываний для архитектуры RISC-V. |
Основные технические характеристики контроллера
МК содержит два контроллера CAN FD: CAN FD 0 и CAN FD 1.
Технические характеристики контроллеров CAN FD:
- возможность передачи кадров CAN FD с полезной нагрузкой до 64 байт;
- скорость передачи данных в фазе данных — до 8 Мбит/с;
- скорость передачи данных в фазе арбитража — до 1 Мбит/с;
- размер буфера приема RX FIFO — 64 байта;
- число пар идентификаторов фильтр-маска — 32;
- возможность отмены сообщений передачи (TX);
- возможность раздельного журналирования ошибок для высокоскоростных режимов передачи данных;
- временные метки для полученных и переданных сообщений.
Помимо предусмотренных стандартом, контроллер CAN FD может работать в следующих режимах:
- настройка;
- внутренняя петля (loopback);
- ожидание (standby);
- мониторинг шины (snoop).
Полное описание режимов и состояний CAN FD см. в документе «BE-U1000. Reference Manual».
Подключение к шине CAN
Выводы контроллера CAN не могут быть подключены к шине непосредственно.
Для связи контроллера с шиной на физическом уровне необходим аппаратный приёмопередатчик.
Для организации связи между CAN-контроллером микроконтроллера и приёмопередатчиком должен использоваться цифровой последовательный интерфейс (TX/RX) с CMOS-уровнями (3,3 В или 5 В).
Пример схемы подключения МК к приемопередатчику показан на рисунке 1.
Рисунок 1 – Пример схемы подключения приемопередатчика
В показанном на рисунке 1 примере применена ИС D2 TJA1042T/3 — автомобильный приёмопередатчик CAN FD, соответствующий требованиям ISO 11898-2:2016 и стандартам автомобильной ЭМС (ISO 7637 / IEC 62228-3). Эти приёмопередатчики обладают улучшенными характеристиками интерфейса CAN и требуют минимального количества внешних компонентов.
Линии CANH и CANL приёмопередатчика, расположенного на конце шины CAN D2, следует соединить через схему раздельного согласования — два резистора по 60 Ом (RL, RH на рисунке Рисунок 1). Поскольку симметрия линий оказывает наибольшее влияние на величину электромагнитного излучения шины в окружающее пространство, разница значений сопротивлений согласующих резисторов должна быть как можно меньшей, предпочтительно не более 1%.
В промежуточных узлах, расположенных на ответвлениях от шины, для согласования могут использоваться резисторы номиналом 1,3 кОм при наличии соответствующего требования автопроизводителя (OEM). Такое сопротивление не оказывает существенного влияния на сопротивление шины и одновременно решает вопросы с высокочастотными микроотражениями и обрывами.
Резисторы согласования RL и RH в средней точке должны соединяться с общей линией питания через шунтирующий по ВЧ конденсатор (CG на рисунке 1). Такая схема согласования одновременно работает как нагрузка линии и отводит синфазную высокочастотную помеху через конденсатор на общую линию питания.
Вход D2 STB предназначен для управления режимом работы приёмопередатчика: высокий уровень на входе STB переводит его в режим ожидания, в котором приёмопередатчик потребляет минимум энергии. Для минимизации потребления энергии D2 в режиме ожидания необходимо удерживать напряжение высокого логического уровня одновременно на входах TXD и STB.
Вход D2 VIO предназначен для питания цифрового интерфейса приёмопередатчика. Этот вход целесообразно подключить к шине цифрового питания МК 3,3 В (3V3 на рисунке 1), что позволит избежать применения преобразователя логических уровней последовательных интерфейсов МК и приёмопередатчика, требующего питания от 5 В. Вход D2 VIO также служит источником питания внутреннего малопотребляющего дифференциального приёмника. В приложениях, требующих работы в режиме пониженного энергопотребления (например, «Type B» — микроконтроллер всегда активен), этот приёмник позволяет отслеживать активность на линиях шины даже когда питание 5 В (5V_CAN на рисунке 1) не подано на вход VCC приёмопередатчика D2.
Для защиты линий питания от помех, создаваемых приёмопередатчиком, в непосредственной близости от корпуса ИС D2 между выводами VIO, VCC и GND можно поместить блокировочные конденсаторы ёмкостью от 0,047 до 0,1 мкФ, которые будут шунтировать линии питания по ВЧ на общую линию питания, однако существует альтернативная схема, показанная на рисунке 1, где выводы питания ИС D2 VIO и VCC соединены между собой такой же шунтирующей ёмкостью CV. Такое включение CV выравнивает потенциалы линий питания на импульсах, устраняя влияние таких помех в линиях питания на работу ИС. Для повышения надёжности рекомендуется использовать два последовательно включенных конденсатора: в случае возникновения внутреннего замыкания в одном из конденсаторов замыкания линий питания по постоянному току не произойдет.
Для защиты от помех из бортовой сети и от статических разрядов рекомендуется соединить каждую линию конденсатором ёмкостью 100 пФ с общей линией питания (конденсаторы СL и СH на рисунке Рисунок 1). Эти конденсаторы рекомендуется устанавливать как можно ближе к разъёмам, куда подключаются линии шины. Разность ёмкостей этих двух конденсаторов также должна быть минимальной.
В ИС D2 уже встроена защита от электростатического разряда на выводах CANL и CANH:
- ±8 кВ в соответствии с ГОСТ 30804.4.2-2013 (IEC 61000-4-2);
- ±8 кВ в соответствии с моделью человеческого тела (Human Body Model — HBM);
- ±300 В в соответствии с моделью оборудования (Machine Model — MM);
- ±500 В в соответствии с моделью заряженного устройства (Charged Device Model — CDM);
и, как правило, в дополнительной защите ИС не нуждается, однако, если требуется более высокая стойкость к воздействиям, на этих выводах можно применить внешние супрессоры. В примере на рисунке Рисунок 1 показано подключение диодной сборки супрессоров VD1 NUP2105L.
Рекомендации по компоновке и трассировке печатных плат:
- печатные проводники линий CANH и CANL на печатной плате следует прокладывать вплотную друг к другу и строго симметрично. Их длина не должна превышать 10 см;
- печатные проводники шины CAN должны перекрываться полигоном, выполненном на прилегающем слое печатной платы, электрически соединенным с общей линией подсистемы питания. Это относится также к печатным проводникам последовательного порта между микроконтроллером и приемопередатчиком CAN;
- по возможности экранируйте линии CAN на печатной плате. Например, на четырехслойной плате печатные проводники сигналов CAN следует выполнять на внутренних слоях, экранируя их полигонами на прилегающих слоях, соединенными с линиями питания;
- избегайте параллельной прокладки сигнальных линий, выходящих за пределы платы, рядом с линиями CANH/CANL. Это необходимо для исключения помех в цепях CAN;
- избегайте прокладки печатных проводников высокоскоростных линий передачи параллельно линиям CAN без экранирования. При необходимости пересечения таких печатных проводников сделайте их перпендикулярными;
- длина дорожек между МК и приёмопередатчиком должна быть минимально возможной;
- импеданс заземления между МК и трансивером должен быть как можно ниже.
Настройка внешних выводов МК
Для настройки выводов МК на выполнение функций выводов контроллера CAN FD им необходимо назначить соответствующие альтернативные функции. Перечень доступных для настройки выводов приведен в таблице 2. Подробную информацию об альтернативных функциях портов МК см. в документе «BE-U1000. Reference Manual», раздел «Alternate Functions».
Таблица 2 — Альтернативные функции выводов МК
| Вывод | Назначение | Альтернативная функция | Регистр и битовое поле |
|---|---|---|---|
| PA[6] | CAN FD 0 TX | 2 | IOAFCR0[26:24] |
| PA[7] | CAN FD 0 RX | 2 | IOAFCR0[30:28] |
| PA[14] | CAN FD 0 TX | 3 | IOAFCR1[26:24] |
| PA[15] | CAN FD 0 RX | 3 | IOAFCR1[30:28] |
| PB[6] | CAN FD 1 TX | 2 | IOAFCR2[26:24] |
| PB[7] | CAN FD 1 RX | 2 | IOAFCR2[30:28] |
| PB[14] | CAN FD 1 TX | 3 | IOAFCR3[26:24] |
| PB[15] | CAN FD 1 RX | 3 | IOAFCR3[30:28] |
Пример настройки выводов PA[6] и PA[7] для работы в качестве CAN FD 0 TX и CAN FD 0 RX:
#define CRU_BASE 0x14000000UL //1
#define IOAFCR0_BASE 0x3C //2
{
uint32_t ioafcr0 = *(volatile uint32_t *)(CRU_BASE + IOAFCR0_BASE); //3
ioafcr0 &= ~(0x7UL << 24);
ioafcr0 |= (0x1UL << 24);
*(volatile uint32_t *)(CRU_BASE + IOAFCR0_BASE) = ioafcr0;
ioafcr0 = *(volatile uint32_t *)(CRU_BASE + IOAFCR0_BASE); //4
ioafcr0 &= ~(0x7UL << 28);
ioafcr0 |= (0x1UL << 28);
*(volatile uint32_t *)(CRU_BASE + IOAFCR0_BASE) = ioafcr0;
}
① установка базового адреса блока CRU;
② установка адреса регистра IOAFCR0 относительно адреса блока CRU;
③ установка АФ 2 для вывода PA[6];
④ установка АФ 2 для вывода PA[7].
Сброс CAN FD
Сброс контроллера CAN FD осуществляется посредством установки в 1 поля SRST регистра SRR. После сброса контроллер переходит в режим настройки (SRR.CEN=0) не менее, чем через 16 тактовых циклов сигнала PCLK.
Сброс CAN FD 0:
#define CANFD0_BASE 0x11010000UL //1
#define CAN_SRR_BASE 0x00 //2
*(volatile uint32_t *)(CANFD0_BASE + CAN_SRR_BASE) |= (1UL); //3
__delay_cycles(100UL); //4
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра SRR относительно адреса CAN FD 0;
③ установка в 1 поля SRST регистра SRR;
④ ожидание перехода в режим настройки.
Сброс CAN FD 1:
#define CANFD1_BASE 0x13010000UL //1
#define CAN_SRR_BASE 0x00 //2
*(volatile uint32_t *)(CANFD1_BASE + CAN_SRR_BASE) |= (1UL); //3
__delay_cycles(100UL); //4
① установка базового адреса контроллера CAN FD 1;
② установка адреса регистра SRR относительно адреса CAN FD 1;
③ установка в 1 поля SRST регистра SRR;
④ ожидание перехода в режим настройки.
Настройка тактирования
CAN FD тактируется следующими сигналами синхронизации:
- CANx2CLK (до 200 МГц) для тактирования интерфейса CAN;
- CANCLK (до 100 МГц) для тактирования триггеров CAN. Частота CANCLK формируется путем деления частоты CANx2CLK на 2.
Домены тактирования регистров CAN FD – PCLK0 для CAN FD 0 и PCLK1 для CAN FD 1.
Для тактирования CAN FD рекомендуется использовать внешний генератор тактовых сигналов.
Перед началом работы с CAN FD необходимо настроить и включить тактирование соответствующего контроллера. Тактирование настраивается при помощи регистров блока CRU.
Подробнее о настройке тактирования см. в документе «Микроконтроллер BE-U1000 Рекомендации по использованию. Настройка тактовых сигналов».
Пример снятия сброса CAN FD 0:
#define CRU_BASE 0x14000000UL //1
#define PCLK0EN_BASE 0x0C //2
*(volatile uint32_t *)(CRU_BASE + PCLK0EN_BASE) |= (1UL << 29); //3
① установка базового адреса блока CRU;
② установка адреса регистра PCLK0EN относительно адреса блока CRU;
③ снятие сброса (PCLK0EN.CAN0RSTN=1).
Ниже показан пример включения тактирования CAN от домена CAN_CLK:
- делитель CANCLKX2_DIV настроен на коэффициент 2,5, его выходная частота равна 80 МГц (при частоте PLL 200 МГц);
- делитель CANCLKX2_DIV выбран в качестве источника тактирования доменов CAN_CLK_X2 (80 МГц, частота тактирования триггеров CAN) и CAN_CLK (40 МГц, частота тактирования контроллеров CAN).
#define CRU_BASE 0x14000000UL //1
#define CLKSEL_BASE 0x0 //2
#define CLKCR1_BASE 0x84 //3
*(volatile uint32_t *)(CRU_BASE + CLKCR1_BASE) =
(*(volatile uint32_t *)(CRU_BASE + CLKCR1_BASE) & ~ (0x1FUL << 6)) | (2UL << 6); //4
*(volatile uint32_t *)(CRU_BASE + CLKCR1_BASE) |= (1UL << 11); //5
*(volatile uint32_t *)(CRU_BASE + CLKSEL_BASE) =
(*(volatile uint32_t *)(CRU_BASE + CLKSEL_BASE) & ~ (0x3UL << 13)) | (1UL << 13); //6
}
① установка базового адреса блока CRU;
② установка адреса регистра CLKSEL относительно адреса блока CRU;
③ установка адреса регистра CLKCR1 относительно адреса блока CRU;
④ настройка делителя CANCLKX2_DIV на коэффициент 2,5: установка поля CANCLKDIV регистра CLKCR1 – бит [0] = 1, биты [4:1] = 1;
⑤ включение CANCLKX2_DIV (CLKCR1.CANCLKDIVEN=1);
⑥ выбор сигнала CANCLKX2_DIV в качестве источника тактирования доменов CAN_CLK_X2 и CAN_CLK (CLKSEL.CANX2CLKSEL=1).
Настройка контроллера CAN
Для работы с контроллером CAN:
- переведите контроллер CAN FD в режим настройки;
- выберите режим работы: нормальный, мониторинга, ожидания или внутренней петли. Нормальный режим подразумевает приём и передачу сообщений, режим внутренней петли позволяет отладить работу контроллера;
- настройте параметры передачи данных;
- выйдите из режима настройки.
Вход в режим настройки
В режиме настройки работа контролера CAN FD приостанавливается и становятся доступны регистры, при помощи которых настраиваются параметры CAN FD. Чтоб войти в режим настройки, необходимо выполнить одно из следующих действий:
- записать 0 в бит CEN регистра
SRR; - записать 1 в бит SRST в регистре
SRR. Выбор режима работы CAN и настройка параметров передачи сообщений возможны только при CEN = 0.
Запись 1 в бит SRST приводит к сбросу CAN FD. После установки бита CAN FD переходит в режим настройки не менее чем через 16 тактовых циклов сигнала PCLK.
Вход в режим настройки CAN FD 0 через установку в 0 поля CEN регистра SRR:
#define CANFD0_BASE 0x11010000UL //1
#define CAN_SRR_BASE 0x00 //2
*(volatile uint32_t *)(CANFD0_BASE + CAN_SRR_BASE) &= ~ (1UL << 1); //3
__delay_cycles(100UL); //4
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра SRR относительно адреса CAN FD 0;
③ установка в 0 поля CEN регистра SRR;
④ ожидание перехода в режим настройки.
Вход в режим настройки CAN FD 0 через установку в 1 поля SRST регистра SRR:
#define CANFD0_BASE 0x11010000UL //1
#define CAN_SRR_BASE 0x00 //2
*(volatile uint32_t *)(CANFD0_BASE + CAN_SRR_BASE) |= (1UL << 0); //3
__delay_cycles(100UL); //4
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра SRR относительно адреса CAN FD 0;
③ установка в 1 поля SRST регистра SRR;
④ ожидание перехода в режим настройки.
Выход из режима настройки CAN FD осуществляется посредством установки в 1 поля CEN регистра SRR:
#define CANFD0_BASE 0x11010000UL //1
#define CAN_SRR_BASE 0x00 //2
*(volatile uint32_t *)(CANFD0_BASE + CAN_SRR_BASE) |= (1UL << 1); //3
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра SRR относительно адреса CAN FD 0;
③ установка в 1 поля CEN регистра SRR.
Настройка режимов работы CAN
Выбор режима работы CAN и настройка параметров передачи сообщений доступны только когда поле CEN регистра SRR установлено в 0.
При отключении режимов ожидания, мониторинга и внутренней петли контроллер переходит в нормальный режим работы.
Установка режима ожидания для CAN FD 0 записью 1 в бит STANDBY регистра MSR:
#define CANFD0_BASE 0x11010000UL //1
#define MSR_BASE 0x4 //2
*(volatile uint32_t *)(CANFD0_BASE + MSR_BASE) |= (1UL << 0); //3
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра MSR относительно адреса CAN FD 0;
③ запись 1 в бит STANDBY регистра MSR.
Установка режима мониторинга для CAN FD 0 записью 1 в бит SNOOP регистра MSR:
#define CANFD0_BASE 0x11010000UL //1
#define MSR_BASE 0x4 //2
*(volatile uint32_t *)(CANFD0_BASE + MSR_BASE) |= (1UL << 2); //3
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра MSR относительно адреса CAN FD 0;
③ запись 1 в бит SNOOP регистра MSR.
Установка режима внутренней петли для CAN FD 0 записью 1 в бит LBACK регистра MSR:
#define CANFD0_BASE 0x11010000UL //1
#define MSR_BASE 0x4 //2
*(volatile uint32_t *)(CANFD0_BASE + MSR_BASE) |= (1UL << 1); //3
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра MSR относительно адреса CAN FD 0;
③ Запись 1 в бит LBACK регистра MSR.
Настройка передачи сообщений
Настройка параметров скорости
Для передачи информации по шине CAN необходимо настроить параметры контроллера CAN FD, приведенные ниже.
- параметры номинальной фазы (фазы арбитража):
a) делитель тактовой частоты периферии для формирования квантов времени Tq (nominal prescaler); б) nominal TS1 – время до точки семплирования для номинальной фазы;
в) nominal TS2 – время после точки семплирования для номинальной фазы;
г) nominal SJW (synchronization jump width) – максимальная ширина скачка синхронизации для компенсации фазового сдвига; - параметры фазы данных (если используется):
а) делитель частоты для фазы данных (data prescaler);
б) data TS1 – время до точки семплирования для фазы данных;
в) data TS1 – время после точки семплирования для фазы данных;
г) data SJW – ширина скачка синхронизации для фазы данных (обычно больше в процентном соотношении из-за высоких скоростей); - параметры кадра: а) формат кадра – стандартный CAN или CAN FD; б) BRS (bit rate switching) – разрешение использования повышенной скорости для фазы данных;
- компенсация задержки сигнала (TDC offset).
Скорость номинальной фазы обычно настраивается в значение до 1 Мбит/с, а фаза данных в значение 2–5 Мбит/с. Ниже приведены значения регистров, при которых для номинальной фазы будет настроена скорость 500 кбит/с, а для фазы данных будет настроена скорость 2 Мбит/с при тактовой частоте контроллера CAN 40 МГц.
Таблица 3 — Параметры передачи
| Параметр | Регистр и битовое поле | Значение регистра |
|---|---|---|
| Nominal Prescaler | BRPR.BRP | 0 |
| Nominal TS1 | BTR.TS1 | 62 |
| Nominal TS2 | BTR.TS2 | 15 |
| Nominal SJW | BTR.SJW | 15 |
| Data Prescaler | DP_BRPR.DP_BRP | 0 |
| Data TS1 | DP_BTR.TS1 | 13 |
| Data TS2 | DP_BTR.TS2 | 4 |
| Data SJW | DP_BTR.DP_SJW | 3 |
| TDC offset | DP_BRPR.TDСOFF | 14 |
В регистры записывается значение на единицу меньше расчетного значения.
Установка битов регистров BRPR, BTR, DP_BRPR и DP_BTR CAN FD 0 в значения из таблицы выше:
#define CANFD0_BASE 0x11010000UL //1
#define BRPR_BASE 0x08 //2
#define BTR_BASE 0x0C //3
#define DP_BTR_BASE 0x8C //4
#define DP_BRPR_BASE 0x88 //5
*(volatile uint32_t *)(CANFD0_BASE + BRPR_BASE) &= ~(0xFFUL); //6
{
uint32_t reg = *(volatile uint32_t *)(CANFD0_BASE + BTR_BASE); //7
// Очищаем TS1 (0:7), TS2 (8:14), SJW (16:22)
reg &= ~((0xFFUL) | (0x7FUL << 8) | (0x7FUL << 16));
// Записываем точные значения из комментария: 62 (0x3E), 15 (0x0F), 15 (0x0F)
reg |= ((0x3EUL) | (0x0FUL << 8) | (0x0FUL << 16));
*(volatile uint32_t *)(CANFD0_BASE + BTR_BASE) = reg;
}
*(volatile uint32_t *)(CANFD0_BASE + DP_BRPR_BASE) &= ~(0xFFUL); //8
{
uint32_t reg = *(volatile uint32_t *)(CANFD0_BASE + DP_BTR_BASE); //9
// Очищаем TS1 (0:4), TS2 (8:11), SJW (16:19) под Data Phase
reg &= ~((0x1FUL) | (0xFUL << 8) | (0xFUL << 16));
reg |= ((0x0DUL) | (0x04UL << 8) | (0x03UL << 16));
*(volatile uint32_t *)(CANFD0_BASE + DP_BTR_BASE) = reg;
}
{
uint32_t reg = *(volatile uint32_t *)(CANFD0_BASE + DP_BRPR_BASE);//10
reg &= ~((0x3FUL << 8) | (0x1UL << 16));
reg |= ((0x0EUL << 8) | (0x1UL << 16));
*(volatile uint32_t *)(CANFD0_BASE + DP_BRPR_BASE) = reg;
}
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра BRPR относительно адреса CAN FD 0;
③ установка адреса регистра BTR относительно адреса CAN FD 0;
④ установка адреса регистра DP_BTR относительно адреса CAN FD 0;
⑤ установка адреса регистра DP_BRPR относительно адреса CAN FD 0;
⑥ установка в значение 0 поля BRP регистра BRPR;
⑦ установка полей регистра BTR: поле TS1 = 62, TS2 = 15, SJW = 15;
⑧ установка в значение 0 поля DP_BRP регистра DP_BRPR;
⑨ установка полей регистра DP_BTR: TS1 = 13, TS2 = 4, DP_SJW = 3;
⑩ установка полей регистра DP_BRPR: TDC = 1, TDCOFF = 14.
Запрет повышенной скорости передачи данных
В некоторых случаях (длинная шина, сложная топология, наличие электромагнитных помех) для повышения надежности передачи необходимо запретить повышенную скорость фазы передачи данных.
По умолчанию повышенная скорость разрешена. Для запрета повышенной скорости в поле BRSD регистра MSR необходимо записать значение 1.
Пример отключения повышенной скорости передачи данных для CAN FD 0:
#define CANFD0_BASE 0x11010000UL //1
#define MSR_BASE 0x4 //2
*(volatile uint32_t *)(CANFD0_BASE + MSR_BASE) |= (1UL << 3); //3
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра MSR относительно адреса CAN FD 0;
③ запись значения 1 в поле BRSD регистра MSR.
Управление автоматической повторной передачей кадров
Количество автоматических повторных отправок кадров после неудачной отправки можно настроить в диапазоне до 255. Повторная автоматическая отправка по умолчанию отключена, включить её можно, установив бит DAR регистра MSR. Если все попытки оказываются неудачными, приёмопередатчик отключается от шины — состояние отключения от шины (высокого внутреннего сопротивления передающего каскада).
Ниже приведён пример включения повторной отправки (MSR.DAR=1) для CAN FD 0.
#define CANFD0_BASE 0x11010000UL //1
#define MSR_BASE 0x4 //2
*(volatile uint32_t *)(CANFD0_BASE + MSR_BASE) |= (1UL << 4); //3
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра MSR относительно адреса CAN FD 0;
③ запись значения 1 в поле DAR регистра MSR.
Управление реакцией на ошибку «Исключение протокола» (PEE)
Ошибку PEE обнаруживает контроллер узла-приёмника. Если он обнаруживает в кадре рецессивный бит res (1, вместо ожидаемого доминантного 0), контроллер приёмника переходит из режима «Приёмник» (Receiver) в режим «Интеграция» (Integrating) (устанавливает бит PEE_CONFIG регистра SR) и ждет состояния холостого хода шины (Bus Idle — 11 рецессивных бит подряд).
По умолчанию реакция на ошибку PEE включена. Отключить ее можно установкой бита DPEE регистра MSR, после чего рецессивный бит res будет восприниматься приёмником как обычная ошибка формы кадра (Form Error) с немедленной отправкой кадра ошибки (Error Frame).
Пример отключения реакции на ошибку PEE (MSR.DPEE=1) для CAN FD 0:
#define CANFD0_BASE 0x11010000UL //1
#define MSR_BASE 0x4 //2
*(volatile uint32_t *)(CANFD0_BASE + MSR_BASE) |= (1UL << 5); //3
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра MSR относительно адреса CAN FD 0;
③ запись значения 1 в поле DAR регистра MSR.
Управление восстановлением после отключения шины
При некоторых аварийных ситуациях контроллер CAN FD может перейти в состояние отключения от шины.
Восстановление передачи данных может быть:
- автоматическим (после 128 циклов по 11 последовательных рецессивных бит подряд) — если установлен бит ABR регистра
MSR; - программным — если после отключения шины установить бит SBR.
Пример включения автоматического восстановления подключения (MSR.ABR=1) для CAN FD 0:
#define CANFD0_BASE 0x11010000UL //1
#define MSR_BASE 0x4 //2
*(volatile uint32_t *)(CANFD0_BASE + MSR_BASE) |= (1UL << 7); //3
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра MSR относительно адреса CAN FD 0;
③ установка в 1 битового поля ABR регистра MSR.
Пример программного восстановления подключения (MSR.SBR=1) для CAN FD 0:
#define CANFD0_BASE 0x11010000UL //1
#define MSR_BASE 0x4 //2
*(volatile uint32_t *)(CANFD0_BASE + MSR_BASE) &= ~ (1UL << 7); //3
*(volatile uint32_t *)(CANFD0_BASE + MSR_BASE) |= (1UL << 6); //4
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра MSR относительно адреса CAN FD 0;
③ установка в 0 битового поля ABR регистра MSR;
④ установка в 1 битового поля SBR регистра MSR.
Бит SBR используется для управления восстановлением подключения только при MSR.ABR=0. При MSR.ABR=1, узел выполняет автоматическое восстановление после отключения от шины независимо от настройки бита MSR.SBR.
Чтобы программно восстановить передачу данных:
- прочитайте значение запроса на готовность буфера передачи (
TRR); - запишите считанное значение
TRRв запрос на отмену буфера передачи (TCR); - дождитесь, пока значение
TRRстанет равным 0; - запишите значение
TRR, считанное на шаге 1.
Значения настроек контроллер CAN FD не сохраняются после выключения питания.
Пример функции восстановления передачи для CAN FD 0 с возвратом значения запроса на готовность буфера передачи:
#define CANFD0_BASE 0x11010000UL //1
#define TRR_BASE 0x90 //2
#define IETRS_BASE 0x94 //3
uint32_t can_tx_recovery(void)
{
uint32_t trr_value;
uint32_t timeout = 10000; //4
trr_value = *(volatile uint32_t *)(CANFD0_BASE + TRR_BASE); //5
*(volatile uint32_t *)(CANFD0_BASE + IETRS_BASE) = trr_value; //6
while ((*(volatile uint32_t *)(CANFD0_BASE + TRR_BASE) != 0) && (timeout > 0))
{
timeout--;
for (volatile int i = 0; i < 100; i++);
}
if (timeout == 0) {
return 0; //7
}
*(volatile uint32_t *)(CANFD0_BASE + TRR_BASE) = trr_value; //8
return(trr_value); //9
}
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра TRR относительно адреса CAN FD 0;
③ установка адреса регистра IETRS относительно адреса CAN FD 0;
④ установка таймаута ожидания;
⑤ чтение значения запроса на готовность буфера передачи;
⑥ запись считанного значения TRR в запрос на отмену буфера передачи;
⑦ ожидание, пока значение TRR станет равным 0;
⑧ возврат в TRR значения, считанного на шаге 1;
⑨ возврат значения TRR. Значение может быть использовано для журналирования ошибок.
Настройка фильтрации получаемых сообщений
После установки бита CEN в регистре SRR CAN FD начинает принимать сообщения, передаваемые по шине. Прежде чем разрешить прием рекомендуется настроить фильтрацию, т.к. обычно требуется получать не все сообщения, передаваемые в шине.
Фильтрация сообщений по ID происходит следующим образом:
- сравнение по маске (регистр AFMR[i]): если бит маски равен 1, то этот бит ID будет сравниваться с битом регистра AFIR[i];
- сравнение битов, прошедших маскирование, с конкретными значениями фильтра ID (регистр AFIR[i]). Будут приняты только те сообщения, ID которых точно соответствует настроенному значению.
В МК реализовано 32 приемных фильтра с номерами от 0 до 31. Для каждого из них предусмотрено два регистра: регистр маски для ID (AFMR[i]) и регистр шаблона ID (AFIR[i]). Регистры работают попарно: если в соответствующем поле UAF[i] регистра AFR записано значение 1, пара принимает участие в фильтрации.
Входящие кадры могут быть иметь базовый или расширенный формат ID. Поскольку регистры фильтрации контроллера CAN рассчитаны на расширенный формат, должны быть назначены все битовые поля регистра AFMR[i] для расширенных кадров (AMID, AMSRR, AMIDE и AMRTR).
Для стандартных кадров должны быть назначены только AMID[28:18], AMSRR и AMIDE, а в AMID[17:0] и AMRTR должен быть записан 0.
Если хотя бы в одном разрешенном AFMR[i] будут записаны все нули, контроллер CAN FD будет принимать все сообщения, передаваемые в шине.
Ниже приведён пример настройки фильтра 0 CAN FD 0 для приёма сообщений с идентификатором 0x321 (стандартный идентификатор CAN FD).
#define CANFD0_BASE 0x11010000UL //1
#define AFR_BASE 0xE0 //2
#define AFMR0_BASE 0xA00 //3
#define AFIR0_BASE 0xA04 //4
*(volatile uint32_t *)(CANFD0_BASE + AFR_BASE) &= ~(1UL); //5
uint32_t reg_afir = 0; //6
reg_afir |= (0x321UL << 21);
*(volatile uint32_t *)(CANFD0_BASE + AFIR0) = reg_afir;
uint32_t reg_afmr = 0;
reg_afmr |= (0x7FFUL << 21); //7
*(volatile uint32_t *)(CANFD0_BASE + AFMR0_BASE) = reg_afmr;
*(volatile uint32_t *)(CANFD0_BASE + AFR_BASE) |= (1UL); //8
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра AFR относительно адреса CAN FD 0;
③ установка адреса регистра AFMR0 относительно адреса CAN FD 0;
④ установка адреса регистра AFIR0 относительно адреса CAN FD 0;
⑤ отключение нулевого фильтра перед настройкой (AFR[0] = 0);
⑥ настройка шаблона по ID 0x321 (стандартный формат), AFIR.AIID=0x321 и AFIR.AIIDE=0;
⑦ настройка маски (проверка всех 11 бит ID), AFMR.AMID=0x7FF;
⑧ включение нулевого фильтра.
Прием сообщений
Входящие сообщения, прошедшие фильтрацию, записываются по мере поступления в буфер FIFO-0 RX. FIFO-0 RX вмещает до 64 сообщений.
Входящие сообщения могут поступать быстрее, чем программа успевает их обрабатывать, что может привести к переполнению буфера. Чтобы не допустить переполнения значение предельного уровня заполнения нужно установить менее 64. При попытке заполнения выше этого уровня будет установлен бит в регистре прерываний ISR.
Для настройки параметра предельного уровня заполнения FIFO RX:
- сбросьте бит CEN в регистре
SRR, чтобы перевести контроллер CAN FD в режим настройки; - запишите значение в поле RXFWM регистра
WMR.
Значение поля после сброса контроллера — 0xF (15).
Узнать о том, что очередное сообщение записано в FIFO RX можно по состоянию бита RXOK регистра ISR, либо используя прерывания по приему сообщения (бит RXOK регистра ISR), для чего:
- установите бит ERXOK регистра
IER; - после обработки сообщения сбросьте бит RXOK, установив в 1 бит CRXOK регистра
ICR. Буфер принятых сообщений отображается на регистры:
RBiID– идентификатор;RBiDLC– длина данных;RBiDWn– регистр n байта данных RBi,
где: i –индекс регистра (от 0 до 63); n – номер регистра поля данных.
Алгоритм чтения полученных сообщений из буфера RX FIFO-0:
- прочитайте содержимое сообщения из буфера RX FIFO по его индексу в поле в RI регистра
FSR; - отметьте факт чтения записью 1 в бит IRI регистра
FSR. Это приведет к увеличению значения RI на 1, и уменьшению FL на 1, что равносильно освобождению одного места в буфере RX FIFO0. Если значение FL равно 0, установка бита IRI не имеет смысла; - повторяйте предыдущие шаги, пока все сообщения не будут прочитаны из RX FIFO-0. Одновременно с чтением поступающих сообщений, буфер может пополнятся сообщениями, принятыми с шины и прошедшими фильтрацию.
Ниже приведён пример считывания сообщений в массив data с проверкой наличия сообщений в буфере RX FIFO, определением типа ID (стандартный/расширенный) и типа кадра для CAN FD 0.
#define CANFD0_BASE 0x11010000UL //1
#define FSR_BASE 0xE8 //2
#define MSR_BASE 0x04 //3
#define RBiID_BASE 0x2100 //4
uint32_t fsr = *(volatile uint32_t *)(CANFD0_BASE + FSR_BASE); //5
uint8_t fill_level = (uint8_t)((fsr >> 8) & 0x3FUL); //6
if (fill_level > 0) //7
{
uint8_t index = (uint8_t)(fsr & 0x3FUL); //8
uint32_t msg_addr = CANFD0_BASE + RBiID_BASE + (index * 0x48); //9
uint32_t rb_id = *(volatile uint32_t *)(msg_addr); //10
uint32_t id;
uint8_t is_ext;
if ((rb_id & (1UL << 19)) == 0) { //11
id = (rb_id >> 21) & 0x7FFUL;
is_ext = 0;
} else {
id = ((rb_id >> 21) & 0x7FFUL) << 18;
id |= (rb_id >> 1) & 0x3FFFFUL;
is_ext = 1;
}
uint8_t is_remote;
if (is_ext) { //12
//расширенный кадр: бит RBiID[0] = RTR/RRS
is_remote = (rb_id & 1UL) ? 1 : 0;
} else {
//стандартный кадр: бит RBiID[20] = SRR/RTR/RRS
is_remote = (rb_id & (1UL << 20)) ? 1 : 0;
}
//чтение RBiDLC.DLC
uint8_t dlc = (uint8_t)((*(volatile uint32_t *)(msg_addr + 0x04) >> 28) & 0x0F); //13
uint8_t data_len = (dlc <= 8) ? dlc : (dlc <= 12) ? (4 * dlc - 24) :
(dlc <= 14) ? (8 * dlc - 72) : 64; //14
uint8_t data[64];
if (is_remote == 0) { //15
for (uint8_t i = 0; i < data_len; i++) {
uint8_t word_idx = i / 4;
uint8_t byte_idx = i % 4;
uint32_t word = *(volatile uint32_t *)(msg_addr + 0x08 + (word_idx * 0x4));
data[i] = (uint8_t)((word >> (8 * (3 - byte_idx))) & 0xFFUL);
}
} else {// REMOTE кадр: данных нет
data_len = 0;
}
*(volatile uint32_t *)(CANFD0_BASE + FSR_BASE) |= (1UL << 7); //16
}
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра FSR относительно адреса CAN FD 0;
③ установка адреса регистра MSR относительно адреса CAN FD 0;
④ установка адреса регистра RB0ID относительно адреса CAN FD 0;
⑤ чтение значения регистра FSR;
⑥ чтение значения FSR.FL для получения информации о заполнении RX FIFO;
⑦ проверка наличия сообщений (FSR.FL > 0);
⑧ получение индекса чтения (FSR.RI);
⑨ вычисление адреса сообщения как: 0x2100 + (FSR.RI \ 72 байта);
⑩ чтение 32-битного значения из RBiID;
⑪ проверка бит RBi.IDE для определения типа ID: стандартный или расширенный;
⑫ определение типа кадра (DATA/REMOTE);
⑬ преобразование RBiDLC.DLC в длину данных;
⑭ чтение данных;
⑮ кадр DATA: чтение данных;
⑯ увеличение значения индекса чтения буфера Rx FIFO (FSR.IRI=1).
Передача сообщений
Формирование кадра
Для передачи информации по шине CAN необходимо сформировать передаваемый кадр.
Алгоритм формирования передаваемого кадра:
- найдите в регистре
TRRбит со значением 0. Номер бита указывает на свободный для заполнения регистрTBiID; - в поле IDE регистра
TBiIDприсвойте кадру тип ID: 0 — стандартный ID,1 — расширенный ID; - в поле EDL / FDF регистра
TBiDLCприсвойте кадру признак длины данных: 0 — обычная длина данных CAN, 1 — увеличенная длина данных CAN FD; - в поле RTR / RRS регистра
TBiIDприсвойте кадру признак удаленная/обычная передача: 0 — обычная передача CAN, 1 — удаленная передача CAN; - в поле BRS регистра
TBiDLCукажите, будет ли использоваться повышенная скорость в фазе передачи данных: 0 — обычная скорость, 1 — повышенная скорость; - в поле DLC регистра
TBiDLCукажите количество байт подлежащих отправке; значения от 0 до 8 включительно определяют число байт, если байт больше 8, применяется кодирование, как указано в таблице 4.
Таблица 4 — Кодирование числа байт в поле DLC регистра TBiDLC для числа байт более 8
| Код | Количество байт |
|---|---|
| 0x9 | до 12 включительно |
| 0xA | до 16 включительно |
| 0xB | до 20 включительно |
| 0xC | до 24 включительно |
| 0xD | до 32 включительно |
| 0xE | до 48 включительно |
| 0xF | до 64 включительно |
- в поле EFC регистра
TBiDLCукажите контроллеру, нужно ли сохранять события отправки кадров в буфер событий: 0 — не сохранять, 1 — сохранять; - в поле ID регистра
TBiID([28:18] или [17:0]) запишите ID сообщения; - опционально можно записать в поле MM регистра
TBiDLCоригинальный 8-битовый маркер кадра; этот маркер попадет в буфер событий отправки кадра и может быть использован для последующего анализа; - запишите данные в поле DATA отправляемого кадра. Для формирования поля подготовьте 64-разрядные слова и запишите их последовательно по 4 байта в непрерывную область памяти, отведенную под TX буфер;
- запишите 1 в бит
TRR[i] – признак готовности сообщения к отправке (запрос на передачу). Механизм поддержки протокола по этому признаку разместит сообщение в FIFO TX для последующей отправки, когда там будет свободное место.
Не допускайте чтения/записи регистров передаваемых сообщений, не проверив, что соответствующий бит TRR[i] сброшен (значение равно 0).
Пример: Чтобы отправить 64 байта данных через буфер №5, нужно записать последовательно:
- байты 0-3 в TB5DW0;
- байты 4-7 в TB5DW1;
. . . - байты 60-63 в TB5DW15.
Все эти записи выполняются также, как запись обычных 32-разрядных значений в соответствующие адреса.
Таким способом можно подготовить множество сообщений к отправке, заполнив поля TBiID, TBiDLC и TBiDWn каждого элемента сообщения в соответствующем буфере TX. Затем запросить их отправку, записав 1 в соответствующие биты регистра TRR одной операцией записи этого регистра.
Когда сообщение будет отправлено в шину, контроллер CAN FD сбросит признак готовности (ожидания) отправки в бите TRR[i], тем самым разрешит заполнение данными регистров TBiID, TBiDLC и TbiDWn.
Событие завершившейся отправки установит бит TXOK в регистре ISR. Вы можете обработать это событие, опросив состояние бита TXOK. Если предварительно установить бит разрешения прерывания ETXOK в регистре IER, то можно использовать обработчик прерывания.
Сбросьте бит TXOK при первой возможности, записав 1 в бит CTXOK регистра ICR.
Ниже приведён пример отправки сообщения с использованием буфера 0 (TB0) с проверкой готовности буфера перед записью, настройкой стандартного идентификатора (ID = 0x123), передачей 8 байт данных и ожиданием завершения передачи через флаг TXOK.
#define CANFD0_BASE 0x11010000UL //1
#define TRR_BASE 0x90 //2
#define ISR_BASE 0x1C //3
#define ICR_BASE 0x24 //4
#define TBIDWN_BASE 0x108 //5
#define TBIDW1_BASE 0x10C //6
#define TBIID_BASE 0x100 //7
#define TBIDLC_BASE 0x104 //8
uint32_t trr = *(volatile uint32_t *)(CANFD0_BASE + TRR_BASE); //9
if (trr & 1UL) {//если TRR[0]=1, то буфер занят
return;
}
uint32_t tb0id = 0; //10
tb0id |= (0x123UL << 21); // ID[28:18] = 0x123
tb0id &= ~(1UL << 19); // IDE = 0 (стандартный ID)
tb0id &= ~(1UL << 0); // RTR/RRS=0 (обычная передача)
*(volatile uint32_t *)(CANFD0_BASE + TBIID_BASE) = tb0id;
uint32_t tb0dlc = 0; //11
tb0dlc |= (8UL << 28); // DLC = 8 (передача 8 байт данных)
tb0dlc &= ~(1UL << 27); // EDF/FDF = 0 (кадр формата CAN)
tb0dlc &= ~(1UL << 26); // BRS = 0 (т.к. кадр CAN)
tb0dlc &= ~(1UL << 24); // EFC = 0 (не сохранять события Tx)
*(volatile uint32_t *)(CANFD0_BASE + TBIDLC_BASE) = tb0dlc;
//12
uint32_t data0 = (0x01UL << 24) | (0x02UL << 16) | (0x03UL << 8) | 0x04UL;
uint32_t data1 = (0x05UL << 24) | (0x06UL << 16) | (0x07UL << 8) | 0x08UL;
*(volatile uint32_t *)(CANFD0_BASE + TBIDWN_BASE) = data0; //13
*(volatile uint32_t *)(CANFD0_BASE + TBIDW1_BASE) = data1; //14
*(volatile uint32_t *)(CANFD0_BASE + TRR_BASE) |= (1UL << 0); //15
while (!(*(volatile uint32_t *)(CANFD0_BASE + ISR_BASE) & (1UL << 1))){}//16
*(volatile uint32_t *)(CANFD0_BASE + ICR_BASE) = (1UL << 1); //17
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра TRR относительно адреса CAN FD 0;
③ установка адреса регистра ISR относительно адреса CAN FD 0;
④ установка адреса регистра ICR относительно адреса CAN FD 0;
④ установка адреса регистра ISR относительно адреса CAN FD 0;
⑤ установка адреса регистра TB0DW0 относительно адреса CAN FD 0;
⑥ установка адреса регистра TB0DW1 относительно адреса CAN FD 0;
⑦ установка адреса регистра TB0ID относительно адреса CAN FD 0;
⑧ установка адреса регистра TB0DLC относительно адреса CAN FD 0;
⑨ проверка свободности буфера 0 (TRR[0] = 0);
⑩ настройка TB0ID;
⑪ настройка TB0DLC;
⑫ запись 8 байт: 0x01…0x08;
⑬ запись данных data0 в TB0DW0[0-3];
⑭ запись данных data1 в TB0DW1[4-7];
⑮ запрос на передачу (TRR[0] = 1);
⑯ ожидание установки ISR.TXOK;
⑰ установка ICR.CTXOK = 1 для сброса прерывания TXOK.
Отмена передачи сообщения
Чтобы отменить передачу, достаточно записать 1 в соответствующий бит регистра TCR, вследствие чего будет отменен соответствующий запрос готовности, то есть сброшен бит RRi в регистре TRR.
Алгоритм отмены:
- проверьте состояние соответствующего бита в регистре
TCR. Если бит установлен, то сообщение ждет отмены; - проверьте состояние соответствующего бита в регистре
TRR. Если бит сброшен, сообщение уже отправлено или отменено; - убедитесь, что передача отменена – дождаться сброса бита в регистре
TCR.
Передачу сообщения невозможно отменить в 4 случаях:
- сообщение уже находится в процессе передачи;
- контроллер находится в режиме настройки;
- контроллер находится в состоянии отключения от шины;
- очередь буфера пуста или бит в
TRRуже равен 0.
Если сообщение из выбранного буфера уже начало передаваться на CAN-шину, контроллер не может прервать передачу посреди кадра, так как это нарушило бы протокол CAN и вызвало ошибку на шине (Error Frame). Если вы запишете 1 в регистр TCR в этот момент, бит CRi установится, но отмена «зависнет» в ожидании. Если передача завершится успешно, то запрос отмены будет проигнорирован, а биты в TRR и TCR сбросятся. В случае ошибки передачи контроллер остановит повторную отправку.
В режиме настройки (установлен бит SRR[CEN] = 0 или MSR[CONFIG] = 1), вся логика отправки и арбитража сообщений полностью останавливается, в связи с чем отмена отправки невозможна.
В состоянии отключения от шины контроллер автоматически сбрасывает все текущие запросы на передачу. Попытка отменить то, что уже автоматически сброшено или заблокировано аварийной логикой, может привести к зависанию контроллера.
Если сообщение уже ушло или вообще не ставилось в очередь (бит RRi в регистре TRR равен 0), то попытка отмены очевидно невозможна. Запись единицы в TCR в лучшем случае будет проигнорирована контроллером, а в худшем — бит TCR останется в неопределенном состоянии до следующей корректной отправки.
Чтобы не использовать циклы ожидания процессора, можно использовать соответствующие прерывания.
Ниже приведён пример функции, которая выполняет отмену передачи сообщения буфера CAN FD 0. При успешной отмене функция возвращает значение 0, а если сообщение не может быть отменено, то функция возвращает значение 1.
#define CANFD0_BASE 0x11010000UL //1
#define TCR_BASE 0x98 //2
#define TRR_BASE 0x90 //3
#define ISR_BASE 0x1C //4
#define ICR_BASE 0x24 //5
uint8_t canfd_transmit_cancel(void)
{
if (*(volatile uint32_t *)(CANFD0_BASE + TCR_BASE) & 1UL) { //6
while (*(volatile uint32_t *)(CANFD0_BASE + TCR_BASE) & 1UL) { //7
}
return 0; //8
}
if (!(*(volatile uint32_t *)(CANFD0_BASE + TRR_BASE) & 1UL)) { //9
return 1; //10
}
*(volatile uint32_t *)(CANFD0_BASE + TCR_BASE) |= (1UL << 0); //11
while (*(volatile uint32_t *)(CANFD0_BASE + TCR_BASE) & (1UL << 0)){} //12
if (*(volatile uint32_t *)(CANFD0_BASE + ISR_BASE) & (1UL << 14)) { //13
*(volatile uint32_t *)(CANFD0_BASE + ICR_BASE) = (1UL << 14); //14
}
return 0;
}
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра TCR относительно адреса CAN FD 0;
③ установка адреса регистра TRR относительно адреса CAN FD 0;
④ установка адреса регистра ISR относительно адреса CAN FD 0;
⑤ установка адреса регистра ICR относительно адреса CAN FD 0;
⑥ проверка состояния бита TCR[0];
⑦ если TCR[0] = 1 сообщение уже в процессе отмены;
⑧ ожидание TCR[0] = 0;
⑨ проверка состояния бита TRR[0];
⑩ если TRR[0] = 0 сообщение уже отправлено или отменено;
⑪ запрос на отмену передачи (TCR[0] = 1);
⑫ ожидание сброса TCR[0] (подтверждения отмены);
⑬ проверка, что ISR.TXCRS=1;
⑭ сброс прерывания TXCRS (ICR.CTXCRS = 1).
Журнал отправки сообщений
CAN FD поддерживает журналирование отправляемых сообщений. Можно разрешить генерацию прерывания по определенному событию.
До установки бита TRR[i] для сообщения:
- настройте сохранение событий в буфер событий установкой бита EFC в поле
TBiDLC; - дождитесь прерывания (если оно настроено) или выполните опрос регистра
TRRдля определения того, было отравлено сообщение (0) или нет (1); - прочитайте значения полей событий в регистрах TXE_FIFO_TBi_ID и TXE_FIFO_TBi_DLC, например, MM и Timestamp в регистре TXE_FIFO_TBi_DLC.
Настройка и обработка прерываний
Каждый из контроллеров CAN FD имеет собственную линию прерываний: canfd_0_irq или canfd_1_irq (в зависимости от номера контроллера CAN), каждая из которых заведена на контроллер прерываний CLIC ядер 0/1.
Прерывания могут генерироваться при возникновении ошибок на шине, при передаче и приеме сообщений, а также при выполнении различных других условий (подробнее см. в документе «BE-U1000. Reference Manual», описание регистров ISR, а также раздел «Прерывания»).
Для работы с прерываниями CAN FD предусмотрены регистры:
IER- регистр разрешения прерывания;ISR- регистр состояния прерывания;ICR– регистр сброса прерывания.
При включении питания МК на линии прерывания устанавливается низкий уровень сигнала (отсутствие прерываний).
Установка битов регистраIERразрешает передачу соответствующих прерываний в CLIC по выделенной линии прерываний. При установке в 0 битов регистраIERсоответствующее прерывание не будет вызывать изменение уровня выделенной линии прерываний на CLIC, однако будет отображено в соответствующем регистре и может быть обработано программно.
Установка битового поля EPEE регистра IER для включения Protocol Exception Event Interrupt на CAN FD 0:
#define CANFD0_BASE 0x11010000UL //1
#define IER_BASE 0x20 //2
*(volatile uint32_t *)(CANFD0_BASE + IER_BASE) |= (1UL << 2); //3
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра IER относительно адреса CAN FD 0;
③ установка в 1 битового поля EPEE регистра IER.
Чтение битового поля PEE регистра ISR для CAN FD 0:
#define CANFD0_BASE 0x11010000UL //1
#define ISR_BASE 0x1C //2
(*(volatile uint32_t *)(CANFD0_BASE + ISR_BASE) & (1UL << 2)) ? 1 : 0; //3
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра ISR относительно адреса CAN FD 0;
③ чтение битового поля PEE регистра ISR.
Сброс битового поля PEE регистра ISR при помощи бита CPEE регистра IСR для CAN FD 0:
#define CANFD0_BASE 0x11010000UL //1
#define ICR_BASE 0x24 //2
*(volatile uint32_t *)(CANFD0_BASE + ICR_BASE) = (1UL << 2); //3
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра ICR относительно адреса CAN FD 0;
③ установка бита CPEE регистра IСR.
Пример установки IER.ETXOK=1 для CAN FD 0, для разрешения генерации прерывания в CLIC при срабатывании прерывания по успешной передаче на CAN FD 0 (ISR.TXOK=1):
#define CANFD0_BASE 0x11010000UL //1
#define IER_BASE 0x20 //2
*(volatile uint32_t *)(CANFD0_BASE + IER_BASE) |= (1UL << 1); //3
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра IER относительно адреса CAN FD 0;
③ установка бита ETXOK регистра IER.
При IER.ETXOK=0, прерывание TXOK не передаётся на CLIC. При этом статус данного прерывания может быть прочитан в ISR.TXOK и обработан программно.
Пример считывания статуса прерывания по успешной передаче (ISR.TXOK):
#define CANFD0_BASE 0x11010000UL //1
#define ISR_BASE 0x1C //2
uint32_t txok_sts = (*(volatile uint32_t *)
(CANFD0_BASE + ISR_BASE) & (1UL << 1)) >> 1; //3
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра ISR относительно адреса CAN FD 0;
③ чтение бита TXOK регистра ISR.
Для сброса прерывания необходимо установить соответствующий бит в регистре ICR. Ниже приведён пример сброса прерывания по успешной передаче (ICR.CTXOK).
#define CANFD0_BASE 0x11010000UL //1
#define ICR_BASE 0x24 //2
*(volatile uint32_t *)(CANFD0_BASE + ICR_BASE) = (1UL << 1); //3
① установка базового адреса контроллера CAN FD 0;
② установка адреса регистра ICR относительно адреса CAN FD 0;
③ установка бита CTXOK регистра ICR.
Тестирование контроллеров CAN FD
Для тестирования работы контроллера CAN можно использовать внутреннюю или внешнюю петлю.
Внешняя петля – это соединение двух контроллеров CAN: CAN FD 0 и CAN FD 1 для отправки сообщений друг другу.
Внутренняя петля – это режим работы контроллера CAN, при котором он отправляет сообщения и сам же их принимает, имитируя работу на шине.
Внешняя петля
Режим внешней петли позволяет тестировать одновременно два контроллера CAN (CAN_FD 0 и CAN_FD 1) в условиях отсутствия приёмопередатчика. При этом проверяются внешние выводы МК и печатной платы. Для этого необходимо соединить внешние выводы контроллеров CAN_FD 0 и CAN_FD 1 как показано на рисунке 2.
Рисунок 2 — Контроллеры CAN FD в режиме внешней петли
Другой вариант позволяет проверить также приемопередатчики, если присоединить их к МК и соединить между собой выводы приемопередатчиков, как показано на рисунке 3.
Рисунок 3 — Приёмопередатчики CAN FD в режиме внешней петли
Для обоих приемопередатчиков необходимо установить терминаторы.
Внутренняя петля
Режим внутренней петли включается установкой бита LBACK регистра MSR и позволяет проводить внутреннее тестирование одного контроллера CAN FD, а также отладку управляющей программы даже при отсутствии приёмопередатчика. Если выбран режим внутренней петли, то на внешнем передающем выводе контроллера CAN FD постоянно поддерживается высокий уровень сигнала (1), а состояние принимающего вывода игнорируется.
Ниже приведен пример программы, реализующей режим внутренней петли с использованием функций SDK.
Программа настраивает контроллер CAN FD 0 в режим внутренней петли и раз в секунду отправляет и принимает сообщения с ID 0x321. Повышенная скорость передачи данных отключена, обмен происходит на скорости 1 Мбит/с.
#define CRU_BASE 0x14000000UL
#define CANFD0_BASE 0x11010000UL
#define PCLK0EN_BASE 0x0C
#define CAN_SRR_BASE 0x00
#define MSR_BASE 0x04
#define BRPR_BASE 0x08
#define BTR_BASE 0x0C
#define DP_BRPR_BASE 0x88
#define RBiID_BASE 0x2100
#define DP_BTR_BASE 0x8C
#define RBiDWn_BASE 0x2108
#define AFIR0_BASE 0xA04
#define WMR_BASE 0xEC
#define RBiDLC_BASE 0x2104
#define FSR_BASE 0xE8
#define TRR_BASE 0x90
#define TBiDLC_BASE 0x104
#define TBiDWn_BASE 0x108
/* ИНИЦИАЛИЗАЦИЯ CANFD В РЕЖИМЕ LOOPBACK */
void CANFD0_Loopback_Init(void)
{
//включение тактирования CANFD0 (PCLK0EN[29]=1)
*(volatile uint32_t *)(CRU_BASE + PCLK0EN_BASE) |= (1UL << 29);
//установка бита SRR.SRST для выполнения сброса CANFD0
*(volatile uint32_t *)(CANFD0_BASE + CAN_SRR_BASE) |= (1UL);
__delay_cycles(100UL);
//установка MSR.LBACK=1
*(volatile uint32_t *)(CANFD0_BASE + MSR_BASE) |= (1UL << 1);
//установка BRPR.BRP=0x1
*(volatile uint32_t *)(CANFD0_BASE + BRPR_BASE) =
(*(volatile uint32_t *)(CANFD0_BASE + BRPR_BASE) & ~ (0xFFUL)) | (0x1UL);
//установка BTR.TS1=0xB , BTR.TS2=0xB , BTR.SJW=0x0
{
uint32_t btr_reg = *(volatile uint32_t *)(CANFD0_BASE + BTR_BASE);
//очистка битовых полей
btr_reg &= ~((0x7FUL << 16) | //BTR.SJW=0x0
(0x7FUL << 8) | //BTR.TS2=0x0
(0xFFUL)); //BTR.TS1=0x0
//установка битовых полей
btr_reg |= ((0xBUL << 8) | //BTR.TS2=0xB
(0xBUL)); //BTR.TS1=0xB
*(volatile uint32_t *)(CANFD0_BASE + BTR_BASE) = btr_reg;
}
//установка DP_BRPR.DP_BRP=0x1
*(volatile uint32_t *)(CANFD0_BASE + DP_BRPR_BASE) =
(*(volatile uint32_t *)(CANFD0_BASE + DP_BRPR_BASE) & ~ (0xFFUL)) | (0x1UL);
//установка DP_BTR.DP_TS1=0xB , DP_BTR.DP_TS2=0xB , DP_BTR.DP_SJW=0x0
{
uint32_t dp_btr_reg = *(volatile uint32_t *)(CANFD0_BASE + DP_BTR_BASE);
//очистка битовых полей
dp_btr_reg &= ~((0xFUL << 16) | //DP_BTR.DP_SJW=0x0
(0xFUL << 8) | //DP_BTR.DP_TS2=0x0
(0x1FUL)); //DP_BTR.DP_TS1=0x0
//установка битовых полей
dp_btr_reg |= ((0xBUL << 8) | //DP_BTR.DP_TS2=0xB
(0xBUL)); //DP_BTR.DP_TS1=0xB
*(volatile uint32_t *)(CANFD0_BASE + DP_BTR_BASE) = dp_btr_reg;
}
//установка MSR.ABR=1
*(volatile uint32_t *)(CANFD0_BASE + MSR_BASE) |= (1UL << 7);
//устанавливаем WMR.RXFM=0x1F
*(volatile uint32_t *)(CANFD0_BASE + WMR_BASE) =
(*(volatile uint32_t *)(CANFD0_BASE + WMR_BASE) & ~(0x3FUL)) | (0x1FUL);
//отключаем фильтр 0, AFR[0]=0
*(volatile uint32_t*)(CANFD0_BASE + AFR_BASE) &= ~(1UL << 0);
//настраиваем фильтр 0
//AFIR0.AIID = 0x123, AFIR0.AISRR = 0, AFIR0.AIIDE = 0
*(volatile uint32_t*)(CANFD0_BASE + AFIR0_BASE) = ((0x123UL & 0x7FFUL) << 21) |//AFIR0.AIID = 0x123
(0UL << 20) | //AFIR0.AISRR = 0
(0UL << 19); //AFIR0.AIIDE = 0
//AFMR0.AMID = 0x7FF, AFMR0.AMSRR = 1, AFMR0.AMIDE = 1
*(volatile uint32_t*)(CANFD0_BASE + AFMR0_BASE) = ((0x7FFUL & 0x7FFUL) << 21) |//AFMR0.AMID = 0x7FF
(1UL << 20) |//AFMR0.AMSRR = 1
(1UL << 19); //AFMR0.AMIDE = 1
//включаем фильтр 0, AFR[0]=1
*(volatile uint32_t*)(CANFD0_BASE + AFR_BASE) |= (1UL << 0);
//CANFD_Enable(CANFD0);
//установка бита SRR.CEN для включения CANFD0
*(volatile uint32_t *)(CANFD0_BASE + CAN_SRR_BASE) |= (1UL << 1);
}
/* ФУНКЦИЯ ДЛЯ ПРИЁМА ДАННЫХ */
void CANFD0_Receive (CANFD_RxData_TypeDef *RxMessage)
{
//читаем FSR.RI для получения индекса буфера RX FIFO-0
uint8_t Index = *(volatile uint32_t*)(CANFD0_BASE + FSR_BASE) & 0x3FUL;
//читаем RBiID.IDE для получения информации о расширении идентификатора
uint8_t IdeExt = (*(volatile uint32_t*)(CANFD0_BASE + RBiID_BASE + (0x48 * Index)) >> 19) & 0x1UL;
if (IdeExt > 0U) //RBiID.IDE = 1 и используется расширенный идентификатор
{
//читаем RBiID.ID[28:18] и RBiID.ID[17:0] для получения расширенного идентификатора
uint32_t ExtID = ((*(volatile uint32_t*)(CANFD0_BASE + RBiID_BASE + (0x48 * Index)) >> 21) & 0x7FFUL) << 18 |
(*(volatile uint32_t*)(CANFD0_BASE + RBiID_BASE + (0x48 * Index)) >> 1) & 0x3FFFFUL;
}
else //RBiID.IDE = 0 и используется стандартный идентификатор
{
//читаем RBiID.ID[28:18] для получения стандартного идентификатора
uint32_t StdID = (*(volatile uint32_t*)(CANFD0_BASE + RBiID_BASE + (0x48 * Index)) >> 21) & 0x7FFUL;
}
//читаем код длины данных из RBiDLC.DLC[3:0]
uint8_t DLCVal = (*(volatile uint32_t*)(CANFD0_BASE + RBiDLC_BASE + (0x48 * Index)) >> 28) & 0xFUL;
//вычисляем длину сообщения
uint8_t MLength;
if (DLCVal <= 0x8) MLength = (uint8_t)DLCVal;
else if (DLCVal == 0x9) MLength = 12U;
else if (DLCVal == 0xA) MLength = 16U;
else if (DLCVal == 0xB) MLength = 20U;
else if (DLCVal == 0xC) MLength = 24U;
else if (DLCVal == 0xD) MLength = 32U;
else if (DLCVal == 0xE) MLength = 48U;
else MLength = 64U;
for (uint8_t i = 0U; i < MLength; i++)
{
uint8_t WordIdx = i / 4U;
uint8_t ByteIdx = i % 4U;
//читаем регистр RBiDWn
uint32_t RegValue = *(volatile uint32_t*)(CANFD0_BASE + RBiDWn_BASE + (0x48 * Index) + (WordIdx * 4U));
RxMessage->RxData[i] = (uint8_t)((RegValue >> (8U * (3U - ByteIdx))) & 0xFFUL);
}
//увеличиваем индекс чтению буфера записью 1 в FSR.IRI
*(volatile uint32_t *)(CANFD0_BASE + FSR_BASE) |= (1UL << 7);
}
/* ФУНКЦИЯ ДЛЯ ОТПРАВКИ ДАННЫХ */
uint8_t CANFD0_Transmit (CANFD_TxData_TypeDef *TxMessage)
{
uint8_t TxBufferIndex = 0U;
//проверяем наличие свободных буферов чтением TRR.RRi
uint32_t RegVal = *(volatile uint32_t*)(CANFD0_BASE + TRR_BASE);
if (RegVal != 0xFFFFFFFFUL) //проверяем, что имеется хотя-бы один свободный буфер
{
//находим индекс первого свободного буфера
uint32_t Mask = 0x1UL;
while (((RegVal & Mask) != 0UL) &&
(TxBufferIndex < 32U))
{
Mask <<= 1;
TxBufferIndex++;
}
//устанаваливаем TBiID.IDE = 0 для использования стандартного идентификатора
*(volatile uint32_t *)(CANFD0_BASE + TBiID_BASE + (TxBufferIndex * 0x48)) &= ~ (1UL << 19);
//устанавливаем TBiID.ID[28:18] = 0x123
*(volatile uint32_t *)(CANFD0_BASE + TBiID_BASE + (TxBufferIndex * 0x48)) =
((0x123UL & 0x7FFUL) << 21);
//устанавливаем TBiDLC.DLC = 0x8
*(volatile uint32_t *)(CANFD0_BASE + TBiDLC_BASE + (TxBufferIndex * 0x48)) =
((0x8UL & 0xFUL) << 28);
uint32_t Data = 0UL;
uint8_t Datalen = 8UL;
for (uint8_t i = 0U; i < Datalen; i++)
{
uint8_t WordIdx = i / 4U;
uint8_t ByteIdx = i % 4U;
if (ByteIdx == 0U)
Data = 0UL;
Data |= ((uint32_t)TxMessage->TxData[i] << (8U * (3U - ByteIdx)));
if ((ByteIdx == 3U) || (i == (Datalen - 1U)))
{
//записываем данные в регистр TBiDWn
//CANFDx->TB[TxBufferIndex].DW[WordIdx] = Data;
*(volatile uint32_t *)(CANFD0_BASE + TBiDWn_BASE + (TxBufferIndex * 0x48) + (WordIdx * 0x4)) = Data;
}
}
//устанавливаем TRR.RRi для включения готовности к отправке
*(volatile uint32_t *)(CANFD0_BASE + TRR_BASE) |= (1UL << TxBufferIndex);
}
else
{
//вывод информации, что свободных буферов нет
//используем индекс ==32, т.к. нумерация буферов 0..31 и число 32 не достигается при нормальной работе
TxBufferIndex = 32U;
}
return TxBufferIndex;
}
/* ИНИЦИАЛИЗАЦИЯ */
void Init(void)
{
CLK_Init();//инициализация тактовых сигналов
UART0_serial_init();//инициализация UART0
CANFD0_Loopback_Init();//инициализация CANFD0 в режиме Loopback
}
/* ОСНОВНАЯ ПРОГРАММА */
int main(void)
{
uint32_t MessageCounter = 0;
CANFD_RxData_TypeDef RxMessage;
CANFD_TxData_TypeDef TxMessage;
Init();
//вывод начального сообщения для отделения служебной информации консоли от выводимых данных
printf("\r\n=== UART initialized ===\r\n\r\n");
for(;;)
{
MessageCounter++;
//формируем строку
char msg[8];
snprintf(msg, sizeof(msg), "M %03lu", (unsigned long)MessageCounter);
memcpy(TxMessage.TxData, msg, 8);
//проверяем, что имеется хотя-бы один свободный буфер
uint8_t NbBuf = CANFD0_Transmit (&TxMessage);
if (NbBuf != 32U)
{
printf("CANFD0 Tx: %s\r\n", (char*)TxMessage.TxData);
}
//Проверяем уровень уровень заполнения FIF0
//Читаем FSR.FL
if (((*(volatile uint32_t*)(CANFD0_BASE + FSR_BASE) >> 8) & 0x7FUL) > 0U)
{
CANFD0_Receive(&RxMessage);
printf("CANFD0 Rx (loopback): %s\r\n", (char*)RxMessage.RxData);
}
// Задержка ~1 секунда
for (volatile uint32_t i = 0; i < 1000000; i++) {
__delay_cycles(100);
}
}
return 0;
}
Скачать PDF ⬇️ AppNote_CAN-FD_v1.pdf
История изменений
| Версия | Дата | Описание |
|---|---|---|
| 1.0 | 27.08.2026 | Начальная версия |