826 DIOs

From Sensoray Technical Wiki
Revision as of 11:26, 4 December 2020 by JL (Talk | contribs)

Jump to: navigation, search

Contents

Connections

IMPORTANT: DIOs are not isolated. An external isolator is required when connecting to a signal which is referenced to a different ground.

DIOs are referenced to the GND pins on connectors J2 and J3, which are internally connected to the PCIe power supply return. When using a DIO to monitor an external signal, make sure the signal is referenced to GND and does not exceed the absolute maximum DIO input voltage range:

  • Incompatible signal ground - An optical isolator should be used when connecting to a signal that is referenced to a different ground, or in cases where a ground loop would be created by connecting signal ground to GND.
  • Unreferenced signal ground - If the signal ground is unreferenced (e.g., the signal generator is powered by an isolated power supply), connect the signal ground to GND. This will reference the external signal to GND.
  • Incompatible signal voltage - If the signal is referenced to GND but the signal voltage exceeds the DIO input range, use a level translator or voltage divider to bring it into range. In the latter case, keep in mind that the DIO has an internal pull-up resistor to +5 V.

3.3 V compatibility

DIOs are compatible with 3.3 V logic input signals. Note however, that every DIO has an internal 10 KΩ pull-up to +5 V, which can affect the signal voltage from high-impedance 3.3 V sources.

When operating as an output, a DIO produces a high logic level via its internal +5 V pull-up resistor. External 3.3 V circuitry must be 5 V tolerant or must limit the voltage (e.g., with Schottky diode to +3.3 V supply).

Examples

Mechanical switch

To monitor the state of a mechanical switch, simply connect the switch between the DIO and GND. This takes advantage of the DIO's built-in pull-up resistor.

DioSwitch.gif

Input isolator

An opto-isolator should be used when the input signal is differential or referenced to a different ground, or in cases where a ground loop would be created by connecting signal ground to GND.

DioOptoIsolator.gif

Unreferenced 5V input

This circuit can be used to monitor an unreferenced (powered by an isolated supply) 5V logic signal. The signal ground is tied to 826 GND to keep it from floating.

DioIsolated5V.gif

Unreferenced 12V logic input

Monitoring an unreferenced 12V logic signal (powered by an isolated supply). The Schottky diode limits the logic-high voltage applied to the DIO.

DioIsolated12V.gif

Driving LEDs

A DIO can directly drive a low-power LED. This is commonly done to indicate status or to drive an optocoupler. High-current LEDs require an external buffer such as a SSR (see next example). A series resistor is required to limit the LED current.

DioLed.gif

Controlling SSRs

A DIO can directly drive a typical solid-state relay. This allows a DIO to control high-power loads such as motors, solenoids, heaters and lighting.

DioSsr.gif

Programming basics

To unconditionally program all DIO outputs, call S826_DioOutputWrite with the mode argument set to S826_BITWRITE (zero). For example, this code will turn on all DIOs:

uint dios[] = { // Specify DIOs that are to be turned on (driven to 0 V):
  0x00FFFFFF,   //   DIO 0-23
  0x00FFFFFF    //   DIO 24-47
}
S826_DioOutputWrite(0, dios, S826_BITWRITE); // Turn on all DIOs.

This example shows how to turn on DIOs 7, 13 and 38, and turn off all other DIOs:

uint dios[] = {         // Specify DIOs that are to be turned on:
  (1 << 7) + (1 << 13), //   DIOs 7 & 13 are in first 24-bit mask (DIOs 0-23),
  (1 << (38 - 24))      //   DIO 38 is in second 24-bit mask (DIOs 24-47).
}
S826_DioOutputWrite(0,  // Program all DIO outputs on board 0:
  dios,                 //   desired output states
  S826_BITWRITE);       //   unconditionally change all DIOs

To read the pin levels of all DIOs, call S826_DioInputRead. This example shows how to read and display all DIO pins on board 0:

int i;
uint pins[2];                // Buffer for pin states.
S826_DioInputRead(0, pins);  // Read all DIO pin states into buffer.
for (i = 0; i < 24; i++)     // Display states of DIOs 0-23.
  printf("dio%d = %d\n", i, (pins[0] >> i) & 1);
for (i = 24; i < 48; i++)    // Display states of DIOs 24-47.
  printf("dio%d = %d\n", i, (pins[1] >> (i - 24)) & 1);

Setting and clearing DIOs

Sometimes it's necessary to set or clear particular DIOs without disturbing others. Typically, this is accomplished with a read-modify-write (RMW) sequence consisting of reading all DIOs into a buffer, modifying the buffer, and then writing the buffer back to the DIOs. This task is further complicated when multiple threads control the DIOs — a common practice in high-performance event-driven applications — because concurrent RMWs on different threads will conflict with each other. To avoid such conflicts, the RMW must be treated as a critical section (e.g., protected by a mutex or semaphore).

Fortunately, the 826 provides a fast, efficient way to set and clear DIOs without the complications of RMW. Simply call S826_DioOutputWrite with the mode argument set to S826_BITSET or S826_BITCLR, as shown in this example:

// Set and clear some DIOs without affecting other DIOs
uint maskA[] = {7, 0};  // bitmask for DIOs 0-2
uint maskB[] = {0, 1};  // bitmask for DIO 24
S826_DioOutputWrite(0, maskA, S826_BITSET);  // Set DIOs 0, 1 and 2.
S826_DioOutputWrite(0, maskB, S826_BITCLR);  // Clear DIO 24.

Debouncing inputs

Oscilloscope screenshot showing the "bouncing" voltage when a switch turns on

DIOs are commonly used to monitor real-world signals that have glitches or other noise. For example, the electrical contacts of mechanical switches may "bounce" when first connected, thus producing pulses that may be incorrectly interpreted by the application program as state changes. This problem can be solved by implementing a software debounce algorithm, but an easier way is to use the input filters provided by the DIO system.

To use the DIO input filters, simply specify a filter interval and designate the DIOs to be filtered. Choose a filter interval that is long enough to suppress the longest expected noise pulse, but not so long that valid state changes will be missed. The following example shows how to suppress pulses up to 200 µs wide on dio0 and dio2:

// Debounce dio0 and dio2 ------------------

#define FILT_USEC 200                  // Desired filter interval (max = 1.31 ms).
uint tfilt = FILT_USEC * 50;           // Interval specified as multiple of 20ns.
uint enabs[] = {5, 0};                 // Enable filters on dio0 and dio2.
S826_DioFilterWrite(0, tfilt, enabs);  // Activate the DIO filters.

Edge detection

Event-driven software often must execute code in response to DIO input changes (e.g., when a pushbutton is pressed, a photoelectric sensor is activated, etc.). Polling is not a good way to detect these events because it degrades system responsiveness and tends to make the source code convoluted and difficult to maintain. However, the alternative — using interrupts — can complicate and prolong program development.

Fortunately, model 826 provides the best of both worlds: it implements DIO edge detection circuitry with interrupts for efficient event monitoring, and the API makes the interrupts easy to use. For example, the following function will return when a falling edge is detected on a particular DIO. It is a blocking function, meaning that other threads can run while it waits for the DIO edge.

int WaitForDioFallingEdge(uint board, uint dio)
{
  uint rise[] = {0, 0};       // not interested in rising edge
  uint fall[] = {(dio < 24) << (dio % 24), (dio > 23) << (dio % 24)}; // interested in falling edge
  S826_DioCapEnablesWrite(board, rise, fall, S826_BITSET);   // Enable falling edge detection.
  return S826_DioCapRead(board, fall, 0, INFINITE_WAIT);     // Block until falling edge.
}

WaitForDioFallingEdge(0, 29);  // Example usage: wait for falling edge on dio29 of board number 0.

Controlling output rise-time with an external pull-up

Each DIO has an output driver that actively drives the signal to 0 V in the on state and is high-impedance in the off state. In the off state, the channel's internal 10 KΩ resistor passively pulls up the signal to +5 V. When the output switches to the off state, this 10 KΩ source resistance (combined with circuit capacitance) stretches the DIO rise time, which delays its transition to logic '1'. If the rise time is too long, it can be shortened by adding an external pull-up resistor (and reducing external capacitance) on the signal net.

The following table shows nominal rise times for unloaded DIO pins. Lower resistance values may be needed to compensate external circuit capacitance, but do not use an external pull-up resistor having less than 220 Ω (to prevent excessive DIO output current).

External pull-up DIO rise time
None 200 ns
1.2 KΩ 20 ns
680 Ω 10 ns

Generating a burst of pulses

How can I make a DIO go active for 10ms and then inactive for another 10ms, and repeat this five times?

There are several ways to do this but the methods you can use depend on a number of factors. Here are two approaches:

  • If high precision is not needed then you could bit-bang the DIO, using a hardware timer (or system Sleep function) to pace the DIO writes like this:
int i;
uint mask[] = {1, 0};       // bitmask for dio0
CreateTimer(0, 0, 10000);   // Create 10 ms timer and start it running.
for (i = 0; i < 5; i++) {
  WaitForTimer(0, 0);                         // Wait for timer tick.
  S826_DioOutputWrite(0, mask, S826_BITSET);  // Set dio0 active.
  WaitForTimer(0, 0);                         // Wait for timer tick.
  S826_DioOutputWrite(0, mask, S826_BITCLR);  // Set dio0 inactive.
}

Example application: I2C Emulator

Can I use DIOs to communicate with I2C devices?

Have a look at Sensoray's I2C emulator, which uses two DIOs to bit-bang an I2C bus. This open source software implements a full-featured I2C master emulator with bus arbitration and bus-hang resolver. All 826-specific code resides in a hardware abstraction layer (HAL) — an architectural feature that belongs in all production-quality software.

If you need to monitor an I2C bus or emulate a slave device, consider using a counter to capture synchronous serial data.

Interfacing RS-422 signals

I need to monitor the state of an RS-422 signal pair. Can I do this with a DIO channel?

DIO channels have TTL/CMOS inputs and therefore are generally incompatible with RS-422 signals. However, it may be permissible to connect one of the two differential RS-422 signals directly to a DIO, but only if the signal voltage is guaranteed to never exceed the absolute maximum DIO input voltages, and the signal must transition between valid logic levels. Also note that the RS-422 pair may require external termination.

Alternatives methods include using an external RS-422 line receiver or optocoupler. Also, if you have a spare counter channel then it may be possible to use a counter to monitor an RS-422 pair.

Relay rack compatibility

IMPORTANT: The DIO circuitry on model 826 is not compatible with 15 or 24 VDC modules. When choosing modules for your relay rack, be sure to select modules that are compatible with 5 VDC logic levels.

Each 50-pin DIO header carries 24 DIO signals that have 5 V logic levels. The header pinout is compatible with the following module racks and other racks that have the same pinouts:

Grayhill (various module types):

  • 8 channels: 70RCK8-HL, 70MRCK8-HL, 70GRCK8-HL, 70LRCK8-HL, 70RCK8-DIN
  • 16 channels: 70RCK16-HL, 70MRCK16-HL, 70GRCK16-HL, 70LRCK16-HL, 70RCK16-DIN
  • 24 channels: 70MRCK24-HL, 70LRCK24-HL, 70LRCK24-DIN

Opto-22 (type G4 modules):

  • 8 channels: G4PB8
  • 16 channels: G4PB16
  • 24 channels: G4PB24

Maximum output current

DIOs are subject to two different maximum current limits: individual and group. Each DIO is capable of continuously sinking up to 24 mA; this is the maximum individual current. However, it's not permitted for all DIOs to do this simultaneously because this would exceed the maximum group current.

DIO channels are organized into groups as shown below. In any particular group, the group current is the total of all individual currents in the group. For example, in Group4 the group current is the sum of the currents flowing in DIO24 through DIO29.

Group DIOs
0 0-5
1 6-11
2 12-17
3 18-23
4 24-29
5 30-35
6 36-41
7 42-47

Each group is capable of continuously sinking up to 72 mA. As shown in the following table, all DIOs in a group may be active at the same time if their individual currents are less than or equal to 12 mA (because 6 * 12 ≤ 72). However, when the individual currents are higher than 12 mA, it is not allowed for all DIOs in a group to be active at the same time.

DIO current (mA) Maximum number of active DIOs
i ≤ 12 6
12 < i ≤ 14.4 5
14.4 < i ≤ 18 4
18 < i ≤ 24 3
Personal tools
Namespaces

Variants
Actions
Toolbox