关于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 }