分析过程:
开始以为是有其他中断打断或占用CPU。但经过实验验证发现这种延迟并非受中断影响,而是和任务有关。
最终确认这种延时和某个任务中的memset调用有关。将这个函数注释掉就可以明显减小中断延迟发生的频率。
memset(buffer,0,lenth);
由于片内空间不足,buffer位于片外SDRAM。
于是先怀疑这个函数可能对中断机制做了什么禁止操作,便用自己写的for循环代替memset函数进行清0操作,并且进行9次。
for(j=0;j<9;j++){
dst=buffer;
for (len=0;len<38400;len++){
*dst++ = 0;
}
}
从示波器可以看到连续9个中断响应都被延迟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无法中断而继续下一次循环。直到循环结束才开始响应中断。
解决方法:
可以使用DMA操作,用DAT_fill()函数代替memset()函数。
可以将较长的for循环分解为多层for循环,以减小最内层for循环执行时间,减小对中断的影响。内层循环结束后可以适当做一点简单的运算来提供5周期的“空隙”。
可以用64位操作或32位操作替换8位操作,可减小赋值所需的总时间。
TI有专门的编译指令来强制打断这种循环,以使中断得到响应。
SPRU198G文档interrupts节内有相关描述。
其实这不算是问题,而是DM64X系列内核的结构特性。为使CPU的效率更高,对中断处理的实时性做了一些折衷。不过,此处需格外注意。如果设计中发现中断未及时响应,可以用我描述的方法来定位是哪里影响到了中断执行。