Преглед изворни кода

Restore Dma (#55)

* rxdma, txdma

* dma api

* update for pac v0.7

* remove deny(warnings)

* changelog
Zgarbul Andrey пре 5 година
родитељ
комит
66cfb78527

+ 2 - 0
CHANGELOG.md

@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 
 ### Added
 
+- Now requires stm32f1 v0.7
+- Restore and improve Serial DMA-based TX, RX and circular implementation
 - Implement ADC example
 - Implement ADC embedded_hal traits
 - Implement ADC clock configuration

+ 4 - 4
Cargo.toml

@@ -19,10 +19,10 @@ name = "timer-interrupt-rtfm"
 required-features = ["rt"]
 
 [dependencies]
-cortex-m = "0.5.8"
+cortex-m = ">=0.5.8,<0.7"
 nb = "0.1.1"
-cortex-m-rt = "0.6.7"
-stm32f1 = "0.6.0"
+cortex-m-rt = "0.6.8"
+stm32f1 = "0.7.0"
 
 [dependencies.void]
 default-features = false
@@ -38,7 +38,7 @@ version = "0.2.2"
 
 [dev-dependencies]
 panic-halt = "0.2.0"
-panic-semihosting = "0.5.1"
+panic-semihosting = {git = "https://github.com/rust-embedded/panic-semihosting"}
 panic-itm = "0.4.0"
 cortex-m-rtfm = "0.4.2"
 cortex-m-semihosting = "0.3.2"

+ 12 - 22
examples/adc.rs

@@ -2,25 +2,21 @@
 #![no_main]
 #![no_std]
 
-#[macro_use]
-extern crate cortex_m_rt as rt;
-extern crate cortex_m;
-extern crate cortex_m_semihosting;
-extern crate embedded_hal;
-extern crate panic_semihosting;
-extern crate stm32f1xx_hal;
+use panic_semihosting as _;
 
-use core::fmt::Write;
-use cortex_m_semihosting::hio;
-use stm32f1xx_hal::prelude::*;
+use stm32f1xx_hal::{
+    prelude::*,
+    pac,
+    adc,
+};
+use cortex_m_rt::{entry,exception,ExceptionFrame};
 
-use rt::ExceptionFrame;
-use stm32f1xx_hal::adc;
+use cortex_m_semihosting::hprintln;
 
 #[entry]
 fn main() -> ! {
     // Aquire peripherals
-    let p = stm32f1xx_hal::stm32::Peripherals::take().unwrap();
+    let p = pac::Peripherals::take().unwrap();
     let mut flash = p.FLASH.constrain();
     let mut rcc = p.RCC.constrain();
 
@@ -30,9 +26,7 @@ fn main() -> ! {
     // practical needs. User specified value is be approximated using supported
     // prescaler values 2/4/6/8.
     let clocks = rcc.cfgr.adcclk(2.mhz()).freeze(&mut flash.acr);
-    hio::hstdout()
-        .map(|mut hio| writeln!(hio, "adc freq: {}", clocks.adcclk().0).unwrap())
-        .unwrap();
+    hprintln!("adc freq: {}", clocks.adcclk().0).unwrap();
 
     // Setup ADC
     let mut adc1 = adc::Adc::adc1(p.ADC1, &mut rcc.apb2);
@@ -51,16 +45,12 @@ fn main() -> ! {
 
     loop {
         let data: u16 = adc1.read(&mut ch0).unwrap();
-        hio::hstdout()
-            .map(|mut hio| writeln!(hio, "adc1: {}", data).unwrap())
-            .unwrap();
+        hprintln!("adc1: {}", data).unwrap();
 
         #[cfg(feature = "stm32f103")]
         {
             let data1: u16 = adc2.read(&mut ch1).unwrap();
-            hio::hstdout()
-                .map(|mut hio| writeln!(hio, "adc2: {}", data1).unwrap())
-                .unwrap();
+            hprintln!("adc2: {}", data1).unwrap();
         }
     }
 }

+ 1 - 2
examples/blinky.rs

@@ -6,11 +6,10 @@
 //! the reference manaual for an explanation. This is not an issue on the blue pill.
 
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_std]
 #![no_main]
 
-extern crate panic_halt;
+use panic_halt as _;
 
 use nb::block;
 

+ 1 - 2
examples/blinky_rtc.rs

@@ -7,11 +7,10 @@
 //! This is not an issue on the blue pill.
 
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_std]
 #![no_main]
 
-extern crate panic_halt;
+use panic_halt as _;
 
 use stm32f1xx_hal::{
     prelude::*,

+ 1 - 2
examples/delay.rs

@@ -1,11 +1,10 @@
 //! "Blinky" using delays instead of a timer
 
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_main]
 #![no_std]
 
-extern crate panic_halt;
+use panic_halt as _;
 
 use stm32f1xx_hal::{
     prelude::*,

+ 2 - 3
examples/hello.rs

@@ -1,13 +1,12 @@
 //! Prints "Hello, world" on the OpenOCD console
 
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_main]
 #![no_std]
 
-extern crate panic_semihosting;
+use panic_semihosting as _;
 
-extern crate stm32f1xx_hal;
+use stm32f1xx_hal as _;
 use cortex_m_semihosting::hprintln;
 
 use cortex_m_rt::entry;

+ 2 - 3
examples/itm.rs

@@ -1,11 +1,10 @@
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_main]
 #![no_std]
 
-extern crate panic_itm;
+use panic_itm as _;
 use cortex_m::iprintln;
-extern crate stm32f1xx_hal;
+use stm32f1xx_hal as _;
 
 use cortex_m_rt::entry;
 

+ 1 - 3
examples/led.rs

@@ -10,12 +10,10 @@
 //! This is not an issue on the blue pill.
 
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_main]
 #![no_std]
 
-extern crate panic_halt;
-extern crate cortex_m_rt as rt;
+use panic_halt as _;
 
 use stm32f1xx_hal::{
     prelude::*,

+ 1 - 2
examples/mfrc522.rs

@@ -1,9 +1,8 @@
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_main]
 #![no_std]
 
-extern crate panic_itm;
+use panic_itm as _;
 
 use cortex_m::iprintln;
 

+ 1 - 2
examples/nojtag.rs

@@ -1,11 +1,10 @@
 //! Disables the JTAG ports to give access to pb3, pb4 and PA15
 
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_main]
 #![no_std]
 
-extern crate panic_halt;
+use panic_halt as _;
 
 use stm32f1xx_hal::{
     prelude::*,

+ 3 - 4
examples/panics.rs

@@ -1,13 +1,12 @@
 //! Prints "Hello, world" on the OpenOCD console
 
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_main]
 #![no_std]
 
-extern crate panic_semihosting;
-//extern crate panic_itm;
-extern crate stm32f1xx_hal;
+use panic_semihosting as _;
+//use panic_itm as _;
+use stm32f1xx_hal as _;
 use cortex_m_semihosting::hprintln;
 
 use cortex_m_rt::{entry, exception, ExceptionFrame};

+ 1 - 2
examples/pwm.rs

@@ -1,11 +1,10 @@
 //! Testing PWM output
 
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_main]
 #![no_std]
 
-extern crate panic_halt;
+use panic_halt as _;
 
 use cortex_m::asm;
 use stm32f1xx_hal::{

+ 9 - 11
examples/pwm_input.rs

@@ -1,23 +1,21 @@
 //! Testing PWM input
 
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_main]
 #![no_std]
 
-extern crate cortex_m;
-extern crate cortex_m_rt as rt;
-extern crate panic_halt;
-extern crate stm32f1xx_hal as hal;
+use panic_halt as _;
 
-use hal::prelude::*;
-use hal::pwm_input::*;
-use hal::stm32;
-use rt::entry;
+use stm32f1xx_hal::{
+    prelude::*,
+    pac,
+    pwm_input::*,
+};
+use cortex_m_rt::entry;
 
 #[entry]
 fn main() -> ! {
-    let p = stm32::Peripherals::take().unwrap();
+    let p = pac::Peripherals::take().unwrap();
 
     let mut flash = p.FLASH.constrain();
     let mut rcc = p.RCC.constrain();
@@ -25,7 +23,7 @@ fn main() -> ! {
     let clocks = rcc.cfgr.freeze(&mut flash.acr);
 
     let mut afio = p.AFIO.constrain(&mut rcc.apb2);
-    let mut dbg = p.DBG;
+    let mut dbg = p.DBGMCU;
 
     let mut gpiob = p.GPIOB.split(&mut rcc.apb2);
 

+ 1 - 2
examples/qei.rs

@@ -1,11 +1,10 @@
 //! Testing the Quadrature Encoder Interface
 
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_main]
 #![no_std]
 
-extern crate panic_semihosting;
+use panic_semihosting as _;
 
 use cortex_m_semihosting::hprintln;
 

+ 1 - 2
examples/rtc.rs

@@ -1,11 +1,10 @@
 //! Outputs the current time in seconds to hstdout using the real time clock
 
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_std]
 #![no_main]
 
-extern crate panic_semihosting;
+use panic_semihosting as _;
 
 use cortex_m_semihosting::hprintln;
 

+ 13 - 25
examples/serial-dma-circ.rs.disabled → examples/serial-dma-circ.rs

@@ -1,26 +1,24 @@
 //! Serial interface circular DMA RX transfer test
 
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_std]
 #![no_main]
 
-extern crate cortex_m_rt as rt;
-#[macro_use(singleton)]
-extern crate cortex_m;
-extern crate panic_semihosting;
-extern crate stm32f1xx_hal as hal;
+use panic_halt as _;
 
-use cortex_m::asm;
-use hal::dma::Half;
-use hal::prelude::*;
-use hal::serial::Serial;
-use hal::stm32f103xx;
-use rt::{entry, exception, ExceptionFrame};
+use cortex_m::{asm, singleton};
+
+use stm32f1xx_hal::{
+    prelude::*,
+    pac,
+    serial::Serial,
+    dma::Half,
+};
+use cortex_m_rt::entry;
 
 #[entry]
 fn main() -> ! {
-    let p = stm32f103xx::Peripherals::take().unwrap();
+    let p = pac::Peripherals::take().unwrap();
 
     let mut flash = p.FLASH.constrain();
     let mut rcc = p.RCC.constrain();
@@ -58,10 +56,10 @@ fn main() -> ! {
         &mut rcc.apb2,
     );
 
-    let rx = serial.split().1;
+    let rx = serial.split().1.with_dma(channels.5);
     let buf = singleton!(: [[u8; 8]; 2] = [[0; 8]; 2]).unwrap();
 
-    let mut circ_buffer = rx.circ_read(channels.5, buf);
+    let mut circ_buffer = rx.circ_read(buf);
 
     while circ_buffer.readable_half().unwrap() != Half::First {}
 
@@ -75,13 +73,3 @@ fn main() -> ! {
 
     loop {}
 }
-
-#[exception]
-fn HardFault(ef: &ExceptionFrame) -> ! {
-    panic!("{:#?}", ef);
-}
-
-#[exception]
-fn DefaultHandler(irqn: i16) {
-    panic!("Unhandled exception (IRQn = {})", irqn);
-}

+ 12 - 24
examples/serial-dma-peek.rs.disabled → examples/serial-dma-peek.rs

@@ -1,25 +1,23 @@
 //! Serial interface DMA RX transfer test
 
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_main]
 #![no_std]
 
-extern crate cortex_m_rt as rt;
-#[macro_use(singleton)]
-extern crate cortex_m;
-extern crate panic_semihosting;
-extern crate stm32f1xx_hal as hal;
+use panic_halt as _;
 
-use cortex_m::asm;
-use hal::prelude::*;
-use hal::serial::Serial;
-use hal::stm32f103xx;
-use rt::{entry, exception, ExceptionFrame};
+use cortex_m::{asm, singleton};
+
+use stm32f1xx_hal::{
+    prelude::*,
+    pac,
+    serial::Serial,
+};
+use cortex_m_rt::entry;
 
 #[entry]
 fn main() -> ! {
-    let p = stm32f103xx::Peripherals::take().unwrap();
+    let p = pac::Peripherals::take().unwrap();
 
     let mut flash = p.FLASH.constrain();
     let mut rcc = p.RCC.constrain();
@@ -57,10 +55,10 @@ fn main() -> ! {
         &mut rcc.apb2,
     );
 
-    let rx = serial.split().1;
+    let rx = serial.split().1.with_dma(channels.5);
     let buf = singleton!(: [u8; 8] = [0; 8]).unwrap();
 
-    let t = rx.read_exact(channels.5, buf);
+    let t = rx.read(buf);
 
     while !t.is_done() {
         let _slice = t.peek();
@@ -72,13 +70,3 @@ fn main() -> ! {
 
     loop {}
 }
-
-#[exception]
-fn HardFault(ef: &ExceptionFrame) -> ! {
-    panic!("{:#?}", ef);
-}
-
-#[exception]
-fn DefaultHandler(irqn: i16) {
-    panic!("Unhandled exception (IRQn = {})", irqn);
-}

+ 12 - 24
examples/serial-dma-rx.rs.disabled → examples/serial-dma-rx.rs

@@ -1,25 +1,23 @@
 //! Serial interface DMA RX transfer test
 
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_main]
 #![no_std]
 
-extern crate cortex_m_rt as rt;
-#[macro_use(singleton)]
-extern crate cortex_m;
-extern crate panic_semihosting;
-extern crate stm32f1xx_hal as hal;
+use panic_halt as _;
 
-use cortex_m::asm;
-use hal::prelude::*;
-use hal::serial::Serial;
-use hal::stm32f103xx;
-use rt::{entry, exception, ExceptionFrame};
+use cortex_m::{asm, singleton};
+
+use stm32f1xx_hal::{
+    prelude::*,
+    pac,
+    serial::Serial,
+};
+use cortex_m_rt::entry;
 
 #[entry]
 fn main() -> ! {
-    let p = stm32f103xx::Peripherals::take().unwrap();
+    let p = pac::Peripherals::take().unwrap();
 
     let mut flash = p.FLASH.constrain();
     let mut rcc = p.RCC.constrain();
@@ -57,22 +55,12 @@ fn main() -> ! {
         &mut rcc.apb2,
     );
 
-    let rx = serial.split().1;
+    let rx = serial.split().1.with_dma(channels.5);
     let buf = singleton!(: [u8; 8] = [0; 8]).unwrap();
 
-    let (_buf, _c, _rx) = rx.read_exact(channels.5, buf).wait();
+    let (_buf, _rx) = rx.read(buf).wait();
 
     asm::bkpt();
 
     loop {}
 }
-
-#[exception]
-fn HardFault(ef: &ExceptionFrame) -> ! {
-    panic!("{:#?}", ef);
-}
-
-#[exception]
-fn DefaultHandler(irqn: i16) {
-    panic!("Unhandled exception (IRQn = {})", irqn);
-}

+ 13 - 24
examples/serial-dma-tx.rs.disabled → examples/serial-dma-tx.rs

@@ -1,24 +1,23 @@
 //! Serial interface DMA TX transfer test
 
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_main]
 #![no_std]
 
-extern crate cortex_m;
-extern crate cortex_m_rt as rt;
-extern crate panic_semihosting;
-extern crate stm32f1xx_hal as hal;
+use panic_halt as _;
 
 use cortex_m::asm;
-use hal::prelude::*;
-use hal::serial::Serial;
-use hal::stm32f103xx;
-use rt::{entry, exception, ExceptionFrame};
+
+use stm32f1xx_hal::{
+    prelude::*,
+    pac,
+    serial::Serial,
+};
+use cortex_m_rt::entry;
 
 #[entry]
 fn main() -> ! {
-    let p = stm32f103xx::Peripherals::take().unwrap();
+    let p = pac::Peripherals::take().unwrap();
 
     let mut flash = p.FLASH.constrain();
     let mut rcc = p.RCC.constrain();
@@ -56,29 +55,19 @@ fn main() -> ! {
         &mut rcc.apb2,
     );
 
-    let tx = serial.split().0;
+    let tx = serial.split().0.with_dma(channels.4);
 
-    let (_, c, tx) = tx.write_all(channels.4, b"The quick brown fox").wait();
+    let (_, tx) = tx.write(b"The quick brown fox").wait();
 
     asm::bkpt();
 
-    let (_, c, tx) = tx.write_all(c, b" jumps").wait();
+    let (_, tx) = tx.write(b" jumps").wait();
 
     asm::bkpt();
 
-    tx.write_all(c, b" over the lazy dog.").wait();
+    tx.write(b" over the lazy dog.").wait();
 
     asm::bkpt();
 
     loop {}
 }
-
-#[exception]
-fn HardFault(ef: &ExceptionFrame) -> ! {
-    panic!("{:#?}", ef);
-}
-
-#[exception]
-fn DefaultHandler(irqn: i16) {
-    panic!("Unhandled exception (IRQn = {})", irqn);
-}

+ 1 - 2
examples/serial.rs

@@ -3,11 +3,10 @@
 //! You have to short the TX and RX pins to make this program work
 
 #![deny(unsafe_code)]
-#![deny(warnings)]
 #![no_main]
 #![no_std]
 
-extern crate panic_halt;
+use panic_halt as _;
 
 use cortex_m::asm;
 

+ 2 - 2
examples/timer-interrupt-rtfm.rs

@@ -9,7 +9,7 @@
 #![no_main]
 
 // you can put a breakpoint on `rust_begin_unwind` to catch panics
-extern crate panic_halt;
+use panic_halt as _;
 
 use cortex_m::asm::wfi;
 use rtfm::app;
@@ -96,4 +96,4 @@ const APP: () = {
         // Clears the update flag
         resources.TIMER_HANDLER.clear_update_interrupt_flag();
     }
-};
+};

+ 188 - 113
src/dma.rs

@@ -65,36 +65,33 @@ pub trait DmaExt {
     fn split(self, ahb: &mut AHB) -> Self::Channels;
 }
 
