diff options
29 files changed, 541 insertions, 147 deletions
diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 8ce484646..89adaf2da 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md | |||
| @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 11 | - added: Add basic RTC support for nRF54L | 11 | - added: Add basic RTC support for nRF54L |
| 12 | - changed: apply trimming values from FICR.TRIMCNF on nrf53/54l | 12 | - changed: apply trimming values from FICR.TRIMCNF on nrf53/54l |
| 13 | - changed: do not panic on BufferedUarte overrun | 13 | - changed: do not panic on BufferedUarte overrun |
| 14 | - added: allow direct access to the input pin of `gpiote::InputChannel` | ||
| 15 | - bugfix: use DETECTMODE_SEC in GPIOTE in secure mode | ||
| 14 | - added: allow configuring the idle state of GPIO pins connected to PWM channels | 16 | - added: allow configuring the idle state of GPIO pins connected to PWM channels |
| 15 | - changed: allow configuring the PWM peripheral in the constructor of `SimplePwm` | 17 | - changed: allow configuring the PWM peripheral in the constructor of `SimplePwm` |
| 16 | - changed: support setting duty cycles with inverted polarity in `SimplePwm` | 18 | - changed: support setting duty cycles with inverted polarity in `SimplePwm` |
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index a490d5b60..3658657c0 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs | |||
| @@ -77,6 +77,9 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) { | |||
| 77 | 77 | ||
| 78 | for &p in ports { | 78 | for &p in ports { |
| 79 | // Enable latched detection | 79 | // Enable latched detection |
| 80 | #[cfg(feature = "_s")] | ||
| 81 | p.detectmode_sec().write(|w| w.set_detectmode(Detectmode::LDETECT)); | ||
| 82 | #[cfg(not(feature = "_s"))] | ||
| 80 | p.detectmode().write(|w| w.set_detectmode(Detectmode::LDETECT)); | 83 | p.detectmode().write(|w| w.set_detectmode(Detectmode::LDETECT)); |
| 81 | // Clear latch | 84 | // Clear latch |
| 82 | p.latch().write(|w| w.0 = 0xFFFFFFFF) | 85 | p.latch().write(|w| w.0 = 0xFFFFFFFF) |
| @@ -259,6 +262,11 @@ impl<'d> InputChannel<'d> { | |||
| 259 | .await; | 262 | .await; |
| 260 | } | 263 | } |
| 261 | 264 | ||
| 265 | /// Get the associated input pin. | ||
| 266 | pub fn pin(&self) -> &Input<'_> { | ||
| 267 | &self.pin | ||
| 268 | } | ||
| 269 | |||
| 262 | /// Returns the IN event, for use with PPI. | 270 | /// Returns the IN event, for use with PPI. |
| 263 | pub fn event_in(&self) -> Event<'d> { | 271 | pub fn event_in(&self) -> Event<'d> { |
| 264 | let g = regs(); | 272 | let g = regs(); |
diff --git a/embassy-nxp/CHANGELOG.md b/embassy-nxp/CHANGELOG.md index 0fb677cd8..39f5c75bd 100644 --- a/embassy-nxp/CHANGELOG.md +++ b/embassy-nxp/CHANGELOG.md | |||
| @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 7 | 7 | ||
| 8 | <!-- next-header --> | 8 | <!-- next-header --> |
| 9 | ## Unreleased - ReleaseDate | 9 | ## Unreleased - ReleaseDate |
| 10 | - LPC55: PWM simple | ||
| 11 | - LPC55: Move ALT definitions for USART to TX/RX pin impls. | ||
| 12 | - LPC55: Remove internal match_iocon macro | ||
| 10 | - LPC55: DMA Controller and asynchronous version of USART | 13 | - LPC55: DMA Controller and asynchronous version of USART |
| 11 | - Moved NXP LPC55S69 from `lpc55-pac` to `nxp-pac` | 14 | - Moved NXP LPC55S69 from `lpc55-pac` to `nxp-pac` |
| 12 | - First release with changelog. | 15 | - First release with changelog. |
diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml index 33f0f2dff..f8c63ba29 100644 --- a/embassy-nxp/Cargo.toml +++ b/embassy-nxp/Cargo.toml | |||
| @@ -38,13 +38,13 @@ embassy-time-queue-utils = { version = "0.3.0", path = "../embassy-time-queue-ut | |||
| 38 | embedded-io = "0.6.1" | 38 | embedded-io = "0.6.1" |
| 39 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 39 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 40 | ## Chip dependencies | 40 | ## Chip dependencies |
| 41 | nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "b736e3038254d593024aaa1a5a7b1f95a5728538"} | 41 | nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "477dfdbfd5e6c75c0730c56494b601c1b2257263"} |
| 42 | 42 | ||
| 43 | imxrt-rt = { version = "0.1.7", optional = true, features = ["device"] } | 43 | imxrt-rt = { version = "0.1.7", optional = true, features = ["device"] } |
| 44 | 44 | ||
| 45 | [build-dependencies] | 45 | [build-dependencies] |
| 46 | cfg_aliases = "0.2.1" | 46 | cfg_aliases = "0.2.1" |
| 47 | nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "b736e3038254d593024aaa1a5a7b1f95a5728538", features = ["metadata"], optional = true } | 47 | nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "477dfdbfd5e6c75c0730c56494b601c1b2257263", features = ["metadata"], optional = true } |
| 48 | proc-macro2 = "1.0.95" | 48 | proc-macro2 = "1.0.95" |
| 49 | quote = "1.0.15" | 49 | quote = "1.0.15" |
| 50 | 50 | ||
diff --git a/embassy-nxp/src/chips/lpc55.rs b/embassy-nxp/src/chips/lpc55.rs index 9f4e7269f..e9addddb6 100644 --- a/embassy-nxp/src/chips/lpc55.rs +++ b/embassy-nxp/src/chips/lpc55.rs | |||
| @@ -97,6 +97,18 @@ embassy_hal_internal::peripherals! { | |||
| 97 | DMA_CH21, | 97 | DMA_CH21, |
| 98 | DMA_CH22, | 98 | DMA_CH22, |
| 99 | 99 | ||
| 100 | // Pulse-Width Modulation Outputs. | ||
| 101 | PWM_OUTPUT0, | ||
| 102 | PWM_OUTPUT1, | ||
| 103 | PWM_OUTPUT2, | ||
| 104 | PWM_OUTPUT3, | ||
| 105 | PWM_OUTPUT4, | ||
| 106 | PWM_OUTPUT5, | ||
| 107 | PWM_OUTPUT6, | ||
| 108 | PWM_OUTPUT7, | ||
| 109 | PWM_OUTPUT8, | ||
| 110 | PWM_OUTPUT9, | ||
| 111 | |||
| 100 | // Universal Synchronous/Asynchronous Receiver/Transmitter (USART) instances. | 112 | // Universal Synchronous/Asynchronous Receiver/Transmitter (USART) instances. |
| 101 | USART0, | 113 | USART0, |
| 102 | USART1, | 114 | USART1, |
diff --git a/embassy-nxp/src/fmt.rs b/embassy-nxp/src/fmt.rs index 27d41ace6..11275235e 100644 --- a/embassy-nxp/src/fmt.rs +++ b/embassy-nxp/src/fmt.rs | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | //! Copied from embassy-rp | 1 | //! Copied from embassy-rp |
| 2 | |||
| 3 | #![macro_use] | 2 | #![macro_use] |
| 4 | #![allow(unused)] | 3 | #![allow(unused)] |
| 5 | 4 | ||
diff --git a/embassy-nxp/src/gpio/lpc55.rs b/embassy-nxp/src/gpio/lpc55.rs index ac8a27d4f..6039d8ca8 100644 --- a/embassy-nxp/src/gpio/lpc55.rs +++ b/embassy-nxp/src/gpio/lpc55.rs | |||
| @@ -1,7 +1,8 @@ | |||
| 1 | use embassy_hal_internal::{PeripheralType, impl_peripheral}; | 1 | use embassy_hal_internal::{PeripheralType, impl_peripheral}; |
| 2 | 2 | ||
| 3 | use crate::pac::common::{RW, Reg}; | ||
| 3 | use crate::pac::iocon::vals::{PioDigimode, PioMode}; | 4 | use crate::pac::iocon::vals::{PioDigimode, PioMode}; |
| 4 | use crate::pac::{GPIO, IOCON, SYSCON}; | 5 | use crate::pac::{GPIO, IOCON, SYSCON, iocon}; |
| 5 | use crate::{Peri, peripherals}; | 6 | use crate::{Peri, peripherals}; |
| 6 | 7 | ||
| 7 | pub(crate) fn init() { | 8 | pub(crate) fn init() { |
| @@ -109,13 +110,7 @@ impl<'d> Input<'d> { | |||
| 109 | 110 | ||
| 110 | /// Set the pull configuration for the pin. To disable the pull, use [Pull::None]. | 111 | /// Set the pull configuration for the pin. To disable the pull, use [Pull::None]. |
| 111 | pub fn set_pull(&mut self, pull: Pull) { | 112 | pub fn set_pull(&mut self, pull: Pull) { |
| 112 | match_iocon!(register, self.pin.pin_bank(), self.pin.pin_number(), { | 113 | self.pin.set_pull(pull); |
| 113 | register.modify(|w| match pull { | ||
| 114 | Pull::None => w.set_mode(PioMode::INACTIVE), | ||
| 115 | Pull::Up => w.set_mode(PioMode::PULL_UP), | ||
| 116 | Pull::Down => w.set_mode(PioMode::PULL_DOWN), | ||
| 117 | }); | ||
| 118 | }); | ||
| 119 | } | 114 | } |
| 120 | 115 | ||
| 121 | /// Get the current input level of the pin. | 116 | /// Get the current input level of the pin. |
| @@ -193,11 +188,20 @@ impl<'d> Flex<'d> { | |||
| 193 | 1 << self.pin.pin_number() | 188 | 1 << self.pin.pin_number() |
| 194 | } | 189 | } |
| 195 | 190 | ||
| 191 | /// Set the pull configuration for the pin. To disable the pull, use [Pull::None]. | ||
| 192 | pub fn set_pull(&mut self, pull: Pull) { | ||
| 193 | self.pin.pio().modify(|w| match pull { | ||
| 194 | Pull::None => w.set_mode(PioMode::INACTIVE), | ||
| 195 | Pull::Up => w.set_mode(PioMode::PULL_UP), | ||
| 196 | Pull::Down => w.set_mode(PioMode::PULL_DOWN), | ||
| 197 | }); | ||
| 198 | } | ||
| 199 | |||
| 196 | /// Set the pin to digital mode. This is required for using a pin as a GPIO pin. The default | 200 | /// Set the pin to digital mode. This is required for using a pin as a GPIO pin. The default |
| 197 | /// setting for pins is (usually) non-digital. | 201 | /// setting for pins is (usually) non-digital. |
| 198 | fn set_as_digital(&mut self) { | 202 | fn set_as_digital(&mut self) { |
| 199 | match_iocon!(register, self.pin_bank(), self.pin_number(), { | 203 | self.pin.pio().modify(|w| { |
| 200 | register.modify(|w| w.set_digimode(PioDigimode::DIGITAL)); | 204 | w.set_digimode(PioDigimode::DIGITAL); |
| 201 | }); | 205 | }); |
| 202 | } | 206 | } |
| 203 | 207 | ||
| @@ -220,6 +224,14 @@ impl<'d> Flex<'d> { | |||
| 220 | pub(crate) trait SealedPin: Sized { | 224 | pub(crate) trait SealedPin: Sized { |
| 221 | fn pin_bank(&self) -> Bank; | 225 | fn pin_bank(&self) -> Bank; |
| 222 | fn pin_number(&self) -> u8; | 226 | fn pin_number(&self) -> u8; |
| 227 | |||
| 228 | #[inline] | ||
| 229 | fn pio(&self) -> Reg<iocon::regs::Pio, RW> { | ||
| 230 | match self.pin_bank() { | ||
| 231 | Bank::Bank0 => IOCON.pio0(self.pin_number() as usize), | ||
| 232 | Bank::Bank1 => IOCON.pio1(self.pin_number() as usize), | ||
| 233 | } | ||
| 234 | } | ||
| 223 | } | 235 | } |
| 224 | 236 | ||
| 225 | /// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an | 237 | /// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an |
| @@ -272,40 +284,6 @@ impl SealedPin for AnyPin { | |||
| 272 | } | 284 | } |
| 273 | } | 285 | } |
| 274 | 286 | ||
| 275 | /// Match the pin bank and number of a pin to the corresponding IOCON register. | ||
| 276 | /// | ||
| 277 | /// # Example | ||
| 278 | /// ``` | ||
| 279 | /// use embassy_nxp::gpio::Bank; | ||
| 280 | /// use embassy_nxp::pac_utils::{iocon_reg, match_iocon}; | ||
| 281 | /// | ||
| 282 | /// // Make pin PIO1_6 digital and set it to pull-down mode. | ||
| 283 | /// match_iocon!(register, Bank::Bank1, 6, { | ||
| 284 | /// register.modify(|w|{ | ||
| 285 | /// w.set_mode(PioMode::PULL_DOWN); | ||
| 286 | /// w.set_digimode(PioDigimode::DIGITAL); | ||
| 287 | /// | ||
| 288 | /// } | ||
| 289 | /// }); | ||
| 290 | /// ``` | ||
| 291 | macro_rules! match_iocon { | ||
| 292 | ($register:ident, $pin_bank:expr, $pin_number:expr, $action:expr) => { | ||
| 293 | match $pin_bank { | ||
| 294 | Bank::Bank0 => { | ||
| 295 | let $register = IOCON.pio0($pin_number as usize); | ||
| 296 | $action; | ||
| 297 | } | ||
| 298 | |||
| 299 | Bank::Bank1 => { | ||
| 300 | let $register = IOCON.pio1($pin_number as usize); | ||
| 301 | $action; | ||
| 302 | } | ||
| 303 | } | ||
| 304 | }; | ||
| 305 | } | ||
| 306 | |||
| 307 | pub(crate) use match_iocon; | ||
| 308 | |||
| 309 | macro_rules! impl_pin { | 287 | macro_rules! impl_pin { |
| 310 | ($name:ident, $bank:expr, $pin_num:expr) => { | 288 | ($name:ident, $bank:expr, $pin_num:expr) => { |
| 311 | impl Pin for peripherals::$name {} | 289 | impl Pin for peripherals::$name {} |
diff --git a/embassy-nxp/src/lib.rs b/embassy-nxp/src/lib.rs index 9576f02b1..4058881a5 100644 --- a/embassy-nxp/src/lib.rs +++ b/embassy-nxp/src/lib.rs | |||
| @@ -10,6 +10,8 @@ pub mod gpio; | |||
| 10 | #[cfg(feature = "lpc55-core0")] | 10 | #[cfg(feature = "lpc55-core0")] |
| 11 | pub mod pint; | 11 | pub mod pint; |
| 12 | #[cfg(feature = "lpc55-core0")] | 12 | #[cfg(feature = "lpc55-core0")] |
| 13 | pub mod pwm; | ||
| 14 | #[cfg(feature = "lpc55-core0")] | ||
| 13 | pub mod usart; | 15 | pub mod usart; |
| 14 | 16 | ||
| 15 | #[cfg(feature = "_time_driver")] | 17 | #[cfg(feature = "_time_driver")] |
| @@ -154,7 +156,10 @@ pub fn init(_config: config::Config) -> Peripherals { | |||
| 154 | gpio::init(); | 156 | gpio::init(); |
| 155 | 157 | ||
| 156 | #[cfg(feature = "lpc55-core0")] | 158 | #[cfg(feature = "lpc55-core0")] |
| 157 | pint::init(); | 159 | { |
| 160 | pint::init(); | ||
| 161 | pwm::Pwm::reset(); | ||
| 162 | } | ||
| 158 | 163 | ||
| 159 | #[cfg(feature = "_time_driver")] | 164 | #[cfg(feature = "_time_driver")] |
| 160 | time_driver::init(); | 165 | time_driver::init(); |
diff --git a/embassy-nxp/src/pwm.rs b/embassy-nxp/src/pwm.rs new file mode 100644 index 000000000..68980924a --- /dev/null +++ b/embassy-nxp/src/pwm.rs | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | //! Pulse-Width Modulation (PWM) driver. | ||
| 2 | |||
| 3 | #[cfg_attr(feature = "lpc55-core0", path = "./pwm/lpc55.rs")] | ||
| 4 | mod inner; | ||
| 5 | pub use inner::*; | ||
diff --git a/embassy-nxp/src/pwm/lpc55.rs b/embassy-nxp/src/pwm/lpc55.rs new file mode 100644 index 000000000..197184ad6 --- /dev/null +++ b/embassy-nxp/src/pwm/lpc55.rs | |||
| @@ -0,0 +1,325 @@ | |||
| 1 | use core::sync::atomic::{AtomicU8, AtomicU32, Ordering}; | ||
| 2 | |||
| 3 | use embassy_hal_internal::{Peri, PeripheralType}; | ||
| 4 | |||
| 5 | use crate::gpio::AnyPin; | ||
| 6 | use crate::pac::iocon::vals::{PioDigimode, PioFunc, PioMode, PioOd, PioSlew}; | ||
| 7 | use crate::pac::sct0::vals; | ||
| 8 | use crate::pac::syscon::vals::{SctRst, SctclkselSel}; | ||
| 9 | use crate::pac::{SCT0, SYSCON}; | ||
| 10 | |||
| 11 | // Since for now the counter is shared, the TOP value has to be kept. | ||
| 12 | static TOP_VALUE: AtomicU32 = AtomicU32::new(0); | ||
| 13 | // To check if there are still active instances. | ||
| 14 | static REF_COUNT: AtomicU8 = AtomicU8::new(0); | ||
| 15 | |||
| 16 | /// The configuration of a PWM output. | ||
| 17 | /// Note the period in clock cycles of an output can be computed as: | ||
| 18 | /// `(top + 1) * (phase_correct ? 1 : 2) * divider * prescale_factor` | ||
| 19 | /// By default, the clock used is 96 MHz. | ||
| 20 | #[non_exhaustive] | ||
| 21 | #[derive(Clone)] | ||
| 22 | pub struct Config { | ||
| 23 | /// Inverts the PWM output signal. | ||
| 24 | pub invert: bool, | ||
| 25 | /// Enables phase-correct mode for PWM operation. | ||
| 26 | /// In phase-correct mode, the PWM signal is generated in such a way that | ||
| 27 | /// the pulse is always centered regardless of the duty cycle. | ||
| 28 | /// The output frequency is halved when phase-correct mode is enabled. | ||
| 29 | pub phase_correct: bool, | ||
| 30 | /// Enables the PWM output, allowing it to generate an output. | ||
| 31 | pub enable: bool, | ||
| 32 | /// A SYSCON clock divider allows precise control over | ||
| 33 | /// the PWM output frequency by gating the PWM counter increment. | ||
| 34 | /// A higher value will result in a slower output frequency. | ||
| 35 | /// The clock is divided by `divider + 1`. | ||
| 36 | pub divider: u8, | ||
| 37 | /// Specifies the factor by which the SCT clock is prescaled to produce the unified | ||
| 38 | /// counter clock. The counter clock is clocked at the rate of the SCT clock divided by | ||
| 39 | /// `PRE + 1`. | ||
| 40 | pub prescale_factor: u8, | ||
| 41 | /// The output goes high when `compare` is higher than the | ||
| 42 | /// counter. A compare of 0 will produce an always low output, while a | ||
| 43 | /// compare of `top` will produce an always high output. | ||
| 44 | pub compare: u32, | ||
| 45 | /// The point at which the counter resets, representing the maximum possible | ||
| 46 | /// period. The counter will either wrap to 0 or reverse depending on the | ||
| 47 | /// setting of `phase_correct`. | ||
| 48 | pub top: u32, | ||
| 49 | } | ||
| 50 | |||
| 51 | impl Config { | ||
| 52 | pub fn new(compare: u32, top: u32) -> Self { | ||
| 53 | Self { | ||
| 54 | invert: false, | ||
| 55 | phase_correct: false, | ||
| 56 | enable: true, | ||
| 57 | divider: 255, | ||
| 58 | prescale_factor: 255, | ||
| 59 | compare, | ||
| 60 | top, | ||
| 61 | } | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | /// PWM driver. | ||
| 66 | pub struct Pwm<'d> { | ||
| 67 | _pin: Peri<'d, AnyPin>, | ||
| 68 | output: usize, | ||
| 69 | } | ||
| 70 | |||
| 71 | impl<'d> Pwm<'d> { | ||
| 72 | pub(crate) fn reset() { | ||
| 73 | // Reset SCTimer => Reset counter and halt it. | ||
| 74 | // It should be done only once during the initialization of the board. | ||
| 75 | SYSCON.presetctrl1().modify(|w| w.set_sct_rst(SctRst::ASSERTED)); | ||
| 76 | SYSCON.presetctrl1().modify(|w| w.set_sct_rst(SctRst::RELEASED)); | ||
| 77 | } | ||
| 78 | fn new_inner<T: Output>(output: usize, channel: Peri<'d, impl OutputChannelPin<T>>, config: Config) -> Self { | ||
| 79 | // Enable clocks (Syscon is enabled by default) | ||
| 80 | critical_section::with(|_cs| { | ||
| 81 | if !SYSCON.ahbclkctrl0().read().iocon() { | ||
| 82 | SYSCON.ahbclkctrl0().modify(|w| w.set_iocon(true)); | ||
| 83 | } | ||
| 84 | if !SYSCON.ahbclkctrl1().read().sct() { | ||
| 85 | SYSCON.ahbclkctrl1().modify(|w| w.set_sct(true)); | ||
| 86 | } | ||
| 87 | }); | ||
| 88 | |||
| 89 | // Choose the clock for PWM. | ||
| 90 | SYSCON.sctclksel().modify(|w| w.set_sel(SctclkselSel::ENUM_0X3)); | ||
| 91 | // For now, 96 MHz. | ||
| 92 | |||
| 93 | // IOCON Setup | ||
| 94 | channel.pio().modify(|w| { | ||
| 95 | w.set_func(channel.pin_func()); | ||
| 96 | w.set_digimode(PioDigimode::DIGITAL); | ||
| 97 | w.set_slew(PioSlew::STANDARD); | ||
| 98 | w.set_mode(PioMode::INACTIVE); | ||
| 99 | w.set_od(PioOd::NORMAL); | ||
| 100 | }); | ||
| 101 | |||
| 102 | Self::configure(output, &config); | ||
| 103 | REF_COUNT.fetch_add(1, Ordering::Relaxed); | ||
| 104 | Self { | ||
| 105 | _pin: channel.into(), | ||
| 106 | output, | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | /// Create PWM driver with a single 'a' pin as output. | ||
| 111 | #[inline] | ||
| 112 | pub fn new_output<T: Output>( | ||
| 113 | output: Peri<'d, T>, | ||
| 114 | channel: Peri<'d, impl OutputChannelPin<T>>, | ||
| 115 | config: Config, | ||
| 116 | ) -> Self { | ||
| 117 | Self::new_inner(output.number(), channel, config) | ||
| 118 | } | ||
| 119 | |||
| 120 | /// Set the PWM config. | ||
| 121 | pub fn set_config(&mut self, config: &Config) { | ||
| 122 | Self::configure(self.output, config); | ||
| 123 | } | ||
| 124 | |||
| 125 | fn configure(output_number: usize, config: &Config) { | ||
| 126 | // Stop and reset the counter | ||
| 127 | SCT0.ctrl().modify(|w| { | ||
| 128 | if config.phase_correct { | ||
| 129 | w.set_bidir_l(vals::Bidir::UP_DOWN); | ||
| 130 | } else { | ||
| 131 | w.set_bidir_l(vals::Bidir::UP); | ||
| 132 | } | ||
| 133 | w.set_halt_l(true); // halt the counter to make new changes | ||
| 134 | w.set_clrctr_l(true); // clear the counter | ||
| 135 | }); | ||
| 136 | // Divides clock by 1-255 | ||
| 137 | SYSCON.sctclkdiv().modify(|w| w.set_div(config.divider)); | ||
| 138 | |||
| 139 | SCT0.config().modify(|w| { | ||
| 140 | w.set_unify(vals::Unify::UNIFIED_COUNTER); | ||
| 141 | w.set_clkmode(vals::Clkmode::SYSTEM_CLOCK_MODE); | ||
| 142 | w.set_noreload_l(true); | ||
| 143 | w.set_autolimit_l(true); | ||
| 144 | }); | ||
| 145 | |||
| 146 | // Before setting the match registers, we have to make sure that `compare` is lower or equal to `top`, | ||
| 147 | // otherwise the counter will not reach the match and, therefore, no events will happen. | ||
| 148 | assert!(config.compare <= config.top); | ||
| 149 | |||
| 150 | if TOP_VALUE.load(Ordering::Relaxed) == 0 { | ||
| 151 | // Match 0 will reset the timer using TOP value | ||
| 152 | SCT0.match_(0).modify(|w| { | ||
| 153 | w.set_matchn_l((config.top & 0xFFFF) as u16); | ||
| 154 | w.set_matchn_h((config.top >> 16) as u16); | ||
| 155 | }); | ||
| 156 | } else { | ||
| 157 | panic!("The top value cannot be changed after the initialization."); | ||
| 158 | } | ||
| 159 | // The actual matches that are used for event logic | ||
| 160 | SCT0.match_(output_number + 1).modify(|w| { | ||
| 161 | w.set_matchn_l((config.compare & 0xFFFF) as u16); | ||
| 162 | w.set_matchn_h((config.compare >> 16) as u16); | ||
| 163 | }); | ||
| 164 | |||
| 165 | SCT0.match_(15).modify(|w| { | ||
| 166 | w.set_matchn_l(0); | ||
| 167 | w.set_matchn_h(0); | ||
| 168 | }); | ||
| 169 | |||
| 170 | // Event configuration | ||
| 171 | critical_section::with(|_cs| { | ||
| 172 | // If it is already set, don't change | ||
| 173 | if SCT0.ev(0).ev_ctrl().read().matchsel() != 15 { | ||
| 174 | SCT0.ev(0).ev_ctrl().modify(|w| { | ||
| 175 | w.set_matchsel(15); | ||
| 176 | w.set_combmode(vals::Combmode::MATCH); | ||
| 177 | // STATE + statev, where STATE is a on-board variable. | ||
| 178 | w.set_stateld(vals::Stateld::ADD); | ||
| 179 | w.set_statev(0); | ||
| 180 | }); | ||
| 181 | } | ||
| 182 | }); | ||
| 183 | SCT0.ev(output_number + 1).ev_ctrl().modify(|w| { | ||
| 184 | w.set_matchsel((output_number + 1) as u8); | ||
| 185 | w.set_combmode(vals::Combmode::MATCH); | ||
| 186 | w.set_stateld(vals::Stateld::ADD); | ||
| 187 | // STATE + statev, where STATE is a on-board variable. | ||
| 188 | w.set_statev(0); | ||
| 189 | }); | ||
| 190 | |||
| 191 | // Assign events to states | ||
| 192 | SCT0.ev(0).ev_state().modify(|w| w.set_statemskn(1 << 0)); | ||
| 193 | SCT0.ev(output_number + 1) | ||
| 194 | .ev_state() | ||
| 195 | .modify(|w| w.set_statemskn(1 << 0)); | ||
| 196 | // TODO(frihetselsker): optimize nxp-pac so that `set_clr` and `set_set` are turned into a bit array. | ||
| 197 | if config.invert { | ||
| 198 | // Low when event 0 is active | ||
| 199 | SCT0.out(output_number).out_clr().modify(|w| w.set_clr(1 << 0)); | ||
| 200 | // High when event `output_number + 1` is active | ||
| 201 | SCT0.out(output_number) | ||
| 202 | .out_set() | ||
| 203 | .modify(|w| w.set_set(1 << (output_number + 1))); | ||
| 204 | } else { | ||
| 205 | // High when event 0 is active | ||
| 206 | SCT0.out(output_number).out_set().modify(|w| w.set_set(1 << 0)); | ||
| 207 | // Low when event `output_number + 1` is active | ||
| 208 | SCT0.out(output_number) | ||
| 209 | .out_clr() | ||
| 210 | .modify(|w| w.set_clr(1 << (output_number + 1))); | ||
| 211 | } | ||
| 212 | |||
| 213 | if config.phase_correct { | ||
| 214 | // Take into account the set matches and reverse their actions while counting back. | ||
| 215 | SCT0.outputdirctrl() | ||
| 216 | .modify(|w| w.set_setclr(output_number, vals::Setclr::L_REVERSED)); | ||
| 217 | } | ||
| 218 | |||
| 219 | // State 0 by default | ||
| 220 | SCT0.state().modify(|w| w.set_state_l(0)); | ||
| 221 | // Remove halt and start the actual counter | ||
| 222 | SCT0.ctrl().modify(|w| { | ||
| 223 | w.set_halt_l(!config.enable); | ||
| 224 | }); | ||
| 225 | } | ||
| 226 | |||
| 227 | /// Read PWM counter. | ||
| 228 | #[inline] | ||
| 229 | pub fn counter(&self) -> u32 { | ||
| 230 | SCT0.count().read().0 | ||
| 231 | } | ||
| 232 | } | ||
| 233 | |||
| 234 | impl<'d> Drop for Pwm<'d> { | ||
| 235 | fn drop(&mut self) { | ||
| 236 | REF_COUNT.fetch_sub(1, Ordering::AcqRel); | ||
| 237 | if REF_COUNT.load(Ordering::Acquire) == 0 { | ||
| 238 | TOP_VALUE.store(0, Ordering::Release); | ||
| 239 | } | ||
| 240 | } | ||
| 241 | } | ||
| 242 | |||
| 243 | trait SealedOutput { | ||
| 244 | /// Output number. | ||
| 245 | fn number(&self) -> usize; | ||
| 246 | } | ||
| 247 | |||
| 248 | /// PWM Output. | ||
| 249 | #[allow(private_bounds)] | ||
| 250 | pub trait Output: PeripheralType + SealedOutput {} | ||
| 251 | |||
| 252 | macro_rules! output { | ||
| 253 | ($name:ident, $num:expr) => { | ||
| 254 | impl SealedOutput for crate::peripherals::$name { | ||
| 255 | fn number(&self) -> usize { | ||
| 256 | $num | ||
| 257 | } | ||
| 258 | } | ||
| 259 | impl Output for crate::peripherals::$name {} | ||
| 260 | }; | ||
| 261 | } | ||
| 262 | |||
| 263 | output!(PWM_OUTPUT0, 0); | ||
| 264 | output!(PWM_OUTPUT1, 1); | ||
| 265 | output!(PWM_OUTPUT2, 2); | ||
| 266 | output!(PWM_OUTPUT3, 3); | ||
| 267 | output!(PWM_OUTPUT4, 4); | ||
| 268 | output!(PWM_OUTPUT5, 5); | ||
| 269 | output!(PWM_OUTPUT6, 6); | ||
| 270 | output!(PWM_OUTPUT7, 7); | ||
| 271 | output!(PWM_OUTPUT8, 8); | ||
| 272 | output!(PWM_OUTPUT9, 9); | ||
| 273 | |||
| 274 | /// PWM Output Channel. | ||
| 275 | pub trait OutputChannelPin<T: Output>: crate::gpio::Pin { | ||
| 276 | fn pin_func(&self) -> PioFunc; | ||
| 277 | } | ||
| 278 | |||
| 279 | macro_rules! impl_pin { | ||
| 280 | ($pin:ident, $output:ident, $func:ident) => { | ||
| 281 | impl crate::pwm::inner::OutputChannelPin<crate::peripherals::$output> for crate::peripherals::$pin { | ||
| 282 | fn pin_func(&self) -> PioFunc { | ||
| 283 | PioFunc::$func | ||
| 284 | } | ||
| 285 | } | ||
| 286 | }; | ||
| 287 | } | ||
| 288 | |||
| 289 | impl_pin!(PIO0_2, PWM_OUTPUT0, ALT3); | ||
| 290 | impl_pin!(PIO0_17, PWM_OUTPUT0, ALT4); | ||
| 291 | impl_pin!(PIO1_4, PWM_OUTPUT0, ALT4); | ||
| 292 | impl_pin!(PIO1_23, PWM_OUTPUT0, ALT2); | ||
| 293 | |||
| 294 | impl_pin!(PIO0_3, PWM_OUTPUT1, ALT3); | ||
| 295 | impl_pin!(PIO0_18, PWM_OUTPUT1, ALT4); | ||
| 296 | impl_pin!(PIO1_8, PWM_OUTPUT1, ALT4); | ||
| 297 | impl_pin!(PIO1_24, PWM_OUTPUT1, ALT2); | ||
| 298 | |||
| 299 | impl_pin!(PIO0_10, PWM_OUTPUT2, ALT5); | ||
| 300 | impl_pin!(PIO0_15, PWM_OUTPUT2, ALT4); | ||
| 301 | impl_pin!(PIO0_19, PWM_OUTPUT2, ALT4); | ||
| 302 | impl_pin!(PIO1_9, PWM_OUTPUT2, ALT4); | ||
| 303 | impl_pin!(PIO1_25, PWM_OUTPUT2, ALT2); | ||
| 304 | |||
| 305 | impl_pin!(PIO0_22, PWM_OUTPUT3, ALT4); | ||
| 306 | impl_pin!(PIO0_31, PWM_OUTPUT3, ALT4); | ||
| 307 | impl_pin!(PIO1_10, PWM_OUTPUT3, ALT4); | ||
| 308 | impl_pin!(PIO1_26, PWM_OUTPUT3, ALT2); | ||
| 309 | |||
| 310 | impl_pin!(PIO0_23, PWM_OUTPUT4, ALT4); | ||
| 311 | impl_pin!(PIO1_3, PWM_OUTPUT4, ALT4); | ||
| 312 | impl_pin!(PIO1_17, PWM_OUTPUT4, ALT4); | ||
| 313 | |||
| 314 | impl_pin!(PIO0_26, PWM_OUTPUT5, ALT4); | ||
| 315 | impl_pin!(PIO1_18, PWM_OUTPUT5, ALT4); | ||
| 316 | |||
| 317 | impl_pin!(PIO0_27, PWM_OUTPUT6, ALT4); | ||
| 318 | impl_pin!(PIO1_31, PWM_OUTPUT6, ALT4); | ||
| 319 | |||
| 320 | impl_pin!(PIO0_28, PWM_OUTPUT7, ALT4); | ||
| 321 | impl_pin!(PIO1_19, PWM_OUTPUT7, ALT2); | ||
| 322 | |||
| 323 | impl_pin!(PIO0_29, PWM_OUTPUT8, ALT4); | ||
| 324 | |||
| 325 | impl_pin!(PIO0_30, PWM_OUTPUT9, ALT4); | ||
diff --git a/embassy-nxp/src/usart/lpc55.rs b/embassy-nxp/src/usart/lpc55.rs index 0be5a8ce7..d54927b25 100644 --- a/embassy-nxp/src/usart/lpc55.rs +++ b/embassy-nxp/src/usart/lpc55.rs | |||
| @@ -11,7 +11,7 @@ use embassy_sync::waitqueue::AtomicWaker; | |||
| 11 | use embedded_io::{self, ErrorKind}; | 11 | use embedded_io::{self, ErrorKind}; |
| 12 | 12 | ||
| 13 | use crate::dma::{AnyChannel, Channel}; | 13 | use crate::dma::{AnyChannel, Channel}; |
| 14 | use crate::gpio::{AnyPin, Bank, SealedPin, match_iocon}; | 14 | use crate::gpio::{AnyPin, SealedPin}; |
| 15 | use crate::interrupt::Interrupt; | 15 | use crate::interrupt::Interrupt; |
| 16 | use crate::interrupt::typelevel::{Binding, Interrupt as _}; | 16 | use crate::interrupt::typelevel::{Binding, Interrupt as _}; |
| 17 | use crate::pac::flexcomm::Flexcomm as FlexcommReg; | 17 | use crate::pac::flexcomm::Flexcomm as FlexcommReg; |
| @@ -146,7 +146,8 @@ impl<'d, M: Mode> UsartTx<'d, M> { | |||
| 146 | tx_dma: Peri<'d, impl Channel>, | 146 | tx_dma: Peri<'d, impl Channel>, |
| 147 | config: Config, | 147 | config: Config, |
| 148 | ) -> Self { | 148 | ) -> Self { |
| 149 | Usart::<M>::init::<T>(Some(tx.into()), None, config); | 149 | let tx_func = tx.pin_func(); |
| 150 | Usart::<M>::init::<T>(Some((tx.into(), tx_func)), None, config); | ||
| 150 | Self::new_inner(T::info(), Some(tx_dma.into())) | 151 | Self::new_inner(T::info(), Some(tx_dma.into())) |
| 151 | } | 152 | } |
| 152 | 153 | ||
| @@ -179,7 +180,8 @@ impl<'d, M: Mode> UsartTx<'d, M> { | |||
| 179 | 180 | ||
| 180 | impl<'d> UsartTx<'d, Blocking> { | 181 | impl<'d> UsartTx<'d, Blocking> { |
| 181 | pub fn new_blocking<T: Instance>(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self { | 182 | pub fn new_blocking<T: Instance>(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self { |
| 182 | Usart::<Blocking>::init::<T>(Some(tx.into()), None, config); | 183 | let tx_func = tx.pin_func(); |
| 184 | Usart::<Blocking>::init::<T>(Some((tx.into(), tx_func)), None, config); | ||
| 183 | Self::new_inner(T::info(), None) | 185 | Self::new_inner(T::info(), None) |
| 184 | } | 186 | } |
| 185 | } | 187 | } |
| @@ -208,7 +210,8 @@ impl<'d, M: Mode> UsartRx<'d, M> { | |||
| 208 | rx_dma: Peri<'d, impl Channel>, | 210 | rx_dma: Peri<'d, impl Channel>, |
| 209 | config: Config, | 211 | config: Config, |
| 210 | ) -> Self { | 212 | ) -> Self { |
| 211 | Usart::<M>::init::<T>(None, Some(rx.into()), config); | 213 | let rx_func = rx.pin_func(); |
| 214 | Usart::<M>::init::<T>(None, Some((rx.into(), rx_func)), config); | ||
| 212 | Self::new_inner(T::info(), T::dma_state(), has_irq, Some(rx_dma.into())) | 215 | Self::new_inner(T::info(), T::dma_state(), has_irq, Some(rx_dma.into())) |
| 213 | } | 216 | } |
| 214 | 217 | ||
| @@ -280,7 +283,8 @@ impl<'d, M: Mode> UsartRx<'d, M> { | |||
| 280 | 283 | ||
| 281 | impl<'d> UsartRx<'d, Blocking> { | 284 | impl<'d> UsartRx<'d, Blocking> { |
| 282 | pub fn new_blocking<T: Instance>(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self { | 285 | pub fn new_blocking<T: Instance>(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self { |
| 283 | Usart::<Blocking>::init::<T>(None, Some(rx.into()), config); | 286 | let rx_func = rx.pin_func(); |
| 287 | Usart::<Blocking>::init::<T>(None, Some((rx.into(), rx_func)), config); | ||
| 284 | Self::new_inner(T::info(), T::dma_state(), false, None) | 288 | Self::new_inner(T::info(), T::dma_state(), false, None) |
| 285 | } | 289 | } |
| 286 | } | 290 | } |
| @@ -405,7 +409,10 @@ impl<'d> Usart<'d, Blocking> { | |||
| 405 | rx: Peri<'d, impl RxPin<T>>, | 409 | rx: Peri<'d, impl RxPin<T>>, |
| 406 | config: Config, | 410 | config: Config, |
| 407 | ) -> Self { | 411 | ) -> Self { |
| 408 | Self::new_inner(usart, tx.into(), rx.into(), false, None, None, config) | 412 | let tx_func = tx.pin_func(); |
| 413 | let rx_func = rx.pin_func(); | ||
| 414 | |||
| 415 | Self::new_inner(usart, tx.into(), tx_func, rx.into(), rx_func, false, None, None, config) | ||
| 409 | } | 416 | } |
| 410 | } | 417 | } |
| 411 | 418 | ||
| @@ -419,10 +426,15 @@ impl<'d> Usart<'d, Async> { | |||
| 419 | rx_dma: Peri<'d, impl RxChannel<T>>, | 426 | rx_dma: Peri<'d, impl RxChannel<T>>, |
| 420 | config: Config, | 427 | config: Config, |
| 421 | ) -> Self { | 428 | ) -> Self { |
| 429 | let tx_func = tx.pin_func(); | ||
| 430 | let rx_func = rx.pin_func(); | ||
| 431 | |||
| 422 | Self::new_inner( | 432 | Self::new_inner( |
| 423 | uart, | 433 | uart, |
| 424 | tx.into(), | 434 | tx.into(), |
| 435 | tx_func, | ||
| 425 | rx.into(), | 436 | rx.into(), |
| 437 | rx_func, | ||
| 426 | true, | 438 | true, |
| 427 | Some(tx_dma.into()), | 439 | Some(tx_dma.into()), |
| 428 | Some(rx_dma.into()), | 440 | Some(rx_dma.into()), |
| @@ -435,20 +447,26 @@ impl<'d, M: Mode> Usart<'d, M> { | |||
| 435 | fn new_inner<T: Instance>( | 447 | fn new_inner<T: Instance>( |
| 436 | _usart: Peri<'d, T>, | 448 | _usart: Peri<'d, T>, |
| 437 | mut tx: Peri<'d, AnyPin>, | 449 | mut tx: Peri<'d, AnyPin>, |
| 450 | tx_func: PioFunc, | ||
| 438 | mut rx: Peri<'d, AnyPin>, | 451 | mut rx: Peri<'d, AnyPin>, |
| 452 | rx_func: PioFunc, | ||
| 439 | has_irq: bool, | 453 | has_irq: bool, |
| 440 | tx_dma: Option<Peri<'d, AnyChannel>>, | 454 | tx_dma: Option<Peri<'d, AnyChannel>>, |
| 441 | rx_dma: Option<Peri<'d, AnyChannel>>, | 455 | rx_dma: Option<Peri<'d, AnyChannel>>, |
| 442 | config: Config, | 456 | config: Config, |
| 443 | ) -> Self { | 457 | ) -> Self { |
| 444 | Self::init::<T>(Some(tx.reborrow()), Some(rx.reborrow()), config); | 458 | Self::init::<T>(Some((tx.reborrow(), tx_func)), Some((rx.reborrow(), rx_func)), config); |
| 445 | Self { | 459 | Self { |
| 446 | tx: UsartTx::new_inner(T::info(), tx_dma), | 460 | tx: UsartTx::new_inner(T::info(), tx_dma), |
| 447 | rx: UsartRx::new_inner(T::info(), T::dma_state(), has_irq, rx_dma), | 461 | rx: UsartRx::new_inner(T::info(), T::dma_state(), has_irq, rx_dma), |
| 448 | } | 462 | } |
| 449 | } | 463 | } |
| 450 | 464 | ||
| 451 | fn init<T: Instance>(tx: Option<Peri<'_, AnyPin>>, rx: Option<Peri<'_, AnyPin>>, config: Config) { | 465 | fn init<T: Instance>( |
| 466 | tx: Option<(Peri<'_, AnyPin>, PioFunc)>, | ||
| 467 | rx: Option<(Peri<'_, AnyPin>, PioFunc)>, | ||
| 468 | config: Config, | ||
| 469 | ) { | ||
| 452 | Self::configure_flexcomm(T::info().fc_reg, T::instance_number()); | 470 | Self::configure_flexcomm(T::info().fc_reg, T::instance_number()); |
| 453 | Self::configure_clock::<T>(&config); | 471 | Self::configure_clock::<T>(&config); |
| 454 | Self::pin_config::<T>(tx, rx); | 472 | Self::pin_config::<T>(tx, rx); |
| @@ -553,31 +571,27 @@ impl<'d, M: Mode> Usart<'d, M> { | |||
| 553 | .modify(|w| w.set_brgval((brg_value - 1) as u16)); | 571 | .modify(|w| w.set_brgval((brg_value - 1) as u16)); |
| 554 | } | 572 | } |
| 555 | 573 | ||
| 556 | fn pin_config<T: Instance>(tx: Option<Peri<'_, AnyPin>>, rx: Option<Peri<'_, AnyPin>>) { | 574 | fn pin_config<T: Instance>(tx: Option<(Peri<'_, AnyPin>, PioFunc)>, rx: Option<(Peri<'_, AnyPin>, PioFunc)>) { |
| 557 | if let Some(tx_pin) = tx { | 575 | if let Some((tx_pin, func)) = tx { |
| 558 | match_iocon!(register, tx_pin.pin_bank(), tx_pin.pin_number(), { | 576 | tx_pin.pio().modify(|w| { |
| 559 | register.modify(|w| { | 577 | w.set_func(func); |
| 560 | w.set_func(T::tx_pin_func()); | 578 | w.set_mode(iocon::vals::PioMode::INACTIVE); |
| 561 | w.set_mode(iocon::vals::PioMode::INACTIVE); | 579 | w.set_slew(iocon::vals::PioSlew::STANDARD); |
| 562 | w.set_slew(iocon::vals::PioSlew::STANDARD); | 580 | w.set_invert(false); |
| 563 | w.set_invert(false); | 581 | w.set_digimode(iocon::vals::PioDigimode::DIGITAL); |
| 564 | w.set_digimode(iocon::vals::PioDigimode::DIGITAL); | 582 | w.set_od(iocon::vals::PioOd::NORMAL); |
| 565 | w.set_od(iocon::vals::PioOd::NORMAL); | 583 | }); |
| 566 | }); | ||
| 567 | }) | ||
| 568 | } | 584 | } |
| 569 | 585 | ||
| 570 | if let Some(rx_pin) = rx { | 586 | if let Some((rx_pin, func)) = rx { |
| 571 | match_iocon!(register, rx_pin.pin_bank(), rx_pin.pin_number(), { | 587 | rx_pin.pio().modify(|w| { |
| 572 | register.modify(|w| { | 588 | w.set_func(func); |
| 573 | w.set_func(T::rx_pin_func()); | 589 | w.set_mode(iocon::vals::PioMode::INACTIVE); |
| 574 | w.set_mode(iocon::vals::PioMode::INACTIVE); | 590 | w.set_slew(iocon::vals::PioSlew::STANDARD); |
| 575 | w.set_slew(iocon::vals::PioSlew::STANDARD); | 591 | w.set_invert(false); |
| 576 | w.set_invert(false); | 592 | w.set_digimode(iocon::vals::PioDigimode::DIGITAL); |
| 577 | w.set_digimode(iocon::vals::PioDigimode::DIGITAL); | 593 | w.set_od(iocon::vals::PioOd::NORMAL); |
| 578 | w.set_od(iocon::vals::PioOd::NORMAL); | 594 | }); |
| 579 | }); | ||
| 580 | }) | ||
| 581 | }; | 595 | }; |
| 582 | } | 596 | } |
| 583 | 597 | ||
| @@ -814,8 +828,6 @@ trait SealedInstance { | |||
| 814 | fn info() -> &'static Info; | 828 | fn info() -> &'static Info; |
| 815 | fn dma_state() -> &'static DmaState; | 829 | fn dma_state() -> &'static DmaState; |
| 816 | fn instance_number() -> usize; | 830 | fn instance_number() -> usize; |
| 817 | fn tx_pin_func() -> PioFunc; | ||
| 818 | fn rx_pin_func() -> PioFunc; | ||
| 819 | } | 831 | } |
| 820 | 832 | ||
| 821 | /// UART instance. | 833 | /// UART instance. |
| @@ -826,7 +838,7 @@ pub trait Instance: SealedInstance + PeripheralType { | |||
| 826 | } | 838 | } |
| 827 | 839 | ||
| 828 | macro_rules! impl_instance { | 840 | macro_rules! impl_instance { |
| 829 | ($inst:ident, $fc:ident, $tx_pin:ident, $rx_pin:ident, $fc_num:expr) => { | 841 | ($inst:ident, $fc:ident, $fc_num:expr) => { |
| 830 | impl $crate::usart::inner::SealedInstance for $crate::peripherals::$inst { | 842 | impl $crate::usart::inner::SealedInstance for $crate::peripherals::$inst { |
| 831 | fn info() -> &'static Info { | 843 | fn info() -> &'static Info { |
| 832 | static INFO: Info = Info { | 844 | static INFO: Info = Info { |
| @@ -848,14 +860,6 @@ macro_rules! impl_instance { | |||
| 848 | fn instance_number() -> usize { | 860 | fn instance_number() -> usize { |
| 849 | $fc_num | 861 | $fc_num |
| 850 | } | 862 | } |
| 851 | #[inline] | ||
| 852 | fn tx_pin_func() -> PioFunc { | ||
| 853 | PioFunc::$tx_pin | ||
| 854 | } | ||
| 855 | #[inline] | ||
| 856 | fn rx_pin_func() -> PioFunc { | ||
| 857 | PioFunc::$rx_pin | ||
| 858 | } | ||
| 859 | } | 863 | } |
| 860 | impl $crate::usart::Instance for $crate::peripherals::$inst { | 864 | impl $crate::usart::Instance for $crate::peripherals::$inst { |
| 861 | type Interrupt = crate::interrupt::typelevel::$fc; | 865 | type Interrupt = crate::interrupt::typelevel::$fc; |
| @@ -863,45 +867,72 @@ macro_rules! impl_instance { | |||
| 863 | }; | 867 | }; |
| 864 | } | 868 | } |
| 865 | 869 | ||
| 866 | impl_instance!(USART0, FLEXCOMM0, ALT1, ALT1, 0); | 870 | impl_instance!(USART0, FLEXCOMM0, 0); |
| 867 | impl_instance!(USART1, FLEXCOMM1, ALT2, ALT2, 1); | 871 | impl_instance!(USART1, FLEXCOMM1, 1); |
| 868 | impl_instance!(USART2, FLEXCOMM2, ALT1, ALT1, 2); | 872 | impl_instance!(USART2, FLEXCOMM2, 2); |
| 869 | impl_instance!(USART3, FLEXCOMM3, ALT1, ALT1, 3); | 873 | impl_instance!(USART3, FLEXCOMM3, 3); |
| 870 | impl_instance!(USART4, FLEXCOMM4, ALT1, ALT2, 4); | 874 | impl_instance!(USART4, FLEXCOMM4, 4); |
| 871 | impl_instance!(USART5, FLEXCOMM5, ALT3, ALT3, 5); | 875 | impl_instance!(USART5, FLEXCOMM5, 5); |
| 872 | impl_instance!(USART6, FLEXCOMM6, ALT2, ALT2, 6); | 876 | impl_instance!(USART6, FLEXCOMM6, 6); |
| 873 | impl_instance!(USART7, FLEXCOMM7, ALT7, ALT7, 7); | 877 | impl_instance!(USART7, FLEXCOMM7, 7); |
| 878 | |||
| 879 | pub(crate) trait SealedTxPin<T: Instance>: crate::gpio::Pin { | ||
| 880 | fn pin_func(&self) -> PioFunc; | ||
| 881 | } | ||
| 882 | |||
| 883 | pub(crate) trait SealedRxPin<T: Instance>: crate::gpio::Pin { | ||
| 884 | fn pin_func(&self) -> PioFunc; | ||
| 885 | } | ||
| 874 | 886 | ||
| 875 | /// Trait for TX pins. | 887 | /// Trait for TX pins. |
| 876 | pub trait TxPin<T: Instance>: crate::gpio::Pin {} | 888 | #[allow(private_bounds)] |
| 889 | pub trait TxPin<T: Instance>: SealedTxPin<T> + crate::gpio::Pin {} | ||
| 890 | |||
| 877 | /// Trait for RX pins. | 891 | /// Trait for RX pins. |
| 878 | pub trait RxPin<T: Instance>: crate::gpio::Pin {} | 892 | #[allow(private_bounds)] |
| 893 | pub trait RxPin<T: Instance>: SealedRxPin<T> + crate::gpio::Pin {} | ||
| 894 | |||
| 895 | macro_rules! impl_tx_pin { | ||
| 896 | ($pin:ident, $instance:ident, $func: ident) => { | ||
| 897 | impl SealedTxPin<crate::peripherals::$instance> for crate::peripherals::$pin { | ||
| 898 | fn pin_func(&self) -> PioFunc { | ||
| 899 | PioFunc::$func | ||
| 900 | } | ||
| 901 | } | ||
| 879 | 902 | ||
| 880 | macro_rules! impl_pin { | ||
| 881 | ($pin:ident, $instance:ident, Tx) => { | ||
| 882 | impl TxPin<crate::peripherals::$instance> for crate::peripherals::$pin {} | 903 | impl TxPin<crate::peripherals::$instance> for crate::peripherals::$pin {} |
| 883 | }; | 904 | }; |
| 884 | ($pin:ident, $instance:ident, Rx) => { | 905 | } |
| 906 | |||
| 907 | macro_rules! impl_rx_pin { | ||
| 908 | ($pin:ident, $instance:ident, $func: ident) => { | ||
| 909 | impl SealedRxPin<crate::peripherals::$instance> for crate::peripherals::$pin { | ||
| 910 | fn pin_func(&self) -> PioFunc { | ||
| 911 | PioFunc::$func | ||
| 912 | } | ||
| 913 | } | ||
| 914 | |||
| 885 | impl RxPin<crate::peripherals::$instance> for crate::peripherals::$pin {} | 915 | impl RxPin<crate::peripherals::$instance> for crate::peripherals::$pin {} |
| 886 | }; | 916 | }; |
| 887 | } | 917 | } |
| 888 | 918 | ||
| 889 | impl_pin!(PIO1_6, USART0, Tx); | 919 | impl_tx_pin!(PIO1_6, USART0, ALT1); |
| 890 | impl_pin!(PIO1_5, USART0, Rx); | 920 | impl_tx_pin!(PIO1_11, USART1, ALT2); |
| 891 | impl_pin!(PIO1_11, USART1, Tx); | 921 | impl_tx_pin!(PIO0_27, USART2, ALT1); |
| 892 | impl_pin!(PIO1_10, USART1, Rx); | 922 | impl_tx_pin!(PIO0_2, USART3, ALT1); |
| 893 | impl_pin!(PIO0_27, USART2, Tx); | 923 | impl_tx_pin!(PIO0_16, USART4, ALT1); |
| 894 | impl_pin!(PIO1_24, USART2, Rx); | 924 | impl_tx_pin!(PIO0_9, USART5, ALT3); |
| 895 | impl_pin!(PIO0_2, USART3, Tx); | 925 | impl_tx_pin!(PIO1_16, USART6, ALT2); |
| 896 | impl_pin!(PIO0_3, USART3, Rx); | 926 | impl_tx_pin!(PIO0_19, USART7, ALT7); |
| 897 | impl_pin!(PIO0_16, USART4, Tx); | 927 | |
| 898 | impl_pin!(PIO0_5, USART4, Rx); | 928 | impl_rx_pin!(PIO1_5, USART0, ALT1); |
| 899 | impl_pin!(PIO0_9, USART5, Tx); | 929 | impl_rx_pin!(PIO1_10, USART1, ALT2); |
| 900 | impl_pin!(PIO0_8, USART5, Rx); | 930 | impl_rx_pin!(PIO1_24, USART2, ALT1); |
| 901 | impl_pin!(PIO1_16, USART6, Tx); | 931 | impl_rx_pin!(PIO0_3, USART3, ALT1); |
| 902 | impl_pin!(PIO1_13, USART6, Rx); | 932 | impl_rx_pin!(PIO0_5, USART4, ALT2); |
| 903 | impl_pin!(PIO0_19, USART7, Tx); | 933 | impl_rx_pin!(PIO0_8, USART5, ALT3); |
| 904 | impl_pin!(PIO0_20, USART7, Rx); | 934 | impl_rx_pin!(PIO1_13, USART6, ALT2); |
| 935 | impl_rx_pin!(PIO0_20, USART7, ALT7); | ||
| 905 | 936 | ||
| 906 | /// Trait for TX DMA channels. | 937 | /// Trait for TX DMA channels. |
| 907 | pub trait TxChannel<T: Instance>: crate::dma::Channel {} | 938 | pub trait TxChannel<T: Instance>: crate::dma::Channel {} |
diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index e932bcaa3..57ec13658 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md | |||
| @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 8 | <!-- next-header --> | 8 | <!-- next-header --> |
| 9 | ## Unreleased - ReleaseDate | 9 | ## Unreleased - ReleaseDate |
| 10 | 10 | ||
| 11 | - Fix several minor typos in documentation | ||
| 11 | - Add PIO SPI | 12 | - Add PIO SPI |
| 12 | - Add PIO I2S input | 13 | - Add PIO I2S input |
| 13 | - Add PIO onewire parasite power strong pullup | 14 | - Add PIO onewire parasite power strong pullup |
diff --git a/embassy-rp/src/block.rs b/embassy-rp/src/block.rs index a3e1ad925..745883b83 100644 --- a/embassy-rp/src/block.rs +++ b/embassy-rp/src/block.rs | |||
| @@ -240,7 +240,7 @@ impl UnpartitionedSpace { | |||
| 240 | } | 240 | } |
| 241 | } | 241 | } |
| 242 | 242 | ||
| 243 | /// Create a new unpartition space from run-time values. | 243 | /// Create a new unpartitioned space from run-time values. |
| 244 | /// | 244 | /// |
| 245 | /// Get these from the ROM function `get_partition_table_info` with an argument of `PT_INFO`. | 245 | /// Get these from the ROM function `get_partition_table_info` with an argument of `PT_INFO`. |
| 246 | pub const fn from_raw(permissions_and_location: u32, permissions_and_flags: u32) -> Self { | 246 | pub const fn from_raw(permissions_and_location: u32, permissions_and_flags: u32) -> Self { |
| @@ -714,7 +714,7 @@ impl PartitionTableBlock { | |||
| 714 | new_table | 714 | new_table |
| 715 | } | 715 | } |
| 716 | 716 | ||
| 717 | /// Add a a SHA256 hash of the Block | 717 | /// Add a SHA256 hash of the Block |
| 718 | /// | 718 | /// |
| 719 | /// Adds a `HASH_DEF` covering all the previous items in the Block, and a | 719 | /// Adds a `HASH_DEF` covering all the previous items in the Block, and a |
| 720 | /// `HASH_VALUE` with a SHA-256 hash of them. | 720 | /// `HASH_VALUE` with a SHA-256 hash of them. |
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 56892d7a2..8bfb5129a 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs | |||
| @@ -267,7 +267,7 @@ impl CoreVoltage { | |||
| 267 | } | 267 | } |
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | /// CLock configuration. | 270 | /// Clock configuration. |
| 271 | #[non_exhaustive] | 271 | #[non_exhaustive] |
| 272 | pub struct ClockConfig { | 272 | pub struct ClockConfig { |
| 273 | /// Ring oscillator configuration. | 273 | /// Ring oscillator configuration. |
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index c15e0e41b..154fc1585 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs | |||
| @@ -300,7 +300,7 @@ impl<'d> InputFuture<'d> { | |||
| 300 | 300 | ||
| 301 | // Each INTR register is divided into 8 groups, one group for each | 301 | // Each INTR register is divided into 8 groups, one group for each |
| 302 | // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, | 302 | // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, |
| 303 | // and EGDE_HIGH. | 303 | // and EDGE_HIGH. |
| 304 | pin.int_proc() | 304 | pin.int_proc() |
| 305 | .inte((pin.pin() / 8) as usize) | 305 | .inte((pin.pin() / 8) as usize) |
| 306 | .write_set(|w| match level { | 306 | .write_set(|w| match level { |
diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index 770087bc8..0853709df 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs | |||
| @@ -52,7 +52,7 @@ pub enum ReadStatus { | |||
| 52 | Done, | 52 | Done, |
| 53 | /// Transaction Incomplete, controller trying to read more bytes than were provided | 53 | /// Transaction Incomplete, controller trying to read more bytes than were provided |
| 54 | NeedMoreBytes, | 54 | NeedMoreBytes, |
| 55 | /// Transaction Complere, but controller stopped reading bytes before we ran out | 55 | /// Transaction Complete, but controller stopped reading bytes before we ran out |
| 56 | LeftoverBytes(u16), | 56 | LeftoverBytes(u16), |
| 57 | } | 57 | } |
| 58 | 58 | ||
| @@ -240,7 +240,7 @@ impl<'d, T: Instance> I2cSlave<'d, T> { | |||
| 240 | 240 | ||
| 241 | if p.ic_rxflr().read().rxflr() > 0 || me.pending_byte.is_some() { | 241 | if p.ic_rxflr().read().rxflr() > 0 || me.pending_byte.is_some() { |
| 242 | me.drain_fifo(buffer, &mut len); | 242 | me.drain_fifo(buffer, &mut len); |
| 243 | // we're recieving data, set rx fifo watermark to 12 bytes (3/4 full) to reduce interrupt noise | 243 | // we're receiving data, set rx fifo watermark to 12 bytes (3/4 full) to reduce interrupt noise |
| 244 | p.ic_rx_tl().write(|w| w.set_rx_tl(11)); | 244 | p.ic_rx_tl().write(|w| w.set_rx_tl(11)); |
| 245 | } | 245 | } |
| 246 | 246 | ||
diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index 3b120e349..572d8db91 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs | |||
| @@ -58,7 +58,7 @@ const PAUSE_TOKEN: u32 = 0xDEADBEEF; | |||
| 58 | const RESUME_TOKEN: u32 = !0xDEADBEEF; | 58 | const RESUME_TOKEN: u32 = !0xDEADBEEF; |
| 59 | static IS_CORE1_INIT: AtomicBool = AtomicBool::new(false); | 59 | static IS_CORE1_INIT: AtomicBool = AtomicBool::new(false); |
| 60 | 60 | ||
| 61 | /// Represents a partiticular CPU core (SIO_CPUID) | 61 | /// Represents a particular CPU core (SIO_CPUID) |
| 62 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] | 62 | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] |
| 63 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 63 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 64 | #[repr(u8)] | 64 | #[repr(u8)] |
diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 38ee1f97c..92b2c603e 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs | |||
| @@ -62,7 +62,7 @@ pub enum FifoJoin { | |||
| 62 | #[cfg(feature = "_rp235x")] | 62 | #[cfg(feature = "_rp235x")] |
| 63 | RxAsControl, | 63 | RxAsControl, |
| 64 | /// FJOIN_RX_PUT | FJOIN_RX_GET: RX can be used as a scratch register, | 64 | /// FJOIN_RX_PUT | FJOIN_RX_GET: RX can be used as a scratch register, |
| 65 | /// not accesible from the CPU | 65 | /// not accessible from the CPU |
| 66 | #[cfg(feature = "_rp235x")] | 66 | #[cfg(feature = "_rp235x")] |
| 67 | PioScratch, | 67 | PioScratch, |
| 68 | } | 68 | } |
diff --git a/embassy-rp/src/pio_programs/i2s.rs b/embassy-rp/src/pio_programs/i2s.rs index 7e5f68ad6..5c49beecb 100644 --- a/embassy-rp/src/pio_programs/i2s.rs +++ b/embassy-rp/src/pio_programs/i2s.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | //! Pio backed I2s output and output drivers | 1 | //! Pio backed I2S output and output drivers |
| 2 | 2 | ||
| 3 | use fixed::traits::ToFixed; | 3 | use fixed::traits::ToFixed; |
| 4 | 4 | ||
| @@ -9,7 +9,7 @@ use crate::pio::{ | |||
| 9 | Common, Config, Direction, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, | 9 | Common, Config, Direction, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, |
| 10 | }; | 10 | }; |
| 11 | 11 | ||
| 12 | /// This struct represents an i2s receiver & controller driver program | 12 | /// This struct represents an I2S receiver & controller driver program |
| 13 | pub struct PioI2sInProgram<'d, PIO: Instance> { | 13 | pub struct PioI2sInProgram<'d, PIO: Instance> { |
| 14 | prg: LoadedProgram<'d, PIO>, | 14 | prg: LoadedProgram<'d, PIO>, |
| 15 | } | 15 | } |
| @@ -35,7 +35,7 @@ impl<'d, PIO: Instance> PioI2sInProgram<'d, PIO> { | |||
| 35 | } | 35 | } |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | /// Pio backed I2s input driver | 38 | /// Pio backed I2S input driver |
| 39 | pub struct PioI2sIn<'d, P: Instance, const S: usize> { | 39 | pub struct PioI2sIn<'d, P: Instance, const S: usize> { |
| 40 | dma: Peri<'d, AnyChannel>, | 40 | dma: Peri<'d, AnyChannel>, |
| 41 | sm: StateMachine<'d, P, S>, | 41 | sm: StateMachine<'d, P, S>, |
| @@ -50,7 +50,7 @@ impl<'d, P: Instance, const S: usize> PioI2sIn<'d, P, S> { | |||
| 50 | // Whether or not to use the MCU's internal pull-down resistor, as the | 50 | // Whether or not to use the MCU's internal pull-down resistor, as the |
| 51 | // Pico 2 is known to have problems with the inbuilt pulldowns, many | 51 | // Pico 2 is known to have problems with the inbuilt pulldowns, many |
| 52 | // opt to just use an external pull down resistor to meet requirements of common | 52 | // opt to just use an external pull down resistor to meet requirements of common |
| 53 | // i2s microphones such as the INMP441 | 53 | // I2S microphones such as the INMP441 |
| 54 | data_pulldown: bool, | 54 | data_pulldown: bool, |
| 55 | data_pin: Peri<'d, impl PioPin>, | 55 | data_pin: Peri<'d, impl PioPin>, |
| 56 | bit_clock_pin: Peri<'d, impl PioPin>, | 56 | bit_clock_pin: Peri<'d, impl PioPin>, |
| @@ -90,13 +90,13 @@ impl<'d, P: Instance, const S: usize> PioI2sIn<'d, P, S> { | |||
| 90 | Self { dma: dma.into(), sm } | 90 | Self { dma: dma.into(), sm } |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | /// Return an in-prograss dma transfer future. Awaiting it will guarentee a complete transfer. | 93 | /// Return an in-progress dma transfer future. Awaiting it will guarantee a complete transfer. |
| 94 | pub fn read<'b>(&'b mut self, buff: &'b mut [u32]) -> Transfer<'b, AnyChannel> { | 94 | pub fn read<'b>(&'b mut self, buff: &'b mut [u32]) -> Transfer<'b, AnyChannel> { |
| 95 | self.sm.rx().dma_pull(self.dma.reborrow(), buff, false) | 95 | self.sm.rx().dma_pull(self.dma.reborrow(), buff, false) |
| 96 | } | 96 | } |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | /// This struct represents an i2s output driver program | 99 | /// This struct represents an I2S output driver program |
| 100 | /// | 100 | /// |
| 101 | /// The sample bit-depth is set through scratch register `Y`. | 101 | /// The sample bit-depth is set through scratch register `Y`. |
| 102 | /// `Y` has to be set to sample bit-depth - 2. | 102 | /// `Y` has to be set to sample bit-depth - 2. |
| @@ -128,14 +128,14 @@ impl<'d, PIO: Instance> PioI2sOutProgram<'d, PIO> { | |||
| 128 | } | 128 | } |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | /// Pio backed I2s output driver | 131 | /// Pio backed I2S output driver |
| 132 | pub struct PioI2sOut<'d, P: Instance, const S: usize> { | 132 | pub struct PioI2sOut<'d, P: Instance, const S: usize> { |
| 133 | dma: Peri<'d, AnyChannel>, | 133 | dma: Peri<'d, AnyChannel>, |
| 134 | sm: StateMachine<'d, P, S>, | 134 | sm: StateMachine<'d, P, S>, |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | impl<'d, P: Instance, const S: usize> PioI2sOut<'d, P, S> { | 137 | impl<'d, P: Instance, const S: usize> PioI2sOut<'d, P, S> { |
| 138 | /// Configure a state machine to output I2s | 138 | /// Configure a state machine to output I2S |
| 139 | pub fn new( | 139 | pub fn new( |
| 140 | common: &mut Common<'d, P>, | 140 | common: &mut Common<'d, P>, |
| 141 | mut sm: StateMachine<'d, P, S>, | 141 | mut sm: StateMachine<'d, P, S>, |
| @@ -179,7 +179,7 @@ impl<'d, P: Instance, const S: usize> PioI2sOut<'d, P, S> { | |||
| 179 | Self { dma: dma.into(), sm } | 179 | Self { dma: dma.into(), sm } |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | /// Return an in-prograss dma transfer future. Awaiting it will guarentee a complete transfer. | 182 | /// Return an in-progress dma transfer future. Awaiting it will guarantee a complete transfer. |
| 183 | pub fn write<'b>(&'b mut self, buff: &'b [u32]) -> Transfer<'b, AnyChannel> { | 183 | pub fn write<'b>(&'b mut self, buff: &'b [u32]) -> Transfer<'b, AnyChannel> { |
| 184 | self.sm.tx().dma_push(self.dma.reborrow(), buff, false) | 184 | self.sm.tx().dma_push(self.dma.reborrow(), buff, false) |
| 185 | } | 185 | } |
diff --git a/embassy-rp/src/pio_programs/pwm.rs b/embassy-rp/src/pio_programs/pwm.rs index ba06bb3c1..e4ad4a6f0 100644 --- a/embassy-rp/src/pio_programs/pwm.rs +++ b/embassy-rp/src/pio_programs/pwm.rs | |||
| @@ -67,7 +67,7 @@ impl<'d, T: Instance, const SM: usize> PioPwm<'d, T, SM> { | |||
| 67 | Self { sm, pin } | 67 | Self { sm, pin } |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | /// Enable's the PIO program, continuing the wave generation from the PIO program. | 70 | /// Enables the PIO program, continuing the wave generation from the PIO program. |
| 71 | pub fn start(&mut self) { | 71 | pub fn start(&mut self) { |
| 72 | self.sm.set_enable(true); | 72 | self.sm.set_enable(true); |
| 73 | } | 73 | } |
diff --git a/embassy-rp/src/pio_programs/spi.rs b/embassy-rp/src/pio_programs/spi.rs index b10fc6628..765ffaa06 100644 --- a/embassy-rp/src/pio_programs/spi.rs +++ b/embassy-rp/src/pio_programs/spi.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | //! PIO backed SPi drivers | 1 | //! PIO backed SPI drivers |
| 2 | 2 | ||
| 3 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 4 | 4 | ||
| @@ -83,7 +83,7 @@ pub enum Error { | |||
| 83 | // No errors for now | 83 | // No errors for now |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | /// PIO based Spi driver. | 86 | /// PIO based SPI driver. |
| 87 | /// Unlike other PIO programs, the PIO SPI driver owns and holds a reference to | 87 | /// Unlike other PIO programs, the PIO SPI driver owns and holds a reference to |
| 88 | /// the PIO memory it uses. This is so that it can be reconfigured at runtime if | 88 | /// the PIO memory it uses. This is so that it can be reconfigured at runtime if |
| 89 | /// desired. | 89 | /// desired. |
diff --git a/embassy-rp/src/pio_programs/uart.rs b/embassy-rp/src/pio_programs/uart.rs index 444efb5db..d59596dd1 100644 --- a/embassy-rp/src/pio_programs/uart.rs +++ b/embassy-rp/src/pio_programs/uart.rs | |||
| @@ -130,7 +130,7 @@ impl<'d, PIO: Instance> PioUartRxProgram<'d, PIO> { | |||
| 130 | } | 130 | } |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | /// PIO backed Uart reciever | 133 | /// PIO backed Uart receiver |
| 134 | pub struct PioUartRx<'d, PIO: Instance, const SM: usize> { | 134 | pub struct PioUartRx<'d, PIO: Instance, const SM: usize> { |
| 135 | sm_rx: StateMachine<'d, PIO, SM>, | 135 | sm_rx: StateMachine<'d, PIO, SM>, |
| 136 | } | 136 | } |
diff --git a/embassy-rp/src/rom_data/rp2040.rs b/embassy-rp/src/rom_data/rp2040.rs index 5a74eddd6..27a8d8981 100644 --- a/embassy-rp/src/rom_data/rp2040.rs +++ b/embassy-rp/src/rom_data/rp2040.rs | |||
| @@ -30,7 +30,7 @@ const DATA_TABLE: *const u16 = 0x0000_0016 as _; | |||
| 30 | /// Address of the version number of the ROM. | 30 | /// Address of the version number of the ROM. |
| 31 | const VERSION_NUMBER: *const u8 = 0x0000_0013 as _; | 31 | const VERSION_NUMBER: *const u8 = 0x0000_0013 as _; |
| 32 | 32 | ||
| 33 | /// Retrive rom content from a table using a code. | 33 | /// Retrieve rom content from a table using a code. |
| 34 | fn rom_table_lookup<T>(table: *const u16, tag: RomFnTableCode) -> T { | 34 | fn rom_table_lookup<T>(table: *const u16, tag: RomFnTableCode) -> T { |
| 35 | unsafe { | 35 | unsafe { |
| 36 | let rom_table_lookup_ptr: *const u32 = rom_hword_as_ptr(ROM_TABLE_LOOKUP_PTR); | 36 | let rom_table_lookup_ptr: *const u32 = rom_hword_as_ptr(ROM_TABLE_LOOKUP_PTR); |
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs index 68fb3b765..054572903 100644 --- a/embassy-rp/src/rtc/mod.rs +++ b/embassy-rp/src/rtc/mod.rs | |||
| @@ -47,7 +47,7 @@ impl<'d, T: Instance> Rtc<'d, T> { | |||
| 47 | Self { inner } | 47 | Self { inner } |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | /// Enable or disable the leap year check. The rp2040 chip will always add a Feb 29th on every year that is divisable by 4, but this may be incorrect (e.g. on century years). This function allows you to disable this check. | 50 | /// Enable or disable the leap year check. The rp2040 chip will always add a Feb 29th on every year that is divisible by 4, but this may be incorrect (e.g. on century years). This function allows you to disable this check. |
| 51 | /// | 51 | /// |
| 52 | /// Leap year checking is enabled by default. | 52 | /// Leap year checking is enabled by default. |
| 53 | pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) { | 53 | pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) { |
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index 559b3b909..d9410e78d 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs | |||
| @@ -157,7 +157,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { | |||
| 157 | 157 | ||
| 158 | /// Private function to apply SPI configuration (phase, polarity, frequency) settings. | 158 | /// Private function to apply SPI configuration (phase, polarity, frequency) settings. |
| 159 | /// | 159 | /// |
| 160 | /// Driver should be disabled before making changes and reenabled after the modifications | 160 | /// Driver should be disabled before making changes and re-enabled after the modifications |
| 161 | /// are applied. | 161 | /// are applied. |
| 162 | fn apply_config(inner: &Peri<'d, T>, config: &Config) { | 162 | fn apply_config(inner: &Peri<'d, T>, config: &Config) { |
| 163 | let p = inner.regs(); | 163 | let p = inner.regs(); |
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 43187df2d..8be87a5d2 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs | |||
| @@ -315,7 +315,7 @@ impl<'d, M: Mode> UartRx<'d, M> { | |||
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | /// Returns Ok(len) if no errors occurred. Returns Err((len, err)) if an error was | 317 | /// Returns Ok(len) if no errors occurred. Returns Err((len, err)) if an error was |
| 318 | /// encountered. in both cases, `len` is the number of *good* bytes copied into | 318 | /// encountered. In both cases, `len` is the number of *good* bytes copied into |
| 319 | /// `buffer`. | 319 | /// `buffer`. |
| 320 | fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> { | 320 | fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> { |
| 321 | let r = self.info.regs; | 321 | let r = self.info.regs; |
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 7675567ff..9848daf49 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md | |||
| @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 11 | * **Fix(stm32h5):** Prevent a HardFault crash on STM32H5 devices by changing `uid()` to return `[u8; 12]` by value instead of a reference. (Fixes #2696) | 11 | * **Fix(stm32h5):** Prevent a HardFault crash on STM32H5 devices by changing `uid()` to return `[u8; 12]` by value instead of a reference. (Fixes #2696) |
| 12 | ## Unreleased - ReleaseDate | 12 | ## Unreleased - ReleaseDate |
| 13 | 13 | ||
| 14 | - fix flash erase on L4 & L5 | ||
| 14 | - fix: Fixed STM32H5 builds requiring time feature | 15 | - fix: Fixed STM32H5 builds requiring time feature |
| 15 | - feat: Derive Clone, Copy for QSPI Config | 16 | - feat: Derive Clone, Copy for QSPI Config |
| 16 | - fix: stm32/i2c in master mode (blocking): subsequent transmissions failed after a NACK was received | 17 | - fix: stm32/i2c in master mode (blocking): subsequent transmissions failed after a NACK was received |
diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index cd23cda5c..b3281f2d5 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs | |||
| @@ -96,14 +96,20 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 96 | #[cfg(any(flash_wl, flash_wb, flash_l4, flash_l5))] | 96 | #[cfg(any(flash_wl, flash_wb, flash_l4, flash_l5))] |
| 97 | { | 97 | { |
| 98 | let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; | 98 | let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; |
| 99 | #[cfg(any(flash_l4, flash_l5))] | ||
| 100 | let pgn = super::BANK1_REGION.size as u32 / super::BANK1_REGION.erase_size as u32; | ||
| 99 | 101 | ||
| 100 | #[cfg(flash_l4)] | 102 | #[cfg(flash_l4)] |
| 101 | let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) }; | 103 | let (idx, bank) = if idx > (pgn - 1) { |
| 104 | (idx - pgn, true) | ||
| 105 | } else { | ||
| 106 | (idx, false) | ||
| 107 | }; | ||
| 102 | 108 | ||
| 103 | #[cfg(flash_l5)] | 109 | #[cfg(flash_l5)] |
| 104 | let (idx, bank) = if pac::FLASH.optr().read().dbank() { | 110 | let (idx, bank) = if pac::FLASH.optr().read().dbank() { |
| 105 | if idx > 255 { | 111 | if idx > (pgn - 1) { |
| 106 | (idx - 256, Some(true)) | 112 | (idx - pgn, Some(true)) |
| 107 | } else { | 113 | } else { |
| 108 | (idx, Some(false)) | 114 | (idx, Some(false)) |
| 109 | } | 115 | } |
diff --git a/examples/lpc55s69/src/bin/pwm.rs b/examples/lpc55s69/src/bin/pwm.rs new file mode 100644 index 000000000..93b898b9d --- /dev/null +++ b/examples/lpc55s69/src/bin/pwm.rs | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_nxp::pwm::{Config, Pwm}; | ||
| 7 | use embassy_time::Timer; | ||
| 8 | use {defmt_rtt as _, panic_halt as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async fn main(_spawner: Spawner) { | ||
| 12 | let p = embassy_nxp::init(Default::default()); | ||
| 13 | let pwm = Pwm::new_output(p.PWM_OUTPUT1, p.PIO0_18, Config::new(1_000_000_000, 2_000_000_000)); | ||
| 14 | loop { | ||
| 15 | info!("Counter: {}", pwm.counter()); | ||
| 16 | Timer::after_millis(50).await; | ||
| 17 | } | ||
| 18 | } | ||
