四、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

猜你喜欢

转载自www.cnblogs.com/kele-dad/p/8922391.html