控制器局域网总线(CAN,Controller Area Network)作为一种专为实时应用设计的串行通讯协议总线,在工业及自动化领域占据着举足轻重的地位。它凭借简单的双绞线即可实现信号的高效传输,凭借出色的性能与广泛的适用性,已然成为世界上应用最为普遍的现场总线之一。实际上在我的应用场景并没有实际使用过这种借口,接下来我们也是主要学习一下STM32这方面的的具体使用方法。
本次测试的C092是支持FDCAN的,CAN FD(CAN with Flexible Data rate),即“可变速率的 CAN”,可视为传统 CAN 协议的升级版。值得注意的是,此次升级主要聚焦于协议层面,物理层并未发生改变。CAN 与 CAN FD 在多个关键方面存在显著差异:
传输速率不同:传统 CAN 的传输速率相对固定,而 CAN FD 引入了可变速率机制,能够根据实际需求灵活调整传输速率。在数据量较大或对实时性要求较高的场景下,CAN FD 可以提高传输速率,从而更快地完成数据传输任务;
数据域长度不同:传统 CAN 的数据域长度有限,限制了每次传输的数据量。而 CAN FD 扩展了数据域的长度,使得在一次通信中可以传输更多的数据,减少了通信次数,提高了通信效率;
帧格式不同:为了适应可变速率和数据域长度的变化,CAN FD 对帧格式进行了相应的优化和改进。新的帧格式能够更好地支持可变速率传输和大数据量传输,同时保持了与传统 CAN 协议的兼容性;
ID 长度不同:CAN FD 不仅在数据域长度上进行了扩展,还对标识符(ID)的长度进行了调整。更长的 ID 长度提供了更多的寻址空间,使得系统能够支持更多的节点,进一步增强了系统的扩展性和灵活性。
我们看一下班次开发板的原理图:
实物接口如下:
可以看到就在常用的USB接口旁边,也就是说基本上对于C0系列来说,USB和FDCAN只能二选一了。
那么如何实现FDCAN的配置呢?
先看一下时钟配置,因为C092支持最大的是48MHz,到FDCAN最大也是48MHz:
启动FDCAN:
这里没有过多的模式和配置,直接启用就好;
注意修改默认引脚:
下面就是具体参数的设置,我们本次主要进行一下回环测试,所以要进行如下配置:
基本参数
| 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
| 发送模式
| | 我们按照例程中的配置参数进行一下配置:
接下来进行比特率的配置,如下图:
上图的选项最小数值是1,比特率=CAN时钟/时钟分频/预分频/(Seg1+Seg2+1),所以就算是最小配置参数,得到的最大比特率是16M,不过我们还是不要设置那么大,就和SPI的配置一样,太大不一定通信稳定。
依然是回环测试,我们将CAN接头短接:
这里我们主要配置过滤ID,前面各开启了一个标准滤波器和一个扩展滤波器:
- /* Configure standard ID reception filter to Rx FIFO 0. Only accept ID = FilterID1 */
- FDCAN_FilterTypeDef sFilterConfig;
- sFilterConfig.IdType = FDCAN_STANDARD_ID;
- sFilterConfig.FilterIndex = 0U;
- sFilterConfig.FilterType = FDCAN_FILTER_DUAL;
- sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
- sFilterConfig.FilterID1 = 0x444;
- sFilterConfig.FilterID2 = 0x444; /* For acceptance, MessageID and FilterID1 must match exactly */
- if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
- {
- Error_Handler();
- }
- /* Configure extended ID reception filter to Rx FIFO 1. Only accept ID between FilterID1 and FilterID2. */
- sFilterConfig.IdType = FDCAN_EXTENDED_ID;
- sFilterConfig.FilterIndex = 0U;
- sFilterConfig.FilterType = FDCAN_FILTER_RANGE_NO_EIDM;
- sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO1;
- sFilterConfig.FilterID1 = 0x1111111;
- sFilterConfig.FilterID2 = 0x2222222;
- if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
- {
- Error_Handler();
- }
复制代码 然后是进行数据的发送和接受,这里都是通过FIFO的模式进行缓存的,并在接收节点进行接收数据打印:
- FDCAN_TxHeaderTypeDef txHeader;
- /* Add message to Tx FIFO */
- txHeader.Identifier = 0x444;
- txHeader.IdType = FDCAN_STANDARD_ID;
- txHeader.TxFrameType = FDCAN_DATA_FRAME;
- txHeader.DataLength = FDCAN_DLC_BYTES_12;
- txHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
- txHeader.BitRateSwitch = FDCAN_BRS_ON;
- txHeader.FDFormat = FDCAN_FD_CAN;
- txHeader.TxEventFifoControl = FDCAN_STORE_TX_EVENTS;
- txHeader.MessageMarker = 0x52U;
- if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &txHeader, txData0) != HAL_OK)
- {
- Error_Handler();
- }
- /* Add second message to Tx FIFO */
- txHeader.Identifier = 0x1111112;
- txHeader.IdType = FDCAN_EXTENDED_ID;
- txHeader.TxFrameType = FDCAN_DATA_FRAME;
- txHeader.DataLength = FDCAN_DLC_BYTES_12;
- txHeader.ErrorStateIndicator = FDCAN_ESI_PASSIVE;
- txHeader.BitRateSwitch = FDCAN_BRS_ON;
- txHeader.FDFormat = FDCAN_FD_CAN;
- txHeader.TxEventFifoControl = FDCAN_STORE_TX_EVENTS;
- txHeader.MessageMarker = 0xCCU;
- if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &txHeader, txData1) != HAL_OK)
- {
- Error_Handler();
- }
- /* Add third message to Tx FIFO */
- txHeader.Identifier = 0x1111113;
- txHeader.IdType = FDCAN_EXTENDED_ID;
- txHeader.TxFrameType = FDCAN_DATA_FRAME;
- txHeader.DataLength = FDCAN_DLC_BYTES_12;
- txHeader.ErrorStateIndicator = FDCAN_ESI_PASSIVE;
- txHeader.BitRateSwitch = FDCAN_BRS_OFF;
- txHeader.FDFormat = FDCAN_FD_CAN;
- txHeader.TxEventFifoControl = FDCAN_STORE_TX_EVENTS;
- txHeader.MessageMarker = 0**U;
- if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &txHeader, txData2) != HAL_OK)
- {
- Error_Handler();
- }
-
- /* Get tick */
- uint32_t tickstart = HAL_GetTick();
- /* Wait transmission complete */
- while (HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan1) != NB_RX_FIFO)
- {
- /* Timeout handling */
- if ((HAL_GetTick() - tickstart) > TX_TIMEOUT)
- {
- Error_Handler();
- }
- }
-
- /*##-4 Receive messages ###################################################*/
- /* Check one message is received in Rx FIFO 0 */
- if (HAL_FDCAN_GetRxFifoFillLevel(&hfdcan1, FDCAN_RX_FIFO0) != 1U)
- {
- Error_Handler();
- }
- /* Retrieve message from Rx FIFO 0 */
- if (HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO0, &rxHeader, rxData) != HAL_OK)
- {
- Error_Handler();
- }
- /* Compare received RX message to expected data */
- if ((rxHeader.Identifier != 0x444) ||
- (rxHeader.IdType != FDCAN_STANDARD_ID) ||
- (rxHeader.DataLength != FDCAN_DLC_BYTES_12) ||
- (BufferCmp8b(txData0, rxData, COUNTOF(rxData)) != 0U))
- {
- Error_Handler();
- }
- HAL_UART_Transmit(&huart2, (uint8_t *)&rxData, 12, 0xFFFF);
- /* Check two messages are received in Rx FIFO 1 */
- if (HAL_FDCAN_GetRxFifoFillLevel(&hfdcan1, FDCAN_RX_FIFO1) != 2U)
- {
- Error_Handler();
- }
- /* Retrieve message from Rx FIFO 1 */
- if (HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO1, &rxHeader, rxData) != HAL_OK)
- {
- Error_Handler();
- }
- /* Compare received RX message to expected data */
- if ((rxHeader.Identifier != 0x1111112) ||
- (rxHeader.IdType != FDCAN_EXTENDED_ID) ||
- (rxHeader.DataLength != FDCAN_DLC_BYTES_12) ||
- (BufferCmp8b(txData1, rxData, COUNTOF(rxData)) != 0U))
- {
- Error_Handler();
- }
- HAL_UART_Transmit(&huart2, (uint8_t *)&rxData, 12, 0xFFFF);
- /* Retrieve next message from Rx FIFO 1 */
- if (HAL_FDCAN_GetRxMessage(&hfdcan1, FDCAN_RX_FIFO1, &rxHeader, rxData) != HAL_OK)
- {
- Error_Handler();
- }
- /* Compare received RX message to expected data */
- if ((rxHeader.Identifier != 0x1111113) ||
- (rxHeader.IdType != FDCAN_EXTENDED_ID) ||
- (rxHeader.DataLength != FDCAN_DLC_BYTES_12) ||
- (BufferCmp8b(txData2, rxData, COUNTOF(rxData)) != 0U))
- {
- Error_Handler();
- }
- HAL_UART_Transmit(&huart2, (uint8_t *)&rxData, 12, 0xFFFF);
复制代码 最后在通过在FIFO中查询的数据进行打印,与发送的数据一致:
这里多了一个C8,应该是串口出现的问题。
|