調査きっかけ
E-TTL2-通信の解析3で解析用プログラムを作ったのち、このプログラムとEOS ストロボ光通信5で作成したプログラムを合体させて、E-TTL2のリモコン送信機が作れないかを考えていた。
通信の解析では、GPIOの割り込みを使って実現をしていたのだが、合体させる場合、CLKの立上がり、立下りの両エッジを認識して処理しないといけないことが分かった。
ただ、標準の割り込みの場合、約2μsの遅延が発生するため、処理が間に合わなくなるのでは?という懸念が出てきた。
遅延をなくすにはどうしたらいいか、検索したら一応以下のものがヒットした。
ただ、「ここからCルーチンの呼び出しはしないでください」となっていたのでそのままでは使えず、さらに探したところ、割り込みを使わずループ内でGPIOのレジスタアクセスで処理可能という記事を見たので、ちょっとそっち関連を調べてみた。
処理方法
“esp32 gpio direct access”でググれば結構な情報が出てきた。
driver/gpio.hをインクルードし、GPIO外部変数を使用することでアクセスは可能だということは分かった。
注意点はアトミックではないこと。複数コアでアクセスする場合には排他制御が必要かもしれない。
一番簡単な実装は以下のようになる。
14番ピンを出力ポートにして、High/Low繰り返している。
#include "driver/gpio.h"
const gpio_num_t OutputPort = GPIO_NUM_14;
extern "C"
void app_main()
{
gpio_pad_select_gpio(OutputPort);
gpio_set_direction(OutputPort, GPIO_MODE_OUTPUT);
GPIO_Clear(OutputPort);
for (;;) {
GPIO.out_w1ts = 1 << OutputPort;
GPIO.out_w1tc = 1 << OutputPort;
}
}
パフォーマンス
CPUを80MHz、160MHz、240MHzと変えて、High/Lowの周期を見てみた。
周波数 | 時間 | |
80MHz | 170ns | |
160MHz | 130ns | |
240MHz | 100ns |
これを見ると、周波数による比率になっているわけではなさそうだった。
処理時間についての考察
ループ部分だけを逆アセンブルすると、以下のような感じになっていた。
書き込みはs32i.n命令で行っているが、前後にmemwという命令が入っていた。
xtensaのマニュアルを見る限り、memwは超訳するとフラッシュ命令みたいなものらしい。
なので、その処理時間がどれくらいかかるかというのは状況によりかなり変わるらしい。
これに関しては、以下のフォーラムの質問にも回答が寄せられている。
おおざっぱだけど、「memwは何サイクルかかるの?」という質問に対して、「フラッシュにかかる時間だから正確な時間はわかんないよ」というものだった。
memwによるオーバーヘッド?が入るため、周波数による倍率比というわけではなかったようだ。
ピン入力の検出
もともとの目論見である、ピンへの入力に対してどれぐらいの反応速度が得られるかという部分について。
for文の中身を以下のよう感じで、InputPortの入力に変化があったらパルスを出すというような形にして見た。
for (;;) {
level = GPIO.in & (1 << InputPort);
if (level != prevLevel) {
GPIO.out_w1ts = 1 << OutputPort;
GPIO.out_w1tc = 1 << OutputPort;
prevLevel = level;
}
}
ちょっと見ずらいが、下段に変化があったら、上段にパルスを出すという形になっている。
80MHzの場合最大で500ns、240MHzの場合150nsという結果になった。
こちらは結構な開きがあった。
標準の割り込み処理を使った場合、2μsの遅延があったのでそれに比べれば短い遅延時間で入力ピンの変化を取り出せることが分かった。
コメント