x210 一步步点亮LED

看朱老师的视频,一点点记录


1 LED硬件工作原理及原理图查阅(硬件有关)

1.1 原理图是在底板x210bv3中查询


查阅原理图,发现开发板上一共有5颗LED。其中一颗D26的接法是:正极接5V,负极接地。因此这颗LED只要上电就会常亮。因此我们分析这颗LED是电源指示灯。

剩下4颗LED的接法是:正极接3.3V,负极接了SoC上的一个引脚(GPIO),具体详细接法是:

D22:GPJ0_3

D23:GPJ0_4

D24:GPJ0_5

D25:PWMTOUT1(GPD0_1)    [PWMTOUT1接在了核心板x210cv3,利用好pdf 阅读器中的搜索功能]

1.2 分析如何点亮及熄灭LED(GPIO)

分析:LED点亮的要求是:正极和负极之间有正向电压差。

思考:在开发板上如何为LED制造这个电压差让它点亮呢?

解答:因为正极已经定了(3.3V),而负极接在了SoC的引脚上,可以通过   SoC中编程来控制负极的电压值,因此我们可以通过程序控制负极输 出低电平(0V),这样在正负极上就有了压差,LED即可点亮。

数据手册查阅及相关寄存器浏览

2.1 GPIO概念的引入

GPIO:general purpose input output 通用输入输出

GPIO就是芯片的引脚(芯片上的引脚有些不是GPIO,只有一部分是),作为GPIO的这类引脚,他的功能和特点是可以被编程控制它的工作模式,也可以编程控制他的电压高低等。

通过之前的分析我们知道,我们设计电路时就把LED接在了一个GPIO上,这样我们就可以通过编程控制GPIO的模式和输入输出值来操控LED亮还是灭;如果你当时设计电路时把LED接在非GPIO上那就不可能了。

 

2.2 阅读数据手册中有关部分(S5PV210_UM_REV1.1)

当我们想要通过编程操控GPIO来操作LED时,我们首先需要通读一下S5PV210的数据手册中有关于GPIO的部分,这部分在数据手册的Section2.2中。


GPJ0CON[0] 就是GPJ0CON_0

[3:0]  —— bit3 ~ bit0   4位

 bit3 ~ bit0,设置的不同分别有7种模式

2.3 GPIO相关的寄存器介绍

回忆下之前说过的,软件操作硬件的接口是:寄存器。

我们当前要操作的硬件是LED,但是LED实际是通过GPIO来间接控制的,所以当前我们实际要操作的设备其实是SoC的GPIO。要操作这些GPIO,必须通过设置他们的寄存器。

查阅数据手册(S5PV210_UM_REV1.1)可知,GPJ0相关的寄存器有以下:

GPJ0CON, (GPJ0 control)GPJ0控制寄存器,用来配置各引脚的工作模式

GPJ0DAT, (GPJ0 data)当引脚配置为input/output模式时,寄存器的相 应位和引脚的电平高低相对应。

GPJ0PUD, (pull up down)控制引脚内部弱上拉、下拉

GPJ0DRV, (driver)配置GPIO引脚的驱动能力

GPJ0CONPDN,(记得是低功耗模式下的控制寄存器)

GPJ0PUDPDN  (记得是低功耗模式下的上下拉寄存器)

注:在驱动LED点亮时,应该将GPIO配置为output模式。

实际上真正操控LED的硬件,主要的有:GPJ0CON, GPJ0DAT 这么2个。

如何点亮LED,编程的步骤是:

1、操控GPJ0CON寄存器中,选中output模式

2、操控GPJ0DAT寄存器,相应的位设置为0

3.从零开始手写汇编点亮LED

3.1 GPxCON、GPxDAT寄存器分析

GPJ0端口一共有8个引脚,分别记住:GPJ0_0 ~ GPJ0_7,相关重要寄存器就是GPJ0CON和GPJ0DAT

