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 }

 



你可能感兴趣的:(Flash)