openamp RPU-APU双核间通信 建立多个通道
Posted 为了维护世界和平_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了openamp RPU-APU双核间通信 建立多个通道相关的知识,希望对你有一定的参考价值。
前言
RPU-APU使用openamp进行通信
源码中只有单通道,并且通道最大512字节。测试数据吞吐量大概100Kb/s
实际应用中数据吞吐量要 2Mb/s,所有要提高数据量。
两种方法:
1)使用更多的通道;2)将通道的缓冲区扩大;
本文介绍建立多个通道方法
一、创建节点函数
先看一下手册中函数的使用说明
函数有删减,分析用
int rpmsg_create_ept(struct rpmsg_endpoint *ept, struct rpmsg_device *rdev,
const char *name, uint32_t src, uint32_t dest,
rpmsg_ept_cb cb, rpmsg_ns_unbind_cb unbind_cb)
...
//如果源地址不是RPMSG_ADDR_ANY
if (src != RPMSG_ADDR_ANY)
status = rpmsg_is_address_set(rdev->bitmap,
RPMSG_ADDR_BMP_SIZE, src);
if (!status)
/* Mark the address as used in the address bitmap. */
rpmsg_set_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE,src);
else if (status > 0)
status = RPMSG_SUCCESS;
goto ret_status;
else
goto ret_status;
else
addr = rpmsg_get_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE);
rpmsg_init_ept(ept, name, addr, dest, cb, unbind_cb);
rpmsg_register_endpoint(rdev, ept);
//目的地址RPMSG_ADDR_ANY
if (rdev->support_ns && ept->dest_addr == RPMSG_ADDR_ANY)
/* Send NS announcement to remote processor */
metal_mutex_release(&rdev->lock);
status = rpmsg_send_ns_message(ept, RPMSG_NS_CREATE);
metal_mutex_acquire(&rdev->lock);
if (status)
rpmsg_unregister_endpoint(ept);
...
src源地址,可以是0,1,2…RPMSG_ADDR_ANY
dest目的地址必须是:RPMSG_ADDR_ANY
官方文档中发送函数
RPU有的函数指定源地址和目的地址,
源地址就是通道创建时的src,
目的地址:比如APU侧,建立连接的时候需要源地址和目的地址,此源地址就是RPU的dest地址
使用rpmsg_send函数 根据 endpoint可以知道建立的连接,可以不使用带src,dest参数的函数。
二、RPU侧创建多通道
创建连接16个连接endpoint
源地址:[0-15],
目的地址:RPMSG_ADDR_ANY
//函数指针
typedef int (*FUN_CALC) (struct rpmsg_endpoint *ept, void *data, size_t len,uint32_t src, void *priv);
//回调函数数组,为了能方便注册函数,使代码简介
FUN_CALC pFuncList[] =
&rpmsg0_endpoint_cb, &rpmsg1_endpoint_cb, &rpmsg2_endpoint_cb, &rpmsg3_endpoint_cb,
&rpmsg4_endpoint_cb, &rpmsg5_endpoint_cb, &rpmsg6_endpoint_cb, &rpmsg7_endpoint_cb,
&rpmsg8_endpoint_cb, &rpmsg9_endpoint_cb,&rpmsg10_endpoint_cb, &rpmsg11_endpoint_cb,
&rpmsg12_endpoint_cb, &rpmsg13_endpoint_cb, &rpmsg14_endpoint_cb,&rpmsg15_endpoint_cb
;
//官方的app函数修改,创建过个endpoint
int app(struct rpmsg_device *rdev, void *priv)
int ret,i;
LPRINTF("Try to create rpmsg endpoint.\\n");
char service_name[32];
for(i=0;i<16;i++)
sprintf(service_name,"rpmsg-openamp-demo-channel%d",i);//服务名字
/* Initialize RPMSG framework */
ret = rpmsg_create_ept(&lept[i], rdev, service_name,
i, RPMSG_ADDR_ANY, pFuncList[i],
rpmsg_service_unbind);
if (ret)
LPERROR("Failed to create endpoint1.\\n");
return -1;
if (ret)
LPERROR("Failed to create endpoint2.\\n");
return -1;
LPRINTF("Successfully created rpmsg endpoint1.\\n");
while(1)
vTaskDelay(100);//增加调度延时函数
platform_poll(priv);//阻塞函数修改,取消_rproc_wait()
for(i=0;i<17;i++)
rpmsg_destroy_ept(&lept[i]);
return 0;
//回调函数1
static int rpmsg0_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
uint32_t src, void *priv)
(void)priv;
(void)src;
/* On reception of a shutdown we signal the application to terminate */
if ((*(unsigned int *)data) == SHUTDOWN_MSG)
LPRINTF("shutdown message is received.\\n");
shutdown_req = 1;
return RPMSG_SUCCESS;
/* Send data back to master */
if (rpmsg_send(ept, data, len) < 0)
LPERROR("rpmsg_send failed2\\n");
else
LPRINTF("rpmsg_send ok0 \\n");
return RPMSG_SUCCESS;
//回调函数2
static int rpmsg1_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
uint32_t src, void *priv)
(void)priv;
(void)src;
/* On reception of a shutdown we signal the application to terminate */
if ((*(unsigned int *)data) == SHUTDOWN_MSG)
LPRINTF("shutdown message is received.\\n");
shutdown_req = 1;
return RPMSG_SUCCESS;
/* Send data back to master */
if (rpmsg_send(ept, data, len) < 0)
LPERROR("rpmsg_send failed3\\n");
else
LPRINTF("rpmsg_send ok1 \\n");
return RPMSG_SUCCESS;
//回调函数3
static int rpmsg2_endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len,
uint32_t src, void *priv)
(void)priv;
(void)src;
/* On reception of a shutdown we signal the application to terminate */
if ((*(unsigned int *)data) == SHUTDOWN_MSG)
LPRINTF("shutdown message is received.\\n");
shutdown_req = 1;
return RPMSG_SUCCESS;
/* Send data back to master */
if (rpmsg_send(ept, data, len) < 0)
LPERROR("rpmsg_send failed3\\n");
else
LPRINTF("rpmsg_send ok2 \\n");
return RPMSG_SUCCESS;
...(剩下的回调函数省略)
platform_poll 函数如下
注释内部while循环,等待函数
int platform_poll(void *priv)
struct remoteproc *rproc = priv;
struct remoteproc_priv *prproc;
unsigned int flags;
prproc = rproc->priv;
//while(1)
flags = metal_irq_save_disable();
if (!(atomic_flag_test_and_set(&prproc->ipi_nokick)))
metal_irq_restore_enable(flags);
remoteproc_get_notification(rproc, RSC_NOTIFY_ID_ANY);//RSC_NOTIFY_ID_ANY
return 0;//break;
//_rproc_wait();
metal_irq_restore_enable(flags);
//
return 0;
三、APU侧创建多通道
在RPU侧建立好16通道后,加载运行,在ls -l /sys/bus/rpmsg/devices
lrwxrwxrwx 1 root root 0 Nov 26 01:20 virtio0.rpmsg-openamp-demo-channel0.-1.0 -> ../../../devices/platform/ff9a0000.zynqmp-rpu/r5@0/r5@0#vdev0buffer/virtio0/virtio0.rpmsg-openamp-demo-channel0.-1.0
lrwxrwxrwx 1 root root 0 Nov 26 01:20 virtio0.rpmsg-openamp-demo-channel1.-1.1 -> ../../../devices/platform/ff9a0000.zynqmp-rpu/r5@0/r5@0#vdev0buffer/virtio0/virtio0.rpmsg-openamp-demo-channel1.-1.1
lrwxrwxrwx 1 root root 0 Nov 26 01:20 virtio0.rpmsg-openamp-demo-channel10.-1.10 -> ../../../devices/platform/ff9a0000.zynqmp-rpu/r5@0/r5@0#vdev0buffer/virtio0/virtio0.rpmsg-openamp-demo-channel10.-1.10
lrwxrwxrwx 1 root root 0 Nov 26 01:20 virtio0.rpmsg-openamp-demo-channel11.-1.11 -> ../../../devices/platform/ff9a0000.zynqmp-rpu/r5@0/r5@0#vdev0buffer/virtio0/virtio0.rpmsg-openamp-demo-channel11.-1.11
lrwxrwxrwx 1 root root 0 Nov 26 01:20 virtio0.rpmsg-openamp-demo-channel12.-1.12 -> ../../../devices/platform/ff9a0000.zynqmp-rpu/r5@0/r5@0#vdev0buffer/virtio0/virtio0.rpmsg-openamp-demo-channel12.-1.12
lrwxrwxrwx 1 root root 0 Nov 26 01:20 virtio0.rpmsg-openamp-demo-channel13.-1.13 -> ../../../devices/platform/ff9a0000.zynqmp-rpu/r5@0/r5@0#vdev0buffer/virtio0/virtio0.rpmsg-openamp-demo-channel13.-1.13
lrwxrwxrwx 1 root root 0 Nov 26 01:20 virtio0.rpmsg-openamp-demo-channel14.-1.14 -> ../../../devices/platform/ff9a0000.zynqmp-rpu/r5@0/r5@0#vdev0buffer/virtio0/virtio0.rpmsg-openamp-demo-channel14.-1.14
lrwxrwxrwx 1 root root 0 Nov 26 01:20 virtio0.rpmsg-openamp-demo-channel15.-1.15 -> ../../../devices/platform/ff9a0000.zynqmp-rpu/r5@0/r5@0#vdev0buffer/virtio0/virtio0.rpmsg-openamp-demo-channel15.-1.15
lrwxrwxrwx 1 root root 0 Nov 26 01:20 virtio0.rpmsg-openamp-demo-channel16.-1.16 -> ../../../devices/platform/ff9a0000.zynqmp-rpu/r5@0/r5@0#vdev0buffer/virtio0/virtio0.rpmsg-openamp-demo-channel16.-1.16
lrwxrwxrwx 1 root root 0 Nov 26 01:20 virtio0.rpmsg-openamp-demo-channel2.-1.2 -> ../../../devices/platform/ff9a0000.zynqmp-rpu/r5@0/r5@0#vdev0buffer/virtio0/virtio0.rpmsg-openamp-demo-channel2.-1.2
lrwxrwxrwx 1 root root 0 Nov 26 01:20 virtio0.rpmsg-openamp-demo-channel3.-1.3 -> ../../../devices/platform/ff9a0000.zynqmp-rpu/r5@0/r5@0#vdev0buffer/virtio0/virtio0.rpmsg-openamp-demo-channel3.-1.3
lrwxrwxrwx 1 root root 0 Nov 26 01:20 virtio0.rpmsg-openamp-demo-channel4.-1.4 -> ../../../devices/platform/ff9a0000.zynqmp-rpu/r5@0/r5@0#vdev0buffer/virtio0/virtio0.rpmsg-openamp-demo-channel4.-1.4
lrwxrwxrwx 1 root root 0 Nov 26 01:20 virtio0.rpmsg-openamp-demo-channel5.-1.5 -> ../../../devices/platform/ff9a0000.zynqmp-rpu/r5@0/r5@0#vdev0buffer/virtio0/virtio0.rpmsg-openamp-demo-channel5.-1.5
lrwxrwxrwx 1 root root 0 Nov 26 01:20 virtio0.rpmsg-openamp-demo-channel6.-1.6 -> ../../../devices/platform/ff9a0000.zynqmp-rpu/r5@0/r5@0#vdev0buffer/virtio0/virtio0.rpmsg-openamp-demo-channel6.-1.6
lrwxrwxrwx 1 root root 0 Nov 26 01:20 virtio0.rpmsg-openamp-demo-channel7.-1.7 -> ../../../devices/platform/ff9a0000.zynqmp-rpu/r5@0/r5@0#vdev0buffer/virtio0/virtio0.rpmsg-openamp-demo-channel7.-1.7
lrwxrwxrwx 1 root root 0 Nov 26 01:20 virtio0.rpmsg-openamp-demo-channel8.-1.8 -> ../../../devices/platform/ff9a0000.zynqmp-rpu/r5@0/r5@0#vdev0buffer/virtio0/virtio0.rpmsg-openamp-demo-channel8.-1.8
lrwxrwxrwx 1 root root 0 Nov 26 01:20 virtio0.rpmsg-openamp-demo-channel9.-1.9 -> ../../../devices/platform/ff9a0000.zynqmp-rpu/r5@0/r5@0#vdev0buffer/virtio0/virtio0.rpmsg-openamp-demo-channel9.-1.9
节点规律:virtio0.rpmsg-openamp-demo-channelX.-1.X
APU 源码echo_test 在创建节点的时候,需要根据virtio0.rpmsg-openamp-demo-channelX.-1.X创建
char rpmsg_dev[][50]=
"virtio0.rpmsg-openamp-demo-channel0.-1.0",
"virtio0.rpmsg-openamp-demo-channel1.-1.1",
"virtio0.rpmsg-openamp-demo-channel2.-1.2",
"virtio0.rpmsg-openamp-demo-channel3.-1.3",
"virtio0.rpmsg-openamp-demo-channel4.-1.4",
"virtio0.rpmsg-openamp-demo-channel5.-1.5",
"virtio0.rpmsg-openamp-demo-channel6.-1.6",
"virtio0.rpmsg-openamp-demo-channel7.-1.7",
"virtio0.rpmsg-openamp-demo-channel8.-1.8",
"virtio0.rpmsg-openamp-demo-channel9.-1.9",
"virtio0.rpmsg-openamp-demo-channel10.-1.10",
"virtio0.rpmsg-openamp-demo-channel11.-1.11",
"virtio0.rpmsg-openamp-demo-channel12.-1.12",
"virtio0.rpmsg-openamp-demo-channel13.-1.13",
"virtio0.rpmsg-openamp-demo-channel14.-1.14",
"virtio0.rpmsg-openamp-demo-channel15.-1.15",
"virtio0.rpmsg-openamp-demo-channel16.-1.16",
;
char rpmsg_name[][40]=
"rpmsg-openamp-demo-channel0",
"rpmsg-openamp-demo-channel1",
"rpmsg-openamp-demo-channel2",
"rpmsg-openamp-demo-channel3",
"rpmsg-openamp-demo-channel4",
"rpmsg-openamp-demo-channel5",
"rpmsg-openamp-demo-channel6",
"rpmsg-openamp-demo-channel7",
"rpmsg-openamp-demo-channel8",
"rpmsg-openamp-demo-channel9",
"rpmsg-openamp-demo-channel10",
"rpmsg-openamp-demo-channel11",
"rpmsg-openamp-demo-channel12",
"rpmsg-openamp-demo-channel13",
"rpmsg-openamp-demo-channel14",
"rpmsg-openamp-demo-channel15",
"rpmsg-openamp-demo-channel16",
;
#define RPMSG_MAX_CHANNEL 17
//主函数
int main(int argc, char *argv[])
int ret, i, j;
int size, bytes_rcvd, bytes_sent;
err_cnt = 0;
int opt;
//char *rpmsg_dev="virtio0.rpmsg-openamp-demo-channel.-1.0";
int ntimes = 1;
char fpath[256];
int rec[474];
char rpmsg_char_name[16][16];
struct rpmsg_endpoint_info eptinfo[16];
char ept_dev_name[16];
char ept_dev_path[32];
int rmpsg_fd[16];
while ((opt = getopt(argc, argv, "d:n:")) != -1)
switch (opt)
case 'd':
//rpmsg_dev = optarg;
break;
case 'n':
ntimes = atoi(optarg);
break;
default:
printf("getopt return unsupported option: -%c\\n",opt);
break;
printf("\\r\\n Echo test start \\r\\n");
/* Load rpmsg_char driver */
printf("\\r\\nMaster>probe rpmsg_char\\r\\n");
ret = system("modprobe rpmsg_char");
if (ret < 0)
perror("Failed to load rpmsg_char driver.\\n");
return -EINVAL;
for(i=0;i<RPMSG_MAX_CHANNEL ;i++)
charfd[i]=-1;
memset(rpmsg_char_name[i],0,sizeof(rpmsg_char_name[0]));
for(i=0;i<RPMSG_MAX_CHANNEL;i++)
printf("\\r\\n Open rpmsg dev %s! \\r\\n", rpmsg_dev);
sprintf(fpath, "%s/devices/%s", RPMSG_BUS_SYS, rpmsg_dev[i]);
if (access(fpath, F_OK))
fprintf(stderr, "Not able to access rpmsg device %s, %s\\n",
fpath, strerror(errno));
return -EINVAL;
memset(fpath,0,sizeof(fpath));
ret = bind_rpmsg_chrdev(rpmsg_dev[i]);
if (ret < 0)
return ret;
charfd[i] = get_rpmsg_chrdev_fd(rpmsg_dev[i], rpmsg_char_name[i]);
if (charfd[i] < 0)
return charfd[i];
/* Create endpoint from rpmsg char driver */
strcpy(eptinfo[i].name, rpmsg_name[i]);
eptinfo[i].src = i;
eptinfo[i].dst = 0xFFFFFFFF;
ret = rpmsg_create_ept(charfd[i], &eptinfo[i]);
if (ret)
printf("failed to create RPMsg endpoint.\\n");
return -EINVAL;
if (!get_rpmsg_ept_dev_name(rpmsg_char_name[i], eptinfo[i].name,ept_dev_name))
return -EINVAL;
sprintf(ept_dev_path, "/dev/%s", ept_dev_name);
rmpsg_fd[i] = open(ept_dev_path, O_RDWR | O_NONBLOCK);
if (rmpsg_fd[i] < 0)
perror("Failed to open rpmsg device.");
close(rmpsg_fd[i]);
return -1;
memset(ept_dev_path,0,sizeof(ept_dev_path));
memset(ept_dev_name,0,sizeof(ept_dev_name));
i_payload = (struct _payload *)malloc(2 * sizeof(unsigned long) + PAYLOAD_MAX_SIZE);
r_payload = (struct _payload *)malloc(2 * sizeof(unsigned long) + PAYLOAD_MAX_SIZE);
if (i_payload == 0 || r_payload == 0)
printf("ERROR: Failed to allocate memory for payload.\\n");
return -1;
while(1)
if(i==15)
i=0;
//16个通道轮询收发
bytes_sent = write(rmpsg_fd[i], i_payload,(2 * sizeof(unsigned long)) + size);
printf("fd bytes_sent=%d\\n",bytes_sent);
bytes_rcvd = read(rmpsg_fd[i], RX_BUF,PAYLOAD_MAX_SIZE);
while (bytes_rcvd <= 0)
bytes_sent = write(rmpsg_fd[i], i_payload,(2 * sizeof(unsigned long)) + size);
printf("while fd bytes_sent=%d\\n",bytes_sent);
usleep(10000);
bytes_rcvd = read(rmpsg_fd[i],RX_BUF,PAYLOAD_MAX_SIZE);
printf("index=%d,recv data len=%d\\n",i,bytes_rcvd);
i++;
free(i_payload);
free(r_payload);
for(i=0;i<16;i++)
close(rmpsg_fd[i]);
if (charfd >= 0)
close(charfd);
return 0;
串口输出,收发正常
index=1,recv data len=17
fd bytes_sent=17
index=2,recv data len=17
fd bytes_sent=17
index=3,recv data len=17
fd bytes_sent=17
index=4,recv data len=17
fd bytes_sent=17
index=5,recv data len=17
fd bytes_sent=17
index=6,recv data len=17
fd bytes_sent=17
index=7,recv data len=17
fd bytes_sent=17
index=8,recv data len=17
fd bytes_sent=17
index=9,recv data len=17
fd bytes_sent=17
index=10,recv data len=17
fd bytes_sent=17
index=11,recv data len=17
fd bytes_sent=17
index=12,recv data len=17
fd bytes_sent=17
index=13,recv data len=17
fd bytes_sent=17
index=14,recv data len=17
openamp测试发现的问题
1)RPU只有收到APU的数据后,才能调用rpmsg_send函数发送数据,这里不知道哪里有问题?
2)单通道缓冲区扩大方法?
以上是关于openamp RPU-APU双核间通信 建立多个通道的主要内容,如果未能解决你的问题,请参考以下文章
ThreadX内核源码分析(SMP) - 核间通信(arm)
ThreadX内核源码分析(SMP) - 核间通信(arm)