About NCS3.1.X MPSL ASSERT

   Platform : NRF54L15
 NCS(2025.9): 3.0.2
NCS(2025.10): 3.1.1  Commit: e2a97fe2578a
      Zephyr: 4.1.99 Commit: ff8f0c579eeb

Cause of the issue
         Earlier, when I were producing products (around 600 units with 2025.9), about 30% of the chips had difficulty connecting. Later, it was found that the boards that disconnected immediately after connecting were stuck at "MPSL ASSERT: 109, 585."
         At that time, the SDK used was 3.0.2. After consulting AI, He was advised to increase CONFIG_MPSL_HFCLK_LATENCY to 1400-1650. The original SDK default was 845, and after I increased it to 1000, the connection yield of the product improved. However, the actual use was still not very stable.
         Until the 3.1.0 update in October 2025, which mentioned optimizations related to MPSL, I updated the SDK to 3.1.1. The actual use was indeed much more stable than 3.0.2, but "MPSL ASSERT: 109, 585" still occasionally occurred.



I think the assertion scenario may be due to the following two possibilities:
1. My system has long delay blocking, which may currently be reflected in the regular operation of RRAM in my system, such as writing logs to RRAM once per second, or writing to external norFlash.
      I have also evaluated the interface delay for writing to RRAM. The schemes are NVS > ZMS > RRAM single. Since using the system storage management scheme may cause uncontrollable and mysterious delays, I ended up directly operating on RRAM single.
2. The SDK 3.1.1 has not completely fixed the MPSL temperature drift issue.

Parents
  • Hi,

    Do you have a bootloader in the device? If so, can you double check that the LF clock source you have configured is the same in the bootloader and application? We have seen this assert before when the bootloader used LFXO and application used LFRC.

  • Yes, I have mcuboot, and all set the HFXO

    &hfxo {
    	load-capacitors = "internal";
    	load-capacitance-femtofarad = <16250>;
    };

  • Hi,

    I see. But what about the low frequency clock source configuration? Can you share that for both the bootloader and application? (I ask because of a known issue that can be triggered by a mismatch here, and this can then affect the HFXO as that is used to calibrate the LFRC). The workaround for that is to make sure that the same clock source is used in the bootloader and application.

  • During the early stages of the project, external matching capacitors were added in the PCB design. However, during later production, it was discovered that there was a significant frequency deviation, and even setting the calibration parameters to their maximum values could not achieve the target value. At that time, the test results showed a very low connection rate, with the measured frequency deviation exceeding 30K.

    Later, the oscillator circuit design was changed to match the EVB, without using external matching capacitors. The internal capacitor calibration value was used on the DTS, and each motherboard was calibrated during the production process. The target value was less than 15K. The DTS parameter 16250 indicates the default value. During the application initialization, I will use the calibration value set in production before initializing bt_enable.

    // Mcuboot Zephyr.dts
    clocks {
    
    		/* node '/clocks/pclk' defined in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:52 */
    		pclk: pclk {
    			compatible = "fixed-clock";     /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:53 */
    			#clock-cells = < 0x0 >;         /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:54 */
    			clock-frequency = < 0xf42400 >; /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:55 */
    			phandle = < 0xe >;              /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:579 */
    		};
    
    		/* node '/clocks/lfxo' defined in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:58 */
    		lfxo: lfxo {
    			compatible = "nordic,nrf54l-lfxo";        /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:59 */
    			#clock-cells = < 0x0 >;                   /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:60 */
    			clock-frequency = < 0x8000 >;             /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:61 */
    			load-capacitors = "internal";             /* in zephyr/boards/nordic/nrf54l15dk/nrf54l_05_10_15_cpuapp_common.dtsi:35 */
    			load-capacitance-femtofarad = < 0x4268 >; /* in zephyr/boards/nordic/nrf54l15dk/nrf54l_05_10_15_cpuapp_common.dtsi:36 */
    			phandle = < 0xd >;                        /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:579 */
    		};
    
    		/* node '/clocks/hfxo' defined in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:64 */
    		hfxo: hfxo {
    			compatible = "nordic,nrf54l-hfxo";        /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:65 */
    			#clock-cells = < 0x0 >;                   /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:66 */
    			clock-frequency = < 0x1e84800 >;          /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:67 */
    			startup-time-us = < 0x356 >;              /* in zephyr/boards/nordic/nrf54l15dk/nrf54l15dk_common.dtsi:112 */
    			load-capacitors = "internal";             /* in ../../shrm2/shrm_2/suunto/sysbuild/mcuboot/boards/nrf54l15dk_nrf54l15_cpuapp.overlay:29 */
    			load-capacitance-femtofarad = < 0x3f7a >; /* in ../../shrm2/shrm_2/suunto/sysbuild/mcuboot/boards/nrf54l15dk_nrf54l15_cpuapp.overlay:30 */
    			phandle = < 0x6 >;                        /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:226 */
    		};
    
    		/* node '/clocks/hfpll' defined in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:71 */
    		hfpll: hfpll {
    			compatible = "fixed-clock";      /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:72 */
    			#clock-cells = < 0x0 >;          /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:73 */
    			clock-frequency = < 0x7a12000 >; /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:74 */
    			phandle = < 0x1 >;               /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:30 */
    		};
    	};
    
    
    
    // application Zephyr.dts
    	clocks {
    		/* node '/clocks/pclk' defined in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:52 */
    		pclk: pclk {
    			compatible = "fixed-clock";     /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:53 */
    			#clock-cells = < 0x0 >;         /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:54 */
    			clock-frequency = < 0xf42400 >; /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:55 */
    			phandle = < 0xe >;              /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:579 */
    		};
    
    		/* node '/clocks/lfxo' defined in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:58 */
    		lfxo: lfxo {
    			compatible = "nordic,nrf54l-lfxo";        /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:59 */
    			#clock-cells = < 0x0 >;                   /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:60 */
    			clock-frequency = < 0x8000 >;             /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:61 */
    			load-capacitors = "internal";             /* in zephyr/boards/nordic/nrf54l15dk/nrf54l_05_10_15_cpuapp_common.dtsi:35 */
    			load-capacitance-femtofarad = < 0x4268 >; /* in zephyr/boards/nordic/nrf54l15dk/nrf54l_05_10_15_cpuapp_common.dtsi:36 */
    			phandle = < 0xd >;                        /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:579 */
    		};
    
    		/* node '/clocks/hfxo' defined in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:64 */
    		hfxo: hfxo {
    			compatible = "nordic,nrf54l-hfxo";        /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:65 */
    			#clock-cells = < 0x0 >;                   /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:66 */
    			clock-frequency = < 0x1e84800 >;          /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:67 */
    			startup-time-us = < 0x356 >;              /* in zephyr/boards/nordic/nrf54l15dk/nrf54l15dk_common.dtsi:112 */
    			load-capacitors = "internal";             /* in ../../shrm2/shrm_2/suunto/boards/nrf54l15dk_nrf54l15_cpuapp.overlay:148 */
    			load-capacitance-femtofarad = < 0x3f7a >; /* in ../../shrm2/shrm_2/suunto/boards/nrf54l15dk_nrf54l15_cpuapp.overlay:149 */
    			phandle = < 0x6 >;                        /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:226 */
    		};
    
    		/* node '/clocks/hfpll' defined in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:71 */
    		hfpll: hfpll {
    			compatible = "fixed-clock";      /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:72 */
    			#clock-cells = < 0x0 >;          /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:73 */
    			clock-frequency = < 0x7a12000 >; /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:74 */
    			phandle = < 0x1 >;               /* in zephyr/dts/vendor/nordic/nrf54l_05_10_15.dtsi:30 */
    		};
    	};

  • Hi,

    I see. Can you also let me know the which clock source is being used in the build for both the application and bootloader by checking the generated .config for both? Do you have CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC or CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL enabled there, and is it the same in both cases? If you have any other special use or interesting findings around he clock configuration or clock usage that could also be useful.

  • .config

    and I found they all set 

    CONFIG_DT_HAS_NORDIC_NRF54L_HFXO_ENABLED=y
    CONFIG_DT_HAS_NORDIC_NRF54L_LFXO_ENABLED=y

