Port for LPC2364/66/68/78
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
Port for LPC2364/66/68/78
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.
Port for LPC2364/66/68/78
Ok, thanks for the quick responce…..
/Peter
Port for LPC2364/66/68/78
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.
Port for LPC2364/66/68/78
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.
Port for LPC2364/66/68/78
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
Port for LPC2364/66/68/78
I’m not aware of a problem with __disableinterrupt(). This is an IAR function I think? Are you calling main() from Supervisor mode?
Regards.
Port for LPC2364/66/68/78
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
Port for LPC2364/66/68/78
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
Port for LPC2364/66/68/78
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.
Port for LPC2364/66/68/78
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.
Port for LPC2364/66/68/78
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);
}
}
Port for LPC2364/66/68/78
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