diff options
| author | Dario Nieuwenhuis <[email protected]> | 2025-05-13 22:33:56 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-05-13 22:33:56 +0200 |
| commit | 102258c0b07ca581d5dabdbd540febd54c0f4443 (patch) | |
| tree | 05765308bab9131f93cd23e1aa5fe306122e8db7 | |
| parent | 8e7e4332b40707e8d36338ad8ec486320bb3538f (diff) | |
| parent | aa85293457039a336eec1f10bcd32d47d7223f95 (diff) | |
Merge branch 'main' into add-rng
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 | ||
| 10 | The following peripherals have a HAL implementation at present | 10 | The 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 | |||
| 3 | use core::marker::PhantomData; | ||
| 4 | |||
| 5 | use crate::clocks::{enable_and_reset, SysconPeripheral}; | ||
| 6 | pub use crate::pac::crc_engine::mode::CrcPolynomial as Polynomial; | ||
| 7 | use crate::{peripherals, Peri, PeripheralType}; | ||
| 8 | |||
| 9 | /// CRC driver. | ||
| 10 | pub struct Crc<'d> { | ||
| 11 | info: Info, | ||
| 12 | _config: Config, | ||
| 13 | _lifetime: PhantomData<&'d ()>, | ||
| 14 | } | ||
| 15 | |||
| 16 | /// CRC configuration | ||
| 17 | pub 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 | |||
| 37 | impl 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 | |||
| 59 | impl 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 | |||
| 72 | impl<'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 | |||
| 169 | struct Info { | ||
| 170 | regs: crate::pac::CrcEngine, | ||
| 171 | } | ||
| 172 | |||
| 173 | trait SealedInstance { | ||
| 174 | fn info() -> Info; | ||
| 175 | } | ||
| 176 | |||
| 177 | /// CRC instance trait. | ||
| 178 | #[allow(private_bounds)] | ||
| 179 | pub trait Instance: SealedInstance + PeripheralType + SysconPeripheral + 'static + Send {} | ||
| 180 | |||
| 181 | impl Instance for peripherals::CRC {} | ||
| 182 | |||
| 183 | impl 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!( | |||
| 18 | pub(crate) mod fmt; | 18 | pub(crate) mod fmt; |
| 19 | 19 | ||
| 20 | pub mod clocks; | 20 | pub mod clocks; |
| 21 | pub mod crc; | ||
| 21 | pub mod gpio; | 22 | pub mod gpio; |
| 22 | pub mod iopctl; | 23 | pub mod iopctl; |
| 23 | pub mod rng; | 24 | pub 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 | ||
| 333 | impl_ipc!(IPC, IPC, IPC); | ||
| 334 | |||
| 330 | impl_usb!(USBD, USBD, USBD); | 335 | impl_usb!(USBD, USBD, USBD); |
| 331 | 336 | ||
| 332 | impl_uarte!(SERIAL0, UARTE0, SERIAL0); | 337 | impl_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 | ||
| 206 | impl_ipc!(IPC, IPC, IPC); | ||
| 207 | |||
| 203 | impl_uarte!(SERIAL0, UARTE0, SERIAL0); | 208 | impl_uarte!(SERIAL0, UARTE0, SERIAL0); |
| 204 | impl_spim!(SERIAL0, SPIM0, SERIAL0); | 209 | impl_spim!(SERIAL0, SPIM0, SERIAL0); |
| 205 | impl_spis!(SERIAL0, SPIS0, SERIAL0); | 210 | impl_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 | |||
| 5 | use core::future::poll_fn; | ||
| 6 | use core::marker::PhantomData; | ||
| 7 | use core::task::Poll; | ||
| 8 | |||
| 9 | use embassy_hal_internal::{Peri, PeripheralType}; | ||
| 10 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 11 | |||
| 12 | use crate::interrupt::typelevel::Interrupt; | ||
| 13 | use crate::{interrupt, pac, ppi}; | ||
| 14 | |||
| 15 | const EVENT_COUNT: usize = 16; | ||
| 16 | |||
| 17 | /// IPC Event | ||
| 18 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
| 19 | pub 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 | |||
| 54 | const 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)] | ||
| 75 | pub 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 | |||
| 110 | impl IpcChannel { | ||
| 111 | fn mask(self) -> u32 { | ||
| 112 | 1 << (self as u32) | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | /// Interrupt Handler | ||
| 117 | pub struct InterruptHandler<T: Instance> { | ||
| 118 | _phantom: PhantomData<T>, | ||
| 119 | } | ||
| 120 | |||
| 121 | impl<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] | ||
| 137 | pub 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 | |||
| 172 | impl<'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 | ||
| 206 | pub struct Event<'d, T: Instance> { | ||
| 207 | number: EventNumber, | ||
| 208 | _phantom: PhantomData<&'d T>, | ||
| 209 | } | ||
| 210 | |||
| 211 | impl<'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)] | ||
| 305 | pub struct EventTrigger<'d, T: Instance> { | ||
| 306 | number: EventNumber, | ||
| 307 | _phantom: PhantomData<&'d T>, | ||
| 308 | } | ||
| 309 | |||
| 310 | impl<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 | |||
| 323 | pub(crate) struct State { | ||
| 324 | wakers: [AtomicWaker; EVENT_COUNT], | ||
| 325 | } | ||
| 326 | |||
| 327 | impl State { | ||
| 328 | pub(crate) const fn new() -> Self { | ||
| 329 | Self { | ||
| 330 | wakers: [const { AtomicWaker::new() }; EVENT_COUNT], | ||
| 331 | } | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | pub(crate) trait SealedInstance { | ||
| 336 | fn regs() -> pac::ipc::Ipc; | ||
| 337 | fn state() -> &'static State; | ||
| 338 | } | ||
| 339 | |||
| 340 | /// IPC peripheral instance. | ||
| 341 | #[allow(private_bounds)] | ||
| 342 | pub trait Instance: PeripheralType + SealedInstance + 'static + Send { | ||
| 343 | /// Interrupt for this peripheral. | ||
| 344 | type Interrupt: interrupt::typelevel::Interrupt; | ||
| 345 | } | ||
| 346 | |||
| 347 | macro_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"))] |
| 90 | pub mod i2s; | 90 | pub mod i2s; |
| 91 | #[cfg(feature = "_nrf5340")] | ||
| 92 | pub 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] |
| 28 | default = [ "rt" ] | 28 | default = [ "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. | ||
| 30 | rt = [ "rp-pac/rt" ] | 33 | rt = [ "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")] |
| 4 | use core::arch::asm; | 67 | use 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 | |||
| 21 | struct Clocks { | 85 | struct 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)] | ||
| 146 | pub 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")] | ||
| 172 | impl 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] |
| 74 | pub struct ClockConfig { | 194 | pub 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 | ||
| 224 | impl 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 | |||
| 96 | impl ClockConfig { | 264 | impl 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)] | ||
| 254 | pub struct PllConfig { | 568 | pub 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 | ||
| 579 | impl 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. |
| 266 | pub struct RefClkConfig { | 624 | pub 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")] | ||
| 795 | fn 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 |
| 409 | pub(crate) unsafe fn init(config: ClockConfig) { | 869 | pub(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)] |
| 787 | fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { | 1298 | fn 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); | |||
| 906 | pub enum GpoutSrc { | 1470 | pub 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)] | ||
| 1768 | mod 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 | |||
| 3 | use fixed::traits::ToFixed; | ||
| 4 | use fixed::types::extra::U8; | ||
| 5 | |||
| 6 | use 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] | ||
| 18 | pub 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 | }; |
| 8 | use crate::pio_programs::clock_divider::calculate_pio_clock_divider; | ||
| 8 | use crate::Peri; | 9 | use 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 | ||
| 3 | pub mod clock_divider; | ||
| 3 | pub mod hd44780; | 4 | pub mod hd44780; |
| 4 | pub mod i2s; | 5 | pub mod i2s; |
| 5 | pub mod onewire; | 6 | pub 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 | ||
| 3 | use fixed::traits::ToFixed; | ||
| 4 | |||
| 5 | use crate::gpio::Pull; | 3 | use crate::gpio::Pull; |
| 6 | use crate::pio::{ | 4 | use 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 | }; |
| 7 | use crate::pio_programs::clock_divider::calculate_pio_clock_divider; | ||
| 9 | use crate::Peri; | 8 | use 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 | ||
| 3 | use core::mem::{self, MaybeUninit}; | 3 | use core::mem::{self, MaybeUninit}; |
| 4 | 4 | ||
| 5 | use fixed::traits::ToFixed; | ||
| 6 | use fixed::types::extra::U8; | ||
| 7 | use fixed::FixedU32; | ||
| 8 | |||
| 9 | use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine}; | 5 | use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine}; |
| 6 | use crate::pio_programs::clock_divider::calculate_pio_clock_divider; | ||
| 10 | use crate::Peri; | 7 | use 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. |
| 37 | pub struct BufferedUart<'d, T: Instance> { | 37 | pub 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. |
| 43 | pub struct BufferedUartRx<'d, T: Instance> { | 43 | pub 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. |
| 48 | pub struct BufferedUartTx<'d, T: Instance> { | 49 | pub 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 | ||
| 52 | pub(crate) fn init_buffers<'d, T: Instance + 'd>( | 54 | pub(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 | ||
| 90 | impl<'d, T: Instance> BufferedUart<'d, T> { | 90 | impl 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 | ||
| 180 | impl<'d, T: Instance> BufferedUartRx<'d, T> { | 193 | impl 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 | ||
| 330 | impl<'d, T: Instance> BufferedUartTx<'d, T> { | 338 | impl 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 | ||
| 469 | impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { | 483 | impl 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 | ||
| 482 | impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> { | 495 | impl 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 | ||
| 500 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterruptHandler<T> { | 512 | impl<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 | ||
| 606 | impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUart<'d, T> { | 618 | impl embedded_io_async::ErrorType for BufferedUart { |
| 607 | type Error = Error; | 619 | type Error = Error; |
| 608 | } | 620 | } |
| 609 | 621 | ||
| 610 | impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUartRx<'d, T> { | 622 | impl embedded_io_async::ErrorType for BufferedUartRx { |
| 611 | type Error = Error; | 623 | type Error = Error; |
| 612 | } | 624 | } |
| 613 | 625 | ||
| 614 | impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUartTx<'d, T> { | 626 | impl embedded_io_async::ErrorType for BufferedUartTx { |
| 615 | type Error = Error; | 627 | type Error = Error; |
| 616 | } | 628 | } |
| 617 | 629 | ||
| 618 | impl<'d, T: Instance + 'd> embedded_io_async::Read for BufferedUart<'d, T> { | 630 | impl 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 | ||
| 624 | impl<'d, T: Instance + 'd> embedded_io_async::Read for BufferedUartRx<'d, T> { | 636 | impl 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 | ||
| 630 | impl<'d, T: Instance + 'd> embedded_io_async::ReadReady for BufferedUart<'d, T> { | 642 | impl 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 | ||
| 636 | impl<'d, T: Instance + 'd> embedded_io_async::ReadReady for BufferedUartRx<'d, T> { | 648 | impl 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 | ||
| 642 | impl<'d, T: Instance + 'd> embedded_io_async::BufRead for BufferedUart<'d, T> { | 654 | impl 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 | ||
| 652 | impl<'d, T: Instance + 'd> embedded_io_async::BufRead for BufferedUartRx<'d, T> { | 664 | impl 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 | ||
| 662 | impl<'d, T: Instance + 'd> embedded_io_async::Write for BufferedUart<'d, T> { | 674 | impl 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 | ||
| 672 | impl<'d, T: Instance + 'd> embedded_io_async::Write for BufferedUartTx<'d, T> { | 684 | impl 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 | ||
| 682 | impl<'d, T: Instance + 'd> embedded_io::Read for BufferedUart<'d, T> { | 694 | impl 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 | ||
| 688 | impl<'d, T: Instance + 'd> embedded_io::Read for BufferedUartRx<'d, T> { | 700 | impl 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 | ||
| 694 | impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUart<'d, T> { | 706 | impl 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 | ||
| 704 | impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUartTx<'d, T> { | 716 | impl 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 | ||
| 714 | impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUartRx<'d, T> { | 726 | impl 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 | ||
| 739 | impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUartTx<'d, T> { | 751 | impl 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 | ||
| 758 | impl<'d, T: Instance> embedded_hal_02::serial::Read<u8> for BufferedUart<'d, T> { | 770 | impl 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 | ||
| 766 | impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUart<'d, T> { | 778 | impl 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 | ||
| 785 | impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUartRx<'d, T> { | 797 | impl embedded_hal_nb::serial::ErrorType for BufferedUartRx { |
| 786 | type Error = Error; | 798 | type Error = Error; |
| 787 | } | 799 | } |
| 788 | 800 | ||
| 789 | impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUartTx<'d, T> { | 801 | impl embedded_hal_nb::serial::ErrorType for BufferedUartTx { |
| 790 | type Error = Error; | 802 | type Error = Error; |
| 791 | } | 803 | } |
| 792 | 804 | ||
| 793 | impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUart<'d, T> { | 805 | impl embedded_hal_nb::serial::ErrorType for BufferedUart { |
| 794 | type Error = Error; | 806 | type Error = Error; |
| 795 | } | 807 | } |
| 796 | 808 | ||
| 797 | impl<'d, T: Instance> embedded_hal_nb::serial::Read for BufferedUartRx<'d, T> { | 809 | impl 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 | ||
| 803 | impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> { | 815 | impl 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 | ||
| 813 | impl<'d, T: Instance> embedded_hal_nb::serial::Read for BufferedUart<'d, T> { | 825 | impl 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 | ||
| 819 | impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUart<'d, T> { | 831 | impl 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; | |||
| 13 | use crate::clocks::clk_peri_freq; | 13 | use crate::clocks::clk_peri_freq; |
| 14 | use crate::dma::{AnyChannel, Channel}; | 14 | use crate::dma::{AnyChannel, Channel}; |
| 15 | use crate::gpio::{AnyPin, SealedPin}; | 15 | use crate::gpio::{AnyPin, SealedPin}; |
| 16 | use crate::interrupt::typelevel::{Binding, Interrupt}; | 16 | use crate::interrupt::typelevel::{Binding, Interrupt as _}; |
| 17 | use crate::interrupt::{Interrupt, InterruptExt}; | ||
| 17 | use crate::pac::io::vals::{Inover, Outover}; | 18 | use crate::pac::io::vals::{Inover, Outover}; |
| 18 | use crate::{interrupt, pac, peripherals, RegExt}; | 19 | use crate::{interrupt, pac, peripherals, RegExt}; |
| 19 | 20 | ||
| @@ -135,37 +136,41 @@ pub struct DmaState { | |||
| 135 | } | 136 | } |
| 136 | 137 | ||
| 137 | /// UART driver. | 138 | /// UART driver. |
| 138 | pub struct Uart<'d, T: Instance, M: Mode> { | 139 | pub 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. |
| 144 | pub struct UartTx<'d, T: Instance, M: Mode> { | 145 | pub 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. |
| 150 | pub struct UartRx<'d, T: Instance, M: Mode> { | 152 | pub 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 | ||
| 155 | impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { | 159 | impl<'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 | ||
| 225 | impl<'d, T: Instance> UartTx<'d, T, Blocking> { | 229 | impl<'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 | ||
| 245 | impl<'d, T: Instance> UartTx<'d, T, Async> { | 252 | impl<'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 | ||
| 262 | impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { | 274 | impl<'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 | ||
| 326 | impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { | 345 | impl<'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 | ||
| 340 | impl<'d, T: Instance> UartRx<'d, T, Blocking> { | 359 | impl<'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 | ||
| 365 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | 387 | impl<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 | ||
| 383 | impl<'d, T: Instance> UartRx<'d, T, Async> { | 405 | impl<'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 | ||
| 688 | impl<'d, T: Instance> Uart<'d, T, Blocking> { | 715 | impl<'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 | ||
| 738 | impl<'d, T: Instance> Uart<'d, T, Async> { | 771 | impl<'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 | ||
| 788 | impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { | 821 | impl<'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 | ||
| 1009 | impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { | 1044 | impl<'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 | ||
| 1049 | impl<'d, T: Instance> Uart<'d, T, Async> { | 1084 | impl<'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 | ||
| 1079 | impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> { | 1114 | impl<'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 | ||
| 1103 | impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d, T, M> { | 1138 | impl<'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 | ||
| 1125 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, M> { | 1160 | impl<'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 | ||
| 1137 | impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T, M> { | 1172 | impl<'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 | ||
| 1145 | impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for Uart<'d, T, M> { | 1180 | impl<'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 | ||
| 1157 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, M> { | 1192 | impl<'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 | ||
| 1180 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, M> { | 1215 | impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, M> { |
| 1181 | type Error = Error; | 1216 | type Error = Error; |
| 1182 | } | 1217 | } |
| 1183 | 1218 | ||
| 1184 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, M> { | 1219 | impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, M> { |
| 1185 | type Error = Error; | 1220 | type Error = Error; |
| 1186 | } | 1221 | } |
| 1187 | 1222 | ||
| 1188 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, T, M> { | 1223 | impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, M> { |
| 1189 | type Error = Error; | 1224 | type Error = Error; |
| 1190 | } | 1225 | } |
| 1191 | 1226 | ||
| 1192 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> { | 1227 | impl<'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 | ||
| 1215 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, M> { | 1250 | impl<'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 | ||
| 1225 | impl<'d, T: Instance> embedded_io::ErrorType for UartTx<'d, T, Blocking> { | 1260 | impl<'d> embedded_io::ErrorType for UartTx<'d, Blocking> { |
| 1226 | type Error = Error; | 1261 | type Error = Error; |
| 1227 | } | 1262 | } |
| 1228 | 1263 | ||
| 1229 | impl<'d, T: Instance> embedded_io::Write for UartTx<'d, T, Blocking> { | 1264 | impl<'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 | ||
| 1239 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, T, M> { | 1274 | impl<'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 | ||
| 1245 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> { | 1280 | impl<'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 | ||
| 1255 | impl<'d, T: Instance> embedded_io::ErrorType for Uart<'d, T, Blocking> { | 1290 | impl<'d> embedded_io::ErrorType for Uart<'d, Blocking> { |
| 1256 | type Error = Error; | 1291 | type Error = Error; |
| 1257 | } | 1292 | } |
| 1258 | 1293 | ||
| 1259 | impl<'d, T: Instance> embedded_io::Write for Uart<'d, T, Blocking> { | 1294 | impl<'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 | ||
| 1304 | struct 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 | |||
| 1269 | trait SealedMode {} | 1311 | trait SealedMode {} |
| 1270 | 1312 | ||
| 1271 | trait SealedInstance { | 1313 | trait 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 { | |||
| 1308 | macro_rules! impl_instance { | 1347 | macro_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))] | ||
| 34 | pub struct PwmPinConfig { | 36 | pub 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 | |||
| 4 | extern crate embassy_imxrt_examples; | ||
| 5 | |||
| 6 | use defmt::*; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_imxrt::crc::{Config, Crc, Polynomial}; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async 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 | |||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_rp::clocks::{clk_sys_freq, ClockConfig}; | ||
| 11 | use embassy_rp::config::Config; | ||
| 12 | use embassy_rp::gpio::{Level, Output}; | ||
| 13 | use embassy_time::{Duration, Instant, Timer}; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | const COUNT_TO: i64 = 10_000_000; | ||
| 17 | |||
| 18 | #[embassy_executor::main] | ||
| 19 | async 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 | |||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Spawner; | ||
| 10 | use embassy_rp::clocks; | ||
| 11 | use embassy_rp::clocks::{ClockConfig, CoreVoltage, PllConfig}; | ||
| 12 | use embassy_rp::config::Config; | ||
| 13 | use embassy_rp::gpio::{Level, Output}; | ||
| 14 | use embassy_time::{Duration, Instant, Timer}; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | const COUNT_TO: i64 = 10_000_000; | ||
| 18 | |||
| 19 | /// Configure the RP2040 for 200 MHz operation by manually specifying the PLL settings. | ||
| 20 | fn 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] | ||
| 40 | async 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; | |||
| 31 | use static_cell::{ConstStaticCell, StaticCell}; | 31 | use static_cell::{ConstStaticCell, StaticCell}; |
| 32 | use {defmt_rtt as _, panic_probe as _}; | 32 | use {defmt_rtt as _, panic_probe as _}; |
| 33 | 33 | ||
| 34 | type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>; | 34 | type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, uart::Async>>; |
| 35 | 35 | ||
| 36 | struct MyType { | 36 | struct 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] |
| 51 | async fn reader(mut rx: BufferedUartRx<'static, UART0>) { | 51 | async 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] |
| 42 | async fn reader(mut rx: UartRx<'static, UART1, Async>) { | 42 | async 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; | |||
| 31 | use static_cell::{ConstStaticCell, StaticCell}; | 31 | use static_cell::{ConstStaticCell, StaticCell}; |
| 32 | use {defmt_rtt as _, panic_probe as _}; | 32 | use {defmt_rtt as _, panic_probe as _}; |
| 33 | 33 | ||
| 34 | type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>; | 34 | type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, uart::Async>>; |
| 35 | 35 | ||
| 36 | struct MyType { | 36 | struct 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] |
| 51 | async fn reader(mut rx: BufferedUartRx<'static, UART0>) { | 51 | async 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] |
| 42 | async fn reader(mut rx: UartRx<'static, UART1, Async>) { | 42 | async 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")] | ||
| 5 | teleprobe_meta::target!(b"rpi-pico"); | ||
| 6 | #[cfg(feature = "rp235xb")] | ||
| 7 | teleprobe_meta::target!(b"pimoroni-pico-plus-2"); | ||
| 8 | |||
| 9 | use defmt::info; | ||
| 10 | #[cfg(feature = "rp2040")] | ||
| 11 | use defmt::{assert, assert_eq}; | ||
| 12 | use embassy_executor::Spawner; | ||
| 13 | use embassy_rp::clocks; | ||
| 14 | #[cfg(feature = "rp2040")] | ||
| 15 | use embassy_rp::clocks::ClockConfig; | ||
| 16 | #[cfg(feature = "rp2040")] | ||
| 17 | use embassy_rp::clocks::CoreVoltage; | ||
| 18 | use embassy_rp::config::Config; | ||
| 19 | use embassy_time::Instant; | ||
| 20 | use {defmt_rtt as _, panic_probe as _}; | ||
| 21 | |||
| 22 | const COUNT_TO: i64 = 10_000_000; | ||
| 23 | |||
| 24 | #[embassy_executor::main] | ||
| 25 | async 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"); | |||
| 8 | use defmt::{assert_eq, *}; | 8 | use defmt::{assert_eq, *}; |
| 9 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| 10 | use embassy_rp::gpio::{Level, Output}; | 10 | use embassy_rp::gpio::{Level, Output}; |
| 11 | use embassy_rp::uart::{Blocking, Config, Error, Instance, Parity, Uart, UartRx}; | 11 | use embassy_rp::uart::{Blocking, Config, Error, Parity, Uart, UartRx}; |
| 12 | use embassy_time::Timer; | 12 | use embassy_time::Timer; |
| 13 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 14 | ||
| 15 | fn read<const N: usize>(uart: &mut Uart<'_, impl Instance, Blocking>) -> Result<[u8; N], Error> { | 15 | fn 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 | ||
| 21 | fn read1<const N: usize>(uart: &mut UartRx<'_, impl Instance, Blocking>) -> Result<[u8; N], Error> { | 21 | fn 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; | |||
| 10 | use embassy_rp::bind_interrupts; | 10 | use embassy_rp::bind_interrupts; |
| 11 | use embassy_rp::gpio::{Level, Output}; | 11 | use embassy_rp::gpio::{Level, Output}; |
| 12 | use embassy_rp::peripherals::UART0; | 12 | use embassy_rp::peripherals::UART0; |
| 13 | use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config, Error, Instance, Parity}; | 13 | use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config, Error, Parity}; |
| 14 | use embassy_time::Timer; | 14 | use embassy_time::Timer; |
| 15 | use embedded_io_async::{Read, ReadExactError, Write}; | 15 | use embedded_io_async::{Read, ReadExactError, Write}; |
| 16 | use {defmt_rtt as _, panic_probe as _}; | 16 | use {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 | ||
| 22 | async fn read<const N: usize>(uart: &mut BufferedUart<'_, impl Instance>) -> Result<[u8; N], Error> { | 22 | async 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 | ||
| 32 | async fn read1<const N: usize>(uart: &mut BufferedUartRx<'_, impl Instance>) -> Result<[u8; N], Error> { | 32 | async 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; | |||
| 10 | use embassy_rp::bind_interrupts; | 10 | use embassy_rp::bind_interrupts; |
| 11 | use embassy_rp::gpio::{Level, Output}; | 11 | use embassy_rp::gpio::{Level, Output}; |
| 12 | use embassy_rp::peripherals::UART0; | 12 | use embassy_rp::peripherals::UART0; |
| 13 | use embassy_rp::uart::{Async, Config, Error, Instance, InterruptHandler, Parity, Uart, UartRx}; | 13 | use embassy_rp::uart::{Async, Config, Error, InterruptHandler, Parity, Uart, UartRx}; |
| 14 | use embassy_time::Timer; | 14 | use embassy_time::Timer; |
| 15 | use {defmt_rtt as _, panic_probe as _}; | 15 | use {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 | ||
| 21 | async fn read<const N: usize>(uart: &mut Uart<'_, impl Instance, Async>) -> Result<[u8; N], Error> { | 21 | async 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 | ||
| 27 | async fn read1<const N: usize>(uart: &mut UartRx<'_, impl Instance, Async>) -> Result<[u8; N], Error> { | 27 | async 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) |
