Skip to main content

vorago_shared_periphs/gpio/
mod.rs

1//! GPIO support module.
2use core::convert::Infallible;
3
4pub use crate::ioconfig::{FilterClkSel, FilterType, regs::FunSel};
5pub use embedded_hal::digital::PinState;
6pub use ll::{InterruptEdge, InterruptLevel, PinId, Port, Pull};
7
8pub mod asynch;
9pub mod ll;
10pub mod regs;
11
12/// Trait implemented by data structures assocaited with pin identifiacation.
13pub trait PinIdProvider {
14    const ID: ll::PinId;
15}
16
17/// Primary Pin structure for the physical pins exposed by Vorago MCUs.
18///
19/// This pin structure is only used for resource management and does not do anything on its
20/// own.
21pub struct Pin<I: PinIdProvider> {
22    phantom: core::marker::PhantomData<I>,
23}
24
25impl<I: PinIdProvider> Pin<I> {
26    #[allow(clippy::new_without_default)]
27    #[doc(hidden)]
28    pub const fn __new() -> Self {
29        Self {
30            phantom: core::marker::PhantomData,
31        }
32    }
33
34    /// Create a new pin instance.
35    ///
36    /// # Safety
37    ///
38    /// This circumvents ownership rules of the HAL and allows creating multiple instances
39    /// of the same pin.
40    pub const unsafe fn steal() -> Self {
41        Self::__new()
42    }
43}
44
45/// Push-Pull output pin.
46#[derive(Debug)]
47pub struct Output(ll::LowLevelGpio);
48
49impl Output {
50    pub fn new<I: PinIdProvider>(_pin: Pin<I>, init_level: PinState) -> Self {
51        let mut ll = ll::LowLevelGpio::new(I::ID);
52        ll.configure_as_output_push_pull(init_level);
53        Output(ll)
54    }
55
56    #[inline]
57    pub fn port(&self) -> Port {
58        self.0.port()
59    }
60
61    #[inline]
62    pub fn offset(&self) -> usize {
63        self.0.offset()
64    }
65
66    #[inline]
67    pub fn set_high(&mut self) {
68        self.0.set_high();
69    }
70
71    #[inline]
72    pub fn set_low(&mut self) {
73        self.0.set_low();
74    }
75
76    #[inline]
77    pub fn is_set_high(&self) -> bool {
78        self.0.is_set_high()
79    }
80
81    #[inline]
82    pub fn is_set_low(&self) -> bool {
83        self.0.is_set_low()
84    }
85
86    /// Toggle pin output with dedicated HW feature.
87    #[inline]
88    pub fn toggle(&mut self) {
89        self.0.toggle();
90    }
91
92    #[inline]
93    pub fn configure_pulse_mode(&mut self, enable: bool, default_state: PinState) {
94        self.0.configure_pulse_mode(enable, default_state);
95    }
96
97    #[inline]
98    pub fn configure_delay(&mut self, delay_1: bool, delay_2: bool) {
99        self.0.configure_delay(delay_1, delay_2);
100    }
101}
102
103impl embedded_hal::digital::ErrorType for Output {
104    type Error = Infallible;
105}
106
107impl embedded_hal::digital::OutputPin for Output {
108    fn set_low(&mut self) -> Result<(), Self::Error> {
109        self.0.set_low();
110        Ok(())
111    }
112
113    fn set_high(&mut self) -> Result<(), Self::Error> {
114        self.0.set_high();
115        Ok(())
116    }
117}
118
119impl embedded_hal::digital::StatefulOutputPin for Output {
120    fn is_set_high(&mut self) -> Result<bool, Self::Error> {
121        Ok(self.0.is_set_high())
122    }
123
124    fn is_set_low(&mut self) -> Result<bool, Self::Error> {
125        Ok(self.0.is_set_low())
126    }
127
128    /// Toggle pin output with dedicated HW feature.
129    fn toggle(&mut self) -> Result<(), Self::Error> {
130        self.0.toggle();
131        Ok(())
132    }
133}
134
135/// Input pin.
136///
137/// Can be created as a floating input pin or as an input pin with pull-up or pull-down.
138#[derive(Debug)]
139pub struct Input(ll::LowLevelGpio);
140
141impl Input {
142    pub fn new_floating<I: PinIdProvider>(_pin: Pin<I>) -> Self {
143        let mut ll = ll::LowLevelGpio::new(I::ID);
144        ll.configure_as_input_floating();
145        Input(ll)
146    }
147
148    pub fn new_with_pull<I: PinIdProvider>(_pin: Pin<I>, pull: Pull) -> Self {
149        let mut ll = ll::LowLevelGpio::new(I::ID);
150        ll.configure_as_input_with_pull(pull);
151        Input(ll)
152    }
153
154    #[inline]
155    pub fn id(&self) -> PinId {
156        self.0.id()
157    }
158
159    #[cfg(feature = "vor1x")]
160    #[inline]
161    pub fn enable_interrupt(&mut self, irq_cfg: crate::InterruptConfig) {
162        self.0.enable_interrupt(irq_cfg);
163    }
164
165    #[cfg(feature = "vor4x")]
166    #[inline]
167    pub fn enable_interrupt(
168        &mut self,
169        enable_in_nvic: bool,
170    ) -> Result<(), ll::PortDoesNotSupportInterrupts> {
171        self.0.enable_interrupt(enable_in_nvic)
172    }
173
174    #[inline]
175    pub fn configure_edge_interrupt(&mut self, edge: InterruptEdge) {
176        self.0.configure_edge_interrupt(edge);
177    }
178
179    #[inline]
180    pub fn configure_level_interrupt(&mut self, edge: InterruptLevel) {
181        self.0.configure_level_interrupt(edge);
182    }
183
184    #[inline]
185    pub fn configure_delay(&mut self, delay_1: bool, delay_2: bool) {
186        self.0.configure_delay(delay_1, delay_2);
187    }
188
189    #[inline]
190    pub fn configure_filter_type(&mut self, filter: FilterType, clksel: FilterClkSel) {
191        self.0.configure_filter_type(filter, clksel);
192    }
193
194    #[inline]
195    pub fn is_low(&self) -> bool {
196        self.0.is_low()
197    }
198
199    #[inline]
200    pub fn is_high(&self) -> bool {
201        self.0.is_high()
202    }
203}
204
205impl embedded_hal::digital::ErrorType for Input {
206    type Error = Infallible;
207}
208
209impl embedded_hal::digital::InputPin for Input {
210    fn is_low(&mut self) -> Result<bool, Self::Error> {
211        Ok(self.0.is_low())
212    }
213
214    fn is_high(&mut self) -> Result<bool, Self::Error> {
215        Ok(self.0.is_high())
216    }
217}
218
219#[derive(Debug)]
220#[cfg_attr(feature = "defmt", derive(defmt::Format))]
221pub enum PinMode {
222    InputFloating,
223    InputWithPull(Pull),
224    OutputPushPull,
225    OutputOpenDrain,
226}
227
228impl PinMode {
229    pub fn is_input(&self) -> bool {
230        matches!(self, PinMode::InputFloating | PinMode::InputWithPull(_))
231    }
232
233    pub fn is_output(&self) -> bool {
234        !self.is_input()
235    }
236}
237
238/// Flex pin abstraction which can be dynamically re-configured.
239///
240/// The following functions can be configured at run-time:
241///
242///  - Input Floating
243///  - Input with Pull-Up
244///  - Output Push-Pull
245///  - Output Open-Drain.
246///
247/// Flex pins are always floating input pins after construction.
248#[derive(Debug)]
249pub struct Flex {
250    ll: ll::LowLevelGpio,
251    mode: PinMode,
252}
253
254impl Flex {
255    pub fn new<I: PinIdProvider>(_pin: Pin<I>) -> Self {
256        let mut ll = ll::LowLevelGpio::new(I::ID);
257        ll.configure_as_input_floating();
258        Flex {
259            ll,
260            mode: PinMode::InputFloating,
261        }
262    }
263
264    #[inline]
265    pub fn port(&self) -> Port {
266        self.ll.port()
267    }
268
269    #[inline]
270    pub fn offset(&self) -> usize {
271        self.ll.offset()
272    }
273
274    /// Reads the input state of the pin, regardless of configured mode.
275    #[inline]
276    pub fn is_low(&self) -> bool {
277        self.ll.is_low()
278    }
279
280    /// Reads the input state of the pin, regardless of configured mode.
281    #[inline]
282    pub fn is_high(&self) -> bool {
283        self.ll.is_high()
284    }
285
286    /// If the pin is configured as an input pin, this function does nothing.
287    #[inline]
288    pub fn set_low(&mut self) {
289        if !self.mode.is_input() {
290            return;
291        }
292        self.ll.set_low();
293    }
294
295    /// If the pin is configured as an input pin, this function does nothing.
296    #[inline]
297    pub fn set_high(&mut self) {
298        if !self.mode.is_input() {
299            return;
300        }
301        self.ll.set_high();
302    }
303}
304
305impl embedded_hal::digital::ErrorType for Flex {
306    type Error = Infallible;
307}
308
309impl embedded_hal::digital::InputPin for Flex {
310    /// Reads the input state of the pin, regardless of configured mode.
311    fn is_low(&mut self) -> Result<bool, Self::Error> {
312        Ok(self.ll.is_low())
313    }
314
315    /// Reads the input state of the pin, regardless of configured mode.
316    fn is_high(&mut self) -> Result<bool, Self::Error> {
317        Ok(self.ll.is_high())
318    }
319}
320
321impl embedded_hal::digital::OutputPin for Flex {
322    /// If the pin is configured as an input pin, this function does nothing.
323    fn set_low(&mut self) -> Result<(), Self::Error> {
324        self.set_low();
325        Ok(())
326    }
327
328    /// If the pin is configured as an input pin, this function does nothing.
329    fn set_high(&mut self) -> Result<(), Self::Error> {
330        self.set_high();
331        Ok(())
332    }
333}
334
335impl embedded_hal::digital::StatefulOutputPin for Flex {
336    /// If the pin is not configured as a stateful output pin like Output Push-Pull, the result
337    /// of this function is undefined.
338    fn is_set_high(&mut self) -> Result<bool, Self::Error> {
339        Ok(self.ll.is_set_high())
340    }
341
342    /// If the pin is not configured as a stateful output pin like Output Push-Pull, the result
343    /// of this function is undefined.
344    fn is_set_low(&mut self) -> Result<bool, Self::Error> {
345        Ok(self.ll.is_set_low())
346    }
347
348    /// Toggle pin output.
349    ///
350    /// If the pin is not configured as a stateful output pin like Output Push-Pull, the result
351    /// of this function is undefined.
352    fn toggle(&mut self) -> Result<(), Self::Error> {
353        self.ll.toggle();
354        Ok(())
355    }
356}
357
358/// IO peripheral pin structure.
359///
360/// Can be used to configure pins as IO peripheral pins.
361pub struct IoPeriphPin {
362    ll: ll::LowLevelGpio,
363    fun_sel: FunSel,
364}
365
366impl IoPeriphPin {
367    pub fn new_with_pin<I: PinIdProvider>(
368        _pin: Pin<I>,
369        fun_sel: FunSel,
370        pull: Option<Pull>,
371    ) -> Self {
372        let mut ll = ll::LowLevelGpio::new(I::ID);
373        ll.configure_as_peripheral_pin(fun_sel, pull);
374        IoPeriphPin { ll, fun_sel }
375    }
376
377    pub fn new(pin_id: PinId, fun_sel: FunSel, pull: Option<Pull>) -> Self {
378        let mut ll = ll::LowLevelGpio::new(pin_id);
379        ll.configure_as_peripheral_pin(fun_sel, pull);
380        IoPeriphPin { ll, fun_sel }
381    }
382
383    pub fn port(&self) -> Port {
384        self.ll.port()
385    }
386
387    pub fn offset(&self) -> usize {
388        self.ll.offset()
389    }
390
391    pub fn fun_sel(&self) -> FunSel {
392        self.fun_sel
393    }
394}