NFSTAT寄存器 的RnB的bit4

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页 


… 
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);
       }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值