#8 LED Dimming via PWM [Post Homework Here]

Talk about the fifth PyroEDU course here.
ThePyroElectro
PyroElectro Admin
Posts: 1181
Joined: Mon Nov 12, 2007 9:24 pm
Location: Earth
Contact:

#8 LED Dimming via PWM [Post Homework Here]

Postby ThePyroElectro » Sat Aug 16, 2014 1:54 pm

A new lesson was posted today:
http://www.pyroelectro.com/edu/fpga/led_dimming_pwm/

Post your homework answers here to compare with everyone else!

Bingo600
Newbie Pyro
Posts: 75
Joined: Sat Jun 28, 2014 7:22 am

Re: #8 LED Dimming via PWM [Post Homework Here]

Postby Bingo600 » Sun Aug 17, 2014 2:01 pm

Chris here is my homework


HOMEWORK QUESTION 1
Name 2 uses of PWM output signals.

Driving leds
Driving motors
Emulating a DAC (with a LC filter on output) , i have used that for variable "contrast" on a "standard" 2x16 HD44xx char lcd.

HOMEWORK QUESTION 2
What modifications would be necessary to make the VHDL program in lesson 8 both fade in
and fade out?

Basically one should "invert" the led assignment after the "ramp up".
I think it could be done with toggling a (down flag) and an then invert of the counter comparison:
UP - if count_0 < count_1 then
Down - if count_0 > count_1 then

I didn't have much success , as it became "pulsing" instead.
I did it another way , see S3E below.


HOMEWORK QUESTION 3
How are duty cycle, period and frequency attributes used to describe PWM signals?

PWM has 2 attributes , period and dutycycle. The 3'rd : Frequency is 1/period is a definition.
The period defines the total pulse-width (time) , and the dutycycle (percent) defines for how long the signal is on/off within the pulse-width.
So a dutycycle of 50/50 would mean equal on/off time , and a dutycycle of 70/30 would mean 70% on and 30% off.
If the period is too short when controlling leds , one would see flickering.

Bingo600
Newbie Pyro
Posts: 75
Joined: Sat Jun 28, 2014 7:22 am

Re: #8 LED Dimming via PWM [Post Homework Here]

Postby Bingo600 » Sun Aug 17, 2014 2:25 pm

You had me on this S3E implementation :?

I used the "Code" , and it was cycling much faster than your video.
I thought i had an error in my 1KHz clockgenerator , and had to output 5Khz to get it to somewhat match your cycle.

Then after the 3'rd watch of the video ... I noticed you count to 100 in the video and 500 in the Code :wink:

Dammm ... One should never "cheat" and "Use the SOURCE" unless the lastname is "Skywalker"

Well i got it to work

Code: Select all

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;



entity lesson8 is
   Generic ( osc_freq: natural := 50000000);
   port(
   RESET: in std_logic;
   clk: in std_logic;
   LED: out std_logic_vector(3 downto 0)
   );
   --constant FREQ_OF_CLK_IN_HZ = 25000000; -- 25 MHz clock
end lesson8;
   
architecture rtl of lesson8 is
   signal khz_1: std_logic :='0';
   signal CLOCK_0: std_logic :='0';   
   signal count_0 : std_logic_vector(3 downto 0);
   signal count_1 : std_logic_vector(3 downto 0);
   signal led_output : std_logic_vector(3 downto 0) := "0000";   

begin --arch

---------------------- Begin 50Mhz to 1KHz Clock divide ---------------------------


   
-- 1KHz Clock   Process
   CLOCK_1KHz: process(clk,RESET)
   VARIABLE ticks:integer range 0 to ((osc_freq/1000)/2); --50Mhz to 1KHz*2 = divide by 50000/2
   begin
   if RESET = '1' then
      ticks:=0;
      khz_1 <= '0';
   elsif rising_edge(clk) then
      ticks:=ticks+1;
      if ticks = ((osc_freq/1000)/2) then
         khz_1 <= not khz_1;
         ticks:=0;
      end if;
   end if;
   end process CLOCK_1Khz;

-- 1KHz resync to 50Mhz
   KHZ_1_sync: process(clk,khz_1,RESET)
   begin
   if RESET = '1' then
      CLOCK_0 <= '0';
   elsif rising_edge(clk) then
      CLOCK_0 <= khz_1;
   end if;
   end process KHZ_1_sync;   
   
---------------------- End 50Mhz to 1KHz Clock divide ---------------------------

   PWM_MODULE_0: process(RESET,CLOCK_0)
   begin
      if RESET = '1' then
         count_0 <= "0000";
         elsif rising_edge(CLOCK_0)then
         count_0 <= count_0 + 1;   
         if count_0 < count_1 then
            led_output <= "1111";
         else
            led_output <= "0000";
         end if; -- if count_0 < ...
      end if; -- RESET ...
      
   end process PWM_MODULE_0;

   COUNTER_0: process(RESET,CLOCK_0)
   variable cnt: integer range 0 to 127;
   begin
      if RESET = '1' then
         count_1 <= "0000";
      elsif rising_edge(CLOCK_0) then
         if cnt = 99 then
            count_1 <= count_1 + 1;
            cnt:= cnt + 1;
         elsif cnt = 100 then
            cnt := 0;
         else
            cnt := cnt + 1;
         end if;
      end if;
   end process COUNTER_0;
   
   LED <= led_output;
   
end rtl;   


To fade down instead , was "easy" ....

Either invert the led assignments or invert the counter0/1 comparison in the PWM process.

But to fade up & down .... :oops:



Btw why use the if elseif else below :

Code: Select all

      elsif rising_edge(CLOCK_0) then
         if cnt = 99 then
            count_1 <= count_1 + 1;
            cnt:= cnt + 1;
         elsif cnt = 100 then
            cnt := 0;
         else
            cnt := cnt + 1;
         end if;


and not just

Code: Select all

      elsif rising_edge(CLOCK_0) then
         if cnt = 100 then
            count_1 <= count_1 + 1;
            cnt:=0;
         else
            cnt := cnt + 1;
         end if;


Is there a "special reason" or ?

Ahhh ..... Is that the "trick" for circumventing that a signal read from anothe process is always "one behind" ???
Clever .... Set it on 99 , and it will react in PWM on 100

See my struggle here:
viewtopic.php?f=26&t=832#p3160



/Bingo
Last edited by Bingo600 on Sun Aug 17, 2014 2:48 pm, edited 3 times in total.

Bingo600
Newbie Pyro
Posts: 75
Joined: Sat Jun 28, 2014 7:22 am

Re: #8 LED Dimming via PWM [Post Homework Here]

Postby Bingo600 » Sun Aug 17, 2014 2:39 pm

The fade up/down was a tough one (for me at least)

I first tried with a "down" flag , that i was toggling when cnt = 100 , in the COUNTER_0 process.
Then testing if it was 0 or 1 in the PWM process and "inverting the led outputs".

But it was giving a pulsating output and didn't work.

I tried many versions , and couldn't get it to work (prob. due to my lack of VHDL (RTL) knowledge).

I finally extended the counters one bit , and created a : signal led_states : std_logic_vector(3 downto 0) := "1111";
This one i could "invert" when in the "upper half" of the extended counter, and that would invert the dimming/fading.

Code: Select all

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;



entity lesson8 is
   Generic ( osc_freq: natural := 50000000);
   port(
   RESET: in std_logic;
   clk: in std_logic;
   LED: out std_logic_vector(3 downto 0)
   );
   --constant FREQ_OF_CLK_IN_HZ = 25000000; -- 25 MHz clock
end lesson8;
   
architecture rtl of lesson8 is
   signal khz_1: std_logic :='0';
   signal CLOCK_0: std_logic :='0';   
   signal count_0 : std_logic_vector(4 downto 0);
   signal count_1 : std_logic_vector(4 downto 0);
   signal led_states : std_logic_vector(3 downto 0) := "1111";
   signal led_output : std_logic_vector(3 downto 0) := "0000";   

begin --arch

---------------------- Begin 50Mhz to 1KHz Clock divide ---------------------------


   
-- 1KHz Clock   Process
   CLOCK_1KHz: process(clk,RESET)
   VARIABLE ticks:integer range 0 to ((osc_freq/1000)/2); --50Mhz to 1KHz*2 = divide by 50000/2
   begin
   if RESET = '1' then
      ticks:=0;
      khz_1 <= '0';
   elsif rising_edge(clk) then
      ticks:=ticks+1;
      if ticks = ((osc_freq/1000)/2) then
         khz_1 <= not khz_1;
         ticks:=0;
      end if;
   end if;
   end process CLOCK_1Khz;

-- 1KHz resync to 50Mhz
   KHZ_1_sync: process(clk,khz_1,RESET)
   begin
   if RESET = '1' then
      CLOCK_0 <= '0';
   elsif rising_edge(clk) then
      CLOCK_0 <= khz_1;
   end if;
   end process KHZ_1_sync;   
   
---------------------- End 50Mhz to 1KHz Clock divide ---------------------------

   PWM_MODULE_0: process(RESET,CLOCK_0)
   begin
      if RESET = '1' then
         count_0 <= "00000";
         led_states <= "1111";
         elsif rising_edge(CLOCK_0)then
         count_0 <= count_0 + 1;   
         
         --if count_0'left = '0' then -- if in lower half of counter - ***Can't stnthesize
         --if count_0 < 16 then -- if in lower half of counter
         
         -- Toggle bright/dim
         if count_0(4) = '0' then -- if in lower half of counter
            led_states <= "1111";   -- dim up
         else
            led_states <= "0000";   -- dim down
         end if; -- count_0(4) = ...
         
         --
         if count_0 < count_1 then
            led_output <= led_states;  --if ledstates = 1111 dim_up else down
         else
            led_output <= not led_states;
         end if; -- if count_0 < ...
      end if; -- RESET ...
      
   end process PWM_MODULE_0;

   COUNTER_0: process(RESET,CLOCK_0)
   variable cnt: integer range 0 to 127;
   begin
      if RESET = '1' then
         count_1 <= "00000";
      elsif rising_edge(CLOCK_0) then
         if cnt = 99 then
            count_1 <= count_1 + 1;
            cnt:= cnt + 1;
         elsif cnt = 100 then
            cnt := 0;
         else
            cnt := cnt + 1;
         end if;
      end if;
   end process COUNTER_0;
   
   LED <= led_output;
   
end rtl;   


It blinks a bit during the fading , especially when fading down in the low duty cycles.
So maybe i still haven't got it correct.

And it could do with some "dead time" on top & bottom.
Hmmm .....

/Bingo

Bingo600
Newbie Pyro
Posts: 75
Joined: Sat Jun 28, 2014 7:22 am

Re: #8 LED Dimming via PWM [Post Homework Here]

Postby Bingo600 » Sun Aug 17, 2014 4:22 pm

Just me toying with initializers & stuff
Avoiding to be bitten by "0000" fields when making the counter 5-bit long.

Neat initializer stuff here
http://vhdlguru.blogspot.se/2010/02/arr ... -vhdl.html




Code: Select all

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;



entity lesson8 is
   Generic ( osc_freq: natural := 50000000);
   port(
   RESET: in std_logic;
   clk: in std_logic;
   LED: out std_logic_vector(3 downto 0)
   );
   --constant FREQ_OF_CLK_IN_HZ = 25000000; -- 25 MHz clock
end lesson8;
   
architecture rtl of lesson8 is
   signal khz_1: std_logic :='0';
   signal CLOCK_0: std_logic :='0';   
   signal count_0 : std_logic_vector(4 downto 0) := "00000";
   signal count_1 : std_logic_vector(4 downto 0) := "00000";
   signal led_states : std_logic_vector(3 downto 0) := "1111";
   --signal led_output : std_logic_vector(3 downto 0) := "0000";   
   signal led_output : std_logic_vector(3 downto 0) := (others => '0');

begin --arch

---------------------- Begin 50Mhz to 1KHz Clock divide ---------------------------


   
-- 1KHz Clock   Process
   CLOCK_1KHz: process(clk,RESET)
   VARIABLE ticks:integer range 0 to ((osc_freq/1000)/2); --50Mhz to 1KHz*2 = divide by 50000/2
   begin
   if RESET = '1' then
      ticks:=0;
      khz_1 <= '0';
   elsif rising_edge(clk) then
      ticks:=ticks+1;
      if ticks = ((osc_freq/1000)/2) then
         khz_1 <= not khz_1;
         ticks:=0;
      end if;
   end if;
   end process CLOCK_1Khz;

-- 1KHz resync to 50Mhz
   KHZ_1_sync: process(clk,khz_1,RESET)
   begin
   if RESET = '1' then
      CLOCK_0 <= '0';
   elsif rising_edge(clk) then
      CLOCK_0 <= khz_1;
   end if;
   end process KHZ_1_sync;   
   
