Commit 88e9e820 authored by Richard R. Carrillo's avatar Richard R. Carrillo

added PTS tests for fmcdio5chttla board

parent 9a9c42ab
#!/bin/sh
LOGDIR=./log
mkdir -p $LOGDIR
sudo rm -fr $LOGDIR/pts*
serial=$1
if [ x$1 = x"" ]; then
echo -n "Please, input SERIAL number: "
read serial
fi
extra_serial=$2
if [ x$2 = x"" ]; then
echo -n "Please, input extra SERIAL number: "
read extra_serial
fi
if [ x$extra_serial = x"" ]; then
extra_serial=0000
fi
tmp=""
echo "--------------------------------------------------------------"
sudo ./pts.py -b FMC-DIO-5chTTLa -s $serial -e $extra_serial -t./test/fmcdio5chttla/python -l $LOGDIR 00 01 02 03 04 05
echo -n "Press enter to exit..."
read tmp
*******************************************************************************
FmcDIO5chTTLa's tests for TPS environment
*******************************************************************************
Seven Solutions S.L.
Author: Richard R. Carrillo <rcarrillo(AT)sevensols.com>
Licence: GPL v2 or later.
Website: http://www.ohwr.org
Website: http://www.sevensols.com
Last modifications: 1/4/2012
This batch of tests makes a connectivity test of the FmcDIO5chTTLa's components.
- test00: Check fmc-dio-5chttl board EEPROM and DAC presence and temperature-sensor operation
- test01: Check fmc-dio-5chttl-board LEDs (LEDs and LED circuit working)
- test02: Check fmc-dio-5chttl-board ports as output (port driver working, connector connectivity and LVDS to LVCMOS IC working)
- test03: Check fmc-dio-5chttl-board ports as inputs (DAC, LVDS comparator)
- test04: Check output-enable circuit of fmc-dio-5chttl-board ports
- test05: Check termination resistors of fmc-dio-5chttl-board ports
These tests are made to work stand-alone too. So, it is possible to execute each one using 'sudo ./test0x.py'
These tests are designed to use Python 2.7 or higher.
#!/usr/bin/python
# Author: Tomasz?
# Author (modifications): Richard Carrillo <rcarrillo(AT)sevensols.com>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
# Website: http://www.sevensols.com
# Last modifications: 1/4/2012
from i2c import *
class CDAC5578:
CMD_POWER_ON = 0x40
CMD_WRITE_CH = 0x30
CMD_SW_RESET = 0x70
CMD_LDAC_CTRL = 0x60
CMD_READ_REG = 0x10
def __init__(self, bus, addr):
""" Configure DAC """
self.bus = bus;
self.addr = addr;
self.cmd_out(self.CMD_SW_RESET, 0);
self.cmd_out(self.CMD_LDAC_CTRL, 0xff); # ignore LDAC pins
self.cmd_out(self.CMD_POWER_ON, 0x1f, 0xe0);
def cmd_out(self, cmd, data, data2 = 0):
""" Send a command to DAC which does not include answer """
self.bus.start(self.addr, True);
self.bus.write(cmd, False)
self.bus.write(data, False)
self.bus.write(data2, True)
def cmd_in(self, cmd):
""" Send a command to DAC which expects answer """
self.bus.start(self.addr, True)
self.bus.write(cmd, False)
self.bus.start(self.addr, False)
reg_val=self.bus.read(False)
self.bus.read(True)
return(reg_val)
def out(self, channel, data):
""" Set a value (data) to a specified DAC channel """
self.cmd_out(self.CMD_WRITE_CH | channel, data)
def rd_out(self, channel):
""" Return the value set to a specified DAC channel """
return(self.cmd_in(self.CMD_READ_REG | channel))
#!/usr/bin/python
# Author: Tomasz?
# Author (modifications): Richard Carrillo <rcarrillo(AT)sevensols.com>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
# Website: http://www.sevensols.com
# Last modifications: 1/4/2012
import rr
import struct
import time
import sys
from xwb_gpio import *
from i2c import *
from eeprom_24aa64 import *
from onewire import *
from ds18b20 import *
from cdac5578 import *
class CFmcDioError(Exception):
def __init__(self, bus_name, addr, msg):
self.error_msgs={CFmcDio.I2C_ADDR_EEPROM:"EEPROM (24AA64T)",
CFmcDio.I2C_ADDR_DAC:"DAC (DAC5578)"}
self.bus_name = bus_name
self.addr = addr
self.msg = msg
def __str__(self):
if self.bus_name == "FMC":
return self.msg + " in " + self.bus_name + ". Is the fmc-dio-5chttla correctly inserted into the carrier?"
elif self.bus_name == "I2C" and self.addr in self.error_msgs.keys():
return "I2C device %s at addr 0x%x produced the error: %s" %(self.error_msgs[self.addr], self.addr, self.msg)
else:
return "Error in "+self.bus_name+" bus. (Addr: "+hex(self.addr)+"): "+self.msg
class CFmcDio:
BASE_GPIO = 0x200
BASE_I2C = 0x100
BASE_ONEWIRE = 0x0
I2C_ADDR_DAC = 0x48
I2C_ADDR_EEPROM = 0x50
I2C_PRESCALER = 400
PIN_PRSNT = 30
GPIO_LED_TOP = 27
GPIO_LED_BOTTOM = 28
DAC_CHANNEL_CORRESP=[0,1,2,7,4,5]
def __init__(self, bus, base, init_devices):
""" fmc-dio-5chttla-board presence check, I2C devices response check and OneWire-device funct. init.
bus = host bus (PCIe, VME, etc...)
base = base address
init_devices = If it is True, I2C and OneWire devices are initialized and can then be used
"""
self.bus = bus
self.base = base
self.gpio = CGPIO(bus, base + self.BASE_GPIO)
if(not self.fmc_present()):
raise CFmcDioError("FMC", base, "DIOERR00: PRESENT line is not asserted")
if init_devices:
try:
self.i2c = COpenCoresI2C(bus, base + self.BASE_I2C, self.I2C_PRESCALER)
board_I2C_periph_addr=[self.I2C_ADDR_DAC,self.I2C_ADDR_EEPROM]
found_I2C_periph_addr=self.i2c.scan()
except I2CDeviceOperationError as e:
raise CFmcDioError("I2C", base, "DIOERR01: "+e.msg)
if not found_I2C_periph_addr:
raise CFmcDioError("I2C", base, "DIOERR02: No I2C device found")
for periph_addr in board_I2C_periph_addr:
if periph_addr not in found_I2C_periph_addr:
raise CFmcDioError("I2C", periph_addr, "DIOERR03: Device not found. Only "+str(len(found_I2C_periph_addr))+" I2C devices found")
try:
self.eeprom = C24AA64(self.i2c, self.I2C_ADDR_EEPROM);
except I2CDeviceOperationError as e:
raise CFmcDioError("I2C", self.I2C_ADDR_EEPROM, "DIOERR04: "+e.msg)
try:
self.dac = CDAC5578(self.i2c, self.I2C_ADDR_DAC);
except I2CDeviceOperationError as e:
raise CFmcDioError("I2C", self.I2C_ADDR_DAC, "DIOERR05: "+e.msg)
self.onewire = COpenCoresOneWire(self.bus, base + self.BASE_ONEWIRE, 624/2, 124/2)
self.ds1820 = CDS18B20(self.onewire, 0);
else:
self.i2c=None
self.onewire=None
self.dac=None
self.eeprom=None
self.ds1820=None
def fmc_present(self):
""" Return 1 if FMC PRESENT pin is asserted """
return not self.gpio.inp(self.PIN_PRSNT);
def set_dir(self, port, d):
""" Enable (d=1) or disable (d=0) the output of a specified port ([0-4]) """
self.gpio.outp(port * 4 + 1, not d)
def set_out(self, port, d):
""" Set the output value (d) of a specified port ([0-4]) """
self.gpio.outp(port * 4, d)
def set_term(self, port, d):
""" Enable (d=1) or disable (d=0) the termination resistor (50ohm)t of a specified port ([0-4]) """
self.gpio.outp(port * 4 + 2, d)
def get_in(self, port):
""" Return the input value of a specified port ([0-4]) """
return self.gpio.inp(port * 4)
def power(self, ins, clock):
pass
def set_led(self, led, state):
""" Changes the state of a specified fmc-dio-5chttla-board LED
led=[0,1]
state=[0=off,1=on]
"""
gpio_leds=[self.GPIO_LED_TOP, self.GPIO_LED_BOTTOM]
self.gpio.outp(gpio_leds[led],state)
#print "LED", gpio_leds[led], "set to", state
def set_in_threshold(self, port, threshold):
""" Configures a specified DAC channel (port) with a specified output value (threshold) """
if self.dac is not None:
# Saturation is done in order to eliminate residual calculation errors
if threshold>255:
threshold>255
if threshold<0:
threshold=0
try:
self.dac.out(self.DAC_CHANNEL_CORRESP[port], threshold)
except I2CDeviceOperationError as e:
raise CFmcDioError("I2C", self.I2C_ADDR_DAC, "DIOERR06: "+e.msg)
else:
raise CFmcDioError("I2C", self.base, "DIOERR07: Device not initialized")
def get_in_threshold(self, port):
""" Returns the DAC value set in a specified channel (port) """
if self.dac is not None:
try:
dacval=self.dac.rd_out(self.DAC_CHANNEL_CORRESP[port])
except I2CDeviceOperationError as e:
raise CFmcDioError("I2C", self.I2C_ADDR_DAC, "DIOERR08: "+e.msg)
return(dacval)
else:
raise CFmcDioError("I2C", self.base, "DIOERR07: Device not initialized")
def DACvalue2voltage(self, dacval):
""" Calculate the voltage corresponding to a specific DAC channel digital value """
return dacval/255*3.3
def DACvoltage2value(self, volt):
""" Calculate the DAC channel digital value corresponding to a specific voltage """
return int(volt/3.3*255+0.5) # +0.5 due to the int() truncation
def find_port_voltage(self,port,range_min,range_max):
""" Uses a binary search algorthm to find the voltage (DAC threshold) in a specified board port
port: number of fmc-dio-5chttla-board port [0-4]
range_max: high voltage limit of the range in which the threshold is expected to be found
range_min: low voltage limit
The range input parameters are specified just to increase the execution speed
"""
# Convert the range limits provided in volts to the corresponding digital DAC value
range_min=self.DACvoltage2value(range_min)
range_max=self.DACvoltage2value(range_max)
# check if the specified range_min is too restrictive
self.set_in_threshold(port,range_min)
time.sleep(0.010) # wait for the DAC output to stabilize
port_inp=self.get_in(port)
if port_inp:
range_low=range_min # correct provided range
else:
range_low=-1
# check if the specified range_max is too restrictive
self.set_in_threshold(port,range_max)
time.sleep(0.010) # wait for the DAC output to stabilize
port_inp=self.get_in(port)
if not port_inp:
range_high=range_max # correct provided range
else:
range_high=256
#print "L: {} H: {}".format(range_low,range_high)
while (range_high-range_low) > 1: # while thresold not found
range_mid=(range_low+range_high)/2 # integer arithmetics
self.set_in_threshold(port,range_mid)
time.sleep(0.010) # wait for the DAC output to stabilize
port_inp=self.get_in(port)
#print "DAC[{}]={}".format(range_mid,port_inp)
if port_inp: # DAC set to a value below the port input voltage
range_low=range_mid
else:
range_high=range_mid
return self.DACvalue2voltage((range_low+range_high)/2.0)
def get_unique_id(self):
""" Get the ID value of the OneWire IC DS1820 consisting in (crc:serial_number:family_code) """
if self.ds1820:
try:
return self.ds1820.read_serial_number()
except OneWireDeviceOperationError as e:
raise CFmcDioError("OneWire", self.base, "DIOERR09: "+e.msg)
else:
raise CFmcDioError("OneWire", self.base, "DIOERR10: Device not initialized")
def get_temp(self):
""" Returns a temperature value in Celsius degrees by means of the OneWire IC DS1820 """
if self.ds1820:
try:
serial_number = self.ds1820.read_serial_number()
temp=self.ds1820.read_temp(serial_number)
except OneWireDeviceOperationError as e:
raise CFmcDioError("OneWire", self.base, "DIOERR11: "+e.msg)
return temp
else:
raise CFmcDioError("OneWire", self.base, "DIOERR10: Device not initialized")
#spec = rr.Gennum()
#dio= CFmcDio(spec, 0x80000);
#print("S/N: %x" % dio.get_unique_id())
#print("Board temp: %d degC" % dio.get_temp());
#!/usr/bin/python
# Author: Tomasz?
# Author (modifications): Richard Carrillo <rcarrillo(AT)sevensols.com>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
# Website: http://www.sevensols.com
# Last modifications: 1/4/2012
import sys
import rr
import time
import onewire
class CDS18B20:
# ROM commands
ROM_SEARCH = 0xF0
ROM_READ = 0x33
ROM_MATCH = 0x55
ROM_SKIP = 0xCC
ROM_ALARM_SEARCH = 0xEC
# DS18B20 functions commands
CONVERT_TEMP = 0x44
WRITE_SCRATCHPAD = 0x4E
READ_SCRATCHPAD = 0xBE
COPY_SCRATCHPAD = 0x48
RECALL_EEPROM = 0xB8
READ_POWER_SUPPLY = 0xB4
FAMILY_CODE = 0x28
MIN_TEMPER = -55
MAX_TEMPER = 125
# Thermometer resolution configuration
RES = {'9-bit':0x0, '10-bit':0x1, '11-bit':0x2, '12-bit':0x3}
def __init__(self, onewire, port):
self.onewire = onewire
self.port = port
def read_serial_number(self):
#print('[DS18B20] Reading serial number')
self.onewire.reset(self.port)
#print('[DS18B20] Write ROM command %.2X') % self.ROM_READ
self.onewire.write_byte(self.port, self.ROM_READ)
family_code = self.onewire.read_byte(self.port)
if family_code != self.FAMILY_CODE:
raise onewire.OneWireDeviceOperationError("Invalid family code reported:"+hex(family_code)+" (expected:"+hex(self.FAMILY_CODE)+"). Wrong chip mounted?")
serial_number = 0
for i in range(6):
serial_number |= self.onewire.read_byte(self.port) << (i*8)
crc = self.onewire.read_byte(self.port)
#print('[DS18B20] Family code : %.2X') % family_code
#print('[DS18B20] Serial number: %.12X') % serial_number
#print('[DS18B20] CRC : %.2X') % crc
return ((crc<<56) | (serial_number<<8) | family_code)
def access(self, serial_number):
#print('[DS18B20] Accessing device')
self.onewire.reset(self.port)
#print('[DS18B20] Write ROM command %.2X') % self.ROM_MATCH
err = self.onewire.write_byte(self.port, self.ROM_MATCH)
#print serial_number
block = []
for i in range(8):
block.append(serial_number & 0xFF)
serial_number >>= 8
#print block
self.onewire.write_block(self.port, block)
def read_temp(self, serial_number):
#print('[DS18B20] Reading temperature')
self.access(serial_number)
#print('[DS18B20] Write function command %.2X') % self.CONVERT_TEMP
self.onewire.write_byte(self.port, self.CONVERT_TEMP)
time.sleep(0.9)
self.access(serial_number)
#print('[DS18B20] Write function command %.2X') % self.READ_SCRATCHPAD
self.onewire.write_byte(self.port, self.READ_SCRATCHPAD)
data = self.onewire.read_block(self.port, 9)
#for i in range(9):
# print('Scratchpad data[%1d]: %.2X') % (i, data[i])
temp = (data[1] << 8) | (data[0])
if temp & 0x1000:
temp = -0x10000 + temp
temp = temp/16.0
if temp < self.MIN_TEMPER or temp > self.MAX_TEMPER:
raise onewire.OneWireDeviceOperationError("Sensor reported an invalid temperature")
return temp
# Set temperature thresholds
# Configure thermometer resolution
#!/usr/bin/python
import sys
import rr
import time
import i2c
class C24AA64:
def __init__(self, i2c, i2c_addr):
self.i2c = i2c
self.i2c_addr = i2c_addr
def wr_data(self, mem_addr, data):
self.i2c.start(self.i2c_addr, True)
self.i2c.write((mem_addr >> 8), False)
self.i2c.write((mem_addr & 0xFF), False)
#print('24AA64:write: data lenght=%d')%(len(data))
for i in range(len(data)-1):
#print('24AA64:write: i=%d')%(i)
self.i2c.write(data[i],False)
i += 1
#print('24AA64:write:last i=%d')%(i)
self.i2c.write(data[i],True)
def rd_data(self, mem_addr, size):
self.i2c.start(self.i2c_addr, True)
self.i2c.write((mem_addr >> 8), False)
self.i2c.write((mem_addr & 0xFF), False)
self.i2c.start(self.i2c_addr, False)
data = []
#print('24AA64:read: data lenght=%d')%(size)
i=0
for i in range(size-1):
data.append(self.i2c.read(False))
#print('24AA64:read: i=%d')%(i)
i += 1
#print('24AA64:read:last i=%d')%(i)
data.append(self.i2c.read(True))
return data;
#!/usr/bin/python
import sys
import rr
import time
class I2CDeviceOperationError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return ("I2C Device produced the error: %s" %(msg))
class COpenCoresI2C:
# OpenCores I2C registers description
R_PREL = 0x0
R_PREH = 0x4
R_CTR = 0x8
R_TXR = 0xC
R_RXR = 0xC
R_CR = 0x10
R_SR = 0x10
CTR_EN = (1<<7)
CR_STA = (1<<7)
CR_STO = (1<<6)
CR_RD = (1<<5)
CR_WR = (1<<4)
CR_ACK = (1<<3)
SR_RXACK = (1<<7)
SR_TIP = (1<<1)
WAIT_TIME_OUT = 2
def wr_reg(self, addr, val):
self.bus.iwrite(0, self.base_addr + addr, 4, val)
def rd_reg(self,addr):
return self.bus.iread(0, self.base_addr + addr, 4)
# Function called during object creation
# bus = host bus (PCIe, VME, etc...)
# base_addr = I2C core base address
# prescaler = SCK prescaler, prescaler = (Fsys/(5*Fsck))-1
def __init__(self, bus, base_addr, prescaler):
self.bus = bus
self.base_addr = base_addr
self.wr_reg(self.R_CTR, 0)
#print("prescaler: %.4X") % prescaler
self.wr_reg(self.R_PREL, (prescaler & 0xff))
#print("PREL: %.2X") % self.rd_reg(self.R_PREL)
self.wr_reg(self.R_PREH, (prescaler >> 8))
#print("PREH: %.2X") % self.rd_reg(self.R_PREH)
self.wr_reg(self.R_CTR, self.CTR_EN)
#print("CTR: %.2X") % self.rd_reg(self.R_CTR)
if not(self.rd_reg(self.R_CTR) & self.CTR_EN):
raise I2CDeviceOperationError("I2C core is not enabled")
def wait_busy(self):
init_time=time.time()
while(self.rd_reg(self.R_SR) & self.SR_TIP):
if (time.time()-init_time) > self.WAIT_TIME_OUT:
raise I2CDeviceOperationError("Wait timeout")
def start(self, addr, write_mode):
#print('i2c:start: addr=%.2X')%addr
addr = addr << 1
#print('i2c:start: addr=%.2X')%addr
if(write_mode == False):
addr = addr | 1
#print('i2c:start: addr=%.2X')%addr
self.wr_reg(self.R_TXR, addr)
#print("R_TXR: %.2X") % self.rd_reg(self.R_TXR)
self.wr_reg(self.R_CR, self.CR_STA | self.CR_WR)
self.wait_busy()
if self.rd_reg(self.R_SR) & self.SR_RXACK:
raise I2CDeviceOperationError("Device ACK not received at the I2C message start")
def write(self, data, last):
self.wr_reg(self.R_TXR, data)
cmd = self.CR_WR
if(last):
cmd = cmd | self.CR_STO
self.wr_reg(self.R_CR, cmd)
self.wait_busy()
if(self.rd_reg(self.R_SR) & self.SR_RXACK):
raise I2CDeviceOperationError("No ACK upon write")
def read(self, last):
cmd = self.CR_RD
if(last):
cmd = cmd | self.CR_STO | self.CR_ACK
self.wr_reg(self.R_CR, cmd)
self.wait_busy()
return self.rd_reg(self.R_RXR)
def scan(self):
periph_addr = []
print "Addresses of I2C devices found:",
for i in range(0, 127):
addr = i << 1
# addr |= 1
self.wr_reg(self.R_TXR, addr)
self.wr_reg(self.R_CR, self.CR_STA | self.CR_WR)
self.wait_busy()
if(not(self.rd_reg(self.R_SR) & self.SR_RXACK)):
periph_addr.append(i)
print("0x{:X}".format(i)),
sys.stdout.flush()
self.wr_reg(self.R_TXR, 0)
self.wr_reg(self.R_CR, self.CR_STO | self.CR_WR)
self.wait_busy()
print ""
return periph_addr
##########################################
# Usage example
#gennum = rr.Gennum();
#i2c = COpenCoresI2C(gennum, 0x80000, 500);
#!/usr/bin/python
#coding: utf8
# Copyright Seven Solutions S.L., 2012
# Author: Richard Carrillo <rcarrillo@sevensols.com>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
# Website: http://www.sevensols.com
import sys,select,fcntl,os
def kbhit():
""" Return True if there is a key pending to be read """
dr,dw,de = select.select([sys.stdin], [], [], 0.1)
# print "dr:"+str(dr)+" dw:"+str(dr)+" de:"+str(de)
return dr <> []
def getch():
""" Read one char from stdin """
return sys.stdin.read(1)
def purgestdin():
""" Discard all key strokes """
# make stdin a non-blocking file
fd = sys.stdin.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
try:
sys.stdin.read(4096) # purge stdin
except:
pass # ignore resource-unavailable exception
# restore stdin attributes
fcntl.fcntl(fd, fcntl.F_SETFL, fl)
#!/usr/bin/python
# Author: Tomasz?
# Author (modifications): Richard Carrillo <rcarrillo(AT)sevensols.com>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
# Website: http://www.sevensols.com
# Last modifications: 1/4/2012
import sys
import rr
import time
class OneWireDeviceOperationError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return ("OneWire Device produced the error: %s" %(msg))
class COpenCoresOneWire:
# OpenCores 1-wire registers description
R_CSR = 0x0
R_CDR = 0x4
CSR_DAT_MSK = (1<<0)
CSR_RST_MSK = (1<<1)
CSR_OVD_MSK = (1<<2)
CSR_CYC_MSK = (1<<3)
CSR_PWR_MSK = (1<<4)
CSR_IRQ_MSK = (1<<6)
CSR_IEN_MSK = (1<<7)
CSR_SEL_OFS = 8
CSR_SEL_MSK = (0xF<<8)
CSR_POWER_OFS = 16
CSR_POWER_MSK = (0xFFFF<<16)
CDR_NOR_MSK = (0xFFFF<<0)
CDR_OVD_OFS = 16
CDR_OVD_MSK = (0XFFFF<<16)
WAIT_TIME_OUT = 2
MAX_BLOCK_LEN = 160
def wr_reg(self, addr, val):
self.bus.iwrite(0, self.base_addr + addr, 4, val)
def rd_reg(self,addr):
return self.bus.iread(0, self.base_addr + addr, 4)
# Function called during object creation
# bus = host bus (PCIe, VME, etc...)
# base_addr = 1-wire core base address
# clk_div_nor = clock divider normal operation, clk_div_nor = Fclk * 5E-6 - 1
# clk_div_ovd = clock divider overdrive operation, clk_div_ovd = Fclk * 1E-6 - 1
def __init__(self, bus, base_addr, clk_div_nor, clk_div_ovd):
self.bus = bus
self.base_addr = base_addr
#print('\n### Onewire class init ###')
#print("Clock divider (normal operation): %.4X") % clk_div_nor
#print("Clock divider (overdrive operation): %.4X") % clk_div_ovd
data = ((clk_div_nor & self.CDR_NOR_MSK) | ((clk_div_ovd<<self.CDR_OVD_OFS) & self.CDR_OVD_MSK))