`include "discipline.h"
`include "constants.h"
//--------------------
// adc_dnl_8bit
//
// - 8 bit ADC DNL measurement
//
// vd0..vd7: data lines from ADC [V,A]
// vout: voltage sent from conversion to ADC [V,A]
// vclk: Clocking signal for the ADC [V,A]
//
// INSTANCE parameters
// vlogic_high = [V]
// vlogic_low = [V]
// tsettle = time to allow for settling after the data lines are
// changed before 'vd0-7' are recorded [s]
// - also the period of the ADC conversion clock.
// vstart = voltage at which start conversion sweep []
// vend = voltage at which end conversion sweep []
// log_to_file = whether to log the results to a file; yes or no []
// filename = the name of the file in which the results are logged []
//
// MODEL parameters
// {none}
//
// Measures an 8 bit ADC's DNL using a histogram method. 'vout' is
// sequentially set to 4096 equally spaced voltages between 'vstart' and
// 'vend'. At each different value of 'vout' a clock pulse in generated
// causing the ADC to convert this 'vout' value. The resultant code of
// each conversion is stored.
//
// When all the conversions have been done, the DNL is calculated from
// the recorded data.
//
// If 'log_to_file' is 'yes', then the DNL (differential non-linearity) is
// recorded and writen to the file, 'filename'.
//
module adc_dnl_8bit(vd7, vd6, vd5, vd4, vd3, vd2, vd1, vd0, vout, vclk);
electrical vd7, vd6, vd5, vd4, vd3, vd2, vd1, vd0;
electrical vout, vclk;
parameter real tsettle=200n from (0:inf);
parameter real vlogic_high=5.0;
parameter real vlogic_low=0.0;
parameter real vstart=0.0;
parameter real vend=0.0;
parameter integer log_to_file = 0;
`define NUM_ADC_BITS 8
`define NUM_OF_CODES 256
`define NUM_OF_CONVS 4096
integer out_file;
// for generating vout levels
integer conv; // conversion number
real vout_inc;
real vout_val;
// for dnl calculations
integer i;
real vtrans;
integer just_finished; // flag for doing dnl calculations
integer code_val[0:`NUM_OF_CONVS-1];
integer bucket[0:`NUM_OF_CODES-1]; // holds number of code hits for each code
real width [0:`NUM_OF_CODES-1]; // holds the code width calculations
real dnl [0:`NUM_OF_CODES-1]; // dnl for each code
integer total_hits; // totals hits between codes 1 and 254
real max_dnl;
integer max_dnl_code;
// for generating clock
//
real tnext_high;
real tnext_low;
real vclk_val;
analog begin
@ ( initial_step ) begin
vtrans = vlogic_high/2;
vout_inc = (vend-vstart)/(`NUM_OF_CONVS-1);
vout_val = vstart;
for (i=0; i < `NUM_OF_CODES; i = i + 1) begin
bucket[i] = 0;
end
tnext_high = tsettle/2;
tnext_low = tsettle;
end
@ ( timer(tnext_high) ) begin
tnext_low = tnext_high + tsettle/2;
tnext_high = tnext_high + tsettle;
vclk_val = vlogic_high;
// record the code value
code_val[conv] = 0;
code_val[conv] = code_val[conv] + (V(vd0) > vtrans)*1;
code_val[conv] = code_val[conv] + (V(vd1) > vtrans)*2;
code_val[conv] = code_val[conv] + (V(vd2) > vtrans)*4;
code_val[conv] = code_val[conv] + (V(vd3) > vtrans)*8;
code_val[conv] = code_val[conv] + (V(vd4) > vtrans)*16;
code_val[conv] = code_val[conv] + (V(vd5) > vtrans)*32;
code_val[conv] = code_val[conv] + (V(vd6) > vtrans)*64;
code_val[conv] = code_val[conv] + (V(vd7) > vtrans)*128;
// get setup for the next conversion
conv = conv + 1;
vout_val = conv*vout_inc + vstart;
if (conv==`NUM_OF_CONVS) begin
just_finished=1;
tnext_low=inf;
tnext_high=inf;
vout_val = vend;
end
end
@ (timer(tnext_low)) begin
vclk_val = vlogic_low;
end
if (just_finished) begin // calculate the dnl function
just_finished = 0;
for (i=0; i < `NUM_OF_CONVS; i = i + 1) begin
bucket[(code_val[i])] = bucket[(code_val[i])] + 1;
end
for (i=1; i < `NUM_OF_CODES-1; i = i + 1) begin
total_hits = total_hits + bucket[i];
end
for (i=1; i < `NUM_OF_CODES-1; i = i + 1) begin
width[i] = 1.0*bucket[i]/total_hits*(`NUM_OF_CODES-2);
end
max_dnl = 0;
max_dnl_code = 0;
for (i=1; i < `NUM_OF_CODES-1; i = i + 1) begin
dnl[i] = width[i] - 1;
if (max_dnl < abs(dnl[i])) begin
max_dnl = abs(dnl[i]);
max_dnl_code = i;
end
end
// log the results to a file if desired
//
if (log_to_file) begin
out_file = $fopen( "%C:r.dat" );
$fstrobe(out_file,"# Generated by Spectre from `%M'");
for (i=0; i < `NUM_OF_CODES; i = i + 1) begin
$fstrobe(out_file,"%d\t%f",i,dnl[i]);
end
$fclose(out_file);
$strobe("Max DNL is %f at code %d",max_dnl,max_dnl_code);
end
end
V(vclk) <+ transition(vclk_val,0,30u,30u);
V(vout) <+ transition(vout_val,0,30u,30u);
end
endmodule
               (
geocities.com/fudinggeadc)