Commit ff9163de authored by Matthieu Cattin's avatar Matthieu Cattin

test28: Read calibration data from fmc eeprom adn apply them.

Work on acquisition (trig and end acq interrupts).
Work on internal trigger (level).
parent f97468f7
......@@ -52,6 +52,7 @@ test28: Long term test
TEST_NB = 28
# Gateware
LOAD_BITSTREAM = False
FMC_ADC_BITSTREAM = '../firmwares/spec_fmcadc100m14b4cha.bin'
EXPECTED_BITSTREAM_TYPE = 0x0
......@@ -78,6 +79,9 @@ RANGES = {'10V':10.0, '1V':1.0, '100mV':0.1}
ADC_NBITS = 16 # ADC chip is 14 bits, but shifted to 16 bits in the firmware
DAC_NBITS = 16
DAC_FS = 10 # DAC full scale range is 10V
CALIBR_BIN_FILENAME = "calibration_data.bin"
EEPROM_BIN_FILENAME = "eeprom_content.out"
EEPROM_SIZE = 8192 # in Bytes
# Acquisition
ACQ_MIN_PERIODS = 2
......@@ -167,6 +171,74 @@ def clear_ddr(carrier, verbose=False):
carrier.set_irq_dma_done_mask(0)
def get_calibr_data(fmc, eeprom_bin_filename, calibr_bin_filename, verbose=False):
if verbose:
print "Read calibration data from FMC EEPROM:"
adc_corr_data = {'10V':{'offset':[],'gain':[],'temp':0},
'1V':{'offset':[],'gain':[],'temp':0},
'100mV':{'offset':[],'gain':[],'temp':0}}
dac_corr_data = {'10V':{'offset':[],'gain':[],'temp':0},
'1V':{'offset':[],'gain':[],'temp':0},
'100mV':{'offset':[],'gain':[],'temp':0}}
# Read entire EEPROM
print("Read all eeprom content.")
eeprom_data_read = fmc.sys_i2c_eeprom_read(0, EEPROM_SIZE)
# Write EEPROM data to binary file
if verbose:
print("Write eeprom content to file (binary): %s"%(eeprom_bin_filename))
f_eeprom = open(eeprom_bin_filename, "wb")
for byte in eeprom_data_read:
f_eeprom.write(chr(byte))
f_eeprom.close()
# Get calibration data
#print("Extract calibration binary file to: %s"%(CALIBR_BIN_FILENAME))
cmd = 'sdb-read -e 0x1000 ' + eeprom_bin_filename + ' calibration.sdb > ' + calibr_bin_filename
if verbose:
print("Exctract calibration binary file, cmd: %s"%(cmd))
os.system(cmd)
if verbose:
print "Get calibration data from binary file."
calibr_data = []
f_calibr_data = open(calibr_bin_filename, "rb")
try:
byte = f_calibr_data.read(1)
while byte != "":
calibr_data.append(ord(byte))
byte = f_calibr_data.read(1)
finally:
f_eeprom.close()
# Re-arrange correction data into 16-bit number (from bytes)
eeprom_corr_data = []
for i in range(0,len(calibr_data),2):
eeprom_corr_data.append((calibr_data[i+1] << 8) + (calibr_data[i]))
if verbose:
print "0x%04X" % eeprom_corr_data[-1]
if verbose:
print "Calibration data length (16-bit): %d" % len(eeprom_corr_data)
for adc_range in RANGES:
for ch in range(NB_CHANNELS):
adc_corr_data[adc_range]['offset'].append(hex2signed(eeprom_corr_data.pop(0)))
for ch in range(NB_CHANNELS):
adc_corr_data[adc_range]['gain'].append(eeprom_corr_data.pop(0))
adc_corr_data[adc_range]['temp'] = eeprom_corr_data.pop(0)/100.0
for IN_RANGE in RANGES:
for ch in range(NB_CHANNELS):
dac_corr_data[adc_range]['offset'].append(hex2signed(eeprom_corr_data.pop(0)))
for ch in range(NB_CHANNELS):
dac_corr_data[adc_range]['gain'].append(eeprom_corr_data.pop(0))
dac_corr_data[adc_range]['temp'] = eeprom_corr_data.pop(0)/100.0
return adc_corr_data, dac_corr_data
# Set AWG (sine wave)
def set_awg(awg, freq, ampl, offset, verbose=False):
# Set sine params
......@@ -230,40 +302,66 @@ def set_adc_offset(fmc, offset_volt, verbose=False):
def set_adc_trig(fmc, hw_sel, hw_pol, channel, thres_volt, delay, in_range, verbose=False):
fs = RANGES[in_range]
nbits = ADC_NBITS
thres = volt2digital(thres_volt, fs, nbits)
hw_en = 0
sw_en = 1
thres = volt2digital_without_offset(thres_volt, fs, nbits)
##################################################
hw_en = 1
sw_en = 0
#################################################
fmc.set_trig_config(hw_sel, hw_pol, hw_en, sw_en, channel, thres, delay)
fmc.print_trig_config()
HW_SEL = ['internal', 'external']
HW_POL = ['rising','falling']
if verbose:
print("Trigger params -> Hardware %s on %s edge, on channel %d with a thresold of 0x%X (%fV)"%(HW_SEL[hw_sel], HW_POL[hw_pol], channel, thres, thres_volt))
print("Trigger params -> Hardware %s on %s edge, on channel %d with a thresold of %fV"%(HW_SEL[hw_sel], HW_POL[hw_pol], channel, thres_volt))
# Make acquisition
def make_acq(fmc, verbose=False):
def make_acq(carrier, fmc, verbose=False):
# Make sure no acquisition is running
fmc.stop_acq()
# Enables acquisition end interrupt
carrier.set_irq_acq_end_mask(1)
#carrier.set_irq_trig_mask(1)
if verbose:
print("IRQ mask : %.8X"%carrier.get_irq_en_mask())
print("IRQ source : %.8X"%carrier.get_irq_source())
# Start acquisition
if verbose:
print("Starting acquisition...")
fmc.start_acq()
###############################
# Random time before trigger
time_to_trig = rdm.randrange(1, 1000)/1000.0
#time_to_trig = rdm.randrange(1, 1000)/1000.0
#if verbose:
# print("Time between acquisition start and trigger: %fs"%(time_to_trig))
#time.sleep(time_to_trig)
#fmc.sw_trig()
###########################
# Wait for trigger interrupt
#carrier.gnum.wait_irq()
# Wait for acquisition end interrupt
carrier.gnum.wait_irq()
irq_src = carrier.get_irq_source()
if verbose:
print("Time between acquisition start and trigger: %fs"%(time_to_trig))
time.sleep(time_to_trig)
fmc.sw_trig()
# Wait end of acquisition
timeout = 0
while('IDLE' != fmc.get_acq_fsm_state()):
time.sleep(.001)
timeout += 1
if(ACQ_TIMEOUT < timeout):
print "Acquisition timeout. Missing trigger?."
print "Acq FSm state: %s"%fmc.get_acq_fsm_state()
print("IRQ source : %.8X"%irq_src)
if(irq_src & carrier.IRQ_SRC_ACQ_END):
carrier.clear_irq_source(carrier.IRQ_SRC_ACQ_END)
if verbose:
print("IRQ source : %.8X"%carrier.get_irq_source())
else:
raise PtsError("Bad IRQ source. expected:0x08 got:0x%02X" %(irq_src))
if 'IDLE' != fmc.get_acq_fsm_state():
raise PtsError("Acq FSM not IDLE. Current state:%s"%fmc.get_acq_fsm_state())
if verbose:
print("Acquisition finished.")
# Disables acquisition end interrupt
carrier.set_irq_acq_end_mask(0)
# Make a linked list dma
def make_dma(carrier, start_byte_addr, length_bytes, in_range, verbose=False):
# Enable "DMA done" interrupt
......@@ -348,15 +446,15 @@ def get_acq_data(carrier, fmc, samples, pre_trig_samples, nb_shots, in_range, ve
data = make_dma(carrier, start, length, in_range, True)
else:
#-----------------------------------------------------------------------
# Single shot case
# Multi-shot case
#-----------------------------------------------------------------------
pass
start = 0
length = (samples*nb_shots)<<3
if verbose:
print("DMA start: %d(bytes), length: %d(bytes)"%(start, length))
data = make_dma(carrier, start, length, in_range, True)
# Converts raw data to signed
#data = [hex2signed(item) for item in data]
# Converts signed data to volts
#fs = RANGES[in_range]
#data = [digital2volt(item, fs, ADC_NBITS) for item in data]
# returns interleaved channel data (in volts)
return data
......@@ -370,14 +468,18 @@ def acq_mean(acq_data):
mean_d.append(mean(acq_data[channel-1::4]))
return mean_d
def plot_all(data, ylimit):
def plot_all(data, ylimit, trig_level, trig_pos):
sample = arange(len(data)/4)
clf()
plot(sample, data[0::4], 'b', label='Channel 1')
plot(sample, data[1::4], 'g', label='Channel 2')
plot(sample, data[2::4], 'c', label='Channel 3')
plot(sample, data[3::4], 'm', label='Channel 4')
ylim(-ylimit-(ylimit/10.0), ylimit+(ylimit/10.0))
plot(sample, len(sample)*[trig_level], 'r', label='Trigger level')
ylim_min = -ylimit-(ylimit/10.0)
ylim_max = ylimit+(ylimit/10.0)
vlines(trig_pos, ylim_min, ylim_max, color='#AA0000', linestyles='solid', label='Trigger position')
ylim(ylim_min, ylim_max)
xlim(0, len(sample))
grid(which='both')
legend()
......@@ -398,10 +500,11 @@ def main (default_directory='.'):
spec = rr.Gennum()
# Load FMC ADC firmware
bitstream_path = os.path.join(default_directory, FMC_ADC_BITSTREAM)
print "Loading FMC ADC firmware: %s\n" % bitstream_path
spec.load_firmware(bitstream_path)
time.sleep(2)
if LOAD_BITSTREAM:
bitstream_path = os.path.join(default_directory, FMC_ADC_BITSTREAM)
print "Loading FMC ADC firmware: %s\n" % bitstream_path
spec.load_firmware(bitstream_path)
time.sleep(2)
# Carrier object declaration (SPEC board specific part)
# Used to check that the firmware is loaded.
......@@ -429,6 +532,17 @@ def main (default_directory='.'):
fmc.testpat_dis() # Disable adc test pattern (just in case)
fmc.test_data_dis() # Disable test data to ddr (just in case)
########################################################################
# Get calibration data from EEPROM
########################################################################
calibr_bin_filename = os.path.join(default_directory, CALIBR_BIN_FILENAME)
eeprom_bin_filename = os.path.join(default_directory, EEPROM_BIN_FILENAME)
adc_corr_data, dac_corr_data = get_calibr_data(fmc, eeprom_bin_filename, calibr_bin_filename, False)
# Apply DAC correction
fmc.set_dac_corr(dac_corr_data)
########################################################################
# Clear DDR
########################################################################
......@@ -443,17 +557,25 @@ def main (default_directory='.'):
########################################################################
# Choose input termination randomly
adc_term = rdm.choice(['ON', 'OFF'])
##########################################################
#adc_term = rdm.choice(['ON', 'OFF'])
adc_term = 'OFF'
##########################################################
print("Input termination: %s"%adc_term)
# Choose input range randomly
adc_range = rdm.choice(['10V', '1V', '100mV'])
##########################################################
#adc_range = rdm.choice(['10V', '1V', '100mV'])
adc_range = '10V'
##########################################################
print("Input range: %s"%adc_range)
# Configure ADC analogue input
set_adc_input(fmc, adc_term, adc_range, True)
adc_offset = 0
set_adc_offset(fmc, adc_offset, True)
for ch in range(1, NB_CHANNELS+1):
fmc.set_adc_gain_offset_corr(ch, adc_corr_data[adc_range]['gain'][ch-1], adc_corr_data[adc_range]['offset'][ch-1])
########################################################################
......@@ -461,13 +583,16 @@ def main (default_directory='.'):
########################################################################
# Building input sine wave
sine_freq = SINE_MIN_FREQ + ((SINE_MAX_FREQ-SINE_MIN_FREQ)*rdm.random())
#sine_freq = SINE_MIN_FREQ + ((SINE_MAX_FREQ-SINE_MIN_FREQ)*rdm.random())
sine_freq = rdm.randrange(SINE_MIN_FREQ, SINE_MAX_FREQ, 1E3)
sine_min_ampl = 0.1 * (RANGES[adc_range]/2) # 10% full scale
sine_max_ampl = 0.9 * (RANGES[adc_range]/2) # 90% full scale
if adc_term == 'ON':
sine_min_ampl *= 2
sine_max_ampl *= 2
sine_ampl = sine_min_ampl + ((sine_max_ampl-sine_min_ampl)*rdm.random())
print("Input sine wave => max amplitude: %2.3fV, min amplitude: %2.3fV"%(sine_min_ampl, sine_max_ampl))
#sine_ampl = sine_min_ampl + ((sine_max_ampl-sine_min_ampl)*rdm.random())
sine_ampl = rdm.randrange(int(sine_min_ampl*1E3), int(sine_max_ampl*1E3), 100)/1000.0
#sine_offset = (sine_max_ampl-sine_ampl)*rdm.random()
sine_offset = 0
print("Input sine wave => Frequency: %3.3fMHz, Amplitude: %2.3fVp, Offset: %2.3fV"%(sine_freq/1E6, sine_ampl, sine_offset))
......@@ -476,35 +601,49 @@ def main (default_directory='.'):
set_awg(awg, sine_freq, sine_ampl, sine_offset, True)
########################################################################
# Set box params
########################################################################
# Randomly select an adc channel
#channel = rdm.randrange(1,NB_CHANNELS+1)
channel = 1
# Connect AWG to selected channel (other channels with 100mV range ref ~= 0.04096V)
box.select_output_ch(channel)
time.sleep(BOX_SET_SLEEP)
########################################################################
# Set acquisition params
########################################################################
# Configure trigger
trig_hw_sel = 1 # external
trig_hw_sel = 0 # internal
trig_hw_pol = 0 # rising
trig_channel = 1
trig_thres = 0
trig_delay = 0
trig_channel = channel
trig_thres = (sine_ampl+0.05) # in Volts
trig_delay = 0 # in samples
set_adc_trig(fmc, trig_hw_sel, trig_hw_pol, trig_channel, trig_thres, trig_delay, adc_range, True)
# Find the minimum number of samples to have ACQ_MIN_PERIODS of the sine wave
acq_min_samples = int(ACQ_MIN_PERIODS*SAMP_FREQ/sine_freq)
print("Minimum number of samples: %d"%acq_min_samples)
# Choose the number of samples randomly
print("Memory size in samples : %d"%MEMORY_SIZE)
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# Can't use all available memory on-board.
# Bad memory management in my Python program...
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
mem_size = MEMORY_SIZE/100
print("Memory size in samples : %d"%mem_size)
# Choose the number of shots and samples randomly
#multishot = rdm.choice([False, True])
multishot = False
if multishot:
acq_samples = rdm.randrange(acq_min_samples, MULTISHOT_MAX_SIZE+1)
acq_nb_shots = rdm.randrange(1, (MEMORY_SIZE/acq_samples)+1)
acq_nb_shots = rdm.randrange(1, (mem_size/acq_samples)+1)
else:
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# Can't use all available memory on-board.
# Bad memory management in my Python program...
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#acq_samples = rdm.randrange(acq_min_samples, MEMORY_SIZE+1)
acq_samples = rdm.randrange(acq_min_samples, (MEMORY_SIZE/10)+1)
acq_samples = rdm.randrange(acq_min_samples, mem_size+1)
acq_nb_shots = 1
print("Final number of samples: %d"%acq_samples)
......@@ -517,22 +656,12 @@ def main (default_directory='.'):
set_acq(fmc, acq_nb_shots, acq_pre_trig_samples, acq_post_trig_samples, acq_decim_factor, True)
########################################################################
# Set box params
########################################################################
# Connect AWG to one channel
channel = 1
box.select_output_ch(channel)
time.sleep(BOX_SET_SLEEP)
########################################################################
# Make acqusisition
########################################################################
# Make acquisition
make_acq(fmc, True)
make_acq(carrier, fmc, True)
# Get data from DDR
acq_data = get_acq_data(carrier, fmc, acq_samples, acq_pre_trig_samples, acq_nb_shots, adc_range, True)
......@@ -540,9 +669,20 @@ def main (default_directory='.'):
print("Number of retrieved samples: %d"%(len(acq_data)/4))
########################################################################
# Check retreived data
########################################################################
# Plot data
plot_all(acq_data, max(acq_data))
acq_data_ch = acq_data[channel-1::4]
print("trig thres:%2.6fV, data@trig: %2.6fV"%(trig_thres, acq_data_ch[acq_pre_trig_samples]))
#fs = RANGES[adc_range]
#trig_thres = signed2hex(volt2digital_without_offset(trig_thres, fs, ADC_NBITS))
#print("trig thres:0x%04X, data@trig: 0x%04X"%(trig_thres, acq_data_ch[acq_pre_trig_samples]))
#plot_all(acq_data, max(acq_data), trig_thres, acq_pre_trig_samples)
sys.exit()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment