[STM32C0] 【STM32C092RC 测评】FDCAN Loopback测试

[复制链接]
 楼主| qintian0303 发表于 2025-5-4 18:57 | 显示全部楼层 |阅读模式
<
      CAN同样可以进行Loopback测试,我们首先连接一下CAN的基本概念。
      控制器局域网总线(CAN)作为专为实时应用量身打造的串行通讯协议,在工业及自动化领域扮演着至关重要的角色。仅需简单的双绞线,它便能实现信号的高效、稳定传输。凭借卓越的性能与广泛的适用性,CAN总线已成为全球范围内应用最为广泛的现场总线之一。我们将深入探索STM32在CAN总线方面的具体应用之法。
      本次测试中的C092型号支持FDCAN,即CAN FD(CAN with Flexible Data Rate),作为传统CAN协议的升级版,其核心升级聚焦于协议层面,物理层维持原状。CAN与CAN FD的关键差异体现在:
      传输速率:传统CAN的传输速率较为固定,而CAN FD引入可变速率机制,能根据实际需求灵活调整,尤其在大数据量或高实时性要求的场景下,显著提升数据传输速率。
      数据域长度:CAN FD扩展了数据域长度,相较于传统CAN有限的数据域,CAN FD单次通信可传输更多数据,减少通信次数,提高通信效率。
      帧格式:为适应可变速率和数据域长度的变化,CAN FD优化了帧格式,不仅支持更高效的变速率与大数据量传输,同时保持与传统CAN协议的兼容性。
      ID长度:CAN FD不仅扩展了数据域长度,还增加了标识符(ID)的长度,提供更多寻址空间,支持更多节点,增强系统扩展性和灵活性。
      我们看一下C092开发板中对应CAN接口的原理图:
0cfea27f1e1b1886e5c310eb92d71a44
      对应的单片机引脚如下:
6262b95c9e295f0a5d0aa875b889978c
      实物接口如下:
1ebab29cef75709f9cf65ea8b42ac5d1
      Loopback测试连接如下:
f99f95f124bc9da10981efd2fd0feb1f
      就是这么简单,紧邻常用的USB接口,C0系列设备在USB与FDCAN之间做出了巧妙的设计取舍,二者仅能择其一配备。
      接下来进行FDCAN的配置:
      先看一下时钟配置,因为C092支持最大的是48MHz,到FDCAN最大也是48MHz:
1f8a1379b9f2dd629d2e68a0ba4bebb0
      启动FDCAN:
956249a6dc37796c58bd23f256b592f3
      下面就是具体参数的设置,我们本次主要进行一下回环测试,所以要进行如下配置:

基本参数
Clock Divider
时钟分频
  
Frame Format
CANFD模式
  
Mode
正常工作模式
  
Auto Retransmission
自动重传
  
Transmit Pause
传输暂停
  
Protocol Exception
协议异常处理
  
Nominal Sync Jump Width
裁决段同步跳转段宽度
  
Data Prescaler
数据段分频系数
  
Data Sync Jump Width
数据段同步跳转段宽度
  
Data Time Seg1
数据段时间段1
  
Data Time Seg2
数据段时间段2
  
Std Filters Nbr
标准滤波器数量
  
Ext Filters Nbr
拓展滤波器数量
  
Tx Fifo Queue Mode
发送模式
  
      
      我们按照例程中的配置参数进行一下配置:
ea729963728dfec536231926d780316d
      接下来进行比特率的配置,如下图:
