From 9de00af0635d3804a644bd497b01e65ad7b0cd08 Mon Sep 17 00:00:00 2001
From: Laurent Navet <laurent.navet@gmail.com>
Date: Wed, 15 Feb 2017 21:28:10 +0100
Subject: [PATCH] cpu/atmega_common: add adc driver

---
 .../arduino-atmega-common/Makefile.features   |   1 +
 .../include/arduino_board.h                   |  24 +++
 .../include/arduino_pinmap.h                  |  23 ++-
 .../include/periph_conf.h                     |  24 ++-
 boards/arduino-due/include/arduino_board.h    |  18 +++
 .../include/arduino_board.h                   |  13 ++
 .../include/arduino_pinmap.h                  |  14 ++
 boards/arduino-zero/include/arduino_board.h   |  12 ++
 boards/arduino-zero/include/arduino_pinmap.h  |  13 ++
 boards/nucleo-common/include/arduino_board.h  |  12 ++
 boards/nucleo-common/include/arduino_pinmap.h |  13 ++
 .../nucleo144-common/include/arduino_board.h  |  12 ++
 .../nucleo144-common/include/arduino_pinmap.h |  13 ++
 .../nucleo32-common/include/arduino_board.h   |  14 ++
 .../nucleo32-common/include/arduino_pinmap.h  |  16 +-
 .../stm32f4discovery/include/arduino_board.h  |  28 ++--
 .../stm32f4discovery/include/arduino_pinmap.h |  61 ++++++++
 boards/waspmote-pro/Makefile.features         |   1 +
 boards/waspmote-pro/include/periph_conf.h     |  11 +-
 cpu/atmega_common/periph/adc.c                | 143 ++++++++++++++++++
 sys/arduino/base.cpp                          |  32 ++++
 sys/arduino/include/arduino.hpp               |  10 ++
 22 files changed, 495 insertions(+), 13 deletions(-)
 create mode 100644 boards/stm32f4discovery/include/arduino_pinmap.h
 create mode 100644 cpu/atmega_common/periph/adc.c

diff --git a/boards/arduino-atmega-common/Makefile.features b/boards/arduino-atmega-common/Makefile.features
index 92b1f77884..7b4cdf7eb9 100644
--- a/boards/arduino-atmega-common/Makefile.features
+++ b/boards/arduino-atmega-common/Makefile.features
@@ -1,4 +1,5 @@
 # Put defined MCU peripherals here (in alphabetical order)
+FEATURES_PROVIDED += periph_adc
 FEATURES_PROVIDED += periph_gpio
 FEATURES_PROVIDED += periph_i2c
 FEATURES_PROVIDED += periph_spi
diff --git a/boards/arduino-atmega-common/include/arduino_board.h b/boards/arduino-atmega-common/include/arduino_board.h
index 3a8d7b958e..de5c4c82df 100644
--- a/boards/arduino-atmega-common/include/arduino_board.h
+++ b/boards/arduino-atmega-common/include/arduino_board.h
@@ -109,6 +109,30 @@ static const gpio_t arduino_pinmap[] = {
 #endif
 };
 
+/**
+ * @brief   Look-up table for the Arduino's analog pins
+ */
+static const adc_t arduino_analog_map[] = {
+    ARDUINO_A0,
+    ARDUINO_A1,
+    ARDUINO_A2,
+    ARDUINO_A3,
+    ARDUINO_A4,
+    ARDUINO_A5,
+    ARDUINO_A6,
+    ARDUINO_A7,
+#ifdef CPU_ATMEGA2560
+    ARDUINO_A8,
+    ARDUINO_A9,
+    ARDUINO_A10,
+    ARDUINO_A11,
+    ARDUINO_A12,
+    ARDUINO_A13,
+    ARDUINO_A14,
+    ARDUINO_A15,
+#endif
+};
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/arduino-atmega-common/include/arduino_pinmap.h b/boards/arduino-atmega-common/include/arduino_pinmap.h
index feac1c5bc2..842a2d72bd 100644
--- a/boards/arduino-atmega-common/include/arduino_pinmap.h
+++ b/boards/arduino-atmega-common/include/arduino_pinmap.h
@@ -25,6 +25,9 @@
 #ifndef ARDUINO_PINMAP_H
 #define ARDUINO_PINMAP_H
 
+#include "periph/gpio.h"
+#include "periph/adc.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -155,9 +158,27 @@ extern "C" {
 #define ARDUINO_PIN_A14         ARDUINO_PIN_68
 #define ARDUINO_PIN_A15         ARDUINO_PIN_69
 #endif
-
 /** @ */
 
+#define ARDUINO_A0              ADC_LINE(0)
+#define ARDUINO_A1              ADC_LINE(1)
+#define ARDUINO_A2              ADC_LINE(2)
+#define ARDUINO_A3              ADC_LINE(3)
+#define ARDUINO_A4              ADC_LINE(4)
+#define ARDUINO_A5              ADC_LINE(5)
+#define ARDUINO_A6              ADC_LINE(6)
+#define ARDUINO_A7              ADC_LINE(7)
+#ifdef CPU_ATMEGA2560
+#define ARDUINO_A8              ADC_LINE(8)
+#define ARDUINO_A9              ADC_LINE(9)
+#define ARDUINO_A10             ADC_LINE(10)
+#define ARDUINO_A11             ADC_LINE(11)
+#define ARDUINO_A12             ADC_LINE(12)
+#define ARDUINO_A13             ADC_LINE(13)
+#define ARDUINO_A14             ADC_LINE(14)
+#define ARDUINO_A15             ADC_LINE(15)
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/arduino-atmega-common/include/periph_conf.h b/boards/arduino-atmega-common/include/periph_conf.h
index af5e5bdcbe..4a1681fde3 100644
--- a/boards/arduino-atmega-common/include/periph_conf.h
+++ b/boards/arduino-atmega-common/include/periph_conf.h
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2014 Freie Universität Berlin, Hinnerk van Bruinehsen
  *               2016 Laurent Navet <laurent.navet@gmail.com>
+ *               2017 HAW Hamburg, Dimitri Nahm
  *
  * 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
@@ -17,6 +18,7 @@
  * @author      Hinnerk van Bruinehsen <h.v.bruinehsen@fu-berlin.de>
  * @author      Laurent Navet <laurent.navet@gmail.com>
  * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
+ * @author      Dimitri Nahm <dimitri.nahm@haw-hamburg.de>
  */
 
 #ifndef PERIPH_CONF_H
@@ -136,9 +138,29 @@ extern "C" {
 /** @} */
 
 /**
- * @brief    I2C configuration
+ * @name    I2C configuration
+ * @{
  */
 #define I2C_NUMOF           1
+/** @} */
+
+/**
+ * @name    ADC configuration
+ *
+ * The number of ADC channels of the atmega328p depends on the package:
+ *  - 6-channel 10-bit ADC in PDIP package
+ *  - 8-channel 10-bit ADC in TQFP and QFN/MLF package
+ * Arduino UNO / Duemilanove has thereby 6 channels. But only 5 channels can be
+ * used for ADC, because the pin of ADC5 emulate a software triggered interrupt.
+ *  -> boards -> arduino-atmega-common -> include -> board_common.h
+ * @{
+ */
+#if defined (CPU_ATMEGA328P) || defined (CPU_ATMEGA1281)
+#define ADC_NUMOF       (8U)
+#elif defined (CPU_ATMEGA2560)
+#define ADC_NUMOF       (16U)
+#endif
+/** @} */
 
 #ifdef __cplusplus
 }
diff --git a/boards/arduino-due/include/arduino_board.h b/boards/arduino-due/include/arduino_board.h
index 2a08f2c4f4..e9a8657351 100644
--- a/boards/arduino-due/include/arduino_board.h
+++ b/boards/arduino-due/include/arduino_board.h
@@ -115,6 +115,24 @@ static const gpio_t arduino_pinmap[] = {
     ARDUINO_PIN_78,
 };
 
+/**
+ * @brief   Look-up table for the Arduino's analog pins
+ */
+static const adc_t arduino_analog_map[] = {
+    ARDUINO_A0,
+    ARDUINO_A1,
+    ARDUINO_A2,
+    ARDUINO_A3,
+    ARDUINO_A4,
+    ARDUINO_A5,
+    ARDUINO_A6,
+    ARDUINO_A7,
+    ARDUINO_A8,
+    ARDUINO_A9,
+    ARDUINO_A10,
+    ARDUINO_A11,
+};
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/arduino-mkr-common/include/arduino_board.h b/boards/arduino-mkr-common/include/arduino_board.h
index 9d7325eac8..41c8fc8796 100644
--- a/boards/arduino-mkr-common/include/arduino_board.h
+++ b/boards/arduino-mkr-common/include/arduino_board.h
@@ -55,6 +55,19 @@ static const gpio_t arduino_pinmap[] = {
     ARDUINO_PIN_A6,
 };
 
+/**
+ * @brief   Look-up table for the Arduino's analog pins
+ */
+static const adc_t arduino_analog_map[] = {
+    ARDUINO_A0,
+    ARDUINO_A1,
+    ARDUINO_A2,
+    ARDUINO_A3,
+    ARDUINO_A4,
+    ARDUINO_A5,
+    ARDUINO_A6,
+};
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/arduino-mkr-common/include/arduino_pinmap.h b/boards/arduino-mkr-common/include/arduino_pinmap.h
index 7a869771df..b48a11f886 100644
--- a/boards/arduino-mkr-common/include/arduino_pinmap.h
+++ b/boards/arduino-mkr-common/include/arduino_pinmap.h
@@ -23,6 +23,7 @@
 #define ARDUINO_PINMAP_H
 
 #include "periph/gpio.h"
+#include "periph/adc.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -58,6 +59,19 @@ extern "C" {
 #define ARDUINO_PIN_A6          GPIO_PIN(PA, 7)  /* AIN7 */
 /** @} */
 
+/**
+ * @name    Mapping of Ardunino analog pins to RIOT ADC lines
+ * @{
+ */
+#define ARDUINO_A0              ADC_LINE(0)
+#define ARDUINO_A1              ADC_LINE(1)
+#define ARDUINO_A2              ADC_LINE(2)
+#define ARDUINO_A3              ADC_LINE(3)
+#define ARDUINO_A4              ADC_LINE(4)
+#define ARDUINO_A5              ADC_LINE(5)
+#define ARDUINO_A6              ADC_LINE(6)
+/** @} */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/arduino-zero/include/arduino_board.h b/boards/arduino-zero/include/arduino_board.h
index 620a6cebe7..ece5c3b1cf 100644
--- a/boards/arduino-zero/include/arduino_board.h
+++ b/boards/arduino-zero/include/arduino_board.h
@@ -58,6 +58,18 @@ static const gpio_t arduino_pinmap[] = {
     ARDUINO_PIN_A5,
 };
 
+/**
+ * @brief   Look-up table for the Arduino's analog pins
+ */
+static const adc_t arduino_analog_map[] = {
+    ARDUINO_A0,
+    ARDUINO_A1,
+    ARDUINO_A2,
+    ARDUINO_A3,
+    ARDUINO_A4,
+    ARDUINO_A5,
+};
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/arduino-zero/include/arduino_pinmap.h b/boards/arduino-zero/include/arduino_pinmap.h
index 77d7310fbb..d8ae6f0c1a 100644
--- a/boards/arduino-zero/include/arduino_pinmap.h
+++ b/boards/arduino-zero/include/arduino_pinmap.h
@@ -23,6 +23,7 @@
 #define ARDUINO_PINMAP_H
 
 #include "periph/gpio.h"
+#include "periph/adc.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -56,6 +57,18 @@ extern "C" {
 #define ARDUINO_PIN_A5          GPIO_PIN(PB, 2)
 /** @ */
 
+/**
+ * @name    Mapping of Ardunino analog pins to RIOT ADC lines
+ * @{
+ */
+#define ARDUINO_A0              ADC_LINE(0)
+#define ARDUINO_A1              ADC_LINE(1)
+#define ARDUINO_A2              ADC_LINE(2)
+#define ARDUINO_A3              ADC_LINE(3)
+#define ARDUINO_A4              ADC_LINE(4)
+#define ARDUINO_A5              ADC_LINE(5)
+/** @} */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/nucleo-common/include/arduino_board.h b/boards/nucleo-common/include/arduino_board.h
index fe2e0232ff..2cdd599e2d 100644
--- a/boards/nucleo-common/include/arduino_board.h
+++ b/boards/nucleo-common/include/arduino_board.h
@@ -58,6 +58,18 @@ static const gpio_t arduino_pinmap[] = {
     ARDUINO_PIN_A5,
 };
 
+/**
+ * @brief   Look-up table for the Arduino's analog pins
+ */
+static const adc_t arduino_analog_map[] = {
+    ARDUINO_A0,
+    ARDUINO_A1,
+    ARDUINO_A2,
+    ARDUINO_A3,
+    ARDUINO_A4,
+    ARDUINO_A5,
+};
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/nucleo-common/include/arduino_pinmap.h b/boards/nucleo-common/include/arduino_pinmap.h
index 86752c71c6..75bd8aa18c 100644
--- a/boards/nucleo-common/include/arduino_pinmap.h
+++ b/boards/nucleo-common/include/arduino_pinmap.h
@@ -23,6 +23,7 @@
 #define ARDUINO_PINMAP_H
 
 #include "periph/gpio.h"
+#include "periph/adc.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -64,6 +65,18 @@ extern "C" {
 #define ARDUINO_PIN_A5          GPIO_PIN(PORT_C, 0)
 /** @ */
 
+/**
+ * @name    Mapping of Ardunino analog pins to RIOT ADC lines
+ * @{
+ */
+#define ARDUINO_A0              ADC_LINE(0)
+#define ARDUINO_A1              ADC_LINE(1)
+#define ARDUINO_A2              ADC_LINE(2)
+#define ARDUINO_A3              ADC_LINE(3)
+#define ARDUINO_A4              ADC_LINE(4)
+#define ARDUINO_A5              ADC_LINE(5)
+/** @} */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/nucleo144-common/include/arduino_board.h b/boards/nucleo144-common/include/arduino_board.h
index 7d20e8b573..3dae69fc9d 100644
--- a/boards/nucleo144-common/include/arduino_board.h
+++ b/boards/nucleo144-common/include/arduino_board.h
@@ -53,6 +53,18 @@ static const gpio_t arduino_pinmap[] = {
     ARDUINO_PIN_A5,
 };
 
+/**
+ * @brief   Look-up table for the Arduino's analog pins
+ */
+static const adc_t arduino_analog_map[] = {
+    ARDUINO_A0,
+    ARDUINO_A1,
+    ARDUINO_A2,
+    ARDUINO_A3,
+    ARDUINO_A4,
+    ARDUINO_A5,
+};
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/nucleo144-common/include/arduino_pinmap.h b/boards/nucleo144-common/include/arduino_pinmap.h
index 80d4c5a436..aceb56dbb1 100644
--- a/boards/nucleo144-common/include/arduino_pinmap.h
+++ b/boards/nucleo144-common/include/arduino_pinmap.h
@@ -23,6 +23,7 @@
 #define ARDUINO_PINMAP_H
 
 #include "periph/gpio.h"
+#include "periph/adc.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -74,6 +75,18 @@ extern "C" {
 #endif
 /** @ */
 
+/**
+ * @name    Mapping of Ardunino analog pins to RIOT ADC lines
+ * @{
+ */
+#define ARDUINO_A0              ADC_LINE(0)
+#define ARDUINO_A1              ADC_LINE(1)
+#define ARDUINO_A2              ADC_LINE(2)
+#define ARDUINO_A3              ADC_LINE(3)
+#define ARDUINO_A4              ADC_LINE(4)
+#define ARDUINO_A5              ADC_LINE(5)
+/** @} */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/nucleo32-common/include/arduino_board.h b/boards/nucleo32-common/include/arduino_board.h
index 2f2b5e3f3d..3d0f7bac0e 100644
--- a/boards/nucleo32-common/include/arduino_board.h
+++ b/boards/nucleo32-common/include/arduino_board.h
@@ -58,6 +58,20 @@ static const gpio_t arduino_pinmap[] = {
     ARDUINO_PIN_A7
 };
 
+/**
+ * @brief   Look-up table for the Arduino's analog pins
+ */
+static const adc_t arduino_analog_map[] = {
+    ARDUINO_A0,
+    ARDUINO_A1,
+    ARDUINO_A2,
+    ARDUINO_A3,
+    ARDUINO_A4,
+    ARDUINO_A5,
+    ARDUINO_A6,
+    ARDUINO_A7,
+};
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/nucleo32-common/include/arduino_pinmap.h b/boards/nucleo32-common/include/arduino_pinmap.h
index 7b7db79fef..fa2ce17278 100644
--- a/boards/nucleo32-common/include/arduino_pinmap.h
+++ b/boards/nucleo32-common/include/arduino_pinmap.h
@@ -23,7 +23,7 @@
 #define ARDUINO_PINMAP_H
 
 #include "periph/gpio.h"
-
+#include "periph/adc.h"
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -63,6 +63,20 @@ extern "C" {
 #define ARDUINO_PIN_A7          GPIO_PIN(PORT_A, 2)
 /** @ */
 
+/**
+ * @name    Mapping of Ardunino analog pins to RIOT ADC lines
+ * @{
+ */
+#define ARDUINO_A0              ADC_LINE(0)
+#define ARDUINO_A1              ADC_LINE(1)
+#define ARDUINO_A2              ADC_LINE(2)
+#define ARDUINO_A3              ADC_LINE(3)
+#define ARDUINO_A4              ADC_LINE(4)
+#define ARDUINO_A5              ADC_LINE(5)
+#define ARDUINO_A6              ADC_LINE(6)
+#define ARDUINO_A7              ADC_LINE(7)
+/** @} */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/stm32f4discovery/include/arduino_board.h b/boards/stm32f4discovery/include/arduino_board.h
index dd0a3169b0..1376f9bd9a 100644
--- a/boards/stm32f4discovery/include/arduino_board.h
+++ b/boards/stm32f4discovery/include/arduino_board.h
@@ -19,7 +19,7 @@
 #ifndef ARDUINO_BOARD_H
 #define ARDUINO_BOARD_H
 
-#include "periph/gpio.h"
+#include "arduino_pinmap.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -28,14 +28,24 @@ extern "C" {
 #define ARDUINO_LED         (2)
 
 static const gpio_t arduino_pinmap[] = {
-    GPIO_PIN(PORT_D, 12),
-    GPIO_PIN(PORT_D, 13),
-    GPIO_PIN(PORT_D, 14),
-    GPIO_PIN(PORT_D, 15),
-    GPIO_PIN(PORT_A, 12),
-    GPIO_PIN(PORT_A, 15),
-    GPIO_PIN(PORT_B, 1),
-    GPIO_PIN(PORT_B, 2),
+    ARDUINO_PIN_0,
+    ARDUINO_PIN_1,
+    ARDUINO_PIN_2,
+    ARDUINO_PIN_3,
+    ARDUINO_PIN_4,
+    ARDUINO_PIN_5,
+    ARDUINO_PIN_6,
+    ARDUINO_PIN_7,
+};
+
+/**
+ * @brief   Look-up table for the Arduino's analog pins
+ */
+static const adc_t arduino_analog_map[] = {
+    ARDUINO_A0,
+    ARDUINO_A1,
+    ARDUINO_A2,
+    ARDUINO_A3,
 };
 
 #ifdef __cplusplus
diff --git a/boards/stm32f4discovery/include/arduino_pinmap.h b/boards/stm32f4discovery/include/arduino_pinmap.h
new file mode 100644
index 0000000000..dfa24aac6b
--- /dev/null
+++ b/boards/stm32f4discovery/include/arduino_pinmap.h
@@ -0,0 +1,61 @@
+/*
+ * 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     boards_stm32f4discovery
+ * @{
+ *
+ * @file
+ * @brief       Mapping from MCU pins to Arduino pins
+ *
+ * You can use the defines in this file for simplified interaction with the
+ * Arduino specific pin numbers.
+ *
+ * @author      Sebastian Meiling <s@mlng.net>
+ */
+
+#ifndef ARDUINO_PINMAP_H
+#define ARDUINO_PINMAP_H
+
+#include "periph/gpio.h"
+#include "periph/adc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name   Mapping of MCU pins to Arduino pins
+ * @{
+ */
+#define ARDUINO_PIN_0           GPIO_PIN(PORT_D, 12)
+#define ARDUINO_PIN_1           GPIO_PIN(PORT_D, 13)
+#define ARDUINO_PIN_2           GPIO_PIN(PORT_D, 14)
+#define ARDUINO_PIN_3           GPIO_PIN(PORT_D, 15)
+#define ARDUINO_PIN_4           GPIO_PIN(PORT_A, 12)
+#define ARDUINO_PIN_5           GPIO_PIN(PORT_A, 15)
+#define ARDUINO_PIN_6           GPIO_PIN(PORT_B, 1)
+#define ARDUINO_PIN_7           GPIO_PIN(PORT_B, 2)
+/** @ */
+
+/**
+ * @name    Mapping of Ardunino analog pins to RIOT ADC lines
+ * @{
+ */
+#define ARDUINO_A0              ADC_LINE(0)
+#define ARDUINO_A1              ADC_LINE(1)
+#define ARDUINO_A2              ADC_LINE(2)
+#define ARDUINO_A3              ADC_LINE(3)
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ARDUINO_PINMAP_H */
+/** @} */
diff --git a/boards/waspmote-pro/Makefile.features b/boards/waspmote-pro/Makefile.features
index 4e3851d2b6..abcd9925d9 100644
--- a/boards/waspmote-pro/Makefile.features
+++ b/boards/waspmote-pro/Makefile.features
@@ -1,4 +1,5 @@
 # Put defined MCU peripherals here (in alphabetical order)
+FEATURES_PROVIDED += periph_adc
 FEATURES_PROVIDED += periph_gpio
 FEATURES_PROVIDED += periph_i2c
 FEATURES_PROVIDED += periph_spi
diff --git a/boards/waspmote-pro/include/periph_conf.h b/boards/waspmote-pro/include/periph_conf.h
index 8c2476c53d..dd97b1ecc3 100644
--- a/boards/waspmote-pro/include/periph_conf.h
+++ b/boards/waspmote-pro/include/periph_conf.h
@@ -104,9 +104,18 @@ extern "C" {
 /** @} */
 
 /**
- * @brief    I2C configuration
+ * @name    I2C configuration
+ * @{
  */
 #define I2C_NUMOF           1
+/** @} */
+
+/**
+ * @name     ADC configuration
+ * @{
+ */
+#define ADC_NUMOF           (8U)
+/** @} */
 
 #ifdef __cplusplus
 }
diff --git a/cpu/atmega_common/periph/adc.c b/cpu/atmega_common/periph/adc.c
new file mode 100644
index 0000000000..fac2ad8918
--- /dev/null
+++ b/cpu/atmega_common/periph/adc.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2016 Laurent Navet <laurent.navet@gmail.com>
+ *               2017 HAW Hamburg, Dimitri Nahm
+ *
+ * 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     drivers_periph
+ * @{
+ *
+ * @file
+ * @brief       Low-level ADC driver implementation for ATmega family
+ *
+ * @author      Laurent Navet <laurent.navet@gmail.com>
+ * @author      Dimitri Nahm <dimitri.nahm@haw-hamburg.de>
+ * @author      Sebastian Meiling <s@mlng.net>
+ * @}
+ */
+
+#include "cpu.h"
+#include "mutex.h"
+#include "assert.h"
+#include "periph/adc.h"
+#include "periph_conf.h"
+
+#define ADC_MAX_CLK         (200000U)
+
+static mutex_t lock = MUTEX_INIT;
+
+static inline void _prep(void)
+{
+    mutex_lock(&lock);
+    /* Enable ADC */
+    ADCSRA |= (1 << ADEN);
+}
+
+static inline void _done(void)
+{
+    /* Disable ADC */
+    ADCSRA &= ~(1 << ADEN);
+    mutex_unlock(&lock);
+}
+
+int adc_init(adc_t line)
+{
+    /* check if the line is valid */
+    if (line >= ADC_NUMOF) {
+        return -1;
+    }
+
+    _prep();
+
+    /* Disable corresponding Digital input */
+    if (line < 8) {
+        DIDR0 |= (1 << line);
+    }
+#if defined(CPU_ATMEGA2560)
+    else {
+        DIDR2 |= (1 << (line - 8));
+    }
+#endif
+
+    /* Set ADC-pin as input */
+#if defined(CPU_ATMEGA328P)
+    DDRC &= ~(1 << line);
+    PORTC &= ~(1 << line);
+#elif defined(CPU_ATMEGA2560) || defined(CPU_ATMEGA1281)
+    if (line < 8) {
+        DDRF  &= ~(1 << line);
+        PORTF &= ~(1 << line);
+    }
+#if defined(CPU_ATMEGA2560)
+    else {
+        DDRK  &= ~(1 << (line-8));
+        PORTK &= ~(1 << (line-8));
+    }
+#endif /* CPU_ATMEGA2560 */
+#endif /* CPU_ATMEGA328P */
+
+    /* set clock prescaler to get the maximal possible ADC clock value */
+    for (uint32_t clk_div = 1; clk_div < 8; ++clk_div) {
+        if ((CLOCK_CORECLOCK / (1 << clk_div)) <= ADC_MAX_CLK) {
+            ADCSRA |= clk_div;
+            break;
+        }
+    }
+
+    /* Ref Voltage is Vcc(5V) */
+    ADMUX |= (1 << REFS0);
+
+    _done();
+
+    return 0;
+}
+
+int adc_sample(adc_t line, adc_res_t res)
+{
+    int sample = 0;
+
+    /* check if resolution is applicable */
+    if (res != ADC_RES_10BIT) {
+        return -1;
+    }
+
+    _prep();
+
+    /* set conversion channel */
+#if defined(CPU_ATMEGA328P) || defined(CPU_ATMEGA1281)
+    ADMUX &= 0xf0;
+    ADMUX |= line;
+#elif defined(CPU_ATMEGA2560)
+    if (line < 8) {
+        ADCSRB &= ~(1 << MUX5);
+        ADMUX &= 0xf0;
+        ADMUX |= line;
+    }
+    else {
+        ADCSRB |= (1 << MUX5);
+        ADMUX &= 0xf0;
+        ADMUX |= (line-8);
+    }
+#endif
+
+    /* Start a new conversion. By default, this conversion will
+       be performed in single conversion mode. */
+    ADCSRA |= (1 << ADSC);
+
+    /* Wait until the conversion is complete */
+    while (ADCSRA & (1 << ADSC)) {}
+
+    /* Get conversion result */
+    sample = ADC;
+
+    /* Clear the ADIF flag */
+    ADCSRA |= (1 << ADIF);
+
+    _done();
+
+    return sample;
+}
diff --git a/sys/arduino/base.cpp b/sys/arduino/base.cpp
index 4f61a81c4c..4c800018ab 100644
--- a/sys/arduino/base.cpp
+++ b/sys/arduino/base.cpp
@@ -21,10 +21,13 @@
 extern "C" {
 #include "xtimer.h"
 #include "periph/gpio.h"
+#include "periph/adc.h"
 }
 
 #include "arduino.hpp"
 
+#define ANALOG_PIN_NUMOF     (sizeof(arduino_analog_map) / sizeof(arduino_analog_map[0]))
+
 void pinMode(int pin, int mode)
 {
     gpio_mode_t m = GPIO_OUT;
@@ -58,3 +61,32 @@ void delay(unsigned long msec)
 {
     xtimer_usleep(1000 * msec);
 }
+
+/*
+ * Bitfield for the state of the ADC-channels.
+ * 0: Not initialized
+ * 1: Successfully initialized
+ */
+static uint16_t adc_line_state = 0;
+
+int analogRead(int arduino_pin)
+{
+    int adc_value;
+
+    /* Check if the ADC line is valid */
+    assert((arduino_pin >= 0) && (arduino_pin < (int)ANALOG_PIN_NUMOF));
+
+    /* Initialization of given ADC channel */
+    if (!(adc_line_state & (1 << arduino_pin))) {
+        if (adc_init(arduino_analog_map[arduino_pin]) != 0) {
+            return -1;
+        }
+        /* The ADC channel is initialized */
+        adc_line_state |= 1 << arduino_pin;
+    }
+
+    /* Read the ADC channel */
+    adc_value = adc_sample(arduino_analog_map[arduino_pin], ADC_RES_10BIT);
+
+    return adc_value;
+}
diff --git a/sys/arduino/include/arduino.hpp b/sys/arduino/include/arduino.hpp
index 5323012ad5..b94f17519f 100644
--- a/sys/arduino/include/arduino.hpp
+++ b/sys/arduino/include/arduino.hpp
@@ -82,5 +82,15 @@ int digitalRead(int pin);
  */
 void delay(unsigned long msec);
 
+/**
+ * @brief   Read the current value of the given analog pin
+ *
+ * @param[in] pin       pin to read
+ *
+ * @return a value between 0 to 1023 that is proportionnal
+ * to the voltage applied to the pin
+ */
+int analogRead(int pin);
+
 #endif /* ARDUINO_H */
 /** @} */
-- 
GitLab