From 063cb6e679276ef852be62edbd3d18c607ce5e42 Mon Sep 17 00:00:00 2001 From: Andreas Neiser Date: Mon, 1 Dec 2014 13:36:41 +0100 Subject: [PATCH] adc.pl: improved phase optimization with newest FPGA firmware --- tools/adc.pl | 237 +++++++++++++++++++++++++++------------------------ 1 file changed, 125 insertions(+), 112 deletions(-) diff --git a/tools/adc.pl b/tools/adc.pl index 7242ddf..227ee5b 100755 --- a/tools/adc.pl +++ b/tools/adc.pl @@ -25,7 +25,7 @@ unless(defined $ARGV[0] && defined $ARGV[1]) { print "\t",' adc_reg $addr $val',"\t write to register of all ADCs, arguments are oct()'ed\n"; print "\t",' adc_testio $id',"\t enable testio of all ADCs, id=0 disables\n"; print "\t",' adc_phase $phase [ADCs]',"\t set the clock-data output phase\n"; - print "\t",' adc_testall',"\t test all ADC channels with patterns\n"; + print "\t",' adc_testall',"\t test ADC LVDS communication with pattern\n"; exit; } @@ -272,33 +272,24 @@ if ($ARGV[1] eq "init") { # init stuff &lmk_init; &adc_init; - - # set the ADC phase to 0x0 - # this is mandatory in order to get - # working communication! - #sendcmd_adc(0x16, 0b0); - #sendcmd_adc(0xFF, 0x1); - #print ">>> Phase set to 0°, your board should be working now...\n"; + while(1) { + print ">>> Optimizing ADC phases...\n"; + &set_optimal_phases; + print ">>> Check ADCs again...\n"; + my @good = &adc_testall; + #print Dumper(\@good); + # check if all ADCs are good + if(@good == grep { $_ } @good) { + last; + } + else { + print ">>> Some ADCs are not working, retrying...\n"; + #exit; + } + } + print ">>> Your board should be working now...\n"; } -# sub read_channels { -# my @result; -# my $ctrlreg = 0xa081; -# trb_register_write($board,$ctrlreg,0); -# usleep(100000); -# trb_register_write($board,$ctrlreg,2); -# for (my $ch=0;$ch<48;$ch++) { -# my $r = trb_register_read_mem($board,0xa000+$ch,1,300); -# push(@result, $r->{$board}); -# #print Dumper($r); -# } -# trb_register_write($board,$ctrlreg,0); - -# return @result; -# } - - - sub read_rates { my $addr=shift; my $size=shift; @@ -307,7 +298,7 @@ sub read_rates { my $mask = 0; $mask |= (1<<$_) for ($start..$start+$bits-1); - my $us = 1000000; + my $us = 100000; # read it my $r1 = trb_register_read_mem($board,$addr,0,$size); usleep($us); @@ -321,106 +312,128 @@ sub read_rates { my $val2 = ($r2->[$i] & $mask) >> $start; # detect overflow if($val2<$val1) { - print "Overflow\n"; + #print "Overflow\n"; $val2 += 1<<$bits; } my $t1 = 0; #$r1->{time}->[$i]; my $t2 = $us/1e6; # $r2->{time}->[$i]; my $rate = ($val2-$val1)/($t2-$t1); #print $r2->{value}->[$i]-$r1->{value}->[$i],"\n"; - print $val2-$val1," ",$rate,"\n"; + #print $val2-$val1," ",$rate,"\n"; + push(@rates,$rate); } - #print - #print $bits,"\n"; - #print 36 & vec($mask, 0, 32),"\n"; - return \@rates; + return @rates; } if ($ARGV[1] eq "adc_testall") { $verbose=0; - @adcs=(0); + my @good = &adc_testall; + for my $adc (0..11) { + printf("ADC %02d: %s\n",$adc, + $good[$adc] ? "Working" : "NOT WORKING!!!"); + } +} + +sub adc_testall { + my @phases = @{(shift || [-1])}; # by default dont change phases + + # checkerboard, sends 0x2aa and 0x155 as ADC words + adc_testio(0b0100); + trb_register_write($board, 0xa019, 0x015502aa); + # midscale short + #adc_testio(0b0001); + #trb_register_write($board, 0xa019, 0x02000200); + + my @good_ranges; + for my $phase (@phases) { + #print "Setting phase to ",$phase*60,"\n"; + adc_phase($phase) if $phase>=0; + # word counts per ADC (12 items) at 0xa030 (upper 28bits) + my @word_rates = read_rates(0xa030, 12, 4, 28); + + # invalid words per channel (4x12=48 items) at 0xa8c0 + # use only upper 31 bits to account for overflow + my @invalid_rates = read_rates(0xa8c0, 48, 1, 31); + + for my $adc (0..11) { + my $word_rate = $word_rates[$adc]; + my $MS = 4e7; # assume 40MS ADC... + my $good = $word_rate > 0.98*$MS; + for my $i (0..3) { + my $ch = $adc*4+$i; + my $invalid_rate = $invalid_rates[$ch]; + $good &= $invalid_rate==0 ? 1 : 0; + } + #printf("%02d %.0f %d\n", $adc, $word_rate, $good); + if($phase<0) { + $good_ranges[$adc] = $good; + } + else { + $good_ranges[$adc]->[$phase] = $good; + $good_ranges[$adc]->[$phase+@phases] = $good; # another copy to account for cyclic phase + } + } + } - # word counts per ADC (12 items) at 0xa030 (upper 28bits) - my $word_counts = read_rates(0xa030,12,4,28); + # disable testio again + adc_testio(0); + trb_register_write($board, 0xa019, 0x0); - print Dumper($word_counts); + return @good_ranges; } -# if ($ARGV[1] eq "adc_testall") { -# $verbose=0; - -# # set pattern to checkerboard, -# # should give alternating 0x155, 0x2aa, 0x155, 0x2aa ... -# my $ok_checkerboard = 1; -# adc_testio(0b0100); -# my @r = read_channels(); -# #print Dumper(\@r); -# for(my $ch=0;$ch<@r;$ch++) { -# my @vals = map { $_ & 0x3ff } @{$r[$ch]}; -# # look at first value +sub set_optimal_phases { + $verbose=0; + + my $max_phase = 0b1011; + + my @good_ranges = adc_testall([0..$max_phase]); -# my @checkerboard; -# my $firstval = $vals[0]; -# if($firstval == 0x2aa) { -# @checkerboard = (0x2aa, 0x155); -# } -# elsif($firstval == 0x155) { -# @checkerboard = (0x155, 0x2aa); -# } -# else { -# printf("ERROR: First value 0x%x from checkerboard not recognized, ch=$ch\n",$firstval); -# $ok_checkerboard = 0; -# next; -# } - - -# # compare the remaining values -# for(my $i=1;$i<@vals;$i++) { -# if($vals[$i] != $checkerboard[$i % 2]) { -# printf("ERROR: Value 0x%x (idx=$i) from checkerboard not recognized, ch=$ch\n",$vals[$i]); -# $ok_checkerboard = 0; -# last; -# } -# } -# } -# if($ok_checkerboard) { -# print ">>> Tested all channels with checkerboard pattern successfully\n"; -# } -# else { -# print ">>> Test with checkerboard failed, see above.\n"; -# } - -# # set testmode to mixed frequency, -# # should give 0b1001100011 -# adc_testio(0b1100); -# my $ok_mixed = 1; -# @r = read_channels(); -# for(my $ch=0;$ch<@r;$ch++) { -# my @vals = map { $_ & 0x3ff } @{$r[$ch]}; - -# for(my $i=0;$i<@vals;$i++) { -# if ($vals[$i] != 0b1001100011) { -# printf("ERROR: Value 0x%x (idx=$i) from mixed-frequency not recognized, ch=$ch\n", $vals[$i]); -# $ok_mixed = 0; -# last; -# } -# } -# } -# if($ok_checkerboard) { -# print ">>> Tested all channels with mixed frequency pattern successfully\n"; -# } -# else { -# print ">>> Test with mixed-frequency pattern failed\n"; -# } -# # disable testio -# adc_testio(0); - -# if($ok_checkerboard && $ok_mixed) { -# print ">>> All ADC channels seem to be nicely working with testpatterns!\n"; -# } -# else { -# print ">>> Test of ADC channels failed :(((\n"; -# } -#} + # find the optimal phases as largest + # consecutive range of good state + # then set the phases for each ADC individually + my @old_adcs = @adcs; + for my $adc (0..11) { + my @good = @{$good_ranges[$adc]}; + #printf("%02d %s\n", $adc, join(' ',@good)); + # search for largest consecutive ones in @good + my $start = -1; + my $max_length = 0; + my $opt_phase = -1; + #my $end = -1; + for(my $i=0;$i<@good;$i++) { + if($start<0) { + if($good[$i]) { + #print "Found start at $i\n"; + $start=$i; + } + } + else { + if(!$good[$i] || $i==@good-1) { + my $length = $i - $start + ($i==@good-1); + #print "Found stop at $i with length $length\n"; + if($length>$max_length) { + $max_length=$length; + $opt_phase = int($start+$length/2) % ($max_phase+1); + } + $start = -1; + } + } + } + if($opt_phase<0) { + print "Warning: No optimal phase found for ADC $adc, guessing 0\n"; + $opt_phase=0; + } + #print "Opt phase: $opt_phase Max length $max_length\n"; + + # now set them for each ADC + @adcs = ($adc); # used by adc_phase + adc_phase($opt_phase); + #printf("Set ADC %02d to optimal phase of %03d degrees\n", $adc, $opt_phase*60); + } + + @adcs = @old_adcs; +} + -- 2.43.0