Creating a Sine Wave Function Generator with Mercury 2

Do you want to create your own Function Generator?

Function generators have a huge role in electronics. Very simply, a function generator is a piece of equipment used to produce sine, triangular, sawtooth, and square electrical waves over a wide range of frequencies (typically less than 20 MHz). They are primarily used for the development, testing, and repair of electronics. The sine wave in particular is important for use in analog circuit development.

Using the VHDL modules included below, you can create your own sine wave function generator by:

  • Using the Mercury 2’s on-board 10-bit Digital-to-Analog Converter (DAC) to produce the amplitude of the sine wave.

  • Implementing a Serial Peripheral Interface (SPI) system to provide the 10-bit phase amplitude to the DAC.

  • Utilizing a pipe-lined Coordinate Rotation Digital Computer (CORDIC) to calculate phase amplitude.

  • Implementing a simple phase accumulator to provide the phase to the CORDIC.

  • Defining the frequency of your sine wave (47.5 Hz to 100 kHz) by using the 5V tolerant I/O on the Mercury 2 development board.

As you can see, there are quite a few modules that provide some powerful tools to you in implementing your sine wave generator. Descriptions of how each of these modules work is provided, but is not necessary for you to start creating your own function generator now. It will also be noted that all of these modules are created with the Mercury 2’s development board in mind, however, some of the entities provided here can be implemented on any FPGA such as the CORDIC or SPI communication modules.


Create your Sine Wave Generator Now!

If you don’t want to have to deal with all the explanations and get to implementing your sine wave generator now, click the button below to download the .zip file and unzip the VHDL files for use in your Vivado 2018.2 project. For more information on how to use Vivado 2018.2 or how to create a project, check out the Getting Started Guide for the Mercury 2.


How Digital-to-Analog Converters Work

Digital-to-Analog Converters (DACs) are devices that convert a digital signal to an analog signal. These digital signals are typically fixed-point binary values with a fixed length. For example, the mcp4812 used on the Mercury 2 board uses a 10-bit binary signal while the mcp4802 uses an 8-bit binary signal and the mcp4822 uses a 12-bit binary number.



How a Coordinate Rotation Digital Computer Works

After installing Vivado 2018.2, launch the Project Navigator. This is found in:
Start > Xilinx Design Tools > Vivado 2018.2

From the "File" menu, select Project > New
After starting the project wizard by clicking “Next” enter in the project name and file location as shown.

After pressing "Next", determine the project type. For this project, select “RTL” as the project type. Since this is our first project, also select the “Do not specify sources at this time” checkbox.

Note: In the future, project source files and user constraint files can be added to the project prior to creation by ensuring the “Do not specify sources at this time” checkbox is left unchecked and then following the project wizard through the addition of source and constraint files.


After pressing “Next” we are presented with a list of devices that our project will be implemented on. Select the specific device (XC7A35TFTG256-1) by scrolling through the list or by entering the device into the search bar or entering the appropriate information into the filter tools. Click on the desired device and then click “Next”.

Mercury2_defaultPartSelection.PNG

After clicking "Next", we are asked to confirm our project settings.

Mercury2_newProjectSummary.PNG

After clicking "Finish", we are greeted with a fresh, new project window!

Mercury2_newProjectWindo.jpg

Step 3: Add the Mercury user constraints file

Next, we must add a user constraints file (UCF). This is very important; it is here that we specify:

  • Pin name and corresponding location

  • Pin voltage standard (LVTTL, LVCMOS, etc)

  • Timing constraints (clock period and duty cycle)

Below is an excerpt from the Mercury UCF file, dealing with the clock and three LEDs. The physical pin location for each of these signals is specified along with their voltage standard. For example, check the schematic, and one would see that pin N14 on the FPGA is connected to the 50MHz oscillator and that the voltage standard is LVCMOS 3.3V.

# on-board system oscillator
set_property -dict {PACKAGE_PIN N14 IOSTANDARD LVCMOS33} [get_ports {clk}]

# on-board user LEDs
set_property -dict {PACKAGE_PIN M1 IOSTANDARD LVCMOS33}  [get_ports {led[0]}]
set_property -dict {PACKAGE_PIN A14 IOSTANDARD LVCMOS33} [get_ports {led[1]}]
set_property -dict {PACKAGE_PIN A13 IOSTANDARD LVCMOS33} [get_ports {led[2]}]

