一、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. 生成自己的Webapi帮助文档(二)

    经过今天一上午的修改,已经有个基础的框架了,其它功能只能是在实际使用中发现一个修改一个了. 以下是生成的结果示例: 相比昨天,几个Model都有修改,这里就不一一贴代码了,放个代码包上来,有需要的自己 ...

  2. Moq的使用心得

    Moq的使用心得 1.Moq中Mock Repository时最好是Mock Repository的接口,这样会避免不知名的错误. var mockClubRepository = new Mock& ...

  3. windbg Symbol file path

    SOS是一个调试器扩展,用于调试.NET应用程序.它提供了一组非常丰富的命令,这些命令使开发人员可以对CLR进行深入分析,并且有助于找出应用程序中各种复杂错误的原因.   由于SOS能够提供CLR内部 ...

  4. MongoDB:利用官方驱动改装为EF代码风格的MongoDB.Repository框架 六:支持多数据库操作

    本次主要内容:修正MongoDB.Repository框架对多数据库的支持. 在之前的五篇文章中对MongoDB.Repository框架做了简单的介绍是实现思路.之前是考虑MongoDB.Repos ...

  5. django restul webservice返回json数据

    做这个demo的前提是你已经配好了python ,django ,djangorestframwork(在我的上一篇博客中有介绍,大家也可以google),mysql-python等. djangor ...

  6. IOS开发之路二十一(UIWebView加载本地html)

    挺简单不多说的直接代码: // // ViewController.h // JSAndJson // // Created by WildCat on 13-9-8. // Copyright (c ...

  7. 3分钟教你做一个iphone手机浏览器

    3分钟教你做一个iphone手机浏览器 第一步:新建一个Single View工程: 第二步:新建好工程,关闭arc. 第三步:拖放一个Text Field 一个UIButton 和一个 UIWebV ...

  8. iOS 动画类型 笔记

    #pragma mark Core Animation - (IBAction)buttonPressed1:(id)sender { UIButton *button = (UIButton *)s ...

  9. jQuery实现table隔行换色和鼠标经过变色

    一.隔行换色 $("tr:odd").css("background-color","#eeeeee"); $("tr:even& ...

  10. HashTable类模板_C++

    好久没看数据结构了,今天终于要用到hash,整理一下写了个hash类模板 template<typename T> class DataType { public: T key; Data ...