1use core::marker::PhantomData;
4
5use portable_atomic::{AtomicU32, Ordering};
6
7pub trait GpioExt {
9 type Parts;
11
12 fn split(self) -> Self::Parts;
14}
15
16pub struct Unknown;
18
19pub struct Input<MODE> {
21 _mode: PhantomData<MODE>,
22}
23
24pub struct Floating;
26pub struct PullUp;
28
29pub struct Output<MODE> {
31 _mode: PhantomData<MODE>,
32}
33
34pub struct Regular<INVERT> {
36 _mode: PhantomData<INVERT>,
37}
38
39pub struct Drive<INVERT> {
41 _mode: PhantomData<INVERT>,
42}
43
44pub struct IOF0<INVERT> {
46 _mode: PhantomData<INVERT>,
47}
48
49pub struct IOF1<INVERT> {
51 _mode: PhantomData<INVERT>,
52}
53
54pub struct NoInvert;
56
57pub struct Invert;
59
60trait PinIndex {
61 const INDEX: usize;
62}
63
64#[inline(always)]
65fn atomic_set_bit(r: &AtomicU32, index: usize, bit: bool) {
66 let mask = 1 << (index & 31);
67 match bit {
68 true => r.fetch_or(mask, Ordering::SeqCst),
69 false => r.fetch_and(!mask, Ordering::SeqCst),
70 };
71}
72
73trait PeripheralAccess {
74 fn peripheral() -> e310x::Gpio0;
75
76 fn input_value(index: usize) -> bool {
77 let p = Self::peripheral();
78 (p.input_val().read().bits() >> (index & 31) & 1) != 0
79 }
80
81 fn set_input_en(index: usize, bit: bool) {
82 let p = Self::peripheral();
83 let r: &AtomicU32 = unsafe { core::mem::transmute(p.input_en()) };
84 atomic_set_bit(r, index, bit);
85 }
86
87 fn set_output_en(index: usize, bit: bool) {
88 let p = Self::peripheral();
89 let r: &AtomicU32 = unsafe { core::mem::transmute(p.output_en()) };
90 atomic_set_bit(r, index, bit);
91 }
92
93 fn output_value(index: usize) -> bool {
94 let p = Self::peripheral();
95 ((p.output_val().read().bits() >> (index & 31)) & 1) != 0
96 }
97
98 fn set_output_value(index: usize, bit: bool) {
99 let p = Self::peripheral();
100 let r: &AtomicU32 = unsafe { core::mem::transmute(p.output_val()) };
101 atomic_set_bit(r, index, bit);
102 }
103
104 fn toggle_pin(index: usize) {
105 let p = Self::peripheral();
106 let r: &AtomicU32 = unsafe { core::mem::transmute(p.output_val()) };
107 let mask = 1 << (index & 31);
108 r.fetch_xor(mask, Ordering::SeqCst);
109 }
110
111 fn set_pullup(index: usize, bit: bool) {
112 let p = Self::peripheral();
113 let r: &AtomicU32 = unsafe { core::mem::transmute(p.pullup()) };
114 atomic_set_bit(r, index, bit);
115 }
116
117 fn set_drive(index: usize, bit: bool) {
118 let p = Self::peripheral();
119 let r: &AtomicU32 = unsafe { core::mem::transmute(p.drive()) };
120 atomic_set_bit(r, index, bit);
121 }
122
123 fn set_out_xor(index: usize, bit: bool) {
124 let p = Self::peripheral();
125 let r: &AtomicU32 = unsafe { core::mem::transmute(p.out_xor()) };
126 atomic_set_bit(r, index, bit);
127 }
128
129 fn set_iof_en(index: usize, bit: bool) {
130 let p = Self::peripheral();
131 let r: &AtomicU32 = unsafe { core::mem::transmute(p.iof_en()) };
132 atomic_set_bit(r, index, bit);
133 }
134
135 fn set_iof_sel(index: usize, bit: bool) {
136 let p = Self::peripheral();
137 let r: &AtomicU32 = unsafe { core::mem::transmute(p.iof_sel()) };
138 atomic_set_bit(r, index, bit);
139 }
140}
141
142macro_rules! gpio {
143 ($GPIOX:ident, $gpiox:ident, [
144 $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty),)+
145 ]) => {
146 pub mod $gpiox {
148 use core::marker::PhantomData;
149 use core::convert::Infallible;
150
151 use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin, ErrorType};
152 use e310x::$GPIOX;
153 use super::{Unknown, IOF0, IOF1, Drive, Floating, GpioExt, Input, Invert,
154 NoInvert, Output, PullUp, Regular, PinIndex, PeripheralAccess};
155
156 pub struct Parts {
158 $(
159 pub $pxi: $PXi<$MODE>,
161 )+
162 }
163
164 impl PeripheralAccess for $GPIOX {
165 #[inline(always)]
166 fn peripheral() -> e310x::Gpio0 {
167 unsafe { $GPIOX::steal() }
168 }
169 }
170
171 impl GpioExt for $GPIOX {
172 type Parts = Parts;
173
174 fn split(self) -> Parts {
175 Parts {
176 $(
177 $pxi: $PXi { _mode: PhantomData },
178 )+
179 }
180 }
181 }
182
183 $(
184 pub struct $PXi<MODE> {
186 _mode: PhantomData<MODE>,
187 }
188
189 impl<MODE> PinIndex for $PXi<MODE> {
190 const INDEX: usize = $i;
191 }
192
193 impl<MODE> $PXi<MODE> {
194 pub fn into_iof0(self) -> $PXi<IOF0<NoInvert>> {
196 $GPIOX::set_out_xor(Self::INDEX, false);
197 $GPIOX::set_iof_sel(Self::INDEX, false);
198 $GPIOX::set_iof_en(Self::INDEX, true);
199 $PXi { _mode: PhantomData }
200 }
201
202 pub fn into_iof1(self) -> $PXi<IOF1<NoInvert>> {
204 $GPIOX::set_out_xor(Self::INDEX, false);
205 $GPIOX::set_iof_sel(Self::INDEX, true);
206 $GPIOX::set_iof_en(Self::INDEX, true);
207 $PXi { _mode: PhantomData }
208 }
209
210 pub fn into_inverted_iof0(self) -> $PXi<IOF0<Invert>> {
212 $GPIOX::set_out_xor(Self::INDEX, true);
213 $GPIOX::set_iof_sel(Self::INDEX, false);
214 $GPIOX::set_iof_en(Self::INDEX, true);
215 $PXi { _mode: PhantomData }
216 }
217
218 pub fn into_inverted_iof1(self) -> $PXi<IOF1<Invert>> {
220 $GPIOX::set_out_xor(Self::INDEX, true);
221 $GPIOX::set_iof_sel(Self::INDEX, true);
222 $GPIOX::set_iof_en(Self::INDEX, true);
223 $PXi { _mode: PhantomData }
224 }
225
226 pub fn into_floating_input(self) -> $PXi<Input<Floating>> {
228 $GPIOX::set_pullup(Self::INDEX, false);
229 $GPIOX::set_input_en(Self::INDEX, true);
230 $GPIOX::set_iof_en(Self::INDEX, false);
231 $PXi { _mode: PhantomData }
232 }
233
234 pub fn into_pull_up_input(self) -> $PXi<Input<PullUp>> {
236 $GPIOX::set_pullup(Self::INDEX, true);
237 $GPIOX::set_input_en(Self::INDEX, true);
238 $GPIOX::set_iof_en(Self::INDEX, false);
239 $PXi { _mode: PhantomData }
240 }
241
242 pub fn into_output(self) -> $PXi<Output<Regular<NoInvert>>> {
244 $GPIOX::set_drive(Self::INDEX, false);
245 $GPIOX::set_out_xor(Self::INDEX, false);
246 $GPIOX::set_output_en(Self::INDEX, true);
247 $GPIOX::set_iof_en(Self::INDEX, false);
248 $PXi { _mode: PhantomData }
249 }
250
251 pub fn into_inverted_output(self) -> $PXi<Output<Regular<Invert>>> {
253 $GPIOX::set_drive(Self::INDEX, false);
254 $GPIOX::set_out_xor(Self::INDEX, true);
255 $GPIOX::set_output_en(Self::INDEX, true);
256 $GPIOX::set_iof_en(Self::INDEX, false);
257 $PXi { _mode: PhantomData }
258 }
259
260 pub fn into_output_drive(self) -> $PXi<Output<Drive<NoInvert>>> {
263 $GPIOX::set_drive(Self::INDEX, true);
264 $GPIOX::set_out_xor(Self::INDEX, false);
265 $GPIOX::set_output_en(Self::INDEX, true);
266 $GPIOX::set_iof_en(Self::INDEX, false);
267 $PXi { _mode: PhantomData }
268 }
269
270 pub fn into_inverted_output_drive(self) -> $PXi<Output<Drive<Invert>>> {
273 $GPIOX::set_drive(Self::INDEX, true);
274 $GPIOX::set_out_xor(Self::INDEX, true);
275 $GPIOX::set_output_en(Self::INDEX, true);
276 $GPIOX::set_iof_en(Self::INDEX, false);
277 $PXi { _mode: PhantomData }
278 }
279 }
280
281 impl<MODE> ErrorType for $PXi<Input<MODE>> {
282 type Error = Infallible;
283 }
284
285 impl<MODE> ErrorType for $PXi<Output<MODE>> {
286 type Error = Infallible;
287 }
288
289 impl<MODE> InputPin for $PXi<Input<MODE>> {
290 #[inline]
291 fn is_high(&mut self) -> Result<bool, Self::Error> {
292 Ok($GPIOX::input_value(Self::INDEX))
293 }
294
295 #[inline]
296 fn is_low(&mut self) -> Result<bool, Self::Error> {
297 Ok(!self.is_high()?)
298 }
299 }
300
301 impl<MODE> OutputPin for $PXi<Output<MODE>> {
302 #[inline]
303 fn set_high(&mut self) -> Result<(), Infallible> {
304 $GPIOX::set_output_value(Self::INDEX, true);
305 Ok(())
306 }
307
308 #[inline]
309 fn set_low(&mut self) -> Result<(), Infallible> {
310 $GPIOX::set_output_value(Self::INDEX, false);
311 Ok(())
312 }
313 }
314
315 impl<MODE> StatefulOutputPin for $PXi<Output<MODE>> {
316 #[inline]
317 fn is_set_high(&mut self) -> Result<bool, Infallible> {
318 Ok($GPIOX::output_value(Self::INDEX))
319 }
320
321 #[inline]
322 fn is_set_low(&mut self) -> Result<bool, Infallible> {
323 Ok(!self.is_set_high()?)
324 }
325
326 #[inline]
327 fn toggle(&mut self) -> Result<(), Infallible> {
328 $GPIOX::toggle_pin(Self::INDEX);
329 Ok(())
330 }
331 }
332 )+
333 }
334 }
335}
336
337gpio!(Gpio0, gpio0, [
341 Pin0: (pin0, 0, Unknown),
342 Pin1: (pin1, 1, Unknown),
343 Pin2: (pin2, 2, Unknown),
344 Pin3: (pin3, 3, Unknown),
345 Pin4: (pin4, 4, Unknown),
346 Pin5: (pin5, 5, Unknown),
347 Pin6: (pin6, 6, Unknown),
348 Pin7: (pin7, 7, Unknown),
349 Pin8: (pin8, 8, Unknown),
350 Pin9: (pin9, 9, Unknown),
351 Pin10: (pin10, 10, Unknown),
352 Pin11: (pin11, 11, Unknown),
353 Pin12: (pin12, 12, Unknown),
354 Pin13: (pin13, 13, Unknown),
355 Pin14: (pin14, 14, Unknown),
356 Pin15: (pin15, 15, Unknown),
357 Pin16: (pin16, 16, Unknown),
358 Pin17: (pin17, 17, Unknown),
359 Pin18: (pin18, 18, Unknown),
360 Pin19: (pin19, 19, Unknown),
361 Pin20: (pin20, 20, Unknown),
362 Pin21: (pin21, 21, Unknown),
363 Pin22: (pin22, 22, Unknown),
364 Pin23: (pin23, 23, Unknown),
365 Pin24: (pin24, 24, Unknown),
366 Pin25: (pin25, 25, Unknown),
367 Pin26: (pin26, 26, Unknown),
368 Pin27: (pin27, 27, Unknown),
369 Pin28: (pin28, 28, Unknown),
370 Pin29: (pin29, 29, Unknown),
371 Pin30: (pin30, 30, Unknown),
372 Pin31: (pin31, 31, Unknown),
373]);