• nand flash相关


    关于nandflash的说明,请参考其他。

    现在先贴出来韦东山先生的代码,作我学习之用。

     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               @设置堆栈 
    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 
    26 halt_loop:
    27             b       halt_loop
    28  

    上面的代码的作用很明显,现在主要说明地址相关的东西;

    ldr     sp, =4096               @设置堆栈   首先上电后4k代码会自动拷贝到steppingstone里面,disable_watch_dog,memsetup等函数都是在这4k范围里面。

    后面的链接脚本如下:

    1 SECTIONS { 
    2   firtst      0x00000000 : { head.o init.o nand.o}     @在nand flash里面地址为0x0000_0000初存放head.o,init.o,nand.o等
    3   second     0x30000000 : AT(4096) { main.o }          @在4096处,注意此时是4k以外,这个代码就是指出当代码大小大于4k时的处理方法。
    4 }                                @可以看到main.o的运行地址是0x3000_0000,说明运行4k以后的代码需要复制到sdram里面执行。
    5


     上面说明main函数是在刚才提到的4k范围以外。所以head文件里面会有将4096(4k)的main函数编译出来的东西拷贝到3000_0000也就是sdram的地方。

    这个在以后程序比较大的时候基本是比较通用的函数,所以一定得花时间搞明白。上面简单的说明来地址映射方面的问题。

    再看init.c,这个文件只是关闭看门狗和初始化sdram:

     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
    24                                             0x00000700,     //BANKCON0
    25                                             0x00000700,     //BANKCON1
    26                                             0x00000700,     //BANKCON2
    27                                             0x00000700,     //BANKCON3  
    28                                             0x00000700,     //BANKCON4
    29                                             0x00000700,     //BANKCON5
    30                                             0x00018005,     //BANKCON6
    31                                             0x00018005,     //BANKCON7
    32                                             0x008C07A3,     //REFRESH
    33                                             0x000000B1,     //BANKSIZE
    34                                             0x00000030,     //MRSRB6
    35                                             0x00000030,     //MRSRB7
    36                                     };
    37 
    38     for(; i < 13; i++)
    39         p[i] = mem_cfg_val[i];
    40 }

     上面设置sdram寄存器的方法是用c语言,现在贴出汇编的方法来比较;

     1 memsetup:
     2     @ 设置存储控制器以便使用SDRAM等外设
     3 
     4     mov r1,     #MEM_CTL_BASE       @ 存储控制器的13个寄存器的开始地址
     5     adrl    r2, mem_cfg_val         @ 这13个值的起始存储地址
     6     add r3,     r1, #52             @ 13*4 = 54
     7 1:  
     8     ldr r4,     [r2], #4            @ 读取设置值,并让r2加4
     9     str r4,     [r1], #4            @ 将此值写入寄存器,并让r1加4
    10     cmp r1,     r3                  @ 判断是否设置完所有13个寄存器
    11     bne 1b                          @ 若没有写成,继续
    12     mov pc,     lr                  @ 返回
    13 
    14 
    15 .align 4
    16 mem_cfg_val:
    17     @ 存储控制器13个寄存器的设置值
    18     .long   0x22011110      @ BWSCON
    19     .long   0x00000700      @ BANKCON0
    20     .long   0x00000700      @ BANKCON1
    21     .long   0x00000700      @ BANKCON2
    22     .long   0x00000700      @ BANKCON3  
    23     .long   0x00000700      @ BANKCON4
    24     .long   0x00000700      @ BANKCON5
    25     .long   0x00018005      @ BANKCON6
    26     .long   0x00018005      @ BANKCON7
    27     .long   0x008C07A3      @ REFRESH
    28     .long   0x000000B1      @ BANKSIZE
    29     .long   0x00000030      @ MRSRB6
    30     .long   0x00000030      @ MRSRB7

    同样是往这13个寄存器写值。

    而main函数只是led的亮灭,这里就不贴出来了

    现在主要看nand.c文件。

    先贴出来如下:

    //===================================我是分解线=============================

    //@nand.c

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



  • 相关阅读:
    微信小程序:动画(Animation)
    小程序滚动事件之头部渐隐渐现demo
    小程序tab栏可滑动,可点击居中demo
    ES7中前端异步特性:async、await。
    vue中生成二维码
    vue之vue-cookies
    echarts中boundaryGap属性
    ES6数组方法总结
    手写自己的ORM框架For SQlServer(简单的CURD)
    Sqlsever新增作业执行计划傻瓜式操作
  • 原文地址:https://www.cnblogs.com/hulig7/p/4060462.html
Copyright © 2020-2023  润新知