Next Previous Contents

5. "Hello world" project (or "blink a LED" application)

Of course, it's possible to start in the embedded world with a real hello world application, but it's easier to do something more simple. We will start with a LED blinking application.

5.1 Hardware

For this example I have chosen TMS470 ARM7TDMI microcontroller, but it's pretty easy to modify it for almost any ARM7TDMI microcontroller. Anyway, if you want to use this microcontroller, you might find useful example schematics at http://www.arm-development.com/tms470. You will have to attach a LED diode through 330 resistor to any of HET ports. The schematics is verified to be working.

Other files (like TMS470 header files) can be downloaded from http://www.arm-development.com/.

5.2 Makefile

The following makefile is used to compile sources to a binary file that can be flashed directly to the microcontroller.


ARM7AS = /usr/local/arm7/bin/arm-elf-as
ARM7LD = /usr/local/arm7/bin/arm-elf-ld
ARM7CC = /usr/local/arm7/bin/arm-elf-gcc
OBJCOPY = /usr/local/arm7/bin/arm-elf-objcopy

CFLAGS = -c -O2 -Wall -DDEBUG=1 -mbig-endian
CC = $(ARM7CC)

COMMON_SRC = hw.c main.c

FIXADDR = -Ttext 0x0 -Tbss 0x30000

all:    code.bin

depend:
        gcc -E -MM startup.S main.c > .depend

-include .depend

clean:
        rm -f *.o code*.bin code*.elf core .depend *~

code.bin:       code.elf
        @$(OBJCOPY) -v -O binary --remove-section ".comment" \
                code.elf code.bin

code.elf:       main.o startup.o rtos.o
        $(ARM7LD) -EB -static $(FIXADDR) -o code.elf \
        startup.o main.o rtos.o \
        libgcc.a

startup.o:      startup.S
        $(ARM7CC) $(CFLAGS) -c startup.S -mbig-endian

5.3 Startup code

This is my own startup code for ARM7 architecture. It has to be modified for each microcontroller, because it uses interrupt controller, which is different for each microcontroller type.


/*
 ARM7 startup code
 Written by Martin Hinner <hinner(at)s e c o n s(dot)com>
*/

#define RAM_BASE 0x300000
#define RAM_SIZE 12*1024

#define USR_STACK_SIZE  1024
#define USR_STACK_POINTER (RAM_BASE + RAM_SIZE)

#define Mode_USR    0x10
#define Mode_FIQ    0x11
#define Mode_IRQ    0x12
#define Mode_SVC    0x13
#define Mode_ABT    0x17
#define Mode_UNDEF  0x1B
#define Mode_SYS    0x1F

#define I_Bit      0x80
#define F_Bit      0x40

#define EIC_Base_Addr      0xFFFFF800
#define ICR_Off_Addr            0x00            /* Interrupt ctrl. reg. */
#define CICR_Off_Addr           0x04
#define CIPR_Off_Addr           0x08            /* Interrupt ctrl. reg. */
#define IVR_Off_Addr            0x18            /* Interrupt ctrl. reg. */
#define FIR_Off_Addr            0x1C            /* Interrupt ctrl. reg. */
#define IER_Off_Addr            0x20            /* Interrupt ctrl. reg. */
#define IPR_Off_Addr            0x40            /* Interrupt ctrl. reg. */
#define SIR0_Off_Addr           0x60            /* Interrupt ctrl. reg. */

        .text


        .global __vectors

__vectors:
        ldr pc, reset_addr
        ldr pc, undef_addr
        ldr pc, swi_addr
        ldr pc, prefetch_addr
        ldr pc, abort_addr
        nop                             @ reserved
        ldr pc, irq_addr
        ldr pc, fiq_addr

reset_addr:
        .word startup_routine
undef_addr:
        .word undef_routine
swi_addr:
        .word 0
prefetch_addr:
        .word abort_routine
abort_addr:
        .word abort_routine
irq_addr:
        .word irq_routine
fiq_addr:
        .word abort_routine

        .global _start
        .extern main
        .extern lowlevelinit

        .global startup_routine
        .global undef_routine
        .global swi_routine
        .global abort_routine
        .global irq_routine

