Sunday 19 August 2018

Developing & Delivering KnowHow

Home > Knowhow > Verilog Designers Guide > Models > Analog to Digital Converter

Analog-to-Digital Converter

OK. We've had a few requests for a Verilog Model of the Month, so here it is. This month we'll present a model of an ADC. You might remember that we modelled an ADC in our April Model of the Month, so this allows us to contrast VHDL coding with Verilog coding.

The example we present is for a 16-bit ADC, but you can easily modify the digital output wordlength for any desired accuracy of ADC.

The 16-bit ADC model is built around a function, ADC_16b_10v_bipolar. Note there are no conversion operators in this code as there was with the VHDL code - Verilog simply doesn't need them due to its absence of data typing.

Note that we must specify a range for the returned value from the function in Verilog, in VHDL, a range constraint is not mandatory. Real-valued ports are not allowed in Verilog so we must use a 64-bit input port to maintain an accurate representation of the analogue signals.

All of the required Verilog code is here, there are no references to other external code modules (there are eight referenced packages in the VHDL code). In the VHDL model there are frequent references to conversion functions, in the Verilog code we can use the built-in $rtoi function.

The charge_ovr reg is intended to be accessed hierarchically from the testbench in order to determine whether reset_charge needs to be re-activated. A note for VHDL coders; hierarchical naming is allowed in Verilog - remember that in VHDL you always have to use ports and generics to allow hierarchy traversal.

You are welcome to use the source code we provide but you must keep the copyright notice with the code (see the Notices page for details).

// 16-bit Analogue-Digital Converter
//
// +-----------------------------+
// |    Copyright 1996 DOULOS    |
// |    designer : Tim Pagden    |
// |     opened:  7 Jun 1996     |
// +-----------------------------+

`timescale 1 ns / 1 ps

module ADC_16bit (analog_in,digital_out);

parameter conversion_time = 25.0, // conversion_time in ns
				  // (see `timescale above)
	  charge_limit = 1000000; // = 1 million

input[63:0] analog_in;

// double-precision representation of a real-valued input port;
// a fix that enables
// analog wires between modules to be coped with in Verilog.
// Think of input[63:0] <variable>
// as the equivalent of MAST's electrical.

output[15:0] digital_out;

reg[15:0] delayed_digitized_signal;
reg[15:0] old_analog,current_analog;
reg[4:0] changed_bits;
reg[19:0] charge;
reg charge_ovr;
reg reset_charge;

/* SIGNALS:-
analog_in = 64-bit representation of a real-valued signal
analog_signal = real valued signal recovered from analog_in
analog_limited = analog_signal, limited to the
			   real-valued input range of the ADC
digital_out = digitized 16bit 2's complement quantization of analog_limited
*/

/* function to convert analog_in to digitized_2s_comp_signal.
Takes analog_in values from (+10.0 v - 1LSB) to -10.0 v and converts
them to values from +32767 to -32768 respectively */

function[15:0] ADC_16b_10v_bipolar;

parameter max_pos_digital_value = 32767,
	  max_in_signal = 10.0;

input[63:0] analog_in;

reg[15:0] digitized_2s_comp_signal;

real analog_signal,analog_abs,analog_limited;
integer digitized_signal;

begin
  analog_signal = $bitstoreal (analog_in);
  if (analog_signal < 0.0)
  begin
    analog_abs = -analog_signal;
    if (analog_abs > max_in_signal)
      analog_abs = max_in_signal;
    analog_limited = -analog_abs;
  end
  else
  begin
    analog_abs = analog_signal;
    if (analog_abs > max_in_signal)
      analog_abs = max_in_signal;
    analog_limited = analog_abs;
  end
  if (analog_limited == max_in_signal)
    digitized_signal = max_pos_digital_value;
  else if (analog_limited == -max_in_signal)
    digitized_signal = -max_pos_digital_value;
  else
    digitized_signal = $rtoi (analog_limited * 3276.8);

  digitized_2s_comp_signal = digitized_signal;
  ADC_16b_10v_bipolar = digitized_2s_comp_signal;
end

endfunction

/* This function determines the number of digital bit changes from
sample to sample; can be used to determine power consumption if required.
Task power_determine not yet implemented */

function[4:0] bit_changes;

input[15:0] old_analog,current_analog;

reg[4:0] bits_different;
integer i;

begin
  bits_different = 0;
  for (i=0;i<=15;i=i+1)
    if (current_analog[i] != old_analog[i])
      bits_different = bits_different + 1;
  bit_changes = bits_different;
end

endfunction

/* Block to allow power consumption to be measured (kind of). Reset_charge
   is used to periodically reset the charge accumulated value (which can be
   used to determine current consumption and thus power consumption) */

always @ (posedge reset_charge)
begin
  charge = 0;
  charge_ovr = 0;
end

/* This block only triggered when analog_in changes by an amount greater
   than 1LSB, a crude sort of scheduler */

always @ (ADC_16b_10v_bipolar (analog_in))
begin
  current_analog = ADC_16b_10v_bipolar (analog_in); // digitized_signal
  changed_bits = bit_changes (old_analog,current_analog);
  old_analog = current_analog;
  charge = charge + (changed_bits * 3);
  if (charge > charge_limit)
    charge_ovr = 1;
end

/* Block to implement conversion_time tpd; always block use to show
   difference between block and assign coding style */

always
  # conversion_time delayed_digitized_signal = ADC_16b_10v_bipolar (analog_in);

assign digital_out = delayed_digitized_signal;

endmodule

To download the Verilog source code for this month's Model of the Month, click here.

To download a simple test fixture, click here.

Your e-mail comments are welcome - send email

Copyright 1995-2010 Doulos

Privacy Policy Site Map Contact Us