---------------------- End 50Mhz to 1KHz Clock divide ---------------------------

   PWM_MODULE_0: process(RESET,CLOCK_0)
   begin
      if RESET = '1' then
         count_0 <= (others => '0');
         led_states <= (others => '1');
         elsif rising_edge(CLOCK_0)then
         count_0 <= count_0 + 1;   
         
         if count_0(count_0'left) = '0' then -- if in lower half of counter - *** Works
         --if count_0 < 16 then -- if in lower half of counter
         
         -- Toggle bright/dim
         --if count_0(4) = '0' then -- if in lower half of counter
            led_states <= (others => '1');   -- dim up
         else
            led_states <= (others => '0');   -- dim down
         end if; -- count_0(4) = ...
         
         --
         if count_0 < count_1 then
            led_output <= led_states;  --if ledstates = 1111 dim_up else down
         else
            led_output <= not led_states;
         end if; -- if count_0 < ...
      end if; -- RESET ...
      
   end process PWM_MODULE_0;

   COUNTER_0: process(RESET,CLOCK_0)
   variable cnt: integer range 0 to 127;
   begin
      if RESET = '1' then
         count_1 <= (others => '0');
         --CONV_STD_LOGIC_VECTOR(0, count_1'length)
      elsif rising_edge(CLOCK_0) then
         if cnt = 99 then
            count_1 <= count_1 + 1;
            cnt:= cnt + 1;
         elsif cnt = 100 then
            cnt := 0;
         else
            cnt := cnt + 1;
         end if;
      end if;
   end process COUNTER_0;
   
   LED <= led_output;
   
end rtl;   

ThePyroElectro
PyroElectro Admin
Posts: 1181
Joined: Mon Nov 12, 2007 9:24 pm
Location: Earth
Contact:

Re: #8 LED Dimming via PWM [Post Homework Here]

Postby ThePyroElectro » Tue Aug 19, 2014 6:45 pm

Bingo600 wrote:Chris here is my homework


HOMEWORK QUESTION 1
Name 2 uses of PWM output signals.

Driving leds
Driving motors
Emulating a DAC (with a LC filter on output) , i have used that for variable "contrast" on a "standard" 2x16 HD44xx char lcd.

HOMEWORK QUESTION 2
What modifications would be necessary to make the VHDL program in lesson 8 both fade in
and fade out?

Basically one should "invert" the led assignment after the "ramp up".
I think it could be done with toggling a (down flag) and an then invert of the counter comparison:
UP - if count_0 < count_1 then
Down - if count_0 > count_1 then

I didn't have much success , as it became "pulsing" instead.
I did it another way , see S3E below.


HOMEWORK QUESTION 3
How are duty cycle, period and frequency attributes used to describe PWM signals?

PWM has 2 attributes , period and dutycycle. The 3'rd : Frequency is 1/period is a definition.
The period defines the total pulse-width (time) , and the dutycycle (percent) defines for how long the signal is on/off within the pulse-width.
So a dutycycle of 50/50 would mean equal on/off time , and a dutycycle of 70/30 would mean 70% on and 30% off.
If the period is too short when controlling leds , one would see flickering.

Good answers. The theory for question 2 is easier to come up with in your mind than the real code is. But it looks like you built some code up that works...although check out my suggestion!

Bingo600 wrote:You had me on this S3E implementation :?

I used the "Code" , and it was cycling much faster than your video.
I thought i had an error in my 1KHz clockgenerator , and had to output 5Khz to get it to somewhat match your cycle.

Then after the 3'rd watch of the video ... I noticed you count to 100 in the video and 500 in the Code :wink:

Dammm ... One should never "cheat" and "Use the SOURCE" unless the lastname is "Skywalker"

Well i got it to work



:shock: I might need to make a note about that in the video.

Bingo600 wrote:
...
...

Is there a "special reason" or ?

Ahhh ..... Is that the "trick" for circumventing that a signal read from anothe process is always "one behind" ???
Clever .... Set it on 99 , and it will react in PWM on 100


I wasn't going for any tricks; rather, I wanted to make it more obvious of what actions were happening at what specific clock counts by separating the conditional statements.

Bingo600 wrote:The fade up/down was a tough one (for me at least)

I first tried with a "down" flag , that i was toggling when cnt = 100 , in the COUNTER_0 process.
Then testing if it was 0 or 1 in the PWM process and "inverting the led outputs".

But it was giving a pulsating output and didn't work.

I tried many versions , and couldn't get it to work (prob. due to my lack of VHDL (RTL) knowledge).

I finally extended the counters one bit , and created a : signal led_states : std_logic_vector(3 downto 0) := "1111";
This one i could "invert" when in the "upper half" of the extended counter, and that would invert the dimming/fading.

It blinks a bit during the fading , especially when fading down in the low duty cycles.
So maybe i still haven't got it correct.

And it could do with some "dead time" on top & bottom.


You're getting there. A suggestion I will make is what you have already (mostly) implemented. Using a 1 bit signal toggle/enable for whether the system should be counting up or counting down with the slower counter.

Bingo600 wrote:Just me toying with initializers & stuff
Avoiding to be bitten by "0000" fields when making the counter 5-bit long.

Neat initializer stuff here
http://vhdlguru.blogspot.se/2010/02/arr ... -vhdl.html



To my knowledge, signal initializations in architectures aren't actually synthesized into the design, instead they're used purely for when you do test bench simulations. To make sure your FPGA/CPLD initializes correctly, often times you will have power-on reset circuit hardware built next to your device to send a reset signal some milliseconds after power supplies are all registered as available and good.

cam
Newbie Pyro
Posts: 1
Joined: Sun Nov 22, 2015 4:09 pm
Location: France

Re: #8 LED Dimming via PWM [Post Homework Here]

Postby cam » Sun Nov 22, 2015 4:21 pm

Hi,

First of all, Thanks for the tutorials! They made me interested into VHDL for solving issues in a project I have for a little while now.
I was working on the dimming up & down. I believe I am not far from having it working properly but, right now it somehow looks unstable.
Meaning it is fading up/down but with some glitches.

I'll continue to work on that. Here's the code:

Code: Select all

LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_unsigned.ALL;

ENTITY PWM_LED IS
   PORT(reset, clock_0: IN std_logic;
                  leds: OUT std_logic_vector(3 downto 0));
END PWM_LED;
   
ARCHITECTURE rtl OF PWM_LED IS
--Number of LEDs defines how much dimming steps there is - 2LEDS/4STEPS 4LEDS/16STEPS - see code in COUNTER_0 process
   SIGNAL up_down : std_logic := '0';
   SIGNAL count_0 : std_logic_vector(3 downto 0) := (OTHERS => '0');
   SIGNAL count_1 : std_logic_vector(3 downto 0) := (OTHERS => '0');
   SIGNAL leds_out : std_logic_vector(3 downto 0) := (OTHERS => '0');

BEGIN 
   PWM_MODULE_0: PROCESS(reset, clock_0)
   BEGIN
      IF reset = '1' THEN count_0 <= (OTHERS => '0');
      ELSIF rising_edge(clock_0) AND up_down = '0' THEN count_0 <= count_0 + 1;   
         IF count_0 < count_1 THEN leds_out <= (OTHERS => '1');
         ELSE leds_out <= (OTHERS => '0');
         END IF;
      ELSIF rising_edge(clock_0) AND up_down = '1' THEN count_0 <= count_0 - 1;   
         IF count_0 > count_1 THEN leds_out <= (OTHERS => '1');
         ELSE leds_out <= (OTHERS => '0');
         END IF;
      END IF;     
   END PROCESS PWM_MODULE_0;

   COUNTER_0: PROCESS(reset, clock_0)
   variable cnt1: integer range 0 to 100 := 0;
   variable cnt2: integer range 0 to 100 := 0;
   BEGIN   
      IF reset = '1' THEN count_1 <= (OTHERS => '0');
         ELSIF rising_edge(clock_0) AND up_down = '0' THEN
            IF cnt1 = 99 THEN count_1 <= count_1 + 1;
               ELSIF cnt1 = 100 THEN up_down <= '1';
                                       cnt1 := 0;
               ELSE cnt1 := cnt1 + 1;                     
            END IF;
         ELSIF rising_edge(clock_0) AND up_down = '1' THEN
            IF cnt2 = 99 THEN count_1 <= count_1 - 1;
               ELSIF cnt2 = 100 THEN up_down <= '0';
                                     cnt2 := 0;
               ELSE cnt2 := cnt2 + 1;                     
            END IF;
      END IF;
   END PROCESS COUNTER_0;
 
   leds <= leds_out;
   
END rtl;


Return to “Introduction to CPLD and FPGA”

Who is online

Users browsing this forum: No registered users and 2 guests