Beagleboard裸机编程

30

我刚拿到了我的 BeagleBoard-Xm,想知道是否有详细的逐步教程来帮助我在硬件上运行非常简单的裸机软件?

我问这个问题是因为我想深入了解硬件架构的工作原理,从引导加载程序、链接器、中断、异常、MMU等方面了解一切。我认为最好的方法是让一个简单的 hello world 程序在没有操作系统的情况下在 BeagleBoard xm 上执行。没有什么高级的东西,只需启动板子并获得屏幕上的“hello world”输出即可!

下一步将是运行一个微小的操作系统,它可以调度一些非常简单的任务。不需要文件系统,只需了解操作系统的基础知识。

2个回答

44

完全没有问题...

首先,让串口运行起来。我有一块旧版的BeagleBoard,记得串口和I/O方面的一切都很麻烦,但是还是要在上面安装一个串口,这样你就可以看到它的启动过程。

它会启动uboot,你可以按下一个键或esc键之类的东西来中断正常的启动(进入Linux)。从uboot提示符开始,很容易加载你的第一个简单程序。

我手头上有一些BeagleBoard代码,但是没有我的BeagleBoard本身,所以请访问http://sam7stuff.blogspot.com/,了解如何混合一些启动汇编和C代码,用于无操作系统的嵌入式程序(针对arm,我还有其他thumb/cortex-m3平台的许多示例,但是它们的启动方式略有不同)。

Sam7端口和内存地址空间与BeagleBoard/OMAP完全不同。以上是一个框架,您可以更改或重新发明它。

您需要从ti.com获取OMAP 35x技术参考手册。在他们的网站上搜索omap部件OMAP3530。

还需要BeagleBoard文档。例如,此语句:

BeagleBoard提供单个RS232端口,可访问UART3的TX和RX线路。

因此,在omap的trm中搜索UART3会显示它位于0x49020000的基址处。(通常很难找出某些东西的完整地址,因为手册通常在这里有一部分内存映射,在那里有另一部分,并且在寄存器描述附近,只有地址的较低几位被指出。)

查看UART寄存器,THR_REG是你要写入的将要通过串口发送的字节,注意它是一个16位寄存器。

知道了这些,我们就可以编写第一个程序:

.globl _start
_start:
    ldr r0,=0x49020000
    mov r1,#0x55
    strh r1,[r0]
    strh r1,[r0]
    strh r1,[r0]
    strh r1,[r0]
    strh r1,[r0]
hang: b hang

这是一个针对它的makefile: ```makefile ```
ARMGNU = arm-none-linux-gnueabi

AOPS = --warn --fatal-warnings
COPS = -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding 

uarttest.bin : uarttest.s
    $(ARMGNU)-as $(AOPS) uarttest.s -o uarttest.o
    $(ARMGNU)-ld -T rammap uarttest.o -o uarttest.elf
    $(ARMGNU)-objdump -D uarttest.elf > uarttest.list
    $(ARMGNU)-objcopy uarttest.elf -O srec uarttest.srec
    $(ARMGNU)-objcopy uarttest.elf -O binary uarttest.bin

使用的链接脚本:

/* rammap */
MEMORY
{
    ram : ORIGIN = 0x80300000, LENGTH = 0x10000
}

SECTIONS
{
    .text : { *(.text*) } > ram
}

