小标
2018-08-24
来源 :
阅读 1656
评论 0
摘要:本文主要向大家介绍了Flash基础入门之NAND Flash,通过具体的内容向大家展现,希望对大家学习Flash基础入门有所帮助。
本文主要向大家介绍了Flash基础入门之NAND Flash,通过具体的内容向大家展现,希望对大家学习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
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标常用软件Flash频道!
喜欢 | 0
不喜欢 | 0
您输入的评论内容中包含违禁敏感词
我知道了

请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号