ARM Beagleboard

From OSDev.wiki
Revision as of 15:33, 30 September 2011 by osdev>Doublebeta
Jump to navigation Jump to search

There's also a tutorial [made by someone else] about barebones dev on the Nintendo Gameboy Advance, but I can't find it. FIXME: Add link to that :X.

This is the first wiki page I've ever written. The wiki seems to have eaten and neglected my code tags. So I used 'source lang="asm"' for everything... it works, but.. FIXME. ;).

TODO: VERIFY THE TUTORIAL(S)!!!

Intro

This is a tutorial on bare-metal [OS] development on the Texas Instruments Beagleboard. This tutorial is written specifically for the Beagleboard-xM Rev C because the author has no other hardware to test on.

Experience in Linux/nix (_very_ important) and at least one assembly language (_incredibly_ important, or at least extensive C knowledge) is assumed and required. Please make sure you can figure out how to get a basic x86 OS (no copypaste!) to the booting stage before attempting this guide. No need to make much more than a 'Hello World', since what you know about x86 won't really apply here.

Materials

You will need a:

  • Beagleboard-xM Rev C, or perhaps an older board, with a serial port.
  • An RS-232 serial port. This is the kind of serial port on the back of your x86 PC, and on the Beagleboard-xM. using TTL (5v) or lower voltage serial will damage something.
  • A serial cable that comes to DB-9 Male on at least one side (to connect to the Beagleboard)
  • Debian, or other *nix with arm-binutils [guide will document installation for Debian]
  • Power supply for your Beagleboard (5v, at least 1A but I recommend/use 3A)
  • A copy of the ARM ARM (ARM Architecture Reference Manual) (download a PDF, make sure it's the new one, with ARMv7 stuff)
  • A copy of the OMAP35x/DM37x TRM (Technical Reference Manual) <-- ^ THESE ARE INCREDIBLY IMPORTANT!
  • Optional: Various peripherals for the Beagleboard. Be aware that _you_ will need to write drivers for them. Welcome to OS Development ^_^.

Getting Started

Testing your serial port

First things first, you're going to want to make sure all your hardware works. Set up your serial port, however yours works, and open up minicom. Make sure you have flow control turned off. Now jumper PIN 2 (RX) to PIN 3 (TX) on the DB-9 side. Just type some characters into minicom, and they should be echoed back. Ensure you can run at 115200 baud, 8N1, which is what you will use to connect to the Beagleboard.

If you get 'Permission Denied' do NOT become root! This is unnecessary. Instead do:

sudo adduser <user> dialout

This will let your user use serial ports without needing root.

Testing the Beagleboard

Follow the guide here http://elinux.org/BeagleBoardDebian#Debian_armhf_port to install the Debian armhf image to a microSD card. We don't really need to boot Debian from it, but it's a nice simple ghetto/lazy way to get u-boot set up and working.

Connect the Beagleboard up via serial, and make sure minicom is running (on your PC). Put the microSD card in the Beagleboard. Connect the Beagleboard to its power supply. You should see some output on the serial port. If not, google around to figure out why not. If a few bytes of garbage appear in Minicom only, make sure the MicroSD card is inserted and VALID. Also make sure you didn't press the 'user button'.

You should get some meaningful output. Unplug your Beagleboard when you are done with it.

Getting an assembler

We will be using ARM development tools from the Emdebian project.

Append:

deb http://www.emdebian.org/debian/ squeeze main

to your /etc/apt/sources.list, changing 'squeeze' for your version of Debian - I'm running wheezy, for example.

now run:

sudo aptitude update
sudo aptitude install gcc4.4-arm-linux-gneabi # check this! it might be an older version for non-wheezy...

That will install a C compiler, and also install binutils, which for this tutorial is really all we need, but you may later wish to write your code in C, since writing it all in ASM is apparently frowned upon (;)).

Writing some CODE!

Now that we have all the crap we need, let's get to writing some code. Before we write an ASM source file, we should make a linker script and a Makefile.

Linker Script

We'll basically take the one from the stackoverflow.com link, No.1 in the ref list, with one change. The linker script there uses 0x80300000 as the start address. This will work just fine, however the default load address of u-boot's 'loady' command loads things into 0x80200000. So there's one less thing we have to specify ^_^.

linker.ld

Take note of what it does. It's pretty simple. Refer to docs if necessary.

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

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

Makefile

This is the basic makefile I use. It's similar to the one on the stackoverflow link. Spot the difference.

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)-ld -T linker.ld 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

Assembly!

YAY! We can write some code now! ARM Assembly is a VERY beautiful and powerful language, and should not be feared. There are indeed reasons NOT to use assembly, namely that it is nonportable and hard to maintain. However, I personally wouldn't want to miss out on playing with this beautiful architecture.

Afterall, arguably the best OS developer here, Solar, wrote his operating system, Solar_OS [1] is written fully in Assembly, so why can't you ;).

You are free to branch to C code after following this tutorial, but remember, you will need to write some things in ASM, just like on x86. Except now ASM is more fun.

boot.asm

#UART base locations from the TRM
.equ UART1.BASE, 		0x4806A000
.equ UART2.BASE, 		0x4806C000
#According to the Beagleboard-xM System Reference Manual, UART3 is connected to the serial port.
# vv USE ME USE ME HARD vv
.equ UART3.BASE, 		0x49020000
# ^^ USE ME USE ME HARD ^^
.equ UART4.BASE, 		0x49042000

#We need to be in ARM mode - we may branch to Thumb mode later if desired.
.arm
_start:
   # Thankfully, U-BOOT already sets up serial for us, so we don't need to do all the reset crap.
   # Just print a '!' symbol to the screen, and hang.
   # Load the location of the transmit register (THR_REG) into r0. It's at the UARTx.BASE, since it is offset 0x000.
   # (load value pointed by the assembler (immediate pointer) into r0)
   ldr r0,=UART3.BASE
   # Move a '!' character into r1
   # (move a character, '!', which is immediate, into r1)
   mov r1,#'!'
   # According to the TRM, we may only write bytes into THR_REG, else we'll corrupt stuff.
   # (store the least-significant-byte of r1 into the address pointed by r0)
   strb r1,[r0]
   # In ASM, labels are like case: statements in C. Code flows into them as if they don't exist - because they don't.
_hang:
   # (branch (jump, JMP) to _hang)
   # b _hang

'Compiling' it

Since it's ASM we technically don't 'compile' it, we 'assemble' (and 'link' it). But anyway, go to where you saved your files and type 'make'. This should progress without any errors.

Executing code on the device

Remember that minicom window we almost forgot about? It's time to use it ;).

Introduction to u-boot

Reset your Beagleboard (hit the reset button).

You should see:

U-Boot 2011.03-rc1-00000-g9a3cc57-dirty (Apr 04 2011 - 12:36:16)                
                                                                                
OMAP36XX/37XX-GP ES2.1, CPU-OPP2, L3-165MHz, Max CPU Clock 1 Ghz                
OMAP3 Beagle board + LPDDR/NAND                                                 
I2C:   ready                                                                    
DRAM:  512 MiB                                                                  
NAND:  0 MiB                                                                    
MMC:   OMAP SD/MMC: 0                                                           
*** Warning - readenv() failed, using default environment                       
                                                                                
In:    serial                                                                   
Out:   serial                                                                   
Err:   serial                                                                   
Beagle xM Rev C                                                                 
No EEPROM on expansion board                                                    
Die ID #2e7000029ff80000016842c813020023                                        
Hit any key to stop autoboot:  3

Hit a key. Before Linux loads.

OMAP3 beagleboard.org #

Whee, a u-boot prompt.

Loading code

Now it's time to load our code into RAM. To do this, we will use 'loady' and the y-modem protocol. We can do all this from minicom - that's why we needed Minicom and not GNU Screen. Hopefully you did what I asked ;).

Just type 'loady'. Don't worry about being fast on your first go, you'll miss it anyway.

OMAP3 beagleboard.org # loady                                                   
## Ready for binary (ymodem) download to 0x80200000 at 115200 bps...

Now hit Ctrl+A. A bar will appear at the bottom.

Press 'S'.

Select 'ymodem'.

Move across to '[Goto]'.

Type in the directory where you saved your code.

Move down to 'boot.bin' and hit 'Space', and then 'Enter'.

Ctrl+C out of the ymodem transfer window if nothing happens.

Reset your Beagleboard and try again - now that the file is already selected, you can just hit enter twice in the file prompt window, preventing timeouts.

Be patient, ymodem can take a few seconds to 'sync'.

After the file is loaded into RAM,

READY: Press any key.

and

Cm - CRC mode, 9(SOH)/0(STX)/0(CAN) packets, 3 retries                          
## Total Size      = 0x00000350 = 848 Bytes                                     
OMAP3 beagleboard.org #

is printed (my file is bigger... don't worry about that), we just have to execute the code in memory!

Executing Code

Execution is started from an address with 'go'. Our _start address is 0x80200000. So, we type:

OMAP3 beagleboard.org # go 0x80200000

and we should get:

## Starting application at 0x80200000 ...                                       
!

If you get that, congratulations! You've just written an 'Operating' System (;)) for the Beagleboard! The process will seem long winded at first, but it's not really at all.

What to do now

Read the ARM ARM. All 2080 pages. And then read it again. (Ok, I haven't done this ^_^)

Read the TRM. All 3652 pages. And then read it again. (I probably _have_ done this ^_^. But I need to read it again :<)

01:26 < doublebeta> embrace the TRM. Hold it close to your heart, and tell it you love it.

Find out how to do push/pop and how to return from functions (and how to return using a pop) from example code and the ARM.

Write routines to print integers and strings. (I've done this, It's a good coding exercise, so I will NOT post example code)

Set up virtual memory.

Enable interrupts (I'm working on this, I'll hopefully make tutorials once I'm done).

Write some device drivers.

Write a scheduler

etc. Do all the stuff you would in an x86 OS.

Branching to C

TODO: Add this

Dependencies of TODO: Care enough to want to branch to C.

It's probably just a matter of linking in your C program and doing

  bx _main

But I quite honestly haven't tried ^_^.

Help

For help, you can try joining #Beagle (note the capital B!) on irc.freenode.net. Speak to doublebeta, if he's not online, pm him. Of course you will be expected to 'pull your own weight' and you will NOT be 'spoon-fed'.

Also, drop in for a chat, eh? Or one of doublebeta's 'discussions' ;).

Vote for a Beagle-specific subforum on forum.osdev.org ;).

References

[1] http://stackoverflow.com/questions/6870712/beagleboard-bare-metal-programming

[2] http://sourceware.org/binutils/docs/as/