在处理像Bootloader、应用程序分区以及多核工程这类项目时,经常需要调整中断向量表在内存里的存放位置;很多人会关心TASKING环境下的中断向量表该怎么重定向,以及把向量表地址改了以后为什么中断就进不去了,这里不能只盯着链接脚本里那个地址去改。下面以AURIX TriCore工程作为例子来说明,如果用的是其他架构,比如Arm Cortex-M通常靠VTOR寄存器来设置,同样需要去查对应芯片的向量表控制寄存器。
一、TASKING中断向量表怎么重定向
在AURIX TriCore这类芯片里面,用来保存中断向量表基地址的寄存器叫作BIV。向量表既可以在链接的过程中就被放进指定的存储区域,也可以在启动阶段再把它切换到新的地址上去。有一点要特别注意,BIV这个寄存器的初始化,必须在全局中断被打开之前就已经完成。
1、先修改链接位置
在TASKING工程所使用的LSL文件里,可以找到中断向量表的布局定义;TASKING的编译器会给不同的内核生成类似.text.inttabn.intvec.vector_number这样的段,里头那个n就代表内核的编号。如果工程里用到了多个内核,通常还会借助inttabnr.lsl这类文件,分别去定义每一个内核自己的向量表。所以第一步,就是去确定这些段被安排到了哪个地址上。
2、同步修改启动代码
链接脚本那边改变之后,还要让启动代码把得到的地址写到每个内核的BIV里去;如果只动了LSL文件,而没有更新启动代码,那么BIV里保存的仍旧是旧地址,当CPU收到中断信号时,它还是会跳回老地方,重定向自然就不起作用了。在AURIX的启动流程中,BIV一般是通过MTCR指令来做初始化的,这部分一定要跟着改。
3、确认中断函数归属内核
在多核工程里面,中断服务函数必须被放到正确内核的向量表里头去;TASKING支持使用__vector_table这个关键字,来指定某个中断函数到底属于哪一个向量表。要是没有特别去指定,部分中断函数可能就默认识别成0号向量表了,这样一旦请求过来,调度就会乱。
4、核对服务请求节点
外设产生中断的时候,还要去看一看SRC寄存器(服务请求控制寄存器)的配置;具体要检查的是服务提供者TOS、优先级SRPN,还有使能位SRE这些参数。按照AURIX的资料说明,SRPN被设成0的中断是不会被处理的,并且服务请求节点也需要显式地开启,光把向量表挪好是不够的。
二、TASKING向量表改地址后为何进不了中断
向量表的地址改完之后,中断迟迟进不去,常见的原因往往不是函数没有被编译进去,而是链接的结果、寄存器里的实际数值,以及外设的配置这几点没能完全对齐。
1、BIV仍然保留旧地址
可以先用调试器去查看各个内核的BIV寄存器,看看它当前的值是不是和map文件里头向量表的起始地址一致;假如Bootloader跳到应用程序之后,没有重新去初始化BIV,那么应用程序的中断就会继续落到Bootloader的向量表里,这样一来中断响应自然就不是开发者预想的那一套了。
2、地址对齐不符合要求
当使用32字节的向量间距时,BIV的基地址应该按照32字节的边界去排列;如果换成了8字节的间距,那还得确认VSS的设置是不是与链接布局一致。CPU会根据PIPN和VSS计算中断服务程序的入口,要是基地址或者间距错了,跳转的位置就会偏掉,中断也就进不到目标函数了。
3、ISR进入了错误内核表
外设SRC里的TOS位决定了由哪个内核来处理这个服务请求;要是TOS指到了CPU1,而中断函数只被放进了CPU0的向量表,那么就算中断请求已经挂起,也不可能跑到预期的函数里。多核项目排查的时候,就要把SRC的配置、BIV的指向,以及__vector_table标定的编号放在一起核对。
4、全局中断没有打开
AURIX芯片复位以后,全局中断是默认关掉的;外设都配置好了,向量表也设完了,还要确认ICR寄存器里的全局中断使能位有没有打开。如果只把SRE置位,却没有开启全局中断,那么中断服务函数还是不会执行,表现出来的就是改完地址后中断一直等不到。
三、TASKING向量表重定向后怎么复核
向量表的重新定向做完以后,建议按照“先看链接结果,再查寄存器里的数值,然后确认请求状态,最后靠断点验证”这样一套顺序来检查。
1、查看map文件
打开map文件搜索.inttab相关的段,确认每一个内核的向量表都已经落到了预期的地址范围内,并且没有和应用程序代码、校验区,或者Bootloader占用的区域互相重叠,这样可以先排除链接层面上的错误。
2、查看运行时寄存器
让程序跑起来再暂停,趁CPU停住的时候去检查BIV、ICR,还有目标外设的SRC这些寄存器;重点关注BIV地址到底对不对,SRE、SRPN和TOS这些位域是不是跟设计时的要求相符,数字上有没有什么出入。
3、给ISR设置断点
可以手工触发一次外设事件,看看断点能不能命中所对应的中断服务函数;如果SRC请求明明已经挂起,但断点却怎么也停不下来,那就把排查的重点放回到BIV、向量表入口和全局中断状态这些地方,暂时不要先去改动业务代码,往往根子就在这里。
总结
中断向量表的迁移不是只改动一个地址就能完事的。在TASKING工程里,需要同步去处理好LSL布局、启动阶段BIV的写入、中断函数具体属于哪个内核、SRC服务请求的配置,以及全局中断的使能这几件事情。改完以后,再利用map文件和实际寄存器进行逐项比对,就能够比较快地找到向量表地址变化以后无法进入中断的真正原因。