赞
踩
zynq7010 平台,PS端需要捕获PL端发送的中断,中断名称为 IRQ_F2P[15:0],该中断一共有16个,中断号分别为 61-68, 84-91。本文针对该中断在petalinux下配置设备树,开发中断驱动程序,并在应用层编写测试程序检测中断。
略。
可参考 https://blog.csdn.net/h244259402/article/details/83993524.
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
添加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>;
};
};
};
修改完成,保存退出,执行petalinux-build编译工程。
编译完成后,进入到工程目录执行:
petalinux-package --prebuilt --force
petalinux-boot --qemu --prebuilt 3
在petalinux环境下,模拟zynq平台的启动(Boot prebuilt kernel with QEMU)。
启动成功后,
ls /proc/device-tree/amba_pl/
可以看到设备树节点增加了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");
执行petalinux-build编译工程。
把编译好的UBOOT.BIN和zynq_fsbl.elf文件烧写到目标板。
启动目标版,
手动导入驱动模块
insmod irq-drv.ko
同时触发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; }
编译用户端程序,并烧写到目标版。
同时触发PL端中断,可以看到打印信息,用户端已经捕获到中断。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。