LINUX驱动之——GPIO的基本驱动

这篇具有很好参考价值的文章主要介绍了LINUX驱动之——GPIO的基本驱动。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

楼主在网上找了很多相关LINUX驱动开发的相关例程。发现基本的驱动开发都是有框架或者多种开发手段的,我们可以使用不同的开发方式来降低开发难度。有文件系统的开发和LINUX系统自带的内核函数来开发。这两者有什么区别呢?就像是单片机的库函数开发和寄存器开发一样。

先让我们来看一下GPIO子系统在linux内核中的结构吧。该文件目录在/sys/class/gpio/下。

struct gpio_chip {
  const char *label;
  struct device *dev;
  struct module *owner;
  int (*request)(struct gpio_chip *chip, unsigned offset);
  void (*free)(struct gpio_chip *chip, unsigned offset);
  int (*get_direction)(struct gpio_chip *chip, unsigned offset);
  int (*direction_input)(struct gpio_chip *chip, unsigned offset);
  int (*direction_output)(struct gpio_chip *chip, unsigned offset,
  int value);
  int (*get)(struct gpio_chip *chip,unsigned offset);
  void (*set)(struct gpio_chip *chip, unsigned offset, int value);
  void (*set_multiple)(struct gpio_chip *chip, unsigned long *mask,
  unsigned long *bits);
  int (*set_debounce)(struct gpio_chip *chip, unsigned offset,
  unsigned debounce);
  int (*to_irq)(struct gpio_chip *chip, unsigned offset);
  int base;
  u16 ngpio;
  const char *const *names;
  bool can_sleep;
  bool irq_not_threaded;
  bool exported;
#ifdef CONFIG_GPIOLIB_IRQCHIP
  /*
   * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip
   * inside the gpiolib to handle IRQs for most practical cases.
   */
  struct irq_chip *irqchip;
  struct irq_domain *irqdomain;
  unsigned int irq_base;
  irq_flow_handler_t irq_handler;
  unsigned int irq_default_type;
#endif
#if defined(CONFIG_OF_GPIO)
  /*
   * If CONFIG_OF is enabled, then all GPIO controllers described in the
    * device tree automatically may have an OF translation
   */
  struct device_node *of_node;
  int of_gpio_n_cells;
  int (*of_xlate)(struct gpio_chip *gc,
  const struct of_phandle_args *gpiospec, u32 *flags);
};

以下几个是主要的注意事项:

  • request 是特定芯片激活的可选回调函数。如果提供了,在调用gpio_request()或gpiod_get()时,它会在分配GPIO之前执行。

  • free 是一个可选的回调函数,用于特定芯片的释放。如果提供了,那么在调用gpiod_put()或gpio_free()时,它会在GPIO被释放之前执行。

  • get_direction 在您需要知道方向的时候执行GPIO偏移量。返回值应为0表示out, 1表示in(与GPIOF_DIR_XXX相同),或负错误。

  • direction_input 将信号偏移量offset配置为输入,否则返回错误。

  • get 返回GPIO offset 的值;对于输出信号,这将返回实际感知到的值或0。

  • set 指定一个输出值给GPIO offset。


有些的芯片运行的Linux系统里面自带了引脚的编号,如果要获取编号可能要在该芯片文档中用公式计算。以Orange-pi为例它的计算公式如图所示:

LINUX驱动之——GPIO的基本驱动

利用SYSFS设置GPIO

当然,我们也能查看已经被占用的GPIO端口。

cat /sys/kernel/debug/gpio
LINUX驱动之——GPIO的基本驱动

例如第一行的意思是编号为8的GPIO的名字是goodix-int,现在是输入模式并且是高电平。已经被占用的GPIO无法使用,除非修改其寄存器。


让我们来尝试的用命令行初始化一个GPIO吧。

echo 10 > export #添加一个GPIO并且设置编号
LINUX驱动之——GPIO的基本驱动

然后我们进入GPIO10的direction 查看其电平状态。

LINUX驱动之——GPIO的基本驱动
echo out > direction #改变为输出模式
LINUX驱动之——GPIO的基本驱动

同理可用次办法尝试设置LED的参数,现在如下图我的电位是低电平所以我的LED灯已经亮起。

LINUX驱动之——GPIO的基本驱动

现在再次查看设备,GPIO10已被添加并且被设置。

LINUX驱动之——GPIO的基本驱动

当然我们也能用代码来实现上面的操作,这里举个例子,在我更后面的博客里面我会详细说明。Linux一切皆文件!! 这使得一切都变得非常好理解。

int gpio_set_dir(unsigned int gpio, unsigned int out_flag)
{
    int fd, len;
    char buf[MAX_BUF];
 
    len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR  "/gpio%d/direction", gpio);
 
    fd = open(buf, O_WRONLY);
    if (fd < 0) {
        perror("gpio/direction");
        return fd;
    }
 
    if (out_flag)
        write(fd, "out", 4);
    else
        write(fd, "in", 3);
 
    close(fd);
    return 0;
}

例如上面就是设置一个IO输入输出的函数。也是打开文件系统然后往里面写参数就可以了。相信大家学过linux文件系统的都会很简单的理解。


方法2:用linux内核函数来初始化GPIO

话不多说,上框架。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
static int led_init(void)//驱动函数入口
{
}
static void led_exit(void)//驱动函数出口
{
}
module_init(led_init);//注册入口
module_exit(led_exit);//注册出口
MODULE_LICENSE("GPL");//模块的许可证声明这个一般都要有这句话,具体可以去百度

然后丰富函数内容。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <mach/platform.h> //PAD_GPIO_C

