エントリー

2016年03月08日の記事は以下のとおりです。

Si5351Aを検討する その4

  • 2016/03/08 14:01
  • カテゴリー:make:

 さて,貧乏生活が抜けきれない私は,50円の8ピンマイコン,ATtiny13Aを使って,Si5351Aを設定しようと企て,同じAVRだし楽勝だろうと思ってtiny2313のコードを移植したものの,まったく動いてくれません。

 はて,何がだめなんだろうと首を練っているところから,今回の日誌は始まります。

 なにせ,2313でちゃんと動いているコードで,しかも単なるGPIOの制御だけのものですから,これで動かないなんてのはちょっと考えにくいわけです。あれこれと試行錯誤をしますが,状況は変わらず。

 こうやって,適当に試行錯誤をすることは,私はそんなに無駄ではないと思っています。確かに理論的ではありませんが,そういう理由も理屈もない手当たり次第な方法によって,なにか変化が見つかれば,そこを手がかりにして尻尾をつかむことができます。

 分からないからといって何もしないと,何も前に進みません。こういうときは,余計なプライドは捨てて,初心者に戻るのです。

 で,コードに問題がないとすると,コンパイルオプションをいじってみようという話になりました。クロックの設定,最適化の設定を変えても変化はなし。この過程でヒューズビットの設定を誤り,ライタで書けない13Aを作ってしまったことは内緒です。(後日ヒューズリセッタを作って復活させましたのでご安心を)

 ところが,CPUの設定を13Aから2313に強引に変えると,なんとまあ動いてしまったではありませんか!これには驚きました。

 これはどう考えたらいんでしょうか。コードにミスがないから動いている,そして動かないのはコンパイラのオプションのせい,ということは,コンパイラのバグなのか!

 しかし,私の環境はAVR Stuidio4.19という古い物で,十分に枯れています。これでこんなバグがあるんだとしたら,世の中の13Aの大半は動かないんじゃないでしょうか。

 いや,でもコンパイラのバグというのは,案外あるものです。もうバグだと決めつけて,最新の環境に変えてみようとしたり,バグの情報を探して半日が過ぎました。しかし成果なし。誰もバグなんてことは言ってません。

 さらに手探りをします。それでは,2313以外に動くCPU設定はあるだろうか?

 試してみたら,これが案外あるんです。動く物と動かない物,かなり拮抗した感じです。ただ規則性があるようでありません。85Aでは動くけど45Aでは動かないとか,そういうよく分からない状況なのです。

 こんなに動く物と動かない物が出てきてしまうなら,もうコンパイラのバグのはずがありません。もう一度疑いの目を自分に向けて見ましょう。そうです,コンピュータというのは,指示されたとおりにしか動かないものなのです。

 ここで,ふと,13Aのメモリが小さいことに気が付きました。いや,プログラム格納用のフラッシュメモリが半分になっていることは分かっていましたが,RAMも半分,EEPROMも半分になっていることを,あまり意識していなかったのです。

 RAMはたったの64バイト。Cでコードが書けるギリギリのメモリと言ってもいいでしょう。

 この続きを,私が嫁さんに説明した会話を再現してみます。嫁さんはソフト屋で,こういう失敗談を笑い話として聞いてもらえる,貴重な相手なのです。

 ・・・

私:まず,I2Cで設定するレジスタの値は,配列にいれてあるわけよ。
嫁:うんうん。
私:ところが,私はこいつをconst宣言してなかった。
嫁:ぶーー(笑)。あんた何年組み込みやってんのよ。
私:そんなん,今どき広大なRAMがあるんやから,いちいちconstなんか宣言せえへんよ。
嫁:またそういう屁理屈を・・・まあええわ,それで?
私:ところが,const宣言しても,動かない。
嫁:ほー。
私:ここがAVRの特殊な事情で,const宣言してもRAMは使うのよ。つまりROMとRAMの両方に同じデータがおかれるわけ。
嫁:なんでそんな無駄な仕組みなのよ?普通const宣言すればRAMにはおかれないよね。
私:そう,これはAVRがハーバードアーキテクチャゆえ,データとプログラムが別々のメモリに配置されるようになっているから,なのね。置かれているものはプログラムだけという前提のROMにデータがおかれていても,それはデータとしてアクセス出来ない。それで結局RAMにコピーするわけ。
嫁:うーん。const宣言だけではだめのか・・・
私:まあ,そもそもconstなんてのはコンパイラに「定数ですよ」と教えて上げるだけで,そこから先はコンパイラ任せよね。「だからどうしたてやんでいバーローチキショー」と冷たいコンパイラやったら,ROMにもRAMにもおくわね。
嫁:ところで,そのレジスタの値は,何個あるのよ?
私:それが,100個ほど。
嫁:なるほどー。それで64バイトのRAMからはみ出すのか。
私:そう,だから128バイトのCPUを使うと,const宣言をしていないこのコードでも動いたわけよ。けどここであきらめる訳にもいかん。なんとかRAMを使わない方法で設定をしないといけないんで,google先生にすがってみたのよ。そうすると,先人達が便利な方法を考えてくれていて,配列をプログラムメモリにおき,使う時にこれを引っ張り出してくる方法を用意してくれてあった。プログラムメモリだけではなく,EEPROMにも置けるようになるという,素晴らしいもの。
嫁:それで,動いたの?
私:うん,動いた!
嫁:それはよかった。というより,本当に何年やってるのよ?組み込み。
私:でも,なんでCPUのオプションを変えると動くんだろうとおもわんか?
嫁:確かに。
私:実は,この設定値,後半の50個ほどは,ほとんどゼロ。意味のある設定値は前半の数十個だけなのね。
嫁:なるほど,RAMが大きいCPUの設定であれば,実メモリが存在しないところでもなんとなく動いて,ゼロを書いてくれたと。でも正しいCPUの設定では,そこで別のデータが読めてしまい,動かなかったと。
私:おそらく,そういうことやろうね。

 とまあ,こんなほほえましい夫婦の会話があって,結局AVRに特有の,定数の置き方を使う事にしました。

 この,AVRならではの方法ですが,プログラムメモリに置く方法とEEPROMのおく方法の2つがあります。どちらも,RAMからデータを取り出す命令とは異なる手順と命令を使いますから,使いやすいようにライブラリとして用意してくれてあるんですね。

 具体的には,最初にavr/pgmspace.hをincludeします。そして定数の定義には,

const PROGMEM unsigned char hoge[] = {xx,xx,xx...};

 読み出しには,

a = pgm_read_byte(&hoge[x]);

 とします。もしこれがプログラムメモリではなく,EEPROMの場合にはavr/eeprom.hをincludeした上で,

const EEMEM unsigned char hoge[] = {xx,xx,xx...};

 読み出しには,

a = eeprom_read_byte(&hoge[x]);

 とします。もしbyteではなくwordの場合には,byteの部分をwordに書き換えてやればOKです。

 当然ですが,前者は定数を変更する場合には再ビルドが必要です。一方後者はプログラムだけではなくEEPROMにもライタで書き込みを行わないと動きません。ヒューズでEEPROMを保護していないと,プログラムの書き込み時にEEPROMが消去されてるようですので,気をつけましょう。

 話を戻すと,tiny13は1kByteしかプログラムメモリがありません。だから定数は出来るだけEEPROMに追い出したいです。それに,プログラムをいちいちビルドしなくても,EEPROMの内容を書き換えるだけで,欲しい周波数の設定に書き換えることが出来ます。これはこれで便利でしょう。

 最後に,設定が完了したらLEDが点灯し,ブザーがかつての国民機のようにぴぽっと鳴るようにして,最後にSLEEPモードに入るという仕上げを行い,なんとかSi5351を任意の周波数発生器として使える環境が整いました。プログラムメモリは,およそ半分強使っています。

 こうしてやってみると,50円のAVRでも,それなりの事が出来るもんだなと思います。特にI2Cは2本しか使いませんので,8ピンのマイコンには最適です。

 I2Cがあれば,センサもディスプレイも発振器も,全部まとめて2本です。実際に使ってみてつくづく思ったのは,やっぱり8ピンというのは,回路を作るのが楽です。2313のように20ピンもあると,配線だけでも結構多いですから,面倒だし,ミスも起きます。

 Si5351Aも面白いのですが,8ピンの13Aも,いじりがいがある面白いマイコンです。

 ということで,次は,作った周波数の簡単な評価です。

ページ移動

  • 前のページ
  • 次のページ
  • ページ
  • 1

ユーティリティ

2016年03月

- - 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31 - -

検索

エントリー検索フォーム
キーワード

ユーザー

新着画像

新着エントリー

過去ログ

Feed