This file calculates a theta-angle-signal based on the given frequency-information:

VHDL
-- Theta (sawtooth) generator
-- Christian Noeding, christian@noeding-online.de
-- https://chrisdevblog.com | https://github.com/xn--nding-jua
--
-- Released under GNU General Public License v3

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity gen_theta is
	generic(
		f_pwm		: integer := 16000;
		f_ref		: integer := 50
		);
	port
	(
		clk		: in std_logic;
		frequency: in signed(31 downto 0); -- Q15.16
		sync_in	: in std_logic; -- sync_ed with PWM-clock
		
		theta		: out signed(31 downto 0); -- Q15.16
		sync_out : out std_logic
	);    
end gen_theta;

architecture behaviour of gen_theta is
	-- with Q15.16 the counter-increment defines a minimum f_ref of 0.38 Hz.
	-- so we are working with Q3.28 internally and convert it to Q15.16 at the end

	signal state		:	natural range 0 to 3 := 0;

	constant counter_top    : signed(31 downto 0) := to_signed(1 * 2**28, 32); -- 1.0 as Q3.28
	constant one_by_fpwm		: signed(31 downto 0) := to_signed((2**28)/f_pwm, 32); -- Q3.28
	constant scaler_theta   : signed(31 downto 0) := to_signed(1686629713, 32); -- 2*pi = 6.283185307179586476925286766559 as Q3.28

	signal counter          : signed(31 downto 0) := to_signed(0, 32);	-- counter in Q3.28
	signal counter_inc    	: signed(31 downto 0) := to_signed((2**28)*f_ref/f_pwm, 32); -- increment defined by used pwm-clock and desired frequency
begin
	process(clk)
	begin
		if rising_edge(clk) then
			if (sync_in = '1' and state = 0) then
				-- increase counter and wrap around when reaching top
				counter_inc <= resize(shift_right(frequency * one_by_fpwm, 16), counter_inc'length); -- Q15.16	* Q3.28 = Qx.44 -> convert to Q15.28
				
				state <= 1; -- start of state-machine
			
			elsif state = 1 then
				if (counter + counter_inc) > counter_top then -- case for positive increment
					counter <= (counter + counter_inc) - counter_top;
				elsif (counter + counter_inc) < 0 then -- case for negative increment
					counter <= (counter + counter_inc) + counter_top;
				else
					counter <= counter + counter_inc;
				end if;
				
				state <= state + 1;
			
			elsif state = 2 then
				-- scale counter for output of theta
				theta <= resize(shift_right(counter * scaler_theta, 40), 32); -- scale theta to 0 to 2*pi | Q3.28 * Q3.28 = Qx.56 -> convert to Q15.16
				sync_out <= '1';
				
				state <= state + 1;

			elsif state = 3 then
				sync_out <= '0';
				
				state <= 0;
				
			end if;
		end if; -- clk
	end process;
end behaviour;

Leave a comment

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