diff --git a/examples/pwm1.rs b/examples/pwm1.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f939fd454fe249bebcb2d8cc8575b960b388c539
--- /dev/null
+++ b/examples/pwm1.rs
@@ -0,0 +1,45 @@
+//! Output a PWM with a duty cycle of ~6% on all the channels of TIM1
+// FIXME doesn't seem to work :-(
+
+#![deny(unsafe_code)]
+#![deny(warnings)]
+#![feature(proc_macro)]
+#![no_std]
+
+extern crate f4;
+extern crate cortex_m_rtfm as rtfm;
+
+use f4::prelude::*;
+use f4::time::Hertz;
+use f4::{Channel, Pwm};
+use rtfm::app;
+
+const FREQUENCY: Hertz = Hertz(10_000);
+
+app! {
+    device: f4::stm32f40x,
+}
+
+fn init(p: init::Peripherals) {
+    let pwm = Pwm(p.TIM3);
+
+    pwm.init(FREQUENCY.invert(), None, p.GPIOA,p.GPIOB,p.GPIOC, p.RCC);
+    let duty = pwm.get_max_duty() / 16;
+
+    const CHANNELS: [Channel; 4] = [Channel::_1, Channel::_2, Channel::_3, Channel::_4];
+
+    for c in &CHANNELS {
+        pwm.set_duty(*c, duty);
+    }
+
+    for c in &CHANNELS {
+        pwm.enable(*c);
+        rtfm::bkpt();
+    }
+}
+
+fn idle() -> ! {
+    loop {
+        rtfm::wfi();
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 34744a15a1776828e6c1d87a3d27d40bc1159420..419783c40fc90d8f92ee9443a8a777e94c587f87 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -40,6 +40,7 @@ pub mod led;
 pub mod serial;
 pub mod timer;
 pub mod time;
+pub mod pwm;
 
 pub mod frequency;
 use frequency::*;
@@ -47,4 +48,4 @@ use frequency::*;
 pub use hal::prelude;
 pub use serial::Serial;
 pub use timer::{Channel, Timer};
-
+pub use pwm::Pwm;
diff --git a/src/pwm.rs b/src/pwm.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a5e8e0153b66ae9ce223cf1c5ceed0ffda1168e6
--- /dev/null
+++ b/src/pwm.rs
@@ -0,0 +1,427 @@
+//! Pulse Width Modulation
+//!
+//! You can use the `Pwm` interface with these TIM instances
+//!
+//! # TIM1
+//!
+//! - CH1 = PA8
+//! - CH2 = PA9
+//! - CH3 = PA10
+//! - CH4 = PA11
+//!
+//! # TIM2
+//!
+//! - CH1 = PA0
+//! - CH2 = PA1
+//! - CH3 = PB10
+//! - CH4 = PA3 (Unimplemented: conflicts with USB USART2_RX)
+//!
+//! # TIM3
+//!
+//! - CH1 = PA6
+//! - CH2 = PC7
+//! - CH3 = PB0
+//! - CH4 = PB1
+//!
+//! # TIM4
+//!
+//! - CH1 = PB6
+//! - CH2 = PB7
+//! - CH3 = PB8
+//! - CH4 = PB9
+
+use core::any::{Any, TypeId};
+// use core::marker::Unsize;
+
+use cast::{u16, u32};
+use hal;
+// use static_ref::Static;
+use stm32f40x::{DMA1, TIM1, TIM2, TIM3, TIM4, GPIOA, GPIOB, GPIOC, RCC};
+
+// use dma::{self, Buffer, Dma1Channel2};
+use timer::{Channel};
+
+/// PWM driver
+pub struct Pwm<'a, T>(pub &'a T)
+where
+    T: 'a;
+
+macro_rules! impl_Pwm {
+    ($TIM:ident, $APB:ident) => {
+        impl<'a> Pwm<'a, $TIM>
+        {
+            /// Initializes the PWM module
+            pub fn init<P>(
+                &self,
+                period: P,
+                dma1: Option<&DMA1>,
+                gpioa: &GPIOA,
+                gpiob: &GPIOB,
+                gpioc: &GPIOC,
+                rcc: &RCC,
+            ) where
+                P: Into<::$APB::Ticks>,
+            {
+                self._init(period.into(), dma1, gpioa, gpiob, gpioc, rcc)
+            }
+
+            fn _init(
+                &self,
+                period: ::$APB::Ticks,
+                dma1: Option<&DMA1>,
+                gpioa: &GPIOA,
+                gpiob: &GPIOB,
+                gpioc: &GPIOC,
+                rcc: &RCC,
+            ) {
+                let tim = self.0;
+
+                // enable AFIO, (DMA1), TIMx and GPIOx
+                if dma1.is_some() {
+                    rcc.ahb1enr.modify(|_, w| w.dma1en().set_bit());
+                }
+
+                if tim.get_type_id() == TypeId::of::<TIM1>() {
+                    rcc.apb2enr.modify(|_, w| w.tim1en().set_bit());
+                } else if tim.get_type_id() == TypeId::of::<TIM2>() {
+                    rcc.apb1enr.modify(|_, w| w.tim2en().set_bit());
+                } else if tim.get_type_id() == TypeId::of::<TIM3>() {
+                    rcc.apb1enr.modify(|_, w| w.tim3en().set_bit());
+                } else if tim.get_type_id() == TypeId::of::<TIM4>() {
+                    rcc.apb1enr.modify(|_, w| w.tim4en().set_bit());
+                }
+
+                rcc.ahb1enr.modify(|_, w| {
+                    if tim.get_type_id() == TypeId::of::<TIM1>() {
+                        w.gpioaen().set_bit()
+                    } else if tim.get_type_id() == TypeId::of::<TIM2>() {
+                        w.gpioaen().set_bit().gpioben().set_bit()
+                    } else if tim.get_type_id() == TypeId::of::<TIM3>() {
+                        w.gpioaen().set_bit().gpioben().set_bit().gpiocen().set_bit()
+                    } else if tim.get_type_id() == TypeId::of::<TIM4>() {
+                        w.gpioben().set_bit()
+                    } else {
+                        unreachable!()
+                    }
+                });
+
+                if tim.get_type_id() == TypeId::of::<TIM2>() {
+                    // CH1 = PA0 = alternate push-pull
+                    // CH2 = PA1 = alternate push-pull
+                    // CH3 = PB10 = alternate push-pull
+                    // CH4 = PA3 = alternate push-pull (Unimplemented: conflicts with USB USART2_RX)
+
+                    // See datasheet DM00115249 Table 9. Alternate function mapping
+                    gpioa.afrl.modify(|_, w| {
+                        w
+                        .afrl0().bits(1)
+                        .afrl1().bits(1)
+                    });
+                    gpioa.moder.modify(|_, w| {
+                        w
+                        .moder0().bits(2)
+                        .moder1().bits(2)
+                    });
+                    gpiob.afrh.modify(|_, w| { unsafe {
+                        w
+                        .afrh10().bits(1)}
+                    });
+                    gpiob.moder.modify(|_, w| { unsafe {
+                        w
+                        .moder10().bits(2)
+                    }
+                    });
+                } else if tim.get_type_id() == TypeId::of::<TIM3>() {
+                    // CH1 = PA6 = alternate push-pull
+                    // CH2 = PC7 = alternate push-pull
+                    // CH3 = PB0 = alternate push-pull
+                    // CH4 = PB1 = alternate push-pull
+                    gpioa.afrl.modify(|_, w| {
+                        w.afrl6().bits(2)
+                    });
+                    gpioa.moder.modify(|_, w| {
+                        w.moder6().bits(2)
+                    });
+                    gpiob.afrl.modify(|_, w| { unsafe {
+                        w.afrl0().bits(2)
+                        .afrl1().bits(2)
+                        }
+                    });
+                    gpiob.moder.modify(|_, w| { unsafe {
+                        w.moder0().bits(2)
+                        .moder1().bits(2)
+                        }
+                    });
+                    gpioc.afrl.modify(|_, w| { unsafe {
+                        w.afrl7().bits(2)
+                        }
+                    });
+                    gpioc.moder.modify(|_, w| { unsafe {
+                        w.moder7().bits(2)
+                        }
+                    });    
+
+                } else if tim.get_type_id() == TypeId::of::<TIM4>() {
+                    // CH1 = PB6 = alternate push-pull
+                    // CH2 = PB7 = alternate push-pull
+                    // CH3 = PB8 = alternate push-pull
+                    // CH4 = PB9 = alternate push-pull
+                    gpiob.afrl.modify(|_, w| { unsafe {
+                        w.afrl6().bits(2)
+                        .afrl7().bits(2)
+                        }
+                    });
+                    gpiob.moder.modify(|_, w| { unsafe {
+                        w.moder6().bits(2)
+                        .moder7().bits(2)
+                        }
+                    });
+                    gpiob.afrh.modify(|_, w| { unsafe {
+                        w.afrh8().bits(2)
+                        .afrh9().bits(2)
+                        }
+                    });
+                    gpiob.moder.modify(|_, w| { unsafe {
+                        w.moder8().bits(2)
+                        .moder9().bits(2)
+                        }
+                    });
+                }
+
+                // PWM mode 1
+                if tim.get_type_id() == TypeId::of::<TIM2>() {
+                    tim.ccmr1_output.modify(|_, w| unsafe {
+                        w.oc1pe()
+                            .set_bit()
+                            .oc1m()
+                            .bits(0b110)
+                            .oc2pe()
+                            .set_bit()
+                            .oc2m()
+                            .bits(0b110)
+                    });
+                    tim.ccmr2_output.modify(|_, w| unsafe {
+                        w.oc3pe()
+                            .set_bit()
+                            .oc3m()
+                            .bits(0b110)
+                    });
+                    tim.ccer
+                        .modify(|_, w| w.cc1p().clear_bit().cc2p().clear_bit().cc3p().clear_bit());
+                } else {
+                    tim.ccmr1_output.modify(|_, w| unsafe {
+                        w.oc1pe()
+                            .set_bit()
+                            .oc1m()
+                            .bits(0b110)
+                            .oc2pe()
+                            .set_bit()
+                            .oc2m()
+                            .bits(0b110)
+                    });
+
+                    tim.ccmr2_output.modify(|_, w| unsafe {
+                        w.oc3pe()
+                            .set_bit()
+                            .oc3m()
+                            .bits(0b110)
+                            .oc4pe()
+                            .set_bit()
+                            .oc4m()
+                            .bits(0b110)
+                    });
+
+                    tim.ccer.modify(|_, w| {
+                        w.cc1p()
+                            .clear_bit()
+                            .cc2p()
+                            .clear_bit()
+                            .cc3p()
+                            .clear_bit()
+                            .cc4p()
+                            .clear_bit()
+                    });
+                }
+
+                self._set_period(period);
+
+                // if let Some(dma1) = dma1 {
+                //     tim2.dier.modify(|_, w| w.ude().set_bit());
+
+                //     if tim2.get_type_id() == TypeId::of::<TIM2>() {
+                //         // TIM2_UP
+                //         // mem2mem: Memory to memory mode disabled
+                //         // pl: Medium priority
+                //         // msize: Memory size = 8 bits
+                //         // psize: Peripheral size = 16 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.ccr2.write(|w| unsafe {
+                //             w.mem2mem()
+                //                 .clear_bit()
+                //                 .pl()
+                //                 .bits(0b01)
+                //                 .msize()
+                //                 .bits(0b00)
+                //                 .psize()
+                //                 .bits(0b01)
+                //                 .minc()
+                //                 .set_bit()
+                //                 .pinc()
+                //                 .clear_bit()
+                //                 .circ()
+                //                 .clear_bit()
+                //                 .dir()
+                //                 .set_bit()
+                //                 .tcie()
+                //                 .set_bit()
+                //                 .en()
+                //                 .clear_bit()
+                //         });
+                //     } else {
+                //         unimplemented!()
+                //     }
+                // }
+
+                tim.cr1.write(|w| unsafe {
+                    w.cms()
+                        .bits(0b00)
+                        .dir()
+                        .bit(false)
+                        .opm()
+                        .bit(false)
+                        .cen()
+                        .set_bit()
+                });
+            }
+
+            fn _set_period(&self, period: ::$APB::Ticks) {
+                let period = period.0;
+
+                let psc = u16((period - 1) / (1 << 16)).unwrap();
+                self.0.psc.write(|w| unsafe{w.psc().bits(psc)});
+
+                let arr = u32(period / u32(psc + 1));
+                self.0.arr.write(|w| unsafe{w.bits(arr)});
+            }
+
+            // /// Uses `buffer` to continuously change the duty cycle on every period
+            // pub fn set_duties<B>(
+            //     &self,
+            //     dma1: &DMA1,
+            //     channel: Channel,
+            //     buffer: &Static<Buffer<B, Dma1Channel2>>,
+            // ) -> ::core::result::Result<(), dma::Error>
+            // where
+            //     B: Unsize<[u8]>,
+            // {
+            //     let tim2 = self.0;
+
+            //     if tim2.get_type_id() == TypeId::of::<TIM2>() {
+            //         if dma1.ccr2.read().en().bit_is_set() {
+            //             return Err(dma::Error::InUse);
+            //         }
+
+            //         let buffer: &[u8] = buffer.lock();
+
+            //         dma1.cndtr2
+            //             .write(|w| unsafe { w.ndt().bits(u16(buffer.len()).unwrap()) });
+            //         dma1.cpar2.write(|w| unsafe {
+            //             match channel {
+            //                 Channel::_1 => w.bits(&tim2.ccr1 as *const _ as u32),
+            //                 Channel::_2 => w.bits(&tim2.ccr2 as *const _ as u32),
+            //                 Channel::_3 => w.bits(&tim2.ccr3 as *const _ as u32),
+            //                 Channel::_4 => w.bits(&tim2.ccr4 as *const _ as u32),
+            //             }
+            //         });
+            //         dma1.cmar2
+            //             .write(|w| unsafe { w.bits(buffer.as_ptr() as u32) });
+            //         dma1.ccr2.modify(|_, w| w.en().set_bit());
+
+            //         Ok(())
+
+            //     } else {
+            //         unimplemented!()
+            //     }
+            // }
+        }
+
+        impl<'a> hal::Pwm for Pwm<'a, $TIM>
+        {
+            type Channel = Channel;
+            type Duty = u32;
+            type Time = ::$APB::Ticks;
+
+            fn get_duty(&self, channel: Channel) -> u32 {
+                // if self.0.get_type_id() == TypeId::of::<TIM1>() {
+                //     match channel {
+                //         Channel::_1 => u32(u32(self.0.ccr1.read().bits()),
+                //         Channel::_2 => u32(u32(self.0.ccr2.read().bits()),
+                //         Channel::_3 => u32(u32(self.0.ccr3.read().bits()),
+                //         Channel::_4 => u32(u32(self.0.ccr4.read().bits()),
+                //     }
+                // } else {
+                    match channel {
+                        Channel::_1 => u32(self.0.ccr1.read().ccr1_h().bits()) << 16 | u32(self.0.ccr1.read().ccr1_l().bits()),
+                        Channel::_2 => u32(self.0.ccr2.read().ccr2_h().bits()) << 16 | u32(self.0.ccr2.read().ccr2_l().bits()),
+                        Channel::_3 => u32(self.0.ccr3.read().ccr3_h().bits()) << 16 | u32(self.0.ccr3.read().ccr3_l().bits()),
+                        Channel::_4 => u32(self.0.ccr4.read().ccr4_h().bits()) << 16 | u32(self.0.ccr4.read().ccr4_l().bits()),
+                    }
+                // }
+            }
+
+            fn disable(&self, channel: Channel) {
+                match channel {
+                    Channel::_1 => self.0.ccer.modify(|_, w| w.cc1e().clear_bit()),
+                    Channel::_2 => self.0.ccer.modify(|_, w| w.cc2e().clear_bit()),
+                    Channel::_3 => self.0.ccer.modify(|_, w| w.cc3e().clear_bit()),
+                    Channel::_4 => self.0.ccer.modify(|_, w| w.cc4e().clear_bit()),
+                }
+            }
+
+            fn enable(&self, channel: Channel) {
+                match channel {
+                    Channel::_1 => self.0.ccer.modify(|_, w| w.cc1e().set_bit()),
+                    Channel::_2 => self.0.ccer.modify(|_, w| w.cc2e().set_bit()),
+                    Channel::_3 => self.0.ccer.modify(|_, w| w.cc3e().set_bit()),
+                    Channel::_4 => self.0.ccer.modify(|_, w| w.cc4e().set_bit()),
+                }
+            }
+
+            fn get_max_duty(&self) -> u32 {
+                self.0.arr.read().bits()
+            }
+
+            fn get_period(&self) -> ::$APB::Ticks {
+                ::$APB::Ticks(u32(self.0.psc.read().bits() * self.0.arr.read().bits()))
+            }
+
+            fn set_duty(&self, channel: Channel, duty: u32) {
+                let dutyl : u16 = u16(duty).unwrap();
+                let dutyh : u16 = u16(duty >> 16).unwrap();
+                match channel {
+                    Channel::_1 => self.0.ccr1.write(|w| unsafe{w.ccr1_h().bits(dutyh).ccr1_l().bits(dutyl)}),
+                    Channel::_2 => self.0.ccr2.write(|w| unsafe{w.ccr2_h().bits(dutyh).ccr2_l().bits(dutyl)}),
+                    Channel::_3 => self.0.ccr3.write(|w| unsafe{w.ccr3_h().bits(dutyh).ccr3_l().bits(dutyl)}),
+                    Channel::_4 => self.0.ccr4.write(|w| unsafe{w.ccr4_h().bits(dutyh).ccr4_l().bits(dutyl)}),
+                }
+            }
+
+            fn set_period<P>(&self, period: P)
+            where
+                P: Into<::$APB::Ticks>,
+            {
+                self._set_period(period.into())
+            }
+        }
+    }
+}
+
+// impl_Pwm!(TIM1,apb2);
+impl_Pwm!(TIM2,apb1);
+impl_Pwm!(TIM3,apb1);
+impl_Pwm!(TIM4,apb1);
\ No newline at end of file
diff --git a/src/timer.rs b/src/timer.rs
index 9dab206d5c2115cf57b608f7277c2ddfce63efb3..65d1e89a6d537a2c141d25e390bbcd7fac928355 100644
--- a/src/timer.rs
+++ b/src/timer.rs
@@ -52,8 +52,6 @@ macro_rules! impl_Timer {
                 let tim = self.0;
 
                 // Enable TIMx
-                // Reference manual does not mention TIM6-8, TIM 12-14 
-                // although they are implemented in device crate...
                 if tim.get_type_id() == TypeId::of::<TIM1>() {
                     rcc.apb2enr.modify(|_, w| w.tim1en().set_bit());
                 } else if tim.get_type_id() == TypeId::of::<TIM2>() {