AM243-IPC

简介

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中断里自己去读取数据?
在这里插入图片描述

相关推荐

  1. <span style='color:red;'>AM</span><span style='color:red;'>243</span>-<span style='color:red;'>IPC</span>

    AM243-IPC

    2024-07-13 11:42:04      23 阅读
  2. ARM-IIC实验

    2024-07-13 11:42:04       35 阅读
  3. arm iic通信

    2024-07-13 11:42:04       43 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-13 11:42:04       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-13 11:42:04       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-13 11:42:04       58 阅读
  4. Python语言-面向对象

    2024-07-13 11:42:04       69 阅读

热门阅读

  1. 【2024暑期实习】接到新需求该如何做?

    2024-07-13 11:42:04       22 阅读
  2. MATLAB中Simulink.exportToTemplate用法

    2024-07-13 11:42:04       22 阅读
  3. C#面:中间件的使用场景有哪些?

    2024-07-13 11:42:04       21 阅读
  4. vue3 学习笔记08 -- computed 和 watch

    2024-07-13 11:42:04       24 阅读
  5. R语言学习笔记6-数据框

    2024-07-13 11:42:04       20 阅读
  6. 菜鸡的原地踏步史07(◐‿◑)

    2024-07-13 11:42:04       18 阅读