ATtiny85 で作る「I2C スキャナ」

「I2C スキャナ」は「ラジオペンチ」さんと「siliconvalley4066」さんのご協力のおかげで、思い描いていた理想の形で完成しました。
(前回の完成記事は下のリンクをご覧ください。まだ、自作基板の無料配布を行っています。)

この I2C スキャナの MCU(Micro Controller Unit:マーベル・・・ではありません。) には、Microchip(旧ATMEL)社の ATtiny44(オリジナルは ATTiny84)を使用しています。
最近は Arduino を使うことが多かったので、同じ会社の ATmega328P を使っていた事になりますね。
慣れというのは恐ろしいもので、「I2C スキャナを作るのには、ATtiny44 の性能でギリだよなぁ。」などと考えていました。

MCU の比較

昔は PIC という MCU をよく利用していましたが、最近では LED を点灯させたり液晶画面に文字を表示するだけに ATmega368P を使うという、当時の事を考えると大変贅沢な事をしています。
反省の意味を込めて表題とは離れてしまいますが、少し時間を使って MCU の能力を比較してみます。

ATmega328PATtiny44
CPU8 bit8 bit
クロック(最大)20 MHz20 MHz
プログラムメモリ32 kB4 kB
ROM33 kB4.25 kB
DATA ROM1 kB256 B
RAM2 kB256 B

やはりメモリ量が全然違いますね。Arduino でも少ないなぁと思うことは有りましたが、ATtiny44 はその1/8程度の容量しかありませんね。

実際のプログラム使用量

実際に AVR 用のプログラム環境「Microchip Studio」で I2C スキャナのプログラムをビルドすると、「2234 bytes 54.5 % Full」と表示されます。
4 kB の容量の半分しか使っていませんでした。まだ余裕ですね。

新たな情報

この記事を書き始めたのは、I2C スキャナのプログラムを修正してくださった「siliconvalley4066」さんのブログに新しい書き込みがあった事がきっかけでした。

詳しくは下のリンク(Arduino NanoでI2Cスキャナ)をご覧ください。

I2C スキャナを作り始めた当初、私もトライしたが挫折した「Arduino Nano にソフトウエア I2C を使って I2C スキャナを移植することが出来た」との事でした。

さっそく公開されている Arduino IDE 用の「i2cscanner.zip」をダウンロードして Arduino Nano で I2C スキャナを作ることが出来ました。
(非常に簡単に動作確認できたのと、今回の趣旨からは外れるので詳細は省略します。)

その後、「siliconvalley4066」さんが GitHub でプログラムを改修した「TinyI2CScanner」を見つけてくれました。
このプログラムの備えている機能を聞いて、私は大変驚きました。(Arduino 化の改修が出来た事だけでもビックリですが)
1 文字フォントの修正(u8g2ライブラリで5×7フォントを使って描画)
2 隣り合ったアドレスの塗りつぶしバグの修正
3 スイッチで7ビットアドレスと8ビット偶数アドレスの表示切り替え(アドレス変換機能)
4 SH1106(1.3 インチ OLED)使用可能
5 Arduino UNO、ATtiny85 でも動作可能

最初の2つは改修型の I2C スキャナで実現しています。
3つ目はプログラムを書き換えること機能的には実装していますが、スイッチで切り替えるとは・・・
4番目と5番目はスゴイですね。

特にこの I2C スキャナのプログラムが、8ピンで超小型の ATtiny85 で動くという事が驚異的です。
2つの I2C を使用するには4本のデータラインが必要です。MCU の電源に2本を使って、スイッチ切替にもう1本を使うと、残りの端子は1本だけです。(残りの端子は RESET 端子なので通常は使わないのかな?)

恥ずかしながら今までは ATtiny85 を使ったことがなかったので、その機能を確認します。
合わせて、あるコンピュータと比較します。(すでに下に見えていますが)

アポロ計画のコンピュータ

最近になって月の有人探査が話題になっていますが、初代の有人月探査計画の「アポロ計画」で宇宙船に搭載されたコンピュータ(AGC:Apollo Guidance Computer)の性能はファミコン並みと悪口を言われたりしますが、実際の姿とその性能は下のとおりです。
(写真は、Apollo11Spaceより引用)

製造年:1966年
CPU:16 bit、2.048 MHz
RAM:4 kB
ROM:74 kB
55W
32kg
61x32x17 cm

実際には打ち上げ前に地上で綿密な計算が何度も行われていて、宇宙船内では簡単な軌道修正が出来ればOKなので安定動作を優先したようです。(ミッション中に異常が発生して、テープドライブからプログラムを再ロードしたことはあったようです。)

