Interfacing a MS8607 sensor with Python using the bus pirate

A couple of days ago, I’ve read about Scott Harden’s interesting approach of interfacing a twi temperature sensor by using Python and Hack-a-day’s bus pirate. Quite accidentally, I had an similar problem. For some experiments I need a good knowledge about my environmental sizes (e.g. ambient pressure, temperature and humidity). I decided to use a MS8607 sensor produced by “Measurement Specialities / TE Connectivity” and is distributed for example by AMSYS. I’ve got some modules and started reading the datasheet. Due a permanent lack of time I was searching for a good and simple way for testing the sensor interface without the whole prototype circus (e.g. design and build some interface cards, testing the code by using debug interfaces and so on). Scott’s solution was simple and I had all tools already available, so I started to adapt his code for my needs.

Calculations Link to heading

Difference between actual and reference temperature : $$\Delta T = D_2 - C_5 \cdot 2^8 $$ Offset for temperature compensated pressure : $$OFF = C_2 \cdot 2^{17} + \frac{C_4 \cdot \Delta T} {2^6}$$ Sensivity for actual temperature : $$SENS = C_1 \cdot 2^{16} + \frac{C_3 \cdot \Delta T}{2^7}$$

Temperature (in 0.01 °C resolution) : $$T = 2000 + \Delta T \cdot \frac{C_6}{2^{23}}$$ Pressure (in 0.01 mbar resolution): $$P = \frac{\dfrac{D_1 \cdot SENS}{2^{21}} - OFF}{2^{15}}$$ Relative humidity (in %) : $$RH = -6 + 125 \cdot \frac{S_{RH}}{2^{16}}$$

import serial
import math
import matplotlib.pyplot as plt
import numpy as np
import time

BUSPIRATE_PORT = 'com5' #customize this! Find it in device manager.

def sendPirate(ser,cmd,silent=True):
    """
    send the command and listen to the response.
    returns a list of the returned lines.
    The first item is always the command sent.
    """
    ser.write(str(cmd+'\n').encode('ascii')) # send our command
    lines=[]
    for line in ser.readlines(): # while there's a response
        lines.append(line.decode('utf-8').strip())
    if not silent:
        print("\n".join(lines))
        print('-'*60)
    return lines

def sendSensor( ser, register, addrwrite=0xEC,  addrread=0xED, silent=True):
    """
    Sending data to sensor by using the bus priate device
    """
    sendPirate (ser,'[%s %s]' % (addrwrite, register), silent=silent) # read two bytes

def readSensor (ser, noBytes, register=0x00, addrwrite=0xEC, addrread=0xED, readonly=False, silent=True):
    """
    Reading data from sensor by using the bus priate device.
    """
    if not readonly:
        lines=sendPirate(ser,'[%s %s [ %s r:%d]' % (addrwrite, register, addrread, noBytes ) ,silent=silent) # read three bytes from adc
    else:
        lines=sendPirate(ser,'[%s r:%d]' % ( addrread, noBytes ) ,silent=silent) # read three bytes from adc

    for line in lines:
        if line.startswith("READ:"):
            line=line.split(" ",1)[1].replace("ACK",'')
            while "  " in line:
                line=" "+line.strip().replace("  "," ")
            word = 0
            validx = 1
            line=" "+line.strip().replace("0x"," ")
            vals = line.split(" ")
            vals=' '.join(vals).split()
            nVals = len(vals)
            for iVal in vals:
                cVal = int(iVal, 16)
                word += cVal * math.pow ( 2 , 8 * (nVals - validx ) )
                validx +=1
    return int(word)

def getPressure( ser, addrwrite=0xEC, register=0x4A, addrread=0xED, silent=False):
    """
    get ambient pressure
    """
    sendSensor ( ser, register, silent=silent )
    time.sleep ( 0.5 )
    word = readSensor ( ser, 3, 0x00, addrwrite, addrread, readonly=False, silent=silent )
    return int(word)

def getTemperature( ser, addrwrite=0xEC, register=0x5A, addrread=0xED, silent=False):
    sendSensor ( ser, register, silent=silent)
    time.sleep (0.5)
    word = readSensor ( ser, 3, 0x00, addrwrite, addrread, readonly=False, silent=silent )
    return int(word)


def getHumidity( ser, addrwrite=0x80, register=0xA0, addrread=0x81, silent=False):
    # start humidity conversion
    # 0xF5 no hold master
    # 0xE5 hold master
    sendSensor ( ser, 0xF5, addrwrite=addrwrite,  addrread=addrread, silent=silent )
    time.sleep(0.5)
    word = readSensor ( ser, 2, register, addrwrite, addrread, readonly=True, silent=silent )
    return int(word)

def getCalibrationWord( ser, register, addrwrite=0xEC, addrread=0xED, silent=False):
    word = readSensor ( ser, 2, register, addrwrite, addrread, readonly=False, silent=silent )
    return int(word)


def initpirate(ser, silent=False):
    # have a clean starting point
    sendPirate(ser,'#',silent=silent) # reset bus pirate (slow, maybe not needed)
    #sendPirate(ser,'v') # show current voltages

    # set mode to I2C
    sendPirate(ser,'m',silent=silent) # change mode (goal is to get away from HiZ)
    sendPirate(ser,'4',silent=silent) # mode 4 is I2C
    sendPirate(ser,'3',silent=silent) # 100KHz
    sendPirate(ser,'W',silent=silent) # turn power supply to ON. Lowercase w for OFF.
    sendPirate(ser,'P',silent=silent) # enable pull-up resistors
    sendPirate(ser,'(1)',silent=silent) # scan I2C devices. Returns "0x90(0x48 W) 0x91(0x48 R)"

def initSensor ( ser, silent=False):
    sendSensor ( ser, 0x1E,silent=silent )
    time.sleep ( 0.5 )
    # reset humidity sensor
    sendSensor ( ser, 0xFE ,  addrwrite=0x80, addrread=0x81, silent=silent )
    time.sleep (0.3)
    PTCal = getPTCalibrationData ( ser, silent=silent )
    return PTCal


def getPTCalibrationData(ser, silent=False ):
    PTCalibration=[]
    for i in range(0,6):
        PTCalibration.append (getCalibrationWord( ser, register=(0xA2 + 2*i),silent=silent) )
        if  not silent:
            print ( "register 0x%X => 0x%X" % ( int(0xA2 + 2*i) , PTCalibration[i] ))
    return PTCalibration


ser=serial.Serial(BUSPIRATE_PORT, 115200, timeout=.1)

# init buspirate
initpirate(ser,silent=True)
# reset PT sensor
PTCal= initSensor(ser, silent=True )

# start pressure conversion
D1   = getPressure ( ser, silent=True )

# start temperature conversion
D2   = getTemperature ( ser , silent=True)
dT   = D2 - PTCal[4] * 256
Temp = 2000 + dT * PTCal[5] / 8388608

OFF  = PTCal[1] * 131072 + (PTCal[3] * dT) / 64
SENS = PTCal[0] * 65536 + (PTCal[2] * dT ) / 128

if Temp >= 2000 :
    Ti   = 5 * (dT * dT) / 274877906944
    OFFi = 0
    SENSi= 0
elif Temp < 2000 :
    Ti   = 3 * (dT * dT) / 8589934592
    OFFi = 61 * ((Temp - 2000) * (Temp - 2000)) / 16
    SENSi= 29 * ((Temp - 2000) * (Temp - 2000)) / 16
    if Temp < -1500:
        OFFi = OFFi + 17 * ((Temp + 1500) * (Temp + 1500))
        SENSi= SENSi + 9 * ((Temp + 1500) * (Temp +1500))

OFF2    = OFF - OFFi
SENS2   = SENS - SENSi
cTemp   = (Temp - Ti) / 100.0
fTemp   =  cTemp * 1.8 + 32
pressure= ((((D1 * SENS2) / 2097152) - OFF2) / 32768.0) / 100.0
D3      = getHumidity ( ser, silent=True )
humidity= (-6.0 + (125.0 * (D3 / 65536.0)))

print ( "Temperature %2.2f °C / Pressure %3.2f mbar / Humidity %3.1f %%" % ( cTemp , pressure, humidity ))