022 - STM32学习笔记 - 扩展外部SDRAM(一) - 初识SDRAM和FMC

022 - STM32学习笔记 - 扩展外部SDRAM(一) - 初识SDRAM和FMC

之前学习了I2C读写EEPROM和SPI读写FLASH,学完之后在学习一种新的存储介质–SDRAM。

一、初识SDRAM

我们知道在stm32内部是有一定大小的SRAM(256Kb)和FLASH(1M)作为内存和程序存储空间,但是如果我们内建的程序体量比较大的时候,Stm32内部的存储空间就不够用了,这时候就需要在外部进行扩展。

在Stm32扩展内存时,可选的有SRAM和SDRAM,但是相对来说,SDRAM的性价比更高一些,所以这里就采用SDRAM来对Stm32进行扩容。给Stm32扩容的方式与PC扩展内存的原理是一样的,PC上扩容只需要增加内存条即可,而内存条则是集成了很多颗SDRAM颗粒从而组成内存单元,在STM32上,则是直接将Stm32与SDRAM直接相连。

野火F429开发板上的SDRAM使用的是IS42-45S16400J芯片,其存储大小为64Mbit,即为8Mb存储空间。

在这里插入图片描述

在这里插入图片描述

根据官方手册,可以看到IS42的芯片内部结构框图可分为5部分:

1、信号线与地址控制

芯片框图中,①部分为信号线,主要由下表所列出的组成。

信号线类型说明
CLKI(输入)同步时钟信号,所有输入信号都在 CLK 为上升沿的时候被采集
CKEI(输入)时钟使能信号,禁止时钟信号时 SDRAM 会启动自刷新操作
CS#I(输入)片选信号,低电平有效
CAS#I(输入)列地址选通,为低电平时地址线表示的是列地址
RAS#I(输入)行地址选通,为低电平时地址线表示的是行地址
WE#I(输入)写入使能,低电平有效
DQM[0:1]I(输入)数据输入/输出掩码信号,表示 DQ 信号线的有效部分
BA[0:1]I(输入)Bank 地址输入,选择要控制的 Bank
A[0:11]I(输入)地址输入
DQ[0:15]I/O(输入/输出)数据输入输出信号
2、逻辑控制单元

通过内部的逻辑控制单元控制整个芯片,外部通过片选信号(CS)、写使能(WE)、列选通(CAS)、行选通(RAS)以及地址线向内部逻辑单元输入命令。输入的命令经过命令译码器译码,同时将控制参数保存到模式寄存器中。内部结构框图②部分即为逻辑控制单元。

3、地址控制

在SDRAM中,地址线分为“A”类与“BA”类两种地址线,其中A类地址线是包含行(Row)和列(Column)共用的地址总线,而BA类地址线则是用于指定SDRAM内部存储阵列号(BANK)。并且在命令模式下,A类地址线还用于输入一些命令参数。内部结构框图③部分为地址控制单元。

4、存储阵列

与我们常用的Excel一样,当我们要读取Excel内的数据时,只需要根据列、行号就可以直接定位到对应的单元格,SDRAM将内部包含四个BANK,类似于Excel中的sheet一样,所以我们寻址时只需要指定BANK号+列地址+行地址,就可以找到指定的存储单元。

在这里插入图片描述

在SDRAM中,向外提供了独立的BA线用于BANK寻址,行列地址则复用A类地址线。在IS42芯片内部结构框图中,④部分就是内部的存储阵列结构,当RAS为低电平时,行地址选通,地址线A[11:0]表示的地址会被送到行地址译码及锁存器中,同时BA[1:0]地址线选中的BANK也会被选中锁存,当控制线CAS为低电平时,列地址选通,地址线A[11:0]表示的地址将送到列地址译码器及锁存器中,从而完成寻址操作。

5、数据输入与输出

上述寻址完成后,DQ[15:0]表示的数据会通过IS42芯片内部结构框图中⑤标记的输入数据寄存器,将输入数据传输到存储阵列中保存;数据的输出与之相反。

