2013年 10月 17日

AVR 消費電力を減らす

割込みタイマーによるカウンタを使った delay_ms に実装しなおしたら 1MHz で動かしても符号が著しく遅くなることがなくなった。

この状態で消費電流を測る

  • アイドル状態 0.38mA
  • パワーダウン状態 62uA
  • キーイング中 0.55mA

delay 中も sleep するようにしたのでキーイング中の消費がだいぶ減ってる。

常時キーイングしてても144日ぐらい持つ。普通ありえないので、1日あたり2時間キーイングとすると、771日でだいたい2年持つ計算 (実際は自然放電されるからもっと短いけど、十分長い)

さらに減らすにはどうしたらいいだろう。チップスペック的にはパワーダウンモードだと0.1uA未満しか流れないみたいだけど、現状の回路だと多少流れてる。プルアップしてるのがわるい?

スリープ前にピン設定を変える

リグとの接続を見る端子がプルアップしているのをスリープ時にオフにすればいいことがわかった。これで

  • アイドル状態 0.38mA
  • パワーダウン状態 10.8uA
  • キーイング中 0.55mA

これで1日2時間キーイングで1440日に…

アイドル中、キーイング中の消費電力はこれよりもっと減らせるだろうか……

ISP Programmer の罠

AVR ISP Mark II を繋いでいると、パワーダウンモードでも10uAほど流れるようだ…… なんとはずしただけで 0uA (測定限界未満) になってしまった。これで同条件で 1693日持つ計算になった。上のプルアップを一時的にやめるというのもやる必要がなかった。

2013年 10月 16日

AVR でエレキーをつくってる

まず何を作ろうという感じだけど、エレキーならはじめて作るマイコンの教材としては、LEDチカチカレベルで簡単だし、なおかつ実用性があるので、ちょうどいい。自分で作れれば何かしら挙動を変えたいときも技術力の許す限りは自由にできるのでやってみてる。

検索するといろいろ作っている人がいるけど、結構難しい感じまで作りこまれたのが多くてつらい。しかし この作例 はプログラムも外付け部品もかなりシンプルだったのでとても参考にした。特にプログラム部分は、割込みを使って非常に少ないコードで基本機能が完全に実装されていて、実装の気が楽になった。

設計の指針

  • いわゆるエレキーの基本機能
    • 長短点メモリー
    • インヒビット
    • スクイズキー
  • スピードコントロールできること
  • 1.2V電池2本で長いこと動くこと
  • サイドトーンを発音できて、単体でも練習用として使えること

最初の実装

最初の実装は全部で80行ほど。スピードコントロールなどもなくて、動作だけ動くかやってみた感じ。この時点ではブザーを鳴らす部分とかもないので、LED をチカチカさせていた

ブザーを鳴らす

一番お手軽なのは電圧かけるだけで鳴るやつを使うことだろうけど、手元にあるのは普通に圧電スピーカーだし、鳴る周波数変えれたら嬉しいので PWM を使って出力することにした。

16bit タイマーでやったんだけど、動作を理解するまでがまず意味不明で大変だったのと、動作を理解しても、比較値やトップ値に対応する実際の変数名がわからなくてひたすら仕様を読んだりした。しかしまだちゃんと理解しているという感じになってない…… 一応鳴るようにはなったし、ピポッって鳴らしたりもできるのでとりあえず良い。

出力

出力はリグと繋ぐ部分。事前に計ったところ、リグのキーイング端子は 5V がかかっていて、スイッチオンのときは 1mA 未満しか流れない。なのでほんと適当にスイッチすればよさそう。

  • トランジスタスイッチング
    • 安い・簡単・消費電力多め
  • FETスイッチング
    • 消費電力少なめ・少々高い・回路電圧からして使えるFETを探すのがめんどう
  • フォトカプラ
    • まだ試してない
トランジスタスイッチ

最初に試した。手元の 2SC1815Y のベースに5.6kΩ程度つけてエミッタ接地でスイッチングさせた。動作としては問題なくうまくいく。

FETスイッチ

エンハンスメント型でゲート電圧2.4V付近で十分電流が流せればなんでもいいはずだけど (ほんとうかな)、定番のスイッチ用 FET というのがよくわからない 、とにかく売ってるやつで適していそうなやつを探した…… CPAN からモジュール探すより難しい。

データシートを見た感じ、2SK2232 のほうが低い電圧でもかなりの電流 (3Aぐらい) が流せるようになるみたいだけど、だいぶ高い。2N7000 は 2.4V 程度だと数十mAしか流せない。

今回の用途だと、まずDS間に大量に電流が流れることがないので 2N7000 で駆動してもよさそうだけど、よくわからない。試した感じではうまくいった。

スピードコントロール

とりあえず手元にある ATTiny2313 には ADC がないので、お手軽にボリューム使ってスピードコントロールするみたいのはできない。コンデンサの充電時間を利用してADCぽいことをするというのをやってる人もいるけど、だいぶ面倒そうだし、そこまでするなら普通に ADC 内蔵のチップを買ったほうがいいな、という気分。ATmega168 というのも手元にあるけど、今回の用途ではオーバースペックすぎて使う気が起きない。

しかし、よくよく考えてもみると、そこまで執拗にボリュームというインターフェイスを使いたいわけではなくて、むしろデジタル的に 15wpm 〜 30wpm 程度を 1wpm 単位で切り替えられたほうが、相手に「QRQ25wpm」とか言われたときに対応しやすいのではないか? と思ったので、プッシュスイッチ × 2 を up/down スイッチとしてスピードコントロールをすることにした。

ただ、この方法だと、何らかの方法を別途用意しないと、現在設定している速度がいくつなのかわからなくなる。

  • up/down 同時押しか何かで現在の設定をサイドトーンに出力
    • 簡単で良さそうだけど急いでるときはだるい
  • up/down 同時押しか何かで一定時間 2桁の7セグを駆動
    • IO使いまくる
  • I2C 液晶をつける
    • TINY だと面倒

と考えた結果、ボタン長押しでサイドトーン側に現在の設定を鳴らすことにした。

ボタンの同時押し

up/down ボタンだけでできるだけ多くの操作を割り当てたい。具体的には

  • 上記の通り、ボタン長押しで速度を発音
  • ボタン同時長押しでエレキーとしての機能を切るモード (調整のときとかに必要)

しかし、これは実際かなり大変で時間がかった。長押しはそんなに難しくないけど、同時押しはとにかくめんどうくさい。似たようなことをやってる人がいた ので、処理のしかたはほぼパクりつつ、PIND にしかスイッチがないので、PIND を一括で状態管理するような感じにした。

しかし、同時押しはどちらかが必ず先に押されるわけだし、通常の長押しと競合してしまったりする。頑張って判定する必要があった。

サイドトーンのオフ

リグに接続している間は当然サイドトーンを切りたい。しかし、スピードを発音したりするので、完全にスピーカーから何も鳴らさないというわけにはいかない。なので自由が効くソフトウェア側で処理するようにしたいと考えた。

しかしこれが曲者で、スイッチ付きジャックのスイッチ部分が信号ラインと一体でまずい。

説明するのが面倒だけど、リグ側からかかる電圧より、こちらの電圧のほうが低いので、ダイオードを1本入れて対処した。あやうい感じで、これでいいのかよくわからないけど、挙動的には望むものになった。

消費電力

何もしない状態だと 8MHz で動かして常時 2mA ぐらい流れる感じだったので、スリープモードとかを調べて実装してみた。

電源電圧 2.4V

  1. 何も対策しないと消費電力 約2mA、単3エネループ (1900mAh) 2本直列だと、950時間、約40日
  2. 毎ループアイドルにするようにする 0.82mA 同約96日
    1. キーの状態を見にいく割込みは生きているので、そのタイミングで毎回起きて、何もしてなかったらまた寝る
    2. 入力がない限り何もしないプログラムならお手軽に低消費電力にできる感じ
  3. 一定以上経つとパワーダウンする 54.9uA 同約1442日
    1. 10秒程度アイドル状態が続いたらパワーダウンモードに移行する
    2. キーの入力状態が変更されると、そこで割込みがかかって起きる
    3. 生きてるものが殆どなくなるので、さすがに制約が多く、ちょっと考えないとうまくいかない感じ

と、結構下げることができた。

動作周波数を1MHzまで下げることでさらに半分以下になったりするけど、while (--t) _delay_ms(1) のオーバーヘッドが無視できなくなるのか、符号のスピードがかなり遅くなってしまうので、やめてしまった。頑張ってオーバーヘッドをさっぴいて delay するようにするか、根本的に設計をみなおすかしないとだめそう。

最低動作電圧

現状

  • マイコン単体だと 1.5V 程度まで動く
  • 出力FETがオンする最低の電源電圧が 2.27V ぐらい。

電源はエネループを想定しているので、2.1V 程度まで動くと嬉しい。今だとちょっと高めで止まってしまう。FET のゲート抵抗をもっと低くしたらいいかもしれない。逆に、2.1V 程度になったら過放電を防ぐためにもちゃんと止まってほしい。むずかしい。

回路図

前述の通り、出力と、PB4(16pin) がダイオード経由で接続されてる。接続されているとき、リグからかかる電圧が PB4 にかからないようにという意図だけど、これでいいのかわからない。逆にこちらからリグ側へは制限されていなくてよくなさそう (プルアップされてるので電圧がかかってる)。接続されていない場合は接地される。もっといい方法がないか知りたいけど、手掛かりがない。

パドル側にはいずれもバリスタをつけてる。パドルは接点が露出したスイッチなので、静電気に気をつかわないとまずそうだなと思ってつけてるけど、これも自己判断なのでこれであっているかわからない。

2013年 10月 11日

Mac で simavr + avr-gdb を使い AVR プログラムを PC 上でデバッグする

Mac の場合 AVR Studio を使えないので、いろいろ不便である。しかし一応開発環境がととのった。結構ググったけど、このようにして開発している人は少ないのか、はたまた情報発信しないのか、あまり gdb まで使ってやってる記事がなかった。

CrossPack-AVR のインストール

avr-gcc (AVR 用のクロスコンパイラー) や avrdude (書きこみツール) の Mac 向けにコンパイル済みパッケージ。配ってるのでインストールするだけでいい。

CrossPack for AVR を普通にダウンロードしてインストーラーからインストールするだけ。

普通 OS X の path_helper によって自動的に PATH が通るので、そのまま Terminal.app で avr-gcc が実行できるようになる。path_helper のパーミッションを落として使ってる場合自力で /usr/local/CrossPack-AVR/bin のパスを通す。

これさえ入れておけば実機開発はできる。

simavr の build

まずレポジトリを clone する。

$ git clone git://gitorious.org/simavr/simavr.git
$ cd simavr/simavr

simavr のビルドは CrossPack-AVR + Mac だと1発では通らない。以下のようにパスの指定が必要。あと、なんか変な状態になったりするので make clean と make を何回かやってみたほうがいいと思う。

make all V=1 AVR_ROOT=/usr/local/CrossPack-AVR AVR_INC=/usr/local/CrossPack-AVR/avr


これでシミュレーションまでできるようになった。

avr-project の Makefile 書き換え

CrossPack-AVR に avr-project というコマンドがついてくる。

$ avr-project Foo

とかやると Foo/firmware 以下に Makefile とかを作ってくれる。Foo.xcodeproj というのも作ってくれるけど、ハマりそうなので使ってない。

デバッグオプション付きでコンパイルするようにする。RELEASE=1 をつけない場合デバッグモード。最適化オプション -Os はどっちも付けてるんだけど、ちょっとどうすべきかわからない。デバッグ時 -Os をつけずに書きこむときだけ -Os をつけたらループが意図せず削除されたとき大変ハマりそうだなーと思う。いっそ -O0 のほうがいいのかもしれないけど……

ifeq ($(RELEASE),1)
COMPILE_OPT = -Os
else
COMPILE_OPT = -Os -g3 -gdwarf-2
endif

AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE)  
COMPILE = avr-gcc -Wall $(COMPILE_OPT) -DF_CPU=$(CLOCK) -mmcu=$(DEVICE)

でもってターゲットも足す

run:	all
	~/project/simavr/simavr/run_avr -g -mcu $(DEVICE) -freq $(CLOCK) main.hex &
	avr-gdb

さらに .gdbinit ファイルをつくる

file ./main.elf
target remote localhost:1234
load
break main
continue

make run をするとコンパイルされて、simavr をバックグランドで起動し、それにGDB接続する、とりあえず main 関数の最初で止まる (はず)。

自分は avr-project は使っていなくて、自作のテンプレート作成ツールを使っている AVR のテンプレート

実際のデバッグ

普通に GDB を使うだけだけどメモ

  • p foobar
    • 変数を表示
  • p/t PORTB
    • PORTB を2進数で表示
  • p set_bit(PINB, 1)
    • PINB の 1 bit 目を立てる (set_bit は自分で定義したもの)
    • 外部入出力をシミュレーションさせるのは結構骨が折れる感じなので、簡易的には、これで外部入力をシミュレーションできる
    • 外部入出力とかはもうさっさと書きこんでデバッグしたほうがトータルで早いと思う…

実機書き込み

書き込み装置は、ここで変にハマると自分には問題解決できる能力がないところなので、純正の AVR ISP Mark II を使った。

この場合 Makefile の PROGRAMMER は以下のようになる

PROGRAMMER = -c avrispmkII -P usb

DEVICE はチップ名にあわせる。ATTiny2313 なら、そのまま DEVICE = attiny2313 でいける。

AVR ISP Mark II は 3x2 PINヘッダなので、このままだとブレッドボートで使えない。なので 1x6 PINヘッダに適当に変換してる。手元にあったピンヘッダがついてる余ってる平行ケーブルを使った。持ってるブレッドボートが狭くてつらい。

その他メモ

avr-gdb 上での _delay_ms() が非常に遅い。

これはいわゆるビジーループなので、動作周波数を下げることで早くデバッグすることができる。

make run CLOCK=10