IC:

Introduction

Inter-Processor Communication (IPC) is a hardware-accelerated communication mechanism specifically designed for multi-core heterogeneous systems. It enables cross-core data interaction through shared SRAM, ensuring low-latency information transfer between multiple cores. Its core objective is to provide efficient collaborative capabilities for multi-core systems.

IPC Architecture

Hardware Architecture Features

The block diagram of IPC is illustrated in the following figure:

../../_images/ipc_block_diagram_dplus.svg
  1. Symmetric Structure

    • Each CPU is equipped with an identical IPC module.

  2. Full-Duplex Communication Model

    • Supports bidirectional, full-duplex communication.

  3. Channel Isolation

    • Channels are designed with hardware-level resource isolation, ensuring data transmission on any channel does not block others.

    • Supports parallel multi-channel operations (e.g., CPUA can simultaneously transmit sensor data via Channel n and log information via Channel m).

  4. Message Pool

    • A pre-allocated memory block where each IPC channel sends/receives messages through predefined fixed addresses in the pool.

  5. Shared Memory

    • For messages larger than 4 bytes: The sender dynamically allocates a shared memory block, writes the memory address into the message pool, and the receiver copies the data locally before the sender releases the shared memory.

    • For messages ≤4 bytes: Directly write the message into the message pool.

  6. NVIC Interrupt Generator

    • After data is ready in an IPC channel, writing to specific registers in the IPC block triggers a receive interrupt on the receiving end. Similarly, completing reception can trigger a transmission completion interrupt on the sender side.

Data Flow Model

  • Sender Process: [Shared Information] → Select available channel → Write to shared memory → Update channel register → Trigger remote interrupt → Remote core reads memory.

  • Receiver Process: Interrupt notification → Read channel register → Locate shared memory → Copy data locally → Process data → Clear interrupt flag.

IPC Definition

Channel

  • Concept: An IPC channel is a bidirectional, independent communication path between two IPC entities. Each direction contains multiple channels.

  • Purpose: Used to transmit send/receive events between two CPUs to achieve inter-core communication.

Component

IPC Configuration Table (IPC_INIT_TABLE)

  • Purpose: Defines all information for the entire transmission link, including data type, receive/transmit callback functions, interrupt handler parameters, transmission direction, and IPC channel number.

  • Usage: Users must place an instance of this structure in the IPC_TABLE_DATA_SECTION. The SDK will enable Tx/Rx interrupts for the corresponding channel and register interrupt handlers based on the structure’s members.

  • Structure Definition:

    IPC_TABLE_DATA_SECTION
    typedef struct _IPC_INIT_TABLE_ {
       u32 USER_MSG_TYPE;  /* Data type: IPC_USER_DATA (data less than 32 bits) or IPC_USER_POINT (address of data larger than 32 bits) */
       void (*Rxfunc)(void *Data, u32 IrqStatus, u32 ChanNum); /* Receive interrupt callback function */
       void *RxIrqData;    /* Parameter for receive callback function */
       void (*Txfunc)(void *Data, u32 IrqStatus, u32 ChanNum); /* Transmit completion interrupt callback function */
       void *TxIrqData;    /* Parameter for transmit callback function */
       u32 IPC_Direction;  /* Transmission direction */
       u32 IPC_Channel;    /* IPC channel number */
    } IPC_INIT_TABLE, *PIPC_INIT_TABLE;
    

IPC Data Structure (IPC_MSG_STRUCT)

  • Purpose: In the message pool, each IPC channel has a fixed location to store the IPC_MSG_STRUCT structure, which is used to store and transmit data.

  • Structure Definition:

    typedef struct ipc_msg_struct {
    u32 msg_type;   /* Data type, same as USER_MSG_TYPE */
    u32 msg;       /* 32-bit data to transmit or data address (for data larger than 32 bits) */
    u32 msg_len;    /* Data length */
    u32 rsvd;      /* Reserved field */
    } IPC_MSG_STRUCT, *PIPC_MSG_STRUCT, ipc_msg_struct_t;
    

IPC Standard Usage

  1. Communication Protocol Stack Registration

    1.1 Channel Selection

    1. File Path: ameba_ipccfg.h

    2. Select and Define Channels:

      • Choose and customize channels by uncommenting and modifying their definitions. Example:

      1/* Uncomment Channel n and add a functional description */
      2#define IPC_N2A_Channeln  n  /*!< User-defined channel: Sensor data transfer from KM0 to KM4 */
      3...
      4//#define IPC_A2N_Channeln  n  /*!< User-defined channel: Sensor data transfer from KM4 to KM0 */
      
    3. Confirm Transmission Direction:

      1#define IPC_KM0_TO_KM4  0  // KM0 as sender, KM4 as receiver
      2#define IPC_KM4_TO_KM0  1  // Reverse direction
      
    4. Guidelines:

      1. Each direction supports 16 physical channels; channel numbers must be within 0–15.

      2. Avoid using system-reserved channels (e.g., those used by Wi-Fi/BT system components).

    1.2 Define Receiver Callback Function

    • The receiver callback function reads messages from the message pool. For pointer-type messages, use _memcpy() to copy shared data to local memory. The SDK automatically clears interrupt flags after the handler exits.

      1uint32_t local_buffer[32] = {0};
      2
      3/* Receive handler (interrupt context) */
      4void Rx_Channeln_Handler(void) {
      5   PIPC_MSG_STRUCT msg = ipc_get_message(IPC_KM0_TO_KM4, IPC_N2A_Channeln); /* Retrieve message metadata */
      6   uint32_t *sensor_data = (uint32_t*)msg->msg;  /* Extract data pointer */
      7   _memcpy(local_buffer, (void*)sensor_data, data_size);  /* Copy data to local (data length pre-agreed) */
      8   rtos_sema_give(ipc_sema);  /* Trigger task-level processing */
      9}
      

    1.3 Register IPC Configuration Table

    • Register an IPC configuration table for each channel on the receiver side. The SDK automatically enables receive interrupts.

       1 /* Channel configuration table */
       2IPC_TABLE_DATA_SECTION
       3const IPC_INIT_TABLE ipc_chn_config = {
       4   .msg_type    = IPC_USER_POINT,     // Message type: pointer (data > 32 bits)
       5   .rx_func     = Rx_Channeln_Handler,
       6   .rx_irq_data = NULL,               // No additional parameters
       7   .tx_func     = NULL,               // Unidirectional transfer (no TX callback)
       8   .tx_irq_data = NULL,
       9   .direction   = IPC_KM0_TO_KM4,     // Direction identifier
      10   .channel_num = IPC_N2A_Channeln    // Channel macro
      11};
      
  2. Data Transmission and Reception

    2.1. Sender Implementation

    • Call ipc_send_message() with direction, channel number, and message.

    • Example: IPC sends a request from KM0 to KM4 via Channel n.

       1 void send_sensor_data(void) {
       2   IPC_MSG_STRUCT ipc_msg_temp;
       3   sensor_buffer = read_sensor();  // Update shared memory
       4
       5   ipc_msg_temp.msg_type = IPC_USER_POINT; // Pointer-based transfer
       6   ipc_msg_temp.msg = (u32)&sensor_buffer;
       7   ipc_msg_temp.msg_len = 1;              // Data length (bytes)
       8   ipc_msg_temp.rsvd = 0;
       9
      10   /* Send shared data (SDK API) with timeout handling */
      11   ipc_send_message(IPC_KM0_TO_KM4, IPC_N2A_Channeln, &ipc_msg_temp);
      12 }
      

    2.2. Receiver Handling

    • The receiver thread monitors ipc_sema , processes data upon arrival, and proceeds to next steps.

       1 /* Interrupt context: Fast data capture */
       2void Rx_Channeln_Handler(void *data) {
       3}
       4
       5/* Task context: Data processing */
       6void ipc_task(void *param) {
       7   while (1) {
       8      /* Wait for data arrival */
       9      rtos_sema_take(ipc_sema, RTOS_WAIT_FOREVER);
      10      /* Process data (already copied to local_buffer via _memcpy) */
      11      data_pipeline_process(local_buffer);
      12   }
      13}
      

IPC Advanced Usage

Application Scenarios

