コードの内容を見直しと、なぜか逆アセンブラを作ってみました。最新情報はM5StickC非公式日本語リファレンスをみてください。
サンプルコード
#include "esp32/ulp.h" #include "driver/rtc_io.h" #include "ulputil.h" // スローメモリー変数割当 enum { SLOW_BLINK_STATE, // Blinkの状態保持 SLOW_PROG_ADDR // プログラムの先頭アドレス }; void ULP_BLINK(uint32_t us) { // ULPの起動間隔を設定 ulp_set_wakeup_period(0, us); // メモリ初期化 memset(RTC_SLOW_MEM, 0, 8000); // 変数初期化 RTC_SLOW_MEM[SLOW_BLINK_STATE] = 0; // ブリンクするPIN(14bitオフセットして指定する) const int pin_blink_bit = RTCIO_GPIO26_CHANNEL + 14; const gpio_num_t pin_blink = GPIO_NUM_26; // GPIO26の初期化(出力に設定して初期値0) rtc_gpio_init(pin_blink); rtc_gpio_set_direction(pin_blink, RTC_GPIO_MODE_OUTPUT_ONLY); rtc_gpio_set_level(pin_blink, 0); // ULPプログラム const ulp_insn_t ulp_prog[] = { I_MOVI(R3, SLOW_BLINK_STATE), // R3 = SLOW_BLINK_STATE I_LD(R0, R3, 0), // R0 = RTC_SLOW_MEM[R3(SLOW_BLINK_STATE)] M_BL(1, 1), // IF R0 < 1 THAN GOTO M_LABEL(1) // R0 => 1の時実行 I_WR_REG(RTC_GPIO_OUT_REG, pin_blink_bit, pin_blink_bit, 1), // pin_blink_bit = 1 I_MOVI(R0, 0), // R0 = 0 I_ST(R0, R3, 0), // RTC_SLOW_MEM[R3(SLOW_BLINK_STATE)] = R0 M_BX(2), // GOTO M_LABEL(2) // R0 < 1の時実行 M_LABEL(1), // M_LABEL(1) I_WR_REG(RTC_GPIO_OUT_REG, pin_blink_bit, pin_blink_bit, 0),// pin_blink_bit = 0 I_MOVI(R0, 1), // R0 = 1 I_ST(R0, R3, 0), // RTC_SLOW_MEM[R3(SLOW_BLINK_STATE)] = R0 M_LABEL(2), // M_LABEL(2) I_HALT() // プログラム停止 }; // 変数の分プログラムを後ろにずらして実行 size_t size = sizeof(ulp_prog) / sizeof(ulp_insn_t); ulp_process_macros_and_load(SLOW_PROG_ADDR, ulp_prog, &size); ulp_run(SLOW_PROG_ADDR); } void setup() { // デバッグ出力用 Serial.begin(115200); // 300ms間隔でULPプログラムを実行 ULP_BLINK(300000); } void loop() { // デバッグ出力 ulpDump(0, 20, SLOW_PROG_ADDR); delay(1000); }
元にしたソースはesp32 ulp programmingですが、デクリメントとかインクリメントとかしていましたが、コストを調べると直値のMOVEと同じだったので、0と1を直接代入するように買えています。
変数もenumで最初に定義して、プログラムのロード場所と実行開始のアドレスを指定しています。
デバッグしていて、なぜか逆アセンブラも作っていました。
0000 : 00C30000 DATA 0 // ST ADDR:0x0006 0001 : 72800003 PROG MOVE R3, 0 // R3 = 0 0002 : D000000C PROG LD R0, R3, 0 // R0 = MEM[R3+0] 0003 : 820A0001 PROG JUMPR + 5, 1, LT // IF R0 < 1 THAN GOTO 0x0008 0004 : 1AD40500 PROG REG_WR 0x0000, 21, 21, 1 // RTC_IO[21:21] = 1 0005 : 72800000 PROG MOVE R0, 0 // R0 = 0 0006 : 6800000C PROG ST R0, R3, 0 // MEM[R3+0] = R0 0007 : 8000002C PROG JUMP 0x000B // GOTO 0x000B 0008 : 1AD40100 PROG REG_WR 0x0000, 21, 21, 0 // RTC_IO[21:21] = 0 0009 : 72800010 PROG MOVE R0, 1 // R0 = 1 000A : 6800000C PROG ST R0, R3, 0 // MEM[R3+0] = R0 000B : B0000000 PROG HALT // HALT 000C : 00000000 PROG NOP // NOP 000D : 00000000 PROG NOP // NOP 000E : 00000000 PROG NOP // NOP 000F : 00000000 PROG NOP // NOP 0010 : 00000000 PROG NOP // NOP 0011 : 00000000 PROG NOP // NOP 0012 : 00000000 PROG NOP // NOP 0013 : 00000000 PROG NOP // NOP
こんな感じの出力がシリアルにでます。一番先頭の変数は書き込まれる場所が2箇所あって、上位16ビットでどこから書き込まれたのかがわかります。上記の場合には0x0006で0(消灯)に設定した状態の出力です。
0000 : 01430001 DATA 1 // ST ADDR:0x000A
もう一箇所はADDR:0x000Aで1(点灯)に設定しています。
まだ使っている命令だけしかキレイにしていないので、もうちょっと手を入れたらライブラリとして公開しようかな。
まとめ
いろいろ中を見ていました、Arduinoから使えるマクロだと、全命令をサポートしていないですね。ステージカウントレジスタを使っている命令が全滅でした。ループのカウンターで使うと便利そうなのですが、まあなくても他のレジスタ使えばなんとかなるはずです。
コメント