SER Async Loopback Timed RX
Edit this on GitLab
SER Async Loopback Timed RX Sample Application (SSK 2.x)
Overview
The SER Async Loopback Timed RX sample application demonstrates how to configure a serial channel for asynchronous timed transmission and timed reception using the NAI Software Support Kit (SSK 2.x). The application configures a channel for loopback mode with both timed TX and timed RX enabled, sends multiple messages separated by a configurable gap time, receives them back, and displays the received data with beginning-of-frame (BOF) indicators. It also reads and displays the contents of the Message Size FIFO, which reports the size of each received message.
This sample works with SER module types that support timed serial functionality. The message size, number of messages, baud rate, and gap time are configurable via preprocessor macros. It serves as a practical reference for the naibrd_SER_SetTimedRxConfig(), naibrd_SER_SetTimedSerialConfig(), and naibrd_SER_ReadTimedRxMsgSizeFifo() APIs.
Prerequisites
Before running this sample, make sure you have:
-
An NAI board with a SER module installed that supports timed serial functionality (e.g., SCA or newer SER variants).
-
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_async_loopback_timed_rx executable from your build output directory. On startup the application looks for a configuration file (default_SerAsync_Loopback_TimedRx.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, the application queries for a channel, configures timed TX and RX, transmits data, and displays the received results.
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:
-
Call
naiapp_RunBoardMenu()to load a saved configuration file or present the interactive 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(). -
Call
Run_SER_ASync_Loopback_TimedRx(cardIndex, module, moduleID).
#ifdef NAIBSP_CONFIG_SOFTWARE_OS_VXWORKS
int32_t SER_ASync_Loopback_TimedRx_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;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
if (naiapp_RunBoardMenu(CONFIG_FILE) == NAI_TRUE)
{
while (stop != NAI_TRUE)
{
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
if (stop != NAI_TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
if (stop != NAI_TRUE)
{
check_status(naibrd_GetModuleName(cardIndex, module, &moduleID));
if ((moduleID != 0))
{
Run_SER_ASync_Loopback_TimedRx(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;
}
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
The entry point is main() on most platforms, or SER_ASync_Loopback_TimedRx_Sample() on VxWorks.
Application Flow
-
Load configuration and connect to the board.
-
Query for channel number and reset the channel.
-
Configure the channel for async loopback.
-
Configure timed RX and timed TX.
-
Verify the configuration was applied correctly.
-
Transmit data and read back the loopback results.
-
Display received data with BOF indicators and Message Size FIFO contents.
Channel Configuration
After resetting the channel and clearing both FIFOs, the application sets up standard async loopback parameters:
check_status(naibrd_SER_SetCommProtocol(cardIndex, module, chanNum, NAIBRD_SER_PROTOCOL_ASYNC));
check_status(naibrd_SER_SetInterface(cardIndex, module, chanNum, NAIBRD_SER_INTF_LOOPBACK));
check_status(naibrd_SER_SetParityType(cardIndex, module, chanNum, NAIBRD_SER_PARITY_NONE));
check_status(naibrd_SER_SetNumDataBits(cardIndex, module, chanNum, NAIBRD_SER_DATA_BITS_8));
check_status(naibrd_SER_SetNumStopBits(cardIndex, module, chanNum, NAIBRD_SER_STOP_BITS_1));
check_status(naibrd_SER_SetBaudrate(cardIndex, module, chanNum, BAUD_RATE));
check_status(naibrd_SER_SetReceiverEnable(cardIndex, module, chanNum, NAI_TRUE));
Timed RX and TX Configuration
The application then configures both the timed RX and timed TX features:
check_status(naibrd_SER_SetTimedRxConfig(cardIndex, module, chanNum, NAI_TRUE, GAP_TIME_BITS));
check_status(naibrd_SER_SetTimedSerialConfig(cardIndex, module, chanNum, NAI_TRUE, GAP_TIME_BYTES,
MSG_SIZE, NUM_MSGS));
-
naibrd_SER_SetTimedRxConfig()enables timed RX mode and sets the gap time in bit-times (GAP_TIME_BITS = 960). The receiver uses this gap time to detect message boundaries. -
naibrd_SER_SetTimedSerialConfig()enables timed TX mode, sets the gap time in bytes (GAP_TIME_BYTES), the message size (MSG_SIZE = 8), and the number of messages (NUM_MSGS = 2).
The application inserts a 500 ms delay after configuration to allow the hardware to settle (must be longer than the gap time).
Configuration Verification
After the delay, the application reads back both the timed RX and TX configurations and verifies that all parameters match:
check_status(naibrd_SER_GetTimedRxConfig(cardIndex, module, chanNum, &enabledRxRead, &gapTimeRxRead));
check_status(naibrd_SER_GetTimedSerialConfig(cardIndex, module, chanNum, &enabledTxRead, &gapTimeTxRead,
&msgSizeRead, &msgCountRead));
If any parameter does not match the expected value, the application prints an error and returns without transmitting.
Data Transmission and Reception
The application populates a send buffer with DATA_SIZE (16) bytes of incremental values, loads the FIFO, and initiates transmission:
check_status(naibrd_SER_LoadBufferWithTimeOut32(cardIndex, module, chanNum, sendBuff, DATA_SIZE, DATA_SIZE,
NAIBRD_FIFO_TIMEOUT_NONE, (int32_t*)&numBytesSent));
check_status(naibrd_SER_TransmitInitiate(cardIndex, module, chanNum));
After the user presses Enter, the application reads back the received data and displays each byte with its BOF (beginning of frame) indicator:
for (idx = 0; idx < numBytesReceived; idx++)
{
naiif_printf("0x%02X %s\r\n",
recvBuff[idx] & 0x00FF,
(recvBuff[idx] & NAIBRD_SER_GEN5_TIMED_RX_BOF_MASK) ? "BOF" : "");
}
The NAIBRD_SER_GEN5_TIMED_RX_BOF_MASK flag in the received word indicates the first byte of each timed message. In this example with MSG_SIZE = 8 and NUM_MSGS = 2, you should see the BOF indicator on bytes 0 and 8.
Message Size FIFO
After displaying the received data, the application reads the Message Size FIFO:
check_status(naibrd_SER_ReadTimedRxMsgSizeFifo(cardIndex, module, chanNum, msgSizes, FIFO_SIZE));
for (idx = 0; idx < FIFO_SIZE; idx++)
{
if (msgSizes[idx] == 0)
break;
naiif_printf("%u\r\n", msgSizes[idx]);
}
The Message Size FIFO records the size of each received message. In this example, you should see two entries each showing a size of 8.
The application also displays Message Size FIFO status flags (Full, Empty, Overflow, Read Error) before and after reading the data, using naibrd_SER_GetEventMappedStatus() calls.
Troubleshooting Reference
| 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 |
Configuration not set properly (error message) |
Timed RX or TX configuration did not apply correctly |
Verify the module supports timed serial. Check the hardware and FPGA revision. |
No BOF indicators in received data |
Timed RX not enabled, gap time too short |
Verify |
Message Size FIFO empty |
No messages were detected by timed RX, receiver not enabled |
Verify receiver is enabled and timed RX configuration is correct. |
Received count does not match DATA_SIZE |
Configuration delay too short, receiver not enabled |
Increase the 500 ms post-configuration delay. Verify receiver is enabled. |
Message Size FIFO overflow |
Too many messages received before reading the FIFO |
Read the FIFO more frequently or increase FIFO depth if supported. |
Status byte indicates error |
Parity or framing error on received data |
In loopback mode this typically indicates a configuration issue. Try resetting the channel. |
Full Source
The complete source for this sample is provided below for reference. The sections above explain each part in detail.
Full Source — ser_async_loopback_timed_rx.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_SerAsync_Loopback_TimedRx.txt";
#define MSG_SIZE 8
#define NUM_MSGS 2
#define BAUD_RATE 9600
#define GAP_TIME_BITS 960
#define DATA_SIZE (MSG_SIZE * NUM_MSGS)
#define FIFO_SIZE 1024
#if GAP_TIME_BITS % 8
#define GAP_TIME_BYTES ((GAP_TIME_BITS / 8) + 1)
#else
#define GAP_TIME_BYTES (GAP_TIME_BITS / 8)
#endif
/* Function prototypes */
void Run_SER_ASync_Loopback_TimedRx(int32_t cardIndex, int32_t module, uint32_t moduleID);
/**************************************************************************************************************/
/** \defgroup SERAsyncLoopbackTimedRx
Illustrates the usage of timed Rx and Tx functionality (exclusive to SCA).
The specified channel is configured for loopback mode, and timed Tx and Rx are both enabled. The channel sends messages
separated by a gap time, and those messages are received back on the same channel. The received data is then displayed,
with the BOF (beginning of frame) bit indicated on the first byte of each message. The contents of the Message Size FIFO
are also displayed, indicating the size of each message received.
The message size, number of messages, baud rate, and gap time are configurable via preprocessor macros.
*/
/**************************************************************************************************************/
#ifdef NAIBSP_CONFIG_SOFTWARE_OS_VXWORKS
int32_t SER_ASync_Loopback_TimedRx_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;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
if (naiapp_RunBoardMenu(CONFIG_FILE) == 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_status(naibrd_GetModuleName(cardIndex, module, &moduleID));
if ((moduleID != 0))
{
Run_SER_ASync_Loopback_TimedRx(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;
}
static void print_msgSize_fifo_statuses(int32_t cardIndex, int32_t module, int32_t channel);
/**************************************************************************************************************/
/** \ingroup SERAsyncLoopbackTimedRx
\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_ASync_Loopback_TimedRx(int32_t cardIndex, int32_t module, uint32_t moduleID)
{
int32_t channelCount;
int32_t chanNum;
uint32_t sendBuff[DATA_SIZE] = {0};
uint32_t recvBuff[DATA_SIZE] = {0};
uint32_t msgSizes[FIFO_SIZE] = {0};
int8_t inputBuffer[80];
int32_t inputResponseCnt;
uint32_t idx;
uint32_t numBytesSent, numBytesReceived;
uint32_t gapTimeRxRead, gapTimeTxRead;
bool_t enabledRxRead;
uint32_t enabledTxRead;
uint32_t msgSizeRead, msgCountRead;
/* Populate array with data to send */
for (idx = 0; idx < DATA_SIZE; idx++)
{
sendBuff[idx] = (uint8_t)idx;
}
channelCount = naibrd_SER_GetChannelCount(moduleID);
naiapp_query_ChannelNumber(channelCount, 1, &chanNum);
naibrd_SER_ChannelReset(cardIndex, module, chanNum);
naibrd_SER_ClearRxFifo(cardIndex, module, chanNum);
naibrd_SER_ClearTxFifo(cardIndex, module, chanNum);
naiif_printf("\r\nSerial Channel # %d\r\n", chanNum);
/* Configure for ASync on the channel selected. */
check_status(naibrd_SER_SetCommProtocol(cardIndex, module, chanNum, NAIBRD_SER_PROTOCOL_ASYNC)); /* Async mode */
check_status(naibrd_SER_SetInterface(cardIndex, module, chanNum, NAIBRD_SER_INTF_LOOPBACK)); /* LoopBack */
check_status(naibrd_SER_SetParityType(cardIndex, module, chanNum, NAIBRD_SER_PARITY_NONE)); /* No Parity */
check_status(naibrd_SER_SetNumDataBits(cardIndex, module, chanNum, NAIBRD_SER_DATA_BITS_8)); /* 8 Data Bits */
check_status(naibrd_SER_SetNumStopBits(cardIndex, module, chanNum, NAIBRD_SER_STOP_BITS_1)); /* 1 Stop Bit */
check_status(naibrd_SER_SetBaudrate(cardIndex, module, chanNum, BAUD_RATE));
check_status(naibrd_SER_SetReceiverEnable(cardIndex, module, chanNum, NAI_TRUE)); /* Enable the Receiver */
check_status(naibrd_SER_SetTimedRxConfig(cardIndex, module, chanNum, NAI_TRUE, GAP_TIME_BITS));
check_status(naibrd_SER_SetTimedSerialConfig(cardIndex, module, chanNum, NAI_TRUE, GAP_TIME_BYTES,
MSG_SIZE, NUM_MSGS));
/* Wait for configuration to be ready, must be longer than gap time. */
naibrd_msDelay(500);
check_status(naibrd_SER_GetTimedRxConfig(cardIndex, module, chanNum, &enabledRxRead, &gapTimeRxRead));
check_status(naibrd_SER_GetTimedSerialConfig(cardIndex, module, chanNum, &enabledTxRead, &gapTimeTxRead,
&msgSizeRead, &msgCountRead));
if (!(
(enabledRxRead & enabledTxRead) && /* timed Tx and Rx enabled? */
(gapTimeRxRead == GAP_TIME_BITS) && /* Rx gap time set properly? */
(gapTimeTxRead == GAP_TIME_BYTES) && /* Tx gap time set properly? */
(msgSizeRead == MSG_SIZE) && /* Tx frame size set properly? */
(msgCountRead == NUM_MSGS) /* Tx frame count set properly? */
))
{
naiif_printf("\r\nError: Configuration not set properly.\r\n");
return;
}
naiif_printf("\r\nSending %u bytes"
"\r\nBaud rate: %u"
"\r\nGap time: %u bit-times\r\n",
DATA_SIZE,
BAUD_RATE,
GAP_TIME_BITS);
check_status(naibrd_SER_LoadBufferWithTimeOut32(cardIndex, module, chanNum, sendBuff, DATA_SIZE, DATA_SIZE,
NAIBRD_FIFO_TIMEOUT_NONE, (int32_t*)&numBytesSent));
check_status(naibrd_SER_TransmitInitiate(cardIndex, module, chanNum));
naiif_printf("\r\nPlease press Enter to read back data...\r\n");
while (naiapp_query_ForQuitResponse(sizeof(inputBuffer), 0x0A, inputBuffer, &inputResponseCnt));
print_msgSize_fifo_statuses(cardIndex, module, chanNum);
check_status(naibrd_SER_GetRxBufferCnt(cardIndex, module, chanNum, &numBytesReceived));
check_status(naibrd_SER_ReceiveBufferWithTimeOut32(cardIndex, module, chanNum, recvBuff, DATA_SIZE, numBytesReceived,
NAIBRD_FIFO_TIMEOUT_NONE, (int32_t*)&numBytesReceived));
naiif_printf("\r\n%d bytes received:\r\n", numBytesReceived);
for (idx = 0; idx < numBytesReceived; idx++)
{
naiif_printf("0x%02X %s\r\n",
recvBuff[idx] & 0x00FF,
(recvBuff[idx] & NAIBRD_SER_GEN5_TIMED_RX_BOF_MASK) ? "BOF" : "");
}
naiif_printf("\r\nMessage Size FIFO contents: \r\n");
check_status(naibrd_SER_ReadTimedRxMsgSizeFifo(cardIndex, module, chanNum, msgSizes, FIFO_SIZE));
for (idx = 0; idx < FIFO_SIZE; idx++)
{
if (msgSizes[idx] == 0)
break;
naiif_printf("%u\r\n", msgSizes[idx]);
}
print_msgSize_fifo_statuses(cardIndex, module, chanNum);
naiif_printf("\r\nPress ENTER to run again, or '%c' to exit program : ", NAI_QUIT_CHAR);
naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
return;
}
void print_msgSize_fifo_statuses(int32_t cardIndex, int32_t module, int32_t channel)
{
nai_status_bit_t fifoStatusFull, fifoStatusEmpty, fifoStatusOverflow, fifoStatusErr;
check_status(naibrd_SER_GetEventMappedStatus(cardIndex, module, channel,
NAIBRD_SER_EVENT_MAP_STATUS_FIFO_MSGSIZE_FULL_REALTIME, &fifoStatusFull));
check_status(naibrd_SER_GetEventMappedStatus(cardIndex, module, channel,
NAIBRD_SER_EVENT_MAP_STATUS_FIFO_MSGSIZE_EMPTY_REALTIME, &fifoStatusEmpty));
check_status(naibrd_SER_GetEventMappedStatus(cardIndex, module, channel,
NAIBRD_SER_EVENT_MAP_STATUS_FIFO_MSGSIZE_OVERFLOW_REALTIME, &fifoStatusOverflow));
check_status(naibrd_SER_GetEventMappedStatus(cardIndex, module, channel,
NAIBRD_SER_EVENT_MAP_STATUS_FIFO_MSGSIZE_READ_ERR_REALTIME, &fifoStatusErr));
naiif_printf("\r\nMessage Size FIFO statuses: Full (%u), Empty (%u), Overflow (%u), Read Error (%u)\r\n",
fifoStatusFull, fifoStatusEmpty, fifoStatusOverflow, fifoStatusErr);
}