SER Async GPIO
Edit this on GitLab
SER Async GPIO Sample Application (SSK 2.x)
Overview
The SER Async GPIO sample application demonstrates how to use the General Purpose Input/Output (GPIO) feature on a serial channel using the NAI Software Support Kit (SSK 2.x). The application configures a channel for loopback mode with GPIO enabled, then toggles the GPO (General Purpose Output) pin high and low while reading back the GPI (General Purpose Input) state. Because the channel is in loopback mode, the GPO output is routed directly to the GPI input, allowing you to verify GPIO functionality without external wiring.
This sample is exclusive to the SC3 module. The GPIO feature allows serial channels to function as digital I/O pins in addition to their normal serial communication role. This is useful for hardware handshaking signals or simple control/status lines.
For the SSK 1.x version, see SER ASync GPIO (SSK 1.x).
Prerequisites
Before running this sample, make sure you have:
-
An NAI board with an SC3 module installed.
-
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_gpio executable from your build output directory. On startup the application looks for a configuration file (default_SerASync_GPIO.txt). Once connected, the application verifies that the selected module is an SC3, queries for a channel, and enters an interactive GPIO toggle loop.
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 and module slot.
-
Retrieve the module ID with
naibrd_GetModuleName()and verify it isNAIBRD_MODULE_ID_SC3. -
Call
Run_SER_ASync_GPIO(cardIndex, module, moduleID).
#ifdef NAIBSP_CONFIG_SOFTWARE_OS_VXWORKS
int32_t SER_ASync_GPIO_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) && (moduleID == NAIBRD_MODULE_ID_SC3))
{
Run_SER_ASync_GPIO(cardIndex, module, moduleID);
}
else
{
naiif_printf("\r\nThe GPIO feature is only available on the NAI SC3 module.\r\n\r\n");
}
}
}
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;
}
|
Important
|
Common connection errors you may encounter at this stage:
|
Channel Configuration
The application configures the channel with loopback and GPIO mode combined:
check_status(naibrd_SER_SetInterface(cardIndex, module, chanNum, NAIBRD_SER_INTF_LOOPBACK | NAIBRD_SER_INTF_GPIO));
check_status(naibrd_SER_SetReceiverEnable(cardIndex, module, chanNum, NAI_TRUE));
naiif_msDelay(500);
The NAIBRD_SER_INTF_LOOPBACK | NAIBRD_SER_INTF_GPIO combination enables both loopback mode and GPIO functionality on the channel. In this mode, the GPO output is tied to the GPI input, allowing you to verify GPIO state changes without external wiring.
GPIO Toggle Loop
The application enters a loop that toggles the GPO pin between high and low states:
Setting GPO High
control |= NAIBRD_SER_CTRL_GPO1;
check_status(naibrd_SER_SetChannelControlRaw(cardIndex, module, chanNum, control));
check_status(naibrd_SER_GetEventMappedStatus(cardIndex, module, chanNum, NAIBRD_SER_EVENT_MAP_STATUS_COMM_GPI1_REALTIME, &gpiState));
naiif_printf( "GPI bit: %s\r\n", gpiState == NAI_STATUS_BIT_HI ? "HI" : "LO");
-
naibrd_SER_SetChannelControlRaw()writes the raw channel control register with theNAIBRD_SER_CTRL_GPO1bit set, which drives the GPO pin high. -
naibrd_SER_GetEventMappedStatus()reads the real-time GPI1 status. In loopback mode, the GPI should read HI immediately after setting GPO high.
Setting GPO Low
control &= ~NAIBRD_SER_CTRL_GPO1;
check_status(naibrd_SER_SetChannelControlRaw(cardIndex, module, chanNum, control));
check_status(naibrd_SER_GetEventMappedStatus(cardIndex, module, chanNum, NAIBRD_SER_EVENT_MAP_STATUS_COMM_GPI1_REALTIME, &gpiState));
naiif_printf( "GPI bit: %s\r\n", gpiState == NAI_STATUS_BIT_HI ? "HI" : "LO");
Clearing the NAIBRD_SER_CTRL_GPO1 bit drives the GPO pin low, and the GPI should read LO.
Troubleshooting Reference
| Error / Symptom | Possible Causes | Suggested Resolution |
|---|---|---|
Module not SC3 |
A non-SC3 module is installed |
The GPIO feature is exclusive to the SC3 module. Verify your hardware configuration. |
GPI does not follow GPO |
Loopback not enabled, GPIO not enabled, interface misconfigured |
Verify the interface is set to `NAIBRD_SER_INTF_LOOPBACK |
NAIBRD_SER_INTF_GPIO`. |
No board found or connection timeout |
Board not powered, incorrect configuration file |
Verify hardware is powered and connected. |
GPI always reads LO |
GPO not being set, channel control register not updated |
Check that |
GPI always reads HI |
GPO stuck high, channel not reset |
Full Source
The complete source for this sample is provided below for reference.
Full Source — ser_async_gpio.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_GPIO.txt";
/* Function prototypes */
void Run_SER_ASync_GPIO(int32_t cardIndex, int32_t module, uint32_t moduleID);
#define CLEAR_FIFO_TIMEOUT 1000 /* 1 second */
/**************************************************************************************************************/
/** \defgroup SERGPIO
\brief This sample application demonstrates how to configure a serial channel to use the GPIO feature.
The Serial Async GPIO sample application illustrates the methods to call in order to exercise the GPIO feature of a serial channel.
To set an output (GPO) channel high, set the Channel Control register RTS/GPO 1 using the naibrd_SER_SetChannelControlRaw() function passing
it NAIBRD_SER_CTRL_GPO1 as the last argument. Inputs (GPI) are monitored by the Dynamic Status register, bits CTS/GPI 1 and GPI 2, which
provide real-time status monitoring of the GPI inputs. The Latched Status register, bits CTS/GPI 1 and GPI 2, latch when an input is
received and are cleared when a 1 is written to the register. The Interrupt Enable register bits CTS/GPI 1 and GPI 2 when set to a 1, will
create an interrupt. To invert the GPI/GPO inputs and outputs, set the Tx-Rx Configuration register bits Invert CTS (GPI) and Invert RTS
(GPO), to 1. See the Register Descriptions for more information.
The main steps include:
- Querying the user for the card index and module number.
- Configuring the serial channel for GPIO functionality.
- Setting and clearing the GPO bit.
- Monitoring the GPI bit status.
*/
/**************************************************************************************************************/
#ifdef NAIBSP_CONFIG_SOFTWARE_OS_VXWORKS
int32_t SER_ASync_GPIO_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 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) && (moduleID == NAIBRD_MODULE_ID_SC3))
{
Run_SER_ASync_GPIO(cardIndex, module, moduleID);
}
else
{
naiif_printf("\r\nThe GPIO feature is only available on the NAI SC3 module.\r\n\r\n");
}
}
}
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 SERGPIO
Configures a serial module to use the GPIO feature. The user is queried for the serial channel to use.
\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_GPIO(int32_t cardIndex, int32_t module, uint32_t moduleID)
{
int32_t channelCount, chanNum;
bool_t bQuit = NAI_FALSE;
uint32_t control;
nai_status_bit_t gpiState = 0;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
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_SetInterface(cardIndex, module, chanNum, NAIBRD_SER_INTF_LOOPBACK | NAIBRD_SER_INTF_GPIO)); /* LoopBack with GPIO */
check_status(naibrd_SER_SetReceiverEnable(cardIndex, module, chanNum, NAI_TRUE));
/* Add a delay here for the configuration to be ready */
naiif_msDelay(500);
/* Ensure GPO is low */
check_status(naibrd_SER_GetChannelControlRaw(cardIndex, module, chanNum, &control));
control &= ~NAIBRD_SER_CTRL_GPO1;
check_status(naibrd_SER_SetChannelControlRaw(cardIndex, module, chanNum, control));
do
{
naiif_printf ("Press ENTER to pull GPO high, or %c to exit program...\r\n", NAI_QUIT_CHAR);
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (NAI_TRUE != bQuit)
{
/* Set the GPO bit to 1 (high state) */
control |= NAIBRD_SER_CTRL_GPO1;
check_status(naibrd_SER_SetChannelControlRaw(cardIndex, module, chanNum, control));
/* Since LOOPBACK mode ties GPO to GPI, GPI will be in a high state. */
check_status(naibrd_SER_GetEventMappedStatus(cardIndex, module, chanNum, NAIBRD_SER_EVENT_MAP_STATUS_COMM_GPI1_REALTIME, &gpiState));
naiif_printf( "GPI bit: %s\r\n", gpiState == NAI_STATUS_BIT_HI ? "HI" : "LO");
naiif_printf ("Press ENTER to pull GPO low, or %c to exit program...\r\n", NAI_QUIT_CHAR);
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
}
if (NAI_TRUE != bQuit)
{
/* Set the GPO bit to 0 (low state) */
control &= ~NAIBRD_SER_CTRL_GPO1;
check_status(naibrd_SER_SetChannelControlRaw(cardIndex, module, chanNum, control));
/* Since LOOPBACK mode ties GPO to GPI, GPI will be in a low state. */
check_status(naibrd_SER_GetEventMappedStatus(cardIndex, module, chanNum, NAIBRD_SER_EVENT_MAP_STATUS_COMM_GPI1_REALTIME, &gpiState));
naiif_printf( "GPI bit: %s\r\n", gpiState == NAI_STATUS_BIT_HI ? "HI" : "LO");
}
} while ( NAI_TRUE != bQuit );
return;
}