ARM汇编

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.伪指令

  1. ldr 读取数据
    ldr r0,=0x3 //伪指令
    本质,是在运行时,先在内存中分配一个空间。将3存入到内存中,然后再用 ldr r0,[地址]来读取数据
    a dcd 0x3
    ldr r1,=a //伪指令
    ldr r0,[r1] //数据加载指令,不是伪指令

  2. adr 读数据
    adr r0,0x3

  3. nop 空转
    用途,用于编写延时函数

12.伪操作
伪指令 是汇编指令
伪操作 是编译器的预处理

  1. 常量
    标号名(常量名) EQU 值(表达式) {类型}

    x equ 23 ;常量23的名字是x 相当于c中的#define

  2. 数据定义
    用于为特定的数据分配存储单元,同时可以完成内存的初始化
    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.内存

  1. 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用来控制内存是只读还是只写的

芯片手册

  1. 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< pINTPND = 1< }

int Main(){
while(1){
}

}

四、移植(了解内核,看懂U-BOOT,会看芯片手册,根据芯片手册控制相应的硬件,汇编,移植)

你可能感兴趣的:(Linux,嵌入式,ARM汇编,汇编,arm开发)