diff --git a/cpu/nrf51/include/periph_cpu.h b/cpu/nrf51/include/periph_cpu.h
index 251bd319c7166af7f5b2e14b8fc4c46791740e84..e4eac37287f73bdedd3eb4681e32a8e0d7dd014a 100644
--- a/cpu/nrf51/include/periph_cpu.h
+++ b/cpu/nrf51/include/periph_cpu.h
@@ -54,6 +54,21 @@ typedef enum {
 } i2c_speed_t;
 /** @} */
 
+/**
+ * @brief   Override ADC resolution values
+ * @{
+ */
+#define HAVE_ADC_RES_T
+typedef enum {
+    ADC_RES_6BIT  = 0xf0,   /**< ADC resolution: 6 bit */
+    ADC_RES_8BIT  = 0x00,   /**< ADC resolution: 8 bit */
+    ADC_RES_10BIT = 0x02,   /**< ADC resolution: 10 bit */
+    ADC_RES_12BIT = 0xf1,   /**< ADC resolution: 12 bit */
+    ADC_RES_14BIT = 0xf2,   /**< ADC resolution: 14 bit */
+    ADC_RES_16BIT = 0xf3    /**< ADC resolution: 16 bit */
+} adc_res_t;
+/** @} */
+
 /**
  * @brief   I2C (TWI) configuration options
  */
