fmql之Linux中断

中断

下半部机制

软中断

softirq_action

tasklet

工作队列

设备树

fmql:

代码

目的

使能key对应GPIO的中断,中断服务函数为使用定时器延时15ms;定时器处理函数为检测key的状态

设备树修改

fmql不用把system.dtb放到SD卡。修改设备树后要在FMQL-Linux-SDK-project-20230801文件夹下,重新编译。生成image.ub和uboot.elf,然后FSBL.out和user.bit 、uboot.elf生成BOOT.bin。把BOOT.bin和image.ub放到SD卡下即可。

irq.c

/*		device-tree :
 * key {
 * 		compatible = "alientek,key";
 * 		status = "okay";
 * 		key-gpio = <&gpio0 12 GPIO_ACTIVE_LOW>;
 * 
 * 		interrupt-parent=<&gpio0>;
 * 		interrupts=<12 IRQ_TYPE_EDGE_BOTH>;			// GPIO0_12
 * };
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/cdev.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/of_address.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/kern_levels.h>
// #include <linux/semaphore.h>
#include <linux/of_irq.h>            // add
#include <linux/irq.h>               // add

#define KEY_COUNT 		1
#define KEY_NAME		"key"

/* 定义key状态 */
enum key_status {
	KEY_PRESS	= 0,	// 按键按下
	KEY_RELEASE	,		// 按键松开
	KEY_KEEP	,		// 按键状态保持
};

struct key_dev {
	dev_t	devid;				// 设备号
	struct	cdev	cdev;		// cdev
	struct	class	*class;		// class
	struct	device	*device;	// devie
	// int		major;				// major
	// int		minor;				// minor
	// struct	device_node	*nd;	// device_node
	int		key_gpio;			// key_gpio
	int		irq_num;				// 中断号
	// int			period;				/* period (ms) */
	struct		timer_list	timer;	/* timer */
	spinlock_t	spinlock;			/* spinlock */
};

static struct key_dev key;
static int status = KEY_KEEP;

static int key_open(struct inode * inode, struct file *filp){
	return 0;
}

static ssize_t key_read(struct file *filp, char __user *buf,
			size_t cnt, loff_t *offt){
	unsigned long flags;
	int ret;

	spin_lock_irqsave(&key.spinlock, flags);

	ret = copy_to_user(buf, &status, sizeof(int));	// key_status --> APP

	status = KEY_KEEP;		// reset key_status

	spin_unlock_irqrestore(&key.spinlock, flags);

	return ret;
}

static ssize_t key_write(struct file *filp, const char __user *buf,
		size_t cnt, loff_t *offt){
	return 0;
}

static int key_release(struct inode * inode, struct file *filp){
	return 0;
}

static void key_timer_function(struct timer_list * unused){
	static int last_val = 1;
	unsigned long flags;
	int current_val;

	spin_lock_irqsave(&key.spinlock, flags);

	current_val = gpio_get_value(key.key_gpio);	// 0: press; 1: release
	if(current_val == 0 && last_val)
		status = KEY_PRESS;
	else if(current_val == 1 && !last_val)
		status = KEY_RELEASE;
	else 
		status = KEY_KEEP;

	last_val = current_val;

	spin_unlock_irqrestore(&key.spinlock, flags);
}

static irqreturn_t key_interrupt(int irq, void *dev_id)
{
	/* 按键防抖
	 * 定时器延时15ms
	 */
	mod_timer(&key.timer, jiffies + msecs_to_jiffies(15));

	return IRQ_HANDLED;
}

static int key_parse_dt(void)
{
	struct device_node *nd;
	const char *str;
	int ret;

	nd = of_find_node_by_path("/key");
	if(NULL == nd){
		printk(KERN_ERR "key: Failed to get key node\r\n");
		return -EINVAL;
	}

	ret = of_property_read_string(nd, "status", &str);
	if(!ret){
		if(strcmp(str,"okay"))
			return -EINVAL;
	}

	ret = of_property_read_string(nd, "compatible", &str);
	if(ret < 0)
		return ret;

	if(strcmp(str, "alientek,key")){
		printk(KERN_ERR "key: Compatible match failed\r\n");
		return -EINVAL;
	}

	key.key_gpio = of_get_named_gpio(nd, "key-gpio", 0);
	if(!gpio_is_valid(key.key_gpio)) {
		printk(KERN_ERR "key: Failed to get key-gpio\r\n");
		return -EINVAL;
	}

	key.irq_num = irq_of_parse_and_map(nd, 0);
	if(!key.irq_num)
		return -EINVAL;

	return 0;
}

static int key_gpio_init(void)
{
	unsigned long irq_flags;
	int ret;

	gpio_direction_input(key.key_gpio);

	irq_flags = irq_get_trigger_type(key.irq_num);
	if(IRQF_TRIGGER_NONE == irq_flags)
		irq_flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;

	ret = request_irq(key.irq_num, key_interrupt, irq_flags, "PS Key0 IRQ", NULL);
	if(ret){
		gpio_free(key.key_gpio);
		return ret;
	}

	return 0;
}

static struct file_operations key_fops = {		// 设备操作函数
	.owner		= THIS_MODULE,
	.open		= key_open,
	.release	= key_release,
	.read		= key_read,
	.write		= key_write,
};

static int __init key_init(void){

	int ret = 0;

	spin_lock_init(&key.spinlock);				// 初始化自旋锁

	ret = key_parse_dt();
	if(ret)		return ret;

	ret = key_gpio_init();
	if(ret)		return ret;

	/* 注册字符设备驱动 */
	key.cdev.owner = THIS_MODULE;
	cdev_init(&key.cdev, &key_fops);	// 初始化cdev

	ret = alloc_chrdev_region(&key.devid, 0, KEY_COUNT, KEY_NAME);
	if(ret)
		goto out1;

	ret = cdev_add(&key.cdev, key.devid, KEY_COUNT);	// 添加cdev
	if(ret)
		goto out2;
	
	key.class = class_create(THIS_MODULE, KEY_NAME);	// 创建类
	if(IS_ERR(key.class)){
		ret = PTR_ERR(key.class);
		goto out3;
	}

	key.device = device_create(key.class, NULL, key.devid, NULL, KEY_NAME);	//创建设备
	if(IS_ERR(key.device)){
		ret = PTR_ERR(key.device);
		goto out4;
	}

	timer_setup(&key.timer, key_timer_function, 0);

	return 0;

out4:
	class_destroy(key.class);

out3:
	cdev_del(&key.cdev);

out2:
	unregister_chrdev_region(key.devid, KEY_COUNT);

out1:
	free_irq(key.irq_num, NULL);
	gpio_free(key.key_gpio);

	return ret;
}

static void __exit key_exit(void){

	/* delete timer */
	del_timer_sync(&key.timer);

	// 注销: 设备,类,cdev,设备号
	// 释放GPIO
	device_destroy(key.class, key.devid);
	class_destroy(key.class);
	cdev_del(&key.cdev);
	unregister_chrdev_region(key.devid, KEY_COUNT);

	free_irq(key.irq_num, NULL);
	gpio_free(key.key_gpio);
}

module_init(key_init);
module_exit(key_exit);

MODULE_AUTHOR("Skylar <Skylar@33.com>");
MODULE_DESCRIPTION("FMQL IRQ");
MODULE_LICENSE("GPL");

keyAPP.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>

/*
 * @description         : main主程序
 * @param - argc        : argv数组元素个数
 * @param - argv        : 具体参数
 * @return              : 0 成功;其他 失败
 */
int main(int argc, char *argv[])
{
	int fd, ret;
	int key_val;

	/* 传递两个参数 */
	if(argc != 2){
		printf("Usage:\n"
				"\t.irqAPP /dev/key \n"
				);
		return -1;
	}

	fd = open(argv[1], O_RDWR);
	if(fd < 0){
		printf("ERROR: %s file open failed\r\n", argv[1]);
		return -1;
	}

	/* 循环读取设备 */
	for(;;){
		readl(fs, &key_val, sizeof(int));
		if(key_val == 0)
			printf("Key Press\r\n");
		else if(key_val == 1)
			printf("Key Release\r\n");
	}

	close(fd);
	return 0;
}

 运行

因为我用的板子上没有按键,所以就复制一下正点原子的:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值