Browse Source

Adds DMA support for ADC1 (#73)

* Adds DMA support for ADC
Thales 5 years ago
parent
commit
4fdc432df2
9 changed files with 355 additions and 67 deletions
  1. 1 0
      CHANGELOG.md
  2. 61 0
      examples/adc-dma-circ.rs
  3. 58 0
      examples/adc-dma-rx.rs
  4. 2 2
      examples/adc.rs
  5. 1 1
      examples/adc_temperature.rs
  6. 158 11
      src/adc.rs
  7. 43 38
      src/dma.rs
  8. 1 1
      src/rcc.rs
  9. 30 14
      src/serial.rs

+ 1 - 0
CHANGELOG.md

@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 
 ### Added
 
+- Added DMA support for ADC1.
 - Added type aliases `Tx1` for `Tx<USART1>`, `RxDma1` for `RxDma<USART1, dma1::C5>`, etc.
 - Add ADC1 reading functions for channels 16 (temperature) and 17 (internal reference voltage)
 - Update existing ADC example according to ADC API changes

+ 61 - 0
examples/adc-dma-circ.rs

@@ -0,0 +1,61 @@
+//! ADC interface circular DMA RX transfer test
+
+#![no_main]
+#![no_std]
+
+use panic_halt as _;
+
+use cortex_m::{asm, singleton};
+
+use stm32f1xx_hal::{
+    prelude::*,
+    pac,
+    adc,
+    dma::Half,
+};
+use cortex_m_rt::entry;
+
+#[entry]
+fn main() -> ! {
+    // Aquire peripherals
+    let p = pac::Peripherals::take().unwrap();
+    let mut flash = p.FLASH.constrain();
+    let mut rcc = p.RCC.constrain();
+
+    // Configure ADC clocks
+    // Default value is the slowest possible ADC clock: PCLK2 / 8. Meanwhile ADC
+    // clock is configurable. So its frequency may be tweaked to meet certain
+    // 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);
+
+    let dma_ch1 = p.DMA1.split(&mut rcc.ahb).1;
+
+    // Setup ADC
+    let adc1 = adc::Adc::adc1(p.ADC1, &mut rcc.apb2, clocks);
+
+    // Setup GPIOA
+    let mut gpioa = p.GPIOA.split(&mut rcc.apb2);
+
+    // Configure pa0 as an analog input
+    let adc_ch0 = gpioa.pa0.into_analog(&mut gpioa.crl);
+
+    let adc_dma = adc1.with_dma(adc_ch0, dma_ch1);
+    let buf = singleton!(: [[u16; 8]; 2] = [[0; 8]; 2]).unwrap();
+
+    let mut circ_buffer = adc_dma.circ_read(buf);
+
+    while circ_buffer.readable_half().unwrap() != Half::First {}
+
+    let _first_half = circ_buffer.peek(|half, _| *half).unwrap();
+
+    while circ_buffer.readable_half().unwrap() != Half::Second {}
+
+    let _second_half = circ_buffer.peek(|half, _| *half).unwrap();
+
+    let (_buf, adc_dma) = circ_buffer.stop();
+    let (_adc1, _adc_ch0, _dma_ch1) = adc_dma.split();
+    asm::bkpt();
+
+    loop {}
+}

+ 58 - 0
examples/adc-dma-rx.rs

@@ -0,0 +1,58 @@
+//! ADC interface DMA RX transfer test
+
+#![no_main]
+#![no_std]
+
+use panic_halt as _;
+
+use cortex_m::{asm, singleton};
+
+use stm32f1xx_hal::{
+    prelude::*,
+    pac,
+    adc,
+};
+use cortex_m_rt::entry;
+
+#[entry]
+fn main() -> ! {
+    // Aquire peripherals
+    let p = pac::Peripherals::take().unwrap();
+    let mut flash = p.FLASH.constrain();
+    let mut rcc = p.RCC.constrain();
+
+    // Configure ADC clocks
+    // Default value is the slowest possible ADC clock: PCLK2 / 8. Meanwhile ADC
+    // clock is configurable. So its frequency may be tweaked to meet certain
+    // 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);
+
+    let dma_ch1 = p.DMA1.split(&mut rcc.ahb).1;
+
+    // Setup ADC
+    let adc1 = adc::Adc::adc1(p.ADC1, &mut rcc.apb2, clocks);
+
+    // Setup GPIOA
+    let mut gpioa = p.GPIOA.split(&mut rcc.apb2);
+
+    // Configure pa0 as an analog input
+    let adc_ch0 = gpioa.pa0.into_analog(&mut gpioa.crl);
+
+    let adc_dma = adc1.with_dma(adc_ch0, dma_ch1);
+    let buf = singleton!(: [u16; 8] = [0; 8]).unwrap();
+
+    // The read method consumes the buf and self, starts the adc and dma transfer and returns a
+    // RxDma struct. The wait method consumes the RxDma struct, waits for the whole transfer to be
+    // completed and then returns the updated buf and underlying adc_dma struct. For non blocking,
+    // one can call the is_done method of RxDma and only call wait after that method returns true.
+    let (_buf, adc_dma) = adc_dma.read(buf).wait();
+    asm::bkpt();
+    
+    // Consumes the AdcDma struct, restores adc configuration to previous state and returns the
+    // Adc struct in normal mode.
+    let (_adc1, _adc_ch0, _dma_ch1) = adc_dma.split();
+    asm::bkpt();
+
+    loop {}
+}

+ 2 - 2
examples/adc.rs

@@ -29,10 +29,10 @@ fn main() -> ! {
     hprintln!("adc freq: {}", clocks.adcclk().0).unwrap();
 
     // Setup ADC
-    let mut adc1 = adc::Adc::adc1(p.ADC1, &mut rcc.apb2, clocks.adcclk());
+    let mut adc1 = adc::Adc::adc1(p.ADC1, &mut rcc.apb2, clocks);
 
     #[cfg(feature = "stm32f103")]
-    let mut adc2 = adc::Adc::adc2(p.ADC2, &mut rcc.apb2, clocks.adcclk());
+    let mut adc2 = adc::Adc::adc2(p.ADC2, &mut rcc.apb2, clocks);
 
     // Setup GPIOB
     let mut gpiob = p.GPIOB.split(&mut rcc.apb2);

+ 1 - 1
examples/adc_temperature.rs

@@ -25,7 +25,7 @@ fn main() -> ! {
     hprintln!("adc freq: {}", clocks.adcclk().0).unwrap();
 
     // Setup ADC
-    let mut adc = adc::Adc::adc1(p.ADC1, &mut rcc.apb2, clocks.adcclk());
+    let mut adc = adc::Adc::adc1(p.ADC1, &mut rcc.apb2, clocks);
 
     // Read temperature sensor
     loop {

+ 158 - 11
src/adc.rs

@@ -4,8 +4,10 @@ use embedded_hal::adc::{Channel, OneShot};
 
 use crate::gpio::Analog;
 use crate::gpio::{gpioa, gpiob, gpioc};
-use crate::rcc::APB2;
-use crate::time::Hertz;
+use crate::rcc::{APB2, Clocks};
+use crate::dma::{Receive, TransferPayload, dma1::C1, CircBuffer, Transfer, W, RxDma};
+use core::sync::atomic::{self, Ordering};
+use cortex_m::asm::delay;
 
 use crate::stm32::ADC1;
 #[cfg(any(
@@ -18,7 +20,7 @@ pub struct Adc<ADC> {
     rb: ADC,
     sample_time: AdcSampleTime,
     align: AdcAlign,
-    clk: Hertz
+    clocks: Clocks
 }
 
 #[derive(Clone, Copy, Debug, PartialEq)]
@@ -173,18 +175,29 @@ macro_rules! adc_hal {
                 ///
                 /// Sets all configurable parameters to one-shot defaults,
                 /// performs a boot-time calibration.
-                pub fn $init(adc: $ADC, apb2: &mut APB2, clk: Hertz) -> Self {
+                pub fn $init(adc: $ADC, apb2: &mut APB2, clocks: Clocks) -> Self {
                     let mut s = Self {
                         rb: adc,
                         sample_time: AdcSampleTime::default(),
                         align: AdcAlign::default(),
-                        clk: clk,
+                        clocks,
                     };
                     s.enable_clock(apb2);
                     s.power_down();
                     s.reset(apb2);
                     s.setup_oneshot();
                     s.power_up();
+
+                    // The manual states that we need to wait two ADC clocks cycles after power-up
+                    // before starting calibration, we already delayed in the power-up process, but
+                    // if the adc clock is too low that was not enough.
+                    if s.clocks.adcclk().0 < 2_500_000 {
+                        let two_adc_cycles = s.clocks.sysclk().0 / s.clocks.adcclk().0 *2;
+                        let already_delayed = s.clocks.sysclk().0 / 800_000;
+                        if two_adc_cycles > already_delayed {
+                            delay(two_adc_cycles - already_delayed);
+                        }
+                    }
                     s.calibrate();
                     s
                 }
@@ -232,6 +245,12 @@ macro_rules! adc_hal {
 
                 fn power_up(&mut self) {
                     self.rb.cr2.modify(|_, w| w.adon().set_bit());
+
+                    // The reference manual says that a stabilization time is needed after power_up,
+                    // this time can be found in the datasheets.
+                    // Here we are delaying for approximately 1us, considering 1.25 instructions per
+                    // cycle. Do we support a chip which needs more than 1us ?
+                    delay(self.clocks.sysclk().0 / 800_000);
                 }
 
                 fn power_down(&mut self) {
@@ -247,6 +266,10 @@ macro_rules! adc_hal {
                     apb2.enr().modify(|_, w| w.$adcxen().set_bit());
                 }
 
+                fn disable_clock(&mut self, apb2: &mut APB2) {
+                    apb2.enr().modify(|_, w| w.$adcxen().clear_bit());
+                }
+
                 fn calibrate(&mut self) {
                     /* reset calibration */
                     self.rb.cr2.modify(|_, w| w.rstcal().set_bit());
@@ -363,6 +386,13 @@ macro_rules! adc_hal {
                     let res = self.rb.dr.read().data().bits();
                     res
                 }
+
+                /// Powers down the ADC, disables the ADC clock and releases the ADC Peripheral
+                pub fn release(mut self, apb2: &mut APB2) -> $ADC {
+                    self.power_down();
+                    self.disable_clock(apb2);
+                    self.rb
+                }
             }
 
             impl<WORD, PIN> OneShot<$ADC, WORD, PIN> for Adc<$ADC>
@@ -373,9 +403,7 @@ macro_rules! adc_hal {
                     type Error = ();
 
                     fn read(&mut self, _pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
-                        self.power_up();
                         let res = self.convert(PIN::channel());
-                        self.power_down();
                         Ok(res.into())
                     }
                 }
@@ -388,14 +416,18 @@ impl Adc<ADC1> {
     fn read_aux(&mut self, chan: u8) -> u16 {
         let tsv_off = if self.rb.cr2.read().tsvrefe().bit_is_clear() {
             self.rb.cr2.modify(|_, w| w.tsvrefe().set_bit());
+
+            // The reference manual says that a stabilization time is needed after the powering the
+            // sensor, this time can be found in the datasheets.
+            // Here we are delaying for approximately 10us, considering 1.25 instructions per
+            // cycle. Do we support a chip which needs more than 10us ?
+            delay(self.clocks.sysclk().0 / 80_000);
             true
         } else {
             false
         };
 
-        self.power_up();
         let val = self.convert(chan);
-        self.power_down();
 
         if tsv_off {
             self.rb.cr2.modify(|_, w| w.tsvrefe().clear_bit());
@@ -429,14 +461,14 @@ impl Adc<ADC1> {
         // recommended ADC sampling for temperature sensor is 17.1 usec,
         // so use the following approximate settings
         // to support all ADC frequencies
-        let sample_time = match self.clk.0 {
+        let sample_time = match self.clocks.adcclk().0 {
             0 ... 1_200_000 => AdcSampleTime::T_1,
             1_200_001 ... 1_500_000 => AdcSampleTime::T_7,
             1_500_001 ... 2_400_000 => AdcSampleTime::T_13,
             2_400_001 ... 3_100_000 => AdcSampleTime::T_28,
             3_100_001 ... 4_000_000 => AdcSampleTime::T_41,
             4_000_001 ... 5_000_000 => AdcSampleTime::T_55,
-            5_000_001 ... 10_000_000 => AdcSampleTime::T_71,
+            5_000_001 ... 14_000_000 => AdcSampleTime::T_71,
             _ => AdcSampleTime::T_239,
         };
 
@@ -490,3 +522,118 @@ adc_hal! {
         adc2rst
     ),
 }
+
+pub struct AdcPayload<PIN: Channel<ADC1>> {
+    adc: Adc<ADC1>,
+    pin: PIN,
+}
+
+pub type AdcDma<PIN> = RxDma<AdcPayload<PIN>, C1>;
+
+impl<PIN> Receive for AdcDma<PIN> where PIN: Channel<ADC1> {
+    type RxChannel = C1;
+    type TransmittedWord = u16;
+}
+
+impl<PIN> TransferPayload for AdcDma<PIN> where PIN: Channel<ADC1> {
+    fn start(&mut self) {
+        self.channel.start();
+        self.payload.adc.rb.cr2.modify(|_, w| w.cont().set_bit());
+        self.payload.adc.rb.cr2.modify(|_, w| w.adon().set_bit());
+    }
+    fn stop(&mut self) {
+        self.channel.stop();
+        self.payload.adc.rb.cr2.modify(|_, w| w.cont().clear_bit());
+    }
+}
+
+impl Adc<ADC1> {
+    pub fn with_dma<PIN>(mut self, pin: PIN, dma_ch: C1) -> AdcDma<PIN>
+    where
+        PIN: Channel<ADC1, ID = u8>,
+    {
+        self.rb.cr1.modify(|_, w| w.discen().clear_bit());
+        self.rb.cr2.modify(|_, w| w.align().bit(self.align.into()));
+        self.set_chan_smps(PIN::channel());
+        self.rb.sqr3.modify(|_, w| unsafe { w.sq1().bits(PIN::channel()) });
+        self.rb.cr2.modify(|_, w| w.dma().set_bit());
+
+        let payload = AdcPayload {
+            adc: self,
+            pin,
+        };
+        RxDma {
+            payload,
+            channel: dma_ch,
+        }
+    }
+}
+
+impl<PIN> AdcDma<PIN> where PIN: Channel<ADC1> {
+    pub fn split(mut self) -> (Adc<ADC1>, PIN, C1) {
+        self.stop();
+
+        let AdcDma {payload, channel} = self;
+        payload.adc.rb.cr2.modify(|_, w| w.dma().clear_bit());
+        payload.adc.rb.cr1.modify(|_, w| w.discen().set_bit());
+
+        (payload.adc, payload.pin, channel)
+    }
+}
+
+impl<B, PIN> crate::dma::CircReadDma<B, u16> for AdcDma<PIN>
+where
+    B: AsMut<[u16]>,
+    PIN: Channel<ADC1>,
+{
+    fn circ_read(mut self, buffer: &'static mut [B; 2]) -> CircBuffer<B, Self> {
+        {
+            let buffer = buffer[0].as_mut();
+            self.channel.set_peripheral_address(unsafe{ &(*ADC1::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()   .bit16()
+                .psize()   .bit16()
+                .circ()    .set_bit()
+                .dir()     .clear_bit()
+            });
+        }
+
+        self.start();
+
+        CircBuffer::new(buffer, self)
+    }
+}
+
+impl<B, PIN> crate::dma::ReadDma<B, u16> for AdcDma<PIN>
+where
+    B: AsMut<[u16]>,
+    PIN: Channel<ADC1>,
+{
+    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{ &(*ADC1::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()   .bit16()
+            .psize()   .bit16()
+            .circ()    .clear_bit()
+            .dir()     .clear_bit()
+        });
+        self.start();
+
+        Transfer::w(buffer, self)
+    }
+}

+ 43 - 38
src/dma.rs

@@ -24,20 +24,20 @@ pub enum Half {
     Second,
 }
 
-pub struct CircBuffer<BUFFER, CHANNEL>
+pub struct CircBuffer<BUFFER, PAYLOAD>
 where
     BUFFER: 'static,
 {
     buffer: &'static mut [BUFFER; 2],
-    channel: CHANNEL,
+    payload: PAYLOAD,
     readable_half: Half,
 }
 
-impl<BUFFER, CHANNEL> CircBuffer<BUFFER, CHANNEL> {
-    pub(crate) fn new(buf: &'static mut [BUFFER; 2], chan: CHANNEL) -> Self {
+impl<BUFFER, PAYLOAD> CircBuffer<BUFFER, PAYLOAD> {
+    pub(crate) fn new(buf: &'static mut [BUFFER; 2], payload: PAYLOAD) -> Self {
         CircBuffer {
             buffer: buf,
-            channel: chan,
+            payload,
             readable_half: Half::Second,
         }
     }
@@ -65,6 +65,11 @@ pub trait DmaExt {
     fn split(self, ahb: &mut AHB) -> Self::Channels;
 }
 
+pub trait TransferPayload {
+    fn start(&mut self);
+    fn stop(&mut self);
+}
+
 pub struct Transfer<MODE, BUFFER, PAYLOAD> {
     _mode: PhantomData<MODE>,
     buffer: BUFFER,
@@ -123,7 +128,7 @@ macro_rules! dma {
 
                 use crate::pac::{$DMAX, dma1};
 
-                use crate::dma::{CircBuffer, DmaExt, Error, Event, Half, Transfer, W, RxDma, TxDma};
+                use crate::dma::{CircBuffer, DmaExt, Error, Event, Half, Transfer, W, RxDma, TxDma, TransferPayload};
                 use crate::rcc::AHB;
 
                 pub struct Channels((), $(pub $CX),+);
@@ -213,7 +218,10 @@ macro_rules! dma {
                         }
                     }
 
-                    impl<B> CircBuffer<B, $CX> {
+                    impl<B, PAYLOAD> CircBuffer<B, RxDma<PAYLOAD, $CX>>
+                    where
+                        RxDma<PAYLOAD, $CX>: TransferPayload,
+                    {
                         /// Peeks into the readable half of the buffer
                         pub fn peek<R, F>(&mut self, f: F) -> Result<R, Error>
                             where
@@ -230,7 +238,7 @@ macro_rules! dma {
                             let ret = f(buf, half_being_read);
 
 
-                            let isr = self.channel.isr();
+                            let isr = self.payload.channel.isr();
                             let first_half_is_done = isr.$htifX().bit_is_set();
                             let second_half_is_done = isr.$tcifX().bit_is_set();
 
@@ -244,7 +252,7 @@ macro_rules! dma {
 
                         /// Returns the `Half` of the buffer that can be read
                         pub fn readable_half(&mut self) -> Result<Half, Error> {
-                            let isr = self.channel.isr();
+                            let isr = self.payload.channel.isr();
                             let first_half_is_done = isr.$htifX().bit_is_set();
                             let second_half_is_done = isr.$tcifX().bit_is_set();
 
@@ -257,7 +265,7 @@ macro_rules! dma {
                             Ok(match last_read_half {
                                 Half::First => {
                                     if second_half_is_done {
-                                        self.channel.ifcr().write(|w| w.$ctcifX().set_bit());
+                                        self.payload.channel.ifcr().write(|w| w.$ctcifX().set_bit());
 
                                         self.readable_half = Half::Second;
                                         Half::Second
@@ -267,7 +275,7 @@ macro_rules! dma {
                                 }
                                 Half::Second => {
                                     if first_half_is_done {
-                                        self.channel.ifcr().write(|w| w.$chtifX().set_bit());
+                                        self.payload.channel.ifcr().write(|w| w.$chtifX().set_bit());
 
                                         self.readable_half = Half::First;
                                         Half::First
@@ -277,9 +285,19 @@ macro_rules! dma {
                                 }
                             })
                         }
+
+                        /// Stops the transfer and returns the underlying buffer and RxDma
+                        pub fn stop(mut self) -> (&'static mut [B; 2], RxDma<PAYLOAD, $CX>) {
+                            self.payload.stop();
+
+                            (self.buffer, self.payload)
+                        }
                     }
 
-                    impl<BUFFER, PAYLOAD, MODE> Transfer<MODE, BUFFER, RxDma<PAYLOAD, $CX>> {
+                    impl<BUFFER, PAYLOAD, MODE> Transfer<MODE, BUFFER, RxDma<PAYLOAD, $CX>>
+                    where
+                        RxDma<PAYLOAD, $CX>: TransferPayload,
+                    {
                         pub fn is_done(&self) -> bool {
                             !self.payload.channel.in_progress()
                         }
@@ -302,7 +320,10 @@ macro_rules! dma {
                         }
                     }
 
-                    impl<BUFFER, PAYLOAD, MODE> Transfer<MODE, BUFFER, TxDma<PAYLOAD, $CX>> {
+                    impl<BUFFER, PAYLOAD, MODE> Transfer<MODE, BUFFER, TxDma<PAYLOAD, $CX>>
+                    where
+                        TxDma<PAYLOAD, $CX>: TransferPayload,
+                    {
                         pub fn is_done(&self) -> bool {
                             !self.payload.channel.in_progress()
                         }
@@ -325,7 +346,10 @@ macro_rules! dma {
                         }
                     }
 
-                    impl<BUFFER, PAYLOAD> Transfer<W, &'static mut BUFFER, RxDma<PAYLOAD, $CX>> {
+                    impl<BUFFER, PAYLOAD> Transfer<W, &'static mut BUFFER, RxDma<PAYLOAD, $CX>>
+                    where
+                        RxDma<PAYLOAD, $CX>: TransferPayload,
+                    {
                         pub fn peek<T>(&self) -> &[T]
                         where
                             BUFFER: AsRef<[T]>,
@@ -338,25 +362,6 @@ 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 {
@@ -448,19 +453,19 @@ dma! {
 
 /// DMA Receiver
 pub struct RxDma<PAYLOAD, RXCH> {
-    pub(crate) _payload: PhantomData<PAYLOAD>,
+    pub(crate) payload: PAYLOAD,
     pub channel: RXCH,
 }
 
 /// DMA Transmitter
 pub struct TxDma<PAYLOAD, TXCH> {
-    pub(crate) _payload: PhantomData<PAYLOAD>,
+    pub(crate) payload: PAYLOAD,
     pub channel: TXCH,
 }
 
 /// DMA Receiver/Transmitter
 pub struct RxTxDma<PAYLOAD, RXCH, TXCH> {
-    pub(crate) _payload: PhantomData<PAYLOAD>,
+    pub(crate) payload: PAYLOAD,
     pub rxchannel: RXCH,
     pub txchannel: TXCH,
 }
@@ -480,7 +485,7 @@ where
     B: AsMut<[RS]>,
     Self: core::marker::Sized,
 {
-    fn circ_read(self, buffer: &'static mut [B; 2]) -> CircBuffer<B, Self::RxChannel>;
+    fn circ_read(self, buffer: &'static mut [B; 2]) -> CircBuffer<B, Self>;
 }
 
 pub trait ReadDma<B, RS>: Receive
@@ -501,4 +506,4 @@ where
     Self: core::marker::Sized,
 {
     fn write(self, buffer: B) -> Transfer<R, B, Self>;
-}
+}

+ 1 - 1
src/rcc.rs

@@ -258,7 +258,7 @@ impl CFGR {
 
         // the USB clock is only valid if an external crystal is used, the PLL is enabled, and the
         // PLL output frequency is a supported one.
-        // usbpre == true: divide clock by 1.5, otherwise no division
+        // usbpre == false: divide clock by 1.5, otherwise no division
         let (usbpre, usbclk_valid) = match (self.hse, pllmul_bits, sysclk) {
             (Some(_), Some(_), 72_000_000) => (false, true),
             (Some(_), Some(_), 48_000_000) => (true, true),

+ 30 - 14
src/serial.rs

@@ -468,7 +468,7 @@ pub type Tx2 = Tx<USART2>;
 pub type Rx3 = Rx<USART3>;
 pub type Tx3 = Tx<USART3>;
 
-use crate::dma::{Transmit, Receive};
+use crate::dma::{Transmit, Receive, TransferPayload};
 
 macro_rules! serialdma {
     ($(
@@ -480,8 +480,8 @@ macro_rules! serialdma {
         ),
     )+) => {
         $(
-            pub type $rxdma = RxDma<$USARTX, $dmarxch>;
-            pub type $txdma = TxDma<$USARTX, $dmatxch>;
+            pub type $rxdma = RxDma<Rx<$USARTX>, $dmarxch>;
+            pub type $txdma = TxDma<Tx<$USARTX>, $dmatxch>;
 
             impl Receive for $rxdma {
                 type RxChannel = $dmarxch;
@@ -493,10 +493,28 @@ macro_rules! serialdma {
                 type ReceivedWord = u8;
             }
 
+            impl TransferPayload for $rxdma {
+                fn start(&mut self) {
+                    self.channel.start();
+                }
+                fn stop(&mut self) {
+                    self.channel.stop();
+                }
+            }
+
+            impl TransferPayload for $txdma {
+                fn start(&mut self) {
+                    self.channel.start();
+                }
+                fn stop(&mut self) {
+                    self.channel.stop();
+                }
+            }
+
             impl Rx<$USARTX> {
                 pub fn with_dma(self, channel: $dmarxch) -> $rxdma {
                     RxDma {
-                        _payload: PhantomData,
+                        payload: self,
                         channel,
                     }
                 }
@@ -505,7 +523,7 @@ macro_rules! serialdma {
             impl Tx<$USARTX> {
                 pub fn with_dma(self, channel: $dmatxch) -> $txdma {
                     TxDma {
-                        _payload: PhantomData,
+                        payload: self,
                         channel,
                     }
                 }
@@ -514,9 +532,9 @@ macro_rules! serialdma {
             impl $rxdma {
                 pub fn split(mut self) -> (Rx<$USARTX>, $dmarxch) {
                     self.stop();
-                    let RxDma {_payload, channel} = self;
+                    let RxDma {payload, channel} = self;
                     (
-                        Rx { _usart: PhantomData },
+                        payload,
                         channel
                     )
                 }
@@ -525,9 +543,9 @@ macro_rules! serialdma {
             impl $txdma {
                 pub fn split(mut self) -> (Tx<$USARTX>, $dmatxch) {
                     self.stop();
-                    let TxDma {_payload, channel} = self;
+                    let TxDma {payload, channel} = self;
                     (
-                        Tx { _usart: PhantomData },
+                        payload,
                         channel,
                     )
                 }
@@ -535,7 +553,7 @@ macro_rules! serialdma {
 
             impl<B> crate::dma::CircReadDma<B, u8> for $rxdma where B: AsMut<[u8]> {
                 fn circ_read(mut self, buffer: &'static mut [B; 2],
-                ) -> CircBuffer<B, $dmarxch>
+                ) -> CircBuffer<B, Self>
                 {
                     {
                         let buffer = buffer[0].as_mut();
@@ -557,9 +575,7 @@ macro_rules! serialdma {
 
                     self.start();
 
-                    let RxDma {_payload, channel} = self;
-
-                    CircBuffer::new(buffer, channel)
+                    CircBuffer::new(buffer, self)
                 }
             }
 
@@ -639,4 +655,4 @@ serialdma! {
         dma1::C3,
         dma1::C2,
     ),
-}
+}