Nand flash code
(1)流水灯
1>我们来看原理图
2>datasheet
3>leds.c
#define GPFCON (*(volatile unsigned long *)0x56000050) //address
#define GPFDAT (*(volatile unsigned long *)0x56000054)
#define GPF4_reset (3<<(4*2))
#define GPF5_reset (3<<(5*2))
#define GPF6_reset (3<<(6*2)) //reset
#define GPF4_out (1<<(4*2))
#define GPF5_out (1<<(5*2))
#define GPF6_out (1<<(6*2))//output
void Delay_ms(volatile unsigned long ms);
int main(void)
{
GPFCON &=~(GPF4_reset | GPF5_reset | GPF6_reset);
GPFCON |= (GPF4_out | GPF5_out | GPF6_out);
while(1)
{
GPFDAT &=~(1<<4);
Delay_ms(30000);
GPFDAT |=(1<<4);//led1
GPFDAT &=~(1<<5);
Delay_ms(30000);
GPFDAT |=(1<<5);//led2
GPFDAT &=~(1<<6);
Delay_ms(30000);
GPFDAT |=(1<<6);//led3
}
return 0;
}
void Delay_ms(volatile unsigned long ms)
{
for(; ms>0; ms--);
}
(2)由于我们的程序所占用的空间会出现大于s3c2440的cpu的sram的空间,所以内存无法满足我们的需求,就需要在片外内存中进行运行。这里通过一个链接脚本将一部分程序放在nand flash的前4k的地方,将另一部分放在nand flash 的4k以后,这样的话,我们将nand flash的4K以后的程序拷贝到sram中进行运行就可以的。
在开发板在nand flash模式下启动,开发板只能将前4K的程序拷贝到sram中运行。
链接脚本:nand.lds
SECTION{
first 0x00000000 : {nand.o init.o crt.o}
second 0x30000000 : AT(4096) {leds.o}
}
(3) nand.c
#define LANGE_PAGE
typedef unsigned int uint32;
//s3c2440控制寄存器
typedef struct{
uint32 NFCONF; //nand flash 配置寄存器
uint32 NFCONT; //nand flash 控制寄存器(s3c2410没有此寄存器)
uint32 NFCMMD; //nand flash 命令寄存器
uint32 NFADDR; //nand flash 地址寄存器
uint32 NFDATA; //nand flash 数据寄存器
uint32 NFMECCD0;
uint32 NFMECCD1;
uint32 NFSECCD;
uint32 NFSTAT; //状态寄存器
uint32 NFESTAT0;
uint32 NFESTAT1;
uint32 NFMECC0;
uint32 NFMECC1;
uint32 NFSECC;
uint32 NFSBLK;
uint32 NFEBLK;
}s3c2440_NAND;
//s3c2410寄存器
typedef struct{
uint32 NFCONF;
uint32 NFCMD:
uint32 NFADDR;
uint32 NFDATA;
uint32 NFSTAT;
uint32 NFECC;
}s3c2410_NAND;
typedef struct{
void (*nand_reset)(void); //复位
void (*nand_select_chip)(void);//片选信号
void (*write_cmd)(unsigned int cmd); //写命令
void (*nand_wait)(void);
void (*write_addr)(unsigned int addr);//写地址
unsigned char (*read_data)(void);//读地址
void (*nand_deselect_chip)(void);//取消片选信号,节能
}t_nand_chip;
t_nand_chip nand_chip;
s3c2440_NAND * s3c2440_nand =(s3c2440_NAND*)0x4e000000;
s3c2410_NAND * s3c2410_nand =(s3c2410_NAND*)0x4e000000; //NFCONF的地址0x4e000000
void s3c2410_nand_select_chip(void)
{
int i;
s3c2410_nand->NFCONF &=~(1<<11); //nFCE==0片选
for(i=0;i<10.i++); //等待
}
void s3c2410_write_cmd(unsigned int cmd)
{
volatile unsigned char *p =(volatile unsigned char *)s3c2410_nand->NFCMD;
*p=cmd;
}
void s3c2410_nand_wait(void)
{
int i;
volatile unsigned char *p =(volatile unsigned char *)s3c2410_nand->NFSTAT;
while(!(*p & 1)); //是否忙碌 //1--ready 0--busy
for(i=0;i<10;i++);
}
void s3c2410_write_addr(unsigned int addr)
{
int i;
volatile unsigned char *p =(volatile unsigned char *)s3c2410_nand->NFADDR;
*p=addr&0xff; /*A0-A7 */
for(i=0;i<10;i++);
*p=(addr>>9)&0xff;/*A9-A16 */
for(i=0;i<10;i++);
*p=(addr>>17)&0xff; /*A17-A24 */
for(i=0;i<10;i++);
*p=(addr>>25)&0x01; //A25
for(i=0;i<10;i++);
}
unsigned char s3c2410_read_data(void)
{
volatile unsigned char *p =(volatile unsigned char *)s3c2410_nand->NFDATA;
return *p;
}
void s3c2410_nand_deselect_chip(void)
{
s3c2410_nand->NFCONF |=(1<<11);
}
void s3c2410_nand_reset(void)
{
s3c2410_nand_select_chip();
s3c2410_write_cmd(0xff); //针对不同的nand flash 对应的nand falsh所要求nand控制器发出的命令有所不同
s3c2410_nand_wait();
s3c2410_nand_deselect_chip();
}
//s3c2440
void s3c2440_nand_select(void)
{
int i;
s3c2440_nand->NFCONT &=~(1<<1);
for(i=0;i<10;i++);
}
void s3c2440_write_cmd(unsigned int cmd)
{
volatile unsigned char *p =(volatile unsignd char *)s3c2440_nand->NFCMMD;
*p =cmd;
}
void s3c2440_nand_wait(void)
{
int i;
volatile unsignd char *p=(volatile unsigned char *)s3c2440_nand->NFSTAT;
while(!(*p & 1)); //判断是否忙碌
for(i=0;i<10;i++);
}
void s3c2440_write_addr(unsigned int addr)//小页--521byte (K9F1208U0M)
{
int i;
volatile unsigned char *p=(volatile unsigned char *)s3c2440_nand->NFADDR;
*p=addr&0xff; //A0-A7共8根线,可寻址2^8=256byte --半页(通过不同的命令 00h--上半页,01h--下半页)
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)&0x01; //A9-A25 共17根线,可寻址 2^17=2^7k=4(层)*1024(块)*32(页)=2^7k page
for(i=0;i<10;i++);
}
void s3c2440_write_addr_lp(unsigned int addr)//大页--2K(512*4)(K9F2G08x0A)
{
int i;
int col,row;//col分两次,row分三次发送
volatile unsigned char *p = (volatile unsigned char *)s3c2440->NFADDR;
col=addr &(2048-1); //addr & (11111111111)--取低11位
row=addr/2048; //取高位 --(2048==一页的大小)
*p=col &0xff; /* A0-A7*/
for(i=0;i<10;i++);
*p=col & 0x0f; /* A8-A11*/ --A0==A11共12根线,可寻空间2^12=2*2K,而一页是1K,留有余量,A11用来访问spare区域,也就是 for(i=0;i<10;i++); -- oob区域用来存放校验信息, spare区域并不在编址范围内,需要使用A11控制访问
*p=row & 0xff; /* A12-A19*/
for(i=0;i<10;i++);
*p=row & 0xff; /* A20-A27*/
for(i=0;i<10;i++);
*p=row & 0xff; /* A28-A29*/ --A12==A28共17根线,可寻空间2^18=2^8k=2(层)*1024(块)*64(页)=2^7k page,同时留有 --余量,用来兼容大容量flash
}
unsigned char s3c2440_read_data(void)
{
volatile unsigned char *p=(volatile unsigned char *)s3c2440_nand->NFDATA;
return 0;
}
void s3c2440_nand_deselect_chip(void)
{
s3c2440_nand->NFCONT |=(1<<1);
}
void s3c2440_nand_reset(void)
{
s3c2440_nand_select_chip();
s3c2440_write_cmd(0xff);
s3c2440_nand_wait();
s3c2440_nand_deselect_chip();
}
GSTATUS1是芯片的ID,对于不同的芯片有对应的ID,s3c2440的ID是0x32440001,s3c2410的ID是0x32410000或0x32410002
s3c2440的ID:
s3c2410的ID:
//nand初始化
void nand_init(void)
{
#define TACLS 0
#define TWRPH0 3
#define TWRPH1 0
if((GSTATUS1==0x32410000)||(GSTATUS1==0x32410002)) //s3c2410
{
nand_chip.nand_reset =s3c2410_nand_reset;
nand_chip.nand_select_chip =s3c2410_nand_select_chip;
nand_chip.write_cmd =s3c2410_write_cmd;
nand_chip.nand_wait =s3c2410_nand_wait;
nand_chip.write_addr =s3c2410_write_addr;
nand_chip.read_data =s3c2410_read_data;
nand_chip.nand_deselect_chip =s3c2410_nand_deselect_chip;
//使能nand flash控制器
//初始化ECC
//禁止片选信号
//设置时序
s3c2410_nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
}
else //s3c2440
{
nand_chip.nand_select_chip =s3c2440_nand_select_chip;
nand_chip.write_cmd =s3c2440_write_cmd;
nand_chip.nand_wait =s3c2440_nand_wait;
#ifdef LANGE_PAGE
nand_chip.write_addr =s3c2440_write_addr_lp;
#else
nand_chip.write_addr =s3c2440_write_addr;
#endif
nand_chip.read_data =s3c2440_read_data;
nand_chip.nand_deselect_chip =s3c2440_nand_deselect_chip;
//使能nand flash控制器
//初始化ECC
//禁止片选信号nFCE
s3c2440_nand->NFCONT =(1<<4) | (1<<1) | (1<<0);
//设置时序
s3c2440_nand->NFCONF =(TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
}
nand_chip.nand_reset(); //复位nand flash
}
void nand_read(unsigned char *buf, unsigned long start_addr, int size)//读数据
{
int i,j;
//地址或长度对齐
//NAND Flash 每次读操作是以page为单位的,一个page在此是2048byte(不同的NAND Flash的page大小不一定相同),
//因为2047的二进制表示是11个1, 即11111111111, 一个数如果是2048的倍数,低11bit必须是0, 即 ****00000000000
//所以把一个数跟2047按位与就可判断它是不是2048的倍数。
#define LANGE_PAGE
if(strat_addr & (2048-1) || (size & (2048-1))) //大页--2048byte
return;
#else
//512的倍数
if(start_addr & (512-1) || (size & (512-1)) ) //小页--512byte
return;
#endif
//选中芯片
nand_chip.nand_select_chip();
对于小页而言,进行读取数据需要发命令00h/01h;
对于大页而言,进行读取数据需要发命令00h ,30h;
小页:
大页:
for(i=strat_addr;i<(start_addr + size);){
//发出命令
nand_chip.write_cmd(0); //00h
//写地址
nand_chip.write_addr(i);
#ifdef LANGE_PAGE
nand_chip.write_cmd(0x30);
#endif
//等待
nand.chip.nand_wait();
#ifdef LANGE_PAGE
for(j=0;j<2048;j++,i++){
#else
for(j=0;j<512;j++,i++){
#endif
//读数据
*buf=nand_chip.read_data();
buf++;
}
}
//取消片选信号
nand_chip.nand_deselect_chip();
return ;
}
(4)关看门狗和配置存储管理器
init.c
#define WHITCH_DOG (*(volatile unsigned long*)0x53000000)
#define MEM_BASE 0x48000000 //存储管理器寄存器的起始地址
void disable_watch_dog(void)
{
WATCH_DOG = 0;
}
void mem_setup(void)
{
int i=0;
unsigned long *p=(unsigned long *)MEM_BASE;
unsigned long const mem_cfg_val[]={
0x22011110,
0x00000700,
0x00000700,
0x00000700,
0x00000700,
0x00000700,
0x00000700,
0x00018005,
0x00018005,
0x008C07A3,
0x000000B1,
0x00000030,
0x00000030
};
for(i=0;i<13;i++)
{
p[i]=mem_cfg_val[i];
}
}
(5)crt.S
.text
.global _strat
_strat:
ldr sp,=4096
bl disable_watch_dog
bl mem_setup
bl nand_init
ldr r0,=0x30000000 @buf
mov r1,#4096 @strat_addr
mov r2,#2048 @size
bl nand_read
ldr sp,=0x34000000
ldr pc,=main
halt_loop:
b halt_loop
(6)Makefile
objs := crt.o nand.o init.o leds.o
nand.bin :$(objs)
arm-linux-ld -Tnand.dis -o nand_elf $^
arm-linux-objcopy -O binary -S nand_elf $@
arm-linux-objdump -D -m arm nand_elf > nand.dis
%.o :%.c
arm-linux-gcc -Wall -c -O2 -o $@ $<
%.o :%.S
arm-linux-gcc -Wall -c -O2 -o $@ $<
clean:
rm -f nand.dis nand.bin nand_elf *.o
Nand flash code的更多相关文章
- 嵌入式Linux驱动学习之路(二十三)NAND FLASH驱动程序
NAND FLASH是一个存储芯片. 在芯片上的DATA0-DATA7上既能传输数据也能传输地址. 当ALE为高电平时传输的是地址. 当CLE为高电平时传输的是命令. 当ALE和CLE都为低电平时传输 ...
- s3c2440 移值u-boot-2016.03 第2篇 支持Nand flash启动
1, 要求:在4K 的代码以内,完成 NOR NAND 类型判断,初始化 NAND 复制自身到 SDRAM ,重定向. 2, 在 /arch/arm/cpu/arm920t/ 文件夹里 添加一个 in ...
- ECC校验原理以及在Nand Flash中的应用
本篇文章主要介绍ECC基本原理以及在Nand Flash中的应用,本文记录自己对ECC校验原理的理解和学习. ECC介绍 ECC,全称为Error Correcting Code, ...
- WinCE NAND flash - FAL
http://blog.csdn.net/renpine/article/details/4572347 http://msdn.microsoft.com/en-US/library/ee48203 ...
- STM32学习笔记——FSMC 驱动大容量NAND FLASH [复制链接]
本文原创于观海听涛,原作者版权所有,转载请注明出处. 近几天开发项目需要用到STM32驱动NAND FLASH,但由于开发板例程以及固件库是用于小页(512B),我要用到的FLASH为1G bit的大 ...
- Samsung K9F1G08U0D SLC NAND FLASH简介(待整理)
Samsung K9F1G08U0D,数据存储容量为128M,采用块页式存储管理.8个I/O引脚充当数据.地址.命令的复用端口.详细:http://www.linux-mtd.infradead.o ...
- NAND FLASH特性说明
1.NAND FLASH 的特殊性. 1)存在坏块.由于NAND生产工艺的原因,出厂芯片中会随机出现坏块.坏块在出厂时已经被初始化,并在特殊区域中标记为不可用,在使用过程中如果出现坏块,也需要进行标记 ...
- NAND FLASH ECC校验原理与实现
ECC简介 由于NAND Flash的工艺不能保证NAND的Memory Array在其生命周期中保持性能的可靠,因此,在NAND的生产中及使用过程中会产生坏块.为了检测数据的可靠性,在应用NAND ...
- Nand Flash基础知识与坏块管理机制的研究
概述 Flash名称的由来,Flash的擦除操作是以block块为单位的,与此相对应的是其他很多存储设备,是以bit位为最小读取/写入的单位,Flash是一次性地擦除整个块:在发送一个擦除命令后,一次 ...
随机推荐
- EasyUI创建DataGrid及冻结列的两种方式
第一种方式:通过HTML标签创建数据表格控件 <table class="easyui-datagrid" title="基本数据表格" style ...
- libvirt_python
一.Connections 连接函数接口libvirt.open(name); //可读写方式连接上QEMU 参数说明: name:连接名称libvirt.openAuth(uri, auth, fl ...
- 【2017-04-17】类库、通用变量、is和as、委托
类库dll文件,里边有很多被编译后的C#代码,不可阅读,不可修改,只能调用 1.类库创建 新建项目为类库,类库文件编写完成后,选择生成—生成解决方案,在debug文件夹下找到dll文件 2.类库引用 ...
- Qt & VS2013 报错:There's no Qt version assigned to this project for platform Win32
如果你想了解关于Qt与VS2013开发环境搭建,可以至此翻页. 这里主要分享环境已搭建成功,在构建项目时遇到的报错解决方案. [1]Qt 与 VS2013开发环境构建时报错 报错界面如下: 注意:对话 ...
- 74.Java异常处理机制
package testDate; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IO ...
- The Little Prince-12/07
The Little Prince-12/07 "My little man, where do you come from? What is this ‘where I live,‘ of ...
- Spring MVC数据绑定
1.绑定默认数据类型 当前端请求参数较为简单的时候,后台形参可以直接使用SpringMVC提供的参数类型来绑定数据. HttpServletRequest:通过request对象获取请求信息: Htt ...
- ElasticSearch vs Solr多维度分析对比
福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号: 大数据躺过的坑 Java从入门到架构师 人工智能躺过的坑 Java全栈大联盟 ...
- Python3 自定义请求头消息headers
Python3 自定义请求头消息headers 使用python爬虫爬取数据的时候,经常会遇到一些网站的反爬虫措施,一般就是针对于headers中的User-Agent,如果没有对headers进行设 ...
- ora-24550 signo=6 signo=11解决
我们有台测试服务器pro*c/oci应用总是发生各种比较奇葩的现象,就这一台机器会发生,其他几十台都不会发生. sig 11的原因,内存地址访问越界.各signo的si_code含义可参考http:/ ...