Sinus wave generator with Verilog and Vivado

5/5 - (23 votes)

This Verilog code generates a sinus wave in FPGAs. It is done with a lookup-table and we will cover different modes with variable and fixed frequency.

 

In this tutorial, I am going to demonstrate different methods to generate a sinus wave in an FPGA with Verilog and VHDL. I am going to program and test the functionality with Vivado 2017.4.

This is going to be divided into 3 parts: Fixed frequency, variable frequency and a PWM sinusoidal signal.

1- Fixed frequency sinus-signal

To generate a fixed sinus signal or any previously defined signal in an FPGA, the most efficient method is to preload and store the signal in the memory.

Why? Calculating the sinus math function is more resource-intensive and complicated than storing hundreds or thousands of values

So, the next two steps are clear: generating a sinus wave file and then load it from the FPGA.

Reading a memory file

The first problem we have to solve is how to store the sinus wave in the memory. Let’s review these 2 ways (maybe more) to load the memory values at the start:

1- Reading it from a file using the $readmemh command.

initial begin 
     $readmemh("sine.mem", rom_memory); 
end

2- Giving individual values of each memory register

initial begin
    rom_memory[0] = 0;
    rom_memory[1] = 201;
    ....
    rom_memory[1023] =-201;
end

In this example, I am going to read the data from the text file “sine.mem”, because it is a more scalable method. For that, the next Verilog code (After creating a new Testbench in Vivado):

module sinus_gen(
    input clk ,
    output reg [15:0] sinus
    );
parameter SIZE = 1024;    
reg [15:0] rom_memory [SIZE-1:0];
integer i;
initial begin
    $readmemh("sine.mem", rom_memory); //File with the signal
    i = 0;
end    
//At every positive edge of the clock, output a sine wave sample.
always@(posedge clk)
begin
    sinus = rom_memory[i];
    i = i+ 1;
    if(i == SIZE)
        i = 0;
end
endmodule

We need, of course, to add the file “sine.mem” as a new source file and later fill it with the signal values. First, let’s add the memory file in Vivado, this can be done easily:

Sine Look up Table Generation

The sinus table can be generated in multiple ways:

  • The smartest and better method would be to do it with Matlab or a python script.
  • The easiest and fastest one is to use an online sine generation tool.

There are many online tools like this. You must give the number of points and the amplitude:

Now, copy and paste the hexadecimal values in the Vivado mem file you already have created.

We precise slights modifications of the pasted values. They have to be raw and clean. We can do it quickly in the replace menu window with right-click over the mem file.

The ‘0x‘ and the comma must be removed.

 

 

 

 

 

 

 

Test bench

To create a functional block, a clock signal generator module is needed. The diagram should be as following:

The simulation results of this example with a clock frequency set to 50MHz:

Making zoom on the wave, we see that each clock cycle corresponds to a sinus step. The resulting frequency is therefore around 50 kHz (=50MHZ/1024)

2- Variable frequency sinus signal

The previous wave sine had a fixed frequency, dependant of the input clock. For this signal, we want to give a certain frequency as an input. For that, the previous block is modified as following:

The input “Frequency Control Word” (fcw) is continuously added to the phase accumulator, which corresponds mathematically to integration. This value corresponds to the phase angle x of a sine function sin(x), which is stored in a table, in this case, of 1024 values. The table map one full period. This table is implemented inside the ROM (Read-Only Memory).

The input width of the phase accumulator is 24-bit, and the 10 most significant bits are used as the address for the sine table, so that the phase resolution is 360/1024 = about 0.3 °.

The Verilog implementation:

`timescale 1ns / 1ps
module sine_dds(
        input clk ,
        input reset,
        input [23:0] fcw,
        output [15:0] dds_sin,
        output dds_clk,
        output dds_stb
            );
reg [15:0] rom_memory [1023:0];

initial begin
    $readmemh("sine.mem", rom_memory);
end

   reg [23:0] accu;
   reg [1:0] fdiv_cnt;
   wire accu_en;
   reg accu_msb_q;
   wire [9:0] lut_index;
	  
//process for frequency divider
always@( posedge clk)
begin
      if(reset == 1'b1)
         fdiv_cnt <= 0; //synchronous reset
      else if(accu_en == 1'b1)
         fdiv_cnt <= 0; 
      else    
         fdiv_cnt <= fdiv_cnt +1;    
end
//logic for accu enable signal, resets also the frequency divider counter
assign accu_en = (fdiv_cnt == 2'd2) ? 1'b1 : 1'b0;

//process for phase accumulator
always@(posedge clk)
begin
      if(reset == 1'b1)         
                accu <= 0; //synchronous reset
      else if(accu_en == 1'b1)
            accu <= accu + fcw;
end

//10 msb's of the phase accumulator are used to index the sinewave lookup-table
assign lut_index = accu[23:14];

//16-bit sine value from lookup table
assign dds_sin = rom_memory[lut_index];
endmodule

This can, of course, be in VHDL implemented. In VHDL the sinus table can easily be written inside the code (without reading from a file). I will show this solution in VHDL:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;

entity sine_dds is
    Port ( clk : in  STD_LOGIC;
           reset : in  STD_LOGIC;
           fcw : in  STD_LOGIC_VECTOR (23 downto 0);
           dds_sin : out  STD_LOGIC_VECTOR (15 downto 0);
           dds_clk : out  STD_LOGIC;
           dds_stb : out  STD_LOGIC);
end sine_dds;

architecture Behavioral of sine_dds is

   type rom_t is array (0 to 1023) of integer range -2**15 to 2**15-1;
   signal rom: rom_t := (
        0,  201,  402,  603,  804, 1005, 1206, 1407, 1608, 1809, 2009, 2210, 2410, 2611, 2811, 3012, 
     3212, 3412, 3612, 3811, 4011, 4210, 4410, 4609, 4808, 5007, 5205, 5404, 5602, 5800, 5998, 6195, 
     6393, 6590, 6786, 6983, 7179, 7375, 7571, 7767, 7962, 8157, 8351, 8545, 8739, 8933, 9126, 9319, 
     9512, 9704, 9896, 10087, 10278, 10469, 10659, 10849, 11039, 11228, 11417, 11605, 11793, 11980, 12167, 12353, 
     12539, 12725, 12910, 13094, 13279, 13462, 13645, 13828, 14010, 14191, 14372, 14553, 14732, 14912, 15090, 15269, 
     15446, 15623, 15800, 15976, 16151, 16325, 16499, 16673, 16846, 17018, 17189, 17360, 17530, 17700, 17869, 18037, 
     18204, 18371, 18537, 18703, 18868, 19032, 19195, 19357, 19519, 19680, 19841, 20000, 20159, 20317, 20475, 20631, 
     20787, 20942, 21096, 21250, 21403, 21554, 21705, 21856, 22005, 22154, 22301, 22448, 22594, 22739, 22884, 23027, 
     23170, 23311, 23452, 23592, 23731, 23870, 24007, 24143, 24279, 24413, 24547, 24680, 24811, 24942, 25072, 25201, 
     25329, 25456, 25582, 25708, 25832, 25955, 26077, 26198, 26319, 26438, 26556, 26674, 26790, 26905, 27019, 27133, 
     27245, 27356, 27466, 27575, 27683, 27790, 27896, 28001, 28105, 28208, 28310, 28411, 28510, 28609, 28706, 28803, 
     28898, 28992, 29085, 29177, 29268, 29358, 29447, 29534, 29621, 29706, 29791, 29874, 29956, 30037, 30117, 30195, 
     30273, 30349, 30424, 30498, 30571, 30643, 30714, 30783, 30852, 30919, 30985, 31050, 31113, 31176, 31237, 31297, 
     31356, 31414, 31470, 31526, 31580, 31633, 31685, 31736, 31785, 31833, 31880, 31926, 31971, 32014, 32057, 32098, 
     32137, 32176, 32213, 32250, 32285, 32318, 32351, 32382, 32412, 32441, 32469, 32495, 32521, 32545, 32567, 32589, 
     32609, 32628, 32646, 32663, 32678, 32692, 32705, 32717, 32728, 32737, 32745, 32752, 32757, 32761, 32765, 32766, 
     32767, 32766, 32765, 32761, 32757, 32752, 32745, 32737, 32728, 32717, 32705, 32692, 32678, 32663, 32646, 32628, 
     32609, 32589, 32567, 32545, 32521, 32495, 32469, 32441, 32412, 32382, 32351, 32318, 32285, 32250, 32213, 32176, 
     32137, 32098, 32057, 32014, 31971, 31926, 31880, 31833, 31785, 31736, 31685, 31633, 31580, 31526, 31470, 31414, 
     31356, 31297, 31237, 31176, 31113, 31050, 30985, 30919, 30852, 30783, 30714, 30643, 30571, 30498, 30424, 30349, 
     30273, 30195, 30117, 30037, 29956, 29874, 29791, 29706, 29621, 29534, 29447, 29358, 29268, 29177, 29085, 28992, 
     28898, 28803, 28706, 28609, 28510, 28411, 28310, 28208, 28105, 28001, 27896, 27790, 27683, 27575, 27466, 27356, 
     27245, 27133, 27019, 26905, 26790, 26674, 26556, 26438, 26319, 26198, 26077, 25955, 25832, 25708, 25582, 25456, 
     25329, 25201, 25072, 24942, 24811, 24680, 24547, 24413, 24279, 24143, 24007, 23870, 23731, 23592, 23452, 23311, 
     23170, 23027, 22884, 22739, 22594, 22448, 22301, 22154, 22005, 21856, 21705, 21554, 21403, 21250, 21096, 20942, 
     20787, 20631, 20475, 20317, 20159, 20000, 19841, 19680, 19519, 19357, 19195, 19032, 18868, 18703, 18537, 18371, 
     18204, 18037, 17869, 17700, 17530, 17360, 17189, 17018, 16846, 16673, 16499, 16325, 16151, 15976, 15800, 15623, 
     15446, 15269, 15090, 14912, 14732, 14553, 14372, 14191, 14010, 13828, 13645, 13462, 13279, 13094, 12910, 12725, 
     12539, 12353, 12167, 11980, 11793, 11605, 11417, 11228, 11039, 10849, 10659, 10469, 10278, 10087, 9896, 9704, 
     9512, 9319, 9126, 8933, 8739, 8545, 8351, 8157, 7962, 7767, 7571, 7375, 7179, 6983, 6786, 6590, 
     6393, 6195, 5998, 5800, 5602, 5404, 5205, 5007, 4808, 4609, 4410, 4210, 4011, 3811, 3612, 3412, 
     3212, 3012, 2811, 2611, 2410, 2210, 2009, 1809, 1608, 1407, 1206, 1005,  804,  603,  402,  201, 
        0, -201, -402, -603, -804, -1005, -1206, -1407, -1608, -1809, -2009, -2210, -2410, -2611, -2811, -3012, 
     -3212, -3412, -3612, -3811, -4011, -4210, -4410, -4609, -4808, -5007, -5205, -5404, -5602, -5800, -5998, -6195, 
     -6393, -6590, -6786, -6983, -7179, -7375, -7571, -7767, -7962, -8157, -8351, -8545, -8739, -8933, -9126, -9319, 
     -9512, -9704, -9896, -10087, -10278, -10469, -10659, -10849, -11039, -11228, -11417, -11605, -11793, -11980, -12167, -12353, 
     -12539, -12725, -12910, -13094, -13279, -13462, -13645, -13828, -14010, -14191, -14372, -14553, -14732, -14912, -15090, -15269, 
     -15446, -15623, -15800, -15976, -16151, -16325, -16499, -16673, -16846, -17018, -17189, -17360, -17530, -17700, -17869, -18037, 
     -18204, -18371, -18537, -18703, -18868, -19032, -19195, -19357, -19519, -19680, -19841, -20000, -20159, -20317, -20475, -20631, 
     -20787, -20942, -21096, -21250, -21403, -21554, -21705, -21856, -22005, -22154, -22301, -22448, -22594, -22739, -22884, -23027, 
     -23170, -23311, -23452, -23592, -23731, -23870, -24007, -24143, -24279, -24413, -24547, -24680, -24811, -24942, -25072, -25201, 
     -25329, -25456, -25582, -25708, -25832, -25955, -26077, -26198, -26319, -26438, -26556, -26674, -26790, -26905, -27019, -27133, 
     -27245, -27356, -27466, -27575, -27683, -27790, -27896, -28001, -28105, -28208, -28310, -28411, -28510, -28609, -28706, -28803, 
     -28898, -28992, -29085, -29177, -29268, -29358, -29447, -29534, -29621, -29706, -29791, -29874, -29956, -30037, -30117, -30195, 
     -30273, -30349, -30424, -30498, -30571, -30643, -30714, -30783, -30852, -30919, -30985, -31050, -31113, -31176, -31237, -31297, 
     -31356, -31414, -31470, -31526, -31580, -31633, -31685, -31736, -31785, -31833, -31880, -31926, -31971, -32014, -32057, -32098, 
     -32137, -32176, -32213, -32250, -32285, -32318, -32351, -32382, -32412, -32441, -32469, -32495, -32521, -32545, -32567, -32589, 
     -32609, -32628, -32646, -32663, -32678, -32692, -32705, -32717, -32728, -32737, -32745, -32752, -32757, -32761, -32765, -32766, 
     -32767, -32766, -32765, -32761, -32757, -32752, -32745, -32737, -32728, -32717, -32705, -32692, -32678, -32663, -32646, -32628, 
     -32609, -32589, -32567, -32545, -32521, -32495, -32469, -32441, -32412, -32382, -32351, -32318, -32285, -32250, -32213, -32176, 
     -32137, -32098, -32057, -32014, -31971, -31926, -31880, -31833, -31785, -31736, -31685, -31633, -31580, -31526, -31470, -31414, 
     -31356, -31297, -31237, -31176, -31113, -31050, -30985, -30919, -30852, -30783, -30714, -30643, -30571, -30498, -30424, -30349, 
     -30273, -30195, -30117, -30037, -29956, -29874, -29791, -29706, -29621, -29534, -29447, -29358, -29268, -29177, -29085, -28992, 
     -28898, -28803, -28706, -28609, -28510, -28411, -28310, -28208, -28105, -28001, -27896, -27790, -27683, -27575, -27466, -27356, 
     -27245, -27133, -27019, -26905, -26790, -26674, -26556, -26438, -26319, -26198, -26077, -25955, -25832, -25708, -25582, -25456, 
     -25329, -25201, -25072, -24942, -24811, -24680, -24547, -24413, -24279, -24143, -24007, -23870, -23731, -23592, -23452, -23311, 
     -23170, -23027, -22884, -22739, -22594, -22448, -22301, -22154, -22005, -21856, -21705, -21554, -21403, -21250, -21096, -20942, 
     -20787, -20631, -20475, -20317, -20159, -20000, -19841, -19680, -19519, -19357, -19195, -19032, -18868, -18703, -18537, -18371, 
     -18204, -18037, -17869, -17700, -17530, -17360, -17189, -17018, -16846, -16673, -16499, -16325, -16151, -15976, -15800, -15623, 
     -15446, -15269, -15090, -14912, -14732, -14553, -14372, -14191, -14010, -13828, -13645, -13462, -13279, -13094, -12910, -12725, 
     -12539, -12353, -12167, -11980, -11793, -11605, -11417, -11228, -11039, -10849, -10659, -10469, -10278, -10087, -9896, -9704, 
     -9512, -9319, -9126, -8933, -8739, -8545, -8351, -8157, -7962, -7767, -7571, -7375, -7179, -6983, -6786, -6590, 
     -6393, -6195, -5998, -5800, -5602, -5404, -5205, -5007, -4808, -4609, -4410, -4210, -4011, -3811, -3612, -3412, 
     -3212, -3012, -2811, -2611, -2410, -2210, -2009, -1809, -1608, -1407, -1206, -1005, -804, -603, -402, -201
     );

   signal accu: std_logic_vector(23 downto 0);
   signal fdiv_cnt: std_logic_vector(1 downto 0);
   signal accu_en: std_logic;
   signal accu_msb_q: std_logic;
   signal lut_index: std_logic_vector(9 downto 0);
	  
begin

---process for frequency divider---
process(clk)
begin
   if clk='1' and clk'event then
      if reset = '1' then
         fdiv_cnt <= (others =>'0');         --synchronous reset
      elsif accu_en = '1' then
         fdiv_cnt <= (others =>'0'); 
      else    
         fdiv_cnt <= fdiv_cnt+1;    
      end if;
   end if;
end process;

--logic for accu enable signal, resets also the frequency divider counter
accu_en <= '1' when fdiv_cnt = 2 else '0';

---process for phase accumulator---
process(clk)
begin
   if clk='1' and clk'event then
      if reset = '1' then         
            accu <= (others =>'0');         --synchronous reset
      elsif accu_en = '1' then
            accu <= accu + fcw;
      end if;
   end if;
end process;

-- 10 msb's of the phase accumulator are used to index the sinewave lookup-table--
lut_index <= accu(23 downto 14);

-- 16-bit sine value from lookup table----------------------------------
dds_sin <= conv_std_logic_vector(rom(conv_integer(lut_index)),16);

end Behavioral;

3- PWM output

Before we start, let’s clarify a brief PWM (Pulse Width Modulation) theory:

The Pulse Width Modulator generates a periodic sequence of pulses whose duration is proportional to the value of an input signal.

A numerator compares the signal value with a sawtooth signal, and as long as the sawtooth signal is greater than the signal value, the output pulse is set active high.

Using an analogue signal as input a PWM  signal is generated. For this a comparison is used as shown in the following schema:

comparison of the input signal and the sawtooth

The Verilog Code

module pwm_gen(clk,reset,sig_in,pwm_out, convert);

parameter integer dwidth_g = 8;
input clk,reset;
input [dwidth_g-1:0] sig_in;
output reg pwm_out;
output convert;

reg [dwidth_g-1:0] cnt;
parameter cnt_max_c = 20'hFFFF;

always@(posedge clk)
    begin
if(reset == 1'b1)
    cnt <= 0;
else
      if(convert == 1'b1) 
      begin
            cnt <= 0;
      end
      else
         cnt <= cnt +1;
      if(cnt < sig_in)
        pwm_out <= 1'b1;
      else
        pwm_out <= 1'b0;
end 
  
//decode max counter value and output the pwm conversion start
assign convert = (cnt == cnt_max_c) ? 1'b1 : 1'b0;

For this the VHDL code is:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_unsigned.all;

entity pwm_gen is
    generic( dwidth_g: integer := 8);
    Port ( clk : in  STD_LOGIC;
           reset : in  STD_LOGIC;
           sig_in : in  STD_LOGIC_VECTOR (dwidth_g-1 downto 0);
           pwm_out : out  STD_LOGIC;
           convert : out  STD_LOGIC);
end pwm_gen;

architecture Behavioral of pwm_gen is


signal cnt: std_logic_vector(dwidth_g-1 downto 0);
signal sig_tmp: std_logic_vector(sig_in'range);
signal convert_int: std_logic;
constant cnt_max_c: std_logic_vector(cnt'range) := (others => '1');

begin
  
  process(clk)
    begin
      if clk='1' and clk'event then
        if reset = '1' then
          cnt <= (others => '0');
        else
          if convert_int = '1' then
             cnt <= (others => '0');
		sig_tmp <= sig_in;  -- register the input signal at conversion start
          else
             cnt <= cnt+1;
          end if;
          if cnt < sig_in then
            pwm_out <= '1';
          else
            pwm_out <= '0';
          end if;
        end if;
     end if;
  end process;
  
--decode max counter value 
  convert_int <= '1' when cnt = cnt_max_c else '0';
 
--output the pwm conversion start---
  convert <= convert_int;   

end Behavioral;

For this simulation, the previously developed block is used as input for the PWM generator block. For that, a new 8bits sine wave was generated.

45 thoughts on “Sinus wave generator with Verilog and Vivado”

  1. I see in my internet explorer in windows.
    fdiv_cnt <= 0;
    < ?
    Is this in your code wrong ?
    I think it would be fdiv_cnt <= 0; or not ?

    1. Hello Willem,

      fdiv_cnt <= 0; should be correct. The code was running, the last time I copied it to here. Sorry, I dont understad were the errata is. do you mean that I may add the '?' symbol somewhere?Thanks for the feedback! Alberto

  2. Hi Alberto,

    Thank you for creating a great tutorial. It is exactly what I was looking for. I am new to FPGA and HDL and design flow in Vivado. I find it hard to create and perform the simulation without more details. Would you please guide me the step-by-steps in more details to simulate the design and to get the waveforms? In particular, what tool in Vivado to display the input and output waveforms? How do I create sinus_gen_0 and sim_clk_gen_0 blocks and how to use them?

    1. Hello Anthony,

      The RTL block is the block with the code with the sinus generator. The clk gen block is a generic clock you add in Vivado.

      The Design flow in Vivado to create the block and simulate them is the normal one and it is generic and not related to this application, therefore the step-by-step description is not here illustrated. (if I added it always, every post would be veeery loong).
      I wrote a small tutorial for Vivado: https://miscircuitos.com/how-to-create-a-testbench-in-vivado-to-learn-verilog-or-vhdl/
      It may helps!
      Best wishes with your vivado proyects!
      Regards, Alberto

      1. Hi Alberto,
        How can I get the sine wave? After writing testbench, they are giving the value only what I put in the memory. But in your document, I saw that sine wave is generating. So how can I get it??
        regards,
        Amitava

      2. Hello Amitava,
        I dont understand what you mean with your question.
        The idea is to store the signal you want to generate into the rom memory and them “print it out” to the output. You can generate a sinus or any other signal.
        Best Regards

      3. Hello Sir,
        Which value should I give in rom_memory? How can I generate that values? Can you explain please?

      4. The easiest and fastest one is use an online sine generation tool that i mention in the post. You also can use matlab or any other math tool

        Regards

  3. Hi there, Alberto. My name is Renan and i’m from Brazil. I was testing your described method, pass by pass. Therefore, after i wrapped and i simulated this, but vivado doesn’t showed to me the wave screen that was showed to you like you posted, exactly after “The simulation results of this example with a clock frequency set to 50MHz:” step. Then, please tell me, what should i do?

    Regards,

    1. Hello Renan,

      I can note guess what could be happening. You should debug it by yourself. First check that the clock is working, then go deeper step by step, trying to see what the outputs are and why it is not working. The Verilog Code should be fine. Maybe the Vivado config or other external aspect.
      If there is something specific or concret just let me know, but you should learn to debug and fix your setups and problems.

      Best Regards
      Alberto

      1. Hi again, Alberto. Thank you for your support! You are totally right, there was an error that i wasn’t pay attention. There is two problems, the first is a warning:
        “WARNING: [Simtcl 6-168] No object found for the given pattern.
        WARNING: [Add_Wave-1] No top level signals found. Simulator will start without a wave window. If you want to open a wave window go to ‘File->New Waveform Configuration’ or type ‘create_wave_config’ in the TCL console.”
        I did exactly what the warning told, but even so, the waveform screen that appeared is not like yours showed by you in the tutorial. The waveform screen shows the internal signals and anothers things, but doesn’t show the output.
        The second problem is when the program apparently try to synthesize the wrapped design:
        “[Synth 8-439] module ‘sim_clk_gen’ not found [directory]” and then, VIVADO shows me the line that has the error, but unfortunately, the design where is the error can’t be modificated, appears “Read-only”, in the top-right from the box. Then i can’t think how i can solve this error. I tried to debug it myself but it’s too complex to me! Any idea what should i do? Thank you so much for your support.

      2. Hello Renan,
        Unfortunately I don’t know right now what could be. Could it be that you are simulating the inner level of the design and not the top level?
        regards

  4. Hello Alberto. This is a good code! I am interested how can I calculate the frequency of the sinusoidal signal using the variable frequency (FCW).
    Thank you so much for your support.

  5. SINE WAVE CODE WORKING BUT HERE ..THE OUTPUT SHOWING AS COUNTER OUTPUT …NOT GD…If possible send me code my mail

  6. Hello Alberto,

    I like your page on different ways to generate a sine wave. But I have a question on generating the sine wave:
    So using sin(wt) = (wt) – [(wt)^3] / 3! + [(wt)^5] / 5!…….
    where w=2*pi*f
    Therefore just like an expansion series formula can we generate a continuous sine wave without storing any samples using Verilog?

    1. Hello Darshit,
      Yes you could, but the maths calculation has a high calculation cost. Much more than storing a table on the memory. But yes, you can implement it!
      Let me know if you finish and how are the results and code!
      Best Regards! 🙂

  7. im trying to implement this in ISE Design Suite
    can some clarify which is the verilog code and which one is the verilog test bench code.

  8. I tried to implement the sinusoidal signal and it works perfect. Now I need to generate another sine wave at the same time with the same frequency but with a different phase. How can I modify the code to get a phase change?

  9. Hello Alberto,
    I am using Quartus II to implement your designs, the fixed frequency case has worked well, as the test bench is fairly simple to write, however I couldn’t get the test bench correctly for the variable frequency case. Please can you help with that regards

    1. Hello Faisal,

      I don’t know about Quartus and even don’t know what you are doing in your testbench, so I can not help you more than sharing my code.

      Hope you the best
      Alberto

  10. Hi Alberto! Thank you so much for your tutorial!
    I have a small question: how can I modify this program such that it’s not only a simulation but it runs on a Red Pitaya? I would need to read the output sine wave with an oscilloscope.
    I added an DAC and the processing system but I don’t know if it’s enough since I’m new to Vivado.
    Best regards,
    Geena.

    1. Hello Geena,
      this program was intended to be used with the Zybo board. You may change the configuration for Red Pitaya, which I’ve never used with Vivado, but I think it would be compatible.

      Regards

  11. Hi Alberto, very nice tutorial, congratulations!!!
    Since the FPGA that i have has no DACs, I wanted to ask you how can i generate on an output pin a 40 kHz frequency, from a 50 MHz clock, which i can see on an oscilloscope.
    I know how to write the constrain, I’m only confused on the code, i searched on internet but no solutions are very well explained or the implementation does not give the expected result!

    Thank you

    Paolo

    1. Hi,
      For having the test bench, you must create it byyourself. I ‘ve already share and take the time to share this code and explanation with the people, please take your time to create your test bench.
      If you dont know how to make a Vivado test bench, then go for a tutorial.
      Best Regards
      Alberto

  12. Very nice tutorial!

    Just wanted to say that you forgot to mention that could even optimize it even further. Since the Sine wave has a lot of symmetry, you only need a quarter of the memory.

    Basically just take the values from 0 to the maximum value, after read out the memory in reverse the reading order until it reaches zero. Than add a negative sign in front until it reaches zero, and make it positive again!
    This could free up some space for a bigger lookup table if you want or a more compact design

    1. Hi Bonnom,
      Sure! nice approach 🙂 Yes, when I develop this project, the only matter was the speed so we didnt pay attention to other topics, but yes, you are totally right, we could use 1/4 of the look up table memory saving a lot of FPGA space.

      Best Regards
      Alberto

Leave a Comment

Your email address will not be published. Required fields are marked *