AD7124 Development

From HiveTool
Revision as of 16:28, 31 January 2018 by Paul (talk | contribs) (Resources)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Raspberry Pi SPI Interface
Analog Devices AD7124-8
Analog Devices Evaluation Board EVAL-AD7124-8SDZ


Summary

How to connect the 4 wire Serial Peripheral Interface (SPI) Bus on the Raspberry Pi to the Analog Devices AD7124-8 Evaluation Board EVAL-AD7124-8SDZ. No other MCU, including the EVAL-SDP-CB1Z System Demonstration Platform (SDP) board, is necessary. The Pi is operated as the Master, the AD7124 is the Slave. The PIGPIO libraries are necessary.

Resources

PIGPIO Library
EVAL-AD7124-8SDZ User Guide (PDF 4.8 MB 40 Pages)
AD7124-8 Data Sheet (PDF 1.7 MB 92 pages)
Analog Device Virtual Eval Tool (Beta)

Wiring

This shows the necessary connections. NOTE: A ground connection (not shown) is required. The EVAL-AD7124-8SDZ board is powered by it's own power supply.

Raspberry Pi Header J8 EVAL-AD7124-8SDZ
Signal Pin Number Signal Pin Number
GPIO 12 SPI0 MOSI 19 DI TDIN or TDIN1
GPIO 13 SPI0 MISO 21 DO TDOUT or TDOU1
GPIO 14 SPI0 SCLK 23 SCLK TSCLK or TSCLK1
GPIO 10 SPI0_CE0 24 ~CS TCS or TCS1

Compiling

To compile with the PIGPIO libraries

 gcc  -pthread -o AD7124 ad7124PIGPIO.c  -lpigpiod_if2 -lrt

Examples

AD7124 -h
AD7124 --pm=LOW  --fs=120 --verbose=9 --aip=1 --aim=2 --gain=7

Raspberry Pi Code

This program is designed to run on the Raspberry Pi and interface to the Analog Devices AD7124-8 Evaluation Board EVAL-AD7124-8SDZ via the 4 wire SPI interface.

/*
 * Hivetool AD7124 driver
 * 
 * To compile with the PIGPIO libraries
 *  gcc  -pthread -o AD7124 ad7124PIGPIO.c  -lpigpiod_if2 -lrt
 * 
 *
 * AD7124 --pm=LOW  --fs=120 --verbose=9 --aip=1 --aim=2 --gain=7
 * 
 * 
 */

#include <stdio.h>
#include <time.h>
#include <unistd.h>                    // usleep
#include <getopt.h>
#include <string.h>                    // strcasecmp
#include <stdlib.h>                    // strtol
#include <pigpiod_if2.h>               // PIGPIO libraries
#include <errno.h>                     // PIGPIO 

/**************************** printf byte to binary converter *************************************
 * https://stackoverflow.com/questions/111928/is-there-a-printf-converter-to-print-in-binary-format
 * ***********************************************************************************************/

#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
#define BYTE_TO_BINARY(byte)  \
  (byte & 0x80 ? '1' : '0'), \
  (byte & 0x40 ? '1' : '0'), \
  (byte & 0x20 ? '1' : '0'), \
  (byte & 0x10 ? '1' : '0'), \
  (byte & 0x08 ? '1' : '0'), \
  (byte & 0x04 ? '1' : '0'), \
  (byte & 0x02 ? '1' : '0'), \
  (byte & 0x01 ? '1' : '0') 

int  initialize( void );                     /* set BCM2835 SPI parameters, reset the AD7124, read ID and Status registers */
void setup( void );                          /* setup the AD7124 configuration registers */
void read_registers(void);                   /* read and dump the AD7124 registers */
char wait_for_ready(void);                   /* wait for conversion by polling the AD7124 Status register */
int  median_select(int arr[], int n);        /* select the median from the data array */
int  get_options(int argc, char **argv);     /* read the command line options */
int  convert_options(void);                  /* convert the command line option integers to hex bytes */
void print_help(void);                       /* display usage when invoked with the --help argument */

enum { LOW_POWER=0x00, MEDIUM_POWER=0x40, HIGH_POWER=0x80 } power_mode = HIGH_POWER;

int pi = 0;
int spi_handle = 0;
int number_active_channels = 1;
int number_of_filtered_samples = 0;

int data_array[64];

/* command line argument defaults */
int  number_of_samples = 64;                        /*  Number of data reads to average */
int  verbose = 0;
char FS[2] = { 0x01, 0x40 };                        /*  Filter Select (FS) default: 320 */
char PGA   = 0x07;                                  /*  PGA default: 128                */
char AINM  = 0x06;                                  /*  Negative analog input: 6 */
char AINP  = 0x07;                                  /*  Positive analog input: 7 */


int main(int argc, char **argv)
{
int i = 0; 
int j = 0;
int sum = 0;
int sample_counter = 0;
int read_counter = 0;

int data_register=0;
int return_code = 0;

char wrBuf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
char rdBuf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
time_t t;

/* Read the command line arguments */
get_options(argc, argv);    

/* connect to the local PIGPIO daemon  */
pi = pigpio_start(NULL, NULL);                        
if (pi < 0) {
  fprintf (stderr, "Unable to connect to pigpiod: %s\n", strerror (errno));
  return 1;
  }

spi_handle = spi_open( pi, 0, 4194304, 0x000003 );

if (spi_handle < 0) {
  fprintf (stderr, "Unable to open SPI device: %s\n", strerror (errno));
  fprintf (stderr, "Unable to open SPI device: %x\n", spi_handle);
  return 2;
  }

/* Initialize the SPI interface and reset the AD7124 */
return_code = initialize();
if ( verbose > 7 ) printf("initialize routine return value: %d\n",return_code);
  
if ( return_code )
   {
   printf("ERROR! Initialization failed code %d. Is the AD7124 connected and powered?\n", return_code);
   return return_code;
   }
   
/* Set up the registers on the AD7124  */
setup();

/* turn on load cell excitation using PDSW Power Down Switch  */
wrBuf[0]= 0x03; wrBuf[1]= 0x00; wrBuf[2]= 0x80; wrBuf[3]= 0x00;
spi_xfer(pi, spi_handle, wrBuf, rdBuf, 4);

  
/* start data conversion, Continuous conversion mode 00 0084  ADC Control  High power, Mode 0*/
wrBuf[0]= 0x01; wrBuf[1]= 0x06; wrBuf[2]= power_mode;    
spi_xfer(pi, spi_handle, wrBuf, rdBuf, 3);

if ( verbose > 6 )
  {
  printf("Write ADC Control: %02x %02x "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"\n", wrBuf[1],wrBuf[2],BYTE_TO_BINARY(wrBuf[1]),BYTE_TO_BINARY(wrBuf[2]));
  }
  
wrBuf[0]= 0x41; wrBuf[1]= 0x00; wrBuf[2]= 0x00;  
spi_xfer(pi, spi_handle, wrBuf, rdBuf, 3);

if ( verbose > 6 )
  {
  printf("Read ADC Control:  %02x %02x "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"\nBeginning continuous conversions\n", rdBuf[1],rdBuf[2],BYTE_TO_BINARY(rdBuf[1]),BYTE_TO_BINARY(rdBuf[2]));
  }


    time(&t);
//    printf(" %s",ctime(&t));

sum=0;
sample_counter=0;
read_counter = 0;

while ( read_counter < 128 && sample_counter < number_of_samples )
  {  
  for ( i=0; i< number_active_channels; i++ ) 
    {  
    if ( !wait_for_ready() )
       {
	/* Read the data register  */
        wrBuf[0]= 0x42; 
        spi_xfer(pi, spi_handle, wrBuf, rdBuf, 5);
     
        data_register = (rdBuf[1] << 16) | (rdBuf[2] << 8) | (rdBuf[3]); 
    
        if ( verbose > 8 ) { printf("Data: %d %02x%02x%02x  Status: %02X ",data_register, rdBuf[1],rdBuf[2],rdBuf[3],rdBuf[4]); }

        /* Read the error register */
        wrBuf[0]= 0x46;
        spi_xfer(pi, spi_handle, wrBuf, rdBuf, 4);

        if ( verbose > 8 )
	   { 
           time(&t);	    
	   printf(" Error: %02X %02X %02X "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"  %s", rdBuf[1],rdBuf[2],rdBuf[3],BYTE_TO_BINARY(rdBuf[1]),BYTE_TO_BINARY(rdBuf[2]),BYTE_TO_BINARY(rdBuf[3]) ,ctime(&t));
           } 

	/* Check for errors  */
	if ( (rdBuf[1] | rdBuf[2] | rdBuf[3]) == 0 )             /* if no errors,  use data to calculate average  */
          {
	   data_array[sample_counter] = data_register;
          sum += data_register;
          sample_counter++;
          }
       }
   } 
// read_registers();  
  read_counter++;
  }

/* turn off load cell excitation using PDSW Power Down Switch  */
wrBuf[0]= 0x03; wrBuf[1]= 0x00; wrBuf[2]= 0x00; wrBuf[3]= 0x00;
spi_xfer(pi, spi_handle, wrBuf, rdBuf, 4);

if (sample_counter == 0)  return 5;
number_of_filtered_samples = sample_counter;

if (sample_counter > 1 )
   {
   /* calculate raw average */ 
   int raw_average = sum/sample_counter;

   /* calculate median */
   int median = median_select( data_array, sample_counter );

   printf("AD7124test Raw Average: %10d Median: %10d  Number of samples: %4d  Number of errors:  %3d  %s", raw_average, median,sample_counter, (read_counter - sample_counter), ctime(&t) );
   //     printf(" %s",ctime(&t));

   sum = 0;
   number_of_filtered_samples = 0;

   /* set limits for outliers  */
//   int high_limit = median * 1.00002;
//   int low_limit = median * .99998;
   int high_limit = median * 1.0002;
   int low_limit = median * .9998;

// printf("high_limit:  %10d low_limit: %10d\n", high_limit, low_limit );


/* Test for outliers and throw them away */

   for ( j=0; j<sample_counter; j++ )
       {
       if ( data_array[j] < high_limit && data_array[j] > low_limit ) 
         {
         number_of_filtered_samples++;
        sum += data_array[j]; 
        //    printf ("data_array: %d less median: %d\n", data_array[j], data_array[j] - median);
        }
 //  else 
 //    printf ("OUTLIER     %d less median: %d\n", data_array[j], data_array[j] - median);
      }

  if (number_of_filtered_samples == 0)  return 6;

  /* calculate raw average */ 
  int filtered_average = sum/number_of_filtered_samples;

  printf("AD7124test Filtered Avg:%10d Median: %10d  Number of samples: %4d  Number  Outliers:  %3d  %s", filtered_average, median, number_of_filtered_samples, (sample_counter - number_of_filtered_samples),  ctime(&t) );
  //     printf(" %s",ctime(&t));
  }
//printf("Weight: %7.3f\n",  0.000536331066441 * ( ( (sum/number_of_filtered_samples)/10 ) - 855362)  );
//printf("Weight: %7.3f\n",  0.00000868891 * ( ( (sum/number_of_filtered_samples) ) - 73.10472780232)  );
printf("Weight: %7.3f\n",  (0.0003438388 *  (sum/number_of_filtered_samples))  - 2892.912  );
spi_close(pi, spi_handle);

return 0;
}

/* *********************** initialize **********************************
 * 
 * set the BCM2835 SPi parameters
 * Reset AD7124
 * check for AD7124 by reading ID register 5 (ID 14)
 * Read Status Register
 * 
 * 
 ***********************************************************************/

int initialize ( void )
 {
 char wrBuf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
 char rdBuf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
 
/* Reset the AD7124 by sending 64 ones */
 spi_write(pi, spi_handle,wrBuf, 8);                   
//   printf("Sent 64 ones to reset\n");
 usleep(1000);                                         /* Wait for the reset to complete */

 wrBuf[0]= 0x45;                        /* check for AD7124 by reading ID register 5 (ID 14) */
 spi_xfer(pi, spi_handle, wrBuf, rdBuf, 2);   

 if (verbose > 6)  printf("initialize()  ID register: %02X\n",rdBuf[1]);
 if ( rdBuf[1] != 0x14 ) 
    { 
    printf("AD7124 reset failed. Bad ID: %02X\n", rdBuf[1]);
    return 3;
    }
    
 /* Read Status Register */
 wrBuf[0]= 0x40;                       
 spi_xfer(pi, spi_handle, wrBuf, rdBuf, 2);

if (verbose > 6)    printf("initialize() Status register: %02X\n",rdBuf[1]);

/* Read Status Register again to clear Power reset bit */
  wrBuf[0]= 0x40; 
  spi_xfer(pi, spi_handle, wrBuf, rdBuf, 2);

  if (verbose > 6)  printf("initialize() Status register: %02X\n",rdBuf[1]);
 
  if ( rdBuf[1] != 0x80 ) 
     {  
     printf("AD7124 reset failed. Bad Status: %02X \n", rdBuf[1]);
     return 4;
     }
     
 return 0;
 }
 
 
/* ************************** setup ************************************
 * 
 * Maybe add an external conf file that sets up the ADC registers?
 * 
 ***********************************************************************/
 
void setup ( void )
 {

char wrBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
char rdBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

wrBuf[0]= 0x09; wrBuf[1]= 0x00; wrBuf[2]= 0x01;                        /* Turn off channel_0 (on by default) */
spi_xfer(pi, spi_handle, wrBuf, rdBuf, 3);
//wrBuf[1] = ( AIMP & 0x18 ) >> 3 ;
wrBuf[0]= 0x0a;
wrBuf[1] = (( AINP >> 3) & 0x07 ) | 0x80;
wrBuf[2] = (( AINP & 0x07 ) << 5) | ( AINM & 0x1F );

spi_xfer(pi, spi_handle, wrBuf, rdBuf, 3);

wrBuf[0]= 0x19; wrBuf[1]= 0x08; wrBuf[2]= 0x7F;
spi_xfer(pi, spi_handle, wrBuf, rdBuf, 3);

wrBuf[0]= 0x21; wrBuf[1]= 0x06; wrBuf[2]= FS[0]; wrBuf[3]= FS[1];       /* Set the Filter Select bits             */
spi_xfer(pi, spi_handle, wrBuf, rdBuf, 4);

wrBuf[0]= 0x07; wrBuf[1]= 0x03; wrBuf[2]= 0xF0; wrBuf[3]= 0x38;
spi_xfer(pi, spi_handle, wrBuf, rdBuf, 4);
if ( verbose > 6 )
  {
  read_registers();                // This sets the number_active_channels (default = 1)
  }
}
 
/* ************************ read_registers *****************************
 * 
 * Read and dump most of the AD7124-8 registers
 * 
 ***********************************************************************/

void read_registers(void)
{
 int i;
 char wrBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 char rdBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

      wrBuf[0]= 0x46;
      spi_xfer(pi, spi_handle, wrBuf, rdBuf, 4);
      printf("%02X Error     : %02X %02X %02X "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"\n", 0x06,rdBuf[1],rdBuf[2],rdBuf[3],BYTE_TO_BINARY(rdBuf[1]),BYTE_TO_BINARY(rdBuf[2]),BYTE_TO_BINARY(rdBuf[3]));

      wrBuf[0]= 0x47;
      spi_xfer(pi, spi_handle, wrBuf, rdBuf, 4);
      printf("%02X Error Enab: %02X %02X %02X "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"\n", 0x07,rdBuf[1],rdBuf[2],rdBuf[3],BYTE_TO_BINARY(rdBuf[1]),BYTE_TO_BINARY(rdBuf[2]),BYTE_TO_BINARY(rdBuf[3]));
 
  number_active_channels=0;
  for ( i = 0x49; i< 0x59; i++ )                                   /* Read Channel Registers */
      {
      wrBuf[0]= i;
      spi_xfer(pi, spi_handle, wrBuf, rdBuf, 3);
  
      /* Test for active channels and count them */  
      if ( rdBuf[1] & 0x80 )  { number_active_channels++; }        
      printf("%02X Channel %2d: %02x %02x "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"\n",i-0x40, (i-0x49),rdBuf[1],rdBuf[2],BYTE_TO_BINARY(rdBuf[1]),BYTE_TO_BINARY(rdBuf[2]));
      }
  printf("Number of active channels: %d\n", number_active_channels);
   
 for ( i = 0x59; i< 0x61; i++ )                                   /* Read Configuration Registers */
     {
     wrBuf[0]= i;
     spi_xfer(pi, spi_handle, wrBuf, rdBuf, 3);
     printf("%02X Config  %2d: %02X %02X "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"\n", i-0x40, (i-0x59),rdBuf[1],rdBuf[2],BYTE_TO_BINARY(rdBuf[1]),BYTE_TO_BINARY(rdBuf[2]));
     }
 for ( i = 0x61; i< 0x69; i++ )                                   /* Read Configuration Registers */
     {
     wrBuf[0]= i;
     spi_xfer(pi, spi_handle, wrBuf, rdBuf, 4);
     printf("%02X Filter  %2d: %02X %02X %02X "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"  "BYTE_TO_BINARY_PATTERN"\n", i-0x40, (i-0x61),rdBuf[1],rdBuf[2],rdBuf[3],BYTE_TO_BINARY(rdBuf[1]),BYTE_TO_BINARY(rdBuf[2]),BYTE_TO_BINARY(rdBuf[3]));
     }  

}

/************************* wait_for_ready  *********************************
 *
 *   This routine spins in a loop waiting until either:
 *   1, The conversion is complete ~RDY bit goes low (data is written to the Data Register)
 *   2. We time out and give up
 * 
 *   WARNING: This routine is senstive to the SPI clock speed.
 *   Low clock speeds can cause delays much greater than 0.1 miliseconds each pass.
 * 
 ***************************************************************************/


char wait_for_ready(void)
{
char wrBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
char rdBuf[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned int waiting=10000;
char busy = 1;

while( busy && waiting )
  {
  /* Read the Status Register */
  wrBuf[0]= 0x40;
  spi_xfer(pi, spi_handle, wrBuf, rdBuf, 2);  
  busy = rdBuf[1] & 0x80 ;                      /* Test the Not Ready bit */
//  printf("Busy: %X  timeout: %d\n", busy, (1000-timeout) );
  
  usleep(100);                                /* wait 0.1 msec */
  waiting--;
  }
  return busy;
}




/************************* median_select  *********************************
 *
 *      from http://ndevilla.free.fr/median/median/
 *  This Quickselect routine is based on the algorithm described in
 *  "Numerical recipes in C", Second Edition,
 *  Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5
 *  This code by Nicolas Devillard - 1998. Public domain.
 *
 ***************************************************************************/

#define ELEM_SWAP(a,b) { register int t=(a);(a)=(b);(b)=t; }

int median_select(int arr[], int n) 
{
    int low, high;
    int median;
    int middle, ll, hh;

    low = 0 ; high = n-1 ; median = (low + high) / 2;
    
    for (;;) {
        if (high <= low) /* One element only */
            return arr[median];

        if (high == low + 1) {  /* Two elements only */
            if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]);
            return arr[median];
            }

    /* Find median of low, middle and high items; swap into position low */
    middle = (low + high) / 2;
    if (arr[middle] > arr[high])    ELEM_SWAP(arr[middle], arr[high]);
    if (arr[low] > arr[high])       ELEM_SWAP(arr[low], arr[high]);
    if (arr[middle] > arr[low])     ELEM_SWAP(arr[middle], arr[low]);

    /* Swap low item (now in position middle) into position (low+1) */
    ELEM_SWAP(arr[middle], arr[low+1]);

    /* Nibble from each end towards middle, swapping items when stuck */
    ll = low + 1;
    hh = high;
    for (;;) {
        do ll++; while (arr[low] > arr[ll]);
        do hh--; while (arr[hh]  > arr[low]);

        if (hh < ll)
        break;

        ELEM_SWAP(arr[ll], arr[hh]);
        }

   /* Swap middle item (in position low) back into correct position */
   ELEM_SWAP(arr[low], arr[hh]);

   /* Re-set active partition */
   if (hh <= median) low = ll;
   if (hh >= median) high = hh - 1;
   }
}

#undef ELEM_SWAP


/****************************** get_options *********************************************************************
 * 
 * https://www.gnu.org/software/libc/manual/html_node/Getopt-Long-Option-Example.html#Getopt-Long-Option-Example
 * https://stackoverflow.com/questions/3792663/atol-v-s-strtol
 * 
 ***************************************************************************************************************/

int get_options (int argc, char **argv)
{
  int short_option;
  char* end;
  
  int  filter_select = 0;
  int  positive_analog_input = 0;
  int  negative_analog_input = 0;
  int  programable_gain = 0;
  
  while (1)
    {
      static struct option long_options[] =
        {
          /* These options set a flag. */
//          {"brief",   no_argument,       &verbose_flag, 0},
          /* These options don?t set a flag.
             We distinguish them by their indices. */
          {"aip",     required_argument, 0, 'p'},
          {"aim",     required_argument, 0, 'm'},
          {"fs",      required_argument, 0, 'f'},
          {"gain",    required_argument, 0, 'g'},
          {"help",    no_argument,       0, 'h'},
          {"samples", required_argument, 0, 'n'},
          {"power",   required_argument, 0, 'w'},
          {"verbose", required_argument, 0, 'v'},
          {0, 0, 0, 0}
        };
      /* getopt_long stores the option index here. */
     int option_index = 0;

     short_option = getopt_long (argc, argv, "n:p:m:f:g:hw:v:",
                      long_options, &option_index);

     /* Detect the end of the options. */
     if (short_option == -1)
       break;

     switch (short_option)
       {
       case 0:
         /* If this option set a flag, do nothing else now. */
         if (long_options[option_index].flag != 0)
           break;
         printf ("option %s", long_options[option_index].name);
         if (optarg)
           printf (" with arg %s", optarg);
         printf ("\n");
         break;

       case 'f':
	  filter_select = strtol(optarg, &end, 10);
	  if (*end)
	     {
	     printf ("ERROR! Filter Select (FS) argument numeric conversion failed, non-numeric part: %s\n", end);
	     exit(-3);  
	     }
	  if ( filter_select > 2047 || filter_select < 1 ) 
	     {
	     printf ("ERROR! Filter Select (FS) argument out of range (1-2047): %d\n", filter_select);	     
	     exit(-1);
	     }
	  FS[0] = filter_select & 0xFF;
	  FS[1] = (filter_select >> 8 ) & 0xFF;
	 
         if ( verbose > 4 ) printf ("Command line option Filter Select (--fs or -f) has value %d converted to %02X %02X \n", filter_select, FS[1], FS[0]);
	  
	  
         break;

	case 'g':
	  programable_gain = strtol(optarg, &end, 10);
	  if (*end)
	     {
	     printf ("ERROR! Programable Gain Amplifier (PGA) argument numeric conversion failed, non-numeric part: %s\n", end);
	     exit(-3);  
	     }
	  if ( programable_gain > 7 || programable_gain < 0 ) 
	     {
	     printf ("ERROR! Programable Gain Amplifier (PGA) argument out of range (0-7): %d\n", programable_gain);	     
	     exit(-1);
	     }
	  PGA = programable_gain & 0x07;
	  
         if ( verbose > 4 ) printf ("Command line option Programable Gain Amplifer (--gain or -g) has value %d converted to %02X\n", programable_gain, PGA);
         break;

//	case '?':
	case 'h':
         print_help();
	  exit(0);
	  break;

	  
       case 'm':
	  negative_analog_input = strtol(optarg, &end, 10);
	  if (*end)
	     {
	     printf ("ERROR! Analog INput Minus (AINM) argument numeric conversion failed, non-numeric part: %s\n", end);
	     exit(-3);  
	     }
	  if ( negative_analog_input > 31 || negative_analog_input < 0 ) 
	     {
	     printf ("ERROR! Analog INput Minus (AINM) argument out of range (0-31): %d\n", negative_analog_input);	     
	     exit(-1);
	     }
	  AINM = 0x1F & negative_analog_input;
	  
         if ( verbose > 4 ) printf ("Command line option Analog INput Minus (AINM) (--aim or -m) has value %d converted to %02X\n", negative_analog_input, AINM);
         break;

       case 'n':
	  number_of_samples = strtol(optarg, &end, 10);
	  if (*end)
	     {
	     printf ("ERROR! Analog INput Minus (AINM) argument numeric conversion failed, non-numeric part: %s\n", end);
	     exit(-3);  
	     }
	  if ( number_of_samples > 64 || number_of_samples < 1 ) 
	     {
	     printf ("ERROR! Number of samples argument out of range (0-31): %d\n", number_of_samples);	     
	     exit(-1);
	     }
	  	  
          if ( verbose > 4 ) printf ("Command line option Number of samples (--samples or -n) has value %d\n", number_of_samples);
          break; 

	  
       case 'p':
	  positive_analog_input = strtol(optarg, &end, 10);
	  if (*end)
	     {
	     printf ("ERROR! Analog INput Plus (AINP) argument numeric conversion failed, non-numeric part: %s\n", end);
	     exit(-3);  
	     }
	  if ( positive_analog_input > 31 || positive_analog_input < 0 ) 
	     {
	     printf ("ERROR! Analog INput Plus (AINP) argument out of range (0-31): %d\n", positive_analog_input);	     
	     exit(-1);
	     }
	  AINP = 0x1F & positive_analog_input;
	     
         if ( verbose > 4 ) printf ("Command line option Analog INput Plus (AINP) (--aip or -p) has value %d converted to %02X\n", positive_analog_input, AINP);
         break;
	  
	case 'w':
	  if ( strcasecmp( optarg, "LOW") == 0 ) { power_mode = LOW_POWER; }
	  else if ( strcasecmp( optarg, "MEDIUM") == 0 ) { power_mode = MEDIUM_POWER; }
	  else if ( strcasecmp( optarg, "HIGH") == 0 ) { power_mode = HIGH_POWER; }
	  else { printf ("ERROR! Expecting --power(-w) [low|LOW|medium|MEDIUM|high|HIGH] found %s\n", optarg); 
	         exit(-2);
	       }
	  break;

       case 'v':
//	  verbose = 1;
//	  if ( optarg )
//	  {
	  verbose = strtol(optarg, &end, 10);
	  if (*end)
	     {
	     printf ("ERROR! Verbose argument numeric conversion failed, non-numeric part: %s\n", end);
	     exit(-3);  
	     }
	  if ( verbose > 9 || verbose < 0 ) 
	     {
	     printf ("ERROR! Verbose argument out of range (0-9): %d\n", verbose);	     
	     exit(-1);
	     }
//	  }   
         if ( verbose > 4 ) printf ("Command line option Verbose (--verbose or -v) with value %d\n", verbose);
         break;

       case '?':
         /* getopt_long already printed an error message. */
	  exit(-5);
         break;

       default:
         abort ();
       }
       
       
       
       
   }

 /* Instead of reporting ?--verbose?
    and ?--brief? as they are encountered,
    we report the final status resulting from them. */
//  if (verbose_flag)
//    puts ("verbose flag is set");

 /* Print any remaining command line arguments (not options). */
 if (optind < argc)
   {
     printf ("non-option ARGV-elements: ");
     while (optind < argc)
       printf ("%s ", argv[optind++]);
     putchar ('\n');
   }

 return (0);
}

/* *********************** print_help **********************************
 * 
 * Prints usage information - some of this could go in a man page
 * 
 ***********************************************************************/

void print_help(void)
{
 printf (
  "Usage: ad7124 [OPTION...]\n\n"
  "  -f, --fs=FS   0 < FS < 2048\n"
  "       Sets the output data rate of the sinc3, sinc4 and fast settling filters, affects the\n"
  "       position of the first notch, the cutoff frequency of the sinc filter, the output noise\n"
  "       and effective resolution\n"
  "\n"
  "  -g, --gain=GAIN\n"
  "       Sets PGA stage gain:\n"
  "       GAIN gain Input Voltage Range\n"
  "        0    1    +/-2.5 V\n"
  "        1    2    +/-1.25 V\n"
  "        2    4    +/-625 mV\n"
  "        3    8    +/-312.5 mV\n"
  "        4    16   +/-156.25 mV\n"
  "        5    32   +/-78.125 mV\n"
  "        6    64   +/-39.06 mV\n"
  "        7    128  +/-19.53 mV\n"
  "\n"
  "  -m, --aim=AIM\n"
  "       AIM selects which input is multiplexed to the ADC negative input where:\n"
  "       AIM  AINM\n"
  "        0   AIN0\n"
  "        1   AIN1\n"
  "        2   AIN2\n"
  "        3   AIN3\n"
  "        4   AIN4\n"
  "        5   AIN5\n"
  "        6   AIN6\n"
  "        7   AIN7\n"
  "        8   AIN8\n"
  "        9   AIN9\n"
  "        10  AIN10\n"
  "        11  AIN11\n"
  "        12  AIN12\n"
  "        13  AIN13\n"
  "        14  AIN14\n"
  "        15  AIN15\n"
  "        16  temperature sensor\n"
  "        17  AVSS\n"
  "        18  internal reference\n"
  "        19  DGND\n"
  "\n"	    
  "  -n, --samples=N\n"
  "        N sets the number of samples that are read and averaged.  0 < N < 65\n"
  "        If N > 1, the samples are read as quickly as possible with no delay between samples.\n"
  "\n"	    
  "  -p, --aip=AIP\n"
  "       AIP selects which input is multiplexed to the ADC positive input. AIP is the same as\n"
  "        AIM in the -m,--aim option.\n"
  "\n"
  "Examples:\n\n"
  "\n"
  "\n"
  "Application Notes:\n"
  "\n"
  "This program is designed to run on the Raspberry Pi and interface to the Analog Devices AD7124-8 Evaluation Board\n"
  "EVAL-AD7124-8SDZ via the 4 wire SPI interface.  No other MCU, including the EVAL-SDP-CB1Z System Demonstration Platform\n" 
  "(SDP) board, is necessary.  The Pi is operated as the Master, the AD7124 is the Slave.\n"
  "\n"  
  "Wiring:\n"
  "Connect:\n"
  "   Raspberry Pi Header J8                       EVAL-AD7124-8SDZ\n"  
  "     Signal        Pin Number                Signal       Pin Number\n"
  " GPIO 12 SPI0 MOSI   19                       DI         TDIN  or TDIN1\n"
  " GPIO 13 SPI0 MISO   21                       DO         TDOUT or TDOU1\n"
  " GPIO 14 SPI0 SCLK   23                       SCLK       TSCLK or TSCLK1\n"
  " GPIO 10 SPI0_CE0    24                       ~CS        TCS   or TCS1\n"
  "\n"
  
 );
}