diff options
| author | Gustav Toft <[email protected]> | 2024-04-11 08:27:30 +0200 |
|---|---|---|
| committer | Gustav Toft <[email protected]> | 2024-04-11 08:27:30 +0200 |
| commit | d4ba6ccc3787624fbc5eee30b6d5c5361ee6e280 (patch) | |
| tree | 572241f460b15e88ee8461f082a352c113a377ed | |
| parent | 6663be0b36a078893b0ef3f3f869b17adf62ca30 (diff) | |
| parent | 4ffe35c840f1a35e3bbc0cdb29203cbaac5abd08 (diff) | |
Merge branch 'main' of https://github.com/GustavToft/embassy
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 | ||
| 14 | firmware (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 |
| 21 | pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; | 21 | pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; |
| 22 | 22 | ||
| 23 | use crate::gpio::sealed::Pin; | 23 | use crate::gpio::{AnyPin, Pin as GpioPin, PselBits, SealedPin}; |
| 24 | use crate::gpio::{AnyPin, Pin as GpioPin, PselBits}; | ||
| 25 | use crate::interrupt::typelevel::Interrupt; | 24 | use crate::interrupt::typelevel::Interrupt; |
| 26 | use crate::ppi::{ | 25 | use 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}; | |||
| 30 | use crate::uarte::{configure, drop_tx_rx, Config, Instance as UarteInstance}; | 29 | use crate::uarte::{configure, drop_tx_rx, Config, Instance as UarteInstance}; |
| 31 | use crate::{interrupt, pac, Peripheral}; | 30 | use crate::{interrupt, pac, Peripheral}; |
| 32 | 31 | ||
| 33 | mod sealed { | 32 | pub(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 | ||
| 56 | pub(crate) use sealed::State; | ||
| 57 | |||
| 58 | impl State { | 51 | impl 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; | |||
| 7 | use cfg_if::cfg_if; | 7 | use cfg_if::cfg_if; |
| 8 | use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; | 8 | use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; |
| 9 | 9 | ||
| 10 | use self::sealed::Pin as _; | ||
| 11 | #[cfg(feature = "nrf51")] | 10 | #[cfg(feature = "nrf51")] |
| 12 | use crate::pac::gpio; | 11 | use 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 | ||
| 364 | pub(crate) mod sealed { | 363 | pub(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]. |
| 416 | pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static { | 411 | #[allow(private_bounds)] |
| 412 | pub 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 | ||
| 465 | impl_peripheral!(AnyPin); | 461 | impl_peripheral!(AnyPin); |
| 466 | impl Pin for AnyPin {} | 462 | impl Pin for AnyPin {} |
| 467 | impl sealed::Pin for AnyPin { | 463 | impl 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) { | |||
| 502 | macro_rules! impl_pin { | 498 | macro_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}; | |||
| 7 | use embassy_hal_internal::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; | 7 | use embassy_hal_internal::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; |
| 8 | use embassy_sync::waitqueue::AtomicWaker; | 8 | use embassy_sync::waitqueue::AtomicWaker; |
| 9 | 9 | ||
| 10 | use crate::gpio::sealed::Pin as _; | 10 | use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin, SealedPin as _}; |
| 11 | use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin}; | ||
| 12 | use crate::interrupt::InterruptExt; | 11 | use crate::interrupt::InterruptExt; |
| 13 | use crate::ppi::{Event, Task}; | 12 | use crate::ppi::{Event, Task}; |
| 14 | use crate::{interrupt, pac, peripherals}; | 13 | use crate::{interrupt, pac, peripherals}; |
| @@ -446,14 +445,13 @@ impl<'d> Flex<'d> { | |||
| 446 | 445 | ||
| 447 | // ======================= | 446 | // ======================= |
| 448 | 447 | ||
| 449 | mod sealed { | 448 | trait 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. |
| 456 | pub trait Channel: sealed::Channel + Into<AnyChannel> + Sized + 'static { | 453 | #[allow(private_bounds)] |
| 454 | pub 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 | } |
| 480 | impl_peripheral!(AnyChannel); | 478 | impl_peripheral!(AnyChannel); |
| 481 | impl sealed::Channel for AnyChannel {} | 479 | impl SealedChannel for AnyChannel {} |
| 482 | impl Channel for AnyChannel { | 480 | impl 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 | ||
| 488 | macro_rules! impl_channel { | 486 | macro_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; | |||
| 6 | use core::marker::PhantomData; | 6 | use core::marker::PhantomData; |
| 7 | use core::mem::size_of; | 7 | use core::mem::size_of; |
| 8 | use core::ops::{Deref, DerefMut}; | 8 | use core::ops::{Deref, DerefMut}; |
| 9 | use core::sync::atomic::{compiler_fence, Ordering}; | 9 | use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; |
| 10 | use core::task::Poll; | 10 | use core::task::Poll; |
| 11 | 11 | ||
| 12 | use embassy_hal_internal::drop::OnDrop; | 12 | use embassy_hal_internal::drop::OnDrop; |
| 13 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 13 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 14 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 14 | 15 | ||
| 15 | use crate::gpio::{AnyPin, Pin as GpioPin}; | 16 | use crate::gpio::{AnyPin, Pin as GpioPin}; |
| 16 | use crate::interrupt::typelevel::Interrupt; | 17 | use 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 | ||
| 1143 | pub(crate) mod sealed { | 1144 | /// Peripheral static state |
| 1144 | use core::sync::atomic::AtomicBool; | 1145 | pub(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 { | 1152 | impl 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 { | 1163 | pub(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. |
| 1174 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 1169 | #[allow(private_bounds)] |
| 1170 | pub 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 | ||
| 1179 | macro_rules! impl_i2s { | 1175 | macro_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 | ||
| 10 | use embassy_hal_internal::drop::OnDrop; | 10 | use embassy_hal_internal::drop::OnDrop; |
| 11 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 11 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 12 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 12 | use fixed::types::I7F1; | 13 | use fixed::types::I7F1; |
| 13 | 14 | ||
| 14 | use crate::chip::EASY_DMA_SIZE; | 15 | use crate::chip::EASY_DMA_SIZE; |
| 15 | use crate::gpio::sealed::Pin; | 16 | use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin}; |
| 16 | use crate::gpio::{AnyPin, Pin as GpioPin}; | ||
| 17 | use crate::interrupt::typelevel::Interrupt; | 17 | use crate::interrupt::typelevel::Interrupt; |
| 18 | use crate::pac::pdm::mode::{EDGE_A, OPERATION_A}; | 18 | use crate::pac::pdm::mode::{EDGE_A, OPERATION_A}; |
| 19 | pub use crate::pac::pdm::pdmclkctrl::FREQ_A as Frequency; | 19 | pub 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 | ||
| 454 | pub(crate) mod sealed { | 454 | /// Peripheral static state |
| 455 | use embassy_sync::waitqueue::AtomicWaker; | 455 | pub(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 { | 459 | impl 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 { | 467 | pub(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 |
| 477 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 473 | #[allow(private_bounds)] |
| 474 | pub 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 | ||
| 482 | macro_rules! impl_pdm { | 479 | macro_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 | ||
| 213 | pub(crate) mod sealed { | 213 | pub(crate) trait SealedChannel {} |
| 214 | pub trait Channel {} | 214 | pub(crate) trait SealedGroup {} |
| 215 | pub trait Group {} | ||
| 216 | } | ||
| 217 | 215 | ||
| 218 | /// Interface for PPI channels. | 216 | /// Interface for PPI channels. |
| 219 | pub trait Channel: sealed::Channel + Peripheral<P = Self> + Sized + 'static { | 217 | #[allow(private_bounds)] |
| 218 | pub 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. |
| 237 | pub trait Group: sealed::Group + Peripheral<P = Self> + Into<AnyGroup> + Sized + 'static { | 236 | #[allow(private_bounds)] |
| 237 | pub 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 | } |
| 256 | impl_peripheral!(AnyStaticChannel); | 256 | impl_peripheral!(AnyStaticChannel); |
| 257 | impl sealed::Channel for AnyStaticChannel {} | 257 | impl SealedChannel for AnyStaticChannel {} |
| 258 | impl Channel for AnyStaticChannel { | 258 | impl 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 | } |
| 274 | impl_peripheral!(AnyConfigurableChannel); | 274 | impl_peripheral!(AnyConfigurableChannel); |
| 275 | impl sealed::Channel for AnyConfigurableChannel {} | 275 | impl SealedChannel for AnyConfigurableChannel {} |
| 276 | impl Channel for AnyConfigurableChannel { | 276 | impl 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"))] |
| 288 | macro_rules! impl_ppi_channel { | 288 | macro_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 | } |
| 340 | impl_peripheral!(AnyGroup); | 340 | impl_peripheral!(AnyGroup); |
| 341 | impl sealed::Group for AnyGroup {} | 341 | impl SealedGroup for AnyGroup {} |
| 342 | impl Group for AnyGroup { | 342 | impl 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 | ||
| 348 | macro_rules! impl_group { | 348 | macro_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 | ||
| 7 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 7 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 8 | 8 | ||
| 9 | use crate::gpio::sealed::Pin as _; | 9 | use crate::gpio::{AnyPin, Pin as GpioPin, PselBits, SealedPin as _}; |
| 10 | use crate::gpio::{AnyPin, Pin as GpioPin, PselBits}; | ||
| 11 | use crate::ppi::{Event, Task}; | 10 | use crate::ppi::{Event, Task}; |
| 12 | use crate::util::slice_in_ram_or; | 11 | use crate::util::slice_in_ram_or; |
| 13 | use crate::{interrupt, pac, Peripheral}; | 12 | use crate::{interrupt, pac, Peripheral}; |
| @@ -847,23 +846,20 @@ impl<'a, T: Instance> Drop for SimplePwm<'a, T> { | |||
| 847 | } | 846 | } |
| 848 | } | 847 | } |
| 849 | 848 | ||
| 850 | pub(crate) mod sealed { | 849 | pub(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. |
| 859 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | 854 | #[allow(private_bounds)] |
| 855 | pub 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 | ||
| 864 | macro_rules! impl_pwm { | 860 | macro_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; | |||
| 7 | use core::task::Poll; | 7 | use core::task::Poll; |
| 8 | 8 | ||
| 9 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 9 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 10 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 10 | 11 | ||
| 11 | use crate::gpio::sealed::Pin as _; | 12 | use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin as _}; |
| 12 | use crate::gpio::{AnyPin, Pin as GpioPin}; | ||
| 13 | use crate::interrupt::typelevel::Interrupt; | 13 | use crate::interrupt::typelevel::Interrupt; |
| 14 | use crate::{interrupt, Peripheral}; | 14 | use crate::{interrupt, Peripheral}; |
| 15 | 15 | ||
| @@ -245,42 +245,39 @@ pub enum LedPolarity { | |||
| 245 | ActiveLow, | 245 | ActiveLow, |
| 246 | } | 246 | } |
| 247 | 247 | ||
| 248 | pub(crate) mod sealed { | 248 | /// Peripheral static state |
| 249 | use embassy_sync::waitqueue::AtomicWaker; | 249 | pub(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 { | 253 | impl 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 { | 261 | pub(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. |
| 271 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 267 | #[allow(private_bounds)] |
| 268 | pub 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 | ||
| 276 | macro_rules! impl_qdec { | 273 | macro_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 | ||
| 10 | use embassy_hal_internal::drop::OnDrop; | 10 | use embassy_hal_internal::drop::OnDrop; |
| 11 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 11 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 12 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 12 | use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; | 13 | use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; |
| 13 | 14 | ||
| 14 | use crate::gpio::{self, Pin as GpioPin}; | 15 | use 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 | ||
| 655 | pub(crate) mod sealed { | 656 | /// Peripheral static state |
| 656 | use embassy_sync::waitqueue::AtomicWaker; | 657 | pub(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 { | 661 | impl 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 { | 669 | pub(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. |
| 678 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 675 | #[allow(private_bounds)] |
| 676 | pub 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 | ||
| 683 | macro_rules! impl_qspi { | 681 | macro_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 | ||
| 20 | use core::marker::PhantomData; | 20 | use core::marker::PhantomData; |
| 21 | 21 | ||
| 22 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 22 | use pac::radio::state::STATE_A as RadioState; | 23 | use pac::radio::state::STATE_A as RadioState; |
| 23 | pub use pac::radio::txpower::TXPOWER_A as TxPower; | 24 | pub 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 | ||
| 59 | pub(crate) mod sealed { | 60 | pub(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 | 64 | impl 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 { | 72 | pub(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 | ||
| 80 | macro_rules! impl_radio { | 77 | macro_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. |
| 99 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 96 | #[allow(private_bounds)] |
| 97 | pub 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 | ||
| 5 | use core::cell::{RefCell, RefMut}; | ||
| 5 | use core::future::poll_fn; | 6 | use core::future::poll_fn; |
| 6 | use core::marker::PhantomData; | 7 | use core::marker::PhantomData; |
| 7 | use core::ptr; | 8 | use core::ptr; |
| 8 | use core::task::Poll; | 9 | use core::task::Poll; |
| 9 | 10 | ||
| 11 | use critical_section::{CriticalSection, Mutex}; | ||
| 10 | use embassy_hal_internal::drop::OnDrop; | 12 | use embassy_hal_internal::drop::OnDrop; |
| 11 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 13 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 14 | use embassy_sync::waitqueue::WakerRegistration; | ||
| 12 | 15 | ||
| 13 | use crate::interrupt::typelevel::Interrupt; | 16 | use crate::interrupt::typelevel::Interrupt; |
| 14 | use crate::{interrupt, Peripheral}; | 17 | use crate::{interrupt, Peripheral}; |
| @@ -205,73 +208,61 @@ impl<'d, T: Instance> rand_core::RngCore for Rng<'d, T> { | |||
| 205 | 208 | ||
| 206 | impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {} | 209 | impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {} |
| 207 | 210 | ||
| 208 | pub(crate) mod sealed { | 211 | /// Peripheral static state |
| 209 | use core::cell::{Ref, RefCell, RefMut}; | 212 | pub(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 {} | 216 | struct InnerState { |
| 217 | ptr: *mut u8, | ||
| 218 | end: *mut u8, | ||
| 219 | waker: WakerRegistration, | ||
| 220 | } | ||
| 228 | 221 | ||
| 229 | impl State { | 222 | unsafe 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> { | 224 | impl 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 { | 236 | impl 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 { | 246 | pub(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. |
| 262 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 252 | #[allow(private_bounds)] |
| 253 | pub 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 | ||
| 267 | macro_rules! impl_rng { | 258 | macro_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; | |||
| 16 | use saadc::oversample::OVERSAMPLE_A; | 16 | use saadc::oversample::OVERSAMPLE_A; |
| 17 | use saadc::resolution::VAL_A; | 17 | use saadc::resolution::VAL_A; |
| 18 | 18 | ||
| 19 | use self::sealed::Input as _; | ||
| 20 | use crate::interrupt::InterruptExt; | 19 | use crate::interrupt::InterruptExt; |
| 21 | use crate::ppi::{ConfigurableChannel, Event, Ppi, Task}; | 20 | use crate::ppi::{ConfigurableChannel, Event, Ppi, Task}; |
| 22 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | 21 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; |
| @@ -662,16 +661,13 @@ pub enum Resolution { | |||
| 662 | _14BIT = 3, | 661 | _14BIT = 3, |
| 663 | } | 662 | } |
| 664 | 663 | ||
| 665 | pub(crate) mod sealed { | 664 | pub(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. |
| 674 | pub trait Input: sealed::Input + Into<AnyInput> + Peripheral<P = Self> + Sized + 'static { | 669 | #[allow(private_bounds)] |
| 670 | pub 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 | ||
| 694 | impl_peripheral!(AnyInput); | 690 | impl_peripheral!(AnyInput); |
| 695 | 691 | ||
| 696 | impl sealed::Input for AnyInput { | 692 | impl 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 | ||
| 5 | use core::future::poll_fn; | 5 | use core::future::poll_fn; |
| 6 | use core::marker::PhantomData; | 6 | use core::marker::PhantomData; |
| 7 | #[cfg(feature = "_nrf52832_anomaly_109")] | ||
| 8 | use core::sync::atomic::AtomicU8; | ||
| 7 | use core::sync::atomic::{compiler_fence, Ordering}; | 9 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 8 | use core::task::Poll; | 10 | use core::task::Poll; |
| 9 | 11 | ||
| 10 | use embassy_embedded_hal::SetConfig; | 12 | use embassy_embedded_hal::SetConfig; |
| 11 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 13 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 14 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 12 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | 15 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; |
| 13 | pub use pac::spim0::config::ORDER_A as BitOrder; | 16 | pub use pac::spim0::config::ORDER_A as BitOrder; |
| 14 | pub use pac::spim0::frequency::FREQUENCY_A as Frequency; | 17 | pub use pac::spim0::frequency::FREQUENCY_A as Frequency; |
| 15 | 18 | ||
| 16 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | 19 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; |
| 17 | use crate::gpio::sealed::Pin as _; | 20 | use crate::gpio::{self, convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _}; |
| 18 | use crate::gpio::{self, convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits}; | ||
| 19 | use crate::interrupt::typelevel::Interrupt; | 21 | use crate::interrupt::typelevel::Interrupt; |
| 20 | use crate::util::{slice_in_ram_or, slice_ptr_len, slice_ptr_parts, slice_ptr_parts_mut}; | 22 | use crate::util::{slice_in_ram_or, slice_ptr_len, slice_ptr_parts, slice_ptr_parts_mut}; |
| 21 | use crate::{interrupt, pac, Peripheral}; | 23 | use crate::{interrupt, pac, Peripheral}; |
| @@ -487,54 +489,46 @@ impl<'d, T: Instance> Drop for Spim<'d, T> { | |||
| 487 | } | 489 | } |
| 488 | } | 490 | } |
| 489 | 491 | ||
| 490 | pub(crate) mod sealed { | 492 | pub(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 { | 500 | impl 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 { | 512 | pub(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 |
| 525 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | 518 | #[allow(private_bounds)] |
| 519 | pub 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 | ||
| 530 | macro_rules! impl_spim { | 524 | macro_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 | ||
| 9 | use embassy_embedded_hal::SetConfig; | 9 | use embassy_embedded_hal::SetConfig; |
| 10 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 10 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 11 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 11 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; | 12 | pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; |
| 12 | pub use pac::spis0::config::ORDER_A as BitOrder; | 13 | pub use pac::spis0::config::ORDER_A as BitOrder; |
| 13 | 14 | ||
| 14 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | 15 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; |
| 15 | use crate::gpio::sealed::Pin as _; | 16 | use crate::gpio::{self, AnyPin, Pin as GpioPin, SealedPin as _}; |
| 16 | use crate::gpio::{self, AnyPin, Pin as GpioPin}; | ||
| 17 | use crate::interrupt::typelevel::Interrupt; | 17 | use crate::interrupt::typelevel::Interrupt; |
| 18 | use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; | 18 | use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut}; |
| 19 | use crate::{interrupt, pac, Peripheral}; | 19 | use crate::{interrupt, pac, Peripheral}; |
| @@ -456,43 +456,38 @@ impl<'d, T: Instance> Drop for Spis<'d, T> { | |||
| 456 | } | 456 | } |
| 457 | } | 457 | } |
| 458 | 458 | ||
| 459 | pub(crate) mod sealed { | 459 | pub(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 { | 463 | impl 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 { | 471 | pub(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 |
| 483 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | 477 | #[allow(private_bounds)] |
| 478 | pub 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 | ||
| 488 | macro_rules! impl_spis { | 483 | macro_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}; | |||
| 11 | use crate::ppi::{Event, Task}; | 11 | use crate::ppi::{Event, Task}; |
| 12 | use crate::{pac, Peripheral}; | 12 | use crate::{pac, Peripheral}; |
| 13 | 13 | ||
| 14 | pub(crate) mod sealed { | 14 | pub(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. |
| 27 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 21 | #[allow(private_bounds)] |
| 22 | pub 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. |
| 33 | pub trait ExtendedInstance: Instance + sealed::ExtendedInstance {} | 28 | pub trait ExtendedInstance: Instance {} |
| 34 | 29 | ||
| 35 | macro_rules! impl_timer { | 30 | macro_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 | ||
| 730 | pub(crate) mod sealed { | 730 | pub(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 { | 734 | impl 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 { | 742 | pub(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. |
| 752 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | 748 | #[allow(private_bounds)] |
| 749 | pub 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 | ||
| 757 | macro_rules! impl_twim { | 754 | macro_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 | ||
| 757 | pub(crate) mod sealed { | 757 | pub(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 { | 761 | impl 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 { | 769 | pub(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. |
| 779 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static { | 775 | #[allow(private_bounds)] |
| 776 | pub 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 | ||
| 784 | macro_rules! impl_twis { | 781 | macro_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 | ||
| 16 | use core::future::poll_fn; | 16 | use core::future::poll_fn; |
| 17 | use core::marker::PhantomData; | 17 | use core::marker::PhantomData; |
| 18 | use core::sync::atomic::{compiler_fence, Ordering}; | 18 | use core::sync::atomic::{compiler_fence, AtomicU8, Ordering}; |
| 19 | use core::task::Poll; | 19 | use core::task::Poll; |
| 20 | 20 | ||
| 21 | use embassy_hal_internal::drop::OnDrop; | 21 | use embassy_hal_internal::drop::OnDrop; |
| 22 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 22 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 23 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 23 | use pac::uarte0::RegisterBlock; | 24 | use 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. |
| 25 | pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; | 26 | pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; |
| 26 | 27 | ||
| 27 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | 28 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; |
| 28 | use crate::gpio::sealed::Pin as _; | 29 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits, SealedPin as _}; |
| 29 | use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits}; | ||
| 30 | use crate::interrupt::typelevel::Interrupt; | 30 | use crate::interrupt::typelevel::Interrupt; |
| 31 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; | 31 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; |
| 32 | use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | 32 | use 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 | ||
| 942 | pub(crate) fn drop_tx_rx(r: &pac::uarte0::RegisterBlock, s: &sealed::State) { | 942 | pub(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 | ||
| 957 | pub(crate) mod sealed { | 957 | pub(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::*; | 962 | impl 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 { | 972 | pub(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. |
| 987 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 979 | #[allow(private_bounds)] |
| 980 | pub 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 | ||
| 992 | macro_rules! impl_uarte { | 985 | macro_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 | ||
| 796 | pub(crate) mod sealed { | 796 | pub(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. |
| 805 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 801 | #[allow(private_bounds)] |
| 802 | pub 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 | ||
| 810 | macro_rules! impl_usb { | 807 | macro_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; | |||
| 8 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 8 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| 10 | 10 | ||
| 11 | use crate::gpio::sealed::Pin as GpioPin; | 11 | use crate::gpio::{self, AnyPin, Pull, SealedPin as GpioPin}; |
| 12 | use crate::gpio::{self, AnyPin, Pull}; | ||
| 13 | use crate::interrupt::typelevel::Binding; | 12 | use crate::interrupt::typelevel::Binding; |
| 14 | use crate::interrupt::InterruptExt; | 13 | use crate::interrupt::InterruptExt; |
| 15 | use crate::peripherals::{ADC, ADC_TEMP_SENSOR}; | 14 | use 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 | ||
| 337 | mod sealed { | 336 | trait SealedAdcSample: crate::dma::Word {} |
| 338 | pub trait AdcSample: crate::dma::Word {} | 337 | trait SealedAdcChannel {} |
| 339 | |||
| 340 | pub trait AdcChannel {} | ||
| 341 | } | ||
| 342 | 338 | ||
| 343 | /// ADC sample. | 339 | /// ADC sample. |
| 344 | pub trait AdcSample: sealed::AdcSample {} | 340 | #[allow(private_bounds)] |
| 341 | pub trait AdcSample: SealedAdcSample {} | ||
| 345 | 342 | ||
| 346 | impl sealed::AdcSample for u16 {} | 343 | impl SealedAdcSample for u16 {} |
| 347 | impl AdcSample for u16 {} | 344 | impl AdcSample for u16 {} |
| 348 | 345 | ||
| 349 | impl sealed::AdcSample for u8 {} | 346 | impl SealedAdcSample for u8 {} |
| 350 | impl AdcSample for u8 {} | 347 | impl AdcSample for u8 {} |
| 351 | 348 | ||
| 352 | /// ADC channel. | 349 | /// ADC channel. |
| 353 | pub trait AdcChannel: sealed::AdcChannel {} | 350 | #[allow(private_bounds)] |
| 351 | pub trait AdcChannel: SealedAdcChannel {} | ||
| 354 | /// ADC pin. | 352 | /// ADC pin. |
| 355 | pub trait AdcPin: AdcChannel + gpio::Pin {} | 353 | pub trait AdcPin: AdcChannel + gpio::Pin {} |
| 356 | 354 | ||
| 357 | macro_rules! impl_pin { | 355 | macro_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); | |||
| 367 | impl_pin!(PIN_28, 2); | 365 | impl_pin!(PIN_28, 2); |
| 368 | impl_pin!(PIN_29, 3); | 366 | impl_pin!(PIN_29, 3); |
| 369 | 367 | ||
| 370 | impl sealed::AdcChannel for peripherals::ADC_TEMP_SENSOR {} | 368 | impl SealedAdcChannel for peripherals::ADC_TEMP_SENSOR {} |
| 371 | impl AdcChannel for peripherals::ADC_TEMP_SENSOR {} | 369 | impl 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}; | |||
| 6 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 6 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 7 | use pac::clocks::vals::*; | 7 | use pac::clocks::vals::*; |
| 8 | 8 | ||
| 9 | use crate::gpio::sealed::Pin; | 9 | use crate::gpio::{AnyPin, SealedPin}; |
| 10 | use crate::gpio::AnyPin; | ||
| 11 | use crate::pac::common::{Reg, RW}; | 10 | use crate::pac::common::{Reg, RW}; |
| 12 | use crate::{pac, reset, Peripheral}; | 11 | use crate::{pac, reset, Peripheral}; |
| 13 | 12 | ||
| @@ -788,14 +787,14 @@ impl_gpinpin!(PIN_20, 20, 0); | |||
| 788 | impl_gpinpin!(PIN_22, 22, 1); | 787 | impl_gpinpin!(PIN_22, 22, 1); |
| 789 | 788 | ||
| 790 | /// General purpose clock input driver. | 789 | /// General purpose clock input driver. |
| 791 | pub struct Gpin<'d, T: Pin> { | 790 | pub 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 | ||
| 796 | impl<'d, T: Pin> Gpin<'d, T> { | 795 | impl<'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 | ||
| 814 | impl<'d, T: Pin> Drop for Gpin<'d, T> { | 813 | impl<'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; | |||
| 208 | const NEW_AW: AtomicWaker = AtomicWaker::new(); | 208 | const NEW_AW: AtomicWaker = AtomicWaker::new(); |
| 209 | static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AW; CHANNEL_COUNT]; | 209 | static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AW; CHANNEL_COUNT]; |
| 210 | 210 | ||
| 211 | mod sealed { | 211 | trait SealedChannel {} |
| 212 | pub trait Channel {} | 212 | trait SealedWord {} |
| 213 | |||
| 214 | pub trait Word {} | ||
| 215 | } | ||
| 216 | 213 | ||
| 217 | /// DMA channel interface. | 214 | /// DMA channel interface. |
| 218 | pub trait Channel: Peripheral<P = Self> + sealed::Channel + Into<AnyChannel> + Sized + 'static { | 215 | #[allow(private_bounds)] |
| 216 | pub 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. |
| 234 | pub trait Word: sealed::Word { | 232 | #[allow(private_bounds)] |
| 233 | pub trait Word: SealedWord { | ||
| 235 | /// Word size. | 234 | /// Word size. |
| 236 | fn size() -> vals::DataSize; | 235 | fn size() -> vals::DataSize; |
| 237 | } | 236 | } |
| 238 | 237 | ||
| 239 | impl sealed::Word for u8 {} | 238 | impl SealedWord for u8 {} |
| 240 | impl Word for u8 { | 239 | impl 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 | ||
| 246 | impl sealed::Word for u16 {} | 245 | impl SealedWord for u16 {} |
| 247 | impl Word for u16 { | 246 | impl 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 | ||
| 253 | impl sealed::Word for u32 {} | 252 | impl SealedWord for u32 {} |
| 254 | impl Word for u32 { | 253 | impl 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 | ||
| 265 | impl_peripheral!(AnyChannel); | 264 | impl_peripheral!(AnyChannel); |
| 266 | 265 | ||
| 267 | impl sealed::Channel for AnyChannel {} | 266 | impl SealedChannel for AnyChannel {} |
| 268 | impl Channel for AnyChannel { | 267 | impl 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 | ||
| 274 | macro_rules! channel { | 273 | macro_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 | ||
| 906 | mod sealed { | 906 | trait SealedInstance {} |
| 907 | pub trait Instance {} | 907 | trait SealedMode {} |
| 908 | pub trait Mode {} | ||
| 909 | } | ||
| 910 | 908 | ||
| 911 | /// Flash instance. | 909 | /// Flash instance. |
| 912 | pub trait Instance: sealed::Instance {} | 910 | #[allow(private_bounds)] |
| 911 | pub trait Instance: SealedInstance {} | ||
| 913 | /// Flash mode. | 912 | /// Flash mode. |
| 914 | pub trait Mode: sealed::Mode {} | 913 | #[allow(private_bounds)] |
| 914 | pub trait Mode: SealedMode {} | ||
| 915 | 915 | ||
| 916 | impl sealed::Instance for FLASH {} | 916 | impl SealedInstance for FLASH {} |
| 917 | impl Instance for FLASH {} | 917 | impl Instance for FLASH {} |
| 918 | 918 | ||
| 919 | macro_rules! impl_mode { | 919 | macro_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}; | |||
| 8 | use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; | 8 | use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| 10 | 10 | ||
| 11 | use self::sealed::Pin as _; | ||
| 12 | use crate::interrupt::InterruptExt; | 11 | use crate::interrupt::InterruptExt; |
| 13 | use crate::pac::common::{Reg, RW}; | 12 | use crate::pac::common::{Reg, RW}; |
| 14 | use crate::pac::SIO; | 13 | use crate::pac::SIO; |
| @@ -802,68 +801,65 @@ impl<'w> Drop for DormantWake<'w> { | |||
| 802 | } | 801 | } |
| 803 | } | 802 | } |
| 804 | 803 | ||
| 805 | pub(crate) mod sealed { | 804 | pub(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]. |
| 866 | pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + sealed::Pin + Sized + 'static { | 861 | #[allow(private_bounds)] |
| 862 | pub 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 { | |||
| 903 | impl_peripheral!(AnyPin); | 899 | impl_peripheral!(AnyPin); |
| 904 | 900 | ||
| 905 | impl Pin for AnyPin {} | 901 | impl Pin for AnyPin {} |
| 906 | impl sealed::Pin for AnyPin { | 902 | impl 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 { | |||
| 914 | macro_rules! impl_pin { | 910 | macro_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 | ||
| 787 | mod sealed { | 787 | pub(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 | ||
| 796 | trait SealedMode {} | ||
| 797 | |||
| 809 | /// Driver mode. | 798 | /// Driver mode. |
| 810 | pub trait Mode: sealed::Mode {} | 799 | #[allow(private_bounds)] |
| 800 | pub trait Mode: SealedMode {} | ||
| 811 | 801 | ||
| 812 | macro_rules! impl_mode { | 802 | macro_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); | |||
| 825 | impl_mode!(Async); | 815 | impl_mode!(Async); |
| 826 | 816 | ||
| 827 | /// I2C instance. | 817 | /// I2C instance. |
| 828 | pub trait Instance: sealed::Instance {} | 818 | #[allow(private_bounds)] |
| 819 | pub trait Instance: SealedInstance { | ||
| 820 | /// Interrupt for this peripheral. | ||
| 821 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 822 | } | ||
| 829 | 823 | ||
| 830 | macro_rules! impl_instance { | 824 | macro_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); | |||
| 862 | impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35); | 856 | impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35); |
| 863 | 857 | ||
| 864 | /// SDA pin. | 858 | /// SDA pin. |
| 865 | pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {} | 859 | pub trait SdaPin<T: Instance>: crate::gpio::Pin {} |
| 866 | /// SCL pin. | 860 | /// SCL pin. |
| 867 | pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {} | 861 | pub trait SclPin<T: Instance>: crate::gpio::Pin {} |
| 868 | 862 | ||
| 869 | macro_rules! impl_pin { | 863 | macro_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; | |||
| 15 | use pio::{Program, SideSet, Wrap}; | 15 | use pio::{Program, SideSet, Wrap}; |
| 16 | 16 | ||
| 17 | use crate::dma::{Channel, Transfer, Word}; | 17 | use crate::dma::{Channel, Transfer, Word}; |
| 18 | use crate::gpio::sealed::Pin as SealedPin; | 18 | use crate::gpio::{self, AnyPin, Drive, Level, Pull, SealedPin, SlewRate}; |
| 19 | use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate}; | ||
| 20 | use crate::interrupt::typelevel::{Binding, Handler, Interrupt}; | 19 | use crate::interrupt::typelevel::{Binding, Handler, Interrupt}; |
| 21 | use crate::pac::dma::vals::TreqSel; | 20 | use crate::pac::dma::vals::TreqSel; |
| 22 | use crate::relocate::RelocatedProgram; | 21 | use 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 | ||
| 1151 | mod sealed { | 1156 | trait 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. |
| 1183 | pub trait Instance: sealed::Instance + Sized + Unpin {} | 1181 | #[allow(private_bounds)] |
| 1182 | pub trait Instance: SealedInstance + Sized + Unpin { | ||
| 1183 | /// Interrupt for this peripheral. | ||
| 1184 | type Interrupt: crate::interrupt::typelevel::Interrupt; | ||
| 1185 | } | ||
| 1184 | 1186 | ||
| 1185 | macro_rules! impl_pio { | 1187 | macro_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); | |||
| 1198 | impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0); | 1201 | impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0); |
| 1199 | 1202 | ||
| 1200 | /// PIO pin. | 1203 | /// PIO pin. |
| 1201 | pub trait PioPin: sealed::PioPin + gpio::Pin {} | 1204 | pub trait PioPin: gpio::Pin {} |
| 1202 | 1205 | ||
| 1203 | macro_rules! impl_pio_pin { | 1206 | macro_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; | |||
| 6 | use pac::pwm::regs::{ChDiv, Intr}; | 6 | use pac::pwm::regs::{ChDiv, Intr}; |
| 7 | use pac::pwm::vals::Divmode; | 7 | use pac::pwm::vals::Divmode; |
| 8 | 8 | ||
| 9 | use crate::gpio::sealed::Pin as _; | 9 | use crate::gpio::{AnyPin, Pin as GpioPin, Pull, SealedPin as _}; |
| 10 | use crate::gpio::{AnyPin, Pin as GpioPin}; | ||
| 11 | use crate::{pac, peripherals, RegExt}; | 10 | use 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 | ||
| 303 | mod sealed { | 323 | trait SealedSlice {} |
| 304 | pub trait Slice {} | ||
| 305 | } | ||
| 306 | 324 | ||
| 307 | /// PWM Slice. | 325 | /// PWM Slice. |
| 308 | pub trait Slice: Peripheral<P = Self> + sealed::Slice + Sized + 'static { | 326 | #[allow(private_bounds)] |
| 327 | pub 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 | ||
| 318 | macro_rules! slice { | 337 | macro_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 | ||
| 191 | mod sealed { | 191 | trait 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. |
| 198 | pub trait Instance: sealed::Instance {} | 196 | #[allow(private_bounds)] |
| 197 | pub trait Instance: SealedInstance {} | ||
| 199 | 198 | ||
| 200 | impl sealed::Instance for crate::peripherals::RTC { | 199 | impl 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}; | |||
| 7 | pub use embedded_hal_02::spi::{Phase, Polarity}; | 7 | pub use embedded_hal_02::spi::{Phase, Polarity}; |
| 8 | 8 | ||
| 9 | use crate::dma::{AnyChannel, Channel}; | 9 | use crate::dma::{AnyChannel, Channel}; |
| 10 | use crate::gpio::sealed::Pin as _; | 10 | use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin as _}; |
| 11 | use crate::gpio::{AnyPin, Pin as GpioPin}; | ||
| 12 | use crate::{pac, peripherals, Peripheral}; | 11 | use 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 | ||
| 446 | mod sealed { | 445 | trait SealedMode {} |
| 447 | use super::*; | ||
| 448 | 446 | ||
| 449 | pub trait Mode {} | 447 | trait 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. |
| 460 | pub trait Mode: sealed::Mode {} | 455 | #[allow(private_bounds)] |
| 456 | pub trait Mode: SealedMode {} | ||
| 461 | 457 | ||
| 462 | /// SPI instance trait. | 458 | /// SPI instance trait. |
| 463 | pub trait Instance: sealed::Instance {} | 459 | #[allow(private_bounds)] |
| 460 | pub trait Instance: SealedInstance {} | ||
| 464 | 461 | ||
| 465 | macro_rules! impl_instance { | 462 | macro_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 | ||
| 528 | macro_rules! impl_mode { | 525 | macro_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 | ||
| 13 | use crate::clocks::clk_peri_freq; | 13 | use crate::clocks::clk_peri_freq; |
| 14 | use crate::dma::{AnyChannel, Channel}; | 14 | use crate::dma::{AnyChannel, Channel}; |
| 15 | use crate::gpio::sealed::Pin; | 15 | use crate::gpio::{AnyPin, SealedPin}; |
| 16 | use crate::gpio::AnyPin; | ||
| 17 | use crate::interrupt::typelevel::{Binding, Interrupt}; | 16 | use crate::interrupt::typelevel::{Binding, Interrupt}; |
| 18 | use crate::pac::io::vals::{Inover, Outover}; | 17 | use crate::pac::io::vals::{Inover, Outover}; |
| 19 | use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; | 18 | use 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 | ||
| 1110 | mod sealed { | 1109 | trait SealedMode {} |
| 1111 | use super::*; | ||
| 1112 | 1110 | ||
| 1113 | pub trait Mode {} | 1111 | trait 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. |
| 1134 | pub trait Mode: sealed::Mode {} | 1123 | #[allow(private_bounds)] |
| 1124 | pub trait Mode: SealedMode {} | ||
| 1135 | 1125 | ||
| 1136 | macro_rules! impl_mode { | 1126 | macro_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); | |||
| 1149 | impl_mode!(Async); | 1139 | impl_mode!(Async); |
| 1150 | 1140 | ||
| 1151 | /// UART instance. | 1141 | /// UART instance. |
| 1152 | pub trait Instance: sealed::Instance {} | 1142 | #[allow(private_bounds)] |
| 1143 | pub trait Instance: SealedInstance { | ||
| 1144 | /// Interrupt for this instance. | ||
| 1145 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 1146 | } | ||
| 1153 | 1147 | ||
| 1154 | macro_rules! impl_instance { | 1148 | macro_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); | |||
| 1184 | impl_instance!(UART1, UART1_IRQ, 22, 23); | 1178 | impl_instance!(UART1, UART1_IRQ, 22, 23); |
| 1185 | 1179 | ||
| 1186 | /// Trait for TX pins. | 1180 | /// Trait for TX pins. |
| 1187 | pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} | 1181 | pub trait TxPin<T: Instance>: crate::gpio::Pin {} |
| 1188 | /// Trait for RX pins. | 1182 | /// Trait for RX pins. |
| 1189 | pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} | 1183 | pub trait RxPin<T: Instance>: crate::gpio::Pin {} |
| 1190 | /// Trait for Clear To Send (CTS) pins. | 1184 | /// Trait for Clear To Send (CTS) pins. |
| 1191 | pub trait CtsPin<T: Instance>: sealed::CtsPin<T> + crate::gpio::Pin {} | 1185 | pub trait CtsPin<T: Instance>: crate::gpio::Pin {} |
| 1192 | /// Trait for Request To Send (RTS) pins. | 1186 | /// Trait for Request To Send (RTS) pins. |
| 1193 | pub trait RtsPin<T: Instance>: sealed::RtsPin<T> + crate::gpio::Pin {} | 1187 | pub trait RtsPin<T: Instance>: crate::gpio::Pin {} |
| 1194 | 1188 | ||
| 1195 | macro_rules! impl_pin { | 1189 | macro_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::{ | |||
| 14 | use crate::interrupt::typelevel::{Binding, Interrupt}; | 14 | use crate::interrupt::typelevel::{Binding, Interrupt}; |
| 15 | use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; | 15 | use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; |
| 16 | 16 | ||
| 17 | pub(crate) mod sealed { | 17 | trait 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. |
| 25 | pub trait Instance: sealed::Instance + 'static { | 23 | #[allow(private_bounds)] |
| 24 | pub 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 | ||
| 30 | impl crate::usb::sealed::Instance for peripherals::USB { | 29 | impl 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" | |||
| 70 | sdio-host = "0.5.0" | 70 | sdio-host = "0.5.0" |
| 71 | critical-section = "1.1" | 71 | critical-section = "1.1" |
| 72 | #stm32-metapac = { version = "15" } | 72 | #stm32-metapac = { version = "15" } |
| 73 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f84633553331c2d154ee72de779a40cbb10fd1bd" } | 73 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2b7ec569a5510c324693f0515ac8ea20b12917a9" } |
| 74 | |||
| 74 | vcell = "0.1.3" | 75 | vcell = "0.1.3" |
| 75 | nb = "1.0.0" | 76 | nb = "1.0.0" |
| 76 | stm32-fmc = "0.3.0" | 77 | stm32-fmc = "0.3.0" |
| @@ -93,9 +94,9 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 93 | [build-dependencies] | 94 | [build-dependencies] |
| 94 | proc-macro2 = "1.0.36" | 95 | proc-macro2 = "1.0.36" |
| 95 | quote = "1.0.15" | 96 | quote = "1.0.15" |
| 96 | #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} | ||
| 97 | stm32-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"]} | ||
| 99 | stm32-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] |
| 101 | default = ["rt"] | 102 | default = ["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))] | ||
| 5 | pub 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)] | ||
| 21 | pub 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))] | ||
| 44 | pub 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)] | ||
| 59 | pub enum AccessCount { | ||
| 60 | #[default] | ||
| 61 | One, | ||
| 62 | Two, | ||
| 63 | } | ||
| 64 | |||
| 65 | /// CORDIC argument/result data width | ||
| 66 | #[allow(missing_docs)] | ||
| 67 | #[derive(Clone, Copy)] | ||
| 68 | pub 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 @@ | |||
| 1 | use super::{Function, Scale}; | ||
| 2 | |||
| 3 | /// Error for [Cordic](super::Cordic) | ||
| 4 | #[derive(Debug)] | ||
| 5 | pub 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 | |||
| 18 | impl From<ConfigError> for CordicError { | ||
| 19 | fn from(value: ConfigError) -> Self { | ||
| 20 | Self::ConfigError(value) | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 24 | impl From<NumberOutOfRange> for CordicError { | ||
| 25 | fn from(value: NumberOutOfRange) -> Self { | ||
| 26 | Self::NumberOutOfRange(value) | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | impl From<ArgError> for CordicError { | ||
| 31 | fn from(value: ArgError) -> Self { | ||
| 32 | Self::ArgError(value) | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | #[cfg(feature = "defmt")] | ||
| 37 | impl 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)] | ||
| 54 | pub struct ConfigError { | ||
| 55 | pub(super) func: Function, | ||
| 56 | pub(super) scale_range: [u8; 2], | ||
| 57 | } | ||
| 58 | |||
| 59 | #[cfg(feature = "defmt")] | ||
| 60 | impl 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)] | ||
| 80 | pub enum NumberOutOfRange { | ||
| 81 | BelowLowerBound, | ||
| 82 | AboveUpperBound, | ||
| 83 | } | ||
| 84 | |||
| 85 | #[cfg(feature = "defmt")] | ||
| 86 | impl 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)] | ||
| 100 | pub 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")] | ||
| 109 | impl 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))] | ||
| 141 | pub(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 | |||
| 3 | use embassy_hal_internal::drop::OnDrop; | ||
| 4 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | ||
| 5 | |||
| 6 | use crate::pac::cordic::vals; | ||
| 7 | use crate::{dma, peripherals}; | ||
| 8 | |||
| 9 | mod enums; | ||
| 10 | pub use enums::*; | ||
| 11 | |||
| 12 | mod errors; | ||
| 13 | pub use errors::*; | ||
| 14 | |||
| 15 | pub mod utils; | ||
| 16 | |||
| 17 | /// CORDIC driver | ||
| 18 | pub struct Cordic<'d, T: Instance> { | ||
| 19 | peri: PeripheralRef<'d, T>, | ||
| 20 | config: Config, | ||
| 21 | } | ||
| 22 | |||
| 23 | /// Cordic instance | ||
| 24 | trait 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)] | ||
| 139 | pub trait Instance: SealedInstance + Peripheral<P = Self> + crate::rcc::RccPeripheral {} | ||
| 140 | |||
| 141 | /// CORDIC configuration | ||
| 142 | #[derive(Debug)] | ||
| 143 | pub struct Config { | ||
| 144 | function: Function, | ||
| 145 | precision: Precision, | ||
| 146 | scale: Scale, | ||
| 147 | } | ||
| 148 | |||
| 149 | impl 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 | ||
| 194 | impl<'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 | |||
| 259 | impl<'d, T: Instance> Drop for Cordic<'d, T> { | ||
| 260 | fn drop(&mut self) { | ||
| 261 | T::disable(); | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | // q1.31 related | ||
| 266 | impl<'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 | ||
| 468 | impl<'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 | |||
| 581 | macro_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 | |||
| 712 | check_arg_value!(check_f64_arg1, check_f64_arg2, &f64); | ||
| 713 | check_arg_value!(check_f32_arg1, check_f32_arg2, &f32); | ||
| 714 | |||
| 715 | foreach_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 | |||
| 728 | dma_trait!(WriteDma, Instance); | ||
| 729 | dma_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 | ||
| 2 | use super::errors::NumberOutOfRange; | ||
| 3 | |||
| 4 | macro_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 | |||
| 44 | floating_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 | |||
| 54 | floating_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 @@ | |||
| 6 | mod _version; | 6 | mod _version; |
| 7 | 7 | ||
| 8 | use core::future::Future; | 8 | use core::future::Future; |
| 9 | use core::iter; | ||
| 9 | use core::marker::PhantomData; | 10 | use core::marker::PhantomData; |
| 10 | 11 | ||
| 11 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | 12 | use 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)] | ||
| 360 | enum 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)] | ||
| 378 | impl 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)] | ||
| 411 | fn 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)] | ||
| 62 | enum 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 | |||
| 80 | impl 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 | |||
| 106 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | 44 | impl<'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; | |||
| 32 | pub mod adc; | 32 | pub mod adc; |
| 33 | #[cfg(can)] | 33 | #[cfg(can)] |
| 34 | pub mod can; | 34 | pub mod can; |
| 35 | // FIXME: Cordic driver cause stm32u5a5zj crash | ||
| 36 | #[cfg(all(cordic, not(any(stm32u5a5, stm32u5a9))))] | ||
| 37 | pub mod cordic; | ||
| 35 | #[cfg(crc)] | 38 | #[cfg(crc)] |
| 36 | pub mod crc; | 39 | pub mod crc; |
| 37 | #[cfg(cryp)] | 40 | #[cfg(cryp)] |
| @@ -61,6 +64,8 @@ pub mod ipcc; | |||
| 61 | pub mod low_power; | 64 | pub mod low_power; |
| 62 | #[cfg(opamp)] | 65 | #[cfg(opamp)] |
| 63 | pub mod opamp; | 66 | pub mod opamp; |
| 67 | #[cfg(octospi)] | ||
| 68 | pub mod ospi; | ||
| 64 | #[cfg(quadspi)] | 69 | #[cfg(quadspi)] |
| 65 | pub mod qspi; | 70 | pub 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)] | ||
| 5 | pub(crate) enum OspiMode { | ||
| 6 | IndirectWrite, | ||
| 7 | IndirectRead, | ||
| 8 | AutoPolling, | ||
| 9 | MemoryMapped, | ||
| 10 | } | ||
| 11 | |||
| 12 | impl 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)] | ||
| 26 | pub 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 | |||
| 39 | impl 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)] | ||
| 54 | pub enum FlashSelection { | ||
| 55 | /// Bank 1 | ||
| 56 | Flash1, | ||
| 57 | /// Bank 2 | ||
| 58 | Flash2, | ||
| 59 | } | ||
| 60 | |||
| 61 | impl 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)] | ||
| 74 | pub enum WrapSize { | ||
| 75 | None, | ||
| 76 | _16Bytes, | ||
| 77 | _32Bytes, | ||
| 78 | _64Bytes, | ||
| 79 | _128Bytes, | ||
| 80 | } | ||
| 81 | |||
| 82 | impl 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)] | ||
| 98 | pub enum MemoryType { | ||
| 99 | Micron, | ||
| 100 | Macronix, | ||
| 101 | Standard, | ||
| 102 | MacronixRam, | ||
| 103 | HyperBusMemory, | ||
| 104 | HyperBusRegister, | ||
| 105 | } | ||
| 106 | |||
| 107 | impl 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)] | ||
| 123 | pub 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 | |||
| 150 | impl 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)] | ||
| 183 | pub 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 | |||
| 194 | impl 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)] | ||
| 208 | pub enum ChipSelectHighTime { | ||
| 209 | _1Cycle, | ||
| 210 | _2Cycle, | ||
| 211 | _3Cycle, | ||
| 212 | _4Cycle, | ||
| 213 | _5Cycle, | ||
| 214 | _6Cycle, | ||
| 215 | _7Cycle, | ||
| 216 | _8Cycle, | ||
| 217 | } | ||
| 218 | |||
| 219 | impl 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)] | ||
| 237 | pub 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 | |||
| 272 | impl 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)] | ||
| 314 | pub 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 | |||
| 349 | impl 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 | |||
| 6 | pub mod enums; | ||
| 7 | |||
| 8 | use embassy_embedded_hal::{GetConfig, SetConfig}; | ||
| 9 | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||
| 10 | pub use enums::*; | ||
| 11 | use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits}; | ||
| 12 | |||
| 13 | use crate::dma::{word, Transfer}; | ||
| 14 | use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _}; | ||
| 15 | use crate::pac::octospi::{vals, Octospi as Regs}; | ||
| 16 | use crate::rcc::RccPeripheral; | ||
| 17 | use crate::{peripherals, Peripheral}; | ||
| 18 | |||
| 19 | /// OPSI driver config. | ||
| 20 | #[derive(Clone, Copy)] | ||
| 21 | pub 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 | |||
| 59 | impl 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. | ||
| 81 | pub 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 | |||
| 118 | impl 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))] | ||
| 147 | pub 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. | ||
| 157 | pub 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 | |||
| 175 | impl<'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 | |||
| 945 | impl<'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 | |||
| 963 | fn 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 | |||
| 972 | trait RegsExt { | ||
| 973 | fn dr_ptr<W>(&self) -> *mut W; | ||
| 974 | } | ||
| 975 | |||
| 976 | impl 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 | |||
| 983 | pub(crate) trait SealedInstance { | ||
| 984 | const REGS: Regs; | ||
| 985 | } | ||
| 986 | |||
| 987 | trait SealedWord { | ||
| 988 | const CONFIG: u8; | ||
| 989 | } | ||
| 990 | |||
| 991 | /// OSPI instance trait. | ||
| 992 | #[allow(private_bounds)] | ||
| 993 | pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {} | ||
| 994 | |||
| 995 | pin_trait!(SckPin, Instance); | ||
| 996 | pin_trait!(NckPin, Instance); | ||
| 997 | pin_trait!(D0Pin, Instance); | ||
| 998 | pin_trait!(D1Pin, Instance); | ||
| 999 | pin_trait!(D2Pin, Instance); | ||
| 1000 | pin_trait!(D3Pin, Instance); | ||
| 1001 | pin_trait!(D4Pin, Instance); | ||
| 1002 | pin_trait!(D5Pin, Instance); | ||
| 1003 | pin_trait!(D6Pin, Instance); | ||
| 1004 | pin_trait!(D7Pin, Instance); | ||
| 1005 | pin_trait!(DQSPin, Instance); | ||
| 1006 | pin_trait!(NSSPin, Instance); | ||
| 1007 | dma_trait!(OctoDma, Instance); | ||
| 1008 | |||
| 1009 | foreach_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 | |||
| 1019 | impl<'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 | |||
| 1028 | impl<'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)] | ||
| 1037 | pub trait Word: word::Word + SealedWord {} | ||
| 1038 | |||
| 1039 | macro_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 | |||
| 1048 | impl_word!(u8, 8); | ||
| 1049 | impl_word!(u16, 16); | ||
| 1050 | impl_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 | ||
| 34 | impl Default for TransferConfig { | 32 | impl 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; | |||
| 15 | use crate::rcc::SealedRccPeripheral; | 15 | use crate::rcc::SealedRccPeripheral; |
| 16 | #[cfg(feature = "low-power")] | 16 | #[cfg(feature = "low-power")] |
| 17 | use crate::rtc::Rtc; | 17 | use crate::rtc::Rtc; |
| 18 | #[cfg(any(time_driver_tim1, time_driver_tim8, time_driver_tim20))] | 18 | use crate::timer::{CoreInstance, GeneralInstance1Channel}; |
| 19 | use crate::timer::AdvancedInstance1Channel; | ||
| 20 | use crate::timer::CoreInstance; | ||
| 21 | use crate::{interrupt, peripherals}; | 19 | use crate::{interrupt, peripherals}; |
| 22 | 20 | ||
| 23 | // NOTE regarding ALARM_COUNT: | 21 | // NOTE regarding ALARM_COUNT: |
| @@ -69,7 +67,7 @@ type T = peripherals::TIM23; | |||
| 69 | type T = peripherals::TIM24; | 67 | type T = peripherals::TIM24; |
| 70 | 68 | ||
| 71 | foreach_interrupt! { | 69 | foreach_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)] | ||
| 266 | const ALARM_STATE_NEW: AlarmState = AlarmState::new(); | 265 | const ALARM_STATE_NEW: AlarmState = AlarmState::new(); |
| 267 | 266 | ||
| 268 | embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { | 267 | embassy_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. |
| 49 | pub trait CoreInstance: RccPeripheral + 'static { | 49 | pub 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 {} | |||
| 64 | pub trait BasicInstance: BasicNoCr2Instance {} | 64 | pub 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. |
| 67 | pub trait GeneralInstance1Channel: CoreInstance {} | 67 | pub 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. |
| 70 | pub trait GeneralInstance2Channel: GeneralInstance1Channel {} | 73 | pub 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, |
| 73 | pub 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. | ||
| 83 | trait 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)] | ||
| 96 | pub 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. |
| 84 | pub trait GeneralInstance32bit4Channel: GeneralInstance4Channel {} | 99 | pub trait GeneralInstance32bit4Channel: GeneralInstance4Channel {} |
| 85 | 100 | ||
| 86 | /// Advanced 16-bit timer with 1 channel instance. | 101 | /// Advanced 16-bit timer with 1 channel instance. |
| 87 | pub trait AdvancedInstance1Channel: BasicNoCr2Instance + GeneralInstance1Channel { | 102 | pub 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); | |||
| 127 | macro_rules! impl_core_timer { | 144 | macro_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)] | ||
| 159 | macro_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)] | ||
| 168 | macro_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)] | ||
| 177 | macro_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)] | ||
| 189 | macro_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 | |||
| 141 | foreach_interrupt! { | 201 | foreach_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)] | ||
| 224 | fn 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 | ||
| 108 | pub(crate) use sealed::State; | 108 | pub(crate) struct State { |
| 109 | pub(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, | 116 | impl 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. | |||
| 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), |
| 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | 6 | and 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 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_rp::gpio::Pull; | ||
| 8 | use embassy_rp::pwm::{Config, InputMode, Pwm}; | 9 | use embassy_rp::pwm::{Config, InputMode, Pwm}; |
| 9 | use embassy_time::{Duration, Ticker}; | 10 | use embassy_time::{Duration, Ticker}; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {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 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::cordic::{self, utils}; | ||
| 7 | use {defmt_rtt as _, panic_probe as _}; | ||
| 8 | |||
| 9 | #[embassy_executor::main] | ||
| 10 | async 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 | |||
| 14 | stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] | 14 | stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] |
| 15 | stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] | 15 | stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] |
| 16 | stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"] | 16 | stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"] |
| 17 | stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"] | 17 | stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan", "cordic"] |
| 18 | stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash"] | 18 | stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash", "cordic"] |
| 19 | stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] | 19 | stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] |
| 20 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"] | 20 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"] |
| 21 | stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] | 21 | stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] |
| @@ -25,8 +25,8 @@ stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] | |||
| 25 | stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"] | 25 | stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"] |
| 26 | stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] | 26 | stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] |
| 27 | stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"] | 27 | stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"] |
| 28 | stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng", "hash"] | 28 | stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng", "hash", "cordic"] |
| 29 | stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng", "hash"] | 29 | stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng", "hash"] # FIXME: cordic test cause it crash |
| 30 | stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] | 30 | stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] |
| 31 | stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng", "hash"] | 31 | stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng", "hash"] |
| 32 | stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] | 32 | stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] |
| @@ -48,6 +48,7 @@ embassy-stm32-wpan = [] | |||
| 48 | not-gpdma = [] | 48 | not-gpdma = [] |
| 49 | dac = [] | 49 | dac = [] |
| 50 | ucpd = [] | 50 | ucpd = [] |
| 51 | cordic = ["dep:num-traits"] | ||
| 51 | 52 | ||
| 52 | cm0 = ["portable-atomic/unsafe-assume-single-core"] | 53 | cm0 = ["portable-atomic/unsafe-assume-single-core"] |
| 53 | 54 | ||
| @@ -83,6 +84,7 @@ chrono = { version = "^0.4", default-features = false, optional = true} | |||
| 83 | sha2 = { version = "0.10.8", default-features = false } | 84 | sha2 = { version = "0.10.8", default-features = false } |
| 84 | hmac = "0.12.1" | 85 | hmac = "0.12.1" |
| 85 | aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] } | 86 | aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] } |
| 87 | num-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" | |||
| 92 | required-features = [ "can",] | 94 | required-features = [ "can",] |
| 93 | 95 | ||
| 94 | [[bin]] | 96 | [[bin]] |
| 97 | name = "cordic" | ||
| 98 | path = "src/bin/cordic.rs" | ||
| 99 | required-features = [ "rng", "cordic",] | ||
| 100 | |||
| 101 | [[bin]] | ||
| 95 | name = "cryp" | 102 | name = "cryp" |
| 96 | path = "src/bin/cryp.rs" | 103 | path = "src/bin/cryp.rs" |
| 97 | required-features = [ "cryp",] | 104 | required-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"] | ||
| 9 | mod common; | ||
| 10 | use common::*; | ||
| 11 | use embassy_executor::Spawner; | ||
| 12 | use embassy_stm32::cordic::utils; | ||
| 13 | use embassy_stm32::{bind_interrupts, cordic, peripherals, rng}; | ||
| 14 | use num_traits::Float; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | bind_interrupts!(struct Irqs { | ||
| 18 | RNG => rng::InterruptHandler<peripherals::RNG>; | ||
| 19 | }); | ||
| 20 | |||
| 21 | /* input value control, can be changed */ | ||
| 22 | |||
| 23 | const INPUT_U32_COUNT: usize = 9; | ||
| 24 | const 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. | ||
| 28 | const OUTPUT_LENGTH: usize = (INPUT_U32_COUNT - 1) * 2; | ||
| 29 | |||
| 30 | #[embassy_executor::main] | ||
| 31 | async 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 | } | ||
