Merge pull request #17 from xoviat/implement-uart
implement uart on serial interface
This commit is contained in:
commit
0204d4e812
@ -8,6 +8,7 @@
|
|||||||
use cortex_m::singleton;
|
use cortex_m::singleton;
|
||||||
use cortex_m_rt::entry;
|
use cortex_m_rt::entry;
|
||||||
use embassy::executor::{task, Executor};
|
use embassy::executor::{task, Executor};
|
||||||
|
use embassy::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;
|
||||||
@ -27,23 +28,23 @@ async fn run(dp: stm32::Peripherals, cp: cortex_m::Peripherals) {
|
|||||||
.pclk1(24.mhz())
|
.pclk1(24.mhz())
|
||||||
.freeze();
|
.freeze();
|
||||||
|
|
||||||
let mut serial = serial::Serial::new(
|
let mut serial = unsafe {
|
||||||
gpioa.pa9.into_alternate_af7(),
|
serial::Serial::new(
|
||||||
gpioa.pa10.into_alternate_af7(),
|
gpioa.pa9.into_alternate_af7(),
|
||||||
interrupt::take!(DMA2_STREAM7),
|
gpioa.pa10.into_alternate_af7(),
|
||||||
interrupt::take!(DMA2_STREAM2),
|
interrupt::take!(DMA2_STREAM7),
|
||||||
interrupt::take!(USART1),
|
interrupt::take!(DMA2_STREAM2),
|
||||||
dp.DMA2,
|
interrupt::take!(USART1),
|
||||||
dp.USART1,
|
dp.DMA2,
|
||||||
config::Parity::ParityNone,
|
dp.USART1,
|
||||||
9600.bps(),
|
config::Parity::ParityNone,
|
||||||
clocks,
|
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;
|
||||||
|
|
||||||
serial.send(buf).await;
|
serial.send(buf).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,8 +10,9 @@ use core::sync::atomic::{self, Ordering};
|
|||||||
use core::task::{Context, Poll};
|
use core::task::{Context, Poll};
|
||||||
|
|
||||||
use embassy::interrupt::OwnedInterrupt;
|
use embassy::interrupt::OwnedInterrupt;
|
||||||
|
use embassy::uart::{Error, Uart};
|
||||||
use embassy::util::Signal;
|
use embassy::util::Signal;
|
||||||
use embedded_dma::{StaticReadBuffer, StaticWriteBuffer, WriteBuffer};
|
use embedded_dma::StaticWriteBuffer;
|
||||||
|
|
||||||
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};
|
||||||
@ -56,7 +57,8 @@ static STATE: State = State {
|
|||||||
static mut INSTANCE: *const Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> = ptr::null_mut();
|
static mut INSTANCE: *const Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> = ptr::null_mut();
|
||||||
|
|
||||||
impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
||||||
pub fn new(
|
// Leaking futures is forbidden!
|
||||||
|
pub unsafe fn new(
|
||||||
txd: PA9<Alternate<AF7>>,
|
txd: PA9<Alternate<AF7>>,
|
||||||
rxd: PA10<Alternate<AF7>>,
|
rxd: PA10<Alternate<AF7>>,
|
||||||
tx_int: interrupt::DMA2_STREAM7Interrupt,
|
tx_int: interrupt::DMA2_STREAM7Interrupt,
|
||||||
@ -135,18 +137,19 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
|||||||
|
|
||||||
STATE.rx_int.signal(());
|
STATE.rx_int.signal(());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Uart for Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
||||||
|
type SendFuture<'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> {
|
||||||
/// `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
|
|
||||||
/// reused until the future has finished.
|
|
||||||
pub fn send<'a, B: 'a>(&'a mut self, tx_buffer: B) -> impl Future<Output = ()> + 'a
|
|
||||||
where
|
|
||||||
B: StaticWriteBuffer<Word = u8>,
|
|
||||||
{
|
|
||||||
unsafe { INSTANCE = self };
|
unsafe { INSTANCE = self };
|
||||||
|
|
||||||
|
#[allow(mutable_transmutes)]
|
||||||
|
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();
|
STATE.tx_int.reset();
|
||||||
@ -155,7 +158,7 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
|||||||
let mut tx_transfer = Transfer::init(
|
let mut tx_transfer = Transfer::init(
|
||||||
tx_stream,
|
tx_stream,
|
||||||
usart,
|
usart,
|
||||||
tx_buffer,
|
static_buf,
|
||||||
None,
|
None,
|
||||||
DmaConfig::default()
|
DmaConfig::default()
|
||||||
.transfer_complete_interrupt(true)
|
.transfer_complete_interrupt(true)
|
||||||
@ -172,6 +175,8 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
|||||||
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);
|
||||||
self.usart.replace(usart);
|
self.usart.replace(usart);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,44 +186,32 @@ impl Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> {
|
|||||||
/// A common pattern is to use [`stop()`](ReceiveFuture::stop) to cancel
|
/// A common pattern is to use [`stop()`](ReceiveFuture::stop) to cancel
|
||||||
/// 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> {
|
||||||
/// `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
|
|
||||||
/// reused until the future has finished.
|
|
||||||
pub fn receive<'a, B: 'a>(&'a mut self, rx_buffer: B) -> impl Future<Output = B> + 'a
|
|
||||||
where
|
|
||||||
B: StaticWriteBuffer<Word = u8> + Unpin,
|
|
||||||
{
|
|
||||||
unsafe { INSTANCE = self };
|
unsafe { INSTANCE = self };
|
||||||
|
|
||||||
|
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();
|
STATE.rx_int.reset();
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
let mut rx_transfer = Transfer::init(
|
let mut rx_transfer = Transfer::init(
|
||||||
rx_stream,
|
rx_stream,
|
||||||
usart,
|
usart,
|
||||||
rx_buffer,
|
static_buf,
|
||||||
None,
|
None,
|
||||||
DmaConfig::default()
|
DmaConfig::default()
|
||||||
.transfer_complete_interrupt(true)
|
.transfer_complete_interrupt(true)
|
||||||
.memory_increment(true)
|
.memory_increment(true)
|
||||||
.double_buffer(false),
|
.double_buffer(false),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.rx_int.unpend();
|
self.rx_int.unpend();
|
||||||
self.rx_int.enable();
|
self.rx_int.enable();
|
||||||
|
|
||||||
rx_transfer.start(|_usart| {});
|
rx_transfer.start(|_usart| {});
|
||||||
|
|
||||||
STATE.rx_int.wait().await;
|
STATE.rx_int.wait().await;
|
||||||
|
let (rx_stream, usart, _, _) = rx_transfer.free();
|
||||||
let (rx_stream, usart, buf, _) = rx_transfer.free();
|
|
||||||
self.rx_stream.replace(rx_stream);
|
self.rx_stream.replace(rx_stream);
|
||||||
self.usart.replace(usart);
|
self.usart.replace(usart);
|
||||||
|
Ok(())
|
||||||
buf
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user