Ticker Timer Priority

27 Feb 2011

I've read some old posts explaining that all Tickers use the same internal hardware timer and they all have the same priority:

I am using several Tickers in my program and want to give them highest priority over everything else.

So for instance, in the following code the OneMilliSecondTimer is called every one millisecond. The ReceiveMessagesCAN2HS is called every time a message comes in on the CAN bus. As you can see in the scope trace picture below, when the program is in the ReceiveMessageCAN2HS routine (top yellow trace) the Ticker function is not called (bottom purple trace).

  • 1) I want to give the Ticker function top priority so that it keeps ticking even when the program in in the Receive MessageCAN2HS function.
  • 2) What hardware timer is the Ticker functions using? I assume TIMER3 from other posts.
  • 3) The following CMSIS code, as you can see from the example does not seem to work, why?: NVIC_SetPriority(TIMER3_IRQn, 1); set mbed tickers to higher priority
  • 4) How can I fix this?
  • 5) Thank you!! <<>>

/media/uploads/numerical7/_scaled_p1020286.jpg

// February 26, 2011
// CAN receive test.

#include "mbed.h"

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

DigitalOut InReceiveMessagesCAN1MS(p17);
DigitalOut InReceiveMessagesCAN2HS(p18);
DigitalOut InOneMillisecondTimer(p19);
DigitalOut InTenMillisecondTimer(p20);


CAN CAN1MS(p9, p10);
CAN CAN2HS(p30, p29);

CANMessage RxCANMessageCAN1MS;
CANMessage RxCANMessageCAN2HS;


int OneMillisecondTicks;
int TenMillisecondTicks;

Ticker SchedulerTimerOneMilli;
Ticker SchedulerTimerTenMilli;

void ReceiveMessagesCAN1MS() 
{
    InReceiveMessagesCAN1MS = !InReceiveMessagesCAN1MS;
    InReceiveMessagesCAN1MS = 1;
    wait_ms(50);
    InReceiveMessagesCAN1MS = 0;
    CAN1MS.read(RxCANMessageCAN1MS);
}

void ReceiveMessagesCAN2HS() 
{
    //InReceiveMessagesCAN2HS = !InReceiveMessagesCAN2HS;
    InReceiveMessagesCAN2HS = 1;
    wait_ms(50);
    InReceiveMessagesCAN2HS = 0;
    CAN2HS.read(RxCANMessageCAN2HS);
}

void OneMillisecondTimer()
{
    OneMillisecondTicks = OneMillisecondTicks + 1;
    InOneMillisecondTimer = !InOneMillisecondTimer;    
}

void TenMillisecondTimer()
{
    TenMillisecondTicks = TenMillisecondTicks + 1;
    InTenMillisecondTimer = !InTenMillisecondTimer;
}

int main()
{   

    //CAN1MS.frequency(125000);  //MSCAN
    CAN2HS.frequency(500000);  //HSCAN
    
    //CAN1MS.attach(&ReceiveMessagesCAN1MS);
    CAN2HS.attach(&ReceiveMessagesCAN2HS);

    SchedulerTimerOneMilli.attach_us(&OneMillisecondTimer,1000);
    //SchedulerTimerTenMilli.attach_us(&TenMillisecondTimer,10000);
    
    NVIC_SetPriority(TIMER3_IRQn, 1); // set mbed tickers to higher priority than other things

    
    CANMessage msg;

    printf("Running Main....\r\n");
    
    while(1) 
    {
        //Do Nothing.... yet....
    }
}

27 Feb 2011

After some more thought...

I think I need to "nest" the function calls. So that if the program is inside ReceiveMessagesCAN2HS(), it will still allow the OneMillisecondTimer() to be called.

I'm wondering if by default, when the ReceiveMessagesCAN2HS() function is called some behind the scenes library code in the mbed library is turning off the timer interrupts? If so, how can I turn them back on?

Thanks.

27 Feb 2011

Hi Kevin,

What you are trying to do looks along the right lines, except 0 is the highest priority. So try setting the CAN interrupt to a lower priority instead of the Timer, and I hope it might just spring in to life. Great picture btw, showing exactly the behaviour.

Simon

27 Feb 2011

Simon. I got it working now. Thanks for you help!

I set the Timer3 interrupts to Priority 1 and the CAN interrupts to Priority 2 like this. It looks like the mbed is not using the CANActivity_IRQn so I did not need to use that interrupt.

NVIC_SetPriority(TIMER3_IRQn, 1); 
NVIC_SetPriority(CAN_IRQn, 2); 

A follow up question: Since I don't really know what is going on behind the scenes of the mbed core libraries, by making these two interrupts such a high priority am I going to screw up anything in the core mbed libraries like printing to USB port or any other critical core functions?

Here is a scope plot of the system working properly. You can see that while the program is servicing the CAN interrupt (yellow line going high), the 1ms Ticker keeps ticking (purple line going high and low).

/media/uploads/numerical7/_scaled_p1020287.jpg

27 Feb 2011

I think the default out of reset is all priorities are zero. So you haven't made these two interrupts the hightest. What you have done is made them all the highest except TIMER3 followed by CAN. You've lowered both the Ticker and the CAN under all other interrupts, just you've lowered CAN below TIMER3. So you're USB interrupts are still a higher priority than the Ticker and CAN.

18 May 2011

Is a higher priority interrupt able to corrupt a CANMessage when it fires while you are reading it in? In other words, can your can.read(msg); be messed up if a higher priority interrupt fires while it's beeing processed?

Edit: Or does priority only say which interrupt is handled NEXT, after the current one is dealt with?

18 May 2011

After some investigation into the NVIC I conclude the following.

If an new interrupt has a higher priority then the interrupt that is currently being processed, it interrupts the current flow. (Nesting).

If the IRQ is dissabled however, no matter what the priority of the incoming interrupt is, it is pended.

If a new interrupt has a lower priority then the interrupt that is currently being processed, it is pended.

You can set priority of individual interrupts or to an entire group of interrupts (of which there are 4).

Priority is given to the lowest interrupt number if priorities are the same.

So interrupts are not silently discarded (as long as the same interrupt doesn't fire multiple times).

Am I right?

Thanks in advance!

Melchior

18 May 2011

Sounds about right. Afaik, out of reset the Mbed library startup code leaves all priorities the same. So once your CAN ISR is running it should complete before servicing the next pending and enabled interrupt or returning. Of course, if something else is altering priorities then all bets are off ;)