行情
HOME
行情
正文内容
stm32 nand 例子 当STM32遇到SDRAM
发布时间 : 2025-04-19
作者 : 小编
访问数量 : 23
扫码分享至微信

当STM32遇到SDRAM

SDRAM是DRAM(动态随机访问存储器)的一种,是最为普遍使用的大容量RAM——俗称内存。(不过“内存”本来是“内部存储器”的意思,相对于“外部存储器”——磁盘、磁带、光盘等。ROM实际上也属于内部的存储器,只不过不可写只能放固定的信息。但是有了EEPROM、Flash ROM之后,因为这些存储芯片也可以改写,就把“内存”和RAM的概念搅混了——卖手机的告诉你内存有多大。实际上Flash ROM的地位等同于以前的硬盘。)目前PC、服务器以及便携设备的RAM大部分是DDR RAM,也是SDRAM的一种(DDR SDRAM),而一般说SDRAM被用来指非DDR的SDRAM了。

先看一下DRAM这类存储器的内部结构

每一个存储单元(1 bit)都是一个小电容加上控制它开关的晶体管,靠电容上有没有存储电荷来记忆0还是1的。所有的存储单元按行列排成一个矩阵:行控制线控制一行晶体管门极(控制通断),列控制线则连接一列晶体管漏极。这样选中某一行时,这一行存储单元的电容就反映在列控制线上:可以读电压判断是0还是1,可以充电或者放电来改写这一行单元。实际的DRAM芯片要比这个复杂,首先电容会漏电,所以需要过一段时间就重新充电或放电来保持记忆;又比如因为矩阵太大了,线上的分布电容比存储单元还要大得多,所以需要Sense amplifier来放大微小电压,需要在读之前给列控制线上的电容进行预充电;又比如因为列数量大于数据总线宽度,一次读取的数据需要锁存起来供多个数据总线周期访问等等,所以控制逻辑是比SRAM复杂的。但是因为单元简单所以DRAM芯片容量做得很大,成本比SRAM要低很多。

SDRAM这个词的"D"代表动态,"S"代表同步,表示它需要一个时钟信号,读写信号在时钟沿上有效。重要的信号除了 CLK, CLKE(时钟允许), /CS(片选) 外,还有

/RAS (低有效): Row Address Strobe, 行地址输入。SDRAM的地址是行和列复用的,省了引脚啊。

/CAS (低有效): Column Address Strobe, 列地址输入。

/WE (低有效): 写使能

但这三个信号并不是按它们的本意单独使用的,而是组合起来定义了若干命令:

除了读和写的命令,还有配置SDRAM模式寄存器的命令,有维持电容(记忆需要)的刷新命令,有预充电的命令等。在读一个位置数据之前,要先选择所在的行,再输出列地址,等待数据准备好……看起来有点复杂了吧,一连串的SDRAM读操作可能是这样的:

所以,SDRAM读数据远远不如SRAM那么简单,SRAM只要把地址送过去,OE一拉低,随后数据就出来到总线上了。SDRAM首先得把行地址送过去,再把列地址送过去,然后SDRAM还要墨迹几个周期,数据才开始送出来。不过有流水线操作,连续读一个行内数据的时候吞吐速度还是有保证的。与SRAM的对比,主要劣势在于延迟大。

在单片系统里,如果片上的RAM不够用来存储频繁更新的数据或者程序,外扩RAM是一个解决办法。在引脚资源丰富的单片机上,大都可以连接SRAM,例如STM32F103就有FSMC控制器,但是SRAM芯片成本高且不便宜。要用SDRAM,必须要带有SDRAM控制器的MCU,用GPIO模拟?还是算了吧。ST的单片机我用过不少了,在F4,F7系列某些型号上,是带有支持SDRAM的FMC控制器的,提供了使用SDRAM的途径,不过一定要144 pin以上的器才可以有对应的引脚分配。

可惜的是Nucleo-144开发板上是不带SDRAM的,得Discovery上才有可能了。我自己DIY了一块F746Z的开发板 【2月DIY】STM32F7开发板自己造,为了参考评估又从论坛借来了一块F429i Discovery开发板。从官方的电路图上可以学习SDRAM是怎样与MCU连接的。

除了Axx地址线,Dxx数据线,NBLx字节选择线这几组是和其它FMC支持的存储器公用线外,其它都是SDRAM专用的。ST MCU的FMC支持两个SDRAM Bank(注意不是指一片SDRAM中的Bank),所以有两组片选和时钟使能。F429i Discovery使用的是Bank2,我自己DIY的是使用Bank1.

有了FMC支持,SDRAM用起来和片上SRAM一样读写(只不过速度慢点罢了,但容量绝对优势)。配置也是启动后配一次即可,在STM32F429的demo例子中,我找到了SDRAM部分的配置函数调用:

void SDRAM_Init(void)

{

FMC_SDRAMInitTypeDef FMC_SDRAMInitStructure;

FMC_SDRAMTimingInitTypeDef FMC_SDRAMTimingInitStructure;

/* GPIO configuration for FMC SDRAM bank */

SDRAM_GPIOConfig();

/* Enable FMC clock */

RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE);

/* Timing configuration for 90 Mhz of SD clock frequency (180Mhz/2) */

FMC_SDRAMTimingInitStructure.FMC_LoadToActiveDelay = 2;

......

/* FMC SDRAM control configuration */

FMC_SDRAMInitStructure.FMC_Bank = FMC_Bank2_SDRAM;

/* Row addressing: [7:0] */

FMC_SDRAMInitStructure.FMC_ColumnBitsNumber = FMC_ColumnBits_Number_8b;

......

FMC_SDRAMInitStructure.FMC_SDRAMTimingStruct = &FMC_SDRAMTimingInitStructure;

/* FMC SDRAM bank initialization */

FMC_SDRAMInit(&FMC_SDRAMInitStructure);

/* FMC SDRAM device initialization sequence */

SDRAM_InitSequence();

}

这里有几个关键步骤:

1. 配置对应的GPIO引脚,不用多说了

2. RCC中使能FMC控制器

3. 配置SDRAM Bank的参数寄存器,包括Timing

4. 执行 InitSequence 给控制器发命令。

在ST手册上也描述了怎么配置FMC SDRAM部分的寄存器,其实说穿了也简单,主要是SDCR(1或者2), 和SDTR(1或者2). 然后用SDCMR来执行几次命令,等待SDSR寄存器的完成状态。最后在SDRTR中设置SDRAM刷新时间参数。

SDCR 寄存器

NB 位是根据SDRAM内部Bank数

NR 位是根据SDRAM行地址位数

NC 位是根据SDRAM列地址位数

MWID 位是选择SDRAM数据线宽度

上面这几项设置决定了SDRAM的容量,例如16-bit数据宽度的SDRAM地址映射按照下图,最高位是Bank,然后行地址,再列地址

CAS 位是SDRAM的 /CAS Latency设定,是读命令发出后过多少个时钟周期输出数据有效,它是SDRAM器件的一个可配置参数。

WP 位是写保护,若置位则总线上的写请求被FMC忽略。

RBURST 位是允许突发读模式,RPIPE 位是AHB总线上读延迟。这两个设置的影响我还不清楚,有待后面详细测试。

SDTR 寄存器,配置关键的Timing参数,也就是状态之间的最小延迟时钟周期个数。不同速度的器件,和运行的频率,都影响需要的最小延迟。

一共有 TRCD, TRP, TWR, TRC, TRAS, TXSR, TMRD 这些参数,可以通过SDRAM器件的手册获得(直接或推算),例如这样的表格

最影响SDRAM性能的关键参数是下表中的几个

关于Timing设置,延迟设置大了顶多吞吐速率低一点,但设置得不够长回造成读写不正确。我对STM32F429i开发板内带的Demo程序使用OpenOCD进行调试,读出来SDCR寄存器配置是0x29d4, SDTR寄存器配置是 0x00116361, 也就是设置了

CAS Latency=3

TRCD=1

TRP=2

TWR=2

TRC=7

TRAS=4

TXSR=7

TMRD=2

除了配置好控制器的参数外,SDRAM上电之后的初始化过程需要进行预充电、自动刷新、配置模式寄存器的过程。在FMC 的SDCMR寄存器中有对应的命令可供操作。

我写的测试初始化程序片段如下

while(FMC_Bank5_6->SDSR & FMC_SDSR_BUSY); /* wait */

FMC_Bank5_6->SDCMR =FMC_SDCMR_CTB1|1; /* enable clock */

delay_us(10000);

while(FMC_Bank5_6->SDSR & FMC_SDSR_BUSY); /* wait */

FMC_Bank5_6->SDCMR =FMC_SDCMR_CTB1|2; /* precharge-all */

while(FMC_Bank5_6->SDSR & FMC_SDSR_BUSY); /* wait */

FMC_Bank5_6->SDCMR =FMC_SDCMR_CTB1|FMC_SDCMR_NRFS_2|FMC_SDCMR_NRFS_1|FMC_SDCMR_NRFS_0|3; /* auto-refresh */

while(FMC_Bank5_6->SDSR & FMC_SDSR_BUSY); /* wait */

FMC_Bank5_6->SDCMR =FMC_SDCMR_CTB1|0x30<<9|4; /* load Mode register: CAS Latency=2, burst=1 */

/* 64ms, 4096 rows: 1542 for 100MHz, 1386 for 90MHz */

FMC_Bank5_6->SDRTR = 105<<1; // 8MHz

复制代码

值得提的是SDRAM芯片内部的模式寄存器(Mode Register), 如上图。它是通过SDRAM的地址线写入的数据(/CAS, /RAS, /WE同时为低)。这个寄存器中CAS Latency设置要和FMC控制器的设置一致。也因为Mode Register操作的存在(尽管不是唯一的原因),SDRAM的地址线在连到MCU的对应引脚时是不能交换的,这和SRAM不同。不过,SDRAM的数据线在同一组内(比如DQ0到DQ7)是可以交换的,PCB布线时可以交换引脚来提供一些方便。

STM32F4/F7 将 SDRAM Bank1 映射到 0xC0000000 开始的地址,SDRAM Bank2 影射到 0xD0000000 开始的地址。虽然SDRAM数据线款可以是 8-bit/16-bit/32-bit, 从AHB总线看到的都是32-bit数据宽度,FMC内部有FIFO,它会自动拆分和拼接数据,使程序不用关心用的SDRAM芯片是什么规格的。还可以用DMA来从SDRAM传输数据。下面这个图是STM32F746的扩展内存地址映射图:

编写一段程序测试一下SDRAM的读写和基本吞吐性能吧。用C语言,一个指针就搞定的事情:

在F429i板子上,SDRAM是8MB容量的,接在Bank2,所以地址是 0xD0000000 开始的8MB范围,相当于2097152个32-bit字。这段程序就是用计数值将这8MB填满,随地址增加,写入的值每次加1. 同时,我用TIMER 5来定时,测试一下这个大循环用的机器周期数,评估SDRAM的吞吐速率。类似地,也可以用16-bit和8-bit为单位进行写操作,我也分别编写了函数。

要检查写进去的数据对不对,再写个函数将8MB内存读一遍,检查是否是每个地址的数据递增的。读的时候也可以用32-bit, 16-bit或者8-bit来访问,于是我的测试程序就检验了3遍:

一旦发现读出来数值与写入的不一致,就返回出错的地址。这样可以帮助Debug. 现在开发板MCU用默认内部16MHz HSI时钟运行,SDRAM的时钟为HCLK的一半,也就是8MHz了。F427执行写操作比我臆想的要慢:

当然按照32-bit访问进行读或者写的总线效率是最高的,最快的时候是2M次写SDRAM总共用了大概12582914个机器周期,也就是每6个机器周期写一次。毕竟,指令执行也需要时间嘛,又不是全部都是写内存的STR指令,还有循环,计数,条件判断呢。6个指令周期一次循环,也不很慢。至于是否因为访问SDRAM造成了延迟——得用内部SRAM操作来对比一下看才知道。

这里先查看一下汇编代码是怎样的:

00000000 <f_word_write>:

0: 4a09 ldr r2, [pc, #36] ; (28 <f_word_write+0x28>)

2: 2300 movs r3, #0

4: 2101 movs r1, #1

6: 6253 str r3, [r2, #36] ; 0x24

8: f04f 4350 mov.w r3, #3489660928 ; 0xd0000000

c: 8011 strh r1, [r2, #0]

e: f843 0b04 str.w r0, [r3], #4

12: f113 5f3e cmn.w r3, #796917760 ; 0x2f800000

16: f100 0001 add.w r0, r0, #1

1a: d1f8 bne.n e <f_word_write+0xe>

1c: 4b02 ldr r3, [pc, #8] ; (28 <f_word_write+0x28>)

1e: 2200 movs r2, #0

20: 801a strh r2, [r3, #0]

22: 6a58 ldr r0, [r3, #36] ; 0x24

24: 4770 bx lr

26: bf00 nop

28: 40000c00

复制代码

这其中的循环是4条指令:

0e: str.w r0, [r3], #4

12: cmn.w r3, #796917760 ; 0x2f800000

16: add.w r0, r0, #1

1a: bne.n e

要写的数加1,写的地址每次加4,cmn指令比较地址是否到达要写的范围边界,bne是条件转移即循环的控制。这4条指令一共用6个指令周期,写SDRAM大概没有成为瓶颈。

有趣的是,从运行测出的结果看,用16-bit写入的时候,一次循环是7个指令周期;用8-bit写入时,一次循环又是6个指令周期了。此外,我试了下用部分循环展开的办法,减少循环的条件转移的开销,把32-bit写满内存时间缩短到原来的78%. 估计一下,如果用SDRAM作为被处理的数据存放地,性能上和片上SRAM相比损失不大,因为数据读写占CPU周期比例不会太多。不过,要作为代码存储例如运行uClinux,可能就有明显差距了。

STM32的FMC不支持SDRAM的Burst(突发)传输,未免有遗憾。在手册上是这么提的:burst length要设成1.

我尝试将burst length设成2/4/8, 结果测试就发现错误了。

以上图文内容均是EEWORLD论坛网友:cruelfox 原创,在此感谢。

欢迎微博@EEWORLD

如果你也写过此类原创干货请关注微信公众号:EEWORLD(电子工程世界)回复“投稿”, 也可将你的原创发至: bbs_service@eeworld.com.cn,一经入选,我们将帮你登上头条!

与更多行业内网友进行交流请登陆EEWORLD论坛。

干货|从头到脚剖析STM32上的CAN通讯

CAN模式

一.工作模式 通过CAN_MCR寄存器控制INRQ和SLEEP

1.初始化INRQ=1 SLEEP=0

软件初始化应该在硬件

2.正常INRQ=0 SLEEP=0

在初始化完成后,软件应该让硬件进入正常模式,以便正常接收和发送报文

3.睡眠SLEEP=1 bxCAN可工作在低功耗的睡眠模式

二.测试模式 通过CAN_BTR寄存器控制LBKM和SILM

1. 静默 可以接受不能发送

2. 循回 可以发送不能接受

3.环回静默 只能自发自收

三.调试模式

STM32标识符筛选器

在CAN协议里,报文的标识符不代表节点的地址,而是跟报文的优先级相关的。因此,节点在接收报文时-根据标识符的值-决定软件是否需要该报文;如果需要,就拷贝到SRAM里;如果不需要,报文就被丢弃且无需软件的干预。为满足这一需求,bxCAN为应用程序提供了14个位宽可变的、可配置的过滤器组(13~0),以便只接收那些软件需要的报文。硬件过滤的做法节省了CPU开销,否则就必须由软件过滤从而占用一定的CPU开销。

STM32普通型芯片的 CAN 有14组过滤器组(互联型有28组过滤器组) ,用以对接收到的帧进行过滤。每组过滤器包括了2个可配置的32位寄存器:CAN_FxR1和 CAN_FxR2。对于过滤器组,通过设置CAN_FM0R的FBMx位,

1.屏蔽位模式

这样 CAN_FxR0中保存的就是标识符匹配值,CAN_FxR2中保存的是屏蔽码,即 CAN_FxR2中如果某一位为1,则 CAN_FxR1中相应的位必须与收到的帧的标志符中的相应位吻合才能通过过滤器。CAN_FxR2中为0的位表示 CAN_FxR1中的相应位可不必与收到的帧进行匹配。

2.标识符列表模式

此时 CAN_FxR1和CAN_FxR2中的都是要匹配的标识符,收到的帧的标识符必须与其中的一个吻合才能通过过滤。

理解:标识符列表模式是为了过滤出一个标识符,而屏蔽位模式因为屏蔽了某些位所以可以过滤出一组标识符,对于不需要用筛选器组的应处以禁用状态

一般我们用的都是普通型的,所以在本文中可以说 STM32有14组过滤器组。根据配置,每1组过滤器组可以有1个,2个或4个过滤器。这些过滤器相当于关卡,每当收到一条报文时,CAN 要先将收到的报文从这些过滤器上”过”一下,能通过的报文是有效报文,收进 FIFO,不能通过的是无效报文(不是发给”我”的报文),直接丢弃。通过对两个可配置寄存器值得改变可以选择过滤器的数量。在一组过滤器中,整组的过滤器都使用同一种工作模式。

另外,每组过滤器中的过滤器宽度是可变的,可以是32位或16位。按工作模式和宽度,一个过滤器组可以变成以下几中形式之一:

(1) 1个32位的屏蔽位模式的过滤器。

(2) 2个32位的列表模式的过滤器。

(3) 2个16位的屏蔽位模式的过滤器。

(4) 4个16位的列表模式的过滤器。

所有的过滤器是并联的,即一个报文只要通过了一个过滤器,就是算是有效的。每组过滤器组有两个32位的寄存器用于存储过滤用的”标准值”,分别是 FxR1,FxR2。

解读:

1.在32位的屏蔽位模式下:

有1个过滤器。

FxR2用于指定需要关心哪些位,FxR1用于指定这些位的标准值。

2.在32位的列表模式下:

有两个过滤器。

FxR1指定过滤器0的标准值,收到报文的标识符只有跟 FxR1完全相同时,才算通过。

FxR2指定过滤器1的标准值。

3.在16位的屏蔽位模式下:

有2个过滤器。

FxR1配置过滤器0,其中,[31-16]位指定要关心的位,[15-0]位指定这些位的标准值。

FxR2配置过滤器1,其中,[31-16]位指定要关心的位,[15-0]位指定这些位的标准值。

4.在16位的列表模式下:

有4个过滤器。

FxR1的[15-0]位配置过滤器0,FxR1的[31-16]位配置过滤器1。

FxR2的[15-0]位配置过滤器2,FxR2的[31-16]位配置过滤器3。

FIFO

STM32的 CAN 有两个 FIFO,分别是 FIFO0和 FIFO1。为了便于区分,下面 FIFO0写作FIFO_0,FIFO1写作 FIFO_1。

每组过滤器组必须关联且只能关联一个 FIFO。复位默认都关联到 FIFO_0。所谓“关联”是指假如收到的报文从某个过滤器通过了,那么该报文会被存到该过滤器相连的 FIFO。从另一方面来说,每个 FIFO 都关联了一串的过滤器组,两个 FIFO 刚好瓜分了所有的过滤器组。每当收到一个报文,CAN 就将这个报文先与 FIFO_0关联的过滤器比较,如果被匹配,就将此报文放入 FIFO_0中。如果不匹配, 再将报文与 FIFO_1关联的过滤器比较, 如果被匹配, 该报文就放入 FIFO_1中。如果还是不匹配,此报文就被丢弃。

每个 FIFO 的所有过滤器都是并联的,只要通过了其中任何一个过滤器,该报文就有效。如果一个报文既符合 FIFO_0的规定,又符合 FIFO_1的规定,显然,根据操作顺序,它只会放到 FIFO_0中。

每个 FIFO 中只有激活了的过滤器才起作用,换句话说,如果一个 FIFO 有20个过滤器,但是只激话了5个,那么比较报文时,只拿这5个过滤器作比较。一般要用到某个过滤器时,在初始化阶段就直接将它激活。需要注意的是,每个 FIFO 必须至少激活一个过滤器,它才有可能收到报文。如果一个过滤器都没有激活,那么是所有报文都报废的。一般的,如果不想用复杂的过滤功能, FIFO 可以只激活一组过滤器组,且将它设置成 32位的屏蔽位模式,两个标准值寄存器(FxR1,FxR2)都设置成0。这样所有报文均能通过。(STM32提供的例程里就是这么做的! )

过滤器匹配序号

过滤器编号用于加速 CPU 对收到报文的处理。收到一个有效报文时, CAN 会将收到的报文 以及它所通过的过滤器编号, 一起存入接收邮箱中。CPU 在处理时,可以根据过滤器编号,快速的知道该报文的用途,从而作出相应处理。

不用过滤器编号其实也是可以的, 这时候 CPU 就要分析所收报文的标识符, 从而知道报文的用途。由于标识符所含的信息较多,处理起来就慢一点了。

STM32使用以下规则对过滤器编号:

(1) FIFO_0和 FIFO_1的过滤器分别独立编号,均从0开始按顺序编号。

(2) 所有关联同一个 FIFO 的过滤器,不管有没有被激活,均统一进行编号。

(3) 编号从0开始,按过滤器组的编号从小到大,按顺序排列。

(4) 在同一过滤器组内,按寄存器从小到大编号。FxR1配置的过滤器编号小,FxR2配置

的过滤器编号大。

(5) 同一个寄存器内,按位序从小到大编号。[15-0]位配置的过滤器编号小,[31-16]位

配置的过滤器编号大。

(6) 过滤器编号是弹性的。 当更改了设置时,每个过滤器的编号都会改变。

但是在设置不变的情况下,各个过滤器的编号是相对稳定的。

这样,每个过滤器在自己在 FIFO 中都有编号。

在 FIFO_0中,编号从0 – (M-1), 其中 M 为它的过滤器总数。

在 FIFO_1中,编号从0 – (N-1),,其中 N 为它的过滤器总数。

一个 FIFO 如果有很多的过滤器,,可能会有一条报文, 在几个过滤器上均能通过,这时 候,,这条报文算是从哪儿过来的呢?

STM32在使用过滤器时,按以下顺序进行过滤:

(1) 位宽为32位的过滤器,优先级高于位宽为16位的过滤器。

(2) 对于位宽相同的过滤器,标识符列表模式的优先级高于屏蔽位模式。

(3) 位宽和模式都相同的过滤器,优先级由过滤器号决定,过滤器号小的优先级高。

按这样的顺序,报文能通过的第一个过滤器,就是该报文的过滤器编号,被存入接收邮箱中。

上面的例子说明了bxCAN的过滤器规则:在接收一个报文时,其标识符首先与配置在标识符列表模式下的过滤器相比较;如果匹配上,报文就被存放到相关联的FIFO中,并且所匹配的过滤器的序号被存入过滤器匹配序号中。如同例子中所显示,报文标识符跟#4标识符匹配,因此报文内容和FMI4被存入FIFO。如果没有匹配,报文标识符接着与配置在屏蔽位模式下的过滤器进行比较。如果报文标识符没有跟过滤器中的任何标识符相匹配,那么硬件就丢弃该报文,且不会对软件有任何打扰。

发送

发送报文的流程

应用程序选择1个空置的发送邮箱;设置标识符,数据长度和待发送数据;然后对CAN_TIxR寄存器的TXRQ位置’1’,来请求发送。 TXRQ位置’1’后,邮箱就不再是空邮箱;而一旦邮箱不再为空置,软件对邮箱寄存器就不再有写的权限。 TXRQ位置1后,邮箱马上进入挂号状态,并等待成为最高优先级的邮箱,参见发送优先级。一旦邮箱成为最高优先级的邮箱,其状态就变为预定发送状态。一旦CAN总线进入空闲状态,预定发送邮箱中的报文就马上被发送(进入发送状态)。一旦邮箱中的报文被成功发送后,它马上变为空置邮箱;硬件相应地对CAN_TSR寄存器的RQCP和TXOK位置1,来表明一次成功发送。如果发送失败,由于仲裁引起的就对CAN_TSR寄存器的ALST位置’1’,由于发送错误引起的就对TERR位置’1’。

发送优先级

一.标识符决定

当有超过1个发送邮箱在挂号时,发送顺序由邮箱中报文的标识符决定。根据CAN协议,标识符数值最低的报文具有最高的优先级。如果标识符的值相等,那么邮箱号小的报文先被发送。由发送请求次序决定。

二.由发送请求次序决定

通过对CAN_MCR寄存器的TXFP位置’1’,可以把发送邮箱配置为发送FIFO。在该模式下,发送的优先级由发送请求次序决定。该模式对分段发送很有用。

中止

通过对CAN_TSR寄存器的ABRQ位置’1’,可以中止发送请求。邮箱如果处于挂号或预定状态,发送请求马上就被中止了。如果邮箱处于发送状态,那么中止请求可能导致2种结果。如果邮箱中的报文被成功发送,那么邮箱变为空置邮箱,并且CAN_TSR寄存器的TXOK位被硬件置’1’。如果邮箱中的报文发送失败了,那么邮箱变为预定状态,然后发送请求被中止,邮箱变为空置邮箱且TXOK位被硬件清’0’。因此如果邮箱处于发送状态,那么在发送操作结束后,邮箱都会变为空置邮箱。

接受

接受流程

FIFO从空状态开始,在接收到第一个有效的报文后, FIFO状态变为挂号_1(pending_1),硬件相应地把CAN_RFR寄存器的FMP[1:0]设置为’01’(二进制01b)。软件可以读取FIFO输出邮箱来读出邮箱中的报文,然后通过对CAN_RFR寄存器的RFOM位设置’1’来释放邮箱,这样FIFO又变为空状态了。如果在释放邮箱的同时,又收到了一个有效的报文,那么FIFO仍然保留在挂号_1状态,软件可以读取FIFO输出邮箱来读出新收到的报文。如果应用程序不释放邮箱,在接收到下一个有效的报文后, FIFO状态变为挂号_2(pending_2),硬件相应地把FMP[1:0]设置为’10’(二进制10b)。重复上面的过程,第三个有效的报文把FIFO变为挂号_3状态(FMP[1:0]=11b)。此时,软件必须对RFOM位设置1来释放邮箱,以便FIFO可以有空间来存放下一个有效的报文;否则,下一个有效的报文到来时就会导致一个报文的丢失。

溢出

当FIFO处于挂号_3状态(即FIFO的3个邮箱都是满的),下一个有效的报文就会导致溢出,并且一个报文会丢失。此时,硬件对CAN_RFR寄存器的FOVR位进行置’1’来表明溢出情况。至于哪个报文会被丢弃,取决于对FIFO的设置:

● 如果禁用了FIFO锁定功能(CAN_MCR寄存器的RFLM位被清’0’),那么FIFO中最后收到的报文就被新报文所覆盖。这样,最新收到的报文不会被丢弃掉。

● 如果启用了FIFO锁定功能(CAN_MCR寄存器的RFLM位被置’1’),那么新收到的报文就被丢弃,软件可以读到FIFO中最早收到的3个报文。

接收相关的中断

一旦往FIFO存入一个报文,硬件就会更新FMP[1:0]位,并且如果CAN_IER寄存器的FMPIE位为’1’,那么就会产生一个中断请求。

当FIFO 变 满 时( 即 第3 个 报 文 被 存 入) , CAN_RFR 寄 存 器 的FULL 位 就 被 置’1’ , 并 且 如 果CAN_IER寄存器的FFIE位为’1’,那么就会产生一个满中断请求。

在溢出的情况下, FOVR位被置’1’,并且如果CAN_IER寄存器的FOVIE位为’1’,那么就会产生一个溢出中断请求。

位时序

位时间特性逻辑通过采样来监视串行的CAN总线,并且通过与帧起始位的边沿进行同步,及通过与后面的边沿进行重新同步,来调整其采样点。

它的操作可以简单解释为,如下所述把名义上的每位时间分为3段:

● 同步段(SYNC_SEG):通常期望位的变化发生在该时间段内。其值固定为1个时间单元(1 xtCAN)。

● 时间段1(BS1):定义采样点的位置。它包含CAN标准里的PROP_SEG和PHASE_SEG1。

其值可以编程为1到16个时间单元,但也可以被自动延长,以补偿因为网络中不同节点的频率差异所造成的相位的正向漂移。

● 时间段2(BS2):定义发送点的位置。它代表CAN标准里的PHASE_SEG2。其值可以编程为1到8个时间单元,但也可以被自动缩短以补偿相位的负向漂移。

重新同步跳跃宽度(SJW)定义了,在每位中可以延长或缩短多少个时间单元的上限。其值可以编程为1到4个时间单元。

有效跳变被定义为,当bxCAN自己没有发送隐性位时,从显性位到隐性位的第1次转变。如果在时间段1(BS1)而不是在同步段(SYNC_SEG)检测到有效跳变,那么BS1的时间就被延长最多SJW那么长,从而采样点被延迟了。相反如果在时间段2(BS2)而不是在SYNC_SEG检测到有效跳变,那么BS2的时间就被缩短最多SJW那么长,从而采样点被提前了。为了避免软件的编程错误,对位时间特性寄存器(CAN_BTR)的设置,只能bxCAN处于初始化状态下进行。

中断

● 发送中断可由下列事件产生:

─ 发送邮箱0变为空, CAN_TSR寄存器的RQCP0位被置’1’。

─ 发送邮箱1变为空, CAN_TSR寄存器的RQCP1位被置’1’。

─ 发送邮箱2变为空, CAN_TSR寄存器的RQCP2位被置’1’。

● FIFO0中断可由下列事件产生:

─ FIFO0接收到一个新报文, CAN_RF0R寄存器的FMP0位不再是’00’。

─ FIFO0变为满的情况, CAN_RF0R寄存器的FULL0位被置’1’。

─ FIFO0发生溢出的情况, CAN_RF0R寄存器的FOVR0位被置’1’。

● FIFO1中断可由下列事件产生:

─ FIFO1接收到一个新报文, CAN_RF1R寄存器的FMP1位不再是’00’。

─ FIFO1变为满的情况, CAN_RF1R寄存器的FULL1位被置’1’。

─ FIFO1发生溢出的情况, CAN_RF1R寄存器的FOVR1位被置’1’。

● 错误和状态变化中断可由下列事件产生:

─ 出错情况,关于出错情况的详细信息请参考CAN错误状态寄存器(CAN_ESR)。

─ 唤醒情况,在CAN接收引脚上监视到帧起始位(SOF)。

─ CAN进入睡眠模式。

关于标识符筛选器和筛选器匹配序号的理解

这两个概念理解起来有点麻烦下面举个例子来理解。面前有很多门,门上写着不同的属性,人得依据属性进门,比如说小门1 小门2 中门 大门1 大门2 其中小门1要求身高恰恰等于1.87的人进入 而中门要求身高小于1.90大于1.87的人进入 这2个概念就是标志筛选器的概念一个是标志符列表,另一个是屏蔽位 而进入门的人在后面的环节中 有测量身高这一环 为了快速获知他们的身高 我们可以用他们进的门来表示,因为门实际上包含了他们的身高信息这就是筛选器匹配的概念 筛选器匹配就是在很多门中有可能同时都可以使这个人进入 但是只有那一个门的身高和人得身高最接近 比如说人高1.70 门A要求1.68-1.12 门B要求1.70 那么就是门B由此筛选出门B这个匹配序号 可以直接获知这个人得身高信息。

相关问答

现在在实习 stm32 ,linux软件工程师和 stm32 之间怎么抉择?

对实习阶段,如果你对电路硬件有些了解的话,建议你学stm32,这样短时期你会看到学习成果提升信心。如果你只对软件有了解的话,建议你选择Linux软件工程师,从长...

stm32f 407能同时控制几个舵机,怎么控制的?- 一起装修网

stm32f407能同时控制几个舵机,怎么控制的?

如何深入学习 stm32 ?

买个开发板,边学边练。鉴借别人的学习经验,能够少走弯路。有兴趣可以看一下我的专题。买个开发板,边学边练。鉴借别人的学习经验,能够少走弯路。有兴趣可以...

rt1052与 STM32 有什么区别?

其实区别不大。KEIL的例子会比较多,keil个人感觉界面更友好。自带RTX系统IAR开发板多数喜欢给IAR的例程,其实和KEIL没什么区别。其实区别不大。KEIL的例子...

DSP与单片机到底有什么区别啊?

典型单片机最容易想到的是st的stm32f334系列,这系列是单核armm4核心,带高精度定时器,外设方面种类跟28335差不多。28335抗干扰性据说比stm32系列好一些。...

哪位朋友比较熟悉 STM32 的,请问 STM32 用KEIL和IAR编程的区别有哪些方面,最好能够列点分说……谢谢?

其实区别不大。KEIL的例子会比较多,keil个人感觉界面更友好。自带RTX系统IAR开发板多数喜欢给IAR的例程,其实和KEIL没什么区别。其实区别不大。KEIL的例子...

学习嵌入式开发的过程难吗?

度...数据结构:数据结构一定要学好,这个关系以后你的代码是“土鳖”编写的还是"土豪"编写的;这个关系到以后你的代码大小是10k还是100k,还关系到你能否往更...

单片机如何通过ADC模块采集模拟信号?

我将以STM32F103RCT6单片机,作为本文参考芯片,此芯片有3个12位的ADC,我选择其中一个ADC,实现采集电池供电电压功能的过程。第一步,配置对应的引脚,ADC功...那...

对单片机编程要用什么软件?单片机编程如何快速入门?

...第二个问题,要快速入门并掌握单片机编程,首先C语言要有一定的基础,最开始可以在vc、vs这些上位机编译平台编写小程序功能自己锻炼,对c语言有了一定的基础...

DMA是什么,有什么功能?

DMA(DirectMemoryAccess,直接内存存取)是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于CPU的大量中断负载。否则,CPU需要从...

 阿里宝卡  表膜 
王经理: 180-0000-0000(微信同号)
10086@qq.com
北京海淀区西三旗街道国际大厦08A座
©2025  上海羊羽卓进出口贸易有限公司  版权所有.All Rights Reserved.  |  程序由Z-BlogPHP强力驱动
网站首页
电话咨询
微信号

QQ

在线咨询真诚为您提供专业解答服务

热线

188-0000-0000
专属服务热线

微信

二维码扫一扫微信交流
顶部