NFSTAT寄存器
当RnB信号由低电平跳变成高电平时,该bit位会被自动置1(硬件完成),表示Flash可以读,读NFDATA寄存器;
但是,此信号何时变为低电平?手动操作该bit位,使其清0。
有点特殊的是,如果将该bit清0,要向该bit写1.
此方法与以往有区别:
写 0 ,清0
写 1,置1
而该bit位:
写1,清0
自动,置1
案例:读Nand flash的第0页的主数据
2048+64 bytes
u-boot.bin
nand_page.h
#define __NAND_H__
#define __NAND_H__
//定义寄存器
#define NFCONF (*((volatile unsigned int*)0xBOE00000));
#define NFCONT (*((volatile unsigned int*)0xBOE00004));
#define NFCMMD (*((volatile unsigned int*)0xBOE00008));
#define NFADDR (*((volatile unsigned int*)0xBOE0000C));
#define NFDATA (*((volatile unsigned int*)0xBOE00010));
#define NFSTAT (*((volatile unsigned int*)0xBOE00028));
//声明函数原型
extern void nand_init(void);
extern void nand_read_id(void);
//buf:保存读取页数据的首地址
//page:表示要读的页号
extern void nand_page_read(unsigned int *buf,unsigned int page);
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
nand_page.c
#include "nand.h"
#include "uart.h"
#include "itoa.h"
void nand_init(void)
{
//nand flash 控制器使用的管脚配置,
//因为我们使用的nand flash启动方式,所以关于GPIO管脚功能配置可以不做
//如果使用的不是nand flash启动,将需要配置
NFCONF = (0xF<<12) | (0xF<<8) |(0xF<<4) | (1<<1);
NFCONT = (3<<12) | (3<<8) | 7;
}
void nand_read_id(void)
{
//1,nand falsh片选信号拉低,使能nand falsh芯片
//操作 NFCONT bit[1] = 0;
NFCONT &= ~(1<<1);// 1<<1 ==> 10
//2,向NFCMMD寄存器写入0x90
NFCMMD = 0x90;
//3,向NFADDR寄存器写入0x0
NFADDR = 0x0;
//4,延时
int i;
for(i = 0;i < 256; i++)
{
;
}
//5,读NFDATA 寄存器(字)ID
//读5个字节的ID号
unsigned int id1;
unsigned int id2;
id1 = NFDATA;
id2 = (NFDATA & 0xFF);//只要低八位
//6,Nand flash片选信号拉高
//操作 NFCONT bit[1] = 1;
NFCONT |= (1<<1) ;
//7,显示读出来的nand flash的ID号
char buf[16];
uart0_puts("\n ID1 = ");
itoa(buf,id1);//转换(整型无法直接打印,打印前转换成字符串)
uart0_puts(buf);//输出
uart0_puts("\n ID2 = ");
itoa(buf2,id2);//转换
uart0_puts(buf2);//输出
}
void nand_page_read(unsigned int *buf,unsigned int page)
{
//1.Nand Flash 片选信号拉低
NFCON &= ~(1<<1);
//2。发送第一次读命令 0x0
NFCMD = 0x0;
//3,发送页内地址,分两个周期
//由于读一页,给该页第0个
//字节的页内地址,即0
NFADDR = 0x0;
NFADDR = 0x0;
//4,发送页号,分三个周期
NFADDR = (page & 0xFF);//低8bit
//bit[15:8]
NFADDR = ((page >> 8) & 0xFF);//中间的8 bit
//bit[18:16]
NFADDR = ((page >> 16) & 0xFF);
//5,发送第二次读命令 0x30
NFCMMD = 0x30
//6,清除标志NFSTAT 写1清bit[4]
NFSTAT |= (1<<4);
//7,等待NFSTAT bit[4]自动置 1
while(!(NFSTAT & (1<<4)))
{
;
}
//8,读取数据(2048)NFDATA
//以字读NFDATA
int i;
for(i=0;i<512;i++)//512*4 = 2048
{
buf[i] = NFDATA;
}
//9, nand flash片选信号拉高
NFCONT |= (1<<1) ;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
cmd.c
#include "cmd.h"
#include "led.h"
#include "nand.h"
#include "nand_page.h"
void cmd_ledon(void)
{
//调用开灯函数
led_on();
}
void cmd_nid(void)
{
//调用读nand flash Id函数
nand_read_id();
}
void cmd_ledoff(void)
{
//调用关灯函数
led_off();
}
static unsinged int test_buf[512];
void cmd_read(void)
{
char itoa_buf[16];
uart0_puts("\n nand read...");
nand_page_read(test_buf,0);
}
void cmd_boot_linux(void)
{
//后面实现
}
const cmd_t cmd_tb1[] =
{
{"ledon",cmd_ledon},
{"ledoff",cmd_ledoff},
{"nid",cmd_nid},
{"nread",cmd_read},
{"bootlinux",cmd_boot_linux},//启动内核的命令,后面会用到
};
int cmd_tab1_num = sizeof(cmd_tb1)/sizeof(cmd_tb1[0]);
cmd_t *find_cmd(const char *name)
{
for(int i=0;i<cmd_tab1_num;i++)
{
if(name == cmd_tb1[i].name)
{
return cmd_tb1[i];
}
}
return NULL;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
案例:如何把linux内核读到内存中?
启动TAPD ,烧写Image
tarena# tftp 0x20008000 Image
tarena#nand erase 0x600000 0xC00000 #从6MB的位置开始,擦除12MB
tarena#nand write 0x20008000 0x600000 0xC00000
cmd.c中的cmd_boot_linux函数实现如下:
typedef void (*func_t)(int r0,int r1,int r2);//函数指针,无返回值,三个整型参数
void cmd_boot_linux(void)
{
//1,从nand falsh的0x600000读取内核Image到内存的
//0x20008000,大小0xC00000
uart0_puts("\n Loading kerenl");
unsigned int *ptr = (unsigned int *)0x200080000
//求起始页 6MB(0x600000)
//每一页2048字节大小
unsigned int page = 0x600000/2048;
int i;
for(i=0;i<0xC00000/2048;i++)
{
uart0_putc('.');
nand_page_read(ptr,page);
page++;//读下页
ptr += 2048/4;//读过来的起始地址
}
uart0_puts("\n Run linux...");
//2,调用内存0x20008000处的Image(内核)
func_t = kernel_start;
kernel_start = (func_t)0x20008000;//把这个地址强制转换为一个函数的地址,为了后面执行这个函数
kernel_start(0,2456,0);//这里与移植有关,先忽略
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
链接脚本 shell.lds
//1,告诉链接器如何组织可执行文件
//2,描述了程序在内存中执行时的大致内存布局,注意各个段的顺序
SECTIONS
{
.= 0x23000000;
.text:
{
main.o(.text);
*.o(.text);
}
.rodata:
{
*.o(.rodata);
}
. = ALIGN(4);//4字节对齐
.data://数据段
{
*.o(.data);
}
.=ALIGN(4);
__bss__start = .;
.bss :
{
.o(.bss);
}
__end =.;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
将makefile文件中的”-Ttext 0x20008000” 修改为”-T shell.lds”即可,链接过程就会按照链接脚本的方式往下执行。
坏块处理
坏块判断原则:
Nand falsh 8192块
1块=64页
main区:
spare区:
0块
0页
1
2
…
63
读第0页,第2048个字节(spare区第一个字节),
如果不是0xFF,那就是一个坏块,
如果是0xFF,读第一页,第2048个宽限(spare区第一个字节)
如果是0xFF,好块
如果不是0xFF,坏块
好块:
第0页,2048,0xFF
第1页,2048,0xFF
坏块:
1)第0页,2048,不是0xFF
2)第0页,2048,0xFF
第1页,2048,不是0xFF
1块
第64页(绝对页号)
第65页(绝对页号)
2块
第128页
第129页
3块
192页
193页
在nandread.h中增加
//读page的len个字节到buf
extern void nand_page_oob(char *buf,int len,unsigned int page);
//判断是否坏块
extern int nand_blk_check(unsigned int page_no);
- 1
- 2
- 3
- 4
- 5
在对应的.c文件中
//读page的len个字节到buf
extern void nand_page_oob(char *buf,int len,unsigned int page)
{
//1,Nand flash 的片选信号拉低
NFCONT &= ~(1<<1);
//2,发送读命令 1: 0x0
NFCMMD = 0x0;
//3,发送页内地址,2次,2048
NFADDR = 0x0;
NFADDR = 0x8;
//4,发送页号地址,3次
NFADDR = (page & 0xFF);
NFADDR = (page >>8) & 0xFF);
NFADDR = (page >>16) & 0xFF);
//5,发送读命令 2:0x30
NFADDR = 0x30;
//6,清等待标志,清NFSTAT bit[4],写1清0
//7,等待NFSTAT bit[4]跳变成1
//8,读取一个字节的坏块标志
//由于是读一个字节,
int i;
for(i=0;i<len;i++)
{
// buf[] = ;
}
//9,nand flash片选信号拉高
NFCONT |=(1<<1);
}
//判断是否坏块
extern int nand_blk_check(unsigned int page_no)
{
unsigned char flag;
nand_page_read_oob(&flag,1,page_no);
if(flag != 0xFF){
return 1;//坏块
}
nand_page_read_oob(&flag,1,page_no++);
if(flag != 0xFF){
return 1;//坏块
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
cmd.c增加命令nbad
void cmd_nandbad(void)
{
int i;
char ibuf[16];
for(i=0;i<;i++)//循环一次判断一块
{
if(nand_blk_check(i)) //页号是每块的起始页号
{
uart0_puts("\n Bad B lock:");
itoa(ibuf,i);//将i转成字符
uart0_puts(ibuf);
}
}
}