在野火F429开发板中使用的SDRAM芯片,存储整列的数据宽度为16位,当与SDRAM进行数据通讯时,16位的数据时同步传输的,但是根据野火官方资料中提到的,实际使用中可能会采用8位、16位宽进行存取数据,16位数据线并不是所有时候都是同时使用。比:如传输8位数据的时候,只需要使用DQ[7:0]这8位数据线即可,而DQ[15:8]这8位数据线必须忽略,否则会修改我们期望存储位置之外的内容。因此在实际使用中,还会使用DQM[1:0]线来配合,没跟DQM线对应8位数据,DQM:0为低电平,DQM:1为高电平时,数据线DQ[7:0]有效,而DQ[15:8]无效;当DQM[1:0]都为低电平时,表示数据线[15:0]均有效。

6、SDRAM命令

控制SDRAM需要用到一些命令,通过不同的信号线状态组合可以合成不同的命令。表格中,H表示高电平,L表示低电平,X表示任意电平。

命令CS#RAS#CAS#WE#DQMADDRDQ
命令禁止HXXXXXX
空操作LHHHXXX
行有效LLHHXBank/rowX
读命令LHLHL/HBank/colX
写命令LHLLL/HBank/colValid
预充电LLHLXCodeX
自动/自我刷新LLLHXXX
加载模式寄存器LLLLXOp-codeX
突发停止LHHLXXactive
a、命令禁止:

当CS#为高电平时,表示命令禁止(COMMAND INHBIT)将禁止SDRAM执行新的操作,但是不能停止当前正在执行的命令。

b、空操作:

“ 空操作” (NO OPERATION), “命令禁止”的反操作, 用于选中 SDRAM,以便接下来发送命令,也就是说当我们要对SDRAM进行后续操作时,首先需要下发空操作命令。

c、行有效:

进行存储单元寻址时,需要先选中要访问的 Bank 和行,使它处于激活状态。该操作通过“行有效” (ACTIVE)命令实现,发送行有效命令时, RAS 线为低电平,同时通过 BA 线以及 A 线发送 Bank 地址和行地址。

d、列读写:

当行有效命令确定后,紧接着就需要进行列寻址,读命令与写命令的时序基本一致,通过共用地址线A[11:0]发送列地址,同时WE#引脚表示读/写方向,WE#为低电平时,表示写,高电平时表示读。同时读写数据时,用DQM#线来确定有效的数据线。在野火F429中仅使用A[7:0]来表示列地址,A10线用于控制是否自动预充电,A10为高电平时使能预充电,低电平时关闭。

e、预充电

在SDRAM中,寻址必须要在读写进行操作完成后,如果要对同一个BANK的另一行进行寻址,就需要将原来有效的行先关闭,重新发送行/列地址。BANK关闭当前工作行,准备打开新行的操作就是预充电(Precharge)。

预充电可以通过每次发送读写命令时同时使用A10线控制自动进行预充电,也可以通过独立的命令控制。按照官方的解释,预充电是对工作行中所有存储整列进行数据重写,并对行地址进行复位,以准备新行的工作。就是说当前一个时序的读写操作完成后,需要对新行进行寻址时,需要先将原来的地址线复位,然后再重新下发行地址以及列地址。

f、刷新

SDRAM需要不断刷新才能保留住数据,刷新与预充电中读写的操作本质是一样的,也是SDRAM中比较重要的一项操作。但是预充电是对一个或者所有的BANK的工作行进行操作,操作周期不定,而刷新是固定周期对所有行进行操作,从而保证在SDRAM中很久没使用到的存储单元的数据正确性。

刷新分为两种:自动刷新与自我刷新,发送命令后,CKE时钟为低电平时,使用自动刷新,否则为自我刷新操作。自动刷新是SDRAM按照周期性(时钟周期)对SDRAM中所有BANK的工作行进行刷新。而自我刷新则是当时钟线关闭时,SDRAM启动内部刷新的操作,不需要依靠外部时钟工作。所以这里两者的区别在于是否存在时钟线是否存在周期信号。

e、加载模式寄存器

SDRAM的控制逻辑是根据它的模式寄存器来管理整个系统,这个模式寄存器就是通过“加载模式寄存器”来进行配置,发送该命令时,需要通过地址线表示要存入模式寄存器的参数“OP-Code”,关于每条地址线表示的参数如下:

在这里插入图片描述

突发长度配置(Burst Length):ADDR[2:0]

突发我们在之前学习DMA的时候接触过了,这里在复习一下,突发主要是指在同一行中相邻的的存储单元连续进行数据传输的方式,连续传输所涉及到的存储单元的数量就是突发长度。

在实际对SDRAM的读写中,我们一般不会对存储器一个一个存储单元的去读写,这样有耗时又耗力,需要不停的发送列地址与读写命令,虽然读写延迟相同可以让数据的传输在I/O端是连续的,但是会消耗大量的内存/控制资源,而且数据在传输过程中,也无法接收新的命令,因此效率比较低下。

要解决上面的问题,需要用到突发传输技术,只需要指定起始列地址和突发长度,内存会自动从起始位置到后面突发长度的存储单元进行读写,不需要控制器连续的提供地址。

在上图中,可以看到突发长度可选为1、2、4、8,当设定为1时,相当于不采用突发模式,常见的突发传输长度设定为4或者8。

这里需要注意的是,当传输的实际数据长度小于设定的突发长度时,可下发突发停止命令结束传输。

突发模式设置(Burst Type):ADDR[3]

突发模式分为顺序模式间隔模式两种,在顺序模式中,操作会按照地址的顺序连续执行;如果时间隔模式,则是操作地址是跳跃的。这里野火的资料中没有过多介绍间隔模式,等到后面学习到了,再做补充。顺序模式访问时,地址顺序时按照“0-1-2-3-4-5-6-7“的地址序列进行访问。

列地址选通延迟(CASLatency):ADDR[6:4]

字面意思,当发送读命令(命令中会包含列地址)时,列地址选通延迟就是在命令下发后,延迟多久后数据线DQ才会输出有效数据,可选的延迟周期有1、2、3个时钟周期,一般设置为2或者3个时钟周期。

这个配置只针对于读命令,写命令时不需要,当发出写命令时,可以同时发送要写入的数据。

工作模式(Operating Mode):ADDR[8:7]

这一项需要注意,在实际使用时必须配置为**“00”**(正常模式),其他值是测试模式或者被保留的设定。

写突发模式(Write Burst Mode):ADDR[9]

WB用于配置写操作时的突发特性,可选择使用BL设置的突发长度或非突发模式。

配置为0时,表示使用BL设置的突发长度,配置为1时,则使用非突发模式。

剩余的三位ADDR[11:10]被保留,不需要进行设置。

二、SDRAM的读写流程

上面再初步认识了SDRAM以及相关的命令后,我们再看一下SDRAM的读写流程

1、初始化流程

在这里插入图片描述

流程如下:

1)、SDRAM上电,并提供至少100us稳定时钟;

2)、发送“空操作”命令(NOP);

3)、发送“预充电”命令(PRECHARGE),控制所有BANK进行预充电,并等待tRP时间,tRP表示预充电与其他命令之间的延迟;

4)、发送至少2个“自动刷新”命令(AUTO REFRESH),每个命令后需等待tRC时间,tRC表示自动刷新时间;注:野火在这里标记的为tRFC

5)、发送“加载模式寄存器”命令(LOAD MODE REGISTER),配置SDRAM的工作参数,并等待tMRD时间,tMRD表示加载模式寄存器命令与行或者刷新命令之间的延迟;

6)、初始化流程完毕,到这里就可以开始读写数据了。

2、读写流程

读时序和写时序过程基本一致,如下时序图:

在这里插入图片描述

读时序

在这里插入图片描述

写时序

1)、发送行有效(ACTIVE)命令,发送的同时需要下发BANK地址和行地址,发送后等待tRCD时间,tRCD表示行有效命令与读/写命令之间的延迟;

2)、发送读/写(READ/WRITE)命令,在发送命令的同时发送列地址,完成寻址的地址输入。这里需要注意下发读命令后,根据模式寄存器的CL定义,延迟CL个时钟周期后,数据线 DQ 才输出有效数据,写命令则是没有CL延迟,下发写命令时,同时就可以将要写入的数据通过DQ写入SDRAM。另外,读/写命令需要通过A[10]地址线进行自动预充电,当SDRAM收到带预充电点的读/写命令后,需要等待tWR时间后才会开始,tWR表示写命令与预充电之间的延迟;

