ARM的纯汇编实验(001)-LED闪烁
这篇文章的内容是记录笔者学习ARM时的第一次汇编语言实验,LED闪烁
我从淘宝买了一块主控制芯片为IMX6ULL(之后简称芯片)的开发板,上面有很多外设。但我想,学习开发的第一步是点亮一个LED。
一,硬件原理分析
我首先把开发板的电路原理图打开,查看这个LED与我们的芯片是如何建立物理联系的;这样我们才能知道如何控制它。
连接LED的引脚被称为"LED0"。所以我们知道对应关系是LED0 = 0时,亮;LED0=1时,灭。
但LED0依然不是连接到芯片的引脚名,我在原理图中跟踪到,LED0又连接到了芯片的GPIO1_IO03引脚。
如此一来,芯片如何控制LED就很清楚了:
GPIO1_IO03输出0,LED亮;
GPIO1_IO03输出1, LED灭。
二,芯片配置分析
如何控制芯片的GPIO1_IO03引脚呢?我便又要打开《IMX6UL参考手册》。
翻到26章,查看到如下内容。这说明,要控制GPIO,
1.要配置IOMUXC寄存器组,设置引脚为GPIO工作模式。
2.配置GPIO的方向寄存器 GPIO_GDIR,对应位设置为1,才是输出模式。
3.给GPIO_DR寄存器的对应位写入1。
那么我们就按照它的步骤来。继续查阅30章:IOMUXC.
可以看到,有两个寄存器和GPIO_IO03有关。说是说寄存器,其实这里的寄存器和ARM内核的R0,R1不一样;它们有地址,赋值的时候和普通的存储器一样操作即可。
通过以上截图可知,
寄存器名 地址
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 0x020E 0068
IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 0x020E 02F4
而要给什么样的值?
根据手册,IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = 0x05
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03的配置就比较麻烦,有很多含义位。干脆直接使用默认的。
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = 0x10B0 (复位后默认值),至于这个值是什么含义,可看手册说明。
再配置GPIO_GDIR寄存器。看这手册26章:GPIO,可知
寄存器名 地址
GPIO_GDIR 0x0209 C004
然后使用鼠标点击一下上图的蓝色的超文本链接,就跳转到了寄存器含义。很明显,我们要给GPIO1_IO03配置为输出模式,那就是让GPIO1_GDIR的第3位为1
最后一步,配置GPIO1_DR,即[0x0209C000] 的第3位决定了输出电平0还是1。
所以芯片本身的参考手册《IMX6UL参考手册》实在是一个好东西。咱不用四处找教程,因为它已经说的很清楚。如果对于英文原版不习惯的同学,建议打开翻译软件,硬着头皮看下去。看得多了,也就习惯了。
三,代码编写
根据以上的分析,我们会发现,在配置芯片的过程中,存在频繁的向存储器写入数据的过程。所以干脆写成函数,方便以后使用。
//函数set_mem_value:设置存储器值 R0:存储器地址 R1:值(32 bits)
set_mem_value:
PUSH {R0-R4,LR}
STR R1,[R0]
POP {R0-R4,PC}
再写一个简单的延时函数
//函数delay:延时
delay:
PUSH {R0-R4,LR}
LDR R0,=0xFFFFF
delay_loop:
CMP R0,#0
BEQ delay_return
SUB R0,#1
B delay_loop
delay_return:
NOP
POP {R0-R4,PC}
这样,整个软件实现的流程可以概述为:
1.配置IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03
2.配置IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03
3.配置GPIO_GDIR
4.配置GPIO1_DR,输出1,延时
5.配置GPIO1_DR,输出0,延时
6.回到步骤4
整体代码如下:
.global _start
_start:
//[0X020E0068] = 0x05 配置IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03
LDR R0,=0X020E0068
LDR R1,=0X05
BL set_mem_value
//[0X020E02F4] = 0X10B0 配置IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03
LDR R0,=0X020E02F4
LDR R1,=0X10B0
BL set_mem_value
//[0X0209C004] = 0X0000008 配置GPIO_GDIR
LDR R0,=0X0209C004
LDR R1,=0X0000008
BL set_mem_value
LDR R0,=0x0209c000
led_flash:
//LED 灭
ORR R1,R1,#0x08
BL set_mem_value
BL delay
//LED 亮
BIC R1,R1,#0X08
BL set_mem_value
BL delay
B led_flash
//函数set_mem_value:设置存储器值 R0:存储器地址 R1:值(32 bits)
set_mem_value:
PUSH {R0-R4,LR}
STR R1,[R0]
POP {R0-R4,PC}
//函数delay:延时
delay:
PUSH {R0-R4,LR}
LDR R0,=0xFFFFF
delay_loop:
CMP R0,#0
BEQ delay_return
SUB R0,#1
B delay_loop
delay_return:
NOP
POP {R0-R4,PC}
四,烧录代码
1.把代码放入一个文件,命名为code.s。
2.在Linux系统下进行编译,生成.imx文件,烧录到SD卡中。
3.把SD卡插在开发板的SD插槽中,并改拨码,使得芯片从SD卡启动。
五,运行效果
给开发板上电,可以看到LED在闪烁。见黄色方框标注。
当然,这样一张图,也看不出什么闪烁效果。将就吧,至少证明代码是确实运行过的。