7215|19

34

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

裸板程序之nand操作 [复制链接]

先附上源码,晚点再分享过程。

SdBoot.rar

27.88 KB, 下载次数: 12

制作脚本

nandflash.zip

2.44 KB, 下载次数: 27

直接make

最新回复

加油楼主 :)   详情 回复 发表于 2015-4-30 14:32

赞赏

1

查看全部赞赏

点赞 关注

回复
举报

34

帖子

0

TA的资源

一粒金砂(中级)

推荐
 
下面我们就用这些基础的nand函数,来组成对nand的页操作,块操作。
int nand_erase(uint block)
{
        uint blocknum=block<<6;
        nand_reset();
        nand_enable();
        nand_enable_rb();
        nand_write_com(0x60);
        nand_write_addr(blocknum & 0xff);
        nand_write_addr((blocknum>>8)&0xff);
        nand_write_addr((blocknum>>16)&0xff);
        nand_write_com(0xD0);
        nand_check_busy();
        nand_disable();
        return 1;
}
无非就是使能nand,开启忙检。发送第一个命令(可以注意到,发送了两次不同的命令。)
为什么是两次?应该考虑到nand是一个高速工作状态下的设备。在nand_init函数里,可以看到NFCONF函数的3个时序参数均被设置为20ns左右。所以,nand是非常讲究工作的效率的。并非是你说要开始nand擦除操作,cpu就会马上操作。它需要一个更确定的时机,比如你已经把地址写进控制器了,它才开始做事。


然后,更重要的!!!! 发送了3次地址,按照常理,不是发送一次就行了吗?

只能说,接口电路很重要,请回头去板子的nand接口,你会发现,2416的nand接口的数据线和地址线是复用的
而nand的地址是28位的,因此不能一次发送完。(好像没人看。。就简单点写了)
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

沙发
 
板子上的nandflash型号是k9f2g08u0c,属于大页nand。
强烈建议先去翻看一下核心板原理图上nandflash的接口电路。
可以发现,nand是接在了2416内部集成的nand控制器上。2416本身片上就有存储器控制(板子上接的是sdram),
nand控制器(控制nand的时序),lcd控制器(控制lcd时序,中间会用到adc,曾经提到过的xp,xm这些路)。
问题来了,这些控制器的作用是什么呢?

控制器主要是为了产生相应的时序,有过单片机io操作经历的应该能很容易理解。比如你在单片机上操作lcd时,要发送命令,需要把数据/命令选择线拉低,再把数据发送到数据线上。
而控制器则是简化了这一过程,当你在代码里把数据发送到数据线上时,控制器会自动的帮你把相应的操作完成,
这样一来,即节省了cpu的占用,又简化了代码。
 
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

板凳
 
上课=-=,晚上接着分享吧。

点评

加油楼主 :)  详情 回复 发表于 2015-4-30 14:32
 
 
 

回复

2万

帖子

74

TA的资源

管理员

4
 
影子的影子 发表于 2015-4-30 14:18
上课=-=,晚上接着分享吧。

加油楼主 :)

加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
个人签名

加油!在电子行业默默贡献自己的力量!:)

 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

5
 
nand的容量=块的数目*每块包含的页数*每页的容量
板子上用的nand属于大页nand,2k块*64页*(2k+64)=容量
这里可以注意一下,每页的容量是2k+64字节,2k指的是可以存储信息的存储单元,在未写入状态下是1,所以擦除nand,就是往存储单元写1.64bytes,指的是这一页的控制信息。包括支持随机读写,ecc的校验值,都在这64字节里。
打开control.c             @vi  control.c

关于nand的基础操作函数都是以宏定义方式存在的。
 
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

6
 
