Skip to content

NRF52_DK: Not all callbacks called when multiple Timeout objects scheduled one by one #6732

Closed
@fkjagodzinski

Description

@fkjagodzinski

Description

  • Type: Bug
  • Priority: Major

Target
NRF52_DK

Toolchain:
ARM, IAR

Toolchain version:
ARM 5.24 (Flex) ARM Compiler 5.06 update 5 (build 528),
IAR ANSI C/C++ Compiler V7.80.4.12462/W32 for ARM

mbed-cli version:
1.5.0

mbed-os sha:
42d77ec

Code

#include "mbed.h"

#define VERBOSE 0

#define NUM_TIMEOUTS 16
#define TEST_DELAY_US 10000ULL

void cnt_callback(volatile uint32_t *cnt)
{
    (*cnt)++;
}

int main()
{
    const ticker_data_t * const us_ticker = get_us_ticker_data();
    const ticker_event_queue_t *ticker_event_q = us_ticker->queue;

    uint32_t cnt1 = 0;
    do {
#if VERBOSE
        us_timestamp_t event_timestamps[NUM_TIMEOUTS] = { 0 };
#endif
        us_timestamp_t ts0, ts1, ts2, end_ts, head_ts1, head_ts2;
        volatile uint32_t callback_count = 0;
        Timeout timeouts[NUM_TIMEOUTS];

        for (size_t i = 0; i < NUM_TIMEOUTS; i++) {
            timeouts[i].attach_us(mbed::callback(cnt_callback, &callback_count), TEST_DELAY_US);
        }
        ts0 = ticker_read_us(us_ticker);
#if VERBOSE
        ticker_event_t *te = ticker_event_q->head;
        int i = 0;
        while (te != NULL) {
            event_timestamps[i] = te->timestamp;
            i++;
            te = te->next;
        }
#endif

        end_ts = ts0 + TEST_DELAY_US;
        while (ticker_read_us(us_ticker) < end_ts) {
        };
        // At this point all callbacks should have been called,
        // so expected values are:
        // cnt1 == NUM_TIMEOUTS
        // ticker_event_q-> head == NULL
        cnt1 = callback_count;
        ts1 = ticker_read_us(us_ticker);
        head_ts1 = (ticker_event_q->head == NULL) ? 0 : ticker_event_q->head->timestamp;

        // Wait more to check if any callback was late.
        end_ts += 2 * TEST_DELAY_US;
        while (callback_count < NUM_TIMEOUTS && ticker_read_us(us_ticker) < end_ts) {
        };
        uint32_t cnt2 = callback_count;
        ts2 = ticker_read_us(us_ticker);
        head_ts2 = (ticker_event_q->head == NULL) ? 0 : ticker_event_q->head->timestamp;

#if VERBOSE
        us_timestamp_t prev_ts = event_timestamps[0];
        for (size_t i = 0; i < NUM_TIMEOUTS; i++) {
            printf("ts[%02i]=%llu, delta=%03llu\r\n", i, event_timestamps[i], event_timestamps[i] - prev_ts);
            prev_ts = event_timestamps[i];
        }
#endif
        printf("ts0=%llu, ts1=%llu, ts2=%llu, ts2-ts0=%llu, "
                "cnt1=%lu, cnt2=%lu, head_ts1=%llu, head_ts2=%llu\r\n", ts0, ts1, ts2, ts2 - ts0, cnt1, cnt2, head_ts1,
                head_ts2);
    } while (cnt1 == NUM_TIMEOUTS);
    printf("gotcha!\r\n");

    return 0;
}

Expected behavior
When multiple Timeout objects are scheduled one by one, all callbacks are called after given delay.

Actual behavior
With multiple repetitions it is possible to catch a case where not all the callbacks are called. The ticker event queue is not empty and still contains outdated events.

Steps to reproduce
mbed compile -t ARM -m NRF52_DK -f

ts0=732, ts1=10803, ts2=10833, ts2-ts0=10101, cnt1=16, cnt2=16, head_ts1=0, head_ts2=0
ts0=103119, ts1=113128, ts2=113128, ts2-ts0=10009, cnt1=16, cnt2=16, head_ts1=0, head_ts2=0
ts0=210632, ts1=220642, ts2=220642, ts2-ts0=10010, cnt1=16, cnt2=16, head_ts1=0, head_ts2=0
ts0=318176, ts1=328186, ts2=348205, ts2-ts0=30029, cnt1=15, cnt2=15, head_ts1=328145, head_ts2=328145
gotcha!

# RESET button pressed
ts0=732, ts1=10742, ts2=10742, ts2-ts0=10010, cnt1=16, cnt2=16, head_ts1=0, head_ts2=0
ts0=103180, ts1=113189, ts2=113189, ts2-ts0=10009, cnt1=16, cnt2=16, head_ts1=0, head_ts2=0
ts0=210663, ts1=220703, ts2=220703, ts2-ts0=10040, cnt1=16, cnt2=16, head_ts1=0, head_ts2=0
ts0=318298, ts1=328308, ts2=328308, ts2-ts0=10010, cnt1=16, cnt2=16, head_ts1=0, head_ts2=0
ts0=425872, ts1=435882, ts2=455902, ts2-ts0=30030, cnt1=3, cnt2=3, head_ts1=435323, head_ts2=435323
gotcha!

# RESET button pressed
ts0=732, ts1=10742, ts2=10742, ts2-ts0=10010, cnt1=16, cnt2=16, head_ts1=0, head_ts2=0
ts0=103210, ts1=113220, ts2=113220, ts2-ts0=10010, cnt1=16, cnt2=16, head_ts1=0, head_ts2=0
ts0=210754, ts1=220825, ts2=220825, ts2-ts0=10071, cnt1=16, cnt2=16, head_ts1=0, head_ts2=0
ts0=318451, ts1=328460, ts2=328460, ts2-ts0=10009, cnt1=16, cnt2=16, head_ts1=0, head_ts2=0
ts0=426025, ts1=436035, ts2=436035, ts2-ts0=10010, cnt1=16, cnt2=16, head_ts1=0, head_ts2=0
ts0=533600, ts1=543640, ts2=543640, ts2-ts0=10040, cnt1=16, cnt2=16, head_ts1=0, head_ts2=0
ts0=641143, ts1=651153, ts2=671173, ts2-ts0=30030, cnt1=12, cnt2=12, head_ts1=650991, head_ts2=650991
gotcha!

# RESET button pressed
ts0=732, ts1=10742, ts2=10742, ts2-ts0=10010, cnt1=16, cnt2=16, head_ts1=0, head_ts2=0
ts0=103180, ts1=113189, ts2=113189, ts2-ts0=10009, cnt1=16, cnt2=16, head_ts1=0, head_ts2=0
ts0=210724, ts1=220733, ts2=220733, ts2-ts0=10009, cnt1=16, cnt2=16, head_ts1=0, head_ts2=0
ts0=318329, ts1=328338, ts2=348358, ts2-ts0=30029, cnt1=13, cnt2=13, head_ts1=328237, head_ts2=328237
gotcha!

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