如何避免相似ISR之间的代码重复?

发布于 2024-07-15 20:39:00 字数 1087 浏览 8 评论 0原文

我有两个中断服务例程(ISR),它们的作用基本上完全相同 但每个都处理来自不同设备的中断(尽管是相同类型的设备)。 因此,逻辑是相同的,但它们访问不同的CPU寄存器和内存位置。

作为一个简单的示例,请考虑以下代码:

extern volatile unsigned int dev1_rx_buffer;
extern volatile unsigned int dev2_rx_buffer;

volatile unsigned char data;

void __attribute__((__interrupt__)) _dev1_interrupt(void)
{
    /* Clear interrupt flag */
    dev1.IF = 0;

    if (dev1.IS_FULL) {
         /* Read data from device */
         data = dev1_rx_buffer;
    } else {
         /* do something else using registers of device 1 */
    }
    /* More stuff using registers of device 1 */
}

void __attribute__((__interrupt__)) _dev2_interrupt(void)
{
    /* Clear interrupt flag */
    dev2.IF = 0;

    if (dev2.IS_FULL) {
         /* Read data from device */
         data = dev2_rx_buffer;
    } else {
         /* do something else using registers of device 2 */
    }
    /* More stuff using registers of device 2 */
}

How can I避免代码重复与适用于 ISR 的限制 (即我无法将参数传递给 ISR,并且应避免函数调用 因为他们的开销)。

我曾考虑编写一个模板,使用高级脚本语言生成两个 ISR,但我更喜欢仅使用 C 或 C 预处理器宏的解决方案。

I have two interrupt service routines (ISR) which basically do the exact same
thing but each handles an interrupt from a different device (although the same type of device). Therefore, the logic is the same but they access different CPU registers and memory locations.

As a simple example consider the following code:

extern volatile unsigned int dev1_rx_buffer;
extern volatile unsigned int dev2_rx_buffer;

volatile unsigned char data;

void __attribute__((__interrupt__)) _dev1_interrupt(void)
{
    /* Clear interrupt flag */
    dev1.IF = 0;

    if (dev1.IS_FULL) {
         /* Read data from device */
         data = dev1_rx_buffer;
    } else {
         /* do something else using registers of device 1 */
    }
    /* More stuff using registers of device 1 */
}

void __attribute__((__interrupt__)) _dev2_interrupt(void)
{
    /* Clear interrupt flag */
    dev2.IF = 0;

    if (dev2.IS_FULL) {
         /* Read data from device */
         data = dev2_rx_buffer;
    } else {
         /* do something else using registers of device 2 */
    }
    /* More stuff using registers of device 2 */
}

How can I avoid the code duplication with the restrictions that apply to ISRs
(i.e. I cannot pass parameters to the ISRs and function calls should be avoided
because of their overhead).

I have thought of writing a template from which to generate the two ISRs using a higher level scripting language, but I'd prefer a solution using only C or C preprocessor macros.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

扭转时空 2024-07-22 20:39:00

在这种情况下,我通常让 ISR(向量入口点)的前端设置一个指向设备特定块的指针,然后使用指向该块的指针调用公共代码。

粗略地(不用担心 ISR 语法等)

void __attribute__((__interrupt__)) Isr1(void)
{
   CommonISR(&dev1info);
}

void __attribute__((__interrupt__)) Isr2(void)
{
   CommonISR(&dev2info);
}

void CommonISR(Foo *devptr)
{
    devptr->count = 0;
    devptr->reset();
    etc...
}

dev1info 和 dev2info 在启动时配置/初始化; 他们可能有指向硬件寄存器的指针,等等......

In cases like this I usually have the front-end of the ISR (vector entry point) set up a pointer to a device specific block, and then call the common code with a pointer to that block.

Roughly (not worrying about ISR syntax etc.)

void __attribute__((__interrupt__)) Isr1(void)
{
   CommonISR(&dev1info);
}

void __attribute__((__interrupt__)) Isr2(void)
{
   CommonISR(&dev2info);
}

void CommonISR(Foo *devptr)
{
    devptr->count = 0;
    devptr->reset();
    etc...
}

dev1info and dev2info are configured/initialized at startup; they might have pointers to HW registers, etc...

屌丝范 2024-07-22 20:39:00

为什么不使用内联辅助函数来获取指向设备和缓冲区的指针?

不过,我会检查生成的程序集以确保编译器执行我所期望的操作。

您也可以使用宏,但恕我直言,对于这么长的函数执行此操作并不好。

Why don't you use an inline helper function which gets pointers to the device and the buffer?

I would check the generated assembly to make sure the compiler does what I expect, though.

You could also use a macro, but IMHO it is not good to do this for functions this long.

蛮可爱 2024-07-22 20:39:00

如果它们处理相同类型的设备,那么只有一个中断处理程序处理多个中断是相当合理的。 您可以检查顶部设置了哪个标志并从那里继续。 但是,如果两个中断处理程序适用于不同类型的设备并且具有相同的逻辑流程,我不建议这样做。

If they are handling the same type of device it's quite reasonable to have just one interrupt handler handling multiple interrupts. You could check which flag was set at the top and continue on from there. However, I wouldn't recommend this if the two interrupt handlers are for different types of devices and just have the same logic flow.

英雄似剑 2024-07-22 20:39:00

您确定您的编译器不会优化函数调用吗?
您绝对可以使用宏来自动生成此代码,但它会有点难看 :

#define __CONCAT(a,b)    a ## b

#define ISR_DECLARE(name) \
\
void __attribute__((__interrupt__)) _CONCAT(name,_interrupt)(void) \
{ \         
    /* Clear interrupt flag */ \
    name.IF = 0; \
    \
    if (name.IS_FULL) \
    { \
        /* Read data from device */ \
        data = _CONCAT(name, _rx_buffer); \
    } \
    else \
    { \
        /* do something else using registers of device 1 */ \
    }\ 
    /* More stuff using registers of device 1 */ \

}

然后:

ISR_DECLARE(dev_1)

ISR_DECLARE(dev_2)

但我强烈建议首先检查您的编译器是否会使用内联优化代码,如之前的帖子中所建议的。

are you sure that your compiler will not optimize a function calls ?
You definitely can use a macros to generate this code automatically, but it will be a bit ugly :

#define __CONCAT(a,b)    a ## b

#define ISR_DECLARE(name) \
\
void __attribute__((__interrupt__)) _CONCAT(name,_interrupt)(void) \
{ \         
    /* Clear interrupt flag */ \
    name.IF = 0; \
    \
    if (name.IS_FULL) \
    { \
        /* Read data from device */ \
        data = _CONCAT(name, _rx_buffer); \
    } \
    else \
    { \
        /* do something else using registers of device 1 */ \
    }\ 
    /* More stuff using registers of device 1 */ \

}

and then:

ISR_DECLARE(dev_1)

ISR_DECLARE(dev_2)

But i would strongly suggest to check first if your compiler will optimize the code using inline, as suggested in previous posts.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文