LPC12xx I2C向量到服务程序

时间:2012-08-31 15:50:29

标签: c embedded

我在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

在中断处理程序中我

  1. 将状态代码添加到内存偏移量(此处为0xABCDEF00)
  2. 将此地址强制转换为函数指针
  3. 并调用该函数。
  4. 我有这个权利吗?我怎么能在C中实现这个?

2 个答案:

答案 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 ;
    }
}