概述
中断
定时器中断原理
定时器再硬件上也可以用作中断,定时器接收一个时钟输入,当时钟脉冲来时,当前计数加1,并和预先设置的计数比较,如果相等,证明计数周期满,产生定时器中断,并复位计数值
中断是一个信号,当硬件需要产生处理器对它的关注就会产生中断
如果想看到中断,我们需要注册中断处理程序,用
request_irq
free_irq
释放中断处理程序
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id)
参数说明:
unsigned int irq:为要注册中断服务函数的中断号,比如外部中断0就是16,定义在mach/irqs.h
irq_handler_t handler:为要注册的中断服务函数,就是(irq_desc+ irq )->action->handler
unsigned long irqflags: 触发中断的参数,比如边沿触发, 定义在linux/interrupt.h。
const char *devname:中断程序的名字,使用cat /proc/interrupt 可以查看中断程序名字
void *dev_id:传入中断处理程序的参数,注册共享中断时不能为NULL,因为卸载时需要这个做参数,避免卸载其它中断服务函数
free_irq()也位于kernel/irq/ manage .c,函数原型如下:
free_irq(unsigned int irq, void *dev_id);
参数说明:
unsigned int irq:要卸载的中断号
void *dev_id:这个是要卸载的中断action下的哪个服务函数,
request_irq 正确使用位置要在设备第一次打开后、硬件被告知产生中断前。
free_irq 要在最后一次关闭设备,被报告以后不需要再处理中断处理器后使用
/proc/interrupts列出当前所以系统注册的中断,记录中断号,中断发生次数,中断设备名称
如下图:从左至右:中断号 中断次数 中断设备名称,更祥细的要看/proc/stat.
intr:系统启动以来的所有interrupts的次数情况
ctxt: 系统上下文切换次数
btime:启动时长(单位:秒),从Epoch(即1970零时)开始到系统启动所经过的时长,每次启动会改变。
此处指为1500827856,转换北京时间为2017/7/24 0:37:36
processes:系统启动后所创建过的进程数量。当短时间该值特别大,系统可能出现异常
procs_running:处于Runnable状态的进程个数
procs_blocked:处于等待I/O完成的进程个数
proc/[pid]>/stat
pid: 进程ID.
comm: task_struct结构体的进程名
state: 进程状态, 此处为S
ppid: 父进程ID (父进程是指通过fork方式,通过clone并非父进程)
pgrp:进程组ID
session:进程会话组ID
tty_nr:当前进程的tty终点设备号
tpgid:控制进程终端的前台进程号
flags:进程标识位,定义在include/linux/sched.h中的PF_*, 此处等于1077952832
minflt: 次要缺页中断的次数,即无需从磁盘加载内存页. 比如COW和匿名页
cminflt:当前进程等待子进程的minflt
majflt:主要缺页中断的次数,需要从磁盘加载内存页. 比如map文件
majflt:当前进程等待子进程的majflt
utime: 该进程处于用户态的时间,单位jiffies,此处等于166114
stime: 该进程处于内核态的时间,单位jiffies,此处等于129684
cutime:当前进程等待子进程的utime
cstime: 当前进程等待子进程的utime
priority: 进程优先级, 此次等于10.
nice: nice值,取值范围[19, -20],此处等于-10
num_threads: 线程个数, 此处等于221
itrealvalue: 该字段已废弃,恒等于0
starttime:自系统启动后的进程创建时间,单位jiffies,此处等于2284
vsize:进程的虚拟内存大小,单位为bytes
rss: 进程独占内存+共享库,单位pages,此处等于93087
rsslim: rss大小上限
说明:
第10~17行主要是随着时间而改变的量;
内核时间单位,sysconf(_SC_CLK_TCK)一般地定义为jiffies(一般地等于10ms)
starttime: 此值单位为jiffies, 结合/proc/stat的btime,可知道每一个线程启动的时间点
1500827856 + 2284/100 = 1500827856, 转换成北京时间为2017/7/24 0:37:58
第四行数据很少使用,只说一下该行第7至9个数的含义:
signal:即将要处理的信号,十进制,此处等于6660
blocked:阻塞的信号,十进制
sigignore:被忽略的信号,十进制,此处等于36088
很多时候我们不知道终端号是多少,我们就需要中断探测probe
int count = 0;
do
{
unsigned long mask;
mask = probe_irq_on();
outb_p(0x10,short_base+2); /* enable reporting */
outb_p(0x00,short_base); /* clear the bit */
outb_p(0xFF,short_base); /* set the bit: interrupt! */
outb_p(0x00,short_base+2); /* disable reporting */
udelay(5); /* give it some time */
short_irq = probe_irq_off(mask);
if (short_irq == 0) { /* none of them? */
printk(KERN_INFO "short: no irq reported by proben");
short_irq = -1;
}
} while (short_irq < 0 && count++ < 5);
if (short_irq < 0)
printk("short: probe failed %i times, giving upn", count);
需要注意的是,只有在配置了CONFIG_GENERIC_IRQ_PROBE的时候,irq探测机制才会生效。
unsigned long probe_irq_on(void);
/*这个函数返回一个未分配中断的位掩码。驱动必须保留返回的位掩码, 并在后面传递给 probe_irq_off。在调用probe_irq_on之后, 驱动应当安排它的设备产生至少一次中断*/
intprobe_irq_off(unsignedlong);
/* 在请求设备产生一个中断后, 驱动调用这个函数, 并将 probe_irq_on 返回的位掩码作为参数传递给probe_irq_off。probe_irq_off 返回在"probe_on"之后发生的中断号。如果没有中断发生, 返回 0 ;如果产生了多次中断,probe_irq_off 返回一个负值*/
void disable_irq(int irq); //等待目前中断处理完成(最好别在顶板部使用,你懂得)
void disable_irq_nosync(int irq); //立即返回
void enable_irq(int irq);//
#define local_irq_save(flags) //禁止中断并保存状态
void local_irq_disable(void); //禁止中断,不保存状态
disable_irq:在非中断处理函数中使用,会阻塞;
2、disable_irq_nosync:在中断处理函数中使用,不会阻塞;用于屏蔽相应中断;
关闭中断之后,中断状态只是暂存,而不是清除。如果你想要在关闭中断期间的所有中断以后也得不到响应,你只能挨个清除
linux中断处理程序架构
linux将中断分为:顶半部和底半部
顶半部:完成尽可能少的比较紧急的任务,它往往只是简单的读取寄存器中的中断状态并清除中断标志后就进行
”登记中断“(也就是将底半部处理程序挂到设备的底半部执行队列中)的工作
特点:响应速度快
底半部:中断处理的大部分工作都在底半部,它几乎做了中断处理程序的所有事情、
特点:处理相对不是非常紧急的事情
底半部的应用 tasklet和工作队列
最后
以上就是炙热自行车为你收集整理的linux驱动中的中断 中断 定时器中断原理的全部内容,希望文章能够帮你解决linux驱动中的中断 中断 定时器中断原理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复