From 0b8039cc0a6e329f7071191379d1662a355cca42 Mon Sep 17 00:00:00 2001 From: Diego Lopez Gutierrez <dlopezgu@bu.edu> Date: Mon, 6 Mar 2023 12:21:59 -0500 Subject: [PATCH 1/7] Enable current source for ADC7 and set current to 14 uA, taking into account new thermistor NTCG063JF103FTB --- tamalero/LPGBT.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tamalero/LPGBT.py b/tamalero/LPGBT.py index 0fab62a..069c3b2 100644 --- a/tamalero/LPGBT.py +++ b/tamalero/LPGBT.py @@ -127,6 +127,8 @@ class LPGBT(RegParser): self.cal_gain = 1.85 self.cal_offset = 512 + self.set_current_adc7() + def read_base_config(self): # print("{:80}{:10}{:10}".format("Register", "value", "default")) @@ -626,7 +628,20 @@ class LPGBT(RegParser): self.cal_gain = gain self.cal_offset = offset + + def set_current_adc7(self, verbose=False): + self.wr_reg("LPGBT.RWF.VOLTAGE_DAC.CURDACENABLE", 0x1) + if verbose: + print("Set current DAC...", self.rd_reg("LPGBT.RWF.VOLTAGE_DAC.CURDACENABLE")) + self.wr_reg("LPGBT.RWF.CUR_DAC.CURDACCHNENABLE", 0x40) # Set pin ADC7 to current source; 0x40 = 64 = 01000000 + if verbose: + print("Set current source to pin ADC7...", bin(self.rd_reg("LPGBT.RWF.CUR_DAC.CURDACCHNENABLE"))) + + self.wr_reg("LPGBT.RWF.CUR_DAC.CURDACSELECT", 0xE) # Set current to 14 uA; max V = 0.977, min V = 0.080 for T in -20-40C range + if verbose: + print("Set current source value to...", int(self.rd_reg("LPGBT.RWF.CUR_DAC.CURDACSELECT")), "uA") + def set_dac(self, v_out): if v_out > 1.00: print ("Can't set the DAC to a value larger than 1.0 V!") -- GitLab From bb7856ac68d85616b4d7954b5a91d047bc6c3c83 Mon Sep 17 00:00:00 2001 From: Diego Lopez Gutierrez <dlopezgu@bu.edu> Date: Thu, 9 Mar 2023 15:46:11 -0500 Subject: [PATCH 2/7] Generalize current_adc function to apply to any ADC input, add get_temp_direct to tamalero.utils to properly calculate temp of RT1 --- tamalero/LPGBT.py | 33 +++++++++++++++++++++++++++------ tamalero/ReadoutBoard.py | 5 +++-- tamalero/utils.py | 27 +++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/tamalero/LPGBT.py b/tamalero/LPGBT.py index 069c3b2..f3766d4 100644 --- a/tamalero/LPGBT.py +++ b/tamalero/LPGBT.py @@ -127,7 +127,7 @@ class LPGBT(RegParser): self.cal_gain = 1.85 self.cal_offset = 512 - self.set_current_adc7() + self.set_current_adc(7) def read_base_config(self): # @@ -629,18 +629,39 @@ class LPGBT(RegParser): self.cal_gain = gain self.cal_offset = offset - def set_current_adc7(self, verbose=False): + def set_current_adc(self, channel, verbose=True): + assert channel in range(8), f"Can only choose from ADC0 to ADC7; ADC{channel} was given instead" + self.wr_reg("LPGBT.RWF.VOLTAGE_DAC.CURDACENABLE", 0x1) if verbose: print("Set current DAC...", self.rd_reg("LPGBT.RWF.VOLTAGE_DAC.CURDACENABLE")) - self.wr_reg("LPGBT.RWF.CUR_DAC.CURDACCHNENABLE", 0x40) # Set pin ADC7 to current source; 0x40 = 64 = 01000000 + if channel == 0: + adc_chn = self.LPGBT_CONST.CURDAC_CHN0_bm + elif channel == 1: + adc_chn = self.LPGBT_CONST.CURDAC_CHN1_bm + elif channel == 2: + adc_chn = self.LPGBT_CONST.CURDAC_CHN2_bm + elif channel == 3: + adc_chn = self.LPGBT_CONST.CURDAC_CHN3_bm + elif channel == 4: + adc_chn = self.LPGBT_CONST.CURDAC_CHN4_bm + elif channel == 5: + adc_chn = self.LPGBT_CONST.CURDAC_CHN5_bm + elif channel == 6: + adc_chn = self.LPGBT_CONST.CURDAC_CHN6_bm + elif channel == 7: + adc_chn = self.LPGBT_CONST.CURDAC_CHN7_bm + + self.wr_reg("LPGBT.RWF.CUR_DAC.CURDACCHNENABLE", adc_chn) # Set pin ADC channel to current source if verbose: print("Set current source to pin ADC7...", bin(self.rd_reg("LPGBT.RWF.CUR_DAC.CURDACCHNENABLE"))) - - self.wr_reg("LPGBT.RWF.CUR_DAC.CURDACSELECT", 0xE) # Set current to 14 uA; max V = 0.977, min V = 0.080 for T in -20-40C range + + curr_dac = 14 # Desired current of 14 uA; max V = 0.977, min V = 0.080 for T in -20-40C range + curr_dac_select = round(curr_dac*256/900) # CURDACSELECT is in units of 900/256 uA per bit + self.wr_reg("LPGBT.RWF.CUR_DAC.CURDACSELECT", curr_dac_select) if verbose: - print("Set current source value to...", int(self.rd_reg("LPGBT.RWF.CUR_DAC.CURDACSELECT")), "uA") + print("Set current source value to...", curr_dac_select*900/256, "uA") def set_dac(self, v_out): if v_out > 1.00: diff --git a/tamalero/ReadoutBoard.py b/tamalero/ReadoutBoard.py index cd2e370..f2dacaa 100644 --- a/tamalero/ReadoutBoard.py +++ b/tamalero/ReadoutBoard.py @@ -1,7 +1,7 @@ import os from tamalero.LPGBT import LPGBT from tamalero.SCA import SCA -from tamalero.utils import get_temp, chunk +from tamalero.utils import get_temp, chunk, get_temp_direct from tamalero.VTRX import VTRX from time import sleep @@ -365,7 +365,8 @@ class ReadoutBoard: elif self.ver == 2: # https://www.digikey.com/en/products/detail/tdk-corporation/NTCG063JF103FTB/5872743 # Parameters need updating? - t1 = get_temp(adc_7, v_ref, 10000, 25, 10000, 3900) # this comes from the lpGBT ADC + curr_dac = self.DAQ_LPGBT.rd_reg("LPGBT.RWF.CUR_DAC.CURDACSELECT")*900/256 + t1 = get_temp_direct(adc_7, curr_dac, 25, 10000, 3380) # this comes from the lpGBT ADC t2 = get_temp(adc_in29, v_ref, 10000, 25, 10000, 3380) # this comes from the SCA ADC if verbose>0: diff --git a/tamalero/utils.py b/tamalero/utils.py index 64a9169..473f860 100644 --- a/tamalero/utils.py +++ b/tamalero/utils.py @@ -37,6 +37,33 @@ def get_temp(v_out, v_ref, r_ref, t_1, r_1, b, celcius=True): return -999 return t_2-delta_t +def get_temp_direct(v_out, curr_dac, t_1, r_1, b, celcius=True): + """ + Calculate the temperature of a thermistor, given the voltage measured on it. + + Arguments: + v_out (float) -- voltage measured on the thermistor + curr_dac (float) -- current source value set on the DAC (in uA) + t_1 (float) -- reference temperature of thermistor + r_1 (float) -- resistance of NTC at reference temperature + b (float) -- B coefficient, with B = (ln(r_1)-ln(r_t)) / (1/t_1 - 1/t_out) + + Keyword arguments: + celcius (bool) -- give and return the temperature in degree celcius. Kelvin scale used otherwise. + """ + + delta_t = 273.15 if celcius else 0 + try: + r_t = v_out / (curr_dac / 10**6) + print(f"r_t: {r_t}") + print(f"v_out: {v_out}") + print(f"curr_dac: {curr_dac / 10**6}") + print(f"b: {b}") + t_2 = b/((b/(t_1+delta_t)) - math.log(r_1) + math.log(r_t)) + except ZeroDivisionError: + print ("Temperature calculation failed!") + return -999 + return t_2-delta_t def read_mapping(f_in, selection='adc', flavor='small'): flavors = {'small':0, 'medium':1, 'large': 2} -- GitLab From 4da1bf5baa611efb294921d3edc480cb7232631a Mon Sep 17 00:00:00 2001 From: Diego Lopez Gutierrez <dlopezgu@bu.edu> Date: Tue, 14 Mar 2023 15:02:27 -0400 Subject: [PATCH 3/7] Include VTRX thermistor, improve accuracy of get_temp function, add VTRX read to ReadoutBoard --- tamalero/LPGBT.py | 52 ++++++++++++++++++++++++++++--- tamalero/ReadoutBoard.py | 7 +++-- tamalero/utils.py | 67 ++++++++++++++++++++++++++++++---------- 3 files changed, 104 insertions(+), 22 deletions(-) diff --git a/tamalero/LPGBT.py b/tamalero/LPGBT.py index f3766d4..3552709 100644 --- a/tamalero/LPGBT.py +++ b/tamalero/LPGBT.py @@ -128,6 +128,7 @@ class LPGBT(RegParser): self.cal_offset = 512 self.set_current_adc(7) + self.set_current_adc(0) def read_base_config(self): # @@ -653,9 +654,14 @@ class LPGBT(RegParser): elif channel == 7: adc_chn = self.LPGBT_CONST.CURDAC_CHN7_bm - self.wr_reg("LPGBT.RWF.CUR_DAC.CURDACCHNENABLE", adc_chn) # Set pin ADC channel to current source + currently_set = self.rd_reg("LPGBT.RWF.CUR_DAC.CURDACCHNENABLE") + print(f"LPGBT.RWF.CUR_DAC.CURDACCHNENABLE currently set: {bin(currently_set)}") + print(f"Want to set {bin(adc_chn)}") + print(f"LPGBT.RWF.CUR_DAC.CURDACCHNENABLE new set: {bin(adc_chn | currently_set)}") + + self.wr_reg("LPGBT.RWF.CUR_DAC.CURDACCHNENABLE", adc_chn | currently_set) # Set pin ADC channel to current source if verbose: - print("Set current source to pin ADC7...", bin(self.rd_reg("LPGBT.RWF.CUR_DAC.CURDACCHNENABLE"))) + print(f"Set current source to pin ADC{channel}...", bin(self.rd_reg("LPGBT.RWF.CUR_DAC.CURDACCHNENABLE"))) curr_dac = 14 # Desired current of 14 uA; max V = 0.977, min V = 0.080 for T in -20-40C range curr_dac_select = round(curr_dac*256/900) # CURDACSELECT is in units of 900/256 uA per bit @@ -954,13 +960,21 @@ class LPGBT(RegParser): print ("Write not successfull!") break - def I2C_read(self, reg=0x0, master=2, slave_addr=0x70, nbytes=1, adr_nbytes=2, freq=2, verbose=False): + def I2C_read(self, reg=0x0, master=2, slave_addr=0x70, nbytes=1, adr_nbytes=2, freq=2, verbose=True): #https://gitlab.cern.ch/lpgbt/pigbt/-/blob/master/backend/apiapp/lpgbtLib/lowLevelDrivers/MASTERI2C.py#L83 + + # debugging + #print("### LPGBT.I2C_read ###") + #print(f"reg: {reg}, \tmaster: {master}, \tslave_addr: {slave_addr}, \tnbytes: {nbytes}, \tadr_nbytes: {adr_nbytes}, \tfreq: {freq}, \tver: {self.ver}") + i2cm = master i2cm1cmd = self.get_node('LPGBT.RW.I2C.I2CM1CMD').real_address i2cm0cmd = self.get_node('LPGBT.RW.I2C.I2CM0CMD').real_address + # debugging + #print(f"i2cm1cmd: {i2cm1cmd}, \ti2cm0cmd: {i2cm0cmd}") + if self.ver == 0: i2cm1status = self.LPGBT_CONST.I2CM1STATUS i2cm0status = self.LPGBT_CONST.I2CM0STATUS @@ -975,28 +989,49 @@ class LPGBT(RegParser): OFFSET_WR = i2cm*(i2cm1cmd - i2cm0cmd) #using the offset trick to switch between masters easily OFFSET_RD = i2cm*(i2cm1status - i2cm0status) + # debugging + #print(f"i2cm1status: {i2cm1status}, \ti2cm0status: {i2cm0status}, \ti2cm0data0: {i2cm0data0}, \ti2cm0cmd: {i2cm0cmd}, \ti2cm0address: {i2cm0address}, \tOFFSET_WR: {OFFSET_WR}, \tOFFSET_RD: {OFFSET_RD}") + ################################################################################ # Write the register address ################################################################################ # https://lpgbt.web.cern.ch/lpgbt/v0/i2cMasters.html#i2c-write-cr-0x0 self.wr_adr(i2cm0data0+OFFSET_WR, adr_nbytes<<self.LPGBT_CONST.I2CM_CR_NBYTES_of | (freq<<self.LPGBT_CONST.I2CM_CR_FREQ_of)) + # debugging + #print(f"Address: {i2cm0data0+OFFSET_WR}, \tValue: {adr_nbytes<<self.LPGBT_CONST.I2CM_CR_NBYTES_of | (freq<<self.LPGBT_CONST.I2CM_CR_FREQ_of)}") self.wr_adr(i2cm0cmd+OFFSET_WR, self.LPGBT_CONST.I2CM_WRITE_CRA) #write to config register + # debugging + #print(f"Address: {i2cm0cmd+OFFSET_WR}, \tValue: {self.LPGBT_CONST.I2CM_WRITE_CRA}") # https://lpgbt.web.cern.ch/lpgbt/v0/i2cMasters.html#i2c-w-multi-4byte0-0x8 for i in range (adr_nbytes): self.wr_adr(self.get_node("LPGBT.RW.I2C.I2CM0DATA%d"%i).real_address + OFFSET_WR, (reg >> (8*i)) & 0xff ) + # debugging + #print(f"Address: {self.get_node('LPGBT.RW.I2C.I2CM0DATA%d'%i).real_address + OFFSET_WR}, \tValue: {(reg >> (8*i)) & 0xff}, \ti: {i}") # self.wr_adr(self.LPGBT_CONST.I2CM0DATA1 + OFFSET_WR , regh) self.wr_adr(i2cm0cmd+OFFSET_WR, self.LPGBT_CONST.I2CM_W_MULTI_4BYTE0) # prepare a multi-write + # debugging + #print(f"Address: {i2cm0cmd+OFFSET_WR}, \tValue: {self.LPGBT_CONST.I2CM_W_MULTI_4BYTE0}") # https://lpgbt.web.cern.ch/lpgbt/v0/i2cMasters.html#i2c-write-multi-0xc self.wr_adr(i2cm0address+OFFSET_WR, slave_addr) + # debugging + #print(f"Address: {i2cm0address+OFFSET_WR}, \tValue: {slave_addr}") self.wr_adr(i2cm0cmd+OFFSET_WR, self.LPGBT_CONST.I2CM_WRITE_MULTI)# execute multi-write + # debugging + #print(f"Address: {i2cm0cmd+OFFSET_WR}, \tValue: {self.LPGBT_CONST.I2CM_WRITE_MULTI}") status = self.rd_adr(i2cm0status+OFFSET_RD) + + # debugging + #print(f"status: {status}, LPGBT_CONST.I2CM_SR_SUCC_bm: {self.LPGBT_CONST.I2CM_SR_SUCC_bm}, Address: {i2cm0status+OFFSET_RD}") + retries = 0 while (status != self.LPGBT_CONST.I2CM_SR_SUCC_bm): status = self.rd_adr(i2cm0status+OFFSET_RD) + # debugging + #print(f"Updating status: {status}, retries: {retries}") retries += 1 if retries > 50: if verbose: @@ -1016,12 +1051,16 @@ class LPGBT(RegParser): self.wr_adr(i2cm0cmd+OFFSET_WR, self.LPGBT_CONST.I2CM_READ_MULTI)# execute read status = self.rd_adr(i2cm0status+OFFSET_RD) + + # debugging + #print(f"status: {status}") + retries = 0 while (status != self.LPGBT_CONST.I2CM_SR_SUCC_bm): status = self.rd_adr(i2cm0status+OFFSET_RD) retries += 1 if retries > 50: - if not quiet: + if verbose: print ("Read not successfull!") return None @@ -1032,8 +1071,13 @@ class LPGBT(RegParser): else: i2cm0read15 = self.get_node("LPGBT.RO.I2CREAD.I2CM0READ.I2CM0READ15").real_address + # debugging + #print(f"i2cm0read15: {i2cm0read15}") + for i in range(0, nbytes): tmp_adr = abs(i-i2cm0read15)+OFFSET_RD + # debugging + #print(f"tmp_adr: {tmp_adr}, \ttmp_adr_val: {self.rd_adr(tmp_adr).value()}") read_values.append(self.rd_adr(tmp_adr).value()) #read_value = self.rd_adr(self.LPGBT_CONST.I2CM0READ15+OFFSET_RD) # get the read value. this is just the first byte diff --git a/tamalero/ReadoutBoard.py b/tamalero/ReadoutBoard.py index f2dacaa..f57066b 100644 --- a/tamalero/ReadoutBoard.py +++ b/tamalero/ReadoutBoard.py @@ -353,6 +353,7 @@ class ReadoutBoard: # high level function to read all the temperature sensors adc_7 = self.DAQ_LPGBT.read_adc(7)/(2**10-1) + adc_0 = self.DAQ_LPGBT.read_adc(0)/(2**10-1) adc_in29 = self.SCA.read_adc(29)/(2**12-1) v_ref = self.DAQ_LPGBT.read_dac() t_SCA = self.SCA.read_temp() # internal temp from SCA @@ -366,16 +367,18 @@ class ReadoutBoard: # https://www.digikey.com/en/products/detail/tdk-corporation/NTCG063JF103FTB/5872743 # Parameters need updating? curr_dac = self.DAQ_LPGBT.rd_reg("LPGBT.RWF.CUR_DAC.CURDACSELECT")*900/256 - t1 = get_temp_direct(adc_7, curr_dac, 25, 10000, 3380) # this comes from the lpGBT ADC + t1 = get_temp_direct(adc_7, curr_dac, thermistor="NTCG063JF103FTB") # this comes from the lpGBT ADC t2 = get_temp(adc_in29, v_ref, 10000, 25, 10000, 3380) # this comes from the SCA ADC + t_VTRX = get_temp_direct(adc_0, curr_dac, thermistor="NCP03XM102E05RL") # this comes from the lpGBT ADC (VTRX TH) if verbose>0: print ("\nV_ref is set to: %.3f V"%v_ref) print ("\nTemperature on RB RT1 is: %.3f C"%t1) print ("Temperature on RB RT2 is: %.3f C"%t2) print ("Temperature on RB SCA is: %.3f C"%t_SCA) + print ("Temperature on RB VTRX is: %.3f C"%t_VTRX) else: print ("V_ref found to be 0. Exiting.") return {'t_SCA': t_SCA} - return {'t1': t1, 't2': t2, 't_SCA': t_SCA} + return {'t1': t1, 't2': t2, 't_SCA': t_SCA, 't_VTRX': t_VTRX} diff --git a/tamalero/utils.py b/tamalero/utils.py index 473f860..490f742 100644 --- a/tamalero/utils.py +++ b/tamalero/utils.py @@ -37,33 +37,68 @@ def get_temp(v_out, v_ref, r_ref, t_1, r_1, b, celcius=True): return -999 return t_2-delta_t -def get_temp_direct(v_out, curr_dac, t_1, r_1, b, celcius=True): +def get_temp_direct(v_out, curr_dac, thermistor="NTCG063JF103FTB", celcius=True): """ Calculate the temperature of a thermistor, given the voltage measured on it. Arguments: v_out (float) -- voltage measured on the thermistor curr_dac (float) -- current source value set on the DAC (in uA) - t_1 (float) -- reference temperature of thermistor - r_1 (float) -- resistance of NTC at reference temperature - b (float) -- B coefficient, with B = (ln(r_1)-ln(r_t)) / (1/t_1 - 1/t_out) + thermistor (str="NTCG063JF103FTB") -- thermistor used for temperature calculation Keyword arguments: celcius (bool) -- give and return the temperature in degree celcius. Kelvin scale used otherwise. """ - delta_t = 273.15 if celcius else 0 - try: - r_t = v_out / (curr_dac / 10**6) - print(f"r_t: {r_t}") - print(f"v_out: {v_out}") - print(f"curr_dac: {curr_dac / 10**6}") - print(f"b: {b}") - t_2 = b/((b/(t_1+delta_t)) - math.log(r_1) + math.log(r_t)) - except ZeroDivisionError: - print ("Temperature calculation failed!") - return -999 - return t_2-delta_t + find_temp = temp_res_fit(thermistor=thermistor) + + r_t = v_out / (curr_dac / 10**6) + t = find_temp(np.log10(r_t)) + + delta_t = 0 if celcius else 273.15 + + print(f"Thermistor: {thermistor}") + print(f"Voltage: {v_out} \t Current: {curr_dac} uA") + print(f"Resistance: {r_t}") + print(f"Temperature: {t}") + + return t+delta_t + +def temp_res_fit(thermistor="NTCG063JF103FTB", power=2): + + T_ref = 25 + if thermistor=="NTCG063JF103FTB": + B_list = [3194, 3270, 3382, 3422] + T_list = [-25, 0, 50, 75] + R_ref = 10e3 + elif thermistor=="NTCG063UH103HTBX": + B_list = [3770, 3822, 3900, 3926] + T_list = [-25, 0, 50, 75] + R_ref = 10e3 + elif thermistor=="NCP03XM102E05RL": + B_list = [3500, 3539, 3545, 3560] + T_list = [50, 80, 85, 100] + R_ref = 1e3 + else: + raise ValueError(f"Only thermistors NTCG063JF103FTB, NTCG063UH103HTBX or NCP03XM102E05RL are currently allowed, but {thermistor} was passed.") + + R_list = [] + + for B, T in zip(B_list, T_list): + R = R_ref * math.exp(-B * ((1/298.15) - (1/(T+273.15)))) + R_list.append(R) + + if thermistor=="NTCG063JF103FTB" or thermistor=="NTCG063UH103HTBX": + T_list.insert(2, T_ref) # Reference temperature of thermistor + R_list.insert(2, R_ref) # Reference resistance of NTC at reference temperature + elif thermistor=="NCP03XM102E05RL": + T_list = [T_ref] + T_list + R_list = [R_ref] + R_list + + poly_coeffs = np.polyfit(np.log10(R_list), T_list, power) + fit = np.poly1d(poly_coeffs) + + return fit def read_mapping(f_in, selection='adc', flavor='small'): flavors = {'small':0, 'medium':1, 'large': 2} -- GitLab From 6c4ca1cf91b4731f466b95bade19f2b528492e8f Mon Sep 17 00:00:00 2001 From: Diego Lopez Gutierrez <dlopezgu@bu.edu> Date: Thu, 23 Mar 2023 12:41:33 -0400 Subject: [PATCH 4/7] Add current_adcs.yaml file that contains the lpGBT adcs to set for current source --- configs/current_adcs.yaml | 3 +++ tamalero/LPGBT.py | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 configs/current_adcs.yaml diff --git a/configs/current_adcs.yaml b/configs/current_adcs.yaml new file mode 100644 index 0000000..e773384 --- /dev/null +++ b/configs/current_adcs.yaml @@ -0,0 +1,3 @@ +lpGBT: + - 0 + - 7 diff --git a/tamalero/LPGBT.py b/tamalero/LPGBT.py index 3552709..5231ae8 100644 --- a/tamalero/LPGBT.py +++ b/tamalero/LPGBT.py @@ -127,8 +127,9 @@ class LPGBT(RegParser): self.cal_gain = 1.85 self.cal_offset = 512 - self.set_current_adc(7) - self.set_current_adc(0) + self.current_adcs = load_yaml(os.path.expandvars('$TAMALERO_BASE/configs/current_adcs.yaml'))['lpGBT'] + for adc in self.current_adcs: + self.set_current_adc(adc) def read_base_config(self): # -- GitLab From 8bde0558ed3e938d15a51b6be2a3c2f834cbeb42 Mon Sep 17 00:00:00 2001 From: Diego Lopez Gutierrez <dlopezgu@bu.edu> Date: Thu, 23 Mar 2023 15:53:23 -0400 Subject: [PATCH 5/7] Set current source to 100uA to get proper temperatures in VTRX and RT1 --- tamalero/LPGBT.py | 6 +++--- tamalero/ReadoutBoard.py | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tamalero/LPGBT.py b/tamalero/LPGBT.py index 5231ae8..7fdafd3 100644 --- a/tamalero/LPGBT.py +++ b/tamalero/LPGBT.py @@ -664,12 +664,12 @@ class LPGBT(RegParser): if verbose: print(f"Set current source to pin ADC{channel}...", bin(self.rd_reg("LPGBT.RWF.CUR_DAC.CURDACCHNENABLE"))) - curr_dac = 14 # Desired current of 14 uA; max V = 0.977, min V = 0.080 for T in -20-40C range - curr_dac_select = round(curr_dac*256/900) # CURDACSELECT is in units of 900/256 uA per bit + curr_dac = 100 # Desired current of 100 uA + curr_dac_select = min(round(curr_dac*256/900), 255) # CURDACSELECT is in units of 900/256 uA per bit, with max of 255 self.wr_reg("LPGBT.RWF.CUR_DAC.CURDACSELECT", curr_dac_select) if verbose: print("Set current source value to...", curr_dac_select*900/256, "uA") - + def set_dac(self, v_out): if v_out > 1.00: print ("Can't set the DAC to a value larger than 1.0 V!") diff --git a/tamalero/ReadoutBoard.py b/tamalero/ReadoutBoard.py index f57066b..1dd4074 100644 --- a/tamalero/ReadoutBoard.py +++ b/tamalero/ReadoutBoard.py @@ -365,7 +365,6 @@ class ReadoutBoard: t2 = get_temp(adc_in29, v_ref, 10000, 25, 10000, 3900) # this comes from the SCA ADC elif self.ver == 2: # https://www.digikey.com/en/products/detail/tdk-corporation/NTCG063JF103FTB/5872743 - # Parameters need updating? curr_dac = self.DAQ_LPGBT.rd_reg("LPGBT.RWF.CUR_DAC.CURDACSELECT")*900/256 t1 = get_temp_direct(adc_7, curr_dac, thermistor="NTCG063JF103FTB") # this comes from the lpGBT ADC t2 = get_temp(adc_in29, v_ref, 10000, 25, 10000, 3380) # this comes from the SCA ADC -- GitLab From 5f6bee8de102352f79c80540911bca9270428e00 Mon Sep 17 00:00:00 2001 From: Andrew Peck <andrew.peck@cern.ch> Date: Tue, 11 Apr 2023 13:40:43 -0400 Subject: [PATCH 6/7] fix thermistor readings + cleanup - use different currents for the two thermistors to keep readings close to the center of the lpgbt analog input - to provide separate methods for reading the different thermistors - provide wrappers around setting and reading the current sources --- tamalero/LPGBT.py | 53 ++++++++++++++++++------ tamalero/ReadoutBoard.py | 88 ++++++++++++++++++++++++++++------------ tamalero/utils.py | 13 +++--- test_tamalero.py | 2 +- 4 files changed, 112 insertions(+), 44 deletions(-) diff --git a/tamalero/LPGBT.py b/tamalero/LPGBT.py index 7fdafd3..3203ea8 100644 --- a/tamalero/LPGBT.py +++ b/tamalero/LPGBT.py @@ -550,7 +550,25 @@ class LPGBT(RegParser): else: print(tabulate(table, headers=["Register","Pin", "Reading", "Voltage", "Comment"], tablefmt="simple_outline")) - def read_adc(self, channel, convert=False): + def set_current_dac(self, units): + self.wr_reg("LPGBT.RWF.CUR_DAC.CURDACSELECT", units) + + def get_current_dac(self): + return self.rd_reg("LPGBT.RWF.CUR_DAC.CURDACSELECT") + + def set_current_dac_uA(self, uA): + # CURDACSELECT is in units of 900/256 uA per bit, with max of 255 + conv = 256.0/900 + val = min(round(uA*conv), 255) + self.set_current_dac(val) + return val/conv + + def get_current_dac_uA(self): + # CURDACSELECT is in units of 900/256 uA per bit, with max of 255 + return self.rd_reg("LPGBT.RWF.CUR_DAC.CURDACSELECT") * 900/256.0 + + + def read_adc(self, channel, calibrate=True, convert=False): # ADCInPSelect[3:0] | Input # ------------------ |---------------------------------------- # 4'd0 | ADC0 (external pin) @@ -587,13 +605,19 @@ class LPGBT(RegParser): self.wr_reg("LPGBT.RW.ADC.ADCCONVERT", 0x0) self.wr_reg("LPGBT.RW.ADC.ADCENABLE", 0x1) + if calibrate: + val = val*self.cal_gain/1.85 + (512 - self.cal_offset) # calibrate + if convert: + conversion = None for k in self.adc_mapping.keys(): if int(self.adc_mapping[k]['pin']) == channel: conversion = self.adc_mapping[k]['conv'] break - val = val*self.cal_gain/1.85 + (512 - self.cal_offset) # calibrate - val = val / (2**10 - 1) * conversion # convert + if conversion is not None: + val = val * conversion / (2**10 - 1) + else: + raise Exception(f"ADC conversion not found when reading ADC {channel}") return val def calibrate_adc(self, recalibrate=False): @@ -631,7 +655,7 @@ class LPGBT(RegParser): self.cal_gain = gain self.cal_offset = offset - def set_current_adc(self, channel, verbose=True): + def set_current_adc(self, channel, verbose=False): assert channel in range(8), f"Can only choose from ADC0 to ADC7; ADC{channel} was given instead" self.wr_reg("LPGBT.RWF.VOLTAGE_DAC.CURDACENABLE", 0x1) @@ -654,21 +678,24 @@ class LPGBT(RegParser): adc_chn = self.LPGBT_CONST.CURDAC_CHN6_bm elif channel == 7: adc_chn = self.LPGBT_CONST.CURDAC_CHN7_bm + else: + raise Exception("Invalid lpGBT ADC channel selected") currently_set = self.rd_reg("LPGBT.RWF.CUR_DAC.CURDACCHNENABLE") - print(f"LPGBT.RWF.CUR_DAC.CURDACCHNENABLE currently set: {bin(currently_set)}") - print(f"Want to set {bin(adc_chn)}") - print(f"LPGBT.RWF.CUR_DAC.CURDACCHNENABLE new set: {bin(adc_chn | currently_set)}") + + if verbose: + print(f"LPGBT.RWF.CUR_DAC.CURDACCHNENABLE currently set: {bin(currently_set)}") + print(f"Want to set {bin(adc_chn)}") + print(f"LPGBT.RWF.CUR_DAC.CURDACCHNENABLE new set: {bin(adc_chn | currently_set)}") self.wr_reg("LPGBT.RWF.CUR_DAC.CURDACCHNENABLE", adc_chn | currently_set) # Set pin ADC channel to current source if verbose: print(f"Set current source to pin ADC{channel}...", bin(self.rd_reg("LPGBT.RWF.CUR_DAC.CURDACCHNENABLE"))) - - curr_dac = 100 # Desired current of 100 uA - curr_dac_select = min(round(curr_dac*256/900), 255) # CURDACSELECT is in units of 900/256 uA per bit, with max of 255 - self.wr_reg("LPGBT.RWF.CUR_DAC.CURDACSELECT", curr_dac_select) + + current = 100 # Desired current of 100 uA + self.set_current_dac_uA(current) if verbose: - print("Set current source value to...", curr_dac_select*900/256, "uA") + print(f"Set current source value to {current} uA") def set_dac(self, v_out): if v_out > 1.00: @@ -696,6 +723,8 @@ class LPGBT(RegParser): elif self.ver == 1: lo_bits = self.rd_reg("LPGBT.RWF.VOLTAGE_DAC.VOLDACVALUE_0TO7") hi_bits = self.rd_reg("LPGBT.RWF.VOLTAGE_DAC.VOLDACVALUE_8TO11") + else: + raise Exception("Invalid lpgbt version detected.") value = lo_bits | (hi_bits << 8) return value/4096*v_ref diff --git a/tamalero/ReadoutBoard.py b/tamalero/ReadoutBoard.py index 1dd4074..1868a9f 100644 --- a/tamalero/ReadoutBoard.py +++ b/tamalero/ReadoutBoard.py @@ -349,35 +349,73 @@ class ReadoutBoard: else: raise RuntimeError(f"{link} link does not have a stable connection after {max_retries} retries") - def read_temp(self, verbose=0): - # high level function to read all the temperature sensors - - adc_7 = self.DAQ_LPGBT.read_adc(7)/(2**10-1) - adc_0 = self.DAQ_LPGBT.read_adc(0)/(2**10-1) - adc_in29 = self.SCA.read_adc(29)/(2**12-1) - v_ref = self.DAQ_LPGBT.read_dac() - t_SCA = self.SCA.read_temp() # internal temp from SCA + def read_vtrx_temp(self): + + # vtrx thermistors + current_vtrx = self.DAQ_LPGBT.set_current_dac_uA(600) + rt_vtrx_voltage = self.DAQ_LPGBT.read_adc(0)/(2**10-1) + + if self.ver == 1: + return -1.0 + elif self.ver == 2: + return get_temp_direct(rt_vtrx_voltage, current_vtrx, thermistor="NCP03XM102E05RL") # this comes from the lpGBT ADC (VTRX TH) + else: + raise Exception("Unknown lpgbt version") + + def read_rb_thermistor(self, rt): + + # read voltage reference; some temperature readings depend on it + v_ref = self.DAQ_LPGBT.read_dac() + if v_ref==0 and ((rt==1 and self.ver==1) or rt==2): + raise Exception("Read temperature called with VREF configured as 0V. VREF must be configured to read the temperatures.") + + if rt==1: + + if self.ver == 1: + # This uses the DAC output for current so just read the voltage + rt1_voltage = self.DAQ_LPGBT.read_adc(7)/(2**10-1) # FIXME: 7 should not be hardcoded + return get_temp(rt1_voltage, v_ref, 10000, 25, 10000, 3900) # this comes from the lpGBT ADC + elif self.ver == 2: + # Set the DAC current then read the voltage + current_rt1 = self.DAQ_LPGBT.set_current_dac_uA(50) + rt1_voltage = self.DAQ_LPGBT.read_adc(7)/(2**10-1) # FIXME: 7 should not be hardcoded + return get_temp_direct(rt1_voltage, current_rt1, thermistor="NTCG063JF103FTB") # this comes from the lpGBT ADC + else: + raise Exception("Unknown lpgbt version") + + elif rt==2: + + rt2_voltage = self.SCA.read_adc(29)/(2**12-1) # FIXME: 29 should not be hardcoded - if v_ref>0: if self.ver == 1: # https://www.digikey.com/en/products/detail/tdk-corporation/NTCG063UH103HTBX/8565486 - t1 = get_temp(adc_7, v_ref, 10000, 25, 10000, 3900) # this comes from the lpGBT ADC - t2 = get_temp(adc_in29, v_ref, 10000, 25, 10000, 3900) # this comes from the SCA ADC + return get_temp(rt2_voltage, v_ref, 10000, 25, 10000, 3900) # this comes from the SCA ADC elif self.ver == 2: # https://www.digikey.com/en/products/detail/tdk-corporation/NTCG063JF103FTB/5872743 - curr_dac = self.DAQ_LPGBT.rd_reg("LPGBT.RWF.CUR_DAC.CURDACSELECT")*900/256 - t1 = get_temp_direct(adc_7, curr_dac, thermistor="NTCG063JF103FTB") # this comes from the lpGBT ADC - t2 = get_temp(adc_in29, v_ref, 10000, 25, 10000, 3380) # this comes from the SCA ADC - t_VTRX = get_temp_direct(adc_0, curr_dac, thermistor="NCP03XM102E05RL") # this comes from the lpGBT ADC (VTRX TH) - - if verbose>0: - print ("\nV_ref is set to: %.3f V"%v_ref) - print ("\nTemperature on RB RT1 is: %.3f C"%t1) - print ("Temperature on RB RT2 is: %.3f C"%t2) - print ("Temperature on RB SCA is: %.3f C"%t_SCA) - print ("Temperature on RB VTRX is: %.3f C"%t_VTRX) + return get_temp(rt2_voltage, v_ref, 10000, 25, 10000, 3380) # this comes from the SCA ADC + else: + raise Exception("Unknown lpgbt version") + else: - print ("V_ref found to be 0. Exiting.") - return {'t_SCA': t_SCA} - return {'t1': t1, 't2': t2, 't_SCA': t_SCA, 't_VTRX': t_VTRX} + raise Exception(f"Attempt to read unknown thermistor {rt=}") + + def read_temp(self, verbose=False): + + """ + read all the temperature sensors + """ + + # internal temp from SCA + t_sca = self.SCA.read_temp() + t_vtrx = self.read_vtrx_temp() + t_rt1 = self.read_rb_thermistor(1) + t_rt2 = self.read_rb_thermistor(2) + + if verbose: + print ("\nTemperature on RB RT1 is: %.1f C" % t_rt1) + print ("Temperature on RB RT2 is: %.1f C" % t_rt2) + print ("Temperature on RB SCA is: %.1f C" % t_sca) + print ("Temperature on RB VTRX is: %.1f C" % t_vtrx) + + return {'t1': t_rt1, 't2': t_rt2, 't_SCA': t_sca, 't_VTRX': t_vtrx} diff --git a/tamalero/utils.py b/tamalero/utils.py index 490f742..e781d71 100644 --- a/tamalero/utils.py +++ b/tamalero/utils.py @@ -37,7 +37,7 @@ def get_temp(v_out, v_ref, r_ref, t_1, r_1, b, celcius=True): return -999 return t_2-delta_t -def get_temp_direct(v_out, curr_dac, thermistor="NTCG063JF103FTB", celcius=True): +def get_temp_direct(v_out, curr_dac, thermistor="NTCG063JF103FTB", celcius=True, verbose=False): """ Calculate the temperature of a thermistor, given the voltage measured on it. @@ -56,11 +56,12 @@ def get_temp_direct(v_out, curr_dac, thermistor="NTCG063JF103FTB", celcius=True) t = find_temp(np.log10(r_t)) delta_t = 0 if celcius else 273.15 - - print(f"Thermistor: {thermistor}") - print(f"Voltage: {v_out} \t Current: {curr_dac} uA") - print(f"Resistance: {r_t}") - print(f"Temperature: {t}") + + if verbose: + print(f"Thermistor: {thermistor}") + print(f"Voltage: {v_out} \t Current: {curr_dac} uA") + print(f"Resistance: {r_t}") + print(f"Temperature: {t}") return t+delta_t diff --git a/test_tamalero.py b/test_tamalero.py index 0c34aef..85d9bc8 100644 --- a/test_tamalero.py +++ b/test_tamalero.py @@ -189,7 +189,7 @@ if __name__ == '__main__': rb_0.DAQ_LPGBT.read_adcs(check=True) # High level reading of temperatures - temp = rb_0.read_temp(verbose=1) + temp = rb_0.read_temp(verbose=True) #------------------------------------------------------------------------------- # I2C Test -- GitLab From 33293d26e399e50de4365e09efd4512d7e57173b Mon Sep 17 00:00:00 2001 From: Andrew Peck <andrew.peck@cern.ch> Date: Tue, 11 Apr 2023 13:47:59 -0400 Subject: [PATCH 7/7] fix: disable calibration by default the calibration settings are not enabled automtically or at the right stage of running which is causing adc reads to fail --- tamalero/LPGBT.py | 2 +- tamalero/ReadoutBoard.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tamalero/LPGBT.py b/tamalero/LPGBT.py index 3203ea8..ff8f4f3 100644 --- a/tamalero/LPGBT.py +++ b/tamalero/LPGBT.py @@ -568,7 +568,7 @@ class LPGBT(RegParser): return self.rd_reg("LPGBT.RWF.CUR_DAC.CURDACSELECT") * 900/256.0 - def read_adc(self, channel, calibrate=True, convert=False): + def read_adc(self, channel, calibrate=False, convert=False): # ADCInPSelect[3:0] | Input # ------------------ |---------------------------------------- # 4'd0 | ADC0 (external pin) diff --git a/tamalero/ReadoutBoard.py b/tamalero/ReadoutBoard.py index 1868a9f..d1a1334 100644 --- a/tamalero/ReadoutBoard.py +++ b/tamalero/ReadoutBoard.py @@ -353,7 +353,7 @@ class ReadoutBoard: # vtrx thermistors current_vtrx = self.DAQ_LPGBT.set_current_dac_uA(600) - rt_vtrx_voltage = self.DAQ_LPGBT.read_adc(0)/(2**10-1) + rt_vtrx_voltage = self.DAQ_LPGBT.read_adc(0)/(2**10-1) # FIXME: 0 should not be hardcoded if self.ver == 1: return -1.0 -- GitLab