嵌入式学习——硬件(Linux内核驱动编程中断、队列、ADC)——day60

1.按键(中断处理)——混杂设备驱动

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/irqreturn.h>
#include <linux/interrupt.h>
#include <mach/irqs.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define GPGCON (0x56000060)
#define GPGDAT (0x56000064)
#define GPGUP (0x56000068)
static unsigned int *regGPGCON;
static unsigned int *regGPGDAT;
static unsigned int *regGPGUP;

int key = 0;

irqreturn_t key_handler(int irq_num, void *dev)
{	
	if(irq_num == IRQ_EINT8)
	{
		key = 1;
	}

	return IRQ_HANDLED;
}

int key_open(struct inode *p_node, struct file *fp)
{
	printk("kernel open\n");
	return 0;
}

int key_release(struct inode *p_node, struct file *fp)
{
	return 0;
}

ssize_t key_write(struct file *fp, const char __user *user_buffer, size_t n, loff_t *offset)
{
	int ret;
	copy_from_user(&ret,user_buffer,4);

	return 4;
}

ssize_t key_read(struct file *fp, char __user *user_buffer, size_t n, loff_t *offset)
{
	copy_to_user(user_buffer, &key,4);
	key = 0;
	return sizeof(key);
}

static struct file_operations fops =
{
	.owner = THIS_MODULE,
	.open = key_open,
	.release = key_release,
	.read = key_read,
};

static struct miscdevice key_device = 
{
	.minor = MISC_DYNAMIC_MINOR,
	.fops = &fops,
	.name = "key"
};

static int __init key_init(void)
{
	int ret;

	ret = misc_register(&key_device);
	if(ret)
	{
		printk("misc_register is error");
		return ret;
	}

	ret = request_irq(IRQ_EINT8, key_handler, IRQF_TRIGGER_RISING | IRQF_DISABLED, "key_irq", &key_device);
	if(ret)
	{
		printk("request_irq is error\n");
		misc_deregister(&key_device);
	}

	regGPGCON = ioremap(GPGCON,4);
	regGPGDAT = ioremap(GPGDAT, 4);
	regGPGUP = ioremap(GPGUP,4);

	return 0;
}

static void __exit key_exit(void)
{
	iounmap(regGPGCON);
	iounmap(regGPGDAT);
	iounmap(regGPGUP);
	
	disable_irq(IRQ_EINT8);
	free_irq(IRQ_EINT8, &key_device);
	misc_deregister(&key_device);
}

module_init(key_init);
module_exit(key_exit);

MODULE_LICENSE("GPL");

2. 按键队列——混杂设备驱动

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/irqreturn.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <mach/irqs.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define GPGCON (0x56000060)
#define GPGDAT (0x56000064)
#define GPGUP (0x56000068)
static unsigned int *regGPGCON;
static unsigned int *regGPGDAT;
static unsigned int *regGPGUP;

static wait_queue_head_t wq;
static int conditon;
int key = 0;

irqreturn_t key_handler(int irq_num, void *dev)
{	
	if(irq_num == IRQ_EINT8)
	{
		key = 1;
	}
	conditon = 1;
	wake_up(&wq);
	return IRQ_HANDLED;
}

int key_open(struct inode *p_node, struct file *fp)
{
	printk("kernel open\n");
	return 0;
}

int key_release(struct inode *p_node, struct file *fp)
{
	return 0;
}

ssize_t key_write(struct file *fp, const char __user *user_buffer, size_t n, loff_t *offset)
{
	return 4;
}

ssize_t key_read(struct file *fp, char __user *user_buffer, size_t n, loff_t *offset)
{
	conditon = 0;
	wait_event_interruptible(wq, conditon);
	copy_to_user(user_buffer, &key,4);
	key = 0;

	return sizeof(key);
}

static struct file_operations fops =
{
	.owner = THIS_MODULE,
	.open = key_open,
	.release = key_release,
	.read = key_read,
};

static struct miscdevice key_device = 
{
	.minor = MISC_DYNAMIC_MINOR,
	.fops = &fops,
	.name = "key"
};

static int __init key_driver_init(void)
{
	int ret;

	ret = misc_register(&key_device);
	if(ret)
	{
		printk("misc_register is error");
		return ret;
	}

	ret = request_irq(IRQ_EINT8, key_handler, IRQF_TRIGGER_RISING | IRQF_DISABLED, "key_irq", &key_device);
	if(ret)
	{
		printk("request_irq is error\n");
		misc_deregister(&key_device);
	}

	init_waitqueue_head(&wq);

	regGPGCON = ioremap(GPGCON,4);
	regGPGDAT = ioremap(GPGDAT, 4);
	regGPGUP = ioremap(GPGUP,4);

	return 0;
}

static void __exit key_exit(void)
{
	iounmap(regGPGCON);
	iounmap(regGPGDAT);
	iounmap(regGPGUP);
	
	disable_irq(IRQ_EINT8);
	free_irq(IRQ_EINT8, &key_device);
	misc_deregister(&key_device);
}

module_init(key_driver_init);
module_exit(key_exit);

MODULE_LICENSE("GPL");

