zoukankan      html  css  js  c++  java
  • Nand flash code

      (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

       

       

  • 相关阅读:
    二进制文件
    Python的特殊成员
    中标麒麟Linux7 如何关闭广播消息
    双重循环输出
    输出星期数
    九九乘法表
    打印菱形
    加法表
    求100以内所有偶数和
    猜大小
  • 原文地址:https://www.cnblogs.com/darren-pty/p/darren_nand.html
Copyright © 2011-2022 走看看