xilinx ps-pl间的共享中断如何使用

首先环境介绍:

Zynq UltraScale+   参考文档    ug1085-zynq-ultrascale-trm.pdf

需求:使用pl提供使能中断寄存器regEn,通过控制regEN使PL端发送中断,PS接收中断并在用户态处理中断;

分析:

1、处理中断实在PS端并且在用户态;那就涉及内核通知用户的机制,只有异步通知,通过信号来做比较合理;

2、PS使用PL属于内部中断 至于有哪些中断类型参考:  ug1085-zynq-ultrascale-trm.pdf 第13节  下载地址

3、如何捕获中断;

PL端提供资料

使能寄存器: regEn 地址 base+offset  假设 = 0x80010030

使用arm的中断4,是一个持续128us左右的高电平脉冲 从图中可以看出xlconcat从0开始即arm4中断

我们拿到这个需求后首先我们可以提供一个命令行配置fpag的寄存器regEn然后让fpga访问抓取信号,或者让他们提供工程我们抓取信号;逻辑提供top2(1).ltx文件使用vivado打开

如何抓取:

ok那我们软件如何编码?

这是内部中断这个截图来自 ug1085 第13节 这表格中包含了所有中断,我们使用的是arm4 也就是121+4 =125 于是我们配置设备树

如何配置设备树: 和7000系列一样设备树和手册上的终端号差值为32,这里要注意;

        irq: irq@0{
            compatible = "test,irq";
            interrupt-parent = <&gic>;
            interrupts = <0 93 4>;
        };

#include "zynqmp-zcu102-revB.dts"

/ {
model = "ZynqMP ZCU102 Rev1.0";
	compatible = "xlnx,zynqmp-zcu102-rev1.0", "xlnx,zynqmp-zcu102", "xlnx,zynqmp";
	amba_pl: amba_pl@0 {
		#address-cells = <2>;
		#size-cells = <2>;
		compatible = "simple-bus";
		ranges ;
		
		irq: irq@0{
			compatible = "test,irq";
			interrupt-parent = <&gic>;
			interrupts = <0 93 4>;
		};
		
		axi_eth_0: ethernet@80060000 {
			axistream-connected = <&axi_eth_0_dma>;
			axistream-control-connected = <&axi_eth_0_dma>;
			clock-frequency = <100000000>;
			clock-names = "s_axi_lite_clk", "axis_clk", "ref_clk";
			clocks = <&clk 71>, <&clk 71>;
			compatible = "xlnx,axi-ethernet-7.1", "xlnx,axi-ethernet-1.00.a";
			device_type = "network";
			interrupt-names = "interrupt";
			interrupt-parent = <&gic>;
			interrupts = <0 91 4>;
			local-mac-address = [00 0a 35 00 00 00];
            xlnx,eth-hasnobuf = <1>;
            xlnx,eth-iscm = <1>;
            fixed-link = <1 1 1000 0 0>;
			phy-mode = "sgmii";
			reg = <0x0 0x80060000 0x0 0x1000>;
            xlnx,rxcsum = <0x0>; 
            xlnx,txcsum = <0x0>; 

		};
		axi_eth_0_dma: dma@80050000 {
			#dma-cells = <1>;
			clock-names = "s_axi_lite_aclk", "m_axi_sg_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk";
			clocks = <&clk 71>, <&clk 71>, <&clk 71>, <&clk 71>;
			compatible = "xlnx,eth-dma";
			interrupt-names = "mm2s_introut", "s2mm_introut";
			interrupt-parent = <&gic>;
			interrupts = <0 91 4 0 92 4>;
			reg = <0x0 0x80050000 0x0 0x1000>;
			xlnx,include-dre ;
		};
	};
};

还需要注意的是出发方式: 表格中提到的是上升沿和高电平触发有效;也需要注意

驱动代码:注册一个平台设备,获取中断号,之后注册字符设备异步打开 头文件占用空间删除了;


static int 				major;
static int             	mijor;
static struct class*	cls;
static int	            irq;
static struct device*	dev;           

static struct fasync_struct *irq_async;
 
static int irq_drv_open(struct inode *Inode, struct file *File)
{
	printk("irq_drv_open is open \n");
	return 0;
} 
 
int irq_drv_release (struct inode *inode, struct file *file)
{
	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)
{
	//发送信号SIGIO信号给fasync_struct 结构体所描述的PID,
	//触发应用程序的SIGIO信号处理函数。用户空间的信号处理函数执行完还会再回到内核态。
	return fasync_helper (fd, filp, on, &irq_async);
} 
 
static struct file_operations irq_fops = {	
	.owner  		= THIS_MODULE,  /* 这是一个宏,推向编译模块时自动创建的__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 no open flag \n", irq);
	kill_fasync (&irq_async, SIGIO, POLL_IN);
	return IRQ_HANDLED;
}
 
static int irq_probe(struct platform_device *pdev)
{
	int					err;
	struct device *irq_dev;

	major = register_chrdev(0, DEVICE_NAME, &irq_fops); 
	cls = class_create(THIS_MODULE, DEVICE_NAME);
	mijor = 1;
	irq_dev = device_create(cls, &pdev->dev, MKDEV(major, mijor), NULL, DEVICE_NAME);
	if (IS_ERR(irq_dev)) {
		class_destroy(cls);
		unregister_chrdev(major, DEVICE_NAME);
		return 0;
	}
	
	//从设备树获取终端号
	irq = platform_get_irq(pdev,0);
	if (irq <= 0)
		return -ENXIO; 
	dev = &pdev->dev;
    printk("irq = %d will be registed \n", irq);	
	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;
	}
		
	
 	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);
	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,
};
 
 //匹配设备树
static const struct of_device_id irq_of_match[] = {
	{.compatible = "rtwp,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");

应用程序: 本以为signal_fun通过fcntl(fd, F_SETFL, Oflags | FASYNC); 已经向内核注册了,那就应该由内核来确定什么时候调用,与设备无关了,那么执行close(fd);就好了

但本人实测 如果将设备句柄关闭但是本应用程序不关闭保持睡眠的话,signal_fun 还是不会相应中断;必须保持fd的应用数量大于0;

int g_endflag = 0;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void signal_fun(int signum)
{
	printf("enter signal_fun \r\n");
	
	pthread_mutex_lock(&mutex);		
	g_endflag = 1;
	pthread_mutex_unlock(&mutex);	
	printf("rtwPval :%f  end\r\n", rtwPVal);
}
BSP_INT32 BSP_InitRtwp(BSP_VOID)
{
	int fd = 0;
	int Oflags;
	g_endflag = 0;
	signal(SIGIO, signal_fun);
	fd = open("/dev/irq_drv", O_RDWR);
	if (fd < 0)
	{
		printf("can't open!\n");
		return BSP_ERROR;
	}
	fcntl(fd, F_SETOWN, getpid());
	Oflags = fcntl(fd, F_GETFL); 
	fcntl(fd, F_SETFL, Oflags | FASYNC);

    while(!g_endflag)
    {
		sleep(1);
    }
	close(fd);
	return BSP_SUCCESS;
}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值