シャープ測距モジュールのI2CスレーブIDの変更プログラム
この測距モジュールは、I2Cインターフェイス(アナログ入力もある)を通してデータを取得できる取り扱いやすいセンサーです。ただ、複数のモジュールを使う場合には、それぞれのモジュールのI2Cのスレーブ アドレスを変更する必要があり(デフォールト アドレスは0x40)、アドレスの変更は、不揮発性メモリに新しいスレーブ アドレスを書き込む必要があります。アプリケーションノートでは、不揮発性メモリに書き込むことを、『E-Fuseにデータを書き込む』と表現しています。書き込み後に電源を再投入すると、新しいスレーブ アドレスで動作するようになっています。注意する必要があるのは、不揮発性メモリへの書き込みは一度しかできないことです。この手順は、アプリケーションノートに詳しく記述されていますが、実際に、4つのモジュールのスレーブ アドレスを変更した例を記録として残しておきます。
<GP2Y0E03の主な仕様>
・出力:I2Cおよびアナログ出力
・電源電圧(VDD):2.7~5.5V
・測距範囲:4~50cm
1.測距モジュール(GP2Y0E03)のRaspberry piへの接続
モジュールの電源やI2C端子をRaspberry piへ接続する以外に、モジュールの裏面にあるVpp端子を接続する必要があります。裏面のVpp端子はターミナルに接続されていないので、ケーブルを直接ハンダ付けしました。
今回の例では、Vpp端子をRaspiのGPIO22に、⑤GPIO1端子をRaspiのGPIO4に接続しています。
2.変更するスレーブ アドレスをE-Fuseに書き込むプログラム
書き込み手順は、シャープ センサー モジュール(GP2Y0E03)のアプリケーションノートに記述されているが、それを実際に実行した手順と、実際に使ったプログラム例を以下に示します。
●プログラム実行前に
①変更するスレーブ アドレス(7bit表記)の上位4ビットを、SET_DATA変数にセット。
例えば、アドレスを0x60にする場合には、SET_DATA=0x0Aとする。
●プログラム実行後の処理手順
<初期化>
①GPIO4→LOW→HIGH(GPIO1端子)・・・I2Cをアクティブに
②GPIO22→LOW(Vpp端子)・・・Vppは0V
<Stage 1>クロックの選択
①アドレス0xECに0xFF(manual)をセット
0xFF=manual clock, 0x7F=auto clock
②GPIO22を「HIGH」に・・・Vpp端子に3.3Vを印加
<Stage 2>E-Fuseターゲットアドレスのセット
①アドレス0xC8に0x00をセット
[7]=0(Enable), [6]=0(Read Out), [5:0]=0x00(E[0]:E-Fuse bit Map(LSB))
[5:0]=address in target bank
ex. A[0]=0x00,B[10]=0x0A, C[63]=0x3F ,E[0]=0x00
[6]=Read Out, 1=load E-F data to Register(bank3)
[7]=Enable Bit, 0=Enable, 1=Disable
<Stage 3>E-Fuse Bit No/ Bank のアサイン
①アドレス0xC0にE-Fuseに0x45を書き込む
書き込む値は0xmn。ここで、mはアサイン ビット値、nはアサイン バンク値
ビット値(上位4ビット)= ビット数 - 1
バンク値(下位4ビット)= 1(BankA), 2(BankB), 3(BankC), 4(BankD), 5(BankE)
ここでは、ビット値=0x4、バンク値=0x5なので、書込み値は0x45
<Stage 4>E-Fuse に書き込むデータのセット
①アドレス0xCDにSET_DATAをセット
Slave ID(7bit表記)の上位4ビットが設定する値。SET_DATAにセットしている。
<Stage 5>E-Fuse Programの Enable化
①アドレス0xCAに0x01(Enable)をセット
0x00=Disable, 0x01=Enable
②書き込み時間500μsec待つ
<Stage 6>E-Fuse Programの Disable化
①アドレス0xCAに0x00(Disable)をセット
0x00=Disable, 0x01=Enable
②GPIO22を「LOW」に・・・Vpp端子を0Vに
<Stage 7.1> バンクの選択
①アドレス0xEFに0x00(Bank0)をセット
0x00=Bank0, 0x03=Bank3(E-Fuse)
<Stage 7.2> E-Fuse bank3のregisterにload
①アドレス0xC8に0x40をセット
[7]=0(Enable), [6]=1(load E-F data to Register), [5:0]=0x00(E[0]:E-Fuse bit Map(LSB))
[5:0]=address in target bank
ex. A[0]=0x00,B[10]=0x0A, C[63]=0x3F ,E[0]=0x00
[6]=Read Out, 1=load E-F data to Register(bank3)
[7]=Enable Bit, 0=Enable, 1=Disable
<Stage 7.3> E-Fuseを読取に
①アドレス0xC8に0x00をセット
[7]=0(Enable), [6]=0(Read Out), [5:0]=0x00(E[0]:E-Fuse bit Map(LSB))
[5:0]=address in target bank
ex. A[0]=0x00,B[10]=0x0A, C[63]=0x3F ,E[0]=0x00
[6]=Read Out, 1=load E-F data to Register(bank3)
[7]=Enable Bit, 0=Enable, 1=Disable
<Stage 8> ソフトウェア リセット
①アドレス0xEEに0x06をセット
0x06=software reset
<Stage 9>書き込んだデータのチェック
<Stage 9.1> クロック選択
①アドレス0xECに0xFFをセット
0xFF=manual clock, 0x7F=auto clock
<Stage 9.2> バンク選択
①アドレス0xEFに0x03(Bank3)をセット
0x00=Bank0, 0x03=Bank3(E-Fuse)
<Stage 9.3> 設定したスレーブ アドレスの確認
①アドレス0x27(Bank3)から、1byte読取り(=readOutData)
0x27 : [7]=0b1, [6:5]=Median Filter(0b11), [4]=enable bit, [3:0]=I2C Slave ID(上位4bit)
②設定したスレーブ アドレスは、(readOutData << 3) & 0x7F
これが正しければ設定完了
<Stage 9.4> バンク選択でBank0に戻す
①アドレス0xEFに0x00(Bank0)をセット
0x00=Bank0, 0x03=Bank3(E-Fuse)
<Stage 9.5> クロック選択でauto clockに戻す
①アドレス0xECに0x7F(auto)をセット
0xFF=manual clock, 0x7F=auto clock
●失敗した場合
一度、変更プログラムを実行した場合、スレーブ アドレスの再変更はできない。バンクEのE[4]=0となっている場合には、変更したアドレスが有効になっている。アプリケーションノートには、修正の救済方法として、1ビットだけ、’1’を’0’に置き換える手順が示されているが、スレーブ アドレスの変更が可能かは検証していない。
◆アドレス変更プログラム例◆
#-*-coding:utf-8-*- # ======================================================= # I2C測距センサー(GP2Y0E03)のSlave IDを変更するプログラム # ======================================================= import RPi.GPIO as GPIO from time import sleep import smbus #--------------------------------------------------------- # 変更後の Slave ID # Slave IDを0x60(7bit表記)に変更する例 # 0x60(7bit表記) -> 上位4bitが書き込む値:0x0A SET_DATA = 0x0A # Slave IDの上位4bitをセット #--------------------------------------------------------- # GP2Y測距センサー I2C Slave Addr(初期値) GP2Y0= 0x40 #7bit 表記 I2C_ACT = 4 #GPIO1を接続 GP2Y_VPP = 22 #Vpp=3.3V # I2C I/O setup I2C = smbus.SMBus(1) GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) # GPIO BCM No GPIO.setup(I2C_ACT, GPIO.OUT) GPIO.setup(GP2Y_VPP, GPIO.OUT) # I2CをActive Modeに GPIO.output(I2C_ACT, GPIO.LOW) #I2C Stand-by GPIO.output(GP2Y_VPP, GPIO.LOW) #Vpp=0V sleep(0.01) GPIO.output(I2C_ACT, GPIO.HIGH) #I2C Active sleep(0.01) #<Stage 1> Clock Select(0xEC:R/W) I2C.write_byte_data(GP2Y0, 0xEC, 0xFF) sleep(0.01) GPIO.output(GP2Y_VPP, GPIO.HIGH) #Vpp=3.3V #<Stage 2> E-Fuse(0xC8:R/W) I2C.write_byte_data(GP2Y0, 0xC8, 0x00) sleep(0.01) #<Stage 3> E-Fuse Bit No/ Bank Assign(0xC9:R/W) I2C.write_byte_data(GP2Y0, 0xC9, 0x45) sleep(0.01) #<Stage 4> E-Fuse Program Data(0xCD:R/W) I2C.write_byte_data(GP2Y0, 0xCD, SET_DATA) sleep(0.01) #<Stage 5> E-Fuse Program Enable Bit(0xCA:R/W) # 0x00=Disable, 0x01=Enable I2C.write_byte_data(GP2Y0, 0xCA, 0x01) sleep(0.01) # Wait for 500us. #<Stage 6> E-Fuse Program Enable Bit(0xCA:R/W) I2C.write_byte_data(GP2Y0, 0xCA, 0x00) sleep(0.01) GPIO.output(GP2Y_VPP, GPIO.LOW) #Vpp=0V #<Stage 7.1> Bank Select(0xEF:R/W) I2C.write_byte_data(GP2Y0, 0xEF, 0x00) sleep(0.01) #<Stage 7.2> E-Fuse(0xC8:R/W) bank3のregisterにload I2C.write_byte_data(GP2Y0, 0xC8, 0x40) # 0100 0000 sleep(0.01) #<Stage 7.3> E-Fuse(0xC8:R/W) I2C.write_byte_data(GP2Y0, 0xC8, 0x00) sleep(0.01) #<Stage 8> Software Reset(0xEE:W) 0x06=software reset I2C.write_byte_data(GP2Y0, 0xEE, 0x06) sleep(0.01) #<Stage 9.1> Clock Select(0xEC:R/W) I2C.write_byte_data(GP2Y0, 0xEC, 0xFF) sleep(0.01) #<Stage 9.2> Bank Select(0xEF:R/W) I2C.write_byte_data(GP2Y0, 0xEF, 0x03) sleep(0.01) #<Stage 9.3> 設置したSlave IDの確認 readOutData = I2C.read_byte_data(GP2Y0, 0x27) sleep(0.01) #<Stage 9.4> Bank Select(0xEF:R/W) I2C.write_byte_data(GP2Y0, 0xEF, 0x00) sleep(0.01) #<Stage 9.5> Clock Select(0xEC:R/W) I2C.write_byte_data(GP2Y0, 0xEC, 0x7F) sleep(0.01) # 設定したSlave IDの確認 print("設定したSlave ID(7bit表記) = ", (readOutData << 3) & 0x7F) # 設定Slave ID=0x60の場合、Register 0x27の値[7:0]は、0b11101100 # Slave ID 上位4bit[3:0] = '1100' -> 7bit表記では0x60となれば変更は成功 GPIO.cleanup()