Part 4: Running my own blink application
Since we now know how to control the LEDs, it’s time to write our very first standalone application to be run on the MSS310. Inspired from Nicholas FitzRoy-Dale’s bare-metal hello world, the following code parts resulted in a working blink application:
File ‘‘mipsregs.h’’:
#define t0 $8 /* temporary values */
#define sp $29 /* stack pointer */
File ‘‘start.s’’:
#include "mipsregs.h"
.globl _start
.ent _start
.text
_start:
li sp, 0x1100000
la t0, entrypoint
jr t0
nop
.end _start
File ‘‘blink.c’’, the application. Cycles through all LED on/off combinations. Pressing the device’s button resets the device.
#include <stdint.h>
#define RSTCTL 0x10000034
#define GPIO2_MODE 0x10000064
#define GPIO_CTRL_1 0x10000604
#define GPIO_DATA_1 0x10000624
#define GPIO_DSET_1 0x10000634
#define GPIO_DCLR_1 0x10000644
#define SYS_RST (1 << 0)
#define GPIO_RELAY (1 << 0)
#define GPIO_LED_PIN_RED (1 << 1)
#define GPIO_LED_PIN_GREEN (1 << 2)
#define GPIO_BUTTON (1 << 3)
static inline void write_l(unsigned int addr, unsigned int val) {
volatile uint32_t *ptr = (uint32_t *)(addr);
*ptr = val;
}
static inline unsigned int read_l(unsigned int addr) {
volatile uint32_t *ptr = (uint32_t *)(addr);
return *ptr;
}
static void reset_if_button_pressed() {
if (!(read_l(GPIO_DATA_1) & GPIO_BUTTON)) {
write_l(RSTCTL, SYS_RST);
}
}
static void delay() {
volatile int i, j;
for (i = 0; i < 1000; i++) {
reset_if_button_pressed();
for (j = 0; j < 500; j++) /* do nothing */;
}
}
void entrypoint(void) {
write_l(GPIO2_MODE, 0x05550550);
write_l(GPIO_CTRL_1, GPIO_RELAY | GPIO_LED_PIN_RED | GPIO_LED_PIN_GREEN);
while (1) {
write_l(GPIO_DCLR_1, GPIO_LED_PIN_RED);
delay();
write_l(GPIO_DCLR_1, GPIO_LED_PIN_GREEN);
delay();
write_l(GPIO_DSET_1, GPIO_LED_PIN_RED);
delay();
write_l(GPIO_DSET_1, GPIO_LED_PIN_GREEN);
delay();
}
}
File ‘‘linker.lds’’.
OUTPUT_ARCH(mips)
ENTRY(_start)
SECTIONS {
. = 0x1000000; /* Our base address */
.text : { /* Code */
*(.text)
}
.rodata : { /* Static data */
*(.rodata)
*(.rodata.*)
}
.data : { /* non-static data */
*(.data*)
}
}
Finally, the ‘‘Makefile’’ to glue all this together.
XTOOLS = /opt/x-tools/mipsel-unknown-elf/bin
AS = $(XTOOLS)/mipsel-unknown-elf-as -mips32
CC = $(XTOOLS)/mipsel-unknown-elf-gcc
LD = $(XTOOLS)/mipsel-unknown-elf-ld
OBJCOPY = $(XTOOLS)/mipsel-unknown-elf-objcopy
CFLAGS = -Os
OBJS = start.o blink.o
blink.bin: blink.elf
$(OBJCOPY) -O binary $< $@
blink.elf: $(OBJS)
$(LD) -T linker.lds -o $@ $+
%.o: %.[Sc]
$(CC) $(CFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.elf *.bin
Build blink.bin
, then run loadb 1000000
from the u-boot command
line and use kermit to upload the bin file. Run go 1000000
and voilà.
Now it’s time to forget all this messy code (which just serves as a proof-of-concept) and start writing a real application. In addition, we still need to find out how to correctly talk to the chip’s embedded WiFi.