simplify impl. and add interupt idea
This commit is contained in:
parent
d5cb9bebaa
commit
2ee2d18465
@ -43,11 +43,13 @@ pub struct Serial<USART: PeriAddress<MemSize = u8>, TSTREAM: Stream, RSTREAM: St
|
|||||||
struct State {
|
struct State {
|
||||||
tx_done: Signal<()>,
|
tx_done: Signal<()>,
|
||||||
rx_done: Signal<()>,
|
rx_done: Signal<()>,
|
||||||
|
dma_done: Signal<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
static STATE: State = State {
|
static STATE: State = State {
|
||||||
tx_done: Signal::new(),
|
tx_done: Signal::new(),
|
||||||
rx_done: Signal::new(),
|
rx_done: Signal::new(),
|
||||||
|
dma_done: Signal::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
||||||
@ -56,13 +58,14 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
|||||||
rxd: PA10<Alternate<AF7>>,
|
rxd: PA10<Alternate<AF7>>,
|
||||||
tx_int: interrupt::DMA2_STREAM2Interrupt,
|
tx_int: interrupt::DMA2_STREAM2Interrupt,
|
||||||
rx_int: interrupt::DMA2_STREAM7Interrupt,
|
rx_int: interrupt::DMA2_STREAM7Interrupt,
|
||||||
|
usart_int: interrupt::USART1Interrupt,
|
||||||
dma: DMA2,
|
dma: DMA2,
|
||||||
usart: USART1,
|
usart: USART1,
|
||||||
parity: Parity,
|
parity: Parity,
|
||||||
baudrate: Bps,
|
baudrate: Bps,
|
||||||
clocks: Clocks,
|
clocks: Clocks,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let serial = HalSerial::usart1(
|
let mut serial = HalSerial::usart1(
|
||||||
usart,
|
usart,
|
||||||
(txd, rxd),
|
(txd, rxd),
|
||||||
SerialConfig {
|
SerialConfig {
|
||||||
@ -76,9 +79,10 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let (usart, _) = serial.release();
|
serial.listen(SerialEvent::Idle);
|
||||||
|
serial.listen(SerialEvent::Txe);
|
||||||
|
|
||||||
// serial.listen(SerialEvent::Idle);
|
let (usart, _) = serial.release();
|
||||||
|
|
||||||
// Register ISR
|
// Register ISR
|
||||||
tx_int.set_handler(Self::on_tx_irq);
|
tx_int.set_handler(Self::on_tx_irq);
|
||||||
@ -89,6 +93,10 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
|||||||
rx_int.unpend();
|
rx_int.unpend();
|
||||||
rx_int.enable();
|
rx_int.enable();
|
||||||
|
|
||||||
|
// usart_int.set_handler(Self::on_usart_irq);
|
||||||
|
// usart_int.unpend();
|
||||||
|
// usart_int.enable();
|
||||||
|
|
||||||
let streams = StreamsTuple::new(dma);
|
let streams = StreamsTuple::new(dma);
|
||||||
|
|
||||||
Serial {
|
Serial {
|
||||||
@ -105,38 +113,50 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
|||||||
unsafe fn on_rx_irq() {
|
unsafe fn on_rx_irq() {
|
||||||
STATE.rx_done.signal(());
|
STATE.rx_done.signal(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn on_usart_irq() {
|
||||||
|
/*
|
||||||
|
TODO: Signal tx_done if txe
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO: Signal rx_done if idle
|
||||||
|
*/
|
||||||
|
|
||||||
|
// STATE.rx_done.signal(());
|
||||||
|
}
|
||||||
/// Sends serial data.
|
/// Sends serial data.
|
||||||
///
|
///
|
||||||
/// `tx_buffer` is marked as static as per `embedded-dma` requirements.
|
/// `tx_buffer` is marked as static as per `embedded-dma` requirements.
|
||||||
/// It it safe to use a buffer with a non static lifetime if memory is not
|
/// It it safe to use a buffer with a non static lifetime if memory is not
|
||||||
/// reused until the future has finished.
|
/// reused until the future has finished.
|
||||||
pub fn send<'a, B>(
|
pub fn send<'a, B>(&'a mut self, tx_buffer: B) -> impl Future<Output = ()> + 'a
|
||||||
&'a mut self,
|
|
||||||
tx_buffer: B,
|
|
||||||
) -> SendFuture<'a, B, USART1, Stream7<DMA2>, Stream2<DMA2>, Channel4>
|
|
||||||
where
|
where
|
||||||
B: WriteBuffer<Word = u8> + 'static,
|
B: WriteBuffer<Word = u8> + 'static,
|
||||||
{
|
{
|
||||||
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();
|
||||||
let mut tx_transfer = Transfer::init(
|
|
||||||
tx_stream,
|
|
||||||
usart,
|
|
||||||
tx_buffer,
|
|
||||||
None,
|
|
||||||
DmaConfig::default()
|
|
||||||
.transfer_complete_interrupt(true)
|
|
||||||
.memory_increment(true)
|
|
||||||
.double_buffer(false),
|
|
||||||
);
|
|
||||||
|
|
||||||
STATE.tx_done.reset();
|
STATE.tx_done.reset();
|
||||||
|
|
||||||
SendFuture {
|
async move {
|
||||||
Serial: self,
|
let mut tx_transfer = Transfer::init(
|
||||||
tx_transfer: Some(tx_transfer),
|
tx_stream,
|
||||||
// tx_stream: Some(tx_stream),
|
usart,
|
||||||
// usart: Some(usart),
|
tx_buffer,
|
||||||
|
None,
|
||||||
|
DmaConfig::default()
|
||||||
|
.transfer_complete_interrupt(true)
|
||||||
|
.memory_increment(true)
|
||||||
|
.double_buffer(false),
|
||||||
|
);
|
||||||
|
|
||||||
|
tx_transfer.start(|_usart| {});
|
||||||
|
|
||||||
|
STATE.tx_done.wait().await;
|
||||||
|
|
||||||
|
let (tx_stream, usart, _buf, _) = tx_transfer.free();
|
||||||
|
self.tx_stream.replace(tx_stream);
|
||||||
|
self.usart.replace(usart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,140 +170,35 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
|||||||
/// `rx_buffer` is marked as static as per `embedded-dma` requirements.
|
/// `rx_buffer` is marked as static as per `embedded-dma` requirements.
|
||||||
/// It it safe to use a buffer with a non static lifetime if memory is not
|
/// It it safe to use a buffer with a non static lifetime if memory is not
|
||||||
/// reused until the future has finished.
|
/// reused until the future has finished.
|
||||||
pub fn receive<'a, B>(
|
pub fn receive<'a, B>(&'a mut self, rx_buffer: B) -> impl Future<Output = B> + 'a
|
||||||
&'a mut self,
|
|
||||||
rx_buffer: B,
|
|
||||||
) -> ReceiveFuture<'a, B, USART1, Stream7<DMA2>, Stream2<DMA2>, Channel4>
|
|
||||||
where
|
where
|
||||||
B: WriteBuffer<Word = u8> + 'static,
|
B: WriteBuffer<Word = u8> + 'static + Unpin,
|
||||||
{
|
{
|
||||||
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();
|
||||||
let mut rx_transfer = Transfer::init(
|
|
||||||
rx_stream,
|
|
||||||
usart,
|
|
||||||
rx_buffer,
|
|
||||||
None,
|
|
||||||
DmaConfig::default()
|
|
||||||
.transfer_complete_interrupt(true)
|
|
||||||
.half_transfer_interrupt(true)
|
|
||||||
.memory_increment(true)
|
|
||||||
.double_buffer(false),
|
|
||||||
);
|
|
||||||
|
|
||||||
STATE.rx_done.reset();
|
STATE.rx_done.reset();
|
||||||
|
|
||||||
ReceiveFuture {
|
async move {
|
||||||
Serial: self,
|
let mut rx_transfer = Transfer::init(
|
||||||
rx_transfer: Some(rx_transfer),
|
rx_stream,
|
||||||
}
|
usart,
|
||||||
}
|
rx_buffer,
|
||||||
}
|
None,
|
||||||
|
DmaConfig::default()
|
||||||
/// Future for the [`LowPowerSerial::send()`] method.
|
.transfer_complete_interrupt(true)
|
||||||
pub struct SendFuture<
|
.memory_increment(true)
|
||||||
'a,
|
.double_buffer(false),
|
||||||
B: WriteBuffer<Word = u8> + 'static,
|
);
|
||||||
USART: PeriAddress<MemSize = u8>,
|
|
||||||
TSTREAM: Stream,
|
rx_transfer.start(|_usart| {});
|
||||||
RSTREAM: Stream,
|
|
||||||
CHANNEL,
|
STATE.rx_done.wait().await;
|
||||||
> {
|
|
||||||
Serial: &'a mut Serial<USART, TSTREAM, RSTREAM>,
|
let (rx_stream, usart, buf, _) = rx_transfer.free();
|
||||||
tx_transfer: Option<Transfer<TSTREAM, CHANNEL, USART, MemoryToPeripheral, B>>,
|
self.rx_stream.replace(rx_stream);
|
||||||
}
|
self.usart.replace(usart);
|
||||||
|
|
||||||
// impl<'a, B> Drop for SendFuture<'a, B>
|
buf
|
||||||
// where
|
|
||||||
// B: WriteBuffer<Word = u8> + 'static,
|
|
||||||
// {
|
|
||||||
// fn drop(self: &mut Self) {}
|
|
||||||
// }
|
|
||||||
|
|
||||||
impl<'a, B> Future for SendFuture<'a, B, USART1, Stream7<DMA2>, Stream2<DMA2>, Channel4>
|
|
||||||
where
|
|
||||||
B: WriteBuffer<Word = u8> + 'static,
|
|
||||||
{
|
|
||||||
type Output = ();
|
|
||||||
|
|
||||||
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
|
|
||||||
let Self {
|
|
||||||
Serial,
|
|
||||||
tx_transfer,
|
|
||||||
} = unsafe { self.get_unchecked_mut() };
|
|
||||||
let mut taken = tx_transfer.take().unwrap();
|
|
||||||
if Stream7::<DMA2>::get_transfer_complete_flag() {
|
|
||||||
let (tx_stream, usart, buf, _) = taken.free();
|
|
||||||
|
|
||||||
Serial.tx_stream.replace(tx_stream);
|
|
||||||
Serial.usart.replace(usart);
|
|
||||||
|
|
||||||
Poll::Ready(())
|
|
||||||
} else {
|
|
||||||
// waker_interrupt!(DMA2_STREAM7, cx.waker().clone());
|
|
||||||
taken.start(|_usart| {});
|
|
||||||
tx_transfer.replace(taken);
|
|
||||||
|
|
||||||
// Poll::Pending
|
|
||||||
STATE.tx_done.poll_wait(cx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Future for the [`Serial::receive()`] method.
|
|
||||||
pub struct ReceiveFuture<
|
|
||||||
'a,
|
|
||||||
B: WriteBuffer<Word = u8> + 'static,
|
|
||||||
USART: PeriAddress<MemSize = u8>,
|
|
||||||
TSTREAM: Stream,
|
|
||||||
RSTREAM: Stream,
|
|
||||||
CHANNEL,
|
|
||||||
> {
|
|
||||||
Serial: &'a mut Serial<USART, TSTREAM, RSTREAM>,
|
|
||||||
rx_transfer: Option<Transfer<RSTREAM, CHANNEL, USART, PeripheralToMemory, B>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// impl<'a, B> Drop for ReceiveFuture<'a, B, USART1, Stream7<DMA2>, Channel4>
|
|
||||||
// where
|
|
||||||
// B: WriteBuffer<Word = u8> + 'static,
|
|
||||||
// {
|
|
||||||
// fn drop(self: &mut Self) {}
|
|
||||||
// }
|
|
||||||
|
|
||||||
impl<'a, B> Future for ReceiveFuture<'a, B, USART1, Stream7<DMA2>, Stream2<DMA2>, Channel4>
|
|
||||||
where
|
|
||||||
B: WriteBuffer<Word = u8> + 'static + Unpin,
|
|
||||||
{
|
|
||||||
type Output = B;
|
|
||||||
|
|
||||||
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<B> {
|
|
||||||
let Self {
|
|
||||||
Serial,
|
|
||||||
rx_transfer,
|
|
||||||
} = unsafe { self.get_unchecked_mut() };
|
|
||||||
let mut taken = rx_transfer.take().unwrap();
|
|
||||||
|
|
||||||
if Stream7::<DMA2>::get_transfer_complete_flag() {
|
|
||||||
let (rx_stream, usart, buf, _) = rx_transfer.take().unwrap().free();
|
|
||||||
|
|
||||||
Serial.rx_stream.replace(rx_stream);
|
|
||||||
Serial.usart.replace(usart);
|
|
||||||
|
|
||||||
Poll::Ready(buf)
|
|
||||||
} else {
|
|
||||||
// waker_interrupt!(DMA2_STREAM2, cx.waker().clone());
|
|
||||||
|
|
||||||
taken.start(|_usart| {});
|
|
||||||
rx_transfer.replace(taken);
|
|
||||||
|
|
||||||
STATE.rx_done.poll_wait(cx);
|
|
||||||
|
|
||||||
/*
|
|
||||||
Note: we have to do this because rx_transfer owns the buffer and we can't
|
|
||||||
access it until the transfer is completed. Therefore we can't pass
|
|
||||||
the buffer to poll_wait, but we still need to be woken.
|
|
||||||
*/
|
|
||||||
Poll::Pending
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ async fn run(dp: stm32::Peripherals, cp: cortex_m::Peripherals) {
|
|||||||
gpioa.pa10.into_alternate_af7(),
|
gpioa.pa10.into_alternate_af7(),
|
||||||
interrupt::take!(DMA2_STREAM2),
|
interrupt::take!(DMA2_STREAM2),
|
||||||
interrupt::take!(DMA2_STREAM7),
|
interrupt::take!(DMA2_STREAM7),
|
||||||
|
interrupt::take!(USART1),
|
||||||
dp.DMA2,
|
dp.DMA2,
|
||||||
dp.USART1,
|
dp.USART1,
|
||||||
config::Parity::ParityNone,
|
config::Parity::ParityNone,
|
||||||
|
Loading…
Reference in New Issue
Block a user