STM32G474_FDCAN的普通CAN模式使用

由于鄙人比较懒,因此本文章只是对 FDCAN 的 经典模式 的简单使用介绍。对于我不需要使用的功能 我就没有深入研究,因此本文只是 CAN 的常用方式的笔记,深入研究的话可以详细阅读手册,本文章没有介绍。

如果有介绍错误的地方,希望各位大佬指正,鄙人一定修改,必要时删除本文章,防止误导他人。欢迎讨论!

FDCAN经典CAN 的最直观差别就是数据帧部分,FDCAN的数据帧波特率可变,并且数据大小不局限于 8 Bytes ,最高支持 64 Bytes 的数据传输。详细差别见 传送门: CAN FD 与 CAN协议区别–简单易懂协议详解

1. FDCAN的框图

在这里插入图片描述
根据上图可以看到,FDCAN 有两个时钟域,APB总线接口和CAN内核时钟。FDCAN的波特率取决于内核时钟,寄存器的配置、消息RAM等,走的是APB时钟。FDCAN的APB时钟在RCC_APB寄存器中配置,内核时钟在RCC_CCIPR寄存器中配置(下一章)。
FDCAN有两个中断线,这两个中断线可以单独的打开或关闭,在FDCAN_ILE寄存器中配置。
其他具体介绍参考DM00355726_ENV4手册的1947页(RM0440手册官方下载传送门)。

2. FDCAN的时钟与波特率

2.1 fdcan_clk

几乎所有通信都可在RCC中配置时钟选择,FDCAN的时钟(fdcan_clk)可在RCC_CCIPR寄存器中进行配置。

在这里插入图片描述

2.2 fdcan_tq_ck

根据系统框图可看到,系统输入的时钟可通过 fdcan_clk 分频得到 fdcan_tq_ck ,在 FDCAN_CKDIV 寄存器中配置分频系数。

这里是引用

2.3 波特率

FDCAN模块的bit采样分三段:

在这里插入图片描述


波特率公式如下:

=

1

t

q

+

t

B

S

1

+

t

B

S

2

波特率 = \frac{1}{t_q + t_{BS1} + t_{BS2}}

=tq+tBS1+tBS21

t

q

=

(

B

R

P

+

1

)

f

d

c

a

n

_

c

l

k

t_q = (BRP + 1)*fdcan\_clk

tq=(BRP+1)fdcan_clk

注意:
1、由于 FDCAN 与 经典CAN 的帧格式有点差异,其数据帧波特率可变,因此在这里分出普通CAN和数据bit时间
2、数据 和 普通 bit 时间寄存器名称不一样,数据波特率寄存器 FDCAN_DBTP ,一般帧波特率寄存器为 FDCAN_NBTP 。当使用经典模式CAN时, FDCAN_DBTP 配置被忽略

3. FDCAN的地址分布

3.1 总体分布

在这里插入图片描述

由于头文件中没有该寄存器的宏定义,因此需要自己建立宏定义。
G474的FDCAN外设一共有3组(FDCAN1,FDCAN2,FDCAN3),寄存器配置分为3个,消息RAM也分为3组。
这里可以先把 消息RAM 的宏定义写好

#define FDCANs_MESSAGE_RAM_BASE		0x4000A400
#define FDCAN1_RAM_BASE				(FDCANs_MESSAGE_RAM_BASE)
#define FDCAN2_RAM_BASE				(FDCAN1_RAM_BASE + 0x00000400)
#define FDCAN3_RAM_BASE				(FDCAN2_RAM_BASE + 0x00000400)

3.2 Message RAM

在这里插入图片描述
1个 信息RAM 有 212 words 的大小,即 212 × 4 = 848 Bytes 。
根据该图,可以创建一个对应上述地址的结构体,方便后期地址的管理:

typedef struct
{
	uint32_t FILTER_11BIT[28];
	uint32_t FILTER_29BIT[16];
	uint32_t Rx_FIFO_0[54];
	uint32_t Rx_FIFO_1[54];
	uint32_t Tx_FIFO[6];
	uint32_t Tx_BUFFER[54];
}FDCAN_RAM_Struct;

4. FDCAN的筛选器

4.1 筛选器的特征

  1. 每个筛选器可配置为
    • 范围筛选
    • 指定ID筛选
    • 屏蔽典型bit筛选
  2. 每个过滤器元件可配置为接受或拒绝过滤
  3. 每个过滤器元素可以单独启用/禁用
  4. 过滤器是按顺序检查的,执行在第一个匹配的过滤器元素时停止

