This repository has been archived on 2025-10-29. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
vorago-shared-hal/src/spi/regs.rs
Robin Mueller 05ea9367d7
Some checks failed
ci / Check build (push) Has been cancelled
ci / Check formatting (push) Has been cancelled
ci / Check Documentation Build (push) Has been cancelled
ci / Clippy (push) Has been cancelled
ci / Check build (pull_request) Has been cancelled
ci / Check formatting (pull_request) Has been cancelled
ci / Check Documentation Build (pull_request) Has been cancelled
ci / Clippy (pull_request) Has been cancelled
some adaptions and fixes
2025-09-02 20:48:19 +02:00

274 lines
7.2 KiB
Rust

use core::marker::PhantomData;
pub use crate::shared::{FifoClear, TriggerLevel};
cfg_if::cfg_if! {
if #[cfg(feature = "vor1x")] {
/// SPI A base address
pub const BASE_ADDR_0: usize = 0x4005_0000;
/// SPI B base address
pub const BASE_ADDR_1: usize = 0x4005_1000;
/// SPI C base address
pub const BASE_ADDR_2: usize = 0x4005_2000;
} else if #[cfg(feature = "vor4x")] {
/// SPI 0 base address
pub const BASE_ADDR_0: usize = 0x4001_5000;
/// SPI 1 base address
pub const BASE_ADDR_1: usize = 0x4001_5400;
/// SPI 2 base address
pub const BASE_ADDR_2: usize = 0x4001_5800;
/// SPI 3 base address
pub const BASE_ADDR_3: usize = 0x4001_5C00;
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Bank {
Spi0,
Spi1,
Spi2,
#[cfg(feature = "vor4x")]
Spi3,
}
impl Bank {
/// Unsafely steal the SPI peripheral block for the given port.
///
/// # Safety
///
/// Circumvents ownership and safety guarantees by the HAL.
pub unsafe fn steal_regs(&self) -> MmioSpi<'static> {
Spi::new_mmio(*self)
}
}
#[bitbybit::bitenum(u4)]
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum WordSize {
OneBit = 0x00,
FourBits = 0x03,
EightBits = 0x07,
SixteenBits = 0x0f,
}
#[derive(Debug, PartialEq, Eq)]
#[bitbybit::bitenum(u3, exhaustive = true)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum HwChipSelectId {
Id0 = 0,
Id1 = 1,
Id2 = 2,
Id3 = 3,
Id4 = 4,
Id5 = 5,
Id6 = 6,
Id7 = 7,
}
#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_fields(feature = "defmt"))]
pub struct Control0 {
#[bits(8..=15, rw)]
scrdv: u8,
#[bit(7, rw)]
sph: bool,
#[bit(6, rw)]
spo: bool,
#[bits(0..=3, rw)]
word_size: Option<WordSize>,
}
#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
pub struct Control1 {
#[bit(11, rw)]
mtxpause: bool,
#[bit(10, rw)]
mdlycap: bool,
#[bit(9, rw)]
bm_stall: bool,
#[bit(8, rw)]
bm_start: bool,
#[bit(7, rw)]
blockmode: bool,
#[bits(4..=6, rw)]
ss: HwChipSelectId,
#[bit(3, rw)]
sod: bool,
#[bit(2, rw)]
slave_mode: bool,
#[bit(1, rw)]
enable: bool,
#[bit(0, rw)]
lbm: bool,
}
#[bitbybit::bitfield(u32)]
#[derive(Debug)]
pub struct Data {
/// Only used for BLOCKMODE. For received data, this bit indicated that the data was the first
/// word after the chip select went active. For transmitted data, setting this bit to 1
/// will end an SPI frame (deassert CS) after the specified data word.
#[bit(31, rw)]
bm_start_stop: bool,
/// Only used for BLOCKMODE. Setting this bit to 1 along with the BMSTOP bit will end an SPI
/// frame without any additional data to be transmitted. If BMSTOP is not set, this bit is
/// ignored.
#[bit(30, rw)]
bm_skipdata: bool,
#[bits(0..=15, rw)]
data: u16,
}
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
pub struct Status {
/// TX FIFO below the trigger level.
#[bit(7, r)]
tx_trigger: bool,
/// RX FIFO above or equals the trigger level.
#[bit(6, r)]
rx_trigger: bool,
#[bit(5, r)]
rx_data_first: bool,
#[bit(4, r)]
busy: bool,
#[bit(3, r)]
rx_full: bool,
#[bit(2, r)]
rx_not_empty: bool,
#[bit(1, r)]
tx_not_full: bool,
#[bit(0, r)]
tx_empty: bool,
}
/// Clock divisor value. Bit 0 is ignored and always 0. This means that only the even values
/// are used as clock divisor values, and uneven values are truncated to the next even value.
/// A value of 0 acts as a 1 for the divisor value.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ClkPrescaler(arbitrary_int::UInt<u32, 8>);
impl ClkPrescaler {
pub const fn new(value: u8) -> Self {
ClkPrescaler(arbitrary_int::UInt::<u32, 8>::new(value as u32))
}
pub const fn value(&self) -> u8 {
self.0.value() as u8
}
}
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
pub struct InterruptControl {
/// TX FIFO count <= TX FIFO trigger level.
#[bit(3, rw)]
tx: bool,
/// RX FIFO count >= RX FIFO trigger level.
#[bit(2, rw)]
rx: bool,
/// Occurs when the RX FIFO has not been read within 32 clock ticks of the SPICLKx2 clock
/// within the RX FIFO not being empty. Clearing the RX interrupt or reading data from the
/// FIFO resets the timeout counter.
#[bit(1, rw)]
rx_timeout: bool,
#[bit(0, rw)]
rx_overrun: bool,
}
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
pub struct InterruptStatus {
/// TX FIFO count <= TX FIFO trigger level.
#[bit(3, r)]
tx: bool,
/// RX FIFO count >= RX FIFO trigger level.
#[bit(2, r)]
rx: bool,
/// Occurs when the RX FIFO has not been read within 32 clock ticks of the SPICLKx2 clock
/// within the RX FIFO not being empty. Clearing the RX interrupt or reading data from the
/// FIFO resets the timeout counter.
#[bit(1, r)]
rx_timeout: bool,
#[bit(0, r)]
rx_overrun: bool,
}
#[bitbybit::bitfield(u32)]
#[derive(Debug)]
pub struct InterruptClear {
/// Clearing the RX interrupt or reading data from the FIFO resets the timeout counter.
#[bit(1, w)]
rx_timeout: bool,
#[bit(0, w)]
rx_overrun: bool,
}
#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
pub struct State {
#[bits(0..=7, r)]
rx_state: u8,
#[bits(8..=15, r)]
rx_fifo: u8,
#[bits(24..=31, r)]
tx_fifo: u8,
}
#[derive(derive_mmio::Mmio)]
#[mmio(no_ctors)]
#[repr(C)]
pub struct Spi {
ctrl0: Control0,
ctrl1: Control1,
data: Data,
#[mmio(PureRead)]
status: Status,
clkprescale: ClkPrescaler,
irq_enb: InterruptControl,
/// Raw interrupt status.
#[mmio(PureRead)]
irq_raw: InterruptStatus,
/// Enabled interrupt status.
#[mmio(PureRead)]
irq_status: InterruptStatus,
#[mmio(Write)]
irq_clear: InterruptClear,
rx_fifo_trigger: TriggerLevel,
tx_fifo_trigger: TriggerLevel,
#[mmio(Write)]
fifo_clear: FifoClear,
#[mmio(PureRead)]
state: u32,
#[cfg(feature = "vor1x")]
_reserved: [u32; 0x3F2],
#[cfg(feature = "vor4x")]
_reserved: [u32; 0xF2],
/// Vorago 1x: 0x0113_07E1. Vorago 4x: 0x0213_07E9.
#[mmio(PureRead)]
perid: u32,
}
cfg_if::cfg_if! {
if #[cfg(feature = "vor1x")] {
static_assertions::const_assert_eq!(core::mem::size_of::<Spi>(), 0x1000);
} else if #[cfg(feature = "vor4x")] {
static_assertions::const_assert_eq!(core::mem::size_of::<Spi>(), 0x400);
}
}
impl Spi {
fn new_mmio_at(base: usize) -> MmioSpi<'static> {
MmioSpi {
ptr: base as *mut _,
phantom: PhantomData,
}
}
pub fn new_mmio(bank: Bank) -> MmioSpi<'static> {
match bank {
Bank::Spi0 => Self::new_mmio_at(BASE_ADDR_0),
Bank::Spi1 => Self::new_mmio_at(BASE_ADDR_1),
Bank::Spi2 => Self::new_mmio_at(BASE_ADDR_2),
#[cfg(feature = "vor4x")]
Bank::Spi3 => Self::new_mmio_at(BASE_ADDR_2),
}
}
}