使用MM32F3270 FSMC驱动外部NOR Flash

mm32系列微控制器为用户提供了丰富的选择,可适用于工业控制、智能家电、建筑安防、医疗设备以及消费类电子产品等多方位嵌入式系统设计。在某些应用中,需要较大容量的存储空间用于存储数据;这时可以通过spi 外扩nor flash,nand flash, 或者通过sdio扩展sd card或tf-card。但有些需要高速存储数据,上述方式还是不够快速,这时可以使用mm32f3270系列的fsmc来外扩并行nor flash来实现。
并行nor flash与并行sram和psram的读写接口大部分相同,但nor flash的写入速度与sram和psram比较,相对较慢,需要通过nwait 信号检查nor flash的操作状态,并做一些等待,相应的时序需要根据不同的nor flash芯片所规定的参数而做相应的设置即可。
本文接下来就使用mm32f3270外挂s29gl128p nor flash芯片来演示fsmc对nor flash芯片的设置与读写。
前文已经介绍了mm32f3270的fsmc的接口功能与特色。结合mm32f3270 的fsmc外部接口信号,可使用异步方式访问nor flash,可以选用复用或非复用方式扩展nor flash,还可以通过配置实现外扩8位总线或16位总线接口的nor flash。
表1:fsmc控制器外部信号
mm32f3270系列mcu因为封装的原因,导致只有部分mcu产品可以通过硬件复用出全部或部分的fsmc接口的相关gpio;外扩nor flash也只有使用 lqfp144引脚封装mcu芯片才能支持连接地址数据非复用和复用方式外扩并行nor flash;而lqfp100引脚封装芯片因地址线缩减,仅支持连接地址数据复用方式外扩并行nor flash。lqfp64因为无法引出足够的地址与数据总线,同样不支持外扩并行nor flash。
表2:mm32f3270不同封装芯片与nor flash接口
目前市场上非复用型16位数据总线接口的nor flash也是较为普遍,下面针对非复用方式,介绍mcu与nor flash的硬件原理图设计和软件寄存器配置。
在此用mm32f3270的fsmc接口扩展s29gl128p nor flash,其原理框图如下:
图1:nor flash原理框图
s29gl128p的数据按 16 位的half word寻址,容量128m bit, 16m字节,从芯片手册中可以查询到s29gl128p的引脚功能描述如下:
表3:nor flash引脚信号
s29gl128p可以通过cs, oe, wr, wp#, ry/by#控制电路,结合address与data i/o实现对nor flash的读写操作。
1、fsmc非复用方式控制nor flash的硬件设计
表4:nor flash数据, 地址, 读写信号与mcu接口的引脚说明
外部设备地址映像从fsmc的角度看,fsmc外扩寻址空间用于访问最多4个fsmc地址映射空间,可以用于访问4个nor闪存或sram/psram存储设备,并对应的有4个专用的片选fsmc_ne[4:1]。
外部存储器划分为固定大小为64m字节的四个存储块,见下图。
存储区块与片选信号对应关系:
haddr是需要转换到外部存储器的内部ahb地址线。haddr[25:0]包含外部存储器地址。haddr是字节地址,而存储器访问不都是按字节访问,因此接到存储器的地址线依存储器的数据宽度有所不同,如下表:
对于16位宽度的外部存储器,fsmc将在内部使用haddr[25:1]产生外部存储器的地址fsmc_a[24:0]。不论外部存储器的宽度是多少(16位或8位),fsmc_a[0]始终应该连到外部存储器的地址线a[0]。
根据外部nor flash设计原理图:
2、fsmc非复用方式控制nor flash的程序设计
根据配置的接口电路配置gpio初始化程序与fsmc初始化程序。
void fsmc_nor_init(void){ fsmc_inittypedef fsmc_initstructure; fsmc_norsram_bank_inittypedef fsmc_bankinitstructure; fsmc_norsram_bankstructinit( fsmc_bankinitstructure); fsmc_norsramstructinit( fsmc_initstructure); rcc_ahb3periphclockcmd(rcc_ahb3enr_fsmc, enable); fsmc_bankinitstructure.fsmc_smreadpipe = 0; fsmc_bankinitstructure.fsmc_readymode = 0; fsmc_bankinitstructure.fsmc_writeperiod = 15; fsmc_bankinitstructure.fsmc_writeholdtime = 3; fsmc_bankinitstructure.fsmc_addrsettime = 3; fsmc_bankinitstructure.fsmc_readperiod = 15; fsmc_bankinitstructure.fsmc_datawidth = fsmc_datawidth_16bits; fsmc_norsram_bank_init( fsmc_bankinitstructure, fsmc_norsram_bank1); fsmc_initstructure.fsmc_mode = fsmc_mode_norflash; fsmc_initstructure.fsmc_timingregselect = fsmc_timingregselect_0; fsmc_initstructure.fsmc_memsize = fsmc_memsize_64mb; fsmc_initstructure.fsmc_memtype = fsmc_memtype_flash; fsmc_initstructure.fsmc_addrdatamode = fsmc_addrdatademux; fsmc_norsraminit( fsmc_initstructure);}  
gpio初始化
void fsmc_gpio_init(void){ gpio_inittypedef gpio_initstructure; gpio_structinit( gpio_initstructure); rcc_apb2periphclockcmd(rcc_apb2periph_syscfg, enable); rcc_ahbperiphclockcmd(rcc_ahbenr_gpiob | rcc_ahbenr_gpioc | rcc_ahbenr_gpioa | rcc_ahbenr_gpiod | rcc_ahbenr_gpioe | rcc_ahbenr_gpiof | rcc_ahbenr_gpiog, enable); gpio_pinafconfig(gpiod, gpio_pinsource4, gpio_af_12); //noe gpio_pinafconfig(gpiod, gpio_pinsource5, gpio_af_12); //nwe gpio_pinafconfig(gpiod, gpio_pinsource6, gpio_af_12); //nwait gpio_pinafconfig(gpiod, gpio_pinsource11, gpio_af_12); //a16 gpio_pinafconfig(gpiod, gpio_pinsource12, gpio_af_12); //a17 gpio_pinafconfig(gpiod, gpio_pinsource13, gpio_af_12); //a18 gpio_pinafconfig(gpiod, gpio_pinsource14, gpio_af_12); //d0 gpio_pinafconfig(gpiod, gpio_pinsource15, gpio_af_12); //d1 //省略部分代码 gpio_pinafconfig(gpiof, gpio_pinsource0, gpio_af_12); //a0 gpio_pinafconfig(gpiof, gpio_pinsource1, gpio_af_12); //a1 gpio_pinafconfig(gpiof, gpio_pinsource2, gpio_af_12); //a2 gpio_pinafconfig(gpiof, gpio_pinsource3, gpio_af_12); //a3 //省略部分代码 gpio_initstructure.gpio_pin = gpio_pin_all; gpio_initstructure.gpio_speed = gpio_speed_50mhz; gpio_initstructure.gpio_mode = gpio_mode_af_pp; gpio_init(gpiod, gpio_initstructure); gpio_initstructure.gpio_pin = gpio_pin_6; gpio_initstructure.gpio_speed = gpio_speed_50mhz; gpio_initstructure.gpio_mode = gpio_mode_floating; gpio_init(gpiod, gpio_initstructure); //省略部分代码}  
从选择的片选信号与fsmc外扩存储映像空间可以得出bank2地址为0x64000000,使用该地址作为读写外部nor flash的基地址。
#define nor_flash_start_addr ((u32)0x64000000)#define nor_flash_end_addr ((u32)0x67ffffff)//读一个半字u16 fsmc_nor_readhalfword(u32 readaddr){ nor_write(addr_shift(0x00555), 0x00aa); nor_write(addr_shift(0x002aa), 0x0055); nor_write((nor_flash_start_addr + readaddr), 0x00f0 );/* exit autoselect (write reset command) */ return (*(vu16*)((nor_flash_start_addr + readaddr)));}//连续读一块半字数据void fsmc_nor_readbuffer(u16* pbuffer, u32 readaddr, u32 numhalfwordtoread){ nor_write(addr_shift(0x0555), 0x00aa); nor_write(addr_shift(0x02aa), 0x0055); nor_write((nor_flash_start_addr + readaddr), 0x00f0);/* exit autoselect (write reset command) */ for(; numhalfwordtoread != 0x00; numhalfwordtoread--) { // read a halfword from the nor *pbuffer++ = *(vu16*)((nor_flash_start_addr + readaddr)); readaddr = readaddr + 2; }}  
读写外部nor flash与读写外部sram的操作,地址寻址方式是一样的,但nor flash的写数据有较大的不同。
以单个word编程为例,如下为写单个word的流程图与实现代码:
nor_status fsmc_nor_writehalfword(u32 writeaddr, u16 data){ nor_write(addr_shift(0x0555), 0x00aa); nor_write(addr_shift(0x02aa), 0x0055); nor_write(addr_shift(0x0555), 0x00a0); nor_write((nor_flash_start_addr + writeaddr), data); return (fsmc_nor_getstatus(program_timeout));}  
通过mindmotion的官网下载mm32f3270 lib_samples:
工程路径如下:
~mm32f327x_sampleslibsamplesfsmcfsmc_nor  
可以看到详细的样例与功能操作。
下章的题目为《使用mm32f3270 的fsmc驱动外部oled》讲解通过fsmc外扩并口oled的实现。
来源:灵动mm32mcu
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理


山东网络安全报告:安全威胁治理态势持续向好
浅谈宽禁带半导体行业概况
一种迷你数控雕刻机系统的设计方案
爱立信进一步加速整个5G部署过程
中科院在太赫兹超分辨光谱成像研究中取得进展
使用MM32F3270 FSMC驱动外部NOR Flash
电容测试仪的工作原理及测量方法
2020年安防行业遭受大考,如何抢占先机率先逆势
ZLG携手NXP举行i.MX RT 跨界处理器全国巡回研讨会
气动点焊机常见故障盘点
ANSYS HFSS和Mechanical仿真技术基础培训在拓普联科开课
在trait中使用 `async fn`
全集成可变带宽中频宽带低通滤波器的设计方案
千丁50余项“黑科技”助推重庆智慧小区落地建设
华为Mate10什么时候上市?华为Mate10最新消息:华为Mate10较华为Mate9大升级,颜值性能并存
Redmi 5G先锋首发骁龙765G,120Hz刷新率屏幕
应用材料公司首办供应商高峰会
iOS10.2越狱iOS10.1.1系统图文教程
4月民营控股企业占经营者总数的95.2%,成为增值电信业务领域主力军
华为 Mate 40 Pro 拆解:几乎每个部件都是模块化
s