Loading header...

Building Peripherals

Many FPGA systems are built from peripherals: counters, timers, PWM blocks, UARTs, SPI masters, GPIO ports, filters, and custom accelerators. A good peripheral is not just logic; it has a clear contract.

Learning Objectives

You will learn to:

  • define a register map;
  • separate bus interface logic from core logic;
  • design status and control bits;
  • think about firmware-visible behavior;
  • avoid ambiguous hardware/software contracts.

Peripheral Structure

flowchart LR A["Bus interface\naddress, write, read"] --> B["Register bank\ncontrol/status/config"] B --> C["Core logic\nPWM, UART, counter, filter"] C --> B C --> D["External pins or stream"] C --> E["Interrupt/status output"]

Keep the interface and the core separate. It makes testing easier and lets you reuse the core behind different buses.

Example Register Map

Offset Name Access Bits Purpose
0x00 CTRL R/W bit0 enable start/stop peripheral
0x04 PERIOD R/W 31:0 PWM period in clock cycles
0x08 DUTY R/W 31:0 high-time in clock cycles
0x0C STATUS R/C bit0 done, bit1 error event flags

R/C means read/clear or write-one-to-clear depending on your chosen convention. Document it.

PWM Core Example

module pwm_core (
    input  wire        clk,
    input  wire        rst,
    input  wire        enable,
    input  wire [31:0] period,
    input  wire [31:0] duty,
    output reg         pwm
);
    reg [31:0] count;

    always @(posedge clk) begin
        if (rst) begin
            count <= 0;
            pwm <= 1'b0;
        end else if (!enable) begin
            count <= 0;
            pwm <= 1'b0;
        end else begin
            count <= (count == period - 1) ? 0 : count + 1;
            pwm <= (count < duty);
        end
    end
endmodule

This core can be tested without any bus.

Hardware/Software Contract

Define:

  • reset values;
  • which bits are writable;
  • whether writes take effect immediately or at period boundary;
  • what happens for invalid values such as duty > period;
  • how status flags clear;
  • interrupt behavior;
  • clock domain assumptions.

Firmware engineers should not need to reverse-engineer the RTL.

Worked Example: Safe PWM Update

If firmware changes period and duty mid-cycle, output may glitch. A better design stores shadow registers and loads them at the period boundary.

flowchart LR A["Firmware write"] --> B["Shadow registers"] B --> C["Load at PWM wrap"] C --> D["Active period/duty"] D --> E["PWM output"]

Common Mistakes

  • Mixing bus protocol details into every core.
  • Leaving register reset values undocumented.
  • Creating status flags that firmware cannot clear safely.
  • Updating output-critical registers mid-cycle without a defined rule.
  • Forgetting that bus clock and peripheral clock may differ.

Summary

A peripheral is a hardware block plus a contract. Separate bus interface, registers, and core logic. Document register behavior precisely. Test the core by itself and the register interface separately.

Next: Pipelining, Resource Use, and Optimization.

Further Reading

  • AMBA AXI4-Lite protocol documentation
  • Wishbone bus specification
  • Vendor IP design examples
  • Open-source FPGA peripheral projects

Mind Map

mindmap root((Peripherals)) Core concept Registers expose control Status reports hardware Bus handshake Interrupt optional Applications Applications GPIO PWM Design checks SPI style blocks Checks Reset values Address map Common mistakes Common mistakes Unclear side effects No backpressure