I am calling :
void vTickISR( void ) __attribute__((naked));
void vTickISR( void )
{
/* Save the context of the interrupted task. */
portSAVE_CONTEXT();
/* Increment the RTOS tick count, then look for the highest priority
task that is ready to run. */
__asm volatile( “bl vTaskIncrementTick” );
#if configUSE_PREEMPTION == 1
__asm volatile( “bl vTaskSwitchContext” );
#endif
/* clear timer interrupt. */
OSTIMER1_CTRL |= 0x00000008;
/* Restore the context of the new task. */
portRESTORE_CONTEXT();
From my IRQ_Handler and program execution never returns back to IRQ_Handler, instead it eventually enters again the IRQ_Handler from the beggining eventhough IRQ is disabled. This eventually causes the stack corruption and program hangs.
void IRQ_Handler(void) __attribute__((interrupt (”IRQ”)));
void IRQ_Handler(void)
{
__asm volatile( “bl vTickISR” );
}
If I leave out the Call to vTickIsr above and replace it with nop’s the code execution completes the IRQ_Handler and returns PC to the previous location before exception happened. And, everthing works fine.. I can get endless interrupts, but tick count is not being incremented.
I have tried using portENTER_CRITICAL(); and portENTER_CRITICAL(); around the call to vTickIsr in IRQ_Handler but that doesnt make much difference.
How do I call vTickIsr() from IRQ_Handler? Or must it be called outside the context of the IRQ?
This seems to be the last item keeping me from running the OS on my platform..
I am using ARM7_LPC2138_Rowley sample project with Xstudio on an ARM926ej-s processor.. Its actually a dual core though, but other side is disabled.
Can some one shed some light on this?
Thanks,
Ozmit
Can vTickIsr() be called from IRQ_Handler?
Can vTickIsr() be called from IRQ_Handler?
Left out this:
“If I leave out the Call to vTickIsr above and replace it with nop’s the code execution completes the IRQ_Handler and returns PC to the previous location before exception happened. And, everthing works fine.. I can get endless interrupts, but tick count is not being incremented.”
I also add clearing the timer Interrupt flag naturally so code can return back to regular program execution until the next timer Interrupt occurs.
Ozmit
Can vTickIsr() be called from IRQ_Handler?
There are two important things here.
1) Context switches can occur from a tick interrupt, or from a SWI interrupt. In both cases, the stack frame must be identical because a task may be switched out from an SWI and in from a tick, or visa versa.
2) Because your ISR is naked, the function will not have a stack frame. All the code in your ISR is asm code, which is fine, other than “OSTIMER1_CTRL |= 0x00000008;”, which is C code. Have you checked that the C code is not attempting to use the stack?
I would not recommend changing the code from the example you are copying, unless you can step through the asm code and know for sure why the change is necessary and why it is ok once it has changed (keeping in mind point 1 above).
Personally I would first try to ascertain why the function is not returning – at what point does it go wrong and why – and that will probably require stepping through the C code until something goes wrong, then returning to the same point and stepping through the assembly code.
Regards.
Can vTickIsr() be called from IRQ_Handler?
The code does not touch the stack.
#define OSTIMER1_BASE (0xD0050000UL)
#define OSTIMER1_CTRL (*(volatile unsigned long *)OSTIMER1_BASE) Compiles to: E59F3054 ldr r3, 0x00008064 <vTickISR+0xC0>
E59F2050 ldr r2, 0x00008064 <vTickISR+0xC0>
E5922000 ldr r2,
E3822008 orr r2, r2, #8
E5832000 str r2, I will look into finding out why it doesnt return back to the IRQ_Handler. Thanks,
Ozmit
#define OSTIMER1_CTRL (*(volatile unsigned long *)OSTIMER1_BASE) Compiles to: E59F3054 ldr r3, 0x00008064 <vTickISR+0xC0>
E59F2050 ldr r2, 0x00008064 <vTickISR+0xC0>
E5922000 ldr r2,
E3822008 orr r2, r2, #8
E5832000 str r2, I will look into finding out why it doesnt return back to the IRQ_Handler. Thanks,
Ozmit
Can vTickIsr() be called from IRQ_Handler?
Richard,
After the code returns from the call to TaskSwitchContext, the timer is Interrupt flag is cleared(In vTickIsr). Then the portRestoreContext macro executes and this is where the problem seems to be happening.
Instead of returning back to the IRQ_Handler, the code returns to :
static portTASK_FUNCTION( prvSemaphoreTest, pvParameters )
{
E92D4800 push {r11, lr}
E28DB004 add r11, sp, #4
E24DD018 sub sp, sp, #24
E50B001C str r0, Which was probably where the execution was prior to the Timer Interrupt triggering. Isnt it suppose to return to the IRQ_Handler to restore stack values that were pushed? The other problem I dont understand is that since I am tracing through the end of vTckIsr, in the portRESTORE_CONTEXT macro, my timer interrupt triggers again, and all though IRQ is disabled, this vector is fetched. In order to see what was really going on, I disabled the Timer interrupt for now after my first Interrupt. Why would this be happening? Thanks,
Ozmit
{
E92D4800 push {r11, lr}
E28DB004 add r11, sp, #4
E24DD018 sub sp, sp, #24
E50B001C str r0, Which was probably where the execution was prior to the Timer Interrupt triggering. Isnt it suppose to return to the IRQ_Handler to restore stack values that were pushed? The other problem I dont understand is that since I am tracing through the end of vTckIsr, in the portRESTORE_CONTEXT macro, my timer interrupt triggers again, and all though IRQ is disabled, this vector is fetched. In order to see what was really going on, I disabled the Timer interrupt for now after my first Interrupt. Why would this be happening? Thanks,
Ozmit
Can vTickIsr() be called from IRQ_Handler?
Richard,
This is what my IRQ_Handler looks like in asm. For now I just assume Im here for the Timer INT.
void IRQ_Handler(void)
{
E52DB004 str r11, !
E28DB000 add r11, sp, #0
— mainISR.c – 130 ————————– __asm volatile( “bl vTickISR” );
EB001577 bl 0x00007FA4 <vTickISR>
— mainISR.c – 136 ————————– }
E28BD000 add sp, r11, #0
E8BD0800 pop {r11}
E25EF004 subs pc, lr, #4 Does this look right?
{
E52DB004 str r11, !
E28DB000 add r11, sp, #0
— mainISR.c – 130 ————————– __asm volatile( “bl vTickISR” );
EB001577 bl 0x00007FA4 <vTickISR>
— mainISR.c – 136 ————————– }
E28BD000 add sp, r11, #0
E8BD0800 pop {r11}
E25EF004 subs pc, lr, #4 Does this look right?
Can vTickIsr() be called from IRQ_Handler?
Ok – I missed this the first time on reading but it has become clearer after reading your second post.
From your other posts I seem to recall you are using an ARM9, is this correct? If it is then you need to be vectoring directly to the vTickISR(), and not vectoring to IRQ_Handler and then having IRQ_Handler call vTickISR(). vTickISR() *is* the handler and has to be so the save context macro is the first thing that runs. The save context macro has the entry code.
Regards.
Can vTickIsr() be called from IRQ_Handler?
Richard,
For right now, my system only generates the Timer INT, but eventually other things in my system can cause an interrupt of which all of them are fetched from the same Vector IRQ_INT(0x00000018). Do I add code in vTickIsr() to mask out non Timer INTs? and jump to those ISR’s repectively? Wouldn’t that cause a similar problem?
Also are you saying that only when I get a Timer INT, I need to engage OS by calling vTaskSwitchContext()?
Thanks,
Ozzy
Ozzy
Can vTickIsr() be called from IRQ_Handler?
Does your MCU have an interrupt controller that allows vectoring directly to a specific ISR? This is common, and the interrupt controller provides a register that holds the address of the correct ISR to execute, and the IRQ vector itself is populated with a simple jump to that address.
When this is the case, you have two ways of writing your interrupt:
1) You can either write each handler separately, and have the save context and restore context code in each interrupt handler, and the IRQ vector populated with code that just immediately branches to the right palce, or…
2) You can install a single interrupt handler so the save and restore context code only appears in one place, and have the interrupt handler read the address to jump to itself.
In both cases, the first code executed *must* be the portSAVE_CONTEXT() macro because that expects the stack frame to be exactly as that set up for each task when the task is created.
If your interrupt controller is less sophisticated and only allows a single entry point, then you have to use method 2 as above.
The same is true of all interrupts that can cause a context switch – the first code that executes (other than a branch to the ISR) must be the portSAVE_CONTEXT() macro. To that end, the tick interrupt is no different to any other interrupt that causes a context switch – the context is saved, C code is executed, and the context is restored. If the C code includes code that switches the TCB pointer then the task that is restored could be different to that which was saved.
I’m sure it is possible to have other configurations, some of which may required the stack set up for a task when it is created to be modified, and others maybe for the stack frame to remain the same, but having portSAVE_CONTEXT execute first is the way it is designed to work at the moment.
So to answer your question (eventually), because the ARM 7/9 (unlike Cortex-M) ports does not have interrupt nesting there is no need to mask out other interrupt anywhere, and the tick interrupt does not need to call any other interrupts as each interrupt should be called separately (although may share an entry point as per scenario 2 above – which only a couple of demos actually use).
I hope I have helped and not caused more confusion.
Regards.
Can vTickIsr() be called from IRQ_Handler?
OK… some what confusing but I think I get it.
I am obviously scenario #2 as my MCU does not have the luxury of installing ISR routines in registers so that they are fetched immediately. I have to first index into a table in RAM that has the address of the ISR functions and then call that function.
So In my IRQ Handler will look something like this:
void IRQ_Handler(void) __attribute__((interrupt (”IRQ”), naked));
void IRQ_Handler(void)
{ /* Save the context of the interrupted task. */
portSAVE_CONTEXT(); if Timer Interrupt
{
/* Increment the RTOS tick count, then look for the highest priority
task that is ready to run. */
__asm volatile( “bl vTaskIncrementTick” ); #if configUSE_PREEMPTION == 1
__asm volatile( “bl vTaskSwitchContext” );
#endif /* clear timer interrupt. */
OSTIMER1_CTRL |= 0x00000008;
//OSTIMER1_CTRL = 0x00000000A;
}
esle
{
look up Index in ISR Function Table
bl – to that ISR }
/* Restore the context of the new task. */
portRESTORE_CONTEXT(); } Should I make the Handler Naked? Thanks!
Ozmit
{ /* Save the context of the interrupted task. */
portSAVE_CONTEXT(); if Timer Interrupt
{
/* Increment the RTOS tick count, then look for the highest priority
task that is ready to run. */
__asm volatile( “bl vTaskIncrementTick” ); #if configUSE_PREEMPTION == 1
__asm volatile( “bl vTaskSwitchContext” );
#endif /* clear timer interrupt. */
OSTIMER1_CTRL |= 0x00000008;
//OSTIMER1_CTRL = 0x00000000A;
}
esle
{
look up Index in ISR Function Table
bl – to that ISR }
/* Restore the context of the new task. */
portRESTORE_CONTEXT(); } Should I make the Handler Naked? Thanks!
Ozmit
Can vTickIsr() be called from IRQ_Handler?
Richard,
I tried what you suggest both making ISR Naked or not and still have the same problem that the PC never gets to the end of the IRQ_Handler and return to the previous code that the processor was executing.
Here is my latest IRQ_Handler:
void IRQ_Handler(void) __attribute__((interrupt (”IRQ”))); void IRQ_Handler(void)
{ /* Save the context of the interrupted task. */
portSAVE_CONTEXT(); /* Increment the RTOS tick count, then look for the highest priority
task that is ready to run. */
__asm volatile( “bl vTaskIncrementTick” ); #if configUSE_PREEMPTION == 1
__asm volatile( “bl vTaskSwitchContext” );
#endif /* clear timer interrupt. */
OSTIMER1_CTRL |= 0x00000008;
//OSTIMER1_CTRL = 0x00000000A;
/* Restore the context of the new task. */ portRESTORE_CONTEXT(); } The bottom line is when the Context is restored, The PC is not pointing back to the end of the IRQ_Handler Routine. Here is the ASM of the Handler: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void IRQ_Handler(void)
{
E92D080C push {r2-r3, r11}
E28DB008 add r11, sp, #8
— mainISR.c – 129 ————————–
/* Save the context of the interrupted task. */
portSAVE_CONTEXT();
E92D0001 push {r0}
E94D2000 stmdb sp, {sp}^
E1A00000 mov r0, r0
E24DD004 sub sp, sp, #4
E8BD0001 pop {r0}
E9204000 stmdb r0!, {lr}
E1A0E000 mov lr, r0
E8BD0001 pop {r0}
E94E7FFF stmdb lr, {r0-lr}^
E1A00000 mov r0, r0
E24EE03C sub lr, lr, #0x3C
E14F0000 mrs r0, spsr
E92E0001 stmdb lr!, {r0}
E59F0094 ldr r0, 0x00002A90 <IRQ_Handler+0xD8>
E5900000 ldr r0,
E92E0001 stmdb lr!, {r0}
E59F008C ldr r0, 0x00002A94 <IRQ_Handler+0xDC>
E5900000 ldr r0,
E580E000 str lr,
E59F3070 ldr r3, 0x00002A84 <IRQ_Handler+0xCC>
E5933000 ldr r3,
E59F306C ldr r3, 0x00002A88 <IRQ_Handler+0xD0>
E5933000 ldr r3,
— mainISR.c – 133 ————————–
/* Increment the RTOS tick count, then look for the highest priority
task that is ready to run. */
__asm volatile( “bl vTaskIncrementTick” );
EB0010B7 bl 0x00006D00 <vTaskIncrementTick>
— mainISR.c – 138 ————————–
#if configUSE_PREEMPTION == 1
__asm volatile( “bl vTaskSwitchContext” );
EB00113C bl 0x00006F18 <vTaskSwitchContext>
— mainISR.c – 141 ————————–
#endif
/* clear timer interrupt. */
OSTIMER1_CTRL |= 0x00000008;
E59F3060 ldr r3, 0x00002A8C <IRQ_Handler+0xD4>
E59F205C ldr r2, 0x00002A8C <IRQ_Handler+0xD4>
E5922000 ldr r2,
E3822008 orr r2, r2, #8
E5832000 str r2,
— mainISR.c – 145 ————————–
//OSTIMER1_CTRL = 0x00000000A;
/* Restore the context of the new task. */
portRESTORE_CONTEXT();
E59F0054 ldr r0, 0x00002A94 <IRQ_Handler+0xDC>
E5900000 ldr r0,
E590E000 ldr lr,
E59F0044 ldr r0, 0x00002A90 <IRQ_Handler+0xD8>
E8BE0002 ldm lr!, {r1}
E5801000 str r1,
E8BE0001 ldm lr!, {r0}
E169F000 msr spsr_cf, r0
E8DE7FFF ldmia lr, {r0-lr}^
E1A00000 mov r0, r0
E59EE03C ldr lr,
E25EF004 subs pc, lr, #4
E59F3014 ldr r3, 0x00002A84 <IRQ_Handler+0xCC>
E5933000 ldr r3,
E59F3010 ldr r3, 0x00002A88 <IRQ_Handler+0xD0>
E5933000 ldr r3,
— mainISR.c – 149 ————————–
}
E24BD008 sub sp, r11, #8
E8BD080C pop {r2-r3, r11}
E25EF004 subs pc, lr, #4
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The strange this is the compiler is placing the parethesis at the end of the Restore context Macro, when in fact the end should be the restore of resgisters and reload of PC and SPSR… E24BD008 sub sp, r11, #8
E8BD080C pop {r2-r3, r11}
E25EF004 subs pc, lr, #4 Here is my stack configuration, just in case you see a problem with that.
.heap 0x0000f9b4 0x400
0x0000f9b4 __heap_start__ = .
*(.heap .heap.*)
0x0000fdb4 . = ALIGN (MAX ((__heap_start__ + __HEAPSIZE__), .), 0x4)
*fill* 0x0000f9b4 0x400 00
0x0000fdb4 __heap_end__ = (__heap_start__ + SIZEOF (.heap))
0x0000fdb4 __heap_load_end__ = __heap_end__
0x00000001 . = ASSERT (((__heap_end__ >= __SRAM_segment_start__) && (__heap_end__ <= __SRAM_segment_end__)), error: .heap is too large to fit in SRAM memory segment)
0x0000fdb4 __stack_load_start__ = ALIGN (__heap_end__, 0x4) .stack 0x0000fdb4 0x400
0x0000fdb4 __stack_start__ = .
*(.stack .stack.*)
0x000101b4 . = ALIGN (MAX ((__stack_start__ + __STACKSIZE__), .), 0x4)
*fill* 0x0000fdb4 0x400 00
0x000101b4 __stack_end__ = (__stack_start__ + SIZEOF (.stack))
0x000101b4 __stack_load_end__ = __stack_end__
0x00000001 . = ASSERT (((__stack_end__ >= __SRAM_segment_start__) && (__stack_end__ <= __SRAM_segment_end__)), error: .stack is too large to fit in SRAM memory segment)
0x000101b4 __stack_irq_load_start__ = ALIGN (__stack_end__, 0x4) .stack_irq 0x000101b4 0x100
0x000101b4 __stack_irq_start__ = .
*(.stack_irq .stack_irq.*)
0x000102b4 . = ALIGN (MAX ((__stack_irq_start__ + __STACKSIZE_IRQ__), .), 0x4)
*fill* 0x000101b4 0x100 00
0x000102b4 __stack_irq_end__ = (__stack_irq_start__ + SIZEOF (.stack_irq))
0x000102b4 __stack_irq_load_end__ = __stack_irq_end__
0x00000001 . = ASSERT (((__stack_irq_end__ >= __SRAM_segment_start__) && (__stack_irq_end__ <= __SRAM_segment_end__)), error: .stack_irq is too large to fit in SRAM memory segment)
0x000102b4 __stack_fiq_load_start__ = ALIGN (__stack_irq_end__, 0x4) .stack_fiq 0x000102b4 0x100
0x000102b4 __stack_fiq_start__ = .
*(.stack_fiq .stack_fiq.*)
0x000103b4 . = ALIGN (MAX ((__stack_fiq_start__ + __STACKSIZE_FIQ__), .), 0x4)
*fill* 0x000102b4 0x100 00
0x000103b4 __stack_fiq_end__ = (__stack_fiq_start__ + SIZEOF (.stack_fiq))
0x000103b4 __stack_fiq_load_end__ = __stack_fiq_end__
0x00000001 . = ASSERT (((__stack_fiq_end__ >= __SRAM_segment_start__) && (__stack_fiq_end__ <= __SRAM_segment_end__)), error: .stack_fiq is too large to fit in SRAM memory segment)
0x000103b4 __stack_svc_load_start__ = ALIGN (__stack_fiq_end__, 0x4) .stack_svc 0x000103b4 0x200
0x000103b4 __stack_svc_start__ = .
*(.stack_svc .stack_svc.*)
0x000105b4 . = ALIGN (MAX ((__stack_svc_start__ + __STACKSIZE_SVC__), .), 0x4)
*fill* 0x000103b4 0x200 00
0x000105b4 __stack_svc_end__ = (__stack_svc_start__ + SIZEOF (.stack_svc))
0x000105b4 __stack_svc_load_end__ = __stack_svc_end__
0x00000001 . = ASSERT (((__stack_svc_end__ >= __SRAM_segment_start__) && (__stack_svc_end__ <= __SRAM_segment_end__)), error: .stack_svc is too large to fit in SRAM memory segment)
0x000105b4 __stack_abt_load_start__ = ALIGN (__stack_svc_end__, 0x4) .stack_abt 0x000105b4 0x0
0x000105b4 __stack_abt_start__ = .
*(.stack_abt .stack_abt.*)
0x000105b4 . = ALIGN (MAX ((__stack_abt_start__ + __STACKSIZE_ABT__), .), 0x4)
0x000105b4 __stack_abt_end__ = (__stack_abt_start__ + SIZEOF (.stack_abt))
0x000105b4 __stack_abt_load_end__ = __stack_abt_end__
0x00000001 . = ASSERT (((__stack_abt_end__ >= __SRAM_segment_start__) && (__stack_abt_end__ <= __SRAM_segment_end__)), error: .stack_abt is too large to fit in SRAM memory segment)
0x000105b4 __stack_und_load_start__ = ALIGN (__stack_abt_end__, 0x4) .stack_und 0x000105b4 0x0
0x000105b4 __stack_und_start__ = .
*(.stack_und .stack_und.*)
0x000105b4 . = ALIGN (MAX ((__stack_und_start__ + __STACKSIZE_UND__), .), 0x4)
0x000105b4 __stack_und_end__ = (__stack_und_start__ + SIZEOF (.stack_und))
0x000105b4 __stack_und_load_end__ = __stack_und_end__
0x00000001 . = ASSERT (((__stack_und_end__ >= __SRAM_segment_start__) && (__stack_und_end__ <= __SRAM_segment_end__)), error: .stack_und is too large to fit in SRAM memory segment)
0x000105b4 __tbss_load_start__ = ALIGN (__stack_und_end__, 0x4) Thanks Ozmit
void IRQ_Handler(void) __attribute__((interrupt (”IRQ”))); void IRQ_Handler(void)
{ /* Save the context of the interrupted task. */
portSAVE_CONTEXT(); /* Increment the RTOS tick count, then look for the highest priority
task that is ready to run. */
__asm volatile( “bl vTaskIncrementTick” ); #if configUSE_PREEMPTION == 1
__asm volatile( “bl vTaskSwitchContext” );
#endif /* clear timer interrupt. */
OSTIMER1_CTRL |= 0x00000008;
//OSTIMER1_CTRL = 0x00000000A;
/* Restore the context of the new task. */ portRESTORE_CONTEXT(); } The bottom line is when the Context is restored, The PC is not pointing back to the end of the IRQ_Handler Routine. Here is the ASM of the Handler: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void IRQ_Handler(void)
{
E92D080C push {r2-r3, r11}
E28DB008 add r11, sp, #8
— mainISR.c – 129 ————————–
/* Save the context of the interrupted task. */
portSAVE_CONTEXT();
E92D0001 push {r0}
E94D2000 stmdb sp, {sp}^
E1A00000 mov r0, r0
E24DD004 sub sp, sp, #4
E8BD0001 pop {r0}
E9204000 stmdb r0!, {lr}
E1A0E000 mov lr, r0
E8BD0001 pop {r0}
E94E7FFF stmdb lr, {r0-lr}^
E1A00000 mov r0, r0
E24EE03C sub lr, lr, #0x3C
E14F0000 mrs r0, spsr
E92E0001 stmdb lr!, {r0}
E59F0094 ldr r0, 0x00002A90 <IRQ_Handler+0xD8>
E5900000 ldr r0,
E92E0001 stmdb lr!, {r0}
E59F008C ldr r0, 0x00002A94 <IRQ_Handler+0xDC>
E5900000 ldr r0,
E580E000 str lr,
E59F3070 ldr r3, 0x00002A84 <IRQ_Handler+0xCC>
E5933000 ldr r3,
E59F306C ldr r3, 0x00002A88 <IRQ_Handler+0xD0>
E5933000 ldr r3,
— mainISR.c – 133 ————————–
/* Increment the RTOS tick count, then look for the highest priority
task that is ready to run. */
__asm volatile( “bl vTaskIncrementTick” );
EB0010B7 bl 0x00006D00 <vTaskIncrementTick>
— mainISR.c – 138 ————————–
#if configUSE_PREEMPTION == 1
__asm volatile( “bl vTaskSwitchContext” );
EB00113C bl 0x00006F18 <vTaskSwitchContext>
— mainISR.c – 141 ————————–
#endif
/* clear timer interrupt. */
OSTIMER1_CTRL |= 0x00000008;
E59F3060 ldr r3, 0x00002A8C <IRQ_Handler+0xD4>
E59F205C ldr r2, 0x00002A8C <IRQ_Handler+0xD4>
E5922000 ldr r2,
E3822008 orr r2, r2, #8
E5832000 str r2,
— mainISR.c – 145 ————————–
//OSTIMER1_CTRL = 0x00000000A;
/* Restore the context of the new task. */
portRESTORE_CONTEXT();
E59F0054 ldr r0, 0x00002A94 <IRQ_Handler+0xDC>
E5900000 ldr r0,
E590E000 ldr lr,
E59F0044 ldr r0, 0x00002A90 <IRQ_Handler+0xD8>
E8BE0002 ldm lr!, {r1}
E5801000 str r1,
E8BE0001 ldm lr!, {r0}
E169F000 msr spsr_cf, r0
E8DE7FFF ldmia lr, {r0-lr}^
E1A00000 mov r0, r0
E59EE03C ldr lr,
E25EF004 subs pc, lr, #4
E59F3014 ldr r3, 0x00002A84 <IRQ_Handler+0xCC>
E5933000 ldr r3,
E59F3010 ldr r3, 0x00002A88 <IRQ_Handler+0xD0>
E5933000 ldr r3,
— mainISR.c – 149 ————————–
}
E24BD008 sub sp, r11, #8
E8BD080C pop {r2-r3, r11}
E25EF004 subs pc, lr, #4
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The strange this is the compiler is placing the parethesis at the end of the Restore context Macro, when in fact the end should be the restore of resgisters and reload of PC and SPSR… E24BD008 sub sp, r11, #8
E8BD080C pop {r2-r3, r11}
E25EF004 subs pc, lr, #4 Here is my stack configuration, just in case you see a problem with that.
.heap 0x0000f9b4 0x400
0x0000f9b4 __heap_start__ = .
*(.heap .heap.*)
0x0000fdb4 . = ALIGN (MAX ((__heap_start__ + __HEAPSIZE__), .), 0x4)
*fill* 0x0000f9b4 0x400 00
0x0000fdb4 __heap_end__ = (__heap_start__ + SIZEOF (.heap))
0x0000fdb4 __heap_load_end__ = __heap_end__
0x00000001 . = ASSERT (((__heap_end__ >= __SRAM_segment_start__) && (__heap_end__ <= __SRAM_segment_end__)), error: .heap is too large to fit in SRAM memory segment)
0x0000fdb4 __stack_load_start__ = ALIGN (__heap_end__, 0x4) .stack 0x0000fdb4 0x400
0x0000fdb4 __stack_start__ = .
*(.stack .stack.*)
0x000101b4 . = ALIGN (MAX ((__stack_start__ + __STACKSIZE__), .), 0x4)
*fill* 0x0000fdb4 0x400 00
0x000101b4 __stack_end__ = (__stack_start__ + SIZEOF (.stack))
0x000101b4 __stack_load_end__ = __stack_end__
0x00000001 . = ASSERT (((__stack_end__ >= __SRAM_segment_start__) && (__stack_end__ <= __SRAM_segment_end__)), error: .stack is too large to fit in SRAM memory segment)
0x000101b4 __stack_irq_load_start__ = ALIGN (__stack_end__, 0x4) .stack_irq 0x000101b4 0x100
0x000101b4 __stack_irq_start__ = .
*(.stack_irq .stack_irq.*)
0x000102b4 . = ALIGN (MAX ((__stack_irq_start__ + __STACKSIZE_IRQ__), .), 0x4)
*fill* 0x000101b4 0x100 00
0x000102b4 __stack_irq_end__ = (__stack_irq_start__ + SIZEOF (.stack_irq))
0x000102b4 __stack_irq_load_end__ = __stack_irq_end__
0x00000001 . = ASSERT (((__stack_irq_end__ >= __SRAM_segment_start__) && (__stack_irq_end__ <= __SRAM_segment_end__)), error: .stack_irq is too large to fit in SRAM memory segment)
0x000102b4 __stack_fiq_load_start__ = ALIGN (__stack_irq_end__, 0x4) .stack_fiq 0x000102b4 0x100
0x000102b4 __stack_fiq_start__ = .
*(.stack_fiq .stack_fiq.*)
0x000103b4 . = ALIGN (MAX ((__stack_fiq_start__ + __STACKSIZE_FIQ__), .), 0x4)
*fill* 0x000102b4 0x100 00
0x000103b4 __stack_fiq_end__ = (__stack_fiq_start__ + SIZEOF (.stack_fiq))
0x000103b4 __stack_fiq_load_end__ = __stack_fiq_end__
0x00000001 . = ASSERT (((__stack_fiq_end__ >= __SRAM_segment_start__) && (__stack_fiq_end__ <= __SRAM_segment_end__)), error: .stack_fiq is too large to fit in SRAM memory segment)
0x000103b4 __stack_svc_load_start__ = ALIGN (__stack_fiq_end__, 0x4) .stack_svc 0x000103b4 0x200
0x000103b4 __stack_svc_start__ = .
*(.stack_svc .stack_svc.*)
0x000105b4 . = ALIGN (MAX ((__stack_svc_start__ + __STACKSIZE_SVC__), .), 0x4)
*fill* 0x000103b4 0x200 00
0x000105b4 __stack_svc_end__ = (__stack_svc_start__ + SIZEOF (.stack_svc))
0x000105b4 __stack_svc_load_end__ = __stack_svc_end__
0x00000001 . = ASSERT (((__stack_svc_end__ >= __SRAM_segment_start__) && (__stack_svc_end__ <= __SRAM_segment_end__)), error: .stack_svc is too large to fit in SRAM memory segment)
0x000105b4 __stack_abt_load_start__ = ALIGN (__stack_svc_end__, 0x4) .stack_abt 0x000105b4 0x0
0x000105b4 __stack_abt_start__ = .
*(.stack_abt .stack_abt.*)
0x000105b4 . = ALIGN (MAX ((__stack_abt_start__ + __STACKSIZE_ABT__), .), 0x4)
0x000105b4 __stack_abt_end__ = (__stack_abt_start__ + SIZEOF (.stack_abt))
0x000105b4 __stack_abt_load_end__ = __stack_abt_end__
0x00000001 . = ASSERT (((__stack_abt_end__ >= __SRAM_segment_start__) && (__stack_abt_end__ <= __SRAM_segment_end__)), error: .stack_abt is too large to fit in SRAM memory segment)
0x000105b4 __stack_und_load_start__ = ALIGN (__stack_abt_end__, 0x4) .stack_und 0x000105b4 0x0
0x000105b4 __stack_und_start__ = .
*(.stack_und .stack_und.*)
0x000105b4 . = ALIGN (MAX ((__stack_und_start__ + __STACKSIZE_UND__), .), 0x4)
0x000105b4 __stack_und_end__ = (__stack_und_start__ + SIZEOF (.stack_und))
0x000105b4 __stack_und_load_end__ = __stack_und_end__
0x00000001 . = ASSERT (((__stack_und_end__ >= __SRAM_segment_start__) && (__stack_und_end__ <= __SRAM_segment_end__)), error: .stack_und is too large to fit in SRAM memory segment)
0x000105b4 __tbss_load_start__ = ALIGN (__stack_und_end__, 0x4) Thanks Ozmit
Can vTickIsr() be called from IRQ_Handler?
Richard,
When I remove the context switching from the IRQ Handler code, it works perfect. Bad things happen when I try portRESTORE_CONTEXT();
Can there be something wrong with the Startup.s file? Maybe I have omitted something? Or even crto.s file the Rowley creates?
Thanks,
Ozmit
Ozmit
Can vTickIsr() be called from IRQ_Handler?
Another piece of Info is that the code is executing in System Mode is that the norm?
Out of Reset its Supervisor and in IRQ Handler its IRQ mode of course. But after Context Switch its stays in System mode.
Hope this is a clue.
Ozmit
Can vTickIsr() be called from IRQ_Handler?
Richard,
What ever clues, hints, suggestions etc, you can share before you leave for the weekend would greatly be appreciated. Im trying to get this OS up and running for a customer that will be licensing FreeRTOS through OpenRTOS.
Have a great weekend.
Ozmit
Can vTickIsr() be called from IRQ_Handler?
I have actually answered this already, don’t know why it didn’t show up. Maybe I closed the browser window too soon.
You need to set up stacks for Supervisor mode and IRQ mode. FIQ mode too if you use FIQ, there is another thread on the limitations of doing that.
main() should be called in Supervisor mode. When the tasks run the MCU will be in System mode, but you don’t need to set up a system mode stack because the stack is allocated from the FreeRTOS heap when the task is created. When an interrupt is taken the MCU automatically enters IRQ mode and returns back to System mode when the interrupt completes.
Regards.
Can vTickIsr() be called from IRQ_Handler?
My stacks are setup per my previous reply. System Stack, IRQ, FIQ and Supervisor. I didnt know about the System stack so I defined it anyways. The CrossStudio project properties file did not have one defined so I guess it was done for a purpose. I will remove it then. But, It doesnt affect the outcome.
Modes are setup as per your request.
I have it working finally, I the tick count is being incremented and I am getting the “Pass” message to print out of the Debug Terminal window.
void IRQ_Handler(void) __attribute__((interrupt (”IRQ”), naked));
void IRQ_Handler(void)
{ /* Save the context of the interrupted task. */
portSAVE_CONTEXT(); /* Increment the RTOS tick count, then look for the highest priority
task that is ready to run. */
__asm volatile( “bl vTaskIncrementTick” ); #if configUSE_PREEMPTION == 1
__asm volatile( “bl vTaskSwitchContext” );
#endif /* clear timer interrupt. */
OSTIMER1_CTRL |= 0x00000008; portRESTORE_CONTEXT(); } Now I have to write the other ISR handlers for my system. Thanks!
Ozmit
void IRQ_Handler(void)
{ /* Save the context of the interrupted task. */
portSAVE_CONTEXT(); /* Increment the RTOS tick count, then look for the highest priority
task that is ready to run. */
__asm volatile( “bl vTaskIncrementTick” ); #if configUSE_PREEMPTION == 1
__asm volatile( “bl vTaskSwitchContext” );
#endif /* clear timer interrupt. */
OSTIMER1_CTRL |= 0x00000008; portRESTORE_CONTEXT(); } Now I have to write the other ISR handlers for my system. Thanks!
Ozmit
Can vTickIsr() be called from IRQ_Handler?
Hello Ozmit,
Could you please share what was your exact problem and what you did to solve it ?
I get the feeling from your last reply that stack wasn’t your problem. Thanks,
Kaustubh
I get the feeling from your last reply that stack wasn’t your problem. Thanks,
Kaustubh
Can vTickIsr() be called from IRQ_Handler?
Kaustubh,
It seems like the context switching was corrupting the stack. The stack were defined so that wasnt the problem.
My first IRQ_HANDLER was not “Naked” and was calling vTickISR in C. Richard quickly pointed out that I basically had to remove that call and make vTickIsr my IRQ_Handler. I made this change but still was having an issue because the Function was still not declared as naked. THerefore it was touching the stack at the begging and the end. This was a problem because after calling macro portRESTORE_CONTEXT() everything is popped from the stack leaving the stack code at the end of the IRQ_Handler dangling and thus leading to stack corruption.
I hope that helps..
Ozmit
Can vTickIsr() be called from IRQ_Handler?
Hello Ozmit,
So IIUC, in _non_ FreeRTOS case the “__attribute__((interrupt (”IRQ”)))” is enough but since FreeRTOS uses portRESTORE_CONTEXT and thus does the restoration itself (without depending on the compiler), adding “naked” attribute is mandatory.
Regards,
Kaustubh
Kaustubh
Can vTickIsr() be called from IRQ_Handler?
If you are writing a standard non FreeRTOS IRQ in a non FreeRTOS application you can use the IRQ function attribute if you are lucky enough to have a version of GCC in which it works. Maybe it is ok in newer copies of GCC, but when the port was written different GCC versions had different (and very subtle) IRQ attribute bugs that made it easier just to write the entry/exit code yourself.
If you are writing an IRQ in a FreeRTOS application and the IRQ can perform a context switch then you must use the naked attribute as described above and must *not* use the IRQ attribute.
Regards.
Can vTickIsr() be called from IRQ_Handler?
Richard,
I left the IRQ attribute on mine and it seems to be working just fine. I am using Rowley’s Cross Studio ver 2.2.0.
The naked attribute coupled with not having to make the extra call from the IRQ instead making my IRQ vTickIsr() where the keys.
Thanks again,
Ozmit
Ozmit
Can vTickIsr() be called from IRQ_Handler?
Richard,
Question, now that I have the IRQ_Handler working, I need to add checks for the other system Interrupt sources, like buttons, I/O, DMA, etc.
Can I call another Handler routine that will do these functions from the IRQ handler using C function calls, or must I use “fromISR” calls to do this.
example:
I get a an interrupt for a button press, and that event requires an action of some type. Do I perform that action within the context of the IRQ or do I wait to return from the IRQ to begin that action? Do I send a message to that task to signal to it that an action needs to take place?
What is the best method?
Thanks,
Ozmit
Ozmit