-pub struct Transfer<MODE, BUFFER, CHANNEL, PAYLOAD> {
+pub struct Transfer<MODE, BUFFER, PAYLOAD> {
     _mode: PhantomData<MODE>,
     buffer: BUFFER,
-    channel: CHANNEL,
     payload: PAYLOAD,
 }
 
-impl<BUFFER, CHANNEL, PAYLOAD> Transfer<R, BUFFER, CHANNEL, PAYLOAD> {
-    pub(crate) fn r(buffer: BUFFER, channel: CHANNEL, payload: PAYLOAD) -> Self {
+impl<BUFFER, PAYLOAD> Transfer<R, BUFFER, PAYLOAD> {
+    pub(crate) fn r(buffer: BUFFER, payload: PAYLOAD) -> Self {
         Transfer {
             _mode: PhantomData,
             buffer,
-            channel,
             payload,
         }
     }
 }
 
-impl<BUFFER, CHANNEL, PAYLOAD> Transfer<W, BUFFER, CHANNEL, PAYLOAD> {
-    pub(crate) fn w(buffer: BUFFER, channel: CHANNEL, payload: PAYLOAD) -> Self {
+impl<BUFFER, PAYLOAD> Transfer<W, BUFFER, PAYLOAD> {
+    pub(crate) fn w(buffer: BUFFER, payload: PAYLOAD) -> Self {
         Transfer {
             _mode: PhantomData,
             buffer,
-            channel,
             payload,
         }
     }
 }
 
-impl<BUFFER, CHANNEL, PAYLOAD> ops::Deref for Transfer<R, BUFFER, CHANNEL, PAYLOAD> {
+impl<BUFFER, PAYLOAD> ops::Deref for Transfer<R, BUFFER, PAYLOAD> {
     type Target = BUFFER;
 
     fn deref(&self) -> &BUFFER {
@@ -108,18 +105,10 @@ pub struct R;
 /// Write transfer
 pub struct W;
 
-/*
 macro_rules! dma {
     ($($DMAX:ident: ($dmaX:ident, $dmaXen:ident, $dmaXrst:ident, {
         $($CX:ident: (
-            $ccrX:ident,
-            $CCRX:ident,
-            $cndtrX:ident,
-            $CNDTRX:ident,
-            $cparX:ident,
-            $CPARX:ident,
-            $cmarX:ident,
-            $CMARX:ident,
+            $chX:ident,
             $htifX:ident,
             $tcifX:ident,
             $chtifX:ident,
@@ -130,23 +119,66 @@ macro_rules! dma {
         $(
             pub mod $dmaX {
                 use core::sync::atomic::{self, Ordering};
+                use core::ptr;
 
                 use crate::pac::{$DMAX, dma1};
 
-                use dma::{CircBuffer, DmaExt, Error, Event, Half, Transfer, W};
-                use rcc::AHB;
+                use crate::dma::{CircBuffer, DmaExt, Error, Event, Half, Transfer, W, RxDma, TxDma};
+                use crate::rcc::AHB;
 
                 pub struct Channels((), $(pub $CX),+);
 
                 $(
+                    /// A singleton that represents a single DMAx channel (channel X in this case)
+                    ///
+                    /// This singleton has exclusive access to the registers of the DMAx channel X
                     pub struct $CX { _0: () }
 
+                    impl $CX {
+                        /// Associated peripheral `address`
+                        ///
+                        /// `inc` indicates whether the address will be incremented after every byte transfer
+                        pub fn set_peripheral_address(&mut self, address: u32, inc: bool) {
+                            self.ch().par.write(|w| w.pa().bits(address) );
+                            self.ch().cr.modify(|_, w| w.pinc().bit(inc) );
+                        }
+
+                        /// `address` where from/to data will be read/write
+                        ///
+                        /// `inc` indicates whether the address will be incremented after every byte transfer
+                        pub fn set_memory_address(&mut self, address: u32, inc: bool) {
+                            self.ch().mar.write(|w| w.ma().bits(address) );
+                            self.ch().cr.modify(|_, w| w.minc().bit(inc) );
+                        }
+
+                        /// Number of bytes to transfer
+                        pub fn set_transfer_length(&mut self, len: usize) {
+                            self.ch().ndtr.write(|w| w.ndt().bits(cast::u16(len).unwrap()));
+                        }
+
+                        /// Starts the DMA transfer
+                        pub fn start(&mut self) {
+                            self.ch().cr.modify(|_, w| w.en().set_bit() );
+                        }
+
+                        /// Stops the DMA transfer
+                        pub fn stop(&mut self) {
+                            self.ifcr().write(|w| w.$cgifX().set_bit());
+                            self.ch().cr.modify(|_, w| w.en().clear_bit() );
+                        }
+
+                        /// Returns `true` if there's a transfer in progress
+                        fn in_progress(&self) -> bool {
+                            self.isr().$tcifX().bit_is_clear()
+                        }
+                    }
+
                     impl $CX {
                         pub fn listen(&mut self, event: Event) {
                             match event {
-                                Event::HalfTransfer => self.ccr().modify(|_, w| w.htie().set_bit()),
+                                Event::HalfTransfer => self.ch().cr.modify(|_, w| w.htie().set_bit()),
                                 Event::TransferComplete => {
-                                    self.ccr().modify(|_, w| w.tcie().set_bit())
+                                    self.ch().cr.modify(|_, w| w.tcie().set_bit())
                                 }
                             }
                         }
@@ -154,44 +186,31 @@ macro_rules! dma {
                         pub fn unlisten(&mut self, event: Event) {
                             match event {
                                 Event::HalfTransfer => {
-                                    self.ccr().modify(|_, w| w.htie().clear_bit())
+                                    self.ch().cr.modify(|_, w| w.htie().clear_bit())
                                 },
                                 Event::TransferComplete => {
-                                    self.ccr().modify(|_, w| w.tcie().clear_bit())
+                                    self.ch().cr.modify(|_, w| w.tcie().clear_bit())
                                 }
                             }
                         }
 
-                        pub(crate) fn isr(&self) -> dma1::isr::R {
+                        pub fn ch(&mut self) -> &dma1::CH {
+                            unsafe { &(*$DMAX::ptr()).$chX }
+                        }
+
+                        pub fn isr(&self) -> dma1::isr::R {
                             // NOTE(unsafe) atomic read with no side effects
                             unsafe { (*$DMAX::ptr()).isr.read() }
                         }
 
-                        pub(crate) fn ifcr(&self) -> &dma1::IFCR {
+                        pub fn ifcr(&self) -> &dma1::IFCR {
                             unsafe { &(*$DMAX::ptr()).ifcr }
                         }
 
-                        pub(crate) fn ccr(&mut self) -> &dma1::$CCRX {
-                            unsafe { &(*$DMAX::ptr()).$ccrX }
-                        }
-
-                        pub(crate) fn cndtr(&mut self) -> &dma1::$CNDTRX {
-                            unsafe { &(*$DMAX::ptr()).$cndtrX }
-                        }
-
-                        pub(crate) fn cpar(&mut self) -> &dma1::$CPARX {
-                            unsafe { &(*$DMAX::ptr()).$cparX }
-                        }
-
-                        pub(crate) fn cmar(&mut self) -> &dma1::$CMARX {
-                            unsafe { &(*$DMAX::ptr()).$cmarX }
-                        }
-
-                        pub(crate) fn get_cndtr(&self) -> u32 {
+                        pub fn get_ndtr(&self) -> u32 {
                             // NOTE(unsafe) atomic read with no side effects
-                            unsafe { (*$DMAX::ptr()).$cndtrX.read().bits() }
+                            unsafe { &(*$DMAX::ptr())}.$chX.ndtr.read().bits()
                         }
-
                     }
 
                     impl<B> CircBuffer<B, $CX> {
@@ -260,37 +279,58 @@ macro_rules! dma {
                         }
                     }
 
-                    impl<BUFFER, PAYLOAD, MODE> Transfer<MODE, BUFFER, $CX, PAYLOAD> {
+                    impl<BUFFER, PAYLOAD, MODE> Transfer<MODE, BUFFER, RxDma<PAYLOAD, $CX>> {
+                        pub fn is_done(&self) -> bool {
+                            !self.payload.channel.in_progress()
+                        }
+
+                        pub fn wait(mut self) -> (BUFFER, RxDma<PAYLOAD, $CX>) {
+                            while !self.is_done() {}
+
+                            atomic::compiler_fence(Ordering::Acquire);
+
+                            self.payload.stop();
+
+                            // we need a read here to make the Acquire fence effective
+                            // we do *not* need this if `dma.stop` does a RMW operation
+                            unsafe { ptr::read_volatile(&0); }
+
+                            // we need a fence here for the same reason we need one in `Transfer.wait`
+                            atomic::compiler_fence(Ordering::Acquire);
+
+                            (self.buffer, self.payload)
+                        }
+                    }
+
+                    impl<BUFFER, PAYLOAD, MODE> Transfer<MODE, BUFFER, TxDma<PAYLOAD, $CX>> {
                         pub fn is_done(&self) -> bool {
-                            self.channel.isr().$tcifX().bit_is_set()
+                            !self.payload.channel.in_progress()
                         }
 
-                        pub fn wait(mut self) -> (BUFFER, $CX, PAYLOAD) {
-                            // XXX should we check for transfer errors here?
-                            // The manual says "A DMA transfer error can be generated by reading
-                            // from or writing to a reserved address space". I think it's impossible
-                            // to get to that state with our type safe API and *safe* Rust.
+                        pub fn wait(mut self) -> (BUFFER, TxDma<PAYLOAD, $CX>) {
                             while !self.is_done() {}
 
-                            self.channel.ifcr().write(|w| w.$cgifX().set_bit());
+                            atomic::compiler_fence(Ordering::Acquire);
+
+                            self.payload.stop();
 
-                            self.channel.ccr().modify(|_, w| w.en().clear_bit());
+                            // we need a read here to make the Acquire fence effective
+                            // we do *not* need this if `dma.stop` does a RMW operation
+                            unsafe { ptr::read_volatile(&0); }
 
-                            // TODO can we weaken this compiler barrier?
-                            // NOTE(compiler_fence) operations on `buffer` should not be reordered
-                            // before the previous statement, which marks the DMA transfer as done
-                            atomic::compiler_fence(Ordering::SeqCst);
+                            // we need a fence here for the same reason we need one in `Transfer.wait`
+                            atomic::compiler_fence(Ordering::Acquire);
 
-                            (self.buffer, self.channel, self.payload)
+                            (self.buffer, self.payload)
                         }
                     }
 
-                    impl<BUFFER, PAYLOAD> Transfer<W, &'static mut BUFFER, $CX, PAYLOAD> {
+                    impl<BUFFER, PAYLOAD> Transfer<W, &'static mut BUFFER, RxDma<PAYLOAD, $CX>> {
                         pub fn peek<T>(&self) -> &[T]
                         where
                             BUFFER: AsRef<[T]>,
                         {
-                            let pending = self.channel.get_cndtr() as usize;
+                            let pending = self.payload.channel.get_ndtr() as usize;
 
                             let slice = self.buffer.as_ref();
                             let capacity = slice.len();
@@ -298,6 +338,25 @@ macro_rules! dma {
                             &slice[..(capacity - pending)]
                         }
                     }
+
+                    impl<PAYLOAD> RxDma<PAYLOAD, $CX> {
+                        pub fn start(&mut self) {
+                            self.channel.start()
+                        }
+                        pub fn stop(&mut self) {
+                            self.channel.stop()
+                        }
+                    }
+
+                    impl<PAYLOAD> TxDma<PAYLOAD, $CX> {
+                        pub fn start(&mut self) {
+                            self.channel.start()
+                        }
+                        pub fn stop(&mut self) {
+                            self.channel.stop()
+                        }
+                    }
+
                 )+
 
                 impl DmaExt for $DMAX {
@@ -308,7 +367,7 @@ macro_rules! dma {
 
                         // reset the DMA control registers (stops all on-going transfers)
                         $(
-                            self.$ccrX.reset();
+                            self.$chX.cr.reset();
                         )+
 
                         Channels((), $($CX { _0: () }),+)
@@ -322,58 +381,37 @@ macro_rules! dma {
 dma! {
     DMA1: (dma1, dma1en, dma1rst, {
         C1: (
-            ccr1, CCR1,
-            cndtr1, CNDTR1,
-            cpar1, CPAR1,
-            cmar1, CMAR1,
+            ch1,
             htif1, tcif1,
             chtif1, ctcif1, cgif1
         ),
         C2: (
-            ccr2, CCR2,
-            cndtr2, CNDTR2,
-            cpar2, CPAR2,
-            cmar2, CMAR2,
+            ch2,
             htif2, tcif2,
             chtif2, ctcif2, cgif2
         ),
         C3: (
-            ccr3, CCR3,
-            cndtr3, CNDTR3,
-            cpar3, CPAR3,
-            cmar3, CMAR3,
+            ch3,
             htif3, tcif3,
             chtif3, ctcif3, cgif3
         ),
         C4: (
-            ccr4, CCR4,
-            cndtr4, CNDTR4,
-            cpar4, CPAR4,
-            cmar4, CMAR4,
+            ch4,
             htif4, tcif4,
             chtif4, ctcif4, cgif4
         ),
         C5: (
-            ccr5, CCR5,
-            cndtr5, CNDTR5,
-            cpar5, CPAR5,
-            cmar5, CMAR5,
+            ch5,
             htif5, tcif5,
             chtif5, ctcif5, cgif5
         ),
         C6: (
-            ccr6, CCR6,
-            cndtr6, CNDTR6,
-            cpar6, CPAR6,
-            cmar6, CMAR6,
+            ch6,
             htif6, tcif6,
             chtif6, ctcif6, cgif6
         ),
         C7: (
-            ccr7, CCR7,
-            cndtr7, CNDTR7,
-            cpar7, CPAR7,
-            cmar7, CMAR7,
+            ch7,
             htif7, tcif7,
             chtif7, ctcif7, cgif7
         ),
@@ -381,49 +419,86 @@ dma! {
 
     DMA2: (dma2, dma2en, dma2rst, {
         C1: (
-            ccr1, CCR1,
-            cndtr1, CNDTR1,
-            cpar1, CPAR1,
-            cmar1, CMAR1,
+            ch1,
             htif1, tcif1,
             chtif1, ctcif1, cgif1
         ),
         C2: (
-            ccr2, CCR2,
-            cndtr2, CNDTR2,
-            cpar2, CPAR2,
-            cmar2, CMAR2,
+            ch2,
             htif2, tcif2,
             chtif2, ctcif2, cgif2
         ),
         C3: (
-            ccr3, CCR3,
-            cndtr3, CNDTR3,
-            cpar3, CPAR3,
-            cmar3, CMAR3,
+            ch3,
             htif3, tcif3,
             chtif3, ctcif3, cgif3
         ),
         C4: (
-            ccr4, CCR4,
-            cndtr4, CNDTR4,
-            cpar4, CPAR4,
-            cmar4, CMAR4,
+            ch4,
             htif4, tcif4,
             chtif4, ctcif4, cgif4
         ),
         C5: (
-            ccr5, CCR5,
-            cndtr5, CNDTR5,
-            cpar5, CPAR5,
-            cmar5, CMAR5,
+            ch5,
             htif5, tcif5,
             chtif5, ctcif5, cgif5
         ),
     }),
 }
-*/
 
-pub trait DmaChannel {
-    type Dma;
+/// DMA Receiver
+pub struct RxDma<PAYLOAD, RXCH> {
+    pub(crate) _payload: PhantomData<PAYLOAD>,
+    pub(crate) channel: RXCH,
+}
+
+/// DMA Transmitter
+pub struct TxDma<PAYLOAD, TXCH> {
+    pub(crate) _payload: PhantomData<PAYLOAD>,
+    pub(crate) channel: TXCH,
+}
+
+/// DMA Receiver/Transmitter
+pub struct RxTxDma<PAYLOAD, RXCH, TXCH> {
+    pub(crate) _payload: PhantomData<PAYLOAD>,
+    pub(crate) rxchannel: RXCH,
+    pub(crate) txchannel: TXCH,
+}
+
+pub trait Receive {
+    type RxChannel;
+    type TransmittedWord;
+}
+
+pub trait Transmit {
+    type TxChannel;
+    type ReceivedWord;
+}
+
+pub trait CircReadDma<B, RS>: Receive
+where
+    B: AsMut<[RS]>,
+    Self: core::marker::Sized,
+{
+    fn circ_read(self, buffer: &'static mut [B; 2]) -> CircBuffer<B, Self::RxChannel>;
+}
+
+pub trait ReadDma<B, RS>: Receive
+where
+    B: AsMut<[RS]>,
+    Self: core::marker::Sized,
+{
+    fn read(
+        self,
+        buffer: &'static mut B,
+    ) -> Transfer<W, &'static mut B, Self>;
+}
+
+pub trait WriteDma<A, B, TS>: Transmit
+where
+    A: AsRef<[TS]>,
+    B: Static<A>,
+    Self: core::marker::Sized,
+{
+    fn write(self, buffer: B) -> Transfer<R, B, Self>;
 }

+ 1 - 0
src/flash.rs

@@ -27,6 +27,7 @@ pub struct ACR {
     _0: (),
 }
 
+#[allow(dead_code)]
 impl ACR {
     pub(crate) fn acr(&mut self) -> &flash::ACR {
         // NOTE(unsafe) this proxy grants exclusive access to this register

+ 3 - 3
src/prelude.rs

@@ -1,5 +1,4 @@
 pub use crate::afio::AfioExt as _stm32_hal_afio_AfioExt;
-pub use crate::dma::DmaChannel as _stm32_hal_dma_DmaChannel;
 pub use crate::dma::DmaExt as _stm32_hal_dma_DmaExt;
 pub use crate::flash::FlashExt as _stm32_hal_flash_FlashExt;
 pub use crate::gpio::GpioExt as _stm32_hal_gpio_GpioExt;
@@ -9,6 +8,7 @@ pub use crate::hal::digital::ToggleableOutputPin as _embedded_hal_digital_Toggle
 pub use crate::hal::prelude::*;
 pub use crate::pwm::PwmExt as _stm32_hal_pwm_PwmExt;
 pub use crate::rcc::RccExt as _stm32_hal_rcc_RccExt;
-//pub use crate::serial::ReadDma as _stm32_hal_serial_ReadDma;
-//pub use crate::serial::WriteDma as _stm32_hal_serial_WriteDma;
+pub use crate::dma::CircReadDma as _stm32_hal_dma_CircReadDma;
+pub use crate::dma::ReadDma as _stm32_hal_dma_ReadDma;
+pub use crate::dma::WriteDma as _stm32_hal_dma_WriteDma;
 pub use crate::time::U32Ext as _stm32_hal_time_U32Ext;

+ 0 - 24
src/pwm.rs

@@ -288,10 +288,7 @@ macro_rules! hal {
                 }
 
                 fn get_duty(&self) -> u16 {
-                    #[cfg(feature = "stm32f103")]
                     unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() }
-                    #[cfg(not(feature = "stm32f103"))]
-                    unsafe { (*$TIMX::ptr()).ccr1.read().ccr1().bits() }
                 }
 
                 fn get_max_duty(&self) -> u16 {
@@ -299,10 +296,7 @@ macro_rules! hal {
                 }
 
                 fn set_duty(&mut self, duty: u16) {
-                    #[cfg(feature = "stm32f103")]
                     unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty)) }
-                    #[cfg(not(feature = "stm32f103"))]
-                    unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr1().bits(duty)) }
                 }
             }
 
@@ -318,10 +312,7 @@ macro_rules! hal {
                 }
 
                 fn get_duty(&self) -> u16 {
-                    #[cfg(feature = "stm32f103")]
                     unsafe { (*$TIMX::ptr()).ccr2.read().ccr().bits() }
-                    #[cfg(not(feature = "stm32f103"))]
-                    unsafe { (*$TIMX::ptr()).ccr2.read().ccr2().bits() }
                 }
 
                 fn get_max_duty(&self) -> u16 {
@@ -329,10 +320,7 @@ macro_rules! hal {
                 }
 
                 fn set_duty(&mut self, duty: u16) {
-                    #[cfg(feature = "stm32f103")]
                     unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr().bits(duty)) }
-                    #[cfg(not(feature = "stm32f103"))]
-                    unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr2().bits(duty)) }
                 }
             }
 
@@ -348,10 +336,7 @@ macro_rules! hal {
                 }
 
                 fn get_duty(&self) -> u16 {
-                    #[cfg(feature = "stm32f103")]
                     unsafe { (*$TIMX::ptr()).ccr3.read().ccr().bits() }
-                    #[cfg(not(feature = "stm32f103"))]
-                    unsafe { (*$TIMX::ptr()).ccr3.read().ccr3().bits() }
                 }
 
                 fn get_max_duty(&self) -> u16 {
@@ -359,10 +344,7 @@ macro_rules! hal {
                 }
 
                 fn set_duty(&mut self, duty: u16) {
-                    #[cfg(feature = "stm32f103")]
                     unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr().bits(duty)) }
-                    #[cfg(not(feature = "stm32f103"))]
-                    unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr3().bits(duty)) }
                 }
             }
 
@@ -378,10 +360,7 @@ macro_rules! hal {
                 }
 
                 fn get_duty(&self) -> u16 {
-                    #[cfg(feature = "stm32f103")]
                     unsafe { (*$TIMX::ptr()).ccr4.read().ccr().bits() }
-                    #[cfg(not(feature = "stm32f103"))]
-                    unsafe { (*$TIMX::ptr()).ccr4.read().ccr4().bits() }
                 }
 
                 fn get_max_duty(&self) -> u16 {
@@ -389,10 +368,7 @@ macro_rules! hal {
                 }
 
                 fn set_duty(&mut self, duty: u16) {
-                    #[cfg(feature = "stm32f103")]
                     unsafe { (*$TIMX::ptr()).ccr4.write(|w| w.ccr().bits(duty)) }
-                    #[cfg(not(feature = "stm32f103"))]
-                    unsafe { (*$TIMX::ptr()).ccr4.write(|w| w.ccr4().bits(duty)) }
                 }
             }
         )+

+ 1 - 1
src/pwm_input.rs

@@ -4,7 +4,7 @@
 use core::marker::PhantomData;
 use core::mem;
 
-use crate::stm32::{DBG, TIM1, TIM2, TIM3, TIM4};
+use crate::stm32::{DBGMCU as DBG, TIM1, TIM2, TIM3, TIM4};
 
 use crate::afio::MAPR;
 use crate::gpio::gpioa::{PA0, PA1, PA15, PA6, PA7, PA8, PA9};

