+ Post New Thread
Results 1 to 3 of 3
  1. #1
    Member level 2
    Points: 309, Level: 3

    Join Date
    Oct 2018
    Posts
    47
    Helped
    1 / 1
    Points
    309
    Level
    3

    Triangular wave generator in FPGA

    I want to implement a triangular wave in an FPGA. Values should go from -2047 to 2047, so I'm using a 12-bit precission.
    The problem is that I want it to be variable in frequency, I want ot be able to modify it's input in order to generate different frequencies, like if it were a signal generator.
    I hav developed the following code:

    Code:
    library ieee;
    use ieee.std_logic_1164.all;
    --use ieee.std_logic_arith.all;
    USE ieee.NUMERIC_STD.all;
    use IEEE.std_logic_signed.all;
    
    --Precondition: Frequencies goes in Hz.
    entity triangle_gen is
    port(
    	clk		: in  std_logic;
    	freqSmp	: in  std_logic_vector(25 downto 0); --Max freq could be 50Mhz
    	freqOut	: in std_logic_vector(25 downto 0); --Output max frequency is the half the sample freq. (Nyquist)
    	triWave	: out std_logic_vector(11 downto 0)
    );
    end triangle_gen;
    
    
    Architecture a of triangle_gen is
    
    	--Senales
    	constant clk_freq	: std_logic_vector(25 downto 0) :="10111110101111000010000000"; --defined as 50MHz
    	constant min_val	: signed(11 downto 0)			:="100000000001";
    	constant max_val	: signed(11 downto 0)			:="011111111111";
    	constant pp_max		: std_logic_vector(11 downto 0)	:="111111111111";	--Peak to peak
    	signal	increment	: std_logic_vector(11 downto 0)	:=(others => '0');	--How much should I increment every time I stop?
    	signal	half_cycle	: std_logic_vector(11 downto 0)	:=(others => '0');
    	signal	cyc_count	: std_logic_vector(25 downto 0)	:=(others => '0');	--When do I stop to assign a value?
    	signal	this_cycle: std_logic_vector(25 downto 0)	:=(others => '0');	--How many clk cycles must I wait?
    	signal	part_count: std_logic_vector(11 downto 0)	:=(others => '0');
    	signal	triWave_aux : std_logic_vector(11 downto 0)	:="100000000001"; 	--Min_val. I start from the lowest.
    	signal	remain		: integer range -2047 to 4094	:=4094;
    	signal	riseUp 		: std_logic :='1';
    	
    Begin
    	--Divisions should be made in the HPS (ARM) It's a SoC.
    	--cyc_count<=(clk_freq/freqSmp)-1;
    	--cyc_count<="00010011000100101100111111"; --Lo estoy poniendo a 5MHZ, como si quisiera hacerla de 1Hz con 10Hz de sampleo
    	cyc_count<="00000000000010011100010000"; --Lo estoy poniendo a 10KHZ, quiero hacer el sampleo a 5khz y la señal a 500hz.
    	half_cycle<=('0'& freqSmp(11 downto 1));
    	--increment<=(pp_max/half_cycle);
    	increment<="000000000010";--El increment es de 1.6384 en realidad
    	
    	process(clk)
    	begin
    		if(rising_edge(clk))then
    			if(this_cycle<cyc_count)then --this_cycle signal acts like a trigger.
    				this_cycle<=this_cycle+'1';
    			else
    					if(riseUp='1')then
    						if(remain>(to_integer(signed(increment))))then
    							remain<=(remain-(to_integer(signed(increment))));
    							triWave_aux<=triWave_aux+increment;
    						else
    							triWave_aux<=std_logic_vector(max_val)-(increment-(std_logic_vector(to_signed(remain,12)))); --El remain es negativo, por lo tanto, la suma resta.
    							riseUp<='0';
    							remain<=(4094-(to_integer(signed(increment))))+remain;
    						end if;
    					else
    						if(remain>(to_integer(signed(increment))))then
    							remain<=(remain-(to_integer(signed(increment))));
    							triWave_aux<=triWave_aux-(std_logic_vector(signed(increment)));
    						else
    							triWave_aux<=std_logic_vector(min_val)+(increment-(std_logic_vector(to_signed(remain,12)))); --El remain es negativo, la resta suma.
    							riseUp<='1';
    							remain<=(4094-(to_integer(signed(increment))))+remain;
    						end if;
    					end if;
    				this_cycle<= (others => '0');
    			end if;
    		end if;
    	end process;
    
    	triWave<=triWave_aux;
    	
    end a;
    The problem I found is I think I am doing something wrong, guess it won't be precisse at all.
    I was wondering if using a double precission or floating point would be a good choice or if it will make my system totally inneficient.
    I am glad to hear some ideas which could help me to develop a better version of my code.

    Thanks as always.

    Cheers.

    •   AltAdvertisment

        
       

  2. #2
    Super Moderator
    Points: 252,660, Level: 100
    Awards:
    1st Helpful Member

    Join Date
    Jan 2008
    Location
    Bochum, Germany
    Posts
    44,014
    Helped
    13388 / 13388
    Points
    252,660
    Level
    100

    Re: Triangular wave generator in FPGA

    You can easily implement a variable frequency triangle oscillator in NCO style with a phase accumulator incremented every clock cycle https://en.wikipedia.org/wiki/Numeri...led_oscillator

    The NCO accumulator output is a sawtooth waveform, it can be converted to triangle by turning down the upper halve, or switching between inverted and non-inverted sawtooth every second cycle, whatever is more appropriate. Notice that the accumulator bit width can be made considerably higher than the output width, giving respective frequency resolution.


    1 members found this post helpful.

    •   AltAdvertisment

        
       

  3. #3
    Member level 2
    Points: 309, Level: 3

    Join Date
    Oct 2018
    Posts
    47
    Helped
    1 / 1
    Points
    309
    Level
    3

    Re: Triangular wave generator in FPGA

    Quote Originally Posted by FvM View Post
    You can easily implement a variable frequency triangle oscillator in NCO style with a phase accumulator incremented every clock cycle https://en.wikipedia.org/wiki/Numeri...led_oscillator

    The NCO accumulator output is a sawtooth waveform, it can be converted to triangle by turning down the upper halve, or switching between inverted and non-inverted sawtooth every second cycle, whatever is more appropriate. Notice that the accumulator bit width can be made considerably higher than the output width, giving respective frequency resolution.
    Thanks, that's all I wanted to know. I had another design based on the NCO, but had no idea about how convert the chainsaw into a triangular wave, so I was programming another module in order to do so.



--[[ ]]--