loadb 20000000 //(1)
nand erase 0x100000 0x200000 //(2)
nand write 0x20000000 0x100000 0x200000 -//(3)
nand read 0x20000000 0x100000 0x200000 -//(4)
(1) 从串口下载到SDRAM的0x20000000处
(2) 从1M处开始擦写Nand Flash,擦写2M大小的空间
(3) 将SDRAM中的0x20000000处开始的内容,烧写到Nand Flash的0x100000处开始的2M空间内
(4) 将Nand Flash的0x100000处开始的2M空间内容,拷贝到SDRAM中0x20000000处开始的地方
Nand flash芯片工作原理
------------------------------------
Nand flash芯片型号为Samsung K9F1208U0B,数据存储容量为64MB,采用块页式存储管理。8个I/O
引脚充当数据、地址、命令的复用端口。
芯片内部存储布局及存储操作特点:
一片Nand flash为一个设备(device), 其数据存储分层为:
1 (Device) = 4096 (Blocks)
1 (Block) -= 32 (Pages/Rows) 页与行是相同的意思,叫法不一样
1 (Page) = 528 (Bytes) = 数据块大小(512Bytes) + OOB 块大小(16Bytes)
在每一页中,最后16个字节(又称OOB)用于Nand Flash命令执行完后设置状态用,剩余512个字节又
分为前半部分和后半部分。可以通过Nand Flash命令00h/01h/50h分别对前半部、后半部、OOB进行定位通过
Nand Flash内置的指针指向各自的首地址。
存储操作特点:
1. 擦除操作的最小单位是块。
2. Nand Flash芯片每一位(bit)只能从1变为0,而不能从0变为1,所以在对其进行写入操作之前要一定将相应块擦除(擦除即是将相应块得位全部变为1).
3. OOB部分的第六字节(即517字节)标志是否是坏块,如果不是坏块该值为FF,否则为坏块。
4. 除OOB第六字节外,通常至少把OOB的前3个字节存放Nand Flash硬件ECC码
------------------------------------
下面对nand flash的初始化代码nand_init()进行分析:
1.如果定义(CONFIG_COMMANDS & CFG_CMD_NAND)没定义(CFG_NAND_LEGACY) 则start_armboot()调用driver/nand/nand.c中的nand_init(),否则如果定义(CONFIG_COMMANDS & CFG_CMD_NAND)并且有定义了CFG_NAND_LEGACY,则调用自己定义的nand_init()。在我当前的情景中是使用driver/nand/nand.c中的nand_init()。
2.nand_init()调用本文件中的nand_init_chip()对nand进行初始化。
3.nand_init_chip()首先调用board_nand_init()。
4.board_nand_init()是需要自己添加的函数,这个函数的主要功能是对struct nand_chip结构体的函数指针赋值,让它们指向自己为nand驱动编写的一些函数,对未赋值的指针,uboot会在后面为其赋上通用nand驱动函数指针。
5.nand_init_chip()接着调用nand_scan().
6.nand_scan()定义在drivers/nand/nand_base.c文件中。它首先对struct nand_chip结构体中在board_nand_init()函数中未赋值的指针赋上通用nand驱动函数指针。
7.通用nand驱动函数nand_select_chip()赋值给struct nand_chip结构体的函数指针用于打开或关闭nand芯片,0为打开,1为关闭。在这个函数中会调用nand_chip结构体中的hwcontrol函数指针,这个指针指向的函数是需要自己编写的。这个函数指针在board_nand_init()函数中被赋值。主要作用是向nand flash发送一些nand flash开启与关闭命令。
8.nand_scan()剩余部分初始化nand_chip和mtd_info结构体。
9.nand_scan()最后在返回时调用drivers/nand/nand_bbt.c文件中的nand_default_bbt()。
10.nand_default_bby()选择一个坏块描述表,返回时调用本文件中的nand_scan_bbt()。
11.nand_scan_bbt()寻找建立一个坏块描述表。
12.最后返回到nand_init(),这样nand驱动的初始化完成了。
下面对命令nand read addr ofs size的执行流程进行分析:
1.nand read addr ofs size命令的作用是从nand flash地址的偏移量ofs处读取长度为size字节的数据存储到内存地址addr处。
2.common/main.c文件中的main_loop()主要执行read_line()读取命令行。
3.read_line()读取到命令行后会调用common/main.c文件中的run_command()。
4.run_command()调用common/command.c文件中的find_cmd()在.u_boot_cmd段中寻找该命令的cmd_tbl_t结构,找到后返回该结构。该命令的结构是通过定义在include/command.h中的宏定义U_BOOT_CMD登记进.u_boot_cmd段中的。
5.run_command()找到该命令的cmd_tbl_t结构后则执行该命令对应的函数。对于本情景是nand命令对应的函数do_nand()。
6.do_nand()有两个版本,一个是定义了CFG_NAND_LEGACY。另一个是未定义CFG_NAND_LEGACY。这两个版本都定义在common/cmd_nand.c文件中。对于本情景使用未定义CFG_NAND_LEGACY的do_nand()函数。要使用do_nand()还必须定义宏CONFIG_COMMANDS&CFG_CMD_NAND。(若未定义CFG_NAND_LEGACY则在这个情景中的do_nand()函数调用的函数都定义在drivers/nand_legacy/nand_legacy.c文件中)。
7.对于我们的情景do_nand()会调用定义在include/nand.h文件中的nand_read()。
8.nand_read()则调用本nand芯片对应的nand_info_t结构的read指针。而read指针在nand_scan()中被指向了同文件(drivers/nand/nand_base.c)中的nand_read()函数。
9.nand_read()函数最终会调用nand_chip结构中的cmdfunc指针,通过这个指针指向的函数向nand flash芯片发送命令。最终完成整个命令的执行。
参考: