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