Can vTickIsr() be called from IRQ_Handler?

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?

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

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

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?

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

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

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

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

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

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

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

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

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