转载地址 http://blog.csdn.net/cp1300/article/details/17252217
原博主用的是2G SD卡 算出的偏移地址为 0X2400 Byte (注意是从结尾向前的偏移量)
对于使用 SDHC卡的朋友可以参考《S3C6410_Internal_ROM_Booting》这个手册 里面讲了S3C6410从IROM启动的过程
用的 SDHC卡的 算出的偏移地址为 0X82400 Byte (注意是从结尾向前的偏移量)
《S3C6410_Internal_ROM_Booting》中的两种卡 BL0 存放的位置:
原文:
这几天晚上一直折腾S3C6410的裸机SD卡启动,不大想使用UBOOT,我是搞硬件的,对底层非常感兴趣,不喜欢已经写好的,因此自己一直在尝试,其实很早之前就试过SD卡启动,也就是ARM11上电后会把SD卡倒数第9KB开始的8KB(倒数0x2400B偏移量)复制到内部SRAM中执行,这个比较简单,但是代码量只有8K,不能像STM32一样玩,因此查阅相关资料,得知启动方式为L0加载L1,L1加载L2,简单来说,就是上电启动后,固化在S3C6410内部的L0代码启动,将NAND,SD卡等外部存储器映射或者复制到内部SRAM,这个从SD卡或者flash复制过去的代码称之为L1,也就是用户的启动代码,在电脑上相当于硬盘主分区的启动代码和BIOS,用来初始化外时钟以及外设,并启动系统,,这部分代码只有8KB因此完成的工作有限,因此可以使用这段代码完成初始化并复制操作系统或者更大的代码到内存,这部分代码就是L2了,只有L1将内存初始化后才能使用内存,再此之前内存只有8KB,就是内部SRAM,从SD卡启动的时候映射到0x0c000000,从NAND可以是0,也可以是0x0c000000.
目前只实现了L1,无需uboot,只需要烧写到SD卡的指定位置即可,需要将开发板选择为SD卡启动.
启动代码,完成了关闭看门狗,初始化时钟,SDRAM内存,堆栈,VIC,中断等操作(启动代码来自互联网)
- 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) ;数据访问终止模式
- 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)
- ;异常处理函数
- ;---------------------------------------------------------------------------------------------------
- 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]
- ;设置系统时钟
- ;设置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
//主要的函数
- #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;
- }
- }
- }
- //跳转到指定位置执行
- __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;
- }
- //主函数
- 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); //设置串口接收缓冲区
- rGPNCON = 0; //初始化按键
- UART0_SendString("SD BOOT 启动成功!\r\n");
- Delay_Ms(100);
- //按键没有按下从SD卡加载程序
- if((rGPNDAT & 0x3f) == 0x3f)
- {
- Delay_Ms(10);
- if((rGPNDAT & 0x3f) == 0x3f )
- {
- if(SD_Init() == SD_OK)
- {
- UART0_SendString("SD卡初始化成功!\r\n");
- if(SD_ReadMultiBlocks(1621032, (u32 *)0x52000000, 1000) == SD_OK)
- {
- UART0_SendString("从SD卡读取程序成功,开始从0x52000000执行!\r\n");
- jump(); //跳转
- }
- else
- {
- UART0_SendString("从SD卡读取程序失败!\r\n");
- LED0_FLASH();
- }
- }
- else
- {
- UART0_SendString("SD卡初始化失败!\r\n");
- }
- }
- }
- while((rGPNDAT & 0x3f) != 0x3f); //等待按键抬起
- Delay_Ms(100);
- //从串口加载程序
- UART0_SendString("请从串口发送代码!\r\n");
- 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("请从串口发送代码!\r\n");
- LED3_FLASH();
- }
- }
- if(Key_Test() == TRUE)
- {
- //测试检查内存
- *((vu32 *)0x59000000) = 0xa55aaa55;
- *((vu32 *)0x59000000)+=1;
- if(*((vu32 *)0x59000000) == (0xa55aaa55+1))
- {
- UART0_SendString("内存0x59000000检查正确!\r\n");
- }
- else
- {
- UART0_SendString("内存0x59000000检查错误!\r\n");
- }
- //测试检查内存
- *((vu32 *)0x54000000) = 0xaa5aaa55;
- *((vu32 *)0x54000000)-=1;
- if(*((vu32 *)0x54000000) == (0xaa5aaa55-1))
- {
- UART0_SendString("内存0x54000000检查正确!\r\n");
- }
- else
- {
- UART0_SendString("内存0x54000000检查错误!\r\n");
- }
- UART0_SendString("发送完成,开始从0x52000000执行!\r\n");
- jump(); //跳转
- }
- Delay_Ms(1);
- }
- }
- if(SD_ReadMultiBlocks(1621032, (u32 *)0x52000000, 1000)
1621032:程序在SD卡中的位置,注意是物理扇区,不是逻辑扇区,物理扇区是你写的裸机代码能读的扇区地址,比如1,2,等,逻辑扇区是文件系统提供的扇区,两个位置不一样,要注意了.
- 0x52000000 程序启动的位置,在编译的时候就要指定好,一般在SDRAM中.
- 1000:需要加载的扇区数量,每个扇区大小为512B,因此我的程序加载的是512KB.
1.使用串口下载程序
准备好后从串口下载程序,按住随便一个按键,RESET除外,即可使用串口下载程序,波特率115200,我使用的是OK6410开发板,因此按键检测为if((rGPNDAT & 0x3f) != 0x3f );
启动后使用串口把bin发送过去
发送完成后按任意按键(reset除外)即可开始执行
可以看到程序已经开始执行了,刚开始的时候我用串口下载程序,一段时间后CPU就会死掉,还得我折腾一下午,最后发现是CPU主频过高,初始化为633MHZ了,结果不稳定,现在是533MHZ比较稳定了.
2.我已经将要启动的大程序放到SD卡指定位置了,直接复位,不要按下任何按键即可加载,后面将会做上界面,选择启动哪个程序,就行安卓手机SD卡刷机一样,可以选启动程序.
3.启动程序如何写入到SD卡
写入还是比较简单的,看下面的图片
先使用十六进制编辑器打开磁盘,一定要是物理磁盘
指定偏移到倒数第0x2400B,注意:4G以上卡不是在这个位置,找度娘去.
注意框框中的选项
打开SD_BOOT bin文件,全部选中,复制
切换到SD卡的指定位置
右键->编辑->剪贴板数据->写入
一定要在指定的扇区开始写入,写入之后不要忘记保存
另一个需要启动的程序也可以用这个工具看看他的位置
注意一定要看物理扇区编号
主要由于8K代码中无法添加文件系统,如果这个代码启动后就可以无限制了,界面什么的都可以添加进去,后面将会完善L2的代码,实现更加方便的功能.
附上工程RVDS4.0的设置
L1的代码设置
为了减小代码体积,优化等级开高一点,平时测试可以开最低.
L2代码工程
其他位置设置都是一样的
附上工程下载位置:http://download.csdn.net/detail/cp1300/6694183
我使用的是RVDS4.0,想下载或使用的可以看看我的博文,里面详细介绍了RVDS4.0的安装以及设置.
http://blog.csdn.net/cp1300/article/details/7772645//安装
http://blog.csdn.net/cp1300/article/details/7772809//建立工程