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


16-Channel solid-state relay/digital output board

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


The PPSSR-16 board is a 16-channel digital output board featuring solid-state relays. It normally connects to the DAQ_IF board via the PPDO bus. The PPSSR-16 has the following features:

  • Open Hardware design based on Creative Commons 4.0 license
  • Single 5V power supply input connector (screw terminals)
  • LED indicates when power is applied
  • 16 independent digital output channels featuring solid-state relays (rated at 2 amps each, though the board allows 1A per relay)
  • 16 LEDs indicate the current state of each output channel
  • 16 two-pin screw terminal output connectors with open/closed contacts
  • Each channel is completely isolated from the output control circuit
  • (2) PPDO-compatible ribbon cable connectors (10-pin) -- one for input and one for output (to support daisy-chaning)
  • Schematic and board layout are available in Eagle format
  • DIN rail mounts allow the board to be optionally mounted in a horizontal orientation on a 35mm DIN rail
  • DIN rail brackets are available in .STL format for 3D-printing
  • 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 PPSSR-16 board:

  • (17) 5mm LEDs
  • (16) AQZ10 Solid-State relays
  • (16) 360 Ω resistors
  • (17) 470 Ω resistors
  • (5) 1.2 kΩ resistors
  • (6) 10 kΩ resistors
  • (3) 1 µF capacitors
  • (1) 470 pF capacitor
  • (4) 0.1 µF decoupling capacitors
  • (4) 2N2222 transistors
  • (1) DS1834 power-on reset IC
  • (1) 74HC125 quad tri-state buffer
  • (1) 74HC00 quad NAND gate
  • (2) TPIC6B595 8-bit serial-in/parallel out high-current shift registers
  • (17) 2-pin screw terminals (5mm/0.2" centers)
  • (2) 10-pin (2x5) male headers
  • (1) 6-pin (2x3) male header
  • (1) 3-pin (1x3) male header
  • (1) PPSSR-16 PCB
  • Optional: (8) test pins
  • Optional: (16) AQZ10 sockets
  • Optional: one set of horizontal 35mm DIN rail mounts for DAQ boards

Note: If you only want a few PPSSR-16 PCBs, contact Plantation Productions ( to see if there are any in stock. Bare boards are $25 each plus shipping. Fully assembled and tested boards with DIN rails and AQZ sockets are $599 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 PPSSR-16 PCBs are four-layer boards. Here are the Gerber files for them (provide these files to Seeed Studio or your personal PCB manufacturer).

PPSSR-16 Gerber Files for PCB

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

PPSSR-16 Eagle files (Schematic and board layout)

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

PPSSR-16 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:

PPSSR-16 DIN Rail Brackets 3D printer files


PPSSR-16 Board Layout

Connecting a PPSSR-16 board to a DAQ system

Up to 10 PPRelay-12 and/or PPSSR-16 (solid-state relay) boards can be daisy-chained together and connected to a single DAQ_IF board. You connect the first board in the daisy-chain directly to the PPDO connection on the DAQ_IF board:


You daisy-chain additional boards (PPRelay-12 or PPSSR-16) by connecting the PPDO Out connector on one board to the PPDO In connector on the next board:



The PPSSR-16 presents one TTL load to all the SPI bus signals. The DAQ_IF board buffers all SPI output signals put on the PPDO bus. Therefore, you can realistically expect a limit of about 10 daisy-chained boards on the PPDO bus. In theory, you could put as many boards in the daisy-chain as you like; however, TTL fanout and trace/ribbon cable length limit you to about 10 boards.

Because the PPDO connector carries high-frequency SPI bus signals, you should try to keep the connecting ribbon cables as short as possible. Excessively long cables may reduce the maximum number of boards you can add to the daisy chain.

Relay Connections

The contacts on each of the 16 relays on the PPSSR-16 board are routed to a 2-pin screw terminal block. These pins are polarized and have (+) and (-) terminals (the relays are DC solid state relays). The relays themselves (AQZ10) are rated for 2A operation. In practice, of course, you do not operate an electronic device at its absolute maximum rated value. Good engineering practice suggests that you derate a device by 50%. Therefore 1A is a more reasonable choice the maximum current you should put through one of these relays. The PPSSR-16 board has 100 mil traces (top and bottom layers) from the relay contacts to the associated screw terminal pins. Therefore, it is probably safe to run these guys with as much as 1 amp without worrying about the PCB heating up too much.

By their design, solid-state relays offer a fair amount of isolation beween the relay circuit and the rest of the circuit (opto-isolation is used by the AQZ10 SSR). However, PPSSR-16 boards are rated for 30VDC at the relay contacts. While the rest of the DAQ system may be spared if a high-voltage surge occurs across the control contacts on the relay, you'll likely damage the (expensive) AQZ10 device in this situation. Note that the AQZ10 SSR has an optional socket. If you anticipate blowing up the SSRs, you may want to install the sockets.

DS1834Sel Jumper

The DS1834SEL jump is a 6-pin header on the board:

There are always two jumpers installed on this header. One jumper (between the Vcc pin and either the 3.3v or 5V pins on the right side of the header) direct the PPSSR-16's Vcc line (which is +5V) to either the 3.3v or 5V size of the DS1834 power-on reset chip. The other jumper routes the DS1834 3.3V reset or 5V reset pin to the PPSSR-16 reset circuitry. The two jumpers are not independent - both jumpers must be set to 3.3V or both jumpers must be set to 5V.

If you're wondering why you would want to route Vcc (5V) to the DS1834, well, it has to do with power-supply tolerance. The DS1834 is programmed with a 10% tolerance. If the power supply drops more than 10% below the rated voltage (typically 5V in the DAQ system) then it forces a reset output. This circuit was copied from the PPRelay-12 design where turning on all the relays could cause a sufficient voltage drop to trigger the DS1834 reset; this shouldn't be a problem on the PPSSR-16, but the jumpers were included, just in case.

Note that applying 5V to the DS1834 3.3V sense input will not damage the IC - all inputs (including the 3.3V sense input) are rated for 5V. For more information about the DS1834 power on reset chip, please consult the data sheet:

DS1834 Power On Reset Data Sheet (PDF)


SRCLR Selection Jumper

The SRCLR jumper is a 3-pin header on the board:



There will always be a jumper present on this header; the jump will either connect the RST and SRCLR pins or it will connect the WD and SRCLR pins.

This pin controls the state of the TPIC6B595 shift register clear signal. If the jumper is on the SRCLR and RST pins, then the SRCLR line is only low while the DS1834 RST output (5V or 3.3V, depending on the DS1834SEL jumpers) is low. In particular, with the jump in this position, holding the WD_LATCH signal low does not force the SRCLR line low.

If you put the jumper between the SRCLR and WD lines, then holding the WD_LATCH line low will force the SRCLR line low for as long as the WD_LATCH is low.

With the jumper in the RST/SRCLR position, clearing the shift registers on the TPIC6B595 ICs occurs under the following circumstances:

  • Power is applied to the board (DS1834 power-on reset chip handles this)
  • The PPDO reset signal is held low for at least 10 msec (input signal to the DS1834, which causes a reset signal to be generated).
  • The WD signal is pulsed (reset occurs on falling edge).

In all of these situations, the PPSSR-16 board briefly pulls the SRCLR line low and synthesizes a clock pulse (RCL on the TPIC6B595 shift register IC) to copy the cleared shift register to the output latch. In particular, note that even though the jumper is not in the RST/SRCLR position, a pulse on the WD_LATCH line will still reset the shift registers and clear the output pins.

Note, however, that if the jumper is in the RST/SRCLR position and the WD_LATCH signal is set from high to low, while the system will reset the shift registers on the falling edge of the WD_LATCH signal, continuing to hold WD_LATCH low will not force the shift registers to remain clear. Until WD_LATCH rises back to a high level, it will have no further effect on the SRCLR line.

If you move the shift register clear selection jump to the SRCLR/WD position, SRCLR is a combination of the DS1834 RST output and the WD_LATCH line. In particular, as long as you hold the WD_LATCH line low the PPSSR-16 will hold the SRCLR line low. Any attempt to shift in additional data will be futile as the TPIC6B595 will continuously clear the shift registers (and transfer zeros to the output latches on an RCK signal).

The correct setting depends upon your application. If you want to ensure that the PPSSR-16 outputs remain in fail-safe mode (relays open) as long as the watchdog timer (on the DAQ_IF board) has not been reset, put the jumper in the SRCLR/WD position. Otherwise, put the jumper in the RST/SRCLR position.



The PPDO (digital output) bus is a 10-pin connector. It has the following pinout:


Note that the PPDO bus is an instance of the DAQ_IF SPI bus with a single chip/board select line (BS0). The PPDO bus presumes that there is a single shift register device hooked up to it (e.g., PPSSR-16 looks like a 16-bit shift regster). The size (in bits) of the shift register is arbitrary. In the DAQ system, each PPRelay-12 or PPSSR-16 board you daisy chain to the PPDO connector adds 16 bits to the size of the shift register. For example, if you have two PPRelay-12 and one PPSSR-16 boards daisy-chained to the PPDO connection, the shift register length is 48 bits (16 bits per board).

If you look at the design of the PPRelay-12 (or PPSSR-16) board, you'll discover that it has two TPIC6B595 serial-in/parallel-out shift registers. The MOSI (Master Out, Slave In -- the PPSSR-16 is a slave) signal coming in on the PPDO In connector is fed to the serial in pin on the first TPIC6B595 shift register. The serial out pin on the first TPIC6B595 shift register goes to the serial in pin on the second TPIC6B595. Finally, the serial out pin on the second TPIC6B595 shift register goes to the MOSI pin on the PPDO Out connector. Therefore, if you shift 48 bits onto the PPDO bus, the last 16 bits you shift will wind up on the first board in the daisy chain; the second 16 bits (the middle 16 bits) you shift in will wind up on the second board in the daisy chain; the first set of 16 bits you shift in wind up on the third board in the daisy chain.

Note that the PPRelay-12 and PPSSR-16 boards do not use the MISO, J238, and IRQ signals. The PPRelay-12 and PPSSR-16 boards are output-only devices, so the MISO (Master input, slave output) pin has no use. Likewise, these two boards don't generate any interrupts, so these boards don't use the IRQ line. The DAQ system reserves the J238 line for end-user use, so the PPRelay-12 and PPSSR-16 boards don't use this pin.

The PPSSR-16 board uses the SCK and MOSI lines to shift data into the shift registers. Although the TPIC6B595 high-current shift registers the PPSSR-16 board uses is not, technically speaking, an SPI device, it turns out that the timing of the SPI clock (SCK) and MOSI (serial output data) signals are compatible with the serial shift clock and serial data in pins on the TPIC6B595 shift register.


Programming PPSSR-16 (PPDO Bus)

As mentioned earlier, the boards daisy-chained to the PPDO connector look like a single shift register to the DAQ_IF board. Adding more PPSSR-16 boards to the daisy chain extends the size of the shift register by 16 bits for each board you add.

To program this "shift register" you must first pull the BS0 line low on the DAQ_IF board. You accomplish this by programming the A0, A1, and A2 output pins (on the DAQ_IF) with zeros and then activate the SPI chip select line. Next, you transmit the specified number of bytes (two bytes for each board in the daisy chain) via the SPI libraries (note: the bit on MOSI gets shifted in on the rising edge of SCK -- this is handled by the SPI libraries or hardware). Finally, you set the BS0 line high (by setting the SPI chip select line high or by writing all ones to the A0, A1, and A2 output lines). On the rising edge of the BS0 signal line, the TPIC6B595 shift registers transfer the data from the internal shift registers to the output latches. Note that during the shift operation, the data on the TPIC6B595 output pins (controlling the relays) does not change until the rising edge of the BS0 signal.

Note: here is some sample code (written for the Netburner) to control the A0, A1, and A2 lines that control BS0:

// disable and enable the board select lines
// for the MCP23s17 chips.
//  Note:   board zero is reserved for the
//          DO24 board (serial shift
//          register board).

void disableDIO( void )
    // Disable by selecting Y7 on the 74HC138.
    // Y7 is unused by the DIO96 and DO24 boards.
    A0Pin()         = 1;    // A pin on '138
    A1Pin()         = 1;    // B pin on '138
    A2Pin()         = 1;    // C pin on '138

// enableDIO-
//  Enables the SPI CS line specified by the argument.
//  board:  0 for PPDIO bus, 1-6 for PPDIO96 buss,
//          7 for disabled

void enableDIO( BYTE board )

    switch( board )
        case 0:
            A0Pin() = 0;    // DOUT boards
            A1Pin() = 0;
            A2Pin() = 0;
        case 1:
            A0Pin() = 1;    // Board 1
            A1Pin() = 0;
            A2Pin() = 0;
        case 2:
            A0Pin() = 0;    // Board 2
            A1Pin() = 1;
            A2Pin() = 0;
        case 3:
            A0Pin() = 1;    // Board 3
            A1Pin() = 1;
            A2Pin() = 0;
        case 4:
            A0Pin() = 0;    // Board 4
            A1Pin() = 0;
            A2Pin() = 1;
        case 5:
            A0Pin() = 1;    // Board 5
            A1Pin() = 0;
            A2Pin() = 1;
        case 6:
            A0Pin() = 0;    // Board 6
            A1Pin() = 1;
            A2Pin() = 1;
            // If bad address, disable the chip selects:
    } // switch
} // enableDIO

Here is some comparable code running on a Teensy 3.2 (Arduino style programming):

 void setBSAdrs( int adrs )
    if( adrs <0 || adrs > 6 )
        adrs = 7;
    digitalWrite( a0, adrs & 1 );
    digitalWrite( a1, (adrs >> 1) & 1 );
    digitalWrite( a2, (adrs >> 2) & 1 );
    if( adrs == 7 )
        digitalWrite( spics, 1 );
        digitalWrite( spics, 0 );
} // setBSAdrs

void disableAdrs( void )
    digitalWrite( spics, 1 );
    digitalWrite( a0, 1 );      // ADRS 7 is unused on DAQ
    digitalWrite( a1, 1 );
    digitalWrite( a2, 1 );
} // setBSAdrs


Here is some Teensy 3.2 library code that writes 16 bits to the SPI bus (the exact code varies by SBC). Note that "RelaySettings" is the SPISettings object created in the Teensy code to communicate with the SPI bus.

SPISettings RelaySettings; //( 2000000, MSBFIRST, SPI_MODE1 );

void transferWord( uint16_t word )
        setBSAdrs( 0 );
        SPI.beginTransaction( RelaySettings );
        SPI.transfer( word >> 8 );
        SPI.transfer( word & 0xff );


So if you wanted to write the 48 bits "0x0000, 0x1f00, 0x8000" to three PPSSR-16 boards attached to the DAQ_IF, you'd use the following Teensy 3.2 code

        setBSAdrs( 0 );
        SPI.beginTransaction( RelaySettings );
        SPI.transfer( 0x80 );       // H.O. byte of 0x8000
        SPI.transfer( 0x0 );        // L.O. byte of 0x8000
        SPI.transfer( 0x1f );       // H.O. byte of 0x1f00
        SPI.transfer( 0x0 );        // L.O. byte of 0x1f00
        SPI.transfer( 0x0 );        // H.O. byte of 0x0
        SPI.transfer( 0x0 );        // L.O. byte of 0x0

Note that you must transfer the H.O. byte of each word first.

Because of the nature of shift registers, if you shift extra data to the shift registers (more than n*2 bytes, where n is the number of daisy-chained boards) then the extra data is lost (the extra data will be the first bytes you shift out). Because of the wiring of the daisy-chain, the last two data bytes you shift out will be shifted into the first board in the daisy chain (the board connected directly to the DAQ_IF board), the two bytes shifted out before the last two bytes will be shifted into the second board of the daisy chain, etc.

Toggling the DAQ_IF reset line will immediately clear all the TPIC6B595 shift registers and output latches. While the reset line is low, the PPSSR-16 and PPSSR-16 boards will force the internal shift registers to all zero bits. On the rising edge of the reset line, the boards will transfer the data (now zeros) from the internal shift registers to the output latches. Note that if you are in the middle of shifting data into the shift registers while also pulsing the reset line (say, in a multi-threaded environment), the results are undefined. If you must shift data into the shift register from one thread and you could be toggling the reset line from a separate thread, you should use synchronization primitives to protect access to the SPI clock.

Here is the Teensy 3.2 code that will toggle the reset line:

#define reset           23

void toggleReset( void )
digitalWrite( reset, 0 );
delay( 3 );
digitalWrite( reset, 1 );
delay( 3 );


Here is the Netburner code that will toggle the reset line:

#define RESET 				(J2[44])

// Reset the DAQ system hardware (put system in fail-safe mode:

void reset( void )

    // Note: as per requirements, pulse should be low for
    // at least 200 mSec.
    RESET = 1;
    RESET = 0;
    RESET   = 1;

Note that DAQ system requirements state that the RESET line must be held low for at least 250 msec. This is why the large delays are present in this code.

If the watchdog timer times out and asserts the WD signal on the PPDO connector, the PPSSR-16 board will automatically put the output relays in a fail-safe mode by clearing the internal shift register and transferring their contents to the TPIC6B595 output latches. As for the reset line, if you're currenting shifting data into the shift register when the WD timer times out, this could create an undefined result. In theory, the software has hung up and probably isn't shifting data to the PPDO connector. In practice, this could be the result of some operation taking too long. To prevent this undefined operation, it's a good idea to always refresh the watchdog timer immediately prior to shifting out any data and checking the WD_LATCH value to ensure that the watchdog timer hasn't already timed out.

Here's some sample Teensy 3.2 code that will refresh the watchdog timer:

#define wd_rfsh         17

void refreshWD( void )
    digitalWrite(wd_rfsh, HIGH );
    delayMicroseconds( 10 );
    digitalWrite( wd_rfsh, LOW);
    delayMicroseconds( 10 );

Here is the Netburner MOD54415 code that will refresh the watchdog timer:

#define RESET 				(J2[44])

			led1Pin()	= 0;
			led1Pin()	= 1;

// shortDelay is defined thusly:
// Software delay function (arg in microseconds)

void shortDelay( unsigned int usec )
    unsigned int i;
    i = 20*usec;    // 20=1usec delay (approx)
        asm("nop"); //needed so delay not optimized out
    }while( i>0);