use crate::typelevel::Sealed;
use super::*;
use core::convert::Infallible;
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CoreId {
#[allow(missing_docs)]
Core0 = 0,
#[allow(missing_docs)]
Core1 = 1,
}
#[derive(Debug)]
pub struct SioGpioBank0 {
_private: (),
}
#[derive(Debug)]
pub struct SioFifo {
_private: (),
}
#[derive(Debug)]
pub struct SioGpioQspi {
_private: (),
}
pub struct MachineTimer {
_private: (),
}
pub struct Sio {
_sio: pac::SIO,
pub gpio_bank0: SioGpioBank0,
pub gpio_qspi: SioGpioQspi,
pub fifo: SioFifo,
pub interp0: Interp0,
pub interp1: Interp1,
pub machine_timer: MachineTimer,
}
impl Sio {
pub fn new(sio: pac::SIO) -> Self {
Self {
_sio: sio,
gpio_bank0: SioGpioBank0 { _private: () },
gpio_qspi: SioGpioQspi { _private: () },
fifo: SioFifo { _private: () },
interp0: Interp0 {
lane0: Interp0Lane0 { _private: () },
lane1: Interp0Lane1 { _private: () },
},
interp1: Interp1 {
lane0: Interp1Lane0 { _private: () },
lane1: Interp1Lane1 { _private: () },
},
machine_timer: MachineTimer { _private: () },
}
}
pub fn read_bank0() -> u32 {
unsafe { (*pac::SIO::PTR).gpio_in().read().bits() }
}
pub fn core() -> CoreId {
match unsafe { (*pac::SIO::ptr()).cpuid().read().bits() as u8 } {
0 => CoreId::Core0,
1 => CoreId::Core1,
_ => unreachable!("This MCU only has 2 cores."),
}
}
}
impl SioFifo {
pub fn is_read_ready(&mut self) -> bool {
let sio = unsafe { &(*pac::SIO::ptr()) };
sio.fifo_st().read().vld().bit_is_set()
}
pub fn is_write_ready(&mut self) -> bool {
let sio = unsafe { &(*pac::SIO::ptr()) };
sio.fifo_st().read().rdy().bit_is_set()
}
pub fn status(&self) -> u32 {
let sio = unsafe { &(*pac::SIO::ptr()) };
sio.fifo_st().read().bits()
}
pub fn write(&mut self, value: u32) {
let sio = unsafe { &(*pac::SIO::ptr()) };
sio.fifo_wr().write(|w| unsafe { w.bits(value) });
crate::arch::sev();
}
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
}
}
pub fn drain(&mut self) {
while self.read().is_some() {
}
}
pub fn write_blocking(&mut self, value: u32) {
while !self.is_write_ready() {
crate::arch::nop();
}
self.write(value);
crate::arch::sev();
}
pub fn read_blocking(&mut self) -> u32 {
loop {
if let Some(data) = self.read() {
return data;
} else {
crate::arch::wfe();
}
}
}
}
impl MachineTimer {
pub fn read(&self) -> u64 {
let sio = unsafe { &(*pac::SIO::ptr()) };
loop {
let mtimeh = sio.mtimeh().read().mtimeh().bits();
let mtime = sio.mtime().read().mtime().bits();
let mtimeh2 = sio.mtimeh().read().mtimeh().bits();
if mtimeh == mtimeh2 {
return u64::from(mtimeh) << 32 | u64::from(mtime);
}
}
}
pub fn set_enabled(&mut self, enabled: bool) {
let sio = unsafe { &(*pac::SIO::ptr()) };
sio.mtime_ctrl().write(|w| w.en().variant(enabled));
}
pub fn set_fullspeed(&mut self, fullspeed: bool) {
let sio = unsafe { &(*pac::SIO::ptr()) };
sio.mtime_ctrl().write(|w| w.fullspeed().variant(fullspeed));
}
}
pub trait SpinlockValid: Sealed {}
pub struct Spinlock<const N: usize>(core::marker::PhantomData<()>)
where
Spinlock<N>: SpinlockValid;
impl<const N: usize> Spinlock<N>
where
Spinlock<N>: SpinlockValid,
{
pub fn try_claim() -> Option<Self> {
let sio = unsafe { &*pac::SIO::ptr() };
let lock = sio.spinlock(N).read().bits();
if lock > 0 {
Some(Self(core::marker::PhantomData))
} else {
None
}
}
pub fn claim() -> Self {
loop {
if let Some(result) = Self::try_claim() {
break result;
}
}
}
pub fn claim_async() -> nb::Result<Self, Infallible> {
Self::try_claim().ok_or(nb::Error::WouldBlock)
}
pub unsafe fn release() {
let sio = &*pac::SIO::ptr();
sio.spinlock(N).write_with_zero(|b| b.bits(1));
}
}
impl<const N: usize> Drop for Spinlock<N>
where
Spinlock<N>: SpinlockValid,
{
fn drop(&mut self) {
unsafe { Self::release() }
}
}
macro_rules! spinlock {
($first:expr, $($rest:tt),+) => {
spinlock!($first);
spinlock!($($rest),+);
};
($id:expr) => {
$crate::paste::paste! {
pub type [<Spinlock $id>] = Spinlock<$id>;
impl SpinlockValid for Spinlock<$id> {}
impl Sealed for Spinlock<$id> {}
}
};
}
spinlock!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30
);
#[cfg(feature = "critical-section-impl")]
pub(crate) type Spinlock31 = Spinlock<31>;
#[cfg(not(feature = "critical-section-impl"))]
pub type Spinlock31 = Spinlock<31>;
impl SpinlockValid for Spinlock<31> {}
impl Sealed for Spinlock<31> {}
pub fn spinlock_state() -> [bool; 32] {
let sio = unsafe { &*pac::SIO::ptr() };
let register = sio.spinlock_st().read().bits();
let mut result = [false; 32];
#[allow(clippy::needless_range_loop)]
for i in 0..32 {
result[i] = (register & (1 << i)) > 0;
}
result
}
pub unsafe fn spinlock_reset() {
const SIO_BASE: u32 = 0xd0000000;
const SPINLOCK0_PTR: *mut u32 = (SIO_BASE + 0x100) as *mut u32;
const SPINLOCK_COUNT: usize = 32;
for i in 0..SPINLOCK_COUNT {
SPINLOCK0_PTR.wrapping_add(i).write_volatile(1);
}
}
pub struct LaneCtrl {
pub clamp: bool,
pub blend: bool,
pub force_msb: u8,
pub add_raw: bool,
pub cross_result: bool,
pub cross_input: bool,
pub signed: bool,
pub mask_msb: u8,
pub mask_lsb: u8,
pub shift: u8,
}
impl Default for LaneCtrl {
fn default() -> Self {
Self::new()
}
}
impl LaneCtrl {
pub const fn new() -> Self {
Self {
clamp: false,
blend: false,
force_msb: 0,
add_raw: false,
cross_result: false,
cross_input: false,
signed: false,
mask_msb: 31,
mask_lsb: 0,
shift: 0,
}
}
pub const fn encode(&self) -> u32 {
assert!(!(self.blend && self.clamp));
assert!(self.force_msb < 0b100);
assert!(self.mask_msb < 0b100000);
assert!(self.mask_lsb < 0b100000);
assert!(self.mask_msb >= self.mask_lsb);
assert!(self.shift < 0b100000);
((self.clamp as u32) << 22)
| ((self.blend as u32) << 21)
| ((self.force_msb as u32) << 19)
| ((self.add_raw as u32) << 18)
| ((self.cross_result as u32) << 17)
| ((self.cross_input as u32) << 16)
| ((self.signed as u32) << 15)
| ((self.mask_msb as u32) << 10)
| ((self.mask_lsb as u32) << 5)
| (self.shift as u32)
}
}
pub trait Lane: Sealed {
fn pop(&mut self) -> u32;
fn peek(&self) -> u32;
fn set_accum(&mut self, v: u32);
fn get_accum(&self) -> u32;
fn set_base(&mut self, v: u32);
fn get_base(&self) -> u32;
fn set_ctrl(&mut self, v: u32);
fn get_ctrl(&self) -> u32;
fn add_accum(&mut self, v: u32);
fn read_raw(&self) -> u32;
}
pub trait Interp: Sealed {
fn pop(&mut self) -> u32;
fn peek(&self) -> u32;
fn set_base(&mut self, v: u32);
fn get_base(&self) -> u32;
fn set_base_1and0(&mut self, v: u32);
}
macro_rules! interpolators {
(
$($interp:ident : ( $( [ $lane:ident,$lane_id:expr ] ),+ ) ),+
) => {
$crate::paste::paste! {
$(
$(
#[doc = "The lane " $lane_id " of " $interp]
pub struct [<$interp $lane>]{
_private: (),
}
impl Lane for [<$interp $lane>]{
fn pop(&mut self) ->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _pop_ $lane:lower>]().read().bits()
}
fn peek(&self) ->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _peek_ $lane:lower>]().read().bits()
}
fn set_accum(&mut self,v:u32){
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _accum $lane_id>]().write(|w| unsafe { w.bits(v) });
}
fn get_accum(&self)->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _accum $lane_id>]().read().bits()
}
fn set_base(&mut self, v:u32){
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _base $lane_id>]().write(|w| unsafe { w.bits(v) });
}
fn get_base(&self)->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _base $lane_id>]().read().bits()
}
fn set_ctrl(&mut self, v:u32){
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _ctrl_lane $lane_id>]().write(|w| unsafe { w.bits(v) });
}
fn get_ctrl(&self)->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _ctrl_lane $lane_id>]().read().bits()
}
fn add_accum(&mut self, v:u32){
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _accum $lane_id _add>]().write(|w| unsafe { w.bits(v) });
}
fn read_raw(&self)->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _accum $lane_id _add>]().read().bits()
}
}
impl Sealed for [<$interp $lane>] {}
)+
#[doc = "Interpolator " $interp]
pub struct $interp {
$(
[<$lane:lower>]: [<$interp $lane>],
)+
}
impl $interp{
$(
pub fn [<get_ $lane:lower>](&mut self)->&mut [<$interp $lane>]{
&mut self.[<$lane:lower>]
}
)+
}
impl Interp for $interp{
fn pop(&mut self) ->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _pop_full>]().read().bits()
}
fn peek(&self) ->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _peek_full>]().read().bits()
}
fn set_base(&mut self, v:u32){
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _base2>]().write(|w| unsafe { w.bits(v)});
}
fn get_base(&self)->u32{
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _base2>]().read().bits()
}
fn set_base_1and0(&mut self, v:u32){
let sio = unsafe { &*pac::SIO::ptr() };
sio.[<$interp:lower _base_1and0>]().write(|w| unsafe { w.bits(v)});
}
}
impl Sealed for $interp {}
)+
}
}
}
interpolators!(
Interp0 : ([Lane0,0],[Lane1,1]),
Interp1 : ([Lane0,0],[Lane1,1])
);