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)单通道缓冲区扩大方法?

猜你喜欢

转载自blog.csdn.net/WANGYONGZIXUE/article/details/121860793
今日推荐