diff --git a/examples/rtt-pwm-dma.rs b/examples/rtt-pwm-dma.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ab05fb1d1a27a22a63d040d0172054f959d82f3d
--- /dev/null
+++ b/examples/rtt-pwm-dma.rs
@@ -0,0 +1,148 @@
+//! examples/rtt-pwm-dma.rs
+//! cargo run --examples rtt-pwm-dma
+
+// #![deny(unsafe_code)]
+// #![deny(warnings)]
+#![no_main]
+#![no_std]
+
+use cortex_m::{asm, peripheral::DWT};
+use panic_halt as _;
+use rtt_target::{rprintln, rtt_init_print};
+use stm32f4xx_hal::{bb, dma, gpio::Speed, prelude::*, pwm, stm32};
+
+#[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true)]
+const APP: () = {
+    #[init]
+    fn init(mut cx: init::Context) {
+        rtt_init_print!();
+        rprintln!("init");
+        let dp = cx.device;
+
+        // Initialize (enable) the monotonic timer (CYCCNT)
+        cx.core.DCB.enable_trace();
+        cx.core.DWT.enable_cycle_counter();
+
+        let rcc = dp.RCC.constrain();
+        // Set up the system clock. 48 MHz?
+        let clocks = rcc
+            .cfgr
+            // .use_hse(8.mhz())
+            .sysclk(48.mhz())
+            .pclk1(24.mhz())
+            .freeze();
+
+        let gpioa = dp.GPIOA.split();
+        // we set the pins to VeryHigh to get the sharpest waveform possible
+        // (rise and fall times should have similar characteristics)
+        let channels = (
+            gpioa.pa8.into_alternate_af1().set_speed(Speed::VeryHigh),
+            gpioa.pa9.into_alternate_af1().set_speed(Speed::VeryHigh),
+        );
+
+        // Setup PWM RAW
+        let tim1 = dp.TIM1;
+        // Here we need unsafe as we are "stealing" the RCC peripheral
+        // At this point it has been contrained into SysConf and used to set clocks
+        let rcc = unsafe { &(*stm32::RCC::ptr()) };
+
+        // pwm_all_channels!(TIM1: (tim1, apb2enr, apb2rstr, 0u8, pclk2, ppre2));
+
+        // Enable and reset the timer peripheral,
+        // it's the same bit position for both registers (0 in this case)
+        // Notice the use of bit banding to set/clear bits individually
+        // It is unsafe, as the register address could be anything within range
+        // of the bitband region
+        unsafe {
+            bb::set(&rcc.apb2enr, 0u8);
+            bb::set(&rcc.apb2rstr, 0u8);
+            bb::clear(&rcc.apb2rstr, 0u8);
+        }
+        // Setup chanel 1 and 2 as pwm_mode1
+        tim1.ccmr1_output()
+            .modify(|_, w| w.oc1pe().set_bit().oc1m().pwm_mode1());
+
+        tim1.ccmr1_output()
+            .modify(|_, w| w.oc2pe().set_bit().oc2m().pwm_mode1());
+
+        // The reference manual is a bit ambiguous about when enabling this bit is really
+        // necessary, but since we MUST enable the preload for the output channels then we
+        // might as well enable for the auto-reload too
+        tim1.cr1.modify(|_, w| w.arpe().set_bit());
+
+        let clk = clocks.pclk2().0 * if clocks.ppre2() == 1 { 1 } else { 2 };
+        // check that its actually 48_000_000
+        rprintln!("clk {}", clk);
+
+        // we want maximum performance, thus we set the prescaler to 0
+        let pre = 0;
+        rprintln!("pre {}", pre);
+        tim1.psc.write(|w| w.psc().bits(pre));
+
+        // we want 8 bits of resolution
+        // so our ARR = 2^8 - 1 = 256 - 1 = 255
+        let arr = 255;
+        rprintln!("arr {}", arr);
+        tim1.arr.write(|w| unsafe { w.bits(arr) });
+
+        //  Trigger update event to load the registers
+        tim1.cr1.modify(|_, w| w.urs().set_bit());
+        tim1.egr.write(|w| w.ug().set_bit());
+        tim1.cr1.modify(|_, w| w.urs().clear_bit());
+
+        // Set main output enable of all Output Compare (OC) registers
+        tim1.bdtr.modify(|_, w| w.moe().set_bit());
+
+        // Set output enable for channels 1 and 2
+        // Channel 1 (bit  0)
+        unsafe { bb::set(&tim1.ccer, 0) }
+        // Channel 4 (bit  0)
+        unsafe { bb::set(&tim1.ccer, 4) }
+
+        // Setup the timer
+        tim1.cr1.write(|w| {
+            w.cms()
+                .bits(0b00) // edge aligned mode
+                .dir() // counter used as upcounter
+                .clear_bit()
+                .opm() // one pulse mode
+                .clear_bit()
+                .cen() // enable counter
+                .set_bit()
+        });
+
+        // Set duty cycle of Channels
+        tim1.ccr1.write(|w| unsafe { w.ccr().bits(128) });
+        tim1.ccr2.write(|w| unsafe { w.ccr().bits(128) });
+
+        // loop {
+        //     for i in 0..255 {
+        //         tim1.ccr1.write(|w| unsafe { w.ccr().bits(i) });
+        //         tim1.ccr2.write(|w| unsafe { w.ccr().bits(i) });
+        //         while tim1.sr.read().tif().is_no_trigger() {}
+        //     }
+        // }
+    }
+
+    #[idle]
+    fn idle(_cx: idle::Context) -> ! {
+        rprintln!("idle");
+        loop {
+            continue;
+        }
+    }
+};
+
+mod dma_pwm {
+    // Not sure we need a dma mode
+    // DMA mode
+    // #[derive(Debug, Clone, Copy)]
+    // pub enum Dma {
+    //     /// No DMA, disabled
+    //     Disabled,
+    //     /// Single DMA, DMA will be disabled after each conversion sequence
+    //     Single,
+    //     /// Continuous DMA, DMA will remain enabled after conversion
+    //     Continuous,
+    // }
+}