Skip to main content

vorago_shared_hal/gpio/
mod.rs

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