The sine wave's amplitude values can be generated from this online tool - Sine Look up table generator. For this particular version of the code, I used the following settings:
You can generate a sine wave using different settings and paste them in the code given below.
To improve the smoothness and precision of the sine wave use more number of points and a higher value for maximum amplitude value. But remember that if we use too many points, the FPGA resources may not be able to keep up with the size of the ROM needed. So even though its possible theoretically, it may not be practically feasible.
The design can be further improvised by reducing the size of the ROM to 1/4th of its original size. Since sine wave is symmetric, if we have the values for any one quadrant, then the rest of the quadrants can be figured out. This comes at the expense of a slightly more complicated logic in the code.
If you need further explanation you can watch this Youtube video I have created - Generic Sine Wave Generator (LUT Based) in VHDL.
sine_wave.vhd:
--library declarations library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all; --try to use this library as much as possible. entity sine_wave is generic(NUM_POINTS : integer := 32; MAX_AMPLITUDE : integer := 255 ); port (clk :in std_logic; dataout : out integer range 0 to MAX_AMPLITUDE ); end sine_wave; architecture Behavioral of sine_wave is signal i : integer range 0 to NUM_POINTS := 0; type memory_type is array (0 to NUM_POINTS-1) of integer range 0 to MAX_AMPLITUDE; --ROM for storing the sine values generated by MATLAB. signal sine : memory_type :=
(128,152,176,198,218,234,245,253, --sine wave amplitudes in the 1st quarter. 255,253,245,234,218,198,176,152, --sine wave amplitudes in the 2nd quarter. 128,103,79,57,37,21,10,2, --sine wave amplitudes in the 3rd quarter. 0,2,10,21,37,57,79,103); --sine wave amplitudes in the 4th quarter. begin process(clk) begin --to check the rising edge of the clock signal if(rising_edge(clk)) then
--one by one output the sine amplitudes in each clock cycle.
dataout <= sine(i);i <= i+ 1; --increment the index.if(i = NUM_POINTS-1) then--reset the index to zero, once we have output all values in ROM
i <= 0;end if;
end if; end process; end Behavioral;
Testbench - tb_sinewave.vhd:
--library declarations library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; library std; use std.env.finish; --entity for testbenches are always empty entity tb_sinewave is end tb_sinewave; architecture behavior of tb_sinewave is --declare the component which we are going to test. Here that is "sine_wave" component sine_wave is generic(NUM_POINTS : integer := 32; MAX_AMPLITUDE : integer := 255 ); port(clk :in std_logic; dataout : out integer range 0 to MAX_AMPLITUDE ); end component; --generic constants constant NUM_POINTS : integer := 32; constant MAX_AMPLITUDE : integer := 255; --Inputs signal clk : std_logic := '0'; --Outputs signal dataout : integer range 0 to MAX_AMPLITUDE; -- Clock period definitions constant clk_period : time := 10 ns; --temporary signals signal data_out_unsigned : unsigned(31 downto 0); begin -- Instantiate the Unit Under Test (UUT) uut: sine_wave generic map(NUM_POINTS, MAX_AMPLITUDE) port map(clk => clk, dataout => dataout ); data_out_unsigned <= to_unsigned(dataout, 32); -- Clock process definitions clk_generate_process :process begin wait for clk_period/2; clk <= not clk; end process; -- Stimulus process stim_proc: process begin wait for clk_period*NUM_POINTS*2; end process; end;
Note the following about the sine wave generator:
- I have used the library numeric_std instead of std_logic_arith and std_logic_unsigned. Why? Read Why the library "numeric_std" is preferred over "std_logic_arith" and others? for in depth information on this.
- I have used rising_edge(clk) instead of if(clk'event and clk='1'). Why? Read Difference between rising_edge(clk) and (clk'event and clk='1') for more information.
- This same entity can be slightly tweaked to output any wave. Just change the values stored in the sine array.
- The code is fully synthesisable and can be tested on any FPGA, if the relevant connections are made.
- What is the frequency of the generated sine wave?
The frequency depends upon the clock frequency supplied to the sine wave entity and the number of points of sine wave stored in the array.
We can say, freq = frequency_clk / number_of_points; - I cannot see sine wave when I simulate this code. Why?
Its possible to see the shape of sine wave in modelsim software. I got the following waveform from modelsim. Right click on the signal name and choose the correct settings to display the values in analog format.
hi!
ReplyDeleteHow do you do to change the frequency of your sine wave?
Jocelyn
@Jocelyn : The freq of the sine wave is determined by the freq of clk in the above program.Here we need 30 clk cycles for sending one full cycle of sine values.So the period of sine wave is (freq of clk/30).
ReplyDeleteHope I am clear.
can u give us a tutorial on using delta-sigma DAC ?
Deleteheloo jocelyn!
ReplyDeletein the above code i have simulated and runed for 30 sin values but the out put wave does not looks like sin! is their any settings reqired for getting out put wave in the form of sin as the below!
file://localhost/C:/Documents%20and%20Settings/Administrator/Desktop/enp%20final/Synthesisable%20Sine%20Wave%20Generator_files/wave.gif
@prahlad : I never told that the wave will look like a sine wave in the simulator.If you want to test out use a DAC,interface it with FPGA board and connect the output of DAC to an oscilloscope.
ReplyDeleteOr another thing you can do is take a graph sheet draw the output values Vs time.You will get a sine signal.If you still not getting contact me.
dude iam using fpga spartan 3e ... i need 2 generate sine wave ,,,,should i use dac and thn fpga to burn code
Deletehi vipin can you help me in implementing PWM and random PWM in fpga...
Deletereally, people probably should be using the coregen dds compiler. but overall, this shows the basic concept.
ReplyDeleteA DDS will generally exploit the symmetry in the sine wave -- only 1/4th of the sine wave values are needed.
this allows a larger table to be used. using a lot of entries allows the user to increment by N, to generate other frequencies.
@Chris : I do agree. But if you just use core gen IP's for each and everything then how will you learn.This is a basic code where you can see how it works.I have mentioned in this post itself that,"The code can be modified for efficient use of memory so that,only the first (pi/2) values are stored in the ROM".
ReplyDeleteI just left it as an exercise for readers.
Thanks,
ReplyDeleteI need to learn how to use the DAC so I can play with this!!
how to interface the dac with the fpga ?
ReplyDeleteThe values were generated using matlab??? Is thr a formula for d generation of sine values??
ReplyDeletehi ,
ReplyDeletei just wanna ask , if i syenthesized this code and , interface it with VGA port , would it display the sinewave figure on monitor ?
Absolutely not...You would need to create double buffering and index the buffers and map the pixel data to the RGB signals and sync to the pixel clock...This requires synchronization with the hsync and vsync signals...It is not a simple thing to do and I suggest you hit the books really hard if you want to learn about very advanced HDL controllers...Just because it can be done, it does not mean it is easy to do so...
Deletecan we get sine wave in modelsim
ReplyDeleteSee my reply below...
Deletehow can we get sine wave in modelsim?
ReplyDeleteYes, you can get a sine wave to show up in modelsim...Just view the data as signal! :)
ReplyDeleteYeah, I think somebody mentioned above that this could have been done much better in four states using a quarter wave LUT and four simple states marking each quadrant...This translates 0-90 degrees would have been decimated into a LUT to whatever radians division is desired. Then on the quadrant 90-180 you would read the LUT in reverse going backwards 90-0 by reversing the indexes of the LUT and so on into the other quadrants, but at that point from 180 to 270 and 270 to 360, you'd want to negate the LUT values. That is how a quarter wave LUT works...
ReplyDeleteHi there! I have generated sine wave.. But after some clock cycle the wave is not accurate..some samples are missing..I have tried adjusting the frequency but still its distorting.. For example., in the case of FSK the waves are distorting after some clock cycles.. What should I do??
ReplyDeleteHi Vipin am working on a similar project but am not using Matlab am only using Quartus Software, how can I generate and store the sine wave values using the Quartus software
ReplyDeleteThe calculation of the sin values is wrong. At 8 bits I would expect the maximum value to be close to 127, however this example only produces 77 as the maximum.
ReplyDeleteThe correct calculation would be int32(sin(t) * 127) for 8 bit or more general int32(sin(t) * 2^(n-1)) for n bits.
Also most people don't have MATLAB available so here is some python code:
n=30;bits=8; from math import sin, pi;print([int(round(sin(x*2*pi/n)*(2**(bits-1)-1))) for x in range(n)])
"n" is the number of values and "bits" the number of bits per value.
You can try it online at https://repl.it/BcM6/1
can i generate sinewave using cpld?can i store look up table values in cpld and call it one by one? need help..
ReplyDeletecan i generate sinewave using cpld? can i store look up values in cpld and can just call it? need help
ReplyDeleteHow to test the code?/ what to write in the testbench
ReplyDeleteyou dont need to enter "anything". You just run it. The only stimulation that you need is the clk. Just declare your clk period, your internal clk signal and instantiate the UUT.
Deleteafter writing vhdl code in quartus-ii how to view the output iesinewave in modelsim..?
ReplyDeleteThe code runs perfectly fine ie generates sine wave(i am using vivado software for running the code which allows analog sine wave output.)
ReplyDeleteBut my question is that whether this sine wave could be used in other programs such as generation of ASK ,PSK by changing its phase and frequency. In other words what will be the code to change its phase and frequerncy?
Does vhdl support complex numbers?
ReplyDeleteCan we use floating point numbers in vhdl?
ReplyDeletelibrary IEEE;
ReplyDeleteuse IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.std_logic_signed.all;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity lms2 is
Port (wr9,wi9,xr,xi : in STD_LOGIC_VECTOR (12 downto 0);
--u : in integer;
yr,yi,er,ei,wr8,wi8,zzz,sum1 : out STD_LOGIC_VECTOR (12 downto 0));
end lms2;
architecture Behavioral of lms2 is
signal a,b :real;
--signal yr11, yi11 : real;
--variable r,s : real range 0.0 to 15.0;
begin
process(wr9,wi9,xr,xi)--process also runs without the parameters,but it gives problems during simulation
--process(u,xr,xi)
variable wr : std_logic_vector(12 downto 0);
variable wi : std_logic_vector(12 downto 0);
--variable wr : std_logic_vector(4 downto 0) :="00010";
--variable wi : std_logic_vector(4 downto 0) :="00011";
--variable wr : std_logic_vector(4 downto 0) :=wr9;
--variable wi : std_logic_vector(4 downto 0) :=wi9;
variable xr1 : real :=3.2;
variable xi1 : real :=4.1;
variable dr1 : real :=5.2;
variable di1 : real :=4.4;
variable yr1 : real;
variable yi1 : real;
variable er1 : real;
variable ei1 : real;
variable wr1 : real := 1.8;
variable wi1 : real := 2.1;
variable u : real :=0.2;
variable f : real := 3.2;
variable g : real := 2.6;
variable h : real;
variable hh : real;
begin
h := f+g;
hh := f*g;
a <= h;
b <=hh;
--process(xr,xi,u)
--bi <= to_integer(unsigned(k)) ;
--bj <= to_integer(unsigned(l)) ;
--bk <= bi*bj;
for z in 0 to 3 loop
yr1 := wr1*xr1-wi1*xi1;--line1
yi1 := wr1*xi1+wi1*xr1;--line2
er1 := (wr1*xr1)-(wi1*xi1)-dr1;--line3
ei1 := (wr1*xi1)+(wi1*xr1)-di1;--line4
wr1 := u*(xr1*er1-xi1*ei1)+wr1;--line5
wi1 := u*(xr1*ei1+xi1*er1)+wi1;--line6
end loop;
--yr11 <= yr1;
--yi11 <= yi1;
end process;
end Behavioral;
We are implementing LMS algorithm . If we are adding line 5 and line 6 (as indicated by comments), we are getting error right from line 1 (as indicated by comments) that "non constant real valued expression not supported". However when we are omitting line 5 and line 6, we are not getting the error. Please ignore the STD_LOGIC_VECTORS(in and out)added in the beginning, as they are reserved for future use
how to make it suitable for a lvds dac?
ReplyDeletewhat is the frequency of above sine wave??
ReplyDeleteWhat is the frequency of above sign wave and how do you modify it?
ReplyDeleteWe are implementing LMS algorithm .
ReplyDeletehow simulated analog signal using ise
ReplyDelete