Hamlib/ts7400/include/test7400ADC.c

439 wiersze
8.7 KiB
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;
/*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;
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);
//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);
//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;
close(devmem);
return ret_val;
}