Commit 502308c9 authored by Matthieu Cattin's avatar Matthieu Cattin

Calibration validation in test20. In work.

parent bd07c34e
#! /usr/bin/env python
# coding: utf8
# Copyright CERN, 2011
# Author: Matthieu Cattin <matthieu.cattin@cern.ch>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
import sys
import rr
import time
import os
from numpy import *
from pylab import *
from ctypes import *
from ptsexcept import *
import spec_fmc_adc
import fmc_adc
import calibr_box
import find_usb_tty
import cp210x_eeprom
from PAGE.Agilent33250A import *
from PAGE.SineWaveform import *
"""
test20: Calibration verification
Note: Requires test00.py to run first to load the firmware!
"""
GN4124_CSR = 0x0
# Calibration box vendor and product IDs
BOX_USB_VENDOR_ID = 0x10c4 # Cygnal Integrated Products, Inc.
BOX_USB_PRODUCT_ID = 0xea60 # CP210x Composite Device
# Agilent AWG serial access vendor and product IDs
AWG_USB_VENDOR_ID = 0x0403 # Future Technology Devices International, Ltd
AWG_USB_PRODUCT_ID = 0x6001 # FT232 USB-Serial (UART) IC
RS232_BAUD = 57600
NB_CHANNELS = 4
AWG_SET_SLEEP = 1
SSR_SET_SLEEP = 0.05
BOX_SET_SLEEP = 1
DAC_SET_SLEEP = 0.1
ACQ_TIMEOUT = 10
MAX_FIRMWARE_RELOAD = 10
PRE_TRIG_SAMPLES = 1000
POST_TRIG_SAMPLES = 100000
NB_SHOTS = 1
ACQ_LENGTH = 50000 # in samples
DMA_LENGTH = 4096 # in bytes
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
def load_firmware(default_directory):
print('Load firmware to FPGA')
path_fpga_loader = '../../../gnurabbit/user/fpga_loader';
path_firmware = '../firmwares/spec_fmcadc100m14b4cha_test.bin';
firmware_loader = os.path.join(default_directory, path_fpga_loader)
bitstream = os.path.join(default_directory, path_firmware)
print firmware_loader + ' ' + bitstream
os.system( firmware_loader + ' ' + bitstream )
time.sleep(2);
def disconnect_channels(fmc):
for i in range(1,NB_CHANNELS+1):
fmc.set_ssr(i, 0x00)
time.sleep(SSR_SET_SLEEP)
def fmc_adc_init(spec, fmc):
print('Initialise FMC board\n')
fmc.__init__(spec)
# Reset offset DACs
fmc.dc_offset_reset()
# Make sure all switches are OFF
disconnect_channels(fmc)
# Reset offset DACs
fmc.dc_offset_reset()
# Set trigger
fmc.set_soft_trig()
# Set acquisition
fmc.set_pre_trig_samples(PRE_TRIG_SAMPLES)
fmc.set_post_trig_samples(POST_TRIG_SAMPLES)
fmc.set_shots(NB_SHOTS)
# Print configuration
#fmc.print_adc_core_config()
def acquisition_all(fmc, spec_fmc):
# Make sure no acquisition is running
fmc.stop_acq()
#print('Acquisition FSM state : %s') % fmc.get_acq_fsm_state()
# Start acquisition
fmc.start_acq()
time.sleep(0.01)
# Trigger
fmc.sw_trig()
# Wait end of acquisition
timeout = 0
while('IDLE' != fmc.get_acq_fsm_state()):
#print fmc.get_acq_fsm_state()
time.sleep(.1)
timeout += 1
if(ACQ_TIMEOUT < timeout):
print('Acquisition timeout. Check that the AWG is switched ON and properly connected.')
return 1
# Retrieve data trough DMA
trig_pos = fmc.get_trig_pos()
#print('Trigger position; 0x%X')%(trig_pos)
channels_data = spec_fmc.get_data((trig_pos<<3), ACQ_LENGTH*8)
#channels_data = spec_fmc.get_data(0x0, ACQ_LENGTH*8)
return channels_data
def plot_all(data, mean, ylimit):
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')
plot(sample, [mean[0]]*len(sample), 'r')
plot(sample, [mean[1]]*len(sample), 'r')
plot(sample, [mean[2]]*len(sample), 'r')
plot(sample, [mean[3]]*len(sample), 'r')
ylim(-ylimit-(ylimit/10.0), ylimit+(ylimit/10.0))
grid(which='both')
legend()
draw()
show()
return 0
# Converts two's complement hex to signed
def hex2signed(value):
if(value & 0x8000):
return -((~value & 0xFFFF) + 1)
else:
return value
# Converts digital value to volts
def digital2volt(value, full_scale, nb_bit):
return float(value) * float(full_scale)/2**nb_bit
# Converts volts to digital value with half full range offset
def volt2digital(value, full_scale, nb_bit):
digital = (value + full_scale/2) * 2**nb_bit/full_scale
if(digital > 2**nb_bit - 1):
digital = 2**nb_bit - 1
if(digital < 0):
digital = 0
#print('volt2digital: %2.9f > %2.9f')%(value,digital)
return int(digital)
# Converts volts to digital value
def volt2digital_without_offset(value, full_scale, nb_bit):
digital = (value) * 2**nb_bit/full_scale
if(digital > 2**nb_bit - 1):
digital = ~(1<<nb_bit)
if(digital < 0):
digital = (1<<nb_bit)
#print('volt2digital: %2.9f > %2.9f')%(value,digital)
return int(digital)
def set_offset_dac(fmc, dac_fs, dac_nbits, channel, offset_volt, dac_corr_flag=False):
dac_v = offset_volt
dac_d = volt2digital(dac_v,dac_fs,dac_nbits)
#print('DAC value: 0x%X (%fV)')%(dac_d, dac_v)
if(True == dac_corr_flag):
fmc.set_dc_offset_corrected(channel,dac_d)
else:
fmc.set_dc_offset(channel,dac_d)
time.sleep(DAC_SET_SLEEP)
def get_mean_value(adc_fs, adc_nbits, acq):
mean_d = []
for channel in range(1,NB_CHANNELS+1):
mean_d.append(mean(acq[channel-1::4]))
mean_v = [digital2volt(item,adc_fs,adc_nbits) for item in mean_d]
return mean_v
def set_box_dac_range(box, fmc, box_out, dac_value, in_range, dac_corr_flag=False):
# Set calibration box output
box.select_output(box_out)
time.sleep(BOX_SET_SLEEP)
# Set offset DACs
for channel in range(1,NB_CHANNELS+1):
set_offset_dac(fmc, DAC_FS, DAC_NBITS, channel, dac_value, dac_corr_flag)
# Set channels input range
for channel in range(1,NB_CHANNELS+1):
fmc.set_input_range(channel, in_range)
time.sleep(SSR_SET_SLEEP)
def channels_mean(spec_fmc, fmc, ADC_FS, print_flag, plot_flag=False):
# Measures value on each channel
acq_d = acquisition_all(fmc, spec_fmc)
acq_d = [hex2signed(item) for item in acq_d]
acq_v = [digital2volt(item,ADC_FS,ADC_NBITS) for item in acq_d]
mean_v = get_mean_value(ADC_FS, ADC_NBITS, acq_d)
if(True == print_flag):
print('\n')
for channel in range(1,NB_CHANNELS+1):
print('Channel %d: mean voltage = %2.9fV')%(channel, mean_v[channel-1])
if(True == plot_flag):
plot_all(acq_v, mean_v, ADC_FS/2.0)
return mean_v
# Calculates ADC + input stage gain
def calc_ga(Vm1, Vm2, Vref1):
return ((Vm2-Vm1)/Vref1)
# Calculates ADC + input stage offset
def calc_oa(Vm2, Vm3, Vm4):
return (Vm2 + Vm3 - Vm4)
# Calculates DAC gain
def calc_gd(Vm1, Vm2, Vm3, Vref1, Vref2):
return ((Vref1*(Vm3-Vm1))/(Vref2*(Vm1-Vm2)))
# Calculates DAC offset
def calc_od(Vm1, Vm2, Vm3, Vm4, Vref1):
return ((Vref1*(Vm1-Vm2-Vm3+Vm4))/(Vm1-Vm2))
def main (default_directory = '.'):
# Load firmware to FPGA
load_firmware(default_directory)
# Objects declaration
spec = rr.Gennum() # bind to the SPEC board
spec_fmc = spec_fmc_adc.CSpecFmcAdc100Ms(spec)
fmc = fmc_adc.CFmcAdc100Ms(spec)
usb_tty = find_usb_tty.CttyUSB()
awg_tty = usb_tty.find_usb_tty(AWG_USB_VENDOR_ID, AWG_USB_PRODUCT_ID)
box_tty = usb_tty.find_usb_tty(BOX_USB_VENDOR_ID, BOX_USB_PRODUCT_ID)
#print "AWG:%s"%awg_tty[0]
#print "BOX:%s"%box_tty[0]
gen = Agilent33250A(device=awg_tty[0], bauds=RS232_BAUD)
sine = SineWaveform()
box = calibr_box.CCalibr_box(box_tty[0])
box_eeprom = cp210x_eeprom.CCP210x_Eeprom("%X"%BOX_USB_VENDOR_ID, "%X"%BOX_USB_PRODUCT_ID)
box_calibr_data = box_eeprom.get_calibr_data()
# Enable "DMA finished" IRQ
spec_fmc.set_irq_en_mask(0x1)
# Initialise fmc adc
fmc_adc_init(spec, fmc)
# Connect to AWG
gen.connect()
# Switch AWG output OFF
gen.output = False
# Measure FMC and carrier temperature
print('SPEC temperature: %3.3f°C') % spec_fmc.get_temp()
print('FMC temperature : %3.3f°C') % fmc.get_temp()
# Open all switches, reset offset DAC to mid-scale (0V)
for channel in range(1,NB_CHANNELS+1):
fmc.set_input_range(channel, 'OPEN')
fmc.set_input_term(channel, 'OFF')
fmc.dc_offset_reset()
#---------------------------------------------------------------------------
# Write DAC gain and offset corerection value to fmc class
#---------------------------------------------------------------------------
print('\nApply DAC correction\n----------------------------------')
print('DACs are precise enough.\nDo not apply any correction.')
"""
dac_gain_corr = [1/item for item in gd]
dac_offset_corr = [-item for item in od]
fmc.set_dac_corr(dac_gain_corr, dac_offset_corr)
for channel in range(1,NB_CHANNELS+1):
print('CH%d DAC offset correction:%1.9f')%(channel,dac_offset_corr[channel-1])
print('CH%d DAC gain correction :%1.9f')%(channel,dac_gain_corr[channel-1])
#---------------------------------------------------------------------------
# Test
#---------------------------------------------------------------------------
print('\nChannel input = 0V, offset DAC = 0V\n----------------------------------')
#raw_input('...')
set_box_dac_range(box, fmc, 'AWG', 0.0, 'CAL_100mV', True)
mean_v = channels_mean(spec_fmc, fmc, ADC_FS, True)
#plot_all(acq_v, mean_v, ADC_FS/2.0)
"""
#---------------------------------------------------------------------------
# Write ADC + input stage gain and offset correction to hardware
#---------------------------------------------------------------------------
print('\nApply ADC offset correction\n----------------------------------')
#fmc.print_adc_core_config()
#adc_gain_corr = [int(round((1/item)*0x8000)) for item in ga]
adc_gain_corr = [0x8000] * 4
adc_offset_corr = [-(volt2digital_without_offset(item,ADC_FS,ADC_NBITS)) for item in oa]
#adc_offset_corr = [0] * 4
for channel in range(1,NB_CHANNELS+1):
fmc.set_adc_gain_offset_corr(channel, adc_gain_corr[channel-1], adc_offset_corr[channel-1])
#fmc.print_adc_core_config()
for channel in range(1,NB_CHANNELS+1):
print('CH%d ADC offset correction write:0x%.8X read:0x%.8X')%(channel,adc_offset_corr[channel-1],fmc.get_adc_offset_corr(channel))
print('CH%d ADC gain correction write:0x%.8X read:0x%.8X')%(channel,adc_gain_corr[channel-1],fmc.get_adc_gain_corr(channel))
#---------------------------------------------------------------------------
# Test
#---------------------------------------------------------------------------
print('\nChannel input = 0V, offset DAC = 0V\n----------------------------------')
#raw_input('...')
set_box_dac_range(box, fmc, 'AWG', 0.0, 'CAL_100mV', True)
mean_v = channels_mean(spec_fmc, fmc, ADC_FS, True)
#---------------------------------------------------------------------------
# Write ADC + input stage gain and offset correction to hardware
#---------------------------------------------------------------------------
print('\nApply ADC gain correction\n----------------------------------')
#fmc.print_adc_core_config()
adc_gain_corr = [int(round((1/item)*0x8000)) for item in ga]
#adc_gain_corr = [0x8000] * 4
adc_offset_corr = [-(volt2digital_without_offset(item,ADC_FS,ADC_NBITS)) for item in oa]
#adc_offset_corr = [0] * 4
for channel in range(1,NB_CHANNELS+1):
fmc.set_adc_gain_offset_corr(channel, adc_gain_corr[channel-1], adc_offset_corr[channel-1])
#fmc.print_adc_core_config()
for channel in range(1,NB_CHANNELS+1):
print('CH%d ADC offset correction write:0x%.8X read:0x%.8X')%(channel,adc_offset_corr[channel-1],fmc.get_adc_offset_corr(channel))
print('CH%d ADC gain correction write:0x%.8X read:0x%.8X')%(channel,adc_gain_corr[channel-1],fmc.get_adc_gain_corr(channel))
#---------------------------------------------------------------------------
# Test
#---------------------------------------------------------------------------
print('\nChannel input = 0V, offset DAC = 0V\n----------------------------------')
#raw_input('...')
set_box_dac_range(box, fmc, 'AWG', 0.0, 'CAL_100mV', True)
mean_v = channels_mean(spec_fmc, fmc, ADC_FS, True)
#---------------------------------------------------------------------------
# Test
#---------------------------------------------------------------------------
print('\nChannel input = 0V, offset DAC = Vref = 0.04096V\n----------------------------------')
#raw_input('...')
set_box_dac_range(box, fmc, 'AWG', 0.04096, 'CAL_100mV', True)
mean_v = channels_mean(spec_fmc, fmc, ADC_FS, True)
#---------------------------------------------------------------------------
# Test
#---------------------------------------------------------------------------
print('\nChannel input = 0V, offset DAC = -Vref = -0.04096V\n----------------------------------')
#raw_input('...')
set_box_dac_range(box, fmc, 'AWG', -0.04096, 'CAL_100mV', True)
mean_v = channels_mean(spec_fmc, fmc, ADC_FS, True)
#---------------------------------------------------------------------------
# Test
#---------------------------------------------------------------------------
print('\nChannel input = Vref = 0.04096V, offset DAC = 0V\n----------------------------------')
#raw_input('...')
set_box_dac_range(box, fmc, '100mV', 0.0, '100mV', True)
mean_v = channels_mean(spec_fmc, fmc, ADC_FS, True)
# Open all switches, reset offset DAC to mid-scale (0V)
for channel in range(1,NB_CHANNELS+1):
fmc.set_input_range(channel, 'OPEN')
fmc.set_input_term(channel, 'OFF')
fmc.dc_offset_reset()
# Close AWG
gen.close()
# Check if an error occured during frequency response test
#if(error != 0):
# raise PtsError('An error occured during frequency response test, check log for details.')
if __name__ == '__main__' :
main()
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