看朱老师的视频,一点点记录
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_3、GPJ0_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颗(两边是熄灭的)LED(3.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 //函数调用返回