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.

You can follow its development on www.jktdev.co.uk.

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

Bill of Materials (BOM)

Reference Qty Value Footprint LCSC Part No MFR Part No Description
U1,U2 2 74HC165 Package_SO:SOIC-16_4.55x10.3mm_P1.27mm C5613 74HC165D Shift Register, 8-bit, Parallel Load
U3,U4 2 74HC595 Package_SO:SOIC-16_4.55x10.3mm_P1.27mm C5947 74HC595D -40°C~+125°C 100MHz [email protected], 50pF 2V~6V 74HC Series Serial-to-Serial or Parallel Tri-State SOIC-16 Shift Registers ROHS
R41,R42,R43,R44,R45,R46,R47,R48,R49,R50,R51,R52,R53,R54,R55,R56 16 1K Resistor_SMD:R_0402_1005Metric C11702 0402WGF1001TCE Resistor
C1 1 10uF Capacitor_SMD:C_1206_3216Metric C13585 CL31A106KBHNNNE Unpolarized capacitor, small symbol
C2,C3,C4,C5 4 100nF Capacitor_SMD:C_0603_1608Metric_Pad1.08x0.95mm_HandSolder C14663 CC0603KRX7R9BB104 Unpolarized capacitor, small symbol
R89 1 0R Resistor_SMD:R_1206_3216Metric_Pad1.30x1.75mm_HandSolder C17888 1206W4F0000T5E Resistor
R57,R58,R59,R60,R61,R62,R63,R64,R65,R66,R67,R68,R69,R70,R71,R72 16 330R Resistor_SMD:R_0603_1608Metric_Pad0.98x0.95mm_HandSolder C23138 0603WAF3300T5E Resistor
R24 1 470R Resistor_SMD:R_0402_1005Metric C25117 0402WGF4700TCE Resistor
R17,R18,R19,R20,R21,R22,R23,R25,R26,R27,R28,R29,R30,R31,R32,R33,R34,R35,R36,R37,R38,R39,R40 23 10K Resistor_SMD:R_0402_1005Metric C25744 0402WGF1002TCE Resistor
D9 1 LED LED_SMD:LED_0603_1608Metric_Pad1.05x0.95mm_HandSolder C510025 SML-D12M8WT86 Light emitting diode
J2,J3 2 Inputs TerminalBlock_Phoenix:TerminalBlock_Phoenix_MPT-0,5-10-2.54_1x10_P2.54mm_Horizontal C918128 DB125-2.54-10P-GN-S Generic screw terminal, single row, 01x10, script generated (kicad-library-utils/schlib/autogen/connector/)
J4,J5 2 Logic Level Outputs TerminalBlock_Phoenix:TerminalBlock_Phoenix_MPT-0,5-10-2.54_1x10_P2.54mm_Horizontal C918128 DB125-2.54-10P-GN-S Generic screw terminal, single row, 01x10, script generated (kicad-library-utils/schlib/autogen/connector/)

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