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 with 16-bit MCU interface. -- -- PWM bit width is configurable by PWM_WIDTH generic parameter and must be in -- range of 1 to 16. Default is 16. -- -- 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. -- -- MCU interface consist of one r/w 16-bit register holding PWM value. -------------------------------------------------------------------------------- entity omsp_pwm is generic ( ADDR : integer := 16#0160#; PWM_WIDTH : integer := 16); port ( -- MCU peripheral interface mclk : in std_logic; puc : in std_logic; per_addr : in std_logic_vector (7 downto 0); per_en : in std_logic; per_wen : in std_logic_vector (1 downto 0); per_din : in std_logic_vector (15 downto 0); per_dout : out std_logic_vector (15 downto 0); -- PWM interface pwm_cnt : in std_logic_vector (PWM_WIDTH-1 downto 0); pwm : out std_logic); end omsp_pwm; -------------------------------------------------------------------------------- architecture behavioral of omsp_pwm is signal pwm_value : std_logic_vector (15 downto 0); signal pwm_sel : boolean; -------------------------------------------------------------------------------- begin pwm_sel <= (per_addr = ADDR/2) and (per_en = '1'); per_dout <= pwm_value when pwm_sel else (others => '0'); -- Peripheral registers process (mclk, puc) begin if puc = '1' then pwm_value <= (others => '0'); elsif rising_edge(mclk) and pwm_sel then if per_wen (0) = '1' then pwm_value (7 downto 0) <= per_din (7 downto 0); end if; if per_wen (1) = '1' then pwm_value (15 downto 8) <= per_din (15 downto 8); end if; end if; end process; -- Generation of the PWM signal process (mclk, puc) begin if puc = '1' then pwm <= '0'; elsif mclk'event and mclk = '1' then if pwm_cnt < pwm_value then pwm <= '1'; else pwm <= '0'; end if; end if; end process; end behavioral;