Linux单片机编译中断,关于对Linux中断的一点点拙见

先来看51单片机的中断机制:

当中断到来时,CPU先把正在执行的命令的地址(命令存在单片机内部,既然在内部必然就有一个所在地址,PC指向的是当前执行的命令的下一条命令,例如:我的命令有第一条、第二条、第三条,如果CPU正在执行第二条命令,那PC是指向第三条命令)压入堆栈存着,这一步是保护现场;

接着CPU被强制跳转到中断矢量处(外部中断0的矢量为0003,外部中断1的矢量为000B,定时器0的中断矢量为0013,定时器1的中断矢量为001B,串口中断矢量为0023),通常在中断矢量中存放的是跳转指令;例如定时器0的中断矢量是000B,而我定义定时器0的中断服务函数是void

time0_interrupt() 1,那么在000B这个地址里面存放的就是代码的功能就是从当前执行程序中跳转到void time0_interrupt()

1函数去执行(至于这条跳转指令是怎么写的还不懂啊,汇编不好是硬伤啊),这是中断响应;

执行完中断服务程序后,一开始被压入堆栈的命令又弹出来继续执行,这是现场恢复;

以上是51单片机的中断过程,那么Linux也是差不多,只是Linux的中断多、代码量大、涉及的代码知识相对难,但是道理还是一样。如下:

开发板上电之后u-boot会关闭看门狗、关闭MMU、设置中断等等,设置中断就是通过这个函数:void __init early_trap_init(void)

函数部分代码是这样:

memcpy((void *)vectors, __vectors_start,

__vectors_end - __vectors_start);//这一段的意思是把中断向量里的那些跳转指令拷贝到vectors这个地址;

__vectors_start:开始时向量的所在的起始地址。

__vectors_end - __vectors_start:指的是_拷贝_vectors_start到__vectors_end的地址里的内容

注意拷贝是跳转指令不是向量,也有人把向量就认为是那些跳转指令,个人见解吧,但这个_vectors_start地址里存放的真的是跳转指令(估计看到这会有点模糊,为什么不是仅仅拷贝跳转地址而是向量地址里面的内容呢?看后面就知道了)

memcpy((void *)vectors + 0x200, __stubs_start,

__stubs_end - __stubs_start);//这一段的意思是,把中断服务程序拷贝到)vectors +

0x200,当然这应该只是一个起始地址,中断服务代码量大的话,占用的内存也会相应大。至于其他两个参数和上面的函数是基本一致的。

等中断来了之后,先是压栈等等工作,保存现场,接着跳转指令就会跳转到

asmlinkage void

__exception_irq_entry asm_do_IRQ(unsigned

int irq, struct pt_regs *regs)

函数去执行,

irq:终断号

regs:用于保存中断之前执行着的地址(关于前面的不解,现在该明白了吧,它是先把跳转指令等拷贝进来,执行跳转的时候顺便保存现场,哎,非要跟51不一样)

简单介绍这个函数的一些代码:

struct pt_regs *old_regs =

set_irq_regs(regs);这个函数就是记录中断现场;

irq_enter();进入中断处理过程,但是里面的功能好复杂,愣是没懂

generic_handle_irq(irq);这个函数需要细说,irq是中断号,函数原型是

static inline void

generic_handle_irq(unsigned int irq)

{

generic_handle_irq_desc(irq, irq_to_desc(irq));

}

它调用了这个函数

static inline void

generic_handle_irq_desc(unsigned int irq, struct irq_desc

*desc)

{

desc->handle_irq(irq, desc);

}

看函数的参数:

irq:中断标号

irq_to_desc(irq)这其实是一个带参宏,是这样的:

#define irq_to_desc(irq)

(&irq_desc[irq])

irq_desc是一个结构体,个人理解是这样的

:每个中断或者说每一组中断对应一个中断标号,每一个中断标号又会对应一个这样的结构体,类似于一个字符设备会对应一个cdev结构体,struct irq_desc

irq_desc[irq]就代表某个中断的结构体,其中断号是irq,通过这个结构体变量(这个结构体变量是数组,说白了,假如irq=1,那irq_desc[1]就纯碎是一个结构体变量)去访问结构体成员,结构体成员很多,例如中断名称、对应中断号的服务函数、中断状态等。

函数内容desc->handle_irq(irq, desc);

关于handle_irq就好多话说了,在irq_desc结构体里面有这样一个成员,是这么写的:

irq_flow_handler_t handle_irq;

(其实就好比int a;就是定义了一个整形的变量a,而irq_flow_handler_t

handle_irq;,就是定义了一个irq_flow_handler_t型的变量handle_irq)

这个irq_flow_handler_t是一个宏,如下:

typedef void (*irq_flow_handler_t)(unsigned

int irq, struct irq_desc *desc);

这又怎么解释呢?

先看这个:char a[10],这个就是定义数组a,这个数组有十个元素,且元素都是字符型的;

再看typedef char T[10];

T

a;这两句一起句的功能也是同上,至于为什么俺也不知道怎么说,但是就是这样,它就是这样,记住就好;说白了就是T代替了char [10];

再看int

(*p)(int,int)

意思是定义了一个指针p,这个指针指向的是一类(切记是一类而不是一个)函数,这类函数有两个int型的参数,函数返回值是int型;

再看typedef int

(*PT)(int,int);

PT p; 呐,这两句加起来的功能就和上面一样,记住就好,用多了就会理解

通过这个例子,应该都知道为什么会有handle_irq(irq,

desc);了吧,开始明明就是个变量而已,摇身一变就函数啦!!!

关于

asmlinkage void

__exception_irq_entry asm_do_IRQ(unsigned

int irq, struct pt_regs *regs)

以上就是中断执行部分。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值