diff options
| -rw-r--r-- | embassy-rp/CHANGELOG.md | 2 | ||||
| -rw-r--r-- | embassy-rp/Cargo.toml | 3 | ||||
| -rw-r--r-- | embassy-rp/src/pio/mod.rs | 54 | ||||
| -rw-r--r-- | embassy-rp/src/uart/buffered.rs | 13 | ||||
| -rw-r--r-- | embassy-rp/src/uart/mod.rs | 28 |
5 files changed, 85 insertions, 15 deletions
diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index fa8609bbf..7480b729f 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md | |||
| @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 19 | - Add fix #4822 in PIO onewire. Change to disable the state machine before setting y register ([#4824](https://github.com/embassy-rs/embassy/pull/4824)) | 19 | - Add fix #4822 in PIO onewire. Change to disable the state machine before setting y register ([#4824](https://github.com/embassy-rs/embassy/pull/4824)) |
| 20 | - Add PIO::Ws2812 color order support | 20 | - Add PIO::Ws2812 color order support |
| 21 | - Add TX-only, no SCK SPI support | 21 | - Add TX-only, no SCK SPI support |
| 22 | - Remove atomic-polyfill with critical-section instead ([#4948](https://github.com/embassy-rs/embassy/pull/4948)) | ||
| 22 | 23 | ||
| 23 | ## 0.8.0 - 2025-08-26 | 24 | ## 0.8.0 - 2025-08-26 |
| 24 | 25 | ||
| @@ -116,4 +117,3 @@ Small release fixing a few gnarly bugs, upgrading is strongly recommended. | |||
| 116 | - rename the Channel trait to Slice and the PwmPin to PwmChannel | 117 | - rename the Channel trait to Slice and the PwmPin to PwmChannel |
| 117 | - i2c: Fix race condition that appears on fast repeated transfers. | 118 | - i2c: Fix race condition that appears on fast repeated transfers. |
| 118 | - Add a basic "read to break" function | 119 | - Add a basic "read to break" function |
| 119 | |||
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 9ad4b47a3..421f0b0f6 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml | |||
| @@ -47,7 +47,7 @@ rt = [ "rp-pac/rt" ] | |||
| 47 | defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"] | 47 | defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"] |
| 48 | ## Enable log support | 48 | ## Enable log support |
| 49 | log = ["dep:log"] | 49 | log = ["dep:log"] |
| 50 | ## Enable chrono support | 50 | ## Enable chrono support |
| 51 | chrono = ["dep:chrono"] | 51 | chrono = ["dep:chrono"] |
| 52 | 52 | ||
| 53 | ## Configure the [`critical-section`](https://docs.rs/critical-section) crate to use an implementation that is safe for multicore use on rp2040. | 53 | ## Configure the [`critical-section`](https://docs.rs/critical-section) crate to use an implementation that is safe for multicore use on rp2040. |
| @@ -159,7 +159,6 @@ embassy-futures = { version = "0.1.2", path = "../embassy-futures" } | |||
| 159 | embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } | 159 | embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } |
| 160 | embassy-embedded-hal = { version = "0.5.0", path = "../embassy-embedded-hal" } | 160 | embassy-embedded-hal = { version = "0.5.0", path = "../embassy-embedded-hal" } |
| 161 | embassy-usb-driver = { version = "0.2.0", path = "../embassy-usb-driver" } | 161 | embassy-usb-driver = { version = "0.2.0", path = "../embassy-usb-driver" } |
| 162 | atomic-polyfill = "1.0.1" | ||
| 163 | defmt = { version = "1.0.1", optional = true } | 162 | defmt = { version = "1.0.1", optional = true } |
| 164 | log = { version = "0.4.14", optional = true } | 163 | log = { version = "0.4.14", optional = true } |
| 165 | nb = "1.1.0" | 164 | nb = "1.1.0" |
diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 92b2c603e..1c370fdfc 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs | |||
| @@ -2,10 +2,9 @@ | |||
| 2 | use core::future::Future; | 2 | use core::future::Future; |
| 3 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 4 | use core::pin::Pin as FuturePin; | 4 | use core::pin::Pin as FuturePin; |
| 5 | use core::sync::atomic::{Ordering, compiler_fence}; | 5 | use core::sync::atomic::{AtomicU8, AtomicU32, Ordering, compiler_fence}; |
| 6 | use core::task::{Context, Poll}; | 6 | use core::task::{Context, Poll}; |
| 7 | 7 | ||
| 8 | use atomic_polyfill::{AtomicU8, AtomicU64}; | ||
| 9 | use embassy_hal_internal::{Peri, PeripheralType}; | 8 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 10 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| 11 | use fixed::FixedU32; | 10 | use fixed::FixedU32; |
| @@ -1232,7 +1231,13 @@ impl<'d, PIO: Instance> Common<'d, PIO> { | |||
| 1232 | w.set_pde(false); | 1231 | w.set_pde(false); |
| 1233 | }); | 1232 | }); |
| 1234 | // we can be relaxed about this because we're &mut here and nothing is cached | 1233 | // we can be relaxed about this because we're &mut here and nothing is cached |
| 1235 | PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); | 1234 | critical_section::with(|_| { |
| 1235 | let val = PIO::state().used_pins.load(Ordering::Relaxed); | ||
| 1236 | PIO::state() | ||
| 1237 | .used_pins | ||
| 1238 | .store(val | 1 << pin.pin_bank(), Ordering::Relaxed); | ||
| 1239 | }); | ||
| 1240 | |||
| 1236 | Pin { | 1241 | Pin { |
| 1237 | pin: pin.into(), | 1242 | pin: pin.into(), |
| 1238 | pio: PhantomData::default(), | 1243 | pio: PhantomData::default(), |
| @@ -1404,6 +1409,42 @@ impl<'d, PIO: Instance> Pio<'d, PIO> { | |||
| 1404 | } | 1409 | } |
| 1405 | } | 1410 | } |
| 1406 | 1411 | ||
| 1412 | struct AtomicU64 { | ||
| 1413 | upper_32: AtomicU32, | ||
| 1414 | lower_32: AtomicU32, | ||
| 1415 | } | ||
| 1416 | |||
| 1417 | impl AtomicU64 { | ||
| 1418 | const fn new(val: u64) -> Self { | ||
| 1419 | let upper_32 = (val >> 32) as u32; | ||
| 1420 | let lower_32 = val as u32; | ||
| 1421 | |||
| 1422 | Self { | ||
| 1423 | upper_32: AtomicU32::new(upper_32), | ||
| 1424 | lower_32: AtomicU32::new(lower_32), | ||
| 1425 | } | ||
| 1426 | } | ||
| 1427 | |||
| 1428 | fn load(&self, order: Ordering) -> u64 { | ||
| 1429 | let (upper, lower) = critical_section::with(|_| (self.upper_32.load(order), self.lower_32.load(order))); | ||
| 1430 | |||
| 1431 | let upper = (upper as u64) << 32; | ||
| 1432 | let lower = lower as u64; | ||
| 1433 | |||
| 1434 | upper | lower | ||
| 1435 | } | ||
| 1436 | |||
| 1437 | fn store(&self, val: u64, order: Ordering) { | ||
| 1438 | let upper_32 = (val >> 32) as u32; | ||
| 1439 | let lower_32 = val as u32; | ||
| 1440 | |||
| 1441 | critical_section::with(|_| { | ||
| 1442 | self.upper_32.store(upper_32, order); | ||
| 1443 | self.lower_32.store(lower_32, order); | ||
| 1444 | }); | ||
| 1445 | } | ||
| 1446 | } | ||
| 1447 | |||
| 1407 | /// Representation of the PIO state keeping a record of which pins are assigned to | 1448 | /// Representation of the PIO state keeping a record of which pins are assigned to |
| 1408 | /// each PIO. | 1449 | /// each PIO. |
| 1409 | // make_pio_pin notionally takes ownership of the pin it is given, but the wrapped pin | 1450 | // make_pio_pin notionally takes ownership of the pin it is given, but the wrapped pin |
| @@ -1418,7 +1459,12 @@ pub struct State { | |||
| 1418 | 1459 | ||
| 1419 | fn on_pio_drop<PIO: Instance>() { | 1460 | fn on_pio_drop<PIO: Instance>() { |
| 1420 | let state = PIO::state(); | 1461 | let state = PIO::state(); |
| 1421 | if state.users.fetch_sub(1, Ordering::AcqRel) == 1 { | 1462 | let users_state = critical_section::with(|_| { |
| 1463 | let val = state.users.load(Ordering::Acquire) - 1; | ||
| 1464 | state.users.store(val, Ordering::Release); | ||
| 1465 | val | ||
| 1466 | }); | ||
| 1467 | if users_state == 1 { | ||
| 1422 | let used_pins = state.used_pins.load(Ordering::Relaxed); | 1468 | let used_pins = state.used_pins.load(Ordering::Relaxed); |
| 1423 | let null = pac::io::vals::Gpio0ctrlFuncsel::NULL as _; | 1469 | let null = pac::io::vals::Gpio0ctrlFuncsel::NULL as _; |
| 1424 | for i in 0..crate::gpio::BANK0_PIN_COUNT { | 1470 | for i in 0..crate::gpio::BANK0_PIN_COUNT { |
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 02649ad81..fdb8ce776 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | //! Buffered UART driver. | 1 | //! Buffered UART driver. |
| 2 | use core::future::Future; | 2 | use core::future::Future; |
| 3 | use core::slice; | 3 | use core::slice; |
| 4 | use core::sync::atomic::{AtomicU8, Ordering}; | ||
| 4 | 5 | ||
| 5 | use atomic_polyfill::AtomicU8; | ||
| 6 | use embassy_hal_internal::atomic_ring_buffer::RingBuffer; | 6 | use embassy_hal_internal::atomic_ring_buffer::RingBuffer; |
| 7 | 7 | ||
| 8 | use super::*; | 8 | use super::*; |
| @@ -241,7 +241,11 @@ impl BufferedUartRx { | |||
| 241 | } | 241 | } |
| 242 | 242 | ||
| 243 | fn get_rx_error(state: &State) -> Option<Error> { | 243 | fn get_rx_error(state: &State) -> Option<Error> { |
| 244 | let errs = state.rx_error.swap(0, Ordering::Relaxed); | 244 | let errs = critical_section::with(|_| { |
| 245 | let val = state.rx_error.load(Ordering::Relaxed); | ||
| 246 | state.rx_error.store(0, Ordering::Relaxed); | ||
| 247 | val | ||
| 248 | }); | ||
| 245 | if errs & RXE_OVERRUN != 0 { | 249 | if errs & RXE_OVERRUN != 0 { |
| 246 | Some(Error::Overrun) | 250 | Some(Error::Overrun) |
| 247 | } else if errs & RXE_BREAK != 0 { | 251 | } else if errs & RXE_BREAK != 0 { |
| @@ -555,7 +559,10 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterr | |||
| 555 | } | 559 | } |
| 556 | let dr = r.uartdr().read(); | 560 | let dr = r.uartdr().read(); |
| 557 | if (dr.0 >> 8) != 0 { | 561 | if (dr.0 >> 8) != 0 { |
| 558 | s.rx_error.fetch_or((dr.0 >> 8) as u8, Ordering::Relaxed); | 562 | critical_section::with(|_| { |
| 563 | let val = s.rx_error.load(Ordering::Relaxed); | ||
| 564 | s.rx_error.store(val | ((dr.0 >> 8) as u8), Ordering::Relaxed); | ||
| 565 | }); | ||
| 559 | error = true; | 566 | error = true; |
| 560 | // only fill the buffer with valid characters. the current character is fine | 567 | // only fill the buffer with valid characters. the current character is fine |
| 561 | // if the error is an overrun, but if we add it to the buffer we'll report | 568 | // if the error is an overrun, but if we add it to the buffer we'll report |
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 8be87a5d2..b7b569dd5 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | //! UART driver. | 1 | //! UART driver. |
| 2 | use core::future::poll_fn; | 2 | use core::future::poll_fn; |
| 3 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 4 | use core::sync::atomic::{AtomicU16, Ordering}; | ||
| 4 | use core::task::Poll; | 5 | use core::task::Poll; |
| 5 | 6 | ||
| 6 | use atomic_polyfill::{AtomicU16, Ordering}; | ||
| 7 | use embassy_futures::select::{Either, select}; | 7 | use embassy_futures::select::{Either, select}; |
| 8 | use embassy_hal_internal::{Peri, PeripheralType}; | 8 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| @@ -456,7 +456,12 @@ impl<'d> UartRx<'d, Async> { | |||
| 456 | transfer, | 456 | transfer, |
| 457 | poll_fn(|cx| { | 457 | poll_fn(|cx| { |
| 458 | self.dma_state.rx_err_waker.register(cx.waker()); | 458 | self.dma_state.rx_err_waker.register(cx.waker()); |
| 459 | match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) { | 459 | let rx_errs = critical_section::with(|_| { |
| 460 | let val = self.dma_state.rx_errs.load(Ordering::Relaxed); | ||
| 461 | self.dma_state.rx_errs.store(0, Ordering::Relaxed); | ||
| 462 | val | ||
| 463 | }); | ||
| 464 | match rx_errs { | ||
| 460 | 0 => Poll::Pending, | 465 | 0 => Poll::Pending, |
| 461 | e => Poll::Ready(Uartris(e as u32)), | 466 | e => Poll::Ready(Uartris(e as u32)), |
| 462 | } | 467 | } |
| @@ -468,7 +473,11 @@ impl<'d> UartRx<'d, Async> { | |||
| 468 | Either::First(()) => { | 473 | Either::First(()) => { |
| 469 | // We're here because the DMA finished, BUT if an error occurred on the LAST | 474 | // We're here because the DMA finished, BUT if an error occurred on the LAST |
| 470 | // byte, then we may still need to grab the error state! | 475 | // byte, then we may still need to grab the error state! |
| 471 | Uartris(self.dma_state.rx_errs.swap(0, Ordering::Relaxed) as u32) | 476 | Uartris(critical_section::with(|_| { |
| 477 | let val = self.dma_state.rx_errs.load(Ordering::Relaxed); | ||
| 478 | self.dma_state.rx_errs.store(0, Ordering::Relaxed); | ||
| 479 | val | ||
| 480 | }) as u32) | ||
| 472 | } | 481 | } |
| 473 | Either::Second(e) => { | 482 | Either::Second(e) => { |
| 474 | // We're here because we errored, which means this is the error that | 483 | // We're here because we errored, which means this is the error that |
| @@ -616,7 +625,12 @@ impl<'d> UartRx<'d, Async> { | |||
| 616 | transfer, | 625 | transfer, |
| 617 | poll_fn(|cx| { | 626 | poll_fn(|cx| { |
| 618 | self.dma_state.rx_err_waker.register(cx.waker()); | 627 | self.dma_state.rx_err_waker.register(cx.waker()); |
| 619 | match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) { | 628 | let rx_errs = critical_section::with(|_| { |
| 629 | let val = self.dma_state.rx_errs.load(Ordering::Relaxed); | ||
| 630 | self.dma_state.rx_errs.store(0, Ordering::Relaxed); | ||
| 631 | val | ||
| 632 | }); | ||
| 633 | match rx_errs { | ||
| 620 | 0 => Poll::Pending, | 634 | 0 => Poll::Pending, |
| 621 | e => Poll::Ready(Uartris(e as u32)), | 635 | e => Poll::Ready(Uartris(e as u32)), |
| 622 | } | 636 | } |
| @@ -629,7 +643,11 @@ impl<'d> UartRx<'d, Async> { | |||
| 629 | Either::First(()) => { | 643 | Either::First(()) => { |
| 630 | // We're here because the DMA finished, BUT if an error occurred on the LAST | 644 | // We're here because the DMA finished, BUT if an error occurred on the LAST |
| 631 | // byte, then we may still need to grab the error state! | 645 | // byte, then we may still need to grab the error state! |
| 632 | Uartris(self.dma_state.rx_errs.swap(0, Ordering::Relaxed) as u32) | 646 | Uartris(critical_section::with(|_| { |
| 647 | let val = self.dma_state.rx_errs.load(Ordering::Relaxed); | ||
| 648 | self.dma_state.rx_errs.store(0, Ordering::Relaxed); | ||
| 649 | val | ||
| 650 | }) as u32) | ||
| 633 | } | 651 | } |
| 634 | Either::Second(e) => { | 652 | Either::Second(e) => { |
| 635 | // We're here because we errored, which means this is the error that | 653 | // We're here because we errored, which means this is the error that |
