diff --git a/Documentation/pycardium/gpio.rst b/Documentation/pycardium/gpio.rst
index 51c7d5f90f270aedf583d0bd347c85323683626d..7d17b3fdf3597aba664ebc46feae7f7a41dc62ba 100644
--- a/Documentation/pycardium/gpio.rst
+++ b/Documentation/pycardium/gpio.rst
@@ -25,7 +25,10 @@ output in your scripts.
    :param int pin: ID of the pin to be configured.
    :param int mode: An integer with the bits for the wanted mode set. Create your
       integer by ORing :py:data:`gpio.mode.OUTPUT`, :py:data:`gpio.mode.INPUT`,
-      :py:data:`gpio.mode.PULL_UP`, :py:data:`gpio.mode.PULL_DOWN`.
+      :py:data:`gpio.mode.ADC`, :py:data:`gpio.mode.PULL_UP`,
+      :py:data:`gpio.mode.PULL_DOWN`.
+
+   .. note:: On WRISTBAND_3, there is no ADC functionality available
 
 .. py:function:: get_mode(pin)
 
@@ -47,6 +50,9 @@ output in your scripts.
 
    :param int pin: ID of the pin of to get the mode of.
    :returns: Current value of the GPIO pin.
+      If the pin is configured as ADC, the value returned
+      will be between 0 and 1000, representing voltages from
+      0V to 3.3V
 
 .. py:data:: WRISTBAND_1
 
diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h
index 29476b026c4b16740d82dff5f3aea04a1c1e85d9..9585690867f3c3e8a854641ce7006466b17143e5 100644
--- a/epicardium/epicardium.h
+++ b/epicardium/epicardium.h
@@ -459,6 +459,7 @@ enum gpio_mode {
     EPIC_GPIO_MODE_IN = (1<<0),
     /** Configure the pin as output */
     EPIC_GPIO_MODE_OUT = (1<<1),
+    EPIC_GPIO_MODE_ADC = (1<<2),
 
     /** Enable the internal pull-up resistor */
     EPIC_GPIO_PULL_UP = (1<<6),
diff --git a/epicardium/modules/gpio.c b/epicardium/modules/gpio.c
index 9577f094a166b6c52f25f11f7dd9acce8077c293..6b6977391f878fa58ad6618b98d08dcd9cf7f5a7 100644
--- a/epicardium/modules/gpio.c
+++ b/epicardium/modules/gpio.c
@@ -1,7 +1,11 @@
 #include "epicardium.h"
 #include "gpio.h"
 #include "max32665.h"
+#include "mxc_sys.h"
+#include "adc.h"
 #include "mxc_errors.h"
+#include "modules/log.h"
+#include "modules/modules.h"
 
 /*
  * Despite what the schematic (currently, 2019-08-18) says these are the correct
@@ -26,6 +30,17 @@ static gpio_cfg_t gpio_configs[] = {
 				    GPIO_PAD_NONE },
 };
 
+static int s_adc_channels[] = {
+	[EPIC_GPIO_WRISTBAND_1] = ADC_CH_5,
+	[EPIC_GPIO_WRISTBAND_2] = ADC_CH_6,
+	/* on P0.29, there is no ADC available
+	 * see GPIO matrix in MAX32665-MAX32668.pdf,
+	 * pages 32,33
+	 */
+	[EPIC_GPIO_WRISTBAND_3] = -1,
+	[EPIC_GPIO_WRISTBAND_4] = ADC_CH_4,
+};
+
 int epic_gpio_set_pin_mode(uint8_t pin, uint8_t mode)
 {
 	if (pin < EPIC_GPIO_WRISTBAND_1 || pin > EPIC_GPIO_WRISTBAND_4)
@@ -43,14 +58,27 @@ int epic_gpio_set_pin_mode(uint8_t pin, uint8_t mode)
 		if (mode & EPIC_GPIO_MODE_IN) {
 			return -EINVAL;
 		}
+	} else if (mode & EPIC_GPIO_MODE_ADC) {
+		if (s_adc_channels[pin] == -1) {
+			LOG_WARN("gpio", "ADC not available on pin %d", pin);
+			return -EINVAL;
+		}
+		cfg->func = GPIO_FUNC_ALT1;
+		if (mode & EPIC_GPIO_MODE_OUT) {
+			return -EINVAL;
+		}
 	} else {
 		return -EINVAL;
 	}
 
-	if (mode & EPIC_GPIO_PULL_UP) {
-		cfg->pad = GPIO_PAD_PULL_UP;
-	} else if (mode & EPIC_GPIO_PULL_DOWN) {
-		cfg->pad = GPIO_PAD_PULL_DOWN;
+	if (!(mode & EPIC_GPIO_MODE_ADC)) {
+		if (mode & EPIC_GPIO_PULL_UP) {
+			cfg->pad = GPIO_PAD_PULL_UP;
+		} else if (mode & EPIC_GPIO_PULL_DOWN) {
+			cfg->pad = GPIO_PAD_PULL_DOWN;
+		} else {
+			cfg->pad = GPIO_PAD_NONE;
+		}
 	} else {
 		cfg->pad = GPIO_PAD_NONE;
 	}
@@ -71,6 +99,8 @@ int epic_gpio_get_pin_mode(uint8_t pin)
 		res |= EPIC_GPIO_MODE_IN;
 	else if (cfg->func == GPIO_FUNC_OUT)
 		res |= EPIC_GPIO_MODE_OUT;
+	else if (cfg->func == GPIO_FUNC_ALT1)
+		res |= EPIC_GPIO_MODE_ADC;
 	if (cfg->pad == GPIO_PAD_PULL_UP)
 		res |= EPIC_GPIO_PULL_UP;
 	else if (cfg->pad == GPIO_PAD_PULL_DOWN)
@@ -106,6 +136,19 @@ int epic_gpio_read_pin(uint8_t pin)
 		return GPIO_OutGet(cfg) != 0;
 	} else if (cfg->func == GPIO_FUNC_IN) {
 		return GPIO_InGet(cfg) != 0;
+	} else if (cfg->func == GPIO_FUNC_ALT1) {
+		int rc = hwlock_acquire(HWLOCK_ADC, pdMS_TO_TICKS(10));
+		if (!rc) {
+			ADC_StartConvert(s_adc_channels[pin], 0, 0);
+			uint16_t value;
+			int rc = ADC_GetData(&value);
+			hwlock_release(HWLOCK_ADC);
+			if (rc < 0) {
+				return -EIO;
+			}
+			return (int)value;
+		}
+		return rc;
 	} else {
 		return -EINVAL;
 	}
diff --git a/pycardium/modules/gpio.c b/pycardium/modules/gpio.c
index 49c3c37c4ea52ee1f207ddf5d78ecd65a957fdc9..08db00b536b02ade2544b74a3ef24a94ef84e386 100644
--- a/pycardium/modules/gpio.c
+++ b/pycardium/modules/gpio.c
@@ -54,6 +54,7 @@ static const mp_rom_map_elem_t gpio_module_modes_table[] = {
 	{ MP_ROM_QSTR(MP_QSTR_INPUT), MP_OBJ_NEW_SMALL_INT(EPIC_GPIO_MODE_IN) },
 	{ MP_ROM_QSTR(MP_QSTR_OUTPUT),
 	  MP_OBJ_NEW_SMALL_INT(EPIC_GPIO_MODE_OUT) },
+	{ MP_ROM_QSTR(MP_QSTR_ADC), MP_OBJ_NEW_SMALL_INT(EPIC_GPIO_MODE_ADC) },
 	{ MP_ROM_QSTR(MP_QSTR_PULL_UP),
 	  MP_OBJ_NEW_SMALL_INT(EPIC_GPIO_PULL_UP) },
 	{ MP_ROM_QSTR(MP_QSTR_PULL_DOWN),
diff --git a/pycardium/modules/qstrdefs.h b/pycardium/modules/qstrdefs.h
index 75c8876e3a1413f753c5d52114822fdc8ad4595d..3ccb0ca01b1d925d009ca48360e4c31f907168ae 100644
--- a/pycardium/modules/qstrdefs.h
+++ b/pycardium/modules/qstrdefs.h
@@ -151,6 +151,7 @@ Q(WRISTBAND_3)
 Q(WRISTBAND_4)
 Q(INPUT)
 Q(OUTPUT)
+Q(ADC)
 Q(PULL_UP)
 Q(PULL_DOWN)