未实现的中断处理程序行为

时间:2013-10-27 22:01:20

标签: 8051

我花了最近几天调试一个不会中断SMBUS字符的小程序。我终于将它追溯到一个未实现的中断处理程序。这不是我需要处理程序,而是8051F330被错误地配置为硬件中断,并且没有中断处理程序来捕获中断。

现在,这对我来说有点令人惊讶。如果没有处理程序,我会期望一个NOP,但我想失踪的RETI导致IRQ被锁定?在这种情况下,主循环似乎有效。我知道需要重置中断标志,但timer0 IRQ与我的SMBUS IRQ没有任何共同之处。

我是否正确地解释了这一点?无意的IRQ启用是否会导致IRQ停止工作?

2 个答案:

答案 0 :(得分:0)

参考the C8051F330 datasheet,表15.1。

每个中断源(复位,定时器0溢出,SMB0等)都有一个硬编码的中断向量地址。当中断被置位时,微生成器向该向量地址生成LCALL指令。 SMB0为0x003B,定时器0溢出为0x000B。在Keil中编写中断处理程序(interrupt关键字时,请参阅this question了解其他示例),链接器通常会在向量地址处放置某种JMP指令以进入处理程序。

如果您忽略为已启用的中断编写处理程序,则micro仍将向该地址移动。然后发生什么取决于链接器在代码空间中放置的位置。我发现小函数往往会填充在向量地址之间,特别是如果你没有使用很多中断并且有几个连续的向量地址没有被使用。您可以通过查看反汇编程序中0x003B(SMB0向量地址)的代码空间来查找。

如果您在正确的时间意外地将某个此类函数的中间位置放在错误位置的中间,您将获取该函数中运行的部分的任何副作用,然后RET在函数结束时会让你回到中断前的位置。除非您没有通过RETI,否则不会清除中断。任何将来相同或更低优先级的中断都将被阻止,因为微观认为您仍在为SMB0中断服务。

您建议NOP可能会替换未实现的处理程序,但由于您的工具链不知道在编译时启用了哪些中断,因此无法执行此操作。如果你没有编写处理程序并在特定的向量地址找到它,那么它假定代码空间的那部分是合理的游戏并且会在那里添加其他东西。

答案 1 :(得分:0)

CPU供应商假设您永远不会忘记编写处理程序,我认为我从来没有看到所有可能的处理程序编写的驱动程序。

我在重新启用Timer4 IT时遇到了使用错误掩码的问题,因此启用了Timer5 IT(在我的情况下为C8051F580)

所以我最终写了一个类似下面的文件。

这在其他答案中是不够的,因为我没有重置每个处理程序中的特定中断(例如清除TF5用于Timer5中断),但它可以让你快速找到错误。

宏SPEC_INT(x)让我在一行中为每个中断创建一个处理程序。注释行对应于我在应用程序代码中实际使用的中断。 每个处理程序调用一个函数int_general_function()

小心,8051不喜欢可重入功能(通常意义上没有堆栈)。当每个处理程序调用相同的函数时,链接器(Keil C51 / BL51)将以 L15 警告警告您。您必须添加到链接器选项,类别覆盖,以下语句

int_general_function!*

为了防止(潜在的)局部变量和(潜在)参数不共享它们在内存中的位置。

#define ALLINTERRUPT_C

#include <my_types.h>
#include <my_platform.h> //contains #include "C8051F580.h"

//A global var
u8 global_unexp_int = 0;

void int_general_function(u8 int_nb)
{
    global_unexp_int = int_nb;

    //Do here other useful things 
    //at least place a breakpoint 
    //if you are in debug
}

#define SPEC_INT(x) \
void i##x (void) interrupt x                \
{                                           \
    int_general_function(x);                \
}

//C8051F580
SPEC_INT(INTERRUPT_INT0)
SPEC_INT(INTERRUPT_TIMER0)
SPEC_INT(INTERRUPT_INT1)
SPEC_INT(INTERRUPT_TIMER1)
//SPEC_INT(INTERRUPT_UART0)
SPEC_INT(INTERRUPT_TIMER2)
SPEC_INT(INTERRUPT_SPI0)
SPEC_INT(INTERRUPT_SMBUS0)
SPEC_INT(INTERRUPT_ADC0_WINDOW)
SPEC_INT(INTERRUPT_ADC0_EOC)
//SPEC_INT(INTERRUPT_PCA0)
SPEC_INT(INTERRUPT_COMPARATOR0)
SPEC_INT(INTERRUPT_COMPARATOR1)
SPEC_INT(INTERRUPT_TIMER3)
SPEC_INT(INTERRUPT_LIN0)
SPEC_INT(INTERRUPT_VREG)
//SPEC_INT(INTERRUPT_CAN0)
SPEC_INT(INTERRUPT_PORT_MATCH)
SPEC_INT(INTERRUPT_UART1)
SPEC_INT(INTERRUPT_PCA1)
SPEC_INT(INTERRUPT_COMPARATOR2)
//SPEC_INT(INTERRUPT_TIMER4)
SPEC_INT(INTERRUPT_TIMER5)

希望它有所帮助...

相关问题