Port for LPC2364/66/68/78

nobody wrote on Monday, March 12, 2007:

I would like to run FreeRTOS on a LPC2378 can I use the IAR - LPC2000 port?
Or do I have to change something?

Best regards,
Peter V.
Denmark

rtel wrote on Monday, March 12, 2007:

The timer and VIC setup are a bit different.  The timer is setup in prvSetupTimerInterrupt() in port.c.  Here is an example for an LPC2368:

static void prvSetupTimerInterrupt( void )
{
unsigned portLONG ulCompareMatch;

    PCLKSEL0 = (PCLKSEL0 & (~(0x3<<2))) | (0x01 << 2);
    T0TCR  = 2;         /* Stop and reset the timer */
    T0CTCR = 0;         /* Timer mode               */
   
    /* A 1ms tick does not require the use of the timer prescale.  This is
    defaulted to zero but can be used if necessary. */
    T0PR = portPRESCALE_VALUE;

    /* Calculate the match value required for our wanted tick rate. */
    ulCompareMatch = configCPU_CLOCK_HZ / configTICK_RATE_HZ;

    /* Protect against divide by zero.  Using an if() statement still results
    in a warning - hence the #if. */
    #if portPRESCALE_VALUE != 0
    {
        ulCompareMatch /= ( portPRESCALE_VALUE + 1 );
    }
    #endif
    T0MR1 = ulCompareMatch;

    T0MCR  = (3 << 3);  /* Reset timer on match and generate interrupt */

    /* Setup the VIC for the timer. */
    VICIntEnable = 0x00000010;
   
    /* The ISR installed depends on whether the preemptive or cooperative
    scheduler is being used. */
    #if configUSE_PREEMPTION == 1
    {
        extern void ( vPreemptiveTick )( void );
        VICVectAddr4 = ( portLONG ) vPreemptiveTick;
    }
    #else
    {
        extern void ( vNonPreemptiveTick )( void );
        VICVectAddr4 = ( portLONG ) vNonPreemptiveTick;
    }
    #endif

    VICVectPriority4 = 1;

    /* Start the timer - interrupts are disabled when this function is called
    so it is okay to do this here. */
    T0TCR = portENABLE_TIMER;
}

It needs tidying up a bit.

Other than that, check you have the correct header file included for your device to ensure the correct register locations (check the top of FreeRTOSConfig.h which is part of the demo, rather than kernel code) and change the linker file accordingly.

Its best to use the existing demo as a base, just make these changes.  This way you start with the correct compiler options.

Regards.

nobody wrote on Monday, March 12, 2007:

Ok, thanks for the quick responce…

/Peter

yamsu wrote on Sunday, October 21, 2007:

I’m also trying to make a port for the FREERTOS v4.5 for IAR LPC2378 (Olimex LPC-2378-STK) board. I have made the changes to the timer and the interrupt configurations. However, even after this the RTOS seems to cease once the vTaskStartScheduler() is called. I believe the timer interrupt is not working since i placed a command to toggle an LED everytime the routine is serviced.

I would really appreciate some help with this port. if any one has been successful in using the LPC2378 with FREERTOS please let me know.

rtel wrote on Sunday, October 21, 2007:

My suggestion would be to get the timer interrupt running in a simple hello world type program first.  A main() function that does nothing other than setup the interrupt, and an ISR that does nothing but toggle the LED every 500 interrupts.  Once you have the timer working, then add in the FreeRTOS.org code, with your new timer setup.

Regards.

yamsu wrote on Monday, October 22, 2007:

Sound advice Richard thanks! Yeah there was some problem with the timer initialization. So managed to fix that and then i tried to setup single task FreeRTOS code. Unfortunately, after calling the xTaskCreate function, going through the heap_c1, the program got stuck in the __disableinterrupt(); function. This seems to be the common problem most people are stuck with on the forum. So I’m joining the league; please do let me know if any of your guys have managed to solve this issue.

Thanks

rtel wrote on Monday, October 22, 2007:

I’m not aware of a problem with __disableinterrupt().  This is an IAR function I think?  Are you calling main() from Supervisor mode?

