[原创][DSP]关于硬件中断(HWI)的两个猜想

作者在 2008-03-20 16:05:48 发布以下内容

这两个猜想是我在用程序模拟HWI时(利用几个IRQ_开头的函数,具体查看CCS的帮助文件),多次测试之后的一点想法,不保证正确,因为TI的帮助文档没去看(因为讨厌鸟语).

使用软件是CCS3.1,利用其DSP/BIOS系统,这个系统的确方便.

=======================================================

先介绍一下几个和中断有关的寄存器

硬件中断总开关,CSR(Control Status Register)寄存器中的第0位GIE(Global interrupt enable),1表示允许中断(相当于打开大门),0表示禁止中断(关上大门)

单个中断开关,IER(Interrupt Enable Register)寄存器,其低16位对应了16个中断的开关情况,相当于16个小门,1表示门开,0表示门关

只有这两个开关都打开的时候,中断才能起作用(这是对可屏蔽中断来说的,有些中断是不能被屏蔽的,这两个开关就都没用)

中断状态寄存器,IFR(Interrupt Flag Register),记录有哪些待响应的中断,低16位对应16个中断,如果为1说明这个中断需要被响应.0表示不需要.

中断返回地址,IRP(Interrupt Return Pointer Register),记录中断调用后的返回地址,如果中断嵌套,那么后面的返回地址会覆盖前面的.不过这个不影响中断返回,我测试过中断嵌套,可以正常返回,经过查看堆栈的地址(B15寄存器是堆栈指针sp),可以看出返回地址还是放在堆栈里面了.这个IRP寄存器,应该就相当于一个窗口,让用户可以看看中断返回的地址,而程序自己在返回的时候,是不从这里读取的,而是从堆栈中读取,读取之后也不会更新IRP寄存器.IRP寄存器只有在中断生效的时候被修改.

--------------------------------------------------------------------------------------------

猜想1:

在中断服务程序(ISR,Interrupt service routine),在被调用之前,BIOS应该还偷偷做了两件事,

第一件是将全局中断开关(GIE,Global Interrupt Enable)关闭,也就是不再响应所有可屏蔽的硬件中断.(GIE是CSR寄存器的第0位)

第二件是将IFR(Interrupt Flag Register)中和这个中断对应的位置0,以等待下次使用IRQ_set(中断号)函数将这个位置1

本来这第一件事也没什么,但是奇怪的就是在ISR(中断服务程序)结束的时候,并没有自动把GIE位恢复,而是就让GIE位一直为0,那么所有的中断就都被屏蔽了,所以只能在自定义的ISR函数最后,自己手动加上IRQ_globalEnable()函数.

不知道是我猜想有误还是哪个设置没设置好.

猜想2. 关于硬件中断的执行顺序

我猜想的中断处理流程:

0.初始化的时候,先打开大门GIE(利用IRQ_globalEnable函数),接着打开需要的中断的小门(利用IRQ_enable函数),这样才能响应中断,不然出现中断的时候,只会置位IFR,而不会调用到ISR.

1.程序运行期间,出现硬件中断信号(由于只是软件模拟,没有实际的硬件,所以只能调用IRQ_set函数来虚拟一个硬件中断,这个跟实际的硬件中断是否相同还没法验证.),这个时候将IFR寄存器中对应的位置1.

2.程序每个指令周期,都检测IFR,如果发现其中有某一位为1,那么再查看GIE和IER中对应的位,如果发现门没开,那就不管,继续执行当前的指令.(具体是先看IFR还是先看GIE和IER我就不清楚了,总之结果是一样的)

3.如果门开了(GIE为1,IER中对应的位也为1),那么将下一条指令的地址,还有一个不知道什么值,都存入堆栈中,同时改变IRP的值为下一条指令的地址.这就是保护现场.

4.做好现场保护后,查看中断向量表,找到该中断对应的跳转地址,然后跳转到已经定义好的中断处理程序(ISR)

5.在运行ISR之前,先是将GIE置0,IFR中对应的位置0,IER的位不变.然后执行程序.

6.程序执行完毕后,从堆栈中找到返回的地址,返回到中断前执行的指令,继续向下执行.

我想HWI执行的顺序应该就是上面这样,另外有几点需要补充:

1.不同的HWI没有优先级之分,只要GIE,IER,IFR条件满足,即使是在一个中断中,新出来的中断会打断当前的ISR,优先执行(无论是不是同样的中断,比如INT4打断INT4,INT5打断INT4,INT4打断INT5都是可以的),这就需要在编程的时候注意了,如果不希望在处理一个中断的时候,被另一个中断打断,就应该是在中断返回之前,再调用IRQ_globalEnable函数,这样处理那些不能被屏蔽的中断,其它中断就不会响应

2.如果GIE位是0,出现中断的时候,就只会在IFR的对应位置1,如果这个时候再来一个同样的中断,这个位还是1,等到GIE为1的时候,这个中断只运行一次,而不是两次.

3.如果GIE位是0,这个时候来了几个不同的中断,在IFR的不同位置了1,那么等到GIE为1的时候,会按照从小到大的顺序执行,而不是按照中断出现的顺序执行.

原创 | 阅读 4464 次
文章评论,共0条
游客请输入验证码