S3C6410 純粹的裸機(jī)啟動(dòng),自己寫的SD BOOT啟動(dòng)
這幾天晚上一直折騰S3C6410的裸機(jī)SD卡啟動(dòng),不大想使用UBOOT,我是搞硬件的,對(duì)底層非常感興趣,不喜歡已經(jīng)寫好的,因此自己一直在嘗試,其實(shí)很早之前就試過SD卡啟動(dòng),也就是ARM11上電后會(huì)把SD卡倒數(shù)第9KB開始的8KB(倒數(shù)0x2400B偏移量)復(fù)制到內(nèi)部SRAM中執(zhí)行,這個(gè)比較簡單,但是代碼量只有8K,不能像STM32一樣玩,因此查閱相關(guān)資料,得知啟動(dòng)方式為L0加載L1,L1加載L2,簡單來說,就是上電啟動(dòng)后,固化在S3C6410內(nèi)部的L0代碼啟動(dòng),將NAND,SD卡等外部存儲(chǔ)器映射或者復(fù)制到內(nèi)部SRAM,這個(gè)從SD卡或者flash復(fù)制過去的代碼稱之為L1,也就是用戶的啟動(dòng)代碼,在電腦上相當(dāng)于硬盤主分區(qū)的啟動(dòng)代碼和BIOS,用來初始化外時(shí)鐘以及外設(shè),并啟動(dòng)系統(tǒng),,這部分代碼只有8KB因此完成的工作有限,因此可以使用這段代碼完成初始化并復(fù)制操作系統(tǒng)或者更大的代碼到內(nèi)存,這部分代碼就是L2了,只有L1將內(nèi)存初始化后才能使用內(nèi)存,再此之前內(nèi)存只有8KB,就是內(nèi)部SRAM,從SD卡啟動(dòng)的時(shí)候映射到0x0c000000,從NAND可以是0,也可以是0x0c000000.
目前只實(shí)現(xiàn)了L1,無需uboot,只需要燒寫到SD卡的指定位置即可,需要將開發(fā)板選擇為SD卡啟動(dòng).
啟動(dòng)代碼,完成了關(guān)閉看門狗,初始化時(shí)鐘,SDRAM內(nèi)存,堆棧,VIC,中斷等操作(啟動(dòng)代碼來自互聯(lián)網(wǎng))
INCLUDE?S3C6410.inc PRESERVE8 AREA?Init,?CODE,?READONLY STACK_BASEADDRESS?EQU??0x0c000400;0x52000000 SVCStack EQU (STACK_BASEADDRESS) ;管理模式 UndefStack EQU (STACK_BASEADDRESS?-?0x300) ;指令終止模式 AbortStack EQU (STACK_BASEADDRESS?-?0x300) ;數(shù)據(jù)訪問終止模式 IRQStack EQU (STACK_BASEADDRESS?-?0x200) ;中斷模式 FIQStack EQU (STACK_BASEADDRESS?-?0x100) ;快速中斷模式 ;--------------------------- ;?CPSR?Mode?Bit?Definition ;--------------------------- Mode_USR????EQU????(0x10) Mode_FIQ????EQU????(0x11) Mode_IRQ????EQU????(0x12) Mode_SVC????EQU????(0x13) Mode_ABT????EQU????(0x17) Mode_UND????EQU????(0x1B) Mode_SYS????EQU????(0x1F) Mode_MASK????EQU????(0x1F) NOINT????????EQU????(0xC0) I_Bit????????EQU????(0x80) F_Bit????????EQU????(0x40) ;異常處理函數(shù) ? ;--------------------------------------------------------------------------------------------------- IMPORT?main EXPORT ResetHandler ResetHandler ????ldr????????r0,?=0x70000013????????;?Base?Addres?:?0x70000000,?Size?:?256?MB?(0x13) mcr????????p15,0,r0,c15,c2,4??????;告訴CPU外設(shè)寄存器的基地址和地址空間?重要 ;設(shè)置為SVC模式 MRS R0,CPSR BIC R0,R0,#0x1F ORR R0,R0,#0xD3 MSR CPSR_cxsf,R0 ;未知模式堆棧 mrs r0,cpsr bic r0,r0,#Mode_MASK orr r1,r0,#Mode_UND|NOINT msr cpsr_cxsf,r1 ;UndefMode ldr sp,=UndefStack ;異常模式堆棧 orr r1,r0,#Mode_ABT|NOINT msr cpsr_cxsf,r1 ;AbortMode ldr sp,=AbortStack ;中斷模式堆棧 orr r1,r0,#Mode_IRQ|NOINT msr cpsr_cxsf,r1 ;IRQMode ldr sp,=IRQStack ;管理模式堆棧 bic r0,r0,#Mode_MASK|NOINT orr r1,r0,#Mode_SVC msr cpsr_cxsf,r1 ;SVCMode ldr sp,=SVCStack ;禁止看門狗 LDR R0,=rWTCON LDR R1,=0x0 STR R1,[R0] ;禁止cache和mmu LDR R0,=0x0 MRC p15,0,R0,c1,c0,0 LDR R1,=0xFFFF BIC R0,R0,R1 MCR p15,0,R0,c1,c0,0 ;禁止所有中斷 LDR R0,=rVIC0INTENCLEAR? LDR R1,=0xFFFFFFFF STR R1,[R0] LDR R0,=rVIC1INTENCLEAR? LDR R1,=0xFFFFFFFF STR R1,[R0] ;--------------------------------------------------------------------------------------------------- ;設(shè)置時(shí)鐘源 LDR R0,=rOTHERS LDR R1,[R0] ORR R1,R1,#(1<<6) LDR R0,=rCLK_SRC LDR R1,=(1<<13)|7 STR R1,[R0] LDR R0,=rCLK_SRC2 LDR R1,=0x0 STR R1,[R0] ;設(shè)置時(shí)鐘分頻 LDR R0,=rCLK_DIV0 LDR R1,=0x01043310 STR R1,[R0] LDR R0,=rCLK_DIV1 LDR R1,=0x0 STR R1,[R0] LDR R0,=rCLK_DIV2 LDR R1,=3<<16 STR R1,[R0] ;使能時(shí)鐘 LDR R0,=rHCLK_GATE LDR R1,=0xFFFFFFFF STR R1,[R0] LDR R0,=rPCLK_GATE STR R1,[R0] LDR R0,=rSCLK_GATE STR R1,[R0] ;設(shè)置系統(tǒng)時(shí)鐘 ;設(shè)置APLL?532MHz LDR R0,=rAPLL_LOCK LDR R1,=0xFFFF STR R1,[R0] LDR R0,=rAPLL_CON LDR R1,=(1<<31)|(266<<16)|(3<<8)|(1) STR R1,[R0] ;設(shè)置MPLL?532MHz LDR R0,=rMPLL_LOCK LDR R1,=0xFFFF STR R1,[R0] LDR R0,=rMPLL_CON LDR R1,=(1<<31)|(266<<16)|(3<<8)|(1) STR R1,[R0] ;設(shè)置EPLL 96MHz LDR R0,=rEPLL_LOCK LDR R1,=0xFFFF STR R1,[R0] LDR R0,=rEPLL_CON0 LDR R1,=(1<<31)|(32<<16)|(1<<8)|(2) STR R1,[R0] LDR R0,=rEPLL_CON1 LDR R1,=0x0 STR R1,[R0]? ;================= ;選擇同步工作模式 ;================= ????ldr?????r4,?=rOTHERS ????ldr?????r5,?[r4] ????bic?????r5,?r5,?#0xC0 ????orr?????r5,?r5,?#0x40???????????;?SyncReq?=?Async,?SyncMUX?=?Sync ????str?????r5,?[r4] ???? _wait_for_async?????????????????????;確認(rèn)工作到同步模式 ????ldr?????r5,?[r4]????????????????;?Read?OTHERS ????and?????r5,?r5,?#0xF00??????????;?Wait?SYNCMODEACK?=?0x0 ????cmp?????r5,?#0x0 ????bne?????_wait_for_async ????ldr?????r4,?=rOTHERS ????ldr?????r5,?[r4] ????bic?????r5,?r5,?#0x40???????????;SyncMUX?=?Async ????str?????r5,?[r4] ????nop ????nop ????nop ????nop ????nop?? ;--------------------------------------------------------------------------------------------------- ;設(shè)置DRAM LDR R0,=0x7E00F120?? LDR R1,=0xD STR R1,[R0] LDR R0,=rP1MEMCCMD LDR R1,=0x4 STR R1,[R0] LDR R0,=rP1REFRESH LDR R1,=0x40D STR R1,[R0] LDR R0,=rP1CASLAT LDR R1,=0x6 STR R1,[R0] LDR R0,=rP1T_DQSS LDR R1,=0x1 STR R1,[R0] LDR R0,=rP1T_MRD LDR R1,=0x2 STR R1,[R0] LDR R0,=rP1T_RAS LDR R1,=0x6 STR R1,[R0] LDR R0,=rP1T_RC LDR R1,=0xA STR R1,[R0] LDR R0,=rP1T_RCD LDR R1,=0xB STR R1,[R0] LDR R0,=rP1T_RFC LDR R1,=0x10B STR R1,[R0] LDR R0,=rP1T_RP LDR R1,=0xB STR R1,[R0] LDR R0,=rP1T_RRD LDR R1,=0x2 STR R1,[R0] LDR R0,=rP1T_WR LDR R1,=0x2 STR R1,[R0] LDR R0,=rP1T_WTR LDR R1,=0x2 STR R1,[R0] LDR R0,=rP1T_XP LDR R1,=0x2 STR R1,[R0] LDR R0,=rP1T_XSR LDR R1,=0x10 STR R1,[R0] LDR R0,=rP1T_ESR LDR R1,=0x10 STR R1,[R0] LDR R0,=rP1MEMCFG LDR R1,=0x1001A STR R1,[R0] LDR R0,=rP1MEMCFG2 LDR R1,=0xB45 STR R1,[R0] LDR R0,=rP1_chip_0_cfg LDR R1,=0x150F0 STR R1,[R0] LDR R0,=rP1_user_cfg LDR R1,=0x0 STR R1,[R0] LDR R0,=rP1_DIRECTCMD LDR R1,=0xC0000 STR R1,[R0] LDR R0,=rP1_DIRECTCMD LDR R1,=0x00000 STR R1,[R0] LDR R0,=rP1_DIRECTCMD LDR R1,=0x40000 STR R1,[R0] STR R1,[R0] LDR R0,=rP1_DIRECTCMD LDR R1,=0xA0000 STR R1,[R0] LDR R0,=rP1_DIRECTCMD LDR R1,=0x80032 STR R1,[R0] LDR R0,=rP1MEMCCMD LDR R1,=0x0 STR R1,[R0] LDR R0,=rP1MEMSTAT DRAM_WAIT LDR R1,[R0] AND R1,R1,#0x3 CMP R1,#0x1 BNE DRAM_WAIT ;--------------------------------------------------------------------------------------------------- ;設(shè)置堆棧 ;STACK_TOP EQU 0x52000000;0x0c000400 ; LDR SP,=STACK_TOP ;--------------------------------------------------------------------------------------------------- ;使能VIC mrc? p15,0,r0,c1,c0,0 orr? r0,r0,#(1<<24) mcr? p15,0,r0,c1,c0,0 ;--------------------------------------------------------------------------------------------------- ;使能VFP MRC????????p15,?0,?r0,?c1,?c0,?2? ? ORR????????r0,?r0,?#0x00F00000? ? MCR????????p15,?0,?r0,?c1,?c0,?2? ? ? MOV????????r1,?#0? ? MCR????????p15,?0,?r1,?c7,?c5,?4? ? MOV????????r0,#0x40000000? ? FMXR???????FPEXC,?r0???????;?FPEXC?=?r0? ? nop? nop? ;--------------------------------------------------------------------------------------------------- LDR R0,=rGPMCON LDR R1,=0x11111 STR R1,[R0] LDR R0,=rGPMPUD LDR R1,=0x0 STR R1,[R0] LDR R0,=rGPMDAT LDR R1,=0 STR R1,[R0] B main END
//主要的函數(shù)
#include?"system.h" #include?"uart.h" #include?"other.h" #include?"SDCARD.h" //簡單的延時(shí) void?Delay_Ms(u32?n) { u32?i; while(n?--) { for(i?=?0;i?<?0xfff;i?++) { nop; } ? } } //跳轉(zhuǎn)到指定位置執(zhí)行 __asm?jump() { LDR?PC,=0x52000000; } //按鍵檢測(cè) bool?Key_Test(void) { static?u8?i?=?0; if((rGPNDAT?&?0x3f)?!=?0x3f?) { i?++; if(i?>?10) { i?=?0; return?TRUE; } } return?FALSE; } //主函數(shù) int?main(void) { u16?n?=?0; u32?cnt1?=?0,?cnt2?=?0; LED_Init(); //初始化LED UART0_Init(ENABLE,115200); //初始化串口 UARTx_SetRxBuff(UART_CH0,?(u8?*)0x52000000,?1024*1024*10); //設(shè)置串口接收緩沖區(qū) rGPNCON =?0; //初始化按鍵 UART0_SendString("SD?BOOT?啟動(dòng)成功!rn"); Delay_Ms(100); //按鍵沒有按下從SD卡加載程序 if((rGPNDAT?&?0x3f)?==?0x3f) { Delay_Ms(10); if((rGPNDAT?&?0x3f)?==?0x3f?) { if(SD_Init()?==?SD_OK) { UART0_SendString("SD卡初始化成功!rn"); if(SD_ReadMultiBlocks(1621032,?(u32?*)0x52000000,?1000)?==?SD_OK) { UART0_SendString("從SD卡讀取程序成功,開始從0x52000000執(zhí)行!rn"); jump(); //跳轉(zhuǎn) } else { UART0_SendString("從SD卡讀取程序失敗!rn"); LED0_FLASH(); } } else { UART0_SendString("SD卡初始化失敗!rn"); } } } while((rGPNDAT?&?0x3f)?!=?0x3f); //等待按鍵抬起 Delay_Ms(100); //從串口加載程序 UART0_SendString("請(qǐng)從串口發(fā)送代碼!rn"); while(1) { n?++; if(n?==?300) { LED1_FLASH(); n?=?0; cnt1?=?cnt2; cnt2?=?UARTx_GetRxCnt(UART_CH0); if(cnt1!=cnt2) { LED2_FLASH(); } else?if(cnt2?==?0) { //UART0_SendString("請(qǐng)從串口發(fā)送代碼!rn"); LED3_FLASH(); } } if(Key_Test()?==?TRUE) { //測(cè)試檢查內(nèi)存 *((vu32?*)0x59000000)?=?0xa55aaa55; *((vu32?*)0x59000000)+=1; if(*((vu32?*)0x59000000)?==?(0xa55aaa55+1)) { UART0_SendString("內(nèi)存0x59000000檢查正確!rn"); } else { UART0_SendString("內(nèi)存0x59000000檢查錯(cuò)誤!rn"); } //測(cè)試檢查內(nèi)存 *((vu32?*)0x54000000)?=?0xaa5aaa55; *((vu32?*)0x54000000)-=1; if(*((vu32?*)0x54000000)?==?(0xaa5aaa55-1)) { UART0_SendString("內(nèi)存0x54000000檢查正確!rn"); } else { UART0_SendString("內(nèi)存0x54000000檢查錯(cuò)誤!rn"); } UART0_SendString("發(fā)送完成,開始從0x52000000執(zhí)行!rn"); jump(); //跳轉(zhuǎn) } Delay_Ms(1); } }
if(SD_ReadMultiBlocks(1621032,?(u32?*)0x52000000,?1000)
當(dāng)沒有按鍵按下的時(shí)候,或從SD卡指定位置加載一個(gè)比較的程序執(zhí)行,可以是操作系統(tǒng),或自己的裸機(jī)程序.
1621032:程序在SD卡中的位置,注意是物理扇區(qū),不是邏輯扇區(qū),物理扇區(qū)是你寫的裸機(jī)代碼能讀的扇區(qū)地址,比如1,2,等,邏輯扇區(qū)是文件系統(tǒng)提供的扇區(qū),兩個(gè)位置不一樣,要注意了.
0x52000000?程序啟動(dòng)的位置,在編譯的時(shí)候就要指定好,一般在SDRAM中.
1000:需要加載的扇區(qū)數(shù)量,每個(gè)扇區(qū)大小為512B,因此我的程序加載的是512KB.
1.使用串口下載程序
準(zhǔn)備好后從串口下載程序,按住隨便一個(gè)按鍵,RESET除外,即可使用串口下載程序,波特率115200,我使用的是OK6410開發(fā)板,因此按鍵檢測(cè)為if((rGPNDAT & 0x3f) != 0x3f );
啟動(dòng)后使用串口把bin發(fā)送過去
發(fā)送完成后按任意按鍵(reset除外)即可開始執(zhí)行
可以看到程序已經(jīng)開始執(zhí)行了,剛開始的時(shí)候我用串口下載程序,一段時(shí)間后CPU就會(huì)死掉,還得我折騰一下午,最后發(fā)現(xiàn)是CPU主頻過高,初始化為633MHZ了,結(jié)果不穩(wěn)定,現(xiàn)在是533MHZ比較穩(wěn)定了.
2.我已經(jīng)將要啟動(dòng)的大程序放到SD卡指定位置了,直接復(fù)位,不要按下任何按鍵即可加載,后面將會(huì)做上界面,選擇啟動(dòng)哪個(gè)程序,就行安卓手機(jī)SD卡刷機(jī)一樣,可以選啟動(dòng)程序.
3.啟動(dòng)程序如何寫入到SD卡
寫入還是比較簡單的,看下面的圖片
先使用十六進(jìn)制編輯器打開磁盤,一定要是物理磁盤
指定偏移到倒數(shù)第0x2400B,注意:4G以上卡不是在這個(gè)位置,找度娘去.
注意框框中的選項(xiàng)
打開SD_BOOT bin文件,全部選中,復(fù)制
切換到SD卡的指定位置
右鍵->編輯->剪貼板數(shù)據(jù)->寫入
一定要在指定的扇區(qū)開始寫入,寫入之后不要忘記保存
另一個(gè)需要啟動(dòng)的程序也可以用這個(gè)工具看看他的位置
注意一定要看物理扇區(qū)編號(hào)
主要由于8K代碼中無法添加文件系統(tǒng),如果這個(gè)代碼啟動(dòng)后就可以無限制了,界面什么的都可以添加進(jìn)去,后面將會(huì)完善L2的代碼,實(shí)現(xiàn)更加方便的功能.
附上工程RVDS4.0的設(shè)置
L1的代碼設(shè)置
為了減小代碼體積,優(yōu)化等級(jí)開高一點(diǎn),平時(shí)測(cè)試可以開最低.
L2代碼工程
其他位置設(shè)置都是一樣的