diff --git a/APSCT_CLK_I2C.py b/APSCT_CLK_I2C.py index 99309c6c99b0140bf4499697e2c9cc513bf45d57..2aaf01438a39d4d548025366262d20011c089c7d 100644 --- a/APSCT_CLK_I2C.py +++ b/APSCT_CLK_I2C.py @@ -29,7 +29,7 @@ sleep_time = 0.15 SET_PLL = True READ_LOCK = True READ_ALL = False -CHECK_EEPROM = False +CHECK_EEPROM = True # False PWR_RST = False #True #False READ_SENSOR = False #True READ_REGS = False #True diff --git a/apsct_lib.py b/apsct_lib.py index 905bd98d3d0f75ac0d57d79da8f1fa5e2c288e6d..5e812283a69d9d0916e50d4fff70fe0207c3fb35 100644 --- a/apsct_lib.py +++ b/apsct_lib.py @@ -19,6 +19,7 @@ import APSCT_I2C import time import RPi.GPIO as gpio import random +import numpy as np sys.path.insert(0, '.') import os if os.name == "posix": @@ -27,7 +28,7 @@ else: from I2C_serial import * I2CBUSNR = 5 -sleep_time = 0.15 +sleep_time = 0.0001 DEBUG = False @@ -63,6 +64,12 @@ class ApsctClass: ret_value[1]) # [start+2:start]) print(stri) + def read_all_io_device_registers(self, device, registers=8): + print(f"Read IO-expander at register 0x{device.I2C_Address:X}") + for register in range(registers): + reg_content = device.read_bytes(register, 1) + print(f"Register {register} 0x{reg_content}") + def power(self, state): # # Set power supply APSCT in the give state @@ -73,24 +80,29 @@ class ApsctClass: stri = "Power to {}".format(state) print(stri) i2c_io_device_a = I2C(0x20, BUSNR=I2CBUSNR) + i2c_io_device_a.write_bytes(0x04, 0) # inversion off + i2c_io_device_a.write_bytes(0x05, 0) # inversion off 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(0x04, 0) # inversion off + i2c_io_device_b.write_bytes(0x05, 0) # inversion off i2c_io_device_b.write_bytes(0x06, 0x2C) # '0' is output, '1' is input + i2c_io_device_b.write_bytes(0x07, 0xFF) # '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_a2 = 0x08 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_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) - print(stri) + bits_to_set_b1 = 0x00 # | (1 << APSCT_I2C.CS) | (0 << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) 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) + if DEBUG: + self.read_all_io_device_registers(i2c_io_device_a) + self.read_all_io_device_registers(i2c_io_device_b) def set_apsct(self): # @@ -142,6 +154,23 @@ class PllClass: self.i2c_address = APSCT_I2C.PLL_200M self.dev_i2c_pll = I2C(self.i2c_address, BUSNR=I2CBUSNR) + def reset_interface(self): + # + # Reset the SPI interface + # + self.dev_i2c_pll.write_bytes(0x06, 0x2C) + sleep(0.01) + write_data = 0x02 | (0 << APSCT_I2C.CS) | (0 << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) + self.dev_i2c_pll.write_bytes(0x02, write_data) + for cnt in range(4): + for clk in [0, 1, 0]: + write_data = 0x02 | (0 << APSCT_I2C.CS) | (clk << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) + self.dev_i2c_pll.write_bytes(0x02, write_data) + sleep(sleep_time) + write_data = 0x02 | (1 << APSCT_I2C.CS) | (0 << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) + self.dev_i2c_pll.write_bytes(0x02, write_data) + sleep(0.01) + def write_byte_pll(self, reg_address, wr_data): # # Write Byte to the PLL @@ -150,122 +179,135 @@ class PllClass: if DEBUG: stri = "Write to address : 0x{1:{fill}2x} value 0x{0:{fill}2x}".format(wr_data, reg_address, fill='0') print(stri) - self.dev_i2c_pll.write_bytes(0x06, 0x2C) + rw_reg_pll = 0b00101101 # 1 is input + self.dev_i2c_pll.write_bytes(0x06, rw_reg_pll) rd_bytes = self.dev_i2c_pll.read_bytes(0x06, 1) if DEBUG: - stri = "IO expander wrote 0x{0:x}, read 0x{1}".format(0x2C, rd_bytes[1]) + stri = "IO expander wrote 0x{0:x}, read 0x{1}".format(rw_reg_pll, rd_bytes[1]) print(stri) - data = (reg_address << 9) + (pll_rw << 8) + wr_data - bit_array = "{0:{fill}16b}".format(data, fill='0') + nof_bytes = 1 + data = (pll_rw << 23) + ((nof_bytes-1) << 21) + (reg_address << 8) + wr_data + bit_array = "{0:{fill}24b}".format(data, fill='0') self.dev_i2c_pll.write_bytes(0x02, 0x02 | (0x1 << APSCT_I2C.CS)) for bit in bit_array: - for clk in range(2): + for clk in [0, 1, 0]: # 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) - 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) - 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) - + sleep(sleep_time) 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, print_value=False): # # Read byte from the PLL # pll_rw = 0x01 # 0 for write, 1 for read + read_bit = '' self.dev_i2c_pll.write_bytes(0x06, 0x2C) - data = (reg_address << 7) + pll_rw - bit_array = "{0:{fill}8b}".format(data, fill='0') + data = (pll_rw << 15) + ((nof_bytes-1) << 13) + reg_address + bit_array = "{0:{fill}16b}".format(data, fill='0') + if DEBUG: + print(f"Write data: {bit_array}") + write_data = 0x02 | (0 << APSCT_I2C.CS) | (0 << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) + self.dev_i2c_pll.write_bytes(0x02, write_data) + sleep(sleep_time) for bit in bit_array: - for clk in range(2): + for clk in [0, 1, 0]: 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 = '' + self.dev_i2c_pll.write_bytes(0x06, 0xAC) 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) + write_data = 0x02 | (0 << APSCT_I2C.CS) | (clk << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI) self.dev_i2c_pll.write_bytes(0x02, write_data) + sleep(sleep_time) 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") + if print_value: + print(f"Read bits {read_bit}") + self.dev_i2c_pll.write_bytes(0x06, 0x2C) 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') print(stri) - return read_bit + return int(read_bit, 2) def setup_pll(self): # # Set registers on the PLL # print(f"Setup PPL {self.frequency}") - self.dev_i2c_pll.write_bytes(0x07, 0x00) + divider_r = 1 + divider_a = 1 + divider_p = 1 + divider_b = int((int(self.frequency[:-3]) * divider_r) / (10 * divider_p)) + if DEBUG: + print(f"Divider P : {divider_p}, Divider A : {divider_a}, Divider B : {divider_b}") + charge_pump_current = 3 # 0 is low (0.6 mA), 7 is high (4.8 mA) if self.frequency == '160MHz': + print("Select 160MHz clock") i2c_address = APSCT_I2C.PLL_200M dev_i2c_pll_sel = I2C(i2c_address, BUSNR=I2CBUSNR) dev_i2c_pll_sel.write_bytes(0x03, 0x08) else: self.dev_i2c_pll.write_bytes(0x03, 0x28) - 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 - if self.frequency == '160MHz': - 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(0x04, (divider_a & 0x3F)) + self.write_byte_pll(0x05, (divider_b & 0x1F00) >> 8) + self.write_byte_pll(0x06, (divider_b & 0x00FF)) + self.write_byte_pll(0x07, 0x00) # No LOR + self.write_byte_pll(0x08, 0x3B) # Charge pump normal + Status bit + self.write_byte_pll(0x09, (charge_pump_current & 0x7) << 4) + self.write_byte_pll(0x0A, 0x00) # Fixed Divide 1 + self.write_byte_pll(0x0B, 0x00) + self.write_byte_pll(0x0C, 0x01) + self.write_byte_pll(0x45, 0x00) # CLK2 as feedback clock input + self.write_byte_pll(0x3D, 0x08) # OUT0 ON LVDS Standard + self.write_byte_pll(0x3E, 0x0A) # OUT1 OFF + self.write_byte_pll(0x3F, 0x0A) # OUT2 OFF + self.write_byte_pll(0x40, 0x03) # OUT3 OFF + self.write_byte_pll(0x41, 0x02) # OUT4 ON LVDS Standard + self.write_byte_pll(0x4B, 0x80) # OUT0 bypass divider + self.write_byte_pll(0x4D, 0x80) # OUT1 bypass divider + self.write_byte_pll(0x4F, 0x80) # OUT2 bypass divider + self.write_byte_pll(0x51, 0x80) # OUT3 bypass divider + self.write_byte_pll(0x53, 0x80) # OUT4 bypass divider + self.write_byte_pll(0x5A, 0x0F) # Update registers def read_all_regs_pll(self): # # Read all registers on the PLL and print on screen # - self.dev_i2c_pll.write_bytes(0x07, 0x00) - bytes_to_read = 24 - ret_value = self.read_byte_pll(0, nof_bytes=bytes_to_read) + bytes_to_read = 90 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)) + ret_value = self.read_byte_pll(cnt, 1) + stri = f"Reg nr 0x{cnt:0>2x} value: 0x{ret_value:0>2x}" print(stri) - def read_lock(self, print_on=True): + def read_lock(self): # # Read lock status # - ret_value = self.read_byte_pll(0x00, nof_bytes=1) - status_pll = int(ret_value, 2) - if status_pll == 0x04: + if (self.frequency == '200MHz'): + i2_c_io_device = I2C(0x20, BUSNR=I2CBUSNR) + else: + i2_c_io_device = I2C(0x21, BUSNR=I2CBUSNR) + i2_c_io_device.write_bytes(0x06, 0x2C) # '0' is output + i2_c_io_device.write_bytes(0x07, 0x00) # '0' is output + ack, ret_value = i2_c_io_device.read_bytes(0x00, 1) + status_pll = int(ret_value, 16) & 0x04 + if status_pll: self.lock = True stri = f"PLL {self.frequency} is in lock" - elif (status_pll & 0x10) > 0: - self.lock = False - stri = f"PLL {self.frequency} Not Locked --> No 10 MHz ref" else: self.lock = False - stri = f"PLL {self.frequency} Not locked --> PLL Error" - if print_on: - print(stri) + stri = f"PLL {self.frequency} is not locked" + print(stri) return self.lock def read_lol(self): @@ -278,13 +320,14 @@ class PllClass: 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 = 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") + if self.frequency == '200MHz': + lol = (status_reg & 0x10) + else: + lol = (status_reg & 0x20) + if lol: + print(f"{self.frequency} has lost lock") ack, ret_value = i2_c_io_device_a.read_bytes(0x01, 1) old_reg = int(ret_value, 16) i2_c_io_device_a.write_bytes(0x03, (old_reg | 0x10)) # '0' is output @@ -382,6 +425,33 @@ class ApsctSensors: self.read_temp() return True + def read_all_avg_voltages(self, avg_nr=6): + # + # Function to read and process one sensline + # + # Return True when done + # + # To remove errors, repeat measurement when returned voltage is < 3 V + # + self.read_all_voltages() + sum_values = {"INPUT": [], + "PLL_160M": [], + "PLL_200M": [], + "DIST_A": [], + "DIST_B": [], + "DIST_C": [], + "DIST_D": [], + "CTRL": []} + for cnt in range(avg_nr): + self.read_all_voltages() + for pwr in self.power_supplies: + sum_values[pwr].append(self.voltages[pwr]) + for pwr in self.power_supplies: + median_value = np.median(sum_values[pwr]) + if DEBUG: + print(f"Power {pwr} last value {self.voltages[pwr]:.2f} V median {median_value:.2f} V") + self.voltages[pwr] = median_value + def read_all_voltages(self): # # Function to read and process one sensline @@ -404,11 +474,11 @@ class ApsctSensors: # print("Check power sensor values") result = True - self.read_all_voltages() + self.read_all_avg_voltages() self.read_temp() for pwr in self.power_supplies: expected = APSCT_I2C.PWR_VOUT[pwr] - if not (0.9*expected < self.voltages[pwr] < 1.1*expected): + if not (0.8*expected < self.voltages[pwr] < 1.2*expected): result = False print(f"Error: {pwr: <9} expected: {expected} V read: {self.voltages[pwr]:4.2f} V") else: @@ -434,8 +504,9 @@ class ApsctSensors: 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 +# self.dev_i2c_sensor.write_bytes(channel_select_word, 0xB8) + self.dev_i2c_sensor.write_bytes(channel_select_word, 0x80) + sleep(0.2) # 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) @@ -443,7 +514,7 @@ class ApsctSensors: if int(ret_value, 16) >= 0xC00000: print("over range") else: - steps = (int(ret_value, 16) & 0x1FFFFF) >> 6 + steps = (int(ret_value, 16) & 0x1FFFFF) / 2**6 voltage = one_step * steps voltage = ((4.7+2.2)/2.2)*2*voltage # Resistor network + half swing if DEBUG: @@ -476,7 +547,7 @@ class ApsctSensors: self.temperature = temperature_k-273 else: self.temperature = 9999 - sleep(0.2) + sleep(0.2) return self.temperature @@ -603,3 +674,24 @@ class ApsctId: else: print(f"ERROR : Back ID is 0x{self.id:02X} expected 0x{63:2X}") return False + + +def main(): + apsct = ApsctClass() + if False: + apsct.power(False) + sleep(1) + apsct.power(True) + sleep(1) + if False: + apsct.pll_200.write_byte_pll(0x06, 0xA5) + apsct.pll_200.write_byte_pll(0x5A, 0x01) + apsct.pll_200.setup_pll() + apsct.pll_200.read_lol() + apsct.pll_200.read_lock() +# apsct.pll_200.read_all_regs_pll() + apsct.sensors.check_values() + + +if __name__ == "__main__": + main() diff --git a/production_apsct.py b/production_apsct.py index a55d7dee8a724aac5c2e082e8064f6bf59873a7f..e74fc0a29ce924796cdcd2162f402031f594aea0 100644 --- a/production_apsct.py +++ b/production_apsct.py @@ -16,6 +16,7 @@ Check APSCT_CLK """ import apsct_lib import sys +import time READ_ALL = False # True @@ -33,6 +34,7 @@ for mode in modi: print(f"Check APSCT in {mode} mode") apsct.frequency = mode apsct.set_apsct() + time.sleep(1) if mode == "200MHz": state = state & apsct.pll_200.read_lock() if mode == "160MHz": @@ -40,6 +42,7 @@ for mode in modi: apsct.frequency = "200MHz" apsct.set_apsct() +time.sleep(1) apsct.pll_200.read_lock() apsct.sensors.apsct_sensors() state = state & apsct.check_apsct() @@ -55,6 +58,7 @@ if state: rw_ok = apsct.eeprom.wr_rd_eeprom(apsct_id, address=0) if rw_ok: rw_ok = apsct.eeprom.wr_rd_eeprom(serial, address=0x20) + print("APSCT tested successfully ") if not rw_ok: print("EEPROM Error") else: