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

SER HDLC Loopback

SER HDLC Loopback Sample Application (SSK 2.x)

Overview

The SER HDLC Loopback sample application demonstrates how to configure a serial channel for HDLC (High-level Data Link Control) synchronous communication and run an internal loopback test using the NAI Software Support Kit (SSK 2.x). The application configures a channel for HDLC mode with internal loopback and an internal clock source, writes 10 words to the transmit FIFO, loops them back through the module’s internal path, and reads them back using the HDLC packet receive API. Each received word includes a status indicator that identifies the beginning of frame (BOF) and end of frame (EOF) markers.

This sample supports SER module types that have synchronous serial capability. It excludes the SC3 (with FPGA revision below 1.000) and the CMH, which do not support synchronous serial. Additionally, on the CMR module, only channels 9 and 10 support synchronous mode.

For the SSK 1.x version, see SER HDLC Loopback (SSK 1.x).

Prerequisites

Before running this sample, make sure you have:

  • An NAI board with a SER module installed that supports synchronous serial (not CMH; SC3 requires FPGA Rev 1.000+).

  • SSK 2.x installed on your development host.

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

How to Run

Launch the ser_hdlc_loopback executable from your build output directory. On startup the application looks for a configuration file (default_SER_HDLC_Loopback.txt). Once connected, the application queries for a channel, configures it for HDLC loopback, transmits data, and displays the received HDLC packet with frame markers.

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

The main() function follows a standard SSK 2.x startup flow. After connecting to the board and selecting a module, the application verifies that the module supports synchronous serial:

  • If the module ID is 0, it prints "Invalid Module".

  • If the module is SC3 with FPGA revision below 1.000, it prints that SC3 does not support synchronous serial.

  • If the module is CMH, it prints that CMH does not support synchronous serial.

  • Otherwise, it proceeds with Run_SER_HDLC_LOOPBACK().

check_status(naibrd_GetModuleName(cardIndex, module, &moduleId));
check_status(naibrd_GetModuleFPGARev(cardIndex, module, &fpgaRev));
if (moduleId == 0)
{
   naiif_printf("\r\nInvalid Module\r\n");
}
else if ((moduleId == NAIBRD_MODULE_ID_SC3) && (fpgaRev < NAIBRD_SC3_REV_1_0))
{
   naiif_printf("\r\nSC3 does not support synchronous serial communications.\r\n");
}
else if (moduleId == NAIBRD_MODULE_ID_CMH)
{
   naiif_printf("\r\nCMH does not support synchronous serial communications.\r\n");
}
else
{
   Run_SER_HDLC_LOOPBACK(cardIndex, module, moduleId);
}
Important

Common connection errors you may encounter at this stage:

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

  • SC3 does not support synchronous serial — upgrade the SC3 FPGA to revision 1.000 or later.

  • CMR channel does not support synchronous serial — on the CMR, only channels 9 and 10 support synchronous mode.

Program Structure

Entry Point

The entry point is main() on most platforms, or SER_HDLC_Loopback_Sample() on VxWorks.

Application Flow

  1. Query for a channel number (with a CMR channel restriction check).

  2. Reset the channel and clear FIFOs.

  3. Configure for HDLC mode with internal loopback and internal clock.

  4. Build and transmit a 10-word payload.

  5. Read back the HDLC packet and display with frame markers.

Channel Configuration

The application configures the channel for HDLC synchronous loopback at 115,200 baud:

check_status(naibrd_SER_ChannelReset(cardIndex, module, chanNum));
check_status(naibrd_SER_ClearRxFifo(cardIndex, module, chanNum));
check_status(naibrd_SER_ClearTxFifo(cardIndex, module, chanNum));

check_status(naibrd_SER_SetCommProtocol(cardIndex, module, chanNum, NAIBRD_SER_PROTOCOL_HDLC));
check_status(naibrd_SER_SetInterface(cardIndex, module, chanNum, NAIBRD_SER_INTF_LOOPBACK));
check_status(naibrd_SER_SetSyncClockMode(cardIndex, module, chanNum, NAIBRD_SER_CLOCK_MODE_INTERNAL));
check_status(naibrd_SER_SetBaudrate(cardIndex, module, chanNum, 115200));
check_status(naibrd_SER_SetReceiverEnable(cardIndex, module, chanNum, 1));

