nandflash驱动设计
一:Nandflash驱动设计写的流程 1,?知道要读的东西??即:芯片选择为nandflash?方式:NFCOPNT-》对应位使有效; 2??清除RnB?即:使其进入空闲状态?方式:NFCONF—》对应位是空闲(清除要写入1才能变0) 3??发送页读指令周期0x00?方式:?NFCMMD=0x00 4??发送列地址和行地址?方式:NFADDR=addr ????注:?行地址是页号,列地址是页内偏移,若是页读则列地址发送0x00就行 ????????若是随机读取则需要定位列地址和行地址 5?发送页读命令周期0x30?方式:NFCMMD=0x30 6?等待RnB??即;等待CPU将前面的工作完成之后使RnB进入忙?方式:检测NFSTAT??????中对应位是否为1,为1等待结束,为0等待继续 7?读取数据?方式:?将NFDATA中的数据传给制定缓冲?eg?buff[i]=NFDATA 8?取消nandflash芯片选择?方式:?NFCONT?使对应为无效 我理解的发送两次页读命令周期:第一次发送0x00?是进行读前的准备工作?即找读的地址?等???第二次发送0x30?是进行真正的将数据从nandflash中读取到缓冲中??同理到其他的周期命令中:一般第一次是准备工作,第二次是进行工作 ? 二:?一切工作看似已经完成,其实还有,这个可能还是用与其他大部分的驱动程序。那就 是在使用一个设备时要先初始化这个设备,在次?我们要初始化的是nandflash 其实在之前初始化的东西很多,比如在用C编写的话要初始化堆栈。还有要初始化SDRAM????总之一句话那就是用到什么就要先初始化什么 ? 1?初始化NFCONFF?其实是初始化NFCONF中的三个位即?TACLS?TWRPH0?TWRPH1 ??因为他们三个基本决定了读取数据的一些重要时间:(具体大小需要按照不同类型的nandflash进行计算,但一般原则是它们的值大一点比较稳定) 2??初始化NFCONT?设置REG_nCE位为1?MOND位为1?即?使片选信号无效 并开启控制器 3?复位?? A?选中nandflash芯片?同上 B?清除RnB?同上 C?发送命令?0xff(reset?命令周期) D?等待?RnB?同上 E?取消选中nandflash 三:?在汇编语言中即程序入口处调用读取页的函数,并用相应的寄存器传参; 四:nandflash驱动的写和读差不多: 参考的芯片手册与文档:S3C2440文档;K9GAG08U0D(nandflash芯片文档) 6410与210都差不多就是寄存器地址与相应的位需要变一下; 代码如下: #define?NFCONF?(*(volatile?unsigned?long*)0x4E000000) #define?NFCONT?(*(volatile?unsigned?long*)0x4E000004) #define?NFSTAT?(*(volatile?unsigned?char*)0x4E000020) #define?NFCMD??(*(volatile?unsigned?char*)0x4E000008) #define?NFADDR?(*(volatile?unsigned?char*)0x4E00000C) #define?NFDATA?(*(volatile?unsigned?char*)0x4E000010) ? #define?TACLS?1 #define?TWRPH0?2 #define?TWRPH1?1 ? ? void?select_chip() { ????NFCONT?&=?~(1<<1); } ? void?deselect_chip() { ????NFCONT?|=?(1<<1); } ? void?clear_RnB() { ???NFSTAT?|=?(1<<2);? } ? void?send_cmd(unsigned?cmd) { ?????NFCMD?=?cmd; } ? void?send_addr(unsigned?addr) { ?????NFADDR?=?addr; } ? void?wait_RnB() { ???while?(!(NFSTAT&(1<<2))) ???{ ???????; ???} } ? void?nand_reset() { ????//选中flash ????select_chip(); ???? ????//清除RnB ????clear_RnB(); ???? ???? ????//发送0xff命令 ????send_cmd(0xff); ???? ???? ????//等待RnB ????wait_RnB(); ???? ????//取消选中flash ????deselect_chip(); } ? void?nand_init() { ????//初始化NFCONF ????NFCONF?=?(TACLS<<12)?|?(TWRPH0<<8)?|?(TWRPH1<<4); ???? ????//初始化NFCONT ????NFCONT?=?(1<<0)?|?(1<<1); ???? ????//复位 ????nand_reset(); } ? void?NF_PageRead(unsigned?long?addr,unsigned?char*?buff) { int?i; //选中nandflash芯片 select_chip(); //清除RnB clear_RnB(); //发送命令0x00 send_cmd(0x00); //发送列地址 send_addr(0x00); send_addr(0x00); //发送行地址 send_addr(addr&0xff); send_addr((addr>>8)&0xff); send_addr((addr>>16)&0xff); //发送命令0x30 send_cmd(0x30); //等待RnB wait_RnB(); //读取数据 for(i=0;i<2048;i++) { ???buff[i]?=?NFDATA;?? } //取消选中nandflash芯片 deselect_chip(); } ? ? 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++; } } ? void?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; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- ruby-on-rails – 使用Rails查看助手与Haml :: Engine
- C++中insert iterator/iostream iterator的使用方法(详细)
- 领域驱动设计战略原则
- ruby-on-rails – 升级到Ruby 2.1.1和Rails 4.1后,Rake doc
- c – 作为函数返回值返回的局部变量(堆栈)
- c – 绑定左值给rvalue引用 – g bug?
- winforms – 在两个列表框之间拖放
- PLSQL Developer连接Oracle11g 64位
- Swift学习第十二枪----移动数据库王者Realm入门教程
- cocos2d-x学习笔记3:更改HelloWorld,建立自己的小项目