aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGustav Toft <[email protected]>2024-04-11 08:27:30 +0200
committerGustav Toft <[email protected]>2024-04-11 08:27:30 +0200
commitd4ba6ccc3787624fbc5eee30b6d5c5361ee6e280 (patch)
tree572241f460b15e88ee8461f082a352c113a377ed
parent6663be0b36a078893b0ef3f3f869b17adf62ca30 (diff)
parent4ffe35c840f1a35e3bbc0cdb29203cbaac5abd08 (diff)
Merge branch 'main' of https://github.com/GustavToft/embassy
-rw-r--r--docs/modules/ROOT/pages/embassy_in_the_wild.adoc8
-rw-r--r--embassy-nrf/src/buffered_uarte.rs25
-rw-r--r--embassy-nrf/src/gpio.rs82
-rw-r--r--embassy-nrf/src/gpiote.rs14
-rw-r--r--embassy-nrf/src/i2s.rs54
-rw-r--r--embassy-nrf/src/pdm.rs41
-rw-r--r--embassy-nrf/src/ppi/mod.rs22
-rw-r--r--embassy-nrf/src/pwm.rs16
-rw-r--r--embassy-nrf/src/qdec.rs41
-rwxr-xr-xembassy-nrf/src/qspi.rs38
-rw-r--r--embassy-nrf/src/radio/mod.rs38
-rw-r--r--embassy-nrf/src/rng.rs81
-rw-r--r--embassy-nrf/src/saadc.rs16
-rw-r--r--embassy-nrf/src/spim.rs60
-rw-r--r--embassy-nrf/src/spis.rs41
-rw-r--r--embassy-nrf/src/timer.rs22
-rw-r--r--embassy-nrf/src/twim.rs35
-rw-r--r--embassy-nrf/src/twis.rs35
-rw-r--r--embassy-nrf/src/uarte.rs57
-rw-r--r--embassy-nrf/src/usb/mod.rs13
-rw-r--r--embassy-rp/src/adc.rs24
-rw-r--r--embassy-rp/src/clocks.rs11
-rw-r--r--embassy-rp/src/dma.rs23
-rw-r--r--embassy-rp/src/flash.rs16
-rw-r--r--embassy-rp/src/gpio.rs96
-rw-r--r--embassy-rp/src/i2c.rs51
-rw-r--r--embassy-rp/src/pio/mod.rs64
-rw-r--r--embassy-rp/src/pwm.rs45
-rw-r--r--embassy-rp/src/rtc/mod.rs11
-rw-r--r--embassy-rp/src/spi.rs27
-rw-r--r--embassy-rp/src/uart/mod.rs55
-rw-r--r--embassy-rp/src/usb.rs13
-rw-r--r--embassy-stm32/Cargo.toml7
-rw-r--r--embassy-stm32/build.rs24
-rw-r--r--embassy-stm32/src/adc/v3.rs14
-rw-r--r--embassy-stm32/src/cordic/enums.rs71
-rw-r--r--embassy-stm32/src/cordic/errors.rs144
-rw-r--r--embassy-stm32/src/cordic/mod.rs729
-rw-r--r--embassy-stm32/src/cordic/utils.rs62
-rw-r--r--embassy-stm32/src/i2c/mod.rs141
-rw-r--r--embassy-stm32/src/i2c/v1.rs628
-rw-r--r--embassy-stm32/src/i2c/v2.rs15
-rw-r--r--embassy-stm32/src/lib.rs7
-rw-r--r--embassy-stm32/src/ospi/enums.rs386
-rw-r--r--embassy-stm32/src/ospi/mod.rs1050
-rw-r--r--embassy-stm32/src/qspi/mod.rs53
-rw-r--r--embassy-stm32/src/rcc/mod.rs2
-rw-r--r--embassy-stm32/src/time_driver.rs45
-rw-r--r--embassy-stm32/src/timer/mod.rs135
-rw-r--r--embassy-stm32/src/usart/buffered.rs38
-rw-r--r--embassy-sync/CHANGELOG.md5
-rw-r--r--embassy-sync/src/channel.rs27
-rw-r--r--embassy-usb/src/builder.rs9
-rw-r--r--examples/rp/src/bin/pio_stepper.rs2
-rw-r--r--examples/rp/src/bin/pwm_input.rs3
-rw-r--r--examples/stm32f0/src/bin/multiprio.rs5
-rw-r--r--examples/stm32f3/src/bin/multiprio.rs5
-rw-r--r--examples/stm32f4/src/bin/multiprio.rs5
-rw-r--r--examples/stm32f4/src/bin/usb_hid_keyboard.rs1
-rw-r--r--examples/stm32h5/src/bin/cordic.rs78
-rw-r--r--examples/stm32h7/src/bin/multiprio.rs5
-rw-r--r--tests/rp/src/bin/pwm.rs46
-rw-r--r--tests/stm32/Cargo.toml15
-rw-r--r--tests/stm32/gen_test.py2
-rw-r--r--tests/stm32/src/bin/cordic.rs135
65 files changed, 3936 insertions, 1133 deletions
diff --git a/docs/modules/ROOT/pages/embassy_in_the_wild.adoc b/docs/modules/ROOT/pages/embassy_in_the_wild.adoc
index 85ad7f4a2..4b650449f 100644
--- a/docs/modules/ROOT/pages/embassy_in_the_wild.adoc
+++ b/docs/modules/ROOT/pages/embassy_in_the_wild.adoc
@@ -9,3 +9,11 @@ Here are known examples of real-world projects which make use of Embassy. Feel f
9* The link:https://github.com/lora-rs/lora-rs[lora-rs] project includes link:https://github.com/lora-rs/lora-rs/tree/main/examples/stm32l0/src/bin[various standalone examples] for NRF52840, RP2040, STM32L0 and STM32WL 9* The link:https://github.com/lora-rs/lora-rs[lora-rs] project includes link:https://github.com/lora-rs/lora-rs/tree/main/examples/stm32l0/src/bin[various standalone examples] for NRF52840, RP2040, STM32L0 and STM32WL
10** link:https://github.com/matoushybl/air-force-one[Air force one: A simple air quality monitoring system] 10** link:https://github.com/matoushybl/air-force-one[Air force one: A simple air quality monitoring system]
11*** Targets nRF52 and uses nrf-softdevice 11*** Targets nRF52 and uses nrf-softdevice
12
13* link:https://github.com/schmettow/ylab-edge-go[YLab Edge Go] and link:https://github.com/schmettow/ylab-edge-pro[YLab Edge Pro] projects develop
14firmware (RP2040, STM32) for capturing physiological data in behavioural science research. Included so far are:
15** biopotentials (analog ports)
16** motion capture (6-axis accelerometers)
17** air quality (CO2, Temp, Humidity)
18** comes with an app for capturing and visualizing data [link:https://github.com/schmettow/ystudio-zero[Ystudio]]
19
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index b04c96e09..385d4015e 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -20,8 +20,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
20// Re-export SVD variants to allow user to directly set values 20// Re-export SVD variants to allow user to directly set values
21pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; 21pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
22 22
23use crate::gpio::sealed::Pin; 23use crate::gpio::{AnyPin, Pin as GpioPin, PselBits, SealedPin};
24use crate::gpio::{AnyPin, Pin as GpioPin, PselBits};
25use crate::interrupt::typelevel::Interrupt; 24use crate::interrupt::typelevel::Interrupt;
26use crate::ppi::{ 25use crate::ppi::{
27 self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, 26 self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task,
@@ -30,19 +29,15 @@ use crate::timer::{Instance as TimerInstance, Timer};
30use crate::uarte::{configure, drop_tx_rx, Config, Instance as UarteInstance}; 29use crate::uarte::{configure, drop_tx_rx, Config, Instance as UarteInstance};
31use crate::{interrupt, pac, Peripheral}; 30use crate::{interrupt, pac, Peripheral};
32 31
33mod sealed { 32pub(crate) struct State {
34 use super::*; 33 tx_buf: RingBuffer,
35 34 tx_count: AtomicUsize,
36 pub struct State {
37 pub tx_buf: RingBuffer,
38 pub tx_count: AtomicUsize,
39 35
40 pub rx_buf: RingBuffer, 36 rx_buf: RingBuffer,
41 pub rx_started: AtomicBool, 37 rx_started: AtomicBool,
42 pub rx_started_count: AtomicU8, 38 rx_started_count: AtomicU8,
43 pub rx_ended_count: AtomicU8, 39 rx_ended_count: AtomicU8,
44 pub rx_ppi_ch: AtomicU8, 40 rx_ppi_ch: AtomicU8,
45 }
46} 41}
47 42
48/// UART error. 43/// UART error.
@@ -53,8 +48,6 @@ pub enum Error {
53 // No errors for now 48 // No errors for now
54} 49}
55 50
56pub(crate) use sealed::State;
57
58impl State { 51impl State {
59 pub(crate) const fn new() -> Self { 52 pub(crate) const fn new() -> Self {
60 Self { 53 Self {
diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs
index f2353f21d..7b272dca0 100644
--- a/embassy-nrf/src/gpio.rs
+++ b/embassy-nrf/src/gpio.rs
@@ -7,7 +7,6 @@ use core::hint::unreachable_unchecked;
7use cfg_if::cfg_if; 7use cfg_if::cfg_if;
8use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; 8use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
9 9
10use self::sealed::Pin as _;
11#[cfg(feature = "nrf51")] 10#[cfg(feature = "nrf51")]
12use crate::pac::gpio; 11use crate::pac::gpio;
13#[cfg(feature = "nrf51")] 12#[cfg(feature = "nrf51")]
@@ -361,59 +360,56 @@ impl<'d> Drop for Flex<'d> {
361 } 360 }
362} 361}
363 362
364pub(crate) mod sealed { 363pub(crate) trait SealedPin {
365 use super::*; 364 fn pin_port(&self) -> u8;
366
367 pub trait Pin {
368 fn pin_port(&self) -> u8;
369 365
370 #[inline] 366 #[inline]
371 fn _pin(&self) -> u8 { 367 fn _pin(&self) -> u8 {
372 cfg_if! { 368 cfg_if! {
373 if #[cfg(feature = "_gpio-p1")] { 369 if #[cfg(feature = "_gpio-p1")] {
374 self.pin_port() % 32 370 self.pin_port() % 32
375 } else { 371 } else {
376 self.pin_port() 372 self.pin_port()
377 }
378 } 373 }
379 } 374 }
375 }
380 376
381 #[inline] 377 #[inline]
382 fn block(&self) -> &gpio::RegisterBlock { 378 fn block(&self) -> &gpio::RegisterBlock {
383 unsafe { 379 unsafe {
384 match self.pin_port() / 32 { 380 match self.pin_port() / 32 {
385 #[cfg(feature = "nrf51")] 381 #[cfg(feature = "nrf51")]
386 0 => &*pac::GPIO::ptr(), 382 0 => &*pac::GPIO::ptr(),
387 #[cfg(not(feature = "nrf51"))] 383 #[cfg(not(feature = "nrf51"))]
388 0 => &*pac::P0::ptr(), 384 0 => &*pac::P0::ptr(),
389 #[cfg(feature = "_gpio-p1")] 385 #[cfg(feature = "_gpio-p1")]
390 1 => &*pac::P1::ptr(), 386 1 => &*pac::P1::ptr(),
391 _ => unreachable_unchecked(), 387 _ => unreachable_unchecked(),
392 }
393 } 388 }
394 } 389 }
390 }
395 391
396 #[inline] 392 #[inline]
397 fn conf(&self) -> &gpio::PIN_CNF { 393 fn conf(&self) -> &gpio::PIN_CNF {
398 &self.block().pin_cnf[self._pin() as usize] 394 &self.block().pin_cnf[self._pin() as usize]
399 } 395 }
400 396
401 /// Set the output as high. 397 /// Set the output as high.
402 #[inline] 398 #[inline]
403 fn set_high(&self) { 399 fn set_high(&self) {
404 unsafe { self.block().outset.write(|w| w.bits(1u32 << self._pin())) } 400 unsafe { self.block().outset.write(|w| w.bits(1u32 << self._pin())) }
405 } 401 }
406 402
407 /// Set the output as low. 403 /// Set the output as low.
408 #[inline] 404 #[inline]
409 fn set_low(&self) { 405 fn set_low(&self) {
410 unsafe { self.block().outclr.write(|w| w.bits(1u32 << self._pin())) } 406 unsafe { self.block().outclr.write(|w| w.bits(1u32 << self._pin())) }
411 }
412 } 407 }
413} 408}
414 409
415/// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an [AnyPin]. 410/// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an [AnyPin].
416pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static { 411#[allow(private_bounds)]
412pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + SealedPin + Sized + 'static {
417 /// Number of the pin within the port (0..31) 413 /// Number of the pin within the port (0..31)
418 #[inline] 414 #[inline]
419 fn pin(&self) -> u8 { 415 fn pin(&self) -> u8 {
@@ -464,7 +460,7 @@ impl AnyPin {
464 460
465impl_peripheral!(AnyPin); 461impl_peripheral!(AnyPin);
466impl Pin for AnyPin {} 462impl Pin for AnyPin {}
467impl sealed::Pin for AnyPin { 463impl SealedPin for AnyPin {
468 #[inline] 464 #[inline]
469 fn pin_port(&self) -> u8 { 465 fn pin_port(&self) -> u8 {
470 self.pin_port 466 self.pin_port
@@ -502,7 +498,7 @@ pub(crate) fn deconfigure_pin(psel_bits: u32) {
502macro_rules! impl_pin { 498macro_rules! impl_pin {
503 ($type:ident, $port_num:expr, $pin_num:expr) => { 499 ($type:ident, $port_num:expr, $pin_num:expr) => {
504 impl crate::gpio::Pin for peripherals::$type {} 500 impl crate::gpio::Pin for peripherals::$type {}
505 impl crate::gpio::sealed::Pin for peripherals::$type { 501 impl crate::gpio::SealedPin for peripherals::$type {
506 #[inline] 502 #[inline]
507 fn pin_port(&self) -> u8 { 503 fn pin_port(&self) -> u8 {
508 $port_num * 32 + $pin_num 504 $port_num * 32 + $pin_num
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index 4a28279a9..d7f075722 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -7,8 +7,7 @@ use core::task::{Context, Poll};
7use embassy_hal_internal::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; 7use embassy_hal_internal::{impl_peripheral, into_ref, Peripheral, PeripheralRef};
8use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
9 9
10use crate::gpio::sealed::Pin as _; 10use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin, SealedPin as _};
11use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin};
12use crate::interrupt::InterruptExt; 11use crate::interrupt::InterruptExt;
13use crate::ppi::{Event, Task}; 12use crate::ppi::{Event, Task};
14use crate::{interrupt, pac, peripherals}; 13use crate::{interrupt, pac, peripherals};
@@ -446,14 +445,13 @@ impl<'d> Flex<'d> {
446 445
447// ======================= 446// =======================
448 447
449mod sealed { 448trait SealedChannel {}
450 pub trait Channel {}
451}
452 449
453/// GPIOTE channel trait. 450/// GPIOTE channel trait.
454/// 451///
455/// Implemented by all GPIOTE channels. 452/// Implemented by all GPIOTE channels.
456pub trait Channel: sealed::Channel + Into<AnyChannel> + Sized + 'static { 453#[allow(private_bounds)]
454pub trait Channel: SealedChannel + Into<AnyChannel> + Sized + 'static {
457 /// Get the channel number. 455 /// Get the channel number.
458 fn number(&self) -> usize; 456 fn number(&self) -> usize;
459 457
@@ -478,7 +476,7 @@ pub struct AnyChannel {
478 number: u8, 476 number: u8,
479} 477}
480impl_peripheral!(AnyChannel); 478impl_peripheral!(AnyChannel);
481impl sealed::Channel for AnyChannel {} 479impl SealedChannel for AnyChannel {}
482impl Channel for AnyChannel { 480impl Channel for AnyChannel {
483 fn number(&self) -> usize { 481 fn number(&self) -> usize {
484 self.number as usize 482 self.number as usize
@@ -487,7 +485,7 @@ impl Channel for AnyChannel {
487 485
488macro_rules! impl_channel { 486macro_rules! impl_channel {
489 ($type:ident, $number:expr) => { 487 ($type:ident, $number:expr) => {
490 impl sealed::Channel for peripherals::$type {} 488 impl SealedChannel for peripherals::$type {}
491 impl Channel for peripherals::$type { 489 impl Channel for peripherals::$type {
492 fn number(&self) -> usize { 490 fn number(&self) -> usize {
493 $number as usize 491 $number as usize
diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs
index 907acdf4c..966271ed9 100644
--- a/embassy-nrf/src/i2s.rs
+++ b/embassy-nrf/src/i2s.rs
@@ -6,11 +6,12 @@ use core::future::poll_fn;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::mem::size_of; 7use core::mem::size_of;
8use core::ops::{Deref, DerefMut}; 8use core::ops::{Deref, DerefMut};
9use core::sync::atomic::{compiler_fence, Ordering}; 9use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
10use core::task::Poll; 10use core::task::Poll;
11 11
12use embassy_hal_internal::drop::OnDrop; 12use embassy_hal_internal::drop::OnDrop;
13use embassy_hal_internal::{into_ref, PeripheralRef}; 13use embassy_hal_internal::{into_ref, PeripheralRef};
14use embassy_sync::waitqueue::AtomicWaker;
14 15
15use crate::gpio::{AnyPin, Pin as GpioPin}; 16use crate::gpio::{AnyPin, Pin as GpioPin};
16use crate::interrupt::typelevel::Interrupt; 17use crate::interrupt::typelevel::Interrupt;
@@ -1140,50 +1141,45 @@ impl<S: Sample, const NB: usize, const NS: usize> MultiBuffering<S, NB, NS> {
1140 } 1141 }
1141} 1142}
1142 1143
1143pub(crate) mod sealed { 1144/// Peripheral static state
1144 use core::sync::atomic::AtomicBool; 1145pub(crate) struct State {
1145 1146 started: AtomicBool,
1146 use embassy_sync::waitqueue::AtomicWaker; 1147 rx_waker: AtomicWaker,
1147 1148 tx_waker: AtomicWaker,
1148 /// Peripheral static state 1149 stop_waker: AtomicWaker,
1149 pub struct State { 1150}
1150 pub started: AtomicBool,
1151 pub rx_waker: AtomicWaker,
1152 pub tx_waker: AtomicWaker,
1153 pub stop_waker: AtomicWaker,
1154 }
1155 1151
1156 impl State { 1152impl State {
1157 pub const fn new() -> Self { 1153 pub(crate) const fn new() -> Self {
1158 Self { 1154 Self {
1159 started: AtomicBool::new(false), 1155 started: AtomicBool::new(false),
1160 rx_waker: AtomicWaker::new(), 1156 rx_waker: AtomicWaker::new(),
1161 tx_waker: AtomicWaker::new(), 1157 tx_waker: AtomicWaker::new(),
1162 stop_waker: AtomicWaker::new(), 1158 stop_waker: AtomicWaker::new(),
1163 }
1164 } 1159 }
1165 } 1160 }
1161}
1166 1162
1167 pub trait Instance { 1163pub(crate) trait SealedInstance {
1168 fn regs() -> &'static crate::pac::i2s::RegisterBlock; 1164 fn regs() -> &'static crate::pac::i2s::RegisterBlock;
1169 fn state() -> &'static State; 1165 fn state() -> &'static State;
1170 }
1171} 1166}
1172 1167
1173/// I2S peripheral instance. 1168/// I2S peripheral instance.
1174pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 1169#[allow(private_bounds)]
1170pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
1175 /// Interrupt for this peripheral. 1171 /// Interrupt for this peripheral.
1176 type Interrupt: interrupt::typelevel::Interrupt; 1172 type Interrupt: interrupt::typelevel::Interrupt;
1177} 1173}
1178 1174
1179macro_rules! impl_i2s { 1175macro_rules! impl_i2s {
1180 ($type:ident, $pac_type:ident, $irq:ident) => { 1176 ($type:ident, $pac_type:ident, $irq:ident) => {
1181 impl crate::i2s::sealed::Instance for peripherals::$type { 1177 impl crate::i2s::SealedInstance for peripherals::$type {
1182 fn regs() -> &'static crate::pac::i2s::RegisterBlock { 1178 fn regs() -> &'static crate::pac::i2s::RegisterBlock {
1183 unsafe { &*pac::$pac_type::ptr() } 1179 unsafe { &*pac::$pac_type::ptr() }
1184 } 1180 }
1185 fn state() -> &'static crate::i2s::sealed::State { 1181 fn state() -> &'static crate::i2s::State {
1186 static STATE: crate::i2s::sealed::State = crate::i2s::sealed::State::new(); 1182 static STATE: crate::i2s::State = crate::i2s::State::new();
1187 &STATE 1183 &STATE
1188 } 1184 }
1189 } 1185 }
diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs
index 754d38310..ef2662c85 100644
--- a/embassy-nrf/src/pdm.rs
+++ b/embassy-nrf/src/pdm.rs
@@ -9,11 +9,11 @@ use core::task::Poll;
9 9
10use embassy_hal_internal::drop::OnDrop; 10use embassy_hal_internal::drop::OnDrop;
11use embassy_hal_internal::{into_ref, PeripheralRef}; 11use embassy_hal_internal::{into_ref, PeripheralRef};
12use embassy_sync::waitqueue::AtomicWaker;
12use fixed::types::I7F1; 13use fixed::types::I7F1;
13 14
14use crate::chip::EASY_DMA_SIZE; 15use crate::chip::EASY_DMA_SIZE;
15use crate::gpio::sealed::Pin; 16use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin};
16use crate::gpio::{AnyPin, Pin as GpioPin};
17use crate::interrupt::typelevel::Interrupt; 17use crate::interrupt::typelevel::Interrupt;
18use crate::pac::pdm::mode::{EDGE_A, OPERATION_A}; 18use crate::pac::pdm::mode::{EDGE_A, OPERATION_A};
19pub use crate::pac::pdm::pdmclkctrl::FREQ_A as Frequency; 19pub use crate::pac::pdm::pdmclkctrl::FREQ_A as Frequency;
@@ -451,42 +451,39 @@ impl<'d, T: Instance> Drop for Pdm<'d, T> {
451 } 451 }
452} 452}
453 453
454pub(crate) mod sealed { 454/// Peripheral static state
455 use embassy_sync::waitqueue::AtomicWaker; 455pub(crate) struct State {
456 456 waker: AtomicWaker,
457 /// Peripheral static state 457}
458 pub struct State {
459 pub waker: AtomicWaker,
460 }
461 458
462 impl State { 459impl State {
463 pub const fn new() -> Self { 460 pub(crate) const fn new() -> Self {
464 Self { 461 Self {
465 waker: AtomicWaker::new(), 462 waker: AtomicWaker::new(),
466 }
467 } 463 }
468 } 464 }
465}
469 466
470 pub trait Instance { 467pub(crate) trait SealedInstance {
471 fn regs() -> &'static crate::pac::pdm::RegisterBlock; 468 fn regs() -> &'static crate::pac::pdm::RegisterBlock;
472 fn state() -> &'static State; 469 fn state() -> &'static State;
473 }
474} 470}
475 471
476/// PDM peripheral instance 472/// PDM peripheral instance
477pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 473#[allow(private_bounds)]
474pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
478 /// Interrupt for this peripheral 475 /// Interrupt for this peripheral
479 type Interrupt: interrupt::typelevel::Interrupt; 476 type Interrupt: interrupt::typelevel::Interrupt;
480} 477}
481 478
482macro_rules! impl_pdm { 479macro_rules! impl_pdm {
483 ($type:ident, $pac_type:ident, $irq:ident) => { 480 ($type:ident, $pac_type:ident, $irq:ident) => {
484 impl crate::pdm::sealed::Instance for peripherals::$type { 481 impl crate::pdm::SealedInstance for peripherals::$type {
485 fn regs() -> &'static crate::pac::pdm::RegisterBlock { 482 fn regs() -> &'static crate::pac::pdm::RegisterBlock {
486 unsafe { &*pac::$pac_type::ptr() } 483 unsafe { &*pac::$pac_type::ptr() }
487 } 484 }
488 fn state() -> &'static crate::pdm::sealed::State { 485 fn state() -> &'static crate::pdm::State {
489 static STATE: crate::pdm::sealed::State = crate::pdm::sealed::State::new(); 486 static STATE: crate::pdm::State = crate::pdm::State::new();
490 &STATE 487 &STATE
491 } 488 }
492 } 489 }
diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs
index f5764b8b7..13f7dcc83 100644
--- a/embassy-nrf/src/ppi/mod.rs
+++ b/embassy-nrf/src/ppi/mod.rs
@@ -210,13 +210,12 @@ unsafe impl Send for Event<'_> {}
210// ====================== 210// ======================
211// traits 211// traits
212 212
213pub(crate) mod sealed { 213pub(crate) trait SealedChannel {}
214 pub trait Channel {} 214pub(crate) trait SealedGroup {}
215 pub trait Group {}
216}
217 215
218/// Interface for PPI channels. 216/// Interface for PPI channels.
219pub trait Channel: sealed::Channel + Peripheral<P = Self> + Sized + 'static { 217#[allow(private_bounds)]
218pub trait Channel: SealedChannel + Peripheral<P = Self> + Sized + 'static {
220 /// Returns the number of the channel 219 /// Returns the number of the channel
221 fn number(&self) -> usize; 220 fn number(&self) -> usize;
222} 221}
@@ -234,7 +233,8 @@ pub trait StaticChannel: Channel + Into<AnyStaticChannel> {
234} 233}
235 234
236/// Interface for a group of PPI channels. 235/// Interface for a group of PPI channels.
237pub trait Group: sealed::Group + Peripheral<P = Self> + Into<AnyGroup> + Sized + 'static { 236#[allow(private_bounds)]
237pub trait Group: SealedGroup + Peripheral<P = Self> + Into<AnyGroup> + Sized + 'static {
238 /// Returns the number of the group. 238 /// Returns the number of the group.
239 fn number(&self) -> usize; 239 fn number(&self) -> usize;
240 /// Convert into a type erased group. 240 /// Convert into a type erased group.
@@ -254,7 +254,7 @@ pub struct AnyStaticChannel {
254 pub(crate) number: u8, 254 pub(crate) number: u8,
255} 255}
256impl_peripheral!(AnyStaticChannel); 256impl_peripheral!(AnyStaticChannel);
257impl sealed::Channel for AnyStaticChannel {} 257impl SealedChannel for AnyStaticChannel {}
258impl Channel for AnyStaticChannel { 258impl Channel for AnyStaticChannel {
259 fn number(&self) -> usize { 259 fn number(&self) -> usize {
260 self.number as usize 260 self.number as usize
@@ -272,7 +272,7 @@ pub struct AnyConfigurableChannel {
272 pub(crate) number: u8, 272 pub(crate) number: u8,
273} 273}
274impl_peripheral!(AnyConfigurableChannel); 274impl_peripheral!(AnyConfigurableChannel);
275impl sealed::Channel for AnyConfigurableChannel {} 275impl SealedChannel for AnyConfigurableChannel {}
276impl Channel for AnyConfigurableChannel { 276impl Channel for AnyConfigurableChannel {
277 fn number(&self) -> usize { 277 fn number(&self) -> usize {
278 self.number as usize 278 self.number as usize
@@ -287,7 +287,7 @@ impl ConfigurableChannel for AnyConfigurableChannel {
287#[cfg(not(feature = "nrf51"))] 287#[cfg(not(feature = "nrf51"))]
288macro_rules! impl_ppi_channel { 288macro_rules! impl_ppi_channel {
289 ($type:ident, $number:expr) => { 289 ($type:ident, $number:expr) => {
290 impl crate::ppi::sealed::Channel for peripherals::$type {} 290 impl crate::ppi::SealedChannel for peripherals::$type {}
291 impl crate::ppi::Channel for peripherals::$type { 291 impl crate::ppi::Channel for peripherals::$type {
292 fn number(&self) -> usize { 292 fn number(&self) -> usize {
293 $number 293 $number
@@ -338,7 +338,7 @@ pub struct AnyGroup {
338 number: u8, 338 number: u8,
339} 339}
340impl_peripheral!(AnyGroup); 340impl_peripheral!(AnyGroup);
341impl sealed::Group for AnyGroup {} 341impl SealedGroup for AnyGroup {}
342impl Group for AnyGroup { 342impl Group for AnyGroup {
343 fn number(&self) -> usize { 343 fn number(&self) -> usize {
344 self.number as usize 344 self.number as usize
@@ -347,7 +347,7 @@ impl Group for AnyGroup {
347 347
348macro_rules! impl_group { 348macro_rules! impl_group {
349 ($type:ident, $number:expr) => { 349 ($type:ident, $number:expr) => {
350 impl sealed::Group for peripherals::$type {} 350 impl SealedGroup for peripherals::$type {}
351 impl Group for peripherals::$type { 351 impl Group for peripherals::$type {
352 fn number(&self) -> usize { 352 fn number(&self) -> usize {
353 $number 353 $number
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index 833370d4b..1318d3f94 100644
--- a/embassy-nrf/src/pwm.rs
+++ b/embassy-nrf/src/pwm.rs
@@ -6,8 +6,7 @@ use core::sync::atomic::{compiler_fence, Ordering};
6 6
7use embassy_hal_internal::{into_ref, PeripheralRef}; 7use embassy_hal_internal::{into_ref, PeripheralRef};
8 8
9use crate::gpio::sealed::Pin as _; 9use crate::gpio::{AnyPin, Pin as GpioPin, PselBits, SealedPin as _};
10use crate::gpio::{AnyPin, Pin as GpioPin, PselBits};
11use crate::ppi::{Event, Task}; 10use crate::ppi::{Event, Task};
12use crate::util::slice_in_ram_or; 11use crate::util::slice_in_ram_or;
13use crate::{interrupt, pac, Peripheral}; 12use crate::{interrupt, pac, Peripheral};
@@ -847,23 +846,20 @@ impl<'a, T: Instance> Drop for SimplePwm<'a, T> {
847 } 846 }
848} 847}
849 848
850pub(crate) mod sealed { 849pub(crate) trait SealedInstance {
851 use super::*; 850 fn regs() -> &'static pac::pwm0::RegisterBlock;
852
853 pub trait Instance {
854 fn regs() -> &'static pac::pwm0::RegisterBlock;
855 }
856} 851}
857 852
858/// PWM peripheral instance. 853/// PWM peripheral instance.
859pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 854#[allow(private_bounds)]
855pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static {
860 /// Interrupt for this peripheral. 856 /// Interrupt for this peripheral.
861 type Interrupt: interrupt::typelevel::Interrupt; 857 type Interrupt: interrupt::typelevel::Interrupt;
862} 858}
863 859
864macro_rules! impl_pwm { 860macro_rules! impl_pwm {
865 ($type:ident, $pac_type:ident, $irq:ident) => { 861 ($type:ident, $pac_type:ident, $irq:ident) => {
866 impl crate::pwm::sealed::Instance for peripherals::$type { 862 impl crate::pwm::SealedInstance for peripherals::$type {
867 fn regs() -> &'static pac::pwm0::RegisterBlock { 863 fn regs() -> &'static pac::pwm0::RegisterBlock {
868 unsafe { &*pac::$pac_type::ptr() } 864 unsafe { &*pac::$pac_type::ptr() }
869 } 865 }
diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs
index 9455ec925..7409c9b1e 100644
--- a/embassy-nrf/src/qdec.rs
+++ b/embassy-nrf/src/qdec.rs
@@ -7,9 +7,9 @@ use core::marker::PhantomData;
7use core::task::Poll; 7use core::task::Poll;
8 8
9use embassy_hal_internal::{into_ref, PeripheralRef}; 9use embassy_hal_internal::{into_ref, PeripheralRef};
10use embassy_sync::waitqueue::AtomicWaker;
10 11
11use crate::gpio::sealed::Pin as _; 12use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin as _};
12use crate::gpio::{AnyPin, Pin as GpioPin};
13use crate::interrupt::typelevel::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
14use crate::{interrupt, Peripheral}; 14use crate::{interrupt, Peripheral};
15 15
@@ -245,42 +245,39 @@ pub enum LedPolarity {
245 ActiveLow, 245 ActiveLow,
246} 246}
247 247
248pub(crate) mod sealed { 248/// Peripheral static state
249 use embassy_sync::waitqueue::AtomicWaker; 249pub(crate) struct State {
250 250 waker: AtomicWaker,
251 /// Peripheral static state 251}
252 pub struct State {
253 pub waker: AtomicWaker,
254 }
255 252
256 impl State { 253impl State {
257 pub const fn new() -> Self { 254 pub(crate) const fn new() -> Self {
258 Self { 255 Self {
259 waker: AtomicWaker::new(), 256 waker: AtomicWaker::new(),
260 }
261 } 257 }
262 } 258 }
259}
263 260
264 pub trait Instance { 261pub(crate) trait SealedInstance {
265 fn regs() -> &'static crate::pac::qdec::RegisterBlock; 262 fn regs() -> &'static crate::pac::qdec::RegisterBlock;
266 fn state() -> &'static State; 263 fn state() -> &'static State;
267 }
268} 264}
269 265
270/// qdec peripheral instance. 266/// qdec peripheral instance.
271pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 267#[allow(private_bounds)]
268pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
272 /// Interrupt for this peripheral. 269 /// Interrupt for this peripheral.
273 type Interrupt: interrupt::typelevel::Interrupt; 270 type Interrupt: interrupt::typelevel::Interrupt;
274} 271}
275 272
276macro_rules! impl_qdec { 273macro_rules! impl_qdec {
277 ($type:ident, $pac_type:ident, $irq:ident) => { 274 ($type:ident, $pac_type:ident, $irq:ident) => {
278 impl crate::qdec::sealed::Instance for peripherals::$type { 275 impl crate::qdec::SealedInstance for peripherals::$type {
279 fn regs() -> &'static crate::pac::qdec::RegisterBlock { 276 fn regs() -> &'static crate::pac::qdec::RegisterBlock {
280 unsafe { &*pac::$pac_type::ptr() } 277 unsafe { &*pac::$pac_type::ptr() }
281 } 278 }
282 fn state() -> &'static crate::qdec::sealed::State { 279 fn state() -> &'static crate::qdec::State {
283 static STATE: crate::qdec::sealed::State = crate::qdec::sealed::State::new(); 280 static STATE: crate::qdec::State = crate::qdec::State::new();
284 &STATE 281 &STATE
285 } 282 }
286 } 283 }
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs
index 4134a4c87..060fe72cd 100755
--- a/embassy-nrf/src/qspi.rs
+++ b/embassy-nrf/src/qspi.rs
@@ -9,6 +9,7 @@ use core::task::Poll;
9 9
10use embassy_hal_internal::drop::OnDrop; 10use embassy_hal_internal::drop::OnDrop;
11use embassy_hal_internal::{into_ref, PeripheralRef}; 11use embassy_hal_internal::{into_ref, PeripheralRef};
12use embassy_sync::waitqueue::AtomicWaker;
12use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; 13use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
13 14
14use crate::gpio::{self, Pin as GpioPin}; 15use crate::gpio::{self, Pin as GpioPin};
@@ -652,42 +653,39 @@ mod _eh1 {
652 impl<'d, T: Instance> embedded_storage_async::nor_flash::MultiwriteNorFlash for Qspi<'d, T> {} 653 impl<'d, T: Instance> embedded_storage_async::nor_flash::MultiwriteNorFlash for Qspi<'d, T> {}
653} 654}
654 655
655pub(crate) mod sealed { 656/// Peripheral static state
656 use embassy_sync::waitqueue::AtomicWaker; 657pub(crate) struct State {
657 658 waker: AtomicWaker,
658 /// Peripheral static state 659}
659 pub struct State {
660 pub waker: AtomicWaker,
661 }
662 660
663 impl State { 661impl State {
664 pub const fn new() -> Self { 662 pub(crate) const fn new() -> Self {
665 Self { 663 Self {
666 waker: AtomicWaker::new(), 664 waker: AtomicWaker::new(),
667 }
668 } 665 }
669 } 666 }
667}
670 668
671 pub trait Instance { 669pub(crate) trait SealedInstance {
672 fn regs() -> &'static crate::pac::qspi::RegisterBlock; 670 fn regs() -> &'static crate::pac::qspi::RegisterBlock;
673 fn state() -> &'static State; 671 fn state() -> &'static State;
674 }
675} 672}
676 673
677/// QSPI peripheral instance. 674/// QSPI peripheral instance.
678pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 675#[allow(private_bounds)]
676pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
679 /// Interrupt for this peripheral. 677 /// Interrupt for this peripheral.
680 type Interrupt: interrupt::typelevel::Interrupt; 678 type Interrupt: interrupt::typelevel::Interrupt;
681} 679}
682 680
683macro_rules! impl_qspi { 681macro_rules! impl_qspi {
684 ($type:ident, $pac_type:ident, $irq:ident) => { 682 ($type:ident, $pac_type:ident, $irq:ident) => {
685 impl crate::qspi::sealed::Instance for peripherals::$type { 683 impl crate::qspi::SealedInstance for peripherals::$type {
686 fn regs() -> &'static crate::pac::qspi::RegisterBlock { 684 fn regs() -> &'static crate::pac::qspi::RegisterBlock {
687 unsafe { &*pac::$pac_type::ptr() } 685 unsafe { &*pac::$pac_type::ptr() }
688 } 686 }
689 fn state() -> &'static crate::qspi::sealed::State { 687 fn state() -> &'static crate::qspi::State {
690 static STATE: crate::qspi::sealed::State = crate::qspi::sealed::State::new(); 688 static STATE: crate::qspi::State = crate::qspi::State::new();
691 &STATE 689 &STATE
692 } 690 }
693 } 691 }
diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs
index 4c0cc3280..8edca1df2 100644
--- a/embassy-nrf/src/radio/mod.rs
+++ b/embassy-nrf/src/radio/mod.rs
@@ -19,6 +19,7 @@ pub mod ieee802154;
19 19
20use core::marker::PhantomData; 20use core::marker::PhantomData;
21 21
22use embassy_sync::waitqueue::AtomicWaker;
22use pac::radio::state::STATE_A as RadioState; 23use pac::radio::state::STATE_A as RadioState;
23pub use pac::radio::txpower::TXPOWER_A as TxPower; 24pub use pac::radio::txpower::TXPOWER_A as TxPower;
24 25
@@ -56,36 +57,32 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
56 } 57 }
57} 58}
58 59
59pub(crate) mod sealed { 60pub(crate) struct State {
60 use embassy_sync::waitqueue::AtomicWaker; 61 /// end packet transmission or reception
61 62 event_waker: AtomicWaker,
62 pub struct State { 63}
63 /// end packet transmission or reception 64impl State {
64 pub event_waker: AtomicWaker, 65 pub(crate) const fn new() -> Self {
65 } 66 Self {
66 impl State { 67 event_waker: AtomicWaker::new(),
67 pub const fn new() -> Self {
68 Self {
69 event_waker: AtomicWaker::new(),
70 }
71 } 68 }
72 } 69 }
70}
73 71
74 pub trait Instance { 72pub(crate) trait SealedInstance {
75 fn regs() -> &'static crate::pac::radio::RegisterBlock; 73 fn regs() -> &'static crate::pac::radio::RegisterBlock;
76 fn state() -> &'static State; 74 fn state() -> &'static State;
77 }
78} 75}
79 76
80macro_rules! impl_radio { 77macro_rules! impl_radio {
81 ($type:ident, $pac_type:ident, $irq:ident) => { 78 ($type:ident, $pac_type:ident, $irq:ident) => {
82 impl crate::radio::sealed::Instance for peripherals::$type { 79 impl crate::radio::SealedInstance for peripherals::$type {
83 fn regs() -> &'static pac::radio::RegisterBlock { 80 fn regs() -> &'static pac::radio::RegisterBlock {
84 unsafe { &*pac::$pac_type::ptr() } 81 unsafe { &*pac::$pac_type::ptr() }
85 } 82 }
86 83
87 fn state() -> &'static crate::radio::sealed::State { 84 fn state() -> &'static crate::radio::State {
88 static STATE: crate::radio::sealed::State = crate::radio::sealed::State::new(); 85 static STATE: crate::radio::State = crate::radio::State::new();
89 &STATE 86 &STATE
90 } 87 }
91 } 88 }
@@ -96,7 +93,8 @@ macro_rules! impl_radio {
96} 93}
97 94
98/// Radio peripheral instance. 95/// Radio peripheral instance.
99pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 96#[allow(private_bounds)]
97pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
100 /// Interrupt for this peripheral. 98 /// Interrupt for this peripheral.
101 type Interrupt: interrupt::typelevel::Interrupt; 99 type Interrupt: interrupt::typelevel::Interrupt;
102} 100}
diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs
index 1c463fb7c..ff61e08f3 100644
--- a/embassy-nrf/src/rng.rs
+++ b/embassy-nrf/src/rng.rs
@@ -2,13 +2,16 @@
2 2
3#![macro_use] 3#![macro_use]
4 4
5use core::cell::{RefCell, RefMut};
5use core::future::poll_fn; 6use core::future::poll_fn;
6use core::marker::PhantomData; 7use core::marker::PhantomData;
7use core::ptr; 8use core::ptr;
8use core::task::Poll; 9use core::task::Poll;
9 10
11use critical_section::{CriticalSection, Mutex};
10use embassy_hal_internal::drop::OnDrop; 12use embassy_hal_internal::drop::OnDrop;
11use embassy_hal_internal::{into_ref, PeripheralRef}; 13use embassy_hal_internal::{into_ref, PeripheralRef};
14use embassy_sync::waitqueue::WakerRegistration;
12 15
13use crate::interrupt::typelevel::Interrupt; 16use crate::interrupt::typelevel::Interrupt;
14use crate::{interrupt, Peripheral}; 17use crate::{interrupt, Peripheral};
@@ -205,73 +208,61 @@ impl<'d, T: Instance> rand_core::RngCore for Rng<'d, T> {
205 208
206impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {} 209impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {}
207 210
208pub(crate) mod sealed { 211/// Peripheral static state
209 use core::cell::{Ref, RefCell, RefMut}; 212pub(crate) struct State {
210 213 inner: Mutex<RefCell<InnerState>>,
211 use critical_section::{CriticalSection, Mutex}; 214}
212 use embassy_sync::waitqueue::WakerRegistration;
213
214 use super::*;
215
216 /// Peripheral static state
217 pub struct State {
218 inner: Mutex<RefCell<InnerState>>,
219 }
220
221 pub struct InnerState {
222 pub ptr: *mut u8,
223 pub end: *mut u8,
224 pub waker: WakerRegistration,
225 }
226 215
227 unsafe impl Send for InnerState {} 216struct InnerState {
217 ptr: *mut u8,
218 end: *mut u8,
219 waker: WakerRegistration,
220}
228 221
229 impl State { 222unsafe impl Send for InnerState {}
230 pub const fn new() -> Self {
231 Self {
232 inner: Mutex::new(RefCell::new(InnerState::new())),
233 }
234 }
235 223
236 pub fn borrow<'cs>(&'cs self, cs: CriticalSection<'cs>) -> Ref<'cs, InnerState> { 224impl State {
237 self.inner.borrow(cs).borrow() 225 pub(crate) const fn new() -> Self {
226 Self {
227 inner: Mutex::new(RefCell::new(InnerState::new())),
238 } 228 }
229 }
239 230
240 pub fn borrow_mut<'cs>(&'cs self, cs: CriticalSection<'cs>) -> RefMut<'cs, InnerState> { 231 fn borrow_mut<'cs>(&'cs self, cs: CriticalSection<'cs>) -> RefMut<'cs, InnerState> {
241 self.inner.borrow(cs).borrow_mut() 232 self.inner.borrow(cs).borrow_mut()
242 }
243 } 233 }
234}
244 235
245 impl InnerState { 236impl InnerState {
246 pub const fn new() -> Self { 237 const fn new() -> Self {
247 Self { 238 Self {
248 ptr: ptr::null_mut(), 239 ptr: ptr::null_mut(),
249 end: ptr::null_mut(), 240 end: ptr::null_mut(),
250 waker: WakerRegistration::new(), 241 waker: WakerRegistration::new(),
251 }
252 } 242 }
253 } 243 }
244}
254 245
255 pub trait Instance { 246pub(crate) trait SealedInstance {
256 fn regs() -> &'static crate::pac::rng::RegisterBlock; 247 fn regs() -> &'static crate::pac::rng::RegisterBlock;
257 fn state() -> &'static State; 248 fn state() -> &'static State;
258 }
259} 249}
260 250
261/// RNG peripheral instance. 251/// RNG peripheral instance.
262pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 252#[allow(private_bounds)]
253pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
263 /// Interrupt for this peripheral. 254 /// Interrupt for this peripheral.
264 type Interrupt: interrupt::typelevel::Interrupt; 255 type Interrupt: interrupt::typelevel::Interrupt;
265} 256}
266 257
267macro_rules! impl_rng { 258macro_rules! impl_rng {
268 ($type:ident, $pac_type:ident, $irq:ident) => { 259 ($type:ident, $pac_type:ident, $irq:ident) => {
269 impl crate::rng::sealed::Instance for peripherals::$type { 260 impl crate::rng::SealedInstance for peripherals::$type {
270 fn regs() -> &'static crate::pac::rng::RegisterBlock { 261 fn regs() -> &'static crate::pac::rng::RegisterBlock {
271 unsafe { &*pac::$pac_type::ptr() } 262 unsafe { &*pac::$pac_type::ptr() }
272 } 263 }
273 fn state() -> &'static crate::rng::sealed::State { 264 fn state() -> &'static crate::rng::State {
274 static STATE: crate::rng::sealed::State = crate::rng::sealed::State::new(); 265 static STATE: crate::rng::State = crate::rng::State::new();
275 &STATE 266 &STATE
276 } 267 }
277 } 268 }
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs
index 662b05614..17c65fa3e 100644
--- a/embassy-nrf/src/saadc.rs
+++ b/embassy-nrf/src/saadc.rs
@@ -16,7 +16,6 @@ pub(crate) use saadc::ch::pselp::PSELP_A as InputChannel;
16use saadc::oversample::OVERSAMPLE_A; 16use saadc::oversample::OVERSAMPLE_A;
17use saadc::resolution::VAL_A; 17use saadc::resolution::VAL_A;
18 18
19use self::sealed::Input as _;
20use crate::interrupt::InterruptExt; 19use crate::interrupt::InterruptExt;
21use crate::ppi::{ConfigurableChannel, Event, Ppi, Task}; 20use crate::ppi::{ConfigurableChannel, Event, Ppi, Task};
22use crate::timer::{Frequency, Instance as TimerInstance, Timer}; 21use crate::timer::{Frequency, Instance as TimerInstance, Timer};
@@ -662,16 +661,13 @@ pub enum Resolution {
662 _14BIT = 3, 661 _14BIT = 3,
663} 662}
664 663
665pub(crate) mod sealed { 664pub(crate) trait SealedInput {
666 use super::*; 665 fn channel(&self) -> InputChannel;
667
668 pub trait Input {
669 fn channel(&self) -> InputChannel;
670 }
671} 666}
672 667
673/// An input that can be used as either or negative end of a ADC differential in the SAADC periperhal. 668/// An input that can be used as either or negative end of a ADC differential in the SAADC periperhal.
674pub trait Input: sealed::Input + Into<AnyInput> + Peripheral<P = Self> + Sized + 'static { 669#[allow(private_bounds)]
670pub trait Input: SealedInput + Into<AnyInput> + Peripheral<P = Self> + Sized + 'static {
675 /// Convert this SAADC input to a type-erased `AnyInput`. 671 /// Convert this SAADC input to a type-erased `AnyInput`.
676 /// 672 ///
677 /// This allows using several inputs in situations that might require 673 /// This allows using several inputs in situations that might require
@@ -693,7 +689,7 @@ pub struct AnyInput {
693 689
694impl_peripheral!(AnyInput); 690impl_peripheral!(AnyInput);
695 691
696impl sealed::Input for AnyInput { 692impl SealedInput for AnyInput {
697 fn channel(&self) -> InputChannel { 693 fn channel(&self) -> InputChannel {
698 self.channel 694 self.channel
699 } 695 }
@@ -706,7 +702,7 @@ macro_rules! impl_saadc_input {
706 impl_saadc_input!(@local, crate::peripherals::$pin, $ch); 702 impl_saadc_input!(@local, crate::peripherals::$pin, $ch);
707 }; 703 };
708 (@local, $pin:ty, $ch:ident) => { 704 (@local, $pin:ty, $ch:ident) => {
709 impl crate::saadc::sealed::Input for $pin { 705 impl crate::saadc::SealedInput for $pin {
710 fn channel(&self) -> crate::saadc::InputChannel { 706 fn channel(&self) -> crate::saadc::InputChannel {
711 crate::saadc::InputChannel::$ch 707 crate::saadc::InputChannel::$ch
712 } 708 }
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index c45d45e68..373f22642 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -4,18 +4,20 @@
4 4
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7#[cfg(feature = "_nrf52832_anomaly_109")]
8use core::sync::atomic::AtomicU8;
7use core::sync::atomic::{compiler_fence, Ordering}; 9use core::sync::atomic::{compiler_fence, Ordering};
8use core::task::Poll; 10use core::task::Poll;
9 11
10use embassy_embedded_hal::SetConfig; 12use embassy_embedded_hal::SetConfig;
11use embassy_hal_internal::{into_ref, PeripheralRef}; 13use embassy_hal_internal::{into_ref, PeripheralRef};
14use embassy_sync::waitqueue::AtomicWaker;
12pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 15pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
13pub use pac::spim0::config::ORDER_A as BitOrder; 16pub use pac::spim0::config::ORDER_A as BitOrder;
14pub use pac::spim0::frequency::FREQUENCY_A as Frequency; 17pub use pac::spim0::frequency::FREQUENCY_A as Frequency;
15 18
16use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 19use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
17use crate::gpio::sealed::Pin as _; 20use crate::gpio::{self, convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _};
18use crate::gpio::{self, convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits};
19use crate::interrupt::typelevel::Interrupt; 21use crate::interrupt::typelevel::Interrupt;
20use crate::util::{slice_in_ram_or, slice_ptr_len, slice_ptr_parts, slice_ptr_parts_mut}; 22use crate::util::{slice_in_ram_or, slice_ptr_len, slice_ptr_parts, slice_ptr_parts_mut};
21use crate::{interrupt, pac, Peripheral}; 23use crate::{interrupt, pac, Peripheral};
@@ -487,54 +489,46 @@ impl<'d, T: Instance> Drop for Spim<'d, T> {
487 } 489 }
488} 490}
489 491
490pub(crate) mod sealed { 492pub(crate) struct State {
493 waker: AtomicWaker,
491 #[cfg(feature = "_nrf52832_anomaly_109")] 494 #[cfg(feature = "_nrf52832_anomaly_109")]
492 use core::sync::atomic::AtomicU8; 495 rx: AtomicU8,
493 496 #[cfg(feature = "_nrf52832_anomaly_109")]
494 use embassy_sync::waitqueue::AtomicWaker; 497 tx: AtomicU8,
495 498}
496 use super::*;
497
498 pub struct State {
499 pub waker: AtomicWaker,
500 #[cfg(feature = "_nrf52832_anomaly_109")]
501 pub rx: AtomicU8,
502 #[cfg(feature = "_nrf52832_anomaly_109")]
503 pub tx: AtomicU8,
504 }
505 499
506 impl State { 500impl State {
507 pub const fn new() -> Self { 501 pub(crate) const fn new() -> Self {
508 Self { 502 Self {
509 waker: AtomicWaker::new(), 503 waker: AtomicWaker::new(),
510 #[cfg(feature = "_nrf52832_anomaly_109")] 504 #[cfg(feature = "_nrf52832_anomaly_109")]
511 rx: AtomicU8::new(0), 505 rx: AtomicU8::new(0),
512 #[cfg(feature = "_nrf52832_anomaly_109")] 506 #[cfg(feature = "_nrf52832_anomaly_109")]
513 tx: AtomicU8::new(0), 507 tx: AtomicU8::new(0),
514 }
515 } 508 }
516 } 509 }
510}
517 511
518 pub trait Instance { 512pub(crate) trait SealedInstance {
519 fn regs() -> &'static pac::spim0::RegisterBlock; 513 fn regs() -> &'static pac::spim0::RegisterBlock;
520 fn state() -> &'static State; 514 fn state() -> &'static State;
521 }
522} 515}
523 516
524/// SPIM peripheral instance 517/// SPIM peripheral instance
525pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 518#[allow(private_bounds)]
519pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static {
526 /// Interrupt for this peripheral. 520 /// Interrupt for this peripheral.
527 type Interrupt: interrupt::typelevel::Interrupt; 521 type Interrupt: interrupt::typelevel::Interrupt;
528} 522}
529 523
530macro_rules! impl_spim { 524macro_rules! impl_spim {
531 ($type:ident, $pac_type:ident, $irq:ident) => { 525 ($type:ident, $pac_type:ident, $irq:ident) => {
532 impl crate::spim::sealed::Instance for peripherals::$type { 526 impl crate::spim::SealedInstance for peripherals::$type {
533 fn regs() -> &'static pac::spim0::RegisterBlock { 527 fn regs() -> &'static pac::spim0::RegisterBlock {
534 unsafe { &*pac::$pac_type::ptr() } 528 unsafe { &*pac::$pac_type::ptr() }
535 } 529 }
536 fn state() -> &'static crate::spim::sealed::State { 530 fn state() -> &'static crate::spim::State {
537 static STATE: crate::spim::sealed::State = crate::spim::sealed::State::new(); 531 static STATE: crate::spim::State = crate::spim::State::new();
538 &STATE 532 &STATE
539 } 533 }
540 } 534 }
diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs
index 772ca40cc..47bbeaf77 100644
--- a/embassy-nrf/src/spis.rs
+++ b/embassy-nrf/src/spis.rs
@@ -8,12 +8,12 @@ use core::task::Poll;
8 8
9use embassy_embedded_hal::SetConfig; 9use embassy_embedded_hal::SetConfig;
10use embassy_hal_internal::{into_ref, PeripheralRef}; 10use embassy_hal_internal::{into_ref, PeripheralRef};
11use embassy_sync::waitqueue::AtomicWaker;
11pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 12pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
12pub use pac::spis0::config::ORDER_A as BitOrder; 13pub use pac::spis0::config::ORDER_A as BitOrder;
13 14
14use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 15use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
15use crate::gpio::sealed::Pin as _; 16use crate::gpio::{self, AnyPin, Pin as GpioPin, SealedPin as _};
16use crate::gpio::{self, AnyPin, Pin as GpioPin};
17use crate::interrupt::typelevel::Interrupt; 17use crate::interrupt::typelevel::Interrupt;
18use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; 18use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
19use crate::{interrupt, pac, Peripheral}; 19use crate::{interrupt, pac, Peripheral};
@@ -456,43 +456,38 @@ impl<'d, T: Instance> Drop for Spis<'d, T> {
456 } 456 }
457} 457}
458 458
459pub(crate) mod sealed { 459pub(crate) struct State {
460 use embassy_sync::waitqueue::AtomicWaker; 460 waker: AtomicWaker,
461 461}
462 use super::*;
463
464 pub struct State {
465 pub waker: AtomicWaker,
466 }
467 462
468 impl State { 463impl State {
469 pub const fn new() -> Self { 464 pub(crate) const fn new() -> Self {
470 Self { 465 Self {
471 waker: AtomicWaker::new(), 466 waker: AtomicWaker::new(),
472 }
473 } 467 }
474 } 468 }
469}
475 470
476 pub trait Instance { 471pub(crate) trait SealedInstance {
477 fn regs() -> &'static pac::spis0::RegisterBlock; 472 fn regs() -> &'static pac::spis0::RegisterBlock;
478 fn state() -> &'static State; 473 fn state() -> &'static State;
479 }
480} 474}
481 475
482/// SPIS peripheral instance 476/// SPIS peripheral instance
483pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 477#[allow(private_bounds)]
478pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static {
484 /// Interrupt for this peripheral. 479 /// Interrupt for this peripheral.
485 type Interrupt: interrupt::typelevel::Interrupt; 480 type Interrupt: interrupt::typelevel::Interrupt;
486} 481}
487 482
488macro_rules! impl_spis { 483macro_rules! impl_spis {
489 ($type:ident, $pac_type:ident, $irq:ident) => { 484 ($type:ident, $pac_type:ident, $irq:ident) => {
490 impl crate::spis::sealed::Instance for peripherals::$type { 485 impl crate::spis::SealedInstance for peripherals::$type {
491 fn regs() -> &'static pac::spis0::RegisterBlock { 486 fn regs() -> &'static pac::spis0::RegisterBlock {
492 unsafe { &*pac::$pac_type::ptr() } 487 unsafe { &*pac::$pac_type::ptr() }
493 } 488 }
494 fn state() -> &'static crate::spis::sealed::State { 489 fn state() -> &'static crate::spis::State {
495 static STATE: crate::spis::sealed::State = crate::spis::sealed::State::new(); 490 static STATE: crate::spis::State = crate::spis::State::new();
496 &STATE 491 &STATE
497 } 492 }
498 } 493 }
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs
index 2970ad3f2..ac5328ded 100644
--- a/embassy-nrf/src/timer.rs
+++ b/embassy-nrf/src/timer.rs
@@ -11,30 +11,25 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
11use crate::ppi::{Event, Task}; 11use crate::ppi::{Event, Task};
12use crate::{pac, Peripheral}; 12use crate::{pac, Peripheral};
13 13
14pub(crate) mod sealed { 14pub(crate) trait SealedInstance {
15 15 /// The number of CC registers this instance has.
16 use super::*; 16 const CCS: usize;
17 17 fn regs() -> &'static pac::timer0::RegisterBlock;
18 pub trait Instance {
19 /// The number of CC registers this instance has.
20 const CCS: usize;
21 fn regs() -> &'static pac::timer0::RegisterBlock;
22 }
23 pub trait ExtendedInstance {}
24} 18}
25 19
26/// Basic Timer instance. 20/// Basic Timer instance.
27pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 21#[allow(private_bounds)]
22pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
28 /// Interrupt for this peripheral. 23 /// Interrupt for this peripheral.
29 type Interrupt: crate::interrupt::typelevel::Interrupt; 24 type Interrupt: crate::interrupt::typelevel::Interrupt;
30} 25}
31 26
32/// Extended timer instance. 27/// Extended timer instance.
33pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {} 28pub trait ExtendedInstance: Instance {}
34 29
35macro_rules! impl_timer { 30macro_rules! impl_timer {
36 ($type:ident, $pac_type:ident, $irq:ident, $ccs:literal) => { 31 ($type:ident, $pac_type:ident, $irq:ident, $ccs:literal) => {
37 impl crate::timer::sealed::Instance for peripherals::$type { 32 impl crate::timer::SealedInstance for peripherals::$type {
38 const CCS: usize = $ccs; 33 const CCS: usize = $ccs;
39 fn regs() -> &'static pac::timer0::RegisterBlock { 34 fn regs() -> &'static pac::timer0::RegisterBlock {
40 unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) } 35 unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) }
@@ -49,7 +44,6 @@ macro_rules! impl_timer {
49 }; 44 };
50 ($type:ident, $pac_type:ident, $irq:ident, extended) => { 45 ($type:ident, $pac_type:ident, $irq:ident, extended) => {
51 impl_timer!($type, $pac_type, $irq, 6); 46 impl_timer!($type, $pac_type, $irq, 6);
52 impl crate::timer::sealed::ExtendedInstance for peripherals::$type {}
53 impl crate::timer::ExtendedInstance for peripherals::$type {} 47 impl crate::timer::ExtendedInstance for peripherals::$type {}
54 }; 48 };
55} 49}
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index 24810a08c..c64743ecc 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -727,41 +727,38 @@ impl<'a, T: Instance> Drop for Twim<'a, T> {
727 } 727 }
728} 728}
729 729
730pub(crate) mod sealed { 730pub(crate) struct State {
731 use super::*; 731 end_waker: AtomicWaker,
732 732}
733 pub struct State {
734 pub end_waker: AtomicWaker,
735 }
736 733
737 impl State { 734impl State {
738 pub const fn new() -> Self { 735 pub(crate) const fn new() -> Self {
739 Self { 736 Self {
740 end_waker: AtomicWaker::new(), 737 end_waker: AtomicWaker::new(),
741 }
742 } 738 }
743 } 739 }
740}
744 741
745 pub trait Instance { 742pub(crate) trait SealedInstance {
746 fn regs() -> &'static pac::twim0::RegisterBlock; 743 fn regs() -> &'static pac::twim0::RegisterBlock;
747 fn state() -> &'static State; 744 fn state() -> &'static State;
748 }
749} 745}
750 746
751/// TWIM peripheral instance. 747/// TWIM peripheral instance.
752pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 748#[allow(private_bounds)]
749pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static {
753 /// Interrupt for this peripheral. 750 /// Interrupt for this peripheral.
754 type Interrupt: interrupt::typelevel::Interrupt; 751 type Interrupt: interrupt::typelevel::Interrupt;
755} 752}
756 753
757macro_rules! impl_twim { 754macro_rules! impl_twim {
758 ($type:ident, $pac_type:ident, $irq:ident) => { 755 ($type:ident, $pac_type:ident, $irq:ident) => {
759 impl crate::twim::sealed::Instance for peripherals::$type { 756 impl crate::twim::SealedInstance for peripherals::$type {
760 fn regs() -> &'static pac::twim0::RegisterBlock { 757 fn regs() -> &'static pac::twim0::RegisterBlock {
761 unsafe { &*pac::$pac_type::ptr() } 758 unsafe { &*pac::$pac_type::ptr() }
762 } 759 }
763 fn state() -> &'static crate::twim::sealed::State { 760 fn state() -> &'static crate::twim::State {
764 static STATE: crate::twim::sealed::State = crate::twim::sealed::State::new(); 761 static STATE: crate::twim::State = crate::twim::State::new();
765 &STATE 762 &STATE
766 } 763 }
767 } 764 }
diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs
index 415150447..f3eab008f 100644
--- a/embassy-nrf/src/twis.rs
+++ b/embassy-nrf/src/twis.rs
@@ -754,41 +754,38 @@ impl<'a, T: Instance> Drop for Twis<'a, T> {
754 } 754 }
755} 755}
756 756
757pub(crate) mod sealed { 757pub(crate) struct State {
758 use super::*; 758 waker: AtomicWaker,
759 759}
760 pub struct State {
761 pub waker: AtomicWaker,
762 }
763 760
764 impl State { 761impl State {
765 pub const fn new() -> Self { 762 pub(crate) const fn new() -> Self {
766 Self { 763 Self {
767 waker: AtomicWaker::new(), 764 waker: AtomicWaker::new(),
768 }
769 } 765 }
770 } 766 }
767}
771 768
772 pub trait Instance { 769pub(crate) trait SealedInstance {
773 fn regs() -> &'static pac::twis0::RegisterBlock; 770 fn regs() -> &'static pac::twis0::RegisterBlock;
774 fn state() -> &'static State; 771 fn state() -> &'static State;
775 }
776} 772}
777 773
778/// TWIS peripheral instance. 774/// TWIS peripheral instance.
779pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { 775#[allow(private_bounds)]
776pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static {
780 /// Interrupt for this peripheral. 777 /// Interrupt for this peripheral.
781 type Interrupt: interrupt::typelevel::Interrupt; 778 type Interrupt: interrupt::typelevel::Interrupt;
782} 779}
783 780
784macro_rules! impl_twis { 781macro_rules! impl_twis {
785 ($type:ident, $pac_type:ident, $irq:ident) => { 782 ($type:ident, $pac_type:ident, $irq:ident) => {
786 impl crate::twis::sealed::Instance for peripherals::$type { 783 impl crate::twis::SealedInstance for peripherals::$type {
787 fn regs() -> &'static pac::twis0::RegisterBlock { 784 fn regs() -> &'static pac::twis0::RegisterBlock {
788 unsafe { &*pac::$pac_type::ptr() } 785 unsafe { &*pac::$pac_type::ptr() }
789 } 786 }
790 fn state() -> &'static crate::twis::sealed::State { 787 fn state() -> &'static crate::twis::State {
791 static STATE: crate::twis::sealed::State = crate::twis::sealed::State::new(); 788 static STATE: crate::twis::State = crate::twis::State::new();
792 &STATE 789 &STATE
793 } 790 }
794 } 791 }
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index cbd5dccbc..fa0a773a8 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -15,18 +15,18 @@
15 15
16use core::future::poll_fn; 16use core::future::poll_fn;
17use core::marker::PhantomData; 17use core::marker::PhantomData;
18use core::sync::atomic::{compiler_fence, Ordering}; 18use core::sync::atomic::{compiler_fence, AtomicU8, Ordering};
19use core::task::Poll; 19use core::task::Poll;
20 20
21use embassy_hal_internal::drop::OnDrop; 21use embassy_hal_internal::drop::OnDrop;
22use embassy_hal_internal::{into_ref, PeripheralRef}; 22use embassy_hal_internal::{into_ref, PeripheralRef};
23use embassy_sync::waitqueue::AtomicWaker;
23use pac::uarte0::RegisterBlock; 24use pac::uarte0::RegisterBlock;
24// Re-export SVD variants to allow user to directly set values. 25// Re-export SVD variants to allow user to directly set values.
25pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; 26pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
26 27
27use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 28use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
28use crate::gpio::sealed::Pin as _; 29use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits, SealedPin as _};
29use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
30use crate::interrupt::typelevel::Interrupt; 30use crate::interrupt::typelevel::Interrupt;
31use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; 31use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
32use crate::timer::{Frequency, Instance as TimerInstance, Timer}; 32use crate::timer::{Frequency, Instance as TimerInstance, Timer};
@@ -939,7 +939,7 @@ pub(crate) fn apply_workaround_for_enable_anomaly(r: &crate::pac::uarte0::Regist
939 } 939 }
940} 940}
941 941
942pub(crate) fn drop_tx_rx(r: &pac::uarte0::RegisterBlock, s: &sealed::State) { 942pub(crate) fn drop_tx_rx(r: &pac::uarte0::RegisterBlock, s: &State) {
943 if s.tx_rx_refcount.fetch_sub(1, Ordering::Relaxed) == 1 { 943 if s.tx_rx_refcount.fetch_sub(1, Ordering::Relaxed) == 1 {
944 // Finally we can disable, and we do so for the peripheral 944 // Finally we can disable, and we do so for the peripheral
945 // i.e. not just rx concerns. 945 // i.e. not just rx concerns.
@@ -954,49 +954,42 @@ pub(crate) fn drop_tx_rx(r: &pac::uarte0::RegisterBlock, s: &sealed::State) {
954 } 954 }
955} 955}
956 956
957pub(crate) mod sealed { 957pub(crate) struct State {
958 use core::sync::atomic::AtomicU8; 958 pub(crate) rx_waker: AtomicWaker,
959 959 pub(crate) tx_waker: AtomicWaker,
960 use embassy_sync::waitqueue::AtomicWaker; 960 pub(crate) tx_rx_refcount: AtomicU8,
961 961}
962 use super::*; 962impl State {
963 963 pub(crate) const fn new() -> Self {
964 pub struct State { 964 Self {
965 pub rx_waker: AtomicWaker, 965 rx_waker: AtomicWaker::new(),
966 pub tx_waker: AtomicWaker, 966 tx_waker: AtomicWaker::new(),
967 pub tx_rx_refcount: AtomicU8, 967 tx_rx_refcount: AtomicU8::new(0),
968 }
969 impl State {
970 pub const fn new() -> Self {
971 Self {
972 rx_waker: AtomicWaker::new(),
973 tx_waker: AtomicWaker::new(),
974 tx_rx_refcount: AtomicU8::new(0),
975 }
976 } 968 }
977 } 969 }
970}
978 971
979 pub trait Instance { 972pub(crate) trait SealedInstance {
980 fn regs() -> &'static pac::uarte0::RegisterBlock; 973 fn regs() -> &'static pac::uarte0::RegisterBlock;
981 fn state() -> &'static State; 974 fn state() -> &'static State;
982 fn buffered_state() -> &'static crate::buffered_uarte::State; 975 fn buffered_state() -> &'static crate::buffered_uarte::State;
983 }
984} 976}
985 977
986/// UARTE peripheral instance. 978/// UARTE peripheral instance.
987pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 979#[allow(private_bounds)]
980pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
988 /// Interrupt for this peripheral. 981 /// Interrupt for this peripheral.
989 type Interrupt: interrupt::typelevel::Interrupt; 982 type Interrupt: interrupt::typelevel::Interrupt;
990} 983}
991 984
992macro_rules! impl_uarte { 985macro_rules! impl_uarte {
993 ($type:ident, $pac_type:ident, $irq:ident) => { 986 ($type:ident, $pac_type:ident, $irq:ident) => {
994 impl crate::uarte::sealed::Instance for peripherals::$type { 987 impl crate::uarte::SealedInstance for peripherals::$type {
995 fn regs() -> &'static pac::uarte0::RegisterBlock { 988 fn regs() -> &'static pac::uarte0::RegisterBlock {
996 unsafe { &*pac::$pac_type::ptr() } 989 unsafe { &*pac::$pac_type::ptr() }
997 } 990 }
998 fn state() -> &'static crate::uarte::sealed::State { 991 fn state() -> &'static crate::uarte::State {
999 static STATE: crate::uarte::sealed::State = crate::uarte::sealed::State::new(); 992 static STATE: crate::uarte::State = crate::uarte::State::new();
1000 &STATE 993 &STATE
1001 } 994 }
1002 fn buffered_state() -> &'static crate::buffered_uarte::State { 995 fn buffered_state() -> &'static crate::buffered_uarte::State {
diff --git a/embassy-nrf/src/usb/mod.rs b/embassy-nrf/src/usb/mod.rs
index e26b49db3..09cf87e97 100644
--- a/embassy-nrf/src/usb/mod.rs
+++ b/embassy-nrf/src/usb/mod.rs
@@ -793,23 +793,20 @@ impl Allocator {
793 } 793 }
794} 794}
795 795
796pub(crate) mod sealed { 796pub(crate) trait SealedInstance {
797 use super::*; 797 fn regs() -> &'static pac::usbd::RegisterBlock;
798
799 pub trait Instance {
800 fn regs() -> &'static pac::usbd::RegisterBlock;
801 }
802} 798}
803 799
804/// USB peripheral instance. 800/// USB peripheral instance.
805pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 801#[allow(private_bounds)]
802pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
806 /// Interrupt for this peripheral. 803 /// Interrupt for this peripheral.
807 type Interrupt: interrupt::typelevel::Interrupt; 804 type Interrupt: interrupt::typelevel::Interrupt;
808} 805}
809 806
810macro_rules! impl_usb { 807macro_rules! impl_usb {
811 ($type:ident, $pac_type:ident, $irq:ident) => { 808 ($type:ident, $pac_type:ident, $irq:ident) => {
812 impl crate::usb::sealed::Instance for peripherals::$type { 809 impl crate::usb::SealedInstance for peripherals::$type {
813 fn regs() -> &'static pac::usbd::RegisterBlock { 810 fn regs() -> &'static pac::usbd::RegisterBlock {
814 unsafe { &*pac::$pac_type::ptr() } 811 unsafe { &*pac::$pac_type::ptr() }
815 } 812 }
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs
index 4c01fe195..101c5b71f 100644
--- a/embassy-rp/src/adc.rs
+++ b/embassy-rp/src/adc.rs
@@ -8,8 +8,7 @@ use core::task::Poll;
8use embassy_hal_internal::{into_ref, PeripheralRef}; 8use embassy_hal_internal::{into_ref, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10 10
11use crate::gpio::sealed::Pin as GpioPin; 11use crate::gpio::{self, AnyPin, Pull, SealedPin as GpioPin};
12use crate::gpio::{self, AnyPin, Pull};
13use crate::interrupt::typelevel::Binding; 12use crate::interrupt::typelevel::Binding;
14use crate::interrupt::InterruptExt; 13use crate::interrupt::InterruptExt;
15use crate::peripherals::{ADC, ADC_TEMP_SENSOR}; 14use crate::peripherals::{ADC, ADC_TEMP_SENSOR};
@@ -334,29 +333,28 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ADC_IRQ_FIFO> for Inter
334 } 333 }
335} 334}
336 335
337mod sealed { 336trait SealedAdcSample: crate::dma::Word {}
338 pub trait AdcSample: crate::dma::Word {} 337trait SealedAdcChannel {}
339
340 pub trait AdcChannel {}
341}
342 338
343/// ADC sample. 339/// ADC sample.
344pub trait AdcSample: sealed::AdcSample {} 340#[allow(private_bounds)]
341pub trait AdcSample: SealedAdcSample {}
345 342
346impl sealed::AdcSample for u16 {} 343impl SealedAdcSample for u16 {}
347impl AdcSample for u16 {} 344impl AdcSample for u16 {}
348 345
349impl sealed::AdcSample for u8 {} 346impl SealedAdcSample for u8 {}
350impl AdcSample for u8 {} 347impl AdcSample for u8 {}
351 348
352/// ADC channel. 349/// ADC channel.
353pub trait AdcChannel: sealed::AdcChannel {} 350#[allow(private_bounds)]
351pub trait AdcChannel: SealedAdcChannel {}
354/// ADC pin. 352/// ADC pin.
355pub trait AdcPin: AdcChannel + gpio::Pin {} 353pub trait AdcPin: AdcChannel + gpio::Pin {}
356 354
357macro_rules! impl_pin { 355macro_rules! impl_pin {
358 ($pin:ident, $channel:expr) => { 356 ($pin:ident, $channel:expr) => {
359 impl sealed::AdcChannel for peripherals::$pin {} 357 impl SealedAdcChannel for peripherals::$pin {}
360 impl AdcChannel for peripherals::$pin {} 358 impl AdcChannel for peripherals::$pin {}
361 impl AdcPin for peripherals::$pin {} 359 impl AdcPin for peripherals::$pin {}
362 }; 360 };
@@ -367,5 +365,5 @@ impl_pin!(PIN_27, 1);
367impl_pin!(PIN_28, 2); 365impl_pin!(PIN_28, 2);
368impl_pin!(PIN_29, 3); 366impl_pin!(PIN_29, 3);
369 367
370impl sealed::AdcChannel for peripherals::ADC_TEMP_SENSOR {} 368impl SealedAdcChannel for peripherals::ADC_TEMP_SENSOR {}
371impl AdcChannel for peripherals::ADC_TEMP_SENSOR {} 369impl AdcChannel for peripherals::ADC_TEMP_SENSOR {}
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index b7f6aeac9..bedb79464 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -6,8 +6,7 @@ use core::sync::atomic::{AtomicU16, AtomicU32, Ordering};
6use embassy_hal_internal::{into_ref, PeripheralRef}; 6use embassy_hal_internal::{into_ref, PeripheralRef};
7use pac::clocks::vals::*; 7use pac::clocks::vals::*;
8 8
9use crate::gpio::sealed::Pin; 9use crate::gpio::{AnyPin, SealedPin};
10use crate::gpio::AnyPin;
11use crate::pac::common::{Reg, RW}; 10use crate::pac::common::{Reg, RW};
12use crate::{pac, reset, Peripheral}; 11use crate::{pac, reset, Peripheral};
13 12
@@ -788,14 +787,14 @@ impl_gpinpin!(PIN_20, 20, 0);
788impl_gpinpin!(PIN_22, 22, 1); 787impl_gpinpin!(PIN_22, 22, 1);
789 788
790/// General purpose clock input driver. 789/// General purpose clock input driver.
791pub struct Gpin<'d, T: Pin> { 790pub struct Gpin<'d, T: GpinPin> {
792 gpin: PeripheralRef<'d, AnyPin>, 791 gpin: PeripheralRef<'d, AnyPin>,
793 _phantom: PhantomData<T>, 792 _phantom: PhantomData<T>,
794} 793}
795 794
796impl<'d, T: Pin> Gpin<'d, T> { 795impl<'d, T: GpinPin> Gpin<'d, T> {
797 /// Create new gpin driver. 796 /// Create new gpin driver.
798 pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> { 797 pub fn new(gpin: impl Peripheral<P = T> + 'd) -> Self {
799 into_ref!(gpin); 798 into_ref!(gpin);
800 799
801 gpin.gpio().ctrl().write(|w| w.set_funcsel(0x08)); 800 gpin.gpio().ctrl().write(|w| w.set_funcsel(0x08));
@@ -811,7 +810,7 @@ impl<'d, T: Pin> Gpin<'d, T> {
811 // } 810 // }
812} 811}
813 812
814impl<'d, T: Pin> Drop for Gpin<'d, T> { 813impl<'d, T: GpinPin> Drop for Gpin<'d, T> {
815 fn drop(&mut self) { 814 fn drop(&mut self) {
816 self.gpin 815 self.gpin
817 .gpio() 816 .gpio()
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs
index 44aabce6b..e6374a86c 100644
--- a/embassy-rp/src/dma.rs
+++ b/embassy-rp/src/dma.rs
@@ -208,14 +208,12 @@ pub(crate) const CHANNEL_COUNT: usize = 12;
208const NEW_AW: AtomicWaker = AtomicWaker::new(); 208const NEW_AW: AtomicWaker = AtomicWaker::new();
209static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AW; CHANNEL_COUNT]; 209static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AW; CHANNEL_COUNT];
210 210
211mod sealed { 211trait SealedChannel {}
212 pub trait Channel {} 212trait SealedWord {}
213
214 pub trait Word {}
215}
216 213
217/// DMA channel interface. 214/// DMA channel interface.
218pub trait Channel: Peripheral<P = Self> + sealed::Channel + Into<AnyChannel> + Sized + 'static { 215#[allow(private_bounds)]
216pub trait Channel: Peripheral<P = Self> + SealedChannel + Into<AnyChannel> + Sized + 'static {
219 /// Channel number. 217 /// Channel number.
220 fn number(&self) -> u8; 218 fn number(&self) -> u8;
221 219
@@ -231,26 +229,27 @@ pub trait Channel: Peripheral<P = Self> + sealed::Channel + Into<AnyChannel> + S
231} 229}
232 230
233/// DMA word. 231/// DMA word.
234pub trait Word: sealed::Word { 232#[allow(private_bounds)]
233pub trait Word: SealedWord {
235 /// Word size. 234 /// Word size.
236 fn size() -> vals::DataSize; 235 fn size() -> vals::DataSize;
237} 236}
238 237
239impl sealed::Word for u8 {} 238impl SealedWord for u8 {}
240impl Word for u8 { 239impl Word for u8 {
241 fn size() -> vals::DataSize { 240 fn size() -> vals::DataSize {
242 vals::DataSize::SIZE_BYTE 241 vals::DataSize::SIZE_BYTE
243 } 242 }
244} 243}
245 244
246impl sealed::Word for u16 {} 245impl SealedWord for u16 {}
247impl Word for u16 { 246impl Word for u16 {
248 fn size() -> vals::DataSize { 247 fn size() -> vals::DataSize {
249 vals::DataSize::SIZE_HALFWORD 248 vals::DataSize::SIZE_HALFWORD
250 } 249 }
251} 250}
252 251
253impl sealed::Word for u32 {} 252impl SealedWord for u32 {}
254impl Word for u32 { 253impl Word for u32 {
255 fn size() -> vals::DataSize { 254 fn size() -> vals::DataSize {
256 vals::DataSize::SIZE_WORD 255 vals::DataSize::SIZE_WORD
@@ -264,7 +263,7 @@ pub struct AnyChannel {
264 263
265impl_peripheral!(AnyChannel); 264impl_peripheral!(AnyChannel);
266 265
267impl sealed::Channel for AnyChannel {} 266impl SealedChannel for AnyChannel {}
268impl Channel for AnyChannel { 267impl Channel for AnyChannel {
269 fn number(&self) -> u8 { 268 fn number(&self) -> u8 {
270 self.number 269 self.number
@@ -273,7 +272,7 @@ impl Channel for AnyChannel {
273 272
274macro_rules! channel { 273macro_rules! channel {
275 ($name:ident, $num:expr) => { 274 ($name:ident, $num:expr) => {
276 impl sealed::Channel for peripherals::$name {} 275 impl SealedChannel for peripherals::$name {}
277 impl Channel for peripherals::$name { 276 impl Channel for peripherals::$name {
278 fn number(&self) -> u8 { 277 fn number(&self) -> u8 {
279 $num 278 $num
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs
index 422b77400..45b385cb4 100644
--- a/embassy-rp/src/flash.rs
+++ b/embassy-rp/src/flash.rs
@@ -903,22 +903,22 @@ pub(crate) unsafe fn in_ram(operation: impl FnOnce()) -> Result<(), Error> {
903 Ok(()) 903 Ok(())
904} 904}
905 905
906mod sealed { 906trait SealedInstance {}
907 pub trait Instance {} 907trait SealedMode {}
908 pub trait Mode {}
909}
910 908
911/// Flash instance. 909/// Flash instance.
912pub trait Instance: sealed::Instance {} 910#[allow(private_bounds)]
911pub trait Instance: SealedInstance {}
913/// Flash mode. 912/// Flash mode.
914pub trait Mode: sealed::Mode {} 913#[allow(private_bounds)]
914pub trait Mode: SealedMode {}
915 915
916impl sealed::Instance for FLASH {} 916impl SealedInstance for FLASH {}
917impl Instance for FLASH {} 917impl Instance for FLASH {}
918 918
919macro_rules! impl_mode { 919macro_rules! impl_mode {
920 ($name:ident) => { 920 ($name:ident) => {
921 impl sealed::Mode for $name {} 921 impl SealedMode for $name {}
922 impl Mode for $name {} 922 impl Mode for $name {}
923 }; 923 };
924} 924}
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index a84c00a2c..ea87fd9da 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -8,7 +8,6 @@ use core::task::{Context, Poll};
8use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; 8use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10 10
11use self::sealed::Pin as _;
12use crate::interrupt::InterruptExt; 11use crate::interrupt::InterruptExt;
13use crate::pac::common::{Reg, RW}; 12use crate::pac::common::{Reg, RW};
14use crate::pac::SIO; 13use crate::pac::SIO;
@@ -802,68 +801,65 @@ impl<'w> Drop for DormantWake<'w> {
802 } 801 }
803} 802}
804 803
805pub(crate) mod sealed { 804pub(crate) trait SealedPin: Sized {
806 use super::*; 805 fn pin_bank(&self) -> u8;
807
808 pub trait Pin: Sized {
809 fn pin_bank(&self) -> u8;
810 806
811 #[inline] 807 #[inline]
812 fn _pin(&self) -> u8 { 808 fn _pin(&self) -> u8 {
813 self.pin_bank() & 0x1f 809 self.pin_bank() & 0x1f
814 } 810 }
815 811
816 #[inline] 812 #[inline]
817 fn _bank(&self) -> Bank { 813 fn _bank(&self) -> Bank {
818 match self.pin_bank() >> 5 { 814 match self.pin_bank() >> 5 {
819 #[cfg(feature = "qspi-as-gpio")] 815 #[cfg(feature = "qspi-as-gpio")]
820 1 => Bank::Qspi, 816 1 => Bank::Qspi,
821 _ => Bank::Bank0, 817 _ => Bank::Bank0,
822 }
823 } 818 }
819 }
824 820
825 fn io(&self) -> pac::io::Io { 821 fn io(&self) -> pac::io::Io {
826 match self._bank() { 822 match self._bank() {
827 Bank::Bank0 => crate::pac::IO_BANK0, 823 Bank::Bank0 => crate::pac::IO_BANK0,
828 #[cfg(feature = "qspi-as-gpio")] 824 #[cfg(feature = "qspi-as-gpio")]
829 Bank::Qspi => crate::pac::IO_QSPI, 825 Bank::Qspi => crate::pac::IO_QSPI,
830 }
831 } 826 }
827 }
832 828
833 fn gpio(&self) -> pac::io::Gpio { 829 fn gpio(&self) -> pac::io::Gpio {
834 self.io().gpio(self._pin() as _) 830 self.io().gpio(self._pin() as _)
835 } 831 }
836 832
837 fn pad_ctrl(&self) -> Reg<pac::pads::regs::GpioCtrl, RW> { 833 fn pad_ctrl(&self) -> Reg<pac::pads::regs::GpioCtrl, RW> {
838 let block = match self._bank() { 834 let block = match self._bank() {
839 Bank::Bank0 => crate::pac::PADS_BANK0, 835 Bank::Bank0 => crate::pac::PADS_BANK0,
840 #[cfg(feature = "qspi-as-gpio")] 836 #[cfg(feature = "qspi-as-gpio")]
841 Bank::Qspi => crate::pac::PADS_QSPI, 837 Bank::Qspi => crate::pac::PADS_QSPI,
842 }; 838 };
843 block.gpio(self._pin() as _) 839 block.gpio(self._pin() as _)
844 } 840 }
845 841
846 fn sio_out(&self) -> pac::sio::Gpio { 842 fn sio_out(&self) -> pac::sio::Gpio {
847 SIO.gpio_out(self._bank() as _) 843 SIO.gpio_out(self._bank() as _)
848 } 844 }
849 845
850 fn sio_oe(&self) -> pac::sio::Gpio { 846 fn sio_oe(&self) -> pac::sio::Gpio {
851 SIO.gpio_oe(self._bank() as _) 847 SIO.gpio_oe(self._bank() as _)
852 } 848 }
853 849
854 fn sio_in(&self) -> Reg<u32, RW> { 850 fn sio_in(&self) -> Reg<u32, RW> {
855 SIO.gpio_in(self._bank() as _) 851 SIO.gpio_in(self._bank() as _)
856 } 852 }
857 853
858 fn int_proc(&self) -> pac::io::Int { 854 fn int_proc(&self) -> pac::io::Int {
859 let proc = SIO.cpuid().read(); 855 let proc = SIO.cpuid().read();
860 self.io().int_proc(proc as _) 856 self.io().int_proc(proc as _)
861 }
862 } 857 }
863} 858}
864 859
865/// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an [AnyPin]. 860/// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an [AnyPin].
866pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static { 861#[allow(private_bounds)]
862pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + SealedPin + Sized + 'static {
867 /// Degrade to a generic pin struct 863 /// Degrade to a generic pin struct
868 fn degrade(self) -> AnyPin { 864 fn degrade(self) -> AnyPin {
869 AnyPin { 865 AnyPin {
@@ -903,7 +899,7 @@ impl AnyPin {
903impl_peripheral!(AnyPin); 899impl_peripheral!(AnyPin);
904 900
905impl Pin for AnyPin {} 901impl Pin for AnyPin {}
906impl sealed::Pin for AnyPin { 902impl SealedPin for AnyPin {
907 fn pin_bank(&self) -> u8 { 903 fn pin_bank(&self) -> u8 {
908 self.pin_bank 904 self.pin_bank
909 } 905 }
@@ -914,7 +910,7 @@ impl sealed::Pin for AnyPin {
914macro_rules! impl_pin { 910macro_rules! impl_pin {
915 ($name:ident, $bank:expr, $pin_num:expr) => { 911 ($name:ident, $bank:expr, $pin_num:expr) => {
916 impl Pin for peripherals::$name {} 912 impl Pin for peripherals::$name {}
917 impl sealed::Pin for peripherals::$name { 913 impl SealedPin for peripherals::$name {
918 #[inline] 914 #[inline]
919 fn pin_bank(&self) -> u8 { 915 fn pin_bank(&self) -> u8 {
920 ($bank as u8) * 32 + $pin_num 916 ($bank as u8) * 32 + $pin_num
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index 26a819b25..256875b4a 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -784,34 +784,24 @@ pub fn i2c_reserved_addr(addr: u16) -> bool {
784 ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0 784 ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0
785} 785}
786 786
787mod sealed { 787pub(crate) trait SealedInstance {
788 use embassy_sync::waitqueue::AtomicWaker; 788 const TX_DREQ: u8;
789 const RX_DREQ: u8;
789 790
790 use crate::interrupt; 791 fn regs() -> crate::pac::i2c::I2c;
791 792 fn reset() -> crate::pac::resets::regs::Peripherals;
792 pub trait Instance { 793 fn waker() -> &'static AtomicWaker;
793 const TX_DREQ: u8;
794 const RX_DREQ: u8;
795
796 type Interrupt: interrupt::typelevel::Interrupt;
797
798 fn regs() -> crate::pac::i2c::I2c;
799 fn reset() -> crate::pac::resets::regs::Peripherals;
800 fn waker() -> &'static AtomicWaker;
801 }
802
803 pub trait Mode {}
804
805 pub trait SdaPin<T: Instance> {}
806 pub trait SclPin<T: Instance> {}
807} 794}
808 795
796trait SealedMode {}
797
809/// Driver mode. 798/// Driver mode.
810pub trait Mode: sealed::Mode {} 799#[allow(private_bounds)]
800pub trait Mode: SealedMode {}
811 801
812macro_rules! impl_mode { 802macro_rules! impl_mode {
813 ($name:ident) => { 803 ($name:ident) => {
814 impl sealed::Mode for $name {} 804 impl SealedMode for $name {}
815 impl Mode for $name {} 805 impl Mode for $name {}
816 }; 806 };
817} 807}
@@ -825,16 +815,18 @@ impl_mode!(Blocking);
825impl_mode!(Async); 815impl_mode!(Async);
826 816
827/// I2C instance. 817/// I2C instance.
828pub trait Instance: sealed::Instance {} 818#[allow(private_bounds)]
819pub trait Instance: SealedInstance {
820 /// Interrupt for this peripheral.
821 type Interrupt: interrupt::typelevel::Interrupt;
822}
829 823
830macro_rules! impl_instance { 824macro_rules! impl_instance {
831 ($type:ident, $irq:ident, $reset:ident, $tx_dreq:expr, $rx_dreq:expr) => { 825 ($type:ident, $irq:ident, $reset:ident, $tx_dreq:expr, $rx_dreq:expr) => {
832 impl sealed::Instance for peripherals::$type { 826 impl SealedInstance for peripherals::$type {
833 const TX_DREQ: u8 = $tx_dreq; 827 const TX_DREQ: u8 = $tx_dreq;
834 const RX_DREQ: u8 = $rx_dreq; 828 const RX_DREQ: u8 = $rx_dreq;
835 829
836 type Interrupt = crate::interrupt::typelevel::$irq;
837
838 #[inline] 830 #[inline]
839 fn regs() -> pac::i2c::I2c { 831 fn regs() -> pac::i2c::I2c {
840 pac::$type 832 pac::$type
@@ -854,7 +846,9 @@ macro_rules! impl_instance {
854 &WAKER 846 &WAKER
855 } 847 }
856 } 848 }
857 impl Instance for peripherals::$type {} 849 impl Instance for peripherals::$type {
850 type Interrupt = crate::interrupt::typelevel::$irq;
851 }
858 }; 852 };
859} 853}
860 854
@@ -862,13 +856,12 @@ impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33);
862impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35); 856impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35);
863 857
864/// SDA pin. 858/// SDA pin.
865pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {} 859pub trait SdaPin<T: Instance>: crate::gpio::Pin {}
866/// SCL pin. 860/// SCL pin.
867pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {} 861pub trait SclPin<T: Instance>: crate::gpio::Pin {}
868 862
869macro_rules! impl_pin { 863macro_rules! impl_pin {
870 ($pin:ident, $instance:ident, $function:ident) => { 864 ($pin:ident, $instance:ident, $function:ident) => {
871 impl sealed::$function<peripherals::$instance> for peripherals::$pin {}
872 impl $function<peripherals::$instance> for peripherals::$pin {} 865 impl $function<peripherals::$instance> for peripherals::$pin {}
873 }; 866 };
874} 867}
diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs
index 7eca700ba..2e5c57a26 100644
--- a/embassy-rp/src/pio/mod.rs
+++ b/embassy-rp/src/pio/mod.rs
@@ -15,8 +15,7 @@ use pac::pio::vals::SmExecctrlStatusSel;
15use pio::{Program, SideSet, Wrap}; 15use pio::{Program, SideSet, Wrap};
16 16
17use crate::dma::{Channel, Transfer, Word}; 17use crate::dma::{Channel, Transfer, Word};
18use crate::gpio::sealed::Pin as SealedPin; 18use crate::gpio::{self, AnyPin, Drive, Level, Pull, SealedPin, SlewRate};
19use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate};
20use crate::interrupt::typelevel::{Binding, Handler, Interrupt}; 19use crate::interrupt::typelevel::{Binding, Handler, Interrupt};
21use crate::pac::dma::vals::TreqSel; 20use crate::pac::dma::vals::TreqSel;
22use crate::relocate::RelocatedProgram; 21use crate::relocate::RelocatedProgram;
@@ -695,6 +694,12 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
695 } 694 }
696 } 695 }
697 696
697 /// Set the clock divider for this state machine.
698 pub fn set_clock_divider(&mut self, clock_divider: FixedU32<U8>) {
699 let sm = Self::this_sm();
700 sm.clkdiv().write(|w| w.0 = clock_divider.to_bits() << 8);
701 }
702
698 #[inline(always)] 703 #[inline(always)]
699 fn this_sm() -> crate::pac::pio::StateMachine { 704 fn this_sm() -> crate::pac::pio::StateMachine {
700 PIO::PIO.sm(SM) 705 PIO::PIO.sm(SM)
@@ -1148,49 +1153,47 @@ fn on_pio_drop<PIO: Instance>() {
1148 } 1153 }
1149} 1154}
1150 1155
1151mod sealed { 1156trait SealedInstance {
1152 use super::*; 1157 const PIO_NO: u8;
1153 1158 const PIO: &'static crate::pac::pio::Pio;
1154 pub trait PioPin {} 1159 const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel;
1155 1160
1156 pub trait Instance { 1161 #[inline]
1157 const PIO_NO: u8; 1162 fn wakers() -> &'static Wakers {
1158 const PIO: &'static crate::pac::pio::Pio; 1163 const NEW_AW: AtomicWaker = AtomicWaker::new();
1159 const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel; 1164 static WAKERS: Wakers = Wakers([NEW_AW; 12]);
1160 type Interrupt: crate::interrupt::typelevel::Interrupt;
1161
1162 #[inline]
1163 fn wakers() -> &'static Wakers {
1164 const NEW_AW: AtomicWaker = AtomicWaker::new();
1165 static WAKERS: Wakers = Wakers([NEW_AW; 12]);
1166 1165
1167 &WAKERS 1166 &WAKERS
1168 } 1167 }
1169 1168
1170 #[inline] 1169 #[inline]
1171 fn state() -> &'static State { 1170 fn state() -> &'static State {
1172 static STATE: State = State { 1171 static STATE: State = State {
1173 users: AtomicU8::new(0), 1172 users: AtomicU8::new(0),
1174 used_pins: AtomicU32::new(0), 1173 used_pins: AtomicU32::new(0),
1175 }; 1174 };
1176 1175
1177 &STATE 1176 &STATE
1178 }
1179 } 1177 }
1180} 1178}
1181 1179
1182/// PIO instance. 1180/// PIO instance.
1183pub trait Instance: sealed::Instance + Sized + Unpin {} 1181#[allow(private_bounds)]
1182pub trait Instance: SealedInstance + Sized + Unpin {
1183 /// Interrupt for this peripheral.
1184 type Interrupt: crate::interrupt::typelevel::Interrupt;
1185}
1184 1186
1185macro_rules! impl_pio { 1187macro_rules! impl_pio {
1186 ($name:ident, $pio:expr, $pac:ident, $funcsel:ident, $irq:ident) => { 1188 ($name:ident, $pio:expr, $pac:ident, $funcsel:ident, $irq:ident) => {
1187 impl sealed::Instance for peripherals::$name { 1189 impl SealedInstance for peripherals::$name {
1188 const PIO_NO: u8 = $pio; 1190 const PIO_NO: u8 = $pio;
1189 const PIO: &'static pac::pio::Pio = &pac::$pac; 1191 const PIO: &'static pac::pio::Pio = &pac::$pac;
1190 const FUNCSEL: pac::io::vals::Gpio0ctrlFuncsel = pac::io::vals::Gpio0ctrlFuncsel::$funcsel; 1192 const FUNCSEL: pac::io::vals::Gpio0ctrlFuncsel = pac::io::vals::Gpio0ctrlFuncsel::$funcsel;
1193 }
1194 impl Instance for peripherals::$name {
1191 type Interrupt = crate::interrupt::typelevel::$irq; 1195 type Interrupt = crate::interrupt::typelevel::$irq;
1192 } 1196 }
1193 impl Instance for peripherals::$name {}
1194 }; 1197 };
1195} 1198}
1196 1199
@@ -1198,12 +1201,11 @@ impl_pio!(PIO0, 0, PIO0, PIO0_0, PIO0_IRQ_0);
1198impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0); 1201impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0);
1199 1202
1200/// PIO pin. 1203/// PIO pin.
1201pub trait PioPin: sealed::PioPin + gpio::Pin {} 1204pub trait PioPin: gpio::Pin {}
1202 1205
1203macro_rules! impl_pio_pin { 1206macro_rules! impl_pio_pin {
1204 ($( $pin:ident, )*) => { 1207 ($( $pin:ident, )*) => {
1205 $( 1208 $(
1206 impl sealed::PioPin for peripherals::$pin {}
1207 impl PioPin for peripherals::$pin {} 1209 impl PioPin for peripherals::$pin {}
1208 )* 1210 )*
1209 }; 1211 };
diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs
index 5aab3ff4f..a1f400cfb 100644
--- a/embassy-rp/src/pwm.rs
+++ b/embassy-rp/src/pwm.rs
@@ -6,8 +6,7 @@ use fixed::FixedU16;
6use pac::pwm::regs::{ChDiv, Intr}; 6use pac::pwm::regs::{ChDiv, Intr};
7use pac::pwm::vals::Divmode; 7use pac::pwm::vals::Divmode;
8 8
9use crate::gpio::sealed::Pin as _; 9use crate::gpio::{AnyPin, Pin as GpioPin, Pull, SealedPin as _};
10use crate::gpio::{AnyPin, Pin as GpioPin};
11use crate::{pac, peripherals, RegExt}; 10use crate::{pac, peripherals, RegExt};
12 11
13/// The configuration of a PWM slice. 12/// The configuration of a PWM slice.
@@ -93,6 +92,7 @@ impl<'d, T: Slice> Pwm<'d, T> {
93 inner: impl Peripheral<P = T> + 'd, 92 inner: impl Peripheral<P = T> + 'd,
94 a: Option<PeripheralRef<'d, AnyPin>>, 93 a: Option<PeripheralRef<'d, AnyPin>>,
95 b: Option<PeripheralRef<'d, AnyPin>>, 94 b: Option<PeripheralRef<'d, AnyPin>>,
95 b_pull: Pull,
96 config: Config, 96 config: Config,
97 divmode: Divmode, 97 divmode: Divmode,
98 ) -> Self { 98 ) -> Self {
@@ -111,6 +111,10 @@ impl<'d, T: Slice> Pwm<'d, T> {
111 } 111 }
112 if let Some(pin) = &b { 112 if let Some(pin) = &b {
113 pin.gpio().ctrl().write(|w| w.set_funcsel(4)); 113 pin.gpio().ctrl().write(|w| w.set_funcsel(4));
114 pin.pad_ctrl().modify(|w| {
115 w.set_pue(b_pull == Pull::Up);
116 w.set_pde(b_pull == Pull::Down);
117 });
114 } 118 }
115 Self { 119 Self {
116 inner, 120 inner,
@@ -122,7 +126,7 @@ impl<'d, T: Slice> Pwm<'d, T> {
122 /// Create PWM driver without any configured pins. 126 /// Create PWM driver without any configured pins.
123 #[inline] 127 #[inline]
124 pub fn new_free(inner: impl Peripheral<P = T> + 'd, config: Config) -> Self { 128 pub fn new_free(inner: impl Peripheral<P = T> + 'd, config: Config) -> Self {
125 Self::new_inner(inner, None, None, config, Divmode::DIV) 129 Self::new_inner(inner, None, None, Pull::None, config, Divmode::DIV)
126 } 130 }
127 131
128 /// Create PWM driver with a single 'a' as output. 132 /// Create PWM driver with a single 'a' as output.
@@ -133,7 +137,7 @@ impl<'d, T: Slice> Pwm<'d, T> {
133 config: Config, 137 config: Config,
134 ) -> Self { 138 ) -> Self {
135 into_ref!(a); 139 into_ref!(a);
136 Self::new_inner(inner, Some(a.map_into()), None, config, Divmode::DIV) 140 Self::new_inner(inner, Some(a.map_into()), None, Pull::None, config, Divmode::DIV)
137 } 141 }
138 142
139 /// Create PWM driver with a single 'b' pin as output. 143 /// Create PWM driver with a single 'b' pin as output.
@@ -144,7 +148,7 @@ impl<'d, T: Slice> Pwm<'d, T> {
144 config: Config, 148 config: Config,
145 ) -> Self { 149 ) -> Self {
146 into_ref!(b); 150 into_ref!(b);
147 Self::new_inner(inner, None, Some(b.map_into()), config, Divmode::DIV) 151 Self::new_inner(inner, None, Some(b.map_into()), Pull::None, config, Divmode::DIV)
148 } 152 }
149 153
150 /// Create PWM driver with a 'a' and 'b' pins as output. 154 /// Create PWM driver with a 'a' and 'b' pins as output.
@@ -156,7 +160,14 @@ impl<'d, T: Slice> Pwm<'d, T> {
156 config: Config, 160 config: Config,
157 ) -> Self { 161 ) -> Self {
158 into_ref!(a, b); 162 into_ref!(a, b);
159 Self::new_inner(inner, Some(a.map_into()), Some(b.map_into()), config, Divmode::DIV) 163 Self::new_inner(
164 inner,
165 Some(a.map_into()),
166 Some(b.map_into()),
167 Pull::None,
168 config,
169 Divmode::DIV,
170 )
160 } 171 }
161 172
162 /// Create PWM driver with a single 'b' as input pin. 173 /// Create PWM driver with a single 'b' as input pin.
@@ -164,11 +175,12 @@ impl<'d, T: Slice> Pwm<'d, T> {
164 pub fn new_input( 175 pub fn new_input(
165 inner: impl Peripheral<P = T> + 'd, 176 inner: impl Peripheral<P = T> + 'd,
166 b: impl Peripheral<P = impl ChannelBPin<T>> + 'd, 177 b: impl Peripheral<P = impl ChannelBPin<T>> + 'd,
178 b_pull: Pull,
167 mode: InputMode, 179 mode: InputMode,
168 config: Config, 180 config: Config,
169 ) -> Self { 181 ) -> Self {
170 into_ref!(b); 182 into_ref!(b);
171 Self::new_inner(inner, None, Some(b.map_into()), config, mode.into()) 183 Self::new_inner(inner, None, Some(b.map_into()), b_pull, config, mode.into())
172 } 184 }
173 185
174 /// Create PWM driver with a 'a' and 'b' pins in the desired input mode. 186 /// Create PWM driver with a 'a' and 'b' pins in the desired input mode.
@@ -177,11 +189,19 @@ impl<'d, T: Slice> Pwm<'d, T> {
177 inner: impl Peripheral<P = T> + 'd, 189 inner: impl Peripheral<P = T> + 'd,
178 a: impl Peripheral<P = impl ChannelAPin<T>> + 'd, 190 a: impl Peripheral<P = impl ChannelAPin<T>> + 'd,
179 b: impl Peripheral<P = impl ChannelBPin<T>> + 'd, 191 b: impl Peripheral<P = impl ChannelBPin<T>> + 'd,
192 b_pull: Pull,
180 mode: InputMode, 193 mode: InputMode,
181 config: Config, 194 config: Config,
182 ) -> Self { 195 ) -> Self {
183 into_ref!(a, b); 196 into_ref!(a, b);
184 Self::new_inner(inner, Some(a.map_into()), Some(b.map_into()), config, mode.into()) 197 Self::new_inner(
198 inner,
199 Some(a.map_into()),
200 Some(b.map_into()),
201 b_pull,
202 config,
203 mode.into(),
204 )
185 } 205 }
186 206
187 /// Set the PWM config. 207 /// Set the PWM config.
@@ -300,12 +320,11 @@ impl<'d, T: Slice> Drop for Pwm<'d, T> {
300 } 320 }
301} 321}
302 322
303mod sealed { 323trait SealedSlice {}
304 pub trait Slice {}
305}
306 324
307/// PWM Slice. 325/// PWM Slice.
308pub trait Slice: Peripheral<P = Self> + sealed::Slice + Sized + 'static { 326#[allow(private_bounds)]
327pub trait Slice: Peripheral<P = Self> + SealedSlice + Sized + 'static {
309 /// Slice number. 328 /// Slice number.
310 fn number(&self) -> u8; 329 fn number(&self) -> u8;
311 330
@@ -317,7 +336,7 @@ pub trait Slice: Peripheral<P = Self> + sealed::Slice + Sized + 'static {
317 336
318macro_rules! slice { 337macro_rules! slice {
319 ($name:ident, $num:expr) => { 338 ($name:ident, $num:expr) => {
320 impl sealed::Slice for peripherals::$name {} 339 impl SealedSlice for peripherals::$name {}
321 impl Slice for peripherals::$name { 340 impl Slice for peripherals::$name {
322 fn number(&self) -> u8 { 341 fn number(&self) -> u8 {
323 $num 342 $num
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs
index c8691bdc2..2ce7ac645 100644
--- a/embassy-rp/src/rtc/mod.rs
+++ b/embassy-rp/src/rtc/mod.rs
@@ -188,16 +188,15 @@ pub enum RtcError {
188 NotRunning, 188 NotRunning,
189} 189}
190 190
191mod sealed { 191trait SealedInstance {
192 pub trait Instance { 192 fn regs(&self) -> crate::pac::rtc::Rtc;
193 fn regs(&self) -> crate::pac::rtc::Rtc;
194 }
195} 193}
196 194
197/// RTC peripheral instance. 195/// RTC peripheral instance.
198pub trait Instance: sealed::Instance {} 196#[allow(private_bounds)]
197pub trait Instance: SealedInstance {}
199 198
200impl sealed::Instance for crate::peripherals::RTC { 199impl SealedInstance for crate::peripherals::RTC {
201 fn regs(&self) -> crate::pac::rtc::Rtc { 200 fn regs(&self) -> crate::pac::rtc::Rtc {
202 crate::pac::RTC 201 crate::pac::RTC
203 } 202 }
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs
index a2a22ffe5..ef4c644ae 100644
--- a/embassy-rp/src/spi.rs
+++ b/embassy-rp/src/spi.rs
@@ -7,8 +7,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
7pub use embedded_hal_02::spi::{Phase, Polarity}; 7pub use embedded_hal_02::spi::{Phase, Polarity};
8 8
9use crate::dma::{AnyChannel, Channel}; 9use crate::dma::{AnyChannel, Channel};
10use crate::gpio::sealed::Pin as _; 10use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin as _};
11use crate::gpio::{AnyPin, Pin as GpioPin};
12use crate::{pac, peripherals, Peripheral}; 11use crate::{pac, peripherals, Peripheral};
13 12
14/// SPI errors. 13/// SPI errors.
@@ -443,28 +442,26 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
443 } 442 }
444} 443}
445 444
446mod sealed { 445trait SealedMode {}
447 use super::*;
448 446
449 pub trait Mode {} 447trait SealedInstance {
448 const TX_DREQ: u8;
449 const RX_DREQ: u8;
450 450
451 pub trait Instance { 451 fn regs(&self) -> pac::spi::Spi;
452 const TX_DREQ: u8;
453 const RX_DREQ: u8;
454
455 fn regs(&self) -> pac::spi::Spi;
456 }
457} 452}
458 453
459/// Mode. 454/// Mode.
460pub trait Mode: sealed::Mode {} 455#[allow(private_bounds)]
456pub trait Mode: SealedMode {}
461 457
462/// SPI instance trait. 458/// SPI instance trait.
463pub trait Instance: sealed::Instance {} 459#[allow(private_bounds)]
460pub trait Instance: SealedInstance {}
464 461
465macro_rules! impl_instance { 462macro_rules! impl_instance {
466 ($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { 463 ($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
467 impl sealed::Instance for peripherals::$type { 464 impl SealedInstance for peripherals::$type {
468 const TX_DREQ: u8 = $tx_dreq; 465 const TX_DREQ: u8 = $tx_dreq;
469 const RX_DREQ: u8 = $rx_dreq; 466 const RX_DREQ: u8 = $rx_dreq;
470 467
@@ -527,7 +524,7 @@ impl_pin!(PIN_29, SPI1, CsPin);
527 524
528macro_rules! impl_mode { 525macro_rules! impl_mode {
529 ($name:ident) => { 526 ($name:ident) => {
530 impl sealed::Mode for $name {} 527 impl SealedMode for $name {}
531 impl Mode for $name {} 528 impl Mode for $name {}
532 }; 529 };
533} 530}
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index 65dcf4eb4..ee2dcb27d 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -12,8 +12,7 @@ use pac::uart::regs::Uartris;
12 12
13use crate::clocks::clk_peri_freq; 13use crate::clocks::clk_peri_freq;
14use crate::dma::{AnyChannel, Channel}; 14use crate::dma::{AnyChannel, Channel};
15use crate::gpio::sealed::Pin; 15use crate::gpio::{AnyPin, SealedPin};
16use crate::gpio::AnyPin;
17use crate::interrupt::typelevel::{Binding, Interrupt}; 16use crate::interrupt::typelevel::{Binding, Interrupt};
18use crate::pac::io::vals::{Inover, Outover}; 17use crate::pac::io::vals::{Inover, Outover};
19use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; 18use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
@@ -1107,35 +1106,26 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M>
1107 } 1106 }
1108} 1107}
1109 1108
1110mod sealed { 1109trait SealedMode {}
1111 use super::*;
1112 1110
1113 pub trait Mode {} 1111trait SealedInstance {
1112 const TX_DREQ: u8;
1113 const RX_DREQ: u8;
1114 1114
1115 pub trait Instance { 1115 fn regs() -> pac::uart::Uart;
1116 const TX_DREQ: u8;
1117 const RX_DREQ: u8;
1118 1116
1119 type Interrupt: interrupt::typelevel::Interrupt; 1117 fn buffered_state() -> &'static buffered::State;
1120 1118
1121 fn regs() -> pac::uart::Uart; 1119 fn dma_state() -> &'static DmaState;
1122
1123 fn buffered_state() -> &'static buffered::State;
1124
1125 fn dma_state() -> &'static DmaState;
1126 }
1127 pub trait TxPin<T: Instance> {}
1128 pub trait RxPin<T: Instance> {}
1129 pub trait CtsPin<T: Instance> {}
1130 pub trait RtsPin<T: Instance> {}
1131} 1120}
1132 1121
1133/// UART mode. 1122/// UART mode.
1134pub trait Mode: sealed::Mode {} 1123#[allow(private_bounds)]
1124pub trait Mode: SealedMode {}
1135 1125
1136macro_rules! impl_mode { 1126macro_rules! impl_mode {
1137 ($name:ident) => { 1127 ($name:ident) => {
1138 impl sealed::Mode for $name {} 1128 impl SealedMode for $name {}
1139 impl Mode for $name {} 1129 impl Mode for $name {}
1140 }; 1130 };
1141} 1131}
@@ -1149,16 +1139,18 @@ impl_mode!(Blocking);
1149impl_mode!(Async); 1139impl_mode!(Async);
1150 1140
1151/// UART instance. 1141/// UART instance.
1152pub trait Instance: sealed::Instance {} 1142#[allow(private_bounds)]
1143pub trait Instance: SealedInstance {
1144 /// Interrupt for this instance.
1145 type Interrupt: interrupt::typelevel::Interrupt;
1146}
1153 1147
1154macro_rules! impl_instance { 1148macro_rules! impl_instance {
1155 ($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { 1149 ($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
1156 impl sealed::Instance for peripherals::$inst { 1150 impl SealedInstance for peripherals::$inst {
1157 const TX_DREQ: u8 = $tx_dreq; 1151 const TX_DREQ: u8 = $tx_dreq;
1158 const RX_DREQ: u8 = $rx_dreq; 1152 const RX_DREQ: u8 = $rx_dreq;
1159 1153
1160 type Interrupt = crate::interrupt::typelevel::$irq;
1161
1162 fn regs() -> pac::uart::Uart { 1154 fn regs() -> pac::uart::Uart {
1163 pac::$inst 1155 pac::$inst
1164 } 1156 }
@@ -1176,7 +1168,9 @@ macro_rules! impl_instance {
1176 &STATE 1168 &STATE
1177 } 1169 }
1178 } 1170 }
1179 impl Instance for peripherals::$inst {} 1171 impl Instance for peripherals::$inst {
1172 type Interrupt = crate::interrupt::typelevel::$irq;
1173 }
1180 }; 1174 };
1181} 1175}
1182 1176
@@ -1184,17 +1178,16 @@ impl_instance!(UART0, UART0_IRQ, 20, 21);
1184impl_instance!(UART1, UART1_IRQ, 22, 23); 1178impl_instance!(UART1, UART1_IRQ, 22, 23);
1185 1179
1186/// Trait for TX pins. 1180/// Trait for TX pins.
1187pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} 1181pub trait TxPin<T: Instance>: crate::gpio::Pin {}
1188/// Trait for RX pins. 1182/// Trait for RX pins.
1189pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} 1183pub trait RxPin<T: Instance>: crate::gpio::Pin {}
1190/// Trait for Clear To Send (CTS) pins. 1184/// Trait for Clear To Send (CTS) pins.
1191pub trait CtsPin<T: Instance>: sealed::CtsPin<T> + crate::gpio::Pin {} 1185pub trait CtsPin<T: Instance>: crate::gpio::Pin {}
1192/// Trait for Request To Send (RTS) pins. 1186/// Trait for Request To Send (RTS) pins.
1193pub trait RtsPin<T: Instance>: sealed::RtsPin<T> + crate::gpio::Pin {} 1187pub trait RtsPin<T: Instance>: crate::gpio::Pin {}
1194 1188
1195macro_rules! impl_pin { 1189macro_rules! impl_pin {
1196 ($pin:ident, $instance:ident, $function:ident) => { 1190 ($pin:ident, $instance:ident, $function:ident) => {
1197 impl sealed::$function<peripherals::$instance> for peripherals::$pin {}
1198 impl $function<peripherals::$instance> for peripherals::$pin {} 1191 impl $function<peripherals::$instance> for peripherals::$pin {}
1199 }; 1192 };
1200} 1193}
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index d68dee4a3..37d37d6d9 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -14,20 +14,19 @@ use embassy_usb_driver::{
14use crate::interrupt::typelevel::{Binding, Interrupt}; 14use crate::interrupt::typelevel::{Binding, Interrupt};
15use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; 15use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
16 16
17pub(crate) mod sealed { 17trait SealedInstance {
18 pub trait Instance { 18 fn regs() -> crate::pac::usb::Usb;
19 fn regs() -> crate::pac::usb::Usb; 19 fn dpram() -> crate::pac::usb_dpram::UsbDpram;
20 fn dpram() -> crate::pac::usb_dpram::UsbDpram;
21 }
22} 20}
23 21
24/// USB peripheral instance. 22/// USB peripheral instance.
25pub trait Instance: sealed::Instance + 'static { 23#[allow(private_bounds)]
24pub trait Instance: SealedInstance + 'static {
26 /// Interrupt for this peripheral. 25 /// Interrupt for this peripheral.
27 type Interrupt: interrupt::typelevel::Interrupt; 26 type Interrupt: interrupt::typelevel::Interrupt;
28} 27}
29 28
30impl crate::usb::sealed::Instance for peripherals::USB { 29impl crate::usb::SealedInstance for peripherals::USB {
31 fn regs() -> pac::usb::Usb { 30 fn regs() -> pac::usb::Usb {
32 pac::USBCTRL_REGS 31 pac::USBCTRL_REGS
33 } 32 }
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 7c6312f6c..89b24f0eb 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -70,7 +70,8 @@ rand_core = "0.6.3"
70sdio-host = "0.5.0" 70sdio-host = "0.5.0"
71critical-section = "1.1" 71critical-section = "1.1"
72#stm32-metapac = { version = "15" } 72#stm32-metapac = { version = "15" }
73stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f84633553331c2d154ee72de779a40cbb10fd1bd" } 73stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2b7ec569a5510c324693f0515ac8ea20b12917a9" }
74
74vcell = "0.1.3" 75vcell = "0.1.3"
75nb = "1.0.0" 76nb = "1.0.0"
76stm32-fmc = "0.3.0" 77stm32-fmc = "0.3.0"
@@ -93,9 +94,9 @@ critical-section = { version = "1.1", features = ["std"] }
93[build-dependencies] 94[build-dependencies]
94proc-macro2 = "1.0.36" 95proc-macro2 = "1.0.36"
95quote = "1.0.15" 96quote = "1.0.15"
96#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
97stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f84633553331c2d154ee72de779a40cbb10fd1bd", default-features = false, features = ["metadata"]}
98 97
98#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
99stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2b7ec569a5510c324693f0515ac8ea20b12917a9", default-features = false, features = ["metadata"]}
99 100
100[features] 101[features]
101default = ["rt"] 102default = ["rt"]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 15bb8ea62..38b6c480c 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -484,7 +484,7 @@ fn main() {
484 let expr = if let Some(mux) = self.chained_muxes.get(&v.name) { 484 let expr = if let Some(mux) = self.chained_muxes.get(&v.name) {
485 self.gen_mux(mux) 485 self.gen_mux(mux)
486 } else { 486 } else {
487 self.gen_clock(&v.name) 487 self.gen_clock(v.name)
488 }; 488 };
489 match_arms.extend(quote! { 489 match_arms.extend(quote! {
490 crate::pac::rcc::vals::#enum_name::#variant_name => #expr, 490 crate::pac::rcc::vals::#enum_name::#variant_name => #expr,
@@ -1006,7 +1006,19 @@ fn main() {
1006 (("quadspi", "BK2_IO3"), quote!(crate::qspi::BK2D3Pin)), 1006 (("quadspi", "BK2_IO3"), quote!(crate::qspi::BK2D3Pin)),
1007 (("quadspi", "BK2_NCS"), quote!(crate::qspi::BK2NSSPin)), 1007 (("quadspi", "BK2_NCS"), quote!(crate::qspi::BK2NSSPin)),
1008 (("quadspi", "CLK"), quote!(crate::qspi::SckPin)), 1008 (("quadspi", "CLK"), quote!(crate::qspi::SckPin)),
1009 ].into(); 1009 (("octospi", "IO0"), quote!(crate::ospi::D0Pin)),
1010 (("octospi", "IO1"), quote!(crate::ospi::D1Pin)),
1011 (("octospi", "IO2"), quote!(crate::ospi::D2Pin)),
1012 (("octospi", "IO3"), quote!(crate::ospi::D3Pin)),
1013 (("octospi", "IO4"), quote!(crate::ospi::D4Pin)),
1014 (("octospi", "IO5"), quote!(crate::ospi::D5Pin)),
1015 (("octospi", "IO6"), quote!(crate::ospi::D6Pin)),
1016 (("octospi", "IO7"), quote!(crate::ospi::D7Pin)),
1017 (("octospi", "DQS"), quote!(crate::ospi::DQSPin)),
1018 (("octospi", "NCS"), quote!(crate::ospi::NSSPin)),
1019 (("octospi", "CLK"), quote!(crate::ospi::SckPin)),
1020 (("octospi", "NCLK"), quote!(crate::ospi::NckPin)),
1021 ].into();
1010 1022
1011 for p in METADATA.peripherals { 1023 for p in METADATA.peripherals {
1012 if let Some(regs) = &p.registers { 1024 if let Some(regs) = &p.registers {
@@ -1129,6 +1141,7 @@ fn main() {
1129 // SDMMCv1 uses the same channel for both directions, so just implement for RX 1141 // SDMMCv1 uses the same channel for both directions, so just implement for RX
1130 (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)), 1142 (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)),
1131 (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)), 1143 (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)),
1144 (("octospi", "OCTOSPI1"), quote!(crate::ospi::OctoDma)),
1132 (("dac", "CH1"), quote!(crate::dac::DacDma1)), 1145 (("dac", "CH1"), quote!(crate::dac::DacDma1)),
1133 (("dac", "CH2"), quote!(crate::dac::DacDma2)), 1146 (("dac", "CH2"), quote!(crate::dac::DacDma2)),
1134 (("timer", "UP"), quote!(crate::timer::UpDma)), 1147 (("timer", "UP"), quote!(crate::timer::UpDma)),
@@ -1139,11 +1152,18 @@ fn main() {
1139 (("timer", "CH2"), quote!(crate::timer::Ch2Dma)), 1152 (("timer", "CH2"), quote!(crate::timer::Ch2Dma)),
1140 (("timer", "CH3"), quote!(crate::timer::Ch3Dma)), 1153 (("timer", "CH3"), quote!(crate::timer::Ch3Dma)),
1141 (("timer", "CH4"), quote!(crate::timer::Ch4Dma)), 1154 (("timer", "CH4"), quote!(crate::timer::Ch4Dma)),
1155 (("cordic", "WRITE"), quote!(crate::cordic::WriteDma)), // FIXME: stm32u5a crash on Cordic driver
1156 (("cordic", "READ"), quote!(crate::cordic::ReadDma)), // FIXME: stm32u5a crash on Cordic driver
1142 ] 1157 ]
1143 .into(); 1158 .into();
1144 1159
1145 for p in METADATA.peripherals { 1160 for p in METADATA.peripherals {
1146 if let Some(regs) = &p.registers { 1161 if let Some(regs) = &p.registers {
1162 // FIXME: stm32u5a crash on Cordic driver
1163 if chip_name.starts_with("stm32u5a") && regs.kind == "cordic" {
1164 continue;
1165 }
1166
1147 let mut dupe = HashSet::new(); 1167 let mut dupe = HashSet::new();
1148 for ch in p.dma_channels { 1168 for ch in p.dma_channels {
1149 // Some chips have multiple request numbers for the same (peri, signal, channel) combos. 1169 // Some chips have multiple request numbers for the same (peri, signal, channel) combos.
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 8c9b47197..e25630be2 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -222,6 +222,13 @@ impl<'d, T: Instance> Adc<'d, T> {
222 // spin 222 // spin
223 } 223 }
224 224
225 // RM0492, RM0481, etc.
226 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
227 #[cfg(adc_h5)]
228 if pin.channel() == 0 {
229 T::regs().or().modify(|reg| reg.set_op0(true));
230 }
231
225 // Configure channel 232 // Configure channel
226 Self::set_channel_sample_time(pin.channel(), self.sample_time); 233 Self::set_channel_sample_time(pin.channel(), self.sample_time);
227 234
@@ -244,6 +251,13 @@ impl<'d, T: Instance> Adc<'d, T> {
244 251
245 T::regs().cr().modify(|reg| reg.set_addis(true)); 252 T::regs().cr().modify(|reg| reg.set_addis(true));
246 253
254 // RM0492, RM0481, etc.
255 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
256 #[cfg(adc_h5)]
257 if pin.channel() == 0 {
258 T::regs().or().modify(|reg| reg.set_op0(false));
259 }
260
247 val 261 val
248 } 262 }
249 263
diff --git a/embassy-stm32/src/cordic/enums.rs b/embassy-stm32/src/cordic/enums.rs
new file mode 100644
index 000000000..e8695fac7
--- /dev/null
+++ b/embassy-stm32/src/cordic/enums.rs
@@ -0,0 +1,71 @@
1/// CORDIC function
2#[allow(missing_docs)]
3#[derive(Debug, Clone, Copy)]
4#[cfg_attr(feature = "defmt", derive(defmt::Format))]
5pub enum Function {
6 Cos = 0,
7 Sin,
8 Phase,
9 Modulus,
10 Arctan,
11 Cosh,
12 Sinh,
13 Arctanh,
14 Ln,
15 Sqrt,
16}
17
18/// CORDIC precision
19#[allow(missing_docs)]
20#[derive(Debug, Clone, Copy, Default)]
21pub enum Precision {
22 Iters4 = 1,
23 Iters8,
24 Iters12,
25 Iters16,
26 Iters20,
27 #[default]
28 Iters24, // this value is recommended by Reference Manual
29 Iters28,
30 Iters32,
31 Iters36,
32 Iters40,
33 Iters44,
34 Iters48,
35 Iters52,
36 Iters56,
37 Iters60,
38}
39
40/// CORDIC scale
41#[allow(missing_docs)]
42#[derive(Debug, Clone, Copy, Default, PartialEq)]
43#[cfg_attr(feature = "defmt", derive(defmt::Format))]
44pub enum Scale {
45 #[default]
46 Arg1Res1 = 0,
47 Arg1o2Res2,
48 Arg1o4Res4,
49 Arg1o8Res8,
50 Arg1o16Res16,
51 Arg1o32Res32,
52 Arg1o64Res64,
53 Arg1o128Res128,
54}
55
56/// CORDIC argument/result register access count
57#[allow(missing_docs)]
58#[derive(Clone, Copy, Default)]
59pub enum AccessCount {
60 #[default]
61 One,
62 Two,
63}
64
65/// CORDIC argument/result data width
66#[allow(missing_docs)]
67#[derive(Clone, Copy)]
68pub enum Width {
69 Bits32,
70 Bits16,
71}
diff --git a/embassy-stm32/src/cordic/errors.rs b/embassy-stm32/src/cordic/errors.rs
new file mode 100644
index 000000000..3c70fc9e7
--- /dev/null
+++ b/embassy-stm32/src/cordic/errors.rs
@@ -0,0 +1,144 @@
1use super::{Function, Scale};
2
3/// Error for [Cordic](super::Cordic)
4#[derive(Debug)]
5pub enum CordicError {
6 /// Config error
7 ConfigError(ConfigError),
8 /// Argument length is incorrect
9 ArgumentLengthIncorrect,
10 /// Result buffer length error
11 ResultLengthNotEnough,
12 /// Input value is out of range for Q1.x format
13 NumberOutOfRange(NumberOutOfRange),
14 /// Argument error
15 ArgError(ArgError),
16}
17
18impl From<ConfigError> for CordicError {
19 fn from(value: ConfigError) -> Self {
20 Self::ConfigError(value)
21 }
22}
23
24impl From<NumberOutOfRange> for CordicError {
25 fn from(value: NumberOutOfRange) -> Self {
26 Self::NumberOutOfRange(value)
27 }
28}
29
30impl From<ArgError> for CordicError {
31 fn from(value: ArgError) -> Self {
32 Self::ArgError(value)
33 }
34}
35
36#[cfg(feature = "defmt")]
37impl defmt::Format for CordicError {
38 fn format(&self, fmt: defmt::Formatter) {
39 use CordicError::*;
40
41 match self {
42 ConfigError(e) => defmt::write!(fmt, "{}", e),
43 ResultLengthNotEnough => defmt::write!(fmt, "Output buffer length is not long enough"),
44 ArgumentLengthIncorrect => defmt::write!(fmt, "Argument length incorrect"),
45 NumberOutOfRange(e) => defmt::write!(fmt, "{}", e),
46 ArgError(e) => defmt::write!(fmt, "{}", e),
47 }
48 }
49}
50
51/// Error during parsing [Cordic::Config](super::Config)
52#[allow(dead_code)]
53#[derive(Debug)]
54pub struct ConfigError {
55 pub(super) func: Function,
56 pub(super) scale_range: [u8; 2],
57}
58
59#[cfg(feature = "defmt")]
60impl defmt::Format for ConfigError {
61 fn format(&self, fmt: defmt::Formatter) {
62 defmt::write!(fmt, "For FUNCTION: {},", self.func);
63
64 if self.scale_range[0] == self.scale_range[1] {
65 defmt::write!(fmt, " SCALE value should be {}", self.scale_range[0])
66 } else {
67 defmt::write!(
68 fmt,
69 " SCALE value should be {} <= SCALE <= {}",
70 self.scale_range[0],
71 self.scale_range[1]
72 )
73 }
74 }
75}
76
77/// Input value is out of range for Q1.x format
78#[allow(missing_docs)]
79#[derive(Debug)]
80pub enum NumberOutOfRange {
81 BelowLowerBound,
82 AboveUpperBound,
83}
84
85#[cfg(feature = "defmt")]
86impl defmt::Format for NumberOutOfRange {
87 fn format(&self, fmt: defmt::Formatter) {
88 use NumberOutOfRange::*;
89
90 match self {
91 BelowLowerBound => defmt::write!(fmt, "input value should be equal or greater than -1"),
92 AboveUpperBound => defmt::write!(fmt, "input value should be equal or less than 1"),
93 }
94 }
95}
96
97/// Error on checking input arguments
98#[allow(dead_code)]
99#[derive(Debug)]
100pub struct ArgError {
101 pub(super) func: Function,
102 pub(super) scale: Option<Scale>,
103 pub(super) arg_range: [f32; 2], // only for debug display, f32 is ok
104 pub(super) inclusive_upper_bound: bool,
105 pub(super) arg_type: ArgType,
106}
107
108#[cfg(feature = "defmt")]
109impl defmt::Format for ArgError {
110 fn format(&self, fmt: defmt::Formatter) {
111 defmt::write!(fmt, "For FUNCTION: {},", self.func);
112
113 if let Some(scale) = self.scale {
114 defmt::write!(fmt, " when SCALE is {},", scale);
115 }
116
117 defmt::write!(fmt, " {} should be", self.arg_type);
118
119 if self.inclusive_upper_bound {
120 defmt::write!(
121 fmt,
122 " {} <= {} <= {}",
123 self.arg_range[0],
124 self.arg_type,
125 self.arg_range[1]
126 )
127 } else {
128 defmt::write!(
129 fmt,
130 " {} <= {} < {}",
131 self.arg_range[0],
132 self.arg_type,
133 self.arg_range[1]
134 )
135 };
136 }
137}
138
139#[derive(Debug)]
140#[cfg_attr(feature = "defmt", derive(defmt::Format))]
141pub(super) enum ArgType {
142 Arg1,
143 Arg2,
144}
diff --git a/embassy-stm32/src/cordic/mod.rs b/embassy-stm32/src/cordic/mod.rs
new file mode 100644
index 000000000..9ac10e714
--- /dev/null
+++ b/embassy-stm32/src/cordic/mod.rs
@@ -0,0 +1,729 @@
1//! coordinate rotation digital computer (CORDIC)
2
3use embassy_hal_internal::drop::OnDrop;
4use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
5
6use crate::pac::cordic::vals;
7use crate::{dma, peripherals};
8
9mod enums;
10pub use enums::*;
11
12mod errors;
13pub use errors::*;
14
15pub mod utils;
16
17/// CORDIC driver
18pub struct Cordic<'d, T: Instance> {
19 peri: PeripheralRef<'d, T>,
20 config: Config,
21}
22
23/// Cordic instance
24trait SealedInstance {
25 /// Get access to CORDIC registers
26 fn regs() -> crate::pac::cordic::Cordic;
27
28 /// Set Function value
29 fn set_func(&self, func: Function) {
30 Self::regs()
31 .csr()
32 .modify(|v| v.set_func(vals::Func::from_bits(func as u8)));
33 }
34
35 /// Set Precision value
36 fn set_precision(&self, precision: Precision) {
37 Self::regs()
38 .csr()
39 .modify(|v| v.set_precision(vals::Precision::from_bits(precision as u8)))
40 }
41
42 /// Set Scale value
43 fn set_scale(&self, scale: Scale) {
44 Self::regs()
45 .csr()
46 .modify(|v| v.set_scale(vals::Scale::from_bits(scale as u8)))
47 }
48
49 /// Enable global interrupt
50 fn enable_irq(&self) {
51 Self::regs().csr().modify(|v| v.set_ien(true))
52 }
53
54 /// Disable global interrupt
55 fn disable_irq(&self) {
56 Self::regs().csr().modify(|v| v.set_ien(false))
57 }
58
59 /// Enable Read DMA
60 fn enable_read_dma(&self) {
61 Self::regs().csr().modify(|v| {
62 v.set_dmaren(true);
63 })
64 }
65
66 /// Disable Read DMA
67 fn disable_read_dma(&self) {
68 Self::regs().csr().modify(|v| {
69 v.set_dmaren(false);
70 })
71 }
72
73 /// Enable Write DMA
74 fn enable_write_dma(&self) {
75 Self::regs().csr().modify(|v| {
76 v.set_dmawen(true);
77 })
78 }
79
80 /// Disable Write DMA
81 fn disable_write_dma(&self) {
82 Self::regs().csr().modify(|v| {
83 v.set_dmawen(false);
84 })
85 }
86
87 /// Set NARGS value
88 fn set_argument_count(&self, n: AccessCount) {
89 Self::regs().csr().modify(|v| {
90 v.set_nargs(match n {
91 AccessCount::One => vals::Num::NUM1,
92 AccessCount::Two => vals::Num::NUM2,
93 })
94 })
95 }
96
97 /// Set NRES value
98 fn set_result_count(&self, n: AccessCount) {
99 Self::regs().csr().modify(|v| {
100 v.set_nres(match n {
101 AccessCount::One => vals::Num::NUM1,
102 AccessCount::Two => vals::Num::NUM2,
103 });
104 })
105 }
106
107 /// Set ARGSIZE and RESSIZE value
108 fn set_data_width(&self, arg: Width, res: Width) {
109 Self::regs().csr().modify(|v| {
110 v.set_argsize(match arg {
111 Width::Bits32 => vals::Size::BITS32,
112 Width::Bits16 => vals::Size::BITS16,
113 });
114 v.set_ressize(match res {
115 Width::Bits32 => vals::Size::BITS32,
116 Width::Bits16 => vals::Size::BITS16,
117 })
118 })
119 }
120
121 /// Read RRDY flag
122 fn ready_to_read(&self) -> bool {
123 Self::regs().csr().read().rrdy()
124 }
125
126 /// Write value to WDATA
127 fn write_argument(&self, arg: u32) {
128 Self::regs().wdata().write_value(arg)
129 }
130
131 /// Read value from RDATA
132 fn read_result(&self) -> u32 {
133 Self::regs().rdata().read()
134 }
135}
136
137/// CORDIC instance trait
138#[allow(private_bounds)]
139pub trait Instance: SealedInstance + Peripheral<P = Self> + crate::rcc::RccPeripheral {}
140
141/// CORDIC configuration
142#[derive(Debug)]
143pub struct Config {
144 function: Function,
145 precision: Precision,
146 scale: Scale,
147}
148
149impl Config {
150 /// Create a config for Cordic driver
151 pub fn new(function: Function, precision: Precision, scale: Scale) -> Result<Self, CordicError> {
152 let config = Self {
153 function,
154 precision,
155 scale,
156 };
157
158 config.check_scale()?;
159
160 Ok(config)
161 }
162
163 fn check_scale(&self) -> Result<(), ConfigError> {
164 use Function::*;
165
166 let scale_raw = self.scale as u8;
167
168 let err_range = match self.function {
169 Cos | Sin | Phase | Modulus if !(0..=0).contains(&scale_raw) => Some([0, 0]),
170
171 Arctan if !(0..=7).contains(&scale_raw) => Some([0, 7]),
172
173 Cosh | Sinh | Arctanh if !(1..=1).contains(&scale_raw) => Some([1, 1]),
174
175 Ln if !(1..=4).contains(&scale_raw) => Some([1, 4]),
176
177 Sqrt if !(0..=2).contains(&scale_raw) => Some([0, 2]),
178
179 Cos | Sin | Phase | Modulus | Arctan | Cosh | Sinh | Arctanh | Ln | Sqrt => None,
180 };
181
182 if let Some(range) = err_range {
183 Err(ConfigError {
184 func: self.function,
185 scale_range: range,
186 })
187 } else {
188 Ok(())
189 }
190 }
191}
192
193// common method
194impl<'d, T: Instance> Cordic<'d, T> {
195 /// Create a Cordic driver instance
196 ///
197 /// Note:
198 /// If you need a peripheral -> CORDIC -> peripheral mode,
199 /// you may want to set Cordic into [Mode::ZeroOverhead] mode, and add extra arguments with [Self::extra_config]
200 pub fn new(peri: impl Peripheral<P = T> + 'd, config: Config) -> Self {
201 T::enable_and_reset();
202
203 into_ref!(peri);
204
205 let mut instance = Self { peri, config };
206
207 instance.reconfigure();
208
209 instance
210 }
211
212 /// Set a new config for Cordic driver
213 pub fn set_config(&mut self, config: Config) {
214 self.config = config;
215 self.reconfigure();
216 }
217
218 /// Set extra config for data count and data width.
219 pub fn extra_config(&mut self, arg_cnt: AccessCount, arg_width: Width, res_width: Width) {
220 self.peri.set_argument_count(arg_cnt);
221 self.peri.set_data_width(arg_width, res_width);
222 }
223
224 fn clean_rrdy_flag(&mut self) {
225 while self.peri.ready_to_read() {
226 self.peri.read_result();
227 }
228 }
229
230 /// Disable IRQ and DMA, clean RRDY, and set ARG2 to +1 (0x7FFFFFFF)
231 pub fn reconfigure(&mut self) {
232 // reset ARG2 to +1
233 {
234 self.peri.disable_irq();
235 self.peri.disable_read_dma();
236 self.peri.disable_write_dma();
237 self.clean_rrdy_flag();
238
239 self.peri.set_func(Function::Cos);
240 self.peri.set_precision(Precision::Iters4);
241 self.peri.set_scale(Scale::Arg1Res1);
242 self.peri.set_argument_count(AccessCount::Two);
243 self.peri.set_data_width(Width::Bits32, Width::Bits32);
244 self.peri.write_argument(0x0u32);
245 self.peri.write_argument(0x7FFFFFFFu32);
246
247 self.clean_rrdy_flag();
248 }
249
250 self.peri.set_func(self.config.function);
251 self.peri.set_precision(self.config.precision);
252 self.peri.set_scale(self.config.scale);
253
254 // we don't set NRES in here, but to make sure NRES is set each time user call "calc"-ish functions,
255 // since each "calc"-ish functions can have different ARGSIZE and RESSIZE, thus NRES should be change accordingly.
256 }
257}
258
259impl<'d, T: Instance> Drop for Cordic<'d, T> {
260 fn drop(&mut self) {
261 T::disable();
262 }
263}
264
265// q1.31 related
266impl<'d, T: Instance> Cordic<'d, T> {
267 /// Run a blocking CORDIC calculation in q1.31 format
268 ///
269 /// Notice:
270 /// If you set `arg1_only` to `true`, please be sure ARG2 value has been set to desired value before.
271 /// This function won't set ARG2 to +1 before or after each round of calculation.
272 /// If you want to make sure ARG2 is set to +1, consider run [.reconfigure()](Self::reconfigure).
273 pub fn blocking_calc_32bit(
274 &mut self,
275 arg: &[u32],
276 res: &mut [u32],
277 arg1_only: bool,
278 res1_only: bool,
279 ) -> Result<usize, CordicError> {
280 if arg.is_empty() {
281 return Ok(0);
282 }
283
284 let res_cnt = Self::check_arg_res_length_32bit(arg.len(), res.len(), arg1_only, res1_only)?;
285
286 self.peri
287 .set_argument_count(if arg1_only { AccessCount::One } else { AccessCount::Two });
288
289 self.peri
290 .set_result_count(if res1_only { AccessCount::One } else { AccessCount::Two });
291
292 self.peri.set_data_width(Width::Bits32, Width::Bits32);
293
294 let mut cnt = 0;
295
296 match arg1_only {
297 true => {
298 // To use cordic preload function, the first value is special.
299 // It is loaded to CORDIC WDATA register out side of loop
300 let first_value = arg[0];
301
302 // preload 1st value to CORDIC, to start the CORDIC calc
303 self.peri.write_argument(first_value);
304
305 for &arg1 in &arg[1..] {
306 // preload arg1 (for next calc)
307 self.peri.write_argument(arg1);
308
309 // then read current result out
310 res[cnt] = self.peri.read_result();
311 cnt += 1;
312 if !res1_only {
313 res[cnt] = self.peri.read_result();
314 cnt += 1;
315 }
316 }
317
318 // read the last result
319 res[cnt] = self.peri.read_result();
320 cnt += 1;
321 if !res1_only {
322 res[cnt] = self.peri.read_result();
323 // cnt += 1;
324 }
325 }
326 false => {
327 // To use cordic preload function, the first and last value is special.
328 // They are load to CORDIC WDATA register out side of loop
329 let first_value = arg[0];
330 let last_value = arg[arg.len() - 1];
331
332 let paired_args = &arg[1..arg.len() - 1];
333
334 // preload 1st value to CORDIC
335 self.peri.write_argument(first_value);
336
337 for args in paired_args.chunks(2) {
338 let arg2 = args[0];
339 let arg1 = args[1];
340
341 // load arg2 (for current calc) first, to start the CORDIC calc
342 self.peri.write_argument(arg2);
343
344 // preload arg1 (for next calc)
345 self.peri.write_argument(arg1);
346
347 // then read current result out
348 res[cnt] = self.peri.read_result();
349 cnt += 1;
350 if !res1_only {
351 res[cnt] = self.peri.read_result();
352 cnt += 1;
353 }
354 }
355
356 // load last value to CORDIC, and finish the calculation
357 self.peri.write_argument(last_value);
358 res[cnt] = self.peri.read_result();
359 cnt += 1;
360 if !res1_only {
361 res[cnt] = self.peri.read_result();
362 // cnt += 1;
363 }
364 }
365 }
366
367 // at this point cnt should be equal to res_cnt
368
369 Ok(res_cnt)
370 }
371
372 /// Run a async CORDIC calculation in q.1.31 format
373 ///
374 /// Notice:
375 /// If you set `arg1_only` to `true`, please be sure ARG2 value has been set to desired value before.
376 /// This function won't set ARG2 to +1 before or after each round of calculation.
377 /// If you want to make sure ARG2 is set to +1, consider run [.reconfigure()](Self::reconfigure).
378 pub async fn async_calc_32bit(
379 &mut self,
380 write_dma: impl Peripheral<P = impl WriteDma<T>>,
381 read_dma: impl Peripheral<P = impl ReadDma<T>>,
382 arg: &[u32],
383 res: &mut [u32],
384 arg1_only: bool,
385 res1_only: bool,
386 ) -> Result<usize, CordicError> {
387 if arg.is_empty() {
388 return Ok(0);
389 }
390
391 let res_cnt = Self::check_arg_res_length_32bit(arg.len(), res.len(), arg1_only, res1_only)?;
392
393 let active_res_buf = &mut res[..res_cnt];
394
395 into_ref!(write_dma, read_dma);
396
397 self.peri
398 .set_argument_count(if arg1_only { AccessCount::One } else { AccessCount::Two });
399
400 self.peri
401 .set_result_count(if res1_only { AccessCount::One } else { AccessCount::Two });
402
403 self.peri.set_data_width(Width::Bits32, Width::Bits32);
404
405 let write_req = write_dma.request();
406 let read_req = read_dma.request();
407
408 self.peri.enable_write_dma();
409 self.peri.enable_read_dma();
410
411 let _on_drop = OnDrop::new(|| {
412 self.peri.disable_write_dma();
413 self.peri.disable_read_dma();
414 });
415
416 unsafe {
417 let write_transfer = dma::Transfer::new_write(
418 &mut write_dma,
419 write_req,
420 arg,
421 T::regs().wdata().as_ptr() as *mut _,
422 Default::default(),
423 );
424
425 let read_transfer = dma::Transfer::new_read(
426 &mut read_dma,
427 read_req,
428 T::regs().rdata().as_ptr() as *mut _,
429 active_res_buf,
430 Default::default(),
431 );
432
433 embassy_futures::join::join(write_transfer, read_transfer).await;
434 }
435
436 Ok(res_cnt)
437 }
438
439 fn check_arg_res_length_32bit(
440 arg_len: usize,
441 res_len: usize,
442 arg1_only: bool,
443 res1_only: bool,
444 ) -> Result<usize, CordicError> {
445 if !arg1_only && arg_len % 2 != 0 {
446 return Err(CordicError::ArgumentLengthIncorrect);
447 }
448
449 let mut minimal_res_length = arg_len;
450
451 if !res1_only {
452 minimal_res_length *= 2;
453 }
454
455 if !arg1_only {
456 minimal_res_length /= 2
457 }
458
459 if minimal_res_length > res_len {
460 return Err(CordicError::ResultLengthNotEnough);
461 }
462
463 Ok(minimal_res_length)
464 }
465}
466
467// q1.15 related
468impl<'d, T: Instance> Cordic<'d, T> {
469 /// Run a blocking CORDIC calculation in q1.15 format
470 ///
471 /// Notice::
472 /// User will take respond to merge two u16 arguments into one u32 data, and/or split one u32 data into two u16 results.
473 pub fn blocking_calc_16bit(&mut self, arg: &[u32], res: &mut [u32]) -> Result<usize, CordicError> {
474 if arg.is_empty() {
475 return Ok(0);
476 }
477
478 if arg.len() > res.len() {
479 return Err(CordicError::ResultLengthNotEnough);
480 }
481
482 let res_cnt = arg.len();
483
484 // In q1.15 mode, 1 write/read to access 2 arguments/results
485 self.peri.set_argument_count(AccessCount::One);
486 self.peri.set_result_count(AccessCount::One);
487
488 self.peri.set_data_width(Width::Bits16, Width::Bits16);
489
490 // To use cordic preload function, the first value is special.
491 // It is loaded to CORDIC WDATA register out side of loop
492 let first_value = arg[0];
493
494 // preload 1st value to CORDIC, to start the CORDIC calc
495 self.peri.write_argument(first_value);
496
497 let mut cnt = 0;
498
499 for &arg_val in &arg[1..] {
500 // preload arg_val (for next calc)
501 self.peri.write_argument(arg_val);
502
503 // then read current result out
504 res[cnt] = self.peri.read_result();
505 cnt += 1;
506 }
507
508 // read last result out
509 res[cnt] = self.peri.read_result();
510 // cnt += 1;
511
512 Ok(res_cnt)
513 }
514
515 /// Run a async CORDIC calculation in q1.15 format
516 ///
517 /// Notice::
518 /// User will take respond to merge two u16 arguments into one u32 data, and/or split one u32 data into two u16 results.
519 pub async fn async_calc_16bit(
520 &mut self,
521 write_dma: impl Peripheral<P = impl WriteDma<T>>,
522 read_dma: impl Peripheral<P = impl ReadDma<T>>,
523 arg: &[u32],
524 res: &mut [u32],
525 ) -> Result<usize, CordicError> {
526 if arg.is_empty() {
527 return Ok(0);
528 }
529
530 if arg.len() > res.len() {
531 return Err(CordicError::ResultLengthNotEnough);
532 }
533
534 let res_cnt = arg.len();
535
536 let active_res_buf = &mut res[..res_cnt];
537
538 into_ref!(write_dma, read_dma);
539
540 // In q1.15 mode, 1 write/read to access 2 arguments/results
541 self.peri.set_argument_count(AccessCount::One);
542 self.peri.set_result_count(AccessCount::One);
543
544 self.peri.set_data_width(Width::Bits16, Width::Bits16);
545
546 let write_req = write_dma.request();
547 let read_req = read_dma.request();
548
549 self.peri.enable_write_dma();
550 self.peri.enable_read_dma();
551
552 let _on_drop = OnDrop::new(|| {
553 self.peri.disable_write_dma();
554 self.peri.disable_read_dma();
555 });
556
557 unsafe {
558 let write_transfer = dma::Transfer::new_write(
559 &mut write_dma,
560 write_req,
561 arg,
562 T::regs().wdata().as_ptr() as *mut _,
563 Default::default(),
564 );
565
566 let read_transfer = dma::Transfer::new_read(
567 &mut read_dma,
568 read_req,
569 T::regs().rdata().as_ptr() as *mut _,
570 active_res_buf,
571 Default::default(),
572 );
573
574 embassy_futures::join::join(write_transfer, read_transfer).await;
575 }
576
577 Ok(res_cnt)
578 }
579}
580
581macro_rules! check_arg_value {
582 ($func_arg1_name:ident, $func_arg2_name:ident, $float_type:ty) => {
583 impl<'d, T: Instance> Cordic<'d, T> {
584 /// check input value ARG1, SCALE and FUNCTION are compatible with each other
585 pub fn $func_arg1_name(&self, arg: $float_type) -> Result<(), ArgError> {
586 let config = &self.config;
587
588 use Function::*;
589
590 struct Arg1ErrInfo {
591 scale: Option<Scale>,
592 range: [f32; 2], // f32 is ok, it only used in error display
593 inclusive_upper_bound: bool,
594 }
595
596 let err_info = match config.function {
597 Cos | Sin | Phase | Modulus | Arctan if !(-1.0..=1.0).contains(arg) => Some(Arg1ErrInfo {
598 scale: None,
599 range: [-1.0, 1.0],
600 inclusive_upper_bound: true,
601 }),
602
603 Cosh | Sinh if !(-0.559..=0.559).contains(arg) => Some(Arg1ErrInfo {
604 scale: None,
605 range: [-0.559, 0.559],
606 inclusive_upper_bound: true,
607 }),
608
609 Arctanh if !(-0.403..=0.403).contains(arg) => Some(Arg1ErrInfo {
610 scale: None,
611 range: [-0.403, 0.403],
612 inclusive_upper_bound: true,
613 }),
614
615 Ln => match config.scale {
616 Scale::Arg1o2Res2 if !(0.0535..0.5).contains(arg) => Some(Arg1ErrInfo {
617 scale: Some(Scale::Arg1o2Res2),
618 range: [0.0535, 0.5],
619 inclusive_upper_bound: false,
620 }),
621 Scale::Arg1o4Res4 if !(0.25..0.75).contains(arg) => Some(Arg1ErrInfo {
622 scale: Some(Scale::Arg1o4Res4),
623 range: [0.25, 0.75],
624 inclusive_upper_bound: false,
625 }),
626 Scale::Arg1o8Res8 if !(0.375..0.875).contains(arg) => Some(Arg1ErrInfo {
627 scale: Some(Scale::Arg1o8Res8),
628 range: [0.375, 0.875],
629 inclusive_upper_bound: false,
630 }),
631 Scale::Arg1o16Res16 if !(0.4375..0.584).contains(arg) => Some(Arg1ErrInfo {
632 scale: Some(Scale::Arg1o16Res16),
633 range: [0.4375, 0.584],
634 inclusive_upper_bound: false,
635 }),
636
637 Scale::Arg1o2Res2 | Scale::Arg1o4Res4 | Scale::Arg1o8Res8 | Scale::Arg1o16Res16 => None,
638
639 _ => unreachable!(),
640 },
641
642 Sqrt => match config.scale {
643 Scale::Arg1Res1 if !(0.027..0.75).contains(arg) => Some(Arg1ErrInfo {
644 scale: Some(Scale::Arg1Res1),
645 range: [0.027, 0.75],
646 inclusive_upper_bound: false,
647 }),
648 Scale::Arg1o2Res2 if !(0.375..0.875).contains(arg) => Some(Arg1ErrInfo {
649 scale: Some(Scale::Arg1o2Res2),
650 range: [0.375, 0.875],
651 inclusive_upper_bound: false,
652 }),
653 Scale::Arg1o4Res4 if !(0.4375..0.584).contains(arg) => Some(Arg1ErrInfo {
654 scale: Some(Scale::Arg1o4Res4),
655 range: [0.4375, 0.584],
656 inclusive_upper_bound: false,
657 }),
658 Scale::Arg1Res1 | Scale::Arg1o2Res2 | Scale::Arg1o4Res4 => None,
659 _ => unreachable!(),
660 },
661
662 Cos | Sin | Phase | Modulus | Arctan | Cosh | Sinh | Arctanh => None,
663 };
664
665 if let Some(err) = err_info {
666 return Err(ArgError {
667 func: config.function,
668 scale: err.scale,
669 arg_range: err.range,
670 inclusive_upper_bound: err.inclusive_upper_bound,
671 arg_type: ArgType::Arg1,
672 });
673 }
674
675 Ok(())
676 }
677
678 /// check input value ARG2 and FUNCTION are compatible with each other
679 pub fn $func_arg2_name(&self, arg: $float_type) -> Result<(), ArgError> {
680 let config = &self.config;
681
682 use Function::*;
683
684 struct Arg2ErrInfo {
685 range: [f32; 2], // f32 is ok, it only used in error display
686 }
687
688 let err_info = match config.function {
689 Cos | Sin if !(0.0..=1.0).contains(arg) => Some(Arg2ErrInfo { range: [0.0, 1.0] }),
690
691 Phase | Modulus if !(-1.0..=1.0).contains(arg) => Some(Arg2ErrInfo { range: [-1.0, 1.0] }),
692
693 Cos | Sin | Phase | Modulus | Arctan | Cosh | Sinh | Arctanh | Ln | Sqrt => None,
694 };
695
696 if let Some(err) = err_info {
697 return Err(ArgError {
698 func: config.function,
699 scale: None,
700 arg_range: err.range,
701 inclusive_upper_bound: true,
702 arg_type: ArgType::Arg2,
703 });
704 }
705
706 Ok(())
707 }
708 }
709 };
710}
711
712check_arg_value!(check_f64_arg1, check_f64_arg2, &f64);
713check_arg_value!(check_f32_arg1, check_f32_arg2, &f32);
714
715foreach_interrupt!(
716 ($inst:ident, cordic, $block:ident, GLOBAL, $irq:ident) => {
717 impl Instance for peripherals::$inst {
718 }
719
720 impl SealedInstance for peripherals::$inst {
721 fn regs() -> crate::pac::cordic::Cordic {
722 crate::pac::$inst
723 }
724 }
725 };
726);
727
728dma_trait!(WriteDma, Instance);
729dma_trait!(ReadDma, Instance);
diff --git a/embassy-stm32/src/cordic/utils.rs b/embassy-stm32/src/cordic/utils.rs
new file mode 100644
index 000000000..008f50270
--- /dev/null
+++ b/embassy-stm32/src/cordic/utils.rs
@@ -0,0 +1,62 @@
1//! Common math utils
2use super::errors::NumberOutOfRange;
3
4macro_rules! floating_fixed_convert {
5 ($f_to_q:ident, $q_to_f:ident, $unsigned_bin_typ:ty, $signed_bin_typ:ty, $float_ty:ty, $offset:literal, $min_positive:literal) => {
6 /// convert float point to fixed point format
7 pub fn $f_to_q(value: $float_ty) -> Result<$unsigned_bin_typ, NumberOutOfRange> {
8 const MIN_POSITIVE: $float_ty = unsafe { core::mem::transmute($min_positive) };
9
10 if value < -1.0 {
11 return Err(NumberOutOfRange::BelowLowerBound)
12 }
13
14 if value > 1.0 {
15 return Err(NumberOutOfRange::AboveUpperBound)
16 }
17
18
19 let value = if 1.0 - MIN_POSITIVE < value && value <= 1.0 {
20 // make a exception for value between (1.0^{-x} , 1.0] float point,
21 // convert it to max representable value of q1.x format
22 (1.0 as $float_ty) - MIN_POSITIVE
23 } else {
24 value
25 };
26
27 // It's necessary to cast the float value to signed integer, before convert it to a unsigned value.
28 // Since value from register is actually a "signed value", a "as" cast will keep original binary format but mark it as a unsigned value for register writing.
29 // see https://doc.rust-lang.org/reference/expressions/operator-expr.html#numeric-cast
30 Ok((value * ((1 as $unsigned_bin_typ << $offset) as $float_ty)) as $signed_bin_typ as $unsigned_bin_typ)
31 }
32
33 #[inline(always)]
34 /// convert fixed point to float point format
35 pub fn $q_to_f(value: $unsigned_bin_typ) -> $float_ty {
36 // It's necessary to cast the unsigned integer to signed integer, before convert it to a float value.
37 // Since value from register is actually a "signed value", a "as" cast will keep original binary format but mark it as a signed value.
38 // see https://doc.rust-lang.org/reference/expressions/operator-expr.html#numeric-cast
39 (value as $signed_bin_typ as $float_ty) / ((1 as $unsigned_bin_typ << $offset) as $float_ty)
40 }
41 };
42}
43
44floating_fixed_convert!(
45 f64_to_q1_31,
46 q1_31_to_f64,
47 u32,
48 i32,
49 f64,
50 31,
51 0x3E00_0000_0000_0000u64 // binary form of 1f64^(-31)
52);
53
54floating_fixed_convert!(
55 f32_to_q1_15,
56 q1_15_to_f32,
57 u16,
58 i16,
59 f32,
60 15,
61 0x3800_0000u32 // binary form of 1f32^(-15)
62);
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index f1b11cc44..a46061d54 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -6,6 +6,7 @@
6mod _version; 6mod _version;
7 7
8use core::future::Future; 8use core::future::Future;
9use core::iter;
9use core::marker::PhantomData; 10use core::marker::PhantomData;
10 11
11use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 12use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
@@ -332,8 +333,142 @@ impl<'d, T: Instance, TXDMA: TxDma<T>, RXDMA: RxDma<T>> embedded_hal_async::i2c:
332 address: u8, 333 address: u8,
333 operations: &mut [embedded_hal_1::i2c::Operation<'_>], 334 operations: &mut [embedded_hal_1::i2c::Operation<'_>],
334 ) -> Result<(), Self::Error> { 335 ) -> Result<(), Self::Error> {
335 let _ = address; 336 self.transaction(address, operations).await
336 let _ = operations;
337 todo!()
338 } 337 }
339} 338}
339
340/// Frame type in I2C transaction.
341///
342/// This tells each method what kind of framing to use, to generate a (repeated) start condition (ST
343/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an
344/// ACK or NACK after the last byte received.
345///
346/// For write operations, the following options are identical because they differ only in the (N)ACK
347/// treatment relevant for read operations:
348///
349/// - `FirstFrame` and `FirstAndNextFrame`
350/// - `NextFrame` and `LastFrameNoStop`
351///
352/// Abbreviations used below:
353///
354/// - `ST` = start condition
355/// - `SR` = repeated start condition
356/// - `SP` = stop condition
357/// - `ACK`/`NACK` = last byte in read operation
358#[derive(Copy, Clone)]
359#[allow(dead_code)]
360enum FrameOptions {
361 /// `[ST/SR]+[NACK]+[SP]` First frame (of this type) in transaction and also last frame overall.
362 FirstAndLastFrame,
363 /// `[ST/SR]+[NACK]` First frame of this type in transaction, last frame in a read operation but
364 /// not the last frame overall.
365 FirstFrame,
366 /// `[ST/SR]+[ACK]` First frame of this type in transaction, neither last frame overall nor last
367 /// frame in a read operation.
368 FirstAndNextFrame,
369 /// `[ACK]` Middle frame in a read operation (neither first nor last).
370 NextFrame,
371 /// `[NACK]+[SP]` Last frame overall in this transaction but not the first frame.
372 LastFrame,
373 /// `[NACK]` Last frame in a read operation but not last frame overall in this transaction.
374 LastFrameNoStop,
375}
376
377#[allow(dead_code)]
378impl FrameOptions {
379 /// Sends start or repeated start condition before transfer.
380 fn send_start(self) -> bool {
381 match self {
382 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true,
383 Self::NextFrame | Self::LastFrame | Self::LastFrameNoStop => false,
384 }
385 }
386
387 /// Sends stop condition after transfer.
388 fn send_stop(self) -> bool {
389 match self {
390 Self::FirstAndLastFrame | Self::LastFrame => true,
391 Self::FirstFrame | Self::FirstAndNextFrame | Self::NextFrame | Self::LastFrameNoStop => false,
392 }
393 }
394
395 /// Sends NACK after last byte received, indicating end of read operation.
396 fn send_nack(self) -> bool {
397 match self {
398 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true,
399 Self::FirstAndNextFrame | Self::NextFrame => false,
400 }
401 }
402}
403
404/// Iterates over operations in transaction.
405///
406/// Returns necessary frame options for each operation to uphold the [transaction contract] and have
407/// the right start/stop/(N)ACK conditions on the wire.
408///
409/// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
410#[allow(dead_code)]
411fn operation_frames<'a, 'b: 'a>(
412 operations: &'a mut [embedded_hal_1::i2c::Operation<'b>],
413) -> Result<impl IntoIterator<Item = (&'a mut embedded_hal_1::i2c::Operation<'b>, FrameOptions)>, Error> {
414 use embedded_hal_1::i2c::Operation::{Read, Write};
415
416 // Check empty read buffer before starting transaction. Otherwise, we would risk halting with an
417 // error in the middle of the transaction.
418 //
419 // In principle, we could allow empty read frames within consecutive read operations, as long as
420 // at least one byte remains in the final (merged) read operation, but that makes the logic more
421 // complicated and error-prone.
422 if operations.iter().any(|op| match op {
423 Read(read) => read.is_empty(),
424 Write(_) => false,
425 }) {
426 return Err(Error::Overrun);
427 }
428
429 let mut operations = operations.iter_mut().peekable();
430
431 let mut next_first_frame = true;
432
433 Ok(iter::from_fn(move || {
434 let Some(op) = operations.next() else {
435 return None;
436 };
437
438 // Is `op` first frame of its type?
439 let first_frame = next_first_frame;
440 let next_op = operations.peek();
441
442 // Get appropriate frame options as combination of the following properties:
443 //
444 // - For each first operation of its type, generate a (repeated) start condition.
445 // - For the last operation overall in the entire transaction, generate a stop condition.
446 // - For read operations, check the next operation: if it is also a read operation, we merge
447 // these and send ACK for all bytes in the current operation; send NACK only for the final
448 // read operation's last byte (before write or end of entire transaction) to indicate last
449 // byte read and release the bus for transmission of the bus master's next byte (or stop).
450 //
451 // We check the third property unconditionally, i.e. even for write opeartions. This is okay
452 // because the resulting frame options are identical for write operations.
453 let frame = match (first_frame, next_op) {
454 (true, None) => FrameOptions::FirstAndLastFrame,
455 (true, Some(Read(_))) => FrameOptions::FirstAndNextFrame,
456 (true, Some(Write(_))) => FrameOptions::FirstFrame,
457 //
458 (false, None) => FrameOptions::LastFrame,
459 (false, Some(Read(_))) => FrameOptions::NextFrame,
460 (false, Some(Write(_))) => FrameOptions::LastFrameNoStop,
461 };
462
463 // Pre-calculate if `next_op` is the first operation of its type. We do this here and not at
464 // the beginning of the loop because we hand out `op` as iterator value and cannot access it
465 // anymore in the next iteration.
466 next_first_frame = match (&op, next_op) {
467 (_, None) => false,
468 (Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true,
469 (Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false,
470 };
471
472 Some((op, frame))
473 }))
474}
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index 9f29ed5e0..d45c48b24 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -41,68 +41,6 @@ pub unsafe fn on_interrupt<T: Instance>() {
41 }); 41 });
42} 42}
43 43
44/// Frame type in I2C transaction.
45///
46/// This tells each method what kind of framing to use, to generate a (repeated) start condition (ST
47/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an
48/// ACK or NACK after the last byte received.
49///
50/// For write operations, the following options are identical because they differ only in the (N)ACK
51/// treatment relevant for read operations:
52///
53/// - `FirstFrame` and `FirstAndNextFrame`
54/// - `NextFrame` and `LastFrameNoStop`
55///
56/// Abbreviations used below:
57///
58/// - `ST` = start condition
59/// - `SR` = repeated start condition
60/// - `SP` = stop condition
61#[derive(Copy, Clone)]
62enum FrameOptions {
63 /// `[ST/SR]+[NACK]+[SP]` First frame (of this type) in operation and last frame overall in this
64 /// transaction.
65 FirstAndLastFrame,
66 /// `[ST/SR]+[NACK]` First frame of this type in transaction, last frame in a read operation but
67 /// not the last frame overall.
68 FirstFrame,
69 /// `[ST/SR]+[ACK]` First frame of this type in transaction, neither last frame overall nor last
70 /// frame in a read operation.
71 FirstAndNextFrame,
72 /// `[ACK]` Middle frame in a read operation (neither first nor last).
73 NextFrame,
74 /// `[NACK]+[SP]` Last frame overall in this transaction but not the first frame.
75 LastFrame,
76 /// `[NACK]` Last frame in a read operation but not last frame overall in this transaction.
77 LastFrameNoStop,
78}
79
80impl FrameOptions {
81 /// Sends start or repeated start condition before transfer.
82 fn send_start(self) -> bool {
83 match self {
84 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true,
85 Self::NextFrame | Self::LastFrame | Self::LastFrameNoStop => false,
86 }
87 }
88
89 /// Sends stop condition after transfer.
90 fn send_stop(self) -> bool {
91 match self {
92 Self::FirstAndLastFrame | Self::LastFrame => true,
93 Self::FirstFrame | Self::FirstAndNextFrame | Self::NextFrame | Self::LastFrameNoStop => false,
94 }
95 }
96
97 /// Sends NACK after last byte received, indicating end of read operation.
98 fn send_nack(self) -> bool {
99 match self {
100 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true,
101 Self::FirstAndNextFrame | Self::NextFrame => false,
102 }
103 }
104}
105
106impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { 44impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
107 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) { 45 pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
108 T::regs().cr1().modify(|reg| { 46 T::regs().cr1().modify(|reg| {
@@ -199,17 +137,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
199 timeout.check()?; 137 timeout.check()?;
200 } 138 }
201 139
202 // Also wait until signalled we're master and everything is waiting for us 140 // Check if we were the ones to generate START
203 while { 141 if T::regs().cr1().read().start() || !T::regs().sr2().read().msl() {
204 Self::check_and_clear_error_flags()?; 142 return Err(Error::Arbitration);
205
206 let sr2 = T::regs().sr2().read();
207 !sr2.msl() && !sr2.busy()
208 } {
209 timeout.check()?;
210 } 143 }
211 144
212 // Set up current address, we're trying to talk to 145 // Set up current address we're trying to talk to
213 T::regs().dr().write(|reg| reg.set_dr(addr << 1)); 146 T::regs().dr().write(|reg| reg.set_dr(addr << 1));
214 147
215 // Wait until address was sent 148 // Wait until address was sent
@@ -231,10 +164,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
231 if frame.send_stop() { 164 if frame.send_stop() {
232 // Send a STOP condition 165 // Send a STOP condition
233 T::regs().cr1().modify(|reg| reg.set_stop(true)); 166 T::regs().cr1().modify(|reg| reg.set_stop(true));
234 // Wait for STOP condition to transmit.
235 while T::regs().cr1().read().stop() {
236 timeout.check()?;
237 }
238 } 167 }
239 168
240 // Fallthrough is success 169 // Fallthrough is success
@@ -301,15 +230,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
301 timeout.check()?; 230 timeout.check()?;
302 } 231 }
303 232
304 // Also wait until signalled we're master and everything is waiting for us 233 // Check if we were the ones to generate START
305 while { 234 if T::regs().cr1().read().start() || !T::regs().sr2().read().msl() {
306 let sr2 = T::regs().sr2().read(); 235 return Err(Error::Arbitration);
307 !sr2.msl() && !sr2.busy()
308 } {
309 timeout.check()?;
310 } 236 }
311 237
312 // Set up current address, we're trying to talk to 238 // Set up current address we're trying to talk to
313 T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)); 239 T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1));
314 240
315 // Wait until address was sent 241 // Wait until address was sent
@@ -340,13 +266,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
340 // Receive last byte 266 // Receive last byte
341 *last = self.recv_byte(timeout)?; 267 *last = self.recv_byte(timeout)?;
342 268
343 if frame.send_stop() {
344 // Wait for the STOP to be sent.
345 while T::regs().cr1().read().stop() {
346 timeout.check()?;
347 }
348 }
349
350 // Fallthrough is success 269 // Fallthrough is success
351 Ok(()) 270 Ok(())
352 } 271 }
@@ -386,64 +305,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
386 /// 305 ///
387 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 306 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
388 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 307 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
389 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
390 // stop condition below.
391 if operations.iter().any(|op| match op {
392 Operation::Read(read) => read.is_empty(),
393 Operation::Write(_) => false,
394 }) {
395 return Err(Error::Overrun);
396 }
397
398 let timeout = self.timeout(); 308 let timeout = self.timeout();
399 309
400 let mut operations = operations.iter_mut(); 310 for (op, frame) in operation_frames(operations)? {
401
402 let mut prev_op: Option<&mut Operation<'_>> = None;
403 let mut next_op = operations.next();
404
405 while let Some(op) = next_op {
406 next_op = operations.next();
407
408 // Check if this is the first frame of this type. This is the case for the first overall
409 // frame in the transaction and whenever the type of operation changes.
410 let first_frame =
411 match (prev_op.as_ref(), &op) {
412 (None, _) => true,
413 (Some(Operation::Read(_)), Operation::Write(_))
414 | (Some(Operation::Write(_)), Operation::Read(_)) => true,
415 (Some(Operation::Read(_)), Operation::Read(_))
416 | (Some(Operation::Write(_)), Operation::Write(_)) => false,
417 };
418
419 let frame = match (first_frame, next_op.as_ref()) {
420 // If this is the first frame of this type, we generate a (repeated) start condition
421 // but have to consider the next operation: if it is the last, we generate the final
422 // stop condition. Otherwise, we branch on the operation: with read operations, only
423 // the last byte overall (before a write operation or the end of the transaction) is
424 // to be NACK'd, i.e. if another read operation follows, we must ACK this last byte.
425 (true, None) => FrameOptions::FirstAndLastFrame,
426 // Make sure to keep sending ACK for last byte in read operation when it is followed
427 // by another consecutive read operation. If the current operation is write, this is
428 // identical to `FirstFrame`.
429 (true, Some(Operation::Read(_))) => FrameOptions::FirstAndNextFrame,
430 // Otherwise, send NACK for last byte (in read operation). (For write, this does not
431 // matter and could also be `FirstAndNextFrame`.)
432 (true, Some(Operation::Write(_))) => FrameOptions::FirstFrame,
433
434 // If this is not the first frame of its type, we do not generate a (repeated) start
435 // condition. Otherwise, we branch the same way as above.
436 (false, None) => FrameOptions::LastFrame,
437 (false, Some(Operation::Read(_))) => FrameOptions::NextFrame,
438 (false, Some(Operation::Write(_))) => FrameOptions::LastFrameNoStop,
439 };
440
441 match op { 311 match op {
442 Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?, 312 Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?,
443 Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?, 313 Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?,
444 } 314 }
445
446 prev_op = Some(op);
447 } 315 }
448 316
449 Ok(()) 317 Ok(())
@@ -459,111 +327,110 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
459 }); 327 });
460 } 328 }
461 329
462 async fn write_with_stop(&mut self, address: u8, write: &[u8], send_stop: bool) -> Result<(), Error> 330 async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error>
463 where 331 where
464 TXDMA: crate::i2c::TxDma<T>, 332 TXDMA: crate::i2c::TxDma<T>,
465 { 333 {
466 let dma_transfer = unsafe { 334 T::regs().cr2().modify(|w| {
467 let regs = T::regs(); 335 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for
468 regs.cr2().modify(|w| { 336 // reception.
469 // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 register. 337 w.set_itbufen(false);
470 w.set_dmaen(true); 338 // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2
471 w.set_itbufen(false); 339 // register.
472 }); 340 w.set_dmaen(true);
473 // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved to this address from the memory after each TxE event. 341 // Sending NACK is not necessary (nor possible) for write transfer.
474 let dst = regs.dr().as_ptr() as *mut u8; 342 w.set_last(false);
475 343 });
476 let ch = &mut self.tx_dma;
477 let request = ch.request();
478 Transfer::new_write(ch, request, write, dst, Default::default())
479 };
480 344
345 // Sentinel to disable transfer when an error occurs or future is canceled.
346 // TODO: Generate STOP condition on cancel?
481 let on_drop = OnDrop::new(|| { 347 let on_drop = OnDrop::new(|| {
482 let regs = T::regs(); 348 T::regs().cr2().modify(|w| {
483 regs.cr2().modify(|w| {
484 w.set_dmaen(false); 349 w.set_dmaen(false);
485 w.set_iterren(false); 350 w.set_iterren(false);
486 w.set_itevten(false); 351 w.set_itevten(false);
487 }) 352 })
488 }); 353 });
489 354
490 Self::enable_interrupts();
491
492 // Send a START condition
493 T::regs().cr1().modify(|reg| {
494 reg.set_start(true);
495 });
496
497 let state = T::state(); 355 let state = T::state();
498 356
499 // Wait until START condition was generated 357 if frame.send_start() {
500 poll_fn(|cx| { 358 // Send a START condition
501 state.waker.register(cx.waker()); 359 T::regs().cr1().modify(|reg| {
360 reg.set_start(true);
361 });
502 362
503 match Self::check_and_clear_error_flags() { 363 // Wait until START condition was generated
504 Err(e) => Poll::Ready(Err(e)), 364 poll_fn(|cx| {
505 Ok(sr1) => { 365 state.waker.register(cx.waker());
506 if sr1.start() { 366
507 Poll::Ready(Ok(())) 367 match Self::check_and_clear_error_flags() {
508 } else { 368 Err(e) => Poll::Ready(Err(e)),
509 Poll::Pending 369 Ok(sr1) => {
370 if sr1.start() {
371 Poll::Ready(Ok(()))
372 } else {
373 // When pending, (re-)enable interrupts to wake us up.
374 Self::enable_interrupts();
375 Poll::Pending
376 }
510 } 377 }
511 } 378 }
379 })
380 .await?;
381
382 // Check if we were the ones to generate START
383 if T::regs().cr1().read().start() || !T::regs().sr2().read().msl() {
384 return Err(Error::Arbitration);
512 } 385 }
513 })
514 .await?;
515 386
516 // Also wait until signalled we're master and everything is waiting for us 387 // Set up current address we're trying to talk to
517 Self::enable_interrupts(); 388 T::regs().dr().write(|reg| reg.set_dr(address << 1));
518 poll_fn(|cx| {
519 state.waker.register(cx.waker());
520 389
521 match Self::check_and_clear_error_flags() { 390 // Wait for the address to be acknowledged
522 Err(e) => Poll::Ready(Err(e)), 391 poll_fn(|cx| {
523 Ok(_) => { 392 state.waker.register(cx.waker());
524 let sr2 = T::regs().sr2().read(); 393
525 if !sr2.msl() && !sr2.busy() { 394 match Self::check_and_clear_error_flags() {
526 Poll::Pending 395 Err(e) => Poll::Ready(Err(e)),
527 } else { 396 Ok(sr1) => {
528 Poll::Ready(Ok(())) 397 if sr1.addr() {
398 Poll::Ready(Ok(()))
399 } else {
400 // When pending, (re-)enable interrupts to wake us up.
401 Self::enable_interrupts();
402 Poll::Pending
403 }
529 } 404 }
530 } 405 }
531 } 406 })
532 }) 407 .await?;
533 .await?;
534 408
535 // Set up current address, we're trying to talk to 409 // Clear condition by reading SR2
536 Self::enable_interrupts(); 410 T::regs().sr2().read();
537 T::regs().dr().write(|reg| reg.set_dr(address << 1)); 411 }
538 412
539 poll_fn(|cx| { 413 let dma_transfer = unsafe {
540 state.waker.register(cx.waker()); 414 // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved to
541 match Self::check_and_clear_error_flags() { 415 // this address from the memory after each TxE event.
542 Err(e) => Poll::Ready(Err(e)), 416 let dst = T::regs().dr().as_ptr() as *mut u8;
543 Ok(sr1) => { 417
544 if sr1.addr() { 418 let ch = &mut self.tx_dma;
545 // Clear the ADDR condition by reading SR2. 419 let request = ch.request();
546 T::regs().sr2().read(); 420 Transfer::new_write(ch, request, write, dst, Default::default())
547 Poll::Ready(Ok(())) 421 };
548 } else { 422
549 // If we need to go around, then re-enable the interrupts, otherwise nothing 423 // Wait for bytes to be sent, or an error to occur.
550 // can wake us up and we'll hang.
551 Self::enable_interrupts();
552 Poll::Pending
553 }
554 }
555 }
556 })
557 .await?;
558 Self::enable_interrupts();
559 let poll_error = poll_fn(|cx| { 424 let poll_error = poll_fn(|cx| {
560 state.waker.register(cx.waker()); 425 state.waker.register(cx.waker());
561 426
562 match Self::check_and_clear_error_flags() { 427 match Self::check_and_clear_error_flags() {
563 // Unclear why the Err turbofish is necessary here? The compiler didn’t require it in the other 428 Err(e) => Poll::Ready(Err::<(), Error>(e)),
564 // identical poll_fn check_and_clear matches. 429 Ok(_) => {
565 Err(e) => Poll::Ready(Err::<T, Error>(e)), 430 // When pending, (re-)enable interrupts to wake us up.
566 Ok(_) => Poll::Pending, 431 Self::enable_interrupts();
432 Poll::Pending
433 }
567 } 434 }
568 }); 435 });
569 436
@@ -573,38 +440,37 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
573 _ => Ok(()), 440 _ => Ok(()),
574 }?; 441 }?;
575 442
576 // The I2C transfer itself will take longer than the DMA transfer, so wait for that to finish too.
577
578 // 18.3.8 “Master transmitter: In the interrupt routine after the EOT interrupt, disable DMA
579 // requests then wait for a BTF event before programming the Stop condition.”
580
581 // TODO: If this has to be done “in the interrupt routine after the EOT interrupt”, where to put it?
582 T::regs().cr2().modify(|w| { 443 T::regs().cr2().modify(|w| {
583 w.set_dmaen(false); 444 w.set_dmaen(false);
584 }); 445 });
585 446
586 Self::enable_interrupts(); 447 if frame.send_stop() {
587 poll_fn(|cx| { 448 // The I2C transfer itself will take longer than the DMA transfer, so wait for that to finish too.
588 state.waker.register(cx.waker()); 449
589 450 // 18.3.8 “Master transmitter: In the interrupt routine after the EOT interrupt, disable DMA
590 match Self::check_and_clear_error_flags() { 451 // requests then wait for a BTF event before programming the Stop condition.”
591 Err(e) => Poll::Ready(Err(e)), 452 poll_fn(|cx| {
592 Ok(sr1) => { 453 state.waker.register(cx.waker());
593 if sr1.btf() { 454
594 if send_stop { 455 match Self::check_and_clear_error_flags() {
595 T::regs().cr1().modify(|w| { 456 Err(e) => Poll::Ready(Err(e)),
596 w.set_stop(true); 457 Ok(sr1) => {
597 }); 458 if sr1.btf() {
459 Poll::Ready(Ok(()))
460 } else {
461 // When pending, (re-)enable interrupts to wake us up.
462 Self::enable_interrupts();
463 Poll::Pending
598 } 464 }
599
600 Poll::Ready(Ok(()))
601 } else {
602 Poll::Pending
603 } 465 }
604 } 466 }
605 } 467 })
606 }) 468 .await?;
607 .await?; 469
470 T::regs().cr1().modify(|w| {
471 w.set_stop(true);
472 });
473 }
608 474
609 drop(on_drop); 475 drop(on_drop);
610 476
@@ -617,20 +483,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
617 where 483 where
618 TXDMA: crate::i2c::TxDma<T>, 484 TXDMA: crate::i2c::TxDma<T>,
619 { 485 {
620 self.write_with_stop(address, write, true).await?; 486 self.write_frame(address, write, FrameOptions::FirstAndLastFrame)
621 487 .await?;
622 // Wait for STOP condition to transmit.
623 Self::enable_interrupts();
624 poll_fn(|cx| {
625 T::state().waker.register(cx.waker());
626 // TODO: error interrupts are enabled here, should we additional check for and return errors?
627 if T::regs().cr1().read().stop() {
628 Poll::Pending
629 } else {
630 Poll::Ready(Ok(()))
631 }
632 })
633 .await?;
634 488
635 Ok(()) 489 Ok(())
636 } 490 }
@@ -640,135 +494,151 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
640 where 494 where
641 RXDMA: crate::i2c::RxDma<T>, 495 RXDMA: crate::i2c::RxDma<T>,
642 { 496 {
643 let state = T::state(); 497 self.read_frame(address, buffer, FrameOptions::FirstAndLastFrame)
644 let buffer_len = buffer.len(); 498 .await?;
645 499
646 let dma_transfer = unsafe { 500 Ok(())
647 let regs = T::regs(); 501 }
648 regs.cr2().modify(|w| {
649 // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2 register.
650 w.set_itbufen(false);
651 w.set_dmaen(true);
652 });
653 // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved to this address from the memory after each TxE event.
654 let src = regs.dr().as_ptr() as *mut u8;
655 502
656 let ch = &mut self.rx_dma; 503 async fn read_frame(&mut self, address: u8, buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error>
657 let request = ch.request(); 504 where
658 Transfer::new_read(ch, request, src, buffer, Default::default()) 505 RXDMA: crate::i2c::RxDma<T>,
659 }; 506 {
507 if buffer.is_empty() {
508 return Err(Error::Overrun);
509 }
510
511 // Some branches below depend on whether the buffer contains only a single byte.
512 let single_byte = buffer.len() == 1;
513
514 T::regs().cr2().modify(|w| {
515 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for
516 // reception.
517 w.set_itbufen(false);
518 // DMA mode can be enabled for transmission by setting the DMAEN bit in the I2C_CR2
519 // register.
520 w.set_dmaen(true);
521 // If, in the I2C_CR2 register, the LAST bit is set, I2C automatically sends a NACK
522 // after the next byte following EOT_1. The user can generate a Stop condition in
523 // the DMA Transfer Complete interrupt routine if enabled.
524 w.set_last(frame.send_nack() && !single_byte);
525 });
660 526
527 // Sentinel to disable transfer when an error occurs or future is canceled.
528 // TODO: Generate STOP condition on cancel?
661 let on_drop = OnDrop::new(|| { 529 let on_drop = OnDrop::new(|| {
662 let regs = T::regs(); 530 T::regs().cr2().modify(|w| {
663 regs.cr2().modify(|w| {
664 w.set_dmaen(false); 531 w.set_dmaen(false);
665 w.set_iterren(false); 532 w.set_iterren(false);
666 w.set_itevten(false); 533 w.set_itevten(false);
667 }) 534 })
668 }); 535 });
669 536
670 Self::enable_interrupts(); 537 let state = T::state();
671
672 // Send a START condition and set ACK bit
673 T::regs().cr1().modify(|reg| {
674 reg.set_start(true);
675 reg.set_ack(true);
676 });
677 538
678 // Wait until START condition was generated 539 if frame.send_start() {
679 poll_fn(|cx| { 540 // Send a START condition and set ACK bit
680 state.waker.register(cx.waker()); 541 T::regs().cr1().modify(|reg| {
542 reg.set_start(true);
543 reg.set_ack(true);
544 });
681 545
682 match Self::check_and_clear_error_flags() { 546 // Wait until START condition was generated
683 Err(e) => Poll::Ready(Err(e)), 547 poll_fn(|cx| {
684 Ok(sr1) => { 548 state.waker.register(cx.waker());
685 if sr1.start() { 549
686 Poll::Ready(Ok(())) 550 match Self::check_and_clear_error_flags() {
687 } else { 551 Err(e) => Poll::Ready(Err(e)),
688 Poll::Pending 552 Ok(sr1) => {
553 if sr1.start() {
554 Poll::Ready(Ok(()))
555 } else {
556 // When pending, (re-)enable interrupts to wake us up.
557 Self::enable_interrupts();
558 Poll::Pending
559 }
689 } 560 }
690 } 561 }
691 } 562 })
692 }) 563 .await?;
693 .await?;
694
695 // Also wait until signalled we're master and everything is waiting for us
696 Self::enable_interrupts();
697 poll_fn(|cx| {
698 state.waker.register(cx.waker());
699 564
700 // blocking read didn’t have a check_and_clear call here, but blocking write did so 565 // Check if we were the ones to generate START
701 // I’m adding it here in case that was an oversight. 566 if T::regs().cr1().read().start() || !T::regs().sr2().read().msl() {
702 match Self::check_and_clear_error_flags() { 567 return Err(Error::Arbitration);
703 Err(e) => Poll::Ready(Err(e)),
704 Ok(_) => {
705 let sr2 = T::regs().sr2().read();
706 if !sr2.msl() && !sr2.busy() {
707 Poll::Pending
708 } else {
709 Poll::Ready(Ok(()))
710 }
711 }
712 } 568 }
713 })
714 .await?;
715 569
716 // Set up current address, we're trying to talk to 570 // Set up current address we're trying to talk to
717 T::regs().dr().write(|reg| reg.set_dr((address << 1) + 1)); 571 T::regs().dr().write(|reg| reg.set_dr((address << 1) + 1));
718 572
719 // Wait for the address to be acknowledged 573 // Wait for the address to be acknowledged
720 574 poll_fn(|cx| {
721 Self::enable_interrupts(); 575 state.waker.register(cx.waker());
722 poll_fn(|cx| { 576
723 state.waker.register(cx.waker()); 577 match Self::check_and_clear_error_flags() {
724 578 Err(e) => Poll::Ready(Err(e)),
725 match Self::check_and_clear_error_flags() { 579 Ok(sr1) => {
726 Err(e) => Poll::Ready(Err(e)), 580 if sr1.addr() {
727 Ok(sr1) => { 581 Poll::Ready(Ok(()))
728 if sr1.addr() { 582 } else {
729 // 18.3.8: When a single byte must be received: the NACK must be programmed during EV6 583 // When pending, (re-)enable interrupts to wake us up.
730 // event, i.e. program ACK=0 when ADDR=1, before clearing ADDR flag. 584 Self::enable_interrupts();
731 if buffer_len == 1 { 585 Poll::Pending
732 T::regs().cr1().modify(|w| {
733 w.set_ack(false);
734 });
735 } 586 }
736 Poll::Ready(Ok(()))
737 } else {
738 Poll::Pending
739 } 587 }
740 } 588 }
589 })
590 .await?;
591
592 // 18.3.8: When a single byte must be received: the NACK must be programmed during EV6
593 // event, i.e. program ACK=0 when ADDR=1, before clearing ADDR flag.
594 if frame.send_nack() && single_byte {
595 T::regs().cr1().modify(|w| {
596 w.set_ack(false);
597 });
741 } 598 }
742 })
743 .await?;
744 599
745 // Clear ADDR condition by reading SR2 600 // Clear condition by reading SR2
746 T::regs().sr2().read(); 601 T::regs().sr2().read();
602 } else {
603 // Before starting reception of single byte (but without START condition, i.e. in case
604 // of continued frame), program NACK to emit at end of this byte.
605 if frame.send_nack() && single_byte {
606 T::regs().cr1().modify(|w| {
607 w.set_ack(false);
608 });
609 }
610 }
747 611
748 // 18.3.8: When a single byte must be received: [snip] Then the 612 // 18.3.8: When a single byte must be received: [snip] Then the user can program the STOP
749 // user can program the STOP condition either after clearing ADDR flag, or in the 613 // condition either after clearing ADDR flag, or in the DMA Transfer Complete interrupt
750 // DMA Transfer Complete interrupt routine. 614 // routine.
751 if buffer_len == 1 { 615 if frame.send_stop() && single_byte {
752 T::regs().cr1().modify(|w| { 616 T::regs().cr1().modify(|w| {
753 w.set_stop(true); 617 w.set_stop(true);
754 }); 618 });
755 } else {
756 // If, in the I2C_CR2 register, the LAST bit is set, I2C
757 // automatically sends a NACK after the next byte following EOT_1. The user can
758 // generate a Stop condition in the DMA Transfer Complete interrupt routine if enabled.
759 T::regs().cr2().modify(|w| {
760 w.set_last(true);
761 })
762 } 619 }
763 620
621 let dma_transfer = unsafe {
622 // Set the I2C_DR register address in the DMA_SxPAR register. The data will be moved
623 // from this address from the memory after each RxE event.
624 let src = T::regs().dr().as_ptr() as *mut u8;
625
626 let ch = &mut self.rx_dma;
627 let request = ch.request();
628 Transfer::new_read(ch, request, src, buffer, Default::default())
629 };
630
764 // Wait for bytes to be received, or an error to occur. 631 // Wait for bytes to be received, or an error to occur.
765 Self::enable_interrupts();
766 let poll_error = poll_fn(|cx| { 632 let poll_error = poll_fn(|cx| {
767 state.waker.register(cx.waker()); 633 state.waker.register(cx.waker());
768 634
769 match Self::check_and_clear_error_flags() { 635 match Self::check_and_clear_error_flags() {
770 Err(e) => Poll::Ready(Err::<T, Error>(e)), 636 Err(e) => Poll::Ready(Err::<(), Error>(e)),
771 _ => Poll::Pending, 637 _ => {
638 // When pending, (re-)enable interrupts to wake us up.
639 Self::enable_interrupts();
640 Poll::Pending
641 }
772 } 642 }
773 }); 643 });
774 644
@@ -777,18 +647,16 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
777 _ => Ok(()), 647 _ => Ok(()),
778 }?; 648 }?;
779 649
780 // Wait for the STOP to be sent (STOP bit cleared). 650 T::regs().cr2().modify(|w| {
781 Self::enable_interrupts(); 651 w.set_dmaen(false);
782 poll_fn(|cx| { 652 });
783 state.waker.register(cx.waker()); 653
784 // TODO: error interrupts are enabled here, should we additional check for and return errors? 654 if frame.send_stop() && !single_byte {
785 if T::regs().cr1().read().stop() { 655 T::regs().cr1().modify(|w| {
786 Poll::Pending 656 w.set_stop(true);
787 } else { 657 });
788 Poll::Ready(Ok(())) 658 }
789 } 659
790 })
791 .await?;
792 drop(on_drop); 660 drop(on_drop);
793 661
794 // Fallthrough is success 662 // Fallthrough is success
@@ -801,8 +669,34 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
801 RXDMA: crate::i2c::RxDma<T>, 669 RXDMA: crate::i2c::RxDma<T>,
802 TXDMA: crate::i2c::TxDma<T>, 670 TXDMA: crate::i2c::TxDma<T>,
803 { 671 {
804 self.write_with_stop(address, write, false).await?; 672 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
805 self.read(address, read).await 673 // stop condition below.
674 if read.is_empty() {
675 return Err(Error::Overrun);
676 }
677
678 self.write_frame(address, write, FrameOptions::FirstFrame).await?;
679 self.read_frame(address, read, FrameOptions::FirstAndLastFrame).await
680 }
681
682 /// Transaction with operations.
683 ///
684 /// Consecutive operations of same type are merged. See [transaction contract] for details.
685 ///
686 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
687 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error>
688 where
689 RXDMA: crate::i2c::RxDma<T>,
690 TXDMA: crate::i2c::TxDma<T>,
691 {
692 for (op, frame) in operation_frames(operations)? {
693 match op {
694 Operation::Read(read) => self.read_frame(addr, read, frame).await?,
695 Operation::Write(write) => self.write_frame(addr, write, frame).await?,
696 }
697 }
698
699 Ok(())
806 } 700 }
807} 701}
808 702
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 8baf2849d..da3b0ee30 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -557,6 +557,21 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
557 Ok(()) 557 Ok(())
558 } 558 }
559 559
560 /// Transaction with operations.
561 ///
562 /// Consecutive operations of same type are merged. See [transaction contract] for details.
563 ///
564 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
565 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error>
566 where
567 RXDMA: crate::i2c::RxDma<T>,
568 TXDMA: crate::i2c::TxDma<T>,
569 {
570 let _ = addr;
571 let _ = operations;
572 todo!()
573 }
574
560 // ========================= 575 // =========================
561 // Blocking public API 576 // Blocking public API
562 577
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 8b826e5ac..ea17f8477 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -32,6 +32,9 @@ pub mod timer;
32pub mod adc; 32pub mod adc;
33#[cfg(can)] 33#[cfg(can)]
34pub mod can; 34pub mod can;
35// FIXME: Cordic driver cause stm32u5a5zj crash
36#[cfg(all(cordic, not(any(stm32u5a5, stm32u5a9))))]
37pub mod cordic;
35#[cfg(crc)] 38#[cfg(crc)]
36pub mod crc; 39pub mod crc;
37#[cfg(cryp)] 40#[cfg(cryp)]
@@ -61,6 +64,8 @@ pub mod ipcc;
61pub mod low_power; 64pub mod low_power;
62#[cfg(opamp)] 65#[cfg(opamp)]
63pub mod opamp; 66pub mod opamp;
67#[cfg(octospi)]
68pub mod ospi;
64#[cfg(quadspi)] 69#[cfg(quadspi)]
65pub mod qspi; 70pub mod qspi;
66#[cfg(rng)] 71#[cfg(rng)]
@@ -244,7 +249,7 @@ pub fn init(config: Config) -> Peripherals {
244 249
245 #[cfg(dbgmcu)] 250 #[cfg(dbgmcu)]
246 crate::pac::DBGMCU.cr().modify(|cr| { 251 crate::pac::DBGMCU.cr().modify(|cr| {
247 #[cfg(any(dbgmcu_h5))] 252 #[cfg(dbgmcu_h5)]
248 { 253 {
249 cr.set_stop(config.enable_debug_during_sleep); 254 cr.set_stop(config.enable_debug_during_sleep);
250 cr.set_standby(config.enable_debug_during_sleep); 255 cr.set_standby(config.enable_debug_during_sleep);
diff --git a/embassy-stm32/src/ospi/enums.rs b/embassy-stm32/src/ospi/enums.rs
new file mode 100644
index 000000000..4021f7ce3
--- /dev/null
+++ b/embassy-stm32/src/ospi/enums.rs
@@ -0,0 +1,386 @@
1//! Enums used in Ospi configuration.
2
3#[allow(dead_code)]
4#[derive(Copy, Clone)]
5pub(crate) enum OspiMode {
6 IndirectWrite,
7 IndirectRead,
8 AutoPolling,
9 MemoryMapped,
10}
11
12impl Into<u8> for OspiMode {
13 fn into(self) -> u8 {
14 match self {
15 OspiMode::IndirectWrite => 0b00,
16 OspiMode::IndirectRead => 0b01,
17 OspiMode::AutoPolling => 0b10,
18 OspiMode::MemoryMapped => 0b11,
19 }
20 }
21}
22
23/// Ospi lane width
24#[allow(dead_code)]
25#[derive(Copy, Clone)]
26pub enum OspiWidth {
27 /// None
28 NONE,
29 /// Single lane
30 SING,
31 /// Dual lanes
32 DUAL,
33 /// Quad lanes
34 QUAD,
35 /// Eight lanes
36 OCTO,
37}
38
39impl Into<u8> for OspiWidth {
40 fn into(self) -> u8 {
41 match self {
42 OspiWidth::NONE => 0b00,
43 OspiWidth::SING => 0b01,
44 OspiWidth::DUAL => 0b10,
45 OspiWidth::QUAD => 0b11,
46 OspiWidth::OCTO => 0b100,
47 }
48 }
49}
50
51/// Flash bank selection
52#[allow(dead_code)]
53#[derive(Copy, Clone)]
54pub enum FlashSelection {
55 /// Bank 1
56 Flash1,
57 /// Bank 2
58 Flash2,
59}
60
61impl Into<bool> for FlashSelection {
62 fn into(self) -> bool {
63 match self {
64 FlashSelection::Flash1 => false,
65 FlashSelection::Flash2 => true,
66 }
67 }
68}
69
70/// Wrap Size
71#[allow(dead_code)]
72#[allow(missing_docs)]
73#[derive(Copy, Clone)]
74pub enum WrapSize {
75 None,
76 _16Bytes,
77 _32Bytes,
78 _64Bytes,
79 _128Bytes,
80}
81
82impl Into<u8> for WrapSize {
83 fn into(self) -> u8 {
84 match self {
85 WrapSize::None => 0x00,
86 WrapSize::_16Bytes => 0x02,
87 WrapSize::_32Bytes => 0x03,
88 WrapSize::_64Bytes => 0x04,
89 WrapSize::_128Bytes => 0x05,
90 }
91 }
92}
93
94/// Memory Type
95#[allow(missing_docs)]
96#[allow(dead_code)]
97#[derive(Copy, Clone)]
98pub enum MemoryType {
99 Micron,
100 Macronix,
101 Standard,
102 MacronixRam,
103 HyperBusMemory,
104 HyperBusRegister,
105}
106
107impl Into<u8> for MemoryType {
108 fn into(self) -> u8 {
109 match self {
110 MemoryType::Micron => 0x00,
111 MemoryType::Macronix => 0x01,
112 MemoryType::Standard => 0x02,
113 MemoryType::MacronixRam => 0x03,
114 MemoryType::HyperBusMemory => 0x04,
115 MemoryType::HyperBusRegister => 0x04,
116 }
117 }
118}
119
120/// Ospi memory size.
121#[allow(missing_docs)]
122#[derive(Copy, Clone)]
123pub enum MemorySize {
124 _1KiB,
125 _2KiB,
126 _4KiB,
127 _8KiB,
128 _16KiB,
129 _32KiB,
130 _64KiB,
131 _128KiB,
132 _256KiB,
133 _512KiB,
134 _1MiB,
135 _2MiB,
136 _4MiB,
137 _8MiB,
138 _16MiB,
139 _32MiB,
140 _64MiB,
141 _128MiB,
142 _256MiB,
143 _512MiB,
144 _1GiB,
145 _2GiB,
146 _4GiB,
147 Other(u8),
148}
149
150impl Into<u8> for MemorySize {
151 fn into(self) -> u8 {
152 match self {
153 MemorySize::_1KiB => 9,
154 MemorySize::_2KiB => 10,
155 MemorySize::_4KiB => 11,
156 MemorySize::_8KiB => 12,
157 MemorySize::_16KiB => 13,
158 MemorySize::_32KiB => 14,
159 MemorySize::_64KiB => 15,
160 MemorySize::_128KiB => 16,
161 MemorySize::_256KiB => 17,
162 MemorySize::_512KiB => 18,
163 MemorySize::_1MiB => 19,
164 MemorySize::_2MiB => 20,
165 MemorySize::_4MiB => 21,
166 MemorySize::_8MiB => 22,
167 MemorySize::_16MiB => 23,
168 MemorySize::_32MiB => 24,
169 MemorySize::_64MiB => 25,
170 MemorySize::_128MiB => 26,
171 MemorySize::_256MiB => 27,
172 MemorySize::_512MiB => 28,
173 MemorySize::_1GiB => 29,
174 MemorySize::_2GiB => 30,
175 MemorySize::_4GiB => 31,
176 MemorySize::Other(val) => val,
177 }
178 }
179}
180
181/// Ospi Address size
182#[derive(Copy, Clone)]
183pub enum AddressSize {
184 /// 8-bit address
185 _8Bit,
186 /// 16-bit address
187 _16Bit,
188 /// 24-bit address
189 _24bit,
190 /// 32-bit address
191 _32bit,
192}
193
194impl Into<u8> for AddressSize {
195 fn into(self) -> u8 {
196 match self {
197 AddressSize::_8Bit => 0b00,
198 AddressSize::_16Bit => 0b01,
199 AddressSize::_24bit => 0b10,
200 AddressSize::_32bit => 0b11,
201 }
202 }
203}
204
205/// Time the Chip Select line stays high.
206#[allow(missing_docs)]
207#[derive(Copy, Clone)]
208pub enum ChipSelectHighTime {
209 _1Cycle,
210 _2Cycle,
211 _3Cycle,
212 _4Cycle,
213 _5Cycle,
214 _6Cycle,
215 _7Cycle,
216 _8Cycle,
217}
218
219impl Into<u8> for ChipSelectHighTime {
220 fn into(self) -> u8 {
221 match self {
222 ChipSelectHighTime::_1Cycle => 0,
223 ChipSelectHighTime::_2Cycle => 1,
224 ChipSelectHighTime::_3Cycle => 2,
225 ChipSelectHighTime::_4Cycle => 3,
226 ChipSelectHighTime::_5Cycle => 4,
227 ChipSelectHighTime::_6Cycle => 5,
228 ChipSelectHighTime::_7Cycle => 6,
229 ChipSelectHighTime::_8Cycle => 7,
230 }
231 }
232}
233
234/// FIFO threshold.
235#[allow(missing_docs)]
236#[derive(Copy, Clone)]
237pub enum FIFOThresholdLevel {
238 _1Bytes,
239 _2Bytes,
240 _3Bytes,
241 _4Bytes,
242 _5Bytes,
243 _6Bytes,
244 _7Bytes,
245 _8Bytes,
246 _9Bytes,
247 _10Bytes,
248 _11Bytes,
249 _12Bytes,
250 _13Bytes,
251 _14Bytes,
252 _15Bytes,
253 _16Bytes,
254 _17Bytes,
255 _18Bytes,
256 _19Bytes,
257 _20Bytes,
258 _21Bytes,
259 _22Bytes,
260 _23Bytes,
261 _24Bytes,
262 _25Bytes,
263 _26Bytes,
264 _27Bytes,
265 _28Bytes,
266 _29Bytes,
267 _30Bytes,
268 _31Bytes,
269 _32Bytes,
270}
271
272impl Into<u8> for FIFOThresholdLevel {
273 fn into(self) -> u8 {
274 match self {
275 FIFOThresholdLevel::_1Bytes => 0,
276 FIFOThresholdLevel::_2Bytes => 1,
277 FIFOThresholdLevel::_3Bytes => 2,
278 FIFOThresholdLevel::_4Bytes => 3,
279 FIFOThresholdLevel::_5Bytes => 4,
280 FIFOThresholdLevel::_6Bytes => 5,
281 FIFOThresholdLevel::_7Bytes => 6,
282 FIFOThresholdLevel::_8Bytes => 7,
283 FIFOThresholdLevel::_9Bytes => 8,
284 FIFOThresholdLevel::_10Bytes => 9,
285 FIFOThresholdLevel::_11Bytes => 10,
286 FIFOThresholdLevel::_12Bytes => 11,
287 FIFOThresholdLevel::_13Bytes => 12,
288 FIFOThresholdLevel::_14Bytes => 13,
289 FIFOThresholdLevel::_15Bytes => 14,
290 FIFOThresholdLevel::_16Bytes => 15,
291 FIFOThresholdLevel::_17Bytes => 16,
292 FIFOThresholdLevel::_18Bytes => 17,
293 FIFOThresholdLevel::_19Bytes => 18,
294 FIFOThresholdLevel::_20Bytes => 19,
295 FIFOThresholdLevel::_21Bytes => 20,
296 FIFOThresholdLevel::_22Bytes => 21,
297 FIFOThresholdLevel::_23Bytes => 22,
298 FIFOThresholdLevel::_24Bytes => 23,
299 FIFOThresholdLevel::_25Bytes => 24,
300 FIFOThresholdLevel::_26Bytes => 25,
301 FIFOThresholdLevel::_27Bytes => 26,
302 FIFOThresholdLevel::_28Bytes => 27,
303 FIFOThresholdLevel::_29Bytes => 28,
304 FIFOThresholdLevel::_30Bytes => 29,
305 FIFOThresholdLevel::_31Bytes => 30,
306 FIFOThresholdLevel::_32Bytes => 31,
307 }
308 }
309}
310
311/// Dummy cycle count
312#[allow(missing_docs)]
313#[derive(Copy, Clone)]
314pub enum DummyCycles {
315 _0,
316 _1,
317 _2,
318 _3,
319 _4,
320 _5,
321 _6,
322 _7,
323 _8,
324 _9,
325 _10,
326 _11,
327 _12,
328 _13,
329 _14,
330 _15,
331 _16,
332 _17,
333 _18,
334 _19,
335 _20,
336 _21,
337 _22,
338 _23,
339 _24,
340 _25,
341 _26,
342 _27,
343 _28,
344 _29,
345 _30,
346 _31,
347}
348
349impl Into<u8> for DummyCycles {
350 fn into(self) -> u8 {
351 match self {
352 DummyCycles::_0 => 0,
353 DummyCycles::_1 => 1,
354 DummyCycles::_2 => 2,
355 DummyCycles::_3 => 3,
356 DummyCycles::_4 => 4,
357 DummyCycles::_5 => 5,
358 DummyCycles::_6 => 6,
359 DummyCycles::_7 => 7,
360 DummyCycles::_8 => 8,
361 DummyCycles::_9 => 9,
362 DummyCycles::_10 => 10,
363 DummyCycles::_11 => 11,
364 DummyCycles::_12 => 12,
365 DummyCycles::_13 => 13,
366 DummyCycles::_14 => 14,
367 DummyCycles::_15 => 15,
368 DummyCycles::_16 => 16,
369 DummyCycles::_17 => 17,
370 DummyCycles::_18 => 18,
371 DummyCycles::_19 => 19,
372 DummyCycles::_20 => 20,
373 DummyCycles::_21 => 21,
374 DummyCycles::_22 => 22,
375 DummyCycles::_23 => 23,
376 DummyCycles::_24 => 24,
377 DummyCycles::_25 => 25,
378 DummyCycles::_26 => 26,
379 DummyCycles::_27 => 27,
380 DummyCycles::_28 => 28,
381 DummyCycles::_29 => 29,
382 DummyCycles::_30 => 30,
383 DummyCycles::_31 => 31,
384 }
385 }
386}
diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs
new file mode 100644
index 000000000..398c3298f
--- /dev/null
+++ b/embassy-stm32/src/ospi/mod.rs
@@ -0,0 +1,1050 @@
1//! OCTOSPI Serial Peripheral Interface
2//!
3
4#![macro_use]
5
6pub mod enums;
7
8use embassy_embedded_hal::{GetConfig, SetConfig};
9use embassy_hal_internal::{into_ref, PeripheralRef};
10pub use enums::*;
11use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits};
12
13use crate::dma::{word, Transfer};
14use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _};
15use crate::pac::octospi::{vals, Octospi as Regs};
16use crate::rcc::RccPeripheral;
17use crate::{peripherals, Peripheral};
18
19/// OPSI driver config.
20#[derive(Clone, Copy)]
21pub struct Config {
22 /// Fifo threshold used by the peripheral to generate the interrupt indicating data
23 /// or space is available in the FIFO
24 pub fifo_threshold: FIFOThresholdLevel,
25 /// Indicates the type of external device connected
26 pub memory_type: MemoryType, // Need to add an additional enum to provide this public interface
27 /// Defines the size of the external device connected to the OSPI corresponding
28 /// to the number of address bits required to access the device
29 pub device_size: MemorySize,
30 /// Sets the minimum number of clock cycles that the chip select signal must be held high
31 /// between commands
32 pub chip_select_high_time: ChipSelectHighTime,
33 /// Enables the free running clock
34 pub free_running_clock: bool,
35 /// Sets the clock level when the device is not selected
36 pub clock_mode: bool,
37 /// Indicates the wrap size corresponding to the external device configuration
38 pub wrap_size: WrapSize,
39 /// Specified the prescaler factor used for generating the external clock based
40 /// on the AHB clock
41 pub clock_prescaler: u8,
42 /// Allows the delay of 1/2 cycle the data sampling to account for external
43 /// signal delays
44 pub sample_shifting: bool,
45 /// Allows hold to 1/4 cycle the data
46 pub delay_hold_quarter_cycle: bool,
47 /// Enables the transaction boundary feature and defines the boundary to release
48 /// the chip select
49 pub chip_select_boundary: u8,
50 /// Enbales the delay block bypass so the sampling is not affected by the delay block
51 pub delay_block_bypass: bool,
52 /// Enables communication regulation feature. Chip select is released when the other
53 /// OctoSpi requests access to the bus
54 pub max_transfer: u8,
55 /// Enables the refresh feature, chip select is released every refresh + 1 clock cycles
56 pub refresh: u32,
57}
58
59impl Default for Config {
60 fn default() -> Self {
61 Self {
62 fifo_threshold: FIFOThresholdLevel::_16Bytes, // 32 bytes FIFO, half capacity
63 memory_type: MemoryType::Micron,
64 device_size: MemorySize::Other(0),
65 chip_select_high_time: ChipSelectHighTime::_5Cycle,
66 free_running_clock: false,
67 clock_mode: false,
68 wrap_size: WrapSize::None,
69 clock_prescaler: 0,
70 sample_shifting: false,
71 delay_hold_quarter_cycle: false,
72 chip_select_boundary: 0, // Acceptable range 0 to 31
73 delay_block_bypass: true,
74 max_transfer: 0,
75 refresh: 0,
76 }
77 }
78}
79
80/// OSPI transfer configuration.
81pub struct TransferConfig {
82 /// Instruction width (IMODE)
83 pub iwidth: OspiWidth,
84 /// Instruction Id
85 pub instruction: Option<u32>,
86 /// Number of Instruction Bytes
87 pub isize: AddressSize,
88 /// Instruction Double Transfer rate enable
89 pub idtr: bool,
90
91 /// Address width (ADMODE)
92 pub adwidth: OspiWidth,
93 /// Device memory address
94 pub address: Option<u32>,
95 /// Number of Address Bytes
96 pub adsize: AddressSize,
97 /// Address Double Transfer rate enable
98 pub addtr: bool,
99
100 /// Alternate bytes width (ABMODE)
101 pub abwidth: OspiWidth,
102 /// Alternate Bytes
103 pub alternate_bytes: Option<u32>,
104 /// Number of Alternate Bytes
105 pub absize: AddressSize,
106 /// Alternate Bytes Double Transfer rate enable
107 pub abdtr: bool,
108
109 /// Data width (DMODE)
110 pub dwidth: OspiWidth,
111 /// Data buffer
112 pub ddtr: bool,
113
114 /// Number of dummy cycles (DCYC)
115 pub dummy: DummyCycles,
116}
117
118impl Default for TransferConfig {
119 fn default() -> Self {
120 Self {
121 iwidth: OspiWidth::NONE,
122 instruction: None,
123 isize: AddressSize::_8Bit,
124 idtr: false,
125
126 adwidth: OspiWidth::NONE,
127 address: None,
128 adsize: AddressSize::_8Bit,
129 addtr: false,
130
131 abwidth: OspiWidth::NONE,
132 alternate_bytes: None,
133 absize: AddressSize::_8Bit,
134 abdtr: false,
135
136 dwidth: OspiWidth::NONE,
137 ddtr: false,
138
139 dummy: DummyCycles::_0,
140 }
141 }
142}
143
144/// Error used for Octospi implementation
145#[derive(Debug)]
146#[cfg_attr(feature = "defmt", derive(defmt::Format))]
147pub enum OspiError {
148 /// Peripheral configuration is invalid
149 InvalidConfiguration,
150 /// Operation configuration is invalid
151 InvalidCommand,
152 /// Size zero buffer passed to instruction
153 EmptyBuffer,
154}
155
156/// OSPI driver.
157pub struct Ospi<'d, T: Instance, Dma> {
158 _peri: PeripheralRef<'d, T>,
159 sck: Option<PeripheralRef<'d, AnyPin>>,
160 d0: Option<PeripheralRef<'d, AnyPin>>,
161 d1: Option<PeripheralRef<'d, AnyPin>>,
162 d2: Option<PeripheralRef<'d, AnyPin>>,
163 d3: Option<PeripheralRef<'d, AnyPin>>,
164 d4: Option<PeripheralRef<'d, AnyPin>>,
165 d5: Option<PeripheralRef<'d, AnyPin>>,
166 d6: Option<PeripheralRef<'d, AnyPin>>,
167 d7: Option<PeripheralRef<'d, AnyPin>>,
168 nss: Option<PeripheralRef<'d, AnyPin>>,
169 dqs: Option<PeripheralRef<'d, AnyPin>>,
170 dma: PeripheralRef<'d, Dma>,
171 config: Config,
172 width: OspiWidth,
173}
174
175impl<'d, T: Instance, Dma> Ospi<'d, T, Dma> {
176 /// Create new OSPI driver for a single spi external chip
177 pub fn new_singlespi(
178 peri: impl Peripheral<P = T> + 'd,
179 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
180 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
181 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
182 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
183 dma: impl Peripheral<P = Dma> + 'd,
184 config: Config,
185 ) -> Self {
186 into_ref!(peri, sck, d0, d1, nss);
187
188 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None);
189 sck.set_speed(crate::gpio::Speed::VeryHigh);
190 nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up);
191 nss.set_speed(crate::gpio::Speed::VeryHigh);
192 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None);
193 d0.set_speed(crate::gpio::Speed::VeryHigh);
194 d1.set_as_af_pull(d1.af_num(), AFType::Input, Pull::None);
195 d1.set_speed(crate::gpio::Speed::VeryHigh);
196
197 Self::new_inner(
198 peri,
199 Some(d0.map_into()),
200 Some(d1.map_into()),
201 None,
202 None,
203 None,
204 None,
205 None,
206 None,
207 Some(sck.map_into()),
208 Some(nss.map_into()),
209 None,
210 dma,
211 config,
212 OspiWidth::SING,
213 false,
214 )
215 }
216
217 /// Create new OSPI driver for a dualspi external chip
218 pub fn new_dualspi(
219 peri: impl Peripheral<P = T> + 'd,
220 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
221 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
222 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
223 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
224 dma: impl Peripheral<P = Dma> + 'd,
225 config: Config,
226 ) -> Self {
227 into_ref!(peri, sck, d0, d1, nss);
228
229 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None);
230 sck.set_speed(crate::gpio::Speed::VeryHigh);
231 nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up);
232 nss.set_speed(crate::gpio::Speed::VeryHigh);
233 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None);
234 d0.set_speed(crate::gpio::Speed::VeryHigh);
235 d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None);
236 d1.set_speed(crate::gpio::Speed::VeryHigh);
237
238 Self::new_inner(
239 peri,
240 Some(d0.map_into()),
241 Some(d1.map_into()),
242 None,
243 None,
244 None,
245 None,
246 None,
247 None,
248 Some(sck.map_into()),
249 Some(nss.map_into()),
250 None,
251 dma,
252 config,
253 OspiWidth::DUAL,
254 false,
255 )
256 }
257
258 /// Create new OSPI driver for a quadspi external chip
259 pub fn new_quadspi(
260 peri: impl Peripheral<P = T> + 'd,
261 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
262 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
263 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
264 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
265 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
266 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
267 dma: impl Peripheral<P = Dma> + 'd,
268 config: Config,
269 ) -> Self {
270 into_ref!(peri, sck, d0, d1, d2, d3, nss);
271
272 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None);
273 sck.set_speed(crate::gpio::Speed::VeryHigh);
274 nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up);
275 nss.set_speed(crate::gpio::Speed::VeryHigh);
276 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None);
277 d0.set_speed(crate::gpio::Speed::VeryHigh);
278 d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None);
279 d1.set_speed(crate::gpio::Speed::VeryHigh);
280 d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None);
281 d2.set_speed(crate::gpio::Speed::VeryHigh);
282 d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None);
283 d3.set_speed(crate::gpio::Speed::VeryHigh);
284
285 Self::new_inner(
286 peri,
287 Some(d0.map_into()),
288 Some(d1.map_into()),
289 Some(d2.map_into()),
290 Some(d3.map_into()),
291 None,
292 None,
293 None,
294 None,
295 Some(sck.map_into()),
296 Some(nss.map_into()),
297 None,
298 dma,
299 config,
300 OspiWidth::QUAD,
301 false,
302 )
303 }
304
305 /// Create new OSPI driver for two quadspi external chips
306 pub fn new_dualquadspi(
307 peri: impl Peripheral<P = T> + 'd,
308 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
309 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
310 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
311 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
312 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
313 d4: impl Peripheral<P = impl D4Pin<T>> + 'd,
314 d5: impl Peripheral<P = impl D5Pin<T>> + 'd,
315 d6: impl Peripheral<P = impl D6Pin<T>> + 'd,
316 d7: impl Peripheral<P = impl D7Pin<T>> + 'd,
317 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
318 dma: impl Peripheral<P = Dma> + 'd,
319 config: Config,
320 ) -> Self {
321 into_ref!(peri, sck, d0, d1, d2, d3, d4, d5, d6, d7, nss);
322
323 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None);
324 sck.set_speed(crate::gpio::Speed::VeryHigh);
325 nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up);
326 nss.set_speed(crate::gpio::Speed::VeryHigh);
327 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None);
328 d0.set_speed(crate::gpio::Speed::VeryHigh);
329 d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None);
330 d1.set_speed(crate::gpio::Speed::VeryHigh);
331 d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None);
332 d2.set_speed(crate::gpio::Speed::VeryHigh);
333 d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None);
334 d3.set_speed(crate::gpio::Speed::VeryHigh);
335 d4.set_as_af_pull(d4.af_num(), AFType::OutputPushPull, Pull::None);
336 d4.set_speed(crate::gpio::Speed::VeryHigh);
337 d5.set_as_af_pull(d5.af_num(), AFType::OutputPushPull, Pull::None);
338 d5.set_speed(crate::gpio::Speed::VeryHigh);
339 d6.set_as_af_pull(d6.af_num(), AFType::OutputPushPull, Pull::None);
340 d6.set_speed(crate::gpio::Speed::VeryHigh);
341 d7.set_as_af_pull(d7.af_num(), AFType::OutputPushPull, Pull::None);
342 d7.set_speed(crate::gpio::Speed::VeryHigh);
343
344 Self::new_inner(
345 peri,
346 Some(d0.map_into()),
347 Some(d1.map_into()),
348 Some(d2.map_into()),
349 Some(d3.map_into()),
350 Some(d4.map_into()),
351 Some(d5.map_into()),
352 Some(d6.map_into()),
353 Some(d7.map_into()),
354 Some(sck.map_into()),
355 Some(nss.map_into()),
356 None,
357 dma,
358 config,
359 OspiWidth::QUAD,
360 true,
361 )
362 }
363
364 /// Create new OSPI driver for octospi external chips
365 pub fn new_octospi(
366 peri: impl Peripheral<P = T> + 'd,
367 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
368 d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
369 d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
370 d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
371 d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
372 d4: impl Peripheral<P = impl D4Pin<T>> + 'd,
373 d5: impl Peripheral<P = impl D5Pin<T>> + 'd,
374 d6: impl Peripheral<P = impl D6Pin<T>> + 'd,
375 d7: impl Peripheral<P = impl D7Pin<T>> + 'd,
376 nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
377 dma: impl Peripheral<P = Dma> + 'd,
378 config: Config,
379 ) -> Self {
380 into_ref!(peri, sck, d0, d1, d2, d3, d4, d5, d6, d7, nss);
381
382 sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None);
383 sck.set_speed(crate::gpio::Speed::VeryHigh);
384 nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up);
385 nss.set_speed(crate::gpio::Speed::VeryHigh);
386 d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None);
387 d0.set_speed(crate::gpio::Speed::VeryHigh);
388 d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None);
389 d1.set_speed(crate::gpio::Speed::VeryHigh);
390 d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None);
391 d2.set_speed(crate::gpio::Speed::VeryHigh);
392 d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None);
393 d3.set_speed(crate::gpio::Speed::VeryHigh);
394 d4.set_as_af_pull(d4.af_num(), AFType::OutputPushPull, Pull::None);
395 d4.set_speed(crate::gpio::Speed::VeryHigh);
396 d5.set_as_af_pull(d5.af_num(), AFType::OutputPushPull, Pull::None);
397 d5.set_speed(crate::gpio::Speed::VeryHigh);
398 d6.set_as_af_pull(d6.af_num(), AFType::OutputPushPull, Pull::None);
399 d6.set_speed(crate::gpio::Speed::VeryHigh);
400 d7.set_as_af_pull(d7.af_num(), AFType::OutputPushPull, Pull::None);
401 d7.set_speed(crate::gpio::Speed::VeryHigh);
402
403 Self::new_inner(
404 peri,
405 Some(d0.map_into()),
406 Some(d1.map_into()),
407 Some(d2.map_into()),
408 Some(d3.map_into()),
409 Some(d4.map_into()),
410 Some(d5.map_into()),
411 Some(d6.map_into()),
412 Some(d7.map_into()),
413 Some(sck.map_into()),
414 Some(nss.map_into()),
415 None,
416 dma,
417 config,
418 OspiWidth::OCTO,
419 false,
420 )
421 }
422
423 fn new_inner(
424 peri: impl Peripheral<P = T> + 'd,
425 d0: Option<PeripheralRef<'d, AnyPin>>,
426 d1: Option<PeripheralRef<'d, AnyPin>>,
427 d2: Option<PeripheralRef<'d, AnyPin>>,
428 d3: Option<PeripheralRef<'d, AnyPin>>,
429 d4: Option<PeripheralRef<'d, AnyPin>>,
430 d5: Option<PeripheralRef<'d, AnyPin>>,
431 d6: Option<PeripheralRef<'d, AnyPin>>,
432 d7: Option<PeripheralRef<'d, AnyPin>>,
433 sck: Option<PeripheralRef<'d, AnyPin>>,
434 nss: Option<PeripheralRef<'d, AnyPin>>,
435 dqs: Option<PeripheralRef<'d, AnyPin>>,
436 dma: impl Peripheral<P = Dma> + 'd,
437 config: Config,
438 width: OspiWidth,
439 dual_quad: bool,
440 ) -> Self {
441 into_ref!(peri, dma);
442
443 // System configuration
444 T::enable_and_reset();
445 while T::REGS.sr().read().busy() {}
446
447 // Device configuration
448 T::REGS.dcr1().modify(|w| {
449 w.set_devsize(config.device_size.into());
450 w.set_mtyp(vals::MemType::from_bits(config.memory_type.into()));
451 w.set_csht(config.chip_select_high_time.into());
452 w.set_dlybyp(config.delay_block_bypass);
453 w.set_frck(false);
454 w.set_ckmode(config.clock_mode);
455 });
456
457 T::REGS.dcr2().modify(|w| {
458 w.set_wrapsize(config.wrap_size.into());
459 });
460
461 T::REGS.dcr3().modify(|w| {
462 w.set_csbound(config.chip_select_boundary);
463 #[cfg(octospi_v1)]
464 {
465 w.set_maxtran(config.max_transfer);
466 }
467 });
468
469 T::REGS.dcr4().modify(|w| {
470 w.set_refresh(config.refresh);
471 });
472
473 T::REGS.cr().modify(|w| {
474 w.set_fthres(vals::Threshold(config.fifo_threshold.into()));
475 });
476
477 // Wait for busy flag to clear
478 while T::REGS.sr().read().busy() {}
479
480 T::REGS.dcr2().modify(|w| {
481 w.set_prescaler(config.clock_prescaler);
482 });
483
484 T::REGS.cr().modify(|w| {
485 w.set_dmm(dual_quad);
486 });
487
488 T::REGS.tcr().modify(|w| {
489 w.set_sshift(match config.sample_shifting {
490 true => vals::SampleShift::HALFCYCLE,
491 false => vals::SampleShift::NONE,
492 });
493 w.set_dhqc(config.delay_hold_quarter_cycle);
494 });
495
496 // Enable peripheral
497 T::REGS.cr().modify(|w| {
498 w.set_en(true);
499 });
500
501 // Free running clock needs to be set after peripheral enable
502 if config.free_running_clock {
503 T::REGS.dcr1().modify(|w| {
504 w.set_frck(config.free_running_clock);
505 });
506 }
507
508 Self {
509 _peri: peri,
510 sck,
511 d0,
512 d1,
513 d2,
514 d3,
515 d4,
516 d5,
517 d6,
518 d7,
519 nss,
520 dqs,
521 dma,
522 config,
523 width,
524 }
525 }
526
527 // Function to configure the peripheral for the requested command
528 fn configure_command(&mut self, command: &TransferConfig, data_len: Option<usize>) -> Result<(), OspiError> {
529 // Check that transaction doesn't use more than hardware initialized pins
530 if <enums::OspiWidth as Into<u8>>::into(command.iwidth) > <enums::OspiWidth as Into<u8>>::into(self.width)
531 || <enums::OspiWidth as Into<u8>>::into(command.adwidth) > <enums::OspiWidth as Into<u8>>::into(self.width)
532 || <enums::OspiWidth as Into<u8>>::into(command.abwidth) > <enums::OspiWidth as Into<u8>>::into(self.width)
533 || <enums::OspiWidth as Into<u8>>::into(command.dwidth) > <enums::OspiWidth as Into<u8>>::into(self.width)
534 {
535 return Err(OspiError::InvalidCommand);
536 }
537
538 T::REGS.cr().modify(|w| {
539 w.set_fmode(0.into());
540 });
541
542 // Configure alternate bytes
543 if let Some(ab) = command.alternate_bytes {
544 T::REGS.abr().write(|v| v.set_alternate(ab));
545 T::REGS.ccr().modify(|w| {
546 w.set_abmode(PhaseMode::from_bits(command.abwidth.into()));
547 w.set_abdtr(command.abdtr);
548 w.set_absize(SizeInBits::from_bits(command.absize.into()));
549 })
550 }
551
552 // Configure dummy cycles
553 T::REGS.tcr().modify(|w| {
554 w.set_dcyc(command.dummy.into());
555 });
556
557 // Configure data
558 if let Some(data_length) = data_len {
559 T::REGS.dlr().write(|v| {
560 v.set_dl((data_length - 1) as u32);
561 })
562 } else {
563 T::REGS.dlr().write(|v| {
564 v.set_dl((0) as u32);
565 })
566 }
567
568 // Configure instruction/address/data modes
569 T::REGS.ccr().modify(|w| {
570 w.set_imode(PhaseMode::from_bits(command.iwidth.into()));
571 w.set_idtr(command.idtr);
572 w.set_isize(SizeInBits::from_bits(command.isize.into()));
573
574 w.set_admode(PhaseMode::from_bits(command.adwidth.into()));
575 w.set_addtr(command.idtr);
576 w.set_adsize(SizeInBits::from_bits(command.adsize.into()));
577
578 w.set_dmode(PhaseMode::from_bits(command.dwidth.into()));
579 w.set_ddtr(command.ddtr);
580 });
581
582 // Set informationrequired to initiate transaction
583 if let Some(instruction) = command.instruction {
584 if let Some(address) = command.address {
585 T::REGS.ir().write(|v| {
586 v.set_instruction(instruction);
587 });
588
589 T::REGS.ar().write(|v| {
590 v.set_address(address);
591 });
592 } else {
593 // Double check requirements for delay hold and sample shifting
594 // if let None = command.data_len {
595 // if self.config.delay_hold_quarter_cycle && command.idtr {
596 // T::REGS.ccr().modify(|w| {
597 // w.set_ddtr(true);
598 // });
599 // }
600 // }
601
602 T::REGS.ir().write(|v| {
603 v.set_instruction(instruction);
604 });
605 }
606 } else {
607 if let Some(address) = command.address {
608 T::REGS.ar().write(|v| {
609 v.set_address(address);
610 });
611 } else {
612 // The only single phase transaction supported is instruction only
613 return Err(OspiError::InvalidCommand);
614 }
615 }
616
617 Ok(())
618 }
619
620 /// Function used to control or configure the target device without data transfer
621 pub async fn command(&mut self, command: &TransferConfig) -> Result<(), OspiError> {
622 // Wait for peripheral to be free
623 while T::REGS.sr().read().busy() {}
624
625 // Need additional validation that command configuration doesn't have data set
626 self.configure_command(command, None)?;
627
628 // Transaction initiated by setting final configuration, i.e the instruction register
629 while !T::REGS.sr().read().tcf() {}
630 T::REGS.fcr().write(|w| {
631 w.set_ctcf(true);
632 });
633
634 Ok(())
635 }
636
637 /// Blocking read with byte by byte data transfer
638 pub fn blocking_read<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError> {
639 if buf.is_empty() {
640 return Err(OspiError::EmptyBuffer);
641 }
642
643 // Wait for peripheral to be free
644 while T::REGS.sr().read().busy() {}
645
646 // Ensure DMA is not enabled for this transaction
647 T::REGS.cr().modify(|w| {
648 w.set_dmaen(false);
649 });
650
651 self.configure_command(&transaction, Some(buf.len()))?;
652
653 let current_address = T::REGS.ar().read().address();
654 let current_instruction = T::REGS.ir().read().instruction();
655
656 // For a indirect read transaction, the transaction begins when the instruction/address is set
657 T::REGS.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD));
658 if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE {
659 T::REGS.ir().write(|v| v.set_instruction(current_instruction));
660 } else {
661 T::REGS.ar().write(|v| v.set_address(current_address));
662 }
663
664 for idx in 0..buf.len() {
665 while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
666 buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut W).read_volatile() };
667 }
668
669 while !T::REGS.sr().read().tcf() {}
670 T::REGS.fcr().write(|v| v.set_ctcf(true));
671
672 Ok(())
673 }
674
675 /// Blocking write with byte by byte data transfer
676 pub fn blocking_write<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), OspiError> {
677 if buf.is_empty() {
678 return Err(OspiError::EmptyBuffer);
679 }
680
681 // Wait for peripheral to be free
682 while T::REGS.sr().read().busy() {}
683
684 T::REGS.cr().modify(|w| {
685 w.set_dmaen(false);
686 });
687
688 self.configure_command(&transaction, Some(buf.len()))?;
689
690 T::REGS
691 .cr()
692 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE));
693
694 for idx in 0..buf.len() {
695 while !T::REGS.sr().read().ftf() {}
696 unsafe { (T::REGS.dr().as_ptr() as *mut W).write_volatile(buf[idx]) };
697 }
698
699 while !T::REGS.sr().read().tcf() {}
700 T::REGS.fcr().write(|v| v.set_ctcf(true));
701
702 Ok(())
703 }
704
705 /// Blocking read with DMA transfer
706 pub fn blocking_read_dma<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError>
707 where
708 Dma: OctoDma<T>,
709 {
710 if buf.is_empty() {
711 return Err(OspiError::EmptyBuffer);
712 }
713
714 // Wait for peripheral to be free
715 while T::REGS.sr().read().busy() {}
716
717 self.configure_command(&transaction, Some(buf.len()))?;
718
719 let current_address = T::REGS.ar().read().address();
720 let current_instruction = T::REGS.ir().read().instruction();
721
722 // For a indirect read transaction, the transaction begins when the instruction/address is set
723 T::REGS.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD));
724 if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE {
725 T::REGS.ir().write(|v| v.set_instruction(current_instruction));
726 } else {
727 T::REGS.ar().write(|v| v.set_address(current_address));
728 }
729
730 let request = self.dma.request();
731 let transfer = unsafe {
732 Transfer::new_read(
733 &mut self.dma,
734 request,
735 T::REGS.dr().as_ptr() as *mut W,
736 buf,
737 Default::default(),
738 )
739 };
740
741 T::REGS.cr().modify(|w| w.set_dmaen(true));
742
743 transfer.blocking_wait();
744
745 finish_dma(T::REGS);
746
747 Ok(())
748 }
749
750 /// Blocking write with DMA transfer
751 pub fn blocking_write_dma<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), OspiError>
752 where
753 Dma: OctoDma<T>,
754 {
755 if buf.is_empty() {
756 return Err(OspiError::EmptyBuffer);
757 }
758
759 // Wait for peripheral to be free
760 while T::REGS.sr().read().busy() {}
761
762 self.configure_command(&transaction, Some(buf.len()))?;
763 T::REGS
764 .cr()
765 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE));
766
767 let request = self.dma.request();
768 let transfer = unsafe {
769 Transfer::new_write(
770 &mut self.dma,
771 request,
772 buf,
773 T::REGS.dr().as_ptr() as *mut W,
774 Default::default(),
775 )
776 };
777
778 T::REGS.cr().modify(|w| w.set_dmaen(true));
779
780 transfer.blocking_wait();
781
782 finish_dma(T::REGS);
783
784 Ok(())
785 }
786
787 /// Asynchronous read from external device
788 pub async fn read<W: Word>(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), OspiError>
789 where
790 Dma: OctoDma<T>,
791 {
792 if buf.is_empty() {
793 return Err(OspiError::EmptyBuffer);
794 }
795
796 // Wait for peripheral to be free
797 while T::REGS.sr().read().busy() {}
798
799 self.configure_command(&transaction, Some(buf.len()))?;
800
801 let current_address = T::REGS.ar().read().address();
802 let current_instruction = T::REGS.ir().read().instruction();
803
804 // For a indirect read transaction, the transaction begins when the instruction/address is set
805 T::REGS.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD));
806 if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE {
807 T::REGS.ir().write(|v| v.set_instruction(current_instruction));
808 } else {
809 T::REGS.ar().write(|v| v.set_address(current_address));
810 }
811
812 let request = self.dma.request();
813 let transfer = unsafe {
814 Transfer::new_read(
815 &mut self.dma,
816 request,
817 T::REGS.dr().as_ptr() as *mut W,
818 buf,
819 Default::default(),
820 )
821 };
822
823 T::REGS.cr().modify(|w| w.set_dmaen(true));
824
825 transfer.await;
826
827 finish_dma(T::REGS);
828
829 Ok(())
830 }
831
832 /// Asynchronous write to external device
833 pub async fn write<W: Word>(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), OspiError>
834 where
835 Dma: OctoDma<T>,
836 {
837 if buf.is_empty() {
838 return Err(OspiError::EmptyBuffer);
839 }
840
841 // Wait for peripheral to be free
842 while T::REGS.sr().read().busy() {}
843
844 self.configure_command(&transaction, Some(buf.len()))?;
845 T::REGS
846 .cr()
847 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE));
848
849 let request = self.dma.request();
850 let transfer = unsafe {
851 Transfer::new_write(
852 &mut self.dma,
853 request,
854 buf,
855 T::REGS.dr().as_ptr() as *mut W,
856 Default::default(),
857 )
858 };
859
860 T::REGS.cr().modify(|w| w.set_dmaen(true));
861
862 transfer.await;
863
864 finish_dma(T::REGS);
865
866 Ok(())
867 }
868
869 /// Set new bus configuration
870 pub fn set_config(&mut self, config: &Config) {
871 // Wait for busy flag to clear
872 while T::REGS.sr().read().busy() {}
873
874 // Disable DMA channel while configuring the peripheral
875 T::REGS.cr().modify(|w| {
876 w.set_dmaen(false);
877 });
878
879 // Device configuration
880 T::REGS.dcr1().modify(|w| {
881 w.set_devsize(config.device_size.into());
882 w.set_mtyp(vals::MemType::from_bits(config.memory_type.into()));
883 w.set_csht(config.chip_select_high_time.into());
884 w.set_dlybyp(config.delay_block_bypass);
885 w.set_frck(false);
886 w.set_ckmode(config.clock_mode);
887 });
888
889 T::REGS.dcr2().modify(|w| {
890 w.set_wrapsize(config.wrap_size.into());
891 });
892
893 T::REGS.dcr3().modify(|w| {
894 w.set_csbound(config.chip_select_boundary);
895 #[cfg(octospi_v1)]
896 {
897 w.set_maxtran(config.max_transfer);
898 }
899 });
900
901 T::REGS.dcr4().modify(|w| {
902 w.set_refresh(config.refresh);
903 });
904
905 T::REGS.cr().modify(|w| {
906 w.set_fthres(vals::Threshold(config.fifo_threshold.into()));
907 });
908
909 // Wait for busy flag to clear
910 while T::REGS.sr().read().busy() {}
911
912 T::REGS.dcr2().modify(|w| {
913 w.set_prescaler(config.clock_prescaler);
914 });
915
916 T::REGS.tcr().modify(|w| {
917 w.set_sshift(match config.sample_shifting {
918 true => vals::SampleShift::HALFCYCLE,
919 false => vals::SampleShift::NONE,
920 });
921 w.set_dhqc(config.delay_hold_quarter_cycle);
922 });
923
924 // Enable peripheral
925 T::REGS.cr().modify(|w| {
926 w.set_en(true);
927 });
928
929 // Free running clock needs to be set after peripheral enable
930 if config.free_running_clock {
931 T::REGS.dcr1().modify(|w| {
932 w.set_frck(config.free_running_clock);
933 });
934 }
935
936 self.config = *config;
937 }
938
939 /// Get current configuration
940 pub fn get_config(&self) -> Config {
941 self.config
942 }
943}
944
945impl<'d, T: Instance, Dma> Drop for Ospi<'d, T, Dma> {
946 fn drop(&mut self) {
947 self.sck.as_ref().map(|x| x.set_as_disconnected());
948 self.d0.as_ref().map(|x| x.set_as_disconnected());
949 self.d1.as_ref().map(|x| x.set_as_disconnected());
950 self.d2.as_ref().map(|x| x.set_as_disconnected());
951 self.d3.as_ref().map(|x| x.set_as_disconnected());
952 self.d4.as_ref().map(|x| x.set_as_disconnected());
953 self.d5.as_ref().map(|x| x.set_as_disconnected());
954 self.d6.as_ref().map(|x| x.set_as_disconnected());
955 self.d7.as_ref().map(|x| x.set_as_disconnected());
956 self.nss.as_ref().map(|x| x.set_as_disconnected());
957 self.dqs.as_ref().map(|x| x.set_as_disconnected());
958
959 T::disable();
960 }
961}
962
963fn finish_dma(regs: Regs) {
964 while !regs.sr().read().tcf() {}
965 regs.fcr().write(|v| v.set_ctcf(true));
966
967 regs.cr().modify(|w| {
968 w.set_dmaen(false);
969 });
970}
971
972trait RegsExt {
973 fn dr_ptr<W>(&self) -> *mut W;
974}
975
976impl RegsExt for Regs {
977 fn dr_ptr<W>(&self) -> *mut W {
978 let dr = self.dr();
979 dr.as_ptr() as *mut W
980 }
981}
982
983pub(crate) trait SealedInstance {
984 const REGS: Regs;
985}
986
987trait SealedWord {
988 const CONFIG: u8;
989}
990
991/// OSPI instance trait.
992#[allow(private_bounds)]
993pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {}
994
995pin_trait!(SckPin, Instance);
996pin_trait!(NckPin, Instance);
997pin_trait!(D0Pin, Instance);
998pin_trait!(D1Pin, Instance);
999pin_trait!(D2Pin, Instance);
1000pin_trait!(D3Pin, Instance);
1001pin_trait!(D4Pin, Instance);
1002pin_trait!(D5Pin, Instance);
1003pin_trait!(D6Pin, Instance);
1004pin_trait!(D7Pin, Instance);
1005pin_trait!(DQSPin, Instance);
1006pin_trait!(NSSPin, Instance);
1007dma_trait!(OctoDma, Instance);
1008
1009foreach_peripheral!(
1010 (octospi, $inst:ident) => {
1011 impl SealedInstance for peripherals::$inst {
1012 const REGS: Regs = crate::pac::$inst;
1013 }
1014
1015 impl Instance for peripherals::$inst {}
1016 };
1017);
1018
1019impl<'d, T: Instance, Dma> SetConfig for Ospi<'d, T, Dma> {
1020 type Config = Config;
1021 type ConfigError = ();
1022 fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
1023 self.set_config(config);
1024 Ok(())
1025 }
1026}
1027
1028impl<'d, T: Instance, Dma> GetConfig for Ospi<'d, T, Dma> {
1029 type Config = Config;
1030 fn get_config(&self) -> Self::Config {
1031 self.get_config()
1032 }
1033}
1034
1035/// Word sizes usable for OSPI.
1036#[allow(private_bounds)]
1037pub trait Word: word::Word + SealedWord {}
1038
1039macro_rules! impl_word {
1040 ($T:ty, $config:expr) => {
1041 impl SealedWord for $T {
1042 const CONFIG: u8 = $config;
1043 }
1044 impl Word for $T {}
1045 };
1046}
1047
1048impl_word!(u8, 8);
1049impl_word!(u16, 16);
1050impl_word!(u32, 32);
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index 3c054e666..0a4b4f074 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -27,8 +27,6 @@ pub struct TransferConfig {
27 pub address: Option<u32>, 27 pub address: Option<u32>,
28 /// Number of dummy cycles (DCYC) 28 /// Number of dummy cycles (DCYC)
29 pub dummy: DummyCycles, 29 pub dummy: DummyCycles,
30 /// Length of data
31 pub data_len: Option<usize>,
32} 30}
33 31
34impl Default for TransferConfig { 32impl Default for TransferConfig {
@@ -40,7 +38,6 @@ impl Default for TransferConfig {
40 instruction: 0, 38 instruction: 0,
41 address: None, 39 address: None,
42 dummy: DummyCycles::_0, 40 dummy: DummyCycles::_0,
43 data_len: None,
44 } 41 }
45 } 42 }
46} 43}
@@ -231,7 +228,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
231 pub fn command(&mut self, transaction: TransferConfig) { 228 pub fn command(&mut self, transaction: TransferConfig) {
232 #[cfg(not(stm32h7))] 229 #[cfg(not(stm32h7))]
233 T::REGS.cr().modify(|v| v.set_dmaen(false)); 230 T::REGS.cr().modify(|v| v.set_dmaen(false));
234 self.setup_transaction(QspiMode::IndirectWrite, &transaction); 231 self.setup_transaction(QspiMode::IndirectWrite, &transaction, None);
235 232
236 while !T::REGS.sr().read().tcf() {} 233 while !T::REGS.sr().read().tcf() {}
237 T::REGS.fcr().modify(|v| v.set_ctcf(true)); 234 T::REGS.fcr().modify(|v| v.set_ctcf(true));
@@ -241,21 +238,19 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
241 pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { 238 pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
242 #[cfg(not(stm32h7))] 239 #[cfg(not(stm32h7))]
243 T::REGS.cr().modify(|v| v.set_dmaen(false)); 240 T::REGS.cr().modify(|v| v.set_dmaen(false));
244 self.setup_transaction(QspiMode::IndirectWrite, &transaction); 241 self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len()));
245 242
246 if let Some(len) = transaction.data_len { 243 let current_ar = T::REGS.ar().read().address();
247 let current_ar = T::REGS.ar().read().address(); 244 T::REGS.ccr().modify(|v| {
248 T::REGS.ccr().modify(|v| { 245 v.set_fmode(QspiMode::IndirectRead.into());
249 v.set_fmode(QspiMode::IndirectRead.into()); 246 });
250 }); 247 T::REGS.ar().write(|v| {
251 T::REGS.ar().write(|v| { 248 v.set_address(current_ar);
252 v.set_address(current_ar); 249 });
253 });
254 250
255 for idx in 0..len { 251 for b in buf {
256 while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {} 252 while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
257 buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() }; 253 *b = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() };
258 }
259 } 254 }
260 255
261 while !T::REGS.sr().read().tcf() {} 256 while !T::REGS.sr().read().tcf() {}
@@ -268,17 +263,15 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
268 #[cfg(not(stm32h7))] 263 #[cfg(not(stm32h7))]
269 T::REGS.cr().modify(|v| v.set_dmaen(false)); 264 T::REGS.cr().modify(|v| v.set_dmaen(false));
270 265
271 self.setup_transaction(QspiMode::IndirectWrite, &transaction); 266 self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len()));
272 267
273 if let Some(len) = transaction.data_len { 268 T::REGS.ccr().modify(|v| {
274 T::REGS.ccr().modify(|v| { 269 v.set_fmode(QspiMode::IndirectWrite.into());
275 v.set_fmode(QspiMode::IndirectWrite.into()); 270 });
276 });
277 271
278 for idx in 0..len { 272 for &b in buf {
279 while !T::REGS.sr().read().ftf() {} 273 while !T::REGS.sr().read().ftf() {}
280 unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(buf[idx]) }; 274 unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(b) };
281 }
282 } 275 }
283 276
284 while !T::REGS.sr().read().tcf() {} 277 while !T::REGS.sr().read().tcf() {}
@@ -290,7 +283,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
290 where 283 where
291 Dma: QuadDma<T>, 284 Dma: QuadDma<T>,
292 { 285 {
293 self.setup_transaction(QspiMode::IndirectWrite, &transaction); 286 self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len()));
294 287
295 T::REGS.ccr().modify(|v| { 288 T::REGS.ccr().modify(|v| {
296 v.set_fmode(QspiMode::IndirectRead.into()); 289 v.set_fmode(QspiMode::IndirectRead.into());
@@ -323,7 +316,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
323 where 316 where
324 Dma: QuadDma<T>, 317 Dma: QuadDma<T>,
325 { 318 {
326 self.setup_transaction(QspiMode::IndirectWrite, &transaction); 319 self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len()));
327 320
328 T::REGS.ccr().modify(|v| { 321 T::REGS.ccr().modify(|v| {
329 v.set_fmode(QspiMode::IndirectWrite.into()); 322 v.set_fmode(QspiMode::IndirectWrite.into());
@@ -347,7 +340,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
347 transfer.blocking_wait(); 340 transfer.blocking_wait();
348 } 341 }
349 342
350 fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) { 343 fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig, data_len: Option<usize>) {
351 T::REGS.fcr().modify(|v| { 344 T::REGS.fcr().modify(|v| {
352 v.set_csmf(true); 345 v.set_csmf(true);
353 v.set_ctcf(true); 346 v.set_ctcf(true);
@@ -357,7 +350,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
357 350
358 while T::REGS.sr().read().busy() {} 351 while T::REGS.sr().read().busy() {}
359 352
360 if let Some(len) = transaction.data_len { 353 if let Some(len) = data_len {
361 T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1)); 354 T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1));
362 } 355 }
363 356
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index d53d02203..c328344aa 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -111,7 +111,7 @@ mod util {
111 } 111 }
112} 112}
113 113
114/// Get the kernel clocok frequency of the peripheral `T`. 114/// Get the kernel clock frequency of the peripheral `T`.
115/// 115///
116/// # Panics 116/// # Panics
117/// 117///
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index cc8161276..e592fbf7d 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -15,9 +15,7 @@ use crate::pac::timer::vals;
15use crate::rcc::SealedRccPeripheral; 15use crate::rcc::SealedRccPeripheral;
16#[cfg(feature = "low-power")] 16#[cfg(feature = "low-power")]
17use crate::rtc::Rtc; 17use crate::rtc::Rtc;
18#[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))] 18use crate::timer::{CoreInstance, GeneralInstance1Channel};
19use crate::timer::AdvancedInstance1Channel;
20use crate::timer::CoreInstance;
21use crate::{interrupt, peripherals}; 19use crate::{interrupt, peripherals};
22 20
23// NOTE regarding ALARM_COUNT: 21// NOTE regarding ALARM_COUNT:
@@ -69,7 +67,7 @@ type T = peripherals::TIM23;
69type T = peripherals::TIM24; 67type T = peripherals::TIM24;
70 68
71foreach_interrupt! { 69foreach_interrupt! {
72 (TIM1, timer, $block:ident, UP, $irq:ident) => { 70 (TIM1, timer, $block:ident, CC, $irq:ident) => {
73 #[cfg(time_driver_tim1)] 71 #[cfg(time_driver_tim1)]
74 #[cfg(feature = "rt")] 72 #[cfg(feature = "rt")]
75 #[interrupt] 73 #[interrupt]
@@ -85,7 +83,7 @@ foreach_interrupt! {
85 DRIVER.on_interrupt() 83 DRIVER.on_interrupt()
86 } 84 }
87 }; 85 };
88 (TIM2, timer, $block:ident, UP, $irq:ident) => { 86 (TIM2, timer, $block:ident, CC, $irq:ident) => {
89 #[cfg(time_driver_tim2)] 87 #[cfg(time_driver_tim2)]
90 #[cfg(feature = "rt")] 88 #[cfg(feature = "rt")]
91 #[interrupt] 89 #[interrupt]
@@ -93,7 +91,7 @@ foreach_interrupt! {
93 DRIVER.on_interrupt() 91 DRIVER.on_interrupt()
94 } 92 }
95 }; 93 };
96 (TIM3, timer, $block:ident, UP, $irq:ident) => { 94 (TIM3, timer, $block:ident, CC, $irq:ident) => {
97 #[cfg(time_driver_tim3)] 95 #[cfg(time_driver_tim3)]
98 #[cfg(feature = "rt")] 96 #[cfg(feature = "rt")]
99 #[interrupt] 97 #[interrupt]
@@ -101,7 +99,7 @@ foreach_interrupt! {
101 DRIVER.on_interrupt() 99 DRIVER.on_interrupt()
102 } 100 }
103 }; 101 };
104 (TIM4, timer, $block:ident, UP, $irq:ident) => { 102 (TIM4, timer, $block:ident, CC, $irq:ident) => {
105 #[cfg(time_driver_tim4)] 103 #[cfg(time_driver_tim4)]
106 #[cfg(feature = "rt")] 104 #[cfg(feature = "rt")]
107 #[interrupt] 105 #[interrupt]
@@ -109,7 +107,7 @@ foreach_interrupt! {
109 DRIVER.on_interrupt() 107 DRIVER.on_interrupt()
110 } 108 }
111 }; 109 };
112 (TIM5, timer, $block:ident, UP, $irq:ident) => { 110 (TIM5, timer, $block:ident, CC, $irq:ident) => {
113 #[cfg(time_driver_tim5)] 111 #[cfg(time_driver_tim5)]
114 #[cfg(feature = "rt")] 112 #[cfg(feature = "rt")]
115 #[interrupt] 113 #[interrupt]
@@ -117,7 +115,7 @@ foreach_interrupt! {
117 DRIVER.on_interrupt() 115 DRIVER.on_interrupt()
118 } 116 }
119 }; 117 };
120 (TIM8, timer, $block:ident, UP, $irq:ident) => { 118 (TIM8, timer, $block:ident, CC, $irq:ident) => {
121 #[cfg(time_driver_tim8)] 119 #[cfg(time_driver_tim8)]
122 #[cfg(feature = "rt")] 120 #[cfg(feature = "rt")]
123 #[interrupt] 121 #[interrupt]
@@ -133,7 +131,7 @@ foreach_interrupt! {
133 DRIVER.on_interrupt() 131 DRIVER.on_interrupt()
134 } 132 }
135 }; 133 };
136 (TIM9, timer, $block:ident, UP, $irq:ident) => { 134 (TIM9, timer, $block:ident, CC, $irq:ident) => {
137 #[cfg(time_driver_tim9)] 135 #[cfg(time_driver_tim9)]
138 #[cfg(feature = "rt")] 136 #[cfg(feature = "rt")]
139 #[interrupt] 137 #[interrupt]
@@ -141,7 +139,7 @@ foreach_interrupt! {
141 DRIVER.on_interrupt() 139 DRIVER.on_interrupt()
142 } 140 }
143 }; 141 };
144 (TIM12, timer, $block:ident, UP, $irq:ident) => { 142 (TIM12, timer, $block:ident, CC, $irq:ident) => {
145 #[cfg(time_driver_tim12)] 143 #[cfg(time_driver_tim12)]
146 #[cfg(feature = "rt")] 144 #[cfg(feature = "rt")]
147 #[interrupt] 145 #[interrupt]
@@ -149,7 +147,7 @@ foreach_interrupt! {
149 DRIVER.on_interrupt() 147 DRIVER.on_interrupt()
150 } 148 }
151 }; 149 };
152 (TIM15, timer, $block:ident, UP, $irq:ident) => { 150 (TIM15, timer, $block:ident, CC, $irq:ident) => {
153 #[cfg(time_driver_tim15)] 151 #[cfg(time_driver_tim15)]
154 #[cfg(feature = "rt")] 152 #[cfg(feature = "rt")]
155 #[interrupt] 153 #[interrupt]
@@ -157,7 +155,7 @@ foreach_interrupt! {
157 DRIVER.on_interrupt() 155 DRIVER.on_interrupt()
158 } 156 }
159 }; 157 };
160 (TIM20, timer, $block:ident, UP, $irq:ident) => { 158 (TIM20, timer, $block:ident, CC, $irq:ident) => {
161 #[cfg(time_driver_tim20)] 159 #[cfg(time_driver_tim20)]
162 #[cfg(feature = "rt")] 160 #[cfg(feature = "rt")]
163 #[interrupt] 161 #[interrupt]
@@ -173,7 +171,7 @@ foreach_interrupt! {
173 DRIVER.on_interrupt() 171 DRIVER.on_interrupt()
174 } 172 }
175 }; 173 };
176 (TIM21, timer, $block:ident, UP, $irq:ident) => { 174 (TIM21, timer, $block:ident, CC, $irq:ident) => {
177 #[cfg(time_driver_tim21)] 175 #[cfg(time_driver_tim21)]
178 #[cfg(feature = "rt")] 176 #[cfg(feature = "rt")]
179 #[interrupt] 177 #[interrupt]
@@ -181,7 +179,7 @@ foreach_interrupt! {
181 DRIVER.on_interrupt() 179 DRIVER.on_interrupt()
182 } 180 }
183 }; 181 };
184 (TIM22, timer, $block:ident, UP, $irq:ident) => { 182 (TIM22, timer, $block:ident, CC, $irq:ident) => {
185 #[cfg(time_driver_tim22)] 183 #[cfg(time_driver_tim22)]
186 #[cfg(feature = "rt")] 184 #[cfg(feature = "rt")]
187 #[interrupt] 185 #[interrupt]
@@ -189,7 +187,7 @@ foreach_interrupt! {
189 DRIVER.on_interrupt() 187 DRIVER.on_interrupt()
190 } 188 }
191 }; 189 };
192 (TIM23, timer, $block:ident, UP, $irq:ident) => { 190 (TIM23, timer, $block:ident, CC, $irq:ident) => {
193 #[cfg(time_driver_tim23)] 191 #[cfg(time_driver_tim23)]
194 #[cfg(feature = "rt")] 192 #[cfg(feature = "rt")]
195 #[interrupt] 193 #[interrupt]
@@ -197,7 +195,7 @@ foreach_interrupt! {
197 DRIVER.on_interrupt() 195 DRIVER.on_interrupt()
198 } 196 }
199 }; 197 };
200 (TIM24, timer, $block:ident, UP, $irq:ident) => { 198 (TIM24, timer, $block:ident, CC, $irq:ident) => {
201 #[cfg(time_driver_tim24)] 199 #[cfg(time_driver_tim24)]
202 #[cfg(feature = "rt")] 200 #[cfg(feature = "rt")]
203 #[interrupt] 201 #[interrupt]
@@ -263,6 +261,7 @@ pub(crate) struct RtcDriver {
263 rtc: Mutex<CriticalSectionRawMutex, Cell<Option<&'static Rtc>>>, 261 rtc: Mutex<CriticalSectionRawMutex, Cell<Option<&'static Rtc>>>,
264} 262}
265 263
264#[allow(clippy::declare_interior_mutable_const)]
266const ALARM_STATE_NEW: AlarmState = AlarmState::new(); 265const ALARM_STATE_NEW: AlarmState = AlarmState::new();
267 266
268embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { 267embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
@@ -307,16 +306,8 @@ impl RtcDriver {
307 w.set_ccie(0, true); 306 w.set_ccie(0, true);
308 }); 307 });
309 308
310 <T as CoreInstance>::Interrupt::unpend(); 309 <T as GeneralInstance1Channel>::CaptureCompareInterrupt::unpend();
311 unsafe { <T as CoreInstance>::Interrupt::enable() }; 310 unsafe { <T as GeneralInstance1Channel>::CaptureCompareInterrupt::enable() };
312
313 #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))]
314 {
315 <T as AdvancedInstance1Channel>::CaptureCompareInterrupt::unpend();
316 unsafe {
317 <T as AdvancedInstance1Channel>::CaptureCompareInterrupt::enable();
318 }
319 }
320 311
321 r.cr1().modify(|w| w.set_cen(true)); 312 r.cr1().modify(|w| w.set_cen(true));
322 } 313 }
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 2ba6b3f11..346127005 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -47,8 +47,8 @@ pub enum TimerBits {
47 47
48/// Core timer instance. 48/// Core timer instance.
49pub trait CoreInstance: RccPeripheral + 'static { 49pub trait CoreInstance: RccPeripheral + 'static {
50 /// Interrupt for this timer. 50 /// Update Interrupt for this timer.
51 type Interrupt: interrupt::typelevel::Interrupt; 51 type UpdateInterrupt: interrupt::typelevel::Interrupt;
52 52
53 /// Amount of bits this timer has. 53 /// Amount of bits this timer has.
54 const BITS: TimerBits; 54 const BITS: TimerBits;
@@ -64,29 +64,46 @@ pub trait BasicNoCr2Instance: CoreInstance {}
64pub trait BasicInstance: BasicNoCr2Instance {} 64pub trait BasicInstance: BasicNoCr2Instance {}
65 65
66/// General-purpose 16-bit timer with 1 channel instance. 66/// General-purpose 16-bit timer with 1 channel instance.
67pub trait GeneralInstance1Channel: CoreInstance {} 67pub trait GeneralInstance1Channel: CoreInstance {
68 /// Capture compare interrupt for this timer.
69 type CaptureCompareInterrupt: interrupt::typelevel::Interrupt;
70}
68 71
69/// General-purpose 16-bit timer with 2 channels instance. 72/// General-purpose 16-bit timer with 2 channels instance.
70pub trait GeneralInstance2Channel: GeneralInstance1Channel {} 73pub trait GeneralInstance2Channel: GeneralInstance1Channel {
74 /// Trigger event interrupt for this timer.
75 type TriggerInterrupt: interrupt::typelevel::Interrupt;
76}
71 77
72/// General-purpose 16-bit timer with 4 channels instance. 78// This trait add *extra* methods to GeneralInstance4Channel,
73pub trait GeneralInstance4Channel: BasicInstance + GeneralInstance2Channel { 79// that GeneralInstance4Channel doesn't use, but the "AdvancedInstance"s need.
80// And it's a private trait, so it's content won't leak to outer namespace.
81//
82// If you want to add a new method to it, please leave a detail comment to explain it.
83trait General4ChBlankSealed {
74 // SimplePwm<'d, T> is implemented for T: GeneralInstance4Channel 84 // SimplePwm<'d, T> is implemented for T: GeneralInstance4Channel
75 // Advanced timers implement this trait, but the output needs to be 85 // Advanced timers implement this trait, but the output needs to be
76 // enabled explicitly. 86 // enabled explicitly.
77 // To support general-purpose and advanced timers, this function is added 87 // To support general-purpose and advanced timers, this function is added
78 // here defaulting to noop and overwritten for advanced timers. 88 // here defaulting to noop and overwritten for advanced timers.
79 /// Enable timer outputs. 89 //
90 // Enable timer outputs.
80 fn enable_outputs(&self) {} 91 fn enable_outputs(&self) {}
81} 92}
82 93
94/// General-purpose 16-bit timer with 4 channels instance.
95#[allow(private_bounds)]
96pub trait GeneralInstance4Channel: BasicInstance + GeneralInstance2Channel + General4ChBlankSealed {}
97
83/// General-purpose 32-bit timer with 4 channels instance. 98/// General-purpose 32-bit timer with 4 channels instance.
84pub trait GeneralInstance32bit4Channel: GeneralInstance4Channel {} 99pub trait GeneralInstance32bit4Channel: GeneralInstance4Channel {}
85 100
86/// Advanced 16-bit timer with 1 channel instance. 101/// Advanced 16-bit timer with 1 channel instance.
87pub trait AdvancedInstance1Channel: BasicNoCr2Instance + GeneralInstance1Channel { 102pub trait AdvancedInstance1Channel: BasicNoCr2Instance + GeneralInstance1Channel {
88 /// Capture compare interrupt for this timer. 103 /// Communication interrupt for this timer.
89 type CaptureCompareInterrupt: interrupt::typelevel::Interrupt; 104 type CommunicationInterrupt: interrupt::typelevel::Interrupt;
105 /// Break input interrupt for this timer.
106 type BreakInputInterrupt: interrupt::typelevel::Interrupt;
90} 107}
91/// Advanced 16-bit timer with 2 channels instance. 108/// Advanced 16-bit timer with 2 channels instance.
92 109
@@ -127,7 +144,7 @@ dma_trait!(Ch4Dma, GeneralInstance4Channel);
127macro_rules! impl_core_timer { 144macro_rules! impl_core_timer {
128 ($inst:ident, $bits:expr) => { 145 ($inst:ident, $bits:expr) => {
129 impl CoreInstance for crate::peripherals::$inst { 146 impl CoreInstance for crate::peripherals::$inst {
130 type Interrupt = crate::_generated::peripheral_interrupts::$inst::UP; 147 type UpdateInterrupt = crate::_generated::peripheral_interrupts::$inst::UP;
131 148
132 const BITS: TimerBits = $bits; 149 const BITS: TimerBits = $bits;
133 150
@@ -138,6 +155,49 @@ macro_rules! impl_core_timer {
138 }; 155 };
139} 156}
140 157
158#[allow(unused)]
159macro_rules! impl_general_1ch {
160 ($inst:ident) => {
161 impl GeneralInstance1Channel for crate::peripherals::$inst {
162 type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC;
163 }
164 };
165}
166
167#[allow(unused)]
168macro_rules! impl_general_2ch {
169 ($inst:ident) => {
170 impl GeneralInstance2Channel for crate::peripherals::$inst {
171 type TriggerInterrupt = crate::_generated::peripheral_interrupts::$inst::TRG;
172 }
173 };
174}
175
176#[allow(unused)]
177macro_rules! impl_advanced_1ch {
178 ($inst:ident) => {
179 impl AdvancedInstance1Channel for crate::peripherals::$inst {
180 type CommunicationInterrupt = crate::_generated::peripheral_interrupts::$inst::COM;
181 type BreakInputInterrupt = crate::_generated::peripheral_interrupts::$inst::BRK;
182 }
183 };
184}
185
186// This macro only apply to "AdvancedInstance(s)",
187// not "GeneralInstance4Channel" itself.
188#[allow(unused)]
189macro_rules! impl_general_4ch_blank_sealed {
190 ($inst:ident) => {
191 impl General4ChBlankSealed for crate::peripherals::$inst {
192 fn enable_outputs(&self) {
193 unsafe { crate::pac::timer::Tim1chCmp::from_ptr(Self::regs()) }
194 .bdtr()
195 .modify(|w| w.set_moe(true));
196 }
197 }
198 };
199}
200
141foreach_interrupt! { 201foreach_interrupt! {
142 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { 202 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => {
143 impl_core_timer!($inst, TimerBits::Bits16); 203 impl_core_timer!($inst, TimerBits::Bits16);
@@ -149,47 +209,52 @@ foreach_interrupt! {
149 impl_core_timer!($inst, TimerBits::Bits16); 209 impl_core_timer!($inst, TimerBits::Bits16);
150 impl BasicNoCr2Instance for crate::peripherals::$inst {} 210 impl BasicNoCr2Instance for crate::peripherals::$inst {}
151 impl BasicInstance for crate::peripherals::$inst {} 211 impl BasicInstance for crate::peripherals::$inst {}
152 impl GeneralInstance1Channel for crate::peripherals::$inst {} 212 impl_general_1ch!($inst);
153 impl GeneralInstance2Channel for crate::peripherals::$inst {} 213 impl_general_2ch!($inst);
154 impl GeneralInstance4Channel for crate::peripherals::$inst {} 214 impl GeneralInstance4Channel for crate::peripherals::$inst {}
215 impl General4ChBlankSealed for crate::peripherals::$inst {}
155 }; 216 };
156 217
157 ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { 218 ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => {
158 impl_core_timer!($inst, TimerBits::Bits16); 219 impl_core_timer!($inst, TimerBits::Bits16);
159 impl BasicNoCr2Instance for crate::peripherals::$inst {} 220 impl BasicNoCr2Instance for crate::peripherals::$inst {}
160 impl BasicInstance for crate::peripherals::$inst {} 221 impl BasicInstance for crate::peripherals::$inst {}
161 impl GeneralInstance1Channel for crate::peripherals::$inst {} 222 impl_general_1ch!($inst);
162 impl GeneralInstance2Channel for crate::peripherals::$inst {} 223 impl_general_2ch!($inst);
163 impl GeneralInstance4Channel for crate::peripherals::$inst {} 224 impl GeneralInstance4Channel for crate::peripherals::$inst {}
225 impl General4ChBlankSealed for crate::peripherals::$inst {}
164 }; 226 };
165 227
166 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { 228 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => {
167 impl_core_timer!($inst, TimerBits::Bits16); 229 impl_core_timer!($inst, TimerBits::Bits16);
168 impl BasicNoCr2Instance for crate::peripherals::$inst {} 230 impl BasicNoCr2Instance for crate::peripherals::$inst {}
169 impl BasicInstance for crate::peripherals::$inst {} 231 impl BasicInstance for crate::peripherals::$inst {}
170 impl GeneralInstance1Channel for crate::peripherals::$inst {} 232 impl_general_1ch!($inst);
171 impl GeneralInstance2Channel for crate::peripherals::$inst {} 233 impl_general_2ch!($inst);
172 impl GeneralInstance4Channel for crate::peripherals::$inst {} 234 impl GeneralInstance4Channel for crate::peripherals::$inst {}
235 impl General4ChBlankSealed for crate::peripherals::$inst {}
173 }; 236 };
174 237
175 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { 238 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
176 impl_core_timer!($inst, TimerBits::Bits32); 239 impl_core_timer!($inst, TimerBits::Bits32);
177 impl BasicNoCr2Instance for crate::peripherals::$inst {} 240 impl BasicNoCr2Instance for crate::peripherals::$inst {}
178 impl BasicInstance for crate::peripherals::$inst {} 241 impl BasicInstance for crate::peripherals::$inst {}
179 impl GeneralInstance1Channel for crate::peripherals::$inst {} 242 impl_general_1ch!($inst);
180 impl GeneralInstance2Channel for crate::peripherals::$inst {} 243 impl_general_2ch!($inst);
181 impl GeneralInstance4Channel for crate::peripherals::$inst {} 244 impl GeneralInstance4Channel for crate::peripherals::$inst {}
182 impl GeneralInstance32bit4Channel for crate::peripherals::$inst {} 245 impl GeneralInstance32bit4Channel for crate::peripherals::$inst {}
246 impl General4ChBlankSealed for crate::peripherals::$inst {}
183 }; 247 };
184 248
185 ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { 249 ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => {
186 impl_core_timer!($inst, TimerBits::Bits16); 250 impl_core_timer!($inst, TimerBits::Bits16);
187 impl BasicNoCr2Instance for crate::peripherals::$inst {} 251 impl BasicNoCr2Instance for crate::peripherals::$inst {}
188 impl BasicInstance for crate::peripherals::$inst {} 252 impl BasicInstance for crate::peripherals::$inst {}
189 impl GeneralInstance1Channel for crate::peripherals::$inst {} 253 impl_general_1ch!($inst);
190 impl GeneralInstance2Channel for crate::peripherals::$inst {} 254 impl_general_2ch!($inst);
191 impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }} 255 impl GeneralInstance4Channel for crate::peripherals::$inst {}
192 impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; } 256 impl_general_4ch_blank_sealed!($inst);
257 impl_advanced_1ch!($inst);
193 impl AdvancedInstance2Channel for crate::peripherals::$inst {} 258 impl AdvancedInstance2Channel for crate::peripherals::$inst {}
194 impl AdvancedInstance4Channel for crate::peripherals::$inst {} 259 impl AdvancedInstance4Channel for crate::peripherals::$inst {}
195 }; 260 };
@@ -198,10 +263,11 @@ foreach_interrupt! {
198 impl_core_timer!($inst, TimerBits::Bits16); 263 impl_core_timer!($inst, TimerBits::Bits16);
199 impl BasicNoCr2Instance for crate::peripherals::$inst {} 264 impl BasicNoCr2Instance for crate::peripherals::$inst {}
200 impl BasicInstance for crate::peripherals::$inst {} 265 impl BasicInstance for crate::peripherals::$inst {}
201 impl GeneralInstance1Channel for crate::peripherals::$inst {} 266 impl_general_1ch!($inst);
202 impl GeneralInstance2Channel for crate::peripherals::$inst {} 267 impl_general_2ch!($inst);
203 impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }} 268 impl GeneralInstance4Channel for crate::peripherals::$inst {}
204 impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; } 269 impl_general_4ch_blank_sealed!($inst);
270 impl_advanced_1ch!($inst);
205 impl AdvancedInstance2Channel for crate::peripherals::$inst {} 271 impl AdvancedInstance2Channel for crate::peripherals::$inst {}
206 impl AdvancedInstance4Channel for crate::peripherals::$inst {} 272 impl AdvancedInstance4Channel for crate::peripherals::$inst {}
207 }; 273 };
@@ -210,19 +276,12 @@ foreach_interrupt! {
210 impl_core_timer!($inst, TimerBits::Bits16); 276 impl_core_timer!($inst, TimerBits::Bits16);
211 impl BasicNoCr2Instance for crate::peripherals::$inst {} 277 impl BasicNoCr2Instance for crate::peripherals::$inst {}
212 impl BasicInstance for crate::peripherals::$inst {} 278 impl BasicInstance for crate::peripherals::$inst {}
213 impl GeneralInstance1Channel for crate::peripherals::$inst {} 279 impl_general_1ch!($inst);
214 impl GeneralInstance2Channel for crate::peripherals::$inst {} 280 impl_general_2ch!($inst);
215 impl GeneralInstance4Channel for crate::peripherals::$inst { fn enable_outputs(&self) { set_moe::<Self>() }} 281 impl GeneralInstance4Channel for crate::peripherals::$inst {}
216 impl AdvancedInstance1Channel for crate::peripherals::$inst { type CaptureCompareInterrupt = crate::_generated::peripheral_interrupts::$inst::CC; } 282 impl_general_4ch_blank_sealed!($inst);
283 impl_advanced_1ch!($inst);
217 impl AdvancedInstance2Channel for crate::peripherals::$inst {} 284 impl AdvancedInstance2Channel for crate::peripherals::$inst {}
218 impl AdvancedInstance4Channel for crate::peripherals::$inst {} 285 impl AdvancedInstance4Channel for crate::peripherals::$inst {}
219 }; 286 };
220} 287}
221
222#[cfg(not(stm32l0))]
223#[allow(unused)]
224fn set_moe<T: GeneralInstance4Channel>() {
225 unsafe { crate::pac::timer::Tim1chCmp::from_ptr(T::regs()) }
226 .bdtr()
227 .modify(|w| w.set_moe(true));
228}
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 51862e185..949ac1b13 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -105,27 +105,23 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
105 } 105 }
106} 106}
107 107
108pub(crate) use sealed::State; 108pub(crate) struct State {
109pub(crate) mod sealed { 109 pub(crate) rx_waker: AtomicWaker,
110 use super::*; 110 pub(crate) rx_buf: RingBuffer,
111 pub struct State { 111 pub(crate) tx_waker: AtomicWaker,
112 pub(crate) rx_waker: AtomicWaker, 112 pub(crate) tx_buf: RingBuffer,
113 pub(crate) rx_buf: RingBuffer, 113 pub(crate) tx_done: AtomicBool,
114 pub(crate) tx_waker: AtomicWaker, 114}
115 pub(crate) tx_buf: RingBuffer, 115
116 pub(crate) tx_done: AtomicBool, 116impl State {
117 } 117 /// Create new state
118 118 pub(crate) const fn new() -> Self {
119 impl State { 119 Self {
120 /// Create new state 120 rx_buf: RingBuffer::new(),
121 pub const fn new() -> Self { 121 tx_buf: RingBuffer::new(),
122 Self { 122 rx_waker: AtomicWaker::new(),
123 rx_buf: RingBuffer::new(), 123 tx_waker: AtomicWaker::new(),
124 tx_buf: RingBuffer::new(), 124 tx_done: AtomicBool::new(true),
125 rx_waker: AtomicWaker::new(),
126 tx_waker: AtomicWaker::new(),
127 tx_done: AtomicBool::new(true),
128 }
129 } 125 }
130 } 126 }
131} 127}
diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md
index e7db97ef7..3f6b39d8b 100644
--- a/embassy-sync/CHANGELOG.md
+++ b/embassy-sync/CHANGELOG.md
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 7
8## Unreleased
9
10- Add `len`, `is_empty` and `is_full` functions to `Channel`.
11
8## 0.5.0 - 2023-12-04 12## 0.5.0 - 2023-12-04
9 13
10- Add a PriorityChannel. 14- Add a PriorityChannel.
@@ -35,7 +39,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
35- Remove unnecessary uses of `atomic-polyfill` 39- Remove unnecessary uses of `atomic-polyfill`
36- Add `#[must_use]` to all futures. 40- Add `#[must_use]` to all futures.
37 41
38
39## 0.1.0 - 2022-08-26 42## 0.1.0 - 2022-08-26
40 43
41- First release 44- First release
diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs
index 48f4dafd6..18be462cb 100644
--- a/embassy-sync/src/channel.rs
+++ b/embassy-sync/src/channel.rs
@@ -449,6 +449,18 @@ impl<T, const N: usize> ChannelState<T, N> {
449 Poll::Pending 449 Poll::Pending
450 } 450 }
451 } 451 }
452
453 fn len(&self) -> usize {
454 self.queue.len()
455 }
456
457 fn is_empty(&self) -> bool {
458 self.queue.is_empty()
459 }
460
461 fn is_full(&self) -> bool {
462 self.queue.is_full()
463 }
452} 464}
453 465
454/// A bounded channel for communicating between asynchronous tasks 466/// A bounded channel for communicating between asynchronous tasks
@@ -572,6 +584,21 @@ where
572 pub fn try_receive(&self) -> Result<T, TryReceiveError> { 584 pub fn try_receive(&self) -> Result<T, TryReceiveError> {
573 self.lock(|c| c.try_receive()) 585 self.lock(|c| c.try_receive())
574 } 586 }
587
588 /// Returns the number of elements currently in the channel.
589 pub fn len(&self) -> usize {
590 self.lock(|c| c.len())
591 }
592
593 /// Returns whether the channel is empty.
594 pub fn is_empty(&self) -> bool {
595 self.lock(|c| c.is_empty())
596 }
597
598 /// Returns whether the channel is full.
599 pub fn is_full(&self) -> bool {
600 self.lock(|c| c.is_full())
601 }
575} 602}
576 603
577/// Implements the DynamicChannel to allow creating types that are unaware of the queue size with the 604/// Implements the DynamicChannel to allow creating types that are unaware of the queue size with the
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index c06107396..387b780de 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -38,11 +38,12 @@ pub struct Config<'a> {
38 38
39 /// Maximum packet size in bytes for the control endpoint 0. 39 /// Maximum packet size in bytes for the control endpoint 0.
40 /// 40 ///
41 /// Valid values are 8, 16, 32 and 64. There's generally no need to change this from the default 41 /// Valid values depend on the speed at which the bus is enumerated.
42 /// value of 8 bytes unless a class uses control transfers for sending large amounts of data, in 42 /// - low speed: 8
43 /// which case using a larger packet size may be more efficient. 43 /// - full speed: 8, 16, 32, or 64
44 /// - high speed: 64
44 /// 45 ///
45 /// Default: 8 bytes 46 /// Default: 64 bytes
46 pub max_packet_size_0: u8, 47 pub max_packet_size_0: u8,
47 48
48 /// Manufacturer name string descriptor. 49 /// Manufacturer name string descriptor.
diff --git a/examples/rp/src/bin/pio_stepper.rs b/examples/rp/src/bin/pio_stepper.rs
index ab9ecf623..4952f4fbd 100644
--- a/examples/rp/src/bin/pio_stepper.rs
+++ b/examples/rp/src/bin/pio_stepper.rs
@@ -69,7 +69,7 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> {
69 let clock_divider: FixedU32<U8> = (125_000_000 / (freq * 136)).to_fixed(); 69 let clock_divider: FixedU32<U8> = (125_000_000 / (freq * 136)).to_fixed();
70 assert!(clock_divider <= 65536, "clkdiv must be <= 65536"); 70 assert!(clock_divider <= 65536, "clkdiv must be <= 65536");
71 assert!(clock_divider >= 1, "clkdiv must be >= 1"); 71 assert!(clock_divider >= 1, "clkdiv must be >= 1");
72 T::PIO.sm(SM).clkdiv().write(|w| w.0 = clock_divider.to_bits() << 8); 72 self.sm.set_clock_divider(clock_divider);
73 self.sm.clkdiv_restart(); 73 self.sm.clkdiv_restart();
74 } 74 }
75 75
diff --git a/examples/rp/src/bin/pwm_input.rs b/examples/rp/src/bin/pwm_input.rs
index 0652dc42b..bf454a936 100644
--- a/examples/rp/src/bin/pwm_input.rs
+++ b/examples/rp/src/bin/pwm_input.rs
@@ -5,6 +5,7 @@
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_rp::gpio::Pull;
8use embassy_rp::pwm::{Config, InputMode, Pwm}; 9use embassy_rp::pwm::{Config, InputMode, Pwm};
9use embassy_time::{Duration, Ticker}; 10use embassy_time::{Duration, Ticker};
10use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
@@ -14,7 +15,7 @@ async fn main(_spawner: Spawner) {
14 let p = embassy_rp::init(Default::default()); 15 let p = embassy_rp::init(Default::default());
15 16
16 let cfg: Config = Default::default(); 17 let cfg: Config = Default::default();
17 let pwm = Pwm::new_input(p.PWM_SLICE2, p.PIN_5, InputMode::RisingEdge, cfg); 18 let pwm = Pwm::new_input(p.PWM_SLICE2, p.PIN_5, Pull::None, InputMode::RisingEdge, cfg);
18 19
19 let mut ticker = Ticker::every(Duration::from_secs(1)); 20 let mut ticker = Ticker::every(Duration::from_secs(1));
20 loop { 21 loop {
diff --git a/examples/stm32f0/src/bin/multiprio.rs b/examples/stm32f0/src/bin/multiprio.rs
index e49951726..1c3f3991a 100644
--- a/examples/stm32f0/src/bin/multiprio.rs
+++ b/examples/stm32f0/src/bin/multiprio.rs
@@ -126,6 +126,11 @@ fn main() -> ! {
126 // Initialize and create handle for devicer peripherals 126 // Initialize and create handle for devicer peripherals
127 let _p = embassy_stm32::init(Default::default()); 127 let _p = embassy_stm32::init(Default::default());
128 128
129 // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as
130 // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application.
131 // In this case we’re using UART1 and UART2, but there’s nothing special about them. Any otherwise unused interrupt
132 // vector would work exactly the same.
133
129 // High-priority executor: USART1, priority level 6 134 // High-priority executor: USART1, priority level 6
130 interrupt::USART1.set_priority(Priority::P6); 135 interrupt::USART1.set_priority(Priority::P6);
131 let spawner = EXECUTOR_HIGH.start(interrupt::USART1); 136 let spawner = EXECUTOR_HIGH.start(interrupt::USART1);
diff --git a/examples/stm32f3/src/bin/multiprio.rs b/examples/stm32f3/src/bin/multiprio.rs
index 328447210..87830b416 100644
--- a/examples/stm32f3/src/bin/multiprio.rs
+++ b/examples/stm32f3/src/bin/multiprio.rs
@@ -127,6 +127,11 @@ fn main() -> ! {
127 127
128 let _p = embassy_stm32::init(Default::default()); 128 let _p = embassy_stm32::init(Default::default());
129 129
130 // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as
131 // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application.
132 // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt
133 // vector would work exactly the same.
134
130 // High-priority executor: UART4, priority level 6 135 // High-priority executor: UART4, priority level 6
131 interrupt::UART4.set_priority(Priority::P6); 136 interrupt::UART4.set_priority(Priority::P6);
132 let spawner = EXECUTOR_HIGH.start(interrupt::UART4); 137 let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs
index 328447210..87830b416 100644
--- a/examples/stm32f4/src/bin/multiprio.rs
+++ b/examples/stm32f4/src/bin/multiprio.rs
@@ -127,6 +127,11 @@ fn main() -> ! {
127 127
128 let _p = embassy_stm32::init(Default::default()); 128 let _p = embassy_stm32::init(Default::default());
129 129
130 // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as
131 // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application.
132 // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt
133 // vector would work exactly the same.
134
130 // High-priority executor: UART4, priority level 6 135 // High-priority executor: UART4, priority level 6
131 interrupt::UART4.set_priority(Priority::P6); 136 interrupt::UART4.set_priority(Priority::P6);
132 let spawner = EXECUTOR_HIGH.start(interrupt::UART4); 137 let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
index a799b4e72..d6e0be5ea 100644
--- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs
+++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
@@ -49,6 +49,7 @@ async fn main(_spawner: Spawner) {
49 // Create the driver, from the HAL. 49 // Create the driver, from the HAL.
50 let mut ep_out_buffer = [0u8; 256]; 50 let mut ep_out_buffer = [0u8; 256];
51 let mut config = embassy_stm32::usb::Config::default(); 51 let mut config = embassy_stm32::usb::Config::default();
52 // If the board you’re using doesn’t have the VBUS pin wired up correctly for detecting the USB bus voltage (e.g. on the f4 blackpill board), set this to false
52 config.vbus_detection = true; 53 config.vbus_detection = true;
53 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); 54 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
54 55
diff --git a/examples/stm32h5/src/bin/cordic.rs b/examples/stm32h5/src/bin/cordic.rs
new file mode 100644
index 000000000..73e873574
--- /dev/null
+++ b/examples/stm32h5/src/bin/cordic.rs
@@ -0,0 +1,78 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::cordic::{self, utils};
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let mut dp = embassy_stm32::init(Default::default());
12
13 let mut cordic = cordic::Cordic::new(
14 &mut dp.CORDIC,
15 unwrap!(cordic::Config::new(
16 cordic::Function::Sin,
17 Default::default(),
18 Default::default(),
19 )),
20 );
21
22 // for output buf, the length is not that strict, larger than minimal required is ok.
23 let mut output_f64 = [0f64; 19];
24 let mut output_u32 = [0u32; 21];
25
26 // tips:
27 // CORDIC peripheral has some strict on input value, you can also use ".check_argX_fXX()" methods
28 // to make sure your input values are compatible with current CORDIC setup.
29 let arg1 = [-1.0, -0.5, 0.0, 0.5, 1.0]; // for trigonometric function, the ARG1 value [-pi, pi] should be map to [-1, 1]
30 let arg2 = [0.5]; // and for Sin function, ARG2 should be in [0, 1]
31
32 let mut input_buf = [0u32; 9];
33
34 // convert input from floating point to fixed point
35 input_buf[0] = unwrap!(utils::f64_to_q1_31(arg1[0]));
36 input_buf[1] = unwrap!(utils::f64_to_q1_31(arg2[0]));
37
38 // If input length is small, blocking mode can be used to minimize overhead.
39 let cnt0 = unwrap!(cordic.blocking_calc_32bit(
40 &input_buf[..2], // input length is strict, since driver use its length to detect calculation count
41 &mut output_u32,
42 false,
43 false
44 ));
45
46 // convert result from fixed point into floating point
47 for (&u32_val, f64_val) in output_u32[..cnt0].iter().zip(output_f64.iter_mut()) {
48 *f64_val = utils::q1_31_to_f64(u32_val);
49 }
50
51 // convert input from floating point to fixed point
52 //
53 // first value from arg1 is used, so truncate to arg1[1..]
54 for (&f64_val, u32_val) in arg1[1..].iter().zip(input_buf.iter_mut()) {
55 *u32_val = unwrap!(utils::f64_to_q1_31(f64_val));
56 }
57
58 // If calculation is a little longer, async mode can make use of DMA, and let core do some other stuff.
59 let cnt1 = unwrap!(
60 cordic
61 .async_calc_32bit(
62 &mut dp.GPDMA1_CH0,
63 &mut dp.GPDMA1_CH1,
64 &input_buf[..arg1.len() - 1], // limit input buf to its actual length
65 &mut output_u32,
66 true,
67 false
68 )
69 .await
70 );
71
72 // convert result from fixed point into floating point
73 for (&u32_val, f64_val) in output_u32[..cnt1].iter().zip(output_f64[cnt0..cnt0 + cnt1].iter_mut()) {
74 *f64_val = utils::q1_31_to_f64(u32_val);
75 }
76
77 println!("result: {}", output_f64[..cnt0 + cnt1]);
78}
diff --git a/examples/stm32h7/src/bin/multiprio.rs b/examples/stm32h7/src/bin/multiprio.rs
index 73f8dd092..fcbb6c653 100644
--- a/examples/stm32h7/src/bin/multiprio.rs
+++ b/examples/stm32h7/src/bin/multiprio.rs
@@ -127,6 +127,11 @@ fn main() -> ! {
127 127
128 let _p = embassy_stm32::init(Default::default()); 128 let _p = embassy_stm32::init(Default::default());
129 129
130 // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as
131 // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application.
132 // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt
133 // vector would work exactly the same.
134
130 // High-priority executor: UART4, priority level 6 135 // High-priority executor: UART4, priority level 6
131 interrupt::UART4.set_priority(Priority::P6); 136 interrupt::UART4.set_priority(Priority::P6);
132 let spawner = EXECUTOR_HIGH.start(interrupt::UART4); 137 let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
diff --git a/tests/rp/src/bin/pwm.rs b/tests/rp/src/bin/pwm.rs
index 4b02e5bab..c05197000 100644
--- a/tests/rp/src/bin/pwm.rs
+++ b/tests/rp/src/bin/pwm.rs
@@ -94,7 +94,7 @@ async fn main(_spawner: Spawner) {
94 // Test level-gated 94 // Test level-gated
95 { 95 {
96 let mut pin2 = Output::new(&mut p11, Level::Low); 96 let mut pin2 = Output::new(&mut p11, Level::Low);
97 let pwm = Pwm::new_input(&mut p.PWM_SLICE3, &mut p7, InputMode::Level, cfg.clone()); 97 let pwm = Pwm::new_input(&mut p.PWM_SLICE3, &mut p7, Pull::None, InputMode::Level, cfg.clone());
98 assert_eq!(pwm.counter(), 0); 98 assert_eq!(pwm.counter(), 0);
99 Timer::after_millis(5).await; 99 Timer::after_millis(5).await;
100 assert_eq!(pwm.counter(), 0); 100 assert_eq!(pwm.counter(), 0);
@@ -110,7 +110,13 @@ async fn main(_spawner: Spawner) {
110 // Test rising-gated 110 // Test rising-gated
111 { 111 {
112 let mut pin2 = Output::new(&mut p11, Level::Low); 112 let mut pin2 = Output::new(&mut p11, Level::Low);
113 let pwm = Pwm::new_input(&mut p.PWM_SLICE3, &mut p7, InputMode::RisingEdge, cfg.clone()); 113 let pwm = Pwm::new_input(
114 &mut p.PWM_SLICE3,
115 &mut p7,
116 Pull::None,
117 InputMode::RisingEdge,
118 cfg.clone(),
119 );
114 assert_eq!(pwm.counter(), 0); 120 assert_eq!(pwm.counter(), 0);
115 Timer::after_millis(5).await; 121 Timer::after_millis(5).await;
116 assert_eq!(pwm.counter(), 0); 122 assert_eq!(pwm.counter(), 0);
@@ -125,7 +131,13 @@ async fn main(_spawner: Spawner) {
125 // Test falling-gated 131 // Test falling-gated
126 { 132 {
127 let mut pin2 = Output::new(&mut p11, Level::High); 133 let mut pin2 = Output::new(&mut p11, Level::High);
128 let pwm = Pwm::new_input(&mut p.PWM_SLICE3, &mut p7, InputMode::FallingEdge, cfg.clone()); 134 let pwm = Pwm::new_input(
135 &mut p.PWM_SLICE3,
136 &mut p7,
137 Pull::None,
138 InputMode::FallingEdge,
139 cfg.clone(),
140 );
129 assert_eq!(pwm.counter(), 0); 141 assert_eq!(pwm.counter(), 0);
130 Timer::after_millis(5).await; 142 Timer::after_millis(5).await;
131 assert_eq!(pwm.counter(), 0); 143 assert_eq!(pwm.counter(), 0);
@@ -137,6 +149,34 @@ async fn main(_spawner: Spawner) {
137 assert_eq!(pwm.counter(), 1); 149 assert_eq!(pwm.counter(), 1);
138 } 150 }
139 151
152 // pull-down
153 {
154 let pin2 = Input::new(&mut p11, Pull::None);
155 Pwm::new_input(
156 &mut p.PWM_SLICE3,
157 &mut p7,
158 Pull::Down,
159 InputMode::FallingEdge,
160 cfg.clone(),
161 );
162 Timer::after_millis(1).await;
163 assert!(pin2.is_low());
164 }
165
166 // pull-up
167 {
168 let pin2 = Input::new(&mut p11, Pull::None);
169 Pwm::new_input(
170 &mut p.PWM_SLICE3,
171 &mut p7,
172 Pull::Up,
173 InputMode::FallingEdge,
174 cfg.clone(),
175 );
176 Timer::after_millis(1).await;
177 assert!(pin2.is_high());
178 }
179
140 info!("Test OK"); 180 info!("Test OK");
141 cortex_m::asm::bkpt(); 181 cortex_m::asm::bkpt();
142} 182}
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index e42470004..e09083111 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -14,8 +14,8 @@ stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not
14stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] 14stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"]
15stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] 15stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"]
16stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"] 16stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"]
17stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"] 17stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan", "cordic"]
18stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"] 18stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash", "cordic"]
19stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] 19stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"]
20stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"] 20stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"]
21stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] 21stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"]
@@ -25,8 +25,8 @@ stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"]
25stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"] 25stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"]
26stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] 26stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"]
27stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"] 27stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"]
28stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng", "hash"] 28stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng", "hash", "cordic"]
29stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng", "hash"] 29stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng", "hash"] # FIXME: cordic test cause it crash
30stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] 30stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"]
31stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng", "hash"] 31stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng", "hash"]
32stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] 32stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"]
@@ -48,6 +48,7 @@ embassy-stm32-wpan = []
48not-gpdma = [] 48not-gpdma = []
49dac = [] 49dac = []
50ucpd = [] 50ucpd = []
51cordic = ["dep:num-traits"]
51 52
52cm0 = ["portable-atomic/unsafe-assume-single-core"] 53cm0 = ["portable-atomic/unsafe-assume-single-core"]
53 54
@@ -83,6 +84,7 @@ chrono = { version = "^0.4", default-features = false, optional = true}
83sha2 = { version = "0.10.8", default-features = false } 84sha2 = { version = "0.10.8", default-features = false }
84hmac = "0.12.1" 85hmac = "0.12.1"
85aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] } 86aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] }
87num-traits = {version="0.2", default-features = false,features = ["libm"], optional = true}
86 88
87# BEGIN TESTS 89# BEGIN TESTS
88# Generated by gen_test.py. DO NOT EDIT. 90# Generated by gen_test.py. DO NOT EDIT.
@@ -92,6 +94,11 @@ path = "src/bin/can.rs"
92required-features = [ "can",] 94required-features = [ "can",]
93 95
94[[bin]] 96[[bin]]
97name = "cordic"
98path = "src/bin/cordic.rs"
99required-features = [ "rng", "cordic",]
100
101[[bin]]
95name = "cryp" 102name = "cryp"
96path = "src/bin/cryp.rs" 103path = "src/bin/cryp.rs"
97required-features = [ "cryp",] 104required-features = [ "cryp",]
diff --git a/tests/stm32/gen_test.py b/tests/stm32/gen_test.py
index 8ff156c0e..daf714376 100644
--- a/tests/stm32/gen_test.py
+++ b/tests/stm32/gen_test.py
@@ -14,7 +14,7 @@ for f in sorted(glob('./src/bin/*.rs')):
14 with open(f, 'r') as f: 14 with open(f, 'r') as f:
15 for line in f: 15 for line in f:
16 if line.startswith('// required-features:'): 16 if line.startswith('// required-features:'):
17 features = line.split(':', 2)[1].strip().split(',') 17 features = [feature.strip() for feature in line.split(':', 2)[1].strip().split(',')]
18 18
19 tests[name] = features 19 tests[name] = features
20 20
diff --git a/tests/stm32/src/bin/cordic.rs b/tests/stm32/src/bin/cordic.rs
new file mode 100644
index 000000000..400e10207
--- /dev/null
+++ b/tests/stm32/src/bin/cordic.rs
@@ -0,0 +1,135 @@
1// required-features: rng, cordic
2
3// Test Cordic driver, with Q1.31 format, Sin function, at 24 iterations (aka PRECISION = 6), using DMA transfer
4
5#![no_std]
6#![no_main]
7
8#[path = "../common.rs"]
9mod common;
10use common::*;
11use embassy_executor::Spawner;
12use embassy_stm32::cordic::utils;
13use embassy_stm32::{bind_interrupts, cordic, peripherals, rng};
14use num_traits::Float;
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 RNG => rng::InterruptHandler<peripherals::RNG>;
19});
20
21/* input value control, can be changed */
22
23const INPUT_U32_COUNT: usize = 9;
24const INPUT_U8_COUNT: usize = 4 * INPUT_U32_COUNT;
25
26// Assume first calculation needs 2 arguments, the reset needs 1 argument.
27// And all calculation generate 2 results.
28const OUTPUT_LENGTH: usize = (INPUT_U32_COUNT - 1) * 2;
29
30#[embassy_executor::main]
31async fn main(_spawner: Spawner) {
32 let dp = embassy_stm32::init(config());
33
34 //
35 // use RNG generate random Q1.31 value
36 //
37 // we don't generate floating-point value, since not all binary value are valid floating-point value,
38 // and Q1.31 only accept a fixed range of value.
39
40 let mut rng = rng::Rng::new(dp.RNG, Irqs);
41
42 let mut input_buf_u8 = [0u8; INPUT_U8_COUNT];
43 defmt::unwrap!(rng.async_fill_bytes(&mut input_buf_u8).await);
44
45 // convert every [u8; 4] to a u32, for a Q1.31 value
46 let mut input_q1_31 = unsafe { core::mem::transmute::<[u8; INPUT_U8_COUNT], [u32; INPUT_U32_COUNT]>(input_buf_u8) };
47
48 // ARG2 for Sin function should be inside [0, 1], set MSB to 0 of a Q1.31 value, will make sure it's no less than 0.
49 input_q1_31[1] &= !(1u32 << 31);
50
51 //
52 // CORDIC calculation
53 //
54
55 let mut output_q1_31 = [0u32; OUTPUT_LENGTH];
56
57 // setup Cordic driver
58 let mut cordic = cordic::Cordic::new(
59 dp.CORDIC,
60 defmt::unwrap!(cordic::Config::new(
61 cordic::Function::Sin,
62 Default::default(),
63 Default::default(),
64 )),
65 );
66
67 #[cfg(feature = "stm32g491re")]
68 let (mut write_dma, mut read_dma) = (dp.DMA1_CH4, dp.DMA1_CH5);
69
70 #[cfg(any(feature = "stm32h563zi", feature = "stm32u585ai", feature = "stm32u5a5zj"))]
71 let (mut write_dma, mut read_dma) = (dp.GPDMA1_CH0, dp.GPDMA1_CH1);
72
73 // calculate first result using blocking mode
74 let cnt0 = defmt::unwrap!(cordic.blocking_calc_32bit(&input_q1_31[..2], &mut output_q1_31, false, false));
75
76 // calculate rest results using async mode
77 let cnt1 = defmt::unwrap!(
78 cordic
79 .async_calc_32bit(
80 &mut write_dma,
81 &mut read_dma,
82 &input_q1_31[2..],
83 &mut output_q1_31[cnt0..],
84 true,
85 false,
86 )
87 .await
88 );
89
90 // all output value length should be the same as our output buffer size
91 defmt::assert_eq!(cnt0 + cnt1, output_q1_31.len());
92
93 let mut cordic_result_f64 = [0.0f64; OUTPUT_LENGTH];
94
95 for (f64_val, u32_val) in cordic_result_f64.iter_mut().zip(output_q1_31) {
96 *f64_val = utils::q1_31_to_f64(u32_val);
97 }
98
99 //
100 // software calculation
101 //
102
103 let mut software_result_f64 = [0.0f64; OUTPUT_LENGTH];
104
105 let arg2 = utils::q1_31_to_f64(input_q1_31[1]);
106
107 for (&arg1, res) in input_q1_31
108 .iter()
109 .enumerate()
110 .filter_map(|(idx, val)| if idx != 1 { Some(val) } else { None })
111 .zip(software_result_f64.chunks_mut(2))
112 {
113 let arg1 = utils::q1_31_to_f64(arg1);
114
115 let (raw_res1, raw_res2) = (arg1 * core::f64::consts::PI).sin_cos();
116 (res[0], res[1]) = (raw_res1 * arg2, raw_res2 * arg2);
117 }
118
119 //
120 // check result are the same
121 //
122
123 for (cordic_res, software_res) in cordic_result_f64[..cnt0 + cnt1]
124 .chunks(2)
125 .zip(software_result_f64.chunks(2))
126 {
127 for (cord_res, soft_res) in cordic_res.iter().zip(software_res.iter()) {
128 // 2.0.powi(-19) is the max residual error for Sin function, in q1.31 format, with 24 iterations (aka PRECISION = 6)
129 defmt::assert!((cord_res - soft_res).abs() <= 2.0.powi(-19));
130 }
131 }
132
133 info!("Test OK");
134 cortex_m::asm::bkpt();
135}