#![cfg_attr(
not(feature = "samd11"),
doc = "
Alternatively, you can use the [`PadsFromIds`] alias to define a set of
`Pads` in terms of [`PinId`]s instead of `Pin`s. This is useful when you
don't have [`Pin`] aliases pre-defined.
```
use atsamd_hal::gpio::{PA08, PA09};
use atsamd_hal::sercom::{Sercom0, uart};
type Pads = uart::PadsFromIds<Sercom0, PA08, PA09>;
```
"
)]
#![cfg_attr(
feature = "dma",
doc = "
# Using UART with DMA
This HAL includes support for DMA-enabled UART transfers. [`Uart`]
implements the DMAC [`Buffer`]
trait. The provided [`send_with_dma`] and
[`receive_with_dma`] build and begin a
[`dmac::Transfer`], thus starting the UART
in a non-blocking way. Optionally, interrupts can be enabled on the provided
[`Channel`]. Note that the `dma` feature must
be enabled. Please refer to the [`dmac`](crate::dmac) module-level
documentation for more information.
```
// Assume channel0 and channel1 are configured `dmac::Channel`s,
// rx is a Uart<C, RxDuplex>, and tx is a Uart<C, TxDuplex>.
/// Create data to send
let tx_buffer: [u8; 50] = [0xff; 50];
let rx_buffer: [u8; 100] = [0xab; 100];
// Launch transmit transfer
let tx_dma = tx.send_with_dma(&mut tx_buffer, channel0, |_| {});
// Launch receive transfer
let rx_dma = rx.receive_with_dma(&mut rx_buffer, channel1, |_| {});
// Wait for transfers to complete and reclaim resources
let (chan0, tx_buffer, tx) = tx_dma.wait();
let (chan1, rx, rx_buffer) = rx_dma.wait();
```
[`Buffer`]: crate::dmac::transfer::Buffer
[`send_with_dma`]: Uart::send_with_dma
[`receive_with_dma`]: Uart::receive_with_dma
[`dmac::Transfer`]: crate::dmac::Transfer
[`Channel`]: crate::dmac::channel::Channel
[`dmac`]: crate::dmac
"
)]
#[cfg(any(feature = "samd11", feature = "samd21"))]
#[path = "uart/pads_thumbv6m.rs"]
mod pads;
#[cfg(feature = "min-samd51g")]
#[path = "uart/pads_thumbv7em.rs"]
mod pads;
pub use pads::*;
mod reg;
use reg::Registers;
mod charsize;
pub use charsize::*;
mod flags;
pub use flags::*;
mod config;
pub use config::*;
pub mod impl_ehal;
use crate::{sercom::*, typelevel::Sealed};
use core::{convert::TryInto, marker::PhantomData};
use num_traits::AsPrimitive;
#[cfg(any(feature = "samd11", feature = "samd21"))]
pub type DataReg = u16;
#[cfg(any(feature = "min-samd51g"))]
pub type DataReg = u32;
#[derive(Debug, Clone, Copy)]
pub enum StopBits {
OneBit,
TwoBits,
}
#[repr(u8)]
#[derive(Debug, Clone, Copy)]
pub enum Parity {
None,
Even,
Odd,
}
#[repr(u8)]
#[derive(Debug, Clone, Copy)]
pub enum BitOrder {
MsbFirst,
LsbFirst,
}
#[repr(u8)]
#[derive(Debug, Clone, Copy)]
pub enum Oversampling {
Bits8 = 8,
Bits16 = 16,
}
#[derive(Debug, Clone, Copy)]
pub enum BaudMode {
Arithmetic(Oversampling),
Fractional(Oversampling),
}
pub trait Capability: Sealed {
const FLAG_MASK: u8;
const STATUS_MASK: u16;
const RXEN: bool;
const TXEN: bool;
}
pub trait Transmit: Capability {}
pub trait Receive: Capability {}
pub trait Simplex: Capability {}
pub enum Duplex {}
impl Sealed for Duplex {}
impl Capability for Duplex {
const FLAG_MASK: u8 = DUPLEX_FLAG_MASK;
const STATUS_MASK: u16 = DUPLEX_STATUS_MASK;
const RXEN: bool = true;
const TXEN: bool = true;
}
impl Receive for Duplex {}
impl Transmit for Duplex {}
pub enum Rx {}
impl Sealed for Rx {}
impl Capability for Rx {
const FLAG_MASK: u8 = RX_FLAG_MASK;
const STATUS_MASK: u16 = RX_STATUS_MASK;
const RXEN: bool = true;
const TXEN: bool = false;
}
impl Receive for Rx {}
impl Simplex for Rx {}
pub enum Tx {}
impl Sealed for Tx {}
impl Capability for Tx {
const FLAG_MASK: u8 = TX_FLAG_MASK;
const STATUS_MASK: u16 = 0;
const RXEN: bool = false;
const TXEN: bool = true;
}
impl Transmit for Tx {}
impl Simplex for Tx {}
pub enum RxDuplex {}
impl Sealed for RxDuplex {}
impl Capability for RxDuplex {
const FLAG_MASK: u8 = RX_FLAG_MASK;
const STATUS_MASK: u16 = RX_STATUS_MASK;
const RXEN: bool = true;
const TXEN: bool = false;
}
impl Receive for RxDuplex {}
pub enum TxDuplex {}
impl Sealed for TxDuplex {}
impl Capability for TxDuplex {
const FLAG_MASK: u8 = TX_FLAG_MASK;
const STATUS_MASK: u16 = 0;
const RXEN: bool = false;
const TXEN: bool = true;
}
impl Transmit for TxDuplex {}
pub struct Uart<C, D>
where
C: ValidConfig,
D: Capability,
{
config: C,
capability: PhantomData<D>,
}
impl<C, D> Uart<C, D>
where
C: ValidConfig,
D: Capability,
{
#[cfg(feature = "dma")]
#[inline]
pub(crate) fn data_ptr(&self) -> *mut C::Word {
self.config.as_ref().registers.data_ptr()
}
#[inline]
fn capability_flags(flags: Flags) -> Flags {
flags & unsafe { Flags::from_bits_unchecked(D::FLAG_MASK) }
}
#[inline]
fn capability_status(status: Status) -> Status {
status & unsafe { Status::from_bits_unchecked(D::STATUS_MASK) }
}
#[inline]
pub fn read_flags(&self) -> Flags {
self.config.as_ref().registers.read_flags()
}
#[inline]
pub fn clear_flags(&mut self, flags: Flags) {
let flags = Self::capability_flags(flags);
self.config.as_mut().registers.clear_flags(flags);
}
#[inline]
pub fn enable_interrupts(&mut self, flags: Flags) {
let flags = Self::capability_flags(flags);
self.config.as_mut().registers.enable_interrupts(flags);
}
#[inline]
pub fn disable_interrupts(&mut self, flags: Flags) {
let flags = Self::capability_flags(flags);
self.config.as_mut().registers.disable_interrupts(flags);
}
#[inline]
pub fn read_status(&self) -> Status {
self.config.as_ref().registers.read_status()
}
#[inline]
pub fn clear_status(&mut self, status: Status) {
let flags = Self::capability_status(status);
self.config.as_mut().registers.clear_status(flags);
}
#[inline]
pub(super) fn _reconfigure<F>(&mut self, update: F)
where
F: FnOnce(&mut SpecificConfig<C>),
{
self.config.as_mut().registers.enable_peripheral(false);
update(self.config.as_mut());
self.config.as_mut().registers.enable_peripheral(true);
}
}
impl<C, D> Uart<C, D>
where
C: ValidConfig,
<C::Pads as PadSet>::Cts: SomePad,
D: Transmit,
{
#[inline]
pub fn clear_ctsic(&mut self) {
let bit = CTSIC;
self.config
.as_mut()
.registers
.clear_flags(unsafe { Flags::from_bits_unchecked(bit) });
}
#[inline]
pub fn enable_ctsic(&mut self) {
let bit = CTSIC;
self.config
.as_mut()
.registers
.enable_interrupts(unsafe { Flags::from_bits_unchecked(bit) });
}
#[inline]
pub fn disable_ctsic(&mut self) {
let bit = CTSIC;
self.config
.as_mut()
.registers
.disable_interrupts(unsafe { Flags::from_bits_unchecked(bit) });
}
}
impl<C, D> Uart<C, D>
where
C: ValidConfig,
D: Simplex,
{
#[inline]
pub fn disable(self) -> C {
let mut config = self.config;
config.as_mut().registers.disable();
config
}
#[inline]
pub fn reconfigure<U>(&mut self, update: U)
where
U: FnOnce(&mut SpecificConfig<C>),
{
self._reconfigure(update);
}
}
impl<C> Uart<C, Duplex>
where
C: ValidConfig,
{
#[inline]
pub fn split(self) -> (Uart<C, RxDuplex>, Uart<C, TxDuplex>) {
let config = unsafe { core::ptr::read(&self.config) };
(
Uart {
config: self.config,
capability: PhantomData,
},
Uart {
config,
capability: PhantomData,
},
)
}
#[inline]
pub fn disable(self) -> C {
let mut config = self.config;
config.as_mut().registers.disable();
config
}
#[inline]
pub fn reconfigure<F>(&mut self, update: F)
where
F: FnOnce(&mut SpecificConfig<C>),
{
self._reconfigure(update);
}
pub fn join(rx: Uart<C, RxDuplex>, _tx: Uart<C, TxDuplex>) -> Self {
Self {
config: rx.config,
capability: PhantomData,
}
}
}
impl<C: ValidConfig> AsMut<Uart<C, Duplex>> for (&mut Uart<C, RxDuplex>, &mut Uart<C, TxDuplex>) {
#[inline]
fn as_mut(&mut self) -> &mut Uart<C, Duplex> {
unsafe { &mut *(self.0 as *mut _ as *mut Uart<C, Duplex>) }
}
}
impl<C, D> AsRef<SpecificConfig<C>> for Uart<C, D>
where
C: ValidConfig,
D: Capability,
{
#[inline]
fn as_ref(&self) -> &SpecificConfig<C> {
self.config.as_ref()
}
}
impl<C, D> Uart<C, D>
where
C: ValidConfig,
D: Receive,
DataReg: AsPrimitive<C::Word>,
{
#[inline]
pub unsafe fn read_data(&mut self) -> DataReg {
self.config.as_mut().registers.read_data()
}
#[inline]
fn read_flags_errors(&self) -> Result<Flags, Error> {
self.read_status().try_into()?;
Ok(self.read_flags())
}
#[inline]
pub fn flush_rx_buffer(&mut self) {
for _ in 0..=2 {
let _data = unsafe { self.config.as_mut().registers.read_data() };
}
self.clear_status(
Status::BUFOVF | Status::FERR | Status::PERR | Status::ISF | Status::COLL,
);
}
}
impl<C, D> Uart<C, D>
where
C: ValidConfig,
D: Transmit,
{
#[inline]
pub unsafe fn write_data(&mut self, data: DataReg) {
self.config.as_mut().registers.write_data(data);
}
}