stm32l4_hal/gpio.rs
1//! General Purpose Input / Output
2
3// Based on (ripped)
4// https://github.com/japaric/stm32f30x-hal/blob/master/src/gpio.rs
5
6use core::marker::PhantomData;
7
8use crate::rcc::AHB2;
9
10/// Extension trait to split a GPIO peripheral in independent pins and registers
11pub trait GpioExt {
12 /// The to split the GPIO into
13 type Parts;
14
15 /// Splits the GPIO block into independent pins and registers
16 fn split(self, ahb: &mut AHB2) -> Self::Parts;
17}
18
19/// Input mode (type state)
20pub struct Input<MODE> {
21 _mode: PhantomData<MODE>,
22}
23
24/// Floating input (type state)
25pub struct Floating;
26/// Pulled down input (type state)
27pub struct PullDown;
28/// Pulled up input (type state)
29pub struct PullUp;
30
31/// Output mode (type state)
32pub struct Output<MODE> {
33 _mode: PhantomData<MODE>,
34}
35
36/// Push pull output (type state)
37pub struct PushPull;
38/// Open drain output (type state)
39pub struct OpenDrain;
40
41/// Alternate mode (type state)
42pub struct Alternate<AF, MODE>
43{
44 _af: PhantomData<AF>,
45 _mode: PhantomData<MODE>,
46}
47
48/// Alternate function 0 (type state)
49pub struct AF0;
50
51/// Alternate function 1 (type state)
52pub struct AF1;
53
54/// Alternate function 2 (type state)
55pub struct AF2;
56
57/// Alternate function 3 (type state)
58pub struct AF3;
59
60/// Alternate function 4 (type state)
61pub struct AF4;
62
63/// Alternate function 5 (type state)
64pub struct AF5;
65
66/// Alternate function 6 (type state)
67pub struct AF6;
68
69/// Alternate function 7 (type state)
70pub struct AF7;
71
72/// Alternate function 8 (type state)
73pub struct AF8;
74
75/// Alternate function 9 (type state)
76pub struct AF9;
77
78/// Alternate function 10 (type state)
79pub struct AF10;
80
81/// Alternate function 11 (type state)
82pub struct AF11;
83
84/// Alternate function 12 (type state)
85pub struct AF12;
86
87/// Alternate function 13 (type state)
88pub struct AF13;
89
90/// Alternate function 14 (type state)
91pub struct AF14;
92
93/// Alternate function 15 (type state)
94pub struct AF15;
95
96macro_rules! gpio {
97 ($GPIOX:ident, $gpiox:ident, $gpioy:ident, $iopxenr:ident, $iopxrst:ident, $PXx:ident, [
98 $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty, $AFR:ident),)+
99 ]) => {
100 /// GPIO
101 pub mod $gpiox {
102 use core::marker::PhantomData;
103
104 use crate::hal::digital::OutputPin;
105 use crate::stm32::{$gpioy, $GPIOX};
106
107 use crate::rcc::AHB2;
108 use super::{
109 Alternate, AF4, AF5, AF6, AF7, AF8, AF9, Floating, GpioExt, Input, OpenDrain, Output,
110 PullDown, PullUp, PushPull,
111 };
112
113 /// GPIO parts
114 pub struct Parts {
115 /// Opaque AFRH register
116 pub afrh: AFRH,
117 /// Opaque AFRL register
118 pub afrl: AFRL,
119 /// Opaque MODER register
120 pub moder: MODER,
121 /// Opaque OTYPER register
122 pub otyper: OTYPER,
123 /// Opaque PUPDR register
124 pub pupdr: PUPDR,
125 $(
126 /// Pin
127 pub $pxi: $PXi<$MODE>,
128 )+
129 }
130
131 impl GpioExt for $GPIOX {
132 type Parts = Parts;
133
134 fn split(self, ahb: &mut AHB2) -> Parts {
135 ahb.enr().modify(|_, w| w.$iopxenr().set_bit());
136 ahb.rstr().modify(|_, w| w.$iopxrst().set_bit());
137 ahb.rstr().modify(|_, w| w.$iopxrst().clear_bit());
138
139 Parts {
140 afrh: AFRH { _0: () },
141 afrl: AFRL { _0: () },
142 moder: MODER { _0: () },
143 otyper: OTYPER { _0: () },
144 pupdr: PUPDR { _0: () },
145 $(
146 $pxi: $PXi { _mode: PhantomData },
147 )+
148 }
149 }
150 }
151
152 /// Opaque AFRL register
153 pub struct AFRL {
154 _0: (),
155 }
156
157 impl AFRL {
158 pub(crate) fn afr(&mut self) -> &$gpioy::AFRL {
159 unsafe { &(*$GPIOX::ptr()).afrl }
160 }
161 }
162
163 /// Opaque AFRH register
164 pub struct AFRH {
165 _0: (),
166 }
167
168 impl AFRH {
169 // TODO remove `allow`
170 #[allow(dead_code)]
171 pub(crate) fn afr(&mut self) -> &$gpioy::AFRH {
172 unsafe { &(*$GPIOX::ptr()).afrh }
173 }
174 }
175
176 /// Opaque MODER register
177 pub struct MODER {
178 _0: (),
179 }
180
181 impl MODER {
182 pub(crate) fn moder(&mut self) -> &$gpioy::MODER {
183 unsafe { &(*$GPIOX::ptr()).moder }
184 }
185 }
186
187 /// Opaque OTYPER register
188 pub struct OTYPER {
189 _0: (),
190 }
191
192 impl OTYPER {
193 pub(crate) fn otyper(&mut self) -> &$gpioy::OTYPER {
194 unsafe { &(*$GPIOX::ptr()).otyper }
195 }
196 }
197
198 /// Opaque PUPDR register
199 pub struct PUPDR {
200 _0: (),
201 }
202
203 impl PUPDR {
204 pub(crate) fn pupdr(&mut self) -> &$gpioy::PUPDR {
205 unsafe { &(*$GPIOX::ptr()).pupdr }
206 }
207 }
208
209 /// Partially erased pin
210 pub struct $PXx<MODE> {
211 i: u8,
212 _mode: PhantomData<MODE>,
213 }
214
215 impl<MODE> OutputPin for $PXx<Output<MODE>> {
216 fn set_high(&mut self) {
217 // NOTE(unsafe) atomic write to a stateless register
218 unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << self.i)) }
219 }
220
221 fn set_low(&mut self) {
222 // NOTE(unsafe) atomic write to a stateless register
223 unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + self.i))) }
224 }
225 }
226
227 $(
228 /// Pin
229 pub struct $PXi<MODE> {
230 _mode: PhantomData<MODE>,
231 }
232
233 impl<MODE> $PXi<MODE> {
234 /// Configures the pin to serve as alternate function 4 (AF4)
235 pub fn into_af4(
236 self,
237 moder: &mut MODER,
238 afr: &mut $AFR,
239 ) -> $PXi<Alternate<AF4, MODE>> {
240 let offset = 2 * $i;
241
242 // alternate function mode
243 let mode = 0b10;
244 moder.moder().modify(|r, w| unsafe {
245 w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
246 });
247
248 let af = 4;
249 let offset = 4 * ($i % 8);
250 afr.afr().modify(|r, w| unsafe {
251 w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
252 });
253
254 $PXi { _mode: PhantomData }
255 }
256
257 /// Configures the pin to serve as alternate function 5 (AF5)
258 pub fn into_af5(
259 self,
260 moder: &mut MODER,
261 afr: &mut $AFR,
262 ) -> $PXi<Alternate<AF5, MODE>> {
263 let offset = 2 * $i;
264
265 // alternate function mode
266 let mode = 0b10;
267 moder.moder().modify(|r, w| unsafe {
268 w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
269 });
270
271 let af = 5;
272 let offset = 4 * ($i % 8);
273 afr.afr().modify(|r, w| unsafe {
274 w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
275 });
276
277 $PXi { _mode: PhantomData }
278 }
279
280 /// Configures the pin to serve as alternate function 6 (AF6)
281 pub fn into_af6(
282 self,
283 moder: &mut MODER,
284 afr: &mut $AFR,
285 ) -> $PXi<Alternate<AF6, MODE>> {
286 let offset = 2 * $i;
287
288 // alternate function mode
289 let mode = 0b10;
290 moder.moder().modify(|r, w| unsafe {
291 w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
292 });
293
294 let af = 6;
295 let offset = 4 * ($i % 8);
296 afr.afr().modify(|r, w| unsafe {
297 w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
298 });
299
300 $PXi { _mode: PhantomData }
301 }
302
303 /// Configures the pin to serve as alternate function 7 (AF7)
304 pub fn into_af7(
305 self,
306 moder: &mut MODER,
307 afr: &mut $AFR,
308 ) -> $PXi<Alternate<AF7, MODE>> {
309 let offset = 2 * $i;
310
311 // alternate function mode
312 let mode = 0b10;
313 moder.moder().modify(|r, w| unsafe {
314 w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
315 });
316
317 let af = 7;
318 let offset = 4 * ($i % 8);
319
320 afr.afr().modify(|r, w| unsafe {
321 w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
322 });
323
324 $PXi { _mode: PhantomData }
325 }
326
327 /// Configures the pin to serve as alternate function 8 (AF8)
328 pub fn into_af8(
329 self,
330 moder: &mut MODER,
331 afr: &mut $AFR,
332 ) -> $PXi<Alternate<AF8, MODE>> {
333 let offset = 2 * $i;
334
335 // alternate function mode
336 let mode = 0b10;
337 moder.moder().modify(|r, w| unsafe {
338 w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
339 });
340
341 let af = 8;
342 let offset = 4 * ($i % 8);
343
344 afr.afr().modify(|r, w| unsafe {
345 w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
346 });
347
348 $PXi { _mode: PhantomData }
349 }
350
351 /// Configures the pin to serve as alternate function 9 (AF9)
352 pub fn into_af9(
353 self,
354 moder: &mut MODER,
355 afr: &mut $AFR,
356 ) -> $PXi<Alternate<AF9, MODE>> {
357 let offset = 2 * $i;
358
359 // alternate function mode
360 let mode = 0b10;
361 moder.moder().modify(|r, w| unsafe {
362 w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
363 });
364
365 let af = 9;
366 let offset = 4 * ($i % 8);
367
368 afr.afr().modify(|r, w| unsafe {
369 w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
370 });
371
372 $PXi { _mode: PhantomData }
373 }
374
375 /// Configures the pin to operate as a floating input pin
376 pub fn into_floating_input(
377 self,
378 moder: &mut MODER,
379 pupdr: &mut PUPDR,
380 ) -> $PXi<Input<Floating>> {
381 let offset = 2 * $i;
382
383 // input mode
384 moder
385 .moder()
386 .modify(|r, w| unsafe { w.bits(r.bits() & !(0b11 << offset)) });
387
388 // no pull-up or pull-down
389 pupdr
390 .pupdr()
391 .modify(|r, w| unsafe { w.bits(r.bits() & !(0b11 << offset)) });
392
393 $PXi { _mode: PhantomData }
394 }
395
396 /// Configures the pin to operate as a pulled down input pin
397 pub fn into_pull_down_input(
398 self,
399 moder: &mut MODER,
400 pupdr: &mut PUPDR,
401 ) -> $PXi<Input<PullDown>> {
402 let offset = 2 * $i;
403
404 // input mode
405 moder
406 .moder()
407 .modify(|r, w| unsafe { w.bits(r.bits() & !(0b11 << offset)) });
408
409 // pull-down
410 pupdr.pupdr().modify(|r, w| unsafe {
411 w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset))
412 });
413
414 $PXi { _mode: PhantomData }
415 }
416
417 /// Configures the pin to operate as a pulled up input pin
418 pub fn into_pull_up_input(
419 self,
420 moder: &mut MODER,
421 pupdr: &mut PUPDR,
422 ) -> $PXi<Input<PullUp>> {
423 let offset = 2 * $i;
424
425 // input mode
426 moder
427 .moder()
428 .modify(|r, w| unsafe { w.bits(r.bits() & !(0b11 << offset)) });
429
430 // pull-up
431 pupdr.pupdr().modify(|r, w| unsafe {
432 w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
433 });
434
435 $PXi { _mode: PhantomData }
436 }
437
438 /// Configures the pin to operate as an open drain output pin
439 pub fn into_open_drain_output(
440 self,
441 moder: &mut MODER,
442 otyper: &mut OTYPER,
443 ) -> $PXi<Output<OpenDrain>> {
444 let offset = 2 * $i;
445
446 // general purpose output mode
447 let mode = 0b01;
448 moder.moder().modify(|r, w| unsafe {
449 w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
450 });
451
452 // open drain output
453 otyper
454 .otyper()
455 .modify(|r, w| unsafe { w.bits(r.bits() | (0b1 << $i)) });
456
457 $PXi { _mode: PhantomData }
458 }
459
460 /// Configures the pin to operate as an push pull output pin
461 pub fn into_push_pull_output(
462 self,
463 moder: &mut MODER,
464 otyper: &mut OTYPER,
465 ) -> $PXi<Output<PushPull>> {
466 let offset = 2 * $i;
467
468 // general purpose output mode
469 let mode = 0b01;
470 moder.moder().modify(|r, w| unsafe {
471 w.bits((r.bits() & !(0b11 << offset)) | (mode << offset))
472 });
473
474 // push pull output
475 otyper
476 .otyper()
477 .modify(|r, w| unsafe { w.bits(r.bits() & !(0b1 << $i)) });
478
479 $PXi { _mode: PhantomData }
480 }
481
482 /// Configures the pin to operate as an touch sample
483 pub fn into_touch_sample(
484 self,
485 moder: &mut MODER,
486 otyper: &mut OTYPER,
487 afr: &mut $AFR,
488 ) -> $PXi<Alternate<AF9, Output<OpenDrain>>> {
489 let od = self.into_open_drain_output(moder, otyper);
490 od.into_af9(moder, afr)
491 }
492
493 /// Configures the pin to operate as an touch channel
494 pub fn into_touch_channel(
495 self,
496 moder: &mut MODER,
497 otyper: &mut OTYPER,
498 afr: &mut $AFR,
499 ) -> $PXi<Alternate<AF9, Output<PushPull>>> {
500 let od = self.into_push_pull_output(moder, otyper);
501 od.into_af9(moder, afr)
502 }
503 }
504
505 impl $PXi<Output<OpenDrain>> {
506 /// Enables / disables the internal pull up
507 pub fn internal_pull_up(&mut self, pupdr: &mut PUPDR, on: bool) {
508 let offset = 2 * $i;
509
510 pupdr.pupdr().modify(|r, w| unsafe {
511 w.bits(
512 (r.bits() & !(0b11 << offset)) | if on {
513 0b01 << offset
514 } else {
515 0
516 },
517 )
518 });
519 }
520 }
521
522 impl<MODE> $PXi<Output<MODE>> {
523 /// Erases the pin number from the type
524 ///
525 /// This is useful when you want to collect the pins into an array where you
526 /// need all the elements to have the same type
527 pub fn downgrade(self) -> $PXx<Output<MODE>> {
528 $PXx {
529 i: $i,
530 _mode: self._mode,
531 }
532 }
533 }
534
535 impl<MODE> OutputPin for $PXi<Output<MODE>> {
536 fn set_high(&mut self) {
537 // NOTE(unsafe) atomic write to a stateless register
538 unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) }
539 }
540
541 fn set_low(&mut self) {
542 // NOTE(unsafe) atomic write to a stateless register
543 unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + $i))) }
544 }
545 }
546 )+
547 }
548 }
549}
550
551gpio!(GPIOA, gpioa, gpioa, gpioaen, gpioarst, PAx, [
552 PA0: (pa0, 0, Input<Floating>, AFRL),
553 PA1: (pa1, 1, Input<Floating>, AFRL),
554 PA2: (pa2, 2, Input<Floating>, AFRL),
555 PA3: (pa3, 3, Input<Floating>, AFRL),
556 PA4: (pa4, 4, Input<Floating>, AFRL),
557 PA5: (pa5, 5, Input<Floating>, AFRL),
558 PA6: (pa6, 6, Input<Floating>, AFRL),
559 PA7: (pa7, 7, Input<Floating>, AFRL),
560 PA8: (pa8, 8, Input<Floating>, AFRH),
561 PA9: (pa9, 9, Input<Floating>, AFRH),
562 PA10: (pa10, 10, Input<Floating>, AFRH),
563 PA11: (pa11, 11, Input<Floating>, AFRH),
564 PA12: (pa12, 12, Input<Floating>, AFRH),
565]);
566
567gpio!(GPIOB, gpiob, gpiob, gpioben, gpiobrst, PBx, [
568 PB0: (pb0, 0, Input<Floating>, AFRL),
569 PB1: (pb1, 1, Input<Floating>, AFRL),
570 PB2: (pb2, 2, Input<Floating>, AFRL),
571 PB3: (pb3, 3, Input<Floating>, AFRL),
572 PB4: (pb4, 4, Input<Floating>, AFRL),
573 PB5: (pb5, 5, Input<Floating>, AFRL),
574 PB6: (pb6, 6, Input<Floating>, AFRL),
575 PB7: (pb7, 7, Input<Floating>, AFRL),
576]);