デモ用の地震計を作りたい
製作編は下記を参照
ゲインアンプ付きA/Dコンバータ(SX8725C)を用いた簡易地震計の製作 1(製作編)
スパイクノイズ問題
製作編では良く分からずPGA3をガンガン持ち上げていたところ、スパイクノイズに悩まされた (縦軸:[mV], 横軸:10 [msec])。地震計未接続の状態でも乗ってくる。
RaspberrryPi Pico の電源ノイズについて色々調べて試したのは2つ。
- RT6150BをスリープにしてLDOでPicoに3.3Vを給電してみた。
- SX8725CとPicoの物理的距離を変えた
今回は5Vを使っているためか、3.3Vの低ノイズ化のノウハウは効果が無かった。また距離も関係なさそうだったので、Pico側から侵入してくるとしたら電源ラインかGNDから直接っぽい。
次に、SX8725Cの内部でなんとかできないか考えた。SX8725Cのデータシートを見るとPGA2とPGA3は基準電圧の影響を受けそうだが、前段のPGA1は独立していそうだ。
色々試したところ、PGA2もしくはPGA3で倍率を上げると問題のスパイクが乗ることが分かった。一方でPGA1のみだと現れない事が分かり、PGA2以降の段は1倍で使う事にした(Disableにはしていない)。地震計未接続の状態。
地震計を接続した状態。1Hzの発振っぽいノイズはPC関連機器から遠ざけると弱まった。
最終的に決定したレジスタの設定は 16bit, 差動入力, ゲインアンプ使用(Pga:x10, Pga2:x1, Pga3:12/12), 5[V]給電, 内部基準電圧(1.22[V])リファレンスとした。
ValACCfg0 = b'\x1E' #30 #0b00011110
ValACCfg1 = b'\xFF' #255 #0b11111111
ValACCfg2 = b'\x00' #0 #0b00000000 #PGA2x1
ValACCfg3 = b'\x8C' #140 #0b10001100 #PGA1x10 PGA3 12/12
ValACCfg4 = b'\x00' #0 #0b00000000 #PGA3OFF 0
ValACCfg5 = b'\x03' #3 #0b00000011 #diff, Vref
ValMode = b'\x88' #132 #0b10000100 #pump off
後る課題
AD関係で残っているのは、オフセット電圧をPythonで微修正して誤魔化している点。レジスタのバイアスやオフセットの値を変えるも、微調整が難しく思い通りにできていない。
これでやっとスタートラインに立ったところで、後は地震計そのものの調整に入ることになる。一定時間測定して、ダンピング係数を確認したり、、、しかしちゃんとした地震観測に使う機材が手元に無いので、振幅等のキャリブレーションはしばらく難しい。
MicroPythonコード
import utime
import machine
led = machine.Pin(25, machine.Pin.OUT)
RT6150_PS = machine.Pin(23, machine.Pin.OUT)
timer = machine.Timer()
led.value(1)
utime.sleep(0.5)
led.value(0)
utime.sleep(0.5)
i2c_bus_number = 0
i2c_sda=machine.Pin(0)
i2c_scl=machine.Pin(1)
i2c=machine.I2C(i2c_bus_number,sda=i2c_sda, scl=i2c_scl, freq=100000)
#if we use only one i2c device, this code is useful to find the address.
addrlist = i2c.scan()
print( "address is :" + str(hex(addrlist[0])) )
addr = addrlist[0]
#addr = 0x48 # Default address of SX8725C
i2c_address = addr
Vref = 1.22 # for internal refernce
#Vref = 5.00 # for Vbatt reference
conversion_factor = Vref / (65535)
zero_shift = -3.7
#zero_shift = 0
# Define registers
RegACOutLsb = 0x50
RegACOutMsb = 0x51
RegACCfg0 = 0x52
RegACCfg1 = 0x53
RegACCfg2 = 0x54
RegACCfg3 = 0x55
RegACCfg4 = 0x56
RegACCfg5 = 0x57
RegMode = 0x70
# Define values
ValACCfg0 = b'\x1E' #30 #0b00011110
ValACCfg1 = b'\xFF' #255 #0b11111111
ValACCfg2 = b'\x00' #0 #0b00000000 #PGA2x1
ValACCfg3 = b'\x8C' #140 #0b10001100 #PGA1x10 PGA3 12/12
ValACCfg4 = b'\x00' #0 #0b00000000 #PGA3OFF 0
#ValACCfg5 = b'\x02' #2 #0b00000010 #diff, VBATT
ValACCfg5 = b'\x03' #3 #0b00000011 #diff, Vref
ValMode = b'\x88' #132 #0b10000100 #pump off
reglist = []
reglist = list(range(0x50, 0x50+8))
reglist.append(0x70)
# --- Check default values (not required) ---
data=[]
for reg in reglist:
readdata = i2c.readfrom_mem(addr,reg,1)
data.append(int.from_bytes(readdata,'big'))
print(data)
#--------------------------------------------
#init
i2c.writeto_mem(addr,RegACCfg0,ValACCfg0)
i2c.writeto_mem(addr,RegACCfg1,ValACCfg1)
i2c.writeto_mem(addr,RegACCfg2,ValACCfg2)
i2c.writeto_mem(addr,RegACCfg3,ValACCfg3)
i2c.writeto_mem(addr,RegACCfg4,ValACCfg4)
i2c.writeto_mem(addr,RegACCfg5,ValACCfg5)
i2c.writeto_mem(addr,RegMode,ValMode)
# --- Check current values (not required) ---
data=[]
for reg in reglist:
readdata = i2c.readfrom_mem(addr,reg,1)
data.append(int.from_bytes(readdata,'big'))
print(data)
#--------------------------------------------
def sign16(x):
return ( -(x & 32768) | (x & 32767) );
#main
def readdata(timer):
data = []
for reg in (RegACOutLsb, RegACOutMsb):
readdata = i2c.readfrom_mem(addr,reg,1)
data.append(int.from_bytes(readdata,'big'))
data16 = (data[1]<<8 | data[0])
dataDiff = sign16(int(hex(data16),16))
mVol = 1000 * dataDiff * conversion_factor
var = "{:0=+12.4f}".format(mVol + zero_shift)
print (var)
led.value(1)
RT6150_PS.value(1)
timer.init(freq=100, mode=machine.Timer.PERIODIC, callback=readdata)