Logo Search packages:      
Sourcecode: hamlib version File versions  Download package

readADC.c

#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <assert.h>

#include "peekpoke.h"
#include "ep93xx_adc.h"

#define DATA_PAGE    0x12C00000
#define CALIB_LOC    2027          //location of calibration values
#define NUM_SAMPLES  5
#define NUM_CHANNELS 4

/* globals */
static unsigned long adc_page, syscon_page;
char *dr_page;
double el,az;

/*Calculate the adc value corresponding to 0V*/
//val1 is the ADC val coresponding to 0.833V
//val2 is the ADC val corresponging to 2.5V
int calcZeroVal(int val1, int val2)
{
      val2 += 0x10000;
      return (int)(val1-(((val2-val1)/(2.5-0.833))*0.833));
}


//return value of 1 indicates the board has no calibration values
//return value of 0 indicates the board has calibration values
int read_calibration(int buf[NUM_CHANNELS][2])
{
      int i,j,k = 0;
      unsigned short cal[NUM_CHANNELS*2];
      // read 16 calibration bytes into buffer
      FILE *f = fopen("/etc/ADC-calibration.dat","r");

      if (!f) goto empty_calibration;

      printf("Non-virgin board detected, evaluating stored "
            "calibration values\n");
      printf("Stored Calibration values [");

      if (fread(cal,NUM_CHANNELS*4,1,f) == 1)
      {
            for(j=0;j<2;j++)
                  for(i=0;i<NUM_CHANNELS;i++)
                  {
                        printf("0x%x", cal[k]);
                        buf[i][j] = cal[k];
                        k++;

                        if(k < NUM_CHANNELS*2)
                              printf(", ");

                  }
                  printf("]\n");
            return 1;
      }
      empty_calibration:

      printf("/etc/ADC-calibration.dat not found or it's not readable\n");

      return 0;
}

void write_calibration(int cal[NUM_CHANNELS][2])
{
      unsigned short buf[16];
      int i,j,k=0;
      FILE *f = fopen("/etc/ADC-calibration.dat","w");

      //Convert 32 bit vals to 16 bit vals
      for(j=0;j<2;j++)
            for(i=0;i<NUM_CHANNELS;i++)
            {
                  buf[k] = (unsigned short)cal[i][j];
                  k++;

            }
      if (!f) goto unwrite_calibration;

      if (fwrite(buf,NUM_CHANNELS*4,1,f) == 1) return;

      unwrite_calibration:

      printf("Problem writing /etc/ADC-calibration.dat: %m\n");
}

static void erase_calibration()
{
      printf("Erasing calibration values...\n");
      unlink("/etc/ADC-calibration.dat");
}

int check_calibration(int cal[NUM_CHANNELS][2],
      int stored_cal[NUM_CHANNELS][2], int state)
{
      double pcnt_diff;
      int i,j,erase_cal =0;
      int failure = 0;

      if(state == 0)    //no calibration values
      {
            printf("Virgin board detected...\n");
            for(j=0;j<2;j++)
            {

                  for(i=0;i<NUM_CHANNELS;i++)
                  {

                        if(j == 0)
                              pcnt_diff = (((double)abs(0xa000 -
                              cal[i][j])) / 0xa000) * 100;
                        else
                              pcnt_diff = (((double)abs(0x3300 -
                              cal[i][j])) / 0x3300) * 100;

                        if(pcnt_diff > 10)
                        {
                              printf("Calculated calibration "
                              "values out of range...\n");

                              exit(-1);
                        }

                  }
            }

            write_calibration(cal);

      } else            //calibration values read
      {

            for(j=0;j<2;j++)
            {
                  for(i=0;i<NUM_CHANNELS;i++)
                  {

                        pcnt_diff = (((double)abs(stored_cal[i][j] -
                          cal[i][j])) / stored_cal[i][j])
                          * 100;
                        if(pcnt_diff > 0.25)
                        {
                              if(!failure)
                              {
                                    printf("Calibration values out"
                                          "of range\n");
                                    failure = 1;
                                    erase_cal = 1;
                              }
                              printf("\tChannel %d: %3.3f%%\n",i
                                , pcnt_diff);
                        }
                  }
            }
      }

      if(erase_cal) erase_calibration();
      if(failure) return 0;

      return 1;
}

void setDR(char *x,int n,int val)
{
      if (n < 0 || n > 8)
            return;

      x[0] = (x[0] & ~(1 << n)) | (val ? (1<<n) : 0);
}

void setD(char *x,int n,int val)
{
      if (n < 0 || n > 8)
            return;

      x[2] = (x[2] & ~(1 << n)) | (val ? (1<<n) : 0);
}

double get_volts(int val, int zero, int range)
{
      if(val <= 0x7000)
            val = val + 0x10000;

      val = val - zero;

      return  ((double)val * 3.3) / range;
}

void calc_calibration(int calibration[NUM_CHANNELS][2],
      int adc_result_1[NUM_CHANNELS][NUM_SAMPLES],
      int adc_result_2[NUM_CHANNELS][NUM_SAMPLES])
{
      int i, j;

      /* zero out our calibration values */
      for(i = 0; i < NUM_CHANNELS; i++)
            for(j = 0; j < 2; j++)
                  calibration[i][j] = 0;

      //convert 0.833V vals to 0V vals
      for(i=0;i<NUM_CHANNELS;i++)
      {
            for(j=0;j<NUM_SAMPLES;j++)
            {
                  if(i % 2)//odd channels
                        adc_result_1[i][j] =
                          calcZeroVal(adc_result_1[i][j],
                          adc_result_1[0][j]);
                  else
                        adc_result_2[i][j] =
                          calcZeroVal(adc_result_2[i][j],
                          adc_result_2[1][j]);
            }
      }

      //sum the readings
      for(i = 0; i < NUM_CHANNELS; i++)
      {
            for(j = 0; j < NUM_SAMPLES; j++ )
            {
                  if(i % 2 == 0 )
                  {
                        //0.833 volt values
                        calibration[i][0] = adc_result_2[i][j]
                          + calibration[i][0];
                        //2.5 volt values
                        calibration[i][1] = adc_result_1[i][j]
                          + calibration[i][1];
                  } else
                  {
                        //0.833 volt values
                        calibration[i][0] = adc_result_1[i][j]
                          + calibration[i][0];
                        //2.5 volt values
                        calibration[i][1] = adc_result_2[i][j]
                          + calibration[i][1];
                  }
            }
      }

      //printf("Calculated Calibration values [");
      for(j = 0; j < 2; j++)
      {
            for(i = 0; i < NUM_CHANNELS; i++)
            {
                  calibration[i][j] = (calibration[i][j] / NUM_SAMPLES);

                  //printf("0x%x", calibration[i][j]);

                  //if((i == NUM_CHANNELS-1) && (j == 1))
                        //printf("]\n");
                  //else
                        //printf(", ");
            }
      }
}

/************************************************************************
 *DESCRIPTION: Read the EP93xx onboard ADC. Discard the first
 *two samples then save the next NUM_SAMPLES.
 ***********************************************************************/
static void read_7xxx_adc(int adc_result[NUM_CHANNELS][NUM_SAMPLES])
{
      int i, j, cur_ch;

      for(i = 0; i < NUM_CHANNELS; i++)
      {
            switch(i)
            {
                  case 0:
                        cur_ch = ADC_CH0;
                  break;
                  case 1:
                        cur_ch = ADC_CH1;
                  break;
                  case 2:
                        cur_ch = ADC_CH2;
                  break;
                  case 3:
                        cur_ch = ADC_CH3;
                  break;
                  case 4:
                        cur_ch = ADC_CH4;
                  break;

            }

            //discard first two samples
            read_channel(adc_page, cur_ch);
            read_channel(adc_page, cur_ch);

            //read more samples
            for(j = 0; j < NUM_SAMPLES; j++)
            {
                  usleep(10000);
                  adc_result[i][j] = read_channel(adc_page, cur_ch);
            }
      }
}

int test_ADC(int calibration[NUM_CHANNELS][2])
{
      int adc_result_1[NUM_CHANNELS][NUM_SAMPLES];
      int adc_result_2[NUM_CHANNELS][NUM_SAMPLES];
      int i, j, return_val;
      int failure = 0;
      //double voltage,el,az;
    double voltage;

      setD(dr_page, 0, 1);    //ADC1 = ADC3 = 0.833V
      setD(dr_page, 2, 1);    //ADC0 = ADC2 = 2.5V
      read_7xxx_adc(adc_result_1);

      setD(dr_page, 0, 0);    //ADC1 = ADC3 = 2.5V
      setD(dr_page, 2, 1);    //ADC0 = ADC2 = 0.833V
      read_7xxx_adc(adc_result_2);


      el = get_volts(adc_result_1[0][0], 0x9E58, 0xC350);
      az = get_volts(adc_result_1[1][0], 0x9E58, 0xC350);

      el = (el/3.3) * 180;
      az = (az/3.3) * 360;
      //printf("\t El.: %3.1f Az.: %3.1f  \n", el, az);

      //verify results are within range
      for(i=0;i<NUM_CHANNELS;i++)
      {
            for(j=0;j<NUM_SAMPLES;j++)
            {
                  //use the datasheet values
                  voltage = get_volts(adc_result_1[i][j], 0x9E58, 0xC350);
                  //printf("\tChannel %d: %3.1f \n", i, voltage);
                  //even channels 2.5V(+-150mV)
                  if(i % 2 == 0 &&
                    (voltage < 2.35 || voltage > 2.65))
                  {
                        if(!failure)
                        {
                              failure = 1;
                              //printf("EP93XX ADC out of range\n");
                        }
                        //printf("\tChannel %d: %3.3fV"
                          //"(expected 2.5V +- 150mV)\n", i, voltage);
                  //odd channels 0.833(+-50mV)
                  }
                  else if(i % 2 == 1 &&
                      (voltage < 0.333 || voltage > 1.333))
                  {
                        if(!failure)
                        {
                              failure = 1;
                              //printf( "EP93xx ADC out of range\n");
                        }

                        //printf("\tChannel %d: %3.3fV"
                         // "(expected 0.833V +- 50mV)\n", i, voltage);
                  }


                  //use the datasheet values
                  voltage = get_volts(adc_result_2[i][j], 0x9E58, 0xC350);

                  //odd channels 2.5V(+-150mV)
                  if(i % 2 == 1 &&
                    (voltage < 2.35 || voltage > 2.65))
                  {
                        if(!failure)
                        {
                              failure = 1;
                              //printf("EP93XX ADC out of range\n");
                        }
                        //printf("\tChannel %d: %3.3fV"
                          //"(expected 2.5V +- 150mV)\n", i, voltage);
                  //even channels 0.833(+-50mV)
                  }
                  else if(i % 2 == 0 &&
                      (voltage < 0.333 || voltage > 1.333))
                  {
                        if(!failure)
                        {
                              failure = 1;
                              //printf( "EP93xx ADC out of range\n");
                        }

                        ///printf("\tChannel %d: %3.3fV" "(expected 0.833V +- 50mV)\n", i, voltage);
                  }
            }
      }


      calc_calibration(calibration, adc_result_1, adc_result_2);

      if(failure)
            return_val = 0;
      else return_val = 1;

      return return_val;
}




int main(void)
{
      int calibration[NUM_CHANNELS][2];
      int stored_calibration[NUM_CHANNELS][2];
      int ret_val, state;
      int devmem = open("/dev/mem", O_RDWR|O_SYNC);
      assert(devmem != -1);

      dr_page = mmap(0, getpagesize(), PROT_READ|PROT_WRITE,
        MAP_SHARED, devmem, DATA_PAGE);
      assert(&dr_page != MAP_FAILED);
      adc_page = (unsigned long)mmap(0, getpagesize(), PROT_READ|PROT_WRITE,
            MAP_SHARED, devmem, ADC_PAGE);
      assert(&adc_page != MAP_FAILED);
      syscon_page = (unsigned long)mmap(0, getpagesize(), PROT_READ|PROT_WRITE
        , MAP_SHARED, devmem, SYSCON_PAGE);
        assert(&syscon_page != MAP_FAILED);

      init_ADC(adc_page, syscon_page);
      setDR(dr_page, 0, 1);
      setDR(dr_page, 1, 0);
      setDR(dr_page, 2, 1);
      setDR(dr_page, 3, 0);


      if(test_ADC(calibration))
      {
            printf("ADC tested ok(data sheet values)\n");
            state = read_calibration(stored_calibration);

            if(check_calibration(calibration, stored_calibration, state))
                  ret_val = 0;
            else
                  ret_val = 1;

      }
      else
            ret_val = 1;
      printf("\t El.: %3.1f Az.: %3.1f  \n", el, az);
      close(devmem);
      return ret_val;
}

Generated by  Doxygen 1.6.0   Back to index