Skip to content

Commit 17dd69b

Browse files
committed
simplify adc.c and USE_PRECISION_OPAMP
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.
1 parent d81d3d9 commit 17dd69b

File tree

2 files changed

+76
-35
lines changed

2 files changed

+76
-35
lines changed

src/adc.c

Lines changed: 67 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -23,37 +23,51 @@
2323
#include "adc.h"
2424
#include "t962.h"
2525
#include "sched.h"
26+
#include "config.h"
2627

27-
#define NUM_ADCH (2)
28-
#define OVERSAMPLING_BITS (4) // This is n (how many additional bits to supply)
29-
#define NUM_ACCUM (256) // This needs to be 4 ^ n
30-
#define ACCUM_MASK (NUM_ACCUM-1)
28+
// indices for channel 1 and 2 respectively
29+
static uint8_t i=0;
30+
static uint8_t j=0;
31+
// hold intermediate sums of 16 ADC samples (with 10 bits -> 14bits needed)
32+
static uint16_t sum1 = 0;
33+
static uint16_t sum2 = 0;
34+
// average values
35+
static uint32_t avg1 = 0;
36+
static uint32_t avg2 = 0;
3137

32-
static uint32_t ADres[NUM_ADCH];
33-
static uint16_t ADidx[NUM_ADCH];
34-
static uint16_t ADaccum[NUM_ADCH][NUM_ACCUM];
38+
// running average over 16 values (each a sum of 16 ADC samples)
39+
#define N 16
3540

36-
static void ADC_Accum(uint32_t chnum, uint32_t value) {
37-
uint16_t temp;
38-
chnum--;
39-
uint8_t idx = ADidx[chnum];
40-
41-
// Done
42-
if (value & (1 << 31)) {
43-
temp = (value >> 6) & 0x3ff;
44-
ADres[chnum] -= ADaccum[chnum][idx];
45-
ADaccum[chnum][idx] = temp;
46-
ADres[chnum] += temp;
47-
idx++;
48-
idx &= ACCUM_MASK;
49-
ADidx[chnum] = idx;
41+
// create a running average over 16 values of sums of 16 samples
42+
// duplicate code, it's not worth the effort of indirection
43+
static void average(uint32_t adc1, uint32_t adc2)
44+
{
45+
// for ADC1
46+
if (adc1 & (1 << 31)) {
47+
adc1 = (adc1 >> 6) & 0x3ff;
48+
sum1 += adc1;
49+
if (i == 15) {
50+
avg1 = ((N - 1) * avg1 + sum1) / N;
51+
i = sum1 = 0;
52+
} else
53+
i++;
54+
}
55+
// for ADC2
56+
if (adc2 & (1 << 31)) {
57+
adc2 = (adc2 >> 6) & 0x3ff;
58+
sum2 += adc2;
59+
if (j == 15) {
60+
avg2 = ((N - 1) * avg2 + sum2) / N;
61+
j = sum2 = 0;
62+
} else
63+
j++;
5064
}
5165
}
5266

5367
static int32_t ADC_Work(void) {
54-
ADC_Accum( 1, AD0DR1);
55-
ADC_Accum( 2, AD0DR2);
56-
return TICKS_US( 100 ); // Run 10000 times per second
68+
average(AD0DR1, AD0DR2);
69+
// Run once per ms, at 256 fold oversampling leads to 1 value every 0.256s
70+
return TICKS_US(1000);
5771
}
5872

5973
void ADC_Init( void ) {
@@ -65,19 +79,37 @@ void ADC_Init( void ) {
6579
AD0CR |= (1 << 16); // Burst
6680
AD0DR1;
6781
AD0DR2;
68-
for (int i = 0; i < NUM_ADCH; i++) {
69-
ADres[i] = ADidx[i] = 0;
70-
for (int j = 0; j < NUM_ACCUM; j++) {
71-
ADaccum[i][j] = 0;
72-
}
73-
}
7482
Sched_SetState( ADC_WORK, 2, 0); // Start right away
7583
}
7684

85+
86+
87+
/*
88+
* This is supposed to deliver values in 1/16 degree Celsius,
89+
* which is about 1 LSB for a pre-amplifier gain of about 80.
90+
* 80 x 41.276uV/K = 3.3021mV/K --> 0.9772 LSB/K (for Vref=3.3V)
91+
* The board has a 3.3V, 1% regulator, so nothing better than 3 degC is
92+
* to be hoped for! Returning a resolution of 1/16 deg C is pretty
93+
* useless.
94+
* Using a precision OPamp is strongly recommended (using a gain
95+
* of 222.2 --> 9.172mV/K -> 2.7141 LSB/K (for Vref=3.3V).
96+
*/
7797
int32_t ADC_Read(uint32_t chnum) {
78-
int32_t result=-1;
79-
if (chnum >= 1 && chnum <= 2) {
80-
result = ADres[chnum - 1] >> OVERSAMPLING_BITS;
81-
}
82-
return result;
98+
#ifndef USE_PRECISION_OPAMP
99+
if (chnum == 1)
100+
return avg1;
101+
if (chnum == 2)
102+
return avg2;
103+
#else
104+
// take care not to overflow an unsigned 32 bit value!
105+
// input is in 1/16th LSBs (up to 16*1024-1, or 14 bit)
106+
// factor is 0.36845 = 7369/20000
107+
#define TC_ADJUST(x) ((int32_t) ((x * 7369) / 20000))
108+
109+
if (chnum == 1)
110+
return TC_ADJUST(avg1);
111+
if (chnum == 2)
112+
return TC_ADJUST(avg2);
113+
#endif
114+
return -1;
83115
}

src/config.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@
3333
*/
3434
#define USE_FET_DRIVER
3535

36+
/*
37+
* use this to adjust gain and omit offset compensation settings
38+
* in sensor.c and setup.c
39+
* This needs a precision operational amplifier (like an OPA2333)
40+
* at a rather precise gain of 222.2 on the TC input!
41+
* The feedback resistors are 220k + 1.2k and 1.0k with 0.1% tolerance
42+
*/
43+
#define USE_PRECISION_OPAMP
44+
3645
/*
3746
* Normally the control input is the average of the first two TCs.
3847
* By defining this any TC that has a readout 5C (or more) higher

0 commit comments

Comments
 (0)