まとめを後日書きました [tech][avr][arduino] ボタン電池で動く小型・低消費電力 AVR エレキー (50円 ワンチップマイコン ATTiny13A) | Fri, Nov 8. 2013 - 氾濫原
さらにもっと消費電力を減らせないだろうか? と考えた。パワーダウンモードの消費が計測不可能なので、支配的なのは特にキーイング中と、アイドル中の消費になっている。
特にキーイング中の消費が比較的多い (200uA近く) ので、どうにかできないかと考えた。キーを押しているとき、内蔵プルアップを通して GND に電流が流れるので、そこの消費が結構多い。
今まで何も考えず AVR 組込みのプルアップ抵抗を使っていたけど、ここでちょっと考えてみることにした。
プルアップの調整
内部プルアップは、実測からすると3V/100uA=30kΩ になってるようだ (スペック上は 20k〜50k)。とりあえず AVR 内部のプルアップ抵抗をオフに。
プルアップ抵抗に許される電圧降下を考える。電源電圧3Vで、入力 H レベルは VCC * 0.6 (スペックから)、ノイズ回避用に 0.4V を足すと
- ピンの必要入力電圧 Vin = 3 * 0.6 + 0.4 = 2.2V
- プルアップでの電圧降下最大 V = 3 - Vin = 0.8V
となった。
マイコン側は十分大きい入力抵抗があると考えると、かなり大きな抵抗を入れても大丈夫そう? なのかな。
試しに 2.2MΩでプルアップしてみると、ICの足にかかる電圧は2.5V程度になった。2.2MΩ で0.5V電圧降下しているので、0.23uA 程度流れてる。3V / 0.23uA でプルアップと内部抵抗の合成値は 13.2MΩ、つまり内部抵抗は11MΩぐらい……? よく「入力抵抗は非常に大きい」といわれるのを見る割に、いまいちどの程度かわからなかったけど、こんなもんなのかな。
この状態で、消費電力をはかる
- before: 内蔵プルアップ: 198uA
- after: 2.2MΩプルアップ: 113uA
とりあえず減ったし、普通に動いてはいる。しかしこれであっているのかさっぱりわからない。
これで、毎日2時間使うケースだと (CR2032/225mAh, 1日2時間, パワーダウン中 0.15e-6mA, キーイング中 113e-3mA) 995日持つ計算になった。
delay_ms のさらなる見直し
128kHz で動かすにあたり delay_ms を以下のようにしていた。
void delay_ms(uint16_t t) {
uint16_t end;
cli();
timer = 0; TCNT0 = 0;
end = NOW + DURATION(t);
sei();
while (NOW <= end) { nop; }
}
timer は 2msec ごとのオーバーフロー割込みでインクリメントされているけど、これだとちょっと精度が悲しいような気がするので、カウンタそのもの (TCNT0) も見ている。オーバーフローでやっているので、単純に timer はカウンタの桁あがりとして扱える。NOW は ((timer<<8)|TCNT0) という定義
while の中を アイドルではなく nop; にしているのは、ここでアイドルに入ってしまうと、次に起きるのが 2msec 後とかになるので、せっかく TCNT0 を見ている意味がなくなるから。
ただ、まだここは精度を維持しつつも最適化の余地があって、以下のようにした。
void delay_ms(uint16_t t) {
uint16_t end;
uint16_t end0;
cli();
timer = 0; TCNT0 = 0;
end = NOW + DURATION(t);
end0 = end - 0x100;
sei();
while (NOW <= end0) {
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_mode();
}
while (NOW <= end) { }
}
少なくとも、最後の TCNT0 分 (8bit) になるまでは、普通に 2msec ごとに寝ていても大丈夫なはずなので、それまではスリープを使い、最後のカウンタ分はビジーループにするようにした。nop; は別にいらなそうなのでとっただけ。
これでキーイング中でも 96uA まで消費電流を落とせた。上と同じように、毎日2時間使うケースだと (CR2032/225mAh, 1日2時間, パワーダウン中 0.15e-6mA, キーイング中 96e-3mA) 1171日持つ計算になった。1000日超え! もうこれでいいかな。