Skip to content

Commit

Permalink
Merge pull request #20 from laurb9/vref_calibration
Browse files Browse the repository at this point in the history
AVR: Calibrate AREF and autodetect between 3.3 or 5V Vcc using the
  • Loading branch information
laurb9 committed Mar 2, 2015
2 parents da1bcda + d5ef1c9 commit 7ee3d6c
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 10 deletions.
4 changes: 4 additions & 0 deletions adc.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ class ADCBase {
*buffer++ = ADCBase::readFast();
}
};
// calibration function, return corrected AREF based on Vbg measured against it.
uint16_t calibrateAREF(){
return 0;
}

/*
* ADC Information
Expand Down
43 changes: 38 additions & 5 deletions adc_avr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
#include "adc_avr.h"
#if defined(ADCSRA) && defined(ADCL)

// Actual voltage of Vbg (internal 1.1V ref) in mV. This is different from chip to chip.
// = 5000*1100/VREFmeasured (with accurate multimeter). 3300*1100/VREFmeasured for 3.3V systems.
#define INTERNAL_REF_MV 1090

const uint8_t ADCInput::prescalers[] = {7,6,5,4,3,2}; // 1:8MHz clock is out of ADC spec for 16MHz AVR

bool ADCInput::init(uint8_t newInput, uint8_t mode){
Expand All @@ -48,24 +52,28 @@ uint8_t ADCInput::getModeCount(){
/*
* Set ADC prescaler
*/
void ADCInput::setPrescaler(uint8_t mode){
bool ADCInput::setPrescaler(uint8_t mode){
if (mode < ADCInput::getModeCount()){
curMode = mode;
uint8_t prescaler = prescalers[mode];
prescaler & 4 ? sbi(ADCSRA,ADPS2) : cbi(ADCSRA,ADPS2);
prescaler & 2 ? sbi(ADCSRA,ADPS1) : cbi(ADCSRA,ADPS1);
prescaler & 1 ? sbi(ADCSRA,ADPS0) : cbi(ADCSRA,ADPS0);
sbi(ADCSRA, ADEN);
delay(10); // allow the ADC to settle
} else {
return false;
}
delay(10); // allow the ADC to settle
return true;
}

/*
* Configure ADC for given mode.
*/
bool ADCInput::setMode(uint8_t mode){
ADCInput::setPrescaler(mode);
return 1;
if (ADCInput::setPrescaler(mode)){
curMode = mode;
}
return (curMode = mode);
}

/*
Expand All @@ -90,6 +98,31 @@ void ADCInput::readMulti(uint16_t *buffer, unsigned size){
cbi(ADCSRA, ADATE); // Disable free running
}

/*
* Read internal reference voltage.
*/
uint16_t ADCInput::calibrateAREF(){
// reset ADC to default mode for highest precision.
setPrescaler(0);
read(); // allow the port to be configured (discard result)

ADMUX = (ADMUX & 0xf0) | 0x0e; // switch to reading the internal 1.1V reference

// wait for the reference input to stabilize
readFast();
delay(200);
uint16_t reference = readFast();

// reference should represent 1100mV
uint16_t rangemV = INTERNAL_REF_MV * ((1L<<bits)-1) / long(reference);

// set ADC to previous mode
setPrescaler(curMode);
read();

return rangemV;
}

/*
* Return ADC clock in Hz. This is only useful to estimate sampling rate.
*/
Expand Down
3 changes: 2 additions & 1 deletion adc_avr.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
class ADCInput : public ADCBase {
protected:
uint8_t curMode;
void setPrescaler(uint8_t mode);
bool setPrescaler(uint8_t mode);
public:
static const uint8_t prescalers[];
uint8_t input; // analog input port
Expand All @@ -51,6 +51,7 @@ class ADCInput : public ADCBase {
loop_until_bit_is_clear(ADCSRA, ADSC); // Conversion finished
return ADCL | (ADCH << 8);
}
uint16_t calibrateAREF();
};

#endif /* ADC_AVR_H_ */
1 change: 1 addition & 0 deletions capture.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class Capture {
uint16_t *data;

int init(ADCInput adc, unsigned samples, uint16_t rangemV);
void calibrate();
void capture();
void tomV();
};
Expand Down
2 changes: 1 addition & 1 deletion scope.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// Maximum number of horizontal grid lines
#define MAX_X_GRID_LINES 10
// Maximum number of vertical grid lines
#define MAX_Y_GRID_LINES 5
#define MAX_Y_GRID_LINES 6

class Scope {
protected:
Expand Down
8 changes: 5 additions & 3 deletions tiny_scope.ino
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void displaySplash(){
display.print(F("Tiny Scope"));

display.setTextSize(1);
display.printf(F("\nINPUT A%d VREF "), capture.adc.input);
display.printf(F("\nINPUT %d VREF "), capture.adc.input);
display.printSmallUnits(1000L*capture.rangemV, "V\n"); // printSmallUnits expects micro[V]
if (capture.adc.getClock()){
display.print(F("ADC CLOCK "));
Expand All @@ -73,8 +73,10 @@ void displaySplash(){
}

void setup(){
int success = capture.init(ADCInput(), SCREEN_WIDTH, AREF_MV);
capture.adc.init(ADC_PIN, EEPROM.read(ADC_MODE_ADDR));
ADCInput adc = ADCInput();
adc.init(ADC_PIN, EEPROM.read(ADC_MODE_ADDR));
uint16_t aref = adc.calibrateAREF();
int success = capture.init(adc, SCREEN_WIDTH, (aref) ? aref : AREF_MV);
delay(100); // give time for display to init; if display blank increase delay
display.begin(SSD1306_SWITCHCAPVCC, DISPLAY_I2C_ADDRESS);
display.setRotation(2);
Expand Down

0 comments on commit 7ee3d6c

Please sign in to comment.