use core::marker::PhantomData;
use core::ptr;
use core::sync::atomic::{self, Ordering};
use nb;
use crate::pac::{USART1, USART2, USART3};
use void::Void;
use crate::afio::MAPR;
use crate::dma::{dma1, CircBuffer, Static, Transfer, R, W, RxDma, TxDma};
use crate::gpio::gpioa::{PA10, PA2, PA3, PA9};
use crate::gpio::gpiob::{PB10, PB11, PB6, PB7};
use crate::gpio::{Alternate, Floating, Input, PushPull};
use crate::rcc::{Clocks, APB1, APB2};
use crate::time::Bps;
pub enum Event {
Rxne,
Txe,
}
#[derive(Debug)]
pub enum Error {
Framing,
Noise,
Overrun,
Parity,
#[doc(hidden)]
_Extensible,
}
pub trait Pins<USART> {
const REMAP: u8;
}
impl Pins<USART1> for (PA9<Alternate<PushPull>>, PA10<Input<Floating>>) {
const REMAP: u8 = 0;
}
impl Pins<USART1> for (PB6<Alternate<PushPull>>, PB7<Input<Floating>>) {
const REMAP: u8 = 1;
}
impl Pins<USART2> for (PA2<Alternate<PushPull>>, PA3<Input<Floating>>) {
const REMAP: u8 = 0;
}
impl Pins<USART3> for (PB10<Alternate<PushPull>>, PB11<Input<Floating>>) {
const REMAP: u8 = 0;
}
pub struct Serial<USART, PINS> {
usart: USART,
pins: PINS,
}
pub struct Rx<USART> {
_usart: PhantomData<USART>,
}
pub struct Tx<USART> {
_usart: PhantomData<USART>,
}
macro_rules! hal {
($(
$(#[$meta:meta])*
$USARTX:ident: (
$usartX:ident,
$usartXen:ident,
$usartXrst:ident,
$usartX_remap:ident,
$pclk:ident,
$bit:ident,
$closure:expr,
$APB:ident
),
)+) => {
$(
$(#[$meta])*
impl<PINS> Serial<$USARTX, PINS> {
pub fn $usartX(
usart: $USARTX,
pins: PINS,
mapr: &mut MAPR,
baud_rate: Bps,
clocks: Clocks,
apb: &mut $APB,
) -> Self
where
PINS: Pins<$USARTX>,
{
apb.enr().modify(|_, w| w.$usartXen().set_bit());
apb.rstr().modify(|_, w| w.$usartXrst().set_bit());
apb.rstr().modify(|_, w| w.$usartXrst().clear_bit());
#[allow(unused_unsafe)]
mapr.mapr()
.modify(|_, w| unsafe{
w.$usartX_remap().$bit(($closure)(PINS::REMAP))
});
usart.cr3.write(|w| w.dmat().set_bit().dmar().set_bit());
let brr = clocks.$pclk().0 / baud_rate.0;
assert!(brr >= 16, "impossible baud rate");
usart.brr.write(|w| unsafe { w.bits(brr) });
usart
.cr1
.write(|w| w.ue().set_bit().re().set_bit().te().set_bit());
Serial { usart, pins }
}
pub fn listen(&mut self, event: Event) {
match event {
Event::Rxne => self.usart.cr1.modify(|_, w| w.rxneie().set_bit()),
Event::Txe => self.usart.cr1.modify(|_, w| w.txeie().set_bit()),
}
}
pub fn unlisten(&mut self, event: Event) {
match event {
Event::Rxne => self.usart.cr1.modify(|_, w| w.rxneie().clear_bit()),
Event::Txe => self.usart.cr1.modify(|_, w| w.txeie().clear_bit()),
}
}
pub fn release(self) -> ($USARTX, PINS) {
(self.usart, self.pins)
}
pub fn split(self) -> (Tx<$USARTX>, Rx<$USARTX>) {
(
Tx {
_usart: PhantomData,
},
Rx {
_usart: PhantomData,
},
)
}
}
impl crate::hal::serial::Read<u8> for Rx<$USARTX> {
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Error> {
let sr = unsafe { (*$USARTX::ptr()).sr.read() };
let err = if sr.pe().bit_is_set() {
Some(Error::Parity)
} else if sr.fe().bit_is_set() {
Some(Error::Framing)
} else if sr.ne().bit_is_set() {
Some(Error::Noise)
} else if sr.ore().bit_is_set() {
Some(Error::Overrun)
} else {
None
};
if let Some(err) = err {
unsafe {
ptr::read_volatile(&(*$USARTX::ptr()).sr as *const _ as *const _);
ptr::read_volatile(&(*$USARTX::ptr()).dr as *const _ as *const _);
}
Err(nb::Error::Other(err))
} else {
if sr.rxne().bit_is_set() {
Ok(unsafe {
ptr::read_volatile(&(*$USARTX::ptr()).dr as *const _ as *const _)
})
} else {
Err(nb::Error::WouldBlock)
}
}
}
}
impl crate::hal::serial::Write<u8> for Tx<$USARTX> {
type Error = Void;
fn flush(&mut self) -> nb::Result<(), Self::Error> {
let sr = unsafe { (*$USARTX::ptr()).sr.read() };
if sr.tc().bit_is_set() {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
let sr = unsafe { (*$USARTX::ptr()).sr.read() };
if sr.txe().bit_is_set() {
unsafe {
ptr::write_volatile(&(*$USARTX::ptr()).dr as *const _ as *mut _, byte)
}
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
)+
}
}
hal! {
USART1: (
usart1,
usart1en,
usart1rst,
usart1_remap,
pclk2,
bit,
|remap| remap == 1,
APB2
),
USART2: (
usart2,
usart2en,
usart2rst,
usart2_remap,
pclk1,
bit,
|remap| remap == 1,
APB1
),
USART3: (
usart3,
usart3en,
usart3rst,
usart3_remap,
pclk1,
bits,
|remap| remap,
APB1
),
}
use crate::dma::{Transmit, Receive};
macro_rules! serialdma {
($(
$USARTX:ident: (
$dmarxch:ty,
$dmatxch:ty,
),
)+) => {
$(
impl Receive for RxDma<$USARTX, $dmarxch> {
type RxChannel = $dmarxch;
type TransmittedWord = u8;
}
impl Transmit for TxDma<$USARTX, $dmatxch> {
type TxChannel = $dmatxch;
type ReceivedWord = u8;
}
impl Rx<$USARTX> {
pub fn with_dma(self, channel: $dmarxch) -> RxDma<$USARTX, $dmarxch> {
RxDma {
_payload: PhantomData,
channel,
}
}
}
impl Tx<$USARTX> {
pub fn with_dma(self, channel: $dmatxch) -> TxDma<$USARTX, $dmatxch> {
TxDma {
_payload: PhantomData,
channel,
}
}
}
impl RxDma<$USARTX, $dmarxch> {
pub fn split(mut self) -> (Rx<$USARTX>, $dmarxch) {
self.stop();
let RxDma {_payload, channel} = self;
(
Rx { _usart: PhantomData },
channel
)
}
}
impl TxDma<$USARTX, $dmatxch> {
pub fn split(mut self) -> (Tx<$USARTX>, $dmatxch) {
self.stop();
let TxDma {_payload, channel} = self;
(
Tx { _usart: PhantomData },
channel,
)
}
}
impl<B> crate::dma::CircReadDma<B, u8> for RxDma<$USARTX, $dmarxch> where B: AsMut<[u8]> {
fn circ_read(mut self, buffer: &'static mut [B; 2],
) -> CircBuffer<B, $dmarxch>
{
{
let buffer = buffer[0].as_mut();
self.channel.set_peripheral_address(unsafe{ &(*$USARTX::ptr()).dr as *const _ as u32 }, false);
self.channel.set_memory_address(buffer.as_ptr() as u32, true);
self.channel.set_transfer_length(buffer.len() * 2);
atomic::compiler_fence(Ordering::Release);
self.channel.ch().cr.modify(|_, w| { w
.mem2mem() .clear_bit()
.pl() .medium()
.msize() .bit8()
.psize() .bit8()
.circ() .set_bit()
.dir() .clear_bit()
});
}
self.start();
let RxDma {_payload, channel} = self;
CircBuffer::new(buffer, channel)
}
}
impl<B> crate::dma::ReadDma<B, u8> for RxDma<$USARTX, $dmarxch> where B: AsMut<[u8]> {
fn read(mut self, buffer: &'static mut B,
) -> Transfer<W, &'static mut B, Self>
{
{
let buffer = buffer.as_mut();
self.channel.set_peripheral_address(unsafe{ &(*$USARTX::ptr()).dr as *const _ as u32 }, false);
self.channel.set_memory_address(buffer.as_ptr() as u32, true);
self.channel.set_transfer_length(buffer.len());
}
atomic::compiler_fence(Ordering::Release);
self.channel.ch().cr.modify(|_, w| { w
.mem2mem() .clear_bit()
.pl() .medium()
.msize() .bit8()
.psize() .bit8()
.circ() .clear_bit()
.dir() .clear_bit()
});
self.start();
Transfer::w(buffer, self)
}
}
impl<A, B> crate::dma::WriteDma<A, B, u8> for TxDma<$USARTX, $dmatxch> where A: AsRef<[u8]>, B: Static<A> {
fn write(mut self, buffer: B
) -> Transfer<R, B, Self>
{
{
let buffer = buffer.borrow().as_ref();
self.channel.set_peripheral_address(unsafe{ &(*$USARTX::ptr()).dr as *const _ as u32 }, false);
self.channel.set_memory_address(buffer.as_ptr() as u32, true);
self.channel.set_transfer_length(buffer.len());
}
atomic::compiler_fence(Ordering::Release);
self.channel.ch().cr.modify(|_, w| { w
.mem2mem() .clear_bit()
.pl() .medium()
.msize() .bit8()
.psize() .bit8()
.circ() .clear_bit()
.dir() .set_bit()
});
self.start();
Transfer::r(buffer, self)
}
}
)+
}
}
serialdma! {
USART1: (
dma1::C5,
dma1::C4,
),
USART2: (
dma1::C6,
dma1::C7,
),
USART3: (
dma1::C3,
dma1::C2,
),
}