STM32硬件基础--FMC读写片外SDRAM

【海东青电子原创文章,转载请注明出处:https://www.jianshu.com/p/506b0c696707

在前一篇文章《STM32硬件基础--FSMC》中讨论了FSMC的基本用法,今天来说说FMC。虽然跟FSMC相比,FMC只是少了一个S,但应用难度可是大大增加了。对于连接片外RAM而言,FSMC接的是静态RAM,FMC接的是动态RAM,而控制动态RAM要复杂得多。举个例子:动态RAM需要不停地(周期性的)刷新,否则RAM中的数据就会丢失,这就产生了“管理”问题,如果用一个MCU来连接DRAM,二者之间交换的就不只是数据(SRAM就是如此)那么简单了,还包含有控制信息。这样,DRAM中除了存储数据的单元,还需要有寄存器(模式寄存器,后面将详述)、还得有个对DRAM的“初始化”过程!这么复杂,为什么还要用DRAM呢?用SRAM不就行了吗?DRAM容量大、便宜呀!所以,PC上那几个G的内存条,都是动态RAM类型的。

STM32F746G-DISCO 板子上使用的是MICRON(美光)公司的 MT48LC4M32B2B5-6A SDRAM芯片。SDRAM,同步的动态RAM的意思。同步,就是需要一个片外时钟CLK信号,所有的读写操作都是跟着这个时钟信号走的,这就叫作“同步”。无疑,SDRAM 是本文中的男一号,是讨论的核心。我们的任务就是如何通过MCU来正确读写SDRAM中的数据。

遗憾的是,SDRAM所涉及的技术比较复杂,需要先了解一些SDRAM技术规范,推荐2个背景资料:

1、《高手进阶,终极内存技术指南》,讲解动态RAM的经典之作,初学者必看。了解基本概念即可。

2、《FMC—扩展外部 SDRAM》,一般性地介绍了SDRAM的基础知识,讲的比较清楚。(向技术博客的原作者致谢!)


上面这些背景资料只需要了解基本概念即可,下面将针对 STM32F746G-DISCO 板子一步步地说明驱动片外SDRAM的方法,包括:

1)使用STM32CUBEMX配置FMC;

2)初始化片外SDRAM;

3)周期性地刷新SDRAM;

4)写代码,通过指针、数组的方式读写片外RAM。

【完整的代码可从此处下载:STM32的FMC例程


为了配置FMC,我们先采取一个偷懒的办法:对于ST官方的开发板,CUBEMX是可以自动配置板子上所有IP资源的,我们重点关心的是有关FMC的参数配置。新建一个CUBEMX项目,选择 STM32F746G-DISCO 板子:


图一


图二

弹出一个对话框,询问是否初始化板子上的所有硬件资源,选 Yes :


图三

找到 FMC 项目,CUBEMX自动配置的参数如下:


图四

赶紧拿个小本子把这些参数记录下来!一会儿我们自己配置FMC时,就要用到这些参数。顺便多说一句,看看上图中FMC的GPIO配置:


图五

注意图五中的PC3这个pin,后面会说到它的问题,这里先卖个关子。

结合F746的芯片参考手册,来重点看看图四中的那些参数。FMC的结构如下:


图六


图七

图六中可以看到,FMC包含了FSMC的功能,此外还支持SDRAM。对于SDRAM,支持2个“Bank”,这是2个物理Bank的意思,可以理解为FMC支持连接2个SDRAM芯片,MCU通过不同的片选信号SDNE0和SDNE1来选择具体使用哪个片外RAM:


图九

我们板子上只有一个SDRAM芯片,它连接的是FMC的Bank1呢,还是Bank2呢?打开 STM32F746G-DISCO 板子的原理图找答案:


图十

显然,使用的是SDNE0,那就是FMC的Bank1无疑了,图七中显示这个Bank内存的起始地址是 0xC000 0000 。这样,在图四的CUBEMX配置界面中,我们应选择的是 SDRAM 1(即Bank1),以及 SDCKE0+SDNE0。但,图四中的 Internal bank number 为什么要选 4 banks 呢?这是说SDRAM芯片的规格是内部有4个bank(即《高手进阶,终极内存技术指南》中说的L-BANK),打开芯片 MT48LC4M32B2 的文档:


图十一

可见,内部是4个Bank,并且行地址为12-bit,列地址为8-bit,所以图四中的Address要设置成12bit。图四中的 Data 选项(在这里应该是FMC数据宽度的意思)需要特别说明一下:MT48LC4M32B2是32位宽的(一次可以读/写32-bit数据),这里为什么配置成了 16 bit 呢?再来看看开发板的原理图(上面图十),高16位数据线DQ16-DQ31接地、没有用到!---- 把这个SDRAM当16-bit的芯片来使用了(那不是浪费了一半的存储容量?确实如此!)。这是因为,STM32F746G-DISCO 板子跑 touchgfx 应用时,只支持16位色,所以16-bit的位宽够用了(对应的,编程时使用 uint16_t 的数据类型)。

再看图四下方的参数,重点讨论一下 CAS latency(SDRAM规范文档中的标识符为:CL),SDRAM文档中称为“读取潜伏期”,具体到 MT48LC4M32B2 这个芯片,CAS latency 的取值范围是这样规定的:


图十二

CL不能小于18ns,换算成SDRAM的CLK是多少呢?首先要看一下CUBEMX中配置的时钟频率:


图十三

MCU的HCLK配置成了200MHz,图四中,SDRAM的CLK是HCLK/2(SDRAM common clock 为 2 HCLK clock cycles),即 100MHz,一个CLK是 1/100MHz == 10ns,即CL要大于1.8个CLK,取整后最小值为2。CUBEMX把CL配置成3是放了一些余量。

图四最下面是SDRAM时序的参数,这里暂时先跳过,我们先按CUBEMX的参数,照猫画虎,自己动手配置FMC。新建一个CUBEMX项目,这次我们不选开发板、而是按选择芯片的方式新建项目:


图十四


图十五


图十六


图十七

为了方便调试,配置板子上的LED(PI口的PIN1):


图十八

重点是FMC:


图十九


图二十

重要的问题来了:我们来看看CUBEMX为FMC自动分配的IO管脚:


图二十一

注意,FMC的信号线 FMC_SDCK0 分配给了 PH2 这个管脚。再来看之前提到的那个图五中的“关子”: FMC_SDCK0 分配给了 PC3!查F746的芯片手册知道,PC3、PH2都可以通过复用功能映射成 FMC_SDCK0 信号。开发板上到底是用的哪个pin?原理图上找答案:


图二十二


图二十三

可见,图五中的管脚配置是“正确”的。但图二十一的配置也可以理解(不是CUBEMX的bug):因为是按选择芯片型号来让CUBEMX自动配置FMC的,CUBEMX并不知道用户实际的电路板上FMC是用哪个pin来对应 FMC_SDCK0 信号的,只能把 FMC_SDCK0 信号分配到某一个pin上(本例中是PH2)。如果与实际电路不符,需要由用户手动修改。而在图二十一中,是按开发板来配置的,CUBEMX知道板子的具体型号,就可以按实际的管脚来正确分配 FMC_SDCK0 信号。其他所有具有复用功能的GPIO都有这个问题,希望大家重视。(这是通过血的教训换来的,第一次用CUBEMX配置FMC时,忽略了这个问题,导致编写代码调试SDRAM时,读出数据总是不稳定、或出错,并且难以调试、追踪,耗了一周时间才找到问题根源,教训深刻啊)

现在来修改图二十一中的管脚配置,同时介绍一个配置GPIO复用功能的小技巧。因为PH2不是我们想要的pin,需要查找其他复用功能为  FMC_SDCK0 的pin,可以先按下Ctrl 键,然后鼠标点击 PH2 管脚,CUBE界面上会有2个pin(PC3和PC5)改变了颜色:


图二十四

修改PC3的功能为 FMC_SDCK0:

图二十五

最后,别忘了把时钟配置到200MHz:


图二十六

然后,生成KEIL工程。main.c中,


图二十七

MX_FMC_Init() 函数实现对FMC的配置,它调用了stm32fxx_hal_sdram.c文件中的 HAL_SDRAM_Init() ,后者首先调用 HAL_SDRAM_MspInit() 对FMC用到的pin初始化,然后分别调用 FMC_SDRAM_Init() 和 FMC_SDRAM_Timing_Init() 对FMC的控制寄存器 FMC_SDCR 和时序寄存器 FMC_SDTR 进行初始化。至此,FMC的配置全部结束,程序可以编译、通过,但还不能正确读写SDRAM,因为SDRAM在正式工作之前,还需要一个“SDRAM初始化”的过程。显然,这个初始化过程对于不同型号的SDRAM可能是不同的,CUBEMX就无能为力了。但仍有捷径可走 ---- 找ST官方的例子:


图二十八

先找到STM32CUBE的F7库的安装目录,然后进入F746G-DISCO 的项目目录,在例子中有关于FMC的例程。从 FMC_SDRAM 项目中的 main.c 文件中,copy 对SDRAM做初始化的函数:BSP_SDRAM_Initialization_Sequence() 到我们的main.c 中,并在 MX_FMC_Init() 函数尾部添加调用:


图二十九

请注意,例程 FMC_SDRAM  中的 CAS Latency 是2,对应地设置SDRAM模式寄存器时也是2。而我们在CUBEMX中将CAS Latency 配置为3,则设置SDRAM模式寄存器时也必须是3:


图三十

刷新周期的计算:先看看 MT48LC4M32B2 手册对刷新周期的时间要求:


图三十一

要求最慢在64ms内对4096行(对应12-bit行地址空间)完成刷新,就是说64ms要刷4096次,所以每刷一次的时间间隔是 64ms÷4096=15.625us。换算成SDRAM的CLK(即SDCLK,100MHz):15.625us÷(1/100us)=1562。为了保证刷新周期在SDRAM的任何工作状态下都能小于64ms,要再减去20个SDCLK(这是SDRAM规范文档要求的),即1562-20=1542。例程中用的数字是1292,则刷新周期在54ms左右。一旦完成刷新参数设置(写到 SDRTR 寄存器中),FMC立即自动开始刷新,即每隔大约60ms,MCU通过FMC向SDRAM发送一条刷新指令。

至此,完成了FMC配置、SDRAM初始化、SDRAM刷新3大步骤,到了最后一步:编程访问SDRAM。关键的一个问题是:外部SDRAM地址从0xC000 0000 开始,如何定义一个变量(数组),使得它的地址恰恰从0xC000 0000 开始?一种方法是定义一个uint16_t类型的数据指针,并且使得这个指针指向0xC000 0000地址,如:

#define    SDRAM_BANK_ADDR       ((uint32_t)0xC0000000)

uint16_t    *pSDRAM;

//set data pointer, pointing external sdram

pSDRAM = (uint16_t *)SDRAM_BANK_ADDR;

然后通过 (*pSDRAM + i) 或 pSDRAM[ i ] 即可访问数据了。在演示代码中,先将一些16位的无符号数据写入SDRAM,再从SDRAM中读出到一个内存数组,然后做比较,如果数据全部匹配,则LED每隔一秒钟慢闪一次;如果数据有误,则LED快闪。通过实验可以看到,LED慢闪,表明读写SDRAM是正确的。

完整的代码请从此处下载:STM32的FMC例程,包含 KEIL 和 IAR 两个版本。

最后,补充图四下方时序参数的说明。SDRAM的时序参数,有不同的描述方式,但在SDRAM规范中,它们都是有统一的“代号”的,比如图四中的 Load mode register to active delay,说的是装载模式寄存器需要花费的时间,代号是tMRD。图四中其他的代号如下:


图三十二

然后,按图索骥,在MT48LC4M32B2 手册中查找:


图三十三


图三十四

单位换算关系:我们配置了SDRAM的时钟频率(SDCLK)是100MHz,等同于一个CK是10ns。反之,10ns的时间就是一个CK。可见,图四中的时序参数基本上都是稍微留了余量的。


小结:

1)CUBEMX配置FMC,核心就是图四那一张图(但,本文用了大量的篇幅,才基本说明了这些参数的由来。这么多内容,CUBEMX用一页就搞定了,牛吧?!)。要特别注意GPIO复用功能的管脚配置,须与实际电路连接一致。

2)对于SDRAM,仅仅配置FMC是不够的,还需要编写代码对SDRAM进行初始化,并设置刷新时间。要特别注意 CAS Latency(CL) 的取值,配置FMC的跟SDRAM初始化的要一致(比如,CL都设置成3)。

3)代码中对SDRAM的访问,可以通过定义一个数据指针、并赋值到片外RAM地址的方式实现。

本文完。


参考文献:

1. 《STM32CubeMX配置SDRAM

详述了配置过程,特别提到了因为TouchGFX对SDRAM做了相关配置,从而系统自动生成了 MX_SDRAM_InitEx() 初始化函数。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容