arm体系结构
一、arm汇编
1.典型的嵌入式处理器
x86 PC机, 不用于嵌入式
arm RISC指令集 市场79.5%
mips RISC指令集 占市场13.9% ARM及MIPS在市场中为常用处理器
microSPARC SUN 占市场3.1%
PowerPc IBM 占市场2.8%
其它 占市场0.8%
2.计算机体系
1).冯.诺依曼体系结构
计算机有数据线、控制线
指令:即编译后的机器码,每一条指令是32位,包括运算符、条件判断、两个运算数等,指令存在寄存器,由CPU运行
指令的执行过程
取指-〉释码 -〉执行 由一根电线来完成 指令和数据用同一个总线
汇编代码逻辑简单,指令多
CISC 复杂指令集 采用冯.诺依曼体系
2).哈佛体系结构
指令的执行过程
取指-〉释码 -〉执行 由三根电线流水式完成 指令和数据用不同的总线
取指
释码
执行
汇编代码逻辑复杂,指令少
RISC 精简指令集 采用哈佛体系结构 重点
Thumb指令集 是ARM体系结构中一种16位的指令集。
3.arm处理器状态
ARM处理器内核使用ARM结构,该结构包含32位的ARM指令集和16位Thumb指令集,因此ARM有两种操作状态:ARM状态、Thumb状态。
4.arm处理器模式
ARM处理器共有7种运行模式:(即程序运行状态)
用户模式:用户程序工作的模式 ,不能直接切换到其它模式,只能通过API指令控制
系统模式:支持操作系统的特权任务,可以直接切换到其它模式
快中断:支持高速数据传输及通道处理,FIQ异常响应时进入此模式
中断: 用于通用中断处理,IRQ异常响应时进入此模式
管理: 操作系统保护代码,系统复位和软件中断响应时进入此模式
中止: 用于支持虚拟内存或存储器保护,用于MMU
未定义:支持硬件协处理器的软件仿真,未定义指令异常响应时进入此模式。
5.qt2440配置
CPU处理器 S3C2440AL,主频400MHz ,最高可达533MHz
SDRAM内存 64MB 32位数据总线 时钟频率 100MHz(最高133MHz)
Nor Flash 2MB 非易失闪存 cmos
Nand Flash 256MB 非易失闪存 硬盘
6.寄存器
共37个寄存器
里面有16个通用寄存器,重点研究16个通用寄存器
里面有2个状态寄存器,重点研究2个状态寄存器
1)通用寄存器
R0 -R7 是寄存器的名称 8个
r0-r3 用于当做函数形参 多于4个的参数被压入到栈(内存)
r0-r1 用于当做函数的返回值
r4-r7 用于当做函数的局变量,多于4个局部变量被压入到栈
在使用时就当成是变量名
r8-r12 共5个,相当于5个变量
这几个寄存器有时可以用于特殊用途
sp 即r13 栈指针寄存器 即内存的指针变量 人为设置,以后在使用时sp指针的值是自动变的
栈的特点:先入后出,出栈时栈内的数据相当于消失了
lr 即r14 保存函数的返回地址,即函数跳转指令后面的指令的内存地址,自动设置
pc 即r15 用来指定要取指的内存地址,一般自动被设置,当取一条指令后,pc就指向下一个指令地址
sp、lr、pc都可以人为的设置
2)状态寄存器
cpsr、spsr 都是状态寄存器
cpsr是代表当前程序的状态
spsr是用于在异常切换时保存的cpsr寄存器的数据,即备份寄存器,是自动保存
cpsr的数据结构
cpsr[4:0] 模式位
cpsr[7:0] 称为控制位 I 一般中断总开关 F 快中断的总开关 T 是指令类型的切换
cpsr[31:28]条件位
其它位没有使用
(1)条件位 背****
条件位中4个位的组合,代表了各种条件,如下:
0b0000 0x0 EQ 相等/等于0 ==
0b0001 0x1 NE 不等 !=
0b0010 0x2 CS/HS 进位/无符号大于或等于 >=
0b0011 0x3 CC/LO 无进位/无符号小于 <
0b0100 0x4 MI 负数 或0值 <=0
0b0101 0x5 PL 非负数 >0
0b0110 0x6 VS 溢出
0b0111 0x7 VC 无溢出
0b1000 0x8 HI 无符号大于 >
0b1001 0x9 LS 无符号小于或等于 <=
0b1010 0xA GE 有符号大于或等于 >=
0b1011 0xB LT 有符号小于 <
0b1100 0xC GT 有符号大于 >
0b1101 0xD LE 有符号小于或等于 <=
0b1110 0xE AL 任何状态,总是 真
0b1111 0xF NV 从不,总不 假
(2)控制位
I 一般中断的开关 0 开启一般中断 1 禁用一般中断
F 快速中断的开关 0 开启快速中断 1 禁用快速中断
T 表示CPU当前的状态,1 代表正在Thumb指令集状态,0表示正在ARM指令集状态。
CPSR[4:0] 模式位,这4个位的组合代表7种处理器模式
0b10000 User 用户模式
0b10001 FIQ 快速中断,异常响应时进入此模式
0b10010 IRQ 中断,如声卡、调制解调器等外部设备产生的中断
0b10011 Supervisor 管理模式,由程序产生的中断,系统复位和软件中断响应
0b10111 Abort 异常中止, 支持虚拟内存或存储器保护
0b11011 Undefined 未定义中断
0b11111 System 系统模式,支持操作系统的特权任务,可以直接切换到其它模式
7.ADS工具的使用
8.汇编的基本结构
段:代码段和数据段,段的格式如下
area 段名,段类型,段的属性...
entry ;段的入口
;汇编指令
end ;段的结束
在汇编中,;代表注释
段的类型:data 数据段、code 代码段
属性: readonly 只读 代码段是只读
readwrite 读写 数据段是读写
align 对齐方式,用在数据段中 align=3,即2的3次方
指令前面必须tab键,标签必须用顶格写
area init,code,readonly
entry
reset ;标签 标签是就代码编译完后的相对的地址
;a=12,b=15,a=a+b;
mov r0,#12 ;r0=12
mov r1,#15 ;r1=15
add r0,r0,r1 ;r0=r0+r1
end
指令:汇编指令(运算符 add)
伪指令:也是汇编指令,在运行进行替换
伪操作:不是汇编指令,是编译识别的指令,用来实现编译时替换(即预处理)
area、entry、end 是伪操作
变量 if while
协处理器:协助处理器的处理器,p0 - p16
机器码格式
cond 00 X opcode s Rn Rd operand2
汇编格式
{}{s} ,,
1) cond码
例:mov r0,#6 ;r0=6
cmp r0,#5 ;比较r0和5 是否相等 比较结果被自写入到cpsr中 如果相等 EQ,r0大 GT,r0小 LT
addlt r0,r0,#10 ;if (lt) r0=r0+10
2) S 码 用于改写cpsr
例:mov r0,#6
mov r1,#5
subs r0,r1,r0; 代表r1-r0是否发生了借位,如果发生了借位,则在cpsr中做标记
3) Rd 是目标寄存器 如r0
4) Rn 第1个操作数寄存器 如r1
5) operand2 第2个操作数 该项可以是寄存器,也可以是“立即获取”的数 如 r0
9.arm寻址
寻址:即找到数据的位置,读或写数据
1)立即寻址
例: mov r0,#3 ;r0=3 数是常量
2)绝对寻址
例: ldr r0,=3 ;r0=*&3 数在内存中,如果3在a中,则相当于 *&a
3)寄存器寻址
例: mov r0,r1 ;r0=r1 数是变量
4)寄存器间接寻址 数在内存中,相当于指针变量取值
area init,code,readonly
entry
reset ;标签 标签是就代码编译完后的相对的地址
ldr r0,=num ;r0=*&num num是地址编号
ldr r1,[r0] ;r1=*r0 r0是指针变量,[]相当于"*"取值
num dcd 0x23 ;num是标签 dcd是32位整型 23代表内存中的值
end
5)寄存器基址寻址
基址:理解为是首地址,有一片连续内存
基址寄存器:用于保存基址的寄存器,理解为是指针变量p
变址寻址: 即基址寄存器的值在发生变化 理解为++p p++ p+=1
(1) 后索引: 先取内存中的值,然后基址寄存器中的值向下移动 即 *p++
格式:ldr 寄存器,[基址寄存器],#常量
当读取数据,基址寄存寄存器中的值向下偏移 “常量”个字节
area init,code,readonly
entry
reset ;标签 标签是就代码编译完后的相对的地址
ldr r0,=a ;r0=*&a num是地址编号
ldr r1,[r0],#4 ;r1=*r0++ 先取出r0地址中的值,然后r0的值向下移动了4字节
num dcd 0x23 ;num是标签 dcd是32位整型 23代表内存中的值
a dcd 0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc ;分配了12个整型内存
end
(2) 前索引: 基址寄存器的值先向下移动,然后取内存中的值 即 *++p
格式: ldr 寄存器,[基址寄存器,#常量]!
从基址的+常量的内存中读取数据
!在运行指令后,改写基址寄存器中的值
area init,code,readonly
entry
reset ;标签 标签是就代码编译完后的相对的地址
ldr r0,=a ;r0=*&a num是地址编号
ldr r1,[r0,#4] ;r1=*(r0+1) 或 r1=r0[1]
ldr r1,[r0,#4]! ;r1=*r0++ 或 r1=r0[1];r0++;
num dcd 0x23 ;num是标签 dcd是32位整型 23代表内存中的值
a dcd 0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc ;分配了12个整型内存
end
(3) 索引寄存器:基址不变,索引值在变化 即 p[i]
area init,code,readonly
entry
reset ;标签 标签是就代码编译完后的相对的地址
ldr r0,=a ;r0=*&a num是地址编号
mov r1,#8
ldr r2,[r0,r1] ;r1就是索引寄存器
ldr r2,[r0,r1]!
num dcd 0x23 ;num是标签 dcd是32位整型 23代表内存中的值
a dcd 0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc ;分配了12个整型内存
end
6)多寄存器寻址 相于当memcpy
格式:ldmia 基址,{寄存器列表}
寄存器列表,每个寄存器之间用“,”分隔,也可用r0-r5方式连指定6寄存器
基址后也可以使用! 使用!后基寄存器的值也会发生变化,读取数据的顺序,与寄存器在{}内的位置无关,与寄存器名顺序有关
area init,code,readonly
entry
reset ;标签 标签是就代码编译完后的相对的地址
ldr r0,=a ;r0=*&a num是地址编号 媁
ldmia r0!,{r1,r3-r12} ?
num dcd 0x23 ;num是标签 dcd是32位整型 23代表内存中的值
a dcd 0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc ;分配了12个整型内存
end
7)寄存器堆栈寻址 即局部变量和形参变量
sp是栈指针
栈就是内存,首先分配内存
格式: ldmfd 栈指针!,{寄存器列表} 出栈
stmfd 栈指针!,{寄存器列表} 入栈
area init,code,readonly
entry
reset ;标签 标签是就代码编译完后的相对的地址
ldr sp,=0x31000000 ;通常分配1M内存
mov r0,#0x1
mov r1,#0x2
mov r2,#0x3
mov r3,#0x4
mov r4,#0x5
mov r5,#0x6
stmfd sp!,{r0-r5} ;将一系列数据从后向前入栈
stmfd sp!,{r1} ;将一个数据入栈
ldmfd sp!,{r6-r12} ;从前向后出栈
num dcd 0x23 ;num是标签 dcd是32位整型 23代表内存中的值
a dcd 0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc ;分配了12个整型内存
end
8)移位寻址 即移位运算
例: mov r0, r1,lsl #2 ;r0=r1<<2
mov r0, r1,lsr #2 ;r0=r1>>2
9)相对寻址 即数据在相对内存地址处,标签就是相对内存地址
(1)函数调用
area init,code,readonly
entry
reset ;标签 标签是就代码编译完后的相对的地址
mov r0,#0x5
mov r1,#0x8
bl max ;调用函数 相对寻址,max就是相对地址
mov r2,r0 ;r2=max(r0,r1);
max ;max就是函数名
cmp r0,r1
movlt r0,r1
mov pc,lr ;return 函数中必须有lr给pc赋值
end
(2)循环
area init,code,readonly
entry
reset ;标签 标签是就代码编译完后的相对的地址
;1+2+3+4…100
;i=1 i<=100 s
mov r0,#1 ;i
loop
add r4,r4,r0 ;r4+=i
add r0,r0,#1
cmp r0,#100
ble loop ;循环跳转
end
9.arm基本指令
1)传输指令
mov 给寄存器赋值 不常用,ldr是常用
mov r0,#0xff 填写1字节数据,数据大的用ldr
mvn 取反运算
mvn r0,#0xfe ;r0=~0xfe
2)位运算
(1)与运算 and
and r0,r0,#5 ;r0=r0 & 0x5
ldr r1,=0x234213fe
and r0,r0,r1
(2) 或运算 orr
orr r0,r0,#5 ;r=0r0 | 0x5
(3) 清零 bic
通常清零的方法
ldr r0,=0x56000000 ;GPBCON地址
ldr r1,[r0] ;GPBCON的值
;gpbcon=gpbcon & ~(3<<2 );
mov r2,#3
mov r2,r2,lsl #2 ;r2<<2
mvn r2,r2 ;r2=~r2
and r1,r1,r2 ;r1=r1 & r2
用bic指令清零
ldr r0,=0x56000000 ;GPBCON地址
ldr r1,[r0] ;GPBCON的值
bic r1,r1,#3<<2 ;r1=r1 & (~(3<<2))
(4)异或 eor
mov r0,#2
mov r1,#3
eor r0,r1,r0
eor r1,r1,r0
eor r0,r1,r0
3)算术运算
add 加法
sub 减法
adc 加法,将cpsr中的进位直接加入到寄器中
sbc 减法,将cpsr中的借位直接计算到寄器中
ldr r0,=0xffffffff ;r0存低位
ldr r1,=0x1
ldr r2,=0x00000001
ldr r3,=0
adds r0,r0,r2 ;加法运算,s影响cpsr,将进位存入cpsr条件位 衉
adc r1,r1,r3
4)比较指令
(1)cmp 比较两个数,比较的结果写在了cpsr中
(2)cmn 反值比较, 即负数比较
例
mov r0,#-1
cmn r0,#-9 ; r0的值-1 与 9比较,而不是和-9比较
movgt r1,#1
(3)tst 位测试指令
判断led灯的4灯是否已被关闭
ldr r0,=0x56000000
ldr r1,[r0]
mov r2,#0xf
mov r2,r2,lsl #5 ;gpbdat[8:5]
tst r1,r2 ;判断r1中,和r2对应的1的位是否为1
;在r1,如果上面的4个位都是0,则改变cpsr寄存器,否则用任何一个是1,则都不改变cpsr寄存器
(4)teq 相等测试
判断两个寄存器中的值是否相同
mov r0,#3
mov r1,#3
teq r0,r1
addeq r0,r0,r1 ;if (r0==r1) r0+=r1
5)移位指令
lsl
lsr
6)跳转指令
b 跳转,用于循环,或分支
bl 函数调用,会改写lr寄存
7)状态指令
mrs 从cpsr中读取数据
msr 向cpsr中写入数据
格式 msr{cond}_,
fields 代表了要更改的区域
c [7:0] 控制位
f [31:24]条件位
x和s保留位
msr cpsr_c,#0xD0 //更改了模式位
10.数据加载指令
用于操作内存,将内存的数据加载到寄存器,或将寄存器的数据保存到内存
1)单数据加载指令
ldr 读数据 ldr r1,[r0] ;r1=*r0
str 写数据 str r1,[r0] ;*r0=r1
后缀
r 操作32位的数据
rt 操作用户模式的32位数据
b 操作8位
bt
h 操作16位
ht
sr 操作有符号32位数
sb
sh
2)多数据加载指令
ldmia 读多个数据到寄存器 ldmia r0!,{r0-r3,r5,lr}^
stmia 写入多个数据到内存 stmia r0!,{r0-r3,r5,lr}
后缀
ia 从内存的低地址向高地址拷贝数据 即从前向后读写数据 从数组第0个元素开始拷贝
ib 从内存的低地址向高地址拷贝数据 即从前向后读写数据 从数组第1个元素开始拷贝,越过了第0个
da 从内存的高地址向低地址拷贝数据 即从后向前读写数据 从数组第0个元素开始拷贝
db 从内存的高地址向低地址拷贝数据 即从后向前读写数据 从数组第1个元素开始拷贝,越过了第0个
! 可选项 当指令执行完毕后,基址寄存器的值,自动向后偏移
^ 可选项 当指令执行完毕后,自动用spsr寄存器恢复cpsr寄存器
栈操作
fd 满递减堆栈
ed 空递减堆栈
fa 满递增堆栈
ea 空递增堆栈
其中
f full 栈指针指向最后一个入栈的数据的地址
e empty 栈指针指向下一个要存数据的内存地址
d del 递减 栈指针向低地址增长 头插
a add 递增 栈指针向高地址增长 尾插
11.伪指令
ldr 读取数据
ldr r0,=0x3 //伪指令
本质,是在运行时,先在内存中分配一个空间。将3存入到内存中,然后再用 ldr r0,[地址]来读取数据
a dcd 0x3
ldr r1,=a //伪指令
ldr r0,[r1] //数据加载指令,不是伪指令
adr 读数据
adr r0,0x3
nop 空转
用途,用于编写延时函数
12.伪操作
伪指令 是汇编指令
伪操作 是编译器的预处理
常量
标号名(常量名) EQU 值(表达式) {类型}
x equ 23 ;常量23的名字是x 相当于c中的#define
数据定义
用于为特定的数据分配存储单元,同时可以完成内存的初始化
DCD 定义数据为32位数据
a dcd 23 ;为一个数据分配了4字节内存
后缀
d 4字节
b 1字节
w 2字节
fd 双精度
fs 单精度
SPACE 申请内存
标号 SPACE 大小
例:
x equ 23 ;常量23的名字是x 相当于c中的#define
area init,code,readonly
entry
reset ;标签 标签是就代码编译完后的相对的地址
mov r0,#x
a dcd 23 ;为一个数据分配了4字节内存
b dcd 23,56,3,4,5,6,7,8,9,10,11,12 ;为12个数据分配4字节内存
s dcb “hello arm” ;共分配了10字节
buf space 4096 ;分配了4096字节的内存
end
13.软中断指令
通常中断是由硬件产生
而中断指令是通过软件的方式模似硬件产生的中断,称为软中断
格式 SWI{} <24位立即数>
这个24位数就相当于传传输到内核的数据,传到内核的中断内 。swi本身会产生中断,swi的调用必须在用户空间
例: swi 0x06 //0x06是产生中断时附带传递的数据
二、汇编与C语言混合编程
C寄存器的标准
r0-r3 形参
r0-r1 返回值
stdfd 入栈
函数扩展
c extern
汇编 export
函数引入
c #include
汇编 import
1)汇编调c函数
//first.s
import max
import Main ;引入函数
area init,code,readonly ?
entry
reset
mov r0,#3
mov r1,#4
bl max ;调C中的函数 lr自动记录mov r4,r0的地址
mov r4,r0
bl Main
end
//test.c
int max(int x,int y){ //x就是r0 y就是r1
return x>y?x:y; //return就是mov pc,lr
}
int Main(){
while(1);
}
2)C调汇编函数
//first.s
import max
import Main
area init,code,readonly
entry
reset
bl Main
export min
min
cmp r0,r1
movgt r0,r1
mov pc,lr
end
//test.c
extern int min(int x,int y);
int Main(){
int a=12,b=24;
int c=min(a,b);
while(1);
}
3)测试多个形参的入栈出栈
//first.s
import fun
import Main
area init,code,readonly
entry
reset
mov r0,#1
mov r1,#2
mov r2,#3
mov r3,#4
;其它参数入栈
ldr sp,=0x31000000
mov r4,#5
mov r5,#6
mov r6,#7
mov r7,#8
stmfd sp!,{r4-r7} ;从后向前入栈
bl fun
mov r4,r0
bl Main
export min
min
cmp r0,r1
movgt r0,r1
mov pc,lr
export fun1
fun1
add r0,r0,r1
add r0,r0,r2
add r0,r0,r3
mov r5,#0
loop
ldmfd sp!,{r4}
add r0,r0,r4
add r5,r5,#1
cmp r5,#5
blt loop
mov pc,lr
end
//test.c
int fun(int x,int y,int z,int w,int j,int i,int a,int b){
return x+y+z+w+j+i+a+b;
}
extern int min(int x,int y);
extern int fun1(int x,int y,int z,int w,int j,int i,int a,int b);
int Main(){
int c=fun1(1,2,3,4,5,6,7,8);
while(1);
}
4)C语言中内嵌汇编
在C语言中汇编的格式
__asm{
汇编代码
}
例:在C语言中更改状态寄存器的模式位
//first.s
import Main
area init,code,readonly
entry
reset
bl Main
end
//test.c
int Main(){
int a,b;
__asm{
msr CPSR_c,#0xd0
b loop
//mov r3,#3
}
loop:
while(1);
}
内嵌汇编的规则
1)内嵌汇编代码少
3) 没有代码段和数据段,因为.c文件中本身就在代码段中
2)不支持伪操作,伪操作不是汇编指令
4)不支持伪指令 如ldr adr不支持
5) 不支持标签
6) 不支持跳转 bx bl blx ,支持b ,用来跳转到c中的标签
7)常量#可省略
三、祼机驱动
1.看门狗
作用,检测CPU是否跑偏
假如CPU运行失常,没有代码来处理看门狗的喂狗,看门狗在一定时间内会重启机器,CPU运行正常情况,要间隔时间进行喂狗
第一步:底板原理图
无
第二步:核心板原理图
无
第三步:芯片手册
看门狗定时器的时钟周期的持续时间计算公式如下:
t_看门狗=1/[PCLK/(预分频值+1)/分频系数]
1/1000000
其中PCLK是指APB总线工作频率,串口、看门狗都连接在APB总线上,工作频率为50MHz。在没有设置系统时钟情况下,默认的是12MHz的晶振频率
8位分频由WTCON[15:8]位数据来控制,有效范围0到255之间。
分频系数由WTCON[4:3]位来设置,可选16、32、64、128
t 是看门狗的时钟周期的可持续时间,如果一旦启动了看门狗,则必须在WTCNT中,在t时间内写入计数,否则看门狗重新机器。这个过程也称为喂狗。
首先思考:超时时间设为多少?
t=1/[12000000/(预分频值+1)/分频系数]
10000*16 =12000000/(预分频值+1)
预分频值= 12000000/ 10000*16 -1 = 74
预分频值= 12000000/ 10000*32 -1 = 36.5
预分频值= 12000000/ 10000*64 -1 = 17.75
预分频值= 12000000/ 10000*64 -1 = 8.375
wtcon [15:8] 74
[5] 0禁用 1 启用
[4:3] 00 16
[2] 0 禁用中断
[0] 1 复位
wtdat 超时时间
10000
wtcnt 由wtdat赋值
//libc.c c函数
#define pWTCON ((volatile unsigned long)0x53000000)
#define pWTDAT ((volatile unsigned long)0x53000004)
#define pWTCNT ((volatile unsigned long)0x53000008)
//看门狗-------------------------------------------------------
void dog_off(){
pWTCON=0;
}
void dog_on(){
pWTDAT=10000;
pWTCON=74<<8 | 1<<5 | 1 ;
}
void dog_feed(){
pWTCNT=10000;
}
//armlib.s 汇编函数
area libs,code,readonly
entry
;//看门狗-------------------------------------------------------
export wt_off
wt_off
ldr r0,=0x53000000 ;wtcon
mov r1,#0
str r1,[r0] ;关闭看门狗
mov pc,lr
export wt_on
wt_on
;//先设置数据寄存器 第一次时自动给wtcnt赋值
ldr r0,=0x53000004 ;wtdat
ldr r1,=10000
str r1,[r0]
;//设置控制寄存器
ldr r0,=0x53000000 ;wtcon
ldr r1,=74<<8 | 1<<5 | 1
str r1,[r0] ;关闭看门狗
mov pc,lr
export wt_feed
wt_feed
;//先设置计数寄存器
ldr r0,=0x53000008 ;wtcnt
ldr r1,=10000
str r1,[r0]
mov pc,lr
end
//汇编入口 first.s
import dog_off
import dog_on
import dog_feed
import Main
area init,code,readonly
entry
reset
bl dog_off ;关闭看门狗
;其它代码
;开启看门狗
bl dog_on ;关闭看门狗
bl Main
end
//用户程序 test.c
void delay(int msec){
int i,j;
for(i=1000;i>0;i–){
for(j=msec*10;j>0;j–);
}
}
extern void wt_feed();
int Main(){
while(1){
delay(1);
wt_feed(); //喂狗
}
}
2.led灯
第一步:底板原理图
led1 nLED1
led2 nLED2
led3 nLED3
led3 nLED3
nLED1高电平灯灭 低电平是灯亮
第二步:核心板原理图
led1 gpb5
led2 gpb6
led3 gpb7
led3 gpb8
第三步:芯片手册
GPBCON 0x56000010 R/W Configures the pins of port B 0x0
GPBDAT 0x56000014 R/W The data register for port B Undef.
GPBUP 0x56000018 R/W Pull-up disable register for port B 0x0
gpbcon 设为输出 1<<10 | 1<< 12 | 1<< 14 | 1<<16
gpbdat 开灯 gpbdat & ~(1<< (5+i))
关灯 gpbdat | (1<<(5+i))
11 1111 1100 0000 0000
0x15400
0x3fc
//first.s
import Main
area init,code,readonly
entry
reset
bl Main
end
//led.s
area led,code,readonly
entry
export led_start
led_start
ldr r0,=0x56000010
ldr r1,=1<<10 | 1<<12 | 1<<14 | 1<<16
str r1,[r0]
mov pc,lr
export led_on
led_on
;r0是i
;r1=~(1<<(5+i))
add r0,r0,#5
mov r1,#1
mvn r1,r1,lsl r0
ldr r0,=0x56000014
str r1,[r0]
mov pc,lr
export led_off
led_off
;r0是i
;r1=~(1<<(5+i))
add r0,r0,#5
ldr r1,=0xf<<5
ldr r0,=0x56000014
str r1,[r0]
mov pc,lr
end
//test.c
void delay(int msec){
int i,j;
for(i=1000;i>0;i–){
for(j=msec*10;j>0;j–);
}
}
int Main(){
int i=0;
led_start();
while(1){
i=i%4;
led_on(i);
delay(1000);
led_off(i);
delay(1000);
i++;
}
}
3.分频器
FCLK CPU 400MHz
、HCLK AHB:Nand、SRAM、Camera、Power、中断、LCD 100MHz
PCLK APB:串口、定时器、CPIO、I2C、I2S、SPI、狗 50MHz
UCLK USB: 48MHz
1)LOCKTIME 寄存器
用于设置变频锁定的时间
[31:16] U_LTIME 设UCLK的锁定时间 通常设为 0x00FF
[15:0] M_LTIME 设FCLK、HCLK、PCLK的锁定时间 通常设置0xFFFF
locktime=0xffffff
2)锁相环控制寄存器
MPLLCON 用于产生FCLK、HCLK、PCLK三种时钟频率
UPLLCON 用于产生UCLK时钟频率
MPLLCON [19:12] MDIV 主频控制
[9:4] PDIV 预分频控制
[1:0] SDIV 后分频控制
查表获取这三项值
405MHz 12MHz MDIV=0x7f PDIV=2 SDIV= 1
400MHz 12MHz 0x5c 1 1 网上查找到的设置
48MHz 12MHz 0x38 2 2
3)时钟控制寄存器
CLKCON [20] 0 禁止了声卡的PCLK 1是开启
…
4)时钟慢速控制寄存器
CLKSLOW 一般不设置
5)时钟分频寄存器 ***
CPU 400MHz 100MHz
CLKDIVN
[3] DIVN_UPLL 0 UPLL频率48Mhz 1 UPLL频率96Mhz
[2:1] HDIVN 根据FCLK产生HCLK的频率
00 HCLK =FCLK
01 HCLK =FCLK/2
10 HCLK =FCLK/4 CAMDIVN[9]必须是0
HCLK =FCLK/8 CAMDIVN[9]必须是1
11 HCLK =FCLK/3 CAMDIVN[8]必须是0
HCLK =FCLK/6 CAMDIVN[8]必须是1
[0] PDIVN 0 同HCLK 1 HCLK/2
FCLK 400 FCLK
HCLK 100 FCLK/4
PCLK 50 FCLK/8
查表,
HDIVN 2
PDIVN 1
HDIVN不设为0,CPU总线改为异步总线模式
例:
import dog_off
import dog_on
import dog_feed
import Main
area init,code,readonly
entry
reset
;关闭看门狗
ldr r0,=0x53000000 ;wtcon
mov r1,#0
str r1,[r0]
;设置工作频率
;//----设置变频锁定时间
ldr r0,=0x4C000000 ;LOCKTIME
ldr r1,=0x00ffffff
str r1,[r0]
;//----锁相环分频器
ldr r0,=0x4C000004 ;MPLLCON 设置CPU主频
ldr r1,=0x5c <<12 | 1<<4 | 1
str r1,[r0]
ldr r0,=0x4C000008 ;UPLLCON 设置USB主频
ldr r1,=0x38 <<12 | 2<<4 | 2
str r1,[r0]
;//----设置AHB和APB总线频率
ldr r0,=0x4C000014 ;CLKDIVN 设置其它总线频率
ldr r1,=2<<1 | 1
str r1,[r0]
;//----设置CPU总线为异步模式
mrc p15,0,r0,c1,c0,0 ;协处理器指令 p15是协处理器名称
orr r0,r0,0xC0000000
mcr p15,0,r0,c1,c0,0
end
//用C实现如下
//设置分频器
#define pLOCKTIME ((volatile unsigned long)0x4C000000)
#define pMPLLCON ((volatile unsigned long)0x4C000004)
#define pUPLLCON ((volatile unsigned long)0x4C000008)
#define pCLKDIVN ((volatile unsigned long)0x4C000014)
void setdivn(){
pLOCKTIME=0x00ffffff;
pMPLLCON=0x5c <<12 | 1<<4 | 1;
pUPLLCON=0x38 <<12 | 2<<4 | 2;
pCLKDIVN=2<<1 | 1;
__asm{
mrc p15,0,r0,c1,c0,0
orr r0,r0,0xC0000000
mcr p15,0,r0,c1,c0,0
}
}
4.内存
CUP引脚上
ADDR0-ADDR26 27地址线 代表内存(电容)的地址
DATA0-DATA31 32数据线 代表内存中的数据
0x00000000 SRAM 4k 引导程序或开机开始运行的地址
0x08000000 留待焊接其它内存
0x10000000 留待焊接其它内存
0x18000000 留待焊接其它内存
0x20000000 留待焊接其它内存
0x28000000 留待焊接其它内存
0x30000000 内存条
0x38000000 内存条
1G内存共分为8个区域,每个区域都一个片选信号线
GCS0-GCS7 代表选择哪一个片选区域
2)内存条
每一个内存条,由4层bank构成
每一个bank是8M 每一电容是2字节16位,共4M个电容,4*16=64M位
共两块内存条
内存1 的数据线 占用DATA0-DATA15
内存2 的数据线 占用DATA16-DATA31
两块内存条共同使用时,相同地址的两个电容,分别代表数据的高16位和低16位
地址线 ADDR2-ADDR14 13根同时连两个内存块
如何区分出每一个字节:用WBE0和wbe1两个电线区分一个电容上的高低字节
SCS0连接在同一个片选信号线
每一个bank 某个电容如何寻找到
每一个bank由13行9列构成的电容矩阵,13行+9列状态组合,正好是共4M个电容
13根地址线采用分时复用的方式代表行和列地址线
SRAS代表行地址选通、SCAS代表列地址选通
每一个内存块共4个bank,当前选是哪一个bank
BA0和BA1来区分是哪个bank
wE用来控制内存是只读还是只写的
芯片手册
BWSCON
DW0[2:1] 片选bank0 代表数据线宽度 一块内存为16,两块为32 所以选 10
DW0[5:4] 片选bank1 代表数据线宽度 一块内存为16,两块为32 所以选 10
WS1[6] 片选bank1 是否使用wait信号 通常设0
ST1[7] 片选bank1 是否使用或禁止数据掩码引脚 s3c2440中没有该引脚,所以设为0
需要设置的是bank6和bank7两个片选
bwscon= 2<<24 | 2<<28 //即0x22000000
2)BANKCON0-BANKCON6
设置bank0到bank5共6个片选设置,采用默认值0x700
3)BANKCON6-BANKCON7
SCAN[1:0] 代表列地址数 13行9列地址线,所以列地址数设为01
Trcd[3:2] 行地址选通到列地址选通时的延时(时序) 不少于20ns HCLK为100MHz频率 即不少于2个时钟,所以选01
MT[16:15] 选择 SDRAM,即11
bankcon6= 3<<15 | 1<<2 | 1 //即18005
4)REFRESH寄存器
用于刷新
counter[10:0] 刷新计数器 存储刷新周期
刷新周期 =(2的11 -计数+1)/HCLK
计数=2的11次方-刷新周期*HCLK+1
刷新周期计算
按行刷新,共13根行地址即 2的13次行= 8192行
电容自动放电的间隔时间64ms
64000/8192 = 7.8us
计数值为 1269
Ssrc[19:18] 刷新周期选7个时钟, 填写11
Trp[21:20] 行地址选通冲电时间 2个时钟 填00
Trefmd[22] 自动刷新 选0
Refen[23] 是否开启刷新 选 1
refresh=1<<23 | 3<<18 | 1269 //8c04f5
5)BANDSIZE
bk76map[2:0] 两块内存都焊在bank6上,bank6是64M,选 001
sclk_en[4] 1 用于省电模式,即地址使用时激活
scke_en[5] 1 掉电时可用
burst_en[7] 1 开启突发方式可用
bandsize= 1<<7 | 1<<5 | 1<<4 | 1 //0xb1
6)MRSRB6-MRSRB7
用于设置CAS潜伏周期 一般设灶3个时钟
BL[2:0] 只设为0
BT[3] 设为0
CL[6:4] 选011
TM[8:7] 选00
WBL[9] 选0
mrsrb6= 3<<4 //0x30
例,内存驱动
import dog_off
import dog_on
import dog_feed
import Main
area init,code,readonly
entry
reset
;关闭看门狗
ldr r0,=0x53000000 ;wtcon
mov r1,#0
str r1,[r0]
;设置工作频率
;//----设置变频锁定时间
ldr r0,=0x4C000000 ;LOCKTIME
ldr r1,=0x00ffffff
str r1,[r0]
;//----锁相环分频器
ldr r0,=0x4C000004 ;MPLLCON 设置CPU主频
ldr r1,=0x5c <<12 | 1<<4 | 1
str r1,[r0]
ldr r0,=0x4C000008 ;UPLLCON 设置USB主频
ldr r1,=0x38 <<12 | 2<<4 | 2
str r1,[r0]
;//----设置AHB和APB总线频率
ldr r0,=0x4C000014 ;CLKDIVN 设置其它总线频率
ldr r1,=2<<1 | 1
str r1,[r0]
;//----设置CPU总线为异步模式
mrc p15,0,r0,c1,c0,0 ;协处理器指令 p15是协处理器名称
orr r0,r0,#0xC0000000
mcr p15,0,r0,c1,c0,0
;驱动内存条
;0x48000000 -0x48000030
ldr r0,=0x48000000 ;寄存器基址
ldr r1,=0x48000030 ;寄存器的最后地址
ldr r2,=memdat ;数据基址
memloop
ldr r4,[r2],#4 ;从memdat数组中用移动法读取数据
str r4,[r0],#4 ;将r4中的数据用移动写入寄存器
cmp r0,r1
ble memloop
;//进入用户程序
bl Main
memdat
DCD 0x22000000 ;//BWSCON
DCD 0x00000700 ;//BANKCON0
DCD 0x00000700
DCD 0x00000700
DCD 0x00000700
DCD 0x00000700
DCD 0x00000700 ;//BANKCON5
DCD 0x00018005 ;//BANKCON6
DCD 0x00018005 ;//BANKCON6
DCD 0x008c04f5 ;//REFRESH
DCD 0x000000b1 ;//BANKSIZE
DCD 0x00000030 ;//MRSRB6
DCD 0x00000030 ;//MRSRB7
end
5.arm体系结构
体现在两点:流水线、异常向量表
(一)异常向量表
1.异常发生时,硬件自动处理的内容
保存了cpsr到spsr中
自动设置cpsr执行状态,关闭所有中断
只存了返回地址PC-4到 lr中 即正在执行的指令的下条指令地址
MOV r0,#2 正在执行 此时发生异常
MOV r1,#3 正在译码 LR
ADD r0,r0,r1 正在取指 PC
CMP r0,r1
将PC指向了异常向量表
2.异常向量表
在代码段中,从0x00到0x1c的内存地址称为异常向量表,异常发生时PC直接跳到该范围内的某地址上,通常这个地址写异常跳转的指令
0x00 复位异常,是刚开机时PC指向的地址, 自动进入管理模式
0x04 未定义异常,译码时指令不能被识别(即运算符MOV等不能被识别) ,自动进入未定义模式
0x08 软中断异常,用户端的SWI指令被执行时,PC自动跳转到该位置, 管理模式
0x0c 指令预取异常,取指令时出现错误, 中止模式
0x10 数据访问异常,从内存中读取数据时,找不到内存地址或内存地址不存在,中止模式(abort)
0x14 未使用异常
0x18 一般中断异常,一般中断被触发时,PC自动跳转到该位置 一般中断模式
0x1c 快中断异常,快中断被触发时,PC自动跳转到该位置 快中断模式
异常向量表前面不能写任何的指令,因为异常向量表就是从0地址开始
例:异常向量表的使用
import Main
area init,code,readonly
entry
;异常向量表
b reSet ;0x00 复位异常
b unDefined ;0x04 未定义异常
b softInterrupt ;0x08 软中断异常
b perfetchAbt ;0x0c 预取指异常
b dataAbt ;0x10 数据访问异常
b unUsed ;0x14 未使用异常
b handlerIrq ;0x18 一般中断异常
b handlerFiq ;0x1c 快中断异常
reSet ;复位异常入口
;//进入用户程序
bl Main
unDefined ;未定义异常入口
softInterrupt ;软中断异常入口
perfetchAbt ;预取指异常入口
dataAbt ;数据访问异常入口
unUsed ;未使用异常入口
handlerIrq ;一般中断异常入口
handlerFiq ;快中断异常入口
end
3.每种模式下所使用的寄存器
系统和用户模式 使用寄存器,就是通用寄存器r0-r15 cpsr
快中断模式 r8-r14 ,spsr使用自已的寄存器 其它的都是通用寄存器 8个
管理模式 r13-r14、spsr使用自已的寄存器 其它的都是通用寄存器 3个
中止模式 r13-r14、spsr使用自已的寄存器 其它的都是通用寄存器 3个
中断模式 r13-r14、spsr使用自已的寄存器 其它的都是通用寄存器 3个
未定义模式 r13-r14、spsr使用自已的寄存器 其它的都是通用寄存器 3个
4.cpsr的控制位
CPSR[7:0] 控制位
[7] I 一般中断的开关 0 开启一般中断 1 禁用一般中断
[6] F 快速中断的开关 0 开启快速中断 1 禁用快速中断
[5] T arm状态,即CPU当前状态 0 arm指令, 1 thumb指令
[4:0] 模式位 共7种模式
0b10000 user 用户模式(中断)
0b10001 FIQ 快速中断模式
0b10010 IRQ 一般中断模式 声卡、调制解调器、外部设备产生的中断
0b10011 Supervisor管理模式(中断) 系统复位和软件中断响应时进入的模式
0b10111 abort 中止模式(异常中断) 支持虚拟内存和存储器保护
0b11011 Undefined 未定义模式(中断) 支持硬件的协处理器的软件仿真
0b11111 system 系统模式(中断)
通过mrs和msr指令切换模式
5.给每一种模式分配栈空间
ldr sp,=0x31000000
sp是r13,每一个模式中,都是有自已的sp寄存器,每一种模式都可以独立保存自已的栈空间内存地址
例:分配各模式下的栈空间
import Main
area init,code,readonly
entry
;//--------------------异常向量表-------------------------
b reSet ;0x00 复位异常
b unDefined ;0x04 未定义异常
b softInterrupt ;0x08 软中断异常
b perfetchAbt ;0x0c 预取指异常
b dataAbt ;0x10 数据访问异常
b unUsed ;0x14 未使用异常
b handlerIrq ;0x18 一般中断异常
b handlerFiq ;0x1c 快中断异常
;//--------------------复位异常入口-------------------------
reSet ;复位异常入口
;关闭看门狗
ldr r0,=0x53000000 ;wtcon
mov r1,#0
str r1,[r0]
;设置工作频率
;//----设置变频锁定时间
ldr r0,=0x4C000000 ;LOCKTIME
ldr r1,=0x00ffffff
str r1,[r0]
;//----锁相环分频器
ldr r0,=0x4C000004 ;MPLLCON 设置CPU主频
ldr r1,=0x5c <<12 | 1<<4 | 1
str r1,[r0]
ldr r0,=0x4C000008 ;UPLLCON 设置USB主频
ldr r1,=0x38 <<12 | 2<<4 | 2
str r1,[r0]
;//----设置AHB和APB总线频率
ldr r0,=0x4C000014 ;CLKDIVN 设置其它总线频率
ldr r1,=2<<1 | 1
str r1,[r0]
;//----设置CPU总线为异步模式
mrc p15,0,r0,c1,c0,0 ;协处理器指令 p15是协处理器名称
orr r0,r0,#0xC0000000
mcr p15,0,r0,c1,c0,0
;驱动内存条
;0x48000000 -0x48000030
ldr r0,=0x48000000 ;寄存器基址
ldr r1,=0x48000030 ;寄存器的最后地址
ldr r2,=memdat ;数据基址
memloop
ldr r4,[r2],#4 ;从memdat数组中用移动法读取数据
str r4,[r0],#4 ;将r4中的数据用移动写入寄存器
cmp r0,r1
ble memloop
;分配各模式下的栈内存
;复位默认是管理模式
ldr sp,=0x30100000 ;管理模式下的栈指针
;切换到用户模式
msr cpsr_c,#0xd0 ;设置为用户模式
ldr sp,=0x30200000 ;用户和系统模式下的栈指针
;切换到快中断模式
msr cpsr_c,#0xd1 ;设置为快中断模式
ldr sp,=0x30300000 ;快中断模式下的栈指针
;切换到一般中断模式
msr cpsr_c,#0xd2 ;设置为一般中断模式
ldr sp,=0x30400000 ;一般中断模式下的栈指针
;切换到中止模式
msr cpsr_c,#0xd7 ;设置为中止模式
ldr sp,=0x30500000 ;中止模式下的栈指针
;切换到未定义模式
msr cpsr_c,#0xdb ;设置为未定义模式
ldr sp,=0x30600000 ;未定义模式下的栈指针
;切换到用户模式
msr cpsr_c,#0x10 ;设置用户模式,同时启动了中断
;//进入用户程序
bl Main
;//-------------------其它异常入口-------------------------
unDefined ;未定义异常入口
softInterrupt ;软中断异常入口
perfetchAbt ;预取指异常入口
dataAbt ;数据访问异常入口
unUsed ;未使用异常入口
handlerIrq ;一般中断异常入口
handlerFiq ;快中断异常入口
;//--------------------常用数据内存-----------------------
memdat
DCD 0x22000000 ;//BWSCON
DCD 0x00000700 ;//BANKCON0
DCD 0x00000700
DCD 0x00000700
DCD 0x00000700
DCD 0x00000700
DCD 0x00000700 ;//BANKCON5
DCD 0x00018005 ;//BANKCON6
DCD 0x00018005 ;//BANKCON6
DCD 0x008c04f5 ;//REFRESH
DCD 0x000000b1 ;//BANKSIZE
DCD 0x00000030 ;//MRSRB6
DCD 0x00000030 ;//MRSRB7
end
(三)异常处理入口
异常处理入口所需要做的事情
1)修正返回地址
a mov r0,#3
b mov r1,#1
c add r0,r0,r1
d sub r0,r0,r1
(1)一般中断和快速中断
如果a正在执行,pc在c的位置 此时发果发生了中断异常,a指令被执行完后开始触发中断,pc 处于d的位置, lr保存c的地址。而中断结束后应该从b的位置执行,这时需要修正lr的值
sub lr,lr,#4
(2)预取指异常
如果a正要执行,pc在c的位置,准备取指,此时取指发生了异常,a没有被执行完。lr在b的位置,但a没有被执行,异常结束后应该从a开始执行,需要修正lr的值
sub lr,lr,#4
(3)数据访问异常
如果a正在执行,发生数据访问异常,a被执行完的时候发现内存地址错误,pc在d的位置,lr保存了c的地址。但a本身出错了,所以要重新执行,需要修正lr的值
sub lr,lr,#8
(4)软中断异常
如果a是软中断指令,a被执行完,但pc还没被更新时触发异常,pc在c的位置,lr在b位置,异常后应反回b的地址,lr不需要修正
(5)未定义异常
如果a正在执行,b在译码,发现指令未定义,此pc在c的位置,lr保存的是b的地址。不需要修正
2)保存现场寄存器
r0-r12要保存,cpsr已被正动保存了,保存时需要入栈,因为异常已发生,模式已切换了,所以这些寄存器被保存到了异常模式下的栈区
stmfd sp!,{r0-r12,lr}
3)调中断处理函数
4)恢复现场寄存器和返回现场
ldmfd sp!,{r0-r12,pc}^
例:;//-------------------其它异常入口-------------------------
unDefined ;未定义异常入口
softInterrupt ;软中断异常入口
perfetchAbt ;预取指异常入口
dataAbt ;数据访问异常入口
unUsed ;未使用异常入口
handlerIrq ;一般中断异常入口
;修正返回地址
sub lr,lr,#4
;保存现场
stmfd sp!,{r0-r12,lr}
;调用中断处理函数
bl irq_event
;恢复现场并返回现场
ldmfd sp!,{r0-r12,pc}^
handlerFiq ;快中断异常入口
(三)中断处理
以key为例
第一步:底板电路图
k1 EINT1
k2 EINT4
k3 EINT2
k4 EINT0
下降沿触发
第二步:核心板电路图
k1 EINT1 GPF1
k2 EINT4 GPF4
k3 EINT2 GPF2
k4 EINT0 GPF0
第三步:芯片手册
1) GPIO
GPFCON 0x56000050
GPFDAT 0x56000054
GPFUP 0x56000058
GPFCON
[1:0] 设为10
[3:2] 设为10
[5:4] 设为10
[9:8] 设为10
cpfcon=2<<8 | 2<<4 | 2<<2 | 2
GPFDAT 不用设置
GPFUP 不用设置
2)EXINT0
EXTINT0 0x56000088
[2:0] 011
[6:4] 011
[10:8] 011
[18:16] 011
extint0= 3<<16 | 3<<8 | 3<<4 | 3
//以上两个寄存器设置完后就可以触发中断
中断号 EINT0-EINT2 直接进入SRCPND寄存器
中断号 EINT4 进入EINTPEND寄存器 再进入SRCPND 聚合为EINT4_7
中断函数处理完后EINTPEND和SRCPND两个寄存器的相应位要清0
EINTPEND 0x560000a8
[4] 中断被触发时自动填1 手写入1则清0
SRCPND 0X4A000000
[0] EINT0
[1] EINT1
[2] EINT2
[4] EINT4_7
中断被触发时自动填1 手写入1则清0
INTPND 0X4A000010
[0] EINT0
[1] EINT1
[2] EINT2
[4] EINT4_7
中断被触发时自动填1 手写入1则清0
识别当前触发的中断是哪一个中断号
INTOFFSET 0x4A000014
EINT4_7 4
EINT2 2
EINT1 1
EINT0 0
这里填写的是已触发完的中断的中断号,即偏移位
例:实现中断
//first.s
import Main
import irq_event
area init,code,readonly
entry
;//--------------------异常向量表-------------------------
b reSet ;0x00 复位异常
b unDefined ;0x04 未定义异常
b softInterrupt ;0x08 软中断异常
b perfetchAbt ;0x0c 预取指异常
b dataAbt ;0x10 数据访问异常
b unUsed ;0x14 未使用异常
b handlerIrq ;0x18 一般中断异常
b handlerFiq ;0x1c 快中断异常
;//--------------------复位异常入口-------------------------
reSet ;复位异常入口
;关闭看门狗
ldr r0,=0x53000000 ;wtcon
mov r1,#0
str r1,[r0]
;设置工作频率
;//----设置变频锁定时间
ldr r0,=0x4C000000 ;LOCKTIME
ldr r1,=0x00ffffff
str r1,[r0]
;//----锁相环分频器
ldr r0,=0x4C000004 ;MPLLCON 设置CPU主频
ldr r1,=0x5c <<12 | 1<<4 | 1
str r1,[r0]
ldr r0,=0x4C000008 ;UPLLCON 设置USB主频
ldr r1,=0x38 <<12 | 2<<4 | 2
str r1,[r0]
;//----设置AHB和APB总线频率
ldr r0,=0x4C000014 ;CLKDIVN 设置其它总线频率
ldr r1,=2<<1 | 1
str r1,[r0]
;//----设置CPU总线为异步模式
mrc p15,0,r0,c1,c0,0 ;协处理器指令 p15是协处理器名称
orr r0,r0,#0xC0000000
mcr p15,0,r0,c1,c0,0
;驱动内存条
;0x48000000 -0x48000030
ldr r0,=0x48000000 ;寄存器基址
ldr r1,=0x48000030 ;寄存器的最后地址
ldr r2,=memdat ;数据基址
memloop
ldr r4,[r2],#4 ;从memdat数组中用移动法读取数据
str r4,[r0],#4 ;将r4中的数据用移动写入寄存器
cmp r0,r1
ble memloop
;分配各模式下的栈内存
;复位默认是管理模式
ldr sp,=0x30100000 ;管理模式下的栈指针
;切换到用户模式
msr cpsr_c,#0xd0 ;设置为用户模式
ldr sp,=0x30200000 ;用户和系统模式下的栈指针
;切换到快中断模式
msr cpsr_c,#0xd1 ;设置为快中断模式
ldr sp,=0x30300000 ;快中断模式下的栈指针
;切换到一般中断模式
msr cpsr_c,#0xd2 ;设置为一般中断模式
ldr sp,=0x30400000 ;一般中断模式下的栈指针
;切换到中止模式
msr cpsr_c,#0xd7 ;设置为中止模式
ldr sp,=0x30500000 ;中止模式下的栈指针
;切换到未定义模式
msr cpsr_c,#0xdb ;设置为未定义模式
ldr sp,=0x30600000 ;未定义模式下的栈指针
;切换到管理模式
msr cpsr_c,#0xd3 ;设置管理模式
;设置GPF管脚
ldr r0,=0x56000050
ldr r1,=2<<8 | 2<<4 | 2<<2 | 2
str r1,[r0]
;设置触发方式
ldr r0,=0x56000088
ldr r1,=3<<16 | 3<<8 | 3<<4 | 3
str r1,[r0]
;切换到用户模式
msr cpsr_c,#0x10 ;设置用户模式,同时启动了中断
;//进入用户程序
bl Main
;//-------------------其它异常入口-------------------------
unDefined ;未定义异常入口
softInterrupt ;软中断异常入口
perfetchAbt ;预取指异常入口
dataAbt ;数据访问异常入口
unUsed ;未使用异常入口
handlerIrq ;一般中断异常入口
;修正返回地址
sub lr,lr,#4
;保存现场
stmfd sp!,{r0-r12,lr}
;调用中断处理函数
bl irq_event
;恢复现场并返回现场
ldmfd sp!,{r0-r12,pc}^
handlerFiq ;快中断异常入口
;//--------------------常用数据内存-----------------------
memdat
DCD 0x22000000 ;//BWSCON
DCD 0x00000700 ;//BANKCON0
DCD 0x00000700
DCD 0x00000700
DCD 0x00000700
DCD 0x00000700
DCD 0x00000700 ;//BANKCON5
DCD 0x00018005 ;//BANKCON6
DCD 0x00018005 ;//BANKCON6
DCD 0x008c04f5 ;//REFRESH
DCD 0x000000b1 ;//BANKSIZE
DCD 0x00000030 ;//MRSRB6
DCD 0x00000030 ;//MRSRB7
end
//test.c
void delay(int msec){
int i,j;
for(i=1000;i>0;i–){
for(j=msec*10;j>0;j–);
}
}
#define pEINTPEND ((unsigned long)0x560000a8)
#define pSRCPND ((unsigned long)0X4A000000)
#define pINTPND ((unsigned long)0X4A000010)
#define pINTOFFSET ((unsigned long)0x4A000014)
void irq_event(){
int key=-1;
//获取当前触发的中断号
unsigned long irqcode=pINTOFFSET;
switch(irqcode){
case 0: key=3; break;
case 1: key=0; break;
case 2: key=2; break;
case 4: key=1;
pEINTPEND= 1<<4; //清零
break;
}
pSRCPND = 1<
int Main(){
while(1){
}
}
四、移植(了解内核,看懂U-BOOT,会看芯片手册,根据芯片手册控制相应的硬件,汇编,移植)