月面に人間を送る前に何度も無人の宇宙船を送り込んだ後に、有人で月の周回軌道を回って帰ってきていますから、このコンピュータは現在のように人間が操作するのではなく、言い方は悪いですが有人長距離 ICBM の姿勢制御組み込み器材的な扱いですね。

また、宇宙船には2台の AGC の他にもロケット内部も含めて、多数のコンピュータが搭載されていました。
さらに、当時としては画期的で信じがたいですが、ソフトウエアはリアルタイムOS 上でマルチタスクに処理を行い、メモリ節約のために仮想マシンが動いていました。
(この筐体はその後、アメリカ軍でも共通規格として採用されていますね。似た形の処理装置をアメリカ軍の器材内で見たことがあります。)

ATTiny85

アポロの AGC と比較すると製造年が 2005年と40年近く違いますから当然ですが、小さくてプログラム容量が極小だと思っていた ATtiny85 も高性能ですね。(ROM と重量などは負けていますが。)

上で比較した表に追加してみます。

ATmega328PATtiny44ATtiny85-20
CPU8 bit8 bit8 bit
クロック(最大)20 MHz20 MHz20 MHz
プログラムメモリ32 kB4 kB8 kB
ROM33 kB4.25 kB8.5 kB
DATA ROM1 kB256 B512 B
RAM2 kB256 B8 kB

あれ?14ピンの ATtiny44 より8ピンの ATtiny85 の方が高性能じゃないですか。
これなら I2C スキャナが動いてもおかしくないですね。

ATtiny85 の機能

データシートを見ながら、今回の製作に必要な情報だけを確認します。

ピンの接続

まずはピンの接続図です。
電源:8ピン
GND:4ピン
SDA:5ピン
SCL:7ピン
これは決定ですね。

残りは1,2,3,6ピンですが、1ピンは RESET 端子なので使うのは最後の最後にします。
ピンの並び的には2,3ピンをソフトウエア I2C 用に使って、切り替えスイッチには6ピンを使うのが良さそうです。

端子のプルアップ

データシートで以下の2つの記載を見つけました。

1 Port B(PB5:PB0) is a 6-bit bi-directional I/O port with internal pull-up resistors.
(直訳:ポート B (PB5:PB0)は、内部プルアップ抵抗 を備えた 6 ビットの双方向 I/O ポートです。)

2 Pull-ups on the SDA and SCL port pin are disabled in Two-wire mode.
(直訳:SDA および SCL ポート ピンのプルアップは、2 線モードでは無効になります。)

素人なりに考えると、PB5(RESET 端子)には内部プルアップ抵抗が備わっている。
PB0(SDA 端子)にも内部プルアップ抵抗があるが、I2C が機能している時には SDA と SCL の内部プルアップ抵抗は無効になる。(つまり外付けが必要)

(Atmel 8-bit AVR Microcontroller with 2/4/8K Bytes In-System Programmable Flash より引用)

OLED のプルアップ

ちなみに、使用する OLED 2種類の SDA と SCL のプルアップ抵抗をネットで見つけた回路図で調べてみたら、

・SH1106:1.3 インチ OLED 4.7 kΩでプルアップ済み。
・SSD1306:0.96 インチ OLED 4.7 kΩでプルアップ済み。

という結果なので、ソフトウエア I2C 側のプルアップ抵抗は必要ない事が分かりました。

Arduino IDE へ追加

Arduino IDE へ ATtiny85 を追加します。(IDE は ver.2 系で説明しています。)

まず、「ファイル」「基本設定」を開きます。
開いた画面の一番下の緑のマークを押して「追加のボードマネージャのURL」を追加します。

開いた画面に「http://drazzy.com/package_drazzy.com_index.json」と入力します。(コピペが楽です。)
すでに何か入っている場合は、改行して下に追加しましょう。

続いて「ボードマネージャー」のアイコンを押して検索欄に「ATtiny」と入力して「ATTinyCore by Spence Konde」を探してインストールします。(図の下側の方です。)

これで、Arduino IDE へ ATtiny85 が追加されました。

ATtiny85 へブートローダの書き込み

前回の「Microchip Studio」を使って ATtiny44 にプログラムを書き込んだ時は、ブートローダは不要でしたが、Arduino IDE からスケッチを書き込んで動作させるにはブートローダが必須です。

まず、「ツール」の「ボード」で追加された「ATTinyCore」の中から「ATtiny25/45/85(No bootloader)」か「ATtiny45/85(Optiboot)」のどちらかを選びます。
(今回は USBasp を使うのでどちらでも同じです。2回目以降の書き込みに USB 変換器を使うなら(Optiboot)を選びます。)

次に、「ツール」の「書き込み装置」で「USBasp(ATTinuCore)」を選びます。

ここまで出来たらパソコンに USB ケーブルで USBasp 経由で ATtiny85 をつなぎます。

この接続で正しくつないでも USBasp 経由の場合は、「ツール」の「ポート」には USB 機器が認識されませんが大丈夫です。

では、ブートローダの書き込みです。
「ツール」の「ブートローダを書き込む」を押します。
配線が間違っていなければ、こんな感じのメッセージが出て書き込みの正常終了が分かります。
(一瞬、メッセージが赤系の色なのでエラーかと思いました。)

I2C スキャナ用の配線

ATtiny85 で I2C スキャナを動作させる場合の配線図です。
下の配線図では動作確認用のブレッドボード用に作図したので付けていませんが、本来は I2C 用の SDA と SCL にはプルアップ抵抗が必要です。
(すでにプルアップ抵抗がオンボードで付いている I2C の部品もあるので、その場合にはプルアップ抵抗を外した方が良いでしょう。)

なお、この配線にスケッチ書き込み用の USBasp をつないだままでも I2C スキャナは正常動作しました。
(電池での動作を確認する時は、流石にパソコンから USB ケーブルを抜きますが)

TinyI2CScanner プログラムの入手

「TinyI2CScanner」の改良版のプログラムが GitHub に上がっているのを「siliconvalley4066」さんが見つけてくれました。
以下の3種類あります。(日付を見ると、どれも7年前に作られたようです。)

・tinyFontブランチ:名前からすると小さいフォントのバージョンでしょうか?
・tinusaurブランチ:ソフトウェアを単純化したバージョン
・master:本家です。
(GitHub のブランチとは、本家の改造バージョンです。)

とりあえず、動作確認は4年前まで改修が行われていた「master」で行います。
ダウンロードは「avaldebe /TinyI2CScanner」の「Download ZIP」を押します。

Arduino IDE で動かす

「siliconvalley4066」さんの記事に丁寧に手順が書いてありますが、要約すると

1 ソースコードの「main.cpp」を TinyI2CScanner.ino 等に名称を変更
2 ライブラリが肥大化して ATtiny85 では動かないので「#define USE_U8X8」を追加
3 SDA 、SCL のピン番号を指定
4 切り替えスイッチのピン番号を指定
5 必要に応じて OLED を変更

以上です。

実際にやってみましょう。

ファイルの名前変更

TinyI2CScanner-master.zip を適当なフォルダに解凍します。
「src」フォルダ内の「main.cpp」を TinyI2CScanner.ino に変更して TinyI2CScanner フォルダに移動します。

スケッチに追記

