Chris_C Posted December 10, 2013 Report Share Posted December 10, 2013 for my second project I decided to PWM the brightness of the LED here's what I ended up with... is this basically the right idea?library IEEE;use IEEE.STD_LOGIC_1164.ALL;use IEEE.STD_LOGIC_UNSIGNED.ALL;entity main is Port ( clock : in STD_LOGIC; led1 : out STD_LOGIC );end main;architecture Behavioral of main is signal counter : STD_LOGIC_VECTOR(22 downto 0) := (others => '0'); signal onDuty : std_logic_vector(6 downto 0) := (others => '0'); signal dutyCount : std_logic_vector(6 downto 0) := (others => '0'); signal subCounter : std_logic_vector(10 downto 0) := "00000000001";begin clock_proc: process(clock) begin if rising_edge(clock) then counter(22 downto 0) <= counter(22 downto 0) + 1; if counter = 0 then -- change the duty cycle onDuty(6 downto 0) <= onDuty(6 downto 0) + 5; -- +5% if onDuty > 100 then onDuty <= (others => '0'); end if; end if; -- counter = 0 -- down counter subCounter(10 downto 0) <= subCounter(10 downto 0) - 1; if subCounter = 0 then subCounter <= "10000000000"; dutyCount(6 downto 0) <= dutyCount(6 downto 0) + 1; if dutyCount > 100 then dutyCount <= (others => '0'); end if; if dutyCount < onDuty then led1 <= '1'; else led1 <= '0'; end if; end if; -- subCounter = 0 end if; -- rising edge clock end process;end Behavioral;it does actually seem to work at any rate! Link to comment Share on other sites More sharing options...
hamster Posted December 10, 2013 Report Share Posted December 10, 2013 If it works, then it is good.:-) You could take a few shortcuts and save resources, you should be able to reduce resources by not havng "subcounter" and instead using something like "if Counter(9 downto 0) = 0 then..." It is important to note that the order of the "if" and the counter increment is different to how it actually will happen - in this code it looks as though the increment happens first, then the "if". The "if" clause is evaluated with the value of the counter when the process is envoked, so it is the same as if counter = 0 then .... end if; -- counter = 0 counter(22 downto 0) <= counter(22 downto 0) + 1; This gives a subtle bug in your code.... onDuty(6 downto 0) <= onDuty(6 downto 0) + 5; -- +5% if onDuty > 100 then onDuty <= (others => '0'); end if; is the same as if onDuty > 100 then onDuty <= (others => '0'); else onDuty(6 downto 0) <= onDuty(6 downto 0) + 5; -- +5% end if; This allows onDuty to become values > 100. What you might have really meant is if onDuty > 100-5 then onDuty <= onDuty- 95; -- +5%, and wrap around - range is 0 to 100.else onDuty <= onDuty + 5; -- +5%end if; Side issue - I always find it interesting how an 8 bit PWM counter can actually have 257 possible states - 0/256, 1/256.... 255/256, 256/256 - so needs nine bits to hold its desired state (or teh counter should should wrap at from 254 to 0, giving a different PWM frequency). Link to comment Share on other sites More sharing options...
Chris_C Posted December 10, 2013 Author Report Share Posted December 10, 2013 okay so why did I change >99 to >100? doh ! nice spot! binary duty cycle is slightly more efficient than percentage but with 7bits you're only "loosing" 28 values... on a related matter the clock IP wizard can only go down to 1mhz is there no way to utilize the clock tiles for kHz type speeds? Link to comment Share on other sites More sharing options...
Chris_C Posted December 11, 2013 Author Report Share Posted December 11, 2013 okay version two fades up then fades down and repeats....library IEEE;use IEEE.STD_LOGIC_1164.ALL;use IEEE.STD_LOGIC_UNSIGNED.ALL;use ieee.numeric_std.all;entity main is Port ( clock : in STD_LOGIC; led1 : out STD_LOGIC );end main;architecture Behavioral of main is signal counter : STD_LOGIC_VECTOR(21 downto 0) := (others => '0'); signal onDuty : signed(7 downto 0) := (others => '0'); signal dutyCount : signed(7 downto 0) := (others => '0'); signal subCounter : std_logic_vector(10 downto 0) := "00000000001"; signal direction : boolean := true;begin clock_proc: process(clock) begin if rising_edge(clock) then counter(21 downto 0) <= counter(21 downto 0) + 1; if counter = 0 then -- change the duty cycle if direction then onDuty(7 downto 0) <= onDuty(7 downto 0) + 5; -- +5% else onDuty(7 downto 0) <= onDuty(7 downto 0) - 5; -- -5% end if; if onDuty < 0 then onDuty <= (others => '0'); direction <= not direction; end if; if onDuty > 99 then onDuty <= "01100011"; direction <= not direction; end if; end if; -- counter = 0 -- down counter subCounter(10 downto 0) <= subCounter(10 downto 0) - 1; if subCounter = 0 then subCounter <= "10000000000"; dutyCount(7 downto 0) <= dutyCount(7 downto 0) + 1; if dutyCount > 99 then dutyCount <= (others => '0'); end if; if dutyCount < onDuty then led1 <= '1'; else led1 <= '0'; end if; end if; -- subCounter = 0 end if; -- rising edge clock end process;end Behavioral;notice the extra sign bit(s) which allows you to detect downward direction going past zero to set the bounce back.... Link to comment Share on other sites More sharing options...
hamster Posted December 11, 2013 Report Share Posted December 11, 2013 Nope - the internal elements used to implement the clock synthisis have a fixed range they can work in. The "proper way" to run at 32kHz is to generate a "clock enable" pulse once every 1000 cycles, and run the whole design at 32MHz. if rising_edge(clk_32MHz) then if clock_enable = '1' then --- do stuff; at 32kHz end if; if count = 999 then count <= (others => '0'); clock_enable <= '1'; else count <= count+ 1; clock_enable <= '0'; end if; However, you could try using the upper bit on a counter that is feed by a MHz range clock as a clock signal. You might want to feed the bit into a global clock buffer to make it work correctly.... The synthisis tools might complain about what you are doing though, as it migh foul up the static timing analysis. Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.