irq_routine:
            sub         lr, lr, #4
            stmfd       sp!, {lr}
@- Save and r0 in IRQ stack
            stmfd       sp!, {r0-r11}

        mvn r8, #0xDF                   @ IRQIVEC = FFFF FF20
        ldr r8,[r8]
        and r8, r8, #0xFF

        mov r0, #(irq_vectors-4)
        mov r14,pc
        ldr pc,[r0, r8, lsl #2]

            ldmia       sp!, {r0-r11}
@- Restore adjusted  LR_irq from IRQ stack directly in the PC
            ldmia       sp!, {pc}^

        

irq_vectors:
        .word IRQ0Handler
        .word IRQ1Handler
        .word IRQ2Handler
        .word IRQ3Handler
        .word IRQ4Handler
        .word IRQ5Handler
        .word IRQ6Handler
        .word IRQ7Handler
        .word IRQ8Handler
        .word IRQ9Handler
        .word IRQ10Handler
        .word IRQ11Handler
        .word IRQ12Handler
        .word IRQ13Handler
        .word IRQ14Handler
        .word IRQ15Handler
        .word IRQ16Handler
        .word IRQ17Handler
        .word IRQ18Handler
        .word IRQ19Handler
        .word IRQ20Handler
        .word IRQ21Handler
        .word IRQ22Handler
        .word IRQ23Handler
        .word IRQ24Handler
        .word IRQ25Handler
        .word IRQ26Handler
        .word IRQ27Handler
        .word IRQ28Handler
        .word IRQ29Handler
        .word IRQ30Handler
        .word IRQ31Handler

        .extern IRQ0Handler
        .extern IRQ1Handler
        .extern IRQ2Handler
        .extern IRQ3Handler
        .extern IRQ4Handler
        .extern IRQ5Handler
        .extern IRQ6Handler
        .extern IRQ7Handler
        .extern IRQ8Handler
        .extern IRQ9Handler
        .extern IRQ10Handler
        .extern IRQ11Handler
        .extern IRQ12Handler
        .extern IRQ13Handler
        .extern IRQ14Handler
        .extern IRQ15Handler
        .extern IRQ16Handler
        .extern IRQ17Handler
        .extern IRQ18Handler
        .extern IRQ19Handler
        .extern IRQ20Handler
        .extern IRQ21Handler
        .extern IRQ22Handler
        .extern IRQ23Handler
        .extern IRQ24Handler
        .extern IRQ25Handler
        .extern IRQ26Handler
        .extern IRQ27Handler
        .extern IRQ28Handler
        .extern IRQ29Handler
        .extern IRQ30Handler
        .extern IRQ31Handler


_start:
startup_routine:

        msr cpsr_c, #Mode_SYS | I_Bit | F_Bit
        ldr SP,=USR_STACK_POINTER
        bl lowlevelinit

        msr cpsr_c, #Mode_IRQ | F_Bit | I_Bit
        ldr SP,=(USR_STACK_POINTER-USR_STACK_SIZE-4)

        msr cpsr_c, #Mode_UNDEF | F_Bit | I_Bit
        ldr SP,=(USR_STACK_POINTER-USR_STACK_SIZE-USR_STACK_SIZE-4)

        msr cpsr_c, #Mode_FIQ | F_Bit | I_Bit
        ldr SP,=(USR_STACK_POINTER-USR_STACK_SIZE-USR_STACK_SIZE-USR_STACK_SIZE-4)

        msr cpsr_c, #Mode_ABT | F_Bit | I_Bit
        ldr SP,=(USR_STACK_POINTER-USR_STACK_SIZE-USR_STACK_SIZE-USR_STACK_SIZE-USR_STACK_SIZE-4)
        msr cpsr_c, #Mode_SVC | F_Bit | I_Bit
        ldr SP,=(USR_STACK_POINTER-USR_STACK_SIZE-USR_STACK_SIZE-USR_STACK_SIZE-USR_STACK_SIZE-USR_STACK_SIZE-4)

        msr cpsr_c, #Mode_SYS
        ldr SP,=USR_STACK_POINTER

        b main

undef_routine:
        b undef_routine

abort_routine:
        b abort_routine

disable:
        stmfd sp!,{r0}
        mrs r0,cpsr
        orr r0, r0, #(I_Bit|F_Bit)
        msr cpsr,r0
        ldmfd sp!,{r0}
        bx lr

enable:
        stmfd sp!,{r0}
        mrs r0,cpsr
        and r0, r0, #~(I_Bit|F_Bit)
        msr cpsr,r0
        ldmfd sp!,{r0}
        bx lr

        .global enable
        .global disable

5.4 Main program

The following code (main.c) contains three important parts:


#include "iotms470r1a128.h"
#include "tms470r1a256_bit_definitions.h"

void
lowlevelinit ()
{
SYSECR = 0x4007;

MFBAHR0 = 0x0;     // memsel0
MFBALR0 = 0xa0;

MFBAHR2 = 0x30;   // memsel1
MFBALR2 = 0x50;

MFBALR0 = 0x1a0;

}



void main(void)
{
  int i;
  int j;
  int canid;


  PCR = CLKDIV_1;                         // ICLK = SYSCLK
  PCR |= PENABLE;                         // enable peripherals

  HETDIR  = 0xFFFFFFFF;                   // HETx Output direction
  HETDOUT = 0x00000000;                   // HET31 reset, else set

#if SERIAL_TEST
  SCI2CTL3 &= ~SW_NRESET;                 // Reset SCI state machine
  SCI2CCR = TIMING_MODE_ASYNC + CHAR_8;   // Async, 8-bit Char
  SCI2CTL1 |= RXENA;                      // RX enabled
  SCI2CTL2 |= TXENA;                      // TX enabled
  SCI2CTL3 = CLOCK ;//+ RX_ACTION_ENA;      // Internal clock. RX interrrupt
  SCI2LBAUD = (6000000/(8*19200))-1;                       // clock/(8*baud)
  SCI2PC2 |= RX_FUNC;                     // SCIRX is the SCI receive pin
  SCI2PC3 |= TX_FUNC;                     // SCITX is the SCI transmit pin
  SCI2CTL3 |= SW_NRESET;                  // Configure SCI2 state machine
#endif


  j = 0;

  for (;;)
  {

#if SERIAL_TEST
   j++ ;
    SCI2TXBUF = '0' + (j%10);
#endif

    for (i=0;i<100000;i++);
    HETDOUT = 0xFFFFFFFF;                // HET31/0 Toggle

    for (i=0;i<100000;i++);
    HETDOUT = 0x0;                // HET31/0 Toggle

#if SERIAL_TEST
    if ( (SCI2CTL1 & RXRDY) ) {
      SCI2TXBUF = SCI2RXBUF;
      SCI2CTL1 = RXENA;
      SCI2CTL1 = RXENA | RXRDY;
    }
#endif

  }
}


void
IRQ0Handler (void)
{
}

void
IRQ1Handler (void)
{
}

/* PIOA */
void
IRQ2Handler (void)
{
}

void
IRQ3Handler (void)
{
}

void
IRQ4Handler (void)
{
}

void
IRQ5Handler (void)
{
}

void
IRQ6Handler (void)
{
}

void
IRQ7Handler (void)
{
}
void
IRQ8Handler (void)
{
}

void
IRQ9Handler (void)
{
}

void
IRQ10Handler (void)
{
}

void
IRQ11Handler (void)
{
}
void
IRQ12Handler (void)
{
}
void
IRQ13Handler (void)
{
}
void
IRQ14Handler (void)
{
}
void
IRQ15Handler (void)
{
}
void
IRQ16Handler (void)
{
}

void
IRQ17Handler (void)
{
}

void
IRQ18Handler (void)
{
}
void
IRQ19Handler (void)
{
}
void
IRQ20Handler (void)
{
}
void
IRQ21Handler (void)
{
}
void
IRQ22Handler (void)
{
}
void
IRQ23Handler (void)
{
}
void
IRQ24Handler (void)
{
}
void
IRQ25Handler (void)
{
}
void
IRQ26Handler (void)
{
}
void
IRQ27Handler (void)
{
}
void
IRQ28Handler (void)
{
}
void
IRQ29Handler (void)
{
}
void
IRQ30Handler (void)
{
}
void
IRQ31Handler (void)
{
}


Next Previous Contents