Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
I2CでRaspberry Piから
複数の周辺機器を制御する
2016-06-10
サイボウズラボ 西尾泰和
(兼 「未踏IoT開発合宿 #1」参加報告)
このスライドの目的
• 一般社団法人未踏のIoT研究会による
「未踏IoT開発合宿 #1」に参加した
• いままであやふやだったI2Cに関する理解が
深まったので忘れないうちに解説する
• 付録として合宿でどんなことをやったかを
報告する
2
前提
以前フリップフロップが1bitの情報を
記憶するところまで解説した。*
今回は
「ある装置の中のフリップフロップの値を
別の装置の中のフリップフロップに入れる」
という「通信」の実現方法を解説する
3
* マイコンのIOピンはなぜ入出力の...
1バイトの情報を送りたい
4
パラレル通信
デメリット:配線の本数が多い
5
その他、信号線間できちんと同期がとれないといけないとかで大変
シリアル通信
1本の信号線を時間
軸方向に区切って複
数のビットを送信
→シリアル通信
6
「シフトレジスタ」がつかわれる
シリアル通信
具体的な実現方法がいくつもある
• UART
• USART
• SPI
• I2C
• USB
7
UART
Universal Asynchronous Receiver/Transmitter
GND(グランド)とTX(送信)とRX(受信)を接続する。
1方向通信なら片方だけでいいので2本の
ジャンパーケーブルでつなぐだけ、と手軽。
8
UART以外の呼ばれ方(余談)
9
「RS-232C」や「シリアル」と呼ぶ人もいる。厳密に言えばUARTは回路の名前で、
通信プロトコル自体には名前にコンセンサスが存在しない状態。
昔はコンピュータに「シリアルポート」がついてて、RS-232C...
UART
Universal Asynchronous Receiver/Transmitter
非同期=クロック信号を共有していない。
どういう周期で信号線を読めばいいかわからない
→周期は事前に決めておく。(ボーレート)
例えばRaspbe...
115200 Baud
11
Putty
Tera Term
Arduino IDE
スタートビット
普段が0の信号線に00011000が流れた時、
00110000や 00000110と区別がつかない。
そこで頭に1を付けて「これから送るぞ」
と伝える。
受信側は、普段0の信号線が1になったら
「お、データが送られてくるぞ」
...
USART
Universal Synchronous/Asynchronous
Receiver/Transmitter
UARTに同期のためのクロック信号を付けたもの。
つまりGND, TX, UX, CLKの4本。
筆者は使ったことがない...
(追記)
Q: クロック信号とは?
A: 素朴に言えば「クロック信号線がLOからHIに
なったタイミングでデータ信号線を読む」といっ
た使い方をするためのタイミングを伝える信号。
(このスライドの後半でこの素朴な理解のせいで
罠にはまるのだが…...
point to pointのデメリット
UARTのような1対1で周辺機器をつなぐ方式は
周辺機器の数Nが増えるとIOピンが2N本必要
ピンを増やすこと・ピンの多いチップを使うこと
のコストは高いので、少ないピン数で通信したい
このニーズはどう...
「バス」の概念
IOピンを節約するために、
複数の周辺機器に個別に配線せず、
みんなで一つの信号線を共有しよう!
→「バス」の概念の誕生
16
バスの実現のために
信号線を共有すると、そこに書いた信号は
すべての周辺機器が受け取れる。なので
「誰がその信号に対して応答すべきか」
を伝える手段が必要になる。
SPIではそれを伝えるために専用の信号線(スレー
ブセレクト)を用意した。
一方...
SPI
Serial Peripheral Interface
USARTの「TX→周辺機器RX」に相当する信号線
がMOSIと呼ばれる*。逆方向の信号線(MISO)、
クロック信号(SCLK)、図に書かれていないGND、
とここまではUSAR...
SPI
複数の周辺機器が接続される場合、スレーブセレ
クトがLOである周辺機器が応答する。
19
画像出典 https://ja.wikipedia.org/wiki/シリアル・ペリフェラル・インタフェース
仕組みはシンプルだが周辺機器
の数だ...
I2C
Inter-Integrated Circuit。発音はI-squared-C。
日本だと「IスケアC」と書いてあることもある*
周辺機器に7bitのアドレスが決まっており、
そのアドレスを指定して通信する。 **
配線はGND含めて3...
I2C
SDA(データ)とSCL(クロック信号)の2本と、
図に書かれていないGNDを接続する。
ここまでのおさらい
UART GND, TX, RX
USART GND, TX, RX, CLK
SPI GND, MOSI, MISO, SC...
余談(USB)
UART~I2Cと色々なシリアル通信の方法があり、
SPIとI2Cはバスを採用していることを解説した。
この延長線にあるのがUSB(Universal Serial Bus)
USBはGNDと、信号線D+/-と*、電力供給のVB...
I2Cのプロトコル
雑な説明
1. マスター: アドレス(7bit)、Read/Write(1/0)、
を送る(1ビットずつ、SDAに出力して、クロッ
クを出力して、を繰り返す)
2. マスター: クロック信号を発行する
スレーブ: クロック信...
合宿で作ったもの
合宿で作ったこ
れの解説をする
24
合宿で作ったもの
I2Cバスに温度センサと液晶の2つをぶら下げ、
温度センサから0.5秒ごとに値を読んで、
それを液晶に表示する。
実は合宿中に満足して分解しちゃったので解説を
書きながら改めて作っている。合宿時の回路は部
品の下に配線があって...
周辺機器
上: 温度センサ
下: 液晶
SCL、SDA、GNDの並びは
同じなので向かい合わせ
に配置することにした。
液晶にはRESETがあるがこ
れはプルアップする
26
できた回路
再掲: SCL、SDA、GNDの並びは同じなので向か
い合わせに配置することにした。液晶のRESETは
プルアップする
27
Raspberry Piにつなぐ
Raspberry Pi 3のピン番号1, 3, 5, 9がそれぞれ
3.3V、SDA1、SCL1、GNDなのでそこへつなぐ
28
奥に3本あるのは本題と関係ない。6, 8, 10がGND, TX, RXで、P...
i2cdetect
つながっている周辺機器のアドレスがわかる
(液晶が3e、温度センサが48)
29
$ i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- ...
ソースコード
30
https://gist.github.com/nishio/6892f3de5d8b54153212c51f5e21f772
import smbus
from time import sleep
bus = smbus....
SMBus
Pythonから制御するにはsmbusライブラリを使う
SMBus(System Management Bus)はI2Cから派生
したプロトコルで、このライブラリでもI2Cを読
み書きできる。
31
I2C and SMBus Su...
温度センサ
ADT7410のデータシートを読む
32
http://www.analog.com/media/en/technical-documentation/data-sheets/ADT7410.pdf
温度計算式
33
難しかったポイント
read_i2c_block_dataで温度によって変化する
2バイトのデータがすんなり得られたが、
温度の計算方法の理解に手間取った。
レジスタの0と1が取れている。
レジスタ0の[14:8](最上位ビット以外)と
レジス...
液晶
「難しかったポイント」につまずく前に
講師の上田さんに教えてもらった。
• WRITEしか受け付けないのでR/Wは常に0
• Instruction WriteとData Writeの2つのコマンド
がある
• まず9回のIWを適切な待ち...
初期化フロー
先頭の00の
最初の0が
Instructionである
フラグ
次の0がWriteであ
るフラグ
1か所だけ200ms
しっかり待つ必要
がある
36
http://akizukidenshi.com/download/ds/xi...
文字コード
文字コードは
ASCIIとかではない
のでPython文字列
から文字コード列
を作る対応付けは
自分で書く必要が
ある
37
I2Cを傍受してみる
I2Cで実際に流れている信号を観察したくなった
オシロスコープやロジックアナライザが手元にあ
るならそれを使うのがよいが、ない
そこでI2CバスにGPIOをつないで読み、可視化す
るプログラムを書いた
38
ボーレートを下げる
$ sudo modprobe -r i2c_bcm2708
$ sudo modprobe i2c-bcm2708 baudrate=100
$ dmesg # 確認
[ 8.506891] bcm2708_i2c 3f8...
可視化
変化があった時だけ表示するプログラムを書いた
1行目がSCL、2行目がSDA(逆にした方が良かった)
「00001100 11001000」が返っているはず。 SCL
の立ち上がりでSDAを読んでみる(次ページ)
40
H__HH_H_...
2回やって比較してみる
41
take 1
01001000
H__HH_H_HH_H_H_H_H
__HH_____HHH______
00000000 10
_H_H_H_H_H_H_H_H_HH _H_H
________________...
アドレス48=1001000
42
take 1
01001000
H__HH_H_HH_H_H_H_H
__HH_____HHH______
00000000 10
_H_H_H_H_H_H_H_H_HH _H_H
_____________...
返り値
43
take 1
01001000
H__HH_H_HH_H_H_H_H
__HH_____HHH______
00000000 10
_H_H_H_H_H_H_H_H_HH _H_H
__________________H HH__...
データはACKを挟んで繰り返される
ことがある
44
http://www.nxp.com/documents/user_manual/UM10204.pdf
ACKとは
I2Cの信号線はプルアップされていて、
GNDと短絡することでLOを出力する。
つまり「接続している回路が誰もLOを
出力しなければHI」という挙動。
マスタは1バイト送り終わった後、
何もせずにSCLを読む。クライアントが
SCL...
SMBusのread word
先に読みたいレジスタのアドレスをWriteし、
そこから2バイトReadする。
46
https://www.kernel.org/doc/Documentation/i2c/smbus-protocol
比較してみる
47
take 1
01001000
H__HH_H_HH_H_H_H_H
__HH_____HHH______
00000000 10
_H_H_H_H_H_H_H_H_HH _H_H
__________________H H...
比較結果
• Write (‘0’)はどこ?
• アドレス後のACKは?
• コマンド後のが01だったり10だったり
…もしかしてコマンド00000000じゃなくて
これの頭の2bitがWriteとACKかも?
• データの間にACKがあるはず...
並べて書いてみる
49
take 1
0 1001000 0 0
00000010 0
0 1001000 1 0
00001100 0
11001000 1 0
take 2
0 1001000 0 0 # S Addr Wr [A]
000...
可視化
時間分解能不足を疑って「変化があった時だけ記
録」をやめてみた
クロック信号の幅の6~8倍の時間分解能で
記録ができている(Pythonでも)
50
HHH____________HHHHHHH______HHHHHH_______HH...
可視化
ただし行末と次の行とのつながりがおかしい
80文字のバッファがいっぱいになった時の処理
が重くて信号を取りこぼしている(仮説)
51
HHH____________HHHHHHH______HHHHHH_______HHHHHH____...
次のアクション
I2Cの通信を眺めて楽しむ目的なら
100bit程度が記録できれば十分(今50bit)
1bitあたり今32サンプル程度
ならば数千サンプルのバッファがあれば十分で、
全部ため込んでから後から可視化すればよい。
これを実装する。...
53全体像。SCLを2列目にした。
_____________________HHHHHHHHHHHHHHHHHHHHHH_____________________________________
HHHHHHHHHH_____________...
スタートコンディション
信号線はデフォルトHI、SCLより先にSDAがLOに
なる。これがアドレスを送る予告になる。
クロックの立ち上がりだけ見てて見落とした。
54
_____________________HHHHHHHHHHHHHHHHH...
スタートコンディション
改めて仕様書を読み直すとちゃんと書いてある
55
http://www.nxp.com/documents/user_manual/UM10204.pdf
アドレス=1001000
アドレス送信後 0 0 00000001 0 0 があって
クロックが長めにHIになる。
ここまでが最初の命令。
56
_____________________HHHHHHHHHHHHHHHHHHHHHH______...
改めて比較→仕様書通り!
S 1001000 0 0 # S Addr Wr [A]
00000001 0 P # Comm [A]
S 1001000 1 0 # S Addr Rd [A]
00001101 0 # [DataLow] A
...
クロックとは何なのか
「クロック信号」という言葉から時計のように定
期的に送られるものと誤解していた。
また、クロックの立ち上がりのタイミングでSDA
を読めばそれでよいのかと勘違いしていた。
実際には「SCLがHIである間にSDAがLOになっ...
I2Cまとめ
無事仕様書の記述と実際に観察された波形とが一
致した。
ボーレートを落とせばPythonでGPIOを叩いても
十分な時間解像度で波形を観察できる。記録時に
は余計な処理をせずに記録に専念するとよい。
SCLは信号線を読む周期やタイ...
付録:その他合宿でやったこと
60
ESP-WROOM-02
61
Wifiにつながるマイコン(まさにIoT!)
電力をかなり食うのでUSBの5Vバスパワーから
LM3671*で3.3Vを作って使った
UARTを使ってATコマンドを送って操作。Wifiに
接続したりHTTP GE...
付録: マルチマスター構成
SPIは、1つのマスターと複数のスレーブ。
I2Cは複数のマスターが可能な仕様。
I2Cの信号線はデフォルトHIで「GNDと導通させ
るかどうか」でLOとHIを表現する。なので複数
のマスターが同時にLOとHIを出力...
付録
Q: スレーブからデータを読むときもマスターが
クロックを発行する? A: Yes
Q: 自分が発行してないクロックに合わせてデー
タを書くとか無茶じゃない?
A: スレーブはクロックがLOになったのを見てか
らデータを書き、マスターはク...
Upcoming SlideShare
Loading in …5
×

I2CでRaspberry Piから 複数の周辺機器を制御する

16,587 views

Published on

兼 「未踏IoT開発合宿 #1」参加報告

Published in: Education
  • Be the first to comment

I2CでRaspberry Piから 複数の周辺機器を制御する

  1. 1. I2CでRaspberry Piから 複数の周辺機器を制御する 2016-06-10 サイボウズラボ 西尾泰和 (兼 「未踏IoT開発合宿 #1」参加報告)
  2. 2. このスライドの目的 • 一般社団法人未踏のIoT研究会による 「未踏IoT開発合宿 #1」に参加した • いままであやふやだったI2Cに関する理解が 深まったので忘れないうちに解説する • 付録として合宿でどんなことをやったかを 報告する 2
  3. 3. 前提 以前フリップフロップが1bitの情報を 記憶するところまで解説した。* 今回は 「ある装置の中のフリップフロップの値を 別の装置の中のフリップフロップに入れる」 という「通信」の実現方法を解説する 3 * マイコンのIOピンはなぜ入出力の両方に使えるのか? http://www.slideshare.net/nishio/io-52977913
  4. 4. 1バイトの情報を送りたい 4
  5. 5. パラレル通信 デメリット:配線の本数が多い 5 その他、信号線間できちんと同期がとれないといけないとかで大変
  6. 6. シリアル通信 1本の信号線を時間 軸方向に区切って複 数のビットを送信 →シリアル通信 6 「シフトレジスタ」がつかわれる
  7. 7. シリアル通信 具体的な実現方法がいくつもある • UART • USART • SPI • I2C • USB 7
  8. 8. UART Universal Asynchronous Receiver/Transmitter GND(グランド)とTX(送信)とRX(受信)を接続する。 1方向通信なら片方だけでいいので2本の ジャンパーケーブルでつなぐだけ、と手軽。 8
  9. 9. UART以外の呼ばれ方(余談) 9 「RS-232C」や「シリアル」と呼ぶ人もいる。厳密に言えばUARTは回路の名前で、 通信プロトコル自体には名前にコンセンサスが存在しない状態。 昔はコンピュータに「シリアルポート」がついてて、RS-232C規格に従って通信できた。 その25本or9本のピンのうちの3本がGND, TX, RXで、それが電子回路との通信に使われた が、最近はシリアルポートがないものが多いので「USBシリアル変換アダプタ」を使う。 https://www.switch-science.com/catalog/1032/ 画像出典 https://ja.wikipedia.org/wiki/RS-232
  10. 10. UART Universal Asynchronous Receiver/Transmitter 非同期=クロック信号を共有していない。 どういう周期で信号線を読めばいいかわからない →周期は事前に決めておく。(ボーレート) 例えばRaspberry Piにシリアル接続するなら 115200ボー、1秒に115200回読む。 10
  11. 11. 115200 Baud 11 Putty Tera Term Arduino IDE
  12. 12. スタートビット 普段が0の信号線に00011000が流れた時、 00110000や 00000110と区別がつかない。 そこで頭に1を付けて「これから送るぞ」 と伝える。 受信側は、普段0の信号線が1になったら 「お、データが送られてくるぞ」 と判断できる。 12 このやり方を「調歩同期」と呼ぶ データの最後に0を付ける(ストップビット)もよく用いられる
  13. 13. USART Universal Synchronous/Asynchronous Receiver/Transmitter UARTに同期のためのクロック信号を付けたもの。 つまりGND, TX, UX, CLKの4本。 筆者は使ったことがない。後述のSPIがメジャー になり、あえて使う理由がなくて使われなくなっ たという理解。 13
  14. 14. (追記) Q: クロック信号とは? A: 素朴に言えば「クロック信号線がLOからHIに なったタイミングでデータ信号線を読む」といっ た使い方をするためのタイミングを伝える信号。 (このスライドの後半でこの素朴な理解のせいで 罠にはまるのだが……スポイラー…) 14 例:1行目がデータの信号線、2行目がクロックの信号線、HのときHI、_の時LOとし、クロックの立ち上が りでデータ信号線を読むと「100100」となる _HHHHHHHHHHHHH_________________________HHHHHHHHHHHHH____________________________ ________HHHHHH______HHHHHHH______HHHHHH_______HHHHHH______HHHHHH_______HHHHHH___
  15. 15. point to pointのデメリット UARTのような1対1で周辺機器をつなぐ方式は 周辺機器の数Nが増えるとIOピンが2N本必要 ピンを増やすこと・ピンの多いチップを使うこと のコストは高いので、少ないピン数で通信したい このニーズはどうすれば満たせるだろうか? (というニーズがかつて高くて後述のSPIやI2Cが生まれたが、 今RasPiで数個の周辺機器を使う程度だとあまり関係ない) 15
  16. 16. 「バス」の概念 IOピンを節約するために、 複数の周辺機器に個別に配線せず、 みんなで一つの信号線を共有しよう! →「バス」の概念の誕生 16
  17. 17. バスの実現のために 信号線を共有すると、そこに書いた信号は すべての周辺機器が受け取れる。なので 「誰がその信号に対して応答すべきか」 を伝える手段が必要になる。 SPIではそれを伝えるために専用の信号線(スレー ブセレクト)を用意した。 一方I2Cでは「アドレス」の概念を導入した。 17 Q: 複数の機器が同時に書きこんだら? A: それに関しては付録で。
  18. 18. SPI Serial Peripheral Interface USARTの「TX→周辺機器RX」に相当する信号線 がMOSIと呼ばれる*。逆方向の信号線(MISO)、 クロック信号(SCLK)、図に書かれていないGND、 とここまではUSARTまでに出てきたものと同じ。 スレーブセレクト(SS)がSPIの特徴。 18 画像出典 https://ja.wikipedia.org/wiki/シリアル・ペリフェラル・インタフェース * Master Out Slave In
  19. 19. SPI 複数の周辺機器が接続される場合、スレーブセレ クトがLOである周辺機器が応答する。 19 画像出典 https://ja.wikipedia.org/wiki/シリアル・ペリフェラル・インタフェース 仕組みはシンプルだが周辺機器 の数だけIOピンが必要でピン 削減効果は弱い。 周辺機器を1個しか接続しない 場合はスレーブセレクトをプル ダウンして「常時そのスレーブ が選ばれてる状態」にすればよ い。(≒USART)
  20. 20. I2C Inter-Integrated Circuit。発音はI-squared-C。 日本だと「IスケアC」と書いてあることもある* 周辺機器に7bitのアドレスが決まっており、 そのアドレスを指定して通信する。 ** 配線はGND含めて3本と、USARTよりさらに少な い。入力も出力も1本の信号線でやるため。 20 * シリアルIスケアC EEPROM 24FC256-I/P: マイコン関連 秋月電子 http://akizukidenshi.com/catalog/g/gI-03568/ ** イーサネットの方が身近な人のために例えると、ネットワーク機器にMACアドレスが ついているようなもの。もちろんMACはI2Cより後に生まれた。
  21. 21. I2C SDA(データ)とSCL(クロック信号)の2本と、 図に書かれていないGNDを接続する。 ここまでのおさらい UART GND, TX, RX USART GND, TX, RX, CLK SPI GND, MOSI, MISO, SCLK, SS I2C GND, SDA, SCL 21 https://ja.wikipedia.org/wiki/I2C
  22. 22. 余談(USB) UART~I2Cと色々なシリアル通信の方法があり、 SPIとI2Cはバスを採用していることを解説した。 この延長線にあるのがUSB(Universal Serial Bus) USBはGNDと、信号線D+/-と*、電力供給のVBUS の4本からなる。クロックはD+/-の差分を使って 伝える。(信号線が2本なところは同じ) 22 * Dが2本ある理由: ケーブルが電波を受けた時に2本に同じようにノイズが乗るので、差 分を取ることでノイズ除去できる。あとクロック。 https://en.wikipedia.org/wiki/USB
  23. 23. I2Cのプロトコル 雑な説明 1. マスター: アドレス(7bit)、Read/Write(1/0)、 を送る(1ビットずつ、SDAに出力して、クロッ クを出力して、を繰り返す) 2. マスター: クロック信号を発行する スレーブ: クロック信号に合わせてSDAに出力 する マスター: それを読む ACKとかに関しては後で詳しく書くので省略 23 Q: スレーブからデータを読むときもマスターがクロックを発行する? A: Yes、付録参照
  24. 24. 合宿で作ったもの 合宿で作ったこ れの解説をする 24
  25. 25. 合宿で作ったもの I2Cバスに温度センサと液晶の2つをぶら下げ、 温度センサから0.5秒ごとに値を読んで、 それを液晶に表示する。 実は合宿中に満足して分解しちゃったので解説を 書きながら改めて作っている。合宿時の回路は部 品の下に配線があって解説に不都合だし。 25
  26. 26. 周辺機器 上: 温度センサ 下: 液晶 SCL、SDA、GNDの並びは 同じなので向かい合わせ に配置することにした。 液晶にはRESETがあるがこ れはプルアップする 26
  27. 27. できた回路 再掲: SCL、SDA、GNDの並びは同じなので向か い合わせに配置することにした。液晶のRESETは プルアップする 27
  28. 28. Raspberry Piにつなぐ Raspberry Pi 3のピン番号1, 3, 5, 9がそれぞれ 3.3V、SDA1、SCL1、GNDなのでそこへつなぐ 28 奥に3本あるのは本題と関係ない。6, 8, 10がGND, TX, RXで、PCからUSB-UARTを使って シリアルコンソールに接続して作業している。
  29. 29. i2cdetect つながっている周辺機器のアドレスがわかる (液晶が3e、温度センサが48) 29 $ i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- 3e -- 40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
  30. 30. ソースコード 30 https://gist.github.com/nishio/6892f3de5d8b54153212c51f5e21f772 import smbus from time import sleep bus = smbus.SMBus(1) addr = 0x3e # initialization data = [0x38, 0x39, 0x14, 0x70, 0x56, 0x6c, 0x38, 0x0c, 0x01] wait = [1, 1, 1, 1, 1, 400, 1, 1, 2] # ms for d, w in zip(data, wait): print 'write', hex(d), 'wait', w, 'ms' bus.write_byte_data(addr, 0b00000000, d) sleep(w / 1000.0) def cls(): bus.write_byte_data(addr, 0b00000000, 0b00000001) char_table = {} for i, c in enumerate('0123456789'): char_table[c]= 0b00110000 + i char_table['.'] = 0b00101110 def write(s): for c in s: bus.write_byte_data(addr, 0b01000000, char_table[c]) def write_deg_mark(): bus.write_byte_data(addr, 0b01000000, 0b11011111) bus.write_byte_data(addr, 0b01000000, 0b01000011) def get_temp(): addr = 0x48 v0, v1 = bus.read_i2c_block_data(addr, 1, 2) temp = ((v0 << 8) + v1 >> 3) / 16.0 return "%2.1f" % temp if __name__ == '__main__': while True: cls() write(get_temp()) write_deg_mark() sleep(0.5)
  31. 31. SMBus Pythonから制御するにはsmbusライブラリを使う SMBus(System Management Bus)はI2Cから派生 したプロトコルで、このライブラリでもI2Cを読 み書きできる。 31 I2C and SMBus Subsystem https://www.kernel.org/doc/htmldocs/device-drivers/i2c.html
  32. 32. 温度センサ ADT7410のデータシートを読む 32 http://www.analog.com/media/en/technical-documentation/data-sheets/ADT7410.pdf
  33. 33. 温度計算式 33
  34. 34. 難しかったポイント read_i2c_block_dataで温度によって変化する 2バイトのデータがすんなり得られたが、 温度の計算方法の理解に手間取った。 レジスタの0と1が取れている。 レジスタ0の[14:8](最上位ビット以外)と レジスタ1の[7:3](下位3ビット以外)をつなげた 13bitの値が温度計算式に入れるべき値。 34
  35. 35. 液晶 「難しかったポイント」につまずく前に 講師の上田さんに教えてもらった。 • WRITEしか受け付けないのでR/Wは常に0 • Instruction WriteとData Writeの2つのコマンド がある • まず9回のIWを適切な待ち時間を挟みつつ発行 して初期化する必要がある • その後文字コード表を見ながら適切なコード をDWすれば文字が出る。 35
  36. 36. 初期化フロー 先頭の00の 最初の0が Instructionである フラグ 次の0がWriteであ るフラグ 1か所だけ200ms しっかり待つ必要 がある 36 http://akizukidenshi.com/download/ds/xiamen/AQM0802.pdf
  37. 37. 文字コード 文字コードは ASCIIとかではない のでPython文字列 から文字コード列 を作る対応付けは 自分で書く必要が ある 37
  38. 38. I2Cを傍受してみる I2Cで実際に流れている信号を観察したくなった オシロスコープやロジックアナライザが手元にあ るならそれを使うのがよいが、ない そこでI2CバスにGPIOをつないで読み、可視化す るプログラムを書いた 38
  39. 39. ボーレートを下げる $ sudo modprobe -r i2c_bcm2708 $ sudo modprobe i2c-bcm2708 baudrate=100 $ dmesg # 確認 [ 8.506891] bcm2708_i2c 3f804000.i2c: BSC1 Controller at 0x3f804000 (irq 79) (baudrate 100000) [ 436.079216] bcm2708_i2c 3f804000.i2c: BSC1 Controller at 0x3f804000 (irq 79) (baudrate 3814) 3814Baudまでしか下がらないみたい。 39
  40. 40. 可視化 変化があった時だけ表示するプログラムを書いた 1行目がSCL、2行目がSDA(逆にした方が良かった) 「00001100 11001000」が返っているはず。 SCL の立ち上がりでSDAを読んでみる(次ページ) 40 H__HH_H_HH_H_H_H_H_H_H_H_H_H_H_H_H_HH_H_H_HHH__HH_H_H_H_H_H_H_H_H_H_H_H_H_H_HH_H __HH_____HHH________________________HHH____H__HH_____HH______HH__________HHHH___ _H_H_H_H_H_H_H_H_H_H_HH __HHHH____HH______HH__H
  41. 41. 2回やって比較してみる 41 take 1 01001000 H__HH_H_HH_H_H_H_H __HH_____HHH______ 00000000 10 _H_H_H_H_H_H_H_H_HH _H_H __________________H HH__ 01001000 10 _HHH__HH_H_H_H_H_H_H _H_H __H__HH_____HH______ HH__ 00001100 _H_H_H_H_H_HH_H_H ________HHHH_____ 11001000 10 _H_H_H_H_H_H_H_H _H_HH HHHH____HH______ HH__H take 2 1001000 __H_H_H_H_H_H_H _HH____HH______ 00000000 01 _H_H_H_H_H_H_H_H _H_H ________________ __HH 0 01001000 10 _H _HHH__H_H_H_H_H_H_HH _H_H __ __H__HH____HH______H HH__ 00001101 _H_H_H_HH_H_HH_H_HH ________HHHHH___HH_ 00010000 10 _H_H_H_HH_H_H_H_H_H_HH ______HH_________HH__H
  42. 42. アドレス48=1001000 42 take 1 01001000 H__HH_H_HH_H_H_H_H __HH_____HHH______ 00000000 10 _H_H_H_H_H_H_H_H_HH _H_H __________________H HH__ 01001000 10 _HHH__HH_H_H_H_H_H_H _H_H __H__HH_____HH______ HH__ 00001100 _H_H_H_H_H_HH_H_H ________HHHH_____ 11001000 10 _H_H_H_H_H_H_H_H _H_HH HHHH____HH______ HH__H take 2 1001000 __H_H_H_H_H_H_H _HH____HH______ 00000000 01 _H_H_H_H_H_H_H_H _H_H ________________ __HH 0 01001000 10 _H _HHH__H_H_H_H_H_H_HH _H_H __ __H__HH____HH______H HH__ 00001101 _H_H_H_HH_H_HH_H_HH ________HHHHH___HH_ 00010000 10 _H_H_H_HH_H_H_H_H_H_HH ______HH_________HH__H 意外なことに2か所あるし やり取りの長さが違って 「2バイト読むから2回」 ってわけでもなさそうだ。
  43. 43. 返り値 43 take 1 01001000 H__HH_H_HH_H_H_H_H __HH_____HHH______ 00000000 10 _H_H_H_H_H_H_H_H_HH _H_H __________________H HH__ 01001000 10 _HHH__HH_H_H_H_H_H_H _H_H __H__HH_____HH______ HH__ 00001100 _H_H_H_H_H_HH_H_H ________HHHH_____ 11001000 10 _H_H_H_H_H_H_H_H _H_HH HHHH____HH______ HH__H take 2 1001000 __H_H_H_H_H_H_H _HH____HH______ 00000000 01 _H_H_H_H_H_H_H_H _H_H ________________ __HH 0 01001000 10 _H _HHH__H_H_H_H_H_H_HH _H_H __ __H__HH____HH______H HH__ 00001101 _H_H_H_HH_H_HH_H_HH ________HHHHH___HH_ 00010000 10 _H_H_H_HH_H_H_H_H _H_HH ______HH_________ HH__H
  44. 44. データはACKを挟んで繰り返される ことがある 44 http://www.nxp.com/documents/user_manual/UM10204.pdf
  45. 45. ACKとは I2Cの信号線はプルアップされていて、 GNDと短絡することでLOを出力する。 つまり「接続している回路が誰もLOを 出力しなければHI」という挙動。 マスタは1バイト送り終わった後、 何もせずにSCLを読む。クライアントが SCLにLOを出力したら「受け取ったよ」 という意味になる。* 45 * i2cdetectはアドレスを指定した後にACKが返ってくるか どうかでそのアドレスに周辺機器がいるかどうかをdetectしている
  46. 46. SMBusのread word 先に読みたいレジスタのアドレスをWriteし、 そこから2バイトReadする。 46 https://www.kernel.org/doc/Documentation/i2c/smbus-protocol
  47. 47. 比較してみる 47 take 1 01001000 H__HH_H_HH_H_H_H_H __HH_____HHH______ 00000000 10 _H_H_H_H_H_H_H_H_HH _H_H __________________H HH__ 01001000 10 _HHH__HH_H_H_H_H_H_H _H_H __H__HH_____HH______ HH__ 00001100 _H_H_H_H_H_HH_H_H ________HHHH_____ 11001000 10 _H_H_H_H_H_H_H_H _H_HH HHHH____HH______ HH__H take 2 1001000 __H_H_H_H_H_H_H _HH____HH______ 00000000 01 _H_H_H_H_H_H_H_H _H_H ________________ __HH 0 01001000 10 _H _HHH__H_H_H_H_H_H_HH _H_H __ __H__HH____HH______H HH__ 00001101 _H_H_H_HH_H_HH_H_HH ________HHHHH___HH_ 00010000 10 _H_H_H_HH_H_H_H_H_H_HH ______HH_________HH__H S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P
  48. 48. 比較結果 • Write (‘0’)はどこ? • アドレス後のACKは? • コマンド後のが01だったり10だったり …もしかしてコマンド00000000じゃなくて これの頭の2bitがWriteとACKかも? • データの間にACKがあるはずでは? →一部のbitが欠けているのでは 48
  49. 49. 並べて書いてみる 49 take 1 0 1001000 0 0 00000010 0 0 1001000 1 0 00001100 0 11001000 1 0 take 2 0 1001000 0 0 # S Addr Wr [A] 000000010 0 # Comm [A] 0 1001000 1 0 # S Addr Rd [A] 00001101 0 # [DataLow] [A] 00010000 1 0 # [DataHigh] NA P S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P あるはずなのにないものを赤字で書いた →あるはずのACKがないが本当にないのか?
  50. 50. 可視化 時間分解能不足を疑って「変化があった時だけ記 録」をやめてみた クロック信号の幅の6~8倍の時間分解能で 記録ができている(Pythonでも) 50 HHH____________HHHHHHH______HHHHHH_______HHHHHH______HHHHHH_______HHHHHH_______H _________HHHHHHHHHHHH__________________________HHHHHHHHHHHH_____________________ __HHHHHH______HHHHHHH______HHHHHHH______HHHHHHH______HHHHHHH______HHHHHHH______H _________________________________________________________________________HHHHHHH ________HHHHHH______HHHHHHH______HHHHHH_______HHHHHH______HHHHHH_______HHHHHH___ _HHHHHHHHHHHHH_________________________HHHHHHHHHHHHH____________________________ __HHHHHH______HHHHHH_______HHHHHH_______HHHHHH______HHHHHHH______HHHHHHH______HH _________________________________HHHHHHHHHHHHHHHHHHHHHHHHHH____________HHHHHHHHH HHHHHH______HHHHHHH______HHHHHH_______HHHHHH_______HHHHHH_______HHHHHH_______HHH HHHHHHHHHHHHHHHHHH____________________________________________________HHHHHHHHHH
  51. 51. 可視化 ただし行末と次の行とのつながりがおかしい 80文字のバッファがいっぱいになった時の処理 が重くて信号を取りこぼしている(仮説) 51 HHH____________HHHHHHH______HHHHHH_______HHHHHH______HHHHHH_______HHHHHH_______H _________HHHHHHHHHHHH__________________________HHHHHHHHHHHH_____________________ __HHHHHH______HHHHHHH______HHHHHHH______HHHHHHH______HHHHHHH______HHHHHHH______H _________________________________________________________________________HHHHHHH ________HHHHHH______HHHHHHH______HHHHHH_______HHHHHH______HHHHHH_______HHHHHH___ _HHHHHHHHHHHHH_________________________HHHHHHHHHHHHH____________________________ __HHHHHH______HHHHHH_______HHHHHH_______HHHHHH______HHHHHHH______HHHHHHH______HH _________________________________HHHHHHHHHHHHHHHHHHHHHHHHHH____________HHHHHHHHH HHHHHH______HHHHHHH______HHHHHH_______HHHHHH_______HHHHHH_______HHHHHH_______HHH HHHHHHHHHHHHHHHHHH____________________________________________________HHHHHHHHHH
  52. 52. 次のアクション I2Cの通信を眺めて楽しむ目的なら 100bit程度が記録できれば十分(今50bit) 1bitあたり今32サンプル程度 ならば数千サンプルのバッファがあれば十分で、 全部ため込んでから後から可視化すればよい。 これを実装する。そしてACKが本当にないのか取 りこぼされてるだけなのか検証する。 52
  53. 53. 53全体像。SCLを2列目にした。 _____________________HHHHHHHHHHHHHHHHHHHHHH_____________________________________ HHHHHHHHHH______________________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHH _______HHHHHHHHHHHHHHHHHHHHHH___________________________________________________ HHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH_______ ________________________________________________________________________________ ____HHHHHHHHHHH___________HHHHHHHHHHH____________HHHHHHHHHHH___________HHHHHHHHH ________________________________________________________________________________ HH___________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___________H _______________________________________________________HHHHHHHHHHHHHHHHHHHHHH___ HHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHHH___ _________________________________________HHHHHHHHHHHHHHHHHHHHHH_________________ ________HHHHHHHHHHH___________HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH______ _____HHHHHHHHHHHHHHHHHHHHHHH____________________________________________HHHHHHHH ________________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHHH________ HHHHHHHHHHHHHH______________________________________________________________HHHH ___HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH_______HHHHHHHHHHH____ HHHHHHHHHHHHHHHHHH______________________________________________________________ _______HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHH ________________________________________________HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH HHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH__________ HHHHHHHHHHH______________________HHHHHHHHHHHHHHHHHHHHHH_________________________ _HHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___ ___________________HHHHHHHHHHHHHHHHHHHHHH_______________________________________ ________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHH ______HHHHHHHHHHHHHHHHHHHHHH____________________________________________________ HHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH_________ _____________HHHHHHHHHHHHHHHHHHHHHH______________________HHHHHHHHHHHHHHHHHHHHHHH __HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
  54. 54. スタートコンディション 信号線はデフォルトHI、SCLより先にSDAがLOに なる。これがアドレスを送る予告になる。 クロックの立ち上がりだけ見てて見落とした。 54 _____________________HHHHHHHHHHHHHHHHHHHHHH_____________________________________ HHHHHHHHHH______________________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHH _______HHHHHHHHHHHHHHHHHHHHHH___________________________________________________ HHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH_______ ________________________________________________________________________________ ____HHHHHHHHHHH___________HHHHHHHHHHH____________HHHHHHHHHHH___________HHHHHHHHH ________________________________________________________________________________ HH___________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___________H _______________________________________________________HHHHHHHHHHHHHHHHHHHHHH___ HHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHHH___ _________________________________________HHHHHHHHHHHHHHHHHHHHHH_________________ ________HHHHHHHHHHH___________HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH______
  55. 55. スタートコンディション 改めて仕様書を読み直すとちゃんと書いてある 55 http://www.nxp.com/documents/user_manual/UM10204.pdf
  56. 56. アドレス=1001000 アドレス送信後 0 0 00000001 0 0 があって クロックが長めにHIになる。 ここまでが最初の命令。 56 _____________________HHHHHHHHHHHHHHHHHHHHHH_____________________________________ HHHHHHHHHH______________________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHH _______HHHHHHHHHHHHHHHHHHHHHH___________________________________________________ HHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH_______ ________________________________________________________________________________ ____HHHHHHHHHHH___________HHHHHHHHHHH____________HHHHHHHHHHH___________HHHHHHHHH ________________________________________________________________________________ HH___________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___________H _______________________________________________________HHHHHHHHHHHHHHHHHHHHHH___ HHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHHH___ _________________________________________HHHHHHHHHHHHHHHHHHHHHH_________________ ________HHHHHHHHHHH___________HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH______
  57. 57. 改めて比較→仕様書通り! S 1001000 0 0 # S Addr Wr [A] 00000001 0 P # Comm [A] S 1001000 1 0 # S Addr Rd [A] 00001101 0 # [DataLow] A 01001000 1 P # [DataHigh] NA P Pのところは「クロックの立ち上がりでSDAを読 む」と0になるが、クロックがLOになる前にSDA がHIになるので0ではなくP(Stop condition) を表現しているのだとわかる。 1つ目のPは直後にSが来ることで、合わせて Repeated Start Conditionだとわかる。 57
  58. 58. クロックとは何なのか 「クロック信号」という言葉から時計のように定 期的に送られるものと誤解していた。 また、クロックの立ち上がりのタイミングでSDA を読めばそれでよいのかと勘違いしていた。 実際には「SCLがHIである間にSDAがLOになった らスタートコンディション」などのようにSDAと 組み合わせて多様な意味が表現されている。 SCLはクライアントがACKを伝えるのにも利用さ れている。 58
  59. 59. I2Cまとめ 無事仕様書の記述と実際に観察された波形とが一 致した。 ボーレートを落とせばPythonでGPIOを叩いても 十分な時間解像度で波形を観察できる。記録時に は余計な処理をせずに記録に専念するとよい。 SCLは信号線を読む周期やタイミングを伝えるだ けではなく、色々な目的に利用されている。 59 I2C傍受: https://gist.github.com/anonymous/96552b6bb37f0783db217143b200912d
  60. 60. 付録:その他合宿でやったこと 60
  61. 61. ESP-WROOM-02 61 Wifiにつながるマイコン(まさにIoT!) 電力をかなり食うのでUSBの5Vバスパワーから LM3671*で3.3Vを作って使った UARTを使ってATコマンドを送って操作。Wifiに 接続したりHTTP GETしたりできた 最終的にアクセスポイントモードに変更してPC から接続し、ブラウザからHTTPリクエストを投 げて、それをシリアルコンソールで眺めた * https://www.switch-science.com/catalog/2638/
  62. 62. 付録: マルチマスター構成 SPIは、1つのマスターと複数のスレーブ。 I2Cは複数のマスターが可能な仕様。 I2Cの信号線はデフォルトHIで「GNDと導通させ るかどうか」でLOとHIを表現する。なので複数 のマスターが同時にLOとHIを出力した場合、信 号線はLOになる。マスターは自分がHIを書いた のに信号線がLOになっている場合、衝突があっ たと判断し、停止する。 62 複数のマスターがつながっているものの例としてLANを考えると、 「誰が送信できるか管理して衝突しないようにする仕組み」としてトークンリングとか、 「衝突してからそれを検知してランダム時間待ってリトライ」のCSMA/CDとかが生まれ 最終的に信号線を直接つなぐのをやめてスイッチングハブがフレームの情報をみて 適切なポートへ中継するようになった。
  63. 63. 付録 Q: スレーブからデータを読むときもマスターが クロックを発行する? A: Yes Q: 自分が発行してないクロックに合わせてデー タを書くとか無茶じゃない? A: スレーブはクロックがLOになったのを見てか らデータを書き、マスターはクロックがHIになる タイミングで読めばよい。 63 HHHHHHHHHHH______________________HHHHHHHHHHHHHHHHHHHHHH_________________________ _HHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___ ___________________HHHHHHHHHHHHHHHHHHHHHH_______________________________________ ________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHH ______HHHHHHHHHHHHHHHHHHHHHH____________________________________________________ HHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHH_________ _____________HHHHHHHHHHHHHHHHHHHHHH______________________HHHHHHHHHHHHHHHHHHHHHHH __HHHHHHHHHHH___________HHHHHHHHHHH___________HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH 3番目の例はクロックから1サンプル遅れているので因果関係がわかりやすい

×