赞
踩
FDCAN为CAN的升级版,它拥有更高的速度由1Mbps上升到5Mbps,每帧数据段最大长度由8字节上升到64字节,同时最重要的是它向下兼容CAN。不过在FDCAN配置普通CAN通信与大家熟知的STMF1、F4等配置CAN不太一样。因此在此记录一下,在STM32CubeMX下配置FDCAN作为普通模式的CAN使用并通信。直接进入正题。
基于STM32G431CBT6芯片,具有170MHz的高频,也有FDCAN接口。首先常规配置时钟,达到最高170MHz。
然后打开FDCAN配置窗口,配置中断和时间报段。选择1/8/8原因是170MHz高频下170MHz/1/(8+8+1),可以达到1Mbps速率。
主要配置这些部分,Data Sync Jump Width、Data Time Seg1和Data Time Seg2默认不需要配置,因为这是FDCAN特有的功能,我们只使用传统CAN模式。同时记得在NVIC Settings上勾选上中断配置。
配置完成就生成程序框架,下面我贴上CAN的代码,需要注意生成的代码只是框架,目前FDCAN还不能正常作为CAN使用。需要加入过滤器代码以及CAN发送接收等部分代码才能正常使用
- #include "fdcan.h"
-
- /* USER CODE BEGIN 0 */
- FDCAN_RxHeaderTypeDef fdcan1_RxHeader;
- FDCAN_TxHeaderTypeDef fdcan1_TxHeader;
- FDCAN_HandleTypeDef hfdcan1;
- /* USER CODE END 0 */
-
- FDCAN_HandleTypeDef hfdcan1;
-
- /* FDCAN1 init function */
- void MX_FDCAN1_Init(void)
- {
-
- /* USER CODE BEGIN FDCAN1_Init 0 */
- FDCAN_FilterTypeDef FDCAN1_RXFilter;
- /* USER CODE END FDCAN1_Init 0 */
-
- /* USER CODE BEGIN FDCAN1_Init 1 */
-
- /* USER CODE END FDCAN1_Init 1 */
- hfdcan1.Instance = FDCAN1;
- hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1;
- hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
- hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
- hfdcan1.Init.AutoRetransmission = DISABLE;
- hfdcan1.Init.TransmitPause = DISABLE;
- hfdcan1.Init.ProtocolException = DISABLE;
- hfdcan1.Init.NominalPrescaler = 10;
- hfdcan1.Init.NominalSyncJumpWidth = 1;
- hfdcan1.Init.NominalTimeSeg1 = 8;
- hfdcan1.Init.NominalTimeSeg2 = 8;
- hfdcan1.Init.DataPrescaler = 1;
- hfdcan1.Init.DataSyncJumpWidth = 1;
- hfdcan1.Init.DataTimeSeg1 = 1;
- hfdcan1.Init.DataTimeSeg2 = 1;
- hfdcan1.Init.StdFiltersNbr = 0;
- hfdcan1.Init.ExtFiltersNbr = 0;
- hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
- if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK)
- {
- Error_Handler();
- }
- /* USER CODE BEGIN FDCAN1_Init 2 */
- FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID; //标准ID
- FDCAN1_RXFilter.FilterIndex=0; //滤波器索引
- FDCAN1_RXFilter.FilterType=FDCAN_FILTER_RANGE; //滤波器类型
- FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0; //过滤器0关联到FIFO0
- FDCAN1_RXFilter.FilterID1=0x0000; //32位ID
- FDCAN1_RXFilter.FilterID2=0x0000; //如果FDCAN配置为传统模式的话,这里是32位掩码
- if(HAL_FDCAN_ConfigFilter(&hfdcan1,&FDCAN1_RXFilter)!=HAL_OK) //滤波器初始化
- {
- Error_Handler();
- }
-
-
- HAL_FDCAN_Start(&hfdcan1); //开启FDCAN
- HAL_FDCAN_ActivateNotification(&hfdcan1,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0);
- /* USER CODE END FDCAN1_Init 2 */
-
- }
-
- void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* fdcanHandle)
- {
-
- GPIO_InitTypeDef GPIO_InitStruct = {0};
- RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
- if(fdcanHandle->Instance==FDCAN1)
- {
- /* USER CODE BEGIN FDCAN1_MspInit 0 */
-
- /* USER CODE END FDCAN1_MspInit 0 */
- /** Initializes the peripherals clocks
- */
- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_FDCAN;
- PeriphClkInit.FdcanClockSelection = RCC_FDCANCLKSOURCE_PCLK1;
- if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
- {
- Error_Handler();
- }
-
- /* FDCAN1 clock enable */
- __HAL_RCC_FDCAN_CLK_ENABLE();
-
- __HAL_RCC_GPIOA_CLK_ENABLE();
- /**FDCAN1 GPIO Configuration
- PA11 ------> FDCAN1_RX
- PA12 ------> FDCAN1_TX
- */
- GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
- GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1;
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
-
- /* FDCAN1 interrupt Init */
- HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, 5, 0);
- HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
- /* USER CODE BEGIN FDCAN1_MspInit 1 */
-
- /* USER CODE END FDCAN1_MspInit 1 */
- }
- }
-
- void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef* fdcanHandle)
- {
-
- if(fdcanHandle->Instance==FDCAN1)
- {
- /* USER CODE BEGIN FDCAN1_MspDeInit 0 */
-
- /* USER CODE END FDCAN1_MspDeInit 0 */
- /* Peripheral clock disable */
- __HAL_RCC_FDCAN_CLK_DISABLE();
-
- /**FDCAN1 GPIO Configuration
- PA11 ------> FDCAN1_RX
- PA12 ------> FDCAN1_TX
- */
- HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);
-
- /* FDCAN1 interrupt Deinit */
- HAL_NVIC_DisableIRQ(FDCAN1_IT0_IRQn);
- /* USER CODE BEGIN FDCAN1_MspDeInit 1 */
-
- /* USER CODE END FDCAN1_MspDeInit 1 */
- }
- }
-
- /* USER CODE BEGIN 1 */
- //can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)
- //len:数据长度(最大为8),可设置为FDCAN_DLC_BYTES_2~FDCAN_DLC_BYTES_8
- //msg:数据指针,最大为8个字节.
- //返回值:0,成功;
- // 其他,失败;
- uint8_t FDCAN1_Send_Msg(uint8_t* msg)
- {
-
- fdcan1_TxHeader.Identifier = 0x001;
- fdcan1_TxHeader.IdType = FDCAN_STANDARD_ID;
- fdcan1_TxHeader.TxFrameType = FDCAN_DATA_FRAME;
- fdcan1_TxHeader.DataLength = FDCAN_DLC_BYTES_8;
- fdcan1_TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
- fdcan1_TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
- fdcan1_TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
- fdcan1_TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
- fdcan1_TxHeader.MessageMarker = 0x52; //由于网上借鉴该函数,我也不太明白为什么是0x52,不过我测试改成0好像也没问题
-
- if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1,&fdcan1_TxHeader,msg)!=HAL_OK) return 1;//发送
- return 0;
- }
- //can口接收数据查询
- //buf:数据缓存区;
- //返回值:0,无数据被收到;
- //其他,接收的数据长度;
- uint8_t FDCAN1_Receive_Msg(uint8_t *buf, uint16_t *Identifier,uint16_t *len)
- {
-
- if(HAL_FDCAN_GetRxMessage(&hfdcan1,FDCAN_RX_FIFO0,&fdcan1_RxHeader,buf)!=HAL_OK)return 0;//接收数据
- *Identifier = fdcan1_RxHeader.Identifier;
- *len=fdcan1_RxHeader.DataLength>>16;
- return fdcan1_RxHeader.DataLength>>16;
- }
-
- /* USER CODE END 1 */
- /* USER CODE BEGIN Header */
- /**
- ******************************************************************************
- * @file fdcan.h
- * @brief This file contains all the function prototypes for
- * the fdcan.c file
- ******************************************************************************
- * @attention
- *
- * Copyright (c) 2023 STMicroelectronics.
- * All rights reserved.
- *
- * This software is licensed under terms that can be found in the LICENSE file
- * in the root directory of this software component.
- * If no LICENSE file comes with this software, it is provided AS-IS.
- *
- ******************************************************************************
- */
- /* USER CODE END Header */
- /* Define to prevent recursive inclusion -------------------------------------*/
- #ifndef __FDCAN_H__
- #define __FDCAN_H__
-
- #ifdef __cplusplus
- extern "C" {
- #endif
-
- /* Includes ------------------------------------------------------------------*/
- #include "main.h"
-
- /* USER CODE BEGIN Includes */
-
- /* USER CODE END Includes */
-
- extern FDCAN_HandleTypeDef hfdcan1;
-
- /* USER CODE BEGIN Private defines */
-
- /* USER CODE END Private defines */
-
- void MX_FDCAN1_Init(void);
-
- /* USER CODE BEGIN Prototypes */
- uint8_t FDCAN1_Send_Msg(uint8_t* msg);
- uint8_t FDCAN1_Receive_Msg(uint8_t *buf, uint16_t *Identifier,uint16_t *len);
- /* USER CODE END Prototypes */
-
- #ifdef __cplusplus
- }
- #endif
-
- #endif /* __FDCAN_H__ */
-
从以上代码可以看出FDCAN部分要增加过滤器配置代码,CubeMX并不会帮你自动生成这部分代码,这些发送接收函数都是网上借鉴的,其实都大差不差。需要注意如果想选定只能收到特定ID的信息,那么FDCAN上过滤器的FilterID1和FilterID2要进行更改,而且我印象单单更改这两个值还不可以,还需要配置其他REJET东西,关于这点可以自行网上了解。可以参考这篇文章:(19条消息) STM32H7 FDCAN id过滤问题_fdcan_filter_mask_swheryoo的博客-CSDN博客
如果想通过FDCAN中断处理,可以在stm32g4xx_it.c文件中找到FDCAN1_IT0_IRQHandler该函数,在里面进行自己想要的中断处理。
- void FDCAN1_IT0_IRQHandler(void)
- {
- /* USER CODE BEGIN FDCAN1_IT0_IRQn 0 */
- //自行添加想实现的功能
- /* USER CODE END FDCAN1_IT0_IRQn 0 */
- HAL_FDCAN_IRQHandler(&hfdcan1);
- /* USER CODE BEGIN FDCAN1_IT0_IRQn 1 */
-
- /* USER CODE END FDCAN1_IT0_IRQn 1 */
- }
自此,FDCAN就可以作为传统的CAN进行通信了,亲测有效。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。