1#![no_implicit_prelude]
21
22extern crate core;
23
24use core::cell::UnsafeCell;
25use core::clone::Clone;
26use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
27use core::convert::{From, TryFrom};
28use core::fmt::{self, Debug, Formatter};
29use core::marker::{Copy, PhantomData};
30use core::option::Option::{self, None, Some};
31use core::result::Result::{self, Err, Ok};
32use core::unreachable;
33
34use crate::asm::nop;
35use crate::int::Acknowledge;
36use crate::pac::pads_bank0::GPIO;
37use crate::pac::{ADC, IO_BANK0, PADS_BANK0, RESETS, SIO, SYSCFG};
38use crate::pin::gpio::{Input, Output};
39use crate::pin::pwm::{PwmID, PwmPin};
40use crate::{Pico, write_reg};
41
42#[path = "pin/boards/lib.rs"]
43mod boards;
44
45#[cfg_attr(rustfmt, rustfmt_skip)]
46pub use self::boards::pins::*;
47
48pub mod adc;
49pub mod led;
50pub mod pwm;
51
52pub enum PinPull {
53 Up,
54 Down,
55 None,
56}
57#[repr(u8)]
58pub enum PinSlew {
59 Slow = 0u8,
60 Fast = 1u8,
61}
62#[repr(u8)]
63pub enum PinState {
64 Low = 0u8,
65 High = 1u8,
66}
67#[repr(u8)]
68pub enum PinStrength {
69 Drive2ma = 0u8,
70 Drive4ma = 1u8,
71 Drive8ma = 2u8,
72 Drive12ma = 3u8,
73}
74#[repr(u8)]
75pub enum PinFunction {
76 JTag = 0x00u8,
77 Spi = 0x01u8,
78 Uart = 0x02u8,
79 I2c = 0x03u8,
80 Pwm = 0x04u8,
81 Sio = 0x05u8,
82 Pio0 = 0x06u8,
83 Pio1 = 0x07u8,
84 Clock = 0x08u8,
85 Usb = 0x09u8,
86 None = 0x1Fu8,
87}
88#[repr(u8)]
89pub enum PinDirection {
90 In = 0u8,
91 Out = 1u8,
92}
93#[repr(u8)]
94pub enum PinInterrupt {
95 Low = 0x1u8,
96 High = 0x2u8,
97 EdgeLow = 0x4u8,
98 EdgeHigh = 0x8u8,
99 All = 0xFu8,
100}
101
102pub struct Pin<F: PinIO> {
103 i: PinID,
104 _p: PhantomData<UnsafeCell<F>>,
105}
106pub struct PinInvalidError;
107
108pub trait PinIO {
109 const INPUT: bool;
110}
111
112pub type PinInput = Pin<Input>;
113pub type PinOutput = Pin<Output>;
114
115#[allow(unused)]
116pub(super) enum I2cID {
118 I2C0,
119 I2C1,
120}
121#[allow(unused)]
122pub(super) enum SpiID {
124 Spi0,
125 Spi1,
126}
127#[allow(unused)]
128pub(super) enum UartID {
130 Uart0,
131 Uart1,
132}
133
134impl PinID {
135 #[inline]
136 pub(super) fn set_pio(&self, pio0: bool) {
137 let v = unsafe { &*IO_BANK0::PTR }
138 .gpio(*self as usize)
139 .gpio_ctrl()
140 .read()
141 .funcsel()
142 .bits();
143 match (v, pio0) {
144 (0x6, true) => return,
145 (0x7, false) => return,
146 _ => (),
147 }
148 self.ctrl().modify(|_, r| {
149 r.slewfast()
150 .set_bit()
151 .schmitt()
152 .set_bit()
153 .slewfast()
154 .set_bit()
155 .ie()
156 .set_bit()
157 .od()
158 .clear_bit()
159 .pue()
160 .clear_bit()
161 .pde()
162 .clear_bit()
163 .drive()
164 .bits(3)
165 });
166 self.set_function(if pio0 { PinFunction::Pio0 } else { PinFunction::Pio1 });
167 }
168 #[inline]
169 pub(super) fn set_input(&self) {
170 unsafe { &*SIO::PTR }
171 .gpio_oe_clr()
172 .write(|r| unsafe { r.bits(self.mask()) });
173 self.ctrl().modify(|_, r| r.ie().bit(true).od().bit(false));
174 }
175 #[inline]
176 pub(super) fn set_output(&self) {
177 unsafe { &*SIO::PTR }
178 .gpio_oe_set()
179 .write(|r| unsafe { r.bits(self.mask()) });
180 self.ctrl().modify(|_, r| r.ie().bit(true).od().bit(false));
181 }
182 #[inline]
183 pub(super) fn set_function(&self, f: PinFunction) {
184 unsafe { &*IO_BANK0::PTR }
185 .gpio(*self as usize)
186 .gpio_ctrl()
187 .modify(|_, r| unsafe { r.funcsel().bits(f as u8) });
188 self.ctrl().modify(|_, r| r.ie().bit(f as u8 != 0x1F))
189 }
190
191 #[inline(always)]
192 fn mask(&self) -> u32 {
193 1 << (*self as u32)
194 }
195 #[inline(always)]
196 fn is_odd(&self) -> bool {
197 (*self as u8) % 2 != 0
198 }
199 #[inline(always)]
200 fn offset(&self) -> usize {
201 (*self as usize) % 8 * 4
202 }
203 #[inline]
204 fn into_input(self) -> PinID {
205 self.set_input();
206 self.set_function(PinFunction::Sio);
207 self
208 }
209 #[inline]
210 fn into_output(self) -> PinID {
211 self.set_output();
212 self.set_function(PinFunction::Sio);
213 self
214 }
215 #[inline]
216 fn ctrl<'a>(&self) -> &'a GPIO {
217 unsafe { &*PADS_BANK0::PTR }.gpio(*self as usize)
218 }
219 fn inter_set(&self, i: PinInterrupt, en: bool) {
220 let (p, n) = (unsafe { &*IO_BANK0::PTR }, (*self as usize) / 8);
221 write_reg(
222 if on_core0() { p.proc0_inte(n).as_ptr() } else { p.proc1_inte(n).as_ptr() },
223 (i as u32) << self.offset(),
224 !en,
225 )
226 }
227 fn inter_status(&self, i: PinInterrupt) -> bool {
228 let (p, n) = (unsafe { &*IO_BANK0::PTR }, (*self as usize) / 8);
229 let r = if on_core0() { p.proc0_ints(n).read().bits() } else { p.proc1_ints(n).read().bits() } >> self.offset();
230 let m = i as u32;
231 r & m == m
232 }
233 fn inter_enabled(&self, i: PinInterrupt) -> bool {
234 let (p, n) = (unsafe { &*IO_BANK0::PTR }, (*self as usize) / 8);
235 let r = if on_core0() { p.proc0_inte(n).read().bits() } else { p.proc1_inte(n).read().bits() } >> self.offset();
236 let m = i as u32;
237 r & m == m
238 }
239 #[inline]
240 fn dorm_wake_set(&self, i: PinInterrupt, en: bool) {
241 let p = unsafe { &*IO_BANK0::PTR };
242 write_reg(
243 p.dormant_wake_inte((*self as usize) / 8).as_ptr(),
244 (i as u32) << self.offset(),
245 !en,
246 )
247 }
248 #[inline]
249 fn dorm_wake_status(&self, i: PinInterrupt) -> bool {
250 let (p, m) = (unsafe { &*IO_BANK0::PTR }, i as u32);
251 (p.dormant_wake_ints((*self as usize) / 8).read().bits() >> self.offset()) & m == m
252 }
253 #[inline]
254 fn dorm_wake_enabled(&self, i: PinInterrupt) -> bool {
255 let (p, m) = (unsafe { &*IO_BANK0::PTR }, i as u32);
256 (p.dormant_wake_inte((*self as usize) / 8).read().bits() >> self.offset()) & m == m
257 }
258}
259impl PinPull {
260 #[inline(always)]
261 fn sets(&self) -> (bool, bool) {
262 match self {
263 PinPull::Up => (true, false),
264 PinPull::Down => (false, true),
265 PinPull::None => (false, false),
266 }
267 }
268}
269impl Pin<Input> {
270 #[inline]
271 pub fn is_low(&self) -> bool {
272 unsafe { &*SIO::PTR }.gpio_in().read().bits() & self.i.mask() == 0
273 }
274 #[inline(always)]
275 pub fn is_high(&self) -> bool {
276 !self.is_low()
277 }
278 #[inline]
279 pub fn get_state(&self) -> bool {
280 self.i.ctrl().read().ie().bit_is_set()
281 }
282 #[inline]
283 pub fn is_enabled(&self) -> bool {
284 self.i.ctrl().read().ie().bit_is_set()
285 }
286 #[inline]
287 pub fn set_state(&self, en: bool) {
288 self.i.ctrl().modify(|_, r| r.ie().bit(en))
289 }
290 #[inline]
291 pub fn into_output(self) -> Pin<Output> {
292 Pin {
293 i: self.i.into_output(),
294 _p: PhantomData,
295 }
296 }
297 #[inline]
298 pub fn into_pwm(self) -> Option<PwmPin<Input>> {
299 let i = pins_pwm(&self.i);
300 if i.is_b() {
301 return None;
302 }
303 self.i.set_function(PinFunction::Pwm);
304 i.set_state(true);
305 Some(PwmPin::<Input>::new(i))
306 }
307}
308impl Pin<Output> {
309 #[inline]
310 pub fn get(_p: &Pico, i: PinID) -> Pin<Output> {
311 let v: Pin<Output> = Pin {
314 i: i.into_output(),
315 _p: PhantomData,
316 };
317 v.low();
318 v.set_pull_type(PinPull::None);
319 v
320 }
321
322 #[inline]
323 pub fn low(&self) {
324 unsafe { &*SIO::PTR }
325 .gpio_out_clr()
326 .write(|r| unsafe { r.gpio_out_clr().bits(self.i.mask()) })
327 }
328 #[inline]
329 pub fn high(&self) {
330 unsafe { &*SIO::PTR }
331 .gpio_out_set()
332 .write(|r| unsafe { r.gpio_out_set().bits(self.i.mask()) })
333 }
334 #[inline]
335 pub fn toggle(&self) {
336 unsafe { &*SIO::PTR }
337 .gpio_out_xor()
338 .write(|r| unsafe { r.gpio_out_xor().bits(self.i.mask()) })
339 }
340 #[inline]
341 pub fn set_on(&self, en: bool) {
342 if en {
343 self.high();
344 } else {
345 self.low();
346 }
347 }
348 #[inline]
349 pub fn get_state(&self) -> bool {
350 self.i.ctrl().read().od().bit_is_set()
351 }
352 #[inline]
353 pub fn is_enabled(&self) -> bool {
354 self.i.ctrl().read().od().bit_is_set()
355 }
356 #[inline]
357 pub fn is_set_low(&self) -> bool {
358 unsafe { &*SIO::PTR }.gpio_out().read().bits() & self.i.mask() == 0
359 }
360 #[inline(always)]
361 pub fn is_set_high(&self) -> bool {
362 !self.is_set_low()
363 }
364 #[inline]
365 pub fn set_state(&self, en: bool) {
366 self.i.ctrl().modify(|_, r| r.od().bit(!en))
367 }
368 #[inline(always)]
369 pub fn into_input(self) -> Pin<Input> {
370 Pin {
371 i: self.i.into_input(),
372 _p: PhantomData,
373 }
374 }
375 pub fn into_pwm(self) -> PwmPin<Output> {
376 let i = pins_pwm(&self.i);
377 self.i.set_function(PinFunction::Pwm);
378 i.set_state(true);
379 PwmPin::<Output>::new(i)
380 }
381 #[inline]
382 pub fn output_high(self) -> Pin<Output> {
383 self.high();
384 self
385 }
386 #[inline]
387 pub fn output(self, high: bool) -> Pin<Output> {
388 if high {
389 self.high()
390 } else {
391 self.low()
392 }
393 self
394 }
395}
396impl<F: PinIO> Pin<F> {
397 #[inline(always)]
398 pub fn id(&self) -> &PinID {
399 &self.i
400 }
401 #[inline]
402 pub fn get_schmitt(&self) -> bool {
403 self.i.ctrl().read().schmitt().bit_is_set()
404 }
405 #[inline]
406 pub fn get_slew(&self) -> PinSlew {
407 if self.i.ctrl().read().slewfast().bit_is_set() { PinSlew::Fast } else { PinSlew::Slow }
408 }
409 #[inline]
410 pub fn set_slew(&self, s: PinSlew) {
411 self.i.ctrl().modify(|_, r| r.slewfast().bit(s as u8 == 1));
412 }
413 #[inline]
414 pub fn pull_type(&self) -> PinPull {
415 let v = self.i.ctrl().read();
416 match (v.pue().bit_is_set(), v.pde().bit_is_set()) {
417 (true, false) => PinPull::Up,
418 (false, true) => PinPull::Down,
419 _ => PinPull::None,
420 }
421 }
422 #[inline]
423 pub fn set_schmitt(&self, en: bool) {
424 self.i.ctrl().modify(|_, r| r.schmitt().bit(en));
425 }
426 #[inline]
427 pub fn is_sync_bypass(&self) -> bool {
428 let i = self.i.mask();
429 unsafe { SYSCFG::steal() }.proc_in_sync_bypass().read().bits() & i == i
430 }
431 #[inline(always)]
432 pub fn is_pwm_avaliable(&self) -> bool {
433 !F::INPUT || (F::INPUT && self.i.is_odd())
434 }
435 #[inline]
436 pub fn pull(self, p: PinPull) -> Pin<F> {
437 self.set_pull_type(p);
438 self
439 }
440 #[inline]
441 pub fn set_pull_type(&self, p: PinPull) {
442 let (x, y) = p.sets();
443 self.i.ctrl().modify(|_, r| r.pue().bit(x).pde().bit(y))
444 }
445 #[inline(always)]
446 pub fn set_drive(&self, s: PinStrength) {
447 self.i.ctrl().modify(|_, r| r.drive().bits(s as _));
448 }
449 #[inline]
450 pub fn get_strength(&self) -> PinStrength {
451 match self.i.ctrl().read().drive().bits() {
452 0 => PinStrength::Drive2ma,
453 1 => PinStrength::Drive4ma,
454 2 => PinStrength::Drive8ma,
455 3 => PinStrength::Drive12ma,
456 _ => unreachable!(),
457 }
458 }
459 #[inline(always)]
460 pub fn set_function(&self, f: PinFunction) {
461 self.i.set_function(f)
462 }
463 #[inline]
464 pub fn interrupt_clear(&self, i: PinInterrupt) {
465 unsafe { &*IO_BANK0::PTR }
466 .intr((self.i as usize) / 8)
467 .write(|r| unsafe { r.bits((i as u32) << self.i.offset()) })
468 }
469 #[inline(always)]
470 pub fn interrupt_set(&self, i: PinInterrupt, en: bool) {
471 self.i.inter_set(i, en)
472 }
473 #[inline(always)]
474 pub fn interrupt_status(&self, i: PinInterrupt) -> bool {
475 self.i.inter_status(i)
476 }
477 #[inline(always)]
478 pub fn interrupt_enabled(&self, i: PinInterrupt) -> bool {
479 self.i.inter_enabled(i)
480 }
481 #[inline(always)]
482 pub fn dormant_wake_set(&self, i: PinInterrupt, en: bool) {
483 self.i.dorm_wake_set(i, en)
484 }
485 #[inline(always)]
486 pub fn dormant_wake_status(&self, i: PinInterrupt) -> bool {
487 self.i.dorm_wake_status(i)
488 }
489 #[inline(always)]
490 pub fn dormant_wake_enabled(&self, i: PinInterrupt) -> bool {
491 self.i.dorm_wake_enabled(i)
492 }
493
494 #[inline]
495 pub unsafe fn set_sync_bypass(&self, en: bool) {
496 write_reg(
497 unsafe { SYSCFG::steal() }.proc_in_sync_bypass().as_ptr(),
498 self.i.mask(),
499 !en,
500 );
501 }
502}
503
504impl PinIO for Input {
505 const INPUT: bool = true;
506}
507impl PinIO for Output {
508 const INPUT: bool = false;
509}
510
511impl<F: PinIO> Clone for Pin<F> {
512 #[inline(always)]
513 fn clone(&self) -> Pin<F> {
514 Pin { i: self.i, _p: PhantomData }
515 }
516}
517
518impl Eq for PinID {}
519impl Ord for PinID {
520 #[inline(always)]
521 fn cmp(&self, other: &PinID) -> Ordering {
522 (*self as u8).cmp(&(*other as u8))
523 }
524}
525impl Copy for PinID {}
526impl Clone for PinID {
527 #[inline(always)]
528 fn clone(&self) -> PinID {
529 *self
530 }
531}
532impl PartialEq for PinID {
533 #[inline(always)]
534 fn eq(&self, other: &PinID) -> bool {
535 (*self as u8).eq(&(*other as u8))
536 }
537}
538impl PartialOrd for PinID {
539 #[inline(always)]
540 fn partial_cmp(&self, other: &PinID) -> Option<Ordering> {
541 (*self as u8).partial_cmp(&(*other as u8))
542 }
543}
544impl TryFrom<u8> for PinID {
545 type Error = PinInvalidError;
546
547 #[inline]
548 fn try_from(v: u8) -> Result<PinID, PinInvalidError> {
549 match v {
550 0 => Ok(PinID::Pin0),
551 1 => Ok(PinID::Pin1),
552 2 => Ok(PinID::Pin2),
553 3 => Ok(PinID::Pin3),
554 4 => Ok(PinID::Pin4),
555 5 => Ok(PinID::Pin5),
556 6 => Ok(PinID::Pin6),
557 7 => Ok(PinID::Pin7),
558 8 => Ok(PinID::Pin8),
559 9 => Ok(PinID::Pin9),
560 10 => Ok(PinID::Pin10),
561 11 => Ok(PinID::Pin11),
562 12 => Ok(PinID::Pin12),
563 13 => Ok(PinID::Pin13),
564 14 => Ok(PinID::Pin14),
565 15 => Ok(PinID::Pin15),
566 16 => Ok(PinID::Pin16),
567 17 => Ok(PinID::Pin17),
568 18 => Ok(PinID::Pin18),
569 19 => Ok(PinID::Pin19),
570 20 => Ok(PinID::Pin20),
571 21 => Ok(PinID::Pin21),
572 22 => Ok(PinID::Pin22),
573 26 => Ok(PinID::Pin26),
574 27 => Ok(PinID::Pin27),
575 28 => Ok(PinID::Pin28),
576 _ => Err(PinInvalidError),
577 }
578 }
579}
580
581impl Copy for PinSlew {}
582impl Clone for PinSlew {
583 #[inline(always)]
584 fn clone(&self) -> PinSlew {
585 *self
586 }
587}
588
589impl Copy for PinState {}
590impl Clone for PinState {
591 #[inline(always)]
592 fn clone(&self) -> PinState {
593 *self
594 }
595}
596
597impl Copy for PinStrength {}
598impl Clone for PinStrength {
599 #[inline(always)]
600 fn clone(&self) -> PinStrength {
601 *self
602 }
603}
604
605impl Copy for PinFunction {}
606impl Clone for PinFunction {
607 #[inline(always)]
608 fn clone(&self) -> PinFunction {
609 *self
610 }
611}
612
613impl Copy for PinInterrupt {}
614impl Clone for PinInterrupt {
615 #[inline(always)]
616 fn clone(&self) -> PinInterrupt {
617 *self
618 }
619}
620
621impl Copy for PinDirection {}
622impl Clone for PinDirection {
623 #[inline(always)]
624 fn clone(&self) -> PinDirection {
625 *self
626 }
627}
628
629impl From<Pin<Output>> for Pin<Input> {
630 #[inline(always)]
631 fn from(v: Pin<Output>) -> Pin<Input> {
632 v.into_input()
633 }
634}
635
636impl<F: PinIO> Acknowledge for Pin<F> {
637 #[inline]
638 fn ack_interrupt(&mut self) -> bool {
639 let r = self.interrupt_status(PinInterrupt::All);
640 self.interrupt_clear(PinInterrupt::All);
641 r
642 }
643}
644
645#[cfg(feature = "debug")]
646impl Debug for PinInvalidError {
647 #[inline]
648 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
649 f.write_str("PinInvalidError")
650 }
651}
652#[cfg(not(feature = "debug"))]
653impl Debug for PinInvalidError {
654 #[inline(always)]
655 fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result {
656 Ok(())
657 }
658}
659
660#[inline]
661pub fn emergency_pin_on(i: PinID) {
662 let v = i.into_output().mask();
663 unsafe { &*SIO::PTR }
664 .gpio_out_set()
665 .write(|r| unsafe { r.gpio_out_set().bits(v) })
666}
667
668pub(crate) fn setup_pins() {
669 let s = unsafe { SIO::steal() };
670 let r = unsafe { RESETS::steal() };
671 let b = unsafe { PADS_BANK0::steal() };
672 r.reset().modify(|_, r| r.pads_bank0().set_bit());
673 r.reset().modify(|_, r| r.io_bank0().set_bit());
674 unsafe {
675 s.gpio_oe().write_with_zero(|r| r.bits(0));
676 s.gpio_out().write_with_zero(|r| r.bits(0));
677 }
678 r.reset().modify(|_, r| r.io_bank0().clear_bit());
679 while r.reset_done().read().io_bank0().bit_is_clear() {
680 nop();
681 }
682 r.reset().modify(|_, r| r.pads_bank0().clear_bit());
683 while r.reset_done().read().pads_bank0().bit_is_clear() {
684 nop();
685 }
686 r.reset().modify(|_, r| r.pwm().clear_bit());
687 while r.reset_done().read().pwm().bit_is_clear() {
688 nop();
689 }
690 b.gpio(0).modify(|_, r| r.od().clear_bit().ie().set_bit());
692 b.gpio(1).modify(|_, r| r.od().clear_bit().ie().set_bit());
693 b.gpio(2).modify(|_, r| r.od().clear_bit().ie().set_bit());
694 b.gpio(3).modify(|_, r| r.od().clear_bit().ie().set_bit());
695 b.gpio(4).modify(|_, r| r.od().clear_bit().ie().set_bit());
696 b.gpio(5).modify(|_, r| r.od().clear_bit().ie().set_bit());
697 b.gpio(6).modify(|_, r| r.od().clear_bit().ie().set_bit());
698 b.gpio(7).modify(|_, r| r.od().clear_bit().ie().set_bit());
699 b.gpio(8).modify(|_, r| r.od().clear_bit().ie().set_bit());
700 b.gpio(9).modify(|_, r| r.od().clear_bit().ie().set_bit());
701 b.gpio(10).modify(|_, r| r.od().clear_bit().ie().set_bit());
702 b.gpio(11).modify(|_, r| r.od().clear_bit().ie().set_bit());
703 b.gpio(12).modify(|_, r| r.od().clear_bit().ie().set_bit());
704 b.gpio(13).modify(|_, r| r.od().clear_bit().ie().set_bit());
705 b.gpio(14).modify(|_, r| r.od().clear_bit().ie().set_bit());
706 b.gpio(15).modify(|_, r| r.od().clear_bit().ie().set_bit());
707 b.gpio(16).modify(|_, r| r.od().clear_bit().ie().set_bit());
708 b.gpio(17).modify(|_, r| r.od().clear_bit().ie().set_bit());
709 b.gpio(18).modify(|_, r| r.od().clear_bit().ie().set_bit());
710 b.gpio(19).modify(|_, r| r.od().clear_bit().ie().set_bit());
711 b.gpio(20).modify(|_, r| r.od().clear_bit().ie().set_bit());
712 b.gpio(21).modify(|_, r| r.od().clear_bit().ie().set_bit());
713 b.gpio(22).modify(|_, r| r.od().clear_bit().ie().set_bit());
714 b.gpio(26).modify(|_, r| r.od().clear_bit().ie().set_bit());
715 b.gpio(27).modify(|_, r| r.od().clear_bit().ie().set_bit());
716 b.gpio(28).modify(|_, r| r.od().clear_bit().ie().set_bit());
717 PwmID::Pwm0A.set_defaults();
718 PwmID::Pwm1A.set_defaults();
719 PwmID::Pwm2A.set_defaults();
720 PwmID::Pwm3A.set_defaults();
721 PwmID::Pwm4A.set_defaults();
722 PwmID::Pwm5A.set_defaults();
723 PwmID::Pwm6A.set_defaults();
724 PwmID::Pwm7A.set_defaults();
725 unsafe { ADC::steal() }.cs().write(|r| r.en().clear_bit());
726}
727
728#[inline]
729fn on_core0() -> bool {
730 unsafe { (*SIO::ptr()).cpuid().read().bits() == 0 }
731}
732
733pub mod gpio {
734 pub struct Input;
735 pub struct Output;
736}