Produce sine lookup table based on the frequency

143 Views Asked by At

Trying to generate sine wave by using LUT. But, the LUT is calculated within the VHDL code as can be seen below. I do know that in VHDL it is not possible to use real. But couldnt figure out how to produce the LUT first and then use it to generate sin wave. Sure I will be able to generate sin wave once I know how to calculate the LUT dynamically in my vhdl code.

In addition, I am getting:

Error (10482):object "sin" is used but not declared

This what I have tried so far:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity SineWave is
    Port ( clk : in STD_LOGIC;
           sine_out : out STD_LOGIC_VECTOR(7 downto 0));
end SineWave;

architecture Behavioral of SineWave is
    constant TABLE_SIZE : integer := 360; -- Number of entries in the lookup table
    type sine_table_type is array (0 to TABLE_SIZE-1) of integer;
    signal sine_table : sine_table_type;

begin
    process(clk)
        variable angle : integer := 0;
          constant fs : integer := 1024;
          variable counter : integer := 0;
          variable frequency : integer := 1; --for now setting frequency manually
    begin
     for i in 0 to TABLE_SIZE-1 loop
      -- Calculate sine value using the formula
      angle := 2 * 180* frequency * (i) * fs; -- formula = sin(2*pie*frequency* n/sampling frequency(fs))
      sine_table(i) <= sin(angle); -- Convert to fixed-point format
      
      -- report "Index: " & integer'image(i) & " Sine Value: " & integer'image(sine_table(i));
    end loop;
        if rising_edge(clk) then
          
          sine_out <= sine_table[counter];
          counter := counter + 1;
          
        end if;
    end process;
end Behavioral;`
1

There are 1 best solutions below

3
Tricky On

There is no sin function available for the integer data type in standard libraries, for sin, you need to use the ieee.math_real library.

While it is true real type cannot be used for synthesisable logic, it can generally be used to set up elaboration time constant values. For example, a SIN LUT.

Your example is incorrect as a LUT as it is generating logic for each element of the table. Your code indicates you are trying to re-initialise the table on every clock edge (rising and falling). You simply need to assign the table to a constant and initialise it from an initialisation function, something like the following:


use ieee.numeric_std.all;
use ieee.math_real.all;

...

type sin_table_t type is array(TABLE_SIZE-1 downto 0) of signed(bitwidth-1 downto 0);

function sin_lut_init return sin_table_t is
    variable angle     : real;
    variable sin_angle : real;
    variable table     : sin_table_t;
begin
    for i in table'range loop
        angle      := MATH_PI * real(i) / real(TABLE_SIZE);
        sin_angle  := sin(angle);

        table(i)   := to_signed( integer( real( 2**bit_width ) * angle ) ), bitwidth );
    end loop;

    return table;
end function;

constant SIN_LUT : sin_table_t := sin_lut_init;