当前位置:   article > 正文

Zynq Ultrascale PS - PL中断_zynqmp 配置pl_ps_group1中断

zynqmp 配置pl_ps_group1中断

1 本文主要介绍ZynqMP Ultrascale PL-PS中断

1.1 zynq 中断学习

在这里插入图片描述zynq的中断分为三种:

1.软件中断(SGI,Software generatedinterrupts,中断号0-15)(16–26 reserved) :被路由到一个或者两个CPU上,通过写ICDSGIR寄存器产生SGI.

2.私有外设中断(PPI,private peripheralinterrupts ,中断号27-31):每个CPU都有一组PPI,包括全局定时器、私有看门狗定时器、私有定时器和来自PL的FIQ/IRQ.

3.共享外设中断(SPI,shared peripheralinterrupts,中断号32-95):由PS和PL上的各种I/O控制器和存储器控制器产生,这些中断信号被路由到相应的CPU.

中断控制器(GIC,generic interrupt controller ):用于集中管理从PS和PL产生的中断信号的资源集合。控制器可以使能、关使能、屏蔽中断源和改变中断源的优先级,并且会将中断送到对应的CPU中,CPU通过私有总线访问这些寄存器。

从下面的表格中可以看到中断向量的具体值。PL 到 PS 部分一共有 20 个中断可以使用。其中 4 个是快速中断。
在这里插入图片描述

2 BRAM中断的两种方式

在这里插入图片描述
在这里插入图片描述
bram收发过程:
zynqMP 通过M_AXI_HPM0_FPD 接口通过AXI Interconnect桥接到bram 控制器,bram控制器通过PORTA端口写入数据到bram。PS通过AXI_GPIO_0发送中断信号给PL,PL收到中断处理数据。
PL 通过BRAM_PORTB_0端口直接写入数据到BRAM中,写入完成后通过pl_int[0:0]发送中断到PS,PS处理bram数据。

2.2 UIO模式

2.2.1 内核配置
$ petalinux-config -c kernel
Device Drivers  --->
    Userspace I/O drivers  --->
        < > generic Hilscher CIF Card driver
        <M> Userspace I/O platform driver with generic IRQ handling
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述
在这里插入图片描述

2.2.2 设备树修改:

chosen {
bootargs = “console=ttyPS0,115200 earlyprintk uio_pdrv_genirq.of_id=generic-uio”;
};

uio@0{
		compatible="generic-uio";
		status="okay";
		interrupt-controller;
		interrupt-parent=<&gic>;
		interrupts=<0x0 91 0x4>;
	};
		uio@1{
		compatible="generic-uio";
		status="okay";
		interrupt-controller;
		interrupt-parent=<&gic>;
		interrupts=<0x0 90 0x4>;
	};
		uio@2{
		compatible="generic-uio";
		status="okay";
		interrupt-controller;
		interrupt-parent=<&gic>;
		interrupts=<0x0 89 0x4>;
	};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

interrupts=<0x0 91 0x4>含义:
91代表了中断号,这个中断号是系统硬件中断号减去32得到.
0x4代表中断类型:
0x1:上升沿触发。
0x2:下降触发
0x4: 高电平沿触发
0x8: 低电平触发
zynq zynqMP 不支持低电平和下降沿触发中断(未求证)。实测最好设置为上升沿触发。

ZynqMP和Zynq的一个区别需要注意,ZynqMP的interrupt-parent指向的是&gic,而Zynq指向了&intc。
可以参考pl.dtsi文件。

2.2.3 启动测试

lsmod 查看UIO Module是否插入
在这里插入图片描述
查看中断发生次数:
cat /proc/interrupt
![在这里插入图片描述]bufe(https://img-blog.csdnimg.cn/20191024150047235.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21heWJlX29ubHk=,size_16,color_FFFFFF,t_70)
使用调试工具向BRAM写入数据:
查看uio中断只有一次。
这是因为uio的终端处理函数被关闭了,需要调用write来重新打开

可以查看内核中的源码kernnel_souce/dirver/uio/uio_pdrv_genirq.c和介绍**https://01.org/linuxgraphics/gfx-docs/drm/driver-api/uio-howto.html **

部分代码自己手动修改,有出入
源码如上图所示:kernel_source/drviver/uio/uio_pdrv_genirq.c)可知,每个UIO设备会有对应的/dev/uioX的设备节点。用户态驱动程序的读操作会阻塞直到UIO硬件中断发生。UIO的中断处理程序uio_pdrv_denirq_handler()会关闭该硬件中断。用户态驱动程序需要通过write函数来触发uio_pdrv_genirq_irqcontrol()以完成中断的使能和关闭。
可使用echo 0x1 > /dev/uio*,重新开启uio中断。

3 手动编写中断驱动程序

3.1 设备树修改

amba_pl: amba_pl@0 {
	#address-cells = <2>;
	#size-cells = <2>;
	compatible = "simple-bus";
	ranges;

	irq: irq@0{
			compatible = "hello,irq";
			interrupt-parent = <&gic>;
			interrupts = <0 91 4>;
	};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

3.2 编写驱动

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/of.h>
#include <linux/delay.h>
 
#include <linux/dma-mapping.h>
 
#include <linux/pm.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/gfp.h>
#include <linux/mm.h>
#include <linux/dma-buf.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/dmaengine.h>
#include <linux/completion.h>
#include <linux/wait.h>
#include <linux/init.h>
 
#include <linux/sched.h>
#include <linux/pagemap.h>
#include <linux/errno.h>	/* error codes */
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/vmalloc.h>
 
#include <linux/moduleparam.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h>
#include <linux/notifier.h>
#include <linux/init.h>
#include <linux/pci.h>
 
#include <linux/time.h>
#include <linux/timer.h> 
//
static char 			devname[16];
static int 				major;
static int             	mijor;
static struct class*	cls;
static void __iomem*	base_address;	
static resource_size_t  remap_size;  
static int	            irq;
static struct device*	dev;           

#define DEVICE_NAME "irq_drv"
static volatile int irq_is_open = 0;
static struct fasync_struct *irq_async;
 
static int irq_drv_open(struct inode *Inode, struct file *File)
{
	irq_is_open = 1;
	return 0;
} 
 
int irq_drv_release (struct inode *inode, struct file *file)
{
	irq_is_open = 0;
	return 0;
}
 
static ssize_t irq_drv_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
	return 0;
}
 
static ssize_t irq_drv_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
	return 0;
}
 
static int irq_drv_fasync (int fd, struct file *filp, int on)
{
	return fasync_helper (fd, filp, on, &irq_async);
} 
 
static struct file_operations irq_fops = {	
	.owner  		= THIS_MODULE,
	.open 			= irq_drv_open,
	.read 			= irq_drv_read, 
	.write 			= irq_drv_write,
	.fasync		 	= irq_drv_fasync,
	.release		= irq_drv_release,
};
 
static irqreturn_t irq_interrupt(int irq, void *dev_id)
{
	printk("irq = %d\n", irq);
	if(irq_is_open)
	{
		kill_fasync (&irq_async, SIGIO, POLL_IN);
	}
	return IRQ_HANDLED;
}
 
static int irq_probe(struct platform_device *pdev)
{
	int					err;
	struct device *tmp_dev;
	memset(devname,0,16);
	strcpy(devname, DEVICE_NAME);	
	major = register_chrdev(0, devname, &irq_fops); 
	cls = class_create(THIS_MODULE, devname);
	mijor = 1;
	tmp_dev = device_create(cls, &pdev->dev, MKDEV(major, mijor), NULL, devname);
	if (IS_ERR(tmp_dev)) {
		class_destroy(cls);
		unregister_chrdev(major, devname);
		return 0;
	}
	
	
	irq = platform_get_irq(pdev,0);
	if (irq <= 0)
		return -ENXIO; 
	dev = &pdev->dev;
 
	err = request_threaded_irq(irq, NULL,
				irq_interrupt,
				IRQF_TRIGGER_RISING | IRQF_ONESHOT,
				devname, NULL);				   
	if (err) {
		printk(KERN_ALERT "irq_probe irq	error=%d\n", err);
		goto fail;
	}
	else
	{
		printk("irq = %d\n", irq);
		printk("devname = %s\n", devname);
	}
	//保存dev
	//platform_set_drvdata(pdev, &xxx);	
 	return 0; 
fail:	
	free_irq(irq, NULL); 
	device_destroy(cls, MKDEV(major, mijor));	
	class_destroy(cls);
	unregister_chrdev(major, devname);
	return -ENOMEM; 
}
 
static int irq_remove(struct platform_device *pdev)
{
	device_destroy(cls, MKDEV(major, mijor));	
	class_destroy(cls);
	unregister_chrdev(major, devname);
	
	free_irq(irq, NULL);
	printk("irq = %d\n", irq);
	return 0;
}
 
static int irq_suspend(struct device *dev)
{
	return 0;
}
 
static int irq_resume(struct device *dev)
{
	return 0;
}
 
static const struct dev_pm_ops irq_pm_ops = {
	.suspend = irq_suspend,
	.resume  = irq_resume,
};
 
//MODULE_DEVICE_TABLE(platform, irq_driver_ids);
 
static const struct of_device_id irq_of_match[] = {
	{.compatible = "hello,irq" },
	{ }
};
MODULE_DEVICE_TABLE(of, irq_of_match);
 
 
static struct platform_driver irq_driver = {
	.probe = irq_probe,
	.remove	= irq_remove,
	.driver = {
		.owner   		= THIS_MODULE,
		.name	 		= "irq@0",
		.pm    			= &irq_pm_ops,
		.of_match_table	= irq_of_match,		
	},
};

module_platform_driver(irq_driver);
MODULE_LICENSE("GPL v2");
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196

Makefile

obj-m := irqdrv.o

SRC := $(shell pwd)

all:
	$(MAKE) -C $(KERNEL_SRC) M=$(SRC)

modules_install:
	$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install

clean:
	rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
	rm -f Module.markers Module.symvers modules.order
	rm -rf .tmp_versions Modules.symvers
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

以上代码目录:
petalinux_proj/vpx2.9/vpx/project-spec/meta-user/recipes-modules/irqdrv/files
插入模块:
insmod irq_drv.ko
BRAM 测试代码:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include<stdio.h>
#include<sys/mman.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include <semaphore.h>
#include <sys/time.h>
#include<pthread.h>

#define BRAM_CTRL_0	0xa0000000	    //AXI_bram_ctrl_0的物理地址
#define DATA_LEN		64			//写入和读取的数据长度
#define BRAM_LENGTH		1024*4
int c;
int fd;
char *uiod;
unsigned i = 0;
unsigned icount;
int irq_on = 1;
int err;
unsigned int * map_base0;
int fd_bram;
int ret;
void *thread_result;
pthread_t new_thread;
unsigned long addr;
unsigned int content;
pthread_t rx_thread;
pthread_t tx_thread;

int fd;
int axi_int_cnt = 0; 
int axi_int_cnt_pre = 0; 
unsigned int bram_buf[BRAM_LENGTH];
unsigned int bram_intr_cnt=0;
int start_time,end_time;
struct timeval start_tv,end_tv;
int debug_flag=1;

void my_signal_fun(int signum)
{
	++axi_int_cnt;
}

