Integrator Resources

The official home for NAI Support

Not sure where to start? Try Quick Start Guide or ask a question below!

Toggle Components with Visual Button
JavaScript Form Processing

PT MB Interrupts

PT MB Interrupts Sample Application (SSK 2.x)

Overview

The PT MB Interrupts sample application demonstrates how to configure and handle hardware interrupts on pulse timer (PT) modules using the NAI Software Support Kit (SSK 2.x). Unlike the typical interrupt samples that use naibrd_ConnectISR(), this sample uses a specialized pulse timer ISR connection function (naibrd_Connect_PulseTimer_ISR()) to register a callback that fires on each pulse timer interrupt event. The callback captures the interrupt vector along with a high-resolution timestamp, making this sample well-suited for measuring interrupt latency and pulse timing accuracy.

This sample supports the PT1 module type. It configures a single channel for single-ended input and waits for pulse timer interrupt events on that channel. This pattern is new to SSK 2.x and has no SSK 1.x counterpart.

Note
This sample requires the NAIBSP_SYS_CONFIG_PULSETIMER BSP configuration flag to be enabled (set to 1). If this flag is not set, the pulse timer ISR connection and disconnection calls are compiled out. This sample is primarily designed for Petalinux on ARM-based platforms.

Prerequisites

Before running this sample, make sure you have:

  • An NAI board with a PT1 module installed.

  • SSK 2.x installed on your development host.

  • The sample applications built with NAIBSP_SYS_CONFIG_PULSETIMER enabled. Refer to the SSK 2.x Software Development Guide for platform-specific build instructions.

  • A platform that supports pulse timer interrupts (Petalinux).

  • An external pulse source connected to the configured channel, or another module providing a pulse output.

How to Run

Launch the pt_mb_interrupts executable from your build output directory. On startup the application looks for a configuration file (default_PT1_Interrupt.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. Once connected, select a channel. The application configures the channel for single-ended input, connects the pulse timer ISR, and waits for interrupt events. Each interrupt prints the count, timestamp, and vector to the console.

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 PT.

The main() function follows a standard SSK 2.x startup flow:

  1. Call naiapp_RunBoardMenu() to load a saved configuration file (if one exists) or present the interactive board menu. The configuration file (default_PT1_Interrupt.txt) is not included with the SSK — it is created when the user saves their connection settings from the board menu.

  2. Query the user for a card index with naiapp_query_CardIndex().

  3. Query for a module slot with naiapp_query_ModuleNumber().

  4. Retrieve the module ID with naibrd_GetModuleName().

  5. Query for a channel number with naiapp_query_ChannelNumber().

#if defined (NAIBSP_CONFIG_SOFTWARE_OS_VXWORKS)
int32_t PT_MB_Interrupt(void)
#else
int32_t main(void)
#endif
{
   int32_t cardIndex;
   int32_t module;
   int32_t channel;
   int32_t moduleCnt;
   uint32_t moduleID;
   int32_t MaxChannel = 0;
   bool_t stop = NAI_FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   if (naiapp_RunBoardMenu(DEF_CONFIG_FILE) == (bool_t)NAI_TRUE)
   {
      while (stop != NAI_TRUE)
      {
         stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(),
            DEF_NIU3A_CARD_INDEX, &cardIndex);
         if (stop != NAI_TRUE)
         {
            check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
            check_status(naiapp_query_ModuleNumber(moduleCnt,
               DEF_PT1_MODULE, &module));
            if (stop != NAI_TRUE)
            {
               check_status(naibrd_GetModuleName(cardIndex, module, &moduleID));
               if ((moduleID != 0))
               {
                  MaxChannel = naibrd_PT_GetChannelCount(moduleID);
                  stop = naiapp_query_ChannelNumber(MaxChannel,
                     DEF_PT1_CHANNEL, &channel);
                  check_status(naibrd_PT_SetInputFormat(cardIndex, module,
                     channel, NAIBRD_PT_INPUTFORMAT_SINGLEENDED_ENABLED));
#if (NAIBSP_SYS_CONFIG_PULSETIMER == 1u)
                  naibrd_Connect_PulseTimer_ISR(cardIndex, SampleCallBack);
#endif
                  naiif_printf("\r\nType Q to quit or Enter to continue:\r\n");
                  stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer),
                     NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
               }
            }
         }
      }
#if (NAIBSP_SYS_CONFIG_PULSETIMER == 1u)
      naibrd_Disconnect_PulseTimer_ISR(cardIndex);
#endif
   }

   naiapp_access_CloseAllOpenCards();
   return 0;
}

