Wednesday, July 9, 2014

Bare metal programming using LPC1768-Xplorer and CodeSourcery toolchain

LPC1768-Xplorer from NGX Technologies is a good board for experimentation. It is compatible with LPC1768-mbed plus it has on board uSD slot and ethernet port to play with.


In this tutorial I would like to take on the very minimal and basic requirements to compile a code that can run on LPC1768-Xplorer.

First, it is necessary to know the memory layout of the microcontroller. For writing linker script, we need to know the boundaries of flash and ram. LPC1768 has 512k of flash and 64k for ram. Flash base address is 0x00000000 and 64k of ram is distributed in 2 banks of 32k each. First bank starts from 0x10000000 and second bank is from 0x2007c000. For this exercise, we shall consider on the first ram bank. So the memory segment in the linker script should be as follows,

MEMORY
{
flash (rx) : ORIGIN = 0x00000000, LENGTH = 512K
ram (wr) : ORIGIN = 0x10000000, LENGTH = 32K
}
Cortex-M3 expects the vector table to be present in the base address of flash which is from 0x00000000. And the first entry in vector table should be top of the ram address which in our case is as follows,

vTopRam = ORIGIN(ram) + LENGTH(ram);

Next, sections should be defined in the linker script so that code and data sections gets placed appropriately during linking.

SECTIONS
{
.text :
{
  . = ALIGN(4);
  *(.isrvectors)
  *(.text)
  *(.rodata)
  *(.rodata*)
  . = ALIGN(4);
  _endflash = .;
} > flash
.data :
{
  . = ALIGN(4);
  _start_data = .;
  *(.data)
  . = ALIGN(4);
  _end_data = .;
} > ram AT > flash
.bss :
{
  . = ALIGN(4);
  _start_bss = .;
  *(.bss)
  . = ALIGN(4);
  _end_bss = .;
 } > ram
}
The first section is .text section where the vector table, code, read only data(constant data) shall reside. Next is the initialized data segment where the initialized globals and static variables resides. Finally, .bss section which holds the uninitialized globals, static variables, globals initialized to zero and static variables initialized to zero. The statement AT > flash indicates that the initialization value of .data segment is stored in the flash after the placement of .text section.
The variables _endflash, _start_data, _end_data, _start_bss, _end_bss can be used to write the initialization logic for .data and .bss segments. This logic is not covered in this tutorial.

Next thing which is required is startup.c which has the vector table and Reset Handler. Below is the code snippet.

#include <stdio.h>
#include <stdint.h>
#include "LPC17xx.h"
extern unsigned int vTopOfRam;
extern int main(void);
void ResetISR(void);
__attribute__((section(".isrvectors")))
void *vecTable[] =
{
&vTopOfRam,
ResetISR
};
void ResetISR(void)
{
LPC_SC->FLASHCFG = (LPC_SC->FLASHCFG & ~0x0000F000) | 0x00004000;
main();
while (1)
  ;
}

As mentioned earlier, the first entry in the vector table is top of the ram address. next entry should be Reset Handler. So we have only two entries in the vector table. Using "__attribute__", it is made sure that this vector table is placed at the flash base during linking. Reset handler, ResetISR contains minimal logic for setting the flash accesses to use 5 CPU clocks and then jumping to main().

The led blinky logic resides in main.c file. The LED on LPC1769-Xplorer is connected to P0.10. Below is the main.c file,

#include <stdio.h>
#include "LPC17xx.h"
#define LED_BIT_POS 10
int main(void)
{
int i;
LPC_GPIO0->FIODIR |= (1 << LED_BIT_POS);
LPC_GPIO0->FIOCLR |= (1 << LED_BIT_POS);
while(1)
{
LPC_GPIO0->FIOCLR |= (1 << LED_BIT_POS);
for (i = 0; i < 0xFFFF ; i++);
LPC_GPIO0->FIOSET |= (1 << LED_BIT_POS);
for (i = 0; i < 0xFFFF ; i++);
}
return 0;
}
The file  LPC17xx.h can be found in the cmsis package provided by NXP Semiconductors/LPCXpresso. These sources can be built using following set of commands,

arm-none-eabi-gcc -c startup.c -mthumb -mcpu=cortex-m3 -O1 -std=c99 -g -o startup.o
arm-none-eabi-gcc -c main.c -mthumb -mcpu=cortex-m3 -O1 -std=c99 -g -o main.o
arm-none-eabi-gcc -nostartfiles -mthumb -mcpu=cortex-m3 -O1 -std=c99 -g -T lpc1769.ld  startup.o  main.o -o app.axf
arm-none-eabi-objcopy -O binary app.axf app.bin

Hope this tutorial provides enough information for a beginner to understand firmware development on cortex-M series controllers. The files related to this project can be found here.

No comments:

Post a Comment