树莓派教程:Pi 的操作系统开发(2)


1OK01



OK01课程包含如何开始编程,教你如何去使能OK’这个led灯,这个灯在pi板子的靠近RCA(黄色端口)和USB端口之间的位置我做了实验后,发现这个灯就是PWR上面的那个ACT灯。


本课内容lesson1

  • 1开始准备

  • 2开始

  • 3第一行真正的代码

  • 4使能输出

  • 5 A Sign Of Life(点亮你的led,表明开发板有动起来的迹象)

  • 6 Happily Ever After(皆大欢喜)

  • 7 Pi Time(到了pi的时间了)

1开始前的准备

        我假设你已经到下载页面,下载了编译代码的gnu工具链。同时你也下载了一个OS的模板。

请下载这个模板然后解压到一个新的文件目录。接上次课,我们已经建立了一个raspberry的目录,所以下面的工作都是在这个raspberry目录下完成的。还有为了方便,我把gnu的工具链,操作系统镜像,os的模板,还有教程,都放在我的百度云盘了。大家可以到那下载。

当然你需要的硬件:raspberrypi的板子,sd卡,给pi供电的电源。

帐号:397916230qq.com

密码: 397916230

当然翻译这教程,我也是边学,翻译的。些内容也很简单,本来是不想翻译的,但是为了给初学者一个引导作用,我还是翻译了。希望为中国的编程教学,贡献出自己的一份力量。

不多说了,继续。

2开始

       现在你解压出了ostempate的模板,解压的命令也很简单:tar xvf template.tar.gz,然后我们在template目录下新建一个source目录,在souce目录下新建一个文件man.s,在这个文件中我们编写操作系统的代码。打开这个mani.s文件,看个人喜好,我用的是nano,

       树莓派用的汇编是ARMv6的的版本,因为树莓派上的cpu的指令架构是ARMv6的。所以我们需要写的代码如下:

.section .init
.globl   _start
_start:

      事实上,上面的代码什么也没有做。上面的指令都是给assembler(汇编器)看的,是我们编程时辅助用的。assembler(汇编器)的作用就是把汇编代码(人类可以理解的)翻译成二进制码(cpu可以理解的)。在汇编代码串,每一行是一个命令。在上面的代码中,第一行告诉assembler(汇编器),我们的代码放在哪里。在我提供的template中,.init段的代码是放在最开始的位置。这对于我们确保在开始时就运行自己的代码,非常重要。如果你不这样做,cpu在开始时就会运行其它的代码。.section命令只是简单的告诉编译器,我们的代码是放在哪一段了,从这一点开始,到下一个.section,之间的代码,都会入在这个section中。在汇编代码中,我们可能会为了增强代码的可读性加入一些空格和空行。

对上面的过程整理下:

1:解压template

tar xvf template.tar.gz
2 :进行telmpatle目录,新建source目录
cd  template/

mkdir source
3: 进入source目录,新建main.s文件
cd source

nano main.s
4: main.s中输入下面的代码
.section .init
.globl  _start
_start:

ldr r0,=0x20200000

mov r1,#1
lsl  r1,#18
str r1,[r0,#4]

mov r1,#1
lsl  r1,#16
str r1,[r0,#40]

loop$:
b  loop$

5 :保存main.s文件后退出ctr+x ;然后选择y后,回车。

6:回到template目录下,输入make,即可得到kernel.img的文件,这就是我们后面要得到的程序,

译者补充:我把下面几步的代码都贴到这里了,后面再讲解;。

译者补充:对于这些.section部分的起名,还有如何将这些断放到具体的位置,这些知识是与makefile,链接文件有关的。目前可以不用看这些东西,有兴趣的可以先看下template目录下kernel.ld文件。我们会看到.init这段代码放到了最前面。以后我再作为一个部分讲讲这些内容。

译者补充:.S(大写的S)是汇编文件的后缀,大写的汇编文件中,可以用#define这样的宏,而.s(小写的)这样的汇编文件中,不能用宏


3第一行真正的代码

现在我们真正的来编写代码了。在汇编代码中,cpu只是简单的取得这些代码,然后按顺序执行一条一条的代码,当然你的代码中有跳转的话,也会跳到别的地方去。每一条指令占一行。下面这行代码的做了什么?

ldr r0,=0x20200000

ldr reg,=val把val这个值放到寄存器中


  这是我们的第一条命令。他告诉cpu把这个数0x20200000保存到r0寄存器中。这里我要回答两个问题:什么是寄存器,0x20200000个什么数。

在树莓派用到的cpu中,一个寄存器,可以保存04,294,967,295范围的整数。这个数看起来很大,这是一个32位的寄存器可以保存的数。寄存器是一个很小的存储单元,注意它是在cpu内部。cpu用它来存储数据,并对这些数据进行操作。像r0这样的通过寄存器有很多,如r0r1213个都是通过的寄存器。我们可以用它们做我们需要做的计算。在这个例子中,我们用到了r0。但是只要你喜欢,你也可以用它们中的任何一个,这不是重点。0x20200000就是一个真实的数,但是它是以16进制的形式表示的。关于原文中10进制16进制的数转化的内容我就不翻译了,有问题再留言问吧。

       现在我们知道这一行代码是令r0=0x20200000,但是为什么要这样做呢?因为在电脑中,会有大量的memorydevices。为了能使用他们,控制他们。我们要给他们每人一个地址。和邮编类似。说白了,我们通过这些地址找到这些memory或是devices。地址在电脑中就是数字。在这里0x20200000这个数字正好是GPIO控制器的地址。这只是设计cpu的厂家在设计时决定的。(当然在设计cpu时也可以用其它的地址,只要与其它的设备不冲突)

我知道这个地址,只是因为我看了官方提供的手册而已(译者:手册我已经上传到百度云soc-peripherals,对于这些系统的地址没有什么特别的,都是一些非常大的16进制的数。

4使输出

A diagram showing key parts of the GPIO controller.

一些汇编的指令:

movreg,#val把数字val放到reg寄存器中。

lslreg,#valreg寄存器中的数按二进制的方式左移val

strreg,[dest,#val]reg寄存器中的数据保存到cpu外面存储器中,存储器的地址为dest中的数+ val.

通过读上面的手册,我知道我们需要发送两个messagesGPIO控制器。我们需要说GPIO控制器能听的懂的语言,如果我们这样做了,GPIO控制器就会按我们说的那样点亮那个OKled.幸运的是,这是个非常简单的芯片,我们只需要发送一些数字,GPIO控制器就会理解我们想做什么。

mov r1,#1
lsl r1,#18
str r1,[r0,#4]

这些指令使能了GPIO的第16个引脚。首先我们得到需要的数保存在r1中,然后把r1中保存的这个数发送到GPIO控制器中。前面的两条指令就是把我们想要的值保存到r1中,我们也可以像先前那样,用一条ldr指令就完成操作。但是这两条指令对我们后来设置任意GPIO的使能有很大的帮助。所以我们用来两条指令来完成这个操作,而不是一条直接赋值的操作。

OKLED通过导线与GPIO的第16个引脚相连,所以我们需要指令全能第16个引脚。r1中的值,就是用来使能LED引脚的。

       第一条指令把1放到r1寄存器中,mov指令要比ldr指令更快,因为mov指令不涉及对外部的memory的操作。但是ldr指令是加载到寄存器中的值通常是保存在外部memory中的。但是,mov指令只能传送小范围的数到寄存器中。在ARM的汇编代码中,几乎所有的指令都是以三个字母开始的。这样做是为了增强记忆,同是告诉你这个指令是做什么的。mov指令是move的简写,而ldr指令是loadregister的简写。mov指令把第二个数送到r1寄存器中。通常在mov指令中,第二个数要以#开头,表明这是一个数。

       第二条指令中的lsl指令是logicalshif left。它的意思是以二进制的形式把第一个数,逻辑左移多少位,(多少位通过第二个参数表示)。在这个例子中把r1中的12左移了18位就变成了10000000000000000002,(译者注:官方有对二进制进行解释,我就不翻译了,不懂的留言)

       再次强调:我只是通过阅读了官方的cpu手册,才知道用什么值操作哪个地址的。手册上说一个GPIO控制器有24字节,这24字节决定了GPIO引脚的设置。前4个字节决定前10GPIO引脚的位置。第二个4个字节决定了接下来的10GPIO引脚的设置,如些下去。cpu上有54GPIO引脚。所以需要6x4字节的GPIO控制器来控制这54个引脚,4个字节中的每3位与1个特定的GPIO引脚有关。因此我们想要控制第16GPIO引脚,我们需要控制第二个有4个字节的寄存器,在这4个字节的寄存器中,我们操作pins1019,q我们需要操作的是pin16,所以在这组寄存器中操作的是第6个三位的数据,在寄存器中的位置就是

6x3=18位。可以看到上面的代码中对我们把1移到了bit18。最后我们用str指令(storeregister)把把r1寄存器中的值保存到了GPIO的第二对控制器中,对于最后一条指令中

是反r0的值加上#4,然后把这个和作为地址。把r1的值保存到这个地址中。这里我们把第1message送到了GPIO控制器中,告诉控制器把第16引脚配置成输出状态。




5 点亮你的raspberrypi

       现在LED已经准备点亮了,我们需要真的点亮他。这意味这我们要给GPIO的控制器发送第2message,把16引脚关掉。没错,是关掉。cpu设计厂家就是这样设计的,你要点亮你的LED,你就是关闭pin。硬件设计工程师也决定了这样的操作才能点亮led.

没有想像中的复杂,就是把0x20200028GPIO控制器中的第16位置1,就可以点亮led了。下面的操作就是做这样的事

mov r1,#1
lsl r1,#16
str r1,[r0,#40]

        希望你能看明白上面的三条代码,因为和之前看到的代码没有多大不同。因为我们想让bit161,点亮led。第16引脚是off的,说明输出低电平,led点亮。

6 皆大欢喜

现在工作就完成了,但是cpu停止,他会一直运行下去,只要他有供电源,他就会一直工作。因此,我们需要给他一个任务做,给他一个死循环的任务去做。下面任务没有任何意思,只是没有这个任务,cpu会跑飞。

loop$:
b loop$

我们称loop$:是一个label,label代表下面代码的地址。

blabel就是跳转到label地址处。

label只是代表下面这行代码的地址,当编译成了机器码后,这个label就没有了,但是我们写程序是时候,这个label可以让我们知道,我们想跳转到哪个地址去。上面这条指令把cpu

stuck住,做一个没用的死循环,直到你安全地关闭电源。

在最后一行最好留一空行,编译器知道你的代码写完了,要不然会产生一个warn,当然不写也没有多大问题。只是一个好习惯。

7 Pi Time(到了pi的时 间 了 )

我们代码现在写完了,现在开始生成二进制的机器码。保存main.s,后到template目录下,

输入:make后,得到机器码kernel.img。下面是如何把这里生成的kernel.img文件。放到sd卡中。然后点亮led.

ubuntu12.10平台下:

如果你的sdcard已经有原来的能在树莓派上跑的os下面就不用看了,直接插上sd到电脑,把sd中的kernel.img改个名字,再把刚才生成的kernel.img放到sd卡中,然后sd卡插到树莓派就可以看到OKLED亮起来了。

1:先看一下你的硬盘分区是如何:

df  -h
2: 插入你的sd卡到电脑,再看下你的sd卡叫什么:
df  -h
3: 对比1操作和2操作,会看到你的sd卡在/dev/下面的什么名字

4:把sdumount掉,后在sd卡上写入操作系统镜像(系统镜像在百度云盘中有),命令如下:(后面的of=/dev/mmcblk0是你的sd的名字)

unzip2013-02-09-wheezy-raspbian.zip

sudodd bs=2M if=2013-02-09-wheezy-raspbian.img of=/dev/mmcblk0

5:写完后同步一下:

sudo sync

6:拔掉sd卡重新插入电脑,把sd中的kernel.img改个名字,再把刚才我们在template目录下生成的kernel.img复制到到sd卡中,然后sd卡插到树莓派就可以看到OKLED亮起来了。(就是ACT


下一课lesson2:OK02,我们将让LED闪起来。

http://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok02.html#waiting





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值