ATtiny85マイコンの手習い(その2・屋内暑さ指数計の移植)(2020/10/07修正)
ArduinoIDEでATtiny85が使えるようにする方法を、前のエントリーで紹介しました。
続いて、ATmega328PからATtiny85への移植を、屋内暑さ指数計を例題にやってみた内容を紹介します。 まず、両ICの簡単な比較は次の通り:
ATmega328Pでの回路図は次の通り:

電源とリセット以外に7ピンを使っています。また、当初のメモリ使用量はflash/EEPROM/RAMの順に13562/0/1254byteでした。
ここから明らかな通り、移植のポイントは使用するピン数とメモリの削減(flash6kB, RAM742byte)です。メモリはほぼ半減ですね。
ピン数については、暑さ指数計ではI/Oに
1.2. LCDおよびセンサと通信するI2Cの2ピン
3. リセット(1ピン固定)
4. LCDコントラストを設定するため可変抵抗から電圧を読み込むADC入力
5. LEDを点滅させるデジタル出力
6. USBの5VからLCDとセンサの電源電圧3.3Vを生成するPWM(元電源が3.3Vなら不要)
を使います。あと電源の計8本で、ちょうど全てです。というか、きっちりなので例題にしました。 スケッチ(プログラム)は次のGitHubリポジトリに掲載しました:
pado3/ArduinoWBGT: Indoor WBGT meter with ATmega328P and ATtiny85
変化を追いやすいように、ブランチを3つに分けています:
1. mainのWBGT01.inoがATmega328Pで最初に使えるようにしたもの
2. WBGT03がATmega328P上でメモリ削減に取り組んだもの
3. WBGT03sがATtiny85で使えるようにしたもの
です。 最初のWBGT01では測定・表示機能の他に、シリアル通信によってArduinoIDE側へ途中経過や測定データを戻す機能がありました。ATtiny85ではピン数が少なくてシリアル通信ができなくなるので、Serial.print()等をバッサリ消しました。これだけでflashが3kbyte減りました。
LCDとセンサの電源をPWMから外部レギュレータに変えてみても、flashは172byteしか減らず、元に戻す。
LCDのコントラストをADC読み取りから決め打ちに変えてみても、flashは160byteしか減らず、元に戻す。
温湿度からWBGTデータを出す対照表(intの20x17 =340byte 680byte(intは2byteでした…) )をオンメモリからEEPROMへ出すと、flashが792byte, RAMが680byteも減りました。出した量の2倍減ったのは驚きましたが、理由は宿題です(おそらく領域と内容がそれぞれ消費していた)。この時、別途EEPROM書き込み用のスケッチ"WBGT03_EEPROM.ino"を作成しました。
温度の演算に使っているdoubleの変数3つをintに変えるとflashが930byteも減りました。元々intの読み取り値を表示・演算のためにdoubleにしているだけなので、intとcharで操作することにします。
ここまでスイッチサイエンスさんのLCD表示サンプルプログラムをそのまま使わせて頂いていたのですが、この中のlcd_printInt()を消して別処理にするとflashが1344byte減りました。どうも、sprintf()がメモリ喰いだったようです。
これで、ATmega328P上では8k/512/512に収まりました。主要なポイントをまとめると次の通りです(他にも細々と手直ししているので単純な加減にはなっていません):
メモリが削減できたのに気をよくして、いよいよATtiny85へ移します。
次のブログなどを参考に調べたところ、ATtinyでは、I2C通信に使っていたWireの代わりにTinyWireMを使います。また、WireとTinyWireMで1つだけ異なるコマンドがあります。
TinyWireMのインストールは、こちらを参考にしました:
ATtiny85でI2C-LCDを使う方法 | Arduino | kosakalab
(ST7032ライブラリは特に必要ありません。)
プログラムの移植は、こちらを参考にしました:
ATtiny85 - Tomiya's blog (3DCG & Photo etc.) こちらを元に、まずはLCDの表示、EEPROMの読み書き、そして全体構成へと進めます。
LCDの表示は、まず"Wire"を"TinyWireM"に全置換します。
次に、Tomiyaさんの記事ではWire.writeからTinyWireM.sendへの差し換えは慎重にとありますが、.writeのままだとフリーズしたので、とりあえず.sendに全置換したところ、あっさり動いてくれました
続いてEEPROMへの読み書きをしたのですが、ここで引っかかりました。ATmega328Pでは対照表全てとメッセージを一気にEEPROMへ書けたのですが、ATtiny85ではRAMオーバーになってしまいます。364byte書き込むのに、512byteしかないRAMに728byte置こうとする訳ですから、そりゃ無理というものです。
最初は、それでもデータを前後半に分けたら書けるかと思ったのですが、コンパイル時に「スケッチが使用できるメモリが少なくなっています。動作が不安定になる可能性があります。」というメッセージが出て、無視して書き込んでみるとデータ化けの嵐。

