diff --git a/datasheets/MAX6070-MAX6071.pdf b/datasheets/MAX6070-MAX6071.pdf new file mode 100644 index 0000000..9f6b71c Binary files /dev/null and b/datasheets/MAX6070-MAX6071.pdf differ diff --git a/src/DEADJOE b/src/DEADJOE new file mode 100644 index 0000000..98e0f6b --- /dev/null +++ b/src/DEADJOE @@ -0,0 +1,7 @@ + +*** These modified files were found in JOE when it aborted on Tue Aug 9 19:43:11 2022 +*** JOE was aborted because the terminal closed + +*** File '(Unnamed)' +_registerAcc +spi_write diff --git a/src/MAX11270.py b/src/MAX11270.py index a118fea..14b39bb 100644 --- a/src/MAX11270.py +++ b/src/MAX11270.py @@ -83,6 +83,10 @@ MAX11270_SPS_4000 = 0b1101 MAX11270_SPS_6400 = 0b1110 MAX11270_SPS_12800 = 0b1111 +def reverseBits(n,width): + b = '{:0{width}b}'.format(n, width=width) + return int(b[::-1], 2) + class MAX11270: ''' Constructor of the class, setup the GPIO pin for SPI-communication @@ -96,7 +100,7 @@ class MAX11270: self.rstbPin = RSTB_Pin self.softSPI = True - + ''' if self.clkPin == 11 and self.mosiPin == 10 and self.misoPin == 9: self.spidev = 0 if self.csPin == 8: @@ -117,12 +121,14 @@ class MAX11270: elif self.csPin == 16: self.spichan == 2 self.softSPI = False - + ''' if vref is None: self.vref = 3 else: self.vref = vref + GPIO.setmode(GPIO.BCM) + GPIO.setup(self.clkPin, GPIO.OUT) GPIO.setup(self.mosiPin, GPIO.OUT) GPIO.setup(self.csPin, GPIO.OUT) @@ -132,10 +138,14 @@ class MAX11270: GPIO.setup(self.misoPin, GPIO.IN) GPIO.output(self.syncPin, GPIO.LOW) + #Reset the ADC at creation time + GPIO.output(self.rstbPin, GPIO.HIGH) GPIO.output(self.rstbPin, GPIO.LOW) + GPIO.output(self.rstbPin, GPIO.HIGH) GPIO.output(self.csPin, GPIO.HIGH) GPIO.output(self.clkPin, GPIO.LOW) + GPIO.output(self.mosiPin, GPIO.LOW) self.ready = 0 self.mstat = 0 @@ -176,11 +186,13 @@ class MAX11270: adc_command <<= 1 self._toggleClock() + + GPIO.output(self.csPin, GPIO.HIGH) ''' Operates the ADC in register access mode, used for configuration and readout ''' - def _registerAccessMode(self,register=0x0,rw) + def _registerAccessMode(self,rw,register=0x0): adc_command = 0b11000000 | register<<1 | rw # Start com GPIO.output(self.csPin, GPIO.LOW) @@ -196,30 +208,31 @@ class MAX11270: self._toggleClock() + #GPIO.output(self.csPin, GPIO.HIGH) + + def _spi_read(self, numbytes): retVal = 0 - # Start readout + # Start readout, in most cases cs is already low, because of register access GPIO.output(self.csPin, GPIO.LOW) #time.sleep(0.0001) - #Commucation consists of 32 transfered bits - for bit in range(numbytes*8): + + numBits = numbytes*8 + for bit in range(numBits): # Read 1 data bit if GPIO.input(self.misoPin): - retVal |= 0x1 - - # Advance input to next bit - retVal <<= 1 + retVal |= (1<<(numBits-1-bit)) self._toggleClock() # Set chip select high to end the read process GPIO.output(self.csPin, GPIO.HIGH) - #print(bin(retVal)) + + print(bin(retVal)) return retVal - def _spi_write(self,adc_command) - + def _spi_write(self,adc_command): # Start com GPIO.output(self.csPin, GPIO.LOW) for bit in range(8): @@ -233,24 +246,46 @@ class MAX11270: adc_command <<= 1 self._toggleClock() + + GPIO.output(self.csPin, GPIO.HIGH) - def _readAndChangeRegisterValue(self,register,value,firstBit,bits=1): + def _readAndChangeRegisterValue(self,register,newBits,firstBit,bits=1): + print('--------------') + #First readout register in order to change only one value #Select register - self._registerAccessMode(register,1) + self._registerAccessMode(1,register) #Read stored values value = self._spi_read(1) - self._registerAccessMode(register,0) - for bit in range(0,bits): - if value >> bit & 1 == 0: - value = value & ~(1<> (firstBit + bit) & 1 != (newBits >> bit) & 1: + if value >> bit & 1 == 1: + value = value & ~(1<> 0 & 1 self.mstat = value >> 1 & 1 self.dataOverrange = value >> 2 & 1 @@ -261,6 +296,24 @@ class MAX11270: self.powerState = value >> 10 & 0b11 self.error = value >> 14 & 1 self.inReset = value >> 15 & 1 + + if disp: + if self.ready: + print('Conversion result available') + if self.mstat: + print('Conversion, self-calibration or system-calibration in progress') + if self.dataOverrange: + print('Conversion result exceeded the max or min value') + if self.systemGainOverrange: + print(' system gain calibration was overranged') + if self.analogOverrange: + print(' the modulator detects that the analog input voltage exceeds 1.3 x full-scale range') + if self.dataReadError: + print(' result is being written to the DATA register while user is reading from the DATA register.') + if self.error: + print('CAL[1:0] bits are set to invalid setting of 11.') + if self.inReset: + print('software reset mode') return value @@ -312,7 +365,7 @@ class MAX11270: else: raise Exception("No known power state selected") - def setSyncMode(self,mode): + def setSyncMode(self,mode): if mode == 'continuousSync': self._readAndChangeRegisterValue(MAX11270_REG_CTRL1,1,6) elif mode == 'pulseSync': @@ -393,17 +446,18 @@ class MAX11270: #%% Data register functions def readDataRegister(self): - self._registerAccessMode(MAX11270_REG_DATA,1) + self._registerAccessMode(1,MAX11270_REG_DATA) return self._spi_read(self.dataBytes) #This function is not complete, as I do not understand the data sheet... def value_to_voltage(self, adcValue): + if adcValue == 0: voltage = -self.vref elif adcValue == 1: voltage = 0 else: - voltage = self.vref / 2**(self.dataBytes*8) *adcValue + voltage = self.vref / 2**(self.dataBytes*8-1) *adcValue return voltage @@ -412,10 +466,9 @@ class MAX11270: ''' def read_differential(self): #Triggers conversion - self._conversionMode(self) + self._conversionMode() time.sleep(0.001) - adc_code = self.readDataRegister(self) - + adc_code = self.readDataRegister() return self.value_to_voltage(adc_code) diff --git a/src/MCP3204.py b/src/MCP3204.py index 387d00d..72df4ae 100644 --- a/src/MCP3204.py +++ b/src/MCP3204.py @@ -1,24 +1,77 @@ -class MCP3204(object): +import spidev as SPI +import pin as GPIO +GPIO.config('./config.json') + +class MCP3204(): def __init__(self,spiDev,cs): - self.spi = SPI.SpiDev(spiDev, cs, max_speed_hz=1000000) - self.spi.set_mode(0) - self.spi.set_bit_order(SPI.MSBFIRST) + GPIO.setmode(GPIO.BCM) + + #self.spi = SPI.SpiDev() + #self.spi.open(spiDev, 0) + #self.max_speed_hz = 1000000 + #self.spi.mode = 0 + #self.spi.set_bit_order(SPI.MSBFIRST) + self.csPin = cs + GPIO.setup(self.csPin, GPIO.OUT) + GPIO.output(self.csPin, GPIO.HIGH) + + self.clkPin = 21 + GPIO.setup(self.clkPin, GPIO.OUT) + GPIO.output(self.clkPin, GPIO.LOW) + + self.mosiPin = 20 + GPIO.setup(self.mosiPin, GPIO.OUT) + GPIO.output(self.mosiPin, GPIO.LOW) + + self.misoPin = 19 + GPIO.setup(self.misoPin, GPIO.IN) def __del__(self): - self.spi.close() + #self.spi.close() + pass + + def _toggleClock(self): + GPIO.output(self.clkPin, GPIO.HIGH) + GPIO.output(self.clkPin, GPIO.LOW) def read(self, ch): if 4 <= ch <= 0: raise Exception('MCP3204 channel must be 0-4: ' + str(ch)) + GPIO.output(self.csPin, GPIO.LOW) + + ret = [] cmd = 128 # 1000 0000 cmd += 64 # 1100 0000 cmd += ((ch & 0x07) << 3) - ret = self.spi.transfer([cmd, 0x0, 0x0]) + #ret = self.spi.xfer2([cmd, 0, 0, 0]) + #print(ret) + for byte in range(3): + retVal = 0 + for bit in range(8): + if cmd & 0b10000000: + GPIO.output(self.mosiPin, GPIO.HIGH) + else: + GPIO.output(self.mosiPin, GPIO.LOW) - # get the 12b out of the return + #Shift command by 1 bit for next tick + cmd <<= 1 + + # Read 1 data bit + if GPIO.input(self.misoPin): + retVal |= 0x1 + + # Advance input to next bit + retVal <<= 1 + + self._toggleClock() + ret.append(retVal) + # get the 24b out of the return + print(ret) val = (ret[0] & 0x01) << 11 # only B11 is here val |= ret[1] << 3 # B10:B3 val |= ret[2] >> 5 # MSB has B2:B0 ... need to move down to LSB + GPIO.output(self.csPin, GPIO.HIGH) return (val & 0x0FFF) # ensure we are only sending 12b + #return(0) \ No newline at end of file diff --git a/src/MCP4822.py b/src/MCP4822.py index 307ad4e..807f811 100644 --- a/src/MCP4822.py +++ b/src/MCP4822.py @@ -20,11 +20,14 @@ class MCP4822: ''' Constructor of the class, setup the GPIO pin for SPI-communication ''' - def __init__(self, CLK_Pin, MOSI_Pin, CS_Pin, vref=None): + def __init__(self, CLK_Pin, MOSI_Pin, CS_Pin, LDAC_Pin, vref=None): + GPIO.setmode(GPIO.BCM) + self.clkPin = CLK_Pin self.mosiPin = MOSI_Pin self.csPin = CS_Pin - + self.ldacPin = LDAC_Pin + if vref is None: self.vref = 2.048 else: @@ -33,10 +36,14 @@ class MCP4822: GPIO.setup(self.clkPin, GPIO.OUT) GPIO.setup(self.mosiPin, GPIO.OUT) GPIO.setup(self.csPin, GPIO.OUT) + GPIO.setup(self.ldacPin, GPIO.OUT) GPIO.output(self.csPin, GPIO.HIGH) GPIO.output(self.clkPin, GPIO.LOW) + GPIO.output(self.mosiPin, GPIO.LOW) + GPIO.output(self.ldacPin, GPIO.LOW) + self.write(1.29,1) def U2dac(self,U,DAC): #U: voltage (V) [0V-4.096V] diff --git a/src/config.json b/src/config.json new file mode 100644 index 0000000..f27296e --- /dev/null +++ b/src/config.json @@ -0,0 +1,3 @@ +{ + "test":false +} diff --git a/src/pin.py b/src/pin.py new file mode 100644 index 0000000..a124f40 --- /dev/null +++ b/src/pin.py @@ -0,0 +1,129 @@ +from random import random +import json + +class InputOutputError(Exception): + pass + +conf={} +TEST='test' +conf[TEST]=False +IN=1 +OUT=0 +HIGH=1 +LOW=0 +BCM=0 +BOARD=1 +pins={} +out={} +values={} + +def config(path): + global conf + with open(path) as c: + conf = json.load(c) + if not conf[TEST]: + global RPi + global GPIO + import RPi.GPIO as GPIO + +#TODO check if initial is discarded for input or error is raised +def setup(channel,in_out,initial=HIGH): + global conf + if type(channel) is list: + for el in channel: + _setup_one(el,in_out,initial) + else: + _setup_one(channel,in_out,initial) + +def _setup_one(channel,in_out,initial): + if conf[TEST]: + pins[channel]=in_out + else: + if initial == HIGH: + initial = GPIO.HIGH + else: + initial = GPIO.LOW + if in_out == IN: + GPIO.setup(channel,GPIO.IN) # initial not a valid parameter for input, GPIO error + else: + GPIO.setup(channel,GPIO.OUT,initial=initial) + +def check_in_out(channel,in_out): + try: + if not pins[channel]==in_out: + raise InputOutputError("Wrong confuration for channel {}! You're treating an input channel as output or vice versa.") + except KeyError: + raise InputOutputError("Wrong confuration for channel {}! setup() not called for this channel before calling input() or output().") + +def setmode(mode): + if conf[TEST]: + pass + else: + if mode == BCM: + GPIO.setmode(GPIO.BCM) + else: + GPIO.setmode(GPIO.BOARD) + +def input(channel): + if conf[TEST]: + check_in_out(channel,IN) + try: + values[channel] + except KeyError: + return random() + return values[channel] + else: + return GPIO.input(channel) + +def output(channel,value): + if type(channel) is list: + for el in channel: + _output_one(el,value) + else: + _output_one(channel,value) + +def _output_one(channel,value): + if conf[TEST]: + check_in_out(channel,OUT) + out[channel]=value + else: + GPIO.output(channel,value) + +def set_value(channel,value): + values[channel]=value + +def get_output(channel): + return out[channel] + +def cleanup(channel=None): + global pins,out,values + if channel==None: + if conf[TEST]: + pins,out,values={},{},{} + else: + GPIO.cleanup() + else: + if type(channel) is list or type(channel) is tuple: + for el in channel: + _cleanup_one(el) + else: + _cleanup_one(channel) + +def _cleanup_one(channel): + global pins,out,values + if conf[TEST]: + if channel in values.keys() and pins[channel]==IN: + del values[channel] + elif channel in out.keys(): + del out[channel] + if channel in pins.keys(): + del pins[channel] + else: + GPIO.cleanup(channel) + +def setwarnings(val): + if conf[TEST]: + pass + else: + GPIO.setwarnings(val) + diff --git a/src/test_MAX11270.py b/src/test_MAX11270.py new file mode 100644 index 0000000..4d6af34 --- /dev/null +++ b/src/test_MAX11270.py @@ -0,0 +1,61 @@ + +import MAX11270 +import math +import MCP4822 +import time + +def adc2T(dU): + #constants + #VREF = (REF+) – (REF–) + #Vref = 2.5 + #wheatstonebridge + # U0_____ + # | + # R0 + # Uw_____|__ + # | | + # R2 R4 + # |__dU__| + # | | + # R1 R3 + # |______| + # Gnd_____|_ + # + # R1 = resistance of thermistor + R0 = 0 + R2 = 5100 #(Ohm) + R3 = 97600 #(Ohm) + R4 = 5100 #(Ohm) + U0 = 3 #(V) + #steinhart-Hart Coefficients 10uA + # NTC_A = 9.7142e-4; + # NTC_B = 2.3268e-4; + # NTC_C = 8.0591e-8; + #steinhart-Hart Coefficients 100uA + NTC_A = 9.6542e-4 + NTC_B = 2.3356e-4 + NTC_C = 7.7781e-8 + + R1 = -(R0*R2*dU - R2*R3*U0 + R0*R3*dU + R0*R4*dU + R2*R3*dU + R2*R4*dU)/(R4*U0 + R0*dU + R3*dU + R4*dU) + #calculate temperature + try: + T = 1/(NTC_A + NTC_B*math.log(float(R1)) + NTC_C*math.pow(math.log(float(R1)),3)) - 273.15 + except ValueError: + T = 6666 + return T + +myADC = MAX11270.MAX11270(21,20,19,17,27,22) +myDAC = MCP4822.MCP4822(11, 10, 8, 5) + +#myDAC.write(0,1) +#myDAC.write(0,0) + +print('-Status-') +print(myADC.readStatusRegister(1)) +#myADC.performCalibration('offsetCalibration') +#print(myADC.readStatusRegister(1)) + +print('--------Readout ADC value ---------') +for i in range(0,100): + print(adc2T(myADC.read_differential())) + time.sleep(10) diff --git a/src/test_MCP3204.py b/src/test_MCP3204.py new file mode 100644 index 0000000..5631d3d --- /dev/null +++ b/src/test_MCP3204.py @@ -0,0 +1,10 @@ + +import MCP3204 + +myADC = MCP3204.MCP3204(1,7) + +print(myADC.read(0)) +print(myADC.read(1)) +print(myADC.read(2)) +print(myADC.read(3)) + diff --git a/src/test_MCP4822.py b/src/test_MCP4822.py new file mode 100644 index 0000000..5df697b --- /dev/null +++ b/src/test_MCP4822.py @@ -0,0 +1,8 @@ +import MCP4822 +import time + +myDAC = MCP4822.MCP4822(11, 10, 8, 5) +myDAC.write(1,0) +myDAC.write(0,1) + +#time.sleep(10) \ No newline at end of file