将方法附加到 c++11 中的中断例程

Attaching a method to an interrupt routine in c++11

本文关键字:中断 例程 c++11 方法      更新时间:2023-10-16

我正在为我的嵌入式机器人项目编写一个小框架。我们运行在赛灵思Zynq FPGA(FPGA和ARM Cortex A9嵌入在单个芯片上(

这个想法相对简单。在我的main()中,我想初始化中断,然后从main调用例程(run()方法(。不知何故,当该方法位于代码中的不同位置时,run()方法必须附加到中断。

中断在静态Timer类中初始化。 在initInterrupt()内部附加了interruptRoutine(),它也在Timer类中。 最终,这迫使我们所有代码都必须 interruptRoutine() .

不知何故,我们希望在main.cc文件(在Timer类上方(中有一个run()方法,该方法存储所有逻辑和所有其他函数调用。

我们如何才能做到这一点?

main.cc:

int main() {
    Timer::initInterrupt();
    Timer::run([] {
        // All logic goes here?
        // Very hopeful thinking that this is possible...
    });
}

计时器类:

class Timer {
public:
    static void initInterrupt(void);
    static void interruptRoutine(void*);
    static void run();
};
    /**
     * Initialize main interrupt routine
     */
    void initInterrupt(void) {
    // Declare pointers
    XScuTimer_Config* ConfigPtr;
    XScuGic_Config* IntcConfig;
    // Initialize timers by looking up config and initializing with that config
    ConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID);
    XScuTimer_CfgInitialize(&TimerInstance, ConfigPtr, ConfigPtr->BaseAddr);
    IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
    XScuGic_CfgInitialize(&IntcInstance, IntcConfig,
            IntcConfig->CpuBaseAddress);
    // Initialize exception handling
    Xil_ExceptionInit();
    Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
            (Xil_ExceptionHandler) XScuGic_InterruptHandler, &IntcInstance);
    // Connect interrupt routine to exception handler
    XScuGic_Connect(&IntcInstance, TIMER_IRPT_INTR,
            (Xil_ExceptionHandler) interruptRoutine, (void *) (&TimerInstance));
    // Enable interrupts
    XScuGic_Enable(&IntcInstance, TIMER_IRPT_INTR);
    XScuTimer_EnableInterrupt(&TimerInstance);
    // Enable exception handler
    Xil_ExceptionEnable();
    // Set auto reload so timer reloads when interrupt is cleared
    XScuTimer_EnableAutoReload(&TimerInstance);
    // Set timer value
    XScuTimer_LoadTimer(&TimerInstance, TIMER_LOAD_VALUE);
    // Start interrupt
    XScuTimer_Start (&TimerInstance);
}
/**
 * main interrupt routine
 */
inline void Timer::interruptRoutine(void *CallBackRef) {
    // Define pointer to timer
    XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;
    // If timer is expired, clear interrupt status
    if (XScuTimer_IsExpired(TimerInstancePtr)) {
        XScuTimer_ClearInterruptStatus(TimerInstancePtr);
        // Currently all the application logic is handled in here
    }
}
inline void Timer::run(Callback){
    // We want all our application logic to be handled in here but it has to be called from the main()
}

在计时器类中,添加一个布尔标志"计时器已过"。此标志是从计时器回调设置的。

然后,主程序通过计时器类中的 getter 函数检查此标志。

如果设置了该标志,则main通过计时器类中的 setter 函数清除该标志,然后执行需要执行的代码。

请记住,对标志的访问必须是原子的!假设它不会被中断,这不是 ISR 内部的问题,但它可能是上述 setter/getter 函数内部的问题。

请注意,以上可能是设计中断的最常见方法。您将希望避免从 ISR 内部执行实际代码,除非您的实时要求非常严格。

这是可能的,但您需要一些基元来向Timer::run()方法发出信号。 第一个问题是当前代码没有为计时器中断提供this指针。 您似乎正在使用 xscutimer.h 代码。 你有这个代码,

// Connect interrupt routine to exception handler
XScuGic_Connect(&IntcInstance, TIMER_IRPT_INTR,
        (Xil_ExceptionHandler) interruptRoutine, (void *) (&TimerInstance));

代码片段中不清楚TimerInstance值。 但是,它应该是静态Timer类实例。 此外,Timer::interruptRoutine应该是一种static方法,而不是inline.然后,您的Timer类应该有一个XScuTimer成员。 此外,您需要向 run 方法发出某种信号,理想情况下还需要一个 yield() 类型的函数。 然后运行看起来像,

 Timer::run() {
    while(1) {
     while(no_work)
        wfi();  //ARM typically has a wfi or wait for interrupt.
     // do work
    }
 }

理想情况下,yield的核心是等待中断指令,以最大限度地降低功耗。如果您不关心功耗,您可以旋转no_work。当然,no_work必须设置为falseTimer::interruptRoutine .

no_work变量应该是无锁的或安全的中断。 sig_atomic_t或其他方式(取决于您的工作(是合适的。 要么工具包有这些东西,要么你必须自己实现它们。 请提供您正在使用的 xilinx 库的参考。

这个问题关于全局变量和 ISR 可能很有用。 对于Cortex-A CPU,您可以使用ldrexstrex及其所有注意事项(不像人们想象的那么容易使用(,以实现非常灵活的ISR/主线信令。 根据您的编译器/库,它可能由C++无锁/原子功能或适合 Xilinx 库的功能提供;这些可以在基础实现中使用ldrexstrex,您不必知道使用它们的复杂性。 必须使用MMU才能工作。

这要么比你想象的简单,要么比你解释的更复杂!

Timer::run()做事:-

inline void Timer::run()
{
... complex stuff...
}

中断例程调用run()

inline void Timer::interruptRoutine(void *CallBackRef) {
    // Define pointer to timer
    XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;
    // If timer is expired, clear interrupt status
    if (XScuTimer_IsExpired(TimerInstancePtr)) {
        XScuTimer_ClearInterruptStatus(TimerInstancePtr);
    run();
 }

你想run()从主...

int main() {
    Timer::initInterrupt();
    Timer::run();
}

不清楚是否要避免将run逻辑放在Timer类中?如果是这样,请run()成为Timer实例的抽象虚拟方法,然后从Timer派生MyTimer,并将您的代码添加到其run()方法中。