nrf5x/
gpio.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! GPIO and GPIOTE (task and events), nRF5x-family
6//!
7//! ### Author
8//! * Philip Levis <pal@cs.stanford.edu>
9//! * Date: August 18, 2016
10
11use core::ops::{Index, IndexMut};
12use enum_primitive::cast::FromPrimitive;
13use enum_primitive::enum_from_primitive;
14use kernel::debug;
15use kernel::hil;
16use kernel::utilities::cells::OptionalCell;
17use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
18use kernel::utilities::registers::{register_bitfields, ReadWrite};
19use kernel::utilities::StaticRef;
20
21#[cfg(feature = "nrf51")]
22const NUM_GPIOTE: usize = 4;
23#[cfg(feature = "nrf52")]
24const NUM_GPIOTE: usize = 8;
25// Dummy value for testing on Travis-CI.
26#[cfg(all(
27    not(all(target_arch = "arm", target_os = "none")),
28    not(feature = "nrf51"),
29    not(feature = "nrf52"),
30))]
31const NUM_GPIOTE: usize = 4;
32
33const GPIO_PER_PORT: usize = 32;
34
35const GPIOTE_BASE: StaticRef<GpioteRegisters> =
36    unsafe { StaticRef::new(0x40006000 as *const GpioteRegisters) };
37
38const GPIO_BASE_ADDRESS: usize = 0x50000000;
39const GPIO_SIZE: usize = 0x300;
40
41/// The nRF5x doesn't automatically provide GPIO interrupts. Instead, to receive
42/// interrupts from a GPIO line, you must allocate a GPIOTE (GPIO Task and
43/// Event) channel, and bind the channel to the desired pin. There are 4
44/// channels for the nrf51 and 8 channels for the nrf52. This means that
45/// requesting an interrupt can fail, if they are all already allocated.
46#[repr(C)]
47struct GpioteRegisters {
48    /// Task for writing to pin specified in CONFIG\[n\].PSEL.
49    /// Action on pin is configured in CONFIG\[n\].POLARITY
50    ///
51    /// - Address: 0x000 - 0x010 (nRF51)
52    /// - Address: 0x000 - 0x020 (nRF52)
53    task_out: [ReadWrite<u32, TasksOut::Register>; NUM_GPIOTE],
54    /// Reserved
55    // task_set and task_clear are not used on nRF52
56    _reserved0: [u8; 0x100 - (0x0 + NUM_GPIOTE * 4)],
57    /// Event generated from pin specified in CONFIG\[n\].PSEL
58    ///
59    /// - Address: 0x100 - 0x110 (nRF51)
60    /// - Address: 0x100 - 0x120 (nRF52)
61    event_in: [ReadWrite<u32, EventsIn::Register>; NUM_GPIOTE],
62    /// Reserved
63    _reserved1: [u8; 0x17C - (0x100 + NUM_GPIOTE * 4)],
64    /// Event generated from multiple input GPIO pins
65    /// - Address: 0x17C - 0x180
66    event_port: ReadWrite<u32, EventsPort::Register>,
67    /// Reserved
68    // inten on nRF51 is ignored because intenset and intenclr provides the same functionality
69    _reserved2: [u8; 0x184],
70    /// Enable interrupt
71    /// - Address: 0x304 - 0x308
72    intenset: ReadWrite<u32, Intenset::Register>,
73    /// Disable interrupt
74    /// - Address: 0x308 - 0x30C
75    intenclr: ReadWrite<u32, Intenclr::Register>,
76    /// Reserved
77    _reserved3: [u8; 0x204],
78    /// Configuration for OUT\[n\], SET\[n\] and CLR\[n\] tasks and IN\[n\] event
79    ///
80    /// - Adress: 0x510 - 0x520 (nRF51)
81    /// - Adress: 0x510 - 0x530 (nRF52)
82    // Note, only IN\[n\] and OUT\[n\] are used in Tock
83    config: [ReadWrite<u32, Config::Register>; NUM_GPIOTE],
84}
85
86#[repr(C)]
87struct GpioRegisters {
88    /// Reserved
89    _reserved1: [u32; 321],
90    /// Write GPIO port
91    /// - Address: 0x504 - 0x508
92    out: ReadWrite<u32, Out::Register>,
93    /// Set individual bits in GPIO port
94    /// - Address: 0x508 - 0x50C
95    outset: ReadWrite<u32, OutSet::Register>,
96    /// Clear individual bits in GPIO port
97    /// - Address: 0x50C - 0x510
98    outclr: ReadWrite<u32, OutClr::Register>,
99    /// Read GPIO Port
100    /// - Address: 0x510 - 0x514
101    in_: ReadWrite<u32, In::Register>,
102    /// Direction of GPIO pins
103    /// - Address: 0x514 - 0x518
104    dir: ReadWrite<u32, Dir::Register>,
105    /// DIR set register
106    /// - Address: 0x518 - 0x51C
107    dirset: ReadWrite<u32, DirSet::Register>,
108    /// DIR clear register
109    /// - Address: 0x51C - 0x520
110    dirclr: ReadWrite<u32, DirClr::Register>,
111    #[cfg(feature = "nrf51")]
112    /// Reserved
113    _reserved2: [u32; 120],
114    /// Latch register indicating what GPIO pins that have met the criteria set in the
115    /// PIN_CNF\[n\].SENSE
116    /// - Address: 0x520 - 0x524
117    #[cfg(feature = "nrf52")]
118    latch: ReadWrite<u32, Latch::Register>,
119    /// Select between default DETECT signal behaviour and LDETECT mode
120    /// - Address: 0x524 - 0x528
121    #[cfg(feature = "nrf52")]
122    detect_mode: ReadWrite<u32, DetectMode::Register>,
123    /// Reserved
124    #[cfg(feature = "nrf52")]
125    _reserved2: [u32; 118],
126    /// Configuration of GPIO pins
127    pin_cnf: [ReadWrite<u32, PinConfig::Register>; 32],
128}
129
130// Gpio
131register_bitfields! [u32,
132    /// Write GPIO port
133    Out [
134        /// Pin\[n\], each bit correspond to a pin 0 to 31
135        /// 0 - Low, Pin driver is low
136        /// 1 - High, Pin driver is high
137        PIN OFFSET(0) NUMBITS(32)
138    ],
139    /// Set individual bits in GPIO port
140    OutSet [
141        /// Pin\[n\], each bit correspond to a pin 0 to 31
142        /// 0 - Low
143        /// 1 - High
144        /// Writing a '1' sets the pin high
145        /// Writing a '0' has no effect
146        PIN OFFSET(0) NUMBITS(32)
147    ],
148    /// Clear individual bits in GPIO port
149    OutClr [
150        /// Pin\[n\], each bit correspond to a pin 0 to 31
151        /// 0 - Low
152        /// 1 - High
153        /// Writing a '1' sets the pin low
154        /// Writing a '0' has no effect
155        PIN OFFSET(0) NUMBITS(32)
156    ],
157    /// Read GPIO port
158    In [
159        /// Pin\[n\], each bit correspond to a pin 0 to 31
160        /// 0 - Low
161        /// 1 - High
162        PIN OFFSET(0) NUMBITS(32)
163    ],
164    /// Direction of GPIO pins
165    Dir [
166        /// 0 - Pin set as input
167        /// 1 - Pin set as output
168        PIN OFFSET(0) NUMBITS(32)
169    ],
170    /// Configure direction of individual GPIO pins as output
171    DirSet [
172        /// Pin\[n\], each bit correspond to a pin 0 to 31
173        /// 0 - Pin set as input
174        /// 1 - Pin set as output
175        /// Write: writing a '1' sets pin to output
176        /// Writing a '0' has no effect
177        PIN OFFSET(0) NUMBITS(32)
178    ],
179    /// Configure direction of individual GPIO pins as input
180    DirClr [
181        /// Pin\[n\], each bit correspond to a pin 0 to 31
182        /// 0 - Pin set as input
183        /// 1 - Pin set as output
184        /// Write: writing a '1' sets pin to input
185        /// Writing a '0' has no effect
186        PIN OFFSET(0) NUMBITS(32)
187    ],
188    /// Latch register indicating what GPIO pins that have met the criteria set in the
189    /// PIN_CNF\[n\].SENSE registers
190    Latch [
191        /// Pin\[n\], each bit correspond to a pin 0 to 31
192        /// 0 - NotLatched
193        /// 1 - Latched
194        PIN OFFSET(0) NUMBITS(32)
195    ],
196    /// Select between default DETECT signal behaviour and LDETECT mode
197    DetectMode [
198        /// 0 - NotLatched
199        /// 1 - Latched
200        DETECTMODE OFFSET(0) NUMBITS(1) [
201            DEFAULT = 0,
202            LDDETECT = 1
203        ]
204    ],
205    /// Configuration of GPIO pins
206    /// Pin\[n\], each bit correspond to a pin 0 to 31
207    PinConfig [
208        /// Pin direction. Same physical register as DIR register
209        DIR OFFSET(0) NUMBITS(1) [
210            Input = 0,
211            Output = 1
212        ],
213        /// Connect or disconnect input buffer
214        INPUT OFFSET(1) NUMBITS(1) [
215            Connect = 0,
216            Disconnect = 1
217        ],
218        /// Pull configuration
219        PULL OFFSET(2) NUMBITS(2) [
220            Disabled = 0,
221            Pulldown = 1,
222            Pullup = 3
223        ],
224        /// Drive configuration
225        DRIVE OFFSET(8) NUMBITS(3) [
226            /// Standard '0', standard '1'
227            S0S1 = 0,
228            /// High drive '0', standard '1'
229            H0S1 = 1,
230            /// Standard '0', high drive '1
231            S0H1 = 2,
232            /// High drive '0', high 'drive '1'
233            H0H1 = 3,
234            /// Disconnect '0' standard '1' (normally used for wired-or connections)
235            D0S1 = 4,
236            /// Disconnect '0', high drive '1' (normally used for wired-or connections)
237            D0H1 = 5,
238            /// Standard '0'. disconnect '1' (normally used for wired-and connections)
239            S0D1 = 6,
240            /// High drive '0', disconnect '1' (normally used for wired-and connections)
241            H0D1 = 7
242        ],
243        /// Pin sensing mechanism
244        SENSE OFFSET(16) NUMBITS(2) [
245            /// Disabled
246            Disabled = 0,
247            /// Sense for high level
248            High = 2,
249            /// Sense for low level
250            Low = 3
251        ]
252    ]
253];
254
255// GpioTe
256register_bitfields! [u32,
257    /// Task for writing to pin specified in CONFIG\[n\].PSEL.
258    /// Action on pin is configured in CONFIG\[n\].POLARITY
259    TasksOut [
260        TASK OFFSET(0) NUMBITS(1) [
261            Disable = 0,
262            Enable = 1
263        ]
264    ],
265
266    /// Event generated from pin specified in CONFIG\[n\].PSEL
267    EventsIn [
268        EVENT OFFSET(0) NUMBITS(1) [
269            NotReady = 0,
270            Ready = 1
271        ]
272    ],
273
274    /// Event generated from multiple input pins
275    EventsPort [
276        PINS OFFSET(0) NUMBITS(1) [
277            NotReady = 0,
278            Ready = 1
279        ]
280    ],
281
282    /// Enable interrupt
283    Intenset [
284        // nRF51 has only 4 inputs
285        IN OFFSET(0) NUMBITS(8),
286        PORT OFFSET(31) NUMBITS(1)
287    ],
288
289    /// Disable interrupt
290    Intenclr [
291        // nRF51 has only 4 inputs
292        IN OFFSET(0) NUMBITS(8),
293        PORT OFFSET(31) NUMBITS(1)
294    ],
295
296    /// Configuration for OUT\[n\], SET\[n\] and CLR\[n\] tasks and IN\[n\] event
297    Config [
298        /// Mode
299        MODE OFFSET(0) NUMBITS(2) [
300            /// Disabled. Pin specified by PSEL will not be acquired by the
301            /// GPIOTE module
302            Disabled = 0,
303            /// The pin specified by PSEL will be configured as an input and the
304            /// IN\[n\] event will be generated if operation specified in POLARITY
305            /// occurs on the pin.
306            Event = 1,
307            ///The GPIO specified by PSEL will be configured as an output and
308            /// triggering the SET\[n\], CLR\[n\] or OUT\[n\] task will perform the
309            /// operation specified by POLARITY on the pin. When enabled as a
310            /// task the GPIOTE module will acquire the pin and the pin can no
311            /// longer be written as a regular output pin from the GPIO module.
312            Task = 3
313        ],
314        /// GPIO number associated with SET\[n\], CLR\[n\] and OUT\[n\] tasks
315        /// and IN\[n\] event. Only 5 bits are used but they are followed by 1 bit
316        /// indicating the port. This allows us to abstract the port away as each port
317        /// is defined for 32 pins.
318        PSEL OFFSET(8) NUMBITS(6) [],
319        /// When In task mode: Operation to be performed on output
320        /// when OUT\[n\] task is triggered. When In event mode: Operation
321        /// on input that shall trigger IN\[n\] event
322        POLARITY OFFSET(16) NUMBITS(2) [
323            /// Task mode: No effect on pin from OUT\[n\] task. Event mode: no
324            /// IN\[n\] event generated on pin activity
325            Disabled = 0,
326            /// Task mode: Set pin from OUT\[n\] task. Event mode: Generate
327            /// IN\[n\] event when rising edge on pin
328            LoToHi = 1,
329            /// Task mode: Clear pin from OUT\[n\] task. Event mode: Generate
330            /// IN\[n\] event when falling edge on pin
331            HiToLo = 2,
332            /// Task mode: Toggle pin from OUT\[n\]. Event mode: Generate
333            /// IN\[n\] when any change on pin
334            Toggle = 3
335        ],
336        /// When in task mode: Initial value of the output when the GPIOTE
337        /// channel is configured. When in event mode: No effect
338        OUTINIT OFFSET(20) NUMBITS(1) [
339            /// Task mode: Initial value of pin before task triggering is low
340            Low = 0,
341            /// Task mode: Initial value of pin before task triggering is high
342            High = 1
343        ]
344    ]
345];
346
347enum_from_primitive! {
348    #[derive(Copy, Clone, Debug, PartialEq)]
349    #[rustfmt::skip]
350    pub enum Pin {
351        P0_00, P0_01, P0_02, P0_03, P0_04, P0_05, P0_06, P0_07,
352        P0_08, P0_09, P0_10, P0_11, P0_12, P0_13, P0_14, P0_15,
353        P0_16, P0_17, P0_18, P0_19, P0_20, P0_21, P0_22, P0_23,
354        P0_24, P0_25, P0_26, P0_27, P0_28, P0_29, P0_30, P0_31,
355        // Pins only on nrf52840.
356        P1_00, P1_01, P1_02, P1_03, P1_04, P1_05, P1_06, P1_07,
357        P1_08, P1_09, P1_10, P1_11, P1_12, P1_13, P1_14, P1_15,
358    }
359}
360
361pub struct GPIOPin<'a> {
362    pin: u8,
363    port: u8,
364    client: OptionalCell<&'a dyn hil::gpio::Client>,
365    gpiote_registers: StaticRef<GpioteRegisters>,
366    gpio_registers: StaticRef<GpioRegisters>,
367    allocated_channel: OptionalCell<usize>,
368}
369
370impl<'a> GPIOPin<'a> {
371    pub const fn new(pin: Pin) -> GPIOPin<'a> {
372        GPIOPin {
373            pin: ((pin as usize) % GPIO_PER_PORT) as u8,
374            port: ((pin as usize) / GPIO_PER_PORT) as u8,
375            client: OptionalCell::empty(),
376            gpio_registers: unsafe {
377                StaticRef::new(
378                    (GPIO_BASE_ADDRESS + ((pin as usize) / GPIO_PER_PORT) * GPIO_SIZE)
379                        as *const GpioRegisters,
380                )
381            },
382            gpiote_registers: GPIOTE_BASE,
383            allocated_channel: OptionalCell::empty(),
384        }
385    }
386
387    pub fn set_high_drive(&self, high_drive: bool) {
388        self.gpio_registers.pin_cnf[self.pin as usize].modify(if high_drive {
389            PinConfig::DRIVE::H0H1
390        } else {
391            PinConfig::DRIVE::S0S1
392        });
393    }
394
395    // This sets the specified pin cfg as per the TRM for i2c pin usage.
396    pub fn set_i2c_pin_cfg(&self) {
397        self.gpio_registers.pin_cnf[self.pin as usize].modify(
398            PinConfig::DIR::Input
399                + PinConfig::INPUT::Disconnect
400                + PinConfig::DRIVE::S0D1
401                + PinConfig::SENSE::Disabled,
402        );
403    }
404}
405
406impl hil::gpio::Configure for GPIOPin<'_> {
407    fn set_floating_state(&self, mode: hil::gpio::FloatingState) {
408        let pin_config = match mode {
409            hil::gpio::FloatingState::PullUp => PinConfig::PULL::Pullup,
410            hil::gpio::FloatingState::PullDown => PinConfig::PULL::Pulldown,
411            hil::gpio::FloatingState::PullNone => PinConfig::PULL::Disabled,
412        };
413        // PIN_CNF also holds the direction and the pin driving mode, settings we don't
414        // want to overwrite!
415        self.gpio_registers.pin_cnf[self.pin as usize].modify(pin_config);
416    }
417
418    fn floating_state(&self) -> hil::gpio::FloatingState {
419        match self.gpio_registers.pin_cnf[self.pin as usize].read_as_enum(PinConfig::PULL) {
420            Some(PinConfig::PULL::Value::Pullup) => hil::gpio::FloatingState::PullUp,
421            Some(PinConfig::PULL::Value::Pulldown) => hil::gpio::FloatingState::PullDown,
422            Some(PinConfig::PULL::Value::Disabled) => hil::gpio::FloatingState::PullNone,
423            None => hil::gpio::FloatingState::PullNone,
424        }
425    }
426
427    fn make_output(&self) -> hil::gpio::Configuration {
428        self.gpio_registers.pin_cnf[self.pin as usize].modify(PinConfig::DIR::Output);
429        hil::gpio::Configuration::Output
430    }
431
432    fn disable_output(&self) -> hil::gpio::Configuration {
433        self.make_input()
434    }
435
436    fn make_input(&self) -> hil::gpio::Configuration {
437        self.gpio_registers.pin_cnf[self.pin as usize]
438            .modify(PinConfig::DIR::Input + PinConfig::INPUT::Connect);
439        hil::gpio::Configuration::Input
440    }
441
442    fn disable_input(&self) -> hil::gpio::Configuration {
443        // GPIOs are either inputs or outputs on this chip. To "disable" input
444        // would cause this pin to start driving, which is likely undesired, so
445        // this function is a no-op.
446        self.configuration()
447    }
448
449    fn configuration(&self) -> hil::gpio::Configuration {
450        let dir = self.gpio_registers.pin_cnf[self.pin as usize].read_as_enum(PinConfig::DIR);
451        let connected =
452            self.gpio_registers.pin_cnf[self.pin as usize].read_as_enum(PinConfig::INPUT);
453        match (dir, connected) {
454            (Some(PinConfig::DIR::Value::Input), Some(PinConfig::INPUT::Value::Connect)) => {
455                hil::gpio::Configuration::Input
456            }
457            (Some(PinConfig::DIR::Value::Input), Some(PinConfig::INPUT::Value::Disconnect)) => {
458                hil::gpio::Configuration::LowPower
459            }
460            (Some(PinConfig::DIR::Value::Output), _) => hil::gpio::Configuration::Output,
461            _ => hil::gpio::Configuration::Other,
462        }
463    }
464
465    fn deactivate_to_low_power(&self) {
466        self.gpio_registers.pin_cnf[self.pin as usize].write(
467            PinConfig::DIR::Input + PinConfig::INPUT::Disconnect + PinConfig::PULL::Disabled,
468        );
469    }
470}
471
472impl hil::gpio::Input for GPIOPin<'_> {
473    fn read(&self) -> bool {
474        self.gpio_registers.in_.get() & (1 << self.pin) != 0
475    }
476}
477
478impl hil::gpio::Output for GPIOPin<'_> {
479    fn set(&self) {
480        self.gpio_registers.outset.set(1 << self.pin);
481    }
482
483    fn clear(&self) {
484        self.gpio_registers.outclr.set(1 << self.pin);
485    }
486
487    fn toggle(&self) -> bool {
488        let result = (1 << self.pin) ^ self.gpio_registers.out.get();
489        self.gpio_registers.out.set(result);
490        result & (1 << self.pin) != 0
491    }
492}
493
494impl<'a> hil::gpio::Interrupt<'a> for GPIOPin<'a> {
495    fn set_client(&self, client: &'a dyn hil::gpio::Client) {
496        self.client.set(client);
497    }
498
499    fn is_pending(&self) -> bool {
500        if let Some(channel) = self.allocated_channel.get() {
501            let ev = &self.gpiote_registers.event_in[channel];
502            ev.any_matching_bits_set(EventsIn::EVENT::Ready)
503        } else {
504            false
505        }
506    }
507
508    fn enable_interrupts(&self, mode: hil::gpio::InterruptEdge) {
509        let channel = if let Some(chan) = self.allocated_channel.get() {
510            // We only support one interrupt mode per pin, despite the
511            // hardware supporting multiple. This is to comply with
512            // expectations in other Tock components, such as the button
513            // driver which re-registers interrupts for a restarted app,
514            // assuming the old ones to be overwritten.
515            chan
516        } else if let Ok(chan) = self.allocate_channel() {
517            // Don't have a channel yet, got a new one:
518            chan
519        } else {
520            debug!("No available GPIOTE interrupt channels");
521            return;
522        };
523
524        // Remember that we have allocated this channel for this pin:
525        self.allocated_channel.set(channel);
526
527        let polarity = match mode {
528            hil::gpio::InterruptEdge::EitherEdge => Config::POLARITY::Toggle,
529            hil::gpio::InterruptEdge::RisingEdge => Config::POLARITY::LoToHi,
530            hil::gpio::InterruptEdge::FallingEdge => Config::POLARITY::HiToLo,
531        };
532        let pin: u32 = (GPIO_PER_PORT as u32 * self.port as u32) + self.pin as u32;
533        self.gpiote_registers.config[channel]
534            .write(Config::MODE::Event + Config::PSEL.val(pin) + polarity);
535        self.gpiote_registers.intenset.set(1 << channel);
536    }
537
538    fn disable_interrupts(&self) {
539        if let Some(channel) = self.allocated_channel.get() {
540            self.gpiote_registers.config[channel]
541                .write(Config::MODE::CLEAR + Config::PSEL::CLEAR + Config::POLARITY::CLEAR);
542            self.gpiote_registers.intenclr.set(1 << channel);
543            self.allocated_channel.clear();
544        }
545    }
546}
547
548impl GPIOPin<'_> {
549    /// Allocate a GPIOTE channel
550    /// If the channel couldn't be allocated return error instead
551    fn allocate_channel(&self) -> Result<usize, ()> {
552        for (i, ch) in self.gpiote_registers.config.iter().enumerate() {
553            if ch.matches_all(Config::MODE::Disabled) {
554                return Ok(i);
555            }
556        }
557        Err(())
558    }
559
560    fn handle_interrupt(&self) {
561        self.client.map(|client| {
562            client.fired();
563        });
564    }
565}
566
567pub struct Port<'a, const N: usize> {
568    pub pins: [GPIOPin<'a>; N],
569}
570
571impl<'a, const N: usize> Index<Pin> for Port<'a, N> {
572    type Output = GPIOPin<'a>;
573
574    fn index(&self, index: Pin) -> &GPIOPin<'a> {
575        &self.pins[index as usize]
576    }
577}
578
579impl<'a, const N: usize> IndexMut<Pin> for Port<'a, N> {
580    fn index_mut(&mut self, index: Pin) -> &mut GPIOPin<'a> {
581        &mut self.pins[index as usize]
582    }
583}
584
585impl<'a, const N: usize> Port<'a, N> {
586    pub const fn new(pins: [GPIOPin<'a>; N]) -> Self {
587        Self { pins }
588    }
589
590    /// GPIOTE interrupt: check each GPIOTE channel, if any has
591    /// fired then trigger its corresponding pin's interrupt handler.
592    pub fn handle_interrupt(&self) {
593        // do this just to get a pointer the memory map
594        // doesn't matter which pin is used because it is the same
595        let pin_registers = self.pins[0].gpiote_registers;
596
597        for (i, ev) in pin_registers.event_in.iter().enumerate() {
598            if ev.any_matching_bits_set(EventsIn::EVENT::Ready) {
599                ev.write(EventsIn::EVENT::NotReady);
600                // Get pin number for the event and `trigger` an interrupt manually on that pin
601                let pin = pin_registers.config[i].read(Config::PSEL) as usize;
602                self.pins[pin].handle_interrupt();
603            }
604        }
605    }
606}