前言:
最近在做一个基于s3c6410的裸机MP3程序要求的功能不多但是由于自己是新手所以也做了二十几天虽然很多部分时间都浪费在了编译和测试上......
下面是需求:
1、流水灯(按键与触摸屏都能单独控制灯亮灭)
2、图片显示(放大缩小,多幅显示,画中画,各种特效)
3、电子音乐、电子琴(蜂鸣器播放)
4、RTC(查看、设置系统时间、闹钟)
5、画图(橡皮擦、画笔颜色)
6、用户设置(如背景图片设置等等,用IIC控制)
7、音乐播放(IIS控制,上一首、下一首、暂停、继续、音量)
8、录音/播放
虽然功能不多 但是涵盖了很多知识点在做的过程中遇到了各种各样的问题,是时候写写笔记了,怕以后忘记了。
正文:
要说启动代码必须要先知道ARM的启动流程这里我就简单的说下s3c2440和s3c6410还有s5pv210从nandflash启动流程吧
s3c2440:
首先先看这一幅图:
图的左边是NorFlash的启动方式,我们不讨论,看右边有个叫 BootSRAM(4KB)的东东他还有个比较常见的名字叫“垫脚石(Stepping Stone)”,由于nandflash不参与CPU 的统一编址所以我们在没有初始化nandflash控制器之前没有办法直接使用nandflash。当我们把裸机程序烧写到nandflash从nandflash启动后2440的CUP会自动把nandflash地址前4KB的程序拷贝到垫脚石中运行,然后我们通过这4KB 的代码做一些必要的初始化后就能把nandflash中剩下的代码拷贝到内存中去运行了,而这4KB 的代码就是start.S,我们的汇编启动代码
S3C6410:
6410和2440有些不同还是先看图:
图中的 BL0~2表示启动的阶段顺序。当6410上电后如果选择IROM启动着cpu会将IROM映射(注意这里是映射不是拷贝,由于6410启动方式曾多所以划出一块不放任何设备的区域用映射的方式来选择启动方式)到镜像区域(从0地址开始)然后运行在IROM(BL0)中厂家固化好的程序把nandflash中的BL1拷贝到8KB的垫脚石中去后面和2440一样做一些必要的初始化后把BL2也就是剩下的代码拷贝到内存中运行。
S5PV210:
210和6410差不多先看图
和6410相比 210的垫脚石大了很多 有96KB 这样的话在拷贝BL2的时候就有两种选择,1、拷贝到垫脚石中直接运行,2、垫脚石放不下,拷贝到内存中运行,所以我们在拷贝的时候要先判断剩下的程序的大小如果BL2大于80KB的话就不拷贝到垫脚石而拷贝到内中运行。
启动流程说完了现在开始讲启动代码吧:
按照上图的流程来写程序,这里只说下需要注意的地方因为具体方法都在三星提供的手册里
1、设置异常向量表,arm有七种工作模式,USER、SVC、ABORED、UDEFINED、IRQ、FIQ、SYS所以我需要为异常模式ABORED、UDEFINED、IRQ、FIQ设置统一的处理入口
2、设置为工作在SVC 模式目的在于获得更高的权限
3、这一步是6410需要做的将外设基地址初始化这样才能正常使用外设
4、清除bss段这个涉及到连接器脚本这里只说作用,BSS段是用来存放全局变量的,清除的目的是为了给C语言全局变量赋初值0.
下面贴出6410代码稍作修改就可以给210和2440使用,其中210需要注意,210有个加头的流程所以210代码会多出16位的首部校验和所以从nandflash拷贝到内存时要吧这十六位数据忽略掉,也就是nandflash的地址向高位移动十六位大小开始拷贝。
5、设置好中断模式的堆栈指针,这样才能正常进出中断,具体设置在下面代码中
.text
.global _start
_start:
<span style="white-space:pre"> </span>b reset
<span style="white-space:pre"> </span>ldr pc, _undifined_instruction
<span style="white-space:pre"> </span>ldr pc, _software_interrupt
<span style="white-space:pre"> </span>ldr pc, _prefetch_abort
<span style="white-space:pre"> </span>ldr pc, _data_abort
<span style="white-space:pre"> </span>ldr pc, _not_used
<span style="white-space:pre"> </span>ldr pc, _irq
<span style="white-space:pre"> </span>ldr pc, _fiq
<span style="white-space:pre"> </span>
@以下只中断向量表
_undifined_instruction: .word undifined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word reset
@异常处理
undifined_instruction:
<span style="white-space:pre"> </span>nop
software_interrupt:
<span style="white-space:pre"> </span>nop
<span style="white-space:pre"> </span>
prefetch_abort:
<span style="white-space:pre"> </span>nop
<span style="white-space:pre"> </span>
data_abort:
<span style="white-space:pre"> </span>nop
not_used:
<span style="white-space:pre"> </span>nop
irq:
<span style="white-space:pre"> </span>ldr sp, =0x54000000 @设置中断模式堆栈指针
<span style="white-space:pre"> </span>sub lr, lr, #4
<span style="white-space:pre"> </span>stmdb sp!, {r0-r12, lr} @保护现场
<span style="white-space:pre"> </span>bl do_irq<span style="white-space:pre"> </span> @进入普通中断统一处理入口(c语言函数)
<span style="white-space:pre"> </span>ldmia sp!, {r0-r12, pc}^ @恢复现场
fiq:<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>nop
reset:
<span style="white-space:pre"> </span>bl set_svc
<span style="white-space:pre"> </span>bl set_peri_port
<span style="white-space:pre"> </span>bl disable_watchdog
<span style="white-space:pre"> </span>bl disable_interrupt
<span style="white-space:pre"> </span>bl disable_mmu
<span style="white-space:pre"> </span>bl init_clock
<span style="white-space:pre"> </span>bl mem_init
<span style="white-space:pre"> </span>bl init_stack
<span style="white-space:pre"> </span>bl nand_init
<span style="white-space:pre"> </span>bl copy_to_ram
<span style="white-space:pre"> </span>bl clean_bss
<span style="white-space:pre"> </span>ldr pc, =gboot_main @跳到C语言主函数也就是内存开始执行,这条指令是绝对跳转
set_peri_port: @初始化外设基地址
<span style="white-space:pre"> </span>ldr r0, =0x70000000 @6410的外设地址是从 0x70000000开始的
<span style="white-space:pre"> </span>orr r0, r0, #0x13
<span style="white-space:pre"> </span>mcr p15,0,r0,c15,c2,4
<span style="white-space:pre"> </span>mov pc, lr
set_svc:
<span style="white-space:pre"> </span>mrs r0, cpsr
<span style="white-space:pre"> </span>bic r0, r0,#0x1f
<span style="white-space:pre"> </span>orr r0, r0,#0xd3
<span style="white-space:pre"> </span>msr cpsr, r0
<span style="white-space:pre"> </span>mov pc, lr
#define pWTCON 0x7e004000
disable_watchdog:
<span style="white-space:pre"> </span>ldr r0, =pWTCON
<span style="white-space:pre"> </span>mov r1, #0x0
<span style="white-space:pre"> </span>str r1, [r0]
<span style="white-space:pre"> </span>mov pc, lr
disable_interrupt:
<span style="white-space:pre"> </span>mvn r1,#0x0
<span style="white-space:pre"> </span>ldr r0,=0x71200014
<span style="white-space:pre"> </span>str r1,[r0]
<span style="white-space:pre"> </span>ldr r0,=0x71300014
<span style="white-space:pre"> </span>str r1,[r0]
<span style="white-space:pre"> </span>mov pc, lr
disable_mmu:
<span style="white-space:pre"> </span>mcr p15,0,r0,c7,c7,0
<span style="white-space:pre"> </span>mrc p15,0,r0,c1,c0,0
<span style="white-space:pre"> </span>bic r0, r0, #0x00000007
<span style="white-space:pre"> </span>mcr p15,0,r0,c1,c0,0
<span style="white-space:pre"> </span>mov pc, lr
#define CLK_DIV0 0x7e00f020
#define OTHERS 0x7e00f900
#define MPLL_CON 0x7e00f010
#define APLL_CON 0x7e00f00c
#define CLK_SRC 0x7e00f01c
#define CLK_SRC_VAL ((0x3<<0)|(0<<13)|(0<<26))
#define DIV_VAL ((0x0<<0)|(0x1<<9)|(0x1<<8)|(0x3<<12))
#define PLL_VAL ((1<<31)|(266<<16)|(3<<8)|(1<<0))
#define EPLL_VAL0 ((1<<31)|(32<<16)|(1<<8)|(2<<0))
#define EPLL_VAL1 (0<<0)
#define EPLL_CON0 0x7E00F014
#define EPLL_CON1 0x7E00F018
#define CLK_DIV2 0x7E00F028
#define DIV2_VAL ((0x0<<8)|(0x0<<12)) @ CLKAUDIO0 = CLKAUDIO1 = 96MHZ
init_clock:
<span style="white-space:pre"> </span>ldr r0, =CLK_DIV0
<span style="white-space:pre"> </span>ldr r1, =DIV_VAL
<span style="white-space:pre"> </span>str r1, [r0]
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>ldr r0, =OTHERS
<span style="white-space:pre"> </span>ldr r1, [r0]
<span style="white-space:pre"> </span>bic r1,r1,#0xc0
<span style="white-space:pre"> </span>str r1, [r0]
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>ldr r0, =APLL_CON
<span style="white-space:pre"> </span>ldr r1, =PLL_VAL
<span style="white-space:pre"> </span>str r1, [r0]
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>ldr r0, =MPLL_CON
<span style="white-space:pre"> </span>ldr r1, =PLL_VAL
<span style="white-space:pre"> </span>str r1, [r0]
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>ldr r0, =CLK_SRC
<span style="white-space:pre"> </span>ldr r1, =CLK_SRC_VAL
<span style="white-space:pre"> </span>str r1, [r0]
<span style="white-space:pre"> </span>@ldr r0, =CLK_DIV2
<span style="white-space:pre"> </span>@ldr r1, =DIV2_VAL
<span style="white-space:pre"> </span>@str r1, [r0]
<span style="white-space:pre"> </span>@ldr r0, =EPLL_CON0 @EPP = 96MHZ
<span style="white-space:pre"> </span>@ldr r1, =EPLL_VAL0
<span style="white-space:pre"> </span>@str r1, [r0]
<span style="white-space:pre"> </span>@ldr r0, =EPLL_CON1
<span style="white-space:pre"> </span>@ldr r1, =EPLL_VAL1
<span style="white-space:pre"> </span>@str r1, [r0]
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>mov pc, lr
<span style="white-space:pre"> </span>
copy_to_ram:
<span style="white-space:pre"> </span>mov r0,#0
<span style="white-space:pre"> </span>ldr r1,=_start
<span style="white-space:pre"> </span>ldr r2,=bss_end
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>sub r2,r2,r1
<span style="white-space:pre"> </span>mov ip,lr
<span style="white-space:pre"> </span>bl nand_to_ram @<span style="font-family: Arial, Helvetica, sans-serif;">nand_to_ram 是C语言函数</span>
<span style="white-space:pre"> </span>mov lr,ip
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>mov pc,lr
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
init_stack:
msr cpsr_c, #0xd2
ldr sp, =0x54000000 //初始化r13_irq
msr cpsr_c, #0xd3
<span style="white-space:pre"> </span>ldr sp, =0x53000000 //初始化R13_svc
<span style="white-space:pre"> </span>mov pc ,lr
clean_bss:
<span style="white-space:pre"> </span>ldr r0, =bss_start
<span style="white-space:pre"> </span>ldr r1, =bss_end
<span style="white-space:pre"> </span>cmp r0, r1
<span style="white-space:pre"> </span>moveq pc, lr
clean_loop:
<span style="white-space:pre"> </span>mov r2, #0
<span style="white-space:pre"> </span>str r2, [r0], #4
<span style="white-space:pre"> </span>cmp r0, r1
<span style="white-space:pre"> </span>bne clean_loop
<span style="white-space:pre"> </span>mov pc, lr
#define GPKCON 0x7f008800
#define GPKDAT 0x7f008808
light_led:
<span style="white-space:pre"> </span>ldr r0, =GPKCON
<span style="white-space:pre"> </span>ldr r1, =0x11110000
<span style="white-space:pre"> </span>str r1, [r0]
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>ldr r0, =GPKDAT
<span style="white-space:pre"> </span>ldr r1, =0xff
<span style="white-space:pre"> </span>str r1, [r0]
<span style="white-space:pre"> </span>mov pc, lr
</pre><pre name="code" class="html">mem.S 内存初始化代码文件
.text
.global mem_init
mem_init:
ldr r0, =0x7e00f120
mov r1, #0x8
str r1, [r0]
ldr r0, =0x7e001004 @内存控制命令寄存器
mov r1, #0x4 @根据手册得知需要先进入配置模式
str r1, [r0]
ldr r0, =0x7e001010 @刷新寄存器地址
ldr r1, =( ( 7800 / ( 1000000000/133000000 ) + 1 ) ) @设置刷新时间
str r1, [r0]
ldr r0, =0x7e001014 @CAS latency寄存器
mov r1, #(3 << 1)
str r1, [r0]
ldr r0, =0x7e001018 @t_DQSS寄存器
mov r1, #0x1
str r1, [r0]
ldr r0, =0x7e00101c @T_MRD寄存器
mov r1, #0x2
str r1, [r0]
ldr r0, =0x7e001020 @t_RAS寄存器
ldr r1, =( ( 45 / ( 1000000000 / 133000000 ) + 1 ) )
str r1, [r0]
ldr r0, =0x7e001024 @t_RC寄存器
ldr r1, =( ( 68 / ( 1000000000 / 133000000 ) + 1 ) )
str r1, [r0]
ldr r0, =0x7e001028 @t_RCD寄存器
ldr r1, =( ( 23 / ( 1000000000 / 133000000 ) + 1 ) )
str r1, [r0]
ldr r0, =0x7e00102c @t_RFC寄存器
ldr r1, =( ( 80 / ( 1000000000 / 133000000 ) + 1 ) )
str r1, [r0]
ldr r0, =0x7e001030 @t_RP寄存器
ldr r1, =( ( 23 / ( 1000000000 / 133000000 ) + 1 ) )
str r1, [r0]
ldr r0, =0x7e001034 @t_rrd寄存器
ldr r1, =( ( 15 / ( 1000000000 / 133000000 ) + 1 ) )
str r1, [r0]
ldr r0, =0x7e001038 @t_wr寄存器
ldr r1, =( ( 15 / ( 1000000000 / 133000000 ) + 1 ) )
@ ldr r2, [r0]
str r1, [r0]
ldr r0, =0x7e00103c @t_wtr寄存器
mov r1, #0x07
str r1, [r0]
ldr r0, =0x7e001040 @t_xp寄存器
mov r1, #0x02
str r1, [r0]
ldr r0, =0x7e001044 @t_xsr寄存器
ldr r1, =( ( 120 / ( 1000000000 / 133000000 ) + 1 ) )
str r1, [r0]
ldr r0, =0x7e001048 @t_esr寄存器
ldr r1, =( ( 120 / ( 1000000000 / 133000000 ) + 1 ) )
str r1, [r0]
ldr r0, =0x7e00100c @内存控制配置寄存器
ldr r1, =0x00010012 @配置控制器
str r1, [r0]
ldr r0, =0x7e00104c @32位DRAM配置控制寄存器
ldr r1, =0x0b45
str r1, [r0]
ldr r0, =0x7e001200 @片选寄存器
ldr r1, =0x150f8
str r1, [r0]
ldr r0, =0x7e001304 @用户配置寄存器
mov r1, #0x0
str r1, [r0]
ldr r0, =0x7e001008
ldr r1, =0x000c0000
str r1, [r0]
ldr r1, =0x00000000
str r1, [r0]
ldr r1, =0x00040000
str r1, [r0]
ldr r1, =0x000a0000
str r1, [r0]
ldr r1, =0x00080032
str r1, [r0]
ldr r0, =0x7e001004
mov r1, #0x0
str r1, [r0]
check_dmc1_ready:
ldr r0, =0x7e001000
ldr r1, [r0]
mov r2, #0x3
and r1, r1, r2
cmp r1, #0x1
bne check_dmc1_ready
nop
mov pc, lr
到这里启动代码(BL1)就简单的总结完了。 希望自己以后还能看懂自己写的东西。。。