相关的寄存器:全局筛选配置(RXGFC)、拓展ID和掩码(XIDAM

如果需要接收数据,一定要配置筛选器,否则会什么也接受不到。

4.2 11-bit 筛选器的格式

在这里插入图片描述
这里根据手册的翻译进行配置就好,29-bit 的筛选器也是如此,手册里全有,我就不放图片了,太占地方。

对于筛选器的掩码模式,可通过传送门了解到:CAN通讯难点———验收筛选器

通过配置筛选器,可以使FDCAN外设接收其他模块发来的信息,在筛选器中配置接收消息的FIFO或者拒收消息。配置筛选器是FDCAN接收的关键。
筛选器的配置不受 INITCCE 标志位的限制,可随时配置。

5. FIFO模式与Queue模式

FIFO模式与队列模式的区别为:

  • 队列模式的优先级遵循邮箱0优先级最高,其次是1,最后是2,如果当前3个邮箱全有数据,优先发送邮箱0的数据
  • FIFO模式的优先级是遵循哪个数据先进入的邮箱,与其所在的索引地址无关,即:如果当前3个邮箱全有数据,邮箱2被最先写入,则优先发送邮箱2的数据。

5.1 TX FIFO 的寄存器格式

在这里插入图片描述

具体说明见手册1969页,我就不复制了,翻一下就能懂每个BIT代表的意思。
根据上表,我们就可以写出对应各个标志位的结构体,方便后期指针使用。
由于其buffer支持 11-bit ID29-bit ID ,因此将其写为共同体。

typedef union
{
	uint32_t HallfWord[54];
	struct
	{
		uint32_t T0_ID:29;					// ID
		uint32_t T0_RTR:1;					//【0|发送数据帧】【1|发送远程帧】
		uint32_t T0_XTD:1;					//【0|11-bit】【1|29-bit】
		uint32_t T0_ESI:1;					// 
		
		uint32_t T1_Reserved1:16;
		uint32_t T1_DLC:4;					//【0~8|发送数据为0~8】【9~15|经典CAN为8,FDCAN为12/16/20/24/32/48/64】
		uint32_t T1_BRS:1;					//【0|无波特率切换】【1|有波特率切换】
		uint32_t T1_FDF:1;					//【0|经典CAN】【1|FDCAN】
		uint32_t T1_Reserved2:1;
		uint32_t T1_EFC:1;					//【0|不保存TX事件】【1|保存】
		uint32_t T1_MM:8;					// 

		uint32_t DataWord[16];
	}bit_29ID;
	struct
	{
		uint32_t T0_Reserved:18;
		uint32_t T0_ID:11;					// ID
		uint32_t T0_RTR:1;					//【0|发送数据帧】【1|发送远程帧】
		uint32_t T0_XTD:1;					//【0|11-bit】【1|29-bit】
		uint32_t T0_ESI:1;					// 
		
		uint32_t T1_Reserved1:16;
		uint32_t T1_DLC:4;					//【0~8|发送数据为0~8】【9~15|经典CAN为8,FDCAN为12/16/20/24/32/48/64】
		uint32_t T1_BRS:1;					//【0|无波特率切换】【1|有波特率切换】
		uint32_t T1_FDF:1;					//【0|经典CAN】【1|FDCAN】
		uint32_t T1_Reserved2:1;
		uint32_t T1_EFC:1;					//【0|不保存TX事件】【1|保存】
		uint32_t T1_MM:8;					// 

		uint32_t DataWord[16];
	}bit_11ID;
}FDCAN_Buffer_Union;

6. FDCAN的初始化

IO口配置我就不介绍了,想必大家都会配置IO。

  1. 首先在RCC->APB1RSTR1寄存器中使能RCC_APB1ENR1_FDCANEN,这样FDCAN的寄存器就可以配置了。
  2. 然后选择FDCAN内核时钟的时钟源,在RCC->CCIPR寄存器的RCC_CCIPR_FDCANSEL中配置。
  3. 置位INIT标志位,开始配置寄存器(只有INIT标志位置位,才可置位CCE标志位)
  4. 等待INIT标志位置位
  5. 置位CCE标志位,解锁受保护的寄存器
  6. 等待CCE标志位置位
  7. 配置时钟分频 (FDCAN_CKDIV 寄存器)
  8. 配置波特率
  9. 配置中断
  10. 配置筛选器
  11. 使能筛选器
  12. 清除INIT标志位

初始化代码见

附录1.1 RCC配置
附录1.2 FDCAN寄存器配置

7. 发送操作

7.1 FDCAN帧模式

FDCAN帧模式由下表各个标志位配置:

在这里插入图片描述

根据上表所示,可以通过 CCCR寄存器Tx Buffer 内部的标志位 配合,实现不同模式的CAN。
由于鄙人只想使用 经典CAN,因此将 CCCR寄存器 中的 FDOE 配置为 0,其他标志位我就不管了。

7.2 发送步骤

  1. 读取 FDCAN1->TXFQS 是否有可用信箱( FDCAN_TXFQS_TFQF 是否置位)
  2. 如果没置位邮箱满标志,则查询 FDCAN_TXFQS_TFQPI 索引,获得的索引就是可以写入的邮箱
  3. 将要发送的数据写入刚才读取的索引的 Tx Buffer 中(在这里可以配置发送长度、ID等信息)
  4. 置位发送请求
  5. 等待发送完成(可以不等待,配置发送完成中断使能后,在中断中置位发送完成标志来判断是否发送完毕)

示例代码见
附录2 发送函数

8. 接收操作

首先配置筛选器来选择接收的消息和接收后存放的FIFO。

接收分为 覆盖模式阻塞模式
覆盖模式 顾名思义,就是当FIFO满了以后,接收到新消息后覆盖老消息。
阻塞模式 就是当FIFO满了之后,忽略新消息,保留老消息。

Rx FIFO 0 接收到消息后,将会在 FDCAN_RXF0S 寄存器中 F0GI 标志位指示新消息存储索引,当 CPU 读取这些消息后,务必将最后 F0GI 的值写入到 FDCAN_RXF0AF0AI 标志位,来确认来读取完毕,这会将 FDCAN_RXF0S寄存器中的索引标志位 F0GI 设置为 F0AI + 1 并更新 FIFO 0 的存储计数 (FDCAN_RXF0S 寄存器中 F0FL 标志位,范围0~3),如果不确认读取完毕,将会导致指示索引 F0GI 失效。

接收操作可以在中断中进行,通过配置 FDCAN_IE 寄存器中的相应 中断使能标志位 来开启中断。如:使能 FIFO0 接收新消息中断就置位 FDCAN_IE_RF0NE 标志位。

因此,接收操作的步骤为:

  1. 读取接收的数据
  2. 确认读取完毕

接收程序见
附录3 中断程序

9. 参考资料传送门

9.1 代码下载(0积分)

代码下载(0积分)

9.2 其他 CAN 知识了解

其他 CAN 知识了解

附录1 初始化

附录1.1 RCC配置

为方便其他模块配置,将其他模块的RCC列表了出来,方便当库文件使用

返回第6章

void RCC_Init(void)//
{
	//--------------------------------------------------------------------------------------//
	//---------------------------------------- AHB1 ----------------------------------------//
	//--------------------------------------------------------------------------------------//
	RCC->AHB1RSTR |= 0			//default: 0x0000 0000
					//	|RCC_AHB1RSTR_CRCRST		//bit12
					//	|RCC_AHB1RSTR_FLASHRST		//bit08
					//	|RCC_AHB1RSTR_FMACRST		//bit04
					//	|RCC_AHB1RSTR_CORDICRST		//bit03
					//	|RCC_AHB1RSTR_DMAMUX1RST	//bit02
					//	|RCC_AHB1RSTR_DMA2RST		//bit01
					//	|RCC_AHB1RSTR_DMA1RST		//bit00
					;
	RCC->AHB1RSTR &= 0xffffffff	//default: 0x0000 0000
					//	&~RCC_AHB1RSTR_CRCRST		//bit12
					//	&~RCC_AHB1RSTR_FLASHRST		//bit08
					//	&~RCC_AHB1RSTR_FMACRST		//bit04
					//	&~RCC_AHB1RSTR_CORDICRST	//bit03
					//	&~RCC_AHB1RSTR_DMAMUX1RST	//bit02
					//	&~RCC_AHB1RSTR_DMA2RST		//bit01
					//	&~RCC_AHB1RSTR_DMA1RST		//bit00
					;
	
	RCC->AHB1ENR |= 0			//default: 0x0000 0100
					//	|RCC_AHB1ENR_CRCEN			//bit12
					//	|RCC_AHB1ENR_FLASHEN		//bit08
					//	|RCC_AHB1ENR_FMACEN			//bit04
					//	|RCC_AHB1ENR_CORDICEN		//bit03
					//	|RCC_AHB1ENR_DMAMUX1EN		//bit02
					//	|RCC_AHB1ENR_DMA2EN			//bit01
					//	|RCC_AHB1ENR_DMA1EN			//bit00
					;
	//--------------------------------------------------------------------------------------//
	//---------------------------------------- AHB2 ----------------------------------------//
	//--------------------------------------------------------------------------------------//
	RCC->AHB2RSTR |= 0			//defualt: 0x0000 0000
					//	|RCC_AHB2RSTR_RNGRST		//bit26
					//	|RCC_AHB2RSTR_RNGRST		//bit24
					//	|RCC_AHB2RSTR_DAC4RST		//bit19
					//	|RCC_AHB2RSTR_DAC3RST		//bit18
					//	|RCC_AHB2RSTR_DAC2RST		//bit17
					//	|RCC_AHB2RSTR_DAC1RST		//bit16
						|RCC_AHB2RSTR_ADC345RST		//bit14
						|RCC_AHB2RSTR_ADC12RST		//bit13
					//	|RCC_AHB2RSTR_GPIOGRST		//bit06
						|RCC_AHB2RSTR_GPIOFRST		//bit05
						|RCC_AHB2RSTR_GPIOERST		//bit04
						|RCC_AHB2RSTR_GPIODRST		//bit03
						|RCC_AHB2RSTR_GPIOCRST		//bit02
						|RCC_AHB2RSTR_GPIOBRST		//bit01
						|RCC_AHB2RSTR_GPIOARST		//bit00
					;
	RCC->AHB2RSTR &= 0xffffffff	//defualt: 0x0000 0000
					//	&~RCC_AHB2RSTR_RNGRST		//bit26
					//	&~RCC_AHB2RSTR_RNGRST		//bit24
					//	&~RCC_AHB2RSTR_DAC4RST		//bit19
					//	&~RCC_AHB2RSTR_DAC3RST		//bit18
					//	&~RCC_AHB2RSTR_DAC2RST		//bit17
					//	&~RCC_AHB2RSTR_DAC1RST		//bit16
						&~RCC_AHB2RSTR_ADC345RST	//bit14
						&~RCC_AHB2RSTR_ADC12RST		//bit13
					//	&~RCC_AHB2RSTR_GPIOGRST		//bit06
						&~RCC_AHB2RSTR_GPIOFRST		//bit05
						&~RCC_AHB2RSTR_GPIOERST		//bit04
						&~RCC_AHB2RSTR_GPIODRST		//bit03
						&~RCC_AHB2RSTR_GPIOCRST		//bit02
						&~RCC_AHB2RSTR_GPIOBRST		//bit01
						&~RCC_AHB2RSTR_GPIOARST		//bit00
					;
	RCC->AHB2ENR = 0			//default: 0x0000 0000
					//	|RCC_AHB2ENR_RNGEN			//bit26
					//	|RCC_AHB2ENR_DAC4EN			//bit19
					//	|RCC_AHB2ENR_DAC3EN			//bit18
					//	|RCC_AHB2ENR_DAC2EN			//bit17
					//	|RCC_AHB2ENR_DAC1EN			//bit16
						|RCC_AHB2ENR_ADC345EN		//bit14
						|RCC_AHB2ENR_ADC12EN		//bit13
					//	|RCC_AHB2ENR_GPIOGEN		//bit06
						|RCC_AHB2ENR_GPIOFEN		//bit05
						|RCC_AHB2ENR_GPIOEEN		//bit04
						|RCC_AHB2ENR_GPIODEN		//bit03
						|RCC_AHB2ENR_GPIOCEN		//bit02
						|RCC_AHB2ENR_GPIOBEN		//bit01
						|RCC_AHB2ENR_GPIOAEN		//bit00
					;
	//--------------------------------------------------------------------------------------//
	//---------------------------------------- AHB3 ----------------------------------------//
	//--------------------------------------------------------------------------------------//
	RCC->AHB3RSTR |= 0			//default:0x0000 0000
					//	|RCC_AHB3RSTR_QSPIRST		//bit08
					//	|RCC_AHB3RSTR_FMCRST		//bit00
					;
	RCC->AHB3RSTR &= 0xffffffff	//default:0x0000 0000
					//	&~RCC_AHB3RSTR_QSPIRST		//bit08
					//	&~RCC_AHB3RSTR_FMCRST		//bit00
					;

	RCC->AHB3ENR |= 0			//default: 0x0000 0000
					//	|RCC_AHB3ENR_QSPIEN			//bit08
					//	|RCC_AHB3ENR_FMCEN			//bit00
					;
	//--------------------------------------------------------------------------------------//
	//---------------------------------------- APB1 ----------------------------------------//
	//--------------------------------------------------------------------------------------//
	RCC->APB1RSTR1 |= 0			//default: 0x0000 0000
					//	|RCC_APB1RSTR1_LPTIM1RST	//bit31
					//	|RCC_APB1RSTR1_I2C3RST		//bit30
					//	|RCC_APB1RSTR1_PWRRST		//bit28
						|RCC_APB1RSTR1_FDCANRST		//bit25
					//	|RCC_APB1RSTR1_USBRST		//bit23
					//	|RCC_APB1RSTR1_I2C2RST		//bit22
					//	|RCC_APB1RSTR1_I2C1RST		//bit21
					//	|RCC_APB1RSTR1_UART5RST		//bit20
					//	|RCC_APB1RSTR1_UART4RST		//bit19
					//	|RCC_APB1RSTR1_USART3RST	//bit18
					//	|RCC_APB1RSTR1_USART2RST	//bit17
					//	|RCC_APB1RSTR1_SPI3RST		//bit15
					//	|RCC_APB1RSTR1_SPI2RST		//bit14
					//	|RCC_APB1RSTR1_CRSRST		//bit08
						|RCC_APB1RSTR1_TIM7RST		//bit05
						|RCC_APB1RSTR1_TIM6RST		//bit04
					//	|RCC_APB1RSTR1_TIM5RST		//bit03
						|RCC_APB1RSTR1_TIM4RST		//bit02
						|RCC_APB1RSTR1_TIM3RST		//bit01
						|RCC_APB1RSTR1_TIM2RST		//bit00
					;
	RCC->APB1RSTR1 &= 0xffffffff//default: 0x0000 0000
					//	&~RCC_APB1RSTR1_LPTIM1RST	//bit31
					//	&~RCC_APB1RSTR1_I2C3RST		//bit30
					//	&~RCC_APB1RSTR1_PWRRST		//bit28
						&~RCC_APB1RSTR1_FDCANRST	//bit25
					//	&~RCC_APB1RSTR1_USBRST		//bit23
					//	&~RCC_APB1RSTR1_I2C2RST		//bit22
					//	&~RCC_APB1RSTR1_I2C1RST		//bit21
					//	&~RCC_APB1RSTR1_UART5RST	//bit20
					//	&~RCC_APB1RSTR1_UART4RST	//bit19
					//	&~RCC_APB1RSTR1_USART3RST	//bit18
					//	&~RCC_APB1RSTR1_USART2RST	//bit17
					//	&~RCC_APB1RSTR1_SPI3RST		//bit15
					//	&~RCC_APB1RSTR1_SPI2RST		//bit14
					//	&~RCC_APB1RSTR1_CRSRST		//bit08
						&~RCC_APB1RSTR1_TIM7RST		//bit05
						&~RCC_APB1RSTR1_TIM6RST		//bit04
					//	&~RCC_APB1RSTR1_TIM5RST		//bit03
						&~RCC_APB1RSTR1_TIM4RST		//bit02
						&~RCC_APB1RSTR1_TIM3RST		//bit01
						&~RCC_APB1RSTR1_TIM2RST		//bit00
					;

	RCC->APB1ENR1 |= 0			//default: 0x0000 0400
					//	|RCC_APB1ENR1_LPTIM1EN		//bit31
					//	|RCC_APB1ENR1_I2C3EN		//bit30
					//	|RCC_APB1ENR1_PWREN			//bit28
						|RCC_APB1ENR1_FDCANEN		//bit25
					//	|RCC_APB1ENR1_USBEN			//bit23
					//	|RCC_APB1ENR1_I2C2EN		//bit22
					//	|RCC_APB1ENR1_I2C1EN		//bit21
					//	|RCC_APB1ENR1_UART5EN		//bit20
					//	|RCC_APB1ENR1_UART4EN		//bit19
					//	|RCC_APB1ENR1_USART3EN		//bit18
					//	|RCC_APB1ENR1_USART2EN		//bit17
					//	|RCC_APB1ENR1_SPI3EN		//bit15
					//	|RCC_APB1ENR1_SPI2EN		//bit14
					//	|RCC_APB1ENR1_WWDGEN		//bit11
					//	|RCC_APB1ENR1_RTCAPBEN		//bit10
					//	|RCC_APB1ENR1_CRSEN			//bit08
						|RCC_APB1ENR1_TIM7EN		//bit05
						|RCC_APB1ENR1_TIM6EN		//bit04
					//	|RCC_APB1ENR1_TIM5EN		//bit03
						|RCC_APB1ENR1_TIM4EN		//bit02
						|RCC_APB1ENR1_TIM3EN		//bit01
						|RCC_APB1ENR1_TIM2EN		//bit00
					;


	RCC->APB1RSTR2 |= 0			//default: 0x0000 0000
					//	|RCC_APB1RSTR2_UCPD1RST		//bit08
					//	|RCC_APB1RSTR2_I2C4RST		//bit01
					//	|RCC_APB1RSTR2_LPUART1RST	//bit00
					;
	RCC->APB1RSTR2 &= 0xffffffff//default: 0x0000 0000
					//	&~RCC_APB1RSTR2_UCPD1RST	//bit08
					//	&~RCC_APB1RSTR2_I2C4RST		//bit01
					//	&~RCC_APB1RSTR2_LPUART1RST	//bit00
					;

	RCC->APB1ENR2 |= 0			//default: 0x0000 0000
					//	|RCC_APB1ENR2_UCPD1EN		//bit08
					//	|RCC_APB1ENR2_I2C4EN		//bit01
					//	|RCC_APB1ENR2_LPUART1EN		//bit00
					;
	//--------------------------------------------------------------------------------------//
	//---------------------------------------- APB2 ----------------------------------------//
	//--------------------------------------------------------------------------------------//
	RCC->APB2RSTR |= 0			//default: 0x0000 0000
				//	|RCC_APB2RSTR_HRTIM1RST		//bit26
				//	|RCC_APB2RSTR_SAI1RST		//bit21
				//	|RCC_APB2RSTR_TIM20RST		//bit20
					|RCC_APB2RSTR_TIM17RST		//bit18
					|RCC_APB2RSTR_TIM16RST		//bit17
					|RCC_APB2RSTR_TIM15RST		//bit16
				//  |RCC_APB2RSTR_SPI4RST		//bit15
					|RCC_APB2RSTR_USART1RST		//bit14
					|RCC_APB2RSTR_TIM8RST		//bit13
				//	|RCC_APB2RSTR_SPI1RST		//bit12
					|RCC_APB2RSTR_TIM1RST		//bit11
					|RCC_APB2RSTR_SYSCFGRST		//bit00
					;
	RCC->APB2RSTR &= 0xffffffff	//default: 0x0000 0000
					//	&~RCC_APB2RSTR_HRTIM1RST	//bit26
					//	&~RCC_APB2RSTR_SAI1RST		//bit21
					//	&~RCC_APB2RSTR_TIM20RST		//bit20
						&~RCC_APB2RSTR_TIM17RST		//bit18
						&~RCC_APB2RSTR_TIM16RST		//bit17
						&~RCC_APB2RSTR_TIM15RST		//bit16
					//	&~RCC_APB2RSTR_SPI4RST		//bit15
						&~RCC_APB2RSTR_USART1RST	//bit14
						&~RCC_APB2RSTR_TIM8RST		//bit13
					//	&~RCC_APB2RSTR_SPI1RST		//bit12
						&~RCC_APB2RSTR_TIM1RST		//bit11
						&~RCC_APB2RSTR_SYSCFGRST	//bit00
					;

	RCC->APB2ENR |= 0			//default: 0x0000 0000
					//	|RCC_APB2ENR_HRTIM1EN		//bit26
					//	|RCC_APB2ENR_SAI1EN			//bit21
					//	|RCC_APB2ENR_TIM20EN		//bit20
						|RCC_APB2ENR_TIM17EN		//bit18
						|RCC_APB2ENR_TIM16EN		//bit17
						|RCC_APB2ENR_TIM15EN		//bit16
					//	|RCC_APB2ENR_SPI4EN			//bit15
						|RCC_APB2ENR_USART1EN		//bit14
						|RCC_APB2ENR_TIM8EN			//bit13
					//	|RCC_APB2ENR_SPI1EN			//bit12
						|RCC_APB2ENR_TIM1EN			//bit11
						|RCC_APB2ENR_SYSCFGEN		//bit00
					;

	RCC->CCIPR |= 0
					// |(0 << RCC_CCIPR_ADC345SEL_Pos)		//
					// |(0 << RCC_CCIPR_ADC12SEL_Pos)		//
					// |(0 << RCC_CCIPR_CLK48SEL_Pos)		//
					|(0 << RCC_CCIPR_FDCANSEL_Pos)		//HSE 8MHz 
					// |(0 << RCC_CCIPR_I2S23SEL_Pos)		//
					// |(0 << RCC_CCIPR_SAI1SEL_Pos)		//
					// |(0 << RCC_CCIPR_LPTIM1SEL_Pos)		//
					// |(0 << RCC_CCIPR_I2C3SEL_Pos)		//
					// |(0 << RCC_CCIPR_I2C2SEL_Pos)		//
					// |(0 << RCC_CCIPR_I2C1SEL_Pos)		//
					// |(0 << RCC_CCIPR_LPUART1SEL_Pos)	//
					// |(0 << RCC_CCIPR_UART5SEL_Pos)		//
					// |(0 << RCC_CCIPR_UART4SEL_Pos)		//
					// |(0 << RCC_CCIPR_USART3SEL_Pos)		//
					// |(0 << RCC_CCIPR_USART2SEL_Pos)		//
					// |(0 << RCC_CCIPR_USART1SEL_Pos)		//
					;
}

返回第6章

附录1.2 FDCAN寄存器配置

返回第6章

/**
 * @description: FDCAN1经典CAN模式,波特率250k
 * @param {*}
 * @return {*}
 */
void FDCAN1_Function_Init(void)
{
	//在RCC_CCIPR寄存器中选择FDCAN时钟为HSE,即8MHz
	//
	FDCAN1->CCCR |= FDCAN_CCCR_INIT;				//置位INIT
	while (!(FDCAN1->CCCR & FDCAN_CCCR_INIT));		//等待置位
	FDCAN1->CCCR |= FDCAN_CCCR_CCE;					//置位CCE
	while (!(FDCAN1->CCCR & FDCAN_CCCR_CCE));		//等待置位
	FDCAN1->CCCR |= 0
					// |FDCAN_CCCR_NISO				//bit15: 【0|ISO11898-1】【1|CANFD v1.0】
					// |FDCAN_CCCR_TXP					//bit14: 【1|在下上一个成功帧后暂停两个bit再起始】
					// |FDCAN_CCCR_EFBI				//bit13: 【1|同步检测边沿需要两个显性tq】
					// |FDCAN_CCCR_PXHD				//bit12: 【0|启动协议异常处理】【1|禁用协议异常处理】
					// |FDCAN_CCCR_BRSE				//bit09: 【1|启用波特率切换】
					// |FDCAN_CCCR_FDOE				//bit08: 【0|FD操作禁止】【1|FD操作使能】
					// |FDCAN_CCCR_TEST				//bit07: 【1|测试模式使能】
					|FDCAN_CCCR_DAR					//bit06: 【0|启用发送失败后自动重传】【1|禁止自动重传】
					// |FDCAN_CCCR_MON					//bit05: 【0|总线监控模式禁止】【1|总线监控模式使能】
					// |FDCAN_CCCR_CSR					//bit04: 【0|无时钟停止请求】【1|时钟停止请求,当时钟停止请求发生,先置位INIT在置位CSA在所有传输请求完成并且CAN总线空闲】
					// |FDCAN_CCCR_CSA					//bit03: 【0|没有时钟停止】【1|FDCAN可通过停止APB时钟和内核时钟来进行掉电】
					// |FDCAN_CCCR_ASM					//bit02: 【1|启用限制模式,限制模式下不会主动发送数据】
					// |FDCAN_CCCR_CCE					//bit01: 【1|允许配置受保护的寄存器,INIT标志位必须置位】
					// |FDCAN_CCCR_INIT				//bit00: 【1|初始化开始】
					;
	FDCAN_CONFIG->CKDIV = 0;						//fdcan_clk = RCC_CCIPR_FDCAN1CLK / CKDIV
	FDCAN1->NBTP = 0
					|(7 << FDCAN_NBTP_NSJW_Pos)		//bit[31:25]: 同步脉宽 务必小于 二阶段采样
					|(0 << FDCAN_NBTP_NBRP_Pos)		//bit[24:16]: BRP。 tq = (BRP + 1)*fdcan_clk
					|(22 << FDCAN_NBTP_NTSEG1_Pos)	//bit[15:08]: 一阶段采样
					|(7 << FDCAN_NBTP_NTSEG2_Pos)	//bit[06:00]: 二阶段采样  波特率 = fdcan_clk/(BRP + 1)/(3+DTSEG1+DTSEG2) = 8000000/(0+1)/(3+22+7) = 250k
					;
	// FDCAN1->DBTP = 0								//数据帧的波特率(经典CAN可忽略)
	// 				|FDCAN_DBTP_TDC					//bit23: 【1|收发延时补偿使能】
	// 				|(0 << FDCAN_DBTP_DBRP_Pos)		//bit[20:16]: tq = (BRP + 1)*fdcan_clk
	// 				|(22 << FDCAN_DBTP_DTSEG1_Pos)	//bit[12:08]: 一阶段采样
	// 				|(7 << FDCAN_DBTP_DTSEG2_Pos)	//bit[07:04]: 二阶段采样 波特率 = 8000000/(3+DTSEG1+DTSEG2) = 8000000/32 = 250k
	// 				|(7 << FDCAN_DBTP_DSJW_Pos)		//bit[03:00]: 同步脉宽
	// 				;
	FDCAN1->IE |= 0
					// |FDCAN_IE_ARAE					//bit23: 访问保留地址使能
					// |FDCAN_IE_PEDE					//bit22: 数据阶段协议错误
					// |FDCAN_IE_PEAE					//bit21: 仲裁阶段协议错误
					// |FDCAN_IE_WDIE					//bit20: 看门狗使能
					// |FDCAN_IE_BOE					//bit19: 总线关闭使能
					// |FDCAN_IE_EWE					//bit18: 警告状态中断使能
					// |FDCAN_IE_EPE					//bit17: 错误被动中断使能
					// |FDCAN_IE_ELOE					//bit16: 错误记录语出中断使能
					// |FDCAN_IE_TOOE					//bit15: 超时中断使能
					// |FDCAN_IE_MRAFE					//bit14: 信息RAM访问失败中断使能
					// |FDCAN_IE_TSWE					//bit13: 时间戳重复中断使能
					// |FDCAN_IE_TEFLE					//bit12: TX事件FIFO元素丢失中断使能
					// |FDCAN_IE_TEFFE					//bit11: TX时间FIFO满中断使能
					// |FDCAN_IE_TEFNE					//bit10: TX事件FIFO新元素进入中断使能
					// |FDCAN_IE_TFEE					//bit09: TXFIFO空中断使能
					// |FDCAN_IE_TCFE					//bit08: 发送取消完成中断使能
					|FDCAN_IE_TCE					//bit07: 传输完成中断使能
					// |FDCAN_IE_HPME					//bit06: 高优先级消息中断使能
					// |FDCAN_IE_RF1LE					//bit05: RXFIFO1报文丢失中断使能
					// |FDCAN_IE_RF1FE					//bit04: RXFIFO1消息满中断使能
					|FDCAN_IE_RF1NE					//bit03: RXFIFO1新消息中断使能
					// |FDCAN_IE_RF0LE					//bit02: RXFIFO0报文丢失中断使能
					// |FDCAN_IE_RF0FE					//bit01: RXFIFO0消息满中断使能
					|FDCAN_IE_RF0NE					//bit00: RXFIFO0新消息中断使能
					;
	FDCAN1->ILE = 0x00000000
					|FDCAN_ILE_EINT1					//bit01: 中断总线 fdcan_intr1_it 使能
					|FDCAN_ILE_EINT0					//bit00: 中断总线 fdcan_intr0_it 使能
					;
	FDCAN1->RXGFC = 0
					// |(0 << FDCAN_RXGFC_LSE_Pos)		//bit[27:24]: 列表信息拓展【0|无拓展消息过滤】【1|1~8拓展消息】【>8|被解释为8】
					|(1 << FDCAN_RXGFC_LSS_Pos)		//bit[20:16]: 【0|无标准消息ID过滤】【1~28|标准消息ID元素过滤数量】【>28|被解释为28】
					// |FDCAN_RXGFC_F0OM				//bit09: FIFO0模式:覆盖或者堵塞【0|阻塞模式】【1|覆盖模式】
					// |FDCAN_RXGFC_F1OM				//bit08: FIFO1模式:覆盖或者堵塞【0|阻塞模式】【1|覆盖模式】
					// |(0 << FDCAN_RXGFC_ANFS_Pos)	//bit[05:04]: 定义如何处理接收到的id为11位且与筛选器列表中的任何元素不匹配的消息。【0|在FIFO0中接收】【1|在FIFO1中接收】【2~3|拒绝】
					// |(0 << FDCAN_RXGFC_ANFE_Pos)	//bit[03:02]: 定义如何处理接收到的id为29位且与筛选器列表中的任何元素不匹配的消息。【0|在FIFO0中接收】【1|在FIFO1中接收】【2~3|拒绝】
					// |FDCAN_RXGFC_RRFS				//bit01: 【1|拒绝所有11位ID远程标准帧】
					// |FDCAN_RXGFC_RRFE				//bit00: 【1|拒绝所有29位ID远程标准帧】
					;
	FDCAN1->XIDAM = 0x1FFFFFFF;						//FDCAN 扩展 ID 和屏蔽寄存器 
	FDCAN1->TXBTIE = 0
					// |0x00000004						//bit02: TxBuffer【1|发送中断使能】
					// |0x00000002						//bit01: TxBuffer【1|发送中断使能】
					 |0x00000001						//bit00: TxBuffer【1|发送中断使能】
					;
	FDCAN1->TXBCIE = 0
					// |0x00000004						//bit02: TxBuffer【1|取消中断使能】
					// |0x00000002						//bit01: TxBuffer【1|取消中断使能】
					// |0x00000001						//bit00: TxBuffer【1|取消中断使能】
					;

	FDCAN1_RAM->FILTER_11BIT[0] = 0x00000000
								|(1 << FDCANx_RAM_FILTER11_S0_SFT_Pos)
								|(1 << FDCANx_RAM_FILTER11_S0_SFEC_Pos)
								|(0x209 << FDCANx_RAM_FILTER11_S0_SFID1_Pos)
								|(0x609 << FDCANx_RAM_FILTER11_S0_SFID2_Pos)
								;

	// FDCAN1_RAM->FILTER_11BIT[1] = 0x00000000
	// 							|(1 << FDCANx_RAM_FILTER11_S0_SFT_Pos)
	// 							|(1 << FDCANx_RAM_FILTER11_S0_SFEC_Pos)
	// 							|(0x209 << FDCANx_RAM_FILTER11_S0_SFID1_Pos)
	// 							|(0x609 << FDCANx_RAM_FILTER11_S0_SFID2_Pos)
	// 							;

	FDCAN1->RXGFC = 0x00000000
					|(0 << FDCAN_RXGFC_LSE_Pos)			//bit[27:24]: 29-bit ID列表大小【0|无拓展帧ID滤波】【1~8|29bitID列表大小数】【>8|认为是8】
					|(1 << FDCAN_RXGFC_LSS_Pos)			//bit[20:16]: 11-bit ID列表大小【0|无拓展帧ID滤波】【1~28|11bitID列表大小数】【>28|认为是28】
					|FDCAN_RXGFC_F0OM					//bit09: FIFO0的接收模式(【0|阻塞】或【1|覆盖】)
					|FDCAN_RXGFC_F1OM					//bit08: FIFO1的接收模式(【0|阻塞】或【1|覆盖】)
					|(1 << FDCAN_RXGFC_ANFS_Pos)		//bit[05:04]: 不匹配的29-bitID接收配置【0|FIFO0接收】【1|FIFO1接收】【2~3|拒绝】
					|(1 << FDCAN_RXGFC_ANFE_Pos)		//bit[03:02]: 不匹配的11-bitID接收配置【0|FIFO0接收】【1|FIFO1接收】【2~3|拒绝】
					// |FDCAN_RXGFC_RRFS					//bit01: 拒绝远程帧【1|拒绝所有带有 11 位标准 ID 的远程帧】
					// |FDCAN_RXGFC_RRFE					//bit00: 拒绝远程拓展帧【1|拒绝所有带有 29 位标准 ID 的远程帧】
					;

	FDCAN1->CCCR &= ~FDCAN_CCCR_INIT;
	while (FDCAN1->CCCR & FDCAN_CCCR_INIT);
}

返回第6章

附录2 发送函数

返回第7章

/**
 * @description: 经典CAN模式,11-bit地址,发送数据帧或远程帧,使用该函数之前应判断该信箱是否空闲,
 * 				否则会导致发送失败
 * @param {uint16_t} ID		11位ID
 * @param {uint8_t} RTR		【0|发送数据帧】【1|发送远程帧】
 * @param {uint8_t} DLC		【0~8|发送数据数量为0~8】
 * @param {uint8_t} *buffer	数据地址
 * @return {*}
 */
void FDCAN1_TxBuffer1_SendData_11ID(uint16_t ID,uint8_t RTR,uint8_t DLC,Buffer_64Byte_Struct *buffer)
{
	FDCAN1_TXBUFFER1->bit_11ID.T0_ESI = 0;//
	FDCAN1_TXBUFFER1->bit_11ID.T0_XTD = 0;//【0|11-bit】【1|29-bit】
	FDCAN1_TXBUFFER1->bit_11ID.T0_RTR = 0;//【0|发送数据帧】【1|发送远程帧】
	FDCAN1_TXBUFFER1->bit_11ID.T0_ID = ID;

	FDCAN1_TXBUFFER1->bit_11ID.T1_MM = 0;
	FDCAN1_TXBUFFER1->bit_11ID.T1_EFC = 0;//【0|不保存TX事件】【1|保存】
	FDCAN1_TXBUFFER1->bit_11ID.T1_FDF = 0;//【0|经典CAN】【1|FDCAN】
	FDCAN1_TXBUFFER1->bit_11ID.T1_BRS = 0;//【0|无波特率切换】【1|有波特率切花】
	FDCAN1_TXBUFFER1->bit_11ID.T1_DLC = DLC;//【0~8|发送数据为0~8】【9~15|经典CAN为8,FDCAN为12/16/20/24/32/48/64】

	FDCAN1_TXBUFFER1->bit_11ID.DataWord[0] = buffer->DataWord[0];
	FDCAN1_TXBUFFER1->bit_11ID.DataWord[1] = buffer->DataWord[1];

	FDCAN1->TXBAR |= 0x00000000
					// |BIT2
					// |BIT1
					|BIT0
					;
}

返回第7章

附录3 中断程序

返回第7章
返回第8章


void FDCAN1_IT1_IRQHandler(void)
{
	uint8_t temp;
	if(FDCAN1->IR & FDCAN_IR_RF1N)//FIFO1有新消息标志
	{
		FDCAN1->IR |= FDCAN_IR_RF1N;//清除新消息标志
		temp = FDCAN1->RXF1S & FDCAN_RXF1S_F1GI) >> FDCAN_RXF1S_F0GI_Pos;
		CAN_Rxbuffer[4] = FDCAN1_RAM->Rx_FIFO_1[temp][0];//读取地址和拓展帧标志等
		CAN_Rxbuffer[5] = FDCAN1_RAM->Rx_FIFO_1[temp][1];//读取数据长度等
		CAN_Rxbuffer[6] = FDCAN1_RAM->Rx_FIFO_1[temp][2];//读取4byte数据
		CAN_Rxbuffer[7] = FDCAN1_RAM->Rx_FIFO_1[temp][3];//读取4byte数据,算上上面的 一共8个byte
		FDCAN1->RXF1A = temp;//返回读取完成
	}
}

返回第7章
返回第8章

版权声明:本文为CSDN博主「Vice Versa XL」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xl22126/article/details/118514472

生成海报
点赞 0

Vice Versa XL

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

在STM32H750XB上使用LWIP

在STM32H750XB上使用LWIP,H743等芯片也适用。主要讲述了配置H7的LWIP,与F4的不同之处。 1.时钟树,主频400MHz 2.MPU配置 3.ETH的GPIO配置,设