文档库 最新最全的文档下载
当前位置:文档库 › STM32 SDRAM扩展及FSMC研究

STM32 SDRAM扩展及FSMC研究

STM32 SDRAM扩展及FSMC研究
STM32 SDRAM扩展及FSMC研究

STM32之FSMC初级研究篇V1.0

一.FSMC简介 (2)

二.FSMC控制TFT彩屏的应用 (5)

三.FSMC扩展外部SRAM应用 (7)

技术交流QQ:99133698,86553920

一.FSMC简介

我们知道STM32是不带MMU的,但为了扩展外部存储器,高密度(256 KB以上FlaSh)的STM32内部带了一个类似MMU的FSMC(可变静态存储控制器),专门为100pin以上的STM32提供一个灵活的外部存储选项。FSMC不像MMU,他是不能实现管理虚拟内存的,也就是说STM32的地址线为32位,能访问的最大地址不能超过4G,但FSMC没有实现全部4G的管理,其最大能管理1Gbyte.

1.FSMC的特点:

①支持多种静态存储器类型。STM32通过FSMC可以与SRAM、ROM、PSRAM、NOR Flash和NANDFlash存储器的引脚直接相连。

②支持丰富的存储操作方法。FSMC不仅支持多种数据宽度的异步读/写操作,而且支持对NOR/PSRAM/NAND存储器的同步突发访问方式。

③支持同时扩展多种存储器。FSMC的映射地址空间中,不同的BANK是独立的,可用于扩展不同类型的存储器。当系统中扩展和使用多个外部存储器时,FSMC会通过总线悬空延迟时间参数的设置,防止各存储器对总线的访问冲突。

④支持更为广泛的存储器型号。通过对FSMC的时间参数设置,扩大了系统中可用存储器的速度范围,为用户提供了灵活的存储芯片选择空间。

⑤支持代码从FSMC扩展的外部存储器中直接运行,而不需要首先调入内部SRAM。

2.FSMC包含两种控制器:

1个NOR闪存/SRAM控制器,可以与NOR闪存、SRAM和PSRAM存储器接口。

1个NAND闪存/PC卡控制器,可以与NAND闪存、PC卡,CF卡和CF+存储器接口。

STM32微控制器之所以能够支持NOR Flash和NAND Flash这两类访问方式完全不同的存储器扩展,是因为FSMC内部实际包括NOR Flash和NAND/PC Card两个控制器,分别支持两种截然不同的存储器访问方式。在STM32内部,FSMC的一端通过内部高速总线AHB连接到内核Cortex-M3,另一端则是面向扩展存储器的外部总线。内核对外部存储器的访问信号发送到AHB总线后,经过FSMC转换为符合外部存储器通信规约的信号,送到外部存储器的相应引脚,实现内核与外部存储器之间的数据交互。FSMC起到桥梁作用,既能够进行信号类型的转换,又能够进行信号宽度和时序的调整,屏蔽掉不同存储类型的差异,使之对内核而言没有区别。

3.FSMC的地址映射

FSMC管理1 GB的映射地址空间。该空间划分为4个大小为256 MB的BANK,每个BANK又划分为4个64 MB的子BANK,如表1所列。FSMC的2个控制器管理的映射地址空间不同。NOR Flash控制器管理第1个BANK,NAND/PC Card控制器管理第2~4个BANK。由于两个控制器管理的存储器类型不同,扩展时应根据选用的存储设备类型确定其映射位置。其中,BANK1的4个子BANK拥有独立的片选线和控制寄存器,可分别扩展一个独立的存储设备,而BANK2~BANK4只有一组控制寄存器

二.FSMC控制TFT彩屏的应用

STM32使用彩屏,可以采用普通的接线方式也可以用FSMC总线。

1.因为液晶屏一般都带有8080总线,包括WR,RD,CS控制线和还有数据总线,当然还有液

晶屏的特殊控制线RS(数据命令选择信号),没有地址线。由于普通接线方式在数据的读写时需要配置成不同的模式导致速度会较慢,而且普通IO口最大只能到50MHZ,读写驱动函数较为耗时,在有外部存储器扩展的情况下,TFT的数据总线只能接到A,B,C这三个口(D,E,F,G都带有FSMC控制线),用普通接线方式让带有FSMC的丰富接口的STM32造成了接口不丰富的假象,其他外设如NRF2401,eprom,网口等这些需要在A,B,C总线上其他复用功能的外设就得为彩屏绕道!!这是很大浪费不是吗。

2.采用FSMC总线来控制彩屏是最理想的。FSMC总线可到72Mhz,另外可以和外部存储器共

用总线,这样就大大提高了IO的利用率。同时FSMC访问液晶是以SRAM的方式访问的,访问速度非常快!只要配置好FSMC的寄存器就能很轻松控制彩屏了,按照官方的例程(多数国产开发板也是参照官方的:如红牛,野火,神州,红龙,原子),液晶屏都是接在NOR/SRAM区的第四块,也就是Bank1->NE4,也就是所地址是从0x6c000000开始的。

那为啥不接在NE1,NE2,NE3,而接在NE4呢,因为官方的评估板NE2是接NOR FLASH,NE3是接SRAM.NE1好像也接了NOR/SRAM,所以用最后的NE4作为液晶的CS控制线;数据线直接接在FSMC上(液晶要引出16位数据线,8位兼容模式不太建议);WR接在FSMC_NWE,RD接在FSMC_NOE,最关键的是RS信号,我这里重点讲下。

FSMC对外部设备的地址映像从0x6000 0000开始,到0x9FFF FFFF结束,这里的地址指的是内部AHB总线上的地址,而外部其实只有0-25总共26根地址线(64MB)。以bank1为例:最大是256MB,NE1-NE4片选其实就是内部的高四位的地址线,这样就能表示4*64=256MB了。外部的地址线0-25是由内部的HADDR[25:0]映射出来的;

这里的HADDR是需要转换到外部设备的内部AHB地址线,每个地址对应一个字节单元。因此,若外部设备的地址宽度是8位的,则 HADDR[25:0]与STM32的CPU引脚FSMC_A[25:0]一一对应,最大可以访问64M字节的空间。若外部设备的地址宽度是16位的,则是HADDR[25:1]与STM32的CPU引脚FSMC_A[24:0]一一对应。在应用的时候,可以将FSMC_A 总线连接到存储器或其他外设的地址总线引脚上。

使用FSMC控制器后,可以把FSMC提供的FSMC_A[25:0]作为地址线,而把FSMC提供的FSMC_D[15:0]作为数据总线。

看了上面也许你还一头雾水,我们拿官方评估板来说吧(请看上图):

下面是官方评估板移植STemWIN的代码,打开相应的文件,stm32f10e_eval_lcd.c是基本的彩屏驱动文件,LCDConf_stm32f10e_eval.c是移植emWIN时的液晶配置文件,我们可以看到FSMC的地址线线接到彩屏的只有A0,A0是作为RS(数据命令)的选通线。仔细点看,有个问题!!!!!既然是A0,那定义的那个LCD结构体LCD->LCD_REG访问的是

0x6c000000,LCD->LCD_RAM访问的是0x6c000002啊,那A0不是一直都是0么.不是的,这就是上面的讲的若外部设备的地址宽度是16位的,则是HADDR[25:1]与STM32的CPU引脚FSMC_A[24:0]一一对应。也就是说我们设置FSMC相关寄存器时候,设置外部访问数据是16bit的话,内部的HADDR[25:1]自动映射到外部IO的ADDR[24:0](也就是IO要开重映射功能时钟的原因吧?)。16bit数据宽度情况下,内部的HADDR的A1才是对于外部IO的A0.内部HADDR_A0始终是0的,所以他不会被映射出来,这就可以让外部地址可以连续的,感觉和访问8位数据一样。

三.FSMC扩展外部SRAM应用

1.UI内存分析

以官方评估板移植StemWIN来说:移植过UCGUI的哥们知道UI对SRAM需求是比较大的,要是全部DEMO都运行的话,对于低密度的STM32来说还是比较费劲的,UCGUI总的代码量+DEMO 需要至少100k(MDK开最高优化等级),ram需求也是比较高的(具体没有实测过,有时间可以用UCOSII测量下内存),UCGUI尚且如此,emWIN更是坑。

官方评估板移植emWIN有带freeos和裸奔的,下面是在MDK下以裸奔的截图。看到消耗这么大,也许还在用STM32_ZE以下的哥们都很无语了,哥片子不够啊!再来看看DEMO的配置,果断发现这些DEMO配置和UCGUI几乎一样啊,关键的DEMO不敢配置上去,因为耗不起!!!看着这么perfect的DEMO就是用不了,心都碎了。

痛定思痛,板子还是可以扩展的不是吗,闲话不扯进入主题。

2.移植SRAM三部曲:

第一部:设置编译器使用外部SRAM,首先打开option for target

我的板子的SRAM接的的NE3,大小为256*16bit==512kbyte,上面可根据你的板子设置。NE1:6000 0000h--63ff ffffh,

NE2:6400 0000h--67ff ffffh,

NE3:6800 0000h--6bff ffffh,

NE4:6c00 0000h--6fff ffffh

第二部:设置启动文件的堆栈位置,打开启动文件

这是设置堆栈的位置,堆栈的尺寸可以调整,有的启动文件设置为0x400,看到46行,这里默认的初始化堆栈是初始化内部sram空间,加了外部sram后我们一定要告诉编译器,堆栈还是从内部sram开始的。这是最关键的,否则外部扩展的SRAM无法用,而且程序也跑不起来,看起来就像死机一样。用__initial_sp EQU 0x20000000 + Stack_Size替换掉__initial_sp即可!!!!

第三部:初始化FSMC,打开system_stm32f10x.c(3.5版固件才有)

定义#define DATA_IN_ExtSRAM 1,这SytemInit函数就会调用SystemInit_ExtMemCtl();函数初始化FSMC。

对于使用3.5固件的哥们,完成上面三步就可以了,下面的都可以不需要看!!!

上面步骤我试验过,我的板子外带512K,加个bargraph demo是木有问题的,另外listview Demo是有两条鱼在跑(我的GUI数组:#define GUI_NUMBYTES (1024) * 256 // x Kbyte);手机像素差,这里就不截图为证了!!其他demo需要的sram和rom都比较大,所以读者可根据板子情况试加进去,看清楚编译后代码量!!!

注意:用了外部RAM下载完后,单片机是不会立刻访问外部ram的(即便你设置了下载后复位运行),要按复位按键才会有效,以后每次上电也要按复位按键才会访问外部SRAM,不知啥情况,具体如何设置的暂且不清楚,望知道的大神能帮我补充这个答案!!!!

只需三步即可,这样你定义的大数组编译器就会自动编译到外部SRAM中。而不需要你用__attribute__((at(0x68000000)))告诉编译器编译在外部。

对于还在使用3.5版本固件以下的哥们来说,没有system_stm32f10x.c函数没关系我们可以修改汇编代码,实现第三部的功能:打开启动文件,找到main函数的入口

添加箭头所指的三条代码,这里是以3.5固件说明的,所以带有SystemInit函数。SRAM_Init()函数则会在main函数之前调用,前提是你自己要定义一个SRAM_Init()

函数:官方评估板的SRAM_Init()我试过,好像没有用,下面我贴出SystemInit函数中的初始化代替官方评估板的,可以参考下。

void SRAM_Init(void)

{

/*!< FSMC Bank1 NOR/SRAM3 is used for the STM3210E-EVAL, if another Bank is

required, then adjust the Register Addresses */

/* Enable FSMC clock */

RCC->AHBENR = 0x00000114;

/* Enable GPIOD, GPIOE, GPIOF and GPIOG clocks */

RCC->APB2ENR = 0x000001E0;

/* --------------- SRAM Data lines, NOE and NWE configuration ---------------*/

/*---------------- SRAM Address lines configuration -------------------------*/

/*---------------- NOE and NWE configuration --------------------------------*/

/*---------------- NE3 configuration ----------------------------------------*/

/*---------------- NBL0, NBL1 configuration ---------------------------------*/

GPIOD->CRL = 0x44BB44BB;

GPIOD->CRH = 0xBBBBBBBB;

GPIOE->CRL = 0xB44444BB;

GPIOE->CRH = 0xBBBBBBBB;

GPIOF->CRL = 0x44BBBBBB;

GPIOF->CRH = 0xBBBB4444;

GPIOG->CRL = 0x44BBBBBB;

GPIOG->CRH = 0x44444B44;

/*---------------- FSMC Configuration ---------------------------------------*/

/*---------------- Enable FSMC Bank1_SRAM Bank ------------------------------*/

FSMC_Bank1->BTCR[4] = 0x00001011;

FSMC_Bank1->BTCR[5] = 0x00000200;

}

这样,就不用再main函数中调用初始化函数了,即便你在main函数中调用,编译器也是不认的!!!

3.编译存储区数据设置

对于有深入探究的哥们想知道什么数据编译器会放在外部,什么数据会放在内部,我这里参考keil for c51给大家讲解下仅供参考,也许MDK不太一样!用过STC_51单片机的哥们知道,要用STC_ 51内部外扩的sram有两种方法,一种是在前面加关键字xdata,另外一种是在option for target 上选择用large模式。选用large模式后,我们看到编译出来编译输出窗口多了个xdata,并且局部变量和数组等都被编译到xdata中了,只有堆栈还留在内部data中。所以设置好编译器外部存储器的使用后,编译器会自动把局部变量和数组都编译到外部取,内部保留的一般都是堆栈或者直接寻址的变量之类的吧!!当然xdata 和__attribute__((at(0x68000000)))一样,也可以让编译器把大数组编译到外部,但是如果没有设置编译器的,那仅仅只有该数组被编译到外部,其他局部变量还是留着内部的。

对于MDK,我们还可以选择什么数据编译到外部(注意:这只有在使用了外部扩展的朋友而言的,),在多文件工程中,我们首先激活main函数所在的*.c文件,激活方法:点击别的文件,然后再点击main所在的*.c文件。

接着我们打开project,看到不是option for target了而是option for file(对于新建的工程也是这样的);打开option for

File ‘main.c’..,界面如下

我们看到了存储器指定的选项,CODE/Const选择代码或常量所在的存储器区,zero 初始化数据指定需要初始化为零的内存区,其他数据选择其他数据所在的存储区。我根据自己的板子设置如下:

特别要注意的是,这是不必要的设置,因为编译器会自动帮你编译到最合适的地方去的。虽然你可以任性,但是当你不需要外部ram的时候,并且启动文件没有设置堆栈,系统初始化文件没有定义使用外部sram的宏时,请将上面的配置设置为默认,否则你的程序跑不起来!!!!屏幕是白的!!!而且即便你用了SRAM告诉你,这样设置也是不合理的,程序跑着跑着会出现屏幕白屏,但是其实单片机没有死,是访问的数据区出问题了!!!!在这里提出这个并非是给那些初学者建议而已,网上有说这个设置的,初学者请慎重考虑,任性也别忘啦可行性!!!

相关文档