Skip to content

Commit

Permalink
simplify adc.c and USE_PRECISION_OPAMP
Browse files Browse the repository at this point in the history
  adc.c used a buffer of 2 x 256 x 2 byte = 1024 bytes to
calculate the sum over the last 256 values for oversampling.
This is pretty useless in the first place as accuracy below 1K
are not to be expected even with a precision opamp instead of the
TLC27L2. The current implementation at least gets rid of the
buffer completely by using a running average method.
Along with the change the sampling is reduced to once per ms
instead of ever 100us, which was an overkill, new values
are delivered every 256ms now, which is good enough.

USE_PRECISION_OPAMP switches the internal gain to 0.36845 as the
pre-amplifier is supposed to have a gain of 222.2 (see adc.c).
At 300 degree C it uses 834 LSBs instead of only 307.

Using an OPA2333 or similiar and replacing the trim resistors
by fixed (and accurate) resistors will do the trick.
  • Loading branch information
taliesin committed Mar 8, 2018
1 parent d81d3d9 commit 17dd69b
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 35 deletions.
102 changes: 67 additions & 35 deletions src/adc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) {
Expand All @@ -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;
}
9 changes: 9 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 17dd69b

Please sign in to comment.