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

Merge branch 'apsct_production' into 'master'

Apsct production

See merge request !3
parents 9d5dc319 0388db4f
No related branches found
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
#
# 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]
......@@ -43,6 +43,11 @@ class I2C:
if SLOW:
sleep(0.2)
except IOError:
ret_ack = 0
ret_value = 'ffff'
if DEBUG:
print("Reading error")
except err:
ret_ack = 0
ret_value = 'ffff'
if DEBUG:
......@@ -50,7 +55,7 @@ class I2C:
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)
rd_value = []
ret_value = ''
......@@ -63,8 +68,13 @@ class I2C:
except IOError:
ret_ack = 0
rd_value.append(0)
if DEBUG:
print("IO-Reading error")
if print_on:
print(f"Reading IOerror {rd_value}")
except err:
ret_ack = 0
rd_value.append(0)
if print_on:
print("Reading error")
for cnt in range(bytes_to_read):
ret_value += (hex(rd_value[cnt])[2:])
return ret_ack,ret_value
......@@ -79,6 +89,11 @@ class I2C:
if SLOW:
sleep(0.3)
except IOError:
ret_ack = 0
ret_value = 0
if DEBUG:
print("Write error")
except err:
ret_ack = 0
ret_value = 0
if DEBUG:
......@@ -93,6 +108,11 @@ class I2C:
if SLOW:
sleep(0.3)
except IOError:
ret_ack = 0
ret_value = 0
if DEBUG:
print("Write error")
except err:
ret_ack = 0
ret_value = 0
if DEBUG:
......@@ -107,6 +127,11 @@ class I2C:
if SLOW:
sleep(0.3)
except IOError:
ret_ack = 0
ret_value = 0
if DEBUG:
print("Write error")
except err:
ret_ack = 0
ret_value = 0
if DEBUG:
......@@ -122,6 +147,11 @@ class I2C:
if SLOW:
sleep(0.3)
except IOError:
ret_ack = 0
ret_value = 0
if DEBUG:
print("No ACK")
except err:
ret_ack = 0
ret_value = 0
if DEBUG:
......
'''
"""
Copyright 2021 Stichting Nederlandse Wetenschappelijk Onderzoek Instituten,
ASTRON Netherlands Institute for Radio Astronomy
Licensed under the Apache License, Version 2.0 (the "License");
......@@ -13,9 +13,12 @@ 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":
......@@ -23,239 +26,417 @@ if os.name =="posix":
else:
from I2C_serial import *
DEBUG = False
I2CBUSNR = 5
sleep_time = 0.15
SET_PLL = True
READ_LOCK = True
READ_ALL = False
CHECK_EEPROM = False
PWR_RST = False #True #False
READ_SENSOR = False #True
READ_REGS = False #True
DEBUG = False
CLK_FREQ = '200MHz'
dev_i2c_eeprom = I2C(0x50)
dev_i2c_eeprom.bus_nr = I2CBUSNR
CS = 6
SCLK = 4
SDO = 5
SDI = 7
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)
PLL_200M = 0x20
PLL_160M = 0x21
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 Write_byte_PLL(reg_address, wr_data, ADDRESS=0x20):
def set_apsct(self):
#
# Write Byte to the ADC
# set APSCT to 200MHz, 160MHz or off
#
I2C_device = I2C(ADDRESS, BUSNR=I2CBUSNR)
PLL_rw = 0x00 # 0 for write, 1 for read
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)
I2C_device.write_bytes(0x06, 0x2C)
self.dev_i2c_pll.write_bytes(0x06, 0x2C)
rd_bytes = self.dev_i2c_pll.read_bytes(0x06, 1)
if DEBUG:
rd_bytes = I2C_device.read_bytes(0x06, 1)
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
data = (reg_address << 9) + (pll_rw << 8) + wr_data
bit_array = "{0:{fill}16b}".format(data, fill='0')
I2C_device.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)
I2C_device.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 << CS) | (clk << SCLK)
I2C_device.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 << CS) | (clk << SCLK)
I2C_device.write_bytes(0x02, Write_data)
Write_data = 0x02 | (1 << CS) | (0 << SCLK) | (0 << SDI)
I2C_device.write_bytes(0x02, Write_data)
if DEBUG:
read_bits = Read_byte_PLL(reg_address, nof_bytes=1, ADDRESS=ADDRESS)
# stri = "Bits written 0x{0:x} to register 0x{1:x} read from PLL are {2}".format(wr_data, reg_address, read_bits)
# print(stri)
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(reg_address, nof_bytes=1, ADDRESS=0x20 ):
def read_byte_pll(self, reg_address, nof_bytes=1):
#
# Read Byte from the ADC
# Read byte from the PLL
#
I2C_device = I2C(ADDRESS, BUSNR=I2CBUSNR)
PLL_rw = 0x01 # 0 for write, 1 for read
I2C_device.write_bytes(0x06, 0x2C)
data = ( reg_address << 7 ) + PLL_rw
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 << CS) | (clk << SCLK) | ( int(bit) << SDI)
I2C_device.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)
# print("read byte")
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) << SDI )
I2C_device.write_bytes(0x02, Write_data)
ret_ack, ret_value = I2C_device.read_bytes(0x00, 1)
# stri= "ret_value = {}".format(int(ret_value,16))
# print(stri)
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)
I2C_device.write_bytes(0x02, Write_data)
stri = "Read back at address 0x{0:{fill}2x} result : 0x{1:{fill}2x} ".format(reg_address, int(read_bit, 2), fill='0')
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 read_all_regs_pll(pll_frequency='200MHz') :
I2C_device = I2C(0x20, BUSNR=I2CBUSNR) #clock selection
I2C_device.write_bytes(0x07, 0x00)
if pll_frequency == '160MHz':
print("Read PLL 160 MHz")
pll_address = PLL_160M
# I2C_device.write_bytes(0x03, 0x0F)
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:
print("Read PLL 200 MHz")
pll_address=PLL_200M
# I2C_device.write_bytes(0x03, 0xF8)
# for reg_cnt in range(0x15):
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 = Read_byte_PLL(0, nof_bytes = bytes_to_read, ADDRESS=pll_address)
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_IO_expanderis():
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])
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 setup_pll(pll_frequency='200MHz') :
I2C_device = I2C(0x20, BUSNR=I2CBUSNR) #clock selection
I2C_device.write_bytes(0x07, 0x00)
if pll_frequency == '160MHz':
print("Set PLL to 160 MHz mode")
pll_address = PLL_160M
I2C_device.write_bytes(0x03, 0x08)
else:
print("Set PLL to 200 MHz mode")
pll_address=PLL_200M
I2C_device.write_bytes(0x03, 0x28)
Write_byte_PLL(0x03, 0x0C, pll_address)
sleep(0.5)
Write_byte_PLL(0x03, 0x08, pll_address)
Write_byte_PLL(0x03, 0x08, pll_address)
Write_byte_PLL(0x04, 0xCF, pll_address) # CF disable not used outputs, 00 enable all
Write_byte_PLL(0x05, 0x97, pll_address)
Write_byte_PLL(0x06, 0x10, pll_address) # cp inv = 0xF4 other 0xE4
Write_byte_PLL(0x07, 0x04, pll_address) # Divider R = 1 dec
Write_byte_PLL(0x08, 0x01, pll_address)
Write_byte_PLL(0x07, 0x00, pll_address)
Write_byte_PLL(0x09, 0x10, pll_address) # reset
if pll_frequency == '160MHz' :
Write_byte_PLL(0x0A, 0x10, pll_address)
else:
Write_byte_PLL(0x0A, 0x14, pll_address)
Write_byte_PLL(0x09, 0x00, pll_address)
Write_byte_PLL(0x0C, 0x8F, pll_address)
Write_byte_PLL(0x0D, 0x88, pll_address) # Dig CLK = 200/1 = 200 MHz
Write_byte_PLL(0x0F, 0x08, pll_address) # RCU CLK = 200/1 = 200 MHz
Write_byte_PLL(0x11, 0x08, pll_address) # PPS ref CLK = 200/1 = 200 MHz
Write_byte_PLL(0x13, 0x88, pll_address) # T.P. CLK = 200/1 = 200 MHz
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
def power(state):
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
if state:
bits_to_set_A1 = 0x02 | (1 << CS) | (0 << SCLK) | (0 << SDI)
bits_to_set_A2 = 0x04
bits_to_set_B1 = 0x02 | (1 << CS) | (0 << SCLK) | (0 << SDI)
else:
bits_to_set_A1 = 0x00 | (1 << CS) | (0 << SCLK) | (0 << SDI)
bits_to_set_A2 = 0x00
bits_to_set_B1 = 0x00 | (1 << CS) | (0 << SCLK) | (0 << 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)
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( data=0x01):
def write_eeprom(self, data="APSCT", address=0):
#
# Write the EEPROM with the serial number etc.
#
ret_ack, ret_value = dev_i2c_eeprom.read_bytes(0)
# 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:
dev_i2c_eeprom.write_bytes(0x00, data)
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():
def read_eeprom(self, address=0, nof_bytes=5):
#
# Read the EEPROM with the serial number etc.
#
ret_ack, ret_value = dev_i2c_eeprom.read_last_reg(1)
# 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 = dev_i2c_eeprom.read_bytes(0x00, 1)
return ret_value
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(value=0x34):
def wr_rd_eeprom(self, value="APSCT-1", address=0):
#
# Write and Read the EEPROM to check functionality
#
if write_eeprom(value):
ret_value = read_eeprom()
stri = "Wrote to EEPROM: 0x{0:X}, Read from EEPROM: 0x{1} ".format(value, ret_value)
# 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
def apsct_sensors():
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):
read_voltage(sens_line)
read_temp()
def read_voltage(input_channel=0):
addr = 0x74
Vref = 3.0
one_step = Vref/(2**(16))
I2C_device = I2C(addr, BUSNR=I2CBUSNR)
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)
sleep(0.1)
I2C_device.write_bytes(channel_select_word, 0xB8)
sleep(0.5)
ret_ack, ret_value = I2C_device.read_last_reg(3)
if 1: #ret_ack:
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)
......@@ -264,94 +445,161 @@ def read_voltage(input_channel=0):
else:
steps = (int(ret_value, 16) & 0x1FFFFF) >> 6
voltage = one_step * steps
voltage = ((4.7+2.2)/2.2)*2*voltage
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)
else:
stri = " No ACK on device 0x{0:x} ".format(addr)
print(stri)
sleep(0.2) # wait for device to go to sleep
return voltage
def read_temp():
Vref = 3.0
addr = 0x74
one_step = Vref/(2**(16))
I2C_device = I2C(addr, BUSNR=I2CBUSNR)
temp_slope = 93.5E-6 * 2**(16+1) / Vref
sleep(1.0)
I2C_device.write_bytes(0xA0, 0xC0)
sleep(1.0)
ret_ack, ret_value = I2C_device.read_last_reg(3)
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)
temperature = temperature_K-273
stri = "Temperature : {0:.2f} gr. C".format(temperature)
print(stri)
temperature_k = (raw_value/temp_slope)
self.temperature = temperature_k-273
else:
print("Error reading tempeature")
def read_lol(pll_frequency='200MHz'):
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
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):
print("lost lock 200MHz")
if ((status_reg & 0x20) > 0) & (pll_frequency=='160MHz'):
print("lost lock 160MHz")
ack, ret_value = I2C_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
sleep(1)
I2C_IO_device_A.write_bytes(0x03, (old_reg & 0xEF)) # '0' is output
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
#if READ_REGS:
# read_all_regs_pll(CLK_FREQ)
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
read_temp()
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")
if CHECK_EEPROM :
wr_rd_eeprom()
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
if PWR_RST :
power(False)
sleep(10)
power(True)
if SET_PLL :
setup_pll(CLK_FREQ)
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
if READ_LOCK:
if CLK_FREQ == '160MHz' :
pll_addr = PLL_160M
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:
pll_addr = PLL_200M
ret_value = Read_byte_PLL(0x00, nof_bytes = 1, ADDRESS=pll_addr)
status_pll = int(ret_value,2)
if status_pll == 0x04:
print("PLL in lock")
elif (status_pll & 0x10) > 0:
print("Not Locked --> No 10 MHz ref")
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("Not locked --> PLL Error")
print(f"ERROR wrote 0x{data:02X} read back 0x{read_value_int:02X}")
return False
if READ_REGS:
read_all_regs_pll(CLK_FREQ)
if READ_ALL:
read_all_regs_pll(CLK_FREQ)
read_IO_expanderis()
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)
if READ_SENSOR:
apsct_sensors()
read_lol(CLK_FREQ)
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
"""
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")
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment