Multiple IPC channels

Hello,

Referencing this link here, I am looking for any updates to using IPC for some custom inter-core communication WHILE ALSO running Bluetooth on an nrf5340.

Long story short, I have a project with custom code for both the cpu_app and cpu_net cores of an nrf5340, and I am looking for a way to communicate between both. Right now, the cpu_net code is running the hci_rpmsg sample so that I can use BLE from the application core. I have not found a clean way to modify this to provide some hooks for my custom use case, nor do I want to try.

If there are any updates on being able to use a custom IPC channel and BLE at the same time, or if IPC is not the right abstraction layer to go through, please let me know! The link I provided mention using the BTS but I am not sure how that is relevant or possible.

I know that there are some complex structures being put to use here and I have tried to spend some time learning it but perhaps there is an easy-to-follow overview of inter-process communication that shows us how IPC, RMPSG, ICMSG, MBOX, shared SRAM and all other abstraction layers play together.

Thank you much.

Parents
  • Hi!

    The right abstraction layer will depend on what you want to send / communicate between the core. 

    If you want to e.g. call a function to run on the net core, from the app core, then maybe Remote procedure call library is the way to go. You can see how that's used in e.g. this sample: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/samples/nrf_rpc/entropy_nrf53/README.html

  • What if I want an event that can be heard between cores?

    For example, if I am using the time sync sample to synchronize a clock on the network core, can I have the the application core subscribe to tick events from that timer? I know that the timer peripherals for both cores are treated separately, so if this is not possible, are there any sort of events I can trigger that will signal between the cores?

    The ultimate goal is to have a system that runs in the background that:

    • synchronizes a clock
    • takes ADC readings on tick events of that clock
    • notifies the foreground code when a buffer of ADC samples is complete
    • repeats this cycle

    We managed to complete this in the nrf5 SDK on the 52832 but need it now on the 5340 with NCS. If there is a way you can imagine sharing events between core's or even signaling to each core in the background that would be great.

    I will play around with this remote procedure library.

    Thanks

  • Hi!

    I was able to get it to run in a BLE application. I'm not seeing any crashes here.

    Did some minor modifications to the original example code.

    Network core:

    On hci_rpmsg sample I added this:

    /////////////
    #include <nrfx_timer.h>
    #include <nrfx_dppi.h>
    #include <nrfx_ipc.h>
    
    // Get a reference to the TIMER instance
    static const nrfx_timer_t sync_timer = NRFX_TIMER_INSTANCE(2);
    
    // Interrupt handler for the timer
    // NOTE: This callback is triggered by an interrupt. Many drivers or modules in Zephyr can not be accessed directly from interrupts, 
    //		 and if you need to access one of these from the timer callback it is necessary to use something like a k_work item to move execution out of the interrupt context. 
    void sync_timer_event_handler(nrf_timer_event_t event_type, void * p_context)
    {
    	static int counter = 0;
    	switch(event_type) {
    		case NRF_TIMER_EVENT_COMPARE0:
    			printk("Sync timer callback. Counter = %d\n", counter++);
    			break;
    		
    		default:
    			break;
    	}
    }
    
    // Function for initializing the TIMER peripheral using the nrfx driver
    static void sync_timer_init(void)
    {
    	uint32_t base_frequency = NRF_TIMER_BASE_FREQUENCY_GET(sync_timer.p_reg);
    	nrfx_timer_config_t timer_config = NRFX_TIMER_DEFAULT_CONFIG(base_frequency);
    	timer_config.bit_width = NRF_TIMER_BIT_WIDTH_16;
    
    	int err = nrfx_timer_init(&sync_timer, &timer_config, sync_timer_event_handler);
    	if (err != NRFX_SUCCESS) {
    		printk("Error initializing timer: %x\n", err);
    	}
    	
    	// Trigger a callback 10us after the timer is reloaded by the appcore
    	nrfx_timer_extended_compare(&sync_timer, NRF_TIMER_CC_CHANNEL0, 10, 0, true);
    
    	IRQ_DIRECT_CONNECT(TIMER2_IRQn, 1, nrfx_timer_2_irq_handler, 0);
    	irq_enable(TIMER2_IRQn);
    }
    
    static void synchronized_start_init(void)
    {
    	uint8_t dppi_ch;
    
    	// DPPI init
    	nrfx_dppi_channel_alloc(&dppi_ch);
    	NRF_TIMER0->SUBSCRIBE_CLEAR = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | dppi_ch;
    	nrfx_dppi_channel_enable(dppi_ch);
    
    	// IPC init
    	uint8_t ipc_ch = 5;
    	NRF_IPC->RECEIVE_CNF[ipc_ch] = BIT(ipc_ch);
    	NRF_IPC->PUBLISH_RECEIVE[ipc_ch] = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | dppi_ch;
    
    	nrfx_timer_enable(&sync_timer);
    }
    
    /////////////
    
    int main(void)
    {
    	int err;
    
    	sync_timer_init();
    	synchronized_start_init();

    Added to prj.conf (samples\bluetooth\hci_rpmsg\prj.conf)

    CONFIG_NRFX_DPPI=y
    CONFIG_NRFX_EGU1=y
    CONFIG_NRFX_IPC=y
    CONFIG_NRFX_TIMER2=y

    Application core:

    On the BLE app:

    ///////////////////////
    
    #include <nrfx_timer.h>
    #include <nrfx_dppi.h>
    #include <nrfx_egu.h>
    #include <nrfx_ipc.h>
    
    
    // Get a reference to the TIMER instance
    static const nrfx_timer_t sync_timer = NRFX_TIMER_INSTANCE(2);
    
    // Interrupt handler for the timer
    // NOTE: This callback is triggered by an interrupt. Many drivers or modules in Zephyr can not be accessed directly from interrupts, 
    //		 and if you need to access one of these from the timer callback it is necessary to use something like a k_work item to move execution out of the interrupt context. 
    void sync_timer_event_handler(nrf_timer_event_t event_type, void * p_context)
    {
    	static int counter = 0;
    	switch(event_type) {
    		case NRF_TIMER_EVENT_COMPARE1:
    			printk("Sync timer callback. Counter = %d\n", counter++);
    			break;
    		
    		default:
    			break;
    	}
    }
    
    // Function for initializing the TIMER peripheral using the nrfx driver
    static void sync_timer_init(void)
    {
    	uint32_t base_frequency = NRF_TIMER_BASE_FREQUENCY_GET(sync_timer.p_reg);
    	nrfx_timer_config_t timer_config = NRFX_TIMER_DEFAULT_CONFIG(base_frequency);
    	timer_config.bit_width = NRF_TIMER_BIT_WIDTH_16;
    
    	int err = nrfx_timer_init(&sync_timer, &timer_config, sync_timer_event_handler);
    	if (err != NRFX_SUCCESS) {
    		printk("Error initializing timer: %x\n", err);
    	}
    
    	IRQ_DIRECT_CONNECT(TIMER2_IRQn, 1, nrfx_timer_2_irq_handler, 0);
    	irq_enable(TIMER2_IRQn);
    }
    
    // Function for scheduling repeated callbacks from the timer
    static void sync_timer_repeated_configure(uint32_t timeout_us)
    {
    	nrfx_timer_extended_compare(&sync_timer, NRF_TIMER_CC_CHANNEL0, timeout_us, 
                                    NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);
    	
    	// Trigger a callback 10us after the timer is reloaded
    	nrfx_timer_extended_compare(&sync_timer, NRF_TIMER_CC_CHANNEL1, 10, 0, true);
    }
    
    static void synchronized_start_init(void)
    {
    	uint8_t dppi_ch;
    
    	// DPPI init
    	nrfx_dppi_channel_alloc(&dppi_ch);
    	//NRF_EGU1->PUBLISH_TRIGGERED[0] = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | dppi_ch;
    	NRF_TIMER2->PUBLISH_COMPARE[0] = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | dppi_ch;
    	nrfx_dppi_channel_enable(dppi_ch);
    
    	// IPC init
    	uint8_t ipc_ch = 5;
    	NRF_IPC->SEND_CNF[ipc_ch] = BIT(ipc_ch);
    	NRF_IPC->SUBSCRIBE_SEND[ipc_ch] = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | dppi_ch;
    }
    
    static void synchronized_start_activate(void)
    {
    	NRF_TIMER2->TASKS_START = 1;
    }
    
    //////////////////////

    Added to prj.conf

    CONFIG_NRFX_DPPI=y
    CONFIG_NRFX_EGU1=y
    CONFIG_NRFX_IPC=y
    CONFIG_NRFX_TIMER2=y

    BR,

    Sigurd

  • I am still getting the same crash as before. Here is what I am doing in the BLE app (cpu_app main.c file).

    Note this code runs AFTER the ble_ready callback is hit.

    Any other ideas on what is causing this crash? I am iterating through my code to toggle different sections/features to narrow down what might be causing the crash.

  • I tested it with the peripheral_lbs example, and did not see a crash.

    Here is how and where in the main() I added it: (cpu_app main.c file)

    int main(void)
    {
    	int blink_status = 0;
    	int err;
    
    	printk("Starting Bluetooth Peripheral LBS example\n");
    
    	err = dk_leds_init();
    	if (err) {
    		printk("LEDs init failed (err %d)\n", err);
    		return 0;
    	}
    
    	err = init_button();
    	if (err) {
    		printk("Button init failed (err %d)\n", err);
    		return 0;
    	}
    
    	if (IS_ENABLED(CONFIG_BT_LBS_SECURITY_ENABLED)) {
    		err = bt_conn_auth_cb_register(&conn_auth_callbacks);
    		if (err) {
    			printk("Failed to register authorization callbacks.\n");
    			return 0;
    		}
    
    		err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
    		if (err) {
    			printk("Failed to register authorization info callbacks.\n");
    			return 0;
    		}
    	}
    
    	err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return 0;
    	}
    
    	printk("Bluetooth initialized\n");
    
    	if (IS_ENABLED(CONFIG_SETTINGS)) {
    		settings_load();
    	}
    
    	err = bt_lbs_init(&lbs_callbacs);
    	if (err) {
    		printk("Failed to init LBS (err:%d)\n", err);
    		return 0;
    	}
    
    	err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad),
    			      sd, ARRAY_SIZE(sd));
    	if (err) {
    		printk("Advertising failed to start (err %d)\n", err);
    		return 0;
    	}
    
    	printk("Advertising successfully started\n");
    
    	sync_timer_init();
    
    	sync_timer_repeated_configure(1000000);
    
    	synchronized_start_init();
    	k_msleep(1000);
    	synchronized_start_activate();
    
    
    
    	for (;;) {
    		dk_set_led(RUN_STATUS_LED, (++blink_status) % 2);
    		k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
    	}
    }

  • Thanks for this. I validated your sample then I was able to integrate it into my project pretty well.

    This will be very helpful moving forward. My question now is that I will need a little bit of shared data to go back and forth. Up to 6 bytes.

    This does not need to be triggered in the backend with DPPI or other peripherals. It can look more like the RPC sample - however I also struggled with this alongside BLE.

    First of all, is RPC the correct one to use? This is what I wanted to get to work: developer.nordicsemi.com/.../README.html

  • Hi!

    Robert de Brum said:
    Thanks for this. I validated your sample then I was able to integrate it into my project pretty well.

    Great!

    Robert de Brum said:
    First of all, is RPC the correct one to use?

    It looks to fulfill your use-case. Only thing I can think of right now for why it should not work with BLE, is that there could be a conflict with SDC/MPSL and the entropy driver. Maybe try to send some predefined bytes instead of random ones gathered from the entropy driver.

Reply
  • Hi!

    Robert de Brum said:
    Thanks for this. I validated your sample then I was able to integrate it into my project pretty well.

    Great!

    Robert de Brum said:
    First of all, is RPC the correct one to use?

    It looks to fulfill your use-case. Only thing I can think of right now for why it should not work with BLE, is that there could be a conflict with SDC/MPSL and the entropy driver. Maybe try to send some predefined bytes instead of random ones gathered from the entropy driver.

Children
No Data
Related