STM32H750 更好用的CANFD 用例详解

前言

参考前几篇:

STM32H7系列的FDCAN目前最大也支持3路, 如STM32H730/723/725/733/735等, Message RAM也是最大10KB=2560words, RAM资源每路分配可以不一样.

先来回顾下STM32G474的FDCAN在Cube中的配置:

  • 标准帧滤波器最大设置28
  • 扩展帧滤波器最大设置8, PPT中却号称28…
  • RxFIFO元素数量不能设置, 生成代码中默认3, 疑似祖传自bxCAN
  • TxFIFO/Queue元素数量不能设置, 生成代码中默认3, 疑似祖传自bxCAN
  • 3路RAM大小一致, 不能手动设置Message Ram Offset
  • Rx/Tx元素的最大有效字节不能设置, 默认取最高64字节

这明显是虚假的FDCAN, 真实的FDCAN应该更灵活, STM32H7它来了, Cube配置更符合PPT中的参数:

  • 标准帧滤波器数量最大设置128, 所有FDCAN的标准帧滤波器数量之和不超过这个数即可
  • 扩展帧滤波器数量最大设置64, 所有FDCAN的扩展帧滤波器数量之和不超过这个数即可
  • RxFIFO0元素数量最大设置64, 所有FDCAN的RxFIFO0数量之和不超过这个数即可, RxFIFO1也有另外64个
  • RxFIFO0元素Data Field Size可以在[8, 12, 16, 20, 24, 32, 48, 64]中选择, 根据具体使用, 不必非要设置最大64字节
  • TxFIFO/Queue元素数量最大设置32, 所有FDCAN的TxFIFO/Queue数量之和不超过这个数即可
  • TxFIFO元素Data Field Size可以在[8, 12, 16, 20, 24, 32, 48, 64]中选择, 根据具体使用, 不必非要设置最大64字节
  • 可以手动设置Message Ram Offset了, 一般FDCAN1设置为0, FDCAN2根据上面的元素占用大小往后偏移, FDCAN3再递推, 只要所有FDCAN外设的RAM占用总和不超过10KB即可.

本篇用的出名较早的STM32H750VBT6, 最大只支持2路FDCAN, 虽然少, 但每路分到的RAM资源可以多一点. 相比STM32G474, STM32H7在STM32CubeMX中的分配更加灵活了.

依然是:

  • 仲裁段500Kbit/s, 采样点0.8
  • 数据段2Mbit/s, 采样点0.75

STM32H750的FDCAN连到Xavier CAN1上, CAN收发器均选用支持2M及以上CANFD的收发器,各自接上120Ω终端电阻.

USART3到PC用STLINK连接.

可以参考 ST官方的STM32H7-FD-CAN

Message RAM分配

回顾下STM32的CAN Message RAM mappings, 这个是支持的最大的元素数量:

在这里插入图片描述

下面会用到的参数总结如下:

  • 1 个 11-bit filter element => 1 words, 所有FDCAN的11-bit filter element数量之和不超过128
  • 1 个 29-bit filter element => 2 words, 所有FDCAN的29-bit filter element数量之和不超过64
  • 1 个 Rx FIFO 0 element => 18 words, 所有FDCAN的Rx FIFO 0 element数量之和不超过64
  • 1 个 Tx Buffer element => 18 words, 所有FDCAN的Tx Buffer element数量之和不超过32

有人说, 简单点, 少点套路多点诚意, 全部启用不好么, 不行, 如果全部元素都启用, 将占用 128 + 128 + 1152 + 1152 + 1152 + 64 + 576 + 128 = 4480 words = 17920 Bytes = 17.5KB, 超过了10KB = 2560 words的最大Ram限制. 所以还是要有所取舍, 用到的分配, 不用的不分配.

接着搞懂这Cube中这两张FDCAN分配图就可以了, 第一张是FDCAN1的, 第二张是FDCAN2的:

在这里插入图片描述

在这里插入图片描述

这里FDCAN1和FDCAN2资源都是对半分的, 都用了992words, 其实也可以不对半, 比如FDCAN1发送ID很多, FDCAN2只接收不发送, 那完全可以把FDCAN1的Tx Fifo Queue Elmts Nbr设置为32, FDCAN2设置为0. 这样FDCAN1一口气发32帧也不会丢帧. 相应的, FDCAN2的Message Ram Offset做相应更改.

这里FDCAN1, FDCAN2都用了RxFIFO0, 没有用RxFIFO1, 也是可以FDCAN1独占64个RxFIFO0元素, 然后FDCAN2独占64个RxFIFO1元素.

实际的Message Ram分配如图:

在这里插入图片描述

FDCAN1 RAM的实际起始地址为 0x4000AC00, FDCAN2 RAM的实际起始地址为 0x4000AC00 + 992 * 4 = 0x4000BB80.

接下来开始干活.

STM32工程搭建

STM32CubeMX配置步骤如下:

  • MCU选择: 打开 STM32CubeMX, 点击 ACCESS TO MCU SELECTOR, 选择 STM32H750VBTx

  • 调试端口配置为SWD: Pinout & Configuration -> Trace and Debug -> DEBUG, Debug 选择 Serial Wire, STM32H系列的Cube Debug位置与其它系列不同.

  • Pinout & Configuration -> System Core -> RCC -> HSE 选择 Crystal/Ceramic Resonator

  • Clock Configuration(我板子上用的外部25M晶振, 主频配置成480MHz, FDCAN主时钟是80MHz): 在这里插入图片描述
    在这里插入图片描述

  • 开启100us定时器中断, 有datasheet的Figure 1. STM32H750xB block diagram可知, TIM6挂载在APB1上, 上面时钟树APB1 Timer Clocks是240MHz: Pinout & Configuration -> Timers -> TIM6 -> 勾选Activated, Prescaler设置为240-1, Counter Period设置为100-1 -> 勾选TIM6中断: 在这里插入图片描述

在这里插入图片描述

  • USART3配置: Pinout & Configuration -> Connectivity -> USART3 -> Mode选择异步Asynchronous, 关闭 OverrunDMA on RX Error, 波特率配置为2M-8-N-1, 并把IO调整到板子上用的PD8, PD9: 在这里插入图片描述

  • FDCAN1配置: Pinout & Configuration -> Connectivity -> FDCAN1, Mode选择FD, Frame Format设置FD mode with BirRate Switshing启用位速率变换, Auto Retransmission设置为Enable开启自动重传, Trasmit Pause设置为Enable开启传输暂停, 速率和采样点设置参考上一篇 STM32 CANFD 基础知识位时间和采样点小节, Nominal仲裁段设置500Kbit/s(80M/NPre/(1+NTSeg1+NTSeg2) = 80M/2/(1+63+16) = 500Kbit/s), 采样点0.8((1+NTSeg1)/(1+NTSeg1+NTSeg2)=64/80=0.8); Data数据段设置为2Mbit/s((80M/DPre/(1+DTSeg1+DTSeg2) = 80M/2/(1+63+16) = 500Kbit/s)), 采样点0.75((1+DTSeg1)/(1+DTSeg1+DTSeg2)=15/20=0.75), Std Filter Nbr标准帧过滤器数量直接设为最大64, Ext Filters Nbr扩展帧滤波器数量直接设为最大32(虽然后面并没有全用上), Rx Fifo0 Elmts Nbr数量设置为32, Size也设置64 bytes data field, Tx Fifo16,FIFO mode, 64 bytes data field; 勾选FDCAN1 interrupt 0中断, 引脚也从默认调整到板子上用的引脚PD0/PD1; FDCAN2除了Messge Ram Offset外, 其它与FDCAN1一致, 引脚从默认调整到板子上用的引脚PB5/PB6: 在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • Project Manager -> Project -> Browse 选择工程位置(Project Location), 填入工程名(Project Name), Toolchain/IDE 选择 MDK-ARM, 把Minimum Heap Size改为0x2000, Minimum Stack Size改为0x2000.

  • Project Manager -> Code Generator -> 勾选Copy only the necessary library files, 还有Generate peripheral initialization as a pair of .c/.h files per periphral

  • 点击右上角 GENERATE CODE 按钮生成代码, 点击Open Project按钮打开工程.

MPU, Dcache, Icache是Cortex-M7新增的东西, 例程一般会打开cache, 在System Core -> CORTEX_M7里面使能两个Cache, 这里不设置暂不影响使用, 我们先不管它.

