A bare metal example of Inter Processor Communication (IPC) on nrf5340

Dear experts,

I am programming bare metal using Segger Embedded Studio and nrf.h and want to achieve a simple example of network core sending data to the application core.

Since the network core runs in non-secure domain and application core runs in secure domain, there is a bit of initialization needed but I cannot get it to work.

Here is my example:

In main() on the application core, I run

  spu_configure();
  ipc_rx_configure();
  ipc_rx_recieve();


spu:

#include "SPU.h"

// IPC is peripheral ID 42 on nRF5340
#define IPC_PERIPH_ID 42

void spu_configure(void) {
// In secure boot eller startup på application core

// Configure RAM region 63 (0x2003E000-0x2003FFF) as non-secure
NRF_SPU_S->RAMREGION[63].PERM =
   (SPU_RAMREGION_PERM_READ_Msk |
    SPU_RAMREGION_PERM_WRITE_Msk |
    SPU_RAMREGION_PERM_EXECUTE_Msk);    // SECATTR bit is 0 => non-secure


NRF_SPU_S->PERIPHID[IPC_PERIPH_ID].PERM &= ~SPU_PERIPHID_PERM_SECATTR_NonSecure; 
                                        // SECATTR = 0 => non-secure access
}



and ipc_rx

#include "ipc_rx.h"

#define SHARED_MEM_ADDR ((volatile uint8_t*)0x2003E000)

typedef struct {
    uint8_t id;
    uint16_t value;
    char label[8];
} message_t;


// Configure the app core to trigger an event every time a message is transmitted from network core
void ipc_rx_configure(void) {


  // Enable interrupt for RECEIVE[0]
  NRF_IPC_S->INTENSET = IPC_INTENSET_RECEIVE0_Msk;
  NVIC_EnableIRQ(IPC_IRQn);
}


void ipc_rx_recieve(void) {

  // From now on this will be interrupt driven so stay here
  while (1) {
    __WFE();
    }

}

// This event will be triggered every time there is a message.
void IPC_IRQHandler(void) {
    if (NRF_IPC_S->EVENTS_RECEIVE[0]) {
        NRF_IPC_S->EVENTS_RECEIVE[0] = 0;

        message_t *msg = (message_t *)SHARED_MEM_ADDR;

        printf("Message: ");
        printf("%s", msg->label);
        printf(" \n");

        // Use msg->id, msg->value, msg->label
    
    }
}

In network core I run<

main()

 ipc_tx_configure();
 for (int i=1; i<1000; i++) {
  
  ipc_tx_transmit();
  
  for(int j=0; j<50000; j++) {
    float dummy = sinf(sinf(3.56));
    }
}



and ipc_tx

#include "ipc_tx.h"

#define SHARED_MEM_ADDR ((volatile uint8_t*)0x2003E000)

typedef struct {
    uint8_t id;
    uint16_t value;
    char label[8];
} message_t;


void ipc_tx_configure(void){

// Not really needed

}


void ipc_tx_transmit(void) {

    message_t *msg = (message_t *)SHARED_MEM_ADDR;

    msg->id = 1;
    msg->value = 1234;
    memcpy(msg->label, "TEMP", 5);

    // Trigger IPC event on channel 0
    NRF_IPC_NS->TASKS_SEND[0] = 1;

}



The code compiles and runs but I cannot seem to get the interrupt triggered on the application core

Any help appreciated.

/Jonas

Parents
  • A small update.

    I can get the interrupt to work now. The app core has to listen to channel 0 and the network core has to be started from the app core.

    // Configure the app core to trigger an event every time a message is transmitted from network core
    void ipc_rx_configure(void) {
    
      // Enable interrupt for RECEIVE[0]
      NRF_IPC_S->INTENSET = IPC_INTENSET_RECEIVE0_Msk;
    
      // Listen to channel 0
      NRF_IPC_S->RECEIVE_CNF[0] = 1;
      
      // Enable IPC interrupt in NVIC
      NVIC_EnableIRQ(IPC_IRQn);
    
      // Start up the network core
      NRF_RESET_S->NETWORK.FORCEOFF = RESET_NETWORK_FORCEOFF_FORCEOFF_Release;
    
    
    }



    Next up is to figure out how I can transfer a message through shared memory. 

    I read about that the IPC contains two registers for general purpose data GPMEM[0] and [1] but I cannot seem to get the data across to the other core.

    On the network core I use NRF_IPC_NS->GPMEM[0] = 27;
    and on the application core I try printf("Value %u", NRF_IPC_S->GPMEM[0]);

    but the value does not seem to get across and stays at 0. Also in the debugger.
    Any thoughts?

Reply
  • A small update.

    I can get the interrupt to work now. The app core has to listen to channel 0 and the network core has to be started from the app core.

    // Configure the app core to trigger an event every time a message is transmitted from network core
    void ipc_rx_configure(void) {
    
      // Enable interrupt for RECEIVE[0]
      NRF_IPC_S->INTENSET = IPC_INTENSET_RECEIVE0_Msk;
    
      // Listen to channel 0
      NRF_IPC_S->RECEIVE_CNF[0] = 1;
      
      // Enable IPC interrupt in NVIC
      NVIC_EnableIRQ(IPC_IRQn);
    
      // Start up the network core
      NRF_RESET_S->NETWORK.FORCEOFF = RESET_NETWORK_FORCEOFF_FORCEOFF_Release;
    
    
    }



    Next up is to figure out how I can transfer a message through shared memory. 

    I read about that the IPC contains two registers for general purpose data GPMEM[0] and [1] but I cannot seem to get the data across to the other core.

    On the network core I use NRF_IPC_NS->GPMEM[0] = 27;
    and on the application core I try printf("Value %u", NRF_IPC_S->GPMEM[0]);

    but the value does not seem to get across and stays at 0. Also in the debugger.
    Any thoughts?

Children
No Data
Related