Ticker not ticking

Hi,

I have an issue where a Ticker (member of a specific class) is not calling a callback function (member of the same class).

class LogManager
{
    public:

    Ticker log_ticker;
    EventFlags event_flags;

    LogManager(){};

    void start()
    {
        log_ticker.attach(callback(this, &LogManager::sample_callback), 200ms);
    }

    void sample_callback()
    {
        event_flags.set(GET_SAMPLE);
        led = !led;
    }
};

By calling start() from an external context (over the main function), the ticker is not running (Confirmed by noflashing LED).
Did I oversee something obvious?

Hello Thibault,

The data memeber led doesn’t seem to be defined and initialized. To make sure all class members are created and initialized by users I would suggest to extend the constructor.
For example:

...
Ticker      log_ticker;
EventFlags  event_flags;
DigitalOut  led;

LogManager(Ticker& ticker, EventFlags eventFlags, PinName ledPin) : 
    log_ticker(ticker),
    event_flags(eventFlags),
    led(ledPin)
    {}
...

Actually it is defined as private member in the class. I forgot it in my little example. I use the LED only to see if the ticker works.

Generally the ticker works. I tested it in the global context, so I can rule hardware issues out. So something is not right with the implementation…

I am defining a ticker within my class members and do not hand over a ticker in the constructor (like you do). I will try your implementation out, because if I do like your example, Ticker gets initialized globally and not within the class. Maybe that’s the issue.

So your idea helped a little. The Ticker only works when defined globally on the heap. Having only the LED called in the callback loop, the program is running as intended. If I try to set flags via event_flags, nothing works at all any more.

Because the Ticker is not copy-able I modified the code a bit:

#define GET_SAMPLE 0b00000000000000000000000000000001

class   LogManager
{
    DigitalOut  led;
public:
    Ticker*     log_ticker;
    EventFlags  event_flags;

    LogManager(Ticker* ticker, uint32_t eventFlags, PinName ledPin) :
    log_ticker(ticker),
    led(ledPin)
    { event_flags.set(eventFlags); }

    void    start()             { log_ticker->attach(callback(this, &LogManager::sample_callback), 500ms); }
    void    sample_callback()   { led = !led; }
};

int main()
{
    Ticker     myTicker;
    LogManager logManager(&myTicker, GET_SAMPLE, LED1);

    logManager.start();

    while (1) {
        ThisThread::sleep_for(10ms);
    }
}

Calling the Ticker* like this is exactly how I did it. I am setting the flags differently, though (Through two tasks, which are also run within this class context). I have defined everything on a global level now and only give the pointers to the instances of my class.

Basically in your example, if I e.g. modify sample_callback from this:

void    sample_callback()   { led = !led; }

to this:

void    sample_callback()   { led = !led;  event_flags.set(SOME_FLAG);}

it does not work any more. I am not even getting an error message.

Actually I sometimes get a error message. The last one was:

�������� 311 Module: 1
Error Message: EventFlags: 0x2000254C, Parameter error
Location: 0x80026A3
Error Value: 0x2000254C
Current Thread: application_unnamed_thread Id: 0x200038A4 Entry: 0x8005D59 StackSize: 0x1000 StackMem: 0x20004608 SP: 0x2001FF2C 
For more info, visit: https://mbed.com/s/error?error=0x80010137&tgt=NUCLEO_F446RE
-- MbedOS Error Info --

I cannot reproduce it though.

  • I have tried to modify my sample above as follows:
void    sample_callback()   { led = !led;  event_flags.set(GET_SAMPLE);}

On LPC1768 it works OK.

  • Make sure the most significant bit of an EventFlag is not set in the program. Otherwise an osFlagsError message is generated:
/** The EventFlags class is used to control event flags or wait for event flags other threads control.

 @note
 EventFlags support 31 flags. The MSB flag is ignored. It is used to return an error code (@a osFlagsError).

 @note
 Memory considerations: The EventFlags control structures will be created on the current thread's stack, both for the Mbed OS
 and underlying RTOS objects (static or dynamic RTOS memory pools are not being used).
*/
  • The following threads could help you get the function name causing the hard fault:

I cant’t really use the crash_log_parser tool, since I am having an MbedOS Error Info and not a MbedOS Fault Handler. Thus, no hard fault, I suppose. But this might be a convenient tool for future errors.

My Flag has the value: #define GET_SAMPLE (1UL << 0).
Interesting, that it works for you and not for me…

What is your target board?

Target board is the NUCLEO_F446RE.
But I investigated your example again and found that I somehow missed copying the while(1){} loop. Of course the destructor of LogManager was called at } of main and everything with it was vanished. Callback functions and everything else. This caused the issue.

Your example helped me alot examining this, so thank you very much at this point!

The Ticker even works within a class context now. As long as the main() loop does not return.

I also have a problem with ticker, target NUCLEO F401RE. Apparently it only works for intervals of 120us and above. Using Mbed Studio, mbed-OS 6.9.0. Test programme : -

#include “mbed.h”
#include

DigitalOut led1(LED1);
Ticker test_tick;
uint32_t counter = 0;

void test_tick_handler () {
counter++;
}

int main()
{
test_tick.attach(&test_tick_handler, 120us);

while (true)
{
    if(counter > 1000)  {
        counter = 0;
        led1 = !led1;
    }
}

}

Hello Thibault,

I’m glad you solved the issue.

Hello Jon,

There appears to be a target dependent limit for the Ticker’s interval. On the LPC1768 your program above works down to 22us. But fails when I set it to 21us.

Hello Zoltan,
Ticker worked fine with OS2, this is a problem for me updating an ongoing project. I have several other projects awaiting update, most using multiple tickers, the shortest ticker interval needed is 25us. This needs to get fixed, an OS6 breakage from OS2. Any work around ideas welcome in the short term. Thanks

the ticker has some overhead, a hardware timer is more efficient. For 25 µs, I would use a hardware timer, even if it is hardware dependent code.

Hello Johannes,
Thanks, yes hardware timers have some merit, but hardware and pcb design for this project was completed 4 years ago, many now built and in service (Nucleo board was used for early code development, our board is not this!). Software upgrades in the field are one thing, hardware upgrades … not possible for this one.

sure, but I mean the hardware timer in the MCU :slight_smile: Mbed uses only one hardware timer, so there should be some spare timers.

Thanks, of course, timer in the MCU. I’ll have a look.