Note the SSK 2.x differences from SSK 1.x in this startup sequence:

  • The VxWorks preprocessor guard uses NAIBSP_CONFIG_SOFTWARE_OS_VXWORKS (SSK 1.x uses __VXWORKS__).

  • The module identifier is retrieved with naibrd_GetModuleName() (SSK 1.x uses naibrd_GetModuleID()).

  • Boolean constants are NAI_TRUE / NAI_FALSE (SSK 1.x uses TRUE / FALSE).

  • Console output uses naiif_printf() from the platform abstraction layer (SSK 1.x uses printf() directly).

Important

Common connection errors you may encounter at this stage:

  • No board found — verify that the board is powered on and physically connected.

  • Connection timeout — confirm network settings or bus configuration.

  • Invalid card or module index — indices are zero-based for cards and one-based for modules.

  • Module not present at selected slot — the slot you selected does not contain a PT1 module.

Program Structure

Entry Point

On standard platforms (Petalinux) the entry point is main(). On VxWorks the entry point is PT_MB_Interrupt(). Unlike most interrupt samples, this application does not use a command menu loop. Instead, the flow is linear:

  1. Connect to the board and select card, module, and channel.

  2. Configure the channel input format to single-ended.

  3. Connect the pulse timer ISR.

  4. Wait for the user to quit.

  5. Disconnect the pulse timer ISR and close all boards.

Channel Configuration

The channel is configured for single-ended input using naibrd_PT_SetInputFormat():

check_status(naibrd_PT_SetInputFormat(cardIndex, module, channel,
   NAIBRD_PT_INPUTFORMAT_SINGLEENDED_ENABLED));

This enables the channel to receive external pulse signals. Additional pulse timer configuration (frequency, period, edge type) should be set using the PT basic ops sample or the API directly before running this sample.

Pulse Timer ISR Connection

This sample uses a specialized ISR connection function specific to pulse timer modules, rather than the general naibrd_ConnectISR():

#if (NAIBSP_SYS_CONFIG_PULSETIMER == 1u)
naibrd_Connect_PulseTimer_ISR(cardIndex, SampleCallBack);
#endif
  • naibrd_Connect_PulseTimer_ISR() — registers the callback for pulse timer interrupt events on the specified card. This function is only available when NAIBSP_SYS_CONFIG_PULSETIMER is set to 1 in the BSP configuration.

  • The callback signature is the same as for naibrd_ConnectISR(): void callback(uint32_t vector).

Disconnecting the ISR

When the user quits, the pulse timer ISR is disconnected:

#if (NAIBSP_SYS_CONFIG_PULSETIMER == 1u)
naibrd_Disconnect_PulseTimer_ISR(cardIndex);
#endif

ISR Callback

The ISR callback captures the interrupt vector, increments a counter, and records a high-resolution timestamp using clock_gettime():

static void SampleCallBack(uint32_t vector)
{
   receivedVector = vector;
   irqCount++;
   clock_gettime(CLOCK_REALTIME, &ts0);
   naiif_printf("%d, timestamp=%lld, %ld, VECTOR=%X\n",
      irqCount, ts0.tv_sec, ts0.tv_nsec, vector);
}
  • irqCount — tracks the total number of interrupts received.

  • clock_gettime(CLOCK_REALTIME, &ts0) — captures nanosecond-precision wall-clock time at the point the ISR executes. This is useful for measuring interrupt latency and pulse interval accuracy.

  • Vector — the interrupt vector value, defined in the PT1 BSP configuration as a four-character code (0x50543120 for 'PT1 ').

Note
Calling naiif_printf() from an ISR is done here for demonstration purposes only. In production code, set a flag and defer printing to a task-level handler.

Troubleshooting Reference

This table summarizes common errors and symptoms. Consult the PT1 Manual for hardware-specific diagnostic procedures.

Error / Symptom Possible Causes Suggested Resolution

No board found or connection timeout

Board not powered, incorrect configuration file, network issue

Verify hardware is powered and connected. Check that default_PT1_Interrupt.txt has correct settings.

Module not detected at selected slot

No module installed at the specified slot

Verify the slot contains a PT1 module

ISR connection call does not exist / compile error

NAIBSP_SYS_CONFIG_PULSETIMER not enabled in BSP

Set NAIBSP_SYS_CONFIG_PULSETIMER to 1 in the BSP configuration and rebuild

No interrupts received

No pulse signal applied to the channel, or channel not configured

Verify an external pulse source is connected. Configure pulse timer parameters (frequency, edge type) using the PT basic ops sample before running this sample.

Timestamps show irregular intervals

Interrupt latency variation, system load

Ensure the system is not under heavy load. Check that the pulse source frequency is within the module’s supported range (less than 500 Hz for the interrupt path).

ISR fires but vector is unexpected

Multiple interrupt sources or BSP misconfiguration

Verify the PT1 interrupt vector matches the expected four-character code in the BSP configuration

Full Source

The complete source for this sample is provided below for reference. The sections above explain each part in detail.

Full Source — pt_mb_interrupt.c (SSK 2.x)
/* nailib include files */
#include "nai_libs/nailib/include/naitypes.h"
#include "nai_libs/nailib/include/nailib.h"
#include "nai_libs/nailib/include/nailib_utils.h"

/* naibrd include files */
#include "nai_libs/naibrd/include/naibrd.h"
#include "nai_libs/naibrd/include/functions/naibrd_pt_config.h"

#include "nai_libs/naibrd/src/maps/nai_map_mod_common.h"
#include "nai_libs/naibrd/include/functions/naibrd_pt.h"
#include "nai_libs/naibrd/src/maps/nai_map_pt.h"
#include "nai_libs/naibrd/src/include_local/naibrd_local.h"

#include "naibsp_sys/include/naibsp_sys_pulsetimer.h"

/* naiif include files */
#include "nai_libs/naiif/include/naiif_stdio.h"

/* Common Sample Program include files */
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_menu.h"
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_query.h"
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_access.h"
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_display.h"
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_utils.h"

/* Common Sample Program include files */
#include "nai_sample_apps/naiapp_common/src/include_local/naiapp_boardaccess_query_local.h"
#include "nai_sample_apps/naiapp_common/src/include_local/naiapp_boardaccess_access_local.h"
#include "nai_sample_apps/naiapp_common/src/include_local/naiapp_boardaccess_display_local.h"
#include "nai_sample_apps/naiapp_common/src/include_local/naiapp_boardaccess_utils_local.h"



static const int8_t *DEF_CONFIG_FILE = (const int8_t *)"default_PT1_Interrupt.txt";
static const int32_t DEF_NIU3A_CARD_INDEX  = 0;
static const int32_t DEF_PT1_MODULE        = 2;
static const int32_t DEF_PT1_CHANNEL       = 1;   /* PT1 interrupt on CHANNEL 1 */

/* Function prototypes */
static void SampleCallBack(uint32_t vector);

static int32_t irqCount=0;
static uint32_t receivedVector=0;
static struct timespec ts0;