When the channel is busy, the sending thread should yield scheduling promptly to avoid CPU resource occupation by polling, ensuring smooth system operation.

Transmission Acknowledgment Configuration

  1. Define Transmitter Callback Function

    • If the IPC_INIT_TABLE initializes a transmitter callback function, the SDK will automatically:

      • Enable the transmission completion interrupt for channel n.

      • Initialize the transmission semaphore (ipc_Semaphore) when the channel is busy and wait for its release to yield scheduling, preventing prolonged CPU occupation.

    • We recommend registering this handler as IPC_TXHandler() from ameba_ipc_api.c. This function releases the semaphore for channel n (ipc_Semaphore).

    • The SDK automatically clears interrupt flags upon IRQ exit.

    void IPC_TXHandler(void *Data, u32 IrqStatus, u32 ChanNum)
    {
       UNUSED(Data);
       UNUSED(IrqStatus);
    
       u32 CPUID = SYS_CPUID();
       IPC_TypeDef *IPCx = IPC_GetDevById(CPUID);
       /* Disable tx channeln interrupt */
       IPC_INTConfig(IPCx, ChanNum, DISABLE);
    
       if (ipc_Semaphore[ChanNum - IPC_TX_CHANNEL_SHIFT] != NULL) {
          /* Release semaphore */
          rtos_sema_give(ipc_Semaphore[ChanNum - IPC_TX_CHANNEL_SHIFT]);
       }
    }
    
  2. Register IPC Configuration Table

    A dedicated IPC configuration table must be registered for each channel on the transmitter side.

    (Note: Transmit/receive configurations can coexist in the same table but require compilation on both cores.)

    /* Channel configuration table */
    IPC_TABLE_DATA_SECTION
    const IPC_INIT_TABLE ipc_chn_config = {
       .msg_type    = IPC_USER_POINT,     // Transfer mode: pointer (data >32 bits)
       .rx_func     = NULL,               // No receive handler
       .rx_irq_data = NULL,               // No receive parameters
       .tx_func     = IPC_TXHandlerL,     // Transmit completion callback
       .tx_irq_data = NULL,
       .direction   = IPC_Direction,      // Direction identifier
       .channel_num = IPC_Channel         // Channel macro
    };
    

Troubleshooting

Channel Conflict

Phenomenon

Error log printed: Channel Conflict for CPU A Channel n ! Ignore If CPU Has Reset

Cause

Two interrupt callback functions are registered for the same channel

Solution

Check the IPC configuration table (IPC_INIT_TABLE) to confirm if the same channel has been registered repeatedly

Send Timeout

Phenomenon

Error log printed: IPC Request Timeout

Cause

The sender attempts to send data through the same channel again before the previous data has been received

Solution

  • Examine the sending logic at the sender, reduce the sending frequency, or introduce a handshake mechanism when multiple threads use the same channel for sending to avoid conflicts

  • Check if the receiver is stuck or trapped in a higher-priority interrupt for an extended period

Semaphore Acquisition Timeout

Phenomenon

Error log printed: IPC Get Semaphore Timeout

Cause

The sender has registered a send completion callback function. The sender attempts to send data through the same channel again before the previous data has been received,

resulting in a timeout while waiting for a semaphore

Solution

  • Examine the sending logic at the sender, reduce the sending frequency, or introduce a handshake mechanism when multiple threads use the same channel for sending to avoid conflicts

  • Check if the receiver is stuck or trapped in a higher-priority interrupt

  • Avoid more than two threads using the same channel simultaneously

No Response from Receiver

Phenomenon 1

A specific IPC channel on the receiver is not responding

Cause

The interrupt for that channel on the receiver has been mistakenly disabled

Solution

Check if the interrupt for the channel has been mistakenly disabled on the receiver and enable it by calling IPC_INTConfig()

Phenomenon 2

All IPC channels on the receiver are not responding

Cause

  • The IPC interrupt on the receiver has been mistakenly disabled

  • The channel direction configuration is incorrect

Solution

  • Check if the IPC interrupt has been mistakenly disabled on the receiver and enable it by calling InterruptRegister()

  • Verify that the direction field in IPC_INIT_TABLE is configured correctly

IPC Application