1. 程式人生 > >十二.ARM裸機學習之SD卡啟動詳解

十二.ARM裸機學習之SD卡啟動詳解

一.主流的外存裝置發展及介紹

2017/12/12 23:08

**

1.首先,清楚記憶體和外存的區別:

**

一般是把這種RAM(random access memory,隨機訪問儲存器,特點是任意位元組讀寫,掉電丟失)叫記憶體,
把ROM(read only memory,只讀儲存器,類似於Flash SD卡之類的,用來儲存東西,掉電不丟失,不能隨機地址訪問,只能以塊為單位來訪問)叫外存

2.儲存裝置按發展趨勢分類:

● 磁儲存裝置:軟盤、硬碟、光碟、CD、磁帶
● Flash:NandFlash、NorFlash
缺點:時序複雜,無壞塊處理機制,介面不統一
NandFlash:MLC(可靠性差,容量大)、SLC(可靠性高、容量小)
現在基本都在發展MLC技術
● 擴充套件卡式Flash:SD卡、MMC卡、MicroSD(TF卡)
內部為NnadFlash儲存顆粒,外部封裝了介面,介面標準統一、通用。
缺點:頻繁使用導致卡槽接觸不可靠
● iNand、MoviNand、eSSD:
內部為NandFlash晶片,整合塊裝置儲存單元,集成了擴充套件卡式Flash 的優點
介面標準統一(時序、物理封裝、引腳定義),以晶片級封裝釋出
晶片內部具有Flash管理模組:具有能壞塊管理等功能
● SSD:固態硬碟
內部為NandFlash晶片,外部封裝為硬碟介面
**

3.SD卡簡介

**
SD卡是具有大容量、高效能、安全等多種特點的多功能儲存卡,它比MMC卡多了一個進行資料著作權保護的暗號認證功能(SDMI規格),讀寫速度比MMC卡要快4倍,達2M/秒。
SD插槽支援MMC卡。
SD卡和Nand、Nor等Flash晶片差異
(1)SD卡/MMC卡等卡類有統一的介面標準,而Nand晶片沒有統一的標準(各家產品會有差異)

二. SD卡程式設計介面

**

1.SD卡3種模式的引腳定義

**
這裡寫圖片描述
SD卡的引腳介面支援兩種通訊協議:SD協議和SPI協議。
SPI協議是微控制器中廣泛使用的一種通訊協議,介面時序簡單,是一種低速通訊協議。
SD通訊協議是一個統一標準的通訊協議。SoC通過SD卡的九針引腳以SD/SPI協議向SD卡管理模組傳送命令、時鐘、資料等資訊,需要按照時序處理操作SD卡。
**

2.S5PV210的SD/MMC控制器

**
(1)SD協議要求SoC中有SD控制器,資料手冊Section8.7,為SD/MMC控制器介紹。
(2)SD卡內部除了儲存單元Flash外,還有SD卡管理模組,我們SoC和SD卡通訊時,通過9針引腳以SD協議/SPI協議向SD卡管理模組傳送命令、時鐘、資料等資訊,然後從SD卡返回資訊給SoC來互動。工作時每一個任務(譬如初始化SD卡、譬如讀一個塊、譬如寫、譬如擦除····)都需要一定的時序來完成(所謂時序就是先向SD卡傳送xx命令,SD卡回xx訊息,然後再向SD卡傳送xx命令····)

三.SD卡啟動流程1

**

1.S5PV210的啟動過程回顧

**
(1)210啟動首先執行內部的iROM(也就是BL0),BL0會判斷OMpin來決定從哪個裝置啟動,如果啟動裝置是SD卡,則BL0會從SD卡讀取前16KB(不一定是16,反正16是工作的)到SRAM中去啟動執行(這部分就是BL1,這就是steppingstone技術)
(2)BL1執行之後剩下的就是軟體的事情了,SoC就不用再去操心了
**

2.SD卡啟動流程(bin檔案小於16KB時和大於16KB時)

**
(1)啟動的第一種情況是整個映象大小小於16KB。這時候相當於我的整個映象作為BL1被steppingstone直接硬體載入執行了而已。
(2)啟動的第二種情況就是整個映象大小大於16KB。(只要大於16KB,哪怕是17KB,或者是700MB都是一樣的)這時候就要把整個映象分為2部分:第一部分16KB大小,第二部分是剩下的大小。然後第一部分作為BL1啟動,負責去初始化DRAM並且將第二部分載入到DRAM中去執行(uboot就是這樣做的)。
**

3.最重要的但是卻隱含未講的東西

**
(1)問題:iROM究竟是怎樣讀取SD卡/NandFlash的?
(2)三星在iROM中事先內建了一些程式碼去初始化外部SD卡/NandFlash,並且內建了讀取各種SD卡/NandFlash的程式碼在iROM中。BL0執行時就是通過呼叫這些device copy function來讀取外部SD卡/NandFlash中的BL1的。
**

4.S5PV210讀取Flash裝置資料的方式

**
三星系列SoC支援SD卡/NandFlash啟動,主要是依靠SteppingStone技術,具體能支援steppingstone技術的是內部的iROM程式碼。
S5PV210內部iROM內部固化了多個裝置拷貝函式,這些函式支援從SD/MMC、eMMC、OneNand、eSSD裝置拷貝資料到SDRAM中。

裝置拷貝函式說明如下:
● NF8_ReadPage_Adv(0xD0037F90):2K、4K,8bit匯流排
● NF16_ReadPage_Adv(0xD0037F94):2K,5 cycle ,16位匯流排
CopySDMMCtoMem(0xD0037F98):從SD/MMC裝置拷貝到SDRAM
● CopyMMC4_3toMem(0xD0037F9C):從eMMC裝置拷貝到SDRAM
● CopyOND_ReadMultiPages(0xD0037FA0):從OneNand裝置拷貝到SDRAM
● CopyOND_ReadMultiPages_Adv(0xD0037FA4):從OneNand裝置拷貝到SDRAM
● Copy_eSSDtoMem(0xD0037FA8): 從eSSD裝置拷貝SDRAM(CPUPIO模式)
● Copy_eSSDtoMem_Adv(0xD0037FAC):從eSSD拷貝SDRAM(UDMA)
● NF8_ReadPage_Adv128p(0xD0037FB0):每塊128頁,每頁2K的Nand

**

四.S5PV210讀取SD卡資料的方式

**

1.CopySDMMCtoMem函式解讀:

這裡寫圖片描述

#define CopySDMMCtoMem(z,a,b,c,e) (((bool(*)(int, unsigned int, unsigned short, unsigned int*, bool))(*((unsigned int *)0xD0037F98)))(z,a,b,c,e))

● 引數1:SD卡通道,0或者2通道,我們板子SD卡通道為2
● 引數2:塊起始地址(塊地址)
● 引數3:拷貝塊的數量
● 引數4:資料拷貝到什麼地址
● 引數5:返回狀態

思考:為什麼讀取SD卡時以塊為單位?

這就涉及到扇區和塊的概念,一個扇區有好多個位元組(一般是512個位元組),一個扇區可以看成是一個塊block(塊的概念就是:不是一個位元組,是多個位元組組成一個共同的操作單元塊),所以就把這一類的裝置稱為塊裝置。常見的塊裝置有:磁儲存裝置硬碟、軟盤、DVD和Flash裝置(U盤、SSD、SD卡、NandFlash、Norflash、eMMC、iNand)。
磁碟和Flash以塊為單位來讀寫,就決定了我們啟動時只能以整塊為單位來讀取SD卡

**

2.使用函式指標呼叫裝置拷貝函式

**
第一種方法:巨集定義方式來呼叫。好處是簡單方便,壞處是編譯器不能幫我們做引數的靜態型別檢查。

#define CopySDMMCtoMem(z,a,b,c,e)(((bool(*)(int, unsigned int, unsigned short, unsigned int*, bool))(*((unsigned int *)0xD0037F98)))(z,a,b,c,e))

第二種方法:用函式指標方式來呼叫。

typedef unsigned int bool;
typedef bool(*pCopySDMMC2Mem) (int, unsigned int, unsigned short, unsigned int *, bool);
// 實際使用時
pCopySDMMC2Mem p1 = (pCopySDMMC2Mem)0xD0037F98;
p1(x, x, x, x, x);  // 第一種呼叫方法,編譯器預設就是一個函式指標
(*p1)(x, x, x, x, x);   // 第二種呼叫方法,和上面一樣,
*p1(x, x, x, x, x); // 錯誤,因為p1先和()結合,而不是先和*結合。

