Search code examples
assemblyarmembeddedbeagleboardbare-metal

How can I boot bare metal from SD card on PocketBeagle?


What I'm Trying To Do:

I am trying to boot my new PocketBeagle into a plain assembly program.

.equ GPIO_BANK1, 0x4804C000
.equ GPIO_OE, 0x134
.equ GPIO_USR_SETPIN0, 0x194
.equ GPIO_USR_PIN0, 0x13C

.globl _start

_start:
    ldr r0, =GPIO_BANK1 
    ldr r1, =GPIO_OE    @ Get the output enable register
    add r0, r1
    mov r1, #0          @ Set all of the GPIO1 Pins to output
    str r1, [r0]
_main:
    ldr r0, =GPIO_BANK1    
    ldr r1, =GPIO_USR_PIN0 @ Get the output register
    add r0, r1
    mov r1, #1
    lsl r1, #24
    str r1, [r0]           @ Set the USR LED to hi.
loop:
    ldr r2, =0x00010000
    sub r2, #1
    cmp r2, #0
    beq _main
    mov r1, #0
    str r1, [r0]
_hang:
    b _main

I compile this file using the following makefile

ARMGNU = arm-eabi

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

According to the manual section 26.1.6 (26.1.8.5 for SD booting), I can boot into this code from an SD card with the FAT filesystem if I name the file MLO. Now, if I got my registers right in the assembly code, then the USR0, USR1, USR2, and USR3 LEDs on the PocketBeagle should light up. (See here USR to PIN Mappings) This is because the GPIO1_21, 22, 23, and 24 pins correspond to those 4 LEDs, and those are the pins that I am (trying to) set high.

But the LEDs do not light up. So I'm doing something wrong, but I can't figure it out.

What I've Tried:

There is very little documentation on the PocketBeagle online. Apparently the PocketBeagle should be electrically very similar to the BeagleBone Black.

  • I've tried the TI StarterWare which is supposed to contain functioning binaries. I used the MLO and an example program from that with no luck. Additionally, I've been unsuccessful getting the projects to compile myself. Code Composer Studio is frustrating me. I've tried looking into how to fix the toolchain for CCS, but, admittedly, I don't know enough about the subject to even know where to begin.
  • I've tried the community driven StarterWareFree. This doesn't come with binaries, but, like above, I can't compile because my tool chain is out of whack.
  • I've made sure that my PocketBeagle still works. I installed the linux distro that is suggested by the BeagleBone community, and I get the heartbeat on the USR0 LED. So the board works.
  • I tried using that Linux's MLO, but I was unable to find the MLO in the image that I was using...
  • I tried using the GPIO_SETDATAOUT register instead; according to the docs it should accomplish the same thing I try to do in the assembly. (Section 25.4 of the manual.)
  • I made sure that the board could recognize the FAT file system by verifying the presence of 0xAA55 at offset 0x01FE of the SD card (I used HxD to do this). So the FAT MBR is there. (section 26.1.8.5.7.1)

What I'm Looking For:

Some direction. Where do I go from here? I've come to accept the fact that I probably won't be able to get the USR LEDs to blink. I don't think the manual can help me any more, and there aren't any resources on the web. I am still learning embedded programming, and I've had success with Arduino and Atmel Studio. I'm not completely novice but guidance is appreciated.

Where can I look for information on embedded system booting? Is there a similar simpler problem that I can tackle to help me understand?

This is probably a poorly formatted question for stackoverflow, but I have such little knowledge of the subject. Please advise.

Context - What is a PocketBeagle:

I linked to the website for the PocketBeagle above. For those who don't want to leave SO, here is some info. It is similar to the BeagleBoneBlack. It has three main components, a micro USB port, an SD card reader and the Octavo Systems OSD3358 1GHz ARM® Cortex-A8 System on Chip. The OSD3358 contains the AM3358 TI Processor; the manual is above. The PocketBeagle comes conveniently configured so that it can boot from the SD card without fussing around with the SYSCONFIG pins. So you can put code on the SD card, put it in the PocketBeagle, and it will boot into that code... hopefully.


Solution

  • After some digging, I realized that my code is accurate, but I was forgetting one step. I need to turn on the GPIO1 bus clock before the GPIO1 bus will output signals. The register that controls this clock can be seen in section 8.1.12.1.29 of the manual. Additionally, I found this noted in a forum on the TI Website.

    What I Did:

    I abandoned trying to boot from the FAT file system and resorted to booting in 'raw mode.' See section 26.1.8.5.5 of the manual. I originally avoided this method because there was less detail, but it was ultimately easier.

    This method was a bit trickier however, because I had to write raw bytes to an SD card. I used HxD to do this. At address 0, I put the following code... this is magic code described in section 26.1.10 of the manual. View this in a hex editor for your reading convenience.

    40 00 00 00 0C 00 00 00 00 00 00 00 00 00 00 00  @...............
    00 00 00 00 43 48 53 45 54 54 49 4E 47 53 00 00  ....CHSETTINGS..
    FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    C1 C0 C0 C0 00 01 00 00 00 00 00 00 00 00 00 00  ÁÀÀÀ............
    00 [0x50-0x1FF]...
    

    Then there must be zeros until address 0x200 (512 Bytes). I put the binary code at address 0x200 with the addition of a GP header described in section 26.1.10.2 of the manual. The GP Header consists of 2 words (of 4 bytes each). The first word being the size of the 'image' (aka YOUR binary) and the second word being the destination in memory that the ROM bootloader will put your code. Since the public RAM of the AM335x chip starts at 0x402F0400, we want to put our code there. (Section 26.1.4.2 of the manual). Keep in mind, this is little endian. I put FF in for the size of my image, but in reality, that is larger than my image.

    FF 00 00 00 00 04 2F 40
    

    Immediately following that, I put the binary of the compiled assembly code posted in the original question. (So my code starts at 0x208) All together, starting from 0x200, the hex dump looks like

    FF 00 00 00 00 04 2F 40 50 00 9F E5 AC 10 A0 E3 
    01 00 80 E0 02 10 A0 E3 00 10 80 E5 40 00 9F E5
    4D 1F A0 E3 01 00 80 E0 00 10 A0 E3 00 10 80 E5 
    2C 00 9F E5 4F 1F A0 E3 01 00 80 E0 00 10 E0 E3
    00 10 80 E5 01 28 A0 E3 01 20 42 E2 00 00 52 E3 
    F6 FF FF 0A 00 10 A0 E3 00 10 80 E5 F3 FF FF EA 
    00 00 E0 44 00 C0 04 48 00 00 00 00 00 00 00 00
    

    My final assembly looked like this

    .equ GPIO1, 0x4804C000
    .equ GPIO_OE, 0x134
    .equ CM_PER, 0x44E00000
    .equ CM_PER_GPIO1_CLKCTRL, 0xAC
    .equ GPIO_DATAOUT, 0x13C
    
    .globl _start
    
    _start:
        ldr r0, =CM_PER                @Clocks control register bus.
        ldr r1, =CM_PER_GPIO1_CLKCTRL  @Offset of the clock register for GPIO1
        add r0, r1
        mov r1, #2                     @Set the enable bit. Man 8.1.12.1.29
        str r1, [r0]
    _led_enable:
        ldr r0, =GPIO1     @Register bank for GPIO1
        ldr r1, =GPIO_OE   @Register that controls output enable.
        add r0, r1
        mov r1, #0
        str r1, [r0]
    _main:
        ldr r0, =GPIO1     
        ldr r1, =GPIO_DATAOUT  @Register than controls the output of GPIO1
        add r0, r1
        ldr r1, =0xFFFFFFFF
        str r1, [r0]
    loop:
        ldr r2, =0x00010000     @The start of a loop that may or may not work.
        sub r2, #1              @I tried to make the USR LEDs blink, but I posted
        cmp r2, #0              @this before I tested it.
        beq _main
        mov r1, #0
        str r1, [r0]
    _hang:
        b _main
    

    My makefile looks like it did in the original question.