Skip to content

periph_rtt: rtt_set_alarm() blocks IRQ for 80 plus usec on STM32 #19520

Open
@Enoch247

Description

Description

When the ztimer_msec module is enabled and backed by periph_rtt on a STM32 CPU I noticed jitter in my ISRs of 100-200 usec. Digging into the issue I see the implementation of rtt in all STM32 (STM32F1 being the exception I believe, but it may have similar problems) busy waits inside of a critical section of code where IRQs are disabled. This happens inside the rtt_set_alarm() function. I thought to move the busy wait out of the critical section, but I believe ztimeris calling this function from an ISR anyway.

Steps to reproduce the issue

Here is the simplest program I can think of to demonstrate the issue:

Makefile:

APPLICATION = periph_rtt_bug
BOARD ?= nucleo-f767zi
RIOTBASE ?= ../../lib/RIOT

FEATURES_REQUIRED += periph_rtt
USEMODULE += ztimer_usec
USEMODULE += ztimer_stopwatch

# uncomment this line to demonstrate bug indirectly via ztimer rather than directly via rtt
#USEMODULE += ztimer_msec

include $(RIOTBASE)/Makefile.include

main.c:

#include <periph/rtt.h>
#include <ztimer.h>
#include <ztimer/stopwatch.h>

static void _cb(void* arg)
{
    (void)arg;
}

int main(void)
{
    unsigned max = 0;
    ztimer_stopwatch_t stopwatch;
    ztimer_t timer = { .callback = &_cb };

#ifndef MODULE_ZTIMER_MSEC

    // Normally ZTIMER_MSEC is backed by rtt, but if ZTIMER_MSEC isn't used,
    // we'll need to init rtt ourselves.
    rtt_init();

#endif

    ztimer_stopwatch_init(ZTIMER_USEC, &stopwatch);

    while (1)
    {
        ztimer_stopwatch_start(&stopwatch);

#ifdef MODULE_ZTIMER_MSEC

        // Demonstrate that setting a timer on ZTIMER_MSEC (when backed by rtt)
        // can take more time than we might expect. This is espesially bad when
        // timers are set from an ISR.
        ztimer_set(ZTIMER_MSEC, &timer, 100);

#else

        // silence unsused variable compiler warning
        (void)timer;

        // Demonstate that we spend an unexpectedly long amount of time  in this
        // call (with IRQs disabled).
        rtt_set_alarm(100, &_cb, NULL);

#endif

        ztimer_stopwatch_stop(&stopwatch);
        const unsigned time = ztimer_stopwatch_measure(&stopwatch);

        if (time > max)
        {
            max = time;
            printf("max: %u\n", max);
        }
    }

    return 0;
}

Expected results

Output-ed max values from sample code above should be very small.

Actual results

Output-ed max values from sample code above are 80-90 usec. When the line USEMODULE += ztimer_msec is uncomment in the Makefile, that increases to as much as 183 usec.

Versions

RIOT Version 2023.04

Metadata

Assignees

Labels

Type: bugThe issue reports a bug / The PR fixes a bug (including spelling errors)

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions