在非DSP/BIOS中使用CSL API进行设置如下(参考内容2中提到,在DSP/BIOS设置更简洁):
1. 编写中断服务例程
在.c源文件中编写ISR函数c_intXX,用于中断处理,如:
interrupt void c_intXX (void)
{
…;
}
注:对于硬件中断而言,XX = 00~15。
2.初始化中断向量表,并在内存段中的中断向量表中配置好对应的中断向量
首先是把中断向量表定位到某一内存段中,我们可以在cmd文件中配置中断向量表的内存映射,如:
MEMORY
{
VECTORS: org = 00000000h, len = 00000400h
L2SRAM: org = 00000400h, len = 00100000h
SDRAM: org = 80000000h, len = 10000000h
}
SECTIONS
{
.vecs :> VECTORS
.data :> L2SRAM
.text :> L2SRAM
.switch :> L2SRAM
.stack :> L2SRAM
.bss :> L2SRAM
.cinit :> L2SRAM
.far :> L2SRAM
.cio :> L2SRAM
.const :> L2SRAM
.sysmem :> SDRAM
.tables :> L2SRAM
}
然后建立一个.asm文件,用以配置中断向量表中的中断向量,我们需要声明一些全局变量,以便其他源文件可以引用这些变量或者引用其他源文件的变量,如:
.global _vectors
.global _c_int00
.global _vector1
.global _vector2
.global _vector3
.global _vector4
.global _vector5
.global _vector6
.global _vector7
.global _c_int08 ; 对应main()函数的c_int08中断服务例程(假设处理的是EDMA中断)
.global _vector9
.global _vector10
.global _vector11
.global _vector12
.global _vector13
.global _vector14
.global _vector15
因为引用了rts的_c_int00中断,即RESET中断,因此需要引入这个符号:
.ref _c_int00
为了把中断服务例程的地址,即中断向量插入到中断向量表中,可以定义一个宏:
VEC_ENTRY .macro addr
STW B0,*--B15
MVKL addr,B0
MVKH addr,B0
B B0
LDW *B15++,B0
NOP 2
NOP
NOP
.endm
为了初始化中断向量表中的中断向量,可以定义一个虚拟的中断向量:
_vec_dummy:
B B3
NOP 5
接下来就可以配置中断向量表了:
.sect “.vecs”
.align 1024
_vectors:
_vector0: VEC_ENTRY _c_int00 ;RESET中断
_vector1: VEC_ENTRY _vec_dummy ;NMI不可屏蔽中断
_vector2: VEC_ENTRY _vec_dummy ;保留中断1
_vector3: VEC_ENTRY _vec_dummy ;保留中断2
_vector4: VEC_ENTRY _vec_dummy ;外部中断INT4
_vector5: VEC_ENTRY _vec_dummy ;外部中断INT5
_vector6: VEC_ENTRY _vec_dummy ;外部中断INT6
_vector7: VEC_ENTRY _vec_dummy ;外部中断INT7
_vector8: VEC_ENTRY _c_int08 ; EDMA控制器中断EDMAINT,对应于c_int08 ISR
_vector9: VEC_ENTRY _vec_dummy;JTAGRTDX中断
_vector10: VEC_ENTRY _vec_dummy;EMIF_SDRAM_Timer中断
_vector11: VEC_ENTRY _vec_dummy;McBSP_0_Receive中断
_vector12: VEC_ENTRY _vec_dummy;McBSP_1_Transmit中断
_vector13: VEC_ENTRY _vec_dummy;Host_Port_Host_to_DSP中断
_vector14: VEC_ENTRY _vec_dummy;Timer0中断
_vector15: VEC_ENTRY _vec_dummy;Timer1中断
3. 在C程序中指定定义的中断向量表,并且启用CPU中断功能
在C程序中,用CSL的IRQ模块来设置中断比较方便,在设置之前,需要外部链接上面的asm程序的中断向量表符号:
extern far void vectors();//之所以为vectors,因为C编译器编译后自动改名其为_vectors
引用了中断向量表之后,就可以设置中断了:
IRQ_setVecs(vectors); //指向asm中定义的中断向量表
IRQ_nmiEnable();
IRQ_globalEnable();
IRQ_map(IRQ_EVT_EDMAINT, 8); //把具体事件和中断号关联起来
IRQ_reset(IRQ_EVT_EDMAINT);
4.启动中断源,如EDMA控制器的中断
至此,中断服务例程c_int8就可以为EDMAINT中断服务了,其它硬件中断向量的配置同理。
5 .实际上述流程定义描述DM642中断的向量表文件,是使用TI公司提供的一个中断向量表文件模板:ves_dm642.asm。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
中断函数_vectors的一般写法如下:
_vectors:
_vector0: VEC_ENTRY _c_int00
_vector1: VEC_ENTRY _vec_dummy
_vector2: VEC_ENTRY _vec_dummy
_vector3: VEC_ENTRY _vec_dummy
......
_vector15: VEC_ENTRY _vec_dummy
其中:_vec_dummy为空函数,VEC_ENTRY 为宏定义
VEC_ENTRY .macro addr
stw b0, *--b15
mvkl addr, b0
mvkh addr, b0
b b0
ldw *b15++, b0
nop 2
nop
nop
.endm
////////////////////////////////////////////////////////////////////////////
我的疑惑是,VEC_ENTRY宏中,用到了两个寄存器,B15和B0,这两个寄存器有什么特殊用途?
VEC_ENTRY .macro addr
STW B0,*--B15 ;把B0内容保存到*B15,然后指针变量后移,相当于压栈
MVKL addr,B0
MVKH addr,B0 ;传入参数的地址给B0
B B0 ;程序跳转到B0指向的地址
LDW *B15++,B0 ;把之前保存的B0恢复;相当于pop
NOP 2
NOP
NOP
.endm
从解释来看,感觉就只是完成一个简单的程序跳转功能,用别的寄存器应该也能实现,非要说有什么特殊用途的话,目前能想到也是在C64X平台下,只有A0、A1。A2、B0、B1、B2可以作为条件寄存器,但这个代码里并不存在条件执行。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
中断服务程序--------->中断向量表存储初始化(存储地址说明)----------->中断向量表全局变量说明--------->引用变量说明------------>工具宏编写---------->中断向量表编写(用到以上的准备)--------------------->c语言中定位中断向量表----------------->中断复用寄存器设置(中断号和中断事件相对应)