STM32学习之:FMC-扩展外部SDRAM

参考资料:《STM32F4xx 参考手册 2》、《STM32F4xx 规格书》、库帮助文档《stm32f4xx_dsp_stdperiph_lib_um.chm》。

关于 SDRAM 存储器,请参考前面的“常用存储器介绍”,实验中 SDRAM 芯片的具体参数,请参考其规格书《IS42-45S16400J》来了解。

1、 SDRAM 控制原理

  STM32 控制器芯片内部有一定大小的 SRAM 及 FLASH 作为内存和程序存储空间,但当程序较大,内存和程序空间不足时,就需要在 STM32 芯片的外部扩展存储器了。

  STM32F429 系列芯片扩展内存时可以选择 SRAM 和 SDRAM,由于 SDRAM 的“容量/价格”比较高,即使用 SDRAM 要比 SRAM 要划算得多。我们以 SDRAM 为例讲解如何为 STM32 扩展内存。

  给 STM32 芯片扩展内存与给 PC扩展内存的原理是一样的,只是 PC上一般以内存条的形式扩展,内存条实质是由多个内存颗粒(即 SDRAM 芯片)组成的通用标准模块,而STM32 直接与 SDRAM 芯片连接。见图 26-2,这是一种型号为 IS42-45S16400J 的 SDRAM芯片内部结构框图,以它为模型进行学习。

  STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

1.1 SDRAM 信号线

  上图虚线框外引出的是 SDRAM 芯片的控制引脚,其说明见下表:

 STM32学习之:FMC-扩展外部SDRAM

除了时钟、地址和数据线,控制 SDRAM 还需要很多信号配合,它们具体作用在描述时序图时进行讲解。

1.2 、控制逻辑

  SDRAM 内部的“控制逻辑”指挥着整个系统的运行,外部可通过 CS、WE、CAS、RAS以及地址线来向控制逻辑输入命令,命令经过“命令器译码器”译码,并将控制参数保存到“模式寄存器中”,控制逻辑依此运行。

1.3、 地址控制

  SDRAM 包含有“A”以及“BA”两类地址线,A类地址线是行(Row)与列(Column)共用的地址总线,BA地址线是独立的用于指定 SDRAM 内部存储阵列号(Bank)。在命令模式下,A类地址线还用于某些命令输入参数。

1.4 、SDRAM 的存储阵列

  要了解 SDRAM 的储存单元寻址以及“A”、“BA”线的具体运用,需要先熟悉它内部存储阵列的结构。见下图:SDRAM的存储阵列模型。

STM32学习之:FMC-扩展外部SDRAM

  SDRAM 内部包含的存储阵列,可以把它理解成一张表格,数据就填在这张表格上。和表格查找一样,指定一个行地址和列地址,就可以精确地找到目标单元格,这是SDRAM 芯片寻址的基本原理。这样的每个单元格被称为存储单元,而这样的表则被称为存储阵列(Bank),目前设计的 SDRAM 芯片基本上内部都包含有 4 个这样的 Bank,寻址时指定 Bank号以及行地址,然后再指定列地址即可寻找到目标存储单元。SDRAM 内部具有多个 Bank时的结构见下图:

STM32学习之:FMC-扩展外部SDRAM

SDRAM 芯片向外部提供有独立的 BA类地址线用于 Bank寻址,而行与列则共用 A类地址线。

图 26-2标号4中表示的就是它内部的存储阵列结构,通讯时当 RAS线为低电平,则“行地址选通器”被选通,地址线 A[11:0]表示的地址会被输入到“行地址译码及锁存器”中,作为存储阵列中选定的行地址,同时地址线 BA[1:0]表示的 Bank也被锁存,选中了要操作的 Bank号;接着控制 CAS线为低电平,“列地址选通器”被选通,地址线 A[11:0]表示的地址会被锁存到“列地址译码器”中作为列地址,完成寻址过程。

1.5 、数据输入输出

  若是写 SDRAM 内容,寻址完成后,DQ[15:0]线表示的数据经过图 26-2 标号5中的输入数据寄存器,然后传输到存储器阵列中,数据被保存;数据输出过程相反。

  本型号的 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 需要用到一系列的命令,见下表。各种信号线状态组合产生不同的控制命令。

STM32学习之:FMC-扩展外部SDRAM

表中的 H 表示高电平,L 表示低电平,X表示任意电平,High-Z 表示高阻态。

STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

本型号的 SDRAM 芯片表示列地址时仅使用 A[7:0]线,而 A10 线用于控制是否“自动预充电”,该线为高电平时使能,低电平时关闭。

STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

6. 刷新

  SDRAM 要不断进行刷新(Refresh)才能保留住数据,因此它是 DRAM 最重要的操作。刷新操作与预充电中重写的操作本质是一样的。

  但因为预充电是对一个或所有 Bank 中的工作行操作,并且不定期,而刷新则是有固定的周期,依次对所有行进行操作,以保证那些久久没被访问的存储单元数据正确。

  刷新操作分为两种:“自动刷新”(Auto Refresh)与“自我刷新”(Self Refresh),发送命令后 CKE 时钟为有效时(低电平),使用自动刷新操作,否则使用自我刷新操作。不论是何种刷新方式,都不需要外部提供行地址信息,因为这是一个内部的自动操作。

  对于“自动刷新”, SDRAM 内部有一个行地址生成器(也称刷新计数器)用来自动地依次生成行地址,每收到一次命令刷新一行。在刷新过程中,所有 Bank都停止工作,而每次刷新所占用的时间为 N 个时钟周期(视 SDRAM 型号而定,通常为 N=9),刷新结束之后才可进入正常的工作状态,也就是说在这 N 个时钟期间内,所有工作指令只能等待而无法执行。一次次地按行刷新,刷新完所有行后,将再次对第一行重新进行刷新操作,这个对同一行刷新操作的时间间隔,称为 SDRAM 的刷新周期,通常为 64ms。显然刷新会对SDRAM 的性能造成影响,但这是它的 DRAM 的特性决定的,也是 DRAM 相对于 SRAM取得成本优势的同时所付出的代价。

  “自我刷新”则主要用于休眠模式低功耗状态下的数据保存,也就是说即使外部控制器不工作了,SDRAM 都能自己确保数据正常。在发出“自我刷新”命令后,将 CKE 置于无效状态(低电平),就进入自我刷新模式,此时不再依靠外部时钟工作,而是根据 SDRAM内部的时钟进行刷新操作。在自我刷新期间除了 CKE 之外的所有外部信号都是无效的,只有重新使 CKE 有效才能退出自我刷新模式并进入正常操作状态。(用于低功耗)

  7. 加载模式寄存器

前面提到 SDRAM 的控制逻辑是根据它的模式寄存器来管理整个系统的,而这个寄存器的参数就是通过“加载模式寄存器”命令(LOAD MODE REGISTER)来配置的。发送该命令时,使用地址线表示要存入模式寄存器的参数“OP-Code”,各个地址线表示的参数如下图:

STM32学习之:FMC-扩展外部SDRAM

模式寄存器的各个参数介绍如下:

