embassy/embassy-stm32/src/usart/v1.rs

146 lines
4.3 KiB
Rust
Raw Normal View History

2021-07-15 05:42:06 +02:00
use core::future::Future;
2021-05-15 03:52:58 +02:00
use core::marker::PhantomData;
use embassy::util::Unborrow;
use embassy_extras::unborrow;
2021-07-15 05:42:06 +02:00
use futures::TryFutureExt;
2021-05-15 03:52:58 +02:00
use super::*;
2021-07-15 05:42:06 +02:00
use crate::dma::NoDma;
use crate::pac::usart::{regs, vals};
2021-05-15 03:52:58 +02:00
2021-07-15 05:42:06 +02:00
pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> {
2021-05-15 03:52:58 +02:00
inner: T,
phantom: PhantomData<&'d mut T>,
2021-07-15 05:42:06 +02:00
tx_dma: TxDma,
#[allow(dead_code)]
rx_dma: RxDma,
2021-05-15 03:52:58 +02:00
}
2021-07-15 05:42:06 +02:00
impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
2021-05-15 03:52:58 +02:00
pub fn new(
inner: impl Unborrow<Target = T>,
rx: impl Unborrow<Target = impl RxPin<T>>,
tx: impl Unborrow<Target = impl TxPin<T>>,
2021-07-15 05:42:06 +02:00
tx_dma: impl Unborrow<Target = TxDma>,
rx_dma: impl Unborrow<Target = RxDma>,
2021-05-15 03:52:58 +02:00
config: Config,
) -> Self {
2021-07-15 05:42:06 +02:00
unborrow!(inner, rx, tx, tx_dma, rx_dma);
2021-05-15 03:52:58 +02:00
2021-06-30 09:57:27 -04:00
T::enable();
2021-06-29 10:59:22 -04:00
let pclk_freq = T::frequency();
2021-05-15 03:52:58 +02:00
// TODO: better calculation, including error checking and OVER8 if possible.
2021-06-29 10:59:22 -04:00
let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate;
2021-05-15 03:52:58 +02:00
let r = inner.regs();
unsafe {
rx.set_as_af(rx.af_num());
tx.set_as_af(tx.af_num());
r.brr().write_value(regs::Brr(div));
r.cr1().write(|w| {
w.set_ue(true);
w.set_te(true);
w.set_re(true);
w.set_m(vals::M::M8);
w.set_pce(config.parity != Parity::ParityNone);
w.set_ps(match config.parity {
Parity::ParityOdd => vals::Ps::ODD,
Parity::ParityEven => vals::Ps::EVEN,
_ => vals::Ps::EVEN,
});
});
r.cr2().write(|_w| {});
r.cr3().write(|_w| {});
}
Self {
inner,
phantom: PhantomData,
2021-07-15 05:42:06 +02:00
tx_dma,
rx_dma,
2021-05-15 03:52:58 +02:00
}
}
2021-05-15 04:25:44 +02:00
2021-07-15 05:42:06 +02:00
async fn write_dma(&mut self, buffer: &[u8]) -> Result<(), Error>
where
TxDma: crate::usart::TxDma<T>,
{
let ch = &mut self.tx_dma;
2021-05-16 02:57:46 +02:00
unsafe {
2021-06-29 10:59:22 -04:00
self.inner.regs().cr3().modify(|reg| {
reg.set_dmat(true);
2021-05-16 02:57:46 +02:00
});
}
2021-06-29 10:59:22 -04:00
let r = self.inner.regs();
let dst = r.dr().ptr() as *mut u8;
2021-07-15 05:42:06 +02:00
ch.write(ch.request(), buffer, dst).await;
2021-05-16 02:57:46 +02:00
Ok(())
}
2021-05-15 04:25:44 +02:00
pub fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
unsafe {
let r = self.inner.regs();
for b in buffer {
loop {
let sr = r.sr().read();
if sr.pe() {
r.dr().read();
return Err(Error::Parity);
} else if sr.fe() {
r.dr().read();
return Err(Error::Framing);
} else if sr.ne() {
r.dr().read();
return Err(Error::Noise);
} else if sr.ore() {
r.dr().read();
return Err(Error::Overrun);
} else if sr.rxne() {
break;
}
}
*b = r.dr().read().0 as u8;
}
}
Ok(())
}
2021-05-15 03:52:58 +02:00
}
2021-07-15 05:42:06 +02:00
impl<'d, T: Instance, RxDma> embedded_hal::blocking::serial::Write<u8>
for Uart<'d, T, NoDma, RxDma>
{
2021-05-15 03:52:58 +02:00
type Error = Error;
fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
unsafe {
let r = self.inner.regs();
for &b in buffer {
while !r.sr().read().txe() {}
r.dr().write_value(regs::Dr(b as u32))
}
}
Ok(())
}
fn bflush(&mut self) -> Result<(), Self::Error> {
unsafe {
let r = self.inner.regs();
while !r.sr().read().tc() {}
}
Ok(())
}
}
2021-07-15 05:42:06 +02:00
// rustfmt::skip because intellij removes the 'where' claus on the associated type.
#[rustfmt::skip]
impl<'d, T: Instance, TxDma, RxDma> embassy_traits::uart::Write for Uart<'d, T, TxDma, RxDma>
where TxDma: crate::usart::TxDma<T>
{
type WriteFuture<'a> where Self: 'a = impl Future<Output = Result<(), embassy_traits::uart::Error>>;
fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
self.write_dma(buf).map_err(|_| embassy_traits::uart::Error::Other)
}
}