×
单片机 > 单片机程序设计 > 详情

【ARM裸板】Nand Flash编程

发布时间:2020-08-21 发布时间:
|

1.读芯片ID

1.1 读芯片ID时序

id_info[i] = nand_read_data();

   }

   nand_disable_cs();//禁止CS

   

   printf("Maker  Code: 0x%xrn",id_info[0]);

   printf("Device Code: 0x%xrn",id_info[1]);

   printf("3rd   cycle: 0x%xnr",id_info[2]);

   printf("Page   size: %d KBnr",1  << (id_info[3] & 0x03));//页大小与id_info[3]最低2位有关

   printf("Block  size: %d KBnr",64 << ((id_info[3] >> 4) & 0x03));//块大小与id_info[3]第4、5位有关


   printf("5th   cycle: 0x%xnr",id_info[4]);


1.2 由ID数据获得芯片参数

int col  = addr % 2048;//列地址  addr &(2048-1); 


int page = addr / 2048;//行地址(相当于页地址)


2.5 NAND等待就绪

while(!(NFSTAT & 0x01));//当NFSATA[0] = 1时,表示就绪

}


2.6 读取数据函数

/* NAND FLASH读取数据

 * param:读取的地址、存放的地址、读取的长度

 */

void read_nand_data(unsigned int addr,unsigned char *buf,unsigned int len)

{

int i = 0;


/*page是定位到哪一个页,col变量定位的就是在这个

*页的偏移量(在这个页上的第几列0~2047)

*/

int col  = addr % 2048;//列地址  addr &(2048-1); 


    /* 因为读取数据的时候是一次性读出一页,因此当给出

* 地址addr之后,每一页的数据大小是2K,因此我们可以

* 根据地址知道我们读取的数据是哪一个页

*/

int page = addr / 2048;//行地址(相当于页地址)


nand_enable_cs();//1.使能CS


while(i < len){

nand_write_cmd(0x00);       //2.发出0x00命令


/* col addr */

nand_write_addr(col & 0xFF);//3.发出地址

nand_write_addr((col >> 8) & 0xFF);  


  /* row/page addr */

    nand_write_addr(page & 0xFF);

    nand_write_addr((page >>  8) & 0xFF);

nand_write_addr((page >> 16) & 0xFF);


nand_write_cmd(0x30);//4.发出0x30命令


        nand_wait_ready(); //5.等待就绪

        /* for循环中有2个条件

         * 1.当读到页尾,但还是没有读完,说明需要读取下一页

         * 2.当已经读取指定字节数,则不再读取

         */     

        for(; (col < 2048) && (i < len); col++){//6.读数据

        buf[i++] = nand_read_data_byte();

        }

        if(i == len){

        break;

        }

        col = 0;

        page++;//指向下一页

}

nand_disable_cs(); //7.禁止CS

}


2.7 NAND重定位

从Nand Flash启动,此时片内SRAM的地址对应的就是CPU的0地址,如果从Nand Flash启动,2440硬件会把nand Flash前4K的数据复制到片内SRAM,如果Nand Flash上的程序大于4K,那后续数据就会丢失,相当于只重定位了前4K的代码。


如何解决上述问题:


1.前提:实现了NAND FLASH读取数据函数

2.代码烧写到NAND FLASH,并从NAND中启动

3.程序运行到重定位代码的位置判断一下,是从Nand Flash启动还是NOR Flash启动(通过往0地址写数据,因为Nand是支持读写的,所以读出的结果和写的结果一样,而NOR Flash不能像内存一样读写,因此读写的内容是不一致的)

4.如果从NOR Flash启动,直接使用简单的重定位代码就行,如果是Nand Flash启动,那就是用Nnad Flash的读函数进行代码的重定位。

首先判断从NorFlash or NandFlash中启动


/* 检查是否从NorFlash中启动

 * 方法:写0x12345678到0地址,在读取出来,如果得到0x12345678,表示0地址上的内容被修改,即为片内RAM,则为nand启动

 * 原因:原因:nor不能直接写入,写入需要发出一定格式的数据,才能写入

 * 返回0为nand启动,返回1为nor启动

*/

int isBootFromNorFlash(void)

{

volatile unsigned int *p = (volatile unsigned int *)0;

unsigned int val = *p;//暂存[0]上的数据

*p = 0xdeadc0de;//dead code任意值

if(0xdeadc0de == *p){

/* 写成功,对应nand启动 */

*p = val;//恢复原来的值

return 0;

}

else{

return 1;

}

}


重定位代码


/*

 * 将除bss段的全部数据拷贝到sdram中

 * 传递形参,原地址src:_start  目标地址dest:__bss_start  长度len:__bss_start-_star

 */

void copy_to_sdram(void)

{

/* 要从lds文件中获取__code_start、__bss_start

* 然后从0地址把数据复制到__code_start

*/

extern int __code_start,__bss_start; //声明外部变量


volatile unsigned int *src  = (volatile unsigned int *)0; //flash中0地址 

volatile unsigned int *dest = (volatile unsigned int *)&__code_start; //目标地址:sdram中的0x30000000地址

volatile unsigned int *end  = (volatile unsigned int *)&__bss_start;  //结束地址:bss的起始地址


int len = (int)&__bss_start - (int)&__code_start;//获取数据总长度


if(isBootFromNorFlash()){//如果从Nor中启动

while(dest < end){

*dest++ = *src++; //拷贝

}

}

else{//从Nand中启动,需要先初始化nand,然后重定位代码

nand_init();

        //从 src 复制到 des ,总共复制len字节,也就是重定位的代码

read_nand_data((unsigned int)src,(unsigned char *)dest,len);

}

}


2.7 读数据测试

读取0地址后160bytes的数据,如果跟.bin文件前160字节数据相同,则读取成功,否则读取失败


/* 测试函数:读数nand上160bytes数据 

 */

void read_nand_flash(void)

{

int i,j;

unsigned int addr,hex_addr;

unsigned char c,str[16],data[160];

volatile unsigned char *p;


/* 获得地址 */

printf("*****Enter the address to read:");

addr = get_uint();


read_nand_data(addr,data,160);//获取到地址上的数据

p = (volatile unsigned char *)data;//p指向data,用于打印data数据


hex_addr = addr;//起始地址

printf("Read Data:rn");

printf("            00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0fnr");

  /* 长度固定为160 bytes */

for(i = 0; i < 10; i++){

printf("0x%08x  ",hex_addr);

//每行打印16个16进制数

for(j = 0; j < 16; j++){

c = *p++;//读取16个

str[j] = c;//保存字符

//先打印数值

printf("%02x ",c);

}

printf(" | ");

//后打印字符

for(j = 0; j < 16; j++){

if(str[j] < 0x20 || str[j] > 0x7e){//不可视字符,打印‘.’

printf(".");

}

else{

printf("%c",str[j]);

}

}

hex_addr+=16;//换行+16

printf("nr");

}


}

/* 检查参数合法性 */

if(addr & (0x1FFFF)){ //128K

printf("Err addr! Please enter an integral multiple of 128Krn");

return -1;

}

if(len & (0x1FFFF)){ //128K

printf("Err len! Please enter an integral multiple of 128Krn");

return -1;

}


3.3 擦除函数

/* NAND FLASH擦除数据

* param:擦除


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
单片机制作超级流水灯