Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • Work_Gijs
  • master
2 results

Target

Select target project
  • lofar2.0/python_test_scripts
1 result
Select Git revision
  • Work_Gijs
  • master
2 results
Show changes

Commits on Source 27

...@@ -26,7 +26,7 @@ else: ...@@ -26,7 +26,7 @@ else:
DEBUG = False DEBUG = False
I2CBUSNR=5 I2CBUSNR=5
sleep_time = 0.15 sleep_time = 0.15
SET_PLL = False #True SET_PLL = True
READ_LOCK = True READ_LOCK = True
READ_ALL = False READ_ALL = False
CHECK_EEPROM = False CHECK_EEPROM = False
......
"""
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
#
# I2C switch addresses
#
i2c_switch_addr_rcu = [0x70, 0x71, 0x72, 0x73]
i2c_bus_rcu = 1
i2c_switch_addr_unb = [0x70]
i2c_bus_unb = 3
#
# ID Pins
#
ID_PINS = [8, 7, 12, 16, 20, 21]
#******************************************# """
# I2C address, registers and ports for UNB2c Copyright 2022 Stichting Nederlandse Wetenschappelijk Onderzoek Instituten,
# Created: 2021-05-11 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 APSPU
# Created: 2022-12-07
#
#
# General, Point of load converters # General, Point of load converters
################################### #
CTR_LBA = 0x3C CTR_LBA = 0x3C
CTR_RCU2_A = 0x3D CTR_RCU2_A = 0x3D
...@@ -18,14 +37,14 @@ VOUT_POLS = {"CTR_LBA" : 8.0, ...@@ -18,14 +37,14 @@ VOUT_POLS = {"CTR_LBA" : 8.0,
"CTR_RCU2_A": 5.60009765625, "CTR_RCU2_A": 5.60009765625,
"CTR_RCU2_D": 3.2998046875} "CTR_RCU2_D": 3.2998046875}
IOUT_POLS = {"CTR_LBA" : 0.45, IOUT_POLS = {"CTR_LBA": 0.2,
"CTR_RCU2_A" : 0.7, "CTR_RCU2_A": 0.6,
"CTR_RCU2_D" : 0.3} "CTR_RCU2_D": 0.2}
LP_VIN = 0x88 # LP_VIN = 0x88
LP_VOUT_MODE = 0x20 LP_VOUT_MODE = 0x20
LP_VOUT = 0x8B # LP_VOUT = 0x8B
LP_temp = 0x8D # LP_temp = 0x8D
LP_IOUT = 0x8C LP_IOUT = 0x8C
LP_VOUT_COMMAND = 0x21 LP_VOUT_COMMAND = 0x21
LP_VOUT_TRIM = 0x22 LP_VOUT_TRIM = 0x22
...@@ -37,15 +56,16 @@ LP_VOUT_UV_LIMIT = 0x44 ...@@ -37,15 +56,16 @@ LP_VOUT_UV_LIMIT = 0x44
LP_STORE_USER_ALL = 0x15 LP_STORE_USER_ALL = 0x15
LP_ON_OFF_CONFIG = 0x02 LP_ON_OFF_CONFIG = 0x02
LP_OPERATION = 0x01 LP_OPERATION = 0x01
LP_WRITE_PROTECT = 0x10
################################### LP_STORE_DEFAULT_ALL = 0x12
#
# Central I2C Devices # Central I2C Devices
################################### #
EEPROM = 0x50 EEPROM = 0x50
################################### #
# FAN speed # FAN speed
################################### #
MAX6620 = 0x29 MAX6620 = 0x29
REG_GLOBAL = 0x00 REG_GLOBAL = 0x00
...@@ -56,15 +76,20 @@ TACH_COUNT_FREQ = 8192 ...@@ -56,15 +76,20 @@ TACH_COUNT_FREQ = 8192
FAN_TACHS = 1 FAN_TACHS = 1
RUN_MONITOR = 0x02 RUN_MONITOR = 0x02
NOF_APS_FANS = 3 NOF_APS_FANS = 3
###################### #
# Functions # Functions
###################### #
# Calculate floating point value according PMBus lineair
def calc_lin_2bytes(data): def calc_lin_2bytes(data):
#
# Calculate floating point value according PMBus lineair
#
# input data (Byte array)
# return value (float)
#
expo = ((data[1] & 0xf8) >> 3) expo = ((data[1] & 0xf8) >> 3)
if expo == 1: if expo == 1:
expo = -7 expo = -7
...@@ -76,14 +101,17 @@ def calc_lin_2bytes(data): ...@@ -76,14 +101,17 @@ def calc_lin_2bytes(data):
output = mantisse * 2**expo output = mantisse * 2**expo
return output return output
# Calculate floating point value according PMBus lineair
def calc_lin_3bytes(data, mode): def calc_lin_3bytes(data, mode):
#
# Calculate floating point value according PMBus lineair
#
# input data (Byte array)
# return value (float)
#
expo = (mode[0] & 0x1F) expo = (mode[0] & 0x1F)
if expo > 2**4: if expo > 2**4:
expo = expo - 2**5 expo = expo - 2**5
mant = (data[1]*256 + data[0]) mant = (data[1]*256 + data[0])
output = mant * 2**expo output = mant * 2**expo
return output return output
...@@ -42,15 +42,20 @@ class I2C: ...@@ -42,15 +42,20 @@ class I2C:
ret_ack = 1 ret_ack = 1
if SLOW: if SLOW:
sleep(0.2) sleep(0.2)
except IOError, err: except IOError:
ret_ack = 0 ret_ack = 0
ret_value = 'ffff' ret_value = 'ffff'
if DEBUG: if DEBUG:
print("Reading error") print("Reading error")
except err:
ret_ack = 0
ret_value = 'ffff'
if DEBUG:
print("Reading IO-error")
return ret_ack, ret_value return ret_ack, ret_value
def read_last_reg(self, bytes_to_read): def read_last_reg(self, bytes_to_read, print_on = DEBUG):
bus = smbus.SMBus(self.bus_nr) bus = smbus.SMBus(self.bus_nr)
rd_value = [] rd_value = []
ret_value = '' ret_value = ''
...@@ -60,10 +65,15 @@ class I2C: ...@@ -60,10 +65,15 @@ class I2C:
ret_ack = 1 ret_ack = 1
if SLOW: if SLOW:
sleep(0.2) sleep(0.2)
except IOError, err: except IOError:
ret_ack = 0 ret_ack = 0
rd_value.append(0) rd_value.append(0)
if DEBUG: if print_on:
print(f"Reading IOerror {rd_value}")
except err:
ret_ack = 0
rd_value.append(0)
if print_on:
print("Reading error") print("Reading error")
for cnt in range(bytes_to_read): for cnt in range(bytes_to_read):
ret_value += (hex(rd_value[cnt])[2:]) ret_value += (hex(rd_value[cnt])[2:])
...@@ -71,16 +81,23 @@ class I2C: ...@@ -71,16 +81,23 @@ class I2C:
def write_bytes(self, register, data): def write_bytes(self, register, data):
bus = smbus.SMBus(self.bus_nr) bus = smbus.SMBus(self.bus_nr)
if type(data) is not list:
data = [data]
try: try:
bus.write_i2c_block_data(self.I2C_Address, register, [data]) bus.write_i2c_block_data(self.I2C_Address, register, data)
ret_ack = 1 ret_ack = 1
if SLOW: if SLOW:
sleep(0.3) sleep(0.3)
except IOError, err: except IOError:
ret_ack = 0 ret_ack = 0
ret_value = 0 ret_value = 0
if DEBUG: if DEBUG:
print("Write error") print("Write error")
except err:
ret_ack = 0
ret_value = 0
if DEBUG:
print("Write IO-error")
return ret_ack return ret_ack
def write_register(self, register): def write_register(self, register):
...@@ -90,11 +107,16 @@ class I2C: ...@@ -90,11 +107,16 @@ class I2C:
ret_ack = 1 ret_ack = 1
if SLOW: if SLOW:
sleep(0.3) sleep(0.3)
except IOError, err: except IOError:
ret_ack = 0 ret_ack = 0
ret_value = 0 ret_value = 0
if DEBUG: if DEBUG:
print("Write error") print("Write error")
except err:
ret_ack = 0
ret_value = 0
if DEBUG:
print("Write IO-error")
return ret_ack return ret_ack
def write_pointer(self, register): def write_pointer(self, register):
...@@ -104,11 +126,16 @@ class I2C: ...@@ -104,11 +126,16 @@ class I2C:
ret_ack = 1 ret_ack = 1
if SLOW: if SLOW:
sleep(0.3) sleep(0.3)
except IOError, err: except IOError:
ret_ack = 0 ret_ack = 0
ret_value = 0 ret_value = 0
if DEBUG: if DEBUG:
print("Write error") print("Write error")
except err:
ret_ack = 0
ret_value = 0
if DEBUG:
print("Write IO-error")
return ret_ack return ret_ack
def ack_check(self): def ack_check(self):
...@@ -119,11 +146,16 @@ class I2C: ...@@ -119,11 +146,16 @@ class I2C:
ret_ack = 1 ret_ack = 1
if SLOW: if SLOW:
sleep(0.3) sleep(0.3)
except IOError, err: except IOError:
ret_ack = 0 ret_ack = 0
ret_value = 0 ret_value = 0
if DEBUG: if DEBUG:
print("No ACK") print("No ACK")
except err:
ret_ack = 0
ret_value = 0
if DEBUG:
print("No ACK IO-Error")
return ret_ack return ret_ack
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -97,7 +97,8 @@ class I2C: ...@@ -97,7 +97,8 @@ class I2C:
def write_pointer(self, register): def write_pointer(self, register):
bus = pi.i2c_open(self.bus_nr, self.I2C_Address) bus = pi.i2c_open(self.bus_nr, self.I2C_Address)
try: try:
pi.i2c_read_device(bus, 1) # pi.i2c_read_device(bus, 1)
pi.i2c_read_device(bus, register)
ret_ack = 1 ret_ack = 1
if SLOW: if SLOW:
sleep(0.3) sleep(0.3)
...@@ -109,6 +110,20 @@ class I2C: ...@@ -109,6 +110,20 @@ class I2C:
pi.i2c_close(bus) pi.i2c_close(bus)
return ret_ack return ret_ack
def write_register(self, register):
bus = pi.i2c_open(self.bus_nr, self.I2C_Address)
try:
ret_value = pi.i2c_write_device(bus, [register])
ret_ack = 1
if SLOW:
sleep(0.3)
except IOError:
ret_ack = 0
ret_value = 0
if DEBUG:
print("No ACK")
return ret_ack
def ack_check(self): def ack_check(self):
bus = smbus.SMBus(self.bus_nr) bus = smbus.SMBus(self.bus_nr)
try: try:
......
'''
Copyright 2021 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.
I2C_serial_Pi
Started by Gijs
Class for using the I2C bus of the I2C. This class is used for the
basic I2C scripts to read and write the RCU2, PCC etc.
'''
import smbus2
import sys
from time import *
DEBUG = False #True
SLOW = False
class I2C:
def __init__(self, ADDRESS='040',BUSNR=3):
self.I2C_Address = ADDRESS
self.bus_nr = BUSNR
def close(self):
bus = smbus2.SMBus(self.bus_nr)
bus.close()
return True
def open(self):
bus = smbus2.SMBus(self.bus_nr)
bus.open(self.bus_nr)
return True
def read_bytes(self, register, bytes_to_read=2):
bus = smbus2.SMBus(self.bus_nr)
try:
rd_value = bus.read_i2c_block_data(self.I2C_Address, register, bytes_to_read)
ret_value = ''
for cnt in range(bytes_to_read):
ret_value += (hex(rd_value[cnt])[2:])
ret_ack = 1
if SLOW:
sleep(0.2)
except IOError:
ret_ack = 0
ret_value = 'ffff'
if DEBUG:
print("Reading IO-error")
return ret_ack, ret_value
def read_last_reg(self, bytes_to_read):
bus = smbus2.SMBus(self.bus_nr)
rd_value = []
ret_value = ''
for cnt in range(bytes_to_read):
try:
rd_value.append(bus.read_byte(self.I2C_Address))
ret_ack = 1
if SLOW:
sleep(0.2)
except IOError:
ret_ack = 0
rd_value.append(0)
if DEBUG:
print("IO-Reading error")
for cnt in range(bytes_to_read):
ret_value += (hex(rd_value[cnt])[2:])
return ret_ack,ret_value
def write_bytes(self, register, data):
bus = smbus2.SMBus(self.bus_nr)
if type(data) is not list:
data = [data]
try:
bus.write_i2c_block_data(self.I2C_Address, register, data)
ret_ack = 1
if SLOW:
sleep(0.3)
except IOError:
ret_ack = 0
ret_value = 0
if DEBUG:
print("Write IO-error")
return ret_ack
def write_register(self, register):
bus = smbus2.SMBus(self.bus_nr)
try:
bus.write_byte(self.I2C_Address, register)
# print(f"Wrote {register:x}")
ret_ack = 1
if SLOW:
sleep(0.3)
except IOError:
ret_ack = 0
ret_value = 0
# if DEBUG:
print("Write IO-error")
return ret_ack
def write_pointer(self, register):
bus = smbus2.SMBus(self.bus_nr)
try:
ret_value = bus.read_i2c_block_data(self.I2C_Address, register, 1)
ret_ack = 1
if SLOW:
sleep(0.3)
except IOError:
ret_ack = 0
ret_value = 0
if DEBUG:
print("Write IO-error")
return ret_ack
def ack_check(self):
bus = smbus2.SMBus(self.bus_nr)
try:
print("check ACK")
ret_value = bus.write_quick(self.I2C_Address)
ret_ack = 1
if SLOW:
sleep(0.3)
except IOError:
ret_ack = 0
ret_value = 0
if DEBUG:
print("No ACK IO-Error")
return ret_ack
if __name__ == "__main__":
I2C_Device = I2C(0x40)
I2C_Device.write_bytes(0x00, 0x00)
ret_ack, ret_value = I2C_Device.read_bytes(0x8C, 2)
print(ret_value)
"""
Copyright 2021 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.
Set APSCT_CLK
"""
import sys
import APSCT_I2C
import time
import RPi.GPIO as gpio
import random
sys.path.insert(0, '.')
import os
if os.name == "posix":
from I2C_serial_pi2 import *
else:
from I2C_serial import *
I2CBUSNR = 5
sleep_time = 0.15
DEBUG = False
class ApsctClass:
#
# Toplevel class that contains all controllable parts of the APSCT
#
def __init__(self, frequency="200MHz"):
self.status = False
self.frequency = frequency
self.eeprom = EepromClass()
self.pll_200 = PllClass("200MHz")
self.pll_160 = PllClass("160MHz")
self.sensors = ApsctSensors()
self.pps = PpsClass()
self.i2cswitch = []
for addr in APSCT_I2C.i2c_switch_addr_rcu:
self.i2cswitch.append(I2cSwitch(address=addr, bus=APSCT_I2C.i2c_bus_rcu))
for addr in APSCT_I2C.i2c_switch_addr_unb:
self.i2cswitch.append(I2cSwitch(address=addr, bus=APSCT_I2C.i2c_bus_unb))
self.apsct_id = ApsctId()
def read_io_expanderis(self):
#
# Read both IO-Expander lines and prints status on the screen
#
i2c_addr = [0x20, 0x21]
for addr in i2c_addr:
i2c_device = I2C(addr, BUSNR=I2CBUSNR) # clock selection
for reg_cnt in range(8):
ack, ret_value = i2c_device.read_bytes(reg_cnt, 2)
stri = "Expander : 0x{:0>2x}, Reg 0x{:0>2x}, value 0x{}{}".format(addr, reg_cnt, ret_value[0],
ret_value[1]) # [start+2:start])
print(stri)
def power(self, 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, '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)
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)
if DEBUG:
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)
def set_apsct(self):
#
# set APSCT to 200MHz, 160MHz or off
#
if self.frequency == "200MHz":
self.power(True)
self.pll_200.setup_pll()
elif self.frequency == "160MHz":
self.power(True)
self.pll_160.setup_pll()
else:
self.power(False)
def check_apsct(self):
#
# 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))
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 contains all function to set the PLL
#
def __init__(self, frequency="200MHz"):
self.status = False
self.lock = False
self.frequency = frequency
if self.frequency == "160MHz":
self.i2c_address = APSCT_I2C.PLL_160M
else:
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):
#
# Write Byte to the PLL
#
pll_rw = 0x00 # 0 for write, 1 for read
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)
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])
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 << 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)
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)
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):
#
# Read byte from the PLL
#
pll_rw = 0x01 # 0 for write, 1 for read
self.dev_i2c_pll.write_bytes(0x06, 0x2C)
data = (reg_address << 7) + pll_rw
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)
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)
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)
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
def setup_pll(self):
#
# Set registers on the PLL
#
print(f"Setup PPL {self.frequency}")
self.dev_i2c_pll.write_bytes(0x07, 0x00)
if self.frequency == '160MHz':
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
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)
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):
#
# Read lock status
#
ret_value = self.read_byte_pll(0x00, nof_bytes=1)
status_pll = int(ret_value, 2)
if status_pll == 0x04:
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)
return self.lock
def read_lol(self):
#
# Read loss of lock status
#
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 = 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 = 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
sleep(1)
i2_c_io_device_a.write_bytes(0x03, (old_reg & 0xEF)) # '0' is output
class EepromClass:
#
# Class to handle EEPROM communication
#
def __init__(self):
self.dev_i2c_eeprom = I2C(APSCT_I2C.EEPROM)
self.dev_i2c_eeprom.bus_nr = I2CBUSNR
def write_eeprom(self, data="APSCT", address=0):
#
# Write the EEPROM with the serial number etc.
#
# Data = data to write in string formal
# Address = address to write the data to
# Return True if successfully
#
ret_ack, ret_value = self.dev_i2c_eeprom.read_bytes(0)
if ret_ack < 1:
print("EEPROM not found during write")
return False
else:
wr_data = bytearray(data.encode("utf-8", errors="ignore"))
for loc, data_byte in enumerate(wr_data):
self.dev_i2c_eeprom.write_bytes(address + loc, data_byte)
sleep(0.1)
return True
def read_eeprom(self, address=0, nof_bytes=5):
#
# Read the EEPROM with the serial number etc.
#
# Address = address to read from
# nof_bytes = number of bytes to read
# return string with the data from the flash
#
ret_ack, ret_value = self.dev_i2c_eeprom.read_last_reg(1)
if ret_ack < 1:
print("no EEPROM found during read")
return False
else:
ret_ack, ret_value = self.dev_i2c_eeprom.read_bytes(address, nof_bytes)
ret_value = bytes.fromhex(ret_value[:nof_bytes * 2])
str_return = ret_value.decode('UTF-8')
return str_return
def wr_rd_eeprom(self, value="APSCT-1", address=0):
#
# Write and Read the EEPROM to check functionality
#
# value = string with data to write
# address = address to write the data to
# return True if read back is same as write value
#
if self.write_eeprom(value, address=0):
ret_value = self.read_eeprom(address=0, nof_bytes=len(value))
print(ret_value)
stri = "Wrote to EEPROM register 0x{2:x} : {0}, Read from EEPROM: {1}".format(value, ret_value, address)
print(stri)
if ret_value == value:
return True
else:
return False
class ApsctSensors:
#
# All monitor. read and write functions for the voltage sensors on APSCT
#
def __init__(self):
#
# All monitor. read and write functions for the EEPROM
#
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
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:
self.voltages[pwr] = self.read_voltage(APSCT_I2C.PWR_LOCATIONS[pwr])
return True
def check_values(self):
#
# Function to check sensor values (voltages and temperature)
#
# return result, True when OK, False in case of error
#
print("Check power sensor values")
result = True
self.read_all_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):
result = False
print(f"Error: {pwr: <9} expected: {expected} V read: {self.voltages[pwr]:4.2f} V")
else:
print(f"OK : {pwr: <9} expected: {expected} V read: {self.voltages[pwr]:4.2f} V")
if not (15 < self.temperature < 50):
result = False
print(f"Error temperature read {self.temperature:4.2f} °C")
else:
print(f"OK temperature read {self.temperature:4.2f} °C")
return result
def read_voltage(self, input_channel=0):
#
# Function to read a voltages of APSCT
#
# 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)
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
ret_ack, ret_value = self.dev_i2c_sensor.read_last_reg(3)
if DEBUG:
stri = "Return value input 0 : 0x{0} ".format(ret_value)
print(stri)
if int(ret_value, 16) >= 0xC00000:
print("over range")
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
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
return voltage
def read_temp(self):
#
# Function to read temperature of APSCT
#
# return value
#
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):
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
else:
self.temperature = 9999
sleep(0.2)
return self.temperature
class PpsClass:
#
# Class to check the PPS signal on GPIO24
#
def __init__(self):
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)
b = time()
self.pps_time = (b-a)/2
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)
gpio.remove_event_detect(24)
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):
#
# 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:
print(f", timing is OK: {timepps:4.2f} s")
self.timing = True
return self.timing
class I2cSwitch:
#
# Class to check a I2C-switch to RCU's and UNB2c's
#
def __init__(self, address=0x70, bus=1):
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:
print("I2C-Switch not found")
return False
else:
self.dev_i2c_switch.write_bytes(0, data)
ret_ack, ret_value = self.dev_i2c_switch.read_last_reg(1)
read_value_int = int(ret_value, 16)
if read_value_int == data:
print(f"OK wrote 0x{data:02X} read back 0x{read_value_int:02X}")
return True
else:
print(f"ERROR wrote 0x{data:02X} read back 0x{read_value_int:02X}")
return False
class ApsctId:
#
# Class to check ID pins
#
def __init__(self):
#
# APSCT Backplane ID
#
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):
#
# Function to read the APSCT-ID from the backplane
#
loc_id = 0
for pin in APSCT_I2C.ID_PINS:
loc_id = loc_id * 2
bit = gpio.input(pin)
loc_id = loc_id + bit
self.id = loc_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}")
return True
else:
print(f"ERROR : Back ID is 0x{self.id:02X} expected 0x{63:2X}")
return False
...@@ -12,8 +12,8 @@ See the License for the specific language governing permissions and ...@@ -12,8 +12,8 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
Created: 2021-05-10 Created: 2022-17-12
This file contains the UniBoard2 class with all monitoring function. It can be used stand-alone to test it. This file contains the APSPU class with all monitoring function. It can be used stand-alone to test it.
""" """
...@@ -21,20 +21,21 @@ import sys ...@@ -21,20 +21,21 @@ import sys
sys.path.insert(0, '.') sys.path.insert(0, '.')
import os import os
import math import math
from APSPU_I2C import * from APSPU_I2C import *
if os.name == "posix": if os.name == "posix":
from I2C_serial_pi2 import * from I2C_serial_pi3 import *
else: else:
from I2C_serial import * from I2C_serial import *
I2CBUSNR = 1 # Bus used on the Pi
I2CBUSNR = 1 DEBUG = False # Set True to print debug information on the screen
DEBUG = False I_OK_MARGIN = 0.5 # I_error in Amps
class ApspuClass: class ApspuClass:
# #
# Class that contains all parts on a UniBoard2 # Toplevel Class that contains all parts on a APSU
# #
def __init__(self): def __init__(self):
self.status = False self.status = False
...@@ -46,7 +47,7 @@ class ApspuClass: ...@@ -46,7 +47,7 @@ class ApspuClass:
def read_all(self): def read_all(self):
# #
# Function to read all monitoring points of the UniBoard # Function to read all monitoring points of the APSPU
# #
print("--------- \nRead APSPU Status\n---------") print("--------- \nRead APSPU Status\n---------")
for pol in self.pols: for pol in self.pols:
...@@ -64,24 +65,41 @@ class ApspuClass: ...@@ -64,24 +65,41 @@ class ApspuClass:
return True return True
def set_pols(self): def set_pols(self):
#
# Function to set output voltage level on the APSPU
# Values are read from the APSPU_I2C
#
print("--------- \nProgram Pols\n---------") print("--------- \nProgram Pols\n---------")
for pol in self.pols: for pol in self.pols:
pol.set_vout_pol(VOUT_POLS[pol.name]) pol.set_vout_pol(VOUT_POLS[pol.name])
vout = pol.read_vout_set()
if not (0.9*VOUT_POLS[pol.name] < vout < 1.1*VOUT_POLS[pol.name]):
print(f"POL {pol.name:10} Error setting Vout, "
f"set to {VOUT_POLS[pol.name]} read back {vout}")
exit()
pol.set_vout_ov_limit_pol(1.2*VOUT_POLS[pol.name]) pol.set_vout_ov_limit_pol(1.2*VOUT_POLS[pol.name])
ov_out = pol.read_ov_limit()
if not (1.1*VOUT_POLS[pol.name] < ov_out < 1.3*VOUT_POLS[pol.name]):
print(f"POL {pol.name:10} Error setting output overvoltage"
f"set {1.2*VOUT_POLS[pol.name]} read back {ov_out}")
exit()
pol.set_on_off_config() pol.set_on_off_config()
if DEBUG: pol.on_off(True)
pol.read_vout_set()
pol.read_ov_limit()
pol.read_uv_limit()
pol.write_to_nvm() pol.write_to_nvm()
print("Done") print("Done")
def check_apspu(self): def check_apspu(self):
#
# Function to check values of read_all() Used during production
#
# Return True is OK, False if not OK
#
print("--------- \nCheck APSPU \n---------") print("--------- \nCheck APSPU \n---------")
check_ok = True check_ok = True
for pol in self.pols: for pol in self.pols:
check_ok = check_ok & pol.check_pol() check_ok = check_ok & pol.check_pol()
check_ok = check_ok & self.fans.check_fans() check_ok = check_ok & self.fans.check_fans()
check_ok = check_ok & self.eeprom.wr_rd_eeprom(value="PROD_CHECK", address=0x30)
if check_ok: if check_ok:
print("APSPU OK") print("APSPU OK")
else: else:
...@@ -89,6 +107,12 @@ class ApspuClass: ...@@ -89,6 +107,12 @@ class ApspuClass:
return check_ok return check_ok
def apspu_on_off(self, on): def apspu_on_off(self, on):
#
# Function to switch off the POLs on APSPU
# on = True to switch APSU on
# on = False to switch APSU off
# Return: always True
#
if on: if on:
print(f">> Switch APSPU ON") print(f">> Switch APSPU ON")
else: else:
...@@ -97,13 +121,14 @@ class ApspuClass: ...@@ -97,13 +121,14 @@ class ApspuClass:
pol.on_off(on) pol.on_off(on)
return True return True
class EepromClass: class EepromClass:
# #
# Class to handle EEPROM communication # Class to handle EEPROM communication
# #
def __init__(self): def __init__(self):
# #
# All monitoring points Point of Load DC/DC converter # All monitor. read and write functions for the EEPROM
# #
self.dev_i2c_eeprom = I2C(EEPROM) self.dev_i2c_eeprom = I2C(EEPROM)
self.dev_i2c_eeprom.bus_nr = I2CBUSNR self.dev_i2c_eeprom.bus_nr = I2CBUSNR
...@@ -112,6 +137,10 @@ class EepromClass: ...@@ -112,6 +137,10 @@ class EepromClass:
# #
# Write the EEPROM with the serial number etc. # Write the EEPROM with the serial number etc.
# #
# Data = data to write in string formal
# Address = address to write the data to
# Return True if successfully
#
ret_ack, ret_value = self.dev_i2c_eeprom.read_bytes(0) ret_ack, ret_value = self.dev_i2c_eeprom.read_bytes(0)
if ret_ack < 1: if ret_ack < 1:
print("EEPROM not found during write") print("EEPROM not found during write")
...@@ -127,6 +156,10 @@ class EepromClass: ...@@ -127,6 +156,10 @@ class EepromClass:
# #
# Read the EEPROM with the serial number etc. # Read the EEPROM with the serial number etc.
# #
# Address = address to read from
# nof_bytes = number of bytes to read
# return string with the data from the flash
#
ret_ack, ret_value = self.dev_i2c_eeprom.read_last_reg(1) ret_ack, ret_value = self.dev_i2c_eeprom.read_last_reg(1)
if ret_ack < 1: if ret_ack < 1:
print("no EEPROM found during read") print("no EEPROM found during read")
...@@ -140,11 +173,18 @@ class EepromClass: ...@@ -140,11 +173,18 @@ class EepromClass:
# #
# Write and Read the EEPROM to check functionality # Write and Read the EEPROM to check functionality
# #
# value = string with data to write
# address = address to write the data to
# return True if read back is same as write value
#
if self.write_eeprom(value, address=0): if self.write_eeprom(value, address=0):
ret_value = self.read_eeprom(address=0, nof_bytes=len(value)) ret_value = self.read_eeprom(address=0, nof_bytes=len(value))
stri = "Wrote to EEPROM register 0x{2:x} : {0}, Read from EEPROM: {1}".format(value, ret_value, address) stri = "Wrote to EEPROM register 0x{2:x} : {0}, Read from EEPROM: {1}".format(value, ret_value, address)
print(stri) print(stri)
if ret_value == value:
return True return True
else:
return False
class PolClass: class PolClass:
...@@ -170,16 +210,16 @@ class PolClass: ...@@ -170,16 +210,16 @@ class PolClass:
else: else:
self.status = True self.status = True
def read_vout_set(self): def read_vout_set(self):
# #
# Function to read the output voltage of the Point of Load DC/DC converter # Function to read the output voltage of the Point of Load DC/DC converter
# #
# Return: output value is of else 999
#
if self.status: if self.status:
ret_ack, raw_value = self.pol_dev.read_bytes(LP_VOUT_COMMAND, 2) ret_ack, raw_value = self.pol_dev.read_bytes(LP_VOUT_COMMAND, 2)
if len(raw_value) < 4: if len(raw_value) < 4:
raw_value = '0' + raw_value raw_value = '0' + raw_value
ret_value = []
ret_value = int(raw_value[2:], 16) * 2**8 ret_value = int(raw_value[2:], 16) * 2**8
ret_value += int(raw_value[:2], 16) ret_value += int(raw_value[:2], 16)
output_value = ret_value * 2**-11 output_value = ret_value * 2**-11
...@@ -193,6 +233,9 @@ class PolClass: ...@@ -193,6 +233,9 @@ class PolClass:
# #
# Function to set the output of the DC/DC converter # Function to set the output of the DC/DC converter
# #
# Return always I2C ack
#
ret_ack = False
if self.status: if self.status:
if DEBUG: if DEBUG:
ret_ack, raw_value = self.pol_dev.read_bytes(LP_ON_OFF_CONFIG, 1) ret_ack, raw_value = self.pol_dev.read_bytes(LP_ON_OFF_CONFIG, 1)
...@@ -204,17 +247,30 @@ class PolClass: ...@@ -204,17 +247,30 @@ class PolClass:
default_off = 1 << 4 default_off = 1 << 4
wr_data = on_off_bit + polarity_pin + use_external + use_soft + default_off wr_data = on_off_bit + polarity_pin + use_external + use_soft + default_off
ret_ack = self.pol_dev.write_bytes(LP_ON_OFF_CONFIG, wr_data) ret_ack = self.pol_dev.write_bytes(LP_ON_OFF_CONFIG, wr_data)
return True return ret_ack
def on_off(self, on=True): def on_off(self, on=True):
#
# Function to switch on or off a POL
#
# if on = True switch on the POL
# if on = Flase swtich off the POL
# Return I2C ack
#
wr_data = (on << 7) + 0 wr_data = (on << 7) + 0
ret_ack = self.pol_dev.write_bytes(LP_OPERATION, wr_data) ret_ack = self.pol_dev.write_bytes(LP_OPERATION, wr_data)
return ret_ack
def set_vout_pol(self, value): def set_vout_pol(self, value):
# #
# Function to read the output voltage of the Point of Load DC/DC converter # Function to read the output voltage of the Point of Load DC/DC converter
# #
# value is the output voltage level in V
# return I2C ack
#
ret_ack = False
if self.status: if self.status:
ret_ack = self.pol_dev.write_bytes(LP_WRITE_PROTECT, [0])
set_value = int(value * (2**11)) set_value = int(value * (2**11))
hex_set_value = hex(set_value) hex_set_value = hex(set_value)
wr_value = (hex_set_value[4:6] + hex_set_value[2:4]) wr_value = (hex_set_value[4:6] + hex_set_value[2:4])
...@@ -224,12 +280,16 @@ class PolClass: ...@@ -224,12 +280,16 @@ class PolClass:
wr_data.append(int(hex_set_value[4:6], 16)) wr_data.append(int(hex_set_value[4:6], 16))
wr_data.append(int(hex_set_value[2:4], 16)) wr_data.append(int(hex_set_value[2:4], 16))
ret_ack = self.pol_dev.write_bytes(LP_VOUT_COMMAND, wr_data) ret_ack = self.pol_dev.write_bytes(LP_VOUT_COMMAND, wr_data)
return True return ret_ack
def set_vout_ov_limit_pol(self, value): def set_vout_ov_limit_pol(self, value):
# #
# Function to read the output voltage of the Point of Load DC/DC converter # Function to read the output voltage of the Point of Load DC/DC converter
# #
# value is the overvoltage level of the output
# return I2C ack
#
ret_ack = False
if self.status: if self.status:
set_value = int(value * (2**11)) set_value = int(value * (2**11))
hex_set_value = hex(set_value) hex_set_value = hex(set_value)
...@@ -240,10 +300,24 @@ class PolClass: ...@@ -240,10 +300,24 @@ class PolClass:
wr_data.append(int(hex_set_value[4:6], 16)) wr_data.append(int(hex_set_value[4:6], 16))
wr_data.append(int(hex_set_value[2:4], 16)) wr_data.append(int(hex_set_value[2:4], 16))
ret_ack = self.pol_dev.write_bytes(LP_VOUT_OV_LIMIT, wr_data) ret_ack = self.pol_dev.write_bytes(LP_VOUT_OV_LIMIT, wr_data)
return True return ret_ack
def write_to_nvm(self): def write_to_nvm(self):
ret_ack = self.pol_dev.write_bytes(LP_STORE_USER_ALL, 0) #
# Function to write the POL's registers to NVM memory
#
# return is always True
#
print(f"Store to NVM for POL {self.name}")
if False:
ret_ack = self.pol_dev.write_register(0x15)
sleep(1)
else:
self.pol_dev.close()
command = f"i2cset -y 1 0x{CTR_POLS[self.name]:02X} 0x15 cp"
os.system(command)
os.system(command)
self.pol_dev.open()
return True return True
def read_vin(self): def read_vin(self):
...@@ -252,13 +326,17 @@ class PolClass: ...@@ -252,13 +326,17 @@ class PolClass:
# #
if self.status: if self.status:
ret_ack, raw_value = self.pol_dev.read_bytes(LP_VIN, 2) ret_ack, raw_value = self.pol_dev.read_bytes(LP_VIN, 2)
if not ret_ack:
self.iout=999
return False
if len(raw_value) < 4: if len(raw_value) < 4:
raw_value = '0' + raw_value raw_value = '0' + raw_value
ret_value = [] ret_value = []
ret_value.append(int(raw_value[:2], 16)) ret_value.append(int(raw_value[:2], 16))
ret_value.append(int(raw_value[2:], 16)) # * 2**8 ret_value.append(int(raw_value[2:], 16))
output_value = calc_lin_2bytes(ret_value) #ret_value * 2**-11 output_value = calc_lin_2bytes(ret_value)
self.vin = output_value self.vin = output_value
return True
def read_vout(self): def read_vout(self):
# #
...@@ -266,7 +344,13 @@ class PolClass: ...@@ -266,7 +344,13 @@ class PolClass:
# #
if self.status: if self.status:
ret_ack, vout_mod = self.pol_dev.read_bytes(LP_VOUT_MODE, 1) ret_ack, vout_mod = self.pol_dev.read_bytes(LP_VOUT_MODE, 1)
if not ret_ack:
self.vout=999
return False
ret_ack, raw_value = self.pol_dev.read_bytes(LP_VOUT, 2) ret_ack, raw_value = self.pol_dev.read_bytes(LP_VOUT, 2)
if not ret_ack:
self.vout=999
return False
vout_mod = int(vout_mod, 16) vout_mod = int(vout_mod, 16)
ret_value = [] ret_value = []
ret_value.append(int(raw_value[:2], 16)) ret_value.append(int(raw_value[:2], 16))
...@@ -275,27 +359,36 @@ class PolClass: ...@@ -275,27 +359,36 @@ class PolClass:
except: except:
ret_value.append(0) ret_value.append(0)
self.vout = calc_lin_3bytes(ret_value, [vout_mod]) self.vout = calc_lin_3bytes(ret_value, [vout_mod])
return True
else: else:
self.vout = 999 self.vout = 999
return False
def read_ov_limit(self): def read_ov_limit(self):
# #
# Function to read the output voltage of the Point of Load DC/DC converter # Function to read the output voltage of the Point of Load DC/DC converter
# and print on the screen
# #
# Return OV limit
#
output_value = 0
if self.status: if self.status:
ret_ack, raw_value = self.pol_dev.read_bytes(LP_VOUT_OV_LIMIT, 2) ret_ack, raw_value = self.pol_dev.read_bytes(LP_VOUT_OV_LIMIT, 2)
if len(raw_value) < 4: if len(raw_value) < 4:
raw_value = '0' + raw_value raw_value = '0' + raw_value
ret_value = []
ret_value = int(raw_value[2:], 16) * 2**8 ret_value = int(raw_value[2:], 16) * 2**8
ret_value += int(raw_value[:2], 16) ret_value += int(raw_value[:2], 16)
output_value = ret_value * 2**-11 output_value = ret_value * 2**-11
if DEBUG:
print(f"Output OV limit is set to: = {output_value:5.2f} V using hex value {raw_value}") print(f"Output OV limit is set to: = {output_value:5.2f} V using hex value {raw_value}")
return output_value
def read_uv_limit(self): def read_uv_limit(self):
# #
# Function to read the output voltage of the Point of Load DC/DC converter # Function to read the output voltage of the Point of Load DC/DC converter
# #
# Return UV limit if OK else False
#
if self.status: if self.status:
ret_ack, raw_value = self.pol_dev.read_bytes(LP_VOUT_UV_LIMIT, 2) ret_ack, raw_value = self.pol_dev.read_bytes(LP_VOUT_UV_LIMIT, 2)
if len(raw_value) < 4: if len(raw_value) < 4:
...@@ -304,10 +397,11 @@ class PolClass: ...@@ -304,10 +397,11 @@ class PolClass:
ret_value = int(raw_value[2:], 16) * 2**8 ret_value = int(raw_value[2:], 16) * 2**8
ret_value += int(raw_value[:2], 16) ret_value += int(raw_value[:2], 16)
output_value = ret_value * 2**-11 output_value = ret_value * 2**-11
if DEBUG:
print(f"Output UV limit is set to: = {output_value:5.2f} V using hex value {raw_value}") print(f"Output UV limit is set to: = {output_value:5.2f} V using hex value {raw_value}")
return output_value return output_value
else: else:
return 9999 return False
def read_iout(self): def read_iout(self):
# #
...@@ -346,6 +440,11 @@ class PolClass: ...@@ -346,6 +440,11 @@ class PolClass:
self.read_vin() self.read_vin()
def check_pol(self): def check_pol(self):
#
# Function to read all monitoring points of the Point of Load DC/DC converter
#
# Return True if OK, False if not OK
#
self.read_all() self.read_all()
self.on_off(on=True) self.on_off(on=True)
check_ok = False check_ok = False
...@@ -372,16 +471,16 @@ class PolClass: ...@@ -372,16 +471,16 @@ class PolClass:
check_ok = False check_ok = False
print(f"POL {self.name:10} TEMP not OK, expected {temp_low} C - {temp_high} C, measured {self.temp} C ") print(f"POL {self.name:10} TEMP not OK, expected {temp_low} C - {temp_high} C, measured {self.temp} C ")
return check_ok return check_ok
i_low = 0.75*IOUT_POLS[self.name] i_low = (1-I_OK_MARGIN)*IOUT_POLS[self.name]
i_high = 1.25*IOUT_POLS[self.name] i_high = (1+I_OK_MARGIN)*IOUT_POLS[self.name]
if i_low < self.iout < i_high: if i_low < self.iout < i_high:
check_ok = True check_ok = True
else: else:
check_ok = False check_ok = False
print(f"POL {self.name:10} Iout not OK, expected {i_low:4.2f} A - {i_high:4.2f} A, measured {self.iout:4.2f} A ") print(f"POL {self.name:10} Iout not OK,"
f" expected {i_low:4.2f} A - {i_high:4.2f} A, measured {self.iout:4.2f} A ")
return check_ok return check_ok
def print_status(self): def print_status(self):
# #
# Function to dump all monitoring points of the Point of Load DC/DC converter on the screen # Function to dump all monitoring points of the Point of Load DC/DC converter on the screen
...@@ -395,13 +494,14 @@ class PolClass: ...@@ -395,13 +494,14 @@ class PolClass:
print(stri) print(stri)
self.read_vout_set() self.read_vout_set()
class FanmonitorClass: class FanmonitorClass:
# #
# Class to read all monitoring points Point of Load DC/DC converter # Class to read all monitoring points fan units in the APS
# #
def __init__(self): def __init__(self):
# #
# All monitoring points Point of Load DC/DC converter # All monitoring points for the fans
# #
self.rpm = [] self.rpm = []
self.fanmonitor_dev = I2C(MAX6620) self.fanmonitor_dev = I2C(MAX6620)
...@@ -426,7 +526,8 @@ class FanmonitorClass: ...@@ -426,7 +526,8 @@ class FanmonitorClass:
self.fanmonitor_dev.write_bytes(REG_GLOBAL, RUN_MONITOR) self.fanmonitor_dev.write_bytes(REG_GLOBAL, RUN_MONITOR)
ret_ack, reg_after = self.fanmonitor_dev.read_bytes(REG_GLOBAL, 1) ret_ack, reg_after = self.fanmonitor_dev.read_bytes(REG_GLOBAL, 1)
if DEBUG: if DEBUG:
stri = "Reg at address 0x{0} before : {1} and after write action {2}".format(REG_GLOBAL, reg_before, reg_after) stri = "Reg at address 0x{0} before : {1} and after write action {2}"\
.format(REG_GLOBAL, reg_before, reg_after)
print(stri) print(stri)
fan_config_reg = int((math.log(TACH_PERIODS) / math.log(2))) << 5 fan_config_reg = int((math.log(TACH_PERIODS) / math.log(2))) << 5
for fan_cnt in range(NOF_APS_FANS): for fan_cnt in range(NOF_APS_FANS):
...@@ -436,13 +537,16 @@ class FanmonitorClass: ...@@ -436,13 +537,16 @@ class FanmonitorClass:
def read_fan(self, fan_nr): def read_fan(self, fan_nr):
# #
# Function to a single fan # Function to a single fan
# fan_nr is the fan to read ranging from 0 till 2
# return the speed of the fan
# #
if fan_nr > NOF_APS_FANS:
return 0
ret_ack, tach_msb = self.fanmonitor_dev.read_bytes(REG_TACH_MSP_REGS[fan_nr], 1) ret_ack, tach_msb = self.fanmonitor_dev.read_bytes(REG_TACH_MSP_REGS[fan_nr], 1)
tach_msb = int(tach_msb, 16) & 0xFF tach_msb = int(tach_msb, 16) & 0xFF
if tach_msb > 254:
if DEBUG :
tach_lsb = 255 tach_lsb = 255
tach = 99999 tach = 99999
if tach_msb > 254:
rpm = 0 rpm = 0
else: else:
ret_ack, tach_lsb = self.fanmonitor_dev.read_bytes(REG_TACH_LSP_REGS[fan_nr], 1) ret_ack, tach_lsb = self.fanmonitor_dev.read_bytes(REG_TACH_LSP_REGS[fan_nr], 1)
...@@ -463,6 +567,9 @@ class FanmonitorClass: ...@@ -463,6 +567,9 @@ class FanmonitorClass:
self.rpm.append(self.read_fan(fan_counter)) self.rpm.append(self.read_fan(fan_counter))
def check_fans(self): def check_fans(self):
#
# Function to check fan speeds
#
self.read_all() self.read_all()
check_ok = True check_ok = True
for cnt, speed in enumerate(self.rpm): for cnt, speed in enumerate(self.rpm):
......
"""
Copyright 2021 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.
Check APSCT_CLK
"""
import apsct_lib
import sys
READ_ALL = False # True
CLK_FREQ = '200MHz'
if len(sys.argv) < 2:
print("Production_apsct.py <ASTRON NR> <Serial number>")
print("e.g. python3 production_apsct.py 2023-01 1234")
exit()
apsct = apsct_lib.ApsctClass(CLK_FREQ)
state = True
modi = ["200MHz", "160MHz", "OFF"]
for mode in modi:
print(f"Check APSCT in {mode} mode")
apsct.frequency = mode
apsct.set_apsct()
if mode == "200MHz":
state = state & apsct.pll_200.read_lock()
if mode == "160MHz":
state = state & apsct.pll_160.read_lock()
apsct.frequency = "200MHz"
apsct.set_apsct()
apsct.pll_200.read_lock()
apsct.sensors.apsct_sensors()
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()
if state:
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")
else:
print("\n >>> Errors during testing <<<\n")
""" """
Copyright 2021 Stichting Nederlandse Wetenschappelijk Onderzoek Instituten, Copyright 2022 Stichting Nederlandse Wetenschappelijk Onderzoek Instituten,
ASTRON Netherlands Institute for Radio Astronomy ASTRON Netherlands Institute for Radio Astronomy
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
...@@ -12,17 +12,15 @@ See the License for the specific language governing permissions and ...@@ -12,17 +12,15 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
Created: 2021-05-10 Created: 2022-12-07
This file contains the UniBoard2 class with all monitoring function. It can be used stand-alone to test it. This file contains the APSPU production script.
""" """
import sys import sys
sys.path.insert(0, '.') sys.path.insert(0, '.')
import os
import math
from apspu_lib import *
from apspu_lib import *
if len(sys.argv) < 2: if len(sys.argv) < 2:
...@@ -32,20 +30,18 @@ if len(sys.argv)<2: ...@@ -32,20 +30,18 @@ if len(sys.argv)<2:
apspu = ApspuClass() apspu = ApspuClass()
apspu.apspu_on_off(False) apspu.apspu_on_off(False)
sleep(5) sleep(5) # Wait for outputs to be stable off
apspu.set_pols() apspu.set_pols()
x = input("Change dipswitches and press key to continue..") input("Change dipswitches and press key to continue..")
apspu.apspu_on_off(True) apspu.apspu_on_off(True)
sleep(10) sleep(5) # Wait for outputs to be stable on
apspu.read_all() apspu.read_all()
apspu.print_status() apspu.print_status()
if apspu.check_apspu(): if apspu.check_apspu():
apspu.apspu_on_off(False) apspu_id = "APSPU-" + sys.argv[1]
sleep(10)
apspu.read_all()
apspu.print_status()
apspu.apspu_on_off(True)
id = "APSPU-" + sys.argv[1]
serial = sys.argv[2] serial = sys.argv[2]
apspu.eeprom.wr_rd_eeprom(id, address=0) rw_ok = apspu.eeprom.wr_rd_eeprom(apspu_id, address=0)
apspu.eeprom.wr_rd_eeprom(serial, address=0x20) if rw_ok:
rw_ok = apspu.eeprom.wr_rd_eeprom(serial, address=0x20)
if not rw_ok:
print("EEPROM Error")