【教程】Agilex 5 SOC FPGA的HPS端如何响应FPGA端中断(四)——设计中断驱动程序

驱动程序采用Linux平台总线(Platform Bus)模型,通过 platform_driver 结构体注册驱动,利用设备树实现设备和驱动的自动匹配。驱动同时注册了一个混杂设备(miscdevice),主设备号为10,为用户空间提供 /dev/pio_button 设备节点。

这个驱动我们不采用编译进内核的方式,而是当作一个可以动态加载的模块。这个驱动模块由源文件和makefile组成。

驱动源文件pio_interrupt.c:

复制代码
//platform driver#include <linux/module.h>#include <linux/types.h>#include <linux/miscdevice.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/platform_device.h>#include <linux/interrupt.h>#include <linux/clk.h>#include <linux/uaccess.h>#include <linux/io.h>#include <linux/poll.h>#include <linux/irq.h>#include <asm/unistd.h>#include <linux/device.h>#include <linux/of.h>#include <linux/slab.h>#include <linux/sched.h>

// define the interrupt registers,  refer to embedded ip user guide for infomation#define  PIO_REGISTER_INTERRUPTMSK 2#define  PIO_REGISTER_EDGECAPTUE   3
struct irq_des{    int  button_irq;    void __iomem *pio_base;};

static volatile int key_values;static volatile int ev_press = 0;
//define the wait quene headstatic DECLARE_WAIT_QUEUE_HEAD(button_waitq);

struct irq_des pio_irq;


static irqreturn_t buttons_interrupt(int irq, void *dev_id){    if(irq ==pio_irq.button_irq){        key_values = readl(pio_irq.pio_base+PIO_REGISTER_EDGECAPTUE*4);        ev_press = 1;        wake_up_interruptible(&button_waitq);        }    //clear all  edge caputre registers    writel(0x0f,pio_irq.pio_base+PIO_REGISTER_EDGECAPTUE*4);     return IRQ_RETVAL(IRQ_HANDLED);}

static int pio_buttons_open(struct inode *inode, struct file *file){    int err = 0;     err = request_irq(pio_irq.button_irq, buttons_interrupt, 0,                           "PIO_BUTTON", NULL);    if (err) {        disable_irq(pio_irq.button_irq);        free_irq(pio_irq.button_irq, NULL);        return -EBUSY;    }      ev_press = 0;    //enable pio interrupt     writel(0x0f,pio_irq.pio_base+PIO_REGISTER_INTERRUPTMSK*4);     return 0;}

static int pio_buttons_close(struct inode *inode, struct file *file){
    free_irq(pio_irq.button_irq, NULL);        return 0;}

static ssize_t pio_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp){    unsigned long err;    wait_event_interruptible(button_waitq, ev_press);    ev_press = 0;
    err = copy_to_user(buff, (const void *)&key_values, min(sizeof(key_values), count));
    return err ? -EFAULT : (ssize_t)min(sizeof(key_values), count);}
static unsigned int pio_buttons_poll( struct file *file, struct poll_table_struct *wait){    unsigned int mask = 0;    poll_wait(file, &button_waitq, wait);    if (ev_press)        mask |= POLLIN | POLLRDNORM;    return mask;}

static struct file_operations dev_fops = {    .owner   =   THIS_MODULE,    .open    =   pio_buttons_open,    .release =   pio_buttons_close,     .read    =   pio_buttons_read,    .poll    =   pio_buttons_poll,};
static struct miscdevice misc = {    .minor = MISC_DYNAMIC_MINOR,    .name = "pio_button",    .fops = &dev_fops,};
static int my_plat_probe(struct platform_device *pdev){    int ret;    struct resource *res;    int  irq;    int  error;    res = platform_get_resource(pdev,IORESOURCE_MEM,0);    if(res == NULL)        return -ENOENT;        if(!request_mem_region(res->start,resource_size(res),pdev->name)){            error=-EBUSY;            return error;    }    pio_irq.pio_base=ioremap(res->start,resource_size(res));    irq=platform_get_irq(pdev,0);    if(irq<0)    {        return irq;    }    pio_irq.button_irq=irq;    ret = misc_register(&misc);    if(ret)        return ret;
    return 0;}
static void my_plat_remove(struct platform_device *pdev){    struct resource *res;    printk("my platfrom device has removed.\n");    res=platform_get_resource(pdev,IORESOURCE_MEM,0);    release_mem_region(res->start,resource_size(res));    misc_deregister(&misc);    //return 0;}
static struct of_device_id pio_button_match[]={    {.compatible="terasic,pio-button",.data=NULL},    {}};MODULE_DEVICE_TABLE(of,pio_button_match);
struct platform_driver my_buttons_drv = {     .probe = my_plat_probe,    .remove = my_plat_remove,    .driver = {         .owner = THIS_MODULE,        .name = "my_buttons",        .of_match_table=pio_button_match,    },};
static int __init platform_drv_init(void){    int ret;
    ret = platform_driver_register(&my_buttons_drv);
    return ret;}
static void __exit platform_drv_exit(void){    platform_driver_unregister(&my_buttons_drv);}
module_init(platform_drv_init);module_exit(platform_drv_exit);
MODULE_AUTHOR("Terasic");MODULE_LICENSE("GPL");

注意上面Makefile文件当中 KDIR := /home/doreen/de25_nan0_sdmmc/linux-socfpga 是指定Linux Kernel 源码路径,读者要改成自己当前开发路径。

设置好编译链环境变量,执行make编译出pio_interrupt.ko文件:

复制代码
export CROSS_COMPILE=aarch64-linux-gnu-
export ARCH=arm64
export PATH=/usr/bin:$PATH  
make

本文源码参考:

GitHub - hbwangjinwu/PIO_Interrupt: A example implement a custom driver for a button pio interrupt driver and test application on DE1_SoC Board · GitHub

往期阅读:

【教程】Agilex 5 SOC FPGA的HPS端如何响应FPGA端中断(一)------GIC控制器介绍

【教程】Agilex 5 SOC FPGA的HPS端如何响应FPGA端中断(二)------修改Quartus工程(GHRD工程)

【教程】Agilex 5 SOC FPGA的HPS端如何响应FPGA端中断(三)------设备树Overlay

相关推荐
LabVIEW开发1 天前
LabVIEW FPGA 编程:少编译几次的办法(系列 04/05)
fpga开发·labview
cmc10281 天前
318.关于在ip内部封装PLL,MMCM的注意事项
fpga开发
LabVIEW开发1 天前
LabVIEW CompactRIO 编程模式怎么选(系列 02/05)
fpga开发·labview
FPGA小迷弟2 天前
FPGA 与千兆以太网校验和:从原理到 Verilog 实现
嵌入式硬件·fpga开发·无人机·ai编程·fpga
码农小韩3 天前
FPGA学习(二)——LED闪烁
fpga开发·verilog·fpga·led·组合逻辑·分频设计
9527华安3 天前
FPGA纯verilog实现DP视频接口,支持2K60帧分辨率,提供3套工程源码和技术支持
fpga开发·音视频·dp
ChaseVLSI4 天前
FPGA与ASIC的区别详解:内部结构、开发成本与适用场景,项目选型到底该选哪个
嵌入式硬件·fpga开发·硬件架构·硬件工程
9527华安5 天前
FPGA实现ARINC818总线协议,基于GT Transceivers Wizard高速收发器,提供7套工程源码和技术支持
fpga开发·transceivers·arinc818
小蘇的FPGA5 天前
fpga-wide-data-crc32
fpga开发
落雨无风5 天前
fpga板级调试常见问题
fpga开发