diff --git a/src/adc.c b/src/adc.c index d1f1f27..5eb342f 100644 --- a/src/adc.c +++ b/src/adc.c @@ -23,37 +23,51 @@ #include "adc.h" #include "t962.h" #include "sched.h" +#include "config.h" -#define NUM_ADCH (2) -#define OVERSAMPLING_BITS (4) // This is n (how many additional bits to supply) -#define NUM_ACCUM (256) // This needs to be 4 ^ n -#define ACCUM_MASK (NUM_ACCUM-1) +// indices for channel 1 and 2 respectively +static uint8_t i=0; +static uint8_t j=0; +// hold intermediate sums of 16 ADC samples (with 10 bits -> 14bits needed) +static uint16_t sum1 = 0; +static uint16_t sum2 = 0; +// average values +static uint32_t avg1 = 0; +static uint32_t avg2 = 0; -static uint32_t ADres[NUM_ADCH]; -static uint16_t ADidx[NUM_ADCH]; -static uint16_t ADaccum[NUM_ADCH][NUM_ACCUM]; +// running average over 16 values (each a sum of 16 ADC samples) +#define N 16 -static void ADC_Accum(uint32_t chnum, uint32_t value) { - uint16_t temp; - chnum--; - uint8_t idx = ADidx[chnum]; - - // Done - if (value & (1 << 31)) { - temp = (value >> 6) & 0x3ff; - ADres[chnum] -= ADaccum[chnum][idx]; - ADaccum[chnum][idx] = temp; - ADres[chnum] += temp; - idx++; - idx &= ACCUM_MASK; - ADidx[chnum] = idx; +// create a running average over 16 values of sums of 16 samples +// duplicate code, it's not worth the effort of indirection +static void average(uint32_t adc1, uint32_t adc2) +{ + // for ADC1 + if (adc1 & (1 << 31)) { + adc1 = (adc1 >> 6) & 0x3ff; + sum1 += adc1; + if (i == 15) { + avg1 = ((N - 1) * avg1 + sum1) / N; + i = sum1 = 0; + } else + i++; + } + // for ADC2 + if (adc2 & (1 << 31)) { + adc2 = (adc2 >> 6) & 0x3ff; + sum2 += adc2; + if (j == 15) { + avg2 = ((N - 1) * avg2 + sum2) / N; + j = sum2 = 0; + } else + j++; } } static int32_t ADC_Work(void) { - ADC_Accum( 1, AD0DR1); - ADC_Accum( 2, AD0DR2); - return TICKS_US( 100 ); // Run 10000 times per second + average(AD0DR1, AD0DR2); + // Run once per ms, at 256 fold oversampling leads to 1 value every 0.256s + return TICKS_US(1000); } void ADC_Init( void ) { @@ -65,19 +79,37 @@ void ADC_Init( void ) { AD0CR |= (1 << 16); // Burst AD0DR1; AD0DR2; - for (int i = 0; i < NUM_ADCH; i++) { - ADres[i] = ADidx[i] = 0; - for (int j = 0; j < NUM_ACCUM; j++) { - ADaccum[i][j] = 0; - } - } Sched_SetState( ADC_WORK, 2, 0); // Start right away } + + +/* + * This is supposed to deliver values in 1/16 degree Celsius, + * which is about 1 LSB for a pre-amplifier gain of about 80. + * 80 x 41.276uV/K = 3.3021mV/K --> 0.9772 LSB/K (for Vref=3.3V) + * The board has a 3.3V, 1% regulator, so nothing better than 3 degC is + * to be hoped for! Returning a resolution of 1/16 deg C is pretty + * useless. + * Using a precision OPamp is strongly recommended (using a gain + * of 222.2 --> 9.172mV/K -> 2.7141 LSB/K (for Vref=3.3V). + */ int32_t ADC_Read(uint32_t chnum) { - int32_t result=-1; - if (chnum >= 1 && chnum <= 2) { - result = ADres[chnum - 1] >> OVERSAMPLING_BITS; - } - return result; +#ifndef USE_PRECISION_OPAMP + if (chnum == 1) + return avg1; + if (chnum == 2) + return avg2; +#else + // take care not to overflow an unsigned 32 bit value! + // input is in 1/16th LSBs (up to 16*1024-1, or 14 bit) + // factor is 0.36845 = 7369/20000 +#define TC_ADJUST(x) ((int32_t) ((x * 7369) / 20000)) + + if (chnum == 1) + return TC_ADJUST(avg1); + if (chnum == 2) + return TC_ADJUST(avg2); +#endif + return -1; } diff --git a/src/config.h b/src/config.h index 0c9e2ac..5f4f152 100644 --- a/src/config.h +++ b/src/config.h @@ -33,6 +33,15 @@ */ #define USE_FET_DRIVER +/* + * use this to adjust gain and omit offset compensation settings + * in sensor.c and setup.c + * This needs a precision operational amplifier (like an OPA2333) + * at a rather precise gain of 222.2 on the TC input! + * The feedback resistors are 220k + 1.2k and 1.0k with 0.1% tolerance + */ +#define USE_PRECISION_OPAMP + /* * Normally the control input is the average of the first two TCs. * By defining this any TC that has a readout 5C (or more) higher