library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; -------------------------------------------------------------------------------- -- This entity is a generator of PWM signal. -- -- PWM bit width is configurable by PWM_WIDTH generic parameter. -- -- In practice, to generate PWM signal component must be fed by a counter vector -- (pwm_cnt input) of appropriate width and also period! (One counter can be -- used by several PWM generators and generated signals are then synchronized.) -- -- The period of the input counter vector should be by 1 smaller than the count -- of all possible PWM values, i.e. counter vector should never reaches the -- maximum possible PWM value, and counting should start from 0. E.g. when full -- range of PWM values is used, binary counter should be reset just one step -- before it overflows. In such a case, when PWM value is maximal, output keeps -- log. 1. -- -- PWM value is buffered and any change is propageted to the output by the next -- pwm period - 'pwm_cyc' must by feed. -------------------------------------------------------------------------------- entity pwm is generic ( PWM_WIDTH : integer); port ( clk : in std_logic; reset : in std_logic; din : in std_logic_vector (PWM_WIDTH-1 downto 0); sel : in std_logic; we : in std_logic; -- PWM interface pwm_cnt : in std_logic_vector (PWM_WIDTH-1 downto 0); pwm_cyc : in std_logic; -- Indicate new pwm period pwm : out std_logic); end pwm; -------------------------------------------------------------------------------- architecture behavioral of pwm is -- Register accessible from bus signal reg : std_logic_vector (PWM_WIDTH-1 downto 0) := (others => '0'); -- Compare value during pwm cycle, loaded from 'reg' when new period begins. signal cmp : std_logic_vector (PWM_WIDTH-1 downto 0) := (others => '0'); -------------------------------------------------------------------------------- begin -- Peripheral register PWM_REGISTER : process (clk, reset) begin if rising_edge(clk) then if reset = '1' then reg <= (others => '0'); else if we = '1' and sel = '1' then reg <= din; end if; end if; end if; end process; -- Generation of PWM signal -- When 'pwm_cyc' is high then new 'cmp' is loaded and 'counter' is reset -- with next clk edge. Pwm output is delayed by one clock. PWM_GEN : process (clk, reset) begin if rising_edge(clk) then if reset = '1' then pwm <= '0'; else if pwm_cyc = '1' then cmp <= reg; end if; if pwm_cnt < cmp then pwm <= '1'; else pwm <= '0'; end if; end if; end if; end process; end behavioral;