diff --git a/cpu/nrf52/include/periph_cpu.h b/cpu/nrf52/include/periph_cpu.h
index 38c7726fc95c6637cac5abcf571664fafd3d83d5..9b8adc33abcb4f227c4e6435c3704a539f393853 100644
--- a/cpu/nrf52/include/periph_cpu.h
+++ b/cpu/nrf52/include/periph_cpu.h
@@ -40,6 +40,30 @@ extern "C" {
 #define SPI_MISOSEL         (dev(bus)->PSEL.MISO)
 /** @} */
 
+/**
+ * @brief   Override ADC resolution values
+ * @{
+ */
+#define HAVE_ADC_RES_T
+typedef enum {
+    ADC_RES_6BIT  = 0xf0,   /**< not supported by hardware */
+    ADC_RES_8BIT  = 0x00,   /**< ADC resolution: 8 bit */
+    ADC_RES_10BIT = 0x01,   /**< ADC resolution: 10 bit */
+    ADC_RES_12BIT = 0x02,   /**< ADC resolution: 12 bit */
+    ADC_RES_14BIT = 0xf1,   /**< supported with oversampling */
+    ADC_RES_16BIT = 0xf2    /**< not supported by hardware */
+} adc_res_t;
+/** @} */
+
+/**
+ * @name    ADC configuration, valid for all boards using this CPU
+ *
+ * The NRF52832 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           (8U)
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/cpu/nrf52/periph/adc.c b/cpu/nrf52/periph/adc.c
new file mode 100644
index 0000000000000000000000000000000000000000..42b3043b7fefb8e1c9dbb3e5ca921c329ffc689a
--- /dev/null
+++ b/cpu/nrf52/periph/adc.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2017 HAW Hamburg
+ *
+ * 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_nrf52
+ * @{
+ *
+ * Any one of the available channels can be enabled for the ADC to operate in
+ * one-shot mode. If more than one CH[n] is configured, the ADC enters scan mode.
+ *
+ * Example of RAM placement (RESULT.MAXCNT = 8), all channels enabled:
+ *
+ *                           31    16 15     0
+ * RESULT.PTR = adc_val[0]   | CH[1] | CH[0] |
+ * RESULT.PTR + 4            | CH[3] | CH[2] |
+ * RESULT.PTR + 8            | CH[5] | CH[4] |
+ * RESULT.PTR + 12           | CH[7] | CH[6] |
+ *
+ * Example of RAM placement (RESULT.MAXCNT = 4), channels 0, 3, 4 and 7 enabled:
+ *
+ *                           31    16 15     0
+ * RESULT.PTR = adc_val[0]   | CH[3] | CH[0] |
+ * RESULT.PTR + 4            | CH[7] | CH[4] |
+ * RESULT.PTR + 8            |       |       |
+ * RESULT.PTR + 12           |       |       |
+ *
+ * Scan mode and oversampling cannot be combined.
+ * -> 8/10/12-bit resolution, 14-bit resolution only with oversampling
+ *
+ * @file
+ * @brief       Low-level ADC driver implementation
+ *
+ * @author      Dimitri Nahm <dimitri.nahm@haw-hamburg.de>
+ *
+ * @}
+ */
+
+#include "cpu.h"
+#include "mutex.h"
+#include "periph/adc.h"
+#include "periph_conf.h"
+
+#ifdef ADC_NUMOF
+
+static int16_t adc_val[ADC_NUMOF];
+static uint8_t adc_ch_enabled = 0;
+static uint8_t adc_return_idx;
+
+/**
+ * @brief   Lock to prevent concurrency issues when used from different threads
+ */
+static mutex_t lock;
+
+static inline void prep(void)
+{
+    mutex_lock(&lock);
+    NRF_SAADC->ENABLE = 1;
+}
+
+static inline void done(void)
+{
+    NRF_SAADC->ENABLE = 0;
+    mutex_unlock(&lock);
+}
+
+int adc_init(adc_t line)
+{
+    if (line >= ADC_NUMOF) {
+        return -1;
+    }
+
+    if ((adc_ch_enabled & (1 << line)) == 0) {
+        /* prepare device */
+        prep();
+
+        /* set the number of enabled channels and the data pointer */
+        NRF_SAADC->RESULT.MAXCNT += 1;
+        NRF_SAADC->RESULT.PTR = (uint32_t)&adc_val;
+
+        /* set ADC channel and use VDD (+5V) as reference */
+        NRF_SAADC->CH[line].PSELP = line + 1;
+        NRF_SAADC->CH[line].CONFIG = (SAADC_CH_CONFIG_GAIN_Gain1_4 << SAADC_CH_CONFIG_RESN_Pos) |
+                                  (SAADC_CH_CONFIG_REFSEL_VDD1_4 << SAADC_CH_CONFIG_REFSEL_Pos);
+
+        /* calibrate the SAADC */
+        NRF_SAADC->EVENTS_CALIBRATEDONE = 0;
+        NRF_SAADC->TASKS_CALIBRATEOFFSET = 1;
+        while (NRF_SAADC->EVENTS_CALIBRATEDONE == 0) {}
+
+        /* remember which ADC channel is enabled */
+        adc_ch_enabled |= (1 << line);
+
+        /* free device */
+        done();
+    }
+
+    return 0;
+}
+
+int adc_sample(adc_t line, adc_res_t res)
+{
+    assert(line < ADC_NUMOF);
+
+    /* check if resolution is valid */
+    if (res > 2) {
+        return -1;
+    }
+
+    /* prepare device */
+    prep();
+
+    /* set resolution */
+    NRF_SAADC->RESOLUTION = res;
+
+    /* start the SAADC and wait for the started event */
+    NRF_SAADC->EVENTS_STARTED = 0;
+    NRF_SAADC->TASKS_START = 1;
+    while (NRF_SAADC->EVENTS_STARTED == 0) {}
+
+    /* start conversions and wait for conversions to be complete */
+    for (uint8_t i = 0; i < NRF_SAADC->RESULT.MAXCNT; i++) {
+        while (NRF_SAADC->STATUS == (SAADC_STATUS_STATUS_Busy << SAADC_STATUS_STATUS_Pos)) {}
+        NRF_SAADC->EVENTS_DONE = 0;
+        NRF_SAADC->TASKS_SAMPLE = 1;
+        while (NRF_SAADC->EVENTS_DONE == 0) {}
+    }
+
+    /* stop the SAADC */
+    NRF_SAADC->EVENTS_STOPPED = 0;
+    NRF_SAADC->TASKS_STOP = 1;
+    while (NRF_SAADC->EVENTS_STOPPED == 0) {}
+
+    /* free device */
+    done();
+
+    /* return the ADC value for the given line */
+    adc_return_idx = 0;
+    for (uint8_t i = 0; i < line; i++) {
+        if (adc_ch_enabled & (1 << i)) {
+            adc_return_idx++;
+        }
+    }
+    if (adc_val[adc_return_idx] < 0) {
+        return 0;
+    }
+    return adc_val[adc_return_idx];
+}
+
+#else
+typedef int dont_be_pedantic;
+#endif /* ADC_CONFIG */
diff --git a/cpu/nrf5x_common/include/periph_cpu_common.h b/cpu/nrf5x_common/include/periph_cpu_common.h
index 78d1ab0491bc050bc2cc63fe8142d0f12edecafd..608883c8e6a8f53379826f81b44b84b17edafa08 100644
--- a/cpu/nrf5x_common/include/periph_cpu_common.h
+++ b/cpu/nrf5x_common/include/periph_cpu_common.h
@@ -109,21 +109,6 @@ typedef enum {
     GPIO_BOTH    = 3        /**< emit interrupt on both flanks */
 } gpio_flank_t;
 /** @} */
-
-/**
- * @brief   Override ADC resolution values
- * @{
- */
-#define HAVE_ADC_RES_T
-typedef enum {
-    ADC_RES_6BIT  = 0xf0,   /**< ADC resolution: 6 bit */
-    ADC_RES_8BIT  = 0x00,   /**< ADC resolution: 8 bit */
-    ADC_RES_10BIT = 0x02,   /**< ADC resolution: 10 bit */
-    ADC_RES_12BIT = 0xf1,   /**< ADC resolution: 12 bit */
-    ADC_RES_14BIT = 0xf2,   /**< ADC resolution: 14 bit */
-    ADC_RES_16BIT = 0xf3    /**< ADC resolution: 16 bit */
-} adc_res_t;
-/** @} */
 #endif /* ndef DOXYGEN */
 
 /**