LPC_SC->PCLKSEL0 |= 0x3 << 24;
break;
default:
- printf("Warning: ADC CCLK clock divider must be 1, 2, 4 or 8. %u supplied.\n",
+ printf("ADC Warning: ADC CCLK clock divider must be 1, 2, 4 or 8. %u supplied.\n",
cclk_div);
printf("Defaulting to 1.\n");
LPC_SC->PCLKSEL0 |= 0x1 << 24;
clock_div=pclk / adc_clk_freq;
if (clock_div > 0xFF) {
- //printf("Warning: Clock division is %u which is above 255 limit. Re-Setting at limit.\n",
- // clock_div);
+ printf("ADC Warning: Clock division is %u which is above 255 limit. Re-Setting at limit.\n", clock_div);
clock_div=0xFF;
}
if (clock_div == 0) {
- printf("Warning: Clock division is 0. Re-Setting to 1.\n");
+ printf("ADC Warning: Clock division is 0. Re-Setting to 1.\n");
clock_div=1;
}
_adc_clk_freq=pclk / clock_div;
if (_adc_clk_freq > MAX_ADC_CLOCK) {
- printf("Warning: Actual ADC sample rate of %u which is above %u limit\n",
+ printf("ADC Warning: Actual ADC sample rate of %u which is above %u limit\n",
_adc_clk_freq / CLKS_PER_SAMPLE, MAX_ADC_CLOCK / CLKS_PER_SAMPLE);
while ((pclk / max_div) > MAX_ADC_CLOCK) max_div++;
- printf("Maximum recommended sample rate is %u\n", (pclk / max_div) / CLKS_PER_SAMPLE);
+ printf("ADC Warning: Maximum recommended sample rate is %u\n", (pclk / max_div) / CLKS_PER_SAMPLE);
}
LPC_ADC->ADCR =
void ADC::burst(int state) {
if ((state & 1) == 1) {
if (startmode(0) != 0)
- fprintf(stderr, "Warning. startmode is %u. Must be 0 for burst mode.\n", startmode(0));
+ fprintf(stderr, "ADC Warning. startmode is %u. Must be 0 for burst mode.\n", startmode(0));
LPC_ADC->ADCR |= (1 << 16);
}
else
Adc::Adc()
{
instance = this;
- this->adc = new mbed::ADC(1000, 8);
+ // ADC sample rate need to be fast enough to be able to read the enabled channels within the thermistor poll time
+ // even though ther maybe 32 samples we only need one new one within the polling time
+ const uint32_t sample_rate= 1000; // 1KHz sample rate
+ this->adc = new mbed::ADC(sample_rate, 8);
this->adc->append(sample_isr);
}
// returns the median value of the last 8 samples
return median_buffer[quick_median(median_buffer, num_samples)];
+#elif defined(OVERSAMPLE)
+ // Oversample to get 2 extra bits of resolution
+ // weed out top and bottom worst values then oversample the rest
+ // put into a 4 element moving average and return the average of the last 4 oversampled readings
+ static uint16_t ave_buf[num_channels][4]{0,0,0,0};
+ std::sort(median_buffer, median_buffer + num_samples);
+ uint32_t sum = 0;
+ for (int i = num_samples / 4; i < (num_samples - (num_samples / 4)); ++i) {
+ sum += median_buffer[i];
+ }
+ // this slows down the rate of change a little bit
+ ave_buf[channel][3]= ave_buf[channel][2];
+ ave_buf[channel][2]= ave_buf[channel][1];
+ ave_buf[channel][1]= ave_buf[channel][0];
+ ave_buf[channel][0]= sum >> OVERSAMPLE;
+ return (ave_buf[channel][0]+ave_buf[channel][1]+ave_buf[channel][2]+ave_buf[channel][3])/4;
+
#else
// sort the 8 readings and return the average of the middle 4
std::sort(median_buffer, median_buffer + num_samples);
sum += median_buffer[i];
}
return sum / (num_samples / 2);
+
#endif
}
#include "PinNames.h" // mbed.h lib
+#include <cmath>
+
class Pin;
namespace mbed {
class ADC;
}
+// define how many bits of extra resolution required
+// 2 bits means the 12bit ADC is 14 bits of resolution
+#define OVERSAMPLE 2
+
class Adc
{
public:
static Adc *instance;
void new_sample(int chan, uint32_t value);
+ // return the maximum ADC value, base is 12bits 4095.
+#ifdef OVERSAMPLE
+ int get_max_value() const { return 4095 << OVERSAMPLE;}
+#else
+ int get_max_value() const { return 4095;}
+#endif
private:
PinName _pin_to_pinname(Pin *pin);
mbed::ADC *adc;
-
static const int num_channels= 6;
+#ifdef OVERSAMPLE
+ // we need 4^n sample to oversample and we get double that to filter out spikes
+ static const int num_samples= powf(4, OVERSAMPLE)*2;
+#else
static const int num_samples= 8;
+#endif
// buffers storing the last num_samples readings for each channel
uint16_t sample_buffers[num_channels][num_samples];
};
}
int adc_value= new_thermistor_reading();
+ const uint32_t max_adc_value= THEKERNEL->adc->get_max_value();
+
// resistance of the thermistor in ohms
- float r = r2 / ((4095.0F / adc_value) - 1.0F);
+ float r = r2 / (((float)max_adc_value / adc_value) - 1.0F);
if (r1 > 0.0F) r = (r1 * r) / (r1 - r);
THEKERNEL->streams->printf("adc= %d, resistance= %f\n", adc_value, r);
}
}
-float Thermistor::adc_value_to_temperature(int adc_value)
+float Thermistor::adc_value_to_temperature(uint32_t adc_value)
{
- if ((adc_value >= 4095) || (adc_value == 0))
+ const uint32_t max_adc_value= THEKERNEL->adc->get_max_value();
+ if ((adc_value >= max_adc_value) || (adc_value == 0))
return infinityf();
// resistance of the thermistor in ohms
- float r = r2 / ((4095.0F / adc_value) - 1.0F);
+ float r = r2 / (((float)max_adc_value / adc_value) - 1.0F);
if (r1 > 0.0F) r = (r1 * r) / (r1 - r);
if(r > this->r0 * 8) return infinityf(); // 800k is probably open circuit
private:
int new_thermistor_reading();
- float adc_value_to_temperature(int adc_value);
+ float adc_value_to_temperature(uint32_t adc_value);
void calc_jk();
// Thermistor computation settings using beta, not used if using Steinhart-Hart