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

Hi,

I am working on a sensor device that requires very accurate timing on the sensing and sensor signal algorithm side. This device needs a low latency and low jitter radio transmission in one use case (A) sending very low volume of data (send to receive < 1ms) and another use case (B) with a lot higher data volume but less strict requirements on latency and jitter. The device should be able to switch back and forth between these two use cases via a push button on the device.

I chose nrf5340 for this device, because with its two cores I can keep my sensor-algo on the app core and (almost) independently have all radio operation on the net core.

My implementation keeps all app core (sensor) code the same for both use cases, sending messages to the net core via IPC. All difference between (A) and (B) is implemented in the software running on the net-core. Aside from some small part of the code processing the IPC-messages use case specific, the main difference is, that use case (A) uses ESB (Enhanced Shock Burst) for radio transmission and use case (B) uses BLE.

Currently I have successfully implemented use case (A) and use case (B) - but I only can build and successfully run the code for use case (A) by using one set of config parameters and (B) by using a different set of config parameters and select the code to be compiled by #if statements depending on config parameters.

As soon as I try to enable BLE and ESB at the same time, I need to activate MPSL and dynamic interrupt config parameters - as in the unofficial sample code for using both protocols concurrently. This, however, leads to interrupt problems with operating IPC or build problems, that I am not able to solve - and especially, that I do not understand the need for.

My question: Is there a way to build and run for BLE- and ESB-use alternatively instead of concurrently, while being able to switch between these protocols without restarting or reflashing the device... and, if possible, without the need for MPSL or dynamic interrupts?

To really keep the lowest possible jitter and latency, my pure ESB-implementation, which currently runs with latency far below 1 ms, should be able to run while BLE completely is inactive for use case (A). When the button is pressed, the device should completely switch off ESB and start BLE-operation and vice versa.

I have seen some questions similar to mine, but was not able to find a simple and solid solution without the use of MPSL and dynamic interrupts etc...keeping the great latency performance of IPC + ESB in my critical use case (A).

Thank you very much for any advice you can give me.

Regards,

Jens

