Skip to content

Ticker issues with NRF52 platform, especially while using event queue call_every timer function. #4893

Closed
@yogeshk19

Description

@yogeshk19

Description


Target
NRF52_DK

Toolchain:
GCC_ARM

MBED_OS version 5.4.4, 5.5

Expected behavior
Event Queue's call_every method should invoke the call back method based on the interval passed to the call_every API. for ex: The application I have written expects to read a sensor every 30 seconds and transmit data to any Bluetooth Central device connected to it.
Actual behavior

In mbed os 5.4.4 the call back method takes forever to be invoked and it is pretty random. Sometimes its takes several minutes and sometimes it takes a few seconds.

In mbed os 5.5 the application just gets into stack underflow error.

However in mbed os 5.3.3, the call_every function works as expected. There was fix made in the issue #3857 and that was incorporated part of the mbed-os 5.4.4 which was supposed to address the ticker issue, however it seems to have made it worse.

Steps to reproduce

  1. Take any of the example MBED BLE applications that is a BLE peripheral application and add the following code to ensure the device operates in low power mode and modify the application such that a sensor is read via the event queue call_every method.
#include <limits.h>
#include <mbed.h>

// import the time duration between two ticks (in us).
extern const uint32_t os_clockrate;

//initialize an event queue loop.
static EventQueue eventQueue(16*32);

void dummy_cb() { }

void os_idle_demon (void) {
    // use int rather than timestamp_t because units are not coherent 
    // between Timer and Timeout ...
    const int max_us_sleep = (INT_MAX / os_clockrate) * os_clockrate; 
    Timer stopwatch;      // keep track of the time asleep
    Timeout alarm_clock;  // will awake the uc if no interrupts does it before

    // never ends, the rtos will suspend this thread when there is something to do
    // either before os_suspend actually suspend the system (and is not in svc) 
    // or immediately after os_resume  
    while (true) {
        // suspend the system 
        uint32_t ticks_to_sleep = os_suspend();
        uint32_t elapsed_ticks = 0;

        if (ticks_to_sleep) { 
            uint64_t us_to_sleep = ticks_to_sleep * os_clockrate; 

            if (us_to_sleep > (uint32_t) max_us_sleep) { 
                us_to_sleep = max_us_sleep;
            }

            // start the stopwatch and setup the alarm_clock to wakeup the uc in us_to_sleep
            stopwatch.start();
            alarm_clock.attach_us(dummy_cb, us_to_sleep);

            // go to sleep, most of the work is done by the softdevice 
            sleep();

            // after sleep, unknown wake up source, can be the stopwatch or another IRQ
            int us_asleep = stopwatch.read_us();

            // stopwatch and alarm_clock cleanup
            stopwatch.stop();
            stopwatch.reset();
            alarm_clock.detach();

            // translate us asleep into ticks 
            elapsed_ticks = us_asleep / os_clockrate;
        }

        // resume the system 
        os_resume(elapsed_ticks);
    }
}

Please let me know if I can add any more details, that would help us get un-blocked.

Thanks,
Yogesh

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions