.text
.global _start
_start:
/*
* Vector table
*/
b reset
b .
b .
b .
b .
b .
b .
b .
reset:
/*
* Set vector address in CP15 VBAR register
*/
//把_start的地址赋给r0
ldr r0, =_start
//修改异常向量表的的地址
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
/*
* Set the cpu to SVC32 mode, Disable FIQ/IRQ
*/
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr ,r0
/*
* Defines access permissions for each coprocessor
*/
// 定义各个协处理器的访问权限
mov r0, #0xfffffff
mcr p15, 0, r0, c1, c0, 2
/*
* Invalidate L1 I/D
*/
mov r0, #0 @Set up for MCR
mcr p15, 0, r0, c8, c7, 0 @Invalidate TLBs
mcr p15, 0, r0, c7, c5, 0 @Invalidate icache
/*
* Set the FPEXC EN bit to enable the FPU
*/
mov r3, #0x40000000
fmxr FPEXC, r3
/*
* Disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002000 @Clear bits 13 (--V-)
bic r0, r0, #0x00000007 @Clear bits 2:0 (-CAM)
orr r0, r0, #0x00001000 @Set bit 12 (---I) Icache
orr r0, r0, #0x00000002 @Set bit 1 (--A-) Align
orr r0, r0, #0x00000800 @Set bit 11 (Z---) BTB
mcr p15, 0, r0, c1, c0, 0
/*
* Initialize stacks
*/
init_stack:
/*svc mode stack*/
msr cpsr, #0xd3
//ldr不加=,相当于把_stack_svc_end中的内容给sp,这里是SVC栈空间的最高地址
ldr sp, _stack_svc_end
/*undef mode stack*/
msr cpsr, #0xdb
ldr sp, _stack_und_end
/*abort mode stack*/
msr cpsr,#0xd7
ldr sp,_stack_abt_end
/*irq mode stack*/
msr cpsr,#0xd2
ldr sp, _stack_irq_end
/*fiq mode stack*/
msr cpsr,#0xd1
ldr sp, _stack_fiq_end
/*user mode stack, enable FIQ/IRQ*/
msr cpsr,#0x10
ldr sp, _stack_usr_end
/*Call main*/
b main
//因为是满减栈,所以SP的起始位置指向栈空间的最高地址
_stack_svc_end:
.word stack_svc + 512
_stack_und_end:
.word stack_und + 512
_stack_abt_end:
.word stack_abt + 512
_stack_irq_end:
.word stack_irq + 512
_stack_fiq_end:
.word stack_fiq + 512
_stack_usr_end:
.word stack_usr + 512
//申请栈空间
.data
stack_svc:
.space 512
stack_und:
.space 512
stack_abt:
.space 512
stack_irq:
.space 512
stack_fiq:
.space 512
stack_usr:
.space 512
利用C语言实现LED闪烁
/*
一.汇编语言访问存储器
1.读存储器
LDR R1,[R2]
2.写存储器
STR R1,[R2]
二.C语言访问存储器
1.读存储器
data = *ADDR;
2.写存储器
*ADDR = data;
*/
void Delay(unsigned int time){
while(time --);
}
int main()
{
/*通过设置DRX2CON寄存器来将GPX2_7引脚设置成输出功能*/
*(unsigned int *)0x11000c40 = 0x10000000;
while(1){
/*点亮LED2*/
*(unsigned int *)0x11000c44 = 0x00000080;
/*延时函数*/
Delay(1000000);
/*熄灭LED2*/
*(unsigned int *)0x11000c44 = 0x00000000;
Delay(1000000);
}
return 0;
}
寄存器的封装方式
1.利用宏定义
//利用宏定义来封装寄存器
#define GPX2CON (*(unsigned int *)0x11000c40)
#define GPX2DAT (*(unsigned int *)0x11000c44)
int mian(){
GPX2CON = 0x10000000;
while(1){
/*点亮LED2*/
GPX2DAT = 0x00000080;
/*延时函数*/
Delay(1000000);
/*熄灭LED2*/
GPX2DAT = 0x00000000;
Delay(1000000);
}
return 0;
}
2
//利用结构体来封装寄存器
tydef struct{
unsigned int CON;
unsigned int DAT;
unsigned int PUD;
unsigned int DRV;
}gpx;
#define GPX2 (*(gpx *)0x11000c40)
int mian(){
GPX2.CON = 0x10000000;
while(1){
/*点亮LED2*/
GPX2.DAT = 0x00000080;
/*延时函数*/
Delay(1000000);
/*熄灭LED2*/
GPX2.DAT = 0x00000000;
Delay(1000000);
}
return 0;
}
3.直接引用头文件"exynos_4412.h"
寄存器操作的标准化
/*
1.unsigned int a;将a的第三位置1,其他位保持不变
******** ******** ******** ********
******** ******** ******** ****1***
00000000 00000000 00000000 00001000
a = a | 0x00000008;
a = a | (1<<3);
2.unsigned int a;将a的第三位置0,其他位保持不变
******** ******** ******** ********
******** ******** ******** ****0***
11111111 11111111 11111111 11110111
a = a & 0xfffffff7;
a = a & (~(1<<3));
3.unsigned int a;将a的第[4-7]置为0101,其他位保持不变
******** ******** ******** ********
******** ******** ******** 0101****
1).清零
11111111 11111111 11111111 00001111
00000000 00000000 00000000 11110000
00000000 00000000 00000000 00001111
a = a & (~(0xf<<4));
2).置位
00000000 00000000 00000000 01010000
00000000 00000000 00000000 00000101
a = a | (0x5<<4);
a = a &(~(0xf<<4)) | (0x5<<4);
*/