主要有这么几个函数
#define nand_write_com(cmd)       {NFCMMD=(cmd);}发送命令给nand,通过操作nand控制器的NFCMMD寄存器
#define nand_write_addr(addr)     {NFADDR=(addr);}
#define nand_write_dat(dat)       {NFDATA8=(dat);}类似的数据和地址发送函数。
#define nand_enable()             {NFCONT &= ~(1<<1);}使能nand函数
#define nand_disable()            {NFCONT |=(1<<1);}不选中nand
2416应该有两个nand控制器?  读数据手册时要注意选择操作标号为0的寄存器
#define nand_enable_rb()          {NFSTAT |=(1<<2);}
#define nand_check_busy()         {while(!(NFSTAT & (1<<0)));}
这两个函数要特别讲一下,nand_enable_rb(),意思是开启忙信号检测功能,开启这个功能后,当nand处于忙状态时,NFSTAT寄存器的第0位会置0,可操作是会置1.我们在各个操作之间,就以检查忙状态函数间隔,这样,才能正确操作nand。如果,不加忙检,读取可能会出错,我就是在这一步,卡了许久。
 
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

8
 
其他的页读,页写函数大同小异,自行分析吧==
关于读id函数,这里介绍一下id。
直白的说就是nand的身份证,通过读取id,可以得知nand的一些信息。恰好工程文件我最后留下的就是这个函数,直接make后下载到sdcard里,启动,连接串口0(注意是串口0,要用串口1的话修改代码里的uart_init函数)
串口就会打印出EC DA 10 95 44
第一位是制造商码,不管
第二位是产品码  ,不管
其他3位则是产品的细节,对应nand的datesheet,可以得知nand的基本属性(uboot和内核都是通过这个方法来得到nand的信息并进行相应操作的)。
补充一下。nand。c里的主函数control,,,你把我注释掉的程序去掉注释,可以打印循环0-0xff的数,
也就是先页写,再把这一页读出来。算是印证了操作的正确性吧。
 
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

9
 
爆炸,写了一大段没发出来。
 
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

10
 
读id函数,void nand_read_id(uchar *buf)
{
        int i;
        nand_enable();
        nand_enable_rb();
        nand_write_com(0x90);
        nand_write_addr(0x0);
        for(i=0;i<100;i++);
        *buf =nand_read_byte();
        *(buf+1) =nand_read_byte();
        *(buf+2) =nand_read_byte();
        *(buf+3) =nand_read_byte();
        *(buf+4) =nand_read_byte();
     nand_disable();
}读取出来的5个数字  ,第1,2位是厂家和产品,不要管
3-5位对应查手册,可以得到详细的nand参数。
uboot和内核都是通过此得到设备信息并操作的
 
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

11
 
剩下的nand随机操作,坏块识别,复制代码到sdram。。明天再说
 
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

12
 
放假拖更了==现在说一下页内读写
 
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

13
 
void nand_Ramdomwrite(uint block,uint page,uint add,uint length,uchar *dat)
{
            uint i;
                page +=(block<<6);
                nand_enable();
                nand_enable_rb();
                nand_write_com(0x80);
                nand_write_addr(0x00);
                nand_write_addr(0x00);
                nand_write_addr((page)&0xff);
                nand_write_addr((page>>8)&0xff);
            nand_write_addr((page>>16)&0xff);
            nand_write_com(0x85);
                nand_write_addr((char)add&0xff);
                nand_write_addr((char)(add>>8)&0x0f);
                for(i=0;i                 {
                nand_write_dat(dat[i]);
                }
                nand_write_com(0x10);
                nand_check_busy();
                nand_disable();
}
随机写,名字虽说是随机写==但是事实上的作用是对某一块一页内某一存储单元起的length长度写入dat
和页写函数没有太大差别。
可能难点是在于地址的理解。首先,第一句计算页号,这里说的地址是绝对地址,是相对于nand第1块第1页的地址,所有将block乘上64倍。这里用左移6位代替运算。这里要注意,直接使用乘除这类操作,是很浪费cpu资源的。然而移位操作要好的多。具体设计到cpu的架构,仅作了解就好
 
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

14
 
void nand_Ramdomread(uint block,uint page,uint add,uint length,uchar *buf)
{
        uint i;
        page+=(block<<6);
        nand_reset();
        nand_enable();
        nand_enable_rb();
        nand_write_com(0x00);
        nand_write_addr(0x00);
        nand_write_addr(0x00);
        nand_write_addr((page)&0xff);
        nand_write_addr((page>>8)&0xff);
        nand_write_addr((page>>16&0xff));
        nand_write_com(0x30);
        nand_check_busy();
        nand_write_com(0x05);
        nand_write_addr((char)add&0xff);
        nand_write_addr((char)(add>>8)&0x0f);
        nand_write_com(0xe0);
        nand_check_busy();
        for(i=0;i         {
        buf[i]=nand_read_byte();
    }
        nand_disable();
}

随机读函数。
这里说一下关于地址发送次数的问题
大家可以看到,当我们发送页地址时,产生了5次地址的发送,而页内地址仅发送两次,这是为什么呢?
 
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

15
 
再次打开helper2416原理图
找到nand接口,再次注意!!!   很重要的一点,nand接口只有地址总线的接口,和存储控制器接口不同,nand接口并没有数据总线接口。

地址总线A0-A28这29根地址总线用来进行nand寻址
如图片所示

因为2416板子上所用的是大页nand,每页容量为2k+64bytes

所有需要A0-A11这12根地址线来寻址(2的12次方是2k),这就是列地址,即在一页中的地址,请回头找一下我在前面nand.c中对NFADDR的定义。这个数据缓冲寄存器是一个8位寄存器,所以,在发送页内地址时。需要2次。第一次发送地址的低8位,再发送高4位,当然,此时要记得屏蔽掉地址的后面几位。

同理,整个nand有2k块,每块64页,一块nand就有128k个页面,需要A12-A28这17根地址线。发送5次地址

。可能看到这里有一个疑问,对整个nand来说,地址是28位,寻址不应该只需要发送地址4次就足够?

这其中涉及到行地址与列地址的不同。请看我的附图,前两次发送了页内地址(即列地址)

后3次才是行地址,第二次发送地址时。并没有全部使用8个位。

这个比较抽象,有疑问可以提出来,我再和你说。

QQ截图20150504221427.png (21.02 KB, 下载次数: 0)

QQ截图20150504221427.png
 
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

16
 
void Nand_IsBadBlock(uint block)
{
        uchar Data;
       
        nand_Ramdomread(block, 0, 2054, 1, &Data);
        if (Data != 0xff) {
                putc('b');
                putc('a');
                putc('d');
                putc('b');
                putc('l');
                putc('o');
                putc('c');               
                putc('k');                                // 坏块
        }
}
坏块识别,没什么难点。每个block第一页spare(即64bytes)区第6字节非0xff标记为好坏。所以读出第2048+6个存储单元的值,判断是否等于0xff。
这里有一个很有意思的地方,我们都知道,nandearse会把擦除后的单元恢复为0xff。
这就印证一点,nandearse擦除的只有main区(2k)
 
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

17
 
把代码搬移到sdram这个还得再弄弄,明天再说吧
 
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

18
 
另外有没有谁教我下字符串输出函数怎么整我一个个字符打的累
 
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

19
 
结尾一下,把nand某一地址起的length长度读取到缓冲区域。刚刚调好了。传一下工程文件有兴趣的看看吧,明天开始看sdram部分,把这部分初始化好。再把缓冲区域的数据写入,就能实现代码从外部rom到内存的过程啦!
 
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

20
 
最后的文件操作是擦除nand第0块,把里面的内容全部变为0xff。再用批量读取函数Nand_readskipbad()读取到缓冲区域(即数组b),再以16进制打印数组b的内容。用串口调试软件印证,得到0xff。说明正确。批量读取函数里的坏块跳过部分挺有意思的,可以仔细分析下

nand.zip

4.02 KB, 下载次数: 14

最新工程文件

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表