c957d1e51ecdd591d0ee595ef027c96e
       上图所示选项中,最小数值设定为1,比特率的计算公式为:比特率 = CAN时钟 / (时钟分频 × 预分频 × (Seg1 + Seg2 + 1))。即便采用此最小配置参数,理论上能达到的最大比特率可高达16MHz。
       软件方面主要是配置过滤器,这里我们主要配置过滤ID,前面各开启了一个标准滤波器和一个扩展滤波器:
  1. <p>/* Configure standard ID reception filter to Rx FIFO 0. Only accept ID = FilterID1 */</p><p>  FDCAN_FilterTypeDef        sFilterConfig;</p><p>  sFilterConfig.IdType       = FDCAN_STANDARD_ID;</p><p>  sFilterConfig.FilterIndex  = 0U;</p><p>  sFilterConfig.FilterType   = FDCAN_FILTER_DUAL;</p><p>  sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;</p><p>  sFilterConfig.FilterID1    = 0x444;</p><p>  sFilterConfig.FilterID2    = 0x444; /* For acceptance, MessageID and FilterID1 must match exactly */</p><p>  if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)</p><p>  {</p><p>    Error_Handler();</p><p>  }</p><p>  /* Configure extended ID reception filter to Rx FIFO 1. Only accept ID between FilterID1 and FilterID2. */</p><p>  sFilterConfig.IdType       = FDCAN_EXTENDED_ID;</p><p>  sFilterConfig.FilterIndex  = 0U;</p><p>  sFilterConfig.FilterType   = FDCAN_FILTER_RANGE_NO_EIDM;</p><p>  sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO1;</p><p>  sFilterConfig.FilterID1    = 0x1111111;</p><p>  sFilterConfig.FilterID2    = 0x2222222;</p><p>  if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)</p><p>  {</p><p>    Error_Handler();</p><p>  }</p>

       然后是进行数据的发送和接收,这里都是通过FIFO的模式进行缓存的,并在接收节点进行接收数据打印,这里面发送配置中主要就是ID要满足上面过滤器的要求:
  1. <p>FDCAN_TxHeaderTypeDef        txHeader;</p><p>  /* Add message to Tx FIFO */</p><p>  txHeader.Identifier          = 0x444;</p><p>  txHeader.IdType              = FDCAN_STANDARD_ID;</p><p>  txHeader.TxFrameType         = FDCAN_DATA_FRAME;</p><p>  txHeader.DataLength          = FDCAN_DLC_BYTES_12;</p><p>  txHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;</p><p>  txHeader.BitRateSwitch       = FDCAN_BRS_ON;</p><p>  txHeader.FDFormat            = FDCAN_FD_CAN;</p><p>  txHeader.TxEventFifoControl  = FDCAN_STORE_TX_EVENTS;</p><p>  txHeader.MessageMarker       = 0x52U;</p><p>  if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &txHeader, txData0) != HAL_OK)</p><p>  {</p><p>    Error_Handler();</p><p>  }</p><p>  /* Add second message to Tx FIFO */</p><p>  txHeader.Identifier          = 0x1111112;</p><p>  txHeader.IdType              = FDCAN_EXTENDED_ID;</p><p>  txHeader.TxFrameType         = FDCAN_DATA_FRAME;</p><p>  txHeader.DataLength          = FDCAN_DLC_BYTES_12;</p><p>  txHeader.ErrorStateIndicator = FDCAN_ESI_PASSIVE;</p><p>  txHeader.BitRateSwitch       = FDCAN_BRS_ON;</p><p>  txHeader.FDFormat            = FDCAN_FD_CAN;</p><p>  txHeader.TxEventFifoControl  = FDCAN_STORE_TX_EVENTS;</p><p>  txHeader.MessageMarker       = 0xCCU;</p><p>  if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &txHeader, txData1) != HAL_OK)</p><p>  {</p><p>    Error_Handler();</p><p>  }</p><p>  /* Add third message to Tx FIFO */</p><p>  txHeader.Identifier          = 0x1111113;</p><p>  txHeader.IdType              = FDCAN_EXTENDED_ID;</p><p>  txHeader.TxFrameType         = FDCAN_DATA_FRAME;</p><p>  txHeader.DataLength          = FDCAN_DLC_BYTES_12;</p><p>  txHeader.ErrorStateIndicator = FDCAN_ESI_PASSIVE;</p><p>  txHeader.BitRateSwitch       = FDCAN_BRS_OFF;</p><p>  txHeader.FDFormat            = FDCAN_FD_CAN;</p><p>  txHeader.TxEventFifoControl  = FDCAN_STORE_TX_EVENTS;</p><p>  txHeader.MessageMarker       = 0xDDU;</p><p>  if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &txHeader, txData2) != HAL_OK)</p><p>  {</p><p>    Error_Handler();</p><p>  }</p><p>/* Get tick */</p><p>  uint32_t tickstart = HAL_GetTick();</p><p>  /* Wait transmission complete */</p><p>  while (HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) != NB_RX_FIFO)</p><p>  {</p><p>    /* Timeout handling */</p><p>    if ((HAL_GetTick() - tickstart) > TX_TIMEOUT)</p><p>    {</p><p>      Error_Handler();</p><p>    }</p><p>  }</p><p>/*##-4 Receive messages ###################################################*/</p><p>  /* Check one message is received in Rx FIFO 0 */</p><p>  if (HAL_FDCAN_GetRxFifoFillLevel(&hfdcan1, FDCAN_RX_FIFO0) != 1U)</p><p>  {</p><p>    Error_Handler();</p><p>  }</p><p>  /* Retrieve message from Rx FIFO 0 */</p><p>  if (HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO0, &rxHeader, rxData) != HAL_OK)</p><p>  {</p><p>    Error_Handler();</p><p>  }</p><p>  /* Compare received RX message to expected data */</p><p>  if ((rxHeader.Identifier != 0x444) ||</p><p>      (rxHeader.IdType     != FDCAN_STANDARD_ID) ||</p><p>      (rxHeader.DataLength != FDCAN_DLC_BYTES_12) ||</p><p>      (BufferCmp8b(txData0, rxData, COUNTOF(rxData)) != 0U))</p><p>  {</p><p>    Error_Handler();</p><p>  }</p><p>HAL_UART_Transmit(&huart2, (uint8_t *)&rxData, 12, 0xFFFF);</p><p>  /* Check two messages are received in Rx FIFO 1 */</p><p>  if (HAL_FDCAN_GetRxFifoFillLevel(&hfdcan1, FDCAN_RX_FIFO1) != 2U)</p><p>  {</p><p>    Error_Handler();</p><p>  }</p><p>  /* Retrieve message from Rx FIFO 1 */</p><p>  if (HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO1, &rxHeader, rxData) != HAL_OK)</p><p>  {</p><p>    Error_Handler();</p><p>  }</p><p>  /* Compare received RX message to expected data */</p><p>  if ((rxHeader.Identifier != 0x1111112) ||</p><p>      (rxHeader.IdType     != FDCAN_EXTENDED_ID) ||</p><p>      (rxHeader.DataLength != FDCAN_DLC_BYTES_12) ||</p><p>      (BufferCmp8b(txData1, rxData, COUNTOF(rxData)) != 0U))</p><p>  {</p><p>    Error_Handler();</p><p>  }</p><p>HAL_UART_Transmit(&huart2, (uint8_t *)&rxData, 12, 0xFFFF);</p><p>  /* Retrieve next message from Rx FIFO 1 */</p><p>  if (HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO1, &rxHeader, rxData) != HAL_OK)</p><p>  {</p><p>    Error_Handler();</p><p>  }</p><p>  /* Compare received RX message to expected data */</p><p>  if ((rxHeader.Identifier != 0x1111113) ||</p><p>      (rxHeader.IdType     != FDCAN_EXTENDED_ID) ||</p><p>      (rxHeader.DataLength != FDCAN_DLC_BYTES_12) ||</p><p>      (BufferCmp8b(txData2, rxData, COUNTOF(rxData)) != 0U))</p><p>  {</p><p>    Error_Handler();</p><p>  }</p><p>HAL_UART_Transmit(&huart2, (uint8_t *)&rxData, 12, 0xFFFF);</p>

       最后在通过在FIFO中查询的数据进行打印,与发送的数据一致:
57ca509e31e472ec35d9287f43bffc64

AdaMaYun 发表于 2025-6-8 19:57 | 显示全部楼层
can自带的指令进行收发
lihuami 发表于 2025-6-10 10:15 | 显示全部楼层
应用FDCAN模块和Loopback测试。
macpherson 发表于 2025-6-10 12:44 | 显示全部楼层
STM32C092RC的FDCAN模块支持的最大波特率是多少?
fengm 发表于 2025-6-10 13:17 | 显示全部楼层
在配置FDCAN模块时,是否需要特别注意某些参数的设置?
ingramward 发表于 2025-6-10 13:53 | 显示全部楼层
是否有实际应用案例展示如何在特定项目中使用FDCAN模块?
burgessmaggie 发表于 2025-6-10 14:34 | 显示全部楼层
如何提高数据传输速率或减少延迟?
jtracy3 发表于 2025-6-10 15:05 | 显示全部楼层
需要注意哪些缓冲区管理问题?              
yorkbarney 发表于 2025-6-10 16:42 | 显示全部楼层
Loopback 模式下能否测试 FDCAN 的所有功能
yiyigirl2014 发表于 2025-6-10 16:43 | 显示全部楼层
CAN 也可以做自发自收测试啊?
ulystronglll 发表于 2025-6-10 17:18 | 显示全部楼层
进行FDCAN Loopback测试时,是否需要特定的硬件或软件环境?
macpherson 发表于 2025-6-10 17:50 | 显示全部楼层
CAN总线的终端电阻 应如何连接?
elsaflower 发表于 2025-6-10 19:34 | 显示全部楼层
FDCAN 功能在 STM32C092RC 上的 Flash/RAM 占用量是多少?
febgxu 发表于 2025-6-10 21:14 | 显示全部楼层
在高负载或噪声干扰环境下,FDCAN的通信稳定性如何?
jimmhu 发表于 2025-6-10 21:46 | 显示全部楼层
若直接短路引脚,是否需要额外串联电阻或电容以避免信号反射
rosemoore 发表于 2025-6-10 22:39 | 显示全部楼层
在Stop模式或Standby模式下,FDCAN能否保持工作状态?
 楼主| qintian0303 发表于 2025-6-11 09:06 | 显示全部楼层
rosemoore 发表于 2025-6-10 22:39
在Stop模式或Standby模式下,FDCAN能否保持工作状态?

Stop模式基本上的外设都停了吧,Standby模式下估计也不行,这个没有试过一般带LP的模块Standby模式下能工作
codingtuzi 发表于 2025-6-11 10:34 | 显示全部楼层
像C0这种低成本,性能优化的小MCU,跑上FDCAN的高速速率,其负载的吞吐率能有多高?我挺怀疑的
sesefadou 发表于 2025-6-12 13:33 | 显示全部楼层
从 Loopback 模式切换到 Normal 模式时需要注意哪些配置变化?
backlugin 发表于 2025-6-12 14:37 | 显示全部楼层
发送数据后如何判断接收是否成功?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:硬件工程师
简介:有着多年硬件开发经验的专业人员,专注于医疗电子领域,热衷于对新鲜事物的探索,喜欢DIY!

558

主题

2727

帖子

12

粉丝
快速回复 在线客服 返回列表 返回顶部