]> rtime.felk.cvut.cz Git - fpga/pwm.git/commitdiff
Added counter and pwm modules.
authorVladimir Burian <buriavl2@fel.cvut.cz>
Mon, 14 Mar 2011 14:05:39 +0000 (15:05 +0100)
committerVladimir Burian <buriavl2@fel.cvut.cz>
Mon, 14 Mar 2011 14:05:39 +0000 (15:05 +0100)
Verified with testbench.

counter.vhd [new file with mode: 0644]
pwm.vhd [new file with mode: 0644]
tb/Makefile [new file with mode: 0644]
tb/tb_pwm.sav [new file with mode: 0644]
tb/tb_pwm.vhd [new file with mode: 0644]

diff --git a/counter.vhd b/counter.vhd
new file mode 100644 (file)
index 0000000..9fe1f7e
--- /dev/null
@@ -0,0 +1,67 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_arith.all;
+use ieee.std_logic_unsigned.all;
+
+--------------------------------------------------------------------------------
+-- General counter which counter width and maximum value can be set by generic
+-- attributes. When 'count' is equal to MAX value, 'event_ow' is high.
+--------------------------------------------------------------------------------
+
+entity counter is
+  generic (
+    WIDTH : integer;
+    MAX   : integer);
+  port (
+    clk      : in  std_logic;
+    reset    : in  std_logic;
+    count    : out std_logic_vector (WIDTH-1 downto 0);
+    event_ow : out std_logic);
+end counter;
+
+--------------------------------------------------------------------------------
+
+architecture behavioral of counter is
+
+  signal eq_max : std_logic;            -- cnt is equal to MAX
+  signal cnt    : std_logic_vector (WIDTH-1 downto 0);
+
+--------------------------------------------------------------------------------
+
+begin
+
+  assert MAX < 2**WIDTH
+    report "MAX is bigger then counter max. value."
+    severity error;
+
+  
+  count    <= cnt;
+  event_ow <= eq_max;
+
+  
+  COUTER : process (clk, reset) is
+  begin
+    if reset = '1' then
+      cnt <= (others => '0');
+
+    elsif rising_edge(clk) then
+      if eq_max = '1' then
+        cnt <= (others => '0');
+      else
+        cnt <= cnt + 1;
+      end if;
+    end if;
+  end process;
+
+  
+  CNT_EQ_MAX : process (cnt) is
+  begin
+    if cnt = CONV_STD_LOGIC_VECTOR(MAX, WIDTH) then
+      eq_max <= '1';
+    else
+      eq_max <= '0';
+    end if;
+  end process;
+  
+end behavioral;
+
diff --git a/pwm.vhd b/pwm.vhd
new file mode 100644 (file)
index 0000000..4cfcc29
--- /dev/null
+++ b/pwm.vhd
@@ -0,0 +1,89 @@
+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);
+    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);
+  -- Compare value during pwm cycle, loaded from 'reg' when new period begins.
+  signal cmp : std_logic_vector (PWM_WIDTH-1 downto 0);
+  
+--------------------------------------------------------------------------------
+
+begin
+
+  -- Peripheral register
+  PWM_REGISTER : process (clk, reset)
+  begin
+    if reset = '1' then
+      reg <= (others => '0');
+
+    elsif rising_edge(clk) then
+      if we = '1' then
+        reg <= din;
+      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 reset = '1' then
+      pwm <= '0';
+      
+    elsif rising_edge(clk) then
+      if pwm_cyc = '1' then
+        cmp <= reg;
+      end if;
+      
+      if pwm_cnt < cmp then
+        pwm <= '1';
+      else
+        pwm <= '0';
+      end if;
+    end if;
+  end process;
+
+end behavioral;
+
diff --git a/tb/Makefile b/tb/Makefile
new file mode 100644 (file)
index 0000000..96978b4
--- /dev/null
@@ -0,0 +1,27 @@
+VHDL_MAIN     = tb_wave_table
+VHDL_ENTITIES = counter.o \
+                pwm.o
+
+STOP_TIME     = 50us
+
+
+all: $(VHDL_MAIN)
+
+run: $(VHDL_MAIN)
+       ghdl -r $< --stop-time=$(STOP_TIME) --vcd=$<.vcd
+
+view: run
+       gtkwave $(VHDL_MAIN).vcd $(VHDL_MAIN).sav
+
+$(VHDL_MAIN): $(VHDL_MAIN).o $(VHDL_ENTITIES)
+       ghdl -e -fexplicit --ieee=synopsys $@
+
+%.o: %.vhd
+       ghdl -a -fexplicit --ieee=synopsys $<
+
+%.o: ../%.vhd
+       ghdl -a -fexplicit --ieee=synopsys $<
+
+clean:
+       rm -Rf *.o *.vcd $(VHDL_MAIN) results.txt work-obj93.cf
+
diff --git a/tb/tb_pwm.sav b/tb/tb_pwm.sav
new file mode 100644 (file)
index 0000000..7832f11
--- /dev/null
@@ -0,0 +1,14 @@
+[timestart] 0
+[size] 1280 746
+[pos] -1 -1
+*-33.403706 5839000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+@28
+clk
+pwm_out
+pwm_cyc
+pwm_cnt[1:0]
+din[1:0]
+@29
+we
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/tb/tb_pwm.vhd b/tb/tb_pwm.vhd
new file mode 100644 (file)
index 0000000..5dbaaca
--- /dev/null
@@ -0,0 +1,127 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_arith.all;
+use ieee.std_logic_unsigned.all;
+
+entity tb_pwm is
+end tb_pwm;
+
+--------------------------------------------------------------------------------
+
+architecture testbench of tb_pwm is
+
+  constant period : time := 250 ns;
+  constant offset : time := 0 us;
+
+
+  constant PWM_W   : integer := 2;
+  constant CNT_MAX : integer := 2**PWM_W - 2;
+
+  
+  signal clk      : std_logic;
+  signal reset    : std_logic;
+  signal din      : std_logic_vector (PWM_W-1 downto 0);
+  signal we       : std_logic;
+  signal pwm_cnt  : std_logic_vector (PWM_W-1 downto 0);
+  signal pwm_cyc  : std_logic;
+  signal pwm_out  : std_logic;
+
+--------------------------------------------------------------------------------
+
+  component 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);
+      we      : in  std_logic;
+      pwm_cnt : in  std_logic_vector (PWM_WIDTH-1 downto 0);
+      pwm_cyc : in  std_logic;
+      pwm     : out std_logic);
+  end component pwm;
+
+  component counter is
+    generic (
+      WIDTH : integer;
+      MAX   : integer);
+    port (
+      clk      : in  std_logic;
+      reset    : in  std_logic;
+      count    : out std_logic_vector (WIDTH-1 downto 0);
+      event_ow : out std_logic);
+  end component counter;
+  
+--------------------------------------------------------------------------------
+  
+begin
+
+  uut : pwm
+    generic map (
+      PWM_WIDTH => PWM_W)
+    port map (
+      clk     => clk,
+      reset   => reset,
+      din     => din,
+      we      => we,
+      pwm_cnt => pwm_cnt,
+      pwm_cyc => pwm_cyc,
+      pwm     => pwm_out);
+  
+  counter_1 : counter
+    generic map (
+      WIDTH => PWM_W,
+      MAX   => CNT_MAX)
+    port map (
+      clk      => clk,
+      reset    => reset,
+      count    => pwm_cnt,
+      event_ow => pwm_cyc);
+
+  
+  CLK_PROC : process
+  begin
+    clk <= '0';
+    wait for offset;
+    
+    loop
+      clk <= '1';
+      wait for period/2;
+      clk <= '0';
+      wait for period/2;
+    end loop;
+  end process;
+
+
+  RSET_PROC : process
+  begin
+    reset <= '0';
+    wait for 1.5 * period;
+    reset <= '1';
+    wait for 1 * period;
+    reset <= '0';
+    wait;
+  end process;
+
+
+  ADDR_PROC : process
+  begin
+    din <= (others => '0');
+    we  <= '0';
+    
+    wait for offset;
+    wait for 3 * period;
+    
+    for i in 0 to 2*(2**PWM_W)-1 loop
+      din <= conv_std_logic_vector(i, PWM_W);
+      we <= '1';
+      wait for period;
+      we <= '0';
+      wait for 12*period;
+    end loop;
+    
+    wait;
+  end process;
+  
+end testbench;
+