Note: All photographs appearing on this page are freely usable for any purpose. Links to high-resolution versions of the pictures appear below each picture.

Digital Data Acquisition & Control System


96-Channel digital I/O board

High-resolution image shot with a Canon EOS 5D MII


The PPDIO96 board is a 96-channel digital I/O board. The PPDIO96 offers the following features:

  • Open Source/Open Hardware design (Creative Commons 4.0 license)
  • Single 5V power supply
  • LED indicates when power is applied
  • 96 independent input or output bits (data direction of each pin is programmable)
  • 5V/TTL-level logic on each pin
  • Up to 25 mA (sink or source) current on each I/O pin (note: it would be unwise to try and sink or source 25 mA on all I/O pins simultaneously -- that would be 2.5A on the I/O pins alone)
  • 8-position DIP switch connected to bits 88-95 (may be disabled by moving all switches to the off position)
  • Fast SPI bus operation utilizing high-performance MCP23S17 general-purpose I/O expander chips
  • Test pins for all SPI signals and IRQ pin
  • Optional programmable pull-up resistors on each input pin allows dry contact connections
  • Programmable polarity on all input pins (active low or active high)
  • Utilizes only a single SPI chip select line for all 96 I/O bits
  • Supports interrupt driven operation, selectable on a chip-by-chip (16 I/O lines per chip) basis
  • 96 I/O pins divided up into 8 banks of 12 bits each
  • Fully buffered -- presents only a single TTL load on the SPI bus and chip select lines
  • Reset and Watchdog timeout signals place all I/O expander chips in fail-safe mode (all pins programmed as inputs)
  • Up to 6 PPDIO96 boards may be daisy-chained off a single DAQ_IF board providing up to 576 bits of digital I/O
  • Optional DIN rail brackets allow installation on 35mm DIN rails
  • DIN rail brackets are available in .STL format for 3D-printing
  • Optically-isolated inputs are possible using companion PPOpto-12 board
  • Each bank of 12 I/O pins can be brought out to screw terminals using the PPBreakout board
  • Full documentation including System Requirements Specifications (SyRS), Hardware Requirements Specifications (HRS), Hardware Inspection list (HI), Hardware Test Cases (HTC), Hardware Test Procedures (HTP), Hardware Design Description (HDD), and (reverse) Traceability Matrix (RTM) are available for the DAQ system, including this board.

Bill of Materials (BOM) for the PPDIO96 board:

  • (1) 5mm LED
  • (1) 220 Ω 1/4-watt 1% resistor
  • (1) 2-pin screw terminal (5mm/0.2" centers)
  • (8) 20-pin (2x10) male headers (ribbon cable connectors)
  • (6) 2-pin headers (for jumpers)
  • Optional: (6) 2-pin jumpers
  • (6) MCP23S17 ICs
  • (1) 74HC125 quad tri-state buffer
  • (7) 0.1 µF decoupling capacitors
  • (1) 8-position DIP switch
  • (1) PPDIO96 PCB
  • Optional: (12) test pins
  • Optional: one set of horizontal 35mm DIN rail mounts for DAQ boards
  • Optional: one PPOPTO vertical 35mm DIN rail mount

Note: If you only want a few PPDIO96 PCBs, contact Plantation Productions ( to see if there are any in stock. Bare boards are $25 each plus shipping. If you need more than a couple and you're not in a huge hurry, it costs about $150 (plus about 4-6 weeks) to have a set of 10 manufactured and shipped to you from China. I use Seeed Studio Fusion PCD service ( The PPDIO96 PCBs are four-layer boards. Here are the Gerber files for them (provide these files to Seeed Studio or your personal PCB manufacturer).

PPDIO96 Gerber Files for PCB

If you want to modify or enhance the PPDIO96 design, or re-layout the PCB using Eagle, here are the Eagle files:

PPDIO96 Eagle files (Schematic and board layout)

If you simply want to view the schematic on-line, you'll find that here:

PPDIO96 Schematic (PDF)

The DIN rails were created using AutoDesk's Fusion 360 (to produce STL files) and I personally print the results on a Lulzbot Taz6 3D printer using ABS filament (ABS is recommended for this job, PLA and PETG are a bit brittle). The STL files can be found here:

PP Standard DIN Rail Brackets 3D printer files


Connecting a PPDIO96 board to a DAQ System

Up to six PPDIO96 boards can be daisy-chained to a single DAQ_IF board. On the PPDIO96 board there is a PPDIO96 input header/connector and a PPDIO96 output header connector.

The PPDIO96 In and PPDIO96 Out headers have the following pinouts:

Note that the only difference between the two is that the BS1..BS6 lines have been shifted up one pin (BS1 is lost and Vcc is connected to pin 2 on the output connector). This shift allows each PPDIO96 board to be electrically identical yet respond to a different board select pin (BS1-BS6) based on their position in the daisy-chain.

To daisy-chain PPDIO96 boards (that is, form a bus of PPDIO96 boards), use the following wiring scheme:

  1. First PPDIO96 board in chain wires its PPDIO96 input connector to the PPDIO96 connector on the DAQ_IF board
  2. Second PPDIO96 board in chain wires its PPDIO96 input connector to the output PPDIO96 connector on the first PPDIO96 board
  3. Third PPDIO96 board in chain wires its PPDIO96 input connector to the output PPDIO96 connector on the second PPDIO96 board
  4. Fourth PPDIO96 board in chain wires its PPDIO96 input connector to the output PPDIO96 connector on the third PPDIO96 board
  5. Fifth PPDIO96 board in chain wires its PPDIO96 input connector to the output PPDIO96 connector on the fourth PPDIO96 board
  6. Sixth PPDIO96 board in chain wires its PPDIO96 input connector to the output PPDIO96 connector on the fifth PPDIO96 board

The last board in the daisy chain (including the situation where there are fewer than six boards connected together) leaves its PPDIO96 output connector disconnected.

Because the DAQ system sends hi-speed SPI signals through the PPDIO96 bus connectors you should try to keep the (ribbon) cables connected the daisy-chained PPDIO96 boards as short as possible. Also try to avoid placing those cable near other high-frequency cables or cables that have large power spikes on them (to avoid inductive coupling with those other signals). The best cable arrangement is to place the boards end-to-end as close together as possible.


Connecting Digital Inputs to the PPDIO96 Board

The 96 I/O lines on the PPDIO96 are broken up into 8 banks of 12 bits/bank. Each bank has a pinout that is compatible with the PPOpto-12 and PPBreakout output connectors:


Note, however, that the bit numbers are offset according to the bank number:

Bank # Starting bit #

So, for example, pins 19 and 20 for Bank 3 would actually be D36 and D37, respectively (and pins 1 and 2 would be D47 and D46, respectively).

Because the digital inputs to the PPDIO96 aren't usually high-frequency signals (host system generally poll these inputs at around 10-20 Hz), their cabling requirements aren't as critical as the PPDIO96 in/out/bus connections.

The MCP23S17 GPIO expansion ICs used on the PPDIO96 run off a 5V power supply. Input pins expect a 5V/TTL-logic level. Either 3.3V or 5V logic as inputs will work just fine on the PPDIO96 input pins. Each pin can be programmed to provide an internal pull-up resistor (to +5V, though it is a weak pull-up) so you can use dry contact inputs as well. If you wish to connect any other voltage levels to the PPDIO96 you will need to provide a level shifter to accomplish this. One easy way to do this is to use a PPOpto-12 board that provide optical isolation and allows input voltages betwee 5VDC and 24VDC.

When using pins on the PPDIO96 as outputs, the PPDIO always produces 5V logic output values. If you need to control a higher or lower voltage you should use a level shifter circuit to achieve this. A mismatch between the PPDIO96 output voltage and some other device could damage the PPDIO96, the other device, or both.

DIP Switches on the PPDIO96

The PPDIO96 board contains eight DIP switches (in a single package) that connect to inputs D88 through D95. This provides a convenient set of switches for setting default values and other options within your software (by reading these DIP switches). The DIP switches connect the specified (input) pins to ground. To use these switches, you should program pins D88 through D95 as inputs and turn on the internal MCP23S17 pull-up resistors for those inputs. After this initialization, the system will read a closed switch as a '0' and an open switch as a '1'.

If you do not intend to use the DIP switches, you do not need to populate the DIP switch package on the board. If the DIP switch is already present and you don't want to use it, just make sure that the switches are all in the open position.

Warning: If a DIP switch is in the closed position and you program the corresponding MCP23S17 pin as an output, this will form a direct short to ground and may damage the MCP23S17 chip. If you program an MCP23S17 pin as an input and the corresponding DIP switch is closed, this will not damage the MCP23S17 but it could damage whatever device is providing the signal source. In the best case, having the switch closed will always force a read of zero, ignoring the actual input data. Moral of the story: when not use a DIP switch make sure it is in the open position; better yet, don't install the DIP switch package if you don't intend to use andy of the DIP switches. If the DIP switches are already installed (and you don't want to use them), it's probably best not to use I/O pins D88 through D95 on the PPDIO96 board.

Test Pins on the PPDIO96

The PPDIO96 board contains 12 test locations that make varous signals available to DVMs, Oscilloscopes, logic analyzers, and other devices. The PPDIO96 board provides plated-through-holes for the following test signals:

  • BS1, BS2, BS3, BS4, BS5, BS6 (SPI bus chip/board select signals)
  • MOSI (Master Out, Slave In SPI data signal)
  • MISO (Master In, Slave Out SPI data signal)
  • SCK (SPI clock signal)
  • IRQ (Common interrupt request signal sent to DAQ_IF board)
  • Gnd
  • Vcc (+5V)

You may optionally install test pins in each of these holes. A test pin allows you to clamp a test lead to the pin allowing hands-free circuit connection (otherwise you will need to press the test probe against the test signal's PCB pad).


Interrupt Support on the PPDIO96

The MCP23S17 GPIO expansion chip provides two interrupt pins (INTA and INTB). The PPDIO96 provides a jumper for each MCP23S17 IC allowing you to tie the INTA pin to the DAQ_IF interrupt line (IRQ). Placing a jumper on the two-pin IRQ header associated with each IC makes that MCP23S17's interrupts available. Leaving the jumper off the header pin (default configuration) disables hardware interrupts for that particular IC.

Note that all INTA pins for all six MCP23S17 ICs on a PPDIO96 board, and in fact, all INTA pins across all six possible boards, are connected to the same IRQ line. Therefore, if you decide to enable interrupts on certain MCP23S17 ICs, you will need to read each IC (with enabled interrupts) to determine the source of the interrupt.

Standard Firmware Note: the standard firmware provided for the DAQ_IF/Netburner combination does not support interrupt operation. If you wish to use interrupts with the PPDIO96 boards you will need to write a custom interrupt service routine to process those interrupts.

PPDIO96 I/O Expansion

ThePPDIO96 board uses six MCP23S17 general-purpose I/O (GPIO) expansion ICs. Each MCP23S16 provides 16 I/O lines that can be individually programmed as an input or an output. The PPDIO96 board provides eight banks of 12 I/O pins. The PPDIO96 circuit board arranges the ports as follows:

MCP23S17 to PPDIO96 Port Assignments
MCP23S17 #:bits used Port
#1:4, #2:8
#2:8, #3:4
#4:4, #5:8
#5:8, #6:4

Note that the data pin numbers on the MCP23S17 do not necessarily align with the bit numbers on a particular port. Pins on the MCP23S17 were assigned to pins on the bank headers to make circuit board layout cleaner, not to provide some logical associate between data bit numbers on the MCP23S17 and bit numbers on the bank headers. As the exact pin association can change based on the circuit board revision, please see the schematic (or the firmware source code) for the latest bit associations.

The PPDIO96 uses the BS1 (board select #1) signal on the PPDIO96-In connector as the SPI chip select for all six MCP23S17 chips on the board. The individual chips are selected with an address in the range 2 through 7 (corresponding to the IC number on the PPDIO96 PCB silkscreen). The software transmits the IC address as part of the MCP23S17 SPI communication protocol (see the MCP23S17 data sheet for more details).

The MCP23S17 is a highly programmable and very versatile device. Please see the data sheet for complete instructions on programming this device.

MCP23S17 Data Sheet

Because the MCP23S17 (and MCP23017 I2C variant) is a popular chip, there exists considerable library code on the Internet (especially for Arduino and Raspberry Pi). Beyond the software accompanying the DAQ system, you should be able to find several examples with a quick on-line search.


Software Support for the PPDIO96

There are two pieces of software of interest to PPDIO96 users: Teensy-based test software and the Netburner-based DAQ system firmware.

The test firmware can be found here:


The PPDIO96 test software is an Arduino Sketch (program) that runs on a Teensy 3.2 module installed on a DAQ_IF board. This simple sketch reads all 96 pins on the PPDIO96 and displays their values (as eight 12-bit hexadecimal numbers) on the Arduino IDE serial terminal. This program is part of the test suite accompanying the DAQ system documentation. For those unfamiliar with the Arduino environment, Arduino sketches are highly structured C/C++ programs that run on Arduino single-board computer systems (and there are dozens of different types of Arduino-compatible systems; the Teensy 3.2 is one example). For more information on the Arduino system visit For more information on the Teensy 3.2 module, visit

PPDIOTest.ino normally tests a single PPDIO96 board attached to a DAQ_IF board (with a Teensy 3.2 installed). However, with some very slight modifications you can also use this test software to check out daisy-chained PPDIO96 boards. Here's the main loop of the PPDIOTest.ino program:

void loop()
    uint16_t    bank[8];
    char        outStr[256];

    for( int i=0; i<8; ++i )
        bank[i] = readBank( 1, i );
        "0:%03x, 1:%03x, 2:%03x, 3:%03x, 4:%03x, 5:%03x, 6:%03x, 7:%03x",
    Serial.println( outStr );
    delay( 100 );


The "readBank( 1, i )" function call reads twelve bits from bank "i" on board 1. The first argument specifies the board number (1-6). By changing this first argument to a '2' you can instruct the test software to read and display the 12 banks on the second board in the PPDIO96 daisy-chain.

I use the PPDIOTest.ino program to test each PPDIO96 board immediately after construction. Using a small jumper wire (with female DuPont connectors on each end) I manually short each D0 through D95 pin to ground and look at the Arduino serial terminal to verify the correct response (you see the 4-bit values F, E, D, B, and 7) as you short each group of four bits (F appears when no pins are shorted).

The Netburner MOD54415 / DAQ firmware has its own web page here. For complete details concerning the firmware, visit that link. On this page there are a few limitations of the PPDIO96 firmware that need to be mentioned.

  • Although the MCP23S17 IC allows you to program any pin as an input or output pin, the DAQ system firmware limits data direction control to banks. That is, all 12 bits in a given bank must be programmed as input or output pins (no mixture of inputs and outputs).
  • By default, the DAQ firmware programs all pins as inputs on power up (this is also enforced by the hardware).


Some Caveats...

There are a couple of issues associated with using MCP23S17 GPIO expansion ICs that you should be aware of:

  • There is a maximum of 25 mA per pin (source or sink) that the MCP23S17 supports. That is an absolute maximum rating, you should normally operate at well under half this amount (i.e., no driving relays or big LEDs with the pins).
  • The maximum current into the Vdd pin (power pin) is 125 mA. So don't even think about sourcing 25 mA per pin for all pins (or even half that amount). You might be able to source 12 mA on as many as 8 pins. I wouldn't even count on that many. Moral of the story: use buffer chips or transistors if you need to source a fair amount of current across multiple pins.
  • The maximum current out of the Vss pin is 150 mA. So you can't sink a whole lot of current through the package, either.
  • The maximum power dissipation for the package is 700 mW. Again, you're very limited as to the current you can sink or source through the package.
  • The internal programmable pull-up resistors are rather weak. They are fine for dry contacts with very little resistance. They certainly won't power anything. They might also have problems with a larger resistive load.
  • On power-up the MCP23S17 defaults all pins to inputs (with no pull-up resistors). This is not a fail-safe condition for an output device insofar as the output value is undefined (it is the safest condition for the MCP23S17 as well as any input devices connected to the MCP23S17). If you have some safety-critical subsystem controlled by an MCP23S17 output in, it must be capable of dealing with an undefined value ('0' or '1') between the power-up reset and when the software finally initializes the pin as an output and programs it with an appropriate value. Using an MCP23S17 pin as an output for a device that requires fail-safe operation is not recommended. Consider using the PPRelay-12 or PPSSR-16 boards in such situations.
  • If the DAQ_IF pulses the reset line, then the PPDIO96 will automatically reset the MCP23S17 ICs, programming all pins as input pins.
  • There is no isolation between pins on the bank connectors. They all share the same ground signal. If you desire isolation beween the signals, consider using a PPOpto-12 board.