STM32使用FSMC控制NAND flash 例程概要
- 格式:doc
- 大小:30.00 KB
- 文档页数:12
一、基本概念(详细内容见st网站stm32应用笔记AN2784)1. FSMC配置控制一个NOR闪存存储器,需要FSMC提供下述功能:●选择合适的存储块映射NOR闪存存储器:共有4个独立的存储块可以用于与NOR闪存、SRAM和PSRAM存储器接口,每个存储块都有一个专用的片选管脚。
●使用或禁止地址/数据总线的复用功能。
●选择所用的存储器类型:NOR闪存、SRAM或PSRAM。
●定义外部存储器的数据总线宽度:8或16位。
●使用或关闭同步NOR闪存存储器的突发访问模式。
●配置等待信号的使用:开启或关闭,极性设置,时序配置。
●使用或关闭扩展模式:扩展模式用于访问那些具有不同读写操作时序的存储器。
因为NOR闪存/SRAM控制器可以支持异步和同步存储器,用户只须根据存储器的参数配置使用到的参数。
FSMC提供了一些可编程的参数,可以正确地与外部存储器接口。
依存储器类型的不同,有些参数是不需要的。
当使用一个外部异步存储器时,用户必须按照存储器的数据手册给出的时序数据,计算和设置下列参数:●ADDSET:地址建立时间●ADDHOLD:地址保持时间●DATAST:数据建立时间●ACCMOD:访问模式这个参数允许FSMC可以灵活地访问多种异步的静态存储器。
共有4种扩展模式允许以不同的时序分别读写存储器。
在扩展模式下,FSMC_BTR用于配置读操作,FSMC_BWR用于配置写操作。
(译注:如果读时序与写时序相同,只须使用FSMC_BTR即可。
)如果使用了同步的存储器,用户必须计算和设置下述参数:●CLKDIV:时钟分频系数●DATLAT:数据延时如果存储器支持的话,NOR闪存的读操作可以是同步的,而写操作仍然是异步的。
当对一个同步的NOR闪存编程时,存储器会自动地在同步与异步之间切换;因此,必须正确地设置所有的参数。
2. 时序计算如上所述,对于异步NOR闪存存储器或类似的存储,有不同的访问协议。
首先要确定对特定存储器所需要使用的操作协议,选择的依据是不同的控制信号和存储器在读或写操作中的动作。
1、FSMC初初了解:FSMC 包括4个模块:(1)AHB接口(包括FSMC配置寄存器)(2)NOR闪存和PSRAM控制器(驱动LCD的时候LCD就好像一个PSRAM的里面只有2个16位的存储空间,一个是DATA RAM 一个是CMD RAM)(3)NAND闪存和PC卡控制器(4)外部设备接口我们驱动TFT很明显用的是第二个模块:NOR闪存。
2、FSMC的外设地址选择FSMC _Bank 用来选择外接存储器的地址,FSMC所控制的外存储器所映射的地址是0x6000 0000 ~ 0x9fff ffff其中属于NOR FLASH 的是0x6000 0000 ~ 0x6fff ffff ,然后这部分的地址空间又被分为四份,每份64MB, 编号是BANK1 ~ BANK 4 ,每个BANK 都有一个片选引脚。
而这四个分存储块的片选,则使用NE[4:1]来选择。
数据线/地址线/控制线是共享的。
NE1 ->Bank1 NE2->Bank2 NE3->Bank3 NE4->Bank4第一块:6000 0000h--63ff ffffh第二块:6400 0000h--67ff ffffh第三块:6800 0000h--6bff ffffh第四块:6c00 0000h--6fff ffffh3、FSMC 驱动LCDFSMC提供了所有的LCD控制器的信号:FSMC_D[16:0]:16bit的数据总线FSMC NEx:分配给NOR的256M,再分为4个区,每个区用来分配一个外设,这四个外设的片选分为是NE1-NE4,对应的引脚为:PD7—NE1,PG9—NE2,PG10-NE3,PG12—NE4FSMC NOE:输出使能,连接LCD的RD脚。
FSMC NWE:写使能,连接LCD的RW脚。
FSMC Ax:用在LCD显示RAM和寄存器之间进行选择的地址线,即该线用于选择LCD的RS脚,该线可用地址线的任意一根线,范围:FSMC_A[25:0]。
一、概述STM32F4是ST公司推出的一款高性能的32位微控制器,它具有强大的性能和丰富的外设资源,广泛应用于工业控制、消费电子、通信设备等领域。
其中,STM32F4的Flash存储器模块具有较大的存储容量和快速的读写速度,非常适合用来存储程序代码和数据。
本文将介绍如何使用STM32F4的Flash存储器模块进行读写操作的例程。
二、开发环境准备1. 基本硬件准备:准备一块STM32F4开发板,如STM32F407ZGT6开发板。
一台电脑,安装了Keil或者其他的开发环境。
2. 软件准备:在电脑上安装好STM32CubeMX和Keil或者其他的开发环境。
三、创建工程1. 打开STM32CubeMX,新建一个工程,选择对应的芯片型号,例如选择STM32F407ZGT6。
2. 配置时钟树,使得系统时钟为想要的频率,一般选择高频率以获得更快的Flash读写速度。
3. 配置Flash存储器,选择合适的扇区大小和擦写次数。
4. 生成代码,导出工程。
四、编写代码1. 在Keil或者其他的开发环境中打开刚刚生成的工程。
2. 找到Flash读写相关的API,一般在芯片提供的库函数中可以找到。
3. 根据需要编写Flash读写的代码,例如可以编写一个函数来实现向Flash写入数据的功能。
五、编译下载1. 编译代码,生成bin文件。
2. 将bin文件下载到STM32F4开发板中,可以使用ST-Link或者其他下载工具来完成。
六、调试运行1. 确保下载成功,重启开发板。
2. 进行调试,观察Flash读写是否正常。
七、注意事项1. 在进行Flash写入操作时,一定要小心谨慎,避免对程序的正常运行造成影响。
2. 在进行Flash擦除操作时,务必注意擦除的范围,避免擦除了不该擦除的数据。
3. 在进行Flash读写操作时,需要留意Flash的特性和限制,以免造成不必要的麻烦。
八、总结本文介绍了如何在STM32F4开发板上使用Flash存储器进行读写操作的例程,从开发环境准备到代码编写再到调试运行都有详细的步骤说明,并给出了注意事项和总结。
通过FSMC总线执行NORFLASH中程序的步骤
从外部NOR闪存存储器执行代码
大容量的STM32F10xxx内置了多达512K字节的闪存存储器,对于多数应用是足够了。
需要更多存储器容量的应用,可以使用外加的NOR闪存存储器。
本节说明了如何使用外部NOR闪存存储器运行用户程序。
这需要2个重要的步骤:
●
加载用户程序至外部NOR存储器:这个操作需要对开发工具进行特别的配置:在链接文件中,必须指定NOR闪存存储器的开始地址(或任何其它地址),这是需要放置用户程序的地址。
●
执行用户代码:一旦用户程序代码加载到NOR闪存存储器,在内部闪存存储器中需要有一段配置FSMC的程序,配置好FSMC后可以跳转至(NOR闪存存储器中的)用户程序代码执行。
当然MDK下也可以吧FSMC的配置信息写到DeBug脚本文件里。
STM32芯片内部的FLASH存储器,主要用于存储我们代码。
如果内部FLASH存储完我们的代码还有剩余的空间,那么这些剩余的空间我们就可以利用起来,存储一些需要掉电保存的数据。
本文以STM32103ZET为例。
STM32103ZET属于大容量产品,其闪存模块组织如下:其主存储器大小为512KB分为256页,每页大小都为2KB我们的程序般默认烧写到第0页的起始地址(0x08000000)处。
当BOOT引脚和BOOT引脚都接GND寸,就是从这个地址开始运行代码的。
这个地址在keil中可以看到:F 面对STM32内部FLASH 进行简单的读写测试:内部FLASH 读写测试 流程图如下:本流程图省略异常情况,只考虑成功的情况:f-Q Options for Target 'FLASH'一丄Utvice Til i«l I Output ] Li itinc | Ustr | C/C++ | AsmLinker Debue Vtiiitws\tSTHicroetedonici SR32F103ZEOpef^g syseiTi : |Sysem \^ewer Rle.{MHi): Bll-Cod* GeniFon —ARM Compter: | Use default cwnpiter veraion 5刁厂 Lse Cjoss-^ottile OrtimiiatorIv Lse Micro LIBotCancelCeCa-olts Help假如我们要下载的程序大小为4.05KB , 则第0、1、2页用于保存我们的程序,我们需要掉电保存的数据只能保存在第 3~第255页这一部分空间内。
我们最终要下载的程序大小可在工程对应的 .map 文件中看到。
.map 文件可以双击工程的Target 的名字快速打开,如:hrlphdrt Tool ; SVM 応 inJ 艸 hti 単 ,-■k ,A 弟=*七住」Mitw J 咖3口知,樹;卜( J... —. ■丹 Ft E4R vl«* PiQjtit “Ml Dtbug•ffli11 htBj£画 IF b.农-I r sj fLASj- In 討mi■. 1.7 viieiiii '.L二KP;L 叭1祠£ -L 二El 仍恤■走r二匚 top.gt £Jt±』CMS5三Q StriPaiph thr.ci二uc4114出, + e 4H ULiJry T'^CiJbd Mt*LMb|HELL ・md " D*fca ] ■W Egf icrtBli 畤TCT P Hmucfi>n 3 Hlih —b kp C b4i-i3 Jhdn_c.driR.Hbloral HD Size Ifodt + ・□ palFl*Total R>I 51■疋c £RM Eta - Zr TZatJ) Totdg flW S 上电 jt 屁It + 觀尿H * 也 G SU TL Use CustziEFife示例代码:本例的关键代码如下(以读写第255页为例):/******************************************************************************************************** -------------------------------------- STM32 Demo ------------------------工程说明:STM32内部FLASH实验作者:ZhengNian博客: zhengnianli.github.io公众号:嵌入式大杂烩********************************************************************************************************/#defi ne MAIN_CONFIG#i nclude "con fig.h"/* STM32F103ZET6有256页,每一页的大小都为2KB */#defi ne ADDR_FLASH _P AGE_255 ((ui nt32_t)0x0807F800) /* Page255 2KB *//* FLASH读写测试结果*/#defi ne #defi ne #defi ne/* Flash 读写测试buf */ #defi ne BufferSize 6ui nt16_t usFlashWriteBuf[BufferSize]= {0x0101,0x0202,0x0303,0x0404,0x0505,0x0606}; ui nt16_t usFlashReadBuf[BufferSize] = {0};/*供本文件调用的函数声明*/ static int FlashReadWriteTest(void);*********************************** ** 函数:main参数:void 返回:无 说明:主函数********************************************************************* ***********************************/ int main(v oid) {/*上电初始化*/ Sysl nit();/*内部Flash 读写测试*/if (TEST_SUCCESS == FlashReadWriteTest()) prin tf("Flash test success!' n"); } else {prin tf("Flash test failed!\n"); } while (1) {} }*************************************函数:FlashReadWriteTest ,内部Flash 读写测试函数 ** 参数:void**返回:TEST_ERROR :错误(擦除、写入错误) TEST_SUCCESS:成功TEST_FAILED :失败 **说明:无********************************************************************************************************/ static int FlashReadWriteTest(void) {TEST_ERROR -1 TEST_SUCCESS 0 TEST_FAILED 1 /*/*错误(擦除、写入错误)*/ /*成功*/失败*/uin t32_t ucStartAddr;/*解锁*/FLASH_U nIockO;/*擦除操作*/ ucStartAddr = ADDR_FLASH _P AGE_255;if (FLASH_CO MP LETE != FLAsH_Erase Page(ucStartAddr)) { prin tf("Erase Error!\n"); return TEST_ERROR;}elseucStartAddr = ADDR_FLASH _P AGE_255;printf("擦除成功,此时FLASH中值为:\n");for (i nt i = 0; i < BufferSize; i++){usFlashReadBuf[i] = *(ui nt32_t*)ucStartAddr;prin tf("ucFlashReadBuf[%d] = 0x%.4x\n", i, usFlashReadBuf[i]); ucStartAddr += 2;}}/*写入操作*/ucStartAddr = ADDR_FLASH _P AGE_255;printf("\n往FLASH中写入的数据为:\n");for (i nt i = 0; i < BufferSize; i++){if (FLASH_CO MP LETE != FLASH _P rogramHalfWord(ucStartAddr, usFlashWriteBuf[i])) {prin tf("Write Error!\n");return TEST_ERROR;} "prin tf("ucFlashWriteBuf[%d] = 0x%.4x\n", i, usFlashWriteBuf[i]); ucStartAddr += 2;} /*上锁*/ FLASH_Lock();/*读取操作*/ucStartAddr = ADDR_FLASH _P AGE_255;printf("\n 从FLASH 中读出的数据为:\n"); for (i nt i = 0; i < BufferSize; i++) {usFlashReadBuf[i] = *(__10 uin t16_t*)ucStartAddr;prin tf("ucFlashReadBuf[%d] = 0x%.4x\n", i, usFlashReadBuf[i]); ucStartAddr += 2; }/*读出的数据与写入的数据做比较*/ for (i nt i = 0; i < BufferSize; i++) {if (usFlashReadBuf[i] != usFlashWriteBuf[i]) {return TEST_FAILED; } }return TEST_SUCCESS; }/******************************************************************** *************************************** End Of File********************************************************************* ***********************************/(1)进行解锁操作STM32的闪存编程是由内嵌的闪存编程/擦除控制器(FPEC )管理,这个模块包含的寄存器如下:STM32复位后,FPEC 模块是被保护的, 不能写入FLASH_CR 寄存器;通 过写入特定的序列到FLASH_KEYF 寄存器可以打开FPEC 模块(即写入KEY1和KEY2 ,只有在写保护被解除后,我们才能操作相关寄存器。
本文原创于观海听涛,原作者版权所有,转载请注明出处。
近几天开发项目需要用到STM32驱动NAND FLASH,但由于开发板例程以及固件库是用于小页(512B),我要用到的FLASH为1G bit的大页(2K),多走了两天弯路。
以下笔记将说明如何将默认固件库修改为大页模式以驱动大容量NAND,并作驱动。
本文硬件:控制器:STM32F103ZET6,存储器:HY27UF081G2A首先说一下NOR与NAND存储器的区别,此类区别网上有很多,在此仅大致说明:1、Nor读取速度比NAND稍快2、Nand写入速度比Nor快很多3、NAND擦除速度(4ms)远快于Nor(5s)4、Nor 带有SRAM接口,有足够的地址引脚来寻址,可以很轻松的挂接到CPU地址和数据总线上,对CPU要求低5、NAND用八个(或十六个)引脚串行读取数据,数据总线地址总线复用,通常需要CPU支持驱动,且较为复杂6、Nor主要占据1-16M容量市场,并且可以片内执行,适合代码存储7、NAND占据8-128M及以上市场,通常用来作数据存储8、NAND便宜一些9、NAND寿命比Nor长10、NAND会产生坏块,需要做坏块处理和ECC更详细区别请继续百度,以上内容部分摘自神舟三号开发板手册下面是NAND的存储结构:由此图可看出NAND存储结构为立体式正如硬盘的盘片被分为磁道,每个磁道又分为若干扇区,一块nand flash也分为若干block,每个block分为如干page。
一般而言,block、page之间的关系随着芯片的不同而不同。
需要注意的是,对于flash的读写都是以一个page开始的,但是在读写之前必须进行flash 的擦写,而擦写则是以一个block为单位的。
我们这次使用的HY27UF081G2A其PDF介绍:Memory Cell Array= (2K+64) Bytes x 64 Pages x 1,024 Blocks由此可见,该NAND每页2K,共64页,1024块。
flasher stm32 用法一、STM32 简介STM32是由意法半导体(STMicroelectronics)推出的一款32位嵌入式微控制器。
它基于ARM Cortex-M内核,提供了丰富的外设接口和强大的处理性能,被广泛应用于各种嵌入式系统和应用中。
二、Flasher STM32 概述Flasher STM32是一款用于烧录STM32微控制器的编程器。
它能够将程序代码和数据存储到STM32的闪存中,并支持对闪存中的内容进行擦除和重新编程。
使用Flasher STM32可以方便地更新和调试STM32系统,提高开发效率和可靠性。
三、Flasher STM32 的使用步骤下面将详细介绍Flasher STM32的使用步骤,以帮助初学者迅速上手:1. 准备工作在使用Flasher STM32之前,需要准备好以下设备和软件:- STM32微控制器开发板- USB连接线- Flasher STM32编程器- STM32CubeIDE或其他相关开发环境(用于生成程序代码)2. 连接设备将STM32开发板通过USB连接线与Flasher STM32编程器相连。
确保连接线接触良好,没有松动。
3. 安装驱动程序根据Flasher STM32编程器的型号,安装对应的驱动程序。
一般情况下,驱动程序会随编程器附带或在官方网站上提供下载。
4. 打开开发环境打开STM32CubeIDE或其他相关的开发环境,创建一个新项目或打开现有的项目。
5. 编写代码根据自己的需求,编写STM32的程序代码。
可以使用C/C++语言,借助开发环境提供的API和库函数进行操作。
6. 配置编程器在开发环境中配置Flasher STM32编程器的相关参数。
一般来说,需要选择正确的编程器型号和连接接口(如USB),并指定目标设备的型号。
7. 编译和烧录使用开发环境提供的编译器,将程序代码编译成二进制文件。
然后,使用FlasherSTM32编程器将二进制文件烧录到STM32的闪存中。
关于STM32的FLASH操作STM32是一款由意法半导体(STMicroelectronics)推出的32位精简型单片机系列。
它采用了ARM Cortex-M内核,并在Flash和内存等方面进行了优化,提供了强大的性能和丰富的外设功能。
FLASH是STM32芯片上的一种非易失性存储器,可以用于存储应用程序代码、数据、配置信息等。
在STM32中进行FLASH操作可以通过编程和标准库函数两种方式实现。
下面将依次介绍这两种方法的使用。
一、编程方式编程方式是直接对FLASH进行底层的读写操作,需要对相关寄存器进行配置和控制。
1.写入数据在STM32的FLASH中写入数据的操作需要经历以下步骤:1) 解锁FLASH:通过FLASH_Unlock(函数解锁FLASH,使其可写入。
2) 擦除FLASH:通过FLASH_ErasePage(函数擦除要写入的FLASH扇区。
3) 写入数据:通过FLASH_ProgramByte(、FLASH_ProgramHalfWord(、FLASH_ProgramWord(等函数对FLASH进行数据写入。
4) 上锁FLASH:通过FLASH_Lock(函数上锁FLASH,防止误操作。
以下是一个简单的例子,演示如何通过编程方式对STM32的FLASH进行数据写入:```c#include "stm32f10x_flash.h"void ConfigureFlash(void)FLASH_Unlock(; // 解锁FlashFLASH_ClearFlag(FLASH_FLAG_EOP , FLASH_FLAG_PGERR ,FLASH_FLAG_WRPRTERR); // 清除状态标志FLASH_ErasePage(FLASH_START_ADDR); // 擦除扇区FLASH_Lock(; // 上锁Flash```2.读取数据读取STM32的FLASH数据需要通过指针的方式直接读取存储器的地址,如下所示:```c#define READ_FLASH(addr) (*(volatile uint32_t*)(addr))void ReadFlash(void)uint32_t data = READ_FLASH(FLASH_START_ADDR);//在这里对读取的数据进行处理```二、标准库函数方式STM32提供了一套标准库函数,方便开发者进行FLASH操作。
关于STM32的FLASH操作STM32是STMicroelectronics公司开发的一系列32位ARM Cortex-M微控制器。
在STM32微控制器中,FLASH (快闪存储器)是用于存储应用程序和数据的重要组件。
在本文中,我们将详细介绍STM32的FLASH操作。
1.FLASH简介:FLASH是一种可擦除可编程的非易失性存储器,常用于存储应用程序代码和数据。
STM32微控制器的FLASH存储器由多个扇区组成。
每个扇区的大小可以是1KB、2KB、4KB或16KB,具体取决于所使用的芯片型号。
FLASH的主要特点包括可擦除、可编程和快速存取。
2.FLASH的特点:2.1 可擦除:FLASH存储器中的数据可以通过擦除操作来清除。
擦除操作可以是扇区擦除(Sector Erase)或全片擦除(Mass Erase)。
扇区擦除只清除指定的扇区,而全片擦除则清除整个FLASH存储器。
2.2 可编程:FLASH存储器中的数据可以通过编程操作来写入。
编程操作可以是半字编程(Half-Word Program)或字编程(Word Program)。
半字编程一次可以写入16位的数据,而字编程一次可以写入32位的数据。
2.3快速存取:FLASH存储器具有快速存取速度,使得应用程序可以在很短的时间内从FLASH中读取数据。
3.FLASH操作注意事项:在进行STM32的FLASH操作时,需要注意以下几个方面:3.1对于每个扇区的擦除操作,只能在原来数据全为‘1’的情况下进行。
因此,在进行擦除操作之前,应该先将该扇区的数据写为全‘1’。
3.2进行编程操作时,只能将数据从‘1’写为‘0’,而不能将数据从‘0’写为‘1’。
因此,在进行编程操作之前,应该先将该数据所在的字节或半字擦除为全‘1’。
3.3FLASH存储器的数据写入操作需要采取双字节对齐的方式。
如果数据不是双字节对齐,则必须先将数据拷贝到对齐的缓冲区中,再进行编程操作。
STM32 FSMC操作SRAM的步骤简析本次操作的S(RAM)的型号是IS62WV51216,是高速,8M位静态SRAM。
它采用ISSI(In(te)rgrated Silicon Solu(ti)on, Inc)公司的高性能CMOS技术,按照512K个字(16)位进行组织存储单元。
其具有高性能、低功耗特点。
为方便用户扩展SRAM的存储空间,为用户有提供了两个片选引脚;此外,含有两个字节控制(信号)UB 和LB,可方便用户按字节访问SRAM或按字访问SRAM。
IS62WV51216具有45ns/55ns访问速度,因为是全静态操作,因此无需外部(时钟)和刷新要求。
IS62WV51216功能框图IS62WV51216有地址译码器、数据IO、控制逻辑和存储阵列四部分构成。
地址译码器将19根地址线上的输入进行译码,将译码值与内部存储阵列的单元地址进行建立映射。
数据IO是SRAM是主控制器数据交互的通道,访问数据时,即可字节进行访问也可按字访问,按字节访问功能增强了其与8位机的兼容性。
控制逻辑部分包括读和写的选(通信)号,以及字节访问和片选引脚。
在(硬件)连接上,SRAM与(STM32)F4通过FSMC(接口)进行互连。
SRAM的片选信号CE与FSMC的NE3连接在一起。
由此可知,SRAM被映射到Bank1的第3个存储区当中,显然,其首地址为0x68000000。
由于SRAM的数据口有16根数据线,因此为加快访问速度,提高数据吞吐量,这里仍将数据宽度设置为16位宽。
此时,FSMC接口的一个地址,映射到AHB地址时对应2个地址空间,即u16数据类型所占宽度。
但是,当用户按字节AHB地址空间时,如读取的是两个相邻字节地址空间(地址按2个字节对齐),则显然此时映射到FSMC接口时,地址是一个值,此时用户操作AHB 地址空间中低地址的字节,即相当于操作了FSMC对应地址的低字节,而当用户操作AHB地址窠中高地址字节时,则相当于操作了FSMC同一地址空间中的高字节,即FSMC地址空间可以不变,但通过SRAM 的UB和LB,分别访问了同一地址的不同字节。
stm32 flash读写例程摘要:1.STM32 Flash存储器概述2.STM32 Flash读写操作步骤3.STM32 Flash读写实例4.注意事项正文:一、STM32 Flash存储器概述STM32 Flash存储器分为两个区域:系统区域和用户区域。
系统区域存储固件和启动代码,用户区域用于存储用户数据。
STM32提供了丰富的库函数和HAL(硬件层)驱动程序,方便开发者实现对Flash存储器的读写操作。
二、STM32 Flash读写操作步骤1.初始化:对Flash模块进行初始化,包括时钟、GPIO等。
2.擦除:在进行写入操作前,需要对目标区域进行擦除。
擦除方式以页为单位。
3.写入:将数据写入Flash存储器。
注意写入地址为奇数时可能会出错。
4.读取:从Flash存储器中读取数据。
三、STM32 Flash读写实例以下是一个简单的STM32 Flash读写实例:1.定义Flash 写入数据函数:```cvoid FlashWrite(uint32_t add, uint16_t dat) {// 打开Flash控制时钟RCCHSICMD(ENABLE);// 设置Flash写入地址FLASH_WriteAddress = add;// 写入16位数据FLASH_DataWrite(dat);// 等待Flash写入完成while (FLASH_BusyStatus != 0);// 关闭Flash控制时钟RCCHSICMD(DISABLE);}```2.定义Flash 读取数据函数:```cuint16_t FlashRead(uint32_t add){// 打开Flash控制时钟RCCHSICMD(ENABLE);// 设置Flash读取地址FLASH_ReadAddress = add;// 读取16位数据uint16_t data = FLASH_DataRead();// 关闭Flash控制时钟RCCHSICMD(DISABLE);return data;}```四、注意事项1.Flash 读写操作时,需注意地址和数据长度。
本文原创于观海听涛,原作者版权所有,转载请注明出处。
近几天开发项目需要用到STM32驱动NAND FLASH,但由于开发板例程以及固件库是用于小页(512B,我要用到的FLASH为1G bit的大页(2K,多走了两天弯路。
以下笔记将说明如何将默认固件库修改为大页模式以驱动大容量NAND,并作驱动。
本文硬件:控制器:STM32F103ZET6,存储器:HY27UF081G2A首先说一下NOR与NAND存储器的区别,此类区别网上有很多,在此仅大致说明:1、Nor读取速度比NAND稍快2、Nand写入速度比Nor快很多3、NAND擦除速度(4ms远快于Nor(5s4、Nor 带有SRAM接口,有足够的地址引脚来寻址,可以很轻松的挂接到CPU 地址和数据总线上,对CPU要求低5、NAND用八个(或十六个引脚串行读取数据,数据总线地址总线复用,通常需要CPU支持驱动,且较为复杂6、Nor主要占据1-16M容量市场,并且可以片内执行,适合代码存储7、NAND占据8-128M及以上市场,通常用来作数据存储8、NAND便宜一些9、NAND寿命比Nor长10、NAND会产生坏块,需要做坏块处理和ECC更详细区别请继续百度,以上内容部分摘自神舟三号开发板手册下面是NAND的存储结构:由此图可看出NAND存储结构为立体式正如硬盘的盘片被分为磁道,每个磁道又分为若干扇区,一块nand flash也分为若干block,每个block分为如干page。
一般而言,block、page之间的关系随着芯片的不同而不同。
需要注意的是,对于flash的读写都是以一个page开始的,但是在读写之前必须进行flash 的擦写,而擦写则是以一个block为单位的。
我们这次使用的HY27UF081G2A其PDF介绍:Memory Cell Array= (2K+64 Bytes x 64 Pages x 1,024 Blocks由此可见,该NAND每页2K,共64页,1024块。
其中:每页中的2K为主容量Data Field, 64bit为额外容量Spare Field。
Spare Field用于存贮检验码和其他信息用的,并不能存放实际的数据。
由此可算出系统总容量为2K*64*1024=134217728个byte,即1Gbit。
NAND闪存颗粒硬件接口:由此图可见,此颗粒为八位总线,地址数据复用,芯片为SOP48封装。
软件驱动:(此部分写的是伪码,仅用于解释含义,可用代码参见附件主程序:1. #define BUFFER_SIZE 0x2000 //此部分定义缓冲区大小,即一次写入的数据2. #define NAND_HY_MakerID 0xAD //NAND厂商号3. #define NAND_HY_DeviceID 0xF1 //NAND器件号4. /*配置与SRAM连接的FSMC BANK2 NAND*/5. NAND_Init(;6. /*读取Nand Flash ID并打印*/7. NAND_ReadID(&NAND_ID;复制代码Tips:NAND器件的ID包含四部分:1st Manufacturer Code2nd Device Identifier3rd Internal chip number, cell Type, Number of Simultaneously Programmedpages.4th Page size, spare size, Block size, Organization1. if((NAND_ID.Maker_ID == NAND_HY_MakerID && (NAND_ID.Device_ID == NAND_HY_DeviceID //判断器件符合2. {3. /*设置NAND FLASH的写地址*/4. WriteReadAddr.Zone = 0x00;5. WriteReadAddr.Block = 0x00;6. WriteReadAddr.Page = 0x05;7. /*擦除待写入数据的块*/8. status = NAND_EraseBlock(WriteReadAddr; //写入前必须擦出9. /*将写Nand Flash的数据BUFFER填充为从0x25开始的连续递增的一串数据*/10. Fill_Buffer(TxBuffer, BUFFER_SIZE , 0x25; //填充数据以测试11. /*将数据写入到Nand Flash中。
WriteReadAddr:读写的起始地址*/12. status = NAND_WriteSmallPage(TxBuffer, WriteReadAddr, PageNumber; //主要写入函数,此部分默认为小页需要修改13. /*从Nand Flash中读回刚写入的数据。
riteReadAddr:读写的起始地址*/14. status = NAND_ReadSmallPage (RxBuffer, WriteReadAddr, PageNumber; //读取主要函数,也需要修改15.16. /*判断读回的数据与写入的数据是否一致*/17. for(j = 0; j < BUFFER_SIZE; j++18. {19. if(TxBuffer[j] != RxBuffer[j]20. {21. WriteReadStatus++;22. }23. }24.25. if (WriteReadStatus == 026. {27. printf("\n\r Nand Flash读写访问成功";28. GPIO_ResetBits(GPIO_LED, DS2_PIN;29. }30. else31. {32. printf("\n\r Nand Flash读写访问失败";33. printf("0x%x",WriteReadStatus;34.35. GPIO_ResetBits(GPIO_LED, DS3_PIN;36.37. }38. }39. else40. {41. printf("\n\r 没有检测到Nand Flash的ID";42. GPIO_ResetBits(GPIO_LED, DS4_PIN;43. }复制代码fsmc_nand.c文件:1. void NAND_Init(void2. {3. GPIO_InitTypeDef GPIO_InitStructure;4. FSMC_NAND_PCCARDTimingInitTypeDef p;5. FSMC_NANDInitTypeDef FSMC_NANDInitStructure;6.7. /*FSMC总线使用的GPIO组时钟使能*/8. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD |RCC_APB2Periph_GPIOE |9. RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG, ENABLE;10.11. /*FSMC CLE, ALE, D0->D3, NOE, NWE and NCE2初始化,推挽复用输出*/12. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_14 | GPIO_Pin_15 |13. GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 |14. GPIO_Pin_7;15. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;16. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;17. GPIO_Init(GPIOD, &GPIO_InitStructure;18. /*FSMC数据线FSMC_D[4:7]初始化,推挽复用输出*/19. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;20. GPIO_Init(GPIOE, &GPIO_InitStructure;21. /*FSMC NWAIT初始化,输入上拉*/22. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;23. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;24. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;25. GPIO_Init(GPIOD, &GPIO_InitStructure;26. /*FSMC INT2初始化,输入上拉*/27. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;28. GPIO_Init(GPIOG, &GPIO_InitStructure;29. /*--------------FSMC 总线存储器参数配置------------------------------*/30. p.FSMC_SetupTime = 0x1; //建立时间31. p.FSMC_WaitSetupTime = 0x3; //等待时间32. p.FSMC_HoldSetupTime = 0x2; //保持时间33. p.FSMC_HiZSetupTime = 0x1; //高阻建立时间34. FSMC_NANDInitStructure.FSMC_Bank = FSMC_Bank2_NAND; //使用FSMC BANK235. FSMC_NANDInitStructure.FSMC_Waitfeature = FSMC_Waitfeature_Enable; //使能FSMC的等待功能36. FSMC_NANDInitStructure.FSMC_MemoryDataWidth =FSMC_MemoryDataWidth_8b; //NAND Flash的数据宽度为8位37. FSMC_NANDInitStructure.FSMC_ECC = FSMC_ECC_Enable; //使能ECC特性38. FSMC_NANDInitStructure.FSMC_ECCPageSize =FSMC_ECCPageSize_2048Bytes; //ECC页大小204839. FSMC_NANDInitStructure.FSMC_TCLRSetupTime = 0x00;40. FSMC_NANDInitStructure.FSMC_TARSetupTime = 0x00;41. FSMC_NANDInitStructure.FSMC_CommonSpaceTimingStruct = &p;42. FSMC_NANDInitStructure.FSMC_AttributeSpaceTimingStruct = &p;43. FSMC_NANDInit(&FSMC_NANDInitStructure;44. /*!使能FSMC BANK2 */45. FSMC_NANDCmd(FSMC_Bank2_NAND, ENABLE;46. }复制代码1. void NAND_ReadID(NAND_IDTypeDef* NAND_ID2. {3. uint32_t data = 0;4. /*!< Send Command to the command area */5. *(__IO uint8_t *(Bank_NAND_ADDR | CMD_AREA = 0x90;6. *(__IO uint8_t *(Bank_NAND_ADDR | ADDR_AREA = 0x00;7. /*!< Sequence to read ID from NAND flash */8. data = *(__IO uint32_t *(Bank_NAND_ADDR | DATA_AREA;9. NAND_ID->Maker_ID = ADDR_1st_CYCLE (data;//四个周期读取四个ID10. NAND_ID->Device_ID = ADDR_2nd_CYCLE (data;11. NAND_ID->Third_ID = ADDR_3rd_CYCLE (data;12. NAND_ID->Fourth_ID = ADDR_4th_CYCLE (data;13. }复制代码1. uint32_t NAND_WriteSmallPage(uint8_t *pBuffer, NAND_ADDRESS Address, uint32_t NumPageToWrite2. {//传入参数:写入数据,写入初始地址,要写几页3. uint32_t index = 0x00, numpagewritten = 0x00, addressstatus =NAND_VALID_ADDRESS;4. uint32_t status = NAND_READY, size = 0x00;5. while((NumPageToWrite != 0x00 && (addressstatus ==NAND_VALID_ADDRESS && (status == NAND_READY6. {7. /*!< Page write command and address */8. *(__IO uint8_t *(Bank_NAND_ADDR | CMD_AREA =NAND_CMD_AREA_A;9. *(__IO uint8_t *(Bank_NAND_ADDR | CMD_AREA = NAND_CMD_WRITE0;10. *(__IO uint8_t *(Bank_NAND_ADDR | ADDR_AREA = 0x00;11. *(__IO uint8_t *(Bank_NAND_ADDR | ADDR_AREA = 0x00;//添加此句12. *(__IO uint8_t *(Bank_NAND_ADDR | ADDR_AREA =ADDR_1st_CYCLE(ROW_ADDRESS;13. *(__IO uint8_t *(Bank_NAND_ADDR | ADDR_AREA =ADDR_2nd_CYCLE(ROW_ADDRESS;14. // *(__IO uint8_t *(Bank_NAND_ADDR | ADDR_AREA =ADDR_3rd_CYCLE(ROW_ADDRESS;//原版有此句15. /*!< Calculate the size */16. size = NAND_PAGE_SIZE + (NAND_PAGE_SIZE * numpagewritten;//统计写入数目17. /*!< Write data */18. for(; index < size; index++19. {20. *(__IO uint8_t *(Bank_NAND_ADDR | DATA_AREA = pBuffer[index];21. }22.23. *(__IO uint8_t *(Bank_NAND_ADDR | CMD_AREA =NAND_CMD_WRITE_TRUE1;24. /*!< Check status for successful operation */25. status = NAND_GetStatus(;26.27. if(status == NAND_READY28. {29. numpagewritten++;30. NumPageToWrite--;31. /*!< Calculate Next small page Address */32. addressstatus = NAND_AddressIncrement(&Address;33. }34. }35.36. return (status | addressstatus;37. }复制代码读取函数同理修改1. uint32_t NAND_EraseBlock(NAND_ADDRESS Address2. {3. *(__IO uint8_t *(Bank_NAND_ADDR | CMD_AREA = NAND_CMD_ERASE0;4. *(__IO uint8_t *(Bank_NAND_ADDR | ADDR_AREA =ADDR_1st_CYCLE(ROW_ADDRESS;5. *(__IO uint8_t *(Bank_NAND_ADDR | ADDR_AREA =ADDR_2nd_CYCLE(ROW_ADDRESS;6. // *(__IO uint8_t *(Bank_NAND_ADDR | ADDR_AREA =ADDR_3rd_CYCLE(ROW_ADDRESS;//两次即可7. *(__IO uint8_t *(Bank_NAND_ADDR | CMD_AREA = NAND_CMD_ERASE1;8. return (NAND_GetStatus(;9. }复制代码 fsmc_nand.h 文件: 1. 2. 3. 4. 5. #define NAND_PAGE_SIZE #define NAND_BLOCK_SIZE #define NAND_ZONE_SIZE #defineNAND_SPARE_AREA_SIZE #define NAND_MAX_ZONE ((uint16_t0x0800 /* 512 bytes per page w/o Spare Area */// 每页 2K ((uint16_t0x0040 /* 32x512 bytes pages per block *///64 个页 ((uint16_t0x0400 /* 1024 Block per zone *///1024 个快((uint16_t0x0040 /* last 16 bytes as spare area */ ((uint16_t0x0001 /* 4 zones of 1024 block */ 复制代码修改完即可实现 512B 至 2K 每页的变更。