Привет, мир, бигльборд на голом металле

Я пытаюсь запустить программу типа «hello world» на моем Beagleboard-xm rev. C, вызвав функцию C puts из сборки.

До сих пор я использовал это как ссылку: http://wiki.osdev.org/ARM_Beagleboard

Вот что у меня есть до сих пор, но нет выхода.

привет.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 = .;

}

Создать файл

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 отключен.


person farnsworth    schedule 04.02.2012    source источник


Ответы (3)


это должно было сработать для вас. Вот какой-то код, который я выкопал в далеком прошлом, не пробовал сегодня вечером на биглборде, просто убедился, что он скомпилирован, когда-то он работал...

запуск.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

Привет :

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 или что-то еще) в оперативную память платы? Если вы не можете этого сделать, возможно, вы неправильно подключены к последовательному порту. последовательный порт бигльборда неисправен, возможно, вам придется сделать свой собственный кабель.

person old_timer    schedule 05.02.2012
comment
Это работает, спасибо. Теперь мне нужно понять, что я делаю не так. Это первый фрагмент кода != ASM, который действительно что-то печатает. - person farnsworth; 05.02.2012
comment
Для дальнейшего справки, если у кого-то возникли проблемы с этим. Я изменил Makefile CROSS_COMPILE = arm-none-linux-gnueabi, так как использую цепочку инструментов исходного кода для Linux. Загрузил файл с помощью loady через ymodem, и, хотя у de memmap его источник находится на 0x82000000, я пошел в ногу со временем и запустил его с помощью go 0x80200000, хотя вы установили источник на 0x82000000. - person farnsworth; 05.02.2012
comment
как arm-none-linux-gnueabi, так и arm-none-eabi взяты из кода, если вы не делаете никаких системных вызовов, то любой из них будет работать. Предположительно, версия, отличная от Linux, лучше, если вы используете вызовы gcclib (используйте деление или по модулю или что-то в этом роде). - person old_timer; 05.02.2012
comment
не подразумевает arm-none-linux-gnueabi, может быть только из исходного кода (теперь менторская графика). вы, безусловно, можете сами собрать любую из упомянутых целей из исходников gnu, и приведенный выше код будет работать. - person old_timer; 05.02.2012
comment
интересно я ошибся адресом? что, если вы измените сценарий компоновщика, чтобы использовать тот же адрес, что и тот, который вы фактически используете? Я предполагаю, что код случайно не зависит от позиции, будучи такой маленькой простой программой, что вполне может иметь место. - person old_timer; 05.02.2012
comment
работает в любом случае. Теперь странно то, что я могу печатать отдельные символы, например, с помощью uart_send('c'), но не могу печатать строки print_string(char *str){ while (*str != '\0') uart_send (*str++); } print_string(Тест); . Есть мысли по этому поводу? - person farnsworth; 06.02.2012
comment
разобрать и проверить, куда он поместил строку, .data или .text. Если .data, вам нужно использовать скрипт компоновщика, который помещает его в .text с использованием адреса .data, а затем загрузочный код, который копирует его из .text в .data. или объявите строку const, чтобы переместить ее в .text и не связываться с .data. - person old_timer; 06.02.2012
comment
Я переместил родаты в текст и использовал const char *s=Test; print_string(s); Тот же результат, ничего. - person farnsworth; 06.02.2012
comment
если вы не добавите его принудительно в сценарий компоновщика, вы должны поместить файлы в командную строку в желаемом порядке. поставив сначала hello.o, вы установите, что по адресу 0x8020000 у вас должен быть boot.o, а затем hello.o. Смотри разборку. - person old_timer; 06.02.2012
comment
когда я его построил, я начал с 0x80200050, если вы изучите файл списка, вы можете попробовать запустить программу с 0x80200xxx вместо 0x80200000 - person old_timer; 06.02.2012
comment
вам также необходимо опросить статус передатчика полный/пустой, вы не можете просто втиснуть байты в регистр передатчика (в общем случае), вам может это сойти с рук, если есть fifo, но не полагайтесь на это. - person old_timer; 06.02.2012
comment
Я перепутал начальный адрес, извините за беспокойство и спасибо за ваше время. - person farnsworth; 06.02.2012
comment
Не проблема, голый металл, вещи низкого уровня, это потерянное искусство, и я заинтересован в том, чтобы сохранить его живым. спасибо, что не отказались от этого, и я надеюсь, что вы продолжите понимать и учиться на этом уровне. Я сама каждый день учусь... - person old_timer; 06.02.2012

Вы не можете просто слепо записать строку символов в UART — вам нужно проверять статус каждого символа — это работает в примере с одним символом, потому что UART всегда будет готов для первого символа, но для второго и второго. последующие символы вам нужно опросить (или еще лучше использовать ISR, но давайте пройдемся, прежде чем мы побежим).

Здесь есть хороший пример кода: http://hardwarefreak.wordpress.com/2011/08/30/some-experience-with-the-beagleboard-xm-part-2/

person Paul R    schedule 04.02.2012
comment
Посмотрите ЛЭ. Я также попытался напечатать только один символ, и я не получил никакого вывода, хорошая статья проверит, решит ли она проблему, хотя мне бы очень хотелось знать, что я делаю неправильно и где. - person farnsworth; 04.02.2012
comment
Может быть, попробуйте запустить код из ссылки, которую я дал выше, и посмотреть, работает ли это? Если это работает, вы можете сравнить со своим кодом и посмотреть, что отличается? - person Paul R; 04.02.2012
comment
Убедитесь, что вы отключили аппаратное управление потоком - person Paul R; 04.02.2012
comment
это не так, я сказал это в более позднем редактировании, последняя строка. Я повторно запустил пример сборки, и он работает, при вызове C это не так. - person farnsworth; 04.02.2012
comment
Есть ли способ узнать, действительно ли ваш код C работает, например. включить или выключить светодиод или что-то в этом роде? - person Paul R; 04.02.2012

Мне не хватает повторений, чтобы комментировать. Но мой ответ на

Работает в любом случае. Теперь странно то, что я могу печатать отдельные символы, например, с помощью uart_send('c'), но не могу печатать строки print_string(char *str){ while (*str != '\0') uart_send (*str++); } print_string("Тест"); . Есть мысли по этому поводу?

is:

Вы быстрее пишете в выходной буфер, так как UART может отправлять. Таким образом, вы должны проверить, не пуст ли выходной буфер, прежде чем отправлять новый символ.

Я сделал это в коде в своем блоге (http://hardwarefreak.wordpress.com/2011/08/30/some-experience-with-the-beagleboard-xm-part-2/)

person Hardwarefreak    schedule 06.02.2012
comment
Я делаю это :), я также переместил родаты в .text, но на экране ничего не отображается, за исключением случаев, когда я делаю print_char('c'); - person farnsworth; 06.02.2012
comment
Ммм.. Прерывания включены? Могу ли я увидеть ваш код и сравнить с моим? - person Hardwarefreak; 06.02.2012
comment
извините, я перепутал начальный адрес, спасибо за ваше время и отличный пример :) - person farnsworth; 06.02.2012