This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hello experts,
I'm trying to use rpmessage for cross core communication.
I'll need to use an interrupt with callback for my program.
Is there any example/guideline on how to setup the constructor?
Here's what I tried:
I use this function to set the callback
RPMessage_CreateParams createParams; RPMessage_CreateParams_init(&createParams); createParams.localEndPt = gRemoteServiceEndPt; /* pick any unique value on that core between 0..RPMESSAGE_MAX_LOCAL_ENDPT-1 * the value need not be unique across cores */ createParams.recvCallback = &ISR_ipcRecvCallback; //Register receive interrupt callback function //Callback args gIPCArgs.obj = &gRecvMsgObject; gIPCArgs.arg = NULL; gIPCArgs.data = (void *) gBufIn; gIPCArgs.dataLen = sizeof(gBufIn); gIPCArgs.remoteCoreId = CSL_CORE_ID_R5FSS0_0; gIPCArgs.remoteEndPt = MAIN_CORE_ACK_REPLY_END_PT; createParams.recvCallbackArgs = &gIPCArgs; return RPMessage_construct(&gAckReplyMsgObject, &createParams);
In the callback function I echo the received message
void ISR_ipcRecvCallback(RPMessage_Object *obj, void *arg, void *data, uint16_t dataLen, uint16_t remoteCoreId, uint16_t remoteCoreEndPt) { uint32_t status; //echo the same message string as reply //send ack to sender CPU at the sender end point status = RPMessage_send( data, dataLen, remoteCoreId, remoteCoreEndPt, RPMessage_getLocalEndPt(obj), SystemP_WAIT_FOREVER); DebugP_assert(status==SystemP_SUCCESS); }
I modified the example "IPC RP Message Echo" provided by the SDK, but it seems that the callback function never gets called
Regards,
Andrea F,
Hi Andrea,
The way you registered call back seems to be fine, however it seems like the arguments you are passing is not being used anywhere in the callback. Any specific reason you're passing these?
Also, I'll try this at my end and share you an example.
Thanks,
G Kowshik
Hi Kowshik,
this is my first time registering a callback function without using sysconfig.
The reason I picked this arguments is because I copied the function from the header "ipc_rpmsg.h" where the callback function is defined as
/** * \brief Callback that is invoked when a message is received from any CPU at the specified local end point * * The callback can be optionally registered during \ref RPMessage_construct * * \note All message contents MUST be consumed in the callback. * When callback returns the message buffer is released back to the sender. * If the message contents are needed for deferred processing then take a copy of the message contents * * \param obj [in] RPMessage end point object created with \ref RPMessage_construct * \param arg [in] Arguments specified by user during \ref RPMessage_construct * \param data [in] Pointer to message * \param dataLen [in] Length of message * \param remoteCoreId [in] Core ID of sender * \param remoteEndPt [in] End point of sender */ typedef void (*RPMessage_RecvCallback)(RPMessage_Object *obj, void *arg, void *data, uint16_t dataLen, uint16_t remoteCoreId, uint16_t remoteEndPt);
In my final project I'll need to copy the received buffer in a local buffer in order to process it later in the main loop, so I don't need all this arguments.
Here's the code I'm using if you want to test it out
/* * Copyright (C) 2021 Texas Instruments Incorporated * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <stdio.h> #include <string.h> #include <inttypes.h> #include <kernel/dpl/ClockP.h> #include <kernel/dpl/DebugP.h> #include <drivers/ipc_notify.h> #include <drivers/ipc_rpmsg.h> #include "ti_drivers_open_close.h" #include "ti_board_open_close.h" /* This example shows message exchange between multiple cores. * * One of the core is designated as the 'main' core * and other cores are designated as `remote` cores. * * The main core initiates IPC with remote core's by sending it a message. * The remote cores echo the same message to the main core. * * The main core repeats this for gMsgEchoCount iterations. * * In each iteration of message exchange, the message value is incremented. * * When iteration count reaches gMsgEchoCount, the example is completed. * */ /* number of iterations of message exchange to do */ uint32_t gMsgEchoCount = 100000u; /* main core that starts the message exchange */ uint32_t gMainCoreId = CSL_CORE_ID_R5FSS0_0; /* remote cores that echo messages from main core, make sure to NOT list main core in this list */ uint32_t gRemoteCoreId[] = { CSL_CORE_ID_R5FSS0_1, CSL_CORE_ID_MAX /* this value indicates the end of the array */ }; uint8_t gBufIn[100]; /* * Remote core service end point * * pick any unique value on that core between 0..RPMESSAGE_MAX_LOCAL_ENDPT-1 * the value need not be unique across cores */ uint16_t gRemoteServiceEndPt = 13u; /* maximum size that message can have in this example */ #define MAX_MSG_SIZE (24u) /* Main core ack reply end point * * pick any unique value on that core between 0..RPMESSAGE_MAX_LOCAL_ENDPT-1 * the value need not be unique across cores */ #define MAIN_CORE_ACK_REPLY_END_PT (12U) typedef struct { RPMessage_Object *obj; //RPMessage end point object created with \ref RPMessage_construct void *arg; //Arguments specified by user during \ref RPMessage_construct void *data; //Pointer to message uint16_t dataLen; //Length of message uint16_t remoteCoreId; //Core ID of sender uint16_t remoteEndPt; //End point of sender } UTIL_ipc_CallbackArgs; UTIL_ipc_CallbackArgs gIPCArgs; /* RPMessage_Object MUST be global or static */ RPMessage_Object gAckReplyMsgObject; int32_t ipc_rpmsg_start_listen(); void ISR_ipcRecvCallback(RPMessage_Object *obj, void *arg, void *data, uint16_t dataLen, uint16_t remoteCoreId, uint16_t remoteEndPt); void ipc_rpmsg_echo_main_core_start(void) { RPMessage_CreateParams createParams; uint32_t msg, i, numRemoteCores; uint64_t curTime; char msgBuf[MAX_MSG_SIZE]; int32_t status; uint16_t remoteCoreId, remoteCoreEndPt, msgSize; RPMessage_CreateParams_init(&createParams); createParams.localEndPt = MAIN_CORE_ACK_REPLY_END_PT; status = RPMessage_construct(&gAckReplyMsgObject, &createParams); DebugP_assert(status==SystemP_SUCCESS); numRemoteCores = 0; for(i=0; gRemoteCoreId[i]!=CSL_CORE_ID_MAX; i++) { numRemoteCores++; } /* wait for all cores to be ready */ IpcNotify_syncAll(SystemP_WAIT_FOREVER); ClockP_usleep(500*1000); /* wait for log messages from remote cores to be flushed, otherwise this delay is not needed */ DebugP_log("[IPC RPMSG ECHO] Message exchange started by main core !!!\r\n"); curTime = ClockP_getTimeUsec(); for(msg=0; msg<gMsgEchoCount; msg++) { snprintf(msgBuf, MAX_MSG_SIZE-1, "%d", msg); msgBuf[MAX_MSG_SIZE-1] = 0; msgSize = strlen(msgBuf) + 1; /* count the terminating char as well */ /* send the same messages to all cores */ for(i=0; gRemoteCoreId[i]!=CSL_CORE_ID_MAX; i++ ) { status = RPMessage_send( msgBuf, msgSize, gRemoteCoreId[i], gRemoteServiceEndPt, RPMessage_getLocalEndPt(&gAckReplyMsgObject), SystemP_WAIT_FOREVER); DebugP_assert(status==SystemP_SUCCESS); } /* wait for response from all cores */ for(i=0; gRemoteCoreId[i]!=CSL_CORE_ID_MAX; i++ ) { /* set 'msgSize' to size of recv buffer, * after return `msgSize` contains actual size of valid data in recv buffer */ msgSize = sizeof(msgBuf); status = RPMessage_recv(&gAckReplyMsgObject, msgBuf, &msgSize, &remoteCoreId, &remoteCoreEndPt, SystemP_WAIT_FOREVER); DebugP_assert(status==SystemP_SUCCESS); } } curTime = ClockP_getTimeUsec() - curTime; DebugP_log("[IPC RPMSG ECHO] All echoed messages received by main core from %d remote cores !!!\r\n", numRemoteCores); DebugP_log("[IPC RPMSG ECHO] Messages sent to each core = %d \r\n", gMsgEchoCount); DebugP_log("[IPC RPMSG ECHO] Number of remote cores = %d \r\n", numRemoteCores); DebugP_log("[IPC RPMSG ECHO] Total execution time = %" PRId64 " usecs\r\n", curTime); DebugP_log("[IPC RPMSG ECHO] One way message latency = %" PRId32 " nsec\r\n", (uint32_t)(curTime*1000u/(gMsgEchoCount*numRemoteCores*2))); RPMessage_destruct(&gAckReplyMsgObject); DebugP_log("All tests have passed!!\r\n"); } /* RPMessage_Object MUST be global or static */ static RPMessage_Object gRecvMsgObject; void ipc_rpmsg_echo_remote_core_start(void) { int32_t status; status = ipc_rpmsg_start_listen(); DebugP_assert(status==SystemP_SUCCESS); DebugP_log("[IPC RPMSG ECHO] Waiting for all cores !!!\r\n"); /* wait for all cores to be ready */ IpcNotify_syncAll(SystemP_WAIT_FOREVER); /* wait for messages forever in a loop */ while(1) { } /* This loop will never exit */ } void ipc_rpmsg_echo_main(void *args) { Drivers_open(); Board_driversOpen(); if(IpcNotify_getSelfCoreId()==gMainCoreId) { ipc_rpmsg_echo_main_core_start(); } else { ipc_rpmsg_echo_remote_core_start(); } Board_driversClose(); /* We dont close drivers to let the UART driver remain open and flush any pending messages to console */ /* Drivers_close(); */ } int32_t ipc_rpmsg_start_listen() { RPMessage_CreateParams createParams; RPMessage_CreateParams_init(&createParams); createParams.localEndPt = gRemoteServiceEndPt; /* pick any unique value on that core between 0..RPMESSAGE_MAX_LOCAL_ENDPT-1 * the value need not be unique across cores */ createParams.recvCallback = &ISR_ipcRecvCallback; //Register receive interrupt callback function //Callback args gIPCArgs.obj = &gRecvMsgObject; gIPCArgs.arg = NULL; gIPCArgs.data = (void *) gBufIn; gIPCArgs.dataLen = sizeof(gBufIn); gIPCArgs.remoteCoreId = CSL_CORE_ID_R5FSS0_0; gIPCArgs.remoteEndPt = MAIN_CORE_ACK_REPLY_END_PT; createParams.recvCallbackArgs = &gIPCArgs; return RPMessage_construct(&gAckReplyMsgObject, &createParams); } /* * IPC receive interrupt Callback function */ void ISR_ipcRecvCallback(RPMessage_Object *obj, void *arg, void *data, uint16_t dataLen, uint16_t remoteCoreId, uint16_t remoteCoreEndPt) { uint32_t status; //echo the same message string as reply //send ack to sender CPU at the sender end point status = RPMessage_send( data, dataLen, remoteCoreId, remoteCoreEndPt, RPMessage_getLocalEndPt(obj), SystemP_WAIT_FOREVER); DebugP_assert(status==SystemP_SUCCESS); }
Best Regards,
Andrea
Hi Andrea,
I have imported the system project from the MCU+SDK and added the following macro in the createParams.recvCallback, and I am able to hit the callback whenever I receive a message from the other cores.
Thanks,
G Kowshik
Thank you Kowshik,
now the callback works fine
All I had to do was change the callback function return type from void to RPMessage_RecvCallback:
What I had
void ISR_ipcRecvCallback(RPMessage_Object *obj, void *arg, void *data, uint16_t dataLen, uint16_t remoteCoreId, uint16_t remoteEndPt);
The change I made to make it work
RPMessage_RecvCallback ISR_ipcRecvCallback(RPMessage_Object *obj, void *arg, void *data, uint16_t dataLen, uint16_t remoteCoreId, uint16_t remoteEndPt);
BR,
Andrea