implement generics on serial
This commit is contained in:
parent
bd3deb785a
commit
9bcb0c36dc
2 changed files with 152 additions and 81 deletions
|
@ -14,6 +14,7 @@ use embassy::traits::uart::Uart;
|
||||||
use embassy::util::Forever;
|
use embassy::util::Forever;
|
||||||
use embassy_stm32f4::interrupt;
|
use embassy_stm32f4::interrupt;
|
||||||
use embassy_stm32f4::serial;
|
use embassy_stm32f4::serial;
|
||||||
|
use stm32f4xx_hal::dma::StreamsTuple;
|
||||||
use stm32f4xx_hal::prelude::*;
|
use stm32f4xx_hal::prelude::*;
|
||||||
use stm32f4xx_hal::serial::config::Config;
|
use stm32f4xx_hal::serial::config::Config;
|
||||||
use stm32f4xx_hal::stm32;
|
use stm32f4xx_hal::stm32;
|
||||||
|
@ -38,10 +39,12 @@ async fn run(dp: stm32::Peripherals, _cp: cortex_m::Peripherals) {
|
||||||
.pclk1(24.mhz())
|
.pclk1(24.mhz())
|
||||||
.freeze();
|
.freeze();
|
||||||
|
|
||||||
|
let streams = StreamsTuple::new(dp.DMA2);
|
||||||
|
|
||||||
let mut serial = unsafe {
|
let mut serial = unsafe {
|
||||||
serial::Serial::new(
|
serial::Serial::new(
|
||||||
dp.USART1,
|
dp.USART1,
|
||||||
dp.DMA2,
|
(streams.7, streams.2),
|
||||||
(
|
(
|
||||||
gpioa.pa9.into_alternate_af7(),
|
gpioa.pa9.into_alternate_af7(),
|
||||||
gpioa.pa10.into_alternate_af7(),
|
gpioa.pa10.into_alternate_af7(),
|
||||||
|
@ -53,6 +56,24 @@ async fn run(dp: stm32::Peripherals, _cp: cortex_m::Peripherals) {
|
||||||
clocks,
|
clocks,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let streams = StreamsTuple::new(dp.DMA1);
|
||||||
|
|
||||||
|
let mut serial = unsafe {
|
||||||
|
serial::Serial::new(
|
||||||
|
dp.USART2,
|
||||||
|
(streams.6, streams.5),
|
||||||
|
(
|
||||||
|
gpioa.pa2.into_alternate_af7(),
|
||||||
|
gpioa.pa3.into_alternate_af7(),
|
||||||
|
),
|
||||||
|
interrupt::take!(DMA1_STREAM6),
|
||||||
|
interrupt::take!(DMA1_STREAM5),
|
||||||
|
interrupt::take!(USART2),
|
||||||
|
Config::default().baudrate(9600.bps()),
|
||||||
|
clocks,
|
||||||
|
)
|
||||||
|
};
|
||||||
let buf = singleton!(: [u8; 30] = [0; 30]).unwrap();
|
let buf = singleton!(: [u8; 30] = [0; 30]).unwrap();
|
||||||
|
|
||||||
buf[5] = 0x01;
|
buf[5] = 0x01;
|
||||||
|
|
|
@ -8,129 +8,120 @@ use core::future::Future;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use core::sync::atomic::{self, Ordering};
|
use core::sync::atomic::{self, Ordering};
|
||||||
|
|
||||||
use embassy::interrupt::InterruptExt;
|
use embassy::interrupt::{Interrupt, InterruptExt};
|
||||||
use embassy::traits::uart::{Error, Uart};
|
use embassy::traits::uart::{Error, Uart};
|
||||||
use embassy::util::Signal;
|
use embassy::util::InterruptFuture;
|
||||||
|
|
||||||
|
use crate::hal::dma;
|
||||||
use crate::hal::dma::config::DmaConfig;
|
use crate::hal::dma::config::DmaConfig;
|
||||||
use crate::hal::dma::traits::{PeriAddress, Stream};
|
use crate::hal::dma::traits::{PeriAddress, Stream};
|
||||||
use crate::hal::dma::{Stream2, Stream7, StreamsTuple, Transfer};
|
use crate::hal::dma::{MemoryToPeripheral, PeripheralToMemory, Transfer};
|
||||||
use crate::hal::rcc::Clocks;
|
use crate::hal::rcc::Clocks;
|
||||||
|
use crate::hal::serial;
|
||||||
use crate::hal::serial::config::{Config as SerialConfig, DmaConfig as SerialDmaConfig};
|
use crate::hal::serial::config::{Config as SerialConfig, DmaConfig as SerialDmaConfig};
|
||||||
use crate::hal::serial::Pins;
|
use crate::hal::serial::Pins;
|
||||||
use crate::hal::serial::{Event as SerialEvent, Serial as HalSerial};
|
use crate::hal::serial::{Event as SerialEvent, Serial as HalSerial};
|
||||||
use crate::interrupt;
|
use crate::interrupt;
|
||||||
use crate::pac::{DMA2, USART1};
|
use crate::pac;
|
||||||
|
|
||||||
/// Interface to the Serial peripheral
|
/// Interface to the Serial peripheral
|
||||||
pub struct Serial<USART: PeriAddress<MemSize = u8>, TSTREAM: Stream, RSTREAM: Stream> {
|
pub struct Serial<
|
||||||
|
USART: PeriAddress<MemSize = u8>,
|
||||||
|
TSTREAM: Stream,
|
||||||
|
RSTREAM: Stream,
|
||||||
|
CHANNEL: dma::traits::Channel,
|
||||||
|
TINT: Interrupt,
|
||||||
|
RINT: Interrupt,
|
||||||
|
UINT: Interrupt,
|
||||||
|
> {
|
||||||
tx_stream: Option<TSTREAM>,
|
tx_stream: Option<TSTREAM>,
|
||||||
rx_stream: Option<RSTREAM>,
|
rx_stream: Option<RSTREAM>,
|
||||||
usart: Option<USART>,
|
usart: Option<USART>,
|
||||||
tx_int: interrupt::DMA2_STREAM7,
|
tx_int: TINT,
|
||||||
rx_int: interrupt::DMA2_STREAM2,
|
rx_int: RINT,
|
||||||
usart_int: interrupt::USART1,
|
usart_int: UINT,
|
||||||
|
channel: core::marker::PhantomData<CHANNEL>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct State {
|
// static mut INSTANCE: *const Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> = ptr::null_mut();
|
||||||
tx_int: Signal<()>,
|
|
||||||
rx_int: Signal<()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
static STATE: State = State {
|
impl<USART, TSTREAM, RSTREAM, CHANNEL, TINT, RINT, UINT>
|
||||||
tx_int: Signal::new(),
|
Serial<USART, TSTREAM, RSTREAM, CHANNEL, TINT, RINT, UINT>
|
||||||
rx_int: Signal::new(),
|
where
|
||||||
};
|
USART: serial::Instance
|
||||||
|
+ dma::traits::PeriAddress<MemSize = u8>
|
||||||
static mut INSTANCE: *const Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> = ptr::null_mut();
|
+ dma::traits::DMASet<TSTREAM, CHANNEL, MemoryToPeripheral>
|
||||||
|
+ dma::traits::DMASet<RSTREAM, CHANNEL, PeripheralToMemory>
|
||||||
impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
+ WithInterrupt<Instance = UINT>,
|
||||||
|
TSTREAM: Stream + WithInterrupt<Instance = TINT>,
|
||||||
|
RSTREAM: Stream + WithInterrupt<Instance = RINT>,
|
||||||
|
CHANNEL: dma::traits::Channel,
|
||||||
|
TINT: Interrupt,
|
||||||
|
RINT: Interrupt,
|
||||||
|
UINT: Interrupt,
|
||||||
|
{
|
||||||
// Leaking futures is forbidden!
|
// Leaking futures is forbidden!
|
||||||
pub unsafe fn new<PINS>(
|
pub unsafe fn new<PINS>(
|
||||||
usart: USART1,
|
usart: USART,
|
||||||
dma: DMA2,
|
streams: (TSTREAM, RSTREAM),
|
||||||
pins: PINS,
|
pins: PINS,
|
||||||
tx_int: interrupt::DMA2_STREAM7,
|
tx_int: TINT,
|
||||||
rx_int: interrupt::DMA2_STREAM2,
|
rx_int: RINT,
|
||||||
usart_int: interrupt::USART1,
|
usart_int: UINT,
|
||||||
mut config: SerialConfig,
|
mut config: SerialConfig,
|
||||||
clocks: Clocks,
|
clocks: Clocks,
|
||||||
) -> Self
|
) -> Self
|
||||||
where
|
where
|
||||||
PINS: Pins<USART1>,
|
PINS: Pins<USART>,
|
||||||
{
|
{
|
||||||
config.dma = SerialDmaConfig::TxRx;
|
config.dma = SerialDmaConfig::TxRx;
|
||||||
let mut serial = HalSerial::usart1(usart, pins, config, clocks).unwrap();
|
let mut serial = HalSerial::new(usart, pins, config, clocks).unwrap();
|
||||||
|
|
||||||
serial.listen(SerialEvent::Idle);
|
serial.listen(SerialEvent::Idle);
|
||||||
// serial.listen(SerialEvent::Txe);
|
// serial.listen(SerialEvent::Txe);
|
||||||
|
|
||||||
let (usart, _) = serial.release();
|
let (usart, _) = serial.release();
|
||||||
|
|
||||||
// Register ISR
|
let (tx_stream, rx_stream) = streams;
|
||||||
tx_int.set_handler(Self::on_tx_irq);
|
|
||||||
rx_int.set_handler(Self::on_rx_irq);
|
|
||||||
usart_int.set_handler(Self::on_rx_irq);
|
|
||||||
// usart_int.unpend();
|
|
||||||
// usart_int.enable();
|
|
||||||
|
|
||||||
let streams = StreamsTuple::new(dma);
|
|
||||||
|
|
||||||
Serial {
|
Serial {
|
||||||
tx_stream: Some(streams.7),
|
tx_stream: Some(tx_stream),
|
||||||
rx_stream: Some(streams.2),
|
rx_stream: Some(rx_stream),
|
||||||
usart: Some(usart),
|
usart: Some(usart),
|
||||||
tx_int: tx_int,
|
tx_int: tx_int,
|
||||||
rx_int: rx_int,
|
rx_int: rx_int,
|
||||||
usart_int: usart_int,
|
usart_int: usart_int,
|
||||||
|
channel: core::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn on_tx_irq(_ctx: *mut ()) {
|
|
||||||
let s = &(*INSTANCE);
|
|
||||||
|
|
||||||
s.tx_int.disable();
|
|
||||||
|
|
||||||
STATE.tx_int.signal(());
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn on_rx_irq(_ctx: *mut ()) {
|
|
||||||
let s = &(*INSTANCE);
|
|
||||||
|
|
||||||
atomic::compiler_fence(Ordering::Acquire);
|
|
||||||
s.rx_int.disable();
|
|
||||||
s.usart_int.disable();
|
|
||||||
atomic::compiler_fence(Ordering::Release);
|
|
||||||
|
|
||||||
STATE.rx_int.signal(());
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn on_usart_irq(_ctx: *mut ()) {
|
|
||||||
let s = &(*INSTANCE);
|
|
||||||
|
|
||||||
atomic::compiler_fence(Ordering::Acquire);
|
|
||||||
s.rx_int.disable();
|
|
||||||
s.usart_int.disable();
|
|
||||||
atomic::compiler_fence(Ordering::Release);
|
|
||||||
|
|
||||||
STATE.rx_int.signal(());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Uart for Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
impl<USART, TSTREAM, RSTREAM, CHANNEL, TINT, RINT, UINT> Uart
|
||||||
|
for Serial<USART, TSTREAM, RSTREAM, CHANNEL, TINT, RINT, UINT>
|
||||||
|
where
|
||||||
|
USART: serial::Instance
|
||||||
|
+ dma::traits::PeriAddress<MemSize = u8>
|
||||||
|
+ dma::traits::DMASet<TSTREAM, CHANNEL, MemoryToPeripheral>
|
||||||
|
+ dma::traits::DMASet<RSTREAM, CHANNEL, PeripheralToMemory>
|
||||||
|
+ WithInterrupt<Instance = UINT>
|
||||||
|
+ 'static,
|
||||||
|
TSTREAM: Stream + WithInterrupt<Instance = TINT> + 'static,
|
||||||
|
RSTREAM: Stream + WithInterrupt<Instance = RINT> + 'static,
|
||||||
|
CHANNEL: dma::traits::Channel + 'static,
|
||||||
|
TINT: Interrupt + 'static,
|
||||||
|
RINT: Interrupt + 'static,
|
||||||
|
UINT: Interrupt + 'static,
|
||||||
|
{
|
||||||
type SendFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
|
type SendFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
|
||||||
type ReceiveFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
|
type ReceiveFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
|
||||||
|
|
||||||
/// Sends serial data.
|
/// Sends serial data.
|
||||||
fn send<'a>(&'a mut self, buf: &'a [u8]) -> Self::SendFuture<'a> {
|
fn send<'a>(&'a mut self, buf: &'a [u8]) -> Self::SendFuture<'a> {
|
||||||
unsafe { INSTANCE = self };
|
|
||||||
|
|
||||||
#[allow(mutable_transmutes)]
|
#[allow(mutable_transmutes)]
|
||||||
let static_buf = unsafe { core::mem::transmute::<&'a [u8], &'static mut [u8]>(buf) };
|
let static_buf = unsafe { core::mem::transmute::<&'a [u8], &'static mut [u8]>(buf) };
|
||||||
|
|
||||||
let tx_stream = self.tx_stream.take().unwrap();
|
let tx_stream = self.tx_stream.take().unwrap();
|
||||||
let usart = self.usart.take().unwrap();
|
let usart = self.usart.take().unwrap();
|
||||||
STATE.tx_int.reset();
|
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
let mut tx_transfer = Transfer::init(
|
let mut tx_transfer = Transfer::init(
|
||||||
|
@ -144,11 +135,11 @@ impl Uart for Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
||||||
.double_buffer(false),
|
.double_buffer(false),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.tx_int.unpend();
|
let fut = InterruptFuture::new(&mut self.tx_int);
|
||||||
self.tx_int.enable();
|
|
||||||
tx_transfer.start(|_usart| {});
|
tx_transfer.start(|_usart| {});
|
||||||
|
|
||||||
STATE.tx_int.wait().await;
|
fut.await;
|
||||||
|
|
||||||
let (tx_stream, usart, _buf, _) = tx_transfer.free();
|
let (tx_stream, usart, _buf, _) = tx_transfer.free();
|
||||||
self.tx_stream.replace(tx_stream);
|
self.tx_stream.replace(tx_stream);
|
||||||
|
@ -165,12 +156,11 @@ impl Uart for Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
||||||
/// unfinished transfers after a timeout to prevent lockup when no more data
|
/// unfinished transfers after a timeout to prevent lockup when no more data
|
||||||
/// is incoming.
|
/// is incoming.
|
||||||
fn receive<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a> {
|
fn receive<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReceiveFuture<'a> {
|
||||||
unsafe { INSTANCE = self };
|
|
||||||
|
|
||||||
let static_buf = unsafe { core::mem::transmute::<&'a mut [u8], &'static mut [u8]>(buf) };
|
let static_buf = unsafe { core::mem::transmute::<&'a mut [u8], &'static mut [u8]>(buf) };
|
||||||
|
|
||||||
let rx_stream = self.rx_stream.take().unwrap();
|
let rx_stream = self.rx_stream.take().unwrap();
|
||||||
let usart = self.usart.take().unwrap();
|
let usart = self.usart.take().unwrap();
|
||||||
STATE.rx_int.reset();
|
|
||||||
async move {
|
async move {
|
||||||
let mut rx_transfer = Transfer::init(
|
let mut rx_transfer = Transfer::init(
|
||||||
rx_stream,
|
rx_stream,
|
||||||
|
@ -182,14 +172,74 @@ impl Uart for Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
||||||
.memory_increment(true)
|
.memory_increment(true)
|
||||||
.double_buffer(false),
|
.double_buffer(false),
|
||||||
);
|
);
|
||||||
self.rx_int.unpend();
|
|
||||||
self.rx_int.enable();
|
let fut = InterruptFuture::new(&mut self.rx_int);
|
||||||
|
|
||||||
rx_transfer.start(|_usart| {});
|
rx_transfer.start(|_usart| {});
|
||||||
STATE.rx_int.wait().await;
|
fut.await;
|
||||||
|
|
||||||
let (rx_stream, usart, _, _) = rx_transfer.free();
|
let (rx_stream, usart, _, _) = rx_transfer.free();
|
||||||
self.rx_stream.replace(rx_stream);
|
self.rx_stream.replace(rx_stream);
|
||||||
self.usart.replace(usart);
|
self.usart.replace(usart);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod private {
|
||||||
|
pub trait Sealed {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait WithInterrupt: private::Sealed {
|
||||||
|
type Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! dma {
|
||||||
|
($($PER:ident => ($dma:ident, $stream:ident),)+) => {
|
||||||
|
$(
|
||||||
|
impl private::Sealed for dma::$stream<pac::$dma> {}
|
||||||
|
impl WithInterrupt for dma::$stream<pac::$dma> {
|
||||||
|
type Instance = interrupt::$PER;
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! usart {
|
||||||
|
($($PER:ident => ($usart:ident),)+) => {
|
||||||
|
$(
|
||||||
|
impl private::Sealed for pac::$usart {}
|
||||||
|
impl WithInterrupt for pac::$usart {
|
||||||
|
type Instance = interrupt::$PER;
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
|
||||||
|
usart! {
|
||||||
|
USART1 => (USART1),
|
||||||
|
USART2 => (USART2),
|
||||||
|
USART3 => (USART3),
|
||||||
|
UART4 => (UART4),
|
||||||
|
UART5 => (UART5),
|
||||||
|
USART6 => (USART6),
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue