Chinaunix首页 | 论坛 | 博客
  • 博客访问: 707924
  • 博文数量: 255
  • 博客积分: 5000
  • 博客等级: 大校
  • 技术积分: 2811
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-09 13:29
个人简介

IT业行者,行者无疆

文章分类

全部博文(255)

文章存档

2011年(121)

2010年(134)

我的朋友

分类: 嵌入式

2010-10-22 18:20:28

s3c2440的nandflash启动 
 
       上文介绍了s3c2440对nandflash的基本操作,其中提到了s3c2440具有nandflash自启动的功能,本文就详细介绍该功能的实现方法。
 
       nandflash由于其自身的特点,不具备运行程序的功能。但s3c2440通过称为“Steppingstone”的内部SRAM缓存,实现了可以运行存储在外部nandflash中的启动代码的功能。它的机制是:当检测到是由nandflash启动时,系统会自动把nandflash中的前4k字节的数据加载到Steppingstone中,然后把该Steppingstone映射为Bank0,因此系统会从Steppingstone开始运行程序,从而实现了s3c2440的nandflash自启动的功能。这一过程是由系统自动完成的,无需人为干预。在系统启动以后,Steppingstone所在的SRAM就可以用作其他用途了。
 
但有人可能会问,如果我的程序很大,超过了4k字节,那是不是就不能利用s3c2440的这个功能了呀?因为Steppingstone只有4k字节大小,也就是程序运行的最大长度只能为4k字节,4k字节以外的内容就运行不到了。这个疑问的答案当然是否定的。我们可以通过在Steppingstone中,把程序的其余部分复制到RAM中,程序运行时由Steppingstone转移到该RAM中,从而就解决了上述难题。一般来说,在启动代码的前4k字节里,要完成s3c2440的核心配置,而把启动代码的剩余部分搬到RAM中运行。
 
       下面我们就介绍一下如何实现上述的功能。
 
       在本博客的第一篇文章中,我们介绍了s3c2440的启动代码,其中有下面这段代码:
 
……   ……
;下面的代码为把ROM中的数据复制到RAM中
ldr   r0, =BWSCON
ldr   r0, [r0]
ands   r0, r0, #6          ;读取OM[1:0]引脚状态
;为0表示从NAND Flash启动,不为0则从NOR Flash启动
bne copy_proc_beg        ;跳转,不用读取NAND Flash
adr  r0, ResetEntry       ;OM[1:0] == 0,从NAND Flash启动
cmp   r0, #0               ;if use Multi-ice,
bne  copy_proc_beg     ;do not read nand flash for boot
;nop
;===========================================================
nand_boot_beg
[{TRUE}
bl   RdNF2SDRAM     ;复制NAND Flash到SDRAM
]
ldr   pc,  =copy_proc_beg
;===========================================================
copy_proc_beg
adr  r0,  ResetEntry
……   ……
 
上面这段代码是nandflash自启动的关键所在,我们在这里再详细讲解一下。前三条语句用于读取寄存器BWSCON的第1位和第2位,当这两位都为0时,表示的是nandflash启动,否则为norflash启动。如果不为0,则跳到copy_proc_beg处开始执行。如果为0,则继续执行下面三条语句:
adr  r0, ResetEntry
cmp   r0, #0
bne  copy_proc_beg
这三条语句的作用是判断当前是否是在仿真的情况下运行的程序。如果是在仿真的情况下,则跳到copy_proc_beg处开始执行,否则开始执行nand_boot_beg处的语句。RdNF2SDRAM是由C语言所撰写的一段程序,它完成了上面我们介绍的把nandflash中的程序复制到SRAM中的功能。我们再来整理一下什么时候执行RdNF2SDRAM程序:必须具备两个条件,一为由nandflash启动,二为不是在仿真的情况下,只有这两个条件都满足时才开始复制nandflash程序。ldr  pc,  = copy_proc_beg语句这段程序的重点,这时候我们已经把所有的程序都复制到了SRAM中了,而在执行这条语句之前(包括这条语句)程序都是在Steppingstone中运行,那么接下来的程序是继续在Steppingstone中运行呢,还是在我们刚刚复制完程序的SRAM中运行呢?当然是在SRAM中运行!这样才能避免我们上面所提到的程序大于4k字节时遇到的问题。而如何从Steppingstone跳到SRAM呢?靠得就是这条语句——ldr  pc,  = copy_proc_beg,它把copy_proc_beg的绝对地址赋予pc,由于程序已经复制到了SRAM中,copy_proc_beg的绝对地址是在SRAM范围内,所以从这句代码以后,程序就开始到SRAM中执行了。在这句话之前的程序大小,我们是要控制在4k字节以内的,而这句代码以后,程序再大,也都会正常运行下去的。
 
       RdNF2SDRAM是C语言编写的一段把nandflash中的数据复制到SRAM的程序。在以前本博客所撰写的所有程序中,我们都没有用到该程序,所以为了编译成功,我们把有关RdNF2SDRAM的地方都注释掉了。现在我们再把这些注释去掉,在C文件中编写RdNF2SDRAM程序。相信大家有了上一篇文章的基础,编写这个程序应该不难的。这里,我就把完整的程序列写出来,以后如果要在nandflash中运行程序,只需把这段程序复制到自己的程序中即可。另外这个程序只针对K9F2G08U0A,如果要使用其他nandflash,还需要做些改动。
 
