---
title: How to Build a 16-Channel Digital Multiplexer on a Low-Cost FPGA
siteUrl: https://logzly.com/muxinsights
author: muxinsights (Digital Multiplexer Insights)
date: 2026-06-18T15:01:34.203623
tags: [digital, fpga, multiplexer]
url: https://logzly.com/muxinsights/how-to-build-a-16-channel-digital-multiplexer-on-a-low-cost-fpga
---


**Disclosure: We are reader supported, and earn affiliate commissions when you buy through us.**


Ever tried to read a dozen sensor signals with a tiny microcontroller and hit the wall of limited pins? That’s the exact moment a 16‑channel multiplexer becomes a lifesaver, and with a low‑cost FPGA you can get the speed and flexibility of hardware without breaking the bank.

## Why a 16-Channel Mux?

A multiplexer (or “mux”) is simply a switch that lets you pick one of many inputs and send it to a single output. In my first hobby project – a DIY [weather station](https://www.amazon.com/s?k=weather+station&tag=organizationtip101-20) – I needed to read eight temperature probes and four humidity sensors. My MCU only had ten free pins, so I built a 4‑to‑1 mux with a 74HC157. It worked, but the extra logic chips cluttered the board and added latency.

When I moved to an FPGA on a $5 development board, I realized I could replace all those discrete chips with a single programmable block. A 16‑channel mux on an FPGA gives you:

* **More channels** without extra wiring.
* **Fast switching** – the FPGA can toggle selections in a few nanoseconds.
* **Re‑configurability** – change the number of channels or add logic on the fly.

For projects where power budget is tight, our guide on [reducing power consumption in FPGA‑based multiplexed I/O](/muxinsights/reduce-power-consumption-in-fpga-based-multiplexed-i-o-practical-techniques-for-embedded-designers) offers practical techniques.

## What You Need

| Item | Why |
|------|-----|
| Low‑cost FPGA board (e.g., Lattice iCE40 or Xilinx Artix‑7 starter kit) | Small, cheap, and has enough I/O for 16 inputs + control |
| 16 digital input signals (logic‑level, 0‑3.3 V) | The sources you want to multiplex |
| One 4‑bit selector (can be from a microcontroller or internal FSM) | Chooses which input is passed through |
| One output pin (to MCU, ADC, or another block) | Carries the selected data |
| Simple PCB or breadboard, jumpers, [power supply](https://www.amazon.com/s?k=power+supply&tag=organizationtip101-20) | For wiring everything together |
| Development software (IceStorm, Vivado, or open‑source toolchain) | To write and load the HDL code |

All of these can be found in a typical hobbyist kit. No need for exotic parts.

## Step 1: Sketch the Logic on Paper

Before you open the IDE, draw a tiny block diagram. You have 16 inputs (I0 … I15), a 4‑bit selector (S3‑S0), and one output (Y). The truth is simple:

```
Y = I[S]   // where S is the binary number formed by S3..S0
```

In hardware terms, you need a **decoder** that turns the 4‑bit selector into a one‑hot 16‑bit signal, then a **multiplexer tree** that routes the chosen input to Y.

## Step 2: Write the Verilog (or VHDL)

I prefer Verilog for quick prototypes. Here’s a clean version you can copy into your project:

```verilog
module mux16 (
    input  wire [15:0] in,   // 16 parallel inputs
    input  wire [3:0]  sel,  // 4‑bit selector
    output wire        out   // selected output
);
    // One‑hot decode of selector
    wire [15:0] sel_onehot = 16'b1 << sel;

    // AND each input with its one‑hot line, then OR them together
    assign out = |(in & sel_onehot);
endmodule
```

A few notes for newcomers:

* `wire [15:0] in` is a bundle of 16 single‑bit signals. If your inputs are wider (e.g., 8‑bit ADC data) you just replicate the module for each bit.
* `16'b1 << sel` shifts a single ‘1’ left by the selector value, creating a one‑hot word where only the chosen line is high.
* The `|` operator reduces the 16‑bit result to a single bit by OR‑ing all bits together.

If you like VHDL, the same idea translates directly – just replace the shift and reduction operators with the appropriate VHDL syntax. You can also follow our step‑by‑step tutorial on [designing an 8‑to‑1 multiplexer in VHDL](/muxinsights/design-an-8-to-1-multiplexer-in-vhdl-a-step-by-step-tutorial-for-beginners) for deeper insight.

## Step 3: Add a Simple Testbench

Before you flash the FPGA, verify the logic in simulation. A tiny testbench saves hours of debugging.

```verilog
module tb_mux16;
    reg  [15:0] in;
    reg  [3:0]  sel;
    wire        out;

    mux16 uut (.in(in), .sel(sel), .out(out));

    initial begin
        // Apply a pattern where each input is its index LSB
        in = 16'b1010101010101010; // alternating 1s and 0s
        repeat (16) begin
            #10 sel = sel + 1;
            $display("sel=%b out=%b", sel, out);
        end
        $finish;
    end
endmodule
```

Run this with your chosen simulator (I use iverilog + gtkwave). You should see `out` follow the bit pattern of the selected input.

## Step 4: Map the Pins

Every FPGA board has a pin‑out file (often a `.pcf` for Lattice or `.xdc` for Xilinx). Assign the 16 input pins, the 4 selector pins, and the output pin to physical pins that match your wiring.

Example for an iCE40 board (PCF format):

```
set_io in[0]  10
set_io in[1]  11
...
set_io in[15] 25
set_io sel[0] 30
set_io sel[1] 31
set_io sel[2] 32
set_io sel[3] 33
set_io out    40
```

Double‑check the board’s schematic to avoid conflicts with power or clock pins.

## Step 5: Synthesize, Place, and Route

Run the toolchain:

```
yosys -p "synth_ice40 -top mux16 -json mux16.json" mux16.v
nextpnr-ice40 --json mux16.json --pcf board.pcf --asc mux16.asc
icepack mux16.asc mux16.bin
```

If you’re on a Xilinx board, replace the commands with `vivado -mode batch` steps. The tools will tell you if any timing constraints are missed. For a simple 16‑input mux, the timing is usually well within the FPGA’s capability.

## Step 6: Load the Bitstream

Use the board’s programmer (USB‑Blaster, FTDI, or built‑in USB) to flash the `.bin` (or `.bit`) file. Most low‑cost boards have a tiny utility like `iceprog` or `openFPGALoader`.

```bash
iceprog mux16.bin
```

Watch the LED blink (if your board has one) – that’s a good sign the FPGA accepted the new configuration.

## Step 7: Wire It Up

Now the fun part. Connect your 16 sensor lines to the input pins you assigned. Hook the selector lines to a microcontroller GPIO or to a small state machine inside the FPGA if you want autonomous scanning.

A quick way to drive the selector is to use a binary counter that increments every few milliseconds. That way each input gets a turn, and you can read the output with a single ADC channel.

```c
// Example Arduino sketch to drive the selector
uint8_t sel = 0;
void setup() {
  for (int i=2; i<6; i++) pinMode(i, OUTPUT); // pins 2‑5 as selector
}
void loop() {
  for (sel=0; sel<16; sel++) {
    for (int i=0; i<4; i++) digitalWrite(2+i, (sel>>i)&1);
    delay(5); // give FPGA time to settle
    int value = analogRead(A0); // read multiplexed output
    // process value...
  }
}
```

You’ll see the ADC reading change as each sensor is selected. If you need higher speed, tighten the delay or use hardware SPI to shift out the selector bits.

## Step 8: Add Optional Features

The beauty of an FPGA is that you can stack extra logic without extra chips. Some ideas:

* **Debounce** the inputs if they come from mechanical switches.
* **Add a small FIFO** to buffer the selected data before sending it out.
* **Implement a simple UART** inside the FPGA to stream all 16 channels directly to a PC.

All of these can be added as separate modules and wired to the same selector.

## Common Pitfalls and How to Avoid Them

| Problem | Fix |
|---------|-----|
| **Glitches on the output when selector changes** | Insert a one‑clock‑cycle register after the mux to synchronize the output. |
| **Input voltage levels don’t match FPGA I/O** | Use level shifters or voltage dividers to bring signals into the 0‑3.3 V range. |
| **Timing warnings during synthesis** | Reduce the clock speed or add a small pipeline stage inside the mux. |
| **Pin assignment conflicts** | Double‑check the board’s reference manual; some pins are reserved for configuration. |

## Wrap‑Up

Building a 16‑channel digital multiplexer on a low‑cost FPGA is a great way to learn both digital logic and practical [board design](https://www.amazon.com/s?k=board+design&tag=organizationtip101-20). You replace a handful of chips with a single programmable device, gain speed, and keep the layout tidy. Follow the steps above, tweak the design to fit your own project, and you’ll have a flexible, reusable mux that can grow with your ideas.
