stm32f7xx_hal/
serial.rs

1//! Serial communication using UART/USART peripherals
2
3use core::fmt;
4use core::marker::PhantomData;
5use core::ops::Deref;
6use core::ops::DerefMut;
7use core::pin::Pin;
8use core::ptr;
9
10use as_slice::{AsMutSlice, AsSlice};
11
12use crate::dma;
13use crate::hal::prelude::*;
14use crate::hal::serial;
15use crate::pac;
16use crate::rcc::{BusClock, Enable, Reset};
17use crate::state;
18use nb::block;
19
20use crate::pac::{RCC, UART4, UART5, UART7, UART8, USART1, USART2, USART3, USART6};
21
22use crate::gpio::{self, Alternate};
23
24use crate::rcc::Clocks;
25use crate::{BitsPerSecond, U32Ext};
26
27/// Serial error
28#[derive(Debug)]
29#[non_exhaustive]
30pub enum Error {
31    /// Framing error
32    Framing,
33    /// Noise error
34    Noise,
35    /// RX buffer overrun
36    Overrun,
37    /// Parity check error
38    Parity,
39}
40
41pub trait Pins<U> {}
42pub trait PinTx<U> {}
43pub trait PinRx<U> {}
44
45impl<U, TX, RX> Pins<U> for (TX, RX)
46where
47    TX: PinTx<U>,
48    RX: PinRx<U>,
49{
50}
51
52mod f7xx_pins {
53    //table 13 in stm32f765bg.pdf
54    use super::{PinRx, PinTx};
55    use crate::gpio::{self, Alternate};
56    use crate::pac::{UART4, UART5, UART7, USART1};
57    impl PinTx<USART1> for gpio::PB14<Alternate<4>> {}
58    impl PinRx<USART1> for gpio::PB15<Alternate<4>> {}
59
60    impl PinTx<UART4> for gpio::PA11<Alternate<6>> {}
61    impl PinRx<UART4> for gpio::PA12<Alternate<6>> {}
62
63    impl PinTx<UART4> for gpio::PD1<Alternate<8>> {}
64    impl PinRx<UART4> for gpio::PD0<Alternate<8>> {}
65
66    impl PinTx<UART4> for gpio::PH13<Alternate<8>> {}
67    impl PinRx<UART4> for gpio::PH14<Alternate<8>> {}
68
69    impl PinRx<UART4> for gpio::PI9<Alternate<8>> {}
70
71    impl PinTx<UART5> for gpio::PB6<Alternate<1>> {}
72    impl PinRx<UART5> for gpio::PB5<Alternate<1>> {}
73
74    impl PinTx<UART5> for gpio::PB9<Alternate<7>> {}
75    impl PinRx<UART5> for gpio::PB8<Alternate<7>> {}
76
77    impl PinTx<UART5> for gpio::PB13<Alternate<8>> {}
78    impl PinRx<UART5> for gpio::PB12<Alternate<8>> {}
79
80    impl PinTx<UART7> for gpio::PA15<Alternate<12>> {}
81    impl PinRx<UART7> for gpio::PA8<Alternate<12>> {}
82
83    impl PinTx<UART7> for gpio::PB4<Alternate<12>> {}
84    impl PinRx<UART7> for gpio::PB3<Alternate<12>> {}
85}
86
87// USART1
88impl PinTx<USART1> for gpio::PA9<Alternate<7>> {}
89impl PinTx<USART1> for gpio::PB6<Alternate<7>> {}
90
91impl PinRx<USART1> for gpio::PA10<Alternate<7>> {}
92impl PinRx<USART1> for gpio::PB7<Alternate<7>> {}
93
94// USART2
95impl PinTx<USART2> for gpio::PA2<Alternate<7>> {}
96impl PinTx<USART2> for gpio::PD5<Alternate<7>> {}
97
98impl PinRx<USART2> for gpio::PA3<Alternate<7>> {}
99impl PinRx<USART2> for gpio::PD6<Alternate<7>> {}
100
101// USART3
102impl PinTx<USART3> for gpio::PB10<Alternate<7>> {}
103impl PinTx<USART3> for gpio::PC10<Alternate<7>> {}
104impl PinTx<USART3> for gpio::PD8<Alternate<7>> {}
105
106impl PinRx<USART3> for gpio::PB11<Alternate<7>> {}
107impl PinRx<USART3> for gpio::PC11<Alternate<7>> {}
108impl PinRx<USART3> for gpio::PD9<Alternate<7>> {}
109
110// USART6
111impl PinTx<USART6> for gpio::PC6<Alternate<8>> {}
112impl PinTx<USART6> for gpio::PG14<Alternate<8>> {}
113
114impl PinRx<USART6> for gpio::PC7<Alternate<8>> {}
115impl PinRx<USART6> for gpio::PG9<Alternate<8>> {}
116
117// UART4
118impl PinTx<UART4> for gpio::PA0<Alternate<8>> {}
119impl PinTx<UART4> for gpio::PC10<Alternate<8>> {}
120
121impl PinRx<UART4> for gpio::PA1<Alternate<8>> {}
122impl PinRx<UART4> for gpio::PC11<Alternate<8>> {}
123
124// UART5
125impl PinTx<UART5> for gpio::PC12<Alternate<8>> {}
126impl PinRx<UART5> for gpio::PD2<Alternate<8>> {}
127
128// UART7
129impl PinTx<UART7> for gpio::PE8<Alternate<8>> {}
130impl PinTx<UART7> for gpio::PF7<Alternate<8>> {}
131
132impl PinRx<UART7> for gpio::PE7<Alternate<8>> {}
133impl PinRx<UART7> for gpio::PF6<Alternate<8>> {}
134
135// UART8
136impl PinTx<UART8> for gpio::PE1<Alternate<8>> {}
137impl PinRx<UART8> for gpio::PE0<Alternate<8>> {}
138
139/// Serial abstraction
140pub struct Serial<U, PINS> {
141    usart: U,
142    pins: PINS,
143}
144
145impl<U, PINS> Serial<U, PINS>
146where
147    PINS: Pins<U>,
148    U: Instance,
149{
150    pub fn new(usart: U, pins: PINS, clocks: &Clocks, config: Config) -> Self {
151        // NOTE(unsafe) This executes only during initialisation
152        let rcc = unsafe { &(*RCC::ptr()) };
153
154        // TODO: The unsafe calls below should be replaced with accessing
155        //       the correct registers directly.
156
157        U::select_sysclock(rcc, config.sysclock);
158        unsafe {
159            U::enable_unchecked();
160        }
161
162        let clk = if config.sysclock {
163            clocks.sysclk()
164        } else {
165            U::clock(clocks)
166        };
167
168        // Calculate correct baudrate divisor on the fly
169        let brr = match config.oversampling {
170            Oversampling::By8 => {
171                usart.cr1.modify(|_, w| w.over8().set_bit());
172
173                let usart_div = 2 * clk / config.baud_rate;
174
175                0xfff0 & usart_div | 0x0007 & ((usart_div & 0x000f) >> 1)
176            }
177            Oversampling::By16 => {
178                usart.cr1.modify(|_, w| w.over8().clear_bit());
179
180                clk / config.baud_rate
181            }
182        };
183
184        usart.brr.write(|w| unsafe { w.bits(brr) });
185
186        // Set character match and reset other registers to disable advanced USART features
187        let ch = config.character_match.unwrap_or(0);
188        usart.cr2.write(|w| w.add().bits(ch));
189
190        // Enable tx / rx, configure data bits and parity
191        usart.cr1.modify(|_, w| {
192            w.te().enabled().re().enabled().ue().enabled();
193
194            // M[1:0] are used to set data bits
195            // M[1:0] = 00: 1 Start bit, 8 data bits, n stop bits
196            // M[1:0] = 01: 1 Start bit, 9 data bits, n stop bits
197            // M[1:0] = 10: 1 Start bit, 7 data bits, n stop bits
198            match config.data_bits {
199                DataBits::Bits8 => w.m1().clear_bit().m0().bit8(),
200                DataBits::Bits9 => w.m1().clear_bit().m0().bit9(),
201                DataBits::Bits7 => w.m0().clear_bit().m1().bit7(),
202            };
203
204            match config.parity {
205                Parity::ParityEven => w.ps().even().pce().enabled(),
206                Parity::ParityOdd => w.ps().odd().pce().enabled(),
207                Parity::ParityNone => w.pce().disabled(),
208            }
209        });
210
211        // Enable DMA
212        usart.cr3.write(|w| w.dmat().enabled().dmar().enabled());
213
214        Serial { usart, pins }
215    }
216
217    /// Starts listening for an interrupt event
218    pub fn listen(&mut self, event: Event) {
219        match event {
220            Event::Rxne => self.usart.cr1.modify(|_, w| w.rxneie().set_bit()),
221            Event::Txe => self.usart.cr1.modify(|_, w| w.txeie().set_bit()),
222            Event::CharacterMatch => self.usart.cr1.modify(|_, w| w.cmie().set_bit()),
223            Event::Error => self.usart.cr3.modify(|_, w| w.eie().set_bit()),
224        }
225    }
226
227    /// End listening for an interrupt event
228    pub fn unlisten(&mut self, event: Event) {
229        match event {
230            Event::Rxne => self.usart.cr1.modify(|_, w| w.rxneie().clear_bit()),
231            Event::Txe => self.usart.cr1.modify(|_, w| w.txeie().clear_bit()),
232            Event::CharacterMatch => self.usart.cr1.modify(|_, w| w.cmie().clear_bit()),
233            Event::Error => self.usart.cr3.modify(|_, w| w.eie().clear_bit()),
234        }
235    }
236
237    pub fn split(self) -> (Tx<U>, Rx<U>) {
238        (
239            Tx {
240                _usart: PhantomData,
241            },
242            Rx {
243                _usart: PhantomData,
244            },
245        )
246    }
247
248    pub fn release(self) -> (U, PINS) {
249        (self.usart, self.pins)
250    }
251}
252
253impl<U, PINS> serial::Read<u8> for Serial<U, PINS>
254where
255    U: Instance,
256{
257    type Error = Error;
258
259    fn read(&mut self) -> nb::Result<u8, Error> {
260        let mut rx: Rx<U> = Rx {
261            _usart: PhantomData,
262        };
263        rx.read()
264    }
265}
266
267impl<U, PINS> serial::Write<u8> for Serial<U, PINS>
268where
269    U: Instance,
270{
271    type Error = Error;
272
273    fn flush(&mut self) -> nb::Result<(), Self::Error> {
274        let mut tx: Tx<U> = Tx {
275            _usart: PhantomData,
276        };
277        tx.flush()
278    }
279
280    fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
281        let mut tx: Tx<U> = Tx {
282            _usart: PhantomData,
283        };
284        tx.write(byte)
285    }
286}
287
288/// Serial receiver
289pub struct Rx<U> {
290    _usart: PhantomData<U>,
291}
292
293impl<U> Rx<U>
294where
295    U: Instance,
296    Self: dma::Target,
297{
298    /// Reads data using DMA until `buffer` is full
299    ///
300    /// DMA supports transfers up to 65535 bytes. If `buffer` is longer, this
301    /// method will panic.
302    pub fn read_all<B>(
303        self,
304        buffer: Pin<B>,
305        dma: &dma::Handle<<Self as dma::Target>::Instance, state::Enabled>,
306        stream: <Self as dma::Target>::Stream,
307    ) -> dma::Transfer<Self, B, dma::Ready>
308    where
309        B: DerefMut + 'static,
310        B::Target: AsMutSlice<Element = u8>,
311    {
312        // This is safe, as we're only using the USART instance to access the
313        // address of one register.
314        let address = &unsafe { &*U::ptr() }.rdr as *const _ as _;
315
316        // Safe, because the trait bounds on this method guarantee that `buffer`
317        // can be written to safely.
318        unsafe {
319            dma::Transfer::new(
320                dma,
321                stream,
322                buffer,
323                self,
324                address,
325                dma::Direction::PeripheralToMemory,
326            )
327        }
328    }
329}
330
331impl<U> serial::Read<u8> for Rx<U>
332where
333    U: Instance,
334{
335    type Error = Error;
336
337    fn read(&mut self) -> nb::Result<u8, Error> {
338        // NOTE(unsafe) atomic read with no side effects
339        let isr = unsafe { (*U::ptr()).isr.read() };
340
341        // NOTE(unsafe): Only used for atomic writes, to clear error flags.
342        let icr = unsafe { &(*U::ptr()).icr };
343
344        if isr.pe().bit_is_set() {
345            icr.write(|w| w.pecf().clear());
346            return Err(nb::Error::Other(Error::Parity));
347        }
348        if isr.fe().bit_is_set() {
349            icr.write(|w| w.fecf().clear());
350            return Err(nb::Error::Other(Error::Framing));
351        }
352        if isr.nf().bit_is_set() {
353            icr.write(|w| w.ncf().clear());
354            return Err(nb::Error::Other(Error::Noise));
355        }
356        if isr.ore().bit_is_set() {
357            icr.write(|w| w.orecf().clear());
358            return Err(nb::Error::Other(Error::Overrun));
359        }
360
361        if isr.rxne().bit_is_set() {
362            // NOTE(unsafe): Atomic read with no side effects
363            return Ok(unsafe {
364                // Casting to `u8` should be fine, as we've configured the USART
365                // to use 8 data bits.
366                (*U::ptr()).rdr.read().rdr().bits() as u8
367            });
368        }
369
370        Err(nb::Error::WouldBlock)
371    }
372}
373
374/// Serial transmitter
375pub struct Tx<U> {
376    _usart: PhantomData<U>,
377}
378
379impl<U> Tx<U>
380where
381    Self: dma::Target,
382    U: Instance,
383{
384    /// Writes data using DMA
385    ///
386    /// DMA supports transfers up to 65535 bytes. If `data` is longer, this
387    /// method will panic.
388    pub fn write_all<B>(
389        self,
390        data: Pin<B>,
391        dma: &dma::Handle<<Self as dma::Target>::Instance, state::Enabled>,
392        stream: <Self as dma::Target>::Stream,
393    ) -> dma::Transfer<Self, B, dma::Ready>
394    where
395        B: Deref + 'static,
396        B::Target: AsSlice<Element = u8>,
397    {
398        // Prepare USART for DMA. See reference manual for STM32F75xxx and
399        // STM32F74xxx, section 31.5.15.
400        //
401        // This is safe, as we're doing just one atomic write.
402        let usart = unsafe { &*U::ptr() };
403        usart.icr.write(|w| w.tccf().clear());
404
405        // Safe, because the trait bounds on this method guarantee that `buffer`
406        // can be read from safely.
407        unsafe {
408            dma::Transfer::new(
409                dma,
410                stream,
411                data,
412                self,
413                &usart.tdr as *const _ as _,
414                dma::Direction::MemoryToPeripheral,
415            )
416        }
417    }
418}
419
420impl<U> serial::Write<u8> for Tx<U>
421where
422    U: Instance,
423{
424    type Error = Error;
425
426    fn flush(&mut self) -> nb::Result<(), Self::Error> {
427        // NOTE(unsafe) atomic read with no side effects
428        let isr = unsafe { (*U::ptr()).isr.read() };
429
430        if isr.tc().bit_is_set() {
431            Ok(())
432        } else {
433            Err(nb::Error::WouldBlock)
434        }
435    }
436
437    fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
438        // NOTE(unsafe) atomic read with no side effects
439        let isr = unsafe { (*U::ptr()).isr.read() };
440
441        if isr.txe().bit_is_set() {
442            // NOTE(unsafe) atomic write to stateless register
443            // NOTE(write_volatile) 8-bit write that's not possible through the svd2rust API
444            unsafe { ptr::write_volatile(core::ptr::addr_of!((*U::ptr()).tdr) as *mut u8, byte) }
445            Ok(())
446        } else {
447            Err(nb::Error::WouldBlock)
448        }
449    }
450}
451
452/// USART configuration
453pub struct Config {
454    pub baud_rate: BitsPerSecond,
455    pub oversampling: Oversampling,
456    pub character_match: Option<u8>,
457    pub sysclock: bool,
458    pub parity: Parity,
459    pub data_bits: DataBits,
460}
461
462pub enum Oversampling {
463    By8,
464    By16,
465}
466
467/// Number of data bits
468pub enum DataBits {
469    /// 8 bits of data
470    Bits8,
471    /// 9 bits of data
472    Bits9,
473    /// 7 bits of data
474    Bits7,
475}
476
477/// Parity generation and checking. If odd or even parity is selected, the
478/// underlying USART will be configured to send/receive the parity bit in
479/// addtion to the data bits.
480pub enum Parity {
481    /// No parity bit will be added/checked.
482    ParityNone,
483    /// The MSB transmitted/received will be generated/checked to have a
484    /// even number of bits set.
485    ParityEven,
486    /// The MSB transmitted/received will be generated/checked to have a
487    /// odd number of bits set.
488    ParityOdd,
489}
490
491impl Default for Config {
492    fn default() -> Self {
493        Self {
494            baud_rate: 115_200.bps(),
495            oversampling: Oversampling::By16,
496            character_match: None,
497            sysclock: false,
498            parity: Parity::ParityNone,
499            data_bits: DataBits::Bits8,
500        }
501    }
502}
503
504/// Interrupt event
505#[derive(Debug)]
506pub enum Event {
507    /// New data has been received
508    Rxne,
509    /// New data can be sent
510    Txe,
511    /// Character match interrupt
512    CharacterMatch,
513    /// Error interrupt
514    Error,
515}
516
517/// Implemented by all USART instances
518pub trait Instance: Deref<Target = pac::usart1::RegisterBlock> + Enable + Reset + BusClock {
519    fn ptr() -> *const pac::usart1::RegisterBlock;
520    fn select_sysclock(rcc: &pac::rcc::RegisterBlock, sys: bool);
521}
522
523macro_rules! impl_instance {
524    ($(
525        $UARTX:ident: ($usartXsel:ident),
526    )+) => {
527        $(
528            impl Instance for $UARTX {
529                fn ptr() -> *const pac::usart1::RegisterBlock {
530                    $UARTX::ptr()
531                }
532
533                fn select_sysclock(rcc: &pac::rcc::RegisterBlock, sys: bool) {
534                    rcc.dckcfgr2.modify(|_, w| w.$usartXsel().bits(sys as _));
535                }
536            }
537        )+
538    }
539}
540
541#[cfg(any(feature = "device-selected",))]
542impl_instance! {
543    USART1: (usart1sel),
544    USART2: (usart2sel),
545    USART3: (usart3sel),
546    UART4:  (uart4sel),
547    UART5:  (uart5sel),
548    USART6: (usart6sel),
549    UART7:  (uart7sel),
550}
551
552impl<U> fmt::Write for Tx<U>
553where
554    Tx<U>: serial::Write<u8>,
555{
556    fn write_str(&mut self, s: &str) -> fmt::Result {
557        let _ = s.as_bytes().iter().map(|c| block!(self.write(*c))).last();
558        Ok(())
559    }
560}