diff --git a/cpu/atmega_common/periph/eeprom.c b/cpu/atmega_common/periph/eeprom.c
index 2a3827336ddd08532d444a4137837c61fef83052..15129e53f6cc62179fde91858836e0ee875e6064 100644
--- a/cpu/atmega_common/periph/eeprom.c
+++ b/cpu/atmega_common/periph/eeprom.c
@@ -24,37 +24,52 @@
 #include "cpu.h"
 #include "periph/eeprom.h"
 
-uint8_t eeprom_read_byte(uint32_t pos)
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+size_t eeprom_read(uint32_t pos, uint8_t *data, size_t len)
 {
-    assert(pos < EEPROM_SIZE);
+    assert(pos + len <= EEPROM_SIZE);
+
+    uint8_t *p = data;
 
-    /* Wait for completion of previous operation */
-    while (EECR & (1 << EEPE)) {}
+    DEBUG("Reading data from EEPROM at pos %" PRIu32 ": ", pos);
+    for (size_t i = 0; i < len; i++) {
+        while (EECR & (1 << EEPE)) {}
 
-    /* Set up address register */
-    EEAR = pos;
+        /* Set up address register */
+        EEAR = pos++;
 
-    /* Start eeprom read by writing EERE */
-    EECR |= (1 << EERE);
+        /* Start eeprom read by writing EERE */
+        EECR |= (1 << EERE);
+        *p++ = (uint8_t)EEDR;
+        DEBUG("0x%02X ", EEDR);
+    }
+    DEBUG("\n");
 
-    /* Return data from Data Register */
-    return EEDR;
+    return len;
 }
 
-void eeprom_write_byte(uint32_t pos, uint8_t data)
+size_t eeprom_write(uint32_t pos, const uint8_t *data, size_t len)
 {
-    assert(pos < EEPROM_SIZE);
+    assert(pos + len <= EEPROM_SIZE);
+
+    uint8_t *p = (uint8_t *)data;
+
+    for (size_t i = 0; i < len; i++) {
+        /* Wait for completion of previous operation */
+        while (EECR & (1 << EEPE)) {}
 
-    /* Wait for completion of previous operation */
-    while (EECR & (1 << EEPE)) {}
+        /* Set up address and Data Registers */
+        EEAR = pos++;
+        EEDR = *p++;
 
-    /* Set up address and Data Registers */
-    EEAR = pos;
-    EEDR = data;
+        /* Write logical one to EEMPE */
+        EECR |= (1 << EEMPE);
 
-    /* Write logical one to EEMPE */
-    EECR |= (1 << EEMPE);
+        /* Start eeprom write by setting EEPE */
+        EECR |= (1 << EEPE);
+    }
 
-    /* Start eeprom write by setting EEPE */
-    EECR |= (1 << EEPE);
+    return len;
 }
diff --git a/cpu/stm32_common/periph/eeprom.c b/cpu/stm32_common/periph/eeprom.c
index bef71291b3b02a66bddf4b7aef35639cc387eb2a..962b543babfb5db451694ef034978b1e0c9ef9af 100644
--- a/cpu/stm32_common/periph/eeprom.c
+++ b/cpu/stm32_common/periph/eeprom.c
@@ -22,12 +22,11 @@
 #include <assert.h>
 
 #include "cpu.h"
+#include "periph/eeprom.h"
 
 #define ENABLE_DEBUG        (0)
 #include "debug.h"
 
-#include "periph/eeprom.h"
-
 extern void _lock(void);
 extern void _unlock(void);
 
@@ -35,20 +34,35 @@ extern void _unlock(void);
 #error "periph/eeprom: EEPROM_START_ADDR is not defined"
 #endif
 
-uint8_t eeprom_read_byte(uint32_t pos)
+size_t eeprom_read(uint32_t pos, uint8_t *data, size_t len)
 {
-    assert(pos < EEPROM_SIZE);
+    assert(pos + len <= EEPROM_SIZE);
+
+    uint8_t *p = data;
+
+    DEBUG("Reading data from EEPROM at pos %" PRIu32 ": ", pos);
+    for (size_t i = 0; i < len; i++) {
+        *p++ = *(uint8_t *)(EEPROM_START_ADDR + pos++);
+        DEBUG("0x%02X ", *p);
+    }
+    DEBUG("\n");
 
-    DEBUG("Reading data from EEPROM at pos %" PRIu32 "\n", pos);
-    return *(uint8_t *)(EEPROM_START_ADDR + pos);
+    return len;
 }
 
-void eeprom_write_byte(uint32_t pos, uint8_t data)
+size_t eeprom_write(uint32_t pos, const uint8_t *data, size_t len)
 {
-    assert(pos < EEPROM_SIZE);
+    assert(pos + len <= EEPROM_SIZE);
+
+    uint8_t *p = (uint8_t *)data;
 
-    DEBUG("Writing data '%c' to EEPROM at pos %" PRIu32 "\n", data, pos);
     _unlock();
-    *(uint8_t *)(EEPROM_START_ADDR + pos) = data;
+
+    for (size_t i = 0; i < len; i++) {
+        *(uint8_t *)(EEPROM_START_ADDR + pos++) = *p++;
+    }
+
     _lock();
+
+    return len;
 }
diff --git a/drivers/include/periph/eeprom.h b/drivers/include/periph/eeprom.h
index 09dd5034ee8b0b30ff031ca2f1762a5e942023c1..affdf13572b2c4a6c860fbf4563692d6a0cf06f1 100644
--- a/drivers/include/periph/eeprom.h
+++ b/drivers/include/periph/eeprom.h
@@ -46,6 +46,9 @@ uint8_t eeprom_read_byte(uint32_t pos);
 /**
  * @brief   Read @p len bytes from the given position
  *
+ * This function must be implemented by each CPU that provides an internal
+ * EEPROM.
+ *
  * @param[in]  pos      start position in eeprom
  * @param[out] data     output byte array to write to
  * @param[in]  len      the number of bytes to read
@@ -65,6 +68,9 @@ void eeprom_write_byte(uint32_t pos, uint8_t data);
 /**
  * @brief   Write @p len bytes at the given position
  *
+ * This function must be implemented by each CPU that provides an internal
+ * EEPROM.
+ *
  * @param[in] pos       start position in eeprom
  * @param[in] data      input byte array to read into
  * @param[in] len       the number of bytes to read
diff --git a/drivers/periph_common/eeprom.c b/drivers/periph_common/eeprom.c
index 07fd94e6db61d3a57566ebb5d6afd3c360c95f56..d22c512701d15df1eb8977dcd940be8abcfe9bcc 100644
--- a/drivers/periph_common/eeprom.c
+++ b/drivers/periph_common/eeprom.c
@@ -28,26 +28,16 @@
 
 #include "periph/eeprom.h"
 
-size_t eeprom_read(uint32_t pos, uint8_t *data, size_t len)
+uint8_t eeprom_read_byte(uint32_t pos)
 {
-    assert(pos + len < EEPROM_SIZE);
-
-    for (size_t i = 0; i < len; i++) {
-        data[i] = eeprom_read_byte(pos++);
-    }
-
-    return len;
+    uint8_t byte;
+    eeprom_read(pos, &byte, 1);
+    return byte;
 }
 
-size_t eeprom_write(uint32_t pos, const uint8_t *data, size_t len)
+void eeprom_write_byte(uint32_t pos, uint8_t byte)
 {
-    assert(pos + len < EEPROM_SIZE);
-
-    for (size_t i = 0; i < len; i++) {
-        eeprom_write_byte(pos++, data[i]);
-    }
-
-    return len;
+    eeprom_write(pos, &byte, 1);
 }
 
 #endif
diff --git a/tests/periph_eeprom/main.c b/tests/periph_eeprom/main.c
index 0de526c83a5dc3498e0487dff2a190b7809116a1..0eac47877f6c3eb016e180798a39217ead634ad3 100644
--- a/tests/periph_eeprom/main.c
+++ b/tests/periph_eeprom/main.c
@@ -21,6 +21,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <assert.h>
 
 #include "shell.h"
 
@@ -65,7 +66,7 @@ static int cmd_read(int argc, char **argv)
         return 1;
     }
 
-    if (pos + count >= EEPROM_SIZE) {
+    if (pos + count > EEPROM_SIZE) {
         puts("Failed: cannot read out of eeprom bounds");
         return 1;
     }
@@ -78,6 +79,26 @@ static int cmd_read(int argc, char **argv)
     return 0;
 }
 
+static int cmd_read_byte(int argc, char **argv)
+{
+    if (argc < 2) {
+        printf("usage: %s <pos>\n", argv[0]);
+        return 1;
+    }
+
+    uint32_t pos = atoi(argv[1]);
+
+    if (pos >= EEPROM_SIZE) {
+        puts("Failed: cannot read out of eeprom bounds");
+        return 1;
+    }
+
+    uint8_t byte = eeprom_read_byte(pos);
+    printf("Byte read from EEPROM: 0x%02X (%c)\n", byte, byte);
+
+    return 0;
+}
+
 static int cmd_write(int argc, char **argv)
 {
     if (argc < 3) {
@@ -87,7 +108,7 @@ static int cmd_write(int argc, char **argv)
 
     uint32_t pos = atoi(argv[1]);
 
-    if (pos + strlen(argv[2]) >= EEPROM_SIZE) {
+    if (pos + strlen(argv[2]) > EEPROM_SIZE) {
         puts("Failed: cannot write out of eeprom bounds");
         return 1;
     }
@@ -98,10 +119,75 @@ static int cmd_write(int argc, char **argv)
     return 0;
 }
 
+static int cmd_write_byte(int argc, char **argv)
+{
+    if (argc < 3) {
+        printf("usage: %s <pos> <byte>\n", argv[0]);
+        return 1;
+    }
+
+    uint32_t pos = atoi(argv[1]);
+
+    if (pos >= EEPROM_SIZE) {
+        puts("Failed: cannot write out of eeprom bounds");
+        return 1;
+    }
+
+    eeprom_write_byte(pos, *(uint8_t *)argv[2]);
+    printf("Byte written to EEPROM\n");
+
+    return 0;
+}
+
+static int cmd_test(int argc, char **argv)
+{
+    (void)argv;
+
+    if (argc != 1) {
+        puts("FAILED");
+        return 1;
+    }
+
+    const char *test = "test";
+
+    /* test read/write function */
+
+    /* read/write from beginning of EEPROM */
+    size_t ret = eeprom_write(0, (uint8_t *)test, 4);
+    assert(ret == 4);
+
+    char *expected[4];
+    ret = eeprom_read(0, (uint8_t *)expected, 4);
+    assert(strncmp((const char *)expected, (const char *)test, 4) == 0);
+    assert(ret == 4);
+
+    /* read/write at end of EEPROM */
+    ret = eeprom_write(EEPROM_SIZE - 4, (uint8_t *)test, 4);
+    assert(ret == 4);
+    ret = eeprom_read(EEPROM_SIZE - 4, (uint8_t *)expected, 4);
+    assert(strncmp((const char *)expected, test, 4) == 0);
+    assert(ret == 4);
+
+    /* read/write single byte */
+    eeprom_write_byte(0, 'A');
+    assert(eeprom_read_byte(0) == 'A');
+    eeprom_write_byte(EEPROM_SIZE - 1, 'A');
+    assert(eeprom_read_byte(EEPROM_SIZE - 1) == 'A');
+    eeprom_write_byte(EEPROM_SIZE / 2, 'A');
+    assert(eeprom_read_byte(EEPROM_SIZE / 2) == 'A');
+
+    puts("SUCCESS");
+    return 0;
+}
+
+
 static const shell_command_t shell_commands[] = {
     { "info", "Print information about eeprom", cmd_info },
     { "read", "Read bytes from eeprom", cmd_read },
-    { "write", "Write bytes to eeprom", cmd_write},
+    { "write", "Write bytes to eeprom", cmd_write },
+    { "read_byte", "Read a single byte from eeprom", cmd_read_byte },
+    { "write_byte", "Write a single byte to eeprom", cmd_write_byte },
+    { "test", "Test the EEPROM implementation", cmd_test },
     { NULL, NULL, NULL }
 };
 
diff --git a/tests/periph_eeprom/tests/01-run.py b/tests/periph_eeprom/tests/01-run.py
new file mode 100755
index 0000000000000000000000000000000000000000..26c16c36d6889adf59b970ab0dd1a00d71612ac1
--- /dev/null
+++ b/tests/periph_eeprom/tests/01-run.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2018 Inria
+#
+# 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.
+
+import sys
+from testrunner import run
+
+
+def testfunc(child):
+    child.sendline('test')
+    child.expect('SUCCESS')
+
+
+if __name__ == "__main__":
+    sys.exit(run(testfunc))