コードの内容を見直しと、なぜか逆アセンブラを作ってみました。最新情報は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から使えるマクロだと、全命令をサポートしていないですね。ステージカウントレジスタを使っている命令が全滅でした。ループのカウンターで使うと便利そうなのですが、まあなくても他のレジスタ使えばなんとかなるはずです。



コメント