From 68014469dd8ed87715ef0eb61af9181b7838d31e Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Fri, 19 Nov 2021 17:19:04 +0000 Subject: [PATCH 1/4] Add SIO FIFO interface. --- rp2040-hal/src/sio.rs | 88 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/rp2040-hal/src/sio.rs b/rp2040-hal/src/sio.rs index c70fef2..ecd0466 100644 --- a/rp2040-hal/src/sio.rs +++ b/rp2040-hal/src/sio.rs @@ -24,6 +24,11 @@ pub struct SioGpioBank0 { _private: (), } +/// Marker struct for ownership of SIO FIFO +pub struct SioFifo { + _private: (), +} + /// Marker struct for ownership of SIO gpio qspi pub struct SioGpioQspi { _private: (), @@ -51,6 +56,8 @@ pub struct Sio { pub gpio_qspi: SioGpioQspi, /// 8-cycle hardware divide/modulo module pub hwdivider: HwDivider, + /// Inter-core FIFO + pub fifo: SioFifo, // we can hand out other things here, for example: // interp0 // interp1 @@ -60,15 +67,92 @@ impl Sio { pub fn new(sio: pac::SIO) -> Self { Self { _sio: sio, - gpio_bank0: SioGpioBank0 { _private: () }, gpio_qspi: SioGpioQspi { _private: () }, - + fifo: SioFifo { _private: () }, hwdivider: HwDivider { _private: () }, } } } +impl SioFifo { + /// Check if the inter-core FIFO has valid data for reading. + /// + /// Returning `true` means there is valid data, `false` means it is empty + /// and you must not read from it. + pub fn is_read_ready(&mut self) -> bool { + let sio = unsafe { &(*pac::SIO::ptr()) }; + sio.fifo_st.read().vld().bit_is_set() + } + + /// Check if the inter-core FIFO is ready to receive data. + /// + /// Returning `true` means there is room, `false` means it is full and you + /// must not write to it. + pub fn is_write_ready(&mut self) -> bool { + let sio = unsafe { &(*pac::SIO::ptr()) }; + sio.fifo_st.read().rdy().bit_is_set() + } + + /// Return the FIFO status, as an integer. + pub fn status(&self) -> u32 { + let sio = unsafe { &(*pac::SIO::ptr()) }; + sio.fifo_st.read().bits() + } + + /// Write to the inter-core FIFO. + /// + /// You must ensure the FIFO has space by calling `is_write_ready` + pub fn write(&mut self, value: u32) { + let sio = unsafe { &(*pac::SIO::ptr()) }; + sio.fifo_wr.write(|w| unsafe { w.bits(value) }); + } + + /// Read from the inter-core FIFO. + /// + /// Will return `Some(data)`, or `None` if the FIFO is empty. + pub fn read(&mut self) -> Option { + if self.is_read_ready() { + let sio = unsafe { &(*pac::SIO::ptr()) }; + Some(sio.fifo_rd.read().bits()) + } else { + None + } + } + + /// Read from the FIFO until it is empty, throwing the contents away. + pub fn drain(&mut self) { + while let Some(_) = self.read() { + // Spin until FIFO empty + } + } + + /// Push to the FIFO, spinning if there's no space. + pub fn write_blocking(&mut self, value: u32) { + // We wait for the FIFO to have some space + while !self.is_write_ready() { + cortex_m::asm::wfe(); + } + + // Write the value to the FIFO - the other core will now be able to pop it + // off its end of the FIFO. + self.write(value as u32); + + // Fire off an event to the other core + cortex_m::asm::sev(); + } + + /// Pop from the FIFO, spinning if there's currently no data. + pub fn read_blocking(&mut self) -> u32 { + // Spin until FIFO has data + loop { + if let Some(data) = self.read() { + return data; + } + } + } +} + impl HwDivider { /// Perform hardware unsigned divide/modulo operation pub fn unsigned(&self, dividend: u32, divisor: u32) -> DivResult { From 038f792e211bef4f61b7e979c041e8f4e531f045 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Fri, 19 Nov 2021 17:38:32 +0000 Subject: [PATCH 2/4] Apply clippy's suggestions. --- rp2040-hal/src/sio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rp2040-hal/src/sio.rs b/rp2040-hal/src/sio.rs index ecd0466..4c326b2 100644 --- a/rp2040-hal/src/sio.rs +++ b/rp2040-hal/src/sio.rs @@ -122,7 +122,7 @@ impl SioFifo { /// Read from the FIFO until it is empty, throwing the contents away. pub fn drain(&mut self) { - while let Some(_) = self.read() { + while self.read().is_some() { // Spin until FIFO empty } } From e9694bbb91c66e67df7150fa900a82d9fad928ff Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (Ferrous Systems)" Date: Thu, 25 Nov 2021 14:45:28 +0000 Subject: [PATCH 3/4] Use released 0.2.0 PAC. --- rp2040-hal/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rp2040-hal/Cargo.toml b/rp2040-hal/Cargo.toml index 8e4ff4b..a6b14d7 100644 --- a/rp2040-hal/Cargo.toml +++ b/rp2040-hal/Cargo.toml @@ -16,7 +16,7 @@ eh1_0_alpha = { version = "=1.0.0-alpha.5", package="embedded-hal", optional=tru embedded-time = "0.12.0" itertools = { version = "0.10.1", default-features = false } nb = "1.0" -rp2040-pac = { git = "https://github.com/rp-rs/rp2040-pac.git", branch = "release_016", version = "0.1.6" } +rp2040-pac = "0.2.0" paste = "1.0" pio = { git = "https://github.com/rp-rs/pio-rs.git", branch = "main" } usb-device = "0.2.8" From 69255f7b8c92b7c3c402e730f77f0fb3d0d3df34 Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (Ferrous Systems)" Date: Thu, 25 Nov 2021 15:14:03 +0000 Subject: [PATCH 4/4] Fix wfe/sev semantics. We must sev on write, so the other core can wfe on read. --- rp2040-hal/src/sio.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/rp2040-hal/src/sio.rs b/rp2040-hal/src/sio.rs index 4c326b2..f8583cd 100644 --- a/rp2040-hal/src/sio.rs +++ b/rp2040-hal/src/sio.rs @@ -62,6 +62,7 @@ pub struct Sio { // interp0 // interp1 } + impl Sio { /// Create `Sio` from the PAC. pub fn new(sio: pac::SIO) -> Self { @@ -123,19 +124,19 @@ impl SioFifo { /// Read from the FIFO until it is empty, throwing the contents away. pub fn drain(&mut self) { while self.read().is_some() { - // Spin until FIFO empty + // Retry until FIFO empty } } /// Push to the FIFO, spinning if there's no space. pub fn write_blocking(&mut self, value: u32) { - // We wait for the FIFO to have some space + // We busy-wait for the FIFO to have some space while !self.is_write_ready() { - cortex_m::asm::wfe(); + cortex_m::asm::nop(); } - // Write the value to the FIFO - the other core will now be able to pop it - // off its end of the FIFO. + // Write the value to the FIFO - the other core will now be able to + // pop it off its end of the FIFO. self.write(value as u32); // Fire off an event to the other core @@ -144,10 +145,16 @@ impl SioFifo { /// Pop from the FIFO, spinning if there's currently no data. pub fn read_blocking(&mut self) -> u32 { - // Spin until FIFO has data + // Keep trying until FIFO has data loop { + // Have we got something? if let Some(data) = self.read() { + // Yes, return it right away return data; + } else { + // No, so sleep the CPU. We expect the sending core to `sev` + // on write. + cortex_m::asm::wfe(); } } }