RTD Interrupt Basic
Edit this on GitLab
RTD Interrupt Basic Sample Application (SSK 1.x)
Overview
The RTD Interrupt Basic sample application demonstrates how to configure RTD (Resistance Temperature Detector) module interrupts to detect temperature-related events using the NAI Software Support Kit (SSK 1.x). RTD interrupts monitor BIT failures, open sensor connections, and temperature threshold crossings at two severity levels (alert and alarm). This dual-level threshold system enables pre-warning before critical temperatures are reached, making RTD interrupts uniquely suited to thermal monitoring applications where graduated response is essential.
Unlike discrete or analog modules that monitor electrical signal transitions, the RTD module’s interrupt system is built around temperature measurement. The seven interrupt status types reflect real-world thermal conditions: sensor health (BIT and open-detect), and four directional threshold crossings organized into alert (early warning) and alarm (critical action) levels. This architecture lets you implement graduated thermal protection — taking preventive action at the alert level and emergency action at the alarm level — without polling.
This sample supports the following RTD module types: G4 (Gen3), RT1, TR1, and TC1 (Gen5).
For background on RTD channel configuration, wire modes, and threshold settings, see the RTD_BasicOps Sample Application guide. For general interrupt concepts — including edge vs. level triggering, interrupt vector numbering, and steering architecture — see the Interrupts API Guide. This guide focuses on how those concepts apply specifically to RTD temperature interrupts.
Prerequisites
Before running this sample, make sure you have:
-
An NAI board with an RTD module installed (G4, RT1, TR1, or TC1).
-
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.
-
Temperature thresholds configured appropriately for your expected temperature range. See the RTD_BasicOps Sample Application guide for threshold configuration details.
How to Run
Launch the RTD_Interrupt_Basic executable from your build output directory. On startup the application looks for a configuration file (default_RTD_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 a channel number and interrupt steering mode, then configures the module 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 RTD. |
The main() function (named RTD_Interrupt_Basic() on VxWorks) follows a standard SSK 1.x startup flow:
-
Call
initializeRTDConfigurations()andinitializeInterruptConfigurations()to zero out the configuration structures. -
Call
naiapp_RunBoardMenu()to load a saved configuration file (if one exists) or present the interactive board menu. The configuration file (default_RTD_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 a card index and module number.
-
Retrieve the module ID with
naibrd_GetModuleID()and proceed to interrupt configuration.
#if defined (__VXWORKS__)
int32_t RTD_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;
initializeRTDConfigurations(0, 0, 0, 0, 0, 0);
initializeInterruptConfigurations(FALSE, FALSE, FALSE, 0, 0, 0, 0);
if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
{
while (stop != TRUE)
{
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
inputRTDConfig.cardIndex = cardIndex;
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
inputRTDConfig.module = module;
if (stop != TRUE)
{
inputRTDConfig.modid = naibrd_GetModuleID(cardIndex, module);
if ((inputRTDConfig.modid != 0))
{
Run_RTD_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 RTD Interrupt Basic sample is split across two source files:
-
RTD_Interrupt_Basic.c— the main entry point. Handles board connection, user prompts for channel and steering selection, and orchestrates the interrupt lifecycle (install ISR, configure, enable, monitor, disable, uninstall). -
nai_rtd_int.c— shared RTD interrupt utilities. Contains the ISR (basic_ISR_RTD()), the module configuration function (configureRTDToInterruptOnRx()), the enable/disable function (enableRTDInterrupts()), and the interrupt polling loop (checkForRTDInterrupt()).
The entry point is main() (or RTD_Interrupt_Basic() on VxWorks). After the board connection is established, Run_RTD_Interrupt_Basic() executes a linear flow:
-
Query the user for a channel number and interrupt steering mode.
-
Install the ISR via
naibrd_InstallISR(). -
Configure the module for interrupts via
configureRTDToInterruptOnRx(). -
Enable interrupts via
enableRTDInterrupts(). -
Enter the polling loop via
checkForRTDInterrupt()— wait for interrupts, report status, and optionally clear. -
On exit: disable interrupts and uninstall the ISR.
static bool_t Run_RTD_Interrupt_Basic()
{
bool_t bQuit = FALSE;
/* Query user for channel */
if (!bQuit)
{
inputRTDConfig.maxChannel = naibrd_RTD_GetChannelCount( inputRTDConfig.modid );
inputRTDConfig.minChannel = NAI_RTD_MIN_CHANNEL;
printf( "\nWhich channel would you like to Receive on? \n" );
bQuit = naiapp_query_ChannelNumber( inputRTDConfig.maxChannel, inputRTDConfig.minChannel, &inputRTDConfig.channel );
}
if (!bQuit)
{
bQuit = GetIntSteeringTypeFromUser( &inputInterruptConfig.steering );
}
if (!bQuit)
{
/**** 2. Implement Bus Interrupt Handling ****/
setIRQ( inputInterruptConfig.steering, &inputInterruptConfig.irq );
naibrd_InstallISR( inputRTDConfig.cardIndex, inputInterruptConfig.irq, basic_ISR_RTD, NULL );
/**** 3. configure Module to perform interrupts ****/
configureRTDToInterruptOnRx( inputInterruptConfig, inputRTDConfig );
enableRTDInterrupts( inputRTDConfig, TRUE );
/**** 5. Show Interrupt Handling ****/
bQuit = checkForRTDInterrupt( inputRTDConfig );
/***** 7. Clear Module Configurations *****/
enableRTDInterrupts( inputRTDConfig, FALSE );
/***** 8. Clear Board Configurations *****/
check_status( naibrd_UninstallISR( inputRTDConfig.cardIndex ) );
}
return bQuit;
}
The menu system is a sample convenience — in your own code, call these API functions directly in the same sequence.
Interrupt Status Types
The RTD module exposes seven distinct interrupt status types. Each type monitors a different temperature-related condition and has both a real-time register (reflecting the current instantaneous state) and a latched register (capturing events that have occurred since the last clear). The interrupt system uses the latched registers — once a condition is detected, the latched bit remains set until your software explicitly clears it, ensuring no events are missed.
BIT (Built-In Test)
NAI_RTD_STATUS_BIT_LATCHED
The module’s internal self-test has detected an accuracy anomaly on a channel. The RTD module contains a precision 100-ohm nominal resistor on each measurement path. The BIT circuitry periodically measures this reference resistor and compares the result against the expected value. When the measured value deviates beyond the acceptable tolerance, the BIT status latches, indicating that the A/D converter’s measurement accuracy may be degraded.
Enable BIT interrupts for health monitoring and safety-critical applications where measurement integrity must be continuously validated. A BIT failure does not necessarily mean the temperature reading is wrong — it means the measurement path can no longer be trusted to meet its specified accuracy. In deployed systems, a BIT interrupt should trigger a diagnostic sequence or failover to a redundant measurement channel.
Open (Sensor Disconnection)
NAI_RTD_STATUS_OPEN_LATCHED
A sensor wire break or disconnection has been detected. The RTD module injects a small background current (0.5 microamps) through the sensor wiring. When the sensor is properly connected, this current flows through the resistance element and produces a measurable voltage. When the sensor wire is broken or disconnected, the current path is interrupted and the voltage reading shifts to an out-of-range value, triggering the open-detect status.
This is the most common real-world interrupt source for RTD modules. In deployed systems where sensor cables may run through harsh environments — subject to vibration, thermal cycling, or physical damage — open-detect interrupts provide immediate notification of sensor loss. Without open-detect, a disconnected sensor could produce readings that appear valid but are actually measuring the open-circuit characteristics of the wiring rather than the actual temperature.
Enable open-detect interrupts whenever sensor cable integrity is critical to your application. Note that wire resistance very close to the open-detect threshold can cause intermittent false triggers, particularly in long cable runs. See the Troubleshooting Reference section for guidance on managing open-detect sensitivity.
Alert Low (Lower Alert Threshold)
NAI_RTD_STATUS_ALERT_LO_LATCHED
The measured temperature has dropped below the lower alert threshold. This is the first-level warning for low-temperature conditions. The alert threshold represents the boundary where operator attention is warranted but the system can continue operating safely.
Alarm Low (Lower Alarm Threshold)
NAI_RTD_STATUS_ALARM_LO_LATCHED
The measured temperature has dropped below the lower alarm threshold. This is the second-level critical warning for low-temperature conditions. The alarm threshold represents the boundary where the temperature has reached a critical level and immediate action is required — such as activating heaters, shutting down equipment, or alerting safety systems.
Alert High (Upper Alert Threshold)
NAI_RTD_STATUS_ALERT_HI_LATCHED
The measured temperature has exceeded the upper alert threshold. This is the first-level warning for high-temperature conditions, analogous to the alert low threshold on the high side. When this interrupt fires, the temperature is above normal operating range but has not yet reached the critical alarm level.
Alarm High (Upper Alarm Threshold)
NAI_RTD_STATUS_ALARM_HI_LATCHED
The measured temperature has exceeded the upper alarm threshold. This is the second-level critical warning for high-temperature conditions. Like alarm low, this represents a condition requiring immediate action — activating cooling systems, reducing power, or initiating an emergency shutdown sequence.
Summary
NAI_RTD_STATUS_SUMMARY_LATCHED
A logical OR of all the above status types. The summary status latches if any individual condition (BIT, open, alert low, alarm low, alert high, or alarm high) is active on any channel. This provides a single register you can check to determine whether any interrupt condition exists on the module without reading all seven individual status types.
Enable the summary interrupt when you want a single notification that "something happened" on the RTD module, then read the individual status types inside your handler to determine the specific cause. This reduces the number of interrupt vectors you need to manage while still providing full visibility.
Dual-Level Threshold Architecture
The four threshold interrupts (alert low, alarm low, alert high, alarm high) form a dual-level monitoring architecture that is unique to temperature measurement modules. No other NAI module type provides this two-tier threshold system.
The design philosophy is:
-
Alert = early warning. The temperature has left the normal operating range but is not yet dangerous. Your application should log the event, notify an operator, or begin preparatory action (pre-warming, pre-cooling, load reduction). Alert thresholds give you time to respond before the situation becomes critical.
-
Alarm = critical condition. The temperature has reached a level where continued operation may cause damage, safety hazards, or specification violations. Your application should take immediate protective action: engage backup cooling/heating, reduce power output, or initiate a controlled shutdown.
The gap between the alert and alarm thresholds defines your response window. A wider gap gives more time to react but triggers the alert earlier (potentially during normal transient conditions). A narrower gap provides less warning time but avoids nuisance alerts. The optimal gap depends on the thermal dynamics of your system — how quickly temperature can change and how long corrective action takes to have effect.
To configure the actual threshold values, use naibrd_RTD_SetAlertLoThreshold(), naibrd_RTD_SetAlarmLoThreshold(), naibrd_RTD_SetAlertHiThreshold(), and naibrd_RTD_SetAlarmHiThreshold(). See the RTD_BasicOps Sample Application guide for threshold configuration details, and consult your module’s manual (particularly the RT1 manual) for supported temperature ranges and resolution.
Interrupt Configuration
The configureRTDToInterruptOnRx() function in nai_rtd_int.c configures the RTD module to generate interrupts. The sample configures only the open-detect latched status type (NAI_RTD_STATUS_OPEN_LATCHED) for demonstration. In your own application, repeat the same pattern for each of the seven status types you need to monitor.
The configuration follows four steps in sequence: disable and clear, set vector, set trigger mode, and set steering. Note that this function uses the "raw" register access variants of the API (naibrd_RTD_SetInterruptEnableRaw() and naibrd_RTD_ClearStatusRaw()) which operate on all channels simultaneously through a bitmask rather than configuring one channel at a time.
Step 1: Disable Interrupts and Clear Status
Always disable interrupts and clear stale status before reconfiguring. Stale latched status from a previous run will trigger an immediate interrupt if not cleared.
nai_rtd_status_type_t typeOpen = NAI_RTD_STATUS_OPEN_LATCHED;
/* clear interruptConfigs of previous channels */
check_status( naibrd_RTD_SetInterruptEnableRaw( cardIndex, module, typeOpen, 0 ) );
check_status( naibrd_RTD_ClearStatusRaw( cardIndex, module, typeOpen, 0xFFFF ) );
naibrd_RTD_SetInterruptEnableRaw() writes a raw bitmask to the interrupt enable register. Passing 0 disables all channels for the specified status type. naibrd_RTD_ClearStatusRaw() writes 0xFFFF to clear all latched status bits regardless of which channels had events.
To configure all seven status types in your own application, repeat this disable-and-clear sequence for each: NAI_RTD_STATUS_BIT_LATCHED, NAI_RTD_STATUS_OPEN_LATCHED, NAI_RTD_STATUS_ALERT_LO_LATCHED, NAI_RTD_STATUS_ALARM_LO_LATCHED, NAI_RTD_STATUS_ALERT_HI_LATCHED, NAI_RTD_STATUS_ALARM_HI_LATCHED, and NAI_RTD_STATUS_SUMMARY_LATCHED.
Step 2: Set Interrupt Vector
The vector identifies which interrupt source generated the event when the ISR fires.
check_status( naibrd_RTD_SetInterruptVector( cardIndex, module, typeOpen, vector ) );
The sample assigns NAI_RTD_INTERRUPT_VECTOR to the open-detect status type. If you enable multiple status types and want to distinguish them inside your ISR without reading status registers, assign a different vector to each type. If you prefer a single ISR that reads all status registers on every interrupt, you can use the same vector for all types.
Step 3: Set Trigger Mode
The trigger mode is set per-channel. The sample iterates over all channels and configures level-triggered mode:
nai_rtd_interrupt_t interrupt_Level_Trigger = NAI_RTD_LEVEL_INTERRUPT;
maxChan = naibrd_RTD_GetChannelCount( inputRTDConfig.modid );
for ( channel = 1; channel <= maxChan; channel++ )
{
check_status( naibrd_RTD_SetInterruptEdgeLevel( cardIndex, module, channel, typeOpen, interrupt_Level_Trigger ) );
}
Level-triggered mode means the interrupt continues to assert as long as the condition remains active. For open-detect, this means the interrupt will keep firing as long as the sensor remains disconnected. Edge-triggered mode fires once when the condition is first detected and will not fire again until the status is cleared and the condition re-occurs. For most RTD applications, level-triggered mode is appropriate because temperature conditions tend to persist and you want continuous notification until the condition is resolved. For detailed theory on edge vs. level triggering, see the Interrupts API Guide.
Step 4: Set Interrupt Steering
Interrupt steering determines how the interrupt signal is delivered from the module to your application:
check_status( naibrd_RTD_SetInterruptSteering( cardIndex, module, typeOpen, steering ) );
The steering value is selected by the user at runtime via GetIntSteeringTypeFromUser(). The available steering options are the same as for other module types: onboard (NAIBRD_INT_STEERING_ON_BOARD_0), cPCI offboard (NAIBRD_INT_STEERING_CPCI_APP), PCIe offboard (NAIBRD_INT_STEERING_PCIE_APP), or Ethernet (NAIBRD_INT_STEERING_ON_BOARD_1). Make sure your steering selection matches the physical bus connection and the IRQ ID used in naibrd_InstallISR().
Enabling Interrupts
After configuration, enableRTDInterrupts() turns on interrupt generation by building a channel bitmask and writing it with naibrd_RTD_SetInterruptEnableRaw():
void enableRTDInterrupts( RtdConfig inputRTDConfig, bool_t enable )
{
int32_t channel;
nai_rtd_status_type_t typeOpen = NAI_RTD_STATUS_OPEN_LATCHED;
int32_t enableRegVal = 0;
int32_t isEnabled = 0;
for ( channel = inputRTDConfig.minChannel; channel <= inputRTDConfig.maxChannel; channel++ )
{
isEnabled = ( ( 1 << ( channel-1 ) ) & enableRegVal );
if (enable)
enableRegVal = ( 1 << ( channel-1 ) ) | enableRegVal;
else if ( isEnabled )
enableRegVal = ( 1 << ( channel-1 ) ) ^ enableRegVal;
}
check_status( naibrd_RTD_SetInterruptEnableRaw( inputRTDConfig.cardIndex, inputRTDConfig.module, typeOpen, enableRegVal ) );
}
The function constructs a bitmask where each bit corresponds to a channel (bit 0 = channel 1, bit 1 = channel 2, etc.). When enable is TRUE, bits for all channels in the configured range are set. When FALSE, they are cleared. The raw bitmask is written to the enable register in a single call, which is more efficient than enabling channels individually.
|
Important
|
Common interrupt configuration errors:
|
Interrupt Handler
The interrupt handling in this sample uses two functions: basic_ISR_RTD() (the ISR that fires on each interrupt) and checkForRTDInterrupt() (a polling loop that checks whether the ISR has fired and reports the results).
ISR: basic_ISR_RTD()
The ISR is intentionally minimal. It sets a flag, captures the interrupt vector, and returns. All substantive work — reading status registers, reporting results, clearing status — happens outside the ISR context in checkForRTDInterrupt().
#if defined (__VXWORKS__)
void basic_ISR_RTD( uint32_t param )
#else
void basic_ISR_RTD( void *param, uint32_t vector )
#endif
{
interruptOccurred = TRUE;
#if defined (__VXWORKS__)
interruptVectorOpen = nai_Onboard_GetInterruptVector();
nai_Onboard_ClearInterrupt();
#else
interruptVectorOpen = vector;
#endif
}
On VxWorks, the ISR must explicitly read the vector with nai_Onboard_GetInterruptVector() and clear the board-level interrupt with nai_Onboard_ClearInterrupt() before returning. On other platforms, the vector is passed as a parameter by the SSK’s interrupt dispatch layer. The interruptOccurred and interruptVectorOpen global variables communicate the event to the polling loop.
Polling Loop: checkForRTDInterrupt()
After the ISR is installed and interrupts are enabled, the application enters checkForRTDInterrupt(). This function polls the interruptOccurred flag each time the user presses Enter, reads the latched status register, reports the vector and status, and optionally clears the status to re-arm the interrupt.
bool_t checkForRTDInterrupt( RtdConfig inputRTDConfig )
{
bool_t bQuit;
uint32_t statusOpen;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
statusOpen = 0;
bQuit = FALSE;
interruptOccurred = FALSE;
while (!bQuit)
{
printf( "\nPress enter to check if interrupt Occurred (press Q to quit):" );
bQuit = naiapp_query_ForQuitResponse( sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt );
if (!bQuit)
{
if (interruptOccurred)
{
check_status( naibrd_RTD_GetStatusRaw( inputRTDConfig.cardIndex, inputRTDConfig.module, NAI_RTD_STATUS_OPEN_LATCHED, &statusOpen ) );
printf( "\nOpen Vector = %#x \n", interruptVectorOpen );
printf( "Open Status = %#x \n", statusOpen );
interruptOccurred = FALSE;
}
else
{
printf( "\nNo Interrupt Occurred" );
}
printf( "\n\nWould you like to clear the status registers? (default:N):" );
bQuit = naiapp_query_ForQuitResponse( sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt );
if ( inputBuffer[0] == 'y' || inputBuffer[0] =='Y' )
{
check_status( naibrd_RTD_ClearStatusRaw( inputRTDConfig.cardIndex, inputRTDConfig.module, NAI_RTD_STATUS_OPEN_LATCHED, statusOpen ) );
}
}
}
return bQuit;
}
The handler reads NAI_RTD_STATUS_OPEN_LATCHED because that is the only status type configured by the sample. In your own application, to check all seven status types, iterate over each type and read its status register:
/* Example: checking all seven RTD interrupt status types */
nai_rtd_status_type_t types[] = {
NAI_RTD_STATUS_BIT_LATCHED,
NAI_RTD_STATUS_OPEN_LATCHED,
NAI_RTD_STATUS_ALERT_LO_LATCHED,
NAI_RTD_STATUS_ALARM_LO_LATCHED,
NAI_RTD_STATUS_ALERT_HI_LATCHED,
NAI_RTD_STATUS_ALARM_HI_LATCHED,
NAI_RTD_STATUS_SUMMARY_LATCHED
};
uint32_t status;
int i;
for (i = 0; i < 7; i++)
{
naibrd_RTD_GetStatusRaw( cardIndex, module, types[i], &status );
if (status != 0)
{
/* Handle the interrupt for this status type */
printf( "Status type %d fired: 0x%08X\n", types[i], status );
naibrd_RTD_ClearStatusRaw( cardIndex, module, types[i], status );
}
}
Open-detect and threshold alerts are the most common real-world interrupt sources. BIT interrupts indicate measurement hardware degradation and are typically rare. Summary interrupts are useful as a single "any condition active" check when you want to minimize the number of register reads in normal (no-interrupt) operation.
After reading and reporting the status, clearing the latched register with naibrd_RTD_ClearStatusRaw() is essential to re-arm the interrupt. For edge-triggered interrupts, failing to clear means no new edge can be generated and the interrupt will never fire again. For level-triggered interrupts, failing to clear means the interrupt will continue to assert continuously (which may be the desired behavior for persistent fault conditions).
|
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.
For RTD interrupts, the most common issues are open-detect false triggers (caused by wire resistance too close to the threshold) and threshold alerts firing immediately after configuration (thresholds not set to appropriate values for the expected temperature range). Both of these are configuration issues rather than hardware failures, and both can be resolved without code changes.
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_RTD_GetStatusRaw()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 mask). -
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 wire mode matches your sensor wiring (2-wire, 3-wire, or 4-wire), and the physical sensor is actually connected and within measurement range. 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 RTD |
No RTD module installed at the selected slot, incorrect module number, or a non-RTD 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. |
Open-detect false positives (intermittent open interrupts with sensor connected) |
Wire resistance close to the open-detect threshold, long cable runs with high resistance, or poor terminal connections |
Check total loop resistance including cable and connections. Clean and re-seat terminal connections. For long cable runs, consider using lower-resistance cable or switching to 4-wire mode to eliminate lead resistance effects. Consult your module’s manual for the open-detect threshold value. |
Threshold alerts fire immediately after enable |
Alert or alarm threshold values do not bracket the current ambient temperature (e.g., alert high set below room temperature) |
Read the current temperature with |
BIT interrupt fires on startup |
Module self-test detected measurement path degradation, or stale BIT status was not cleared before enabling interrupts |
Clear all status registers before enabling interrupts. If BIT continues to fire after clearing, the measurement path may have a genuine accuracy issue — consult the module manual for diagnostic procedures. |
Wrong wire mode affecting measurements and thresholds |
Module configured for a different wire mode than the physical sensor wiring (e.g., 2-wire mode with a 4-wire sensor) |
Verify the wire mode matches your physical wiring. Incorrect wire mode causes measurement errors that can trigger false threshold crossings. See RTD_BasicOps for wire mode configuration. |
Background operation suspended (open-detect stops working) |
Module’s background measurement cycle has been disrupted by a configuration change or power event |
Re-read the channel configuration and verify the module is actively measuring. The 0.5 microamp background current injection that enables open-detect only runs during active measurement cycles. |
Steering mismatch (interrupts configured but never arrive) |
Steering mode set to onboard but application runs offboard (or vice versa), or steering set to Ethernet but no IDR configured |
Match steering to where your application executes. Onboard: |
Only open-detect interrupts work (other types silent) |
Only |
Repeat the full configuration sequence (disable, clear, set vector, set trigger mode, set steering, enable) for each additional status type you want to monitor. |
ISR fires but checkForRTDInterrupt shows "No Interrupt Occurred" |
The |
In production applications, use an interrupt count or queue rather than a boolean flag. The boolean approach in this sample can miss interrupts that occur between user key presses. |
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 main application and shared RTD interrupt utilities.
Full Source — RTD_Interrupt_Basic.c (SSK 1.x)
/**************************************************************************************************************/
/**
<summary>
The RTD_Interrupt_Basic program demonstrates how to check for RTD Open interrupts via PCI Bus Connection
to the board. 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_rtd_int.h"
#include "nai_rtd_cfg.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_rtd.h"
#define NAI_RTD_MIN_CHANNEL 1
InterruptConfig inputInterruptConfig;
/* Extern Functions or Variables*/
extern RtdConfig inputRTDConfig;
/*********************************************/
/* Application Name and Revision Declaration */
/*********************************************/
static const int8_t *CONFIG_FILE = (int8_t *)"default_RTD_Interrupt_Basic.txt";
/********************************/
/* Internal Function Prototypes */
/********************************/
static bool_t Run_RTD_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 RTD_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;
initializeRTDConfigurations(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);
inputRTDConfig.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);
inputRTDConfig.module = module;
if (stop != TRUE)
{
inputRTDConfig.modid = naibrd_GetModuleID(cardIndex, module);
if ((inputRTDConfig.modid != 0))
{
Run_RTD_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 RTD open latched status of channel is set to 1.
API CALLS - naibrd_RTD_SetInterruptEdgeLevel, naibrd_RTD_SetInterruptVector, naibrd_RTD_SetInterruptSteering,
naibrd_RTD_SetInterruptEnableRaw, naibrd_RTD_ClearStatusRaw
4. Nothing needs to be done for the RTD 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_RTD_ClearStatusRaw
7. Clear Module Configurations
API CALLS - naibrd_RTD_SetInterruptEnableRaw
8. Clear Board Configurations
API CALLS - naibrd_UninstallISR
</summary>
*/
/**************************************************************************************************************/
static bool_t Run_RTD_Interrupt_Basic()
{
bool_t bQuit = FALSE;
/* Query user for channel */
if (!bQuit)
{
inputRTDConfig.maxChannel = naibrd_RTD_GetChannelCount( inputRTDConfig.modid );
inputRTDConfig.minChannel = NAI_RTD_MIN_CHANNEL;
printf( "\nWhich channel would you like to Receive on? \n" );
bQuit = naiapp_query_ChannelNumber( inputRTDConfig.maxChannel, inputRTDConfig.minChannel, &inputRTDConfig.channel );
}
/* Query user for location interrupt will be sent out to */
if (!bQuit)
{
bQuit = GetIntSteeringTypeFromUser( &inputInterruptConfig.steering );
}
if (!bQuit)
{
/**** 2. Implement Bus Interrupt Handling ****/
setIRQ( inputInterruptConfig.steering, &inputInterruptConfig.irq );
naibrd_InstallISR( inputRTDConfig.cardIndex, inputInterruptConfig.irq, basic_ISR_RTD, NULL );
/**** 3. configure Module to perform interrupts ****/
configureRTDToInterruptOnRx( inputInterruptConfig, inputRTDConfig );
enableRTDInterrupts( inputRTDConfig,TRUE );
/**** 4. Configure Module to cause Interrupts ****/
/* Nothing needs to be done for the RTD module */
/**** 5. Show Interrupt Handling (check for interrupt/ISR activity and clear statuses: contains step 6) ****/
bQuit = checkForRTDInterrupt( inputRTDConfig );
/***** 7. Clear Module Configurations *****/
enableRTDInterrupts( inputRTDConfig, FALSE );
/***** 8. Clear Board Configurations *****/
check_status( naibrd_UninstallISR( inputRTDConfig.cardIndex ) );
}
return bQuit;
}
Full Source — nai_rtd_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_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "include/naiapp_boardaccess_display.h"
#include "include/naiapp_boardaccess_utils.h"
/* Common RTD Sample Program include files */
#include "nai_rtd_int.h"
#include "nai_rtd_cfg.h"
/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
#include "naibrd_ether.h"
#include "functions/naibrd_rtd.h"
#include "../src/maps/nai_map_rtd.h"
#include <stdlib.h>
bool_t interruptOccurred;
uint32_t interruptVectorOpen;
/* Extern Functions or Variables*/
extern InterruptConfig inputInterruptConfig;
extern RtdConfig inputRTDConfig;
extern FILE* fifoDataFile;
/**************************************************************************************************************/
/**
<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_RTD( uint32_t param )
#else
void basic_ISR_RTD( void *param, uint32_t vector )
#endif
{
interruptOccurred = TRUE;
#if defined (WIN32)
UNREFERENCED_PARAMETER( param );
#endif
#if defined (__VXWORKS__)
interruptVectorOpen = nai_Onboard_GetInterruptVector();
nai_Onboard_ClearInterrupt();
#else
interruptVectorOpen = vector;
#endif
}
/**************************************************************************************************************/
/**
<summary>
This function configures an interrupt to occur when the open latched status of any of the RTD channels is
set to 1.
</summary>
*/
/**************************************************************************************************************/
void configureRTDToInterruptOnRx( InterruptConfig inputInterruptConfig, RtdConfig inputRTDConfig )
{
int32_t channel;
int32_t maxChan;
int32_t cardIndex = inputRTDConfig.cardIndex;
int32_t module = inputRTDConfig.module;
int32_t vector = NAI_RTD_INTERRUPT_VECTOR;
nai_rtd_interrupt_t interrupt_Level_Trigger = NAI_RTD_LEVEL_INTERRUPT;
int32_t steering = inputInterruptConfig.steering;
nai_rtd_status_type_t typeOpen = NAI_RTD_STATUS_OPEN_LATCHED;
/* clear interruptConfigs of previous channels */
check_status( naibrd_RTD_SetInterruptEnableRaw( cardIndex, module, typeOpen, 0 ) );
check_status( naibrd_RTD_ClearStatusRaw( cardIndex, module, typeOpen, 0xFFFF ) );
check_status( naibrd_RTD_SetInterruptVector( cardIndex, module, typeOpen, vector ) );
maxChan = naibrd_RTD_GetChannelCount( inputRTDConfig.modid );
for ( channel = 1; channel <= maxChan; channel++ )
{
check_status( naibrd_RTD_SetInterruptEdgeLevel( cardIndex, module, channel, typeOpen, interrupt_Level_Trigger ) ); /* Level triggered */
}
check_status( naibrd_RTD_SetInterruptSteering( cardIndex, module, typeOpen, steering ) );
}
/**************************************************************************************************************/
/**
<summary>
Enables the channels within the (minChannel, maxChannel) range to interrupt
if enable is true and disables them otherwise.
</summary>
*/
/**************************************************************************************************************/
void enableRTDInterrupts( RtdConfig inputRTDConfig, bool_t enable )
{
int32_t channel;
nai_rtd_status_type_t typeOpen = NAI_RTD_STATUS_OPEN_LATCHED;
int32_t enableRegVal = 0;
int32_t isEnabled = 0;
for ( channel = inputRTDConfig.minChannel; channel <= inputRTDConfig.maxChannel; channel++ )
{
isEnabled = ( ( 1 << ( channel-1 ) ) & enableRegVal );
if (enable)
enableRegVal = ( 1 << ( channel-1 ) ) | enableRegVal;
else if ( isEnabled )
enableRegVal = ( 1 << ( channel-1 ) ) ^ enableRegVal;
}
check_status( naibrd_RTD_SetInterruptEnableRaw( inputRTDConfig.cardIndex, inputRTDConfig.module, typeOpen, enableRegVal ) );
}
/**************************************************************************************************************/
/**
<summary>
Prompts user to check if an interrupt has occurred. MyIsr() should be installed if using this function.
</summary>
*/
/**************************************************************************************************************/
bool_t checkForRTDInterrupt( RtdConfig inputRTDConfig )
{
bool_t bQuit;
uint32_t statusOpen;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
statusOpen = 0;
bQuit = FALSE;
interruptOccurred = FALSE;
while (!bQuit)
{
printf( "\nPress enter to check if interrupt Occurred (press Q to quit):" );
bQuit = naiapp_query_ForQuitResponse( sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt );
if (!bQuit)
{
if (interruptOccurred)
{
check_status( naibrd_RTD_GetStatusRaw( inputRTDConfig.cardIndex, inputRTDConfig.module, NAI_RTD_STATUS_OPEN_LATCHED, &statusOpen ) );
printf( "\nOpen Vector = %#x \n", interruptVectorOpen );
printf( "Open Status = %#x \n", statusOpen );
interruptOccurred = FALSE;
}
else
{
printf( "\nNo Interrupt Occurred" );
}
printf( "\n\nWould you like to clear the status registers? (default:N):" );
bQuit = naiapp_query_ForQuitResponse( sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt );
if ( inputBuffer[0] == 'y' || inputBuffer[0] =='Y' )
{
check_status( naibrd_RTD_ClearStatusRaw( inputRTDConfig.cardIndex, inputRTDConfig.module, NAI_RTD_STATUS_OPEN_LATCHED, statusOpen ) );
}
}
}
return bQuit;
}
/**************************************************************************************************************/
/**
<summary>
GetRTDLatchStatusTriggerMode handles prompting the user for the trigger mode for the latched status register
(Edge Triggered or Level Triggered).
</summary>
*/
/**************************************************************************************************************/
bool_t GetRTDLatchStatusTriggerMode( 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>
DisplayMessage_RTDInterrupt handles displaying the messages associated with the msgId passed in.
</summary>
*/
/**************************************************************************************************************/
void DisplayMessage_RTDInterrupt( int32_t msgId )
{
switch (msgId)
{
case (int32_t)MSG_BANNER_RTD_INT:
{
printf( "\n********************************************************************************" );
printf( "\n****** RTD INTERRUPT ******" );
printf( "\nAn interrupt will occur when one of the interrupt conditions of the RTD module" );
printf( "\nstatuses is met." );
printf( "\n********************************************************************************" );
}
break;
case (int32_t)MSG_USER_CLEAR_RTD_INT:
{
printf( "Press \"C\" to clear interrupts... " );
}
break;
}
}
/**************************************************************************************************************/
/**
<summary>
This routine takes in the vector of the RTD open interrupt that has just occurred. And gets the open latched
status of all channels that interrupted, and prints it.
</summary>
*/
/**************************************************************************************************************/
void handleRTDInterrupt( uint32_t nVector )
{
uint32_t statusOpen;
printf( "\n\nInterrupt Occurred \n\n" );
if ( inputInterruptConfig.bPromptForInterruptClear )
{
promptUserToClearInterrupt_RTD();
}
check_status( naibrd_RTD_GetStatusRaw( inputRTDConfig.cardIndex, inputRTDConfig.module, NAI_RTD_STATUS_OPEN_LATCHED, &statusOpen ) );
check_status( naibrd_RTD_ClearStatusRaw( inputRTDConfig.cardIndex, inputRTDConfig.module, NAI_RTD_STATUS_OPEN_LATCHED, statusOpen ) );
printInterruptInformationToFile( nVector, statusOpen, FALSE, fifoDataFile );
printInterruptInformation_RTD( nVector, statusOpen, FALSE );
}
/**************************************************************************************************************/
/**
<summary>
This function prompts the user to clear the open status latched register upon open interrupt.
</summary>
*/
/**************************************************************************************************************/
void promptUserToClearInterrupt_RTD()
{
/* Prompt the user to clear the interrupt received */
SetUserRequestClearInt( FALSE );
printf( "\n" );
DisplayMessage_RTDInterrupt( MSG_USER_CLEAR_RTD_INT );
/* Wait for the user to respond */
while ( !GetUserRequestClearInt() )
{
nai_msDelay( 10 );
}
}
/**************************************************************************************************************/
/**
<summary>
Function will print the RTD open latched status and idr id or vector to a file.
</summary>
*/
/**************************************************************************************************************/
void printInterruptInformationToFile( int32_t interruptID, uint32_t statusOpen, bool_t isEther, FILE* stream )
{
fprintf( stream, "Interrupt Information\n" );
fprintf( stream, "-----------------------------------\n" );
if (isEther)
fprintf( stream, "\nIDR ID = %#x \n", interruptID );
else
fprintf( stream, "\nVector = %#x \n", interruptID );
fprintf( stream, "Open Status = %#x \n", statusOpen );
}
/**************************************************************************************************************/
/**
<summary>
Function will print the RTD open latched status and idr id or vector.
</summary>
*/
/**************************************************************************************************************/
void printInterruptInformation_RTD( int32_t interruptID, uint32_t statusOpen, bool_t isEther )
{
printf( "Interrupt Information\n" );
printf( "-----------------------------------\n" );
if (isEther)
printf( "\nIDR ID = %#x \n", interruptID );
else
printf( "\nVector = %#x \n", interruptID );
printf( "Open Status = %#x \n", statusOpen );
}
void ClearInterrupt_RTD()
{
uint32_t status;
if (inputInterruptConfig.bPromptForInterruptClear)
{
promptUserToClearInterrupt_RTD();
}
naibrd_RTD_GetStatusRaw( inputRTDConfig.cardIndex, inputRTDConfig.module, NAI_RTD_STATUS_OPEN_LATCHED, &status );
naibrd_RTD_ClearStatusRaw( inputRTDConfig.cardIndex, inputRTDConfig.module, NAI_RTD_STATUS_OPEN_LATCHED, status );
}