simplify impl. and add interupt idea

This commit is contained in:
xoviat 2021-01-01 14:59:57 -06:00
parent d5cb9bebaa
commit 2ee2d18465
2 changed files with 67 additions and 151 deletions

View File

@ -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,20 +113,32 @@ 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();
STATE.tx_done.reset();
async move {
let mut tx_transfer = Transfer::init( let mut tx_transfer = Transfer::init(
tx_stream, tx_stream,
usart, usart,
@ -130,13 +150,13 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
.double_buffer(false), .double_buffer(false),
); );
STATE.tx_done.reset(); tx_transfer.start(|_usart| {});
SendFuture { STATE.tx_done.wait().await;
Serial: self,
tx_transfer: Some(tx_transfer), let (tx_stream, usart, _buf, _) = tx_transfer.free();
// tx_stream: Some(tx_stream), self.tx_stream.replace(tx_stream);
// usart: Some(usart), self.usart.replace(usart);
} }
} }
@ -150,15 +170,15 @@ 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();
STATE.rx_done.reset();
async move {
let mut rx_transfer = Transfer::init( let mut rx_transfer = Transfer::init(
rx_stream, rx_stream,
usart, usart,
@ -166,124 +186,19 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
None, None,
DmaConfig::default() DmaConfig::default()
.transfer_complete_interrupt(true) .transfer_complete_interrupt(true)
.half_transfer_interrupt(true)
.memory_increment(true) .memory_increment(true)
.double_buffer(false), .double_buffer(false),
); );
STATE.rx_done.reset(); rx_transfer.start(|_usart| {});
ReceiveFuture { STATE.rx_done.wait().await;
Serial: self,
rx_transfer: Some(rx_transfer), let (rx_stream, usart, buf, _) = rx_transfer.free();
} self.rx_stream.replace(rx_stream);
} self.usart.replace(usart);
}
buf
/// Future for the [`LowPowerSerial::send()`] method.
pub struct SendFuture<
'a,
B: WriteBuffer<Word = u8> + 'static,
USART: PeriAddress<MemSize = u8>,
TSTREAM: Stream,
RSTREAM: Stream,
CHANNEL,
> {
Serial: &'a mut Serial<USART, TSTREAM, RSTREAM>,
tx_transfer: Option<Transfer<TSTREAM, CHANNEL, USART, MemoryToPeripheral, B>>,
}
// impl<'a, B> Drop for SendFuture<'a, B>
// 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
} }
} }
} }

View File

@ -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,