スケッチ内の「#include <Arduino.h>」の下に3行を追記します。
(さらに「#define DISPLAY_128X64 SH1106」を追記すると 1.3 インチ OLED 対応です。)

スケッチの書き込み

USBasp 経由でスケッチを書き込むには、「スケッチ」の「書き込み装置を使って書き込む」を押します。
通常の書き込みでは動作しません。

「書き込み装置を使って書き込む」を押します。
あれ?エラーが出ました。
忘れていました。このスケッチでは ATtiny85 の I2C を動かすのに「TinyWireM.h」を使っていました。

ライブラリの追加

ライブラリの検索で「TinyWireM.h」を探します。
出てきたコレをインストールします。

再度「書き込み装置を使って書き込む」を押します。
通常の USB 経由での書き込みに比べると「心配になるぐらい」何倍もの時間がかかりますが、Windows 版の Arduino IDE では進捗グラフが出るのでおとなしく待ちましょう。(Linux 版は何も出ないのでエラーかな?と思うレベルです。)

動作画面

正常に書き込みが終わると、勝手にリセットされて OLED に I2C スキャナの画面が表示されます。
下の写真の画面は、1.3 インチの OLED(SH1106)を使用しています。

左列が「3」最上段が「C」との交点に印が付いているので「0x3C」ですね。
接続されているのが OLED なので I2C アドレスは合っています。

スイッチを押すと(画面の書き換えが凄く遅いですが)こちらの表示に切り替わります。
8ビットアドレス表示ですね。
I2C アドレスは OLED 裏に記載されている「0x78」です。

他のプログラムの検証

他に2つのブランチがありますので、一応動作確認をしてみます。

tinyFontブランチ

tinyFontブランチのプログラムも、同じ手順で検証してみました。
こちらのプログラムは、「src」フォルダに「main.cpp」と画面定義用の「img.h」があるので、名前を TinyI2CScanner2.ino に変えた main.cpp と同じフォルダに入れておきます。(今回は TinyI2CScanner2 にしました。)

中身を見ると、2つ目のソフトウエア I2C が見当たりません。ハードウエアで持っている I2C 端子(5,7ピン)につないだ OLED に OLED のアドレスを表示するので、検出端子に同じ I2C アドレスの OLED をつないでも認識できません。
そして、どこかで見たような画面表示の不具合(Y軸が8ドット上にズレる)が発生しました。

また、スイッチでアドレスを切り替える機能も搭載されていませんし、OLED も 0.96 インチのSSD1306 のみの対応です。

tinyFontブランチのまとめ

・OLED 表示でY軸が8ドット上にズレる不具合が発生
・セカンド I2C 未搭載
・アドレス切り替えスイッチがない(7ビットアドレス表示機能なし)
・0.96 インチの OLED(SSD1306)のみ対応

本来ならば、このスケッチを修正して正常動作させるべきでしょうが、Main ブランチで正常動作しているので動作確認のみで、機能が落ちるこちらのブランチを改良する深みにハマるのはやめておきます。

tinusaurブランチ

最後に tinusaurブランチを確認します。
今回は Main と同様に「main.cpp」単体で出来ていました。
名前を TinyI2CScanner3.ino に変えた main.cpp を「TinyI2CScanner3」フォルダに入れておきます。

まず、「ssd1306xled.h」という 0.96 インチの OLED 用(SSD1306)のライブラリが必要です。
追加でこのライブラリを入れて書き込みを行うと、こちらも画面の端に表示の不具合が出ます。
(表示不良は最下行の一部だけなので、I2C アドレスを確認することは出来ます。)
起動時の画面

タクトスイッチを押した後の画面

スイッチでアドレスを切り替える機能は正常に動作しました。
一応正常動作しているのですが、ソフトウエアの仕様でアドレスを区切るための四角は出ますがアドレスを表す数字が表示されません。
画面の外にシールで数字を表示するという「力技」です。
(こんな感じになるであろう完成予想図です。)

スイッチ切替後の画面

でも、上の図面を書いていて気付いたのですが、スイッチで切り替えた後に左列の数字が変化します。
スイッチを切り替える毎にシールを張り替える?それとも、スライドスイッチに連動して数字を機械的に入れ替える?
どちらにしても面倒ですね。

tinusaurブランチのまとめ

・画面表示の一部不具合
・セカンド I2C 未搭載
・OLED 画面内にアドレス表示がない(仕様です。)
・スイッチ切替ごとに枠外の数字を切り替える処置が必要
・0.96 インチの OLED(SSD1306)のみ対応

まとめと講評

OLED が2種類選択できることや表示に不具合のない事などを考慮すると、他の2つのブランチと比較すると メモリ不足で画面表示がオリジナルの枠表示ではなくなってしまっても、Main ブランチが一番良い感じです。(3年間の改善の結果でしょうか?)

8ピンの ATtiny85 を使ったこの I2C スキャナならば、コイン電池を内蔵して小型化が可能な気がします。
時間のある時に、3D プリンタでケースを作って完成形をご覧いただきたいです。
現在の満足度は60点です。

コメント

  1. まいくろ より:

    申し訳ありません、気になったので。
    ATmega368P → 328P
    我が家では328Pもtiny85も部品箱で眠ったままです。
    この記事をきっかけにして何か書き込んでみようかな・・・

    • パオさん より:

      「まいくろ」さん、コメントありがとうございます。
      「最近よく使っている」と書いておきながら、型番を間違っていました。(お恥ずかしい)
      ATtiny85 なら小型のI2Cスキャナが出来ます。
      部品が余っているなら1台作っておくと便利ですよ。

  2. トドお父さん より:

    パオさん、わたしのブログにコメントありがとうございました。

    表示のズレの件、パオさんの対策で直りましたが、ラジオペンチさんのブログに
    siliconvalley4066さんが原因らしい内容を書かれてましたので、深堀りしてみました。
    https://ameblo.jp/powpher/entry-12863559745.html

    情報に従って、oled_cls() でoled_init() で設定された、column とPageのスタート
    アドレスとエンドアドレスの重複設定をコメントアウトしてみました。

    次に oled_xy() は不要と書かれていたので、呼び出しをコメントアウトしました。
    これで、スタート Page(0) 、エンド Page(7)でも、正常に表示するようになりました。

    ATTINY85と0.96”OLEDでtiny I2C Scannerができる楽しい記事をありがとうございました。

    • パオさん より:

      「トドお父さん」コメントありがとうございます。

      ブログの記事が長いので分かりづらいと思いますが、実は私も1か月ほど前に「siliconvalley4066」さんから教えて頂いた表示ズレの改善などを行っていました。
      (私が最初に行ったのは、本家の「elektor MAG」誌のユーザフォーラムで長期間塩漬けになっていた表示不具合の「暫定的な」対策でした。)
      https://me-yoh.com/i2c-scanner_pcb_share#toc28

      最新のブログも拝見しました。
      新しい系列のATtinyは、書き込み方法も変更されているとは知りませんでした。勉強になります。