vorago_shared_hal/spi/
regs.rs

1use core::marker::PhantomData;
2
3pub use crate::shared::{FifoClear, TriggerLevel};
4
5cfg_if::cfg_if! {
6    if #[cfg(feature = "vor1x")] {
7        /// SPI A base address
8        pub const BASE_ADDR_0: usize = 0x4005_0000;
9        /// SPI B base address
10        pub const BASE_ADDR_1: usize = 0x4005_1000;
11        /// SPI C base address
12        pub const BASE_ADDR_2: usize = 0x4005_2000;
13    } else if #[cfg(feature = "vor4x")] {
14        /// SPI 0 base address
15        pub const BASE_ADDR_0: usize = 0x4001_5000;
16        /// SPI 1 base address
17        pub const BASE_ADDR_1: usize = 0x4001_5400;
18        /// SPI 2 base address
19        pub const BASE_ADDR_2: usize = 0x4001_5800;
20        /// SPI 3 base address
21        pub const BASE_ADDR_3: usize = 0x4001_5C00;
22    }
23}
24
25#[derive(Debug, PartialEq, Eq, Clone, Copy)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
27pub enum Bank {
28    Spi0,
29    Spi1,
30    Spi2,
31    #[cfg(feature = "vor4x")]
32    Spi3,
33}
34
35impl Bank {
36    /// Unsafely steal the SPI peripheral block for the given port.
37    ///
38    /// # Safety
39    ///
40    /// Circumvents ownership and safety guarantees by the HAL.
41    pub unsafe fn steal_regs(&self) -> MmioSpi<'static> {
42        Spi::new_mmio(*self)
43    }
44}
45
46#[bitbybit::bitenum(u4)]
47#[derive(Debug, PartialEq, Eq)]
48#[cfg_attr(feature = "defmt", derive(defmt::Format))]
49pub enum WordSize {
50    OneBit = 0x00,
51    FourBits = 0x03,
52    EightBits = 0x07,
53    SixteenBits = 0x0f,
54}
55
56#[derive(Debug, PartialEq, Eq)]
57#[bitbybit::bitenum(u3, exhaustive = true)]
58#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59pub enum HwChipSelectId {
60    Id0 = 0,
61    Id1 = 1,
62    Id2 = 2,
63    Id3 = 3,
64    Id4 = 4,
65    Id5 = 5,
66    Id6 = 6,
67    Id7 = 7,
68}
69
70#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_fields(feature = "defmt"))]
71pub struct Control0 {
72    #[bits(8..=15, rw)]
73    scrdv: u8,
74    #[bit(7, rw)]
75    sph: bool,
76    #[bit(6, rw)]
77    spo: bool,
78    #[bits(0..=3, rw)]
79    word_size: Option<WordSize>,
80}
81
82#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
83pub struct Control1 {
84    #[bit(11, rw)]
85    mtxpause: bool,
86    #[bit(10, rw)]
87    mdlycap: bool,
88    #[bit(9, rw)]
89    bm_stall: bool,
90    #[bit(8, rw)]
91    bm_start: bool,
92    #[bit(7, rw)]
93    blockmode: bool,
94    #[bits(4..=6, rw)]
95    ss: HwChipSelectId,
96    #[bit(3, rw)]
97    sod: bool,
98    #[bit(2, rw)]
99    slave_mode: bool,
100    #[bit(1, rw)]
101    enable: bool,
102    #[bit(0, rw)]
103    lbm: bool,
104}
105
106#[bitbybit::bitfield(u32)]
107#[derive(Debug)]
108pub struct Data {
109    /// Only used for BLOCKMODE. For received data, this bit indicated that the data was the first
110    /// word after the chip select went active. For transmitted data, setting this bit to 1
111    /// will end an SPI frame (deassert CS) after the specified data word.
112    #[bit(31, rw)]
113    bm_start_stop: bool,
114    /// Only used for BLOCKMODE. Setting this bit to 1 along with the BMSTOP bit will end an SPI
115    /// frame without any additional data to be transmitted. If BMSTOP is not set, this bit is
116    /// ignored.
117    #[bit(30, rw)]
118    bm_skipdata: bool,
119    #[bits(0..=15, rw)]
120    data: u16,
121}
122
123#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
124pub struct Status {
125    /// TX FIFO below the trigger level.
126    #[bit(7, r)]
127    tx_trigger: bool,
128    /// RX FIFO above or equals the trigger level.
129    #[bit(6, r)]
130    rx_trigger: bool,
131    #[bit(5, r)]
132    rx_data_first: bool,
133    #[bit(4, r)]
134    busy: bool,
135    #[bit(3, r)]
136    rx_full: bool,
137    #[bit(2, r)]
138    rx_not_empty: bool,
139    #[bit(1, r)]
140    tx_not_full: bool,
141    #[bit(0, r)]
142    tx_empty: bool,
143}
144
145/// Clock divisor value. Bit 0 is ignored and always 0. This means that only the even values
146/// are used as clock divisor values, and uneven values are truncated to the next even value.
147/// A value of 0 acts as a 1 for the divisor value.
148#[derive(Debug, Copy, Clone, PartialEq, Eq)]
149pub struct ClockPrescaler(arbitrary_int::UInt<u32, 8>);
150
151impl ClockPrescaler {
152    pub const fn new(value: u8) -> Self {
153        ClockPrescaler(arbitrary_int::UInt::<u32, 8>::new(value as u32))
154    }
155    pub const fn value(&self) -> u8 {
156        self.0.value() as u8
157    }
158}
159
160#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
161pub struct InterruptControl {
162    /// TX FIFO count <= TX FIFO trigger level.
163    #[bit(3, rw)]
164    tx: bool,
165    /// RX FIFO count >= RX FIFO trigger level.
166    #[bit(2, rw)]
167    rx: bool,
168    /// Occurs when the RX FIFO has not been read within 32 clock ticks of the SPICLKx2 clock
169    /// within the RX FIFO not being empty. Clearing the RX interrupt or reading data from the
170    /// FIFO resets the timeout counter.
171    #[bit(1, rw)]
172    rx_timeout: bool,
173    #[bit(0, rw)]
174    rx_overrun: bool,
175}
176
177#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
178pub struct InterruptStatus {
179    /// TX FIFO count <= TX FIFO trigger level.
180    #[bit(3, r)]
181    tx: bool,
182    /// RX FIFO count >= RX FIFO trigger level.
183    #[bit(2, r)]
184    rx: bool,
185    /// Occurs when the RX FIFO has not been read within 32 clock ticks of the SPICLKx2 clock
186    /// within the RX FIFO not being empty. Clearing the RX interrupt or reading data from the
187    /// FIFO resets the timeout counter.
188    #[bit(1, r)]
189    rx_timeout: bool,
190    #[bit(0, r)]
191    rx_overrun: bool,
192}
193
194#[bitbybit::bitfield(u32)]
195#[derive(Debug)]
196pub struct InterruptClear {
197    /// Clearing the RX interrupt or reading data from the FIFO resets the timeout counter.
198    #[bit(1, w)]
199    rx_timeout: bool,
200    #[bit(0, w)]
201    rx_overrun: bool,
202}
203
204#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
205pub struct State {
206    #[bits(0..=7, r)]
207    rx_state: u8,
208    #[bits(8..=15, r)]
209    rx_fifo: u8,
210    #[bits(24..=31, r)]
211    tx_fifo: u8,
212}
213
214#[derive(derive_mmio::Mmio)]
215#[mmio(no_ctors)]
216#[repr(C)]
217pub struct Spi {
218    ctrl0: Control0,
219    ctrl1: Control1,
220    data: Data,
221    #[mmio(PureRead)]
222    status: Status,
223    clkprescale: ClockPrescaler,
224    irq_enb: InterruptControl,
225    /// Raw interrupt status.
226    #[mmio(PureRead)]
227    irq_raw: InterruptStatus,
228    /// Enabled interrupt status.
229    #[mmio(PureRead)]
230    irq_status: InterruptStatus,
231    #[mmio(Write)]
232    irq_clear: InterruptClear,
233    rx_fifo_trigger: TriggerLevel,
234    tx_fifo_trigger: TriggerLevel,
235    #[mmio(Write)]
236    fifo_clear: FifoClear,
237    #[mmio(PureRead)]
238    state: u32,
239    #[cfg(feature = "vor1x")]
240    _reserved: [u32; 0x3F2],
241    #[cfg(feature = "vor4x")]
242    _reserved: [u32; 0xF2],
243    /// Vorago 1x: 0x0113_07E1. Vorago 4x: 0x0213_07E9.
244    #[mmio(PureRead)]
245    perid: u32,
246}
247
248cfg_if::cfg_if! {
249    if #[cfg(feature = "vor1x")] {
250        static_assertions::const_assert_eq!(core::mem::size_of::<Spi>(), 0x1000);
251    } else if #[cfg(feature = "vor4x")] {
252        static_assertions::const_assert_eq!(core::mem::size_of::<Spi>(), 0x400);
253    }
254}
255
256impl Spi {
257    fn new_mmio_at(base: usize) -> MmioSpi<'static> {
258        MmioSpi {
259            ptr: base as *mut _,
260            phantom: PhantomData,
261        }
262    }
263
264    pub fn new_mmio(bank: Bank) -> MmioSpi<'static> {
265        match bank {
266            Bank::Spi0 => Self::new_mmio_at(BASE_ADDR_0),
267            Bank::Spi1 => Self::new_mmio_at(BASE_ADDR_1),
268            Bank::Spi2 => Self::new_mmio_at(BASE_ADDR_2),
269            #[cfg(feature = "vor4x")]
270            Bank::Spi3 => Self::new_mmio_at(BASE_ADDR_2),
271        }
272    }
273}