malloc-in-isr-cause-hangup-raspberry-pi-pico-and-arduino-ide

Raspberry Pi Pico と Arduino IDE で割り込みを使うとハングアップ

この記事では Raspberry Pi Pico + Arduino IDE の組み合わせで割り込みを使うとハングアップする現象の原因を説明します。結論からいえば、割り込みハンドラ内で digitalWrite を使うとハングアップすることがあります。この原因は digitalWrite がメモリ確保(newmalloc)を行うことです。

使用するボードコア

Arduino Mbed OS RP2040 Boards 4.1.1

Arduino IDE は、個別に用意された「ボードコア」をインストールすることで、各 Arduino やその他マイコンボードの開発に対応します。この記事の内容は Arduino 公式で用意されているボードコア「Arduino Mbed OS RP2040 Boards」のバージョン 4.1.1 で検証しました。

ハングアップとは

この記事でいう「ハングアップ」は、Raspberry Pi Pico が Arduino IDE と通信できなくなる、プログラムを書き込めなくなる現象を意味しています。Raspberry Pi Pico がハングアップすると、オンボード LED(ピン 25)が 4 回高速点滅(約 1 秒に 4 回)、4 回低速点滅(約 3 秒に 4 回)を繰り返します。

いったんハングアップしてしまうと Raspberry Pi Pico 上のスケッチの動作が停止し、Arduino IDE のシリアルモニタでの通信もできなくなり、プログラムを書き込むこともできなくなります。ハングアップから復帰するには、USB ケーブルを抜き、BOOTSEL ボタンを押したままケーブルを挿し、Arduino IDE から再度(ハングアップしないよう修正した)プログラムを書き込む必要があります。

ハングアップの検証

次のコードで検証しました。このコードの期待動作としては、起動後 2 秒でオンボード LED が点灯し、以後ずっと点灯状態になったまま、というものです。実際、次のコードをそのまま実行するとそのような動作になると思います。setup() の中の digitalWrite() 呼び出しをコメントアウトすると、起動後 2 秒でハングアップするようになります。

#include <mbed.h>

mbed::Timeout t;

void callback() {
  digitalWrite(25, 1);
}

void setup() {
  digitalWrite(25, 0); // ここをコメントアウトするとハングアップ
  t.attach(callback, 2);
}

void loop() {
  // put your main code here, to run repeatedly:
}

digitalWrite() の実装は wiring_digital.cpp にあります。この実装を見ると、あるピンへの初回の読み書きでは gpio 変数が NULL となり、new が実行されるらしいことが分かります。これがハングアップの原因でしょうか。

試しに digitalWrite() を割り込みハンドラの中で呼ばず、純粋にメモリ確保を行うスケッチで追加検証しました。

#include <mbed.h>

mbed::Timeout t;
int *ip;

void callback() {
  if (ip == 0) {
    ip = (int*)malloc(4);
  }
}

void setup() {
  t.attach(callback, 2);
}

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(25, ip != 0);
}

このスケッチでもハングアップが起きました。USB ケーブルを抜き挿しして Raspberry Pi Pico を再起動すると、きっかり 2 秒後に LED がハングアップを知らせる点滅に変わりました。

ハングアップの原因

さらに (int*)malloc(4)new int(…) に置き換えてもハングアップが再現します。以上から、割り込みハンドラ内でメモリ割り当てを行うとハングアップすると結論づけました。



この記事を参照しているブログ内記事はありません。

作成:2024-05-10 10:27:55

最終更新:2024-05-10 10:27:55