Keil配置, Keil 点击魔术棒或者Project -> Options for Target ..., 默认配置DebugST-link Debugger, 点击Setting:

  • Flash Download选项卡 -> 勾选Reset and Run, 这样下载后可以自动复位运行.
  • Pack选项卡, 去掉默认的Enable勾选

切换到Target选项卡, 勾选Use MicroLIB, 不晓得为什么H7的Cube每次生成的代码这个都没有勾选, 导致只能仿真运行, 实际却不运行的尴尬局面, 每次得手动勾选上这个才解决.

到此配置结束. 下面是手动添加的代码详解.

串口配置

为 USART3 添加printf支持, 这个与其他系列的MCU稍有不同:

#include <stdio.h>

int fputc(int ch,FILE *f)
{
    HAL_UART_Transmit(&huart3,(uint8_t *)&ch,1,100);     
    return 0;
}

100us定时器

因为用最大64字节测试的, 实测只发送的情况下, 1s传输最多约2500帧, 再多就丢帧了, 也就是400us/帧, 保守一点, 这里设置500us传一帧, 如果没传出去, 有重传的机会. 为了准确点, 这里取100us:

/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim6);  //Starts the TIM Base generation in interrupt mode.
/* USER CODE END 2 */

uint8_t tim6_flag = 0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) 
{
    if(htim->Instance == TIM6) {
        tim6_flag = 1;
    }
}

FDCAN配置

主要是标准帧滤波器, 扩展帧滤波器设置, 开启新消息接收中断, 开启Bus-Off中断, 设置发送传输延时补偿等.

FDCAN_FilterTypeDef sFilterConfig1;

void fdcan1_config(void)
{
  sFilterConfig1.IdType = FDCAN_STANDARD_ID;
  sFilterConfig1.FilterIndex = 0;
  sFilterConfig1.FilterType = FDCAN_FILTER_MASK;
  sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  sFilterConfig1.FilterID1 = 0;
  sFilterConfig1.FilterID2 = 0;
  HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig1);

  sFilterConfig1.IdType = FDCAN_EXTENDED_ID;
  sFilterConfig1.FilterIndex = 0;
  sFilterConfig1.FilterType = FDCAN_FILTER_MASK;
  sFilterConfig1.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  sFilterConfig1.FilterID1 = 0;
  sFilterConfig1.FilterID2 = 0;
  HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig1);   
  
  /* Configure global filter to reject all non-matching frames */
  HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE);
  
  /* Configure Rx FIFO 0 watermark to 2 */
  //HAL_FDCAN_ConfigFifoWatermark(&hfdcan1, FDCAN_CFG_RX_FIFO0, 2);

  /* Activate Rx FIFO 0 new message notification on both FDCAN instances */
  HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);

  HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_BUS_OFF, 0);

  /* Configure and enable Tx Delay Compensation, required for BRS mode.
        TdcOffset default recommended value: DataTimeSeg1 * DataPrescaler
        TdcFilter default recommended value: 0 */
  HAL_FDCAN_ConfigTxDelayCompensation(&hfdcan1, hfdcan1.Init.DataPrescaler * hfdcan1.Init.DataTimeSeg1, 0);
  HAL_FDCAN_EnableTxDelayCompensation(&hfdcan1);

  HAL_FDCAN_Start(&hfdcan1);
}

这里设置了用一个标准帧滤波器设置了标准帧的全接收, 用一个扩展帧滤波器设置了扩展帧的全接收, 用的掩码的方式设置全接收.

收到的消息扔到RxFIFO0中, 设置了RxFIFO0的新消息来的中断.

这里程序中滤波器只各用了一个(index = 0), 如果想用更多, 递增index, 最多不超过各自设置的Nbr.

FDCAN2的配置和FDCAN1类似.

Bus-Off处理

如果CANH, CANL短接, 或者和其它节点的传输速率/采样点不一致, 会引发Bus-Off, 上面开启了Bus-Off中断, 发生Bus-Off时, 直接在中断中初始化FDCAN外设:

void HAL_FDCAN_ErrorStatusCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t ErrorStatusITs)
{
  //__HAL_FDCAN_CLEAR_FLAG(hfdcan, FDCAN_FLAG_BUS_OFF);
  if(hfdcan->Instance == FDCAN1) {
    MX_FDCAN1_Init();
    fdcan1_config();
  } else if(hfdcan->Instance == FDCAN2) {
    MX_FDCAN2_Init();
    fdcan2_config();
  } else {
  }
}

新消息接收处理

直接把接收的消息通过2M波特率的串口打印出来.

FDCAN_RxHeaderTypeDef RxHeader1;

uint8_t RxData1[64];
uint8_t RxData2[64];

0xF0000 => 64
uint8_t dlc2len[]={0,1,2,3,4,5,6,7,8,12,16,20,24,32,48,64};
uint8_t can_dlc2len(uint32_t RxHeader_DataLength)
{
  return dlc2len[RxHeader_DataLength>>16];
}

uint8_t cnt = 0;
uint8_t brs[] = {'-', 'B'};
uint8_t esi[] = {'-', 'E'};
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
{
  if((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != 0) {

    //memset(&RxHeader1, 0, sizeof(FDCAN_RxHeaderTypeDef));	//if use, lose frame
        
    HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader1, RxData1);
    if (hfdcan->Instance == FDCAN1) {
      printf("fdcan1, ");
    } else if (hfdcan->Instance == FDCAN2) { 
      printf("fdcan2, ");
    } else {
    }
    printf("0x%8X, %02d, %c, %c:",RxHeader1.Identifier, 
                                  can_dlc2len(RxHeader1.DataLength), 
                                  brs[RxHeader1.BitRateSwitch>>20 & 0x1],
                                  esi[RxHeader1.ErrorStateIndicator>>31 & 0x1]);
    for(cnt = 0; cnt < can_dlc2len(RxHeader1.DataLength); cnt++) {
      printf(" %02X", RxData1[cnt]);
    }
    printf("\n\r");
  }
}

注意 RxHeader.DataLength => can_dlc 的对应关系.

示例如图:

在这里插入图片描述

图中消息来自fdcan1, can_id为0x18FF000x, 64字节数据, 开启了BRS和ESI, :后面是64字节的十六进制数据.

printf还是比较耗时间的, 这里仅做低负载下的演示, 实际使用不建议中断中这么搞.

发送处理

发送开启了BRS和ESI, 如果发送失败, 有重发机会.

#include <string.h>

FDCAN_TxHeaderTypeDef TxHeader1;

uint8_t TxData1[64];

typedef struct {
  uint8_t flag;
  uint8_t index;
  FDCAN_TxHeaderTypeDef TxHeader[16];
  uint8_t TxData[64*16];
} FDCAN_SendFailTypeDef;

FDCAN_SendFailTypeDef fdcan1_send_fail = {0};

void fdcan1_transmit(uint32_t can_id, uint32_t DataLength, uint8_t tx_data[])
{
  TxHeader1.Identifier = can_id;
  TxHeader1.IdType = FDCAN_EXTENDED_ID;
  if(can_id < 0x800) {  //exactly not right
    TxHeader1.IdType = FDCAN_STANDARD_ID;
  }
  TxHeader1.TxFrameType = FDCAN_DATA_FRAME;
  TxHeader1.DataLength = DataLength;
  TxHeader1.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
  TxHeader1.BitRateSwitch = FDCAN_BRS_ON;
  TxHeader1.FDFormat = FDCAN_FD_CAN;
  TxHeader1.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
  TxHeader1.MessageMarker = 0;  //Tx Event FIFO Use
  if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader1, tx_data) != HAL_OK) {
    memcpy(&fdcan1_send_fail.TxHeader[fdcan1_send_fail.index], &TxHeader1, sizeof(FDCAN_TxHeaderTypeDef));
    memcpy(&fdcan1_send_fail.TxData[64*fdcan1_send_fail.index], tx_data, can_dlc2len(DataLength));
    fdcan1_send_fail.index = (fdcan1_send_fail.index + 1) & 0x0F;  //0~15
    fdcan1_send_fail.flag = 1;
  } 
}

int main(void)
{
  ...
  
  /* USER CODE BEGIN 2 */
  fdcan1_config();
  fdcan2_config();
  
  for(uint8_t i = 0; i < 64; i++) {
    TxData1[i] = i;
    TxData2[i] = i;
  }

  HAL_TIM_Base_Start_IT(&htim6);

  uint32_t count = 0;
  uint32_t cnt_100us = 0;
  uint32_t cnt_500us = 0;
  uint32_t i = 0;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

    if(tim6_flag && count < 1000) {
      tim6_flag = 0;
      TxData1[0] = count >> 8 & 0xFF;
      TxData1[1] = count & 0xFF;

      ++cnt_100us;
      cnt_500us = cnt_100us / 5;
      if(cnt_500us && (cnt_100us%5==0) ) {
        switch(cnt_500us) {
          case 1: fdcan1_transmit(0x108, FDCAN_DLC_BYTES_64, TxData1); 
                   fdcan1_transmit(0x101, FDCAN_DLC_BYTES_64, TxData1);
                   fdcan1_transmit(0x102, FDCAN_DLC_BYTES_64, TxData1);
                   fdcan1_transmit(0x103, FDCAN_DLC_BYTES_64, TxData1);
                   fdcan1_transmit(0x104, FDCAN_DLC_BYTES_64, TxData1);
                   fdcan1_transmit(0x105, FDCAN_DLC_BYTES_64, TxData1);
                   fdcan1_transmit(0x106, FDCAN_DLC_BYTES_64, TxData1);
                   fdcan1_transmit(0x107, FDCAN_DLC_BYTES_64, TxData1);
                   fdcan1_transmit(0x12345678, FDCAN_DLC_BYTES_64, TxData1);
                   fdcan1_transmit(0x12345671, FDCAN_DLC_BYTES_64, TxData1);
                   fdcan1_transmit(0x12345672, FDCAN_DLC_BYTES_64, TxData1);
                   fdcan1_transmit(0x12345673, FDCAN_DLC_BYTES_64, TxData1);
                   fdcan1_transmit(0x12345674, FDCAN_DLC_BYTES_64, TxData1);
                   fdcan1_transmit(0x12345675, FDCAN_DLC_BYTES_64, TxData1);
                   fdcan1_transmit(0x12345676, FDCAN_DLC_BYTES_64, TxData1);
                   fdcan1_transmit(0x12345677, FDCAN_DLC_BYTES_64, TxData1); 
                   break;
          case 17: /* next send */ break;
          case 18: break;
          case 19: break;
          case 20: ++count; cnt_100us = 0; break; //10ms
        }
      } else {  //fail retransmission once

        if(fdcan1_send_fail.flag && cnt_500us > 16) {  //can't conflict with normal send
          for(i = 0; i < fdcan1_send_fail.index; i++) {
            fdcan1_transmit(fdcan1_send_fail.TxHeader[i].Identifier, 
                            fdcan1_send_fail.TxHeader[i].DataLength,
                            &fdcan1_send_fail.TxData[64*i]);
          }
          fdcan1_send_fail.index = 0; 
          fdcan1_send_fail.flag = 0;  //maybe send 4 times or more
        }

        if(fdcan2_send_fail.flag && cnt_500us > 16) {
          for(i = 0; i < fdcan2_send_fail.index; i++) {
            fdcan2_transmit(fdcan2_send_fail.TxHeader[i].Identifier, 
                            fdcan2_send_fail.TxHeader[i].DataLength,
                            &fdcan2_send_fail.TxData[64*i]);
          }
          fdcan2_send_fail.index = 0;
          fdcan2_send_fail.flag = 0;
        }

      }
    }

  }
  /* USER CODE END 3 */
}

fdcan2和fdcan1的发送类似, 2个发送函数可以合并成一个, 这里没有合并.

发送函数中的DataLength指的是类似FDCAN_DLC_BYTES_64这种的宏定义, 而不是数字64.

这里用can_id < 0x800只是为了简便, 其实不正确, 这种情况下也有可能是扩展帧, 但通常不会这么用.

因为发送最多可以缓存16帧, 所以可以一口气发送16帧而不会丢帧, 如case 1处, 也可以一帧一帧发送, 如case 2, case 3, case 4… 大概6ms/16帧或者500us/帧.

因为总线中还有其他节点发送之类的, 有可能发送失败, 发送失败后重传的机会, 具体情况根据现场可另行调整.

如果fdcan1, fdcan2没有在一个网络中, 可以一口气 fdcan1发送16帧 + fdcan2发送16帧, 或者把32都给fdcan1的Nbr, 这样可以一口气发32帧不丢帧.

一般车辆总线中发送都是最快10ms内把要发的不同ID的数据一股脑发出去(当然也有20ms, 50ms, 100ms周期的数据这里暂不考虑), 所以这里100us中断计数100次就是10ms.

程序中发送1000*16=16000帧后停止发送, 10ms发16帧, 所以10s后数据就发完了.

使用Xavier配合测试一下

把STM32的FDCAN1连到Xavier的CAN1上, Xavier CAN1设置:

#!/bin/sh

sudo modprobe can
sudo modprobe can_raw
sudo modprobe mttcan

sudo ip link set down can0
sudo ip link set can0 type can bitrate 500000 sample-point 0.8 dbitrate 2000000 dsample-point 0.75 fd on restart-ms 100
sudo ip link set up can0 
sudo ifconfig can0 txqueuelen 1000

sudo ip link set down can1
sudo ip link set can1 type can bitrate 500000 sample-point 0.8 dbitrate 2000000 dsample-point 0.75 fd on restart-ms 100
sudo ip link set up can1
sudo ifconfig can1 txqueuelen 1000

Xavier也是仲裁段500Kbit/s, 采样点0.8, 数据段2Mbit/s, 采样点0.75.

restart-ms 100设置总线Bus-Off时, 100ms后重启.

设置完后查看设置状态 ip -details -statistics link show can1:

$ ip -details -statistics link show can1
6: can1: <NOARP,UP,LOWER_UP,ECHO> mtu 72 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000
    link/can  promiscuity 0 
    can <FD> state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 100 
          bitrate 498701 sample-point 0.792 
          tq 26 prop-seg 30 phase-seg1 30 phase-seg2 16 sjw 1
          mttcan: tseg1 2..255 tseg2 0..127 sjw 1..127 brp 1..511 brp-inc 1
          dbitrate 2021052 dsample-point 0.736 
          dtq 26 dprop-seg 6 dphase-seg1 7 dphase-seg2 5 dsjw 1
          mttcan: dtseg1 1..31 dtseg2 0..15 dsjw 1..15 dbrp 1..15 dbrp-inc 1
          clock 38400000
          re-started bus-errors arbit-lost error-warn error-pass bus-off
          0          0          0          13         20         0         numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 
    RX: bytes  packets  errors  dropped overrun mcast   
    64578440   1013451  0       0       0       0       
    TX: bytes  packets  errors  dropped carrier collsns 
    952448     15914    0       0       0       0    

位速率和采样点的些许误差测试并无影响.

使用 candump -ta -x can1 >32.dat, 这里-ta显示绝对时间, 然后下载STM32程序运行, 上面的16000帧数据全部存到32.dat文件中了, 共计16000行这里截取首尾部分显示:

 (1614077476.632584)  can1  RX B -  108  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077476.632961)  can1  RX B -  101  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077476.633393)  can1  RX B -  102  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077476.633754)  can1  RX B -  103  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077476.634198)  can1  RX B -  104  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077476.634558)  can1  RX B -  105  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077476.634952)  can1  RX B -  106  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077476.635348)  can1  RX B -  107  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077476.635782)  can1  RX B -  12345678  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077476.636217)  can1  RX B -  12345671  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077476.636641)  can1  RX B -  12345672  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077476.637075)  can1  RX B -  12345673  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077476.637509)  can1  RX B -  12345674  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077476.638000)  can1  RX B -  12345675  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077476.638380)  can1  RX B -  12345676  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077476.638811)  can1  RX B -  12345677  [64]  00 00 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077476.642570)  can1  RX B -       108  [64]  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 

 ... 

 (1614077486.617982)  can1  RX B E  12345677  [64]  03 E6 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077486.622256)  can1  RX B E       108  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077486.622604)  can1  RX B E       101  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077486.622959)  can1  RX B E       102  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077486.623405)  can1  RX B E       103  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077486.623687)  can1  RX B E       104  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077486.624052)  can1  RX B E       105  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077486.624416)  can1  RX B E       106  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077486.624781)  can1  RX B E       107  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077486.625178)  can1  RX B E  12345678  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077486.625578)  can1  RX B E  12345671  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077486.625982)  can1  RX B E  12345672  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077486.626377)  can1  RX B E  12345673  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077486.626777)  can1  RX B E  12345674  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077486.627177)  can1  RX B E  12345675  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077486.627579)  can1  RX B E  12345676  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
 (1614077486.627977)  can1  RX B E  12345677  [64]  03 E7 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F

可以看到并不是低ID就优先发送, 发送时没有管ID优先级, FIFO是按照先进先出发的.

这里前三行的格式问题, ESI的144行之前是-, 144行及以后是E, 暂时不解. 其它正常, ID顺序和数据都对得上.

Xavier发送脚本, ##后面的3表示开启BRS和ESI:

#!/bin/sh

while true; do
    cansend can1 18FF0001##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16
    cansend can1 18FF0002##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16
    cansend can1 18FF0003##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16  
    cansend can1 18FF0004##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16
    cansend can1 18FF0005##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16
    cansend can1 18FF0006##3.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16.01.02.03.04.05.06.07.08.09.10.11.12.13.14.15.16  
    sleep 0.01
done

可以在USART3串口中看到收到的数据, 如上面 新消息接收处理 小节配图.

完整工程下载

https://download.csdn.net/download/weifengdq/15437227

其他例子可以参考STM32Cube中的示例, 针不戳:

  • 直接用FDCAN传图像FDCAN_Image_transmission
  • 用作传统CAN的示例FDCAN_Classic_Frame_Networking
  • 时钟校准FDCAN_Clock_calibration

关于用作Classic CAN

可参考之前的文章 STM32CubeMX_CAN_CAN3_FDCAN.

核心思想是:

  • Mode 设置为Classic Master或者Classic Slave, 而不是FD
  • 仲裁段的通信速率设置为500Kbit/s, 数据段可以不用管, 或者保险点设置为500Kbit/s.

微信公众号

欢迎扫描二维码关注本人微信公众号, 及时获取或者发送给我最新消息:
在这里插入图片描述

  • 23
    点赞
  • 161
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
STM32H750单片机开发板基础代码60例实验例程软件工程源码合集: 实验0 新建工程实验 实验1 跑马灯实验 实验10 电容触摸按键实验 实验11 OLED实验 实验12 内存保护(MPU)实验 实验13 TFTLCD(MCU屏)实验 实验14 SDRAM实验 实验15 LTDC LCD(RGB屏)实验 实验16 USMART调试实验 实验17 RTC实验 实验18 硬件随机数实验 实验19 待机唤醒实验 实验2 按键输入实验 实验20 ADC实验 实验21 内部温度传感器实验 实验22 DAC实验 实验23 PWM DAC实验 实验24 DMA实验 实验25 IIC实验 实验26 IO扩展实验 实验27 光环境传感器实验 实验28 SPI实验 实验29 QSPI实验 实验3 串口通信实验 实验30 485实验 实验31 FDCAN实验 实验32 触摸屏实验 实验33 红外遥控器实验 实验34 DS18B20数字温度传感器实验 实验35 DHT11数字温湿度传感器实验 实验36 ICM20608六轴传感器实验 实验37 无线通信实验 实验38 FLASH模拟EEPROM实验 实验39 摄像头实验 实验4 外部中断实验 实验40 内存管理实验 实验41 SD卡实验 实验42 NAND FLASH实验 实验43 FATFS实验 实验44 汉字显示实验 实验45 图片显示实验 实验46 硬件JPEG解码实验 实验47 照相机实验 实验48 音乐播放器实验 实验49 录音机实验 实验5 独立看门狗实验 实验50 SPDIF(光纤音频)实验 实验51 视频播放器实验 实验52 FPU测试(Julia分形)实验 实验53 DSP测试实验 实验54 手写识别实验 实验55 T9拼音输入法实验 实验56 串口IAP实验 实验57 USB读卡器(Slave)实验 实验58 USB声卡(Slave)实验 实验59 USB虚拟串口(Slave)实验 实验6 窗口看门狗实验 实验60 USB U盘(Host)实验 实验61 USB鼠标键盘实验(Host) 实验62 网络通信实验 实验63 UCOSII实验1-任务调度 实验64 UCOSII实验2-信号量和邮箱 实验65 UCOSII实验3-消息队列、信号量集和软件定时器 实验65 综合例程 实验7 定时器中断实验 实验8 PWM输出实验 实验9 输入捕获实验
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值