Regards.

jorick23 wrote on Monday, October 22, 2007:

The _disable_interrupt intrinsic function in the IAR ARM compiler sets both the Disable IRQ and Disable FIQ bits in the CPSR register.  Then it tests them using an AND instruction to mask out unwanted bits to make sure the bits are really set.  If they aren’t, it loops back and sets them again.  It continues looping until the bits are set, and then exits the function.

One problem with the way the bits are tested is that if the Disable FIQ bit gets set but the IRQ bit doesn’t, the function exits thinking all is well when it really isn’t.

In my application, written on the STR750 platform, I had to rewrite the _disable_interrupt function in order to avoid disabling the FIQ (it MUST remain on all the time in my application), but when I saw the looping that was being done, I removed it.  I haven’t had a single problem with bits not being set when they should be.

What’s happening on your platform?  Are the Disable bits not being set inside the _disable_interrupt function?

Here’s my assembler implementation of the _disable_interrupt function without the loops.  There are two functions required, one for Thumb mode, and one for ARM mode.  You must keep the function names ??DiI_t and ??DiI_a in order for them to properly replace the ones in the library.  If you want to disable FIQ interrupts too, change the 0x80 to 0xC0 in the orr instruction in the ??DiI_a function.

/******************************************************************************
*~    ??DiI_t                   Disable IRQ interrupts from Thumb mode        *
*******************************************************************************
*                                                                             *
* This function disables only IRQ interrupts.  FIQ interrupts are left alone. *
*                                                                             *
* This function is a replacement for the IAR library function with the same   *
* name.  The IAR version, which is the handler for the intrinsic function     *
* _disable_interrupt ( ), also disables FIQ interrupts which adversly affects *
* the operation of the pump.                                                  *
*                                                                             *
*       Args:   void                                                          *
*                                                                             *
*       Return: void                                                          *
*                                                                             *
******************************************************************************/

        rseg    CODE:CODE(2)
        code16

??DiI_t:
        bx      pc                      // Switch to arm mode
        nop                             // Alignment instruction

// Control passes to the ??DiI_a function to handle the actual disabling of the
// interrupts.

/******************************************************************************
*~    ??DiI_a                   Disable IRQ interrupts from ARM mode          *
*******************************************************************************
*                                                                             *
* See ??DiI_t above for more info.                                            *
*                                                                             *
*       Args:   void                                                          *
*                                                                             *
*       Return: void                                                          *
*                                                                             *
******************************************************************************/

        code32

??DiI_a:
        mrs     r0, cpsr                // Get the status flags
        orr     r0, r0, #0x80           // Disable IRQ interrupts
        msr     cpsr_c, r0              // Store the updated status flags
        bx      lr                      // Return

yamsu wrote on Tuesday, October 23, 2007:

You got it barry!!! I’m not entering main() in supervisor mode. I stepped through the startup file but main is called in user mode; hence, this is the root of all problems!

Here is a snippet of my startup file:

;  Enter IRQ Mode and set its Stack Pointer
        MSR     CPSR_c, #Mode_IRQ|I_Bit|F_Bit
        LDR     SP, =SFE(IRQ_STACK)&0xFFFFFFF8

;  Enter Sys Mode and set its Stack Pointer (Common with user)
        MSR     CPSR_c, #Mode_SYS
        LDR     SP, =SFE(CSTACK)&0xFFFFFFF8

;  Enter Supervisor Mode and set its Stack Pointer
        MSR     CPSR_c, #Mode_SVC|I_Bit|F_Bit     ;Goes into user mode
        LDR     SP, =SFE(SVC_STACK)&0xFFFFFFF8

;Must Start in supervisor mode
       MSR     CPSR_c, #Mode_SVC|I_Bit|F_Bit      ; has no effect on the mode
; Enter the C code

        LDR     R0, =?main
        BX      R0
        B       .

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Now as soon as it executes the first         MSR     CPSR_c, #Mode_SVC|I_Bit|F_Bit
the processor decides to go into user mode and even the second mode switch line cannot get the processor into the supervisor mode. Of course this is not an issue with the LPC2119, on which i have FREERTOS running smoothly.

Here is the entire cstartup.s79 file:

; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs

Mode_USR        DEFINE  0x10
Mode_FIQ        DEFINE  0x11
Mode_IRQ        DEFINE  0x12
Mode_SVC        DEFINE  0x13
Mode_ABT        DEFINE  0x17
Mode_UND        DEFINE  0x1B
Mode_SYS        DEFINE  0x1F

I_Bit           DEFINE  0x80            ; when I bit is set, IRQ is disabled
F_Bit           DEFINE  0x40            ; when F bit is set, FIQ is disabled

; Exception Vectors
; Mapped to Address 0.
; Absolute addressing mode must be used.
; Dummy Handlers are implemented as infinite loops which can be modified.

        PROGRAM ?RESET
        COMMON  INTVEC:CODE(3)
        PUBLIC  __program_start
        EXTERN    ?cstartup
        EXTERN  Reset_Handler, Undef_Handler, SWI_Handler, PAbt_Handler, DAbt_Handler, FIQ_Handler
        EXTERN    vPortYieldProcessor
        CODE32  ; Always ARM mode after reset

__program_start
    org 0x00
        LDR     PC, =Reset_Handler
    org 0x04
        LDR     PC, =Undef_Handler
    org 0x08
        LDR     PC, =SWI_Handler
    org 0x0C
        LDR     PC, =PAbt_Handler
    org 0x10
        LDR     PC, =DAbt_Handler
    org 0x18
        LDR     PC, [PC, #-0x0120]  ; Vector from VicVectAddr
    org 0x1C
        LDR     PC, =FIQ_Handler

        LTORG
        ENDMOD

; Reset Handler

        MODULE  ?CSTARTUP
        RSEG  IRQ_STACK:DATA(2)
;        RSEG  FIQ_STACK:DATA(3)
        RSEG  SVC_STACK:DATA:NOROOT(2)
;        RSEG  ABT_STACK:DATA(3)
;        RSEG  UND_STACK:DATA(3)
        RSEG  CSTACK:DATA(2)
        RSEG  ICODE:CODE:NOROOT(2)
       PUBLIC  Reset_Handler, Undef_Handler, SWI_Handler, PAbt_Handler, DAbt_Handler, FIQ_Handler
        EXTERN  ?main
        CODE32

Reset_Handler

;  Enter Undefined Instruction Mode and set its Stack Pointer
;        MSR     CPSR_c, #Mode_UND|I_Bit|F_Bit
;        LDR     SP, =SFE(UND_STACK)&0xFFFFFFF8

;  Enter Abort Mode and set its Stack Pointer
;        MSR     CPSR_c, #Mode_ABT|I_Bit|F_Bit
;        LDR     SP, =SFE(ABT_STACK)&0xFFFFFFF8

;  Enter FIQ Mode and set its Stack Pointer
;        MSR     CPSR_c, #Mode_FIQ|I_Bit|F_Bit
;        LDR     SP, =SFE(FIQ_STACK)&0xFFFFFFF8

;  Enter IRQ Mode and set its Stack Pointer
        MSR     CPSR_c, #Mode_IRQ|I_Bit|F_Bit
        LDR     SP, =SFE(IRQ_STACK)&0xFFFFFFF8

;  Enter (now dont) User Mode and set its Stack Pointer
        MSR     CPSR_c, #Mode_SYS|I_Bit|F_Bit
        LDR     SP, =SFE(CSTACK)&0xFFFFFFF8

;  Enter Supervisor Mode and set its Stack Pointer
        MSR     CPSR_c, #Mode_SVC|I_Bit|F_Bit
        LDR     SP, =SFE(SVC_STACK)&0xFFFFFFF8

; Must start in supervisor mode.
        MSR     CPSR_c, #Mode_SVC|I_Bit|F_Bit

; Enter the C code

        LDR     R0, =?main
        BX      R0
        B       .

Undef_Handler
SWI_Handler
PAbt_Handler
DAbt_Handler
FIQ_Handler

        B       .

        LTORG
        ENDMOD
        END

yamsu wrote on Tuesday, October 23, 2007:

False Alarm! I managed to solve the above problem with the supervisor mode.

Apparently there was a mistake in my .xcl file (linker file)

it was:
-D_CSTACK_SIZE=200
-D_SVC_STACK_SIZE=190
-D_IRQ_STACK_SIZE=190
-D_HEAP_SIZE=4

-Z(DATA)CSTACK+_CSTACK_SIZE=RAMSTART-RAMEND
-Z(DATA)SVC_STACK+_SVC_STACK_SIZE=RAMSTART-RAMEND
-Z(DATA)IRQ_STACK+_IRQ_STACK_SIZE=RAMSTART-RAMEND
-Z(DATA HEAP+_HEAP_SIZE=RAMSTART-RAMEND

instead of:
-D_CSTACK_SIZE=200
-D_SVC_STACK_SIZE=190
-D_IRQ_STACK_SIZE=190
-D_HEAP_SIZE=4

-Z(DATA)CSTACK+_CSTACK_SIZE=RAMSTART-RAMEND
-Z(DATA)SVC_STACK+_SVC_STACK_SIZE=RAMSTART-RAMEND
-Z(DATA)IRQ_STACK+_IRQ_STACK_SIZE,HEAP+_HEAP_SIZE=RAMSTART-RAMEND

I’m afraid i don’t really know that the change is here, but the latter was available from the FreeRTOS LPC2129 demo.

Now i’m entering main in supervisor mode and there is no trouble with the __disable_interrupt() function. (Thanks for the response jorick23 but it was the supervisor mode problem)

However, as soon as i reach the
vPortStartFirstTask();
it does something strange it exits out and i get an error message:

The stack pointer for stack ‘CSTACK’ (currently 0x40000EFC) is outside the stack range (0x400046E4 to 0x400048E4)

the good thing i guess is I’m at the verge for starting this task, which incidently doesn’t do anyhting but block for a fixed length of time and toggle an LED.

sotd wrote on Tuesday, October 23, 2007:

I have not followed this whole thread so might be in the wrong ball park here, but are you using IAR V5?  I say this because of the error “The stack pointer for stack ‘CSTACK’”.  There was a discussion on this on the yahoo group yesterday where Richard said that the FreeRTOS projects would be converted to V5 once it supported the M3 MCU.  V4 and V5 have different start up source.

yamsu wrote on Tuesday, October 23, 2007:

I’m using version IAR 4.41A but i got some newer iolpc2378.h header files from olimex and its just possible that these are for version 5. I’m still getting the CSTACK error everytime i halt the debugger.

On another note i have found yet another correction in my cstartup.s79 file I forgot to assign the SWI_handler as vPortYieldProcessor

org 0x08
    LDR      PC, =vPortYieldProcessor

Richard i hope you are following my little journey. Cus now i have made it to the tasks!!! But of course they aren’t working. The LED is lighting up but it isn’t flashing. If i stop the debugging at any time i still get The stack pointer for stack ‘CSTACK’ error

here is the code for the task (based on the example of xTaskdelay() on www.freertos.org):

void vLed( void * pvParameters ) {

portTickType xDelay, xNextTime;

// Calc the time at which we want to perform the action
// next.
xNextTime = xTaskGetTickCount () + ( portTickType ) 10;

for( ;; ) {

xDelay = xNextTime - xTaskGetTickCount (); xNextTime += ( portTickType ) 10;

// Guard against overflow

if( xDelay <= ( portTickType ) 10 )
{
vTaskDelay( xDelay );
}

// Perform action here.
//LED Toggle
FIO0PIN ^= (1UL<<13);
}

videotec wrote on Wednesday, November 28, 2007:

Hi Yamsu
I’m beginning to work on the same Olimex board with IAR compiler.
I’m a newbie on Freertos but I’ve some experience on LPC23xx. What if you send me what you did up to now and we work together on the issue? I would like to avoid working from the scratch if something is already available.
Did you already get “The Insider’s Guide to the NXP LPC2300/2400 Based Microcontrollers” by Hitex?

Alessandro