DSW Interrupt Basic
Edit this on GitLab
DSW Interrupt Basic Sample Application (SSK 1.x)
Overview
The DSW Interrupt Basic sample application demonstrates how to configure and handle hardware interrupts on discrete switch (DSW) modules using the NAI Software Support Kit (SSK 1.x). DSW modules support the richest set of interrupt status types of any discrete I/O module in the NAI product line — seven distinct types, each with real-time and latched variants, for a total of fourteen status registers per channel. The seven types are: BIT (built-in test), overcurrent, maximum-high threshold, minimum-low threshold, mid-range, low-to-high transition, and high-to-low transition. This makes the DSW Interrupt Basic sample the most comprehensive discrete interrupt example in the SSK.
This sample supports the following DSW module types: K7, DT2, and DT5. For background on general discrete I/O operations (channel configuration, reading and writing states, threshold setup), see the DSW BasicOps guide. For interrupt concepts — including edge vs. level triggering, interrupt vector numbering, steering architecture, and latency measurement — see the Interrupts API Guide. This guide focuses on how those concepts apply specifically to DSW modules and their extended set of interrupt status types.
Prerequisites
Before running this sample, make sure you have:
-
An NAI board with a DSW module installed (K7, DT2, or DT5).
-
SSK 1.x installed on your development host.
-
The sample applications built. Refer to the SSK 1.x build instructions for your platform if you have not already compiled them.
How to Run
Launch the DSW_Interrupt_Basic executable from your build output directory. On startup the application looks for a configuration file (default_DSW_Interrupt_Basic.txt). On the first run, this file will not exist — the application will present an interactive board menu where you configure a board connection, card index, and module slot. You can save this configuration so that subsequent runs skip the menu and connect automatically. Once connected, the application prompts you for interrupt steering and begins waiting for interrupt events.
Board Connection and Module Selection
|
Note
|
This startup sequence is common to all NAI sample applications. The board connection and module selection code shown here is not specific to DSW. For details on board connection configuration, see the First Time Setup Guide. |
The main() function (or DSW_Interrupt_Basic() on VxWorks) follows a standard SSK 1.x startup flow:
-
Initialize DSW and interrupt configuration structures to default values.
-
Call
naiapp_RunBoardMenu()to load a saved configuration file (if one exists) or present the interactive board menu. The configuration file (default_DSW_Interrupt_Basic.txt) is not included with the SSK — it is created when the user saves their connection settings from the board menu. On the first run, the menu will always appear. -
Query the user for the card index and module slot.
-
Retrieve the module ID to confirm a DSW module is present before proceeding.
#if defined (__VXWORKS__)
int32_t DSW_Interrupt_Basic(void)
#else
int32_t main(void)
#endif
{
bool_t stop = FALSE;
int32_t cardIndex;
int32_t moduleCnt;
int32_t module;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
initializeDSWConfigurations(0, 0, 0, 0, 0, 0);
initializeInterruptConfigurations(FALSE, FALSE, FALSE, 0, 0, 0, 0);
if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
{
while (stop != TRUE)
{
/* Query the user for the card index */
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
inputDSWConfig.cardIndex = cardIndex;
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
/* Query the user for the module number */
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
inputDSWConfig.module = module;
if (stop != TRUE)
{
inputDSWConfig.modid = naibrd_GetModuleID(cardIndex, module);
if ((inputDSWConfig.modid != 0))
{
Run_DSW_Interrupt_Basic();
}
}
}
printf("\nType Q to quit or Enter key to restart application:\n");
stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
}
}
printf("\nType the Enter key to exit the program: ");
naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
naiapp_access_CloseAllOpenCards();
return 0;
}
|
Important
|
Common connection errors you may encounter at this stage:
|
Program Structure
The DSW Interrupt Basic sample is split across two source files:
-
DSW_Interrupt_Basic.c— the application entry point. Handles board connection, user prompts, and orchestrates the interrupt lifecycle. -
nai_dsw_int.c— shared interrupt configuration and handling code. Contains the ISR, configuration functions, enable/disable logic, and the interrupt polling loop.
The entry point is main() (or DSW_Interrupt_Basic() on VxWorks). After the board connection is established, the application follows a linear flow:
-
Determine the channel count for the installed module via
naibrd_DSW_GetChannelCount(). -
Query the user for interrupt steering mode (onboard or offboard).
-
Install the ISR.
-
Configure all interrupt registers (disable, clear, set vectors, set trigger mode, set steering).
-
Enable interrupts on all channels.
-
Enter a polling loop that checks for interrupt events and reports status.
-
On exit, disable interrupts and uninstall the ISR.
Shared Data Structures
The sample uses two structures to track runtime state:
typedef struct
{
int32_t cardIndex;
int32_t module;
uint32_t modid;
int32_t channel;
int32_t maxChannel;
int32_t minChannel;
} DswConfig;
DswConfig holds the board and module identifiers collected during the interactive prompts. maxChannel is populated from naibrd_DSW_GetChannelCount() and determines the channel range for configuration loops.
The InterruptConfig structure (from naiapp_interrupt.h) tracks interrupt delivery settings: steering mode, IRQ selection, and edge/level trigger preference.
Both structures are declared as global externs shared between the entry point file and the common interrupt code.
Interrupt Status Types
The DSW module exposes seven distinct interrupt status types — significantly more than the four types available on standard DT modules (BIT, overcurrent, low-to-high, high-to-low). The additional three threshold-based types (maximum-high, minimum-low, and mid-range) are unique to DSW and reflect the module’s ability to monitor input voltage against programmable threshold levels. Each type exists in both a latched and a real-time variant, yielding fourteen total status registers per channel.
Understanding the threshold hierarchy is essential for configuring DSW interrupts correctly. The DSW module defines five voltage zones arranged from lowest to highest:
| Min-Low Zone | Lower Threshold | Mid-Range Zone | Upper Threshold | Max-High Zone | 0V ─────────────── lower limit ─────────── (middle) ──────── upper limit ────────────────── Vmax
The lower and upper thresholds are programmable per-channel. Consult your module’s manual for the supported voltage ranges and threshold register addresses.
BIT (Built-In Test)
NAI_DSW_STATUS_BIT_LATCHED / NAI_DSW_STATUS_BIT_REALTIME
The module’s internal self-test has detected an anomaly on a channel. The Built-In Test circuitry continuously monitors the health of each discrete switch channel, checking for conditions such as open inputs, stuck outputs, or internal reference failures. When BIT detects a problem, it latches the corresponding status bit and, if enabled, raises an interrupt.
Enable BIT interrupts for health monitoring, safety-critical applications, or continuous hardware validation. In systems where a failed channel must be flagged immediately — rather than discovered during a periodic status poll — BIT interrupts provide the fastest notification path.
Overcurrent
NAI_DSW_STATUS_OVERCURRENT_LATCHED / NAI_DSW_STATUS_OVERCURRENT_REALTIME
An output channel detected an overcurrent condition. The module’s current-sensing circuitry monitors each output and latches this status when the channel is sourcing or sinking more current than its rated limit. An overcurrent event typically indicates a wiring fault, a short circuit, or an unexpectedly heavy load on the channel.
Enable overcurrent interrupts for output protection, fault detection, and load monitoring. In applications that drive external relays, solenoids, or indicator lamps through DSW outputs, an overcurrent interrupt lets you react immediately — disabling the output, alerting the operator, or switching to a backup channel — before damage occurs.
Maximum High Threshold
NAI_DSW_STATUS_MAX_HI_LATCHED / NAI_DSW_STATUS_MAX_HI_REALTIME
The input voltage on a channel has exceeded the upper maximum threshold. This threshold sits above the upper programmable limit and represents an absolute ceiling for the input signal. When the voltage rises above this level, the module latches the max-high status.
Enable maximum-high threshold interrupts to detect overvoltage conditions at the input. This is distinct from a simple high state — it indicates the voltage has exceeded the expected operating range entirely. This can flag miswired inputs, power supply faults in the external circuit, or signals from a voltage domain that does not match the module’s configuration.
Minimum Low Threshold
NAI_DSW_STATUS_MIN_LO_LATCHED / NAI_DSW_STATUS_MIN_LO_REALTIME
The input voltage on a channel has dropped below the lower minimum threshold. This threshold sits below the lower programmable limit and represents an absolute floor for the input signal. When the voltage falls below this level, the module latches the min-low status.
Enable minimum-low threshold interrupts to detect undervoltage conditions or open/floating inputs. A channel that should be driven to a valid logic level but reads below the minimum threshold may have a broken wire, a disconnected sensor, or insufficient drive strength in the external circuit.
Mid-Range
NAI_DSW_STATUS_MID_RANGE_LATCHED / NAI_DSW_STATUS_MID_RANGE_REALTIME
The input voltage on a channel is in the mid-range zone — between the lower and upper programmable thresholds. In discrete logic terms, this is an indeterminate region where the voltage is neither a clear logic high nor a clear logic low. The module latches this status when the input voltage enters the mid-range zone.
Enable mid-range interrupts to detect indeterminate or transitioning signals. A channel that lingers in the mid-range zone may indicate slow signal transitions, noisy inputs, improper termination, or a signal source with insufficient drive strength to reach a valid logic level. In safety-critical systems, mid-range detection can flag channels whose inputs are unreliable.
Low-to-High Transition
NAI_DSW_STATUS_LO_HI_TRANS_LATCHED / NAI_DSW_STATUS_LO_HI_TRANS_REALTIME
A discrete input transitioned from low to high. The module captures the rising edge and latches the status bit so the event is not lost even if the input changes again before the software reads the register.
Enable low-to-high transition interrupts for rising-edge detection: switch closures, signal activation, event counting, or detecting when an external condition becomes active. This is the most common trigger type for applications that need to respond the moment an input asserts.
High-to-Low Transition
NAI_DSW_STATUS_HI_LO_TRANS_LATCHED / NAI_DSW_STATUS_HI_LO_TRANS_REALTIME
A discrete input transitioned from high to low. Like its low-to-high counterpart, the module captures the falling edge and latches it for reliable software consumption.
Enable high-to-low transition interrupts for falling-edge detection: switch openings, signal deactivation, or detecting when an external condition clears. Used together with low-to-high interrupts, the two transition types give full visibility into both edges of a signal, which is useful for measuring pulse widths or tracking state changes.
|
Note
|
The five threshold-based types (BIT, overcurrent, maximum-high, minimum-low, and mid-range) are unique to DSW modules and are not available on standard DT or TTL discrete modules. If you are migrating from a DT interrupt sample, be aware that DSW requires configuring and clearing additional status types. Consult your DSW module’s manual for the specific threshold voltage values, programmable ranges, and register addresses. |
Interrupt Configuration
The configureDSWToInterrupt() function in nai_dsw_int.c sets up the module registers before interrupt generation is enabled. The configuration sequence follows the same pattern as other discrete interrupt samples but must account for the DSW module’s larger set of status types.
Step 1: Disable Interrupts Before Reconfiguring
Always disable interrupts before changing configuration to avoid spurious interrupts during setup. The function begins by calling enableDSWInterrupts(inputDSWConfig, FALSE), which iterates over every channel and disables all interrupt status types.
enableDSWInterrupts(inputDSWConfig, FALSE);
Step 2: Clear All Status Registers
Stale latched status from a previous run will trigger an immediate interrupt if not cleared. The pattern is: read the current status, then write back the value to clear it. The sample clears the low-to-high and high-to-low transition status types. In your own application, you should clear all seven latched status types to prevent any stale condition from generating a spurious interrupt.
/* Clear the Interrupt Status (Read the status and write back "1" to statuses which are set to clear the status) */
check_status(naibrd_DSW_GetGroupStatusRaw(cardIndex, module, 1, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, &rawstatus));
check_status(naibrd_DSW_ClearGroupStatusRaw(cardIndex, module, 1, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, rawstatus));
check_status(naibrd_DSW_GetGroupStatusRaw(cardIndex, module, 1, NAI_DSW_STATUS_HI_LO_TRANS_LATCHED, &rawstatus));
check_status(naibrd_DSW_ClearGroupStatusRaw(cardIndex, module, 1, NAI_DSW_STATUS_HI_LO_TRANS_LATCHED, rawstatus));
To clear all seven status types in your own application, repeat the read-and-clear pattern for each latched type:
/* Clear all 7 latched status types */
nai_dsw_status_type_t types[] = {
NAI_DSW_STATUS_BIT_LATCHED,
NAI_DSW_STATUS_OVERCURRENT_LATCHED,
NAI_DSW_STATUS_MAX_HI_LATCHED,
NAI_DSW_STATUS_MIN_LO_LATCHED,
NAI_DSW_STATUS_MID_RANGE_LATCHED,
NAI_DSW_STATUS_LO_HI_TRANS_LATCHED,
NAI_DSW_STATUS_HI_LO_TRANS_LATCHED
};
for (int i = 0; i < 7; i++)
{
check_status(naibrd_DSW_GetGroupStatusRaw(cardIndex, module, 1, types[i], &rawstatus));
check_status(naibrd_DSW_ClearGroupStatusRaw(cardIndex, module, 1, types[i], rawstatus));
}
Step 3: Set Interrupt Vectors
The vector identifies which interrupt source generated the event. The sample assigns separate vectors for low-to-high and high-to-low transitions (NAI_DSW_LOHI_INTERRUPT_VECTOR = 0x10 and NAI_DSW_HILO_INTERRUPT_VECTOR = 0x20) so the ISR can distinguish which transition type fired without reading the status register. If you enable additional status types, assign vectors for each one so your handler can quickly identify the source.
/* Setup the Interrupt Vector - map to the same vector */
check_status(naibrd_DSW_SetGroupInterruptVector(cardIndex, module, 1, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, NAI_DSW_LOHI_INTERRUPT_VECTOR));
check_status(naibrd_DSW_SetGroupInterruptVector(cardIndex, module, 1, NAI_DSW_STATUS_HI_LO_TRANS_LATCHED, NAI_DSW_HILO_INTERRUPT_VECTOR));
Step 4: Set Trigger Mode
The trigger mode is set per-channel for each status type. The user’s selection (interrupt_Edge_Trigger) determines whether the interrupt fires once on the transition into the latched state (edge-triggered, NAI_DSW_EDGE_INTERRUPT = 0) or continues to assert as long as the condition remains active (level-triggered, NAI_DSW_LEVEL_INTERRUPT = 1). The sample configures both transition types for every channel. For detailed theory on edge vs. level triggering, see the Interrupts API Guide.
for (chan = 1; chan <= inputDSWConfig.maxChannel; chan++)
{
check_status(naibrd_DSW_SetEdgeLevelInterrupt(cardIndex, module, chan, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, (nai_dsw_interrupt_t)interrupt_Edge_Trigger));
check_status(naibrd_DSW_SetEdgeLevelInterrupt(cardIndex, module, chan, NAI_DSW_STATUS_HI_LO_TRANS_LATCHED, (nai_dsw_interrupt_t)interrupt_Edge_Trigger));
}
Note the per-channel loop: unlike vector and steering (which are set per-group), the trigger mode must be configured individually for each channel. In your own application, extend this loop to cover all seven status types if you enable threshold-based interrupts.
Step 5: Set Interrupt Steering
Interrupt steering determines how the interrupt signal is delivered from the module to your application. The sample sets the steering mode for both transition types based on the user’s selection.
check_status(naibrd_DSW_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, steering));
check_status(naibrd_DSW_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DSW_STATUS_HI_LO_TRANS_LATCHED, steering));
The steering options are the same as for other discrete modules:
-
Onboard (
NAIBRD_INT_STEERING_ON_BOARD_0) — handled locally on the board’s processor. -
PCIe offboard (
NAIBRD_INT_STEERING_PCIE_APP) — routes the interrupt to the PCIe host. -
cPCI offboard (
NAIBRD_INT_STEERING_CPCI_APP) — routes the interrupt to the CompactPCI backplane host.
Make sure the steering mode you select here matches the IRQ ID used in naibrd_InstallISR(). A mismatch will silently prevent interrupts from reaching your ISR.
Enable Interrupts
The enableDSWInterrupts() function enables or disables interrupt generation for every channel across the configured status types:
void enableDSWInterrupts(DswConfig inputDSWConfig, bool_t enable) {
int32_t channel;
for (channel = inputDSWConfig.minChannel; channel <= inputDSWConfig.maxChannel; channel++)
{
check_status(naibrd_DSW_SetInterruptEnable(inputDSWConfig.cardIndex, inputDSWConfig.module, channel, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, enable));
check_status(naibrd_DSW_SetInterruptEnable(inputDSWConfig.cardIndex, inputDSWConfig.module, channel, NAI_DSW_STATUS_HI_LO_TRANS_LATCHED, enable));
}
}
The sample enables only low-to-high and high-to-low transition interrupts. To enable all seven status types in your own application, add naibrd_DSW_SetInterruptEnable() calls for each additional type (NAI_DSW_STATUS_BIT_LATCHED, NAI_DSW_STATUS_OVERCURRENT_LATCHED, NAI_DSW_STATUS_MAX_HI_LATCHED, NAI_DSW_STATUS_MIN_LO_LATCHED, NAI_DSW_STATUS_MID_RANGE_LATCHED) inside the channel loop.
|
Important
|
Common interrupt configuration errors:
|
Interrupt Handler
The DSW Interrupt Basic sample uses a simplified interrupt handling approach compared to the full DT Interrupt sample. It installs a minimal ISR that sets a flag, then polls for that flag in a user-driven loop.
ISR
The basic_ISR_DSW() function is the Interrupt Service Routine registered with naibrd_InstallISR(). It performs the minimum work required inside an ISR context: setting a flag and capturing the interrupt vector.
#if defined (__VXWORKS__)
void basic_ISR_DSW(uint32_t param)
#else
void basic_ISR_DSW(void *param, uint32_t vector)
#endif
{
#if defined (WIN32)
UNREFERENCED_PARAMETER(param);
#endif
interruptOccured = TRUE;
#if defined (__VXWORKS__)
interruptVector = nai_Onboard_GetInterruptVector();
nai_Onboard_ClearInterrupt();
#else
interruptVector = vector;
#endif
}
The ISR sets the global interruptOccured flag to TRUE and captures the vector that identifies which status type triggered the interrupt. On VxWorks, the vector must be read explicitly via nai_Onboard_GetInterruptVector() and the interrupt must be cleared within the ISR context. On other platforms, the vector is passed as a parameter by the interrupt dispatch infrastructure.
Interrupt Polling Loop
The checkForDSWInterrupt() function provides a user-driven polling loop. Each time the user presses Enter, the function checks whether the ISR has set the interruptOccured flag. If an interrupt has occurred, it reads and displays the low-to-high transition status register, then optionally clears it at the user’s request.
bool_t checkForDSWInterrupt(DswConfig inputDSWConfig) {
bool_t bQuit;
int32_t cardIndex;
int32_t module;
uint32_t rawstatus = 0;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
cardIndex = inputDSWConfig.cardIndex;
module = inputDSWConfig.module;
bQuit = FALSE;
interruptOccured = FALSE;
while (!bQuit) {
printf("\nPress enter to check if Lo-Hi interrupt Occurred (press Q to quit):");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit) {
if (interruptOccured) {
check_status(naibrd_DSW_GetGroupStatusRaw(cardIndex, module, 1, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, &rawstatus));
printf("\nVector = %#x \n", interruptVector);
printf("Status = %#x \n", rawstatus);
interruptOccured = FALSE;
}
else {
printf("\nNo Interrupt Occurred");
}
printf("\n\nWould you like to clear the status register? (default:N):");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (inputBuffer[0] == 'y' || inputBuffer[0] == 'Y')
{
check_status(naibrd_DSW_ClearGroupStatusRaw(cardIndex, module, 1, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, rawstatus));
}
}
}
return bQuit;
}
The polling loop is a sample convenience for interactive demonstration. In your own application, you would typically handle the interrupt in a background thread or callback rather than polling. The key operations are the same regardless of approach:
-
Detect that an interrupt occurred (via the ISR flag, a thread signal, or a callback invocation).
-
Read the status register(s) to determine which channels fired and for which status type.
-
Process the event in your application logic.
-
Clear the status register to re-arm the interrupt for the next event.
If you are monitoring all seven DSW status types, your handler must check each one. The sample only checks NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, but a comprehensive handler would iterate over all seven latched types:
/* Check all 7 latched status types */
nai_dsw_status_type_t types[] = {
NAI_DSW_STATUS_BIT_LATCHED,
NAI_DSW_STATUS_OVERCURRENT_LATCHED,
NAI_DSW_STATUS_MAX_HI_LATCHED,
NAI_DSW_STATUS_MIN_LO_LATCHED,
NAI_DSW_STATUS_MID_RANGE_LATCHED,
NAI_DSW_STATUS_LO_HI_TRANS_LATCHED,
NAI_DSW_STATUS_HI_LO_TRANS_LATCHED
};
for (int i = 0; i < 7; i++)
{
check_status(naibrd_DSW_GetGroupStatusRaw(cardIndex, module, 1, types[i], &rawstatus));
if (rawstatus != 0)
{
/* Report which channels fired for this status type */
printf("DSW Status Type %d: 0x%08X\n", types[i], rawstatus);
/* Clear to re-arm */
check_status(naibrd_DSW_ClearGroupStatusRaw(cardIndex, module, 1, types[i], rawstatus));
}
}
This iteration pattern — looping over all seven status types, reading each, reporting non-zero results, and clearing — is the recommended approach for any DSW interrupt handler that monitors multiple status types. Compare this with the DT interrupt handler, which only needs to iterate over four types.
Orchestration in Run_DSW_Interrupt_Basic
The Run_DSW_Interrupt_Basic() function ties the full interrupt lifecycle together in a linear sequence:
static bool_t Run_DSW_Interrupt_Basic()
{
bool_t bQuit = FALSE;
/* Query user for RX channel */
inputDSWConfig.maxChannel = naibrd_DSW_GetChannelCount(inputDSWConfig.modid);
inputDSWConfig.minChannel = 1;
if(!bQuit)
{
bQuit = GetIntSteeringTypeFromUser(&inputInterruptConfig.steering);
}
if (!bQuit)
{
/**** 2. Implement Bus Interrupt Handling****/
setIRQ(inputInterruptConfig.steering,&inputInterruptConfig.irq);
naibrd_InstallISR(inputDSWConfig.cardIndex,inputInterruptConfig.irq, basic_ISR_DSW,NULL);
/****3. configure Module to perform interrupts****/
configureDSWToInterrupt(inputInterruptConfig,inputDSWConfig);
enableDSWInterrupts(inputDSWConfig,TRUE);
/****5. Show Interrupt Handling (contains step 6)****/
bQuit = checkForDSWInterrupt(inputDSWConfig);
/*****7. Clear Module Configurations*****/
enableDSWInterrupts(inputDSWConfig,FALSE);
/*****8. Clear Board Configurations *****/
check_status(naibrd_UninstallISR(inputDSWConfig.cardIndex));
}
return bQuit;
}
The sequence is: determine channel count, query steering, map steering to IRQ, install ISR, configure module registers, enable interrupts, poll for events, then clean up by disabling interrupts and uninstalling the ISR. In your own application, follow this same order — the configuration must complete before enabling, and cleanup must disable before uninstalling.
|
Important
|
Common interrupt handling errors:
|
Troubleshooting Reference
This table summarizes common errors and symptoms covered in the sections above. For detailed context, refer to the relevant section. Consult your module’s manual for hardware-specific diagnostic procedures.
Debugging Interrupts That Are Not Firing
When interrupts are not being delivered, use this two-step approach to isolate the problem:
-
Check whether the status registers are changing. Call
naibrd_DSW_GetGroupStatusRaw()to read the latched status registers for the interrupt type you expect. If the status bits are changing when the hardware condition occurs, the module is detecting the event correctly — the issue is in your interrupt delivery path (steering, ISR installation, or enable state). -
If the status registers are NOT changing, the issue is at the hardware or channel configuration level. Verify that the correct channel is configured, the physical signal is actually present at the input, and (for threshold types) that the threshold values are programmed correctly. You can also read the status registers directly at their register addresses to bypass the API layer entirely. Consult your module’s manual for the specific register addresses for each status type.
| Error / Symptom | Possible Causes | Suggested Resolution |
|---|---|---|
No board found or connection timeout |
Board not powered, incorrect or missing configuration file, network issue |
Verify hardware is powered and connected. If the configuration file exists, check that it lists the correct interface and address. If it does not exist, the board menu will appear — configure and save your connection settings. |
Module not detected or not recognized as DSW |
No DSW module installed at the selected slot, incorrect module number, or a non-DSW module is present |
Verify hardware configuration. |
ISR installation failure |
Steering mode does not match hardware configuration, driver not loaded, or bus access issue |
Verify steering mode matches your bus architecture. On Linux, check that the NAI driver is loaded. On Windows, verify the device appears in Device Manager. |
Interrupts not firing after enable |
Status registers not cleared before enabling, wrong steering mode, ISR not installed |
Follow the full setup sequence: disable, clear status, configure vectors/triggers/steering, install ISR, enable. See the debugging technique above. |
Wrong steering mode |
Using onboard steering from an external host, or offboard steering from the onboard processor |
Match steering to where your application executes. Onboard: |
Threshold interrupts fire unexpectedly |
Threshold values not programmed — default values may not match your signal levels |
Program the upper and lower thresholds via the DSW configuration API before enabling threshold-based interrupts. Use the DSW BasicOps guide for threshold configuration details. Consult the module manual for default threshold values. |
Threshold interrupts never fire |
Thresholds set outside the range of your input signal, or threshold status types not enabled |
Verify that threshold values bracket your expected signal range. Confirm that the specific threshold status type is enabled, has a vector assigned, and has steering configured. |
Overcurrent interrupt firing |
Channel sourcing or sinking more current than rated limit — possible short circuit or heavy load |
Check external wiring for shorts. Verify load impedance is within the module’s rated output current. Consult the module manual for per-channel current limits. |
BIT interrupt firing |
Internal self-test detected an anomaly — possible open input, stuck output, or reference failure |
Read the BIT status register to identify the affected channel. Check wiring and external connections. If the channel is genuinely faulty, replace the module or route to a spare channel. |
Transition interrupts not firing |
Channel configured as output (transitions are detected on inputs), or no signal transitions present at the input |
Verify the channel is configured as an input. Confirm that the external signal is actually transitioning. Read the real-time status register to see the current input state. |
Mid-range status fires continuously |
Input voltage lingering in the indeterminate zone between lower and upper thresholds |
This indicates the input signal is not reaching a valid logic level. Check for noise, improper termination, or insufficient drive strength. Widen the threshold gap if the signal characteristics require it. |
Interrupts stop after first event (edge-triggered) |
Status not cleared in handler — edge interrupts require clearing to re-arm |
Ensure |
Interrupts fire continuously (level-triggered) |
The underlying condition persists — this is expected for level-triggered interrupts |
Switch to edge triggering if continuous firing is not desired, or address the underlying hardware condition. |
Status registers not changing (debugging) |
Channel not configured correctly, trigger mode mismatch, no physical signal present, thresholds not programmed |
Verify channel configuration, trigger mode, threshold values, and that the expected signal is present at the input. Read registers directly — consult module manual for addresses. |
Full Source
The complete source for this sample is provided below for reference. The sections above explain each part in detail. This sample consists of two source files: the application entry point and the shared interrupt configuration and handling code.
Full Source — DSW_Interrupt_Basic.c (SSK 1.x)
/**************************************************************************************************************/
/**
<summary>
The DSW_Interrupt_Basic program demonstrates how to perform an interrupt when a single channel receives
a message. The purpose of this program is to demonstrate the method calls in the naibrd library for performing
the interrupt. More information on this process can be found in the naibrd SSK Quick Guide(Interrupts) file.
</summary>
*/
/**************************************************************************************************************/
/************************/
/************************/
/* Include Declarations */
/************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/*Common Module Specific Sample Program include files*/
#include "nai_dsw_cfg.h"
#include "nai_dsw_int.h"
/* Common Sample Program include files */
#include "include/naiapp_interrupt.h"
#include "include/naiapp_interrupt_ether.h"
#include "include/naiapp_boardaccess_menu.h"
#include "include/naiapp_boardaccess_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "include/naiapp_boardaccess_display.h"
#include "include/naiapp_boardaccess_utils.h"
/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
/* Module Specific NAI Board Library files */
#include "functions/naibrd_dsw.h"
/* Extern Functions or Variables*/
extern InterruptConfig inputInterruptConfig;
extern DswConfig inputDSWConfig;
/*********************************************/
/* Application Name and Revision Declaration */
/*********************************************/
static const int8_t *CONFIG_FILE = (int8_t *)"default_DSW_Interrupt_Basic.txt";
/********************************/
/* Internal Function Prototypes */
/********************************/
static bool_t Run_DSW_Interrupt_Basic();
/**************************************************************************************************************/
/***** Main Routine *****/
/**************************************************************************************************************/
/**************************************************************************************************************/
/**
<summary>
The main routine assists in gaining access to the board.
The following routines from the nai_sys_cfg.c file are
called to assist with accessing and configuring the board.
- ConfigDevice
- DisplayDeviceCfg
- GetBoardSNModCfg
- CheckModule
</summary>
*/
/*****************************************************************************/
#if defined (__VXWORKS__)
int32_t DSW_Interrupt_Basic(void)
#else
int32_t main(void)
#endif
{
bool_t stop = FALSE;
int32_t cardIndex;
int32_t moduleCnt;
int32_t module;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
initializeDSWConfigurations(0, 0, 0, 0, 0, 0);
initializeInterruptConfigurations(FALSE, FALSE, FALSE, 0, 0, 0, 0);
if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
{
while (stop != TRUE)
{
/* Query the user for the card index */
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
inputDSWConfig.cardIndex = cardIndex;
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
/* Query the user for the module number */
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
inputDSWConfig.module = module;
if (stop != TRUE)
{
inputDSWConfig.modid = naibrd_GetModuleID(cardIndex, module);
if ((inputDSWConfig.modid != 0))
{
Run_DSW_Interrupt_Basic();
}
}
}
printf("\nType Q to quit or Enter key to restart application:\n");
stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
}
}
printf("\nType the Enter key to exit the program: ");
naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
naiapp_access_CloseAllOpenCards();
return 0;
}
/**************************************************************************************************************/
/**
<summary>
This function is broken into the following major steps. These steps correspond with the steps provided
in the naibrd SSK Quick Guide(Interrupts) file.
2. Bus Interrupt Handling - Install ISR
API CALLS - naibrd_InstallISR
3. Enable Module Interrupts- Configures module to interrupt when channel receives DSW message.
API CALLS - naibrd_DSW_SetInterruptEdgeLevel, naibrd_DSW_SetIntVector, naibrd_DSW_SetInterruptSteering, naibrd_DSW_SetIntEnable
4. Not applicable to DSW module
5. Show Interrupt Handling - Check if any interrupt has occurred and report back the status and vector
6. Re-arming Interrupts - Clear the status register to allow interrupts to occur again. This is done by writing to the status register.
In this program, we use an API call to do this.
API CALLS - naibrd_DSW_ClearStatusRaw
7. Clear Module Configurations
8. Clear Board Configurations
API CALLS - naibrd_UninstallISR
</summary>
*/
/**************************************************************************************************************/
static bool_t Run_DSW_Interrupt_Basic()
{
bool_t bQuit = FALSE;
/* Query user for RX channel */
inputDSWConfig.maxChannel = naibrd_DSW_GetChannelCount(inputDSWConfig.modid);
inputDSWConfig.minChannel = 1;
if(!bQuit)
{
bQuit = GetIntSteeringTypeFromUser(&inputInterruptConfig.steering);
}
if (!bQuit)
{
/**** 2. Implement Bus Interrupt Handling****/
setIRQ(inputInterruptConfig.steering,&inputInterruptConfig.irq);
naibrd_InstallISR(inputDSWConfig.cardIndex,inputInterruptConfig.irq, basic_ISR_DSW,NULL);
/****3. configure Module to perform interrupts****/
configureDSWToInterrupt(inputInterruptConfig,inputDSWConfig);
enableDSWInterrupts(inputDSWConfig,TRUE);
/****5. Show Interrupt Handling (contains step 6)****/
bQuit = checkForDSWInterrupt(inputDSWConfig);
/*****7. Clear Module Configurations*****/
enableDSWInterrupts(inputDSWConfig,FALSE);
/*****8. Clear Board Configurations *****/
check_status(naibrd_UninstallISR(inputDSWConfig.cardIndex));
}
return bQuit;
}
Full Source — nai_dsw_int.c (SSK 1.x)
/* Common Sample Program include files */
#include "include/naiapp_interrupt.h"
#include "include/naiapp_interrupt_ether.h"
#include "include/naiapp_boardaccess_menu.h"
#include "include/naiapp_boardaccess_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "include/naiapp_boardaccess_display.h"
#include "include/naiapp_boardaccess_utils.h"
/* Common DSW Sample Program include files */
#include "nai_dsw_int.h"
#include "nai_dsw_cfg.h"
/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
#include "naibrd_ether.h"
#include "functions/naibrd_dsw.h"
#include "maps/nai_map_dsw.h"
#include <stdlib.h>
bool_t interruptOccured; /* used by checkForInterrupt to see if interrupt occurred */
int32_t frameCount; /* counter increment when frames are found */
uint32_t interruptVector; /* used by checkForInterrupt to get vector of the interrupt that occurred in myIsr */
InterruptConfig inputInterruptConfig;
/* Extern Functions or Variables*/
extern DswConfig inputDSWConfig;
/**************************************************************************************************************/
/**
<summary>
This function configures an interrupt to occur when a message is received on any of the dsw channels.
</summary>
*/
/**************************************************************************************************************/
void configureDSWToInterrupt(InterruptConfig inputInterruptConfig, DswConfig inputDSWConfig)
{
int32_t cardIndex = inputDSWConfig.cardIndex;
int32_t module = inputDSWConfig.module;
int32_t interrupt_Edge_Trigger = inputInterruptConfig.interrupt_Edge_Trigger;
int32_t steering = inputInterruptConfig.steering;
uint32_t rawstatus = 0;
int32_t chan;
enableDSWInterrupts(inputDSWConfig, FALSE);
/* Clear the Interrupt Status (Read the status and write back "1" to statuses which are set to clear the status) */
check_status(naibrd_DSW_GetGroupStatusRaw(cardIndex, module, 1, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, &rawstatus));
check_status(naibrd_DSW_ClearGroupStatusRaw(cardIndex, module, 1, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, rawstatus));
check_status(naibrd_DSW_GetGroupStatusRaw(cardIndex, module, 1, NAI_DSW_STATUS_HI_LO_TRANS_LATCHED, &rawstatus));
check_status(naibrd_DSW_ClearGroupStatusRaw(cardIndex, module, 1, NAI_DSW_STATUS_HI_LO_TRANS_LATCHED, rawstatus));
/* Setup the Interrupt Vector - map to the same vector */
check_status(naibrd_DSW_SetGroupInterruptVector(cardIndex, module, 1, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, NAI_DSW_LOHI_INTERRUPT_VECTOR));
check_status(naibrd_DSW_SetGroupInterruptVector(cardIndex, module, 1, NAI_DSW_STATUS_HI_LO_TRANS_LATCHED, NAI_DSW_HILO_INTERRUPT_VECTOR));
/* Setup the Latched Status Mode */
for (chan = 1; chan <= inputDSWConfig.maxChannel; chan++)
{
check_status(naibrd_DSW_SetEdgeLevelInterrupt(cardIndex, module, chan, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, (nai_dsw_interrupt_t)interrupt_Edge_Trigger));
check_status(naibrd_DSW_SetEdgeLevelInterrupt(cardIndex, module, chan, NAI_DSW_STATUS_HI_LO_TRANS_LATCHED, (nai_dsw_interrupt_t)interrupt_Edge_Trigger));
}
check_status(naibrd_DSW_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, steering));
check_status(naibrd_DSW_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DSW_STATUS_HI_LO_TRANS_LATCHED, steering));
}
/**************************************************************************************************************/
/**
<summary>
Enables the channels within the (minChannel,maxChannel) range to interrupt
if enable is true and disables them otherwise.
</summary>
*/
/**************************************************************************************************************/
void enableDSWInterrupts(DswConfig inputDSWConfig, bool_t enable) {
int32_t channel;
for (channel = inputDSWConfig.minChannel; channel <= inputDSWConfig.maxChannel; channel++)
{
check_status(naibrd_DSW_SetInterruptEnable(inputDSWConfig.cardIndex, inputDSWConfig.module, channel, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, enable));
check_status(naibrd_DSW_SetInterruptEnable(inputDSWConfig.cardIndex, inputDSWConfig.module, channel, NAI_DSW_STATUS_HI_LO_TRANS_LATCHED, enable));
}
}
/**************************************************************************************************************/
/**
<summary>
The routine is called to handle a interrupt. This function alerts checkForInterrupt that an interrupt has occurred.
In vxWorks you must clear the Interrupt on the board within the ISR.
</summary>
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
void basic_ISR_DSW(uint32_t param)
#else
void basic_ISR_DSW(void *param, uint32_t vector)
#endif
{
#if defined (WIN32)
UNREFERENCED_PARAMETER(param);
#endif
interruptOccured = TRUE;
#if defined (__VXWORKS__)
interruptVector = nai_Onboard_GetInterruptVector();
nai_Onboard_ClearInterrupt();
#else
interruptVector = vector;
#endif
}
/**************************************************************************************************************/
/**
<summary>
Prompts user to check if an interrupt has occurred. MyIsr() should be installed if using this function.
</summary>
*/
/**************************************************************************************************************/
bool_t checkForDSWInterrupt(DswConfig inputDSWConfig) {
bool_t bQuit;
int32_t cardIndex;
int32_t module;
uint32_t rawstatus = 0;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
cardIndex = inputDSWConfig.cardIndex;
module = inputDSWConfig.module;
bQuit = FALSE;
interruptOccured = FALSE;
while (!bQuit) {
printf("\nPress enter to check if Lo-Hi interrupt Occurred (press Q to quit):");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit) {
if (interruptOccured) {
check_status(naibrd_DSW_GetGroupStatusRaw(cardIndex, module, 1, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, &rawstatus));
printf("\nVector = %#x \n", interruptVector);
printf("Status = %#x \n", rawstatus);
interruptOccured = FALSE;
}
else {
printf("\nNo Interrupt Occurred");
}
printf("\n\nWould you like to clear the status register? (default:N):");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (inputBuffer[0] == 'y' || inputBuffer[0] == 'Y')
{
check_status(naibrd_DSW_ClearGroupStatusRaw(cardIndex, module, 1, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, rawstatus));
}
}
}
return bQuit;
}
/**************************************************************************************************************/
/**
<summary>
GetDSWLatchStatusTriggerMode handles prompting the user for the trigger mode for the latched status register
(Edge Triggered or Level Triggered).
</summary>
*/
/**************************************************************************************************************/
bool_t GetDSWLatchStatusTriggerMode(int32_t* interrupt_Edge_Trigger)
{
bool_t bQuit;
uint32_t temp;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
printf("\nEnter Latched Status Trigger Mode (Edge=0, Level=1) (Default=0): ");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt > 0)
{
temp = (int32_t)atol((const char*)inputBuffer);
if (temp == 0 || temp == 1)
{
*interrupt_Edge_Trigger = temp;
}
else
{
printf("ERROR: Invalid Interrupt Trigger Mode.\n");
}
}
else
*interrupt_Edge_Trigger = 0;
}
return(bQuit);
}
/**************************************************************************************************************/
/**
<summary>
This routine takes in the vector of the DSW RX interrupt that has just occurred. And gets the status, fifo status,
and fifo data of all channels that interrupted, and prints it.
</summary>
*/
/**************************************************************************************************************/
void handleDSWInterrupt(uint32_t nVector) {
uint32_t rawstatus = 0;
printf("\n\nInterrupt Occurred \n\n");
if (inputInterruptConfig.bPromptForInterruptClear)
{
promptUserToClearInterrupt_DSW();
}
check_status(naibrd_DSW_GetGroupStatusRaw(inputDSWConfig.cardIndex, inputDSWConfig.module, 1, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, &rawstatus));
check_status(naibrd_DSW_ClearGroupStatusRaw(inputDSWConfig.cardIndex, inputDSWConfig.module, 1, NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, rawstatus));
printInterruptInformation_DSW(nVector, rawstatus, FALSE);
}
void promptUserToClearInterrupt_DSW()
{
/* Prompt the user to clear the interrupt received */
SetUserRequestClearInt(FALSE);
printf("\n");
DisplayMessage_DSWInterrupt(MSG_USER_CLEAR_DSW_INT);
/* Wait for the user to respond */
while (!GetUserRequestClearInt())
{
nai_msDelay(10);
}
}
/**************************************************************************************************************/
/**
<summary>
DisplayMessage_DSWInterrupt handles displaying the messages associated with the msgId passed in.
</summary>
*/
/**************************************************************************************************************/
void DisplayMessage_DSWInterrupt(int32_t msgId)
{
switch (msgId)
{
case (int32_t)MSG_BANNER_DSW_INT:
{
printf("\n********************************************************************************");
printf("\n****** DSW INTERRUPT ******");
printf("\nAn interrupt will occur when the DSW Module receives a Lo-Hi transition status ");
printf("\n********************************************************************************");
}
break;
case (int32_t)MSG_USER_TRIGGER_DSW_INT:
{
printf("\nPress \"Q\" to quit the application.\nPlease trigger DSW Lo-Hi status interrupt (Recv Msg):");
}
break;
case (int32_t)MSG_USER_CLEAR_DSW_INT:
{
printf("Press \"C\" to clear interrupts... ");
}
break;
}
}
/**************************************************************************************************************/
/**
<summary>
Function will print the Data provided for each channel that has been set in the status register.
It will also print the status and idr id or vector.
</summary>
*/
/**************************************************************************************************************/
void printInterruptInformation_DSW(int32_t interruptID, uint32_t status, bool_t isEther)
{
printf("Interrupt Information\n");
printf("-----------------------------------\n");
if (isEther)
printf("\nIDR ID = %#x \n", interruptID);
else
printf("\nVector = %#x \n", interruptID);
printf("Status = %#x \n", status);
printf("\nFrames Rx = %d", frameCount);
printf("\n-----------------------------------\n");
}