use embassy_hal_common::{into_ref, PeripheralRef}; use gpio::Pin; use crate::{gpio, pac, peripherals, Peripheral}; #[non_exhaustive] pub struct Config { pub baudrate: u32, pub data_bits: u8, pub stop_bits: u8, } impl Default for Config { fn default() -> Self { Self { baudrate: 115200, data_bits: 8, stop_bits: 1, } } } pub struct Uart<'d, T: Instance> { inner: PeripheralRef<'d, T>, } impl<'d, T: Instance> Uart<'d, T> { pub fn new( inner: impl Peripheral
+ 'd, tx: impl Peripheral
> + 'd, rx: impl Peripheral
> + 'd, cts: impl Peripheral
> + 'd, rts: impl Peripheral
> + 'd,
config: Config,
) -> Self {
into_ref!(inner, tx, rx, cts, rts);
unsafe {
let p = inner.regs();
let clk_base = crate::clocks::clk_peri_freq();
let baud_rate_div = (8 * clk_base) / config.baudrate;
let mut baud_ibrd = baud_rate_div >> 7;
let mut baud_fbrd = ((baud_rate_div & 0x7f) + 1) / 2;
if baud_ibrd == 0 {
baud_ibrd = 1;
baud_fbrd = 0;
} else if baud_ibrd >= 65535 {
baud_ibrd = 65535;
baud_fbrd = 0;
}
// Load PL011's baud divisor registers
p.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
p.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
p.uartlcr_h().write(|w| {
w.set_wlen(config.data_bits - 5);
w.set_stp2(config.stop_bits == 2);
w.set_pen(false);
w.set_eps(false);
w.set_fen(true);
});
p.uartcr().write(|w| {
w.set_uarten(true);
w.set_rxe(true);
w.set_txe(true);
});
tx.io().ctrl().write(|w| w.set_funcsel(2));
rx.io().ctrl().write(|w| w.set_funcsel(2));
cts.io().ctrl().write(|w| w.set_funcsel(2));
rts.io().ctrl().write(|w| w.set_funcsel(2));
}
Self { inner }
}
pub fn send(&mut self, data: &[u8]) {
unsafe {
let p = self.inner.regs();
for &byte in data {
if !p.uartfr().read().txff() {
p.uartdr().write(|w| w.set_data(byte));
}
}
}
}
}
mod sealed {
use super::*;
pub trait Instance {
fn regs(&self) -> pac::uart::Uart;
}
pub trait TxPin