[Программирование микроконтроллеров, DIY или Сделай сам] FDCAN на STM32

Автор Сообщение
news_bot ®

Стаж: 6 лет 3 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
11-Мар-2021 16:31

Запускаем модуль flexible data rate can на STM32H743 на регистрах без cubemx.
Вступление.Новый стандарт FDCAN был разработан компанией BOSCH в 2012 году. Стандарт обеспечивает больший объём передаваемых данных и скорости больше 1 мбит (для поля данных), скорость которого может достигать 12 мбит. Размер поля данных был увеличен до 64 байт. Что касается совместимости can и fdcan, то приёмники нового стандарта понимают вариант протокола, а старые приёмники не совместимы с новым стандартом. Углубляться в особенности протокола не будем, т.к. этой информации достаточно в интернете, а сразу перейдём к реализации fdcan от stm.Инициализация модуля FDCAN.Основное отличие FDCAN от BxCAN в микроконтроллерах stm32 заключается в реализации выделенной памяти для фильтров и буферов. В мк stm32h743 для fdcan выделено ровно 10 кбайт общей памяти (для fdcan1 и fdcan2). Эта область памяти гибко настраивается под любые нужны.
Адресация этой памяти идёт по 4 байта (слово): младшие два бита адреса не используются и адрес битовых полей xxSA (стартовый адрес каждого раздела) сдвинут на два бита вправо. Стартовый адрес в мк stm32h743 = 0x4000AC00.Далее последовательность настройки:1) Выбираем источник тактирования модулей fdcan:
  • 00: hse_ck clock is selected as FDCAN kernel clock (default after reset)
  • 01: pll1_q_ck clock is selected as FDCAN kernel clock
  • 10: pll2_q_ck clock is selected as FDCAN
RCC->D2CCIP1R |= RCC_D2CCIP1R_FDCANSEL_1;
2) Настраиваем пины GPIO на нужную нам функцию:Если используем стандартный CAN, то ищем пины FDCANxTX / FDCANxRX. Если используем FDCAN, то пины соответственно FDCANx_TXFD_MODE / FDCANxRXFDMODE. В моём примере я использовал обычный CAN на пинах PA11 (RX) и PA12 (TX), альтернативная функция #9. Использую свою инициализацию. Библиотека есть на github`e.
gpio_init (PORT_A, 11, MODE_ALT_F, TYPE_PUSH_PULL, SPEED_MAX, PULL_NO, ALTF_9); // RX
gpio_init (PORT_A, 12, MODE_ALT_F, TYPE_PUSH_PULL, SPEED_MAX, PULL_NO, ALTF_9); // TX
3) Включаем FDCAN модули:
RCC->APB1HENR |= RCC_APB1HENR_FDCANEN;
4) Входим в процесс инициализации:
FDCAN1->CCCR |= FDCAN_CCCR_INIT;
while ((FDCAN1->CCCR & FDCAN_CCCR_INIT) == 0) {};
5) Разрешаем запись в регистры настройки:
FDCAN1->CCCR |= FDCAN_CCCR_CCE;
6) Включаем классический CAN и выключаем автоматическую ретрансляцию:
FDCAN1->CCCR &= ~(FDCAN_CCCR_FDOE);
FDCAN1->CCCR |= FDCAN_CCCR_DAR; // RETR OFF
7) При необходимости можно включить Loopback режим для отладки:
FDCAN1->CCCR |= FDCAN_CCCR_TEST;
FDCAN1->TEST |= FDCAN_TEST_LBCK;
8) Очищаем область памяти:
#define FDCAN_MEM_START_ADDR          0x4000AC00UL
#define FDCAN_MEM_END_ADDR            0x4000D3FFUL
unsigned long *i;
for (i = (unsigned long*)FDCAN_MEM_START_ADDR; i < (unsigned long*)FDCAN_MEM_END_ADDR; i++) *i = 0;
10) Настраиваем номинальные time quanta сегменты и при необходимости time quanta сегменты для переменного битрейта :
#define CAN_PRESCALER   6
#define CAN_SYNC_JW     2
#define CAN_SYNC_SEG    1
#define CAN_PHASE_SEG1 11
#define CAN_PHASE_SEG2  4
// nominal time quanta segments
FDCAN1->NBTP  = (CAN_SYNC_JW    - 1) << FDCAN_NBTP_NSJW_Pos;
FDCAN1->NBTP |= (CAN_PRESCALER  - 1) << FDCAN_NBTP_NBRP_Pos;
FDCAN1->NBTP |= (CAN_PHASE_SEG1 - 1) << FDCAN_NBTP_NTSEG1_Pos;
FDCAN1->NBTP |= (CAN_PHASE_SEG2 - 1) << FDCAN_NBTP_NTSEG2_Pos;
// flexible bitrate time quanta segments
FDCAN1->DBTP  = (CAN_SYNC_JW    - 1) << FDCAN_DBTP_DSJW_Pos;
FDCAN1->DBTP |= (CAN_PRESCALER  - 1) << FDCAN_DBTP_DBRP_Pos;
FDCAN1->DBTP |= (CAN_PHASE_SEG1 - 1) << FDCAN_DBTP_DTSEG1_Pos;
FDCAN1->DBTP |= (CAN_PHASE_SEG2 - 1) << FDCAN_DBTP_DTSEG2_Pos;
В итоге, при частоте fdcan kernel clock равной 48 МГц, битрейт получается 500 КГц.Один бит протокола can состоит из четырёх временных сегментов:
  • Сегмент синхронизации (SYNC_SEG)
  • Cегмент распространения (PROP_SEG)
  • Фазовый сегмент 1 (PHASE_SEG1)
  • Фазовый сегмент 2 (PHASE_SEG2)
