aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/pages/imxrt.adoc1
-rw-r--r--embassy-imxrt/src/crc.rs190
-rw-r--r--embassy-imxrt/src/lib.rs1
-rw-r--r--embassy-nrf/src/chips/nrf5340_app.rs5
-rw-r--r--embassy-nrf/src/chips/nrf5340_net.rs5
-rw-r--r--embassy-nrf/src/ipc.rs363
-rw-r--r--embassy-nrf/src/lib.rs2
-rw-r--r--embassy-rp/Cargo.toml5
-rw-r--r--embassy-rp/src/clocks.rs821
-rw-r--r--embassy-rp/src/pio_programs/clock_divider.rs25
-rw-r--r--embassy-rp/src/pio_programs/hd44780.rs11
-rw-r--r--embassy-rp/src/pio_programs/mod.rs1
-rw-r--r--embassy-rp/src/pio_programs/rotary_encoder.rs8
-rw-r--r--embassy-rp/src/pio_programs/stepper.rs17
-rw-r--r--embassy-rp/src/uart/buffered.rs304
-rw-r--r--embassy-rp/src/uart/mod.rs300
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs2
-rw-r--r--examples/mimxrt6/src/bin/crc.rs175
-rw-r--r--examples/rp/src/bin/overclock.rs64
-rw-r--r--examples/rp/src/bin/overclock_manual.rs79
-rw-r--r--examples/rp/src/bin/sharing.rs2
-rw-r--r--examples/rp/src/bin/uart_buffered_split.rs2
-rw-r--r--examples/rp/src/bin/uart_unidir.rs2
-rw-r--r--examples/rp235x/src/bin/sharing.rs2
-rw-r--r--examples/rp235x/src/bin/uart_buffered_split.rs2
-rw-r--r--examples/rp235x/src/bin/uart_unidir.rs2
-rw-r--r--tests/rp/src/bin/overclock.rs70
-rw-r--r--tests/rp/src/bin/uart.rs6
-rw-r--r--tests/rp/src/bin/uart_buffered.rs6
-rw-r--r--tests/rp/src/bin/uart_dma.rs6
30 files changed, 2144 insertions, 335 deletions
diff --git a/docs/pages/imxrt.adoc b/docs/pages/imxrt.adoc
index 9fcb6725c..bbd65e494 100644
--- a/docs/pages/imxrt.adoc
+++ b/docs/pages/imxrt.adoc
@@ -9,5 +9,6 @@ The link: link:https://github.com/embassy-rs/embassy/tree/main/embassy-imxrt[Emb
9 9
10The following peripherals have a HAL implementation at present 10The following peripherals have a HAL implementation at present
11 11
12* CRC
12* GPIO 13* GPIO
13* RNG 14* RNG
diff --git a/embassy-imxrt/src/crc.rs b/embassy-imxrt/src/crc.rs
new file mode 100644
index 000000000..24d6ba5bd
--- /dev/null
+++ b/embassy-imxrt/src/crc.rs
@@ -0,0 +1,190 @@
1//! Cyclic Redundancy Check (CRC)
2
3use core::marker::PhantomData;
4
5use crate::clocks::{enable_and_reset, SysconPeripheral};
6pub use crate::pac::crc_engine::mode::CrcPolynomial as Polynomial;
7use crate::{peripherals, Peri, PeripheralType};
8
9/// CRC driver.
10pub struct Crc<'d> {
11 info: Info,
12 _config: Config,
13 _lifetime: PhantomData<&'d ()>,
14}
15
16/// CRC configuration
17pub struct Config {
18 /// Polynomial to be used
19 pub polynomial: Polynomial,
20
21 /// Reverse bit order of input?
22 pub reverse_in: bool,
23
24 /// 1's complement input?
25 pub complement_in: bool,
26
27 /// Reverse CRC bit order?
28 pub reverse_out: bool,
29
30 /// 1's complement CRC?
31 pub complement_out: bool,
32
33 /// CRC Seed
34 pub seed: u32,
35}
36
37impl Config {
38 /// Create a new CRC config.
39 #[must_use]
40 pub fn new(
41 polynomial: Polynomial,
42 reverse_in: bool,
43 complement_in: bool,
44 reverse_out: bool,
45 complement_out: bool,
46 seed: u32,
47 ) -> Self {
48 Config {
49 polynomial,
50 reverse_in,
51 complement_in,
52 reverse_out,
53 complement_out,
54 seed,
55 }
56 }
57}
58
59impl Default for Config {
60 fn default() -> Self {
61 Self {
62 polynomial: Polynomial::CrcCcitt,
63 reverse_in: false,
64 complement_in: false,
65 reverse_out: false,
66 complement_out: false,
67 seed: 0xffff,
68 }
69 }
70}
71
72impl<'d> Crc<'d> {
73 /// Instantiates new CRC peripheral and initializes to default values.
74 pub fn new<T: Instance>(_peripheral: Peri<'d, T>, config: Config) -> Self {
75 // enable CRC clock
76 enable_and_reset::<T>();
77
78 let mut instance = Self {
79 info: T::info(),
80 _config: config,
81 _lifetime: PhantomData,
82 };
83
84 instance.reconfigure();
85 instance
86 }
87
88 /// Reconfigured the CRC peripheral.
89 fn reconfigure(&mut self) {
90 self.info.regs.mode().write(|w| {
91 w.crc_poly()
92 .variant(self._config.polynomial)
93 .bit_rvs_wr()
94 .variant(self._config.reverse_in)
95 .cmpl_wr()
96 .variant(self._config.complement_in)
97 .bit_rvs_sum()
98 .variant(self._config.reverse_out)
99 .cmpl_sum()
100 .variant(self._config.complement_out)
101 });
102
103 // Init CRC value
104 self.info
105 .regs
106 .seed()
107 .write(|w| unsafe { w.crc_seed().bits(self._config.seed) });
108 }
109
110 /// Feeds a byte into the CRC peripheral. Returns the computed checksum.
111 pub fn feed_byte(&mut self, byte: u8) -> u32 {
112 self.info.regs.wr_data8().write(|w| unsafe { w.bits(byte) });
113
114 self.info.regs.sum().read().bits()
115 }
116
117 /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum.
118 pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 {
119 let (prefix, data, suffix) = unsafe { bytes.align_to::<u32>() };
120
121 for b in prefix {
122 self.info.regs.wr_data8().write(|w| unsafe { w.bits(*b) });
123 }
124
125 for d in data {
126 self.info.regs.wr_data32().write(|w| unsafe { w.bits(*d) });
127 }
128
129 for b in suffix {
130 self.info.regs.wr_data8().write(|w| unsafe { w.bits(*b) });
131 }
132
133 self.info.regs.sum().read().bits()
134 }
135
136 /// Feeds a halfword into the CRC peripheral. Returns the computed checksum.
137 pub fn feed_halfword(&mut self, halfword: u16) -> u32 {
138 self.info.regs.wr_data16().write(|w| unsafe { w.bits(halfword) });
139
140 self.info.regs.sum().read().bits()
141 }
142
143 /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum.
144 pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 {
145 for halfword in halfwords {
146 self.info.regs.wr_data16().write(|w| unsafe { w.bits(*halfword) });
147 }
148
149 self.info.regs.sum().read().bits()
150 }
151
152 /// Feeds a words into the CRC peripheral. Returns the computed checksum.
153 pub fn feed_word(&mut self, word: u32) -> u32 {
154 self.info.regs.wr_data32().write(|w| unsafe { w.bits(word) });
155
156 self.info.regs.sum().read().bits()
157 }
158
159 /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum.
160 pub fn feed_words(&mut self, words: &[u32]) -> u32 {
161 for word in words {
162 self.info.regs.wr_data32().write(|w| unsafe { w.bits(*word) });
163 }
164
165 self.info.regs.sum().read().bits()
166 }
167}
168
169struct Info {
170 regs: crate::pac::CrcEngine,
171}
172
173trait SealedInstance {
174 fn info() -> Info;
175}
176
177/// CRC instance trait.
178#[allow(private_bounds)]
179pub trait Instance: SealedInstance + PeripheralType + SysconPeripheral + 'static + Send {}
180
181impl Instance for peripherals::CRC {}
182
183impl SealedInstance for peripherals::CRC {
184 fn info() -> Info {
185 // SAFETY: safe from single executor
186 Info {
187 regs: unsafe { crate::pac::CrcEngine::steal() },
188 }
189 }
190}
diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs
index f728ba060..b1183d8fc 100644
--- a/embassy-imxrt/src/lib.rs
+++ b/embassy-imxrt/src/lib.rs
@@ -18,6 +18,7 @@ compile_error!(
18pub(crate) mod fmt; 18pub(crate) mod fmt;
19 19
20pub mod clocks; 20pub mod clocks;
21pub mod crc;
21pub mod gpio; 22pub mod gpio;
22pub mod iopctl; 23pub mod iopctl;
23pub mod rng; 24pub mod rng;
diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs
index 0103fa7ae..99cf29487 100644
--- a/embassy-nrf/src/chips/nrf5340_app.rs
+++ b/embassy-nrf/src/chips/nrf5340_app.rs
@@ -262,6 +262,9 @@ embassy_hal_internal::peripherals! {
262 PPI_GROUP4, 262 PPI_GROUP4,
263 PPI_GROUP5, 263 PPI_GROUP5,
264 264
265 // IPC
266 IPC,
267
265 // GPIO port 0 268 // GPIO port 0
266 #[cfg(feature = "lfxo-pins-as-gpio")] 269 #[cfg(feature = "lfxo-pins-as-gpio")]
267 P0_00, 270 P0_00,
@@ -327,6 +330,8 @@ embassy_hal_internal::peripherals! {
327 EGU5, 330 EGU5,
328} 331}
329 332
333impl_ipc!(IPC, IPC, IPC);
334
330impl_usb!(USBD, USBD, USBD); 335impl_usb!(USBD, USBD, USBD);
331 336
332impl_uarte!(SERIAL0, UARTE0, SERIAL0); 337impl_uarte!(SERIAL0, UARTE0, SERIAL0);
diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs
index 22d33d080..c2932be31 100644
--- a/embassy-nrf/src/chips/nrf5340_net.rs
+++ b/embassy-nrf/src/chips/nrf5340_net.rs
@@ -141,6 +141,9 @@ embassy_hal_internal::peripherals! {
141 PPI_GROUP4, 141 PPI_GROUP4,
142 PPI_GROUP5, 142 PPI_GROUP5,
143 143
144 // IPC
145 IPC,
146
144 // GPIO port 0 147 // GPIO port 0
145 P0_00, 148 P0_00,
146 P0_01, 149 P0_01,
@@ -200,6 +203,8 @@ embassy_hal_internal::peripherals! {
200 EGU0, 203 EGU0,
201} 204}
202 205
206impl_ipc!(IPC, IPC, IPC);
207
203impl_uarte!(SERIAL0, UARTE0, SERIAL0); 208impl_uarte!(SERIAL0, UARTE0, SERIAL0);
204impl_spim!(SERIAL0, SPIM0, SERIAL0); 209impl_spim!(SERIAL0, SPIM0, SERIAL0);
205impl_spis!(SERIAL0, SPIS0, SERIAL0); 210impl_spis!(SERIAL0, SPIS0, SERIAL0);
diff --git a/embassy-nrf/src/ipc.rs b/embassy-nrf/src/ipc.rs
new file mode 100644
index 000000000..a8a08c911
--- /dev/null
+++ b/embassy-nrf/src/ipc.rs
@@ -0,0 +1,363 @@
1//! InterProcessor Communication (IPC)
2
3#![macro_use]
4
5use core::future::poll_fn;
6use core::marker::PhantomData;
7use core::task::Poll;
8
9use embassy_hal_internal::{Peri, PeripheralType};
10use embassy_sync::waitqueue::AtomicWaker;
11
12use crate::interrupt::typelevel::Interrupt;
13use crate::{interrupt, pac, ppi};
14
15const EVENT_COUNT: usize = 16;
16
17/// IPC Event
18#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub enum EventNumber {
20 /// IPC Event 0
21 Event0 = 0,
22 /// IPC Event 1
23 Event1 = 1,
24 /// IPC Event 2
25 Event2 = 2,
26 /// IPC Event 3
27 Event3 = 3,
28 /// IPC Event 4
29 Event4 = 4,
30 /// IPC Event 5
31 Event5 = 5,
32 /// IPC Event 6
33 Event6 = 6,
34 /// IPC Event 7
35 Event7 = 7,
36 /// IPC Event 8
37 Event8 = 8,
38 /// IPC Event 9
39 Event9 = 9,
40 /// IPC Event 10
41 Event10 = 10,
42 /// IPC Event 11
43 Event11 = 11,
44 /// IPC Event 12
45 Event12 = 12,
46 /// IPC Event 13
47 Event13 = 13,
48 /// IPC Event 14
49 Event14 = 14,
50 /// IPC Event 15
51 Event15 = 15,
52}
53
54const EVENTS: [EventNumber; EVENT_COUNT] = [
55 EventNumber::Event0,
56 EventNumber::Event1,
57 EventNumber::Event2,
58 EventNumber::Event3,
59 EventNumber::Event4,
60 EventNumber::Event5,
61 EventNumber::Event6,
62 EventNumber::Event7,
63 EventNumber::Event8,
64 EventNumber::Event9,
65 EventNumber::Event10,
66 EventNumber::Event11,
67 EventNumber::Event12,
68 EventNumber::Event13,
69 EventNumber::Event14,
70 EventNumber::Event15,
71];
72
73/// IPC Channel
74#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
75pub enum IpcChannel {
76 /// IPC Channel 0
77 Channel0,
78 /// IPC Channel 1
79 Channel1,
80 /// IPC Channel 2
81 Channel2,
82 /// IPC Channel 3
83 Channel3,
84 /// IPC Channel 4
85 Channel4,
86 /// IPC Channel 5
87 Channel5,
88 /// IPC Channel 6
89 Channel6,
90 /// IPC Channel 7
91 Channel7,
92 /// IPC Channel 8
93 Channel8,
94 /// IPC Channel 9
95 Channel9,
96 /// IPC Channel 10
97 Channel10,
98 /// IPC Channel 11
99 Channel11,
100 /// IPC Channel 12
101 Channel12,
102 /// IPC Channel 13
103 Channel13,
104 /// IPC Channel 14
105 Channel14,
106 /// IPC Channel 15
107 Channel15,
108}
109
110impl IpcChannel {
111 fn mask(self) -> u32 {
112 1 << (self as u32)
113 }
114}
115
116/// Interrupt Handler
117pub struct InterruptHandler<T: Instance> {
118 _phantom: PhantomData<T>,
119}
120
121impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
122 unsafe fn on_interrupt() {
123 let regs = T::regs();
124
125 // Check if an event was generated, and if it was, trigger the corresponding waker
126 for event in EVENTS {
127 if regs.events_receive(event as usize).read() & 0x01 == 0x01 {
128 regs.intenclr().write(|w| w.0 = 0x01 << event as u32);
129 T::state().wakers[event as usize].wake();
130 }
131 }
132 }
133}
134
135/// IPC driver
136#[non_exhaustive]
137pub struct Ipc<'d, T: Instance> {
138 /// Event 0
139 pub event0: Event<'d, T>,
140 /// Event 1
141 pub event1: Event<'d, T>,
142 /// Event 2
143 pub event2: Event<'d, T>,
144 /// Event 3
145 pub event3: Event<'d, T>,
146 /// Event 4
147 pub event4: Event<'d, T>,
148 /// Event 5
149 pub event5: Event<'d, T>,
150 /// Event 6
151 pub event6: Event<'d, T>,
152 /// Event 7
153 pub event7: Event<'d, T>,
154 /// Event 8
155 pub event8: Event<'d, T>,
156 /// Event 9
157 pub event9: Event<'d, T>,
158 /// Event 10
159 pub event10: Event<'d, T>,
160 /// Event 11
161 pub event11: Event<'d, T>,
162 /// Event 12
163 pub event12: Event<'d, T>,
164 /// Event 13
165 pub event13: Event<'d, T>,
166 /// Event 14
167 pub event14: Event<'d, T>,
168 /// Event 15
169 pub event15: Event<'d, T>,
170}
171
172impl<'d, T: Instance> Ipc<'d, T> {
173 /// Create a new IPC driver.
174 pub fn new(
175 _p: Peri<'d, T>,
176 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
177 ) -> Self {
178 T::Interrupt::unpend();
179 unsafe { T::Interrupt::enable() };
180
181 let _phantom = PhantomData;
182 #[rustfmt::skip]
183 let r = Self { // attributes on expressions are experimental
184 event0: Event { number: EventNumber::Event0, _phantom },
185 event1: Event { number: EventNumber::Event1, _phantom },
186 event2: Event { number: EventNumber::Event2, _phantom },
187 event3: Event { number: EventNumber::Event3, _phantom },
188 event4: Event { number: EventNumber::Event4, _phantom },
189 event5: Event { number: EventNumber::Event5, _phantom },
190 event6: Event { number: EventNumber::Event6, _phantom },
191 event7: Event { number: EventNumber::Event7, _phantom },
192 event8: Event { number: EventNumber::Event8, _phantom },
193 event9: Event { number: EventNumber::Event9, _phantom },
194 event10: Event { number: EventNumber::Event10, _phantom },
195 event11: Event { number: EventNumber::Event11, _phantom },
196 event12: Event { number: EventNumber::Event12, _phantom },
197 event13: Event { number: EventNumber::Event13, _phantom },
198 event14: Event { number: EventNumber::Event14, _phantom },
199 event15: Event { number: EventNumber::Event15, _phantom },
200 };
201 r
202 }
203}
204
205/// IPC event
206pub struct Event<'d, T: Instance> {
207 number: EventNumber,
208 _phantom: PhantomData<&'d T>,
209}
210
211impl<'d, T: Instance> Event<'d, T> {
212 /// Trigger the event.
213 pub fn trigger(&self) {
214 let nr = self.number;
215 T::regs().tasks_send(nr as usize).write_value(1);
216 }
217
218 /// Wait for the event to be triggered.
219 pub async fn wait(&mut self) {
220 let regs = T::regs();
221 let nr = self.number as usize;
222 regs.intenset().write(|w| w.0 = 1 << nr);
223 poll_fn(|cx| {
224 T::state().wakers[nr].register(cx.waker());
225
226 if regs.events_receive(nr).read() == 1 {
227 regs.events_receive(nr).write_value(0x00);
228 Poll::Ready(())
229 } else {
230 Poll::Pending
231 }
232 })
233 .await;
234 }
235
236 /// Returns the [`EventNumber`] of the event.
237 pub fn number(&self) -> EventNumber {
238 self.number
239 }
240
241 /// Create a handle that can trigger the event.
242 pub fn trigger_handle(&self) -> EventTrigger<'d, T> {
243 EventTrigger {
244 number: self.number,
245 _phantom: PhantomData,
246 }
247 }
248
249 /// Configure the channels the event will broadcast to
250 pub fn configure_trigger<I: IntoIterator<Item = IpcChannel>>(&mut self, channels: I) {
251 T::regs().send_cnf(self.number as usize).write(|w| {
252 for channel in channels {
253 w.0 |= channel.mask();
254 }
255 })
256 }
257
258 /// Configure the channels the event will listen on
259 pub fn configure_wait<I: IntoIterator<Item = IpcChannel>>(&mut self, channels: I) {
260 T::regs().receive_cnf(self.number as usize).write(|w| {
261 for channel in channels {
262 w.0 |= channel.mask();
263 }
264 });
265 }
266
267 /// Get the task for the IPC event to use with PPI.
268 pub fn task(&self) -> ppi::Task<'d> {
269 let nr = self.number as usize;
270 let regs = T::regs();
271 ppi::Task::from_reg(regs.tasks_send(nr))
272 }
273
274 /// Get the event for the IPC event to use with PPI.
275 pub fn event(&self) -> ppi::Event<'d> {
276 let nr = self.number as usize;
277 let regs = T::regs();
278 ppi::Event::from_reg(regs.events_receive(nr))
279 }
280
281 /// Reborrow into a "child" Event.
282 ///
283 /// `self` will stay borrowed until the child Event is dropped.
284 pub fn reborrow(&mut self) -> Event<'_, T> {
285 Self { ..*self }
286 }
287
288 /// Steal an IPC event by number.
289 ///
290 /// # Safety
291 ///
292 /// The event number must not be in use by another [`Event`].
293 pub unsafe fn steal(number: EventNumber) -> Self {
294 Self {
295 number,
296 _phantom: PhantomData,
297 }
298 }
299}
300
301/// A handle that can trigger an IPC event.
302///
303/// This `struct` is returned by [`Event::trigger_handle`].
304#[derive(Debug, Copy, Clone)]
305pub struct EventTrigger<'d, T: Instance> {
306 number: EventNumber,
307 _phantom: PhantomData<&'d T>,
308}
309
310impl<T: Instance> EventTrigger<'_, T> {
311 /// Trigger the event.
312 pub fn trigger(&self) {
313 let nr = self.number;
314 T::regs().tasks_send(nr as usize).write_value(1);
315 }
316
317 /// Returns the [`EventNumber`] of the event.
318 pub fn number(&self) -> EventNumber {
319 self.number
320 }
321}
322
323pub(crate) struct State {
324 wakers: [AtomicWaker; EVENT_COUNT],
325}
326
327impl State {
328 pub(crate) const fn new() -> Self {
329 Self {
330 wakers: [const { AtomicWaker::new() }; EVENT_COUNT],
331 }
332 }
333}
334
335pub(crate) trait SealedInstance {
336 fn regs() -> pac::ipc::Ipc;
337 fn state() -> &'static State;
338}
339
340/// IPC peripheral instance.
341#[allow(private_bounds)]
342pub trait Instance: PeripheralType + SealedInstance + 'static + Send {
343 /// Interrupt for this peripheral.
344 type Interrupt: interrupt::typelevel::Interrupt;
345}
346
347macro_rules! impl_ipc {
348 ($type:ident, $pac_type:ident, $irq:ident) => {
349 impl crate::ipc::SealedInstance for peripherals::$type {
350 fn regs() -> pac::ipc::Ipc {
351 pac::$pac_type
352 }
353
354 fn state() -> &'static crate::ipc::State {
355 static STATE: crate::ipc::State = crate::ipc::State::new();
356 &STATE
357 }
358 }
359 impl crate::ipc::Instance for peripherals::$type {
360 type Interrupt = crate::interrupt::typelevel::$irq;
361 }
362 };
363}
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 07ba2f6d4..5bce65a98 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -88,6 +88,8 @@ pub mod gpiote;
88#[cfg(not(feature = "_nrf54l"))] // TODO 88#[cfg(not(feature = "_nrf54l"))] // TODO
89#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] 89#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
90pub mod i2s; 90pub mod i2s;
91#[cfg(feature = "_nrf5340")]
92pub mod ipc;
91#[cfg(not(feature = "_nrf54l"))] // TODO 93#[cfg(not(feature = "_nrf54l"))] // TODO
92#[cfg(any( 94#[cfg(any(
93 feature = "nrf52832", 95 feature = "nrf52832",
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index b440591cf..8fb8a50fd 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -26,7 +26,10 @@ features = ["defmt", "unstable-pac", "time-driver", "rp2040"]
26 26
27[features] 27[features]
28default = [ "rt" ] 28default = [ "rt" ]
29## Enable the rt feature of [`rp-pac`](https://docs.rs/rp-pac). This brings in the [`cortex-m-rt`](https://docs.rs/cortex-m-rt) crate, which adds startup code and minimal runtime initialization. 29
30## Enable the `rt` feature of [`rp-pac`](https://docs.rs/rp-pac).
31## With `rt` enabled the PAC provides interrupt vectors instead of letting [`cortex-m-rt`](https://docs.rs/cortex-m-rt) do that.
32## See <https://docs.rs/cortex-m-rt/latest/cortex_m_rt/#device> for more info.
30rt = [ "rp-pac/rt" ] 33rt = [ "rp-pac/rt" ]
31 34
32## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers. 35## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers.
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 67aa5e540..6694aab66 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -1,4 +1,67 @@
1//! Clock configuration for the RP2040 1//! # Clock configuration for the RP2040 and RP235x microcontrollers.
2//!
3//! # Clock Configuration API
4//!
5//! This module provides both high-level convenience functions and low-level manual
6//! configuration options for the RP2040 clock system.
7//!
8//! ## High-Level Convenience Functions
9//!
10//! For most users, these functions provide an easy way to configure clocks:
11//!
12//! - `ClockConfig::system_freq(125_000_000)` - Set system clock to a specific frequency with automatic voltage scaling
13//! - `ClockConfig::crystal(12_000_000)` - Default configuration with 12MHz crystal giving 125MHz system clock
14//!
15//! ## Manual Configuration
16//!
17//! For advanced users who need precise control:
18//!
19//! ```rust,ignore
20//! // Start with default configuration and customize it
21//! let mut config = ClockConfig::default();
22//!
23//! // Set custom PLL parameters
24//! config.xosc = Some(XoscConfig {
25//! hz: 12_000_000,
26//! sys_pll: Some(PllConfig {
27//! refdiv: 1,
28//! fbdiv: 200,
29//! post_div1: 6,
30//! post_div2: 2,
31//! }),
32//! // ... other fields
33//! });
34//!
35//! // Set voltage for overclocking
36//! config.core_voltage = CoreVoltage::V1_15;
37//! ```
38//!
39//! ## Examples
40//!
41//! ### Standard 125MHz configuration
42//! ```rust,ignore
43//! let config = ClockConfig::crystal(12_000_000);
44//! ```
45//!
46//! Or using the default configuration:
47//! ```rust,ignore
48//! let config = ClockConfig::default();
49//! ```
50//!
51//! ### Overclock to 200MHz
52//! ```rust,ignore
53//! let config = ClockConfig::system_freq(200_000_000);
54//! ```
55//!
56//! ### Manual configuration for advanced scenarios
57//! ```rust,ignore
58//! use embassy_rp::clocks::{ClockConfig, XoscConfig, PllConfig, CoreVoltage};
59//!
60//! // Start with defaults and customize
61//! let mut config = ClockConfig::default();
62//! config.core_voltage = CoreVoltage::V1_15;
63//! // Set other parameters as needed...
64//! ```
2 65
3#[cfg(feature = "rp2040")] 66#[cfg(feature = "rp2040")]
4use core::arch::asm; 67use core::arch::asm;
@@ -18,6 +81,7 @@ use crate::{pac, reset, Peri};
18// gpin is not usually safe to use during the boot init() call, so it won't 81// gpin is not usually safe to use during the boot init() call, so it won't
19// be very useful until we have runtime clock reconfiguration. once this 82// be very useful until we have runtime clock reconfiguration. once this
20// happens we can resurrect the commented-out gpin bits. 83// happens we can resurrect the commented-out gpin bits.
84
21struct Clocks { 85struct Clocks {
22 xosc: AtomicU32, 86 xosc: AtomicU32,
23 sys: AtomicU32, 87 sys: AtomicU32,
@@ -26,6 +90,7 @@ struct Clocks {
26 pll_usb: AtomicU32, 90 pll_usb: AtomicU32,
27 usb: AtomicU32, 91 usb: AtomicU32,
28 adc: AtomicU32, 92 adc: AtomicU32,
93 // See above re gpin handling being commented out
29 // gpin0: AtomicU32, 94 // gpin0: AtomicU32,
30 // gpin1: AtomicU32, 95 // gpin1: AtomicU32,
31 rosc: AtomicU32, 96 rosc: AtomicU32,
@@ -42,6 +107,7 @@ static CLOCKS: Clocks = Clocks {
42 pll_usb: AtomicU32::new(0), 107 pll_usb: AtomicU32::new(0),
43 usb: AtomicU32::new(0), 108 usb: AtomicU32::new(0),
44 adc: AtomicU32::new(0), 109 adc: AtomicU32::new(0),
110 // See above re gpin handling being commented out
45 // gpin0: AtomicU32::new(0), 111 // gpin0: AtomicU32::new(0),
46 // gpin1: AtomicU32::new(0), 112 // gpin1: AtomicU32::new(0),
47 rosc: AtomicU32::new(0), 113 rosc: AtomicU32::new(0),
@@ -65,10 +131,64 @@ pub enum PeriClkSrc {
65 Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH as _, 131 Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH as _,
66 /// XOSC. 132 /// XOSC.
67 Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC as _, 133 Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC as _,
134 // See above re gpin handling being commented out
68 // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0 as _ , 135 // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
69 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , 136 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
70} 137}
71 138
139/// Core voltage regulator settings for RP2040.
140///
141/// The RP2040 voltage regulator can be configured for different output voltages.
142/// Higher voltages allow for higher clock frequencies but increase power consumption and heat.
143#[cfg(feature = "rp2040")]
144#[derive(Clone, Copy, Debug, PartialEq, Eq)]
145#[repr(u8)]
146pub enum CoreVoltage {
147 /// 0.80V - Suitable for lower frequencies
148 V0_80 = 0b0000,
149 /// 0.85V
150 V0_85 = 0b0110,
151 /// 0.90V
152 V0_90 = 0b0111,
153 /// 0.95V
154 V0_95 = 0b1000,
155 /// 1.00V
156 V1_00 = 0b1001,
157 /// 1.05V
158 V1_05 = 0b1010,
159 /// 1.10V - Default voltage level
160 V1_10 = 0b1011,
161 /// 1.15V - Required for overclocking to 133-200MHz
162 V1_15 = 0b1100,
163 /// 1.20V
164 V1_20 = 0b1101,
165 /// 1.25V
166 V1_25 = 0b1110,
167 /// 1.30V
168 V1_30 = 0b1111,
169}
170
171#[cfg(feature = "rp2040")]
172impl CoreVoltage {
173 /// Get the recommended Brown-Out Detection (BOD) setting for this voltage.
174 /// Sets the BOD threshold to approximately 80% of the core voltage.
175 fn recommended_bod(self) -> u8 {
176 match self {
177 CoreVoltage::V0_80 => 0b0100, // 0.645V (~81% of 0.80V)
178 CoreVoltage::V0_85 => 0b0101, // 0.688V (~81% of 0.85V)
179 CoreVoltage::V0_90 => 0b0110, // 0.731V (~81% of 0.90V)
180 CoreVoltage::V0_95 => 0b0111, // 0.774V (~81% of 0.95V)
181 CoreVoltage::V1_00 => 0b1000, // 0.817V (~82% of 1.00V)
182 CoreVoltage::V1_05 => 0b1000, // 0.817V (~78% of 1.05V)
183 CoreVoltage::V1_10 => 0b1001, // 0.860V (~78% of 1.10V)
184 CoreVoltage::V1_15 => 0b1010, // 0.903V (~79% of 1.15V)
185 CoreVoltage::V1_20 => 0b1011, // 0.946V (~79% of 1.20V)
186 CoreVoltage::V1_25 => 0b1100, // 0.989V (~79% of 1.25V)
187 CoreVoltage::V1_30 => 0b1101, // 1.032V (~79% of 1.30V)
188 }
189 }
190}
191
72/// CLock configuration. 192/// CLock configuration.
73#[non_exhaustive] 193#[non_exhaustive]
74pub struct ClockConfig { 194pub struct ClockConfig {
@@ -89,12 +209,63 @@ pub struct ClockConfig {
89 /// RTC clock configuration. 209 /// RTC clock configuration.
90 #[cfg(feature = "rp2040")] 210 #[cfg(feature = "rp2040")]
91 pub rtc_clk: Option<RtcClkConfig>, 211 pub rtc_clk: Option<RtcClkConfig>,
212 /// Core voltage scaling (RP2040 only). Defaults to 1.10V.
213 #[cfg(feature = "rp2040")]
214 pub core_voltage: CoreVoltage,
215 /// Voltage stabilization delay in microseconds.
216 /// If not set, defaults will be used based on voltage level.
217 #[cfg(feature = "rp2040")]
218 pub voltage_stabilization_delay_us: Option<u32>,
219 // See above re gpin handling being commented out
92 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, 220 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>,
93 // gpin1: Option<(u32, Gpin<'static, AnyPin>)>, 221 // gpin1: Option<(u32, Gpin<'static, AnyPin>)>,
94} 222}
95 223
224impl Default for ClockConfig {
225 /// Creates a minimal default configuration with safe values.
226 ///
227 /// This configuration uses the ring oscillator (ROSC) as the clock source
228 /// and sets minimal defaults that guarantee a working system. It's intended
229 /// as a starting point for manual configuration.
230 ///
231 /// Most users should use one of the more specific configuration functions:
232 /// - `ClockConfig::crystal()` - Standard configuration with external crystal
233 /// - `ClockConfig::rosc()` - Configuration using only the internal oscillator
234 /// - `ClockConfig::system_freq()` - Configuration for a specific system frequency
235 fn default() -> Self {
236 Self {
237 rosc: None,
238 xosc: None,
239 ref_clk: RefClkConfig {
240 src: RefClkSrc::Rosc,
241 div: 1,
242 },
243 sys_clk: SysClkConfig {
244 src: SysClkSrc::Rosc,
245 div_int: 1,
246 div_frac: 0,
247 },
248 peri_clk_src: None,
249 usb_clk: None,
250 adc_clk: None,
251 #[cfg(feature = "rp2040")]
252 rtc_clk: None,
253 #[cfg(feature = "rp2040")]
254 core_voltage: CoreVoltage::V1_10,
255 #[cfg(feature = "rp2040")]
256 voltage_stabilization_delay_us: None,
257 // See above re gpin handling being commented out
258 // gpin0: None,
259 // gpin1: None,
260 }
261 }
262}
263
96impl ClockConfig { 264impl ClockConfig {
97 /// Clock configuration derived from external crystal. 265 /// Clock configuration derived from external crystal.
266 ///
267 /// This uses default settings for most parameters, suitable for typical use cases.
268 /// For manual control of PLL parameters, use `new_manual()` or modify the struct fields directly.
98 pub fn crystal(crystal_hz: u32) -> Self { 269 pub fn crystal(crystal_hz: u32) -> Self {
99 Self { 270 Self {
100 rosc: Some(RoscConfig { 271 rosc: Some(RoscConfig {
@@ -152,6 +323,11 @@ impl ClockConfig {
152 div_frac: 0, 323 div_frac: 0,
153 phase: 0, 324 phase: 0,
154 }), 325 }),
326 #[cfg(feature = "rp2040")]
327 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V)
328 #[cfg(feature = "rp2040")]
329 voltage_stabilization_delay_us: None,
330 // See above re gpin handling being commented out
155 // gpin0: None, 331 // gpin0: None,
156 // gpin1: None, 332 // gpin1: None,
157 } 333 }
@@ -192,20 +368,157 @@ impl ClockConfig {
192 div_frac: 171, 368 div_frac: 171,
193 phase: 0, 369 phase: 0,
194 }), 370 }),
371 #[cfg(feature = "rp2040")]
372 core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V)
373 #[cfg(feature = "rp2040")]
374 voltage_stabilization_delay_us: None,
375 // See above re gpin handling being commented out
195 // gpin0: None, 376 // gpin0: None,
196 // gpin1: None, 377 // gpin1: None,
197 } 378 }
198 } 379 }
199 380
200 // pub fn bind_gpin<P: GpinPin>(&mut self, gpin: Gpin<'static, P>, hz: u32) { 381 /// Configure clocks derived from an external crystal with specific system frequency.
201 // match P::NR { 382 ///
202 // 0 => self.gpin0 = Some((hz, gpin.into())), 383 /// This function calculates optimal PLL parameters to achieve the requested system
203 // 1 => self.gpin1 = Some((hz, gpin.into())), 384 /// frequency. This only works for the usual 12MHz crystal. In case a different crystal is used,
204 // _ => unreachable!(), 385 /// You will have to set the PLL parameters manually.
205 // } 386 ///
206 // // pin is now provisionally bound. if the config is applied it must be forgotten, 387 /// # Arguments
207 // // or Gpin::drop will deconfigure the clock input. 388 ///
208 // } 389 /// * `sys_freq_hz` - The desired system clock frequency in Hz
390 ///
391 /// # Returns
392 ///
393 /// A ClockConfig configured to achieve the requested system frequency using the
394 /// the usual 12Mhz crystal, or panic if no valid parameters can be found.
395 ///
396 /// # Note on core voltage:
397 /// To date the only officially documented core voltages (see Datasheet section 2.15.3.1. Instances) are:
398 /// - Up to 133MHz: V1_10 (default)
399 /// - Above 133MHz: V1_15, but in the context of the datasheet covering reaching up to 200Mhz
400 /// That way all other frequencies below 133MHz or above 200MHz are not explicitly documented and not covered here.
401 /// In case You want to go below 133MHz or above 200MHz and want a different voltage, You will have to set that manually and with caution.
402 #[cfg(feature = "rp2040")]
403 pub fn system_freq(hz: u32) -> Self {
404 // Start with the standard configuration from crystal()
405 const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000;
406 let mut config = Self::crystal(DEFAULT_CRYSTAL_HZ);
407
408 // No need to modify anything if target frequency is already 125MHz
409 // (which is what crystal() configures by default)
410 if hz == 125_000_000 {
411 return config;
412 }
413
414 // Find optimal PLL parameters for the requested frequency
415 let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, hz)
416 .unwrap_or_else(|| panic!("Could not find valid PLL parameters for system clock"));
417
418 // Replace the sys_pll configuration with our custom parameters
419 if let Some(xosc) = &mut config.xosc {
420 xosc.sys_pll = Some(sys_pll_params);
421 }
422
423 // Set the voltage scale based on the target frequency
424 // Higher frequencies require higher voltage
425 #[cfg(feature = "rp2040")]
426 {
427 config.core_voltage = match hz {
428 freq if freq > 133_000_000 => CoreVoltage::V1_15,
429 _ => CoreVoltage::V1_10, // Use default voltage (V1_10)
430 };
431 }
432
433 config
434 }
435
436 /// Configure with manual PLL settings for full control over system clock
437 ///
438 /// This method provides a simple way to configure the system with custom PLL parameters
439 /// without needing to understand the full nested configuration structure.
440 ///
441 /// # Arguments
442 ///
443 /// * `xosc_hz` - The frequency of the external crystal in Hz
444 /// * `pll_config` - The PLL configuration parameters to achieve desired frequency
445 /// * `core_voltage` - Voltage scaling for overclocking (required for >133MHz)
446 ///
447 /// # Returns
448 ///
449 /// A ClockConfig configured with the specified PLL parameters
450 ///
451 /// # Example
452 ///
453 /// ```rust,ignore
454 /// // Configure for 200MHz operation
455 /// let config = Config::default();
456 /// config.clocks = ClockConfig::manual_pll(
457 /// 12_000_000,
458 /// PllConfig {
459 /// refdiv: 1, // Reference divider (12 MHz / 1 = 12 MHz)
460 /// fbdiv: 100, // Feedback divider (12 MHz * 100 = 1200 MHz VCO)
461 /// post_div1: 3, // First post divider (1200 MHz / 3 = 400 MHz)
462 /// post_div2: 2, // Second post divider (400 MHz / 2 = 200 MHz)
463 /// },
464 /// CoreVoltage::V1_15
465 /// );
466 /// ```
467 #[cfg(feature = "rp2040")]
468 pub fn manual_pll(xosc_hz: u32, pll_config: PllConfig, core_voltage: CoreVoltage) -> Self {
469 // Validate PLL parameters
470 assert!(pll_config.is_valid(xosc_hz), "Invalid PLL parameters");
471
472 let mut config = Self::default();
473
474 config.xosc = Some(XoscConfig {
475 hz: xosc_hz,
476 sys_pll: Some(pll_config),
477 usb_pll: Some(PllConfig {
478 refdiv: 1,
479 fbdiv: 120,
480 post_div1: 6,
481 post_div2: 5,
482 }),
483 delay_multiplier: 128,
484 });
485
486 config.ref_clk = RefClkConfig {
487 src: RefClkSrc::Xosc,
488 div: 1,
489 };
490
491 config.sys_clk = SysClkConfig {
492 src: SysClkSrc::PllSys,
493 div_int: 1,
494 div_frac: 0,
495 };
496
497 config.core_voltage = core_voltage;
498 config.peri_clk_src = Some(PeriClkSrc::Sys);
499
500 // Set reasonable defaults for other clocks
501 config.usb_clk = Some(UsbClkConfig {
502 src: UsbClkSrc::PllUsb,
503 div: 1,
504 phase: 0,
505 });
506
507 config.adc_clk = Some(AdcClkConfig {
508 src: AdcClkSrc::PllUsb,
509 div: 1,
510 phase: 0,
511 });
512
513 config.rtc_clk = Some(RtcClkConfig {
514 src: RtcClkSrc::PllUsb,
515 div_int: 1024,
516 div_frac: 0,
517 phase: 0,
518 });
519
520 config
521 }
209} 522}
210 523
211/// ROSC freq range. 524/// ROSC freq range.
@@ -251,6 +564,7 @@ pub struct XoscConfig {
251} 564}
252 565
253/// PLL configuration. 566/// PLL configuration.
567#[derive(Clone, Copy, Debug)]
254pub struct PllConfig { 568pub struct PllConfig {
255 /// Reference divisor. 569 /// Reference divisor.
256 pub refdiv: u8, 570 pub refdiv: u8,
@@ -262,6 +576,50 @@ pub struct PllConfig {
262 pub post_div2: u8, 576 pub post_div2: u8,
263} 577}
264 578
579impl PllConfig {
580 /// Calculate the output frequency for this PLL configuration
581 /// given an input frequency.
582 pub fn output_frequency(&self, input_hz: u32) -> u32 {
583 let ref_freq = input_hz / self.refdiv as u32;
584 let vco_freq = ref_freq * self.fbdiv as u32;
585 vco_freq / ((self.post_div1 * self.post_div2) as u32)
586 }
587
588 /// Check if this PLL configuration is valid for the given input frequency.
589 pub fn is_valid(&self, input_hz: u32) -> bool {
590 // Check divisor constraints
591 if self.refdiv < 1 || self.refdiv > 63 {
592 return false;
593 }
594 if self.fbdiv < 16 || self.fbdiv > 320 {
595 return false;
596 }
597 if self.post_div1 < 1 || self.post_div1 > 7 {
598 return false;
599 }
600 if self.post_div2 < 1 || self.post_div2 > 7 {
601 return false;
602 }
603 if self.post_div2 > self.post_div1 {
604 return false;
605 }
606
607 // Calculate reference frequency
608 let ref_freq = input_hz / self.refdiv as u32;
609
610 // Check reference frequency range
611 if ref_freq < 5_000_000 || ref_freq > 800_000_000 {
612 return false;
613 }
614
615 // Calculate VCO frequency
616 let vco_freq = ref_freq * self.fbdiv as u32;
617
618 // Check VCO frequency range
619 vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000
620 }
621}
622
265/// Reference clock config. 623/// Reference clock config.
266pub struct RefClkConfig { 624pub struct RefClkConfig {
267 /// Reference clock source. 625 /// Reference clock source.
@@ -280,6 +638,7 @@ pub enum RefClkSrc {
280 Rosc, 638 Rosc,
281 /// PLL USB. 639 /// PLL USB.
282 PllUsb, 640 PllUsb,
641 // See above re gpin handling being commented out
283 // Gpin0, 642 // Gpin0,
284 // Gpin1, 643 // Gpin1,
285} 644}
@@ -298,6 +657,7 @@ pub enum SysClkSrc {
298 Rosc, 657 Rosc,
299 /// XOSC. 658 /// XOSC.
300 Xosc, 659 Xosc,
660 // See above re gpin handling being commented out
301 // Gpin0, 661 // Gpin0,
302 // Gpin1, 662 // Gpin1,
303} 663}
@@ -333,6 +693,7 @@ pub enum UsbClkSrc {
333 Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH as _, 693 Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH as _,
334 /// XOSC. 694 /// XOSC.
335 Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC as _, 695 Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC as _,
696 // See above re gpin handling being commented out
336 // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0 as _ , 697 // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
337 // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1 as _ , 698 // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
338} 699}
@@ -360,6 +721,7 @@ pub enum AdcClkSrc {
360 Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH as _, 721 Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH as _,
361 /// XOSC. 722 /// XOSC.
362 Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC as _, 723 Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC as _,
724 // See above re gpin handling being commented out
363 // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0 as _ , 725 // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
364 // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1 as _ , 726 // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
365} 727}
@@ -388,6 +750,7 @@ pub enum RtcClkSrc {
388 Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH as _, 750 Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH as _,
389 /// XOSC. 751 /// XOSC.
390 Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC as _, 752 Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC as _,
753 // See above re gpin handling being commented out
391 // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 as _ , 754 // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
392 // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 as _ , 755 // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
393} 756}
@@ -405,6 +768,103 @@ pub struct RtcClkConfig {
405 pub phase: u8, 768 pub phase: u8,
406} 769}
407 770
771/// Find valid PLL parameters (refdiv, fbdiv, post_div1, post_div2) for a target output frequency
772/// based on the input frequency.
773///
774/// This function searches for the best PLL configuration to achieve the requested target frequency
775/// while staying within the VCO frequency range of 750MHz to 1800MHz. It prioritizes stability
776/// over exact frequency matching by using larger divisors where possible.
777///
778/// # Parameters
779///
780/// * `input_hz`: The input frequency in Hz (typically the crystal frequency, e.g. 12MHz for th most common one used on rp2040 boards)
781/// * `target_hz`: The desired output frequency in Hz (e.g. 125MHz for standard RP2040 operation)
782///
783/// # Returns
784///
785/// * `Some(PllConfig)` if valid parameters were found
786/// * `None` if no valid parameters could be found for the requested combination
787///
788/// # Example
789///
790/// ```rust,ignore
791/// // Find parameters for 133MHz system clock from 12MHz crystal
792/// let pll_params = find_pll_params(12_000_000, 133_000_000).unwrap();
793/// ```
794#[cfg(feature = "rp2040")]
795fn find_pll_params(input_hz: u32, target_hz: u32) -> Option<PllConfig> {
796 // Fixed reference divider for system PLL
797 const PLL_SYS_REFDIV: u8 = 1;
798
799 // Calculate reference frequency
800 let reference_freq = input_hz as u64 / PLL_SYS_REFDIV as u64;
801
802 // Start from highest fbdiv for better stability (like SDK does)
803 for fbdiv in (16..=320).rev() {
804 let vco_freq = reference_freq * fbdiv;
805
806 // Check VCO frequency is within valid range
807 if vco_freq < 750_000_000 || vco_freq > 1_800_000_000 {
808 continue;
809 }
810
811 // Try all possible postdiv combinations starting from larger values
812 // (more conservative/stable approach)
813 for post_div1 in (1..=7).rev() {
814 for post_div2 in (1..=post_div1).rev() {
815 let out_freq = vco_freq / (post_div1 * post_div2);
816
817 // Check if we get the exact target frequency without remainder
818 if out_freq == target_hz as u64 && (vco_freq % (post_div1 * post_div2) == 0) {
819 return Some(PllConfig {
820 refdiv: PLL_SYS_REFDIV,
821 fbdiv: fbdiv as u16,
822 post_div1: post_div1 as u8,
823 post_div2: post_div2 as u8,
824 });
825 }
826 }
827 }
828 }
829
830 // If we couldn't find an exact match, find the closest match
831 let mut best_config = None;
832 let mut min_diff = u32::MAX;
833
834 for fbdiv in (16..=320).rev() {
835 let vco_freq = reference_freq * fbdiv;
836
837 if vco_freq < 750_000_000 || vco_freq > 1_800_000_000 {
838 continue;
839 }
840
841 for post_div1 in (1..=7).rev() {
842 for post_div2 in (1..=post_div1).rev() {
843 let out_freq = (vco_freq / (post_div1 * post_div2) as u64) as u32;
844 let diff = if out_freq > target_hz {
845 out_freq - target_hz
846 } else {
847 target_hz - out_freq
848 };
849
850 // If this is closer to the target, save it
851 if diff < min_diff {
852 min_diff = diff;
853 best_config = Some(PllConfig {
854 refdiv: PLL_SYS_REFDIV,
855 fbdiv: fbdiv as u16,
856 post_div1: post_div1 as u8,
857 post_div2: post_div2 as u8,
858 });
859 }
860 }
861 }
862 }
863
864 // Return the closest match if we found one
865 best_config
866}
867
408/// safety: must be called exactly once at bootup 868/// safety: must be called exactly once at bootup
409pub(crate) unsafe fn init(config: ClockConfig) { 869pub(crate) unsafe fn init(config: ClockConfig) {
410 // Reset everything except: 870 // Reset everything except:
@@ -447,6 +907,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
447 reset::reset(peris); 907 reset::reset(peris);
448 reset::unreset_wait(peris); 908 reset::unreset_wait(peris);
449 909
910 // See above re gpin handling being commented out
450 // let gpin0_freq = config.gpin0.map_or(0, |p| { 911 // let gpin0_freq = config.gpin0.map_or(0, |p| {
451 // core::mem::forget(p.1); 912 // core::mem::forget(p.1);
452 // p.0 913 // p.0
@@ -464,19 +925,60 @@ pub(crate) unsafe fn init(config: ClockConfig) {
464 }; 925 };
465 CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed); 926 CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed);
466 927
928 // Set Core Voltage (RP2040 only), if we have config for it and we're not using the default
929 #[cfg(feature = "rp2040")]
930 {
931 let voltage = config.core_voltage;
932 let vreg = pac::VREG_AND_CHIP_RESET;
933 let current_vsel = vreg.vreg().read().vsel();
934 let target_vsel = voltage as u8;
935
936 // If the target voltage is different from the current one, we need to change it
937 if target_vsel != current_vsel {
938 // Use modify() to preserve the HIZ and EN bits - otherwise we will disable the regulator when changing voltage
939 vreg.vreg().modify(|w| w.set_vsel(target_vsel));
940
941 // Wait for the voltage to stabilize. Use the provided delay or default based on voltage
942 let settling_time_us = config.voltage_stabilization_delay_us.unwrap_or_else(|| {
943 match voltage {
944 CoreVoltage::V1_15 => 1000, // 1ms for 1.15V
945 CoreVoltage::V1_20 | CoreVoltage::V1_25 | CoreVoltage::V1_30 => 2000, // 2ms for higher voltages
946 _ => 0, // no delay for all others
947 }
948 });
949
950 if settling_time_us != 0 {
951 // Delay in microseconds, using the ROSC frequency to calculate cycles
952 let cycles_per_us = rosc_freq / 1_000_000;
953 let delay_cycles = settling_time_us * cycles_per_us;
954 cortex_m::asm::delay(delay_cycles);
955 }
956
957 // Only now set the BOD level. At this point the voltage is considered stable.
958 vreg.bod().write(|w| {
959 w.set_vsel(voltage.recommended_bod());
960 w.set_en(true); // Enable brownout detection
961 });
962 }
963 }
964
467 let (xosc_freq, pll_sys_freq, pll_usb_freq) = match config.xosc { 965 let (xosc_freq, pll_sys_freq, pll_usb_freq) = match config.xosc {
468 Some(config) => { 966 Some(config) => {
469 // start XOSC 967 // start XOSC
470 // datasheet mentions support for clock inputs into XIN, but doesn't go into
471 // how this is achieved. pico-sdk doesn't support this at all.
472 start_xosc(config.hz, config.delay_multiplier); 968 start_xosc(config.hz, config.delay_multiplier);
473 969
474 let pll_sys_freq = match config.sys_pll { 970 let pll_sys_freq = match config.sys_pll {
475 Some(sys_pll_config) => configure_pll(pac::PLL_SYS, config.hz, sys_pll_config), 971 Some(sys_pll_config) => match configure_pll(pac::PLL_SYS, config.hz, sys_pll_config) {
972 Ok(freq) => freq,
973 Err(e) => panic!("Failed to configure PLL_SYS: {}", e),
974 },
476 None => 0, 975 None => 0,
477 }; 976 };
478 let pll_usb_freq = match config.usb_pll { 977 let pll_usb_freq = match config.usb_pll {
479 Some(usb_pll_config) => configure_pll(pac::PLL_USB, config.hz, usb_pll_config), 978 Some(usb_pll_config) => match configure_pll(pac::PLL_USB, config.hz, usb_pll_config) {
979 Ok(freq) => freq,
980 Err(e) => panic!("Failed to configure PLL_USB: {}", e),
981 },
480 None => 0, 982 None => 0,
481 }; 983 };
482 984
@@ -484,6 +986,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
484 } 986 }
485 None => (0, 0, 0), 987 None => (0, 0, 0),
486 }; 988 };
989
487 CLOCKS.xosc.store(xosc_freq, Ordering::Relaxed); 990 CLOCKS.xosc.store(xosc_freq, Ordering::Relaxed);
488 CLOCKS.pll_sys.store(pll_sys_freq, Ordering::Relaxed); 991 CLOCKS.pll_sys.store(pll_sys_freq, Ordering::Relaxed);
489 CLOCKS.pll_usb.store(pll_usb_freq, Ordering::Relaxed); 992 CLOCKS.pll_usb.store(pll_usb_freq, Ordering::Relaxed);
@@ -496,6 +999,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
496 RefClkSrc::Xosc => (Src::XOSC_CLKSRC, Aux::CLKSRC_PLL_USB, xosc_freq / div), 999 RefClkSrc::Xosc => (Src::XOSC_CLKSRC, Aux::CLKSRC_PLL_USB, xosc_freq / div),
497 RefClkSrc::Rosc => (Src::ROSC_CLKSRC_PH, Aux::CLKSRC_PLL_USB, rosc_freq / div), 1000 RefClkSrc::Rosc => (Src::ROSC_CLKSRC_PH, Aux::CLKSRC_PLL_USB, rosc_freq / div),
498 RefClkSrc::PllUsb => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq / div), 1001 RefClkSrc::PllUsb => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq / div),
1002 // See above re gpin handling being commented out
499 // RefClkSrc::Gpin0 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN0, gpin0_freq / div), 1003 // RefClkSrc::Gpin0 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN0, gpin0_freq / div),
500 // RefClkSrc::Gpin1 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN1, gpin1_freq / div), 1004 // RefClkSrc::Gpin1 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN1, gpin1_freq / div),
501 } 1005 }
@@ -540,6 +1044,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
540 SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq), 1044 SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq),
541 SysClkSrc::Rosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::ROSC_CLKSRC, rosc_freq), 1045 SysClkSrc::Rosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::ROSC_CLKSRC, rosc_freq),
542 SysClkSrc::Xosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::XOSC_CLKSRC, xosc_freq), 1046 SysClkSrc::Xosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::XOSC_CLKSRC, xosc_freq),
1047 // See above re gpin handling being commented out
543 // SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq), 1048 // SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq),
544 // SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1, gpin1_freq), 1049 // SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1, gpin1_freq),
545 }; 1050 };
@@ -583,6 +1088,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
583 PeriClkSrc::PllUsb => pll_usb_freq, 1088 PeriClkSrc::PllUsb => pll_usb_freq,
584 PeriClkSrc::Rosc => rosc_freq, 1089 PeriClkSrc::Rosc => rosc_freq,
585 PeriClkSrc::Xosc => xosc_freq, 1090 PeriClkSrc::Xosc => xosc_freq,
1091 // See above re gpin handling being commented out
586 // PeriClkSrc::Gpin0 => gpin0_freq, 1092 // PeriClkSrc::Gpin0 => gpin0_freq,
587 // PeriClkSrc::Gpin1 => gpin1_freq, 1093 // PeriClkSrc::Gpin1 => gpin1_freq,
588 }; 1094 };
@@ -608,6 +1114,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
608 UsbClkSrc::PllSys => pll_sys_freq, 1114 UsbClkSrc::PllSys => pll_sys_freq,
609 UsbClkSrc::Rosc => rosc_freq, 1115 UsbClkSrc::Rosc => rosc_freq,
610 UsbClkSrc::Xosc => xosc_freq, 1116 UsbClkSrc::Xosc => xosc_freq,
1117 // See above re gpin handling being commented out
611 // UsbClkSrc::Gpin0 => gpin0_freq, 1118 // UsbClkSrc::Gpin0 => gpin0_freq,
612 // UsbClkSrc::Gpin1 => gpin1_freq, 1119 // UsbClkSrc::Gpin1 => gpin1_freq,
613 }; 1120 };
@@ -631,6 +1138,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
631 AdcClkSrc::PllSys => pll_sys_freq, 1138 AdcClkSrc::PllSys => pll_sys_freq,
632 AdcClkSrc::Rosc => rosc_freq, 1139 AdcClkSrc::Rosc => rosc_freq,
633 AdcClkSrc::Xosc => xosc_freq, 1140 AdcClkSrc::Xosc => xosc_freq,
1141 // See above re gpin handling being commented out
634 // AdcClkSrc::Gpin0 => gpin0_freq, 1142 // AdcClkSrc::Gpin0 => gpin0_freq,
635 // AdcClkSrc::Gpin1 => gpin1_freq, 1143 // AdcClkSrc::Gpin1 => gpin1_freq,
636 }; 1144 };
@@ -659,6 +1167,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
659 RtcClkSrc::PllSys => pll_sys_freq, 1167 RtcClkSrc::PllSys => pll_sys_freq,
660 RtcClkSrc::Rosc => rosc_freq, 1168 RtcClkSrc::Rosc => rosc_freq,
661 RtcClkSrc::Xosc => xosc_freq, 1169 RtcClkSrc::Xosc => xosc_freq,
1170 // See above re gpin handling being commented out
662 // RtcClkSrc::Gpin0 => gpin0_freq, 1171 // RtcClkSrc::Gpin0 => gpin0_freq,
663 // RtcClkSrc::Gpin1 => gpin1_freq, 1172 // RtcClkSrc::Gpin1 => gpin1_freq,
664 }; 1173 };
@@ -725,6 +1234,7 @@ pub fn xosc_freq() -> u32 {
725 CLOCKS.xosc.load(Ordering::Relaxed) 1234 CLOCKS.xosc.load(Ordering::Relaxed)
726} 1235}
727 1236
1237// See above re gpin handling being commented out
728// pub fn gpin0_freq() -> u32 { 1238// pub fn gpin0_freq() -> u32 {
729// CLOCKS.gpin0.load(Ordering::Relaxed) 1239// CLOCKS.gpin0.load(Ordering::Relaxed)
730// } 1240// }
@@ -783,46 +1293,100 @@ fn start_xosc(crystal_hz: u32, delay_multiplier: u32) {
783 while !pac::XOSC.status().read().stable() {} 1293 while !pac::XOSC.status().read().stable() {}
784} 1294}
785 1295
1296/// PLL (Phase-Locked Loop) configuration
786#[inline(always)] 1297#[inline(always)]
787fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { 1298fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result<u32, &'static str> {
1299 // Calculate reference frequency
788 let ref_freq = input_freq / config.refdiv as u32; 1300 let ref_freq = input_freq / config.refdiv as u32;
1301
1302 // Validate PLL parameters
1303 // Feedback divider (FBDIV) must be between 16 and 320
789 assert!(config.fbdiv >= 16 && config.fbdiv <= 320); 1304 assert!(config.fbdiv >= 16 && config.fbdiv <= 320);
1305
1306 // Post divider 1 (POSTDIV1) must be between 1 and 7
790 assert!(config.post_div1 >= 1 && config.post_div1 <= 7); 1307 assert!(config.post_div1 >= 1 && config.post_div1 <= 7);
1308
1309 // Post divider 2 (POSTDIV2) must be between 1 and 7
791 assert!(config.post_div2 >= 1 && config.post_div2 <= 7); 1310 assert!(config.post_div2 >= 1 && config.post_div2 <= 7);
1311
1312 // Post divider 2 (POSTDIV2) must be less than or equal to post divider 1 (POSTDIV1)
1313 assert!(config.post_div2 <= config.post_div1);
1314
1315 // Reference divider (REFDIV) must be between 1 and 63
792 assert!(config.refdiv >= 1 && config.refdiv <= 63); 1316 assert!(config.refdiv >= 1 && config.refdiv <= 63);
1317
1318 // Reference frequency (REF_FREQ) must be between 5MHz and 800MHz
793 assert!(ref_freq >= 5_000_000 && ref_freq <= 800_000_000); 1319 assert!(ref_freq >= 5_000_000 && ref_freq <= 800_000_000);
1320
1321 // Calculate VCO frequency
794 let vco_freq = ref_freq.saturating_mul(config.fbdiv as u32); 1322 let vco_freq = ref_freq.saturating_mul(config.fbdiv as u32);
1323
1324 // VCO (Voltage Controlled Oscillator) frequency must be between 750MHz and 1800MHz
795 assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000); 1325 assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000);
796 1326
797 // Load VCO-related dividers before starting VCO 1327 // We follow the SDK's approach to PLL configuration which is:
1328 // 1. Power down PLL
1329 // 2. Configure the reference divider
1330 // 3. Configure the feedback divider
1331 // 4. Power up PLL and VCO
1332 // 5. Wait for PLL to lock
1333 // 6. Configure post-dividers
1334 // 7. Enable post-divider output
1335
1336 // 1. Power down PLL before configuration
1337 p.pwr().write(|w| {
1338 w.set_pd(true); // Power down the PLL
1339 w.set_vcopd(true); // Power down the VCO
1340 w.set_postdivpd(true); // Power down the post divider
1341 w.set_dsmpd(true); // Disable fractional mode
1342 *w
1343 });
1344
1345 // Short delay after powering down
1346 cortex_m::asm::delay(10);
1347
1348 // 2. Configure reference divider first
798 p.cs().write(|w| w.set_refdiv(config.refdiv as _)); 1349 p.cs().write(|w| w.set_refdiv(config.refdiv as _));
1350
1351 // 3. Configure feedback divider
799 p.fbdiv_int().write(|w| w.set_fbdiv_int(config.fbdiv)); 1352 p.fbdiv_int().write(|w| w.set_fbdiv_int(config.fbdiv));
800 1353
801 // Turn on PLL 1354 // 4. Power up PLL and VCO, but keep post divider powered down during initial lock
802 let pwr = p.pwr().write(|w| { 1355 p.pwr().write(|w| {
803 w.set_dsmpd(true); // "nothing is achieved by setting this low" 1356 w.set_pd(false); // Power up the PLL
804 w.set_pd(false); 1357 w.set_vcopd(false); // Power up the VCO
805 w.set_vcopd(false); 1358 w.set_postdivpd(true); // Keep post divider powered down during initial lock
806 w.set_postdivpd(true); 1359 w.set_dsmpd(true); // Disable fractional mode (simpler configuration)
807 *w 1360 *w
808 }); 1361 });
809 1362
810 // Wait for PLL to lock 1363 // 5. Wait for PLL to lock with a timeout
811 while !p.cs().read().lock() {} 1364 let mut timeout = 1_000_000;
1365 while !p.cs().read().lock() {
1366 timeout -= 1;
1367 if timeout == 0 {
1368 // PLL failed to lock, return 0 to indicate failure
1369 return Err("PLL failed to lock");
1370 }
1371 }
812 1372
813 // Set post-dividers 1373 // 6. Configure post dividers after PLL is locked
814 p.prim().write(|w| { 1374 p.prim().write(|w| {
815 w.set_postdiv1(config.post_div1); 1375 w.set_postdiv1(config.post_div1);
816 w.set_postdiv2(config.post_div2); 1376 w.set_postdiv2(config.post_div2);
817 }); 1377 });
818 1378
819 // Turn on post divider 1379 // 7. Enable the post divider output
820 p.pwr().write(|w| { 1380 p.pwr().modify(|w| {
821 *w = pwr; 1381 w.set_postdivpd(false); // Power up post divider
822 w.set_postdivpd(false); 1382 *w
823 }); 1383 });
824 1384
825 vco_freq / ((config.post_div1 * config.post_div2) as u32) 1385 // Final delay to ensure everything is stable
1386 cortex_m::asm::delay(100);
1387
1388 // Calculate and return actual output frequency
1389 Ok(vco_freq / ((config.post_div1 * config.post_div2) as u32))
826} 1390}
827 1391
828/// General purpose input clock pin. 1392/// General purpose input clock pin.
@@ -906,6 +1470,7 @@ impl_gpoutpin!(PIN_25, 3);
906pub enum GpoutSrc { 1470pub enum GpoutSrc {
907 /// Sys PLL. 1471 /// Sys PLL.
908 PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS as _, 1472 PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS as _,
1473 // See above re gpin handling being commented out
909 // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 as _ , 1474 // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
910 // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 as _ , 1475 // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
911 /// USB PLL. 1476 /// USB PLL.
@@ -1001,6 +1566,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
1001 1566
1002 let base = match src { 1567 let base = match src {
1003 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), 1568 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
1569 // See above re gpin handling being commented out
1004 // ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), 1570 // ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(),
1005 // ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), 1571 // ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(),
1006 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), 1572 ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(),
@@ -1009,7 +1575,6 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
1009 ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(), 1575 ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(),
1010 ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(), 1576 ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(),
1011 ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(), 1577 ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(),
1012 //ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq() as _,
1013 ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(), 1578 ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(),
1014 _ => unreachable!(), 1579 _ => unreachable!(),
1015 }; 1580 };
@@ -1069,6 +1634,7 @@ impl rand_core::RngCore for RoscRng {
1069 dest.fill_with(Self::next_u8) 1634 dest.fill_with(Self::next_u8)
1070 } 1635 }
1071} 1636}
1637
1072/// Enter the `DORMANT` sleep state. This will stop *all* internal clocks 1638/// Enter the `DORMANT` sleep state. This will stop *all* internal clocks
1073/// and can only be exited through resets, dormant-wake GPIO interrupts, 1639/// and can only be exited through resets, dormant-wake GPIO interrupts,
1074/// and RTC interrupts. If RTC is clocked from an internal clock source 1640/// and RTC interrupts. If RTC is clocked from an internal clock source
@@ -1197,3 +1763,196 @@ pub fn dormant_sleep() {
1197 } 1763 }
1198 } 1764 }
1199} 1765}
1766
1767#[cfg(test)]
1768mod tests {
1769 use super::*;
1770
1771 #[cfg(feature = "rp2040")]
1772 #[test]
1773 fn test_find_pll_params() {
1774 #[cfg(feature = "rp2040")]
1775 {
1776 // Test standard 125 MHz configuration with 12 MHz crystal
1777 let params = find_pll_params(12_000_000, 125_000_000).unwrap();
1778 assert_eq!(params.refdiv, 1);
1779 assert_eq!(params.fbdiv, 125);
1780
1781 // Test USB PLL configuration for 48MHz
1782 // The algorithm may find different valid parameters than the SDK defaults
1783 // We'll check that it generates a valid configuration that produces 48MHz
1784 let params = find_pll_params(12_000_000, 48_000_000).unwrap();
1785 assert_eq!(params.refdiv, 1);
1786
1787 // Calculate the actual output frequency
1788 let ref_freq = 12_000_000 / params.refdiv as u32;
1789 let vco_freq = ref_freq as u64 * params.fbdiv as u64;
1790 let output_freq = (vco_freq / ((params.post_div1 * params.post_div2) as u64)) as u32;
1791
1792 // Verify the output frequency is correct
1793 assert_eq!(output_freq, 48_000_000);
1794
1795 // Verify VCO frequency is in valid range
1796 assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000);
1797
1798 // Test overclocked configuration for 200 MHz
1799 let params = find_pll_params(12_000_000, 200_000_000).unwrap();
1800 assert_eq!(params.refdiv, 1);
1801 let vco_freq = 12_000_000 as u64 * params.fbdiv as u64;
1802 let output_freq = (vco_freq / ((params.post_div1 * params.post_div2) as u64)) as u32;
1803 assert_eq!(output_freq, 200_000_000);
1804 assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000); // VCO in valid range
1805
1806 // Test non-standard crystal with 16 MHz
1807 let params = find_pll_params(16_000_000, 125_000_000).unwrap();
1808 let vco_freq = (16_000_000 / params.refdiv as u32) as u64 * params.fbdiv as u64;
1809 let output_freq = (vco_freq / ((params.post_div1 * params.post_div2) as u64)) as u32;
1810
1811 // Test non-standard crystal with 15 MHz
1812 let params = find_pll_params(15_000_000, 125_000_000).unwrap();
1813 let vco_freq = (15_000_000 / params.refdiv as u32) as u64 * params.fbdiv as u64;
1814 let output_freq = (vco_freq / ((params.post_div1 * params.post_div2) as u64)) as u32;
1815
1816 // With a 15 MHz crystal, we might not get exactly 125 MHz
1817 // Check that it's close enough (within 0.2% margin)
1818 let freq_diff = if output_freq > 125_000_000 {
1819 output_freq - 125_000_000
1820 } else {
1821 125_000_000 - output_freq
1822 };
1823 let error_percentage = (freq_diff as f64 / 125_000_000.0) * 100.0;
1824 assert!(
1825 error_percentage < 0.2,
1826 "Output frequency {} is not close enough to target 125 MHz. Error: {:.2}%",
1827 output_freq,
1828 error_percentage
1829 );
1830
1831 assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000);
1832 }
1833 }
1834
1835 #[cfg(feature = "rp2040")]
1836 #[test]
1837 fn test_pll_config_validation() {
1838 // Test PLL configuration validation logic
1839 let valid_config = PllConfig {
1840 refdiv: 1,
1841 fbdiv: 125,
1842 post_div1: 6,
1843 post_div2: 2,
1844 };
1845
1846 // Valid configuration should pass validation
1847 assert!(valid_config.is_valid(12_000_000));
1848
1849 // Test fbdiv constraints
1850 let mut invalid_config = valid_config;
1851 invalid_config.fbdiv = 15; // Below minimum of 16
1852 assert!(!invalid_config.is_valid(12_000_000));
1853
1854 invalid_config.fbdiv = 321; // Above maximum of 320
1855 assert!(!invalid_config.is_valid(12_000_000));
1856
1857 // Test post_div constraints
1858 invalid_config = valid_config;
1859 invalid_config.post_div1 = 0; // Below minimum of 1
1860 assert!(!invalid_config.is_valid(12_000_000));
1861
1862 invalid_config = valid_config;
1863 invalid_config.post_div1 = 8; // Above maximum of 7
1864 assert!(!invalid_config.is_valid(12_000_000));
1865
1866 // Test post_div2 must be <= post_div1
1867 invalid_config = valid_config;
1868 invalid_config.post_div2 = 7;
1869 invalid_config.post_div1 = 3;
1870 assert!(!invalid_config.is_valid(12_000_000));
1871
1872 // Test reference frequency constraints
1873 invalid_config = valid_config;
1874 assert!(!invalid_config.is_valid(4_000_000)); // Below minimum of 5 MHz
1875 assert!(!invalid_config.is_valid(900_000_000)); // Above maximum of 800 MHz
1876
1877 // Test VCO frequency constraints
1878 invalid_config = valid_config;
1879 invalid_config.fbdiv = 16;
1880 assert!(!invalid_config.is_valid(12_000_000)); // VCO too low: 12MHz * 16 = 192MHz
1881
1882 // Test VCO frequency constraints - too high
1883 invalid_config = valid_config;
1884 invalid_config.fbdiv = 200;
1885 invalid_config.refdiv = 1;
1886 // This should be INVALID: 12MHz * 200 = 2400MHz exceeds max VCO of 1800MHz
1887 assert!(!invalid_config.is_valid(12_000_000));
1888
1889 // Test a valid high VCO configuration
1890 invalid_config.fbdiv = 150; // 12MHz * 150 = 1800MHz, exactly at the limit
1891 assert!(invalid_config.is_valid(12_000_000));
1892 }
1893
1894 #[cfg(feature = "rp2040")]
1895 #[test]
1896 fn test_manual_pll_helper() {
1897 {
1898 // Test the new manual_pll helper method
1899 let config = ClockConfig::manual_pll(
1900 12_000_000,
1901 PllConfig {
1902 refdiv: 1,
1903 fbdiv: 100,
1904 post_div1: 3,
1905 post_div2: 2,
1906 },
1907 CoreVoltage::V1_15,
1908 );
1909
1910 // Check voltage scale was set correctly
1911 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
1912
1913 // Check PLL config was set correctly
1914 assert_eq!(config.xosc.as_ref().unwrap().sys_pll.as_ref().unwrap().refdiv, 1);
1915 assert_eq!(config.xosc.as_ref().unwrap().sys_pll.as_ref().unwrap().fbdiv, 100);
1916 assert_eq!(config.xosc.as_ref().unwrap().sys_pll.as_ref().unwrap().post_div1, 3);
1917 assert_eq!(config.xosc.as_ref().unwrap().sys_pll.as_ref().unwrap().post_div2, 2);
1918
1919 // Check we get the expected frequency
1920 assert_eq!(
1921 config
1922 .xosc
1923 .as_ref()
1924 .unwrap()
1925 .sys_pll
1926 .as_ref()
1927 .unwrap()
1928 .output_frequency(12_000_000),
1929 200_000_000
1930 );
1931 }
1932 }
1933
1934 #[cfg(feature = "rp2040")]
1935 #[test]
1936 fn test_auto_voltage_scaling() {
1937 {
1938 // Test automatic voltage scaling based on frequency
1939 // Under 133 MHz should use default voltage (V1_10)
1940 let config = ClockConfig::system_freq(125_000_000);
1941 assert_eq!(config.core_voltage, CoreVoltage::V1_10);
1942
1943 // 133-200 MHz should use V1_15
1944 let config = ClockConfig::system_freq(150_000_000);
1945 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
1946 let config = ClockConfig::system_freq(200_000_000);
1947 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
1948
1949 // Above 200 MHz should use V1_25
1950 let config = ClockConfig::system_freq(250_000_000);
1951 assert_eq!(config.core_voltage, CoreVoltage::V1_15);
1952
1953 // Below 125 MHz should use V1_10
1954 let config = ClockConfig::system_freq(100_000_000);
1955 assert_eq!(config.core_voltage, CoreVoltage::V1_10);
1956 }
1957 }
1958}
diff --git a/embassy-rp/src/pio_programs/clock_divider.rs b/embassy-rp/src/pio_programs/clock_divider.rs
new file mode 100644
index 000000000..02e353f53
--- /dev/null
+++ b/embassy-rp/src/pio_programs/clock_divider.rs
@@ -0,0 +1,25 @@
1//! Helper functions for calculating PIO clock dividers
2
3use fixed::traits::ToFixed;
4use fixed::types::extra::U8;
5
6use crate::clocks::clk_sys_freq;
7
8/// Calculate a PIO clock divider value based on the desired target frequency.
9///
10/// # Arguments
11///
12/// * `target_hz` - The desired PIO clock frequency in Hz
13///
14/// # Returns
15///
16/// A fixed-point divider value suitable for use in a PIO state machine configuration
17#[inline]
18pub fn calculate_pio_clock_divider(target_hz: u32) -> fixed::FixedU32<U8> {
19 // Requires a non-zero frequency
20 assert!(target_hz > 0, "PIO clock frequency cannot be zero");
21
22 // Calculate the divider
23 let divider = (clk_sys_freq() + target_hz / 2) / target_hz;
24 divider.to_fixed()
25}
diff --git a/embassy-rp/src/pio_programs/hd44780.rs b/embassy-rp/src/pio_programs/hd44780.rs
index 5846a8027..546c85a89 100644
--- a/embassy-rp/src/pio_programs/hd44780.rs
+++ b/embassy-rp/src/pio_programs/hd44780.rs
@@ -5,6 +5,7 @@ use crate::pio::{
5 Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, 5 Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection,
6 StateMachine, 6 StateMachine,
7}; 7};
8use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
8use crate::Peri; 9use crate::Peri;
9 10
10/// This struct represents a HD44780 program that takes command words (<wait:24> <command:4> <0:4>) 11/// This struct represents a HD44780 program that takes command words (<wait:24> <command:4> <0:4>)
@@ -134,7 +135,10 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> {
134 135
135 let mut cfg = Config::default(); 136 let mut cfg = Config::default();
136 cfg.use_program(&word_prg.prg, &[&e]); 137 cfg.use_program(&word_prg.prg, &[&e]);
137 cfg.clock_divider = 125u8.into(); 138
139 // Target 1 MHz PIO clock (each cycle is 1µs)
140 cfg.clock_divider = calculate_pio_clock_divider(1_000_000);
141
138 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); 142 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
139 cfg.shift_out = ShiftConfig { 143 cfg.shift_out = ShiftConfig {
140 auto_fill: true, 144 auto_fill: true,
@@ -160,7 +164,10 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> {
160 164
161 let mut cfg = Config::default(); 165 let mut cfg = Config::default();
162 cfg.use_program(&seq_prg.prg, &[&e]); 166 cfg.use_program(&seq_prg.prg, &[&e]);
163 cfg.clock_divider = 8u8.into(); // ~64ns/insn 167
168 // Target ~15.6 MHz PIO clock (~64ns/insn)
169 cfg.clock_divider = calculate_pio_clock_divider(15_600_000);
170
164 cfg.set_jmp_pin(&db7); 171 cfg.set_jmp_pin(&db7);
165 cfg.set_set_pins(&[&rs, &rw]); 172 cfg.set_set_pins(&[&rs, &rw]);
166 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); 173 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
diff --git a/embassy-rp/src/pio_programs/mod.rs b/embassy-rp/src/pio_programs/mod.rs
index 74537825b..8eac328b3 100644
--- a/embassy-rp/src/pio_programs/mod.rs
+++ b/embassy-rp/src/pio_programs/mod.rs
@@ -1,5 +1,6 @@
1//! Pre-built pio programs for common interfaces 1//! Pre-built pio programs for common interfaces
2 2
3pub mod clock_divider;
3pub mod hd44780; 4pub mod hd44780;
4pub mod i2s; 5pub mod i2s;
5pub mod onewire; 6pub mod onewire;
diff --git a/embassy-rp/src/pio_programs/rotary_encoder.rs b/embassy-rp/src/pio_programs/rotary_encoder.rs
index e520da8a3..70b3795e9 100644
--- a/embassy-rp/src/pio_programs/rotary_encoder.rs
+++ b/embassy-rp/src/pio_programs/rotary_encoder.rs
@@ -1,11 +1,10 @@
1//! PIO backed quadrature encoder 1//! PIO backed quadrature encoder
2 2
3use fixed::traits::ToFixed;
4
5use crate::gpio::Pull; 3use crate::gpio::Pull;
6use crate::pio::{ 4use crate::pio::{
7 Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine, 5 Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine,
8}; 6};
7use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
9use crate::Peri; 8use crate::Peri;
10 9
11/// This struct represents an Encoder program loaded into pio instruction memory. 10/// This struct represents an Encoder program loaded into pio instruction memory.
@@ -48,7 +47,10 @@ impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> {
48 cfg.set_in_pins(&[&pin_a, &pin_b]); 47 cfg.set_in_pins(&[&pin_a, &pin_b]);
49 cfg.fifo_join = FifoJoin::RxOnly; 48 cfg.fifo_join = FifoJoin::RxOnly;
50 cfg.shift_in.direction = ShiftDirection::Left; 49 cfg.shift_in.direction = ShiftDirection::Left;
51 cfg.clock_divider = 10_000.to_fixed(); 50
51 // Target 12.5 KHz PIO clock
52 cfg.clock_divider = calculate_pio_clock_divider(12_500);
53
52 cfg.use_program(&program.prg, &[]); 54 cfg.use_program(&program.prg, &[]);
53 sm.set_config(&cfg); 55 sm.set_config(&cfg);
54 sm.set_enable(true); 56 sm.set_enable(true);
diff --git a/embassy-rp/src/pio_programs/stepper.rs b/embassy-rp/src/pio_programs/stepper.rs
index 495191659..0e9a8daf9 100644
--- a/embassy-rp/src/pio_programs/stepper.rs
+++ b/embassy-rp/src/pio_programs/stepper.rs
@@ -2,11 +2,8 @@
2 2
3use core::mem::{self, MaybeUninit}; 3use core::mem::{self, MaybeUninit};
4 4
5use fixed::traits::ToFixed;
6use fixed::types::extra::U8;
7use fixed::FixedU32;
8
9use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine}; 5use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine};
6use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
10use crate::Peri; 7use crate::Peri;
11 8
12/// This struct represents a Stepper driver program loaded into pio instruction memory. 9/// This struct represents a Stepper driver program loaded into pio instruction memory.
@@ -64,7 +61,9 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> {
64 sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]); 61 sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]);
65 let mut cfg = Config::default(); 62 let mut cfg = Config::default();
66 cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]); 63 cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]);
67 cfg.clock_divider = (125_000_000 / (100 * 136)).to_fixed(); 64
65 cfg.clock_divider = calculate_pio_clock_divider(100 * 136);
66
68 cfg.use_program(&program.prg, &[]); 67 cfg.use_program(&program.prg, &[]);
69 sm.set_config(&cfg); 68 sm.set_config(&cfg);
70 sm.set_enable(true); 69 sm.set_enable(true);
@@ -73,9 +72,11 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> {
73 72
74 /// Set pulse frequency 73 /// Set pulse frequency
75 pub fn set_frequency(&mut self, freq: u32) { 74 pub fn set_frequency(&mut self, freq: u32) {
76 let clock_divider: FixedU32<U8> = (125_000_000 / (freq * 136)).to_fixed(); 75 let clock_divider = calculate_pio_clock_divider(freq * 136);
77 assert!(clock_divider <= 65536, "clkdiv must be <= 65536"); 76 let divider_f32 = clock_divider.to_num::<f32>();
78 assert!(clock_divider >= 1, "clkdiv must be >= 1"); 77 assert!(divider_f32 <= 65536.0, "clkdiv must be <= 65536");
78 assert!(divider_f32 >= 1.0, "clkdiv must be >= 1");
79
79 self.sm.set_clock_divider(clock_divider); 80 self.sm.set_clock_divider(clock_divider);
80 self.sm.clkdiv_restart(); 81 self.sm.clkdiv_restart();
81 } 82 }
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
index da18138b5..02649ad81 100644
--- a/embassy-rp/src/uart/buffered.rs
+++ b/embassy-rp/src/uart/buffered.rs
@@ -34,28 +34,29 @@ impl State {
34} 34}
35 35
36/// Buffered UART driver. 36/// Buffered UART driver.
37pub struct BufferedUart<'d, T: Instance> { 37pub struct BufferedUart {
38 pub(crate) rx: BufferedUartRx<'d, T>, 38 pub(super) rx: BufferedUartRx,
39 pub(crate) tx: BufferedUartTx<'d, T>, 39 pub(super) tx: BufferedUartTx,
40} 40}
41 41
42/// Buffered UART RX handle. 42/// Buffered UART RX handle.
43pub struct BufferedUartRx<'d, T: Instance> { 43pub struct BufferedUartRx {
44 pub(crate) phantom: PhantomData<&'d mut T>, 44 pub(super) info: &'static Info,
45 pub(super) state: &'static State,
45} 46}
46 47
47/// Buffered UART TX handle. 48/// Buffered UART TX handle.
48pub struct BufferedUartTx<'d, T: Instance> { 49pub struct BufferedUartTx {
49 pub(crate) phantom: PhantomData<&'d mut T>, 50 pub(super) info: &'static Info,
51 pub(super) state: &'static State,
50} 52}
51 53
52pub(crate) fn init_buffers<'d, T: Instance + 'd>( 54pub(super) fn init_buffers<'d>(
53 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 55 info: &Info,
56 state: &State,
54 tx_buffer: Option<&'d mut [u8]>, 57 tx_buffer: Option<&'d mut [u8]>,
55 rx_buffer: Option<&'d mut [u8]>, 58 rx_buffer: Option<&'d mut [u8]>,
56) { 59) {
57 let state = T::buffered_state();
58
59 if let Some(tx_buffer) = tx_buffer { 60 if let Some(tx_buffer) = tx_buffer {
60 let len = tx_buffer.len(); 61 let len = tx_buffer.len();
61 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; 62 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
@@ -76,61 +77,73 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>(
76 // This means we can leave the interrupt enabled the whole time as long as 77 // This means we can leave the interrupt enabled the whole time as long as
77 // we clear it after it happens. The downside is that the we manually have 78 // we clear it after it happens. The downside is that the we manually have
78 // to pend the ISR when we want data transmission to start. 79 // to pend the ISR when we want data transmission to start.
79 let regs = T::regs(); 80 info.regs.uartimsc().write(|w| {
80 regs.uartimsc().write(|w| {
81 w.set_rxim(true); 81 w.set_rxim(true);
82 w.set_rtim(true); 82 w.set_rtim(true);
83 w.set_txim(true); 83 w.set_txim(true);
84 }); 84 });
85 85
86 T::Interrupt::unpend(); 86 info.interrupt.unpend();
87 unsafe { T::Interrupt::enable() }; 87 unsafe { info.interrupt.enable() };
88} 88}
89 89
90impl<'d, T: Instance> BufferedUart<'d, T> { 90impl BufferedUart {
91 /// Create a buffered UART instance. 91 /// Create a buffered UART instance.
92 pub fn new( 92 pub fn new<'d, T: Instance>(
93 _uart: Peri<'d, T>, 93 _uart: Peri<'d, T>,
94 tx: Peri<'d, impl TxPin<T>>, 94 tx: Peri<'d, impl TxPin<T>>,
95 rx: Peri<'d, impl RxPin<T>>, 95 rx: Peri<'d, impl RxPin<T>>,
96 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 96 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
97 tx_buffer: &'d mut [u8], 97 tx_buffer: &'d mut [u8],
98 rx_buffer: &'d mut [u8], 98 rx_buffer: &'d mut [u8],
99 config: Config, 99 config: Config,
100 ) -> Self { 100 ) -> Self {
101 super::Uart::<'d, T, Async>::init(Some(tx.into()), Some(rx.into()), None, None, config); 101 super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), Some(rx.into()), None, None, config);
102 init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer)); 102 init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), Some(rx_buffer));
103 103
104 Self { 104 Self {
105 rx: BufferedUartRx { phantom: PhantomData }, 105 rx: BufferedUartRx {
106 tx: BufferedUartTx { phantom: PhantomData }, 106 info: T::info(),
107 state: T::buffered_state(),
108 },
109 tx: BufferedUartTx {
110 info: T::info(),
111 state: T::buffered_state(),
112 },
107 } 113 }
108 } 114 }
109 115
110 /// Create a buffered UART instance with flow control. 116 /// Create a buffered UART instance with flow control.
111 pub fn new_with_rtscts( 117 pub fn new_with_rtscts<'d, T: Instance>(
112 _uart: Peri<'d, T>, 118 _uart: Peri<'d, T>,
113 tx: Peri<'d, impl TxPin<T>>, 119 tx: Peri<'d, impl TxPin<T>>,
114 rx: Peri<'d, impl RxPin<T>>, 120 rx: Peri<'d, impl RxPin<T>>,
115 rts: Peri<'d, impl RtsPin<T>>, 121 rts: Peri<'d, impl RtsPin<T>>,
116 cts: Peri<'d, impl CtsPin<T>>, 122 cts: Peri<'d, impl CtsPin<T>>,
117 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 123 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
118 tx_buffer: &'d mut [u8], 124 tx_buffer: &'d mut [u8],
119 rx_buffer: &'d mut [u8], 125 rx_buffer: &'d mut [u8],
120 config: Config, 126 config: Config,
121 ) -> Self { 127 ) -> Self {
122 super::Uart::<'d, T, Async>::init( 128 super::Uart::<'d, Async>::init(
129 T::info(),
123 Some(tx.into()), 130 Some(tx.into()),
124 Some(rx.into()), 131 Some(rx.into()),
125 Some(rts.into()), 132 Some(rts.into()),
126 Some(cts.into()), 133 Some(cts.into()),
127 config, 134 config,
128 ); 135 );
129 init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer)); 136 init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), Some(rx_buffer));
130 137
131 Self { 138 Self {
132 rx: BufferedUartRx { phantom: PhantomData }, 139 rx: BufferedUartRx {
133 tx: BufferedUartTx { phantom: PhantomData }, 140 info: T::info(),
141 state: T::buffered_state(),
142 },
143 tx: BufferedUartTx {
144 info: T::info(),
145 state: T::buffered_state(),
146 },
134 } 147 }
135 } 148 }
136 149
@@ -160,68 +173,75 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
160 } 173 }
161 174
162 /// sets baudrate on runtime 175 /// sets baudrate on runtime
163 pub fn set_baudrate(&mut self, baudrate: u32) { 176 pub fn set_baudrate<'d>(&mut self, baudrate: u32) {
164 super::Uart::<'d, T, Async>::set_baudrate_inner(baudrate); 177 super::Uart::<'d, Async>::set_baudrate_inner(self.rx.info, baudrate);
165 } 178 }
166 179
167 /// Split into separate RX and TX handles. 180 /// Split into separate RX and TX handles.
168 pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { 181 pub fn split(self) -> (BufferedUartTx, BufferedUartRx) {
169 (self.tx, self.rx) 182 (self.tx, self.rx)
170 } 183 }
171 184
172 /// Split the Uart into a transmitter and receiver by mutable reference, 185 /// Split the Uart into a transmitter and receiver by mutable reference,
173 /// which is particularly useful when having two tasks correlating to 186 /// which is particularly useful when having two tasks correlating to
174 /// transmitting and receiving. 187 /// transmitting and receiving.
175 pub fn split_ref(&mut self) -> (&mut BufferedUartTx<'d, T>, &mut BufferedUartRx<'d, T>) { 188 pub fn split_ref(&mut self) -> (&mut BufferedUartTx, &mut BufferedUartRx) {
176 (&mut self.tx, &mut self.rx) 189 (&mut self.tx, &mut self.rx)
177 } 190 }
178} 191}
179 192
180impl<'d, T: Instance> BufferedUartRx<'d, T> { 193impl BufferedUartRx {
181 /// Create a new buffered UART RX. 194 /// Create a new buffered UART RX.
182 pub fn new( 195 pub fn new<'d, T: Instance>(
183 _uart: Peri<'d, T>, 196 _uart: Peri<'d, T>,
184 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 197 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
185 rx: Peri<'d, impl RxPin<T>>, 198 rx: Peri<'d, impl RxPin<T>>,
186 rx_buffer: &'d mut [u8], 199 rx_buffer: &'d mut [u8],
187 config: Config, 200 config: Config,
188 ) -> Self { 201 ) -> Self {
189 super::Uart::<'d, T, Async>::init(None, Some(rx.into()), None, None, config); 202 super::Uart::<'d, Async>::init(T::info(), None, Some(rx.into()), None, None, config);
190 init_buffers::<T>(irq, None, Some(rx_buffer)); 203 init_buffers(T::info(), T::buffered_state(), None, Some(rx_buffer));
191 204
192 Self { phantom: PhantomData } 205 Self {
206 info: T::info(),
207 state: T::buffered_state(),
208 }
193 } 209 }
194 210
195 /// Create a new buffered UART RX with flow control. 211 /// Create a new buffered UART RX with flow control.
196 pub fn new_with_rts( 212 pub fn new_with_rts<'d, T: Instance>(
197 _uart: Peri<'d, T>, 213 _uart: Peri<'d, T>,
198 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 214 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
199 rx: Peri<'d, impl RxPin<T>>, 215 rx: Peri<'d, impl RxPin<T>>,
200 rts: Peri<'d, impl RtsPin<T>>, 216 rts: Peri<'d, impl RtsPin<T>>,
201 rx_buffer: &'d mut [u8], 217 rx_buffer: &'d mut [u8],
202 config: Config, 218 config: Config,
203 ) -> Self { 219 ) -> Self {
204 super::Uart::<'d, T, Async>::init(None, Some(rx.into()), Some(rts.into()), None, config); 220 super::Uart::<'d, Async>::init(T::info(), None, Some(rx.into()), Some(rts.into()), None, config);
205 init_buffers::<T>(irq, None, Some(rx_buffer)); 221 init_buffers(T::info(), T::buffered_state(), None, Some(rx_buffer));
206 222
207 Self { phantom: PhantomData } 223 Self {
224 info: T::info(),
225 state: T::buffered_state(),
226 }
208 } 227 }
209 228
210 fn read<'a>(buf: &'a mut [u8]) -> impl Future<Output = Result<usize, Error>> + 'a 229 fn read<'a>(
211 where 230 info: &'static Info,
212 T: 'd, 231 state: &'static State,
213 { 232 buf: &'a mut [u8],
233 ) -> impl Future<Output = Result<usize, Error>> + 'a {
214 poll_fn(move |cx| { 234 poll_fn(move |cx| {
215 if let Poll::Ready(r) = Self::try_read(buf) { 235 if let Poll::Ready(r) = Self::try_read(info, state, buf) {
216 return Poll::Ready(r); 236 return Poll::Ready(r);
217 } 237 }
218 T::buffered_state().rx_waker.register(cx.waker()); 238 state.rx_waker.register(cx.waker());
219 Poll::Pending 239 Poll::Pending
220 }) 240 })
221 } 241 }
222 242
223 fn get_rx_error() -> Option<Error> { 243 fn get_rx_error(state: &State) -> Option<Error> {
224 let errs = T::buffered_state().rx_error.swap(0, Ordering::Relaxed); 244 let errs = state.rx_error.swap(0, Ordering::Relaxed);
225 if errs & RXE_OVERRUN != 0 { 245 if errs & RXE_OVERRUN != 0 {
226 Some(Error::Overrun) 246 Some(Error::Overrun)
227 } else if errs & RXE_BREAK != 0 { 247 } else if errs & RXE_BREAK != 0 {
@@ -235,15 +255,11 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
235 } 255 }
236 } 256 }
237 257
238 fn try_read(buf: &mut [u8]) -> Poll<Result<usize, Error>> 258 fn try_read(info: &Info, state: &State, buf: &mut [u8]) -> Poll<Result<usize, Error>> {
239 where
240 T: 'd,
241 {
242 if buf.is_empty() { 259 if buf.is_empty() {
243 return Poll::Ready(Ok(0)); 260 return Poll::Ready(Ok(0));
244 } 261 }
245 262
246 let state = T::buffered_state();
247 let mut rx_reader = unsafe { state.rx_buf.reader() }; 263 let mut rx_reader = unsafe { state.rx_buf.reader() };
248 let n = rx_reader.pop(|data| { 264 let n = rx_reader.pop(|data| {
249 let n = data.len().min(buf.len()); 265 let n = data.len().min(buf.len());
@@ -252,7 +268,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
252 }); 268 });
253 269
254 let result = if n == 0 { 270 let result = if n == 0 {
255 match Self::get_rx_error() { 271 match Self::get_rx_error(state) {
256 None => return Poll::Pending, 272 None => return Poll::Pending,
257 Some(e) => Err(e), 273 Some(e) => Err(e),
258 } 274 }
@@ -262,8 +278,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
262 278
263 // (Re-)Enable the interrupt to receive more data in case it was 279 // (Re-)Enable the interrupt to receive more data in case it was
264 // disabled because the buffer was full or errors were detected. 280 // disabled because the buffer was full or errors were detected.
265 let regs = T::regs(); 281 info.regs.uartimsc().write_set(|w| {
266 regs.uartimsc().write_set(|w| {
267 w.set_rxim(true); 282 w.set_rxim(true);
268 w.set_rtim(true); 283 w.set_rtim(true);
269 }); 284 });
@@ -274,23 +289,19 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
274 /// Read from UART RX buffer blocking execution until done. 289 /// Read from UART RX buffer blocking execution until done.
275 pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { 290 pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
276 loop { 291 loop {
277 match Self::try_read(buf) { 292 match Self::try_read(self.info, self.state, buf) {
278 Poll::Ready(res) => return res, 293 Poll::Ready(res) => return res,
279 Poll::Pending => continue, 294 Poll::Pending => continue,
280 } 295 }
281 } 296 }
282 } 297 }
283 298
284 fn fill_buf<'a>() -> impl Future<Output = Result<&'a [u8], Error>> 299 fn fill_buf<'a>(state: &'static State) -> impl Future<Output = Result<&'a [u8], Error>> {
285 where
286 T: 'd,
287 {
288 poll_fn(move |cx| { 300 poll_fn(move |cx| {
289 let state = T::buffered_state();
290 let mut rx_reader = unsafe { state.rx_buf.reader() }; 301 let mut rx_reader = unsafe { state.rx_buf.reader() };
291 let (p, n) = rx_reader.pop_buf(); 302 let (p, n) = rx_reader.pop_buf();
292 let result = if n == 0 { 303 let result = if n == 0 {
293 match Self::get_rx_error() { 304 match Self::get_rx_error(state) {
294 None => { 305 None => {
295 state.rx_waker.register(cx.waker()); 306 state.rx_waker.register(cx.waker());
296 return Poll::Pending; 307 return Poll::Pending;
@@ -306,64 +317,70 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
306 }) 317 })
307 } 318 }
308 319
309 fn consume(amt: usize) { 320 fn consume(info: &Info, state: &State, amt: usize) {
310 let state = T::buffered_state();
311 let mut rx_reader = unsafe { state.rx_buf.reader() }; 321 let mut rx_reader = unsafe { state.rx_buf.reader() };
312 rx_reader.pop_done(amt); 322 rx_reader.pop_done(amt);
313 323
314 // (Re-)Enable the interrupt to receive more data in case it was 324 // (Re-)Enable the interrupt to receive more data in case it was
315 // disabled because the buffer was full or errors were detected. 325 // disabled because the buffer was full or errors were detected.
316 let regs = T::regs(); 326 info.regs.uartimsc().write_set(|w| {
317 regs.uartimsc().write_set(|w| {
318 w.set_rxim(true); 327 w.set_rxim(true);
319 w.set_rtim(true); 328 w.set_rtim(true);
320 }); 329 });
321 } 330 }
322 331
323 /// we are ready to read if there is data in the buffer 332 /// we are ready to read if there is data in the buffer
324 fn read_ready() -> Result<bool, Error> { 333 fn read_ready(state: &State) -> Result<bool, Error> {
325 let state = T::buffered_state();
326 Ok(!state.rx_buf.is_empty()) 334 Ok(!state.rx_buf.is_empty())
327 } 335 }
328} 336}
329 337
330impl<'d, T: Instance> BufferedUartTx<'d, T> { 338impl BufferedUartTx {
331 /// Create a new buffered UART TX. 339 /// Create a new buffered UART TX.
332 pub fn new( 340 pub fn new<'d, T: Instance>(
333 _uart: Peri<'d, T>, 341 _uart: Peri<'d, T>,
334 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 342 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
335 tx: Peri<'d, impl TxPin<T>>, 343 tx: Peri<'d, impl TxPin<T>>,
336 tx_buffer: &'d mut [u8], 344 tx_buffer: &'d mut [u8],
337 config: Config, 345 config: Config,
338 ) -> Self { 346 ) -> Self {
339 super::Uart::<'d, T, Async>::init(Some(tx.into()), None, None, None, config); 347 super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), None, None, None, config);
340 init_buffers::<T>(irq, Some(tx_buffer), None); 348 init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), None);
341 349
342 Self { phantom: PhantomData } 350 Self {
351 info: T::info(),
352 state: T::buffered_state(),
353 }
343 } 354 }
344 355
345 /// Create a new buffered UART TX with flow control. 356 /// Create a new buffered UART TX with flow control.
346 pub fn new_with_cts( 357 pub fn new_with_cts<'d, T: Instance>(
347 _uart: Peri<'d, T>, 358 _uart: Peri<'d, T>,
348 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 359 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
349 tx: Peri<'d, impl TxPin<T>>, 360 tx: Peri<'d, impl TxPin<T>>,
350 cts: Peri<'d, impl CtsPin<T>>, 361 cts: Peri<'d, impl CtsPin<T>>,
351 tx_buffer: &'d mut [u8], 362 tx_buffer: &'d mut [u8],
352 config: Config, 363 config: Config,
353 ) -> Self { 364 ) -> Self {
354 super::Uart::<'d, T, Async>::init(Some(tx.into()), None, None, Some(cts.into()), config); 365 super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), None, None, Some(cts.into()), config);
355 init_buffers::<T>(irq, Some(tx_buffer), None); 366 init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), None);
356 367
357 Self { phantom: PhantomData } 368 Self {
369 info: T::info(),
370 state: T::buffered_state(),
371 }
358 } 372 }
359 373
360 fn write(buf: &[u8]) -> impl Future<Output = Result<usize, Error>> + '_ { 374 fn write<'d>(
375 info: &'static Info,
376 state: &'static State,
377 buf: &'d [u8],
378 ) -> impl Future<Output = Result<usize, Error>> + 'd {
361 poll_fn(move |cx| { 379 poll_fn(move |cx| {
362 if buf.is_empty() { 380 if buf.is_empty() {
363 return Poll::Ready(Ok(0)); 381 return Poll::Ready(Ok(0));
364 } 382 }
365 383
366 let state = T::buffered_state();
367 let mut tx_writer = unsafe { state.tx_buf.writer() }; 384 let mut tx_writer = unsafe { state.tx_buf.writer() };
368 let n = tx_writer.push(|data| { 385 let n = tx_writer.push(|data| {
369 let n = data.len().min(buf.len()); 386 let n = data.len().min(buf.len());
@@ -379,14 +396,13 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
379 // FIFO and the number of bytes drops below a threshold. When the 396 // FIFO and the number of bytes drops below a threshold. When the
380 // FIFO was empty we have to manually pend the interrupt to shovel 397 // FIFO was empty we have to manually pend the interrupt to shovel
381 // TX data from the buffer into the FIFO. 398 // TX data from the buffer into the FIFO.
382 T::Interrupt::pend(); 399 info.interrupt.pend();
383 Poll::Ready(Ok(n)) 400 Poll::Ready(Ok(n))
384 }) 401 })
385 } 402 }
386 403
387 fn flush() -> impl Future<Output = Result<(), Error>> { 404 fn flush(state: &'static State) -> impl Future<Output = Result<(), Error>> {
388 poll_fn(move |cx| { 405 poll_fn(move |cx| {
389 let state = T::buffered_state();
390 if !state.tx_buf.is_empty() { 406 if !state.tx_buf.is_empty() {
391 state.tx_waker.register(cx.waker()); 407 state.tx_waker.register(cx.waker());
392 return Poll::Pending; 408 return Poll::Pending;
@@ -403,8 +419,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
403 } 419 }
404 420
405 loop { 421 loop {
406 let state = T::buffered_state(); 422 let mut tx_writer = unsafe { self.state.tx_buf.writer() };
407 let mut tx_writer = unsafe { state.tx_buf.writer() };
408 let n = tx_writer.push(|data| { 423 let n = tx_writer.push(|data| {
409 let n = data.len().min(buf.len()); 424 let n = data.len().min(buf.len());
410 data[..n].copy_from_slice(&buf[..n]); 425 data[..n].copy_from_slice(&buf[..n]);
@@ -416,7 +431,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
416 // FIFO and the number of bytes drops below a threshold. When the 431 // FIFO and the number of bytes drops below a threshold. When the
417 // FIFO was empty we have to manually pend the interrupt to shovel 432 // FIFO was empty we have to manually pend the interrupt to shovel
418 // TX data from the buffer into the FIFO. 433 // TX data from the buffer into the FIFO.
419 T::Interrupt::pend(); 434 self.info.interrupt.pend();
420 return Ok(n); 435 return Ok(n);
421 } 436 }
422 } 437 }
@@ -425,8 +440,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
425 /// Flush UART TX blocking execution until done. 440 /// Flush UART TX blocking execution until done.
426 pub fn blocking_flush(&mut self) -> Result<(), Error> { 441 pub fn blocking_flush(&mut self) -> Result<(), Error> {
427 loop { 442 loop {
428 let state = T::buffered_state(); 443 if self.state.tx_buf.is_empty() {
429 if state.tx_buf.is_empty() {
430 return Ok(()); 444 return Ok(());
431 } 445 }
432 } 446 }
@@ -434,7 +448,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
434 448
435 /// Check if UART is busy. 449 /// Check if UART is busy.
436 pub fn busy(&self) -> bool { 450 pub fn busy(&self) -> bool {
437 T::regs().uartfr().read().busy() 451 self.info.regs.uartfr().read().busy()
438 } 452 }
439 453
440 /// Assert a break condition after waiting for the transmit buffers to empty, 454 /// Assert a break condition after waiting for the transmit buffers to empty,
@@ -445,7 +459,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
445 /// This method may block for a long amount of time since it has to wait 459 /// This method may block for a long amount of time since it has to wait
446 /// for the transmit fifo to empty, which may take a while on slow links. 460 /// for the transmit fifo to empty, which may take a while on slow links.
447 pub async fn send_break(&mut self, bits: u32) { 461 pub async fn send_break(&mut self, bits: u32) {
448 let regs = T::regs(); 462 let regs = self.info.regs;
449 let bits = bits.max({ 463 let bits = bits.max({
450 let lcr = regs.uartlcr_h().read(); 464 let lcr = regs.uartlcr_h().read();
451 let width = lcr.wlen() as u32 + 5; 465 let width = lcr.wlen() as u32 + 5;
@@ -458,7 +472,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
458 let div_clk = clk_peri_freq() as u64 * 64; 472 let div_clk = clk_peri_freq() as u64 * 64;
459 let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; 473 let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk;
460 474
461 Self::flush().await.unwrap(); 475 Self::flush(self.state).await.unwrap();
462 while self.busy() {} 476 while self.busy() {}
463 regs.uartlcr_h().write_set(|w| w.set_brk(true)); 477 regs.uartlcr_h().write_set(|w| w.set_brk(true));
464 Timer::after_micros(wait_usecs).await; 478 Timer::after_micros(wait_usecs).await;
@@ -466,28 +480,26 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
466 } 480 }
467} 481}
468 482
469impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { 483impl Drop for BufferedUartRx {
470 fn drop(&mut self) { 484 fn drop(&mut self) {
471 let state = T::buffered_state(); 485 unsafe { self.state.rx_buf.deinit() }
472 unsafe { state.rx_buf.deinit() }
473 486
474 // TX is inactive if the buffer is not available. 487 // TX is inactive if the buffer is not available.
475 // We can now unregister the interrupt handler 488 // We can now unregister the interrupt handler
476 if !state.tx_buf.is_available() { 489 if !self.state.tx_buf.is_available() {
477 T::Interrupt::disable(); 490 self.info.interrupt.disable();
478 } 491 }
479 } 492 }
480} 493}
481 494
482impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> { 495impl Drop for BufferedUartTx {
483 fn drop(&mut self) { 496 fn drop(&mut self) {
484 let state = T::buffered_state(); 497 unsafe { self.state.tx_buf.deinit() }
485 unsafe { state.tx_buf.deinit() }
486 498
487 // RX is inactive if the buffer is not available. 499 // RX is inactive if the buffer is not available.
488 // We can now unregister the interrupt handler 500 // We can now unregister the interrupt handler
489 if !state.rx_buf.is_available() { 501 if !self.state.rx_buf.is_available() {
490 T::Interrupt::disable(); 502 self.info.interrupt.disable();
491 } 503 }
492 } 504 }
493} 505}
@@ -499,7 +511,7 @@ pub struct BufferedInterruptHandler<T: Instance> {
499 511
500impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterruptHandler<T> { 512impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterruptHandler<T> {
501 unsafe fn on_interrupt() { 513 unsafe fn on_interrupt() {
502 let r = T::regs(); 514 let r = T::info().regs;
503 if r.uartdmacr().read().rxdmae() { 515 if r.uartdmacr().read().rxdmae() {
504 return; 516 return;
505 } 517 }
@@ -603,95 +615,95 @@ impl embedded_io::Error for Error {
603 } 615 }
604} 616}
605 617
606impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUart<'d, T> { 618impl embedded_io_async::ErrorType for BufferedUart {
607 type Error = Error; 619 type Error = Error;
608} 620}
609 621
610impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUartRx<'d, T> { 622impl embedded_io_async::ErrorType for BufferedUartRx {
611 type Error = Error; 623 type Error = Error;
612} 624}
613 625
614impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUartTx<'d, T> { 626impl embedded_io_async::ErrorType for BufferedUartTx {
615 type Error = Error; 627 type Error = Error;
616} 628}
617 629
618impl<'d, T: Instance + 'd> embedded_io_async::Read for BufferedUart<'d, T> { 630impl embedded_io_async::Read for BufferedUart {
619 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 631 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
620 BufferedUartRx::<'d, T>::read(buf).await 632 BufferedUartRx::read(self.rx.info, self.rx.state, buf).await
621 } 633 }
622} 634}
623 635
624impl<'d, T: Instance + 'd> embedded_io_async::Read for BufferedUartRx<'d, T> { 636impl embedded_io_async::Read for BufferedUartRx {
625 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 637 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
626 Self::read(buf).await 638 Self::read(self.info, self.state, buf).await
627 } 639 }
628} 640}
629 641
630impl<'d, T: Instance + 'd> embedded_io_async::ReadReady for BufferedUart<'d, T> { 642impl embedded_io_async::ReadReady for BufferedUart {
631 fn read_ready(&mut self) -> Result<bool, Self::Error> { 643 fn read_ready(&mut self) -> Result<bool, Self::Error> {
632 BufferedUartRx::<'d, T>::read_ready() 644 BufferedUartRx::read_ready(self.rx.state)
633 } 645 }
634} 646}
635 647
636impl<'d, T: Instance + 'd> embedded_io_async::ReadReady for BufferedUartRx<'d, T> { 648impl embedded_io_async::ReadReady for BufferedUartRx {
637 fn read_ready(&mut self) -> Result<bool, Self::Error> { 649 fn read_ready(&mut self) -> Result<bool, Self::Error> {
638 Self::read_ready() 650 Self::read_ready(self.state)
639 } 651 }
640} 652}
641 653
642impl<'d, T: Instance + 'd> embedded_io_async::BufRead for BufferedUart<'d, T> { 654impl embedded_io_async::BufRead for BufferedUart {
643 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { 655 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
644 BufferedUartRx::<'d, T>::fill_buf().await 656 BufferedUartRx::fill_buf(self.rx.state).await
645 } 657 }
646 658
647 fn consume(&mut self, amt: usize) { 659 fn consume(&mut self, amt: usize) {
648 BufferedUartRx::<'d, T>::consume(amt) 660 BufferedUartRx::consume(self.rx.info, self.rx.state, amt)
649 } 661 }
650} 662}
651 663
652impl<'d, T: Instance + 'd> embedded_io_async::BufRead for BufferedUartRx<'d, T> { 664impl embedded_io_async::BufRead for BufferedUartRx {
653 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { 665 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
654 Self::fill_buf().await 666 Self::fill_buf(self.state).await
655 } 667 }
656 668
657 fn consume(&mut self, amt: usize) { 669 fn consume(&mut self, amt: usize) {
658 Self::consume(amt) 670 Self::consume(self.info, self.state, amt)
659 } 671 }
660} 672}
661 673
662impl<'d, T: Instance + 'd> embedded_io_async::Write for BufferedUart<'d, T> { 674impl embedded_io_async::Write for BufferedUart {
663 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 675 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
664 BufferedUartTx::<'d, T>::write(buf).await 676 BufferedUartTx::write(self.tx.info, self.tx.state, buf).await
665 } 677 }
666 678
667 async fn flush(&mut self) -> Result<(), Self::Error> { 679 async fn flush(&mut self) -> Result<(), Self::Error> {
668 BufferedUartTx::<'d, T>::flush().await 680 BufferedUartTx::flush(self.tx.state).await
669 } 681 }
670} 682}
671 683
672impl<'d, T: Instance + 'd> embedded_io_async::Write for BufferedUartTx<'d, T> { 684impl embedded_io_async::Write for BufferedUartTx {
673 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 685 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
674 Self::write(buf).await 686 Self::write(self.info, self.state, buf).await
675 } 687 }
676 688
677 async fn flush(&mut self) -> Result<(), Self::Error> { 689 async fn flush(&mut self) -> Result<(), Self::Error> {
678 Self::flush().await 690 Self::flush(self.state).await
679 } 691 }
680} 692}
681 693
682impl<'d, T: Instance + 'd> embedded_io::Read for BufferedUart<'d, T> { 694impl embedded_io::Read for BufferedUart {
683 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 695 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
684 self.rx.blocking_read(buf) 696 self.rx.blocking_read(buf)
685 } 697 }
686} 698}
687 699
688impl<'d, T: Instance + 'd> embedded_io::Read for BufferedUartRx<'d, T> { 700impl embedded_io::Read for BufferedUartRx {
689 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 701 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
690 self.blocking_read(buf) 702 self.blocking_read(buf)
691 } 703 }
692} 704}
693 705
694impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUart<'d, T> { 706impl embedded_io::Write for BufferedUart {
695 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 707 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
696 self.tx.blocking_write(buf) 708 self.tx.blocking_write(buf)
697 } 709 }
@@ -701,7 +713,7 @@ impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUart<'d, T> {
701 } 713 }
702} 714}
703 715
704impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUartTx<'d, T> { 716impl embedded_io::Write for BufferedUartTx {
705 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 717 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
706 self.blocking_write(buf) 718 self.blocking_write(buf)
707 } 719 }
@@ -711,11 +723,11 @@ impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUartTx<'d, T> {
711 } 723 }
712} 724}
713 725
714impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUartRx<'d, T> { 726impl embedded_hal_02::serial::Read<u8> for BufferedUartRx {
715 type Error = Error; 727 type Error = Error;
716 728
717 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 729 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
718 let r = T::regs(); 730 let r = self.info.regs;
719 if r.uartfr().read().rxfe() { 731 if r.uartfr().read().rxfe() {
720 return Err(nb::Error::WouldBlock); 732 return Err(nb::Error::WouldBlock);
721 } 733 }
@@ -736,7 +748,7 @@ impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUartRx<'d, T
736 } 748 }
737} 749}
738 750
739impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUartTx<'d, T> { 751impl embedded_hal_02::blocking::serial::Write<u8> for BufferedUartTx {
740 type Error = Error; 752 type Error = Error;
741 753
742 fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> { 754 fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> {
@@ -755,7 +767,7 @@ impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedU
755 } 767 }
756} 768}
757 769
758impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUart<'d, T> { 770impl embedded_hal_02::serial::Read<u8> for BufferedUart {
759 type Error = Error; 771 type Error = Error;
760 772
761 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 773 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
@@ -763,7 +775,7 @@ impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUart<'d, T>
763 } 775 }
764} 776}
765 777
766impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUart<'d, T> { 778impl embedded_hal_02::blocking::serial::Write<u8> for BufferedUart {
767 type Error = Error; 779 type Error = Error;
768 780
769 fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> { 781 fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> {
@@ -782,25 +794,25 @@ impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedU
782 } 794 }
783} 795}
784 796
785impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUartRx<'d, T> { 797impl embedded_hal_nb::serial::ErrorType for BufferedUartRx {
786 type Error = Error; 798 type Error = Error;
787} 799}
788 800
789impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUartTx<'d, T> { 801impl embedded_hal_nb::serial::ErrorType for BufferedUartTx {
790 type Error = Error; 802 type Error = Error;
791} 803}
792 804
793impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUart<'d, T> { 805impl embedded_hal_nb::serial::ErrorType for BufferedUart {
794 type Error = Error; 806 type Error = Error;
795} 807}
796 808
797impl<'d, T: Instance> embedded_hal_nb::serial::Read for BufferedUartRx<'d, T> { 809impl embedded_hal_nb::serial::Read for BufferedUartRx {
798 fn read(&mut self) -> nb::Result<u8, Self::Error> { 810 fn read(&mut self) -> nb::Result<u8, Self::Error> {
799 embedded_hal_02::serial::Read::read(self) 811 embedded_hal_02::serial::Read::read(self)
800 } 812 }
801} 813}
802 814
803impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> { 815impl embedded_hal_nb::serial::Write for BufferedUartTx {
804 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 816 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
805 self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) 817 self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
806 } 818 }
@@ -810,13 +822,13 @@ impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> {
810 } 822 }
811} 823}
812 824
813impl<'d, T: Instance> embedded_hal_nb::serial::Read for BufferedUart<'d, T> { 825impl embedded_hal_nb::serial::Read for BufferedUart {
814 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 826 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
815 embedded_hal_02::serial::Read::read(&mut self.rx) 827 embedded_hal_02::serial::Read::read(&mut self.rx)
816 } 828 }
817} 829}
818 830
819impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUart<'d, T> { 831impl embedded_hal_nb::serial::Write for BufferedUart {
820 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 832 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
821 self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) 833 self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other)
822 } 834 }
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index 7ce074a3f..c3a15fda5 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -13,7 +13,8 @@ use pac::uart::regs::Uartris;
13use crate::clocks::clk_peri_freq; 13use crate::clocks::clk_peri_freq;
14use crate::dma::{AnyChannel, Channel}; 14use crate::dma::{AnyChannel, Channel};
15use crate::gpio::{AnyPin, SealedPin}; 15use crate::gpio::{AnyPin, SealedPin};
16use crate::interrupt::typelevel::{Binding, Interrupt}; 16use crate::interrupt::typelevel::{Binding, Interrupt as _};
17use crate::interrupt::{Interrupt, InterruptExt};
17use crate::pac::io::vals::{Inover, Outover}; 18use crate::pac::io::vals::{Inover, Outover};
18use crate::{interrupt, pac, peripherals, RegExt}; 19use crate::{interrupt, pac, peripherals, RegExt};
19 20
@@ -135,37 +136,41 @@ pub struct DmaState {
135} 136}
136 137
137/// UART driver. 138/// UART driver.
138pub struct Uart<'d, T: Instance, M: Mode> { 139pub struct Uart<'d, M: Mode> {
139 tx: UartTx<'d, T, M>, 140 tx: UartTx<'d, M>,
140 rx: UartRx<'d, T, M>, 141 rx: UartRx<'d, M>,
141} 142}
142 143
143/// UART TX driver. 144/// UART TX driver.
144pub struct UartTx<'d, T: Instance, M: Mode> { 145pub struct UartTx<'d, M: Mode> {
146 info: &'static Info,
145 tx_dma: Option<Peri<'d, AnyChannel>>, 147 tx_dma: Option<Peri<'d, AnyChannel>>,
146 phantom: PhantomData<(&'d mut T, M)>, 148 phantom: PhantomData<M>,
147} 149}
148 150
149/// UART RX driver. 151/// UART RX driver.
150pub struct UartRx<'d, T: Instance, M: Mode> { 152pub struct UartRx<'d, M: Mode> {
153 info: &'static Info,
154 dma_state: &'static DmaState,
151 rx_dma: Option<Peri<'d, AnyChannel>>, 155 rx_dma: Option<Peri<'d, AnyChannel>>,
152 phantom: PhantomData<(&'d mut T, M)>, 156 phantom: PhantomData<M>,
153} 157}
154 158
155impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { 159impl<'d, M: Mode> UartTx<'d, M> {
156 /// Create a new DMA-enabled UART which can only send data 160 /// Create a new DMA-enabled UART which can only send data
157 pub fn new( 161 pub fn new<T: Instance>(
158 _uart: Peri<'d, T>, 162 _uart: Peri<'d, T>,
159 tx: Peri<'d, impl TxPin<T>>, 163 tx: Peri<'d, impl TxPin<T>>,
160 tx_dma: Peri<'d, impl Channel>, 164 tx_dma: Peri<'d, impl Channel>,
161 config: Config, 165 config: Config,
162 ) -> Self { 166 ) -> Self {
163 Uart::<T, M>::init(Some(tx.into()), None, None, None, config); 167 Uart::<M>::init(T::info(), Some(tx.into()), None, None, None, config);
164 Self::new_inner(Some(tx_dma.into())) 168 Self::new_inner(T::info(), Some(tx_dma.into()))
165 } 169 }
166 170
167 fn new_inner(tx_dma: Option<Peri<'d, AnyChannel>>) -> Self { 171 fn new_inner(info: &'static Info, tx_dma: Option<Peri<'d, AnyChannel>>) -> Self {
168 Self { 172 Self {
173 info,
169 tx_dma, 174 tx_dma,
170 phantom: PhantomData, 175 phantom: PhantomData,
171 } 176 }
@@ -173,7 +178,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
173 178
174 /// Transmit the provided buffer blocking execution until done. 179 /// Transmit the provided buffer blocking execution until done.
175 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 180 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
176 let r = T::regs(); 181 let r = self.info.regs;
177 for &b in buffer { 182 for &b in buffer {
178 while r.uartfr().read().txff() {} 183 while r.uartfr().read().txff() {}
179 r.uartdr().write(|w| w.set_data(b)); 184 r.uartdr().write(|w| w.set_data(b));
@@ -183,14 +188,13 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
183 188
184 /// Flush UART TX blocking execution until done. 189 /// Flush UART TX blocking execution until done.
185 pub fn blocking_flush(&mut self) -> Result<(), Error> { 190 pub fn blocking_flush(&mut self) -> Result<(), Error> {
186 let r = T::regs(); 191 while !self.info.regs.uartfr().read().txfe() {}
187 while !r.uartfr().read().txfe() {}
188 Ok(()) 192 Ok(())
189 } 193 }
190 194
191 /// Check if UART is busy transmitting. 195 /// Check if UART is busy transmitting.
192 pub fn busy(&self) -> bool { 196 pub fn busy(&self) -> bool {
193 T::regs().uartfr().read().busy() 197 self.info.regs.uartfr().read().busy()
194 } 198 }
195 199
196 /// Assert a break condition after waiting for the transmit buffers to empty, 200 /// Assert a break condition after waiting for the transmit buffers to empty,
@@ -201,7 +205,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
201 /// This method may block for a long amount of time since it has to wait 205 /// This method may block for a long amount of time since it has to wait
202 /// for the transmit fifo to empty, which may take a while on slow links. 206 /// for the transmit fifo to empty, which may take a while on slow links.
203 pub async fn send_break(&mut self, bits: u32) { 207 pub async fn send_break(&mut self, bits: u32) {
204 let regs = T::regs(); 208 let regs = self.info.regs;
205 let bits = bits.max({ 209 let bits = bits.max({
206 let lcr = regs.uartlcr_h().read(); 210 let lcr = regs.uartlcr_h().read();
207 let width = lcr.wlen() as u32 + 5; 211 let width = lcr.wlen() as u32 + 5;
@@ -222,65 +226,80 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
222 } 226 }
223} 227}
224 228
225impl<'d, T: Instance> UartTx<'d, T, Blocking> { 229impl<'d> UartTx<'d, Blocking> {
226 /// Create a new UART TX instance for blocking mode operations. 230 /// Create a new UART TX instance for blocking mode operations.
227 pub fn new_blocking(_uart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self { 231 pub fn new_blocking<T: Instance>(_uart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self {
228 Uart::<T, Blocking>::init(Some(tx.into()), None, None, None, config); 232 Uart::<Blocking>::init(T::info(), Some(tx.into()), None, None, None, config);
229 Self::new_inner(None) 233 Self::new_inner(T::info(), None)
230 } 234 }
231 235
232 /// Convert this uart TX instance into a buffered uart using the provided 236 /// Convert this uart TX instance into a buffered uart using the provided
233 /// irq and transmit buffer. 237 /// irq and transmit buffer.
234 pub fn into_buffered( 238 pub fn into_buffered<T: Instance>(
235 self, 239 self,
236 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 240 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
237 tx_buffer: &'d mut [u8], 241 tx_buffer: &'d mut [u8],
238 ) -> BufferedUartTx<'d, T> { 242 ) -> BufferedUartTx {
239 buffered::init_buffers::<T>(irq, Some(tx_buffer), None); 243 buffered::init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), None);
240 244
241 BufferedUartTx { phantom: PhantomData } 245 BufferedUartTx {
246 info: T::info(),
247 state: T::buffered_state(),
248 }
242 } 249 }
243} 250}
244 251
245impl<'d, T: Instance> UartTx<'d, T, Async> { 252impl<'d> UartTx<'d, Async> {
246 /// Write to UART TX from the provided buffer using DMA. 253 /// Write to UART TX from the provided buffer using DMA.
247 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { 254 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
248 let ch = self.tx_dma.as_mut().unwrap().reborrow(); 255 let ch = self.tx_dma.as_mut().unwrap().reborrow();
249 let transfer = unsafe { 256 let transfer = unsafe {
250 T::regs().uartdmacr().write_set(|reg| { 257 self.info.regs.uartdmacr().write_set(|reg| {
251 reg.set_txdmae(true); 258 reg.set_txdmae(true);
252 }); 259 });
253 // If we don't assign future to a variable, the data register pointer 260 // If we don't assign future to a variable, the data register pointer
254 // is held across an await and makes the future non-Send. 261 // is held across an await and makes the future non-Send.
255 crate::dma::write(ch, buffer, T::regs().uartdr().as_ptr() as *mut _, T::TX_DREQ.into()) 262 crate::dma::write(
263 ch,
264 buffer,
265 self.info.regs.uartdr().as_ptr() as *mut _,
266 self.info.tx_dreq.into(),
267 )
256 }; 268 };
257 transfer.await; 269 transfer.await;
258 Ok(()) 270 Ok(())
259 } 271 }
260} 272}
261 273
262impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { 274impl<'d, M: Mode> UartRx<'d, M> {
263 /// Create a new DMA-enabled UART which can only receive data 275 /// Create a new DMA-enabled UART which can only receive data
264 pub fn new( 276 pub fn new<T: Instance>(
265 _uart: Peri<'d, T>, 277 _uart: Peri<'d, T>,
266 rx: Peri<'d, impl RxPin<T>>, 278 rx: Peri<'d, impl RxPin<T>>,
267 _irq: impl Binding<T::Interrupt, InterruptHandler<T>>, 279 _irq: impl Binding<T::Interrupt, InterruptHandler<T>>,
268 rx_dma: Peri<'d, impl Channel>, 280 rx_dma: Peri<'d, impl Channel>,
269 config: Config, 281 config: Config,
270 ) -> Self { 282 ) -> Self {
271 Uart::<T, M>::init(None, Some(rx.into()), None, None, config); 283 Uart::<M>::init(T::info(), None, Some(rx.into()), None, None, config);
272 Self::new_inner(true, Some(rx_dma.into())) 284 Self::new_inner(T::info(), T::dma_state(), true, Some(rx_dma.into()))
273 } 285 }
274 286
275 fn new_inner(has_irq: bool, rx_dma: Option<Peri<'d, AnyChannel>>) -> Self { 287 fn new_inner(
288 info: &'static Info,
289 dma_state: &'static DmaState,
290 has_irq: bool,
291 rx_dma: Option<Peri<'d, AnyChannel>>,
292 ) -> Self {
276 debug_assert_eq!(has_irq, rx_dma.is_some()); 293 debug_assert_eq!(has_irq, rx_dma.is_some());
277 if has_irq { 294 if has_irq {
278 // disable all error interrupts initially 295 // disable all error interrupts initially
279 T::regs().uartimsc().write(|w| w.0 = 0); 296 info.regs.uartimsc().write(|w| w.0 = 0);
280 T::Interrupt::unpend(); 297 info.interrupt.unpend();
281 unsafe { T::Interrupt::enable() }; 298 unsafe { info.interrupt.enable() };
282 } 299 }
283 Self { 300 Self {
301 info,
302 dma_state,
284 rx_dma, 303 rx_dma,
285 phantom: PhantomData, 304 phantom: PhantomData,
286 } 305 }
@@ -299,7 +318,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
299 /// 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
300 /// `buffer`. 319 /// `buffer`.
301 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)> {
302 let r = T::regs(); 321 let r = self.info.regs;
303 for (i, b) in buffer.iter_mut().enumerate() { 322 for (i, b) in buffer.iter_mut().enumerate() {
304 if r.uartfr().read().rxfe() { 323 if r.uartfr().read().rxfe() {
305 return Ok(i); 324 return Ok(i);
@@ -323,12 +342,12 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
323 } 342 }
324} 343}
325 344
326impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { 345impl<'d, M: Mode> Drop for UartRx<'d, M> {
327 fn drop(&mut self) { 346 fn drop(&mut self) {
328 if self.rx_dma.is_some() { 347 if self.rx_dma.is_some() {
329 T::Interrupt::disable(); 348 self.info.interrupt.disable();
330 // clear dma flags. irq handlers use these to disambiguate among themselves. 349 // clear dma flags. irq handlers use these to disambiguate among themselves.
331 T::regs().uartdmacr().write_clear(|reg| { 350 self.info.regs.uartdmacr().write_clear(|reg| {
332 reg.set_rxdmae(true); 351 reg.set_rxdmae(true);
333 reg.set_txdmae(true); 352 reg.set_txdmae(true);
334 reg.set_dmaonerr(true); 353 reg.set_dmaonerr(true);
@@ -337,23 +356,26 @@ impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> {
337 } 356 }
338} 357}
339 358
340impl<'d, T: Instance> UartRx<'d, T, Blocking> { 359impl<'d> UartRx<'d, Blocking> {
341 /// Create a new UART RX instance for blocking mode operations. 360 /// Create a new UART RX instance for blocking mode operations.
342 pub fn new_blocking(_uart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self { 361 pub fn new_blocking<T: Instance>(_uart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self {
343 Uart::<T, Blocking>::init(None, Some(rx.into()), None, None, config); 362 Uart::<Blocking>::init(T::info(), None, Some(rx.into()), None, None, config);
344 Self::new_inner(false, None) 363 Self::new_inner(T::info(), T::dma_state(), false, None)
345 } 364 }
346 365
347 /// Convert this uart RX instance into a buffered uart using the provided 366 /// Convert this uart RX instance into a buffered uart using the provided
348 /// irq and receive buffer. 367 /// irq and receive buffer.
349 pub fn into_buffered( 368 pub fn into_buffered<T: Instance>(
350 self, 369 self,
351 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 370 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
352 rx_buffer: &'d mut [u8], 371 rx_buffer: &'d mut [u8],
353 ) -> BufferedUartRx<'d, T> { 372 ) -> BufferedUartRx {
354 buffered::init_buffers::<T>(irq, None, Some(rx_buffer)); 373 buffered::init_buffers(T::info(), T::buffered_state(), None, Some(rx_buffer));
355 374
356 BufferedUartRx { phantom: PhantomData } 375 BufferedUartRx {
376 info: T::info(),
377 state: T::buffered_state(),
378 }
357 } 379 }
358} 380}
359 381
@@ -364,7 +386,7 @@ pub struct InterruptHandler<T: Instance> {
364 386
365impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { 387impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
366 unsafe fn on_interrupt() { 388 unsafe fn on_interrupt() {
367 let uart = T::regs(); 389 let uart = T::info().regs;
368 if !uart.uartdmacr().read().rxdmae() { 390 if !uart.uartdmacr().read().rxdmae() {
369 return; 391 return;
370 } 392 }
@@ -380,13 +402,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
380 } 402 }
381} 403}
382 404
383impl<'d, T: Instance> UartRx<'d, T, Async> { 405impl<'d> UartRx<'d, Async> {
384 /// Read from UART RX into the provided buffer. 406 /// Read from UART RX into the provided buffer.
385 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 407 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
386 // clear error flags before we drain the fifo. errors that have accumulated 408 // clear error flags before we drain the fifo. errors that have accumulated
387 // in the flags will also be present in the fifo. 409 // in the flags will also be present in the fifo.
388 T::dma_state().rx_errs.store(0, Ordering::Relaxed); 410 self.dma_state.rx_errs.store(0, Ordering::Relaxed);
389 T::regs().uarticr().write(|w| { 411 self.info.regs.uarticr().write(|w| {
390 w.set_oeic(true); 412 w.set_oeic(true);
391 w.set_beic(true); 413 w.set_beic(true);
392 w.set_peic(true); 414 w.set_peic(true);
@@ -408,28 +430,33 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
408 // interrupt flags will have been raised, and those will be picked up immediately 430 // interrupt flags will have been raised, and those will be picked up immediately
409 // by the interrupt handler. 431 // by the interrupt handler.
410 let ch = self.rx_dma.as_mut().unwrap().reborrow(); 432 let ch = self.rx_dma.as_mut().unwrap().reborrow();
411 T::regs().uartimsc().write_set(|w| { 433 self.info.regs.uartimsc().write_set(|w| {
412 w.set_oeim(true); 434 w.set_oeim(true);
413 w.set_beim(true); 435 w.set_beim(true);
414 w.set_peim(true); 436 w.set_peim(true);
415 w.set_feim(true); 437 w.set_feim(true);
416 }); 438 });
417 T::regs().uartdmacr().write_set(|reg| { 439 self.info.regs.uartdmacr().write_set(|reg| {
418 reg.set_rxdmae(true); 440 reg.set_rxdmae(true);
419 reg.set_dmaonerr(true); 441 reg.set_dmaonerr(true);
420 }); 442 });
421 let transfer = unsafe { 443 let transfer = unsafe {
422 // If we don't assign future to a variable, the data register pointer 444 // If we don't assign future to a variable, the data register pointer
423 // is held across an await and makes the future non-Send. 445 // is held across an await and makes the future non-Send.
424 crate::dma::read(ch, T::regs().uartdr().as_ptr() as *const _, buffer, T::RX_DREQ.into()) 446 crate::dma::read(
447 ch,
448 self.info.regs.uartdr().as_ptr() as *const _,
449 buffer,
450 self.info.rx_dreq.into(),
451 )
425 }; 452 };
426 453
427 // wait for either the transfer to complete or an error to happen. 454 // wait for either the transfer to complete or an error to happen.
428 let transfer_result = select( 455 let transfer_result = select(
429 transfer, 456 transfer,
430 poll_fn(|cx| { 457 poll_fn(|cx| {
431 T::dma_state().rx_err_waker.register(cx.waker()); 458 self.dma_state.rx_err_waker.register(cx.waker());
432 match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) { 459 match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) {
433 0 => Poll::Pending, 460 0 => Poll::Pending,
434 e => Poll::Ready(Uartris(e as u32)), 461 e => Poll::Ready(Uartris(e as u32)),
435 } 462 }
@@ -441,7 +468,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
441 Either::First(()) => { 468 Either::First(()) => {
442 // We're here because the DMA finished, BUT if an error occurred on the LAST 469 // We're here because the DMA finished, BUT if an error occurred on the LAST
443 // byte, then we may still need to grab the error state! 470 // byte, then we may still need to grab the error state!
444 Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32) 471 Uartris(self.dma_state.rx_errs.swap(0, Ordering::Relaxed) as u32)
445 } 472 }
446 Either::Second(e) => { 473 Either::Second(e) => {
447 // We're here because we errored, which means this is the error that 474 // We're here because we errored, which means this is the error that
@@ -521,8 +548,8 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
521 ) -> Result<usize, ReadToBreakError> { 548 ) -> Result<usize, ReadToBreakError> {
522 // clear error flags before we drain the fifo. errors that have accumulated 549 // clear error flags before we drain the fifo. errors that have accumulated
523 // in the flags will also be present in the fifo. 550 // in the flags will also be present in the fifo.
524 T::dma_state().rx_errs.store(0, Ordering::Relaxed); 551 self.dma_state.rx_errs.store(0, Ordering::Relaxed);
525 T::regs().uarticr().write(|w| { 552 self.info.regs.uarticr().write(|w| {
526 w.set_oeic(true); 553 w.set_oeic(true);
527 w.set_beic(true); 554 w.set_beic(true);
528 w.set_peic(true); 555 w.set_peic(true);
@@ -555,13 +582,13 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
555 // interrupt flags will have been raised, and those will be picked up immediately 582 // interrupt flags will have been raised, and those will be picked up immediately
556 // by the interrupt handler. 583 // by the interrupt handler.
557 let ch = self.rx_dma.as_mut().unwrap(); 584 let ch = self.rx_dma.as_mut().unwrap();
558 T::regs().uartimsc().write_set(|w| { 585 self.info.regs.uartimsc().write_set(|w| {
559 w.set_oeim(true); 586 w.set_oeim(true);
560 w.set_beim(true); 587 w.set_beim(true);
561 w.set_peim(true); 588 w.set_peim(true);
562 w.set_feim(true); 589 w.set_feim(true);
563 }); 590 });
564 T::regs().uartdmacr().write_set(|reg| { 591 self.info.regs.uartdmacr().write_set(|reg| {
565 reg.set_rxdmae(true); 592 reg.set_rxdmae(true);
566 reg.set_dmaonerr(true); 593 reg.set_dmaonerr(true);
567 }); 594 });
@@ -572,9 +599,9 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
572 // is held across an await and makes the future non-Send. 599 // is held across an await and makes the future non-Send.
573 crate::dma::read( 600 crate::dma::read(
574 ch.reborrow(), 601 ch.reborrow(),
575 T::regs().uartdr().as_ptr() as *const _, 602 self.info.regs.uartdr().as_ptr() as *const _,
576 sbuffer, 603 sbuffer,
577 T::RX_DREQ.into(), 604 self.info.rx_dreq.into(),
578 ) 605 )
579 }; 606 };
580 607
@@ -582,8 +609,8 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
582 let transfer_result = select( 609 let transfer_result = select(
583 transfer, 610 transfer,
584 poll_fn(|cx| { 611 poll_fn(|cx| {
585 T::dma_state().rx_err_waker.register(cx.waker()); 612 self.dma_state.rx_err_waker.register(cx.waker());
586 match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) { 613 match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) {
587 0 => Poll::Pending, 614 0 => Poll::Pending,
588 e => Poll::Ready(Uartris(e as u32)), 615 e => Poll::Ready(Uartris(e as u32)),
589 } 616 }
@@ -596,7 +623,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
596 Either::First(()) => { 623 Either::First(()) => {
597 // We're here because the DMA finished, BUT if an error occurred on the LAST 624 // We're here because the DMA finished, BUT if an error occurred on the LAST
598 // byte, then we may still need to grab the error state! 625 // byte, then we may still need to grab the error state!
599 Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32) 626 Uartris(self.dma_state.rx_errs.swap(0, Ordering::Relaxed) as u32)
600 } 627 }
601 Either::Second(e) => { 628 Either::Second(e) => {
602 // We're here because we errored, which means this is the error that 629 // We're here because we errored, which means this is the error that
@@ -635,7 +662,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
635 continue; 662 continue;
636 } 663 }
637 664
638 let regs = T::regs(); 665 let regs = self.info.regs;
639 let all_full = next_addr == eval; 666 let all_full = next_addr == eval;
640 667
641 // NOTE: This is off label usage of RSR! See the issue below for 668 // NOTE: This is off label usage of RSR! See the issue below for
@@ -685,9 +712,9 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
685 } 712 }
686} 713}
687 714
688impl<'d, T: Instance> Uart<'d, T, Blocking> { 715impl<'d> Uart<'d, Blocking> {
689 /// Create a new UART without hardware flow control 716 /// Create a new UART without hardware flow control
690 pub fn new_blocking( 717 pub fn new_blocking<T: Instance>(
691 uart: Peri<'d, T>, 718 uart: Peri<'d, T>,
692 tx: Peri<'d, impl TxPin<T>>, 719 tx: Peri<'d, impl TxPin<T>>,
693 rx: Peri<'d, impl RxPin<T>>, 720 rx: Peri<'d, impl RxPin<T>>,
@@ -697,7 +724,7 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
697 } 724 }
698 725
699 /// Create a new UART with hardware flow control (RTS/CTS) 726 /// Create a new UART with hardware flow control (RTS/CTS)
700 pub fn new_with_rtscts_blocking( 727 pub fn new_with_rtscts_blocking<T: Instance>(
701 uart: Peri<'d, T>, 728 uart: Peri<'d, T>,
702 tx: Peri<'d, impl TxPin<T>>, 729 tx: Peri<'d, impl TxPin<T>>,
703 rx: Peri<'d, impl RxPin<T>>, 730 rx: Peri<'d, impl RxPin<T>>,
@@ -720,24 +747,30 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
720 747
721 /// Convert this uart instance into a buffered uart using the provided 748 /// Convert this uart instance into a buffered uart using the provided
722 /// irq, transmit and receive buffers. 749 /// irq, transmit and receive buffers.
723 pub fn into_buffered( 750 pub fn into_buffered<T: Instance>(
724 self, 751 self,
725 irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>, 752 _irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
726 tx_buffer: &'d mut [u8], 753 tx_buffer: &'d mut [u8],
727 rx_buffer: &'d mut [u8], 754 rx_buffer: &'d mut [u8],
728 ) -> BufferedUart<'d, T> { 755 ) -> BufferedUart {
729 buffered::init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer)); 756 buffered::init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), Some(rx_buffer));
730 757
731 BufferedUart { 758 BufferedUart {
732 rx: BufferedUartRx { phantom: PhantomData }, 759 rx: BufferedUartRx {
733 tx: BufferedUartTx { phantom: PhantomData }, 760 info: T::info(),
761 state: T::buffered_state(),
762 },
763 tx: BufferedUartTx {
764 info: T::info(),
765 state: T::buffered_state(),
766 },
734 } 767 }
735 } 768 }
736} 769}
737 770
738impl<'d, T: Instance> Uart<'d, T, Async> { 771impl<'d> Uart<'d, Async> {
739 /// Create a new DMA enabled UART without hardware flow control 772 /// Create a new DMA enabled UART without hardware flow control
740 pub fn new( 773 pub fn new<T: Instance>(
741 uart: Peri<'d, T>, 774 uart: Peri<'d, T>,
742 tx: Peri<'d, impl TxPin<T>>, 775 tx: Peri<'d, impl TxPin<T>>,
743 rx: Peri<'d, impl RxPin<T>>, 776 rx: Peri<'d, impl RxPin<T>>,
@@ -760,7 +793,7 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
760 } 793 }
761 794
762 /// Create a new DMA enabled UART with hardware flow control (RTS/CTS) 795 /// Create a new DMA enabled UART with hardware flow control (RTS/CTS)
763 pub fn new_with_rtscts( 796 pub fn new_with_rtscts<T: Instance>(
764 uart: Peri<'d, T>, 797 uart: Peri<'d, T>,
765 tx: Peri<'d, impl TxPin<T>>, 798 tx: Peri<'d, impl TxPin<T>>,
766 rx: Peri<'d, impl RxPin<T>>, 799 rx: Peri<'d, impl RxPin<T>>,
@@ -785,8 +818,8 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
785 } 818 }
786} 819}
787 820
788impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { 821impl<'d, M: Mode> Uart<'d, M> {
789 fn new_inner( 822 fn new_inner<T: Instance>(
790 _uart: Peri<'d, T>, 823 _uart: Peri<'d, T>,
791 mut tx: Peri<'d, AnyPin>, 824 mut tx: Peri<'d, AnyPin>,
792 mut rx: Peri<'d, AnyPin>, 825 mut rx: Peri<'d, AnyPin>,
@@ -798,6 +831,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
798 config: Config, 831 config: Config,
799 ) -> Self { 832 ) -> Self {
800 Self::init( 833 Self::init(
834 T::info(),
801 Some(tx.reborrow()), 835 Some(tx.reborrow()),
802 Some(rx.reborrow()), 836 Some(rx.reborrow()),
803 rts.as_mut().map(|x| x.reborrow()), 837 rts.as_mut().map(|x| x.reborrow()),
@@ -806,19 +840,20 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
806 ); 840 );
807 841
808 Self { 842 Self {
809 tx: UartTx::new_inner(tx_dma), 843 tx: UartTx::new_inner(T::info(), tx_dma),
810 rx: UartRx::new_inner(has_irq, rx_dma), 844 rx: UartRx::new_inner(T::info(), T::dma_state(), has_irq, rx_dma),
811 } 845 }
812 } 846 }
813 847
814 fn init( 848 fn init(
849 info: &Info,
815 tx: Option<Peri<'_, AnyPin>>, 850 tx: Option<Peri<'_, AnyPin>>,
816 rx: Option<Peri<'_, AnyPin>>, 851 rx: Option<Peri<'_, AnyPin>>,
817 rts: Option<Peri<'_, AnyPin>>, 852 rts: Option<Peri<'_, AnyPin>>,
818 cts: Option<Peri<'_, AnyPin>>, 853 cts: Option<Peri<'_, AnyPin>>,
819 config: Config, 854 config: Config,
820 ) { 855 ) {
821 let r = T::regs(); 856 let r = info.regs;
822 if let Some(pin) = &tx { 857 if let Some(pin) = &tx {
823 let funcsel = { 858 let funcsel = {
824 let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8; 859 let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8;
@@ -896,7 +931,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
896 }); 931 });
897 } 932 }
898 933
899 Self::set_baudrate_inner(config.baudrate); 934 Self::set_baudrate_inner(info, config.baudrate);
900 935
901 let (pen, eps) = match config.parity { 936 let (pen, eps) = match config.parity {
902 Parity::ParityNone => (false, false), 937 Parity::ParityNone => (false, false),
@@ -926,8 +961,8 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
926 }); 961 });
927 } 962 }
928 963
929 fn lcr_modify<R>(f: impl FnOnce(&mut crate::pac::uart::regs::UartlcrH) -> R) -> R { 964 fn lcr_modify<R>(info: &Info, f: impl FnOnce(&mut crate::pac::uart::regs::UartlcrH) -> R) -> R {
930 let r = T::regs(); 965 let r = info.regs;
931 966
932 // Notes from PL011 reference manual: 967 // Notes from PL011 reference manual:
933 // 968 //
@@ -978,11 +1013,11 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
978 1013
979 /// sets baudrate on runtime 1014 /// sets baudrate on runtime
980 pub fn set_baudrate(&mut self, baudrate: u32) { 1015 pub fn set_baudrate(&mut self, baudrate: u32) {
981 Self::set_baudrate_inner(baudrate); 1016 Self::set_baudrate_inner(self.tx.info, baudrate);
982 } 1017 }
983 1018
984 fn set_baudrate_inner(baudrate: u32) { 1019 fn set_baudrate_inner(info: &Info, baudrate: u32) {
985 let r = T::regs(); 1020 let r = info.regs;
986 1021
987 let clk_base = crate::clocks::clk_peri_freq(); 1022 let clk_base = crate::clocks::clk_peri_freq();
988 1023
@@ -1002,11 +1037,11 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
1002 r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd)); 1037 r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
1003 r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd)); 1038 r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
1004 1039
1005 Self::lcr_modify(|_| {}); 1040 Self::lcr_modify(info, |_| {});
1006 } 1041 }
1007} 1042}
1008 1043
1009impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { 1044impl<'d, M: Mode> Uart<'d, M> {
1010 /// Transmit the provided buffer blocking execution until done. 1045 /// Transmit the provided buffer blocking execution until done.
1011 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 1046 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
1012 self.tx.blocking_write(buffer) 1047 self.tx.blocking_write(buffer)
@@ -1034,19 +1069,19 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
1034 1069
1035 /// Split the Uart into a transmitter and receiver, which is particularly 1070 /// Split the Uart into a transmitter and receiver, which is particularly
1036 /// useful when having two tasks correlating to transmitting and receiving. 1071 /// useful when having two tasks correlating to transmitting and receiving.
1037 pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) { 1072 pub fn split(self) -> (UartTx<'d, M>, UartRx<'d, M>) {
1038 (self.tx, self.rx) 1073 (self.tx, self.rx)
1039 } 1074 }
1040 1075
1041 /// Split the Uart into a transmitter and receiver by mutable reference, 1076 /// Split the Uart into a transmitter and receiver by mutable reference,
1042 /// which is particularly useful when having two tasks correlating to 1077 /// which is particularly useful when having two tasks correlating to
1043 /// transmitting and receiving. 1078 /// transmitting and receiving.
1044 pub fn split_ref(&mut self) -> (&mut UartTx<'d, T, M>, &mut UartRx<'d, T, M>) { 1079 pub fn split_ref(&mut self) -> (&mut UartTx<'d, M>, &mut UartRx<'d, M>) {
1045 (&mut self.tx, &mut self.rx) 1080 (&mut self.tx, &mut self.rx)
1046 } 1081 }
1047} 1082}
1048 1083
1049impl<'d, T: Instance> Uart<'d, T, Async> { 1084impl<'d> Uart<'d, Async> {
1050 /// Write to UART TX from the provided buffer. 1085 /// Write to UART TX from the provided buffer.
1051 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { 1086 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
1052 self.tx.write(buffer).await 1087 self.tx.write(buffer).await
@@ -1076,10 +1111,10 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
1076 } 1111 }
1077} 1112}
1078 1113
1079impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> { 1114impl<'d, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, M> {
1080 type Error = Error; 1115 type Error = Error;
1081 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 1116 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
1082 let r = T::regs(); 1117 let r = self.info.regs;
1083 if r.uartfr().read().rxfe() { 1118 if r.uartfr().read().rxfe() {
1084 return Err(nb::Error::WouldBlock); 1119 return Err(nb::Error::WouldBlock);
1085 } 1120 }
@@ -1100,11 +1135,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d,
1100 } 1135 }
1101} 1136}
1102 1137
1103impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d, T, M> { 1138impl<'d, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d, M> {
1104 type Error = Error; 1139 type Error = Error;
1105 1140
1106 fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> { 1141 fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> {
1107 let r = T::regs(); 1142 let r = self.info.regs;
1108 if r.uartfr().read().txff() { 1143 if r.uartfr().read().txff() {
1109 return Err(nb::Error::WouldBlock); 1144 return Err(nb::Error::WouldBlock);
1110 } 1145 }
@@ -1114,7 +1149,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d,
1114 } 1149 }
1115 1150
1116 fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> { 1151 fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> {
1117 let r = T::regs(); 1152 let r = self.info.regs;
1118 if !r.uartfr().read().txfe() { 1153 if !r.uartfr().read().txfe() {
1119 return Err(nb::Error::WouldBlock); 1154 return Err(nb::Error::WouldBlock);
1120 } 1155 }
@@ -1122,7 +1157,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d,
1122 } 1157 }
1123} 1158}
1124 1159
1125impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, M> { 1160impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, M> {
1126 type Error = Error; 1161 type Error = Error;
1127 1162
1128 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 1163 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
@@ -1134,7 +1169,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for
1134 } 1169 }
1135} 1170}
1136 1171
1137impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T, M> { 1172impl<'d, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, M> {
1138 type Error = Error; 1173 type Error = Error;
1139 1174
1140 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 1175 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
@@ -1142,7 +1177,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T,
1142 } 1177 }
1143} 1178}
1144 1179
1145impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for Uart<'d, T, M> { 1180impl<'d, M: Mode> embedded_hal_02::serial::Write<u8> for Uart<'d, M> {
1146 type Error = Error; 1181 type Error = Error;
1147 1182
1148 fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> { 1183 fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> {
@@ -1154,7 +1189,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for Uart<'d, T
1154 } 1189 }
1155} 1190}
1156 1191
1157impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, M> { 1192impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, M> {
1158 type Error = Error; 1193 type Error = Error;
1159 1194
1160 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 1195 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
@@ -1177,21 +1212,21 @@ impl embedded_hal_nb::serial::Error for Error {
1177 } 1212 }
1178} 1213}
1179 1214
1180impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, M> { 1215impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, M> {
1181 type Error = Error; 1216 type Error = Error;
1182} 1217}
1183 1218
1184impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, M> { 1219impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, M> {
1185 type Error = Error; 1220 type Error = Error;
1186} 1221}
1187 1222
1188impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, T, M> { 1223impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, M> {
1189 type Error = Error; 1224 type Error = Error;
1190} 1225}
1191 1226
1192impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> { 1227impl<'d, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, M> {
1193 fn read(&mut self) -> nb::Result<u8, Self::Error> { 1228 fn read(&mut self) -> nb::Result<u8, Self::Error> {
1194 let r = T::regs(); 1229 let r = self.info.regs;
1195 if r.uartfr().read().rxfe() { 1230 if r.uartfr().read().rxfe() {
1196 return Err(nb::Error::WouldBlock); 1231 return Err(nb::Error::WouldBlock);
1197 } 1232 }
@@ -1212,7 +1247,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M
1212 } 1247 }
1213} 1248}
1214 1249
1215impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, M> { 1250impl<'d, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, M> {
1216 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 1251 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
1217 self.blocking_write(&[char]).map_err(nb::Error::Other) 1252 self.blocking_write(&[char]).map_err(nb::Error::Other)
1218 } 1253 }
@@ -1222,11 +1257,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T,
1222 } 1257 }
1223} 1258}
1224 1259
1225impl<'d, T: Instance> embedded_io::ErrorType for UartTx<'d, T, Blocking> { 1260impl<'d> embedded_io::ErrorType for UartTx<'d, Blocking> {
1226 type Error = Error; 1261 type Error = Error;
1227} 1262}
1228 1263
1229impl<'d, T: Instance> embedded_io::Write for UartTx<'d, T, Blocking> { 1264impl<'d> embedded_io::Write for UartTx<'d, Blocking> {
1230 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 1265 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
1231 self.blocking_write(buf).map(|_| buf.len()) 1266 self.blocking_write(buf).map(|_| buf.len())
1232 } 1267 }
@@ -1236,13 +1271,13 @@ impl<'d, T: Instance> embedded_io::Write for UartTx<'d, T, Blocking> {
1236 } 1271 }
1237} 1272}
1238 1273
1239impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, T, M> { 1274impl<'d, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, M> {
1240 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 1275 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
1241 embedded_hal_02::serial::Read::read(&mut self.rx) 1276 embedded_hal_02::serial::Read::read(&mut self.rx)
1242 } 1277 }
1243} 1278}
1244 1279
1245impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> { 1280impl<'d, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, M> {
1246 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { 1281 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
1247 self.blocking_write(&[char]).map_err(nb::Error::Other) 1282 self.blocking_write(&[char]).map_err(nb::Error::Other)
1248 } 1283 }
@@ -1252,11 +1287,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M>
1252 } 1287 }
1253} 1288}
1254 1289
1255impl<'d, T: Instance> embedded_io::ErrorType for Uart<'d, T, Blocking> { 1290impl<'d> embedded_io::ErrorType for Uart<'d, Blocking> {
1256 type Error = Error; 1291 type Error = Error;
1257} 1292}
1258 1293
1259impl<'d, T: Instance> embedded_io::Write for Uart<'d, T, Blocking> { 1294impl<'d> embedded_io::Write for Uart<'d, Blocking> {
1260 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 1295 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
1261 self.blocking_write(buf).map(|_| buf.len()) 1296 self.blocking_write(buf).map(|_| buf.len())
1262 } 1297 }
@@ -1266,13 +1301,17 @@ impl<'d, T: Instance> embedded_io::Write for Uart<'d, T, Blocking> {
1266 } 1301 }
1267} 1302}
1268 1303
1304struct Info {
1305 regs: pac::uart::Uart,
1306 tx_dreq: pac::dma::vals::TreqSel,
1307 rx_dreq: pac::dma::vals::TreqSel,
1308 interrupt: Interrupt,
1309}
1310
1269trait SealedMode {} 1311trait SealedMode {}
1270 1312
1271trait SealedInstance { 1313trait SealedInstance {
1272 const TX_DREQ: pac::dma::vals::TreqSel; 1314 fn info() -> &'static Info;
1273 const RX_DREQ: pac::dma::vals::TreqSel;
1274
1275 fn regs() -> pac::uart::Uart;
1276 1315
1277 fn buffered_state() -> &'static buffered::State; 1316 fn buffered_state() -> &'static buffered::State;
1278 1317
@@ -1308,11 +1347,14 @@ pub trait Instance: SealedInstance + PeripheralType {
1308macro_rules! impl_instance { 1347macro_rules! impl_instance {
1309 ($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { 1348 ($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
1310 impl SealedInstance for peripherals::$inst { 1349 impl SealedInstance for peripherals::$inst {
1311 const TX_DREQ: pac::dma::vals::TreqSel = $tx_dreq; 1350 fn info() -> &'static Info {
1312 const RX_DREQ: pac::dma::vals::TreqSel = $rx_dreq; 1351 static INFO: Info = Info {
1313 1352 regs: pac::$inst,
1314 fn regs() -> pac::uart::Uart { 1353 tx_dreq: $tx_dreq,
1315 pac::$inst 1354 rx_dreq: $rx_dreq,
1355 interrupt: crate::interrupt::typelevel::$irq::IRQ,
1356 };
1357 &INFO
1316 } 1358 }
1317 1359
1318 fn buffered_state() -> &'static buffered::State { 1360 fn buffered_state() -> &'static buffered::State {
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 54ab7d0d5..8fd7e8df4 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -31,6 +31,8 @@ pub struct PwmPin<'d, T, C> {
31/// PWM pin config 31/// PWM pin config
32/// 32///
33/// This configures the pwm pin settings 33/// This configures the pwm pin settings
34#[derive(Debug, Copy, Clone)]
35#[cfg_attr(feature = "defmt", derive(defmt::Format))]
34pub struct PwmPinConfig { 36pub struct PwmPinConfig {
35 /// PWM Pin output type 37 /// PWM Pin output type
36 pub output_type: OutputType, 38 pub output_type: OutputType,
diff --git a/examples/mimxrt6/src/bin/crc.rs b/examples/mimxrt6/src/bin/crc.rs
new file mode 100644
index 000000000..005a250e5
--- /dev/null
+++ b/examples/mimxrt6/src/bin/crc.rs
@@ -0,0 +1,175 @@
1#![no_std]
2#![no_main]
3
4extern crate embassy_imxrt_examples;
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_imxrt::crc::{Config, Crc, Polynomial};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let mut p = embassy_imxrt::init(Default::default());
14 let data = b"123456789";
15
16 info!("Initializing CRC");
17
18 // CRC-CCITT
19 let mut crc = Crc::new(p.CRC.reborrow(), Default::default());
20 let output = crc.feed_bytes(data);
21 defmt::assert_eq!(output, 0x29b1);
22
23 // CRC16-ARC
24 let mut crc = Crc::new(
25 p.CRC.reborrow(),
26 Config {
27 polynomial: Polynomial::Crc16,
28 reverse_in: true,
29 reverse_out: true,
30 complement_out: false,
31 seed: 0,
32 ..Default::default()
33 },
34 );
35 let output = crc.feed_bytes(data);
36 defmt::assert_eq!(output, 0xbb3d);
37
38 // CRC16-CMS
39 let mut crc = Crc::new(
40 p.CRC.reborrow(),
41 Config {
42 polynomial: Polynomial::Crc16,
43 reverse_in: false,
44 reverse_out: false,
45 complement_out: false,
46 seed: 0xffff,
47 ..Default::default()
48 },
49 );
50 let output = crc.feed_bytes(data);
51 defmt::assert_eq!(output, 0xaee7);
52
53 // CRC16-DDS-110
54 let mut crc = Crc::new(
55 p.CRC.reborrow(),
56 Config {
57 polynomial: Polynomial::Crc16,
58 reverse_in: false,
59 reverse_out: false,
60 complement_out: false,
61 seed: 0x800d,
62 ..Default::default()
63 },
64 );
65 let output = crc.feed_bytes(data);
66 defmt::assert_eq!(output, 0x9ecf);
67
68 // CRC16-MAXIM-DOW
69 let mut crc = Crc::new(
70 p.CRC.reborrow(),
71 Config {
72 polynomial: Polynomial::Crc16,
73 reverse_in: true,
74 reverse_out: true,
75 complement_out: true,
76 seed: 0,
77 ..Default::default()
78 },
79 );
80 let output = crc.feed_bytes(data);
81 defmt::assert_eq!(output, 0x44c2);
82
83 // CRC16-MODBUS
84 let mut crc = Crc::new(
85 p.CRC.reborrow(),
86 Config {
87 polynomial: Polynomial::Crc16,
88 reverse_in: true,
89 reverse_out: true,
90 complement_out: false,
91 seed: 0xffff,
92 ..Default::default()
93 },
94 );
95 let output = crc.feed_bytes(data);
96 defmt::assert_eq!(output, 0x4b37);
97
98 // CRC32-BZIP2
99 let mut crc = Crc::new(
100 p.CRC.reborrow(),
101 Config {
102 polynomial: Polynomial::Crc32,
103 reverse_in: false,
104 reverse_out: false,
105 complement_out: true,
106 seed: 0xffff_ffff,
107 ..Default::default()
108 },
109 );
110 let output = crc.feed_bytes(data);
111 defmt::assert_eq!(output, 0xfc89_1918);
112
113 // CRC32-CKSUM
114 let mut crc = Crc::new(
115 p.CRC.reborrow(),
116 Config {
117 polynomial: Polynomial::Crc32,
118 reverse_in: false,
119 reverse_out: false,
120 complement_out: true,
121 seed: 0,
122 ..Default::default()
123 },
124 );
125 let output = crc.feed_bytes(data);
126 defmt::assert_eq!(output, 0x765e_7680);
127
128 // CRC32-ISO-HDLC
129 let mut crc = Crc::new(
130 p.CRC.reborrow(),
131 Config {
132 polynomial: Polynomial::Crc32,
133 reverse_in: true,
134 reverse_out: true,
135 complement_out: true,
136 seed: 0xffff_ffff,
137 ..Default::default()
138 },
139 );
140 let output = crc.feed_bytes(data);
141 defmt::assert_eq!(output, 0xcbf4_3926);
142
143 // CRC32-JAMCRC
144 let mut crc = Crc::new(
145 p.CRC.reborrow(),
146 Config {
147 polynomial: Polynomial::Crc32,
148 reverse_in: true,
149 reverse_out: true,
150 complement_out: false,
151 seed: 0xffff_ffff,
152 ..Default::default()
153 },
154 );
155 let output = crc.feed_bytes(data);
156 defmt::assert_eq!(output, 0x340b_c6d9);
157
158 // CRC32-MPEG-2
159 let mut crc = Crc::new(
160 p.CRC.reborrow(),
161 Config {
162 polynomial: Polynomial::Crc32,
163 reverse_in: false,
164 reverse_out: false,
165 complement_out: false,
166 seed: 0xffff_ffff,
167 ..Default::default()
168 },
169 );
170 let output = crc.feed_bytes(data);
171 defmt::assert_eq!(output, 0x0376_e6e7);
172
173 info!("end program");
174 cortex_m::asm::bkpt();
175}
diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs
new file mode 100644
index 000000000..9c78e0c9d
--- /dev/null
+++ b/examples/rp/src/bin/overclock.rs
@@ -0,0 +1,64 @@
1//! # Overclocking the RP2040 to 200 MHz
2//!
3//! This example demonstrates how to configure the RP2040 to run at 200 MHz.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::clocks::{clk_sys_freq, ClockConfig};
11use embassy_rp::config::Config;
12use embassy_rp::gpio::{Level, Output};
13use embassy_time::{Duration, Instant, Timer};
14use {defmt_rtt as _, panic_probe as _};
15
16const COUNT_TO: i64 = 10_000_000;
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) -> ! {
20 // Set up for clock frequency of 200 MHz, setting all necessary defaults.
21 let config = Config::new(ClockConfig::system_freq(200_000_000));
22
23 // Show the voltage scale for verification
24 info!("System core voltage: {}", Debug2Format(&config.clocks.core_voltage));
25
26 // Initialize the peripherals
27 let p = embassy_rp::init(config);
28
29 // Show CPU frequency for verification
30 let sys_freq = clk_sys_freq();
31 info!("System clock frequency: {} MHz", sys_freq / 1_000_000);
32
33 // LED to indicate the system is running
34 let mut led = Output::new(p.PIN_25, Level::Low);
35
36 loop {
37 // Reset the counter at the start of measurement period
38 let mut counter = 0;
39
40 // Turn LED on while counting
41 led.set_high();
42
43 let start = Instant::now();
44
45 // This is a busy loop that will take some time to complete
46 while counter < COUNT_TO {
47 counter += 1;
48 }
49
50 let elapsed = Instant::now() - start;
51
52 // Report the elapsed time
53 led.set_low();
54 info!(
55 "At {}Mhz: Elapsed time to count to {}: {}ms",
56 sys_freq / 1_000_000,
57 counter,
58 elapsed.as_millis()
59 );
60
61 // Wait 2 seconds before starting the next measurement
62 Timer::after(Duration::from_secs(2)).await;
63 }
64}
diff --git a/examples/rp/src/bin/overclock_manual.rs b/examples/rp/src/bin/overclock_manual.rs
new file mode 100644
index 000000000..35160b250
--- /dev/null
+++ b/examples/rp/src/bin/overclock_manual.rs
@@ -0,0 +1,79 @@
1//! # Overclocking the RP2040 to 200 MHz manually
2//!
3//! This example demonstrates how to manually configure the RP2040 to run at 200 MHz.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::clocks;
11use embassy_rp::clocks::{ClockConfig, CoreVoltage, PllConfig};
12use embassy_rp::config::Config;
13use embassy_rp::gpio::{Level, Output};
14use embassy_time::{Duration, Instant, Timer};
15use {defmt_rtt as _, panic_probe as _};
16
17const COUNT_TO: i64 = 10_000_000;
18
19/// Configure the RP2040 for 200 MHz operation by manually specifying the PLL settings.
20fn configure_manual_overclock() -> Config {
21 // Set the PLL configuration manually, starting from default values
22 let mut config = Config::default();
23
24 // Set the system clock to 200 MHz
25 config.clocks = ClockConfig::manual_pll(
26 12_000_000, // Crystal frequency, 12 MHz is common. If using custom, set to your value.
27 PllConfig {
28 refdiv: 1, // Reference divider
29 fbdiv: 100, // Feedback divider
30 post_div1: 3, // Post divider 1
31 post_div2: 2, // Post divider 2
32 },
33 CoreVoltage::V1_15, // Core voltage, should be set to V1_15 for 200 MHz
34 );
35
36 config
37}
38
39#[embassy_executor::main]
40async fn main(_spawner: Spawner) -> ! {
41 // Initialize with our manual overclock configuration
42 let p = embassy_rp::init(configure_manual_overclock());
43
44 // Verify the actual system clock frequency
45 let sys_freq = clocks::clk_sys_freq();
46 info!("System clock frequency: {} MHz", sys_freq / 1_000_000);
47
48 // LED to indicate the system is running
49 let mut led = Output::new(p.PIN_25, Level::Low);
50
51 loop {
52 // Reset the counter at the start of measurement period
53 let mut counter = 0;
54
55 // Turn LED on while counting
56 led.set_high();
57
58 let start = Instant::now();
59
60 // This is a busy loop that will take some time to complete
61 while counter < COUNT_TO {
62 counter += 1;
63 }
64
65 let elapsed = Instant::now() - start;
66
67 // Report the elapsed time
68 led.set_low();
69 info!(
70 "At {}Mhz: Elapsed time to count to {}: {}ms",
71 sys_freq / 1_000_000,
72 counter,
73 elapsed.as_millis()
74 );
75
76 // Wait 2 seconds before starting the next measurement
77 Timer::after(Duration::from_secs(2)).await;
78 }
79}
diff --git a/examples/rp/src/bin/sharing.rs b/examples/rp/src/bin/sharing.rs
index 5416e20ce..497c4f845 100644
--- a/examples/rp/src/bin/sharing.rs
+++ b/examples/rp/src/bin/sharing.rs
@@ -31,7 +31,7 @@ use rand::RngCore;
31use static_cell::{ConstStaticCell, StaticCell}; 31use static_cell::{ConstStaticCell, StaticCell};
32use {defmt_rtt as _, panic_probe as _}; 32use {defmt_rtt as _, panic_probe as _};
33 33
34type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>; 34type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, uart::Async>>;
35 35
36struct MyType { 36struct MyType {
37 inner: u32, 37 inner: u32,
diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs
index da7e94139..3adbc18ab 100644
--- a/examples/rp/src/bin/uart_buffered_split.rs
+++ b/examples/rp/src/bin/uart_buffered_split.rs
@@ -48,7 +48,7 @@ async fn main(spawner: Spawner) {
48} 48}
49 49
50#[embassy_executor::task] 50#[embassy_executor::task]
51async fn reader(mut rx: BufferedUartRx<'static, UART0>) { 51async fn reader(mut rx: BufferedUartRx) {
52 info!("Reading..."); 52 info!("Reading...");
53 loop { 53 loop {
54 let mut buf = [0; 31]; 54 let mut buf = [0; 31];
diff --git a/examples/rp/src/bin/uart_unidir.rs b/examples/rp/src/bin/uart_unidir.rs
index a45f40756..c2c8dfad8 100644
--- a/examples/rp/src/bin/uart_unidir.rs
+++ b/examples/rp/src/bin/uart_unidir.rs
@@ -39,7 +39,7 @@ async fn main(spawner: Spawner) {
39} 39}
40 40
41#[embassy_executor::task] 41#[embassy_executor::task]
42async fn reader(mut rx: UartRx<'static, UART1, Async>) { 42async fn reader(mut rx: UartRx<'static, Async>) {
43 info!("Reading..."); 43 info!("Reading...");
44 loop { 44 loop {
45 // read a total of 4 transmissions (32 / 8) and then print the result 45 // read a total of 4 transmissions (32 / 8) and then print the result
diff --git a/examples/rp235x/src/bin/sharing.rs b/examples/rp235x/src/bin/sharing.rs
index 5416e20ce..497c4f845 100644
--- a/examples/rp235x/src/bin/sharing.rs
+++ b/examples/rp235x/src/bin/sharing.rs
@@ -31,7 +31,7 @@ use rand::RngCore;
31use static_cell::{ConstStaticCell, StaticCell}; 31use static_cell::{ConstStaticCell, StaticCell};
32use {defmt_rtt as _, panic_probe as _}; 32use {defmt_rtt as _, panic_probe as _};
33 33
34type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>; 34type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, uart::Async>>;
35 35
36struct MyType { 36struct MyType {
37 inner: u32, 37 inner: u32,
diff --git a/examples/rp235x/src/bin/uart_buffered_split.rs b/examples/rp235x/src/bin/uart_buffered_split.rs
index f707c4b5e..7cad09f9b 100644
--- a/examples/rp235x/src/bin/uart_buffered_split.rs
+++ b/examples/rp235x/src/bin/uart_buffered_split.rs
@@ -48,7 +48,7 @@ async fn main(spawner: Spawner) {
48} 48}
49 49
50#[embassy_executor::task] 50#[embassy_executor::task]
51async fn reader(mut rx: BufferedUartRx<'static, UART0>) { 51async fn reader(mut rx: BufferedUartRx) {
52 info!("Reading..."); 52 info!("Reading...");
53 loop { 53 loop {
54 let mut buf = [0; 31]; 54 let mut buf = [0; 31];
diff --git a/examples/rp235x/src/bin/uart_unidir.rs b/examples/rp235x/src/bin/uart_unidir.rs
index 4e98f9e1e..45c9c8407 100644
--- a/examples/rp235x/src/bin/uart_unidir.rs
+++ b/examples/rp235x/src/bin/uart_unidir.rs
@@ -39,7 +39,7 @@ async fn main(spawner: Spawner) {
39} 39}
40 40
41#[embassy_executor::task] 41#[embassy_executor::task]
42async fn reader(mut rx: UartRx<'static, UART1, Async>) { 42async fn reader(mut rx: UartRx<'static, Async>) {
43 info!("Reading..."); 43 info!("Reading...");
44 loop { 44 loop {
45 // read a total of 4 transmissions (32 / 8) and then print the result 45 // read a total of 4 transmissions (32 / 8) and then print the result
diff --git a/tests/rp/src/bin/overclock.rs b/tests/rp/src/bin/overclock.rs
new file mode 100644
index 000000000..be8e85a3f
--- /dev/null
+++ b/tests/rp/src/bin/overclock.rs
@@ -0,0 +1,70 @@
1#![no_std]
2#![no_main]
3
4#[cfg(feature = "rp2040")]
5teleprobe_meta::target!(b"rpi-pico");
6#[cfg(feature = "rp235xb")]
7teleprobe_meta::target!(b"pimoroni-pico-plus-2");
8
9use defmt::info;
10#[cfg(feature = "rp2040")]
11use defmt::{assert, assert_eq};
12use embassy_executor::Spawner;
13use embassy_rp::clocks;
14#[cfg(feature = "rp2040")]
15use embassy_rp::clocks::ClockConfig;
16#[cfg(feature = "rp2040")]
17use embassy_rp::clocks::CoreVoltage;
18use embassy_rp::config::Config;
19use embassy_time::Instant;
20use {defmt_rtt as _, panic_probe as _};
21
22const COUNT_TO: i64 = 10_000_000;
23
24#[embassy_executor::main]
25async fn main(_spawner: Spawner) {
26 #[cfg(feature = "rp2040")]
27 let mut config = Config::default();
28 #[cfg(not(feature = "rp2040"))]
29 let config = Config::default();
30
31 // Initialize with 200MHz clock configuration for RP2040, other chips will use default clock
32 #[cfg(feature = "rp2040")]
33 {
34 config.clocks = ClockConfig::system_freq(200_000_000);
35 let voltage = config.clocks.core_voltage;
36 assert!(matches!(voltage, CoreVoltage::V1_15), "Expected voltage scale V1_15");
37 }
38
39 let _p = embassy_rp::init(config);
40
41 // Test the system speed
42 let (time_elapsed, clk_sys_freq) = {
43 let mut counter = 0;
44 let start = Instant::now();
45 while counter < COUNT_TO {
46 counter += 1;
47 }
48 let elapsed = Instant::now() - start;
49
50 (elapsed.as_millis(), clocks::clk_sys_freq())
51 };
52
53 // Report the elapsed time, so that the compiler doesn't optimize it away for chips other than RP2040
54 info!(
55 "At {}Mhz: Elapsed time to count to {}: {}ms",
56 clk_sys_freq / 1_000_000,
57 COUNT_TO,
58 time_elapsed
59 );
60
61 #[cfg(feature = "rp2040")]
62 {
63 // we should be at 200MHz
64 assert_eq!(clk_sys_freq, 200_000_000, "System clock frequency is not 200MHz");
65 // At 200MHz, the time to count to 10_000_000 should be at 600ms, testing with 1% margin
66 assert!(time_elapsed <= 606, "Elapsed time is too long");
67 }
68
69 cortex_m::asm::bkpt();
70}
diff --git a/tests/rp/src/bin/uart.rs b/tests/rp/src/bin/uart.rs
index 84744ab77..80230f3fe 100644
--- a/tests/rp/src/bin/uart.rs
+++ b/tests/rp/src/bin/uart.rs
@@ -8,17 +8,17 @@ teleprobe_meta::target!(b"pimoroni-pico-plus-2");
8use defmt::{assert_eq, *}; 8use defmt::{assert_eq, *};
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_rp::gpio::{Level, Output}; 10use embassy_rp::gpio::{Level, Output};
11use embassy_rp::uart::{Blocking, Config, Error, Instance, Parity, Uart, UartRx}; 11use embassy_rp::uart::{Blocking, Config, Error, Parity, Uart, UartRx};
12use embassy_time::Timer; 12use embassy_time::Timer;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
15fn read<const N: usize>(uart: &mut Uart<'_, impl Instance, Blocking>) -> Result<[u8; N], Error> { 15fn read<const N: usize>(uart: &mut Uart<'_, Blocking>) -> Result<[u8; N], Error> {
16 let mut buf = [255; N]; 16 let mut buf = [255; N];
17 uart.blocking_read(&mut buf)?; 17 uart.blocking_read(&mut buf)?;
18 Ok(buf) 18 Ok(buf)
19} 19}
20 20
21fn read1<const N: usize>(uart: &mut UartRx<'_, impl Instance, Blocking>) -> Result<[u8; N], Error> { 21fn read1<const N: usize>(uart: &mut UartRx<'_, Blocking>) -> Result<[u8; N], Error> {
22 let mut buf = [255; N]; 22 let mut buf = [255; N];
23 uart.blocking_read(&mut buf)?; 23 uart.blocking_read(&mut buf)?;
24 Ok(buf) 24 Ok(buf)
diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs
index d5f655e9b..cb78fc142 100644
--- a/tests/rp/src/bin/uart_buffered.rs
+++ b/tests/rp/src/bin/uart_buffered.rs
@@ -10,7 +10,7 @@ use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts; 10use embassy_rp::bind_interrupts;
11use embassy_rp::gpio::{Level, Output}; 11use embassy_rp::gpio::{Level, Output};
12use embassy_rp::peripherals::UART0; 12use embassy_rp::peripherals::UART0;
13use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config, Error, Instance, Parity}; 13use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config, Error, Parity};
14use embassy_time::Timer; 14use embassy_time::Timer;
15use embedded_io_async::{Read, ReadExactError, Write}; 15use embedded_io_async::{Read, ReadExactError, Write};
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
@@ -19,7 +19,7 @@ bind_interrupts!(struct Irqs {
19 UART0_IRQ => BufferedInterruptHandler<UART0>; 19 UART0_IRQ => BufferedInterruptHandler<UART0>;
20}); 20});
21 21
22async fn read<const N: usize>(uart: &mut BufferedUart<'_, impl Instance>) -> Result<[u8; N], Error> { 22async fn read<const N: usize>(uart: &mut BufferedUart) -> Result<[u8; N], Error> {
23 let mut buf = [255; N]; 23 let mut buf = [255; N];
24 match uart.read_exact(&mut buf).await { 24 match uart.read_exact(&mut buf).await {
25 Ok(()) => Ok(buf), 25 Ok(()) => Ok(buf),
@@ -29,7 +29,7 @@ async fn read<const N: usize>(uart: &mut BufferedUart<'_, impl Instance>) -> Res
29 } 29 }
30} 30}
31 31
32async fn read1<const N: usize>(uart: &mut BufferedUartRx<'_, impl Instance>) -> Result<[u8; N], Error> { 32async fn read1<const N: usize>(uart: &mut BufferedUartRx) -> Result<[u8; N], Error> {
33 let mut buf = [255; N]; 33 let mut buf = [255; N];
34 match uart.read_exact(&mut buf).await { 34 match uart.read_exact(&mut buf).await {
35 Ok(()) => Ok(buf), 35 Ok(()) => Ok(buf),
diff --git a/tests/rp/src/bin/uart_dma.rs b/tests/rp/src/bin/uart_dma.rs
index a09101223..a7af81f5f 100644
--- a/tests/rp/src/bin/uart_dma.rs
+++ b/tests/rp/src/bin/uart_dma.rs
@@ -10,7 +10,7 @@ use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts; 10use embassy_rp::bind_interrupts;
11use embassy_rp::gpio::{Level, Output}; 11use embassy_rp::gpio::{Level, Output};
12use embassy_rp::peripherals::UART0; 12use embassy_rp::peripherals::UART0;
13use embassy_rp::uart::{Async, Config, Error, Instance, InterruptHandler, Parity, Uart, UartRx}; 13use embassy_rp::uart::{Async, Config, Error, InterruptHandler, Parity, Uart, UartRx};
14use embassy_time::Timer; 14use embassy_time::Timer;
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
@@ -18,13 +18,13 @@ bind_interrupts!(struct Irqs {
18 UART0_IRQ => InterruptHandler<UART0>; 18 UART0_IRQ => InterruptHandler<UART0>;
19}); 19});
20 20
21async fn read<const N: usize>(uart: &mut Uart<'_, impl Instance, Async>) -> Result<[u8; N], Error> { 21async fn read<const N: usize>(uart: &mut Uart<'_, Async>) -> Result<[u8; N], Error> {
22 let mut buf = [255; N]; 22 let mut buf = [255; N];
23 uart.read(&mut buf).await?; 23 uart.read(&mut buf).await?;
24 Ok(buf) 24 Ok(buf)
25} 25}
26 26
27async fn read1<const N: usize>(uart: &mut UartRx<'_, impl Instance, Async>) -> Result<[u8; N], Error> { 27async fn read1<const N: usize>(uart: &mut UartRx<'_, Async>) -> Result<[u8; N], Error> {
28 let mut buf = [255; N]; 28 let mut buf = [255; N];
29 uart.read(&mut buf).await?; 29 uart.read(&mut buf).await?;
30 Ok(buf) 30 Ok(buf)