FpgaI2c
概要 †
- Nexys 4 付属のI2C温度計の SDA, SCL 信号線を直接スイッチで ON/OFFしながら、温度計を操作してみます。チャタリング防止や LED 表示などのため、ちょっと verilog で回路を作ります。
- 参考: Nesys4 のマニュアル
- このマニュアルを確認しながら設定を行うと良いと思います。
- Nexys 4 付属の温度計, Analog Devices の ADT7420
- 詳しい情報は以下の pdf に載っています。
- ADT7420 をNexys 4 で使うとき、
- Vivadoのxdcファイルの場合は、sclの PACKAGE_PIN は "F16", sdaの PACKAGE_PINは "G16" を指定します。 (Nexys4のマニュアルのpage 22, 12 Temperature Sensor で確認してください)
##Temperature Sensor
##Bank = 15, Pin name = IO_L14N_T2_SRCC_15, Sch name = TMP_SCL
set_property PACKAGE_PIN F16 [get_ports scl]
set_property IOSTANDARD LVCMOS33 [get_ports scl]
##Bank = 15, Pin name = IO_L13N_T2_MRCC_15, Sch name = TMP_SDA
set_property PACKAGE_PIN G16 [get_ports sda]
set_property IOSTANDARD LVCMOS33 [get_ports sda]
- ISEのUCFの場合は、sclの LOCは "F16", sdaの LOCは "G16" を指定します。 (Nexys4のマニュアルのpage 22, 12 Temperature Sensor で確認してください)
NET "scl" LOC = "F16" | IOSTANDARD = "LVCMOS33"; #Bank = 15, Pin name = IO_L14N_T2_SRCC_15, Sch name = TMP_SCL
NET "sda" LOC = "G16" | IOSTANDARD = "LVCMOS33"; #Bank = 15, Pin name = IO_L13N_T2_MRCC_15, Sch name = TMP_SDA
- ADT7420 の(slave)device addressは、0x4b (=1001011) です。
- 温度データを取り出すには、以下の手順を実行します。
- Master がStart 信号を送信。... scl=1, sda=1の状態から、scl=1, sda=0 の状態にして、その後、scl=0, sda=0 とする。
- これ以降、通信を終了するまで、Master またはdeviceが sda に high(=Z=1)または low(=0)を設定し、その状態で、Master が sclを 0->1->0 に変化することを繰り返す。
- Master がdevice(ADT7420)のアドレス(0x4b)と、Masterからデータが送信されることを表す 0 (レジスタ番号書き込み)を送信。
- device が ack 信号(成功していれば、0)を出力。 Master側ではこのとき、 sda 端子をZ状態(=1)として、入力を待つ。
- Master がレジスタを表す 8bitのデータ(0000 0000)を出力。
- device が ack 信号 0 を出力
- Master がrestart 信号を送信(start と同じ)
- Master が device address (0x4b)と、入力を表す 1を出力。
- device が ack 信号 0 を出力
- device が 最初の 8 bit を出力... この時のbit 列を Master 側で入力。
- Master が ack 0 を出力。
- device が次の8 bit を出力 ... この時の bit 列を Master 側で入力。
- Master が nack 1 を出力。
- 通信終了手順を行う。 ... sclを 1 にして、その間に sdaを 0から 1 にする。
回路の概要 †
- sw[7:0]と up button, left button, center button, right button をチャタリング防止回路に通し、その出力をswx[7:0], BUx, BLx, BCx, BRx とします。
- sw[0]をチャタリング防止回路を通して(swx[o]), sda に接続します。
- center button をチャタリング防止回路を通して(BCx), sclに接続します。
- down button をリセット信号とします。
- sda を led[8] に接続します。scl が 0->1 に変化するたびに、これをシフトして、過去8回のsda の High/Low の遷移を led[15:8] に表示します。 これを実現するために、レジスタ data[7:0] を使っています。
- 1つのポートで入出力を行う為、scl, sda は verilog の inout 型を使います。
- data[7:0]の値を16進法4桁でLEDマトリックスの左側4個に出力する回路に接続します。
- sw[7:0]をled[7:0]に接続します。
- sw[7:0]を16進法4桁でLEDマトリックスの右側4個に出力する回路に接続します。
- 回路図
Verilog と xdc または ucf †
verilog のコンパイルと bit ファイルの作成 †
- Run systhesis をクリック
- Run Implementation ... ポップアップウィンドウで指定, 左側のメニュー一覧から選んでもよい.
- bitファイルの生成,Generate bit stream
Nexys4とパソコンの接続, bit ファイルのダウンロード †
- bitファイル生成後, ポップアップウィンドウが開きます. Open Hardware Manager を選びます。ここでは OKはクリックしません.
- パソコンとNexys4を接続します.
- ポップアップウィンドウのOKをクリックします.
- Hardware Managerの Open Tagert が click 可能になります。
- Open Taget を click し, auto connect をクリックします。
- Program Device をクリックします。
- プログラム可能なデバイス名(xc7a100t)が表示されます。これをクリックします。
- プログラム(download)するbitファイルの候補が表示されるので、確認して、programボタンをクリックします。
- ダウンロードが終了すると、ボードの7セグメントLEDに"0000 0000"が表示される(スライドスイッチがすべてOffの場合)。
-
(スライドスイッチ 0 がONになっているので、左端が1になっています。)
実行 †
- 手順詳細
- bitファイルのダウンロード終了時点で、自動的に回路に電源が供給されて、回路が動き始めます。
- sw[0](sda) を1にします。center button (scl)は、押していない時に0, 押したときに 1 になります。
- sclを1 にして、sda を 1->0にします。(center button を1にして、その状態のまま, sw[0]を1から0にする)
- sclを0にします。(center buttonを離す)
- sdaを1にして、sclを 0->1->0にします。(sw[0]を1にして、center button を押して離す)... これで device の7bit のアドレスのMSBの1bit がデバイス側に送られます。
- sdaを0にして、sclを 0->1->0にします。
- sdaを0のまま、sclを 0->1->0にします。
- sdaを1にして、sclを 0->1->0にします。
- sdaを0にして、sclを 0->1->0にします。
- sdaを1にして、sclを 0->1->0にします。
- sdaを1のまま、sclを 0->1->0にします。ここまでが、ADT7420のアドレス, 0x4bの出力です。
- sdaを0にして、sclを 0->1->0にします。write (=0)の出力です。
- sdaを1(Z)にして、sclを0->1->0にします。ADT7420から ack(=0)が出力され、led[8]に表示されるはずです。
- sdaを0にして、sclを8回、0->1->0にします。 ... register 0の指定です。
- sdaを1(Z)にして、sclを0->1->0にし、ADT7420から ackを入力します。
- sdaを1のまま、sclを1にします。
- sclを1のまま、sdaを0にして、restart します。そのあと、sclを0にします。
- sdaを1にして、sclを 0->1->0にします。
- sdaを0にして、sclを 0->1->0にします。
- sdaを0のまま、sclを 0->1->0にします。
- sdaを1にして、sclを 0->1->0にします。
- sdaを0にして、sclを 0->1->0にします。
- sdaを1にして、sclを 0->1->0にします。
- sdaを1のまま、sclを 0->1->0にします。ADT7420のアドレス, 0x4bの再出力です。
- sdaを1にして、sclを 0->1->0にします。read (=1)の出力です。
- sdaを1のまま、sclを 0->1->0にし、ADT7420からackを入力します。
- sdaを1のまま、sclを8回 0->1->0します。このとき、ADT7420から温度データが送られてきて、それが、led[8]から入力され、右にシフトされます。最初の bit は、符号を表します。符号を含む最初の8bitは、全16bitのMSB側の8bitです。
- sdaを0にして、sclを 0->1->0にして、Master から ADT7420へ ack (0)を送ります。
- sdaを1にして、そのまま、sclを8回 0->1->0します。このとき、ADT7420から温度データの下位8bitが送られてきて、それが、led[8]から入力され、右にシフトされます。入力された全16bitのうち、符号を除く上位8bit、(つまり、最初の1byte(8bit)のうち、2番目以降の7bit と、次に入力された1byte の最初の1bit )が、摂氏で表した温度の整数部分を表します。
- 最後に、sdaを0, sclを1, そのまま sdaを1, にすることによって、通信終了信号がMaster からADT7420へ送られます。これで一通りのサイクルが終了します。
- 実際に操作しているところの動画です。
- 説明
- 最初のスイッチの操作 ... I2C通信開始信号送信
- center button を押して sclを 1にして、押したままにしておく。
- スライドスイッチをOffからONにして, sdaを1にする。
- スライドスイッチをONからOFFにする。
- アドレスの送信の最初の部分
- sclを0にしたあと, sdaを1にして、sclを 0->1->0
- led[8]が点灯(1がsdaに流れたことを示す)。
- 再スタート, アドレス指定, 読み込みbit (1)送信, ack受信(0)受信の後, 最初に読み込んだ8bitのデータが 00010000
- 次の8bit が, 11010000
- この2つの01の列を接続した16bitの値が計測された温度です。最初の1bitは符号で、そのあとの8bit が摂氏で表した温度の小数点より大きいあたい、残りが、小数点より小さい値です。
- 従って、0010 0001 が摂氏の小数点より大きい値となり、摂氏33度であることがわかります(ボードの熱で、ちょっと高い温度になるようです)。小数点以下の部分は、101なので 1/2 + 1/8=0.5+0.125=0.625となり、整数部分に加えると、33.625度、ということになります。
- 実際に赤外線温度計で計測すると、摂氏33.6度となっており、かなり近い値が計測されていることが確認できます。
考察 †
- 手でI2Cデバイスを制御するのは大変。ちょっと間違えたら1からやり直し。
- tinyCPUを作ったのだから、それを使って、プログラムで制御したらいいじゃん。
Counter: 6439,
today: 1,
yesterday: 1
|