SER HDLC Loopback
Edit this on GitLab
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:
|
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_HDLCsets the channel for HDLC synchronous protocol instead of async. -
naibrd_SER_SetSyncClockMode()configures the clock source.NAIBRD_SER_CLOCK_MODE_INTERNALmeans 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 |
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. |
|
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;
}