1.内核驱动中,驱动注册,阻塞IO,gpio子系统,中断处理的整体结合示例

这篇具有很好参考价值的文章主要介绍了1.内核驱动中,驱动注册,阻塞IO,gpio子系统,中断处理的整体结合示例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一,功能实现要求

/*功能实现 在stm32开发板上实现功能

           1.使用阻塞IO读取number变量的值,当number的值改变时打印number的值

           2.注册KEY1按键的驱动和LED1的驱动以及对应的设备文件,

           3.按键和指示灯设备信息放在同一个设备树的节点中

           4.当KEY1按下时LED1灯的状态取反,number的值取反,number值为0或1

           */

二,示例图

1.内核驱动中,驱动注册,阻塞IO,gpio子系统,中断处理的整体结合示例,驱动,驱动开发

 三,驱动注册(无实际功能)

        1.主要实现手动注册驱动,并自动提交目录以及myled1和mykey1两个设备文件

int request_dev(void)
{
    int i;
    // 1.实例化字符设备驱动对象
    cdev = cdev_alloc();
    if (cdev == NULL)
    {
        ret = -ENOMEM;
        goto OUT1;
    }
    // 2.部分初始化字符设备驱动对象
    cdev_init(cdev, &fops);
    // 3.申请设备号
    if (my_major == 0) // 动态申请设备号
    {
        ret = alloc_chrdev_region(&devno, my_minor, 3, "mycdev"); // 成功返回0,失败返回错误码
        if (ret)
        {
            printk("动态申请设备号失败\n");
            goto OUT2;
        }
        printk("动态申请设备号成功\n");
        my_major = MAJOR(devno); // 获取主设备号
        my_minor = MINOR(devno); // 获取次设备号
    }
    else // 静态制定设备号
    {
        // 通过自定义主设备号和次设备号获取设备号
        devno = MKDEV(my_major, 0);
        ret = register_chrdev_region(devno, 3, "mycdev"); // 成功申请设备号返回0,失败返回错误码
        if (ret)
        {
            printk("静态申请设备号失败\n");
            goto OUT2;
        }
        printk("静态申请设备号成功\n");
    }
    // 4.将字符设备驱动对象注册进内核
    ret = cdev_add(cdev, devno, 3);
    if (ret)
    {
        printk("字符设备驱动注册进内核失败\n");
        goto OUT3;
    }
    printk("字符设备驱动注册进内核成功\n");
    // 5.自动创建设备节点
    // 向上提交目录
    cls = class_create(THIS_MODULE, "mycdev");
    if (IS_ERR(cls)) // 为真表示cls指向4K的预留空间
    {
        printk("向上提交目录失败\n");
        ret = -PTR_ERR(cls);
        goto OUT4;
    }
    printk("向上提交目录成功\n");
    // 自动创建设备文件LED1
    dev = device_create(cls, NULL, MKDEV(my_major, 0), NULL, "myled1");
    if (IS_ERR(dev))
    {
        printk("自动创建设备文件myled1失败\n");
        ret = PTR_ERR(dev);
        goto OUT5;
    }
    printk("自动创建设备文件myled1成功\n");

    // 自动创建设备文件KEY1
    dev = device_create(cls, NULL, MKDEV(my_major, 1), NULL, "mykey1");
    if (IS_ERR(dev))
    {
        printk("自动创建设备文件mykey1失败\n");
        ret = PTR_ERR(dev);
        goto OUT5;
    }
    printk("自动创建设备文件mykey1成功\n");
    return 0;
OUT5:
    // 释放提交成功的设备节点信息
    for (--i; i >= 0; i--)
    {
        device_destroy(cls, MKDEV(my_major, i));
    }
    // 销毁目录
    class_destroy(cls);
OUT4:
    cdev_del(cdev);
OUT3:
    unregister_chrdev_region(devno, 3);
OUT2:
    kfree(cdev);
OUT1:
    return ret;
}

 四,LED1灯的初始化

        采用从自定义的设备树节点中获取LED1的GPIO对象信息,为LED1灯各个寄存器使能。只需手动调用电平改变函数gpiod-set-value即可实现灯的亮灭.

int request_LED(void)
{
    // 1.解析设备树节点信息通过名字
    dnode = of_find_node_by_name(NULL, "numbers");
    if (dnode == NULL)
    {
        printk("设备树节点解析失败\n");
        return -ENOMEM;
    }
    printk("设备树节点解析成功\n");

    // 2.通过节点信息获取GPIO对象
    // 2.1申请LED1对应资源
    gpiono_led1 = gpiod_get_from_of_node(dnode, "led1", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(gpiono_led1))
    {
        printk("LED1资源申请失败\n");
        return -PTR_ERR(gpiono_led1);
    }
    printk("LED1资源申请成功\n");
    return 0;
}

5.按键中断的初始化

        也是根据自己定义的设备树节点中获取信息,申请对应的软中断号,然后根据获取到的软终断号初始化中断号,从而实现中断发生回调中断处理函数处理中断时间。

int request_interrupts(void)
{
    // 准备:在设备树中添加gpiof组控制按键的节点信息
    // 1.在设备数中寻找到对应设备树节点的信息 of_find_node_by_name
    dnode = of_find_node_by_name(NULL, "numbers");
    if (dnode == NULL)
    {
        printk("节点信息获取失败\n");
        return -ENXIO;
    }
    printk("节点信息获取成功\n");
    // 2.根据节点地址寻找key对应的软中断号 irq_of_parse_and_map
    // 获取KEY按键对应的软中断号 参2的索引的值在于你的自定义节点GPIO控制所在位置,
    // myirq{
    //     interrupts-extended=<&gpiof 9 0>,<&gpiof 7 0>,<&gpiof8 0>;
    // };KEDY1对应<&gpiof 9 0>索引为0,KEY2对应<&gpiof 7 0>,索引为1,类似数组依次对应

    myirq_key[0] = irq_of_parse_and_map(dnode, 0);
    if (!myirq_key[0])
    {
        printk("key1软中断号获取失败\n");
        return ENOMEM;
    }
    printk("key1软中断号获取成功\n");

    // 3.注册中断号 包括对应的软中断号,中断执行的处理函数,中断的检测方式,中断名
    // 注册KEY对应的软中断号
    // 参1:中断号对应的软中断号 参2:中断的处理函数 参3:中断触发的方式 参4:为中断起一个名字 参5:给中断函数传递的值

    // KEY1
    ret = request_irq(myirq_key[0], myirq_handler, IRQF_TRIGGER_FALLING, irq_key1_name, 0);
    if (ret < 0)
    {
        printk("key1中断注册失败\n");
        return ret;
    }
    printk("key1中断注册成功\n");
    return 0;
}

6.阻塞IO

        当中断没有发生时,函数一直处于等待状态,当中断发生,标志位的值改变,从而使函数往下运行,改变number内核变量的值

int my_wait(void)
{
    // 判断condition的值,为1则改变number的值
    wait_event_interruptible(wq_head, condition);
    if (number==1)
    {
        number = 0;
    }
    else if(number==0)
    {
        number = 1;
    }
    condition = 0;
    return 0;
}

7.按键中断处理函数

        根据LED1现在的状态改变,更改标志位并唤醒睡眠中的进程。实现功能的要求。文章来源地址https://www.toymoban.com/news/detail-551486.html

// 中断处理函数
irqreturn_t myirq_handler(int irqno, void *dev_id)
{
    printk("软中断号%d的处理\n", irqno);
    // 改变LED灯的状态
    gpiod_set_value(gpiono_led1, !gpiod_get_value(gpiono_led1));
    // 改变number的值
    //  改变标志
    condition = 1;
    // 唤醒可中断进程
    wake_up_interruptible(&wq_head);
    return IRQ_HANDLED;
}

到了这里,关于1.内核驱动中,驱动注册,阻塞IO,gpio子系统,中断处理的整体结合示例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux驱动开发之【pinctrl和gpio子系统】

    目录 一、 pinctrl和gpio子系统 1.pinctrl子系统 1.1 pinctrl子系统简介 1.2 pinctrl子系统驱动 1.3 设备树中添加pinctrl节点模版 2. gpio子系统 2.1 gpio子系统简介 2.2 gpio子系统驱动 2.3 gpio子系统API函数 2.4 设备树中添加gpio节点模板 2.5 与gpio相关的OF函数 3. 驱动程序编写 3.1 驱动入口函数 3

    2024年02月06日
    浏览(33)
  • 【Linux驱动开发】012 gpio子系统API函数

    设置好设备树以后, 在驱动程序中就可以使用 gpio 子系统提供的 API 函数来操作指定的 GPIO, gpio 子系统向驱动开发人员屏蔽了具体的读写寄存器过程。这就是驱动分层与分离的好处,大家各司其职,做好自己的本职工作即可。 gpio 子系统提供的常用的 API 函数有下面几个:

    2023年04月18日
    浏览(35)
  • <Linux开发>驱动开发 -之-基于pinctrl/gpio子系统的beep驱动

    <Linux开发>驱动开发 -之-基于pinctrl/gpio子系统的beep驱动 交叉编译环境搭建: <Linux开发> linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下: <Linux开发> -之-系统移植 uboot移植过程详细记录(第一部分) <Linux开发> -之-系统移植 uboot移植过程详细记录(第二部分

    2024年02月13日
    浏览(28)
  • RK3568驱动指南|第十二篇 GPIO子系统-第128章 GPIO入门实验

    瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网

    2024年01月21日
    浏览(28)
  • 【IMX6ULL驱动开发学习】14.Linux驱动开发 - GPIO中断(设备树 + GPIO子系统)

    代码自取 【14.key_tree_pinctrl_gpios_interrupt】: https://gitee.com/chenshao777/imx6-ull_-drivers 主要接口函数: 1. of_gpio_count (获得GPIO的数量) 2. kzalloc (向内核申请空间) 3. of_get_gpio (获取GPIO子系统标号) 4. gpio_to_irq (根据GPIO子系统标号得到软件中断号) 5. request_irq (根据软件中断号

    2024年02月12日
    浏览(35)
  • 【嵌入式Linux内核驱动】SPI子系统 | 硬件原理 | 应用编程 | 内核驱动 | 总体框架

    1.1 SPI通信协议 SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线 四根通信线:SCK(Serial Clock)、MOSI(Master Output Slave Input)、MISO(Master Input Slave Output)、SS(Slave Select) 同步,全双工 支持总线挂载多设备(一主多从) 1.2 硬件连接 多NSS独立片选方式 菊花

    2024年02月16日
    浏览(48)
  • 【嵌入式Linux内核驱动】05_IIC子系统 | 硬件原理与常见面试问题 | 应用编程 | 内核驱动 | 总体框架

    1.1 IIC 基础 IIC协议简介—学习笔记_iic标准协议_越吃越胖的黄的博客-CSDN博客 I2C(Inter-Integrated Circuit)是一种串行通信协议,用于连接微控制器、传感器、存储器和其他外设。 I2C使用两条线(SDA和SCL)进行通信,可以连接多个设备,每个设备都有一个唯一的地址。I2C总线上的

    2024年02月09日
    浏览(35)
  • 【IMX6ULL驱动开发学习】08.IMX6ULL通过GPIO子系统函数点亮LED

    通过GPIO子系统函数点亮LED 1、GPIO子系统函数 1.1 确定 led 的GPIO标号,查看内核中的gpiochip 查看 gpiochip ,以正点原子的IMX6ULL阿尔法开发板为例 查看原理图,发现led接的引脚是 GPIO1_IO3,对应 /sys/kernel/debug/gpio 中的 gpiochip0 组,gpiochip0 组从0开始算起, 所以 GPIO1_IO3 对应的标号就

    2024年02月10日
    浏览(62)
  • Linux Mii management/mdio子系统分析之三 mii_bus注册、注销及其驱动开发流程

    (转载)原文链接:https://blog.csdn.net/u014044624/article/details/123303174       本篇是mii management/mdio模块分析的第三篇文章,本章我们主要介绍mii-bus的注册与注销接口。在前面的介绍中也已经说过,我们可以将mii-bus理解为mdio总线的控制器的抽象,就像spi-master、i2c-adapter一样。 本

    2024年01月16日
    浏览(33)
  • 9.GPIO子系统

    目录 GPIO1节点 内核设备树新增rgb_led节点(使用gpio子系统) 常用的对外接口 头文件 of_find_node_by_path()函数 of_get_named_gpio()函数 gpio_request()函数 gpio_free()函数 gpio_direction_output()函数 gpio_direction_input()函数 gpio_get_value()函数 gpio_set_value()函数 GPIO子系统实验:IO引脚高低电平控制 修

    2024年02月11日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包