本帖最后由 吹口琴的钢铁侠 于 2017-9-21 10:02 编辑
OK01这个教程会从零开始尝试把树莓派的RCA和USB口附近的那个’ACT’LED点亮,并搭建好环境为接下来的教程做好铺垫。
准备 在实际动手之前,需要你先看完前一篇教程,并下载安装了必要的GUN工具链以及代码的模版文件OS Template。
文件结构在模版文件夹里面你会看到这样的文件目录:
build/ (empty)
source/
main.s
kernel.ld
LICENSE
Makefile
找个编辑器打开main.s文件,我们就可以开始写汇编代码了,树莓派使用的汇编是ARMv6,我们要写的汇编也就是ARMv6。 把下面这些代码复制粘贴进去:[mw_shl_code=asm,true].section .init
.globl _start
_start:[/mw_shl_code]
这些代码对树莓派没有直接的作用,它们是写给汇编器看的,汇编器是一个把我们将要写的汇编代码转换成树莓派能直接运行的机器码的程序。在汇编代码中,每一行都是一条新的命令,这里的第一行告诉汇编器和链接器把我们的代码放到哪里去,.init这里的代码会和模版文件组合,最终被放到输出代码的最前面。这一点很重要,因为我们要保证哪部分代码首先运行,如果我们不这么做的话,代码会按照字母表的顺序运行。
.section命令只是告诉了汇编器从这一点到下一个.seciton是代码的链接后的位置,而后面的两行告诉了工具链程序的入口。
第一行代码把下面的代码拷贝粘贴进去 [mw_shl_code=asm,true]ldr r0,=0x20200000[/mw_shl_code]
在汇编代码中,计算机会简单的从上往下运行代码,每一行都是一个指令,除非遇到某些指令发生跳转。 这第一行代码告诉处理器,把0x20200000这个数字存储到r0这个寄存器里面,0x20200000显然是个十六进制的数字,那么什么是寄存器? 寄存器是处理器内部的一些用来存数据的小部件,可以理解成一个个的抽屉,有些寄存器会有一些特定的功能,在树莓派上有13个通用寄存器,每一个可以存储一个32比特的数字(从0到4,294,967,295 ),从r0一直到r12,对于这13个寄存器,做任何操作和运算都没关系,在这一行代码中,换成其他寄存器也没关系。 这行代码把0x20200000存到r0,是为了接下来的控制GPIO,而GPIO控制器的位置恰好就是0x20200000,这一点可以通过参考中的数据手册来查到。
指令
[mw_shl_code=asm,true]ldr reg,=val
[/mw_shl_code]把val存到对应的寄存器中
设置GPIO的输出模式
[mw_shl_code=asm,true]mov r1,#1
lsl r1,#18
str r1,[r0,#4][/mw_shl_code]
要让这个ACT LED亮起来,首先和Arduino类似的要先设置这个引脚端口为输出模式,然后再让它输出高电平。
上面的代码就能让ACTLED这个GPIO16设置为输出模式,首先我们把1存到r1,然后通过lsl指令,得到二进制的1000000000000000000,其实也可以直接把这个数存到r1,但是为了后面的操作和代码,这样写更有意义。
在GPIO控制器中,有24个字节用来设置GPIO,前4个对应前10个GPIO,第二个4个对应第二个10个,总共有54个GPIO,所以我们需要6x4总共24个字节。
在4个一组里面,每三个比特对应一个GPIO,我们操作的是16号GPIO,所以我们需要操作第二个4字节中第六个3比特,也就是上面代码中18的由来。
其中的str指令,会把r1中的值,写到地址为r0的值加上4偏移的位置
指令[mw_shl_code=asm,true]mov reg, #val [/mw_shl_code]
把val存到对应的reg寄存器 mov指令比ldr快,因为mov不牵涉到内存,而ldr是从内存把数存到寄存器,但是mov只能对某些数字做操作
[mw_shl_code=asm,true]lsl reg, #val reg[/mw_shl_code]
寄存器的值逻辑左移val位
[mw_shl_code=asm,true]str reg, [dest, #val] [/mw_shl_code]
把reg寄存器重的值写到地址为dest寄存器的值+val
输出高电平
[mw_shl_code=asm,true]mov r1,#1
lsl r1,#16
str r1,[r0,#40][/mw_shl_code]
现在GPIO已经准备好被点亮了,这意味着我们要让GPIO16输出低电平,没错是低电平,板子本身设计就是这样。
上面的指令都已经见过了,为了让GPIO16输出低电平,我们得让一个第十六位是1的数写到偏移GPIO控制器40的地址位置,这样就能输出低电平了。
死循环需要的代码都写完了,应该结束了,但是假如就那样的话,只要有供电,处理器就会持续工作,如果不给他其他的任务,树莓派就会崩溃。[mw_shl_code=asm,true]loop$:
b loop$[/mw_shl_code]
这里的第一行不是一个命令,是一个标签,或者说名字,这意味着我们可以通过loop$这个名字来找到这一行代码,代码编译完成之后标签都没有意义了会变成地址,对于写代码的我们则是又很重大的意义,b指令的作用是下一条执行的指令跳转到后面的标签所指代的代码块,在这里就会导致树莓派一直循环直到断电。 另外GNU工具链要求代码的最后有一个空行。
编译和运行编译非常简单,用终端进入到代码的根目录,也就是Makefile的同级目录中,运行make,没什么问题的话,就会生成一个kernel.img的文件。 安装这个系统代码之前,首先需要一个已经装好了常规的Raspbian系统的树莓派SD卡,在SD卡的目录中很容易就能找到一个kernel.img的文件,把它替换成刚刚生成的新文件,然后插上电源,就能看到这个ACTLED亮起来了。
参考
|