一、NAND FLASH的特点

S3C6410的NAND FLASH控制器有如下特点

1、自导入模式:复位后,引导代码被送入到8KB的STEPPINGSTONE中,引导代码移动完毕,引导代码将在STEPPINGSTONE中执行。导入期间,NAND FLASH控制器不支持ECC矫正。

2、NAND FLSH 控制器I/F:支持512字节和2KB页

3、软件模式:用户可以直接访问nand flash 控制器,该特性可以用于读/檫/编程nand flash 存储器。

1)写命令寄存器=NAND FLASH存储器命令周期

2)写地址寄存器=NAND FLASH存储器地址周期

3)写数据寄存器=写数据到NAND FLASH存储器(写周期)

4)读数据寄存器=从NAND FLASH 存储器数据(读周期)

5)读主ECC寄存器和备用ECC寄存器=从NAND FLASH存储器读数据

4、接口:8位NAND FLASH存储器接口总线

5、硬件:ECC产生、检测和标志(软件纠正)

6、支持SLC和MLC的NAND FLASH控制器:1位ECC用于SLC,4位ECC用于MLC的NAND FLASH

7、特殊功能寄存器I/F:支持字节/半字/字数据访问ECC的数据寄存器,用字来访问其他寄存器

8、STEPPINGSTONE I/F:支持字节/半字/字数据的访问

9、8KB的内部SRAM的缓冲器STEPPINGSTONE,在NAND FLASH引导后可做其他用途使用

该Tiny6410 开发板使用的NAND FLASH的类型为MLC大小为2G,型号K9GA08U0E-S

二、驱动设计

第一步:设置NAND FLASH的控制寄存器

  通过S3C6410数据手册可知NNAD FLASH的控制寄存器为NFCONF

寄存器       地址

NFCONF   0x70200000

  在NFCONF寄存器中主要用到TACLS、TWRPH0、TWRPH1,这三个变量。这三个变量用于配置nand flash 的时序。通过时序图

  由上图可知,TACLS为CLE/ALE 有效到nWE有效之间的持续时间。TWRPH0 位nWE的有效持续时间。TWRPH1为nWE无效到CLE/ALE 无效之间的持续时间。这些时间都是以HCLK为单位的。

  通过K9F2G08U0E数据手册(如下图)可知tWp 和TWRPH0相对应,(tcls-twp)与TALS相对应,tCLH与TWRPH1相对应。

  K9F2G08U0给出的值都是最小值。故在取值是只要满足该最小值就可以了。因此在这里我将TACLS、TWRPH0、TWRPH1分别取值为0x2、0xF和0x7。

故将NFCONF寄存器的设值为((0x2<<12)|(0xf<<8)|(0x7<<4))

第二步:使能NAND FLASH

  通过S3C6410的诗句手册可以知道使能NAND FLASH的寄存器为NFCONT

寄存器      地址

NFCONT   0x7020004

  由寄存器的描述可知,NFCONT的bit0位是控制NAND FLASH的。故将NFCONT的第零位设值为1即使能了NAND FLASH。

第三步:读操作(页读)

如下图可知读操作主要分五步走

  1、发片选:即设置NFCONT的bit1为0

  2、发命令:0x00,即往NFCMD写0x00

  3、发地址:由下图知地址需要分5个时钟周期来发送的,即往NFADDR写入地址,因为NFADDR一次只能接受8bit的数据

  4、发读命令:0x30,即往NFCMD写0x30

  5、连续读2048个字节,即连续读NFDATA寄存器2048次。

第四步:拷贝

  调用NAND FLASH的读操作,直到把.bin文件完全的从NAND FLASH中拷贝到 DRAM中。

第五步:编码运行

主要代码实现如下

//start.S
.global _start
_start
//把外设告诉CPU
ldr r0, =0x70000000
orr r0,r0,#0x13
mcr p15,0,r0,c15,c2,4
//官看门狗
ldr r0,=0x7E004000
mov r1,#0
str r1,[r0]
//设置栈
ldr sp,=0x0c002000
//开启icaches
#ifdef CONFIG_SYS_ICACHE_OFF
bic r0,r0,#0x00001000
#else
orr r0,r0,#0x00001000
mcr p15,0,r0,c1,c0,0x00001000
#endif
//设置时钟
bl clock_init //初始换sdram
bl sdram_init //初始化nand flash bl nand_init //重定位,把代码、数据复制到他的链接中去
adr r0,_start @_start的当前地址
ldr r1,=_star @_start的链接地址
ldr r2,=bss_start
sub r2,r2,r1
cmp r0,r1
beq clean_bss bl copy2ddr cmp r0,#0
bne halt //清理bss段,把bss对应的内存清零
clean_bss:
ldr r0,=bss_start
ldr r1,=bss_end
mov r3,#0
cmp r0,r1
beq on_ddr
clean_loop:
str r3,[r0],#4
cmp r0,r1
bne clean_loop //跳转
on_ddr:
ldr pc,=main
halt:
b halt
//nand.c
#include "Tiny6410Addr.h"
//nand flash 的命令
#define NAND_CMD_READ0 0
#define NAND_CMD_READ1 1
#define NAND_CMD_RNDOUT 5
#define NAND_CMD_PAGEPROG 0x10
#define NAND_CMD_READOOB 0x50
#define NAND_CMD_ERASE1 0x60
#define NAND_CMD_STATUS 0x70
#define NAND_CMD_STATUS_MULTI 0x71
#define NAND_CMD_SEQIN 0x80
#define NAND_CMD_RNDIN 0x85
#define NAND_CMD_READID 0x90
#define NAND_CMD_ERASE2 0xd0
#define NAND_CMD_RESET 0xff
/*
typedef struct{
void (*nand_reset)(void);
void (*nand_select_chip)(void);
void (*nand_deselect_chip)(void);
void (*write_cmd)(int Cmd);
void (*read_cmd)(int Cmd);
void (*wait_idle)(void);
void (*write_addr)(unsigned int addr); }NAND_CHIP;
static NAND_CHIP nand_chip;
*/
void nand_init(void); //Tiny6410 nand Flash 的操作函数申明
static void Tiny6410_nand_reset(void); //重启
static void Tiny6410_nand_select_chip(void); //片选使能
static void Tiny6410_nand_diselect_chip(void); //关闭片选
static void Tiny6410_write_cmd(int cmd); //写命令
static void Tiny6410_read_cmd(int cmd); //读命令
static void Tiny6410_wait_idle(void); //等待
static void Tiny6410_write_addr(unsigned int addr); //写地址
///////////////////////////////////////// //Tiny6410 nand Flash 的操作函数实现
static void Tiny6410_nand_reset(void)
{
Tiny6410_nand_select_chip();
Tiny6410_write_cmd(int cmd);
Tiny6410_wait_idle();
Tiny6410_nand_diselect_chip(); }
//片选使能
static void Tiny6410_nand_select_chip(void)
{
NFCONT &= ~(1 << 1);
}
//取消片选
static void Tiny6410_nand_diselect_chip(void)
{
NFCONT |= (1 << 1);
}
static void Tiny6410_write_cmd(int cmd)
{ }
//等待数据
static void Tiny6410_wait_idle(void)
{
do {
while(!(NFSTAT & (1 << 0)));
} while(0) }
//读命令
static void Tiny6410_read_cmd(int cmd)
{
NFCMD = cmd;
}
//写命令
static void Tiny6410_write_cmd(int cmd)
{
//NFCMD = cmd;
}
static void Tiny6410_write_addr(unsigned long addr)
{
NFADDR = 0;
NFADDR = 0;
NFADDR = (addr) & 0xff;
NFADDR = (addr >> 8) & 0xff;
NFADDR = (addr >> 16) & 0xff;
} ///////////////////////////////////////
//nand flash 初始化
void init_nand(void)
{
//设置NAND FLASH 控制器
NFCONF = ((0x2 << 12)|(0xf << 8)|(0x7 << 4));
NFCONT |= ((0x3 << 0)); } //读以页数据
static int nand_read_page(unsigned char *buf,unsigned long addr)
{
int i; //发出片选
Tiny6410_nand_select_chip();
//发送读命令
Tiny6410_read_cmd(NAND_CMD_READ0);
//发送地址
Tiny6410_write_addr(addr);
//发送读命令
Tiny6410_read_cmd(NAND_CMD_READSTART);
//等待数据
Tiny6410_wait_idle();
//连续读取2048个字节
for(i=0; i < page_size; i++)
{
*buf++ = NFDATA8_REG;
}
//取消片选
Tiny6410_nand_diselect_chip();
return 0;
} //从NAND 中拷贝到DRAM
int copy2dram(unsigned int nand_start,unsigned int dram_start,unsigned int len)
{
unsigned char *buf = (unsigned char *)ddr_start;
int i;
unsigned int page_shift = 11;
//发片选
Tiny6410_nand_select_chip(); // 使len为2048的整数倍
len = (len/2048+1)*2048; // 循环拷贝,每次拷贝一页数据
for (i = 0; i < (len>>page_shift); i++, buf+=(1<<page_shift))
{
// 读一页,即2048byte
nandll_read_page(buf, i);
} return 0;
}
//nand.lds
SECTIONS {
. = 0x50000000; .text : {
start.o
clock.o
sdram.o
nand.o
* (.text)
} .rodata : {
* (.rodata)
} .data : {
* (.data)
} bss_start = .;
.bss ALIGN(4) : { *(.bss) *(COMMON) }
bss_end = .;
}
//TinyAddr.h
#ifndef _Tiny6410Addr_H
#define _Tiny6410Addr_H
//GPK
#define GPKIO_BASE (0x7F008800)
#define rGPKCON0 (*((volatile unsigned long *)(GPKIO_BASE+0x00)))
#define rGPKDAT (*((volatile unsigned long *)(GPKIO_BASE+0x08))) //CLOCK
#define APLL_LOCK (*((volatile unsigned long *)0x7E00F000))
#define MPLL_LOCK (*((volatile unsigned long *)0x7E00F004))
#define EPLL_LOCK (*((volatile unsigned long *)0x7E00F008))
#define OTHERS (*((volatile unsigned long *)0x7e00f900))
#define CLK_DIV0 (*((volatile unsigned long *)0x7E00F020))
#define APLL_CON (*((volatile unsigned long *)0x7E00F00C))
#define MPLL_CON (*((volatile unsigned long *)0x7E00F010))
#define CLK_SRC (*((volatile unsigned long *)0x7E00F01C)) //GPA /uart
#define ULCON0 (*((volatile unsigned long *)0x7F005000))
#define UCON0 (*((volatile unsigned long *)0x7F005004))
#define UFCON0 (*((volatile unsigned long *)0x7F005008))
#define UMCON0 (*((volatile unsigned long *)0x7F00500C))
#define UTRSTAT0 (*((volatile unsigned long *)0x7F005010))
#define UFSTAT0 (*((volatile unsigned long *)0x7F005018))
#define UTXH0 (*((volatile unsigned char *)0x7F005020))
#define URXH0 (*((volatile unsigned char *)0x7F005024))
#define UBRDIV0 (*((volatile unsigned short *)0x7F005028))
#define UDIVSLOT0 (*((volatile unsigned short *)0x7F00502C))
#define GPACON (*((volatile unsigned long *)0x7F008000)) //Sdram
#define P1MEMSTAT (*((volatile unsigned long *)0x7e001000))
#define P1MEMCCMD (*((volatile unsigned long *)0x7e001004))
#define P1DIRECTCMD (*((volatile unsigned long *)0x7e001008))
//#define MEMCCMD (*((volatile unsigned long *)0x7e001004))
#define P1REFRESH (*((volatile unsigned long *)0x7e001010))
#define P1CASLAT (*((volatile unsigned long *)0x7e001014))
#define MEM_SYS_CFG (*((volatile unsigned long *)0x7e00f120))
#define P1MEMCFG (*((volatile unsigned long *)0x7e00100c))
#define P1T_DQSS (*((volatile unsigned long *)0x7e001018))
#define P1T_MRD (*((volatile unsigned long *)0x7e00101c))
#define P1T_RAS (*((volatile unsigned long *)0x7e001020))
#define P1T_RC (*((volatile unsigned long *)0x7e001024))
#define P1T_RCD (*((volatile unsigned long *)0x7e001028))
#define P1T_RFC (*((volatile unsigned long *)0x7e00102c))
#define P1T_RP (*((volatile unsigned long *)0x7e001030))
#define P1T_RRD (*((volatile unsigned long *)0x7e001034))
#define P1T_WR (*((volatile unsigned long *)0x7e001038))
#define P1T_WTR (*((volatile unsigned long *)0x7e00103c))
#define P1T_XP (*((volatile unsigned long *)0x7e001040))
#define P1T_XSR (*((volatile unsigned long *)0x7e001044))
#define P1T_ESR (*((volatile unsigned long *)0x7e001048))
#define P1MEMCFG2 (*((volatile unsigned long *)0X7e00104c))
#define P1_chip_0_cfg (*((volatile unsigned long *)0x7e001200)) //Nand
#define NAND_BASE (0x70200000)
#define NFCONF (*((volatile unsigned long *)NAND_BASE + 0x00))
#define NFCONT (*((volatile unsigned long *)NAND_BASE + 0x04))
#define NFCMMD (*((volatile unsigned long *)NAND_BASE + 0x08))
#define NFADDR (*((volatile unsigned long *)NAND_BASE + 0x0c))
#define NFDATA (*((volatile unsigned long *)NAND_BASE + 0x10))
#define NFMECCDATA0 (*((volatile unsigned long *)NAND_BASE + 0x14))
#define NFMECCDATA1 (*((volatile unsigned long *)NAND_BASE + 0x18))
#define NFSECCDATA0 (*((volatile unsigned long *)NAND_BASE + 0x1c))
#define NFSBLK (*((volatile unsigned long *)NAND_BASE + 0x20))
#define NFEBLK (*((volatile unsigned long *)NAND_BASE + 0x24))
#define NFSTAT (*((volatile unsigned long *)NAND_BASE + 0x28))
#define NFESTAT0 (*((volatile unsigned long *)NAND_BASE + 0x2c))
#define NFESTAT1 (*((volatile unsigned long *)NAND_BASE + 030))
#define NFMECC0 (*((volatile unsigned long *)NAND_BASE + 0x34))
#define NFMECC1 (*((volatile unsigned long *)NAND_BASE + 0x38))
#define NFSECC (*((volatile unsigned long *)NAND_BASE + 0x3c))
#define NFMLCBITPT (*((volatile unsigned long *)NAND_BASE + 0x40))
/*#define NF8ECCERR0 (*((volatile unsigned long *)NAND_BASE + 0x44))
#define NF8ECCERR1 (*((volatile unsigned long *)NAND_BASE + 0x48))
#define NF8ECCERR2 (*((volatile unsigned long *)NAND_BASE + 0x4c))
#define NFM8ECC0 (*((volatile unsigned long *)NAND_BASE + 0x50))
#define NFM8ECC1 (*((volatile unsigned long *)NAND_BASE + 0x54))
#define NFM8ECC2 (*((volatile unsigned long *)NAND_BASE + 0x58))
#define NFM8ECC3 (*((volatile unsigned long *)NAND_BASE + 0x5c))
#define NFMLC8BITPT0 (*((volatile unsigned long *)NAND_BASE + 0x60))
#define NFMLC8BITPT1 (*((volatile unsigned long *)NAND_BASE + 0x64))
*/ #endif

总结:

  综上所述主要分为两个大步。

  第一步:读S3C6410数据手册,了解NANDfLASH 的操作流程。

  第二步:读NAND FLASH数据手册,了解各个寄存器的具体设置。

  

Tiny6410之NAND FLASH驱动的更多相关文章

  1. Smart210学习记录----nand flash驱动

    [详解]如何编写Linux下Nand Flash驱动  :http://www.cnblogs.com/linux-rookie/articles/3016990.html 当读写文件请求到来的时候, ...

  2. Nand Flash驱动(实现初始化以及读操作)

    简单制作一个Nand Flash驱动(只需要初始化Flash以及读Flash) 打开2440芯片手册,K9F2G08U0M芯片手册(因为2440中Nand Flash是用的256MB(2Gb)内存,8 ...

  3. linux2.6.30.4内核移植(2)——Nand Flash驱动移植

    内核源码:linux2.6.30.4 交叉编译工具:3.4.5 移植linux内核至:TQ2440 工作基础:http://www.cnblogs.com/nufangrensheng/p/36696 ...

  4. linux下Pl353 NAND Flash驱动分析

    linux的NAND Flash驱动位于drivers/mtd/nand子文件夹下: nand_base.c-->定义通用的nand flash基本操作函数,如读写page,可自己重写这些函数 ...

  5. NAND FLASH 驱动分析

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

  6. 如何编写linux下nand flash驱动-2

    [Nand Flash引脚(Pin)的说明] 图3.Nand Flash引脚功能说明 上图是常见的Nand Flash所拥有的引脚(Pin)所对应的功能,简单翻译如下: 1.       I/O0 ~ ...

  7. 如何编写linux下nand flash驱动-4

    2.       软件方面 如果想要在Linux下编写Nand Flash驱动,那么就先要搞清楚Linux下,关于此部分的整个框架.弄明白,系统是如何管理你的nand flash的,以及,系统都帮你做 ...

  8. 15.1 linux操作系统下nand flash驱动框架2

    当我们需要在操作系统上读写普通文件的时候,总是需要一层层往下,最终到达硬件相关操作,当然底层设备大多数都是块设备 NAND FLASH就作为一个最底层的块设备. 而写驱动,就是要构建硬件与操作系统之间 ...

  9. 十八、Nand Flash驱动和Nor Flash驱动

    在读者学习本章之前,最好了解Nand Flash读写过程和操作,可以参考:Nand Flash裸机操作. 一开始想在本章写eMMC框架和设备驱动,但是没有找到关于eMMC设备驱动具体写法,所以本章仍继 ...

随机推荐

  1. Html 导航

    首页,来一个比较简单的例子热热身,相信有点css基础的人都可以看懂的.自所以,写一些教程,或许这样的教程已经泛滥啦,但是,还是想理理自己的思想来帮助自己及引导初学者更好的理解css. 1.竖直排列导航 ...

  2. 关于模板pair的用法

    在挑战程序设计竞赛中看到调用pair,就上网查了一下 类型申明有两种 template <class T1, class T2> struct pair typedef pairt< ...

  3. Android JNI(NDK)开发总结

    早就知道Java有个jni可以调用本地化代码,一直没有动力去研究它,现在公司想通过在Android中调用本地化代码来申请较多的内存以突破Android对单个进程的内存限制,这确实是可行的:我的Nexu ...

  4. 前端css:“圣杯布局”

    昨天面试前端,一面危险通过,面试官建议我看看“圣杯布局”,听起来很玄妙的名字,花了一晚上弄明白怎么回事,惊讶于前端工作的细节和技巧! 我先看几个基础,在后面要用到的: 1.CSS right/left ...

  5. Prolog学习:基本概念 and Asp.net与Dojo交互:仪器仪表实现

    Asp.net与Dojo交互:仪器仪表实现 项目中需要用到仪器仪表的界面来显示实时的采集信息值,于是便遍地寻找,参考了fusionchart和anychart之后,发现都是收费的,破解的又没有这些功能 ...

  6. 基于Redis的CustomerSessionProvider(一)

    CustomerSessionProvider需要实现SessionStateStoreProviderBase 在设计Redis Session Provider的时候,需要考虑 1.是否每个用户的 ...

  7. HttpStack及其实现类

    HttpStack及其实现类 前两篇已经对网络请求流程已经梳理了个大概,这次我们着重看一下HttpStack和它的其实现类.我们之前在Network篇讲过它仅有一个实现类,而今天我们讲的HttpSta ...

  8. Define Constraints That Are Minimal and Sufficient 设定不多不少的约束

    Define Constraints That Are Minimal and Sufficient 设定不多不少的约束   今天第二章第二节. 主管不在,然后暂时没什么任务,把第二节看了,然后整理一 ...

  9. Aliexpress API 授权流程整理

    Aliexpress API 授权流程整理   前言 我零零总总用了好几个月的时间,写了一个自用的小程序,从 Aliexpress 上抓取订单的小程序.刚开始写的时候,该API还没有开放,而且没有订单 ...

  10. java分割excel文件可用jxl

    excel导入是经常使用到的功能,如果文件数据量大的话还是建议分割后导入,java常用的API是poi和jxl,我采用的是jxl,那么让我们来看下怎么用jxl来实现分割. 需要在pom中导入jxl的包 ...