GPJ0CON寄存器中设置8个引脚的工作模式(32/8=4,每个引脚可以分到4位,譬如GPJ0_0对应的bit位为bit0~bit3,GPJ0_3对应的位为bit12~bit15。工作方法是:给相应的寄存器位写入相应的值,该引脚硬件就会按照相应的模式去工作。譬如给bit12~bit15写入0b0001,GPJ0_3引脚就成为输出模式了)

 

3.2 从零开始写代码操作寄存器

需要哪些先决条件才能写呢?

1. 硬件接法和引脚:GPJ0_3 GPJ0_4 GPJ0_5 低电平亮/高电平灭;

2. GPJ0CON(0xE0200240)寄存器和GPJ0DAT(0xE0200244)寄存器;

3. 工程管理:Makefile等。

根据以上分析,我们就知道代码的写法了,代码所要完成的动作就是:

把相应的配置数据写入相应的寄存器即可。

3.3 怎么写?

先将朱老师写好的led文件(1.leds_s)中的 三个文件(Makefile、mkv210_image、write2sd)复制到自己的文件夹(2.leds_s)里,然后新建一个.S文件(led.S),在这个文件里写程序。具体的程序怎么写、为什么这么写,在这个文件后面都有注释。

3.4 编译、下载、运行看结果

编译时用我们的工程管理,直接make编译得到led.bin和210.bin

下载运行可以用usb启动dnw下载;也可以用sd卡烧录下载,根据自己的情况用一般都用usb下载,因为方便。usb启动dnw下载,则运行led.bin文件

注意:开发板上按下电源键之后4颗LED默认都是半亮的,当我们下载程序后其中3颗变的很亮,这说明我们的程序已经运行了。

 

3.5 总结和回顾(软件控制硬件思想、寄存器意义、原理图数据手册的作用)

软件到底是怎么控制硬件的?为什么程序一运行硬件就能跟着动?

软件编程控制硬件的接口就是:寄存器

 

4.问题及解决

问题1 后缀名没改

应该创建文件名为2.leds_s.S ,而我创建为2.leds_s.S.txt。

问题2 不细心

编程的时候把r0写成了ro 。

问题3 编译得到led.bin和210.bin,运行哪一个?

usb启动dnw下载,则运行led.bin文件;

sd卡烧录下载,则运行210.bin文件。

 

5 程序分析

目的:3个LED(GPJ0_3GPJ0_4、GPJ0_5)全亮2.leds_s)

 

 

 

第一步:把0x11111111写入0xE0200240(GPJ0CON)位置。

原因:  应该将GPJ0_3、GPJ0_4、GPJ0_5这3个引脚设置为输出模式,其余5个引脚无所谓,故干脆把8个引脚(GPJ0CON_0~GPJ0CON_7)全设置为输出模式。

 

第二步:把0x0写入0xE0200244(GPJ0DAT)位置。

原因:  实际上只需要将GPJ0DAT的8个bit中的bit3—bit5设置为0,其余  bit位0是1无所谓,所以干脆都设置为0,即00000000,即0x0。

 

6.问题提出:如何只点亮中间1颗(两边是熄灭的)LED3.leds_s)

  分析:  程序其实就是写了GPJ0CON和GPJ0DAT这2个寄存器而已,功能更  改也要从这里下手。GPJ0CON寄存器不需要修改,GPJ0DAT中设置  相应的输出值即可。

  直接解法:  GPJ0DAT = 0x28    代码见<3.led_s>

  目的:只让中间的LED(GPJ0_4)亮,另外两个(GPJ0_3、GPJ0_5)熄。

  程序分析:

第一步:把0x11111111写入0xE0200240(GPJ0CON)位置。把8个引脚全设置 为输出模式,代码不变

 

第二步:把0x28写入0xE0200244(GPJ0DAT)位置。

原因:  GPJ0DAT的8个bit中的bit4设置为0,bit3和bit5为1,其余几  位是0是1无所谓(因为我只需要用bit3,bit4,bit5),那我就将  其余几位都设置为0,即00101000,即0x28。

小结: 1.这样写可以完成任务。

     2.这样写有缺陷。缺陷就是需要人为的去计算这个特定的设置值,而   且看代码的也不容易看懂。

解决方案:在写代码时用位运算去让编译器帮我们计算这个特定值。

 

7.使用位运算实现功能

7.1常用位运算:位与(&)  位或(|)  位非(取反 ~) 移位(左移<<  右移>>)

7.2 目的:  中间亮两边灭

直接解法:  GPJ0DAT = 0x28

位运算:  ldr r0, = ((1<<3) | (1<<5))

分析:  1左移3位为1000,1左移5位为100000,1000和100000进行位或  运算,得到0b00101000,即0x28

0b00101000  // 00101000前面加个0b,代表00101000是二进制

 

还可以这样,ldr r0, = ((1<<3) | (0<<4) | (1<<5))

别人一看就知道,哪个亮哪个灭,bit3和bit5灭,bit4亮

 

7.3 扩展一下:如何只熄灭中间1颗而点亮旁边2颗

ldr r0, = ((0<<3) | (1<<4) | (0<<5))

 

8 汇编编写延时函数并实现LED闪烁效果

8.1闪烁效果原理分析

闪烁 = 亮 + 延时 + 灭 + 延时 + 亮 + 延时 ······

8.2 汇编编写延时函数

汇编编写延时函数的原理,用一个寄存器存放一个数字,然后在循环中每个循环里给数字减1,然后再判断这个数字的值是否为0.如果为0则停止循环,如果不为0则继续循环。

 

// 延时函数:函数名:delay

delay:

ldr r2, =9000000

ldr r3, =0x0//这两句是初始化

delay_loop:

sub r2, r2, #1 //r2 = r2 - 1

cmp r2, r3 //cmp会影响Z标志位,如果r2等于r3则Z=1,    

//下一句中eq就会成立

bne delay_loop //这三句是函数体

mov pc, lr //函数调用返回

 

8.3 用汇编写死循环也很简单

flash:

-延时-灭-延时... //循环体

b flash

 

8.4 汇编编写及调用函数的方式

汇编中整个汇编的主程序是一个死循环,这个死循环是我们汇编程序的主体,类似于C中的main函数。其他函数必须写在这个主死循环程序的后面(死循环外),不然会出错。

汇编编写delay延时函数时,要注意函数的初始化和函数体的位置,不能把初始化写在了循环体内。

汇编中调用函数用bl指令,子函数中最后用mov pc, lr来返回。

 

编程操控一个硬件的步骤:

1 分析硬件工作原理

2 分析原理图

3 分析数据手册

4 找到相关的SFR

5 写代码设置寄存器得到想要的效果

9.自己做的。板子上有4颗LED的(还有个在GPD0_1),四个灯依次点亮

1.分析硬件工作原理(底板x210bv3)

1.观察第四个灯D25:PWMTOUT1

所以要查核心板x210cv3,[PWMTOUT1接在了核心板x210cv3,利用好pdf阅读器中的搜索功能],发现PWMTOUT1对应的就是GPD0_1

2.分析数据手册

在S5PV210_UM_REV1.1中查找GPIO对应的SFR——GPJ0、GPD0

4.找到相关的SFR

然后相关的SFR为GPJ0_CON、GPJ0_DAT、GPD0_CON、GPD0_DAT

5 写代码设置寄存器得到想要的效果  文件名<9.leds_s>和<11.leds_swang>

1.观察第四个灯D25:PWMTOUT1

所以要查核心板x210cv3,[PWMTOUT1接在了核心板x210cv3,利用好pdf阅读器中的搜索功能],发现PWMTOUT1对应的就是GPD0_1

2.分析数据手册

在S5PV210_UM_REV1.1中查找GPIO对应的SFR——GPJ0、GPD0

