ESP32-gpio_isr_registerを使ったGPIO割り込み

タイマーとGPIOの割り込みを使ったクラスを作っていたところ、どうしてもタイマー割り込みルーチンに入ってこない状況になってしまった。
当初、タイマー割り込みの使い型が悪いのかと思い、そちらの方のサンプルを作って確認していたのだが、問題はあったのだが、使えるような実装ができたので、その内容を反映し試したがだめだった。

そこで、GPIOの割り込みルーチンに再度的を絞って調査したところ、一度割り込みが発生すると、その後ずっと割り込みが発生してしまう状況だったことが分かった。

具体的には以下のようなイメージ。
1段目はロジアナのデータ取得開始のためのパルスで2段目が4段目の立ち上がりエッジを検出してパルスを出すといったもの。

想定しているのは、黄色のような部分の立ち上がりエッジだけパルスが発生するというもの。実際には、1度目の黄色立上りの検出以降すぐにかつ連続して割り込みが発生してしまっていた。

割り込みの登録は以下のようなコード。クラス名はGpioIntrとしている。

gpio_set_intr_type(clk_, GPIO_INTR_POSEDGE);
gpio_isr_register(GpioIntr::pinIntr, (void*)this, ESP_INTR_FLAG_IRAM, nullptr);

割り込みルーチンは以下に示す。

IRAM_ATTR void GpioIntr::pinIntr(void* user)
{
    auto work = (GpioIntr*)user;
    work->pinAction();
}
void GpioIntr::pinAction()
{
    debug_.pulse(1, 1);
}

この問題について検索してみたが情報はなく、タイマー割り込みでステータスクリアをするコードを呼んでいたのを思い出し、同様なものがないかを調べたが存在せず。
苦肉の策で、割り込み処理内の上のソースでいうとdebug_.pulse(1, 1);の後にgpio_intr_enable(clk_);を呼び出したところ、以下の様な想定通りの動作になった。
ただこれでなぜ正常に動作するのかは不明。github中のgpio_intr_enableのソースを見てもちょっと追えなかった。

またこの件、EPSのAPIやリファレンスマニュアルも見たのだが、注意書きなどの記載もなかった。

なお、gpio_isr_handler_add()を使った割り込み関数の呼び出し方法を使った場合は、問題なく想定通りの動作になった。
なのでgpio_isr_register()は使わない方が正解なのだろう。サンプルもgpio_isr_handler_add()を利用したものだったし、gpio_isr_register()での登録GPIOすべての割り込みで共通なので使いづらいだろうし。

コメント

タイトルとURLをコピーしました