vorago_shared_hal/
lib.rs

1//! Shared HAL code for Vorago VA108xx and VA416xx microcontrollers.
2#![no_std]
3#[cfg(feature = "vor4x")]
4pub mod clock;
5pub mod embassy;
6pub mod gpio;
7pub mod i2c;
8pub mod ioconfig;
9pub mod pins;
10pub mod pwm;
11pub mod spi;
12pub mod sysconfig;
13pub mod time;
14pub mod timer;
15pub mod uart;
16
17pub use sysconfig::{
18    assert_peripheral_reset, deassert_peripheral_reset, disable_peripheral_clock,
19    enable_peripheral_clock, reset_peripheral_for_cycles,
20};
21
22#[cfg(not(feature = "_family-selected"))]
23compile_error!("no Vorago CPU family was select. Choices: vor1x or vor4x");
24
25pub use ioconfig::regs::FunctionSelect;
26#[cfg(feature = "vor1x")]
27use va108xx as pac;
28#[cfg(feature = "vor4x")]
29use va416xx as pac;
30
31#[cfg(feature = "vor1x")]
32#[derive(Debug, Copy, Clone, PartialEq, Eq)]
33#[cfg_attr(feature = "defmt", derive(defmt::Format))]
34pub enum PeripheralSelect {
35    PortA = 0,
36    PortB = 1,
37    Spi0 = 4,
38    Spi1 = 5,
39    Spi2 = 6,
40    Uart0 = 8,
41    Uart1 = 9,
42    I2c0 = 16,
43    I2c1 = 17,
44    Irqsel = 21,
45    IoConfig = 22,
46    Utility = 23,
47    Gpio = 24,
48}
49
50#[cfg(feature = "vor4x")]
51#[derive(Debug, Copy, Clone, PartialEq, Eq)]
52#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53pub enum PeripheralSelect {
54    Spi0 = 0,
55    Spi1 = 1,
56    Spi2 = 2,
57    Spi3 = 3,
58    Uart0 = 4,
59    Uart1 = 5,
60    Uart2 = 6,
61    I2c0 = 7,
62    I2c1 = 8,
63    I2c2 = 9,
64    Can0 = 10,
65    Can1 = 11,
66    Rng = 12,
67    Adc = 13,
68    Dac = 14,
69    Dma = 15,
70    Ebi = 16,
71    Eth = 17,
72    Spw = 18,
73    Clkgen = 19,
74    IrqRouter = 20,
75    IoConfig = 21,
76    Utility = 22,
77    Watchdog = 23,
78    PortA = 24,
79    PortB = 25,
80    PortC = 26,
81    PortD = 27,
82    PortE = 28,
83    PortF = 29,
84    PortG = 30,
85}
86
87cfg_if::cfg_if! {
88    if #[cfg(feature = "vor1x")] {
89        /// Number of GPIO ports and IOCONFIG registers for PORT A
90        pub const NUM_PORT_A: usize = 32;
91        /// Number of GPIO ports and IOCONFIG registers for PORT B
92        pub const NUM_PORT_B: usize = 24;
93    } else if #[cfg(feature = "vor4x")] {
94        /// Number of GPIO ports and IOCONFIG registers for PORT C to Port F
95        pub const NUM_PORT_DEFAULT: usize = 16;
96        /// Number of GPIO ports and IOCONFIG registers for PORT A
97        pub const NUM_PORT_A: usize = NUM_PORT_DEFAULT;
98        /// Number of GPIO ports and IOCONFIG registers for PORT B
99        pub const NUM_PORT_B: usize = NUM_PORT_DEFAULT;
100        /// Number of GPIO ports and IOCONFIG registers for PORT G
101        pub const NUM_PORT_G: usize = 8;
102    }
103}
104
105/// GPIO port enumeration.
106#[derive(Debug, Clone, Copy, PartialEq, Eq)]
107#[cfg_attr(feature = "defmt", derive(defmt::Format))]
108pub enum Port {
109    A = 0,
110    B = 1,
111    #[cfg(feature = "vor4x")]
112    C = 2,
113    #[cfg(feature = "vor4x")]
114    D = 3,
115    #[cfg(feature = "vor4x")]
116    E = 4,
117    #[cfg(feature = "vor4x")]
118    F = 5,
119    #[cfg(feature = "vor4x")]
120    G = 6,
121}
122
123impl Port {
124    pub const fn max_offset(&self) -> usize {
125        match self {
126            Port::A => NUM_PORT_A,
127            Port::B => NUM_PORT_B,
128            #[cfg(feature = "vor4x")]
129            Port::C | Port::D | Port::E | Port::F => NUM_PORT_DEFAULT,
130            #[cfg(feature = "vor4x")]
131            Port::G => NUM_PORT_G,
132        }
133    }
134
135    /// Unsafely steal the GPIO peripheral block for the given port.
136    ///
137    /// # Safety
138    ///
139    /// Circumvents ownership and safety guarantees by the HAL.
140    pub unsafe fn steal_gpio(&self) -> gpio::regs::MmioGpio<'static> {
141        gpio::regs::Gpio::new_mmio(*self)
142    }
143}
144
145#[derive(Debug, thiserror::Error)]
146#[cfg_attr(feature = "defmt", derive(defmt::Format))]
147#[error("invalid GPIO offset {offset} for port {port:?}")]
148pub struct InvalidOffsetError {
149    offset: usize,
150    port: Port,
151}
152
153/// Generic interrupt config which can be used to specify whether the HAL driver will
154/// use the IRQSEL register to route an interrupt, and whether the IRQ will be unmasked in the
155/// Cortex-M0 NVIC. Both are generally necessary for IRQs to work, but the user might want to
156/// perform those steps themselves.
157#[cfg(feature = "vor1x")]
158#[derive(Debug, PartialEq, Eq, Clone, Copy)]
159#[cfg_attr(feature = "defmt", derive(defmt::Format))]
160pub struct InterruptConfig {
161    /// Interrupt target vector. Should always be set, might be required for disabling IRQs
162    pub id: va108xx::Interrupt,
163    /// Specfiy whether IRQ should be routed to an IRQ vector using the IRQSEL peripheral.
164    pub route: bool,
165    /// Specify whether the IRQ is unmasked in the Cortex-M NVIC. If an interrupt is used for
166    /// multiple purposes, the user can enable the interrupts themselves.
167    pub enable_in_nvic: bool,
168}
169
170#[cfg(feature = "vor1x")]
171impl InterruptConfig {
172    pub fn new(id: va108xx::Interrupt, route: bool, enable_in_nvic: bool) -> Self {
173        InterruptConfig {
174            id,
175            route,
176            enable_in_nvic,
177        }
178    }
179}
180
181/// Enable a specific interrupt using the NVIC peripheral.
182///
183/// # Safety
184///
185/// This function is `unsafe` because it can break mask-based critical sections.
186#[inline]
187pub unsafe fn enable_nvic_interrupt(irq: pac::Interrupt) {
188    unsafe {
189        cortex_m::peripheral::NVIC::unmask(irq);
190    }
191}
192
193/// Disable a specific interrupt using the NVIC peripheral.
194#[inline]
195pub fn disable_nvic_interrupt(irq: pac::Interrupt) {
196    cortex_m::peripheral::NVIC::mask(irq);
197}
198
199#[allow(dead_code)]
200pub(crate) mod sealed {
201    pub trait Sealed {}
202}
203
204pub(crate) mod shared {
205    use arbitrary_int::u5;
206
207    #[derive(Debug)]
208    pub struct TriggerLevel(arbitrary_int::UInt<u32, 5>);
209
210    impl TriggerLevel {
211        pub const fn new(value: u5) -> Self {
212            TriggerLevel(arbitrary_int::UInt::<u32, 5>::new(value.value() as u32))
213        }
214
215        pub const fn value(&self) -> u5 {
216            u5::new(self.0.value() as u8)
217        }
218    }
219
220    #[bitbybit::bitfield(u32, default = 0x0)]
221    #[derive(Debug)]
222    pub struct FifoClear {
223        #[bit(1, w)]
224        tx_fifo: bool,
225        #[bit(0, w)]
226        rx_fifo: bool,
227    }
228}