3)、执行预充电(auto precharge)命令后,需要等待tRP时间,tRP表示预充电与其它命令之间的延迟;

4)、本次读写完成后,发送第二次“行有效”(ACTIVE)命令准备读写下一个数据;

在上图中,标号为④的 tRAS,表示自刷新周期,即在前一个“行有效”与 “预充电” 命令之间的时间;标号⑤处的 tRC,表示两个行有效命令或两个刷新命令之间的延迟。

关于上面tRP、tRC、tMRD、tRCD、tWR、tRP时间周期,是跟具体SDRAM相关,具体可查阅数据手册获知,这里我截图出来一部分,各位先看一下,后面在FMC配置的时候再去说怎么看。

在这里插入图片描述

三、可变存储控制器(FMC)

在最开始学习STM32时,我们遇到加入固件库后,加入FSMC的文件后,会报错,这里是因为在STM32中为了驱动SRAM、SDRAM、NOR FLASH以及NAND FLASH等类型的存储器,需要用到存储控制器,即FMC/FSMC。在429中采用的时FMC(Flexible Memory Controller),即为可变存储控制器,在其他STM32控制器中,可能只有FSMC控制器(Flexible Static Memory Controller)可变静态存储控制器,两者的区别是,在驱动SDRAM时需要定时刷新,而这项功能只有FMC才支持,FSMC不支持,因此FSMC只能支持普通的SDRAM,不能支持DDR类型的SDRAM。

1、FMC结构

下图即为FMC外设的结构框图:

在这里插入图片描述

a、通讯引脚

图中标号为①的即为我们在控制SDRAM中需要用到的引脚,虽然看着FMC框图中引脚很多,特别时有一部分信号线都是共用的,比如其中地址线FMC_A和FMC_D时所有控制器共用,具体哪些引脚对应哪些GPIO端口,可以在STM32的官方手册中查到,这里直接看一下野火F429核心板原理图就知道如何对应的了。

在这里插入图片描述

这里需要注意,FMC_SDCKE线和FMC_SDNE都各有两条,FMC_SDCKE用于控制SDRAM的时钟使能,FMC_SDNE用于控制SDRAM芯片的片选使能,这两条线用于控制STM32使用不同的存储区域驱动SDRAM,使用编号为0的信号线组会使用STM32的存储器区域1,使用编号为1的信号线组会使用存储器区域2。

b、存储控器控制器

在FMC的外设图中,可以看到NOR/PSRAM/SRAM设备使用的是相同的控制器,NAND/PC卡用的是相同的控制器,而SDRAM存储器使用独立的控制器。不同的控制器有专用寄存器用于配置器工作模式。

SDRAM控制寄存器及时序寄存器各有两个,分别对应SDRAM存储区域1和存储区域2的配置。

FMC_SDCR 控制寄存器可配置 SDCLK 的同步时钟频率、突发读使能、写保护、 CAS延迟、行列地址位数以及数据总线宽度等。

FMC_SDTR 时序寄存器用于配置 SDRAM 访问时的各种时间延迟,如 TRP 行预充电
延迟、 TMRD 加载模式寄存器激活延迟等。

FMC_SDCMR 命令模式寄存器用于存储要发送到 SDRAM 模式寄存器的配置,以及要向 SDRAM 芯片发送的命令。

FMC_SDRTR 用于配置 SDRAM 的自动刷新周期

c、时钟逻辑控制

在这里插入图片描述

FMC外设是挂载在AHB3总线上,时钟信号有HCLK提供,控制器的时钟输出由其分频而得。用于与SDRAM芯片进行时钟同步的引脚为FMC_SDCLK,他的时钟频率可通过FMC_SDCR1寄存器的SDCLK位配置,可配置为HCLK的1/2或者1/3,我们之前学习RCC时钟树时知道F429的HCLK时钟频率一般配置为180MHz,因此与SDRAM通讯的时钟最高频率为90MHz。

2、FMC地址映射

当FMC连接好外部存储器并初始化后,可以通过直接访问地址来读取数据,之前学习I2C读写EEPROM和SPI读写FLASH时,我们需要通过I2C或SPI总线下发地址,才能接收到由存储器返回的数据。地址和数据都要通过不同的变量存储,并且还得使用代码控制发送读写命令。

当使用FMC访问外部存储器时,存储单元是映射到STM32的内存存储空间,访问某个地址的数据时,可以通过映射的地址指针直接去读写该地址的内容,至于底层的事情,就交给FMC自动完成即可。

在这里插入图片描述

上图中FMC区域中Block3和4为External RAM地址空间,主要映射的为NOR/PSRAM/SRAM/NAND FLASH以及PC卡的地址;Block5和6为External device区域,映射的为SDRAM的地址,因此访问挂载在FMC上的存储器时,就可以通过直接访问映射的地址直接访问了。

a、存储区域

FMC把SDRAM的存储区域划分为BNAK1和BANK2两块,这里只是FMC的地址区域划分,并不是SDRAM片内的BANK划分,需要注意。FMC的每个BANK都有不一样的其实地址,而且有独立的FMC_SDCR控制寄存器、FMC_SDTR时序寄存器、FMC_SDCKE时钟使能信号线和FMC_SDCLK信号线。FMCSDCKE0和FMC_SDCLJ0对应的存储区域1的地址范围是0xC000 0000 ~ 0xCFFF FFFF,而FMC_SDCKE1和FMC_SDCLK1对应的存储区域2地址范围是0xD000 0000 ~ 0xDFFF FFFF。

b、SDRAM时序结构体

FMC使用SDRAM存储器时主要是配置时序寄存器以及控制寄存器,利用标准库的SDRAM时序结构体以及初始化结构体可以写入参数。

SDRAM时序结构体FMC_SDRAMTimingInitTypeDef

/** * @brief  控制SDRAM的时序参数,单位为周期,每个参数的值范围为1-16个周期*/
typedef struct
{uint32_t FMC_LoadToActiveDelay;      /* TMRD:加载模式寄存器命令后的延迟 */uint32_t FMC_ExitSelfRefreshDelay;   /* TXSR:自刷新后的延迟 */uint32_t FMC_SelfRefreshTime;        /* TRAS:自刷新时间 */uint32_t FMC_RowCycleDelay;          /* TRC:行循环延迟 */uint32_t FMC_WriteRecoveryTime;      /* TWR:恢复延迟 */uint32_t FMC_RPDelay;                /* TRP:行预充电延迟 */uint32_t FMC_RCDDelay;               /* TRCD:行到列延迟 */
}FMC_SDRAMTimingInitTypeDef;

FMC_LoadToActiveDelay:本成员设置TMRD延迟,即为发送加载模式寄存器命令后要等待的时间,之后才可以再发送行有效或者刷新命令。

FMC_ExitSelfRefreshDelay:设置推出TXRS延迟,即退出自我刷新命令后要等待的时间,之后才可以发送行有效命令。

FMC_SelfRefreshTime:设置自我刷新时间TRAS,即发送行有效命令后需要等待的时间,之后才能执行预充电命令。

FMC_RowCycleDelay:设置TRC延迟,两个行有效命令之间的延迟,以及两个相邻刷新命令之间的延迟。

FMC_WriteRecoveryTime:设置TWR延迟,即写命令和预充电命令之间的延迟,之后才可以执行预充电命令。

FMC_RPDelay:设置TRP延迟,即预充电命令与其他命令之间的延迟。

FMC_RCDDelay:设置TRCD延迟,即行有效命令到列读写命令之间的延迟。

c、SDRAM初始化结构体
/* @brief FMC SDRAM 初始化结构体类型定义 */
typedef struct
{uint32_t FMC_Bank; 					/*选择 FMC 的 SDRAM 存储区域*/uint32_t FMC_ColumnBitsNumber; 		 /*定义 SDRAM 的列地址宽度 */uint32_t FMC_RowBitsNumber;			 /*定义 SDRAM 的行地址宽度 */uint32_t FMC_SDMemoryDataWidth;		 /*定义 SDRAM 的数据宽度 */uint32_t FMC_InternalBankNumber;	 /*定义 SDRAM 内部的 Bank 数目 */uint32_t FMC_CASLatency;			/*定义 CASLatency 的时钟个数*/uint32_t FMC_WriteProtection;		 /*定义是否使能写保护模式 */uint32_t FMC_SDClockPeriod;			 /*配置同步时钟 SDCLK 的参数*/uint32_t FMC_ReadBurst;				 /*是否使能突发读模式*/uint32_t FMC_ReadPipeDelay;			  /*定义在 CAS 个延迟后再等待多少个 HCLK 时钟才读取数据 */FMC_SDRAMTimingInitTypeDef* FMC_SDRAMTimingStruct; /*定义 SDRAM 的时序参数*/
} FMC_SDRAMInitTypeDef;

FMC_Bank:选择 FMC 映射的 SDRAM 存储区域,可选择存储区域 1 或 2 (FMC_Bank1/2_SDRAM)。

FMC_ColumnBitsNumber:设置要控制的 SDRAM 的列地址宽度,可选择 8-11 (FMC_ColumnBits_Number_8/9/10/11b)。

FMC_RowBitsNumber:设置要控制的 SDRAM 的行地址宽度,可选择设置成 11-13 (FMC_RowBits_Number_11/12/13b)。

FMC_SDMemoryDataWidth:设置要控制的 SDRAM 的数据宽度,可选择设置成 8、 16 或 32 位(FMC_SDMemory_Width_8/16/32b)。

FMC_InternalBankNumber:设置要控制的 SDRAM 的内部 Bank 数目,可选择设置成 2 或 4 个 Bank 数目(FMC_InternalBank_Number_2/4),请注意区分这个结构体成员与 FMC_Bank 的区别。

FMC_CASLatency:设置 CASLatency 即 CL 的时钟数目,可选择设置为 1、 2 或 3 个时钟周期(FMC_CAS_Latency_1/2/3)。

FMC_WriteProtection:设置是否使能写保护模式,如果使能了写保护则不能向 SDRAM 写入数据,正常使用都是禁止写保护的。

FMC_SDClockPeriod:设置 FMC 与外部 SDRAM 通讯时的同步时钟参数,可以设置成 STM32 的HCLK 时 钟 频 率 的 1/2 、 1/3 或 禁 止 输 出 时 钟 (FMC_SDClock_Period_2/3 或FMC_SDClock_Disable)。

FMC_ReadBurst:设置是否使能突发读取模式,禁止时等效于 BL=1,使能时 BL 的值等于模式寄存器中的配置。

FMC_ReadPipeDelay:配置在 CASLatency 个时钟周期后,再等待多少个 HCLK 时钟周期才进行数据采样,在确保正确的前提下,这个值设置为越短越好,可选择设置的参数值为 0、1 或 2 个 HCLK 时钟周期(FMC_ReadPipe_Delay_0/1/2)。

FMC_SDRAMTimingStruct:上面已经学习过了,这里不做赘述。

c、SDRAM命令结构体

了解了SDRAM的时序结构体和初始化结构体后,还有一个比较重要的结构体需要了解,在控制SDRAM时,需要发送各种命令,通过向FMC的命令模式寄存器FMC_SDCMR写入控制参数,就可以向外发送命令,这里了解一下FMC_SDRAMCommandTypeDef结构体

typedef struct
{uint32_t FMC_CommandMode;				/*要发送的命令 */uint32_t FMC_CommandTarget;				/*目标存储器区域 */uint32_t FMC_AutoRefreshNumber;			 /*若发送的是自动刷新命令,此处为发送的刷新次数,其它命令时无效 */uint32_t FMC_ModeRegisterDefinition;	 /*若发送的是加载模式寄存器命令,此处为要写入 SDRAM 模式寄存器的参数 */
} FMC_SDRAMCommandTypeDef;

FMC_CommandMode:配置将要发送的命令,具体命令参数如下表:

命令说明
FMC_Command_Mode_normal正常模式命令
FMC_Command_Mode_CLK_Enabled使能 CLK 命令
FMC_Command_Mode_PALL对所有 Bank 预充电命令
FMC_Command_Mode_AutoRefresh自动刷新命令
FMC_Command_Mode_LoadMode加载模式寄存器命令
FMC_Command_Mode_Selfrefresh自我刷新命令
FMC_Command_Mode_PowerDown掉电命令

FMC_CommandTarget:选择需要控制的FMC存储区域,可选为存储区1或者2(FMC_Command_Target_bank1/2)。

FMC_AutoRefreshNumber:当需要连续多次发送“自动刷新”命令时,配置此项可控制发送次数,可选参数值为1-16。如果发送的是其他命令时,此项无效。

FMC_ModeRegisterDefinition:此项对应的是SDRAM的模式寄存器,发送加载模式寄存器命令时,此项会通过地址线发送到SDRAM的模式寄存器中。

以上三个结构体成员配置完成后,就可以调用库函数FMC_SDRAMCmdConfig把这些参数写入到FMC_SDCMR寄存器中,之后FMC会自动发送响应的命令了。

OK,关于SDRAM和FMC的相关内容就先学习到这里,下节就开始实战了,相关的参数配置等到实战的时候在做总结。
或者2(FMC_Command_Target_bank1/2)。

FMC_AutoRefreshNumber:当需要连续多次发送“自动刷新”命令时,配置此项可控制发送次数,可选参数值为1-16。如果发送的是其他命令时,此项无效。

FMC_ModeRegisterDefinition:此项对应的是SDRAM的模式寄存器,发送加载模式寄存器命令时,此项会通过地址线发送到SDRAM的模式寄存器中。

以上三个结构体成员配置完成后,就可以调用库函数FMC_SDRAMCmdConfig把这些参数写入到FMC_SDCMR寄存器中,之后FMC会自动发送响应的命令了。

OK,关于SDRAM和FMC的相关内容就先学习到这里,下节就开始实战了,相关的参数配置等到实战的时候在做总结。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/34397.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无人驾驶实战-第十二课(强化学习自动驾驶系统)(完)

在七月算法上报了《无人驾驶实战》课程,老师讲的真好。好记性不如烂笔头,记录一下学习内容。 课程入口,感兴趣的也可以跟着学一下。 ————————————————————————————————————————— 强化学习&#xff…

c++日志工具之——log4cpp

1、log4cpp概述 Log4cpp是一个开源的C类库,它提供了C程序中使用日志和跟踪调试的功能,它的优点如下: 提供应用程序运行上下文,方便跟踪调试; 可扩展的、多种方式记录日志,包括命令行、文件、回卷文件、内…

阿里云服务器搭建WordPress建站教程基于Windows系统

本教程是使用阿里云服务器镜像系统选择的是Windows操作系统,手动安装WordPress博客网站全过程。本教程介绍如何在Windows操作系统的ECS实例上搭建WordPress网站。 目录 准备工作 搭建WordPress网站 解析WordPress网站域名 准备工作 创建Windows操作系统的ECS实…

Docker mysql+nacos单机部署

docker 网络创建 由于nacos需要访问mysql的数据,因此mysql容器和nacos容器之间需要进行通信。容器间通信有很多方式,在这里采用同一网络下的方式进行实现。因此需要创建网络。创建网络的命令如下: docker network create --driver bridge n…

HICP学习--BGP综合小实验

需要完善 一、实验拓扑 二、实验需求 1、R2-7每台路由器均存在一个环回接口用于建立邻居,同时还存在一个环回来代表连接用户的接口;最终这些连接用户的接口网络需要可以和R1/8的环回通讯 2、AS2网段地址172.16.0.0/16 减路由条目数量 三、实验步骤 首先配置IP R…

tensorflow / tensorflow-gpu cuda cudNN tensorRT 安装,启用显卡加速

tensorflow / tensorflow-gpu cuda cudNN tensorRT 安装,启用显卡加速 说明 Tensorflow-GPU 已被移除。请安装 tensorflow 。 tensorflow 通过 Nvidia CUDA 支持 GPU 加速操作。 自 2019 年 9月发布 的 TensorFlow2.1 以来,tensorFlow 和 tensorflow-GPU 一直是同…

智慧城市美术效果Unity实现笔记流程

智慧城市美术效果Unity实现笔记流程: 参考 对标 效果图: 参考资料: 方案一: fBlender GIS 获取城市 房屋道路等数据 安装BlenderGIS插件 落叶大师智慧城市效果解析 方案二: CityEngine2022地块生成 写实类-参考图&…

c语言每日一练(6)

前言:每日一练系列,每一期都包含5道选择题,2道编程题,博主会尽可能详细地进行讲解,令初学者也能听的清晰。每日一练系列会持续更新,暑假时三天之内必有一更,到了开学之后,将看学业情…

华为运动健康,十年创新天地宽

我听一位朋友讲过这样一个故事。某天早上,急诊科的医生迎来了一位患者,患者进来后直接说:“大夫,我房颤了。” 这位医生非常诧异,因为心脏房颤确实非常危急,但很多时候并没有明显的生理体征,患者…

JavaScript之BOM+window对象+定时器+location,navigator,history对象

一.BOM概述 BOM即浏览器对象模型,它提供了独立于内容而与窗口进行交互的对象 BOM的顶级对象是window 二.window对象的常见事件 1.窗口加载事件window.onload window.onload function(){} 或者 window.addEventListener("onload" , function(){}); window.onlo…

Mybatis-plus动态条件查询QueryWrapper的使用

Mybatis-plus动态条件查询QueryWrapper的使用 一:queryWrapper介绍 queryWrapper是mybatis plus中实现查询的对象封装操作类,可以封装sql对象,包括where条件,order by排序,select哪些字段等等,他的层级关…

CentOS7连接网络

1.下载centos7镜像文件 2.安装centos7 3.修改网卡,ens33. 注意: 这里使用的是dhcp,设置IPADDR192.168.31.64一方面是为了后面使用crt或者MobaXterm连接,另一方面它和windows电脑的网卡要一致.这样才可以连接到网络.win r,输入cmd,打开命令窗口输入ipconfig.可以看到IPv4: 102…

phpstorm配置ftp同步文件到服务器

这里的默认快捷键 不是 CtrlS ;需要设置快捷键,这里原来是save all操作时上传文件到服务器; ** 设置好快捷键后按 CtrlS就会同步文件(添加删除文件后保存,服务器也会同步) ** 搜索出save all 后&#xf…

NPM与外部服务的集成(上)

目录 1、关于访问令牌 1.1 关于传统令牌 1.2 关于粒度访问令牌 2、创建和查看访问令牌 2.1 创建访问令牌 在网站上创建传统令牌 在网站上创建粒度访问令牌 使用CLI创建令牌 CIDR限制令牌错误 查看访问令牌 在网站上查看令牌 在CLI上查看令牌 令牌属性 1、关于访问令…

报错注入(主键重复)攻击原理

基本原理 利用数据表中主键不能重复的特点,通过构造重复的主键,使得数据库报错,并将报错结果返回到前端。 SQL说明函数 以pet数据表为例进行说明 rond(): 返回[0,1)区间内的任意浮点数。 count(): 返回每个组的列行数。 如&#xff0…

SWIG使用方法

安装 下载 swigwin软件包,解压到合适的位置,然后将路径添加到环境变量即可。 编写C代码 //vector.hpp class Vector { private:int x;int y; public:Vector(int,int);double abs();void display(); };//vector.cpp #include "vector.hpp" …

CI/CD—K8S 基本理解与部署

1 K8S 是什么 Kubernetes 是一款容器的编排调度工具,来源于 Google 开源的 Brog 系统。Kubernetes简称K8S,是用8代替8个字符 “ubernete” 而成的缩写,用于管理云平台中多个主机上的容器化的应用,Kubernetes 的目标是让部署容器化…

解决createRoot is not a function

报错: 出现的原因:在于把react18使用的vite构建,在开发中因react版本太高与其他库不兼容,而在降级的时候,出现以上dom渲染出现报错。 解决:将 src/index.j文件改成如下 import React from react; import…

【数据结构与算法】十大经典排序算法-冒泡排序

🌟个人博客:www.hellocode.top 🏰Java知识导航:Java-Navigate 🔥CSDN:HelloCode. 🌴掘金:HelloCode 🌞知乎:HelloCode ⚡如有问题,欢迎指正&#…

锐捷设备密码管理、密码恢复、恢复出厂设置

目录 配置登录用户名密码以及Enable密码 只需要密码登录 需要用户名和密码登录(无AAA) 需要用户名和密码登录(有AAA) 密码恢复 Web密码忘记 Telnet/SSH密码忘记 Console密码忘记 所有密码都忘记,通过Console进…