Burst Length

  Burst Length译为突发长度,下面简称 BL。突发是指在同一行中相邻的存储单元连续进行数据传输的方式,连续传输所涉及到存储单元(列)的数量就是突发长度。

  上文讲到的读/写操作,都是一次对一个存储单元进行寻址,如果要连续读/写就还要对当前存储单元的下一个单元进行寻址,也就是要不断的发送列地址与读/写命令(行地址不变,所以不用再对行寻址)。虽然由于读/写延迟相同可以让数据的传输在 I/O 端是连续的,但它占用了大量的内存控制资源,在数据进行连续传输时无法输入新的命令,效率很低。

  为此,人们开发了突发传输技术,只要指定起始列地址与突发长度,内存就会依次地自动对后面相应数量的存储单元进行读/写操作而不再需要控制器连续地提供列地址。这样,除了第一笔数据的传输需要若干个周期外,其后每个数据只需一个周期的即可获得。其实我们在 EERPOM 及 FLASH 读写章节讲解的按页写入就是突发写入,而它们的读取过程都是突发性质的。  

  非突发连续读取模式:不采用突发传输而是依次单独寻址,此时可等效于 BL=1。虽然也可以让数据连续地传输,但每次都要发送列地址与命令信息,控制资源占用极大。突发连续读取模式:只要指定起始列地址与突发长度,寻址与数据的读取自动进行,而只要控制好两段突发读取命令的间隔周期(与 BL 相同)即可做到连续的突发传输。 而 BL 的数值,也是不能随便设或在数据进行传输前临时决定。在初始化 SDRAM 调用 LOAD MODEREGISTER 命令时就被固定。BL可用的选项是 1、2、4、8,常见的设定是 4 和 8。若传输时实际需要数据长度小于设定的 BL值,则调用“突发停止”(BURST TERMINATE)命令结束传输。

BT  

  模式寄存器中的 BT位用于设置突发模式,突发模式分为顺序(Sequential)与间隔(Interleaved)两种。在顺序方式中,操作按地址的顺序连续执行,如果是间隔模式,则操作地址是跳跃的。跳跃访问的方式比较乱,不太符合思维习惯,我们一般用顺序模式。顺序访问模式时按照 “0-1-2-3-4-5-6-7”的地址序列访问。

CASLatency  

模式寄存器中的 CASLatency是指列地址选通延迟,简称 CL。在发出读命令(命令同时包含列地址)后,需要等待几个时钟周期数据线 DQ 才会输出有效数据,这之间的时钟周期就是指 CL,CL一般可以设置为 2 或 3个时钟周期。如下图:

STM32学习之:FMC-扩展外部SDRAM

  CL只是针对读命令时的数据延时,在写命令时不需要这个延时的,发出写命令时可同时发送要写入的数据。

Op Mode  

  OP Mode指 Operating Mode,SDRAM 的工作模式。当它被配置为“00”的时候表示工作在正常模式,其它值是测试模式或被保留的设定。实际使用时必须配置成正常模式。

WB

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

Reserved

  模式寄存器的最后三位的被保留,没有设置参数。

7 SDRAM 的初始化流程

  最后我们来了解 SDRAM 的初始化流程。SDRAM 并不是上电后立即就可以开始读写数据的,它需要按步骤进行初始化,对存储矩阵进行预充电、刷新并设置模式寄存器,见图 26-10。

STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

其中 t RP 、t RFC 、t MRD 等时间参数跟具体的 SDRAM 有关,可查阅其数据手册获知,STM32 FMC访问时配置需要这些参数。

 SDRAM 的读写流程

初始化步骤完成,开始读写数据,其时序流程见图 26-11 及图 26-12。

STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

 STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

1. 通讯引脚

  在框图的右侧是 FMC外设相关的控制引脚,由于控制不同类型存储器的时候会有一些不同的引脚,看起来有非常多,其中地址线 FMC_A和数据线 FMC_D 是所有控制器都共用的。这些 FMC引脚具体对应的 GPIO 端口及引脚号可在《STM32F4xx 规格书》中搜索查找到,不在此列出。针对 SDRAM 控制器,我们是整理出以下的 FMC与 SDRAM 引脚对照表 26-3。

STM32学习之:FMC-扩展外部SDRAM

STM32学习之: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 的地址不一样。

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 的自动刷新周期。

