Hello experts,
I need help / advice on an IPC communication between R5F cores.
I want to demonstrate IPC communication between two R5F cores (mcu1_0 and mcu2_1)
Tool/software:
I'm using SBL boot via UART (
CORE1_0:
Core 1_0 runs modified sciserver_testapp_freertos example. I picked this because I need sciserver with freertos running on mcu1_0 apparently.
I've modified taskFxn to initialize IPC and send a string to mcu2_1 after sciserver is setup. Code attached:
uint32_t virt2phy_func(const void *virtAddr) { return ((uint32_t)virtAddr); } void *phy2virt_func(uint32_t phyAddr) { uint32_t temp = phyAddr; #if defined (BUILD_M4F_0) temp = phyAddr + 0x40000000; #endif return ((void *)temp); } void newmsg_callback_func(uint32_t srcEndPt, uint32_t procId) { return; } void uart_print(const char *str) { UART_printf("%s", str); return; } uint8_t vqBuf[VQ_BUF_SIZE] __attribute__((section(".my_ipc_data_buffer"), aligned(8))); uint8_t selfBuf[RPMSG_DATA_SIZE] __attribute__((section(".my_ipc_data_buffer"), aligned(8))); static void taskFxn(void* a0, void* a1) { int32_t ret = CSL_PASS; Sciclient_ConfigPrms_t clientPrms; Sciserver_TirtosCfgPrms_t appPrms; char *versionStr = NULL; char *rmpmhalVersionStr = NULL; /* Sciclient needs to be initialized before Sciserver. Sciserver depends on * Sciclient API to execute message forwarding */ ret = Sciclient_configPrmsInit(&clientPrms); if (ret == CSL_PASS) { ret = Sciclient_boardCfgParseHeader( (uint8_t *) SCISERVER_COMMON_X509_HEADER_ADDR, &clientPrms.inPmPrms, &clientPrms.inRmPrms); } if (ret == CSL_PASS) { ret = Sciclient_init(&clientPrms); } /* Enable UART console print*/ if (ret == CSL_PASS) { SciApp_consoleInit(); } if (ret == CSL_PASS) { ret = Sciserver_tirtosInitPrms_Init(&appPrms); appPrms.taskPriority[SCISERVER_TASK_USER_LO] = SCISERVER_SETUP_TASK_PRI_LOW; appPrms.taskPriority[SCISERVER_TASK_USER_HI] = SCISERVER_SETUP_TASK_PRI_HIGH; } if (ret == CSL_PASS) { ret = Sciserver_tirtosInit(&appPrms); } /* Set PMIC Shutdown Function Pointer */ if (ret == CSL_PASS) { ret = Sciclient_setPmicShutdownCb(SciApp_pmicShutdown); } if (ret == CSL_PASS) { versionStr = Sciserver_getVersionStr(); rmpmhalVersionStr = Sciserver_getRmPmHalVersionStr(); SciApp_printf("Sciserver Testapp Built On: %s %s\n", __DATE__, __TIME__); SciApp_printf("Sciserver Version: %s\n", versionStr); SciApp_printf("RM_PM_HAL Version: %s\n", rmpmhalVersionStr); } #if defined LDRA_DYN_COVERAGE_EXIT UART_printf("\n LDRA Entry... \n"); /* Add 3 minutes delay before printing execution history to make sure extended ut running on mcu2_0 will complete it's execution, this will introduce additional code coverage by sending requests to sciserver. */ Osal_delay(180*1000); upload_execution_history(); UART_printf("\n LDRA Exit... \n"); #endif if (ret == CSL_PASS) { SciApp_printf("Starting Sciserver..... PASSED\n"); } else { SciApp_printf("Starting Sciserver..... FAILED\n"); } UART_printf("IPC_echo_test mcu1_1\n"); uint32_t numProc = 1; uint32_t pRemoteProcArray[] = {IPC_MCU2_1}; uint32_t selfProcId = IPC_MCU1_0; uint32_t selfPt = 10; uint32_t remotePt = 10; uint32_t remoteProcId = IPC_MCU2_1; Ipc_InitPrms initPrms; Ipc_VirtIoParams vqParam; /* Step1 : Initialize the multiproc */ if (IPC_SOK == Ipc_mpSetConfig(selfProcId, numProc, pRemoteProcArray)) { UART_printf("IPC_echo_test (core : %s) (ID: %d).....\r\n", Ipc_mpGetSelfName(), Ipc_mpGetSelfId()); /* Initialize params with defaults */ IpcInitPrms_init(0U, &initPrms); initPrms.newMsgFxn = &newmsg_callback_func; initPrms.virtToPhyFxn = &virt2phy_func; initPrms.phyToVirtFxn = &phy2virt_func; initPrms.printFxn = &uart_print; if (IPC_SOK != Ipc_init(&initPrms)) { return; } } else { UART_printf("Ipc_mpSetConfig failed\n"); } App_printf("Required Local memory for Virtio_Object = %d\r\n", numProc * Ipc_getVqObjMemoryRequiredPerCore()); /* Step2 : Initialize Virtio */ vqParam.vqObjBaseAddr = (void *)vqBuf; vqParam.vqBufSize = numProc * Ipc_getVqObjMemoryRequiredPerCore(); vqParam.vringBaseAddr = (void *)VRING_BASE_ADDRESS; vqParam.vringBufSize = IPC_VRING_BUFFER_SIZE; vqParam.timeoutCnt = 100; /* Wait for counts */ // Ipc_initVirtIO(&vqParam); if (IPC_SOK != Ipc_initVirtIO(&vqParam)) { // E_NOT_OK; UART_printf("Ipc_initVirtIO: E_NOT_OK\n"); } App_printf("Required Local memory for RPMessage Object = %d\n", RPMessage_getObjMemRequired()); UART_printf("selfBuf @ %p\n", selfBuf); UART_printf("vqBuf @ %p\n", vqBuf); UART_printf("VRING_BASE_ADDRESS @ %p\n", (void*)VRING_BASE_ADDRESS); /* Step 3: Initialize RPMessage */ RPMessage_Params selfRPMsgParam; RPMessageParams_init(&selfRPMsgParam); selfRPMsgParam.buf = selfBuf; selfRPMsgParam.bufSize = RPMSG_DATA_SIZE; selfRPMsgParam.stackBuffer = NULL; selfRPMsgParam.stackSize = 0U; selfRPMsgParam.requestedEndpt = remotePt; UART_printf("RPMessage_init: RPMSG_DATA_SIZE %d\n", RPMSG_DATA_SIZE); RPMessage_init(&selfRPMsgParam); RPMessage_Handle selfRPMsgHandle; selfRPMsgHandle = RPMessage_create(&selfRPMsgParam, &selfPt); if (selfRPMsgHandle == NULL) { UART_printf("RPMessage_create failed!\n"); return; } UART_printf("Created RPMessage endpoint %d on core %s\n", selfPt, Ipc_mpGetSelfName()); char sendMsg[512] = "hello from mcu1_0"; uint32_t msgLen = strlen(sendMsg); UART_printf("A----------------------\n"); int32_t status = RPMessage_send(selfRPMsgHandle, remoteProcId, remotePt, selfPt, (void *)sendMsg, msgLen); if (status != IPC_SOK) { UART_printf("Failed: RPMessage %s ----> %s\nMsg: %s\n", Ipc_mpGetSelfName(), Ipc_mpGetName(remoteProcId), sendMsg); UART_printf("remoteProcId %d\n", remoteProcId); } else { UART_printf("Success: RPMessage %s ----> %s\nMsg: %s\n", Ipc_mpGetSelfName(), Ipc_mpGetName(remoteProcId), sendMsg); } }
I've also modified linker script so it includes my_ipc_data_buffer
(path to linker script ti-processor-sdk-rtos-j784s4-evm-11_00_00_06/pdk_j784s4_11_00_00_21/packages/ti/drv/sciclient/examples/sciserver_testapp/linker_r5_freertos_release.lds)
#define DDR0_ALLOCATED_START 0xA0000000 #define MCU1_0_DDR_SPACE_BASE (DDR0_ALLOCATED_START + 0x00400000) MEMORY { VECTORS (X) : ORIGIN = 0x00000000 , LENGTH = 0x00000040 R5F_TCMA0(RWIX) : ORIGIN = 0x00000040 , LENGTH = 0x00007F00 R5F_TCMB0(RWIX) : ORIGIN = 0x41010100 , LENGTH = 0x00007F00 SBL_USED_OCMC_RAM : ORIGIN = 0x41C01000 , LENGTH = 0x2F000 OCMC_RAM_BOARD_CFG (RWIX) : ORIGIN = 0x41c80000 , LENGTH = 0x2000 /* Sciserver App Space */ OCMC_RAM_SCISERVER (RWIX) : ORIGIN = 0x41C82000 , LENGTH = 0x00060000 OCMC_RAM_X509_HEADER1 (RWIX) : ORIGIN = 0x41cffb00 , LENGTH = 0x500 /* covers header for J7200/J721E */ OCMC_RAM_X509_HEADER2 (RWIX) : ORIGIN = 0x41cfdb00 , LENGTH = 0x500 /* covers header for J721S2 */ MCU1_0_DDR_SPACE (RWIX) : origin=MCU1_0_DDR_SPACE_BASE length=0x00C00000 /* 12MB */ } SECTIONS { .freertosrstvectors : {} palign(8) > VECTORS .bootCode : {} palign(8) > R5F_TCMA0 .startupCode : {} palign(8) > R5F_TCMA0 .text.hwi : {} palign(8) > R5F_TCMA0 .startupData : {} palign(8) > R5F_TCMA0, type = NOINIT .text : {} palign(8) > OCMC_RAM_SCISERVER .my_ipc_data_buffer (NOINIT) : {} palign(128) > MCU1_0_DDR_SPACE ...
I'm using MCU1_0_DDR_SPACE
All of this is compiled with
make -s -j BOARD=j784s4_evm SOC=j784s4 BUILD_TYPE=release sciserver_testapp_freertos
CORE2_1:
I've this example (taken from ipc_testsetup.c) - this is a baremetal app
/*
* receiver goes on mcu2_1
*/
#include <stdint.h>
#include <ti/board/board.h>
#include <ti/csl/tistdtypes.h>
#include <ti/drv/ipc/examples/common/src/ipc_setup.h>
#include <ti/drv/ipc/ipc.h>
#include <ti/drv/ipc/soc/V4/ipc_soc.h>
#include <ti/drv/sciclient/sciclient.h>
#include <ti/drv/uart/UART_stdio.h>
uint32_t virt2phy_func(const void *virtAddr)
{
return ((uint32_t)virtAddr);
}
void *phy2virt_func(uint32_t phyAddr) {
uint32_t temp = phyAddr;
#if defined (BUILD_M4F_0)
temp = phyAddr + 0x40000000;
#endif
return ((void *)temp);
}
// void newmsg_callback_func(uint32_t srcEndPt, uint32_t procId) { return; }
void newmsg_callback_func(uint32_t srcEndPt, uint32_t procId) {
UART_printf("MCU2_1: newmsg_callback_func called from procId=%d, srcEndPt=%d\n", procId, srcEndPt);
}
void uart_print(const char *str)
{
UART_printf("%s", str);
return;
}
uint8_t vqBuf[VQ_BUF_SIZE] __attribute__((section(".my_ipc_data_buffer"), aligned(8)));
uint8_t selfBuf[RPMSG_DATA_SIZE] __attribute__((section(".my_ipc_data_buffer"), aligned(8)));
int main(void) {
Sciclient_ConfigPrms_t config;
Sciclient_configPrmsInit(&config);
Sciclient_init(&config);
Board_initCfg boardCfg;
boardCfg = BOARD_INIT_PINMUX_CONFIG | BOARD_INIT_UART_STDIO;
Board_init(boardCfg);
// UART_printf("IPC_echo_test\n");
uint32_t numProc = 1;
uint32_t pRemoteProcArray[] = {IPC_MCU1_0};
uint32_t selfProcId = IPC_MCU2_1;
uint32_t selfPt = 10;
uint32_t remotePt = 10;
uint32_t remoteProcId = IPC_MCU1_0;
Ipc_InitPrms initPrms;
Ipc_VirtIoParams vqParam;
/* Step1 : Initialize the multiproc */
if (IPC_SOK == Ipc_mpSetConfig(selfProcId, numProc, pRemoteProcArray)) {
UART_printf("IPC_echo_test (core : %s) .....\r\n", Ipc_mpGetSelfName());
/* Initialize params with defaults */
IpcInitPrms_init(0U, &initPrms);
initPrms.newMsgFxn = &newmsg_callback_func;
initPrms.virtToPhyFxn = &virt2phy_func;
initPrms.phyToVirtFxn = &phy2virt_func;
initPrms.printFxn = &uart_print;
if (IPC_SOK != Ipc_init(&initPrms)) {
return -1;
}
} else {
UART_printf("Ipc_mpSetConfig failed\n");
}
/* Step2 : Initialize Virtio */
vqParam.vqObjBaseAddr = (void *)vqBuf;
vqParam.vqBufSize = numProc * Ipc_getVqObjMemoryRequiredPerCore();
vqParam.vringBaseAddr = (void *)VRING_BASE_ADDRESS;
vqParam.vringBufSize = IPC_VRING_BUFFER_SIZE;
vqParam.timeoutCnt = 100; /* Wait for counts */
if (IPC_SOK != Ipc_initVirtIO(&vqParam))
{
// E_NOT_OK;
UART_printf("Ipc_initVirtIO: E_NOT_OK\n");
}
UART_printf("selfBuf @ %p\n", selfBuf);
UART_printf("vqBuf @ %p\n", vqBuf);
UART_printf("VRING_BASE_ADDRESS @ %p\n", (void*)VRING_BASE_ADDRESS);
/* Step 3: Initialize RPMessage */
RPMessage_Params selfRPMsgParam;
RPMessageParams_init(&selfRPMsgParam);
selfRPMsgParam.buf = selfBuf;
selfRPMsgParam.bufSize = RPMSG_DATA_SIZE;
selfRPMsgParam.stackBuffer = NULL;
selfRPMsgParam.stackSize = 0U;
selfRPMsgParam.requestedEndpt = remotePt;
RPMessage_init(&selfRPMsgParam);
RPMessage_Handle selfRPMsgHandle;
selfRPMsgHandle = RPMessage_create(&selfRPMsgParam, &selfPt);
if (selfRPMsgHandle == NULL) {
UART_printf("RPMessage_create failed!\n");
return 0;
}
UART_printf("Created RPMessage endpoint %d on core %s\n", selfPt, Ipc_mpGetSelfName());
UART_printf("Waiting for message from %s...\n", Ipc_mpGetName(remoteProcId));
char recvMsg[512] = {0};
uint16_t msgLen = sizeof(recvMsg);
Osal_delay(3*1000);
// int32_t status = RPMessage_recvNb(selfRPMsgHandle,
// recvMsg, &msgLen, &remotePt,
// &remoteProcId);
int32_t status = RPMessage_recv(selfRPMsgHandle, recvMsg, &msgLen,
&remotePt, &remoteProcId, IPC_RPMESSAGE_TIMEOUT_FOREVER);
UART_printf("After RPMessage_recv\n");
if (status != IPC_SOK) {
UART_printf("Failed: RPMessage %s <---- %s\nMsg: %s\n", Ipc_mpGetSelfName(),
Ipc_mpGetName(remoteProcId), recvMsg);
} else {
UART_printf("Success: RPMessage %s <---- %s\nMsg: %s\n",
Ipc_mpGetSelfName(), Ipc_mpGetName(remoteProcId), recvMsg);
}
return (0);
}
Linker script for it is:
... /* Memory Map */ MEMORY { /* MCU0_R5F_0 local view */ MCU0_R5F_TCMA (X) : origin=0x0 length=0x100 /* MCU0_R5F_0 SoC view */ MCU0_R5F0_ATCM (RWIX) : origin=0x41000000 length=0x8000 MCU0_R5F0_BTCM (RWIX) : origin=0x41010000 length=0x8000 /* MCU0_R5F_1 SoC view */ MCU0_R5F1_ATCM (RWIX) : origin=0x41400000 length=0x8000 MCU0_R5F1_BTCM (RWIX) : origin=0x41410000 length=0x8000 MSMC3_DMSC_FW (RWIX) : origin=0x700F0000 length=0x10000 /* 64KB */ /* Used in this file */ DDR0_MCU_2_1 (RWIX) : origin=0x9B000000 length=0x4000000 /* 64 MB */ /* MSMC_SRAM */ RESET_VECTORS (X) : origin=0x70000000 length=0x40000 /* 256KB */ MAIN_MSRAM_0 : origin=0x70040000 length=0xB0000 /* 1MB - 320KB */ } /* Section Configuration */ SECTIONS { .rstvectors : {} palign(8) > MCU0_R5F_TCMA .bootCode : {} palign(8) > MAIN_MSRAM_0 .startupCode : {} palign(8) > MAIN_MSRAM_0 .startupData : {} palign(8) > MAIN_MSRAM_0, type = NOINIT .text : {} palign(8) > DDR0_MCU_2_1 .const : {} palign(8) > DDR0_MCU_2_1 .rodata : {} palign(8) > DDR0_MCU_2_1 .cinit : {} palign(8) > DDR0_MCU_2_1 .pinit : {} palign(8) > DDR0_MCU_2_1 .bss : {} align(4) > DDR0_MCU_2_1 .far : {} align(4) > DDR0_MCU_2_1 .data : {} palign(128) > DDR0_MCU_2_1 .boardcfg_data : {} palign(128) > MAIN_MSRAM_0 .sysmem : {} > DDR0_MCU_2_1 .data_buffer : {} palign(128) > DDR0_MCU_2_1 /* Require to host MPU configuration code in MAIN_MSRAM_0 */ .my_ipc_data_buffer (NOINIT) : {} palign(128) > MAIN_MSRAM_0 .CDD_IPC_MPU_CFG_OCMRAM : {} palign(8) > MAIN_MSRAM_0 ...
All of this is compiled with:
make receiver_example_app BOARD=j784s4_evm BUILD_TYPE=release SOC=j784s4 CORE=mcu2_1
Both examples are build with
MULTICORE CREATION:
Once compiled I create a multicore image with:
./MulticoreImageGen LE 55 multicore.appimage 8 sciserver_testapp_freertos_mcu1_0_release.rprc 9 sender_example_app_mcu1_1_release.rprc 10 sbl_mcux_0_dummy_app.rprc 11 receiver_example_app_mcu2_1_release.rprc
sender_example_app_mcu1_1_release is just a hello world print:
int main(void) { UART_printf("Sender example\n"); return 0; }
(I'm using sbl_mcux_0_dummy_app on mcu2_0 since "mcu2_0 can't be in a higher power state than mcu2_1" as found here https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1085821/faq-tda4vm-booting-mcu2_1-application-form-sbl)
-------------------------------
Similar question:
https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1517544/tda4vm-sciclient_init-is-blocked-when-using-ipclld
PROBLEM:
Running this results with mcu2_1 hanging in RPMessage_recv. (Very rarely it works, but it's unpredictable)
Prints from mcu1_0:
Sciserver Testapp Built On: Jul 11 2025 09:42:12 Sciserver Version: 11.0.0-REL.PSDK.11.00.00.21 RM_PM_HAL Version: v11.00.09 Starting Sciserver..... PASSED IPC_echo_test mcu1_0 IPC_echo_test (core : mcu1_0) (ID: 1)..... selfBuf @ a0400800 vqBuf @ a0400000 VRING_BASE_ADDRESS @ ac000000 RPMessage_init: RPMSG_DATA_SIZE 135424 Created RPMessage endpoint 10 on core mcu1_0 A---------------------- procId is 4 Success: RPMessage mcu1_0 ----> mcu2_1 Msg: hello from mcu1_0
Prints from mcu2_1:
IPC_echo_test (core : mcu2_1) .....
selfBuf @ 70040800
vqBuf @ 70040000
VRING_BASE_ADDRESS @ ac000000
Created RPMessage endpoint 10 on core mcu2_1
Waiting for message from mcu1_0...
After some debugging I know that RPMessage_recv hangs here:
pOsalPrms->unLockHIsrGate(module.gateSwi, key);
/* Block until notified. */
semStatus = pOsalPrms->lockMutex(obj->semHandle, timeout);
key = pOsalPrms->lockHIsrGate(module.gateSwi);
So it seems that the core does not get notified. What am I missing?
WHAT I NEED HELP WITH / CLARIFICATION:
Notice how I'm putting my_ipc_buffer_data section in different memory ranges on mcu1_0 and mcu2_1 (I've also tried putting it in the same memory range, but not much luck in making it work reliably)
What else can I do to make this work?
Thanks in advance.