diff --git a/.vscode/launch.json b/.vscode/launch.json
index 1f9250e5f98054cf9176a53f2b6cad3664ce0fed..2b76fa0e1cf361a7bbfb2eee245abd53f26d41cc 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -37,6 +37,23 @@
                 "load"
             ],
             "cwd": "${workspaceRoot}"
+        },
+        {
+            "type": "gdb",
+            "request": "attach",
+            "name": "Debug usart1",
+            "gdbpath": "/usr/bin/arm-none-eabi-gdb",
+            //"executable": ".target/thumbv7em-none-eabihf/debug/examples/hello",
+            "target": ":3333",
+            "remote": true,
+            //"debugger_args": [],
+            "autorun": [
+                "monitor reset halt",
+                "monitor arm semihosting enable",
+                "file ./target/thumbv7em-none-eabihf/debug/examples/usart1",
+                "load"
+            ],
+            "cwd": "${workspaceRoot}"
         }
     ]
 }
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index bcf2c182dc70ce6895b3f6b7a00df6f4ac3e666a..d4e35cba6dfb8546f2370736b85a9236e4246a10 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -7,10 +7,6 @@
             "taskName": "xargo build  --example hello --release",
             "type": "shell",
             "command": "xargo build  --example hello --release",
-            // "group": {
-            //     "kind": "build",
-            //     "isDefault": true
-            // },
             "problemMatcher": [
                 "$rustc"
             ]
@@ -19,10 +15,6 @@
             "taskName": "xargo build --example hello",
             "type": "shell",
             "command": "xargo build --example hello",
-            // "group": {
-            //     "kind": "build",
-            //     "isDefault": true
-            // },
             "problemMatcher": [
                 "$rustc"
             ]
@@ -31,6 +23,14 @@
             "taskName": "xargo build --example gpio",
             "type": "shell",
             "command": "xargo build --example gpio",
+            "problemMatcher": [
+                "$rustc"
+            ]
+        },
+        {
+            "taskName": "xargo build --example usart1",
+            "type": "shell",
+            "command": "xargo build --example usart1",
             "group": {
                 "kind": "build",
                 "isDefault": true
diff --git a/examples/gpio.rs b/examples/gpio.rs
index c806721da2457c85cbd4446378e65eb29f63f668..54b931cdcb7184d7b84eec0b96705e2542997926 100644
--- a/examples/gpio.rs
+++ b/examples/gpio.rs
@@ -7,14 +7,12 @@
 extern crate cortex_m_rtfm as rtfm;
 extern crate cortex_m_semihosting as semihosting;
 extern crate nucleo_64;
-
-use nucleo_64::gpio::PA5;
 extern crate stm32f40x;
 
 use rtfm::app;
 use semihosting::hio;
-
 use core::fmt::Write;
+use nucleo_64::gpio::PA5;
 
 app! {
     device: nucleo_64::stm32f40x,
diff --git a/examples/usart1.1.rs b/examples/usart1.1.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ca0d23bd65dbd8f3b4bdaa512a0bf290f99dcba6
--- /dev/null
+++ b/examples/usart1.1.rs
@@ -0,0 +1,56 @@
+//! Test the USART1 instance
+//!
+//! Connect the TX and RX pins to run this test
+
+#![deny(unsafe_code)]
+#![deny(warnings)]
+#![feature(proc_macro)]
+#![no_std]
+
+extern crate blue_pill;
+extern crate cortex_m_rtfm as rtfm;
+extern crate nb;
+
+use blue_pill::Serial;
+use blue_pill::prelude::*;
+use blue_pill::time::Hertz;
+use rtfm::app;
+
+const BAUD_RATE: Hertz = Hertz(115_200);
+
+app! {
+    device: blue_pill::stm32f103xx,
+}
+
+fn init(p: init::Peripherals) {
+    let serial = Serial(p.USART1);
+
+    serial.init(BAUD_RATE.invert(), p.AFIO, None, p.GPIOA, p.RCC);
+
+    const BYTE: u8 = b'A';
+
+    assert!(serial.write(BYTE).is_ok());
+
+    for _ in 0..1_000 {
+        match serial.read() {
+            Ok(byte) => {
+                assert_eq!(byte, BYTE);
+                return;
+            }
+            Err(nb::Error::Other(e)) => panic!("{:?}", e),
+            Err(nb::Error::WouldBlock) => continue,
+        }
+    }
+
+    panic!("Timeout")
+}
+
+fn idle() -> ! {
+    // OK
+    rtfm::bkpt();
+
+    // Sleep
+    loop {
+        rtfm::wfi();
+    }
+}
diff --git a/examples/usart1.rs b/examples/usart1.rs
index ca0d23bd65dbd8f3b4bdaa512a0bf290f99dcba6..9b9ea4bd350b609a038ec0a396484665b2994e43 100644
--- a/examples/usart1.rs
+++ b/examples/usart1.rs
@@ -1,38 +1,120 @@
 //! Test the USART1 instance
 //!
 //! Connect the TX and RX pins to run this test
-
-#![deny(unsafe_code)]
-#![deny(warnings)]
+//!
+//! PA2 (TX), PA3(RX) on the MCU is connected to the pin header CN3
+//#![deny(unsafe_code)]
+//#![deny(warnings)]
+#![allow(warnings)]
 #![feature(proc_macro)]
 #![no_std]
 
-extern crate blue_pill;
 extern crate cortex_m_rtfm as rtfm;
+extern crate cortex_m_semihosting as semihosting;
 extern crate nb;
+extern crate nucleo_64;
+extern crate stm32f40x;
 
-use blue_pill::Serial;
-use blue_pill::prelude::*;
-use blue_pill::time::Hertz;
+//use nucleo_64::Serial;
+use nucleo_64::prelude::*;
+use nucleo_64::time::Hertz;
+use semihosting::hio;
+use core::fmt::Write;
 use rtfm::app;
+use core::ops::Deref;
+use core::ptr;
+use nucleo_64::apb1;
 
 const BAUD_RATE: Hertz = Hertz(115_200);
 
 app! {
-    device: blue_pill::stm32f103xx,
+    device: nucleo_64::stm32f40x,
 }
 
+use stm32f40x::{gpioa, DMA1, USART1, USART2, USART3, usart6, GPIOA, GPIOB, RCC};
+
+
+#[inline(never)]
 fn init(p: init::Peripherals) {
-    let serial = Serial(p.USART1);
+    writeln!(hio::hstdout().unwrap(), "Init!").unwrap();
+    // RM0368 6.3.9
+    // enable clock to GPIOA, USART2
+    p.RCC.ahb1enr.modify(|_, w| w.gpioaen().enable());
+
+    // enable clock to
+    p.RCC.apb1enr.modify(|_, w| w.usart2en().bit(true));
+
+    // PA2 = TX, PA3 = RX
+    // p.AFIO.mapr.modify(|_, w| w.usart2_remap().clear_bit());
+
+
+    // RM0368 8.4.1
+    // set output mode for GPIOA
+    // PA2 = TX (output mode), PA3 = RX (input mode)
+    p.GPIOA.moder.modify(|_, w| {
+        w.moder2()
+            .variant(stm32f40x::gpioa::moder::MODER15W::ALTERNATEMODE)
+            .moder3()
+            .variant(stm32f40x::gpioa::moder::MODER15W::ALTERNATEMODE)
+    });
+
+
+    // we don't care about the speed register atm
+    // DM00102166
+    // AF7, Table 9
+    // PA2 and PA3 is connected to USART2 TX and RX respectively
+    p.GPIOA.afrl.modify(|_, w| w.afrl2().af7().afrl3().af7());
+
+    // 8N1, stop bit
+    p.USART2.cr2.write(|w| unsafe { w.stop().bits(0b00) });
+
+    // baud rate
+    //    let brr :<U::Ticks>= BAUD_RATE.into();
+    let brr: apb1::Ticks = BAUD_RATE.invert().into();
+    let brr = brr.0;
+    assert!(brr >= 16, "impossible baud rate");
+
+    p.USART2.brr.write(|w| unsafe { w.bits(brr) });
+
+    // disable hardware flow control
+    // enable DMA TX and RX transfers
+    p.USART2.cr3.write(|w| {
+        w.rtse() /* Ready To Send disable */
+            .clear_bit()
+            .ctse() /* Clear To Send disable */
+            .clear_bit()
+            .dmat() /* Enable DMA Transmit */
+            .set_bit()
+            .dmar()  /* Enable DMA Receive */
+            .set_bit()
+    });
 
-    serial.init(BAUD_RATE.invert(), p.AFIO, None, p.GPIOA, p.RCC);
+    // enable TX, RX; disable parity checking
+    p.USART2.cr1.write(|w| {
+        w.ue() /* Usart Enable */
+            .set_bit()
+            .re() /* Receiver Enable */
+            .set_bit()
+            .te() /* Transmitter Enable */
+            .set_bit()
+            .m() /* Word Length, 8 */
+            .clear_bit()
+            .pce() /* Parity Control Enable */
+            .clear_bit()
+            .rxneie() /* Reception Interrupt Enable */
+            .clear_bit()
+    });
+
+    // let serial = Serial(p.USART1);
+
+    // serial.init(BAUD_RATE.invert(), p.AFIO, None, p.GPIOA, p.RCC);
 
     const BYTE: u8 = b'A';
 
-    assert!(serial.write(BYTE).is_ok());
+    assert!(write(p.USART2, BYTE).is_ok());
 
     for _ in 0..1_000 {
-        match serial.read() {
+        match read(p.USART2) {
             Ok(byte) => {
                 assert_eq!(byte, BYTE);
                 return;
@@ -41,10 +123,61 @@ fn init(p: init::Peripherals) {
             Err(nb::Error::WouldBlock) => continue,
         }
     }
-
     panic!("Timeout")
 }
 
+// Specialized `Result` type
+pub type Result<T> = ::core::result::Result<T, nb::Error<Error>>;
+
+/// An error
+#[derive(Debug)]
+pub enum Error {
+    /// De-synchronization, excessive noise or a break character detected
+    Framing,
+    /// Noise detected in the received frame
+    Noise,
+    /// RX buffer overrun
+    Overrun,
+    #[doc(hidden)] _Extensible,
+}
+fn write(usart2: &USART2, byte: u8) -> Result<()> {
+    let sr = usart2.sr.read();
+
+    if sr.ore().bit_is_set() {
+        Err(nb::Error::Other(Error::Overrun))
+    } else if sr.nf().bit_is_set() {
+        Err(nb::Error::Other(Error::Noise))
+    } else if sr.fe().bit_is_set() {
+        Err(nb::Error::Other(Error::Framing))
+    } else if sr.txe().bit_is_set() {
+        // NOTE(write_volatile) see NOTE in the `read` method
+        unsafe { ptr::write_volatile(&usart2.dr as *const _ as *mut u8, byte) }
+        Ok(())
+    } else {
+        Err(nb::Error::WouldBlock)
+    }
+}
+
+fn read(usart2: &USART2) -> Result<u8> {
+    let sr = usart2.sr.read();
+
+    if sr.ore().bit_is_set() {
+        Err(nb::Error::Other(Error::Overrun))
+    } else if sr.nf().bit_is_set() {
+        Err(nb::Error::Other(Error::Noise))
+    } else if sr.fe().bit_is_set() {
+        Err(nb::Error::Other(Error::Framing))
+    } else if sr.rxne().bit_is_set() {
+        // NOTE(read_volatile) the register is 9 bits big but we'll only
+        // work with the first 8 bits
+        Ok(unsafe {
+            ptr::read_volatile(&usart2.dr as *const _ as *const u8)
+        })
+    } else {
+        Err(nb::Error::WouldBlock)
+    }
+}
+
 fn idle() -> ! {
     // OK
     rtfm::bkpt();
diff --git a/src/lib.rs b/src/lib.rs
index 19dc3f41f2c96c2c91baa07bbba2829d9820f735..0f57797788ead322b0adf5fff07ed04e7ea1708b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -38,7 +38,7 @@ pub mod gpio;
 // pub mod rtc;
 // pub mod serial;
 // pub mod spi;
-// pub mod time;
+pub mod time;
 // pub mod timer;
 pub use hal::prelude;
 
@@ -120,17 +120,22 @@ macro_rules! frequency {
     }
 }
 
-// /// Advance High-performance Bus (AHB)
-// pub mod ahb {
-//     frequency!(8_000_000);
-// }
+/// Advance High-performance Bus (AHA)
+pub mod ahb1 {
+    frequency!(16_000_000);
+}
 
-// /// Advance Peripheral Bus 1 (APB1)
-// pub mod apb1 {
-//     frequency!(8_000_000);
-// }
+/// Advance High-performance Bus (AHB)
+pub mod ahb2 {
+    frequency!(16_000_000);
+}
 
-// /// Advance Peripheral Bus 2 (APB2)
-// pub mod apb2 {
-//     frequency!(8_000_000);
-// }
+/// Advance Peripheral Bus 1 (APB1)
+pub mod apb1 {
+    frequency!(16_000_000);
+}
+
+/// Advance Peripheral Bus 2 (APB2)
+pub mod apb2 {
+    frequency!(16_000_000);
+}
diff --git a/src/serial.1.rs b/src/serial.1.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4c9c11c16061e50056b69aa7600059bbde365819
--- /dev/null
+++ b/src/serial.1.rs
@@ -0,0 +1,460 @@
+//! Serial interface
+//!
+//! You can use the `Serial` interface with these USART instances
+//!
+//! # USART1
+//!
+//! - TX = PA9
+//! - RX = PA10
+//! - Interrupt = USART1
+//!
+//! # USART2
+//!
+//! - TX = PA2
+//! - RX = PA3
+//! - Interrupt = USART2
+//!
+//! # USART3
+//!
+//! - TX = PB10
+//! - RX = PB11
+//! - Interrupt = USART3
+
+use core::any::{Any, TypeId};
+use core::marker::Unsize;
+use core::ops::Deref;
+use core::ptr;
+
+use cast::u16;
+use hal;
+use nb;
+use static_ref::Static;
+use stm32f103xx::{gpioa, DMA1, USART1, USART2, USART3, usart1, AFIO, GPIOA,
+                  GPIOB, RCC};
+
+use dma::{self, Buffer, Dma1Channel4, Dma1Channel5};
+
+/// Specialized `Result` type
+pub type Result<T> = ::core::result::Result<T, nb::Error<Error>>;
+
+/// IMPLEMENTATION DETAIL
+pub unsafe trait Usart: Deref<Target = usart1::RegisterBlock> {
+    /// IMPLEMENTATION DETAIL
+    type GPIO: Deref<Target = gpioa::RegisterBlock>;
+    /// IMPLEMENTATION DETAIL
+    type Ticks: Into<u32>;
+}
+
+unsafe impl Usart for USART1 {
+    type GPIO = GPIOA;
+    type Ticks = ::apb2::Ticks;
+}
+
+unsafe impl Usart for USART2 {
+    type GPIO = GPIOA;
+    type Ticks = ::apb1::Ticks;
+}
+
+unsafe impl Usart for USART3 {
+    type GPIO = GPIOB;
+    type Ticks = ::apb1::Ticks;
+}
+
+/// An error
+#[derive(Debug)]
+pub enum Error {
+    /// De-synchronization, excessive noise or a break character detected
+    Framing,
+    /// Noise detected in the received frame
+    Noise,
+    /// RX buffer overrun
+    Overrun,
+    #[doc(hidden)]
+    _Extensible,
+}
+
+/// Interrupt event
+pub enum Event {
+    /// RX buffer Not Empty (new data available)
+    Rxne,
+    /// Transmission Complete
+    Tc,
+    /// TX buffer Empty (more data can be send)
+    Txe,
+}
+
+/// Serial interface
+///
+/// # Interrupts
+///
+/// - RXNE
+pub struct Serial<'a, U>(pub &'a U)
+where
+    U: Any + Usart;
+
+impl<'a, U> Clone for Serial<'a, U>
+where
+    U: Any + Usart,
+{
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl<'a, U> Copy for Serial<'a, U>
+where
+    U: Any + Usart,
+{
+}
+
+impl<'a, U> Serial<'a, U>
+where
+    U: Any + Usart,
+{
+    /// Initializes the serial interface with a baud rate of `baut_rate` bits
+    /// per second
+    ///
+    /// The serial interface will be configured to use 8 bits of data, 1 stop
+    /// bit, no hardware control and to omit parity checking
+    pub fn init<B>(
+        &self,
+        baud_rate: B,
+        afio: &AFIO,
+        dma1: Option<&DMA1>,
+        gpio: &U::GPIO,
+        rcc: &RCC,
+    ) where
+        B: Into<U::Ticks>,
+    {
+        self._init(baud_rate.into(), afio, dma1, gpio, rcc)
+    }
+
+    fn _init(
+        &self,
+        baud_rate: U::Ticks,
+        afio: &AFIO,
+        dma1: Option<&DMA1>,
+        gpio: &U::GPIO,
+        rcc: &RCC,
+    ) {
+        let usart = self.0;
+
+        // power up peripherals
+        if dma1.is_some() {
+            rcc.ahbenr.modify(|_, w| w.dma1en().enabled());
+        }
+        if usart.get_type_id() == TypeId::of::<USART1>() {
+            rcc.apb2enr.modify(|_, w| {
+                w.afioen().enabled().iopaen().enabled().usart1en().enabled()
+            });
+        } else if usart.get_type_id() == TypeId::of::<USART2>() {
+            rcc.apb1enr.modify(|_, w| w.usart2en().enabled());
+            rcc.apb2enr
+                .modify(|_, w| w.afioen().enabled().iopaen().enabled());
+        } else if usart.get_type_id() == TypeId::of::<USART3>() {
+            rcc.apb1enr.modify(|_, w| w.usart3en().enabled());
+            rcc.apb2enr
+                .modify(|_, w| w.afioen().enabled().iopben().enabled());
+        }
+
+        if usart.get_type_id() == TypeId::of::<USART1>() {
+            // PA9 = TX, PA10 = RX
+            afio.mapr.modify(|_, w| w.usart1_remap().clear_bit());
+            gpio.crh.modify(|_, w| {
+                w.mode9()
+                    .output()
+                    .cnf9()
+                    .alt_push()
+                    .mode10()
+                    .input()
+                    .cnf10()
+                    .bits(0b01)
+            });
+        } else if usart.get_type_id() == TypeId::of::<USART2>() {
+            // PA2 = TX, PA3 = RX
+            afio.mapr.modify(|_, w| w.usart2_remap().clear_bit());
+            gpio.crl.modify(|_, w| {
+                w.mode2()
+                    .output()
+                    .cnf2()
+                    .alt_push()
+                    .mode3()
+                    .input()
+                    .cnf3()
+                    .bits(0b01)
+            });
+        } else if usart.get_type_id() == TypeId::of::<USART3>() {
+            // PB10 = TX, PB11 = RX
+            afio.mapr
+                .modify(|_, w| unsafe { w.usart3_remap().bits(0b00) });
+            gpio.crh.modify(|_, w| {
+                w.mode10()
+                    .output()
+                    .cnf10()
+                    .alt_push()
+                    .mode11()
+                    .input()
+                    .cnf11()
+                    .bits(0b01)
+            });
+        }
+
+        if let Some(dma1) = dma1 {
+            if usart.get_type_id() == TypeId::of::<USART1>() {
+                // TX DMA transfer
+                // mem2mem: Memory to memory mode disabled
+                // pl: Medium priority
+                // msize: Memory size = 8 bits
+                // psize: Peripheral size = 8 bits
+                // minc: Memory increment mode enabled
+                // pinc: Peripheral increment mode disabled
+                // circ: Circular mode disabled
+                // dir: Transfer from memory to peripheral
+                // tceie: Transfer complete interrupt enabled
+                // en: Disabled
+                dma1.ccr4.write(|w| unsafe {
+                    w.mem2mem()
+                        .clear_bit()
+                        .pl()
+                        .bits(0b01)
+                        .msize()
+                        .bits(0b00)
+                        .psize()
+                        .bits(0b00)
+                        .minc()
+                        .set_bit()
+                        .circ()
+                        .clear_bit()
+                        .pinc()
+                        .clear_bit()
+                        .dir()
+                        .set_bit()
+                        .tcie()
+                        .set_bit()
+                        .en()
+                        .clear_bit()
+                });
+
+                // RX DMA transfer
+                // mem2mem: Memory to memory mode disabled
+                // pl: Medium priority
+                // msize: Memory size = 8 bits
+                // psize: Peripheral size = 8 bits
+                // minc: Memory increment mode enabled
+                // pinc: Peripheral increment mode disabled
+                // circ: Circular mode disabled
+                // dir: Transfer from peripheral to memory
+                // tceie: Transfer complete interrupt enabled
+                // en: Disabled
+                dma1.ccr5.write(|w| unsafe {
+                    w.mem2mem()
+                        .clear_bit()
+                        .pl()
+                        .bits(0b01)
+                        .msize()
+                        .bits(0b00)
+                        .psize()
+                        .bits(0b00)
+                        .minc()
+                        .set_bit()
+                        .circ()
+                        .clear_bit()
+                        .pinc()
+                        .clear_bit()
+                        .dir()
+                        .clear_bit()
+                        .tcie()
+                        .set_bit()
+                        .en()
+                        .clear_bit()
+                });
+            } else {
+                // TODO enable DMA for USART{2,3}
+                unimplemented!()
+            }
+        }
+
+        // 8N1
+        usart.cr2.write(|w| unsafe { w.stop().bits(0b00) });
+
+        // baud rate
+        let brr = baud_rate.into();
+
+        assert!(brr >= 16, "impossible baud rate");
+
+        usart.brr.write(|w| unsafe { w.bits(brr) });
+
+        // disable hardware flow control
+        // enable DMA TX and RX transfers
+        usart.cr3.write(|w| {
+            w.rtse()
+                .clear_bit()
+                .ctse()
+                .clear_bit()
+                .dmat()
+                .set_bit()
+                .dmar()
+                .set_bit()
+        });
+
+        // enable TX, RX; disable parity checking
+        usart.cr1.write(|w| {
+            w.ue()
+                .set_bit()
+                .re()
+                .set_bit()
+                .te()
+                .set_bit()
+                .m()
+                .clear_bit()
+                .pce()
+                .clear_bit()
+                .rxneie()
+                .clear_bit()
+        });
+    }
+
+    /// Starts listening for an interrupt `event`
+    pub fn listen(&self, event: Event) {
+        let usart = self.0;
+
+        match event {
+            Event::Rxne => usart.cr1.modify(|_, w| w.rxneie().set_bit()),
+            Event::Tc => usart.cr1.modify(|_, w| w.tcie().set_bit()),
+            Event::Txe => usart.cr1.modify(|_, w| w.txeie().set_bit()),
+        }
+    }
+
+    /// Stops listening for an interrupt `event`
+    pub fn unlisten(&self, event: Event) {
+        let usart = self.0;
+
+        match event {
+            Event::Rxne => usart.cr1.modify(|_, w| w.rxneie().clear_bit()),
+            Event::Tc => usart.cr1.modify(|_, w| w.tcie().clear_bit()),
+            Event::Txe => usart.cr1.modify(|_, w| w.txeie().clear_bit()),
+        }
+    }
+}
+
+impl<'a, U> hal::serial::Read<u8> for Serial<'a, U>
+where
+    U: Any + Usart,
+{
+    type Error = Error;
+
+    fn read(&self) -> Result<u8> {
+        let usart1 = self.0;
+        let sr = usart1.sr.read();
+
+        if sr.ore().bit_is_set() {
+            Err(nb::Error::Other(Error::Overrun))
+        } else if sr.ne().bit_is_set() {
+            Err(nb::Error::Other(Error::Noise))
+        } else if sr.fe().bit_is_set() {
+            Err(nb::Error::Other(Error::Framing))
+        } else if sr.rxne().bit_is_set() {
+            // NOTE(read_volatile) the register is 9 bits big but we'll only
+            // work with the first 8 bits
+            Ok(unsafe {
+                ptr::read_volatile(&usart1.dr as *const _ as *const u8)
+            })
+        } else {
+            Err(nb::Error::WouldBlock)
+        }
+    }
+}
+
+impl<'a, U> hal::serial::Write<u8> for Serial<'a, U>
+where
+    U: Any + Usart,
+{
+    type Error = Error;
+
+    fn write(&self, byte: u8) -> Result<()> {
+        let usart1 = self.0;
+        let sr = usart1.sr.read();
+
+        if sr.ore().bit_is_set() {
+            Err(nb::Error::Other(Error::Overrun))
+        } else if sr.ne().bit_is_set() {
+            Err(nb::Error::Other(Error::Noise))
+        } else if sr.fe().bit_is_set() {
+            Err(nb::Error::Other(Error::Framing))
+        } else if sr.txe().bit_is_set() {
+            // NOTE(write_volatile) see NOTE in the `read` method
+            unsafe {
+                ptr::write_volatile(&usart1.dr as *const _ as *mut u8, byte)
+            }
+            Ok(())
+        } else {
+            Err(nb::Error::WouldBlock)
+        }
+    }
+}
+
+impl<'a> Serial<'a, USART1> {
+    /// Starts a DMA transfer to receive serial data into a `buffer`
+    ///
+    /// This will mutably lock the `buffer` preventing borrowing its contents
+    /// The `buffer` can be `release`d after the DMA transfer finishes
+    // TODO support circular mode + half transfer interrupt as a double
+    // buffering mode
+    pub fn read_exact<B>(
+        &self,
+        dma1: &DMA1,
+        buffer: &Static<Buffer<B, Dma1Channel5>>,
+    ) -> ::core::result::Result<(), dma::Error>
+    where
+        B: Unsize<[u8]>,
+    {
+        let usart1 = self.0;
+
+        if dma1.ccr5.read().en().bit_is_set() {
+            return Err(dma::Error::InUse);
+        }
+
+        let buffer: &mut [u8] = buffer.lock_mut();
+
+        dma1.cndtr5
+            .write(|w| unsafe { w.ndt().bits(u16(buffer.len()).unwrap()) });
+        dma1.cpar5
+            .write(|w| unsafe { w.bits(&usart1.dr as *const _ as u32) });
+        dma1.cmar5
+            .write(|w| unsafe { w.bits(buffer.as_ptr() as u32) });
+        dma1.ccr5.modify(|_, w| w.en().set_bit());
+
+        Ok(())
+    }
+
+    /// Starts a DMA transfer to send `buffer` through this serial port
+    ///
+    /// This will immutably lock the `buffer` preventing mutably borrowing its
+    /// contents. The `buffer` can be `release`d after the DMA transfer finishes
+    pub fn write_all<B>(
+        &self,
+        dma1: &DMA1,
+        buffer: &Static<Buffer<B, Dma1Channel4>>,
+    ) -> ::core::result::Result<(), dma::Error>
+    where
+        B: Unsize<[u8]>,
+    {
+        let usart1 = self.0;
+
+        if dma1.ccr4.read().en().bit_is_set() {
+            return Err(dma::Error::InUse);
+        }
+
+        let buffer: &[u8] = buffer.lock();
+
+        dma1.cndtr4
+            .write(|w| unsafe { w.ndt().bits(u16(buffer.len()).unwrap()) });
+        dma1.cpar4
+            .write(|w| unsafe { w.bits(&usart1.dr as *const _ as u32) });
+        dma1.cmar4
+            .write(|w| unsafe { w.bits(buffer.as_ptr() as u32) });
+        dma1.ccr4.modify(|_, w| w.en().set_bit());
+
+        Ok(())
+    }
+}
diff --git a/src/serial.rs b/src/serial.rs
index 4c9c11c16061e50056b69aa7600059bbde365819..ef86e05dea2274530f9ff009821fb61cdb6dbf5b 100644
--- a/src/serial.rs
+++ b/src/serial.rs
@@ -29,16 +29,16 @@ use cast::u16;
 use hal;
 use nb;
 use static_ref::Static;
-use stm32f103xx::{gpioa, DMA1, USART1, USART2, USART3, usart1, AFIO, GPIOA,
-                  GPIOB, RCC};
+use stm32f40x::{gpioa, DMA1, USART1, USART2, USART3, usart6,
+                /*AFIO, */ GPIOA, GPIOB, RCC};
 
-use dma::{self, Buffer, Dma1Channel4, Dma1Channel5};
+//use dma::{self, Buffer, Dma1Channel4, Dma1Channel5};
 
 /// Specialized `Result` type
 pub type Result<T> = ::core::result::Result<T, nb::Error<Error>>;
 
 /// IMPLEMENTATION DETAIL
-pub unsafe trait Usart: Deref<Target = usart1::RegisterBlock> {
+pub unsafe trait Usart: Deref<Target = usart6::RegisterBlock> {
     /// IMPLEMENTATION DETAIL
     type GPIO: Deref<Target = gpioa::RegisterBlock>;
     /// IMPLEMENTATION DETAIL
@@ -69,8 +69,7 @@ pub enum Error {
     Noise,
     /// RX buffer overrun
     Overrun,
-    #[doc(hidden)]
-    _Extensible,
+    #[doc(hidden)] _Extensible,
 }
 
 /// Interrupt event