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 }



优质内容筛选与推荐>>
1、JavaScript While 循环
2、转载:解密Redis持久化
3、2008年微软(北京).NET俱乐部年会 - 照片纪实
4、基于visual Studio2013解决C语言竞赛题之0707月份输出
5、Linux学习笔记(4)磁盘分区(fdisk)、挂载与文件系统命令


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn