加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

NAND Flash启动的问题

发布时间:2020-12-15 17:25:06 所属栏目:百科 来源:网络整理
导读:从Nand Flash启动U-BOOT的基本原理 ------------------------------------------- 前4K的问题 ??? 如果S3C2410被配置成从Nand Flash启动(配置由硬件工程师在电路板设置),S3C2410的Nand Flash控制器有一个特殊的功能,在S3C2410上电后,Nand Flash控制器会自动

从Nand Flash启动U-BOOT的基本原理
-------------------------------------------
前4K的问题
??? 如果S3C2410被配置成从Nand Flash启动(配置由硬件工程师在电路板设置),S3C2410的Nand Flash控制器有一个特殊的功能,在S3C2410上电后,Nand Flash控制器会自动的把Nand Flash上的前4K数据搬移到4K内部SRAM中,并把0x00000000设置内部SRAM的起始地址,CPU从内部SRAM的0x00000000位置开始启动。这个过程不需要程序干涉。
??? 程序员需要完成的工作,是把最核心的启动程序放在Nand Flash的前4K中。
启动程序的安排
??? 由于Nand Flash控制器从Nand Flash中搬移到内部SRAM的代码是有限的,所以在启动代码的前4K里,我们必须完成S3C2410的核心配置以及把启动代码(U-BOOT)剩余部分搬到SDRAM中运行。


??? u-boot源码不支持从nand flash启动,可是s3c2410支持从nand flash启动,开发板(sbc-2410x)加电后s3c2410将nand flash的前4k(保存有u-boot的部分功能--拷贝功能--把nand flash中的内容拷贝到SDRAM)拷贝到sram(s3c2410芯片内的sram)。这就需要修改u-boot源码,增加u-boot的功能: 使u-boot在得到执行权后能够将其自身拷贝到开发板上SDRAM中,以便处理器能够执行u-boot。

* NOR FLASH地址线和数据线分开,来了地址和控制信号,数据就出来。

*NAND Flash地址线和数据线在一起,需要用程序来控制,才能出数据。通俗的说,就是光给地址不行,要先命令,再给地址,才能读到NAND的数据。而且都是在一个总线完成的。

?Nand Flash的命令、地址、数据都通过I/O口发送,管脚复用,这样做做的好处是,可以明显减少NAND FLASH的管脚数目,将来如果设计者想将NAND FLASH更换为更高密度、更大容量的,也不必改动电路板。

?NAND FLASH不能够执行程序,本人总结其原因如下 :

1. NAND FLASH本身是连接到了控制器上而不是系统总线上。CPU启动后是要取指令执行的,如果是SROM、NOR FLASH 等之类的,CPU 发个地址就可以取得指令并执行,NAND FLASH不行,因为NAND FLASH 是管脚复用,它有自己的一套时序,这样CPU无法取得可以执行的代码,也就不能初始化系统了。

?2. NAND FLASH是顺序存取设备,不能够被随机访问,程序就不能够分支或跳转,这样你如何去设计程序。

?

U-BOOT 支持ARM、 PowerPC等多种架构的处理器,也支持Linux、NetBSD和VxWorks等多种操作系统,主要用来开发嵌入式系统初始化代码 bootloader。bootloader是芯片复位后进入操作系统之前执行的一段代码,完成由硬件启动到操作系统启动的过渡,为运行操作系统提供基本的运行环境,如初始化CPU、堆栈、初始化存储器系统等,其功能类似于PC机的BIOS.



NAND闪存工作原理

?????? S3C2410开发板的NAND闪存由NAND闪存控制器(集成在S3C2410 CPU中)和NAND闪存芯片(K9F1208U0A)两大部分组成。当要访问NAND闪存芯片中的数据时,必须通过NAND闪存控制器发送命令才能完成。所以,NAND闪存相当于S3C2410的一个外设,而不位于它的内存地址区。

?????? NAND闪存(K9F1208U0A)的数据存储结构分层为:1设备(Device) = 4096 块(Block);1块= 32页/行(Page/row);1页= 528B = 数据块 (512B) + OOB块 (16B)
在每一页中,最后16个字节(又称OOB)在NAND闪存命令执行完毕后设置状态,剩余512个字节又分为前半部分和后半部分。可以通过NAND闪存命令00h/01h/50h分别对前半部、后半部、OOB进行定位,通过NAND闪存内置的指针指向各自的首地址。
NAND闪存的操作特点为:擦除操作的最小单位是块;NAND闪存芯片每一位只能从1变为0,而不能从0变为1,所以在对其进行写入操作之前一定要将相应块擦除;OOB部分的第6字节为坏快标志,即如果不是坏块该值为FF,否则为坏块;除OOB第6字节外,通常用OOB的前3个字节存放NAND闪存的硬件 ECC(校验寄存器)码;
???
从NAND闪存启动U-BOOT的设计思路

?????? 如果S3C2410被配置成从NAND闪存启动,上电后,S3C2410的NAND闪存控制器会自动把NAND闪存中的前4K数据搬移到内部RAM中,并把0x00000000设置为内部RAM的起始地址,CPU从内部RAM的0x00000000位置开始启动。因此要把最核心的启动程序放在NAND闪存的前4K中。

?????? 由于NAND闪存控制器从NAND闪存中搬移到内部RAM的代码是有限的,所以,在启动代码的前4K里,必须完成S3C2410的核心配置,并把启动代码的剩余部分搬到RAM中运行。在U-BOOT中,前4K完成的主要工作就是U-BOOT启动的第一个阶段(stage1)。?
根据U-BOOT的执行流程图,可知要实现从NAND闪存中启动U-BOOT,首先需要初始化NAND闪存,并从NAND闪存中把U-BOOT搬移到RAM中,最后需要让U-BOOT支持NAND闪存的命令操作。
##################################################################################

对u-boot启动代码start.s(汇编部分)的注解。

需要注意的是代码的搬运过程。

对于从nandflash启动的s3c2410,上电后会自动从nandflash搬移4k代码(肯定包含start.s部分)到0地址的缓存(bootstone)中,然后从0地址开始读取指令并运行。那么这4k的代码必须实现必要的初始化和u-boot代码的搬移(到sdram中),最后u-boot将在sdram中运行。

u-boot默认是从norflash或sdram中启动运行的。原版的start.s对于代码搬移的实现如下:

1,首先读取_start的地址值(相对pc的值,特别注意adr伪指令)和_TEXT_BASE地址处TEXT_BASE的值(在连接脚本中定义的常数),以判别程序从哪里运行,是否需要搬移。

relocate:???????????????/*?relocate U-Boot to RAM???????*/

????adr?r0,_start??????/*?r0 <- current position of code???*/

????ldr?r1,_TEXT_BASE??????/*?test if we run from flash or RAM?*/

????cmp?????r0,r1????????????????

????beq?????stack_setup

?

2,如果需要,搬移所有整个代码段到sdram(TEXT_BASE地址处)。下面用于计算代码段长度和代码段终止地址。

?

??? ldr?r2,_armboot_start

????ldr?r3,_bss_start

????sub?r2,r3,r2??????/*?r2 <- size of armboot????????????*/

????add?r2,r0,r2??????/*?r2 <- source end address?????????*/

?

3,如果是从nandflash启动,上述实际上只有效搬移了4k的代码到sdram,因为u-boot代码段大部分还在nandflash中。所以需要添加从nandflash拷贝到sdram的代码。这里由copy_myself函数实现,再次搬移了128k,并且覆盖了前次搬移的4k。

?

?????bl????copy_myself

?

4,搬移完成后,程序必须跳到sdram中去运行。注意下面的ldr伪指令,得到on_the_ram的绝对地址(连接完成后就是个常数值,位于sdram中),然后赋值给pc。

?

??? @ jump to ram

??????ldr???r1,=on_the_ram

??????add???pc,r1,#0

?

5,跳到start_armboot(),运行第一跳c指令。这里的ldr是普通指令,_start_armboot标号处存储了start_armboot()函数的绝对地址(连接完就是个常数)。到此start.s的工作完成。

??? on_the_ram:

??? #endif

??? /*end add*/

?

????????ldr?pc,_start_armboot

??? _start_armboot:?.word start_armboot

?

##################################################################################
# cd u-boot-1.1.6
在board/bks2410加入NAND Flash读函数,建立nand_read.c,加入如下内容(copy from vivi):
# vi board/sbc2410x/ nand_read.c
-----------------------------------------------
#include <config.h>
#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGi(x) (*(volatile unsigned int *)(x))
#define NF_BASE?? 0x4e000000
#define NFCONF??? __REGi(NF_BASE + 0x0)
#define NFCMD???? __REGb(NF_BASE + 0x4)
#define NFADDR??? __REGb(NF_BASE + 0x8)
#define NFDATA??? __REGb(NF_BASE + 0xc)
#define NFSTAT??? __REGb(NF_BASE + 0x10)

#define BUSY 1
inline void wait_idle(void) {
??? int i;

??? while(!(NFSTAT & BUSY))
??? ??? for(i=0; i<10; i++);
}

#define NAND_SECTOR_SIZE 512
#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)
{
??? int i,j;

??? if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
??? ??? return -1; /* invalid alignment */
??? }

??? /* chip Enable */
??? NFCONF &= ~0x800;
??? for(i=0; i<10; i++);

??? for(i=start_addr; i < (start_addr + size);) {
??? ??? /* READ0 */
??? ??? NFCMD = 0;

??? ??? /* Write Address */
??? ??? NFADDR = i & 0xff;
??? ??? NFADDR = (i >> 9) & 0xff;
??? ??? NFADDR = (i >> 17) & 0xff;
??? ??? NFADDR = (i >> 25) & 0xff;

??? ??? wait_idle();

??? ??? for(j=0; j < NAND_SECTOR_SIZE; j++,i++) {
??? ??? ??? *buf = (NFDATA & 0xff);
??? ??? ??? buf++;
??? ??? }
??? }

??? /* chip Disable */
??? NFCONF |= 0x800; /* chip disable */

??? return 0;
}



# vi board/sbc2410x/Makefile +28
-----------------------------------------------
COBJS?? := sbc2410x.o flash.o??? ??? ==>
COBJS?? := sbc2410x.o flash.o nand_read.o




# vi cpu/arm920t/start.S
-----------------------------------------------
从Nand Flash中把数据拷贝到RAM,是由copy_myself程序段完成
(1) 在"ldr pc,_start_armboot"之前加入(223行):
#ifdef CONFIG_S3C2410_NAND_BOOT
?? bl???? copy_myself

?? @ jump to ram
?? ldr??? r1,=on_the_ram
?? add??? pc,#0
?? nop
?? nop
?? 1:???? b????? 1b?????????? @ infinite loop

on_the_ram:
#endif


(2) 在"_start_armboot: .word start_armboot"之后加入:
#ifdef CONFIG_S3C2410_NAND_BOOT
copy_myself:
?? mov r10,lr
@ reset NAND
?? mov r1,#NAND_CTL_BASE
?? ldr r2,=0xf830?????????? ?? @ initial value
?? str r2,[r1,#oNFCONF]
?? ldr r2,#oNFCONF]
?? bic r2,r2,#0x800?????????? @ enable chip
?? str r2,#oNFCONF]
?? mov r2,#0xff??????????????? @ RESET command
?? strb r2,#oNFCMD]
?? mov r3,#0?????????????????? @ wait

1:add?? r3,#0x1
?? cmp r3,#0xa
?? blt 1b
2:ldr?? r2,#oNFSTAT]?????? @ wait ready
?? tst r2,#0x1
?? beq 2b
?? ldr r2,#oNFCONF]
?? orr r2,#0x800????????? @ disable chip
?? str r2,#oNFCONF]

@ get read to call C functions (for nand_read())
?? ldr sp,DW_STACK_START?????? @ setup stack pointer
?? mov fp,#0?????????????????? @ no previous frame,so fp=0

@ copy vivi to RAM
?? ldr??? r0,=UBOOT_RAM_BASE
?? mov??? r1,#0x0
?? mov??? r2,#0x20000
?? bl???? nand_read_ll
?? tst??? r0,#0x0
?? beq??? ok_nand_read

#ifdef CONFIG_DEBUG_LL
?? bad_nand_read:
?? ldr??? r0,STR_FAIL
?? ldr??? r1,SerBase
?? bl???? PrintWord
1:b?????? 1b?????????? @ infinite loop
?? #endif

ok_nand_read:
#ifdef CONFIG_DEBUG_LL
?? ldr??? r0,STR_OK
?? ldr??? r1,SerBase
?? bl???? PrintWord
#endif

@ verify
?? mov??? r0,#0
?? ldr??? r1,=UBOOT_RAM_BASE
?? mov??? r2,#0x400????? @ 4 bytes * 1024 = 4K-bytes
go_next:
?? ldr??? r3,[r0],#4
?? ldr??? r4,[r1],#4
?? teq??? r3,r4
?? bne??? notmatch
?? subs?? r2,#4
?? beq??? done_nand_read
?? bne??? go_next

notmatch:
#ifdef CONFIG_DEBUG_LL
?? sub??? r0,#4
?? ldr??? r1,SerBase
?? bl???? PrintHexWord
?? ldr??? r0,SerBase
?? bl???? PrintWord
#endif
1:b?????? 1b
done_nand_read:
#ifdef CONFIG_DEBUG_LL
?? ldr??? r0,SerBase
?? bl???? PrintWord
#endif
?? mov??? pc,r10
@ clear memory
@ r0: start address
@ r1: length
?? mem_clear:
?? mov r2,#0
?? mov r3,r2
?? mov r4,r2
?? mov r5,r2
?? mov r6,r2
?? mov r7,r2
?? mov r8,r2
?? mov r9,r2

clear_loop:
?? stmia r0!,{r2-r9}
?? subs?? r1,#(8 * 4)
?? bne??? clear_loop
?? mov??? pc,lr

#endif @ CONFIG_S3C2410_NAND_BOOT


(3) 在文件的最后加入:
??? .align????? 2
DW_STACK_START:
.word?????? STACK_BASE+STACK_SIZE-4





# vi include/configs/sbc2410x.h
-----------------------------------------------
(1) 将CONFIG_SERVERIP设置为主机IP
??? 这样以后在通过网络下载内核映像时,就不用就该IP地址了。(这一项修改与nand flash没有关系)

#define CONFIG_SERVERIP???? 192.168.0.240


(2) 在文件末尾添加如下内容
/* * Nandflash Boot */ #define CONFIG_S3C2410_NAND_BOOT 1 #define STACK_BASE???????? 0x33f00000 #define STACK_SIZE???? ??? 0x8000 #define UBOOT_RAM_BASE???? 0x33f80000 /* NAND Flash Controller */ #define NAND_CTL_BASE????? 0x4E000000 #define bINT_CTL(Nb)?????? __REG(INT_CTL_BASE + (Nb)) /* Offset */ #define oNFCONF??????????? 0x00 #define oNFCMD???????????? 0x04 #define oNFADDR??????????? 0x08 #define oNFDATA??????????? 0x0c #define oNFSTAT??????????? 0x10 #define oNFECC???????????? 0x14

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读