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设备驱动具体写法,所以本章仍继 ...
随机推荐
- IOS UI 第八篇:基本UI
实现图片的滚动,并且自动停止在每张图片上 - (void)viewDidLoad{ [super viewDidLoad]; UIScrollView *scrollView = [[U ...
- 网络地址到物理地址的映射(ARP)
网络的互连首先要解决的问题就是网络地址到物理地址的映射,以太网接口分配的是一个48位的物理地址,而IP地址却只有32位,因此无法将它编码到IP地址中.有人建议可以构建一个中央数据库存储所有网络中的网络 ...
- 【IOS开发】SimPholders的使用
推荐一个Xocde开发工具 “SimPholders”,能够快速访问到你的模拟器文件夹,最重要的是完全免费! 官方地址
- Hive中抽取连续多天登录用户
昨天群上有人发个阿里的面试题,题目描述大概如下: 数据源:用户登录表,只有俩个字段,uid和dt 试用HQL抽取出连续登录了K天的用户uid 第一个想法就是直接用一个UDF解决,按uid分组,把dt收 ...
- Bootstrap3.0学习第三轮(栅格系统案例)
Bootstrap3.0学习第三轮(栅格系统案例) 前言 在前面的一篇文章当中http://www.cnblogs.com/aehyok/p/3400499.html主要学习了栅格系统的基本原理,以及 ...
- [转]LLVM MC Project
Intro to the LLVM MC Project The LLVM Machine Code (aka MC) sub-project of LLVM was created to solve ...
- HashTable和HashSet中的类型陷阱
HashTable和HashSet中的类型陷阱 发现这个陷阱的起因是这样的:我现在有上百万字符串,我准备用TopK算法统计出出现次数做多的前100个字符串. 首先我用Hashtable统计出了每个字符 ...
- GitHub创建SSH Keys
第一步:在用户主目录下,看有没有.ssh目录,如果有,再看看这个目录下 有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步,如果没有 打开Git Bash,创建SSH ...
- 转:运行yum报错Error: Cannot retrieve metalink for reposit
http://www.netpc.com.cn/593.html 运行yum报错Error: Cannot retrieve metalink for repository: epel. Please ...
- json-smart 使用示例
json-smart 使用示例 json是一种通用的数据格式.相比与protocal buffer.thrift等数据格式,json具有可读性强(文本).天生具备良好的扩展性(随意增减字段)等优良特点 ...