diff --git a/boards/iot-lab_M3/include/board.h b/boards/iot-lab_M3/include/board.h
index d913d7c4af6d69ced6004d9bfd438cb95a1a574d..8e35ded673973b3420c1df3256a03d69c099b477 100644
--- a/boards/iot-lab_M3/include/board.h
+++ b/boards/iot-lab_M3/include/board.h
@@ -38,7 +38,8 @@
  * @{
  */
 #define STDIO               UART_0
-#define STDIO_BAUDRATE      (115200)
+#define STDIO_BAUDRATE      (115200U)
+#define STDIO_RX_BUFSIZE    (64U)
 /** @} */
 
 /**
diff --git a/boards/msbiot/include/board.h b/boards/msbiot/include/board.h
index 18931c63b60f5baafbdf77c46f43a3b63471349d..0b6034a9f9510d152aa24fcd444281a883f1de63 100644
--- a/boards/msbiot/include/board.h
+++ b/boards/msbiot/include/board.h
@@ -40,6 +40,7 @@
  */
 #define STDIO               UART_0
 #define STDIO_BAUDRATE      (115200U)
+#define STDIO_RX_BUFSIZE    (64U)
 /** @} */
 
 /**
diff --git a/boards/stm32f0discovery/include/board.h b/boards/stm32f0discovery/include/board.h
index 13b8451979c2102ab053a94884c0a62990805c1b..355776edf4e413e62feaa4108dabaa3d17d1deda 100644
--- a/boards/stm32f0discovery/include/board.h
+++ b/boards/stm32f0discovery/include/board.h
@@ -38,6 +38,8 @@
  * @name Assign the UART interface to be used for stdio
  */
 #define STDIO               UART_0
+#define STDIO_BAUDRATE      (115200U)
+#define STDIO_RX_BUFSIZE    (64U)
 
 /**
  * @name LED pin definitions
diff --git a/boards/stm32f3discovery/include/board.h b/boards/stm32f3discovery/include/board.h
index 7918d0f393c43aefd389bbbbc81e7ec468598b91..0f071217be8ff15fe8c9309cb513b2e88a716fa5 100644
--- a/boards/stm32f3discovery/include/board.h
+++ b/boards/stm32f3discovery/include/board.h
@@ -39,7 +39,7 @@
  */
 #define STDIO               UART_0
 #define STDIO_BAUDRATE      (115200U)
-#define STDIO_BUFSIZE       (64U)
+#define STDIO_RX_BUFSIZE    (64U)
 /** @} */
 
 /**
diff --git a/boards/stm32f4discovery/include/board.h b/boards/stm32f4discovery/include/board.h
index e40813bc2e48a0ba4aff170f6a6f0c9039123b96..0b0195b0a49f82796d763b8e10a8b54c7570e98f 100644
--- a/boards/stm32f4discovery/include/board.h
+++ b/boards/stm32f4discovery/include/board.h
@@ -40,6 +40,7 @@
  */
 #define STDIO               UART_0
 #define STDIO_BAUDRATE      (115200U)
+#define STDIO_RX_BUFSIZE    (64U)
 /** @} */
 
 /**
diff --git a/cpu/stm32f0/Makefile.include b/cpu/stm32f0/Makefile.include
index c2bd10a42374fbb4b87845d7ae723a3cd356ad97..27d71f5cf2f1f737fbaa5079e267a66400759481 100644
--- a/cpu/stm32f0/Makefile.include
+++ b/cpu/stm32f0/Makefile.include
@@ -7,6 +7,9 @@ export USEMODULE += cortex-m0_common
 # define path to cortex-m common module, which is needed for this CPU
 export CORTEX_COMMON = $(RIOTCPU)/cortex-m0_common/
 
+# this CPU implementation makes use of the ringbuffer, so include the lib module
+export USEMODULE += lib
+
 # define the linker script to use for this CPU. The CPU_MODEL variable is defined in the
 # board's Makefile.include. This enables multiple STMF0 controllers with different memory to
 # use the same code-base.
diff --git a/cpu/stm32f0/syscalls.c b/cpu/stm32f0/syscalls.c
index f8dcdc78e95c852bdcc4d3734bbd1ccb806463cc..1f0787e8ebc40b326229aae2b722fbde03865214 100644
--- a/cpu/stm32f0/syscalls.c
+++ b/cpu/stm32f0/syscalls.c
@@ -30,10 +30,15 @@
 
 #include "thread.h"
 #include "kernel.h"
+#include "mutex.h"
+#include "ringbuffer.h"
 #include "irq.h"
 #include "board.h"
 #include "periph/uart.h"
 
+#ifdef MODULE_UART0
+#include "board_uart0.h"
+#endif
 
 /**
  * manage the heap
@@ -41,12 +46,44 @@
 extern uint32_t _end;                       /* address of last used memory cell */
 caddr_t heap_top = (caddr_t)&_end + 4;
 
+#ifndef MODULE_UART0
+/**
+ * @brief use mutex for waiting on incoming UART chars
+ */
+static mutex_t uart_rx_mutex;
+static char rx_buf_mem[STDIO_RX_BUFSIZE];
+static ringbuffer_t rx_buf;
+#endif
+
+/**
+ * @brief Receive a new character from the UART and put it into the receive buffer
+ */
+void rx_cb(void *arg, char data)
+{
+#ifndef MODULE_UART0
+    (void)arg;
+
+    ringbuffer_add_one(&rx_buf, data);
+    mutex_unlock(&uart_rx_mutex);
+#else
+    if (uart0_handler_pid) {
+        uart0_handle_incoming(data);
+
+        uart0_notify_thread();
+    }
+#endif
+}
+
 /**
  * @brief Initialize NewLib, called by __libc_init_array() from the startup script
  */
 void _init(void)
 {
-    uart_init_blocking(STDIO, 115200);
+#ifndef MODULE_UART0
+    mutex_init(&uart_rx_mutex);
+    ringbuffer_init(&rx_buf, rx_buf_mem, STDIO_RX_BUFSIZE);
+#endif
+    uart_init(STDIO, STDIO_BAUDRATE, rx_cb, 0, 0);
 }
 
 /**
@@ -152,11 +189,16 @@ int _open_r(struct _reent *r, const char *name, int mode)
  */
 int _read_r(struct _reent *r, int fd, void *buffer, unsigned int count)
 {
-    char c;
-    char *buff = (char*)buffer;
-    uart_read_blocking(STDIO, &c);
-    buff[0] = c;
+#ifndef MODULE_UART0
+    while (rx_buf.avail == 0) {
+        mutex_lock(&uart_rx_mutex);
+    }
+    return ringbuffer_get(&rx_buf, (char*)buffer, rx_buf.avail);
+#else
+    char *res = (char*)buffer;
+    res[0] = (char)uart0_readc();
     return 1;
+#endif
 }
 
 /**
diff --git a/cpu/stm32f1/Makefile.include b/cpu/stm32f1/Makefile.include
index 87dd950e2b507048f096c83bba4ba182ed993429..7370ae77acdcb271f3934d5eda17eed80b81624d 100644
--- a/cpu/stm32f1/Makefile.include
+++ b/cpu/stm32f1/Makefile.include
@@ -4,6 +4,9 @@ export CFLAGS += -DCOREIF_NG=1
 # tell the build system that the CPU depends on the Cortex-M common files
 export USEMODULE += cortex-m3_common
 
+# this CPU implementation makes use of the ringbuffer, so include the lib module
+export USEMODULE += lib
+
 # define path to cortex-m common module, which is needed for this CPU
 export CORTEXM_COMMON = $(RIOTCPU)/cortex-m3_common/
 
diff --git a/cpu/stm32f1/periph/uart.c b/cpu/stm32f1/periph/uart.c
index 5b4c397b29b595a3fb7216af4cae9fcff3df1a2b..bfd847741173fdcc5f4069906b5f3b631f113a5d 100644
--- a/cpu/stm32f1/periph/uart.c
+++ b/cpu/stm32f1/periph/uart.c
@@ -29,11 +29,6 @@
 #include "sched.h"
 #include "thread.h"
 
-#ifdef MODULE_UART0
-#include "board_uart0.h"
-#endif
-
-
 /**
  * @brief Each UART device has to store two callbacks.
  */
@@ -296,28 +291,17 @@ static inline void irq_handler(uint8_t uartnum, USART_TypeDef *dev)
 {
     if (dev->SR & USART_SR_RXNE) {
         char data = (char)dev->DR;
-#ifdef MODULE_UART0
-        if (uart0_handler_pid) {
-            uart0_handle_incoming(data);
-
-            uart0_notify_thread();
-        }
-#else
         config[uartnum].rx_cb(config[uartnum].arg, data);
-#endif
     }
     else if (dev->SR & USART_SR_ORE) {
         /* ORE is cleared by reading SR and DR sequentially */
         dev->DR;
     }
     else if (dev->SR & USART_SR_TXE) {
-#ifdef MODULE_UART0
-        dev->SR &= ~(USART_SR_TXE);
-#else
-        config[uartnum].tx_cb(config[uartnum].arg);
-#endif
+        if (config[uartnum].tx_cb(config[uartnum].arg) == 0) {
+            dev->CR1 &= ~(USART_CR1_TXEIE);
+        }
     }
-
     if (sched_context_switch_request) {
         thread_yield();
     }
diff --git a/cpu/stm32f1/syscalls.c b/cpu/stm32f1/syscalls.c
index c7962b99e29e1849291b508fdf3de3738e117a8b..247caa4bb5bbb5836569d4414f666fc9d9aa5e21 100644
--- a/cpu/stm32f1/syscalls.c
+++ b/cpu/stm32f1/syscalls.c
@@ -28,28 +28,62 @@
 #include <sys/unistd.h>
 #include <stdint.h>
 
+#include "board.h"
 #include "thread.h"
 #include "kernel.h"
+#include "mutex.h"
+#include "ringbuffer.h"
 #include "irq.h"
 #include "periph/uart.h"
 
+#ifdef MODULE_UART0
+#include "board_uart0.h"
+#endif
+
 /**
  * manage the heap
  */
 extern uint32_t _end;                       /* address of last used memory cell */
 caddr_t heap_top = (caddr_t)&_end + 4;
 
+#ifndef MODULE_UART0
+/**
+ * @brief use mutex for waiting on incoming UART chars
+ */
+static mutex_t uart_rx_mutex;
+static char rx_buf_mem[STDIO_RX_BUFSIZE];
+static ringbuffer_t rx_buf;
+#endif
+
+/**
+ * @brief Receive a new character from the UART and put it into the receive buffer
+ */
+void rx_cb(void *arg, char data)
+{
+#ifndef MODULE_UART0
+    (void)arg;
+
+    ringbuffer_add_one(&rx_buf, data);
+    mutex_unlock(&uart_rx_mutex);
+#else
+    if (uart0_handler_pid) {
+        uart0_handle_incoming(data);
+
+        uart0_notify_thread();
+    }
+#endif
+}
 
 /**
  * @brief Initialize NewLib, called by __libc_init_array() from the startup script
  */
 void _init(void)
 {
-#ifdef MODULE_UART0
-    uart_init(UART_0, 115200, NULL, NULL, NULL);
-#else
-    uart_init_blocking(UART_0, 115200);
+#ifndef MODULE_UART0
+    mutex_init(&uart_rx_mutex);
+    ringbuffer_init(&rx_buf, rx_buf_mem, STDIO_RX_BUFSIZE);
 #endif
+    uart_init(STDIO, STDIO_BAUDRATE, rx_cb, 0, 0);
 }
 
 /**
@@ -155,11 +189,16 @@ int _open_r(struct _reent *r, const char *name, int mode)
  */
 int _read_r(struct _reent *r, int fd, void *buffer, unsigned int count)
 {
-    char c;
-    char *buff = (char*)buffer;
-    uart_read_blocking(UART_0, &c);
-    buff[0] = c;
+#ifndef MODULE_UART0
+    while (rx_buf.avail == 0) {
+        mutex_lock(&uart_rx_mutex);
+    }
+    return ringbuffer_get(&rx_buf, (char*)buffer, rx_buf.avail);
+#else
+    char *res = (char*)buffer;
+    res[0] = (char)uart0_readc();
     return 1;
+#endif
 }
 
 /**
diff --git a/cpu/stm32f3/syscalls.c b/cpu/stm32f3/syscalls.c
index e2747d46da2c7ae7c9ca38f6fe10df1cb05b16f7..4f89a0e7e35337f32f77eee71028dced84f4a9aa 100644
--- a/cpu/stm32f3/syscalls.c
+++ b/cpu/stm32f3/syscalls.c
@@ -37,28 +37,42 @@
 #include "irq.h"
 #include "periph/uart.h"
 
+#ifdef MODULE_UART0
+#include "board_uart0.h"
+#endif
+
 /**
  * @brief manage the heap
  */
 extern uint32_t _end;                       /* address of last used memory cell */
 caddr_t heap_top = (caddr_t)&_end + 4;
 
+#ifndef MODULE_UART0
 /**
  * @brief use mutex for waiting on incoming UART chars
  */
 static mutex_t uart_rx_mutex;
-static char rx_buf_mem[STDIO_BUFSIZE];
+static char rx_buf_mem[STDIO_RX_BUFSIZE];
 static ringbuffer_t rx_buf;
+#endif
 
 /**
  * @brief Receive a new character from the UART and put it into the receive buffer
  */
 void rx_cb(void *arg, char data)
 {
+#ifndef MODULE_UART0
     (void)arg;
 
     ringbuffer_add_one(&rx_buf, data);
     mutex_unlock(&uart_rx_mutex);
+#else
+    if (uart0_handler_pid) {
+        uart0_handle_incoming(data);
+
+        uart0_notify_thread();
+    }
+#endif
 }
 
 /**
@@ -66,10 +80,11 @@ void rx_cb(void *arg, char data)
  */
 void _init(void)
 {
+#ifndef MODULE_UART0
     mutex_init(&uart_rx_mutex);
-    ringbuffer_init(&rx_buf, rx_buf_mem, STDIO_BUFSIZE);
-    uart_init(STDIO, STDIO_BAUDRATE, rx_cb, 0, 0);
-}
+    ringbuffer_init(&rx_buf, rx_buf_mem, STDIO_RX_BUFSIZE);
+#endif
+    uart_init(STDIO, STDIO_BAUDRATE, rx_cb, 0, 0);}
 
 /**
  * @brief Free resources on NewLib de-initialization, not used for RIOT
@@ -174,10 +189,16 @@ int _open_r(struct _reent *r, const char *name, int mode)
  */
 int _read_r(struct _reent *r, int fd, void *buffer, unsigned int count)
 {
+#ifndef MODULE_UART0
     while (rx_buf.avail == 0) {
         mutex_lock(&uart_rx_mutex);
     }
     return ringbuffer_get(&rx_buf, (char*)buffer, rx_buf.avail);
+#else
+    char *res = (char*)buffer;
+    res[0] = (char)uart0_readc();
+    return 1;
+#endif
 }
 
 /**
diff --git a/cpu/stm32f4/Makefile.include b/cpu/stm32f4/Makefile.include
index 511a37959b503b470162bd818e443663954f1120..bb97cdfef0b421fa00053c6941be098711673e35 100644
--- a/cpu/stm32f4/Makefile.include
+++ b/cpu/stm32f4/Makefile.include
@@ -4,6 +4,9 @@ export CFLAGS += -DCOREIF_NG=1
 # export the peripheral drivers to be linked into the final binary
 export USEMODULE += periph
 
+# this CPU implementation makes use of the ringbuffer, so include the lib module
+export USEMODULE += lib
+
 # tell the build system that the CPU depends on the Cortex-M common files
 export USEMODULE += cortex-m4_common
 
diff --git a/cpu/stm32f4/periph/uart.c b/cpu/stm32f4/periph/uart.c
index 93bddb01f7dad1ab5f9080b122123dfd6c80982d..891ffd30325712ef0c0a978188219e4a9d4eb1b8 100644
--- a/cpu/stm32f4/periph/uart.c
+++ b/cpu/stm32f4/periph/uart.c
@@ -27,7 +27,6 @@
 
 /* guard file in case no UART device was specified */
 #if UART_NUMOF
-
 /**
  * @brief Each UART device has to store two callbacks.
  */
diff --git a/cpu/stm32f4/syscalls.c b/cpu/stm32f4/syscalls.c
index fa915f7b608e1ed7846ca93f6d8ef8657ae4b7e6..2d4508ca3fd41ebffadd608ea804801d572bab46 100644
--- a/cpu/stm32f4/syscalls.c
+++ b/cpu/stm32f4/syscalls.c
@@ -31,21 +31,59 @@
 #include "board.h"
 #include "thread.h"
 #include "kernel.h"
+#include "mutex.h"
+#include "ringbuffer.h"
 #include "irq.h"
 #include "periph/uart.h"
 
+#ifdef MODULE_UART0
+#include "board_uart0.h"
+#endif
+
 /**
  * manage the heap
  */
 extern uint32_t _end;                       /* address of last used memory cell */
 caddr_t heap_top = (caddr_t)&_end + 4;
 
+#ifndef MODULE_UART0
+/**
+ * @brief use mutex for waiting on incoming UART chars
+ */
+static mutex_t uart_rx_mutex;
+static char rx_buf_mem[STDIO_RX_BUFSIZE];
+static ringbuffer_t rx_buf;
+#endif
+
+/**
+ * @brief Receive a new character from the UART and put it into the receive buffer
+ */
+void rx_cb(void *arg, char data)
+{
+#ifndef MODULE_UART0
+    (void)arg;
+
+    ringbuffer_add_one(&rx_buf, data);
+    mutex_unlock(&uart_rx_mutex);
+#else
+    if (uart0_handler_pid) {
+        uart0_handle_incoming(data);
+
+        uart0_notify_thread();
+    }
+#endif
+}
+
 /**
  * @brief Initialize NewLib, called by __libc_init_array() from the startup script
  */
 void _init(void)
 {
-    uart_init_blocking(STDIO, STDIO_BAUDRATE);
+#ifndef MODULE_UART0
+    mutex_init(&uart_rx_mutex);
+    ringbuffer_init(&rx_buf, rx_buf_mem, STDIO_RX_BUFSIZE);
+#endif
+    uart_init(STDIO, STDIO_BAUDRATE, rx_cb, 0, 0);
 }
 
 /**
@@ -151,11 +189,16 @@ int _open_r(struct _reent *r, const char *name, int mode)
  */
 int _read_r(struct _reent *r, int fd, void *buffer, unsigned int count)
 {
-    char c;
-    char *buff = (char*)buffer;
-    uart_read_blocking(STDIO, &c);
-    buff[0] = c;
+#ifndef MODULE_UART0
+    while (rx_buf.avail == 0) {
+        mutex_lock(&uart_rx_mutex);
+    }
+    return ringbuffer_get(&rx_buf, (char*)buffer, rx_buf.avail);
+#else
+    char *res = (char*)buffer;
+    res[0] = (char)uart0_readc();
     return 1;
+#endif
 }
 
 /**
@@ -175,11 +218,13 @@ int _read_r(struct _reent *r, int fd, void *buffer, unsigned int count)
  */
 int _write_r(struct _reent *r, int fd, const void *data, unsigned int count)
 {
-    char *c = (char*)data;
-    for (int i = 0; i < count; i++) {
-        uart_write_blocking(STDIO, c[i]);
+    int i = 0;
+
+    while (i < count) {
+        uart_write_blocking(STDIO, ((char*)data)[i++]);
     }
-    return count;
+
+    return i;
 }
 
 /**