+ 1 - 1
src/qei.rs

@@ -94,7 +94,7 @@ macro_rules! hal {
                     });
 
                     // configure as quadrature encoder
-                    tim.smcr.write(|w| unsafe { w.sms().bits(3) });
+                    tim.smcr.write(|w| w.sms().bits(3));
 
                     tim.arr.write(|w| w.arr().bits(u16::MAX));
                     tim.cr1.write(|w| w.cen().set_bit());

+ 153 - 197
src/serial.rs

@@ -38,15 +38,14 @@
 
 use core::marker::PhantomData;
 use core::ptr;
+use core::sync::atomic::{self, Ordering};
 
 use nb;
 use crate::pac::{USART1, USART2, USART3};
 use void::Void;
-use embedded_hal::serial::Write;
 
 use crate::afio::MAPR;
-//use crate::dma::{dma1, CircBuffer, Static, Transfer, R, W};
-// use crate::dma::{CircBuffer, Static, Transfer, R, W};
+use crate::dma::{dma1, CircBuffer, Static, Transfer, R, W, RxDma, TxDma};
 use crate::gpio::gpioa::{PA10, PA2, PA3, PA9};
 use crate::gpio::gpiob::{PB10, PB11, PB6, PB7};
 use crate::gpio::{Alternate, Floating, Input, PushPull};
@@ -282,149 +281,6 @@ macro_rules! hal {
                 }
             }
 
-            /*
-            impl<B> ReadDma<B> for Rx<$USARTX> where B: AsMut<[u8]> {
-                fn circ_read(self, mut chan: Self::Dma, buffer: &'static mut [B; 2],
-                ) -> CircBuffer<B, Self::Dma>
-                {
-                    {
-                        let buffer = buffer[0].as_mut();
-                        chan.cmar().write(|w| {
-                            w.ma().bits(buffer.as_ptr() as usize as u32)
-                        });
-                        chan.cndtr().write(|w| {
-                            w.ndt().bits(u16(buffer.len() * 2).unwrap())
-                        });
-                        chan.cpar().write(|w| unsafe {
-                            w.pa().bits(&(*$USARTX::ptr()).dr as *const _ as usize as u32)
-                        });
-
-                        // TODO can we weaken this compiler barrier?
-                        // NOTE(compiler_fence) operations on `buffer` should not be reordered after
-                        // the next statement, which starts the DMA transfer
-                        atomic::compiler_fence(Ordering::SeqCst);
-
-                        chan.ccr().modify(|_, w| {
-                            w.mem2mem()
-                                .clear_bit()
-                                .pl()
-                                .medium()
-                                .msize()
-                                .bit8()
-                                .psize()
-                                .bit8()
-                                .minc()
-                                .set_bit()
-                                .pinc()
-                                .clear_bit()
-                                .circ()
-                                .set_bit()
-                                .dir()
-                                .clear_bit()
-                                .en()
-                                .set_bit()
-                        });
-                    }
-
-                    CircBuffer::new(buffer, chan)
-                }
-
-                fn read_exact(self, mut chan: Self::Dma, buffer: &'static mut B,
-                ) -> Transfer<W, &'static mut B, Self::Dma, Self>
-                {
-                    {
-                        let buffer = buffer.as_mut();
-                        chan.cmar().write(|w| {
-                            w.ma().bits(buffer.as_ptr() as usize as u32)
-                        });
-                        chan.cndtr().write(|w| {
-                            w.ndt().bits(u16(buffer.len()).unwrap())
-                        });
-                        chan.cpar().write(|w| unsafe {
-                            w.pa().bits(&(*$USARTX::ptr()).dr as *const _ as usize as u32)
-                        });
-
-                        // TODO can we weaken this compiler barrier?
-                        // NOTE(compiler_fence) operations on `buffer` should not be reordered after
-                        // the next statement, which starts the DMA transfer
-                        atomic::compiler_fence(Ordering::SeqCst);
-
-                        chan.ccr().modify(|_, w| {
-                            w.mem2mem()
-                                .clear_bit()
-                                .pl()
-                                .medium()
-                                .msize()
-                                .bit8()
-                                .psize()
-                                .bit8()
-                                .minc()
-                                .set_bit()
-                                .pinc()
-                                .clear_bit()
-                                .circ()
-                                .clear_bit()
-                                .dir()
-                                .clear_bit()
-                                .en()
-                                .set_bit()
-                        });
-                    }
-
-                    Transfer::w(buffer, chan, self)
-                }
-            }
-            */
-
-            /*
-            impl<A, B> WriteDma<A, B> for Tx<$USARTX> where A: AsRef<[u8]>, B: Static<A> {
-                fn write_all(self, mut chan: Self::Dma, buffer: B
-                ) -> Transfer<R, B, Self::Dma, Self>
-                {
-                    {
-                        let buffer = buffer.borrow().as_ref();
-                        chan.cmar().write(|w| {
-                            w.ma().bits(buffer.as_ptr() as usize as u32)
-                        });
-                        chan.cndtr().write(|w| {
-                            w.ndt().bits(u16(buffer.len()).unwrap())
-                        });
-                        chan.cpar().write(|w| unsafe {
-                            w.pa().bits(&(*$USARTX::ptr()).dr as *const _ as usize as u32)
-                        });
-
-                        // TODO can we weaken this compiler barrier?
-                        // NOTE(compiler_fence) operations on `buffer` should not be reordered after
-                        // the next statement, which starts the DMA transfer
-                        atomic::compiler_fence(Ordering::SeqCst);
-
-                        chan.ccr().modify(|_, w| {
-                            w.mem2mem()
-                                .clear_bit()
-                                .pl()
-                                .medium()
-                                .msize()
-                                .bit8()
-                                .psize()
-                                .bit8()
-                                .minc()
-                                .set_bit()
-                                .pinc()
-                                .clear_bit()
-                                .circ()
-                                .clear_bit()
-                                .dir()
-                                .set_bit()
-                                .en()
-                                .set_bit()
-                        });
-                    }
-
-                    Transfer::r(buffer, chan, self)
-                }
-            }
-            */
-
             impl crate::hal::serial::Write<u8> for Tx<$USARTX> {
                 type Error = Void;
 
@@ -495,64 +351,164 @@ hal! {
     ),
 }
 
-/*
-use dma::DmaChannel;
+use crate::dma::{Transmit, Receive};
 
-impl DmaChannel for Rx<USART1> {
-    type Dma = dma1::C5;
-}
+macro_rules! serialdma {
+    ($(
+        $USARTX:ident: (
+            $dmarxch:ty,
+            $dmatxch:ty,
+        ),
+    )+) => {
+        $(
+            impl Receive for RxDma<$USARTX, $dmarxch> {
+                type RxChannel = $dmarxch;
+                type TransmittedWord = u8;
+            }
 
-impl DmaChannel for Tx<USART1> {
-    type Dma = dma1::C4;
-}
+            impl Transmit for TxDma<$USARTX, $dmatxch> {
+                type TxChannel = $dmatxch;
+                type ReceivedWord = u8;
+            }
 
-impl DmaChannel for Rx<USART2> {
-    type Dma = dma1::C6;
-}
+            impl Rx<$USARTX> {
+                pub fn with_dma(self, channel: $dmarxch) -> RxDma<$USARTX, $dmarxch> {
+                    RxDma {
+                        _payload: PhantomData,
+                        channel,
+                    }
+                }
+            }
 
-impl DmaChannel for Tx<USART2> {
-    type Dma = dma1::C7;
-}
+            impl Tx<$USARTX> {
+                pub fn with_dma(self, channel: $dmatxch) -> TxDma<$USARTX, $dmatxch> {
+                    TxDma {
+                        _payload: PhantomData,
+                        channel,
+                    }
+                }
+            }
 
-impl DmaChannel for Rx<USART3> {
-    type Dma = dma1::C3;
-}
+            impl RxDma<$USARTX, $dmarxch> {
+                pub fn split(mut self) -> (Rx<$USARTX>, $dmarxch) {
+                    self.stop();
+                    let RxDma {_payload, channel} = self;
+                    (
+                        Rx { _usart: PhantomData },
+                        channel
+                    )
+                }
+            }
 
-impl DmaChannel for Tx<USART3> {
-    type Dma = dma1::C2;
-}
+            impl TxDma<$USARTX, $dmatxch> {
+                pub fn split(mut self) -> (Tx<$USARTX>, $dmatxch) {
+                    self.stop();
+                    let TxDma {_payload, channel} = self;
+                    (
+                        Tx { _usart: PhantomData },
+                        channel,
+                    )
+                }
+            }
 
-pub trait ReadDma<B>: DmaChannel
-where
-    B: AsMut<[u8]>,
-    Self: core::marker::Sized,
-{
-    fn circ_read(self, chan: Self::Dma, buffer: &'static mut [B; 2]) -> CircBuffer<B, Self::Dma>;
-    fn read_exact(
-        self,
-        chan: Self::Dma,
-        buffer: &'static mut B,
-    ) -> Transfer<W, &'static mut B, Self::Dma, Self>;
-}
+            impl<B> crate::dma::CircReadDma<B, u8> for RxDma<$USARTX, $dmarxch> where B: AsMut<[u8]> {
+                fn circ_read(mut self, buffer: &'static mut [B; 2],
+                ) -> CircBuffer<B, $dmarxch>
+                {
+                    {
+                        let buffer = buffer[0].as_mut();
+                        self.channel.set_peripheral_address(unsafe{ &(*$USARTX::ptr()).dr as *const _ as u32 }, false);
+                        self.channel.set_memory_address(buffer.as_ptr() as u32, true);
+                        self.channel.set_transfer_length(buffer.len() * 2);
+
+                        atomic::compiler_fence(Ordering::Release);
+
+                        self.channel.ch().cr.modify(|_, w| { w
+                            .mem2mem() .clear_bit()
+                            .pl()      .medium()
+                            .msize()   .bit8()
+                            .psize()   .bit8()
+                            .circ()    .set_bit()
+                            .dir()     .clear_bit()
+                        });
+                    }
 
-pub trait WriteDma<A, B>: DmaChannel
-where
-    A: AsRef<[u8]>,
-    B: Static<A>,
-    Self: core::marker::Sized,
-{
-    fn write_all(self, chan: Self::Dma, buffer: B) -> Transfer<R, B, Self::Dma, Self>;
-}
-*/
-
-impl<USART> core::fmt::Write for Tx<USART>
-where
-    Tx<USART>: embedded_hal::serial::Write<u8>,
-{
-    fn write_str(&mut self, s: &str) -> core::fmt::Result {
-        s.as_bytes()
-            .iter()
-            .try_for_each(|c| nb::block!(self.write(*c)))
-            .map_err(|_| core::fmt::Error)
+                    self.start();
+
+                    let RxDma {_payload, channel} = self;
+
+                    CircBuffer::new(buffer, channel)
+                }
+            }
+
+            impl<B> crate::dma::ReadDma<B, u8> for RxDma<$USARTX, $dmarxch> where B: AsMut<[u8]> {
+                fn read(mut self, buffer: &'static mut B,
+                ) -> Transfer<W, &'static mut B, Self>
+                {
+                    {
+                        let buffer = buffer.as_mut();
+                        self.channel.set_peripheral_address(unsafe{ &(*$USARTX::ptr()).dr as *const _ as u32 }, false);
+                        self.channel.set_memory_address(buffer.as_ptr() as u32, true);
+                        self.channel.set_transfer_length(buffer.len());
+                    }
+                    atomic::compiler_fence(Ordering::Release);
+                    self.channel.ch().cr.modify(|_, w| { w
+                        .mem2mem() .clear_bit()
+                        .pl()      .medium()
+                        .msize()   .bit8()
+                        .psize()   .bit8()
+                        .circ()    .clear_bit()
+                        .dir()     .clear_bit()
+                    });
+                    self.start();
+
+                    Transfer::w(buffer, self)
+                }
+            }
+
+            impl<A, B> crate::dma::WriteDma<A, B, u8> for TxDma<$USARTX, $dmatxch> where A: AsRef<[u8]>, B: Static<A> {
+                fn write(mut self, buffer: B
+                ) -> Transfer<R, B, Self>
+                {
+                    {
+                        let buffer = buffer.borrow().as_ref();
+
+                        self.channel.set_peripheral_address(unsafe{ &(*$USARTX::ptr()).dr as *const _ as u32 }, false);
+
+                        self.channel.set_memory_address(buffer.as_ptr() as u32, true);
+                        self.channel.set_transfer_length(buffer.len());
+                    }
+
+                    atomic::compiler_fence(Ordering::Release);
+
+                    self.channel.ch().cr.modify(|_, w| { w
+                        .mem2mem() .clear_bit()
+                        .pl()      .medium()
+                        .msize()   .bit8()
+                        .psize()   .bit8()
+                        .circ()    .clear_bit()
+                        .dir()     .set_bit()
+                    });
+                    self.start();
+
+                    Transfer::r(buffer, self)
+                }
+            }
+        )+
     }
 }
+
+serialdma! {
+    USART1: (
+        dma1::C5,
+        dma1::C4,
+    ),
+    USART2: (
+        dma1::C6,
+        dma1::C7,
+    ),
+    USART3: (
+        dma1::C3,
+        dma1::C2,
+    ),
+}

+ 2 - 2
src/spi.rs

@@ -140,7 +140,7 @@ macro_rules! hal {
                     // dff: 8 bit frames
                     // bidimode: 2-line unidirectional
                     // spe: enable the SPI bus
-                    spi.cr1.write(|w| unsafe {
+                    spi.cr1.write(|w|
                         w.cpha()
                             .bit(mode.phase == Phase::CaptureOnSecondTransition)
                             .cpol()
@@ -163,7 +163,7 @@ macro_rules! hal {
                             .clear_bit()
                             .spe()
                             .set_bit()
-                    });
+                    );
 
                     Spi { spi, pins }
                 }

+ 1 - 1
src/watchdog.rs

@@ -1,7 +1,7 @@
 //! Watchdog peripherals
 
 use crate::{
-    stm32::{IWDG, DBG},
+    stm32::{IWDG, DBGMCU as DBG},
     hal::watchdog::{Watchdog, WatchdogEnable},
     time::MilliSeconds,
 };