//nandflash程序
#define rGPACON    (*(volatile unsigned *)0x56000000)      //Port A control
 
#define rNFCONF         (*(volatile unsigned *)0x4E000000)     //NAND Flash configuration
#define rNFCONT         (*(volatile unsigned *)0x4E000004)     //NAND Flash control
#define rNFCMD          (*(volatile unsigned *)0x4E000008)     //NAND Flash command
#define rNFADDR        (*(volatile unsigned *)0x4E00000C)    //NAND Flash address
#define rNFDATA8       (*(volatile unsigned char *)0x4E000010)     //NAND Flash data
#define rNFSTAT          (*(volatile unsigned *)0x4E000020)     //NAND Flash operation status
 
#define NF_CMD(data)               {rNFCMD  = (data); }
#define NF_ADDR(addr)             {rNFADDR = (addr); } 
#define NF_nFCE_L()                 {rNFCONT &= ~(1<<1); }
#define NF_nFCE_H()                {rNFCONT |= (1<<1); }
#define NF_RDDATA8()              (rNFDATA8)
#define NF_CLEAR_RB()           {rNFSTAT |= (1<<2); }
#define NF_DETECT_RB()         {while(!(rNFSTAT&(1<<2)));}
 
#define NF_CE_L()                     NF_nFCE_L()
#define NF_CE_H()                    NF_nFCE_H()
 
//nandflash命令集
#define CMD_READ1                 0x00       //读命令周期1
#define CMD_READ2                 0x30       //读命令周期2
#define CMD_RESET                 0xff        //复位
 
// HCLK=100Mhz
#define TACLS                    1
#define TWRPH0                 2
#define TWRPH1                 0
 
//把nandflash中的数据复制到SRAM
void RdNF2SDRAM( )
{
       unsigned int i, j;
       unsigned int start_addr = 0x0;              //nandflash起始地址
       unsigned char * to = (unsigned char *)0x30000000;           //SRAM起始地址
       unsigned int size = 0x100000;              //复制数据的大小
      
       //初始化nandflash
       rGPACON = (rGPACON &~(0x3f<<17)) | (0x3f<<17);
rNFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);
       rNFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);
      
       //开始复制数据
       for(i = (start_addr >> 11); size > 0; )
       {
              //nandflash复位
              NF_CE_L();
              NF_CLEAR_RB();
              NF_CMD(CMD_RESET); 
              NF_DETECT_RB();
              NF_CE_H();
 
              NF_nFCE_L();  
              NF_CLEAR_RB();
 
              NF_CMD(CMD_READ1);           //读命令
 
              //5个周期地址
              NF_ADDR(0x00);
              NF_ADDR(0x00);
              NF_ADDR((i) & 0xff);
              NF_ADDR((i >> 8) & 0xff);
              NF_ADDR((i >> 16) & 0xff);
 
              NF_CMD(CMD_READ2);           //读命令
 
              NF_DETECT_RB();             //等待
 
              //开始复制一页数据
              for (j = 0; j < 2048; j++)
              {
                     to[j] =  NF_RDDATA8();
              }
 
              NF_nFCE_H();
             
              size -= 2048;
              to += 2048;
              i ++;
       }    
}           
 
       上面程序是把nandflash中的程序从地址0x0开始,复制到SRAM中,它的绝对地址为0x30000000,复制的大小为0x100000。为了简化程序,在这里我们没有进行ECC校验。
 
       经过上面的修改,我们就可以把程序烧写到nandflash中,并运行起来了。至于如何烧写nandflash,我这里就不过多介绍了。我是用J-Link间接烧写的方法,该方法在网上就可以搜索到,而且在购买J-Link所附带的光盘中应该也有详细地讲解。
 
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/zhaocj/archive/2010/08/11/5803699.aspx
阅读(1026) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~