В реализации stm используются три сегмента:
  • Сегмент синхронизации (SYNC_SEG):
  • Битовый сегмент 1 (включая PROP_SEG и PHASE_SEG1)
  • Битовый сегмент 2 (PHASE_SEG2)

Сегменты одинарного бита протокола CANTime quanta - минимальная неделимая единица времени в протоколе CAN. Её получаем разделив единицу на fdcan kernel clock. Получаем Tq = 2.08333333e-8. Далее вступает в действие прескалер частоты. Мы умножаем нашу Tq на значение CAN_PRESCALER и получаем Tq = 0,000000125 сек.Чтобы получить конечное время одного бита, умножаем сумму наших сегментов (1 + 14 + 4) на Tq и получаем 0,000002 сек. В последнем действии берём единицу и делим на наше время одного бита. 1 / 0,000002 = 500 000 Гц.11) Выключаем приём не нужных пакетов:
FDCAN1->GFC |= FDCAN_GFC_ANFS; // Reject non-matching frames standard
FDCAN1->GFC |= FDCAN_GFC_ANFE; // Reject non-matching frames extended
FDCAN1->GFC |= FDCAN_GFC_RRFS; // Reject all remote frames with 11-bit standard ID
FDCAN1->GFC |= FDCAN_GFC_RRFE; // Reject all remote frames with 29-bit standard ID
10) Настраиваем количество фильтров и их начальные адреса в области выделенной памяти:
// 11-bit filters
#define FDCAN_11B_FILTER_EL_CNT       0UL
#define FDCAN_11B_FILTER_EL_SIZE      4UL
#define FDCAN_11B_FILTER_EL_W_SIZE    (FDCAN_11B_FILTER_EL_SIZE / 4)
#define FCCAN_11B_FILTER_START_ADDR   (FDCAN_MEM_START_ADDR)
#define FDCAN_11B_FILTER_OFFSET       0UL
// 29-bit filters
#define FDCAN_29B_FILTER_EL_CNT       4UL
#define FDCAN_29B_FILTER_EL_SIZE      8UL
#define FDCAN_29B_FILTER_EL_W_SIZE    (FDCAN_29B_FILTER_EL_SIZE / 4)
#define FCCAN_29B_FILTER_START_ADDR   (FCCAN_11B_FILTER_START_ADDR + FDCAN_11B_FILTER_EL_CNT * FDCAN_11B_FILTER_EL_SIZE)
#define FDCAN_29B_FILTER_OFFSET       (FDCAN_11B_FILTER_OFFSET     + FDCAN_11B_FILTER_EL_CNT * FDCAN_11B_FILTER_EL_W_SIZE)
FDCAN1->SIDFC = (FDCAN_11B_FILTER_EL_CNT << FDCAN_SIDFC_LSS_Pos); // standart filter count
FDCAN1->XIDFC = (FDCAN_29B_FILTER_EL_CNT << FDCAN_XIDFC_LSE_Pos); // extended filter count
FDCAN1->SIDFC |= (FDCAN_11B_FILTER_OFFSET << FDCAN_SIDFC_FLSSA_Pos); // standard filter start address
FDCAN1->XIDFC |= (FDCAN_29B_FILTER_OFFSET << FDCAN_XIDFC_FLESA_Pos); // extended filter start address
11) Далее настраиваем сами фильтры, о чём подробнее:Структура стандартного фильтра (размер = 32 бита):
Структура элемента стандартного фильтраSFT00: Диапазон значений идентификаторов от SFID1 до SFID201: Идентификатор SFID1 + идентификатор SFID210: Классический фильтр: SFID1 = фильтр, SFID2 = маска11: Фильтр выключен.SFEC000: Фильтр выключен.001: Сохранять валидные пакеты в FIFO 0010: Сохранять валидные пакеты в FIFO 1011: Отклонять пакеты валидные пакеты100: Сделать приоритетным валидный пакет101: Сделать приоритетным валидный пакет и поместить в буфер FIFO 0110: Сделать приоритетным валидный пакет и поместить в буфер FIFO 1111: Сохранить в Rx буфер или как отладочное сообщение, конфигурация FDCAN_SFT[1:0] игнорируется.SFID1Стандартный идентификатор 1SFID2Стандартный идентификатор 2 / маскаРасширенные фильтры занимают уже два слова в выделенной памяти. Структура расширенного фильтра (размер = 64 бита):
Структура элемента расширенного фильтраEFEC000: Фильтр выключен.001: Сохранять валидные пакеты в FIFO 0010: Сохранять валидные пакеты в FIFO 1011: Отклонять пакеты валидные пакеты100: Сделать приоритетным валидный пакет101: Сделать приоритетным валидный пакет и поместить в буфер FIFO 0110: Сделать приоритетным валидный пакет и поместить в буфер FIFO 1111: Сохранить в Rx буфер, конфигурация FDCAN_SFT[1:0] игнорируется.EFTI00: Диапазон значений идентификаторов от EFID1 до EFID201: Идентификатор EFID1 + идентификатор EFID210: Классический фильтр: EFID1 = фильтр, EFID2 = маска11: Диапазон значений идентификаторов от EFID1 до EFID2. FDCAN_XIDAM маска не применяется.EFID1Расширенный идентификатор 1EFID2Расширенный идентификатор 2Для обработки расширенных кадров в регистре XIDAM можно задать глобальную маску, которая после перезагрузки МК имеет значение 0x1FFF FFFF, т.е. заставляет fdcan модуль проверять все биты идентификаторов. Если выставить этот регистр в ноль, то модуль будет принимать абсолютно все пакеты. В битовом поле EFTI расширенных фильтров можно отключить использование этой маски.Настраиваем сами фильтры:
#define CAN_TEST_ID_0 0x01
#define CAN_TEST_ID_1 0x02
// FILTER TYPE
#define FILTER_TYPE_RANGE       0UL
#define FILTER_TYPE_DUAL        1UL
#define FILTER_TYPE_CLASSIC     2UL
#define FILTER_TYPE_DISABLE     3UL
/* FILTER CONFIG */
#define FILTER_CFG_DISABLED     0UL
#define FILTER_CFG_STORE_FIFO_0 1UL
#define FILTER_CFG_STORE_FIFO_1 2UL
#define FILTER_CFG_REJECT       3UL
unsigned long *ptr = (unsigned long*)FCCAN_29B_FILTER_START_ADDR;
*ptr++ = (FILTER_CFG_STORE_FIFO_0 << 29) | (CAN_TEST_ID_0);
*ptr++ = (FILTER_TYPE_DUAL        << 30) | (CAN_TEST_ID_1);
// И так далее по списку фильтров.
В данном примере настроен один элемент расширенных фильтров в двойном режиме.12) Настраиваем приёмный буфер FIFO 0. Смещение относительно начала выделенной памяти и количество элементов:
// Rx FIFO 0
#define FDCAN_RX_FIFO_0_EL_CNT        10
#define FDCAN_RX_FIFO_0_HEAD_SIZE     8UL
#define FDCAN_RX_FIFO_0_DATA_SIZE     8UL
#define FDCAN_RX_FIFO_0_EL_SIZE       (FDCAN_RX_FIFO_0_HEAD_SIZE   + FDCAN_RX_FIFO_0_DATA_SIZE)
#define FDCAN_RX_FIFO_0_EL_W_SIZE     (FDCAN_RX_FIFO_0_EL_SIZE / 4)
#define FDCAN_RX_FIFO_0_START_ADDR    (FCCAN_29B_FILTER_START_ADDR + FDCAN_29B_FILTER_EL_CNT * FDCAN_29B_FILTER_EL_SIZE)
#define FDCAN_RX_FIFO_0_OFFSET        (FDCAN_29B_FILTER_OFFSET     + FDCAN_29B_FILTER_EL_CNT * FDCAN_29B_FILTER_EL_W_SIZE)
FDCAN1->RXF0C  = FDCAN_RX_FIFO_0_OFFSET << FDCAN_RXF0C_F0SA_Pos;
FDCAN1->RXF0C |= FDCAN_RX_FIFO_0_EL_CNT << FDCAN_RXF0C_F0S_Pos;
13) Настраиваем буфер отправки сообщений. Режим буфера = FIFO. Если режим указан, как очередь, то сообщения отправляются согласно идентификаторам (больше идентификатор - быстрее отправится).
// TX buffers (FIFO)
#define FDCAN_TX_FIFO_EL_CNT          10UL
#define FDCAN_TX_FIFO_HEAD_SIZE       8UL
#define FDCAN_TX_FIFO_DATA_SIZE       8UL
#define FDCAN_TX_FIFO_EL_SIZE         (FDCAN_TX_FIFO_HEAD_SIZE + FDCAN_TX_FIFO_DATA_SIZE)
#define FDCAN_TX_FIFO_EL_W_SIZE       (FDCAN_TX_FIFO_EL_SIZE / 4)
#define FDCAN_TX_FIFO_START_ADDR      (FDCAN_TX_EVENT_START_ADDR + FDCAN_TX_EVENT_FIFO_EL_CNT * FDCAN_TX_EVENT_FIFO_EL_SIZE)
#define FDCAN_TX_FIFO_OFFSET          (FDCAN_TX_EVENT_OFFSET     + FDCAN_TX_EVENT_FIFO_EL_CNT * FDCAN_TX_EVENT_FIFO_EL_W_SIZE)
FDCAN1->TXBC &= ~(FDCAN_TXBC_TFQM); // FIFO operation
FDCAN1->TXBC |= FDCAN_TX_FIFO_EL_CNT << FDCAN_TXBC_TFQS_Pos;
FDCAN1->TXBC |= FDCAN_TX_FIFO_OFFSET << FDCAN_TXBC_TBSA_Pos;
13) Включаем прерывание модуля fdcan по приёму пакета:
FDCAN1->IE |= FDCAN_IE_RF0NE;
FDCAN1->ILE |= FDCAN_ILE_EINT0;
14) Выходим из режима инициализации и включаем прерывание в NVIC.
FDCAN1->CCCR &= ~(FDCAN_CCCR_INIT);
while ((FDCAN1->CCCR & FDCAN_CCCR_INIT) == 1) {};
NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
__enable_irq();
На этом инициализация закончена.Чтение сообщения из выделенной памяти.Для удобства создадим структуру нашего can пакета и структуру для удобного доступа к элементам выделенной памяти.
struct can_message
{
  unsigned char error;
  unsigned long id;
  unsigned char data[8];
  unsigned char length;
  unsigned char format;
  unsigned char type;
};
struct can_fifo_element
{
  unsigned long word0;
  unsigned long word1;
  unsigned long word2;
  unsigned long word3;
};
Функция чтение пакета (кадра) из выделенной памяти:
#define CAN_STANDARD_FORMAT     0UL
#define CAN_EXTENDED_FORMAT     1UL
#define DATA_FRAME              0UL
#define REMOTE_FRAME            1UL
struct can_message can_rx_message;
struct can_message can_tx_message;
void FDCAN1_read_msg (struct can_message* msg, unsigned char idx)
{
  struct can_fifo_element *fifo;
  // присваиваем адрес нашей структуре
  fifo = (struct can_fifo_element*)(FDCAN_RX_FIFO_0_START_ADDR + idx * FDCAN_RX_FIFO_0_EL_SIZE);
  // парсим поля
  msg->error   = (unsigned char)((fifo->word0 >> 31) & 0x01);
  msg->format  = (unsigned char)((fifo->word0 >> 30) & 0x01);
  msg->type    = (unsigned char)((fifo->word0 >> 29) & 0x01);
  // тип идентификатора
  if (msg->format == CAN_EXTENDED_FORMAT)
  {
    msg->id = fifo->word0 & 0x1FFFFFFF;
  }
  else
  {
    msg->id = (fifo->word0 >> 18) & 0x7FF;
  }
  // длина данных
  msg->length  = (unsigned char)((fifo->word1 >> 16) & 0x0F);
  // данные
  msg->data[0] = (unsigned char)((fifo->word2 >>  0) & 0xFF);
  msg->data[1] = (unsigned char)((fifo->word2 >>  8) & 0xFF);
  msg->data[2] = (unsigned char)((fifo->word2 >> 16) & 0xFF);
  msg->data[3] = (unsigned char)((fifo->word2 >> 24) & 0xFF);
  msg->data[4] = (unsigned char)((fifo->word3 >>  0) & 0xFF);
  msg->data[5] = (unsigned char)((fifo->word3 >>  8) & 0xFF);
  msg->data[6] = (unsigned char)((fifo->word3 >> 16) & 0xFF);
  msg->data[7] = (unsigned char)((fifo->word3 >> 24) & 0xFF);
}
Для чтения принятого пакета мы подставляем в функцию FDCAN1_read_msg наш can_rx_message и номер в буфере приёма.Саму же функцию мы вызываем в прерывании. По хорошему так делать нельзя и лучше в прерывании возводить флаг нового сообщения, а потом в основном цикле (или задаче RTOS) считывать сам пакет, но для простого тестирования будем делать именно так.Обработчик прерывания от модуля fdcan:
void FDCAN1_IT0_IRQHandler(void)
{
  unsigned char rx_fifo_get_index;
  // новое сообщение получено
  if((FDCAN1->IR & FDCAN_IR_RF0N) != 0)
  {
    // очищаем флаг
    FDCAN1->IR = FDCAN_IR_RF0N;
    // берём индекс нового пакета в буфере
    rx_fifo_get_index = (unsigned char)((FDCAN1->RXF0S >> 8) & 0x3F);
    // читаем пакет
    FDCAN1_read_msg (&can_rx_message, rx_fifo_get_index);
    // обновляем индекс прочитанных пакетов
    FDCAN1->RXF0A = rx_fifo_get_index;
  };
  // сообщение потеряно в случае переполнения
  if((FDCAN1->IR & FDCAN_IR_RF0L) != 0)
  {
    // очищаем флаг
    FDCAN1->IR = FDCAN_IR_RF0L;
  };
  // буфер RX FIFO переполнен
  if((FDCAN1->IR & FDCAN_IR_RF0F) != 0)
  {
    // do something
  };
}
После того, как мы прочитали новый пакет, нужно обновить индекс (указатель) подтверждения считывания пакета RXF0A.Буфер приёма сообщений RX FIFOМаксимальная длина элемента RX FIFO при использовании нового fdcan равна 18 слов (4 байта * 18 = 72 байта). Это 2 слова на заголовок и 16 слов на данные, что даёт 64 байта данных. При использовании стандартного CAN (8 байт данных) максимальная длина элемента равна 4 слова (4 байта * 4 = 16 байт).
Структура элемента буфера приёмаESI (R0 bit 31)Индикатор ошибки узла 0: Transmitting node is error active 1: Transmitting node is error passiveXTD (R0 bit 30)0: 11-bit стандартный идентификатор.1: 29-bit расширенный идентификатор.RTR (R0 bit 29)0: Получен пакет с данными.1: Получен пакет удалённого запроса (remote frame).ID (R0 bits 28:0)Идентификатор. В случаем стандартного, идентификатор начинается с 18-го бита [28:18].ANMF (R1 bit 31)0: Получен валидный пакет прошедший фильтрацию. Один из фильтров совпал.1: Получен пакет не прошедший фильтрацию.FIDX (R1 bits 30:24)Индекс фильтра пропустившего пакет.FDF (R1 bit 21)0: Стандартный формат пакета.1: Новый формат (fdcan) пакета. Новая кодировка DLC и CRC.BRS (R1 bit 20)0: Пакет без смены битрейта фазы данных.1: Пакет со сменой битрейта фазы данных.DLC (R1 bits 19:16)0-8: Классический CAN + CAN FD: пакет содержит от 0 до 8 байт.9-15: Классический CAN: пакет содержит 8 байт.9-15: CAN FD: полученный пакет содержит 12/16/20/24/32/48/64 байт данных.RXTS (R1 bits 15:0)Счётчик метки времени.DBxБайты данных.Немного подробнее о кодировании поля DLC:
Кодирование поля DLCДумаю, что тут всё понятно и без объяснений.Буфер отправки сообщений TX FIFOМаксимальная длина элемента TX FIFO при использовании нового fdcan равна 18 слов (4 байта * 18 = 72 байта). Это 2 слова на заголовок и 16 слов на данные, что даёт 64 байта данных. При использовании стандартного CAN (8 байт данных) максимальная длина элемента равна 4 слова (4 байта * 4 = 16 байт).
Структура элемента буфера отправкиESI (T0 bit 31)Флаг ошибки:0: ESI бит CAN FD зависит от ошибки (error passive flag)1: ESI бит CAN FD передаётся рецессивным.XTD (T0 bit 30)0: 11-bit стандартный идентификатор.1: 29-bit расширенный идентификатор.RTR (T0 bit 29)0: Пакет с данными.1: Пакет удалённого запроса (remote frame).ID (T0 bits 28:0)Идентификатор. В случаем стандартного, идентификатор начинается с 18-го бита [28:18].MM (T1 bits 31:24)Маркер сообщения.EFC (T1 bit 23)0: Не сохранять событие в TX event fifo.1: Сохранить событие в TX event fifo.FDF (T1 bit 21)0: Стандартный формат пакета.1: Новый формат (fdcan) пакета. Новая кодировка DLC и CRC.BRS (T1 bit 20)0: Пакет без смены битрейта фазы данных.1: Пакет со сменой битрейта фазы данных.DLC (T1 bits 19:16)0-8: Классический CAN + CAN FD: пакет содержит от 0 до 8 байт.9-15: Классический CAN: пакет содержит 8 байт.9-15: CAN FD: полученный пакет содержит 12/16/20/24/32/48/64 байт данных.DBxБайты данных.Отправка сообщенийЗаполняем структуру нашего пакета, конкретно в нашем случаем мы отправляем пакет обычного can (не fdcan) с 8-мю байтами данных, и скармливаем его функции FDCAN1_send_msg. Функция заполняет нужные поля элемента TX FIFO и отправляет пакет.
#define CAN_STANDARD_FORMAT     0UL
#define CAN_EXTENDED_FORMAT     1UL
#define DATA_FRAME              0UL
#define REMOTE_FRAME            1UL
// Заполняем поля пакета
can_tx_message.id      = 1;
can_tx_message.format  = CAN_EXTENDED_FORMAT;
can_tx_message.type    = DATA_FRAME;
can_tx_message.length  = 10;
can_tx_message.data[0] = 20;
can_tx_message.data[1] = 30;
can_tx_message.data[2] = 40;
can_tx_message.data[3] = 50;
can_tx_message.data[4] = 60;
can_tx_message.data[5] = 70;
can_tx_message.data[6] = 80;
can_tx_message.data[7] = 90;
void FDCAN1_send_msg (struct can_message *msg)
{
  struct can_fifo_element *fifo;
  unsigned char tx_index;
  // проверка буфера
  if ((FDCAN1->TXFQS & FDCAN_TXFQS_TFQF) != 0)
  {
    // буфер переполнен
  }
  // берём следующий свободный индекс
  tx_index = (FDCAN1->TXFQS >> 16) & 0xF;
  // присваиваем нашей fifo структуре адрес в буфере
  fifo = (struct can_fifo_element *)(FDCAN_TX_FIFO_START_ADDR + tx_index * FDCAN_TX_FIFO_EL_SIZE);
  //идентификатор пакета STD или EXT
  if (msg->format == CAN_STANDARD_FORMAT)
  {
    fifo->word0 = (msg->id << 18);
  }
  else
  {
    fifo->word0 = msg->id;
    fifo->word0 |= 1UL << 30; // extended flag
  }
  // кадр удалённого запроса
  if (msg->type == REMOTE_FRAME) fifo->word0 |= 1UL << 29;
  // количество байт данных
  fifo->word1 = (8UL << 16);  //Data size
  // данные
  fifo->word2 = (msg->data[3] << 24)|(msg->data[2] << 16)|(msg->data[1] << 8)|msg->data[0];
  fifo->word3 = (msg->data[7] << 24)|(msg->data[6] << 16)|(msg->data[5] << 8)|msg->data[4];
  // увеличиваем индекс и запускаем передачу пакета
  FDCAN1->TXBAR |= (1UL << tx_index);
}
ЗаключениеВ целом, по сравнению с BxCAN, ничего сложного нету. Можно разобраться и без cubemx за пару вечеров. Если у вас что-то не заработало, то в первую очередь проверьте тактирование модуля. При неправильной настройке, у вас не будет срабатывать выход из режима инициализации. Так же можно включить режим loopback, чтобы убедиться, что ваш код полностью рабочий, а проблема возможно дальше на самой линии can. Полный код на гитхабе
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_programmirovanie_mikrokontrollerov (Программирование микроконтроллеров), #_diy_ili_sdelaj_sam (DIY или Сделай сам), #_stm32, #_can, #_fdcan, #_programmirovanie (программирование), #_cmsis, #_cortex_m, #_programmirovanie_mikrokontrollerov (
Программирование микроконтроллеров
)
, #_diy_ili_sdelaj_sam (
DIY или Сделай сам
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 10-Май 20:08
Часовой пояс: UTC + 5