Merge branch 'embassy-rs:main' into simplepwm-dma
This commit is contained in:
commit
f5a218a018
15 changed files with 222 additions and 50 deletions
|
@ -35,8 +35,7 @@ The <a href="https://docs.embassy.dev/embassy-net/">embassy-net</a> network stac
|
|||
The <a href="https://github.com/embassy-rs/nrf-softdevice">nrf-softdevice</a> crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers.
|
||||
The <a href="https://github.com/embassy-rs/embassy/tree/main/embassy-stm32-wpan">embassy-stm32-wpan</a> crate provides Bluetooth Low Energy 5.x support for stm32wb microcontrollers.
|
||||
|
||||
- **LoRa** -
|
||||
<a href="hthttps://github.com/lora-rs/lora-rs">The lora-rs project</a> provides an async LoRa and LoRaWAN stack that works well on Embassy.
|
||||
- **LoRa** - The <a href="https://github.com/lora-rs/lora-rs">lora-rs</a> project provides an async LoRa and LoRaWAN stack that works well on Embassy.
|
||||
|
||||
- **USB** -
|
||||
<a href="https://docs.embassy.dev/embassy-usb/">embassy-usb</a> implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
|
||||
|
|
3
ci.sh
3
ci.sh
|
@ -207,6 +207,9 @@ cargo batch \
|
|||
$BUILD_EXTRA
|
||||
|
||||
|
||||
# failed, a wire must've come loose, will check asap.
|
||||
rm out/tests/rpi-pico/i2c
|
||||
|
||||
rm out/tests/stm32wb55rg/wpan_mac
|
||||
rm out/tests/stm32wb55rg/wpan_ble
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ The link:https://docs.embassy.dev/embassy-net/[embassy-net] network stack implem
|
|||
The link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers.
|
||||
|
||||
=== LoRa
|
||||
link:https://github.com/embassy-rs/lora-phy[lora-phy] and link:https://docs.embassy.dev/embassy-lora/[embassy-lora] supports LoRa networking on a wide range of LoRa radios, fully integrated with a Rust link:https://github.com/ivajloip/rust-lorawan[LoRaWAN] implementation.
|
||||
link:https://github.com/lora-rs/lora-rs[lora-rs] supports LoRa networking on a wide range of LoRa radios, fully integrated with a Rust LoRaWAN implementation. It provides four crates — lora-phy, lora-modulation, lorawan-encoding, and lorawan-device — and basic examples for various development boards. It has support for STM32WL wireless microcontrollers or Semtech SX127x transceivers, among others.
|
||||
|
||||
=== USB
|
||||
link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
|
||||
|
|
|
@ -49,7 +49,7 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result<TokenStream, TokenStre
|
|||
},
|
||||
}
|
||||
|
||||
let mut arg_names = Vec::new();
|
||||
let mut args = Vec::new();
|
||||
let mut fargs = f.sig.inputs.clone();
|
||||
|
||||
for arg in fargs.iter_mut() {
|
||||
|
@ -59,8 +59,8 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result<TokenStream, TokenStre
|
|||
}
|
||||
syn::FnArg::Typed(t) => match t.pat.as_mut() {
|
||||
syn::Pat::Ident(id) => {
|
||||
arg_names.push(id.ident.clone());
|
||||
id.mutability = None;
|
||||
args.push((id.clone(), t.attrs.clone()));
|
||||
}
|
||||
_ => {
|
||||
ctxt.error_spanned_by(arg, "pattern matching in task arguments is not yet supported");
|
||||
|
@ -79,13 +79,24 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result<TokenStream, TokenStre
|
|||
task_inner.vis = syn::Visibility::Inherited;
|
||||
task_inner.sig.ident = task_inner_ident.clone();
|
||||
|
||||
// assemble the original input arguments,
|
||||
// including any attributes that may have
|
||||
// been applied previously
|
||||
let mut full_args = Vec::new();
|
||||
for (arg, cfgs) in args {
|
||||
full_args.push(quote!(
|
||||
#(#cfgs)*
|
||||
#arg
|
||||
));
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
let mut task_outer: ItemFn = parse_quote! {
|
||||
#visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken<impl Sized> {
|
||||
type Fut = impl ::core::future::Future + 'static;
|
||||
const POOL_SIZE: usize = #pool_size;
|
||||
static POOL: ::embassy_executor::raw::TaskPool<Fut, POOL_SIZE> = ::embassy_executor::raw::TaskPool::new();
|
||||
unsafe { POOL._spawn_async_fn(move || #task_inner_ident(#(#arg_names,)*)) }
|
||||
unsafe { POOL._spawn_async_fn(move || #task_inner_ident(#(#full_args,)*)) }
|
||||
}
|
||||
};
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
|
@ -93,7 +104,7 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result<TokenStream, TokenStre
|
|||
#visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken<impl Sized> {
|
||||
const POOL_SIZE: usize = #pool_size;
|
||||
static POOL: ::embassy_executor::_export::TaskPoolRef = ::embassy_executor::_export::TaskPoolRef::new();
|
||||
unsafe { POOL.get::<_, POOL_SIZE>()._spawn_async_fn(move || #task_inner_ident(#(#arg_names,)*)) }
|
||||
unsafe { POOL.get::<_, POOL_SIZE>()._spawn_async_fn(move || #task_inner_ident(#(#full_args,)*)) }
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -135,3 +135,17 @@ fn executor_task_self_wake_twice() {
|
|||
]
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn executor_task_cfg_args() {
|
||||
// simulate cfg'ing away argument c
|
||||
#[task]
|
||||
async fn task1(a: u32, b: u32, #[cfg(any())] c: u32) {
|
||||
let (_, _) = (a, b);
|
||||
}
|
||||
|
||||
#[task]
|
||||
async fn task2(a: u32, b: u32, #[cfg(all())] c: u32) {
|
||||
let (_, _, _) = (a, b, c);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -222,6 +222,11 @@ impl<'a> UdpSocket<'a> {
|
|||
pub fn payload_send_capacity(&self) -> usize {
|
||||
self.with(|s, _| s.payload_send_capacity())
|
||||
}
|
||||
|
||||
/// Set the hop limit field in the IP header of sent packets.
|
||||
pub fn set_hop_limit(&mut self, hop_limit: Option<u8>) {
|
||||
self.with_mut(|s, _| s.set_hop_limit(hop_limit))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for UdpSocket<'_> {
|
||||
|
|
|
@ -342,6 +342,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
|||
s.tx_count.store(0, Ordering::Relaxed);
|
||||
s.rx_started_count.store(0, Ordering::Relaxed);
|
||||
s.rx_ended_count.store(0, Ordering::Relaxed);
|
||||
s.rx_started.store(false, Ordering::Relaxed);
|
||||
let len = tx_buffer.len();
|
||||
unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
|
||||
let len = rx_buffer.len();
|
||||
|
|
|
@ -152,6 +152,12 @@ impl<'d, T: Pin> Output<'d, T> {
|
|||
self.pin.set_low()
|
||||
}
|
||||
|
||||
/// Toggle the output level.
|
||||
#[inline]
|
||||
pub fn toggle(&mut self) {
|
||||
self.pin.toggle()
|
||||
}
|
||||
|
||||
/// Set the output level.
|
||||
#[inline]
|
||||
pub fn set_level(&mut self, level: Level) {
|
||||
|
@ -310,6 +316,16 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||
self.pin.set_low()
|
||||
}
|
||||
|
||||
/// Toggle the output level.
|
||||
#[inline]
|
||||
pub fn toggle(&mut self) {
|
||||
if self.is_set_low() {
|
||||
self.set_high()
|
||||
} else {
|
||||
self.set_low()
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the output level.
|
||||
#[inline]
|
||||
pub fn set_level(&mut self, level: Level) {
|
||||
|
@ -538,6 +554,15 @@ mod eh02 {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d, T> {
|
||||
type Error = Infallible;
|
||||
#[inline]
|
||||
fn toggle(&mut self) -> Result<(), Self::Error> {
|
||||
self.toggle();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement [`embedded_hal_02::digital::v2::InputPin`] for [`Flex`];
|
||||
///
|
||||
/// If the pin is not in input mode the result is unspecified.
|
||||
|
@ -574,6 +599,15 @@ mod eh02 {
|
|||
Ok(self.ref_is_set_low())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d, T> {
|
||||
type Error = Infallible;
|
||||
#[inline]
|
||||
fn toggle(&mut self) -> Result<(), Self::Error> {
|
||||
self.toggle();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Input<'d, T> {
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
//! # I2Cv1
|
||||
//!
|
||||
//! This implementation is used for STM32F1, STM32F2, STM32F4, and STM32L1 devices.
|
||||
//!
|
||||
//! All other devices (as of 2023-12-28) use [`v2`](super::v2) instead.
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::task::Poll;
|
||||
|
||||
|
@ -10,6 +16,17 @@ use crate::dma::Transfer;
|
|||
use crate::pac::i2c;
|
||||
use crate::time::Hertz;
|
||||
|
||||
// /!\ /!\
|
||||
// /!\ Implementation note! /!\
|
||||
// /!\ /!\
|
||||
//
|
||||
// It's somewhat unclear whether using interrupts here in a *strictly* one-shot style is actually
|
||||
// what we want! If you are looking in this file because you are doing async I2C and your code is
|
||||
// just totally hanging (sometimes), maybe swing by this issue:
|
||||
// <https://github.com/embassy-rs/embassy/issues/2372>.
|
||||
//
|
||||
// There's some more details there, and we might have a fix for you. But please let us know if you
|
||||
// hit a case like this!
|
||||
pub unsafe fn on_interrupt<T: Instance>() {
|
||||
let regs = T::regs();
|
||||
// i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of
|
||||
|
@ -375,6 +392,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
|
|||
T::regs().sr2().read();
|
||||
Poll::Ready(Ok(()))
|
||||
} else {
|
||||
// If we need to go around, then re-enable the interrupts, otherwise nothing
|
||||
// can wake us up and we'll hang.
|
||||
Self::enable_interrupts();
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,32 +208,30 @@ pub fn init(config: Config) -> Peripherals {
|
|||
let p = Peripherals::take_with_cs(cs);
|
||||
|
||||
#[cfg(dbgmcu)]
|
||||
if config.enable_debug_during_sleep {
|
||||
crate::pac::DBGMCU.cr().modify(|cr| {
|
||||
#[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))]
|
||||
{
|
||||
cr.set_dbg_stop(true);
|
||||
cr.set_dbg_standby(true);
|
||||
}
|
||||
#[cfg(any(
|
||||
dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1,
|
||||
dbgmcu_l4, dbgmcu_wb, dbgmcu_wl
|
||||
))]
|
||||
{
|
||||
cr.set_dbg_sleep(true);
|
||||
cr.set_dbg_stop(true);
|
||||
cr.set_dbg_standby(true);
|
||||
}
|
||||
#[cfg(dbgmcu_h7)]
|
||||
{
|
||||
cr.set_d1dbgcken(true);
|
||||
cr.set_d3dbgcken(true);
|
||||
cr.set_dbgsleep_d1(true);
|
||||
cr.set_dbgstby_d1(true);
|
||||
cr.set_dbgstop_d1(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
crate::pac::DBGMCU.cr().modify(|cr| {
|
||||
#[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))]
|
||||
{
|
||||
cr.set_dbg_stop(config.enable_debug_during_sleep);
|
||||
cr.set_dbg_standby(config.enable_debug_during_sleep);
|
||||
}
|
||||
#[cfg(any(
|
||||
dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1,
|
||||
dbgmcu_l4, dbgmcu_wb, dbgmcu_wl
|
||||
))]
|
||||
{
|
||||
cr.set_dbg_sleep(config.enable_debug_during_sleep);
|
||||
cr.set_dbg_stop(config.enable_debug_during_sleep);
|
||||
cr.set_dbg_standby(config.enable_debug_during_sleep);
|
||||
}
|
||||
#[cfg(dbgmcu_h7)]
|
||||
{
|
||||
cr.set_d1dbgcken(config.enable_debug_during_sleep);
|
||||
cr.set_d3dbgcken(config.enable_debug_during_sleep);
|
||||
cr.set_dbgsleep_d1(config.enable_debug_during_sleep);
|
||||
cr.set_dbgstby_d1(config.enable_debug_during_sleep);
|
||||
cr.set_dbgstop_d1(config.enable_debug_during_sleep);
|
||||
}
|
||||
});
|
||||
|
||||
#[cfg(not(any(stm32f1, stm32wb, stm32wl)))]
|
||||
peripherals::SYSCFG::enable_and_reset_with_cs(cs);
|
||||
|
|
|
@ -24,7 +24,7 @@ use crate::time::Hertz;
|
|||
),
|
||||
path = "v2.rs"
|
||||
)]
|
||||
#[cfg_attr(any(rtc_v3, rtc_v3u5), path = "v3.rs")]
|
||||
#[cfg_attr(any(rtc_v3, rtc_v3u5, rtc_v3l5), path = "v3.rs")]
|
||||
mod _version;
|
||||
#[allow(unused_imports)]
|
||||
pub use _version::*;
|
||||
|
@ -43,7 +43,7 @@ pub(crate) enum WakeupPrescaler {
|
|||
Div16 = 16,
|
||||
}
|
||||
|
||||
#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4))]
|
||||
#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4, stm32l5))]
|
||||
impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
|
||||
fn from(val: WakeupPrescaler) -> Self {
|
||||
use crate::pac::rtc::vals::Wucksel;
|
||||
|
@ -57,7 +57,7 @@ impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4))]
|
||||
#[cfg(any(stm32wb, stm32f4, stm32l0, stm32g4, stm32l5))]
|
||||
impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
|
||||
fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
|
||||
use crate::pac::rtc::vals::Wucksel;
|
||||
|
@ -348,7 +348,7 @@ impl Rtc {
|
|||
) {
|
||||
use embassy_time::{Duration, TICK_HZ};
|
||||
|
||||
#[cfg(any(rtc_v3, rtc_v3u5))]
|
||||
#[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
|
||||
use crate::pac::rtc::vals::Calrf;
|
||||
|
||||
// Panic if the rcc mod knows we're not using low-power rtc
|
||||
|
@ -375,7 +375,7 @@ impl Rtc {
|
|||
while !regs.isr().read().wutwf() {}
|
||||
}
|
||||
|
||||
#[cfg(any(rtc_v3, rtc_v3u5))]
|
||||
#[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
|
||||
{
|
||||
regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
|
||||
while !regs.icsr().read().wutwf() {}
|
||||
|
@ -404,7 +404,7 @@ impl Rtc {
|
|||
/// was called, otherwise none
|
||||
pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> {
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
#[cfg(any(rtc_v3, rtc_v3u5))]
|
||||
#[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
|
||||
use crate::pac::rtc::vals::Calrf;
|
||||
|
||||
let instant = self.instant().unwrap();
|
||||
|
@ -420,13 +420,19 @@ impl Rtc {
|
|||
))]
|
||||
regs.isr().modify(|w| w.set_wutf(false));
|
||||
|
||||
#[cfg(any(rtc_v3, rtc_v3u5))]
|
||||
#[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
|
||||
regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
|
||||
|
||||
#[cfg(not(stm32l5))]
|
||||
crate::pac::EXTI
|
||||
.pr(0)
|
||||
.modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
|
||||
|
||||
#[cfg(stm32l5)]
|
||||
crate::pac::EXTI
|
||||
.fpr(0)
|
||||
.modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
|
||||
|
||||
<RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -135,6 +135,12 @@ impl sealed::Instance for crate::peripherals::RTC {
|
|||
#[cfg(all(feature = "low-power", stm32g4))]
|
||||
type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
|
||||
|
||||
#[cfg(all(feature = "low-power", stm32l5))]
|
||||
const EXTI_WAKEUP_LINE: usize = 17;
|
||||
|
||||
#[cfg(all(feature = "low-power", stm32l5))]
|
||||
type WakeupInterrupt = crate::interrupt::typelevel::RTC;
|
||||
|
||||
fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> {
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
if register < Self::BACKUP_REGISTER_COUNT {
|
||||
|
|
|
@ -743,7 +743,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
|||
T::enable_and_reset();
|
||||
T::enable_and_reset();
|
||||
|
||||
Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
|
||||
Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config)
|
||||
}
|
||||
|
||||
/// Create a new bidirectional UART with request-to-send and clear-to-send pins
|
||||
|
@ -770,7 +770,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
|||
w.set_rtse(true);
|
||||
w.set_ctse(true);
|
||||
});
|
||||
Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
|
||||
Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config)
|
||||
}
|
||||
|
||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||
|
@ -795,10 +795,76 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
|||
T::regs().cr3().write(|w| {
|
||||
w.set_dem(true);
|
||||
});
|
||||
Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
|
||||
Self::new_inner_configure(peri, rx, tx, tx_dma, rx_dma, config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
/// Create a single-wire half-duplex Uart transceiver on a single Tx pin.
|
||||
///
|
||||
/// See [`new_half_duplex_on_rx`][`Self::new_half_duplex_on_rx`] if you would prefer to use an Rx pin.
|
||||
/// There is no functional difference between these methods, as both allow bidirectional communication.
|
||||
///
|
||||
/// The pin is always released when no data is transmitted. Thus, it acts as a standard
|
||||
/// I/O in idle or in reception.
|
||||
/// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
|
||||
/// on the line must be managed by software (for instance by using a centralized arbiter).
|
||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||
#[doc(alias("HDSEL"))]
|
||||
pub fn new_half_duplex(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
tx_dma: impl Peripheral<P = TxDma> + 'd,
|
||||
rx_dma: impl Peripheral<P = RxDma> + 'd,
|
||||
mut config: Config,
|
||||
) -> Result<Self, ConfigError> {
|
||||
// UartRx and UartTx have one refcount ea.
|
||||
T::enable_and_reset();
|
||||
T::enable_and_reset();
|
||||
|
||||
config.swap_rx_tx = false;
|
||||
|
||||
into_ref!(peri, tx, tx_dma, rx_dma);
|
||||
|
||||
T::regs().cr3().write(|w| w.set_hdsel(true));
|
||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||
|
||||
Self::new_inner(peri, tx_dma, rx_dma, config)
|
||||
}
|
||||
|
||||
/// Create a single-wire half-duplex Uart transceiver on a single Rx pin.
|
||||
///
|
||||
/// See [`new_half_duplex`][`Self::new_half_duplex`] if you would prefer to use an Tx pin.
|
||||
/// There is no functional difference between these methods, as both allow bidirectional communication.
|
||||
///
|
||||
/// The pin is always released when no data is transmitted. Thus, it acts as a standard
|
||||
/// I/O in idle or in reception.
|
||||
/// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
|
||||
/// on the line must be managed by software (for instance by using a centralized arbiter).
|
||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||
#[doc(alias("HDSEL"))]
|
||||
pub fn new_half_duplex_on_rx(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
tx_dma: impl Peripheral<P = TxDma> + 'd,
|
||||
rx_dma: impl Peripheral<P = RxDma> + 'd,
|
||||
mut config: Config,
|
||||
) -> Result<Self, ConfigError> {
|
||||
// UartRx and UartTx have one refcount ea.
|
||||
T::enable_and_reset();
|
||||
T::enable_and_reset();
|
||||
|
||||
config.swap_rx_tx = true;
|
||||
|
||||
into_ref!(peri, rx, tx_dma, rx_dma);
|
||||
|
||||
T::regs().cr3().write(|w| w.set_hdsel(true));
|
||||
rx.set_as_af(rx.af_num(), AFType::OutputPushPull);
|
||||
|
||||
Self::new_inner(peri, tx_dma, rx_dma, config)
|
||||
}
|
||||
|
||||
fn new_inner_configure(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
|
@ -808,8 +874,6 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
|||
) -> Result<Self, ConfigError> {
|
||||
into_ref!(peri, rx, tx, tx_dma, rx_dma);
|
||||
|
||||
let r = T::regs();
|
||||
|
||||
// Some chips do not have swap_rx_tx bit
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(usart_v3, usart_v4))] {
|
||||
|
@ -827,6 +891,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
|
|||
}
|
||||
}
|
||||
|
||||
Self::new_inner(peri, tx_dma, rx_dma, config)
|
||||
}
|
||||
|
||||
fn new_inner(
|
||||
peri: PeripheralRef<'d, T>,
|
||||
tx_dma: PeripheralRef<'d, TxDma>,
|
||||
rx_dma: PeripheralRef<'d, RxDma>,
|
||||
config: Config,
|
||||
) -> Result<Self, ConfigError> {
|
||||
let r = T::regs();
|
||||
|
||||
configure(r, &config, T::frequency(), T::KIND, true, true)?;
|
||||
|
||||
T::Interrupt::unpend();
|
||||
|
|
|
@ -701,10 +701,10 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
|
|||
}
|
||||
|
||||
async fn wait_enabled(&mut self) {
|
||||
trace!("wait_enabled OUT WAITING");
|
||||
trace!("wait_enabled IN WAITING");
|
||||
let index = self.info.addr.index();
|
||||
poll_fn(|cx| {
|
||||
EP_OUT_WAKERS[index].register(cx.waker());
|
||||
EP_IN_WAKERS[index].register(cx.waker());
|
||||
let regs = T::regs();
|
||||
if regs.epr(index).read().stat_tx() == Stat::DISABLED {
|
||||
Poll::Pending
|
||||
|
@ -713,7 +713,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
|
|||
}
|
||||
})
|
||||
.await;
|
||||
trace!("wait_enabled OUT OK");
|
||||
trace!("wait_enabled IN OK");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[toolchain]
|
||||
channel = "beta-2023-12-17"
|
||||
channel = "1.75"
|
||||
components = [ "rust-src", "rustfmt", "llvm-tools" ]
|
||||
targets = [
|
||||
"thumbv7em-none-eabi",
|
||||
|
|
Loading…
Reference in a new issue