Hi All,
I've just confirmed that calling _task_stop_preemption() from my main task (priority 11) prevents my 100mS timer interrupt service routine from being called (priority 2). The MQX RTOS Reference Manual description of _task_stop_preemption() says that "Interrupts are still handled" (Rev. 3 01/2010, section 2.1.286, page 383). I'm using MQX 3.8.1.1. Am I misunderstanding this perhaps? Has anyone else seen this behavior? Maybe only external GPIO type interrupts continue to be serviced? My 100mS Timer interrupt updates leds on my project and I think it looks bad when a "Run" led stalls (even briefly). Any ideas? Thanks!
Best Tim
Solved! Go to Solution.
The timer component is not an interrupt or ISR. It's a task so you should not expect it to run when you stop preemption. So things are behaving as expected.
In general I would say that you should not stop preemption for long periods of time. It sounds like you have this infrequent task that sorts data and another processes it. You're probably going to have to restructure your code or I think you'll get yourself in to trouble.
If you post what you are trying to accomplish we could make some suggestions.
Kenny
I'm using a newer version of MQX but I don't believe these routines block interrupts but rather prevent an interrupt from *causing* a context switch (preemption). I'm interpreting this to mean that your task code is guaranteed not be preempted by another task which is a different thing. I suspect something else is going on. Also, if you have code that is blocking that LED long enough that you can perceive it with the naked eye something may be disabling interrupts for too long a time. Maybe you can describe your code in a little more detail. An ISR priority 2 is quite high priority relative to the possible 0-15 levels on this implementation of the Cortex-M4F.
Imagine if you had another timer that posted to a queue that a higher task was listening to. Normally the scheduler would restore the newly readied task's context and return to it instead of yours. But _task_stop_preemption() would not allow it. As soon _task_start_preemption() is called that high priority task will run.
Also the priority of your task and the priority of your interrupt are two different things. The first is determined by the RTOS scheduler. The second determined by the Cortex NVIC.
Kenny
Hi Kenny,
Here's a copy of my main() loop task/function that I modified to test if _task_stop_preemption() would prevent servicing my 100mS timer interrupt. As long as the inner while(cRun == gcYES) loop is running, the ISR for my timer is never called. That timer ISR does very little except update led's and inc a few counters that are used in my code. This project is not using task queue's (other then what MQX does behind the scenes).
You are correct to note that I am holding off task preemption for quite a while for it to be noticeable with a run led blinking at 100mS, and I was aware of this when I did it. The holding off of preemption is required while some infrequent organizing (including sorting) of data used by another task is being done. I could hold off that one task in other ways to allow the timer ISR to run but I thought that just calling _task_stop_preemption() should have worked, and preventing all other tasks (mostly network sockets support) from preempting wasn't going to cause a problem. Thanks for your reply!
Best Regards,
Tim
void MAIN_task(uint_32 initial_data)
{ uint_8 cRun, cPcemptTest = gcNO;
//Wake things up //---------------------------------------------------------------------------- MAIN_SystemInit();
//Endless loop that the processor runs forever
//---------------------------------------------------------------------------- while(1) { //The delay causes MAIN_Task() to block and give other tasks a chance to run //---------------------------------------------------------------------------- _time_delay(5);
//Check for processor request items //---------------------------------------------------------------------------- PSERVE_CheckServiceRequests();
//Service remote system client connections //----------------------------------------------------------------------------
RMTSYS_ServiceRemoteSystems();
//100mS Timer interrupt preemption test
//---------------------------------------------------------------------------- if(PremptTest == gcYES) {
cPremptTest = gcNO; cRun = gcYES; _task_stop_preemption(); while(cRun == gcYES) { asm(nop); }
_task_start_preemption(); }
}
return;
}
Perhaps what happens is the scheduler rejects interrupts that are kernel aware and that might explain things. Remember that when you install an interrupt with _int_install_isr your code gets called between calls to the scheduler. If you use _int_install_kernel_isr then MQX has no idea that is running. Given that you don't need kernel services this is probably an acceptable solution for you. Even if you did you could invoke another kernel aware interrupt using software.
If the above proves incorrect then you'll have to do some low-level debugging.
The first thing I would try is examine the state of things before and after _task_stop_preemption(). Examine BASEPRI and PRIMASK before and after. I would expect--based on 4.1.1 behavior--that BASEPRI is zero and PRIMASK bit zero is cleared.
Double-check that the timer ISR is installed by looking directly at the table if it is a kernel interrupt or reading back the installed interrupt. Maybe your other task does something that the timer depends on like enable a clock to the periperhal?
I'm banking on the kernel ISR.
Kenny
Hi Kenny,
I'm not using _int_install_isr(), I'm installing the timer like this:
//Create the timer componant
//----------------------------------------------------------------------------
lError = _timer_create_component(2, 1024); //Set Task Priority = 2, stack size=1024
if(lError != MQX_OK)
PSERVE_LogMsg("MAIN_SystemInit() - Error Creating 100mS Timer", gcLOGENTRY_ERROR);
else
{
timer_100ms = _timer_start_periodic_every(INT_100msTimer, 0, TIMER_ELAPSED_TIME_MODE, 100); //Funct(), DataPtr, Mode, milli-seconds
if(timer_100ms == TIMER_NULL_ID)
{
_timer_cancel(timer_100ms);
PSERVE_LogMsg("MAIN_SystemInit() - 100mS Timer Start Error", gcLOGENTRY_ERROR);
}
}
}
You've given me some good ideas to help track this down, I appreciate it. I'll post back here what I find. Have a great day.
Best Regards,
Tim
The timer component is not an interrupt or ISR. It's a task so you should not expect it to run when you stop preemption. So things are behaving as expected.
In general I would say that you should not stop preemption for long periods of time. It sounds like you have this infrequent task that sorts data and another processes it. You're probably going to have to restructure your code or I think you'll get yourself in to trouble.
If you post what you are trying to accomplish we could make some suggestions.
Kenny
Ahhh, well that would explain it now wouldn't it. I guess I just assumed that MQX was setting up a processor timer interrupt for me. Proof once again of what happens when you assume! I can think of several ways to correct this problem, I appreciate your taking the time to point out my error and save me some work. Thanks again.
Best Regards,
Tim