2021-05-10 23:29:59 +10:00
|
|
|
//! Single Cycle Input and Output (SIO)
|
2021-05-10 13:33:36 +10:00
|
|
|
//!
|
|
|
|
//! To be able to partition parts of the SIO block to other modules:
|
|
|
|
//!
|
2021-08-11 10:53:42 +10:00
|
|
|
//! ```no_run
|
|
|
|
//! use rp2040_hal::{gpio::Pins, pac, sio::Sio};
|
|
|
|
//!
|
2021-05-24 12:08:42 +10:00
|
|
|
//! let mut peripherals = pac::Peripherals::take().unwrap();
|
|
|
|
//! let sio = Sio::new(peripherals.SIO);
|
2021-05-10 13:33:36 +10:00
|
|
|
//! ```
|
|
|
|
//!
|
|
|
|
//! And then for example
|
|
|
|
//!
|
2021-08-11 10:53:42 +10:00
|
|
|
//! ```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);
|
2021-05-10 13:33:36 +10:00
|
|
|
//! ```
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
/// Marker struct for ownership of SIO gpio bank0
|
2021-05-10 23:29:59 +10:00
|
|
|
pub struct SioGpioBank0 {
|
2021-05-29 22:26:49 +10:00
|
|
|
_private: (),
|
|
|
|
}
|
|
|
|
|
2021-11-20 04:19:04 +11:00
|
|
|
/// Marker struct for ownership of SIO FIFO
|
|
|
|
pub struct SioFifo {
|
|
|
|
_private: (),
|
|
|
|
}
|
|
|
|
|
2021-05-24 12:08:42 +10:00
|
|
|
/// Marker struct for ownership of SIO gpio qspi
|
|
|
|
pub struct SioGpioQspi {
|
|
|
|
_private: (),
|
|
|
|
}
|
|
|
|
|
2021-05-29 22:26:49 +10:00
|
|
|
/// Marker struct for ownership of divide/modulo module
|
|
|
|
pub struct HwDivider {
|
|
|
|
_private: (),
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Result of divide/modulo operation
|
|
|
|
pub struct DivResult<T> {
|
|
|
|
/// The remainder of divide/modulo operation
|
|
|
|
pub remainder: T,
|
|
|
|
/// The quotient of divide/modulo operation
|
|
|
|
pub quotient: T,
|
2021-05-10 23:29:59 +10:00
|
|
|
}
|
2021-05-10 13:33:36 +10:00
|
|
|
|
|
|
|
/// Struct containing ownership markers for managing ownership of the SIO registers.
|
|
|
|
pub struct Sio {
|
2021-05-10 23:29:59 +10:00
|
|
|
_sio: pac::SIO,
|
2021-05-10 13:33:36 +10:00
|
|
|
/// GPIO Bank 0 registers
|
2021-05-10 23:29:59 +10:00
|
|
|
pub gpio_bank0: SioGpioBank0,
|
2021-05-24 12:08:42 +10:00
|
|
|
/// GPIO QSPI registers
|
|
|
|
pub gpio_qspi: SioGpioQspi,
|
2021-05-29 22:26:49 +10:00
|
|
|
/// 8-cycle hardware divide/modulo module
|
|
|
|
pub hwdivider: HwDivider,
|
2021-11-20 04:19:04 +11:00
|
|
|
/// Inter-core FIFO
|
|
|
|
pub fifo: SioFifo,
|
2021-05-10 13:33:36 +10:00
|
|
|
// we can hand out other things here, for example:
|
|
|
|
// interp0
|
|
|
|
// interp1
|
|
|
|
}
|
|
|
|
impl Sio {
|
|
|
|
/// Create `Sio` from the PAC.
|
2021-05-10 23:29:59 +10:00
|
|
|
pub fn new(sio: pac::SIO) -> Self {
|
2021-05-10 13:33:36 +10:00
|
|
|
Self {
|
|
|
|
_sio: sio,
|
2021-05-29 22:26:49 +10:00
|
|
|
gpio_bank0: SioGpioBank0 { _private: () },
|
2021-05-24 12:08:42 +10:00
|
|
|
gpio_qspi: SioGpioQspi { _private: () },
|
2021-11-20 04:19:04 +11:00
|
|
|
fifo: SioFifo { _private: () },
|
2021-05-29 22:26:49 +10:00
|
|
|
hwdivider: HwDivider { _private: () },
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-20 04:19:04 +11:00
|
|
|
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<u32> {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-29 22:26:49 +10:00
|
|
|
impl HwDivider {
|
|
|
|
/// Perform hardware unsigned divide/modulo operation
|
|
|
|
pub fn unsigned(&self, dividend: u32, divisor: u32) -> DivResult<u32> {
|
|
|
|
let sio = unsafe { &(*pac::SIO::ptr()) };
|
2021-07-30 02:20:31 +10:00
|
|
|
sio.div_udividend.write(|w| unsafe { w.bits(dividend) });
|
2021-05-29 22:26:49 +10:00
|
|
|
|
2021-07-30 02:20:31 +10:00
|
|
|
sio.div_udivisor.write(|w| unsafe { w.bits(divisor) });
|
2021-05-29 22:26:49 +10:00
|
|
|
|
|
|
|
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<i32> {
|
|
|
|
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,
|
2021-05-10 13:33:36 +10:00
|
|
|
}
|
|
|
|
}
|
2021-05-10 23:29:59 +10:00
|
|
|
}
|