Generating a PWM (Pulse Width Modulation) signal with an FPGA involves configuring a counter-comparator logic block to control the duty cycle and frequency. Below is a step-by-step guide using Verilog/VHDL for implementation on Xilinx (Artix-7/Kintex-7) or Intel (Cyclone/MAX 10) FPGAs.
1. PWM Basics
- PWM = A square wave with adjustable duty cycle (pulse width) and frequency.
- Duty Cycle = (ON time) / (Total Period) × 100%
- Frequency = 1 / (Total Period)
2. Hardware Requirements
- FPGA Board (e.g., Xilinx Artix-7, Intel Cyclone IV).
- Clock Source (e.g., 50 MHz onboard oscillator).
- Output Pin (connected to LED, motor driver, or oscilloscope).
3. PWM Implementation in Verilog
A. Simple PWM Generator
verilog
module pwm_generator (
input clk, // FPGA clock (e.g., 50 MHz)
input reset, // Active-high reset
input [7:0] duty, // 8-bit duty cycle (0-255 = 0%-100%)
output reg pwm_out // PWM output signal
);
reg [7:0] counter; // 8-bit counter (0-255)
always @(posedge clk or posedge reset) begin
if (reset) begin
counter <= 0;
pwm_out <= 0;
end
else begin
counter <= counter + 1;
pwm_out <= (counter < duty) ? 1 : 0; // Compare & set PWM
end
end
endmodule
Key Points:
- duty controls the ON time (e.g., duty = 128 → 50% duty cycle).
- Frequency = clk_freq / (2^counter_bits) (e.g., 50 MHz / 256 ≈ 195.3 kHz for 8-bit counter).
B. Adjustable Frequency PWM
To control both frequency and duty cycle, add a period register:
verilog
module pwm_advanced (
input clk,
input reset,
input [15:0] period, // Total clock cycles per PWM period
input [15:0] duty, // ON time (must be ≤ period)
output reg pwm_out
);
reg [15:0] counter;
always @(posedge clk or posedge reset) begin
if (reset) begin
counter <= 0;
pwm_out <= 0;
end
else begin
if (counter >= period - 1)
counter <= 0;
else
counter <= counter + 1;
pwm_out <= (counter < duty) ? 1 : 0;
end
end
endmodule
Example Settings:
For 1 kHz PWM with 50 MHz clock:
period = 50,000,000 / 1,000 = 50,000
duty = 25,000 → 50% duty cycle.
4. PWM Implementation in VHDL
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 STD_LOGIC_VECTOR (7 downto 0);
pwm : 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 <= '0';
elsif rising_edge(clk) then
counter <= counter + 1;
if counter < unsigned(duty) then
pwm <= '1';
else
pwm <= '0';
end if;
end if;
end process;
end Behavioral;
5. Testing PWM on Hardware
A. Pin Assignment
Connect pwm_out to an FPGA GPIO pin (check your board’s constraints file).
Example (Xilinx Artix-7):
tcl
set_property PACKAGE_PIN "R10" [get_ports pwm_out]
set_property IOSTANDARD LVCMOS33 [get_ports pwm_out]
B. Verification
- Oscilloscope: Check PWM waveform.
- LED: Vary duty to see brightness change.
- Logic Analyzer: Capture duty cycle transitions.
6. Advanced PWM Techniques
A. Dead-Time Insertion (For H-Bridge Motors)
- Adds a small delay between PWM transitions to prevent shoot-through.
- Requires two complementary PWM signals with adjustable delay.
B. Center-Aligned PWM
- Used in motor control for symmetric waveforms.
- Implemented with up/down counters:
verilog
if (direction == UP)
counter <= counter + 1;
else
counter <= counter - 1;
C. Using FPGA IP Cores
Xilinx "AXI Timer" or Intel "PWM IP Core" for hardware-optimized PWM.
7. Example Applications
- Motor Speed Control (H-Bridge driver).
- LED Dimming (adjust brightness).
- Servo Control (1-2 ms pulses @ 50 Hz).
- Audio Generation (class-D amplifiers).
Conclusion
- Basic PWM = Counter + Comparator.
- Frequency depends on clock speed and counter resolution.
- Duty cycle is set by comparing counter to a threshold.
- FPGAs excel at PWM due to parallel hardware control.
Top comments (0)