i2c-tiny-usbを作った

# 動機
デスクトップからI2Cを叩く際には、USBシリアルを経由して自作の[I2CBridge](https://github.com/toyoshim/I2CBridge)を使っていたんだけど、ラップトップで手元をごちゃごちゃさせたくなかったので、USBから直接I2Cを叩くことを考えた。
またラップトップではWindows上のVMでLinuxを走らせていたんだけど、その中からUSBシリアル→I2CBridge→デバイスという経路だと妙に重くなっていたのも理由。ただ、結局こちらは解決できなかった。

# ここが嬉しい
自分でゼロから作っても良かったんだけど、[i2c-tiny-usb](http://www.harbaum.org/till/i2c_tiny_usb/index.shtml)はドライバがLinuxのkernelに取り込まれてるのが魅力。```/dev/i2c-N```といったデバイス名を経由して共通のAPIでアクセスできる。つまり、Raspberry PiのI2C向けに書いたコードがそのまま動く。
Windowsからlibusb経由で叩くサンプルもあるので、いざ直接Windowsでコードを書く気になった時も安心。

# 改変
オリジナルはATTINY 45を使っていたんだけど、日本だと（秋月に売ってないので）安く手に入れにくい事もあり、かわりに秋月で手に入る85を使った。他にも手元の在庫で作った関係で部品はかなり変えて作ってる。以下、改変リスト。

|部品 | オリジナル            | 改変後                |
|----:|:----------------------|:----------------------|
|D1,D2|3.6V ツェナーダイオード|3.3V ツェナーダイオード|
|R2,R3|68Ω 抵抗              |75Ω 抵抗              |
|C6   |10μF 電解コンデンサ   |47μF 電解コンデンサ   |
|U$1  |ATTINY45               |ATTINY85               |

最初の試作版はクリスタルも使わずにセラロックにしていたんだけど不安定だったのでクリスタルに戻した。結局不安定だった理由はUSB端子のハンダ付けが甘かったのが主な理由だったみたいだけど。ブレッドボードに並べた範囲では手元の10個ほどのセラロック全てで安定動作してました。って事で、V-USBではクリスタル使うべきってのが一般的なんだけど、個人的にはセラロックでも十分動いてます。昔は相性問題がでるホストもあったんだけど、そういう時にはハブを間に入れることで解決。まぁ、今回は安全を見て、またラップトップで使う事も考えてクリスタルにしておきました。
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f31323834332f33363965353937612d366332312d393737622d316465652d3266346336626564633932302e6a706567.jpeg](https://qiita-image-store.s3.amazonaws.com/0/12843/07c85fbd-8fe1-b019-70e8-58d2a803a932.jpeg)
完成した基板はこんな感じ。ラップトップでコンパクトに使えるよう、そのままUSBに挿せる形で作りました。右のピンがI2Cになってて、別の基板にそのままぷすっと挿せば使える。「ピッコロさん緑色なのに〜」とか際どいセリフをこの御時世にどうどうと映画で使える鳥山先生は偉大です。

# ファームウェア
## コンパイル時の注意
最初はチップを変えたこともあり、再コンパイルした物を使ってたんですが、付属の45用の物をそのまま焼いても動くようです。一応、再コンパイルする際の注意点をいくつか書いておきます。

* -mmcu=attiny45を-mmcu=attiny85に変更（念のため）
* if !defined(\_\_AVR_ATtiny45\_\_)の分岐を85でも適用されるよう修正
* VUSB版で行くならusbdrvを最新版に入れ替えるのが最新AVR-gccでコンパイルする近道
 * 変えたくなければPROGMEMで宣言してる変数をconstにする
 * 45/85のコードパスは問題ないが、別のコードパスでは割り込みハンドラの名前がpoisonedと言われるので修正が必要（deprecateを許してbuildするかリネームするか）

パッチの例を[こちら](https://github.com/toyoshim/misc/blob/i2c_tiny_usb/i2c_tiny_usb.diff)に置いておきます。

## 焼き込み時の注意
セラロックや外部クロック（安売りでまとめ買いしたSGシリーズとか）を使うならfuse設定を正しく変更するのを忘れずに。あと、このファームはリセットピンを殺すので一旦fuseを書き込むと定電圧シリアルプログラミングができなくなります。

1. ファームウェア書き込み
2. fuse設定書き込み

の順番に書き込まないと後悔するので注意。またhidaspxでhigh/low両方のfuseをまとめて書き込もうとした際、[RSTピン無効化チェック](http://www-ice.yamagata-cit.ac.jp/ken/senshu/sitedev/index.php?AVR%2FHID_reports06#content_1_5)に引っかかってクロック設定だけ書き換えてしまう事にならないように注意。ここで警告メッセージをみると焼きこみ環境でもクロック入れないと次の修正ができません。-fH0x～のところを-f#H0x～と書いて確実に一発でキメましょう。
![fuse_errors.png](https://qiita-image-store.s3.amazonaws.com/0/12843/98d31e80-80fd-149a-db54-12543c59862d.png)
悪い例。GUIから書き込みをしていて油断していたスクリーンショットがこちらになります。クロック入れてコマンドから焼き直し。
ちなみに私はクリスタルとセラロックを行ったり来たりとデバッグしてた関係で高電圧シリアルでfuseをリセットする装置、でんし研さんの[Tiny45・13リセッター](http://homepage2.nifty.com/denshiken/AVR004.html)も作りました。
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f31323834332f31353661326530382d643833652d336536652d643766322d3631316633656232616566342e6a706567.jpeg](https://qiita-image-store.s3.amazonaws.com/0/12843/8121a924-b385-31c0-9aee-a47bc3ab75b6.jpeg)
こっちの方が回路面倒でしたが、一度作っておくと圧倒的に便利。しかし右上の抵抗周り汚いな。まぁ、茶色い感じの仕上がりです。

# I2Cの電圧
ここまでやっておいて、いざターゲットのデバイスを繋いだら動かなくて焦りましたが……単純に電圧の問題でした。本家の回路は5V動作でD-/D+だけ3.6Vに落としてるんですが、実は自分が使いたかったI2Cのターゲットは5Vでは動作しなかった。という事で電源を3.3Vに落としたい。
という事で、ここは最小限の手間で対応するため、基板上にスイッチを付け足してUSB電源を直接電源ラインに流す線と、USB電源を3.3Vツェナーx2で受けてから電源ラインに流す線を切り替えられるようにしました。
![USB-5v-33v-switch.png](https://qiita-image-store.s3.amazonaws.com/0/12843/92c483b5-976c-6917-8aae-524750f84061.png)
USB電源にざっくりこんな回路を挟んだだけ。最初の写真に写っていたスイッチはこの電源電圧の切り替えスイッチです。
（2016/8/10 注: 回路図のダイオードの向きが逆でした。実装は合ってたのに…。あとで回路図修正しますが、ひとまず注釈まで）
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f31323834332f64613032363032342d663639352d333337362d643635392d3738333831656134666361622e6a706567.jpeg](https://qiita-image-store.s3.amazonaws.com/0/12843/1e73d44f-d045-d22b-3b9d-1aac6f9dfe01.jpeg)
背面が足を使うだけで立体交差する事なくうまく配線できてて「ひゃっほーい」な気分だったのに、最後に追加したこの電源回路のせいで赤い線が2本入ってしまいました。残念。

# Linux上で使ってみる
```shell-session
% sudo apt-get install i2c-tools
% sudo modprove i2c-dev
```
ここまでやると```/dev/i2c-N```のデバイスが見えるはずです。