Parents
  • Hi,

    There is an unofficial sample here which demonstrate using either BLE or ESB, swithing between the two but not running it concurrently: https://github.com/droidecahedron/esb_multi (esb_prx_blefallback).

  • Hi Einar,

    thank you very much for this sample, which looks very understandable on first sight. I already have noticed differences in configuration, that are influencing the behavior of my code significantly.

    Above sample uses two config parameters that I have not noticed in any other blue-esb sample before:

    CONFIG_BT_UNINIT_MPSL_ON_DISABLE=y

    CONFIG_MPSL_DYNAMIC_INTERRUPTS=y

    Adding these two to my prj.conf for the MPSL-case solves the underlying problem, that the software crashes on the first write call to ESB-radio. If I do not enable BLE in my code, but have BLE configured, I now can safely run ESB communication and the other way around. So: one step ahead already! 

    I still need to look deeper into switching back and forth between protocols though. 

    Unfortunately I still do not completely understand, why I need to use MPSL in this at all, but it looks to me like the bluetooth implementation uses MPSL „implicitly“ - so some MPSL is active as soon as BLE is enabled… and I „actively“ need to have the system disable MPSL, if I have BLE configured, but need to use the radio in any other way.

    I would really appreciate, if you could explain the need for MPSL in this use case in a few words, because I probably will need to understand the configuration a little more in depth for further trouble shooting.

    Thanks a lot for your explanation in advance!

    I will let you know, if I can solve my switching of protocol topic completely with the help of this sample or if I need further assistance on this.

    Regards,

    Jens

  • Hi Einar,

    I found out, that sdk v2.6.4 seems to be the last version released for my MacOS 13. Therefore I upgraded to v2.6.4. After finding out, how to make it work after this upgrade (I had to configure to disable the partition manager), unfortunately at first the behavior of my software did not change at all.

    But then I remembered the following in https://github.com/too1/ncs-esb-ble-mpsl-demo/blob/master/app_netcore/src/main.c:

    LOG_WRN("Change ESB_EVT_IRQ and ESB_EVT_IRQHandler in esb_peripherals.h to use SWI3 instead of SWI0!");

    In sdk v2.6.4 this tweak seems to improve the situation: I changed these 2 entries to SWI3 within the sdk-file esb_peripherals.h.

    I had tried that before in sdk v2.4... but saw no change - and changed back, because of this.

    So far, however, this seems to be unstable for ESB-transmission in my setup, though - after some messages are transmitted, the transmission stops and restarts again after swapping to BLE and back. I will have to take a look into this, of course. BLE seems to run stable now...

    But, I really do not like to fiddle with sdk files like this. Is there any other way of changing this behavior without changing sdk files?

    Thank you very much in advance for all further advice!

    Regards,

    Jens

  • Hi Einar,

    I believed I solved my instability problem. It seems to have been due to extremely heavy logging tasks for BLE and elsewhere in my code (left overs from debugging this problem) leading to race conditions and blocking. After deactivating most of the logging, so far my software seems to be stable over the limited time I have been testing now.

    So, the only thing left is the necessary change to the SDK file "esb_peripherals.h". Is there any better approach than to fiddle with the SDK files?... or, if this is the only way to solve it in v2.6.4, a fix in SDK versions after v2.6.4?

    Thanks for an answer and perspective to this final question related to this thread. I do not feel too confident with this SDK-hack for the long term.

    Regards,

    Jens

  • Hi Jens,

    Thank you for letting me know that you see this working in a stable way now. As you write, the interrupt number is currently hard coded so you will have to modify the SDK code for now. But I have made an internal ticket so that this can be updated to be configurable in another way in the future.

    Br,

    Einar

  • Thank you, Einar!

    So solution for my case in short is now: 

    - use no older than SDK v2.6.4

    - take the CONFIG parameters e.g. from 

    - change the interrupt number in the esb_peripherals.h of the sdk as can be read in the warning message in this other sample (which will not be necessary as "SDK hack" after your internal ticket has been resolved):

    https://github.com/too1/ncs-esb-ble-mpsl-demo/blob/master/app_netcore/src/main.c:

    LOG_WRN("Change ESB_EVT_IRQ and ESB_EVT_IRQHandler in esb_peripherals.h to use SWI3 instead of SWI0!");

    - take care to actively give other threads "enough room to execute" by scheduling the swap steps in tasks for the system work queue of zephyr (executing with prio -1).

    - do not use excessive logging ;-) if you do not want to run into stability problems...

    So much for now - and thanks again! Solved from my perspective.

    Jens

  • I am looking at the code for SDK v3.3.0-preview, and it's still SWI0. Why is that?

    #if defined(CONFIG_SOC_SERIES_NRF54H)
    
    	/** The ESB EVT IRQ is using EGU on nRF54 devices. */
    	#define ESB_EVT_IRQ_NUMBER EGU020_IRQn
    	#define ESB_EVT_USING_EGU 1
    
    	/** The ESB Radio interrupt number. */
    	#define ESB_RADIO_IRQ_NUMBER RADIO_0_IRQn
    
    	/** DPPIC instance number used by ESB. */
    	#define ESB_DPPIC_INSTANCE_NO 020
    
    	/** ESB EGU instance configuration. */
    	#define ESB_EGU NRF_EGU020
    
    	/** Use end of packet send/received over the air for nRF54 devices. */
    	#define ESB_RADIO_EVENT_END NRF_RADIO_EVENT_PHYEND
    	#define ESB_RADIO_SHORT_END_DISABLE NRF_RADIO_SHORT_PHYEND_DISABLE_MASK
    
    	#define ESB_RADIO_INT_END_MASK NRF_RADIO_INT_PHYEND_MASK
    
    #elif defined(CONFIG_SOC_SERIES_NRF54L)
    
    	/** The ESB EVT IRQ is using EGU on nRF54 devices. */
    	#define ESB_EVT_IRQ_NUMBER EGU10_IRQn
    	#define ESB_EVT_USING_EGU 1
    
    	/** The ESB Radio interrupt number. */
    	#define ESB_RADIO_IRQ_NUMBER RADIO_0_IRQn
    
    	/** DPPIC instance number used by ESB. */
    	#define ESB_DPPIC_INSTANCE_NO 10
    
    	/** ESB EGU instance configuration. */
    	#define ESB_EGU NRF_EGU10
    
    	/** Use end of packet send/received over the air for nRF54 devices. */
    	#define ESB_RADIO_EVENT_END NRF_RADIO_EVENT_PHYEND
    	#define ESB_RADIO_SHORT_END_DISABLE NRF_RADIO_SHORT_PHYEND_DISABLE_MASK
    
    	#define ESB_RADIO_INT_END_MASK NRF_RADIO_INT_PHYEND_MASK
    #else
    
    	/** The ESB event IRQ number when running on the nRF52 and nRF53 device. */
    	#define ESB_EVT_IRQ_NUMBER SWI0_IRQn
    
    	/** The ESB Radio interrupt number. */
    	#define ESB_RADIO_IRQ_NUMBER RADIO_IRQn
    
    	/** ESB EGU instance configuration. */
    	#define ESB_EGU NRF_EGU0
    
    	/** nRF52 and nRF53 device has just one kind of end event. */
    	#define ESB_RADIO_EVENT_END NRF_RADIO_EVENT_END
    	#define ESB_RADIO_SHORT_END_DISABLE NRF_RADIO_SHORT_END_DISABLE_MASK
    
    	#define ESB_RADIO_INT_END_MASK NRF_RADIO_INT_END_MASK
    
    #endif

Reply
  • I am looking at the code for SDK v3.3.0-preview, and it's still SWI0. Why is that?

    #if defined(CONFIG_SOC_SERIES_NRF54H)
    
    	/** The ESB EVT IRQ is using EGU on nRF54 devices. */
    	#define ESB_EVT_IRQ_NUMBER EGU020_IRQn
    	#define ESB_EVT_USING_EGU 1
    
    	/** The ESB Radio interrupt number. */
    	#define ESB_RADIO_IRQ_NUMBER RADIO_0_IRQn
    
    	/** DPPIC instance number used by ESB. */
    	#define ESB_DPPIC_INSTANCE_NO 020
    
    	/** ESB EGU instance configuration. */
    	#define ESB_EGU NRF_EGU020
    
    	/** Use end of packet send/received over the air for nRF54 devices. */
    	#define ESB_RADIO_EVENT_END NRF_RADIO_EVENT_PHYEND
    	#define ESB_RADIO_SHORT_END_DISABLE NRF_RADIO_SHORT_PHYEND_DISABLE_MASK
    
    	#define ESB_RADIO_INT_END_MASK NRF_RADIO_INT_PHYEND_MASK
    
    #elif defined(CONFIG_SOC_SERIES_NRF54L)
    
    	/** The ESB EVT IRQ is using EGU on nRF54 devices. */
    	#define ESB_EVT_IRQ_NUMBER EGU10_IRQn
    	#define ESB_EVT_USING_EGU 1
    
    	/** The ESB Radio interrupt number. */
    	#define ESB_RADIO_IRQ_NUMBER RADIO_0_IRQn
    
    	/** DPPIC instance number used by ESB. */
    	#define ESB_DPPIC_INSTANCE_NO 10
    
    	/** ESB EGU instance configuration. */
    	#define ESB_EGU NRF_EGU10
    
    	/** Use end of packet send/received over the air for nRF54 devices. */
    	#define ESB_RADIO_EVENT_END NRF_RADIO_EVENT_PHYEND
    	#define ESB_RADIO_SHORT_END_DISABLE NRF_RADIO_SHORT_PHYEND_DISABLE_MASK
    
    	#define ESB_RADIO_INT_END_MASK NRF_RADIO_INT_PHYEND_MASK
    #else
    
    	/** The ESB event IRQ number when running on the nRF52 and nRF53 device. */
    	#define ESB_EVT_IRQ_NUMBER SWI0_IRQn
    
    	/** The ESB Radio interrupt number. */
    	#define ESB_RADIO_IRQ_NUMBER RADIO_IRQn
    
    	/** ESB EGU instance configuration. */
    	#define ESB_EGU NRF_EGU0
    
    	/** nRF52 and nRF53 device has just one kind of end event. */
    	#define ESB_RADIO_EVENT_END NRF_RADIO_EVENT_END
    	#define ESB_RADIO_SHORT_END_DISABLE NRF_RADIO_SHORT_END_DISABLE_MASK
    
    	#define ESB_RADIO_INT_END_MASK NRF_RADIO_INT_END_MASK
    
    #endif

Children
No Data
Related