我在C中实现“矢量到服务例程”时遇到了一些问题。
现在我实现I2C接口的IRQ-Handler,如下所示:
void I2C0_IRQHandler(void)
{
statusCode = LPC_I2C->STAT;
switch ( statusCode ) { (...) }
}
许多状态代码都很慢,因此必须访问所有案例。
LPC12xx微控制器的用户手册提供了一个提示:
如果状态代码用作服务向量 例程,然后例程被八个地址位置取代。 对于大多数服务例程来说,八个字节的代码就足够了
所以我应该编写一些处理程序函数,每个函数只有8个字节的代码大小,并将它们放在正确的内存位置:
0xABCDEF00: handler_for_code_0x00
0xABCDEF08: handler_for_code_0x08
(...)
0xABCDEF90: handler_for_code_0x90
在中断处理程序中我
我有这个权利吗?我怎么能在C中实现这个?
答案 0 :(得分:1)
在C中这样做很难。我可以想到两个解决方案:
(1)使用asm创建8字节处理函数表,其中每个处理程序只是跳转到C函数,例如
org 0xABCDEF00
jmp handler_for_code_0x00
org 0xABCDEF08
jmp handler_for_code_0x01
...
org 0xABCDEF90
jmp handler_for_code_0x1f
(2)不是使用向量中断,而是保留当前的方案,但是使用函数指针创建跳转表(假设您的编译器还不够智能,无法从switch语句生成跳转表),例如
typedef void (*handler_fn)(void);
static void handler_for_code_0x00(void) { ... }
static void handler_for_code_0x01(void) { ... }
...
static void handler_for_code_0x1f(void) { ... }
static void handler_for_code_unused(void) { ... }
const handler_fn handler_table[NUM_STATUS_CODE] = {
handler_for_code_0x00,
handler_for_code_0x01,
handler_for_code_unused,
handler_for_code_0x03,
handler_for_code_0x04,
...
handler_for_code_0x1d
handler_for_code_unused,
handler_for_code_0x1f
};
void I2C0_IRQHandler(void)
{
statusCode = LPC_I2C->STAT >> 3 ; // Get table index
handler_table[statusCode]();
}
答案 1 :(得分:1)
您如何确定switch
会因其他情况减慢?
大多数编译器都会生成一个确定性的跳转表,当然不会“访问”每个案例。您可以帮助编译器生成有效的代码,方法是确保案例在数值上是顺序的,而不是稀疏分离(即值之间没有间隙)。
只有32个可能的状态代码,所以带有所有代码的情况的详尽开关(即使情况为空)也可能并不令人望而却步。 STAT
的前三位未使用,因此如果您首先将状态向右移位三位以使状态值从零开始,那么也可以使编译器生成更高效的代码。我实际上希望它能生成一个相当于@Dill建议的跳转表(这将是我的建议)。
以下是大多数编译器经过优化的惯用示例,只需将代码添加到您明确要处理的情况中。如果您的编译器没有生成确定性代码,请尝试使用编译器优化级别。但是,如果它不能这样做,我会考虑使用不同的编译器!
void I2C0_IRQHandler(void)
{
switch( LPC_I2C->STAT >> 3 )
{
case 0x01 :
break ;
case 0x02 :
break ;
case 0x03 :
break ;
case 0x04 :
break ;
case 0x05 :
break ;
case 0x06 :
break ;
case 0x07 :
break ;
case 0x08 :
break ;
case 0x09 :
break ;
case 0x0a :
break ;
case 0x0b :
break ;
case 0x0c :
break ;
case 0x0d :
break ;
case 0x0e :
break ;
case 0x0f :
break ;
case 0x10:
break ;
case 0x11 :
break ;
case 0x12 :
break ;
case 0x13 :
break ;
case 0x14 :
break ;
case 0x15 :
break ;
case 0x16 :
break ;
case 0x17 :
break ;
case 0x18 :
break ;
case 0x19 :
break ;
case 0x1a :
break ;
case 0x1b :
break ;
case 0x1c :
break ;
case 0x1d :
break ;
case 0x1e :
break ;
case 0x1f :
break ;
}
}