Nand flash陷阱

来源:互联网 发布:淘宝如何加入全球购 编辑:程序博客网 时间:2024/06/05 11:51

转载:http://blog.csdn.net/girlkoo/article/details/8115849

当系统以Nand方式启动时,硬件将Nand Flash的前8KB拷贝到Steppingstone,然后从0地址开始运行程序,在这8KB以内代码中,我们需要完成必要的硬件初始化,如果代码超过8K,我们还需要将剩余代码的搬移到链接地址处,一般在SDRAM/DDR中。其中,硬件部分需要初始化系统时钟、DDR和NAND Flash三部分。这就是S3C6410以Nand方式启动时的大致流程,看上去跟ARM9(S3C2440)没有差别,但是如果您亲自动手写一下这个启动过程,你会发现ARM9跟ARM11还是存在若干差别的,这里我要说的是Nand裸机驱动的问题。述了S3C6410的Nand方式启动流程,看上去跟ARM9(S3C2440)没有太大差别,但是如果您亲自动手写一下这个启动过程,你会发现ARM9跟ARM11还是存在若干差别的,这里我要说的是Nand裸机驱动的问题。

我的开发板式Tiny6410,配置的Nand flash是K9GAG08U0E,块空间1M,页空间8K。于是可以实现nand_read函数:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. int nand_read(unsigned int nand_start, unsigned int ddr_start, unsigned int len)  
  2. {  
  3.     unsigned long rest = len;  
  4.     unsigned long addr = nand_start;  
  5.     unsigned long page;  
  6.     unsigned char *dest = (unsigned char *)ddr_start;  
  7.     int i;  
  8.   
  9.     nand_select();  
  10.     while(rest > 0){  
  11.         nand_cmd(0x00);  
  12.         nand_addr(addr);  
  13.         nand_cmd(0x30);  
  14.         nand_ready();  
  15.   
  16.         page = rest>PAGE_SIZE?PAGE_SIZE:rest;  
  17.         for(i = 0; i != page; ++i){  
  18.             *dest++ = NFDATA;  
  19.         }  
  20.         rest -= page;  
  21.         addr += page;  
  22.     }  
  23.     nand_deselect();  
  24.   
  25.     return 0;  
  26. }  

如上,我们可以完成必要的硬件初始化后用nand_read(0, 0x50000000, __bss_start-_start)来将完整的代码从Nand搬移到DDR中,开始我也是这样想的,但是发现代码根本无法运行,后来调试了一下发现,这样只将代码的前2K拷贝到DDR中,接下来的6K代码丢失了,而再接下来的代码是正确的!这很奇怪啊,手册中明却指出,该Nand的页大小为8KB,但为何我实际读取时却只能读取到2KB呢?原来S3C6410启动时拷贝的8K代码不是存储在Nand flash的第一页上,而是存储在Nand flash的前4页上,每页2K,总共8K,这是S3C6410芯片的硬件结构决定的!也就是说,虽然我们的Nand flash的页大小是8K,但是S3C6410为了适应各种型号的Nand flash并保证硬件能正确的拷贝Nand flash中的前8K到SRAM中,硬性的加上这一规定。因此,nand2ddr函数应该这样写:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. void copy2ddr(unsigned long length){  
  2.     unsigned long rest = length;  
  3.     unsigned long size;  
  4.     unsigned long i;  
  5.   
  6.     for(i = 0; i != 4; ++i){  
  7.         size = rest>2048?2048:rest;  
  8.         nand_read(PAGE_SIZE*i, 0x50000000+i*2048, size);  
  9.         rest -= size;  
  10.         if(rest == 0)  
  11.             return;  
  12.     }  
  13.   
  14.     nand_read(PAGE_SIZE*4, 0x50000000+PAGE_SIZE, rest);  
  15. }  

对应还有写操作,原理一样,逆着写回去,这里就不分析原理了,nand_write函数:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. void nand_write(unsigned int nand_start, unsigned char * buf, unsigned int len)  
  2. {  
  3.     unsigned long count = 0;  
  4.     unsigned long addr  = nand_start;  
  5.     int i = nand_start % PAGE_SIZE;  
  6.   
  7.     nand_select();  
  8.     while (count < len)  
  9.     {  
  10.         nand_cmd(0x80);  
  11.         nand_addr(addr);  
  12.         for (; i < PAGE_SIZE && count < len; i++)  
  13.         {  
  14.             NFDATA = buf[count++];  
  15.             addr++;  
  16.         }  
  17.         nand_cmd(0x10);  
  18.         nand_ready();  
  19.         i = 0;  
  20.     }  
  21.     nand_deselect();  
  22. }  

store2nand函数应该这样写:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. void store2nand(unsigned long ddr_start, unsigned long length){  
  2.     unsigned char* src = (unsigned char*)ddr_start;  
  3.     unsigned long rest = length;  
  4.     unsigned long size;  
  5.     unsigned long i;  
  6.   
  7.     for(i = 0; i != 4; ++i){  
  8.         size = rest>2048?2048:rest;  
  9.         nand_write(PAGE_SIZE*i, src+2048*i, size);  
  10.         rest -= size;  
  11.         if(rest == 0)  
  12.             return;  
  13.     }  
  14.   
  15.     nand_write(PAGE_SIZE*4, src+2048*4, rest);  
  16. }  

store2nand函数可以用来下载程序时写nand用,如果不按照这种方式将程序写入nand,硬件就无法正确加载Nand flash的前8K代码,程序也就无法正常运行。

下面是我自己写的Tiny6410裸机程序,arm-linux-gcc环境,如果需要可以下载了看看,代码实现了系统时钟、DDR、Nand flash还有串口的初始化,下面是链接地址,以后还会继续完善:

下载地址:(前段时间忘了改了)

http://download.csdn.net/detail/girlkoo/4690705

0 0
原创粉丝点击