Lpc

1788自带有emc接口用于驱动nandflash,norflash,sdram设备,对于nandflash驱动因为配置简单,时序也简单

首先,针对nandflash而言应当在系统中有三个地址,分别是数据读写地址,命令读写地址以及地址设置地址,这三个地址都需要更具电路图设置,电路图如下

根据这张图可以看到,CLE地址线也就是命令锁存线为高的时候,地址为命令地址,ALE也就是地址锁存线为高,地址为地址锁存线,当CLE和ALE都为低但是CE选中的时候地址为数据地址,那CS1代表的数据地址是多少呢,需要根据1788的地址分配来判断

当CS1选中的时候系统总线在0X90000000,因为A24 A25的存在,不难分析出,0x91000000为地址锁存使能,0x92000000为命令锁存使能,(因为没有其他的地址线连接,所以,其他的地址位都设置为0),

对nandflash的操作主要有下面几种

  1. 单纯命令

对0x92000000直接赋予相应的命令,也就是

*0x92000000 = cmd,然后等待系统响应就可以了,有时候系统有响应,比如读取状态,读取ID等,有的没有响应,例如复位命令

对于有响应的命令,,直接等待芯片完成操作之后读取地址线数据就可以了,也就是,

Returnvalue = *(0x90000000)

  1. 写入操作

说起写入操作,就必须要说一说nand的内部数据分区,首先,nand的数据分区是以块进行的,类似下图

也就是说,一块nandflash的实际容量的计算是块数量*页数量*主数据区域大小+(附加数据区域大小)

但是在实际工程应用中,附加数据区域是不会用来存放用户数据的,主要用来存储数据的ECC效验信息以及坏块信息,部分厂商在芯片出厂的时候会进行一次芯片完整性校验,对出厂就已经存在的坏块,会在第一页和第二页的附加数据区域存放一个数据0xff(nand flash指标只要坏块不超过40就可以买卖)

针对我使用的nand,块数量为1024 页数量为64,主数据区域存放2048byte数据

,所以用户实际可使用的空间为128mBYTE,但是存储设备一般用bit做单位,也就是1GBIT

对nandflash进行读取的时候,写入一个三十二位的地址,这个地址里面包括了几个数据

  1. 要读写的块是哪一个块
  2. 要读写的页是哪一页
  3. 要读写的数据位于一页中的哪一个字节
  4. 最后合成地址

地址的低16位为数据页内地址,高16位为块和页的地址(注意,这个计算出的地址还得加上基础地址0x90000000)

写入的过程,nandflash一个读出命令分为两个字节,先发送第一个字节的命令,然后写入32位的地址,然后写入读取命令的第二个字节,接下来读取数据(注意,读取数据是以页为单位进行的,当读取到页尾的时候就不能在进行读取了,要从新写入地址)

  1. 写入操作

Nandflash有一个特性就是擦除必须以块为单位,写入必须以页为单位,同时,写入的过程中他只能将数据从0变成1,不能将数据从1编程0(只有擦除才能将数据从1变成0),所以我们变成的时候必须保证要写的这一页必须是已经擦除过,里面的数据都是0才能保证我们写入的数据被接受,若是没有擦除过的数据,写入数据之后必然会失败

写入的时候同样是32位地址,其中,页内相对地址为0,只需要块地址和页地址,先写入编程命令1,在写入32位地址,在写入编程命令2,接着写入页空间大小的数据,编程完成

以上就是nand的读些过程,当然,lpc1788还需要配置之后才能使用emc的接口,过程如下

  1. 设置相应的IO口功能,使相应的IO口对应emc
  2. 打开emc的时钟
  3. 设置几个重要的参数…总线位宽,总线有效电平,还有一些时间配置参数

片选到写使能的延迟时间

片选到数据输出使能的延时时间

片选到写入的延时

顺序读取的时候每一次读取之间的延时

