Embedded Freaks..

August 10, 2009

Cortex-M3 SysTick peripheral

Filed under: Cortex-M — Tags: — kunilkuda @ 5:10 pm

The interesting part of Cortex-M3 is SysTick, an additional timer, provided by ARM, to switch the process context on RTOS. ARM was hoping that by using SysTick, most of RTOS will be portable from vendor to vendors.

But I’m a bit curious on how to use it. Hence, here’s the simple demo on how to use SysTick on Cortex-M3.main.c

/*
 * main.c
 *
 *  Created on: 10-Aug-2009
 *      Author: kunil
 */

#include "LPC17xx.h"
#include "core_cm3.h"

/*
 * Linker file variables
 */
extern void __sidata;
extern void __sdata;
extern void __edata;
extern void __sbss;
extern void __ebss;

static int main(void);
static void setup_SysTick(void);
static void setup_LEDs(void);
static void display_current_time(void);

static unsigned int u32_current_time;

/*
 * Override the standard Reset_Handler() on startup_LPC1766
 */
void Reset_Handler(void) {
 unsigned int *source, *destination;

 // Copy data section from ROM to RAM
 source = (unsigned int *) &__sidata;
 for (destination = (unsigned int *) &__sdata; destination
      < (unsigned int *) &__edata; destination++) {
   *destination = *source;
 }

 // Clear the BSS section
 for (destination = (unsigned int *) &__sbss; destination
       < (unsigned int *) &__ebss; destination++) {
   *destination = 0;
 }

 main();

 // If main() ever return, this will hold it
 while(1);
}

/*
 * Override the standard SysTick_Handler() on startup_LPC1766
 */
void SysTick_Handler(void) {
 u32_current_time++;
}

int main(void) {
 setup_SysTick();
 setup_LEDs();
 while (1) {
 /* Wait for interrupt..a.k.a sleep until interrupt */
 asm volatile ("wfi");
 display_current_time();
 }
}

static void setup_SysTick(void) {
 /* The upper limit of SysTick
 *
 * Since the MCU clock will be equal to internal RC (assumming the PLL is not
 * activated), 4000000 value will generate 1s interrupt
 *
 * The value is counted at 1 (not zero). Hence -1 offset is introduced
 */
 SysTick->LOAD = (4000000 - 1);
 /* SysTick control register
 *
 * SYSTICK_CLKSOURCE = 1 means the timer will use CPU (core)'s clock
 * SYSTICK_TICKINT = 1 means the SysTick interrupt is activated on NVIC
 * SYSTICK_ENABLE = 1 means enable SysTick
 */
 SysTick->CTRL = (1 << SYSTICK_CLKSOURCE) | (1<<SYSTICK_TICKINT) | (1 << SYSTICK_ENABLE);
}

