前言
RPU-APU使用openamp进行通信
源码中只有单通道,并且通道最大512字节。
两种方法:
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_ANYif (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_ANYif (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_ANYreturn 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)单通道缓冲区扩大方法?
The RPMsg buffer size is limited to 512 bytes, but 496 bytes are used for the payload.
The OpenAMP message size is limited by the buffer size defined in the rpmsg kernel module.
IMPORTANT: Do not redefine the RPMsg buffer size.
手册中提示,RPMsg buffer的大小不能调整