静态模板成员函数作为中断服务程序

问题描述 投票:0回答:2

在下面的Mapper类中,静态成员函数timer0CompA作为中断服务程序。它在中断向量中获得名称“__vector_14”。

struct Mapper {
    static void timer0CompA() __asm__("__vector_14") __attribute__((__signal__, __used__, __externally_visible__));  
};
void Mapper::timer0CompA(){}

如果我尝试对模板类使用相同的方法

template<typename T>
struct Mapper {...};

模板成员函数未插入到中断向量中。

我知道如果它能工作的话将会有问题:不同的实例化将在汇编代码中获得相同的名称,因此我们将得到一个双重定义的符号。但就我而言,这很有用......

有什么提示吗?

c++ templates interrupt avr
2个回答
0
投票

运行时解决方案,并不完全是最佳的:

  1. 禁用设备上的中断。
  2. 建立一个中断数组,您将使用与 isr 向量数组相同的格式。
  3. 覆盖 ISR 闪存部分。确保保存 Flash 页面未使用的部分并将其写回。
  4. 重新启用设备上的中断。

但是,由于您需要一次编写整个 Flash 页面,因此您最好一次完成所有操作。

注意:您可能会发现自己意外覆盖了应用程序代码,因此请确保用于执行更改的函数不在闪存的该部分中,并且写回不使用的页面部分。


0
投票

gcc 和 clang 在使用

__asm__()
__attribute__((signal))
与类模板成员函数时似乎都有点不一致。

第一

__asm__()
.

  • GCC - 默默地忽略模板类中方法的
    __asm()
    。据我所知根本没有任何影响。适用于静态和非静态成员。
  • Clang - 尊重它,并将在模板类的all实例中为成员提供请求的名称。这意味着如果您多次实例化模板,您将收到编译错误,多个定义具有相同的损坏名称。

有一种方法可以同时适用于两者:

__asm()
在模板方法的显式特化中,gcc 和 clang 都遵循这种方法。您可以通过在每个专业化中为其指定不同的 __asm() 名称来多次实例化模板。

示例:

template <typename T>
class foo {
    static void f();
    // We put the real code in _f, each specialization of f() will
    // just call _f() to avoid re-writing the code.
    static inline void _f() { /*code*/ };
};

// Can only add __asm to a declaration, not a definition
template <> void foo<int>::f() __asm("__vector_1");
template <> void foo<int>::f() { foo<int>::_f(); }

template <> void foo<char>::f() __asm("__vector_2");
template <> void foo<char>::f() { foo<char>::_f(); }

上面的内容为您提供了在 clang 和 gcc 上具有正确的损坏符号名称的方法。

_f()
中的实际方法代码将内联到
f()
中,因此额外的函数不需要任何成本。

下一个

__attribute__((signal/interrupt))
:

属性

signal
仅在AVR上支持,而godbolt上没有Clang AVR,所以我使用了
interrupt
,这也是一个ISR,但与AVR“信号”类型略有不同。

这与

__asm()
上的处理方式相同。 Gcc 会在模板类方法上默默地忽略它,而 clang 会尊重它。

所以我们可以调整上面的例子来使其工作:

template <> void foo<int>::f() __asm("__vector_1") __attribute__((interrupt));
template <> void foo<char>::f() __asm("__vector_2") __attribute__((interrupt));

__attribute__((used))
还有另一个怪癖:如果将其放入类模板中,则尝试专门化该方法会失败。似乎在专业化中命名类足以定义“已使用”的类方法,然后专业化会尝试再次定义相同的方法。解决方案是仅在专业化中添加属性:

// This fails
class bar {
    static void f() __attribute__((used));
};
template <> void bar<int>::f();

// error: explicit specialization of 'f' after instantiation
// template <> void bar<int>::f();
//                            ^
// implicit instantiation first required here
// template <> void bar<int>::f();
//                  ^

// This works
class bar {
    static void f();
};
template <> void bar<int>::f() __attribute__((used));
© www.soinside.com 2019 - 2024. All rights reserved.