CHIRIMENでI2Cデバイスを使ってみる

今日は、CHIRIMENからI2Cデバイスを使ってみたいと思います。

# I2Cとは?

I2Cと書いて「アイ・スクエア・シー」と読んだり「アイ・ツー・シー」と読んだりします。
まぁ、私はいい加減な人なので、どっちでもいいです。
で、これは何か？というと、シリアル通信規格の一種です。
I2Cと同じようによく使われるシリアル通信に、UARTやSPIなどがありますが、I2Cは2本の線（SCL/SDA）で構成する1つのバスに複数のモジュールを接続できるのが最大の特徴と思います。配線が少なくて済むのでいろいろ楽です。

参考：
- [UM10204 2C バス仕様およびユーザーマニュアル](http://www.nxp.com/documents/user_manual/UM10204_JA.pdf)
- [I2C(Wikipedia)](https://ja.wikipedia.org/wiki/I2C)

I2Cでは「Master」から複数の「Slave」を制御します。例外もありますが、基本的にホストコンピュータ側が「Master」となり、デバイス側が「Slave」として動作します。CHIRIMENはI2C「Master」として動作します。

# I2Cに対応したモジュール

I2Cに対応したセンサーやアクチュエータなどは、その多くがI2C Slaveとして動作するデバイスです。

- [スイッチサイエンスでI2Cで検索して出てくる商品の一覧](https://www.switch-science.com/catalog/list/?keyword=I2C)
- [秋月電子でI2Cで検索して出てくる商品の一覧](http://akizukidenshi.com/catalog/goods/search.aspx?search=x&keyword=I2C&image=%8C%9F%8D%F5)

# CHIRIMENに接続するI2Cデバイスを選ぶには?

上記スイッチサイエンスや秋月電子で購入できるI2C対応デバイスが全てすぐにCHIRIMENで使えれば良いのですが、残念ながら現時点では「すぐに利用可能」なデバイスは限られています。

CHIRIMENで利用可能なI2C機器は、下記条件を満たしたものに限定される認識です。

- 1. 対象デバイスのI2Cバス上でのデータ送受信の仕様が、[Web I2C API](https://rawgit.com/browserobo/WebI2C/master/index.html)がサポート可能な仕様であること
- 2. I2Cバスライン(SDL/SCA)の電圧が3.3Vに対応した機器であること

上記条件を満たした機器であっても、すぐに使えるわけではありません。下記のような作業が必要になります。

- 3. デバイスを利用するためのドライバーを入手する。あるいは自作する
- 4. ドライバーを経由してI2Cデバイスを制御するWebアプリを書く

なんだか大変そうですね。確かに全部自分でやろうとすると結構大変です。

そこで最初は、CHIRIMENコミュニティの[examples](https://github.com/chirimen-oh/examples)に登録されたデバイスから使ってみると良いと思います。

[examples](https://github.com/chirimen-oh/examples)には、CHIRIMENコミュニティ有志によって動作確認されたデバイスのサンプルコードが登録されています。

# ~~Web I2C APIを使ってみる~~ → I2CデバイスをCHIRIMENに対応させてみる

それでは、[examples](https://github.com/chirimen-oh/examples)に登録されているデバイスをCHIRIMENにつないでみましょう！

。。。という風に進めたかったのですが、ポカをしてしまい、なぜか現在手元に[examples](https://github.com/chirimen-oh/examples)に登録されているデバイスが１つもありません。。。。。

なぜか手元のI2Cデバイスは？というと、Arduino、[Canzasi](https://github.com/tadfmac/Canzasi)、そして[MCP4018（デジタルポテンショメータ）](http://akizukidenshi.com/catalog/g/gI-07610/)という状況。

いきなりハードル高めで申し訳ありませんが、[MCP4018](http://akizukidenshi.com/catalog/g/gI-07610/)をCHIRIMENで使ってみようと思います。

> つまり、最初はexampleを使ってみよう！ということができず、最初っから上記1〜4全部やってみよう！というスパルタ記事です。ええ、書いてる私も泣きそうw

## 1. Web I2C API に対応できるか? をデータシートで調べる

I2C対応デバイスをCHIRIMENで使えるようにするために、最初の条件を確認してみます。

### 現時点で [Web I2C API]() が対応しているAPIを知る

現時点の[Web I2C API](https://rawgit.com/browserobo/WebI2C/master/index.html)は、まだドラフト段階のため、様々なI2C機器のデータ送受信仕様が実現できるようにAPIが網羅されているわけではありません。
現在[Web I2C API](https://rawgit.com/browserobo/WebI2C/master/index.html)で、I2C Slaveデバイスへのデータ書き込みや読み込みに利用可能なAPIは`5.5 The I2CSlaveDevice interface`に記載のある下記APIです。

```.webidl
interface I2CSlaveDevice {
    readonly attribute unsigned short slaveAddress;
    Promise  read8(unsigned short registerNumber);
    Promise  read16(unsigned short registerNumber);
    Promise  write8(unsigned short registerNumber, octet value);
    Promise  write16(unsigned short registerNumber, unsigned short value);
};
```

上記は全てCHIRIMENで利用可能です。

上記APIを呼び出した時にI2Cバスに流れるデータは下図のようになります。

![webI2c-I2CSlave-Interface@2x.png](https://qiita-image-store.s3.amazonaws.com/0/31758/1edacb6a-8e47-262e-36c8-a665fc80dde2.png)

これをよく覚えておきましょう。

### MCP4018のデータシートを読む

[MCP4018のデータシート](http://akizukidenshi.com/download/ds/microchip/MCP4018.pdf)を読んでいきます。
MCP4018はデジタルポテンショメータというもので、デジタルで制御可能な可変抵抗です。
今回買ったのは、10kΩのものです。127段階で10kΩを最大とした抵抗値に変更可能です。

> I2Cがどうとか以前に、[SC70-6](http://cds.linear.com/docs/en/packaging/SOT_6_05-08-1638.pdf)というパッケージサイズが、非常にハンダ付けハードルが高いですが、変換基板等へのハンダ付けの話はここではしませんw
> SC70-6の変換基板が入手できればそれが一番ですが、[SOT23-8の変換基板](http://akizukidenshi.com/catalog/g/gP-08342/)でもなんとかなるでしょう。私はaitendoのSOT23-8の変換基板を使いました。

少なくとも、下記を読む必要があります。

- P.1。概要と各ピンの機能把握。
- P.36〜 I2Cのコマンドプロトコルについて書かれている

ここで確認することは2つ。

1. I2Cスレーブアドレス

これは、P.36 Figure 5-9 を見ると、7bitで `0101111`となっていますので、`0x2F`であることがわかりました。

2. I2Cコマンド

続いてI2Cコマンドも確認します。
重要なのは、`5.4.1 WRITE OPERATION`です。
デジタルポテンショメーターの機能を使う目的では、これに対応するだけでも問題ないでしょう。

ここで気になる部分が。

> Data bytes may be written after each Acknowledge.
The command is terminated once a Stop (P) condition
occurs. Refer to Figure 5-12 for the write sequence.
For a single byte write, the master sends a STOP or
RESTART condition after the 1st data byte is sent.
The MSb of each Data Byte is a don’t care, since the
wiper register is only 7-bits wide. 

確かに、7bitの分解能しかないMCP4018がシングルバイトのみの書き込みで十分です。
しかし、ここで言う`MSb`が、何byte目を指すのか。実はこの仕様を正確に把握することが重要になります。

前に書いたように、現行のWeb I2C APIは「1byteだけの書き込み」はサポートしませんが、MCP4018側が下記のような動作を行ってくれれば、2byteを書き込む`I2CSlave.write8()`がつかえそうです。

1. 最初に来た1byte（I2CSlave.write8()を使った場合、registerNumberパラメータ）を有効な値として取り扱う。
2. Stopコンディションの直前に来たデータ（I2CSlave.write8()を使った場合、valueパラメータ）が有効になる

いずれの動作であっても、`I2CSlave.write8()`がつかえそうです。(書き方は変わりますが)

> 検証してみたところ、2. の動作となるようです。

さて、MCP4018は`5.4.2 READ OPERATIONS`にあるように、データReadにも対応しているようですが、正直何に使うのか？なので、ここでは無視することにします。

## I2Cバスライン(SDL/SCA)の電圧が3.3Vに対応したデバイスか？ をデータシートで調べる

こちらも[MCP4018のデータシート](http://akizukidenshi.com/download/ds/microchip/MCP4018.pdf)を確認する作業です。

P.4 `AC/DC CHARACTERISTICS`によると、2.7〜5.5Vという電圧に対応しています。
まずは、電源ラインはクリアになりました。3.3Vにも対応しています。

もう1箇所確認が必要なページがP.8です。`Digital Inputs/Outputs (SDA, SCK)`の項です。
大事な箇所なので、下記にキャプチャーを置きます。

<img width="639" alt="DCi2cbus.png" src="https://qiita-image-store.s3.amazonaws.com/0/31758/2d90b61a-4ea7-5410-a350-e57c058bc123.png">

これを見ると、

- HIGH = VDDの電圧の70%以上であること
- LOW = -0.5V〜VDDの電圧の30%以下の範囲であること

となっています。

CHIRIMENのI2Cポートの電圧は3.3Vですので、MCP4018のVDDを3.3Vから供給すれば問題ないはずです。

> CHIRIMENの5VからMCP4018のVDDには接続しないでください。
> 上記の通り、MCP4018がI2CのラインでのHIGHの検出に「VDDの電圧の70%以上」が必要です。
> 5VをVDDとしてしまうと、MCP4018側がHIGHである、と認識する閾値電圧は 5 * 0.7 = 3.5Vとなり、3.3Vより高くなってしまいます。つまり、CHIRIMEN側がHIGHにしたつもりで3.3Vまで上げたとしても、MCP4018側がHIGHになってないと認識してしまう原因となります。MCP4018に限らず、「VDDの電圧の70%以上をHIGHとする」という仕様は[I2Cバス仕様](http://www.nxp.com/documents/user_manual/UM10204_JA.pdf)中(3.1.2章)にも記載のある設計仕様ですので、覚えておきましょう。

## 3. デバイスを利用するためのドライバーを書く

仕様がだいたい理解できましたので、MCP4018をWeb I2C APIから使うコードを書いてみましょう。
[i2c-VEML6070のサンプル](https://github.com/chirimen-oh/examples/tree/master/i2c-VEML6070/js)をベースに書いてみます。

下記のようになりました。

```mcp4018.js
var mcp4018 = function(i2cPort){
  this.i2cPort = i2cPort;
  this.slaveAddress = 0x2F;
  this.i2cSlave = null;
};

mcp4018.prototype = {
  init: function(){
    return new Promise((resolve, reject) => {
      this.i2cPort.open(this.slaveAddress).then((i2cSlave) => {
        this.i2cSlave = i2cSlave;
        console.log("i2cPort.open");
        resolve();
      });
    });
  },
  set: function(value){
    if(this.i2cSlave){
      console.log("mcp4018.set("+value+")");
      if(value > 127) value = 127;
      if(value < 0) value = 0;
      this.i2cSlave.write8(0,value);
    }else{
      console.log("i2cSlave has gone.....");
    }
  }
};
```

### 少し解説

T.B.D. 解説は後日書く予定

## 4. ドライバーを経由してI2Cデバイスを制御するWebアプリを書く

MCP4018を制御するドライバーができましたので、引き続きWebアプリを作って完成です。
今回は、下記のような回路を作って、LEDを「ふわふわ」と点滅させてみます。
PWMと違い、アナログ電圧で「ふわふわ」やってますので、精神的な「ふわふわ」感も向上してるはず！？w

![Group 5.png](https://qiita-image-store.s3.amazonaws.com/0/31758/f543a0a3-031d-6377-6f29-89d7863a2c11.png)

残りのWebアプリのコードは下記の通り、今回はUIなどぜんぜんありませんw

```index.html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
<title>mcp4018 Test</title>
<script src="./webi2c.js"></script>
<script src="./mcp4018.js"></script>
<script src="./main.js"></script>
</head>
<body>
<p>mcp4018 TEST</p>
</body>
</html>
```

そして、こちらが先ほど作ったmcp4018.jsを使って、LEDの抵抗値を少しづつ変えることで明るさを変更している部分です。

```main.js
navigator.requestI2CAccess().then((i2cAccess) => {
  var port = i2cAccess.ports.get(0);
  var value = 0;
  var mode = 0;
  var digipot = new mcp4018(port);
  digipot.init().then(() => {
    console.log("digipot.init() done!");
    setInterval(() => {
      if(mode){
        value -=4;
        if(value < 0){
          value = 0;
          mode = 0;
        }
      }else{
        value +=4;
        if(value > 127){
          value = 127;
          mode = 1;
        }
      }
      digipot.set(value);
    },30);
  },(v) => {
    console.log("digipot init error:"+v);
  });  
}).catch((e) => {
  console.error("digipot I2C bus error!", e);
});
```

上記ファイルに加え、[@MSakamakiさんによるpolyfill](https://github.com/club-wot/WebGPIO)から、

- webi2c.js
- worker.js

をindex.htmlと同じフォルダに入れる必要があります。

最終的なWebアプリのフォルダの中に必要なファイルは下記になります。

- index.html
- main.js
- mcp4018.js
- webi2c.js
- worker.js

上記をWebサーバに置けば完成です！

[動作サンプル(CHIRIMENのブラウザからMCP4018との回路組んでからアクセス)](http://mz4u.net/chirimen/mcp4018/)

![imb_203FC71B-66B8-4B4C-9A50-0B56B188C54B.gif](https://qiita-image-store.s3.amazonaws.com/0/31758/3bba661e-beee-e08c-692e-2b9e417df1ed.gif)

# 今回はここまで！

今回は、市販のI2Cデバイスの中からCHIRIMENに対応可能なデバイスの見つけ方（データシートの読み方）と、Web I2C APIへの対応手順について記載してみました。

> Web I2C APIへの対応手順については、少し記載が足りないので後日補足予定です。ようするに途中で疲れましたw

次回は、[Canzasi]()というArduinoを利用してI2Cデバイスを作る環境を紹介します。