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)

IPC的使用

对比传统的Xilinx AMP方案和OPENAMP方案-xapp1078和ug1186

推翻自己已有认知

openamp 实现项目的功能需求