Tiny6410之NAND FLASH驱动
一、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驱动的更多相关文章
- Smart210学习记录----nand flash驱动
[详解]如何编写Linux下Nand Flash驱动 :http://www.cnblogs.com/linux-rookie/articles/3016990.html 当读写文件请求到来的时候, ...
- Nand Flash驱动(实现初始化以及读操作)
简单制作一个Nand Flash驱动(只需要初始化Flash以及读Flash) 打开2440芯片手册,K9F2G08U0M芯片手册(因为2440中Nand Flash是用的256MB(2Gb)内存,8 ...
- linux2.6.30.4内核移植(2)——Nand Flash驱动移植
内核源码:linux2.6.30.4 交叉编译工具:3.4.5 移植linux内核至:TQ2440 工作基础:http://www.cnblogs.com/nufangrensheng/p/36696 ...
- linux下Pl353 NAND Flash驱动分析
linux的NAND Flash驱动位于drivers/mtd/nand子文件夹下: nand_base.c-->定义通用的nand flash基本操作函数,如读写page,可自己重写这些函数 ...
- NAND FLASH 驱动分析
NAND FLASH是一个存储芯片 那么: 这样的操作很合理"读地址A的数据,把数据B写到地址A" 问1. 原理图上NAND FLASH和S3C2440之间只有数据线, ...
- 如何编写linux下nand flash驱动-2
[Nand Flash引脚(Pin)的说明] 图3.Nand Flash引脚功能说明 上图是常见的Nand Flash所拥有的引脚(Pin)所对应的功能,简单翻译如下: 1. I/O0 ~ ...
- 如何编写linux下nand flash驱动-4
2. 软件方面 如果想要在Linux下编写Nand Flash驱动,那么就先要搞清楚Linux下,关于此部分的整个框架.弄明白,系统是如何管理你的nand flash的,以及,系统都帮你做 ...
- 15.1 linux操作系统下nand flash驱动框架2
当我们需要在操作系统上读写普通文件的时候,总是需要一层层往下,最终到达硬件相关操作,当然底层设备大多数都是块设备 NAND FLASH就作为一个最底层的块设备. 而写驱动,就是要构建硬件与操作系统之间 ...
- 十八、Nand Flash驱动和Nor Flash驱动
在读者学习本章之前,最好了解Nand Flash读写过程和操作,可以参考:Nand Flash裸机操作. 一开始想在本章写eMMC框架和设备驱动,但是没有找到关于eMMC设备驱动具体写法,所以本章仍继 ...
随机推荐
- 用户故事(User Story)
用户故事(User Story) 用户故事是描述对用户有价值的功能,好的用户故事应该包括角色.功能和商业价值三个要素.用户故事通常的格式为:作为一个<角色>, 我想要<功 ...
- 【ios开发】自定义Actionsheet实现时间选择器和省市区选择器
最近的工程有一个个人资料页面,需要填写生日和地区的信息,需要自己定义个actionsheet. 但是到网上搜了一下都不太合适,只好自己研究研究,重写了一个.共享出来给大家用用,突然发现自己精神很高尚吗 ...
- Bug Tracker
Bug Tracker 使用笔记(有图有真相) 目的:管理Bug,完善业务流程. 前提条件:BugTracker是基于IIS和SQL Server和Asp.Net的.相当于一个Web端的管理系统. ...
- 大IT公司笔试
都是一些非常非常基础的题,是我最近参加各大IT公司笔试后靠记忆记下来的,经过整理献给与我一样参加各大IT校园招聘的同学们,纯考Java基础功底,老手们就不用进来了,免得笑话我们这些未出校门的孩纸们,但 ...
- [RM 状态机详解3]RMContainer状态机详解
摘要 RMContainer是RM内部维护的Container状态.事实上,在RM的调度器中,会维护着一个liveContainers列表,保存着所有存活着的Container信息.图1显示RMCon ...
- springmvc国际化 基于请求的国际化配置
springmvc国际化 基于请求的国际化配置 基于请求的国际化配置是指,在当前请求内,国际化配置生效,否则自动以浏览器为主. 项目结构图: 说明:properties文件中为国际化资源文件.格式相关 ...
- 分布式搜索ElasticSearch构建集群与简单搜索实例应用
分布式搜索ElasticSearch构建集群与简单搜索实例应用 关于ElasticSearch不介绍了,直接说应用. 分布式ElasticSearch集群构建的方法. 1.通过在程序中创建一个嵌入es ...
- mov sreg, r/m16 在16位和32位编程中的区别
总结于<X86汇编语言 从实模式到保护模式> 仅适用于X86系列处理器 1. 两者的区别: 例:mov ds, ax A.在指定16位编译模式下,产生的二进制码是 8E D8 B.在指定3 ...
- S2SH整合
Struts2.Spring.Hibernate三大框架在一个项目中的具体职责分配如下: 三大框架整合,导入各个框架和整合所需的包(本项目采用的是Struts2.3+spring3.0+hiberna ...
- 根据Mob官网的天气预报接口写了一个简单的demo
第一步 自己注册一个应用,然后获取里面的 App Key,下载MobAPI SDK 然后拖入 MobAPI.framework 和 MOBFoundation.framework 到你的项目中 第二步 ...