- void FlexCAN_Configure(void)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
- NVIC_InitTypeDef NVIC_InitStruct;
- flexcan_config_t FlexCAN_ConfigStruct;
- flexcan_rx_mb_config_t FlexCAN_RxMB_ConfigStruct;
- RCC_ClocksTypeDef RCC_Clocks;
- RCC_GetClocksFreq(&RCC_Clocks);
- RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);
- RCC_APB1PeriphClockCmd(RCC_APB1ENR_FLEXCAN, ENABLE);
- GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_3);
- GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_3);
- GPIO_StructInit(&GPIO_InitStruct);
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_FLOATING;
- GPIO_Init(GPIOB, &GPIO_InitStruct);
- GPIO_StructInit(&GPIO_InitStruct);
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_Init(GPIOB, &GPIO_InitStruct);
- NVIC_InitStruct.NVIC_IRQChannel = FLEX_CAN_IRQn;
- NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
- NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStruct);
- FLEXCAN_GetDefaultConfig(&FlexCAN_ConfigStruct);
- FlexCAN_ConfigStruct.baudRate = 1000000U; /* 1Mbps */
- FlexCAN_ConfigStruct.baudRateFD = 2000000U; /* 2Mbps */
- FlexCAN_ConfigStruct.clkSrc = Enum_Flexcan_ClkSrc1;
- FlexCAN_ConfigStruct.enableLoopBack = false;
- FlexCAN_ConfigStruct.disableSelfReception = true;
- FlexCAN_ConfigStruct.enableIndividMask = true;
- FLEXCAN_Init(FLEX_CAN1, &FlexCAN_ConfigStruct);
- FLEXCAN_EnterFreezeMode(FLEX_CAN1);
- FLEX_CAN1->MCR |= 1 << 13;
- FLEX_CAN1->CTRL1 &= (~CAN_CTRL1_SMP(1));
- FLEXCAN_ExitFreezeMode(FLEX_CAN1);
- /* Baudrate calculate by automatically */
- FLEXCAN_FDCalculateImprovedTimingValues(FlexCAN_ConfigStruct.baudRate, FlexCAN_ConfigStruct.baudRateFD,
- RCC_Clocks.PCLK1_Frequency, &FlexCAN_ConfigStruct.timingConfig);
- FLEXCAN_FDInit(FLEX_CAN1, &FlexCAN_ConfigStruct, FLEXCAN_64BperMB, true);
- FLEXCAN_SetFDTxMbConfig(FLEX_CAN1, 1, true);
- FLEXCAN_SetFDTxMbConfig(FLEX_CAN1, 3, true);
- FlexCAN_RxMB_ConfigStruct.id = FLEXCAN_ID_STD(0x111);
- FlexCAN_RxMB_ConfigStruct.format = Enum_Flexcan_FrameFormatStandard;
- FlexCAN_RxMB_ConfigStruct.type = Enum_Flexcan_FrameTypeData;
- FLEXCAN_SetFDRxMbConfig(FLEX_CAN1, 0, &FlexCAN_RxMB_ConfigStruct, true);
- FLEXCAN_SetRxIndividualMask(FLEX_CAN1, 0, FLEXCAN_RX_MB_STD_MASK(0xFFF, 0, 0));
- /* Enable MB0 Interrupt */
- FLEX_CAN1->IMASK1 |= (0x01U << 0);
- FlexCAN_RxMB_ConfigStruct.id = FLEXCAN_ID_EXT(0x222);
- FlexCAN_RxMB_ConfigStruct.format = Enum_Flexcan_FrameFormatExtend;
- FlexCAN_RxMB_ConfigStruct.type = Enum_Flexcan_FrameTypeData;
- FLEXCAN_SetFDRxMbConfig(FLEX_CAN1, 2, &FlexCAN_RxMB_ConfigStruct, true);
- FLEXCAN_SetRxIndividualMask(FLEX_CAN1, 2, FLEXCAN_RX_MB_EXT_MASK(0xFFF, 0, 1));
- /* Enable MB2 Interrupt */
- FLEX_CAN1->IMASK1 |= (0x01U << 2);
- }
配置PB8、PB9复用为FlexCAN的RX、TX引脚;
配置CAN 1Mbps和CAN FD 2Mbps、MB选择64字节负载;
配置NVIC中断;
配置MB1、MB3为发送邮箱;
配置MB0、MB2为接收邮箱;
MB0仅接收ID为0x111的标准帧;
MB2仅接收ID为0x222的扩展帧。
7.2 发送标准帧报文
- void FlexCAN_FD_SendStandardFrameMessage(uint32_t ID, uint8_t *Buffer, uint8_t Length)
- {
- flexcan_fd_frame_t FlexCAN_FD_FrameStruct;
- FlexCAN_FD_FrameStruct.length = Length;
- FlexCAN_FD_FrameStruct.type = (uint8_t)Enum_Flexcan_FrameTypeData;
- FlexCAN_FD_FrameStruct.format = (uint8_t)Enum_Flexcan_FrameFormatStandard;
- FlexCAN_FD_FrameStruct.brs = 1;
- FlexCAN_FD_FrameStruct.edl = 1;
- FlexCAN_FD_FrameStruct.id = ID;
- for (uint8_t i = 0; i < 16; i++)
- {
- FlexCAN_FD_FrameStruct.dataWord[i] = Buffer[i * 4] << 24 | Buffer[i * 4 + 1] << 16 | Buffer[i * 4 + 2] << 8 | Buffer[i * 4 + 3];
- }
- FLEXCAN_WriteFDTxMb(FLEX_CAN1, 1, &FlexCAN_FD_FrameStruct);
- }
flexcan_fd_frame_t是按照FlexCAN MB结构定义的结构体,将要发送的标准帧按照帧结构依次设置结构体的各字段,接着写入MB1发送邮箱。
7.3 发送扩展帧报文
- void FlexCAN_FD_SendExtendFrameMessage(uint32_t ID, uint8_t *Buffer, uint8_t Length)
- {
- flexcan_fd_frame_t FlexCAN_FD_FrameStruct;
- FlexCAN_FD_FrameStruct.length = Length;
- FlexCAN_FD_FrameStruct.type = (uint8_t)Enum_Flexcan_FrameTypeData;
- FlexCAN_FD_FrameStruct.format = (uint8_t)Enum_Flexcan_FrameFormatExtend;
- FlexCAN_FD_FrameStruct.brs = 1;
- FlexCAN_FD_FrameStruct.edl = 1;
- FlexCAN_FD_FrameStruct.id = ID;
- for (uint8_t i = 0; i < 16; i++)
- {
- FlexCAN_FD_FrameStruct.dataWord[i] = Buffer[i * 4] << 24 | Buffer[i * 4 + 1] << 16 | Buffer[i * 4 + 2] << 8 | Buffer[i * 4 + 3];
- }
- FLEXCAN_WriteFDTxMb(FLEX_CAN1, 3, &FlexCAN_FD_FrameStruct);
- }
同上,将要发送的扩展帧按照帧结构依次设置结构体的各字段,接着写入MB3发送邮箱。
7.4 获取报文并发送
- void FlexCAN_FD_RxMB_Handler(uint8_t Index)
- {
- uint8_t Buffer[64];
- flexcan_fd_frame_t FlexCAN_FD_FrameStruct;
- FLEXCAN_ReadFDRxMb(FLEX_CAN1, Index, &FlexCAN_FD_FrameStruct);
- for(uint8_t i = 0; i < 16; i++)
- {
- Buffer[i*4+0] = (FlexCAN_FD_FrameStruct.dataWord[i] >> 0x18) & 0xFF;
- Buffer[i*4+1] = (FlexCAN_FD_FrameStruct.dataWord[i] >> 0x10) & 0xFF;
- Buffer[i*4+2] = (FlexCAN_FD_FrameStruct.dataWord[i] >> 0x08) & 0xFF;
- Buffer[i*4+3] = (FlexCAN_FD_FrameStruct.dataWord[i] >> 0x00) & 0xFF;
- }
- if (Index == 0)
- {
- FlexCAN_FD_SendStandardFrameMessage((FlexCAN_FD_FrameStruct.id >> CAN_ID_STD_SHIFT), Buffer, FlexCANFD_TX_64Bytes_DataLen);
- }
- else
- {
- FlexCAN_FD_SendExtendFrameMessage((FlexCAN_FD_FrameStruct.id >> CAN_ID_EXT_SHIFT), Buffer, FlexCANFD_TX_64Bytes_DataLen);
- }
- }
读接收邮箱(Index),获取CAN FD报文中的数据,并发送该报文。
7.5 中断服务子程序
- void FlexCAN_IRQHandler(void)
- {
- uint32_t u32flag = 1;
- /* MB0 */
- if (FLEXCAN_GetMbStatusFlags(FLEX_CAN1, u32flag << 0) != 0)
- {
- FlexCAN_FD_RxMB_Handler(0);
- FLEXCAN_ClearMbStatusFlags(FLEX_CAN1, u32flag << 0);
- }
- /* MB1 */
- if (FLEXCAN_GetMbStatusFlags(FLEX_CAN1, u32flag << 1) != 0)
- {
- FLEXCAN_ClearMbStatusFlags(FLEX_CAN1, u32flag << 1);
- }
- /* MB2 */
- if (FLEXCAN_GetMbStatusFlags(FLEX_CAN1, u32flag << 2) != 0)
- {
- FlexCAN_FD_RxMB_Handler(2);
- FLEXCAN_ClearMbStatusFlags(FLEX_CAN1, u32flag << 2);
- }
- /* MB3 */
- if (FLEXCAN_GetMbStatusFlags(FLEX_CAN1, u32flag << 3) != 0)
- {
- FLEXCAN_ClearMbStatusFlags(FLEX_CAN1, u32flag << 3);
- }
- }
- MB0、MB2完成接收调用MB接收函数,获取报文并通过MB1、MB3发送。MB1、MB3完成传输,清除对应标志。
- 7.6 FlexCAN_FD中断示例
- void FlexCAN_FD_Interrupt_Sample(void)
- {
- uint8_t Buffer[64] =
- {
- 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xAA,
- 0xAA,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x55,
- 0x55,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xAA,
- 0xAA,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x88,
- };
- printf("\r\nTest %s", __FUNCTION__);
- FlexCAN_Configure();
- while (1)
- {
- FlexCAN_FD_SendStandardFrameMessage(0x214, Buffer, FlexCANFD_TX_64Bytes_DataLen);
- PLATFORM_LED_Toggle(LED1);
- PLATFORM_DelayMS(1000);
- }
- }
MB0、MB2完成接收调用MB接收函数,获取报文并通过MB1、MB3发送。MB1、MB3完成传输,清除对应标志。
7.6 FlexCAN_FD中断示例
- void FlexCAN_FD_Interrupt_Sample(void)
- {
- uint8_t Buffer[64] =
- {
- 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xAA,
- 0xAA,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x55,
- 0x55,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xAA,
- 0xAA,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x88,
- };
- printf("\r\nTest %s", __FUNCTION__);
- FlexCAN_Configure();
- while (1)
- {
- FlexCAN_FD_SendStandardFrameMessage(0x214, Buffer, FlexCANFD_TX_64Bytes_DataLen);
- PLATFORM_LED_Toggle(LED1);
- PLATFORM_DelayMS(1000);
- }
- }
调用FlexCAN_Configure(),在while中间隔1s中发送标准帧报文,帧ID为0x214,数据为定义好的Buffer[64]。
在主函数中调用FlexCAN_FD_Interrupt_Sample()。
8. 验证
连接CAN调试工具,配置波特率CAN 1Mbps、CAN FD 2Mbps,观测上位机软件:
接收区间隔1s接收到一次FD报文,ID为0x214。
在发送区发送标准帧FD报文,ID为0x111,发送扩展帧FD报文,ID为0x222,各发送5次:
每发送1次报文,接收区接收到1次该ID的报文,和程序预期一致。