今更ながらSPRESENSEの消費電力調べてみた①

ソニーが販売しているSPRESENSEを、今更ながら消費電力を実機で細かく見ていきます。

SPRESENSEの消費電力についてはWEBを調べれば<a href="https://www.aps-web.jp/academy/amp/10632/">こちら</a>が真っ先にヒットするかと思います。

しかしいつも思うんですが、
「いや、そうじゃないんや。どれだけ消費電力が抑えられるかの改造なんかじゃなくて、単純にsleep時の消費電力とかもっとみせてくれや」
ってなるんですよね。
あと自分でも「どれくらい省エネできてるんだろ」といつも思っています。

というわけで、
# 念願のPower Profiler Kit IIを手に入れた

<img src="https://www.mouser.jp/images/marketingid/2020/microsites/103756347/Nordic_PPK2_KC.png"/>

※画像は借り物です。

これを使うと細かく消費電力とか分析できます。USBの電力測定モジュールとかでもいいんですが、私がAmazonで買ったものは5mA以下の検出ができないので、coldSleepとか見たいならやっぱりちゃんとしたものを買わないとダメ見たいです。
ましてμAオーダーやnAオーダーを見るなら必須ですね。

# 早速しらべる
- USBではなくバッテリー供給口の方から5Vを入力
- メインボードのLEDは除去したものしかなかったので、それを使用(大体200μAくらい節電だった気がする)
- n数は1。端末依存って言われたらそれまでだけど、仕事柄数十台のSPRESENSEを扱っているので大体同じ感じな印象

## メインボードのみの消費電力
### 1. idle状態
- 電源投入直後
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3737064/780ef7bd-42dc-17b0-b078-32e0f2f3a274.png" width="100%">
        
- 1分間平均
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3737064/18aa5bec-624c-e756-af0c-e591c65b5994.png" width="100%">

- 検証ソース

```cpp
void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:

}
```

起動時、わずかに突入電流があります。
別回で紹介する予定ですが、試しにESP32とかを見てみるとこの突入電流が小さいので、これはSPRESENSEの特徴っぽいです。
    
idle時でも1分間の平均は`7.76mA`と優秀ですね。

### 2. coldSleep状態
- 電源投入直後
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3737064/d6994c39-908a-03f3-5f9c-eed4539b22e1.png" width="100%">

- 1分間平均
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3737064/b9280d77-f0e2-86a1-33a7-fb0c70d77b2b.png" width="100%">


<details><summary>検証ソース</summary>

```cpp
    // ほぼサンプルソースのまま
    #include <LowPower.h>
    #include <RTC.h>
    
    const char* boot_cause_strings[] = {
    "Power On Reset with Power Supplied",
    "System WDT expired or Self Reboot",
    "Chip WDT expired",
    "WKUPL signal detected in deep sleep",
    "WKUPS signal detected in deep sleep",
    "RTC Alarm expired in deep sleep",
    "USB Connected in deep sleep",
    "Others in deep sleep",
    "SCU Interrupt detected in cold sleep",
    "RTC Alarm0 expired in cold sleep",
    "RTC Alarm1 expired in cold sleep",
    "RTC Alarm2 expired in cold sleep",
    "RTC Alarm Error occurred in cold sleep",
    "Unknown(13)",
    "Unknown(14)",
    "Unknown(15)",
    "GPIO detected in cold sleep",
    "GPIO detected in cold sleep",
    "GPIO detected in cold sleep",
    "GPIO detected in cold sleep",
    "GPIO detected in cold sleep",
    "GPIO detected in cold sleep",
    "GPIO detected in cold sleep",
    "GPIO detected in cold sleep",
    "GPIO detected in cold sleep",
    "GPIO detected in cold sleep",
    "GPIO detected in cold sleep",
    "GPIO detected in cold sleep",
    "SEN_INT signal detected in cold sleep",
    "PMIC signal detected in cold sleep",
    "USB Disconnected in cold sleep",
    "USB Connected in cold sleep",
    "Power On Reset",
    };
    
    void printBootCause(bootcause_e bc)
    {
        Serial.println("--------------------------------------------------");
        Serial.print("Boot Cause: ");
        Serial.print(boot_cause_strings[bc]);
        if ((COLD_GPIO_IRQ36 <= bc) && (bc <= COLD_GPIO_IRQ47)) {
            // Wakeup by GPIO
            int pin = LowPower.getWakeupPin(bc);
            Serial.print(" <- pin ");
            Serial.print(pin);
        }
        Serial.println();
        Serial.println("--------------------------------------------------");
    }
    
    void setup()
    {
        Serial.begin(115200);
        while (!Serial);
        
        // Initialize LowPower library
        LowPower.begin();
        
        // Get the boot cause
        bootcause_e bc = LowPower.bootCause();
        
        if ((bc == POR_SUPPLY) || (bc == POR_NORMAL)) {
            Serial.println("Example for RTC wakeup from cold sleep");
        } else {
            Serial.println("wakeup from cold sleep");
        }
        
        // Print the boot cause
        printBootCause(bc);
        
        // Print the current clock
        RTC.begin();
        RtcTime now = RTC.getTime();
        printf("%04d/%02d/%02d %02d:%02d:%02d\n",
                now.year(), now.month(), now.day(),
                now.hour(), now.minute(), now.second());
        
        // Cold sleep during about 70 seconds
        Serial.print("Go to cold sleep...");
        delay(1000);
        LowPower.coldSleep(70);
    }
    
    void loop()
    {
    }

```


</details>

coldSleepで分平均`1.4mA`まで下がりました。
以前に調べたことがあるのですが、raspberry pi pico のdeepSleepでこれくらいだった気がします。その時はCPU周波数をがっつり落とすなど対策した記憶がありますので、サンプルコードそのままでこれだけ省エネできるのはすごい。


### 3. deepSleep状態
- 電源投入直後
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3737064/37203fec-8d34-7b2e-00f9-0465a465a32a.png" width="100%">


- 1分間平均
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3737064/db7de7a8-1195-6b02-4271-fe51b790b5f2.png" width="100%">

- 検証ソース
    - coldSleepからdeepSleepに変えただけ

deepSleepはなんと分平均`47μA`まで下がりました、
しかし起動時の数秒は若干電力が高い状態が続いています。
プログラム上ではdelayを少し入れていますが、その秒数よりも長いです。

ともあれdeepSleepでここまで省エネだと、単一電池とか使えば相当長生きできるIoT端末ができそうですね。

次回はSPRESENSEにCAMERAモジュールを搭載した場合の電力計測した結果を書きたいと思います。

<a href="https://qiita.com/saya-reg/items/044defa2f7eb1f06a9e0">今更ながらSPRESENSEの消費電力調べてみた⓶</a>