赞
踩
STM32控制器芯片内部有一定大小的SRAM和FLASH作为内存和程序存储空间,但当程序较大,内存和程序空间不足时,就需要在STM32芯片的外部扩展存储器了。
STM32F429系列芯片扩展内存时可以选择SRAM(静态内存,上电无需初始化)和SDRAM(动态内存,上电需初始化),由于SDRAM的性价比比较高,即使用SDRAM要比SRAM划算的多。我们以SDRAM为例讲解如何为STM32扩展内存。
给STM32芯片扩展内存与给PC扩展内存的原理是一样的,只是PC上一般以内存条的形式扩展,内存条实质是由多个内存颗粒(即SDRAM芯片)组成的通用标准模块,而STM32直接与SDRAM芯片连接。下图是一种型号为IS42-45S16400J的SDRAM芯片内部结构框图,以它为模型进行学习。本小节的SDRAM芯片为STM32扩展内存,它的行地址宽度为12位,列地址宽度为8位,内部含有4个bank,数据线宽度为16位,容量大小为8MB。
1.1 SDRAM信号线
除了时钟、地址和数据线,控制SDRAM还需要很多信号配合,它们具体作用在描述时序图时进行讲解。
1.2 控制逻辑
SDRAM内部的“控制逻辑”指挥着整个系统的运行,外部可通过CS, WE, CAS, RAS以及地址线来向控制逻辑输入命令,命令经过“命令器译码器”译码,并将控制参数保存到“模式寄存器中”,控制逻辑依次运行。
1.3 地址控制
SDRAM包含有“A”以及“BA”2类地址线,A类地址线是行(Row)与列(Column)共用的地址总线,BA地址线是独立的用于指定SDRAM内部存储阵列号(bank)。在命令模式下,A类地址线还用于某些命令输入参数。
1.4 SDRAM的存储阵列
要了解SDRAM的存储单元寻址以及“A”、“BA”线的具体运用,需要先熟悉它内部存储阵列的结构。如下图
SDRAM内部包含的存储阵列,可以把它理解成一张表格,数据就填在这张表格上。和表格查找一样,指定一个行地址和列地址,就可以精确地找到目标单元格,这是SDRAM芯片寻址的基本原理。这样的每个单元格被称为“存储单元”,而这样的表则被称为“存储阵列(bank)”,目前设计的SDRAM芯片基本上内部都包含有4个这样的bank,寻址时指定bank号以及行地址,然后再指定列地址即可寻找到目标存储单元。SDRAM内部具有多个bank时的结构见下图:
SDRAM芯片向外部提供有独立的BA类地址线用于bank寻址,而行与列则共用A类地址线。
图中④表示的就是它内部的存储阵列结构,通讯时当RAS线为低电平,则“行地址选通器”被选通,地址线A[11:0]表示的地址会被输入到“行地址译码及锁存器”中,作为存储阵列中选定的行地址,同时地址线BA[1:0]表示的bank也被锁存,选中了要操作的bank号;接着控制CAS线为低电平,“列地址选通器”被选通,地址线A[11:0]表示的地址会被锁存到“列地址译码器”中作为列地址,完成寻址过程。
1.5 数据输入输出
若是写SDRAM内容,寻址完成后,DQ[15:0]线表示的数据经过⑤中的输入数据寄存器,然后传输到存储器阵列中,数据被保存;数据输出过程相反。
本型号的SDRAM存储阵列的“数据宽度”是16位(即数据线的数量),在与SDRAM进行数据通讯时,16位的数据是同步传输的,但实际应用中我们可能会以8位、16位的宽度存取数据,也就是说16位的数据线并不是所有时候都同时使用的,而且在传输低宽度数据的时候,我们不希望其他数据线表示的数据被录入。如传输8位数据的时候,我们只需要DQ[7:0]表示的数据,而DQ[15:8]数据线表示的数据必须忽略,否则会修改非目标存储空间的内容。所以数据输入输出时,还会使用DQM[1:0]线来配合,每个DQM线对应8位数据,如“DQM0(LDQM)”为低电平,“DQM1(HDQM)”为高电平时,数据线DQ[7:0]表示的数据有效,而DQ[15:8]表示的数据无效。
1.6 SDRAM的命令
控制SDRAM需要用到一系列的命令,各种信号线状态组合产生不同的控制命令。
本型号的SDRAM芯片表示列地址时仅使用A[7:0]线,而A10线用于控制是否“自动预充电”,该线为高电平时使能,低电平时关闭。
预充电:SDRAM的寻址具有独占性,所以在进行完读写操作后,如果要对同一个bank的另一行进行寻址,就要将原来有效(ACTIVE)的行关闭,重新发送行/列地址。bank关闭当前工作行,准备打开新行的操作就是预充电(precharge)。预充电可以通过独立的命令控制,也可以在每次发送读写命令的同时使用“A10”线控制自动进行预充电。实际上,预充电是一种对工作行中所有存储阵列进行数据重写,并对行地址进行复位,以准备新行的工作。独立的预充电命令时序图如下,该命令配合使用A10线控制,若A10为高电平时,所有bank都预充电;A10为低电平时,使用BA线选择要预充电的bank。
刷新:SDRAM要不断进行刷新(refresh)才能保留住数据,因此它是DRAM最重要的操作。刷新操作与预充电中重写的操作本质是一样的。但因为预充电是对一个或所有bank中的工作行操作,并且不定期,而刷新则是有固定的周期,依次对所有行进行操作,以保证那些久久没有被访问的存储单元数据正确。刷新操作分为2种:“自动刷新(auto refresh)”与“自我刷新(self refresh)”,发送命令后CKE时钟为有效时(低电平),使用自动刷新操作,否则使用自我刷新操作。不论是何种刷新方式,都不需要外部提供行地址信息,因为这是一个内部的自动操作。对于“自动刷新”,SDRAM内部有一个行地址生成器(也称为刷新计数器)用来自动地依次生成行地址,每收到一次命令刷新一行。在刷新过程中,所有bank都停止工作,而每次刷新所占用的时间为N个时钟周期(视SDRAM型号而定,通常为N=9),刷新结束之后才可进入正常的工作状态,也就是说在这N个时钟周期内所有工作指令只能等待而无法执行。一次次地按行刷新,刷新完所有行后,将再次对第一行重新进行刷新操作,这个对同一行刷新操作的时间间隔,称为SDRAM的刷新周期,通常为64ms。显然刷新会对SDRAM的性能造成影响,但这是它的DRAM(动态内存)的特性决定的,也是DRAM相对于SRAM取得成本优势的同时所付出的代价。“自我刷新”则主要用于休眠模式低功耗状态下的数据保存,也就是说即使外部控制器不工作了。SDRAM都能自己确保数据正常。在发出“自我刷新”命令后,将CKE置于无效状态(低电平),就进入自我刷新模式,此时不再依靠外部时钟工作,而是根据SDRAM内部的时钟进行刷新操作。在自我刷新期间除了CKE之外的所有外部信号都是无效的,只有重新使CKE有效才能退出自我刷新模式并进入正常操作状态。
加载模式寄存器:前面提到SDRAM的控制逻辑是根据他的模式寄存器来管理整个系统的,而这个寄存器的参数就是通过“加载模式寄存器”命令(LOAD MODE REGISTER)来配置的。发送该命令时,使用地址线表示要存入模式寄存器的参数“OP-Code”,各个地址线表示的参数如下图:
最后我们来了解SDRAM的初始化流程,SDRAM并不是上电后立即就可以开始读写数据的,它需要按步骤进行初始化,对存储矩阵预充电、刷新并设置模式寄存器,见下图。
该流程说明如下:
初始化步骤完成,开始读写数据,其时序流程图如下
STM32F429使用FMC外设来管理扩展的存储器,FMC称为可变存储控制器。它可以用于驱动包括SRAM、SDRAM、NOR FLASH、NAND FLASH等类型的存储器。在其他系列的STM32控制器中,只有FSMC控制器(可变静态存储控制器),所以它们不能驱动SDRAM这样的动态存储器,因为驱动SDRAM时需要定时刷新,STM32F429的FMC外设才支持该功能,且只支持普通的SDRAM,不支持DDR类型的SDRAM。我们只讲述FMC的SDRAM控制功能。
5.1 通讯引脚
在框图的右侧是FMC外设相关的控制引脚,由于控制不同类型存储器的时候会有一些不同的引脚,看起来非常多,其中地址线FMC_A和数据线FMC_D是所有控制器都共用的。这些FMC引脚具体对应的GPIO端口及引脚号可在《STM32F4XX规格书》中搜索查找到,不在此列出。针对SDRAM控制器,我们是整理出以下的FMC与SDRAM引脚对照表。
其中比较特殊的是FMC_A[15:14]引脚用作bank的寻址线;而FMC_SDCKE线和FMC_SDNE都各有2条,FMC_SDCKE用于控制SDRAM的时钟使能,FMC_SDNE用于控制SDRAM芯片的片选使能。它们用于控制STM32使用不同的存储区域驱动SDRAM,使用编号为0的信号线组会使用STM32的存储器区域1,使用编号为1的信号线会使用存储器区域2,。使用不同存储区域时,STM32访问SDRAM的地址不一样,具体将在“FMC的地址映射”小节讲解。
5.2 存储器控制器
上面不同类型的引脚是连接到FMC内部对应的存储控制器中的。NOR/PSRAM/SRAM设备使用相同的控制器,NAND/PC卡设备使用相同的控制器,而SDRAM存储器使用独立的控制器。不同的控制器有专用的寄存器用于配置其工作模式。
控制SDRAM的有FMC_SDCR1/FMC_SDCR2控制寄存器、FMC_SDTR1/FMC_SDTR2时序寄存器、FMC_SDCMR命令模式寄存器以及FMC_SDRTR刷新定时器寄存器。其中控制寄存器及时序寄存器各有2个,分别对应于SDRAM存储区域1和存储区域2的配置。
FMC_SDCR控制寄存器可配置SDCLK的同步时钟频率、突发读使能、写保护、CAS延迟、行列地址位数以及数据总线宽度等。
FMC_SDTR时序寄存器用于配置SDRAM访问时的各种时间延迟,如TRP行预充电延迟、TMRD加载模式寄存器激活延迟等。
FMC_SDCMR命令模式寄存器用于存储要发送到SDRAM模式寄存器的配置,以及要向SDRAM芯片发送的命令。
FMC_SDRTR用于配置SDRAM的自动刷新周期。
5.3 时钟控制逻辑
FMC外设挂载在AHB3总线上,时钟信号来自于HCLK(默认180MHZ),控制器的时钟输出就是由它分频得到。如SDRAM控制器的FMC_SDCLK引脚输出的时钟,是用于与SDRAM芯片进行同步通讯,它的时钟频率可通过FMC_SDCR1寄存器的SDCLK位配置,可以配置为HCLK的1/2或1/3,也就是说,与SDRAM通讯的同步时钟最高频率为90MHZ。
FMC连接好外部的存储器并初始化后,就可以直接通过访问地址来读写数据,这种地址访问与IIC EEPROM、SPI FLASH的不一样,后2种方式都需要控制IIC或SPI总线给存储器发送地址,然后获取数据;在程序里,这个地址和数据都需要分开使用不同的变量存储,并且访问时还需要使用代码控制发送读写命令。而使用FMC外接存储器时,其存储单元是映射到STM32的内部寻址空间的;在程序里,定义一个指向这些地址的指针,然后就可以通过指针直接修改该存储单元的内容,FMC外设会自动完成数据访问过程,读写命令之类的操作不需要程序控制。FMC的地址映射如下图。
图中左侧的是cortex-M4内核的存储空间分配,右侧是STM32 FMC外设的地址映射。可以看到FMC的NOR/PSRAM/SRAM/NAND FLASH以及PC卡的地址都在external RAM地址空间内,而SDRAM的地址是分配到external device区域的。正是因为存在这样的地址映射,使得访问FMC控制的存储器时,就跟访问STM32的片上外设寄存器一样(片上外设的地址映射即图中左侧的“peripheral”区域)。
6.1 SDRAM的存储区域
FMC把SDRAM的存储区域分成了bank1和bank2两块,这里的bank与SDRAM芯片内部的bank是不一样的概念,只是FMC的地址区域划分而已。每个bank有不一样的起始地址,且有独立的FMC_SDCR控制寄存器和FMC_SDTR时序寄存器,还有独立的FMC_SDCKE时钟使能信号线和FMC_SDCLK信号线。FMC_SDCKE0和FMC_SDCLK0对应存储区域1的地址范围是0xC000000-0xCFFFFFFF,而FMC_SDCKE1和FMC_SDCLK1对应的存储区域2的地址范围是0xD0000000-0xDFFFFFFF 。 当程序里控制内核访问这些地址的存储空间时,FMC外设即会产生对应的时序,对它外接的SDRAM芯片进行读写。
6.2 external RAM和external device的区别
比较遗憾的是FMC给SDRAM分配的区域不在external RAM区,这个区域可以直接执行代码,而SDRAM所在的external device区却不支持这个功能。这里说的可直接执行代码的特性就是在“常用存储器”章节介绍的XIP(eXecute In Place)特性,即存储器上若存储了代码,CPU可直接访问代码执行,无需缓存到其他设备上再运行;而且XIP特性还对存储器的种类有要求,SRAM/SDRAM及NOR FLASH都支持这种特性,而NAND FLASH及PC卡是不支持XIP的。结合存储器的特性和STM32 FMC存储器种类的地址分配,就发现他的地址规划不合理了,NAND FLASH和PC卡这些不支持XIP的存储器却占据了 external RAM的空间,而支持XIP的SDRAM存储器的空间却被分配到了 external device区。
为了解决这个问题,通过配置“SYSCFG_MEMRMP”寄存器的“SWP_FMC”寄存器位可用于交换SDRAM与NAND/PC卡的地址映射,使得存储在SDRAM中的代码能被执行,只是由于SDRAM的最高同步时钟是90MHZ,代码的执行速度会受影响。
本章主要讲解当STM32的片内SRAM不够用时使用SDRAM扩展内存,但假如程序太大,它的程序空间FLASH不够用怎么办呢?首先是裁剪代码,目前STM32F429系列芯片内部FLASH空间最高可达2MB,实际应用中只要我们把代码中的图片、字模等占据大空间的内容放到外部存储器中,纯粹的代码很难达到2MB。如果还不够用,非要扩展程序空间的话,一种方法是使用FMC扩展NOR FLASH,把程序存储到NOR上,程序代码能够直接在NOR FLASH上执行。另一种方法是把程序存储在其他外部存储器,如SD卡,需要时把存储在SD卡上的代码加载到SRAM或SDRAM上,再在RAM上执行代码。
如果SDRAM不是用于存储可执行代码,只是用来保存数据的话,在 external RAM或 external device区域都没有区别,不需要与NAND的映射地址交换。
控制FMC使用SDRAM存储器时主要是配置时序寄存器以及控制寄存器,利用ST标准库的SDRAM时序结构体以及初始化结构体可以很方便地写入参数。
这个结构体成员定义的都是SDRAM发送各种命令后必须的延迟,它的配置对应到FMC_SDTR中的寄存器位。所有成员参数值的单位是周期,参数值大小都可以设置成“1-16”。关于这些延时时间的定义可以看“SDRAM初始化流程”和“SDRAM读写流程”小节的时序图了解。具体参数值根据SDRAM芯片的手册说明来配置。各成员介绍如下:
这个SDRAMTimingTypeDef时序结构体配置的延时参数,将作为下一节的FMC SDRAM初始化结构体的一个成员。
这个结构体,除最后一个成员是上一小节讲解的时序配置外,其他结构体成员的配置都对应到FMC_SDCR中的寄存器位。各个成员意义在前面的小节已有具体讲解,其可选参数介绍如下,括号中的是STM32标准库定义的宏:
配置完SDRAM初始化结构体后,调用FMC_SDRAMInit函数把这些配置写入到FMC的SDRAM控制寄存器和时序寄存器,实现FMC的初始化。
控制SDRAM时需要各种命令,通过向FMC的命令模式寄存器FMC_SDCMR写入控制参数,即可控制FMC对外发送命令,为了方便使用,STM32标准库也把它封装成了结构体。
命令结构体中的各个成员介绍如下:
配置完这些结构体成员,调用库函数FMC_SDRAMCmdConfig即可把这些参数写入到FMC_SDCMR寄存器中,然后FMC外设就会发送相应的命令了。
#include "./sdram/bsp_sdram.h" /** * @brief 延迟一段时间 * @param 延迟的时间长度 * @retval None */ static void SDRAM_delay(__IO uint32_t nCount) { __IO uint32_t index = 0; for(index = (100000 * nCount); index != 0; index--) { } } /** * @brief 初始化控制SDRAM的IO * @param 无 * @retval 无 */ static void SDRAM_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; /* 使能SDRAM相关的GPIO时钟 */ /*地址信号线*/ RCC_AHB1PeriphClockCmd(FMC_A0_GPIO_CLK | FMC_A1_GPIO_CLK | FMC_A2_GPIO_CLK | FMC_A3_GPIO_CLK | FMC_A4_GPIO_CLK | FMC_A5_GPIO_CLK | FMC_A6_GPIO_CLK | FMC_A7_GPIO_CLK | FMC_A8_GPIO_CLK | FMC_A9_GPIO_CLK | FMC_A10_GPIO_CLK| FMC_A11_GPIO_CLK| FMC_BA0_GPIO_CLK| FMC_BA1_GPIO_CLK| /*数据信号线*/ FMC_D0_GPIO_CLK | FMC_D1_GPIO_CLK | FMC_D2_GPIO_CLK | FMC_D3_GPIO_CLK | FMC_D4_GPIO_CLK | FMC_D5_GPIO_CLK | FMC_D6_GPIO_CLK | FMC_D7_GPIO_CLK | FMC_D8_GPIO_CLK | FMC_D9_GPIO_CLK | FMC_D10_GPIO_CLK| FMC_D11_GPIO_CLK| FMC_D12_GPIO_CLK| FMC_D13_GPIO_CLK| FMC_D14_GPIO_CLK| FMC_D15_GPIO_CLK| /*控制信号线*/ FMC_CS_GPIO_CLK | FMC_WE_GPIO_CLK | FMC_RAS_GPIO_CLK | FMC_CAS_GPIO_CLK |FMC_CLK_GPIO_CLK | FMC_CKE_GPIO_CLK | FMC_UDQM_GPIO_CLK|FMC_LDQM_GPIO_CLK, ENABLE); /*-- GPIO 配置 -----------------------------------------------------*/ /* 通用 GPIO 配置 */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //配置为复用功能 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; /*A行列地址信号线 针对引脚配置*/ GPIO_InitStructure.GPIO_Pin = FMC_A0_GPIO_PIN; GPIO_Init(FMC_A0_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_A0_GPIO_PORT, FMC_A0_PINSOURCE , FMC_A0_AF); GPIO_InitStructure.GPIO_Pin = FMC_A1_GPIO_PIN; GPIO_Init(FMC_A1_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_A1_GPIO_PORT, FMC_A1_PINSOURCE , FMC_A1_AF); GPIO_InitStructure.GPIO_Pin = FMC_A2_GPIO_PIN; GPIO_Init(FMC_A2_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_A2_GPIO_PORT, FMC_A2_PINSOURCE , FMC_A2_AF); GPIO_InitStructure.GPIO_Pin = FMC_A3_GPIO_PIN; GPIO_Init(FMC_A3_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_A3_GPIO_PORT, FMC_A3_PINSOURCE , FMC_A3_AF); GPIO_InitStructure.GPIO_Pin = FMC_A4_GPIO_PIN; GPIO_Init(FMC_A4_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_A4_GPIO_PORT, FMC_A4_PINSOURCE , FMC_A4_AF); GPIO_InitStructure.GPIO_Pin = FMC_A5_GPIO_PIN; GPIO_Init(FMC_A5_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_A5_GPIO_PORT, FMC_A5_PINSOURCE , FMC_A5_AF); GPIO_InitStructure.GPIO_Pin = FMC_A6_GPIO_PIN; GPIO_Init(FMC_A6_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_A6_GPIO_PORT, FMC_A6_PINSOURCE , FMC_A6_AF); GPIO_InitStructure.GPIO_Pin = FMC_A7_GPIO_PIN; GPIO_Init(FMC_A7_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_A7_GPIO_PORT, FMC_A7_PINSOURCE , FMC_A7_AF); GPIO_InitStructure.GPIO_Pin = FMC_A8_GPIO_PIN; GPIO_Init(FMC_A8_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_A8_GPIO_PORT, FMC_A8_PINSOURCE , FMC_A8_AF); GPIO_InitStructure.GPIO_Pin = FMC_A9_GPIO_PIN; GPIO_Init(FMC_A9_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_A9_GPIO_PORT, FMC_A9_PINSOURCE , FMC_A9_AF); GPIO_InitStructure.GPIO_Pin = FMC_A10_GPIO_PIN; GPIO_Init(FMC_A10_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_A10_GPIO_PORT, FMC_A10_PINSOURCE , FMC_A10_AF); GPIO_InitStructure.GPIO_Pin = FMC_A11_GPIO_PIN; GPIO_Init(FMC_A11_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_A11_GPIO_PORT, FMC_A11_PINSOURCE , FMC_A11_AF); /*BA地址信号线*/ GPIO_InitStructure.GPIO_Pin = FMC_BA0_GPIO_PIN; GPIO_Init(FMC_BA0_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_BA0_GPIO_PORT, FMC_BA0_PINSOURCE , FMC_BA0_AF); GPIO_InitStructure.GPIO_Pin = FMC_BA1_GPIO_PIN; GPIO_Init(FMC_BA1_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_BA1_GPIO_PORT, FMC_BA1_PINSOURCE , FMC_BA1_AF); /*DQ数据信号线 针对引脚配置*/ GPIO_InitStructure.GPIO_Pin = FMC_D0_GPIO_PIN; GPIO_Init(FMC_D0_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_D0_GPIO_PORT, FMC_D0_PINSOURCE , FMC_D0_AF); GPIO_InitStructure.GPIO_Pin = FMC_D1_GPIO_PIN; GPIO_Init(FMC_D1_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_D1_GPIO_PORT, FMC_D1_PINSOURCE , FMC_D1_AF); GPIO_InitStructure.GPIO_Pin = FMC_D2_GPIO_PIN; GPIO_Init(FMC_D2_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_D2_GPIO_PORT, FMC_D2_PINSOURCE , FMC_D2_AF); GPIO_InitStructure.GPIO_Pin = FMC_D3_GPIO_PIN; GPIO_Init(FMC_D3_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_D3_GPIO_PORT, FMC_D3_PINSOURCE , FMC_D3_AF); GPIO_InitStructure.GPIO_Pin = FMC_D4_GPIO_PIN; GPIO_Init(FMC_D4_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_D4_GPIO_PORT, FMC_D4_PINSOURCE , FMC_D4_AF); GPIO_InitStructure.GPIO_Pin = FMC_D5_GPIO_PIN; GPIO_Init(FMC_D5_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_D5_GPIO_PORT, FMC_D5_PINSOURCE , FMC_D5_AF); GPIO_InitStructure.GPIO_Pin = FMC_D6_GPIO_PIN; GPIO_Init(FMC_D6_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_D6_GPIO_PORT, FMC_D6_PINSOURCE , FMC_D6_AF); GPIO_InitStructure.GPIO_Pin = FMC_D7_GPIO_PIN; GPIO_Init(FMC_D7_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_D7_GPIO_PORT, FMC_D7_PINSOURCE , FMC_D7_AF); GPIO_InitStructure.GPIO_Pin = FMC_D8_GPIO_PIN; GPIO_Init(FMC_D8_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_D8_GPIO_PORT, FMC_D8_PINSOURCE , FMC_D8_AF); GPIO_InitStructure.GPIO_Pin = FMC_D9_GPIO_PIN; GPIO_Init(FMC_D9_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_D9_GPIO_PORT, FMC_D9_PINSOURCE , FMC_D9_AF); GPIO_InitStructure.GPIO_Pin = FMC_D10_GPIO_PIN; GPIO_Init(FMC_D10_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_D10_GPIO_PORT, FMC_D10_PINSOURCE , FMC_D10_AF); GPIO_InitStructure.GPIO_Pin = FMC_D11_GPIO_PIN; GPIO_Init(FMC_D11_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_D11_GPIO_PORT, FMC_D11_PINSOURCE , FMC_D11_AF); GPIO_InitStructure.GPIO_Pin = FMC_D12_GPIO_PIN; GPIO_Init(FMC_D12_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_D12_GPIO_PORT, FMC_D12_PINSOURCE , FMC_D12_AF); GPIO_InitStructure.GPIO_Pin = FMC_D13_GPIO_PIN; GPIO_Init(FMC_D13_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_D13_GPIO_PORT, FMC_D13_PINSOURCE , FMC_D13_AF); GPIO_InitStructure.GPIO_Pin = FMC_D14_GPIO_PIN; GPIO_Init(FMC_D14_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_D14_GPIO_PORT, FMC_D14_PINSOURCE , FMC_D14_AF); GPIO_InitStructure.GPIO_Pin = FMC_D15_GPIO_PIN; GPIO_Init(FMC_D15_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_D15_GPIO_PORT, FMC_D15_PINSOURCE , FMC_D15_AF); /*控制信号线*/ GPIO_InitStructure.GPIO_Pin = FMC_CS_GPIO_PIN; GPIO_Init(FMC_CS_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_CS_GPIO_PORT, FMC_CS_PINSOURCE , FMC_CS_AF); GPIO_InitStructure.GPIO_Pin = FMC_WE_GPIO_PIN; GPIO_Init(FMC_WE_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_WE_GPIO_PORT, FMC_WE_PINSOURCE , FMC_WE_AF); GPIO_InitStructure.GPIO_Pin = FMC_RAS_GPIO_PIN; GPIO_Init(FMC_RAS_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_RAS_GPIO_PORT, FMC_RAS_PINSOURCE , FMC_RAS_AF); GPIO_InitStructure.GPIO_Pin = FMC_CAS_GPIO_PIN; GPIO_Init(FMC_CAS_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_CAS_GPIO_PORT, FMC_CAS_PINSOURCE , FMC_CAS_AF); GPIO_InitStructure.GPIO_Pin = FMC_CLK_GPIO_PIN; GPIO_Init(FMC_CLK_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_CLK_GPIO_PORT, FMC_CLK_PINSOURCE , FMC_CLK_AF); GPIO_InitStructure.GPIO_Pin = FMC_CKE_GPIO_PIN; GPIO_Init(FMC_CKE_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_CKE_GPIO_PORT, FMC_CKE_PINSOURCE , FMC_CKE_AF); GPIO_InitStructure.GPIO_Pin = FMC_UDQM_GPIO_PIN; GPIO_Init(FMC_UDQM_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_UDQM_GPIO_PORT, FMC_UDQM_PINSOURCE , FMC_UDQM_AF); GPIO_InitStructure.GPIO_Pin = FMC_LDQM_GPIO_PIN; GPIO_Init(FMC_LDQM_GPIO_PORT, &GPIO_InitStructure); GPIO_PinAFConfig(FMC_LDQM_GPIO_PORT, FMC_LDQM_PINSOURCE , FMC_LDQM_AF); } /** * @brief 对SDRAM芯片进行初始化配置 * @param None. * @retval None. */ static void SDRAM_InitSequence(void) { FMC_SDRAMCommandTypeDef FMC_SDRAMCommandStructure; uint32_t tmpr = 0; /* Step 3 --------------------------------------------------------------------*/ /* 配置命令:开启提供给SDRAM的时钟 */ FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_CLK_Enabled; FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_COMMAND_TARGET_BANK; FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 0; FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0; /* 检查SDRAM标志,等待至SDRAM空闲 */ while(FMC_GetFlagStatus(FMC_BANK_SDRAM, FMC_FLAG_Busy) != RESET) { } /* 发送上述命令*/ FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure); /* Step 4 --------------------------------------------------------------------*/ /* 延时 */ SDRAM_delay(10); /* Step 5 --------------------------------------------------------------------*/ /* 配置命令:对所有的bank预充电 */ FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_PALL; FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_COMMAND_TARGET_BANK; FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 0; FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0; /* 检查SDRAM标志,等待至SDRAM空闲 */ while(FMC_GetFlagStatus(FMC_BANK_SDRAM, FMC_FLAG_Busy) != RESET) { } /* 发送上述命令*/ FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure); /* Step 6 --------------------------------------------------------------------*/ /* 配置命令:自动刷新 */ FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_AutoRefresh; FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_COMMAND_TARGET_BANK; FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 2; //2个自动刷新命令 FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0; /* 检查SDRAM标志,等待至SDRAM空闲 */ while(FMC_GetFlagStatus(FMC_BANK_SDRAM, FMC_FLAG_Busy) != RESET) { } /* 发送自动刷新命令*/ FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure); /* Step 7 --------------------------------------------------------------------*/ /* 设置sdram寄存器配置 */ tmpr = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_4 | SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | SDRAM_MODEREG_CAS_LATENCY_2 | SDRAM_MODEREG_OPERATING_MODE_STANDARD | SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; /* 配置命令:设置SDRAM寄存器 */ FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_LoadMode; FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_COMMAND_TARGET_BANK; FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1; FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = tmpr; /* 检查SDRAM标志,等待至SDRAM空闲 */ while(FMC_GetFlagStatus(FMC_BANK_SDRAM, FMC_FLAG_Busy) != RESET) { } /* 发送上述命令*/ FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure); /* Step 8 --------------------------------------------------------------------*/ /* 设置刷新计数器 */ /*刷新速率 = (COUNT + 1) x SDRAM 频率时钟 COUNT =( SDRAM 刷新周期/行数) - 20*/ /* 64ms/4096=15.62us (15.62 us x FSDCLK) - 20 =1386 */ FMC_SetRefreshCount(1386); /* 发送上述命令*/ while(FMC_GetFlagStatus(FMC_BANK_SDRAM, FMC_FLAG_Busy) != RESET) { } } /** * @brief 初始化配置使用SDRAM的FMC及GPIO接口, * 本函数在SDRAM读写操作前需要被调用 * @param None * @retval None */ void SDRAM_Init(void) { FMC_SDRAMInitTypeDef FMC_SDRAMInitStructure; FMC_SDRAMTimingInitTypeDef FMC_SDRAMTimingInitStructure; /* 配置FMC接口相关的 GPIO*/ SDRAM_GPIO_Config(); /* 使能 FMC 时钟 */ RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE); /* SDRAM时序结构体,根据SDRAM参数表配置----------------*/ /* SDCLK: 90 Mhz (HCLK/2 :180Mhz/2) 1个时钟周期Tsdclk =1/90MHz=11.11ns*/ /* TMRD: 2 Clock cycles */ FMC_SDRAMTimingInitStructure.FMC_LoadToActiveDelay = 2; /* TXSR: min=70ns (7x11.11ns) */ FMC_SDRAMTimingInitStructure.FMC_ExitSelfRefreshDelay = 7; /* TRAS: min=42ns (4x11.11ns) max=120k (ns) */ FMC_SDRAMTimingInitStructure.FMC_SelfRefreshTime = 4; /* TRC: min=70 (7x11.11ns) */ FMC_SDRAMTimingInitStructure.FMC_RowCycleDelay = 7; /* TWR: min=1+ 7ns (1+1x11.11ns) */ FMC_SDRAMTimingInitStructure.FMC_WriteRecoveryTime = 2; /* TRP: 15ns => 2x11.11ns */ FMC_SDRAMTimingInitStructure.FMC_RPDelay = 2; /* TRCD: 15ns => 2x11.11ns */ FMC_SDRAMTimingInitStructure.FMC_RCDDelay = 2; /* FMC SDRAM 控制配置 */ /*选择存储区域*/ FMC_SDRAMInitStructure.FMC_Bank = FMC_BANK_SDRAM; /* 行地址线宽度: [7:0] */ FMC_SDRAMInitStructure.FMC_ColumnBitsNumber = FMC_ColumnBits_Number_8b; /* 列地址线宽度: [11:0] */ FMC_SDRAMInitStructure.FMC_RowBitsNumber = FMC_RowBits_Number_12b; /* 数据线宽度 */ FMC_SDRAMInitStructure.FMC_SDMemoryDataWidth = SDRAM_MEMORY_WIDTH; /* SDRAM内部bank数量*/ FMC_SDRAMInitStructure.FMC_InternalBankNumber = FMC_InternalBank_Number_4; /* CAS潜伏期 */ FMC_SDRAMInitStructure.FMC_CASLatency = SDRAM_CAS_LATENCY; /* 禁止写保护*/ FMC_SDRAMInitStructure.FMC_WriteProtection = FMC_Write_Protection_Disable; /* SDCLK时钟分频因子,SDCLK = HCLK/SDCLOCK_PERIOD*/ FMC_SDRAMInitStructure.FMC_SDClockPeriod = SDCLOCK_PERIOD; /* 突发读模式设置*/ FMC_SDRAMInitStructure.FMC_ReadBurst = SDRAM_READBURST; /* 读延迟配置 */ FMC_SDRAMInitStructure.FMC_ReadPipeDelay = FMC_ReadPipe_Delay_0; /* SDRAM时序参数 */ FMC_SDRAMInitStructure.FMC_SDRAMTimingStruct = &FMC_SDRAMTimingInitStructure; /* 调用初始化函数,向寄存器写入配置 */ FMC_SDRAMInit(&FMC_SDRAMInitStructure); /* 执行FMC SDRAM的初始化流程*/ SDRAM_InitSequence(); //对SDRAM芯片进行初始化配置,SDRAM芯片上电需要初始化 } /** * @brief 以“字”为单位向sdram写入数据 * @param pBuffer: 指向数据的指针 * @param uwWriteAddress: 要写入的SDRAM内部地址 * @param uwBufferSize: 要写入数据大小 * @retval None. */ void SDRAM_WriteBuffer(uint32_t* pBuffer, uint32_t uwWriteAddress, uint32_t uwBufferSize) { __IO uint32_t write_pointer = (uint32_t)uwWriteAddress; /* 禁止写保护 */ FMC_SDRAMWriteProtectionConfig(FMC_Bank2_SDRAM, DISABLE); /* 检查SDRAM标志,等待至SDRAM空闲 */ while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET) { } /* 循环写入数据 */ for (; uwBufferSize != 0; uwBufferSize--) { /* 发送数据到SDRAM */ *(uint32_t *) (SDRAM_BANK_ADDR + write_pointer) = *pBuffer++; /* 地址自增*/ write_pointer += 4; } } /** * @brief 从SDRAM中读取数据 * @param pBuffer: 指向存储数据的buffer * @param ReadAddress: 要读取数据的地十 * @param uwBufferSize: 要读取的数据大小 * @retval None. */ void SDRAM_ReadBuffer(uint32_t* pBuffer, uint32_t uwReadAddress, uint32_t uwBufferSize) { __IO uint32_t write_pointer = (uint32_t)uwReadAddress; /* 检查SDRAM标志,等待至SDRAM空闲 */ while(FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET) { } /*读取数据 */ for(; uwBufferSize != 0x00; uwBufferSize--) { *pBuffer++ = *(__IO uint32_t *)(SDRAM_BANK_ADDR + write_pointer ); /* 地址自增*/ write_pointer += 4; } } /** * @brief 测试SDRAM是否正常 * @param None * @retval 正常返回1,异常返回0 */ uint8_t SDRAM_Test(void) { /*写入数据计数器*/ uint32_t counter=0; /* 8位的数据 */ uint8_t ubWritedata_8b = 0, ubReaddata_8b = 0; /* 16位的数据 */ uint16_t uhWritedata_16b = 0, uhReaddata_16b = 0; SDRAM_INFO("正在检测SDRAM,以8位、16位的方式读写sdram..."); /*按8位格式读写数据,并校验*/ /* 把SDRAM数据全部重置为0 ,IS42S16400J_SIZE是以8位为单位的 */ for (counter = 0x00; counter < IS42S16400J_SIZE; counter++) { *(__IO uint8_t*) (SDRAM_BANK_ADDR + counter) = (uint8_t)0x0; } /* 向整个SDRAM写入数据 8位 */ for (counter = 0; counter < IS42S16400J_SIZE; counter++) { *(__IO uint8_t*) (SDRAM_BANK_ADDR + counter) = (uint8_t)(ubWritedata_8b + counter); } /* 读取 SDRAM 数据并检测*/ for(counter = 0; counter<IS42S16400J_SIZE;counter++ ) { ubReaddata_8b = *(__IO uint8_t*)(SDRAM_BANK_ADDR + counter); //从该地址读出数据 if(ubReaddata_8b != (uint8_t)(ubWritedata_8b + counter)) //检测数据,若不相等,跳出函数,返回检测失败结果。 { SDRAM_ERROR("8位数据读写错误!"); return 0; } } /*按16位格式读写数据,并检测*/ /* 把SDRAM数据全部重置为0 */ for (counter = 0x00; counter < IS42S16400J_SIZE/2; counter++) { *(__IO uint16_t*) (SDRAM_BANK_ADDR + 2*counter) = (uint16_t)0x00; } /* 向整个SDRAM写入数据 16位 */ for (counter = 0; counter < IS42S16400J_SIZE/2; counter++) { *(__IO uint16_t*) (SDRAM_BANK_ADDR + 2*counter) = (uint16_t)(uhWritedata_16b + counter); } /* 读取 SDRAM 数据并检测*/ for(counter = 0; counter<IS42S16400J_SIZE/2;counter++ ) { uhReaddata_16b = *(__IO uint16_t*)(SDRAM_BANK_ADDR + 2*counter); //从该地址读出数据 if(uhReaddata_16b != (uint16_t)(uhWritedata_16b + counter)) //检测数据,若不相等,跳出函数,返回检测失败结果。 { SDRAM_ERROR("16位数据读写错误!"); return 0; } } SDRAM_INFO("SDRAM读写测试正常!"); /*检测正常,return 1 */ return 1; } /*********************************************END OF FILE**********************/
#ifndef __SDRAM_H #define __SDRAM_H #include "stm32f4xx.h" #include <stdio.h> #define IS42S16400J_SIZE 0x800000 //400000*16bits = 0x800000 ,8M字节 /*SDRAM 的bank选择*/ #define FMC_BANK_SDRAM FMC_Bank2_SDRAM #define FMC_COMMAND_TARGET_BANK FMC_Command_Target_bank2 /** * @brief FMC SDRAM 数据基地址 */ #define SDRAM_BANK_ADDR ((uint32_t)0xD0000000) /** * @brief FMC SDRAM 数据宽度 */ /* #define SDRAM_MEMORY_WIDTH FMC_SDMemory_Width_8b */ #define SDRAM_MEMORY_WIDTH FMC_SDMemory_Width_16b /** * @brief FMC SDRAM CAS Latency */ #define SDRAM_CAS_LATENCY FMC_CAS_Latency_2 //#define SDRAM_CAS_LATENCY FMC_CAS_Latency_3 /** * @brief FMC SDRAM SDCLK时钟分频因子 */ #define SDCLOCK_PERIOD FMC_SDClock_Period_2 /* Default configuration used with LCD */ /* #define SDCLOCK_PERIOD FMC_SDClock_Period_3 */ /** * @brief FMC SDRAM 突发读取特性 */ //#define SDRAM_READBURST FMC_Read_Burst_Disable /* Default configuration used with LCD */ #define SDRAM_READBURST FMC_Read_Burst_Enable /** * @brief FMC SDRAM Bank Remap */ /* #define SDRAM_BANK_REMAP */ /** * @brief FMC SDRAM 模式配置的寄存器相关定义 */ #define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000) #define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001) #define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002) #define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004) #define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000) #define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008) #define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020) #define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030) #define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000) #define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000) #define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200) /*信息输出*/ #define SDRAM_DEBUG_ON 1 #define SDRAM_INFO(fmt,arg...) printf("<<-SDRAM-INFO->> "fmt"\n",##arg) #define SDRAM_ERROR(fmt,arg...) printf("<<-SDRAM-ERROR->> "fmt"\n",##arg) #define SDRAM_DEBUG(fmt,arg...) do{\ if(SDRAM_DEBUG_ON)\ printf("<<-SDRAM-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\ }while(0) /** * @} */ /*A行列地址信号线*/ #define FMC_A0_GPIO_PORT GPIOF #define FMC_A0_GPIO_CLK RCC_AHB1Periph_GPIOF #define FMC_A0_GPIO_PIN GPIO_Pin_0 #define FMC_A0_PINSOURCE GPIO_PinSource0 #define FMC_A0_AF GPIO_AF_FMC #define FMC_A1_GPIO_PORT GPIOF #define FMC_A1_GPIO_CLK RCC_AHB1Periph_GPIOF #define FMC_A1_GPIO_PIN GPIO_Pin_1 #define FMC_A1_PINSOURCE GPIO_PinSource1 #define FMC_A1_AF GPIO_AF_FMC #define FMC_A2_GPIO_PORT GPIOF #define FMC_A2_GPIO_CLK RCC_AHB1Periph_GPIOF #define FMC_A2_GPIO_PIN GPIO_Pin_2 #define FMC_A2_PINSOURCE GPIO_PinSource2 #define FMC_A2_AF GPIO_AF_FMC #define FMC_A3_GPIO_PORT GPIOF #define FMC_A3_GPIO_CLK RCC_AHB1Periph_GPIOF #define FMC_A3_GPIO_PIN GPIO_Pin_3 #define FMC_A3_PINSOURCE GPIO_PinSource3 #define FMC_A3_AF GPIO_AF_FMC #define FMC_A4_GPIO_PORT GPIOF #define FMC_A4_GPIO_CLK RCC_AHB1Periph_GPIOF #define FMC_A4_GPIO_PIN GPIO_Pin_4 #define FMC_A4_PINSOURCE GPIO_PinSource4 #define FMC_A4_AF GPIO_AF_FMC #define FMC_A5_GPIO_PORT GPIOF #define FMC_A5_GPIO_CLK RCC_AHB1Periph_GPIOF #define FMC_A5_GPIO_PIN GPIO_Pin_5 #define FMC_A5_PINSOURCE GPIO_PinSource5 #define FMC_A5_AF GPIO_AF_FMC #define FMC_A6_GPIO_PORT GPIOF #define FMC_A6_GPIO_CLK RCC_AHB1Periph_GPIOF #define FMC_A6_GPIO_PIN GPIO_Pin_12 #define FMC_A6_PINSOURCE GPIO_PinSource12 #define FMC_A6_AF GPIO_AF_FMC #define FMC_A7_GPIO_PORT GPIOF #define FMC_A7_GPIO_CLK RCC_AHB1Periph_GPIOF #define FMC_A7_GPIO_PIN GPIO_Pin_13 #define FMC_A7_PINSOURCE GPIO_PinSource13 #define FMC_A7_AF GPIO_AF_FMC #define FMC_A8_GPIO_PORT GPIOF #define FMC_A8_GPIO_CLK RCC_AHB1Periph_GPIOF #define FMC_A8_GPIO_PIN GPIO_Pin_14 #define FMC_A8_PINSOURCE GPIO_PinSource14 #define FMC_A8_AF GPIO_AF_FMC #define FMC_A9_GPIO_PORT GPIOF #define FMC_A9_GPIO_CLK RCC_AHB1Periph_GPIOF #define FMC_A9_GPIO_PIN GPIO_Pin_15 #define FMC_A9_PINSOURCE GPIO_PinSource15 #define FMC_A9_AF GPIO_AF_FMC #define FMC_A10_GPIO_PORT GPIOG #define FMC_A10_GPIO_CLK RCC_AHB1Periph_GPIOG #define FMC_A10_GPIO_PIN GPIO_Pin_0 #define FMC_A10_PINSOURCE GPIO_PinSource0 #define FMC_A10_AF GPIO_AF_FMC #define FMC_A11_GPIO_PORT GPIOG #define FMC_A11_GPIO_CLK RCC_AHB1Periph_GPIOG #define FMC_A11_GPIO_PIN GPIO_Pin_1 #define FMC_A11_PINSOURCE GPIO_PinSource1 #define FMC_A11_AF GPIO_AF_FMC /*BA地址线*/ #define FMC_BA0_GPIO_PORT GPIOG #define FMC_BA0_GPIO_CLK RCC_AHB1Periph_GPIOG #define FMC_BA0_GPIO_PIN GPIO_Pin_4 #define FMC_BA0_PINSOURCE GPIO_PinSource4 #define FMC_BA0_AF GPIO_AF_FMC #define FMC_BA1_GPIO_PORT GPIOG #define FMC_BA1_GPIO_CLK RCC_AHB1Periph_GPIOG #define FMC_BA1_GPIO_PIN GPIO_Pin_5 #define FMC_BA1_PINSOURCE GPIO_PinSource5 #define FMC_BA1_AF GPIO_AF_FMC /*DQ数据信号线*/ #define FMC_D0_GPIO_PORT GPIOD #define FMC_D0_GPIO_CLK RCC_AHB1Periph_GPIOD #define FMC_D0_GPIO_PIN GPIO_Pin_14 #define FMC_D0_PINSOURCE GPIO_PinSource14 #define FMC_D0_AF GPIO_AF_FMC #define FMC_D1_GPIO_PORT GPIOD #define FMC_D1_GPIO_CLK RCC_AHB1Periph_GPIOD #define FMC_D1_GPIO_PIN GPIO_Pin_15 #define FMC_D1_PINSOURCE GPIO_PinSource15 #define FMC_D1_AF GPIO_AF_FMC #define FMC_D2_GPIO_PORT GPIOD #define FMC_D2_GPIO_CLK RCC_AHB1Periph_GPIOD #define FMC_D2_GPIO_PIN GPIO_Pin_0 #define FMC_D2_PINSOURCE GPIO_PinSource0 #define FMC_D2_AF GPIO_AF_FMC #define FMC_D3_GPIO_PORT GPIOD #define FMC_D3_GPIO_CLK RCC_AHB1Periph_GPIOD #define FMC_D3_GPIO_PIN GPIO_Pin_1 #define FMC_D3_PINSOURCE GPIO_PinSource1 #define FMC_D3_AF GPIO_AF_FMC #define FMC_D4_GPIO_PORT GPIOE #define FMC_D4_GPIO_CLK RCC_AHB1Periph_GPIOE #define FMC_D4_GPIO_PIN GPIO_Pin_7 #define FMC_D4_PINSOURCE GPIO_PinSource7 #define FMC_D4_AF GPIO_AF_FMC #define FMC_D5_GPIO_PORT GPIOE #define FMC_D5_GPIO_CLK RCC_AHB1Periph_GPIOE #define FMC_D5_GPIO_PIN GPIO_Pin_8 #define FMC_D5_PINSOURCE GPIO_PinSource8 #define FMC_D5_AF GPIO_AF_FMC #define FMC_D6_GPIO_PORT GPIOE #define FMC_D6_GPIO_CLK RCC_AHB1Periph_GPIOE #define FMC_D6_GPIO_PIN GPIO_Pin_9 #define FMC_D6_PINSOURCE GPIO_PinSource9 #define FMC_D6_AF GPIO_AF_FMC #define FMC_D7_GPIO_PORT GPIOE #define FMC_D7_GPIO_CLK RCC_AHB1Periph_GPIOE #define FMC_D7_GPIO_PIN GPIO_Pin_10 #define FMC_D7_PINSOURCE GPIO_PinSource10 #define FMC_D7_AF GPIO_AF_FMC #define FMC_D8_GPIO_PORT GPIOE #define FMC_D8_GPIO_CLK RCC_AHB1Periph_GPIOE #define FMC_D8_GPIO_PIN GPIO_Pin_11 #define FMC_D8_PINSOURCE GPIO_PinSource11 #define FMC_D8_AF GPIO_AF_FMC #define FMC_D9_GPIO_PORT GPIOE #define FMC_D9_GPIO_CLK RCC_AHB1Periph_GPIOE #define FMC_D9_GPIO_PIN GPIO_Pin_12 #define FMC_D9_PINSOURCE GPIO_PinSource12 #define FMC_D9_AF GPIO_AF_FMC #define FMC_D10_GPIO_PORT GPIOE #define FMC_D10_GPIO_CLK RCC_AHB1Periph_GPIOE #define FMC_D10_GPIO_PIN GPIO_Pin_13 #define FMC_D10_PINSOURCE GPIO_PinSource13 #define FMC_D10_AF GPIO_AF_FMC #define FMC_D11_GPIO_PORT GPIOE #define FMC_D11_GPIO_CLK RCC_AHB1Periph_GPIOE #define FMC_D11_GPIO_PIN GPIO_Pin_14 #define FMC_D11_PINSOURCE GPIO_PinSource14 #define FMC_D11_AF GPIO_AF_FMC #define FMC_D12_GPIO_PORT GPIOE #define FMC_D12_GPIO_CLK RCC_AHB1Periph_GPIOE #define FMC_D12_GPIO_PIN GPIO_Pin_15 #define FMC_D12_PINSOURCE GPIO_PinSource15 #define FMC_D12_AF GPIO_AF_FMC #define FMC_D13_GPIO_PORT GPIOD #define FMC_D13_GPIO_CLK RCC_AHB1Periph_GPIOD #define FMC_D13_GPIO_PIN GPIO_Pin_8 #define FMC_D13_PINSOURCE GPIO_PinSource8 #define FMC_D13_AF GPIO_AF_FMC #define FMC_D14_GPIO_PORT GPIOD #define FMC_D14_GPIO_CLK RCC_AHB1Periph_GPIOD #define FMC_D14_GPIO_PIN GPIO_Pin_9 #define FMC_D14_PINSOURCE GPIO_PinSource9 #define FMC_D14_AF GPIO_AF_FMC #define FMC_D15_GPIO_PORT GPIOD #define FMC_D15_GPIO_CLK RCC_AHB1Periph_GPIOD #define FMC_D15_GPIO_PIN GPIO_Pin_10 #define FMC_D15_PINSOURCE GPIO_PinSource10 #define FMC_D15_AF GPIO_AF_FMC /*控制信号线*/ /*CS片选*/ #define FMC_CS_GPIO_PORT GPIOH #define FMC_CS_GPIO_CLK RCC_AHB1Periph_GPIOH #define FMC_CS_GPIO_PIN GPIO_Pin_6 #define FMC_CS_PINSOURCE GPIO_PinSource6 #define FMC_CS_AF GPIO_AF_FMC /*WE写使能*/ #define FMC_WE_GPIO_PORT GPIOC #define FMC_WE_GPIO_CLK RCC_AHB1Periph_GPIOC #define FMC_WE_GPIO_PIN GPIO_Pin_0 #define FMC_WE_PINSOURCE GPIO_PinSource0 #define FMC_WE_AF GPIO_AF_FMC /*RAS行选通*/ #define FMC_RAS_GPIO_PORT GPIOF #define FMC_RAS_GPIO_CLK RCC_AHB1Periph_GPIOF #define FMC_RAS_GPIO_PIN GPIO_Pin_11 #define FMC_RAS_PINSOURCE GPIO_PinSource11 #define FMC_RAS_AF GPIO_AF_FMC /*CAS列选通*/ #define FMC_CAS_GPIO_PORT GPIOG #define FMC_CAS_GPIO_CLK RCC_AHB1Periph_GPIOG #define FMC_CAS_GPIO_PIN GPIO_Pin_15 #define FMC_CAS_PINSOURCE GPIO_PinSource15 #define FMC_CAS_AF GPIO_AF_FMC /*CLK同步时钟,存储区域2*/ #define FMC_CLK_GPIO_PORT GPIOG #define FMC_CLK_GPIO_CLK RCC_AHB1Periph_GPIOG #define FMC_CLK_GPIO_PIN GPIO_Pin_8 #define FMC_CLK_PINSOURCE GPIO_PinSource8 #define FMC_CLK_AF GPIO_AF_FMC /*CKE时钟使能,存储区域2*/ #define FMC_CKE_GPIO_PORT GPIOH #define FMC_CKE_GPIO_CLK RCC_AHB1Periph_GPIOH #define FMC_CKE_GPIO_PIN GPIO_Pin_7 #define FMC_CKE_PINSOURCE GPIO_PinSource7 #define FMC_CKE_AF GPIO_AF_FMC /*DQM1数据掩码*/ #define FMC_UDQM_GPIO_PORT GPIOE #define FMC_UDQM_GPIO_CLK RCC_AHB1Periph_GPIOE #define FMC_UDQM_GPIO_PIN GPIO_Pin_1 #define FMC_UDQM_PINSOURCE GPIO_PinSource1 #define FMC_UDQM_AF GPIO_AF_FMC /*DQM0数据掩码*/ #define FMC_LDQM_GPIO_PORT GPIOE #define FMC_LDQM_GPIO_CLK RCC_AHB1Periph_GPIOE #define FMC_LDQM_GPIO_PIN GPIO_Pin_0 #define FMC_LDQM_PINSOURCE GPIO_PinSource0 #define FMC_LDQM_AF GPIO_AF_FMC /** @defgroup STM32429 SDRAM函数 * @{ */ void SDRAM_Init(void); void SDRAM_WriteBuffer(uint32_t* pBuffer, uint32_t uwWriteAddress, uint32_t uwBufferSize); void SDRAM_ReadBuffer(uint32_t* pBuffer, uint32_t uwReadAddress, uint32_t uwBufferSize); uint8_t SDRAM_Test(void); #endif /* __SDRAM_H */
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。