Can vTickIsr() be called from IRQ_Handler?

ozsmit wrote on Thursday, November 15, 2012:

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

ozsmit wrote on Thursday, November 15, 2012:

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

rtel wrote on Thursday, November 15, 2012:

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.

ozsmit wrote on Thursday, November 15, 2012:

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

ozsmit wrote on Thursday, November 15, 2012:

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

ozsmit wrote on Thursday, November 15, 2012:

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?

rtel wrote on Thursday, November 15, 2012:

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.

ozsmit wrote on Thursday, November 15, 2012:

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

rtel wrote on Thursday, November 15, 2012:

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.

ozsmit wrote on Thursday, November 15, 2012:

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

ozsmit wrote on Thursday, November 15, 2012:

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\)  
\{  
&nbsp;&nbsp;&nbsp; E92D080C&nbsp;&nbsp;&nbsp; push \{r2-r3, r11\}  
&nbsp;&nbsp;&nbsp; E28DB008&nbsp;&nbsp;&nbsp; add r11, sp, \#8  
-- mainISR.c - 129 --------------------------  
/\* Save the context of the interrupted task. \*/  
portSAVE\_CONTEXT\(\);  
&nbsp;&nbsp;&nbsp; E92D0001&nbsp;&nbsp;&nbsp; push \{r0\}  
&nbsp;&nbsp;&nbsp; E94D2000&nbsp;&nbsp;&nbsp; stmdb sp, \{sp\}^  
&nbsp;&nbsp;&nbsp; E1A00000&nbsp;&nbsp;&nbsp; mov r0, r0  
&nbsp;&nbsp;&nbsp; E24DD004&nbsp;&nbsp;&nbsp; sub sp, sp, \#4  
&nbsp;&nbsp;&nbsp; E8BD0001&nbsp;&nbsp;&nbsp; pop \{r0\}  
&nbsp;&nbsp;&nbsp; E9204000&nbsp;&nbsp;&nbsp; stmdb r0\!, \{lr\}  
&nbsp;&nbsp;&nbsp; E1A0E000&nbsp;&nbsp;&nbsp; mov lr, r0  
&nbsp;&nbsp;&nbsp; E8BD0001&nbsp;&nbsp;&nbsp; pop \{r0\}  
&nbsp;&nbsp;&nbsp; E94E7FFF&nbsp;&nbsp;&nbsp; stmdb lr, \{r0-lr\}^  
&nbsp;&nbsp;&nbsp; E1A00000&nbsp;&nbsp;&nbsp; mov r0, r0  
&nbsp;&nbsp;&nbsp; E24EE03C&nbsp;&nbsp;&nbsp; sub lr, lr, \#0x3C  
&nbsp;&nbsp;&nbsp; E14F0000&nbsp;&nbsp;&nbsp; mrs r0, spsr  
&nbsp;&nbsp;&nbsp; E92E0001&nbsp;&nbsp;&nbsp; stmdb lr\!, \{r0\}  
&nbsp;&nbsp;&nbsp; E59F0094&nbsp;&nbsp;&nbsp; ldr r0, 0x00002A90 &lt;IRQ\_Handler+0xD8&gt;  
&nbsp;&nbsp;&nbsp; E5900000&nbsp;&nbsp;&nbsp; ldr r0,   
&nbsp;&nbsp;&nbsp; E92E0001&nbsp;&nbsp;&nbsp; stmdb lr\!, \{r0\}  
&nbsp;&nbsp;&nbsp; E59F008C&nbsp;&nbsp;&nbsp; ldr r0, 0x00002A94 &lt;IRQ\_Handler+0xDC&gt;  
&nbsp;&nbsp;&nbsp; E5900000&nbsp;&nbsp;&nbsp; ldr r0,   
&nbsp;&nbsp;&nbsp; E580E000&nbsp;&nbsp;&nbsp; str lr,   
&nbsp;&nbsp;&nbsp; E59F3070&nbsp;&nbsp;&nbsp; ldr r3, 0x00002A84 &lt;IRQ\_Handler+0xCC&gt;  
&nbsp;&nbsp;&nbsp; E5933000&nbsp;&nbsp;&nbsp; ldr r3,   
&nbsp;&nbsp;&nbsp; E59F306C&nbsp;&nbsp;&nbsp; ldr r3, 0x00002A88 &lt;IRQ\_Handler+0xD0&gt;  
&nbsp;&nbsp;&nbsp; E5933000&nbsp;&nbsp;&nbsp; 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" \);  
&nbsp;&nbsp;&nbsp; EB0010B7&nbsp;&nbsp;&nbsp; bl 0x00006D00 &lt;vTaskIncrementTick&gt;  
-- mainISR.c - 138 --------------------------  
\#if configUSE\_PREEMPTION == 1  
\_\_asm volatile\( "bl vTaskSwitchContext" \);  
&nbsp;&nbsp;&nbsp; EB00113C&nbsp;&nbsp;&nbsp; bl 0x00006F18 &lt;vTaskSwitchContext&gt;  
-- mainISR.c - 141 --------------------------  
\#endif  
/\* clear timer interrupt. \*/  
OSTIMER1\_CTRL |= 0x00000008;  
&nbsp;&nbsp;&nbsp; E59F3060&nbsp;&nbsp;&nbsp; ldr r3, 0x00002A8C &lt;IRQ\_Handler+0xD4&gt;  
&nbsp;&nbsp;&nbsp; E59F205C&nbsp;&nbsp;&nbsp; ldr r2, 0x00002A8C &lt;IRQ\_Handler+0xD4&gt;  
&nbsp;&nbsp;&nbsp; E5922000&nbsp;&nbsp;&nbsp; ldr r2,   
&nbsp;&nbsp;&nbsp; E3822008&nbsp;&nbsp;&nbsp; orr r2, r2, \#8  
&nbsp;&nbsp;&nbsp; E5832000&nbsp;&nbsp;&nbsp; str r2,   
-- mainISR.c - 145 --------------------------  
//OSTIMER1\_CTRL = 0x00000000A;  
/\* Restore the context of the new task. \*/  
portRESTORE\_CONTEXT\(\);  
&nbsp;&nbsp;&nbsp; E59F0054&nbsp;&nbsp;&nbsp; ldr r0, 0x00002A94 &lt;IRQ\_Handler+0xDC&gt;  
&nbsp;&nbsp;&nbsp; E5900000&nbsp;&nbsp;&nbsp; ldr r0,   
&nbsp;&nbsp;&nbsp; E590E000&nbsp;&nbsp;&nbsp; ldr lr,   
&nbsp;&nbsp;&nbsp; E59F0044&nbsp;&nbsp;&nbsp; ldr r0, 0x00002A90 &lt;IRQ\_Handler+0xD8&gt;  
&nbsp;&nbsp;&nbsp; E8BE0002&nbsp;&nbsp;&nbsp; ldm lr\!, \{r1\}  
&nbsp;&nbsp;&nbsp; E5801000&nbsp;&nbsp;&nbsp; str r1,   
&nbsp;&nbsp;&nbsp; E8BE0001&nbsp;&nbsp;&nbsp; ldm lr\!, \{r0\}  
&nbsp;&nbsp;&nbsp; E169F000&nbsp;&nbsp;&nbsp; msr spsr\_cf, r0  
&nbsp;&nbsp;&nbsp; E8DE7FFF&nbsp;&nbsp;&nbsp; ldmia lr, \{r0-lr\}^  
&nbsp;&nbsp;&nbsp; E1A00000&nbsp;&nbsp;&nbsp; mov r0, r0  
&nbsp;&nbsp;&nbsp; E59EE03C&nbsp;&nbsp;&nbsp; ldr lr,   
&nbsp;&nbsp;&nbsp; E25EF004&nbsp;&nbsp;&nbsp; subs pc, lr, \#4  
&nbsp;&nbsp;&nbsp; E59F3014&nbsp;&nbsp;&nbsp; ldr r3, 0x00002A84 &lt;IRQ\_Handler+0xCC&gt;  
&nbsp;&nbsp;&nbsp; E5933000&nbsp;&nbsp;&nbsp; ldr r3,   
&nbsp;&nbsp;&nbsp; E59F3010&nbsp;&nbsp;&nbsp; ldr r3, 0x00002A88 &lt;IRQ\_Handler+0xD0&gt;  
&nbsp;&nbsp;&nbsp; E5933000&nbsp;&nbsp;&nbsp; ldr r3,   
-- mainISR.c - 149 --------------------------  
\}  
&nbsp;&nbsp;&nbsp; E24BD008&nbsp;&nbsp;&nbsp; sub sp, r11, \#8  
&nbsp;&nbsp;&nbsp; E8BD080C&nbsp;&nbsp;&nbsp; pop \{r2-r3, r11\}  
&nbsp;&nbsp;&nbsp; E25EF004&nbsp;&nbsp;&nbsp; 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

ozsmit wrote on Thursday, November 15, 2012:

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

ozsmit wrote on Thursday, November 15, 2012:

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

ozsmit wrote on Friday, November 16, 2012:

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

rtel wrote on Saturday, November 17, 2012:

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.

ozsmit wrote on Sunday, November 18, 2012:

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

ksashtekar wrote on Monday, November 19, 2012:

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

ozsmit wrote on Monday, November 19, 2012:

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

ksashtekar wrote on Tuesday, November 20, 2012:

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

rtel wrote on Tuesday, November 20, 2012:

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.