3. 时钟控制逻辑  

  FMC外设挂载在 AHB3 总线上,时钟信号来自于 HCLK(默认 180MHz),控制器的时钟输出就是由它分频得到。如 SDRAM 控制器的 FMC_SDCLK 引脚输出的时钟,是用于与SDRAM 芯片进行同步通讯,它的时钟频率可通过 FMC_SDCR1 寄存器的 SDCLK 位配置,可以配置为 HCLK 的 1/2 或 1/3,也就是说,与 SDRAM 通讯的同步时钟最高频率为90MHz。

 

FMC 的地址映射  

  FMC连接好外部的存储器并初始化后,就可以直接通过访问地址来读写数据,这种地址访问与 I2C EEPROM、SPI FLASH 的不一样,后两种方式都需要控制 I2C或 SPI总线给存储器发送地址,然后获取数据;在程序里,这个地址和数据都需要分开使用不同的变量存储,并且访问时还需要使用代码控制发送读写命令。而使用 FMC外接存储器时,其存储单元是映射到 STM32 的内部寻址空间的;在程序里,定义一个指向这些地址的指针,然后就可以通过指针直接修改该存储单元的内容,FMC外设会自动完成数据访问过程,读写命令之类的操作不需要程序控制。 

 STM32学习之:FMC-扩展外部SDRAM

  图中左侧的是 Cortex-M4 内核的存储空间分配,右侧是 STM32 FMC 外设的地址映射。可以看到 FMC的 NOR/PSRAM/SRAM/NAND FLASH 以及 PC卡的地址都在 External RAM地址空间内,而 SDRAM 的地址是分配到 External device区域的。正是因为存在这样的地址映射,使得访问 FMC控制的存储器时,就跟访问 STM32 的片上外设寄存器一样(片上外设的地址映射即图中左侧的“Peripheral”区域)。

1. SDRAM 的存储区域  

  FMC把 SDRAM 的存储区域分成了 Bank1 和 Bank2 两块,这里的 Bank与 SDRAM 芯片内部的 Bank是不一样的概念,只是 FMC的地址区域划分而已。每个 Bank有不一样的起始地址,且有独立的 FMC_SDCR 控制寄存器和 FMC_SDTR 时序寄存器,还有独立的FMC_SDCKE 时钟使能信号线和 FMC_SDCLK 信号线。FMC_SDCKE0和 FMC_SDCLK0对应的存储区域 1 的地址范围是 0xC000 0000-0xCFFF FFFF,而 FMC_SDCKE1 和FMC_SDCLK1 对应的存储区域 2 的地址范围是 0xD000 0000- 0xDFFF FFFF。当程序里控制内核访问这些地址的存储空间时,FMC外设会即会产生对应的时序,对它外接的SDRAM 芯片进行读写。

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 存储器的空间却被分配到了 Extern 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 或Exteranl device 区域都没有区别,不需要与 NAND 的映射地址交换。

  5、 SDRAM 时序结构体

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

STM32学习之:FMC-扩展外部SDRAM

  这个结构体成员定义的都是 SDRAM 发送各种命令后必须的延迟,它的配置对应到FMC_SDTR 中的寄存器位。所有成员参数值的单位是周期,参数值大小都可设置成“1-16”。关于这些延时时间的定义可以看“SDRAM 初始化流程”和“SDRAM 读写流程”小节的时序图了解。具体参数值根据 SDRAM 芯片的手册说明来配置。各成员介绍如下:

STM32学习之:FMC-扩展外部SDRAM

  这个 SDRAMTimingInitTypeDef 时序结构体配置的延时参数,将作为下一节的 FMC  SDRAM 初始化结构体的一个成员。

SDRAM 初始化结构体

STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

  这个结构体,除最后一个成员是上一小节讲解的时序配置外,其它结构体成员的配置都对应到 FMC_SDCR 中的寄存器位。各个成员意义在前面的小节已有具体讲解,其可选参数介绍如下,括号中的是 STM32 标准库定义的宏:

STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

  配置完 SDRAM 初始化结构体后,调用 FMC_SDRAMInit 函数把这些配置写入到 FMC的 SDRAM 控制寄存器及时序寄存器,实现 FMC的初始化。

SDRAM 命令结构体

控制 SDRAM 时需要各种命令,通过向 FMC的命令模式寄存器 FMC_SDCMR写入控制参数,即可控制 FMC对外发送命令,为了方便使用,STM32 标准库也把它封装成了结构体,见代码清单 26-3。

STM32学习之:FMC-扩展外部SDRAM

命令结构体中的各个成员介绍如下:

STM32学习之:FMC-扩展外部SDRAM

  配置完这些结构体成员,调用库函数 FMC_SDRAMCmdConfig即可把这些参数写入到FMC_SDCMR寄存器中,然后 FMC外设就会发送相应的命令了。

特殊引脚:

STM32学习之:FMC-扩展外部SDRAMSTM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

. 编程要点

1、 初始化通讯使用的目标引脚及端口时钟;
2、使能 FMC外设的时钟;
3、 配置 FMC SDRAM 的时序、工作模式;
4、根据 SDRAM 的初始化流程编写初始化函数;
5、 建立机制访问外部 SDRAM 存储器;
6、编写测试程序,对读写数据进行校验。

 

把 FMC SDRAM 硬件相关的配置都以宏的形式定义到 “bsp_sdram.h”文件中,

STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

  以上代码根据硬件的连接,把与 SDRAM 通讯使用的引脚号、引脚源以及复用功能映射都以宏封装起来。其中 FMC_CKE和 FMC_CLK 引脚对应的是 FMC的存储区域 2,所以后面我们对 SDRAM 的寻址空间也是要指向存储区域 2 的。

  初始化 FMC  的 GPIO

利用上面的宏,编写 FMC的 GPIO 引脚初始化函数,

STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

  与所有使用到 GPIO 的外设一样,都要先把使用到的 GPIO 引脚模式初始化,以上代码把 FMC SDRAM 的所有信号线全都初始化为 FMC 复用功能,所有引脚配置都是一样的。

配置 FMC 

  接下来需要配置 FMC SDRAM 的工作模式,这个函数的主体是根据硬件连接的SDRAM 特性,对时序结构体以及初始化结构体进行赋值。

STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

 

 

 设置自动刷新周期

  在上面 SDRAM_InitSequence 函数的最后,我们还调用了库函数 FMC_SetRefreshCount设置 FMC自动刷新周期,这个函数会向刷新定时寄存器 FMC_SDRTR 写入计数值,这个计数值每个 SDCLK 周期自动减 1,减至 0 时 FMC会自动向 SDRAM 发出自动刷新命令,控制 SDRAM 刷新,SDRAM 每次收到刷新命令后,刷新一行,对同一行进行刷新操作的时间间隔称为 SDRAM 的刷新周期。

根据 STM32F4xx 参考手册的说明,COUNT值的计算公式如下:

 

 STM32学习之:FMC-扩展外部SDRAM

STM32学习之:FMC-扩展外部SDRAM

直接定义一个全局变量:

 

#define SDRAM_BASE_ADDR (0XD0000000)

  

/*把变量ptest强制定义到SDRAM_BASE_ADDR中*/

/*使用这种语法一定要定义成全局变量*/
uint16_t ptest __attribute__ ((at(SDRAM_BASE_ADDR+100)));  //0X64

 

uint16_t tempt __attribute__ ((at(SDRAM_BASE_ADDR+40)));  //0X28

 

uint16_t test; 

在main函数中给对应变量赋值:

ptest = 0xaa;

tempt = 0x34;

test = 0xaa;

STM32学习之:FMC-扩展外部SDRAM

在.map中可以看到,test是直接定义到内部SRAM中( 0x20000010),tempt 和 ptest是定义到外部SRAM中的(0xd0000028)。