//! Single Cycle Input and Output (SIO) //! //! To be able to partition parts of the SIO block to other modules: //! //! ```no_run //! use rp2040_hal::{gpio::Pins, pac, sio::Sio}; //! //! let mut peripherals = pac::Peripherals::take().unwrap(); //! let sio = Sio::new(peripherals.SIO); //! ``` //! //! And then for example //! //! ```no_run //! # use rp2040_hal::{gpio::Pins, pac, sio::Sio}; //! # let mut peripherals = pac::Peripherals::take().unwrap(); //! # let sio = Sio::new(peripherals.SIO); //! let pins = Pins::new(peripherals.IO_BANK0, peripherals.PADS_BANK0, sio.gpio_bank0, &mut peripherals.RESETS); //! ``` use super::*; /// Marker struct for ownership of SIO gpio bank0 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: (), } /// Marker struct for ownership of divide/modulo module pub struct HwDivider { _private: (), } /// Result of divide/modulo operation pub struct DivResult { /// The remainder of divide/modulo operation pub remainder: T, /// The quotient of divide/modulo operation pub quotient: T, } /// Struct containing ownership markers for managing ownership of the SIO registers. pub struct Sio { _sio: pac::SIO, /// GPIO Bank 0 registers pub gpio_bank0: SioGpioBank0, /// GPIO QSPI registers 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 } impl Sio { /// Create `Sio` from the PAC. 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 self.read().is_some() { // 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 { let sio = unsafe { &(*pac::SIO::ptr()) }; sio.div_udividend.write(|w| unsafe { w.bits(dividend) }); sio.div_udivisor.write(|w| unsafe { w.bits(divisor) }); cortex_m::asm::delay(8); // Note: quotient must be read last let remainder = sio.div_remainder.read().bits(); let quotient = sio.div_quotient.read().bits(); DivResult { remainder, quotient, } } /// Perform hardware signed divide/modulo operation pub fn signed(&self, dividend: i32, divisor: i32) -> DivResult { let sio = unsafe { &(*pac::SIO::ptr()) }; sio.div_sdividend .write(|w| unsafe { w.bits(dividend as u32) }); sio.div_sdivisor .write(|w| unsafe { w.bits(divisor as u32) }); cortex_m::asm::delay(8); // Note: quotient must be read last let remainder = sio.div_remainder.read().bits() as i32; let quotient = sio.div_quotient.read().bits() as i32; DivResult { remainder, quotient, } } }