1 工具介绍
1.1 ADS 命令行命令介绍
1.1.1 armasm
1. 命令:armasm [选项] -o 目标文件 源文件
2. 选项说明
-Errors 错误文件名 ;指定一个错误输出文件
-I 目录[,目录] ;指定源文件搜索目录
-PreDefine 预定义宏 ;指定预定义的宏
-NOCache ;编译源代码时禁止使用Cache进 优化
-MaxCache
-NOWarn ;关闭所有的警告信息
-G ;输出调试表
-keep ;在目标文件中保存本地符号表
-LIttleend ;生成小端(Little-endian) ARM代码
-BIgend ;生成大端(Big-endian) ARM代码
-CPU
-16 ;建立16位的thumb指令.
-32 ;建立 32位的ARM指令.
3. 编译一个汇编文件
c:/adsloader>armasm -LIttleend -cpu ARM920T -32 bdinit.s
把汇编语言编译成小端, 32位, ARM920T CPU.
1.1.2 armcc, armcpp
1. 命令:armcc [选项] 源文件1 源文件2 ... 源文件n
2. 选项说明
-c ;编译但是不连接
-D ;指定一个编译时使用的预定义宏常量
-E ;仅仅对C源文件做预处理
-g ;产生调试信息表
-I ;指头文件的搜索路径
-o
-O[0/1/2] ;指定源代码的优化级别
-S ;输出汇编代码来代替目标文件
-CPU
3.编译一个C程序
c:/adsloader>armcc -c -O1 -cpu ARM920T bdisr.c
编译不连接, 二级优化, ARM920T CPU.
1.1.3 armlink
1. 命令:armlink [选项] 输入文件
2. 选项说明
-partial ;合并目标文件
-Output 文件 ;指定输出文件名
-scatter 文件 ;按照指定的文件为可执行文件建立内存映射
-ro-base 地址值 ;只读代码段的起始地址
-rw-base 地址值 ;RW/ZI段的起始地址
3. 把多个目标文件合并成一个目标文件
c:/adsloader>armlink -partial bdmain.o bdport.o bdserial.o bdmmu.o bdisr.o -o
bd.o
4. 把几个目标文件编译一个可执地文件
c:/adsloader>armlink bd.o bdinit.o -scatter bdscf.scf -o bd.axf
1.1.4 fromelf
1. 命令:fromelf [选项] 输入文件
2. 选项说明
-bin 二进制文件名 ;产生的二进制文件
-elf elf文件名 ;产生一个elf文件
-text text文件名 ;产生text文件
3. 产生一个可执行的二进制代码
c:/adsloader>fromelf bd.axf -bin -o bd.bin
2 基本原理
2.1 可执行文件组成及内存映射
2.1.1 可执行文件的组成
在ADS下,可执行文件有两种,一种是.axf文件,带有调试信息,可供AXD调试工具使用.另一种是.bin
文件,可执行的二进制代码文件。我们重点是讲描.bin文件的组成。
我们把可执行文件分为两种情况:分别为存放态和运 态。
1. 存放态
存放态是指可执行文件通过fromelf产生后,在存储介质(flash或磁盘)上的分布. 此时可执行文件一
般由两部分组成:分别是代码段和数据段。代码段又分为可执行代码段(.text)和只读数据段(.rodata),
数据段又分为初始化数据段(.data)和未初始化数据段(.bss)。可执行文件的存放态如下:
+-------------+-----------
| .bss |
+-------------+-- 数据段
| .data |
+-------------+-----------
| .rodata |
|_____________| 代码段
| .text |
+-------------+-----------
2. 运 态
可执行文件通过装载过程, 搬入到RAM中运 , 这时候可执行文件就变成运 态。在ADS下对可执行代
码各段有另一个名称:
| ... |
+-------------+-----------
| .bss | ZI 段
+-------------+-- 数据段
| .data | RW 段
+-------------+-----------
| .rodata |
|_____________| 代码段(RO 段)
| .text |
+-------------+-----------
| ... |
装载前
当可执行文件装载后, 在RAM中的分布如下:
| ... |
+-------------+-- ZI段结束地址
| ZI 段 |
+-------------+-- ZI段起始地址
| 保留区2 |
+-------------+-- RW段结束地址
| RW 段 |
|-------------+-- RW段起始地址
| 保留区1 |
+-------------+-- RO段结束地址
| RO 段 |
+-------------+-- RO段起始地址
| ... |
装载后
所以装载过程必须完成把执行文件的各个段从存储介质上搬到RAM指定的位置。而这个装载过程由谁来完
成呢?由我们的启动程序来完成.
2.1.2 装载过程
在ADS 中,可以通过两种方式来指定可执行代码各段在RAM中的位置,一个是用armlink来指定,一种是
用 scatter文件来指定.RAM区的起始地址:0x30000000.
1. armlink指定代码段地址
我们通常的代码,只用指定两个段开始地址, RO段的起始地址和RW段的起始地址, ZI段紧接在RW段之
后.示例见该部分的1.1.3.
2. scatter指定代码段地址
我们也可以通过 scatter文件指定可执行文件各段的详细地址. Scatter文件如下:
MYLOADER 0x30000000
;MYLOADER: 为可执行文件的名称, 可自定义
;0x3000000: 起始地址
{
RO 0x30000000
;RO 只读代码段的名称
;0x30000000: 只读代码段的起始地址
{
init.o (Init, +First)
; Init 代码段为可执行文件的第一部分.
* (+RO) ;所有其它的代码段和只读数据段放在该部分
}
RW +0
;RW: RW 段的名称
;+0: 表示RW 段紧接着RO 段
{
* (+RW) ;所有RW 段放在该部份
}
ZI +0
;ZI: ZI 段的名称
;+0: 表示ZI 段紧接着RW 段
{
*(+ZI) ;所有ZI 段放在该部分
}
}
3. ADS 产生的各代码段宏
|Image$$RO$$Base| /* RO 代码段起始地址 */
|Image$$RO$$Limit| /* RO 代码段结束地址 */
|Image$$RW$$Base| /* RW 代码段起始地址 */
|Image$$RW$$Limit| /* RW 代码段结束地址 */
|Image$$ZI$$Base| /* ZI 代码段起始地址 */
|Image$$ZI$$Limit| /* ZI 代码段结束地址 */
注意:在两个$$之间的名称, 与scatter 中指定的段的名称相同.
4. 装载过程说明
当从NorFlash 启动时, 要把flash 芯片的首地址映射到0x00000000 位置, 系统启动后, 启动程序本身把自己从
flash 中搬到RAM 中运 . 搬移后的各段起始地址, 由以上宏来确定.
当从NandFlash 启动时, S3C2410 会自动把前NandFlash 的前4k 搬到S3C2410 的内部RAM 中,并把内部
RAM 的首地址设为0x00000000 ,CPU 从0x00000000 开始执 . 所以, 在nandFlash 的前4k 程序中,必须包含从
NandFlash 把BootLoader 的其余部分装入RAM 的程序.
2.1.3 启动过程的汇编部分
当系统启动时, ARM CPU 会跳到0x00000000 去执 。一般BootLoader 都包括如下几个部分:
1. 建立中断向量异常表
2. 显示的切换到SVC 且32 指令模式
3. 关闭S3C2410 的内部看门狗
4. 禁止所有的中断
5. 配置系统时钟频率和总线频率
6. 设置内存区的控制寄存器
7. 初始化中断
8. 安装中断向表量
9. 把可执行文件的各个段搬到运 态的各个位置
10. 跳到C 代码部分执
2.1.4 启动过程的 C部分
1. 初始化MMU
2.初始化外部端口
3. 中断处理程序表初始化
4. 串口初始化
5. 其它部分初始化(可选)
6. 主程序循环
3 AXD 的使用以及源代码说明
3.1 源代码说明
3.1.1 汇编源代码说明
;===============================================================================
; 引用头文件
;===============================================================================
get bdinit.h
;===============================================================================
; 引用标准变量
;===============================================================================
IMPORT |Image$$RO$$Base| ; Base address of RO section
IMPORT |Image$$RO$$Limit| ; End address of RO section
IMPORT |Image$$RW$$Base| ; Base address of RW section
IMPORT |Image$$RW$$Limit| ; End address of RW section
IMPORT |Image$$ZI$$Base| ; Base address of ZI section
IMPORT |Image$$ZI$$Limit| ; End addresss of ZI section
IMPORT bdmain ; The entry function of C program
;===============================================================================
; 宏定义
;===============================================================================
; macro HANDLER
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
sub sp,sp,#4 ;Decrement sp (to store jump address)
stmfd sp!,{r0} ;PUSH the work register to stack
ldr r0,=$HandleLabel;Load the address of HandleXXX to r0
ldr r0,[r0] ;Load the contents(service routine start address) of HandleXXX
str r0,[sp,#4] ;Store the contents(ISR) of HandleXXX to stack
ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
MEND
;===============================================================================
; 汇编语言的入口代码
;===============================================================================
AREA Init,CODE,READONLY
CODE32
ENTRY
;=====================
; 建立中断向量表
;=====================
----------------------- 页面 19-----------------------
b reset_handler ;0x00000000: Reset (SVC)
b undef_handler ;0x00000004: Undefined instruction (Undef)
b swi_handler ;0x00000008: Software Interrupt (SVC)
b iabr_handler ;0x0000000C: Instruction Abort (Abort)
b dabr_handler ;0x00000010: Data Abort (Abort)
b no_handler ;0x00000014:
b irq_handler ;0x00000018: IRQ (IRQ)
b fiq_handler ;0x0000001C: FIQ (FIQ)
LTORG
undef_handler HANDLER HandleUndef
swi_handler HANDLER HandleSWI
iabr_handler HANDLER HandlePabort
dabr_handler HANDLER HandleDabort
no_handler HANDLER HandleReserved
irq_handler HANDLER HandleIRQ
fiq_handler HANDLER HandleFIQ
;=============================
; 复位时运行的主程序
;=============================
reset_handler
;Set the cpu to SVC32 mode
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr_cxsf,r0
;Turn off watchdog
ldr r0,=WTCON
ldr r1,=0x0
str r1,[r0]
;Disable all the first level interrupts
ldr r0,=INTMSK
ldr r1,=0xffffffff
str r1,[r0]
;Disable all the second level interrupts
ldr r0,=INTSUBMSK
ldr r1,=0x7ff
str r1,[r0]
;Configure MPLL
ldr r0,=MPLLCON
ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV) ;Fin=12MHz,Fout=200MHz
str r1,[r0]
;Set FCLK:HCLK:PCLK = 1:2:4
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
;Set memory control registers
ldrr0,=SMRDATA
----------------------- 页面 20-----------------------
ldr r1,=BWSCON
add r2, r0, #52 ;End address of SMRDATA
0
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne %B0
;Initialize stacks
bl InitStacks
;Setup IRQ handler
ldr r0,=HandleIRQ ;This routine is needed
ldr r1,=IsrIRQ
str r1,[r0]
;Copy RW/ZI section into RAM
ldr r0, =|Image$$RO$$Limit|;Get pointer to ROM data
ldr r1, =|Image$$RW$$Base| ;and RAM cop
ldr r3, =|Image$$ZI$$Base|
cmp r0, r1 ; Check that they are different
beq %F2
1
cmp r1, r3 ; Copy init data
ldrcc r2, [r0], #4 ;--> LDRCC r2, [r0] + ADD r0, r0, #4
strcc r2, [r1], #4 ;--> STRCC r2, [r1] + ADD r1, r1, #4
bcc %B1
2
ldr r1, =|Image$$ZI$$Limit| ; Top of zero init segment
mov r2, #0
3
cmp r3, r1 ; Zero init
strcc r2, [r3], #4
bcc %B3
bl bdmain ;Jump to the main function
;Dead loop
1
nop
b %B1
;===============================================================================
; 初始中断处理程序
;===============================================================================
IsrIRQ
sub sp,sp,#4 ;reserved for PC
stmfd sp!,{r8-r9}
ldr r9,=INTOFFSET
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
ldr r8,[r8]
----------------------- 页面 21-----------------------
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}
;===============================================================================
; 初始化各个模式下堆栈
;===============================================================================
InitStacks
mrs r0,cpsr
bic r0,r0,#MODEMASK
orr r1,r0,#UNDEFMODE|NOINT
msr cpsr_cxsf,r1 ;UndefMode
ldr sp,=UndefStack
orr r1,r0,#ABORTMODE|NOINT
msr cpsr_cxsf,r1 ;AbortMode
ldr sp,=AbortStack
orr r1,r0,#IRQMODE|NOINT
msr cpsr_cxsf,r1 ;IRQMode
ldr sp,=IRQStack
orr r1,r0,#FIQMODE|NOINT
msr cpsr_cxsf,r1 ;FIQMode
ldr sp,=FIQStack
bic r0,r0,#MODEMASK|NOINT
orr r1,r0,#SVCMODE
msr cpsr_cxsf,r1 ;SVCMode
ldr sp,=SVCStack
mov pc,lr ;Return the call routine
LTORG
;===============================================================================
; 内存区控制寄存器值表; 你可根据需要修改bdinit.h 文件, 下面代码不用做任何改动
;===============================================================================
SMRDATA DATA
DCD
(0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(
B7_BWSCON<<28))
DCD
((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) ;GCS0
DCD
((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) ;GCS1
DCD
((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) ;GCS2
DCD
((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) ;GCS3
DCD
((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) ;GCS4
DCD
((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) ;GCS5
DCD ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) ;GCS6
DCD ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) ;GCS7
----------------------- 页面 22-----------------------
DCD ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
DCD 0x32 ;SCLK power saving mode, BANKSIZE 128M/128M
DCD 0x30 ;MRSR6 CL=3clk
DCD 0x30 ;MRSR7
ALIGN
;===============================================================================
; 异常及中断向量表空间; 安装异常或中断处理程序在bdisr.c 中,isr_setup()来完成.
;===============================================================================
AREA RamData, DATA, READWRITE
^ _ISR_STARTADDRESS ;表示下面数据区从_ISR_STARTADDRESS指定的位置开始
HandleReset # 4
HandleUndef # 4
HandleSWI # 4
HandlePabort # 4
HandleDabort # 4
HandleReserved # 4
HandleIRQ # 4
HandleFIQ # 4
;=============================
; The Interrupt table
;=============================
HandleEINT0 # 4
HandleEINT1 # 4
HandleEINT2 # 4
HandleEINT3 # 4
HandleEINT4_7 # 4
HandleEINT8_23 # 4
HandleRSV6 # 4
HandleBATFLT # 4
HandleTICK # 4
HandleWDT # 4
HandleTIMER0 # 4
HandleTIMER1 # 4
HandleTIMER2 # 4
HandleTIMER3 # 4
HandleTIMER4 # 4
HandleUART2 # 4
HandleLCD # 4
HandleDMA0 # 4
HandleDMA1 # 4
HandleDMA2 # 4
HandleDMA3 # 4
HandleMMC # 4
HandleSPI0 # 4
HandleUART1 # 4
HandleRSV24 # 4
HandleUSBD # 4
HandleUSBH # 4
HandleIIC # 4
HandleUART0 # 4
HandleSPI1 # 4
----------------------- 页面 23-----------------------
HandleRTC # 4
HandleADC # 4
END
3.1.2 C语言源代码说明
void bdmain(void)
{
/* 禁止Cache 和MMU */
cache_disable();
mmu_disable();
/* 端口初始化 */
port_init();
/* 中断处理程序 */
isr_init();
/* 串口初始化 */
serial_init(0, 115200);
/* 输出信息进行主循环 */
serial_printf("is ok!/n");
while(1) {
}
}
通常基本ADS 的测试程序都可以在这个架构上加入自己的代码.
3.2 AXD 的使用
3.2.1 配置仿真器
1. 为仿真器安装Server
一般的仿真器都对应有一个Server 程序,所以在使用在线仿真之前,必须先安装这个Server 程序。我使用
是Dragon-ICE 仿真器, 所以先要安装Dragon-ICE Server 程序。
2. 连接仿真器
把dragon-ICE 仿真器的JTAG 口连接上ARM 板(注意:ARM 板要断电连接), 另一端通过并口连接到PC 上,
有的仿真器是通过USB 口连接到PC 上, 这与仿真器的硬件相关。连接好后, 打开ARM 电源,启动ARM 板。
当ARM 通电启动后,启动Dragon-ICE Server 检测ARM 板,详细步骤及设置参见对应的仿真器手册。我的
dragon-ICE Server 启动, 按”自动检测”可以检测到ARM920T 。
3.2.2 启动AXD 配置开发板
1. 启动AXD
先启动Dragon-ICE Server 程序.
按如下步聚启动AXD:
开始->所有程序->ARM Developer Suite v1.2->AXD Debugger
2. 装载仿真器库文件
从AXD 菜单的Options--> Configure Target...启动”Choose Target” 目标板配置窗口.
在”Choose Target”窗口中,点击”Add”按钮,选择仿真器的库文件. 我的仿真器服务器程序安装在
c:/Dragon-ICE 下,所以选择项c:/Dragon-ICE/dragon-ice.dll 文件
----------------------- 页面 24-----------------------
3. 为AXD 在线仿真配置仿真器
在"Target Environments"中选中Dragon-ICE 中,点击右边的"Configure"按钮.
在”FJB Dragon-ICE Release v1.2”窗口点击"This computer..."按钮,再点击"OK"按钮。
回到”Choose Target”窗口,点击"OK"按钮。完成配置.
回到主界面, 在右边的”Target”窗口会出现ARM920T_0.这表明AXD 已经进入ARM 板的在线仿真状态.
点击菜单"System Views"-->"Controls Monitors".会出现"ARM920T-Register"窗口.此时,会显示当前ARM 板上所
有寄存器的状态。
4. 配置ARM 板
如果ARM 板通电后,没有程序运行并把内存区控制寄存器配置好的说,外部RAM 是不能使用的. 所以必须
通过仿真器来设置这些寄存器. 如果ARM 板已经有启动程序并且已经配置好, 这一步可以省略.
首先把2410cfg.txt 拷贝到c:/下.
回到AXD 主界面, 从菜单”System Views” --> “Command Line Interface” 。会出现一个Command Line
Interface 的调试命令 窗口,并显示如下提示符:
Debug >
输入obey c:/2410cfg.txt 装载所有配置命令.
Debug >obey c:/2410cfg.txt
5. 2410cfg.txt 文件说明
sreg psr, 0x00000013
;设置当前CPSR 的值, 把CPU 的模式切换到SVC 模式和32 位指令集, 关闭IRQ 和FIQ 。
smem 0x53000000,0,32
;设置看门狗控制寄存器WTCON
;禁止看门狗定时器
smem 0x4C000004,((0x74<<12)+(0x3<<4)+0x1),32
;设置主频率设置寄存器MPLLCON
; 目前CPU 的工作频率FCLK 是124.00MHz
smem 0x4C000014,0x3,32
;设置时钟分频寄存器CLKDIVN
;设置FCLK/HCLK/PCLK 的频率比例1:2:4
smem 0x48000000,((2<<28)+(2<<24)+(1<<20)+(1<<16)+(1<<12)+(1<<8)+(1<<4)+0),32
;设置内存总线控制BWSCON
;SDRAM BANK 6&7 is 32 位
;其它BANK is 16 位
smem 0x48000004,((3<<13)+(3<<11)+(7<<8)+(3<<6)+(3<<4)+(3<<2)+3),32
;设置寄存器区0 控制寄存器:BANKCON0
smem 0x4800001c,((3<<15)+(1<<2)+1),32
;设置寄存器区6 控制寄存器: BANKCON6(SDRAM)
作者介绍:本文由尚观科技老师和同学生(刘勇,孙贺,聂强,聂大鹏 ,牛须乐,孙磊)共同创作
;RAS to CAS 延时3 时钟周期
;列地址是9 位
smem 0x48000020,((3<<15)+(1<<2)+1),32
;设置寄存器区7 控制寄存器: BANKCON7(SDRAM)
;RAS to CAS 延时 3 时钟周期
;列地址是9 位
smem 0x48000024,((1<<23)+(3<<18)+(2<<16)+1113),32
;set 外部RAM 刷新寄存器:REFRESH
;允许自刷新
;HCLK=FCLK/2, 60MHz,刷新计算器是1113
smem 0x48000028,0x31,32
----------------------- 页面 25-----------------------
;设置寄存器的大小
;禁止burst 操作
;允许SDRAM power down 模式
;SCLK 在访问期间仍在活动状态
;SDRAM 模式寄存器设置
smem 0x4800002c,0x30,32
smem 0x48000030,0x30,32
3.2.3 使用AXD在线仿真调试程序
1. 装载可执行的文件
AXD 只支持.axf 格式的可执行文件.
启动AXD, 在菜单的File 中,选择Load Image..., 选择c:/adsbloadter/prj/prj_Data/DebugRel/prj .axf 加载执
image. 就可以执行并调试了. AXD 提供了非常方便的调试手段, 包括在线单步, 自由设置断点等.
作者介绍:本文由尚观科技老师和同学生(刘勇,孙贺,聂强,聂大鹏 ,牛须乐,孙磊)共同创作
转自:http://www.uplinux.com/shizi/wenxian/33.html