3. ADC中断队列——混杂设备驱动

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/irqreturn.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <mach/irqs.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define ADCCON (0x58000000)
#define CLKCON (0x4C00000C)
#define ADCDAT0 (0x5800000C)
static unsigned int *regADCCON;
static unsigned int *regADCDAT0;
static unsigned int *regCLKCON;
static wait_queue_head_t wq;
static int condition;

unsigned int adc = 0;

void wake_up_queue(void)
{
	condition = 1;
	wake_up(&wq);
}

irqreturn_t adc_handler(int irq_num, void *dev)
{
	printk("adc interrupt!\n");
	if(irq_num == IRQ_ADC)
	{
		adc = *regADCDAT0 & 0x3ff;
	}
	
	wake_up_queue();

	return IRQ_HANDLED;
}

int adc_open(struct inode *p_node, struct file *fp)
{
	printk("kernel open\n");
	return 0;
}

int adc_release(struct inode *p_node, struct file *fp)
{
	return 0;
}

ssize_t adc_write(struct file *fp, const char __user *user_buffer, size_t n, loff_t *offset)
{
	int ret;
	copy_from_user(&ret,user_buffer,4);

	return 4;
}

ssize_t adc_read(struct file *fp, char __user *user_buffer, size_t n, loff_t *offset)
{
	condition = 0;
	*regADCCON |= (1 << 0);//打开adc
	wait_event_interruptible(wq, condition);
	copy_to_user(user_buffer, &adc, 4);

	return sizeof(adc);
}

static struct file_operations fops =
{
	.owner = THIS_MODULE,
	.open = adc_open,
	.release = adc_release,
	.read = adc_read,
};

static struct miscdevice adc_device = 
{
	.minor = MISC_DYNAMIC_MINOR,
	.fops = &fops,
	.name = "adc"
};

void adc_init(void)
{
	unsigned int t;

	t = *regADCCON;
	t |= (1 << 14);	//使能预分频
	t &= ~(0xff << 6);
	t |= (49 << 6);//给预分频值
	t &= ~(0x07 << 3);// 模拟输入通道选择AIN0(引脚)
	t &= ~(1 << 2);// 正常工作模式
	t &= ~(1 << 1);//使能ADC转换
    *regADCCON = t;
}

static int __init adc_driver_init(void)
{
	int ret;

	ret = misc_register(&adc_device);
	if(ret)
	{
		printk("misc_register is error");
		return ret;
	}

	ret = request_irq(IRQ_ADC, adc_handler, IRQF_DISABLED, "adc_irq", &adc_device);
	if(ret)
	{
		printk("request_irq is error\n");
		misc_deregister(&adc_device);
	}
	
	init_waitqueue_head(&wq);//初始化队列

	regADCCON = ioremap(ADCCON,4);
	regCLKCON = ioremap(CLKCON,4);
	regADCDAT0 = ioremap(ADCDAT0, 4);
	*regCLKCON |= (1 << 15);

	adc_init();

	return 0;
}

static void __exit adc_exit(void)
{
	iounmap(regADCCON);
	iounmap(regADCDAT0);
	iounmap(regCLKCON);
	
	disable_irq(IRQ_ADC);
	free_irq(IRQ_ADC, &adc_device);

	misc_deregister(&adc_device);
}

module_init(adc_driver_init);
module_exit(adc_exit);

MODULE_LICENSE("GPL");

4. 中断顶半部和底半部

中断(Interrupt)是计算机系统中处理异步事件的一种机制,当硬件设备需要CPU进行处理时,会发出中断信号。中断处理通常会分为顶半部(Top Half)和底半部(Bottom Half),以优化中断处理的效率。

顶半部(Top Half)

顶半部是中断处理的第一部分,通常会在中断发生时立即执行。其主要特点如下:

  1. 高优先级执行:顶半部代码在中断上下文中执行,具有最高的优先级,以确保快速响应硬件设备的请求。
  2. 最小化处理:顶半部的处理时间应尽可能短,因为它会阻塞其他中断的处理。顶半部通常只执行必要的最小工作,比如读取硬件寄存器,确认中断源,保存一些状态信息等。
  3. 不可被其他中断打断:在某些系统中,顶半部的执行是不可中断的,这意味着在顶半部执行期间,不会处理其他中断,保证了顶半部的快速完成。

底半部(Bottom Half)

底半部是在顶半部之后执行的中断处理的第二部分。其主要特点如下:

  1. 延迟执行:底半部的处理在稍后时间执行,不需要立即完成,通常在内核的上下文中以较低优先级运行。
  2. 复杂处理:底半部适合执行较复杂、耗时的操作,比如数据传输、缓冲区处理、与用户空间的交互等。
  3. 可被其他中断打断:与顶半部不同,底半部的执行可以被其他中断打断,因为它的优先级较低。

实现方式

在Linux系统中,底半部的实现有多种方式,包括软中断(Softirq)、任务队列(Tasklet)和工作队列(Workqueue)。这些机制允许将较复杂和耗时的处理任务推迟到合适的时间进行,以减少中断处理对系统的影响。

总结

顶半部和底半部的划分有助于优化中断处理的效率。顶半部用于快速响应和处理最小的中断任务,而底半部则处理较为复杂和耗时的操作,确保系统能够及时响应硬件中断的同时,不会因中断处理而导致系统性能下降。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值