stm32: consolidate crates
This commit is contained in:
2
embassy-stm32/src/f4/mod.rs
Normal file
2
embassy-stm32/src/f4/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod qei;
|
||||
pub mod serial;
|
91
embassy-stm32/src/f4/qei.rs
Normal file
91
embassy-stm32/src/f4/qei.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use crate::interrupt;
|
||||
use core::future::Future;
|
||||
use core::pin::Pin;
|
||||
use embassy::traits::qei::WaitForRotate;
|
||||
use embedded_hal::Direction;
|
||||
use stm32f4xx_hal::pac::TIM2;
|
||||
use stm32f4xx_hal::{qei, qei::Pins};
|
||||
|
||||
pub struct Qei<T: Instance, PINS> {
|
||||
_qei: qei::Qei<T, PINS>,
|
||||
int: T::Interrupt,
|
||||
}
|
||||
|
||||
impl<PINS: Pins<TIM2>> Qei<TIM2, PINS> {
|
||||
pub fn tim2(tim: TIM2, pins: PINS, interrupt: interrupt::TIM2) -> Self {
|
||||
let qei = qei::Qei::tim2(tim, pins);
|
||||
|
||||
let tim = unsafe {
|
||||
&mut *(stm32f4xx_hal::stm32::TIM2::ptr()
|
||||
as *mut stm32f4xx_hal::stm32::tim2::RegisterBlock)
|
||||
};
|
||||
/*
|
||||
enable qei interrupt
|
||||
*/
|
||||
tim.dier.write(|w| w.uie().set_bit());
|
||||
|
||||
Qei {
|
||||
_qei: qei,
|
||||
int: interrupt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<PINS: Pins<TIM2> + 'static> WaitForRotate for Qei<TIM2, PINS> {
|
||||
type RotateFuture<'a> = impl Future<Output = Direction> + 'a;
|
||||
|
||||
fn wait_for_rotate<'a>(
|
||||
self: Pin<&'a mut Self>,
|
||||
count_down: u16,
|
||||
count_up: u16,
|
||||
) -> Self::RotateFuture<'a> {
|
||||
let s = unsafe { self.get_unchecked_mut() };
|
||||
|
||||
let tim = unsafe {
|
||||
&mut *(stm32f4xx_hal::stm32::TIM2::ptr()
|
||||
as *mut stm32f4xx_hal::stm32::tim2::RegisterBlock)
|
||||
};
|
||||
|
||||
/*
|
||||
the interrupt will be reached at zero or the max count
|
||||
write the total range to the qei.
|
||||
*/
|
||||
tim.arr
|
||||
.write(|w| unsafe { w.bits((count_down + count_up) as u32) });
|
||||
|
||||
/*
|
||||
set timer to the correct value in the range
|
||||
*/
|
||||
tim.cnt.write(|w| unsafe { w.bits(count_down as u32) });
|
||||
|
||||
/*
|
||||
clear interrupt flag
|
||||
*/
|
||||
tim.sr.write(|w| w.uif().clear_bit());
|
||||
|
||||
async move {
|
||||
embassy::util::InterruptFuture::new(&mut s.int).await;
|
||||
|
||||
if tim.cnt.read().bits() == 0 {
|
||||
Direction::Downcounting
|
||||
} else if tim.cnt.read() == count_down + count_up {
|
||||
Direction::Upcounting
|
||||
} else {
|
||||
panic!("unexpected value")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod sealed {
|
||||
pub trait Sealed {}
|
||||
}
|
||||
|
||||
pub trait Instance: sealed::Sealed {
|
||||
type Interrupt: interrupt::Interrupt;
|
||||
}
|
||||
|
||||
impl sealed::Sealed for TIM2 {}
|
||||
impl Instance for TIM2 {
|
||||
type Interrupt = interrupt::TIM2;
|
||||
}
|
364
embassy-stm32/src/f4/serial.rs
Normal file
364
embassy-stm32/src/f4/serial.rs
Normal file
@ -0,0 +1,364 @@
|
||||
//! Async Serial.
|
||||
|
||||
use core::future::Future;
|
||||
use core::marker::PhantomData;
|
||||
use core::pin::Pin;
|
||||
use embassy::interrupt::Interrupt;
|
||||
use embassy::traits::uart::{Error, Read, ReadUntilIdle, Write};
|
||||
use embassy::util::InterruptFuture;
|
||||
use futures::{select_biased, FutureExt};
|
||||
|
||||
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},
|
||||
};
|
||||
use crate::interrupt;
|
||||
use crate::pac;
|
||||
|
||||
/// Interface to the Serial peripheral
|
||||
pub struct Serial<
|
||||
USART: PeriAddress<MemSize = u8> + WithInterrupt,
|
||||
TSTREAM: Stream + WithInterrupt,
|
||||
RSTREAM: Stream + WithInterrupt,
|
||||
CHANNEL: Channel,
|
||||
> {
|
||||
tx_stream: Option<TSTREAM>,
|
||||
rx_stream: Option<RSTREAM>,
|
||||
usart: Option<USART>,
|
||||
tx_int: TSTREAM::Interrupt,
|
||||
rx_int: RSTREAM::Interrupt,
|
||||
usart_int: USART::Interrupt,
|
||||
channel: PhantomData<CHANNEL>,
|
||||
}
|
||||
|
||||
// static mut INSTANCE: *const Serial<USART1, Stream7<DMA2>, Stream2<DMA2>> = ptr::null_mut();
|
||||
|
||||
impl<USART, TSTREAM, RSTREAM, CHANNEL> Serial<USART, TSTREAM, RSTREAM, CHANNEL>
|
||||
where
|
||||
USART: serial::Instance
|
||||
+ PeriAddress<MemSize = u8>
|
||||
+ DMASet<TSTREAM, CHANNEL, MemoryToPeripheral>
|
||||
+ DMASet<RSTREAM, CHANNEL, PeripheralToMemory>
|
||||
+ WithInterrupt,
|
||||
TSTREAM: Stream + WithInterrupt,
|
||||
RSTREAM: Stream + WithInterrupt,
|
||||
CHANNEL: Channel,
|
||||
{
|
||||
// Leaking futures is forbidden!
|
||||
pub unsafe fn new<PINS>(
|
||||
usart: USART,
|
||||
streams: (TSTREAM, RSTREAM),
|
||||
pins: PINS,
|
||||
tx_int: TSTREAM::Interrupt,
|
||||
rx_int: RSTREAM::Interrupt,
|
||||
usart_int: USART::Interrupt,
|
||||
mut config: SerialConfig,
|
||||
clocks: Clocks,
|
||||
) -> Self
|
||||
where
|
||||
PINS: Pins<USART>,
|
||||
{
|
||||
config.dma = SerialDmaConfig::TxRx;
|
||||
|
||||
let (usart, _) = serial::Serial::new(usart, pins, config, clocks)
|
||||
.unwrap()
|
||||
.release();
|
||||
|
||||
let (tx_stream, rx_stream) = streams;
|
||||
|
||||
Serial {
|
||||
tx_stream: Some(tx_stream),
|
||||
rx_stream: Some(rx_stream),
|
||||
usart: Some(usart),
|
||||
tx_int: tx_int,
|
||||
rx_int: rx_int,
|
||||
usart_int: usart_int,
|
||||
channel: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<USART, TSTREAM, RSTREAM, CHANNEL> Read for Serial<USART, TSTREAM, RSTREAM, CHANNEL>
|
||||
where
|
||||
USART: serial::Instance
|
||||
+ PeriAddress<MemSize = u8>
|
||||
+ DMASet<TSTREAM, CHANNEL, MemoryToPeripheral>
|
||||
+ DMASet<RSTREAM, CHANNEL, PeripheralToMemory>
|
||||
+ WithInterrupt
|
||||
+ 'static,
|
||||
TSTREAM: Stream + WithInterrupt + 'static,
|
||||
RSTREAM: Stream + WithInterrupt + 'static,
|
||||
CHANNEL: Channel + 'static,
|
||||
{
|
||||
type ReadFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
|
||||
|
||||
/// Receives serial data.
|
||||
///
|
||||
/// The future is pending until the buffer is completely filled.
|
||||
fn read<'a>(self: Pin<&'a mut Self>, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
|
||||
let this = unsafe { self.get_unchecked_mut() };
|
||||
let static_buf = unsafe { core::mem::transmute::<&'a mut [u8], &'static mut [u8]>(buf) };
|
||||
|
||||
async move {
|
||||
let rx_stream = this.rx_stream.take().unwrap();
|
||||
let usart = this.usart.take().unwrap();
|
||||
|
||||
let mut rx_transfer = Transfer::init(
|
||||
rx_stream,
|
||||
usart,
|
||||
static_buf,
|
||||
None,
|
||||
DmaConfig::default()
|
||||
.transfer_complete_interrupt(true)
|
||||
.memory_increment(true)
|
||||
.double_buffer(false),
|
||||
);
|
||||
|
||||
let fut = InterruptFuture::new(&mut this.rx_int);
|
||||
rx_transfer.start(|_usart| {});
|
||||
fut.await;
|
||||
|
||||
let (rx_stream, usart, _, _) = rx_transfer.free();
|
||||
this.rx_stream.replace(rx_stream);
|
||||
this.usart.replace(usart);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<USART, TSTREAM, RSTREAM, CHANNEL> Write for Serial<USART, TSTREAM, RSTREAM, CHANNEL>
|
||||
where
|
||||
USART: serial::Instance
|
||||
+ PeriAddress<MemSize = u8>
|
||||
+ DMASet<TSTREAM, CHANNEL, MemoryToPeripheral>
|
||||
+ DMASet<RSTREAM, CHANNEL, PeripheralToMemory>
|
||||
+ WithInterrupt
|
||||
+ 'static,
|
||||
TSTREAM: Stream + WithInterrupt + 'static,
|
||||
RSTREAM: Stream + WithInterrupt + 'static,
|
||||
CHANNEL: Channel + 'static,
|
||||
{
|
||||
type WriteFuture<'a> = impl Future<Output = Result<(), Error>> + 'a;
|
||||
|
||||
/// Sends serial data.
|
||||
fn write<'a>(self: Pin<&'a mut Self>, buf: &'a [u8]) -> Self::WriteFuture<'a> {
|
||||
let this = unsafe { self.get_unchecked_mut() };
|
||||
#[allow(mutable_transmutes)]
|
||||
let static_buf = unsafe { core::mem::transmute::<&'a [u8], &'static mut [u8]>(buf) };
|
||||
|
||||
async move {
|
||||
let tx_stream = this.tx_stream.take().unwrap();
|
||||
let usart = this.usart.take().unwrap();
|
||||
|
||||
let mut tx_transfer = Transfer::init(
|
||||
tx_stream,
|
||||
usart,
|
||||
static_buf,
|
||||
None,
|
||||
DmaConfig::default()
|
||||
.transfer_complete_interrupt(true)
|
||||
.memory_increment(true)
|
||||
.double_buffer(false),
|
||||
);
|
||||
|
||||
let fut = InterruptFuture::new(&mut this.tx_int);
|
||||
|
||||
tx_transfer.start(|_usart| {});
|
||||
fut.await;
|
||||
|
||||
let (tx_stream, usart, _buf, _) = tx_transfer.free();
|
||||
|
||||
this.tx_stream.replace(tx_stream);
|
||||
this.usart.replace(usart);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<USART, TSTREAM, RSTREAM, CHANNEL> ReadUntilIdle for Serial<USART, TSTREAM, RSTREAM, CHANNEL>
|
||||
where
|
||||
USART: serial::Instance
|
||||
+ PeriAddress<MemSize = u8>
|
||||
+ DMASet<TSTREAM, CHANNEL, MemoryToPeripheral>
|
||||
+ DMASet<RSTREAM, CHANNEL, PeripheralToMemory>
|
||||
+ WithInterrupt
|
||||
+ 'static,
|
||||
TSTREAM: Stream + WithInterrupt + 'static,
|
||||
RSTREAM: Stream + WithInterrupt + 'static,
|
||||
CHANNEL: Channel + 'static,
|
||||
{
|
||||
type ReadUntilIdleFuture<'a> = impl Future<Output = Result<usize, Error>> + 'a;
|
||||
|
||||
/// Receives serial data.
|
||||
///
|
||||
/// The future is pending until either the buffer is completely full, or the RX line falls idle after receiving some data.
|
||||
///
|
||||
/// Returns the number of bytes read.
|
||||
fn read_until_idle<'a>(
|
||||
self: Pin<&'a mut Self>,
|
||||
buf: &'a mut [u8],
|
||||
) -> Self::ReadUntilIdleFuture<'a> {
|
||||
let this = unsafe { self.get_unchecked_mut() };
|
||||
let static_buf = unsafe { core::mem::transmute::<&'a mut [u8], &'static mut [u8]>(buf) };
|
||||
|
||||
async move {
|
||||
let rx_stream = this.rx_stream.take().unwrap();
|
||||
let usart = this.usart.take().unwrap();
|
||||
|
||||
unsafe {
|
||||
/* __HAL_UART_ENABLE_IT(&uart->UartHandle, UART_IT_IDLE); */
|
||||
(*USART::ptr()).cr1.modify(|_, w| w.idleie().set_bit());
|
||||
|
||||
/* __HAL_UART_CLEAR_IDLEFLAG(&uart->UartHandle); */
|
||||
(*USART::ptr()).sr.read();
|
||||
(*USART::ptr()).dr.read();
|
||||
};
|
||||
|
||||
let mut rx_transfer = Transfer::init(
|
||||
rx_stream,
|
||||
usart,
|
||||
static_buf,
|
||||
None,
|
||||
DmaConfig::default()
|
||||
.transfer_complete_interrupt(true)
|
||||
.memory_increment(true)
|
||||
.double_buffer(false),
|
||||
);
|
||||
|
||||
let total_bytes = RSTREAM::get_number_of_transfers() as usize;
|
||||
|
||||
let fut = InterruptFuture::new(&mut this.rx_int);
|
||||
let fut_idle = InterruptFuture::new(&mut this.usart_int);
|
||||
|
||||
rx_transfer.start(|_usart| {});
|
||||
|
||||
futures::future::select(fut, fut_idle).await;
|
||||
|
||||
let (rx_stream, usart, _, _) = rx_transfer.free();
|
||||
|
||||
let remaining_bytes = RSTREAM::get_number_of_transfers() as usize;
|
||||
|
||||
unsafe {
|
||||
(*USART::ptr()).cr1.modify(|_, w| w.idleie().clear_bit());
|
||||
}
|
||||
this.rx_stream.replace(rx_stream);
|
||||
this.usart.replace(usart);
|
||||
|
||||
Ok(total_bytes - remaining_bytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod private {
|
||||
pub trait Sealed {}
|
||||
}
|
||||
|
||||
pub trait WithInterrupt: private::Sealed {
|
||||
type Interrupt: Interrupt;
|
||||
}
|
||||
|
||||
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 Interrupt = interrupt::$PER;
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! usart {
|
||||
($($PER:ident => ($usart:ident),)+) => {
|
||||
$(
|
||||
impl private::Sealed for pac::$usart {}
|
||||
impl WithInterrupt for pac::$usart {
|
||||
type Interrupt = 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),
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "stm32f401", feature = "stm32f410", feature = "stm32f411",))]
|
||||
usart! {
|
||||
USART1 => (USART1),
|
||||
USART2 => (USART2),
|
||||
USART6 => (USART6),
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "stm32f405", feature = "stm32f407"))]
|
||||
usart! {
|
||||
USART1 => (USART1),
|
||||
USART2 => (USART2),
|
||||
USART3 => (USART3),
|
||||
USART6 => (USART6),
|
||||
|
||||
UART4 => (UART4),
|
||||
UART5 => (UART5),
|
||||
}
|
||||
|
||||
#[cfg(feature = "stm32f412")]
|
||||
usart! {
|
||||
USART1 => (USART1),
|
||||
USART2 => (USART2),
|
||||
USART3 => (USART3),
|
||||
USART6 => (USART6),
|
||||
}
|
||||
|
||||
#[cfg(feature = "stm32f413")]
|
||||
usart! {
|
||||
USART1 => (USART1),
|
||||
USART2 => (USART2),
|
||||
USART3 => (USART3),
|
||||
USART6 => (USART6),
|
||||
USART7 => (USART7),
|
||||
USART8 => (USART8),
|
||||
|
||||
UART5 => (UART5),
|
||||
UART9 => (UART9),
|
||||
UART10 => (UART10),
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
feature = "stm32f427",
|
||||
feature = "stm32f429",
|
||||
feature = "stm32f446",
|
||||
feature = "stm32f469"
|
||||
))]
|
||||
usart! {
|
||||
USART1 => (USART1),
|
||||
USART2 => (USART2),
|
||||
USART3 => (USART3),
|
||||
USART6 => (USART6),
|
||||
|
||||
UART4 => (UART4),
|
||||
UART5 => (UART5),
|
||||
// UART7 => (UART7),
|
||||
// UART8 => (UART8),
|
||||
}
|
@ -25,6 +25,25 @@
|
||||
feature = "stm32f469",
|
||||
feature = "stm32f479",
|
||||
))]
|
||||
mod f4;
|
||||
|
||||
#[cfg(any(
|
||||
feature = "stm32f401",
|
||||
feature = "stm32f405",
|
||||
feature = "stm32f407",
|
||||
feature = "stm32f412",
|
||||
feature = "stm32f413",
|
||||
feature = "stm32f415",
|
||||
feature = "stm32f417",
|
||||
feature = "stm32f423",
|
||||
feature = "stm32f427",
|
||||
feature = "stm32f429",
|
||||
feature = "stm32f437",
|
||||
feature = "stm32f439",
|
||||
feature = "stm32f446",
|
||||
feature = "stm32f469",
|
||||
feature = "stm32f479",
|
||||
))]
|
||||
pub use {stm32f4xx_hal as hal, stm32f4xx_hal::stm32 as pac};
|
||||
|
||||
#[cfg(any(feature = "stm32l0x1", feature = "stm32l0x2", feature = "stm32l0x3",))]
|
||||
@ -58,8 +77,6 @@ pub mod can;
|
||||
feature = "stm32f401",
|
||||
feature = "stm32f405",
|
||||
feature = "stm32f407",
|
||||
feature = "stm32f410",
|
||||
feature = "stm32f411",
|
||||
feature = "stm32f412",
|
||||
feature = "stm32f413",
|
||||
feature = "stm32f415",
|
||||
@ -75,6 +92,25 @@ pub mod can;
|
||||
))]
|
||||
pub mod rtc;
|
||||
|
||||
#[cfg(any(
|
||||
feature = "stm32f401",
|
||||
feature = "stm32f405",
|
||||
feature = "stm32f407",
|
||||
feature = "stm32f412",
|
||||
feature = "stm32f413",
|
||||
feature = "stm32f415",
|
||||
feature = "stm32f417",
|
||||
feature = "stm32f423",
|
||||
feature = "stm32f427",
|
||||
feature = "stm32f429",
|
||||
feature = "stm32f437",
|
||||
feature = "stm32f439",
|
||||
feature = "stm32f446",
|
||||
feature = "stm32f469",
|
||||
feature = "stm32f479",
|
||||
))]
|
||||
pub use f4::{qei, serial};
|
||||
|
||||
#[cfg(any(
|
||||
feature = "stm32f401",
|
||||
feature = "stm32f405",
|
||||
|
Reference in New Issue
Block a user