1use core::fmt;
2use core::marker::PhantomData;
3use core::ops::Deref;
4
5use crate::{
6 time::Hertz,
7 traits::wg::serial,
8 typestates::pin::{
9 flexcomm::{
10 Usart,
12 UsartPins,
13 },
14 PinId,
15 },
16};
17
18pub mod config;
19
20#[derive(Debug)]
22#[non_exhaustive]
23pub enum Error {
24 Framing,
26 Noise,
28 Overrun,
30 Parity,
32}
33
34pub struct Serial<TX, RX, USART, PINS>
46where
47 TX: PinId,
48 RX: PinId,
49 USART: Usart,
50 PINS: UsartPins<TX, RX, USART>,
51{
52 usart: USART,
53 pins: PINS,
54 _tx: PhantomData<TX>,
55 _rx: PhantomData<RX>,
56}
57
58pub struct Tx<USART: Usart> {
65 addr: usize,
66 _usart: PhantomData<USART>,
67}
68
69pub struct Rx<USART: Usart> {
71 addr: usize,
72 _usart: PhantomData<USART>,
73}
74
75impl<USART: Usart> Deref for Tx<USART> {
76 type Target = raw::usart0::RegisterBlock;
77 fn deref(&self) -> &Self::Target {
78 let ptr = self.addr as *const _;
79 unsafe { &*ptr }
80 }
81}
82
83impl<USART: Usart> Deref for Rx<USART> {
84 type Target = raw::usart0::RegisterBlock;
85 fn deref(&self) -> &Self::Target {
86 let ptr = self.addr as *const _;
87 unsafe { &*ptr }
88 }
89}
90
91impl<TX, RX, USART, PINS> Serial<TX, RX, USART, PINS>
92where
93 TX: PinId,
94 RX: PinId,
95 USART: Usart,
96 PINS: UsartPins<TX, RX, USART>,
97{
98 const CLOCK_SPEED: u32 = 12_000_000;
99
100 pub fn new(usart: USART, pins: PINS, config: config::Config) -> Self {
101 use self::config::*;
102
103 let speed: Hertz = config.speed;
104 let speed: u32 = speed.0;
105
106 usart
107 .fifocfg
108 .modify(|_, w| w.enabletx().enabled().enablerx().enabled());
109
110 usart.fifotrig.modify(|_, w| unsafe {
111 w.txlvl()
112 .bits(0)
113 .txlvlena()
114 .enabled()
115 .rxlvl()
116 .bits(1)
117 .rxlvlena()
118 .enabled()
119 });
120
121 usart.cfg.write(|w| unsafe {
122 w.paritysel()
123 .bits(match config.parity {
124 Parity::ParityNone => 0,
125 Parity::ParityEven => 2,
126 Parity::ParityOdd => 3,
127 })
128 .stoplen()
129 .bit(match config.stopbits {
130 StopBits::STOP1 => false,
131 StopBits::STOP2 => true,
132 })
133 .datalen()
134 .bits(match config.wordlength {
135 WordLength::DataBits7 => 0,
136 WordLength::DataBits8 => 1,
137 WordLength::DataBits9 => 2,
138 })
139 .loop_()
142 .normal()
143 .syncen()
145 .asynchronous_mode()
146 .clkpol()
148 .falling_edge()
149 .enable()
151 .enabled()
152 });
153
154 let mut best_diff = !0;
156 let mut best_osr = 15;
157 let mut best_brg = !0;
158
159 for osr in (9..=16).rev() {
162 let brg = Self::CLOCK_SPEED / (osr * speed);
163 if brg >= 0xffff {
164 continue;
165 }
166 let realized_speed = Self::CLOCK_SPEED / (osr * brg);
167 let diff = if speed > realized_speed {
168 speed - realized_speed
169 } else {
170 realized_speed - speed
171 };
172 if diff < best_diff {
173 best_diff = diff;
174 best_osr = osr;
175 best_brg = brg;
176 }
177 }
178
179 if best_brg >= 0xffff {
181 panic!("baudrate not supported");
182 }
183
184 usart
185 .brg
186 .write(|w| unsafe { w.brgval().bits(best_brg as u16 - 1) });
187 usart
188 .osr
189 .write(|w| unsafe { w.osrval().bits(best_osr as u8 - 1) });
190
191 Self {
192 usart,
193 pins,
194 _tx: PhantomData,
195 _rx: PhantomData,
196 }
197 }
198
199 fn addr(&self) -> usize {
200 &(*self.usart) as *const _ as usize
201 }
202
203 pub fn split(self) -> (Tx<USART>, Rx<USART>) {
204 (
215 Tx {
216 addr: self.addr(),
217 _usart: PhantomData,
218 },
219 Rx {
220 addr: self.addr(),
221 _usart: PhantomData,
222 },
223 )
224 }
225
226 pub fn release(self) -> (USART, PINS) {
227 (self.usart, self.pins)
228 }
229}
230
231impl<TX, RX, USART, PINS> serial::Read<u8> for Serial<TX, RX, USART, PINS>
232where
233 TX: PinId,
234 RX: PinId,
235 USART: Usart,
236 PINS: UsartPins<TX, RX, USART>,
237{
238 type Error = Error;
239
240 fn read(&mut self) -> nb::Result<u8, Error> {
241 let mut rx: Rx<USART> = Rx {
242 addr: self.addr(),
243 _usart: PhantomData,
244 };
245 rx.read()
246 }
247}
248
249impl<USART: Usart> serial::Read<u8> for Rx<USART> {
250 type Error = Error;
251
252 fn read(&mut self) -> nb::Result<u8, Error> {
253 let fifostat = self.fifostat.read();
254
255 if fifostat.rxnotempty().bit() {
256 let fiford = self.fiford.read();
259
260 if fiford.framerr().bit_is_set() {
261 return Err(nb::Error::Other(Error::Framing));
262 }
263
264 if fiford.parityerr().bit_is_set() {
265 return Err(nb::Error::Other(Error::Parity));
266 }
267
268 if fiford.rxnoise().bit_is_set() {
269 return Err(nb::Error::Other(Error::Noise));
270 }
271
272 if fifostat.rxerr().bit_is_set() {
273 self.fifocfg.modify(|_, w| w.emptyrx().set_bit());
275 self.fifostat.modify(|_, w| w.rxerr().set_bit());
276 return Err(nb::Error::Other(Error::Overrun));
277 }
278
279 Ok(fiford.rxdata().bits() as u8)
280 } else {
281 Err(nb::Error::WouldBlock)
283 }
284 }
285}
286
287impl<TX, RX, USART, PINS> serial::Write<u8> for Serial<TX, RX, USART, PINS>
288where
289 TX: PinId,
290 RX: PinId,
291 USART: Usart,
292 PINS: UsartPins<TX, RX, USART>,
293{
294 type Error = Error;
295
296 fn flush(&mut self) -> nb::Result<(), Self::Error> {
297 let mut tx: Tx<USART> = Tx {
298 addr: self.addr(),
299 _usart: PhantomData,
300 };
301 tx.flush()
302 }
303
304 fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
305 let mut tx: Tx<USART> = Tx {
306 addr: self.addr(),
307 _usart: PhantomData,
308 };
309 tx.write(byte)
310 }
311}
312
313impl<USART: Usart> serial::Write<u8> for Tx<USART> {
314 type Error = Error;
315
316 fn flush(&mut self) -> nb::Result<(), Self::Error> {
317 if self.stat.read().txidle().bit() {
318 Ok(())
319 } else {
320 Err(nb::Error::WouldBlock)
321 }
322 }
323
324 fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
325 if self.fifostat.read().txnotfull().bit() {
326 self.fifowr.write(|w| unsafe { w.bits(byte as u32) });
329
330 Ok(())
331 } else {
332 Err(nb::Error::WouldBlock)
333 }
334 }
335}
336
337impl<USART: Usart> fmt::Write for Tx<USART>
338where
339 Tx<USART>: serial::Write<u8>,
340{
341 fn write_str(&mut self, s: &str) -> fmt::Result {
342 use crate::traits::wg::serial::Write;
343 let _ = s
344 .as_bytes()
345 .iter()
346 .map(|c| nb::block!(self.write(*c)))
347 .last();
348 Ok(())
349 }
350}