(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

   

   

Nand flash code的更多相关文章

  1. 嵌入式Linux驱动学习之路(二十三)NAND FLASH驱动程序

    NAND FLASH是一个存储芯片. 在芯片上的DATA0-DATA7上既能传输数据也能传输地址. 当ALE为高电平时传输的是地址. 当CLE为高电平时传输的是命令. 当ALE和CLE都为低电平时传输 ...

  2. s3c2440 移值u-boot-2016.03 第2篇 支持Nand flash启动

    1, 要求:在4K 的代码以内,完成 NOR NAND 类型判断,初始化 NAND 复制自身到 SDRAM ,重定向. 2, 在 /arch/arm/cpu/arm920t/ 文件夹里 添加一个 in ...

  3. ECC校验原理以及在Nand Flash中的应用

         本篇文章主要介绍ECC基本原理以及在Nand Flash中的应用,本文记录自己对ECC校验原理的理解和学习. ECC介绍      ECC,全称为Error Correcting Code, ...

  4. WinCE NAND flash - FAL

    http://blog.csdn.net/renpine/article/details/4572347 http://msdn.microsoft.com/en-US/library/ee48203 ...

  5. STM32学习笔记——FSMC 驱动大容量NAND FLASH [复制链接]

    本文原创于观海听涛,原作者版权所有,转载请注明出处. 近几天开发项目需要用到STM32驱动NAND FLASH,但由于开发板例程以及固件库是用于小页(512B),我要用到的FLASH为1G bit的大 ...

  6. Samsung K9F1G08U0D SLC NAND FLASH简介(待整理)

    Samsung  K9F1G08U0D,数据存储容量为128M,采用块页式存储管理.8个I/O引脚充当数据.地址.命令的复用端口.详细:http://www.linux-mtd.infradead.o ...

  7. NAND FLASH特性说明

    1.NAND FLASH 的特殊性. 1)存在坏块.由于NAND生产工艺的原因,出厂芯片中会随机出现坏块.坏块在出厂时已经被初始化,并在特殊区域中标记为不可用,在使用过程中如果出现坏块,也需要进行标记 ...

  8. NAND FLASH ECC校验原理与实现

    ECC简介 由于NAND Flash的工艺不能保证NAND的Memory Array在其生命周期中保持性能的可靠,因此,在NAND的生产中及使用过程中会产生坏块.为了检测数据的可靠性,在应用NAND  ...

  9. Nand Flash基础知识与坏块管理机制的研究

    概述 Flash名称的由来,Flash的擦除操作是以block块为单位的,与此相对应的是其他很多存储设备,是以bit位为最小读取/写入的单位,Flash是一次性地擦除整个块:在发送一个擦除命令后,一次 ...

随机推荐

  1. 文件、文件夹操作(I)

    遍历一个目录下的所有文件 首先我们获取用户文档目录路径 let manager = FileManager.default let urlForDocument = manager.urls(for: ...

  2. 大数据处理框架之Strom:redis storm 整合

    storm 引入redis ,主要是使用redis缓存库暂存storm的计算结果,然后redis供其他应用调用取出数据. 新建maven工程 pom.xml <project xmlns=&qu ...

  3. Java综合高级篇

    1.你用过哪些集合类? 大公司最喜欢问的Java集合类面试题 40个Java集合面试问题和答案 java.util.Collections 是一个包装类.它包含有各种有关集合操作的静态多态方法. ja ...

  4. TCP客户端图片上传服务端保存本地示例

    //TCP客户端public class TCPClient { public static void main(String[] args)throws IOException { Socket s ...

  5. EasyUi通过OCUpload上传及POI上传 实现导入xls表格功能

    Easyui上传文件案例 第一步:要想使用OCUpload首先前端需要导入js包         <script type="text/javascript" src=&qu ...

  6. Linux基础命令---文本编辑ex

    ex ex会启动vim编辑器,它的执行效果和vim –E相同.从ex模式回到普通模式,可以在vim中输入:vim. 此命令的适用范围:RedHat.RHEL.Ubuntu.CentOS.SUSE.op ...

  7. android TextView Unicde编码转换 android中一些特殊字符Unicode码值

    android TextView Unicde编码转换 android中一些特殊字符Unicode码值 android中一些特殊字符(如:←↑→↓等箭头符号,约等于号≍)的Unicode码值 Text ...

  8. AtCoder Beginner Contest 085(ABCD)

    A - Already 2018 题目链接:https://abc085.contest.atcoder.jp/tasks/abc085_a Time limit : 2sec / Memory li ...

  9. kubernetes install for centos

    官方的文档写的很清楚 https://kubernetes.io/docs/getting-started-guides/centos/centos_manual_config/ 如果已经安装过doc ...

  10. 通过数组和枚举简化GPIO操作编码(转)

    源: 通过数组和枚举简化GPIO操作编码