tick ISR curiosity

anonymous wrote on Thursday, January 11, 2007:

FreeRTOS 4.1.1, GCC, LPC2…

In an attempt to eliminate round-robin scheduling of tasks of equal priority, I wrote my own tick ISR. It calls vTaskIncrementTick(), but then it calls vTaskSwitchContext() only if a task of higher priority gets scheduled. To do this, it exits the ISR with


where NeedTickSwitch() answers the question regarding relative priorities (I put it in tasks.c so it can compare uxTopReadyPriority to pxCurrentTCB->uxPriority).

This trick didn’t work. But I can’t quite get a handle on what is going wrong. My testing seems to imply vTaskSwitchContext() must always be called after vTaskIncrementTick(). I don’t see why, but is this true?

embeddedc wrote on Friday, January 12, 2007:

How about this, leave all other stuff unmodified and just change vTaskSwitchContext() as follows:

void vTaskSwitchContext( void )
static unsigned portBASE_TYPE uxLastTopReadyPriority = 0;

____if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
________xMissedYield = pdTRUE;

____while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )

____if( uxTopReadyPriority > uxLastTopReadyPriority )
________listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );
________uxLastTopReadyPriority = uxTopReadyPriority;

Would that do what you want?  I have not actually tried it, but the idea is to only select a new task to run if the top priority ready task is higher than the last time the selection function was called.

anonymous wrote on Friday, January 12, 2007:

I think that would mean taskYIELD() would not perform as expected. I don’t know what other ill effects it might have. In fact, it was this explicit control between tasks of equal priority that I was looking for.

My understanding is that ISRs are supposed to have the capability to determine whether or not they trigger a context switch using portEXIT_SWITCHING_ISR(). I would rather use a prescibed mechanism than change the kernel. But portEXIT_SWITCHING_ISR() doesn’t seem to work with the tick ISR.

Richard, can you shed any light?

rtel wrote on Friday, January 12, 2007:

I think you are right about the not yielding with the suggested code.

I could not think of a reason why vTaskSwitchContext() would have to be called after incrementing the tick, in fact when running with configUSE_PREEMPTION set to 0 it is not.  So your results are suprising.

+ What do you find happens?  The system crashes or just still round robins when you don’t want it to?
+ What are you calling when you enter the tick ISR?  portSAVE_CONTEXT() of portENTER_SWITCHING_ISR()?

Some of the other ARM7 ports have a different IRQ handling mechanism where the context is saved automatically prior to vectoring to the handler.  This prevents you having to use the ENTER/EXIT_SWITCHING_ISR() macros.


anonymous wrote on Friday, January 12, 2007:


I have a common ISR that handles all (VIC default vector) IRQs, including the tick interrrupt.

extern void  __attribute__ ((naked)) PortIRQDispatch(void);

void PortIRQDispatch(void)



ISRDispatch() does a table lookup to properly dispatch to the correct ISR. NeedTaskSwitch() is implemented in tasks.c as:

short    NeedTaskSwitch(void)
__static portTickType lastCount;
__short               didTick = lastCount!=xTickCount;

__lastCount = xTickCount;

__return didTick || uxTopReadyPriority>pxCurrentTCB->uxPriority;

The above version works as I had hoped. The ‘didTick’ trick ensures that true is returned whenever vTaskIncrementTick() is called in the ISR. The following version does not work as expected.

short    NeedTaskSwitch(void)
__return uxTopReadyPriority>pxCurrentTCB->uxPriority;

The test has a lower priority task in an infinite loop. A higher priority task delays for a certain period. It never appears to run after the delay period. But then I have some difficulty with debugging. I see NeedTaskSwitch() return true at the appropriate time, but I can’t seem to properly step out of the restoring of the context to see what is happening. I don’t know if the stepping out issue is an artifact of the actual
problem, or if it is just an artifact of my debugging tools. Visually, during the final
__SUBS    PC, LR, #4
the LR has the same value as the PC, so it just steps back 1 instruction and appears to be looping infinitely. But this is inconsistent with the free-running behaviour so I tend to suspect the debug tools rather than think this is the actual problem. Free-running, a breakpoint after the delay in the higher priority task never triggers, and the lower priority task continues looping.

The truth be told, I never examined the registers of the restored context to try to figure out which of the 2 tasks was being restored. I may take some time to do this some time in the future. Or, if you are willing to look at it…


rtel wrote on Sunday, January 14, 2007:

Not 100% sure about this but I think it might be to do with a mismatch between the IRQ and SWI stack frames.

Could you give this a go.

void __attribute__ ((naked)) PortIRQDispatch(void);

void PortIRQDispatch(void)


____if( NeedTaskSwitch())

Keep the brackets between the SAVE/RESTORE to start with, I don’t think they are needed unless you declare a stack variable in the function, but they won’t do any harm.



anonymous wrote on Sunday, January 14, 2007:


I have absolutely no idea why this has solved the problem nor how what you have suggested differs in any significant way from the original, but it does seem to have solved the problem. And no, the extra brackets are not required.

Does this mean that there is something not quite right about the ARM port that we should be aware of?

Thanks, Richard. I’ll maybe look it more closely tomorrow.

rtel wrote on Monday, January 15, 2007:

The portENTER_SWITCHING_ISR() macro contains one extra line (to change the stack frame) when compared to the portSAVE_CONTEXT() macro as they are intended for use in slightly different situations.  The code I suggested matched the way the original tick ISR was written.


anonymous wrote on Monday, January 15, 2007:

Sorry about continuing to beat this dead horse, but I would like to understand the implications of this for my future use of FreeRTOS.

1. Is the only downside of using the portSAVE_CONTEXT()/portRESTORE_CONTEXT() version the fact that the main ISR function can’t have local variables?

2. Does the fact that the tick ISR had a problem with the portENTER_SWITCHING_ISR()/portEXIT_SWITCHING_ISR() version mean that other ISRs could also have problems with these macros, or is this problem specifically related to the use of vTaskIncrementTick() in the ISR?


rtel wrote on Tuesday, January 16, 2007:

Not sure - I need to look into this in more detail.

I recently updated the demo makefiles in the download to include the -fomit-fame-pointer options.  Are you using this?  I am wondering if it has caused a problem.


anonymous wrote on Tuesday, January 16, 2007:

Oh… no, I found the -fomit-fame-pointer interfered too much much with debugging, so I ‘fixed’ the GCC problem within FreeRTOS. Could that be the problem? Have you actually reproduced the my ISR problem, or have you just been relying on my description?

Here is what I did for the problem of GCC emitting ARM/Thumb code incompatible with context switching:


____"SUB    SP, SP, #4                           
____"LDMIA  SP!,{R0}                           
/*gb - step over possible GCC stacked items (GCC bug)*/
____"SUB    R0, R0, #8           

        /* Push the return address onto the stack. */
____"STMDB  R0!, {LR}

rtel wrote on Tuesday, January 16, 2007:

Glen - would it be possible for you to send me a zip file containing a mini project that exhibits the behaviour?  It does not really have to do anything.  I will then merge your FreeRTOS specific files into an LPC2000 demo project and run it in CrossWorks so I can step through the code to see exactly what is what.  You can send the file to the email address on the WEB site rather than SourceForge as the latter strips off binary attachments (r +++dot+++ barry !!!at!!! freertos.org).


anonymous wrote on Wednesday, January 17, 2007:

Sorry, I won’t be able put together a mini app for some time. I’ll get back to you. Thanks for the time you have put on it so far.


anonymous wrote on Wednesday, January 17, 2007:

Oh, oh. I have discovered the problem was mine. The actual strategy I was using is fine. My blunder was misinterpreting what I was seeing.

My deepest apologies , Richard. As I trimmed things down I discovered my blunder. (Good strategy on your part!) I even got it wrong when I said that the change you suggested fixed the problem. Well, in fact there was no problem.