The complete User Constraint File can be downloaded for the Mercury 2 board by clicking on the button below to download the file.

After downloading the UCF, unzip it, then add it to the project by right-clicking the “Constraints” folder from the hierarchy section of the Sources window and selecting “Edit Constraints Sets…”.

Mercury2_addUCF.jpg

Next click on the “Add Files” and navigate the file explorer to the UCF that you downloaded. Once the file is added to the project constraints, click “OK”.

Mercury2_addUCF2.PNG

The UCF is now added to your project! You can verify the addition of the file by checking the Constraints folder in the Sources window for Mercury2.xdc.

Mercury2_UCF.jpg

Step 4: Write some VHDL code!

Let's create a VHDL file and make a simple design. Right-click the “Design Sources” folder from the hierarchy section of the Sources window and select “Add Sources..”.

Mercury2_addSource.jpg

From the “Add Sources” wizard, select the “Add or create design sources” from the radio button choices then click “Next”.

Mercury2_addSource2.PNG

Create a new source file by clicking on the “Create File” button. Specify file type as VHDL and name the file the same as the project. In this case, the file name will be “led_demo”. Finish the creation of the source file by specifying file location as “Local to Project” and click “OK”.

Mercury2_addSource3.PNG

Complete the addition of the VHDL source file by clicking the “Finish” button.

Mercury2_addSource4.PNG

Optional: Input and Output ports can be added to the source VHDL file by defining them as shown in the image below. Inputs and Outputs can also be hard coded in the VHDL file later.

Mercury2_addSource5.PNG

You can verify the addition of the source VHDL file by checking the “Design Sources” folder in the Sources window.

Mercury2_Source.jpg

Let's go ahead and code a simple example that flashes the LEDs on and off, with a period of one second.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity led_demo is
  port
    (
      clk : in std_logic;
      led : out std_logic_vector(2 downto 0)    
    );
end led_demo;

architecture RTL of led_demo is

  signal count : integer range 0 to 49999999 := 0;
  signal pulse : std_logic := '0';

begin

  counter : process(clk)
  begin
    if clk'event and clk = '1' then
      if count = 49999999 then
        count <= 0;
        pulse <= not pulse;
      else
        count <= count + 1;
      end if;      
    end if;
  end process;

  led(2 downto 0) <= (others => pulse);

end RTL;

We want to flash an LED: on for 1 second, then off for 1 second.

To achieve this, we have written a "counter" process (that runs on the 50MHz clock) and counts from 0 to 49,999,999. After reaching the maximum value, it resets "count" register to zero, and flips the state of "pulse" register. All three LEDs have been wired to "pulse".


Step 5: Compile our design!

Let's go ahead and compile our design.

The Mercury 2 programmer requires a .bit file of the synthesized and implemented design of our project in order to run. All three processes can be done by clicking the “Generate Bitstream” option from the Flow Navigator window in Vivado. This will initiate design synthesis, implementation, and generate the bitstream for the project. The "Synthesize" process takes the hardware described in VHDL, and infers the logical building blocks (registers, state machines, adders, etc.) that were described. The "Implement" process takes this design and tries to implement it using the resources available on the FPGA.

Mercury2_generateBitstream.jpg

Step 6: Program the Mercury board

Now, let's program the Mercury 2 board with the bitstream we just generated!

The led_demo.bit file for the programmer can be found by navigating to the bit file found in the project folder - in this case: Mercury2 > led_demo > led_demo.runs > impl_1 > led_demo.bit
We will be using this bit file with the programmer to burn our design onto the flash chip used on the Mercury 2 board.

Mercury2_bitFile.PNG
12.PNG
 

Then click "Burn" to write this file to the FPGA.

 

The progress bar will scroll by as the flash chip is being written to. This process should take about 10 seconds.

 

The flash chip on the board has been programmed, and the FPGA will immediately boot using the newly programmed bitstream. (Since this is stored on flash, the bitstream is non-volatile.)

The LEDs should be flashing: on for one second, off for one second!

 

We are now up and running with Mercury!