MPSL timeslot API stops TIMER10 at IDLE and doesn't restart it?

I'm porting some code from nRF52832/nRF52840 to nRF54L15 using the MPSL timeslot API. The old code uses MPSL version v2.5.1, the new v2.9.0.

The firmware opens a session and then schedules a timeslot. In the end the timeslot handler returns the END request, it gets a MPSL_TIMESLOT_SIGNAL_SESSION_IDLE and then it just returns NONE.

We don't close the session here.

Some time later we schedule a new timeslot with the same session id. The handler gets the START signal, but this time TIMER10 is not running. For nRF52, with the old version, TIMER0 was started for the new timeslot as well.

Is this a bug or is this the expected behaviour with v2.9.0?

  • No, of course we shouldn't use any of MPSLs resources. I'm just thinking if there is some bug somewhere in our code that causes them to be used anyway which in turn causes the TIMER10 to be stopped since there is no code that can stop the timer on its own in our code.

    We compile our code as application code with security, so GRTC IRQ channel 2 will be used.

    We use GRTC channel 0 to trigger an interrupt with a compare, this is run in thread mode:

    #define CPU_TIMER_GRTC_CALLBACK_CH       0
    #define CPU_TIMER_GRTC_RFTIMER_RAMPUP_CH 1
    
    #define RF_SLOTS_SYNC_10_DPPI            1
    #define RF_SLOTS_SYNC_20_DPPI            1
    #define RF_SLOTS_SYNC_11_21_PPIB       1
    #define RF_TIMER0 NRF_TIMER10
    #define RF_TIMER0_IRQn TIMER10_IRQn


        nrf_grtc_event_disable(NRF_GRTC, ~0);
    
        nrf_grtc_int_enable(NRF_GRTC,
            (1 << (GRTC_INTENSET0_COMPARE0_Pos + CPU_TIMER_GRTC_CALLBACK_CH)));
    
        nrf_grtc_sys_counter_set(NRF_GRTC, true);
        nrf_grtc_clksel_set(NRF_GRTC, NRF_GRTC_CLKSEL_LFXO);
        nrf_grtc_task_trigger(NRF_GRTC, NRF_GRTC_TASK_START);
    
        nrf_grtc_sys_counter_compare_event_enable(
            NRF_GRTC, CPU_TIMER_GRTC_CALLBACK_CH
        );
        
        nrf_grtc_sys_counter_cc_set(
            NRF_GRTC,
            CPU_TIMER_GRTC_CALLBACK_CH,
            cpu_timer_scheduled_counter
        );
        
        nrf_grtc_event_clear(NRF_GRTC,
            nrf_grtc_sys_counter_compare_event_get(CPU_TIMER_GRTC_CALLBACK_CH));
    
        NVIC_SetPriority(cpu_peripherials_cfg_grtc_irq,
            cpu_peripherials_cfg_grtc_irq_prio);
        NVIC_ClearPendingIRQ(cpu_peripherials_cfg_grtc_irq);
        NVIC_EnableIRQ(cpu_peripherials_cfg_grtc_irq);
    
    


    and in the interrupt handler we simply run:
        NRF_GRTC->EVENTS_COMPARE[CPU_TIMER_GRTC_CALLBACK_CH] = 0;
        nrf_grtc_sys_counter_cc_set(
            NRF_GRTC,
            CPU_TIMER_GRTC_CALLBACK_CH,
            cpu_timer_scheduled_counter
        );


    GRTC channel 1 is used to  trigger a capture in TIMER10 channel 3, we run this in a timeslot handler:


        nrf_timer_cc_set(RF_TIMER0, NRF_TIMER_CC_CHANNEL3, 0);
    
        nrf_grtc_publish_set(
            NRF_GRTC,
            nrf_grtc_sys_counter_compare_event_get(CPU_TIMER_GRTC_RFTIMER_RAMPUP_CH),
            RF_SLOTS_SYNC_20_DPPI);
        nrf_timer_subscribe_set(
            RF_TIMER0,
            NRF_TIMER_TASK_CAPTURE3,
            RF_SLOTS_SYNC_10_DPPI);
    
        nrf_ppib_subscribe_set(NRF_PPIB21,
            nrf_ppib_send_task_get(RF_SLOTS_SYNC_11_21_PPIB),
            RF_SLOTS_SYNC_20_DPPI);
        nrf_ppib_publish_set(NRF_PPIB11,
            nrf_ppib_receive_event_get(RF_SLOTS_SYNC_11_21_PPIB),
            RF_SLOTS_SYNC_10_DPPI);
    
        nrf_dppi_channels_enable(NRF_DPPIC10, 1 << RF_SLOTS_SYNC_10_DPPI);
        nrf_dppi_channels_enable(NRF_DPPIC20, 1 << RF_SLOTS_SYNC_20_DPPI);
    
        nrf_grtc_sys_counter_cc_add_set(
            NRF_GRTC,
            CPU_TIMER_GRTC_RFTIMER_RAMPUP_CH,
            100,
            NRF_GRTC_CC_ADD_REFERENCE_SYSCOUNTER);
    
        RF_TIMER0->TASKS_CAPTURE[2] = 1;
        __DSB();
        uint32_t cc2_time = nrf_timer_cc_get(RF_TIMER0, NRF_TIMER_CC_CHANNEL2);
        nrf_timer_cc_set(RF_TIMER0,
            NRF_TIMER_CC_CHANNEL2,
            cc2_time + RF_SLOTS_CPU_SYNC_INTERVAL + 100);
        
        nrf_timer_event_clear(RF_TIMER0, NRF_TIMER_EVENT_COMPARE2);
        NVIC_ClearPendingIRQ(RF_TIMER0_IRQn);
        nrf_timer_int_enable(RF_TIMER0, TIMER_INTENSET_COMPARE2_Msk);


    When we get the TIMER event in the timeslot handler for channel 2 we run:

        nrf_timer_event_clear(RF_TIMER0, NRF_TIMER_EVENT_COMPARE2);
        
        nrf_ppib_subscribe_clear(NRF_PPIB11,
            nrf_ppib_send_task_get(RF_SLOTS_SYNC_10_DPPI));
        nrf_ppib_subscribe_clear(NRF_PPIB21,
            nrf_ppib_receive_event_get(RF_SLOTS_SYNC_20_DPPI));
    
        nrf_dppi_channels_disable(NRF_DPPIC10, 1 << RF_SLOTS_SYNC_10_DPPI);
        nrf_dppi_channels_disable(NRF_DPPIC20, 1 << RF_SLOTS_SYNC_20_DPPI);
    
        uint64_t syscounter_time = nrf_grtc_sys_counter_cc_get(
            NRF_GRTC,
            CPU_TIMER_GRTC_RFTIMER_RAMPUP_CH);


Related