Bird
Raised Fist0
VHDLprogramming~5 mins

PWM generator in VHDL

Choose your learning style10 modes available
Introduction

A PWM generator creates a signal that switches on and off quickly to control power or speed, like dimming a light or controlling a motor.

To control the brightness of an LED by changing how long it stays on.
To adjust the speed of a small motor in a toy or robot.
To send signals to devices that need varying power levels.
To create sound tones by turning a signal on and off rapidly.
Syntax
VHDL
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity pwm_generator is
    port(
        clk      : in  std_logic;
        reset    : in  std_logic;
        duty     : in  unsigned(7 downto 0); -- duty cycle 0-255
        pwm_out  : out std_logic
    );
end pwm_generator;

architecture Behavioral of pwm_generator is
    signal counter : unsigned(7 downto 0) := (others => '0');
begin
    process(clk, reset)
    begin
        if reset = '1' then
            counter <= (others => '0');
            pwm_out <= '0';
        elsif rising_edge(clk) then
            if counter < 255 then
                counter <= counter + 1;
            else
                counter <= (others => '0');
            end if;

            if counter < duty then
                pwm_out <= '1';
            else
                pwm_out <= '0';
            end if;
        end if;
    end process;
end Behavioral;

The duty input controls how long the output stays high in one cycle.

The counter runs from 0 to 255 to create a full PWM cycle.

Examples
This sets the PWM signal to be on half the time and off half the time.
VHDL
duty <= to_unsigned(128, 8); -- 50% duty cycle
This sets the PWM signal to be on 25% of the time and off 75%.
VHDL
duty <= to_unsigned(64, 8); -- 25% duty cycle
This makes the PWM output always on (full power).
VHDL
duty <= to_unsigned(255, 8); -- 100% duty cycle
Sample Program

This program creates a PWM signal with a 50% duty cycle, then changes it to 25%, and finally to 100%. The testbench simulates the clock and shows how the output changes over time.

VHDL
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity pwm_generator is
    port(
        clk      : in  std_logic;
        reset    : in  std_logic;
        duty     : in  unsigned(7 downto 0);
        pwm_out  : out std_logic
    );
end pwm_generator;

architecture Behavioral of pwm_generator is
    signal counter : unsigned(7 downto 0) := (others => '0');
begin
    process(clk, reset)
    begin
        if reset = '1' then
            counter <= (others => '0');
            pwm_out <= '0';
        elsif rising_edge(clk) then
            if counter < 255 then
                counter <= counter + 1;
            else
                counter <= (others => '0');
            end if;

            if counter < duty then
                pwm_out <= '1';
            else
                pwm_out <= '0';
            end if;
        end if;
    end process;
end Behavioral;

-- Testbench to simulate PWM output
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity pwm_tb is
end pwm_tb;

architecture Behavioral of pwm_tb is
    signal clk     : std_logic := '0';
    signal reset   : std_logic := '1';
    signal duty    : unsigned(7 downto 0) := (others => '0');
    signal pwm_out : std_logic;

    constant clk_period : time := 10 ns;

begin
    uut: entity work.pwm_generator
        port map(
            clk => clk,
            reset => reset,
            duty => duty,
            pwm_out => pwm_out
        );

    clk_process : process
    begin
        while true loop
            clk <= '0';
            wait for clk_period / 2;
            clk <= '1';
            wait for clk_period / 2;
        end loop;
    end process;

    stim_proc: process
    begin
        wait for 20 ns;
        reset <= '0';
        duty <= to_unsigned(128, 8); -- 50% duty cycle
        wait for 2600 ns;
        duty <= to_unsigned(64, 8); -- 25% duty cycle
        wait for 2600 ns;
        duty <= to_unsigned(255, 8); -- 100% duty cycle
        wait;
    end process;
end Behavioral;
OutputSuccess
Important Notes

In real hardware, the PWM frequency depends on the clock speed and counter size.

Changing the duty cycle changes how long the output stays high in each cycle.

Resetting the counter ensures the PWM starts cleanly.

Summary

PWM generator creates a signal that switches on and off to control power.

Duty cycle controls how long the signal stays on in each cycle.

VHDL uses a counter and compares it to the duty cycle to create PWM.

Practice

(1/5)
1. What is the main purpose of a PWM generator in VHDL?
easy
A. To create a signal that switches on and off quickly to control power
B. To store data in memory
C. To perform arithmetic calculations
D. To generate random numbers

Solution

  1. Step 1: Understand PWM function

    PWM (Pulse Width Modulation) generates a signal that switches on and off rapidly.
  2. Step 2: Identify purpose in power control

    This switching controls the power delivered to devices by changing the duty cycle.
  3. Final Answer:

    To create a signal that switches on and off quickly to control power -> Option A
  4. Quick Check:

    PWM controls power by switching signal [OK]
Hint: PWM controls power by fast on/off switching [OK]
Common Mistakes:
  • Confusing PWM with memory storage
  • Thinking PWM does arithmetic
  • Assuming PWM generates random signals
2. Which VHDL statement correctly compares a counter to a duty cycle to generate a PWM output?
easy
A. pwm_out := '1' if counter > duty_cycle else '0';
B. pwm_out = '1' when counter = duty_cycle else '0';
C. pwm_out <= '1' when counter < duty_cycle else '0';
D. pwm_out <= '1' if counter = duty_cycle else '0';

Solution

  1. Step 1: Identify correct VHDL assignment syntax

    In VHDL, signal assignment uses '<=' and conditional assignment uses 'when ... else'.
  2. Step 2: Match correct comparison and syntax

    pwm_out <= '1' when counter < duty_cycle else '0'; uses '<=' and 'when ... else' with correct comparison 'counter < duty_cycle'.
  3. Final Answer:

    pwm_out <= '1' when counter < duty_cycle else '0'; -> Option C
  4. Quick Check:

    VHDL signal conditional assignment = pwm_out <= '1' when counter < duty_cycle else '0'; [OK]
Hint: Use '<=' with 'when ... else' for conditional signal assignment [OK]
Common Mistakes:
  • Using ':=' instead of '<=' for signals
  • Using 'if' instead of 'when' in signal assignment
  • Using '=' for assignment instead of comparison
3. Given this VHDL snippet for PWM output:
process(clk)
begin
  if rising_edge(clk) then
    if counter < duty_cycle then
      pwm_out <= '1';
    else
      pwm_out <= '0';
    end if;
    if counter = max_count then
      counter <= 0;
    else
      counter <= counter + 1;
    end if;
  end if;
end process;

What is the value of pwm_out when counter is 3 and duty_cycle is 5?
medium
A. Undefined
B. '1'
C. '0'
D. Error

Solution

  1. Step 1: Compare counter and duty_cycle values

    Counter is 3, duty_cycle is 5, so 3 < 5 is true.
  2. Step 2: Determine pwm_out value based on condition

    Since counter < duty_cycle, pwm_out is assigned '1'.
  3. Final Answer:

    '1' -> Option B
  4. Quick Check:

    3 < 5 means pwm_out = '1' [OK]
Hint: If counter < duty_cycle, pwm_out is '1' [OK]
Common Mistakes:
  • Confusing '<' with '>' in condition
  • Assuming pwm_out is '0' when counter < duty_cycle
  • Ignoring the process clock edge condition
4. Identify the error in this VHDL PWM process:
process(clk)
begin
  if clk'event and clk = '1' then
    if counter <= duty_cycle then
      pwm_out <= '1';
    else
      pwm_out <= '0';
    end if;
    if counter = max_count then
      counter <= 0;
    else
      counter <= counter + 1;
    end if;
  end if;
end process;
medium
A. Using 'clk'event and clk = '1' instead of rising_edge(clk)
B. Using '<=' in 'if counter <= duty_cycle' instead of '<'
C. Missing reset condition for counter
D. No error, code is correct

Solution

  1. Step 1: Check clock edge detection method

    Using 'clk'event and clk = '1' is legal but less safe than rising_edge(clk).
  2. Step 2: Identify best practice for clock edge

    rising_edge(clk) is preferred for clarity and synthesis compatibility.
  3. Final Answer:

    Using 'clk'event and clk = '1' instead of rising_edge(clk) -> Option A
  4. Quick Check:

    Use rising_edge(clk) for clock detection [OK]
Hint: Use rising_edge(clk) for clock detection [OK]
Common Mistakes:
  • Using 'clk'event and clk = '1' which is outdated
  • Confusing '<=' with '<' in duty cycle comparison
  • Ignoring reset logic necessity
5. You want to design a PWM generator in VHDL that supports variable frequency and duty cycle. Which approach correctly allows changing frequency and duty cycle dynamically?
hard
A. Use asynchronous signals to change frequency and duty cycle without counters
B. Use a fixed counter for frequency and hard-coded duty cycle value
C. Use a single counter and fix duty cycle at compile time
D. Use two counters: one for period (frequency) and one for duty cycle comparison, both updated dynamically

Solution

  1. Step 1: Understand dynamic frequency and duty cycle needs

    Changing frequency means changing the PWM period, so a period counter is needed.
  2. Step 2: Use counters for period and duty cycle comparison

    One counter tracks the period length, another compares to duty cycle to set output.
  3. Step 3: Allow dynamic updates

    Both counters and duty cycle values must be variable to change PWM parameters on the fly.
  4. Final Answer:

    Use two counters: one for period (frequency) and one for duty cycle comparison, both updated dynamically -> Option D
  5. Quick Check:

    Two counters enable dynamic frequency and duty cycle [OK]
Hint: Use separate counters for period and duty cycle [OK]
Common Mistakes:
  • Fixing duty cycle or frequency at compile time
  • Using asynchronous signals causing glitches
  • Trying to change frequency without a period counter
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard