STM32CubeMX_CAN_CAN3_FDCAN

文章目录

    • 前言
    • STM32CubeMX新建工程
    • CAN配置
    • 生成代码
    • CAN发送
    • CAN接收
    • CAN3
    • CANFD板子
    • CANFD配置
    • CANFD发送
    • CANFD接收
    • 工程代码
    • 微信公众号

前言

STM32CubeMX_环境搭建_GPIO_外部中断
STM32CubeMX_定时器中断_PWM
STM32CubeMX_UART_printf_接收中断_DMA空闲中断_LPUART
STM32CubeMX_以太网_RMII_LwIP_UDP

前四节简单的总结了GPIO, EXTI, TIMER, UART, 以太网的相关用法, 本节总结一下STM32的CAN, FDCAN, CAN3的用法. STM32的CAN很多系列都有: F0/1/2/3/4/7, L4/L4+等都能找到CAN的身影, 分别有1路到3路不等. 而FDCANSTM32G系列/H系列/L5系列中比较常见. 本节我们先从CAN开始, 原理性的东西自己查去, 主要看操作.

用的是下面这个自制的STM32F405RGT6的板子:
STM32CubeMX_CAN_CAN3_FDCAN_第1张图片
CAN的引脚为:

CAN STM32
CAN1_TX PB9
CAN1_RX PB8
CAN2_TX PB13
CAN2_RX PB12

然后通过CAN电平转换芯片TJA1051连接到CAN分析仪上去:
STM32CubeMX_CAN_CAN3_FDCAN_第2张图片
MCU本身外接的12MHz的晶振, 硬件连接介绍完毕, 下面开始操作.

STM32CubeMX新建工程

步骤如下:

  • MCU选择: 打开 STM32CubeMX, 点击 ACCESS TO MCU SELECTOR, 选择 STM32F405RGTx
  • 调试端口配置为SWD: Pinout & Configuration -> System Core -> SYS -> Debug 选择 Serial Wire
  • Pinout & Configuration -> System Core -> RCC -> HSE 选择 Crystal/Ceramic Resonator
  • Clock Configuration:
    STM32CubeMX_CAN_CAN3_FDCAN_第3张图片

注意CAN时钟属于APB1 peripheral clocks(MHz), 所以是42MHz.

CAN配置

Pinout & Configuration -> Connectivity -> CAN1, Mode里面勾选Master Mode, 发现默认的CAN引脚是PA11, PA12, 我们修改为PB8, PB9:
STM32CubeMX_CAN_CAN3_FDCAN_第4张图片
Pinout & Configuration -> Connectivity -> CAN2, 勾选Slave Mode, 默认的就是PB12, PB13, 不用手动修正:
STM32CubeMX_CAN_CAN3_FDCAN_第5张图片
CAN1CAN2Configuration 中, 预分配Prescaler设置为7, BS1设为5, BS2设为6, 这样波特率为42M/7/(5+6+1)=500K, 1是固定的, 与RJW的关系不大:
STM32CubeMX_CAN_CAN3_FDCAN_第6张图片
NVIC Setting 中勾选CAN1, CAN2的RX0中断, 优先级默认不改:
STM32CubeMX_CAN_CAN3_FDCAN_第7张图片
STM32CubeMX_CAN_CAN3_FDCAN_第8张图片

生成代码

Project Manager -> Project -> Browse 选择工程位置(Project Location), 填入工程名(Project Name), Toolchain/IDE 选择 MDK-ARM.

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

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

Keil 点击魔术棒或者Project -> Options for Target ..., 默认配置DebugST-link Debugger, 点击Setting -> Flash Download -> 勾选Reset and Run, 这样下载后可以自动复位运行.

如有疑问, 仍然去参考 STM32CubeMX_环境搭建_GPIO_外部中断 一节.

CAN发送

CAN1为例, main.c中添加:

/* USER CODE BEGIN PV */
CAN_TxHeaderTypeDef   TxHeader;
uint8_t               TxData[8] = {0};
uint32_t              TxMailbox;
/* USER CODE END PV */

  /* USER CODE BEGIN 2 */
	if (HAL_CAN_Start(&hcan1) != HAL_OK) {
		Error_Handler();
	}
	
	TxHeader.StdId = 0x321;
	TxHeader.ExtId = 0x01;
	TxHeader.RTR = CAN_RTR_DATA;
	TxHeader.IDE = CAN_ID_STD;
	TxHeader.DLC = 2;
	TxHeader.TransmitGlobalTime = DISABLE;
	
	TxData[0] = 0xAC;
	TxData[1] = 0xAD;
  /* USER CODE END 2 */
  
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		++TxData[1];		
		HAL_CAN_AddTxMessage(&hcan1, &TxHeader, TxData, &TxMailbox);
		HAL_Delay(10);	
  }
  /* USER CODE END 3 */

编译下载运行:
STM32CubeMX_CAN_CAN3_FDCAN_第9张图片

CAN接收

CAN接收需要先设置滤波器, 这里设为0, 全部接收:

/* USER CODE BEGIN 0 */
void CAN1_Config(void) {
	/*## Configure the CAN Filter ##*/
	CAN_FilterTypeDef  sFilterConfig;
    sFilterConfig.FilterBank = 0;
    sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
    sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
    sFilterConfig.FilterIdHigh = 0x0000;
    sFilterConfig.FilterIdLow = 0x0000;
    sFilterConfig.FilterMaskIdHigh = 0x0000;
    sFilterConfig.FilterMaskIdLow = 0x0000;
    sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
    sFilterConfig.FilterActivation = ENABLE;
    sFilterConfig.SlaveStartFilterBank = 14;		
	if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK) {
		Error_Handler();	/* Filter configuration Error */
	}
	
	/*## Start the CAN peripheral ##*/
	if (HAL_CAN_Start(&hcan1) != HAL_OK) {
		Error_Handler();
	}
	
	/*## Activate CAN RX notification ##*/
	if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) {
		Error_Handler();
	}
}

void CAN2_Config(void) {
	/*## Configure the CAN Filter ##*/
	CAN_FilterTypeDef  sFilterConfig;
    sFilterConfig.FilterBank = 14;
    sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
    sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
    sFilterConfig.FilterIdHigh = 0x0000;
    sFilterConfig.FilterIdLow = 0x0000;
    sFilterConfig.FilterMaskIdHigh = 0x0000;
    sFilterConfig.FilterMaskIdLow = 0x0000;
    sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
    sFilterConfig.FilterActivation = ENABLE;
    sFilterConfig.SlaveStartFilterBank = 14;		
	if (HAL_CAN_ConfigFilter(&hcan2, &sFilterConfig) != HAL_OK) {
		Error_Handler();	/* Filter configuration Error */
	}
	
	/*## Start the CAN peripheral ##*/
	if (HAL_CAN_Start(&hcan2) != HAL_OK) {
		Error_Handler();
	}
	
	/*## Activate CAN RX notification ##*/
	if (HAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) {
		Error_Handler();
	}
}
/* USER CODE END 0 */

上面CAN2FilterBank是从14开始的, 一共28个滤波器, CAN1CAN2各占14个.

main函数中初始化调用:

  /* USER CODE BEGIN 2 */
	CAN1_Config();
	CAN2_Config();
  /* USER CODE END 2 */

然后是接收中断, 这里把接收到的中断通通回传, CAN1的传给CAN1, CAN2的回传给CAN2:

/* USER CODE BEGIN 4 */
/**
  * @brief  Rx Fifo 0 message pending callback
  * @param  hcan: pointer to a CAN_HandleTypeDef structure that contains
  *         the configuration information for the specified CAN.
  * @retval None
  */
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK) {
		Error_Handler();
	}
	
	TxHeader.StdId = RxHeader.StdId;
	TxHeader.ExtId = RxHeader.ExtId;
	TxHeader.RTR = RxHeader.RTR;
	TxHeader.IDE = RxHeader.IDE;
	TxHeader.DLC = RxHeader.DLC;

	memcpy(TxData, RxData, RxHeader.DLC);	
	
	HAL_CAN_AddTxMessage(hcan, &TxHeader, TxData, &TxMailbox);
}

编译下载运行:
STM32CubeMX_CAN_CAN3_FDCAN_第10张图片
事实上, 我们上面没有考虑发送失败怎么办, 可以自己写一个发送函数, 发送失败延时重发, 失败超过限定次数放弃:

void CAN_SendStdMsg(CAN_HandleTypeDef *hcan, CAN_TxHeaderTypeDef *txMsg, uint8_t sendData[]) {
    //txMsg->StdId = 0x321;
    txMsg->ExtId = 0x00;
    txMsg->RTR = CAN_RTR_DATA;
    txMsg->IDE = CAN_ID_STD;
    txMsg->DLC = 8;
    txMsg->TransmitGlobalTime = DISABLE;
	
	uint32_t	TxMailbox;
	uint32_t j = 0;
	while(1) {
		if ((HAL_CAN_AddTxMessage(hcan, txMsg, sendData, &TxMailbox)!= HAL_ERROR) || (j++ > 10)) {
			break;	//success or fail_num>10, stop send
		}
		for(__IO uint16_t k=0; k < 500; k++);	//busy, delay some time
	}
}

void CAN_SendExtMsg(CAN_HandleTypeDef *hcan, CAN_TxHeaderTypeDef *txMsg, uint8_t sendData[]) {
    txMsg->StdId = 0x00;
    //txMsg->ExtId = 0x00;
    txMsg->RTR = CAN_RTR_DATA;
    txMsg->IDE = CAN_ID_EXT;
    txMsg->DLC = 8;
    txMsg->TransmitGlobalTime = DISABLE;
	
	uint32_t	TxMailbox;
	uint32_t j = 0;
	while(1) {
		if ((HAL_CAN_AddTxMessage(hcan, txMsg, sendData, &TxMailbox)!= HAL_ERROR) || (j++ > 10)) {
			break;	//success or fail_num>10, stop send
		}
		for(__IO uint16_t k=0; k < 500; k++);	//busy, delay some time
	}
}

CAN3

STM32F413 / 423, STM32F765 / 767 / 769 / 777 / 779 系列有第三路CAN, 也就是CAN3, 上面CAN1Master, CAN2Slave, 28个滤波器组也用完了, 那CAN3怎么搞? 以STM32F767为例:
STM32CubeMX_CAN_CAN3_FDCAN_第11张图片
图中直接变成一个Master, 应该是可以和CAN1平起平坐的, 中断里面也没什么差别:
STM32CubeMX_CAN_CAN3_FDCAN_第12张图片
CAN3的滤波器设置与CAN1类似:

void CAN3_Config(void) {
	/*## Configure the CAN Filter ##*/
	CAN_FilterTypeDef  sFilterConfig;
    sFilterConfig.FilterBank = 0;
    sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
    sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
    sFilterConfig.FilterIdHigh = 0x0000;
    sFilterConfig.FilterIdLow = 0x0000;
    sFilterConfig.FilterMaskIdHigh = 0x0000;
    sFilterConfig.FilterMaskIdLow = 0x0000;
    sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
    sFilterConfig.FilterActivation = ENABLE;	
	if (HAL_CAN_ConfigFilter(&hcan3, &sFilterConfig) != HAL_OK) {
		Error_Handler();	/* Filter configuration Error */
	}
	
	/*## Start the CAN peripheral ##*/
	if (HAL_CAN_Start(&hcan3) != HAL_OK) {
		Error_Handler();
	}
	
	/*## Activate CAN RX notification ##*/
	if (HAL_CAN_ActivateNotification(&hcan3, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) {
		Error_Handler();
	}
}

接收中断函数也是一样的, 不必担心.

打开HAL_CAN_ConfigFilter函数定义, 里面有这几句话:

/* CAN1 and CAN2 are dual instances with 28 common filters banks */
/* Select master instance to access the filter banks */

/* CAN3 is single instance with 14 dedicated filters banks */

CAN3有自己独立的滤波器. 但HAL库函数用起来, 让你感觉和CAN1用法是一样的.

CANFD板子

上面说到, STM32G系列/H系列/L5系列 有CANFD, 换一块自己手打的STM32G474的小板子:
STM32CubeMX_CAN_CAN3_FDCAN_第13张图片
FDCAN电平芯片在背面, 注意用到FDCAN功能时, CAN电平转换芯片也需要支持才行, 硬件连接上:

FDCAN STM32
FDCAN1_TX PD1
FDCAN1_RX PD0
FDCAN2_TX PB6
FDCAN2_RX PB5
FDCAN3_TX PB4
FDCAN3_RX PB3

外挂的12MHz晶振.

操作如下:

  • MCU选择: 打开 STM32CubeMX, 点击 ACCESS TO MCU SELECTOR, 选择 STM32G474VETx
  • 调试端口配置为SWD: Pinout & Configuration -> System Core -> SYS -> Debug 选择 Serial Wire
  • Pinout & Configuration -> System Core -> RCC -> HSE 选择 Crystal/Ceramic Resonator
  • Clock Configuration:
    STM32CubeMX_CAN_CAN3_FDCAN_第14张图片

CANFD配置

Pinout & Configuration -> Connectivity -> FDCAN1, Mode 可选Classic Master作为普通CAN用, 也可以选择FD, 由于我最近没有CANFD的应用, 就选Classic Master先当普通CAN用(至于FD的可参考http://bbs.eeworld.com.cn/thread-1080702-1-1.html这篇文章), 然后手动把引脚从PA11/PA12挪到PD0/PD1:
STM32CubeMX_CAN_CAN3_FDCAN_第15张图片
回到 Clock Configuration 时钟树里, 可以看到FDCAN的时钟是独立可选的, 先用默认的PCLK1, 170MHz:
STM32CubeMX_CAN_CAN3_FDCAN_第16张图片
CANFD的速率可变, 仲裁比特率最高1Mbps(与CAN相同), 数据比特率可以很高(8Mbps?),这就牵涉到两个波特率的配置, 如下图所示:
STM32CubeMX_CAN_CAN3_FDCAN_第17张图片
红色框中的Nominal可以当成仲裁波特率, 蓝色框中的Data当成数据波特率, 由于这里只当CAN用, 设成一样的500K波特率就可以了, 计算方法: FDCAN_CLK / Prescaler / (seg1 + seg2 + 1) = 170M/17/(9+10+1)=500K.

NVIC中勾选FDCAN1 interrupt 0, 优先级先默认不配置:
STM32CubeMX_CAN_CAN3_FDCAN_第18张图片

参考上面的生成代码一小节, 打开工程.

CANFD发送

main.c代码如下:

/* USER CODE BEGIN PV */
FDCAN_TxHeaderTypeDef TxHeader;
uint8_t TxData[8] = {0};
/* USER CODE END PV */

  /* USER CODE BEGIN 2 */
  if (HAL_FDCAN_Start(&hfdcan1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE END 2 */
  
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		
		TxHeader.Identifier = 0x1234567;
		TxHeader.IdType = FDCAN_EXTENDED_ID;
		TxHeader.TxFrameType = FDCAN_DATA_FRAME;
		TxHeader.DataLength = FDCAN_DLC_BYTES_8;	//not 8
		TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
		TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
		TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
		TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
		TxHeader.MessageMarker = 0;
		
		++TxData[7];
		
		if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData) != HAL_OK) {
			Error_Handler();
		}
		
		HAL_Delay(1000);
  }
  /* USER CODE END 3 */

CANFD接收

main.c代码如下, 滤波器设置了全接收(标准帧未测试), 中断函数中回传接收到的CAN帧:

/* USER CODE BEGIN PV */
FDCAN_TxHeaderTypeDef TxHeader;
FDCAN_RxHeaderTypeDef RxHeader;
uint8_t TxData[8] = {0};
uint8_t RxData[8];
/* USER CODE END PV */

/* USER CODE BEGIN 0 */
void FDCAN1_Config(void) {
	FDCAN_FilterTypeDef sFilterConfig;

  /* Configure Rx filter */
  sFilterConfig.IdType = FDCAN_STANDARD_ID;
  sFilterConfig.FilterIndex = 0;
  sFilterConfig.FilterType = FDCAN_FILTER_RANGE;
  sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  sFilterConfig.FilterID1 = 0x00;
  sFilterConfig.FilterID2 = 0x7FF;
  if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }
	
	sFilterConfig.IdType = FDCAN_EXTENDED_ID;
  sFilterConfig.FilterIndex = 0;
  sFilterConfig.FilterType = FDCAN_FILTER_RANGE;
  sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  sFilterConfig.FilterID1 = 0x00;
  sFilterConfig.FilterID2 = 0x1FFFFFFF;
  if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }

  /* Configure global filter:
     Filter all remote frames with STD and EXT ID
     Reject non matching frames with STD ID and EXT ID */
  if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)
  {
    Error_Handler();
  }

  /* Start the FDCAN module */
  if (HAL_FDCAN_Start(&hfdcan1) != HAL_OK)
  {
    Error_Handler();
  }

  if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
  {
    Error_Handler();
  }
}
/* USER CODE END 0 */

  /* USER CODE BEGIN 2 */
	FDCAN1_Config();
  /* USER CODE END 2 */

/* USER CODE BEGIN 4 */

void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
{
  if((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != RESET)
  {
    /* Retrieve Rx messages from RX FIFO0 */
    if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK)
    {
			Error_Handler();
			if(hfdcan == &hfdcan1) {
				TxHeader.Identifier = RxHeader.Identifier;
				TxHeader.IdType = RxHeader.IdType;	//FDCAN_STANDARD_ID, FDCAN_EXTENDED_ID
				TxHeader.TxFrameType = RxHeader.RxFrameType;	//FDCAN_DATA_FRAME, FDCAN_REMOTE_FRAME
				TxHeader.DataLength = RxHeader.DataLength;	//FDCAN_DLC_BYTES_8
				TxHeader.ErrorStateIndicator = RxHeader.ErrorStateIndicator;	//FDCAN_ESI_ACTIVE
				TxHeader.BitRateSwitch = RxHeader.BitRateSwitch;	//FDCAN_BRS_OFF
				TxHeader.FDFormat = RxHeader.FDFormat;	//FDCAN_CLASSIC_CAN, FDCAN_FD_CAN
				TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
				TxHeader.MessageMarker = 0;
				
				memcpy(TxData, RxData, TxHeader.DataLength);
				
				if(HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData) != HAL_OK) {
					Error_Handler();
				}
				
			}
    }	
	}
}
/* USER CODE END 4 */

工程代码

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

微信公众号

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

你可能感兴趣的:(STM32)