summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Shawcroft <scott@chickadee.tech>2016-08-26 16:56:03 -0700
committerScott Shawcroft <scott@chickadee.tech>2016-08-26 17:01:38 -0700
commit259ae8a39d347d2c653d737f2a1aec4f03d970fc (patch)
tree16a5b7ac8aa46de5cc114de47cc9339344cf634c
parent3cb4938c637290625d2fd71f7b4b94d385a4070b (diff)
atmel-samd: Initial ADC support.
-rw-r--r--atmel-samd/Makefile3
-rw-r--r--atmel-samd/adc.c139
-rw-r--r--atmel-samd/adc.h27
-rw-r--r--atmel-samd/asf/sam0/drivers/adc/adc.h1155
-rw-r--r--atmel-samd/asf/sam0/drivers/adc/adc_callback.h182
-rw-r--r--atmel-samd/asf/sam0/drivers/adc/adc_sam_b.h426
-rw-r--r--atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc.c715
-rw-r--r--atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc_callback.c255
-rw-r--r--atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc_feature.h728
-rw-r--r--atmel-samd/boards/arduino_zero/pins.c45
-rw-r--r--atmel-samd/boards/feather_m0_ble/pins.c47
-rw-r--r--atmel-samd/modmachine.c2
-rw-r--r--atmel-samd/pin.h22
13 files changed, 3691 insertions, 55 deletions
diff --git a/atmel-samd/Makefile b/atmel-samd/Makefile
index 95d9b0691..6003c519c 100644
--- a/atmel-samd/Makefile
+++ b/atmel-samd/Makefile
@@ -47,6 +47,7 @@ INC += $(addprefix -Iasf/sam0/,\
drivers/extint/ \
drivers/port \
drivers/system \
+ drivers/adc/adc_sam_d_r \
drivers/system/clock \
drivers/system/clock/clock_samd21_r21_da \
drivers/system/interrupt \
@@ -97,6 +98,7 @@ SRC_ASF = $(addprefix asf/sam0/,\
drivers/sercom/sercom_interrupt.c \
drivers/sercom/usart/usart.c \
drivers/sercom/usart/usart_interrupt.c \
+ drivers/adc/adc_sam_d_r/adc.c \
drivers/system/clock/clock_samd21_r21_da/clock.c \
drivers/system/clock/clock_samd21_r21_da/gclk.c \
drivers/system/interrupt/system_interrupt.c \
@@ -108,6 +110,7 @@ SRC_ASF = $(addprefix asf/sam0/,\
)
SRC_C = \
+ adc.c \
main.c \
modmachine.c \
modutime.c \
diff --git a/atmel-samd/adc.c b/atmel-samd/adc.c
new file mode 100644
index 000000000..1a7c5cbf9
--- /dev/null
+++ b/atmel-samd/adc.c
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "py/nlr.h"
+#include "py/runtime.h"
+#include "py/binary.h"
+#include "py/mphal.h"
+#include "adc.h"
+#include "pin.h"
+
+#include "asf/sam0/drivers/adc/adc.h"
+
+/// \moduleref machine
+/// \class ADC - analog to digital conversion: read analog values on a pin
+///
+/// Usage:
+///
+/// adc = machine.ADC(pin) # create an analog object from a pin
+/// val = adc.read() # read an analog value
+
+typedef struct {
+ mp_obj_base_t base;
+ pin_obj_t * pin;
+ struct adc_module adc_instance;
+} adc_obj_t;
+
+/******************************************************************************/
+/* Micro Python bindings : adc object (single channel) */
+
+STATIC void adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ adc_obj_t *self = self_in;
+ mp_print_str(print, "<ADC on ");
+ mp_obj_print_helper(print, self->pin, PRINT_STR);
+}
+
+
+STATIC void adc_init_single(adc_obj_t *adc_obj) {
+ struct adc_config config_adc;
+ adc_get_config_defaults(&config_adc);
+
+ config_adc.positive_input = adc_obj->pin->adc_input;
+ config_adc.resolution = ADC_RESOLUTION_CUSTOM;
+ config_adc.accumulate_samples = ADC_ACCUMULATE_SAMPLES_16;
+ config_adc.divide_result = ADC_DIVIDE_RESULT_16;
+ config_adc.clock_prescaler = ADC_CLOCK_PRESCALER_DIV128;
+
+ adc_init(&adc_obj->adc_instance, ADC, &config_adc);
+}
+
+/// \classmethod \constructor(pin)
+/// Create an ADC object associated with the given pin.
+/// This allows you to then read analog values on that pin.
+STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
+ // check number of arguments
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+
+ // 1st argument is the pin name
+ mp_obj_t pin_obj = args[0];
+
+ const pin_obj_t *pin = pin_find(pin_obj);
+ if (!pin->has_adc) {
+ // No ADC function on that pin
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %q does not have ADC capabilities", pin->name));
+ }
+
+ adc_obj_t *o = m_new_obj(adc_obj_t);
+ memset(o, 0, sizeof(*o));
+ o->base.type = &adc_type;
+ o->pin = pin_obj;
+ adc_init_single(o);
+
+ return o;
+}
+
+/// \method read()
+/// Read the value on the analog pin and return it. The returned value
+/// will be between 0 and 4095.
+// TODO(tannewt): Don't turn it all on just for one read. This simplifies
+// handling of reading multiple inputs and surviving sleep though so for now its
+// ok.
+STATIC mp_obj_t mp_adc_read(mp_obj_t self_in) {
+ adc_obj_t *self = self_in;
+
+ adc_enable(&self->adc_instance);
+ adc_start_conversion(&self->adc_instance);
+
+ uint16_t data;
+ enum status_code status = adc_read(&self->adc_instance, &data);
+ while (status == STATUS_BUSY) {
+ status = adc_read(&self->adc_instance, &data);
+ }
+ if (status == STATUS_ERR_OVERFLOW) {
+ // TODO(tannewt): Throw an error.
+ }
+
+ adc_disable(&self->adc_instance);
+ return mp_obj_new_int(data);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, mp_adc_read);
+
+STATIC const mp_map_elem_t adc_locals_dict_table[] = {
+ { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&adc_read_obj},
+};
+
+STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);
+
+const mp_obj_type_t adc_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ADC,
+ .print = adc_print,
+ .make_new = adc_make_new,
+ .locals_dict = (mp_obj_t)&adc_locals_dict,
+};
diff --git a/atmel-samd/adc.h b/atmel-samd/adc.h
new file mode 100644
index 000000000..ed01f20c8
--- /dev/null
+++ b/atmel-samd/adc.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+extern const mp_obj_type_t adc_type;
diff --git a/atmel-samd/asf/sam0/drivers/adc/adc.h b/atmel-samd/asf/sam0/drivers/adc/adc.h
new file mode 100644
index 000000000..a31bff722
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/adc/adc.h
@@ -0,0 +1,1155 @@
+/**
+ * \file
+ *
+ * \brief SAM Peripheral Analog-to-Digital Converter Driver
+ *
+ * Copyright (C) 2012-2016 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef ADC_H_INCLUDED
+#define ADC_H_INCLUDED
+
+/**
+ * \defgroup asfdoc_sam0_adc_group SAM Analog-to-Digital Converter (ADC) Driver
+ *
+ * This driver for Atmel&reg; | SMART ARM&reg;-based microcontrollers provides an interface for the configuration
+ * and management of the device's Analog-to-Digital Converter functionality, for
+ * the conversion of analog voltages into a corresponding digital form.
+ * The following driver Application Programming Interface (API) modes are covered by this manual:
+ * - Polled APIs
+ * \if ADC_CALLBACK_MODE
+ * - Callback APIs
+ * \endif
+ *
+ * The following peripheral is used by this module:
+ * - ADC (Analog-to-Digital Converter)
+ *
+ * The following devices can use this module:
+ * \if DEVICE_SAML21_SUPPORT
+ * - Atmel | SMART SAM L21/L22
+ * - Atmel | SMART SAM C20/C21
+ * \else
+ * - Atmel | SMART SAM D20/D21
+ * - Atmel | SMART SAM R21
+ * - Atmel | SMART SAM D09/D10/D11
+ * - Atmel | SMART SAM DA1
+ * \endif
+ *
+ * The outline of this documentation is as follows:
+ * - \ref asfdoc_sam0_adc_prerequisites
+ * - \ref asfdoc_sam0_adc_module_overview
+ * - \ref asfdoc_sam0_adc_special_considerations
+ * - \ref asfdoc_sam0_adc_extra_info
+ * - \ref asfdoc_sam0_adc_examples
+ * - \ref asfdoc_sam0_adc_api_overview
+ *
+ *
+ * \section asfdoc_sam0_adc_prerequisites Prerequisites
+ *
+ * There are no prerequisites for this module.
+ *
+ *
+ * \section asfdoc_sam0_adc_module_overview Module Overview
+ *
+ * This driver provides an interface for the Analog-to-Digital conversion
+ * functions on the device, to convert analog voltages to a corresponding
+ * digital value. The ADC has up to 12-bit resolution, and is capable of
+ * \if DEVICE_SAML21_SUPPORT
+ * converting up to 1,000,000 samples per second (MSPS).
+ * \else
+ * converting up to 500K samples per second (KSPS).
+ * \endif
+ *
+ * The ADC has a compare function for accurate monitoring of user defined
+ * thresholds with minimum software intervention required.
+ * The ADC may be configured for 8-, 10-, or 12-bit result, reducing the
+ * conversion time. ADC conversion results are provided left or right adjusted
+ * which eases calculation when the result is represented as a signed integer.
+ *
+ * The input selection is flexible, and both single-ended and differential
+ * measurements can be made. For differential measurements, an optional gain
+ * stage is available to increase the dynamic range. In addition, several
+ * internal signal inputs are available. The ADC can provide both signed and
+ * unsigned results.
+ *
+ * The ADC measurements can either be started by application software or an
+ * incoming event from another peripheral in the device, and both internal and
+ * external reference voltages can be selected.
+ *
+ * \note Internal references will be enabled by the driver, but not disabled.
+ * Any reference not used by the application should be disabled by the application.
+ *
+ * A simplified block diagram of the ADC can be seen in
+ * \ref asfdoc_sam0_adc_module_block_diagram "the figure below".
+ *
+ * \anchor asfdoc_sam0_adc_module_block_diagram
+ * \dot
+ * digraph overview {
+ * splines = false;
+ * rankdir=LR;
+ *
+ * mux1 [label="Positive input", shape=box];
+ * mux2 [label="Negative input", shape=box];
+ *
+ *
+ * mux3 [label="Reference", shape=box];
+ *
+ * adc [label="ADC", shape=polygon, sides=5, orientation=90, distortion=-0.6, style=filled, fillcolor=darkolivegreen1, height=1, width=1];
+ * prescaler [label="PRESCALER", shape=box, style=filled, fillcolor=lightblue];
+ *
+ * mux1 -> adc;
+ * mux2 -> adc;
+ * mux3 -> adc:sw;
+ * prescaler -> adc;
+ *
+ * postproc [label="Post processing", shape=box];
+ * result [label="RESULT", shape=box, style=filled, fillcolor=lightblue];
+ *
+ * adc:e -> postproc:w;
+ * postproc:e -> result:w;
+ *
+ * {rank=same; mux1 mux2}
+ * {rank=same; prescaler adc}
+ *
+ * }
+ * \enddot
+ *
+ *
+ * \subsection asfdoc_sam0_adc_module_overview_prescaler Sample Clock Prescaler
+ * The ADC features a prescaler, which enables conversion at lower clock rates
+ * than the input Generic Clock to the ADC module. This feature can be used to
+ * lower the synchronization time of the digital interface to the ADC module
+ * via a high speed Generic Clock frequency, while still allowing the ADC
+ * sampling rate to be reduced.
+ *
+ * \subsection asfdoc_sam0_adc_module_overview_resolution ADC Resolution
+ * The ADC supports full 8-, 10-, or 12-bit resolution. Hardware
+ * oversampling and decimation can be used to increase the
+ * effective resolution at the expense of throughput. Using oversampling and
+ * decimation mode the ADC resolution is increased from 12-bit to an effective
+ * 13-, 14-, 15-, or 16-bit. In these modes the conversion rate is reduced, as
+ * a greater number of samples is used to achieve the increased resolution. The
+ * available resolutions and effective conversion rate is listed in
+ * \ref asfdoc_sam0_adc_module_conversion_rate "the table below".
+ *
+ * \anchor asfdoc_sam0_adc_module_conversion_rate
+ * <table>
+ * <caption>Effective ADC Conversion Speed Using Oversampling</caption>
+ * <tr>
+ * <th>Resolution</th>
+ * <th>Effective conversion rate</th>
+ * </tr>
+ * <tr>
+ * <td>13-bit</td>
+ * <td>Conversion rate divided by 4</td>
+ * </tr>
+ * <tr>
+ * <td>14-bit</td>
+ * <td>Conversion rate divided by 16</td>
+ * </tr>
+ * <tr>
+ * <td>15-bit</td>
+ * <td>Conversion rate divided by 64</td>
+ * </tr>
+ * <tr>
+ * <td>16-bit</td>
+ * <td>Conversion rate divided by 256</td>
+ * </tr>
+ * </table>
+ *
+ * \subsection asfdoc_sam0_adc_module_overview_conversion Conversion Modes
+ * ADC conversions can be software triggered on demand by the user application,
+ * if continuous sampling is not required. It is also possible to configure the
+ * ADC in free running mode, where new conversions are started as soon as the
+ * previous conversion is completed, or configure the ADC to scan across a
+ * number of input pins (see \ref asfdoc_sam0_adc_module_overview_pin_scan).
+ *
+ * \subsection asfdoc_sam0_adc_module_overview_diff_mode Differential and Single-ended Conversion
+ * The ADC has two conversion modes; differential and single-ended. When
+ * measuring signals where the positive input pin is always at a higher voltage
+ * than the negative input pin, the single-ended conversion mode should be used
+ * in order to achieve a full 12-bit output resolution.
+ *
+ * If however the positive input pin voltage may drop below the negative input
+ * pin the signed differential mode should be used.
+ *
+ * \subsection asfdoc_sam0_adc_module_overview_sample_time Sample Time
+ * The sample time for each ADC conversion is configurable as a number of half
+ * prescaled ADC clock cycles (depending on the prescaler value), allowing the
+ * user application to achieve faster or slower sampling depending on the
+ * source impedance of the ADC input channels. For applications with high
+ * impedance inputs the sample time can be increased to give the ADC an adequate
+ * time to sample and convert the input channel.
+ *
+ * The resulting sampling time is given by the following equation:
+ * \f[
+ * t_{SAMPLE} = (sample\_length+1) \times \frac{ADC_{CLK}} {2}
+ * \f]
+ *
+ * \subsection asfdoc_sam0_adc_module_overview_averaging Averaging
+ * The ADC can be configured to trade conversion speed for accuracy by averaging
+ * multiple samples in hardware. This feature is suitable when operating in
+ * noisy conditions.
+ *
+ * You can specify any number of samples to accumulate (up to 1024) and the
+ * divide ratio to use (up to divide by 128). To modify these settings the
+ * ADC_RESOLUTION_CUSTOM needs to be set as the resolution. When this is set
+ * the number of samples to accumulate and the division ratio can be set by
+ * the configuration struct members \ref adc_config.accumulate_samples and
+ * \ref adc_config.divide_result. When using this mode the ADC result register
+ * will be set to be 16-bit wide to accommodate the larger result sizes
+ * produced by the accumulator.
+ *
+ * The effective ADC conversion rate will be reduced by a factor of the number
+ * of accumulated samples;
+ * however, the effective resolution will be increased according to
+ * \ref asfdoc_sam0_adc_module_hw_av_resolution "the table below".
+ *
+ * \anchor asfdoc_sam0_adc_module_hw_av_resolution
+ * <table>
+ * <caption>Effective ADC Resolution From Various Hardware Averaging Modes</caption>
+ * <tr>
+ * <th>Number of samples</tr>
+ * <th>Final result</tr>
+ * </tr>
+ * <tr>
+ * <td>1</td>
+ * <td>12-bit</td>
+ * </tr>
+ * <tr>
+ * <td>2</td>
+ * <td>13-bit</td>
+ * </tr>
+ * <tr>
+ * <td>4</td>
+ * <td>14-bit</td>
+ * </tr>
+ * <tr>
+ * <td>8</td>
+ * <td>15-bit</td>
+ * </tr>
+ * <tr>
+ * <td>16</td>
+ * <td>16-bit</td>
+ * </tr>
+ * <tr>
+ * <td>32</td>
+ * <td>16-bit</td>
+ * </tr>
+ * <tr>
+ * <td>64</td>
+ * <td>16-bit</td>
+ * </tr>
+ * <tr>
+ * <td>128</td>
+ * <td>16-bit</td>
+ * </tr>
+ * <tr>
+ * <td>256</td>
+ * <td>16-bit</td>
+ * </tr>
+ * <tr>
+ * <td>512</td>
+ * <td>16-bit</td>
+ * </tr>
+ * <tr>
+ * <td>1024</td>
+ * <td>16-bit</td>
+ * </tr>
+ * </table>
+ *
+ *
+ * \subsection asfdoc_sam0_adc_module_overview_offset_corr Offset and Gain Correction
+ * Inherent gain and offset errors affect the absolute accuracy of the ADC.
+ *
+ * The offset error is defined as the deviation of the ADC's actual transfer
+ * function from ideal straight line at zero input voltage.
+ *
+ * The gain error is defined as the deviation of the last output step's
+ * midpoint from the ideal straight line, after compensating for offset error.
+ *
+ * The offset correction value is subtracted from the converted data before the
+ * result is ready. The gain correction value is multiplied with the offset
+ * corrected value.
+ *
+ * The equation for both offset and gain error compensation is shown below:
+ * \f[
+ * ADC_{RESULT} = (VALUE_{CONV} + CORR_{OFFSET}) \times CORR_{GAIN}
+ * \f]
+ *
+ * When enabled, a given set of offset and gain correction values can be applied
+ * to the sampled data in hardware, giving a corrected stream of sample data to
+ * the user application at the cost of an increased sample latency.
+ *
+ * In single conversion, a latency of 13 ADC Generic Clock cycles is added for
+ * the final sample result availability. As the correction time is always less
+ * than the propagation delay, in free running mode this latency appears only
+ * during the first conversion. After the first conversion is complete, future
+ * conversion results are available at the defined sampling rate.
+ *
+ * \subsection asfdoc_sam0_adc_module_overview_pin_scan Pin Scan
+ * In pin scan mode, the first ADC conversion will begin from the configured
+ * positive channel, plus the requested starting offset. When the first
+ * conversion is completed, the next conversion will start at the next positive
+ * input channel and so on, until all requested pins to scan have been sampled
+ * and converted.
+ * SAM L21/L22 has automatic sequences feature instead of pin scan mode. In automatic
+ * sequence mode, all of 32 positives inputs can be included in a sequence. The
+ * sequence starts from the lowest input, and go to the next enabled input
+ * automatically.
+ *
+ * Pin scanning gives a simple mechanism to sample a large number of physical
+ * input channel samples, using a single physical ADC channel.
+ *
+ * \subsection asfdoc_sam0_adc_module_overview_window_monitor Window Monitor
+ * The ADC module window monitor function can be used to automatically compare
+ * the conversion result against a preconfigured pair of upper and lower
+ * threshold values.
+ *
+ * The threshold values are evaluated differently, depending on whether
+ * differential or single-ended mode is selected. In differential mode, the
+ * upper and lower thresholds are evaluated as signed values for the comparison,
+ * while in single-ended mode the comparisons are made as a set of unsigned
+ * values.
+ *
+ * The significant bits of the lower window monitor threshold and upper window
+ * monitor threshold values are user-configurable, and follow the overall ADC
+ * sampling bit precision set when the ADC is configured by the user application.
+ * For example, only the eight lower bits of the window threshold values will be
+ * compared to the sampled data whilst the ADC is configured in 8-bit mode.
+ * In addition, if using differential mode, the 8<SUP>th</SUP> bit will be considered as
+ * the sign bit even if bit 9 is zero.
+ *
+ * \subsection asfdoc_sam0_adc_module_overview_events Events
+ * Event generation and event actions are configurable in the ADC.
+ *
+ * The ADC has two actions that can be triggered upon event reception:
+ * \li Start conversion
+ * \li Flush pipeline and start conversion
+ *
+ * The ADC can generate two events:
+ * \li Window monitor
+ * \li Result ready
+ *
+ * If the event actions are enabled in the configuration, any incoming event
+ * will trigger the action.
+ *
+ * If the window monitor event is enabled, an event will be generated
+ * when the configured window condition is detected.
+ *
+ * If the result ready event is enabled, an event will be generated when a
+ * conversion is completed.
+ *
+ * \note The connection of events between modules requires the use of the
+ * \ref asfdoc_sam0_events_group "SAM Event System Driver (EVENTS)"
+ * to route output event of one module to the input event of another.
+ * For more information on event routing, refer to the event driver
+ * documentation.
+ *
+ *
+ * \section asfdoc_sam0_adc_special_considerations Special Considerations
+ *
+ * An integrated analog temperature sensor is available for use with the ADC.
+ * The bandgap voltage, as well as the scaled I/O and core voltages can also be
+ * measured by the ADC. For internal ADC inputs, the internal source(s) may need
+ * to be manually enabled by the user application before they can be measured.
+ *
+ *
+ * \section asfdoc_sam0_adc_extra_info Extra Information
+ *
+ * For extra information, see \ref asfdoc_sam0_adc_extra. This includes:
+ * - \ref asfdoc_sam0_adc_extra_acronyms
+ * - \ref asfdoc_sam0_adc_extra_dependencies
+ * - \ref asfdoc_sam0_adc_extra_errata
+ * - \ref asfdoc_sam0_adc_extra_history
+ *
+ *
+ * \section asfdoc_sam0_adc_examples Examples
+ *
+ * For a list of examples related to this driver, see
+ * \ref asfdoc_sam0_adc_exqsg.
+ *
+ *
+ * \section asfdoc_sam0_adc_api_overview API Overview
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <compiler.h>
+#include <system.h>
+#include <adc_feature.h>
+
+/**
+ * \name Module Status Flags
+ *
+ * ADC status flags, returned by \ref adc_get_status() and cleared by
+ * \ref adc_clear_status().
+ *
+ * @{
+ */
+
+/** ADC result ready. */
+#define ADC_STATUS_RESULT_READY (1UL << 0)
+/** Window monitor match. */
+#define ADC_STATUS_WINDOW (1UL << 1)
+/** ADC result overwritten before read. */
+#define ADC_STATUS_OVERRUN (1UL << 2)
+
+/** @} */
+
+#if ADC_CALLBACK_MODE == true
+# if (ADC_INST_NUM > 1)
+# define _ADC_INTERRUPT_VECT_NUM(n, unused) \
+ SYSTEM_INTERRUPT_MODULE_ADC##n,
+/**
+ * \internal Get the interrupt vector for the given device instance
+ *
+ * \param[in] The ADC module instance number
+ *
+ * \return Interrupt vector for of the given ADC module instance.
+ */
+static enum system_interrupt_vector _adc_interrupt_get_interrupt_vector(
+ uint32_t inst_num)
+{
+ static uint8_t adc_interrupt_vectors[ADC_INST_NUM] = {
+ MREPEAT(ADC_INST_NUM, _ADC_INTERRUPT_VECT_NUM, 0)
+ };
+
+ return (enum system_interrupt_vector)adc_interrupt_vectors[inst_num];
+}
+# endif
+#endif
+
+#if !defined(__DOXYGEN__)
+uint8_t _adc_get_inst_index(
+ Adc *const hw);
+#endif
+
+/**
+ * \name Driver Initialization and Configuration
+ * @{
+ */
+enum status_code adc_init(
+ struct adc_module *const module_inst,
+ Adc *hw,
+ struct adc_config *config);
+
+void adc_get_config_defaults(
+ struct adc_config *const config);
+
+#if (SAMD) || (SAMR21)
+void adc_regular_ain_channel(
+ uint32_t *pin_array, uint8_t size);
+#endif
+
+/** @} */
+
+/**
+ * \name Status Management
+ * @{
+ */
+
+/**
+ * \brief Retrieves the current module status.
+ *
+ * Retrieves the status of the module, giving overall state information.
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ *
+ * \return Bitmask of \c ADC_STATUS_* flags.
+ *
+ * \retval ADC_STATUS_RESULT_READY ADC result is ready to be read
+ * \retval ADC_STATUS_WINDOW ADC has detected a value inside the set
+ * window range
+ * \retval ADC_STATUS_OVERRUN ADC result has overrun
+ */
+static inline uint32_t adc_get_status(
+ struct adc_module *const module_inst)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ Adc *const adc_module = module_inst->hw;
+
+ uint32_t int_flags = adc_module->INTFLAG.reg;
+
+ uint32_t status_flags = 0;
+
+ /* Check for ADC Result Ready */
+ if (int_flags & ADC_INTFLAG_RESRDY) {
+ status_flags |= ADC_STATUS_RESULT_READY;
+ }
+
+ /* Check for ADC Window Match */
+ if (int_flags & ADC_INTFLAG_WINMON) {
+ status_flags |= ADC_STATUS_WINDOW;
+ }
+
+ /* Check for ADC Overrun */
+ if (int_flags & ADC_INTFLAG_OVERRUN) {
+ status_flags |= ADC_STATUS_OVERRUN;
+ }
+
+ return status_flags;
+}
+
+/**
+ * \brief Clears a module status flag.
+ *
+ * Clears the given status flag of the module.
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ * \param[in] status_flags Bitmask of \c ADC_STATUS_* flags to clear
+ */
+static inline void adc_clear_status(
+ struct adc_module *const module_inst,
+ const uint32_t status_flags)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ Adc *const adc_module = module_inst->hw;
+
+ uint32_t int_flags = 0;
+
+ /* Check for ADC Result Ready */
+ if (status_flags & ADC_STATUS_RESULT_READY) {
+ int_flags |= ADC_INTFLAG_RESRDY;
+ }
+
+ /* Check for ADC Window Match */
+ if (status_flags & ADC_STATUS_WINDOW) {
+ int_flags |= ADC_INTFLAG_WINMON;
+ }
+
+ /* Check for ADC Overrun */
+ if (status_flags & ADC_STATUS_OVERRUN) {
+ int_flags |= ADC_INTFLAG_OVERRUN;
+ }
+
+ /* Clear interrupt flag */
+ adc_module->INTFLAG.reg = int_flags;
+}
+/** @} */
+
+/**
+ * \name Enable, Disable, and Reset ADC Module, Start Conversion and Read Result
+ * @{
+ */
+
+/**
+ * \brief Enables the ADC module.
+ *
+ * Enables an ADC module that has previously been configured. If any internal reference
+ * is selected it will be enabled.
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ */
+static inline enum status_code adc_enable(
+ struct adc_module *const module_inst)
+{
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ Adc *const adc_module = module_inst->hw;
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+
+#if ADC_CALLBACK_MODE == true
+# if (ADC_INST_NUM > 1)
+ system_interrupt_enable(_adc_interrupt_get_interrupt_vector(
+ _adc_get_inst_index(adc_module)));
+# elif (SAMC20)
+ system_interrupt_enable(SYSTEM_INTERRUPT_MODULE_ADC0);
+# else
+ system_interrupt_enable(SYSTEM_INTERRUPT_MODULE_ADC);
+# endif
+#endif
+
+ /* Disbale interrupt */
+ adc_module->INTENCLR.reg = ADC_INTENCLR_MASK;
+ /* Clear interrupt flag */
+ adc_module->INTFLAG.reg = ADC_INTFLAG_MASK;
+
+ adc_module->CTRLA.reg |= ADC_CTRLA_ENABLE;
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+ return STATUS_OK;
+}
+
+/**
+ * \brief Disables the ADC module.
+ *
+ * Disables an ADC module that was previously enabled.
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ */
+static inline enum status_code adc_disable(
+ struct adc_module *const module_inst)
+{
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ Adc *const adc_module = module_inst->hw;
+
+#if ADC_CALLBACK_MODE == true
+# if (ADC_INST_NUM > 1)
+ system_interrupt_disable(_adc_interrupt_get_interrupt_vector(
+ _adc_get_inst_index(adc_module)));
+# elif (SAMC20)
+ system_interrupt_disable(SYSTEM_INTERRUPT_MODULE_ADC0);
+# else
+ system_interrupt_disable(SYSTEM_INTERRUPT_MODULE_ADC);
+# endif
+#endif
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+
+ /* Disbale interrupt */
+ adc_module->INTENCLR.reg = ADC_INTENCLR_MASK;
+ /* Clear interrupt flag */
+ adc_module->INTFLAG.reg = ADC_INTFLAG_MASK;
+
+ adc_module->CTRLA.reg &= ~ADC_CTRLA_ENABLE;
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+ return STATUS_OK;
+}
+
+/**
+ * \brief Resets the ADC module.
+ *
+ * Resets an ADC module, clearing all module state, and registers to their
+ * default values.
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ */
+static inline enum status_code adc_reset(
+ struct adc_module *const module_inst)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ Adc *const adc_module = module_inst->hw;
+
+ /* Disable to make sure the pipeline is flushed before reset */
+ adc_disable(module_inst);
+
+ /* Software reset the module */
+ adc_module->CTRLA.reg |= ADC_CTRLA_SWRST;
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+ return STATUS_OK;
+}
+
+
+/**
+ * \brief Enables an ADC event input or output.
+ *
+ * Enables one or more input or output events to or from the ADC module. See
+ * \ref adc_events "Struct adc_events" for a list of events this module supports.
+ *
+ * \note Events cannot be altered while the module is enabled.
+ *
+ * \param[in] module_inst Software instance for the ADC peripheral
+ * \param[in] events Struct containing flags of events to enable
+ */
+static inline void adc_enable_events(
+ struct adc_module *const module_inst,
+ struct adc_events *const events)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+ Assert(events);
+
+ Adc *const adc_module = module_inst->hw;
+
+ uint32_t event_mask = 0;
+
+ /* Configure Window Monitor event */
+ if (events->generate_event_on_window_monitor) {
+ event_mask |= ADC_EVCTRL_WINMONEO;
+ }
+
+ /* Configure Result Ready event */
+ if (events->generate_event_on_conversion_done) {
+ event_mask |= ADC_EVCTRL_RESRDYEO;
+ }
+
+ adc_module->EVCTRL.reg |= event_mask;
+}
+
+/**
+ * \brief Disables an ADC event input or output.
+ *
+ * Disables one or more input or output events to or from the ADC module. See
+ * \ref adc_events "Struct adc_events" for a list of events this module supports.
+ *
+ * \note Events cannot be altered while the module is enabled.
+ *
+ * \param[in] module_inst Software instance for the ADC peripheral
+ * \param[in] events Struct containing flags of events to disable
+ */
+static inline void adc_disable_events(
+ struct adc_module *const module_inst,
+ struct adc_events *const events)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+ Assert(events);
+
+ Adc *const adc_module = module_inst->hw;
+
+ uint32_t event_mask = 0;
+
+ /* Configure Window Monitor event */
+ if (events->generate_event_on_window_monitor) {
+ event_mask |= ADC_EVCTRL_WINMONEO;
+ }
+
+ /* Configure Result Ready event */
+ if (events->generate_event_on_conversion_done) {
+ event_mask |= ADC_EVCTRL_RESRDYEO;
+ }
+
+ adc_module->EVCTRL.reg &= ~event_mask;
+}
+
+/**
+ * \brief Starts an ADC conversion.
+ *
+ * Starts a new ADC conversion.
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ */
+static inline void adc_start_conversion(
+ struct adc_module *const module_inst)
+{
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ Adc *const adc_module = module_inst->hw;
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+
+ adc_module->SWTRIG.reg |= ADC_SWTRIG_START;
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+}
+
+/**
+ * \brief Reads the ADC result.
+ *
+ * Reads the result from an ADC conversion that was previously started.
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ * \param[out] result Pointer to store the result value in
+ *
+ * \return Status of the ADC read request.
+ * \retval STATUS_OK The result was retrieved successfully
+ * \retval STATUS_BUSY A conversion result was not ready
+ * \retval STATUS_ERR_OVERFLOW The result register has been overwritten by the
+ * ADC module before the result was read by the software
+ */
+static inline enum status_code adc_read(
+ struct adc_module *const module_inst,
+ uint16_t *result)
+{
+ Assert(module_inst);
+ Assert(module_inst->hw);
+ Assert(result);
+
+ if (!(adc_get_status(module_inst) & ADC_STATUS_RESULT_READY)) {
+ /* Result not ready */
+ return STATUS_BUSY;
+ }
+
+ Adc *const adc_module = module_inst->hw;
+
+#if (SAMD) || (SAMR21)
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+#endif
+
+ /* Get ADC result */
+ *result = adc_module->RESULT.reg;
+
+ /* Reset ready flag */
+ adc_clear_status(module_inst, ADC_STATUS_RESULT_READY);
+
+ if (adc_get_status(module_inst) & ADC_STATUS_OVERRUN) {
+ adc_clear_status(module_inst, ADC_STATUS_OVERRUN);
+ return STATUS_ERR_OVERFLOW;
+ }
+
+ return STATUS_OK;
+}
+
+/** @} */
+
+/**
+ * \name Runtime Changes of ADC Module
+ * @{
+ */
+
+/**
+ * \brief Flushes the ADC pipeline.
+ *
+ * Flushes the pipeline and restarts the ADC clock on the next peripheral clock
+ * edge. All conversions in progress will be lost. When flush is complete, the
+ * module will resume where it left off.
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ */
+static inline void adc_flush(
+ struct adc_module *const module_inst)
+{
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ Adc *const adc_module = module_inst->hw;
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+
+ adc_module->SWTRIG.reg |= ADC_SWTRIG_FLUSH;
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+}
+void adc_set_window_mode(
+ struct adc_module *const module_inst,
+ const enum adc_window_mode window_mode,
+ const int16_t window_lower_value,
+ const int16_t window_upper_value);
+
+/**
+ * \brief Sets positive ADC input pin.
+ *
+ * Sets the positive ADC input pin selection.
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ * \param[in] positive_input Positive input pin
+ */
+static inline void adc_set_positive_input(
+ struct adc_module *const module_inst,
+ const enum adc_positive_input positive_input)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ Adc *const adc_module = module_inst->hw;
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+
+ /* Set positive input pin */
+ adc_module->INPUTCTRL.reg =
+ (adc_module->INPUTCTRL.reg & ~ADC_INPUTCTRL_MUXPOS_Msk) |
+ (positive_input);
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+}
+
+
+/**
+ * \brief Sets negative ADC input pin for differential mode.
+ *
+ * Sets the negative ADC input pin, when the ADC is configured in differential
+ * mode.
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ * \param[in] negative_input Negative input pin
+ */
+static inline void adc_set_negative_input(
+ struct adc_module *const module_inst,
+ const enum adc_negative_input negative_input)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ Adc *const adc_module = module_inst->hw;
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+
+ /* Set negative input pin */
+ adc_module->INPUTCTRL.reg =
+ (adc_module->INPUTCTRL.reg & ~ADC_INPUTCTRL_MUXNEG_Msk) |
+ (negative_input);
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+}
+
+/** @} */
+
+#if ADC_CALLBACK_MODE == true
+/**
+ * \name Enable and Disable Interrupts
+ * @{
+ */
+
+/**
+ * \brief Enable interrupt.
+ *
+ * Enable the given interrupt request from the ADC module.
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ * \param[in] interrupt Interrupt to enable
+ */
+static inline void adc_enable_interrupt(struct adc_module *const module_inst,
+ enum adc_interrupt_flag interrupt)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ Adc *const adc_module = module_inst->hw;
+ /* Enable interrupt */
+ adc_module->INTENSET.reg = interrupt;
+}
+
+/**
+ * \brief Disable interrupt.
+ *
+ * Disable the given interrupt request from the ADC module.
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ * \param[in] interrupt Interrupt to disable
+ */
+static inline void adc_disable_interrupt(struct adc_module *const module_inst,
+ enum adc_interrupt_flag interrupt)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ Adc *const adc_module = module_inst->hw;
+ /* Enable interrupt */
+ adc_module->INTENCLR.reg = interrupt;
+}
+
+/** @} */
+#endif /* ADC_CALLBACK_MODE == true */
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+
+/**
+ * \page asfdoc_sam0_adc_extra Extra Information for ADC Driver
+ *
+ * \section asfdoc_sam0_adc_extra_acronyms Acronyms
+ * Below is a table listing the acronyms used in this module, along with their
+ * intended meanings.
+ *
+ * <table>
+ * <tr>
+ * <th>Acronym</th>
+ * <th>Description</th>
+ * </tr>
+ * <tr>
+ * <td>ADC</td>
+ * <td>Analog-to-Digital Converter</td>
+ * </tr>
+ * <tr>
+ * <td>DAC</td>
+ * <td>Digital-to-Analog Converter</td>
+ * </tr>
+ * <tr>
+ * <td>LSB</td>
+ * <td>Least Significant Bit</td>
+ * </tr>
+ * <tr>
+ * <td>MSB</td>
+ * <td>Most Significant Bit</td>
+ * </tr>
+ * <tr>
+ * <td>DMA</td>
+ * <td>Direct Memory Access</td>
+ * </tr>
+ * </table>
+ *
+ *
+ * \section asfdoc_sam0_adc_extra_dependencies Dependencies
+ * This driver has the following dependencies:
+ *
+ * - \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver"
+ *
+ *
+ * \section asfdoc_sam0_adc_extra_errata Errata
+ * There are no errata related to this driver.
+ *
+ *
+ * \section asfdoc_sam0_adc_extra_history Module History
+ * An overview of the module history is presented in the table below, with
+ * details on the enhancements and fixes made to the module since its first
+ * release. The current version of this corresponds to the newest version in
+ * the table.
+ *
+ * <table>
+ * <tr>
+ * <th>Changelog</th>
+ * </tr>
+ * \if DEVICE_SAML21_SUPPORT
+ * <tr>
+ * <td>Initial Release</td>
+ * </tr>
+ * \else
+ * <tr>
+ * <td>Added support for SAM R21</td>
+ * </tr>
+ * <tr>
+ * <td>Added support for SAM D21 and new DMA quick start guide</td>
+ * </tr>
+ * <tr>
+ * <td>Added ADC calibration constant loading from the device signature
+ * row when the module is initialized</td>
+ * </tr>
+ * <tr>
+ * <td>Initial Release</td>
+ * </tr>
+ * \endif
+ * </table>
+ */
+
+/**
+ * \page asfdoc_sam0_adc_exqsg Examples for ADC Driver
+ *
+ * This is a list of the available Quick Start guides (QSGs) and example
+ * applications for \ref asfdoc_sam0_adc_group. QSGs are simple examples with
+ * step-by-step instructions to configure and use this driver in a selection of
+ * use cases. Note that a QSG can be compiled as a standalone application or be
+ * added to the user application.
+ *
+ * - \subpage asfdoc_sam0_adc_basic_use_case
+ * \if ADC_CALLBACK_MODE
+ * - \subpage asfdoc_sam0_adc_basic_use_case_callback
+ * \endif
+ * - \subpage asfdoc_sam0_adc_dma_use_case
+ *
+ * \page asfdoc_sam0_adc_document_revision_history Document Revision History
+ *
+ * <table>
+ * <tr>
+ * <th>Doc. Rev.</th>
+ * <th>Date</th>
+ * <th>Comments</th>
+ * </tr>
+ * \if DEVICE_SAML21_SUPPORT
+ * <tr>
+ * <td>42451B</td>
+ * <td>12/2015</td>
+ * <td>Added support for SAM L22</td>
+ * </tr>
+ * <tr>
+ * <td>42451A</td>
+ * <td>07/2015</td>
+ * <td>Initial document release</td>
+ * </tr>
+ * \else
+ * <tr>
+ * <td>42109E</td>
+ * <td>12/2015</td>
+ * <td>Added support for SAM DA1 and SAM D09</td>
+ * </tr>
+ * <tr>
+ * <td>42109D</td>
+ * <td>12/2014</td>
+ * <td>Added support for SAM R21 and SAM D10/D11</td>
+ * </tr>
+ * <tr>
+ * <td>42109C</td>
+ * <td>01/2014</td>
+ * <td>Added support for SAM D21</td>
+ * </tr>
+ * <tr>
+ * <td>42109B</td>
+ * <td>06/2013</td>
+ * <td>Added additional documentation on the event system. Corrected
+ * documentation typos.</td>
+ * </tr>
+ * <tr>
+ * <td>42109A</td>
+ * <td>06/2013</td>
+ * <td>Initial release</td>
+ * </tr>
+ * \endif
+ * </table>
+ */
+
+#endif /* ADC_H_INCLUDED */
diff --git a/atmel-samd/asf/sam0/drivers/adc/adc_callback.h b/atmel-samd/asf/sam0/drivers/adc/adc_callback.h
new file mode 100644
index 000000000..f6b30e86e
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/adc/adc_callback.h
@@ -0,0 +1,182 @@
+/**
+ * \file
+ *
+ * \brief SAM Peripheral Analog-to-Digital Converter Driver
+ *
+ * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef ADC_CALLBACK_H_INCLUDED
+#define ADC_CALLBACK_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \addtogroup asfdoc_sam0_adc_group
+ *
+ * @{
+ */
+
+#include <adc.h>
+
+/**
+ * Enum for the possible types of ADC asynchronous jobs that may be issued to
+ * the driver.
+ */
+enum adc_job_type {
+ /** Asynchronous ADC read into a user provided buffer */
+ ADC_JOB_READ_BUFFER,
+};
+
+/**
+ * \name Callback Management
+ * @{
+ */
+void adc_register_callback(
+ struct adc_module *const module,
+ adc_callback_t callback_func,
+ enum adc_callback callback_type);
+
+void adc_unregister_callback(
+ struct adc_module *module,
+ enum adc_callback callback_type);
+
+/**
+ * \brief Enables callback.
+ *
+ * Enables the callback function registered by \ref
+ * adc_register_callback. The callback function will be called from the
+ * interrupt handler when the conditions for the callback type are met.
+ *
+ * \param[in] module Pointer to ADC software instance struct
+ * \param[in] callback_type Callback type given by an enum
+ *
+ * \return Status of the operation.
+ * \retval STATUS_OK If operation was completed
+ * \retval STATUS_ERR_INVALID If operation was not completed,
+ * due to invalid callback_type
+ *
+ */
+static inline void adc_enable_callback(
+ struct adc_module *const module,
+ enum adc_callback callback_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+
+ /* Enable callback */
+ module->enabled_callback_mask |= (1 << callback_type);
+
+ /* Enable window interrupt if this is a window callback */
+ if (callback_type == ADC_CALLBACK_WINDOW) {
+ adc_enable_interrupt(module, ADC_INTERRUPT_WINDOW);
+ }
+ /* Enable overrun interrupt if error callback is registered */
+ if (callback_type == ADC_CALLBACK_ERROR) {
+ adc_enable_interrupt(module, ADC_INTERRUPT_OVERRUN);
+ }
+}
+
+/**
+ * \brief Disables callback.
+ *
+ * Disables the callback function registered by the \ref
+ * adc_register_callback.
+ *
+ * \param[in] module Pointer to ADC software instance struct
+ * \param[in] callback_type Callback type given by an enum
+ *
+ * \return Status of the operation.
+ * \retval STATUS_OK If operation was completed
+ * \retval STATUS_ERR_INVALID If operation was not completed,
+ * due to invalid callback_type
+ *
+ */
+static inline void adc_disable_callback(
+ struct adc_module *const module,
+ enum adc_callback callback_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+
+ /* Disable callback */
+ module->enabled_callback_mask &= ~(1 << callback_type);
+
+ /* Disable window interrupt if this is a window callback */
+ if (callback_type == ADC_CALLBACK_WINDOW) {
+ adc_disable_interrupt(module, ADC_INTERRUPT_WINDOW);
+ }
+ /* Disable overrun interrupt if this is the error callback */
+ if (callback_type == ADC_CALLBACK_ERROR) {
+ adc_disable_interrupt(module, ADC_INTERRUPT_OVERRUN);
+ }
+}
+
+/** @} */
+
+
+/**
+ * \name Job Management
+ * @{
+ */
+enum status_code adc_read_buffer_job(
+ struct adc_module *const module_inst,
+ uint16_t *buffer,
+ uint16_t samples);
+
+enum status_code adc_get_job_status(
+ struct adc_module *module_inst,
+ enum adc_job_type type);
+
+void adc_abort_job(
+ struct adc_module *module_inst,
+ enum adc_job_type type);
+/** @} */
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ADC_CALLBACK_H_INCLUDED */
diff --git a/atmel-samd/asf/sam0/drivers/adc/adc_sam_b.h b/atmel-samd/asf/sam0/drivers/adc/adc_sam_b.h
new file mode 100644
index 000000000..5323ad92a
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/adc/adc_sam_b.h
@@ -0,0 +1,426 @@
+/**
+ * \file
+ *
+ * \brief SAMB Peripheral Analog-to-Digital Converter Driver
+ *
+ * Copyright (C) 2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef ADC_SAM_B_H_INCLUDED
+#define ADC_SAM_B_H_INCLUDED
+
+/**
+ * \defgroup asfdoc_samb_adc_group SAM Analog-to-Digital Converter (ADC) Driver
+ *
+ * This driver for Atmel&reg; | SMART SAM devices provides an interface for the
+ * configuration and management of the device's Analog-to-Digital Converter
+ * functionality, for the conversion of analog voltages into a corresponding
+ * digital form.
+ *
+ * The following peripheral is used by this module:
+ * - ADC (Analog-to-Digital Converter)
+ *
+ * The following devices can use this module:
+ * - Atmel | SMART SAM B11
+ *
+ * The outline of this documentation is as follows:
+ * - \ref asfdoc_samb_adc_prerequisites
+ * - \ref asfdoc_samb_adc_module_overview
+ * - \ref asfdoc_samb_adc_special_considerations
+ * - \ref asfdoc_samb_adc_extra_info
+ * - \ref asfdoc_samb_adc_examples
+ * - \ref asfdoc_samb_adc_api_overview
+ *
+ *
+ * \section asfdoc_samb_adc_prerequisites Prerequisites
+ *
+ * There are no prerequisites for this module.
+ *
+ *
+ * \section asfdoc_samb_adc_module_overview Module Overview
+ *
+ * This driver provides an interface for the Analog-to-Digital conversion
+ * functions on the device, to convert analog voltages to a corresponding
+ * digital value. The ADC has up to 12-bit resolution.
+ *
+ * \subsection asfdoc_samb_adc_module_overview_prescaler Sample Clock Prescaler
+ * \f[
+ * F_{clk} = N + 2 \times {(throughput\_frequency)}
+ * \f]
+ * \f[
+ * (N = ADC resolution)
+ * \f]
+ *
+ * Example: For throughput of 100KS/s use sampling clock (Fclk=1.3MHz)
+ *
+ * \subsection asfdoc_samb_adc_module_overview_resolution ADC Resolution
+ * There are two ADC resolution of operation:
+ * - \b High Resolution (11-bit)
+ *
+ * Set the reference voltage to half the supply voltage or below. In this
+ * mode the input signal dynamic range equals twice the reference voltage.
+ *
+ * Example: If supply voltage =3V and reference voltage= 1.4V, input signal
+ * dynamic range can be from ground to 2*reference voltage (0~2.8V).
+ * - \b Medium Resolution (10-bit)
+ *
+ * Set the reference voltage to any value below supply voltage (up to
+ * supply voltage - 300mV) and in this condition the input dynamic range is
+ * from zero to reference voltage.
+ *
+ * Example: If supply voltage =3V and reference voltage= 2.7V, input signal
+ * dynamic range can be from ground to reference voltage (0~2.7V).
+ *
+ * \subsection asfdoc_samb_adc_module_overview_conversion Channel Modes
+ * There are two modes for input channel selection:
+ * - Either to assign a specific input channel
+ * - Time domain multiplexing between 4 input channels
+ * - Channel1 to channel4
+ * - channel5 to channel8
+ *
+ * \section asfdoc_samb_adc_special_considerations Special Considerations
+ * An integrated analog temperature sensor is available for use with the ADC.
+ * The internal specific voltage can also be measured by the ADC. For internal
+ * ADC inputs, the internal source(s) may need to be manually enabled by the
+ * user application before they can be measured.
+ *
+ *
+ * \section asfdoc_samb_adc_extra_info Extra Information
+ *
+ * For extra information, see \ref asfdoc_samb_adc_extra. This includes:
+ * - \ref asfdoc_samb_adc_extra_acronyms
+ * - \ref asfdoc_samb_adc_extra_dependencies
+ * - \ref asfdoc_samb_adc_extra_errata
+ * - \ref asfdoc_samb_adc_extra_history
+ *
+ *
+ * \section asfdoc_samb_adc_examples Examples
+ *
+ * For a list of examples related to this driver, see
+ * \ref asfdoc_samb_adc_exqsg.
+ *
+ *
+ * \section asfdoc_samb_adc_api_overview API Overview
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <compiler.h>
+#include <system_sam_b.h>
+
+/**
+ * \brief ADC internal reference voltage level enum
+ *
+ * Enum for the possible internal reference voltage level for the ADC.
+ *
+ */
+enum adc_internal_buf {
+ /** Internal buffer voltage level: 0.5V */
+ ADC_INTERNAL_BUF_0_5 = 0,
+ /** Internal buffer voltage level: 0.6V */
+ ADC_INTERNAL_BUF_0_6,
+ /** Internal buffer voltage level: 0.7V */
+ ADC_INTERNAL_BUF_0_7,
+ /** Internal buffer voltage level: 0.8V */
+ ADC_INTERNAL_BUF_0_8,
+ /** Internal buffer voltage level: 0.9V */
+ ADC_INTERNAL_BUF_0_9,
+ /** Internal buffer voltage level: 1.0V */
+ ADC_INTERNAL_BUF_1_0,
+ /** Internal buffer voltage level: 1.1V */
+ ADC_INTERNAL_BUF_1_1,
+ /** Internal buffer voltage level: 1.2V */
+ ADC_INTERNAL_BUF_1_2,
+ /** Internal buffer voltage level: 1.3V */
+ ADC_INTERNAL_BUF_1_3,
+ /** Internal buffer voltage level: 1.4V */
+ ADC_INTERNAL_BUF_1_4,
+ /** Internal buffer voltage level: 1.5V */
+ ADC_INTERNAL_BUF_1_5,
+ /** Internal buffer voltage level: 1.6V */
+ ADC_INTERNAL_BUF_1_6,
+ /** Internal buffer voltage level: 1.7V */
+ ADC_INTERNAL_BUF_1_7,
+ /** Internal buffer voltage level: 1.8V */
+ ADC_INTERNAL_BUF_1_8,
+ /** Internal buffer voltage level: 1.9V */
+ ADC_INTERNAL_BUF_1_9,
+ /** Internal buffer voltage level: 2.0V */
+ ADC_INTERNAL_BUF_2_0,
+};
+
+/**
+ * \brief ADC reference voltage enum
+ *
+ * Enum for the possible reference voltages for the ADC.
+ *
+ */
+enum adc_reference {
+ /** Internal form buffer reference */
+ ADC_REFERENCE_INTERNAL_BUF = 0,
+ /** Internal from IxR reference */
+ ADC_REFERENCE_INTERNAL_IR,
+ /** VBATT/2 reference */
+ ADC_REFERENCE_VBATT_2,
+ /** GPIO_MS1 reference */
+ ADC_REFERENCE_GPIO_MS1,
+ /** GPIO_MS2 reference */
+ ADC_REFERENCE_GPIO_MS2,
+ /** GPIO_MS3 reference */
+ ADC_REFERENCE_GPIO_MS3,
+ /** GPIO_MS4 reference */
+ ADC_REFERENCE_GPIO_MS4,
+ /** VBATTERY reference */
+ ADC_REFERENCE_VBATT,
+};
+
+/**
+ * \brief ADC input channel selection enum
+ *
+ * Enum for the possible input channel selections for the ADC.
+ *
+ */
+enum adc_input_channel {
+ /** GPIO_MS1 input */
+ ADC_INPUT_CH_GPIO_MS1 = 0,
+ /** GPIO_MS2 input */
+ ADC_INPUT_CH_GPIO_MS2,
+ /** GPIO_MS3 input */
+ ADC_INPUT_CH_GPIO_MS3,
+ /** GPIO_MS4 input */
+ ADC_INPUT_CH_GPIO_MS4,
+ /** On chip temperature measurement input */
+ ADC_INPUT_CH_TEMPERATURE,
+ /** VBATT divided by 4 voltage level */
+ ADC_INPUT_CH_VBATT_4,
+ /** LP_LDO_OUT_1P2 low power domain voltage */
+ ADC_INPUT_CH_LPD0_LDO,
+ /** ADC reference voltage level */
+ ADC_INPUT_CH_VREF,
+};
+
+/**
+ * \brief ADC input channel time multiplexing selection mode enum
+ *
+ * Enum for the possible channel time multiplexing mode for the ADC.
+ *
+ */
+enum adc_channel_mode {
+ /**
+ * Input channels time multiplexing is between channel 0 to channel 3.
+ * In this mode, ADC input channel selection is invalid.
+ */
+ ADC_CH_MODE_CH0_TO_CH3,
+ /**
+ * Input channels time multiplexing is between channel 4 to channel 7.
+ * In this mode, ADC input channel selection is invalid.
+ */
+ ADC_CH_MODE_CH4_TO_CH7,
+ /** Assign a specific input channel using \ref adc_input_channel */
+ ADC_CH_MODE_ASSIGN,
+};
+
+/**
+ * \brief ADC input dynamic range selection enum
+ *
+ * Enum for the possible input dynamic range for the ADC.
+ *
+ */
+enum adc_input_dynamic_range{
+ /** Input dynamic range from 0V to VBATT voltage level */
+ ADC_INPUT_DYNAMIC_RANGE_0 = 0,
+ /** Input dynamic range from 0.08*VBATT to 0.92*VBATT voltage level */
+ ADC_INPUT_DYNAMIC_RANGE_1,
+ /** Input dynamic range from 0.17*VBATT to 0.83*VBATT voltage level */
+ ADC_INPUT_DYNAMIC_RANGE_2,
+ /** Input dynamic range from 0.25*VBATT to 0.75*VBATT voltage level */
+ ADC_INPUT_DYNAMIC_RANGE_3,
+};
+
+/**
+ * \brief ADC comparator biasing current enum
+ *
+ * Enum for the possible comparator biasing current for the ADC different
+ * sampling rates.
+ *
+ */
+enum adc_bias_current {
+ /** Comparator bias current is 4uA for throughput 100KS/s */
+ ADC_BIAS_CURRENT_0 = 0,
+ /** Comparator bias current is 8uA */
+ ADC_BIAS_CURRENT_1,
+ /** Comparator bias current is 20uA */
+ ADC_BIAS_CURRENT_2,
+ /** Comparator bias current is 24uA for throughput 1MS/s */
+ ADC_BIAS_CURRENT_3,
+};
+
+/**
+ * \brief ADC configuration structure
+ *
+ * Configuration structure for an ADC instance. This structure should be
+ * initialized by the \ref adc_get_config_defaults()
+ * function before being modified by the user application.
+ */
+struct adc_config {
+ /** Voltage reference */
+ enum adc_reference reference;
+ /** Internal reference voltage level */
+ enum adc_internal_buf internal_vref;
+ /** Input channel */
+ enum adc_input_channel input_channel;
+ /** Input channel selection */
+ enum adc_channel_mode channel_mode;
+ /** Input channel time multiplexing selection mode */
+ enum adc_input_dynamic_range input_dynamic_range;
+ /** Comparator biasing current selection */
+ enum adc_bias_current bias_current;
+ /** Invert ADC Clock */
+ bool invert_clock;
+ /** Fractional part for the clock divider */
+ uint8_t frac_part;
+ /** Integer part for the clock divider */
+ uint16_t int_part;
+};
+
+/** \name Configuration, initialization and get status
+ * @{
+ */
+void adc_get_config_defaults(struct adc_config *const config);
+void adc_init(struct adc_config *config);
+uint32_t adc_get_status(void);
+/** @}*/
+
+/** \name Enable/Disable and Reset
+ * @{
+ */
+void adc_enable(void);
+void adc_disable(void);
+void adc_reset(void);
+/** @}*/
+
+/** \name Read Result
+ * @{
+ */
+enum status_code adc_read(enum adc_input_channel input_channel, uint16_t *result);
+/** @}*/
+
+/** @}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/**
+ * \page asfdoc_samb_adc_extra Extra Information for ADC Driver
+ *
+ * \section asfdoc_samb_adc_extra_acronyms Acronyms
+ * Below is a table listing the acronyms used in this module, along with their
+ * intended meanings.
+ *
+ * <table>
+ * <tr>
+ * <th>Acronym</th>
+ * <th>Description</th>
+ * </tr>
+ * <tr>
+ * <td>ADC</td>
+ * <td>Analog-to-Digital Converter</td>
+ * </tr>
+ * </table>
+ *
+ *
+ * \section asfdoc_samb_adc_extra_dependencies Dependencies
+ * There are no dependencies related to this driver.
+ *
+ *
+ * \section asfdoc_samb_adc_extra_errata Errata
+ * There are no errata related to this driver.
+ *
+ *
+ * \section asfdoc_samb_adc_extra_history Module History
+ * An overview of the module history is presented in the table below, with
+ * details on the enhancements and fixes made to the module since its first
+ * release. The current version of this corresponds to the newest version in
+ * the table.
+ *
+ * <table>
+ * <tr>
+ * <th>Changelog</th>
+ * </tr>
+ * <tr>
+ * <td>Initial Release</td>
+ * </tr>
+ * </table>
+ */
+
+/**
+ * \page asfdoc_samb_adc_exqsg Examples for ADC Driver
+ *
+ * This is a list of the available Quick Start guides (QSGs) and example
+ * applications for \ref asfdoc_samb_adc_group. QSGs are simple examples with
+ * step-by-step instructions to configure and use this driver in a selection of
+ * use cases. Note that a QSG can be compiled as a standalone application or be
+ * added to the user application.
+ *
+ * - \subpage asfdoc_samb_adc_basic_use_case
+ *
+ * \page asfdoc_samb_adc_document_revision_history Document Revision History
+ *
+ * <table>
+ * <tr>
+ * <th>Doc. Rev.</td>
+ * <th>Date</td>
+ * <th>Comments</td>
+ * </tr>
+ * <tr>
+ * <td>A</td>
+ * <td>09/2015</td>
+ * <td>Initial document release</td>
+ * </tr>
+ * </table>
+ */
+
+#endif /* ADC_SAM_B_H_INCLUDED */
diff --git a/atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc.c b/atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc.c
new file mode 100644
index 000000000..1565c8625
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc.c
@@ -0,0 +1,715 @@
+/**
+ * \file
+ *
+ * \brief SAM Peripheral Analog-to-Digital Converter Driver
+ *
+ * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#include "asf/sam0/drivers/adc/adc.h"
+
+#if SAMD20
+/* The Die revision D number */
+#define REVISON_D_NUM 3
+#endif
+
+/**
+ * \brief Initializes an ADC configuration structure to defaults
+ *
+ * Initializes a given ADC configuration struct to a set of known default
+ * values. This function should be called on any new instance of the
+ * configuration struct before being modified by the user application.
+ *
+ * The default configuration is as follows:
+ * \li GCLK generator 0 (GCLK main) clock source
+ * \li 1V from internal bandgap reference
+ * \li Div 4 clock prescaler
+ * \li 12-bit resolution
+ * \li Window monitor disabled
+ * \li No gain
+ * \li Positive input on ADC PIN 0
+ * \li Negative input on ADC PIN 1
+ * \li Averaging disabled
+ * \li Oversampling disabled
+ * \li Right adjust data
+ * \li Single-ended mode
+ * \li Free running disabled
+ * \li All events (input and generation) disabled
+ * \li Sleep operation disabled
+ * \li No reference compensation
+ * \li No gain/offset correction
+ * \li No added sampling time
+ * \li Pin scan mode disabled
+ *
+ * \param[out] config Pointer to configuration struct to initialize to
+ * default values
+ */
+void adc_get_config_defaults(struct adc_config *const config)
+{
+ Assert(config);
+ config->clock_source = GCLK_GENERATOR_0;
+ config->reference = ADC_REFERENCE_INT1V;
+ config->clock_prescaler = ADC_CLOCK_PRESCALER_DIV4;
+ config->resolution = ADC_RESOLUTION_12BIT;
+ config->window.window_mode = ADC_WINDOW_MODE_DISABLE;
+ config->window.window_upper_value = 0;
+ config->window.window_lower_value = 0;
+ config->gain_factor = ADC_GAIN_FACTOR_1X;
+#if SAMR21
+ config->positive_input = ADC_POSITIVE_INPUT_PIN6 ;
+#else
+ config->positive_input = ADC_POSITIVE_INPUT_PIN0 ;
+#endif
+ config->negative_input = ADC_NEGATIVE_INPUT_GND ;
+ config->accumulate_samples = ADC_ACCUMULATE_DISABLE;
+ config->divide_result = ADC_DIVIDE_RESULT_DISABLE;
+ config->left_adjust = false;
+ config->differential_mode = false;
+ config->freerunning = false;
+ config->event_action = ADC_EVENT_ACTION_DISABLED;
+ config->run_in_standby = false;
+ config->reference_compensation_enable = false;
+ config->correction.correction_enable = false;
+ config->correction.gain_correction = ADC_GAINCORR_RESETVALUE;
+ config->correction.offset_correction = ADC_OFFSETCORR_RESETVALUE;
+ config->sample_length = 0;
+ config->pin_scan.offset_start_scan = 0;
+ config->pin_scan.inputs_to_scan = 0;
+}
+
+/**
+ * \brief Sets the ADC window mode
+ *
+ * Sets the ADC window mode to a given mode and value range.
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ * \param[in] window_mode Window monitor mode to set
+ * \param[in] window_lower_value Lower window monitor threshold value
+ * \param[in] window_upper_value Upper window monitor threshold value
+ */
+void adc_set_window_mode(
+ struct adc_module *const module_inst,
+ const enum adc_window_mode window_mode,
+ const int16_t window_lower_value,
+ const int16_t window_upper_value)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ Adc *const adc_module = module_inst->hw;
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+
+ /* Set window mode */
+ adc_module->WINCTRL.reg = window_mode << ADC_WINCTRL_WINMODE_Pos;
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+
+ /* Set lower window monitor threshold value */
+ adc_module->WINLT.reg = window_lower_value << ADC_WINLT_WINLT_Pos;
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+
+ /* Set upper window monitor threshold value */
+ adc_module->WINUT.reg = window_upper_value << ADC_WINUT_WINUT_Pos;
+}
+
+/**
+* \internal Configure MUX settings for the analog pins
+*
+* This function will set the given ADC input pins
+* to the analog function in the pinmux, giving
+* the ADC access to the analog signal
+*
+* \param [in] pin AINxx pin to configure
+*/
+static inline void _adc_configure_ain_pin(uint32_t pin)
+{
+#define PIN_INVALID_ADC_AIN 0xFFFFUL
+
+ /* Pinmapping table for AINxx -> GPIO pin number */
+ const uint32_t pinmapping[] = {
+#if (SAMD20E) || (SAMD21E)|| (SAMDA1E)
+ PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5,
+ PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17,
+ PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19,
+#elif (SAMD20G) || (SAMD21G)|| (SAMDA1G)
+ PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1,
+ PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3,
+ PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5,
+ PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17,
+ PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19,
+#elif (SAMD20J) || (SAMD21J)|| (SAMDA1J)
+ PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1,
+ PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3,
+ PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5,
+ PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7,
+ PIN_PB00B_ADC_AIN8, PIN_PB01B_ADC_AIN9,
+ PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11,
+ PIN_PB04B_ADC_AIN12, PIN_PB05B_ADC_AIN13,
+ PIN_PB06B_ADC_AIN14, PIN_PB07B_ADC_AIN15,
+ PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17,
+ PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19,
+#elif SAMR21E
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+#elif SAMR21G
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5,
+ PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+#elif (SAMD09C) || (SAMD10C) || (SAMD11C)
+ PIN_PA02B_ADC_AIN0, PIN_INVALID_ADC_AIN,
+ PIN_PA04B_ADC_AIN2, PIN_PA05B_ADC_AIN3,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_PA14B_ADC_AIN6, PIN_PA15B_ADC_AIN7,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+#elif (SAMD09D)
+ PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1,
+ PIN_PA04B_ADC_AIN2, PIN_PA05B_ADC_AIN3,
+ PIN_PA06B_ADC_AIN4, PIN_PA07B_ADC_AIN5,
+ PIN_PA14B_ADC_AIN6, PIN_PA15B_ADC_AIN7,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+#elif (SAMD10DS) || (SAMD10DU) || (SAMD11DS) || (SAMD11DU)
+ PIN_PA02B_ADC_AIN0, PIN_INVALID_ADC_AIN,
+ PIN_PA04B_ADC_AIN2, PIN_PA05B_ADC_AIN3,
+ PIN_PA06B_ADC_AIN4, PIN_PA07B_ADC_AIN5,
+ PIN_PA14B_ADC_AIN6, PIN_PA15B_ADC_AIN7,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+#elif (SAMD10DM) || (SAMD11DM)
+ PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1,
+ PIN_PA04B_ADC_AIN2, PIN_PA05B_ADC_AIN3,
+ PIN_PA06B_ADC_AIN4, PIN_PA07B_ADC_AIN5,
+ PIN_PA14B_ADC_AIN6, PIN_PA15B_ADC_AIN7,
+ PIN_PA10B_ADC_AIN8, PIN_PA11B_ADC_AIN9,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+ PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
+#else
+# error ADC pin mappings are not defined for this device.
+#endif
+ };
+
+ uint32_t pin_map_result = PIN_INVALID_ADC_AIN;
+
+ if (pin <= ADC_EXTCHANNEL_MSB) {
+ pin_map_result = pinmapping[pin >> ADC_INPUTCTRL_MUXPOS_Pos];
+
+ Assert(pin_map_result != PIN_INVALID_ADC_AIN);
+
+ struct system_pinmux_config config;
+ system_pinmux_get_config_defaults(&config);
+
+ /* Analog functions are all on MUX setting B */
+ config.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE;
+ config.mux_position = 1;
+
+ system_pinmux_pin_set_config(pin_map_result, &config);
+ }
+}
+
+/**
+ * \internal Writes an ADC configuration to the hardware module
+ *
+ * Writes out a given ADC module configuration to the hardware module.
+ *
+ * \param[out] module_inst Pointer to the ADC software instance struct
+ * \param[in] config Pointer to configuration struct
+ *
+ * \return Status of the configuration procedure
+ * \retval STATUS_OK The configuration was successful
+ * \retval STATUS_ERR_INVALID_ARG Invalid argument(s) were provided
+ */
+static enum status_code _adc_set_config(
+ struct adc_module *const module_inst,
+ struct adc_config *const config)
+{
+ uint8_t adjres = 0;
+ uint32_t resolution = ADC_RESOLUTION_16BIT;
+ enum adc_accumulate_samples accumulate = ADC_ACCUMULATE_DISABLE;
+#if SAMD20
+ uint8_t revision_num = ((REG_DSU_DID & DSU_DID_DIE_Msk) >> DSU_DID_DIE_Pos);
+#endif
+
+ /* Get the hardware module pointer */
+ Adc *const adc_module = module_inst->hw;
+
+ /* Configure GCLK channel and enable clock */
+ struct system_gclk_chan_config gclk_chan_conf;
+ system_gclk_chan_get_config_defaults(&gclk_chan_conf);
+ gclk_chan_conf.source_generator = config->clock_source;
+ system_gclk_chan_set_config(ADC_GCLK_ID, &gclk_chan_conf);
+ system_gclk_chan_enable(ADC_GCLK_ID);
+
+ /* Setup pinmuxing for analog inputs */
+ if (config->pin_scan.inputs_to_scan != 0) {
+ uint8_t offset = config->pin_scan.offset_start_scan;
+ uint8_t start_pin =
+ offset +(uint8_t)config->positive_input;
+ uint8_t end_pin =
+ start_pin + config->pin_scan.inputs_to_scan;
+
+ while (start_pin < end_pin) {
+ _adc_configure_ain_pin((offset % 16)+(uint8_t)config->positive_input);
+ start_pin++;
+ offset++;
+ }
+ _adc_configure_ain_pin(config->negative_input);
+ } else {
+ _adc_configure_ain_pin(config->positive_input);
+ _adc_configure_ain_pin(config->negative_input);
+ }
+
+ /* Configure run in standby */
+ adc_module->CTRLA.reg = (config->run_in_standby << ADC_CTRLA_RUNSTDBY_Pos);
+
+ /* Configure reference */
+ adc_module->REFCTRL.reg =
+ (config->reference_compensation_enable << ADC_REFCTRL_REFCOMP_Pos) |
+ (config->reference);
+
+ /* Set adjusting result and number of samples */
+ switch (config->resolution) {
+
+ case ADC_RESOLUTION_CUSTOM:
+ adjres = config->divide_result;
+ accumulate = config->accumulate_samples;
+ /* 16-bit result register */
+ resolution = ADC_RESOLUTION_16BIT;
+ break;
+
+ case ADC_RESOLUTION_13BIT:
+ /* Increase resolution by 1 bit */
+ adjres = ADC_DIVIDE_RESULT_2;
+ accumulate = ADC_ACCUMULATE_SAMPLES_4;
+ /* 16-bit result register */
+ resolution = ADC_RESOLUTION_16BIT;
+ break;
+
+ case ADC_RESOLUTION_14BIT:
+ /* Increase resolution by 2 bit */
+ adjres = ADC_DIVIDE_RESULT_4;
+ accumulate = ADC_ACCUMULATE_SAMPLES_16;
+ /* 16-bit result register */
+ resolution = ADC_RESOLUTION_16BIT;
+ break;
+#if SAMD20
+ /* See $35.1.8 for ADC errata of SAM D20.
+ The revisions before D have this issue.*/
+ case ADC_RESOLUTION_15BIT:
+ /* Increase resolution by 3 bit */
+ if(revision_num < REVISON_D_NUM) {
+ adjres = ADC_DIVIDE_RESULT_8;
+ } else {
+ adjres = ADC_DIVIDE_RESULT_2;
+ }
+ accumulate = ADC_ACCUMULATE_SAMPLES_64;
+ /* 16-bit result register */
+ resolution = ADC_RESOLUTION_16BIT;
+ break;
+
+ case ADC_RESOLUTION_16BIT:
+ if(revision_num < REVISON_D_NUM) {
+ /* Increase resolution by 4 bit */
+ adjres = ADC_DIVIDE_RESULT_16;
+ } else {
+ adjres = ADC_DIVIDE_RESULT_DISABLE;
+ }
+ accumulate = ADC_ACCUMULATE_SAMPLES_256;
+ /* 16-bit result register */
+ resolution = ADC_RESOLUTION_16BIT;
+ break;
+#else
+ case ADC_RESOLUTION_15BIT:
+ /* Increase resolution by 3 bit */
+ adjres = ADC_DIVIDE_RESULT_2;
+ accumulate = ADC_ACCUMULATE_SAMPLES_64;
+ /* 16-bit result register */
+ resolution = ADC_RESOLUTION_16BIT;
+ break;
+
+ case ADC_RESOLUTION_16BIT:
+ /* Increase resolution by 4 bit */
+ adjres = ADC_DIVIDE_RESULT_DISABLE;
+ accumulate = ADC_ACCUMULATE_SAMPLES_256;
+ /* 16-bit result register */
+ resolution = ADC_RESOLUTION_16BIT;
+ break;
+#endif
+ case ADC_RESOLUTION_8BIT:
+ /* 8-bit result register */
+ resolution = ADC_RESOLUTION_8BIT;
+ break;
+ case ADC_RESOLUTION_10BIT:
+ /* 10-bit result register */
+ resolution = ADC_RESOLUTION_10BIT;
+ break;
+ case ADC_RESOLUTION_12BIT:
+ /* 12-bit result register */
+ resolution = ADC_RESOLUTION_12BIT;
+ break;
+
+ default:
+ /* Unknown. Abort. */
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+ adc_module->AVGCTRL.reg = ADC_AVGCTRL_ADJRES(adjres) | accumulate;
+
+ /* Check validity of sample length value */
+ if (config->sample_length > 63) {
+ return STATUS_ERR_INVALID_ARG;
+ } else {
+ /* Configure sample length */
+ adc_module->SAMPCTRL.reg =
+ (config->sample_length << ADC_SAMPCTRL_SAMPLEN_Pos);
+ }
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+
+ /* Configure CTRLB */
+ adc_module->CTRLB.reg =
+ config->clock_prescaler |
+ resolution |
+ (config->correction.correction_enable << ADC_CTRLB_CORREN_Pos) |
+ (config->freerunning << ADC_CTRLB_FREERUN_Pos) |
+ (config->left_adjust << ADC_CTRLB_LEFTADJ_Pos) |
+ (config->differential_mode << ADC_CTRLB_DIFFMODE_Pos);
+
+ /* Check validity of window thresholds */
+ if (config->window.window_mode != ADC_WINDOW_MODE_DISABLE) {
+ switch (resolution) {
+ case ADC_RESOLUTION_8BIT:
+ if (config->differential_mode &&
+ (config->window.window_lower_value > 127 ||
+ config->window.window_lower_value < -128 ||
+ config->window.window_upper_value > 127 ||
+ config->window.window_upper_value < -128)) {
+ /* Invalid value */
+ return STATUS_ERR_INVALID_ARG;
+ } else if (config->window.window_lower_value > 255 ||
+ config->window.window_upper_value > 255){
+ /* Invalid value */
+ return STATUS_ERR_INVALID_ARG;
+ }
+ break;
+ case ADC_RESOLUTION_10BIT:
+ if (config->differential_mode &&
+ (config->window.window_lower_value > 511 ||
+ config->window.window_lower_value < -512 ||
+ config->window.window_upper_value > 511 ||
+ config->window.window_upper_value < -512)) {
+ /* Invalid value */
+ return STATUS_ERR_INVALID_ARG;
+ } else if (config->window.window_lower_value > 1023 ||
+ config->window.window_upper_value > 1023){
+ /* Invalid value */
+ return STATUS_ERR_INVALID_ARG;
+ }
+ break;
+ case ADC_RESOLUTION_12BIT:
+ if (config->differential_mode &&
+ (config->window.window_lower_value > 2047 ||
+ config->window.window_lower_value < -2048 ||
+ config->window.window_upper_value > 2047 ||
+ config->window.window_upper_value < -2048)) {
+ /* Invalid value */
+ return STATUS_ERR_INVALID_ARG;
+ } else if (config->window.window_lower_value > 4095 ||
+ config->window.window_upper_value > 4095){
+ /* Invalid value */
+ return STATUS_ERR_INVALID_ARG;
+ }
+ break;
+ case ADC_RESOLUTION_16BIT:
+ if (config->differential_mode &&
+ (config->window.window_lower_value > 32767 ||
+ config->window.window_lower_value < -32768 ||
+ config->window.window_upper_value > 32767 ||
+ config->window.window_upper_value < -32768)) {
+ /* Invalid value */
+ return STATUS_ERR_INVALID_ARG;
+ } else if (config->window.window_lower_value > 65535 ||
+ config->window.window_upper_value > 65535){
+ /* Invalid value */
+ return STATUS_ERR_INVALID_ARG;
+ }
+ break;
+ }
+ }
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+
+ /* Configure window mode */
+ adc_module->WINCTRL.reg = config->window.window_mode;
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+
+ /* Configure lower threshold */
+ adc_module->WINLT.reg =
+ config->window.window_lower_value << ADC_WINLT_WINLT_Pos;
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+
+ /* Configure lower threshold */
+ adc_module->WINUT.reg = config->window.window_upper_value <<
+ ADC_WINUT_WINUT_Pos;
+
+ uint8_t inputs_to_scan = config->pin_scan.inputs_to_scan;
+ if (inputs_to_scan > 0) {
+ /*
+ * Number of input sources included is the value written to INPUTSCAN
+ * plus 1.
+ */
+ inputs_to_scan--;
+ }
+
+ if (inputs_to_scan > (ADC_INPUTCTRL_INPUTSCAN_Msk >> ADC_INPUTCTRL_INPUTSCAN_Pos) ||
+ config->pin_scan.offset_start_scan > (ADC_INPUTCTRL_INPUTOFFSET_Msk >> ADC_INPUTCTRL_INPUTOFFSET_Pos)) {
+ /* Invalid number of input pins or input offset */
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+
+ /* Configure pin scan mode and positive and negative input pins */
+ adc_module->INPUTCTRL.reg =
+ config->gain_factor |
+ (config->pin_scan.offset_start_scan <<
+ ADC_INPUTCTRL_INPUTOFFSET_Pos) |
+ (inputs_to_scan << ADC_INPUTCTRL_INPUTSCAN_Pos) |
+ config->negative_input |
+ config->positive_input;
+
+ /* Configure events */
+ adc_module->EVCTRL.reg = config->event_action;
+
+ /* Disable all interrupts */
+ adc_module->INTENCLR.reg =
+ (1 << ADC_INTENCLR_SYNCRDY_Pos) | (1 << ADC_INTENCLR_WINMON_Pos) |
+ (1 << ADC_INTENCLR_OVERRUN_Pos) | (1 << ADC_INTENCLR_RESRDY_Pos);
+
+ if (config->correction.correction_enable){
+ /* Make sure gain_correction value is valid */
+ if (config->correction.gain_correction > ADC_GAINCORR_GAINCORR_Msk) {
+ return STATUS_ERR_INVALID_ARG;
+ } else {
+ /* Set gain correction value */
+ adc_module->GAINCORR.reg = config->correction.gain_correction <<
+ ADC_GAINCORR_GAINCORR_Pos;
+ }
+
+ /* Make sure offset correction value is valid */
+ if (config->correction.offset_correction > 2047 ||
+ config->correction.offset_correction < -2048) {
+ return STATUS_ERR_INVALID_ARG;
+ } else {
+ /* Set offset correction value */
+ adc_module->OFFSETCORR.reg = config->correction.offset_correction <<
+ ADC_OFFSETCORR_OFFSETCORR_Pos;
+ }
+ }
+
+ /* Load in the fixed device ADC calibration constants */
+ adc_module->CALIB.reg =
+ ADC_CALIB_BIAS_CAL(
+ (*(uint32_t *)ADC_FUSES_BIASCAL_ADDR >> ADC_FUSES_BIASCAL_Pos)
+ ) |
+ ADC_CALIB_LINEARITY_CAL(
+ (*(uint64_t *)ADC_FUSES_LINEARITY_0_ADDR >> ADC_FUSES_LINEARITY_0_Pos)
+ );
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Initializes the ADC channel sequence
+ *
+ * Like SAMD and SAMR21 the INPUTOFFSET register will be incremented one
+ * automatically after a conversion done, causing the next conversion
+ * to be done with the positive input equal to MUXPOS + INPUTOFFSET,
+ * it is scanning continuously one by one even ADC channels are not continuous.
+ *
+ * Initializes the ADC channel sequence by the sequence of pin_array.
+ *
+ * \param[in] pin_array The array of the Mux selection for the positive ADC input
+ * \param[in] size The size of pin_array
+ */
+void adc_regular_ain_channel(uint32_t *pin_array, uint8_t size)
+{
+ for (int i = 0; i < size; i++) {
+ _adc_configure_ain_pin(pin_array[i]);
+ }
+}
+
+/**
+ * \brief Initializes the ADC
+ *
+ * Initializes the ADC device struct and the hardware module based on the
+ * given configuration struct values.
+ *
+ * \param[out] module_inst Pointer to the ADC software instance struct
+ * \param[in] hw Pointer to the ADC module instance
+ * \param[in] config Pointer to the configuration struct
+ *
+ * \return Status of the initialization procedure.
+ * \retval STATUS_OK The initialization was successful
+ * \retval STATUS_ERR_INVALID_ARG Invalid argument(s) were provided
+ * \retval STATUS_BUSY The module is busy with a reset operation
+ * \retval STATUS_ERR_DENIED The module is enabled
+ */
+enum status_code adc_init(
+ struct adc_module *const module_inst,
+ Adc *hw,
+ struct adc_config *config)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(hw);
+ Assert(config);
+
+ /* Associate the software module instance with the hardware module */
+ module_inst->hw = hw;
+
+ /* Turn on the digital interface clock */
+ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PM_APBCMASK_ADC);
+
+ if (hw->CTRLA.reg & ADC_CTRLA_SWRST) {
+ /* We are in the middle of a reset. Abort. */
+ return STATUS_BUSY;
+ }
+
+ if (hw->CTRLA.reg & ADC_CTRLA_ENABLE) {
+ /* Module must be disabled before initialization. Abort. */
+ return STATUS_ERR_DENIED;
+ }
+
+ /* Store the selected reference for later use */
+ module_inst->reference = config->reference;
+
+ /* Make sure bandgap is enabled if requested by the config */
+ if (module_inst->reference == ADC_REFERENCE_INT1V) {
+ system_voltage_reference_enable(SYSTEM_VOLTAGE_REFERENCE_BANDGAP);
+ }
+
+#if ADC_CALLBACK_MODE == true
+ for (uint8_t i = 0; i < ADC_CALLBACK_N; i++) {
+ module_inst->callback[i] = NULL;
+ };
+
+ module_inst->registered_callback_mask = 0;
+ module_inst->enabled_callback_mask = 0;
+ module_inst->remaining_conversions = 0;
+ module_inst->job_status = STATUS_OK;
+
+ _adc_instances[0] = module_inst;
+
+ if (config->event_action == ADC_EVENT_ACTION_DISABLED &&
+ !config->freerunning) {
+ module_inst->software_trigger = true;
+ } else {
+ module_inst->software_trigger = false;
+ }
+#endif
+
+ /* Write configuration to module */
+ return _adc_set_config(module_inst, config);
+}
diff --git a/atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc_callback.c b/atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc_callback.c
new file mode 100644
index 000000000..6f673dd34
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc_callback.c
@@ -0,0 +1,255 @@
+/**
+ * \file
+ *
+ * \brief SAM Peripheral Analog-to-Digital Converter Driver
+ *
+ * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+#include "adc_callback.h"
+
+struct adc_module *_adc_instances[ADC_INST_NUM];
+
+static void _adc_interrupt_handler(const uint8_t instance)
+{
+ struct adc_module *module = _adc_instances[instance];
+
+ /* get interrupt flags and mask out enabled callbacks */
+ uint32_t flags = module->hw->INTFLAG.reg;
+
+ if (flags & ADC_INTFLAG_RESRDY) {
+ if ((module->enabled_callback_mask & (1 << ADC_CALLBACK_READ_BUFFER)) &&
+ (module->registered_callback_mask & (1 << ADC_CALLBACK_READ_BUFFER))) {
+ /* clear interrupt flag */
+ module->hw->INTFLAG.reg = ADC_INTFLAG_RESRDY;
+
+ while (adc_is_syncing(module)) {
+ /* Wait for synchronization */
+ }
+
+ /* store ADC result in job buffer */
+ *(module->job_buffer++) = module->hw->RESULT.reg;
+
+ if (--module->remaining_conversions > 0) {
+ if (module->software_trigger == true) {
+ adc_start_conversion(module);
+ }
+ } else {
+ if (module->job_status == STATUS_BUSY) {
+ /* job is complete. update status,disable interrupt
+ *and call callback */
+ module->job_status = STATUS_OK;
+ adc_disable_interrupt(module, ADC_INTERRUPT_RESULT_READY);
+
+ (module->callback[ADC_CALLBACK_READ_BUFFER])(module);
+ }
+ }
+ }
+ }
+
+ if (flags & ADC_INTFLAG_WINMON) {
+ module->hw->INTFLAG.reg = ADC_INTFLAG_WINMON;
+ if ((module->enabled_callback_mask & (1 << ADC_CALLBACK_WINDOW)) &&
+ (module->registered_callback_mask & (1 << ADC_CALLBACK_WINDOW))) {
+ (module->callback[ADC_CALLBACK_WINDOW])(module);
+ }
+
+ }
+
+ if (flags & ADC_INTFLAG_OVERRUN) {
+ module->hw->INTFLAG.reg = ADC_INTFLAG_OVERRUN;
+ if ((module->enabled_callback_mask & (1 << ADC_CALLBACK_ERROR)) &&
+ (module->registered_callback_mask & (1 << ADC_CALLBACK_ERROR))) {
+ (module->callback[ADC_CALLBACK_ERROR])(module);
+ }
+ }
+}
+
+/** Interrupt handler for the ADC module. */
+void ADC_Handler(void)
+{
+ _adc_interrupt_handler(0);
+}
+
+/**
+ * \brief Registers a callback
+ *
+ * Registers a callback function which is implemented by the user.
+ *
+ * \note The callback must be enabled by for the interrupt handler to call it
+ * when the condition for the callback is met.
+ *
+ * \param[in] module Pointer to ADC software instance struct
+ * \param[in] callback_func Pointer to callback function
+ * \param[in] callback_type Callback type given by an enum
+ *
+ */
+void adc_register_callback(
+ struct adc_module *const module,
+ adc_callback_t callback_func,
+ enum adc_callback callback_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(callback_func);
+
+ /* Register callback function */
+ module->callback[callback_type] = callback_func;
+
+ /* Set the bit corresponding to the callback_type */
+ module->registered_callback_mask |= (1 << callback_type);
+}
+
+/**
+ * \brief Unregisters a callback
+ *
+ * Unregisters a callback function which is implemented by the user.
+ *
+ * \param[in] module Pointer to ADC software instance struct
+ * \param[in] callback_type Callback type given by an enum
+ *
+ */
+void adc_unregister_callback(
+ struct adc_module *const module,
+ enum adc_callback callback_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+
+ /* Unregister callback function */
+ module->callback[callback_type] = NULL;
+
+ /* Clear the bit corresponding to the callback_type */
+ module->registered_callback_mask &= ~(1 << callback_type);
+}
+
+/**
+ * \brief Read multiple samples from ADC
+ *
+ * Read \c samples samples from the ADC into the buffer \c buffer.
+ * If there is no hardware trigger defined (event action) the
+ * driver will retrigger the ADC conversion whenever a conversion
+ * is complete until \c samples samples has been acquired. To avoid
+ * jitter in the sampling frequency using an event trigger is advised.
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ * \param[in] samples Number of samples to acquire
+ * \param[out] buffer Buffer to store the ADC samples
+ *
+ * \return Status of the job start.
+ * \retval STATUS_OK The conversion job was started successfully and is
+ * in progress
+ * \retval STATUS_BUSY The ADC is already busy with another job
+ */
+enum status_code adc_read_buffer_job(
+ struct adc_module *const module_inst,
+ uint16_t *buffer,
+ uint16_t samples)
+{
+ Assert(module_inst);
+ Assert(samples);
+ Assert(buffer);
+
+ if(module_inst->remaining_conversions != 0 ||
+ module_inst->job_status == STATUS_BUSY){
+ return STATUS_BUSY;
+ }
+
+ module_inst->job_status = STATUS_BUSY;
+ module_inst->remaining_conversions = samples;
+ module_inst->job_buffer = buffer;
+
+ adc_enable_interrupt(module_inst, ADC_INTERRUPT_RESULT_READY);
+
+ if(module_inst->software_trigger == true) {
+ adc_start_conversion(module_inst);
+ }
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Gets the status of a job
+ *
+ * Gets the status of an ongoing or the last job.
+ *
+ * \param [in] module_inst Pointer to the ADC software instance struct
+ * \param [in] type Type of job to get status
+ *
+ * \return Status of the job.
+ */
+enum status_code adc_get_job_status(
+ struct adc_module *module_inst,
+ enum adc_job_type type)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+
+ if (type == ADC_JOB_READ_BUFFER ) {
+ return module_inst->job_status;
+ } else {
+ return STATUS_ERR_INVALID_ARG;
+ }
+}
+
+/**
+ * \brief Aborts an ongoing job
+ *
+ * Aborts an ongoing job.
+ *
+ * \param [in] module_inst Pointer to the ADC software instance struct
+ * \param [in] type Type of job to abort
+ */
+void adc_abort_job(
+ struct adc_module *module_inst,
+ enum adc_job_type type)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+
+ if (type == ADC_JOB_READ_BUFFER) {
+ /* Disable interrupt */
+ adc_disable_interrupt(module_inst, ADC_INTERRUPT_RESULT_READY);
+ /* Mark job as aborted */
+ module_inst->job_status = STATUS_ABORTED;
+ module_inst->remaining_conversions = 0;
+ }
+}
+
diff --git a/atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc_feature.h b/atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc_feature.h
new file mode 100644
index 000000000..9635a190d
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc_feature.h
@@ -0,0 +1,728 @@
+/**
+ * \file
+ *
+ * \brief SAM ADC functionality
+ *
+ * Copyright (C) 2014-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+#ifndef ADC_FEATURE_H_INCLUDED
+#define ADC_FEATURE_H_INCLUDED
+
+/**
+ * \addtogroup asfdoc_sam0_adc_group
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if ADC_CALLBACK_MODE == true
+# include <system_interrupt.h>
+
+#if !defined(__DOXYGEN__)
+extern struct adc_module *_adc_instances[ADC_INST_NUM];
+#endif
+
+/** Forward definition of the device instance. */
+struct adc_module;
+
+/** Type of the callback functions. */
+typedef void (*adc_callback_t)(struct adc_module *const module);
+
+/**
+ * \brief ADC Callback enum
+ *
+ * Callback types for ADC callback driver.
+ *
+ */
+enum adc_callback {
+ /** Callback for buffer received */
+ ADC_CALLBACK_READ_BUFFER,
+ /** Callback when window is hit */
+ ADC_CALLBACK_WINDOW,
+ /** Callback for error */
+ ADC_CALLBACK_ERROR,
+# if !defined(__DOXYGEN__)
+ /** Number of available callbacks */
+ ADC_CALLBACK_N,
+# endif
+};
+
+#endif
+
+/**
+ * \brief ADC reference voltage enum
+ *
+ * Enum for the possible reference voltages for the ADC.
+ *
+ */
+enum adc_reference {
+ /** 1.0V voltage reference */
+ ADC_REFERENCE_INT1V = ADC_REFCTRL_REFSEL_INT1V,
+ /** 1/1.48V<SUB>CC</SUB> reference */
+ ADC_REFERENCE_INTVCC0 = ADC_REFCTRL_REFSEL_INTVCC0,
+ /** 1/2V<SUB>CC</SUB> (only for internal V<SUB>CC</SUB> > 2.1V) */
+ ADC_REFERENCE_INTVCC1 = ADC_REFCTRL_REFSEL_INTVCC1,
+ /** External reference A */
+ ADC_REFERENCE_AREFA = ADC_REFCTRL_REFSEL_AREFA,
+ /** External reference B */
+ ADC_REFERENCE_AREFB = ADC_REFCTRL_REFSEL_AREFB,
+};
+
+/**
+ * \brief ADC clock prescaler enum
+ *
+ * Enum for the possible clock prescaler values for the ADC.
+ *
+ */
+enum adc_clock_prescaler {
+ /** ADC clock division factor 4 */
+ ADC_CLOCK_PRESCALER_DIV4 = ADC_CTRLB_PRESCALER_DIV4,
+ /** ADC clock division factor 8 */
+ ADC_CLOCK_PRESCALER_DIV8 = ADC_CTRLB_PRESCALER_DIV8,
+ /** ADC clock division factor 16 */
+ ADC_CLOCK_PRESCALER_DIV16 = ADC_CTRLB_PRESCALER_DIV16,
+ /** ADC clock division factor 32 */
+ ADC_CLOCK_PRESCALER_DIV32 = ADC_CTRLB_PRESCALER_DIV32,
+ /** ADC clock division factor 64 */
+ ADC_CLOCK_PRESCALER_DIV64 = ADC_CTRLB_PRESCALER_DIV64,
+ /** ADC clock division factor 128 */
+ ADC_CLOCK_PRESCALER_DIV128 = ADC_CTRLB_PRESCALER_DIV128,
+ /** ADC clock division factor 256 */
+ ADC_CLOCK_PRESCALER_DIV256 = ADC_CTRLB_PRESCALER_DIV256,
+ /** ADC clock division factor 512 */
+ ADC_CLOCK_PRESCALER_DIV512 = ADC_CTRLB_PRESCALER_DIV512,
+};
+
+/**
+ * \brief ADC resolution enum
+ *
+ * Enum for the possible resolution values for the ADC.
+ *
+ */
+enum adc_resolution {
+ /** ADC 12-bit resolution */
+ ADC_RESOLUTION_12BIT = ADC_CTRLB_RESSEL_12BIT,
+ /** ADC 16-bit resolution using oversampling and decimation */
+ ADC_RESOLUTION_16BIT = ADC_CTRLB_RESSEL_16BIT,
+ /** ADC 10-bit resolution */
+ ADC_RESOLUTION_10BIT = ADC_CTRLB_RESSEL_10BIT,
+ /** ADC 8-bit resolution */
+ ADC_RESOLUTION_8BIT = ADC_CTRLB_RESSEL_8BIT,
+ /** ADC 13-bit resolution using oversampling and decimation */
+ ADC_RESOLUTION_13BIT,
+ /** ADC 14-bit resolution using oversampling and decimation */
+ ADC_RESOLUTION_14BIT,
+ /** ADC 15-bit resolution using oversampling and decimation */
+ ADC_RESOLUTION_15BIT,
+ /** ADC 16-bit result register for use with averaging. When using this mode
+ * the ADC result register will be set to 16-bit wide, and the number of
+ * samples to accumulate and the division factor is configured by the
+ * \ref adc_config.accumulate_samples and \ref adc_config.divide_result
+ * members in the configuration struct.
+ */
+ ADC_RESOLUTION_CUSTOM,
+};
+
+/**
+ * \brief ADC window monitor mode enum
+ *
+ * Enum for the possible window monitor modes for the ADC.
+ *
+ */
+enum adc_window_mode {
+ /** No window mode */
+ ADC_WINDOW_MODE_DISABLE = ADC_WINCTRL_WINMODE_DISABLE,
+ /** RESULT > WINLT */
+ ADC_WINDOW_MODE_ABOVE_LOWER = ADC_WINCTRL_WINMODE_MODE1,
+ /** RESULT < WINUT */
+ ADC_WINDOW_MODE_BELOW_UPPER = ADC_WINCTRL_WINMODE_MODE2,
+ /** WINLT < RESULT < WINUT */
+ ADC_WINDOW_MODE_BETWEEN = ADC_WINCTRL_WINMODE_MODE3,
+ /** !(WINLT < RESULT < WINUT) */
+ ADC_WINDOW_MODE_BETWEEN_INVERTED = ADC_WINCTRL_WINMODE_MODE4,
+};
+
+/**
+ * \brief ADC gain factor selection enum
+ *
+ * Enum for the possible gain factor values for the ADC.
+ *
+ */
+enum adc_gain_factor {
+ /** 1x gain */
+ ADC_GAIN_FACTOR_1X = ADC_INPUTCTRL_GAIN_1X,
+ /** 2x gain */
+ ADC_GAIN_FACTOR_2X = ADC_INPUTCTRL_GAIN_2X,
+ /** 4x gain */
+ ADC_GAIN_FACTOR_4X = ADC_INPUTCTRL_GAIN_4X,
+ /** 8x gain */
+ ADC_GAIN_FACTOR_8X = ADC_INPUTCTRL_GAIN_8X,
+ /** 16x gain */
+ ADC_GAIN_FACTOR_16X = ADC_INPUTCTRL_GAIN_16X,
+ /** 1/2x gain */
+ ADC_GAIN_FACTOR_DIV2 = ADC_INPUTCTRL_GAIN_DIV2,
+};
+
+/**
+ * \brief ADC event action enum
+ *
+ * Enum for the possible actions to take on an incoming event.
+ *
+ */
+enum adc_event_action {
+ /** Event action disabled */
+ ADC_EVENT_ACTION_DISABLED = 0,
+ /** Flush ADC and start conversion */
+ ADC_EVENT_ACTION_FLUSH_START_CONV = ADC_EVCTRL_SYNCEI,
+ /** Start conversion */
+ ADC_EVENT_ACTION_START_CONV = ADC_EVCTRL_STARTEI,
+};
+
+/**
+ * \brief ADC positive MUX input selection enum
+ *
+ * Enum for the possible positive MUX input selections for the ADC.
+ *
+ */
+enum adc_positive_input {
+ /** ADC0 pin */
+ ADC_POSITIVE_INPUT_PIN0 = ADC_INPUTCTRL_MUXPOS_PIN0,
+ /** ADC1 pin */
+ ADC_POSITIVE_INPUT_PIN1 = ADC_INPUTCTRL_MUXPOS_PIN1,
+ /** ADC2 pin */
+ ADC_POSITIVE_INPUT_PIN2 = ADC_INPUTCTRL_MUXPOS_PIN2,
+ /** ADC3 pin */
+ ADC_POSITIVE_INPUT_PIN3 = ADC_INPUTCTRL_MUXPOS_PIN3,
+ /** ADC4 pin */
+ ADC_POSITIVE_INPUT_PIN4 = ADC_INPUTCTRL_MUXPOS_PIN4,
+ /** ADC5 pin */
+ ADC_POSITIVE_INPUT_PIN5 = ADC_INPUTCTRL_MUXPOS_PIN5,
+ /** ADC6 pin */
+ ADC_POSITIVE_INPUT_PIN6 = ADC_INPUTCTRL_MUXPOS_PIN6,
+ /** ADC7 pin */
+ ADC_POSITIVE_INPUT_PIN7 = ADC_INPUTCTRL_MUXPOS_PIN7,
+ /** ADC8 pin */
+ ADC_POSITIVE_INPUT_PIN8 = ADC_INPUTCTRL_MUXPOS_PIN8,
+ /** ADC9 pin */
+ ADC_POSITIVE_INPUT_PIN9 = ADC_INPUTCTRL_MUXPOS_PIN9,
+ /** ADC10 pin */
+ ADC_POSITIVE_INPUT_PIN10 = ADC_INPUTCTRL_MUXPOS_PIN10,
+ /** ADC11 pin */
+ ADC_POSITIVE_INPUT_PIN11 = ADC_INPUTCTRL_MUXPOS_PIN11,
+ /** ADC12 pin */
+ ADC_POSITIVE_INPUT_PIN12 = ADC_INPUTCTRL_MUXPOS_PIN12,
+ /** ADC13 pin */
+ ADC_POSITIVE_INPUT_PIN13 = ADC_INPUTCTRL_MUXPOS_PIN13,
+ /** ADC14 pin */
+ ADC_POSITIVE_INPUT_PIN14 = ADC_INPUTCTRL_MUXPOS_PIN14,
+ /** ADC15 pin */
+ ADC_POSITIVE_INPUT_PIN15 = ADC_INPUTCTRL_MUXPOS_PIN15,
+ /** ADC16 pin */
+ ADC_POSITIVE_INPUT_PIN16 = ADC_INPUTCTRL_MUXPOS_PIN16,
+ /** ADC17 pin */
+ ADC_POSITIVE_INPUT_PIN17 = ADC_INPUTCTRL_MUXPOS_PIN17,
+ /** ADC18 pin */
+ ADC_POSITIVE_INPUT_PIN18 = ADC_INPUTCTRL_MUXPOS_PIN18,
+ /** ADC19 pin */
+ ADC_POSITIVE_INPUT_PIN19 = ADC_INPUTCTRL_MUXPOS_PIN19,
+ /** Temperature reference */
+ ADC_POSITIVE_INPUT_TEMP = ADC_INPUTCTRL_MUXPOS_TEMP,
+ /** Bandgap voltage */
+ ADC_POSITIVE_INPUT_BANDGAP = ADC_INPUTCTRL_MUXPOS_BANDGAP,
+ /** 1/4 scaled core supply */
+ ADC_POSITIVE_INPUT_SCALEDCOREVCC = ADC_INPUTCTRL_MUXPOS_SCALEDCOREVCC,
+ /** 1/4 scaled I/O supply */
+ ADC_POSITIVE_INPUT_SCALEDIOVCC = ADC_INPUTCTRL_MUXPOS_SCALEDIOVCC,
+ /** DAC input */
+ ADC_POSITIVE_INPUT_DAC = ADC_INPUTCTRL_MUXPOS_DAC,
+};
+
+/**
+ * \brief ADC negative Multiplexer(MUX) input selection enum
+ *
+ * Enum for the possible negative Multiplexer(MUX) input selections for the ADC.
+ *
+ */
+enum adc_negative_input {
+ /** ADC0 pin */
+ ADC_NEGATIVE_INPUT_PIN0 = ADC_INPUTCTRL_MUXNEG_PIN0,
+ /** ADC1 pin */
+ ADC_NEGATIVE_INPUT_PIN1 = ADC_INPUTCTRL_MUXNEG_PIN1,
+ /** ADC2 pin */
+ ADC_NEGATIVE_INPUT_PIN2 = ADC_INPUTCTRL_MUXNEG_PIN2,
+ /** ADC3 pin */
+ ADC_NEGATIVE_INPUT_PIN3 = ADC_INPUTCTRL_MUXNEG_PIN3,
+ /** ADC4 pin */
+ ADC_NEGATIVE_INPUT_PIN4 = ADC_INPUTCTRL_MUXNEG_PIN4,
+ /** ADC5 pin */
+ ADC_NEGATIVE_INPUT_PIN5 = ADC_INPUTCTRL_MUXNEG_PIN5,
+ /** ADC6 pin */
+ ADC_NEGATIVE_INPUT_PIN6 = ADC_INPUTCTRL_MUXNEG_PIN6,
+ /** ADC7 pin */
+ ADC_NEGATIVE_INPUT_PIN7 = ADC_INPUTCTRL_MUXNEG_PIN7,
+ /** Internal ground */
+ ADC_NEGATIVE_INPUT_GND = ADC_INPUTCTRL_MUXNEG_GND,
+ /** I/O ground */
+ ADC_NEGATIVE_INPUT_IOGND = ADC_INPUTCTRL_MUXNEG_IOGND,
+};
+
+/**
+ * \brief ADC number of accumulated samples enum
+ *
+ * Enum for the possible numbers of ADC samples to accumulate.
+ * This setting is only used when the \ref ADC_RESOLUTION_CUSTOM
+ * resolution setting is used.
+ *
+ */
+enum adc_accumulate_samples {
+ /** No averaging */
+ ADC_ACCUMULATE_DISABLE = ADC_AVGCTRL_SAMPLENUM_1,
+ /** Average 2 samples */
+ ADC_ACCUMULATE_SAMPLES_2 = ADC_AVGCTRL_SAMPLENUM_2,
+ /** Average 4 samples */
+ ADC_ACCUMULATE_SAMPLES_4 = ADC_AVGCTRL_SAMPLENUM_4,
+ /** Average 8 samples */
+ ADC_ACCUMULATE_SAMPLES_8 = ADC_AVGCTRL_SAMPLENUM_8,
+ /** Average 16 samples */
+ ADC_ACCUMULATE_SAMPLES_16 = ADC_AVGCTRL_SAMPLENUM_16,
+ /** Average 32 samples */
+ ADC_ACCUMULATE_SAMPLES_32 = ADC_AVGCTRL_SAMPLENUM_32,
+ /** Average 64 samples */
+ ADC_ACCUMULATE_SAMPLES_64 = ADC_AVGCTRL_SAMPLENUM_64,
+ /** Average 128 samples */
+ ADC_ACCUMULATE_SAMPLES_128 = ADC_AVGCTRL_SAMPLENUM_128,
+ /** Average 256 samples */
+ ADC_ACCUMULATE_SAMPLES_256 = ADC_AVGCTRL_SAMPLENUM_256,
+ /** Average 512 samples */
+ ADC_ACCUMULATE_SAMPLES_512 = ADC_AVGCTRL_SAMPLENUM_512,
+ /** Average 1024 samples */
+ ADC_ACCUMULATE_SAMPLES_1024 = ADC_AVGCTRL_SAMPLENUM_1024,
+};
+
+/**
+ * \brief ADC possible dividers for the result register
+ *
+ * Enum for the possible division factors to use when accumulating
+ * multiple samples. To keep the same resolution for the averaged
+ * result and the actual input value, the division factor must
+ * be equal to the number of samples accumulated. This setting is only
+ * used when the \ref ADC_RESOLUTION_CUSTOM resolution setting is used.
+ */
+enum adc_divide_result {
+ /** Don't divide result register after accumulation */
+ ADC_DIVIDE_RESULT_DISABLE = 0,
+ /** Divide result register by 2 after accumulation */
+ ADC_DIVIDE_RESULT_2 = 1,
+ /** Divide result register by 4 after accumulation */
+ ADC_DIVIDE_RESULT_4 = 2,
+ /** Divide result register by 8 after accumulation */
+ ADC_DIVIDE_RESULT_8 = 3,
+ /** Divide result register by 16 after accumulation */
+ ADC_DIVIDE_RESULT_16 = 4,
+ /** Divide result register by 32 after accumulation */
+ ADC_DIVIDE_RESULT_32 = 5,
+ /** Divide result register by 64 after accumulation */
+ ADC_DIVIDE_RESULT_64 = 6,
+ /** Divide result register by 128 after accumulation */
+ ADC_DIVIDE_RESULT_128 = 7,
+};
+
+#if ADC_CALLBACK_MODE == true
+/**
+ * Enum for the possible ADC interrupt flags.
+ */
+enum adc_interrupt_flag {
+ /** ADC result ready */
+ ADC_INTERRUPT_RESULT_READY = ADC_INTFLAG_RESRDY,
+ /** Window monitor match */
+ ADC_INTERRUPT_WINDOW = ADC_INTFLAG_WINMON,
+ /** ADC result overwritten before read */
+ ADC_INTERRUPT_OVERRUN = ADC_INTFLAG_OVERRUN,
+};
+#endif
+
+/**
+ * \brief ADC oversampling and decimation enum
+ *
+ * Enum for the possible numbers of bits resolution can be increased by when
+ * using oversampling and decimation.
+ *
+ */
+enum adc_oversampling_and_decimation {
+ /** Don't use oversampling and decimation mode */
+ ADC_OVERSAMPLING_AND_DECIMATION_DISABLE = 0,
+ /** 1-bit resolution increase */
+ ADC_OVERSAMPLING_AND_DECIMATION_1BIT,
+ /** 2-bit resolution increase */
+ ADC_OVERSAMPLING_AND_DECIMATION_2BIT,
+ /** 3-bit resolution increase */
+ ADC_OVERSAMPLING_AND_DECIMATION_3BIT,
+ /** 4-bit resolution increase */
+ ADC_OVERSAMPLING_AND_DECIMATION_4BIT
+};
+
+/**
+ * \brief Window monitor configuration structure
+ *
+ * Window monitor configuration structure.
+ */
+struct adc_window_config {
+ /** Selected window mode */
+ enum adc_window_mode window_mode;
+ /** Lower window value */
+ int32_t window_lower_value;
+ /** Upper window value */
+ int32_t window_upper_value;
+};
+
+/**
+ * \brief ADC event enable/disable structure.
+ *
+ * Event flags for the ADC module. This is used to enable and
+ * disable events via \ref adc_enable_events() and \ref adc_disable_events().
+ */
+struct adc_events {
+ /** Enable event generation on conversion done */
+ bool generate_event_on_conversion_done;
+ /** Enable event generation on window monitor */
+ bool generate_event_on_window_monitor;
+};
+
+/**
+ * \brief Gain and offset correction configuration structure
+ *
+ * Gain and offset correction configuration structure.
+ * Part of the \ref adc_config struct and will be initialized by
+ * \ref adc_get_config_defaults.
+ */
+struct adc_correction_config {
+ /**
+ * Enables correction for gain and offset based on values of gain_correction and
+ * offset_correction if set to true
+ */
+ bool correction_enable;
+ /**
+ * This value defines how the ADC conversion result is compensated for gain
+ * error before written to the result register. This is a fractional value,
+ * 1-bit integer plus an 11-bit fraction, therefore
+ * 1/2 <= gain_correction < 2. Valid \c gain_correction values ranges from
+ * \c 0b010000000000 to \c 0b111111111111.
+ */
+ uint16_t gain_correction;
+ /**
+ * This value defines how the ADC conversion result is compensated for
+ * offset error before written to the result register. This is a 12-bit
+ * value in two's complement format.
+ */
+ int16_t offset_correction;
+};
+
+/**
+ * \brief Pin scan configuration structure
+ *
+ * Pin scan configuration structure. Part of the \ref adc_config struct and will
+ * be initialized by \ref adc_get_config_defaults.
+ */
+struct adc_pin_scan_config {
+ /**
+ * Offset (relative to selected positive input) of the first input pin to be
+ * used in pin scan mode
+ */
+ uint8_t offset_start_scan;
+ /**
+ * Number of input pins to scan in pin scan mode. A value below two will
+ * disable pin scan mode.
+ */
+ uint8_t inputs_to_scan;
+};
+
+/**
+ * \brief ADC configuration structure
+ *
+ * Configuration structure for an ADC instance. This structure should be
+ * initialized by the \ref adc_get_config_defaults()
+ * function before being modified by the user application.
+ */
+struct adc_config {
+ /** GCLK generator used to clock the peripheral */
+ enum gclk_generator clock_source;
+ /** Voltage reference */
+ enum adc_reference reference;
+ /** Clock prescaler */
+ enum adc_clock_prescaler clock_prescaler;
+ /** Result resolution */
+ enum adc_resolution resolution;
+ /** Gain factor */
+ enum adc_gain_factor gain_factor;
+ /** Positive Multiplexer (MUX) input */
+ enum adc_positive_input positive_input;
+ /** Negative MUX input. For singled-ended conversion mode, the negative
+ * input must be connected to ground. This ground could be the internal
+ * GND, IOGND or an external ground connected to a pin. */
+ enum adc_negative_input negative_input;
+ /** Number of ADC samples to accumulate when using the
+ * \c ADC_RESOLUTION_CUSTOM mode. Note: if the result width increases,
+ * result resolution will be changed accordingly.
+ */
+ enum adc_accumulate_samples accumulate_samples;
+ /** Division ration when using the ADC_RESOLUTION_CUSTOM mode */
+ enum adc_divide_result divide_result;
+ /** Left adjusted result */
+ bool left_adjust;
+ /** Enables differential mode if true.
+ * if false, ADC will run in singled-ended mode. */
+ bool differential_mode;
+ /** Enables free running mode if true */
+ bool freerunning;
+ /** Enables ADC in standby sleep mode if true */
+ bool run_in_standby;
+ /**
+ * Enables reference buffer offset compensation if true.
+ * This will increase the accuracy of the gain stage, but decreases the input
+ * impedance; therefore the startup time of the reference must be increased.
+ */
+ bool reference_compensation_enable;
+ /**
+ * This value (0-63) control the ADC sampling time in number of half ADC
+ * prescaled clock cycles (depends of \c ADC_PRESCALER value), thus
+ * controlling the ADC input impedance. Sampling time is set according to
+ * the formula:
+ * Sample time = (sample_length+1) * (ADCclk / 2).
+ */
+ uint8_t sample_length;
+ /** Window monitor configuration structure */
+ struct adc_window_config window;
+ /** Gain and offset correction configuration structure */
+ struct adc_correction_config correction;
+ /** Event action to take on incoming event */
+ enum adc_event_action event_action;
+ /** Pin scan configuration structure */
+ struct adc_pin_scan_config pin_scan;
+};
+
+/**
+ * \brief ADC software device instance structure.
+ *
+ * ADC software instance structure, used to retain software state information
+ * of an associated hardware module instance.
+ *
+ * \note The fields of this structure should not be altered by the user
+ * application; they are reserved for module-internal use only.
+ */
+struct adc_module {
+#if !defined(__DOXYGEN__)
+ /** Pointer to ADC hardware module */
+ Adc *hw;
+ /** Keep reference configuration so we know when enable is called */
+ enum adc_reference reference;
+# if ADC_CALLBACK_MODE == true
+ /** Array to store callback functions */
+ adc_callback_t callback[ADC_CALLBACK_N];
+ /** Pointer to buffer used for ADC results */
+ volatile uint16_t *job_buffer;
+ /** Remaining number of conversions in current job */
+ volatile uint16_t remaining_conversions;
+ /** Bit mask for callbacks registered */
+ uint8_t registered_callback_mask;
+ /** Bit mask for callbacks enabled */
+ uint8_t enabled_callback_mask;
+ /** Holds the status of the ongoing or last conversion job */
+ volatile enum status_code job_status;
+ /** If software triggering is needed */
+ bool software_trigger;
+# endif
+#endif
+};
+
+#if !defined(__DOXYGEN__)
+
+/**
+ * \brief Determines if the hardware module(s) are currently synchronizing to the bus.
+ *
+ * Checks to see if the underlying hardware peripheral module(s) are currently
+ * synchronizing across multiple clock domains to the hardware bus. This
+ * function can be used to delay further operations on a module until such time
+ * that it is ready, to prevent blocking delays for synchronization in the
+ * user application.
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ *
+ * \return Synchronization status of the underlying hardware module(s).
+ *
+ * \retval true if the module synchronization is ongoing
+ * \retval false if the module has completed synchronization
+ */
+static inline bool adc_is_syncing(
+ struct adc_module *const module_inst)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+
+ Adc *const adc_module = module_inst->hw;
+
+ if (adc_module->STATUS.reg & ADC_STATUS_SYNCBUSY) {
+ return true;
+ }
+
+ return false;
+}
+#endif
+
+/**
+ * \name ADC Gain and Pin Scan Mode
+ * @{
+ */
+
+/**
+ * \brief Sets ADC gain factor
+ *
+ * Sets the ADC gain factor to a specified gain setting.
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ * \param[in] gain_factor Gain factor value to set
+ */
+static inline void adc_set_gain(
+ struct adc_module *const module_inst,
+ const enum adc_gain_factor gain_factor)
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ Adc *const adc_module = module_inst->hw;
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+
+ /* Set new gain factor */
+ adc_module->INPUTCTRL.reg =
+ (adc_module->INPUTCTRL.reg & ~ADC_INPUTCTRL_GAIN_Msk) |
+ (gain_factor);
+}
+
+/**
+ * \brief Sets the ADC pin scan mode
+ *
+ * Configures the pin scan mode of the ADC module. In pin scan mode, the first
+ * conversion will start at the configured positive input + start_offset. When
+ * a conversion is done, a conversion will start on the next input, until
+ * \c inputs_to_scan number of conversions are made.
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ * \param[in] inputs_to_scan Number of input pins to perform a conversion on
+ * (must be two or more)
+ * \param[in] start_offset Offset of first pin to scan (relative to
+ * configured positive input)
+ *
+ * \return Status of the pin scan configuration set request.
+ *
+ * \retval STATUS_OK Pin scan mode has been set successfully
+ * \retval STATUS_ERR_INVALID_ARG Number of input pins to scan or offset has
+ * an invalid value
+ */
+static inline enum status_code adc_set_pin_scan_mode(
+ struct adc_module *const module_inst,
+ uint8_t inputs_to_scan,
+ const uint8_t start_offset)
+
+{
+ /* Sanity check arguments */
+ Assert(module_inst);
+ Assert(module_inst->hw);
+
+ Adc *const adc_module = module_inst->hw;
+
+ if (inputs_to_scan > 0) {
+ /*
+ * Number of input sources included is the value written to INPUTSCAN
+ * plus 1.
+ */
+ inputs_to_scan--;
+ }
+
+ if (inputs_to_scan > (ADC_INPUTCTRL_INPUTSCAN_Msk >> ADC_INPUTCTRL_INPUTSCAN_Pos) ||
+ start_offset > (ADC_INPUTCTRL_INPUTOFFSET_Msk >> ADC_INPUTCTRL_INPUTOFFSET_Pos)) {
+ /* Invalid number of input pins */
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+ while (adc_is_syncing(module_inst)) {
+ /* Wait for synchronization */
+ }
+
+ /* Set pin scan mode */
+ adc_module->INPUTCTRL.reg =
+ (adc_module->INPUTCTRL.reg &
+ ~(ADC_INPUTCTRL_INPUTSCAN_Msk | ADC_INPUTCTRL_INPUTOFFSET_Msk)) |
+ (start_offset << ADC_INPUTCTRL_INPUTOFFSET_Pos) |
+ (inputs_to_scan << ADC_INPUTCTRL_INPUTSCAN_Pos);
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Disables pin scan mode
+ *
+ * Disables pin scan mode. The next conversion will be made on only one pin
+ * (the configured positive input pin).
+ *
+ * \param[in] module_inst Pointer to the ADC software instance struct
+ */
+static inline void adc_disable_pin_scan_mode(
+ struct adc_module *const module_inst)
+{
+ /* Disable pin scan mode */
+ adc_set_pin_scan_mode(module_inst, 0, 0);
+}
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif /* ADC_FEATURE_H_INCLUDED */
+
diff --git a/atmel-samd/boards/arduino_zero/pins.c b/atmel-samd/boards/arduino_zero/pins.c
index fb255ef60..fb9794fa4 100644
--- a/atmel-samd/boards/arduino_zero/pins.c
+++ b/atmel-samd/boards/arduino_zero/pins.c
@@ -1,32 +1,25 @@
#include "pins.h"
#include "asf/sam0/drivers/system/system.h"
-#define PIN(p_name) \
-const pin_obj_t pin_## p_name = { \
- { &pin_type }, \
- .name = MP_QSTR_ ## p_name, \
- .pin = (PIN_## p_name), \
-}
-
-PIN(PA02);
-PIN(PB08);
-PIN(PB09);
-PIN(PA04);
-PIN(PA05);
-PIN(PB02);
-PIN(PA11);
-PIN(PA10);
-PIN(PA14);
-PIN(PA09);
-PIN(PA08);
-PIN(PA15);
-PIN(PA20);
-PIN(PA06);
-PIN(PA07);
-PIN(PA18);
-PIN(PA16);
-PIN(PA19);
-PIN(PA17);
+PIN(PA02, true, ADC_POSITIVE_INPUT_PIN0);
+PIN(PB08, true, ADC_POSITIVE_INPUT_PIN8);
+PIN(PB09, true, ADC_POSITIVE_INPUT_PIN9);
+PIN(PA04, true, ADC_POSITIVE_INPUT_PIN4);
+PIN(PA05, true, ADC_POSITIVE_INPUT_PIN5);
+PIN(PB02, true, ADC_POSITIVE_INPUT_PIN10);
+PIN(PA11, true, ADC_POSITIVE_INPUT_PIN19);
+PIN(PA10, true, ADC_POSITIVE_INPUT_PIN18);
+PIN(PA14, false, NO_ADC_INPUT);
+PIN(PA09, true, ADC_POSITIVE_INPUT_PIN17);
+PIN(PA08, true, ADC_POSITIVE_INPUT_PIN16);
+PIN(PA15, false, NO_ADC_INPUT);
+PIN(PA20, false, NO_ADC_INPUT);
+PIN(PA06, true, ADC_POSITIVE_INPUT_PIN6);
+PIN(PA07, true, ADC_POSITIVE_INPUT_PIN7);
+PIN(PA18, false, NO_ADC_INPUT);
+PIN(PA16, false, NO_ADC_INPUT);
+PIN(PA19, false, NO_ADC_INPUT);
+PIN(PA17, false, NO_ADC_INPUT);
STATIC const mp_map_elem_t pin_cpu_pins_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_PA02), (mp_obj_t)&pin_PA02 },
diff --git a/atmel-samd/boards/feather_m0_ble/pins.c b/atmel-samd/boards/feather_m0_ble/pins.c
index d487ac16f..991116031 100644
--- a/atmel-samd/boards/feather_m0_ble/pins.c
+++ b/atmel-samd/boards/feather_m0_ble/pins.c
@@ -1,33 +1,26 @@
#include "pins.h"
#include "asf/sam0/drivers/system/system.h"
-#define PIN(p_name) \
-const pin_obj_t pin_## p_name = { \
- { &pin_type }, \
- .name = MP_QSTR_ ## p_name, \
- .pin = (PIN_## p_name), \
-}
-
-PIN(PA02);
-PIN(PB08);
-PIN(PB09);
-PIN(PA04);
-PIN(PA05);
-PIN(PB02);
-PIN(PB11);
-PIN(PB10);
-PIN(PA12);
-PIN(PA11);
-PIN(PA10);
-PIN(PA22);
-PIN(PA23);
-PIN(PA15);
-PIN(PA20);
-PIN(PA07);
-PIN(PA18);
-PIN(PA16);
-PIN(PA19);
-PIN(PA17);
+PIN(PA02, true, ADC_POSITIVE_INPUT_PIN0);
+PIN(PB08, true, ADC_POSITIVE_INPUT_PIN8);
+PIN(PB09, true, ADC_POSITIVE_INPUT_PIN9);
+PIN(PA04, true, ADC_POSITIVE_INPUT_PIN4);
+PIN(PA05, true, ADC_POSITIVE_INPUT_PIN5);
+PIN(PB02, true, ADC_POSITIVE_INPUT_PIN10);
+PIN(PB11, false, NO_ADC_INPUT);
+PIN(PB10, false, NO_ADC_INPUT);
+PIN(PA12, false, NO_ADC_INPUT);
+PIN(PA11, true, ADC_POSITIVE_INPUT_PIN19);
+PIN(PA10, true, ADC_POSITIVE_INPUT_PIN18);
+PIN(PA22, false, NO_ADC_INPUT);
+PIN(PA23, false, NO_ADC_INPUT);
+PIN(PA15, false, NO_ADC_INPUT);
+PIN(PA20, false, NO_ADC_INPUT);
+PIN(PA07, true, ADC_POSITIVE_INPUT_PIN7);
+PIN(PA18, false, NO_ADC_INPUT);
+PIN(PA16, false, NO_ADC_INPUT);
+PIN(PA19, false, NO_ADC_INPUT);
+PIN(PA17, false, NO_ADC_INPUT);
STATIC const mp_map_elem_t pin_cpu_pins_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_PA02), (mp_obj_t)&pin_PA02 },
diff --git a/atmel-samd/modmachine.c b/atmel-samd/modmachine.c
index f2e1b6de1..1471ca981 100644
--- a/atmel-samd/modmachine.c
+++ b/atmel-samd/modmachine.c
@@ -31,12 +31,14 @@
#include "py/obj.h"
#include "py/runtime.h"
+#include "adc.h"
#include "pin.h"
#if MICROPY_PY_MACHINE
STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) },
+ { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&adc_type) },
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pin_type) },
};
diff --git a/atmel-samd/pin.h b/atmel-samd/pin.h
index 0c071c099..4a02f41db 100644
--- a/atmel-samd/pin.h
+++ b/atmel-samd/pin.h
@@ -27,8 +27,24 @@
#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_PIN_H__
#define __MICROPY_INCLUDED_ATMEL_SAMD_PIN_H__
-// This file requires pin_defs_xxx.h (which has port specific enums and
-// defines, so we include it here. It should never be included directly
+// Don't reorder these includes because they are dependencies of adc_feature.h.
+// They should really be included by adc_feature.h.
+#include "compiler.h"
+#include "asf/sam0/drivers/system/clock/gclk.h"
+#include "asf/sam0/utils/cmsis/samd21/include/component/adc.h"
+#include "asf/sam0/drivers/adc/adc_sam_d_r/adc_feature.h"
+
+// This macro is used to simplify pin definition in boards/<board>/pins.c
+#define PIN(p_name, p_has_adc, p_adc_input) \
+const pin_obj_t pin_## p_name = { \
+ { &pin_type }, \
+ .name = MP_QSTR_ ## p_name, \
+ .pin = (PIN_## p_name), \
+ .has_adc = p_has_adc, \
+ .adc_input = p_adc_input, \
+}
+
+#define NO_ADC_INPUT (0)
#include "mpconfigport.h"
@@ -38,6 +54,8 @@ typedef struct {
mp_obj_base_t base;
qstr name;
uint32_t pin;
+ bool has_adc;
+ enum adc_positive_input adc_input;
} pin_obj_t;
extern const mp_obj_type_t pin_type;