当前位置:   article > 正文

ZYNQ-Linux下PL中断的驱动配置_zynqmp linux pl中断

zynqmp linux pl中断

说明

zynq7010 平台,PS端需要捕获PL端发送的中断,中断名称为 IRQ_F2P[15:0],该中断一共有16个,中断号分别为 61-68, 84-91。本文针对该中断在petalinux下配置设备树,开发中断驱动程序,并在应用层编写测试程序检测中断。

开发环境

  1. PC:Windows 10;
  2. 虚拟机:Ubuntu 16.04;
  3. Vivado:2018.2;
  4. PetaLinux:2018.2;
  5. 硬件环境:zynq7010;

PL部分配置

略。
可参考 https://blog.csdn.net/h244259402/article/details/83993524.

PS部分配置

关于中断号说明

1、对于SPI中断,则对应到Linux 的中断标号,为芯片datasheet的中断号 -16。
例如中断号为 30,则对应的linux 中断号为 30 -16 = 14。
2、对于非 SPI 中断,则对应的 linux 中断标号,为芯片 datasheet 的中断号 -32。
例如:IRQ_F2P中断,中断号为 61,则对应的 linux 中断号为 61 - 32 = 29。

设备树配置

devicetree是连接硬件资源和用户空间的桥梁,用户在添加配置设备树文件时尤为要注意,用户在这个文件目录下(project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi)添加。

gedit project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi
  • 1

添加irq中断

/include/ "system-conf.dtsi"
/ {
        amba_pl: amba_pl{
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "simple-bus";
                ranges;
                irq@0{
                        compatible = "hello,irq";
                        interrupt-parent = <&intc>;
                        interrupts = <0 29 2>;
                };
        };
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

修改完成,保存退出,执行petalinux-build编译工程。
编译完成后,进入到工程目录执行:

petalinux-package --prebuilt --force
petalinux-boot --qemu --prebuilt 3
  • 1
  • 2

在petalinux环境下,模拟zynq平台的启动(Boot prebuilt kernel with QEMU)。
启动成功后,

ls /proc/device-tree/amba_pl/
  • 1

可以看到设备树节点增加了irq@0。

编写驱动程序

$ cd plnx-proj-root
$ petalinux-create -t modules --name mymodule --enable
$ cd plnx-proj-root/project-spec/meta-user/recipes-modules/mymodule

修改mymodule.c的内容

#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
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208

执行petalinux-build编译工程。
把编译好的UBOOT.BIN和zynq_fsbl.elf文件烧写到目标板。
启动目标版,
在这里插入图片描述
手动导入驱动模块

insmod irq-drv.ko
  • 1

在这里插入图片描述
同时触发PL端中断,内核能打印出正确调试信息。

用户端测试程序

#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <strings.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
#include <poll.h>
#include <fcntl.h>

// 信号处理函数
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)
	{
		usleep(1000);
	}
	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

编译用户端程序,并烧写到目标版。
同时触发PL端中断,可以看到打印信息,用户端已经捕获到中断。
在这里插入图片描述

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

闽ICP备14008679号