M
Mark Zerr
Guest
I am currently working on a 8 bit pulse width modulator circuit for a
graduate level Digital Design course. I have a couple problems with
my current code. I am using Altera's UP-1 education board with a Flex
10K CPLD. I am using Altera's Max Plus II Baseline educational
license for VHDL compiling and simulating. I am passing the PWM
output to all 8 segments of one of the LEDs on the board and using the
8 bit switch block for user control.
1. My counter seems to double count 1111 1111 and 0000 0000. This
does not really affect the operation, except that the counter causes
the overall PWM output's period to last 2 clock cycles longer than it
should.
2. Do I really need a clock divider process to be able to slow down
the PWM train to accurately be able to use the PWM output to vary the
LED brightness? Currently, I reduce the 25 Mhz clock down to about
123 Khz, which gives 240 PWM periods per second.
3. I have a glitch on the 1111 1111 control input condition caused by
my bad counter issue in #1 above. Not a big deal, but I like my stuff
to be perfect.
Here is my current code...any help or suggestions for improving it are
welcomed.
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.all;
USE IEEE.STD_LOGIC_ARITH.all;
USE IEEE.STD_LOGIC_UNSIGNED.all;
ENTITY PWM_8BIT is
PORT( clk, RESET : IN STD_LOGIC;
CONTROL : IN STD_LOGIC_VECTOR(7 downto 0);
COUNT_OUT : OUT STD_LOGIC_VECTOR(7 downto 0);
PWM_LED_OUT : OUT STD_LOGIC_VECTOR(7 downto 0);
CLK_DIV_OUT : OUT STD_LOGIC);
END PWM_8BIT;
ARCHITECTURE ARCHI of PWM_8BIT is
SIGNAL clk_div : STD_LOGIC;
SIGNAL COUNT_ALL : STD_LOGIC_VECTOR(7 downto 0);
SIGNAL CONTROL_INT : STD_LOGIC_VECTOR(7 downto 0);
SIGNAL PWM_INT : STD_LOGIC_VECTOR(7 downto 0);
BEGIN
CONTROL_INT <= CONTROL; --Store the User input in a signal
-- An up/down counter
PROCESS (clk_div, RESET)
VARIABLE UP_DOWN_INT : STD_LOGIC;
VARIABLE COUNT_INT : STD_LOGIC_VECTOR(7 downto 0);
VARIABLE DIRECTION : INTEGER;
BEGIN
IF RESET = '0' THEN --If RESET than count goes to "0"
COUNT_INT := "00000000";
ELSE
IF COUNT_INT = "00000000" THEN --Find the count direction
UP_DOWN_INT := '1';
END IF;
IF COUNT_INT = "11111111" THEN
UP_DOWN_INT := '0';
END IF;
IF UP_DOWN_INT = '1' THEN --Inc or dec selection
DIRECTION := 1;
ELSE
DIRECTION := -1;
END IF;
IF (clk_div'EVENT AND clk_div = '1') THEN --Update the counter on
the clock edge
COUNT_INT := COUNT_INT + DIRECTION;
END IF;
END IF;
COUNT_OUT <= COUNT_INT; --Copy the count to the output pins
COUNT_ALL <= COUNT_INT; --Pass the count to an internal signal
END PROCESS;
--Comparator Logic
PROCESS (clk_div, RESET)
BEGIN
IF RESET = '0' THEN --If reset then make pwm-->0
PWM_INT <= "11111111";
ELSE
IF COUNT_ALL >= CONTROL_INT THEN --Compare the count to the control
input value
PWM_INT <= "11111111"; --if bigger, then turn on the pwm
ELSE
PWM_INT <= "00000000"; --if smaller, then turn off the pwm
END IF;
END IF;
END PROCESS;
--Hack the PWM output if it is screwed up!
PROCESS (clk_div, RESET)
BEGIN
IF (clk_div'EVENT AND clk_div = '1') THEN --This makes sure the PWM
only changes on an edge
-- IF CONTROL_INT = "11111111" THEN --This stuff attempts to fix
"11111111" condition.
-- PWM_LED_OUT <= "00000000"; --This stuff attempts to fix
"11111111" condition.
-- ELSE --This stuff attempts to fix "11111111" condition.
PWM_LED_OUT <= PWM_INT;
-- END IF; --This stuff attempts to fix "11111111" condition.
END IF;
END PROCESS;
--Stupid clock divider
PROCESS(clk)
VARIABLE i : INTEGER range 0 to 100 := 0;
BEGIN
IF clk'event AND clk = '1' THEN
IF i = 100 THEN
i := 0;
clk_div <= NOT clk_div;
ELSE
i := i + 1;
END IF;
END IF;
CLK_DIV_OUT <= clk_div;
END PROCESS;
END ARCHI;
graduate level Digital Design course. I have a couple problems with
my current code. I am using Altera's UP-1 education board with a Flex
10K CPLD. I am using Altera's Max Plus II Baseline educational
license for VHDL compiling and simulating. I am passing the PWM
output to all 8 segments of one of the LEDs on the board and using the
8 bit switch block for user control.
1. My counter seems to double count 1111 1111 and 0000 0000. This
does not really affect the operation, except that the counter causes
the overall PWM output's period to last 2 clock cycles longer than it
should.
2. Do I really need a clock divider process to be able to slow down
the PWM train to accurately be able to use the PWM output to vary the
LED brightness? Currently, I reduce the 25 Mhz clock down to about
123 Khz, which gives 240 PWM periods per second.
3. I have a glitch on the 1111 1111 control input condition caused by
my bad counter issue in #1 above. Not a big deal, but I like my stuff
to be perfect.
Here is my current code...any help or suggestions for improving it are
welcomed.
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.all;
USE IEEE.STD_LOGIC_ARITH.all;
USE IEEE.STD_LOGIC_UNSIGNED.all;
ENTITY PWM_8BIT is
PORT( clk, RESET : IN STD_LOGIC;
CONTROL : IN STD_LOGIC_VECTOR(7 downto 0);
COUNT_OUT : OUT STD_LOGIC_VECTOR(7 downto 0);
PWM_LED_OUT : OUT STD_LOGIC_VECTOR(7 downto 0);
CLK_DIV_OUT : OUT STD_LOGIC);
END PWM_8BIT;
ARCHITECTURE ARCHI of PWM_8BIT is
SIGNAL clk_div : STD_LOGIC;
SIGNAL COUNT_ALL : STD_LOGIC_VECTOR(7 downto 0);
SIGNAL CONTROL_INT : STD_LOGIC_VECTOR(7 downto 0);
SIGNAL PWM_INT : STD_LOGIC_VECTOR(7 downto 0);
BEGIN
CONTROL_INT <= CONTROL; --Store the User input in a signal
-- An up/down counter
PROCESS (clk_div, RESET)
VARIABLE UP_DOWN_INT : STD_LOGIC;
VARIABLE COUNT_INT : STD_LOGIC_VECTOR(7 downto 0);
VARIABLE DIRECTION : INTEGER;
BEGIN
IF RESET = '0' THEN --If RESET than count goes to "0"
COUNT_INT := "00000000";
ELSE
IF COUNT_INT = "00000000" THEN --Find the count direction
UP_DOWN_INT := '1';
END IF;
IF COUNT_INT = "11111111" THEN
UP_DOWN_INT := '0';
END IF;
IF UP_DOWN_INT = '1' THEN --Inc or dec selection
DIRECTION := 1;
ELSE
DIRECTION := -1;
END IF;
IF (clk_div'EVENT AND clk_div = '1') THEN --Update the counter on
the clock edge
COUNT_INT := COUNT_INT + DIRECTION;
END IF;
END IF;
COUNT_OUT <= COUNT_INT; --Copy the count to the output pins
COUNT_ALL <= COUNT_INT; --Pass the count to an internal signal
END PROCESS;
--Comparator Logic
PROCESS (clk_div, RESET)
BEGIN
IF RESET = '0' THEN --If reset then make pwm-->0
PWM_INT <= "11111111";
ELSE
IF COUNT_ALL >= CONTROL_INT THEN --Compare the count to the control
input value
PWM_INT <= "11111111"; --if bigger, then turn on the pwm
ELSE
PWM_INT <= "00000000"; --if smaller, then turn off the pwm
END IF;
END IF;
END PROCESS;
--Hack the PWM output if it is screwed up!
PROCESS (clk_div, RESET)
BEGIN
IF (clk_div'EVENT AND clk_div = '1') THEN --This makes sure the PWM
only changes on an edge
-- IF CONTROL_INT = "11111111" THEN --This stuff attempts to fix
"11111111" condition.
-- PWM_LED_OUT <= "00000000"; --This stuff attempts to fix
"11111111" condition.
-- ELSE --This stuff attempts to fix "11111111" condition.
PWM_LED_OUT <= PWM_INT;
-- END IF; --This stuff attempts to fix "11111111" condition.
END IF;
END PROCESS;
--Stupid clock divider
PROCESS(clk)
VARIABLE i : INTEGER range 0 to 100 := 0;
BEGIN
IF clk'event AND clk = '1' THEN
IF i = 100 THEN
i := 0;
clk_div <= NOT clk_div;
ELSE
i := i + 1;
END IF;
END IF;
CLK_DIV_OUT <= clk_div;
END PROCESS;
END ARCHI;