zoukankan      html  css  js  c++  java
  • 实验四--nand flash的使用

    一。环境和编译器

      开发板:jz2440

           系统:ubuntu12.04

           编译器:gcc

    二。验证代码

    1.head.S

     1 @******************************************************************************
     2 @ File:head.s
     3 @ 功能:设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行
     4 @auther:
     5 @******************************************************************************       
     6   
     7 .text
     8 .global _start
     9 _start:
    10             @函数disable_watch_dog, memsetup, init_nand, nand_read_ll在init.c中定义
    11             ldr     sp, =4096               @设置堆栈 
    12             bl      disable_watch_dog       @关WATCH DOG
    13             bl      memsetup                @初始化SDRAM
    14             bl      nand_init               @初始化NAND Flash
    15 
    16             @将NAND Flash中地址4096开始的1024字节代码(main.c编译得到)复制到SDRAM中
    17                                             @nand_read_ll函数需要3个参数:
    18             ldr     r0,     =0x30000000     @1. 目标地址=0x30000000,这是SDRAM的起始地址
    19             mov     r1,     #4096           @2.  源地址   = 409620             mov     r2,     #2048           @3.  复制长度= 2048(bytes)
    21 bl nand_read @调用C函数nand_read 22 23 ldr sp, =0x34000000 @设置栈 24 ldr lr, =halt_loop @设置返回地址 25 ldr pc, =main @b指令和bl指令只跳转32M的范围,所以这里使用向pc赋值的方法进行跳转 26 halt_loop: 27 b halt_loop

    2.init.c

     1 #define     WTCON    (*(volatile unsigned long *)0x53000000)
     2 #define     MEM_CTL_BASE        0x48000000
     3  
     4 void disable_watch_dog();
     5 void memsetup();
     6 
     7 /*关掉看门狗 */
     8 void disable_watch_dog()
     9 {
    10     WTCON    = 0;
    11 }
    12 
    13 /* 设置SDRAM */
    14 void memsetup()
    15 {
    16     int     i = 0;
    17     unsigned long *p = (unsigned long *)MEM_CTL_BASE;
    18 
    19     /* SDRAM 13个寄存器的值 */
    20     unsigned long  const    mem_cfg_val[]={ 0x22011110,     //BWSCON
    21                                             0x00000700,     //BANKCON0
    22                                             0x00000700,     //BANKCON1
    23                                             0x00000700,     //BANKCON2
    24                                             0x00000700,     //BANKCON3  
    25                                             0x00000700,     //BANKCON4
    26                                             0x00000700,     //BANKCON5
    27                                             0x00018005,     //BANKCON6
    28                                             0x00018005,     //BANKCON7
    29                                             0x008C07A3,     //REFRESH
    30                                             0x000000B1,     //BANKSIZE
    31                                             0x00000030,     //MRSRB6
    32                                             0x00000030,     //MRSRB7
    33                                     };
    34 
    35     for(; i < 13; i++)
    36         p[i] = mem_cfg_val[i];
    37 }

    3.nand.c  以下代码不支持2410 也不支持小页读写,是裁剪源码的结果。

    
    
      1 #define GSTATUS1        (*(volatile unsigned int *)0x560000B0)
      2 #define BUSY            1
      3 
      4 #define NAND_SECTOR_SIZE_LP    2048
      5 #define NAND_BLOCK_MASK_LP     (NAND_SECTOR_SIZE_LP - 1)
      6 
      7 typedef unsigned int S3C24X0_REG32;
      8 
      9 
     10 typedef struct {
     11     S3C24X0_REG32   NFCONF;
     12     S3C24X0_REG32   NFCONT;
     13     S3C24X0_REG32   NFCMD;
     14     S3C24X0_REG32   NFADDR;
     15     S3C24X0_REG32   NFDATA;
     16     S3C24X0_REG32   NFMECCD0;
     17     S3C24X0_REG32   NFMECCD1;
     18     S3C24X0_REG32   NFSECCD;
     19     S3C24X0_REG32   NFSTAT;
     20     S3C24X0_REG32   NFESTAT0;
     21     S3C24X0_REG32   NFESTAT1;
     22     S3C24X0_REG32   NFMECC0;
     23     S3C24X0_REG32   NFMECC1;
     24     S3C24X0_REG32   NFSECC;
     25     S3C24X0_REG32   NFSBLK;
     26     S3C24X0_REG32   NFEBLK;
     27 } S3C2440_NAND;
     28 
     29 static S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
     30 
     31 
     32 
     33 /* 供外部调用的函数 */
     34 void nand_init(void);
     35 void nand_read(unsigned char *buf, unsigned long start_addr, int size);
     36 
     37 
     38 /* S3C2440的NAND Flash处理函数 */
     39 static void s3c2440_nand_reset(void);
     40 static void s3c2440_wait_idle(void);
     41 static void s3c2440_nand_select_chip(void);
     42 static void s3c2440_nand_deselect_chip(void);
     43 static void s3c2440_write_cmd(int cmd);
     44 static void s3c2440_write_addr_lp(unsigned int addr);
     45 static unsigned char s3c2440_read_data(void);
     46 
     47 
     48 
     49 /* 复位 */
     50 static void s3c2440_nand_reset(void)
     51 {
     52     s3c2440_nand_select_chip();
     53     s3c2440_write_cmd(0xff);  // 复位命令
     54     s3c2440_wait_idle();
     55     s3c2440_nand_deselect_chip();
     56 }
     57 
     58 /* 等待NAND Flash就绪 */
     59 static void s3c2440_wait_idle(void)
     60 {
     61     int i;
     62     volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;
     63     while(!(*p & BUSY))
     64         for(i=0; i<10; i++);
     65 }
     66 
     67 /* 发出片选信号 */
     68 static void s3c2440_nand_select_chip(void)
     69 {
     70     int i;
     71     s3c2440nand->NFCONT &= ~(1<<1);
     72     for(i=0; i<10; i++);    
     73 }
     74 
     75 /* 取消片选信号 */
     76 static void s3c2440_nand_deselect_chip(void)
     77 {
     78     s3c2440nand->NFCONT |= (1<<1);
     79 }
     80 
     81 /* 发出命令 */
     82 static void s3c2440_write_cmd(int cmd)
     83 {
     84     volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;
     85     *p = cmd;
     86 }
     87 
     88 
     89 
     90 
     91 static void s3c2440_write_addr_lp(unsigned int addr)
     92 {
     93     int i;
     94     volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
     95     int col, page;
     96 
     97     col = addr & NAND_BLOCK_MASK_LP;
     98     page = addr / NAND_SECTOR_SIZE_LP;
     99     
    100     *p = col & 0xff;            /* Column Address A0~A7 */
    101     for(i=0; i<10; i++);        
    102     *p = (col >> 8) & 0x0f;     /* Column Address A8~A11 */
    103     for(i=0; i<10; i++);
    104     *p = page & 0xff;            /* Row Address A12~A19 */
    105     for(i=0; i<10; i++);
    106     *p = (page >> 8) & 0xff;    /* Row Address A20~A27 */
    107     for(i=0; i<10; i++);
    108     *p = (page >> 16) & 0x03;    /* Row Address A28~A29 */
    109     for(i=0; i<10; i++);
    110 }
    111 
    112 
    113 /* 读取数据 */
    114 static unsigned char s3c2440_read_data(void)
    115 {
    116     volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;
    117     return *p;
    118 }
    119 
    120 
    121 /* 初始化NAND Flash */
    122 void nand_init(void)
    123 {
    124 #define TACLS   0
    125 #define TWRPH0  3
    126 #define TWRPH1  0
    127 
    128 
    129         /* 设置时序 */
    130         s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
    131         /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
    132         s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);
    133    
    134     
    135     /* 复位NAND Flash */
    136     s3c2440_nand_reset();
    137 }
    138 
    139 
    140 /* 读函数 */
    141 void nand_read(unsigned char *buf, unsigned long start_addr, int size)
    142 {
    143     int i, j;
    144 
    145 
    146     if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) {
    147         return ;    /* 地址或长度不对齐 */
    148     }     //NAND_BLOCK_MASK_LP=2047   111_1111_1111  SIZE与之相与,若等于0,说明SIZE低11都是0,那么地址对齐;否则不对齐
    149     
    150 
    151     /* 选中芯片 */
    152     s3c2440_nand_select_chip();
    153 
    154     for(i=start_addr; i < (start_addr + size);) {
    155       /* 发出READ0命令 */
    156       s3c2440_write_cmd(0);
    157 
    158       /* Write Address */
    159       s3c2440_write_addr_lp(i);
    160 
    161       s3c2440_write_cmd(0x30);        
    162 
    163       s3c2440_wait_idle();
    164 
    165 
    166       for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) {
    167 
    168           *buf = s3c2440_read_data();
    169           buf++;
    170       }   //i的值等于0,512,1024,1536这四个值,也就可以读写0到2047这2k之内连续的地址的值
    171     }
    172 
    173     /* 取消片选信号 */
    174     s3c2440_nand_deselect_chip();
    175     
    176     return ;
    177 }
    
    
    
    
    

    4.led.c

        就是led闪烁之类的,免了。

    5.Makefile

      

     1 objs := head.o init.o nand.o led.o
     2 
     3 nand.bin : $(objs)
     4     arm-linux-ld -Tnand.lds    -o nand_elf $^
     5     arm-linux-objcopy -O binary -S nand_elf $@
     6     arm-linux-objdump -D -m arm  nand_elf > nand.dis
     7 
     8 %.o:%.c
     9     arm-linux-gcc -Wall -c -O2 -o $@ $<
    10 
    11 %.o:%.S
    12     arm-linux-gcc -Wall -c -O2 -o $@ $<
    13 
    14 clean:
    15     rm -f  nand.dis nand.bin nand_elf  *.o

    以上makefile与之前不同,下面是编译细节,请用心比较

    6.链接脚本

    1 SECTIONS { 
    2   firtst      0x00000000 : { head.o init.o nand.o}
    3   second     0x30000000 : AT(4096) { led.o }
    4 } 
    5  

    三。实验结果

      经验证,可实现。

      本代码参考韦东山先生的源码,作来相应的裁剪。

      源码上支持2410和2440,以及大页,小页的读写,这里都分别作了裁剪到只支持2440和大页读。

      nand flash理论性的东西改天附上。

    四。根据

            

      我们这里选用芯片的存储结构,这里选用大页读写,单位是2k,小页是512字节。其中64BYTES是OBB,这里没有用到。

      而大页的写地址定义如下:

      

      需要连续5次,正如代码中:

      

     1 static void s3c2440_write_addr_lp(unsigned int addr)
     2 {
     3     int i;
     4     volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
     5     int col, page;
     6 
     7     col = addr & NAND_BLOCK_MASK_LP;
     8     page = addr / NAND_SECTOR_SIZE_LP;
     9     
    10     *p = col & 0xff;            /* Column Address A0~A7 */
    11     for(i=0; i<10; i++);        
    12     *p = (col >> 8) & 0x0f;     /* Column Address A8~A11 */
    13     for(i=0; i<10; i++);
    14     *p = page & 0xff;            /* Row Address A12~A19 */
    15     for(i=0; i<10; i++);
    16     *p = (page >> 8) & 0xff;    /* Row Address A20~A27 */
    17     for(i=0; i<10; i++);
    18     *p = (page >> 16) & 0x03;    /* Row Address A28~A29 */
    19     for(i=0; i<10; i++);
    20 }

    明显区别与小页的,可以参看原理图中小页的写地址定义。

    此外,读写命令如下:

      复位命令是ff,代码是

    1 /* 复位 */
    2 static void s3c2440_nand_reset(void)
    3 {
    4     s3c2440_nand_select_chip();
    5     s3c2440_write_cmd(0xff);  // 复位命令
    6     s3c2440_wait_idle();
    7     s3c2440_nand_deselect_chip();
    8 }

    而2440中相关控制寄存器如下截图:

    使能信号是NFCONT的最低位  置1  ;

    片选是NFCONT【1】位    写0;

    NFCONT[4]是ECC功能用的。

    片选代码:

     1 /* 发出片选信号 */
     2 static void s3c2440_nand_select_chip(void)
     3 {
     4     int i;
     5     s3c2440nand->NFCONT &= ~(1<<1);
     6     for(i=0; i<10; i++);    
     7 }
     8 
     9 /* 取消片选信号 */
    10 static void s3c2440_nand_deselect_chip(void)
    11 {
    12     s3c2440nand->NFCONT |= (1<<1);
    13 }

    此外等待信号由NFSTAT决定:

    代码是:

    1 /* 等待NAND Flash就绪 */
    2 static void s3c2440_wait_idle(void)
    3 {
    4     int i;
    5     volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;
    6     while(!(*p & BUSY))
    7         for(i=0; i<10; i++);
    8 }

    发出命令即直接向NFCMD写地址就好:

    1 /* 发出命令 */
    2 static void s3c2440_write_cmd(int cmd)
    3 {
    4     volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;
    5     *p = cmd;
    6 }

    读数据:

    1 /* 读取数据 */
    2 static unsigned char s3c2440_read_data(void)
    3 {
    4     volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;
    5     return *p;
    6 }

    连续读写一页的数据:

     1 /* 读函数 */
     2 void nand_read(unsigned char *buf, unsigned long start_addr, int size)
     3 {
     4     int i, j;
     5 
     6 
     7     if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) {
     8         return ;    /* 地址或长度不对齐 */
     9     }
    10     
    11 
    12     /* 选中芯片 */
    13     s3c2440_nand_select_chip();
    14 
    15     for(i=start_addr; i < (start_addr + size);) {
    16       /* 发出READ0命令 */
    17       s3c2440_write_cmd(0);
    18 
    19       /* Write Address */
    20       s3c2440_write_addr_lp(i);
    21 
    22       s3c2440_write_cmd(0x30);        
    23 
    24       s3c2440_wait_idle();
    25 
    26 
    27       for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) {
    28 
    29           *buf = s3c2440_read_data();
    30           buf++;
    31       }
    32     }
    33 
    34     /* 取消片选信号 */
    35     s3c2440_nand_deselect_chip();
    36     
    37     return ;
    38 }

    首先判断地址对齐,如不对齐,读数据取消,因为结果是未知的。   上面解释就是SIZE与上2047(111_1111_1111),若SIZE的低11位都是0,那么相与后,结果是0,则说明地址对齐;否则不对齐。

    i的值是0、2048这个值,可以在0到2047这2k区间连续读。

          /* 发出READ0命令 */

          s3c2440_write_cmd(0);

          /* Write Address */
          s3c2440_write_addr_lp(i);
          s3c2440_write_cmd(0x30);
      s3c2440_wait_idle();

    先发出命令00,表示从开始读,也就是顺序读写。

    然后写如地址。

  • 相关阅读:
    win7下环境搭建
    python简介-copy
    解决MindManager缺少mfc100u.dll无法启动的难题-转载
    Svn win7系统下状态图标不显示-转载
    【R笔记】order函数例子
    【R笔记】R语言进阶之4:数据整形(reshape)
    【R笔记】R语言利器之ddply
    天池新人实战赛之[离线赛]题目与思路
    第一次写博客
    程序员需要有多懒 ?- cocos2d-x 数学函数、常用宏粗整理
  • 原文地址:https://www.cnblogs.com/hulig7/p/4088187.html
Copyright © 2011-2022 走看看