4.找到相关的SFR

然后相关的SFR为GPJ0_CON、GPJ0_DAT、GPD0_CON、GPD0_DAT

5 写代码设置寄存器得到想要的效果  文件名<9.leds_s>和<11.leds_swang>


1.观察第四个灯D25:PWMTOUT1

所以要查核心板x210cv3,[PWMTOUT1接在了核心板x210cv3,利用好pdf阅读器中的搜索功能],发现PWMTOUT1对应的就是GPD0_1

2.分析数据手册

在S5PV210_UM_REV1.1中查找GPIO对应的SFR——GPJ0、GPD0

4.找到相关的SFR

然后相关的SFR为GPJ0_CON、GPJ0_DAT、GPD0_CON、GPD0_DAT

5 写代码设置寄存器得到想要的效果  文件名<9.leds_s>和<11.leds_swang>

/*
 *文件名: 9.leds_s
 *作者:
 *描述: 流水灯-四个灯依次点亮
*/


#define GPJ0CON 0xE0200240
#define GPJ0DAT 0xE0200244
#define GPD0CON 0xE02000A0
#define GPD0DAT 0xE02000A4


.global _start //用.global把_start链接属性改为外部,这样其他文件就可以看见_start了
_start:
//第一步:把0x11111111写入0xE0200240(GPJ0CON)位置。意思是把8个引脚全设置为输出模式,代码不变。
ldr r0, =0x11111111 //从后面的=可以看出用的是ldr伪指令,因为需要编译器来判断这个数
ldr r1, =GPJ0CON //是合法立即数还是非法立即数。一般写代码都用ldr伪指令
str r0, [r1] //寄存器间接寻址功能是把r0中的数写入到r1中的数为地址的内存中去

//第二步:把0x1111写入0xE02100A0(GPD0CON)位置。
ldr r0, =10000 //ldr r0, =(1<<4)
ldr r1, =GPD0CON
str r0, [r1]

flash:
//第1步:第一颗灯亮
//ldr r0, = ((0<<3) | (1<<4) | (1<<5))
ldr r0,= GPD0DAT
ldr r1,= 1111 //ldr r1,= (1<<1)
str r1,[r0]
ldr r0, = ~(1<<3) //1000  位取反   为 0111
ldr r1, =GPJ0DAT
str r0,[r1] //把0写入到GPJ0DAT寄存器中,引脚即输出低电平,LED点亮
//然后:延时
bl delay 

//第2步:第二颗灯亮
ldr r0,= GPD0DAT
ldr r1,= 1111
str r1,[r0]
ldr r0, = ~(1<<4)
ldr r1, =GPJ0DAT
str r0,[r1] //把0写入到GPJ0DAT寄存器中,引脚即输出低电平,LED点亮
//然后:延时
bl delay 

//第3步:第三颗灯亮
ldr r0,= GPD0DAT
ldr r1,= 1111
str r1,[r0]

ldr r0, = ~(1<<5)
ldr r1, =GPJ0DAT
str r0, [r1] //把0写入到GPJ0DAT寄存器中,引脚即输出低电平,LED点亮
//然后:延时
bl delay 

//第4步:第四课灯亮
ldr r0, =1101 //ldr r0, =(0<<1)
ldr r1, =GPD0DAT
str r0, [r1]
ldr r0,= GPJ0DAT
ldr r1,= (1<<3)|(1<<4)|(1<<5)
str r1,[r0]
//然后:延时
bl delay 

b flash

// 延时函数:函数名:delay
delay:
ldr r2, =9000000
ldr r3, =0x0
delay_loop:
sub r2, r2, #1 //r2 = r2 - 1
cmp r2, r3 //cmp会影响Z标志位,如果r2等于r3则Z=1,下一句中eq就会成立
bne delay_loop
mov pc, lr //函数调用返回

猜你喜欢

转载自blog.csdn.net/yaodaoji/article/details/55667706