ENC SSI BasicOps
Edit this on GitLab
ENC SSI BasicOps Sample Application (SSK 1.x)
Overview
The ENC SSI BasicOps sample application demonstrates how to configure and operate SSI (Synchronous Serial Interface) encoder channels using the NAI Software Support Kit (SSK 1.x). It covers the core SSI encoder operations you will need in your own application: setting the SSI mode (controller or listener), configuring clock rate and edge polarity, specifying data width and coding format (Gray or binary), configuring input electrical characteristics, triggering data transfers, and monitoring channel status.
This sample supports NAI encoder modules identified by the EC1 module ID (NAI_MODULE_ID_EC1). Check the naibrd_enc.h header file for the current list of supported ENC module IDs, as new variants may be added in future SSK releases. The sample serves as a practical API reference — each menu command maps directly to one or more naibrd_ENC_*() API calls that you can lift into your own code.
What Is SSI?
SSI (Synchronous Serial Interface) is a point-to-point serial protocol widely used to read absolute position from rotary and linear encoders. Unlike incremental encoders, which output pulse trains that must be counted from a known reference point, SSI encoders transmit the complete absolute position in a single data frame every time they are clocked. This means an SSI encoder knows its exact position immediately at power-on — there is no homing sequence required.
The SSI protocol uses two signal lines:
-
Clock — generated by the interface controller (master) and sent to the encoder. Each clock pulse shifts one bit of position data out of the encoder.
-
Data — driven by the encoder (slave) back to the controller. The encoder presents the most-significant bit first and shifts out successive bits on each clock edge.
A complete SSI transaction consists of the controller issuing a burst of clock pulses equal to the encoder’s data width. The encoder responds synchronously, shifting out its position word one bit per clock cycle. After the last bit, the data line returns to a known idle state.
Gray Code vs. Binary Coding
Many SSI encoders transmit position data in Gray code rather than standard binary. In Gray code, only one bit changes between any two adjacent positions. This eliminates a class of read errors that can occur with natural binary encoding, where multiple bits may change simultaneously at certain position transitions (for example, transitioning from position 7 to 8 in binary requires all four lower bits to change at once). If the controller reads the encoder during such a multi-bit transition, it could capture a momentary invalid value.
The NAI encoder module can accept both Gray-coded and standard binary SSI data. When you read position data, the module provides both the raw SSI data and a Gray-decoded value through separate API calls, so you can work with whichever representation your application requires.
Controller vs. Listener Mode
The NAI encoder module can operate in two SSI roles:
-
Interface Controller — the module generates the clock signal and drives it out to the encoder on Port A (output). The encoder returns position data on Port B (input). This is the standard operating mode when the NAI module is the only device reading the encoder.
-
Listener — the module monitors both clock and data lines passively (both Port A and Port B configured as inputs). A separate controller generates the clock. The NAI module captures the data in sync with the observed clock edges. Use listener mode when another controller already drives the SSI bus and you need to tap into the same encoder data.
Prerequisites
Before running this sample, make sure you have:
-
An NAI board with an ENC module installed (EC1 or compatible encoder module).
-
SSK 1.x installed on your development host.
-
The sample applications built. Refer to the SSK 1.x build instructions for your platform if you have not already compiled them.
How to Run
Launch the ENC_SSI_BasicOps executable from your build output directory. On startup the application looks for a configuration file (default_ENC_SSI_BasicOps.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. You can save this configuration so that subsequent runs skip the menu and connect automatically. Once connected, you select a channel and then a command menu lets you exercise each SSI operation.
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 ENC. For details on board connection configuration, see the First Time Setup Guide. |
The main() function follows a standard SSK 1.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_ENC_SSI_BasicOps.txt) is not included with the SSK — it is created when the user saves their connection settings from the board menu. On the first run, the menu will always appear. -
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_GetModuleID()so downstream code can adapt to the specific encoder variant installed.
#if defined (__VXWORKS__)
int32_t ENC_SSI_BasicOps(void)
#else
int32_t main(void)
#endif
{
bool_t stop = 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) == TRUE)
{
while (stop != TRUE)
{
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
if (stop != TRUE)
{
moduleID = naibrd_GetModuleID(cardIndex, module);
if ((moduleID != 0))
{
Run_ENC_SSI_BasicOps(cardIndex, module, moduleID);
}
}
}
printf("\nType Q to quit or Enter key to restart application:\n");
stop = 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:
|
Program Structure
Entry Point
On standard platforms the entry point is main(). On VxWorks the entry point is ENC_SSI_BasicOps() — the SSK 1.x build system selects the correct variant via a preprocessor guard:
#if defined (__VXWORKS__)
int32_t ENC_SSI_BasicOps(void)
#else
int32_t main(void)
#endif
The startup flow is the same in both cases:
-
Attempt to load the saved configuration file via
naiapp_RunBoardMenu(CONFIG_FILE). If the file does not yet exist, the interactive board menu is presented instead. -
Enter a loop that queries for card index and module slot.
-
Validate the module by calling
naibrd_GetModuleID()and, if non-zero, callRun_ENC_SSI_BasicOps()to enter the interactive command loop. -
On exit, close all open board connections with
naiapp_access_CloseAllOpenCards().
Module Validation
Run_ENC_SSI_BasicOps() calls naibrd_ENC_GetChannelCount() with the detected module ID to determine whether the selected slot contains a valid encoder module. If the channel count is zero, the module is not recognized as an encoder and the application prints a diagnostic message. Otherwise, it proceeds to Cfg_ENC_Channel():
int32_t Run_ENC_SSI_BasicOps(int32_t cardIndex, int32_t module, int32_t ModuleID)
{
int32_t MaxChannel;
MaxChannel = naibrd_ENC_GetChannelCount(ModuleID);
if (MaxChannel == 0)
{
printf(" *** Module selection not recognized as DSW module. ***\n\n");
}
else
{
Cfg_ENC_Channel(cardIndex, module, MaxChannel);
}
return cardIndex;
}
In your own application, call naibrd_ENC_GetChannelCount() after retrieving the module ID to confirm that an encoder module is present and to determine how many channels are available.
Application Parameters
The Cfg_ENC_Channel() function populates an naiapp_AppParameters_t struct that is passed to every command handler. Your application will need to track these same values to identify which board, module, and channel you are targeting:
naiapp_AppParameters_t enc_params;
p_naiapp_AppParameters_t enc_ssi_params = &enc_params;
enc_ssi_params->cardIndex = cardIndex;
enc_ssi_params->module = module;
enc_ssi_params->maxChannels = MaxChannel;
-
cardIndex— identifies which board in a multi-board system. -
module— the slot number where the ENC module is installed. -
maxChannels— total channel count for the detected module, retrieved by callingnaibrd_ENC_GetChannelCount()with the module ID. -
channel— the currently selected channel (queried interactively; defaults to 1).
Command Loop
Cfg_ENC_Channel() drives the interactive command loop. On each iteration it queries for a channel number, displays the current SSI data for that channel, prints the command menu, and dispatches the user’s selection to the matching handler function. The menu system is a sample convenience — in your own code, call these API functions directly.
naiapp_utils_LoadParamMenuCommands(ENC_SSI_BASICOP_CMD_COUNT, ENC_SSI_BasicOpMenuCmds);
while (bContinue)
{
Display_ENC_SSIChannelCfg(cardIndex, module, enc_ssi_params->channel);
naiapp_display_ParamMenuCommands((int8_t *)"ENC SSI Basic Operation Menu");
printf("\nType ENC SSI command or %c to quit : ", NAI_QUIT_CHAR);
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt > 0)
{
bCmdFound = naiapp_utils_GetParamMenuCmdNum(inputResponseCnt, inputBuffer, &cmd);
if (bCmdFound)
{
/* dispatch to the selected command handler */
}
}
}
else
bContinue = FALSE;
}
The available commands are registered in the ENC_SSI_BasicOpMenuCmds[] table:
| Command | Description |
|---|---|
V |
View current configuration — displays all SSI parameters and input settings |
I |
Set input configuration — input mode, termination, threshold, high voltage |
M |
Set SSI mode — interface controller or listener |
C |
Set SSI clock period — clock rate in microseconds |
E |
Set SSI clock edge level — rising or falling edge |
D |
Set SSI data bits — expected data width from the encoder |
P |
Set SSI parity — even or odd |
PC |
Enable/disable parity checking |
ZB |
Enable/disable zero bit |
T |
Trigger data transfer — initiates an SSI clock burst to read encoder position |
STAT |
Display SSI status — shows all status flags for the selected channel |
Reading SSI Encoder Data
Before diving into individual configuration commands, it is important to understand how encoder data is read. Each time the command loop iterates, the sample displays the current SSI data for the selected channel by calling Display_ENC_SSIChannelCfg().
To read the current encoder position in your own application, call naibrd_ENC_GetSSI_Data() for the raw (binary or Gray-coded) value and naibrd_ENC_GetSSI_GreyData() for the Gray-decoded value:
uint32_t ssiData = 0u;
uint32_t ssiGrayData = 0u;
check_status(naibrd_ENC_GetSSI_Data(cardIndex, module, chan, &ssiData));
check_status(naibrd_ENC_GetSSI_GreyData(cardIndex, module, chan, &ssiGrayData));
-
ssiData— the raw position word as received from the encoder over the SSI bus. If the encoder transmits Gray code, this value is in Gray code. If the encoder transmits standard binary, bothssiDataandssiGrayDatawill contain the same value. -
ssiGrayData— the position value after Gray-to-binary conversion. Use this when your encoder transmits Gray code and you need a standard binary position value.
Both values are returned as 32-bit unsigned integers. The number of significant bits depends on the data width configured with naibrd_ENC_SetSSI_DataBits().
Viewing the Full Configuration (V)
To retrieve and display all SSI configuration parameters for a channel, call the series of naibrd_ENC_Get*() functions shown below. This is useful for verifying that your configuration was applied correctly before triggering data transfers.
/* Input configuration */
check_status(naibrd_ENC_GetInputMode(cardIndex, module, chan, &inputMode));
check_status(naibrd_ENC_GetInputTermination(cardIndex, module, chan, NAI_ENC_PORT_A, &termA));
check_status(naibrd_ENC_GetInputTermination(cardIndex, module, chan, NAI_ENC_PORT_B, &termB));
check_status(naibrd_ENC_GetInputTermination(cardIndex, module, chan, NAI_ENC_PORT_Index, &termIndx));
check_status(naibrd_ENC_GetInputThreshold(cardIndex, module, chan, &inputThreshold));
check_status(naibrd_ENC_GetHighVoltEnable(cardIndex, module, chan, NAI_ENC_PORT_A, &highVoltA));
check_status(naibrd_ENC_GetHighVoltEnable(cardIndex, module, chan, NAI_ENC_PORT_B, &highVoltB));
check_status(naibrd_ENC_GetHighVoltEnable(cardIndex, module, chan, NAI_ENC_PORT_Index, &highVoltIndx));
/* SSI protocol configuration */
check_status(naibrd_ENC_GetSSI_Mode(cardIndex, module, chan, &ssiMode));
check_status(naibrd_ENC_GetIOFormat(cardIndex, module, chan, NAI_ENC_PORT_A, &ioformatA));
check_status(naibrd_ENC_GetIOFormat(cardIndex, module, chan, NAI_ENC_PORT_B, &ioformatB));
check_status(naibrd_ENC_GetIOFormat(cardIndex, module, chan, NAI_ENC_PORT_Index, &ioformatIndx));
check_status(naibrd_ENC_GetSSI_ClockRate(cardIndex, module, chan, &clockRate));
check_status(naibrd_ENC_GetSSI_ClockEdgeLevel(cardIndex, module, chan, &clockEdge));
check_status(naibrd_ENC_GetSSI_DataBits(cardIndex, module, chan, &dataBits));
check_status(naibrd_ENC_GetSSI_Parity(cardIndex, module, chan, &parity));
check_status(naibrd_ENC_GetSSI_ParityEnable(cardIndex, module, chan, &parityEn));
check_status(naibrd_ENC_GetSSI_ZeroBitEnable(cardIndex, module, chan, &zeroBitEn));
The configuration display is split into two groups:
Input electrical settings:
-
inputMode— Differential or Single-Ended. -
termA,termB,termIndx— Termination state for each port (Port A, Port B, Index). -
inputThreshold— Input voltage threshold in volts. -
highVoltA,highVoltB,highVoltIndx— High voltage mode enable for each port.
SSI protocol settings:
-
ssiMode— Interface Controller or Listener. -
ioformatA,ioformatB,ioformatIndx— I/O direction (Input or Output) for each port. -
clockRate— Clock period in microseconds. -
clockEdge— Rising or Falling edge. -
dataBits— Number of data bits expected from the encoder. -
parity— Even or Odd. -
parityEn— Whether parity checking is enabled. -
zeroBitEn— Whether the zero bit is enabled.
|
Important
|
Common Errors
|
Input Configuration (I)
To configure the electrical input characteristics of an SSI encoder channel, use the input configuration command. This sets four independent parameters: input mode, termination, voltage threshold, and high voltage mode. Each parameter can be skipped individually, allowing you to change only the settings you need.
Input Mode
To set the input signaling mode, call naibrd_ENC_SetInputMode():
check_status(naibrd_ENC_SetInputMode(cardIndex, module, chan, inputMode));
-
NAI_ENC_INPUT_DIFFERENTIAL— differential signaling. Use this when your encoder provides complementary signal pairs (A+/A-, B+/B-). Differential mode offers better noise immunity and is the standard for industrial SSI encoders. -
NAI_ENC_INPUT_SINGLE_ENDED— single-ended signaling. Use this for encoders with single-wire outputs referenced to ground.
Input Termination
To set the line termination for each port, call naibrd_ENC_SetInputTermination() once per port:
check_status(naibrd_ENC_SetInputTermination(cardIndex, module, chan, NAI_ENC_PORT_A, termination));
check_status(naibrd_ENC_SetInputTermination(cardIndex, module, chan, NAI_ENC_PORT_B, termination));
check_status(naibrd_ENC_SetInputTermination(cardIndex, module, chan, NAI_ENC_PORT_Index, termination));
-
NAI_ENC_TERMINATED— enables the on-board termination resistor. Use this when the cable is not externally terminated. -
NAI_ENC_NOT_TERMINATED— disables the on-board termination. Use this when external termination is already present on the cable or at the encoder.
Proper termination is critical for signal integrity, especially at higher clock rates or over longer cable runs. Incorrect termination can cause signal reflections that lead to bit errors.
Input Threshold
To set the voltage threshold for detecting logic high vs. low on the input signals, call naibrd_ENC_SetInputThreshold():
check_status(naibrd_ENC_SetInputThreshold(cardIndex, module, chan, inputThreshold));
The threshold is specified in volts. The sample accepts values from 0 to 3.75 V. Consult your module’s manual for the exact supported range and resolution for your specific module variant.
High Voltage Mode
To enable or disable high voltage input mode on each port, call naibrd_ENC_SetHighVoltEnable():
check_status(naibrd_ENC_SetHighVoltEnable(cardIndex, module, chan, NAI_ENC_PORT_A, highVoltageEn));
check_status(naibrd_ENC_SetHighVoltEnable(cardIndex, module, chan, NAI_ENC_PORT_B, highVoltageEn));
check_status(naibrd_ENC_SetHighVoltEnable(cardIndex, module, chan, NAI_ENC_PORT_Index, highVoltageEn));
-
TRUE— enables high voltage mode, allowing the port to accept signal levels above the standard range. -
FALSE— disables high voltage mode, restricting the port to the standard voltage range.
Enable high voltage mode only when your encoder outputs signals at voltage levels that exceed the module’s standard input range. Consult your module’s manual for the voltage ranges in each mode.
|
Important
|
Common Errors
|
SSI Mode (M)
To set the SSI operating mode for a channel, call naibrd_ENC_SetSSI_Mode(). The mode determines whether the NAI module generates the clock (controller) or passively listens to an external clock (listener). Setting the SSI mode also requires configuring the control mode to SSI and setting the appropriate I/O direction for Port A and Port B.
check_status(naibrd_ENC_SetControlMode(cardIndex, module, chan, NAI_ENC_MODE_SSI));
check_status(naibrd_ENC_SetSSI_Mode(cardIndex, module, chan, mode));
check_status(naibrd_ENC_SetIOFormat(cardIndex, module, chan, NAI_ENC_PORT_A, portAFormat));
check_status(naibrd_ENC_SetIOFormat(cardIndex, module, chan, NAI_ENC_PORT_B, portBFormat));
The three calls after SetSSI_Mode() are essential and must be made together:
-
naibrd_ENC_SetControlMode()— sets the channel’s overall operating mode to SSI (NAI_ENC_MODE_SSI). This must be called before setting SSI-specific parameters. -
naibrd_ENC_SetSSI_Mode()— selects controller or listener mode:-
NAI_ENC_SSI_CONTROLLER— the module generates the clock on Port A (output) and reads data on Port B (input). -
NAI_ENC_SSI_LISTENER— the module monitors both clock (Port A, input) and data (Port B, input) passively.
-
-
naibrd_ENC_SetIOFormat()— configures each port’s direction to match the selected mode:
| Mode | Port A (Clock) | Port B (Data) |
|---|---|---|
Controller |
|
|
Listener |
|
|
|
Important
|
Common Errors
|
SSI Clock Period ©
To set the SSI clock rate, call naibrd_ENC_SetSSI_ClockRate():
check_status(naibrd_ENC_SetSSI_ClockRate(cardIndex, module, chan, clockRate));
-
clockRate— the clock period in microseconds. The sample accepts integer values from 1 to 32 in steps of 1 microsecond, corresponding to clock frequencies from 1 MHz down to approximately 31.25 kHz.
The clock period determines how fast data is shifted out of the encoder. Shorter periods (higher frequencies) allow faster position updates but require shorter cable runs and better signal integrity. Longer periods (lower frequencies) tolerate longer cables and noisier environments at the cost of slower update rates.
Consult your encoder’s datasheet for its maximum supported clock frequency. If you set the clock faster than the encoder can respond, the received data will be corrupted. A typical starting point for most industrial SSI encoders is a clock period of 4 to 8 microseconds.
|
Important
|
Common Errors
|
SSI Clock Edge (E)
To select which clock edge the module uses to sample SSI data, call naibrd_ENC_SetSSI_ClockEdgeLevel():
check_status(naibrd_ENC_SetSSI_ClockEdgeLevel(cardIndex, module, chan, clockEdgeLvl));
-
NAI_ENC_SSI_CLOCK_RISING— data is sampled on the rising edge of the clock signal. -
NAI_ENC_SSI_CLOCK_FALLING— data is sampled on the falling edge of the clock signal.
Most SSI encoders shift data on the falling clock edge, meaning the controller should sample on the rising edge. However, this varies by manufacturer. Consult your encoder’s datasheet to determine the correct edge polarity. If data appears bit-shifted or garbled, the wrong clock edge is a common cause.
|
Important
|
Common Errors
|
SSI Data Bits (D)
To configure the expected data width of the SSI frame, call naibrd_ENC_SetSSI_DataBits():
check_status(naibrd_ENC_SetSSI_DataBits(cardIndex, module, chan, dataBits));
-
dataBits— the number of data bits the encoder transmits per SSI frame, configurable from 1 to 31.
This value must match the resolution of your encoder. For example, a 13-bit absolute encoder transmits 13 bits of position data per frame. If this value does not match the encoder’s actual data width, the received position data will be incorrect:
-
Too few bits configured — the module stops clocking before the encoder has finished transmitting, truncating the position value.
-
Too many bits configured — the module continues clocking after the encoder has finished, reading invalid trailing bits as part of the position value.
Consult your encoder’s datasheet for its exact data width. Common SSI encoder resolutions are 12, 13, 16, and 25 bits. Multi-turn encoders may transmit additional bits for the turn count (e.g., 12 bits of single-turn position plus 13 bits of multi-turn count for a total of 25 data bits).
|
Important
|
Common Errors
|
SSI Parity (P)
To set the parity type used for error detection on the SSI data frame, call naibrd_ENC_SetSSI_Parity():
check_status(naibrd_ENC_SetSSI_Parity(cardIndex, module, chan, parity));
-
NAI_ENC_SSI_PARITY_EVEN— even parity. The parity bit is set so that the total number of 1-bits in the data frame (including the parity bit) is even. -
NAI_ENC_SSI_PARITY_ODD— odd parity. The parity bit is set so that the total number of 1-bits is odd.
This setting must match the parity scheme configured on your encoder. If the parity type is mismatched and parity checking is enabled, every frame will generate a parity error. Consult your encoder’s datasheet for its parity configuration.
Note that setting the parity type alone does not enable parity checking. You must also enable parity checking with the PC command (see SSI Parity Check Enable (PC)).
|
Important
|
Common Errors
|
SSI Parity Check Enable (PC)
To enable or disable parity checking on the SSI data frame, call naibrd_ENC_SetSSI_ParityEnable():
check_status(naibrd_ENC_SetSSI_ParityEnable(cardIndex, module, chan, enable));
-
TRUE— enables parity checking. The module will compare the received parity bit against the expected parity (even or odd, as configured with the P command) and set the parity error status flag if they do not match. -
FALSE— disables parity checking. The parity bit in the SSI frame is ignored.
When parity checking is enabled and the encoder includes a parity bit in its SSI frame, the module automatically validates each received frame. A parity error indicates that one or more bits were corrupted during transmission — typically caused by electrical noise, cable problems, or incorrect data bits / parity type configuration.
If your encoder does not transmit a parity bit, leave parity checking disabled. Enabling it when the encoder does not send a parity bit will generate false parity errors on every frame.
|
Important
|
Common Errors
|
SSI Zero Bit Enable (ZB)
To enable or disable the zero bit (also called the "start bit" or "idle bit") in the SSI frame, call naibrd_ENC_SetSSI_ZeroBitEnable():
check_status(naibrd_ENC_SetSSI_ZeroBitEnable(cardIndex, module, chan, enable));
-
TRUE— enables zero bit handling. The module expects the encoder to transmit a zero bit after the data bits and before the next idle period. This zero bit is part of the SSI protocol specification and signals the end of the data frame. -
FALSE— disables zero bit handling. The module does not expect or process a trailing zero bit.
Most standard SSI encoders include the zero bit as part of the protocol. If your encoder follows the standard SSI specification, enable this setting. Some non-standard or simplified SSI implementations may omit the zero bit — consult your encoder’s datasheet.
|
Important
|
Common Errors
|
Triggering a Data Transfer (T)
To initiate an SSI data transfer, call naibrd_ENC_SSI_TriggerData():
nai_status_t status = check_status(naibrd_ENC_SSI_TriggerData(cardIndex, module, chan));
if (status == NAI_SUCCESS)
{
printf("Triggered SSI clock, SSI data refreshed. \n\n");
}
This command instructs the module to generate a burst of clock pulses on Port A (in controller mode) and capture the encoder’s response on Port B. After the trigger completes, the position data registers are updated with the new encoder position, which you can then read with naibrd_ENC_GetSSI_Data() and naibrd_ENC_GetSSI_GreyData().
In controller mode, the trigger causes the module to generate exactly the number of clock pulses specified by the data bits setting (plus any parity and zero bit pulses, if enabled). In listener mode, the trigger command has no effect because the module is passively monitoring an external clock — data is captured whenever the external controller clocks the encoder.
A typical usage pattern in your own application:
-
Configure SSI parameters (mode, clock, data bits, parity).
-
Call
naibrd_ENC_SSI_TriggerData()to initiate a transfer. -
Call
naibrd_ENC_GetSSI_Data()to read the updated position. -
Repeat steps 2-3 at your desired update rate.
|
Important
|
Common Errors
|
SSI Status (STAT)
To monitor the health and state of the SSI channel, call naibrd_ENC_GetSSI_Status() with each status flag:
nai_status_bit_t status;
check_status(naibrd_ENC_GetSSI_Status(cardIndex, module, chan, NAI_ENC_SSI_STATUS_NEWDATA, &status));
check_status(naibrd_ENC_GetSSI_Status(cardIndex, module, chan, NAI_ENC_SSI_STATUS_OVERFLOW, &status));
check_status(naibrd_ENC_GetSSI_Status(cardIndex, module, chan, NAI_ENC_SSI_STATUS_PARITY_ERROR, &status));
check_status(naibrd_ENC_GetSSI_Status(cardIndex, module, chan, NAI_ENC_SSI_STATUS_BUSY, &status));
check_status(naibrd_ENC_GetSSI_Status(cardIndex, module, chan, NAI_ENC_SSI_STATUS_WATCHDOG_ERROR, &status));
check_status(naibrd_ENC_GetSSI_Status(cardIndex, module, chan, NAI_ENC_SSI_STATUS_EXTRA, &status));
The available status flags are:
-
NewData (
NAI_ENC_SSI_STATUS_NEWDATA) — set when a new SSI frame has been received since the last read. Indicates fresh position data is available. -
Overflow (
NAI_ENC_SSI_STATUS_OVERFLOW) — set when a new frame arrived before the previous frame was read. This means your application is not reading data fast enough to keep up with the SSI update rate. -
Parity Error (
NAI_ENC_SSI_STATUS_PARITY_ERROR) — set when the received parity bit does not match the expected parity. Indicates data corruption, typically from electrical noise or misconfigured parity settings. Only meaningful when parity checking is enabled. -
Busy (
NAI_ENC_SSI_STATUS_BUSY) — set when an SSI transfer is currently in progress. If you read data while busy is asserted, the value may be from the previous frame rather than the current one. -
Watchdog Error (
NAI_ENC_SSI_STATUS_WATCHDOG_ERROR) — set when the expected SSI response was not received within the timeout period. This typically indicates that the encoder is not connected, not powered, or not responding to clock signals. -
Extra (
NAI_ENC_SSI_STATUS_EXTRA) — set when extra bits were received beyond the expected data width. This usually means the data bits setting is too low for the encoder, or the zero bit configuration does not match the encoder’s frame format.
In your own application, check these status flags after each triggered read to verify data integrity. The parity error, watchdog error, and overflow flags are especially important for safety-critical position-sensing applications.
|
Important
|
Common Errors
|
Troubleshooting Reference
|
Note
|
This section summarizes errors covered in the preceding sections. Consult your module’s manual for hardware-specific diagnostics and detailed register descriptions. |
| Error / Symptom | Possible Causes | Suggested Resolution |
|---|---|---|
No board found |
Board not powered; incorrect interface or address in configuration file. |
Verify board power and physical connections. Check configuration file settings. |
Connection timeout |
Network misconfiguration; firewall blocking; incorrect bus settings for PCI/PCIe. |
Confirm IP settings, disable firewalls for testing, verify bus configuration. |
Module not recognized (channel count = 0) |
Selected slot does not contain an encoder module; unsupported module ID. |
Verify slot population using the board menu. Check that the module type is supported. |
No data after trigger |
Encoder not connected or not powered; SSI mode not set to controller; I/O format incorrect. |
Verify encoder wiring and power. Set mode to controller. Set Port A to output and Port B to input. |
Garbled or bit-shifted data |
Wrong clock edge polarity; data bits setting does not match encoder resolution. |
Try the opposite clock edge. Verify data bits match the encoder’s datasheet. |
Persistent parity errors |
Parity type mismatch (even vs. odd); data bits incorrect (parity bit read at wrong position); encoder does not transmit parity but checking is enabled. |
Match parity type to encoder specification. Verify data bits. Disable parity checking if encoder has no parity bit. |
Persistent watchdog errors |
Encoder not responding; no physical connection; incorrect SSI mode (listener when controller is needed). |
Check encoder power and wiring. Ensure mode is set to controller. |
Overflow flag |
Application not reading data fast enough; trigger rate exceeds read rate. |
Read data more frequently or reduce the trigger rate. |
Extra bits flag |
Data bits setting too low for encoder; zero bit configuration mismatch. |
Increase data bits to match encoder resolution. Enable or disable zero bit to match encoder frame format. |
Data does not change |
Trigger not issued; encoder shaft not moving; listener mode (no external controller driving clock). |
Issue a trigger command. Verify encoder is free to rotate. In listener mode, verify external clock source. |
Position wraps unexpectedly |
Data bits set lower than encoder resolution, truncating the position value. |
Set data bits to match the full resolution of your encoder. |
False parity errors on every frame |
Parity checking enabled but encoder does not include a parity bit in its frame. |
Disable parity checking with |
Full Source
Full Source — ENC_SSI_BasicOps.c (SSK 1.x)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
/* Common Sample Program include files */
#include "include/naiapp_boardaccess_menu.h"
#include "include/naiapp_boardaccess_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "include/naiapp_boardaccess_display.h"
#include "include/naiapp_boardaccess_utils.h"
/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
#include "functions/naibrd_enc.h"
#include "advanced/nai_ether_adv.h"
static const int8_t *CONFIG_FILE = (const int8_t *)"default_ENC_SSI_BasicOps.txt";
/* Function prototypes */
int32_t Run_ENC_SSI_BasicOps(int32_t cardIndex, int32_t module, int32_t ModuleID);
static void Cfg_ENC_Channel(int32_t cardIndex, int32_t module, int32_t MaxChannel);
static void Display_ENC_SSIChannelCfg(int32_t cardIndex, int32_t module, int32_t chan);
static nai_status_t Display_ENC_SSIStatus(int32_t paramCount, int32_t* p_params);
static nai_status_t View_ENC_Config(int32_t paramCount, int32_t* p_params);
static nai_status_t Configure_ENC_InputConfig(int32_t paramCount, int32_t* p_params);
static nai_status_t Configure_ENC_SSIMode(int32_t paramCount, int32_t* p_params);
static nai_status_t Configure_ENC_SSIClockPeriod(int32_t paramCount, int32_t* p_params);
static nai_status_t Configure_ENC_SSIClockEdge(int32_t paramCount, int32_t* p_params);
static nai_status_t Configure_ENC_SSIDataBits(int32_t paramCount, int32_t* p_params);
static nai_status_t Configure_ENC_SSIParity(int32_t paramCount, int32_t* p_params);
static nai_status_t Configure_ENC_SSIParityEn(int32_t paramCount, int32_t* p_params);
static nai_status_t Configure_ENC_SSIZeroBitEn(int32_t paramCount, int32_t* p_params);
static const int32_t DEF_ENC_CHANNEL = 1;
/****** Command Table *******/
enum enc_ssi_basicops_commands
{
ENC_SSI_BAISCOP_CMD_VIEW_CONFIG,
ENC_SSI_BASICOP_CMD_INPUT_CONFIG,
ENC_SSI_BASICOP_CMD_SETMODE,
ENC_SSI_BASICOP_CMD_CLOCK_PERIOD,
ENC_SSI_BASICOP_CMD_CLOCK_EDGE,
ENC_SSI_BASICOP_CMD_DATABITS,
ENC_SSI_BASICOP_CMD_PARITY,
ENC_SSI_BASICOP_CMD_PARITY_EN,
ENC_SSI_BASICOP_CMD_ZEROBIT_EN,
ENC_SSI_BASICOP_CMD_TRIGGER_DATA,
ENC_SSI_BASICOP_CMD_STATUS,
ENC_SSI_BASICOP_CMD_COUNT
};
/****** Command Tables *******/
naiapp_cmdtbl_params_t ENC_SSI_BasicOpMenuCmds[] =
{
{"V", "View Current Config", ENC_SSI_BAISCOP_CMD_VIEW_CONFIG, View_ENC_Config},
{"I", "Set Input Configuration", ENC_SSI_BASICOP_CMD_INPUT_CONFIG, Configure_ENC_InputConfig},
{"M", "Set SSI Mode", ENC_SSI_BASICOP_CMD_SETMODE, Configure_ENC_SSIMode},
{"C", "Set SSI Clock Period", ENC_SSI_BASICOP_CMD_CLOCK_PERIOD, Configure_ENC_SSIClockPeriod},
{"E", "Set SSI Clock EdgeLevel", ENC_SSI_BASICOP_CMD_CLOCK_EDGE, Configure_ENC_SSIClockEdge},
{"D", "Set SSI DataBits", ENC_SSI_BASICOP_CMD_DATABITS, Configure_ENC_SSIDataBits},
{"P", "Set SSI Parity", ENC_SSI_BASICOP_CMD_PARITY, Configure_ENC_SSIParity},
{"PC", "Enable/Disable ParityCheck", ENC_SSI_BASICOP_CMD_PARITY_EN, Configure_ENC_SSIParityEn},
{"ZB", "Enable/Disable ZeroBit", ENC_SSI_BASICOP_CMD_ZEROBIT_EN, Configure_ENC_SSIZeroBitEn},
{"T", "Trigger Data Transfer", ENC_SSI_BASICOP_CMD_TRIGGER_DATA, NULL},
{"STAT", "Display SSI Status", ENC_SSI_BASICOP_CMD_STATUS, Display_ENC_SSIStatus}
};
/**************************************************************************************************************/
/**
<summary>
The purpose of the ENC_SSI_BasicOps is to illustrate the methods to call in the naibrd library to perform basic
SSI operations with the encoder modules for configuration setup, controlling the drive outputs, and reading
SSI data.
The following system configuration routines from the nai_sys_cfg.c file are called to assist with the configuration
setup for this program prior to calling the naibrd ENC routines.
- ClearDeviceCfg
- QuerySystemCfg
- DisplayDeviceCfg
- GetBoardSNModCfg
- SaveDeviceCfg
</summary>
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
int32_t ENC_SSI_BasicOps(void)
#else
int32_t main(void)
#endif
{
bool_t stop = 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) == TRUE)
{
while (stop != TRUE)
{
/* Query the user for the card index */
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
/* Query the user for the module number */
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
if (stop != TRUE)
{
moduleID = naibrd_GetModuleID(cardIndex, module);
if ((moduleID != 0))
{
Run_ENC_SSI_BasicOps(cardIndex, module, moduleID);
}
}
}
printf("\nType Q to quit or Enter key to restart application:\n");
stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
}
}
printf("\nType the Enter key to exit the program: ");
naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
naiapp_access_CloseAllOpenCards();
return 0;
}
/**************************************************************************************************************/
/**
<summary>
Run_ENC_SSI_BasicOps prompts the user for the card, module and channel to use for the application and calls
Cfg_ENC_Channel if the card, module, channel is valid for as a discrete module.
</summary>
*/
/**************************************************************************************************************/
int32_t Run_ENC_SSI_BasicOps(int32_t cardIndex, int32_t module, int32_t ModuleID)
{
int32_t MaxChannel;
MaxChannel = naibrd_ENC_GetChannelCount(ModuleID);
if (MaxChannel == 0)
{
printf(" *** Module selection not recognized as DSW module. ***\n\n");
}
else
{
Cfg_ENC_Channel(cardIndex, module, MaxChannel);
}
return cardIndex;
}
/**************************************************************************************************************/
/**
<summary>
Cfg_ENC_Channel handles calling the Display_ENC_ChannelCfg routine to display the encoder channel configuration
and calling the routines associated with the user's menu commands.
</summary>
*/
/**************************************************************************************************************/
static void Cfg_ENC_Channel(int32_t cardIndex, int32_t module, int32_t MaxChannel)
{
bool_t bQuit = FALSE;
bool_t bContinue = TRUE;
bool_t bCmdFound = FALSE;
int32_t defaultchan = 1;
nai_status_t status = (nai_status_t)0;
int32_t cmd;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
naiapp_AppParameters_t enc_params;
p_naiapp_AppParameters_t enc_ssi_params = &enc_params;
enc_ssi_params->cardIndex = cardIndex;
enc_ssi_params->module = module;
enc_ssi_params->maxChannels = MaxChannel;
while (bContinue)
{
printf(" \r\n\r\n");
printf("Channel selection \r\n");
printf("================= \r\n");
defaultchan = DEF_ENC_CHANNEL;
bQuit = naiapp_query_ChannelNumber(MaxChannel, defaultchan, &enc_ssi_params->channel);
naiapp_utils_LoadParamMenuCommands(ENC_SSI_BASICOP_CMD_COUNT, ENC_SSI_BasicOpMenuCmds);
while (bContinue)
{
Display_ENC_SSIChannelCfg(cardIndex, module, enc_ssi_params->channel);
naiapp_display_ParamMenuCommands((int8_t *)"ENC SSI Basic Operation Menu");
printf("\nType ENC SSI command or %c to quit : ", NAI_QUIT_CHAR);
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt > 0)
{
bCmdFound = naiapp_utils_GetParamMenuCmdNum(inputResponseCnt, inputBuffer, &cmd);
if (bCmdFound)
{
switch (cmd)
{
case ENC_SSI_BAISCOP_CMD_VIEW_CONFIG:
case ENC_SSI_BASICOP_CMD_INPUT_CONFIG:
case ENC_SSI_BASICOP_CMD_SETMODE:
case ENC_SSI_BASICOP_CMD_CLOCK_PERIOD:
case ENC_SSI_BASICOP_CMD_CLOCK_EDGE:
case ENC_SSI_BASICOP_CMD_DATABITS:
case ENC_SSI_BASICOP_CMD_PARITY:
case ENC_SSI_BASICOP_CMD_PARITY_EN:
case ENC_SSI_BASICOP_CMD_ZEROBIT_EN:
case ENC_SSI_BASICOP_CMD_STATUS:
ENC_SSI_BasicOpMenuCmds[cmd].func(APP_PARAM_COUNT, (int32_t*)enc_ssi_params);
break;
case ENC_SSI_BASICOP_CMD_TRIGGER_DATA:
status = check_status(naibrd_ENC_SSI_TriggerData(cardIndex, module, enc_ssi_params->channel));
if (status == NAI_SUCCESS)
{
printf("Triggered SSI clock, SSI data refreshed. \n\n");
}
break;
default:
printf("Invalid command entered\n");
break;
}
}
else
printf("Invalid command entered\n");
}
}
else
bContinue = FALSE;
}
}
}
/**************************************************************************************************************/
/**
<summary>
Display_ENC_SSIChannelCfg illustrate the methods to call in the naibrd library to retrieve the configuration states
for basic operation.
</summary>
*/
/**************************************************************************************************************/
static void Display_ENC_SSIChannelCfg(int32_t cardIndex, int32_t module, int32_t chan)
{
uint32_t ssiData = 0u;
uint32_t ssiGrayData = 0u;
check_status(naibrd_ENC_GetSSI_Data(cardIndex, module, chan, &ssiData));
check_status(naibrd_ENC_GetSSI_GreyData(cardIndex, module, chan, &ssiGrayData));
printf("\n");
printf("-----------------Data------------------\n");
printf(" SSI Data: 0x%08x \n", ssiData);
printf(" SSI Data GreyFormat: 0x%08x \n", ssiGrayData);
printf("---------------------------------------\n");
}
/**************************************************************************************************************/
/**
<summary>
View_ENC_Config displays all menu configurable Encoder settings
</summary>
*/
/**************************************************************************************************************/
static nai_status_t View_ENC_Config(int32_t paramCount, int32_t* p_params)
{
p_naiapp_AppParameters_t p_enc_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_enc_params->cardIndex;
int32_t module = p_enc_params->module;
int32_t chan = p_enc_params->channel;
nai_enc_input_mode_t inputMode = 0;
nai_enc_term_t termA = 0, termB = 0, termIndx = 0;
nai_enc_ssi_mode_t ssiMode = 0;
nai_enc_ioformat_t ioformatA = 0, ioformatB = 0, ioformatIndx = 0;
nai_enc_ssi_clock_t clockEdge = 0;
nai_enc_ssi_parity_t parity = 0;
float64_t inputThreshold = 0;
bool_t highVoltA = 0, highVoltB = 0, highVoltIndx = 0;
bool_t parityEn = 0;
bool_t zeroBitEn = 0;
int32_t clockRate = 0;
int32_t dataBits = 0;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
check_status(naibrd_ENC_GetInputMode(cardIndex, module, chan, &inputMode));
check_status(naibrd_ENC_GetInputTermination(cardIndex, module, chan, NAI_ENC_PORT_A, &termA));
check_status(naibrd_ENC_GetInputTermination(cardIndex, module, chan, NAI_ENC_PORT_B, &termB));
check_status(naibrd_ENC_GetInputTermination(cardIndex, module, chan, NAI_ENC_PORT_Index, &termIndx));
check_status(naibrd_ENC_GetInputThreshold(cardIndex, module, chan, &inputThreshold));
check_status(naibrd_ENC_GetHighVoltEnable(cardIndex, module, chan, NAI_ENC_PORT_A, &highVoltA));
check_status(naibrd_ENC_GetHighVoltEnable(cardIndex, module, chan, NAI_ENC_PORT_B, &highVoltB));
check_status(naibrd_ENC_GetHighVoltEnable(cardIndex, module, chan, NAI_ENC_PORT_Index, &highVoltIndx));
check_status(naibrd_ENC_GetSSI_Mode(cardIndex, module, chan, &ssiMode));
check_status(naibrd_ENC_GetIOFormat(cardIndex, module, chan, NAI_ENC_PORT_A, &ioformatA));
check_status(naibrd_ENC_GetIOFormat(cardIndex, module, chan, NAI_ENC_PORT_B, &ioformatB));
check_status(naibrd_ENC_GetIOFormat(cardIndex, module, chan, NAI_ENC_PORT_Index, &ioformatIndx));
check_status(naibrd_ENC_GetSSI_ClockRate(cardIndex, module, chan, &clockRate));
check_status(naibrd_ENC_GetSSI_ClockEdgeLevel(cardIndex, module, chan, &clockEdge));
check_status(naibrd_ENC_GetSSI_DataBits(cardIndex, module, chan, &dataBits));
check_status(naibrd_ENC_GetSSI_Parity(cardIndex, module, chan, &parity));
check_status(naibrd_ENC_GetSSI_ParityEnable(cardIndex, module, chan, &parityEn));
check_status(naibrd_ENC_GetSSI_ZeroBitEnable(cardIndex, module, chan, &zeroBitEn));
printf("\n === Channel %d Configuration ===\n\n", chan);
printf("InputMode: %s\n", inputMode ? "Single-Ended" : "Differential");
printf("InputTermination PortA: %s\n", termA ? "Terminated" : "Non-Terminated");
printf("InputTermination PortB: %s\n", termB ? "Terminated" : "Non-Terminated");
printf("InputTermination PortIndx: %s\n", termIndx ? "Terminated" : "Non-Terminated");
printf("InputThreshold(V): %.7f\n", inputThreshold);
printf("HighVoltage Mode PortA: %s\n", highVoltA ? "Enabled" : "Disabled");
printf("HighVoltage Mode PortB: %s\n", highVoltB ? "Enabled" : "Disabled");
printf("HighVoltage Mode PortIndx: %s\n", highVoltIndx ? "Enabled" : "Disabled");
printf("\n\n");
printf("SSI Mode: %s\n", ssiMode ? "Listener" : "Interface Controller");
printf("IOFormat PortA: %s\n", ioformatA ? "Output" : "Input");
printf("IOFormat PortB: %s\n", ioformatB ? "Output" : "Input");
printf("IOFormat PortIndx: %s\n", ioformatIndx ? "Output" : "Input");
printf("ClockPeriod(uS): %i\n", clockRate);
printf("ClockEdgeLevel: %s\n", clockEdge ? "Falling" : "Rising");
printf("DataBits: %i\n", dataBits);
printf("Parity: %s\n", parity ? "Odd" : "Even");
printf("Parity Check: %s\n", parityEn ? "Enabled" : "Disabled");
printf("ZeroBit: %s\n", zeroBitEn ? "Enabled" : "Disabled");
return NAI_SUCCESS;
}
/**************************************************************************************************************/
/**
<summary>
Configure_ENC_InputConfig handles the user request to configure input mode, input threshold, termination and
high voltage mode for the selected channel.
</summary>
*/
/**************************************************************************************************************/
static nai_status_t Configure_ENC_InputConfig(int32_t paramCount, int32_t* p_params)
{
p_naiapp_AppParameters_t p_enc_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_enc_params->cardIndex;
int32_t module = p_enc_params->module;
int32_t chan = p_enc_params->channel;
bool_t bQuit = FALSE;
bool_t bUpdateMode = FALSE, bUpdateThreshold = FALSE, bUpdateTerm = FALSE, bUpdateHighVolt = FALSE;
nai_enc_input_mode_t inputMode = NAI_ENC_INPUT_DIFFERENTIAL;
nai_enc_term_t termination = NAI_ENC_NOT_TERMINATED;
float64_t inputThreshold = 0;
bool_t highVoltageEn = FALSE;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
/* Set the input mode on channel. */
printf("\nType the desired Input Mode: ");
printf("'D'=Differential, 'S'=Single Ended, 'X'=Skip): ");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt > 0)
{
switch (toupper(inputBuffer[0]))
{
case 'D':
inputMode = NAI_ENC_INPUT_DIFFERENTIAL;
bUpdateMode = TRUE;
break;
case 'S':
inputMode = NAI_ENC_INPUT_SINGLE_ENDED;
bUpdateMode = TRUE;
break;
case 'X':
break;
default:
printf("ERROR: Invalid input mode entry\n");
break;
}
}
}
/* Set the termination type on channel. */
printf("\nType the desired Termination: ");
printf("'T'=Terminated, 'N'=Non-Terminated, 'X'=Skip): ");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt > 0)
{
switch (toupper(inputBuffer[0]))
{
case 'T':
termination = NAI_ENC_TERMINATED;
bUpdateTerm = TRUE;
break;
case 'N':
termination = NAI_ENC_NOT_TERMINATED;
bUpdateTerm = TRUE;
break;
case 'X':
break;
default:
printf("ERROR: Invalid termination entry\n");
break;
}
}
}
/* Set the input threshold voltage on channel. */
printf("\nEnter the desired input threshold voltage (0-3.75)V, 'X'=Skip: ");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt > 0)
{
if (toupper(inputBuffer[0]) == 'X')
{
bUpdateThreshold = FALSE;
}
inputThreshold = atof((const char *)inputBuffer);
bUpdateThreshold = TRUE;
}
}
/* Enable/Disable high voltage mode on channel. */
printf("\nType the desired input to enable/disable parity checking: ");
printf("'E'=Enable, 'D'=Disable, 'X'=Skip): ");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt > 0)
{
switch (toupper(inputBuffer[0]))
{
case 'E':
highVoltageEn = TRUE;
bUpdateHighVolt = TRUE;
break;
case 'D':
highVoltageEn = FALSE;
bUpdateHighVolt = TRUE;
break;
case 'X':
break;
default:
printf("ERROR: Invalid entry\n");
break;
}
}
}
if (!bQuit)
{
if (bUpdateMode)
{
check_status(naibrd_ENC_SetInputMode(cardIndex, module, chan, inputMode));
}
if (bUpdateTerm)
{
check_status(naibrd_ENC_SetInputTermination(cardIndex, module, chan, NAI_ENC_PORT_A, termination));
check_status(naibrd_ENC_SetInputTermination(cardIndex, module, chan, NAI_ENC_PORT_B, termination));
check_status(naibrd_ENC_SetInputTermination(cardIndex, module, chan, NAI_ENC_PORT_Index, termination));
}
if (bUpdateThreshold)
{
check_status(naibrd_ENC_SetInputThreshold(cardIndex, module, chan, inputThreshold));
}
if (bUpdateHighVolt)
{
check_status(naibrd_ENC_SetHighVoltEnable(cardIndex, module, chan, NAI_ENC_PORT_A, highVoltageEn));
check_status(naibrd_ENC_SetHighVoltEnable(cardIndex, module, chan, NAI_ENC_PORT_B, highVoltageEn));
check_status(naibrd_ENC_SetHighVoltEnable(cardIndex, module, chan, NAI_ENC_PORT_Index, highVoltageEn));
}
}
return NAI_SUCCESS;
}
/**************************************************************************************************************/
/**
<summary>
Configure_ENC_SSIMode handles the user request to configure the SSI mode for the selected channel and calls
the method in the naibrd library to set the SSI mode. SSI input/output pins are also configured based on the
SSI mode requested. Common control mode is also set to SSI upon selecting an SSI mode.
</summary>
*/
/**************************************************************************************************************/
static nai_status_t Configure_ENC_SSIMode(int32_t paramCount, int32_t* p_params)
{
p_naiapp_AppParameters_t p_enc_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_enc_params->cardIndex;
int32_t module = p_enc_params->module;
int32_t chan = p_enc_params->channel;
bool_t bQuit = FALSE;
bool_t bUpdateMode = FALSE;
nai_enc_ssi_mode_t mode = NAI_ENC_SSI_CONTROLLER;
nai_enc_ioformat_t portAFormat = NAI_ENC_IOFORMAT_OUTPUT;
nai_enc_ioformat_t portBFormat = NAI_ENC_IOFORMAT_INPUT;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
/* Set the SSI mode (Interface controller or Listener) on channel. */
printf("\nType the desired SSI mode ");
printf("'C'=SSI Interface Controller, 'L'=SSI Listener): ");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt > 0)
{
switch (toupper(inputBuffer[0]))
{
case 'C':
mode = NAI_ENC_SSI_CONTROLLER;
portAFormat = NAI_ENC_IOFORMAT_OUTPUT; /*Clock*/
portBFormat = NAI_ENC_IOFORMAT_INPUT; /*Data*/
bUpdateMode = TRUE;
break;
case 'L':
mode = NAI_ENC_SSI_LISTENER;
portAFormat = NAI_ENC_IOFORMAT_INPUT; /*Clock*/
portBFormat = NAI_ENC_IOFORMAT_INPUT; /*Data*/
bUpdateMode = TRUE;
break;
default:
printf("ERROR: Invalid SSI mode Entry\n");
break;
}
}
}
if (!bQuit)
{
if (bUpdateMode)
{
check_status(naibrd_ENC_SetControlMode(cardIndex, module, chan, NAI_ENC_MODE_SSI));
check_status(naibrd_ENC_SetSSI_Mode(cardIndex, module, chan, mode));
check_status(naibrd_ENC_SetIOFormat(cardIndex, module, chan, NAI_ENC_PORT_A, portAFormat));
check_status(naibrd_ENC_SetIOFormat(cardIndex, module, chan, NAI_ENC_PORT_B, portBFormat));
}
}
return (bQuit) ? NAI_ERROR_UNKNOWN : NAI_SUCCESS;
}
/**************************************************************************************************************/
/**
<summary>
Display_ENC_SSIStatus illustrates the methods to call in the naibrd library to retrieve the SSI status states.
</summary>
*/
/**************************************************************************************************************/
static nai_status_t Display_ENC_SSIStatus(int32_t paramCount, int32_t* p_params)
{
p_naiapp_AppParameters_t p_enc_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_enc_params->cardIndex;
int32_t module = p_enc_params->module;
int32_t chan = p_enc_params->channel;
nai_status_bit_t status;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
/* Available status:
NAI_ENC_SSI_STATUS_NEWDATA
NAI_ENC_SSI_STATUS_OVERFLOW
NAI_ENC_SSI_STATUS_PARITY_ERROR
NAI_ENC_SSI_STATUS_BUSY
NAI_ENC_SSI_STATUS_WATCHDOG_ERROR
NAI_ENC_SSI_STATUS_EXTRA
*/
printf("\n");
printf(" -------------------------- Status ------------------------------\n");
printf(" NewData Overflow ParityErr Busy WatchDogErr Extra\n");
printf(" ---------- ---------- ---------- ---------- ---------- ---------\n");
check_status(naibrd_ENC_GetSSI_Status(cardIndex, module, chan, NAI_ENC_SSI_STATUS_NEWDATA, &status));
printf(" %3i ", status);
check_status(naibrd_ENC_GetSSI_Status(cardIndex, module, chan, NAI_ENC_SSI_STATUS_OVERFLOW, &status));
printf(" %3i ", status);
check_status(naibrd_ENC_GetSSI_Status(cardIndex, module, chan, NAI_ENC_SSI_STATUS_PARITY_ERROR, &status));
printf(" %3i ", status);
check_status(naibrd_ENC_GetSSI_Status(cardIndex, module, chan, NAI_ENC_SSI_STATUS_BUSY, &status));
printf(" %3i ", status);
check_status(naibrd_ENC_GetSSI_Status(cardIndex, module, chan, NAI_ENC_SSI_STATUS_WATCHDOG_ERROR, &status));
printf(" %3i ", status);
check_status(naibrd_ENC_GetSSI_Status(cardIndex, module, chan, NAI_ENC_SSI_STATUS_EXTRA, &status));
printf(" %3i ", status);
printf("\n\n");
return NAI_ERROR_UNKNOWN;
}
/**************************************************************************************************************/
/**
<summary>
Configure_ENC_SSIClockPeriod handles the user request to configure the SSI clock period for the selected channel
and calls the method in the naibrd library to set the SSI clock period. Clock period is configurable from
range of 1 to 32 in steps of 1uS.
</summary>
*/
/**************************************************************************************************************/
static nai_status_t Configure_ENC_SSIClockPeriod(int32_t paramCount, int32_t* p_params)
{
p_naiapp_AppParameters_t p_enc_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_enc_params->cardIndex;
int32_t module = p_enc_params->module;
int32_t chan = p_enc_params->channel;
bool_t bQuit = FALSE;
bool_t bUpdatePeriod = FALSE;
int32_t clockRate = 0;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
/* Set the SSI clock period on channel. */
printf("\nEnter the desired clock period (1-32)uS: ");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt > 0)
{
clockRate = atoi((const char *)inputBuffer);
bUpdatePeriod = TRUE;
}
}
if (!bQuit)
{
if (bUpdatePeriod)
{
check_status(naibrd_ENC_SetSSI_ClockRate(cardIndex, module, chan, clockRate));
}
}
return (bQuit) ? NAI_ERROR_UNKNOWN : NAI_SUCCESS;
}
/**************************************************************************************************************/
/**
<summary>
Configure_ENC_SSIClockEdge handles the user request to configure the SSI clock edge for the selected channel
and calls the method in the naibrd library to set the SSI clock edge. Clock edge level determines whether
SSI data is clocked on rising or falling edge.
</summary>
*/
/**************************************************************************************************************/
static nai_status_t Configure_ENC_SSIClockEdge(int32_t paramCount, int32_t* p_params)
{
p_naiapp_AppParameters_t p_enc_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_enc_params->cardIndex;
int32_t module = p_enc_params->module;
int32_t chan = p_enc_params->channel;
bool_t bQuit = FALSE;
bool_t bUpdateClockEdge = FALSE;
nai_enc_ssi_clock_t clockEdgeLvl = NAI_ENC_SSI_CLOCK_RISING;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
/* Set the SSI clock edge level on channel. */
printf("\nType the desired edge level to clock SSI data on: ");
printf("'R'=Rising Edge, 'F'=Falling Edge): ");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt > 0)
{
switch (toupper(inputBuffer[0]))
{
case 'R':
clockEdgeLvl = NAI_ENC_SSI_CLOCK_RISING;
bUpdateClockEdge = TRUE;
break;
case 'F':
clockEdgeLvl = NAI_ENC_SSI_CLOCK_FALLING;
bUpdateClockEdge = TRUE;
break;
default:
printf("ERROR: Invalid SSI clock edge entry\n");
break;
}
}
}
if (!bQuit)
{
if (bUpdateClockEdge)
{
check_status(naibrd_ENC_SetSSI_ClockEdgeLevel(cardIndex, module, chan, clockEdgeLvl));
}
}
return (bQuit) ? NAI_ERROR_UNKNOWN : NAI_SUCCESS;
}
/**************************************************************************************************************/
/**
<summary>
Configure_ENC_SSIDataBits handles the user request to configure the number of SSI data bits for the selected
channel and calls the method in the naibrd library to set the number of SSI data bits. DataBits correspond to
expected data width are configurable from 1 to 31.
</summary>
*/
/**************************************************************************************************************/
static nai_status_t Configure_ENC_SSIDataBits(int32_t paramCount, int32_t* p_params)
{
p_naiapp_AppParameters_t p_enc_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_enc_params->cardIndex;
int32_t module = p_enc_params->module;
int32_t chan = p_enc_params->channel;
bool_t bQuit = FALSE;
bool_t bUpdatePeriod = FALSE;
int32_t dataBits = 0;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
/* Set the SSI data bits on channel. */
printf("\nEnter the expected number of data bits (1-31): ");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt > 0)
{
dataBits = atoi((const char *)inputBuffer);
bUpdatePeriod = TRUE;
}
}
if (!bQuit)
{
if (bUpdatePeriod)
{
check_status(naibrd_ENC_SetSSI_DataBits(cardIndex, module, chan, dataBits));
}
}
return (bQuit) ? NAI_ERROR_UNKNOWN : NAI_SUCCESS;
}
/**************************************************************************************************************/
/**
<summary>
Configure_ENC_SSIParity handles the user request to configure the SSI parity for the selected channel
and calls the method in the naibrd library to set the SSI parity. Parity can be configured as even or odd.
</summary>
*/
/**************************************************************************************************************/
static nai_status_t Configure_ENC_SSIParity(int32_t paramCount, int32_t* p_params)
{
p_naiapp_AppParameters_t p_enc_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_enc_params->cardIndex;
int32_t module = p_enc_params->module;
int32_t chan = p_enc_params->channel;
bool_t bQuit = FALSE;
bool_t bUpdateParity = FALSE;
nai_enc_ssi_parity_t parity = NAI_ENC_SSI_PARITY_EVEN;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
/* Set the SSI clock edge level on channel. */
printf("\nType the desired SSI parity: ");
printf("'E'=Even, 'O'=Odd): ");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt > 0)
{
switch (toupper(inputBuffer[0]))
{
case 'E':
parity = NAI_ENC_SSI_PARITY_EVEN;
bUpdateParity = TRUE;
break;
case 'O':
parity = NAI_ENC_SSI_PARITY_ODD;;
bUpdateParity = TRUE;
break;
default:
printf("ERROR: Invalid SSI parity entry\n");
break;
}
}
}
if (!bQuit)
{
if (bUpdateParity)
{
check_status(naibrd_ENC_SetSSI_Parity(cardIndex, module, chan, parity));
}
}
return (bQuit) ? NAI_ERROR_UNKNOWN : NAI_SUCCESS;
}
/**************************************************************************************************************/
/**
<summary>
Configure_ENC_SSIParityEn handles the user request to enable/disable the SSI parity check for the selected
channel and calls the method in the naibrd library to enable/disable the SSI parity check.
</summary>
*/
/**************************************************************************************************************/
static nai_status_t Configure_ENC_SSIParityEn(int32_t paramCount, int32_t* p_params)
{
p_naiapp_AppParameters_t p_enc_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_enc_params->cardIndex;
int32_t module = p_enc_params->module;
int32_t chan = p_enc_params->channel;
bool_t bQuit = FALSE;
bool_t bUpdateParityEn = FALSE;
bool_t enable = FALSE;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
/* Set the SSI clock edge level on channel. */
printf("\nType the desired input to enable/disable parity checking: ");
printf("'E'=Enable, 'D'=Disable): ");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt > 0)
{
switch (toupper(inputBuffer[0]))
{
case 'E':
enable = TRUE;
bUpdateParityEn = TRUE;
break;
case 'D':
enable = FALSE;
bUpdateParityEn = TRUE;
break;
default:
printf("ERROR: Invalid entry\n");
break;
}
}
}
if (!bQuit)
{
if (bUpdateParityEn)
{
check_status(naibrd_ENC_SetSSI_ParityEnable(cardIndex, module, chan, enable));
}
}
return (bQuit) ? NAI_ERROR_UNKNOWN : NAI_SUCCESS;
}
/**************************************************************************************************************/
/**
<summary>
Configure_ENC_SSIZeroBitEn handles the user request to enable/disable the SSI zero bit for the selected
channel and calls the method in the naibrd library to enable/disable the SSI zero bit.
</summary>
*/
/**************************************************************************************************************/
static nai_status_t Configure_ENC_SSIZeroBitEn(int32_t paramCount, int32_t* p_params)
{
p_naiapp_AppParameters_t p_enc_params = (p_naiapp_AppParameters_t)p_params;
int32_t cardIndex = p_enc_params->cardIndex;
int32_t module = p_enc_params->module;
int32_t chan = p_enc_params->channel;
bool_t bQuit = FALSE;
bool_t bUpdateZeroBitEn = FALSE;
bool_t enable = FALSE;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
#if defined (WIN32)
UNREFERENCED_PARAMETER(paramCount);
#endif
/* Set the SSI clock edge level on channel. */
printf("\nType the desired input to enable/disable zero bit: ");
printf("'E'=Enable, 'D'=Disable): ");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt > 0)
{
switch (toupper(inputBuffer[0]))
{
case 'E':
enable = TRUE;
bUpdateZeroBitEn = TRUE;
break;
case 'D':
enable = FALSE;
bUpdateZeroBitEn = TRUE;
break;
default:
printf("ERROR: Invalid entry\n");
break;
}
}
}
if (!bQuit)
{
if (bUpdateZeroBitEn)
{
check_status(naibrd_ENC_SetSSI_ZeroBitEnable(cardIndex, module, chan, enable));
}
}
return (bQuit) ? NAI_ERROR_UNKNOWN : NAI_SUCCESS;
}