You are here: Register Set > ADC Data (Offset=0)
STX104 Reference Manual
ContentsIndexHome
PreviousUpNext
ADC Data (Offset=0)

ADC Data Register.

Register Layout

ADC LSB. Offset=0x0, Byte 0. Offset=0, Word 0.

D7 
D6 
D5 
D4 
D3 
D2 
D1 
D0 
AD7 
AD6 
AD5 
AD4 
AD3 
AD2 
AD1 
AD0 

 

ADC MSB. Offset=0x1, Byte 1. Offset=0, Word 0.

D15 
D14 
D13 
D12 
D11 
D10 
D9 
D8 
AD15 
AD14 
AD13 
AD12 
AD11 
AD10 
AD9 
AD8 
Bit Definitions
NAME 
DIRECTION 
DEFAULT 
DESCRIPTION 
AD[15:0] 
- na - 
ADC data word. AD0 is the least significant bit. AD15 is the most significant data bit.
A reading of 010 (0x0000) represents a negative full scale input and a value of 6553510 (0xFFFF) represents an input of positive full scale.
The two registers can both be read simultaneously by simply reading the data as a 16-bit I/O transaction (Examples: “in ax, dx” or “inpw(base_address+0)” ).
 

The ADC LSB register provides the least significant data byte and the ADC MSB register provides the most significant data byte. Each of the two registers can be read in any order (when FIFO Superset is not enabled). Writing any data to the ADC LSB register issues a software trigger. 

Data bandwidth between the STX104 and CPU (PC/104 ISA bus) can be doubled by simply reading the ADC register as a 16-bit register. Software examples are shown below. Further improvement bus bandwidth can be had by limiting the CPU-burst readouts (i.e. Insw() function) to the data fragment buffer size; thus eliminating I/O wait states. 

 

When FIFO Superset is enabled (M1 jumper installed) the ADC data is read out of the FIFO as either a word or a byte at a time. To read out the data correctly as a byte at a time, you must first read the LSB and then the MSB. Once the MSB is read, the FIFO is considered to be read and FIFO is advanced to the next value to be read (if not empty). You may continue to read the data until the FIFO empty flag is set. It is possible to continuously sample analog inputs (continuous ADC sampling or triggering) and continuously read FIFO without any breaks in sampling. 

 

It is the programmer’s responsibility to be sure that data is read out in the correct sequence, as well as starting and stopping the acquisition as required. 

 

VOLTAGE INPUT RANGES
OUTPUT
RANGE 
UNIPOLAR JUMPER
J9 * 
ADC CFG REG
G1 
ADC CFG REG
G0 
RESOLUTION 
NEG FULL SCALE
VOLTAGE 
POS FULL SCALE
VOLTAGE 
NEG FULL SCALE
HEX 
POS FULL SCALE
HEX 
+/- 10 Volts 
305 uV 
-10.00 
+10.00 
0x0000 
0xFFFF 
+/- 5 Volts 
153 uV 
-5.000 
+5.000 
0x0000 
0xFFFF 
+/- 2.5 Volts 
76 uV 
-2.500 
+2.500 
0x0000 
0xFFFF 
+/- 1.25 Volts 
38 uV 
-1.250 
+1.250 
0x0000 
0xFFFF 
0 - 10 Volts 
153 uV 
0.000 
+10.00 
0x0000 
0xFFFF 
0 - 5 Volts 
76 uV 
0.000 
+5.000 
0x0000 
0xFFFF 
0 - 2.5 Volts 
38 uV 
0.000 
+2.500 
0x0000 
0xFFFF 
0 - 1.25 Volts 
19 uV 
0.000 
+1.250 
0x0000 
0xFFFF 

* '1' = Jumper installed. '0' = Jumper not installed. 

 

USING THE INSW() FUNCTION or THE REP INSW INSTRUCTION

Using the REP INSW instruction (or Insw() function in Linux) provides a very high speed mechanism for reading out ADC data from the FIFO. This instruction is available on 286 CPUs and above. In fact, this is faster and easier to use than DMA; both in implementation and execution. Using REP INSW alleviates video problems related with DMA as well as improved CPU timing management (i.e. DMA adds timing holes in the system that are not easily managed by simple real-time kernels). The speed of any ISA bus I/O transaction is dependent on the CPU ISA bus speed which is usually set in the BIOS setup; use this setting with caution as it may affect performance of other cards and/or can cause data loss. This is usually available on many CPU cards. 

Limiting the size of the sample count to the STX104 data fragment buffer in the Insw() function call will eliminate I/O bus wait states and further enhance overall throughput. In most cases this will improve throughput by another factor of two.

Examples of how to read the ADC data: 

 

8-Bit Read in C/C++:
union { unsigned int word; unsigned char byte[2]; } ad_value[16];
...
adc_value(channel).byte[0] = inp(base_address+0);
adc_value(channel).byte[1] = inp(base_address+1);
/* adc_value(channel).word now contains the full ADC word value */
...

 

16-Bit Read in C/C++:
unsigned int ad_value[16];
...
adc_value(channel) = inpw(base_address+0);
...
8-Bit Read and FIFO enabled in C/C++:
union { unsigned int word; unsigned char byte[2]; } ad_value[16];
...
if ( fifo_not_empty() == true ) /* function to check fifo status */
{
 adc_value(channel).byte[0] = inp(base_address+0);
 adc_value(channel).byte[1] = inp(base_address+1);
 /* adc_value(channel).word now contains the full ADC word value */
}
...

 

16-Bit Read and FIFO enabled in C/C++:
unsigned ad_value[16];
...
if ( fifo_not_empty() == true ) /* function to check fifo status */
{
adc_value(channel) = inpw(base_address+0);
}
...

 

16-Bit Read with FIFO enabled in C/C++ using REP INSW:
typedef unsigned int WORD;

void insw(WORD port, void *buf, int count)
{
 _ES = FP_SEG(buf); /* Segment of buf */
 _DI = FP_OFF(buf); /* Offset of buf */
 _CX = count; /* Number to read */
 _DX = port; /* Port */
 asm REP INSW;
}

void main()
{
 WORD *data[512];
 ...
 insw(0x300, data, 512); /* assumes 512 samples (or two blocks) in FIFO */
 ...
}

 

An example shown below illustrating how to set the gain and use it to determine the actual input voltage.
/****************************************************************************
   Apex Embedded Systems
   Revised: 03MAR08
   STX104 Analog Input Demo
****************************************************************************/

#include <conio.h>
#include <stdio.h>
#include <dos.h>

/****************************************************************************/
float adc_gain[8] = { 20.0/65536.0, 10.0/65536.0, 5.0/65536.0, 2.5/65536.0,
              10.0/65536.0,  5.0/65536.0, 2.5/65536.0, 1.25/65536.0 };
float adc_offset[8] = { -10.0, -5.0, -2.5, -1.25, 0.0, 0.0, 0.0, 0.0 };

/****************************************************************************/
float Adc_Voltage ( void )
{
    long sum;
    int index;
    float voltage;

    /* take several samples and average */
    sum = 0;
    for ( index=0; index <256; index++ )
    {
       outportb(0x300, 0x00); /* start a sample */
       while ( (inportb(0x308) & 0x80) != 0x00 ); /* wait for sample */
       sum = sum + ((long)inpw(0x300));
    }
    sum = sum / 256;
    index = inportb( 0x30B ) & 0x07;
    voltage = ( (float) sum ) * adc_gain[index] + adc_offset[index];
    return voltage;
}

/****************************************************************************/
void main()
{
      int x,y;
      unsigned char channels;

      channels = 0x00; /* scan channel zero only */
      /* base address set to factory default at 0x300 */
      /* initialize STX104 */
      outportb(0x309, 0x00); /* no interrupts, no DMA and s/w trigger */

      /* Applies to firmware revision 080214H only: for non-zero first_channel
         please write to channel register twice to correct for errata issue.  This
         is transparent for other firmware revisions (simply means that acquisition
         controller is reset twice).
      */
      outportb(0x302, channels);
      outportb(0x302, channels);
      while ((inportb(0x308) & 0x80 ) == 0x80 ); /* wait       */

      printf("0) +10.0V   input\n");
      printf("1)  +5.0V   input\n");
      printf("2)  +2.5V   input\n");
      printf("3)  +1.25V  input\n");
      printf("9) Quit this test\n");

      do {
           y = inportb( 0x30B ) & 0x07;
           if ( (y & 0x04) == 0x00 ) printf("Bipolar:  ");
           else printf("Unipolar: ");
           y = y & 0x03;
           printf(" Gain=");
           if ( y == 0 )      printf("10V,   ");
           else if ( y == 1 ) printf(" 5V,   ");
           else if ( y == 2 ) printf(" 2.5V, ");
           else if ( y == 3 ) printf(" 1.25V,");
           printf(" Voltage = %+10.6f        \r", Adc_Voltage());

           if ( kbhit() )
           {
              y = getch();
              /* set gain */
              if ( y == '0' )      { x = 0;    outportb( 0x30B, x ); }
              else if ( y == '1' ) { x = 1;    outportb( 0x30B, x ); }
              else if ( y == '2' ) { x = 2;    outportb( 0x30B, x ); }
              else if ( y == '3' ) { x = 3;    outportb( 0x30B, x ); }
              else if ( y == '9' ) x = 9;
           }
       } while ( x != 9 );
       printf("\n\n");
}
Copyright © 1997-2008 by Apex Embedded Systems. All rights reserved. Updated on Wednesday, April 02, 2008.
What do you think about this topic? Send feedback!