S3C2416裸機開發(fā)系列三_啟動代碼以及流水燈c代碼
啟動代碼是處理器上電復(fù)位后最先運行的一段代碼。主要是用來把處理器初始化到一個確定的狀態(tài),為c運行環(huán)境作好準備。如設(shè)置異常向量表,初始化系統(tǒng)時鐘,初始化外部內(nèi)存,把用戶代碼拷貝到外部內(nèi)存,初始化棧,清0全局變量區(qū),靜態(tài)變量區(qū)等。與體系結(jié)構(gòu)相關(guān)的部分,只能用匯編來寫。由于S3C2416/50/51目前在各個編譯器中都還沒有啟動代碼文件,因此筆者在MDK下主要參考S3C2440的啟動代碼來寫一個S3C2416的啟動代碼。
1. 啟動代碼流程啟動代碼的內(nèi)容,順序等都沒有特定的要求,只要能達到初始化c運行環(huán)境即可。這里筆者說明一下,編寫的啟動代碼應(yīng)該是地址無關(guān)的,即鏈接到任存儲器地址都是可以運行的。如S3C2416在nand boot/Norboot時用戶的第一條代碼是在0x0處執(zhí)行的,而在IROM boot時,用戶的第一條代碼是在0x40000000處執(zhí)行的,啟動代碼對不同的啟動模式都是要能正確運行的。此外,啟動代碼文件內(nèi)容應(yīng)該是板級無關(guān)的,不同的開發(fā)板,只要是同一處理器(S3C2416/50/51),啟動代碼文件都是適用的。即板級的代碼如GPIO口的初始化不適合放在啟動代碼中實現(xiàn)。此處筆者只以筆者的啟動代碼思路來作講解。
1.1. 異常向量表處理器在上電復(fù)位完成后,第一條代碼進入的是異常向量表中對應(yīng)的復(fù)位向量地址。對于arm,這個異常向量表的地址通常是0x00000000偏移處,如發(fā)生復(fù)位,則arm進入0x0處的復(fù)位向量地址,發(fā)生IRQ中斷則進入0x18處的IRQ異常向量地址。異常向量表就是用來記錄各個異常進入時的代碼處理位置。
1.2. 關(guān)看門狗復(fù)位代碼最先做的事應(yīng)該是關(guān)看門狗,因為如果看門狗打開的話,在啟動代碼進行初始化過程中是無法喂狗的,可能造成處理器一直不停復(fù)位。
1.3. 關(guān)閉所有中斷啟動代碼未完成時,各個狀態(tài)都還不是確定的,如果有中斷打開并引起中斷異常,可能造成代碼跑飛。
1.4. 初始化系統(tǒng)時鐘一般來說,處理器復(fù)位后都是運行在一個較低速的時鐘下,為加快啟動,通常盡可能快地設(shè)置處理器的各個時鐘。
1.5. 初始化外部內(nèi)存除了Nor flash可以直接執(zhí)行代碼外,其它的代碼存儲器如nand flash、sd/mmc都是不能直接執(zhí)行代碼的。因此需要初始化外部內(nèi)存,用來存儲代碼,變量。(本章節(jié)為避免復(fù)雜化,暫時不講解,注釋掉調(diào)用DDR2的初始化及用戶代碼的搬移)
1.6. 用戶代碼拷貝到外部內(nèi)存對于代碼存儲在nand、sd/mmc等不能直接執(zhí)行代碼的存儲器,初始代碼是一定需要把用戶代碼從這些設(shè)備讀入到特定的內(nèi)存中執(zhí)行的。而對于Nor flash可直接執(zhí)行代碼的存儲器,通常為了提高性能,也是會把代碼從Nor flash讀出,在內(nèi)存中執(zhí)行的。
1.7. MMU初始化MMU的初始化不總是必須的,主要是為提高性能,開D-cache必須開MMU。如果是IROM SD/MMC或IROM NAND方式運行代碼,用到了中斷,則也必須開MMU,因為IROM啟動在0x0地址處為IROM固化代碼,需要對中斷向量表重新映射到RAM。(本章節(jié)為避免復(fù)雜化,暫時不講解,注釋掉MMU的初始化)
1.8. 初始化棧不管是用匯編還是用c編寫代碼,棧是一定要分配及初始化的。arm7/arm9有七種工作模式,每種模式的棧均應(yīng)該設(shè)置,最后是進入用戶模式。
1.9. 跳轉(zhuǎn)到c入口進入c入口之前是需要初始化c環(huán)境的,如清0全局變量、靜態(tài)變量區(qū)等。此處為保持跟MDK的其它arm啟動代碼一致,直接跳轉(zhuǎn)到__main,利用編譯器的庫函數(shù)來完成c環(huán)境的初始化,最后才是真正的用戶main函數(shù)。啟動代碼完成后,最后是用絕對地址來跳轉(zhuǎn)到c入口__main的。
2. 啟動代碼的實現(xiàn)筆者對啟動代碼都是有一定的注釋,有些寄存器的設(shè)置是需要參考芯片數(shù)據(jù)手冊,S3C2416數(shù)據(jù)手冊,arm架構(gòu)以及匯編語法學習筆者在之前的文章已給出相關(guān)資料的鏈接,歡迎下載學習。只要加入了啟動代碼,就可以任意用c語言來開發(fā)S3C2416了。
;/*******************************************************/
;/* s3c2416.s: start code forsamsung s3c2416/50/51(arm9) */
;/********************************************************/
; Clock setting(External Crystal12M):
; MPLLCLK = 800M, EPLLCLK = 96M
; ARMCLK = 400M, HCLK = 133M
; DDRCLK = 266M, SSMCCLK = 66M,PCLK = 66M
; HSMMC1 = 24M
; Standard definitions of Mode bitsand Interrupt (I & F) flags in PSRs
Mode_USR EQU0x10
Mode_FIQ EQU0x11
Mode_IRQ EQU0x12
Mode_SVC EQU0x13
Mode_ABT EQU0x17
Mode_UND EQU0x1B
Mode_SYS EQU0x1F
; when I bit is set, IRQ isdisabled
I_Bit EQU 0x80
; when F bit is set, FIQ isdisabled
F_Bit EQU 0x40
; Stack Configuration
UND_Stack_Size EQU0x00000020
SVC_Stack_Size EQU0x00000020
ABT_Stack_Size EQU0x00000020
FIQ_Stack_Size EQU0x00000100
IRQ_Stack_Size EQU0x00000400
USR_Stack_Size EQU0x00001000
ISR_Stack_Size EQU(UND_Stack_Size + SVC_Stack_Size +
ABT_Stack_Size+ FIQ_Stack_Size +
IRQ_Stack_Size)
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACEUSR_Stack_Size
__initial_sp SPACE ISR_Stack_Size
Stack_Top
; Heap Configuration
Heap_Size EQU0x00000200
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACEHeap_Size
__heap_limit
; Internal Memory Base Addresses
IRAM_BASE EQU0x40000000
; Watchdog Timer Base Address
WT_BASE EQU0x53000000
; Interrupt Register Base Address
INT_BASE EQU 0x4A000000
INTMSK1_OFS EQU 0x08
INTSUBMSK_OFS EQU 0x1C
INTMSK2_OFS EQU 0x48
; Clock Base Address
CLOCK_BASE EQU 0x4C000000
LOCKCON0_OFS EQU 0x00
LOCKCON1_OFS EQU 0x04
MPLLCON_OFS EQU 0x10
EPLLCON_OFS EQU 0x18
CLKSRC_OFS EQU 0x20
CLKDIV0_OFS EQU 0x24
CLKDIV1_OFS EQU 0x28
CLKDIV2_OFS EQU 0x2C
;----------------------- CODE-------------------------------------------
PRESERVE8
;Area Definition and Entry Point
;Startup Code must be linked first at Address at which it expects to run.
AREA RESET, CODE, READONLY
; ENTRY