#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/

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]

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

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

Return to “Introduction to CPLD and FPGA”

Who is online

Users browsing this forum: No registered users and 1 guest