Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Triangular wave generator in FPGA

Status
Not open for further replies.

Ironlord

Member level 3
Joined
Oct 16, 2018
Messages
63
Helped
1
Reputation
2
Reaction score
1
Trophy points
8
Activity points
713
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.
 

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/Numerically_controlled_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.
 
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/Numerically_controlled_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.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top