vorago_shared_hal/timer/
regs.rs

1use core::marker::PhantomData;
2
3use arbitrary_int::{prelude::*, u7};
4
5#[cfg(feature = "vor1x")]
6const BASE_ADDR: usize = 0x4002_0000;
7#[cfg(feature = "vor4x")]
8const BASE_ADDR: usize = 0x4001_8000;
9
10#[bitbybit::bitenum(u3)]
11#[derive(Debug, PartialEq, Eq)]
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub enum StatusSelect {
14    /// Pulse when timer reaches 0.
15    OneCyclePulse = 0b000,
16    OutputActiveBit = 0b001,
17    /// Creates a divide by two output clock of the timer.
18    ToggleOnEachCycle = 0b010,
19    /// 1 when count value >= PWM A value, 0 otherwise
20    PwmaOutput = 0b011,
21    /// 1 when count value < PWM A value and >= PWM B, 0 when counter value >= PWM A value or < PWM
22    /// B value
23    PwmbOutput = 0b100,
24    EnabledBit = 0b101,
25    /// 1 when counter value <= PWM A value and 0 otherwise.
26    PwmaActiveBit = 0b110,
27}
28
29#[bitbybit::bitfield(u32, debug, defmt_fields(feature = "defmt"))]
30pub struct Control {
31    /// The counter is requested to stop on the next normal count cycle.
32    #[bit(9, rw)]
33    request_stop: bool,
34    #[bit(8, rw)]
35    status_invert: bool,
36    #[bits(5..=7, rw)]
37    status_sel: Option<StatusSelect>,
38    #[bit(4, rw)]
39    irq_enable: bool,
40    /// Only applies if the Auto-Disable bit is 0. The ACTIVE bit goes to 0 when the count reaches
41    /// 0, but the timer remains enabled.
42    #[bit(3, rw)]
43    auto_deactivate: bool,
44    /// Counter is fully disabled when count reaches 0, which means that both the ENABLE
45    /// and ACTIVE bits go to 0.
46    #[bit(2, rw)]
47    auto_disable: bool,
48    #[bit(1, r)]
49    active: bool,
50    #[bit(0, rw)]
51    enable: bool,
52}
53
54#[derive(Debug)]
55#[cfg_attr(feature = "defmt", derive(defmt::Format))]
56pub struct EnableControl(arbitrary_int::UInt<u32, 1>);
57
58impl EnableControl {
59    pub fn new_disable() -> Self {
60        EnableControl(arbitrary_int::UInt::<u32, 1>::from_u32(0))
61    }
62
63    pub fn new_enable() -> Self {
64        EnableControl(arbitrary_int::UInt::<u32, 1>::from_u32(1))
65    }
66
67    pub fn enabled(&self) -> bool {
68        self.0.value() != 0
69    }
70}
71
72#[bitbybit::bitenum(u1, exhaustive = true)]
73#[derive(Default, Debug, PartialEq, Eq)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75pub enum CascadeInvert {
76    #[default]
77    ActiveHigh = 0,
78    ActiveLow = 1,
79}
80
81/// When two cascade sources are selected, configure the required operation.
82#[bitbybit::bitenum(u1, exhaustive = true)]
83#[derive(Default, Debug, PartialEq, Eq)]
84#[cfg_attr(feature = "defmt", derive(defmt::Format))]
85pub enum DualCascadeOp {
86    #[default]
87    LogicalAnd = 0,
88    LogicalOr = 1,
89}
90
91#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_fields(feature = "defmt"))]
92pub struct CascadeControl {
93    /// The counter is automatically disabled if the corresponding Cascade 2 level-sensitive input
94    /// souce is active when the count reaches 0. If the counter is not 0, the cascade control is
95    /// ignored.
96    #[bit(10, rw)]
97    trigger2: bool,
98    #[bit(9, rw)]
99    inv2: CascadeInvert,
100    /// Enable Cascade 2 signal active as a requirement to stop counting. This mode is similar
101    /// to the REQ_STOP control bit, but signalled by a Cascade source.
102    #[bit(8, rw)]
103    en2: bool,
104    /// Same as the trigger field for Cascade 0.
105    #[bit(7, rw)]
106    trigger1: bool,
107    /// Enable trigger mode for Cascade 0. In trigger mode, couting will start with the selected
108    /// cascade signal active, but once the counter is active, cascade control will be ignored.
109    #[bit(6, rw)]
110    trigger0: bool,
111    /// Specify required operation if both Cascade 0 and Cascade 1 are active.
112    /// 0 is a logical AND of both cascade signals, 1 is a logical OR.
113    #[bit(4, rw)]
114    dual_cascade_op: DualCascadeOp,
115    /// Inversion bit for Cascade 1
116    #[bit(3, rw)]
117    inv1: CascadeInvert,
118    /// Enable Cascade 1 signal active as a requirement for counting.
119    #[bit(2, rw)]
120    en1: bool,
121    /// Inversion bit for Cascade 0.
122    #[bit(1, rw)]
123    inv0: CascadeInvert,
124    /// Enable Cascade 0 signal active as a requirement for counting.
125    #[bit(0, rw)]
126    en0: bool,
127}
128
129#[derive(Debug, PartialEq, Eq)]
130#[cfg_attr(feature = "defmt", derive(defmt::Format))]
131pub struct InvalidCascadeSourceId;
132
133#[cfg(feature = "vor1x")]
134#[derive(Debug, PartialEq, Eq)]
135#[cfg_attr(feature = "defmt", derive(defmt::Format))]
136#[repr(u8)]
137pub enum CascadeSource {
138    PortA(u8),
139    PortB(u8),
140    Tim(u8),
141    RamSbe = 96,
142    RamMbe = 97,
143    RomSbe = 98,
144    RomMbe = 99,
145    Txev = 100,
146    ClockDivider(u8),
147}
148
149#[cfg(feature = "vor4x")]
150#[derive(Debug, PartialEq, Eq)]
151#[cfg_attr(feature = "defmt", derive(defmt::Format))]
152#[repr(u8)]
153pub enum CascadeSource {
154    PortA(u8),
155    PortB(u8),
156    PortC(u8),
157    PortD(u8),
158    PortE(u8),
159    Tim(u8),
160    TxEv,
161    AdcIrq,
162    RomSbe,
163    RomMbe,
164    Ram0Sbe,
165    Ram0Mbe,
166    Ram1Sbe,
167    Ram1Mbe,
168    WdogIrq,
169}
170
171impl CascadeSource {
172    #[cfg(feature = "vor1x")]
173    pub fn id(&self) -> Result<u7, InvalidCascadeSourceId> {
174        let port_check = |base: u8, id: u8, len: u8| -> Result<u7, InvalidCascadeSourceId> {
175            if id > len - 1 {
176                return Err(InvalidCascadeSourceId);
177            }
178            Ok(u7::new(base + id))
179        };
180        match self {
181            CascadeSource::PortA(id) => port_check(0, *id, 32),
182            CascadeSource::PortB(id) => port_check(32, *id, 32),
183            CascadeSource::Tim(id) => port_check(64, *id, 24),
184            CascadeSource::RamSbe => Ok(u7::new(96)),
185            CascadeSource::RamMbe => Ok(u7::new(97)),
186            CascadeSource::RomSbe => Ok(u7::new(98)),
187            CascadeSource::RomMbe => Ok(u7::new(99)),
188            CascadeSource::Txev => Ok(u7::new(100)),
189            CascadeSource::ClockDivider(id) => port_check(120, *id, 8),
190        }
191    }
192
193    #[cfg(feature = "vor4x")]
194    fn id(&self) -> Result<u7, InvalidCascadeSourceId> {
195        let port_check = |base: u8, id: u8| -> Result<u7, InvalidCascadeSourceId> {
196            if id > 15 {
197                return Err(InvalidCascadeSourceId);
198            }
199            Ok(u7::new(base + id))
200        };
201        match self {
202            CascadeSource::PortA(id) => port_check(0, *id),
203            CascadeSource::PortB(id) => port_check(16, *id),
204            CascadeSource::PortC(id) => port_check(32, *id),
205            CascadeSource::PortD(id) => port_check(48, *id),
206            CascadeSource::PortE(id) => port_check(64, *id),
207            CascadeSource::Tim(id) => {
208                if *id > 23 {
209                    return Err(InvalidCascadeSourceId);
210                }
211                Ok(u7::new(80 + id))
212            }
213            CascadeSource::TxEv => Ok(u7::new(104)),
214            CascadeSource::AdcIrq => Ok(u7::new(105)),
215            CascadeSource::RomSbe => Ok(u7::new(106)),
216            CascadeSource::RomMbe => Ok(u7::new(106)),
217            CascadeSource::Ram0Sbe => Ok(u7::new(108)),
218            CascadeSource::Ram0Mbe => Ok(u7::new(109)),
219            CascadeSource::Ram1Sbe => Ok(u7::new(110)),
220            CascadeSource::Ram1Mbe => Ok(u7::new(111)),
221            CascadeSource::WdogIrq => Ok(u7::new(112)),
222        }
223    }
224
225    #[cfg(feature = "vor1x")]
226    pub fn from_raw(raw: u32) -> Result<Self, InvalidCascadeSourceId> {
227        let id = u7::new((raw & 0x7F) as u8);
228        if id.value() > 127 {
229            return Err(InvalidCascadeSourceId);
230        }
231        let id = id.as_u8();
232        if id < 32 {
233            return Ok(CascadeSource::PortA(id));
234        } else if (32..56).contains(&id) {
235            return Ok(CascadeSource::PortB(id - 32));
236        } else if (64..88).contains(&id) {
237            return Ok(CascadeSource::Tim(id - 64));
238        } else if id > 120 {
239            return Ok(CascadeSource::ClockDivider(id - 120));
240        }
241        match id {
242            96 => Ok(CascadeSource::RamSbe),
243            97 => Ok(CascadeSource::RamMbe),
244            98 => Ok(CascadeSource::RomSbe),
245            99 => Ok(CascadeSource::RomMbe),
246            100 => Ok(CascadeSource::Txev),
247            _ => Err(InvalidCascadeSourceId),
248        }
249    }
250    #[cfg(feature = "vor4x")]
251    pub fn from_raw(raw: u32) -> Result<Self, InvalidCascadeSourceId> {
252        use crate::NUM_PORT_DEFAULT;
253
254        let id = u7::new((raw & 0x7F) as u8);
255        if id.value() > 127 {
256            return Err(InvalidCascadeSourceId);
257        }
258        let id = id.as_u8();
259        if id < 16 {
260            return Ok(CascadeSource::PortA(id));
261        } else if (16..16 + NUM_PORT_DEFAULT as u8).contains(&id) {
262            return Ok(CascadeSource::PortB(id - 16));
263        } else if (32..32 + NUM_PORT_DEFAULT as u8).contains(&id) {
264            return Ok(CascadeSource::PortC(id - 32));
265        } else if (48..48 + NUM_PORT_DEFAULT as u8).contains(&id) {
266            return Ok(CascadeSource::PortD(id - 48));
267        } else if (64..64 + NUM_PORT_DEFAULT as u8).contains(&id) {
268            return Ok(CascadeSource::PortE(id - 64));
269        } else if (80..104).contains(&id) {
270            return Ok(CascadeSource::Tim(id - 80));
271        }
272        match id {
273            104 => Ok(CascadeSource::TxEv),
274            105 => Ok(CascadeSource::AdcIrq),
275            106 => Ok(CascadeSource::RomSbe),
276            107 => Ok(CascadeSource::RomMbe),
277            108 => Ok(CascadeSource::Ram0Sbe),
278            109 => Ok(CascadeSource::Ram0Mbe),
279            110 => Ok(CascadeSource::Ram1Sbe),
280            111 => Ok(CascadeSource::Ram1Mbe),
281            112 => Ok(CascadeSource::WdogIrq),
282            _ => Err(InvalidCascadeSourceId),
283        }
284    }
285}
286
287#[bitbybit::bitfield(u32)]
288pub struct CascadeSourceReg {
289    #[bits(0..=6, rw)]
290    raw: u7,
291}
292
293impl CascadeSourceReg {
294    pub fn new(source: CascadeSource) -> Result<Self, InvalidCascadeSourceId> {
295        let id = source.id()?;
296        Ok(Self::new_with_raw_value(id.as_u32()))
297    }
298
299    pub fn as_cascade_source(&self) -> Result<CascadeSource, InvalidCascadeSourceId> {
300        CascadeSource::from_raw(self.raw().as_u32())
301    }
302}
303
304#[derive(derive_mmio::Mmio)]
305#[mmio(no_ctors)]
306#[repr(C)]
307pub struct Timer {
308    control: Control,
309    reset_value: u32,
310    count_value: u32,
311    enable_control: EnableControl,
312    cascade_control: CascadeControl,
313    /// CASCADE0 and CASCADE1 are used to control the counting and activation of the counter.
314    /// CASCADE2 is used to request stopping of the timer.
315    cascade: [CascadeSourceReg; 3],
316    /// PWM A compare value.
317    pwma_value: u32,
318    /// PWM B compare value.
319    pwmb_value: u32,
320    #[cfg(feature = "vor1x")]
321    _reserved: [u32; 0x3f5],
322    #[cfg(feature = "vor4x")]
323    _reserved: [u32; 0xf5],
324    /// Vorago 1x: 0x0111_07E1. Vorago 4x: 0x0211_07E9
325    perid: u32,
326}
327
328cfg_if::cfg_if! {
329    if #[cfg(feature = "vor1x")] {
330        static_assertions::const_assert_eq!(core::mem::size_of::<Timer>(), 0x1000);
331    } else if #[cfg(feature = "vor4x")] {
332        static_assertions::const_assert_eq!(core::mem::size_of::<Timer>(), 0x400);
333    }
334}
335
336#[derive(Debug, PartialEq, Eq)]
337#[cfg_attr(feature = "defmt", derive(defmt::Format))]
338pub struct InvalidTimerIndex(pub usize);
339
340#[derive(Debug, Copy, Clone, PartialEq, Eq)]
341#[cfg_attr(feature = "defmt", derive(defmt::Format))]
342pub struct TimId(u8);
343
344impl TimId {
345    pub const fn new(index: usize) -> Result<Self, InvalidTimerIndex> {
346        if index > 23 {
347            return Err(InvalidTimerIndex(index));
348        }
349        Ok(TimId(index as u8))
350    }
351
352    pub const fn new_unchecked(index: usize) -> Self {
353        if index > 23 {
354            panic!("invalid timer index");
355        }
356        TimId(index as u8)
357    }
358
359    /// Unsafely steal the TIM peripheral block for the TIM ID.
360    ///
361    /// # Safety
362    ///
363    /// Circumvents ownership and safety guarantees by the HAL.
364    pub const unsafe fn steal_regs(&self) -> MmioTimer<'static> {
365        Timer::new_mmio(*self)
366    }
367
368    pub const fn value(&self) -> u8 {
369        self.0
370    }
371
372    #[cfg(feature = "vor4x")]
373    pub const fn interrupt_id(&self) -> va416xx::Interrupt {
374        match self.value() {
375            0 => va416xx::Interrupt::TIM0,
376            1 => va416xx::Interrupt::TIM1,
377            2 => va416xx::Interrupt::TIM2,
378            3 => va416xx::Interrupt::TIM3,
379            4 => va416xx::Interrupt::TIM4,
380            5 => va416xx::Interrupt::TIM5,
381            6 => va416xx::Interrupt::TIM6,
382            7 => va416xx::Interrupt::TIM7,
383            8 => va416xx::Interrupt::TIM8,
384            9 => va416xx::Interrupt::TIM9,
385            10 => va416xx::Interrupt::TIM10,
386            11 => va416xx::Interrupt::TIM11,
387            12 => va416xx::Interrupt::TIM12,
388            13 => va416xx::Interrupt::TIM13,
389            14 => va416xx::Interrupt::TIM14,
390            15 => va416xx::Interrupt::TIM15,
391            16 => va416xx::Interrupt::TIM16,
392            17 => va416xx::Interrupt::TIM17,
393            18 => va416xx::Interrupt::TIM18,
394            19 => va416xx::Interrupt::TIM19,
395            20 => va416xx::Interrupt::TIM20,
396            21 => va416xx::Interrupt::TIM21,
397            22 => va416xx::Interrupt::TIM22,
398            23 => va416xx::Interrupt::TIM23,
399            _ => unreachable!(),
400        }
401    }
402}
403
404impl Timer {
405    const fn new_mmio_at(base: usize) -> MmioTimer<'static> {
406        MmioTimer {
407            ptr: base as *mut _,
408            phantom: PhantomData,
409        }
410    }
411
412    pub const fn new_mmio(id: TimId) -> MmioTimer<'static> {
413        if cfg!(feature = "vor1x") {
414            Timer::new_mmio_at(BASE_ADDR + 0x1000 * id.value() as usize)
415        } else {
416            Timer::new_mmio_at(BASE_ADDR + 0x400 * id.value() as usize)
417        }
418    }
419    pub fn new_mmio_with_raw_index(
420        timer_index: usize,
421    ) -> Result<MmioTimer<'static>, InvalidTimerIndex> {
422        if timer_index > 23 {
423            return Err(InvalidTimerIndex(timer_index));
424        }
425        if cfg!(feature = "vor1x") {
426            Ok(Timer::new_mmio_at(BASE_ADDR + 0x1000 * timer_index))
427        } else {
428            Ok(Timer::new_mmio_at(BASE_ADDR + 0x400 * timer_index))
429        }
430    }
431}