static void setup_LEDs(void) {
 // Enable P1.28, P1.29, and P1.31 as output
 GPIO1->FIODIR = (1 << 28) | (1 << 29) | (1 << 31);
 // Enable P2.2 - P2.6 as output
 GPIO2->FIODIR = (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
}

static void display_current_time(void) {
 /* Accessing the pins directly
 *
 * u32_current_time[0] = P1.28
 * u32_current_time[1] = P1.29
 * u32_current_time[2] = P1.31
 * u32_current_time[3] = P2.2
 * u32_current_time[4] = P2.3
 * u32_current_time[5] = P2.4
 * u32_current_time[6] = P2.5
 * u32_current_time[7] = P2.6
 */
 GPIO1->FIOPIN = 0;
 GPIO2->FIOPIN = 0;

 GPIO1->FIOPIN |= (((u32_current_time & 0x03) >> 0) << 28);
 GPIO1->FIOPIN |= (((u32_current_time & 0x04) >> 2) << 31);
 GPIO2->FIOPIN |= (((u32_current_time & 0xF8) >> 3) <<  2);
}

To use the source code, you will need the ‘cm3_core.h’, ‘system_LPC17xx.h and ‘LPC17xx.h’ file from CMSIS website. I’m using ver 1.20 source code from their site, and also my own C start up / linker file.

startup_LPC17xx.c

/*
 * startup_LPC1766.c - Startup file for LPC1766 Cortex-M3
 *
 * @author: kunilkuda_at_gmail_dot_com
 */
extern void __cs3_stack; ///< This is global variable from linker script

/* We gave 'weak' attribute, so these functions can be aliased into a single
 * function
 */
void __attribute__((weak)) Reset_Handler(void);     /* Reset Handler */
void __attribute__((weak)) NMI_Handler(void);       /* NMI Handler */
void __attribute__((weak)) HardFault_Handler(void); /* Hard Fault Handler */
void __attribute__((weak)) MemManage_Handler(void); /* MPU Fault Handler */
void __attribute__((weak)) BusFault_Handler(void);  /* Bus Fault Handler */
void __attribute__((weak)) UsageFault_Handler(void);/* Usage Fault Handler */
void __attribute__((weak)) SVC_Handler(void);       /* SVCall Handler */
void __attribute__((weak)) DebugMon_Handler(void);  /* Debug Monitor Handler */
void __attribute__((weak)) PendSV_Handler(void);    /* PendSV Handler */
void __attribute__((weak)) SysTick_Handler(void);   /* SysTick Handler */

/*
 * Ask GCC to put this array into .cs3.interrupt_vector section
 */
__attribute__ ((section(".cs3.interrupt_vector")))
void (* const g_pfnVectors[])(void) = {
 &__cs3_stack,       // The initial stack pointer
 Reset_Handler,      // The reset handler
 NMI_Handler,        // The NMI handler
 HardFault_Handler,  // The hard fault handler
 MemManage_Handler,  // The MPU fault handler
 BusFault_Handler,   // The bus fault handler
 UsageFault_Handler, // The usage fault handler
 0,                  // Reserved
 0,                  // Reserved
 0,                  // Reserved
 0,                  // Reserved
 SVC_Handler,        // SVCall handler
 DebugMon_Handler,   // Debug monitor handler
 0,                  // Reserved
 PendSV_Handler,     // The PendSV handler
 SysTick_Handler,    // The SysTick handler
};

/* Here's how to alias multiple functions into single function
 */
void Default_Handler(void);
#pragma weak NMI_Handler        = Default_Handler /* NMI handler */
#pragma weak HardFault_Handler  = Default_Handler /* Hard Fault handler */
#pragma weak MemManage_Handler  = Default_Handler /* MPU Fault Handler */
#pragma weak BusFault_Handler   = Default_Handler /* Bus Fault Handler */
#pragma weak UsageFault_Handler = Default_Handler /* Usage Fault Handler */
#pragma weak SVC_Handler        = Default_Handler /* SVCall Handler */
#pragma weak DebugMon_Handler   = Default_Handler /* Debug Monitor Handler */
#pragma weak PendSV_Handler     = Default_Handler /* PendSV Handler */
#pragma weak SysTick_Handler    = Default_Handler /* SysTick Handler */

void Default_Handler(void) {
 while (1);
}

extern int main(void);
void Reset_Handler(void) {
 main();

 // If main() ever exit, this should hold MCU from running wild
 while(1);
}

LPC1766.ld

/*
 * Define the supported output formats - elf32-littlearm is the
 *  default
 */
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")

/* Define the target architecture */
OUTPUT_ARCH(arm)

/* Define the system entry point */
ENTRY(Reset_Handler)

/* Define the memory layout for the board */
SECTIONS
{
 /* LPC1766 flash is at 0x0000_0000 */
 .flash 0x00000000 :
 {
 /* Tell the linker to collect any .cs3.interrupt_vector section to this
 address */
 KEEP(*(.cs3.interrupt_vector));

 /* Collect the executable parts here */
 *(.text .text.*);
 /* Collect the const variables here */
 *(.rodata .rodata.*);

 __sidata = .;
 }

 /*
 * This section refers to variables with init value. The init values are
 * stored on ROM, but addressed on RAM (otherwise the variables cannot be
 * manipulated).
 *
 * This section will be loaded at 0x10000000, the start of LPC1766 RAM
 */
 .data_at_ram 0x10000000: AT (LOADADDR(.flash) + SIZEOF(.flash))
 {
 __sdata = .;
 *(.data .data.*);
 __edata = .;
 }

 .ram :
 {
 __sbss = .;
 /* Collect the global / static variables, without init value here */
 *(.bss .bss.*);
 __ebss = .;
 }

 /* Set __cs3_stack to point the end of memory
 * This one depends on your MCU. I'm using LPC1766 with 256kB flash and
 * 32kB RAM
 */

 __cs3_stack = 0x10000000 + (32 * 1024);
}

To compile the files:

# arm-none-eabi-gcc -O2 -ffunction-sections -fdata-sections -g3 -Wall -c -mcpu=cortex-m3 -mthumb -omain.o main.c
# arm-none-eabi-gcc -O2 -ffunction-sections -fdata-sections -g3 -Wall -c -mcpu=cortex-m3 -mthumb -ostartup_LPC1766.o startup_LPC1766.c
# arm-none-eabi-gcc -Wl,--gc-sections -Wl,-Map,LPC1766_Systick_Interrupt.map -Wl,-T,/home/kunil/workspace/LPC1766_Systick_Interrupt/LPC1766.ld -oLPC1766_Systick_Interrupt.elf  main.o startup_LPC1766.o

To generate the HEX file:

# arm-none-eabi-objcopy -j .flash -j .data_at_ram -O ihex LPC1766_Systick_Interrupt.elf LPC1766_Systick_Interrupt.hex

The eclipse project file can be downloaded from here.

Advertisements

5 Comments »

  1. Thanks for sharing!

    It’ll help me getting started with programming my LPC1756 along with gcc/eclipse…

    Comment by nio — January 4, 2010 @ 3:12 pm

  2. Well the hex file on your file got my processor up and running, and I was able to get first two commands of the build to work. I modified the third line to match my environment. Any ideas?

    C:\work\eclipse\BlinkV1\Debug>arm-none-eabi-gcc -Wl,-gc-sections -Wl,-Map,LPC176
    6_Systick_Interrupt.map -Wl,-T,C:\work\eclipse\BlinkV1\LPC1766.ld -oLPC1766_Syst
    ick_Interrupt.elf main.o startup_LPC1766.o
    c:/program files (x86)/codesourcery/sourcery g++ lite/bin/../lib/gcc/arm-none-ea
    bi/4.4.1/../../../../arm-none-eabi/bin/ld.exe: ûgc-sections: No such file: No such file or directory
    collect2: ld returned 1 exit status

    Comment by KB — August 29, 2010 @ 3:11 am

  3. Nevermind. I was able to make my own makefile, fiddle with some of the setting in Eclipse, and be on my way. Works great. Thanks

    Comment by KB — August 29, 2010 @ 11:54 pm

  4. Well, that’s suppose to be: ‘--gc-sections‘ (with two dashes) rather than ‘-gc-sections‘ (with single dash)

    Comment by kunilkuda — August 30, 2010 @ 10:00 am

  5. […] Cortex-M3 SysTick peripheral (via Embedded Freaks..) 2011/04/13 bygreencn Leave a comment Go to comments The interesting part of Cortex-M3 is SysTick, an additional timer, provided by ARM, to switch the process context on RTOS. ARM was hoping that by using SysTick, most of RTOS will be portable from vendor to vendors. But I'm a bit curious on how to use it. Hence, here's the simple demo on how to use SysTick on Cortex-M3.main.c [/sourcecode] /* * main.c * *  Created on: 10-Aug-2009 *      Author: kunil */ #include "LPC17xx.h" … Read More […]

    Pingback by Cortex-M3 SysTick peripheral (via Embedded Freaks..) « Green World — April 13, 2011 @ 12:26 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: