1use crate::{
4 gpio::{
5 InputPin,
6 LpPin,
7 OutputPin,
8 lp_io::{LpFunction, low_level},
9 },
10 peripherals::{LP_CLKRST, LP_UART, LPWR},
11 uart::{DataBits, Parity, StopBits},
12};
13
14pub trait Tx: LpPin + OutputPin {
16 #[doc(hidden)]
17 fn connect_tx(&self);
18}
19
20pub trait Rx: LpPin + InputPin {
22 #[doc(hidden)]
23 fn connect_rx(&self);
24}
25
26#[cfg(lp_io_has_gpio_matrix)]
29for_each_lp_function! {
30 (($_signal:ident, LP_GPIOn, $_pin:literal), $gpio:ident, $_af:ident, $_lp_in:tt $_lp_out:tt) => {
31 impl Tx for crate::peripherals::$gpio<'_> {
32 fn connect_tx(&self) {
33 crate::gpio::lp_io::connect_output_signal(
34 self,
35 crate::gpio::lp_io::LpOutputSignal::LP_UART_TXD,
36 );
37 }
38 }
39
40 impl Rx for crate::peripherals::$gpio<'_> {
41 fn connect_rx(&self) {
42 crate::gpio::lp_io::connect_input_signal(
43 self,
44 crate::gpio::lp_io::LpInputSignal::LP_UART_RXD,
45 );
46 }
47 }
48 };
49}
50
51#[cfg(not(lp_io_has_gpio_matrix))]
52for_each_lp_function! {
53 (LP_UART_TXD, $gpio:ident, $af:ident) => {
54 impl Tx for crate::peripherals::$gpio<'_> {
55 fn connect_tx(&self) {
56 low_level::set_config(self.lp_number(), false, true, LpFunction::$af);
59 }
60 }
61 };
62 (LP_UART_RXD, $gpio:ident, $af:ident) => {
63 impl Rx for crate::peripherals::$gpio<'_> {
64 fn connect_rx(&self) {
65 low_level::set_config(self.lp_number(), true, true, LpFunction::$af);
66 }
67 }
68 };
69}
70
71#[derive(Debug, Clone, Copy, procmacros::BuilderLite)]
73#[cfg_attr(feature = "defmt", derive(defmt::Format))]
74#[non_exhaustive]
75pub struct Config {
76 baudrate: u32,
79 data_bits: DataBits,
81 parity: Parity,
83 stop_bits: StopBits,
85 #[builder_lite(unstable)]
87 clock_source: ClockSource,
88}
89
90impl Default for Config {
91 fn default() -> Config {
92 Config {
93 baudrate: 115_200,
94 data_bits: Default::default(),
95 parity: Default::default(),
96 stop_bits: Default::default(),
97 clock_source: Default::default(),
98 }
99 }
100}
101
102#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
104#[cfg_attr(feature = "defmt", derive(defmt::Format))]
105#[non_exhaustive]
106#[instability::unstable]
107pub enum ClockSource {
108 RcFast,
110
111 #[default]
113 Xtal,
114}
115
116pub struct LpUart {
118 uart: LP_UART<'static>,
119}
120
121impl LpUart {
122 pub fn new(
125 uart: LP_UART<'static>,
126 config: Config,
127 tx: impl Tx + 'static,
128 rx: impl Rx + 'static,
129 ) -> Self {
130 rx.connect_rx();
131 tx.connect_tx();
132
133 let mut me = Self { uart };
134 let uart = me.uart.register_block();
135
136 uart.conf0().modify(|_, w| unsafe {
142 w.parity().clear_bit();
143 w.parity_en().clear_bit();
144 w.bit_num().bits(0x3);
145 w.stop_bit_num().bits(0x1)
146 });
147 uart.idle_conf()
149 .modify(|_, w| unsafe { w.tx_idle_num().bits(0) });
150 uart.hwfc_conf().modify(|_, w| w.rx_flow_en().clear_bit());
152
153 LPWR::regs()
158 .lpperi()
159 .modify(|_, w| w.lp_uart_clk_sel().clear_bit());
160
161 me.change_baud_internal(&config);
164 me.change_parity(config.parity);
166 me.change_data_bits(config.data_bits);
168 me.change_stop_bits(config.stop_bits);
170 me.change_tx_idle(0); me.rxfifo_reset();
175 me.txfifo_reset();
176
177 me
178 }
179
180 fn rxfifo_reset(&mut self) {
181 self.uart
182 .register_block()
183 .conf0()
184 .modify(|_, w| w.rxfifo_rst().set_bit());
185 self.update();
186
187 self.uart
188 .register_block()
189 .conf0()
190 .modify(|_, w| w.rxfifo_rst().clear_bit());
191 self.update();
192 }
193
194 fn txfifo_reset(&mut self) {
195 self.uart
196 .register_block()
197 .conf0()
198 .modify(|_, w| w.txfifo_rst().set_bit());
199 self.update();
200
201 self.uart
202 .register_block()
203 .conf0()
204 .modify(|_, w| w.txfifo_rst().clear_bit());
205 self.update();
206 }
207
208 fn update(&mut self) {
209 let register_block = self.uart.register_block();
210 register_block
211 .reg_update()
212 .modify(|_, w| w.reg_update().set_bit());
213 while register_block.reg_update().read().reg_update().bit_is_set() {
214 }
216 }
217
218 fn change_baud_internal(&mut self, config: &Config) {
219 let clk = match config.clock_source {
220 ClockSource::RcFast => crate::soc::clocks::rc_fast_clk_frequency(),
221 ClockSource::Xtal => crate::soc::clocks::xtal_d2_clk_frequency(),
222 };
223
224 LP_CLKRST::regs().lpperi().modify(|_, w| {
225 w.lp_uart_clk_sel().bit(match config.clock_source {
226 ClockSource::RcFast => false,
227 ClockSource::Xtal => true,
228 })
229 });
230 self.uart.register_block().clk_conf().modify(|_, w| {
231 w.rx_sclk_en().set_bit();
232 w.tx_sclk_en().set_bit()
233 });
234
235 let divider = clk / config.baudrate;
236 let divider = divider as u16;
237
238 self.uart
239 .register_block()
240 .clkdiv()
241 .write(|w| unsafe { w.clkdiv().bits(divider).frag().bits(0) });
242
243 self.update();
244 }
245
246 pub fn change_baud(&mut self, config: &Config) {
248 self.change_baud_internal(config);
249 self.txfifo_reset();
250 self.rxfifo_reset();
251 }
252
253 fn change_parity(&mut self, parity: Parity) -> &mut Self {
254 if parity != Parity::None {
255 self.uart
256 .register_block()
257 .conf0()
258 .modify(|_, w| w.parity().bit((parity as u8 & 0x1) != 0));
259 }
260
261 self.uart
262 .register_block()
263 .conf0()
264 .modify(|_, w| match parity {
265 Parity::None => w.parity_en().clear_bit(),
266 Parity::Even => w.parity_en().set_bit().parity().clear_bit(),
267 Parity::Odd => w.parity_en().set_bit().parity().set_bit(),
268 });
269
270 self
271 }
272
273 fn change_data_bits(&mut self, data_bits: DataBits) -> &mut Self {
274 self.uart
275 .register_block()
276 .conf0()
277 .modify(|_, w| unsafe { w.bit_num().bits(data_bits as u8) });
278
279 self.update();
280 self
281 }
282
283 fn change_stop_bits(&mut self, stop_bits: StopBits) -> &mut Self {
284 self.uart
285 .register_block()
286 .conf0()
287 .modify(|_, w| unsafe { w.stop_bit_num().bits(stop_bits as u8 + 1) });
288
289 self.update();
290 self
291 }
292
293 fn change_tx_idle(&mut self, idle_num: u16) -> &mut Self {
294 self.uart
295 .register_block()
296 .idle_conf()
297 .modify(|_, w| unsafe { w.tx_idle_num().bits(idle_num) });
298
299 self.update();
300 self
301 }
302}