naiif_msDelay(100);

Key differences from async configuration:

  • NAIBRD_SER_PROTOCOL_HDLC sets the channel for HDLC synchronous protocol instead of async.

  • naibrd_SER_SetSyncClockMode() configures the clock source. NAIBRD_SER_CLOCK_MODE_INTERNAL means both TX and RX clocks are generated internally.

  • The baud rate is set to 115,200 (higher than the typical 9600 used in async samples).

Data Transmission

The application builds a 10-word payload with incremental values starting at 0x31, loads the FIFO, and initiates transmission:

for (i = 0; i < NUM_DATA_TX; i++)
   SendData[i] = (uint8_t)(i + 0x31);

nNumWordsSend = i;
check_status(naibrd_SER_LoadBufferWithTimeOut32(cardIndex, module, chanNum, SendData, nNumWordsSend, NUM_DATA_TX,
   NAIBRD_FIFO_TIMEOUT_NONE, &nNumWordsRecv));

check_status(naibrd_SER_TransmitInitiate(cardIndex, module, chanNum));

HDLC Packet Reception

After a 500 ms delay, the application reads the received data using the HDLC-specific receive API:

check_status(naibrd_SER_GetRxBufferCnt(cardIndex, module, chanNum, (uint32_t*)&nNumWordsRecv));
check_status(naibrd_SER_ReceiveHDLCPacket(cardIndex, module, chanNum, RecvDataStatus, nNumWordsRecv,
   &nNumWordsRecv, NAIBRD_FIFO_TIMEOUT_NONE));

naibrd_SER_ReceiveHDLCPacket() reads an HDLC packet from the receive FIFO. Unlike the async receive API, this function is aware of HDLC framing and returns a complete packet with frame boundary information.

Each received word contains the data byte in the lower 8 bits and a status byte in the upper 8 bits. The status byte indicates frame boundaries:

  • NAIBRD_SER_SYNC_BOF — Beginning of HDLC frame.

  • NAIBRD_SER_SYNC_EOF — End of HDLC frame.

for (i = 0; i < nNumWordsRecv; i++)
{
   naiif_printf("Sent 0x%02X; Recd 0x%02X, Status= %02X",
      SendData[i], (RecvDataStatus[i] & 0x00FF), (RecvDataStatus[i] >> 8) & 0x00FF);
   if (((RecvDataStatus[i] >> 8) & 0x00FF) == NAIBRD_SER_SYNC_BOF)
   {
      naiif_printf("\tBeginning of HDLC frame (BOF)\r\n");
   }
   else if (((RecvDataStatus[i] >> 8) & 0x00FF) == NAIBRD_SER_SYNC_EOF)
   {
      naiif_printf("\tEnd of HDLC frame (EOF)\r\n");
   }
   else
   {
      naiif_printf("\r\n");
   }
}

Troubleshooting Reference

Error / Symptom Possible Causes Suggested Resolution

SC3 does not support synchronous serial

SC3 FPGA revision is below 1.000

Upgrade the SC3 FPGA to revision 1.000 or later.

CMR channel does not support synchronous serial

Selected a CMR channel below 9

On the CMR module, only channels 9 and 10 support synchronous mode.

No data received

Receiver not enabled, clock mode misconfigured

Verify receiver is enabled and clock mode is set to internal.

No BOF/EOF markers in received data

Data not received as HDLC packet, used wrong receive API

Ensure naibrd_SER_ReceiveHDLCPacket() is used instead of naibrd_SER_ReceiveBufferWithTimeOut32().

Received count does not match sent count

Receiver not ready, delay too short

Increase the post-transmit delay before reading.

No board found or connection timeout

Board not powered, incorrect configuration file

Verify hardware is powered and connected.

NAI_ERROR_NOT_SUPPORTED

Module does not support HDLC protocol

Verify your module supports synchronous serial. Consult the SC3 Manual.

Full Source

The complete source for this sample is provided below for reference.

Full Source — ser_hdlc_loopback.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_ser.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"

static const int8_t *CONFIG_FILE = (const int8_t *)"default_SER_HDLC_Loopback.txt";

/* Function prototypes */
void Run_SER_HDLC_LOOPBACK(int32_t cardIndex, int32_t module, uint32_t moduleId);

#define NUM_DATA_TX  10
#define MAX_DATA_RX  NUM_DATA_TX
#define MAX_TIMEOUT  200

#define NAIBRD_SC3_REV_1_0    ((float64_t) 1.000)  /* SC3 w/ FPGA Rev of 001.000 or greater has sync functionality */

/**************************************************************************************************************/
/** \defgroup SERLoopbackSync

\brief This sample application demonstrates how to configure and use a serial channel for synchronous loopback transmission.

The Serial Loopback Synchronous Sample Application illustrates the methods to call in the `naibrd` library to configure a given serial
channel for loopback transmission. The application writes data to the selected serial channel's transmit buffer, transmits it via an
internal loopback, and receives and prints the data.

The main steps include:
- Querying the user for the card index and module number.
- Configuring the serial channel for synchronous communication with loopback.
- Transmitting data through the serial channel.
- Receiving the transmitted data and displaying it.
*/
/**************************************************************************************************************/

#ifdef NAIBSP_CONFIG_SOFTWARE_OS_VXWORKS
int32_t SER_HDLC_Loopback_Sample(void)
#else
int32_t main(void)
#endif
{
   bool_t stop = NAI_FALSE;
   int32_t cardIndex;
   int32_t moduleCnt;
   int32_t module;
   uint32_t moduleId = 0;
   float64_t fpgaRev;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   if (naiapp_RunBoardMenu(CONFIG_FILE) == (bool_t)NAI_TRUE)
   {
      while (stop != NAI_TRUE)
      {
         /* Query the user for the card index */
         stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
         if (stop != NAI_TRUE)
         {
            check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));

            /* Query the user for the module number */
            stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
            if (stop != NAI_TRUE)
            {
               /* Check to make sure the module is NOT an SC3 */
               check_status(naibrd_GetModuleName(cardIndex, module, &moduleId));
               check_status(naibrd_GetModuleFPGARev(cardIndex, module, &fpgaRev));
               if (moduleId == 0)
               {
                  naiif_printf("\r\nInvalid Module\r\n");
               }
               else if ((moduleId == NAIBRD_MODULE_ID_SC3) && (fpgaRev < NAIBRD_SC3_REV_1_0))
               {
                  naiif_printf("\r\nSC3 does not support synchronous serial communications.\r\n");
               }
               else if (moduleId == NAIBRD_MODULE_ID_CMH)
               {
                  naiif_printf("\r\nCMH does not support synchronous serial communications.\r\n");
               }
               else
               {
                  Run_SER_HDLC_LOOPBACK(cardIndex, module, moduleId);
               }
            }
         }

         naiif_printf("\r\nType Q to quit or Enter key to restart application:\r\n");
         stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      }
   }

   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;
}

/**************************************************************************************************************/
/** \ingroup SERLoopbackSync
Configures a serial module for synchronous internal loopback transmission. The user is queried for the
serial channel to perform this transmission on.
\param cardIndex (Input) Logical Card Index assigned to connection with the NAI_BOARD (0 - NAI_MAX_CARDS-1).
\param module    (Input) Module Number of the module to access (1 - [max modules for board]).
\param moduleId  (Input) The ID of the module.
*/
/**************************************************************************************************************/
void Run_SER_HDLC_LOOPBACK(int32_t cardIndex, int32_t module, uint32_t moduleId)
{
   int32_t channelCount;
   int32_t nNumWordsSend;
   int32_t nNumWordsRecv, i;
   uint32_t SendData[NUM_DATA_TX], RecvDataStatus[MAX_DATA_RX];
   int32_t chanNum;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   channelCount = naibrd_SER_GetChannelCount(moduleId);
   naiif_printf("\r\nSelect TX/RX Channel.");
   naiapp_query_ChannelNumber(channelCount, 1, &chanNum);

   if ((moduleId == NAIBRD_MODULE_ID_CMR) && (chanNum < 9)) /* Only channels 9 & 10 support sync on the CMR */
   {
      naiif_printf("\r\nCMR channel %d does not support synchronous serial communications.\r\n", chanNum);
      return;
   }

   /* Reset and clear channels FIFOs. */
   check_status(naibrd_SER_ChannelReset(cardIndex, module, chanNum));
   check_status(naibrd_SER_ClearRxFifo(cardIndex, module, chanNum));
   check_status(naibrd_SER_ClearTxFifo(cardIndex, module, chanNum));

   /* Configure Transmitter. */
   naiif_printf("\r\nSerial Channel # %d\r\n", chanNum);
   check_status(naibrd_SER_SetCommProtocol(cardIndex, module, chanNum, NAIBRD_SER_PROTOCOL_HDLC));      /* HDLC mode */
   check_status(naibrd_SER_SetInterface(cardIndex, module, chanNum, NAIBRD_SER_INTF_LOOPBACK));         /* RS422 */
   check_status(naibrd_SER_SetSyncClockMode(cardIndex, module, chanNum, NAIBRD_SER_CLOCK_MODE_INTERNAL));   /* Tx and Rx internal */
   check_status(naibrd_SER_SetBaudrate(cardIndex, module, chanNum, 115200));                            /* 115,200 baudrate */
   check_status(naibrd_SER_SetReceiverEnable(cardIndex, module, chanNum, 1));
   /* 100 millisecond wait to ensure the receiver is on. */
   naiif_msDelay(100);

   /* Fill the first 8 bits (data bits) with incremental data */
   for (i = 0; i < NUM_DATA_TX; i++)
      SendData[i] = (uint8_t)(i + 0x31);

   nNumWordsSend = i;
   naiif_printf("Sending %d words ...", nNumWordsSend);

   check_status(naibrd_SER_LoadBufferWithTimeOut32(cardIndex, module, chanNum, SendData, nNumWordsSend, NUM_DATA_TX,
      NAIBRD_FIFO_TIMEOUT_NONE, &nNumWordsRecv));                /* Load TX fifo with data from SendData array */

   /* Initiate Transmit */
   check_status(naibrd_SER_TransmitInitiate(cardIndex, module, chanNum));
   naiif_printf(" %d words sent\r\n", nNumWordsRecv);

   naiif_printf("Please press Enter to read back data...");
   while (naiapp_query_ForQuitResponse(sizeof(inputBuffer), 0x0A, inputBuffer, &inputResponseCnt));

   naiif_msDelay(500);
   nNumWordsRecv = 0;

   check_status(naibrd_SER_GetRxBufferCnt(cardIndex, module, chanNum, (uint32_t*)&nNumWordsRecv));
   check_status(naibrd_SER_ReceiveHDLCPacket(cardIndex, module, chanNum, RecvDataStatus, nNumWordsRecv,
      &nNumWordsRecv, NAIBRD_FIFO_TIMEOUT_NONE));                            /* Retrieve data from RX fifo */

   naiif_printf(" %d words read\r\n", nNumWordsRecv);

   for (i = 0; i < nNumWordsRecv; i++)
   {
      naiif_printf("Sent 0x%02X; Recd 0x%02X, Status= %02X",
         SendData[i], (RecvDataStatus[i] & 0x00FF), (RecvDataStatus[i] >> 8) & 0x00FF);
      if (((RecvDataStatus[i] >> 8) & 0x00FF) == NAIBRD_SER_SYNC_BOF)
      {
         naiif_printf("\tBeginning of HDLC frame (BOF)\r\n");
      }
      else if (((RecvDataStatus[i] >> 8) & 0x00FF) == NAIBRD_SER_SYNC_EOF)
      {
         naiif_printf("\tEnd of HDLC frame (EOF)\r\n");
      }
      else
      {
         naiif_printf("\r\n");
      }
   }
   return;
}

Help Bot

X