PT MB Interrupts
Edit this on GitLab
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_PULSETIMERenabled. 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:
-
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. -
Query the user for a card index with
naiapp_query_CardIndex(). -
Query for a module slot with
naiapp_query_ModuleNumber(). -
Retrieve the module ID with
naibrd_GetModuleName(). -
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 usesnaibrd_GetModuleID()). -
Boolean constants are
NAI_TRUE/NAI_FALSE(SSK 1.x usesTRUE/FALSE). -
Console output uses
naiif_printf()from the platform abstraction layer (SSK 1.x usesprintf()directly).
|
Important
|
Common connection errors you may encounter at this stage:
|
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:
-
Connect to the board and select card, module, and channel.
-
Configure the channel input format to single-ended.
-
Connect the pulse timer ISR.
-
Wait for the user to quit.
-
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 whenNAIBSP_SYS_CONFIG_PULSETIMERis set to1in the BSP configuration. -
The callback signature is the same as for
naibrd_ConnectISR():void callback(uint32_t vector).
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 (
0x50543120for '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 |
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 |
|
Set |
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;
}