void sendthread(void *arg)
{
	int i=0;
	unsigned int *p_rxbuf = (int *)arg;
	char rx_buf[BRAM_LENGTH*4] = {0};
	unsigned int rx2_buf[BRAM_LENGTH] = {0};
	int length=map_base0[1]&0xffff;
	
	memcpy(rx2_buf,p_rxbuf,length);	
	for (i= 0; i < length; i++){
		if((i%10==0)&&(i>0))
		{
			sprintf(rx_buf+strlen(rx_buf)," %c\n",'|'); 
		}
		sprintf(rx_buf+strlen(rx_buf),"%08X ",rx2_buf[i]);
	}
	printf("bram_intr_cnt:%d\n%s\n\n",++bram_intr_cnt,rx_buf);		
}

void recvthread()
{
	int i;
	int bram_intr_cnt=0;
	//printf("axi_int_cnt:%d,axi_int_cnt_pre:%d---\n",axi_int_cnt,axi_int_cnt_pre);
	while(1)
	{
		if(axi_int_cnt > axi_int_cnt_pre)
		{
			int len=map_base0[1]&0xffff;
			//printf("axi_int_cnt:%d,axi_int_cnt_pre:%d\n",axi_int_cnt,axi_int_cnt_pre);	
			axi_int_cnt_pre = axi_int_cnt;
			bram_intr_cnt++;
			if(bram_intr_cnt==1)
			{
				gettimeofday(&start_tv, NULL);
				start_time=start_tv.tv_sec * 1000 + start_tv.tv_usec / 1000;
				printf("start_millisecond: %ld,start_time:%ld (ms)\n", start_tv.tv_sec * 1000 + start_tv.tv_usec / 1000,start_time); 
			}
			//bram_buf[0] = axi_int_cnt;
			memcpy(bram_buf,map_base0,len);
			if(debug_flag==1)
			{
				ret = pthread_create(&tx_thread,NULL,(void*)sendthread,bram_buf);
				if(ret!=0){
					perror("tx thread creation failed!\n");
					exit(-1);
				}
			}
			if(bram_intr_cnt==1000)
			{
				gettimeofday(&end_tv, NULL);
				end_time=end_tv.tv_sec * 1000 + end_tv.tv_usec / 1000;
				printf("start_millisecond: %ld,end_time:%ld (ms)\n", end_tv.tv_sec * 1000 + end_tv.tv_usec / 1000,end_time);
				printf("Total:%0.4f MBytes,time:%ld (ms)\n",1000*len*4.0/(1024*1024),end_time-start_time);
			}	
		}else{
			usleep(10);
		}		
	}
}

int main(int argc, char **argv)
{
	unsigned char key_val;
	int ret;
	int Oflags;
	if(argc>1)
	{
		debug_flag=atoi(argv[1]);
	}
	ret = pthread_create(&rx_thread,NULL,(void*)recvthread,NULL);
	if(ret!=0){
		perror("rx thread creation failed!\n");
		exit(-1);
	}

   fd_bram = open("/dev/mem", O_RDWR|O_SYNC);
    if (fd_bram == -1){	
		printf("can't open /dev/mem !\n");
        return (-1);
    }

	printf("/dev/mem is opened !\n");
    map_base0 = mmap(NULL, 1024 * 4, PROT_READ|PROT_WRITE, MAP_SHARED, fd_bram, BRAM_CTRL_0);
    if ((map_base0 == 0 ) ){
        printf("NULL pointer!\n");
    }
    else{
        printf("mmap successfull!\n");
    }
	signal(SIGIO, my_signal_fun);
	
	fd = open("/dev/irq_drv", O_RDWR);
	if (fd < 0)
	{
		printf("can't open!\n");
	} 
	fcntl(fd, F_SETOWN, getpid());
	
	Oflags = fcntl(fd, F_GETFL); 
	
	fcntl(fd, F_SETFL, Oflags | FASYNC);
 
	while (1)
	{
		sleep(5);	
	}	
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166

运行测试略!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/172460
推荐阅读
相关标签
  

闽ICP备14008679号