Differential I/O (DF) Family Guide

Overview

The DF family is NAI’s line of differential digital I/O modules — DF1 and DF2, each with 16 channels of RS-422/RS-485 differential transceiver I/O, every channel individually programmable as an input or an output. This is digital I/O: each channel carries a logic state (on/off), not an analog measurement.

The “differential” part is what sets this family apart. An ordinary discrete I/O line is single-ended — one wire whose voltage is read against a shared ground; over a long, electrically noisy cable run, noise on that wire causes false readings. A differential channel uses two complementary wires (an A/B pair): to signal “on” it drives A high and B low; to signal “off”, A low and B high. The receiver ignores ground and looks only at the difference between A and B. Because noise couples into both wires almost equally, it cancels in the difference — so the real signal survives where a single-ended line would be corrupted. That common-mode rejection is why differential (RS-422/485) signaling carries logic states reliably over long, noisy runs at lower drive voltages. NAI’s phrasing: complementary signals on balanced lines “double noise immunity.”

So a DF channel is a noise-hardened digital line you can point in or out — to command something (output: the module drives the line) or to sense a status (input: the module reads the line) — with 16 such channels per module.

In a real system, differential digital I/O is used wherever logic-level control and status signals must travel reliably over distance or through electrical noise: enable/inhibit, ready/fault, and mode-select discretes between LRUs over long harnesses; RS-422/485-style command and handshake lines; and sync/trigger distribution across a chassis or between units. DF2 adds the ability for a channel to generate timed waveforms (PWM and programmed bit patterns) and to measure pulse timing on an input — covered below.

DF is the differential member of NAI’s discrete/switching I/O families — RS-422/485 lines for noise-hardened signaling over long, noisy runs. The DT family provides single-ended field-level discrete I/O (relay/lamp/solenoid loads, contact sensing, isolated options); the TL family handles single-ended logic-level TTL/CMOS I/O; and the RY family uses mechanical relay contacts for galvanic isolation and switching AC, high voltage, or analog signals. DF is the differential counterpart for when signals must survive distance or electrical noise.

DF modules at a glance

Both members are 16-channel RS-422/485 differential transceivers, each channel programmable as an input or an output, with programmable slew rate, debounce (rejects relay-contact-bounce false edges), input termination, and continuous background BIT. They differ in what a channel can do beyond basic input/output:

ModuleChannelsPer-channel capabilityAPI
DF116Programmable differential I/O — each channel a basic input or outputnaibrd_DIF_*
DF216Enhanced — basic I/O plus per-channel PWM output, pattern generation, and pulse-timing measurement (selected via an op-mode/Mode-Select register)naibrd_DIF_*

Choosing a member:

  • Basic differential digital I/O — sensing and commanding noise-hardened on/off lines — DF1.
  • You also need a channel to generate a PWM waveform, replay a programmed bit pattern, or measure the timing/width of incoming pulsesDF2 (a superset of DF1; it does everything DF1 does and adds the enhanced modes).

Note

Both modules use the same naibrd_DIF_* API (the API and SSK sample apps are named DIF, not “DF”). The enhanced PWM / pattern-generator / pulse-timing calls simply have no effect on DF1, which has no enhanced modes. Confirm exact specs on each module’s manual: DF1 Manual, DF2 Manual.

Physical setup

Each channel is a differential pair — two complementary lines (A and B). You wire the channel’s A/B pair to the matching pair on the far device (A→A, B→B); the module drives that pair when the channel is an output and reads it when the channel is an input. The exact pins are per-module, so always get them from the module’s manual or overlay card; the pattern is the same for every channel:

  1. Identify the module’s slot number on your NAI motherboard or system.
  2. Bring the channel’s lines out through the breakout board, where the slot’s pins appear as generic IO# numbers.
  3. Map IO# pins to the channel’s A and B differential lines per the pinout in the manual.
  4. Wire A→A and B→B to the far device’s differential pair.

A few things hold for every DF channel:

  • Set the channel direction first. Each channel is an input or an output — naibrd_DIF_SetIOFormat with NAIBRD_DIF_IOFORMAT_INPUT or NAIBRD_DIF_GEN5_IOFORMAT_OUTPUT. Drive outputs with SetOutputState; read inputs with GetInputState.
  • Terminate long lines. On a long RS-422/485 run, enable the receiver-end termination (naibrd_DIF_SetInputTermination, NAIBRD_DIF_INPUT_TERMINATED) to absorb reflections; short bench links usually don’t need it.
  • Pick a slew rate. naibrd_DIF_SetSlewRateNAIBRD_DIF_SLEWRATE_FAST for higher-speed signaling, NAIBRD_DIF_SLEWRATE_SLOW to limit EMI on slower signals.
  • Debounce mechanical inputs. For inputs fed by relay or switch contacts, set a debounce time (naibrd_DIF_SetDebounceTime) so contact bounce reads as one clean edge instead of several.

Worked examples (use your module’s pinout for the actual pins):

  • Drive a control output. Set the channel to output mode, wire its A/B pair to the receiving device, and drive it NAIBRD_DIF_STATE_HI / _LO to command on/off.
  • Read a status input. Set the channel to input mode, wire its A/B pair to the source device, and read GetInputState — terminate the line and debounce if it comes from a long run or a mechanical contact.
  • Bench output→input loopback. Cable an output channel’s A/B pair to an input channel’s A/B pair on the same module, drive the output, and confirm the input follows — exactly the self-test below.

Software

There’s nothing DF-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 DF module. The only family-specific part is which API functions you call: DF modules use the naibrd_DIF_* calls (the API is named DIF, not “DF”).

These calls are stateless — every function takes (cardIndex, module, channel) and acts immediately; there is no Open/Init/Free lifecycle to manage. Where to find what you need:

  • Which functions/registers to call — the DF1 Manual and DF2 Manual document every naibrd_DIF_* register (direction, output/input state, slew rate, termination, debounce, BIT/status — and on DF2, PWM, pattern generation, and pulse-timing).
  • 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 DF1 module: pull the naibrd_DIF_* calls from the DF1 Manual, set up the ARM Linux toolchain per Connecting to Boards, then load and launch a DIF 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 digital I/O module has no internal test-injection, so proving a channel end-to-end means driving an output and reading it 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_DIF_GetChanMappedStatus(cardIndex, module, channel,
   NAIBRD_DIF_STATUS_BIT_LATCHED, &bitStatus);                          /* LO = normal */

Two-channel loopback (proves the transceivers and wiring). Set one channel as an output and another as an input, cable the output’s A/B pair to the input’s A/B pair, drive the output, and read it back:

/* Channel A = output, Channel B = input, cabled A/B-pair to A/B-pair */
naibrd_DIF_SetIOFormat(cardIndex, module, chOut, NAIBRD_DIF_GEN5_IOFORMAT_OUTPUT);
naibrd_DIF_SetIOFormat(cardIndex, module, chIn,  NAIBRD_DIF_IOFORMAT_INPUT);
 
naibrd_DIF_SetOutputState(cardIndex, module, chOut, NAIBRD_DIF_STATE_HI);
naibrd_dif_state_t in_hi;
naibrd_DIF_GetInputState(cardIndex, module, chIn, &in_hi);              /* should read HI */
 
naibrd_DIF_SetOutputState(cardIndex, module, chOut, NAIBRD_DIF_STATE_LO);
naibrd_dif_state_t in_lo;
naibrd_DIF_GetInputState(cardIndex, module, chIn, &in_lo);             /* should read LO */

If BIT status is clean and the input channel follows the output’s HI/LO, your board connection, the SSK, the transceivers, and your wiring are all confirmed. The DIF BasicOps sample drives exactly this flow — direction, output/input state, and status across channels.

Features

Each operation works per channel through the naibrd_DIF_* API. The blocks below group the calls by what you’re doing — think of them like the controls on ESP2’s DIF panel — with the SSK 1.x and 2.x signatures side by side. (The 1.x → 2.x rename is narrow: nai_dif_* enum types became naibrd_dif_*, and GetStatus/ClearStatus became per-channel GetChanMappedStatus/ClearChanMappedStatus; function names and out-parameter names are otherwise the same.) The PWM, pattern-generation, and pulse-timing blocks are DF2-only enhanced modes.

Configure a channel

What it does: set up a channel before use — its direction (input or output), slew rate, input termination, and debounce time — and reset it when needed.

Applies to: all DF channels.

Also here: SetIOFormat uses NAIBRD_DIF_IOFORMAT_INPUT / NAIBRD_DIF_GEN5_IOFORMAT_OUTPUT; slew is NAIBRD_DIF_SLEWRATE_SLOW / _FAST; termination is NAIBRD_DIF_INPUT_TERMINATED.

Relevant APIs:

/* SSK 1.x */
nai_status_t naibrd_DIF_SetIOFormat(int32_t cardIndex, int32_t module, int32_t channel, nai_dif_ioformat_t format);
nai_status_t naibrd_DIF_SetSlewRate(int32_t cardIndex, int32_t module, int32_t channel, nai_dif_slewRate_t rate);
nai_status_t naibrd_DIF_SetInputTermination(int32_t cardIndex, int32_t module, int32_t channel, nai_dif_input_term_t InputTermination);
nai_status_t naibrd_DIF_SetDebounceTime(int32_t cardIndex, int32_t module, int32_t channel, float64_t debounceTime);
nai_status_t naibrd_DIF_Reset(int32_t cardIndex, int32_t module, int32_t channel, nai_dif_reset_type_t resetType);
/* SSK 2.x */
nai_status_t naibrd_DIF_SetIOFormat(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dif_ioformat_t format);
nai_status_t naibrd_DIF_SetSlewRate(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dif_slewRate_t rate);
nai_status_t naibrd_DIF_SetInputTermination(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dif_input_term_t InputTermination);
nai_status_t naibrd_DIF_SetDebounceTime(int32_t cardIndex, int32_t module, int32_t channel, float64_t debounceTime);
nai_status_t naibrd_DIF_Reset(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dif_reset_type_t resetType);

Exercise it: DIF BasicOps · DIF BasicOps (1.x) · ESP2 DIF panel.

Drive outputs & read inputs

What it does: the core operation — drive an output channel HI or LO, and read the logic state of an input (or read back what an output is driving).

Applies to: all DF channels.

Also here: state values are NAIBRD_DIF_STATE_HI / NAIBRD_DIF_STATE_LO.

Relevant APIs:

/* SSK 1.x */
nai_status_t naibrd_DIF_SetOutputState(int32_t cardIndex, int32_t module, int32_t channel, nai_dif_state_t state);
nai_status_t naibrd_DIF_GetOutputState(int32_t cardIndex, int32_t module, int32_t channel, nai_dif_state_t* outstate);
nai_status_t naibrd_DIF_GetInputState(int32_t cardIndex, int32_t module, int32_t channel, nai_dif_state_t* outstate);
/* SSK 2.x */
nai_status_t naibrd_DIF_SetOutputState(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dif_state_t state);
nai_status_t naibrd_DIF_GetOutputState(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dif_state_t* outstate);
nai_status_t naibrd_DIF_GetInputState(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dif_state_t* outstate);

Exercise it: DIF BasicOps · DIF BasicOps (1.x).

PWM output — DF2

What it does: drive a channel as a pulse-width-modulated output — set the period and pulse width (duty cycle) and run it continuously or for a set number of cycles. Use it to drive PWM-controlled loads or generate a timed pulse train.

Applies to: DF2 only.

Also here: select the mode with SetOpMode (NAIBRD_DIF_MODE_OUTPUT_PWM_FOREVER or NAIBRD_DIF_MODE_OUTPUT_PWM_CYCLE_NUM_TIMES); polarity is NAIBRD_DIF_PWMPOLARITY_POS / _NEG; SetPWM_BurstNum sets the cycle count for the “N times” mode.

Relevant APIs:

/* SSK 1.x */
nai_status_t naibrd_DIF_SetOpMode(int32_t cardIndex, int32_t module, int32_t channel, nai_dif_enhanced_mode_t mode);
nai_status_t naibrd_DIF_SetPWM_Polarity(int32_t cardIndex, int32_t module, int32_t channel, nai_dif_pwm_polarity_t polarity);
nai_status_t naibrd_DIF_SetPWM_Period(int32_t cardIndex, int32_t module, int32_t channel, float64_t period);
nai_status_t naibrd_DIF_SetPWM_Pulsewidth(int32_t cardIndex, int32_t module, int32_t channel, float64_t pulsewidth);
nai_status_t naibrd_DIF_SetPWM_BurstNum(int32_t cardIndex, int32_t module, int32_t channel, uint32_t burstNum);
nai_status_t naibrd_DIF_StartPWM(int32_t cardIndex, int32_t module, int32_t channel);
nai_status_t naibrd_DIF_StopPWM(int32_t cardIndex, int32_t module, int32_t channel);
/* SSK 2.x */
nai_status_t naibrd_DIF_SetOpMode(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dif_enhanced_mode_t mode);
nai_status_t naibrd_DIF_SetPWM_Polarity(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dif_pwm_polarity_t polarity);
nai_status_t naibrd_DIF_SetPWM_Period(int32_t cardIndex, int32_t module, int32_t channel, float64_t period);
nai_status_t naibrd_DIF_SetPWM_Pulsewidth(int32_t cardIndex, int32_t module, int32_t channel, float64_t pulsewidth);
nai_status_t naibrd_DIF_SetPWM_BurstNum(int32_t cardIndex, int32_t module, int32_t channel, uint32_t burstNum);
nai_status_t naibrd_DIF_StartPWM(int32_t cardIndex, int32_t module, int32_t channel);
nai_status_t naibrd_DIF_StopPWM(int32_t cardIndex, int32_t module, int32_t channel);

Exercise it: DIF PWM · DIF PWM (1.x).

Pattern generation — DF2

What it does: replay a programmed sequence of digital states from pattern RAM out a channel — set the RAM start/end addresses, the step period, and an optional burst count, then enable it. Use it to stimulate or test another device with a known waveform.

Applies to: DF2 only.

Also here: select NAIBRD_DIF_MODE_OUTPUT_PATTERN_RAM with SetOpMode; SetPatternGenCtrl toggles NAIBRD_DIF_PATTERN_RAM_CONTROL_ENABLE / _BURST / _PAUSE.

Relevant APIs:

/* SSK 1.x */
nai_status_t naibrd_DIF_SetPatternGenStartAddr(int32_t cardIndex, int32_t module, uint32_t startAddr);
nai_status_t naibrd_DIF_SetPatternGenEndAddr(int32_t cardIndex, int32_t module, uint32_t EndAddr);
nai_status_t naibrd_DIF_SetPatternGenPeriod(int32_t cardIndex, int32_t module, float64_t period_mS);
nai_status_t naibrd_DIF_SetPatternGen_BurstNum(int32_t cardIndex, int32_t module, uint32_t burstNum);
nai_status_t naibrd_DIF_SetPatternGenCtrl(int32_t cardIndex, int32_t module, nai_dif_pattern_ctrl_t controlBit, nai_dif_enable_t state);
/* SSK 2.x */
nai_status_t naibrd_DIF_SetPatternGenStartAddr(int32_t cardIndex, int32_t module, uint32_t startAddr);
nai_status_t naibrd_DIF_SetPatternGenEndAddr(int32_t cardIndex, int32_t module, uint32_t EndAddr);
nai_status_t naibrd_DIF_SetPatternGenPeriod(int32_t cardIndex, int32_t module, float64_t period_mS);
nai_status_t naibrd_DIF_SetPatternGen_BurstNum(int32_t cardIndex, int32_t module, uint32_t burstNum);
nai_status_t naibrd_DIF_SetPatternGenCtrl(int32_t cardIndex, int32_t module, naibrd_dif_pattern_ctrl_t controlBit, naibrd_dif_enable_t state);

Exercise it: DIF Pattern Generator · DIF Pattern Generator (1.x).

Pulse-timing & edge measurement — DF2

What it does: measure the timing of an incoming signal — high/low time, period, frequency, edge timestamps, or edge counts — by putting the channel in a measurement op-mode; results accumulate in a per-channel FIFO you read out.

Applies to: DF2 only.

Also here: the op-mode picks the measurement: NAIBRD_DIF_MODE_MEASURE_HIGH_TIME / _LOW_TIME / _MEASURE_PERIOD_FROM_RISING_EDGE / _MEASURE_FREQUENCY, the TIMESTAMP_{RISING,FALLING,ALL}_EDGES, and the COUNT_{RISING,FALLING,ALL}_EDGES modes. Read the FIFO with GetFIFOCount then ReadFIFORaw (or GetCountData for the count modes); ClearFIFO resets it.

Relevant APIs:

/* SSK 1.x */
nai_status_t naibrd_DIF_SetOpMode(int32_t cardIndex, int32_t module, int32_t channel, nai_dif_enhanced_mode_t mode);
nai_status_t naibrd_DIF_GetFIFOCount(int32_t cardIndex, int32_t module, int32_t channel, uint32_t* outcount);
nai_status_t naibrd_DIF_ReadFIFORaw(int32_t cardIndex, int32_t module, int32_t channel, uint32_t count, uint32_t outdata[], uint32_t* outread);
nai_status_t naibrd_DIF_GetCountData(int32_t cardIndex, int32_t module, int32_t channel, uint32_t* outcount);
nai_status_t naibrd_DIF_ClearFIFO(int32_t cardIndex, int32_t module, int32_t channel);
/* SSK 2.x */
nai_status_t naibrd_DIF_SetOpMode(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dif_enhanced_mode_t mode);
nai_status_t naibrd_DIF_GetFIFOCount(int32_t cardIndex, int32_t module, int32_t channel, uint32_t* outcount);
nai_status_t naibrd_DIF_ReadFIFORaw(int32_t cardIndex, int32_t module, int32_t channel, uint32_t count, uint32_t outdata[], uint32_t* outread);
nai_status_t naibrd_DIF_GetCountData(int32_t cardIndex, int32_t module, int32_t channel, uint32_t* outcount);
nai_status_t naibrd_DIF_ClearFIFO(int32_t cardIndex, int32_t module, int32_t channel);

Exercise it: DIF Measure · DIF Measure (1.x).

Health, BIT & status

What it does: read the channel’s fault flags and tune BIT. A background test comparator checks each channel; status reports BIT, overcurrent, and low→high / high→low transition events, each real-time and latched.

Applies to: all DF channels (BIT/status per channel; BIT interval per module).

Also here: status types are NAIBRD_DIF_STATUS_{BIT,OVERCURRENT,LO_HI_TRANS,HI_LO_TRANS}_{LATCHED,REALTIME}.

Relevant APIs:

/* SSK 1.x */
nai_status_t naibrd_DIF_GetStatus(int32_t cardIndex, int32_t module, int32_t channel, nai_dif_status_type_t type, nai_status_bit_t* outstatusVal);
nai_status_t naibrd_DIF_ClearStatus(int32_t cardIndex, int32_t module, int32_t channel, nai_dif_status_type_t type);
nai_status_t naibrd_DIF_SetBITInterval(int32_t cardIndex, int32_t module, uint32_t bitInterval);
/* SSK 2.x */
nai_status_t naibrd_DIF_GetChanMappedStatus(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dif_chan_mapped_status_type_t type, nai_status_bit_t* outstatusVal);
nai_status_t naibrd_DIF_ClearChanMappedStatus(int32_t cardIndex, int32_t module, int32_t channel, naibrd_dif_chan_mapped_status_type_t type);
nai_status_t naibrd_DIF_SetBITInterval(int32_t cardIndex, int32_t module, uint32_t bitInterval);

Exercise it: DIF BasicOps (status) · DIF Interrupts (1.x, interrupt-driven status).

Try it

The snippets below show the order of naibrd_DIF_* calls for each task — drop them into the body of an NAI sample app (after the standard connection flow: naiapp_RunBoardMenu()naiapp_query_CardIndex() / naiapp_query_ModuleNumber()cardIndex/module, see Opening a Software Handle to Your Board) and you have a working channel. Each is the conceptual sequence, not a fully-buildable program; the sample apps under each block’s “Exercise it:” line above are the full reference. DF calls are stateless — there is no Open/Init/Free.

Try it — Drive an output and read an input

Set a channel’s direction, then drive an output HI/LO or read an input’s state.

/* SSK 1.x — output drive + input read */
naibrd_DIF_SetIOFormat(cardIndex, module, chOut, NAI_DIF_GEN5_IOFORMAT_OUTPUT);
naibrd_DIF_SetIOFormat(cardIndex, module, chIn,  NAI_DIF_IOFORMAT_INPUT);
 
naibrd_DIF_SetOutputState(cardIndex, module, chOut, NAI_DIF_STATE_HI);   /* command on */
 
nai_dif_state_t state;
naibrd_DIF_GetInputState(cardIndex, module, chIn, &state);              /* sense the line */
/* SSK 2.x — output drive + input read */
naibrd_DIF_SetIOFormat(cardIndex, module, chOut, NAIBRD_DIF_GEN5_IOFORMAT_OUTPUT);
naibrd_DIF_SetIOFormat(cardIndex, module, chIn,  NAIBRD_DIF_IOFORMAT_INPUT);
 
naibrd_DIF_SetOutputState(cardIndex, module, chOut, NAIBRD_DIF_STATE_HI);  /* command on */
 
naibrd_dif_state_t state;
naibrd_DIF_GetInputState(cardIndex, module, chIn, &state);                /* sense the line */

Try it — Generate a PWM output (DF2)

Put the channel in PWM mode, set the period and pulse width, then start it. Here: a 1 ms period with a 0.25 ms pulse (25% duty), running continuously.

/* SSK 1.x — continuous 25%-duty PWM */
naibrd_DIF_SetIOFormat(cardIndex, module, channel, NAI_DIF_GEN5_IOFORMAT_OUTPUT);
naibrd_DIF_SetOpMode(cardIndex, module, channel, NAI_DIF_MODE_OUTPUT_PWM_FOREVER);
naibrd_DIF_SetPWM_Polarity(cardIndex, module, channel, NAI_DIF_PWMPOLARITY_POS);
naibrd_DIF_SetPWM_Period(cardIndex, module, channel, 1.0);        /* ms */
naibrd_DIF_SetPWM_Pulsewidth(cardIndex, module, channel, 0.25);   /* ms */
naibrd_DIF_StartPWM(cardIndex, module, channel);
/* ... naibrd_DIF_StopPWM(cardIndex, module, channel); when done */
/* SSK 2.x — continuous 25%-duty PWM */
naibrd_DIF_SetIOFormat(cardIndex, module, channel, NAIBRD_DIF_GEN5_IOFORMAT_OUTPUT);
naibrd_DIF_SetOpMode(cardIndex, module, channel, NAIBRD_DIF_MODE_OUTPUT_PWM_FOREVER);
naibrd_DIF_SetPWM_Polarity(cardIndex, module, channel, NAIBRD_DIF_PWMPOLARITY_POS);
naibrd_DIF_SetPWM_Period(cardIndex, module, channel, 1.0);        /* ms */
naibrd_DIF_SetPWM_Pulsewidth(cardIndex, module, channel, 0.25);   /* ms */
naibrd_DIF_StartPWM(cardIndex, module, channel);
/* ... naibrd_DIF_StopPWM(cardIndex, module, channel); when done */

Try it — Measure pulse high-time (DF2)

Put the channel in a measurement mode, then read accumulated measurements out of the FIFO.

/* SSK 1.x — measure high-time into the FIFO */
naibrd_DIF_SetIOFormat(cardIndex, module, channel, NAI_DIF_IOFORMAT_INPUT);
naibrd_DIF_SetOpMode(cardIndex, module, channel, NAI_DIF_MODE_MEASURE_HIGH_TIME);
 
uint32_t avail, got, data[64];
naibrd_DIF_GetFIFOCount(cardIndex, module, channel, &avail);
naibrd_DIF_ReadFIFORaw(cardIndex, module, channel, (avail < 64 ? avail : 64), data, &got);
/* SSK 2.x — measure high-time into the FIFO */
naibrd_DIF_SetIOFormat(cardIndex, module, channel, NAIBRD_DIF_IOFORMAT_INPUT);
naibrd_DIF_SetOpMode(cardIndex, module, channel, NAIBRD_DIF_MODE_MEASURE_HIGH_TIME);
 
uint32_t avail, got, data[64];
naibrd_DIF_GetFIFOCount(cardIndex, module, channel, &avail);
naibrd_DIF_ReadFIFORaw(cardIndex, module, channel, (avail < 64 ? avail : 64), data, &got);

Building and running the SSK samples. The snippets above are condensed for orientation. For full, buildable programs see the “Exercise it:” links under each block in FeaturesDIF BasicOps / DIF PWM / DIF Pattern Generator / DIF Measure (2.x) and the matching DIF BasicOps / DIF PWM / DIF Pattern Generator / DIF Measure (1.x) — and Using NAI SSK 2.x Sample Applications · Using NAI SSK 1.x Sample Applications for build/run instructions across platforms.

Hardware capabilities and status monitoring

This section covers what the hardware provides and what you can monitor — for how to configure and drive each channel, see Features and Try it above.

What the hardware provides:

  • 16 RS-422/485 differential transceiver channels — each individually programmable as an input or an output, for noise-immune logic signaling over long runs.
  • Programmable slew rate — fast or slow, trading signaling speed against EMI.
  • Programmable input termination — switch in receiver-end termination for long lines.
  • Programmable debounce — reject mechanical contact-bounce false edges on inputs.
  • Background BIT — a per-channel test comparator continuously checks each channel with no external programming; overcurrent and logic-transition events are flagged too.
  • DF2 enhanced modes — per-channel PWM output (continuous or N cycles), pattern generation from RAM, and pulse-timing / edge measurement (high/low time, period, frequency, edge timestamps, edge counts) buffered through a FIFO.

Statuses you can monitor programmatically (per channel, each in real-time and latched form via naibrd_DIF_GetChanMappedStatus):

StatusWhat it tells you
BITA built-in-test fault on the channel
OvercurrentThe output channel is drawing too much current (e.g. a shorted line)
Low→High transitionA rising edge was detected on the channel
High→Low transitionA falling edge was detected on the channel

Set the background-test cadence with naibrd_DIF_SetBITInterval. ESP2’s status panel shows DIF state and status interactively if you’d rather watch it in a GUI first.

Common pitfalls

  • Direction not set. A channel must be set to input or output (naibrd_DIF_SetIOFormat) before driving or reading it. Driving a channel left as an input (or reading one set as an output) won’t behave as expected.
  • Differential pair miswired (A/B swapped). A differential channel’s two lines are complementary — swapping A and B inverts the sense of the signal. Wire A→A and B→B.
  • Long line not terminated. On a long RS-422/485 run, missing receiver-end termination causes reflections and errors. Enable termination (naibrd_DIF_SetInputTermination) for long lines; leave it off for short bench links.
  • Mechanical input not debounced. An input fed by relay/switch contacts can register several edges per actuation. Set a debounce time (naibrd_DIF_SetDebounceTime) so it reads as one clean edge.
  • Output overcurrent (shorted line). A shorted or overloaded output trips the overcurrent status — check it and clear with Reset (NAIBRD_DIF_RESET_OVERCURRENT) after fixing the wiring.
  • (DF2) Enhanced calls on DF1. PWM, pattern-generation, and pulse-timing modes exist only on DF2; those calls have no effect on DF1.
  • (DF2) Measurement FIFO not serviced. In a measurement mode, read the FIFO (GetFIFOCountReadFIFORaw) and clear it (ClearFIFO) so it doesn’t overflow or return stale data.