Project 4 A Pulse-Width Modulator IP Block

Creating and programming a PWM circuit to control LED brightness



This project presents the design and implementation a more involved hardware IP block – a pulse-width modulator (PWM) signal generator. A PWM circuit creates a continuous sequence of pulses, with each pulse staring at a regular interval, and then remaining asserted for a programmable length of time. The length (or width) of the pulse in each interval can be changed, and in any given “pulse window”, the ratio of signal high time to signal low time (or “duty cycle”) establishes the information carried by the signal.

Figure 1. PWM signals and definitions
Figure 1. PWM signals and definitions

PWM signals are useful in many settings: they can be filtered with a simple passive filter (one R and one C) to create an analog voltage; they can directly drive an LED, and the perceived brightness of the LED will be proportional to the pulse high time; they can switch motor-control power FETs on and off to set DC motor speed; and there are many other uses as well.

Figure 2. PWM signals, filtering, and applications
Figure 2. PWM signals, filtering, and applications


PWM circuits are often used as simple, inexpensive DACs (Digital to Analog Converters) to create low-to-medium frequency analog voltage signals from a single digital signal. The switching digital waveform can be filtered with a low-pass filter to remove the higher frequency waveform components that originate from the pulse frequency “carrier” signal. Note the “information” in the PWM pulse train is carried by the pulse widths, and not the pulse frequency. The higher frequency “pulse frequency” is just a carrier to communicate the pulse widths, and it is intended to be filtered out.

In the case of driving an LED, the higher-frequency information is filtered out by the human eye, and not by an electronic circuit (note the human eye “bioware” can only respond to stimuli up to about 50Hz).

When creating an analog voltage output from a PWM signal, the pulse frequency should be at least 10 times higher than the output filter 3dB frequency (and preferably 100 times higher) to minimize switching noise in the output waveform. As examples, to create an analog voltage that could drive a speaker with up to 10KHz of bandwidth, a pulse frequency of at least 100Kz is required, and 500KHz would be even better. To create a bias voltage on an analog amplifier, a 1KHz pulse frequency could be used together with a 10Hz low-pass filter.

When driving an LED, the pulse frequency should be greater than 60 Hz so that LED flickering/blinking is not observable. If the pulse frequency is between 60Hz and perhaps 10KHz, the perceived LED brightness will be in direct proportion to the PWM’s duty cycle – that is, the longer the waveform is high during any pulse window, the brighter the LED will appear. (Note – if too high a pulse frequency is used, the LED may not achieve full brightness during a given pulse).

In this project, you will develop a PWM IP block to control LED brightness. The PWM circuit must be accessible/controllable from software running on the ARM, so it must instantiated as an AXI-connected peripheral device. You must create a hardware definition file to configure the processor and FPGA with your circuits, and then write software to program the PWM circuit with appropriate parameters.

When creating a PWM waveform, you must consider the frequency and resolution required by the application. The frequency is the rate at which new pulses are started, and the resolution is the number of different pulse-widths possible during one pulse window (for example, an 8-bit resolution allows for 256 different step sizes, or about .4% of duty cycle per step). Once the resolution is established, the duty cycle can be set by selecting a pulse width. To create a variable output waveform, the duty cycle can be changed in every single pulse window. To create a static output voltage, the duty cycle can be set once, and then used in every pulse window.

For any given main clock input, there is a trade-off between frequency and resolution. For example, consider a system with a 10MHz clock. If a 10-bit resolution is needed (60dB of dynamic range), then the maximum attainable frequency is 10MHz / 2^10, or a little less than 10Khz. At that frequency, an output waveform with about 1KHz of bandwidth could be constructed. If more bandwidth is needed, say up to 4KHz, then the PWM frequency would need to be around 40KHz, and that would require cutting the resolution to 8 bits (check the math!).

In a typical PWM peripheral circuit, the pulse frequency and duty cycle are set by a values in programmable registers. The pulse frequency is created using a comparator that resets a pulse-window counter, and the duty cycle is set by a comparator that drives the output waveform low whenever the count value is greater than the duty cycle value. A main clock divider is sometimes includes as well (as shown below), but if no main clock divider is included, larger values can be used in the frequency and duty cycle registers to define the same waveform.

Many microcontrollers use PWM circuits to create low-bandwidth analog signals because they require only a single pin and a simple external filter. Most microcontroller PWM signal generators can be programmed to create a pulse frequency in the 1KHz to 100KHz range, and most use an 8-bit or 16-bit value to define the pulse width (so, pulse widths from 256 to 65,384 can be defined).

Figure 3. An example circuit for creating a PWM signal
Figure 3. An example circuit for creating a PWM signal

In the circuit above, the register values could be programmed directly to define a given PWM waveform. In a more abstract (better) software interface, a frequency value could be passed into a subroutine (in Hertz), and a duty cycle value could be passed as a percentage value. The Hertz value would be used to compute the PWM frequency register value, and the percentage would be used to compute the duty cycle value register. Note that the values are not completely independent – if the PWM frequency is set too high, the PWM duty cycle range is limited.


1. Design and implement a PWM IP block

Create a PWM block in Verilog that uses a 10-bit value to set the duty cycle, and use the 10 slide switches for input. Your circuit can use Blackboard’s 100MHz FPGA clock, so with a 10-bit resolution, you can use up to a 100KHz pulse frequency (by setting the “PWM frequency” divider value in the figure above to 1000). A 100KHz frequency is of course much faster than you need to control LED brightness (in fact, it’s quite possibly too fast.). You could instead set the PWM frequency divider value to something larger, perhaps in the range of 20,000, to establish a more reasonable pulse frequency for driving LEDs. Whatever value you use for the PWM frequency, make sure your 10-bit value can define duty cycles from 0% to 100%.

For his requirement, you can use a fixed PWM Frequency divider.

2. Create a programmable 4-channel PWM LED controller

Modify your PWM controller from requirement 1 to have an AXI interface, and create four identical PWM controller circuits (for this requirement, you can again use a fixed PWM frequency). Connect the PWM outputs to LD0-LD3, and control their brightness through software running on the ARM. Include enable signals for each PWM channel, and use seperate memory locations (registers) for each channel’s duty value.

A potential register definition is shown in the table below.

Address Name Bits used Function
0x4BB03000 Control Register 3:0 Enable PWM signals on LD3:LD0. The 4 LED signals should always be low if their respective bits are cleared
0x4BB03004 PWM_LED_0 9:0 10-bit PWM duty value for LD0.
0x4BB03008 PWM_LED_1 9:0 10-bit PWM duty value for LD1.
0x4BB0300C PWM_LED_2 9:0 10-bit PWM duty value for LD2.
0x4BB03010 PWM_LED_3 9:0 10-bit PWM duty value for LD3.

As always, you should define a good software API to control your PWM module. For example, create functions to read and/or set the duty cycle, and to enable or disable the LEDs. After you’ve defined your functions, write a program to demonstrate that your IP core works as desired.

3. Create a four-channel PWM controller with programmable PWM frequencies

Modify your PWM controller so that the PWM frequency of each of the four PWM controllers can be adjusted through software. You will need to add four new regsiters to hold the PWM frequency values. Update your software interface to include PWM frequency setting functions, and write software to demonstrate your system’s new capabilities.


1. Create various colors on the RGB LEDs.

Make an RGB LED controller that allows you to change the brightness of each color channel for each RGB LED module. You can implement enables for each RGB module, or for individual channels. Create a workable software interface for your LEDs.