百为STM32开发板教程之十二——NAND FLASH
发布时间:2020-12-15 17:53:36 所属栏目:百科 来源:网络整理
导读:参考资料: 百为stm32开发板光盘V3百为stm32开发板光盘芯片数据手册K9F1208.pdf 百为stm32开发板光盘st官方参考资料Application notesAN2784 Using the high-density STM32F10xxx FSMC peripheral to drive external memories.pdf 实验目的:实现擦除NAN
参考资料: 百为stm32开发板光盘V3百为stm32开发板光盘芯片数据手册K9F1208.pdf 百为stm32开发板光盘st官方参考资料Application notesAN2784 Using the high-density STM32F10xxx FSMC peripheral to drive external memories.pdf 实验目的:实现擦除NAND FLASH的第一个块,并读写NAND FLASH的开头两页 主要内容: 一、了解STM32 FSMC NAND控制器 二、了解K9F1208 NAND FLASH的原理与操作 三、编程实现擦除K9F1208 NAND FLASH的第一个块,并读写K9F1208 NAND FLASH的开头两页 一、STM32 FSMC NAND控制器 1、1、STM32 FSMC功能框图: FSMC主要包括有:AHB接口(包含FSMC配置寄存器) , NOR闪存和PSRAM控制器,NAND闪存和PC卡控制器,外部设备接口 2、STM32 FSMC外部设备地址映射: 从FSMC的角度看,可以把外部存储器划分为固定大小为256M字节的四个存储块,见下图 ● 存储块1用于访问最多4个NOR闪存或PSRAM存储设备。这个存储区又被划分为4个NOR/PSRAM区,并有4个专用的片选。? ● 存储块2和3用于访问NAND闪存设备,每个存储块连接一个NAND闪存。? ● 存储块4用于访问PC卡设备? 每一个存储块上的存储器类型是由用户在配置寄存器中定义的。 其中块2和块3属于NAND存储块,每个存储块又可以划分为通用和属性空间 通用和属性空间又可以在低256K字节部分划分为3个区 ● 数据区(通用/属性空间的前64K字节区域)? ● 命令区(通用/属性空间的第2个64K字节区域)? ● 地址区(通用/属性空间的第2个128K字节区域) 应用软件使用这3个区访问NAND闪存存储器:? ● 发送命令到NAND闪存存储器:软件只需对命令区的任意一个地址写入命令即可。? ● 指定操作NAND闪存存储器的地址:软件只需对地址区的任意一个地址写入命令即可。因为一个NAND地址可以有4或5个字节(依实际的存储器容量而定),需要连续地执行对地址区的写才能输出完整的操作地址。? ● 读写数据:软件只需对数据区的任意一个地址写入或读出数据即可。 因为NAND闪存存储器自动地累加其内部的操作地址,读写数据时没有必要变换数据区的地址,即不必对连续的地址区操作。 3、STM32的NAND控制信号 (1)STM32 FSMC NAND控制信号描述: (2)STM32 FSMC信号连接K9F1208 NAND FLASH: (3)百为STM3210E-EVAL开发板上STM32和K9F1208的连接电路图(这里电路图上画的是NAND512,实际焊接的硬件是K9F1208): 二、K9F1208 NAND FLASH的原理与操作 1、K9F1208 的硬件结构组织 K9F1208是容量为512M bit,即64M byte的存储器,它是由4096个块(block)组成,其中每个块又是由32个页(page)组成,每个页由512byte+16byte组成。 K9F1208的读写都是以页为单位,而擦除则是以块为单位。 程序中相关定义: /* FSMC NAND memory parameters */ #define NAND_PAGE_SIZE? ?? ?? ?? ? ((u16)0x0200) /* 512 bytes per page w/o Spare Area */ #define NAND_BLOCK_SIZE? ?? ?? ?? ?((u16)0x0020) /* 32x512 bytes pages per block */ #define NAND_ZONE_SIZE? ?? ?? ?? ? ((u16)0x0400) /* 1024 Block per zone */ #define NAND_SPARE_AREA_SIZE? ?? ? ((u16)0x0010) /* last 16 bytes as spare area */ #define NAND_MAX_ZONE? ?? ?? ?? ???((u16)0x0004) /* 4 zones of 1024 block */ 2、K9F1208引脚定义 3、K9F1208的操作命令集 (1)读ID命令: 先输出命令90H,再输出地址00H,然后读回4个字节的数据即是K9F1208的ID,ECH,76H,5AH,3FH 代码如下: void FSMC_NAND_ReadID(NAND_IDTypeDef* NAND_ID) { ??u32 data = 0; ??/* 发送命令到命令区0x70010000 */?? ??*(vu8 *)(Bank_NAND_ADDR | CMD_AREA) = 0x90; ??*(vu8 *)(Bank_NAND_ADDR | ADDR_AREA) = 0x00; ? ?/* 从K9F1208 NAND FLASH读回ID序列 */? ? ?data = *(vu32 *)(Bank_NAND_ADDR | DATA_AREA);??//从数据区0x70000000读回数据 ? ?NAND_ID->Maker_ID? ?= ADDR_1st_CYCLE (data); ? ?NAND_ID->Device_ID??= ADDR_2nd_CYCLE (data); ? ?NAND_ID->Third_ID? ?= ADDR_3rd_CYCLE (data); ? ?NAND_ID->Fourth_ID??= ADDR_4th_CYCLE (data);?? } (2)块擦除命令 块擦除是先输出60H,再输出块地址,然后输出D0H,用70H读回状态,等待操作完成即可 u32 FSMC_NAND_EraseBlock(NAND_ADDRESS Address) ??*(vu8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_ERASE0;??//发送命令60H到命令区0x70010000 ??*(vu8 *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_1st_CYCLE(ROW_ADDRESS);??//发送地址A9~A16到地址区0x70020000 ??*(vu8 *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_2nd_CYCLE(ROW_ADDRESS); //发送地址A17~A24到地址区0x70020000 ??*(vu8 *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_3rd_CYCLE(ROW_ADDRESS);??//发送地址A25到地址区0x70020000 ? ? ??*(vu8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_ERASE1;??//发送命令D0H到命令区0x70010000? ??return (FSMC_NAND_GetStatus());??//读回操作结果 (4)页写入命令 因为每个页(page)可分为A,B,C三个区 具体时序: 我们这里采用的第一种方式,可以写入0~528byte的数据。K9F1208属于小页的NAND(512byte+16byte),区别于大页的NAND(2048byte+64byte) u32 FSMC_NAND_WriteSmallPage(u8 *pBuffer,NAND_ADDRESS Address,u32 NumPageToWrite) ??u32 index = 0x00,numpagewritten = 0x00,addressstatus = NAND_VALID_ADDRESS; ??u32 status = NAND_READY,size = 0x00; ??while((NumPageToWrite != 0x00) && (addressstatus == NAND_VALID_ADDRESS) && (status == NAND_READY)) ??{ ? ? /* 页写命令和地址 */ ? ? *(vu8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_AREA_A;??//发送命令00H到命令区0x70010000,从A区开始写入 ? ? *(vu8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_WRITE0;??//发送命令80H到命令区0x70010000 ? ? *(vu8 *)(Bank_NAND_ADDR | ADDR_AREA) = 0x00;??//发送地址A0~A7到地址区0x70020000,从地址0开始写入?? ? ? *(vu8 *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_1st_CYCLE(ROW_ADDRESS); //发送地址A9~A16到地址区0x70020000?? ? ? *(vu8 *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_2nd_CYCLE(ROW_ADDRESS);??//发送地址A17~A24到地址区0x70020000?? ? ? *(vu8 *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_3rd_CYCLE(ROW_ADDRESS);??//发送地址A25到地址区0x70020000 ? ? /* 计算写入数据的大小 */ ? ? size = NAND_PAGE_SIZE + (NAND_PAGE_SIZE * numpagewritten); ? ? /* 写入数据 */ ? ? for(; index < size; index++) ? ? { ? ?? ?*(vu8 *)(Bank_NAND_ADDR | DATA_AREA) = pBuffer[index];??//发送数据到数据区0x70000000 ? ? } ? ?? ? ? /* 检查状态看是否操作成功 */ ? ? status = FSMC_NAND_GetStatus(); ? ? if(status == NAND_READY)??//如果操作完成 ? ?? ?numpagewritten++;??//已写入页数加1 ? ?? ?NumPageToWrite--;??//待写入页数减1 ? ?? ?/* 计算要写入的下一个小页的地址 */ ? ?? ?addressstatus = FSMC_NAND_AddressIncrement(&Address);? ?? ? ? }? ?? ??} ?? ??return (status | addressstatus); (5)read 1页读命令 页读命令是先输出00H,再输出要读入的页地址,然后就可以读回最多528byte的数据了。 u32 FSMC_NAND_ReadSmallPage(u8 *pBuffer,u32 NumPageToRead) ??while((NumPageToRead != 0x0) && (addressstatus == NAND_VALID_ADDRESS)) ??{? ?? ? ? /* 页读命令和页地址*/ ? ? *(vu8 *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_AREA_A;? ?//发送命令00H到命令区0x70010000 ? ? *(vu8 *)(Bank_NAND_ADDR | ADDR_AREA) = 0x00;??////发送地址A0~A7(00H)到地址区0x70020000 ? ? *(vu8 *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_1st_CYCLE(ROW_ADDRESS); //发送地址A9~A16到地址区0x70020000? ? ? *(vu8 *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_2nd_CYCLE(ROW_ADDRESS);??//发送地址A17~A24到地址区0x70020000? ? ? *(vu8 *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_3rd_CYCLE(ROW_ADDRESS);? ?//发送地址A25到地址区0x70020000 ? ??? ? ? /* 计算要读的数据大小 */ ? ? size = NAND_PAGE_SIZE + (NAND_PAGE_SIZE * numpageread); ? ? /* 读数据到pBuffer */? ?? ? ?? ?pBuffer[index]= *(vu8 *)(Bank_NAND_ADDR | DATA_AREA);??//从数据区0x70000000读回数据 ? ? numpageread++;??//已读的页数加1 ? ? NumPageToRead--;??//待读的页数减1 ? ? /* 计算下一个要读的页地址 */? ?? ?? ?? ?? ? ? ? addressstatus = FSMC_NAND_AddressIncrement(&Address); ??/* 检查状态看是否操作成功 */ ??status = FSMC_NAND_GetStatus(); /* main.c */ ??/* FSMC NAND初始化 */ ??FSMC_NAND_Init(); ??/* 读NAND ID操作 */ ??FSMC_NAND_ReadID(&NAND_ID); ??/* 检查ID是否正确 */ ??if((NAND_ID.Maker_ID == NAND_K9F1208_MakerID) && (NAND_ID.Device_ID == NAND_K9F1208_DeviceID)) ? ? /* 初始化要写入NAND的页地址 */? ? ? WriteReadAddr.Zone = 0x00; ? ? WriteReadAddr.Block = 0x00; ? ? WriteReadAddr.Page = 0x00;? ? ? /* 擦除NAND FLASH的第一个块(第1和第2页所在的块) */ ? ? status = FSMC_NAND_EraseBlock(WriteReadAddr); ? ? /* 写数据到NAND FLASH的第1和第2页 */ ? ? /* 填充要发送的数据到buffer */ ? ? Fill_Buffer(TxBuffer,BUFFER_SIZE,0x66); ? ? status = FSMC_NAND_WriteSmallPage(TxBuffer,WriteReadAddr,PageNumber);??//PageNumber=2,表示要写入第1和第2页 ? ? /* 从NAND FLASH读回数据 */ ? ? status = FSMC_NAND_ReadSmallPage (RxBuffer,PageNumber); ? ? /* 比较写入的数据和读回的数据是否相等 */ ? ? for(j = 0; j < BUFFER_SIZE; j++) ? ?? ?if(TxBuffer[j] != RxBuffer[j]) ? ?? ?{? ??? ? ?? ???WriteReadStatus++; ? ?? ?}? ? ? if (WriteReadStatus == 0) ? ? {? ? ?? ?/* 如果相等,则点亮LED1 */ ? ?? ?GPIO_SetBits(GPIOF,GPIO_Pin_6); ? ? else ? ?? ?/* 否则,点亮LED2 */ ??else //ID不正确 ? ? /* 点亮LED3 */ ? ? GPIO_SetBits(GPIOF,GPIO_Pin_8);?? ??} (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
推荐文章
站长推荐
热点阅读