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

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

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

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

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

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

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

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]

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 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 clockend 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;   `

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

But to fade up & down .... 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]

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 clockend 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]

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 clockend 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
Posts: 1181
Joined: Mon Nov 12, 2007 9:24 pm
Location: Earth
Contact:

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

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

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 Dammm ... One should never "cheat" and "Use the SOURCE" unless the lastname is "Skywalker"

Well i got it to work 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]

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;`