1.什么是nand,什么是nor?nand啟動與nor啟動的區(qū)別及聯(lián)系。(收集整理) 答:1)在NOR FLASH里面可以直接執(zhí)行代碼,而在NAND FLASH里面不可以,在2410里面,如果選擇NAND啟動方式的話,NAND里的代碼是被拷貝到RAM里面去執(zhí)行的。 2)NAND FLASH每次取數(shù)據(jù)前要寫入好像是0X55,0XAA才行,而NOR FLASH直接取到數(shù)據(jù)。 3)NOR FLASH地址線和數(shù)據(jù)線分開,來了地址和控制信號,數(shù)據(jù)就出來。NAND Flash地址線和數(shù)據(jù)線在一起,需要用程序來控制,才能出數(shù)據(jù)。 2.如何開機(jī)進(jìn)入BIOS模式? 答:將S2跳轉(zhuǎn)開關(guān)打至nor flash端即可。 3.使用supervivi作為bootloader.而有些開發(fā)板使用uboot 4.SEC s3c241x什么意思? 三、ARM的nor flash與nand flash啟動過程區(qū)別 s3c2440啟動過程詳解 1:地址空間的分配 2:開發(fā)板上一般都用SDRAM做內(nèi)存flash(nor、nand)來當(dāng)做ROM。其中nand flash沒有地址線,一次至少要讀一頁(512B).其他兩個有地址線 3:nandflash不用來運(yùn)行代碼,只用來存儲代碼,NORflash,SDRAM可以直接運(yùn)行代碼) 4:s3c2440總共有8個內(nèi)存banks 6個內(nèi)存bank可以當(dāng)作ROM或者SRAM來使用 留下的2個bank除了當(dāng)作ROM 或者SRAM,還可以用SDRAM(各種內(nèi)存的讀寫方式不一樣) 7個bank的起始地址是固定的 還有一個靈活的bank的內(nèi)存地址,并且bank大小也可以改變 5:s3c2440支持兩種啟動模式:NAND和非NAND(這里是nor flash)。 具體采用的方式取決于OM0、OM1兩個引腳 OM[1:0]所決定的啟動方式 OM[1:0]=00時(shí),處理器從NAND Flash啟動 OM[1:0]=01時(shí),處理器從16位寬度的ROM啟動 OM[1:0]=10時(shí),處理器從32位寬度的ROM啟動。 OM[1:0]=11時(shí),處理器從Test Mode啟動。 6.開發(fā)板出廠時(shí)已經(jīng)在nand flash,nor flash燒入了相同的BIOS。 當(dāng)從NAND啟動時(shí) cpu會自動從NAND flash中讀取前4KB的數(shù)據(jù)放置在片內(nèi)SRAM里(s3c2440是soc),同時(shí)把這段片內(nèi)SRAM映射到nGCS0片選的空間(即0x00000000)。cpu是從0x00000000開始執(zhí)行,也就是NAND flash里的前4KB內(nèi)容。因?yàn)镹AND FLASH連地址線都沒有,不能直接把NAND映射到0x00000000,只好使用片內(nèi)SRAM做一個載體。通過這個載體把nandflash中大代碼復(fù)制到RAM(一般是SDRAM)中去執(zhí)行 當(dāng)從非NAND flash啟動時(shí) nor flash被映射到0x00000000地址(就是nGCS0,這里就不需要片內(nèi)SRAM來輔助了,所以片內(nèi)SRAM的起始地址還是0x40000000). 然后cpu從0x00000000開始執(zhí)行(也就是在Norfalsh中執(zhí)行)。 2410支持從nand flash啟動。通過將flash中最開始的4k代碼拷貝到,2410片內(nèi)的一塊不用初始化的sram中運(yùn)行,該拷貝過程完全由硬件支持,無需軟件操作。
Nand Flash控制器有一個特殊的功能,在S3C2410上電后,Nand Flash控制器會自動的把Nand Flash上的前4K數(shù)據(jù)搬移到4K內(nèi)部RAM中,并把0x00000000設(shè)置內(nèi)部RAM的起始地址,CPU從內(nèi)部RAM的0x00000000位置開始啟動。這個過程不需要程序干涉。程序員需要完成的工作,是把最核心的啟動程序放在Nand Flash的前4K中。 u-boot源碼不支持從nand flash啟動,可是s3c2410支持從nand flash啟動,開發(fā)板(sbc-2410x)加電后s3c2410將nand flash的前4k(保存有u-boot的部分功能--拷貝功能--把nand flash中的內(nèi)容拷貝到SDRAM)拷貝到sram(s3c2410芯片內(nèi)的sram),即nGCS0,映射地址為0x00000000。這就需要修改u-boot源碼,增加u-boot的功能:使u-boot在得到執(zhí)行權(quán)后能夠?qū)⑵渥陨砜截惖介_發(fā)板上SDRAM中,以便處理器能夠執(zhí)行u-boot。Nand Flash的命令、地址、數(shù)據(jù)都通過I/O口發(fā)送,管腳復(fù)用,這樣做做的好處是,可以明顯減少NAND FLASH的管腳數(shù)目,將來如果設(shè)計(jì)者想將NAND FLASH更換為更高密度、更大容量的,也不必改動電路板。
NAND FLASH不能夠執(zhí)行程序,本人總結(jié)其原因如下 : 1. NAND FLASH本身是連接到了控制器上而不是系統(tǒng)總線上。CPU啟動后是要取指令執(zhí)行的,如果是SROM、NOR FLASH 等之類的,CPU 發(fā)個地址就可以取得指令并執(zhí)行,NAND FLASH不行,因?yàn)镹AND FLASH是管腳復(fù)用,它有自己的一套時(shí)序,這樣CPU無法取得可以執(zhí)行的代碼,也就不能初始化系統(tǒng)了。例如:str r0,[r1],該命令包含了目的地址和源寄存器,按照cpu的時(shí)序?qū)⒓拇嫫髦械臄?shù)據(jù)保存到內(nèi)存中。如果想把數(shù)據(jù)存儲到nand flash上,必須按照nand flash的讀寫時(shí)序進(jìn)行,如先寫NFCONF,然后NFCMD,NFADDR,最后讀NFDATA。 2. NAND FLASH是順序存取設(shè)備,不能夠被隨機(jī)訪問,讀寫訪問以頁為單位,程序就不能夠分支或跳轉(zhuǎn),這樣你如何去設(shè)計(jì)程序。
bootloader bootloader是芯片復(fù)位后進(jìn)入操作系統(tǒng)之前執(zhí)行的一段代碼,完成由硬件啟動到操作系統(tǒng)啟動的過渡,為運(yùn)行操作系統(tǒng)提供基本的運(yùn)行環(huán)境,如初始化CPU、堆棧、初始化存儲器系統(tǒng)等,其功能類似于PC機(jī)的BIOS。
從NAND閃存啟動U-BOOT的設(shè)計(jì)思路 如果S3C2410被配置成從NAND閃存啟動,上電后,S3C2410的NAND閃存控制器會自動把NAND閃存中的前4K數(shù)據(jù)搬移到內(nèi)部RAM中,并把0x00000000設(shè)置為內(nèi)部RAM的起始地址,CPU從內(nèi)部RAM的0x00000000位置開始啟動。因此要把最核心的啟動程序放在NAND閃存的前4K中。 由于NAND閃存控制器從NAND閃存中搬移到內(nèi)部RAM的代碼是有限的,所以在啟動代碼的前4K里,必須完成S3C2410的核心置,并把啟動代碼的剩余部分搬到RAM中運(yùn)行。在U-BOOT中,前4K完成的主要工作就是U-BOOT啟動的第一個階段(stage1)。 根據(jù)U-BOOT的執(zhí)行流程圖,可知要實(shí)現(xiàn)從NAND閃存中啟動U-BOOT,首先需要初始化NAND閃存,并從NAND閃存中把U-BOOT搬移到RAM中,最后需要讓U-BOOT支持NAND閃存的命令操作。 開發(fā)環(huán)境 本設(shè)計(jì)中目標(biāo)板硬件環(huán)境如下:CPU為S3C2410,SDRAM為HY57V561620,NAND閃存為64MB的K9F1208U0A。 主機(jī)軟件環(huán)境為Redhat9.0、 u-boot-1.1.3、gcc 2.95.3。修改U-BOOT的Makefile,加入: wch2410_config : unconfig @./mkconfig $(@:_config=) arm arm920t wch2410 NULL s3c24x0 即將開發(fā)板起名為wch2410,接下來依次進(jìn)行如下操作: mkdir board/wch2410 cp board/smdk2410 board/wch2410 mv smdk2410.c wch2410.c cp include/configs/smdk2410.h include/configs/wch2410.h export PATH=/usr/local/arm/2.95.3/bin:$PATH 最后執(zhí)行: make wch2410_config make all ARCH=arm 生成u-boot.bin,即通過了測試編譯。 具體設(shè)計(jì) 支持NAND閃存的啟動程序設(shè)計(jì) 因?yàn)閁-BOOT的入口程序是/cpu/arm920t/start.S,故需在該程序中添加NAND閃存的復(fù)位程序,以及實(shí)現(xiàn)從NAND閃存中把U-BOOT搬移到RAM中的功能程序。 首先在/include/configs/wch2410.h中加入CONFIG_S3C2410_NAND_BOOT, 如下: #define CONFIG_S3C2410_NAND_BOOT 1 @支持從NAND 閃存中啟動 然后在/cpu/arm920t/start.S中添加 #ifdef CONFIG_S3C2410_NAND_BOOT copy_myself: mov r10, lr ldr sp, DW_STACK_START @安裝棧的起始地址 mov fp, #0 @初始化幀指針寄存器 bl nand_reset @跳到復(fù)位C函數(shù)去執(zhí)行,執(zhí)行NAND閃存復(fù)位 ....... /*從NAND閃存中把U-BOOT拷貝到RAM*/ ldr r0, =UBOOT_RAM_BASE @ 設(shè)置第1個參數(shù): UBOOT在RAM中的起始地址 mov r1, #0x0 @ 設(shè)置第2個參數(shù):NAND閃存的起始地址 mov r2, #0x20000 @ 設(shè)置第3個參數(shù): U-BOOT的長度(128KB) bl nand_read_whole @ 調(diào)用nand_read_whole(),把NAND閃存中的數(shù)據(jù)讀入到RAM中 tst r0, #0x0 @ 如果函數(shù)的返回值為0,表示執(zhí)行成功 beq ok_nand_read @ 執(zhí)行內(nèi)存比較,把RAM中的前4K內(nèi)容與NAND閃存中的前4K內(nèi)容進(jìn)行比較, 如果完全相同, 則表示搬移成功 其中,nand_reset (),nand_read_whole()被加在/board/wch2410/wch2410.c中。 支持U-BOOT命令設(shè)計(jì) 在U-BOOT下對nand閃存的支持主要是在命令行下實(shí)現(xiàn)對nand閃存的操作。對nand閃存實(shí)現(xiàn)的命令為:nand info(打印nand Flash信息)、nand device(顯示某個nand閃存設(shè)備)、nand read(讀取nand閃存)、nand write(寫nand閃存)、nand erease(擦除nand閃存)、nand bad(顯示壞塊)等。 用到的主要數(shù)據(jù)結(jié)構(gòu)有:struct nand_flash_dev、struct nand_chip。前者包括主要的芯片型號、存儲容量、設(shè)備ID、I/O總線寬度等信息;后者是具體對NAND閃存進(jìn)行操作時(shí)用到的信息。 a. 設(shè)置配置選項(xiàng) 修改/include/configs/wch2410.h,主要是在CONFIG_COMMANDS中打開CFG_CMD_NAND選項(xiàng)。定義NAND閃存控制器在SFR區(qū)中的起始寄存器地址、頁面大小,定義NAND閃存命令層的底層接口函數(shù)等。 b. 加入NAND閃存芯片型號 在/include/linux/mtd/ nand_ids.h中對如下結(jié)構(gòu)體賦值進(jìn)行修改: static struct nand_flash_dev nand_flash_ids[] = { ...... {"Samsung K9F1208U0A", NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000, 0}, ....... } 這樣對于該款NAND閃存芯片的操作才能正確執(zhí)行。 c. 編寫NAND閃存初始化函數(shù) 在/board/wch2410/wch2410.c中加入nand_init()函數(shù)。 void nand_init(void) { /* 初始化NAND閃存控制器, 以及NAND閃存芯片 */ nand_reset(); /* 調(diào)用nand_probe()來檢測芯片類型 */ printf ("%4lu MB/n", nand_probe(CFG_NAND_BASE) >> 20); } 該函數(shù)在啟動時(shí)被start_armboot()調(diào)用。 最后重新編譯U-BOOT并將生成的u-boot.bin燒入NAND閃存中,目標(biāo)板上電后從串口輸出如下信息: U-Boot 1.1.3 (Nov 14 2006 - 11:29:50) U-Boot code: 33F80000 -> 33F9C9E4 BSS: -> 33FA0B28 RAM Configuration: Bank #0: 30000000 64 MB ## Unknown Flash on Bank 0: ID 0xffff, Size = 0x00000000 = 0 MB Flash: 0 kB NAND: 64 MB In: serial Out: serial Err: serial Hit any key to stop autoboot: 0 wch2410 # 結(jié)語 以往將U-BOOT移植到ARM9平臺中的解決方案主要針對的是ARM9中的NOR閃存,因?yàn)镹OR閃存的結(jié)構(gòu)特點(diǎn)致使應(yīng)用程序可以直接在其內(nèi)部運(yùn)行,不用把代碼讀到RAM中,移植過程相對簡單。從NAND閃存中啟動U-BOOT的設(shè)計(jì)難點(diǎn)在于NAND閃存需要把U-BOOT的代碼搬移到RAM中,并要讓U-BOOT支持NAND閃存的命令操作。本文介紹了實(shí)現(xiàn)這一設(shè)計(jì)的思路及具體程序。移植后,U-BOOT在嵌入式系統(tǒng)中運(yùn)行良好。 參考文獻(xiàn) 1 杜春雷 . ARM 體系結(jié)構(gòu)與編程 [M]. 北京 : 清華大學(xué)出版社, 2003 2 S3C2410 User's Mannual[Z].Samsung
vivi中的源碼 #ifdef CONFIG_S3C2410_NAND_BOOT @ @ copy_myself: copy vivi to ram @ copy_myself: mov r10, lr
@ reset NAND mov r1, #NAND_CTL_BASE ldr r2, =0xf830 @ initial value str r2, [r1, #oNFCONF] ldr r2, [r1, #oNFCONF] bic r2, r2, #0x800 @ enable chip str r2, [r1, #oNFCONF] mov r2, #0xff @ RESET command strb r2, [r1, #oNFCMD] mov r3, #0 @ wait 1: add r3, r3, #0x1 cmp r3, #0xa blt 1b 2: ldr r2, [r1, #oNFSTAT] @ wait ready tst r2, #0x1 beq 2b ldr r2, [r1, #oNFCONF] orr r2, r2, #0x800 @ disable chip str r2, [r1, #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, =VIVI_RAM_BASE mov r1, #0x0 mov r2, #0x20000 bl nand_read_ll
tst r0, #0x0 beq ok_nand_read
Freescale i.MX25系列arm的NAND Flash啟動過程
Freescale的i.MX25系列arm支持的啟動方式有: WEIM接口的NOR Flash, SLC/MLC NAND Flash(通過NFC), SD/MMC卡, EEPROM通過SPI接口, EEPROM通過I2C接口, USB啟動等.
不同的啟動方式可以通過arm內(nèi)部寄存器, 芯片引腳, 特別的i.MX25中有eFuse部分來進(jìn)行相應(yīng)的配置. 這里總結(jié)下基于NAND Flash的啟動方式.
涉及到NAND Flash配置的eFuse有:(部分)
-------------------------- bootloader, NAND Flash和boot ROM
在我接觸的系統(tǒng)中, 系統(tǒng)的bootloader程序以及application程序都是儲存在NAND Flash中的, 系統(tǒng)上電之后首先要將bootloader加載進(jìn)內(nèi)存中, 然后bootloader再將application加載進(jìn)內(nèi)存里. 所謂"加載"主要指的是程序的拷貝, 其他還有堆棧, 中斷向量表, 程序指針等一些初始化操作.
上述過程中第一步, 即"上電后, 將bootloader加載進(jìn)內(nèi)存"是怎么完成的呢? 畢竟上電之后內(nèi)存里面什么程序都沒有, 而bootloader又是在NAND flash里的, 就是說系統(tǒng)怎么知道如何讀取bootloader呢?(沒有flash驅(qū)動程序)
這就要結(jié)合上面那張表來回答, 這些表里的設(shè)置是給誰看的呢? 是給芯片內(nèi)部的boot ROM來看的, 這個boot ROM是真正系統(tǒng)啟動的第一步, 它完成了硬件的初始化, 下一步要讀取鏡像的驗(yàn)證和讀取(這里是bootloader), 然后將程序指針跳到相應(yīng)的地址上去執(zhí)行, 它里面含有flash的驅(qū)動程序.
詳細(xì)的內(nèi)部boot ROM讀取NAND Flash的過程, 原文敘述如下:
ARM中的一些地址映射為:
-------------------------- 從boot ROM到bootloader
這樣應(yīng)該能理解boot ROM是怎么將bootloader從NAND Flash中加載進(jìn)內(nèi)存的吧, 這里的內(nèi)存是SDRAM, 地址為0x80000000. 上面一段原文中提到了一個詞是"image header", 根據(jù)它, boot ROM知道讀取多少數(shù)據(jù), 并且程序指針如何跳轉(zhuǎn). 這個過程可以用下圖表示:
圖中的IPL(initial program loader)應(yīng)該就是bootloader吧. 另外一些術(shù)語的解釋為:
一個典型的flash image header文件的原文解釋為:
bootloader的工程編譯鏈接好之后通常是bin或者h(yuǎn)ex文件, 然后通過某種hex或bin工具把上述那個頭文件加進(jìn)去. 然后再燒到NAND Flash中去.
-------------------------- 從bootloader到application
我的系統(tǒng)里, flash最開始的一個block用于儲存bootloader, 其余的被格式化成一個類似fat16的分區(qū), 所以對于Flash的讀寫都是基于文件的操作. Application就是分區(qū)上的一個文件.
bootloader要將這個application加載進(jìn)內(nèi)存, 所以bootloader里面有操作系統(tǒng)和文件系統(tǒng), 能夠?qū)ξ募M(jìn)行讀寫. 用的是threadX操作系統(tǒng)和fileX文件系統(tǒng), 都很小, bootloader大概88KB.
ARM的固件和bootloader,STANDSTONE固件程序,OS初始化 Firmware和bootloader 固件程序通常駐留在ROM中的,當(dāng)系統(tǒng)上電時(shí),首先執(zhí)行的程序。 一個主要的目的就是加載和啟動操作系統(tǒng),這部分程序叫為bootloader。
固件程序執(zhí)行流程為:
系統(tǒng)的image儲存在某種媒介上,通常是有文件系統(tǒng)(file system)的,這時(shí)候image就是一個文件,操作文件需要固件程序能夠支持文件系統(tǒng)。
image也可能就是一組二進(jìn)制代碼,這是最原始的image。通常ARM的image是ELF格式的,帶有頭和調(diào)試信息,ELF是老的COFF格式的升級版。
---------------------------- STANDSTONE固件程序 書中介紹了一個叫STANDSTONE的簡單固件程序,它完成設(shè)置系統(tǒng)環(huán)境、加載并啟動鏡像的功能。所謂啟動就是將系統(tǒng)的控制權(quán)交給啟動了鏡像,也就是一般所說的操作系統(tǒng)了。
STANDSTONE的程序工程組織結(jié)構(gòu):
可以看出,編譯好的STANDSTONE產(chǎn)生的image,不僅包含了STANDSTONE的代碼,而且包含了payload的bin(二進(jìn)制鏡像)。
STANDSTONE的執(zhí)行流程:
ARM上電時(shí)從0x00000000開始執(zhí)行,向量表就放在該地址,上電即進(jìn)入reset異常。 STANDSTONE較簡單,沒用其他異常,將其都設(shè)置成循環(huán)。 reset異常,處理器跳轉(zhuǎn)到standstone_init1的地方去運(yùn)行,接著是第二步:
這一步在設(shè)置系統(tǒng)寄存器里特定的LED顯示寄存器。
這部分代碼完成了內(nèi)存重映射,本來flash ROM是0地址開始的,現(xiàn)在編程了0x01800000,當(dāng)然物理上是沒變,只是邏輯上改了。 并且初始化了兩個bank的SRAM。 分析代碼:第一句是重映射錢standstone_init2的絕對地址,standstone_init2是固件程序的一部分,所以肯定在0x0到0x00080000范圍內(nèi),重映射好要接著執(zhí)行standstone_init2,所以需要計(jì)算出重映射好之后的地址,這也就是第三句指令做的事。 然后r0指向memorymaptable_str,然后將memorymaptable_str開始的數(shù)據(jù)賦值給r1-r12,r0后又賦值為某個系統(tǒng)寄存器,將r1-r12的數(shù)據(jù)賦值給這個系統(tǒng)寄存器。這幾句就完成了重映射,這個系統(tǒng)寄存器是內(nèi)存控制器,它接受memorymaptable_str這類能夠表明內(nèi)存分布情況的數(shù)據(jù)。 最后跳轉(zhuǎn)到standstone_init2,這句很巧妙,因?yàn)镾TMIA執(zhí)行好之后,PC所指向的地址已經(jīng)變成了SDRAM里的內(nèi)容,指令都到0x01800000以后的地址去了,但因?yàn)锳RM的流水線結(jié)構(gòu),所以MOV語句已經(jīng)取出,能夠執(zhí)行。
第四步是初始化串口,用于交互式命令通信,由于這部分和特定芯片相關(guān),沒有顯示。
第五步是bootloader,就是加載之前那個payload的bin鏡像
程序里假設(shè)了payload的bin鏡像的起始地址payload_start_address,結(jié)束地址payload_end_address。 一開始將r12設(shè)為payload_start_address,將r13設(shè)為0地址,也就是SRAM的地址。 將payload_start_address拷貝至{r0-r11}再由{r0-r11}拷貝至SRAM。 拷貝完成之后跳轉(zhuǎn)到0地址去執(zhí)行payload的bin鏡像。
---------------------------- OS初始化 通過前一篇的固件程序,假設(shè)已經(jīng)完成了內(nèi)存重映射和OS的拷貝,即將SRAM映射到了0x00000000和0x00080000之間,OS從固件拷貝到了0x00000000起始的地方。另外,假設(shè)芯片內(nèi)的配置寄存器的基地址是0x03ff0000。
看一下OS的工程結(jié)構(gòu):
e7t/devices文件夾包含驅(qū)動程序,events下包含異常中斷服務(wù)程序,core下是OS,apps下是應(yīng)用程序。
雖然固件程序里完成了初始化,但那個初始化是針對芯片而言的,比如設(shè)置棧指針、內(nèi)存映射、OS拷貝等;OS拷貝到0x0地址之后,固件程序?qū)c也置為了0x0,要知道0x0地址是存放異常向量表的,第一個是reset異常,這也就是這個OS的第一條指令了,這不過這個reset指的是OS的reset,和固件程序里的reset不是同一個。
OS的reset異常完成OS的初始化工作,分成三個階段:棧設(shè)置、PCB設(shè)置、開始C程序。首先是棧設(shè)置: bringupInitFIQRegisters程序段將FIQ的寄存器用作系統(tǒng)狀態(tài)記錄,所以對FIQ的三個寄存器做了設(shè)為了0。接下去的幾句是設(shè)置了棧指針,因?yàn)槭乖赟VC模式下,所以可以通過MSR指令改寫模式,并設(shè)置該模式下的棧。設(shè)置好之后,再回到SVC模式。
PCB設(shè)置:PSB指的是process control blcok,是一種數(shù)據(jù)結(jié)構(gòu),當(dāng)任務(wù)發(fā)生切換時(shí),將PCB數(shù)據(jù)拷貝到棧上:
最后跳轉(zhuǎn)至C程序: 進(jìn)入C程序后,第一個函數(shù)初始化了驅(qū)動、IO、異常中斷服務(wù)等;然后開始定時(shí)器即時(shí);然后切換至user模式;然后開始第一個任務(wù)。
系統(tǒng)內(nèi)存分布
---------------------------- reference:ARM System Developer's Guide.pdf
|