LED灯实验

cpu控制硬件原理

        我们学习的所有指令,六大指令里边,只有内存访问指令能访问cpu之外的内容。那cpu如何控制硬件?*****load/store指令--》操作4G内存

任何一个芯片都有一个地址映射表。告诉你地址空间是如何映射的,便于我们找到对应的硬件地址。

 

我们的SOC型号是S5P6818,对应的芯片用户手册为:(推荐:急速PDF阅读器)

S5P6818X用户手册V0.00

其中一章是:Memory map或Memory Controller 中的一张表中可以看地址隐射关系。

硬件控制原理:*****

CPU不能直接控制硬件,硬件是由其对应的控制器(寄存器)来控制的

每个控制器(寄存器)都会映射到CPU寻址范围内的一段空间

CPU通过对控制器(寄存器)的读和写实现对硬件间接的控制

cpu间接控制硬件。 on off on off off off

硬件板子介绍:

提供的工程模板里有一个map.lds,是指导程序如何排布。运行裸机程序首先需要看这个文件。


OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
	. = 0x48c00000; //起始地址,异常向量表的起始地址
	. = ALIGN(4);   
	.text      :  //代码
	{
		./Start/start.o(.text) 
                       //运行的第一段代码是start.s编译生成的.o
		*(.text)
	}
	. = ALIGN(4);
    .rodata : //只读  
	{ *(.rodata) }
    . = ALIGN(4);
    .data :   //.data
	{ *(.data) }
    . = ALIGN(4);
	__bss_start = .; 
    .bss ://.bss
     { *(.bss) }
	__bss_end__ = .;
}

start启动代码

start.S文件:
.text        @ .:伪操作
	.arm

	.global	_start
_start:   @第一段代码
	@ 第一条指令,内存地址0x43c00000
	@ 异常向量表
	b reset       @直接通过跳转指令跳转到reset
	b .
	b .
	b .
	b .
	b .
	b irq	@ IRQ异常对应的位置
	b .

 /* The actual reset code */
reset:
	/* 将异常向量表的基地址重定向到0x43c00000,即这段代码执行后遇到IRQ后PC的值会变成0x43c00000 + 0x18 */
	ldr	r0,=0x43c00000   @伪指令,将0x43c00000 放到r0中
	mcr	p15,0,r0,c12,c0,0		@ Vector Base Address Register
                     @p15是一个协处理器,管内存的,c12,c0都是p15里边的寄存器。c12管异常向量表的位置的。
	mrc p15, 0, r0, c1, c0, 0             @mrc是处理器指令
	bic r0, #(1<<13)
	mcr p15, 0, r0, c1, c0, 0

	/* 设置CPU为SVC模式 32位数据处理 ARM状态 */
	mrs r0, cpsr
	bic r0, r0, #0x1f
	orr r0, r0, #0xd3
	msr cpsr, r0

	/* Enable NEON/VFP unit */ 设置协处理器,浮点运算的协处理器
	mrc p15, #0, r1, c1, c0, #2
	orr r1, r1, #(0xf << 20)
	mcr p15, #0, r1, c1, c0, #2
	mov r1, #0
	mcr p15, #0, r1, c7, c5, #4
	mov r0, #0x40000000
	fmxr fpexc, r0

	/* Cache init */协处理器设置高速缓存,比内存读取更快
	mrc	p15, 0, r0, c0, c0, 0
	and	r1, r0, #0x00f00000
	and	r2, r0, #0x0000000f
	orr r2, r2, r1, lsr #20-4
	cmp r2, #0x30
	mrceq p15, 0, r0, c1, c0, 1
	orreq r0, r0, #0x6
	mcreq p15, 0, r0, c1, c0, 1

	/* Invalidate L1 I/D */
	mov r0, #0
	mcr	p15, 0, r0, c8, c7, 0
	mcr	p15, 0, r0, c7, c5, 0

	/* 关闭MMU,所以该代码运行在实际的物理地址上 */mmc负责虚拟地址和虚拟地址转换的,关闭,操作的是实际的物理地址。
/*mmu:内存管理单元,基于操作系统才有*/
	mrc p15, 0, r0, c1, c0, 0
	bic r0, r0, #0x00002000
	bic r0, r0, #0x00000007
	orr r0, r0, #0x00001000
	orr r0, r0, #0x00000002
	orr r0, r0, #0x00000800
	mcr p15, 0, r0, c1, c0, 0

	/* 初始化各个模式下的栈 */每个模式下都有自己栈指针,即每个模式都有自己的栈地址。每个模式下的栈初始化都需要切换到这模式下。

	/*********svc mode stack************/
	mrs r0, cpsr
	bic r0, r0, #0xdf

	orr r1, r0, #0xd3
	msr cpsr, r1
	ldr sp, _stack_svc_end

	/**********undef mode stack**********/
	orr r1, r0, #0xdb
	msr cpsr, r1
	ldr sp, _stack_und_end

	/*********abort mode stack*********/
	orr r1, r0, #0xd7
	msr cpsr, r1
	ldr sp, _stack_abt_end

	/*********irq mode stack************/
	orr r1, r0, #0xd2
	msr cpsr, r1
	ldr sp, _stack_irq_end

	/*********fiq mode stack************/
	orr r1, r0, #0xd1
	msr cpsr, r1
	ldr sp, _stack_fiq_end

   /*********user mode stack************/     
	orr r1, r0, #0x10
	msr cpsr, r1
	ldr sp, _stack_usr_end
      思考:为什么最后初始化user模式下的栈?因为user模式下不能再切换到其他模式了。

	/*Close Watch Dog Timer*//
	ldr r0, =0xC0012004
	ldr r1, [r0]
	orr r1, r1, #0x04000000
	str r1, [r0]

	ldr r0, =0xC0019000
	ldr r1, [r0]
	and r1, r1, #0xFFFFFFDF
	str r1, [r0]
	
	/* USER模式下的栈放在最后初始化 */
	/*
	 	1.因为USER模式不能切换成其他模式
		2.main执行时CPU处于USER模式
	 */
	/* Call _main */
	b main    @跳转到main函数运行代码。

/* IRQ的异常处理程序 */
irq:
	@ 遇到IRQ异常后CPU自动保存的返回地址是遇到异常时指令下下条指令的地址,所以我们需要人为修正
	sub  lr,lr,#4
	@ 因为IRQ模式下使用的寄存器与USER模式相同(R0-R12),所以在处理异常前要先将之前的寄存器压栈保护
	stmfd sp!,{r0-r12,lr}
	@ 异常处理,跳转到C处理(也可以用汇编在这写。)
	bl do_irq
	@ 异常返回
	@ 1.将R0-R12寄存器的值出栈恢复
	@ 2.将SPSR的值给CPSR,回到了USER模式
	@ 3.将LR的值给PC,实现程序的返回
	ldmfd sp!,{r0-r12,pc}^

_stack_svc_end:      .long   stack_svc + 512
_stack_und_end:      .long   stack_und + 512
_stack_abt_end:      .long   stack_abt + 512
_stack_irq_end:      .long   stack_irq + 512
_stack_fiq_end:      .long   stack_fiq + 512
_stack_usr_end:      .long   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

LED实验

步骤:

1.通过底板原理图,找到对应电路分析灯怎么亮。给一个高电平灯亮。

2.通过核心板原理,找到对应引脚。

3.通过手册确定引脚功能--》GPIO,输出一个高电平灯亮

GPIO共160个,分为5类:ABCDE 每一类32个,标号0-31

控制寄存器-->设置

1)选GPIOA28的功能 --》对应寄存器是GPIOAALTFN1

地址:0xC001A024 设置值为:0x00000000

GPIOAALTFN1 =GPIOAALTFN1 & ~(3<<24)

2)设置GPIOA28为输出功能--》GPIOAOUTENB

地址:0xC001A004 设置值为:0x10000000

3)设置GPIOA28为输出高电平--》GPIOAOUT

地址:0xC001A000 设置值为:0x10000000

本地开发和交叉开发

  • 本地开发:PC端编写代码,编译代码,运行代码
  • 交叉开发:PC端编写代码,编译代码,Target(目标板)运行代码

PC Target

X86架构 arm架构

  • 使用交叉编译工具链将源码编译成支持ARM架构的可执行程序
  • 再将可执行程序拷贝到目标板上运行。

PC:gcc

交叉编译工具链:arm-none-linux-gnueabi-gcc

注:arm-none-linux-gnueabi-:交叉编译工具链的名字,名字就是一个代号,

在工作中用的不一定是这个,不同的公司做的交叉编译工具链的名字不同

  • 安装交叉编译工具链
  • 获取交叉编译工具链

一般交叉编译工具链和uboot和linux内核源码,都具有配套的关系。

  • 自己去gnu官网获取交叉编译工具链的源码,自己进行编译生成对应的交叉编译工具链。不推荐:编译过程很繁琐
  • 直接从芯片厂家获取交叉编译工具链
  • 直接跟开发板的生成厂家获取交叉编译工具链
  • 直接找主管获取交叉编译工具链(单位)

**********************************************

  • 安装交叉编译工具链:

安装步骤:

1、 在ubuntu的家目录下创建arm-gcc目录

$ cd  ~

$ mkdir  arm-gcc

$ cd arm-gcc

将学生资料中“1.工具软件\2.汇编环境搭建\3.编译工具”中的gcc-4.9.4.tar.xz拷贝到arm-gcc目录下并解压

$ tar  -xvf  gcc-4.9.4.tar.xz

2、 将交叉编译工具链添加到全局环境变量使其全局可用

打开配置文件/etc/bash.bashrc

$ sudo  vi  /etc/bash.bashrc

在其最后一行添加如下内容

export  PATH=$PATH:/home/hq/arm-gcc/gcc-4.9.4/bin

查看环境变量命令 pritfenv/env

重启配置文件使配置生效

$ source  /etc/bash.bashrc

6. 测试交叉编译工具链是否安装成功

arm-none-linux-gnueabi-gcc -v

打印以下内容,表示成功

gcc version 4.6.4 (Sourcery G++ Lite 2010.09-50)

LED实验

  • 分析电路图
  • 分析电路图的思路:从外设(地板)---》SOC(核心板)分析

分析LED

  • 在电路板上找到led灯的位置
  • LED灯旁边会有白色的字,此白字为丝印LED灯旁边的字,是led灯的编号
  • 打开底板的原理图,在原理图上搜索led灯编号(RGB)

分析led的电路图

共阳三色二极管:三个二极管的正极接到一起

  • RGB_R/RGB_G/RGB_B 表示网络标号

网络标号名字相同表示具有相同的电气连接属性,反应到电路板上,他们通过导线连接到一起

  • 根据网络标号到核心板原理图,找到soc哪个引脚驱动着LED灯
  • 2. 读懂芯片手册(黑盒测试,白盒测试)
  • 工作寄存器:R0-R15,cpsr,spsr,由ARM公司提供,没有地址
  • 控制寄存器:就是内存的一块空间,具有地址,由芯片厂家提供。寄存器是在GPIO章节被使用,所以看芯片手册的时候看GPIO章节,里面一定有相关寄存器的使用和功能实现。
  • 我们只需要向控制寄存器中写值或者读值,就可以让我们处理器完成一定的功能。这也就是我们软件编程控制硬件的思想。

1》GPIOxOUT:控制引脚输出高低电平

RED_LED--->GPIOA28

GPIOAOUT ---> 0xC001A000

GPIOA28输出高电平:

GPIOAOUT[28] <--写-- 1

GPIOA28输出低电平:

GPIOAOUT[28] <--写-- 0

2》GPIOxOUTENB:控制引脚的输入输出模式

GPIOAOUTENB ---> 0xC001A004

设置GPIOA28引脚为输出模式:

GPIOAOUTENB[28] <--写-- 1

3》GPIOxALTFN:控制引脚功能的选择

GPIOAALTFN1 ---> 0xC001A024

设置GPIOA28引脚为GPIO功能:

GPIOAALTFN1[25:24] <--写-- 0b00

00 = ALT Function0

01 = ALT Function1

10 = ALT Function2

11 = ALT Function3

GPIO引脚功能的选择:每两位控制一个GPIO引脚,

 

对应的功能可以在芯片手册的

2.3章节进行查看。

3. 编写代码

1. 设置为GPIOA28为GPIO功能

2. 设置GPIOA28为输出功能

while(1)

{

设置GPIOA28输出高电平

延时

设置GPIOA28输出低电平

延时

}

4. 下载调试修改bug

1》拷贝.bin文件到windows中

2》开发板和电脑进行硬件连接

串口线的USB端插到电脑的USB口

串口线的串口端插到开发板的UART0端口上

开发板插上电源

3》配置windows超级终端

如果串口线第一次使用需要安装串口驱动

串口驱动文件在资料中

配置超级终端:

可以查看配置超级终端的使用说明文档

资料中有

在设备管理器中,查看串口线使用的那个端口号

配置端口属性:

波特率:115200

数据位:8

停止位:1

校验位:无

流控:无

4》开发板上电,超级终端会有打印信息

在倒计时减到0之前按任意键,进入到FS6818#界面

执行命令 loadb 0x43c00000 --》下载二进制文件到内存的0x43c00000

传送--》发送文件--》选择要下载.bin文件,选择Kermit协议 --》 确定下载

执行命令:go 0x43c00000 --》到0x43c00000位置运行代码

如果需要重新下载代码,重复步骤4

修改倒计时的时间:

setenv bootdelay 60

saveenv

作业:语音:实现硬件板子点灯操作的步骤

对交叉编译工具的理解

录视频:流水灯(1~3s)

汇编移位操作指令

明天早上三个人分享:

1:今天学习内容,2:流水灯代码,3:汇编移位指令代码

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值