五、SD卡啟動模式程式設計

S5PV210啟動過程:開發板上電後,BL0執行時會從啟動裝置載入BL1到iRAM中執行,BL1執行時會初始化SDRAM,將BL2從啟動裝置拷貝到DDR,然後從BL1遠跳轉到BL2執行。
總體思路:將我們的程式碼分為2部分:第一部分BL1小於等於16KB,第二部分為任意大小,iROM程式碼執行完成後從SD卡啟動會自動讀取BL1到SRAM中執行;BL1執行時負責初始化DDR,然後手動將BL2從SD卡copy到DDR中正確位置,然後BL1遠跳轉到BL2中執行BL2。
**

BL1階段工作

**
● 關看門狗
● 設定棧
● 開iCache
**初始化DDR
從SD卡拷貝BL2到DDR
遠跳轉執行BL2**
這裡寫圖片描述
說明:如圖,S5PV210規定BL1從block1開始,BL1長度為16KB內,我們就定為16KB(也就是32個block),即BL1從block1-block32,
**

BL2階段工作:

**
● 跳轉到BL2執行時,點亮LED燈。
BL2理論上可以從33扇區開始,但我們為了安全會用一些空扇區作為隔離區,故可以從45扇區開始,定義BL2長度為16KB,也就是32扇區
BL2從block45-block76。BL1的執行地址和連結地址為0xD0020010。
說明:BL2的執行地址為DDR中的地址,因此連結地址需要設定為DDR的地址。
我們選0x23E00000(因為我們BL1中只初始化了DDR1,地址空間範圍是0x20000000~0x2FFFFFFF)

六.uboot中的做法

第二種思路:程式程式碼仍然包括BL1和BL2兩部分,但是組織形式上不分為2部分而是作為一個整體來組織。它的實現方式是:iROM啟動然後從SD卡的扇區1開始讀取16KB的BL1然後去執行BL1,BL1負責初始化DDR,然後從SD卡中讀取整個程式(BL1+BL2)到DDR中,然後從DDR中執行(利用ldr pc, =main這種方式以遠跳轉從SRAM中執行的BL1跳轉到DDR中執行的BL2)。
**

再來分析uboot的SD卡啟動細節

**
(1)uboot編譯好之後有200多KB,超出了16KB。uboot的組織方式就是前面16KB為BL1,剩下的部分為BL2.
(2)uboot在燒錄到SD卡的時候,先擷取uboot.bin的前16KB(實際指令碼擷取的是8KB)燒錄到SD卡的block1~bolck32;然後將整個uboot燒錄到SD卡的某個扇區中(譬如49扇區)
(3)實際uboot從SD卡啟動時是這樣的:iROM先執行,根據OMpin判斷出啟動裝置是SD卡,然後從S卡的block1開始讀取16KB(8KB)到SRAM中執行BL1,BL1執行時負責初始化DDR,並且從SD卡的49扇區開始複製整個uboot到DDR中指定位置(0x23E00000)去備用;然後BL1繼續執行直到ldr pc, =main時BL1跳轉到DDR上的BL2中接著執行uboot的第二階段。

總結:uboot中的這種啟動方式比上節講的分散載入的好處在於:能夠相容各種啟動方式。
程式碼分析:E:\Linux\13.sd_relocate

在linux下使用dd命令燒錄程式,插上SD卡,開發板正常執行看到LED閃爍。
這裡寫圖片描述

七.遇到的問題:

**

插上分別使用九鼎1燒錄好的SD卡和在linux下使用dd命令刷寫uboot,啟動都沒有反應?

**

最終問題是SD卡沒有啟動起
採用的方法是從新刷機,板子刷入安卓系統,由於SD卡無法啟動,故採用USB—dnw刷機方式:
刷機分2步:第一步刷x210_usb.bin,地址是0xd0020010;第二步刷uboot.bin,刷機地址是0x23e00000,uboot啟動起來後,先fdisk -c 0去重新分割槽,然後再fastboot….再按照刷機過程刷入系統。
然後重啟,等待系統開機完畢
然後破壞開發板iNand中的bootloader以從SD2啟動(參考 二.ARM裸機刷系統(SD卡uboot+串列埠+usb otg刷機方式)),即解決了這個問題。
這裡寫圖片描述