OpenCores
URL https://opencores.org/ocsvn/signal_waveform_generator/signal_waveform_generator/trunk

Subversion Repositories signal_waveform_generator

[/] [signal_waveform_generator/] [trunk/] [hw/] [sources/] [PwmController/] [sources/] [PwmController.vhd] - Rev 2

Compare with Previous | Blame | View Log

------------------------------------------------------------------------
-- Engineer:    Dalmasso Loic
-- Create Date: 28/01/2025
-- Module Name: PwmController
-- Description:
--      PWM Controller with configurable PWM Resolution (in bits), PWM Signal Output Frequency (Hz) and PWM Signal Output Frequency Error Range (Hz).
--		The size of the Duty Cycle input is 1-bit greater than the PWM Resolution to handle 100% Duty Cycle.
--		The Duty Cyle value is dynamic but the new value will be applied only at the end of the PWM Duty Cycle Period (when Next Duty Cycle Trigger is enable).
--		User MUST carefully select generic parameters to satisfy PWM Output Frequency & Accuracy. Otherwise, assertion will be throw.
--		User can fix a Range of valid PWM Frequency Output.
--
-- Generics
--		sys_clock: System Input Clock Frequency (Hz)
--		pwm_resolution: PWM Resolution (Bits)
--		signal_output_freq: PWM Signal Output Frequency (Hz)
--		signal_output_freq_error: Range of PWM Signal Output Error Range (Hz)
-- Ports
--		Input 	-	i_sys_clock: System Input Clock
--		Input 	-	i_reset: Reset ('0': No Reset, '1': Reset)
--		Input 	-	i_duty_cycle: Duty Cycle to apply (Value Range: [0;2^pwm_resolution])
--		Output 	-	o_next_duty_cycle_trigger: Next Duty Cycle Trigger ('0': No Trigger, '1': Trigger Enable)
--		Output 	-	o_pwm: PWM Output
------------------------------------------------------------------------
 
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
 
ENTITY PwmController is
 
GENERIC(
	sys_clock: INTEGER := 100_000_000;
	pwm_resolution: INTEGER := 8;
	signal_output_freq: INTEGER := 7;
	signal_output_freq_error: INTEGER := 1
);
 
PORT(
	i_sys_clock: IN STD_LOGIC;
    i_reset: IN STD_LOGIC;
	i_duty_cycle: IN UNSIGNED(pwm_resolution downto 0);
	o_next_duty_cycle_trigger: OUT STD_LOGIC;
	o_pwm: OUT STD_LOGIC
);
 
END PwmController;
 
ARCHITECTURE Behavioral of PwmController is
 
------------------------------------------------------------------------
-- Constant Declarations
------------------------------------------------------------------------
-- System Clock Period
constant SYSTEM_CLOCK_PERIOD: REAL := real(1) / real(sys_clock);
 
-- PWM Resolution Max Value
constant PWM_RESOLUTION_MAX_VALUE: INTEGER := 2**pwm_resolution;
 
-- PWM Duty Cycle Frequency
constant PWM_DUTY_CYCLE_FREQUENCY: INTEGER := INTEGER( PWM_RESOLUTION_MAX_VALUE * signal_output_freq);
 
-- PWM Max Clock Divider
constant PWM_MAX_CLOCK_DIVIDER: INTEGER := INTEGER( real(1) / (real(PWM_RESOLUTION_MAX_VALUE) * SYSTEM_CLOCK_PERIOD * real(PWM_DUTY_CYCLE_FREQUENCY) ) );
 
------------------------------------------------------------------------
-- Signal Declarations
------------------------------------------------------------------------
-- PWM Clock Divider & Clock Enable
signal pwm_clock_divider: INTEGER range 0 to PWM_MAX_CLOCK_DIVIDER := 0;
signal pwm_clock_enable: STD_LOGIC := '0';
 
-- PWM Counter
signal pwm_counter: UNSIGNED(pwm_resolution-1 downto 0) := (others => '0');
 
-- Duty Cycle Input Register
signal duty_cycle_reg: UNSIGNED(pwm_resolution downto 0) := (others => '0');
 
------------------------------------------------------------------------
-- Module Implementation
------------------------------------------------------------------------
begin
 
	--------------------------------------------------
	-- PWM Frequency Output Configuration Assertion --
	--------------------------------------------------
	process
	variable duty_cycle: real;
	variable signal_output_freq_min: real;
	variable signal_output_freq_max: real;
	variable signal_output_freq_actual: real;
	begin
		duty_cycle := ( real(1) / ( real(PWM_RESOLUTION_MAX_VALUE) * SYSTEM_CLOCK_PERIOD * (real(PWM_MAX_CLOCK_DIVIDER) + 1.0) ) );
		signal_output_freq_min := real(signal_output_freq) - real(signal_output_freq_error);
		signal_output_freq_max := real(signal_output_freq) + real(signal_output_freq_error);
		signal_output_freq_actual := ( duty_cycle / real(PWM_RESOLUTION_MAX_VALUE) );
 
		assert (signal_output_freq_min <= signal_output_freq_actual) and (signal_output_freq_actual <= signal_output_freq_max)
		report
				"PWM Module Configuration Failure !" & LF &
				"Signal Output Freq Min: " & real'image(real(signal_output_freq_min)) & LF &
				"Signal Output Freq Max: " & real'image(real(signal_output_freq_max)) & LF &
				"Actual Signal Output Freq: " & real'image(real(signal_output_freq_actual))
		severity FAILURE;
		wait;
	end process;
 
	-----------------------
	-- PWM Clock Divider --
	-----------------------
	process(i_sys_clock)
	begin
		if rising_edge(i_sys_clock) then
 
			-- Reset PWM Clock Divider
			if (i_reset = '1') or (PWM_MAX_CLOCK_DIVIDER = 0) or (pwm_clock_divider = PWM_MAX_CLOCK_DIVIDER -1) then
				pwm_clock_divider <= 0;
 
			-- Increment PWM Clock Divider
			else
				pwm_clock_divider <= pwm_clock_divider +1;
			end if;
		end if;
	end process;
 
	-----------------------
	-- PWM Clock Enable --
	-----------------------
	process(i_sys_clock)
	begin
		if rising_edge(i_sys_clock) then
 
			-- Reset PWM Clock Enable
			if (i_reset = '1') then
				pwm_clock_enable <= '0';
 
			-- PWM Clock Enable
			elsif (PWM_MAX_CLOCK_DIVIDER = 0) or (pwm_clock_divider = PWM_MAX_CLOCK_DIVIDER -1) then
				pwm_clock_enable <= '1';
 
			-- PWM Clock Disable
			else
				pwm_clock_enable <= '0';
			end if;
		end if;
	end process;
 
	-----------------
	-- PWM Counter --
	-----------------
	process(i_sys_clock)
	begin
		if rising_edge(i_sys_clock) then
 
			-- Reset PWM Counter
			if (i_reset = '1') then
				pwm_counter <= (others => '0');
 
			-- PWM Clock Enable
			elsif (pwm_clock_enable = '1') then
 
				-- Increment PWM Counter
				pwm_counter <= pwm_counter + 1;
 
			end if;
		end if;
	end process;
 
	------------------------------
	-- Duty Cycle Input Handler --
	------------------------------
	process(i_sys_clock)
	begin
		if rising_edge(i_sys_clock) then
 
			-- Reset or PWM Clock Enable and End of PWM Counter
			if (i_reset = '1') or ((pwm_clock_enable = '1') and (pwm_counter = PWM_RESOLUTION_MAX_VALUE -1)) then
				duty_cycle_reg <= i_duty_cycle;
			end if;
 
		end if;
	end process;
 
	-----------------------------
	-- Next Duty Cycle Trigger --
	-----------------------------
	process(i_sys_clock)
	begin
		if rising_edge(i_sys_clock) then
 
			-- PWM Clock Enable and End of PWM Counter
			if (pwm_clock_enable = '1') and (pwm_counter = PWM_RESOLUTION_MAX_VALUE -1) then
				o_next_duty_cycle_trigger <= '1';
 
			else
				o_next_duty_cycle_trigger <= '0';
			end if;
 
		end if;
	end process;
 
	----------------
	-- PWM Output --
	----------------
	process(i_sys_clock)
	begin
		if rising_edge(i_sys_clock) then
 
			-- Reset PWM Output
			if (i_reset = '1') then 
				o_pwm <= '0';
 
			-- PWM Clock Enable
			elsif (pwm_clock_enable = '1') then
 
				-- Reset PWM Output
				if (pwm_counter >= duty_cycle_reg) then
					o_pwm <= '0';
 
				-- Set PWM Output
				else
					o_pwm <= '1';
				end if;
			end if;
 
		end if;
	end process;
 
end Behavioral;

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.