18_ZYNQ7020开发板_外部中断操作

linux中断框架
三步走,申请中断、实现中断、使能中断
一、中断的申请和释放函数
中断申请函数request_irq
函数原型:

Int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char
*name, void *dev);

irq:申请的中断号,是中断的唯一标识,是内核找到对应中断的服务依据
handler:中断服务函数,中断触发后会执行的函数
flags:中断标志,用于设置中断的触发方式
中断常有的标识:
在这里插入图片描述
name:中断名称,申请中断成功后会在/proc/interrupts文件中找到这个名字
返回值:0-申请成功,其它标识申请失败
二、中断释放函数free_irq
函数在释放后,会禁止中断并删除中断服务函数

void free_irq(unsigned int irq, void *dev);

irq:需要释放的中断

三、实现服务的申请函数

irqreturn_t (*irq_handler_t) (int, void *)

第一个参数int型中断函数对应的中断号
第二个参数是通用指针,需要和request_irq函数的参数dev一致
四、中断使能和禁止
1)enable_irq(unsigned int irq)、disable_irq(unsigned int irq)呾 disable_irq_nosync(unsigned
int irq)
enable_irq 呾 disable_irq分别是中断使能和禁止函数,irq是目标中断号。
2)local_irq_enable()呾 local_irq_disable()
local_irq_enable()函数是用于使能当前处理器的中断系统
local_irq_disable()函数用于禁止当前处理器的中断系统。
四、原理图
在这里插入图片描述
在这里插入图片描述
五、设备树

/include/ "system-conf.dtsi"
/ {
    model = "Zynq ALINX Development Board";
    compatible = "alinx,zynq", "xlnx,zynq-7000";

    aliases {
        ethernet0 = "&gem0";
        serial0 = "&uart1";
    };

    usb_phy0: usb_phy@0 {
        compatible = "ulpi-phy";
        #phy-cells = <0>;
        reg = <0xe0002000 0x1000>;
        view-port = <0x0170>;
        drv-vbus;
    };
    
    amba {
        slcr@f8000000 {
            pinctrl@700 {
                pinctrl_led_default: led-default {  
                    mux {  
                        groups = "gpio0_0_grp";  
                        function = "gpio0";  
                    };  

                    conf {  
                        pins = "MIO0"; 
                        io-standard = <1>; 
                        bias-disable;  
                        slew-rate = <0>;  
                    };      
                }; 
                pinctrl_key_default: key-default {
                    mux {
                        groups = "gpio0_50_grp";
                        function = "gpio0";
                    };

                    conf {
                        pins = "MIO50";
                        io-standard = <1>;
                        bias-high-impedance;
                        slew-rate = <0>;
                    };
                };
            };
        };
    };

    alinxled {
        compatible = "alinx-led";
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_led_default>;
        alinxled-gpios = <&gpio0 0 0>;
    };

    alinxkey {
        compatible = "alinx-key";
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_key_default>;
        alinxkey-gpios = <&gpio0 50 0>;
    };
};

&i2c0 {
    clock-frequency = <100000>;
};

&usb0 {
    dr_mode = "host";
    usb-phy = <&usb_phy0>;
};

&sdhci0 {
    u-boot,dm-pre-reloc;
};

&uart1 {
    u-boot,dm-pre-reloc;
};

&flash0 {
    compatible = "micron,m25p80", "w25q256", "spi-flash";
};

&gem0 {
    phy-handle = <&ethernet_phy>;
    ethernet_phy: ethernet-phy@1 {
        reg = <1>;
        device_type = "ethernet-phy";
    };
};

&amba_pl {
    hdmi_encoder_0:hdmi_encoder {
        compatible = "digilent,drm-encoder";
        digilent,edid-i2c = <&i2c0>;
    };

    xilinx_drm {
        compatible = "xlnx,drm";
        xlnx,vtc = <&v_tc_0>;
        xlnx,connector-type = "HDMIA";
        xlnx,encoder-slave = <&hdmi_encoder_0>;
        clocks = <&axi_dynclk_0>;
        dglnt,edid-i2c = <&i2c0>;
        planes {
            xlnx,pixel-format = "rgb888";
            plane0 {
                dmas = <&axi_vdma_0 0>;
                dma-names = "dma";
            };
        };
    };
};

&axi_dynclk_0 {
    compatible = "digilent,axi-dynclk";
    #clock-cells = <0>;
    clocks = <&clkc 15>;
};

&v_tc_0 {
    compatible = "xlnx,v-tc-5.01.a";
};

六、驱动代码

#include <linux/module.h>  
#include <linux/kernel.h>  
#include <linux/fs.h>  
#include <linux/init.h>  
#include <linux/ide.h>  
#include <linux/types.h>  
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <asm/uaccess.h>
#include <asm/mach/map.h>
#include <asm/io.h>
  
/* 设备节点名称 */  
#define DEVICE_NAME       "timer_led"
/* 设备号个数 */  
#define DEVID_COUNT       1
/* 驱动个数 */  
#define DRIVE_COUNT       1
/* 主设备号 */
#define MAJOR_U
/* 次设备号 */
#define MINOR_U           0

  
/* 把驱动代码中会用到的数据打包进设备结构体 */
struct alinx_char_dev{
    dev_t              devid;             //设备号
    struct cdev        cdev;              //字符设备
    struct class       *class;            //类
    struct device      *device;           //设备
    struct device_node *nd;               //设备树的设备节点
    int                alinx_led_gpio;    //gpio号
    char               led_status;        //gpio状态
    unsigned int       time_count;        //定时器时间
    struct timer_list  timer;             //定时器
};
/* 声明设备结构体 */
static struct alinx_char_dev alinx_char = {
    .cdev = {
        .owner = THIS_MODULE,
    },
};

