シャープ測距モジュールのI2CスレーブIDの変更プログラム

測距モジュール
シャープ測距モジュール(GP2Y0E03)

この測距モジュールは、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に接続しています。

モジュール裏面
モジュールの裏面:Vpp端子へケーブルをハンダ付け

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()