Arduino/ESP32でプログラムを作成する際のデバッグ方法について。
一番に思い浮かぶのがSerialなどのシリアル通信を使ったもの。
これを使えば、現在の状態などをわかりやすい形で見ることができる。
ただ、シリアル通信を使う場合、データ作成と実際の通信処理に時間がかかってしまうので、外部入力(PIO)で状態遷移やデータ処理などを行うプログラムでは、入力データの時間に比べ、デバッグ用のデータを作成、出力するための処理に時間を使ってしまうため、処理が正しく動かないという本末転倒な状況になってしまう。
そこで、現在の状況を短い処理時間で表現するための方法が求められることになる。
使ったことがないので分からないけど、ICEとか使えればあまり考えなくてもいいのかもしれないが。あとネット検索してみたが、今回のようなケースのデバッグ方法について、ちょっと見つけることができなかった。
そこで今回ロジックアナライザを使うデバッグをやってみた。
普通は、実際にデバイスを操作するピンの状態や外部IOからの受け取る情報を可視化するのがロジックアナライザだが、開発用マイコンの空きピンをデバッグ情報用のピンとして使い、それをロジックアナライザで観察することで、現在のプログラムの状況を可視化するようにした。
実機では使えないかもしれないが、単独クラスの評価位であれば利用できるのではないかな。
以下はデバッグ用のクラスをESP-IDF様に記述したもの。
class DebugPin
{
private:
gpio_num_t pin_[4];
public:
DebugPin(gpio_num_t pin1, gpio_num_t pin2, gpio_num_t pin3, gpio_num_t pin4);
~DebugPin();
void begin();
void pulse(int pin, size_t num = 0);
};
DebugPin::DebugPin(gpio_num_t pin1, gpio_num_t pin2, gpio_num_t pin3, gpio_num_t pin4)
{
pin_[0] = pin1;
pin_[1] = pin2;
pin_[2] = pin3;
pin_[3] = pin4;
}
DebugPin::~DebugPin()
{
}
void DebugPin::begin()
{
gpio_config_t io_conf = {
1ULL << pin_[0] | 1ULL << pin_[1] | 1ULL << pin_[2] | 1ULL << pin_[3],
GPIO_MODE_OUTPUT,
GPIO_PULLUP_DISABLE,
GPIO_PULLDOWN_DISABLE,
GPIO_INTR_DISABLE
};
gpio_config(&io_conf);
}
void DebugPin::pulse(int pin, size_t num)
{
for (auto i = 0; i < num; i++) {
gpio_set_level(pin_[pin], 1);
gpio_set_level(pin_[pin], 0);
}
}
これを、使用する側でpulseを呼び出すことで、ロジックアナライザにパルスが出力される。
パルス部分を拡大すると、以下のような感じ。
デバッグ用のパルス関数の呼び出しは多分500nsぐらいかな。
これくらいであればデバッグ用の情報出力処理時間としては許容範囲かも。
今回のクラスはデバッグ用の情報として4つのピンに対してパルス数を指定可能なようにしている。
現在の内部状態や呼び出された関数に合わせ、ピンやパルス数を指定することで、ロジックアナライザでどのような状態になっているかが判断できる。
ただしパルス数を多くするとそれだけデバッグ用の処理時間が多くなる。そのため、短く済ませたい処理での状態確認には1パルス、そうでないものは複数パルスとするのがいいと思う。
デバッグ以外、実機では中身がからのものに差し替えれば、問題ない?と思う。というか最適化でコード自体がなくなってくれるといいのだけど。
コメント