ATtiny202のスリープ機能を試す

# はじめに
本記事ではATtiny202のスリープ機能について、自分なりに使い方をまとめてみました。タクトスイッチ1個を使い、スリープ状態への移行と復帰を制御するような具体例で試してみます。[**以前**](https://qiita.com/ricelectric/items/8909016f22b879acb428)の記事に引き続き、少しでも参考になりましたら幸いです。
![picture.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951963/0048f60d-1765-58b3-c691-ac55a5c1abd2.jpeg)
# 開発環境
* Windows 11 Home 22H2
* Arduino IDE 1.8.19
* megaTinyCore 2.6.10
# 回路構成
PA6にLED、PA7にタクトスイッチを接続しました。書き込み方法などは[**以前**](https://qiita.com/ricelectric/items/8909016f22b879acb428)の記事でも解説しているため、今回は割愛します。
![breadboard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951963/a9c4686b-aaf8-f11a-8941-a547d557a6c3.png)
# クロック周波数
クロック周波数はデフォルトだと20MHzに設定されているため、低電圧検出機能が4.2V付近で作動します。今回は乾電池2本で駆動することを想定しているため、このままだと正しく動作しません。そこで、閾値を最小値の1.8Vにまで下げてみたところ、クロック周波数も5MHz以下にまで落とす必要がありました。なお、設定した項目を適用するためにはヒューズビットを書き換える必要があります。Arduino開発環境を利用している場合はブートローダの書き込みを実行するだけなので簡単です。
![screenshot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951963/93e6c2db-fc77-48da-fecb-fe410f3defc6.png)
クロック周波数は動作時の消費電流に影響します。しかし、スリープ時はCPUも停止するため、スリープ時の消費電流とは無関係です。
# スリープ機能
以下の表で示すようにモードとしては3種類が用意されているみたいです。今回は最も消費電流が小さくなるモードを選択しました。RTCなど、ほとんどの機能は停止します。また、スリープ状態から復帰する手段としては3種類の中から選べます。今回は外部割り込みを選択しました。ピン状態の立ち下がり、立ち上がり、その両方を含む変化、あるいはローレベルのいずれかを検出できます。ATtiny202では全ての入出力ピンが外部割り込みに使用できますが、注意としては非同期で検出できる入出力ピンがPA2とPA6に限られている点です。つまり、その他はピン状態の変化、あるいはローレベルしか検出できません。
![table.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951963/8b132780-7deb-717b-4607-006c864fa9b2.png)
復帰に要する時間はオシレータの起動に要する時間とペリフェラルへ供給されるクロック信号6回に要する時間との合計です。
![start-up_time.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951963/23f746b4-699c-47a0-4aaa-f8b3e93b7e17.png)
# プログラム
タクトスイッチを1秒くらい押し続けるとスリープ状態に移行します。そして、タクトスイッチを再び押すとPA7がローレベルとなり、外部割り込みが発生してスリープ状態から復帰します。押し続ける時間により判定しているため、条件分岐を増やせば複数の機能を割り当てることも可能です。
```cpp:sleep.ino
#include <avr/sleep.h>

#define PIN_LED PIN_PA6
#define PIN_BUTTON PIN_PA7


//the interrupt is handled after waking up here
ISR(PORTA_PORT_vect) {
  PORTA.INTFLAGS = PORT_INT7_bm; //clear the interrupt flag on PA7
}

void sleep() {
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); //select the power down sleep mode

  noInterrupts(); //disable all interrupts
  sleep_enable();
  interrupts(); //enable all interrupts

  PORTA.PIN7CTRL = PORT_PULLUPEN_bm | PORT_ISC_LEVEL_gc; //pull up PA7, trigger on low level
  sleep_cpu(); //actually go to sleep here
  
  //the program will continue after waking up from here
  sleep_disable();
  PORTA.PIN7CTRL = PORT_PULLUPEN_bm; //pull up PA7, turn off the pin change interrupt
}

void setup() {
  pinMode(PIN_LED, OUTPUT);
  pinMode(PIN_BUTTON, INPUT_PULLUP); //pull up PA7

  //pull up unused pins to minimize current consumption
  pinMode(PIN_PA1, INPUT_PULLUP);
  pinMode(PIN_PA2, INPUT_PULLUP);
  pinMode(PIN_PA0, INPUT_PULLUP);
  pinMode(PIN_PA3, INPUT_PULLUP);

  digitalWrite(PIN_LED, HIGH); //turn on the LED
}

void loop() {
  static unsigned long lastTime;
  static int lastState = HIGH;
  
  int state = digitalRead(PIN_PA7); //read the state of the button

  //detect the state change
  if (state != lastState) {
    if (state == LOW) { //the button is pressed
      lastTime = millis();
    } else { //the button is released
      unsigned long interval = millis() - lastTime;

      //the button is pressed for more than 1 second
      if (interval > 1000) {
        digitalWrite(PIN_LED, LOW); //turn off the LED
        sleep(); //go to sleep
        digitalWrite(PIN_LED, HIGH); //turn on the LED
      }
    }
  }
  lastState = state;
  delay(10);
}
```
未使用ピンは内部プルアップを有効化し、電位を固定することで意図しない発振を防ぎ、より消費電流を抑えることができます。
# 検証
まずは動作時の消費電流を測定してみたところ、約2.735mAとなりました。LEDには約1.630mAの電流が流れていたのでATtiny202には差し引き約1.105mAの電流が流れていた計算となります。クロック周波数は5MHzです。また、検証時は単3形の乾電池2本を電源として使用し、電圧は約2.478Vでした。
![active_mode.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951963/a3179bcf-9670-2f41-9d08-8f0ca09a98af.jpeg)
次にスリープ時の消費電流を測定してみたところ、なんと約0.1uAとなりました。
![sleep_mode.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951963/cd882b93-d469-2177-9675-7ef642293771.jpeg)
このように消費電流を大幅に抑えることができました。起動時間も短く、非常に優秀だと思います。
# おわりに
例えばLR44など、容量が100mAhくらいの小型なボタン電池2個で駆動することを仮定した場合、理論上は約114年も持つ計算となります。もちろん、動作時の消費電流を減らしていく工夫は必要ですが、スリープ時の消費電流は無視できるくらい小さいことが検証できました。活用の幅も広がりそうです。
# 参考文献
* https://akizukidenshi.com/goodsaffix/attiny202-402.pdf
* http://www.technoblogy.com/show?2RA3