diff --git a/boards/arduino-due/Makefile.features b/boards/arduino-due/Makefile.features
index 1cfb85130405e07d3865bb9bbf061e222fef0002..6e911845de29d665510358375192784f5b53a21e 100644
--- a/boards/arduino-due/Makefile.features
+++ b/boards/arduino-due/Makefile.features
@@ -1,4 +1,5 @@
 # Put defined MCU peripherals here (in alphabetical order)
+FEATURES_PROVIDED += periph_adc
 FEATURES_PROVIDED += periph_cpuid
 FEATURES_PROVIDED += periph_gpio
 FEATURES_PROVIDED += periph_hwrng
diff --git a/cpu/sam3/include/periph_cpu.h b/cpu/sam3/include/periph_cpu.h
index 89b44b92c9a380f23b1b75afe0c81b94a5b4239a..117e772d385e9b36ecb4e47811d98b0b555f9613 100644
--- a/cpu/sam3/include/periph_cpu.h
+++ b/cpu/sam3/include/periph_cpu.h
@@ -80,6 +80,15 @@ typedef uint32_t gpio_t;
  */
 #define GPIO_MODE(io, pu, od)   (io | (pu << 1) | (od << 2))
 
+/**
+ * @name    ADC configuration, valid for all boards using this CPU
+ *
+ * The sam3 has a fixed mapping of ADC pins and a fixed number of ADC channels,
+ * so this ADC configuration is valid for all boards using this CPU. No need for
+ * any board specific configuration.
+ */
+#define ADC_NUMOF           (16U)
+
 #ifndef DOXYGEN
 /**
  * @brief   Override GPIO modes
@@ -154,6 +163,21 @@ typedef enum {
 } spi_clk_t;
 /** @} */
 
+/**
+ * @brief   Override ADC resolution values
+ * @{
+ */
+#define HAVE_ADC_RES_T
+typedef enum {
+    ADC_RES_6BIT  = 0x1,                    /**< not applicable */
+    ADC_RES_8BIT  = 0x2,                    /**< not applicable */
+    ADC_RES_10BIT = ADC_MR_LOWRES_BITS_10,  /**< ADC resolution: 10 bit */
+    ADC_RES_12BIT = ADC_MR_LOWRES_BITS_12,  /**< ADC resolution: 12 bit */
+    ADC_RES_14BIT = 0x4,                    /**< not applicable */
+    ADC_RES_16BIT = 0x8                     /**< not applicable */
+} adc_res_t;
+/** @} */
+
 /**
  * @brief   Timer configuration data
  */
diff --git a/cpu/sam3/periph/adc.c b/cpu/sam3/periph/adc.c
new file mode 100644
index 0000000000000000000000000000000000000000..1c2651e6704a5b6553b6f0dcd9a2798e4b0f9c37
--- /dev/null
+++ b/cpu/sam3/periph/adc.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 Freie Universität Berlin
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     cpu_sam3
+ * @{
+ *
+ * @file
+ * @brief       Low-level ADC driver implementation
+ *
+ * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ *
+ * @}
+ */
+
+#include <stdio.h>
+
+
+#include "mutex.h"
+#include "periph/adc.h"
+
+#define RES_INVALID         (0x0f)
+#define WP_KEY              (0x414443)
+#define PMC_BIT             (1 << (ID_ADC - 32))
+
+/* max ADC clock is 6.4MHz, we aim for 5MHz per default */
+#ifndef ADC_CLOCK_TARGET
+#define ADC_CLOCK_TARGET    (5000000)
+#endif
+#define PRESCALER           ((CLOCK_CORECLOCK / (2 * ADC_CLOCK_TARGET)) - 1)
+
+
+static mutex_t lock = MUTEX_INIT;
+
+static inline void use(void)
+{
+    mutex_lock(&lock);
+    PMC->PMC_PCER1 = PMC_BIT;
+}
+
+static inline void done(void)
+{
+    PMC->PMC_PCDR1 = PMC_BIT;
+    mutex_unlock(&lock);
+}
+
+int adc_init(adc_t line)
+{
+    assert(line < ADC_NUMOF);
+
+    use();
+
+    /* disable ADC write protection */
+    ADC->ADC_WPMR = ADC_WPMR_WPKEY(WP_KEY);
+    ADC->ADC_CHDR = 0x0000ffff;
+
+    /* if line 15 is used, enable the temperature sensor */
+    if (line == 15) {
+        ADC->ADC_ACR |= ADC_ACR_TSON;
+    }
+
+    done();
+    return 0;
+}
+
+int adc_sample(adc_t line, adc_res_t res)
+{
+    assert(line < ADC_NUMOF);
+
+    /* check if resolution is applicable */
+    if (res & RES_INVALID) {
+        return -1;
+    }
+
+    use();
+
+    /* set resolution */
+    ADC->ADC_MR = (res | ADC_MR_PRESCAL(PRESCALER));
+    /* enable channel */
+    ADC->ADC_CHER = (1 << line);
+
+    /* start conversion */
+    ADC->ADC_CR = ADC_CR_START;
+    /* wait for result */
+    while (!(ADC->ADC_ISR & ADC_ISR_DRDY)) {}
+    /* read result */
+    int sample = (int)(ADC->ADC_LCDR & ADC_LCDR_LDATA_Msk);
+
+    /* disable channel */
+    ADC->ADC_CHDR = (1 << line);
+
+    done();
+    return sample;
+}