This page has a simple version of what you need to test the Analog Devices AD5541A 16 bit 1 Ms/s DAC mounted on a Digilent Pmod DA3. I am using a NandLand GoBoard, but this code can be easily ported to other environments.
Top level module
///////////////////////////////////////////////////////////////////////////////
// File downloaded from https://halverscience.net
///////////////////////////////////////////////////////////////////////////////
// Demonstrates and test Digilent's Pmod DA3 digital-to-analog converter
// using the Nandland.com GoBoard
// The DAC is to be plugged into the 2nd port of the Pmod connector, i.e., the
// 2nd row of holes.
// The DAC is fed various 16 bit patterns depending on which Make_Test_Waveform module
// you use. The sample rate is 1 MHz.
// Created 7/2020 by Peter Halverson.
///////////////////////////////////////////////////////////////////////////////
`default_nettype none // Use this to find undeclared wires. Optional.
module DAC_Test_Top
(input wire i_Clk, // Main Clock, 25 MHz
output wire o_Segment1_A, // Segment1 is upper digit, Segment2 is lower digit
output wire o_Segment1_B, output wire o_Segment1_C, output wire o_Segment1_D,
output wire o_Segment1_E, output wire o_Segment1_F, output wire o_Segment1_G,
output wire o_Segment2_A, output wire o_Segment2_B, output wire o_Segment2_C,
output wire o_Segment2_D, output wire o_Segment2_E, output wire o_Segment2_F,
output wire o_Segment2_G,
output wire o_LED_1, output wire o_LED_2, output wire o_LED_3, output wire o_LED_4,
output wire io_PMOD_1, // Wiring to the ADC board ~ chip select (active low)
//input io_PMOD_2, // data from ADC 0
output wire io_PMOD_2, // temporary mirror of data to DAC
input wire io_PMOD_3, // data from ADC 1 (not used)
output wire io_PMOD_4, // clock to read out data
output wire io_PMOD_7, // Wiring to the DAC board ~ chip select (active low)
output wire io_PMOD_8, // data to DAC 0
output wire io_PMOD_9, // data to ADC 1 (not used)
output wire io_PMOD_10, // clock to read out data
input wire i_Switch_1, // Wires to the switches. Not used now, but useful for debugging.
input wire i_Switch_2, input wire i_Switch_3, input wire i_Switch_4,
output wire o_VGA_HSync, // VGA connector
output wire o_VGA_VSync, // I'm using this to trigger the oscilloscope (3rd row, 2nd hole)
// Ground is 2nd row, last hole, to the right.
output wire o_VGA_Red_0, output wire o_VGA_Red_1, output wire o_VGA_Red_2,
output wire o_VGA_Grn_0, output wire o_VGA_Grn_1, output wire o_VGA_Grn_2,
output wire o_VGA_Blu_0, output wire o_VGA_Blu_1, output wire o_VGA_Blu_2
);
wire w_Sample_Clock; // 1 MHz. This is the max speed of the DA3 module.
Make_Sample_Clock
Make_Sample_Clock_inst(
.i_Clk(i_Clk), // 25 MHz clock goes in
.o_Sample_Clock(w_Sample_Clock) // 1 MHz comes out
);
wire [15:0] w_Waveform;
// -------------------------Here is where you can choose which waveform.----------------
Make_Test_Waveform_Sawtooth
//Make_Test_Waveform_Growing_Squarewave
Make_Test_Waveform(
.i_Clk(i_Clk),
.i_Sample_Clock(w_Sample_Clock),
.o_Waveform(w_Waveform),
.o_Scope_Trigger(o_VGA_VSync)
);
// GoBoard's PMOD connector
// Looking at the connector into the holes, you see two rows of 6 holes:
// oooooo 1st row
// oooooo 2nd row
//
// The first row, which is for PMOD module 1, going left-to-right is
// Pin 6, VCC (+3.3 V)
// Pin 5, Ground
// Pin 4, Port 1 pin 4 (usually a clock signal to the module)
// Pin 3, Port 1 pin 3 (can be data or other signal)
// Pin 2, Port 1 pin 2 (usually data to or from the module)
// Pin 1, Port 1 pin 1 (usually a select or "activate" signal, active low, to the module)
//
// The second row, which is for PMOD module 2, going left-to-right is
// Pin 12, VCC (+3.3 V)
// Pin 11, Ground
// Pin 10, Port 2 pin 4 (usually a clock signal to the module)
// Pin 9, Port 2 pin 3 (can be data or other signal)
// Pin 8, Port 2 pin 2 (usually data to or from the module)
// Pin 7, Port 2 pin 1 (usually a select or "activate" signal, active low, to the module)
// Comments apply to the Pmod DA3. (The Pmod DA2 is different)
wire w_Pmod_Port2_Pin1; // ~CS, Pull low when moving data into the DAC
wire w_Pmod_Port2_Pin2; // DIN Data stream going to the DAC. 16 bits.
wire w_Pmod_Port2_Pin3; // ~LDAC, Falling edge or holding low activates the DAC
wire w_Pmod_Port2_Pin4; // SCLK, DAC Clock. Data bits are latched on rising edge of this clock.
Send_To_DAC_Pmod_DA3 Send_To_DAC_Pmod_DA3_inst(
.i_Clk(i_Clk),
.i_Data_Valid(w_Sample_Clock),
.i_DAC_Data(w_Waveform),
.o_notCS(w_Pmod_Port2_Pin1),
.o_notLDAC(w_Pmod_Port2_Pin3),
.o_Sclk(w_Pmod_Port2_Pin4),
.o_Serial_Data(w_Pmod_Port2_Pin2)
);
// Wires to the DAC
assign io_PMOD_7 = w_Pmod_Port2_Pin1;//Chip select signal, active low
assign io_PMOD_1 = w_Pmod_Port2_Pin1;//DUPLICATE for easier connection to oscilloscope
assign io_PMOD_8 = w_Pmod_Port2_Pin2;//Serial data out to DAC
assign io_PMOD_2 = w_Pmod_Port2_Pin2;//DUPLICATE for easier connection to oscilloscope
assign io_PMOD_9 = w_Pmod_Port2_Pin3;//~LDAC, When pulled down, activates the DAC.
//(See AD5541A data sheet)
assign io_PMOD_10 = w_Pmod_Port2_Pin4;//25 MHz clock to clock in the serial data stream
assign io_PMOD_4 = w_Pmod_Port2_Pin4; //DUPLICATE for easier connection to oscilloscope
assign o_Segment1_A = 1; //Turn off the 7 segment displays
assign o_Segment1_B = 1; assign o_Segment1_C = 1; assign o_Segment1_D = 1;
assign o_Segment1_E = 1; assign o_Segment1_F = 1; assign o_Segment1_G = 1;
assign o_Segment2_A = 1; assign o_Segment2_B = 1; assign o_Segment2_C = 1;
assign o_Segment2_D = 1; assign o_Segment2_E = 1; assign o_Segment2_F = 1;
assign o_Segment2_G = 1;
assign o_LED_1 = 0; // Turn off the LEDs (because they are annoying)
assign o_LED_2 = 0; assign o_LED_3 = 0; assign o_LED_4 = 0;
endmodule
`default_nettype wire // Sets the default back to the usual.
Make_Test_Waveform_Sawtooth.
Module to make a sawtooth that uses all 65536 DAC codes.
///////////////////////////////////////////////////////////////////////////////
// File downloaded from https://halverscience.net
///////////////////////////////////////////////////////////////////////////////
// Generates a sawtooth wave to test the Digilent Pmod DA3 DAC.
// Since the sawtooth tries all 2**16 cominations at a 1 MHz sample rate
// the output frequency will be 1 MHz / 2**16 = 15.258 Hz
// Author: Peter Halverson 7/2020
///////////////////////////////////////////////////////////////////////////////
`default_nettype none // Use this to find undeclared wires. Optional.
module Make_Test_Waveform_Sawtooth (
input wire i_Clk,
input wire i_Sample_Clock,
output wire [15:0] o_Waveform,
output wire o_Scope_Trigger
);
reg [15:0] r_Waveform;
always @(posedge i_Sample_Clock) begin
r_Waveform <= r_Waveform + 1; // This will make a sawtooth
end //always
assign o_Waveform = r_Waveform;
assign o_Scope_Trigger = r_Waveform[15]; // Used to sync my oscilloscope for a stable display
endmodule
`default_nettype wire // Sets the default back to the usual.
Make_Test_Waveform_Growing_Squarewave
Module to produces a 500 kHz squarewave, sawtooth modulated.
The benefit of this test is that it will detect issues with rapidly changing DAC codes and fast analog slewrates. (It helped me discover a subtle bug in my Verilog having to do with unspecified state machine states.)
The problem with this test is that it drives digital oscilloscopes crazy. Beware of aliasing!
///////////////////////////////////////////////////////////////////////////////
// File downloaded from https://halverscience.net
///////////////////////////////////////////////////////////////////////////////
// Generates a 500 KHz square wave modulated by a sawtooth wave to test the
// Digilent Pmod DA3 DAC.
// Since the sawtooth tries all 2**16 cominations at a 1 MHz sample rate
// the output frequency will be 1 MHz / 2**16 = 15.258 Hz
// Author: Peter Halverson 7/2020
///////////////////////////////////////////////////////////////////////////////
`default_nettype none // Use this to find undeclared wires.
module Make_Test_Waveform_Growing_Squarewave (
input wire i_Clk,
input wire i_Sample_Clock,
output wire [15:0] o_Waveform,
output wire o_Scope_Trigger
);
reg [15:0] r_Waveform;
reg [15:0] r_Counter;
always @(posedge i_Sample_Clock) begin
r_Counter <= r_Counter + 1; // This will make a sawtooth
if (r_Counter[0] == 1'b1) begin
//r_Waveform <= 16'hffff;
r_Waveform[15] <= 1'b1;
r_Waveform[14:0] <= r_Counter[15:1]; // This makes a sawtooth that begins at
// 1000 0000 0000 0000 and ends at 1111 1111 1111 1111
end else begin
//r_Waveform <= 16'h0000;
r_Waveform[15] <= 1'b0;
r_Waveform[14:0] <= ~r_Counter[15:1]; // This makes a sawtooth that begins at
// 0111 1111 1111 1111 and ends at 0000 0000 0000 0000
end
end //always
assign o_Waveform = r_Waveform;
assign o_Scope_Trigger = r_Counter[15]; // Used to sync the oscilloscope for a stable display
endmodule
`default_nettype wire // Sets the default back to the usual.
Send_To_DAC_Pmod_DA3.
Module to serialize and send data to the DAC.
///////////////////////////////////////////////////////////////////////////////
// File downloaded from https://halverscience.net
///////////////////////////////////////////////////////////////////////////////
// Serializes and sends data to an Analog Devices AD5541 16 bit DAC mounted on a
// Digilent Pmod DA3 digital-to-analog converter board.
// Created 7/2020 by Peter Halverson.
///////////////////////////////////////////////////////////////////////////////
// AD5541 max clock frequency is 50 MHz. We're using 25 MHz.
// DAC expects a serial data stream 16 bits long. MSB first.
`default_nettype none // Use this to find undeclared wires.
module Send_To_DAC_Pmod_DA3 (
input wire i_Clk,
input wire i_Data_Valid,
input wire [15:0] i_DAC_Data,
output reg o_notCS, // Hold low to make chip accept data bits
output wire o_notLDAC, // Either hold low to make chip output on receipt of last bit, or
// pull low when you want the output to happen.
output wire o_Sclk, // DAC accepts data bits on RISING edges of this clock.
output reg o_Serial_Data
);
parameter IDLE = 1'b0;// State Machine states (Only two; I could have used an if statement)
parameter SEND_BITS = 1'b1;
reg r_SM_Main;
reg [14:0] Output_Buffer;
reg [4:0] Bit_Count;
always @(posedge i_Clk) begin
case (r_SM_Main)
IDLE : begin
if (i_Data_Valid == 1'b1) begin
Bit_Count <= 4'b0000;
o_notCS <= 1'b0; // Start the DAC
o_Serial_Data <= i_DAC_Data[15]; //Send the MSB immediately
Output_Buffer <= i_DAC_Data[14:0]; //Will send the remaining bits later
r_SM_Main <= SEND_BITS;
end else begin
o_notCS <= 1'b1; // Keep the DAC inactive
o_Serial_Data <= 1'b0; // Just make the data out be zero (not needed?)
r_SM_Main <= IDLE;// Not needed? Well, yes it IS needed. In some cases the code won't
// work without it. WHY???
// Example: try the 500 kHz squarewave modulated by
// 15 Hz Sawtooth to see it not work.
end //if
end // case: IDLE
SEND_BITS : begin
if (Bit_Count == 4'b1111) begin
o_Serial_Data <= Output_Buffer[14];// Send last bit, which has been shifted to MSB
//The last bit has been sent
o_notCS <= 1'b1; // Deactivate the DAC
r_SM_Main <= IDLE;
end else begin
o_notCS <= 1'b0; // Keep the DAC active (Not needed?)
o_Serial_Data <= Output_Buffer[14]; // Send bit 14 of Output_Buffer
Output_Buffer <= Output_Buffer << 1; // Shift output buffer left one bit; moves next
// bit into bit 14.
Bit_Count <= Bit_Count + 1;
r_SM_Main <= SEND_BITS;// Not needed? Well, yes it's needed. In some cases the code won't
// work without it. WHY???
end //if
end //case: SEND_BITS
endcase
end //always
assign o_Sclk = ~i_Clk; //Invert the clock because the chip registers data bits on rising edges.
assign o_notLDAC = 1'b0; //Holding low to get immediate DAC output
endmodule
`default_nettype wire // Sets the default back to the usual.
Make_Sample_Clock
Module to make a 1 MHz clock for the DAC
///////////////////////////////////////////////////////////////////////////////
// File downloaded from https://halverscience.net
///////////////////////////////////////////////////////////////////////////////
// Takes the 25 MHz clock and divides it down to whatever low frequency is needed.
// Note the output is NOT symmetric. It is a 40 ns pulse (1/25 MHz = 40 ns) once every period.
// Author: Peter Halverson 7/2020
///////////////////////////////////////////////////////////////////////////////
`default_nettype none // Use this to find undeclared wires. Optional.
module Make_Sample_Clock (
input wire i_Clk, // 25 MHz clock in
output reg o_Sample_Clock
);
parameter DIVIDER = 25; // This gives 1 MHz
reg [4:0] r_Count; //5 bits needed
always @(posedge i_Clk) begin
if (r_Count == DIVIDER-1) begin
r_Count <= 0;
o_Sample_Clock <= 1;
end else begin
r_Count <= r_Count + 1;
o_Sample_Clock <= 0;
end
end //always
endmodule
`default_nettype wire // Sets the default back to the usual.