結果としてデータを4分割とメッセージを別枠にした5段階書き込みをすることになりました。
ここをクリアしたところで、ATmega328PのWBGT03から
1. "Wire"を"TinyWireM"に全置換
2. "TinyWireM.write"を"TinyWireM.send"に全置換
すると、あっさりとWBGT計として動作してくれました。

この時のメモリ使用量は5548/364/79byteで、flashもRAMも使用量がとても少なくなりました。おそらくライブラリの違いが大きいのだろうと思われます。
回路図は次の通りです:
というわけで、無事にシュリンクすることができました。ただ、ここから更にflashを4kまで削減してATtiny45に収めるのは一苦労しそうです。 以上、何かの参考になれば幸いです。ご利用は自己責任で。 パドラッパ from MacBook Air (2017) 【2020/10/07追記】
・EEPROM周りでのポカを修正しました(見え消しあり、お恥ずかしい限り)。
・回路図のノードが分かりにくかったので修正しました。
続いて、ATmega328PからATtiny85への移植を、屋内暑さ指数計を例題にやってみた内容を紹介します。 まず、両ICの簡単な比較は次の通り:
| 項目 | ATmega328P | ATtiny85 | 単位 |
|---|---|---|---|
| ピン数 | 28 | 8 | 本 |
| (内I/O) | 23 | 6 | 本 |
| (内ADC) | 6 | 4 | ch |
| (内PWM) | 6 | 2 | 本 |
| flash | 32k | 8k | byte |
| EEPROM | 1k | 512 | byte |
| RAM | 2k | 512 | byte |

電源とリセット以外に7ピンを使っています。また、当初のメモリ使用量はflash/EEPROM/RAMの順に13562/0/1254byteでした。
ここから明らかな通り、移植のポイントは使用するピン数とメモリの削減(flash6kB, RAM742byte)です。メモリはほぼ半減ですね。
ピン数については、暑さ指数計ではI/Oに
1.2. LCDおよびセンサと通信するI2Cの2ピン
3. リセット(1ピン固定)
4. LCDコントラストを設定するため可変抵抗から電圧を読み込むADC入力
5. LEDを点滅させるデジタル出力
6. USBの5VからLCDとセンサの電源電圧3.3Vを生成するPWM(元電源が3.3Vなら不要)
を使います。あと電源の計8本で、ちょうど全てです。というか、きっちりなので例題にしました。 スケッチ(プログラム)は次のGitHubリポジトリに掲載しました:
pado3/ArduinoWBGT: Indoor WBGT meter with ATmega328P and ATtiny85
変化を追いやすいように、ブランチを3つに分けています:
1. mainのWBGT01.inoがATmega328Pで最初に使えるようにしたもの
2. WBGT03がATmega328P上でメモリ削減に取り組んだもの
3. WBGT03sがATtiny85で使えるようにしたもの
です。 最初のWBGT01では測定・表示機能の他に、シリアル通信によってArduinoIDE側へ途中経過や測定データを戻す機能がありました。ATtiny85ではピン数が少なくてシリアル通信ができなくなるので、Serial.print()等をバッサリ消しました。これだけでflashが3kbyte減りました。
LCDとセンサの電源をPWMから外部レギュレータに変えてみても、flashは172byteしか減らず、元に戻す。
LCDのコントラストをADC読み取りから決め打ちに変えてみても、flashは160byteしか減らず、元に戻す。
温湿度からWBGTデータを出す対照表(intの20x17 =
温度の演算に使っているdoubleの変数3つをintに変えるとflashが930byteも減りました。元々intの読み取り値を表示・演算のためにdoubleにしているだけなので、intとcharで操作することにします。
ここまでスイッチサイエンスさんのLCD表示サンプルプログラムをそのまま使わせて頂いていたのですが、この中のlcd_printInt()を消して別処理にするとflashが1344byte減りました。どうも、sprintf()がメモリ喰いだったようです。
これで、ATmega328P上では8k/512/512に収まりました。主要なポイントをまとめると次の通りです(他にも細々と手直ししているので単純な加減にはなっていません):
| 項目 | flash | EEPROM | RAM |
|---|---|---|---|
| WBGT01初期 | 13562 | 0 | 1254 |
| Serial削除 | 10460 | 0 | 969 |
| 対照表をEEPROMへ | 9480 | 340 | 289 |
| 一部メッセージ削除 | 9402 | 340 | 270 |
| doubleを3つintに | 8472 | 340 | 270 |
| メッセージをEEPROMから読む | 8576 | 364 | 276 |
| lcd_printInt()削除 | 7272 | 364 | 272 |
| floatを1つintにして表示処理 | 7852 | 364 | 270 |
| 細かな処理や待ちの見直し | 7888 | 364 | 279 |
メモリが削減できたのに気をよくして、いよいよATtiny85へ移します。
次のブログなどを参考に調べたところ、ATtinyでは、I2C通信に使っていたWireの代わりにTinyWireMを使います。また、WireとTinyWireMで1つだけ異なるコマンドがあります。
TinyWireMのインストールは、こちらを参考にしました:
ATtiny85でI2C-LCDを使う方法 | Arduino | kosakalab
(ST7032ライブラリは特に必要ありません。)
プログラムの移植は、こちらを参考にしました:
ATtiny85 - Tomiya's blog (3DCG & Photo etc.) こちらを元に、まずはLCDの表示、EEPROMの読み書き、そして全体構成へと進めます。
LCDの表示は、まず"Wire"を"TinyWireM"に全置換します。
次に、Tomiyaさんの記事ではWire.writeからTinyWireM.sendへの差し換えは慎重にとありますが、.writeのままだとフリーズしたので、とりあえず.sendに全置換したところ、あっさり動いてくれました
続いてEEPROMへの読み書きをしたのですが、ここで引っかかりました。ATmega328Pでは対照表全てとメッセージを一気にEEPROMへ書けたのですが、ATtiny85ではRAMオーバーになってしまいます。
最初は、それでもデータを前後半に分けたら書けるかと思ったのですが、コンパイル時に「スケッチが使用できるメモリが少なくなっています。動作が不安定になる可能性があります。」というメッセージが出て、無視して書き込んでみるとデータ化けの嵐。

結果としてデータを4分割とメッセージを別枠にした5段階書き込みをすることになりました。
ここをクリアしたところで、ATmega328PのWBGT03から
1. "Wire"を"TinyWireM"に全置換
2. "TinyWireM.write"を"TinyWireM.send"に全置換
すると、あっさりとWBGT計として動作してくれました。

この時のメモリ使用量は5548/364/79byteで、flashもRAMも使用量がとても少なくなりました。おそらくライブラリの違いが大きいのだろうと思われます。
回路図は次の通りです:

というわけで、無事にシュリンクすることができました。ただ、ここから更にflashを4kまで削減してATtiny45に収めるのは一苦労しそうです。 以上、何かの参考になれば幸いです。ご利用は自己責任で。 パドラッパ from MacBook Air (2017) 【2020/10/07追記】
・EEPROM周りでのポカを修正しました(見え消しあり、お恥ずかしい限り)。
・回路図のノードが分かりにくかったので修正しました。
| 固定リンク | 0


コメント