目录
简介
am243x是德州仪器(TI)家的多核处理器,最豪华的配置AM2434内含4个Cortex-R5(800Mhz),1个Cortex-M4(400Mhz)处理器。内置2MB SRAM,256KB紧耦合内存(R5侧),256KBSRAM(M4侧)。支持多种工业网络通讯协议,主要应用于工业网关,PLC等
IPC是内核之间直接通信的办法。AM243X使用IPC notify向内核发布信号,使用RPmessage向内核传递消息。
IPC Notify
am243x中使用IPC notify实现片内核心之间简单的数据通信。只携带一个2字节数据。
每一个内核中支持16个Client ID。与其说是client id,我觉得更像通信消息的槽位。内核可以为每一个Client ID绑定中断回调函数。
使用 system empty工程测试
Sender R5F_0_0
#include <kernel/dpl/ClockP.h>
#include <drivers/ipc_notify.h>
uint16_t clientId = 4; //发送clientid为4的消息
uint16_t message_value = 0x3374; //消息数据
void empty_main(void *args)
{
/* Open drivers to open the UART driver for console */
Drivers_open();
Board_driversOpen();
//指定远端内核,远端内核的client id, 消息内容
int32_t ret = IpcNotify_sendMsg(CSL_CORE_ID_M4FSS0_0, clientId, message_value, 1);
DebugP_assert(ret == SystemP_SUCCESS);
Board_driversClose();
Drivers_close();
}
Receiver M4F
中断方式接收
#include <drivers/ipc_notify.h>
void ipc_notify_msg_handler_id4(uint32_t remoteCoreId, uint16_t localClientId, uint32_t msgValue, int32_t crcStatus, void *args)
{
asm("bkpt");
}
uint16_t clientId = 4; //接收clientid为4的消息
void empty_main(void *args)
{
/* Open drivers to open the UART driver for console */
Drivers_open();
Board_driversOpen();
int32_t status;
status = IpcNotify_registerClient(clientId, ipc_notify_msg_handler_id4, NULL);
DebugP_assert(status==SystemP_SUCCESS);
while(1);
Board_driversClose();
Drivers_close();
}
测试
进入调试模式
接收方的接收中断函数里有软件断点,接收到数据之后会在此处中断
依次启动M4(接收方),R5_0_0(发送方)。
M4进入IPC中断中,断点处栈空间变量如下
符合预期,测试成功
疑问
似乎不配置MPU也可以成功运行,不清楚为什么。
后面的RPMessage机制就必须配置MPU才能运行
RP Message
单次传输最大数据量1152字节。
缓冲区个数最多16个
RP Message使用EndPoint(端点)机制,这个机制有点类似于Socket的Port。发送方持有发送端点,向接收端点发送消息。
配置
参与通信的核心需要预先配置IPC和MPU
本文的测试中,所有核心的IPC和MPU配置全部一致(除M4的IMPU不需要配置)
IPC点击一下ADD,参数保持不变即可。如果要测试更长的数据需要对RP Message Buffer Size (Bytes)做相应的调整
IPC配置如下
MPU配置如下,增加0x701D0000 长度34KB的配置。该区域就是IPC RAM的内存保护规则,需要配置Cache为 NoCache选项。
Sender R5F_0_0
uint32_t gRemoteCoreId = CSL_CORE_ID_R5FSS0_1;
uint32_t gMainCoreId = CSL_CORE_ID_R5FSS0_0;
uint16_t gRemoteServiceEndPt = 13u;
uint16_t gLocalServiceEndPt = 12u;
void ipc_rpmsg_echo_main_core_start(void)
{
int32_t status;
char sendBuf[64] = "Hello world";
while(1)
{
status = RPMessage_send(
sendBuf, sizeof(sendBuf),
gRemoteCoreId, gRemoteServiceEndPt,
gLocalServiceEndPt,
SystemP_WAIT_FOREVER);
DebugP_assert(status==SystemP_SUCCESS);
DebugP_log("send %s\n", sendBuf);
ClockP_usleep(500*1000);
}
}
Receiver R5F_0_1
注意,这里没有采用中断接收而是轮询接收。如果要求修改为中断接收那么需要在初始化createParams的时候指定中断回调函数。
uint32_t gRemoteCoreId = CSL_CORE_ID_R5FSS0_1;
uint32_t gMainCoreId = CSL_CORE_ID_R5FSS0_0;
uint16_t gRemoteServiceEndPt = 13u;
uint16_t gLocalServiceEndPt = 12u;
static RPMessage_Object gRecvMsgObject;
void ipc_rpmsg_echo_remote_core_start(void)
{
int32_t status;
RPMessage_CreateParams createParams;
uint16_t recvMsgSize, remoteCoreId, remoteCoreEndPt;
char recvBuf[64] = {0};
RPMessage_CreateParams_init(&createParams);
createParams.localEndPt = gRemoteServiceEndPt;
status = RPMessage_construct(&gRecvMsgObject, &createParams);
DebugP_assert(status==SystemP_SUCCESS);
while(1)
{
status = RPMessage_recv(&gRecvMsgObject,
recvBuf, &recvMsgSize,
&remoteCoreId, &remoteCoreEndPt,
SystemP_WAIT_FOREVER);
DebugP_assert(status==SystemP_SUCCESS);
DebugP_log("recv %s\n", recvBuf);
}
}
中断接收
注意,只能使用createParams的recvNotifyCallback,而不是recvCallback,后者会报assert失败
static RPMessage_Object gRecvMsgObject;
static void recvNotifyCallback(RPMessage_Object *obj, void *arg)
{
int32_t status;
uint16_t recvMsgSize, remoteCoreId, remoteCoreEndPt;
char recvBuf[64] = {0};
status = RPMessage_recv(&gRecvMsgObject,
recvBuf, &recvMsgSize,
&remoteCoreId, &remoteCoreEndPt,
SystemP_WAIT_FOREVER);
DebugP_assert(status==SystemP_SUCCESS);
asm("bkpt");
}
void ipc_rpmsg_echo_remote_core_start(void)
{
int32_t status;
RPMessage_CreateParams createParams;
RPMessage_CreateParams_init(&createParams);
createParams.localEndPt = gRemoteServiceEndPt;
createParams.recvNotifyCallback = recvNotifyCallback;
status = RPMessage_construct(&gRecvMsgObject, &createParams);
DebugP_assert(status==SystemP_SUCCESS);
while(1);
}
测试
问题
为啥不允许注册recvCallback,而是要我在notify中断里自己去读取数据?