NandFlash驱动设计
NandFlash种类nandflash在嵌入式系统中的角色和硬盘在电脑中的角色一样。 MLC与SLC对比: 访问方式内存采用统一编址:cpu有地址空间,在这个地址空间给内存分配了地址。因此,要访问内存只需要访问相应的地址就可以。内存需要用地址线和数据线和cpu连接。 Nandflash采用独立编址:与内存不同,cpu并没有给nandflash分配地址空间,nandflash处于cpu地址空间之外,因此称为独立编址。 在cpu内部有nandflash控制器,该控制器与nandflash连接。当要访问nandflash某个地址时, nandflash控制器中有地址寄存器、命令寄存器、数据寄存器,需要访问nandflash时程序只需往这三个寄存器写入相应的地址、命令、数据即可。 nandflash结构一个nandflash可分为多个blocks,每个block可分为多个pages,每个page分为数据区和空闲区,数据区用于存放数据,空闲区用于存放校验码等信息。如上图共有2048个blocks,每个block分为64pages,一页分为2K和64B两个区域。 nandflash信号引脚: 读取nandflash数据nandflash有两种读数据方式: 页读信号流程: 从指令表格可看出,00h和30h这两个指令是读数据指令,所以页读流程中发送的指令为00h和30h。从I/O引脚可看出,页读第一步是发送00h,第二步是分5轮发送地址,第三步是发送命令30h,第四步是等待R/B信号,当其从低电平变为高电平时开始读取数据。判断R/B信号从低电平变为高电平是通过读取一个寄存器的某一位的值来判断的,因此在等待前需要对该寄存器进行清除;在对nandflash进行操作前需要选中nandflash芯片,操作完成后需要取消选中的nandflash芯片,因此页读流程为: 接下来说明以上8步骤的实现方法。查阅S3C2440数据手册,可得关于nandflash控制的寄存器: 1.选中与取消选中nandflash芯片 2.清除R/B与判断等待R/B是否结束 3.发送命令 因为是页读,所以偏移量为0,即发送列地址为0;发送行地址是先发送最低8位,最后才发送最高8位 5.接收数据 以上是nandflash读数据的步骤,但读数据前需要初始化nandflash。初始化分为三步:初始化NFCONF寄存器、初始化NFCONT寄存器、复位。 由上图可知,twp>12ns,tcls>12ns,tclh>5ns. 其中TACLS=tcls-twp,TWRPH0=twp,TWRPH1=tclh 因此步骤为: 之前代码搬迁时我们是将代码从iram复制到内存,现在初始化好nandflash,我们可以将代码从nandflash搬移到内存了。代码搬移使用的是页读。因为使用的是c语言,因此在reset中需要将初始化c语言环境搬到代码搬移前面。 reset:
bl set_svc
bl disable_watchdog
bl disable_interrupt
bl disable_mmu
bl init_clock
bl init_sdram
bl init_stack
bl nand_init
bl copy_to_ram
bl clean_bss
ldr pc,=gboot_main
copy_to_ram:
mov r0,#0 @r0的值会作为nand_to_ram的第一个参数传递过去
ldr r1,=_start @r1的值会作为nand_to_ram的第二个参数传递过去
ldr r2,=bss_end
sub r2,r2,r1 @r3的值会作为nand_to_ram的第三个参数传递过去
mov ip,lr
bl nand_to_ram
mov lr,ip
mov pc,lr
void nand_to_ram(unsigned long start_addr,unsigned char* sdram_addr,int size)
{
int i;
for( i=(start_addr >>11); size>0;)
{
NF_PageRead(i,sdram_addr);
size -= 2048;
sdram_addr += 2048;
i++;
}
}
往nandflash写数据与nandflash读数据相对,写数据也有两种方式,页写和随机写。 由上可以得出页写的步骤流程: 但有了以上步骤还无法实现写数据,对于nandflash,若要进行写数据则必须先对nandflash进行擦除。擦除流程图为: 以上是块擦除方式,也即不仅仅擦除该页的数据,还擦除该页所在的块的数据。 int NF_Erase(unsigned long addr)
{
int ret;
//选中flash芯片
select_chip();
//清除RnB
clear_RnB();
//发送命令0x60
send_cmd(0x60);
//发送行地址
send_addr(addr&0xff);
send_addr((addr>>8)&0xff);
send_addr((addr>>16)&0xff);
//发送命令D0
send_cmd(0xD0);
//等待RnB
wait_RnB();
//发送命令0x70
send_cmd(0x70);
//读取擦除结果
ret = NFDATA;
//取消选中flash芯片
deselect_chip();
return ret;
}
int NF_WritePage(unsigned long addr,unsigned char* buff)
{
int ret;
int i;
//选中flash芯片
select_chip();
//清除RnB
clear_RnB();
//发送命令0x80
send_cmd(0x80);
//发送列地址
send_addr(0x00);
send_addr(0x00);
//发送行地址
send_addr(addr&0xff);
send_addr((addr>>8)&0xff);
send_addr((addr>>16)&0xff);
//写入数据
for(i=0;i<2048;i++)
{
NFDATA = buff[i];
}
//发送命令0x10
send_cmd(0x10);
//等待RnB
wait_RnB();
//发送命令0x70
send_cmd(0x70);
//读取写入结果
ret = NFDATA;
//取消选中flash芯片
deselect_chip();
return ret;
}
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |