赞
踩
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 个是快速中断。
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数据。
$ 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
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>; };
interrupts=<0x0 91 0x4>含义:
91代表了中断号,这个中断号是系统硬件中断号减去32得到.
0x4代表中断类型:
0x1:上升沿触发。
0x2:下降触发
0x4: 高电平沿触发
0x8: 低电平触发
zynq zynqMP 不支持低电平和下降沿触发中断(未求证)。实测最好设置为上升沿触发。
ZynqMP和Zynq的一个区别需要注意,ZynqMP的interrupt-parent指向的是&gic,而Zynq指向了&intc。
可以参考pl.dtsi文件。
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中断。
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>;
};
#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");
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
以上代码目录:
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; }
运行测试略!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。