STM32MP157驱动开发——按键驱动(中断)

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

编写使用中断的按键驱动程序

  • 对于使用中断的按键驱动,内核自带的驱动程序 drivers/input/keyboard/gpio_keys.c 就可以,需要做的只是修改设备树指定引脚及键值

  • 中断是引入其他基础知识的前提:休眠-唤醒、POLL 机制、异步通知、定时器、中断的线程化处理都离不开中断

编程思路

设备树相关

查看原理图确定按键使用的引脚,再在设备树中添加节点,在节点里指定中断信息

例子:

gpio_keys_first {
	compatible = "first_key,gpio_key";
	gpios = <&gpio5 1 GPIO_ACTIVE_HIGH
			&gpio4 14 GPIO_ACTIVE_HIGH>;
	pinctrl-names = "default";
	pinctrl-0 = <&key1_pinctrl
				&key2_pinctrl>;
};

注意:在设备树里面可以不用设置中断,因为Linux 系统中异常与中断里面提到对于 GPIO,可以在驱动程序里面使用 gpio_to_irq 或 gpiod_to_irq 获得中断号

驱动代码相关

  • 首先要获得中断号
  • 然后编写中断处理函数;
  • 最后 request_irq。

代码

修改设备树文件

STM32MP157驱动开发——按键驱动(中断),stm32,驱动开发,单片机
对于一个引脚要用作中断时,

  • a) 要通过 PinCtrl 把它设置为 GPIO 功能;【ST 公司对于 STM32MP157 系列芯片,GPIO 为默认模式 不需要再进行配置Pinctrl 信息】
  • b) 表明自身:是哪一个 GPIO 模块里的哪一个引脚【修改设备树】

打开内核的设备树文件:arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dts

gpio_keys_first {
	compatible = "first_key,gpio_key";
	gpios = <&gpiog 3 GPIO_ACTIVE_LOW
			&gpiog 2 GPIO_ACTIVE_LOW>;
};

与此同时,需要把用到引脚的节点禁用

注意,如果其他设备树文件也用到该节点,需要设置属性为disabled状态,在arch/arm/boot/dts目录下执行如下指令查找哪些设备树用到该节点

grep "&gpiog" * -nr

如果用到该节点,需要添加属性去屏蔽:

status = "disabled"; 

STM32MP157驱动开发——按键驱动(中断),stm32,驱动开发,单片机

gpio_key_drv.c

#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>


struct gpio_key{
	int gpio;
	struct gpio_desc *gpiod;
	int flag;
	int irq;
} ;

static struct gpio_key *gpio_keys_first;

//中断处理函数,参数是request_irq函数参数的最后一个
static irqreturn_t gpio_key_isr(int irq, void *dev_id)
{
	struct gpio_key *gpio_key = dev_id;//获取的是引脚的电平,因为设置了上升沿和下降沿都触发
	int val;
	val = gpiod_get_value(gpio_key->gpiod);
	
	printk("key %d %d\n", gpio_key->gpio, val);
	
	return IRQ_HANDLED;
}

/* 1. 从platform_device获得GPIO
 * 2. gpio=>irq
 * 3. request_irq
 */
static int gpio_key_probe(struct platform_device *pdev)
{
	int err;
	struct device_node *node = pdev->dev.of_node;//platform_device 里面有device结构体
	int count;
	int i;
	enum of_gpio_flags flag;
	unsigned flags = GPIOF_IN;
		
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	count = of_gpio_count(node);
	if (!count)
	{
		printk("%s %s line %d, there isn't any gpio available\n", __FILE__, __FUNCTION__, __LINE__);
		return -1;
	}

	gpio_keys_first = kzalloc(sizeof(struct gpio_key) * count, GFP_KERNEL);
	for (i = 0; i < count; i++)
	{
		gpio_keys_first[i].gpio = of_get_gpio_flags(node, i, &flag);
		if (gpio_keys_first[i].gpio < 0)
		{
			printk("%s %s line %d, of_get_gpio_flags fail\n", __FILE__, __FUNCTION__, __LINE__);
			return -1;
		}
		gpio_keys_first[i].gpiod = gpio_to_desc(gpio_keys_first[i].gpio);
		gpio_keys_first[i].flag = flag & OF_GPIO_ACTIVE_LOW;
		//如果设备树里面是低电平有效,则flags或上GPIO子系统里面的低电平有效的宏定义(注意有F)
		if (flag & OF_GPIO_ACTIVE_LOW)
			flags |= GPIOF_ACTIVE_LOW;
		//读出引脚的逻辑值
		err = devm_gpio_request_one(&pdev->dev, gpio_keys_first[i].gpio, flags, NULL);

		
		gpio_keys_first[i].irq  = gpio_to_irq(gpio_keys_first[i].gpio);//从 GPIO 获得中断号,该中断号是使用request_irq的参数之一
	}

	for (i = 0; i < count; i++)
	{
		err = request_irq(gpio_keys_first[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "my_gpio_key", &gpio_keys_first[i]);
	}
        
    return 0;
    
}

static int gpio_key_remove(struct platform_device *pdev)
{
	//int err;
	struct device_node *node = pdev->dev.of_node;
	int count;
	int i;

	count = of_gpio_count(node);
	for (i = 0; i < count; i++)
	{
		free_irq(gpio_keys_first[i].irq, &gpio_keys_first[i]);
	}
	kfree(gpio_keys_first);
    return 0;
}


static const struct of_device_id my_keys[] = {
    { .compatible = "first_key,gpio_key" },
    { },
};

/* 1. 定义platform_driver */
static struct platform_driver gpio_keys_driver = {
    .probe      = gpio_key_probe,
    .remove     = gpio_key_remove,
    .driver     = {
        .name   = "my_gpio_key",
        .of_match_table = my_keys,
    },
};

/* 2. 在入口函数注册platform_driver */
static int __init gpio_key_init(void)
{
    int err;
    
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	
    err = platform_driver_register(&gpio_keys_driver); 
	
	return err;
}

/* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
 *     卸载platform_driver
 */
static void __exit gpio_key_exit(void)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

    platform_driver_unregister(&gpio_keys_driver);
}


/* 7. 其他完善:提供设备信息,自动创建设备节点                                     */

module_init(gpio_key_init);
module_exit(gpio_key_exit);

MODULE_LICENSE("GPL");



Makefile

# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
# 2.1 ARCH,          比如: export ARCH=arm64
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
# 2.3 PATH,          比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin 
# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,
#       请参考各开发板的高级用户使用手册

KERN_DIR =  /home/book/100ask_stm32mp157_pro-sdk/Linux-5.4

all:
	make -C $(KERN_DIR) M=`pwd` modules 

clean:
	make -C $(KERN_DIR) M=`pwd` modules clean
	rm -rf modules.order

# 参考内核源码drivers/char/ipmi/Makefile
# 要想把a.c, b.c编译成ab.ko, 可以这样指定:
# ab-y := a.o b.o
# obj-m += ab.o



obj-m += gpio_key_drv.o


编译测试

首先要设置 ARCH、CROSS_COMPILE、PATH 这三个环境变量后,进入 ubuntu 上板子内核源码的目录,在Linux内核源码根目录下,执行如下命令即可编译 dtb 文件:

make dtbs V=1

编译好的文件在路径由DTC指定,移植设备树到开发板的共享文件夹中,先保存源文件,然后覆盖源文件,重启后会挂载新的设备树,进入该目录查看是否有新添加的设备节点

cd /sys/firmware/devicetree/base 

编译驱动程序,在Makefile文件目录下执行make指令,此时,目录下有编译好的内核模块gpio_key_drv.ko移植到开发板上

确定一下烧录系统:cat /proc/mounts,查看boot分区挂载的位置,将其重新挂载在boot分区:mount /dev/mmcblk2p2 /boot,然后将共享文件夹里面的设备树文件拷贝到boot目录下,这样的话设备树文件就在boot目录下

cp /mnt/stm32mp157c-100ask-512d-lcd-v1.dtb /boot

重启后挂载,运行文章来源地址https://www.toymoban.com/news/detail-610622.html

insmod gpio_key_drv.ko // 装载驱动程序

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

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

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

相关文章

  • STM32MP157驱动开发——按键驱动(POLL 机制)

    使用休眠-唤醒的方式等待某个事件发生时,有一个缺点:等待的时间可能很久。我们可以加上一个超时时间,这时就可以使用 poll 机制。 ① APP 不知道驱动程序中是否有数据,可以先调用 poll 函数查询一下,poll 函数可以传入超时时间; ② APP 进入内核态, 调用到驱动程序的

    2024年02月15日
    浏览(37)
  • STM32MP157驱动开发——按键驱动(线程化处理)

    工作队列是在内核的线程的上下文中执行的 工作队列中有多个 work,前一个 work 没处理完会影响后面的 work。解决方法有如下2种: 比如自己创建一个内核线程,不跟别的 work 在一块。例如存储设备比如 SD/TF采用的就是单独一个线程。 使用线程化的中断处理。中断的处理仍然

    2024年02月16日
    浏览(42)
  • STM32MP157驱动开发——按键驱动(定时器)

    定时器涉及函数参考内核源码:includelinuxtimer.h 给定时器的各个参数赋值: 设置定时器 :主要是初始化 timer_list 结构体,设置其中的函数、参数。 a) 向内核添加定时器。timer-expires 表示超时时间。 b) 当超时时间到达,内核就会调用这个函数:timer-function(timer-data)。 修改定时

    2024年02月15日
    浏览(52)
  • ARM开发,stm32mp157a-A7核中断实验(实现按键中断功能)

    ---key.h头文件--- ---key.c函数实现--- ---do_irq.c终端处理函数--- ---main.c测试文件---

    2024年02月11日
    浏览(42)
  • STM32MP157驱动开发——LED驱动(原始架构)

    LED 的驱动方式,常见的有四种。 ① 使用引脚输出 3.3V 点亮 LED,输出 0V 熄灭 LED。 ② 使用引脚拉低到 0V 点亮 LED,输出 3.3V 熄灭 LED。 ③ 使用引脚输出 1.2V 点亮 LED,输出 0V 熄灭 LED。 ④ 使用引脚输出 0V 点亮 LED,输出 1.2V 熄灭 LED。 有的芯片为了省电等原因,其引脚驱动能力

    2024年02月03日
    浏览(38)
  • STM32MP157驱动开发——USB设备驱动

    参考文章:【正点原子】I.MX6U嵌入式Linux驱动开发——Linux USB驱动   由于 USB 协议太过庞大和复杂,所以本节只对 STM32MP157 自带的 USB 驱动进行使能和测试。详细的 USB 接口和协议的介绍,可以参考原子哥的资料《USB2.0 协议中文版.pdf》和《USB3.0 协议中文版.pdf》。   USB 全

    2023年04月14日
    浏览(53)
  • STM32MP157驱动开发——Linux LCD驱动(上)

      LCD 是很常用的一个外设,通过 LCD 可以显示图片、界面UI等,提高人机交互的效率。STM32MP1 提供了一个 LTDC 接口用于连接 RGB 接口的液晶屏。本节就来学习如何使用这个接口。   LCD 全称是 Liquid Crystal Display,也就是液晶显示器,是现在最常用到的显示器。网上对于 LCD

    2024年02月08日
    浏览(42)
  • 驱动开发,stm32mp157a开发板的led灯控制实验

            编写LED灯的驱动,在应用程序中编写控制LED灯亮灭的代码逻辑实现LED灯功能的控制; LED1-PE10 LED1亮灭: RCC寄存器[4]-1 0X50000A28 GPIOE_MODER[21:20]-01 (输出) 0X50006000 GPIOE_ODR[10]-1(输出高电平) 0(输出低电平)0X50006014 LED2-PF10 LED2亮灭: RCC寄存器[5]-1 0X50000A28 GPIOE_MODER[21:20]

    2024年02月09日
    浏览(43)
  • LED驱动(原始架构)——STM32MP157

    LED 的驱动方式,常见的有四种。 ① 使用引脚输出 3.3V 点亮 LED,输出 0V 熄灭 LED。 ② 使用引脚拉低到 0V 点亮 LED,输出 3.3V 熄灭 LED。 ③ 使用引脚输出 1.2V 点亮 LED,输出 0V 熄灭 LED。 ④ 使用引脚输出 0V 点亮 LED,输出 1.2V 熄灭 LED。 有的芯片为了省电等原因,其引脚驱动能力

    2024年02月16日
    浏览(42)
  • STM32 Linux开发板丨STM32MP157开发板资料手册+实战教程+视频教程

    iTOP-STM32MP157开发板是基于意法半导体STARM双Cortex-A7核加单Cortex-M4核的一款多核异构处理器。Cortex-A7内核提供对开源操作系统Linux的支持,借助Linux系统庞大而丰富的软件组件处理复杂应用。M4内核上运行对于实时性要求严格的应用。 开发板既有A7核,又有M4核,从学习者角度来看

    2024年02月12日
    浏览(38)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包