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?

Parents
  • Thanks Hieu for your kind reply. 

    Sebastian, The MPSL developer tried to replicate the issue and TIMER10 was running at the start of the timeslot when the same not closed session id was used. It seems something else is happening in your setup or a corner case we cannot reproduce. Please help us reproduce this. I see that TIMER10 in the code is handled the exact same way as other times with macro magic, but maybe what you are seeing might be a hardware glitch in this timer in some special scenario. Hard to know unless we manage to reproduce it here.

  • It is on my todo list to reproduce this in a small example.

    From what I can see from the include file, only DPPI channel 0 on PD 10 is used by MPSL. If our code triggers it, could that stop the timer?

    We use some one GRTC channel (should only be channel 0) and some TIMER10 capture/compare channels (0-3). Could that cause it to stop?

  • SebastianA said:
    From what I can see from the include file, only DPPI channel 0 on PD 10 is used by MPSL. If our code triggers it, could that stop the timer?

    Not sure what you mean by "if your code triggers it"? You should not use any triggers with the resource that MPSL is using.

    SebastianA said:
    We use some one GRTC channel (should only be channel 0) and some TIMER10 capture/compare channels (0-3). Could that cause it to stop?

    This is possible. Can you show me some snippets on how you are using the GRTC and TIMER10 channels and the exact context in which these registers are touched/configured in your application.

Reply
  • SebastianA said:
    From what I can see from the include file, only DPPI channel 0 on PD 10 is used by MPSL. If our code triggers it, could that stop the timer?

    Not sure what you mean by "if your code triggers it"? You should not use any triggers with the resource that MPSL is using.

    SebastianA said:
    We use some one GRTC channel (should only be channel 0) and some TIMER10 capture/compare channels (0-3). Could that cause it to stop?

    This is possible. Can you show me some snippets on how you are using the GRTC and TIMER10 channels and the exact context in which these registers are touched/configured in your application.

Children
  • 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