Hardware Abstraction Layer (HAL)
IPC (Inter-Processor Communication)

General Description

High level interface for communicating between processors on a multi-core device.

The IPC driver allows communication between multiple CPUs or between multiple tasks operating in different domains within a single CPU. It supports binary semaphores and message queues, similar to how they are used for task interactions in an RTOS envrionment.

Features

Quick Start

For binary semaphores, initialize the semaphore for the task/CPU. Then take/give the semaphore. For queues, only one task/CPU may initialize a queue. Other tasks/CPUs then get the handle of the created queue. Use the get/put functions to take out or put in items to the queue.

Code Snippets

Snippet 1: Binary semaphore example

/* General: error handling is not shown. Use CY_ASSERT(CY_RSLT_SUCCESS == result); to check */
#define SEMAPHORE_NUM 0UL
/*************************************************************/
/* Task0 (CPU0) */
/*************************************************************/
cy_rslt_t rslt0;
cyhal_ipc_t semaphore0;
rslt0 = cyhal_ipc_semaphore_init(&semaphore0, SEMAPHORE_NUM, false);
for (int i = 0; i < IPC_OPERATIONS_LOOPS; ++i)
{
{
printf("Hello from CPU 0\n");
rslt0 = cyhal_ipc_semaphore_give(&semaphore0);
}
}
/*************************************************************/
/* Task1 (CPU1) */
/*************************************************************/
cy_rslt_t rslt1;
cyhal_ipc_t semaphore1;
rslt1 = cyhal_ipc_semaphore_init(&semaphore1, SEMAPHORE_NUM, false);
for (int i = 0; i < IPC_OPERATIONS_LOOPS; ++i)
{
{
printf("Hello from CPU 1\n");
rslt1 = cyhal_ipc_semaphore_give(&semaphore1);
}
}
IPC object.
Definition: cyhal_hw_types.h:843
cy_rslt_t cyhal_ipc_semaphore_take(cyhal_ipc_t *obj, uint32_t timeout_us)
Takes/acquires a semaphore.
cy_rslt_t cyhal_ipc_semaphore_init(cyhal_ipc_t *obj, uint32_t semaphore_num, bool preemptable)
Creates a single semaphore based on a given number.
cy_rslt_t cyhal_ipc_semaphore_give(cyhal_ipc_t *obj)
Gives/releases a semaphore.
#define CYHAL_IPC_NEVER_TIMEOUT
This define can be used as timeout argument for the IPC HAL driver functions, that take timeout as in...
Definition: cyhal_ipc.h:104
uint32_t cy_rslt_t
Provides the result of an operation as a structured bitfield.
Definition: cy_result.h:426
#define CY_RSLT_SUCCESS
cy_rslt_t return value indicating success
Definition: cy_result.h:453

Snippet 2: Message queue example

/* General: error handling is not shown. Use CY_ASSERT(CY_RSLT_SUCCESS == result); to check */
#define CHANNEL_NUM CYHAL_IPC_CHAN_0
#define QUEUE1_NUM 1UL
#define QUEUE1_ITEMS 8UL
#define QUEUE2_NUM 2UL
#define QUEUE2_ITEMS 1UL
#define QUEUE2_MSG_LEN_MAX 25UL
/*************************************************************/
/* Task0 (CPU0) */
/*************************************************************/
#define INVALID_SENSOR_DATA 0UL
#define VALID_SENSOR_DATA 1UL
cy_rslt_t rslt0;
cyhal_ipc_t task0_queue1;
cyhal_ipc_t task0_queue2;
uint32_t task0_sensor = VALID_SENSOR_DATA;
char* task0_message = NULL;
/* Allocating in shared memory char array, that will store message from task1 */
CY_SECTION_SHAREDMEM
static char task1_message[QUEUE2_MSG_LEN_MAX];
char* task1_message_ptr = task1_message;
/* Defining and allocating (shared) memory pools for queue1 and queue2 */
void* queue1_pool, * queue2_pool;
CYHAL_IPC_QUEUE_POOL_ALLOC(queue1_pool, QUEUE1_ITEMS, sizeof(task0_sensor));
CYHAL_IPC_QUEUE_POOL_ALLOC(queue2_pool, QUEUE2_ITEMS, sizeof(task0_message));
/* Defining and allocating (shared) memory for queue handles */
cyhal_ipc_queue_t* queue1_handle, * queue2_handle;
CYHAL_IPC_QUEUE_HANDLE_ALLOC(queue1_handle);
CYHAL_IPC_QUEUE_HANDLE_ALLOC(queue2_handle);
queue1_handle->channel_num = CHANNEL_NUM;
queue1_handle->queue_num = QUEUE1_NUM;
queue1_handle->queue_pool = queue1_pool;
queue1_handle->num_items = QUEUE1_ITEMS;
queue1_handle->item_size = sizeof(task0_sensor);
queue2_handle->channel_num = CHANNEL_NUM;
queue2_handle->queue_num = QUEUE2_NUM;
queue2_handle->queue_pool = queue2_pool;
queue2_handle->num_items = QUEUE2_ITEMS;
queue2_handle->item_size = sizeof(task0_message);
rslt0 = cyhal_ipc_queue_init(&task0_queue1, queue1_handle);
rslt0 = cyhal_ipc_queue_init(&task0_queue2, queue2_handle);
for (int i = 0; i < IPC_OPERATIONS_LOOPS; ++i)
{
if (task0_sensor != INVALID_SENSOR_DATA)
{
rslt0 = cyhal_ipc_queue_put(&task0_queue1, &task0_sensor, CYHAL_IPC_NEVER_TIMEOUT);
}
if (cyhal_ipc_queue_get(&task0_queue2, &task0_message,
{
if (task0_message != NULL)
{
printf("%s\n", task0_message);
task0_message = NULL;
}
}
}
/*************************************************************/
/* Task1 (CPU1) */
/*************************************************************/
cy_rslt_t rslt1;
cyhal_ipc_t task1_queue1;
cyhal_ipc_t task1_queue2;
uint32_t task1_sensor;
rslt1 = cyhal_ipc_queue_get_handle(&task1_queue1, CHANNEL_NUM, QUEUE1_NUM);
rslt1 = cyhal_ipc_queue_get_handle(&task1_queue2, CHANNEL_NUM, QUEUE2_NUM);
for (int i = 0; i < IPC_OPERATIONS_LOOPS; ++i)
{
if (cyhal_ipc_queue_get(&task1_queue1, &task1_sensor,
{
#if defined(__ARMCC_VERSION) || defined (__clang__)
sprintf(task1_message, "Sensor data received: %u\n", task1_sensor);
#else
sprintf(task1_message, "Sensor data received: %lu\n", task1_sensor);
#endif /* __ARMCC_VERSION or other */
rslt1 = cyhal_ipc_queue_put(&task1_queue2, &task1_message_ptr, CYHAL_IPC_NEVER_TIMEOUT);
}
}
uint32_t item_size
Size of each item in the queue (populated by user during initialization)
Definition: cyhal_ipc.h:129
uint32_t queue_num
Queue number (populated by user during initialization)
Definition: cyhal_ipc.h:126
uint32_t num_items
Maximum number of items allowed in the queue (populated by user during initialization)
Definition: cyhal_ipc.h:128
uint32_t channel_num
IPC channel number (e.g. CYHAL_IPC_CHAN_0) (populated by user during initialization)
Definition: cyhal_ipc.h:125
void * queue_pool
Pointer to the queue pool (populated by user during initialization). This is pointer to shared memory...
Definition: cyhal_ipc.h:127
cy_rslt_t cyhal_ipc_queue_put(cyhal_ipc_t *obj, void *msg, uint32_t timeout_us)
Adds one item to the queue.
cy_rslt_t cyhal_ipc_queue_init(cyhal_ipc_t *obj, cyhal_ipc_queue_t *queue_handle)
Creates a new queue for a given IPC channel based on the given queue number and other parameters.
cy_rslt_t cyhal_ipc_queue_get(cyhal_ipc_t *obj, void *msg, uint32_t timeout_us)
Removes one item from the queue.
cy_rslt_t cyhal_ipc_queue_get_handle(cyhal_ipc_t *obj, uint32_t channel_num, uint32_t queue_num)
Gets a handle pointer for a given IPC channel and queue number.
IPC queue structure element.
Definition: cyhal_ipc.h:124

API Reference

 IPC HAL Results
 IPC specific return codes.
 

Data Structures

struct  cyhal_ipc_queue_t
 IPC queue structure element. More...
 

Macros

#define CYHAL_IPC_NEVER_TIMEOUT   (0xFFFFFFFFUL)
 This define can be used as timeout argument for the IPC HAL driver functions, that take timeout as input parameter, in order to make function never time out (wait forever)
 

Typedefs

typedef void(* cyhal_ipc_event_callback_t) (void *callback_arg, cyhal_ipc_event_t event)
 Event handler for IPC interrupts.
 

Enumerations

enum  cyhal_ipc_event_t {
  CYHAL_IPC_NO_INTR = 0 ,
  CYHAL_IPC_QUEUE_WRITE = 1 << 0 ,
  CYHAL_IPC_QUEUE_READ = 1 << 1 ,
  CYHAL_IPC_QUEUE_FULL = 1 << 2 ,
  CYHAL_IPC_QUEUE_EMPTY = 1 << 3 ,
  CYHAL_IPC_QUEUE_RESET = 1 << 4
}
 Flags enum of IPC events. More...
 

Functions

cy_rslt_t cyhal_ipc_semaphore_init (cyhal_ipc_t *obj, uint32_t semaphore_num, bool preemptable)
 Creates a single semaphore based on a given number. More...
 
void cyhal_ipc_semaphore_free (cyhal_ipc_t *obj)
 Frees the IPC semaphore. More...
 
cy_rslt_t cyhal_ipc_semaphore_take (cyhal_ipc_t *obj, uint32_t timeout_us)
 Takes/acquires a semaphore. More...
 
cy_rslt_t cyhal_ipc_semaphore_give (cyhal_ipc_t *obj)
 Gives/releases a semaphore. More...
 
cy_rslt_t cyhal_ipc_queue_init (cyhal_ipc_t *obj, cyhal_ipc_queue_t *queue_handle)
 Creates a new queue for a given IPC channel based on the given queue number and other parameters. More...
 
void cyhal_ipc_queue_free (cyhal_ipc_t *obj)
 Frees the queue. More...
 
cy_rslt_t cyhal_ipc_queue_get_handle (cyhal_ipc_t *obj, uint32_t channel_num, uint32_t queue_num)
 Gets a handle pointer for a given IPC channel and queue number. More...
 
void cyhal_ipc_queue_register_callback (cyhal_ipc_t *obj, cyhal_ipc_event_callback_t callback, void *callback_arg)
 Registers a callback to be executed when certain events occur. More...
 
void cyhal_ipc_queue_enable_event (cyhal_ipc_t *obj, cyhal_ipc_event_t event, uint8_t intr_priority, bool enable)
 Enables which events trigger the callback execution. More...
 
cy_rslt_t cyhal_ipc_queue_put (cyhal_ipc_t *obj, void *msg, uint32_t timeout_us)
 Adds one item to the queue. More...
 
cy_rslt_t cyhal_ipc_queue_get (cyhal_ipc_t *obj, void *msg, uint32_t timeout_us)
 Removes one item from the queue. More...
 
uint32_t cyhal_ipc_queue_count (cyhal_ipc_t *obj)
 Returns how many items are in the queue. More...
 
cy_rslt_t cyhal_ipc_queue_reset (cyhal_ipc_t *obj)
 Clear all the items in the queue. More...
 

Data Structure Documentation

◆ cyhal_ipc_queue_t

struct cyhal_ipc_queue_t
Data Fields
uint32_t channel_num IPC channel number (e.g. CYHAL_IPC_CHAN_0) (populated by user during initialization)
uint32_t queue_num Queue number (populated by user during initialization)
void * queue_pool Pointer to the queue pool (populated by user during initialization). This is pointer to shared memory, in which queue elements will be stored. CYHAL_IPC_QUEUE_POOL_ALLOC macro can be used to allocate memory for pool.
uint32_t num_items Maximum number of items allowed in the queue (populated by user during initialization)
uint32_t item_size Size of each item in the queue (populated by user during initialization)
uint32_t curr_items Current number of items in the queue (not expected to be modified by user)
void * queue_head Pointer to the queue head in circular buffer (not expected to be modified by user)
void * queue_tail Pointer to the queue tail in circular buffer (not expected to be modified by user)
uint32_t triggered_events Events, that were triggered by latest performed operation (not expected to be modified by user)
struct cyhal_ipc_queue_s * next_queue_obj Pointer to the next queue object (not expected to be modified by user)

Enumeration Type Documentation

◆ cyhal_ipc_event_t

Flags enum of IPC events.

Multiple events can be enabled via cyhal_ipc_queue_enable_event and the callback from cyhal_ipc_queue_register_callback will be run to notify.

Enumerator
CYHAL_IPC_NO_INTR 

No interrupt.

CYHAL_IPC_QUEUE_WRITE 

New item was written to the queue.

CYHAL_IPC_QUEUE_READ 

New item was read from the queue.

CYHAL_IPC_QUEUE_FULL 

Queue is full.

CYHAL_IPC_QUEUE_EMPTY 

Queue is empty.

CYHAL_IPC_QUEUE_RESET 

Queue was reset.

Function Documentation

◆ cyhal_ipc_semaphore_init()

cy_rslt_t cyhal_ipc_semaphore_init ( cyhal_ipc_t obj,
uint32_t  semaphore_num,
bool  preemptable 
)

Creates a single semaphore based on a given number.

This function must be called by all tasks/CPUs accessing the semaphore.

Parameters
[out]objPointer to an IPC object. The caller must allocate the memory for this object but the init function will initialize its contents.
[in]semaphore_numThe semaphore number to initialize.
[in]preemptableAllows whether the semaphore can be preempted by another task.
Returns
The status of the init request

◆ cyhal_ipc_semaphore_free()

void cyhal_ipc_semaphore_free ( cyhal_ipc_t obj)

Frees the IPC semaphore.

This function frees the resources associated with the semaphore.

Parameters
[in,out]objThe IPC object.

◆ cyhal_ipc_semaphore_take()

cy_rslt_t cyhal_ipc_semaphore_take ( cyhal_ipc_t obj,
uint32_t  timeout_us 
)

Takes/acquires a semaphore.

If the semaphore is available, it is acquired and this function and returns. This function has a timeout argument (in microseconds). If the semaphore is not available, it blocks until it times out or succeeds in acquiring it.

Parameters
[in]objThe IPC object.
[in]timeout_usTimeout in microseconds. Value 0 can be used if no timeout needed while CYHAL_IPC_NEVER_TIMEOUT can be used to make function block until semaphore is successfully taken.
Returns
The status of the take request

◆ cyhal_ipc_semaphore_give()

cy_rslt_t cyhal_ipc_semaphore_give ( cyhal_ipc_t obj)

Gives/releases a semaphore.

The semaphore is released allowing other tasks waiting on the semaphore to take it.

Parameters
[in]objThe IPC object.
Returns
The status of the give request

◆ cyhal_ipc_queue_init()

cy_rslt_t cyhal_ipc_queue_init ( cyhal_ipc_t obj,
cyhal_ipc_queue_t queue_handle 
)

Creates a new queue for a given IPC channel based on the given queue number and other parameters.

This function requires cyhal_ipc_queue_t (queue handle) pointer to shared memory. Some elements of cyhal_ipc_queue_t structure are expected to be filled by user. One key element of the structure to be filled by user is a pointer to the queue pool allocated in the shared memory. Queue handle is used by other tasks/CPUs to refer to the queue. Note that this function must be called only by one of the tasks/CPUs for the same IPC channel. This CPU can call the function multiple times for the same IPC channel, but with a different queue number.

Note
CYHAL_IPC_QUEUE_HANDLE_ALLOC and CYHAL_IPC_QUEUE_POOL_ALLOC macro can be used in order to allocate memory for (respectively) queue handle (cyhal_ipc_queue_t) and queue pool in shared section. Please refer to Snippet 2: Message queue example for initialization guidance.
Parameters
[out]objPointer to an IPC object. The caller must allocate the memory for this object but the init function will initialize its contents.
[in]queue_handleQueue handle. Fields channel_num, queue_num, queue_pool, num_items and item_size are expected to be filled by user before initialization. Please refer to Snippet 2: Message queue example for initialization guidance.
Returns
The status of the init request

◆ cyhal_ipc_queue_free()

void cyhal_ipc_queue_free ( cyhal_ipc_t obj)

Frees the queue.

This operation only removes the queue handle from the list of available queues. The queue pool and the queue handle allocated in the shared memory needs to be freed (if dynamically allocated) by the application.

Parameters
[in,out]objThe IPC object

◆ cyhal_ipc_queue_get_handle()

cy_rslt_t cyhal_ipc_queue_get_handle ( cyhal_ipc_t obj,
uint32_t  channel_num,
uint32_t  queue_num 
)

Gets a handle pointer for a given IPC channel and queue number.

This function should be called by other tasks/CPUs that have not called the initialization function.

Parameters
[out]objThe IPC object handle.
[in]channel_numIPC channel to use for the queue messaging.
[in]queue_numQueue number.
Returns
The status of the get handle request

◆ cyhal_ipc_queue_register_callback()

void cyhal_ipc_queue_register_callback ( cyhal_ipc_t obj,
cyhal_ipc_event_callback_t  callback,
void *  callback_arg 
)

Registers a callback to be executed when certain events occur.

Parameters
[in]objThe IPC object.
[in]callbackThe callback handler which will be invoked when an event triggers.
[in]callback_argGeneric argument that will be provided to the callback when called.

◆ cyhal_ipc_queue_enable_event()

void cyhal_ipc_queue_enable_event ( cyhal_ipc_t obj,
cyhal_ipc_event_t  event,
uint8_t  intr_priority,
bool  enable 
)

Enables which events trigger the callback execution.

It can trigger when a new item is written to the queue, read from the queue, when the queue becomes full, when the queue becomes empty or when there is a reset. Note that these events might execute callbacks associated to all queues that belong to an IPC channel. When defining the ISR priority, the last call to this function overwrites the priority for all queue callbacks registered to the same IPC channel.

Parameters
[in]objThe IPC object
[in]eventThe IPC event type
[in]intr_priorityThe priority for NVIC interrupt events
[in]enableTrue to turn on specified events, False to turn off

◆ cyhal_ipc_queue_put()

cy_rslt_t cyhal_ipc_queue_put ( cyhal_ipc_t obj,
void *  msg,
uint32_t  timeout_us 
)

Adds one item to the queue.

This function can be called by any task/CPU. This function has a timeout argument (in microseconds). If the queue is full, it stays there until it times out or the queue is no longer full. This function can be blocking or non-blocking (timeout set to ZERO).

Parameters
[in]objThe IPC object
[in]msgLocation of message queue item
[in]timeout_usTimeout in microseconds. Value 0 can be used if no timeout needed while CYHAL_IPC_NEVER_TIMEOUT can be used to make function block until element is successfully put into the queue.
Returns
The status of the put request

◆ cyhal_ipc_queue_get()

cy_rslt_t cyhal_ipc_queue_get ( cyhal_ipc_t obj,
void *  msg,
uint32_t  timeout_us 
)

Removes one item from the queue.

This function can be called by any task/CPU. This function has a timeout argument (in microseconds). If the queue is empty, it stays there until it times out or the queue receives a new item. This function can be blocking or non-blocking (timeout set to ZERO).

Parameters
[in]objThe IPC object
[out]msgLocation of message queue item
[in]timeout_usTimeout in microseconds. Value 0 can be used if no timeout needed while CYHAL_IPC_NEVER_TIMEOUT can be used to make function block until element is successfully taken from the queue.
Returns
The status of the get request

◆ cyhal_ipc_queue_count()

uint32_t cyhal_ipc_queue_count ( cyhal_ipc_t obj)

Returns how many items are in the queue.

This function can be called by any task/CPU.

Parameters
[in]objThe IPC object
Returns
Number of items in the queue

◆ cyhal_ipc_queue_reset()

cy_rslt_t cyhal_ipc_queue_reset ( cyhal_ipc_t obj)

Clear all the items in the queue.

This function can be called by the any task/CPU.

Parameters
[in]objThe IPC object
Returns
The status of the reset request