请注意,codesourcery的Linux版本被称为交叉编译器,但实际上,这段代码只需要汇编器和链接器(binutils工具)。arm-none-eabi-...类型的交叉编译器同样可以使用(假设您从codesourcery获取了精简版工具)。
一旦你有了一个.bin文件,请查看uboot的帮助文档,我不记得确切的命令,但它可能是“l 0x80300000”或“load_xmodem”之类的东西。基本上,你想通过串口将.bin文件传输到处理器的内存空间中,然后使用go或其他命令告诉uboot跳转到你的程序。
运行时,你应该会看到一些U字符(0x55是“U”)从串口输出。
你的主要目标是先建立一个简单的串口例程,以便你可以打印一些调试信息并查看程序正在执行什么操作。稍后你可以涉及到图形等内容,但首先要使用串口。
有些作弊行为。由于uboot启动并初始化了串口,我们不必自己再去初始化。只需将字节推入thr即可。但很快你就会溢出thr的存储并且丢失字节,所以你需要读取omap的trm,并找到一些指示发送器为空的位,它已经传输完毕,然后创建一个uart_send类型的函数,它轮询发送器是否为空,然后发送一个字节出去。
另外,请忘记printf(),你需要创建自己的打印数字(八进制或十六进制最容易),以及可能的打印字符串。我一整天都在做这样的工作,99% 的时间,我只使用一个小例程将32位十六进制数输出到串口。从这些数字中,我可以调试并查看程序的状态。
因此,采用sam7模型或类似模型(请注意编译器和链接器命令行选项的重要性,以及链接命令行上文件的顺序,第一个文件必须是入口点,如果您想让.bin文件的第一个指令/字成为入口点,那通常是个好主意,因为日后您需要知道如何控制这个过程以从ROM启动)。
你可以在不删除或替换uboot的情况下做很多事情,如果你开始查看基于Linux的uboot引导命令,你会发现它几乎是从闪存或其他地方复制了一个.bin文件到内存中的一个位置,然后跳转到它。现在跳转到Linux,特别是ARM Linux,涉及到一些ARM表和可能设置一些寄存器,而您的程序不需要这些。基本上,无论你想使用哪个命令,在将程序复制到RAM后,你都需要在uboot的启动脚本中编写它,如果你选择让板子像使用Linux一样启动和运行。
说可以使用jtag而不依赖于uboot工作,但是当你选择这条路时,需要在引导时完成一定数量的工作以使芯片运行起来,特别是配置uart可能需要一些时钟分频器、时钟使能、I/O使能等等。这就是为什么sam7示例从闪烁led开始而不是uart的原因。amotek jtag-tiny是一个很好的jtag wiggler,我一直很满意,在工作中每天都会用到它们。beagleboard可能使用TI引脚布局而不是标准的ARM引脚布局,因此您可能需要更改接线。我不知道OMAP是否会直接给您访问arm tap控制器的权限,还是需要进行一些ti特定的操作。暂时最好选择uboot路线。

一旦你有了一个框架,其中只有少量的汇编代码来设置堆栈并跳转到入口点C代码,你就可以开始将该C代码转换为操作系统或进行任何你想做的事情。如果您查看chibios、prex或其他类似的rtos,您会发现它们有小的asm引导代码,将它们带入系统。同样,其中包括调试和非调试的uart例程。许多rtos都要使用中断而不是轮询thr是否为空。

如果这篇文章不能让你成功运行hello world(让你做一些工作),请告诉我,我会找出我的beagleboard并创建一个完整的示例。虽然我的板子不完全符合你的需求,但对于hello world来说应该足够接近了。


哇,这太棒了!感谢您花时间帮助我,非常感激!一旦我完成论文,我就会开始深入研究并尝试让它工作!也许我应该购买一个Jtag来调试我的Beagleboard!再次感谢! - MrGigu
我终于找到时间玩这块板子并且让它工作了!现在我可以在控制台上输出一些文本 :) 还有一个人也使用了这篇文章作为他的裸机教程的参考,想让你知道!http://wiki.osdev.org/Beagleboard。再次感谢! - MrGigu
@dewlch,老兄,你在嵌入式系统领域可谓是无所不在啊。再次创造出了惊人的东西。现在如果我看到一个好的答案/文章,我都能猜到是你写的。 - deepak
1
@dwelch 确实如此。还有几个人回答了很棒的问题,但大多数时候我需要的答案或文章都是你写的。Github仓库也很棒!这可能是你第十二次帮助我了。再次感谢你提供这个惊人的答案。 - deepak
我对多核编程有一个普遍的疑问。根据我的理解,双核 ARM CPU 有两个程序计数器。在这种情况下,使用汇编语言如何访问这两个程序计数器? - robomon

4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接