AM261x MCU+ SDK: IPC Notify

| AM261x MCU+ SDK 26.00.00 |

IPC Notify

This module define's APIs for low latency IPC between different core's on a CPU. These low latency IPC APIs are constrained in features but offer extermely fast transfer of message values between two cores.

Underlying implementation will use HW mechanisms to interrupt the receiving cores, it will also use HW FIFOs (when available) or shared memory based SW FIFOs in fast internal RAM's to transport the message values.

# Features Supported

- Low latency message send and receive between any to any CPUs running no-RTOS or RTOS
- Low latency is achieved by
  - Accessing the HW in very few steps (due to this most error checking is left to the user)
  - Combining the message and client ID into a single 32b value that is send via HW/SW FIFO's (due to this there are constraints on max client ID and max message value)
  - Handling the message received within ISR itself and calling user callback within few steps of receiving the interrupt.
- Client ID field allows to send messages to different SW clients on the receving side
  - Typically each SW client will be indepedant SW entity, so client ID allows to do basic demultiplexing of messages and thus keep the SW entities indepedant of each other even when IPC is involved.
- Ability to register different user handlers for different client ID's
- Callback based mechnism to recieve messages
- Ability to block on message send for ever OR return with error, if the underlying IPC HW/SW FIFO is full.

# SysConfig Features

Note
  It is strongly recommend to use SysConfig where it is available instead of using direct SW API calls. This will help simplify the SW application and also catch common mistakes early in the development cycle.
  IPC Examples should be build as System Projects. Single core build will fail since IPC code generation dependends on all core contexts in the application.

- Enable/Disable IPC Notify between different CPUs
- Enable/Disable SafeIPC. If Enabled, the Shared memory is organized in a way that allows Firewalling. Only Sender and Receiver core will have access to the Queue. Firewall configuration is not part of IPC SysCfg module. It has to be done separately. The SysCfg generated code has comments on the Start and End addresses and the involved cores. This can be used during the firewall configuration. Data Integrity Check has to be handled in application. CRC can be sent as a part of Payload and decoded in the receiver end.
- Enable/Disable CRC. If Enabled, Data Integrity Check is enabled for IPC Notify Data. The calculated CRC is sent as a part of Payload (ClientID + CRC + Data) and decoded in the receiver end. Application has to define a hook function which will be used by driver for CRC calculation. 8 Bit CRC is used by IPC Notify.

# Important Usage Guidelines

- To balance low latency performance vs flexiblility to end user, below contraints are introduced in the API
  - The maximum number of clients supported is constrained to IPC_NOTIFY_CLIENT_ID_MAX.
  - The maximum message value that is exchanged is contrained to IPC_NOTIFY_MSG_VALUE_MAX
- IPC_NOTIFY_MSG_VALUE_MAX is < 32b, and hence one cannot pass pointers as messages.
  - However, passing pointers as messages is not a recommended SW design and instead one should pass offset from some known base address as values instead.
  - Offsets can easily fit within IPC_NOTIFY_MSG_VALUE_MAX limit.
- Internally the implementation will combine client ID and message value as one 32b integer.

# Example Usage

Include the below files to access the APIs

#include <stdio.h>
#include <drivers/ipc_notify.h>
#include <kernel/dpl/DebugP.h>

Initialize IPC Notify

int32_t status;
IpcNotify_Params notifyParams;
/* initialize parameters to default */
IpcNotify_Params_init(&notifyParams);
/* specify the core on which this API is called */
notifyParams.selfCoreId = CSL_CORE_ID_R5FSS0_0;
/* list the cores that will do IPC Notify with this core
* Make sure to NOT list `self` core in the list below
*/
notifyParams.numCores = 1;
notifyParams.coreIdList[0] = CSL_CORE_ID_R5FSS0_1;
status = IpcNotify_init(&notifyParams);
DebugP_assert(status==SystemP_SUCCESS);

Register handler to receive messages

int32_t status;
/* client ID to register against, make sure messages are sent to this client ID */
uint16_t clientId = 4;
/* create a local queue to hold the emssage */
MyQueue_create(&gMyLocalQ);
/* register a handler to receive messages */
status = IpcNotify_registerClient(clientId, MyMsg_handler, &gMyLocalQ);
DebugP_assert(status==SystemP_SUCCESS);

Send message

/* send `msgValue` to `clientId` of core CSL_CORE_ID_R5FSS0_1 */
int32_t status;
/* client ID for which this message is intended,
* make sure a handler is registered for this client ID
*/
uint16_t clientId = 4;
/* message value to send, amke sure the
* registered handler handles this message
*/
uint32_t msgValue = 0x08765432;
/* no error checks done inside IpcNotify_sendMsg(), so doing here just to show the constraints */
DebugP_assert(msgValue < IPC_NOTIFY_MSG_VALUE_MAX);
DebugP_assert(clientId < IPC_NOTIFY_CLIENT_ID_MAX);
/* wait until msg is put into internal HW/SW FIFO */
status = IpcNotify_sendMsg(CSL_CORE_ID_R5FSS0_0, clientId, msgValue, 1);
DebugP_assert(status==SystemP_SUCCESS);

Receive message and handle it in a task

/* NOTE: local queue implementation not shown, this is a standard FIFO like SW queue,
* which is thread and interrupt safe and can block until there is a element to dequeue
*/
/* local Q to hold received messages */
MyQueue_Obj gMyLocalQ;
void MyMsg_handler(uint32_t remoteCoreId, uint16_t localClientId, uint32_t msgValue, int32_t crcStatus, void *args)
{
MyQueue_Obj *myLocalQ = (MyQueue_Obj*)args;
/* message received from remote core `remoteCoreId`, for client ID `localClientId` on this core */
/* instead of handling the messages in callback which is called within ISR, queue this into a larger SW queue.
* Handle to the SW queue is passed via args in this example.
* SW queue could be one per remote core, one per client ID or a common Q for all remote cores and so on.
* Passing queue handle as argument allows the handler to remain
* common across multiple remote cores and client ID's
*/
MyQueue_put(myLocalQ, msgValue);
/* NOTE: THis is a sample handler, actually application can have different design based on its
* specific requirements
*/
}
/* Message handler task */
void MyTask_main(void *args)
{
while(1)
{
uint32_t msgValue;
/* block until there is a element to dequeue from this Q */
MyQueue_wait(&gMyLocalQ, &msgValue);
if(msgValue == 0x08765432)
{
/* handle message value.
* typically message value will be a command to execute
* OR
* it will point (offset or index within a known shared memory base address or array)
* to command and parameters to execute
*/
}
}
}

# API

APIs for IPC Notify

args
void * args
Definition: hsmclient_msg.h:4
IpcNotify_Params::selfCoreId
uint32_t selfCoreId
Definition: ipc_notify.h:164
IPC_NOTIFY_CLIENT_ID_MAX
#define IPC_NOTIFY_CLIENT_ID_MAX
Maximum number of clients possible for receiving messages.
Definition: ipc_notify.h:56
IpcNotify_registerClient
int32_t IpcNotify_registerClient(uint16_t localClientId, IpcNotify_FxnCallback msgCallback, void *args)
Register a callback to handle messages received from a specific remote core and for a specific local ...
CSL_CORE_ID_R5FSS0_0
#define CSL_CORE_ID_R5FSS0_0
Definition: cslr_soc_defines.h:144
IpcNotify_sendMsg
int32_t IpcNotify_sendMsg(uint32_t remoteCoreId, uint16_t remoteClientId, uint32_t msgValue, uint32_t waitForFifoNotFull)
Send message to a specific remote core and specific client ID on that remote core.
IpcNotify_Params
Parameters used by IpcNotify_init.
Definition: ipc_notify.h:154
IpcNotify_Params::coreIdList
uint32_t coreIdList[CSL_CORE_ID_MAX]
Definition: ipc_notify.h:159
IpcNotify_Params_init
void IpcNotify_Params_init(IpcNotify_Params *params)
Set default value to IpcNotify_Params.
ipc_notify.h
IPC_NOTIFY_MSG_VALUE_MAX
#define IPC_NOTIFY_MSG_VALUE_MAX
Maximum value of message that can be sent and received.
Definition: ipc_notify.h:76
SystemP_SUCCESS
#define SystemP_SUCCESS
Return status when the API execution was successful.
Definition: SystemP.h:56
IpcNotify_Params::numCores
uint32_t numCores
Definition: ipc_notify.h:156
DebugP.h
CSL_CORE_ID_R5FSS0_1
#define CSL_CORE_ID_R5FSS0_1
Definition: cslr_soc_defines.h:145
DebugP_assert
#define DebugP_assert(expression)
Function to call for assert check.
Definition: DebugP.h:187
IpcNotify_init
int32_t IpcNotify_init(const IpcNotify_Params *params)
Initialize IPC Notify module.