nRF54L15: System hangs in clocks_start() and triggers MPSL ASSERT 2, 62 when initializing ESB in a CONFIG_BT project (NCS 3.1.1)

I am developing a dual-mode HID device (mouse) using nRF54L15 with nRF Connect SDK v3.1.1. The device determines its mode (BLE_mouse or ESB) at boot time via a GPIO pin. Once the mode is selected, only that protocol runs until the next reset; they do not run simultaneously.
Both BLE_mouse and ESB codes work perfectly as standalone projects. However, when I merge them into one project (with CONFIG_BT=y), I encounter the following issues when trying to initialize ESB mode.
Scenario A: Initializing ESB without calling mpsl_lib_uninit()
If I call clocks_start() and then esb_initialize() directly, the system triggers an MPSL ASSERT and leads to a Hard Fault.
Code:
err = clocks_start();
if (err) {
    LOG_ERR("clocks_start failed: %d", err);
    return 0;
}
LOG_INF("esb_initialize");
esb_initialize(RFMOUSE_M);
Error Log:
E: MPSL ASSERT: 2, 62
E: ***** HARD FAULT *****
E:   Fault escalation (see below)
E: ARCH_EXCEPT with reason 3

E: r0/a1:  0x00000003  r1/a2:  0x0003393b  r2/a3:  0x20007f18
E: r3/a4:  0x00000003 r12/ip:  0x20004028 r14/lr:  0x0001ed73
E:  xpsr:  0x2100009a
E: Faulting instruction address (r15/pc): 0x0001ed82
E: >>> ZEPHYR FATAL ERROR 3: Kernel oops on CPU 0
E: Fault during interrupt handling

E: Current thread: 0x20004028 (idle)
E: Resetting system
Scenario B: Calling mpsl_lib_uninit() before ESB initialization
If I call mpsl_lib_uninit() to release resources first, the system hangs indefinitely inside the do-while loop of my clocks_start() function.
Code:
err = mpsl_lib_uninit();
if (err) {
    LOG_ERR("mpsl_lib_uninit failed: %d", err);
    return;
} else {
    LOG_INF("mpsl_lib_uninit Start");
}

err = clocks_start(); // Hangs here
if (err) {
    LOG_ERR("clocks_start failed: %d", err);
    return 0;
}
esb_initialize(RFMOUSE_M);
Clock Initialization Code (clocks_start):
int clocks_start(void)
{
    int err;
    int res;
    struct onoff_manager *clk_mgr;
    struct onoff_client clk_cli;
    
    clk_mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF);
    if (!clk_mgr) {
        LOG_ERR("Unable to get the Clock manager");
        return -ENXIO;
    }

    sys_notify_init_spinwait(&clk_cli.notify);
    
    err = onoff_request(clk_mgr, &clk_cli);
    if (err < 0) {
        LOG_ERR("Clock request failed: %d", err);
        return err;
    }
    
    do {
        // [Hang Point]: After mpsl_lib_uninit(), err never becomes 0.
        // It seems the notification for clock readiness is never triggered.
        err = sys_notify_fetch_result(&clk_cli.notify, &res);
        if (!err && res) {
            LOG_ERR("Clock could not be started: %d", res);
            return res;
        }
    } while (err);
    
    return 0;
Environment:
  • Chip: nRF54L15
  • SDK Version: nRF Connect SDK v3.1.1
  • Kconfig: CONFIG_BT=y, CONFIG_MPSL=y, CONFIG_ESB=y, CONFIG_DYNAMIC_INTERRUPTS=y
Question:
On nRF54L15 (NCS v3.1.1), what is the recommended standard procedure to completely release Radio and Clock resources from MPSL so that nrf_esb can be initialized and take full control?
Parents
  • Hi,

     

    This mspl error:

    E: MPSL ASSERT: 2, 62

    Indicates that MPSL is getting a RADIO_IRQ triggering while it is not expecting it. It sounds like there is an incorrect radio_irq setting when you're selecting ESB.

    Can you share the ordering of initialisation from your end?

    Scenario B: Calling mpsl_lib_uninit() before ESB initialization
    If I call mpsl_lib_uninit() to release resources first, the system hangs indefinitely inside the do-while loop of my clocks_start() function.

    Since you are using NCS v3.1.x, you can be seeing this error:

     RE: MPSL disabling USB interrupts 

    Which is fixed in ncs v3.2.0:

    https://docs.nordicsemi.com/bundle/ncs-3.2.0/page/nrfxlib/mpsl/CHANGELOG.html#d1920e1523

     

    However, this does not fully match up with your setup either. 

     

    Kind regards,

    Håkon

  • Dear Håkon,

    Thank you for your response. Here is the ordering of my initialization in main.c and my esb_initialize() function.
    My Initialization Sequence in main():
    if(Device_Mode == RFMOUSE_M)
    {
        err = clocks_start();
        if (err) {
            LOG_ERR("clocks_start failed: %d", err);
            return 0;
        }
        LOG_INF("esb_initialize");
        esb_initialize(RFMOUSE_M);
    }
    My esb_initialize() implementation:
    int esb_initialize(uint8_t RF_M)
    {
        int err;
        RF_Mode = RF_M;
    
        uint8_t base_addr_0[4] = {0xE7, 0xE7, 0xE7, 0xE7};
        uint8_t base_addr_1[4] = {0xC2, 0xC2, 0xC2, 0xC2};
        uint8_t addr_prefix[8] = {0xE7, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8};
        struct esb_config config = ESB_DEFAULT_CONFIG;
    
        config.protocol = ESB_PROTOCOL_ESB_DPL;
        config.retransmit_delay = 600;
        config.bitrate = ESB_BITRATE_4MBPS;
        config.event_handler = RF_event_handler;
        config.mode = ESB_MODE_PTX;
        config.selective_auto_ack = true;
        config.retransmit_count = 0;
        
        if (IS_ENABLED(CONFIG_ESB_FAST_SWITCHING)) {
            config.use_fast_ramp_up = true;
        }
    
        if(RF_Mode == RFDONGLE_M) {
            config.mode = ESB_MODE_PRX;
        }
    
        err = esb_init(&config);
        if (err) return err;
    
        esb_set_base_address_0(base_addr_0);
        esb_set_base_address_1(base_addr_1);
        esb_set_prefixes(addr_prefix, ARRAY_SIZE(addr_prefix));
        esb_set_rf_channel(Channel);
        esb_set_tx_power(0);
        
        if(RF_Mode == RFDONGLE_M) {
            err = esb_start_rx();
        }
        return 0;
    }
    Additional context:
    I am developing an 8K polling rate mouse application on nRF54L15 (NCS v3.1).
    To achieve this performance, I have enabled DPPIC10 in my project:
    CONFIG_NRFX_DPPIC10=y

    After further testing, I found the following behavior:

    • If I only call esb_init() without transmitting any data, the system runs normally.
    • However, once I call esb_write_payload() to start transmission, the system immediately triggers:
      MPSL ASSERT: 2, 62
    Any suggestions or insights would be greatly appreciated.
    Best Regards,
    Doris
  • Hi,

     

    Have you looked into the two samples mentioned in this thread?

     How to software-switch between ESB and BLE on a nrf5340 net-core? 

    I suspect there is a problem with the switch between ESB/BLE that is causing the radio_irq to be wrongly routed to mpsl.

     

    Kind regards,

    Håkon

Reply Children
No Data
Related