void timer_function(unsigned long data)
{    
    /* 反转led状态 */
    alinx_char.led_status = !alinx_char.led_status;
    /* 设置led */
    gpio_set_value(alinx_char.alinx_led_gpio, alinx_char.led_status);
    /* 重新开始计时 */
    mod_timer(&alinx_char.timer, jiffies + msecs_to_jiffies(alinx_char.time_count));
}

/* open函数实现, 对应到Linux系统调用函数的open函数 */  
static int timer_led_open(struct inode *inode_p, struct file *file_p)  
{  
    printk("gpio_test module open\n");  
    return 0;  
}  
  
  
/* write函数实现, 对应到Linux系统调用函数的write函数 */  
static ssize_t timer_led_write(struct file *file_p, const char __user *buf, size_t len, loff_t *loff_t_p)  
{  
    int retvalue;
    /* 获取用户数据 */
    retvalue = copy_from_user(&alinx_char.time_count, buf, len); 
    /* 设置好timer后先点亮led */
    alinx_char.led_status = 1;
    gpio_set_value(alinx_char.alinx_led_gpio, alinx_char.led_status);
    /* 开启timer */
    mod_timer(&alinx_char.timer, jiffies + msecs_to_jiffies(alinx_char.time_count));
    
    return 0;  
}  
  
/* release函数实现, 对应到Linux系统调用函数的close函数 */  
static int timer_led_release(struct inode *inode_p, struct file *file_p)  
{  
    printk("gpio_test module release\n");  
    /* 删除定时器 */
    del_timer_sync(&alinx_char.timer);
    return 0;  
}  
      
/* file_operations结构体声明, 是上面open、write实现函数与系统调用函数对应的关键 */  
static struct file_operations ax_char_fops = {  
    .owner   = THIS_MODULE,  
    .open    = timer_led_open,  
    .write   = timer_led_write,     
    .release = timer_led_release,   
};  
  
/* 模块加载时会调用的函数 */  
static int __init timer_led_init(void)  
{
    /* 用于接受返回值 */
    u32 ret = 0;
    
    /* 获取led设备节点 */
    alinx_char.nd = of_find_node_by_path("/alinxled");
    if(alinx_char.nd == NULL)
    {
        printk("alinx_char node not find\r\n");
        return -EINVAL;
    }
    else
    {
        printk("alinx_char node find\r\n");
    }
    
    /* 获取节点中gpio标号 */
    alinx_char.alinx_led_gpio = of_get_named_gpio(alinx_char.nd, "alinxled-gpios", 0);
    if(alinx_char.alinx_led_gpio < 0)
    {
        printk("can not get alinxled-gpios");
        return -EINVAL;
    }
    printk("alinxled-gpio num = %d\r\n", alinx_char.alinx_led_gpio);
    
    /* 申请gpio标号对应的引脚 */
    ret = gpio_request(alinx_char.alinx_led_gpio, "alinxled");
    if(ret != 0)
    {
        printk("can not request gpio\r\n");
    }
    
    /* 把这个io设置为输出 */
    ret = gpio_direction_output(alinx_char.alinx_led_gpio, 1);
    if(ret < 0)
    {
        printk("can not set gpio\r\n");
    }
    
    /* 注册设备号 */
    alloc_chrdev_region(&alinx_char.devid, MINOR_U, DEVID_COUNT, DEVICE_NAME);
    
    /* 初始化字符设备结构体 */
    cdev_init(&alinx_char.cdev, &ax_char_fops);
    
    /* 注册字符设备 */
    cdev_add(&alinx_char.cdev, alinx_char.devid, DRIVE_COUNT);
    
    /* 创建类 */
    alinx_char.class = class_create(THIS_MODULE, DEVICE_NAME);
    if(IS_ERR(alinx_char.class)) 
    {
        return PTR_ERR(alinx_char.class);
    }
    
    /* 创建设备节点 */
    alinx_char.device = device_create(alinx_char.class, NULL, 
                                      alinx_char.devid, NULL, 
                                      DEVICE_NAME);
    if (IS_ERR(alinx_char.device)) 
    {
        return PTR_ERR(alinx_char.device);
    }

    /* 设置定时器回掉函数  */
    alinx_char.timer.function = timer_function;    
    /* 初始化定时器 */
    init_timer(&alinx_char.timer);
    return 0;  
}

/* 卸载模块 */  
static void __exit timer_led_exit(void)  
{  
    /* 释放gpio */
    gpio_free(alinx_char.alinx_led_gpio);

    /* 注销字符设备 */
    cdev_del(&alinx_char.cdev);
    
    /* 注销设备号 */
    unregister_chrdev_region(alinx_char.devid, DEVID_COUNT);
    
    /* 删除设备节点 */
    device_destroy(alinx_char.class, alinx_char.devid);
    
    /* 删除类 */
    class_destroy(alinx_char.class);
       
    printk("timer_led_dev_exit_ok\n");  
}  
  
/* 标记加载、卸载函数 */  
module_init(timer_led_init);  
module_exit(timer_led_exit);  
  
/* 驱动描述信息 */  
MODULE_AUTHOR("Alinx");  
MODULE_ALIAS("gpio_led");  
MODULE_DESCRIPTION("TIMER LED driver");  
MODULE_VERSION("v1.0");  
MODULE_LICENSE("GPL");  

七、执行结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值