alt_stm32f30x_hal/
serial.rs

1//! Serial
2
3use core::marker::PhantomData;
4use core::ptr;
5use core::sync::atomic::{self, Ordering};
6
7use crate::pac::{Interrupt, RCC, USART1, USART2, USART3};
8use hal::serial::{self, Write};
9use nb;
10use void::Void;
11
12use crate::dma::{dma1, CircBuffer, Static, Transfer, R, W};
13use crate::gpio::{AltFn, HighSpeed, PinMode, PullType, PushPull, AF7};
14use crate::gpio::{PA10, PA14, PA15, PA2, PA3, PA9};
15use crate::gpio::{PB10, PB11, PB3, PB4, PB6, PB7};
16use crate::gpio::{PC10, PC11, PC4, PC5};
17use crate::gpio::{PD5, PD6, PD8, PD9};
18use crate::gpio::{PE0, PE1, PE15};
19use crate::rcc::Clocks;
20use crate::time::Bps;
21
22/// Interrupt event
23pub enum Event {
24    /// New data has been received
25    Rxne,
26    /// New data can be sent
27    Txe,
28}
29
30/// Serial error
31#[derive(Debug)]
32pub enum Error {
33    /// Framing error
34    Framing,
35    /// Noise error
36    Noise,
37    /// RX buffer overrun
38    Overrun,
39    /// Parity check error
40    Parity,
41    #[doc(hidden)]
42    _Extensible,
43}
44
45/// Serial abstraction
46pub struct Serial<USART, PINS> {
47    usart: USART,
48    pins: PINS,
49}
50
51/// Serial receiver
52pub struct Rx<USART> {
53    _usart: PhantomData<USART>,
54}
55
56/// Serial transmitter
57pub struct Tx<USART> {
58    _usart: PhantomData<USART>,
59}
60
61/// Serial extension for USART
62pub trait SerialExt<USART, ITX, IRX, TX, RX> {
63    /// Configures USART and consumes pair of (tx, rx) pins
64    /// to act as serial port.
65    /// Configures pins accordingly.
66    /// Returns [`Serial`].
67    ///
68    /// [`Serial`]: ./struct.Serial.html
69    fn serial(self,
70              pins: (ITX, IRX),
71              baud_rate: Bps<u32>,
72              clocks: Clocks)
73              -> Serial<USART, (TX, RX)>;
74}
75
76macro_rules! serial {
77    ($USARTX:ident,
78     $INTNAME:ident,
79     $apbenr:ident,
80     $apbrstr:ident,
81     $usartXen:ident,
82     $usartXrst:ident,
83     $pclkX:ident,
84     $afn:ident,
85     $speed:ident,
86     [$($txpin: ident, )+],
87     $restrx: tt
88    ) => {
89        serial!{$USARTX,
90                $INTNAME,
91                $apbenr,
92                $apbrstr,
93                $usartXen,
94                $usartXrst,
95                $pclkX,
96                $afn,
97                $speed,
98                [$(
99                    ($txpin, $restrx),
100                )+]}
101    };
102    ($USARTX:ident,
103     $INTNAME:ident,
104     $apbenr:ident,
105     $apbrstr:ident,
106     $usartXen:ident,
107     $usartXrst:ident,
108     $pclkX:ident,
109     $afn:ident,
110     $speed:ident,
111     [$(($txpin: ident, [$($rxpin: ident,)+]), )+]
112    ) => {
113        $(
114            $(
115                impl <PT: PullType,
116                PM: PinMode>
117                    SerialExt<$USARTX,
118                $txpin<PT, PM>,
119                $rxpin<PT, PM>,
120                $txpin<PT, AltFn<$afn, PushPull, $speed>>,
121                $rxpin<PT, AltFn<$afn, PushPull, $speed>>>
122                    for $USARTX {
123                        fn serial(self,
124                                  pins: ($txpin<PT, PM>, $rxpin<PT, PM>),
125                                  baud_rate: Bps<u32>,
126                                  clocks: Clocks)
127                                  -> Serial<$USARTX, ($txpin<PT, AltFn<$afn, PushPull, $speed>>,
128                                                      $rxpin<PT, AltFn<$afn, PushPull, $speed>>)>
129                        {
130                            let outpins = (
131                                pins.0
132                                    .alternating($afn)
133                                    .output_speed($speed),
134                                pins.1
135                                    .alternating($afn)
136                                    .output_speed($speed),
137                            );
138
139                            // enable or reset $USARTX
140                            let apbenr = unsafe { &(*RCC::ptr()).$apbenr };
141                            let apbrstr = unsafe { &(*RCC::ptr()).$apbrstr };
142                            apbenr.modify(|_, w| w.$usartXen().enabled());
143                            apbrstr.modify(|_, w| w.$usartXrst().set_bit());
144                            apbrstr.modify(|_, w| w.$usartXrst().clear_bit());
145                            self.cr3.write(|w| w.dmat().set_bit().dmar().set_bit());
146
147                            let brr = clocks.$pclkX().0 / baud_rate.0;
148                            assert!(brr >= 16, "impossible baud rate");
149                            self.brr.write(|w| unsafe { w.bits(brr) });
150
151                            // UE: enable USART
152                            // RE: enable receiver
153                            // TE: enable transceiver
154                            self.cr1.write(|w| {
155                                w.ue()
156                                    .set_bit()
157                                    .re()
158                                    .set_bit()
159                                    .te()
160                                    .set_bit()
161                            });
162
163                            Serial { usart: self,
164                                     pins: outpins, }
165                        }
166                    }
167            )+
168        )+
169
170        impl<TX, RX> Serial<$USARTX, (TX, RX)> {
171            /// Returns associated interrupt
172            pub fn get_interrupt(&self) -> Interrupt {
173                Interrupt::$INTNAME
174            }
175
176            /// Starts listening for an interrupt event
177            pub fn listen(&mut self, event: Event) {
178                match event {
179                    Event::Rxne => {
180                        self.usart.cr1.modify(|_, w| w.rxneie().set_bit())
181                    }
182                    Event::Txe => {
183                        self.usart.cr1.modify(|_, w| w.txeie().set_bit())
184                    }
185                }
186            }
187
188            /// Starts listening for an interrupt event
189            pub fn unlisten(&mut self, event: Event) {
190                match event {
191                    Event::Rxne => {
192                        self.usart.cr1.modify(|_, w| w.rxneie().clear_bit())
193                    }
194                    Event::Txe => {
195                        self.usart.cr1.modify(|_, w| w.txeie().clear_bit())
196                    }
197                }
198            }
199
200            /// Splits the `Serial` abstraction into a transmitter and a
201            /// receiver half
202            pub fn split(self) -> (Tx<$USARTX>, Rx<$USARTX>) {
203                (Tx { _usart: PhantomData, }, Rx { _usart: PhantomData, })
204            }
205
206            /// Releases the USART peripheral and associated pins
207            pub fn free(self) -> ($USARTX, (TX, RX)) {
208                (self.usart, self.pins)
209            }
210        }
211
212        impl Rx<$USARTX> {
213            /// clear overrun
214            pub fn clear_overrun_error(&mut self) -> u8 {
215                unsafe { (*$USARTX::ptr()).icr.write(|w| w.orecf().set_bit()) };
216                let rdr = unsafe { (*$USARTX::ptr()).rdr.read() };
217                (rdr.bits() & 0xFF) as u8
218            }
219
220            /// clear framing error
221            pub fn clear_framing_error(&mut self) -> u8 {
222                unsafe { (*$USARTX::ptr()).icr.write(|w| w.fecf().set_bit()) };
223                let rdr = unsafe { (*$USARTX::ptr()).rdr.read() };
224                (rdr.bits() & 0xFF) as u8
225            }
226
227            /// clear noise error
228            pub fn clear_noise_error(&mut self) -> u8 {
229                unsafe { (*$USARTX::ptr()).icr.write(|w| w.ncf().set_bit()) };
230                let rdr = unsafe { (*$USARTX::ptr()).rdr.read() };
231                (rdr.bits() & 0xFF) as u8
232            }
233        }
234
235        impl serial::Read<u8> for Rx<$USARTX> {
236            type Error = Error;
237
238            fn read(&mut self) -> nb::Result<u8, Error> {
239                // NOTE(unsafe) atomic read with no side effects
240                let isr = unsafe { (*$USARTX::ptr()).isr.read() };
241
242                Err(if isr.pe().bit_is_set() {
243                    nb::Error::Other(Error::Parity)
244                } else if isr.fe().bit_is_set() {
245                    self.clear_framing_error();
246                    nb::Error::Other(Error::Framing)
247                } else if isr.nf().bit_is_set() {
248                    self.clear_noise_error();
249                    nb::Error::Other(Error::Noise)
250                } else if isr.ore().bit_is_set() {
251                    self.clear_overrun_error();
252                    nb::Error::Other(Error::Overrun)
253                } else if isr.rxne().bit_is_set() {
254                    // NOTE(read_volatile) see `write_volatile` below
255                    return Ok(unsafe {
256                        ptr::read_volatile(&(*$USARTX::ptr()).rdr as *const _
257                                           as *const _)
258                    });
259                } else {
260                    nb::Error::WouldBlock
261                })
262            }
263        }
264
265        impl serial::Write<u8> for Tx<$USARTX> {
266            // NOTE(Void) See section "29.7 USART interrupts"; the only
267            // possible errors during transmission are: clear to send
268            // (which is disabled in this case)
269            // errors and framing errors (which only occur in SmartCard
270            // mode); neither of these apply to our hardware configuration
271            type Error = Void;
272
273            fn flush(&mut self) -> nb::Result<(), Void> {
274                // NOTE(unsafe) atomic read with no side effects
275                let isr = unsafe { (*$USARTX::ptr()).isr.read() };
276
277                if isr.tc().bit_is_set() {
278                    Ok(())
279                } else {
280                    Err(nb::Error::WouldBlock)
281                }
282            }
283
284            fn write(&mut self, byte: u8) -> nb::Result<(), Void> {
285                // NOTE(unsafe) atomic read with no side effects
286                let isr = unsafe { (*$USARTX::ptr()).isr.read() };
287
288                if isr.txe().bit_is_set() {
289                    // NOTE(unsafe) atomic write to stateless register
290                    // NOTE(write_volatile) 8-bit write that's not possible
291                    // through the svd2rust API
292                    unsafe {
293                        ptr::write_volatile(&(*$USARTX::ptr()).tdr as *const _
294                                            as *mut _,
295                                            byte)
296                    }
297                    Ok(())
298                } else {
299                    Err(nb::Error::WouldBlock)
300                }
301            }
302        }
303
304        impl core::fmt::Write for Tx<$USARTX>
305        {
306            fn write_str(&mut self, s: &str) -> core::fmt::Result {
307                for c in s.chars() {
308                    match self.write_char(c) {
309                        Ok(_) => {},
310                        Err(_) => {},
311                    }
312                }
313                match self.flush() {
314                    Ok(_) => {},
315                    Err(_) => {},
316                };
317                Ok(())
318            }
319
320            fn write_char(&mut self, s: char) -> core::fmt::Result {
321                match nb::block!(self.write(s as u8)) {
322                    Ok(_) => {},
323                    Err(_) => {},
324                }
325                Ok(())
326            }
327        }
328
329            impl<B> ReadDma<B> for Rx<$USARTX> where B: AsMut<[u8]> {
330                fn circ_read(self, mut chan: Self::Dma, buffer: &'static mut [B; 2],
331                ) -> CircBuffer<B, Self::Dma>
332                {
333                    {
334                        let buffer = buffer[0].as_mut();
335                        chan.ch().mar.write(|w| unsafe {
336                                w.ma().bits(buffer.as_ptr() as usize as u32)
337                            }
338                        );
339                        chan.ch().ndtr.write(|w|
340                            w.ndt().bits((buffer.len() * 2) as u16)
341                        );
342                        chan.ch().par.write(|w| unsafe {
343                            w.pa().bits(&(*$USARTX::ptr()).rdr as *const _ as usize as u32)
344                        });
345
346                        // TODO can we weaken this compiler barrier?
347                        // NOTE(compiler_fence) operations on `buffer` should not be reordered after
348                        // the next statement, which starts the DMA transfer
349                        atomic::compiler_fence(Ordering::SeqCst);
350
351                        unsafe {
352                            chan.ch().cr.modify(|_, w| {
353                                w.mem2mem()
354                                    .clear_bit()
355                                    .pl()
356                                    .bits(0b01)
357                                    .msize()
358                                    .bits(0b0) // 8 bit
359                                    .psize()
360                                    .bits(0b0)
361                                    .minc()
362                                    .set_bit()
363                                    .pinc()
364                                    .clear_bit()
365                                    .circ()
366                                    .set_bit()
367                                    .dir()
368                                    .clear_bit()
369                            });
370                            chan.ch().cr.modify(|_, w| w.en().set_bit() )
371                        }
372                    }
373
374                    CircBuffer::new(buffer, chan)
375                }
376
377                fn read_exact(self, mut chan: Self::Dma, buffer: &'static mut B,
378                ) -> Transfer<W, &'static mut B, Self::Dma, Self>
379                {
380                    {
381                        let buffer = buffer.as_mut();
382                        chan.ch().mar.write(|w| unsafe {
383                            w.ma().bits(buffer.as_ptr() as usize as u32)
384                        });
385                        chan.ch().ndtr.write(|w|
386                            w.ndt().bits(buffer.len() as u16)
387                        );
388                        chan.ch().par.write(|w| unsafe {
389                            w.pa().bits(&(*$USARTX::ptr()).rdr as *const _ as usize as u32)
390                        });
391
392                        // TODO can we weaken this compiler barrier?
393                        // NOTE(compiler_fence) operations on `buffer` should not be reordered after
394                        // the next statement, which starts the DMA transfer
395                        atomic::compiler_fence(Ordering::SeqCst);
396
397                        unsafe {
398                            chan.ch().cr.modify(|_, w| {
399                                w.mem2mem()
400                                    .clear_bit()
401                                    .pl()
402                                    .bits(0b01)
403                                    .msize()
404                                    .bits(0b0)
405                                    .psize()
406                                    .bits(0b0)
407                                    .minc()
408                                    .set_bit()
409                                    .pinc()
410                                    .clear_bit()
411                                    .circ()
412                                    .clear_bit()
413                                    .dir()
414                                    .clear_bit()
415                                    .en()
416                                    .set_bit()
417                            });
418                        }
419                    }
420
421                    Transfer::w(buffer, chan, self)
422                }
423            }
424
425            impl<A, B> WriteDma<A, B> for Tx<$USARTX> where A: AsRef<[u8]>, B: Static<A> {
426                fn write_all(self, mut chan: Self::Dma, buffer: B
427                ) -> Transfer<R, B, Self::Dma, Self>
428                {
429                    {
430                        let buffer = buffer.borrow().as_ref();
431                        chan.ch().par.write(|w| unsafe {
432                            w.pa().bits(&(*$USARTX::ptr()).tdr as *const _ as usize as u32)
433                        });
434
435                        chan.ch().mar.write(|w| unsafe {
436                            w.ma().bits(buffer.as_ptr() as usize as u32)
437                        });
438
439                        chan.ch().ndtr.write(|w|
440                            w.ndt().bits(buffer.len() as u16)
441                        );
442
443                        // TODO can we weaken this compiler barrier?
444                        // NOTE(compiler_fence) operations on `buffer` should not be reordered after
445                        // the next statement, which starts the DMA transfer
446                        atomic::compiler_fence(Ordering::SeqCst);
447
448                        unsafe {
449                            chan.ch().cr.modify(|_, w| {
450                                w.mem2mem()
451                                    .clear_bit()
452                                    .pl()
453                                    .bits(0b01)
454                                    .msize()
455                                    .bits(0b0)
456                                    .psize()
457                                    .bits(0b0)
458                                    .minc()
459                                    .set_bit()
460                                    .pinc()
461                                    .clear_bit()
462                                    .circ()
463                                    .clear_bit()
464                                    .dir()
465                                    .set_bit()
466                                    .en()
467                                    .set_bit()
468                            });
469                        }
470                    }
471
472                    Transfer::r(buffer, chan, self)
473                }
474            }
475    };
476}
477
478use crate::dma::DmaChannel;
479
480impl DmaChannel for Rx<USART1> {
481    type Dma = dma1::C5;
482}
483
484impl DmaChannel for Tx<USART1> {
485    type Dma = dma1::C4;
486}
487
488impl DmaChannel for Rx<USART2> {
489    type Dma = dma1::C6;
490}
491
492impl DmaChannel for Tx<USART2> {
493    type Dma = dma1::C7;
494}
495
496impl DmaChannel for Rx<USART3> {
497    type Dma = dma1::C3;
498}
499
500impl DmaChannel for Tx<USART3> {
501    type Dma = dma1::C2;
502}
503
504/// ReadDma
505pub trait ReadDma<B>: DmaChannel
506    where B: AsMut<[u8]>,
507          Self: core::marker::Sized
508{
509    /// circ
510    fn circ_read(self,
511                 chan: Self::Dma,
512                 buffer: &'static mut [B; 2])
513                 -> CircBuffer<B, Self::Dma>;
514    /// exact
515    fn read_exact(self,
516                  chan: Self::Dma,
517                  buffer: &'static mut B)
518                  -> Transfer<W, &'static mut B, Self::Dma, Self>;
519}
520
521/// WriteDma
522pub trait WriteDma<A, B>: DmaChannel
523    where A: AsRef<[u8]>,
524          B: Static<A>,
525          Self: core::marker::Sized
526{
527    /// Write all
528    fn write_all(self,
529                 chan: Self::Dma,
530                 buffer: B)
531                 -> Transfer<R, B, Self::Dma, Self>;
532}
533
534// XXX: we can't use GATs yet, so had to retort to macros
535serial!(USART1,
536        USART1_EXTI25,
537        apb2enr,
538        apb2rstr,
539        usart1en,
540        usart1rst,
541        pclk2,
542        AF7,
543        HighSpeed, // XXX: not sure, maybe we should allow setting this
544        [PA9, PB6, PC4, PE0,],
545        [PA10, PB7, PC5, PE1,]);
546serial!(USART2,
547        USART2_EXTI26,
548        apb1enr,
549        apb1rstr,
550        usart2en,
551        usart2rst,
552        pclk1,
553        AF7,
554        HighSpeed,
555        [PA2, PA14, PB3, PD5,],
556        [PA3, PA15, PB4, PD6,]);
557serial!(USART3,
558        USART3_EXTI28,
559        apb1enr,
560        apb1rstr,
561        usart3en,
562        usart3rst,
563        pclk1,
564        AF7,
565        HighSpeed,
566        [PB10, PC10, PD8,],
567        [PB11, PC11, PD9, PE15,]);