Odd Ticker behaviour

11 Feb 2011

Simon,

Take a look at this:-

#include "mbed.h"

DigitalOut led1(LED1);
DigitalOut led2(LED2);
Ticker  t3;

bool doOnceFlag = false;

void callback(void)  { 
    led2 = !led2; 
    if (!doOnceFlag) {
        // re-task ticker flash rate
        t3.detach(); 
        t3.attach(&callback, 5); 
        doOnceFlag = true;
    }
}

int main() {
    t3.attach(&callback, 5);
    wait(1);
    while(1) {             
        led1 = 1;
        wait(0.05);   
        led1 = 0;        
        wait(0.95);
    }
}

In the above code led1 is just setup to flash one per second as a "marker".

Led2 is switched on and off via the Ticker callback. Now, one thing I wanted to do was to alter the flash rate of led2. So, in the callback I "re-tasked" the Ticker to a new rate by detaching and then attaching again. Now, In the example above I'm actually setting it to 5seconds. But is doesn't matter what you set, just that 5 seconds happen to show this odd behaviour.

Try in on an Mbed. What happens is when the Ticker is reassigned the next flash doesn't happen 5seconds later, it happens 10 seconds later! In fact, experiement shows that whenever you re-task the Ticker the next callback is always twice the value you specify. After that it returns to normal 5second period.

So I'm curious, have I missed something obvious? Or is that a possible edge case bug?

11 Feb 2011

btw, when I mean "twice the value" try changing the 5 to a 4 in the callback() function. What happens then is the doesn't of off 4seconds later, it goes off 8 seconds later then reverting to 4seconds. Not what I was expecting.

11 Feb 2011

Hi Andy,

first i tried just to declare doOnceFlag as "volatile", but that didn't change anything.

But the following code behaves as expected:

#include "mbed.h"

DigitalOut led1(LED1);
DigitalOut led2(LED2);
Ticker  t3;

volatile bool doOnceFlag = false;
volatile bool reAttach = false;

void callback(void)  { 
    led2 = !led2; 
    if (!doOnceFlag) {
        doOnceFlag = true;
        reAttach = true;
    }
}

int main() {
    t3.attach(&callback, 5);
    wait(1);
    while(1) {
        if (reAttach) {
            // re-task ticker flash rate
            t3.detach();
            t3.attach(&callback, 4);
            reAttach = false;
        }             
        led1 = 1;
        wait(0.05);   
        led1 = 0;        
        wait(0.95);
    }
}

So it seems that detaching and attaching a ticker callback ISR inside the same ISR itself (in your case) messes something up (probably the ISR loses somehow the first call after reattach).

In my case, where i do the detach and attach inside main() (controlled by a ISR flag of course), everything works as expected.

Best regards

Nenad

11 Feb 2011

Nenad

I see what you are saying. But that appears to be more of a workaround a bug than a working solution. I would expect when you call .attach(&x, time) it should be "time from now". What other possible time reference frame is there?

11 Feb 2011

Hi Andy,

Thanks for this example. It basically comes down to the Timer events relying on the fact they are manipulated from outside their own event handler. But this assumption/requirement is not made clear and perhaps not a good restriction, so I think the best solution is actually to fix it to make it function in that case too.

The underlying logic is basically:

handle this event
insert an event at previous event time + interval

So, if some of the events own records have been changed during handling the event itself, it can insert the new event at the wrong time. That is why you are getting 5 seconds (your internal re-registration) + 5 seconds (it updating by 5 second shift) to get the 10 second delay.

I'll get these updated so they can be used within themselves too, as it does actually seem a good use case.

Thanks again!

Simon

11 Feb 2011

Hi,

Ok, if you update your mbed library to v28 (click on the mbed library in the IDE, and choose "update to latest revision" in the right pane), all should work as expected now.

Please tell me if this fixes it, and/or if you have any further problems.

Simon

11 Feb 2011

Hi Simon,

Thanks for the clarification. As for the use case, it's a little odd and not really "real world" but I might as well explain it as knowing odd ball stuff like this is often useful.

I recently wrote a notebook page for beginners about interrupts. I now want to write another notebook leading on from that about interrupt priorities. In order to demo what happens when you alter them I needed some simple to use IRQ to control LED examples. But all Mbed Tickers are derived from TIMER3. So altering the priority of TIMER3 alters all Tickers.

My solution to this was to "knock up" a set of classes that mimic the Ticker class but use TIMER1, TIMER2 and the RIT. This allows me to create demos of "Tickers" with different IRQs and hence I can mess with their priorities as I like.

But when I ran my first demos I noticed the Mbed Ticker wasn't doing what my own classes were doing. I initially though I had a bug in my classes but then noticed the "double time" of the Ticker compared to my own versions. That's when I perculated down the demo on this post to show what I meant.

I just published my own Ticker mimic classes but I haven't made them public as they're rough (not meant for production) and only down down to millisecond rather than microsecond.

Import libraryTickers

A set of classes that mimic the behaviour of Mbed Ticker class but using TIMER0, TIMER1, TIMER2 and the RIT.

11 Feb 2011

v28 works as expected, thanks for the quick response :)