【教程】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

相关推荐
szxinmai主板定制专家16 小时前
基于 RK3588+RK1820/28 算力卡的国产工控机,适用于机器视觉,机器人等边缘算力场景
人工智能·fpga开发·zynq·控制器·mpsoc·半导体设备
unicrom_深圳市由你创科技20 小时前
硬件在环(HIL)测试在FPGA项目中为什么重要?
fpga开发
嵌入式-老费1 天前
esp32开发与应用(和高云FPGA的配合)
fpga开发
156002548401 天前
基于3U VPX总线架构的VU37P FPGA高带宽HBM缓存数据处理卡(缓存带宽480GB/s)
fpga开发·架构
szxinmai主板定制专家1 天前
基于 RK3576 的智能割草机器人解决方案,从样机到量产
人工智能·嵌入式硬件·计算机视觉·fpga开发·机器人·rk3588+fpga·割草机器人
续写烂尾2 天前
SD NAND vs SPI NAND:接口协议、坏块管理与开发成本全面对比
fpga开发
叶子野格2 天前
《Verilog学习:数字系统设计基础》
学习·fpga开发
花 满 楼2 天前
TPWM — PWM 测量模式(TIM PWM Measurement Mode)
单片机·嵌入式硬件·fpga开发
叶子野格2 天前
《Verilog学习:前置知识》
学习·fpga开发