/*
Fast ADC
Continous sampling
https://github.com/PaulStoffregen/cores/blob/master/teensy3/analog.c
*/
#define VREF_MARGIN 0.02
#define DAC_RANGE 4096.0
#define DAC_MARGIN (0.02 * DAC_RANGE)
void ADC1_init(uint8_t channel);
uint16_t ADC1_read(uint8_t channel);
const int ledPin = 13;
void setup() {
// Config
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
pinMode(A20, INPUT);
// Set 12 bit resolution
analogWriteResolution(12);
analogReadResolution(12);
ADC1_init(A20);
}
void loop() {
int volts_read, error;
float mean, desvest;
int const average_dots = 128;
// DAC range sweep
for(int volts_write=DAC_MARGIN; volts_write<DAC_RANGE-DAC_MARGIN; volts_write++) {
// Change DAC output
analogWrite(A21, volts_write);
delayMicroseconds(20);
// Compute mean and standard deviation of error
mean = desvest = 0;
for(int j=0; j<average_dots; j++) {
volts_read = analogRead(A20); // ADC1_read(A20);
*portToggleRegister(ledPin) = 1;
error = volts_write - volts_read;
mean += error;
desvest += error*error;
}
mean = mean * (1.0/average_dots);
desvest
= sqrt(desvest
* (1.0/average_dots
) - mean
*mean
);
// Print mean and standard deviation of error
Serial.print("Volts="); Serial.print(volts_write);
Serial.print("\tMean="); Serial.print(mean);
Serial.print("\tDesvest="); Serial.print(desvest);
Serial.println();
}
while(Serial.read() < 0);
}
/**************************************************************************/
// __MK64FX512__ and __MK66FX1M0__ Teensy analog pins definitions
// Numbers below 128 belongs to ADC0. Numbers greater than 128 belongs to ADC1
// Source: https://github.com/PaulStoffregen/cores/blob/master/teensy3/analog.c
static const uint8_t pin2sc1a[] = {
5, 14, 8, 9, 13, 12, 6, 7, 15, 4, 3, 19+128, 14+128, 15+128, // 0-13 -> A0-A13
5, 14, 8, 9, 13, 12, 6, 7, 15, 4, // 14-23 are A0-A9
255, 255, 255, 255, 255, 255, 255, // 24-30 are digital only
14+128, 15+128, 17, 18, 4+128, 5+128, 6+128, 7+128, 17+128, // 31-39 are A12-A20
255, 255, 255, 255, 255, 255, 255, 255, 255, // 40-48 are digital only
10+128, 11+128, // 49-50 are A23-A24
255, 255, 255, 255, 255, 255, 255, // 51-57 are digital only
255, 255, 255, 255, 255, 255, // 58-63 (sd card pins) are digital only
3, 19+128, // 64-65 are A10-A11
23, 23+128,// 66-67 are A21-A22 (DAC pins)
1, 1+128, // 68-69 are A25-A26 (unused USB host port on Teensy 3.5)
26, // 70 is Temperature Sensor
18+128 // 71 is Vref
};
// Init ADC1
void ADC1_init(uint8_t channel) {
uint32_t ADC_CFG1, ADC_CFG2, ADC_SC1A;
if (channel > sizeof(pin2sc1a)) return;
ADC_CFG1 =
//+ ADC_CFG1_ADLPC // Low-power configuration
//+ ADC_CFG1_ADLSMP // Long Sample Time
+ ADC_CFG1_MODE(1) // 0=8bit, 1=12bit, 2=10bit, 3=16bit
+ ADC_CFG1_ADIV(1) // Clock divide, 0=direct, 1=div2, 2=div4, 3=div8
+ ADC_CFG1_ADICLK(1) // Input clock, 0=bus, 1=bus/2, 2= , 3=async
+ 0;
ADC1_CFG1 = ADC_CFG1;
ADC_CFG2 =
//+ ADC_CFG2_MUXSEL // Selects ADxxB channels instead ADxxA channels
//+ ADC_CFG2_ADACKEN // Async clock enable
//+ ADC_CFG2_ADHSC // Add 2 extra clocks to conversion (for high speed clocks)
//+ ADC_CFG2_ADLSTS(3) // Extra clocks for long sample (ADLSMP=1) (0=24,1=12,2=6,3=4)
+ 0;
ADC1_CFG2 = ADC_CFG2;
ADC_SC1A =
//+ ADC_SC1_COCO // Conversion Complete
//+ ADC_AIEN // Interrupt Enable
//+ ADC_DIFF // Differential Mode Enable
+ pin2sc1a[channel]; // Input channel select and conversion init
ADC1_SC1A = ADC_SC1A;
ADC1_SC2 =
//+ ADC_SC2_ADACT // Conversion active
//+ ADC_SC2_ADTRG // Conversion Trigger 0=Software, 1=Hardware
//+ ADC_SC2_ACFE // Compare Function Enable
//+ ADC_SC2_ACFGT // Compare Function Greater Than Enable
//+ ADC_SC2_ACREN // Compare Function Range Enable
//+ ADC_SC2_DMAEN // DMA Enable
+ ADC_SC2_REFSEL(0); // Voltage Reference 0=Ext pins, 1=Alternate Ext. pins
ADC1_SC3 =
//+ ADC_SC3_CAL // Init Calibration
//+ ADC_SC3_CALF // Calibration Failed
+ ADC_SC3_ADCO // Continuous conversion Enable
//+ ADC_SC3_AVGE // Hardware average enable
//+ ADC_SC3_AVGS(3) // Hardware average 0=4 sampl, 1=8 sampl, 2=16 sampl, 3=32 sampl
+0;
// Start Calibration
ADC1_SC3 |= ADC_SC3_CAL;
while ((ADC1_SC3 & ADC_SC3_CAL)) {
if (ADC1_SC3 & ADC_SC3_CALF) {
Serial.println("Calibration error");
return;
}
}
ADC1_SC3 &= ~ADC_SC3_CAL;
ADC1_CFG1 = ADC_CFG1;
ADC1_CFG2 = ADC_CFG2;
// Conversion init
ADC1_SC1A = ADC_SC1A;
//Serial.println(ADC_SC1A); for(;;);
}
// Read ADC1
uint16_t ADC1_read(uint8_t channel) {
// Change channel and init conversion.
// ADC0_SC1A = (ADC0_SC1A & (~(int)0x1F)) + pin2sc1a[channel & 0x1F]
while ((ADC1_SC1A & ADC_SC1_COCO) == 0);
return ADC1_RA;
}