diff --git a/examples/usart2-dma.rs b/examples/usart2-dma.rs
index e49e4abd76c78fca8e4d78d7adcaad25a324d99e..1e946cd3ce12291d0b121b91aada7b07750048e1 100644
--- a/examples/usart2-dma.rs
+++ b/examples/usart2-dma.rs
@@ -3,14 +3,17 @@
 #![deny(warnings)]
 #![feature(const_fn)]
 #![feature(proc_macro)]
+#![feature(lang_items)]
 #![no_std]
 
 extern crate cortex_m_rtfm as rtfm;
 extern crate f4;
 extern crate heapless;
 
+use core::fmt::Write;
 use core::ops::Deref;
 use f4::Serial;
+use f4::Writer as w;
 use f4::prelude::*;
 use f4::dma::{Buffer, Dma1Channel5, Dma1Channel6};
 use f4::time::Hertz;
@@ -33,13 +36,14 @@ app! {
         static CMD_BUFFER: Vec<u8, [u8; MAX_CMD_LEN]> = Vec::new([0; MAX_CMD_LEN]);
         static RX_BUFFER: Buffer<[u8; MAX_RX_LEN], Dma1Channel5> = Buffer::new([0; MAX_RX_LEN]);
         static TX_BUFFER: Buffer<[u8; MAX_TX_LEN], Dma1Channel6> = Buffer::new([0; MAX_TX_LEN]);
+        static CNT: u8 = 1;
     },
 
     tasks: {
         DMA1_STREAM5: {
             path: rx_done,
             priority: 1,
-            resources: [CMD_BUFFER, RX_BUFFER, TX_BUFFER, DMA1, USART2],
+            resources: [CMD_BUFFER, RX_BUFFER, TX_BUFFER, DMA1, USART2, CNT],
         },
         DMA1_STREAM6: {
             path: tx_done,
@@ -48,15 +52,21 @@ app! {
         },
     },
 }
-
 fn init(p: init::Peripherals, r: init::Resources) {
     // There is no need to claim() resources in the init.
     // Start the serial port
     let serial = Serial(p.USART2);
     serial.init(BAUD_RATE.invert(), Some(p.DMA1), p.GPIOA, p.RCC);
-    // Send a welcome message. We can only clone slices of equal length, else panic.
-    r.TX_BUFFER.borrow_mut()[..15].clone_from_slice(b"Hello, world!\r\n");
+
+    // Send a welcome message by borrowing transmit buffer and writing a formatted string into it
+    let x = 1.0;
+    write!(
+        w::out(&mut r.TX_BUFFER.borrow_mut()[..MAX_TX_LEN]),
+        "Hello, world! {}\r\n",
+        x
+    ).unwrap();
     serial.write_all(p.DMA1, r.TX_BUFFER).unwrap();
+
     // Listen to serial input on the receive DMA
     serial.read_exact(p.DMA1, r.RX_BUFFER).unwrap();
 }
@@ -102,7 +112,7 @@ fn rx_done(t: &mut Threshold, mut r: DMA1_STREAM5::Resources) {
         if byte == b'\r' {
             // End of command
             match &***cmd {
-                b"hi" => {
+                b"hi" | b"Hi" => {
                     say_hello = true;
                 }
                 _ => {}
@@ -118,11 +128,18 @@ fn rx_done(t: &mut Threshold, mut r: DMA1_STREAM5::Resources) {
     });
     // If user wrote 'hi' and pressed enter, respond appropriately
     if say_hello {
+        // Increment 'hi' counter
+        **r.CNT = **r.CNT + 1;
+        let cnt: u8 = **r.CNT;
+        // Claim the transmit buffer and write a formatted string into it
         r.TX_BUFFER.claim_mut(t, |tx, _| {
-            let array = &**tx.deref();
-            // We can only clone slices of equal length, else panic
-            array.borrow_mut()[..15].clone_from_slice(b"Hello, there!\r\n");
+            write!(
+                w::out(&mut (*tx).deref().borrow_mut()[..MAX_TX_LEN]),
+                "Hello, there! {}\r\n",
+                cnt
+            ).unwrap();
         });
+
         // Transmit the response
         r.TX_BUFFER.claim(t, |tx, t| {
             r.DMA1.claim(t, |dma, t| {
@@ -132,6 +149,7 @@ fn rx_done(t: &mut Threshold, mut r: DMA1_STREAM5::Resources) {
                 });
             });
         });
+        // r.CNT.claim_mut(t, |cnt,_| cnt.wrapping_add(1));
     }
 }
 
@@ -147,4 +165,4 @@ fn tx_done(t: &mut Threshold, r: DMA1_STREAM6::Resources) {
         let array = &**tx.deref();
         array.borrow_mut()[..MAX_TX_LEN].clone_from_slice(&[0; MAX_TX_LEN]);
     });
-}
\ No newline at end of file
+}
diff --git a/src/lib.rs b/src/lib.rs
index e8b7554749979033079e4eabf92f2d2f73bb2641..25060109bf0bf1dd19f2fb9bdc4f2a8b8a549281 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -50,6 +50,7 @@ use frequency::*;
 
 pub use hal::prelude;
 pub use serial::Serial;
+pub use serial::Writer;
 pub use timer::{Channel, Timer};
 pub use pwm::Pwm;
 pub use capture::Capture;
diff --git a/src/serial.rs b/src/serial.rs
index 262d30a35fc1ef006cba9edb5476eca943e3fbb6..c0f7e824b59d1d806f1d7fdbdc97d7910aa1452f 100644
--- a/src/serial.rs
+++ b/src/serial.rs
@@ -21,6 +21,40 @@ use stm32f40x::{gpioa, DMA1, USART2, usart6, GPIOA, RCC};
 
 use dma::{self, Buffer, Dma1Channel5, Dma1Channel6};
 
+use core::fmt;
+use core::iter;
+
+///
+pub struct Writer<'a> {
+    buf: &'a mut [u8],
+    offset: usize,
+}
+
+impl<'a> Writer<'a> {
+    ///
+    pub fn out(buf: &'a mut [u8]) -> Self {
+        Writer {
+            buf: buf,
+            offset: 0,
+        }
+    }
+}
+
+impl<'a> fmt::Write for Writer<'a> {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        let bytes = s.as_bytes();
+        // Skip over already-copied data
+        let remainder = &mut self.buf[self.offset..];
+        // Make the two slices the same length
+        let remainder = &mut remainder[..bytes.len()];
+        // Copy
+        remainder.copy_from_slice(bytes);
+        // Increment offset by number of copied bytes
+        self.offset += bytes.len();
+        Ok(())
+    }
+}
+
 /// Specialized `Result` type
 pub type Result<T> = ::core::result::Result<T, nb::Error<Error>>;