LPC1788 nand驱动
Lpc
1788自带有emc接口用于驱动nandflash,norflash,sdram设备,对于nandflash驱动因为配置简单,时序也简单
首先,针对nandflash而言应当在系统中有三个地址,分别是数据读写地址,命令读写地址以及地址设置地址,这三个地址都需要更具电路图设置,电路图如下
根据这张图可以看到,CLE地址线也就是命令锁存线为高的时候,地址为命令地址,ALE也就是地址锁存线为高,地址为地址锁存线,当CLE和ALE都为低但是CE选中的时候地址为数据地址,那CS1代表的数据地址是多少呢,需要根据1788的地址分配来判断
当CS1选中的时候系统总线在0X90000000,因为A24 A25的存在,不难分析出,0x91000000为地址锁存使能,0x92000000为命令锁存使能,(因为没有其他的地址线连接,所以,其他的地址位都设置为0),
对nandflash的操作主要有下面几种
- 单纯命令
对0x92000000直接赋予相应的命令,也就是
*0x92000000 = cmd,然后等待系统响应就可以了,有时候系统有响应,比如读取状态,读取ID等,有的没有响应,例如复位命令
对于有响应的命令,,直接等待芯片完成操作之后读取地址线数据就可以了,也就是,
Returnvalue = *(0x90000000)
- 写入操作
说起写入操作,就必须要说一说nand的内部数据分区,首先,nand的数据分区是以块进行的,类似下图
也就是说,一块nandflash的实际容量的计算是块数量*页数量*主数据区域大小+(附加数据区域大小)
但是在实际工程应用中,附加数据区域是不会用来存放用户数据的,主要用来存储数据的ECC效验信息以及坏块信息,部分厂商在芯片出厂的时候会进行一次芯片完整性校验,对出厂就已经存在的坏块,会在第一页和第二页的附加数据区域存放一个数据0xff(nand flash指标只要坏块不超过40就可以买卖)
针对我使用的nand,块数量为1024 页数量为64,主数据区域存放2048byte数据
,所以用户实际可使用的空间为128mBYTE,但是存储设备一般用bit做单位,也就是1GBIT
对nandflash进行读取的时候,写入一个三十二位的地址,这个地址里面包括了几个数据
- 要读写的块是哪一个块
- 要读写的页是哪一页
- 要读写的数据位于一页中的哪一个字节
- 最后合成地址
地址的低16位为数据页内地址,高16位为块和页的地址(注意,这个计算出的地址还得加上基础地址0x90000000)
写入的过程,nandflash一个读出命令分为两个字节,先发送第一个字节的命令,然后写入32位的地址,然后写入读取命令的第二个字节,接下来读取数据(注意,读取数据是以页为单位进行的,当读取到页尾的时候就不能在进行读取了,要从新写入地址)
- 写入操作
Nandflash有一个特性就是擦除必须以块为单位,写入必须以页为单位,同时,写入的过程中他只能将数据从0变成1,不能将数据从1编程0(只有擦除才能将数据从1变成0),所以我们变成的时候必须保证要写的这一页必须是已经擦除过,里面的数据都是0才能保证我们写入的数据被接受,若是没有擦除过的数据,写入数据之后必然会失败
写入的时候同样是32位地址,其中,页内相对地址为0,只需要块地址和页地址,先写入编程命令1,在写入32位地址,在写入编程命令2,接着写入页空间大小的数据,编程完成
以上就是nand的读些过程,当然,lpc1788还需要配置之后才能使用emc的接口,过程如下
- 设置相应的IO口功能,使相应的IO口对应emc
- 打开emc的时钟
- 设置几个重要的参数…总线位宽,总线有效电平,还有一些时间配置参数
片选到写使能的延迟时间
片选到数据输出使能的延时时间
片选到写入的延时
顺序读取的时候每一次读取之间的延时
设置好这些参数之后稍微延时一会,就能进行nand的操作了
代码如下
#ifndef __NANDFLASH_H_ #define __NANDFLASH_H_#include "common.h" #include "debugserial.h" #include "delay.h"//nand flash 使用cs1 //reday/busy p2.21 //ale p5.1 //cle p5.0 //we p4.25 //oe p4.24 //ce p4.27//命令地址 #define K9F1G_CLE ((volatile uint8_t *)0x92000000) //命令锁存使能地址 #define K9F1G_ALE ((volatile uint8_t *)0x91000000) //地址锁存使能地址 #define K9F1G_DATA ((volatile uint8_t *)0x90000000) //数据地址//nand 命令列表 #define K9FXX_READ_1 0x00 //读数据第一个周期命令 #define K9FXX_READ_2 0x30 //读数据第二个周期命令 #define K9FXX_READ_COPYBACK_1 0x00 //读取数据用于copyback #define K9FXX_READ_COPYBACK_2 0x35 //copy back指令2 #define K9FXX_READ_ID 0x90 //读取ID #define K9FXX_RESET 0xFF //复位 #define K9FXX_BLOCK_PROGRAM_1 0x80 //页编程第一周期指令 #define K9FXX_BLOCK_PROGRAM_2 0x10 //页编程第二周期地址 #define K9FXX_BLOCK_ERASE_1 0x60 //块擦除第一周期命令 #define K9FXX_BLOCK_ERASE_2 0xD0 //块擦除第二周期命令 #define K9FXX_READ_STATUS 0x70 //读状态 70H//芯片ID #define K9FXX_ID 0xF1009540 /* Byte 3 and 2 only *///nand状态 #define K9FXX_BUSY (1 << 6) #define K9FXX_OK (1 << 0)//相关定义 #define NANDFLASH_BASE_ADDR 0x00000000 //起始地址#define NANDFLASH_NUMOF_BLOCK 1024 //nand一共拥有的块数量#define NANDFLASH_RW_PAGE_SIZE 2048 // 每页2048个存储字节#define NANDFLASH_SPARE_SIZE 64 //每页64个spare的备用空间(用于页数据的ECC校验和存放)#define NANDFLASH_PAGE_PER_BLOCK 64 //一个块的中page数量#define NANDFLASH_PAGE_FSIZE (NANDFLASH_RW_PAGE_SIZE + NANDFLASH_SPARE_SIZE)//每一页的实际大小(byte)#define NANDFLASH_BLOCK_RWSIZE (NANDFLASH_RW_PAGE_SIZE * NANDFLASH_PAGE_PER_BLOCK)//每一页可读取的空间#define NANDFLASH_BLOCK_FSIZE (NANDFLASH_PAGE_FSIZE * NANDFLASH_PAGE_PER_BLOCK)//实际上每一页的空间//可读取空间 = 2048(一页存储字节)*64(页数量)*1024(块数量) = 128MB //实际空间 = (2048+64)*64 * 1024 = 132 MB #define NANDFLASH_INVALIDBLOCK_CHECK_COLUMM (2048)//支持块校验数#define NAND_WAIT_BUSY_MAX_TIME 100 //MS 等待响应时间void nand_init(void);void nand_reset(void);u8 nand_wait_ready(void);u32 nand_read_id(void);u8 nand_read_status(u32 cmd);u8 nand_block_erase(u32 block_num);u8 nand_page_program(u32 blocknum,u32 pagenum,u8* buffer);u8 nand_check(void);u8 nand_page_read(u32 pagenum,u32 blocknum,u8* buffer);u32 nand_page_read_from_begin(u32 block,u32 page,u8* buffer);u32 nand_page_read_from_addr(u32 blocknum,u32 pagenum,u32 addrinpage,u8* buffer,u32 readsize);u32 nand_read_form_addr(u32 addrInWholeNand,u8* buffer,u32 size);#endif#include "nandflash.h"/*********************************************************************//*** 获取相应的io配置寄存器指针**********************************************************************/ static u32 * PIN_GetPointer(u8 portnum, u8 pinnum) {u32 *pPIN = NULL;pPIN = (u32 *)(LPC_IOCON_BASE + ((portnum * 32 + pinnum)*sizeof(u32)));return pPIN; }/*********************************************************************//***配置IO口功能**********************************************************************/ static void PINSEL_ConfigPin ( u8 portnum, u8 pinnum, u8 funcnum) {u32 *pPIN = NULL;pPIN = PIN_GetPointer(portnum, pinnum);*pPIN &= 0x00000007;//Clear function bits*pPIN |= funcnum; }//初始化nand接口,主要是初始化IO口以及初始化EMC外设 void nand_init() {LPC_SC->SCS |= (1<<0);//emc地址不移位//打开emc时钟与端口时钟LPC_SC->PCONP |= (1<<15)|(1<<11);//打开时钟LPC_SC->EMCDLYCTL = 0x00001010;//延时时间初始化LPC_EMC->Control = 0x00000001;//emc使能LPC_EMC->Config = 0x00000000;//emc配置清零,小端模式//我们选用的nand使用的外部引脚主要有//P3.0-P3.7 P5.0 P5.1 P4.24 P4.25 P4.31 P2.21 //配置IO寄存器 //d0--d7PINSEL_ConfigPin(3,0,1);PINSEL_ConfigPin(3,1,1);PINSEL_ConfigPin(3,2,1);PINSEL_ConfigPin(3,3,1);PINSEL_ConfigPin(3,4,1);PINSEL_ConfigPin(3,5,1);PINSEL_ConfigPin(3,6,1);PINSEL_ConfigPin(3,7,1);//cle alePINSEL_ConfigPin(5,0,1);PINSEL_ConfigPin(5,1,1);PINSEL_ConfigPin(4,24,1);//OEPINSEL_ConfigPin(4,25,1);//WEPINSEL_ConfigPin(4,31,1);//CS1//初始化忙引脚为输入模式PINSEL_ConfigPin(2,21,0);P2dir(21) = 0;LPC_EMC->Control = (1<<0)|(1<<1);//使能emc并复位存储器映射LPC_EMC->StaticConfig1 &= ~(3<<0); //设置总线宽度八位LPC_EMC->StaticConfig1 |= (1<<7); //设置读写有效电平,读为低电平LPC_EMC->StaticWaitWen1 &= ~(7<<0);LPC_EMC->StaticWaitWen1 |= (2<<0);//设置片选到写使能的延时时间LPC_EMC->StaticWaitOen1 &= ~(7<<0);LPC_EMC->StaticWaitOen1 |= (2<<0);//设置片选到输出使能的延时LPC_EMC->StaticWaitWr1 &= ~(0x1f<<0);LPC_EMC->StaticWaitWr1 |= (0x1f<<0);//设置片选到写入的延时LPC_EMC->StaticWaitPage1 &= ~(0x1f<<0);LPC_EMC->StaticWaitPage1 |= (0x1f<<0);//设置读模式顺序存取延时LPC_EMC->StaticWaitRd1 &= ~(0x1f<<0);LPC_EMC->StaticWaitRd1 |= (0x1f<<0);//设置片选到读取的延时LPC_EMC->StaticWaitTurn1 &= ~(0x1f<<0);LPC_EMC->StaticWaitTurn1 |= (0x1f<<0);//设置总线周转周期 DelayMs(2); }//nand复位 void nand_reset() {volatile u8 *pCLE;/* Reset NAND FLASH through NAND FLASH command */pCLE = K9F1G_CLE;*pCLE = K9FXX_RESET;DelayMs(2);return; }//等待nand不忙 u8 nand_wait_ready() {u8 waitTime = 0;while(P2in(21) == 1) /* 等待他为高,说明我们的操作正在进行 */{waitTime++;DelayUs(1);if(waitTime > NAND_WAIT_BUSY_MAX_TIME)return 1;}waitTime = 0;while(!(P2in(21) == 1)) /* 等待他为低,说明操作已经完成 */{waitTime++;DelayUs(1);if(waitTime > NAND_WAIT_BUSY_MAX_TIME)return 1;}return 0; }//读取nand id u32 nand_read_id() {u8 b, c, d, e;volatile u8 *pCLE;volatile u8 *pALE;volatile u8 *pDATA;pCLE = K9F1G_CLE;pALE = K9F1G_ALE;pDATA = K9F1G_DATA;*pCLE = K9FXX_READ_ID;*pALE = 0;b = *pDATA;//伪读取 无效b = *pDATA;c = *pDATA;d = *pDATA;e = *pDATA;return ((b << 24) | (c << 16) | (d << 8) | e); }//读取nand状态 u8 nand_read_status(u32 cmd) {volatile u8 *pCLE;volatile u8 *pDATA;u8 waitTime = 0; //等待时间 u8 StatusData;pCLE = K9F1G_CLE;pDATA = K9F1G_DATA;*pCLE = K9FXX_READ_STATUS;while ( (*pDATA & 0xC0) != 0xC0 ) //等待芯片ready并且无保护(失败应当有错误处理,暂时没做) {waitTime++;DelayUs(1);if(waitTime > NAND_WAIT_BUSY_MAX_TIME)return 1;}StatusData = *pDATA;switch (cmd){case K9FXX_BLOCK_PROGRAM_1://编程或擦除的第二个指令case K9FXX_BLOCK_ERASE_1:if (StatusData & 0x01) /* Erase/Program failure(1) or pass(0) */return 1;elsereturn 0;case K9FXX_READ_1: /* bit 5 and 6, Read busy(0) or ready(1) */return 0;default:break;}return(1); }//块擦除nand u8 nand_block_erase(u32 block_num) {volatile u8 *pCLE;volatile u8 *pALE;u32 rowAddr;pCLE = K9F1G_CLE;pALE = K9F1G_ALE;//计算地址rowAddr = (NANDFLASH_BASE_ADDR + block_num * NANDFLASH_BLOCK_FSIZE);//得到块基地址rowAddr = rowAddr - (rowAddr % NANDFLASH_BLOCK_FSIZE);//得到块偏移地址(页地址)*pCLE = K9FXX_BLOCK_ERASE_1;*pALE = (u8)(rowAddr & 0x00FF); /* column address low */*pALE = (u8)((rowAddr & 0xFF00) >> 8); /* column address high */*pCLE = K9FXX_BLOCK_ERASE_2;//擦除数据 nand_wait_ready();return(nand_read_status(K9FXX_BLOCK_ERASE_1)); }//每次至少写入2048字节 nand指定页编程 注意,编程之前需要先擦除的 u8 nand_page_program(u32 blocknum,u32 pagenum,u8* buffer) {volatile u8 *pCLE;volatile u8 *pALE;volatile u8 *pDATA;u32 i, curAddr, curColumm;pCLE = K9F1G_CLE;pALE = K9F1G_ALE;pDATA = K9F1G_DATA;curAddr = NANDFLASH_BASE_ADDR + blocknum * NANDFLASH_BLOCK_FSIZE+ pagenum * NANDFLASH_PAGE_FSIZE;curColumm = curAddr % NANDFLASH_PAGE_FSIZE;curAddr -= curColumm;//得到具体地址*pCLE = K9FXX_BLOCK_PROGRAM_1;//编程命令1*pALE = (u8)(curColumm & 0x000000FF); /* column address low */*pALE = (u8)((curColumm & 0x00000F00) >> 8); /* column address high */*pALE = (u8)((curAddr & 0x00FF0000) >> 16); /* row address low */*pALE = (u8)((curAddr & 0xFF000000) >> 24); /* row address high *///Not write to spare area for the NandFlash valid block checkingfor ( i = 0; i < NANDFLASH_RW_PAGE_SIZE; i++ ){*pDATA = *buffer++;}*pCLE = K9FXX_BLOCK_PROGRAM_2;//编程命令2 nand_wait_ready();return( nand_read_status( K9FXX_BLOCK_PROGRAM_1 ) );//读取编程结果 }//nand读取任意地址(慎用) 这个地址包含了附加数据地址 返回实际读取数据量 u32 nand_read_form_addr(u32 addrInWholeNand,u8* buffer,u32 size) {volatile u8 *pCLE;volatile u8 *pALE;volatile u8 *pDATA;u32 i, curColumm, curRow;i = 0;pCLE = K9F1G_CLE;pALE = K9F1G_ALE;pDATA = K9F1G_DATA;curColumm = addrInWholeNand % NANDFLASH_PAGE_FSIZE;curRow = addrInWholeNand - curColumm;*pCLE = K9FXX_READ_1;*pALE = (u8)(curColumm & 0x000000FF); /* column address low */*pALE = (u8)((curColumm & 0x00000F00) >> 8); /* column address high */*pALE = (u8)((curRow & 0x00FF0000) >> 16); /* row address low */*pALE = (u8)((curRow & 0xFF000000) >> 24); /* row address high */*pCLE = K9FXX_READ_2;nand_wait_ready();for ( i = 0; i < (NANDFLASH_PAGE_FSIZE - curColumm); i++ ){*buffer = *pDATA;buffer++;if((i + 1) >= size)break;}return i; }//nand读取指定页数据,数据长度不能大于2048-addrinpage u32 nand_page_read_from_addr(u32 blocknum,u32 pagenum,u32 addrinpage,u8* buffer,u32 readsize) {u32 curAddr = 0;curAddr += NANDFLASH_BASE_ADDR + blocknum * NANDFLASH_BLOCK_FSIZE;curAddr += pagenum * NANDFLASH_PAGE_FSIZE;curAddr += addrinpage;return (nand_read_form_addr(curAddr, buffer, readsize)); }//nand读取指定的页码全部数据,数据数量为 2048+32 u32 nand_page_read_from_begin(u32 block,u32 page,u8* buffer) {return (nand_page_read_from_addr(block, page, 0, buffer, NANDFLASH_PAGE_FSIZE)); }//nand读取指定页吗全部数据 u8 nand_page_read(u32 blocknum,u32 pagenum,u8* buffer) {return (nand_page_read_from_begin(blocknum,pagenum,buffer) != 0); }//nand检查,每次检查每个bloak的前两个page,检查最后一个字节是不是0xff u8 nand_check(void) {u32 invailedBlock = 0;u8 temp = 0;u16 i = 0;for(i = 0; i < NANDFLASH_NUMOF_BLOCK;i++){nand_page_read_from_addr(i,0,2048,&temp,1);if(temp == 0xff){invailedBlock++;continue;}nand_page_read_from_addr(i,1,2048,&temp,1);if(temp == 0xff){invailedBlock++;}}return (u8)invailedBlock; }
转载于:https://www.cnblogs.com/dengxiaojun/p/4069341.html
LPC1788 nand驱动相关推荐
- u-boot的nand驱动写过程分析
从命令说起,在u-boot输入下列命令: nand write 40008000 0 20000 命令的意思是将内存0x40008000开始的部分写入nand,从nand地址0开始写,写入长度是0x2 ...
- SylixOS下基于NUC970的NAND驱动
开发环境 开发环境 宿主机: Windows7 64bits 系统 开发板: 安米MDK972 软件环境: RealEvo-IDE3.0 NAND Flash: S34ML02G100TF100 S3 ...
- 基于MTD的NAND驱动开发(二)
基于MTD的NAND驱动开发(二) 基于MTD的NAND驱动开发(三) http://blog.csdn.net/leibniz_zsu/article/details/4977853 http:// ...
- Linux内核的Nand驱动流程分析
最近在做Linux内核移植,总体的感觉是这样的,想要彻底的阅读Linux内核代码几乎是不可能的,至少这还不是嵌入式学期初期的重要任务.内核代码解压后有250M左右,据统计,有400多万行,而且涉及到了 ...
- linux NAND驱动之三:6410平台上的NAND驱动加载
1,platform_driver 的定义和注册 在s3c_nand.c中, static struct platform_driver s3c6410_nand_driver = { ...
- linux NAND驱动之一:内核中的NAND代码布局
在Linux 内核中,MTD 源代码放在/driver/mtd 目录中,该目录中包含chips .devices .maps .nand .onenand 和ubi 六个子目录.其中只有nand 和o ...
- NAND驱动分析--(二)
在上一篇nand驱动分析中,大概描述了nand flash驱动加载时的初始化流程,接下来对其调用的一些函数进行进一步的阐述. 首先,上一篇说到调用了fsl_elbc_chip_init()函数,此函数 ...
- 分享自清客 《基于MTD的NAND驱动开发(完) (转)》
url:http://blog.csdn.net/mianyy/article/details/6712631 六.NAND驱动中的坏块管理 由 于NAND Flash的现有工艺不能保证NAND的Me ...
- 24.Linux-Nand Flash驱动(分析MTD层并制作NAND驱动)
1.本节使用的nand flash型号为K9F2G08U0M,它的命令如下: 1.1我们以上图的read id(读ID)为例,它的时序图如下: 首先需要使能CE片选 1)使能CLE 2)发送0X90命 ...
- linux nand 驱动,Linux NAND FLASH驱动分析(一)
最近一直在忙着工作上的事情,好久都没有更新博客了,发现最近思想是比较混乱的.学任何东西都坚持不下去,既然选择驱动开发这条路就要坚持下去. 之前分析了Linux块设备驱动,是以内存块来模拟的虚拟块设备. ...
最新文章
- linux回显冲突,Linux-Binfmt-support-不允许我回显注册
- Python图片爬取方法总结
- 十以内的加减java编写程序_Java实现随机出题,10道10以内加减法计算代码实例
- MQTT再学习 -- 漫谈MQTT协议
- 常用的分隔符有哪三种_三种废水处理方法
- mysql脚本的制作_制作脚本实现mysql自动备份
- 现在的编程语言越来越多,为什么 C 和 C++ 还没有被现在的时代淘汰呢?
- 乘风破浪的迁移学习!四字成语讲明白这个大热研究方向
- Echart 地图实例
- python的神经网络模块接法图解_图神经网络库PyTorch geometric
- OpenCV处理椒盐噪声以及提高对比度
- gpt-2 文章自动生成_有助于您理解GPT-3的文章
- 博通网卡管理软件Linux,博通网卡管理软件
- python 创建netcdf_如何用python netCDF4创建netCDF文件?
- 2019年字节跳动2020届秋招在线笔试真题(后端开发工程师)
- 一些电脑清理方法,学起来,总会用到的
- 小程序文档整理之 -- API(媒体)
- 静态,关键字:static 接口,IUSB , API 接口关键字:interface
- python爬取软件内数据_各种数据爬取工具爬虫合集整理
- 我的2017年文章汇总——深度学习篇