你好世界,裸机Beagleboard。

10
我正在尝试在我的Beagleboard-xm rev. C上调用C语言puts函数来运行一个“hello world”类型的程序。以下是参考资料:http://wiki.osdev.org/ARM_Beagleboard。目前为止,我已经有了下面这些代码,但是没有输出结果。 hello.c
volatile unsigned int * const UART3DR = (unsigned int *)0x49020000;

void puts(const char *s) {
  while(*s != '\0') { 
    *UART3DR = (unsigned int)(*s); 
    s++; 
  }
}

void hello() {
  puts("Hello, Beagleboard!\n");
}

boot.asm

.global start
start:
   ldr sp, =stack_bottom
   bl hello
   b .

linker.ld

ENTRY(start)

MEMORY
{
    ram : ORIGIN = 0x80200000, LENGTH = 0x10000
}

SECTIONS
{
    .hello : { hello.o(.text) } > ram
    .text : { *(.text) } > ram
    .data : { *(.data) } > ram
    .bss : { *(.bss) } > ram
     . = . + 0x5000; /* 4kB of stack memory */
    stack_bottom = .;

}

Makefile

ARMGNU = arm-linux-gnueabi

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

boot.bin: boot.asm
   $(ARMGNU)-as boot.asm -o boot.o
   $(ARMGNU)-gcc-4.6 -c $(COPS) hello.c -o hello.o
   $(ARMGNU)-ld -T linker.ld hello.o boot.o -o boot.elf
   $(ARMGNU)-objdump -D boot.elf > boot.list
   $(ARMGNU)-objcopy boot.elf -O srec boot.srec
   $(ARMGNU)-objcopy boot.elf -O binary boot.bin

仅使用这样的asm文件是有效的。

.equ UART3.BASE,        0x49020000
start:
   ldr r0,=UART3.BASE
   mov r1,#'c'

这里有一些关于Beagleboard/minicom相关的信息:http://paste.ubuntu.com/829072/
有什么指导吗?:)
我也尝试过
void hello() {
  *UART3DR = 'c';
}

我正在使用minicom,并通过ymodem发送文件,然后尝试使用以下命令运行它:

go 0x80200000

Minicom 中的硬件和软件控制流被关闭。

3个回答

3

你应该可以使用这个方法。以下是我从很久以前挖掘出来的一些代码,我没有在Beagleboard上尝试它,只是确保编译它,它曾经起过作用......

startup.s:

    .code 32

.globl _start
_start:

    bl main
hang: b hang

.globl PUT32
PUT32:
    str r1,[r0]
    bx lr

.globl GET32
GET32:
    ldr r0,[r0]
    bx lr

hello.c :

extern void PUT32 ( unsigned int, unsigned int );
extern unsigned int GET32 ( unsigned int );
void uart_send ( unsigned char x )
{
    while((GET32(0x49020014)&0x20)==0x00) continue;
    PUT32(0x49020000,x);
}
void hexstring ( unsigned int d )
{
    //unsigned int ra;
    unsigned int rb;
    unsigned int rc;

    rb=32;
    while(1)
    {
        rb-=4;
        rc=(d>>rb)&0xF;
        if(rc>9) rc+=0x37; else rc+=0x30;
        uart_send(rc);
        if(rb==0) break;
    }
    uart_send(0x0D);
    uart_send(0x0A);
}
int main ( void )
{
    hexstring(0x12345678);
    return(0);
}

memmap(链接脚本):


MEMORY
{
    ram : ORIGIN = 0x82000000, LENGTH = 256K
}

SECTIONS
{
    ROM : { startup.o } > ram
}

Makefile :

CROSS_COMPILE = arm-none-eabi

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

all : hello.bin

hello.bin : startup.o hello.o memmap
    $(CROSS_COMPILE)-ld startup.o hello.o -T memmap -o hello.elf  
    $(CROSS_COMPILE)-objdump -D hello.elf > hello.list
    $(CROSS_COMPILE)-objcopy hello.elf -O binary hello.bin

startup.o : startup.s
    $(CROSS_COMPILE)-as $(AOPS) startup.s -o startup.o

hello.o : hello.c 
    $(CROSS_COMPILE)-gcc -c $(COPS) hello.c -o hello.o

clean :
    rm -f *.o
    rm -f *.elf
    rm -f *.bin
    rm -f *.list

看起来我把堆栈指针留在了引导加载程序的位置。同样,你也认为引导加载程序已经初始化了串口。

我假设你已经使串口访问正常工作,你可以看到uboot并且能够输入命令以便将这个程序(xmodem或其他)下载到开发板的内存中?如果你不能做到这一点,那么可能是你没有正确连接串口。BeagleBoard的串口有些问题,可能需要自己制作电缆。


如果有人遇到问题,可以参考以下内容。我修改了Makefile CROSS_COMPILE = arm-none-linux-gnueabi,因为我正在使用适用于Linux的CodeSourcery工具链。通过ymodem加载文件,虽然de memmap的起始地址为0x82000000,但我仍然使用go 0x80200000运行它,即使您将其原点设置为0x82000000。 - farnsworth
both arm-none-linux-gnueabi and arm-none-eabi are from codesourcery, if you dont make any system calls then either will work. Supposedly the non-linux version is better if you use gcclib calls (use divide or modulo or things like that).两者都来自Codesourcery,如果您不进行任何系统调用,则两者都可以使用。据说非Linux版本在使用gcclib调用(如除法或模数等)时更好。 - old_timer
不要理解为arm-none-linux-gnueabi,只能使用code sourcery(现在是mentor graphics)提供的。你肯定可以从gnu源代码构建任何一个目标,然后上述代码就可以正常工作。 - old_timer
有趣,我地址错了吗?如果你改变链接脚本使用与实际使用的相同地址会怎样?我的猜测是代码意外地是位置无关的,因为这是一个非常简单的小程序,很可能是这种情况。 - old_timer
2
没问题,裸机编程、底层开发这些东西已经成为一门失传的艺术,我对保持它的活力很感兴趣。谢谢你不放弃这个领域,希望你能继续理解和学习这个层次的知识。我自己也在每天学习中成长。 - old_timer
显示剩余8条评论

2

请检查LE。我也尝试打印一个字符,但没有得到任何输出,很好的文章会检查是否解决问题,但我真的很想知道我错在哪里。 - farnsworth
也许尝试运行我上面给出的链接中的代码,看看是否有效?如果有效,那么您可以将其与您的代码进行比较,看看有什么不同? - Paul R
请确保关闭硬件流控制。 - Paul R
我在后面的编辑中说过,它已经关闭了。我重新运行了汇编示例,它可以工作,但调用C时却不行。 - farnsworth
有没有办法可以确定你的 C 代码实际上正在运行,例如打开或关闭 LED 等? - Paul R

2

我还没有足够的声望来评论..但是对于

两种方式都可以工作。现在奇怪的是,我可以使用 uart_send('c') 打印单个字符,但无法打印字符串 print_string(char *str){ while (*str != '\0') uart_send(*str++); } print_string("Test"); 。你有什么想法吗?

我的回答是:

当 UART 能够发送时,您可以更快地将字符写入输出缓冲区。因此,在发送新字符之前,您必须检查输出缓冲区是否为空。

我已经在我的博客代码中实现了这一点 (http://hardwarefreak.wordpress.com/2011/08/30/some-experience-with-the-beagleboard-xm-part-2/)


我正在做这件事 :), 我也将rodata移动到.text,但屏幕上除非我执行print_char('c'),否则什么都没有显示。 - farnsworth
Mmh.. 中断是否已启用? 能否让我看看你的代码并与我的进行比较? - Philipp
抱歉,我搞错了起始地址,感谢您的时间和出色的示例 :) - farnsworth

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