diff --git a/apsct_lib.py b/apsct_lib.py index f6b0a253c0ac22db4adb5591dc62e36731d618c4..332bf877730968c6f06a879d791cc8740d4388fd 100644 --- a/apsct_lib.py +++ b/apsct_lib.py @@ -30,9 +30,10 @@ I2CBUSNR = 5 sleep_time = 0.15 DEBUG = False + class ApsctClass: # - # Toplevel class that contrains all parts of the APSCT + # Toplevel class that contains all controllable parts of the APSCT # def __init__(self, frequency="200MHz"): self.status = False @@ -49,9 +50,9 @@ class ApsctClass: self.i2cswitch.append(I2cSwitch(address=addr, bus=APSCT_I2C.i2c_bus_unb)) self.apsct_id = ApsctId() - def read_IO_expanderis(self): + def read_io_expanderis(self): # - # Read both IO-Expander lines and pints on the screen + # Read both IO-Expander lines and prints status on the screen # i2c_addr = [0x20, 0x21] for addr in i2c_addr: @@ -64,32 +65,32 @@ class ApsctClass: def power(self, state): # - # Set power supply APSCTs in the give state + # Set power supply APSCT in the give state # # state is True: Power on # state is False: Power off # stri = "Power to {}".format(state) print(stri) - I2C_IO_device_A = I2C(0x20, BUSNR=I2CBUSNR) - I2C_IO_device_A.write_bytes(0x06, 0x2C) # '0' is output - I2C_IO_device_A.write_bytes(0x07, 0x00) # '0' is output - I2C_IO_device_B = I2C(0x21, BUSNR=I2CBUSNR) - I2C_IO_device_B.write_bytes(0x06, 0x2C) # '0' is output + i2c_io_device_a = I2C(0x20, BUSNR=I2CBUSNR) + i2c_io_device_a.write_bytes(0x06, 0x2C) # '0' is output, '1' is input + i2c_io_device_a.write_bytes(0x07, 0x00) # '0' is output, '1' is input + i2c_io_device_b = I2C(0x21, BUSNR=I2CBUSNR) + i2c_io_device_b.write_bytes(0x06, 0x2C) # '0' is output, '1' is input if state: - bits_to_set_A1 = 0x02 | (1 << APSCT_I2C.CS) | (0 << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) - bits_to_set_A2 = 0x04 - bits_to_set_B1 = 0x02 | (1 << APSCT_I2C.CS) | (0 << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) + bits_to_set_a1 = 0x02 | (1 << APSCT_I2C.CS) | (0 << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) + bits_to_set_a2 = 0x04 + bits_to_set_b1 = 0x02 | (1 << APSCT_I2C.CS) | (0 << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) else: - bits_to_set_A1 = 0x00 | (1 << APSCT_I2C.CS) | (0 << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) - bits_to_set_A2 = 0x00 - bits_to_set_B1 = 0x00 | (1 << APSCT_I2C.CS) | (0 << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) + bits_to_set_a1 = 0x00 | (1 << APSCT_I2C.CS) | (0 << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) + bits_to_set_a2 = 0x00 + bits_to_set_b1 = 0x00 | (1 << APSCT_I2C.CS) | (0 << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) if DEBUG: - stri = "Bits to reg 0 0x{0:x}".format(bits_to_set_A1) + stri = "Bits to reg 0 0x{0:x}".format(bits_to_set_a1) print(stri) - I2C_IO_device_A.write_bytes(0x02, bits_to_set_A1) - I2C_IO_device_A.write_bytes(0x03, bits_to_set_A2) - I2C_IO_device_B.write_bytes(0x02, bits_to_set_B1) + i2c_io_device_a.write_bytes(0x02, bits_to_set_a1) + i2c_io_device_a.write_bytes(0x03, bits_to_set_a2) + i2c_io_device_b.write_bytes(0x02, bits_to_set_b1) def set_apsct(self): # @@ -106,13 +107,14 @@ class ApsctClass: def check_apsct(self): # - # Check voltages, temp and lock on APSCT + # Check voltages, temperature and PLL-lock on APSCT # + # Return Result, True when OK, False in case of an error result = self.sensors.check_values() result = result & self.pps.check_timing() result = result & self.apsct_id.check_id() for i2c_switch in self.i2cswitch: - result = result & i2c_switch.check_switch(data=random.randint(0,2**8)) + result = result & i2c_switch.check_switch(data=random.randint(0, 2**8)) if self.frequency == "200MHz": self.pll_200.read_lock() lock = self.pll_200.lock @@ -128,7 +130,7 @@ class ApsctClass: class PllClass: # - # Toplevel class that contrains all parts of the PLL + # Toplevel class that contains all function to set the PLL # def __init__(self, frequency="200MHz"): self.status = False @@ -140,7 +142,7 @@ class PllClass: self.i2c_address = APSCT_I2C.PLL_200M self.dev_i2c_pll = I2C(self.i2c_address, BUSNR=I2CBUSNR) - def Write_byte_PLL(self, reg_address, wr_data): + def write_byte_pll(self, reg_address, wr_data): # # Write Byte to the PLL # @@ -158,21 +160,21 @@ class PllClass: self.dev_i2c_pll.write_bytes(0x02, 0x02 | (0x1 << APSCT_I2C.CS)) for bit in bit_array: for clk in range(2): - Write_data = 0x02 | (0 << APSCT_I2C.CS) | (clk << APSCT_I2C.SCLK) | (int(bit) << APSCT_I2C.SDI) - self.dev_i2c_pll.write_bytes(0x02, Write_data) + write_data = 0x02 | (0 << APSCT_I2C.CS) | (clk << APSCT_I2C.SCLK) | (int(bit) << APSCT_I2C.SDI) + self.dev_i2c_pll.write_bytes(0x02, write_data) for clk in range(2): - Write_data = 0x02 | (0 << APSCT_I2C.CS) | (clk << APSCT_I2C.SCLK) - self.dev_i2c_pll.write_bytes(0x02, Write_data) + write_data = 0x02 | (0 << APSCT_I2C.CS) | (clk << APSCT_I2C.SCLK) + self.dev_i2c_pll.write_bytes(0x02, write_data) for clk in range(2): - Write_data = 0x02 | (1 << APSCT_I2C.CS) | (clk << APSCT_I2C.SCLK) - self.dev_i2c_pll.write_bytes(0x02, Write_data) + write_data = 0x02 | (1 << APSCT_I2C.CS) | (clk << APSCT_I2C.SCLK) + self.dev_i2c_pll.write_bytes(0x02, write_data) - Write_data = 0x02 | (1 << APSCT_I2C.CS) | (0 << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) - self.dev_i2c_pll.write_bytes(0x02, Write_data) + write_data = 0x02 | (1 << APSCT_I2C.CS) | (0 << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) + self.dev_i2c_pll.write_bytes(0x02, write_data) - def Read_byte_PLL(self, reg_address, nof_bytes=1): + def read_byte_pll(self, reg_address, nof_bytes=1): # - # Read Byte from the PLL + # Read byte from the PLL # pll_rw = 0x01 # 0 for write, 1 for read self.dev_i2c_pll.write_bytes(0x06, 0x2C) @@ -180,21 +182,21 @@ class PllClass: bit_array = "{0:{fill}8b}".format(data, fill='0') for bit in bit_array: for clk in range(2): - Write_data = 0x02 | (0 << APSCT_I2C.CS) | (clk << APSCT_I2C.SCLK) | (int(bit) << APSCT_I2C.SDI) - self.dev_i2c_pll.write_bytes(0x02, Write_data) + write_data = 0x02 | (0 << APSCT_I2C.CS) | (clk << APSCT_I2C.SCLK) | (int(bit) << APSCT_I2C.SDI) + self.dev_i2c_pll.write_bytes(0x02, write_data) sleep(sleep_time) read_bit = '' for cnt in range(8*nof_bytes): for clk in [0, 1]: # Read after rizing edge - Write_data = 0x02 | (clk << APSCT_I2C.SCLK) | (int(bit_array[-1]) << APSCT_I2C.SDI) - self.dev_i2c_pll.write_bytes(0x02, Write_data) + write_data = 0x02 | (clk << APSCT_I2C.SCLK) | (int(bit_array[-1]) << APSCT_I2C.SDI) + self.dev_i2c_pll.write_bytes(0x02, write_data) ret_ack, ret_value = self.dev_i2c_pll.read_bytes(0x00, 1) if ret_ack: read_bit += str((int(ret_value, 16) >> APSCT_I2C.SDO) & 0x01) else: print("ACK nok") - Write_data = 0x02 | (1 << APSCT_I2C.CS) | (0 << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) - self.dev_i2c_pll.write_bytes(0x02, Write_data) + write_data = 0x02 | (1 << APSCT_I2C.CS) | (0 << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) + self.dev_i2c_pll.write_bytes(0x02, write_data) if DEBUG: stri = "Read back at address 0x{0:{fill}2x} result : 0x{1:{fill}2x} ".format(reg_address, int(read_bit, 2), fill='0') @@ -213,27 +215,27 @@ class PllClass: dev_i2c_pll_sel.write_bytes(0x03, 0x08) else: self.dev_i2c_pll.write_bytes(0x03, 0x28) - self.Write_byte_PLL(0x03, 0x0C) + self.write_byte_pll(0x03, 0x0C) sleep(0.5) - self.Write_byte_PLL(0x03, 0x08) - self.Write_byte_PLL(0x03, 0x08) - self.Write_byte_PLL(0x04, 0xCF) # CF disable not used outputs, 00 enable all - self.Write_byte_PLL(0x05, 0x97) - self.Write_byte_PLL(0x06, 0x10) # cp inv = 0xF4 other 0xE4 - self.Write_byte_PLL(0x07, 0x04) # Divider R = 1 dec - self.Write_byte_PLL(0x08, 0x01) - self.Write_byte_PLL(0x07, 0x00) - self.Write_byte_PLL(0x09, 0x10) # reset + self.write_byte_pll(0x03, 0x08) + self.write_byte_pll(0x03, 0x08) + self.write_byte_pll(0x04, 0xCF) # CF disable not used outputs, 00 enable all + self.write_byte_pll(0x05, 0x97) + self.write_byte_pll(0x06, 0x10) # cp inv = 0xF4 other 0xE4 + self.write_byte_pll(0x07, 0x04) # Divider R = 1 dec + self.write_byte_pll(0x08, 0x01) + self.write_byte_pll(0x07, 0x00) + self.write_byte_pll(0x09, 0x10) # reset if self.frequency == '160MHz': - self.Write_byte_PLL(0x0A, 0x10) + self.write_byte_pll(0x0A, 0x10) else: - self.Write_byte_PLL(0x0A, 0x14) - self.Write_byte_PLL(0x09, 0x00) - self.Write_byte_PLL(0x0C, 0x8F) - self.Write_byte_PLL(0x0D, 0x88) # Dig CLK = 200/1 = 200 MHz - self.Write_byte_PLL(0x0F, 0x08) # RCU CLK = 200/1 = 200 MHz - self.Write_byte_PLL(0x11, 0x08) # PPS ref CLK = 200/1 = 200 MHz - self.Write_byte_PLL(0x13, 0x88) # T.P. CLK = 200/1 = 200 MHz + self.write_byte_pll(0x0A, 0x14) + self.write_byte_pll(0x09, 0x00) + self.write_byte_pll(0x0C, 0x8F) + self.write_byte_pll(0x0D, 0x88) # Dig CLK = 200/1 = 200 MHz + self.write_byte_pll(0x0F, 0x08) # RCU CLK = 200/1 = 200 MHz + self.write_byte_pll(0x11, 0x08) # PPS ref CLK = 200/1 = 200 MHz + self.write_byte_pll(0x13, 0x88) # T.P. CLK = 200/1 = 200 MHz def read_all_regs_pll(self): # @@ -241,19 +243,18 @@ class PllClass: # self.dev_i2c_pll.write_bytes(0x07, 0x00) bytes_to_read = 24 - ret_value = self.Read_byte_PLL(0, nof_bytes=bytes_to_read) + ret_value = self.read_byte_pll(0, nof_bytes=bytes_to_read) for cnt in range(bytes_to_read): start = cnt*8 stri = "Reg nr 0x{:0>2x} value: 0x{:0>2x}".format(cnt, int(ret_value[start:start+8], 2)) print(stri) - def read_lock(self, PRINT_ON=True): + def read_lock(self, print_on=True): # # Read lock status # - ret_value = self.Read_byte_PLL(0x00, nof_bytes=1) + ret_value = self.read_byte_pll(0x00, nof_bytes=1) status_pll = int(ret_value, 2) - stri = "" if status_pll == 0x04: self.lock = True stri = f"PLL {self.frequency} is in lock" @@ -263,7 +264,7 @@ class PllClass: else: self.lock = False stri = f"PLL {self.frequency} Not locked --> PLL Error" - if PRINT_ON: + if print_on: print(stri) return self.lock @@ -271,24 +272,24 @@ class PllClass: # # Read loss of lock status # - I2C_IO_device_A = I2C(0x20, BUSNR=I2CBUSNR) - I2C_IO_device_A.write_bytes(0x06, 0x2C) # '0' is output - I2C_IO_device_A.write_bytes(0x07, 0x00) # '0' is output - I2C_IO_device_B = I2C(0x21, BUSNR=I2CBUSNR) - I2C_IO_device_B.write_bytes(0x06, 0x2C) # '0' is output - I2C_IO_device_B.write_bytes(0x07, 0xFF) # '0' is output + i2_c_io_device_a = I2C(0x20, BUSNR=I2CBUSNR) + i2_c_io_device_a.write_bytes(0x06, 0x2C) # '0' is output + i2_c_io_device_a.write_bytes(0x07, 0x00) # '0' is output + i2_c_io_device_b = I2C(0x21, BUSNR=I2CBUSNR) + i2_c_io_device_b.write_bytes(0x06, 0x2C) # '0' is output + i2_c_io_device_b.write_bytes(0x07, 0xFF) # '0' is output - ack, ret_value = I2C_IO_device_B.read_bytes(0x01, 1) + ack, ret_value = i2_c_io_device_b.read_bytes(0x01, 1) status_reg = int(ret_value, 16) if (self.frequency == '200MHz') & ((status_reg & 0x10) > 0): print("200MHz has lost lock") if ((status_reg & 0x20) > 0) & (self.frequency == '160MHz'): print("160MHz has last lock") - ack, ret_value = I2C_IO_device_A.read_bytes(0x01, 1) + ack, ret_value = i2_c_io_device_a.read_bytes(0x01, 1) old_reg = int(ret_value, 16) - I2C_IO_device_A.write_bytes(0x03, (old_reg | 0x10)) # '0' is output + i2_c_io_device_a.write_bytes(0x03, (old_reg | 0x10)) # '0' is output sleep(1) - I2C_IO_device_A.write_bytes(0x03, (old_reg & 0xEF)) # '0' is output + i2_c_io_device_a.write_bytes(0x03, (old_reg & 0xEF)) # '0' is output class EepromClass: @@ -296,13 +297,10 @@ class EepromClass: # Class to handle EEPROM communication # def __init__(self): - # - # All monitor. read and write functions for the EEPROM - # self.dev_i2c_eeprom = I2C(APSCT_I2C.EEPROM) self.dev_i2c_eeprom.bus_nr = I2CBUSNR - def write_eeprom(self, data="APSPU", address=0): + def write_eeprom(self, data="APSCT", address=0): # # Write the EEPROM with the serial number etc. # @@ -339,7 +337,7 @@ class EepromClass: str_return = ret_value.decode('UTF-8') return str_return - def wr_rd_eeprom(self, value="APSPU-1", address=0): + def wr_rd_eeprom(self, value="APSCT-1", address=0): # # Write and Read the EEPROM to check functionality # @@ -373,13 +371,25 @@ class ApsctSensors: self.temperature = 9999 self.dev_i2c_sensor.write_bytes(0xB0, 0xB8) - def apsct_sensors(self): + # + # read all 7 power sens lines + # + # Return True when done + # for sens_line in range(7): self.read_voltage(sens_line) self.read_temp() + return True def read_all_voltages(self): + # + # Function to read and process one sensline + # + # Return True when done + # + # To remove errors, repeat measurement when returned voltage is < 3 V + # for pwr in self.power_supplies: self.voltages[pwr] = self.read_voltage(APSCT_I2C.PWR_LOCATIONS[pwr]) if self.voltages[pwr] < 3: @@ -388,7 +398,7 @@ class ApsctSensors: def check_values(self): # - # Function to check sensor values + # Function to check sensor values (voltages and temperature) # # return result, True when OK, False in case of error # @@ -418,14 +428,14 @@ class ApsctSensors: # return value # voltage = 9999 - Vref = 3.0 - one_step = Vref/(2**16) + vref = 3.0 + one_step = vref/(2**16) channel_select_word = 0xB0 | ((input_channel % 2) << 3) | ((input_channel >> 1) & 0x7) if DEBUG: stri = "Word to select sens input is 0x{0:x}".format(channel_select_word) print(stri) self.dev_i2c_sensor.write_bytes(channel_select_word, 0xB8) - sleep(0.3) # Wait for device to take snapshot + sleep(0.3) # Wait for device to take snapshot ret_ack, ret_value = self.dev_i2c_sensor.read_last_reg(3) if DEBUG: stri = "Return value input 0 : 0x{0} ".format(ret_value) @@ -435,11 +445,11 @@ class ApsctSensors: else: steps = (int(ret_value, 16) & 0x1FFFFF) >> 6 voltage = one_step * steps - voltage = ((4.7+2.2)/2.2)*2*voltage # Resistor network + half swing + voltage = ((4.7+2.2)/2.2)*2*voltage # Resistor network + half swing if DEBUG: string = "Voltage sens line {1} is {0:.4f} V".format(voltage, input_channel) print(string) - sleep(0.2) # wait for device to go to sleep + sleep(0.2) # wait for device to go to sleep return voltage def read_temp(self): @@ -448,37 +458,42 @@ class ApsctSensors: # # return value # - Vref = 3.0 - temp_slope = 93.5E-6 * 2**(16+1) / Vref + vref = 3.0 + temp_slope = 93.5E-6 * 2**(16+1) / vref ret_ack = self.dev_i2c_sensor.write_bytes(0xA0, 0xC0) + if not ret_ack: + self.temperature = 9999 + return self.temperature sleep(0.5) self.temperature = 9999 loops = 0 - while (self.temperature > 100 ) & (loops < 2): + while (self.temperature > 100) & (loops < 2): loops = loops + 1 ret_ack, ret_value = self.dev_i2c_sensor.read_last_reg(3) if ret_ack: raw_value = (int(ret_value, 16) & 0x1FFFFF) >> 6 - temperature_K = (raw_value/temp_slope) - self.temperature = temperature_K-273 + temperature_k = (raw_value/temp_slope) + self.temperature = temperature_k-273 else: self.temperature = 9999 sleep(0.2) return self.temperature + class PpsClass: # - # Class to check the PPS signal + # Class to check the PPS signal on GPIO24 # def __init__(self): - # - # Whats needed to measure the toggle on GPIO24 - # gpio.setmode(gpio.BCM) gpio.setup(24, gpio.IN) self.pps_time = 999 + self.timing = False def time_pps(self): + # + # measure time between rising edges on (0.5Hz) PPS input + # gpio.wait_for_edge(24, gpio.RISING) a = time() gpio.wait_for_edge(24, gpio.RISING) @@ -487,6 +502,9 @@ class PpsClass: return self.pps_time def check_pps(self): + # + # Check is signal toggles PPS input within 5 second period + # gpio.add_event_detect(24, gpio.RISING) sleep(5) pps_ok = gpio.event_detected(24) @@ -494,37 +512,44 @@ class PpsClass: return pps_ok def print_pps(self): + # + # Print PPS period time on screen + # if self.check_pps(): print(f"Time between pps is {self.time_pps():4.2f} s") else: print("No PPS found") def check_timing(self): - print("Check pps timing", end = "" ) + # + # Check is time is 1 second +/- 10% + # + print("Check pps timing", end="") self.timing = False if not self.check_pps(): print(" no pps") return False timepps = self.time_pps() - if (0.9 < timepps < 1.1): + if 0.9 < timepps < 1.1: print(f", timing is OK: {timepps:4.2f} s") self.timing = True return self.timing + class I2cSwitch: # - # Class to check a I2C-switch + # Class to check a I2C-switch to RCU's and UNB2c's # def __init__(self, address=0x70, bus=1): - # - # Whats needed to measure the toggle on GPIO24 - # - self.address = address - self.bus = bus - self.dev_i2c_switch = I2C(address) + self.address = address # Address of the switch + self.bus = bus # I2C bus number on the Po + self.dev_i2c_switch = I2C(address) # I2C software device self.dev_i2c_switch.bus_nr = bus def check_switch(self, data=0xa5): + # + # Check if you can write and read from the buffer + # print(f"Check I2C switch at 0x{self.address:x} bus {self.bus}", end=' ') ret_ack, ret_value = self.dev_i2c_switch.read_bytes(0) if ret_ack < 1: @@ -544,27 +569,33 @@ class I2cSwitch: class ApsctId: # - # Class to check a I2C-switch + # Class to check ID pins # def __init__(self): # # APSCT Backplane ID # - self.id = 9999 - gpio.setmode(gpio.BCM) + self.id = 9999 # placeholder for APSCT-ID + gpio.setmode(gpio.BCM) # Set IO pins used for the APSCT-ID for pin in APSCT_I2C.ID_PINS: gpio.setup(pin, gpio.IN) def read_id(self): - id = 0 + # + # Function to read the APSCT-ID from the backplane + # + loc_id = 0 for pin in APSCT_I2C.ID_PINS: - id = id * 2 - bit = gpio.input(8) - id = id + bit + loc_id = loc_id * 2 + bit = gpio.input(pin) + loc_id = loc_id + bit self.id = id return self.id def check_id(self): + # + # Function Check the ID. + # self.read_id() if self.id == 63: print(f"OK : Back ID is 0x{self.id:02X}") @@ -572,4 +603,3 @@ class ApsctId: else: print(f"ERROR : Back ID is 0x{self.id:02X} expected 0x{63:2X}") return False - return True diff --git a/production_apsct.py b/production_apsct.py index c45becb4bc006b6dc901ef42d7bd5e3d7501f2c0..a55d7dee8a724aac5c2e082e8064f6bf59873a7f 100644 --- a/production_apsct.py +++ b/production_apsct.py @@ -17,7 +17,7 @@ Check APSCT_CLK import apsct_lib import sys -READ_ALL = False # True +READ_ALL = False # True CLK_FREQ = '200MHz' @@ -47,7 +47,7 @@ state = state & apsct.check_apsct() if READ_ALL: apsct.pll_200.read_all_regs_pll() apsct.pll_160.read_all_regs_pll() - apsct.read_IO_expanderis() + apsct.read_io_expanderis() if state: apsct_id = "APSCT-" + sys.argv[1]