http://hi.bccn.net/202661/viewspace-9733.html
这两个猜想是我在用程序模拟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的时候,会按照从小到大的顺序执行,而不是按照中断出现的顺序执行.
文章评论(0条评论)
登录后参与讨论