aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaarten de Vries <[email protected]>2025-10-28 10:10:39 +0100
committerGitHub <[email protected]>2025-10-28 10:10:39 +0100
commitf1476ad7f21e73d3d5c015c261f9ee8b43cbd9a1 (patch)
treef778924f0f9c7f8abd45f11ced220206cf2ce344
parent369959e654d095d0e3d95597693bd64fcdb50ec5 (diff)
parent05663c231ebd82af0491dfb9d418fd0566cb02ff (diff)
Merge branch 'main' into nrf-simplepwm-config
-rw-r--r--embassy-nrf/CHANGELOG.md2
-rw-r--r--embassy-nrf/src/gpiote.rs8
-rw-r--r--embassy-nxp/CHANGELOG.md3
-rw-r--r--embassy-nxp/Cargo.toml4
-rw-r--r--embassy-nxp/src/chips/lpc55.rs12
-rw-r--r--embassy-nxp/src/fmt.rs1
-rw-r--r--embassy-nxp/src/gpio/lpc55.rs66
-rw-r--r--embassy-nxp/src/lib.rs7
-rw-r--r--embassy-nxp/src/pwm.rs5
-rw-r--r--embassy-nxp/src/pwm/lpc55.rs325
-rw-r--r--embassy-nxp/src/usart/lpc55.rs173
-rw-r--r--embassy-rp/CHANGELOG.md1
-rw-r--r--embassy-rp/src/block.rs4
-rw-r--r--embassy-rp/src/clocks.rs2
-rw-r--r--embassy-rp/src/gpio.rs2
-rw-r--r--embassy-rp/src/i2c_slave.rs4
-rw-r--r--embassy-rp/src/multicore.rs2
-rw-r--r--embassy-rp/src/pio/mod.rs2
-rw-r--r--embassy-rp/src/pio_programs/i2s.rs18
-rw-r--r--embassy-rp/src/pio_programs/pwm.rs2
-rw-r--r--embassy-rp/src/pio_programs/spi.rs4
-rw-r--r--embassy-rp/src/pio_programs/uart.rs2
-rw-r--r--embassy-rp/src/rom_data/rp2040.rs2
-rw-r--r--embassy-rp/src/rtc/mod.rs2
-rw-r--r--embassy-rp/src/spi.rs2
-rw-r--r--embassy-rp/src/uart/mod.rs2
-rw-r--r--embassy-stm32/CHANGELOG.md1
-rw-r--r--embassy-stm32/src/flash/l.rs12
-rw-r--r--examples/lpc55s69/src/bin/pwm.rs18
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
38embedded-io = "0.6.1" 38embedded-io = "0.6.1"
39embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 39embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
40## Chip dependencies 40## Chip dependencies
41nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "b736e3038254d593024aaa1a5a7b1f95a5728538"} 41nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "477dfdbfd5e6c75c0730c56494b601c1b2257263"}
42 42
43imxrt-rt = { version = "0.1.7", optional = true, features = ["device"] } 43imxrt-rt = { version = "0.1.7", optional = true, features = ["device"] }
44 44
45[build-dependencies] 45[build-dependencies]
46cfg_aliases = "0.2.1" 46cfg_aliases = "0.2.1"
47nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "b736e3038254d593024aaa1a5a7b1f95a5728538", features = ["metadata"], optional = true } 47nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "477dfdbfd5e6c75c0730c56494b601c1b2257263", features = ["metadata"], optional = true }
48proc-macro2 = "1.0.95" 48proc-macro2 = "1.0.95"
49quote = "1.0.15" 49quote = "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 @@
1use embassy_hal_internal::{PeripheralType, impl_peripheral}; 1use embassy_hal_internal::{PeripheralType, impl_peripheral};
2 2
3use crate::pac::common::{RW, Reg};
3use crate::pac::iocon::vals::{PioDigimode, PioMode}; 4use crate::pac::iocon::vals::{PioDigimode, PioMode};
4use crate::pac::{GPIO, IOCON, SYSCON}; 5use crate::pac::{GPIO, IOCON, SYSCON, iocon};
5use crate::{Peri, peripherals}; 6use crate::{Peri, peripherals};
6 7
7pub(crate) fn init() { 8pub(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> {
220pub(crate) trait SealedPin: Sized { 224pub(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/// ```
291macro_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
307pub(crate) use match_iocon;
308
309macro_rules! impl_pin { 287macro_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")]
11pub mod pint; 11pub mod pint;
12#[cfg(feature = "lpc55-core0")] 12#[cfg(feature = "lpc55-core0")]
13pub mod pwm;
14#[cfg(feature = "lpc55-core0")]
13pub mod usart; 15pub 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")]
4mod inner;
5pub 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 @@
1use core::sync::atomic::{AtomicU8, AtomicU32, Ordering};
2
3use embassy_hal_internal::{Peri, PeripheralType};
4
5use crate::gpio::AnyPin;
6use crate::pac::iocon::vals::{PioDigimode, PioFunc, PioMode, PioOd, PioSlew};
7use crate::pac::sct0::vals;
8use crate::pac::syscon::vals::{SctRst, SctclkselSel};
9use crate::pac::{SCT0, SYSCON};
10
11// Since for now the counter is shared, the TOP value has to be kept.
12static TOP_VALUE: AtomicU32 = AtomicU32::new(0);
13// To check if there are still active instances.
14static 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)]
22pub 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
51impl 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.
66pub struct Pwm<'d> {
67 _pin: Peri<'d, AnyPin>,
68 output: usize,
69}
70
71impl<'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
234impl<'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
243trait SealedOutput {
244 /// Output number.
245 fn number(&self) -> usize;
246}
247
248/// PWM Output.
249#[allow(private_bounds)]
250pub trait Output: PeripheralType + SealedOutput {}
251
252macro_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
263output!(PWM_OUTPUT0, 0);
264output!(PWM_OUTPUT1, 1);
265output!(PWM_OUTPUT2, 2);
266output!(PWM_OUTPUT3, 3);
267output!(PWM_OUTPUT4, 4);
268output!(PWM_OUTPUT5, 5);
269output!(PWM_OUTPUT6, 6);
270output!(PWM_OUTPUT7, 7);
271output!(PWM_OUTPUT8, 8);
272output!(PWM_OUTPUT9, 9);
273
274/// PWM Output Channel.
275pub trait OutputChannelPin<T: Output>: crate::gpio::Pin {
276 fn pin_func(&self) -> PioFunc;
277}
278
279macro_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
289impl_pin!(PIO0_2, PWM_OUTPUT0, ALT3);
290impl_pin!(PIO0_17, PWM_OUTPUT0, ALT4);
291impl_pin!(PIO1_4, PWM_OUTPUT0, ALT4);
292impl_pin!(PIO1_23, PWM_OUTPUT0, ALT2);
293
294impl_pin!(PIO0_3, PWM_OUTPUT1, ALT3);
295impl_pin!(PIO0_18, PWM_OUTPUT1, ALT4);
296impl_pin!(PIO1_8, PWM_OUTPUT1, ALT4);
297impl_pin!(PIO1_24, PWM_OUTPUT1, ALT2);
298
299impl_pin!(PIO0_10, PWM_OUTPUT2, ALT5);
300impl_pin!(PIO0_15, PWM_OUTPUT2, ALT4);
301impl_pin!(PIO0_19, PWM_OUTPUT2, ALT4);
302impl_pin!(PIO1_9, PWM_OUTPUT2, ALT4);
303impl_pin!(PIO1_25, PWM_OUTPUT2, ALT2);
304
305impl_pin!(PIO0_22, PWM_OUTPUT3, ALT4);
306impl_pin!(PIO0_31, PWM_OUTPUT3, ALT4);
307impl_pin!(PIO1_10, PWM_OUTPUT3, ALT4);
308impl_pin!(PIO1_26, PWM_OUTPUT3, ALT2);
309
310impl_pin!(PIO0_23, PWM_OUTPUT4, ALT4);
311impl_pin!(PIO1_3, PWM_OUTPUT4, ALT4);
312impl_pin!(PIO1_17, PWM_OUTPUT4, ALT4);
313
314impl_pin!(PIO0_26, PWM_OUTPUT5, ALT4);
315impl_pin!(PIO1_18, PWM_OUTPUT5, ALT4);
316
317impl_pin!(PIO0_27, PWM_OUTPUT6, ALT4);
318impl_pin!(PIO1_31, PWM_OUTPUT6, ALT4);
319
320impl_pin!(PIO0_28, PWM_OUTPUT7, ALT4);
321impl_pin!(PIO1_19, PWM_OUTPUT7, ALT2);
322
323impl_pin!(PIO0_29, PWM_OUTPUT8, ALT4);
324
325impl_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;
11use embedded_io::{self, ErrorKind}; 11use embedded_io::{self, ErrorKind};
12 12
13use crate::dma::{AnyChannel, Channel}; 13use crate::dma::{AnyChannel, Channel};
14use crate::gpio::{AnyPin, Bank, SealedPin, match_iocon}; 14use crate::gpio::{AnyPin, SealedPin};
15use crate::interrupt::Interrupt; 15use crate::interrupt::Interrupt;
16use crate::interrupt::typelevel::{Binding, Interrupt as _}; 16use crate::interrupt::typelevel::{Binding, Interrupt as _};
17use crate::pac::flexcomm::Flexcomm as FlexcommReg; 17use 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
180impl<'d> UsartTx<'d, Blocking> { 181impl<'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
281impl<'d> UsartRx<'d, Blocking> { 284impl<'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
828macro_rules! impl_instance { 840macro_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
866impl_instance!(USART0, FLEXCOMM0, ALT1, ALT1, 0); 870impl_instance!(USART0, FLEXCOMM0, 0);
867impl_instance!(USART1, FLEXCOMM1, ALT2, ALT2, 1); 871impl_instance!(USART1, FLEXCOMM1, 1);
868impl_instance!(USART2, FLEXCOMM2, ALT1, ALT1, 2); 872impl_instance!(USART2, FLEXCOMM2, 2);
869impl_instance!(USART3, FLEXCOMM3, ALT1, ALT1, 3); 873impl_instance!(USART3, FLEXCOMM3, 3);
870impl_instance!(USART4, FLEXCOMM4, ALT1, ALT2, 4); 874impl_instance!(USART4, FLEXCOMM4, 4);
871impl_instance!(USART5, FLEXCOMM5, ALT3, ALT3, 5); 875impl_instance!(USART5, FLEXCOMM5, 5);
872impl_instance!(USART6, FLEXCOMM6, ALT2, ALT2, 6); 876impl_instance!(USART6, FLEXCOMM6, 6);
873impl_instance!(USART7, FLEXCOMM7, ALT7, ALT7, 7); 877impl_instance!(USART7, FLEXCOMM7, 7);
878
879pub(crate) trait SealedTxPin<T: Instance>: crate::gpio::Pin {
880 fn pin_func(&self) -> PioFunc;
881}
882
883pub(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.
876pub trait TxPin<T: Instance>: crate::gpio::Pin {} 888#[allow(private_bounds)]
889pub trait TxPin<T: Instance>: SealedTxPin<T> + crate::gpio::Pin {}
890
877/// Trait for RX pins. 891/// Trait for RX pins.
878pub trait RxPin<T: Instance>: crate::gpio::Pin {} 892#[allow(private_bounds)]
893pub trait RxPin<T: Instance>: SealedRxPin<T> + crate::gpio::Pin {}
894
895macro_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
880macro_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
907macro_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
889impl_pin!(PIO1_6, USART0, Tx); 919impl_tx_pin!(PIO1_6, USART0, ALT1);
890impl_pin!(PIO1_5, USART0, Rx); 920impl_tx_pin!(PIO1_11, USART1, ALT2);
891impl_pin!(PIO1_11, USART1, Tx); 921impl_tx_pin!(PIO0_27, USART2, ALT1);
892impl_pin!(PIO1_10, USART1, Rx); 922impl_tx_pin!(PIO0_2, USART3, ALT1);
893impl_pin!(PIO0_27, USART2, Tx); 923impl_tx_pin!(PIO0_16, USART4, ALT1);
894impl_pin!(PIO1_24, USART2, Rx); 924impl_tx_pin!(PIO0_9, USART5, ALT3);
895impl_pin!(PIO0_2, USART3, Tx); 925impl_tx_pin!(PIO1_16, USART6, ALT2);
896impl_pin!(PIO0_3, USART3, Rx); 926impl_tx_pin!(PIO0_19, USART7, ALT7);
897impl_pin!(PIO0_16, USART4, Tx); 927
898impl_pin!(PIO0_5, USART4, Rx); 928impl_rx_pin!(PIO1_5, USART0, ALT1);
899impl_pin!(PIO0_9, USART5, Tx); 929impl_rx_pin!(PIO1_10, USART1, ALT2);
900impl_pin!(PIO0_8, USART5, Rx); 930impl_rx_pin!(PIO1_24, USART2, ALT1);
901impl_pin!(PIO1_16, USART6, Tx); 931impl_rx_pin!(PIO0_3, USART3, ALT1);
902impl_pin!(PIO1_13, USART6, Rx); 932impl_rx_pin!(PIO0_5, USART4, ALT2);
903impl_pin!(PIO0_19, USART7, Tx); 933impl_rx_pin!(PIO0_8, USART5, ALT3);
904impl_pin!(PIO0_20, USART7, Rx); 934impl_rx_pin!(PIO1_13, USART6, ALT2);
935impl_rx_pin!(PIO0_20, USART7, ALT7);
905 936
906/// Trait for TX DMA channels. 937/// Trait for TX DMA channels.
907pub trait TxChannel<T: Instance>: crate::dma::Channel {} 938pub 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]
272pub struct ClockConfig { 272pub 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;
58const RESUME_TOKEN: u32 = !0xDEADBEEF; 58const RESUME_TOKEN: u32 = !0xDEADBEEF;
59static IS_CORE1_INIT: AtomicBool = AtomicBool::new(false); 59static 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
3use fixed::traits::ToFixed; 3use 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
13pub struct PioI2sInProgram<'d, PIO: Instance> { 13pub 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
39pub struct PioI2sIn<'d, P: Instance, const S: usize> { 39pub 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
132pub struct PioI2sOut<'d, P: Instance, const S: usize> { 132pub 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
137impl<'d, P: Instance, const S: usize> PioI2sOut<'d, P, S> { 137impl<'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
3use core::marker::PhantomData; 3use 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
134pub struct PioUartRx<'d, PIO: Instance, const SM: usize> { 134pub 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.
31const VERSION_NUMBER: *const u8 = 0x0000_0013 as _; 31const 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.
34fn rom_table_lookup<T>(table: *const u16, tag: RomFnTableCode) -> T { 34fn 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
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_nxp::pwm::{Config, Pwm};
7use embassy_time::Timer;
8use {defmt_rtt as _, panic_halt as _};
9
10#[embassy_executor::main]
11async 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}