The following logic contains a standard PI-controller

VHDL
-- PI controller
-- 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 pi_controller is
	PORT
	(
		clk			: in std_logic;
		actual		: in signed(31 downto 0); -- Q15.16
		setpoint		: in signed(31 downto 0); -- Q15.16
		kp				: in signed(31 downto 0); -- Q10.21
		ki				: in signed(31 downto 0); -- Q10.21
		Ts				: in signed(31 downto 0); -- Q0.31
		reset			: in std_logic;
		sync_in		: in std_logic;

		output		: out signed(31 downto 0); -- Q15.16
		sync_out		: out std_logic
	);    
end pi_controller;

architecture behavioral of pi_controller is
	signal state			:	natural range 0 to 5 := 0;

	constant omega_init	:	signed(47 downto 0) := to_signed(105414357, 48); -- Q23.24 = 2*pi*1
	
	signal actual_int		: signed(31 downto 0); -- Q15.16
	signal setpoint_int	: signed(31 downto 0); -- Q15.16
	signal kp_int			: signed(31 downto 0); -- Q10.21
	signal ki_int			: signed(31 downto 0); -- Q10.21
	signal Ts_int			: signed(31 downto 0); -- Q0.31
	
	signal error			: signed(23 downto 0); -- Q11.12
	signal i_gain_ts		: signed(31 downto 0); -- Q0.31
	
	signal p_part			: signed(47 downto 0); -- Q23.24
	signal i_inc			: signed(47 downto 0); -- Q23.24
	signal i_part			: signed(47 downto 0); -- Q23.24
begin
	process(clk)
	begin
		if (rising_edge(clk)) then
			if (sync_in = '1' and state = 0) then
				if (reset = '1') then
					i_part <= to_signed(0, 48);
				end if;
				
				actual_int <= actual;
				setpoint_int <= setpoint;
				kp_int <= kp;
				ki_int <= ki;
				Ts_int <= Ts;

				state <= 1; -- start of state-machine
			elsif (state = 1) then
				error <= resize(setpoint_int - actual_int, error'length);
				i_gain_ts <= resize(shift_right(ki_int * Ts_int, 21), 32); -- Q10.21 * Q0.31 = Qx.52 -> convert to Q0.31
				
				state <= state + 1;

			elsif (state = 2) then
				p_part <= resize(shift_right(kp_int * error, 9), p_part'length); -- Q10.21 * Q11.12 = Qx.33 -> convert to Q23.24
				i_inc <= resize(shift_right(i_gain_ts * error, 19), i_inc'length); -- Q0.31 * Q11.12 = Qx.43 -> convert to Q23.24
				
				state <= state + 1;
				
			elsif (state = 3) then
				i_part <= i_part + i_inc;
				
				state <= state + 1;

			elsif (state = 4) then
				output <= resize(shift_right(p_part + i_part + omega_init, 8), output'length); -- convert Q23.24 to Q15.16
				sync_out <= '1';

				state <= state + 1;

			elsif (state = 5) then
				sync_out <= '0';
				
				state <= 0;
				
			end if;
		end if;
	end process;
end behavioral;

Leave a comment

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