GRTC peripheral not always emitting scheduled events

I'm trying to use the new GRTC peripheral in nRF54L15 but in various situations I notice that the events are not triggered as expected.

Here is a "minimal reproducible example", based on the "Create a blank application" template in VS Code with NCS 2.8.0.

main.c:

#include <zephyr/kernel.h>

int main(void)
{
    // Turn off LED1 and LED3 on the devkit
    NRF_P1->PIN_CNF[10] = (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos);
    NRF_P1->PIN_CNF[14] = (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos);
    NRF_P1->OUTCLR = (1U << 10) | (1U << 14);

    // Reset GRTC to a known state and start
    NRF_GRTC->TASKS_STOP = 1;
    for (volatile int i = 0; i < 200; i++) {}
    NRF_GRTC->MODE = (GRTC_MODE_AUTOEN_Default << GRTC_MODE_AUTOEN_Pos) | (GRTC_MODE_SYSCOUNTEREN_Disabled << GRTC_MODE_SYSCOUNTEREN_Pos);
    NRF_GRTC->TIMEOUT = 0;
    NRF_GRTC->WAKETIME = 3;
    NRF_GRTC->SHORTS = 0;
    NRF_GRTC->PWMCONFIG = GRTC_PWMCONFIG_ResetValue;
    NRF_GRTC->CLKOUT = GRTC_CLKOUT_ResetValue;
    NRF_GRTC->CLKCFG = (GRTC_CLKCFG_CLKSEL_SystemLFCLK << GRTC_CLKCFG_CLKSEL_Pos) | (1 << GRTC_CLKCFG_CLKFASTDIV_Pos);
    NRF_GRTC->MODE = (GRTC_MODE_AUTOEN_Default << GRTC_MODE_AUTOEN_Pos) | (GRTC_MODE_SYSCOUNTEREN_Enabled << GRTC_MODE_SYSCOUNTEREN_Pos);
    NRF_GRTC->TASKS_CLEAR = 1;
    for (volatile int i = 0; i < 200; i++) {}
    for (int i = 0; i < 4; i++) NRF_GRTC->SYSCOUNTER[i].ACTIVE = 0;
    for (int i = 0; i < 12; i++) NRF_GRTC->CC[i].CCEN = 0;
    NRF_GRTC->TASKS_START = 1;

    // Delay ~3 LFCLK cycles
    NRF_TIMER20->TASKS_STOP = 1;
    NRF_TIMER20->TASKS_CLEAR = 1;
    NRF_TIMER20->PRESCALER = 4;
    NRF_TIMER20->EVENTS_COMPARE[0] = 0;
    NRF_TIMER20->CC[0] = 93;
    NRF_TIMER20->TASKS_START = 1;
    while (!NRF_TIMER20->EVENTS_COMPARE[0]) {
    }
    NRF_TIMER20->TASKS_STOP = 1;
    NRF_TIMER20->TASKS_CLEAR = 1;

    // These lines are not necessary to reproduce the issue
    for (;;) {
        (void)NRF_GRTC->SYSCOUNTER[0].SYSCOUNTERL;
        if (!(NRF_GRTC->SYSCOUNTER[0].SYSCOUNTERH & GRTC_SYSCOUNTER_SYSCOUNTERH_BUSY_Msk)) {
            break;
        }
    }

    // Set up to trigger a one-shot event when syscounter >= CC[0]
    NRF_GRTC->EVENTS_COMPARE[0] = 0;
    NRF_GRTC->CC[0].CCL = 5000;
    NRF_GRTC->CC[0].CCH = 0; // This write also enables the CC[0] event

    uint32_t cnt = 0;
    while (!NRF_GRTC->EVENTS_COMPARE[0]) {
        if (++cnt == 1000000) {
            // Turn on LED3
            // Often gets stuck here
            NRF_P1->OUTSET = 1U << 14;
        }
    }

    // Turn on LED1
    // Success case, happens very seldom
    NRF_P1->OUTSET = 1U << 10;
    return 0;
}

prj.conf:

CONFIG_SERIAL=n

The build settings use "nrf54l15dk/nrf54l15/cpuapp", "Nordic Kits" and the rest uses the default configuration. Flash the board and then press the reset button on the devkit and see which of the two LEDs of LED1 and LED3 that lights up. Press the reset button multiple times to repeat the test many times and notice the failure rate.

In this program, I configure a compare event to be triggered after 5 milliseconds. However, the event is never triggered, so the LED3 on the devkit turns on after a short timeout. The expected outcome is that the event is triggered so that LED1 lights up. In this particular example, the failure frequency is 100% on my new nRF54L15-PDK 0.8.1 but around 70% on my older devkit 0.7.0. Not sure if the difference is due to difference versions or if it is individual chip differences. It seems pretty random when the success case happens and when the failure case happens.

I've tried to read through the GRTC section in the data sheet multiple times to see if there is something I have missed, but have not found anything.

Could there be something important in the data sheet that is missing regarding configuration or required register write sequence, or is this a hardware bug?

Note that how easy it is to trigger the issue depends on e.g. the WAKETIME/TIMEOUT register settings. I have managed to reproduce the problem with a non-zero TIMEOUT and/or a smaller WAKETIME but that requires slightly more code. This is more or less the most simple example I could come up with.

Note that if I at the same time as I turn on LED3 due to timeout also implicitly force the GRTC into active state, e.g. by reading SYSCOUNTERL, then the event triggers at that point.

Note that it appears the problem cannot be reproduced with CONFIG_SERIAL=y.

I have also tried to run the same code in a "bare metal" project without Zephyr but the same issue is observed.

I'm attaching the project so you can test it directly. I guess you can flash the merged.hex file in the build directory in case the project cannot be built in VS Code for some reason.

grtc_test.tar.gz

Related