/**************************************************************************************************************/
/** \ingroup PT1Interrupts
The callback function that is installed via naibrd_ConnectISR(). This function will be called when the PT1
interrupt is received. Prints out that the interrupt has been received.
\param vector (Input) Interrupt vector to identify which channel caused the interrupt.
For PT1, the Interrupt Vector is defined as PT1_INTERRUPT_VECTOR.
*/
/**************************************************************************************************************/
static void SampleCallBack(uint32_t vector)
{
   receivedVector = vector;
   irqCount++;
   clock_gettime(CLOCK_REALTIME, &ts0);
   naiif_printf("%d, timestamp=%lld, %ld, VECTOR=%X\n", irqCount, ts0.tv_sec, ts0.tv_nsec, vector);
}
//static int32_t Run_PT_BasicInterrupt(int32_t cardIndex, int32_t module, uint32_t moduleID, int32_t channel);

/**************************************************************************************************************/
/**
\ingroup PT1_Interrupt Test
 * <summary>
 * The purpose of the pt1 interrupt example is to illustrate the methods to call in the naibrd library to
 * install pt1 interrupt callback routine to service pt1 interrupt in user application.
 *
 * NIU3C PT1 interrupt Properties		: (Use NIU3A )
 * PT1 Module Slot                      : 2
 * PT1 Channel with Interrupt Trigger:  : 1
 * PT1 GIC IRQ number                   : 142
 * PT1 interrupt Name                   : fpga_irq_pt
 * PT1 IRQ Input Trigger                : < 500 Hz
 * PT1 interrupt Trigger                : Rising Edge
 * PT1 input device                     : /dev/input/event1
 * PT1 IRQ Event type                   : EV_MSC (4)
 * PT1 IRQ Event Code                   : EV_PT1 (3)
 * PT1 interrupt Vector                 : 0x50543120     //FOUR_CHAR_CODE('P', 'T', '1', ' ')
 *
 * Refer naiapp_mod_pt_basic_ops sample for setting PT1 Interrupt hardware configurations
 * </summary>
</returns>
  - NAI_SUCCESS
 */
/**************************************************************************************************************/
#if defined (NAIBSP_CONFIG_SOFTWARE_OS_VXWORKS)
int32_t PT_MB_Interrupt(void)
#else
int32_t main(void)
#endif
{
   int32_t cardIndex;
   int32_t module;
   int32_t channel;
   int32_t moduleCnt;
   uint32_t moduleID;
   int32_t MaxChannel=0;
   bool_t stop = NAI_FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   if (naiapp_RunBoardMenu(DEF_CONFIG_FILE) == (bool_t)NAI_TRUE)
   {
      while (stop != NAI_TRUE)
      {
         /* Select Card Index */
         stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), DEF_NIU3A_CARD_INDEX, &cardIndex);
         if (stop != NAI_TRUE)
         {
            check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));

            /* Select Module */
            check_status(naiapp_query_ModuleNumber(moduleCnt, DEF_PT1_MODULE, &module));
            if (stop != NAI_TRUE)
            {
               check_status(naibrd_GetModuleName(cardIndex, module, &moduleID));
               if ((moduleID != 0))
               {
            	  MaxChannel=naibrd_PT_GetChannelCount(moduleID);
            	  stop = naiapp_query_ChannelNumber(MaxChannel, DEF_PT1_CHANNEL, &channel);
            	  check_status(naibrd_PT_SetInputFormat(cardIndex, module, channel, NAIBRD_PT_INPUTFORMAT_SINGLEENDED_ENABLED));
#if (NAIBSP_SYS_CONFIG_PULSETIMER == 1u)
            	  naibrd_Connect_PulseTimer_ISR(cardIndex, SampleCallBack);
#endif   /* NAIBSP_SYS_CONFIG_PULSETIMER */
            	  naiif_printf("\r\nType Q to quit or Enter to continue:\r\n");
                  stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
               }
            }
         }
      }
#if (NAIBSP_SYS_CONFIG_PULSETIMER == 1u)
      naibrd_Disconnect_PulseTimer_ISR(cardIndex);
#endif   /* NAIBSP_SYS_CONFIG_PULSETIMER */
   }

   naiif_printf("\r\nType the Enter key to exit the program: ");
   naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   naiapp_access_CloseAllOpenCards();

   return 0;
}

Help Bot

X