diff --git a/libraries/SAMD_AnalogCorrection/examples/CorrectADCResponse/CorrectADCResponse.ino b/libraries/SAMD_AnalogCorrection/examples/CorrectADCResponse/CorrectADCResponse.ino new file mode 100644 index 0000000000000000000000000000000000000000..2b74538e17405b24d921dd7f1f460f79fa83f8aa --- /dev/null +++ b/libraries/SAMD_AnalogCorrection/examples/CorrectADCResponse/CorrectADCResponse.ino @@ -0,0 +1,210 @@ +/* + This sketch easily and quickly finds the right ADC correction values for a particular Arduino ZERO board. + The correction values that are found are only valid for the board where the sketch is executed. + + This example code is in the public domain. + + Written 6 May 2015 by Claudio Indellicati +*/ + +/* + How to use this sketch + + 1) Remove any connection cable, shield or jumper from your Arduino ZERO + 2) Connect pin A1 to the nearest GND pin using the shortest jumper possible + 3) Connect pin A2 to the 3.3V pin using the shortest jumper possible + 4) Connect the Arduino ZERO to your PC using a USB cable plugged in the USB programming port of the board + 5) Upload this sketch and leave the board powered on for at least one minute + 6) Open the Serial Monitor and press the reset button on the Arduino ZERO + 7) At the and of the procedure you can find logged + - the offset and gain values for the board where the sketch has been just executed + - the instruction line to copy/paste in the final sketch +*/ + +#include "SAMD_AnalogCorrection.h" + +#define ADC_GND_PIN A1 +#define ADC_3V3_PIN A2 + +#define ADC_READS_SHIFT 8 +#define ADC_READS_COUNT (1 << ADC_READS_SHIFT) + +#define ADC_MIN_GAIN 0x0400 +#define ADC_UNITY_GAIN 0x0800 +#define ADC_MAX_GAIN (0x1000 - 1) +#define ADC_RESOLUTION_BITS 12 +#define ADC_RANGE (1 << ADC_RESOLUTION_BITS) +#define ADC_TOP_VALUE (ADC_RANGE - 1) + +#define MAX_TOP_VALUE_READS 10 + +void setup() +{ + Serial.begin(9600); + + Serial.println("\r\nCalibrating ADC with factory values"); + + analogReadResolution(ADC_RESOLUTION_BITS); + + Serial.println("\r\nReading GND and 3.3V ADC levels"); + Serial.print(" "); + readGndLevel(); + Serial.print(" "); + read3V3Level(); + + int offsetCorrectionValue = 0; + uint16_t gainCorrectionValue = ADC_UNITY_GAIN; + + Serial.print("\r\nOffset correction (@gain = "); + Serial.print(gainCorrectionValue); + Serial.println(" (unity gain))"); + + // Set default correction values and enable correction + analogReadCorrection(offsetCorrectionValue, gainCorrectionValue); + + for (int offset = 0; offset < (int)(ADC_OFFSETCORR_MASK >> 1); ++offset) + { + analogReadCorrection(offset, gainCorrectionValue); + + Serial.print(" Offset = "); + Serial.print(offset); + Serial.print(", "); + + if (readGndLevel() == 0) + { + offsetCorrectionValue = offset; + break; + } + } + + Serial.println("\r\nGain correction"); + + uint8_t topValueReadsCount = 0U; + + uint16_t minGain = 0U, + maxGain = 0U; + + analogReadCorrection(offsetCorrectionValue, gainCorrectionValue); + Serial.print(" Gain = "); + Serial.print(gainCorrectionValue); + Serial.print(", "); + uint16_t highLevelRead = read3V3Level(); + + if (highLevelRead < ADC_TOP_VALUE) + { + for (uint16_t gain = ADC_UNITY_GAIN + 1; gain <= ADC_MAX_GAIN; ++gain) + { + analogReadCorrection(offsetCorrectionValue, gain); + + Serial.print(" Gain = "); + Serial.print(gain); + Serial.print(", "); + highLevelRead = read3V3Level(); + + if (highLevelRead == ADC_TOP_VALUE) + { + if (minGain == 0U) + minGain = gain; + + if (++topValueReadsCount >= MAX_TOP_VALUE_READS) + { + maxGain = minGain; + break; + } + + maxGain = gain; + } + + if (highLevelRead > ADC_TOP_VALUE) + break; + } + } + else if (highLevelRead >= ADC_TOP_VALUE) + { + if (highLevelRead == ADC_TOP_VALUE) + maxGain = ADC_UNITY_GAIN; + + for (uint16_t gain = ADC_UNITY_GAIN - 1; gain >= ADC_MIN_GAIN; --gain) + { + analogReadCorrection(offsetCorrectionValue, gain); + + Serial.print(" Gain = "); + Serial.print(gain); + Serial.print(", "); + highLevelRead = read3V3Level(); + + if (highLevelRead == ADC_TOP_VALUE) + { + if (maxGain == 0U) + maxGain = gain; + + minGain = gain; + } + + if (highLevelRead < ADC_TOP_VALUE) + break; + } + } + + gainCorrectionValue = (minGain + maxGain) >> 1; + + analogReadCorrection(offsetCorrectionValue, gainCorrectionValue); + + Serial.println("\r\nReadings after corrections"); + Serial.print(" "); + readGndLevel(); + Serial.print(" "); + read3V3Level(); + + Serial.println("\r\n=================="); + Serial.println("\r\nCorrection values:"); + Serial.print(" Offset = "); + Serial.println(offsetCorrectionValue); + Serial.print(" Gain = "); + Serial.println(gainCorrectionValue); + Serial.println("\r\nAdd the next line to your sketch:"); + Serial.print(" analogReadCorrection("); + Serial.print(offsetCorrectionValue); + Serial.print(", "); + Serial.print(gainCorrectionValue); + Serial.println(");"); + Serial.println("\r\n=================="); +} + +void loop() +{ +} + +uint16_t readGndLevel() +{ + uint32_t readAccumulator = 0; + + for (int i = 0; i < ADC_READS_COUNT; ++i) + readAccumulator += analogRead(ADC_GND_PIN); + + uint16_t readValue = readAccumulator >> ADC_READS_SHIFT; + + Serial.print("ADC(GND) = "); + Serial.println(readValue); + + return readValue; +} + +uint16_t read3V3Level() +{ + uint32_t readAccumulator = 0; + + for (int i = 0; i < ADC_READS_COUNT; ++i) + readAccumulator += analogRead(ADC_3V3_PIN); + + uint16_t readValue = readAccumulator >> ADC_READS_SHIFT; + + if (readValue < (ADC_RANGE >> 1)) + readValue += ADC_RANGE; + + Serial.print("ADC(3.3V) = "); + Serial.println(readValue); + + return readValue; +} + diff --git a/libraries/SAMD_AnalogCorrection/library.properties b/libraries/SAMD_AnalogCorrection/library.properties new file mode 100644 index 0000000000000000000000000000000000000000..e12ada2d1fb81df47a63665cecd6384df3135c74 --- /dev/null +++ b/libraries/SAMD_AnalogCorrection/library.properties @@ -0,0 +1,8 @@ +name=SAMD_AnalogCorrection +version=1.0 +author=Arduino +maintainer=Arduino <info@arduino.cc> +sentence=Sets and enables the digital correction logic of the SAMD ADC. +paragraph=Useful to correct the values returned by the ADC. +url= +architectures=samd diff --git a/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.cpp b/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1681b0a438e68336185ea11351d0708552657e04 --- /dev/null +++ b/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.cpp @@ -0,0 +1,31 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "SAMD_AnalogCorrection.h" + +void analogReadCorrection (int offset, uint16_t gain) +{ + // Set correction values + ADC->OFFSETCORR.reg = ADC_OFFSETCORR_OFFSETCORR(offset); + ADC->GAINCORR.reg = ADC_GAINCORR_GAINCORR(gain); + + // Enable digital correction logic + ADC->CTRLB.bit.CORREN = 1; + while(ADC->STATUS.bit.SYNCBUSY); +} + diff --git a/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.h b/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.h new file mode 100644 index 0000000000000000000000000000000000000000..5edb91ee35055b291892b1c58fcc2e0da7d21731 --- /dev/null +++ b/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.h @@ -0,0 +1,24 @@ +/* + Copyright (c) 2015 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#include <Arduino.h> + +void analogReadCorrection (int offset, uint16_t gain); +