Difference between revisions of "826"

From Sensoray Technical Wiki
Jump to: navigation, search
(Oversampling)
(Usage)
 
(879 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
[[File:826 photo.jpg|thumb|Model 826 board]]
 
[[File:826 photo.jpg|thumb|Model 826 board]]
  
This is the technical wiki page for Sensoray's [http://www.sensoray.com/products/826.htm model 826], a versatile analog and digital I/O system on a PCI Express board. The board has 48 digital I/Os with edge detection, sixteen 16-bit analog inputs, eight 16-bit analog outputs, six 32-bit counter channels, a watchdog timer with fail-safe controller, and a flexible signal router.
+
This is the top-level wiki page for Sensoray's [http://www.sensoray.com/products/826.htm model 826], a versatile analog and digital I/O system on a PCI Express board. The board has 48 digital I/Os with edge detection, sixteen 16-bit analog inputs, eight 16-bit analog outputs, six 32-bit counter channels with quadrature clock decoders, three-stage watchdog timer with fail-safe controller, and a flexible signal router.
  
==Counters==
+
;Related pages
 
+
Each board subsystem has a dedicated wiki page:
===Snapshot counts upon match===
+
* [[826 ADC|ADC]] - analog input system
 
+
* [[826 DAC|DACs]] - analog output system
When a snapshot is caused by counts equal to a compare register, the snapshot counts will always equal the compare register value. Similarly, when a snapshot is caused by counts reaching zero, the snapshot counts will always be zero.
+
* [[826 DIOs|DIOs]] - general-purpose digital I/Os
 
+
* [[826 counters|Counters]] - counter/timers, including appnotes for interfacing incremental encoders
===How to use interrupts===
+
* [[826 watchdog|Watchdog]] - watchdog timer and fail-safe controller
 
+
:''I want to use interrupts to perform actions after a time delay. I see that counters have an "Interrupt System (IRQ)" signal but have no idea how to access it.''
+
 
+
An interrupt request (IRQ) is generated whenever a counter snapshot is captured. Every IRQ source on the 826 is associated with a blocking API function, which manages IRQs for you so that you need not be concerned with the complexities of interrupts. In the case of counters, the blocking API function is <code>S826_CounterSnapshotRead()</code>. Simply call this API function and counter IRQs will automatically be configured and handled.
+
 
+
A simple way to implement a delayed interrupt is to preload the counter with the desired time delay, configure it to count down, and have it capture a snapshot (and thus generate an IRQ) when it reaches zero counts. To wait for the interrupt, call <code>S826_CounterSnapshotRead()</code> with a non-zero <code>tmax</code> value (maximum wait time, which must be longer than the delay time). The function will return upon interrupt and you can then perform the desired actions. For example:
+
  
 +
;Please note:
 +
* Code and circuit examples are intended to function as described, but this is not guaranteed. If you discover an error, please [http://www.sensoray.com/support/message.htm?s=Web%20feedback inform the webmaster].
 +
* In code examples, error checking has been simplified or omitted for clarity. It is recommended to always perform error checking in your production software.
 +
* C language examples depend on header file <code>826api.h</code>, which should be included at the top of your source code like this:
 
  #include "826api.h"
 
  #include "826api.h"
 
// Wait 0.5 seconds while other threads are allowed to run ------------------
 
 
// Configure the delay timer:
 
S826_CounterModeWrite(0, 0, 0x01400020);      // Configure counter0: 1 MHz down counter, auto preload @startup.
 
S826_CounterPreloadWrite(0, 0, 0, 500000);    // Delay time in microseconds (0.5 seconds).
 
S826_CounterSnapshotConfigWrite(0, 0,        // Configure snapshots:
 
    S826_SSRMASK_ZERO                        //  capture snapshot when counts==0
 
    | (S826_SSRMASK_ZERO << 16),              //  disable subsequent snapshots when counts==0
 
    S826_BITSET);                            //  don't alter any other snapshot enables
 
 
// Now do the delay:
 
S826_CounterStateWrite(0, 0, 1);              // Start the delay timer running.
 
S826_CounterSnapshotRead(0, 0,                // Block while waiting for timer:
 
    NULL, NULL, NULL,                          //  ignore snapshot counts, timestamp and reason
 
    S826_WAIT_INFINITE);                      //  don't timeout
 
 
printf("Delay time has elapsed!");            // TODO: INSERT YOUR DESIRED ACTIONS HERE
 
  
Note that the calling thread cannot do anything else while it waits for <code>S826_CounterSnapshotRead()</code> to return, although other threads can still do productive work.
+
==Timestamp generator==
  
===Periodic timer===
+
The timestamp generator is a free-running 32-bit counter that serves as a time reference. The counter increments once per microsecond and overflows (to zero, without notification) every 2<sup>32</sup> &micro;s (approximately 71.6 minutes). It is a binary counter and consequently does not keep track of the date or time-of-day. At any moment, the current count may be sampled; such a sample is called a ''timestamp''.
  
:''How can I use a counter to call a function periodically?''
+
A timestamp is automatically appended to every counter snapshot and to every ADC sample so that application programs can know (to within 1 &micro;s) when each sample was acquired. Also, application programs can read the timestamp generator at any time to get a timestamp.
  
Configure the counter so that it repeatedly counts down to zero and then preloads. The preload value determines the time period. A snapshot is captured every time zero counts is reached, which causes <code>S826_CounterSnapshotRead()</code> to return, whereupon you can call your periodic function.
+
===Usage===
  
First, configure the counter and start it running:
+
Timestamps are particularly useful for precisely measuring the elapsed time between hardware events. Calculation of elapsed time is easy (a single subtraction) as long as the time interval doesn't exceed 71.6 minutes. It can be used in a variety of ways, including [[826 counters#Measuring speed|measuring speed]] and [[826 counters#Serial data capture|capturing serial data]].
  
#include "826api.h"
+
If desired, an application program can directly read the current time as shown below:
+
// Configure counter so it can be used to call PeriodicFunction() 10 times per second
+
+
S826_CounterModeWrite(0, 0, 0x01C02020);      // Counter0: 1 MHz down counter; preload @startup and counts==0.
+
S826_CounterPreloadWrite(0, 0, 0, 100000);    // Period in microseconds (0.1 seconds).
+
S826_CounterSnapshotConfigWrite(0, 0,        // Configure snapshots:
+
    S826_SSRMASK_ZERO,                        //  capture snapshot when counts==0
+
    S826_BITWRITE);                          //  disable all other snapshot triggers
+
S826_CounterStateWrite(0, 0, 1);              // Start the periodic timer running.
+
+
Now execute the following code in its own thread. This code uses hardware interrupts, which allows other threads to run while this one waits for the next periodic counter interrupt.
+
 
+
// Repeat while no errors detected:
+
while (S826_CounterSnapshotRead(0, 0,        // Block until next period.
+
      NULL, NULL, NULL,                      //    (ignore snapshot values)
+
      S826_WAIT_INFINITE) = S826_ERR_OK)      //    (disable function timeout)
+
  PeriodicFunction();                        // Execute the periodic function.
+
 
+
Alternatively, if you need to perform other processing while waiting for the next period and cannot use another thread to do so, you can poll the counter by calling <code>S826_CounterSnapshotRead()</code> with a zero wait time:
+
  
  while (1) { // Repeat forever:
+
  // Read the timestamp generator's current count.
  uint errcode = S826_CounterSnapshotRead(   // Poll to see if period has elapsed (but don't block).
+
uint CurrentTimestamp(uint board)
      0, 0, NULL, NULL, NULL, 0);
+
{
   if (errcode == S826_ERR_OK)                // If it's a new period
+
   uint t;
    PeriodicFunction();                       //  execute the periodic function.
+
   S826_TimestampRead(board, &t);
   else if (errcode != S826_ERR_NOTREADY)     // Else if fatal error detected
+
   return t;
    break;                                   //  exit the polling loop.
+
   else                                        // Else
+
    DoSomeOtherStuff();                       //  do other processing.
+
 
  }
 
  }
  
===Incremental encoders===
+
The following example shows a simple application of direct timestamp reads:
  
====Encoder wiring====
+
// Example: Use board0 to measure system Sleep() time.
 +
uint t1, t0 = CurrentTimestamp(0);  // Get start time.
 +
Sleep(25);                          // Sleep approximately 25 ms.
 +
t1 = CurrentTimestamp(0);            // Get end time.
 +
printf("Slept %d &micro;s", t1 - t0);      // Display actual sleep time.
  
:''I want to connect two TTL/CMOS incremental encoders to counter channels 0 and 1 &mdash; what's the correct way to do this?''
+
==Board ID==
  
Connect the encoders as shown below. If the encoder has a "Z" (index) output, connect Z to the counter's +IX input.  
+
The "BOARD NUM" switches (at top edge of board near mounting bracket) assign the board ID used by software. The ID is binary coded on the four switches and can be programmed to any value from 0 (default) to 15. A board's ID determines the corresponding ''bit'' that will be set to '1' in the value returned by <code>S826_SystemOpen</code>. If you have a single 826 board, the return value will be <code>(2^ID)</code>. If you have multiple boards, the return value is the sum of <code>(2^ID)</code> for each board. You can enter the return value [http://www.sensoray.com/support/826_boardID.htm here] to quickly determine its meaning.
  
[[File:826 ttl encoder.gif|350px|center|alt=Wiring diagram showing how to connect two TTL/CMOS-compatible single-ended incremental encoders to the 826 board using counter channels 0 and 1]]
+
;Examples
 +
* You have one board with ID set to 0, so the value returned by <code>S826_SystemOpen</code> will be <code>(2^0) = 1</code>.
 +
* You have two boards with IDs set to 1 and 4, so the value returned by <code>S826_SystemOpen</code> will be <code>(2^1)+(2^4) = 2+16 = 18</code>.
  
====Programming fundamentals====
+
This code snippet will tell you the meaning of the value returned by <code>S826_SystemOpen</code>:
  
:''Which functions should I use for incremental encoders?''
+
int id, flags = S826_SystemOpen();
 +
if (flags < 0)
 +
  printf("S826_SystemOpen returned error code %d", flags);
 +
else if (flags == 0)
 +
  printf("No boards were detected");
 +
else {
 +
  printf("Boards were detected with these IDs:");
 +
  for (id = 0; id < 16; id++) {
 +
    if (flags & (1 << id))
 +
      printf(" %d", id);
 +
  }
 +
}
  
The flexible counter architecture allows for many options, but basic operation works as follows:
+
==Hardware version==
  
First configure and enable the counter channel:
+
===Reading the PWB revision===
  
#include "826api.h"
+
The circuit board revision (PWB rev) is visible on the solder-side of the 826 board (opposite the mounting bracket, on the bottom corner). <code>S826_VersionRead</code> returns the PWB rev as a numeric value with decimal range [0:31], which corresponds to a text string in the standard ASME version letter sequence. The following code shows how to convert this 32-bit value to the alphabetic revision code seen on the board:
+
S826_CounterModeWrite(0, 0, 0x00000070)// Configure counter 0 as incremental encoder interface.
+
S826_CounterStateWrite(0, 0, 1);          // Start tracking encoder counts.
+
  
To read the instantaneous encoder counts without invoking a snapshot:
+
  // Read and display version info from board 0
 
+
  uint counts;
+
S826_CounterRead(0, 0, &counts);          // Read current encoder counts.
+
printf("Encoder counts = %d\n", counts);  // Display encoder counts.
+
 
+
When reading instantaneous counts you may need to know when the counts were sampled. You ''could'' rely on your software and operating system to sample the counts at precise times, but there's an easier and more accurate way: trigger a snapshot (via software) and then read the counts and sample time &mdash; accurate to within one microsecond:
+
 
+
uint counts;      // encoder counts when the snapshot was captured
+
uint timestamp;  // time the snapshot was captured
+
 
   
 
   
  S826_CounterSnapshot(0, 0);              // Trigger snapshot on counter 0.
+
  // Extract major_version, minor_version and build_number from a 32-bit version number:
S826_CounterSnapshotRead(0, 0,            // Read the snapshot:
+
  #define VER_FIELDS(N) ((N) >> 24) & 0xFF, ((N) >> 16) & 0xFF, (N) & 0xFFFF
    &counts, &timestamp, NULL,            //  receive the snapshot info here
+
    0);                                  //  no need to wait for snapshot; it's already been captured
+
printf("Counts = %d at time = %d\n", counts, timestamp);
+
 
+
For example, two snapshots allow you to measure speed:
+
 
+
uint counts0, counts1;      // encoder counts when snapshot was captured
+
uint tstamp0, tstamp1;      // timestamp when snapshot was captured
+
+
S826_CounterSnapshot(0, 0);              // Trigger first snapshot.
+
+
// TODO: WAIT AWHILE TO ALLOW ENCODER TO MOVE
+
+
S826_CounterSnapshot(0, 0);              // Trigger second snapshot.
+
S826_CounterSnapshotRead(0, 0,            // Read the first snapshot:
+
    &counts0, &tstamp0, NULL,            //  receive the snapshot info here
+
    0);                                  //  no need to wait for snapshot; it's already been captured
+
S826_CounterSnapshotRead(0, 0,            // Read the second snapshot:
+
    &counts1, &tstamp1, NULL,            //  receive the snapshot info here
+
    0);
+
+
printf("Speed (counts/second) = %d\n", 1000000 * (counts1 - counts0) / (tstamp1 / tstamp0));
+
 
+
Encoder counts can be changed to an arbitrary value at any time. This is typically done when the encoder is at a known reference position (e.g., at startup or whenever mechanical registration is required), but not at other times as it would disrupt position tracking. To change the counts, write the new counts value to the Preload0 register and then call <code>S826_CounterPreload()</code> to force a preload:
+
 
+
  S826_CounterPreloadWrite(0, 0, 0, 12345); // Write desired counts value (12345) to Preload0 register.
+
S826_CounterPreload(0, 0, 0, 0);          // Jam Preload0 value into counter.
+
 
+
====Using interrupts with encoders====
+
 
+
This code snippet employs hardware interrupts to block the calling thread until the encoder counts equals a particular value. Other threads are allowed to run while the calling thread waits for the counter to reach the target value. A snapshot is captured when the target count is reached. The snapshot generates an interrupt request, which in turn causes <code>S826_CounterSnapshotRead()</code> to return. The example ignores the snapshot counts (which will always equal the target value as explained [[826#Snapshot counts upon match|here]]), the timestamp, and the reason code (which will always indicate a Match0 event).
+
 
+
S826_CounterCompareWrite(0, 0, 0,        // Set Compare0 register to target value:
+
    5000);                                //  5000 counts (for this example)
+
S826_CounterSnapshotConfigWrite(0, 0,    // Enable snapshots:
+
    S826_SSRMASK_MATCH0,                  //  when counts==Compare0
+
    S826_BITWRITE);                      //  disable all other snapshot triggers
+
S826_CounterSnapshotRead(0, 0,            // Wait for counter to reach target counts:
+
    NULL, NULL, NULL,                    //  ignore snapshot counts, timestamp and reason
+
    S826_WAIT_INFINITE);                  //  disable function timeout
+
printf("Counter reached target counts");
+
 
+
In some cases you may want to wait for two different count values at the same time. The following example shows how to wait for the encoder counts to reach an upper or lower threshold (whichever occurs first). Furthermore, it will only wait for a limited amount of time. To set this up, the threshold values are programmed into Compare registers and then snapshots are enabled for matches to both Compare registers. To set a limit on how long to wait, a time limit value is specified by <code>tmax</code> when calling <code>S826_CounterSnapshotRead</code>.
+
 
+
Since snapshots can now be caused by different events, we must know what triggered a snapshot in order to decide how to handle it; this is indicated by the snapshot's reason flags. Alternatively, we could use the snapshot counts value, which will always equal the threshold value that triggered the snapshot.
+
 
+
uint counts;      // encoder counts when the snapshot was captured
+
uint timestamp;  // time the snapshot was captured
+
uint reason;      // event(s) that caused the snapshot
+
uint errcode;    // API error code
+
 
   
 
   
  S826_CounterCompareWrite(0, 0, 0, 3000); // Set Compare0 register to low limit (3000 counts)
+
  const char *revchar[] = { // ASME revision sequence
  S826_CounterCompareWrite(0, 0, 1, 4000); // Set Compare1 register to high limit (4000 counts)
+
  "A", "B", "C", "D""E", "F", "G""H",
  S826_CounterSnapshotConfigWrite(0, 0,     // Enable snapshots:
+
  "J""K", "L", "M", "N""P",  "R",  "T",
    S826_SSRMASK_MATCH0                  // when counts==low limit
+
  "U", "V", "W""Y",  "AA", "AB", "AC", "AD",
    | S826_SSRMASK_MATCH1,               // or when counts==high limit
+
  "AE", "AF", "AG", "AH", "AJ", "AK", "AL", "AM"
    S826_BITWRITE);                      // disable all other snapshot triggers
+
  };
  errcode = S826_CounterSnapshotRead(0, 0// Wait for a snapshot:
+
    &counts, &timestamp, &reason,         // receive the snapshot info here
+
    10000000);                            // timeout if wait exceeds 10 seconds (10000000 us)
+
 
   
 
   
  switch (errcode) {                       // Decode and handle the snapshot:
+
  uint api, drv, bd, fpga;
   case S826_ERR_NOTREADY:
+
int errcode = S826_VersionRead(0, &api, &drv, &bd, &fpga);  // Read version info.
    S826_CounterRead(0, 0, &counts);     // snapshot not available, so read counts manually
+
if (errcode == S826_ERR_OK) {                               // If no errors then display info:
    printf("Timeout -- counter didn't reach either threshold within 10 seconds; current counts = %d", counts);
+
   printf("API version    = %d.%d.%d\n", VER_FIELDS(api));   //   API major.minor.build
    break;
+
  printf("Driver version = %d.%d.%d\n", VER_FIELDS(drv));   //  DRVR major.minor.build
   case S826_ERR_OK:
+
   printf("FPGA version  = %d.%d.%d\n", VER_FIELDS(fpga)); //  FPGA major.minor.build
    if (reason & S826_SSRMASK_MATCH0)
+
  printf("PWB revision  = Rev %s\n",   revchar[bd & 31]); //  PWB rev as seen on circuit board
      printf("Counter reached upper threshold at timestamp %d", timestamp);
+
    if (reason & S826_SSRMASK_MATCH1)
+
      printf("Counter reached lower threshold at timestamp %d", timestamp);
+
 
  }
 
  }
 +
else
 +
  printf(" S826_VersionRead returned error code %d", errcode);
  
====Measuring velocity====
+
===Rev C changes===
  
:''How can I use a counter to measure vehicle velocity at approximately 10 samples/second?''
+
Sensoray has developed Revision C of the 826 circuit board. This change was necessary due to the impending EOL (end-of-life) of a critical component. Specifically, the critical component (PCI Express interface chip) and FPGA were removed and replaced by a new FPGA, which absorbed the functions of the two removed components.
  
Velocity measurements depend on having the ability to determine the vehicle's displacement (distance traveled) at a known time. Counter snapshots are ideally suited for this task because they include both displacement and time information. To set this up, configure the counter to track displacement (by counting quadrature clocks without interruption), and then trigger 10 snapshots/second using one of these methods:
+
<u>'''Applications and developers are not affected by this change'''</u>
  
# If the counter's IX input is not being used, select the internal tick generator (set to 10 Hz) as the IX signal source, and configure the counter to capture snapshots on IX rising edges.
+
The Rev C board is fully compatible with Rev B boards and applications:
# If IX is already being used, create a thread that executes approximately 10 times per second (need not be exact). Each time the thread runs, have it call <code>S826_CounterSnapshot</code> to trigger a soft snapshot. In this case the sample rate will not be exactly 10 Hz, but velocity will still be measured precisely.
+
* Mechanical attributes are unchanged, including board dimensions and placements of connectors, switches, indicator LEDs, and hold-down bracket.
 +
* Connector pinouts, electrical and timing specifications are unchanged.
 +
* Rev C is 100% software compatible with Rev B on all software layers: application, API and driver (including user-developed drivers and APIs for RTOS, etc.).
  
Create another thread to handle the counter shapshots. Each time this thread receives a new snapshot, it can use the counts/timestamp pairs from the new and previous snapshots to precisely compute the velocity (in counts per microsecond):
+
Rev B and Rev C boards can be used interchangeably in new and existing applications. From an application's perspective, the only detectable differences between Rev B and Rev C boards are the version numbers returned by the API function S826_VersionRead():
 +
* S826_VersionRead() will report the PWB version as Rev B or Rev C as appropriate for the board's hardware version.
 +
* S826_VersionRead() will report FPGA version 0.0.70 or higher for Rev C boards, or version 0.0.69 or lower for Rev B boards.
  
<center>
+
==Connector pinouts==
velocity = (counts<sub>new</sub> &ndash; counts<sub>prev</sub>) / (timestamp<sub>new</sub> &ndash; timestamp<sub>prev</sub>)
+
</center>
+
  
====Output pulse every N encoder pulses====
+
The following drawings show the pinouts of the board's header connectors as viewed from the top (component) side of the circuit board:
  
:''Can the 826 generate an output pulse every N shaft encoder pulses?''
+
<gallery heights=350px widths=180px perrow=3>
 +
File:826 pinout J1.gif
 +
File:826 pinout J2.gif
 +
File:826 pinout J3.gif
 +
File:826 pinout J4.gif
 +
File:826 pinout J5.gif
 +
File:826 pinout P2.gif
 +
</gallery>
  
A short (20 ns) pulse can be generated with one counter ("counterA") and one general-purpose I/O (DIO). A longer output pulse can be generated with two counters ("counterA" and "counterB") and one DIO.
+
==Software==
  
First, initialize the 826:
+
===C examples===
* Configure counterA as an incremental encoder interface.
+
* Configure counterA to capture snapshots upon Compare register matches.
+
* Configure counterA's ExtOut mode (OM=1) to output a pulse upon Compare register match.
+
* Case 1: Short output pulse:
+
** Program the signal router to output counterA's ExtOut signal on the DIO. The pulse duration will be 20 ns and consequently an external pull-up must be added to the DIO to speed up the rising edge of the output pulse (see [[826#Using external pull-up resistors|Using external pull-up resistors]] for details).
+
* Case 2: Output pulse with programmable duration:
+
** Configure counterB as a pulse generator, using counterA's ExtOut as a preload trigger. Program the preload counts to the desired pulse width.
+
** Program the signal router to output counterB's ExtOut signal on the DIO.
+
  
After initializing, program counterA's Compare register with the encoder counts that are to trigger the next output pulse, then wait for a snapshot. When the counts matches the Compare register, a snapshot will be captured and the output pulse will automatically be generated. Upon receiving the snapshot, the application must write into the Compare register the counts corresponding to the next output pulse, before the counter reaches that value.
+
A variety of [http://www.sensoray.com/downloads/s826_example.c C programming examples] have been collected together in a common source file to illustrate how to program resources on the 826.
  
====Encoder FAULT output====
+
===VB.NET demo===
  
:''My encoder has a FAULT output. Can the 826 monitor the FAULT signal and notify the processor when it changes state?''
+
To help you jump-start your project, we offer the [[826 demo (VB.NET)|VB.NET demo for model 826]]. This demo program provides a pre-built Windows executable with a GUI for nearly every hardware resource on the board. All source files are provided, along with a VisualStudio project.
  
Some incremental encoders output a FAULT (or FLT) signal to indicate problems such as damaged bearings, code disc defects/contamination, or malfunctioning LEDs/detectors. The FLT signal is typically conveyed over an RS-422 differential pair, which is compatible with the 826's counter inputs. This hardware compatibility and the counter's flexible architecture allow it to monitor the FLT signal and automatically notify the processor when FLT changes state. Note that the general technique discussed here can be used to monitor the state of any RS-422 signal.
+
===Programming in C#===
  
To implement this, connect FLT to the counter's IX input. If FLT is active-low, swap the differential pair between line driver and receiver as shown below (don't swap if active-high) so that a disconnected or unpowered encoder will be reported as a fault.
+
Each 826 SDK includes a C# demo application. These demos show how to call API functions from C#, and can serve as a useful starting point for a custom application.
  
[[File:826 encoder FLT.png|400px|center|alt=Using an 826 counter channel to monitor an incremental encoder's active-low FAULT output]]
+
====Linux demo====
  
The following code initializes the counter, starts it running, and then monitors the FLT signal state. It should be run in a dedicated thread because it blocks while waiting for FLT state changes. The counter is configured to count up at 1 MHz. A preload is triggered whenever IX is high, and the first Compare0 match triggers a snapshot; these allow the FLT state to be determined when the counter is enabled. Snapshots are also triggered upon IX rising and falling edges; these are used to notify the processor that FLT has changed state.
+
In the Linux SDK, a C# GUI demo is available which uses Linux mono. To get the required libraries on Ubuntu, type:
 +
"sudo apt-get install mono-complete"
 +
For a C# development environment, type:
 +
"sudo apt-get install monodevelop"
  
int FLT_state = -1;    // Public FLT state indicator: -1=unknown, 0=normal, 1=fault
+
====Pointer arguments====
+
// FLT monitor thread: maintains FLT_state and notifies other threads when FLT_state changes.
+
int EncoderFaultMonitor(uint board, uint chan)
+
{
+
  uint errcode;
+
  S826_CounterModeWrite(board, chan, 0x01010020);      // Configure the counter channel.
+
  S826_CounterSnapshotConfigWrite(board, chan, 0x00010019, S826_BITWRITE)
+
  S826_CounterPreloadWrite(board, chan, 0, 0);
+
  S826_CounterCompareWrite(board, chan, 0, 1);
+
  S826_CounterStateWrite(board, chan, 1);              // Enable counter channel.
+
  errcode = ReadFLT(board, chan, 1);                    // Determine FLT initial state.
+
  while (errcode == S826_ERR_OK);                      // Monitor FLT state transitions.
+
    errcode = ReadFLT(board, chan, S826_WAIT_INFINITE);
+
  return errcode;
+
}
+
  
The following function is called by the above code to determine the state of FLT. Note that you must insert code that notifies other threads (e.g., via semaphore) when FLT_state has changed.
+
Many of the API functions have pointer arguments. This is no problem for C#, which allows you to pass function arguments by reference. To see how this is done, consider the <code>S826_AdcEnableRead</code> function:
  
// Wait up to tmax for a FLT state change, then copy the current state to FLT_state.
+
The C prototype is:
static int ReadFLT(uint board, uint chan, uint tmax)
+
{
+
  uint reason;
+
  int errcode = S826_CounterSnapshotRead(board, chan, NULL, NULL, &reason, tmax);
+
  if (errcode == S826_ERR_NOTREADY) {    // If no snapshots captured within finite tmax then
+
    errcode = S826_ERR_OK;                //  cancel error;
+
    FLT_state = 1;                        //  counts holding at 0 because FLT asserted.
+
  } else if (errcode != S826_ERR_OK)      // Else if error detected then
+
    FLT_state = -1;                      //  abort and declare FLT state unknown.
+
  else                                    // Else
+
    FLT_state = ((reason & S826_SSRMASK_IXRISE) != 0);  //  FLT state determined by snapshot trig.
+
   
+
  // TODO: NOTIFY OTHER THREADS THAT FLT STATE CHANGED
+
   
+
  return errcode;
+
}
+
  
====Unexpected snapshots====
+
int S826_AdcEnableRead(unsigned int board, unsigned int *enable);
  
:''Why do I occasionally get two snapshots (upon counts match) from my incremental encoder when only one is expected?''
+
So in C# you should declare the function this way:
  
Assuming your encoder has not changed direction, the unexpected snapshots are probably caused by noise or slow edges on the encoder clock signals. This is possible even when the snapshot timestamps are identical, because encoder clocks are sampled every 20 nanoseconds whereas timestamp counts are incremented only once per microsecond.
+
[DllImport("s826.dll", CallingConvention = CallingConvention.StdCall)]
 +
static extern Int32 S826_AdcEnableRead(UInt32 board, ref UInt32 enable);
 +
Now you can call the function this way:
  
If this is what is happening, unexpected snapshots can be prevented by calling <code>S826_CounterFilterWrite()</code> to establish a clock filter. A small filter value is usually sufficient -- just enough to clean up clock edges, but not so long that valid encoder counts will be missed. For example, this will set the clock filter to 100 ns (index input will not be filtered):
+
Uint32 isEnabled;
 +
Int32 errcode = S826_AdcEnableRead(0, ref isEnabled);
  
#define FILT_NS    100                // Filter time in ns -- change as desired to multiple of 20.
+
===Labview===
#define FILT_RES  20                // Filter resolution in nanoseconds.
+
#define FILT_CLK  (1 << 30)          // Bit flag to enable clock filtering.
+
S826_CounterFilterWrite(0, 0,        // Activate clock filter on counter 0.
+
    FILT_CLK + FILT_NS / FILT_RES);
+
  
Another way to handle this is to configure the Match snapshot trigger to become automatically disabled when it fires. Note that if you use this method, you will need to re-enable the Match trigger to capture snapshots of subsequent matches.
+
Before running an 826 virtual instrument (VI) under Labview, make sure you install the latest versions of the 826 DLL (s826.dll) and device driver (both are contained in the 826 SDK, which you can obtain from the ''Downloads'' tab of the [http://www.sensoray.com/products/826.htm 826 product page]).
  
S826_CounterSnapshotConfigWrite(0, 5, // Configure snapshots on counter 5:
+
Each VI is a basically a wrapper for a DLL function and consequently the VIs are dependent on the DLL, which in turn depends on the driver. Board hardware and firmware version numbers will be automatically read from the 826 board by software when all dependencies are satisfied -- it is not necessary to manually enter any board selection information except the board number, which is specified by the board's switch settings (factory default is board number 0).
    S826_SSRMASK_MATCH0                //  enable snapshot upon Match0 (counts==Compare0 register)
+
    | (S826_SSRMASK_MATCH0 << 16),    //  disable subsequent Match0 snapshots upon Match0
+
    S826_BITWRITE);                    //  disable all other snapshot triggers
+
  
===Timing===
+
The VIs are not independently documented, but since each VI wraps a DLL function, the DLL documentation effectively explains the function of each associated VI. The DLL documentation can be found in the 826 product manual (download from the [http://www.sensoray.com/products/826.htm 826 product page] ''Documentation'' tab).
  
====Input filters====
+
The VIs may be installed under Labview's instrument library (e.g., "instr.lib\Sensoray 826") or elsewhere if desired. Refer to Labview documentation for information about paths and other relevant topics.
  
The ClkA, ClkB and Index inputs are acquired using an internal 50 MHz sampling clock (SysClk) with 3 ns minimum setup time. Consequently, an edge on any of these signals will will be detected 0.3 to 20.3 ns after it occurs. In the below timing diagram, the input edge is detected at SysClk 2 because it occurs after SysClk 1 and &ge; 0.3 ns before SysClk 2.
+
===Matlab===
  
Each input has a digital filter with programmable time F. A filter's input signal will appear on its output when the input has remained stable for time F. The filter delays the detected edge by F+1 SysClk periods. This diagram show filter timing in the general case:
+
To use an 826 with Matlab you must first install the latest 64-bit versions of the 826 API (s826.dll) and device driver; these are both part of the 826 SDK, which you can obtain from the ''Downloads'' tab of the [http://www.sensoray.com/products/826.htm 826 product page]. You may then use Matlab's <code>loadlibrary()</code> function to enable access to the API, and <code>calllib()</code> to call API functions. The API functions are described in the 826 product manual, which can be found on the [http://www.sensoray.com/products/826.htm 826 product page] ''Documentation'' tab. The following example illustrates how this works.
  
[[File:Clock filter general.png|center|External clock delay due to clock sampler and noise filter]]
+
Note: Matlab cannot execute <code>loadlibrary()</code> unless a compatible C compiler is installed on your computer. If Matlab complains about an "Error using loadlibrary" because "No supported compiler was found" then you must download and install one of the Matlab-compatible compilers (e.g., MinGW-w64) to resolve this issue. Please consult Mathworks for a list of compatible compilers.
  
The filter delay can be minimized by setting F=0, which results in the following timing:
+
% Simple Matlab example: turn on general-purpose digital I/O 2 ***************************
 
+
[[File:Clock filter minimum.png|center|External clock delay due to clock sampler and noise filter]]
+
% Change these values as required:
 
+
hdrPath = 'C:\Sensoray\826api.h';           % Path to API header
====Counter functions====
+
dllPath = 'C:\Windows\System32\s826.dll';   % Path to API executable
 
+
board = 0;                                 % Use 826 board #0 (i.e., board w/ID switches set to 0)
The filtered ClkA/B signals are decoded and used to control the counter. As shown in the following diagram, counts will change one SysClk period after a filter output change and then, one SysClk later, a snapshot is captured to the event FIFO and ExtOut goes active for one SysClk period. If ExtOut is routed to a DIO, it will be delayed one additional SysClk period by the DIO output sampler on its way to the DIO connector pin.
+
 
+
[[File:826 counter timing.png|center|Counter timing diagram]]
+
 
+
Summary of counter timing parameters:
+
 
+
{| class="wikitable"
+
! style="text-align:left;"| Timing Parameter
+
! style="text-align:left;"| Minimum
+
! style="text-align:left;"| Maximum
+
|-
+
|ClkA/ClkB setup time
+
| 3 ns
+
|
+
|-
+
|ClkA/ClkB hold time
+
| 0 ns
+
|
+
|-
+
|ClkA/ClkB to counts change
+
|40 ns
+
|60 ns
+
|-
+
|ClkA/ClkB to counts change
+
|40 ns
+
|60 ns
+
|-
+
|ClkA/ClkB to snapshot
+
|60 ns
+
|80 ns
+
|-
+
|ClkA/ClkB to ExtOut (internal)
+
|60 ns
+
|80 ns
+
|-
+
|ClkA/ClkB to ExtOut (DIO pin)
+
|80 ns
+
|100 ns
+
|}
+
 
+
====Using external pull-up resistors====
+
 
+
: ''My PWM stops working when it outputs high frequencies. Why does this happen and how can I prevent it?''
+
 
+
The PWM signal (from the counter's ExtOut) is output by a DIO channel. When the DIO driver transitions to the ''off'' state, its 10 K&Omega; source resistance (combined with circuit capacitance) stretches the DIO rise time and thereby delays its transition to logic '1' (see DIO rising edge in the above timing diagram). As the PWM ''off'' time decreases, the rise time (which is constant) becomes a higher percentage of the ''off'' time. When the ''off'' time is too short (i.e., off time < rise time), the PWM output will seem to "stop" because there is not enough time for the signal to reach logic '1'.
+
 
+
This situation can arise when the PWM is operating at high frequencies or generating short positive pulses, and can be avoided by [[826#Controlling output rise-time with an external pull-up|speeding up the DIO rise time]].
+
 
+
===PWM operation===
+
 
+
====How to configure a counter for PWM operation====
+
 
+
This example shows how to configure counter channel 0 to operate as a PWM generator with the output appearing on DIO channel 0. Note that you ''must'' call <code>S826_SafeWrenWrite()</code> before calling <code>S826_DioOutputSourceWrite()</code>; if you neglect to do this then the PWM signal will not appear on DIO 0.
+
 
+
#include "826api.h"
+
 
   
 
   
  uint data[2]= {1, 0}; // DIO 0
+
  loadlibrary(dllPath, hdrPath, 'alias', 's826');     % Load the API.
  S826_SafeWrenWrite(0, 2);                   // Enable writes to DIO signal router.
+
  boardflags = calllib('s826', 'S826_SystemOpen');   % Open API and detect all boards.
  S826_DioOutputSourceWrite(0, data);         // Route counter0 output to DIO 0.
+
  if (boardflags < 0)                                % If API failed to open
  S826_CounterModeWrite(0, 0, 0x01682020);   // Configure counter0 for PWM, with auto-preload when starting.
+
    disp("S826_SystemOpen error");                 %  Report error.
S826_CounterPreloadWrite(0, 0, 0, 900);    // On time in us (0.9 ms).
+
  else                                                % Else
S826_CounterPreloadWrite(0, 0, 1, 500);    // Off time in us (0.5 ms).
+
    if (boardflags ~= bitshift(1, board))          %  If board #0 was not detected
S826_CounterStateWrite(0, 0, 1);           // Start the PWM generator.
+
        disp("Failed to detect 826 board");         %    Report error (check board's switch settings).
 +
    else                                            %  Else ...
 +
        buf = libpointer('uint32Ptr', [6 0]);       %     Allocate buffer for DIO state data.
 +
        errcode = calllib('s826', ...              %    Turn on DIO1 and DIO2.
 +
            'S826_DioOutputWrite', board, buf, 0);
 +
        clear buf;                                  %     Free buffer.
 +
        if (errcode ~= S826_ERR_OK)
 +
            disp('DIO write problem')              %    Report error if DIO write failed.
 +
        end
 +
    end
 +
    errcode = calllib('s826', 'S826_SystemClose'); %  Close API.
 +
end
 +
unloadlibrary s826;                                % Unload the API.
  
====Fail-safe PWM generator====
+
====Matlab SDK====
  
:''I'm using a PWM output to control a motor. Is there a way to automatically shut off the motor if my program crashes?''
+
Sensoray offers an open-source software development kit for Matlab programmers, which you can obtain from the ''Downloads'' tab of the [http://www.sensoray.com/products/826.htm 826 product page]. The Matlab SDK includes two files:
 +
* <code>s826.m</code> is a class that defines useful constants and provides wrappers for all 826 API functions. Include this file in any project that interacts with model 826 boards.
 +
* <code>s826_demo.m</code> is a short program that demonstrates how to use the s826 class.
  
Yes, you can use the watchdog timer and fail-safe controller to force the PWM output to a constant state. To do this, configure the watchdog to activate safemode when it times out, as shown in this simplified block diagram:
+
===ROS (Robot Operating System)===
  
[[File:826PwmWatchdog.gif|550px|center|alt=Fail-safe PWM generator]]
+
Sensoray SDKs do not include a ROS package, but the Linux SDK has everything needed to create one. The simplest way to use ROS with model 826 is to install the Linux 826 device driver and API (shared library), and then call the API functions as shown in the following example. Note that this example is coded in C++, but you can easily call the API functions from Python or any other language.
  
Before enabling the PWM generator or watchdog, program the desired PWM failsafe level into the DIO channel's <code>SafeData</code> register; this specifies the signal that will be sent to your motor controller when your program crashes (which will shut off the motor). Note that the DIO output is active-low. The <code>SafeEnable</code> register is set to '1' by default, thus enabling fail-safe operation on the DIO channel. Next, program the watchdog interval and start the watchdog running. Finally, start the PWM running.
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
+
// Simple ROS (Robot Operating System) example for Sensoray 826 PCI Express analog/digital IO board.
After enabling the watchdog, your program must periodically kick it to prevent it from timing out, by calling <code>S826_WatchdogKick()</code>. When your program is running normally, the PWM signal will appear on the DIO pin. If your program crashes (or fails to kick the watchdog in a timely manner), the watchdog will time-out and activate the fail-safe controller. This will switch the DIO pin to the level specified by the <code>SafeData</code> register, which in turn will halt the motor.
+
// Function: Publishes 16 analog inputs 10 times per second
 
+
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  #include "826api.h"
+
 
   
 
   
  #define CRASH_DET_SECONDS 0.5  // Halt motor if program fails to kick watchdog within this time.
+
  #define X826(func)   if ((errcode = (func)) != S826_ERR_OK) { printf("\nERROR: %d\n", errcode); return; }    // Call function and process error
#define MOTOR_HALT_LEVEL  0   // DIO pin level ('0'=5V, '1'=0V) that will halt motor.
+
 
   
 
   
  uint wdtime[5] = {(uint)(50000000 * (CRASH_DET_SECONDS)), 1, 1, 0, 0}; // watchdog interval
+
  int PublishAINChannels()
uint dio_routing[2]= {1, 0};                                          // map counter0 to DIO 0
+
uint safe_data[2]= {MOTOR_HALT_LEVEL, 0};                              // fail-safe level
+
+
// Create a fail-safe PWM generator using counter0 and DIO 0.
+
S826_SafeWrenWrite(0, 2);                  // Enable writes to watchdog, router and SafeData.
+
S826_DioSafeWrite(0, safe_data, 2);        // Specify DIO state to use when program crashes.
+
S826_DioOutputSourceWrite(0, dio_routing);  // Route counter0 output to DIO 0.
+
S826_CounterModeWrite(0, 0, 0x01682020);    // Config counter0 for PWM; preload when starting.
+
S826_CounterPreloadWrite(0, 0, 0, 900);    // PWM on time in us (0.9 ms).
+
S826_CounterPreloadWrite(0, 0, 1, 500);    // PWM off time in us (0.5 ms).
+
S826_WatchdogConfigWrite(0, 0x10, wdtime);  // Set wdog interval; trig safemode upon timeout.
+
+
// Start the PWM generator running.
+
S826_WatchdogEnableWrite(0, 1);            // Start watchdog. PROGRAM MUST KICK IT FROM NOW ON!
+
S826_CounterStateWrite(0, 0, 1);            // Start the PWM generator.
+
 
+
====Phase-locked PWM outputs====
+
 
+
Some applications require multiple, phase-locked PWM outputs. Although the 826's counter channels do not directly support phase locking, it is possible to simulate phase-locked PWM outputs by using counters configured as hardware-triggered one-shots. This technique can be used in a variety of ways.
+
 
+
=====Example: quadrature generator=====
+
 
+
A quadrature generator can be implemented with three counter channels and two DIOs as shown below. Except for DIO load connections, no external wiring is required (counter and DIO interconnects are established by the board's programmable signal router).
+
 
+
[[File:826 quadrature gen.gif|500px|center|alt=Quadrature generator]]
+
 
+
The counter channels are configured as follows:
+
 
+
*CH0 - PWM with output on DIO1.
+
*CH1 - 1-shot with IndexSource=ExtOut0, preload upon Index. This delays Phase2 wrt Phase1.
+
*CH2 - 1-shot with IndexSource=ExtOut1, preload upon Index, output on DIO2. This generates the Phase2 output pulse.
+
 
+
=====Example: 3-phase controller=====
+
 
+
A 3-phase PWM controller (shown below) can be created by extending the above example. This is implemented with five counter channels and three DIOs (channel numbers are arbitrarily assigned). Except for DIO load connections, no external wiring is required (counter and DIO interconnects are established by the board's programmable signal router).
+
 
+
 
+
[[File:826 3Phase pwm.png|500px|center|alt=3-phase PWM generator]]
+
 
+
 
+
In the above example, counter channels are configured as follows:
+
 
+
*CH0 - PWM with output on DIO1.
+
*CH1 - 1-shot with IndexSource=ExtOut0, preload upon Index. This delays Phase2 wrt Phase1.
+
*CH3 - 1-shot with IndexSource=ExtOut1, preload upon Index. This delays Phase3 wrt Phase2.
+
*CH2 - 1-shot with IndexSource=ExtOut1, preload upon Index, output on DIO2. This generates the Phase2 output pulse.
+
*CH4 - 1-shot with IndexSource=ExtOut3, preload upon Index, output on DIO3. This generates the Phase3 output pulse.
+
 
+
===Serial data capture===
+
 
+
A counter channel can be used to capture serial data by leveraging its snapshot FIFO. When the counter has been appropriately configured and enabled, the computer allows the channel hardware to acquire snapshots while it asynchronously reads and processes snapshots from the FIFO.
+
 
+
====Serial data capture (asynchronous)====
+
 
+
A timestamp is included in every snapshot, which is especially useful for capturing data from asynchronous sources and irregularly-timed sources such as bar code wands. The basic idea is to apply the serial data signal to the counter's IX or ExtIn input and have the counter automatically capture snapshots at signal edges.
+
 
+
In each snapshot, only the timestamp and reason flags are of interest (counts are ignored). The reason flag indicates whether a snapshot was triggered by rising or falling edge and the timestamp indicates the time when the edge occurred. For example, in the serial data waveform shown below, the first rising edge (A) caused a snapshot to be captured when the timestamp generator value was 100, and the reason code indicates the snapshot was triggered by a rising edge.
+
 
+
[[File:826 serial data capture.png|500px|center|alt=Serial data capture]]
+
 
+
Any two consecutive snapshots represent a matched pair of rising/falling or falling/rising edges, corresponding to an interval during which the serial data value was '1' or '0', respectively. For example, in the waveform shown above, snapshots A and B bracket a '1' interval. It is possible to determine the binary value of the serial data from the first reason code, and the duration of the data value from the difference between the timestamps.
+
 
+
To see how this works, consider the above serial data waveform. The counter automatically captures a snapshot for each of the edge events A, B, C and D. When the computer considers snapshots A and B, it determines that the serial data was '1' during interval A-B because A was triggered by a serial data rising edge. Furthermore, it knows that the serial data held at '1' for 300 microseconds (the difference between the A and B timestamps). Similary, it can determine that interval B-C was a logic '0' lasting 200 microseconds, and C-D was a 400 microsecond logic '1'.
+
 
+
For maximum efficiency, consider using a dedicated thread to read the FIFO. This eliminates polling and makes the application event-driven because the thread can wait in <code>S826_CounterSnapshotRead()</code> for the next snapshot without wasting CPU time. Also, this decouples the timing of serial data acquisition from other tasks, thereby greatly simplifying overall software development and maintenance. If fast processing of the serial data is required, raise the thread priority to an appropriately high level.
+
 
+
====Serial data capture (synchronous)====
+
 
+
To capture clocked serial data (e.g., SPI, I<sup>2</sup>C), apply the clock signal to the counter's ExtIn or IX input and configure the counter to capture snapshots at either the rising or falling edge of the clock signal (whichever edge indicates stable data). Apply the data signal to the counter's ClkA input and set the counter's clock mode K=6 (external quadrature clock, x2 multiplier); this will cause the counts to change (it will alternate between two values) upon each data edge.
+
 
+
A serial data bit can be obtained directly from the counts lsb (least significant bit) of each snapshot. Timestamps may be used to identify data packet boundaries, or ignored if frame markers are encoded in the data.
+
 
+
An open-source demo of this technique is available at [http://www.sensoray.com/downloads/appnote_826_serial_acq.zip synchronous serial receiver].
+
 
+
===Mode register decoder utility===
+
 
+
:''Is there an easy way to convert a mode register value to a human readable description of counter settings?''
+
 
+
Yes: download Sensoray's [http://www.sensoray.com/downloads/util_826_DecodeCounterMode.zip counter mode decoder] utility program (Windows compatible). Run the program and enter the mode register value to see an English language description of the counter mode settings.
+
 
+
==ADC==
+
 
+
===Handling ADC interrupts===
+
 
+
An interrupt request (IRQ) is generated when the ADC subsystem completes a conversion burst. The IRQ works in conjunction with <code>S826_CounterSnapshotRead()</code>, a blocking API function. To wait for the next IRQ, simply call <code>S826_CounterSnapshotRead()</code> from any thread; the function will return upon ADC interrupt.
+
 
+
The following example shows how this works. In this example, only slot 0 is being used, and timestamps are not used. Note that the ADC (and its trigger source) must have been previously configured and enabled (see next example).
+
 
+
void AdcHandler(void)
+
 
  {
 
  {
  uint errcode;
+
    int adcbuf[16];     // adc data buffer
  int slotval[16]; // buffer must be sized for 16 slots
+
     uint slotlist;     // timeslot flags
  while (1) {
+
     uint slot;         // timeslot index (and ain channel number)
     uint slotlist = 1; // only slot 0 is of interest in this example
+
     uint board = 0;     // board ID
     errcode = S826_AdcRead(0, adcdata, NULL, &slotlist, S826_WAIT_INFINITE); // wait for IRQ
+
    int errcode;
    if (errcode != S826_ERR_OK)
+
      break;
+
     printf("Raw adc data = %d", slotval[0] & 0xFFFF);
+
  }
+
}
+
 
+
===Periodic ADC conversions (self-paced)===
+
 
+
:''Can the ADC periodically acquire samples without using a counter to pace it?''
+
 
+
Yes: To do this, configure the ADC for continuous triggering mode and use the slot settling times to control the sampling rate. Note that the sampling period will have a small amount of jitter (&le; 1 microsecond) because ADC conversion time is 2-3 microseconds. This example shows how to acquire 20 samples per second from analog input channel 0:
+
 
+
#define SAMPLING_PERIOD 50000        // Sampling period in microseconds (50000 = 20 samples/s).
+
#define TSETTLE SAMPLING_PERIOD - 3; // Compensate for nominal ADC conversion time.
+
 
   
 
   
// Configure the ADC subsystem and start it running
+
    // Initialize data array for publisher
S826_AdcSlotConfigWrite(board, 0, 0, TSETTLE, S826_ADC_GAIN_1); // measuring ain 0 on slot 0
+
    std_msgs::Int16MultiArray data_array;
S826_AdcSlotlistWrite(board, 1, S826_BITWRITE);                 // enable slot 0
+
    data_array.layout.dim.push_back(std_msgs::MultiArrayDimension());
S826_AdcTrigModeWrite(board, 0);                               // trigger mode = continuous
+
    data_array.layout.dim[0].label = "board-" + to_string(board) + " AIN";
S826_AdcEnableWrite(board, 1);                                 // start adc conversions
+
    data_array.layout.dim[0].size = 16;
 +
    data_array.layout.dim[0].stride = 1;
 +
    data_array.layout.data_offset = 0;
 +
   
 +
    // Configure adc and start it running.
 +
    for (slot = 0; slot < 16, slot++ )                          // Configure slots: chan = slot number, settle time = 20 us, range = +/-10 V
 +
        X826(S826_AdcSlotConfigWrite(board, slot, slot, 20, S826_ADC_GAIN_1));
 +
    X826(S826_AdcSlotlistWrite(board, 0xFFFF, S826_BITWRITE)); // Enable all slots.
 +
    X826(S826_AdcTrigModeWrite(board, 0));                     // Select continuous trigger mode.
 +
    X826(S826_AdcEnableWrite(board, 1));                       // Start conversions.
 
   
 
   
while (1) {
+
    ROS_INFO("\tPublishing AIN Channels");
  AdcHandler();  // Handle periodic ADC interrupts (using code from earlier example)
+
}
+
 
+
===Oversampling===
+
 
+
Oversampling is a useful technique for reducing noise and increasing resolution. Model 826 facilitates oversampling by allowing an analog input (AIN) to be measured multiple times in a single ADC burst.
+
 
+
The following example shows how to oversample two AINs. In each burst, AIN0 is digitized eight times and then AIN1 is digitized eight times. To set this up, each AIN is assigned eight contiguous slots. The first of these is allowed to settle (for 50 &micro;s in this example) because the ADC input has just switched. The seven subsequent conversions do not require any settling time (and thus are set to 0 &micro;s) because the input has not switched. Note: Error checking has been omitted for clarity, but should always be included in robust application code.
+
 
+
#define TSETTLE  50  // Settling time (in microseconds) after switching ADC input
+
 
+
// Average 8 samples and convert to volts (assumes +/-10V measurement range)
+
#define VOLTS(SUM)  (SUM * (10.0 / (8.0 * 32768.0)))
+
 
   
 
   
int slot;
+
    ros::Rate loop_rate(10);
int adcbuf[16];  // Sample buffer -- always set size=16 (even if fewer samples needed)
+
 
   
 
   
// Adc timeslot attributes.
+
    while (ros::ok())
struct SLOTATTR {
+
    {
  uint chan;      // analog input channel
+
        // Wait for next publish time. This is at top of loop so first ADC burst will complete before we try to read the data.
  uint tsettle;  // settling time in microseconds
+
        // Otherwise we might get bogus data the first time through the loop.
} attr[16] = {                                            // During each burst:
+
        loop_rate.sleep();
  {0, TSETTLE},                                            //  switch to AIN0, delay, then digitize
+
  {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},  // digitize AIN0 seven more times
+
  {1, TSETTLE},                                            //  switch to AIN1, delay, then digitize
+
  {1, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}, {1, 0}}; //  digitize AIN1 seven more times
+
 
   
 
   
// Program attributes for all 16 timeslots.
+
        // Fetch ADC data
for (slot = 0; slot < 16; slot++)
+
        data_array.data.clear();
  S826_AdcSlotConfigWrite(board, slot, attr[slot].chan, attr[slot].tsettle, S826_ADC_GAIN_1);
+
        slotlist = 0xFFFF; // from all 16 slots
 +
        errcode = S826_AdcRead(board, adcbuf, NULL, &slotlist, 0);
 
   
 
   
// Configure adc system and start it running.
+
        // Handle errors
S826_AdcSlotlistWrite(board, 0xFFFF, S826_BITWRITE); // Enable all 16 timeslots.
+
        if ((errcode != S826_ERR_OK) && (errcode != S826_ERR_MISSEDTRIG)) { // this app doesn't care about adc missed triggers
S826_AdcTrigModeWrite(board, 0);                     // Select continuous triggering mode.
+
            printf("\nERROR: %d\n", errcode);
S826_AdcEnableWrite(board, 1);                       // Start conversions.
+
            break;
 +
        }
 
   
 
   
while (1)    // Repeatedly fetch and display oversampled data:
+
        // Publish ADC data
{
+
        for (slot = 0; slot < 16; slot++) {
  int sum[] = {0, 0};                                // Reset sample accumulators (one per AIN).
+
            // Publishing raw data (16-bit signed int). Convert to +/-10V by multiplying by 10/32768.
  uint slotlist = 0xFFFF;                            // Wait for ADC burst
+
            // example: cout << (double)(data_array.data[i] * 10) / 32768 << endl;
  S826_AdcRead(board, adcbuf, NULL, &slotlist, 1000); //  and read samples from 16 slots.
+
            data_array.data.push_back((short)(adcbuf[slot] & 0xFFFF));
+
        }
  for (slot = 0; slot < 16; slot++)                   // Sum the 8 samples from each AIN
+
        analog_input_pub.publish(data_array);
    sum[slot >> 3] += (short)(adcbuf[slot] & 0xFFFF); //  while masking off sample meta-data.
+
    }
 
   
 
   
  // Compute and report measured voltages.
+
    S826_AdcEnableWrite(board, 0);          // Halt conversions.
  printf("AIN0=%3.3fV, AIN1=%3.3fV\n", VOLTS(sum[0]), VOLTS(sum[1]));
+
    return errcode;
 
  }
 
  }
  
===Calibration errors caused by missing shunt===
+
===Resources for custom driver development===
  
On 826 SDKs earlier than version 3.2.0, analog calibration values will not be applied without J6 (labeled "Calibration Enable") installed. A missing shunt is intended to protect against accidental overwriting of calibration values, but in these SDKs it also prevents the reading of those values. This is resolved in SDK version 3.2.0 and above; in these versions the shunt functions as intended and must be installed only when calibrating the board (though leaving it installed all the time is okay).
+
[[File:826 software stack.png|thumb|300px|826 software stack. The generic API is portable &mdash; to port, simply adapt the Linux driver and HAL for your OS/RTOS.]]
 +
:''I want to develop my own device driver for the 826. Does Sensoray offer any resources for custom driver development?''
  
If board calibration is incorrect, make sure J6 is installed or upgrade to SDK version 3.2.0 or higher. The 826 SDK can be downloaded from the [http://www.sensoray.com/products/826.htm 826 product page].
+
Yes, we provide these resources free of charge:
  
===Apparent nonlinearity===
+
* '''Linux Software Development Kit (SDK)''' - Includes source code for the 826 driver, hardware abstraction layer (HAL) and API middleware, comprising a complete 826 software stack for Linux. The generic API is operating system independent and thread-safe, which makes this SDK a great starting point for porting to any operating system. The stack has been carefully designed for reliable operation in and for easy porting to real-time operating systems. The SDK can be found on the Downloads tab of the [http://www.sensoray.com/products/826.htm 826 product page].
 +
* '''Model 826 Technical Manual''' - This comprehensive manual explains the API and 826 hardware in detail (download from the Documentation tab of the [http://www.sensoray.com/products/826.htm 826 product page]).
 +
* '''Register Map''' - A map of the board's hardware registers is available [http://www.sensoray.com/downloads/man_826_register_map.pdf here]. The registers are accessed through PCI BAR 2. Registers appear in both banked and flat address spaces. The banked space is only required for rev 0 boards; you should use the flat space exclusively if you have a later rev, as this will yield superior performance.
  
[[File:AdgGroundReference.gif|thumb|300px|To prevent high CMV, connect isolated source to ADC ground.]]
+
===Software updates===
ADC linearity can be adversely affected by high common-mode voltage (CMV). This can happen when the ADC is used to measure an isolated voltage source such as a battery, thermocouple, or isolated power supply. Since the source is isolated, the CMV may float up or down until it exceeds the maximum allowed CMV of the ADC's input circuitry.
+
  
When measuring an isolated source, be sure to connect one side of the source to the ADC power supply ground as shown in the diagram to the right. This will prevent high CMV that might othewise result in apparent non-linearity or calibration errors.{{clear}}
+
1. Windows 3.3.4
 +
* C# demo application added to SDK. Error checking for invalid modes to S826_CounterModeWrite.
 +
2. Linux 3.3.5
 +
* C# GUI demo available, using Linux mono.
  
===ADC accuracy specification===
+
===Windows===
  
Resolution and no missing codes are both 16 bits minimum.
+
====Custom installation and re-distribution====
  
{| class="wikitable"
+
Sensoray's installer uses the Nullsoft Scriptable Install System ([https://en.wikipedia.org/wiki/Nullsoft_Scriptable_Install_System NSIS]). It is created from a .NSI script. The core API is installed as follows in NSI script code:
!rowspan="2"| Parameter
+
!colspan="3"| Value
+
!rowspan="2"| Units
+
!rowspan="2"| Description
+
|-
+
! Min
+
! Typ
+
! Max
+
|-
+
|Integral Nonlinearity Error
+
|
+
| &plusmn;0.75
+
| &plusmn;1.5
+
| LSB
+
| Deviation of ADC transfer function from best-fit line
+
|-
+
| Differential Nonlinearity Error
+
|
+
| &plusmn;0.5
+
| &plusmn;1.25
+
| LSB
+
| Deviation of ADC code width from ideal code width
+
|-
+
| Gain Error
+
|
+
| &plusmn;2
+
| &plusmn;40
+
| LSB
+
| Deviation of difference between actual level of last data transition and actual level of first transition from difference between ideal levels
+
|-
+
| Gain Error Temperature Drift
+
|
+
| &plusmn;0.3
+
|
+
| ppm/&deg;C
+
|
+
|-
+
| Zero Error
+
|
+
|
+
| &plusmn;0.8
+
| mV
+
| Difference between ideal midscale voltage and actual voltage producing the midscale output code
+
|-
+
| Zero Temperature Drift
+
|
+
| &plusmn;0.3
+
|
+
| ppm/&deg;C
+
|
+
|}
+
 
+
===Maximum input voltage===
+
 
+
The analog inputs accept common mode voltages up to &plusmn;12V with no resulting input current or damage. CMV up to &plusmn;25V is tolerated continuously, though this will cause currents to flow in the analog inputs. CMV greater than 25V may be tolerated for brief intervals, but this can cause significant currents to flow in the analog inputs and is not specified nor guaranteed to be safe.
+
 
+
==DAC==
+
 
+
===Specifying setpoint in Volts===
+
 
+
:''Is there a way to program the analog outputs using Volts units?''
+
 
+
The following function will set a DAC output to the specified voltage. Note that the function does not check for illegal voltage values.
+
 
+
int SetDacOutput(uint board, uint chan, double volts)
+
{
+
  uint setpoint;
+
  uint range;
+
  int errcode = S826_DacRead(board, chan, &range, &setpoint, 0);  // get DAC output range
+
  switch (range)
+
  {
+
    case S826_DAC_SPAN_0_5:  setpoint = (uint)(volts * 0xFFFF /  5); break;          // 0 to +5V
+
    case S826_DAC_SPAN_0_10:  setpoint = (uint)(volts * 0xFFFF / 10); break;          // 0 to +10V
+
    case S826_DAC_SPAN_5_5:  setpoint = (uint)(volts * 0xFFFF / 10) + 0x8000; break; // -5V to +5V
+
    case S826_DAC_SPAN_10_10: setpoint = (uint)(volts * 0xFFFF / 20) + 0x8000; break; // -10V to +10V
+
  }
+
  if (errcode == S826_ERR_OK)
+
    errcode = S826_DacDataWrite(board, chan, setpoint, 0);
+
  return errcode;
+
}
+
 
+
===Linux Demo Sine Wave Generator counter error (-15)===
+
 
+
The Linux sine wave generator demo may experience a timeout and exit with an error code -15 (S826_ERR_FIFOOVERFLOW).  This occurs because the priority of the demo thread may be too low for the sample time.  Linux is not a RTOS and the process (or interrupt) may be delayed and not complete the DAC output in the specified time.
+
 
+
Older version of the demo will exit when S826_ERR_FIFOOVERFLOW occurs.  Later versions of the demo, however, will print an error code and continue outputting the sine wave.
+
 
+
In any case, if the DAC output sampling time requirements are very small and need to be precise, it is recommended to run the process at a higher priority.  You may also consider using a low-latency or rt kernel.
+
 
+
To run the demo at a higher priority:
+
 
+
"nice -n 19 ./s826demo"
+
 
+
For Ubuntu low-latency kernel:
+
 
+
"sudo apt-get install linux-lowlatency linux-headers-lowlatency"
+
 
+
For Ubuntu rt kernel:
+
 
+
"sudo apt-get install linux-rt linux-headers-rt"
+
 
+
In extreme high performance cases, you may consider using the raw DAC write command (S826_DacRawWrite) instead of S826_DacDataWrite. You must make sure to understand the DAC ranges before doing so.  This should normally not be necessary as S826_DacDataWrite is only marginally slower.
+
 
+
===DAC accuracy specification===
+
 
+
Resolution and monotonicity are both 16 bits minimum.
+
{| class="wikitable"
+
!rowspan="2" style="text-align:left;"| PARAMETER
+
!rowspan="2" style="text-align:left;"| CONDITIONS
+
!colspan="3"| VALUE
+
!rowspan="2" style="text-align:left;"| UNITS
+
|-
+
! MIN
+
! TYP
+
! MAX
+
|-
+
|Integral Nonlinearity
+
|
+
|
+
|
+
|&plusmn;2
+
|LSB
+
|-
+
|Differential Nonlinearity
+
|
+
|
+
|
+
|&plusmn;1
+
|LSB
+
|-
+
|Gain Error
+
|
+
|
+
|&plusmn;4
+
|&plusmn;20
+
|LSB
+
|-
+
|Gain Temperature Coefficient
+
|
+
|
+
|&plusmn;2
+
|
+
| ppm/&deg;C
+
|-
+
|Unipolar Zero-Scale Error
+
|5V unipolar range, 25&deg;C<br>10V unipolar range, 25&deg;C<br>5V unipolar range<br>10V unipolar range
+
|
+
|&plusmn;80<br>&plusmn;100<br>&plusmn;140<br>&plusmn;150
+
|&plusmn;200<br>&plusmn;300<br>&plusmn;400<br>&plusmn;600
+
|&micro;V<br>&micro;V<br>&micro;V<br>&micro;V
+
|-
+
|V_offset Temperature Coefficient
+
|All unipolar ranges
+
|
+
|&plusmn;2
+
|
+
|&micro;V/&deg;C
+
|-
+
|Bipolar Zero Error
+
|All bipolar ranges
+
|
+
|&plusmn;2
+
|&plusmn;12
+
|LSB
+
|}
+
 
+
==DIOs==
+
 
+
===Controlling output rise-time with an external pull-up===
+
 
+
Each DIO channel has an output driver that actively drives the signal to 0 V in the ''on'' state and is high-impedance in the ''off'' state. In the ''off'' state, the channel's internal 10 K&Omega; resistor passively pulls up the signal to +5 V. This 10 K&Omega; source resistance (combined with circuit capacitance) stretches the DIO rise time, which delays its transition to logic '1'. The rise time can be shortened by adding an external pull-up resistor (and reducing external capacitance) on the signal net.
+
 
+
The following table shows nominal rise times for unloaded DIO pins. Lower resistance values may be needed to compensate external circuit capacitance, but do not use an external pull-up resistor having less than 220 &Omega; (to prevent excessive DIO output current).
+
 
+
{| class="wikitable"
+
! style="text-align:left;"| External pull-up
+
! style="text-align:left;"| DIO rise time
+
|-
+
|None
+
|200 ns
+
|-
+
|1.2 K&Omega;
+
|20 ns
+
|-
+
|680 &Omega;
+
|10 ns
+
|}
+
 
+
===Generating a burst of pulses===
+
 
+
:''How can I make a DIO go active for 10ms and then inactive for another 10ms, and repeat this five times?''
+
 
+
There are several ways to do this but the methods you can use depend on a number of factors. Here are two general strategies:
+
 
+
1. If high precision is not needed you can call <code>S826_DioOutputWrite()</code> multiple times, with 10ms software delays between the calls. The precision of this method may depend on your operating system and CPU load. The code for this method is simple and straightforward.
+
 
+
2. If you need precise timing then you could use two counter channels. For example, using counter channels 0 and 1:
+
 
+
* Counter 0: Configure as PWM generator with 10ms on/off times, with external enable. Connect its enable input to counter 1's output. The goal here is for counter 0 to enable counter 1 to output pulses; counter 0 will enable the PWM generator until 5 pulses have been generated.
+
* Counter 1: Configure as event down-counter, with preload (value=5) upon enable, with external clock, with output active when counts not zero. Connect its clock input (must be external connection) to counter 0's output. The goal here is for counter 1 to count PWM pulses until it counts from 5 down to 0; it will then set its output low, thus disabling the PWM generator.
+
 
+
===Example application: I<sup>2</sup>C Emulator===
+
 
+
:''Can I use DIOs to communicate with I<sup>2</sup>C devices?''
+
 
+
Have a look at [http://www.sensoray.com/downloads/appnote_826_i2c_emulator.pdf Sensoray's I<sup>2</sup>C emulator], which uses two DIOs to bit-bang an I<sup>2</sup>C bus. This open source software implements a full-featured I<sup>2</sup>C master emulator with bus arbitration and bus-hang resolver. All 826-specific code resides in a hardware abstraction layer (HAL) &mdash; an architectural feature that belongs in all production-quality software.
+
 
+
If you need to monitor an I<sup>2</sup>C bus or emulate a slave device, consider [[826#Serial data capture (synchronous)|using a counter to capture synchronous serial data]].
+
 
+
===Interfacing RS-422 signals===
+
 
+
:''I need to monitor the state of an RS-422 signal pair. Can I do this with a DIO channel?''
+
 
+
DIO channels are TTL/CMOS compatible and therefore not compatible with incoming RS-422 signals. However, it is possible to use a counter channel to monitor the state of an RS-422 signal pair, using the technique described [[826#Encoder FAULT output|here]].
+
 
+
==Watchdog timer==
+
 
+
===Turning off the relay===
+
 
+
:''How do I turn off the watchdog's Reset Out relay after the watchdog has turned it on?''
+
 
+
Call <code>S826_WatchdogEnableWrite()</code> with enable=0.
+
 
+
==Software==
+
 
+
===Board IDs===
+
 
+
The "BOARD NUM" switches (at top edge of board near mounting bracket) assign the board ID used by software. The ID is binary coded on the four switches and can be programmed to any value from 0 (default) to 15. A board's ID determines the corresponding ''bit'' that will be set to '1' in the value returned by <code>S826_SystemOpen</code>. If you have one 826 board, the returned value is <code>(2^ID)</code>. If you have multiple boards, the returned value is the sum of <code>(2^ID)</code> for each board.
+
 
+
;Examples
+
* You have one board with ID set to 0, so the value returned by <code>S826_SystemOpen</code> will be <code>(2^0) = 1</code>.
+
* You have two boards with IDs set to 1 and 4, so the value returned by <code>S826_SystemOpen</code> will be <code>(2^1)+(2^4) = 2+16 = 18</code>.
+
 
+
This code snippet will tell you the meaning of the value returned by <code>S826_SystemOpen</code>:
+
 
+
int id, flags = S826_SystemOpen();
+
if (flags < 0)
+
  printf("S826_SystemOpen returned error code %d", flags);
+
else if (flags == 0)
+
  printf("No boards were detected");
+
else {
+
  printf("Boards were detected with these IDs:");
+
  for (id = 0; id < 16; id++) {
+
    if (flags & (1 << id))
+
      printf(" %d", id);
+
  }
+
}
+
 
+
===Custom installation and re-distribution (Windows)===
+
Sensoray's installer uses the NSIS installation system. It is created from a .NSI script. The core API is installed as follows in NSI script code:
+
  
 
  Section "Core API"
 
  Section "Core API"
Line 838: Line 318:
 
  ${EndIf}
 
  ${EndIf}
 
  SectionEnd
 
  SectionEnd
 
  
 
The drivers are installed via dpinst.exe in the NSI script as follows:
 
The drivers are installed via dpinst.exe in the NSI script as follows:
Line 892: Line 371:
 
Yes, the full script is available [http://www.sensoray.com/wiki/index.php?title=826_NSIS_Install_Script here].
 
Yes, the full script is available [http://www.sensoray.com/wiki/index.php?title=826_NSIS_Install_Script here].
  
===Silent install (Windows)===
+
====Silent install====
:''I want to run the installer silently. Do you have any way to do this?''
+
 
 +
:''I want to run the installer silently. Do you have any way to do this?''
  
 
There are many options.  For re-distribution, you may create your own installation package.  Also, starting with version 3.3.9, there are additional command line options to quiet the setup.exe installer from command line or batch file.  These options are described below.   
 
There are many options.  For re-distribution, you may create your own installation package.  Also, starting with version 3.3.9, there are additional command line options to quiet the setup.exe installer from command line or batch file.  These options are described below.   
Line 921: Line 401:
 
One work-around is to launch the setup in an Windows Command Prompt Window started in administrator mode (right-click and select "Run As Administrator").  Another approach is to launch the setup as a user with administrator privileges.  User access control may also be disabled, but we do not recommend this for security reasons.
 
One work-around is to launch the setup in an Windows Command Prompt Window started in administrator mode (right-click and select "Run As Administrator").  Another approach is to launch the setup as a user with administrator privileges.  User access control may also be disabled, but we do not recommend this for security reasons.
  
===Labview===
+
====Link error====
  
Before running an 826 virtual instrument (VI) under Labview, make sure you install the latest versions of the 826 DLL (s826.dll) and device driver (both are contained in the 826 SDK, which you can obtain from the ''Downloads'' tab of the [http://www.sensoray.com/products/826.htm 826 product page]). Each VI is a basically a wrapper for a DLL function and consequently the VIs are dependent on the DLL, which in turn depends on the driver. Board hardware and firmware version numbers will be automatically read from the 826 board by software when all dependencies are satisfied -- it is not necessary to manually enter any board selection information except the board number, which is specified by the board's switch settings (factory default is board number 0).
+
:''I'm using VisualStudio (VS) on a 64-bit machine to build a 32-bit application for the 826. VS reports that linking failed because it can't open s826.lib. What could be the problem?''
  
The VIs are not independently documented, but since each VI wraps a DLL function, the DLL documentation effectively explains the function of each associated VI. The DLL documentation can be found in the 826 product manual (download from the [http://www.sensoray.com/products/826.htm 826 product page] ''Documentation'' tab).
+
You should use the 32-bit DLL (and its associated LIB) because you are building a 32-bit application (x86). Use the 64-bit version only when building 64-bit apps (x64). To avoid confusion, you can copy the 32-bit DLL and its associated LIB file from the install directory to your project directory, then point the linker to it there. Make sure to also point the debugger to the 32-bit DLL by setting its working directory.
  
===Software updates===
+
Note: You will always use the 64-bit driver on a 64-bit OS regardless of 32/64-bit application type, but you don't need to select this as it is automatically installed by the SDK installer.
  
1. Windows 3.3.4
+
====Windows 10 IoT====
* C# demo application added to SDK. Error checking for invalid modes to S826_CounterModeWrite.
+
2. Linux 3.3.5
+
* C# GUI demo available, using Linux mono. To get required libraries on Ubuntu, type:
+
"sudo apt-get install mono-complete"
+
For a C# development environment, type:
+
"sudo apt-get install monodevelop"
+
  
===Resources for custom driver development===
+
Sensoray has created a Universal driver (UD) for the 826 under OneCoreUAP-based editions of Windows.  It is similar to the standard driver, but compiled as [https://docs.microsoft.com/en-us/windows-hardware/drivers/what-s-new-in-driver-development#universal-windows-drivers Universal].  This driver is in our SDK zip file under the "driver/sensoray_826_universal_driver" directory.  Installation may be dependent on the specific Windows version.  The inf is Windows Universal compatible.  Sensoray does not currently have a demonstration Universal Windows App for the 826, but the .NET demo app may be portable.
  
:''I want to develop my own driver for the 826. Does Sensoray offer any resources for custom driver development?''
+
===Linux===
  
Yes, we provide these resources free of charge:
+
====Linux versions====
  
* '''Linux Software Development Kit (SDK)''' - Includes source code for the 826 driver and middleware, comprising a complete 826 API for Linux. The middleware core is operating system independent and thread-safe, which makes this SDK a great starting point for porting to any operating system. The SDK can be found on the Downloads tab of the [http://www.sensoray.com/products/826.htm 826 product page]. The SDK has been carefully designed for reliable operation in multi-threaded and multi-process applications, and consequently it can be easily ported to real-time operating systems.
+
:''Do you recommend specific Linux distributions for use with the 826?''
* '''Model 826 Technical Manual''' - This comprehensive manual explains the API and 826 hardware in detail (download from the Documentation tab of the [http://www.sensoray.com/products/826.htm 826 product page]).
+
* '''Register Map''' - A map of the board's hardware registers is available [http://www.sensoray.com/downloads/man_826_register_map.pdf here]. The registers are accessed through PCI BAR 2. Registers appear in both banked and flat address spaces. The banked space is only required for rev 0 boards; you should use the flat space exclusively if you have a later rev, as this will yield superior performance.
+
  
===Linux versions===
+
We no longer support the obsolete kernel 2.4, but otherwise have no specific recommendation as it depends on the application (e.g., it might be desirable to use a low-latency kernel). The 826 driver is compatible with kernel versions 2.6 and higher.
  
:''Do you recommend specific Linux distributions for use with the 826?''
+
====Troubleshooting====
  
We no longer support the obsolete kernel 2.4, but otherwise have no specific recommendation as it depends on the application (e.g., it might be desirable to use a low-latency kernel). We normally test first on Ubuntu LTS, but have a script to test builds on kernel versions 2.6.x, 3.x, and 4.x.
+
:''The board worked yesterday but it doesn't work today. I didn't change anything. What could be the problem?''
  
===C examples===
+
It's likely that the operating system upgraded the Linux kernel during an automatic update. See [[Linux Troubleshooting|this appnote]] for details.
  
A variety of C programming examples have been collected together in a common source file to illustrate how to program resources on the 826. [http://www.sensoray.com/downloads/s826_example.c Download the examples].
+
====Build errors====
  
===VB.NET demo===
+
On some Linux distributions, "<code>sudo make install</code>" may issue messages like these:
  
To help you jump-start your VB.NET project, we created the [http://www.sensoray.com/downloads/app-826-win-vb.zip VB.NET demo for model 826]. This demo program provides a GUI for nearly every hardware resource on the board. All source files are provided, including a module that declares all functions, types, and constants for the 826 API.
+
* <code>modprobe: ERROR: could not insert 's826': Required key not available</code>
 +
* <code>SSL error:02001002:system library:fopen:No such file or directory: ../crypto/bio/bss_file.c</code>
  
===Modprobe error===
+
In such cases, it's likely that the 826 driver successfully installed and you are simply seeing a warning. You can confirm this by trying "<code>sudo modprobe s826</code>" and the 826 demo application.
  
:''When I try'' "<code>sudo make install</code>" ''it reports'' "<code>modprobe: ERROR: could not insert 's826': Required key not available</code>". ''How can I install the driver?''
+
=====Different gcc version=====
  
It's likely that the 826 driver is installed and you are actually seeing a warning. You can confirm this by trying "<code>sudo modprobe s826</code>" and the 826 demo application.
+
''Why do I get the following error when building the demo?"
  
===Windows link error===
+
relocation R_X86_64_32S against `.bss' can not be used when making a PIE object; recompile with -fPIE
  
:''I'm using VisualStudio (VS) on a 64-bit machine to build a 32-bit application for the 826. VS reports that linking failed because it can't open s826.lib. What could be the problem?''
+
Answer: You have a newer version of gcc, so you must rebuild the middleware. To do this, switch to the SDK downloads directory and then:
 +
* call "make lib"
 +
* cd to middleware directory: "cd middleware"
 +
* "cp *.a ../demo/"
 +
* "cd .."
  
You should use the 32-bit DLL (and its associated LIB) because you are building a 32-bit application (x86). Use the 64-bit version only when building 64-bit apps (x64). To avoid confusion, you can copy the 32-bit DLL and its associated LIB file from the install directory to your project directory, then point the linker to it there. Make sure to also point the debugger to the 32-bit DLL by setting its working directory.
+
Now rebuild the demo with the new .a files:
 +
* "make -C demo s826demo"
  
Note: You will always use the 64-bit driver on a 64-bit OS regardless of 32/64-bit application type, but you don't need to select this as it is automatically installed by the SDK installer.
+
==Remote access==
 +
 
 +
:''Is there any way to use an 826 with a laptop?''
 +
 
 +
Not directly, because laptops don't provide exposed PCI Express slots. However, it is possible to locate the 826 in a host computer that does have PCIe slots and, with appropriate software, remotely access its interfaces from a laptop (e.g., via Ethernet or USB).
 +
 
 +
When designing such a system, it's important to consider that neither Ethernet nor USB are capable of real-time communication with register-based measurement and control hardware. Consequently, depending on the application, this may require the host to offload time-critical I/O functions from the laptop, such as interrupt handling, counter FIFO processing, and low-level register I/O sequences, in order to achieve real-time performance.
 +
 
 +
Functions that are not time-critical can be implemented in various ways. For example, the host computer could run a SNMP agent process that serves as a bridge between Ethernet and the 826. To do this, you will need to create a MIB and implement the associated functions in the agent.
 +
 
 +
==Environmental specifications==
 +
 
 +
{| class="wikitable"
 +
! style="text-align:left;"| Parameter
 +
! style="text-align:left;"| Value
 +
|-
 +
|Pressure, operating
 +
|650 to 1010 hPa
 +
|-
 +
|Humidity, operating
 +
|20% to 80% RH, non-condensing
 +
|}
  
 
==Migrating from model 626==
 
==Migrating from model 626==
  
===Using 626 cables with the 826===
+
For users who are upgrading PCI systems to PCIe, we recommend model 826 as a replacement for model 626.
  
:''I have a 7505TDIN breakout board and 7501C1 (50-pin cable) for the 626. Can I use these with the 826?''
+
===Porting guide===
  
The 7505TDIN and 7501C are both compatible with the 826. However, we recommend using an 826C2 cable instead of the 7501C because it has a low profile header at one end that results in a denser cable stackup. That said, the 7501C cable can be used if it doesn't cause mechanical interference in your system.
+
A migration aid is available to help C developers port applications to model 826. The aid consists of C code which provides, when feasible, equivalent 826 API calls for 626 API functions. In cases where equivalent functions are not available, compiler errors and runtime warnings are issued, and tips are given for resolving porting issues.
 +
 
 +
* [http://www.sensoray.com/downloads/port626.zip 626-to-826 migration aid]
 +
 
 +
===Differences between models 626 and 826===
 +
 
 +
The following table compares the interfaces on the two boards:
 +
 
 +
{| class="wikitable"
 +
! Interface
 +
! 626
 +
! 826
 +
|-
 +
| System bus
 +
| PCI
 +
| PCI Express
 +
|-
 +
| Counters
 +
| 6 channels (3 A/B pairs)<br>24-bit resolution<br>24-bit sampling latch
 +
| 6 channels (identical)<br>32-bit resolution<br>16-deep FIFO with timestamps
 +
|-
 +
| GPIOs
 +
| 48 channels<br>40 w/edge detection (1 Msps)<br>no debounce<br>not fail-safe
 +
| 48 channels<br>48 w/edge detection (50 Msps)<br>debounce filter<br>fail-safe outputs
 +
|-
 +
| Analog out
 +
| 4 channels<br>14-bit resolution<br>20 Ksps<br>not fail-safe
 +
| 8 channels<br>16-bit resolution<br>900 Ksps<br>fail-safe outputs
 +
|-
 +
| Analog in
 +
| 16 channels<br>16-bit resolution<br>15 Ksps
 +
| 16 channels<br>16-bit resolution<br>300 Ksps
 +
|-
 +
| Watchdog timer
 +
| Single stage<br>4 shunt-selectable intervals
 +
| 3 timer stages<br>software programmable intervals
 +
|-
 +
| Fail-safe controller
 +
| n/a
 +
| Integrated
 +
|-
 +
| Timestamp generator
 +
| n/a
 +
| 32 bits, 1 &micro;s resolution
 +
|}
  
 
===Connector pinout differences===
 
===Connector pinout differences===
  
:''Do the 826 and 626 have identical connector pinouts?''
+
:''Do models 826 and 626 have the same connectors and pinouts?''
  
The digital and counter connector pinouts are identical. Analog connector pinouts differ slightly because the 826 has four additional analog outputs. The analog pinouts are identical except for pins 41, 43, 45 and 47, which convey DAC channel 4-7 outputs on the 826 (vs. remote sense inputs on the 626).
+
Both boards have identical connector types, and all connector pinouts are identical except for analog connector J1. Model 826 has four additional analog outputs (channels 4-7) on pins 41, 43, 45 and 47. Model 626 uses these pins as remote sense inputs for analog output channels 0-3.
 +
[[File:826 vs 626 pinouts.gif|left|350px]]
 +
{{Clear}}
  
==See also==
+
===Software differences===
  
* [[GPIO interfacing]] - design tips for DIO circuits
+
;Driver and API
 +
Models 826 and 626 use different device drivers and APIs. The driver and API for each model is exclusive to that model and is not compatible with the other model. The drivers and APIs are necessarily different due to the expanded capabilities of model 826 and to significant hardware architecture differences between the two models. In addition, the 826 API provides blocking functions to simplify development of both event-driven and polling applications.
  
 +
;Application code
 +
Since the APIs are different, it is necessary to revise application code when upgrading to model 826. Numerous examples can be found in this wiki to help in that endeavor. Also, consider using our [http://www.sensoray.com/downloads/port626.zip 626-to-826 migration aid] for C developers who are moving 626 applications to model 826.
 +
 +
===Using 626 cables with the 826===
 +
 +
:''I have a 7505TDIN breakout board and 7501C1 (50-pin cable) for the 626. Can I use these with the 826?''
 +
 +
The 7505TDIN and 7501C are both compatible with the 826. However, we recommend using an 826C2 cable instead of the 7501C because it has a low profile header at one end that results in a denser cable stackup. That said, the 7501C cable can be used if it doesn't cause mechanical interference in your system.
  
  
  
[[Category:Products]]
+
[[Category:826| ]]

Latest revision as of 08:18, 15 February 2022

Model 826 board

This is the top-level wiki page for Sensoray's model 826, a versatile analog and digital I/O system on a PCI Express board. The board has 48 digital I/Os with edge detection, sixteen 16-bit analog inputs, eight 16-bit analog outputs, six 32-bit counter channels with quadrature clock decoders, three-stage watchdog timer with fail-safe controller, and a flexible signal router.

Related pages

Each board subsystem has a dedicated wiki page:

  • ADC - analog input system
  • DACs - analog output system
  • DIOs - general-purpose digital I/Os
  • Counters - counter/timers, including appnotes for interfacing incremental encoders
  • Watchdog - watchdog timer and fail-safe controller
Please note
  • Code and circuit examples are intended to function as described, but this is not guaranteed. If you discover an error, please inform the webmaster.
  • In code examples, error checking has been simplified or omitted for clarity. It is recommended to always perform error checking in your production software.
  • C language examples depend on header file 826api.h, which should be included at the top of your source code like this:
#include "826api.h"

Contents

[edit] Timestamp generator

The timestamp generator is a free-running 32-bit counter that serves as a time reference. The counter increments once per microsecond and overflows (to zero, without notification) every 232 µs (approximately 71.6 minutes). It is a binary counter and consequently does not keep track of the date or time-of-day. At any moment, the current count may be sampled; such a sample is called a timestamp.

A timestamp is automatically appended to every counter snapshot and to every ADC sample so that application programs can know (to within 1 µs) when each sample was acquired. Also, application programs can read the timestamp generator at any time to get a timestamp.

[edit] Usage

Timestamps are particularly useful for precisely measuring the elapsed time between hardware events. Calculation of elapsed time is easy (a single subtraction) as long as the time interval doesn't exceed 71.6 minutes. It can be used in a variety of ways, including measuring speed and capturing serial data.

If desired, an application program can directly read the current time as shown below:

// Read the timestamp generator's current count. 
uint CurrentTimestamp(uint board)
{ 
  uint t;
  S826_TimestampRead(board, &t);
  return t;
}

The following example shows a simple application of direct timestamp reads:

// Example: Use board0 to measure system Sleep() time.
uint t1, t0 = CurrentTimestamp(0);   // Get start time.
Sleep(25);                           // Sleep approximately 25 ms.
t1 = CurrentTimestamp(0);            // Get end time.
printf("Slept %d µs", t1 - t0);      // Display actual sleep time.

[edit] Board ID

The "BOARD NUM" switches (at top edge of board near mounting bracket) assign the board ID used by software. The ID is binary coded on the four switches and can be programmed to any value from 0 (default) to 15. A board's ID determines the corresponding bit that will be set to '1' in the value returned by S826_SystemOpen. If you have a single 826 board, the return value will be (2^ID). If you have multiple boards, the return value is the sum of (2^ID) for each board. You can enter the return value here to quickly determine its meaning.

Examples
  • You have one board with ID set to 0, so the value returned by S826_SystemOpen will be (2^0) = 1.
  • You have two boards with IDs set to 1 and 4, so the value returned by S826_SystemOpen will be (2^1)+(2^4) = 2+16 = 18.

This code snippet will tell you the meaning of the value returned by S826_SystemOpen:

int id, flags = S826_SystemOpen();
if (flags < 0)
  printf("S826_SystemOpen returned error code %d", flags);
else if (flags == 0)
  printf("No boards were detected");
else {
  printf("Boards were detected with these IDs:");
  for (id = 0; id < 16; id++) {
    if (flags & (1 << id))
      printf(" %d", id);
  }
}

[edit] Hardware version

[edit] Reading the PWB revision

The circuit board revision (PWB rev) is visible on the solder-side of the 826 board (opposite the mounting bracket, on the bottom corner). S826_VersionRead returns the PWB rev as a numeric value with decimal range [0:31], which corresponds to a text string in the standard ASME version letter sequence. The following code shows how to convert this 32-bit value to the alphabetic revision code seen on the board:

// Read and display version info from board 0

// Extract major_version, minor_version and build_number from a 32-bit version number:
#define VER_FIELDS(N) ((N) >> 24) & 0xFF, ((N) >> 16) & 0xFF, (N) & 0xFFFF

const char *revchar[] = {  // ASME revision sequence
  "A",  "B",  "C",  "D",  "E",  "F",  "G",  "H",
  "J",  "K",  "L",  "M",  "N",  "P",  "R",  "T",
  "U",  "V",  "W",  "Y",  "AA", "AB", "AC", "AD",
  "AE", "AF", "AG", "AH", "AJ", "AK", "AL", "AM"
};

uint api, drv, bd, fpga;
int errcode = S826_VersionRead(0, &api, &drv, &bd, &fpga);  // Read version info.
if (errcode == S826_ERR_OK) {                               // If no errors then display info:
  printf("API version    = %d.%d.%d\n", VER_FIELDS(api));   //   API major.minor.build
  printf("Driver version = %d.%d.%d\n", VER_FIELDS(drv));   //   DRVR major.minor.build
  printf("FPGA version   = %d.%d.%d\n", VER_FIELDS(fpga));  //   FPGA major.minor.build
  printf("PWB revision   = Rev %s\n",   revchar[bd & 31]);  //   PWB rev as seen on circuit board
}
else
  printf(" S826_VersionRead returned error code %d", errcode);

[edit] Rev C changes

Sensoray has developed Revision C of the 826 circuit board. This change was necessary due to the impending EOL (end-of-life) of a critical component. Specifically, the critical component (PCI Express interface chip) and FPGA were removed and replaced by a new FPGA, which absorbed the functions of the two removed components.

Applications and developers are not affected by this change

The Rev C board is fully compatible with Rev B boards and applications:

  • Mechanical attributes are unchanged, including board dimensions and placements of connectors, switches, indicator LEDs, and hold-down bracket.
  • Connector pinouts, electrical and timing specifications are unchanged.
  • Rev C is 100% software compatible with Rev B on all software layers: application, API and driver (including user-developed drivers and APIs for RTOS, etc.).

Rev B and Rev C boards can be used interchangeably in new and existing applications. From an application's perspective, the only detectable differences between Rev B and Rev C boards are the version numbers returned by the API function S826_VersionRead():

  • S826_VersionRead() will report the PWB version as Rev B or Rev C as appropriate for the board's hardware version.
  • S826_VersionRead() will report FPGA version 0.0.70 or higher for Rev C boards, or version 0.0.69 or lower for Rev B boards.

[edit] Connector pinouts

The following drawings show the pinouts of the board's header connectors as viewed from the top (component) side of the circuit board:

[edit] Software

[edit] C examples

A variety of C programming examples have been collected together in a common source file to illustrate how to program resources on the 826.

[edit] VB.NET demo

To help you jump-start your project, we offer the VB.NET demo for model 826. This demo program provides a pre-built Windows executable with a GUI for nearly every hardware resource on the board. All source files are provided, along with a VisualStudio project.

[edit] Programming in C#

Each 826 SDK includes a C# demo application. These demos show how to call API functions from C#, and can serve as a useful starting point for a custom application.

[edit] Linux demo

In the Linux SDK, a C# GUI demo is available which uses Linux mono. To get the required libraries on Ubuntu, type:

"sudo apt-get install mono-complete"

For a C# development environment, type:

"sudo apt-get install monodevelop"

[edit] Pointer arguments

Many of the API functions have pointer arguments. This is no problem for C#, which allows you to pass function arguments by reference. To see how this is done, consider the S826_AdcEnableRead function:

The C prototype is:

int S826_AdcEnableRead(unsigned int board, unsigned int *enable);

So in C# you should declare the function this way:

[DllImport("s826.dll", CallingConvention = CallingConvention.StdCall)]
static extern Int32 S826_AdcEnableRead(UInt32 board, ref UInt32 enable); 

Now you can call the function this way:

Uint32 isEnabled;
Int32 errcode = S826_AdcEnableRead(0, ref isEnabled);

[edit] Labview

Before running an 826 virtual instrument (VI) under Labview, make sure you install the latest versions of the 826 DLL (s826.dll) and device driver (both are contained in the 826 SDK, which you can obtain from the Downloads tab of the 826 product page).

Each VI is a basically a wrapper for a DLL function and consequently the VIs are dependent on the DLL, which in turn depends on the driver. Board hardware and firmware version numbers will be automatically read from the 826 board by software when all dependencies are satisfied -- it is not necessary to manually enter any board selection information except the board number, which is specified by the board's switch settings (factory default is board number 0).

The VIs are not independently documented, but since each VI wraps a DLL function, the DLL documentation effectively explains the function of each associated VI. The DLL documentation can be found in the 826 product manual (download from the 826 product page Documentation tab).

The VIs may be installed under Labview's instrument library (e.g., "instr.lib\Sensoray 826") or elsewhere if desired. Refer to Labview documentation for information about paths and other relevant topics.

[edit] Matlab

To use an 826 with Matlab you must first install the latest 64-bit versions of the 826 API (s826.dll) and device driver; these are both part of the 826 SDK, which you can obtain from the Downloads tab of the 826 product page. You may then use Matlab's loadlibrary() function to enable access to the API, and calllib() to call API functions. The API functions are described in the 826 product manual, which can be found on the 826 product page Documentation tab. The following example illustrates how this works.

Note: Matlab cannot execute loadlibrary() unless a compatible C compiler is installed on your computer. If Matlab complains about an "Error using loadlibrary" because "No supported compiler was found" then you must download and install one of the Matlab-compatible compilers (e.g., MinGW-w64) to resolve this issue. Please consult Mathworks for a list of compatible compilers.

% Simple Matlab example: turn on general-purpose digital I/O 2 ***************************

% Change these values as required:
hdrPath = 'C:\Sensoray\826api.h';           % Path to API header
dllPath = 'C:\Windows\System32\s826.dll';   % Path to API executable
board = 0;                                  % Use 826 board #0 (i.e., board w/ID switches set to 0)

loadlibrary(dllPath, hdrPath, 'alias', 's826');     % Load the API.
boardflags = calllib('s826', 'S826_SystemOpen');    % Open API and detect all boards.
if (boardflags < 0)                                 % If API failed to open
    disp("S826_SystemOpen error");                  %   Report error.
else                                                % Else
    if (boardflags ~= bitshift(1, board))           %   If board #0 was not detected
        disp("Failed to detect 826 board");         %     Report error (check board's switch settings).
    else                                            %   Else ...
        buf = libpointer('uint32Ptr', [6 0]);       %     Allocate buffer for DIO state data.
        errcode = calllib('s826', ...               %     Turn on DIO1 and DIO2.
            'S826_DioOutputWrite', board, buf, 0);
        clear buf;                                  %     Free buffer.
        if (errcode ~= S826_ERR_OK)
            disp('DIO write problem')               %     Report error if DIO write failed.
        end
    end
    errcode = calllib('s826', 'S826_SystemClose');  %   Close API.
end
unloadlibrary s826;                                 % Unload the API.

[edit] Matlab SDK

Sensoray offers an open-source software development kit for Matlab programmers, which you can obtain from the Downloads tab of the 826 product page. The Matlab SDK includes two files:

  • s826.m is a class that defines useful constants and provides wrappers for all 826 API functions. Include this file in any project that interacts with model 826 boards.
  • s826_demo.m is a short program that demonstrates how to use the s826 class.

[edit] ROS (Robot Operating System)

Sensoray SDKs do not include a ROS package, but the Linux SDK has everything needed to create one. The simplest way to use ROS with model 826 is to install the Linux 826 device driver and API (shared library), and then call the API functions as shown in the following example. Note that this example is coded in C++, but you can easily call the API functions from Python or any other language.

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Simple ROS (Robot Operating System) example for Sensoray 826 PCI Express analog/digital IO board.
// Function: Publishes 16 analog inputs 10 times per second
///////////////////////////////////////////////////////////////////////////////////////////////////////////

#define X826(func)    if ((errcode = (func)) != S826_ERR_OK) { printf("\nERROR: %d\n", errcode); return; }    // Call function and process error

int PublishAINChannels()
{
    int adcbuf[16];     // adc data buffer
    uint slotlist;      // timeslot flags
    uint slot;          // timeslot index (and ain channel number)
    uint board = 0;     // board ID
    int errcode;

    // Initialize data array for publisher
    std_msgs::Int16MultiArray data_array;
    data_array.layout.dim.push_back(std_msgs::MultiArrayDimension());
    data_array.layout.dim[0].label = "board-" + to_string(board) + " AIN";
    data_array.layout.dim[0].size = 16;
    data_array.layout.dim[0].stride = 1;
    data_array.layout.data_offset = 0;
   
    // Configure adc and start it running.
    for (slot = 0; slot < 16, slot++ )                          // Configure slots: chan = slot number, settle time = 20 us, range = +/-10 V
        X826(S826_AdcSlotConfigWrite(board, slot, slot, 20, S826_ADC_GAIN_1));
    X826(S826_AdcSlotlistWrite(board, 0xFFFF, S826_BITWRITE));  // Enable all slots.
    X826(S826_AdcTrigModeWrite(board, 0));                      // Select continuous trigger mode.
    X826(S826_AdcEnableWrite(board, 1));                        // Start conversions.

    ROS_INFO("\tPublishing AIN Channels");

    ros::Rate loop_rate(10);

    while (ros::ok())
    {
        // Wait for next publish time. This is at top of loop so first ADC burst will complete before we try to read the data.
        // Otherwise we might get bogus data the first time through the loop.
        loop_rate.sleep();

        // Fetch ADC data
        data_array.data.clear();
        slotlist = 0xFFFF; // from all 16 slots
        errcode = S826_AdcRead(board, adcbuf, NULL, &slotlist, 0);

        // Handle errors
        if ((errcode != S826_ERR_OK) && (errcode != S826_ERR_MISSEDTRIG)) {  // this app doesn't care about adc missed triggers
            printf("\nERROR: %d\n", errcode);
            break;
        }

        // Publish ADC data
        for (slot = 0; slot < 16; slot++) {
            // Publishing raw data (16-bit signed int). Convert to +/-10V by multiplying by 10/32768.
            // example: cout << (double)(data_array.data[i] * 10) / 32768 << endl;
            data_array.data.push_back((short)(adcbuf[slot] & 0xFFFF));
        }
        analog_input_pub.publish(data_array);
    }

    S826_AdcEnableWrite(board, 0);          // Halt conversions.
    return errcode;
}

[edit] Resources for custom driver development

826 software stack. The generic API is portable — to port, simply adapt the Linux driver and HAL for your OS/RTOS.
I want to develop my own device driver for the 826. Does Sensoray offer any resources for custom driver development?

Yes, we provide these resources free of charge:

  • Linux Software Development Kit (SDK) - Includes source code for the 826 driver, hardware abstraction layer (HAL) and API middleware, comprising a complete 826 software stack for Linux. The generic API is operating system independent and thread-safe, which makes this SDK a great starting point for porting to any operating system. The stack has been carefully designed for reliable operation in and for easy porting to real-time operating systems. The SDK can be found on the Downloads tab of the 826 product page.
  • Model 826 Technical Manual - This comprehensive manual explains the API and 826 hardware in detail (download from the Documentation tab of the 826 product page).
  • Register Map - A map of the board's hardware registers is available here. The registers are accessed through PCI BAR 2. Registers appear in both banked and flat address spaces. The banked space is only required for rev 0 boards; you should use the flat space exclusively if you have a later rev, as this will yield superior performance.

[edit] Software updates

1. Windows 3.3.4

  • C# demo application added to SDK. Error checking for invalid modes to S826_CounterModeWrite.

2. Linux 3.3.5

  • C# GUI demo available, using Linux mono.

[edit] Windows

[edit] Custom installation and re-distribution

Sensoray's installer uses the Nullsoft Scriptable Install System (NSIS). It is created from a .NSI script. The core API is installed as follows in NSI script code:

Section "Core API"
SectionIn RO
${If} ${RunningX64}
 SetOutPath "$WINDIR\system32";
 !insertmacro  DisableX64FSRedirection
 File "..\mid-826\code\Release64\s826.dll";
 !insertmacro  EnableX64FSRedirection
 SetOutPath "$WINDIR\SysWOW64";
 File "..\mid-826\code\Release\s826.dll";
${Else}
 SetOutPath "$WINDIR\system32";
 File "..\mid-826\code\Release\s826.dll";
${EndIf}
SectionEnd

The drivers are installed via dpinst.exe in the NSI script as follows:

Section "Drivers"
SectionIn RO
CreateDirectory "$INSTDIR\driver\x64";
SetOutPath "$INSTDIR\driver\x64";
File "..\cd\driver\x64\dpinst.exe";
File "..\cd\driver\x64\s826.cat";
File "..\cd\driver\x64\s826.inf";
File "..\cd\driver\x64\s826.sys";
File "..\cd\driver\x64\s826filter.cat";
File "..\cd\driver\x64\s826filter.inf";
File "..\cd\driver\x64\s826filter.sys";
File "..\cd\driver\x64\WdfCoInstaller01009.dll";
CreateDirectory "$INSTDIR\driver\x32";
SetOutPath "$INSTDIR\driver\x32";
File "..\cd\driver\x32\dpinst.exe";
File "..\cd\driver\x32\s826.cat";
File "..\cd\driver\x32\s826.inf";
File "..\cd\driver\x32\s826.sys";
File "..\cd\driver\x32\s826filter.cat";
File "..\cd\driver\x32\s826filter.inf";
File "..\cd\driver\x32\s826filter.sys";
File "..\cd\driver\x32\WdfCoInstaller01009.dll";
MessageBox MB_OK "Driver installation dialog will pop-up. Follow the prompts and click Finish when done"
${If} ${RunningX64}
 ExecWait '"$INSTDIR\driver\x64\dpinst.exe" /f'
${Else}
 ExecWait '"$INSTDIR\driver\x32\dpinst.exe" /f'
${EndIf}
NoInstallDriver:
SectionEnd
What other libraries does the installer install as part of the Core API?

The 826 is compiled with Microsoft Visual Studio C++ 2008. The re-distributables for C++ must be installed. The installer installs this library silently running the command:

"vcredist_x86.exe /q"

and the following additional command on 64-bit systems:

"vcredist_x64.exe /q"

These re-distributables are available from Microsoft for x64 and x86.

Are any other libraries required? I installed the libraries above, but the demo doesn't work with my custom installer?

The demo is written using .NET libraries (version 3.5). These are also available from Microsoft here. The executable can be silently installed using this command:

"dotnetfx35setup.exe /qb"
Could I obtain the full 826 NSI script as a template for creating my own installer?

Yes, the full script is available here.

[edit] Silent install

I want to run the installer silently. Do you have any way to do this?

There are many options. For re-distribution, you may create your own installation package. Also, starting with version 3.3.9, there are additional command line options to quiet the setup.exe installer from command line or batch file. These options are described below.

What are the options for silent install?

The basic silent install is invoked by running the following command from command line or batch script:

"setup.exe /S"

Please note that the /S is case sensitive and must be upper case.

I've pre-installed the drivers and don't want to re-install them during the installation? Is there a command for that?
"setup.exe /S /no_driver=1"
Is there an additional command to not install the demo programs?

Yes, in version 3.3.9, the following command will install the required DLLs and system libraries, but no drivers or demo programs.

"setup.exe /S /no_driver=1 /no_demos=1"
I want to install the drivers silently, but there is always a pop-up to verify.

Unfortunately, there is no way around this. Windows requires confirmation from the user for driver install, even if the driver is signed.

I'm running the setup silently, but it pops up a dialog to confirm if I want to make changes to the PC (User Account Control). How do I prevent this?

Windows controls this through User Access Control. If running the setup from a standard windows console, the Windows User Account Control (UAC) will pop-up. This cannot be by-passed by Sensoray because the installer installs files to system directories.

One work-around is to launch the setup in an Windows Command Prompt Window started in administrator mode (right-click and select "Run As Administrator"). Another approach is to launch the setup as a user with administrator privileges. User access control may also be disabled, but we do not recommend this for security reasons.

[edit] Link error

I'm using VisualStudio (VS) on a 64-bit machine to build a 32-bit application for the 826. VS reports that linking failed because it can't open s826.lib. What could be the problem?

You should use the 32-bit DLL (and its associated LIB) because you are building a 32-bit application (x86). Use the 64-bit version only when building 64-bit apps (x64). To avoid confusion, you can copy the 32-bit DLL and its associated LIB file from the install directory to your project directory, then point the linker to it there. Make sure to also point the debugger to the 32-bit DLL by setting its working directory.

Note: You will always use the 64-bit driver on a 64-bit OS regardless of 32/64-bit application type, but you don't need to select this as it is automatically installed by the SDK installer.

[edit] Windows 10 IoT

Sensoray has created a Universal driver (UD) for the 826 under OneCoreUAP-based editions of Windows. It is similar to the standard driver, but compiled as Universal. This driver is in our SDK zip file under the "driver/sensoray_826_universal_driver" directory. Installation may be dependent on the specific Windows version. The inf is Windows Universal compatible. Sensoray does not currently have a demonstration Universal Windows App for the 826, but the .NET demo app may be portable.

[edit] Linux

[edit] Linux versions

Do you recommend specific Linux distributions for use with the 826?

We no longer support the obsolete kernel 2.4, but otherwise have no specific recommendation as it depends on the application (e.g., it might be desirable to use a low-latency kernel). The 826 driver is compatible with kernel versions 2.6 and higher.

[edit] Troubleshooting

The board worked yesterday but it doesn't work today. I didn't change anything. What could be the problem?

It's likely that the operating system upgraded the Linux kernel during an automatic update. See this appnote for details.

[edit] Build errors

On some Linux distributions, "sudo make install" may issue messages like these:

  • modprobe: ERROR: could not insert 's826': Required key not available
  • SSL error:02001002:system library:fopen:No such file or directory: ../crypto/bio/bss_file.c

In such cases, it's likely that the 826 driver successfully installed and you are simply seeing a warning. You can confirm this by trying "sudo modprobe s826" and the 826 demo application.

[edit] Different gcc version

Why do I get the following error when building the demo?"

relocation R_X86_64_32S against `.bss' can not be used when making a PIE object; recompile with -fPIE

Answer: You have a newer version of gcc, so you must rebuild the middleware. To do this, switch to the SDK downloads directory and then:

  • call "make lib"
  • cd to middleware directory: "cd middleware"
  • "cp *.a ../demo/"
  • "cd .."

Now rebuild the demo with the new .a files:

  • "make -C demo s826demo"

[edit] Remote access

Is there any way to use an 826 with a laptop?

Not directly, because laptops don't provide exposed PCI Express slots. However, it is possible to locate the 826 in a host computer that does have PCIe slots and, with appropriate software, remotely access its interfaces from a laptop (e.g., via Ethernet or USB).

When designing such a system, it's important to consider that neither Ethernet nor USB are capable of real-time communication with register-based measurement and control hardware. Consequently, depending on the application, this may require the host to offload time-critical I/O functions from the laptop, such as interrupt handling, counter FIFO processing, and low-level register I/O sequences, in order to achieve real-time performance.

Functions that are not time-critical can be implemented in various ways. For example, the host computer could run a SNMP agent process that serves as a bridge between Ethernet and the 826. To do this, you will need to create a MIB and implement the associated functions in the agent.

[edit] Environmental specifications

Parameter Value
Pressure, operating 650 to 1010 hPa
Humidity, operating 20% to 80% RH, non-condensing

[edit] Migrating from model 626

For users who are upgrading PCI systems to PCIe, we recommend model 826 as a replacement for model 626.

[edit] Porting guide

A migration aid is available to help C developers port applications to model 826. The aid consists of C code which provides, when feasible, equivalent 826 API calls for 626 API functions. In cases where equivalent functions are not available, compiler errors and runtime warnings are issued, and tips are given for resolving porting issues.

[edit] Differences between models 626 and 826

The following table compares the interfaces on the two boards:

Interface 626 826
System bus PCI PCI Express
Counters 6 channels (3 A/B pairs)
24-bit resolution
24-bit sampling latch
6 channels (identical)
32-bit resolution
16-deep FIFO with timestamps
GPIOs 48 channels
40 w/edge detection (1 Msps)
no debounce
not fail-safe
48 channels
48 w/edge detection (50 Msps)
debounce filter
fail-safe outputs
Analog out 4 channels
14-bit resolution
20 Ksps
not fail-safe
8 channels
16-bit resolution
900 Ksps
fail-safe outputs
Analog in 16 channels
16-bit resolution
15 Ksps
16 channels
16-bit resolution
300 Ksps
Watchdog timer Single stage
4 shunt-selectable intervals
3 timer stages
software programmable intervals
Fail-safe controller n/a Integrated
Timestamp generator n/a 32 bits, 1 µs resolution

[edit] Connector pinout differences

Do models 826 and 626 have the same connectors and pinouts?

Both boards have identical connector types, and all connector pinouts are identical except for analog connector J1. Model 826 has four additional analog outputs (channels 4-7) on pins 41, 43, 45 and 47. Model 626 uses these pins as remote sense inputs for analog output channels 0-3.

826 vs 626 pinouts.gif

[edit] Software differences

Driver and API

Models 826 and 626 use different device drivers and APIs. The driver and API for each model is exclusive to that model and is not compatible with the other model. The drivers and APIs are necessarily different due to the expanded capabilities of model 826 and to significant hardware architecture differences between the two models. In addition, the 826 API provides blocking functions to simplify development of both event-driven and polling applications.

Application code

Since the APIs are different, it is necessary to revise application code when upgrading to model 826. Numerous examples can be found in this wiki to help in that endeavor. Also, consider using our 626-to-826 migration aid for C developers who are moving 626 applications to model 826.

[edit] Using 626 cables with the 826

I have a 7505TDIN breakout board and 7501C1 (50-pin cable) for the 626. Can I use these with the 826?

The 7505TDIN and 7501C are both compatible with the 826. However, we recommend using an 826C2 cable instead of the 7501C because it has a low profile header at one end that results in a denser cable stackup. That said, the 7501C cable can be used if it doesn't cause mechanical interference in your system.

Personal tools
Namespaces

Variants
Actions
Toolbox