zynq pl配置linux中断

zynq pl配置linux中断

一、zynq工程如图所示

下图所示为zynq的pl工程图,请注意途中画蓝色框内,在图一左侧的蓝色框内,请在vivado约束条件中设置irq[0:0]与板子上的按键连接具体约束条件见。在右侧蓝框内的xlconcat_0中,由于In0[0:0]连接别的设备,In1[0:0]连接外部按键,故In0[0:0]的中断号为61,In1[0:0]的中断号为62。图二是将中断连接到zynq的IRQ_F2P[1:0]中。
图一:
在这里插入图片描述
图二:
zynq pl配置linux中断_第1张图片

二、zynq中断号的由来

  1. Zynq的中断类型有:
    软件中断(Software Generated Interrupt, SGI,中断号0-15)(16–26 reserved)
    私有外设中断(Private Peripheral Interrupt, PPI,中断号27-31),
    共享外设中断(Shared Peripheral Interrupt, SPI,中断号32-95).
  2. 私有外设中断(PPI):每个CPU都有一组PPI,包括全局定时器、私有看门狗定时器、私有定时器和来自PL的FIQ/IRQ.
  3. 软件中断(SGI)被路由到一个或者两个CPU上,通过写ICDSGIR寄存器产生SGI.
  4. 共享外设中断(SPI)由PS和PL上的各种I/O控制器和存储器控制器产生,这些中断信号被路由的CPU.
  5. 通用中断控制器(GIC)是核心资源,用于集中管理从PS和PL产生的中断信号的资源集合。控制器可以使能、关使能、屏蔽中断源和改变中断源的优先级,并且会将中断送到对应的CPU中,CPU通过私有总线访问这些寄存器。
  6. 中断控制器(ICC,Interrupt Controller CPU)和中断控制器分配器(ICD, Interrupt Controller Distributor)是GIC寄存器子集。
  7. (外部)中断请求(IRQ)、快速中断请求(FIQ)。
  8. a、对于非 SPI中断,则对应到Linux 的中断标号,为芯片datasheet的中断号 -16。
    例如中断号为 30,则对应的linux 中断号为 30 -16 = 14。
    b、对于SPI 中断,则对应的 linux 中断标号,为芯片 datasheet 的中断号 -32。
    例如:IRQ_F2P中断,中断号为 61,则对应的 linux 中断号为 61 - 32 = 29。
  9. 总上所述,下图为u585-zynq的数据手册中截取的部分内容,详细信息请参考该数据手册,该表画黄色的区域标识pl的中断号。由于In0[0:0]在前,In1[0:0]在后,分配中断号的时候,In0[0:0]会被先分配,故之前提到的In0[0:0]为61,In1[0:0]为62。
    zynq pl配置linux中断_第2张图片

三、vivado中约束条件

zynq pl配置linux中断_第3张图片zynq pl配置linux中断_第4张图片

四、设备树内增加如下内容

zynq pl配置linux中断_第5张图片
其中interrupts = <0 32 2>;内的0代表的是SPI中断,32对应的中断号,2代表中断触发方式为下降沿触发。触发方式一共有4中,分别是上升沿触发(1),下降沿触发(2),高电平触发(4),低电平触发(8)。
zynq pl配置linux中断_第6张图片

五、驱动代码

// An highlighted block
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
#include 
 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
#include 
#include 
#include 	/* error codes */
#include 
#include 
#include 
 
#include 
#include 
#include 
#include 
#include 
#include 
 
#include 
#include 
 
//
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,		
	},
};

六、应用代码

// An highlighted block
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

// 信号处理函数
void my_signal_fun(int signum)
{
	printf("sigal number = %d\n", signum);
}

int main(int argc, char *argv[])
{
	unsigned char key_val;
	int ret;
	int Oflags;

	// 在应用程序中捕捉SIGIO信号(由驱动程序发送)
	signal(SIGIO, my_signal_fun);
	int fd = open("/dev/irq_drv", O_RDWR);
	if (fd < 0)
	{
		printf(">>can't open file!\n");
	}
	fcntl(fd, F_SETOWN, getpid());
	Oflags = fcntl(fd, F_GETFL); 
	fcntl(fd, F_SETFL, Oflags | FASYNC);
	while (1)
	{
		sleep(1000);
	}
	return 0;
}

七、后面讲介绍基于AXI_GPIO的pl中断

axi_gpio我已经学习了一段时间,由于对FPGA不是特别熟悉,所以走了一些弯路,后面写一些经验体会吧,希望能给大家有所帮助。

你可能感兴趣的:(zynq-pl)