2020-12-31 23:40:51 +01:00
|
|
|
//! Async low power Serial.
|
2020-12-28 16:17:36 +01:00
|
|
|
//!
|
2020-12-29 03:48:26 +01:00
|
|
|
//! The peripheral is autmatically enabled and disabled as required to save power.
|
|
|
|
//! Lowest power consumption can only be guaranteed if the send receive futures
|
|
|
|
//! are dropped correctly (e.g. not using `mem::forget()`).
|
|
|
|
|
|
|
|
use core::future::Future;
|
2021-03-06 06:04:20 +01:00
|
|
|
use core::marker::PhantomData;
|
2021-01-04 19:48:13 +01:00
|
|
|
use core::ptr;
|
|
|
|
use core::sync::atomic::{self, Ordering};
|
2020-12-28 16:17:36 +01:00
|
|
|
|
2021-03-05 00:20:35 +01:00
|
|
|
use embassy::interrupt::{Interrupt, InterruptExt};
|
2021-03-02 00:32:23 +01:00
|
|
|
use embassy::traits::uart::{Error, Uart};
|
2021-03-05 00:20:35 +01:00
|
|
|
use embassy::util::InterruptFuture;
|
2020-12-29 03:48:26 +01:00
|
|
|
|
2021-03-06 06:04:20 +01:00
|
|
|
use crate::hal::{
|
|
|
|
dma,
|
|
|
|
dma::config::DmaConfig,
|
|
|
|
dma::traits::{Channel, DMASet, PeriAddress, Stream},
|
|
|
|
dma::{MemoryToPeripheral, PeripheralToMemory, Transfer},
|
|
|
|
rcc::Clocks,
|
|
|
|
serial,
|
|
|
|
serial::config::{Config as SerialConfig, DmaConfig as SerialDmaConfig},
|
|
|
|
serial::{Event as SerialEvent, Pins, Serial as HalSerial},
|
|
|
|
};
|
2020-12-28 16:17:36 +01:00
|
|
|
use crate::interrupt;
|
2021-03-05 00:20:35 +01:00
|
|
|
use crate::pac;
|
2020-12-28 23:43:29 +01:00
|
|
|
|
2020-12-31 23:40:51 +01:00
|
|
|
/// Interface to the Serial peripheral
|
2021-03-05 00:20:35 +01:00
|
|
|
pub struct Serial<
|
2021-03-06 05:59:54 +01:00
|
|
|
USART: PeriAddress<MemSize = u8> + WithInterrupt,
|
|
|
|
TSTREAM: Stream + WithInterrupt,
|
|
|
|
RSTREAM: Stream + WithInterrupt,
|
2021-03-05 00:20:35 +01:00
|
|
|
CHANNEL: dma::traits::Channel,
|
|
|
|
> {
|
2020-12-31 23:38:31 +01:00
|
|
|
tx_stream: Option<TSTREAM>,
|
|
|
|
rx_stream: Option<RSTREAM>,
|
|
|
|
usart: Option<USART>,
|
2021-03-06 05:59:54 +01:00
|
|
|
tx_int: TSTREAM::Interrupt,
|
|
|
|
rx_int: RSTREAM::Interrupt,
|
|
|
|
usart_int: USART::Interrupt,
|
2021-03-06 06:04:20 +01:00
|
|
|
channel: PhantomData<CHANNEL>,
|
2020-12-28 16:17:36 +01:00
|
|
|
}
|
|
|
|
|
2021-03-05 00:20:35 +01:00
|
|
|
// static mut INSTANCE: *const Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> = ptr::null_mut();
|
|
|
|
|
2021-03-06 05:59:54 +01:00
|
|
|
impl<USART, TSTREAM, RSTREAM, CHANNEL> Serial<USART, TSTREAM, RSTREAM, CHANNEL>
|
2021-03-05 00:20:35 +01:00
|
|
|
where
|
|
|
|
USART: serial::Instance
|
2021-03-06 06:04:20 +01:00
|
|
|
+ PeriAddress<MemSize = u8>
|
|
|
|
+ DMASet<TSTREAM, CHANNEL, MemoryToPeripheral>
|
|
|
|
+ DMASet<RSTREAM, CHANNEL, PeripheralToMemory>
|
2021-03-06 05:59:54 +01:00
|
|
|
+ WithInterrupt,
|
|
|
|
TSTREAM: Stream + WithInterrupt,
|
|
|
|
RSTREAM: Stream + WithInterrupt,
|
2021-03-06 06:04:20 +01:00
|
|
|
CHANNEL: Channel,
|
2021-03-05 00:20:35 +01:00
|
|
|
{
|
2021-01-06 21:31:43 +01:00
|
|
|
// Leaking futures is forbidden!
|
2021-01-14 18:42:23 +01:00
|
|
|
pub unsafe fn new<PINS>(
|
2021-03-05 00:20:35 +01:00
|
|
|
usart: USART,
|
|
|
|
streams: (TSTREAM, RSTREAM),
|
2021-01-14 18:42:23 +01:00
|
|
|
pins: PINS,
|
2021-03-06 05:59:54 +01:00
|
|
|
tx_int: TSTREAM::Interrupt,
|
|
|
|
rx_int: RSTREAM::Interrupt,
|
|
|
|
usart_int: USART::Interrupt,
|
2021-01-14 18:42:23 +01:00
|
|
|
mut config: SerialConfig,
|
2020-12-30 05:57:00 +01:00
|
|
|
clocks: Clocks,
|
2021-01-14 18:42:23 +01:00
|
|
|
) -> Self
|
|
|
|
where
|
2021-03-05 00:20:35 +01:00
|
|
|
PINS: Pins<USART>,
|
2021-01-14 18:42:23 +01:00
|
|
|
{
|
|
|
|
config.dma = SerialDmaConfig::TxRx;
|
2021-03-05 00:20:35 +01:00
|
|
|
let mut serial = HalSerial::new(usart, pins, config, clocks).unwrap();
|
2020-12-28 16:17:36 +01:00
|
|
|
|
2021-01-01 21:59:57 +01:00
|
|
|
serial.listen(SerialEvent::Idle);
|
2021-01-04 19:48:13 +01:00
|
|
|
// serial.listen(SerialEvent::Txe);
|
2020-12-30 05:57:00 +01:00
|
|
|
|
2021-01-01 21:59:57 +01:00
|
|
|
let (usart, _) = serial.release();
|
2020-12-30 05:57:00 +01:00
|
|
|
|
2021-03-05 00:20:35 +01:00
|
|
|
let (tx_stream, rx_stream) = streams;
|
2020-12-28 16:17:36 +01:00
|
|
|
|
2020-12-31 23:40:51 +01:00
|
|
|
Serial {
|
2021-03-05 00:20:35 +01:00
|
|
|
tx_stream: Some(tx_stream),
|
|
|
|
rx_stream: Some(rx_stream),
|
2020-12-30 05:57:00 +01:00
|
|
|
usart: Some(usart),
|
2021-01-04 19:48:13 +01:00
|
|
|
tx_int: tx_int,
|
|
|
|
rx_int: rx_int,
|
|
|
|
usart_int: usart_int,
|
2021-03-05 00:20:35 +01:00
|
|
|
channel: core::marker::PhantomData,
|
2020-12-29 19:33:50 +01:00
|
|
|
}
|
2020-12-28 16:17:36 +01:00
|
|
|
}
|
2021-01-06 19:12:29 +01:00
|
|
|
}
|
2021-01-04 19:48:13 +01:00
|
|
|
|
2021-03-06 05:59:54 +01:00
|
|
|
impl<USART, TSTREAM, RSTREAM, CHANNEL> Uart for Serial<USART, TSTREAM, RSTREAM, CHANNEL>
|
2021-03-05 00:20:35 +01:00
|
|
|
where
|
|
|
|
USART: serial::Instance
|
2021-03-06 06:04:20 +01:00
|
|
|
+ PeriAddress<MemSize = u8>
|
|
|
|
+ DMASet<TSTREAM, CHANNEL, MemoryToPeripheral>
|
|
|
|
+ DMASet<RSTREAM, CHANNEL, PeripheralToMemory>
|
2021-03-06 05:59:54 +01:00
|
|
|
+ WithInterrupt
|
2021-03-05 00:20:35 +01:00
|
|
|
+ 'static,
|
2021-03-06 05:59:54 +01:00
|
|
|
TSTREAM: Stream + WithInterrupt + 'static,
|
|
|
|
RSTREAM: Stream + WithInterrupt + 'static,
|
2021-03-06 06:04:20 +01:00
|
|
|
CHANNEL: Channel + 'static,
|
2021-03-05 00:20:35 +01:00
|
|
|
{
|
2021-01-06 21:12:33 +01:00
|
|
|
type SendFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
|
|
|
|
type ReceiveFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
|
|
|
|
|
2020-12-29 03:48:26 +01:00
|
|
|
/// Sends serial data.
|
2021-01-06 21:12:33 +01:00
|
|
|
fn send<'a>(&'a mut self, buf: &'a [u8]) -> Self::SendFuture<'a> {
|
2021-01-14 00:40:32 +01:00
|
|
|
#[allow(mutable_transmutes)]
|
2021-01-07 04:02:02 +01:00
|
|
|
let static_buf = unsafe { core::mem::transmute::<&'a [u8], &'static mut [u8]>(buf) };
|
|
|
|
|
|
|
|
let tx_stream = self.tx_stream.take().unwrap();
|
|
|
|
let usart = self.usart.take().unwrap();
|
|
|
|
|
|
|
|
async move {
|
|
|
|
let mut tx_transfer = Transfer::init(
|
|
|
|
tx_stream,
|
|
|
|
usart,
|
|
|
|
static_buf,
|
|
|
|
None,
|
|
|
|
DmaConfig::default()
|
|
|
|
.transfer_complete_interrupt(true)
|
|
|
|
.memory_increment(true)
|
|
|
|
.double_buffer(false),
|
|
|
|
);
|
|
|
|
|
2021-03-05 00:20:35 +01:00
|
|
|
let fut = InterruptFuture::new(&mut self.tx_int);
|
|
|
|
|
2021-01-07 04:02:02 +01:00
|
|
|
tx_transfer.start(|_usart| {});
|
|
|
|
|
2021-03-05 00:20:35 +01:00
|
|
|
fut.await;
|
2021-01-07 04:02:02 +01:00
|
|
|
|
|
|
|
let (tx_stream, usart, _buf, _) = tx_transfer.free();
|
|
|
|
self.tx_stream.replace(tx_stream);
|
|
|
|
self.usart.replace(usart);
|
|
|
|
|
|
|
|
Ok(())
|
2020-12-29 03:48:26 +01:00
|
|
|
}
|
2020-12-28 16:17:36 +01:00
|
|
|
}
|
|
|
|
|
2020-12-29 03:48:26 +01:00
|
|
|
/// Receives serial data.
|
|
|
|
///
|
|
|
|
/// The future is pending until the buffer is completely filled.
|
|
|
|
/// A common pattern is to use [`stop()`](ReceiveFuture::stop) to cancel
|
|
|
|
/// unfinished transfers after a timeout to prevent lockup when no more data
|
|
|
|
/// is incoming.
|
2021-01-06 21:12:33 +01:00
|
|
|
fn receive<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a> {
|
2021-01-07 04:02:02 +01:00
|
|
|
let static_buf = unsafe { core::mem::transmute::<&'a mut [u8], &'static mut [u8]>(buf) };
|
2021-03-05 00:20:35 +01:00
|
|
|
|
2021-01-07 04:02:02 +01:00
|
|
|
let rx_stream = self.rx_stream.take().unwrap();
|
|
|
|
let usart = self.usart.take().unwrap();
|
2021-03-05 00:20:35 +01:00
|
|
|
|
2021-01-07 04:02:02 +01:00
|
|
|
async move {
|
|
|
|
let mut rx_transfer = Transfer::init(
|
|
|
|
rx_stream,
|
|
|
|
usart,
|
|
|
|
static_buf,
|
|
|
|
None,
|
|
|
|
DmaConfig::default()
|
|
|
|
.transfer_complete_interrupt(true)
|
|
|
|
.memory_increment(true)
|
|
|
|
.double_buffer(false),
|
|
|
|
);
|
2021-03-05 00:20:35 +01:00
|
|
|
|
|
|
|
let fut = InterruptFuture::new(&mut self.rx_int);
|
|
|
|
|
2021-01-07 04:02:02 +01:00
|
|
|
rx_transfer.start(|_usart| {});
|
2021-03-05 00:20:35 +01:00
|
|
|
fut.await;
|
|
|
|
|
2021-01-07 04:02:02 +01:00
|
|
|
let (rx_stream, usart, _, _) = rx_transfer.free();
|
|
|
|
self.rx_stream.replace(rx_stream);
|
|
|
|
self.usart.replace(usart);
|
2021-03-05 00:20:35 +01:00
|
|
|
|
2021-01-07 04:02:02 +01:00
|
|
|
Ok(())
|
2020-12-30 18:05:52 +01:00
|
|
|
}
|
2020-12-28 16:17:36 +01:00
|
|
|
}
|
|
|
|
}
|
2021-03-05 00:20:35 +01:00
|
|
|
|
|
|
|
mod private {
|
|
|
|
pub trait Sealed {}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait WithInterrupt: private::Sealed {
|
2021-03-06 05:59:54 +01:00
|
|
|
type Interrupt: Interrupt;
|
2021-03-05 00:20:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! dma {
|
|
|
|
($($PER:ident => ($dma:ident, $stream:ident),)+) => {
|
|
|
|
$(
|
|
|
|
impl private::Sealed for dma::$stream<pac::$dma> {}
|
|
|
|
impl WithInterrupt for dma::$stream<pac::$dma> {
|
2021-03-06 05:59:54 +01:00
|
|
|
type Interrupt = interrupt::$PER;
|
2021-03-05 00:20:35 +01:00
|
|
|
}
|
|
|
|
)+
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! usart {
|
|
|
|
($($PER:ident => ($usart:ident),)+) => {
|
|
|
|
$(
|
|
|
|
impl private::Sealed for pac::$usart {}
|
|
|
|
impl WithInterrupt for pac::$usart {
|
2021-03-06 05:59:54 +01:00
|
|
|
type Interrupt = interrupt::$PER;
|
2021-03-05 00:20:35 +01:00
|
|
|
}
|
|
|
|
)+
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-05 00:27:46 +01:00
|
|
|
#[cfg(any(feature = "stm32f405",))]
|
2021-03-05 00:20:35 +01:00
|
|
|
dma! {
|
|
|
|
DMA2_STREAM0 => (DMA2, Stream0),
|
|
|
|
DMA2_STREAM1 => (DMA2, Stream1),
|
|
|
|
DMA2_STREAM2 => (DMA2, Stream2),
|
|
|
|
DMA2_STREAM3 => (DMA2, Stream3),
|
|
|
|
DMA2_STREAM4 => (DMA2, Stream4),
|
|
|
|
DMA2_STREAM5 => (DMA2, Stream5),
|
|
|
|
DMA2_STREAM6 => (DMA2, Stream6),
|
|
|
|
DMA2_STREAM7 => (DMA2, Stream7),
|
|
|
|
DMA1_STREAM0 => (DMA1, Stream0),
|
|
|
|
DMA1_STREAM1 => (DMA1, Stream1),
|
|
|
|
DMA1_STREAM2 => (DMA1, Stream2),
|
|
|
|
DMA1_STREAM3 => (DMA1, Stream3),
|
|
|
|
DMA1_STREAM4 => (DMA1, Stream4),
|
|
|
|
DMA1_STREAM5 => (DMA1, Stream5),
|
|
|
|
DMA1_STREAM6 => (DMA1, Stream6),
|
|
|
|
}
|
|
|
|
|
2021-03-05 00:27:46 +01:00
|
|
|
#[cfg(any(feature = "stm32f405",))]
|
2021-03-05 00:20:35 +01:00
|
|
|
usart! {
|
|
|
|
USART1 => (USART1),
|
|
|
|
USART2 => (USART2),
|
|
|
|
USART3 => (USART3),
|
|
|
|
UART4 => (UART4),
|
|
|
|
UART5 => (UART5),
|
|
|
|
USART6 => (USART6),
|
|
|
|
}
|