Digital I/O Expander Board

Revision Status

Revision Status Changes
Rev A Active (Initial release)

Digital I/O Expander Board

The Digital I/O Expander Board is a deterministic, shift-register-based expansion module providing 16 digital inputs and 16 digital outputs. It allows you to significantly scale the number of digital inputs and outputs available to a microcontroller using only a small, dedicated set of control lines.

Features

  • 32-Channel Expansion: Adds 16 inputs and 16 outputs to your design.
  • Deterministic Interface: Uses simple serial shift registers instead of bus-based GPIO expander ICs, preventing bus lockup risks and offering predictable timing.
  • Robust Connections: The host microcontroller connects via a centralized 12-pin header, while all 32 external I/O channels, along with 3.3 V and GND rails, are broken out to screw terminal blocks.

Circuitry & Component Details

  • Input Side: Employs 2 × 74HC165 parallel-in, serial-out shift registers.
  • Output Side: Employs 2 × 74HC595 serial-in, parallel-out shift registers.

[!IMPORTANT] Rev A Silkscreen Labeling Issue: On Rev A boards, the input channel labels are reversed across each 8-input bank: * Physical input I0 is labeled as I7 (and vice-versa). * Physical input I8 is labeled as I15 (and vice-versa).

The electrical connections are fully functional, but you must map the inputs in software or account for this reversal in your wiring. This silkscreen mapping issue has been resolved in the Rev B PCB design.

Pinout & Interface

12-Pin Control Header

Pin Label Direction Description
1 3.3V Input Logic Supply (Typically 3.3 V)
2 INDATA Output Serial Data Line (74HC165)
3 /INDATA Output Inverted Serial Data Line (74HC165, optional spare)
4 /INLOAD Input Input Parallel Load line (Active Low, 74HC165)
5 INCLK Input Input Clock line for input shift registers (74HC165)
6 GND Input Logic Ground Reference
7 OUTCLK Input Output Clock line for output shift registers (74HC595)
8 LATCH Input Output Latch line to update output pins (74HC595)
9 /OUTEN Input Output Enable (Active Low, 74HC595)
10 OUTDATA Input Output Serial Data Line (74HC595)
11 /OUTCLR Input Master Reset / Clear (Active Low, 74HC595)
12 GND Input Logic Ground Reference

Test Verification & Code

This board has been verified using a Raspberry Pi Pico 2 W running MicroPython. The following code reads the 16 inputs and mirrors their states directly onto the 16 outputs (accounting for the physical channel layout).

import machine
import time

# Initialize status LED
led = machine.Pin("LED", machine.Pin.OUT)

# Output Shift Register (74HC595) Pins
outclk = machine.Pin(1, machine.Pin.OUT)
outlatch = machine.Pin(2, machine.Pin.OUT)
_outen = machine.Pin(3, machine.Pin.OUT)
outdata = machine.Pin(4, machine.Pin.OUT)
_outclr = machine.Pin(5, machine.Pin.OUT)

# Input Shift Register (74HC165) Pins
indata = machine.Pin(6, machine.Pin.IN)
_inload = machine.Pin(8, machine.Pin.OUT)
inclk = machine.Pin(9, machine.Pin.OUT)

# Enable outputs and clear any existing register data
_outen.value(0)
_outclr.value(0)
time.sleep(0.1)
_outclr.value(1)

while True:
    led.toggle()

    # Latch the current states of physical inputs into the 74HC165 registers
    _inload.value(0)
    time.sleep(0.0001)
    _inload.value(1)

    bitstream = 0

    # Clock in the 16 bits of input data
    for i in range(16):
        readbit = indata.value()

        # Build bitstream
        if readbit:
            bitstream = bitstream | (1 << i)
        else:
            bitstream = bitstream & ~(1 << i)

        inclk.value(0)
        time.sleep(0.0001)
        inclk.value(1)

    # Latch line low to prepare for serial output transmission
    outlatch.value(0)
    outclk.value(0)
    time.sleep(0.0001)

    # Clock out the 16 bits to the 74HC595 outputs
    for i in range(16):
        outclk.value(0)
        time.sleep(0.0001)

        # Extract bit to send
        bittoset = (bitstream >> (15 - i)) & 1

        outdata.value(bittoset)
        led.value(bittoset)

        outclk.value(1)
        time.sleep(0.0001)

    # Latch the data to the physical outputs
    outlatch.value(1)

Gerber Files

Project Files