06/06(日) ESP32-ULP実装-トイレ設置してみる

電池稼働させたかったので電力消耗を抑える必要があり、ULPで実装。初代ESPを使っていたので最近の情報が違うことが多く苦労する。
初代ESP32は platform = espressif32@5.4.0 にする必要あり。また *.S ファイルによるアセンブラからの実装も不可。なんとかFSMマクロで作成して、とりあえずトイレに光センサーでロギング&Zabbixへ送信できるようにしたものをトイレへ設置

センサー値が移動平均を大きく乖離した時に発動する例

        I_MOVI(R1, adc_no),                 // [0]  //処理中ADCを保存
        I_MOVI(R2, MYULP_ADC_EVENT_SOURCE), //
        I_ST(R1, R2, 0),
        I_DELAY(20),          // 一発目は捨て
        I_ADC(R0, 0, adc_no), // ADC
        I_STAGE_RST(),        // カウンタリセット [5]
        I_MOVI(R3, 0),        // 累計地 R3 クリア
        I_DELAY(20),          // -4 <--
        I_ADC(R0, 0, adc_no), // -3
        I_ADDR(R3, R3, R0),   // -2
        I_STAGE_INC(1),       // -1  [10]
        I_JUMPS(-4, 4, JUMPS_LT), I_RSHI(R3, R3, 2),
        // VALUE の書き込み
        I_MOVR(R0, R3),             // R0 <- R3 へ退避
        I_MOVI(R2, addr_adc_value), // 値保存
        I_ST(R0, R2, 0),            // [15]
        // 移動平均(4ビットシフトなので16回)
        I_MOVI(R1, addr_avg_value), I_LD(R2, R1, 0), // R2 = avg
        //
        // avg>>4
        //
        I_RSHI(R3, R2, 4), // R3 = avg/16
        //
        // current>>4
        //
        I_RSHI(R0, R0, 4), // R0 = current/16
        //
        // avg = avg - avg/16
        //
        I_SUBR(R2, R2, R3),
        //
        // avg = avg + current/16
        //
        I_ADDR(R2, R2, R0),
        //
        // avg保存
        //
        I_MOVI(R1, addr_adc_value),     // [20]
        I_LD(R0, R1, 0),            // R0 <-- 計測値復帰
        I_MOVI(R1, addr_avg_value), 
        I_LD(R2, R1, 0),            // R2 .. 平均値

        I_MOVI(R1, addr_threshold),
        I_LD(R3, R1, 0),             // R3 <-- MYULP_ADC_THRESHOLD [25]

        I_ADDR(R1, R2, R3),         // R1 <-- 平均値R2 + 閾値R3 許容値境地最大
        I_SUBR(R0, R0, R1),         // R0 <- R0 - R1  
        I_BGE(3,0x7fff), // I_BL(2,1) は 許容値最大のほうが大きい
        I_WAKE(),
        //I_HALT(),
        I_BXI(start_addr + 37),         // [30]
        I_MOVI(R1, addr_adc_value), 
        I_LD(R0, R1, 0),            // R0 <-- 計測値復帰
        I_SUBR(R1, R2, R3),         // R1 <-- 平均値R2 - 閾値R3 許容値境地最小
        I_SUBR(R0, R1, R0),         // R0 <- R1 - R0  
        I_BGE(2,0x7fff), // I_BL(2,1) は 許容値最小のほうが小さい
        I_WAKE(),
        I_HALT()                        // [37]

照度センサーなどで、日中の明るさが断続的に変わる場合でも、光の変化を検知したい場合。
16回移動平均値を常に計算してそこから閾値分ずれた時点でWAKEさせる。

ULP:センサー閾値を動的に変化させつつ、で以上、以下を切り替える例

        // 指定されたADCチャンネルから値を読み込む (R0に結果が入る)
        I_MOVI(R1, adc_no),                 // [0]  //処理中ADCを保存
        I_MOVI(R2, MYULP_ADC_EVENT_SOURCE), //
        I_ST(R1, R2, 0),
        I_DELAY(20),          // 一発目は捨て
        I_ADC(R0, 0, adc_no), // ADC
        I_STAGE_RST(),        // カウンタリセット [5]
        I_MOVI(R3, 0),        // 累計地 R3 クリア
        I_DELAY(20),          // -4 <--
        I_ADC(R0, 0, adc_no), // -3
        I_ADDR(R3, R3, R0),   // -2
        I_STAGE_INC(1),       // -1  [10]
        I_JUMPS(-4, 4, JUMPS_LT),
        I_RSHI(R3, R3, 2),
        // VALUE の書き込み
        I_MOVR(R0, R3),             // R0 <- R3 へ退避
        I_MOVI(R2, addr_adc_value), // 値保存
        I_ST(R0, R2, 0),            // [15]

        I_MOVI(R2, addr_threshold),
        I_LD(R3, R2, 0), // R3 <-- MYULP_ADC_THRESHOLD
        I_MOVI(R2, addr_threshold_dir),
        I_LD(R1, R2, 0), // R1 <-- MYULP_ADC_THRESHOLD

        I_ADDI(R1, R1, 0),       // R1 <- R1+0  // 以上か以下かの判定() [20]
        I_BXZI(start_addr + 26), // 🍎    🚨
        //
        I_SUBR(R0, R0, R3), // R0 <- R0 - R3 [25]
        I_BGE(2, 0x7fff), // I_BL(2,1) は センサー値R0 の 方が大きい場合は WAKE
        I_WAKE(),
        // I_HALT(),
        I_BXI(start_addr + 29),
        //
        I_SUBR(R0, R3, R0), // 🍎 R0 <- R3-R0   [26]
        I_BGE(2, 0x7fff),   // I_BL(2,1) は 閾値の方が大きい場合は WAKE
        I_WAKE(),
        I_HALT(), //[29]

スイッチ的な動きをするセンサーなどでもTTLレベル(0と4095)だけではなく中間値が必ず発生する。閾値3500以上でWAKEさせ、次のOFFは閾値500以下でWAKEさせるなどの設定が可能