Skip to main content

k210_hal/
serial.rs

1//! Serial interface
2//!
3//! You can use the `Serial` interface with these UART instances:
4//! * [`UARTHS`](crate::pac::UARTHS)
5//! * [`UART1`](crate::pac::UART1)
6//! * [`UART2`](crate::pac::UART2)
7//! * [`UART3`](crate::pac::UART3)
8
9use core::mem;
10use core::convert::Infallible;
11
12use embedded_hal::serial;
13
14use crate::pac::{UARTHS,uart1,UART1,UART2,UART3};
15use crate::clock::Clocks;
16use crate::time::Bps;
17use core::marker::PhantomData;
18use crate::external_pins::ExternalPin;
19use crate::fpioa;
20
21
22/// Extension trait that constrains UART peripherals
23pub trait SerialExt<PINS>: Sized {
24    /// Configures a UART peripheral to provide serial communication
25    fn configure(self, pins: PINS, baud_rate: Bps, clocks: &Clocks) -> Serial<Self, PINS>;
26}
27
28/// Serial abstraction
29pub struct Serial<UART, PINS> {
30    uart: UART,
31    pins: PINS,
32}
33
34impl<UART, PINS> Serial<UART, PINS> {
35    /// Splits the `Serial` abstraction into a transmitter and a
36    /// receiver half
37    pub fn split(self) -> (Tx<UART, PINS>, Rx<UART, PINS>) {
38        (
39            Tx {
40                uart: self.uart,
41                pins: self.pins
42            },
43            Rx {
44                uart: unsafe { mem::zeroed() },
45                _pins: PhantomData,
46            }
47        )
48    }
49
50    /// Forms `Serial` abstraction from a transmitter and a
51    /// receiver half
52    pub fn join(tx: Tx<UART, PINS>, _rx: Rx<UART, PINS>) -> Self {
53        Serial { uart: tx.uart, pins: tx.pins }
54    }
55
56    /// Releases the UART peripheral
57    pub fn free(self) -> (UART, PINS) {
58        (self.uart, self.pins)
59    }
60}
61
62/// Serial transmitter
63pub struct Tx<UART, PINS> {
64    uart: UART,
65    pins: PINS,
66}
67
68/// Serial receiver
69pub struct Rx<UART, PINS> {
70    uart: UART,
71    _pins: PhantomData<PINS>,
72}
73
74
75impl<TX: ExternalPin, RX: ExternalPin> SerialExt<(TX, RX)> for UARTHS {
76    fn configure(self, pins: (TX, RX), baud_rate: Bps, clocks: &Clocks) -> Serial<UARTHS, (TX, RX)>
77    {
78        let uart = self;
79        fpioa::set_function(TX::INDEX, fpioa::Function::UARTHS_TX);
80        fpioa::set_function(RX::INDEX, fpioa::Function::UARTHS_RX);
81
82        let div = clocks.cpu().0 / baud_rate.0 - 1;
83        unsafe {
84            uart.div.write(|w| w.bits(div));
85        }
86
87        uart.txctrl.write(|w| w.txen().bit(true));
88        uart.rxctrl.write(|w| w.rxen().bit(true));
89
90        Serial { uart, pins }
91    }
92}
93
94impl<PINS> Serial<UARTHS, PINS> {
95    /// Starts listening for an interrupt event
96    pub fn listen(self) -> Self {
97        self.uart.ie.write(|w| w.txwm().bit(false).rxwm().bit(true));
98        self
99    }
100
101    /// Stops listening for an interrupt event
102    pub fn unlisten(self) -> Self {
103        self.uart
104            .ie
105            .write(|w| w.txwm().bit(false).rxwm().bit(false));
106        self
107    }
108}
109
110impl<PINS> serial::Read<u8> for Rx<UARTHS, PINS> {
111    type Error = Infallible;
112
113    fn read(&mut self) -> nb::Result<u8, Infallible> {
114        let rxdata = self.uart.rxdata.read();
115
116        if rxdata.empty().bit_is_set() {
117            Err(nb::Error::WouldBlock)
118        } else {
119            Ok(rxdata.data().bits() as u8)
120        }
121    }
122}
123
124impl<PINS> serial::Write<u8> for Tx<UARTHS, PINS> {
125    type Error = Infallible;
126
127    fn write(&mut self, byte: u8) -> nb::Result<(), Infallible> {
128        let txdata = self.uart.txdata.read();
129
130        if txdata.full().bit_is_set() {
131            Err(nb::Error::WouldBlock)
132        } else {
133            unsafe {
134                (*UARTHS::ptr()).txdata.write(|w| w.data().bits(byte));
135            }
136            Ok(())
137        }
138    }
139
140    fn flush(&mut self) -> nb::Result<(), Infallible> {
141        let txdata = self.uart.txdata.read();
142
143        if txdata.full().bit_is_set() {
144            Err(nb::Error::WouldBlock)
145        } else {
146            Ok(())
147        }
148    }
149}
150
151mod closed_trait {
152    use core::ops::Deref;
153    /// Trait to be able to generalize over UART1/UART2/UART3
154    pub trait UartX: Deref<Target = super::uart1::RegisterBlock> {
155        const INDEX: u8;
156    }
157}
158use closed_trait::UartX;
159
160impl UartX for UART1 { const INDEX: u8 = 1; }
161impl UartX for UART2 { const INDEX: u8 = 2; }
162impl UartX for UART3 { const INDEX: u8 = 3; }
163
164const UART_RECEIVE_FIFO_1: u32 = 0;
165const UART_SEND_FIFO_8: u32 = 3;
166
167impl<UART: UartX, TX: ExternalPin, RX: ExternalPin> SerialExt<(TX, RX)> for UART {
168    fn configure(self, pins: (TX, RX), baud_rate: Bps, clocks: &Clocks) -> Serial<UART, (TX, RX)> {
169        let uart = self;
170        fpioa::set_function(TX::INDEX, fpioa::Function::uart(UART::INDEX, fpioa::UartFunction::TX));
171        fpioa::set_function(RX::INDEX, fpioa::Function::uart(UART::INDEX, fpioa::UartFunction::RX));
172
173        // Hardcode these for now:
174        let data_width = 8; // 8 data bits
175        let stopbit_val = 0; // 1 stop bit
176        let parity_val = 0; // No parity
177        // Note: need to make sure that UARTx clock is enabled through sysctl before here
178        let divisor = clocks.apb0().0 / baud_rate.0;
179        let dlh = ((divisor >> 12) & 0xff) as u8;
180        let dll = ((divisor >> 4) & 0xff) as u8;
181        let dlf = (divisor & 0xf) as u8;
182        unsafe {
183            // Set Divisor Latch Access Bit (enables DLL DLH) to set baudrate
184            uart.lcr.write(|w| w.bits(1 << 7));
185            uart.dlh_ier.write(|w| w.bits(dlh.into()));
186            uart.rbr_dll_thr.write(|w| w.bits(dll.into()));
187            uart.dlf.write(|w| w.bits(dlf.into()));
188            // Clear Divisor Latch Access Bit after setting baudrate
189            uart.lcr.write(|w| w.bits((data_width - 5) | (stopbit_val << 2) | (parity_val << 3)));
190            // Write IER
191            uart.dlh_ier.write(|w| w.bits(0x80)); /* THRE */
192            // Write FCT
193            uart.fcr_iir.write(|w| w.bits(UART_RECEIVE_FIFO_1 << 6 | UART_SEND_FIFO_8 << 4 | 0x1 << 3 | 0x1));
194        }
195
196        Serial { uart, pins }
197    }
198}
199
200impl<UART: UartX, PINS> Serial<UART, PINS> {
201    /// Starts listening for an interrupt event
202    pub fn listen(self) -> Self {
203        self
204    }
205
206    /// Stops listening for an interrupt event
207    pub fn unlisten(self) -> Self {
208        self
209    }
210}
211
212impl<UART: UartX, PINS> serial::Read<u8> for Rx<UART, PINS> {
213    type Error = Infallible;
214
215    fn read(&mut self) -> nb::Result<u8, Infallible> {
216        let lsr = self.uart.lsr.read();
217
218        if (lsr.bits() & (1<<0)) == 0 { // Data Ready bit
219            Err(nb::Error::WouldBlock)
220        } else {
221            let rbr = self.uart.rbr_dll_thr.read();
222            Ok((rbr.bits() & 0xff) as u8)
223        }
224    }
225}
226
227impl<UART: UartX, PINS> serial::Write<u8> for Tx<UART, PINS> {
228    type Error = Infallible;
229
230    fn write(&mut self, byte: u8) -> nb::Result<(), Infallible> {
231        let lsr = self.uart.lsr.read();
232
233        if (lsr.bits() & (1<<5)) != 0 { // Transmit Holding Register Empty bit
234            Err(nb::Error::WouldBlock)
235        } else {
236            unsafe {
237                self.uart.rbr_dll_thr.write(|w| w.bits(byte.into()));
238            }
239            Ok(())
240        }
241    }
242
243    fn flush(&mut self) -> nb::Result<(), Infallible> {
244        // TODO
245        Ok(())
246    }
247}