Xilinx XDMA 上位机应用程序控制逻辑

Xilinx XDMA pcie 上位机应用程序控制逻辑

1. 驱动安装的参数

关于驱动的编译和安装这里就不多讲了,无非就是make 和 insmod 。这里讲一下驱动安装时,控制驱动属性的几个参数:
1.中断模式

static unsigned int interrupt_mode;
module_param(interrupt_mode, uint, 0644);
MODULE_PARM_DESC(interrupt_mode, "0 - Auto , 1 - MSI, 2 - Legacy, 3 - MSI-x");

中断模式分为三种,MSIX是最新的中断模式,老版本的内核可能不支持。就比如说我的内核。如果不指定驱动安装额中断参数,那么就会产生内核安装的错误。所以这里我们选择MSI的中断模式。

2.驱动运行模式

static unsigned int poll_mode;
module_param(poll_mode, uint, 0644);
MODULE_PARM_DESC(poll_mode, "Set 1 for hw polling, default is 0 (interrupts)");

驱动的运行模式分为两种, 中断模式和poll_mode 模式,默认是中断模式,设置为1是硬件polling模式。根据实际应用场景可以选择相应的设置。
3.sgdma传输延时

unsigned int h2c_timeout = 10;
module_param(h2c_timeout, uint, 0644);
MODULE_PARM_DESC(h2c_timeout, "H2C sgdma timeout in seconds, default is 10 sec.");

unsigned int c2h_timeout = 10;
module_param(c2h_timeout, uint, 0644);
MODULE_PARM_DESC(c2h_timeout, "C2H sgdma timeout in seconds, default is 10 sec.");

默认是10s钟, 可以自定义设置。

4.其他参数

static unsigned int enable_st_c2h_credit = 0;
module_param(enable_st_c2h_credit, uint, 0644);
MODULE_PARM_DESC(enable_st_c2h_credit,
	"Set 1 to enable ST C2H engine credit feature, default is 0 ( credit control disabled)");

unsigned int desc_blen_max = XDMA_DESC_BLEN_MAX;
module_param(desc_blen_max, uint, 0644);
MODULE_PARM_DESC(desc_blen_max,
		 "per descriptor max. buffer length, default is (1 << 28) - 1");

这两个参数,没有使用过,基本上也没怎么了解。 大概也就是数据传输的认证和描述符的buf长度吧 。

2.驱动安装后生成的几个设备

驱动安装成功后,会生成几个设备文件。对应的应用编程, 就是操作这些设备文件来实现对应的业务逻辑。简单的介绍一下几个设备的功能:
Xilinx XDMA 上位机应用程序控制逻辑_第1张图片
1. xdma0_h2c_0 xdma0_c2h_0
这两个设备就是用来读写的设备文件,h2c 是写设备,c2h是读设备。对应的是FPGA端设置的通道。
2. xdma0_events_x
用于处理中断事件的设备,IP核内设置对应的中断号,对应的中断设备。
3. xdma0_user
xdma_user设备节点用于实现PCIe的地址映射,为上层应用提供编程控制接口、AXI接口等
4. xdma0_control
xdma0_control设备节点主要是为上层提供DMA寄存器接口

比较常用的就这几个设备。

3.应用程序逻辑

两个线程:一个线程用于处理中断事件,另外一个线程用于处理数据读取。线程之间的同步用信号量。
读取的数据保存在文件。

	/*信号量初始化*/
	sem_init(&c2h_sem, 0, 0);
	/*线程创建*/
	pthread_create(&c2h_event_thread, NULL, c2h_event_process, NULL);
	pthread_create(&c2h_data_thread, NULL, c2h_data_process, NULL);

void *c2h_event_process(void *param)
{
	static int flag = 0;
	int fd = open_event("/dev/xdma0_events_0");
	printf("c2h event thread running, c2h_event_fd = %d\n", fd);
	while(1)
	{
		int val = read_event(fd);
		if(val ) 
		{
			sem_post(&c2h_sem);
			if (flag < total_frame) {
				printf("c2h get %d frame event\n",flag);
				flag++;
			}else{
				pthread_exit(0);
			}
		}else{	
			continue;
		}
	}
}
void *c2h_data_process(void *param)
{
	int fd = open("/dev/xdma0_c2h_0",O_RDWR | O_NONBLOCK);
	printf("c2h data thread running, c2h_data_fd = %d\n", fd);

	/*读取的数据写文件*/
	FILE *record_fp = fopen("/mnt/nfs/c2h_record.bin", "wb");
	unsigned char *buf = new unsigned char[frame_bytes];
	while(1)
	{
		sem_wait(&c2h_sem);
	 	int read_bytes = read(xdma_c2h_fd, c2h_align_mem, trans_bytes);
	 	memcpy(buf, c2h_align_mem, read_bytes);
		recv_frame_cnt++;
		fwrite(buf, frame_bytes, 1, record_fp);
		printf("Have been read %d frame,with %d irq\n",recv_frame_cnt,irq_num);
		if(recv_frame_cnt >= total_frame)
		{
			clock_gettime(CLOCK_MONOTONIC, &ts_end);
			printf("video recv over!\n");
			delete buf;
			fclose(record_fp);
			pthread_exit(0);
		}
	}
}

读取的数据保存在以4096字节的堆区。函数调用时:

/*4096字节对齐分配内存*/
posix_memalign((void **)&c2h_align_mem,4096, frame_bytes);

设备xdma_usr的使用,之前有说过,xdma_user设备节点用于实现PCIe的地址映射,为上层应用提供编程控制接口、AXI接口等。
那么FPGA端可以设置一些属性放在寄存器中供我们读取。比如我这边就从寄存器a4获取的帧的大小,
mmap 函数是将硬件的地址硬件映射至linux 用户层可访问的虚拟地址空间。

	int control_fd = open_control("/dev/xdma0_user");
	control_base = mmap_control(control_fd,MAP_SIZE);
	/*获取帧大小*/
	frame_bytes = read_control(control_base,0x0a4);
	printf("frame_bytes:%d\n", frame_bytes);

测试代码很简单,逻辑基本上就是这样。

最近我会去研究XDMA的驱动,看他的实际逻辑时如何的。之后会更新一篇文章,来梳理我之后的学习内容。

相关的的驱动及测试代码,以及FPGA工程,已经上传至网盘,有需要的朋友可以自行下载。

链接:https://pan.baidu.com/s/1wdPqUf8_2K6r8ZbVupizrw
提取码:i2sw

你可能感兴趣的:(linux,Xilinx,XDMA,后端,fpga开发,驱动开发)