Flash基础入门之Nand flash code
小标 2018-08-24 来源 : 阅读 1550 评论 0

摘要:本文主要向大家介绍了Flash基础入门之Nand flash code,通过具体的内容向大家展现,希望对大家学习Flash基础入门有所帮助。

本文主要向大家介绍了Flash基础入门之Nand flash code,通过具体的内容向大家展现,希望对大家学习Flash基础入门有所帮助。

  (1)流水灯
     
   1>我们来看原理图

   2>datasheet
 
  3>leds.c
      
     #define GPFCON  (*(volatile unsigned long *)0x56000050)  //address
     #define GPFDAT  (*(volatile unsigned long *)0x56000054)
  
     #define GPF4_reset (3<<(4*2))
     #define GPF5_reset (3<<(5*2))
     #define GPF6_reset (3<<(6*2)) //reset
 
     #define GPF4_out  (1<<(4*2))
     #define GPF5_out  (1<<(5*2))
     #define GPF6_out  (1<<(6*2))//output
     void Delay_ms(volatile unsigned long ms);
     int main(void)
 {
   GPFCON &=~(GPF4_reset | GPF5_reset | GPF6_reset);
   GPFCON |= (GPF4_out | GPF5_out | GPF6_out);
     
   while(1)
 {
    GPFDAT &=~(1<<4);
    Delay_ms(30000);
    GPFDAT |=(1<<4);//led1
   
    GPFDAT &=~(1<<5);
    Delay_ms(30000);
    GPFDAT |=(1<<5);//led2
 
    GPFDAT &=~(1<<6);
    Delay_ms(30000);
    GPFDAT |=(1<<6);//led3

   return 0;
}
     void Delay_ms(volatile unsigned long ms)
{
   for(; ms>0; ms--);
}
 
 
 
 
  (2)由于我们的程序所占用的空间会出现大于s3c2440的cpu的sram的空间,所以内存无法满足我们的需求,就需要在片外内存中进行运行。这里通过一个链接脚本将一部分程序放在nand flash的前4k的地方,将另一部分放在nand flash 的4k以后,这样的话,我们将nand flash的4K以后的程序拷贝到sram中进行运行就可以的。
     
  在开发板在nand flash模式下启动,开发板只能将前4K的程序拷贝到sram中运行。
 
  链接脚本:nand.lds
   SECTION{
     first   0x00000000  : {nand.o init.o crt.o}
     second  0x30000000  : AT(4096) {leds.o}
}
  
 
 
 (3) nand.c
    
   #define  LANGE_PAGE
   typedef unsigned int  uint32;
   //s3c2440控制寄存器
  typedef struct{
     uint32  NFCONF;  //nand flash 配置寄存器
     uint32  NFCONT;  //nand flash 控制寄存器(s3c2410没有此寄存器)
     uint32  NFCMMD;  //nand flash 命令寄存器
     uint32  NFADDR;  //nand flash 地址寄存器
     uint32  NFDATA;  //nand flash 数据寄存器
     uint32  NFMECCD0; 
     uint32  NFMECCD1;
     uint32  NFSECCD;
     uint32  NFSTAT;  //状态寄存器
     uint32  NFESTAT0;
     uint32  NFESTAT1;
     uint32  NFMECC0;
     uint32  NFMECC1;
     uint32  NFSECC;
     uint32  NFSBLK;
     uint32  NFEBLK;
}s3c2440_NAND;
  
 
   //s3c2410寄存器
  typedef struct{
    
    uint32  NFCONF;
    uint32  NFCMD:
    uint32  NFADDR;
    uint32  NFDATA;
    uint32  NFSTAT;
    uint32  NFECC;
}s3c2410_NAND;
 
 
  typedef struct{
    void (*nand_reset)(void); //复位
    void (*nand_select_chip)(void);//片选信号
    void (*write_cmd)(unsigned int cmd); //写命令
    void (*nand_wait)(void);
    void (*write_addr)(unsigned int addr);//写地址
    unsigned char (*read_data)(void);//读地址
    void (*nand_deselect_chip)(void);//取消片选信号,节能
}t_nand_chip;
 
 
   t_nand_chip  nand_chip;
   s3c2440_NAND * s3c2440_nand =(s3c2440_NAND*)0x4e000000;
   s3c2410_NAND * s3c2410_nand =(s3c2410_NAND*)0x4e000000;  //NFCONF的地址0x4e000000
   
 
 
 
   void s3c2410_nand_select_chip(void)
  {
    int i;
    s3c2410_nand->NFCONF &=~(1<<11);  //nFCE==0片选
    for(i=0;i<10.i++); //等待
}
   
 
 
 
   void s3c2410_write_cmd(unsigned int cmd)
 {
     volatile unsigned char *p =(volatile unsigned char *)s3c2410_nand->NFCMD;
     *p=cmd;
}
 
 
  void s3c2410_nand_wait(void)
 {
     int i;
     volatile unsigned char *p =(volatile unsigned char *)s3c2410_nand->NFSTAT;
     while(!(*p & 1)); //是否忙碌   //1--ready  0--busy
     
     for(i=0;i<10;i++);
}
 
 
  void s3c2410_write_addr(unsigned int addr)
 {
     int i;
     volatile unsigned char *p =(volatile unsigned char *)s3c2410_nand->NFADDR;
     *p=addr&0xff;  /*A0-A7 */
     for(i=0;i<10;i++);
     *p=(addr>>9)&0xff;/*A9-A16 */
     for(i=0;i<10;i++);
     *p=(addr>>17)&0xff; /*A17-A24 */
     for(i=0;i<10;i++);
     *p=(addr>>25)&0x01; //A25
     for(i=0;i<10;i++);
}
 
 
  unsigned char s3c2410_read_data(void)
 {
     volatile unsigned char *p =(volatile unsigned char *)s3c2410_nand->NFDATA;
     return *p;
}
 
 
  void s3c2410_nand_deselect_chip(void)
 {
     s3c2410_nand->NFCONF |=(1<<11);
 }
 
 
  void s3c2410_nand_reset(void)
  {
     s3c2410_nand_select_chip();
     s3c2410_write_cmd(0xff);  //针对不同的nand flash 对应的nand falsh所要求nand控制器发出的命令有所不同 
     s3c2410_nand_wait();
     s3c2410_nand_deselect_chip();

 
 
//s3c2440
  void s3c2440_nand_select(void)
  {
     int i;
     s3c2440_nand->NFCONT &=~(1<<1);
     for(i=0;i<10;i++);
}
 
 
  void s3c2440_write_cmd(unsigned int cmd)
 {
     volatile unsigned char *p =(volatile unsignd char *)s3c2440_nand->NFCMMD;
     *p =cmd;
 }
 
 
  void s3c2440_nand_wait(void)
  {
     int i;
     volatile unsignd char *p=(volatile unsigned char *)s3c2440_nand->NFSTAT;
     while(!(*p & 1)); //判断是否忙碌
     for(i=0;i<10;i++);
}
 
 
  void s3c2440_write_addr(unsigned int addr)//小页--521byte (K9F1208U0M)
  {
     int i;
     volatile unsigned char *p=(volatile unsigned char *)s3c2440_nand->NFADDR;
     *p=addr&0xff;     //A0-A7共8根线,可寻址2^8=256byte --半页(通过不同的命令 00h--上半页,01h--下半页)
     for(i=0;i<10;i++);
     *p=(addr>>9)&0xff;
     for(i=0;i<10;i++);
     *p=(addr>>17)&0xff;
     for(i=0;i<10;i++);
     *p=(addr>>25)&0x01;  //A9-A25 共17根线,可寻址 2^17=2^7k=4(层)*1024(块)*32(页)=2^7k page
     for(i=0;i<10;i++);
}
    
 
 
 
 
   void s3c2440_write_addr_lp(unsigned int addr)//大页--2K(512*4)(K9F2G08x0A)
 {
     int i;
     int col,row;//col分两次,row分三次发送
     volatile unsigned char *p = (volatile unsigned char *)s3c2440->NFADDR;
     col=addr &(2048-1);  //addr & (11111111111)--取低11位
     row=addr/2048;   //取高位 --(2048==一页的大小)
     *p=col &0xff; /* A0-A7*/
     for(i=0;i<10;i++);
     *p=col & 0x0f;  /* A8-A11*/  --A0==A11共12根线,可寻空间2^12=2*2K,而一页是1K,留有余量,A11用来访问spare区域,也就是      for(i=0;i<10;i++);             -- oob区域用来存放校验信息, spare区域并不在编址范围内,需要使用A11控制访问
 
     *p=row & 0xff; /* A12-A19*/
     for(i=0;i<10;i++);
     *p=row & 0xff; /* A20-A27*/
     for(i=0;i<10;i++);
     *p=row & 0xff;  /* A28-A29*/  --A12==A28共17根线,可寻空间2^18=2^8k=2(层)*1024(块)*64(页)=2^7k page,同时留有                                    --余量,用来兼容大容量flash
}
    
 
 
 
 
     unsigned char s3c2440_read_data(void)
 {
     volatile unsigned char *p=(volatile unsigned char *)s3c2440_nand->NFDATA;
     return 0;
 } 
 
 
 
  void s3c2440_nand_deselect_chip(void)
 {
     s3c2440_nand->NFCONT |=(1<<1);
}
 
 
  void s3c2440_nand_reset(void)
 {
     s3c2440_nand_select_chip();
     s3c2440_write_cmd(0xff); 
     s3c2440_nand_wait();
     s3c2440_nand_deselect_chip();
 }
 
     GSTATUS1是芯片的ID,对于不同的芯片有对应的ID,s3c2440的ID是0x32440001,s3c2410的ID是0x32410000或0x32410002
 
   s3c2440的ID:
    
 
   s3c2410的ID:
   
 
 
 
  //nand初始化
  void nand_init(void)
 {
     #define  TACLS    0
     #define  TWRPH0   3
     #define  TWRPH1   0
   if((GSTATUS1==0x32410000)||(GSTATUS1==0x32410002)) //s3c2410
    {
       nand_chip.nand_reset =s3c2410_nand_reset;
       nand_chip.nand_select_chip =s3c2410_nand_select_chip;
       nand_chip.write_cmd =s3c2410_write_cmd;
       nand_chip.nand_wait =s3c2410_nand_wait;
       nand_chip.write_addr =s3c2410_write_addr;
       nand_chip.read_data =s3c2410_read_data;
       nand_chip.nand_deselect_chip =s3c2410_nand_deselect_chip;
       
       
       //使能nand flash控制器
       //初始化ECC
       //禁止片选信号
       //设置时序
       s3c2410_nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
    }
   else                   //s3c2440
    {
       nand_chip.nand_select_chip =s3c2440_nand_select_chip;
       nand_chip.write_cmd =s3c2440_write_cmd;
       nand_chip.nand_wait =s3c2440_nand_wait;
     #ifdef  LANGE_PAGE
       nand_chip.write_addr =s3c2440_write_addr_lp;
     #else
       nand_chip.write_addr =s3c2440_write_addr;
     #endif
       nand_chip.read_data =s3c2440_read_data;
       nand_chip.nand_deselect_chip =s3c2440_nand_deselect_chip;
       
   
       //使能nand flash控制器
      //初始化ECC
      //禁止片选信号nFCE 
      s3c2440_nand->NFCONT =(1<<4) | (1<<1) | (1<<0);
 
      
      
 
      //设置时序
     s3c2440_nand->NFCONF =(TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
    }
    nand_chip.nand_reset(); //复位nand flash
 }
 
  void nand_read(unsigned char *buf, unsigned long start_addr, int size)//读数据
 {
    int i,j;
     //地址或长度对齐
     //NAND Flash 每次读操作是以page为单位的,一个page在此是2048byte(不同的NAND Flash的page大小不一定相同), 
     //因为2047的二进制表示是11个1, 即11111111111, 一个数如果是2048的倍数,低11bit必须是0, 即 ****00000000000
     //所以把一个数跟2047按位与就可判断它是不是2048的倍数。
    #define LANGE_PAGE  
     if(strat_addr & (2048-1) || (size & (2048-1))) //大页--2048byte
       return;
    #else
       //512的倍数
     if(start_addr & (512-1) || (size & (512-1)) ) //小页--512byte
       return;
     #endif  
    
   //选中芯片
   nand_chip.nand_select_chip();
    
   对于小页而言,进行读取数据需要发命令00h/01h;
   对于大页而言,进行读取数据需要发命令00h ,30h;
   
   小页:
  
   
   
   大页:
   
 
   for(i=strat_addr;i<(start_addr + size);){
 
   //发出命令
   nand_chip.write_cmd(0); //00h
   
   //写地址
   nand_chip.write_addr(i);
  
  #ifdef LANGE_PAGE
    nand_chip.write_cmd(0x30);
  #endif
  //等待  
  nand.chip.nand_wait();
 
  #ifdef LANGE_PAGE
    for(j=0;j<2048;j++,i++){
  #else
    for(j=0;j<512;j++,i++){
  #endif
    //读数据
    *buf=nand_chip.read_data();
     buf++;
  }
 }
   //取消片选信号 
   nand_chip.nand_deselect_chip();
   return ;
 }
 
  (4)关看门狗和配置存储管理器
   init.c
   
   #define WHITCH_DOG  (*(volatile unsigned long*)0x53000000)
   #define MEM_BASE  0x48000000  //存储管理器寄存器的起始地址
 
   void disable_watch_dog(void)
   {
     WATCH_DOG = 0;
  
   }  
   void mem_setup(void)
  {
     int i=0;
     unsigned long *p=(unsigned long *)MEM_BASE;
     unsigned long const mem_cfg_val[]={
 
                      0x22011110,
                      0x00000700,
                      0x00000700,
                      0x00000700,
                      0x00000700,
                      0x00000700,
                      0x00000700,
                      0x00018005,
                      0x00018005,
                      0x008C07A3,
                      0x000000B1,
                      0x00000030,
                      0x00000030
      };
    for(i=0;i<13;i++)
     {
       p[i]=mem_cfg_val[i];
     }
  }
 
  (5)crt.S
  .text
    .global _strat
    _strat:
       ldr sp,=4096
           bl disable_watch_dog
           bl mem_setup
           bl nand_init
    
           ldr r0,=0x30000000 @buf
           mov r1,#4096       @strat_addr
           mov r2,#2048       @size
 
           bl nand_read
           ldr sp,=0x34000000
           ldr pc,=main
halt_loop:
           b halt_loop
 
  (6)Makefile 
  objs := crt.o nand.o init.o leds.o
  nand.bin :$(objs)
    arm-linux-ld -Tnand.dis -o nand_elf $^
        arm-linux-objcopy -O binary -S nand_elf $@
        arm-linux-objdump -D -m arm nand_elf > nand.dis
 
  %.o :%.c
    arm-linux-gcc -Wall -c -O2 -o $@ $<
  %.o :%.S
    arm-linux-gcc -Wall -c -O2 -o $@ $<
 
  clean:
    rm -f nand.dis nand.bin nand_elf *.o
   
 
       

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标常用软件Flash频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved