Преглед на файлове

Implement Read<u8> / Write<u8> on Serial type

Danilo Bargen преди 4 години
родител
ревизия
011797365a
променени са 3 файла, в които са добавени 78 реда и са изтрити 25 реда
  1. 1 0
      CHANGELOG.md
  2. 14 7
      examples/serial.rs
  3. 63 18
      src/serial.rs

+ 1 - 0
CHANGELOG.md

@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 ## [Unreleased]
 
 - Add `InputPin` impl for generic open drain outputs
+- Implement `Read<u8>` / `Write<u8>` for `Serial` (#171)
 
 ## [v0.5.2] - 2019-12-15
 

+ 14 - 7
examples/serial.rs

@@ -59,7 +59,7 @@ fn main() -> ! {
 
     // Set up the usart device. Taks ownership over the USART register and tx/rx pins. The rest of
     // the registers are used to enable and configure the device.
-    let serial = Serial::usart3(
+    let mut serial = Serial::usart3(
         p.USART3,
         (tx, rx),
         &mut afio.mapr,
@@ -68,16 +68,13 @@ fn main() -> ! {
         &mut rcc.apb1,
     );
 
-    // Split the serial struct into a receiving and a transmitting part
-    let (mut tx, mut rx) = serial.split();
 
+    // Loopback test. Write `X` and wait until the write is successful.
     let sent = b'X';
-
-    // Write `X` and wait until the write is successful
-    block!(tx.write(sent)).ok();
+    block!(serial.write(sent)).ok();
 
     // Read the byte that was just sent. Blocks until the read is complete
-    let received = block!(rx.read()).unwrap();
+    let received = block!(serial.read()).unwrap();
 
     // Since we have connected tx and rx, the byte we sent should be the one we received
     assert_eq!(received, sent);
@@ -85,5 +82,15 @@ fn main() -> ! {
     // Trigger a breakpoint to allow us to inspect the values
     asm::bkpt();
 
+
+    // You can also split the serial struct into a receiving and a transmitting part
+    let (mut tx, mut rx) = serial.split();
+    let sent = b'Y';
+    block!(tx.write(sent)).ok();
+    let received = block!(rx.read()).unwrap();
+    assert_eq!(received, sent);
+    asm::bkpt();
+
+
     loop {}
 }

+ 63 - 18
src/serial.rs

@@ -1,9 +1,10 @@
 //! # Serial Communication (USART)
+//!
 //! This module contains the functions to utilize the USART (Universal
 //! synchronous asynchronous receiver transmitter)
 //!
-//!
 //! ## Example usage:
+//!
 //!  ```rust
 //! // prelude: create handles to the peripherals and registers
 //! let p = crate::pac::Peripherals::take().unwrap();
@@ -113,6 +114,16 @@ impl Pins<USART3> for (PD8<Alternate<PushPull>>, PD9<Input<Floating>>) {
     const REMAP: u8 = 0b11;
 }
 
+/// Internal trait for the serial read / write logic.
+///
+/// Note that reading / writing is done on the USART peripheral, not on the
+/// rx / tx pins!
+trait UsartReadWrite<Word> {
+    fn read() -> nb::Result<Word, Error>;
+    fn write(byte: Word) -> nb::Result<(), Infallible>;
+    fn flush() -> nb::Result<(), Infallible>;
+}
+
 pub enum Parity {
     ParityNone,
     ParityEven,
@@ -346,10 +357,8 @@ macro_rules! hal {
                 }
             }
 
-            impl crate::hal::serial::Read<u8> for Rx<$USARTX> {
-                type Error = Error;
-
-                fn read(&mut self) -> nb::Result<u8, Error> {
+            impl UsartReadWrite<u8> for $USARTX {
+                fn read() -> nb::Result<u8, Error> {
                     // NOTE(unsafe) atomic read with no side effects
                     let sr = unsafe { (*$USARTX::ptr()).sr.read() };
 
@@ -389,38 +398,74 @@ macro_rules! hal {
                         }
                     }
                 }
-            }
-
-            impl crate::hal::serial::Write<u8> for Tx<$USARTX> {
-                type Error = Infallible;
 
-                fn flush(&mut self) -> nb::Result<(), Self::Error> {
+                fn write(byte: u8) -> nb::Result<(), Infallible> {
                     // NOTE(unsafe) atomic read with no side effects
                     let sr = unsafe { (*$USARTX::ptr()).sr.read() };
 
-                    if sr.tc().bit_is_set() {
+                    if sr.txe().bit_is_set() {
+                        // NOTE(unsafe) atomic write to stateless register
+                        // NOTE(write_volatile) 8-bit write that's not possible through the svd2rust API
+                        unsafe {
+                            ptr::write_volatile(&(*$USARTX::ptr()).dr as *const _ as *mut _, byte)
+                        }
                         Ok(())
                     } else {
                         Err(nb::Error::WouldBlock)
                     }
                 }
 
-                fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
+                fn flush() -> nb::Result<(), Infallible> {
                     // NOTE(unsafe) atomic read with no side effects
                     let sr = unsafe { (*$USARTX::ptr()).sr.read() };
 
-                    if sr.txe().bit_is_set() {
-                        // NOTE(unsafe) atomic write to stateless register
-                        // NOTE(write_volatile) 8-bit write that's not possible through the svd2rust API
-                        unsafe {
-                            ptr::write_volatile(&(*$USARTX::ptr()).dr as *const _ as *mut _, byte)
-                        }
+                    if sr.tc().bit_is_set() {
                         Ok(())
                     } else {
                         Err(nb::Error::WouldBlock)
                     }
                 }
             }
+
+            impl crate::hal::serial::Read<u8> for Rx<$USARTX> {
+                type Error = Error;
+
+                fn read(&mut self) -> nb::Result<u8, Error> {
+                    $USARTX::read()
+                }
+            }
+
+            impl crate::hal::serial::Write<u8> for Tx<$USARTX> {
+                type Error = Infallible;
+
+                fn flush(&mut self) -> nb::Result<(), Self::Error> {
+                    $USARTX::flush()
+                }
+                fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
+                    $USARTX::write(byte)
+                }
+            }
+
+            impl<PINS> crate::hal::serial::Read<u8> for Serial<$USARTX, PINS> {
+                type Error = Error;
+
+                fn read(&mut self) -> nb::Result<u8, Error> {
+                    $USARTX::read()
+                }
+            }
+
+            impl<PINS> crate::hal::serial::Write<u8> for Serial<$USARTX, PINS> {
+                type Error = Infallible;
+
+                fn flush(&mut self) -> nb::Result<(), Self::Error> {
+                    $USARTX::flush()
+                }
+
+                fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
+                    $USARTX::write(byte)
+                }
+            }
+
         )+
     }
 }