问题描述:
系统调试过程中发现硬件中断经常得不到及时响应,根据现象推断中断会被延迟达150us以上。
问题分析:
中断信号是连到CPLD的,DSP的GPIO6也与CPLD相连。用CPLD的任一个输出脚IOX做为中断延迟指示。中断沿来了之后将IOX置为高电平,DSP进入中断服务函数马上给GPIO6一个翻转,CPLD检查到来自GPIO6的翻转后将IOX清为低电平。这样,通过观察IOX上的信号正脉冲宽度就可以看到从中断发生到中断得到响应所用的时间了。而且通过脉宽触发模式就可以设置大于150us的正脉冲触发,这样就能捕捉到异常情形了。通过测试发现,一般延迟只有400ns左右,但任务负载一重就会出现宽度超过150us的正脉冲,也就是中断被延迟了150us以上才得到响应。
下图为观察到的IOX管脚上的波形:
开始以为是有其他中断打断而占用CPU。但经过实验验证发现这种延迟并非受中断影响,而是和任务有关。
最终确认这种延时和某个任务中的memset()函数调用有关――这个函数对片外SDRAM中的384×100个字节进行清0操作。将这个函数注释掉就可以明显减小中断延迟发生的频率。
memset(buffer,0,lenth);
由于片内空间不足,buffer位于片外SDRAM,lenth为384×100。
于是先怀疑这个函数可能对中断机制做了什么禁止操作,便用自己写的for循环代替memset函数进行清0操作,看是不是会解决这个问题。后来却发现延迟反而更长了。于是将for循环多进行几遍,编程使for循环重复9次。
for(j=0;j<9;j++){
dst=buffer;
for (len=0;len<38400;len++){
*dst++ = 0;
}
}
从示波器可以看到连续9个中断响应异常:
上面的波形即可看出,中断发生是200us周期的,超过200us的中断延迟会致使一次中断丢失。这几个异常中断响应之间(脉冲下降沿间隔)都是300us.,于是推断一次内循环大致耗时300us。
更改次数为5,则可以见到连续5个中断响应都被延迟300us左右。如果按133M写速率的话,这个时间刚好是38400/133M=288us。于是怀疑为for循环内中断一直不能得到响应。
在for循环内设置断点观察。发现for循环运行中,GIE有效,IER内的中断使能有效,IFR中断对应位也正常置1,但程序不会跳转到中断服务程序。直到内层的for循环结束后,才会跳转到中断服务程序,外层的for循环是可以打断的。因为自身的IER仍有效,所以判断没有进入HWI_enter调试程序,不是DSP/BIOS的问题。应当是DSP芯片循环赋值硬件机制和中断配合的问题。
上面的赋值语句是按字节赋值,DSP处理时每循环一次2个时钟周期,每循环一次写3个字节(多逻辑单元并行操作)。也许正是这种多逻辑单元并行处理机制导致的CPU不能即时响应中断。
后来在TI的一篇文档中找到了答案。TMS320C64x/C64x+ DSP CPU and Instruction Set Reference Guide(SPRU732H)。第534页列出了中断得到CPU响应需具备的条件。
· IFm is set during CPU cycle 6. (This determination is made in CPU cycle 4 by the interrupt logic.)
· There is not a higher priority IFm bit set in IFR.
· The corresponding bit in IER is set (IEm = 1).
· GIE = 1
· NMIE = 1
· The five previous execute packets (n through n + 4) do not contain a branch (even if the branch is not
taken).
其中第6条即标明,CPU响应中断前5个执行包内,不能有跳转指令。(execute packets指同一周期内可并行执行的指令集合——最多一周期可执行8条指令。)因为循环赋值的for循环内只有五六条汇编指令,往往在二到三个周期内即可完成一次循环,然后CPU无法中断而继续下一次循环。直到循环结束才开始响应中断。而从内层的for循环到下一次循环之间则刚好多于5个执行包,所以外层的for循环可以被中断
解决方法:
可以使用DMA操作,用DAT_fill()函数代替memset()函数。
可以将较长的for循环分解为多层for循环,以减小最内层for循环执行时间,减小对中断的影响。内层循环结束后可以适当做一点简单的运算来提供5周期的“空隙”。
可以用64位操作或32位操作替换8位操作,可减小赋值所需的总时间。
可以用编译器的“-mi”编译项来让编译器自动处理(后面需带参数,具体意义和用法可参见TI的SPRU198G文档“TMS320C6000 Programmer’s Guide”的“interrupts”一节,356页)。
注:64x和64x+都是这样的。