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 {