NAND FLASH
来源:互联网 发布:java中的设计模式详解 编辑:程序博客网 时间:2024/04/30 22:13
当OM1、OM0都是低电平——即开发板插上BOOT SEL跳线时,S3C2410从NAND Flash启动:NAND Flash的开始4k代码会被自动地复制到内部SRAM中。我们需要使用这4k代码来把更多的代码从NAND Flash中读到SDRAM中去。NAND Flash的操作通过NFCONF、NFCMD、NFADDR、NFDATA、NFSTAT和NFECC六个寄存器来完成。在开始下面内容前,请打开S3C2410数据手册和NAND Flash K9F1208U0M的数据手册。
在S3C2410数据手册218页,我们可以看到读写NAND Flash的操作次序:
1. Set NAND flash configuration by NFCONF register.
2. Write NAND flash command onto NFCMD register.
3. Write NAND flash address onto NFADDR register.
4. Read/Write data from NFDATA while checking NAND flash status by NFSTAT
register. R/nB signal should be checked before read operation or
after program operation.
下面依次介绍:
1、NFCONF:设为0xf830——使能NAND Flash控制器(15位)、初始化ECC(12位)、NAND Flash片选信号nFCE=1(inactive也就是未激活,真正使用时再让它等于0,一般在自启动后这位都会被置为1,等到真正需要使用NAND FLASH时才激活这位)、设置TACLS、TWRPH0、TWRPH1。需要指出的是TACLS、TWRPH0和TWRPH1,请打开S3C2410数据手册218页,
可以看到这三个参数控制的是NAND Flash信号线CLE/ALE与写控制信号nWE的时序关系。我们设的值为TACLS=0,TWRPH0=3,TWRPH1=0,其含义为: TACLS=1个HCLK时钟,TWRPH0=4个HCLK时钟,TWRPH1=1个HCLK时钟。请打开K9F1208U0M数据手册第13页,在表“AC Timing Characteristics for Command / Address / Data Input”中可以看到:
CLE setup Time = 0 ns,CLE Hold Time = 10 ns,
ALE setup Time = 0 ns,ALE Hold Time = 10 ns,
WE Pulse Width = 25 ns
可以计算,即使在HCLK=100MHz的情况下,TACLS+TWRPH0+TWRPH1=6/100 uS=60
ns,也是可以满足NAND Flash K9F1208U0M的时序要求的。
2、NFCMD:
对于不同型号的Flash,操作命令一般不一样。对于本板使用的K9F1208U0M,请打开其数据手册第8页“Table 1. Command Sets”,上面列得一清二楚。下面在分析源代码是会涉及到Flash的命令,该寄存器一般也只用后八位也就是[7:0]。
3、NFADDR:同样也只用到该寄存器的后八位
4、NFDATA:只用到低8位,这个寄存器中涉及到读和写两种状态,如果NFCMD中是读命令,则可以直接从这个寄存器中读出对应地址的值,如果是写命令则是Programming data。
5、NFSTAT:只用到位0,0-busy,1-ready
6、NFECC:待补
现在来看一下如何从NAND Flash中读出数据,请打开K9F1208U0M数据手册第29页“PAGE READ”,跟本节的第2段是遥相呼应啊,提炼出来罗列如下(设读地址为addr)首先从汇编代码上来分析:
前面的对看门狗,SDRAM的初始化与上面都是一样的,主要来看看对NAND FLASH操作的这一块:
copy_myself:
mov r10, lr //前面代码中是通过bl copy_myself来进入到该程序段来执行,所以必须要保存lr,当使用bl或者blx跳转到子过程的时候,r14保存了返回地址,可以在调用过程结尾恢复
@ inital
mov r1, #NAND_CTL_BASE
ldr r2, =0xf830 @ initial value
str r2, [r1, #oNFCONF] //初始化NFCONF寄存器
@ reset nand flash
ldr r2, [r1, #oNFCONF] //将NFCONF寄存器中的值赋给r2
bic r2, r2, #0x800 @ nFCE active 在第一次操作NAND Flash前,通常复位一下,相当于NFCONF &= ~0x800 (使能NAND Flash) ,也就是将NFCONF寄存器的11位使能NAND FLASH的片选信号激活,这样后续才能对FLASH操作
str r2, [r1, #oNFCONF]
mov r2, #0xff @ reset command
strb r2, [r1, #oNFCMD] //NFCMD = 0xff (reset命令) 在这里就涉及到FLASH的命令行拉,这里0xff表示的是reset命令
@ delay
mov r3, #0x0a //一段延迟代码,用来等待一段时间然后再来检测NFSTAT是否准备好
1:
subs r3, r3, #1
bne 1b
@ wait idle state
2:
ldr r2, [r1, #oNFSTAT]
tst r2, #0x01 //tst指令:位测试比较指令,主要来测试r1的第0位是否为1,将r2与0x01相与来查看r2的最后一位是否为1,不为1则表示NAND FLASH还没准备好,则循环等待
beq 2b
ldr r2, [r1, #oNFCONF]
orr r2, r2, #0x800 @ nFCE inactive 如果FLASH已经准备好了,则将FLASH重新设置为未激活也就是NFCONF |=0x800,也就是相当于保存当前的状态,然后等到在C代码中要实际操作FLASH由重新激活
str r2, [r1, #oNFCONF]
ldr sp, =4096 @ nand_read.c needed 在上个例子中讲过因为涉及到C函数的调用所以需要进出栈,所以必须要设置堆栈
ldr r0, =0x30000000 @ nand_read_ll argument 1 为C函数的调用准备好参数,r0:SDRAM的起始地址,为目的地址
mov r1, #4096 @ nand_read_ll argument 2 因为NAND FLASH前4K的数据早就自动的读到steppingstone中,所以需要从4K之后开始读取,所以r1就是源地址
mov r2, #1024 @ nand_read_ll argument 3 r3表示要读取数据的大小 在这里是要读取1K的数据
@ 1024 enough for this example
bl nand_read_ll //调用C函数nand_read_ll
mov pc, r10 //调用C函数完毕后返回原调用处
继续来看看利用C语言来的FLASH进行操作:
#define NFCONF (*(volatile unsigned int *)0x4e000000)
#define NFCMD (*(volatile unsigned int *)0x4e000004)
#define NFADDR (*(volatile unsigned char *)0x4e000008)
#define NFDATA (*(volatile unsigned char *)0x4e00000c)
#define NFSTAT (*(volatile unsigned char *)0x4e000010)
上面是定义NAND FLASH寄存器的地址。再来看看真正的FLASH 读函数:
#define NAND_SECTOR_SIZE 512 //nand flash 每个扇区的大小为512B
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)
/* low level nand read function */
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{ //可以看到从汇编语言中传递过来的参数buf为目的地址SDRAM的0x30000000,start_addr则是FLASH中的源地址
int i, j;
/*
* K9F5608UOC asks for 512B per page, and read/write operation must
* do with page. Therefore, first judge whether start_addr and size
* are valid.
*/
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) { 检查FLASH中开始地址和药读取的大小是否是按页为单位的。
return -1; /* invalid alignment */
}
/* chip Enable */因为要开始对FLASH进行操作了,所以需要将FLASH的片选激活
NFCONF &= ~0x800;
for (i=0; i<10; i++) {
;
}
//正式开始从FLASH中读取数据到SDRAM中
for (i=start_addr; i < (start_addr + size); i+=NAND_SECTOR_SIZE) {
NFCMD = 0;//将FLASH命令寄存器设置为0x0表示是读命令
/* Write Address */ 这步得稍微注意一下,请打开K9F1208U0M数据手册第7页,那个表格列出了在地址操作的4个步骤对应的地址线,A8没用到:
NFADDR = i & 0xff;
NFADDR = (i >> 9) & 0xff; (注意了,左移9位,不是8位)
NFADDR = (i >> 17) & 0xff; (左移17位,不是16位)
NFADDR = (i >> 25) & 0xff; (左移25位,不是24位)
wait_idle();在地址,命令都设置好后,我们就循环的等待NFSTAT的最后一位为1也就是准备好了,然后才开始从NFDATA读数据
for(j=0; j < NAND_SECTOR_SIZE; j++) { //连续读NFDATA寄存器512次,得到一页数据(512字节)
*buf++ = (NFDATA & 0xff);
}
}
/* chip Disable */
NFCONF |= 0x800; /* chip disable */
return 0;
}
本实验代码在NAND目录下,源代码为head.s、nand_read.c和main.c。head.s中关WATCH DOG、初始化SDRAM、初始化NAND Flash,然后调用nand_read.c中的nand_read_ll函数来从NAND Flash地址4096开始处复制到SDRAM中,最后,跳到main.c中的
main函数继续执行。代码本身没什么难度,与前面程序最大的差别就是“链接脚本”的引入:在上个实验中最后一段提到过在arm-linux-ld命令中,选项“-Ttext”可以使用选项“-Tfilexxx”来代替。在本实验中,使用“-Tnand.lds”。nand.lds
内容如下:
1 SECTIONS {
2 firtst 0x00000000 : { head.o init.o } 也就是相当于FLASH的前4K用来存放head.o以及init.o,自启动时加载到steppingstone并且在该地址执行
3 second 0x30000000 : AT(4096) { main.o }
4 }
完整的连接脚本文件形式如下:
SECTIONS {
...
secname start BLOCK(align) (NOLOAD) : AT ( ldadr )
{ contents } >region :phdr =fill
...
}
并非每个选项都是必须的,仅介绍nand.lds用到的:
1、secname:段名,对于nand.lds,段名为first和second
2、start:本段运行时的地址,如果没有使用AT(xxx),则本段存储的地址也是start ,这就是我们所讲的运行时域和加载时域
3、AT( ldadr ):定义本段存储(加载)的地址
4、{ contents }:决定哪些内容放在本段,可以是整个目标文件,也可以是目标文件中的某段(代码段、数据段等)
nand.lds的含义是:head.o放在0x00000000地址开始处,init.o放在hean.o后面,它们的运行地址是0x00000000;main.o放在地址4096(0x1000)开始处,但是它的运行地址在0x30000000,在运行前需要从4096处复制到0x30000000处。
- Nand Flash
- NAND Flash
- nand flash
- NAND FLASH
- NAND FLASH
- nand flash
- Nand Flash
- NAND Flash
- NAND FLASH
- nand flash
- nand flash
- Nand flash
- NAND FLASH
- NAND FLASH
- NAND Flash
- Nand flash
- nand flash
- NAND FLASH
- zoj 1648 Circuit Board
- 读懂邮件头信息
- Android中的onCreateOptionsMenu()方法和onOptionsItemSelected()方法示例
- c# cs 文件清理缓存代码
- mkl中dsytri求解矩阵的逆
- NAND FLASH
- 在ASP.NET中使用IHttpHandler处理请求(如自实现AJAX)时,无法获得Session(或者说是Session 为 null)的原因及解决方法
- 更改Textiew背景色和字体颜色
- (一)libvirt库简介
- C#课后练习
- 电子邮件的工作原理
- 如何实现用更少的空间表示英文字母(a ~ z)构成char A[n]字符串
- zoj 2545
- java 编码2 url