专题6-点亮指路灯
1. LED原理图分析
在嵌入式系统软件(bootloader, kernel)开发初期,由于串口等硬件尚未被初始化,因此调试手段相当有限,这时通常会采用LED来作为程序调试的重要手段。
左边的图是低电平导通,右边的图是高电平导通。
LED的引脚究竟接在哪里是依靠核心板的电路图来识别的,依靠核心板的GPIO到底是接在哪里来判断的。
2. GPIO
GPIO(General-Purpose Input/Output Ports)通用输入/输出端口。在嵌入式系统中, CPU经常需要控制许多结构简单的外部设备或者电路,这些设备通常只要求两种状态(开/关), 对这些设备的控制,使用传统的串口或者USB口就显得复杂,所以,在嵌入式微处理器上通常提供了一种“通用可编程I/O端口”,也就是GPIO。
一个GPIO端口至少需要两个寄存器,一个是“控制寄存器”,用于选择该端口作为输入还是输出。另一个是存放数据的”数据寄存器”。
s3c2440有130个IO引脚,分成了A-J一共9个组;6410有187个IO引脚,被分成了A-Q一共17个组
3. 设计流程
(1)设置GPIO控制寄存器,把引脚设置为输出功能
(2)根据原理图设置GPIO数据寄存器,点亮LED
4. 写代码
TQ2440:
在TQ210的电路原理图上,可以观测到它的LED启动方式的低电平启动,对应的名称为nLED_1~nLED_4。接着我们打开TQ210的核心板原理图,搜索nLED_1~nLED_4,找到对应的引脚是GBD5~GPB8对应着10-17位,前10位可以都设置为0。
打开2440的芯片手册,找到对应的GPB控制寄存器GPBCON,如下:
GPBDAT寄存器,0-21对应0-11引脚:
代码:
在之前的start.s上做如下的修改:
reset:
bl set_svc
bl disable_watchdog
bl disable_interrupt
bl disable_mmu
bl light_led
#define GPBCON 0x56000010 @控制寄存器
#define GPBDAT 0x56000014 @数据寄存器
light_led:
ldr r0, =GPBCON @控制寄存器
ldr r1,=0x15400 @二进制的01 01 01 01 00 00 00 00 00
str r1, [r0] @将r1的值填到r0之中
ldr r0, =GPBDAT @数据寄存器
ldr r1,=0x6BF @二进制的1 10 10 11 11 11
str r1, [r0] @将r1的值填到r0之中
mov pc, lr @返回
在2440上按要求连接,输入命令/home/dnw ./gboot.bin 0X30000000,关闭电源,将开发板设置从nand flash启动,发现连个量,两个是熄灭的。
Tiny6410:
打开它的核心板原理图,可以看到它的二极管是低电平点亮。LED1-LED4分别连GPK4-GPK7引脚。
两个寄存器完成控制,一个寄存器完成数据。GPK这组一共有16个脚,一组控制寄存器需要4位控制一个,也就是需要2组控制寄存器。
控制寄存器,我们需要操作的是GPK4-GKP7,如下:
数据寄存器,设置两个量,两个灭,每一位控制一个灯
代码:
reset:
bl set_svc
bl disable_watchdog
bl disable_interrupt
bl disable_mmu
bl light_led
#define GPKCON 0x7f008800 @控制寄存器
#define GPKDAT 0x7f008808 @数据寄存器
light_led:
ldr r0, =GPKCON @控制寄存器
ldr r1,=0x11110000 @二进制的0001 0001 0001 0001 0000 0000 0000 0000
str r1, [r0] @将r1的值填到r0之中
ldr r0, =GPKDAT @数据寄存器
ldr r1,=0xa0 @二进制的1010 0000,4-7一个量一个灭
str r1, [r0] @将r1的值填到r0之中
mov pc, lr @返回
下载命令/home/dnw ./gboot.bin 0x50000000,发现在6410中的4盏灯都没有亮。原因是在6410的初始化过程需要进行“外设基地址初始化”,这就是我们需要补齐的。
专题6补充-外设基地址初始化(6410)
打开ARM11核的手册,搜索CP15,对应的是c15 0 c2 4显示:
在page3-130,显示:
在6410中的PC15的基地址是:
代码改成:
reset:
bl set_svc
bl set_peri_port @转到外设基地址
bl disable_watchdog
bl disable_interrupt
bl disable_mmu
bl light_led
set_peri_port:
ldr r0, =0x70000000 @外设基地址开始处
orr r0, r0, #0x13 @对应的256M,对应数字b10100
mcr p15,0,r0,c15,c2,4 @写回pc15寄存器
mov pc, lr
TQ210开发板(V4):
LED的原理图显示它是高电平点亮。
TQ210有237个GPIO引脚,分成了很多组,我们用到的是GPC0和GPC1组。
GPC0组的控制寄存器地址是0xE0200060,GPC0DAT寄存器地址是0xE0200064。
我们用到GPC0的第3位和第4位,控制方式如下:
对应的数据寄存器值的选定表如下,前三位都是0,led高电平工作,3-4位为1:
代码:
reset:
bl set_svc
bl disable_watchdog
bl disable_interrupt
bl disable_mmu
bl light_led
light_led:
ldr R0,=0xE0200060 @设置控制寄存器
ldr R1,=0x11000 @控制数据寄存器值,二进制为0001 0001 0000 0000 0000
str R1,[R0]
ldr R0,=0xE0200064 @设置数据寄存器
ldr R1,=0x00000018 @设置数据寄存器的值,二进制位11000
str R1,[R0]
mov pc, lr
执行make后,进行210文件加头,运行./mkv210 gboot.bin gboot-210.bin,使用命令
./home/dnw gboot-210.bin 0xc0008000。发现led的程序没有亮。
检查发现,所有的步骤都没有遗漏,点灯程序也正确。为了检测究竟是哪里出的错误,间点灯程序上移动,检查是否是其他的初始化程序出现了问题,最终发现是mmu的关闭程序出现了问题。
打开cotex_a8核心手册,在147页,如下:
在之前的2440和6410中的Icache和Dcache的初始化语句都是mcr p15,0,r0,c7,c7,0
但是在210中是没有的,Icache初始化是:mcr p15,0,r0,c7,c5,0,Dcache的初始化语句是:
mcr p15,0,r0,c7,c6,1。改写TQ210的mmu初始化位置:
disable_mmu:
mcr p15,0,r0,c7,c5,0
mcr p15,0,r0,c7,c6,1
mrc p15,0,r0,c1,c0,0
bic r0, r0, #0x00000007
mcr p15,0,r0,c1,c0,0
mov pc, lr
这样在编译就通过了,显示正确的结果。