這幾天晚上一直折騰S3C6410的裸機SD卡啟動,不大想使用UBOOT,我是搞硬件的,對底層非常感興趣,不喜歡已經(jīng)寫好的,因此自己一直在嘗試,其實很早之前就試過SD卡啟動,也就是ARM11上電后會把SD卡倒數(shù)第9KB開始的8KB(倒數(shù)0x2400B偏移量)復制到內(nèi)部SRAM中執(zhí)行,這個比較簡單,但是代碼量只有8K,不能像STM32一樣玩,因此查閱相關資料,得知啟動方式為L0加載L1,L1加載L2,簡單來說,就是上電啟動后,固化在S3C6410內(nèi)部的L0代碼啟動,將NAND,SD卡等外部存儲器映射或者復制到內(nèi)部SRAM,這個從SD卡或者flash復制過去的代碼稱之為L1,也就是用戶的啟動代碼,在電腦上相當于硬盤主分區(qū)的啟動代碼和BIOS,用來初始化外時鐘以及外設,并啟動系統(tǒng),,這部分代碼只有8KB因此完成的工作有限,因此可以使用這段代碼完成初始化并復制操作系統(tǒng)或者更大的代碼到內(nèi)存,這部分代碼就是L2了,只有L1將內(nèi)存初始化后才能使用內(nèi)存,再此之前內(nèi)存只有8KB,就是內(nèi)部SRAM,從SD卡啟動的時候映射到0x0c000000,從NAND可以是0,也可以是0x0c000000.
目前只實現(xiàn)了L1,無需uboot,只需要燒寫到SD卡的指定位置即可,需要將開發(fā)板選擇為SD卡啟動.
啟動代碼,完成了關閉看門狗,初始化時鐘,SDRAM內(nèi)存,堆棧,VIC,中斷等操作(啟動代碼來自互聯(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外設寄存器的基地址和地址空間?重要 ;設置為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] ;--------------------------------------------------------------------------------------------------- ;設置時鐘源 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] ;設置時鐘分頻 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] ;使能時鐘 LDR R0,=rHCLK_GATE LDR R1,=0xFFFFFFFF STR R1,[R0] LDR R0,=rPCLK_GATE STR R1,[R0] LDR R0,=rSCLK_GATE STR R1,[R0] ;設置系統(tǒng)時鐘 ;設置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] ;設置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] ;設置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?????????????????????;確認工作到同步模式 ????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?? ;--------------------------------------------------------------------------------------------------- ;設置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 ;--------------------------------------------------------------------------------------------------- ;設置堆棧 ;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" //簡單的延時 void?Delay_Ms(u32?n) { u32?i; while(n?--) { for(i?=?0;i?<?0xfff;i?++) { nop; } ? } } //跳轉(zhuǎn)到指定位置執(zhí)行 __asm?jump() { LDR?PC,=0x52000000; } //按鍵檢測 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); //設置串口接收緩沖區(qū) rGPNCON =?0; //初始化按鍵 UART0_SendString("SD?BOOT?啟動成功!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("請從串口發(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("請從串口發(fā)送代碼!rn"); LED3_FLASH(); } } if(Key_Test()?==?TRUE) { //測試檢查內(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檢查錯誤!rn"); } //測試檢查內(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檢查錯誤!rn"); } UART0_SendString("發(fā)送完成,開始從0x52000000執(zhí)行!rn"); jump(); //跳轉(zhuǎn) } Delay_Ms(1); } }
if(SD_ReadMultiBlocks(1621032,?(u32?*)0x52000000,?1000)
當沒有按鍵按下的時候,或從SD卡指定位置加載一個比較的程序執(zhí)行,可以是操作系統(tǒng),或自己的裸機程序.
1621032:程序在SD卡中的位置,注意是物理扇區(qū),不是邏輯扇區(qū),物理扇區(qū)是你寫的裸機代碼能讀的扇區(qū)地址,比如1,2,等,邏輯扇區(qū)是文件系統(tǒng)提供的扇區(qū),兩個位置不一樣,要注意了.
0x52000000?程序啟動的位置,在編譯的時候就要指定好,一般在SDRAM中.
1000:需要加載的扇區(qū)數(shù)量,每個扇區(qū)大小為512B,因此我的程序加載的是512KB.
1.使用串口下載程序
準備好后從串口下載程序,按住隨便一個按鍵,RESET除外,即可使用串口下載程序,波特率115200,我使用的是OK6410開發(fā)板,因此按鍵檢測為if((rGPNDAT & 0x3f) != 0x3f );
啟動后使用串口把bin發(fā)送過去
發(fā)送完成后按任意按鍵(reset除外)即可開始執(zhí)行
可以看到程序已經(jīng)開始執(zhí)行了,剛開始的時候我用串口下載程序,一段時間后CPU就會死掉,還得我折騰一下午,最后發(fā)現(xiàn)是CPU主頻過高,初始化為633MHZ了,結(jié)果不穩(wěn)定,現(xiàn)在是533MHZ比較穩(wěn)定了.
2.我已經(jīng)將要啟動的大程序放到SD卡指定位置了,直接復位,不要按下任何按鍵即可加載,后面將會做上界面,選擇啟動哪個程序,就行安卓手機SD卡刷機一樣,可以選啟動程序.
3.啟動程序如何寫入到SD卡
寫入還是比較簡單的,看下面的圖片
先使用十六進制編輯器打開磁盤,一定要是物理磁盤
指定偏移到倒數(shù)第0x2400B,注意:4G以上卡不是在這個位置,找度娘去.
注意框框中的選項
打開SD_BOOT bin文件,全部選中,復制
切換到SD卡的指定位置
右鍵->編輯->剪貼板數(shù)據(jù)->寫入
一定要在指定的扇區(qū)開始寫入,寫入之后不要忘記保存
另一個需要啟動的程序也可以用這個工具看看他的位置
注意一定要看物理扇區(qū)編號
主要由于8K代碼中無法添加文件系統(tǒng),如果這個代碼啟動后就可以無限制了,界面什么的都可以添加進去,后面將會完善L2的代碼,實現(xiàn)更加方便的功能.
附上工程RVDS4.0的設置
L1的代碼設置
為了減小代碼體積,優(yōu)化等級開高一點,平時測試可以開最低.
L2代碼工程
其他位置設置都是一樣的