设置好这些参数之后稍微延时一会,就能进行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 * + 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 |= (<<);//emc地址不移位
//打开emc时钟与端口时钟
LPC_SC->PCONP |= (<<)|(<<);//打开时钟
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--d7
PINSEL_ConfigPin(,,);
PINSEL_ConfigPin(,,);
PINSEL_ConfigPin(,,);
PINSEL_ConfigPin(,,);
PINSEL_ConfigPin(,,);
PINSEL_ConfigPin(,,);
PINSEL_ConfigPin(,,);
PINSEL_ConfigPin(,,);
//cle ale
PINSEL_ConfigPin(,,);
PINSEL_ConfigPin(,,); PINSEL_ConfigPin(,,);//OE
PINSEL_ConfigPin(,,);//WE
PINSEL_ConfigPin(,,);//CS1 //初始化忙引脚为输入模式
PINSEL_ConfigPin(,,);
P2dir() = ; LPC_EMC->Control = (<<)|(<<);//使能emc并复位存储器映射
LPC_EMC->StaticConfig1 &= ~(<<); //设置总线宽度八位
LPC_EMC->StaticConfig1 |= (<<); //设置读写有效电平,读为低电平
LPC_EMC->StaticWaitWen1 &= ~(<<);
LPC_EMC->StaticWaitWen1 |= (<<);//设置片选到写使能的延时时间
LPC_EMC->StaticWaitOen1 &= ~(<<);
LPC_EMC->StaticWaitOen1 |= (<<);//设置片选到输出使能的延时
LPC_EMC->StaticWaitWr1 &= ~(0x1f<<);
LPC_EMC->StaticWaitWr1 |= (0x1f<<);//设置片选到写入的延时
LPC_EMC->StaticWaitPage1 &= ~(0x1f<<);
LPC_EMC->StaticWaitPage1 |= (0x1f<<);//设置读模式顺序存取延时
LPC_EMC->StaticWaitRd1 &= ~(0x1f<<);
LPC_EMC->StaticWaitRd1 |= (0x1f<<);//设置片选到读取的延时
LPC_EMC->StaticWaitTurn1 &= ~(0x1f<<);
LPC_EMC->StaticWaitTurn1 |= (0x1f<<);//设置总线周转周期 DelayMs();
} //nand复位
void nand_reset()
{
volatile u8 *pCLE; /* Reset NAND FLASH through NAND FLASH command */
pCLE = K9F1G_CLE;
*pCLE = K9FXX_RESET; DelayMs();
return;
} //等待nand不忙
u8 nand_wait_ready()
{
u8 waitTime = ;
while(P2in() == ) /* 等待他为高,说明我们的操作正在进行 */
{
waitTime++;
DelayUs();
if(waitTime > NAND_WAIT_BUSY_MAX_TIME)
return ; }
waitTime = ;
while(!(P2in() == )) /* 等待他为低,说明操作已经完成 */
{
waitTime++;
DelayUs();
if(waitTime > NAND_WAIT_BUSY_MAX_TIME)
return ; }
return ;
} //读取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 = ; b = *pDATA;//伪读取 无效
b = *pDATA;
c = *pDATA;
d = *pDATA;
e = *pDATA; return ((b << ) | (c << ) | (d << ) | e);
} //读取nand状态
u8 nand_read_status(u32 cmd)
{
volatile u8 *pCLE;
volatile u8 *pDATA;
u8 waitTime = ; //等待时间
u8 StatusData; pCLE = K9F1G_CLE;
pDATA = K9F1G_DATA; *pCLE = K9FXX_READ_STATUS; while ( (*pDATA & 0xC0) != 0xC0 ) //等待芯片ready并且无保护(失败应当有错误处理,暂时没做)
{
waitTime++;
DelayUs();
if(waitTime > NAND_WAIT_BUSY_MAX_TIME)
return ; }
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 ;
else
return ; case K9FXX_READ_1: /* bit 5 and 6, Read busy(0) or ready(1) */
return ;
default:
break;
} return();
} //块擦除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) >> ); /* 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) >> ); /* column address high */ *pALE = (u8)((curAddr & 0x00FF0000) >> ); /* row address low */ *pALE = (u8)((curAddr & 0xFF000000) >> ); /* row address high */ //Not write to spare area for the NandFlash valid block checking
for ( i = ; 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 = ; 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) >> ); /* column address high */ *pALE = (u8)((curRow & 0x00FF0000) >> ); /* row address low */ *pALE = (u8)((curRow & 0xFF000000) >> ); /* row address high */ *pCLE = K9FXX_READ_2; nand_wait_ready(); for ( i = ; i < (NANDFLASH_PAGE_FSIZE - curColumm); i++ )
{
*buffer = *pDATA; buffer++;
if((i + ) >= 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 = ; 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, , buffer, NANDFLASH_PAGE_FSIZE));
} //nand读取指定页吗全部数据
u8 nand_page_read(u32 blocknum,u32 pagenum,u8* buffer)
{
return (nand_page_read_from_begin(blocknum,pagenum,buffer) != );
} //nand检查,每次检查每个bloak的前两个page,检查最后一个字节是不是0xff
u8 nand_check(void)
{
u32 invailedBlock = ;
u8 temp = ;
u16 i = ;
for(i = ; i < NANDFLASH_NUMOF_BLOCK;i++)
{
nand_page_read_from_addr(i,,,&temp,);
if(temp == 0xff)
{
invailedBlock++;
continue;
}
nand_page_read_from_addr(i,,,&temp,);
if(temp == 0xff)
{
invailedBlock++;
}
}
return (u8)invailedBlock;
}

LPC1788 nand驱动的更多相关文章

  1. 基于MTD的NAND驱动开发、K9F1G08 2K page、Yaffs2 Files System

    转载:http://hi.baidu.com/cui1206/item/1d4119e376132513585dd886 基于MTD的NAND驱动(linux-2.6.22.10内核),目前已可以在该 ...

  2. MTD中的nand驱动初步分析---面向u-boot

    之前提到nand驱动的初始化分析,有一个结构体 struct mtd_info始终贯穿这些代码 再来分析一下这个结构体的基本功能,如何初始化,如何使用 一.分析过程 看看结构体的出现和使用方式 第一次 ...

  3. u-boot的nand驱动写过程分析

    从命令说起,在u-boot输入下列命令: nand write 40008000 0 20000 命令的意思是将内存0x40008000开始的部分写入nand,从nand地址0开始写,写入长度是0x2 ...

  4. MTD下的Nand驱动

    目录 MTD下的Nand驱动 引入 平台设备资源文件 关键数据结构 平台框架 s3c24xx_nand_probe nand_scan s3c2410_nand_add_partition add_m ...

  5. NAND驱动

    NAND FLASH是一个存储芯片 那么: 这样的操作很合理"读地址A的数据,把数据B写到地址A" 问1. 原理图上NAND FLASH和S3C2440之间只有数据线,      ...

  6. nand驱动移植

    首先下载nand flash驱动 s3c_nand.c ,此文件包含着nand flash驱动具体的实现,将其复制到drivers/mtd/nand下: s3c_nand.c 下载地址 s3c_nan ...

  7. Linux-Nand Flash驱动(分析MTD层并制作NAND驱动)

    1.本节使用的nand flash型号为K9F2G08U0M,它的命令如下: 1.1我们以上图的read id(读ID)为例,它的时序图如下: 首先需要使能CE片选 1)使能CLE 2)发送0X90命 ...

  8. 24.Linux-Nand Flash驱动(分析MTD层并制作NAND驱动)

    1.本节使用的nand flash型号为K9F2G08U0M,它的命令如下: 1.1我们以上图的read id(读ID)为例,它的时序图如下: 首先需要使能CE片选 1)使能CLE 2)发送0X90命 ...

  9. 移植nand驱动补缺:make mrproper与make clean以及make distclean,find/grep. makefile

    make mrproper与make clean以及make distclean的区别: linux内核源码根目录下面的makefile中有很清晰的解析: useage: “clean”:Remove ...

随机推荐

  1. lucene3.6.1 经典案例 入门教程 (包含从文件中读取content)

    转载http://liqita.iteye.com/blog/1676664 第一步:下载lucene的核心包 lucene-core-3.6.1-javadoc.jar (3.5 MB) lucen ...

  2. java 缓冲流

    english.txt The arrow missed the target. They rejected the union demand. Where does this road go to? ...

  3. CodeForces 689C Mike and Chocolate Thieves (二分最大化最小值)

    题目并不难,就是比赛的时候没敢去二分,也算是一个告诫,应该敢于思考…… #include<stdio.h> #include<iostream> using namespace ...

  4. JSch - Java实现的SFTP

    JSch - Java实现的SFTP(文件上传详解篇)     JSch是Java Secure Channel的缩写.JSch是一个SSH2的纯Java实现.它允许你连接到一个SSH服务器,并且可以 ...

  5. java导读

    导读:      我们学习Java大概有3个方向,第一,桌面系统,包括C/S结构:第二,J2ME,面向无限领域,很有潜力的家伙,看看中国的手机用户就知道了.第三,面向企业应用.计算的平台,J2EE. ...

  6. java设计原则:16种原则

    一   类的设计原则   1 依赖倒置原则-Dependency Inversion Principle (DIP) 2 里氏替换原则-Liskov Substitution Principle (L ...

  7. Angular服务器通信之:$http

    $http服务提供了浏览器XMLHttpRequest对象的封装,并且作为Angular中和后台服务通信的底层服务,在此之上Angular还提供了一个可选模块ngResource支持与RESTFul的 ...

  8. 【项目笔记】【bug】数组空指针异常

    package com.example.googleplay.ui.holder; import java.util.ArrayList; import android.view.View; impo ...

  9. VC6.0 调试.dll文件

    对于自己制作的.DLL文件,一直没有比较好的调试方法,其实是知道的太少. 下面就说说VC6.0下面 怎么调试DLL文件: 首先得有一个调用DLL文件的可执行程序,然后调用这个可执行程序. 在工程上 右 ...

  10. 宿主机丢失vmnet0和vmnet8网卡

    好久没打开虚拟机竟然发现与主机的连接网卡都不见了,有人说进入编辑-->虚拟网络编辑-->将主机虚拟适配器连接到此网络打钩就好,我觉得蛮有道理的,但是试验打勾并点击应用时虚拟机又会返回到没打 ...