LV.12 D13 C工程与寄存器封装 学习笔记

一、C语言工程简介

把模板在linux解压出来

代码写在interface.c就可以了。

map.lds是链接脚本文件(负责代码的排布)

include中是头文件,src中是写好的源代码 

LV.12 D13 C工程与寄存器封装 学习笔记_第1张图片

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来控制。

 

你可能感兴趣的:(学习,笔记,arm开发)