Reply Children
  • I see  this looks good. Can you le me know which 32.768 kHz and 32 MHz crystals you have? (exact part numbers so that I can see the datasheet)?

  • Hi,

    Thank you. Did you try a higher value for CONFIG_MPSL_HFCLK_LATENCY? It could be good to set this to 1650 and also update or the config for your board files if you set it there, similarly to what was done in the for he DK in this commit.

    It could also be useful to test the startup time of the 32 MHz crystal oscillator (HFXO). That can be done using this code snippet (put into for instance the hello_world sample project, and adjust the OUTPUT_PIN definition to a pin you can access on your hardware):

    #include <stdio.h>
    #include <hal/nrf_gpio.h>
    #include <zephyr/kernel.h>
    
    #define OUTPUT_PIN NRF_GPIO_PIN_MAP(2,6)
    
    int main(void)
    {
    	printf("Measuring HFXO startup time on %s\n", CONFIG_BOARD_TARGET);
    
    	// Coinfigure output pin
    	nrf_gpio_cfg_output(OUTPUT_PIN);
    	nrf_gpio_pin_clear(OUTPUT_PIN);
    
    	// Sleep for a seconds to avoid confusion. Only last pulse on the logic analyzer will then be relevant.
    	k_sleep(K_MSEC(1000));
    
    	NRF_CLOCK->EVENTS_XOTUNED = 0;
    	nrf_gpio_pin_set(OUTPUT_PIN);
    	NRF_CLOCK->TASKS_XOSTART = 1;
    	while (NRF_CLOCK->EVENTS_XOSTARTED == 0) {}
    	nrf_gpio_pin_clear(OUTPUT_PIN);
    	NRF_CLOCK->EVENTS_XOTUNED = 0;
    
      return 0;
    }
    

    Measure the last pulse, and the duration of that is the time from starting the HFXO until it is calibrated and ready for use with the radio. Then multiply this by two, and use that value with CONFIG_MPSL_HFCLK_LATENCY.

  • Increasing CONFIG_MPSL_HFCLK_LATENCY to 1650 is a very bad decision. I strongly urge the SDK not to do so. This will significantly increase the system's static power consumption, including the power consumption of the RF oscillator. Increasing this value will negate the efficiency of the high - end manufacturing process of NRF54.

    Regarding the code you provided, are you suggesting that I measure the 32M crystal oscillator at startup and dynamically set CONFIG_MPSL_HFCLK_LATENCY based on the obtained value?

  • Hi,

    It is only the default value that is increased as we have seen problems on several custom boards with higher value, and quite a few user use the DK board files without adapting properly to their needs. You are free to optimize the value to match your hardware. (The value 1650 is also what was used previously for many years for older devices when this was not configurable.)

    Yes. the latency should ideally be set based on the actual crystal you are using. This way, you can find a sweet spot that allows lower power consumption by not starting the crystal too early, while at the same time making sure it is started early enough for your specific crystal that you do not run into problems. Note the recommendation of multiplying the measured value by two (as explained in the API doc), as there are variations from crystal to crystal, and other factors like the temperature also affect startup time.

    EDIT: I read your post again now. I am not suggesting you do this dynamically. I suggest you test the startup time on your bench in room temperature on a typical device. Then use this as a basis for the static configuration.

Related