kea_hal/gpio.rs
1//! GPIO Pheripheral
2//!
3//! Note that per 11.1 of KEA64 Ref Man, if the pin is switch to alternate
4//! peripheral function, the IO functions are disabled. Peripherals have
5//! priority over IO.
6
7use core::marker::PhantomData;
8
9/// Default mode for GPIO pins
10///
11/// at reset, per 11.1 of KEA64 sub-family reference manual (pg. 133)
12/// PTA4:5, PTB4, and PTC4 default to SWD_DIO, SWD_CLK, NMI, & RESET function.
13pub type DefaultMode = HighImpedence;
14
15/// Trait to split the pin register into independent pins and regs
16pub trait GPIOExt {
17 /// holds the pins
18 type Parts;
19
20 /// splits the peripheral into pins
21 fn split(self) -> Self::Parts;
22}
23
24/// High Impedence type state
25///
26/// This is a type state AND and a pin state. It's not technically an input
27/// since the port cannot (successfully) be written to or read from.
28/// The Input probably not readable in this state.
29/// @TODO Verify if functional in state
30pub struct HighImpedence;
31
32/// Input Mode type state
33pub struct Input<MODE> {
34 _mode: PhantomData<MODE>,
35}
36
37/// Output Mode type state
38pub struct Output<MODE> {
39 _mode: PhantomData<MODE>,
40}
41
42/// Floating input type state
43pub struct Floating;
44
45/// PullUp input type state
46pub struct PullUp;
47
48/// PushPull output type state
49pub struct PushPull;
50
51/// High Current Drive output state
52///
53/// For KEA, this is called High Current Drive output type state and is only
54/// available on a few ports.
55pub struct HighDrive;
56
57macro_rules! gpio {
58 ($GPIOx:ident, $gpiox:ident, $puex: ident,
59 [ $($PTX:ident: $PTXn:expr,)+ ],
60 [ $($PTXi:ident: ($ptxi:ident, $i:expr, $FLTOffset:expr),)+ ],
61 [ $($HighDrivePin:ident: ($i2:expr, $HighDriveIndex:expr),)+
62 ]) => {
63
64 /// GPIO Port Module
65 pub mod $gpiox {
66 use super::{PushPull, PullUp, HighDrive, HighImpedence,
67 Floating, Input, Output, GPIOExt, DefaultMode
68 };
69 use crate::hal::digital::v2::{ToggleableOutputPin, InputPin, OutputPin, StatefulOutputPin};
70 use crate::pac::{$GPIOx, PORT};
71 use core::marker::PhantomData;
72 use core::convert::Infallible;
73
74 /// Port Collection
75 pub struct Parts {
76 $(
77 /// A pin in the port
78 pub $ptxi: $PTXi<DefaultMode>,
79 )+
80 }
81
82 impl GPIOExt for $GPIOx {
83 type Parts = Parts;
84
85 fn split(self) -> Parts {
86 Parts {
87 $(
88 $ptxi: $PTXi { _mode: PhantomData },
89 )+
90 }
91 }
92 }
93
94 $(
95 /// Partially erased pin?
96 pub struct $PTX<MODE> {
97 i: u8,
98 _mode: PhantomData<MODE>,
99 }
100
101
102 impl<MODE> OutputPin for $PTX<Output<MODE>> {
103 type Error = Infallible;
104
105 fn set_high(&mut self) -> Result<(), Self::Error> {
106 // Atomically set high via stateless register
107 unsafe {
108 (*$GPIOx::ptr()).psor.write(|w| {
109 w.bits(1 << self.i)
110 });
111 }
112 Ok(())
113 }
114
115 fn set_low(&mut self) -> Result<(), Self::Error> {
116 // Atomically set low via statelss register
117 unsafe {
118 (*$GPIOx::ptr()).pcor.write(|w| {
119 w.bits(1 << self.i)
120 });
121 }
122 Ok(())
123 }
124 }
125
126 impl<MODE> StatefulOutputPin for $PTX<Output<MODE>> {
127 fn is_set_high(&self) -> Result<bool, Self::Error> {
128 Ok(!self.is_set_low()?)
129 }
130 fn is_set_low(&self) -> Result<bool, Self::Error> {
131 // Atomically check truthiness of bit in port
132 Ok(unsafe {
133 (*$GPIOx::ptr()).pdor.read().bits() & (1 << self.i)
134 } == 0)
135 }
136 }
137
138 impl<MODE> ToggleableOutputPin for $PTX<Output<MODE>> {
139 type Error = Infallible;
140
141 fn toggle(&mut self) -> Result<(), Self::Error>{
142 Ok(unsafe {
143 (*$GPIOx::ptr()).ptor.write(|w| {
144 w.bits(1 << self.i)
145 })
146 })
147 }
148 }
149
150 impl<MODE> InputPin for $PTX<Output<MODE>> {
151 type Error = Infallible;
152
153 fn is_high(&self) -> Result<bool, Self::Error> {
154 Ok(!self.is_low()?)
155 }
156
157 fn is_low(&self) -> Result<bool, Self::Error> {
158 Ok(unsafe{
159 (*$GPIOx::ptr()).pdir.read().bits() & (1 << self.i)
160 } == 0)
161 }
162 }
163 )+
164
165 $(
166 /// a GPIO Port Pin
167 pub struct $PTXi<MODE> {
168 _mode: PhantomData<MODE>,
169 }
170
171 // What is this Into business? I don't remember!
172 // What is the interface like? Where did I see this?
173
174 impl From<$PTXi<DefaultMode>> for $PTXi<Input<PullUp>> {
175 fn from(pin: $PTXi<DefaultMode>) -> $PTXi<Input<PullUp>> {
176 pin.into_pull_up_input()
177 }
178 }
179
180 impl From<$PTXi<DefaultMode>> for $PTXi<Input<Floating>> {
181 fn from(pin: $PTXi<DefaultMode>) -> $PTXi<Input<Floating>> {
182 pin.into_floating_input()
183 }
184 }
185
186 impl From<$PTXi<DefaultMode>> for $PTXi<Output<PushPull>> {
187 fn from(pin: $PTXi<DefaultMode>) -> $PTXi<Output<PushPull>> {
188 pin.into_push_pull_output()
189 }
190 }
191
192 /// Implements the I/O type conversion methods
193 impl<MODE> $PTXi<MODE> {
194 /// Configure as floating
195 pub fn into_floating_input(self) -> $PTXi<Input<Floating>> {
196 //whatever it needs to grab the right bits
197 // from pull up reg and mode reg
198 unsafe {
199 let gpio = &(*$GPIOx::ptr());
200 let port = &(*PORT::ptr());
201
202 // Turn off Pull Up (1 = pullup)
203 port.$puex.modify(|r, w| {
204 w.bits(r.bits() & !(1 << $i))
205 });
206
207 // Set to Input (0 = input)
208 gpio.pddr.modify(|r, w| {
209 w.bits(r.bits() & !(1 << $i))
210 });
211 // 0 = input
212 gpio.pidr.modify(|r, w| {
213 w.bits(r.bits() & !(1 << $i))
214 });
215 }
216 $PTXi {_mode: PhantomData}
217 }
218
219 /// Configure as pull up input
220 pub fn into_pull_up_input(self) -> $PTXi<Input<PullUp>> {
221 unsafe {
222 let gpio = &(*$GPIOx::ptr());
223 let port = &(*PORT::ptr());
224
225 // Set to Input
226 // 0 = input, 1 = output
227 gpio.pddr.modify(|r, w| {
228 w.bits(r.bits() & !(1 << $i))
229 });
230 // 0 = input, 1 = output
231 gpio.pidr.modify(|r, w| {
232 w.bits(r.bits() & !(1 << $i))
233 });
234
235 // Turn on Pull Up
236 // 1 = on, 0 = off
237 port.$puex.modify(|r, w| {
238 w.bits(r.bits() | (1 << $i))
239 });
240
241 }
242
243 $PTXi {_mode: PhantomData}
244 }
245
246 /// Configure as PushPull output
247 pub fn into_push_pull_output(self) -> $PTXi<Output<PushPull>> {
248 unsafe {
249 let gpio = &(*$GPIOx::ptr());
250 let port = &(*PORT::ptr());
251
252 // Turn off Pull Up
253 port.$puex.modify(|r, w| {
254 w.bits(r.bits() & !(1 << $i))
255 });
256
257 // Disable input (temporarily hiZ)
258 gpio.pidr.modify(|r, w| {
259 w.bits(r.bits() | (1 << $i))
260 });
261
262 // set to output
263 gpio.pddr.modify(|r,w| {
264 w.bits(r.bits() | (1 << $i))
265 });
266
267 }
268
269 $PTXi {_mode: PhantomData}
270 }
271
272 /// Configure into High Impedence output
273 pub fn into_high_impedence(self) -> $PTXi<HighImpedence> {
274 unsafe {
275 let gpio = &(*$GPIOx::ptr());
276 let port = &(*PORT::ptr());
277
278 // Turn off Pull Up
279 port.$puex.modify(|r, w| {
280 w.bits(r.bits() & !(1 << $i))
281 });
282
283
284 // Make HiZ (disable input)
285 gpio.pidr.modify(|r, w| {
286 w.bits(r.bits() & (1 << $i))
287 });
288
289 // Set to Input
290 gpio.pddr.modify(|r, w| {
291 w.bits(r.bits() & !(1 << $i))
292 });
293
294 }
295 $PTXi {_mode: PhantomData}
296 }
297 }
298
299 impl<MODE> OutputPin for $PTXi<Output<MODE>> {
300 type Error = Infallible;
301
302 fn set_high(&mut self) -> Result<(), Self::Error> {
303 // Atomically set high via stateless register
304 unsafe {
305 (*$GPIOx::ptr()).psor.write(|w| {
306 w.bits(1 << $i)
307 });
308 }
309 Ok(())
310 }
311
312 fn set_low(&mut self) -> Result<(), Self::Error> {
313 // Atomically set low via statelss register
314 unsafe {
315 (*$GPIOx::ptr()).pcor.write(|w| {
316 w.bits(1 << $i)
317 });
318 }
319 Ok(())
320 }
321 }
322
323 impl<MODE> StatefulOutputPin for $PTXi<Output<MODE>> {
324 fn is_set_high(&self) -> Result<bool, Self::Error> {
325 Ok(!self.is_set_low()?)
326 }
327 fn is_set_low(&self) -> Result<bool, Self::Error> {
328 // Atomically check truthiness of bit in port
329 Ok(unsafe {
330 (*$GPIOx::ptr()).pdor.read().bits() & (1 << $i)
331 } == 0)
332 }
333 }
334
335 impl<MODE> ToggleableOutputPin for $PTXi<Output<MODE>> {
336 type Error = Infallible;
337
338 fn toggle(&mut self) -> Result<(), Self::Error>{
339 Ok(unsafe {
340 (*$GPIOx::ptr()).ptor.write(|w| {
341 w.bits(1 << $i)
342 })
343 })
344 }
345 }
346
347 impl<MODE> InputPin for $PTXi<Input<MODE>> {
348 type Error = Infallible;
349
350 fn is_high(&self) -> Result<bool, Self::Error> {
351 Ok(!self.is_low()?)
352 }
353
354 fn is_low(&self) -> Result<bool, Self::Error> {
355 Ok(unsafe{
356 (*$GPIOx::ptr()).pdir.read().bits() & (1 << $i)
357 } == 0)
358 }
359
360 }
361 )+
362
363 $(
364 // impl Into<$HighDrivePin<Output<HighDrive>>> for $HighDrivePin<DefaultMode> {
365 // fn into(self) -> $HighDrivePin<Output<HighDrive>> {
366 // self.into_high_drive_output()
367 // }
368 // }
369
370 impl From<$HighDrivePin<DefaultMode>> for $HighDrivePin<Output<HighDrive>> {
371 fn from(pin: $HighDrivePin<DefaultMode>) -> $HighDrivePin<Output<HighDrive>> {
372 pin.into_high_drive_output()
373 }
374 }
375
376 impl<MODE> $HighDrivePin<MODE> {
377 /// Configure into push pull output
378 ///
379 /// The KEA series calls this high current drive
380 /// This is only implemented for PTB4:5, PTD0:1, PTE0:1,
381 /// and PTH0:1.
382 pub fn into_high_drive_output(self) -> $HighDrivePin<Output<HighDrive>> {
383 unsafe {
384 let gpio = &(*$GPIOx::ptr());
385 let port = &(*PORT::ptr());
386
387 // Turn off Pull Up
388 port.$puex.modify(|r, w| {
389 w.bits(r.bits() & !(1 << $i2))
390 });
391
392
393 // Disable input (temporarily hiZ)
394 gpio.pidr.modify(|r, w| {
395 w.bits(r.bits() | (1 << $i2))
396 });
397
398 // Set to Output
399 gpio.pddr.modify(|r,w| {
400 w.bits(r.bits() | (1 << $i2))
401 });
402
403 // Enable high current drivers
404 port.hdrve.modify(|r,w| {
405 w.bits(r.bits() | (1 << $HighDriveIndex))
406 });
407 }
408
409 $HighDrivePin {_mode: PhantomData}
410 }
411 }
412 )+
413 }
414 }
415}
416
417gpio!(GPIOA, gpioa, puel, [
418 PTA: 0,
419 PTB: 1,
420 PTC: 2,
421 PTD: 3,
422], [
423 PTA0: (pta0, 0, 0),
424 PTA1: (pta1, 1, 0),
425 PTA2: (pta2, 2, 0),
426 PTA3: (pta3, 3, 0),
427 PTA4: (pta4, 4, 0),
428 PTA5: (pta5, 5, 0),
429 PTA6: (pta6, 6, 0),
430 PTA7: (pta7, 7, 0),
431 PTB0: (ptb0, 8, 2),
432 PTB1: (ptb1, 9, 2),
433 PTB2: (ptb2, 10, 2),
434 PTB3: (ptb3, 11, 2),
435 PTB4: (ptb4, 12, 2),
436 PTB5: (ptb5, 13, 2),
437 PTB6: (ptb6, 14, 2),
438 PTB7: (ptb7, 15, 2),
439 PTC0: (ptc0, 16, 4),
440 PTC1: (ptc1, 17, 4),
441 PTC2: (ptc2, 18, 4),
442 PTC3: (ptc3, 19, 4),
443 PTC4: (ptc4, 20, 4),
444 PTC5: (ptc5, 21, 4),
445 PTC6: (ptc6, 22, 4),
446 PTC7: (ptc7, 23, 4),
447 PTD0: (ptd0, 24, 6),
448 PTD1: (ptd1, 25, 6),
449 PTD2: (ptd2, 26, 6),
450 PTD3: (ptd3, 27, 6),
451 PTD4: (ptd4, 28, 6),
452 PTD5: (ptd5, 29, 6),
453 PTD6: (ptd6, 30, 6),
454 PTD7: (ptd7, 31, 6),
455], [
456 PTB4: (12, 0),
457 PTB5: (13, 1),
458 PTD0: (24, 2),
459 PTD1: (25, 3),
460]);
461
462gpio!(GPIOB, gpiob, pueh, [
463 PTE: 0,
464 PTF: 1,
465 PTG: 2,
466 PTH: 3,
467], [
468 PTE0: (pte0, 0, 8),
469 PTE1: (pte1, 1, 8),
470 PTE2: (pte2, 2, 8),
471 PTE3: (pte3, 3, 8),
472 PTE4: (pte4, 4, 8),
473 PTE5: (pte5, 5, 8),
474 PTE6: (pte6, 6, 8),
475 PTE7: (pte7, 7, 8),
476 PTF0: (ptf0, 8, 10),
477 PTF1: (ptf1, 9, 10),
478 PTF2: (ptf2, 10, 10),
479 PTF3: (ptf3, 11, 10),
480 PTF4: (ptf4, 12, 10),
481 PTF5: (ptf5, 13, 10),
482 PTF6: (ptf6, 14, 10),
483 PTF7: (ptf7, 15, 10),
484 PTG0: (ptg0, 16, 12),
485 PTG1: (ptg1, 17, 12),
486 PTG2: (ptg2, 18, 12),
487 PTG3: (ptg3, 19, 12),
488 PTH0: (pth0, 24, 14),
489 PTH1: (pth1, 25, 14),
490 PTH2: (pth2, 26, 14),
491 PTH6: (pth6, 30, 14),
492 PTH7: (pth7, 31, 14),
493], [
494 PTE0: (0, 4),
495 PTE1: (1, 5),
496 PTH0: (24, 6),
497 PTH1: (25, 7),
498]);