您的位置:首页 > 运维架构 > Linux

《嵌入式linux应用程序开发完全手册》NAND FLASH硬件编程学习笔记

2009-10-27 19:47 344 查看
1. 先看一下Flash的引脚图,它与S3C2440连线比较少(相对nor flash),地址数据和命令都是在如图示的一些使能信号的配合下,通过8个I/O引脚传输。写地址,数据,命令时,nCE,nWE信号必须为低电平,它们在nWE信号的上升沿被锁存,命令锁存使用信号CLE和地址锁存信号ALE用来区分I/O引脚上传输的是命令还是地址。



SECTIONS {
firtst  	0x00000000 : { head.o init.o nand.o}
second 	0x30000000 : AT(4096) { main.o }
}


Main.o的运行地址是0x30000000,生成映像文件中的偏移地址为4096。
(2) 程序主框架

@******************************************************************************
@ File:head.s
@ 功能:设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行
@******************************************************************************

.text
.global _start
_start:
@函数disable_watch_dog, memsetup, init_nand, nand_read_ll在init.c中定义
ldr     sp, =4096               @设置堆栈
bl      disable_watch_dog       @关WATCH DOG
bl      memsetup                @初始化SDRAM
bl      nand_init               @初始化NAND Flash

@将NAND Flash中地址4096开始的1024字节代码(main.c编译得到)复制到SDRAM中
@nand_read_ll函数需要3个参数:
ldr     r0,     =0x30000000     @1. 目标地址=0x30000000,这是SDRAM的起始地址
mov     r1,     #4096           @2.  源地址   = 4096,连接的时候,main.c中的代码都存在NAND Flash地址4096开始处
mov     r2,     #1024           @3.  复制长度= 1024(bytes),对于本实验的main.c,这是足够了
bl      nand_read               @调用C函数nand_read

ldr     sp, =0x34000000         @设置栈
ldr     lr, =halt_loop          @设置返回地址
ldr     pc, =main               @b指令和bl指令只能前后跳转32M的范围,所以这里使用向pc赋值的方法进行跳转
halt_loop:
b       halt_loop


(3) 利用函数指针指向各个操作函数,并构成一个结构体以方便使用
/* NAND FLASH (see S3C2440 manual chapter 6, www.100ask.net) */
typedef struct {
S3C24X0_REG32   NFCONF;
S3C24X0_REG32   NFCONT;
S3C24X0_REG32   NFCMD;
S3C24X0_REG32   NFADDR;
S3C24X0_REG32   NFDATA;
S3C24X0_REG32   NFMECCD0;
S3C24X0_REG32   NFMECCD1;
S3C24X0_REG32   NFSECCD;
S3C24X0_REG32   NFSTAT;
S3C24X0_REG32   NFESTAT0;
S3C24X0_REG32   NFESTAT1;
S3C24X0_REG32   NFMECC0;
S3C24X0_REG32   NFMECC1;
S3C24X0_REG32   NFSECC;
S3C24X0_REG32   NFSBLK;
S3C24X0_REG32   NFEBLK;
} S3C2440_NAND;

typedef struct {
void (*nand_reset)(void);
void (*wait_idle)(void);
void (*nand_select_chip)(void);
void (*nand_deselect_chip)(void);
void (*write_cmd)(int cmd);
void (*write_addr)(unsigned int addr);
unsigned char (*read_data)(void);
}t_nand_chip;

static S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;

static t_nand_chip nand_chip;


(4) Nand_init函数

/* 初始化NAND Flash */
void nand_init(void)
{
#define TACLS   0
#define TWRPH0  3
#define TWRPH1

nand_chip.nand_reset         = s3c2440_nand_reset;
nand_chip.wait_idle          = s3c2440_wait_idle;
nand_chip.nand_select_chip   = s3c2440_nand_select_chip;
nand_chip.nand_deselect_chip = s3c2440_nand_deselect_chip;
nand_chip.write_cmd          = s3c2440_write_cmd;
nand_chip.write_addr         = s3c2440_write_addr;
nand_chip.read_data          = s3c2440_read_data;

/* 设置时序 */
s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
/* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);
/* 复位NAND Flash */
nand_reset();
}



[b](5)
Flash的基本命令操作

[/b]
/* 复位 */
static void s3c2440_nand_reset(void)
{
s3c2440_nand_select_chip();
s3c2440_write_cmd(0xff);  // 复位命令
s3c2440_wait_idle();
s3c2440_nand_deselect_chip();
}

/* 等待NAND Flash就绪 */
static void s3c2440_wait_idle(void)
{
int i;
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;
while(!(*p & BUSY))
for(i=0; i<10; i++);
}

/* 发出片选信号 */
static void s3c2440_nand_select_chip(void)
{
int i;
s3c2440nand->NFCONT &= ~(1<<1);
for(i=0; i<10; i++);
}

/* 取消片选信号 */
static void s3c2440_nand_deselect_chip(void)
{
s3c2440nand->NFCONT |= (1<<1);
}

/* 发出命令 */
static void s3c2440_write_cmd(int cmd)
{
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;
*p = cmd;
}

/* 发出地址 */
static void s3c2440_write_addr(unsigned int addr)
{
int i;
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;

*p = addr & 0xff;
for(i=0; i<10; i++);
*p = (addr >> 9) & 0xff;
for(i=0; i<10; i++);
*p = (addr >> 17) & 0xff;
for(i=0; i<10; i++);
*p = (addr >> 25) & 0xff;
for(i=0; i<10; i++);
}

/* 读取数据 */
static unsigned char s3c2440_read_data(void)
{
volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;
return *p;
}

/* 在第一次使用NAND Flash前,复位一下NAND Flash */
static void nand_reset(void)
{
nand_chip.nand_reset();
}

static void wait_idle(void)
{
nand_chip.wait_idle();
}

static void nand_select_chip(void)
{
int i;
nand_chip.nand_select_chip();
for(i=0; i<10; i++);
}

static void nand_deselect_chip(void)
{
nand_chip.nand_deselect_chip();
}

static void write_cmd(int cmd)
{
nand_chip.write_cmd(cmd);
}
static void write_addr(unsigned int addr)
{
nand_chip.write_addr(addr);
}

static unsigned char read_data(void)
{
return nand_chip.read_data();
}


(6) [b] nand_read函数[/b]


[b]

[b]步骤如下:


(1)选择芯片
(2)发出读命令
(3)发出地址
(4)等待数据就绪
(5)读取数据
(6)flish,取消片选信号

[/b]
[/b]
/* 读函数 */
void nand_read(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j;

if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
return ;    /* 地址或长度不对齐 */
}

/* 选中芯片 */
nand_select_chip();

for(i=start_addr; i < (start_addr + size);) {
/* 发出READ0命令 */
write_cmd(0);

/* Write Address */
write_addr(i);
wait_idle();

for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
*buf = read_data();
buf++;
}
}

/* 取消片选信号 */
nand_deselect_chip();

return ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: