2016-04-19 9 views
0

私は組み込みロボットプロジェクト用の小さなフレームワークを作成しています。ザイリンクスのZynq FPGA(FPGAとARM Cortex A9を1チップに内蔵)を使用しています。C++の割り込みルーチンにメソッドをアタッチする

アイデアは比較的単純です。私のmain()では、私は割り込みを初期化して、メインから同様にルーチン(run()メソッド)を呼び出す必要があります。何らかの形で、run()メソッドは、コード内の別々の場所にある間に割り込みにアタッチする必要があります。

割り込みは、スタティックTimerクラスで初期化されます。 initInterrupt()の内部には、が付属しており、Timerクラスにも含まれています。最終的には、すべてのコードをinterruptRoutine()の範囲で実行する必要があります。

どういうわけか、run()メソッドをmain.ccファイル(Timerクラスより上)に入れて、すべてのロジックと他のすべての関数呼び出しを格納したいとします。

これをどのように達成できますか?

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() 
} 

答えて

0

どちらかこれはあなたが説明してきたよりも、あなたが思うよりも簡単、またはより複雑です!どうかは明らかではありません

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(); 
} 

- :

Timer::run()はものを行いますを置くことを避けたいTimerクラス内のロジック?その場合は、run()Timerインスタンスの抽象仮想メソッドにしてから、TimerからMyTimerを派生させ、そのコードにrun()メソッドを追加します。

+0

私はそれが私が説明したより少し複雑だと思う。私は私の 'Timer'クラスがどんなロジックについて何かを知ることを望んでいません。それはSRPに続く。メインはすべての権限を委譲しますが、私は何とか割り込みでそのコードをすべて実行する必要があります。問題は、私が今ここで行うことができる唯一の場所は 'interruptRoutine()'の 'Timer'クラスの中にあることです。 – Ortix92

+0

@ Ortix92 - 私が言及した派生クラスの仮想メソッドはどうですか?それはあなたのために働くだろうか?それ以外の場合は、通常のコールバック関数を使用してください。 – Roddy

1

タイマークラスでは、ブーリアンフラグ "timer elapsed"を追加します。このフラグは、タイマーコールバックから設定されます。

メインプログラムは、タイマークラスのゲッター機能を使ってこのフラグをチェックします。

フラグが設定されている場合、mainは、タイマークラスのセッター機能を使用してフラグをクリアしてから、実行する必要があるコードを実行します。

フラグへのアクセスはアトミックでなければならないことにご注意ください!中断されることはないと仮定してISR内部からの問題ではありませんが、前述のセッター/ゲッター関数内で問題となる可能性があります。

これはおそらく割り込みを設計する最も一般的な方法であることに注意してください。リアルタイムの要件が非常に厳しい場合を除き、ISRの内部から実際のコードを実行しないようにします。

+0

私たちは約20kHzでサンプリングしているので、リアルタイム要件はちょっと厳しいですが、間違いなく試してみます。おそらくこれを実装する方法のサンプルコードを少し表示できますか?ありがとう! – Ortix92

1

これも可能ですが、割り込みハンドラから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::interruptRoutinestaticメソッドであり、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_workTimer::interruptRoutinefalseに設定する必要があります。

no_work変数はロックフリーまたは割り込みセーフでなければなりません。 sig_atomic_tまたは他の手段(あなたの仕事に応じて)が適切です。ツールキットにはこれらの機能があります。または、自分で実装する必要があります。あなたが使用しているザイリンクスライブラリへの参照を与えてください。

この質問はglobal variable and ISRに役立つ場合があります。 Cortex-A CPUの場合、かなり柔軟なISR /メインラインシグナリングのために、ldrexstrexをすべての注意点(人々が思うほど簡単ではない)で使用することができます。コンパイラ/ライブラリに応じて、C++ lock-free/atomicの機能またはザイリンクスライブラリに適したものによって提供される場合があります。これらは基本的な実装でldrexstrexを使用することができ、それらの使用の複雑さを知る必要はありません。彼らが働くには、MMUが使用されていなければなりません。

+0

私のコードを更新しました。私は本当に 'initInterrupt()'でコードの塊を見逃していました。あなたが提案したことを間違いなく見ていきます。しかし、それでも、すべての作業はTimerクラス内で行われているようです。これは私が避けようとしているもの(読みやすさとコードの構造)です。 – Ortix92

+0

'Timer'にコードを入れたくない場合は、' initInterrupt() 'や' Timer :: run() 'メソッドに情報を渡す必要があります。単に 'Timer :: waitToRun()'と呼ぶことができます。これはあなたの 'main()' ... 'while(Timer :: waitToRun()){/ * main code * /}'にコードを置きます。実行するコードを渡したいと思うようです。おそらく多くの人々がgrokのために物事を遅くし、確かにもっと複雑にする多くの派手なC++構文を除いて、その利益を見ていないのですか? –