static int led_init(void)
{
    gpio_request(10,"myled");
    gpio_direction_output(10, 0);
    printk("led init...\n");
    return 0;
}
static void led_exit(void)
{
    gpio_set_value(10, 1);
    gpio_free(10);
    printk("led exit...\n");
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

这样,一个GPIO的LED驱动就完成啦。下面我将再次说明以下与GPIO相关的简单驱动内核函数。

  • fint gpio_request(unsigned gpio, const char *label)

函数功能:CPU的任何一个GPIO引脚硬件资源对于Linux内核来说都是一种宝贵的资源,如果某个内核程序要想访问这个GPIO引脚资源,首先必须想Linux内核申请资源(类似malloc)

  • void gpio_free(unsigned gpio)

函数功能:内核程序如果不再使用访问GPIO硬件资源记得要将硬件资源归还给linux内核,类似free

  • int gpio_direction_output(unsigned gpio, int value)

函数功能:配置GPIO引脚为输出功能,并且输出一个value值(1高电平/0低电平)

  • int gpio_direction_input(unsigned gpio)

函数功能:配置GPIO为输入功能

  • int gpio_set_value(unsigned gpio, int value)

函数功能:设置GPIO引脚的输出值为value(1:高/0:低),前提是必须首先将GPIO配置为输出功能

  • int gpio_get_value(unsigned gpio)

函数功能:获取GPIO引脚的电平状态,返回值就是引脚的电平状态(返回1:高电平;返回0:低电平),此引脚到底是输入还是输出没关系!


设备树

Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离。在设备树出现以前,所有关于设备的具体信息都要写在驱动里,一旦外围设备变化,驱动代码就要重写。引入了设备树之后,驱动代码只负责处理驱动的逻辑,而关于设备的具体信息存放到设备树文件中,这样,如果只是硬件接口信息的变化而没有驱动逻辑的变化,驱动开发者只需要修改设备树文件信息,不需要改写驱动代码。设备树源文件扩展名为.dts(device tree source),一般放置/arch/arm/boot/dts/目录内。设备树信息在根文件系统中/proc/device-tree目录下,包括根节点’/’的所有属性和子节点。

LINUX驱动之——GPIO的基本驱动

设备树的格式如下(例子):

    gpios {
        compatible = "gpio-user";                                                                                                                                                                                   
        status = "okay";
        /*input*/
        gpio0 {
            label = "in0";
            gpios = <&gpio1 1 0>;
            default-direction = "in";
         };
        ... ...
         /*output*/
         gpio17 {
            label = "out1";
            gpios = <&gpio3 3 0>;
            default-direction = "out";
        };
    };

为啥有时候要修改设备树呢?因为有时候你不想重新改动驱动代码,或者其他不需要的设备占用了你的IO,你想把它ban掉。有时候开发会涉及到设备树的修改,这里我引用一个大佬写的比较详细的博客:设备树的使用和说明 - 知乎 (zhihu.com)。(如有侵权亲联系我我会立刻删掉)


我们在编译这些文件的时候一般的会用makefile编译。不会写makefile的小伙伴可以去学CMake,足以应付一些不太复杂的文件编译。在这里我也推荐一篇大佬写的不错的博客:https://blog.csdn.net/weixin_44498318/article/details/106219135。(如有侵权亲联系我我会立刻删掉)文章来源地址https://www.toymoban.com/news/detail-453970.html

到了这里,关于LINUX驱动之——GPIO的基本驱动的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • Linux驱动开发:gpio子系统

    目录 1、GPIO配置流程 2、GPIO子系统API 2.1 of_find_node_by_path 2.2 of_get_named_gpio 2.3 gpio_request 与 gpiod_get 与 gpiod_get_index 2.4 gpio_direction_input 与 gpiod_direction_input 2.5 gpio_direction_output 与 gpiod_direction_output 2.6 gpio_get_value 与 gpiod_get_value 2.7 gpio_set_value 与 gpiod_set_value 2.8  gpiod_get_from

    2024年02月12日
    浏览(49)
  • 【Linux驱动开发】011 gpio子系统

    前面我们编写了基于设备树的 LED 驱动,但是驱动的本质还是没变,都是配置 LED 灯所使用的 GPIO 寄存器,驱动开发方式和裸机基本没啥区别。本章我们就来学习一下如何借助 pinctrl 和 gpio 子系统来简化 GPIO 驱动开发。   Linux 内核针对 PIN 的配置推出了 pinctrl 子系统,对于

    2024年02月03日
    浏览(49)
  • linux驱动_leds-gpio

    项目里面有几个通信通道,每个通道有个状态指示灯(LED)。预期断开是灭,已连接是亮,数据传输时闪烁。一开始使用通用sysfs文件系统控制GPIO的方式控制,例如用以下脚本控制GPIO: 在应用软件实现点灯逻辑,控制亮和灭都没问题,但是闪烁功能的实时性太差,只能考虑别的

    2024年02月11日
    浏览(41)
  • 【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日
    浏览(50)
  • <Linux开发>驱动开发 -之-基于pinctrl/gpio子系统的beep驱动

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

    2024年02月13日
    浏览(41)
  • 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日
    浏览(45)
  • 【Linux驱动开发】012 gpio子系统API函数

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

    2023年04月18日
    浏览(43)
  • 【IMX6ULL驱动开发学习】09.Linux驱动之GPIO中断(附SR501人体红外感应驱动代码)

    Linux驱动的GPIO中断编程主要有以下几个步骤: 1、 通过GPIO号获取 软件中断号 (中断编程不需要设置GPIO输入输出,当然申请GPIO,设置输入也没问题) 参数 含义 gpio GPIO引脚编号 2、 注册 中断处理函数 ,设置中断 触发方式 (上升沿、下降沿等) 参数 含义 irq 软件中断号(通过

    2024年02月11日
    浏览(54)
  • 为什么MD5算法不可逆,但网上有很多网站声称能够解密MD5

    我们要明白,MD5不是加密算法,而是一种信息摘要算法,主要用于保证数据的完整性,以及数据不被篡改。既然不是加密算法,那么就不存在解密的说法,但是为什么网上有很多网站声称能够解密MD5呢? MD5算法不可逆 Md5是计算机安全领取常用的一种密码散列函数,主要用于

    2024年02月11日
    浏览(56)
  • 【嵌入式Linux内核驱动】04_Jetson nano GPIO应用 | 驱动开发 | 官方gpiolib、设备树与chip_driver

    0.暴露给应用层 应用 解决调试目录为空的问题 调试信息 1.最简读写文件(在/SYS下) 设备树 验证测试 编译文件 驱动 of_get_named_gpio_flags //获取设备树节点的属性 gpio_is_valid //判断是否合法 devm_gpio_request //申请使用gpio,并调用设置pinctrl device_create_file //根据设备树节点属性,创建

    2024年02月07日
    浏览(61)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包