diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-12-08 01:43:25 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-12-08 01:43:25 +0000 |
| commit | 6081b36356878f969457c80b6069f7fefcde6a29 (patch) | |
| tree | 8d2d1e40bc8d14df64647b0bff18b847c8dd31bc | |
| parent | c574b0eb7331292f1b8af278402da5af50fedf5d (diff) | |
| parent | 090a7adf78cd6d9dea8fee773523c53a03ae63d5 (diff) | |
Merge #525
525: Applies the Uarte patch r=huntc a=huntc
Applies the Nordic workaround found in the `Uarte` for the nRF9160 and nRF5340 to the `BufferedUarte`.
Co-authored-by: huntc <[email protected]>
| -rw-r--r-- | embassy-nrf/src/buffered_uarte.rs | 3 | ||||
| -rw-r--r-- | embassy-nrf/src/uarte.rs | 110 |
2 files changed, 56 insertions, 57 deletions
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 5468f6c0b..9b0451c12 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs | |||
| @@ -22,7 +22,7 @@ use crate::pac; | |||
| 22 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; | 22 | use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; |
| 23 | use crate::timer::Instance as TimerInstance; | 23 | use crate::timer::Instance as TimerInstance; |
| 24 | use crate::timer::{Frequency, Timer}; | 24 | use crate::timer::{Frequency, Timer}; |
| 25 | use crate::uarte::{Config, Instance as UarteInstance}; | 25 | use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance}; |
| 26 | 26 | ||
| 27 | // Re-export SVD variants to allow user to directly set values | 27 | // Re-export SVD variants to allow user to directly set values |
| 28 | pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; | 28 | pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; |
| @@ -132,6 +132,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { | |||
| 132 | irq.pend(); | 132 | irq.pend(); |
| 133 | 133 | ||
| 134 | // Enable UARTE instance | 134 | // Enable UARTE instance |
| 135 | apply_workaround_for_enable_anomaly(&r); | ||
| 135 | r.enable.write(|w| w.enable().enabled()); | 136 | r.enable.write(|w| w.enable().enabled()); |
| 136 | 137 | ||
| 137 | // BAUDRATE register values are `baudrate * 2^32 / 16000000` | 138 | // BAUDRATE register values are `baudrate * 2^32 / 16000000` |
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 60e69e032..72dcd41b2 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs | |||
| @@ -116,7 +116,7 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 116 | irq.enable(); | 116 | irq.enable(); |
| 117 | 117 | ||
| 118 | // Enable | 118 | // Enable |
| 119 | Self::apply_workaround_for_enable_anomaly(); | 119 | apply_workaround_for_enable_anomaly(&r); |
| 120 | r.enable.write(|w| w.enable().enabled()); | 120 | r.enable.write(|w| w.enable().enabled()); |
| 121 | 121 | ||
| 122 | Self { | 122 | Self { |
| @@ -124,61 +124,6 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 124 | } | 124 | } |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | #[cfg(not(any(feature = "_nrf9160", feature = "nrf5340")))] | ||
| 128 | fn apply_workaround_for_enable_anomaly() { | ||
| 129 | // Do nothing | ||
| 130 | } | ||
| 131 | |||
| 132 | #[cfg(any(feature = "_nrf9160", feature = "nrf5340"))] | ||
| 133 | fn apply_workaround_for_enable_anomaly() { | ||
| 134 | use core::ops::Deref; | ||
| 135 | |||
| 136 | let r = T::regs(); | ||
| 137 | |||
| 138 | // Apply workaround for anomalies: | ||
| 139 | // - nRF9160 - anomaly 23 | ||
| 140 | // - nRF5340 - anomaly 44 | ||
| 141 | let rxenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x564) as *const u32; | ||
| 142 | let txenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x568) as *const u32; | ||
| 143 | |||
| 144 | // NB Safety: This is taken from Nordic's driver - | ||
| 145 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 146 | if unsafe { core::ptr::read_volatile(txenable_reg) } == 1 { | ||
| 147 | r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); | ||
| 148 | } | ||
| 149 | |||
| 150 | // NB Safety: This is taken from Nordic's driver - | ||
| 151 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 152 | if unsafe { core::ptr::read_volatile(rxenable_reg) } == 1 { | ||
| 153 | r.enable.write(|w| w.enable().enabled()); | ||
| 154 | r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||
| 155 | |||
| 156 | let mut workaround_succeded = false; | ||
| 157 | // The UARTE is able to receive up to four bytes after the STOPRX task has been triggered. | ||
| 158 | // On lowest supported baud rate (1200 baud), with parity bit and two stop bits configured | ||
| 159 | // (resulting in 12 bits per data byte sent), this may take up to 40 ms. | ||
| 160 | for _ in 0..40000 { | ||
| 161 | // NB Safety: This is taken from Nordic's driver - | ||
| 162 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 163 | if unsafe { core::ptr::read_volatile(rxenable_reg) } == 0 { | ||
| 164 | workaround_succeded = true; | ||
| 165 | break; | ||
| 166 | } else { | ||
| 167 | // Need to sleep for 1us here | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | if !workaround_succeded { | ||
| 172 | panic!("Failed to apply workaround for UART"); | ||
| 173 | } | ||
| 174 | |||
| 175 | let errors = r.errorsrc.read().bits(); | ||
| 176 | // NB Safety: safe to write back the bits we just read to clear them | ||
| 177 | r.errorsrc.write(|w| unsafe { w.bits(errors) }); | ||
| 178 | r.enable.write(|w| w.enable().disabled()); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 182 | fn on_interrupt(_: *mut ()) { | 127 | fn on_interrupt(_: *mut ()) { |
| 183 | let r = T::regs(); | 128 | let r = T::regs(); |
| 184 | let s = T::state(); | 129 | let s = T::state(); |
| @@ -330,6 +275,59 @@ impl<'d, T: Instance> Write for Uarte<'d, T> { | |||
| 330 | } | 275 | } |
| 331 | } | 276 | } |
| 332 | 277 | ||
| 278 | #[cfg(not(any(feature = "_nrf9160", feature = "nrf5340")))] | ||
| 279 | pub(in crate) fn apply_workaround_for_enable_anomaly(_r: &crate::pac::uarte0::RegisterBlock) { | ||
| 280 | // Do nothing | ||
| 281 | } | ||
| 282 | |||
| 283 | #[cfg(any(feature = "_nrf9160", feature = "nrf5340"))] | ||
| 284 | pub(in crate) fn apply_workaround_for_enable_anomaly(r: &crate::pac::uarte0::RegisterBlock) { | ||
| 285 | use core::ops::Deref; | ||
| 286 | |||
| 287 | // Apply workaround for anomalies: | ||
| 288 | // - nRF9160 - anomaly 23 | ||
| 289 | // - nRF5340 - anomaly 44 | ||
| 290 | let rxenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x564) as *const u32; | ||
| 291 | let txenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x568) as *const u32; | ||
| 292 | |||
| 293 | // NB Safety: This is taken from Nordic's driver - | ||
| 294 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 295 | if unsafe { core::ptr::read_volatile(txenable_reg) } == 1 { | ||
| 296 | r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); | ||
| 297 | } | ||
| 298 | |||
| 299 | // NB Safety: This is taken from Nordic's driver - | ||
| 300 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 301 | if unsafe { core::ptr::read_volatile(rxenable_reg) } == 1 { | ||
| 302 | r.enable.write(|w| w.enable().enabled()); | ||
| 303 | r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||
| 304 | |||
| 305 | let mut workaround_succeded = false; | ||
| 306 | // The UARTE is able to receive up to four bytes after the STOPRX task has been triggered. | ||
| 307 | // On lowest supported baud rate (1200 baud), with parity bit and two stop bits configured | ||
| 308 | // (resulting in 12 bits per data byte sent), this may take up to 40 ms. | ||
| 309 | for _ in 0..40000 { | ||
| 310 | // NB Safety: This is taken from Nordic's driver - | ||
| 311 | // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 | ||
| 312 | if unsafe { core::ptr::read_volatile(rxenable_reg) } == 0 { | ||
| 313 | workaround_succeded = true; | ||
| 314 | break; | ||
| 315 | } else { | ||
| 316 | // Need to sleep for 1us here | ||
| 317 | } | ||
| 318 | } | ||
| 319 | |||
| 320 | if !workaround_succeded { | ||
| 321 | panic!("Failed to apply workaround for UART"); | ||
| 322 | } | ||
| 323 | |||
| 324 | let errors = r.errorsrc.read().bits(); | ||
| 325 | // NB Safety: safe to write back the bits we just read to clear them | ||
| 326 | r.errorsrc.write(|w| unsafe { w.bits(errors) }); | ||
| 327 | r.enable.write(|w| w.enable().disabled()); | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 333 | /// Interface to an UARTE peripheral that uses an additional timer and two PPI channels, | 331 | /// Interface to an UARTE peripheral that uses an additional timer and two PPI channels, |
| 334 | /// allowing it to implement the ReadUntilIdle trait. | 332 | /// allowing it to implement the ReadUntilIdle trait. |
| 335 | pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> { | 333 | pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> { |
