Troubles while setting up FreeRTOS @ SAM7X

nobody wrote on Wednesday, December 20, 2006:

Hello alltogether!

I knew that this is not a FreeRTOS forum, but i think there are many people here which are very familiar with freeRTOS on ARM microcontrollers.

What is the problem?

I used the provided port files for the SAM7 and copied it to my project at eclipse (using yagarto). Further I took the startup code which is provided at Jim Lynch’s great tutorial.

But I have to tell the Controller with the startup code where to jump if there occurs a software Interrupt? Is this correct?

I modified the Startup code as follows:

Code (originally by J. P. Lynch):

/* Stack Sizes */
.set  UND_STACK_SIZE, 0x00000010      /* stack for "undefined instruction" interrupts is 16 bytes     */
.set  ABT_STACK_SIZE, 0x00000010      /* stack for "abort" interrupts is 16 bytes                     */
.set  FIQ_STACK_SIZE, 0x00000080      /* stack for "FIQ" interrupts  is 128 bytes                  */
.set  IRQ_STACK_SIZE, 0X00000080      /* stack for "IRQ" normal interrupts is 128 bytes               */
.set  SVC_STACK_SIZE, 0x00000010      /* stack for "SVC" supervisor mode is 16 bytes               */

/* Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs (program status registers)     */
.set  MODE_USR, 0x10                  /* Normal User Mode                                   */
.set  MODE_FIQ, 0x11                  /* FIQ Processing Fast Interrupts Mode                       */
.set  MODE_IRQ, 0x12                  /* IRQ Processing Standard Interrupts Mode                    */
.set  MODE_SVC, 0x13                  /* Supervisor Processing Software Interrupts Mode              */
.set  MODE_ABT, 0x17                  /* Abort Processing memory Faults Mode                       */
.set  MODE_UND, 0x1B                  /* Undefined Processing Undefined Instructions Mode           */
.set  MODE_SYS, 0x1F                  /* System Running Priviledged Operating System Tasks  Mode       */
.set  I_BIT, 0x80                     /* when I bit is set, IRQ is disabled (program status registers) */
.set  F_BIT, 0x40                     /* when F bit is set, FIQ is disabled (program status registers) */

/* Interrupt controller offsets  */
.set  AT91C_BASE_AIC, 0xFFFFF000       /* (AIC) Base Address                 */
.set  AIC_IVR, 256                  /* IRQ Vector Register                */
.set  AIC_EOICR, 304               /* End of Interrupt Command Register  */

/* identify all GLOBAL symbols  */
.global _vec_reset                  
.global _vec_undef                  
.global _vec_swi                  
.global _vec_pabt                  
.global _vec_dabt                  
.global _vec_rsv                  
.global _vec_irq                  
.global _vec_fiq
.global AT91F_Irq_Handler
.global   AT91F_Default_FIQ_handler
.global   AT91F_Default_IRQ_handler
.global   AT91F_Spurious_handler

/* GNU assembler controls  */
.text                           /* all assembler code that follows will go into .text section    */
.arm                           /* compile for 32-bit ARM instruction set                   */
.align                           /* align section on 32-bit boundary                         */

/* ============================================================ */
/*                   VECTOR TABLE                        */
/*                                                */
/*   Must be located in FLASH at address 0x00000000            */
/*                                                */
/*   Easy to do if this file crt.s is first in the list          */
/*   for the linker step in the makefile, e.g.               */
/*                                                */
/*       $(LD) $(LFLAGS) -o main.out  crt.o main.o            */
/*                                                */
/* ============================================================ */
/* FreeRTOS SWI Interrupt - needed by PORTYIELD */

_vec_reset:      b           _init_reset            /* RESET vector - must be at 0x00000000   */
_vec_undef:      b           _vec_undef            /* Undefined Instruction vector         */
_vec_swi:      b           _yield_handler         /* Software Interrupt vector         */
_vec_pabt:      b           _vec_pabt            /* Prefetch abort vector            */
_vec_dabt:      b           _vec_dabt            /* Data abort vector               */
_vec_rsv:      b           _vec_rsv            /* Reserved vector                  */
_vec_irq:      b           _vec_irq            /* Interrupt Request (IRQ) vector      */
_vec_fiq:      b           _vec_fiq            /* Fast interrupt request (FIQ) vector   */

_yield_handler:   b       vPortYieldProcessor

/* Reset Handler */
            /* Setup a stack for each mode with interrupts initially disabled. */
             ldr   r0, =_stack_end               /* r0 = top-of-stack  */
             msr   CPSR_c, #MODE_UND|I_BIT|F_BIT    /* switch to Undefined Instruction Mode  */
             mov   sp, r0                     /* set stack pointer for UND mode  */
             sub   r0, r0, #UND_STACK_SIZE         /* adjust r0 past UND stack  */
             msr   CPSR_c, #MODE_ABT|I_BIT|F_BIT    /* switch to Abort Mode */
             mov   sp, r0                     /* set stack pointer for ABT mode  */
             sub   r0, r0, #ABT_STACK_SIZE         /* adjust r0 past ABT stack  */
             msr   CPSR_c, #MODE_FIQ|I_BIT|F_BIT    /* switch to FIQ Mode */
             mov   sp, r0                     /* set stack pointer for FIQ mode  */   
               sub   r0, r0, #FIQ_STACK_SIZE         /* adjust r0 past FIQ stack  */
             msr   CPSR_c, #MODE_IRQ|I_BIT|F_BIT    /* switch to IRQ Mode */
             mov   sp, r0                     /* set stack pointer for IRQ mode  */
             sub   r0, r0, #IRQ_STACK_SIZE         /* adjust r0 past IRQ stack  */
             msr   CPSR_c, #MODE_SVC|I_BIT|F_BIT    /* switch to Supervisor Mode */
             mov   sp, r0                     /* set stack pointer for SVC mode  */
             sub   r0, r0, #SVC_STACK_SIZE         /* adjust r0 past SVC stack  */
             msr   CPSR_c, #MODE_SYS|I_BIT|F_BIT    /* switch to System Mode */
             mov   sp, r0                     /* set stack pointer for SYS mode  */
                                           /* we now start execution in SYSTEM mode        */
                                           /* This is exactly like USER mode (same stack)  */
                                           /* but SYSTEM mode has more privileges          */

            /* copy initialized variables .data section  (Copy from ROM to RAM) */
                ldr     R1, =_etext
                ldr     R2, =_data
                ldr     R3, =_edata
1:              cmp     R2, R3
                ldrlo   R0, [R1], #4
                strlo   R0, [R2], #4
                blo     1b

            /* Clear uninitialized variables .bss section (Zero init)  */
                mov     R0, #0
                ldr     R1, =_bss_start
                ldr     R2, =_bss_end
2:            cmp     R1, R2
                strlo   R0, [R1], #4
                blo     2b

            /* Enter the C code  */
                b       main

/* ========================================================== */
/* - Function             : AT91F_Irq_Handler                 */
/* - Treatments           : IRQ Controller Interrupt Handler. */
/* - Called Functions     : AIC_IVR[interrupt]                */
/* ---------------------------------------------------------- */

/* Adjust and save LR_irq in IRQ stack */
            sub      lr, lr, #4
            stmfd   sp!, {lr}
/* Save and r0 in IRQ stack */
            stmfd   sp!, {r0}

/* Write in the IVR to support Protect Mode                */
/* No effect in Normal Mode                                */
/* De-assert the NIRQ and clear the source in Protect Mode */
            ldr      r14, =AT91C_BASE_AIC
            ldr      r0 , [r14, #AIC_IVR]
            str      r14, [r14, #AIC_IVR]

/* Enable Interrupt and Switch in Supervisor Mode */
            msr      CPSR_c, #MODE_SVC
/* Save scratch/used registers and LR in User Stack */
            stmfd   sp!, { r1-r3, r12, r14}

/* =============================================== */
/* Branch to the routine pointed by the AIC_IVR    */
/* =============================================== */

/* Branch to the routine pointed by the AIC_IVR */
            mov      r14, pc
            bx      r0

/* =============================================== */
/* Manage Exception Exit                     */
/* =============================================== */

/* Restore scratch/used registers and LR from User Stack */
            ldmia   sp!, { r1-r3, r12, r14}

/* Disable Interrupt and switch back in IRQ mode */
             msr      CPSR_c, #MODE_IRQ|I_BIT

/* Mark the End of Interrupt on the AIC */
            ldr      r14, =AT91C_BASE_AIC
            str      r14, [r14, #AIC_EOICR]

/* Restore SPSR_irq and r0 from IRQ stack */
            ldmia   sp!, {r0}

/* Restore adjusted  LR_irq from IRQ stack directly in the PC */
            ldmia   sp!, {pc}^

AT91F_Default_FIQ_handler:   b     AT91F_Default_FIQ_handler

AT91F_Default_IRQ_handler:   b     AT91F_Default_IRQ_handler

AT91F_Spurious_handler:      b     AT91F_Spurious_handler


In fact, i only inserted the vPortYieldProcessor function to the SWI Interrupt source.

And this is my application code which creates one task:

//                         FREERTOS - APPLICATION

#include "./include/AT91SAM7X256.h"
#include "./include/board_ex256.h"
#include "./include/registers.h"
#include "./include/lcd.h" 
#include "./include/debug.h"

/* FreeRTOS includes */

#include "./freeRTOS/include/FreeRTOS.h"
#include "./freeRTOS/include/task.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern   void LowLevelInit(void);

void init(void);
//void IRQ_Routine (void)   __attribute__ ((interrupt("IRQ")));
void FIQ_Routine (void)   __attribute__ ((interrupt("FIQ")));
//void SWI_Routine (void)   __attribute__ ((interrupt("SWI")));
void UNDEF_Routine (void) __attribute__ ((interrupt("UNDEF")));

/* Task functions */

void OS_Setup(void);
void TaskBlink(void *taskData);
/* Set the TaskStack Size to the default minimal value */
#define TaskStackSize configMINIMAL_STACK_SIZE

void OS_Setup(void)
   unsigned int taskData = 0x0;
   xTaskHandle taskHandle;
   /* Lets create the Application TASKS */
   xTaskCreate(TaskBlink, "TaskBlink", TaskStackSize, (void *) &taskData, tskIDLE_PRIORITY+1, &taskHandle);      
   printf("Task Created \n\r");

void TaskBlink(void *taskData)
   char debugMessage[100];
   taskData = taskData;
   printf("We are in Task Blink now \n\r");

       printf("FREE_RTOS: Backlight ON \n\r");
       printf("FREE_RTOS: Backlight OFF \n\r");

int main(int argc, char **argv) {    
   printf("Trying to start FREE_RTOS \n\r");
      /* Hopefully the OS never returns here */   

void init(void) {
  //*************** lowlevel init (watchdog, PLL clock, default interrupts, etc.)

  //*************** inint defined state
  //set all Ports to PIO controlled, not on-chip peripheral
  pPIOA->PIO_PER = 0xffffffff; 
  pPIOB->PIO_PER = 0xffffffff;
  //we coould also have used
  //pSYS->PIOA_PER = 0xffffffff; 
  //pSYS->PIOB_PER = 0xffffffff;

  //enable all pull ups
  pSYS->PIOA_PPUER = 0xffffffff; 
  pSYS->PIOB_PPUER = 0xffffffff;

  //select multiplex function A (should be default). only needed if
  //on-chip peripheral was selected
  pSYS->PIOA_ASR = 0xffffffff;
  pSYS->PIOB_ASR = 0xffffffff;

  //we use PIO controlled i/o lines (see above) and set them to input
  pSYS->PIOA_ODR = 0xffffffff; 
  pSYS->PIOB_ODR = 0xffffffff; 

  //****************** init lcd

  //for buttons interrupt do not forget to enable PIO Clock


/*  Stubs for various interrupts (may be replaced later)  */
/*  ----------------------------------------------------  */

void FIQ_Routine (void)  {
   while (1) ;   

void UNDEF_Routine (void) {
   while (1) ;   

My problem is that after i call vTaskStartScheduler(); the program stopps and the task code is not executed.

My first idea was that there is something wrong with the OS tick timer. How could i figure out if the tick timer is not running?

Do i have to add further modifications at my startup code to get freeRTOS running?

Any help is welcome. Thanks a lot in advance.


nobody wrote on Wednesday, December 20, 2006:

Just looking at the startup code I can see a number of problems.  Use the startup code that comes with FreeRTOS download for the SAM7X (in the lwIP demo directory there are all the files you need).  The startup code is provided for you - you do not need to rewrite it although you may want to tweak it a bit.

SVC_STACK_SIZE way too small.

Exception entry and exit is going to mangle the stack compared to how FreeRTOS expectes it.  You can either vector directly to the FreeRTOS code (as per the SAM7X GCC example) or have handler code that saves/restores the context as FreeRTOS expects it (as per the STR750 GCC example). 

Likewise the SWI handler.

I’m not familiar with Yagarto but there have been people mentioning differences between WinARM and GNUARM.  Yagarto is another one in the mix.  You might be better off starting with GNUARM as this is what the demos were written using.

nobody wrote on Thursday, December 21, 2006:

thanks for the reply.

I change the Stack Sizes, but it is still not running.

Sorry, but i downloaded the Code from but i couldn’t find a startup code for SAM7X and GCC. Maybe someone can tell me where this startup code is located at the file structure.

Thanks a lot in advance.

nobody wrote on Thursday, December 21, 2006:

Demo\lwIP_Demo_Rowley_ARM7\boot.s, and
Demo\lwIP_Demo_Rowley_ARM7\makefile and also the linker script.

I would suggest:

i/ Downloading gnuarm from  This has the same functionality as YAG.  Set the bin directory in your path instead of YAG.

ii/ From the command prompt, rather than in Eclipse, go to the above referenced directory and type make.  You should be able to build the code with no problems :slight_smile:

iii/ Take out anything from the makefile that you don’t want.  Maybe you want to just leave the flash demo tasks to flash some LED’s to start with and remove all else.  You will also have to edit main.c to stop calling the functions to start tasks that are no longer in the makefile.

iv/ Update partest.c (Demo\lwIP_Demo_Rowley_ARM7\ParTest) to access the LEDs that are on your board.  They are currently set to flash the LEDs that are on the SAM7X EK board from atmel.

v/ Once this is all running - go back to using Ecliplse and try to build the same project from in that environment.

I don’t think Eclipse gains you much other than a very slow clunky IDE full of oddity and restriction.  I prefer the command line approach which is fast.  If you want a good fast easy IDE at a low price consider buying a personal license of CrossWorks.