Commit f1d55d46 authored by Matthieu Cattin's avatar Matthieu Cattin

add fmcadc100m14b4cha test dir and script

parent 4a78fffb
#!/bin/sh
# Copyright CERN, 2011
# Author: Matthieu Cattin <matthieu.cattin@cern.ch>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
LOGDIR=./log_fmcadc100m14b4cha
mkdir -p $LOGDIR
sudo rm -fr $LOGDIR/pts*
serial=$1
if [ x$1 = x"" ]; then
echo -n "Please, input SERIAL number: "
read serial
fi
if [ x$serial = x"" ]; then
serial=0000
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
echo -n "--------------------------------------------------------------\n"
sudo ./pts.py -b FmcAdc100M14b4cha -s $serial -e $extra_serial -t./test/fmcadc100m14b4cha/python -l $LOGDIR 00 01 02 03 04 05 06 07 08
echo -n "Press enter to exit... "
read tmp
from Utilities import *
from Item import *
"""This class manages a generic waveform generator."""
class ADC(Item):
def get(self, what):
"""Get an attribute value. Supports Pyro4."""
return self.__getattribute__(what)
def set(self, what, how):
"""Set an attribute value. Supports Pyro4."""
self.__setattr__(what, how)
def clockFrequency():
doc = "Clock frequency used by the ADC"
def fget(self): return 0
def fset(self, value): return
return locals()
@Property
def clockFrequencies():
doc = "Clock frequencies"
def fget(self): return tuple()
def fset(self, value): return
return locals()
@Property
def nrBits():
doc = "Number of bits of the device."
def fget(self): return 0
return locals()
def readEvent(self, samples):
'''Read an event of size 'samples' from the ADC. Uses self.segment
and self.channel to select the missing parameters.'''
return []
def __init__(self, *args, **kwargs):
Item.__init__(self, *args, **kwargs)
This diff is collapsed.
from Utilities import *
from Item import *
"""This class manages a generic waveform generator."""
class Generator(Item):
def get(self, what):
"""Get an attribute value. Supports Pyro4."""
return self.__getattribute__(what)
def set(self, what, how):
"""Set an attribute value. Supports Pyro4."""
self.__setattr__(what, how)
# this dictionary is used to map data types into function which can
# translate such type of data into something the generator can understand.
adaptDict = {}
def adaptKeys(self):
"""Returns all data types supported."""
return self.adaptDict.keys()
def adapt(self, wave, *args, **kwargs):
"""Adapt a wave to the generator"""
return self.adaptDict[type(wave)](wave, *args, **kwargs)
def __init__(self, *args, **kwargs):
Item.__init__(self, *args, **kwargs)
"""This class just represent an API item. An item is configurable and has two
methods, get and set, which actually wrap getattribute and setattr."""
class Item(object):
# these are the default values of the parameters used
#
# the key of the dictionary is the actual name of the parameter in the class
# the item is a list:
# 1. Name of the parameter
# 2. Description
# 3. Default value
# 4. Type (it's just an object, really)
_parameters = {}
def __init__(self, *args, **kwargs):
"""Create the object and loads alll the parameters from kwargs.
Look at _parameters for more information."""
self.parameters = dict(self._parameters)
for i in kwargs:
if i in self.parameters.keys():
self.parameters[i][2] = kwargs[i]
for i in self.parameters.keys():
self.__setattr__(i, self.parameters[i][2])
import sys
import Pyro4
import Item
from Utilities import *
from numpy import *
"""This class represents a remote object, using Pyro4 framework.
All it needs is a URI."""
class RemoteObject(Item.Item, Pyro4.Proxy):
_parameters = {'uri': ['URI', 'Name of the service', '', str]}
def __init__(self, *args, **kwargs):
Item.Item.__init__(self, *args, **kwargs)
Pyro4.Proxy.__init__(self, uri = Pyro4.locateNS().lookup(self.uri))
name = 'Remote Object'
target = RemoteObject
import Waveform
from Utilities import *
from numpy import *
import Pyro4
import Pyro4.util
import sys
class SineWaveform(Waveform.Waveform):
def get(self, what):
return self.__getattribute__(what)
def set(self, what, how):
self.__setattr__(what, how)
_parameters = {'frequency':['Frequency', 'Frequency of the sinewave, in HZ', 1000, float],
'amplitude':['Amplitude', 'Amplitude of the sinewave, in Vpp', 1, float],
'dc':['DC Compoment', 'DC component of the sinewave, in Vpp', 0, float]}
def __init__(self, *args, **kwargs):
Waveform.Waveform.__init__(self, *args, **kwargs)
def generate(self, sampleRate, samples, nbits, fsr):
f = self.frequency
A = self.amplitude
C = self.dc
t = arange(samples, dtype=float)/sampleRate
s = A*sin(2*pi*f*t) +C
lsb = fsr/(2**nbits)
return (s/lsb).astype(int)
def scale(self, factor):
"""Multiply the frequency by factor."""
self.frequency *= factor
return self
name = 'Sine Waveform'
target = SineWaveform
import commands
def launch():
g = target()
hn = commands.getoutput('hostname')
daemon=Pyro4.Daemon(host = hn)
myUri = daemon.register(g)
ns=Pyro4.locateNS()
ns.register("Sine", myUri)
daemon.requestLoop()
if __name__ == '__main__':
launch()
This diff is collapsed.
import Waveform
from Utilities import *
from numpy import *
import Pyro4
import Pyro4.util
import sys
import commands
class TTWaveform(Waveform.Waveform):
def get(self, what):
return self.__getattribute__(what)
def set(self, what, how):
self.__setattr__(what, how)
_parameters = {'frequency':['Frequency (1)', 'Frequency of the first sinewave, in HZ', float(5e6), float],
'ratio':['Ratio', 'Ratio between the frequency of the second sinewave and the one', 6./5., float],
'amplitude':['Amplitude', 'Amplitude of each sinewave, in Vpp', 1., float],
'dc':['DC Compoment', 'DC component of the whole waveform, in Vpp', 0., float]}
def __init__(self, *args, **kwargs):
Waveform.Waveform.__init__(self, *args, **kwargs)
def generate(self, sampleRate, samples, nbits, fsr):
f1, f2 = self.frequency, self.frequency * self.ratio
A = self.amplitude
C = self.dc
t = arange(samples, dtype=float)/sampleRate
s = A*sin(2*pi*f1*t) +A*sin(2*pi*f2*t) +C
lsb = fsr/(2**nbits)
return (s/lsb).astype(int)
def scale(self, factor):
"""Multiply the frequency by factor"""
self.frequency *= factor
return self
name = 'Two Tones Waveform'
target = TTWaveform
def launch():
g = target()
hn = commands.getoutput('hostname')
daemon = Pyro4.Daemon(host = hn)
myUri = daemon.register(g)
ns=Pyro4.locateNS()
ns.register("TTSine", myUri)
daemon.requestLoop()
if __name__ == '__main__':
launch()
def Property(func):
return property(**func())
decodeDict = {'KHZ': 3, 'MHZ': 6, 'HZ':0, 'UHZ': -6, 'NHZ': 9,
'MV': -3, 'NV': -6, 'KV': 3, 'V':0,
'MVPP': -3, 'NVPP': -6, 'KVPP': 3, 'VPP':0}
def decode(values):
return float(values[0])* (10.**float(decodeDict[values[1].upper()]))
def parse(value, s):
if type(value) is str:
value = value.split(" ")
value[0] = float(value[0])
value = tuple(value)
if type(value) is tuple and len(value) == 1:
value = value[0]
if type(value) is not tuple:
value = (value, s)
return tuple(str(i) for i in value)
def prettyParameter(x, vx):
print 'Parameter %s is called %s.' % (x, vx[0])
print 'Description:', vx[1]
print 'Default value, in %s, is %s' % (repr(vx[3]), repr(vx[2]))
from numpy import array
from Item import *
"""This class represent a generic waveform."""
class Waveform(Item):
def get(self, what):
"""Get an attribute value. Supports Pyro4."""
return self.__getattribute__(what)
def set(self, what, how):
"""Set an attribute value. Supports Pyro4."""
self.__setattr__(what, how)
"""A waveform must provide this method.
Create a numeric array which represents the wave."""
def generate(self, nbits, frequency, samples, fsr):
return array([])
def __init__(self, *args, **kwargs):
Item.__init__(self, *args, **kwargs)
def getType(self):
return type(self)
__author__="Federico"
__date__ ="$Aug 17, 2011 4:43:08 PM$"
# PAGE: Python ADC and GEnerators API
hasSis33 = False
import SineWaveform, TTWaveform
import Agilent33250A
import RemoteObject
try:
import Sis33
hasSis33 = True
except:
print 'Error while loading Sis33 module, skipping it'
waveforms = (RemoteObject, SineWaveform, TTWaveform)
generators = (Agilent33250A, RemoteObject)
if hasSis33:
adcs = (RemoteObject, Sis33)
else:
adcs = (RemoteObject, )
#!/usr/bin/python
import sys
import rr
import time
class CCSR:
def __init__(self, bus, base_addr):
self.base_addr = base_addr;
self.bus = bus;
def wr_reg(self, addr, val):
#print(" wr:%.8X reg:%.8X")%(val,(self.base_addr+addr))
self.bus.iwrite(0, self.base_addr + addr, 4, val)
def rd_reg(self, addr):
reg = self.bus.iread(0, self.base_addr + addr, 4)
#print(" reg:%.8X value:%.8X")%((self.base_addr+addr), reg)
return reg
def wr_bit(self, addr, bit, value):
reg = self.rd_reg(addr)
if(0==value):
reg &= ~(1<<bit)
else:
reg |= (1<<bit)
self.wr_reg(addr, reg)
def rd_bit(self, addr, bit):
if(self.rd_reg(addr) & (1<<bit)):
return 1
else:
return 0
#!/usr/bin/python
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 fonctions commands
CONVERT_TEMP = 0x44
WRITE_SCRATCHPAD = 0x4E
READ_SCRATCHPAD = 0xBE
COPY_SCRATCHPAD = 0x48
RECALL_EEPROM = 0xB8
READ_POWER_SUPPLY = 0xB4
# 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')
if(1 != self.onewire.reset(self.port)):
print('[DS18B20] No presence pulse detected')
return -1
else:
#print('[DS18B20] Write ROM command %.2X') % self.ROM_READ
err = self.onewire.write_byte(self.port, self.ROM_READ)
if(err != 0):
print('[DS18B20] Write error')
return -1
family_code = self.onewire.read_byte(self.port)
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')
if(1 != self.onewire.reset(self.port)):
print('[DS18B20] No presence pulse detected')
return -1
else:
#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)
return 0
def read_temp(self, serial_number):
#print('[DS18B20] Reading temperature')
err = self.access(serial_number)
#print('[DS18B20] Write function command %.2X') % self.CONVERT_TEMP
err = self.onewire.write_byte(self.port, self.CONVERT_TEMP)
time.sleep(1)
err = self.access(serial_number)
#print('[DS18B20] Write function command %.2X') % self.READ_SCRATCHPAD
err = 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
return temp
# Set temperature thresholds
# Configure thermometer resolution
This diff is collapsed.
#!/usr/bin/python
import sys
import rr
import time
import csr
class CGN4124:
# Host registers (BAR12), for DMA items storage
HOST_BAR = 0xC
HOST_DMA_CARRIER_START_ADDR = 0x00
HOST_DMA_HOST_START_ADDR_L = 0x04
HOST_DMA_HOST_START_ADDR_H = 0x08
HOST_DMA_LENGTH = 0x0C
HOST_DMA_NEXT_ITEM_ADDR_L = 0x10
HOST_DMA_NEXT_ITEM_ADDR_H = 0x14
HOST_DMA_ATTRIB = 0x18
# GN4124 chip registers (BAR4)
GN4124_BAR = 0x4
R_CLK_CSR = 0x808
R_INT_CFG0 = 0x820
R_GPIO_DIR_MODE = 0xA04
R_GPIO_INT_MASK_CLR = 0xA18
R_GPIO_INT_MASK_SET = 0xA1C
R_GPIO_INT_STATUS = 0xA20
R_GPIO_INT_VALUE = 0xA28
CLK_CSR_DIVOT_MASK = 0x3F0
INT_CFG0_GPIO = 15
GPIO_INT_SRC = 8
# GN4124 core registers (BAR0)
R_DMA_CTL = 0x00
R_DMA_STA = 0x04
R_DMA_CARRIER_START_ADDR = 0x08
R_DMA_HOST_START_ADDR_L = 0x0C
R_DMA_HOST_START_ADDR_H = 0x10
R_DMA_LENGTH = 0x14
R_DMA_NEXT_ITEM_ADDR_L = 0x18
R_DMA_NEXT_ITEM_ADDR_H = 0x1C
R_DMA_ATTRIB = 0x20
DMA_CTL_START = 0
DMA_CTL_ABORT = 1
DMA_CTL_SWAP = 2
DMA_STA = ['Idle','Done','Busy','Error','Aborted']
DMA_ATTRIB_LAST = 0
DMA_ATTRIB_DIR = 1
def rd_reg(self, bar, addr):
return self.bus.iread(bar, addr, 4)
def wr_reg(self, bar, addr, value):
self.bus.iwrite(bar, addr, 4, value)
def __init__(self, bus, csr_addr):
self.bus = bus
self.dma_csr = csr.CCSR(bus, csr_addr)
self.dma_item_cnt = 0
# Get page list
self.pages = self.bus.getplist()
# Shift by 12 to get the 32-bit physical addresses
self.pages = [addr << 12 for addr in self.pages]
self.set_interrupt_config()
# Enable interrupt from gn4124
self.bus.irqena()
# Set local bus frequency
def set_local_bus_freq(self, freq):
# freq in MHz
# LCLK = (25MHz*(DIVFB+1))/(DIVOT+1)
# DIVFB = 31
# DIVOT = (800/LCLK)-1
divot = int(round((800/freq)-1,0))
#print '%d' % divot
data = 0xe001f00c + (divot << 4)
#print '%.8X' % data
#print 'Set local bus freq to %dMHz' % int(round(800/(divot+1),0))
self.wr_reg(self.GN4124_BAR, self.R_CLK_CSR, data)
# Get local bus frequency
# return: frequency in MHz
def get_local_bus_freq(self):
reg = self.rd_reg(self.GN4124_BAR, self.R_CLK_CSR)
divot = ((reg & self.CLK_CSR_DIVOT_MASK)>>4)
return (800/(divot + 1))
# Get physical addresses of the pages allocated to GN4124
def get_physical_addr(self):
return self.pages
# Wait for interrupt
def wait_irq(self):
# Add here reading of the interrupt source (once the irq core will be present)
return self.bus.irqwait()
# GN4124 interrupt configuration
def set_interrupt_config(self):
# Set interrupt line from FPGA (GPIO8) as input
self.wr_reg(self.GN4124_BAR, self.R_GPIO_DIR_MODE, (1<<self.GPIO_INT_SRC))
# Set interrupt mask for all GPIO except for GPIO8
self.wr_reg(self.GN4124_BAR, self.R_GPIO_INT_MASK_SET, ~(1<<self.GPIO_INT_SRC))
# Make sure the interrupt mask is cleared for GPIO8
self.wr_reg(self.GN4124_BAR, self.R_GPIO_INT_MASK_CLR, (1<<self.GPIO_INT_SRC))
# Interrupt on rising edge of GPIO8
self.wr_reg(self.GN4124_BAR, self.R_GPIO_INT_VALUE, (1<<self.GPIO_INT_SRC))
# GPIO as interrupt 0 source
self.wr_reg(self.GN4124_BAR, self.R_INT_CFG0, (1<<self.INT_CFG0_GPIO))
# Get DMA controller status
def get_dma_status(self):
reg = self.dma_csr.rd_reg(self.R_DMA_STA)
if(reg > len(self.DMA_STA)):
print("DMA status register : %.8X") % reg
raise Exception('Invalid DMA status')
else:
return self.DMA_STA[reg]
# Configure DMA byte swapping
# 0 = A1 B2 C3 D4 (straight)
# 1 = B2 A1 D4 C3 (swap bytes in words)
# 2 = C3 D4 A1 B2 (swap words)
# 3 = D4 C3 B2 A1 (invert bytes)
def set_dma_swap(self, swap):
if(swap > 3):
raise Exception('Invalid swapping configuration : %d') % swap
else:
self.dma_csr.wr_reg(self.R_CTL, (swap << self.DMA_CTL_SWAP))
# Add DMA item (first item is on the board, the following in the host memory)
# carrier_addr, host_addr, length and next_item_addr are in bytes
# dma_dir = 1 -> PCIe to carrier
# dma_dir = 0 -> carrier to PCIe
# dma_last = 0 -> last item in the transfer
# dma_last = 1 -> more item in the transfer
# Only supports 32-bit host address
def add_dma_item(self, carrier_addr, host_addr, length, dma_dir, last_item):
if(0 == self.dma_item_cnt):
# write the first DMA item in the carrier
self.dma_csr.wr_reg(self.R_DMA_CARRIER_START_ADDR, carrier_addr)
self.dma_csr.wr_reg(self.R_DMA_HOST_START_ADDR_L, (host_addr & 0xFFFFFFFF))
self.dma_csr.wr_reg(self.R_DMA_HOST_START_ADDR_H, (host_addr >> 32))
self.dma_csr.wr_reg(self.R_DMA_LENGTH, length)
self.dma_csr.wr_reg(self.R_DMA_NEXT_ITEM_ADDR_L, (self.pages[0] & 0xFFFFFFFF))
self.dma_csr.wr_reg(self.R_DMA_NEXT_ITEM_ADDR_H, 0x0)
attrib = (dma_dir << self.DMA_ATTRIB_DIR) + (last_item << self.DMA_ATTRIB_LAST)
self.dma_csr.wr_reg(self.R_DMA_ATTRIB, attrib)
else:
# write nexy DMA item(s) in host memory
# uses page 0 to store DMA items
# current and next item addresses are automatically set
current_item_addr = (self.dma_item_cnt-1)*0x20
next_item_addr = (self.dma_item_cnt)*0x20
self.wr_reg(self.HOST_BAR, self.HOST_DMA_CARRIER_START_ADDR + current_item_addr, carrier_addr)
self.wr_reg(self.HOST_BAR, self.HOST_DMA_HOST_START_ADDR_L + current_item_addr, host_addr)
self.wr_reg(self.HOST_BAR, self.HOST_DMA_HOST_START_ADDR_H + current_item_addr, 0x0)
self.wr_reg(self.HOST_BAR, self.HOST_DMA_LENGTH + current_item_addr, length)
self.wr_reg(self.HOST_BAR, self.HOST_DMA_NEXT_ITEM_ADDR_L + current_item_addr,
self.pages[0] + next_item_addr)
self.wr_reg(self.HOST_BAR, self.HOST_DMA_NEXT_ITEM_ADDR_H + current_item_addr, 0x0)
attrib = (dma_dir << self.DMA_ATTRIB_DIR) + (last_item << self.DMA_ATTRIB_LAST)
self.wr_reg(self.HOST_BAR, self.HOST_DMA_ATTRIB + current_item_addr, attrib)
self.dma_item_cnt += 1
# Start DMA transfer
def start_dma(self):
self.dma_item_cnt = 0
self.dma_csr.wr_bit(self.R_DMA_CTL, self.DMA_CTL_START, 1)
# The following two lines should be removed
# when the GN4124 vhdl core will implement auto clear of start bit
#while(('Idle' == self.get_dma_status()) or
# ('Busy' == self.get_dma_status())):
# pass
self.dma_csr.wr_bit(self.R_DMA_CTL, self.DMA_CTL_START, 0)
# Abort DMA transfer
def abort_dma(self):
self.dma_item_cnt = 0
self.dma_csr.wr_bit(self.R_DMA_CTL, self.DMA_CTL_ABORT, 1)
# The following two lines should be removed
# when the GN4124 vhdl core will implement auto clear of start bit
while('Aborted' != self.get_dma_status()):
pass
self.dma_csr.wr_bit(self.R_DMA_CTL, self.DMA_CTL_ABORT, 0)