Skip to content
Snippets Groups Projects
Commit 8ecf836e authored by Gijs Schoonderbeek's avatar Gijs Schoonderbeek
Browse files

Added test functionality, not tested on HW yet.

parent b7b9a175
Branches
No related tags found
1 merge request!3Apsct production
"""
Copyright 2022 Stichting Nederlandse Wetenschappelijk Onderzoek Instituten,
ASTRON Netherlands Institute for Radio Astronomy
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Created: 2022-12-07
This file contains the definitions of the APSPU registers etc.
"""
#
# I2C address, registers and ports for APSCT
# Created: 2023-01-06
#
#
# Power supplies
#
PWR_LOCATIONS = {"INPUT": 0,
"PLL_160M": 1,
"PLL_200M": 2,
"DIST_A": 3,
"DIST_B": 4,
"DIST_C": 5,
"DIST_D": 6,
"CTRL": 7}
PWR_VOUT = {"INPUT": 3.3,
"PLL_160M": 3.3,
"PLL_200M": 3.3,
"DIST_A": 3.3,
"DIST_B": 3.3,
"DIST_C": 3.3,
"DIST_D": 3.3,
"CTRL": 3.3}
#
# PLL constants / pin locations
#
CS = 6
SCLK = 4
SDO = 5
SDI = 7
PLL_200M = 0x20
PLL_160M = 0x21
#
# Central I2C Devices
#
EEPROM = 0x50
......@@ -15,6 +15,7 @@ Set APSCT_CLK
"""
import sys
import APSCT_I2C
import time
sys.path.insert(0, '.')
import os
......@@ -26,26 +27,17 @@ else:
I2CBUSNR = 5
sleep_time = 0.15
EEPROM = 0x50
PLL_200M = 0x20
PLL_160M = 0x21
CS = 6
SCLK = 4
SDO = 5
SDI = 7
class ApsctClass:
#
# Toplevel class that contrains all parts of the APSCT
#
def __init__(self):
def __init__(self, frequency="200MHz"):
self.status = False
self.frequency = frequency
self.eeprom = EepromClass()
self.pll_200 = PllClass(PLL_200M)
self.pll_160 = PllClass(PLL_160M)
self.pll_200 = PllClass("200MHz")
self.pll_160 = PllClass("160MHz")
self.sensors = ApsctSensors()
def read_IO_expanderis(self):
......@@ -76,13 +68,13 @@ class ApsctClass:
I2C_IO_device_B = I2C(0x21, BUSNR=I2CBUSNR)
I2C_IO_device_B.write_bytes(0x06, 0x2C) # '0' is output
if state:
bits_to_set_A1 = 0x02 | (1 << CS) | (0 << SCLK) | (0 << 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 << CS) | (0 << SCLK) | (0 << SDI)
bits_to_set_B1 = 0x02 | (1 << APSCT_I2C.CS) | (0 << APSCT_I2C.SCLK) | (0 << APSCT_I2C.SDI)
else:
bits_to_set_A1 = 0x00 | (1 << CS) | (0 << SCLK) | (0 << 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 << CS) | (0 << SCLK) | (0 << SDI)
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)
......@@ -90,32 +82,47 @@ class ApsctClass:
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, state):
def set_apsct(self):
#
# set APSCT to 200MHz, 160MHz or off
#
if state == "200MHz":
if self.frequency == "200MHz":
self.power(True)
self.pll_200.setup_pll()
elif state == "160MHz":
elif self.frequency == "160MHz":
self.power(True)
self.pll_160.setup_pll()
else:
self.power(False)
def check_apsct(self):
result = self.sensors.check_values()
if self.frequency == "200MHz":
self.pll_200.read_lock()
lock = self.pll_200.lock
result = result & lock
elif self.frequency == "160MHz":
self.pll_160.read_lock()
lock = self.pll_160.lock
result = result & lock
else:
result = result
return result
class PllClass:
#
# Toplevel class that contrains all parts of the PLL
#
def __init__(self, address=0x20):
def __init__(self, frequency="200MHz"):
self.status = False
self.i2c_address = address
self.dev_i2c_pll = I2C(self.i2c_address, BUSNR=I2CBUSNR)
if address == 0x20:
self.frequency = '200MHz'
self.lock = False
self.frequency = frequency
if self.frequency == "160MHz":
self.i2c_address = APSCT_I2C.PLL_160M
else:
self.frequency = '160MHz'
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):
#
......@@ -131,19 +138,19 @@ class PllClass:
print(stri)
data = (reg_address << 9) + (pll_rw << 8) + wr_data
bit_array = "{0:{fill}16b}".format(data, fill='0')
self.dev_i2c_pll.write_bytes(0x02, 0x02 | (0x1 << CS))
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 << CS) | (clk << SCLK) | (int(bit) << SDI)
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 << CS) | (clk << SCLK)
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 << CS) | (clk << SCLK)
Write_data = 0x02 | (1 << APSCT_I2C.CS) | (clk << APSCT_I2C.SCLK)
self.dev_i2c_pll.write_bytes(0x02, Write_data)
Write_data = 0x02 | (1 << CS) | (0 << SCLK) | (0 << SDI)
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):
......@@ -156,21 +163,22 @@ 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 << CS) | (clk << SCLK) | (int(bit) << SDI)
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 << SCLK) | (int(bit_array[-1]) << SDI)
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) >> SDO) & 0x01)
read_bit += str((int(ret_value, 16) >> APSCT_I2C.SDO) & 0x01)
else:
print("ACK nok")
Write_data = 0x02 | (1 << CS) | (0 << SCLK) | (0 << SDI)
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)
......@@ -226,13 +234,19 @@ class PllClass:
ret_value = self.Read_byte_PLL(0x00, nof_bytes=1)
status_pll = int(ret_value, 2)
if status_pll == 0x04:
self.lock = True
if DEBUG:
print("PLL in lock")
elif (status_pll & 0x10) > 0:
self.lock = False
if DEBUG:
print("Not Locked --> No 10 MHz ref")
else:
self.lock = False
if DEBUG:
print("Not locked --> PLL Error")
def read_lol(self, pll_frequency='200MHz'):
def read_lol(self):
#
# Read loss of lock status
#
......@@ -245,9 +259,9 @@ class PllClass:
ack, ret_value = I2C_IO_device_B.read_bytes(0x01, 1)
status_reg = int(ret_value, 16)
if (pll_frequency == '200MHz') & ((status_reg & 0x10) > 0):
if (self.frequency == '200MHz') & ((status_reg & 0x10) > 0):
print("200MHz has lost lock")
if ((status_reg & 0x20) > 0) & (pll_frequency == '160MHz'):
if ((status_reg & 0x20) > 0) & (self.frequency == '160MHz'):
print("160MHz has last lock")
ack, ret_value = I2C_IO_device_A.read_bytes(0x01, 1)
old_reg = int(ret_value, 16)
......@@ -264,7 +278,7 @@ class EepromClass:
#
# All monitor. read and write functions for the EEPROM
#
self.dev_i2c_eeprom = I2C(EEPROM)
self.dev_i2c_eeprom = I2C(APSCT_I2C.EEPROM)
self.dev_i2c_eeprom.bus_nr = I2CBUSNR
def write_eeprom(self, data="APSPU", address=0):
......@@ -301,7 +315,6 @@ class EepromClass:
else:
ret_ack, ret_value = self.dev_i2c_eeprom.read_bytes(address, nof_bytes)
ret_value = bytes.fromhex(ret_value[:nof_bytes * 2])
#print(" ret value = {}".format(ret_value))
str_return = ret_value.decode('UTF-8')
return str_return
......@@ -334,12 +347,39 @@ class ApsctSensors:
#
self.dev_i2c_sensor = I2C(0x74)
self.dev_i2c_sensor.bus_nr = I2CBUSNR
self.power_supplies = list(APSCT_I2C.PWR_LOCATIONS.keys())
self.voltages = {}
self.temperature = 9999
def apsct_sensors(self):
for sens_line in range(7):
self.read_voltage(sens_line)
self.read_temp()
def read_all_voltages(self):
for pwr in self.power_supplies:
self.voltages[pwr] = self.read_voltage(APSCT_I2C.PWR_LOCATIONS[pwr])
return True
def check_values(self):
#
# Function to check sensor values
#
# return result, True when OK, False in case of error
#
result = True
self.read_all_voltages()
self.read_temp()
for pwr in self.power_supplies:
expected = APSCT_I2C.PWR_VOUT[pwr]
if 0.9*expected > self.voltages[pwr] > 1.1*expected:
result = False
print(f"Error {pwr} expected {expected} V read {self.voltages[pwr]} V")
if 15 > self.temperature > 50:
result = False
print(f"Error temperature read {self.temperature} °C")
return result
def read_voltage(self, input_channel=0):
#
# Function to read a voltages of APSCT
......@@ -347,6 +387,7 @@ class ApsctSensors:
# input_channel = sens port
# return value
#
voltage = 9999
Vref = 3.0
one_step = Vref/(2**16)
channel_select_word = 0xB0 | ((input_channel % 2) << 3) | ((input_channel >> 1) & 0x7)
......@@ -368,6 +409,7 @@ class ApsctSensors:
voltage = ((4.7+2.2)/2.2)*2*voltage
string = "Voltage sens line {1} is {0:.4f} V".format(voltage, input_channel)
print(string)
return voltage
def read_temp(self):
#
......@@ -384,9 +426,7 @@ class ApsctSensors:
if ret_ack:
raw_value = (int(ret_value, 16) & 0x1FFFFF) >> 6
temperature_K = (raw_value/temp_slope)
temperature = temperature_K-273
stri = "Temperature : {0:.2f} gr. C".format(temperature)
print(stri)
self.temperature = temperature_K-273
else:
print("Error reading tempeature")
self.temperature = 9999
return self.temperature
......@@ -11,49 +11,60 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Set APSCT_CLK
Check APSCT_CLK
"""
import time
import apsct_lib
import sys
DEBUG = False
SET_PLL = True
READ_LOCK = True
READ_ALL = True
CHECK_EEPROM = True
PWR_RST = False # True
READ_SENSOR = True
READ_REGS = False # True
CLK_FREQ = '200MHz'
apsct = apsct_lib.ApsctClass()
apsct.sensors.read_temp()
if len(sys.argv) < 2:
print("Production_apsct.py <ASTRON NR> <Serial number>")
print("e.g. python3 production_apsct.py 2023-01 1234")
exit()
if CHECK_EEPROM:
apsct.eeprom.wr_rd_eeprom()
apsct = apsct_lib.ApsctClass(CLK_FREQ)
if PWR_RST:
apsct.power(False)
time.sleep(10)
apsct.power(True)
if SET_PLL:
apsct.set_apsct(CLK_FREQ)
print*("Check APSCT in 200MHz mode")
apsct.frequency = "200MHz"
apsct.set_apsct()
apsct.pll_200.read_lock()
apsct.pll_200.read_lol()
apsct.pll_160.read_lock()
apsct.pll_160.read_lol()
apsct.sensors.apsct_sensors()
if READ_LOCK:
print*("Check APSCT in 160MHz mode")
apsct.frequency = "160MHz"
apsct.set_apsct()
apsct.pll_200.read_lock()
apsct.pll_200.read_lol()
apsct.pll_160.read_lock()
apsct.pll_160.read_lol()
apsct.sensors.apsct_sensors()
if READ_REGS:
apsct.pll_200.read_all_regs_pll()
print*("Check APSCT in off mode")
apsct.frequency = "OFF"
apsct.set_apsct()
apsct.pll_200.read_lock()
apsct.pll_200.read_lol()
apsct.pll_160.read_lock()
apsct.pll_160.read_lol()
apsct.sensors.apsct_sensors()
if READ_ALL:
apsct.pll_200.read_all_regs_pll()
# apsct.pll_160.read_all_regs_pll()
apsct.read_IO_expanderis()
if READ_SENSOR:
apsct.sensors.apsct_sensors()
apsct.pll_200.read_lol(CLK_FREQ)
if apsct.check_apsct():
apsct_id = "APSCT-" + sys.argv[1]
serial = sys.argv[2]
rw_ok = apsct.eeprom.wr_rd_eeprom(apsct_id, address=0)
if rw_ok:
rw_ok = apsct.eeprom.wr_rd_eeprom(serial, address=0x20)
if not rw_ok:
print("EEPROM Error")
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment