DT Family Guide

Overview

The DT family is NAI’s line of programmable discrete I/O smart function modules. A single DT module gives you multiple channels that can each act as a discrete input (voltage or contact sensing, with programmable pull-up/pull-down so you don’t need external resistors) or a discrete output (high-side, low-side, or push-pull switching), plus measurement, thresholds, and debounce.

This page is the starting point if you’re working with any DT module. Use it to understand what the family does, pick the right member for your channel count and switching needs, get the module wired up, and run your first sample application against it. It’s aimed at engineers integrating discrete I/O — relays, switches, lamps, solenoids, contact sensing — into an NAI board or system.

DT modules drive and sense the discrete devices found throughout aircraft and rugged platforms — relay coils, solenoids, incandescent lamps and LEDs, and contact/position sensors. NAI calls out applications like switching high-inrush lamp loads (e.g., paralleled #327 lamps via 2 A/bank current sharing), dual-series “key” outputs for missile launch control, and detecting hatch-open / wheels-up–style indicator contacts with programmable debounce to reject relay chatter.

DT is the field-level single-ended member of NAI’s discrete/switching I/O families. The TL family handles logic-level TTL/CMOS I/O; the DF family uses differential (RS-422/485) lines for noise-hardened signaling over long, noisy runs; and the RY family uses mechanical relay contacts for galvanic isolation and switching AC, high voltage, or analog signals. Reach for DT when you’re switching or sensing field-level discrete loads on single-ended lines.

For a short visual introduction to the discrete I/O family, watch this overview:

DT modules at a glance

ModuleChannelsTypeWhat makes it differentManual
DT124SFFull programmable discrete I/O; push-pull to 500 mA/ch, current sharing to 2 A/bankDT1 Manual
DT216SFIsolated channels, ±80 V input sensing, bidirectional switch to 625 mA/ch, diode clampingDT2 Manual
DT3x4Output onlyHigh-current output: to 2 A / 65 V, hi-side / lo-side / push-pullDT3x Manual
DT424EFDT1 features plus pulse/frequency period measurement & signal generationDT4 Manual
DT516EFDT2 features plus pulse/frequency period measurement & signal generationDT5 Manual

In the Type column, SF = Standard Function and EF = Enhanced Function. Every DT module does programmable discrete input/output; an EF module does everything its SF counterpart does and adds a timing block on top — pulse/frequency period measurement on inputs and arbitrary pulse/frequency signal generation on outputs. (DT3x is the exception: it’s output-only, with neither inputs nor EF timing.)

Choosing a member:

  • Basic discrete I/O — DT1 (24 ch) or DT2 (16 ch).
  • Pulse/frequency period measurement or signal generation — the EF versions, DT4 (24 ch) or DT5 (16 ch). EF modules do everything their SF counterpart does and add the timing features.
  • High-current loads, outputs only — DT3x (4 ch, up to 2 A / 65 V per channel).
  • Galvanic isolation or higher input voltages — DT2 and DT5 have isolated channels and measure inputs up to ±80 V; reach for them when channels must be isolated from each other or from the system, or when sensing voltages above the DT1/DT4 range.

Combination modules that include discrete I/O:

ModuleCombinesManual
CM2Discrete I/O + ARINC 429CM2 Manual
CM4Serial + Discrete I/OCM4 Manual
CM8MIL-STD-1553 + Discrete I/OCM8 Manual

Physical setup

Discrete I/O wiring differs per module — the specific pinout is the one thing that changes between DT members — so the per-module pinout always comes from that module’s manual. The setup pattern, though, is the same for every DT module:

  1. Identify the module’s slot number on your NAI motherboard or system. (NAI function modules are COSA modules, factory-installed into the system’s module slots.)
  2. Bring the I/O out through the breakout board. The slot’s pins appear on the breakout as generic IO# numbers.
  3. Map IO# pins to the module’s discrete channels — either by reading the pinout in the module’s manual or by laying the module’s pinout overlay card over its MOD# pins on the breakout.
  4. Wire your discrete signals (contacts, loads, sensing lines) to the mapped pins.

A few electrical points hold for every DT module: outputs switch an externally supplied VCC (a 3–60 V source you provide), low-side/sink configurations return to ISO-GND, and input channels are wired differently from outputs — sensing a voltage or contact rather than driving a load. The exact pins for VCC, ISO-GND, and each channel are in the module’s manual.

Two common cases make this concrete (use your module’s pinout for the actual pin numbers):

  • Driving a load (relay coil, lamp, solenoid) as a high-side output. Supply your VCC (3–60 V) to the module’s VCC pin and tie your supply ground to ISO-GND. Wire the load between the channel’s output pin and ISO-GND. Configured high-side, the channel sources current from VCC into the load when you drive it high — up to 500 mA per channel on DT1/DT4, or up to 2 A per channel on DT3x. For inductive loads like relay coils, on-module diode clamping handles the flyback.
  • Sensing a switch or relay contact as an input. Wire the contact between the channel’s pin and ground. Instead of an external pull resistor, enable the channel’s programmable pull-up or pull-down current source (0–5 mA, in banks of 6 channels) so an open contact reads a clean level. Add debounce to reject contact chatter (see Software, below).

The DT module manuals are functional/register references (pinouts included); they have no install steps. Connector and cabling specifics live in Connectors and Cabling Info; powering and reaching the board is covered in Connecting to Boards.

Software

There’s nothing DT-specific about which software you run. The NAI SSK (naibrd library) is identical across every OS and architecture — PetaLinux, VxWorks, DEOS, Windows. What OS you’re on is determined by your motherboard/SBC, not by the DT module. The only family-specific part is which API functions you call: DT modules use the naibrd_DT_* calls.

Where to find what you need:

  • Which functions/registers to call — the specific module’s manual (e.g. DT1 Manual) documents every naibrd_DT_* register.
  • Building and deploying on your platformConnecting to Boards covers the toolchain, deployment, and terminal access for PetaLinux/ARM Linux, VxWorks, DEOS, and Windows.
  • Launching the app on the board itselfRunning Applications from the Target walks through loading and launching your executable on the target.

Example — a 68ARM2 SBC with a DT1 module: pull the naibrd_DT_* calls from the DT1 Manual, set up the ARM Linux toolchain per Connecting to Boards, then load and launch the sample on the target per Running Applications from the Target.

Confirm communication

The quickest proof of life is a background-BIT check plus a two-channel output→input loopback — a discrete I/O module has no internal test-injection, so proving a channel end-to-end means driving an output and reading it back on an input.

Built-in test (no wiring). A test comparator continuously checks each channel in the background and flags a fault in status. Confirm no BIT fault is latched:

nai_status_bit_t bitStatus;
naibrd_DT_GetChanMappedStatus(cardIndex, module, channel,
   NAIBRD_DT_STATUS_BIT_LATCHED, &bitStatus);                       /* LO = normal */

Two-channel loopback (proves the drivers and wiring). Set one channel as an output and another as an input, wire the output to the input (sharing a common ground), drive the output, and read it back:

/* Channel 0 = high-side output, channel 1 = input, output wired to input */
naibrd_DT_SetIOFormat(cardIndex, module, chOut, NAIBRD_DT_IOFORMAT_OUTPUT_HIGH);
naibrd_DT_SetIOFormat(cardIndex, module, chIn,  NAIBRD_DT_IOFORMAT_INPUT);
 
naibrd_dt_state_t in_hi;
naibrd_DT_SetOutputState(cardIndex, module, chOut, NAIBRD_DT_STATE_HI);
naibrd_DT_GetInputState(cardIndex, module, chIn, &in_hi);          /* should read HI */
 
naibrd_dt_state_t in_lo;
naibrd_DT_SetOutputState(cardIndex, module, chOut, NAIBRD_DT_STATE_LO);
naibrd_DT_GetInputState(cardIndex, module, chIn, &in_lo);          /* should read LO */

You can cross-check the reading against the channel’s measured voltage with naibrd_DT_GetVoltage. If BIT status is clean and the input channel follows the output’s HI/LO, your board connection, the SSK, the channel drivers, and your wiring are all confirmed. The DT BasicOps sample drives exactly this flow — I/O format, output/input state, measured voltage, and status across channels.

Features

Each DT operation works per channel through the naibrd_DT_* API. The blocks below group the calls by what you’re doing, with the SSK 1.x and 2.x signatures side by side. (The 1.x → 2.x change is mostly the enum-type rename nai_dt_*naibrd_dt_*, plus GetStatus/ClearStatusGetChanMappedStatus/ClearChanMappedStatus, ReadFIFORawReadFIFO, and a new SetEnhancedMode in 2.x.)

Configure a channel

What it does: set the channel’s I/O format (input, low-side, high-side, or push-pull output), its input thresholds and debounce, and its pull-up/pull-down current source for contact sensing.

Applies to: all DT modules.

Relevant APIs:

/* SSK 1.x */
nai_status_t naibrd_DT_SetIOFormat(int32_t cardIndex, int32_t module, int32_t channel, nai_dt_ioformat_t format);
nai_status_t naibrd_DT_SetThreshold(int32_t cardIndex, int32_t module, int32_t channel, nai_dt_thresh_type_t type, float64_t threshold);
nai_status_t naibrd_DT_SetDebounceTime(int32_t cardIndex, int32_t module, int32_t channel, float64_t debounceTime);
nai_status_t naibrd_DT_SetPullUpDownResConfig(int32_t cardIndex, int32_t module, int32_t channel, nai_dt_pullresconfig_t config);
/* SSK 2.x */
nai_status_t naibrd_DT_SetIOFormat(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dt_ioformat_t format);
nai_status_t naibrd_DT_SetThreshold(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dt_thresh_type_t type, float64_t threshold);
nai_status_t naibrd_DT_SetDebounceTime(int32_t cardIndex, int32_t module, int32_t channel, float64_t debounceTime);
nai_status_t naibrd_DT_SetPullUpDownResConfig(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dt_pullresconfig_t config);

Exercise it: DT BasicOps · ESP2 “DT” tab.

Drive outputs & read inputs

What it does: drive an output channel high/low, and read an input channel’s logic state plus its measured voltage (and output current).

Applies to: all DT modules.

Relevant APIs:

/* SSK 1.x */
nai_status_t naibrd_DT_SetOutputState(int32_t cardIndex, int32_t module, int32_t channel, nai_dt_state_t state);
nai_status_t naibrd_DT_GetOutputState(int32_t cardIndex, int32_t module, int32_t channel, nai_dt_state_t* outstate);
nai_status_t naibrd_DT_GetInputState(int32_t cardIndex, int32_t module, int32_t channel, nai_dt_state_t* outstate);
nai_status_t naibrd_DT_GetVoltage(int32_t cardIndex, int32_t module, int32_t channel, float64_t* outvoltage);
nai_status_t naibrd_DT_GetCurrent(int32_t cardIndex, int32_t module, int32_t channel, float64_t* outcurrent);
/* SSK 2.x */
nai_status_t naibrd_DT_SetOutputState(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dt_state_t state);
nai_status_t naibrd_DT_GetOutputState(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dt_state_t* p_outState);
nai_status_t naibrd_DT_GetInputState(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dt_state_t* p_inputState);
nai_status_t naibrd_DT_GetVoltage(int32_t cardIndex, int32_t module, int32_t channel, float64_t* p_outVoltage);
nai_status_t naibrd_DT_GetCurrent(int32_t cardIndex, int32_t module, int32_t channel, float64_t* p_outCurrent_mA);

Exercise it: DT BasicOps · ESP2 “DT” tab.

Pulse/frequency timing (EF — DT4/DT5)

What it does: on Enhanced-Function modules, measure pulse/frequency period on inputs and generate pulse/frequency signals on outputs — the captured edges stream through a per-channel FIFO.

Applies to: DT4 / DT5 only (Enhanced-Function members).

Relevant APIs:

/* SSK 1.x */
nai_status_t naibrd_DT_SetEnhanceTriggerEnable(int32_t cardIndex, int32_t module, int32_t channel, nai_dt_enable_t enable);
nai_status_t naibrd_DT_GetFIFOCount(int32_t cardIndex, int32_t module, int32_t channel, uint32_t* outcount);
nai_status_t naibrd_DT_ReadFIFORaw(int32_t cardIndex, int32_t module, int32_t channel, uint32_t count, uint32_t outdata[], uint32_t* outread);
/* SSK 2.x */
nai_status_t naibrd_DT_SetEnhancedMode(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dt_enhanced_mode_t mode);
nai_status_t naibrd_DT_SetEnhanceTriggerEnable(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dt_enable_type_t enable);
nai_status_t naibrd_DT_GetFIFOCount(int32_t cardIndex, int32_t module, int32_t channel, int32_t* p_outcount);
nai_status_t naibrd_DT_ReadFIFO(int32_t cardIndex, int32_t module, int32_t channel, int32_t count, int32_t timeout, uint32_t outdata[], int32_t* p_outcount, int32_t* p_outcountRemaining);

Exercise it: the DT pulse/frequency samples · ESP2 “DT” tab.

Status, BIT & protection

What it does: read per-channel status (BIT, overcurrent, threshold band, transitions), and reset a latched overcurrent fault.

Applies to: all DT modules.

Relevant APIs:

/* SSK 1.x */
nai_status_t naibrd_DT_GetStatus(int32_t cardIndex, int32_t module, int32_t channel, nai_dt_status_type_t type, nai_status_bit_t* outstatusBit);
nai_status_t naibrd_DT_GetBitStatus(int32_t cardIndex, int32_t module, int32_t channel, nai_dt_bit_status_type_t type, nai_status_bit_t* outstatusBit);
nai_status_t naibrd_DT_ClearStatus(int32_t cardIndex, int32_t module, int32_t channel, nai_dt_status_type_t type);
nai_status_t naibrd_DT_Reset(int32_t cardIndex, int32_t module, int32_t channel, nai_dt_reset_type_t resetType);
/* SSK 2.x */
nai_status_t naibrd_DT_GetChanMappedStatus(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dt_chan_mapped_status_type_t statusType, nai_status_bit_t* p_outstatusBit);
nai_status_t naibrd_DT_GetBitStatus(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dt_bit_status_type_t type, nai_status_bit_t* p_outstatusBit);
nai_status_t naibrd_DT_ClearChanMappedStatus(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dt_chan_mapped_status_type_t statusType);
nai_status_t naibrd_DT_Reset(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dt_reset_type_t resetType);

Exercise it: DT Summary · ESP2 “DT” tab.

Try it

The DT BasicOps sample application is the fastest way to drive a real DT channel. It exercises the core DT operations you’ll reuse in your own code: setting a channel’s I/O format (input, low-side, high-side, or push-pull output), controlling output state, configuring voltage thresholds, setting debounce time, reading channel status and measured voltage/current, and resetting overcurrent conditions. It supports DT1 through DT5, so it works for any member of the family.

Getting connected. Every NAI sample app — BasicOps included — starts with the same connection flow before any DT call: naiapp_RunBoardMenu() opens (or loads a saved) board connection, then naiapp_query_CardIndex() and naiapp_query_ModuleNumber() ask which board and which module slot to talk to. Under the hood the connection is opened with naibrd_OpenDevice(). The result is the three coordinates every naibrd_DT_* call takes: cardIndex (which opened board), module (the slot the DT module sits in), and channel (the discrete channel on that module). When you write your own program, you do the same — see Opening a Software Handle to Your Board.

Once connected, configuring and driving a channel looks like this:

/* SSK 1.x */
/* Drive channel 0 as a high-side output, then turn it on */
naibrd_DT_SetIOFormat(cardIndex, module, 0, NAI_DT_IOFORMAT_OUTPUT_HIGH);
naibrd_DT_SetOutputState(cardIndex, module, 0, NAI_DT_STATE_HI);
 
/* Read back a channel wired as an input */
naibrd_DT_SetIOFormat(cardIndex, module, 1, NAI_DT_IOFORMAT_INPUT);
naibrd_DT_GetInputState(cardIndex, module, 1, &state);   /* logic level */
naibrd_DT_GetVoltage(cardIndex, module, 1, &volts);      /* measured V  */
 
/* Reject relay-contact chatter on an input channel */
naibrd_DT_SetDebounceTime(cardIndex, module, 1, debounceMs);
/* SSK 2.x */
/* Drive channel 0 as a high-side output, then turn it on */
naibrd_DT_SetIOFormat(cardIndex, module, 0, NAIBRD_DT_IOFORMAT_OUTPUT_HIGH);
naibrd_DT_SetOutputState(cardIndex, module, 0, NAIBRD_DT_STATE_HI);
 
/* Read back a channel wired as an input */
naibrd_DT_SetIOFormat(cardIndex, module, 1, NAIBRD_DT_IOFORMAT_INPUT);
naibrd_DT_GetInputState(cardIndex, module, 1, &state);   /* logic level */
naibrd_DT_GetVoltage(cardIndex, module, 1, &volts);      /* measured V  */
 
/* Reject relay-contact chatter on an input channel */
naibrd_DT_SetDebounceTime(cardIndex, module, 1, debounceMs);

On a DT4 or DT5, call naibrd_DT_SetEnhancedMode() first to unlock the EF pulse/frequency features — they’re inactive in standard mode.

Run it: DT BasicOps (SSK 2.x) · DT BasicOps (SSK 1.x). For the full set of DT sample apps — and how to build and run them — see the sample-application guides: Using NAI SSK 2.x Sample Applications · Using NAI SSK 1.x Sample Applications.

Hardware capabilities and status monitoring

This section covers what the DT hardware provides and what you can monitor — for how to drive each operation (with the 1.x/2.x APIs), see Features above.

Hardware capabilities. Beyond logic state, every DT channel can measure its actual voltage (and output current), applies programmable thresholds with hysteresis (four levels: Min-Low < Lower < Upper < Max-High) and a debounce filter, offers pull-up / pull-down current sources for contact sensing without external resistors, runs continuous background BIT (CBIT), and protects outputs with overcurrent / short-circuit shutdown (latched until reset). DT4/DT5 add Enhanced-Function timing — pulse/frequency period measurement and arbitrary signal generation.

Statuses you can monitor programmatically. DT modules expose a set of status registers, most available in both a real-time (current value) and latched (sticky until you clear it) form:

StatusWhat it tells youExample constant / call
SummaryWhether any fault (BIT or overcurrent) is set on a channel — one bit per channel, so a single register reveals if anything is wrong module-wideNAIBRD_DT_STATUS_SUMMARY_LATCHED
BITBuilt-In Test detected a fault on a channelNAIBRD_DT_STATUS_BIT_LATCHED, naibrd_DT_GetBitStatus
OvercurrentAn output exceeded its current limit and shut downNAIBRD_DT_STATUS_OVERCURRENT_LATCHED
Threshold bandWhere an input sits relative to its thresholds (min-low / mid-range / max-high)NAIBRD_DT_STATUS_MIN_LO_LATCHED, _MID_RANGE_LATCHED, _MAX_HI_LATCHED
Logic transitionA low→high or high→low edge was seen on a channelNAIBRD_DT_STATUS_LO_HI_TRANS_LATCHED, _HI_LO_TRANS_LATCHED
Watchdog / inter-FPGA faultInternal module-health faultsNAIBRD_DT_STATUS_WATCHDOG_TIMER_FAULT_LATCHED, _INTER_FPGA_FAULT_LATCHED

Read these per channel with naibrd_DT_GetChanMappedStatus (2.x) / naibrd_DT_GetStatus (1.x) and naibrd_DT_GetBitStatus, or poll the bit-mapped summary register to check every channel at once. The DT Summary sample app is built around exactly this — displaying latched BIT, overcurrent, and summary status per channel, clearing latched status, and forcing a BIT error for diagnostic testing. ESP2’s status panel shows the same statuses interactively if you’d rather watch them in a GUI first.

Common pitfalls

  • An output channel won’t drive a load. DT outputs switch your power, not the module’s — they need an external VCC (3–60 V) applied to the module. With no VCC supplied, a channel set to output simply won’t source or sink current. Check the supply and that ISO-GND is tied to your supply ground.
  • An input reads stuck high or low. For contact sensing, enable the channel’s pull-up or pull-down current source rather than expecting an external resistor — without it, an open contact floats. If a voltage input reads the wrong state, check the configured thresholds (naibrd_DT_SetThreshold).
  • A relay or switch input flickers or double-triggers. That’s contact bounce. Set a debounce time (naibrd_DT_SetDebounceTime) to filter it.
  • EF features (pulse/frequency) do nothing on a DT4/DT5. They’re only active in enhanced mode — call naibrd_DT_SetEnhancedMode() before using them.
  • An output shut off unexpectedly. DT outputs have thermal and overcurrent protection. Read channel status to confirm, and reset the overcurrent condition once the fault is cleared (the BasicOps sample shows this).
  • You picked the wrong member for the voltage/isolation you need. DT1/DT4 are non-isolated; DT2/DT5 are isolated and sense up to ±80 V. Re-check the comparison table if your signal is isolated or out of range.