• 四、NAND Flash


    4.1 nand flash启动u-boot

      nand flash 启动的时候,CPU 需要将 nand flash 中前面 4KB 的内容复制到 SRAM 中执行,然后将 NAND Flash 中的所有内容拷贝到 SDRAM中。

      前4 KB 的拷贝 是硬件自动执行的。

    4.1.1 地址空间

      原理图如下:

      

      nand flash 只有数据总线,并没有像 SDRAM 一样有地址总线。这样就有两种寻址方式就不同。

      SDRAM 或 网卡、片内4K内存 都是地址总线接到 2440 上,他们的地址都是 CPU可以看到的,都是CPU发出来的,这为 CPU 统一编址。

      nand flash 上页存在地址空间(0~256 M),nand flash 上的 0 地址 和 CPU 上的 0地址是不同的。

      nand flash 地址都是通过 数据总线来发送的。

      JZ2440板子上用的是大页的 nand flash,大页是指一个页里面有 2K 字节,小页只有 512 字节。结构如下图:

      

      一页分为 2K 字节 + 64字节的OOB,一块的大小为 128K + 4K byte,128/2 = 64 页组成一块。

      OOB 在大多数时候不参与编址。

    4.1.2 nand flash 操作

      CPU 先发出命令给 nandflash 要寻址,然后发送地址,然后再发送 读或写命令,在读或写数据。

      nand flash  的命令如下图:

      

      nandflash 引脚功能

      

    • 从硬件上访问 NAND
      • 发出命令:CLE引脚,命令发送到数据总线上
      • 发出地址:ALE引脚,地址发送到数据总线上
      • 传输数据:R/W
    • 2440 控制
      • 发出命令,寄存器 NFCMMD 寄存器
      • 发出地址,寄存器 NFADDR 寄存器
      • 读写数据,NFDATA
      • 状态,NFSTAT  

      读流程如下:(其他流程见 nand flash  的芯片手册的第三章)

      

     4.1.3 代码

      nand.lds

    1 SECTIONS { 
    2     // head.o init.o nand.o 存放在地址 0x0000 0000 处
    3   firtst      0x00000000 : { head.o init.o nand.o}
    4     // main.o 存放在地址 0x3000 0000 处  SDRAM
    5   second     0x30000000 : AT(4096) { main.o }
    6 }

       head.S

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

      init.c

     1 /* WOTCH DOG register */
     2 #define     WTCON                (*(volatile unsigned long *)0x53000000)
     3 
     4 /* SDRAM regisers */
     5 #define     MEM_CTL_BASE        0x48000000
     6  
     7 void disable_watch_dog();
     8 void memsetup();
     9 
    10 /*上电后,WATCH DOG默认是开着的,要把它关掉 */
    11 void disable_watch_dog()
    12 {
    13     WTCON    = 0;
    14 }
    15 
    16 /* 设置控制SDRAM的13个寄存器 */
    17 void memsetup()
    18 {
    19     int     i = 0;
    20     unsigned long *p = (unsigned long *)MEM_CTL_BASE;
    21 
    22     /* SDRAM 13个寄存器的值 */
    23     unsigned long  const    mem_cfg_val[]={ 0x22011110,     //BWSCON,这里将所有的内存配置都设置了,我们关注SDRAM DW6 0010 即可,为16位
    24                                             0x00000700,     //BANKCON0,
    25                                             0x00000700,     //BANKCON1
    26                                             0x00000700,     //BANKCON2
    27                                             0x00000700,     //BANKCON3  
    28                                             0x00000700,     //BANKCON4
    29                                             0x00000700,     //BANKCON5
    30                                             0x00018005,     //BANKCON6,SDRAM 的设置,对照寄存器查看参数
    31                                             0x00018005,     //BANKCON7
    32                                             0x008C07A3,     //REFRESH,刷新寄存器,使能,刷新模式为自刷新,RAS改变时间为2个时钟,
    33                                                             //SDRAM Semi Row cycle time 为7个时钟
    34                                                             //Refresh Counte 为 11 1010 0011 = 931,Refresh period = (211-refresh_count+1)/HCLK
    35                                             0x000000B1,     //BANKSIZE,SDRAM 大小设置为 64M
    36                                             0x00000030,     //MRSRB6,SDRAM 模式设置
    37                                             0x00000030,     //MRSRB7
    38                                     };
    39 
    40     for(; i < 13; i++)
    41         p[i] = mem_cfg_val[i];  // 为每一个 内存控制器的寄存器设置参数
    42 }
    View Code

      nand,c

      1 /* nand flash support S3C2410 and S3C2440 */
      2 
      3 #define LARGER_NAND_PAGE
      4 
      5 #define GSTATUS1        (*(volatile unsigned int *)0x560000B0)
      6 #define BUSY            1
      7 
      8 #define NAND_SECTOR_SIZE    512
      9 #define NAND_BLOCK_MASK     (NAND_SECTOR_SIZE - 1)
     10 
     11 #define NAND_SECTOR_SIZE_LP    2048
     12 #define NAND_BLOCK_MASK_LP     (NAND_SECTOR_SIZE_LP - 1)    //2047
     13 
     14 typedef unsigned int S3C24X0_REG32;
     15 
     16 
     17 /* NAND FLASH (see S3C2410 manual chapter 6) */
     18 typedef struct {
     19     S3C24X0_REG32   NFCONF;
     20     S3C24X0_REG32   NFCMD;
     21     S3C24X0_REG32   NFADDR;
     22     S3C24X0_REG32   NFDATA;
     23     S3C24X0_REG32   NFSTAT;
     24     S3C24X0_REG32   NFECC;
     25 } S3C2410_NAND;
     26 
     27 /* NAND FLASH (see S3C2440 manual chapter 6) */
     28 typedef struct {
     29     S3C24X0_REG32   NFCONF;     // nand flash 控制寄存器
     30     S3C24X0_REG32   NFCONT;     // nand flash 配置寄存器
     31     S3C24X0_REG32   NFCMD;      // nand flash 命令寄存器
     32     S3C24X0_REG32   NFADDR;     // nand flash 地址寄存器
     33     S3C24X0_REG32   NFDATA;     // nand flash 数据寄存器
     34     S3C24X0_REG32   NFMECCD0;   // nand flash ECC0/1寄存器
     35     S3C24X0_REG32   NFMECCD1;   // nand flash ECC2/3寄存器
     36     S3C24X0_REG32   NFSECCD;    // nand flash ECC寄存器
     37     S3C24X0_REG32   NFSTAT;     // nand flash 工作状态寄存器
     38     S3C24X0_REG32   NFESTAT0;   // nand flash IO[7:0]状态寄存器       
     39     S3C24X0_REG32   NFESTAT1;   // nand flash IO[15:8]状态寄存器
     40     S3C24X0_REG32   NFMECC0;    // nand flash ECC0寄存器
     41     S3C24X0_REG32   NFMECC1;    // nand flash ECC1寄存器
     42     S3C24X0_REG32   NFSECC;     // nand flash ECC寄存器
     43     S3C24X0_REG32   NFSBLK;     // nand flash 块开始地址寄存器
     44     S3C24X0_REG32   NFEBLK;     // nand flash 块结束地址寄存器
     45 } S3C2440_NAND;
     46 
     47 
     48 typedef struct {
     49     void (*nand_reset)(void);
     50     void (*wait_idle)(void);
     51     void (*nand_select_chip)(void);
     52     void (*nand_deselect_chip)(void);
     53     void (*write_cmd)(int cmd);
     54     void (*write_addr)(unsigned int addr);
     55     unsigned char (*read_data)(void);
     56 }t_nand_chip;
     57 
     58 // 设置 nand 基地址
     59 static S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;
     60 static S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;
     61 
     62 static t_nand_chip nand_chip;
     63 
     64 /* 供外部调用的函数 */
     65 void nand_init(void);
     66 void nand_read(unsigned char *buf, unsigned long start_addr, int size);
     67 
     68 /* NAND Flash操作的总入口, 它们将调用S3C2410或S3C2440的相应函数 */
     69 static void nand_reset(void);
     70 static void wait_idle(void);
     71 static void nand_select_chip(void);
     72 static void nand_deselect_chip(void);
     73 static void write_cmd(int cmd);
     74 static void write_addr(unsigned int addr);
     75 static unsigned char read_data(void);
     76 
     77 /* S3C2410的NAND Flash处理函数 */
     78 static void s3c2410_nand_reset(void);
     79 static void s3c2410_wait_idle(void);
     80 static void s3c2410_nand_select_chip(void);
     81 static void s3c2410_nand_deselect_chip(void);
     82 static void s3c2410_write_cmd(int cmd);
     83 static void s3c2410_write_addr(unsigned int addr);
     84 static unsigned char s3c2410_read_data();
     85 
     86 /* S3C2440的NAND Flash处理函数 */
     87 static void s3c2440_nand_reset(void);
     88 static void s3c2440_wait_idle(void);
     89 static void s3c2440_nand_select_chip(void);
     90 static void s3c2440_nand_deselect_chip(void);
     91 static void s3c2440_write_cmd(int cmd);
     92 static void s3c2440_write_addr(unsigned int addr);
     93 static unsigned char s3c2440_read_data(void);
     94 
     95 /* S3C2410的NAND Flash操作函数 */
     96 
     97 /* 复位 */
     98 static void s3c2410_nand_reset(void)
     99 {
    100     s3c2410_nand_select_chip();
    101     s3c2410_write_cmd(0xff);  // 复位命令
    102     s3c2410_wait_idle();
    103     s3c2410_nand_deselect_chip();
    104 }
    105 
    106 /* 等待NAND Flash就绪 */
    107 static void s3c2410_wait_idle(void)
    108 {
    109     int i;
    110     volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFSTAT;
    111     while(!(*p & BUSY))
    112         for(i=0; i<10; i++);
    113 }
    114 
    115 /* 发出片选信号 */
    116 static void s3c2410_nand_select_chip(void)
    117 {
    118     int i;
    119     s3c2410nand->NFCONF &= ~(1<<11);
    120     for(i=0; i<10; i++);    
    121 }
    122 
    123 /* 取消片选信号 */
    124 static void s3c2410_nand_deselect_chip(void)
    125 {
    126     s3c2410nand->NFCONF |= (1<<11);
    127 }
    128 
    129 /* 发出命令 */
    130 static void s3c2410_write_cmd(int cmd)
    131 {
    132     volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFCMD;
    133     *p = cmd;
    134 }
    135 
    136 /* 发出地址 */
    137 static void s3c2410_write_addr(unsigned int addr)
    138 {
    139     int i;
    140     volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFADDR;
    141     
    142     *p = addr & 0xff;
    143     for(i=0; i<10; i++);
    144     *p = (addr >> 9) & 0xff;
    145     for(i=0; i<10; i++);
    146     *p = (addr >> 17) & 0xff;
    147     for(i=0; i<10; i++);
    148     *p = (addr >> 25) & 0xff;
    149     for(i=0; i<10; i++);
    150 }
    151 
    152 /* 读取数据 */
    153 static unsigned char s3c2410_read_data(void)
    154 {
    155     volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFDATA;
    156     return *p;
    157 }
    158 
    159 /* S3C2440的NAND Flash操作函数 */
    160 
    161 /* 复位 */
    162 static void s3c2440_nand_reset(void)
    163 {
    164     s3c2440_nand_select_chip();
    165     s3c2440_write_cmd(0xff);  // 发送复位命令
    166     s3c2440_wait_idle();
    167     s3c2440_nand_deselect_chip();
    168 }
    169 
    170 /* 等待NAND Flash就绪 */
    171 static void s3c2440_wait_idle(void)
    172 {
    173     int i;
    174     volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;
    175     while(!(*p & BUSY)) //BUSY = 1,NFSTAT的 bit0 = 1 时候,为就绪,则跳出循环准备操作
    176         for(i=0; i<10; i++);
    177 }
    178 
    179 /* 发出片选信号 */
    180 static void s3c2440_nand_select_chip(void)
    181 {
    182     int i;
    183     s3c2440nand->NFCONT &= ~(1<<1);//将 nFCE 强制拉低,使能片选
    184     for(i=0; i<10; i++);//延迟    
    185 }
    186 
    187 /* 取消片选信号 */
    188 static void s3c2440_nand_deselect_chip(void)
    189 {
    190     s3c2440nand->NFCONT |= (1<<1);//将 nFCE 强制拉高,不使能片选
    191 }
    192 
    193 /* 发出命令 */
    194 static void s3c2440_write_cmd(int cmd)
    195 {
    196     // 获取  NFCMD 的地址,对NFCMD的地址进行强转
    197     volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;
    198     *p = cmd;
    199 }
    200 
    201 /* 发出地址 */
    202 static void s3c2440_write_addr(unsigned int addr)
    203 {
    204     int i;
    205     volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
    206     
    207     *p = addr & 0xff;
    208     for(i=0; i<10; i++);
    209     *p = (addr >> 9) & 0xff;
    210     for(i=0; i<10; i++);
    211     *p = (addr >> 17) & 0xff;
    212     for(i=0; i<10; i++);
    213     *p = (addr >> 25) & 0xff;
    214     for(i=0; i<10; i++);
    215 }
    216 
    217 
    218 static void s3c2440_write_addr_lp(unsigned int addr)
    219 {
    220     int i;
    221     volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;
    222     int col, page;
    223 
    224     col = addr & NAND_BLOCK_MASK_LP;
    225     page = addr / NAND_SECTOR_SIZE_LP;
    226     
    227     *p = col & 0xff;            /* Column Address A0~A7 */
    228     for(i=0; i<10; i++);        
    229     *p = (col >> 8) & 0x0f;     /* Column Address A8~A11 */
    230     for(i=0; i<10; i++);
    231     *p = page & 0xff;            /* Row Address A12~A19 */
    232     for(i=0; i<10; i++);
    233     *p = (page >> 8) & 0xff;    /* Row Address A20~A27 */
    234     for(i=0; i<10; i++);
    235     *p = (page >> 16) & 0x03;    /* Row Address A28~A29 */
    236     for(i=0; i<10; i++);
    237 }
    238 
    239 
    240 /* 读取数据 */
    241 static unsigned char s3c2440_read_data(void)
    242 {
    243     volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;
    244     return *p;
    245 }
    246 
    247 
    248 /* 在第一次使用NAND Flash前,复位一下NAND Flash */
    249 static void nand_reset(void)
    250 {
    251     nand_chip.nand_reset();
    252 }
    253 
    254 static void wait_idle(void)
    255 {
    256     nand_chip.wait_idle();
    257 }
    258 
    259 static void nand_select_chip(void)
    260 {
    261     int i;
    262     nand_chip.nand_select_chip();
    263     for(i=0; i<10; i++);
    264 }
    265 
    266 static void nand_deselect_chip(void)
    267 {
    268     nand_chip.nand_deselect_chip();
    269 }
    270 
    271 static void write_cmd(int cmd)
    272 {
    273     nand_chip.write_cmd(cmd);
    274 }
    275 static void write_addr(unsigned int addr)
    276 {
    277     nand_chip.write_addr(addr);
    278 }
    279 
    280 static unsigned char read_data(void)
    281 {
    282     return nand_chip.read_data();
    283 }
    284 
    285 
    286 /* 初始化NAND Flash */
    287 void nand_init(void)
    288 {
    289 #define TACLS   0
    290 #define TWRPH0  3
    291 #define TWRPH1  0
    292 
    293     /* 判断是S3C2410还是S3C2440 */
    294     /* GSTATUS1:通用状态寄存器,GSTATUS1 为读寄存器,是用来读出 chip ID,这是用来定位我们的设备的 */
    295     /* 所用的设备为 S3C2440AL,设备ID为 0x32440001 */
    296     if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32440001))
    297     {
    298         nand_chip.nand_reset         = s3c2410_nand_reset;
    299         nand_chip.wait_idle          = s3c2410_wait_idle;
    300         nand_chip.nand_select_chip   = s3c2410_nand_select_chip;
    301         nand_chip.nand_deselect_chip = s3c2410_nand_deselect_chip;
    302         nand_chip.write_cmd          = s3c2410_write_cmd;
    303         nand_chip.write_addr         = s3c2410_write_addr;
    304         nand_chip.read_data          = s3c2410_read_data;
    305 
    306         /* 使能NAND Flash控制器, 初始化ECC, 禁止片选, 设置时序 */
    307         s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
    308     }
    309     else
    310     {
    311         nand_chip.nand_reset         = s3c2440_nand_reset;
    312         nand_chip.wait_idle          = s3c2440_wait_idle;
    313         nand_chip.nand_select_chip   = s3c2440_nand_select_chip;
    314         nand_chip.nand_deselect_chip = s3c2440_nand_deselect_chip;
    315         nand_chip.write_cmd          = s3c2440_write_cmd;
    316 #ifdef LARGER_NAND_PAGE
    317         nand_chip.write_addr         = s3c2440_write_addr_lp;
    318 #else
    319         nand_chip.write_addr         = s3c2440_write_addr;
    320 #endif
    321         nand_chip.read_data          = s3c2440_read_data;
    322 
    323         /* 设置时序 */
    324         s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
    325         /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
    326         s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);
    327     }
    328     
    329     /* 复位NAND Flash */
    330     nand_reset();
    331 }
    332 
    333 
    334 /* 读函数 */
    335 /* buf = 0x30000000, start_addr = 4096,size = 2048 */
    336 void nand_read(unsigned char *buf, unsigned long start_addr, int size)
    337 {
    338     int i, j;
    339 
    340 #ifdef LARGER_NAND_PAGE
    341     if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) {
    342         return ;    /* 地址或长度不对齐 */
    343     }
    344 #else
    345     if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
    346         return ;    /* 地址或长度不对齐 */
    347     }
    348 #endif    
    349 
    350     /* 选中芯片 */
    351     nand_select_chip();
    352 
    353     for(i=start_addr; i < (start_addr + size);) {
    354       /* 发出READ0命令 */
    355       write_cmd(0);
    356 
    357       /* Write Address */
    358       write_addr(i);
    359 #ifdef LARGER_NAND_PAGE
    360       write_cmd(0x30);        
    361 #endif
    362       wait_idle();
    363 
    364 #ifdef LARGER_NAND_PAGE
    365       for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) {
    366 #else
    367       for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
    368 #endif
    369           *buf = read_data();
    370           buf++;
    371       }
    372     }
    373 
    374     /* 取消片选信号 */
    375     nand_deselect_chip();
    376     
    377     return ;
    378 }
    View Code

      main.c

     1 #define    GPFCON        (*(volatile unsigned long *)0x56000050)
     2 #define    GPFDAT        (*(volatile unsigned long *)0x56000054)
     3 
     4 #define    GPF4_out    (1<<(4*2))
     5 #define    GPF5_out    (1<<(5*2))
     6 #define    GPF6_out    (1<<(6*2))
     7 
     8 void  wait(volatile unsigned long dly)
     9 {
    10     for(; dly > 0; dly--);
    11 }
    12 
    13 int main(void)
    14 {
    15     unsigned long i = 0;
    16 
    17     GPFCON = GPF4_out|GPF5_out|GPF6_out;        // 将LED1-3对应的GPF4/5/6三个引脚设为输出
    18 
    19     while(1){
    20         wait(30000);
    21         GPFDAT = (~(i<<4));         // 根据i的值,点亮LED1-3
    22         if(++i == 8)
    23             i = 0;
    24     }
    25 
    26     return 0;
    27 }
    View Code
  • 相关阅读:
    正当防卫与互殴的界限在哪里
    [php入门] 5、初学CSS从中记下的一些基础点(For小白)
    [ZigBee] 13、ZigBee基础阶段性回顾与加深理解——用定时器1产生PWM来控制LED亮度(七色灯)
    [ZigBee] 12、ZigBee之看门狗定时器——饿了就咬人的GOOD DOG
    [ZigBee] 11、ZigBee之睡眠定时器二
    [ZigBee] 10、ZigBee之睡眠定时器
    [ZigBee] 9、ZigBee之AD剖析——AD采集CC2530温度串口显示
    [ZigBee] 8、ZigBee之UART剖析·二(串口收发)
    [php入门] 4、HTML基础入门一篇概览
    [ZigBee] 2、 ZigBee开发环境搭建
  • 原文地址:https://www.cnblogs.com/kele-dad/p/8922391.html
Copyright © 2020-2023  润新知