一、C语言工程简介
把模板在linux解压出来
代码写在interface.c就可以了。
map.lds是链接脚本文件(负责代码的排布)
include中是头文件,src中是写好的源代码
start.s是启动代码,在interface.c之前运行,把cpu和栈做一个初始化
二、启动代码分析
.text
.global _start
_start:
/*
* Vector table
* 异常向量表(占32个字节)
*/
b reset
b .
b .
b .
b .
b .
b .
b .
reset:
/*
* Set vector address in CP15 VBAR register
*/
ldr r0, =_start @把异常向量表的值给r0
mcr p15, 0, r0, c12, c0, 0 @Set VBAR (把r0寄存器的值放到p15协处理器中的c12寄存器)
/*
* Set the cpu to SVC32 mode, Disable FIQ/IRQ
* 把cpu模式改成SVC模式,改成ARM状态,关闭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
* MMU:负责物理地址和虚拟地址间的转换
*/
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 @把cpu的模式改为svc模式
ldr sp, _stack_svc_end @把svc模式下的栈的最高地址给了svc模式下的sp
/*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*/
/*把cpu的模式改为user模式,并打开FIO/IRQ中断
msr cpsr,#0x10
ldr sp, _stack_usr_end
/*Call main*/
b main
/*
* 把各个栈最高的地址算出来,作为起始地址
*/
_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
/*
* 给各个模式都申请了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()
{
/*通过设置GPX2CON寄存器来将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 main()
{
GPX2CON = 0x10000000;
while(1)
{
/*点亮LED2*/
GPX2DAT = 0x00000080;
/*延时*/
Delay(1000000);
/*熄灭LED2*/
GPX2DAT = 0x00000000;
/*延时*/
Delay(1000000);
}
return 0;
}
2、把相关的几个寄存器封装成一个结构体,其地址空间必须是连续的
typedef struct
{
unsigned int CON;
unsigned int DAT;
unsigned int PUD;
unsigned int DRV;
}gpx2;
#define GPX2 (*(gpx2 *)0x11000c40)
int main()
{
GPX2.CON = 0x10000000;
while(1)
{
/*点亮LED2*/
GPX2.DAT = 0x00000080;
/*延时*/
Delay(1000000);
/*熄灭LED2*/
GPX2.DAT = 0x00000000;
/*延时*/
Delay(1000000);
}
return 0;
}
3、把整个芯片里的寄存器封装好,引用头文件
#include "exynos_4412.h"
int main()
{
GPX2.CON = 0x10000000;
while(1)
{
/*点亮LED2*/
GPX2.DAT = 0x00000080;
/*延时*/
Delay(1000000);
/*熄灭LED2*/
GPX2.DAT = 0x00000000;
/*延时*/
Delay(1000000);
}
return 0;
}
五、寄存器操作的标准化
只改寄存器的某几位,其他位保持不变
#include "exynos_4412.h"
int main()
{
GPX2.CON = GPX2.CON & (~(0xF << 28)) | (0x1 << 28);
while(1)
{
/*点亮LED2*/
GPX2.DAT = GPX2.DAT | (1 << 7);
/*延时*/
Delay(1000000);
/*熄灭LED2*/
GPX2.DAT = GPX2.DAT & (~(1 << 7));
/*延时*/
Delay(1000000);
}
return 0;
}
/*
* 1.unsigned int a; 将a的第3位置1,其他位保持不变
* ******** ******** ******** ********
* ******** ******** ******** ****1***
* 00000000 00000000 00000000 00001000
*
* a = a | (1 << 3);
*
* 2.unsigned int a; 将a的第3位置0,其他位保持不变
* ******** ******** ******** ********
* ******** ******** ******** ****0***
* 11111111 11111111 11111111 11110111
*
* a = a & (~(1 << 3));
*
* 3.unsigned int a; 将a的第[7:4]位置为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);
*/
我没并不只能控制LED,一切可以通过高低电频控制的东西,都可以通过GPIO来控制。