8 bit PWM modulator help

Discussion in 'VHDL' started by Mark Zerr, Apr 9, 2004.

  1. Mark Zerr

    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;
    Mark Zerr, Apr 9, 2004
    #1
    1. Advertising

  2. Mark Zerr

    Garrett Mace Guest

    1. Is your up/down counter REALLY behaving the way you want it to? Is there
    anything about your end-value comparisons that might keep your up/down
    toggles from being activated in the current clock cycle?

    2. Do you really even need an up/down counter, instead of a simple counter
    that just rolls over to zero?

    I haven't looked at the code very hard, but these might be two things to
    consider.
    Garrett Mace, Apr 10, 2004
    #2
    1. Advertising

  3. Mark Zerr

    Mark Zerr Guest

    "Garrett Mace" <> wrote in message news:<LFKdc.78570$-kc.rr.com>...
    > 1. Is your up/down counter REALLY behaving the way you want it to? Is there
    > anything about your end-value comparisons that might keep your up/down
    > toggles from being activated in the current clock cycle?


    I suspect this is my problem, but I cannot figure out what is wrong
    with my programming as it is currently coded.

    >
    > 2. Do you really even need an up/down counter, instead of a simple counter
    > that just rolls over to zero?


    Yes, it must be an up/down counter....it is a requirement of the
    project to simulate a triangular wave for the comparison to generate
    the PWM train output.


    >
    > I haven't looked at the code very hard, but these might be two things to
    > consider.



    Thanks for your help though....any other ideas comments are
    appreciated.
    Mark Zerr, Apr 11, 2004
    #3

  4. > > 2. Do you really even need an up/down counter, instead of a simple

    counter
    > > that just rolls over to zero?

    >
    > Yes, it must be an up/down counter....it is a requirement of the
    > project to simulate a triangular wave for the comparison to generate
    > the PWM train output.

    What are advantages of traingular over saw-edged wave? BTW, they both are
    triangular.
    valentin tihomirov, Apr 11, 2004
    #4
  5. Mark Zerr

    Marcin Guest

    (Mark Zerr) wrote in message news:<>...
    > 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.


    Mark,

    Look carefully at the sensitivity list - comparator logic is simple
    combinational logic. I will change it to: PROCESS (COUNT_ALL,
    CONTROL_INT, RESET)

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

    [...]

    Stupid clock divider is really stupid without reset;)

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


    I hope this help a little.

    Marcin
    Marcin, Apr 11, 2004
    #5
  6. Mark Zerr

    Mark Zerr Guest

    "valentin tihomirov" <> wrote in message news:<c5be1v$2r5n2n$-berlin.de>...
    > > > 2. Do you really even need an up/down counter, instead of a simple

    > counter
    > > > that just rolls over to zero?

    > >
    > > Yes, it must be an up/down counter....it is a requirement of the
    > > project to simulate a triangular wave for the comparison to generate
    > > the PWM train output.

    > What are advantages of traingular over saw-edged wave? BTW, they both are
    > triangular.


    To be honest....I would have not even wanted to use an up/down
    counter. I would have simply counted from 0 to max...with the middle
    being the the pseudo cross over point for the "triangular" wave. For
    some reason my professor wanted a true up/down counter. I think it
    was to show the problems that can arise when designing a counter like
    this. As for the saw toothed wave, I am not sure what the advantage
    of that wave would be compared to the way I am doing it now. In all
    reality it does not matter. The circuit works perfectly fine right
    now, but I was curious if I was missing some good design principles,
    since I am so new to vhdl.
    Mark Zerr, Apr 12, 2004
    #6
  7. Mark Zerr

    Mark Zerr Guest

    (Marcin) wrote in message news:<>...

    >
    > Mark,
    >
    > Look carefully at the sensitivity list - comparator logic is simple
    > combinational logic. I will change it to: PROCESS (COUNT_ALL,
    > CONTROL_INT, RESET)
    >


    Yes this is a good point. I have changed the sensitivity list.
    Sometimes I still get confused about the proper sensitivities for a
    given process. VHDL is very foreign to me since everything is
    happening concurrently. This type of programming caused me major
    headaches when I first started learning a couple weeks ago.

    >
    > Stupid clock divider is really stupid without reset;)
    >
    >
    > I hope this help a little.
    >
    > Marcin


    I agree that my clock divider should have a reset. This has been
    fixed. It was an oversight...trust me!

    Thanks for your input Marcin!
    Mark Zerr, Apr 12, 2004
    #7
  8. Mark Zerr

    Garrett Mace Guest


    > To be honest....I would have not even wanted to use an up/down
    > counter. I would have simply counted from 0 to max...with the middle
    > being the the pseudo cross over point for the "triangular" wave. For
    > some reason my professor wanted a true up/down counter. I think it
    > was to show the problems that can arise when designing a counter like
    > this. As for the saw toothed wave, I am not sure what the advantage
    > of that wave would be compared to the way I am doing it now. In all
    > reality it does not matter. The circuit works perfectly fine right
    > now, but I was curious if I was missing some good design principles,
    > since I am so new to vhdl.



    A saw-toothed "wave" is simpler to understand and implement. Part of a
    project I did a while back was generating eight different sine waves through
    PWM. I used one very simple PWM clock that looked like this:

    ***
    entity PWMClock is
    port (
    CLK, Enable, RST : in std_logic;
    PWMClockOut : out std_logic_vector(7 downto 0)
    );
    end PWMClock;

    architecture PWM of PWMClock is

    signal PWMTemp : std_logic_vector(7 downto 0);

    begin

    process (CLK, RST)
    begin
    if (RST = '1') then
    PWMTemp <= "00000000";
    elsif (rising_edge(CLK) and Enable = '1') then
    PWMTemp <= PWMTemp + 1;
    end if;
    end process;

    PWMClockOut <= PWMTemp;

    end PWM;
    ***



    This was a "sawtooth wave," merely a counter that rolls over. Then the eight
    PWM modules all used this same clock. The actual PWM output modules were
    also very simple:



    ***
    entity PWMOutput is
    port (
    RST : in std_logic;
    PWMLevel, PWMClock : in std_logic_vector(7 downto 0);
    PWMOut : out std_logic
    );
    end PWMOutput;

    architecture PWM of PWMOutput is

    signal PWMOutTemp : std_logic;

    begin

    process (PWMClock, RST) is

    begin

    if (PWMClock = "00000000") then
    PWMOutTemp <= '1';
    elsif (PWMClock = PWMLevel or RST = '1') then
    PWMOutTemp <= '0';
    end if;

    end process;

    PWMOut <= PWMOutTemp;

    end PWM;
    ***

    PWMLevel was piped in from a sine table. As you can see, the PWM module just
    checked for equality and then toggled a flip-flop, to turn off the output
    once the PWM value had been reached. This was Xilinx VHDL instead of Altera,
    so some parts might be less familiar to you. There may be a more optimized
    solution for PWM if you work in structural instead of behavioral, but this
    is pretty simple.
    Garrett Mace, Apr 12, 2004
    #8
  9. Mark Zerr

    Mark Zerr Guest

    "Garrett Mace" <> wrote in message news:<3ezec.84859$-kc.rr.com>...
    >
    > A saw-toothed "wave" is simpler to understand and implement. Part of a
    > project I did a while back was generating eight different sine waves through
    > PWM. I used one very simple PWM clock that looked like this:
    >
    > ***
    > entity PWMClock is
    > port (
    > CLK, Enable, RST : in std_logic;
    > PWMClockOut : out std_logic_vector(7 downto 0)
    > );
    > end PWMClock;
    >
    > architecture PWM of PWMClock is
    >
    > signal PWMTemp : std_logic_vector(7 downto 0);
    >
    > begin
    >
    > process (CLK, RST)
    > begin
    > if (RST = '1') then
    > PWMTemp <= "00000000";
    > elsif (rising_edge(CLK) and Enable = '1') then
    > PWMTemp <= PWMTemp + 1;
    > end if;
    > end process;
    >
    > PWMClockOut <= PWMTemp;
    >
    > end PWM;
    > ***
    >
    >
    >
    > This was a "sawtooth wave," merely a counter that rolls over. Then the eight
    > PWM modules all used this same clock. The actual PWM output modules were
    > also very simple:
    >


    OK...this makes sense.

    >
    >
    > ***
    > entity PWMOutput is
    > port (
    > RST : in std_logic;
    > PWMLevel, PWMClock : in std_logic_vector(7 downto 0);
    > PWMOut : out std_logic
    > );
    > end PWMOutput;
    >
    > architecture PWM of PWMOutput is
    >
    > signal PWMOutTemp : std_logic;
    >
    > begin
    >
    > process (PWMClock, RST) is
    >
    > begin
    >
    > if (PWMClock = "00000000") then
    > PWMOutTemp <= '1';
    > elsif (PWMClock = PWMLevel or RST = '1') then
    > PWMOutTemp <= '0';
    > end if;
    >
    > end process;
    >
    > PWMOut <= PWMOutTemp;
    >
    > end PWM;
    > ***
    >
    > PWMLevel was piped in from a sine table. As you can see, the PWM module just
    > checked for equality and then toggled a flip-flop, to turn off the output
    > once the PWM value had been reached. This was Xilinx VHDL instead of Altera,
    > so some parts might be less familiar to you. There may be a more optimized
    > solution for PWM if you work in structural instead of behavioral, but this
    > is pretty simple.


    Yeah...I see where you are going now...this is a nice method. I have
    decided that my current glitch is not that big of deal though, and I
    intend to just leave it the way I am currently doing it. Thanks for
    all the input though...it was interesting learning another way to
    accomplish this circuit.
    Mark Zerr, Apr 13, 2004
    #9
  10. On 12 Apr 2004 06:26:01 -0700, (Mark Zerr) wrote:

    >"valentin tihomirov" <> wrote in message news:<c5be1v$2r5n2n$-berlin.de>...
    >> > > 2. Do you really even need an up/down counter, instead of a simple

    >> counter
    >> > > that just rolls over to zero?
    >> >
    >> > Yes, it must be an up/down counter....it is a requirement of the
    >> > project to simulate a triangular wave for the comparison to generate
    >> > the PWM train output.

    >> What are advantages of traingular over saw-edged wave? BTW, they both are
    >> triangular.

    >
    >To be honest....I would have not even wanted to use an up/down
    >counter. I would have simply counted from 0 to max...with the middle
    >being the the pseudo cross over point for the "triangular" wave. For
    >some reason my professor wanted a true up/down counter.


    Single-sided PWM (sawtooth) and double-sided PWM (triangle) have
    different distortion characteristics, double sided having lower
    distortion because it isn't also a form of PPM (pulse position
    modulation). Perhaps this is what your professor is looking for?

    - Brian
    Brian Drummond, Apr 14, 2004
    #10
  11. Mark Zerr

    Mark Zerr Guest

    Brian Drummond <> wrote in message news:<>...

    >
    > Single-sided PWM (sawtooth) and double-sided PWM (triangle) have
    > different distortion characteristics, double sided having lower
    > distortion because it isn't also a form of PPM (pulse position
    > modulation). Perhaps this is what your professor is looking for?
    >
    > - Brian


    Brian,

    This is interesting...I had not considered this. I spoke with my
    professor, and he seemed to indicate I was making this far more
    difficult than necessary. He said, he really just wanted to be sure
    we could work with vhdl and create a simple circuit. I think he also
    wanted us to create a PWM that basically was equivalent to its analog
    triangular analog brother.

    Mark
    Mark Zerr, Apr 15, 2004
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. iceman

    PWM using FPGA

    iceman, Nov 13, 2004, in forum: VHDL
    Replies:
    10
    Views:
    28,940
  2. Replies:
    0
    Views:
    560
  3. Paul Watson

    Is pwm Python MegaWidgets viable?

    Paul Watson, Apr 2, 2006, in forum: Python
    Replies:
    4
    Views:
    774
    James Stroud
    Apr 4, 2006
  4. john

    Modulator / Demodulator

    john, May 16, 2008, in forum: VHDL
    Replies:
    0
    Views:
    662
  5. algabusi
    Replies:
    0
    Views:
    855
    algabusi
    Oct 14, 2008
Loading...

Share This Page