msp432/
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//! General Purpose Input/Output (GPIO)
6
7use core::cell::Cell;
8use core::marker::PhantomData;
9use kernel::hil::gpio;
10use kernel::utilities::cells::OptionalCell;
11use kernel::utilities::registers::interfaces::{Readable, Writeable};
12use kernel::utilities::registers::{register_bitfields, register_structs, ReadOnly, ReadWrite};
13use kernel::utilities::StaticRef;
14
15const GPIO_BASES: [StaticRef<GpioRegisters>; 6] = [
16    unsafe { StaticRef::new(0x4000_4C00u32 as *const GpioRegisters) }, // PORT 1&2
17    unsafe { StaticRef::new(0x4000_4C20u32 as *const GpioRegisters) }, // PORT 3&4
18    unsafe { StaticRef::new(0x4000_4C40u32 as *const GpioRegisters) }, // PORT 5&6
19    unsafe { StaticRef::new(0x4000_4C60u32 as *const GpioRegisters) }, // PORT 7&8
20    unsafe { StaticRef::new(0x4000_4C80u32 as *const GpioRegisters) }, // PORT 9&10
21    unsafe { StaticRef::new(0x4000_4D20u32 as *const GpioRegisters) }, // PORT J
22];
23
24const PINS_PER_PORT: u8 = 8;
25
26register_structs! {
27    GpioRegisters {
28        (0x00 => input: [ReadOnly<u8, PxIN::Register>; 2]),
29        (0x02 => out: [ReadWrite<u8, PxOUT::Register>; 2]),
30        (0x04 => dir: [ReadWrite<u8, PxDIR::Register>; 2]),
31        (0x06 => ren: [ReadWrite<u8, PxREN::Register>; 2]),
32        (0x08 => ds: [ReadWrite<u8, PxDS::Register>; 2]),
33        (0x0A => sel0: [ReadWrite<u8, PxSEL0::Register>; 2]),
34        (0x0C => sel1: [ReadWrite<u8, PxSEL1::Register>; 2]),
35        (0x0E => iv1: ReadWrite<u16, PxIV::Register>),
36        (0x10 => _reserved),
37        (0x16 => selc: [ReadWrite<u8, PxSELC::Register>; 2]),
38        (0x18 => ies: [ReadWrite<u8, PxIES::Register>; 2]),
39        (0x1A => ie: [ReadWrite<u8, PxIE::Register>; 2]),
40        (0x1C => ifg: [ReadWrite<u8, PxIFG::Register>; 2]),
41        (0x1E => iv2: ReadWrite<u16, PxIV::Register>),
42        (0x20 => @END),
43    }
44}
45
46register_bitfields! [u8,
47    /// Input-register, get input-status of pins
48    PxIN [
49        PIN0 OFFSET(0) NUMBITS(1),
50        PIN1 OFFSET(1) NUMBITS(1),
51        PIN2 OFFSET(2) NUMBITS(1),
52        PIN3 OFFSET(3) NUMBITS(1),
53        PIN4 OFFSET(4) NUMBITS(1),
54        PIN5 OFFSET(5) NUMBITS(1),
55        PIN6 OFFSET(6) NUMBITS(1),
56        PIN7 OFFSET(7) NUMBITS(1)
57    ],
58    /// Output-register, set output status of pins
59    PxOUT [
60        PIN0 OFFSET(0) NUMBITS(1),
61        PIN1 OFFSET(1) NUMBITS(1),
62        PIN2 OFFSET(2) NUMBITS(1),
63        PIN3 OFFSET(3) NUMBITS(1),
64        PIN4 OFFSET(4) NUMBITS(1),
65        PIN5 OFFSET(5) NUMBITS(1),
66        PIN6 OFFSET(6) NUMBITS(1),
67        PIN7 OFFSET(7) NUMBITS(1)
68    ],
69    /// Direction-register, set direction of pins
70    PxDIR [
71        PIN0 OFFSET(0) NUMBITS(1),
72        PIN1 OFFSET(1) NUMBITS(1),
73        PIN2 OFFSET(2) NUMBITS(1),
74        PIN3 OFFSET(3) NUMBITS(1),
75        PIN4 OFFSET(4) NUMBITS(1),
76        PIN5 OFFSET(5) NUMBITS(1),
77        PIN6 OFFSET(6) NUMBITS(1),
78        PIN7 OFFSET(7) NUMBITS(1)
79    ],
80    /// Pull-register, enable/disable pullup- or -down resistor
81    PxREN [
82        PIN0 OFFSET(0) NUMBITS(1),
83        PIN1 OFFSET(1) NUMBITS(1),
84        PIN2 OFFSET(2) NUMBITS(1),
85        PIN3 OFFSET(3) NUMBITS(1),
86        PIN4 OFFSET(4) NUMBITS(1),
87        PIN5 OFFSET(5) NUMBITS(1),
88        PIN6 OFFSET(6) NUMBITS(1),
89        PIN7 OFFSET(7) NUMBITS(1)
90    ],
91    /// Drive-strength register, select high(1) or low(0) drive-strength
92    PxDS [
93        PIN0 OFFSET(0) NUMBITS(1),
94        PIN1 OFFSET(1) NUMBITS(1),
95        PIN2 OFFSET(2) NUMBITS(1),
96        PIN3 OFFSET(3) NUMBITS(1),
97        PIN4 OFFSET(4) NUMBITS(1),
98        PIN5 OFFSET(5) NUMBITS(1),
99        PIN6 OFFSET(6) NUMBITS(1),
100        PIN7 OFFSET(7) NUMBITS(1)
101    ],
102    /// Function-selection register 0, combined with function-selection 1 the
103    /// module function is selected (GPIO, primary, secondary or tertiary)
104    PxSEL0 [
105        PIN0 OFFSET(0) NUMBITS(1),
106        PIN1 OFFSET(1) NUMBITS(1),
107        PIN2 OFFSET(2) NUMBITS(1),
108        PIN3 OFFSET(3) NUMBITS(1),
109        PIN4 OFFSET(4) NUMBITS(1),
110        PIN5 OFFSET(5) NUMBITS(1),
111        PIN6 OFFSET(6) NUMBITS(1),
112        PIN7 OFFSET(7) NUMBITS(1)
113    ],
114    /// Function-selection register 1, combined with function-selection 0 the
115    /// module function is selected (GPIO, primary, secondary or tertiary)
116    PxSEL1 [
117        PIN0 OFFSET(0) NUMBITS(1),
118        PIN1 OFFSET(1) NUMBITS(1),
119        PIN2 OFFSET(2) NUMBITS(1),
120        PIN3 OFFSET(3) NUMBITS(1),
121        PIN4 OFFSET(4) NUMBITS(1),
122        PIN5 OFFSET(5) NUMBITS(1),
123        PIN6 OFFSET(6) NUMBITS(1),
124        PIN7 OFFSET(7) NUMBITS(1)
125    ],
126    /// Complement selection, set a bit in PxSEL0 and PxSEL1 concurrently
127    PxSELC [
128        PIN0 OFFSET(0) NUMBITS(1),
129        PIN1 OFFSET(1) NUMBITS(1),
130        PIN2 OFFSET(2) NUMBITS(1),
131        PIN3 OFFSET(3) NUMBITS(1),
132        PIN4 OFFSET(4) NUMBITS(1),
133        PIN5 OFFSET(5) NUMBITS(1),
134        PIN6 OFFSET(6) NUMBITS(1),
135        PIN7 OFFSET(7) NUMBITS(1)
136    ],
137    /// Interrupt-edge selction, 0=rising-edge, 1=falling-edge
138    PxIES [
139        PIN0 OFFSET(0) NUMBITS(1),
140        PIN1 OFFSET(1) NUMBITS(1),
141        PIN2 OFFSET(2) NUMBITS(1),
142        PIN3 OFFSET(3) NUMBITS(1),
143        PIN4 OFFSET(4) NUMBITS(1),
144        PIN5 OFFSET(5) NUMBITS(1),
145        PIN6 OFFSET(6) NUMBITS(1),
146        PIN7 OFFSET(7) NUMBITS(1)
147    ],
148    /// Interrupt enable register
149    PxIE [
150        PIN0 OFFSET(0) NUMBITS(1),
151        PIN1 OFFSET(1) NUMBITS(1),
152        PIN2 OFFSET(2) NUMBITS(1),
153        PIN3 OFFSET(3) NUMBITS(1),
154        PIN4 OFFSET(4) NUMBITS(1),
155        PIN5 OFFSET(5) NUMBITS(1),
156        PIN6 OFFSET(6) NUMBITS(1),
157        PIN7 OFFSET(7) NUMBITS(1)
158    ],
159    /// Interrupt flag register
160    PxIFG [
161        PIN0 OFFSET(0) NUMBITS(1),
162        PIN1 OFFSET(1) NUMBITS(1),
163        PIN2 OFFSET(2) NUMBITS(1),
164        PIN3 OFFSET(3) NUMBITS(1),
165        PIN4 OFFSET(4) NUMBITS(1),
166        PIN5 OFFSET(5) NUMBITS(1),
167        PIN6 OFFSET(6) NUMBITS(1),
168        PIN7 OFFSET(7) NUMBITS(1)
169    ]
170];
171
172register_bitfields! [u16,
173    // interrupt vector register
174    PxIV [
175        IV OFFSET(0) NUMBITS(16)
176    ]
177];
178
179#[rustfmt::skip]
180#[repr(u8)]
181#[derive(Copy, Clone)]
182pub enum IntPinNr {
183    P01_0, P01_1, P01_2, P01_3, P01_4, P01_5, P01_6, P01_7,
184    P02_0, P02_1, P02_2, P02_3, P02_4, P02_5, P02_6, P02_7,
185    P03_0, P03_1, P03_2, P03_3, P03_4, P03_5, P03_6, P03_7,
186    P04_0, P04_1, P04_2, P04_3, P04_4, P04_5, P04_6, P04_7,
187    P05_0, P05_1, P05_2, P05_3, P05_4, P05_5, P05_6, P05_7,
188    P06_0, P06_1, P06_2, P06_3, P06_4, P06_5, P06_6, P06_7,
189}
190
191#[rustfmt::skip]
192#[allow(non_camel_case_types)]
193#[repr(u8)]
194#[derive(Copy, Clone)]
195pub enum PinNr {
196    P07_0, P07_1, P07_2, P07_3, P07_4, P07_5, P07_6, P07_7,
197    P08_0, P08_1, P08_2, P08_3, P08_4, P08_5, P08_6, P08_7,
198    P09_0, P09_1, P09_2, P09_3, P09_4, P09_5, P09_6, P09_7,
199    P10_0, P10_1, P10_2, P10_3, P10_4, P10_5, P10_6, P10_7,
200    PJ_0,  PJ_1,  PJ_2,  PJ_3,  PJ_4,  PJ_5,  PJ_6,  PJ_7,
201}
202
203#[derive(Clone, Copy, Debug, PartialEq)]
204enum ModuleFunction {
205    Gpio,
206    Primary,
207    Secondary,
208    Tertiary,
209}
210
211pub struct GpioManager<'a> {
212    pub int_pins: [IntPin<'a>; 48],
213    pub pins: [Pin<'a>; 40],
214}
215
216impl GpioManager<'_> {
217    pub fn new() -> Self {
218        Self {
219            int_pins: [
220                IntPin::new(IntPinNr::P01_0),
221                IntPin::new(IntPinNr::P01_1),
222                IntPin::new(IntPinNr::P01_2),
223                IntPin::new(IntPinNr::P01_3),
224                IntPin::new(IntPinNr::P01_4),
225                IntPin::new(IntPinNr::P01_5),
226                IntPin::new(IntPinNr::P01_6),
227                IntPin::new(IntPinNr::P01_7),
228                IntPin::new(IntPinNr::P02_0),
229                IntPin::new(IntPinNr::P02_1),
230                IntPin::new(IntPinNr::P02_2),
231                IntPin::new(IntPinNr::P02_3),
232                IntPin::new(IntPinNr::P02_4),
233                IntPin::new(IntPinNr::P02_5),
234                IntPin::new(IntPinNr::P02_6),
235                IntPin::new(IntPinNr::P02_7),
236                IntPin::new(IntPinNr::P03_0),
237                IntPin::new(IntPinNr::P03_1),
238                IntPin::new(IntPinNr::P03_2),
239                IntPin::new(IntPinNr::P03_3),
240                IntPin::new(IntPinNr::P03_4),
241                IntPin::new(IntPinNr::P03_5),
242                IntPin::new(IntPinNr::P03_6),
243                IntPin::new(IntPinNr::P03_7),
244                IntPin::new(IntPinNr::P04_0),
245                IntPin::new(IntPinNr::P04_1),
246                IntPin::new(IntPinNr::P04_2),
247                IntPin::new(IntPinNr::P04_3),
248                IntPin::new(IntPinNr::P04_4),
249                IntPin::new(IntPinNr::P04_5),
250                IntPin::new(IntPinNr::P04_6),
251                IntPin::new(IntPinNr::P04_7),
252                IntPin::new(IntPinNr::P05_0),
253                IntPin::new(IntPinNr::P05_1),
254                IntPin::new(IntPinNr::P05_2),
255                IntPin::new(IntPinNr::P05_3),
256                IntPin::new(IntPinNr::P05_4),
257                IntPin::new(IntPinNr::P05_5),
258                IntPin::new(IntPinNr::P05_6),
259                IntPin::new(IntPinNr::P05_7),
260                IntPin::new(IntPinNr::P06_0),
261                IntPin::new(IntPinNr::P06_1),
262                IntPin::new(IntPinNr::P06_2),
263                IntPin::new(IntPinNr::P06_3),
264                IntPin::new(IntPinNr::P06_4),
265                IntPin::new(IntPinNr::P06_5),
266                IntPin::new(IntPinNr::P06_6),
267                IntPin::new(IntPinNr::P06_7),
268            ],
269            pins: [
270                Pin::new(PinNr::P07_0),
271                Pin::new(PinNr::P07_1),
272                Pin::new(PinNr::P07_2),
273                Pin::new(PinNr::P07_3),
274                Pin::new(PinNr::P07_4),
275                Pin::new(PinNr::P07_5),
276                Pin::new(PinNr::P07_6),
277                Pin::new(PinNr::P07_7),
278                Pin::new(PinNr::P08_0),
279                Pin::new(PinNr::P08_1),
280                Pin::new(PinNr::P08_2),
281                Pin::new(PinNr::P08_3),
282                Pin::new(PinNr::P08_4),
283                Pin::new(PinNr::P08_5),
284                Pin::new(PinNr::P08_6),
285                Pin::new(PinNr::P08_7),
286                Pin::new(PinNr::P09_0),
287                Pin::new(PinNr::P09_1),
288                Pin::new(PinNr::P09_2),
289                Pin::new(PinNr::P09_3),
290                Pin::new(PinNr::P09_4),
291                Pin::new(PinNr::P09_5),
292                Pin::new(PinNr::P09_6),
293                Pin::new(PinNr::P09_7),
294                Pin::new(PinNr::P10_0),
295                Pin::new(PinNr::P10_1),
296                Pin::new(PinNr::P10_2),
297                Pin::new(PinNr::P10_3),
298                Pin::new(PinNr::P10_4),
299                Pin::new(PinNr::P10_5),
300                Pin::new(PinNr::P10_6),
301                Pin::new(PinNr::P10_7),
302                Pin::new(PinNr::PJ_0),
303                Pin::new(PinNr::PJ_1),
304                Pin::new(PinNr::PJ_2),
305                Pin::new(PinNr::PJ_3),
306                Pin::new(PinNr::PJ_4),
307                Pin::new(PinNr::PJ_5),
308                Pin::new(PinNr::PJ_6),
309                Pin::new(PinNr::PJ_7),
310            ],
311        }
312    }
313}
314
315/// Supports interrupts
316pub struct IntPin<'a> {
317    pin: u8,
318    registers: StaticRef<GpioRegisters>,
319    reg_idx: usize,
320    detect_both_edges: Cell<bool>,
321    client: OptionalCell<&'a dyn gpio::Client>,
322}
323
324/// Does not support interrupts
325pub struct Pin<'a> {
326    pin: u8,
327    registers: StaticRef<GpioRegisters>,
328    reg_idx: usize,
329    // Add the phantom data in order to make the macro implementation work
330    // because IntPin requires a lifetime parameter
331    phantom: PhantomData<&'a ()>,
332}
333
334impl<'a> Pin<'a> {
335    const fn new(pin: PinNr) -> Pin<'a> {
336        let pin_nr = (pin as u8) % PINS_PER_PORT;
337        let p = (pin as u8) / PINS_PER_PORT;
338        Pin {
339            pin: pin_nr,
340            registers: GPIO_BASES[3 + ((p / 2) as usize)],
341            reg_idx: (p % 2) as usize,
342            phantom: PhantomData,
343        }
344    }
345}
346
347impl<'a> IntPin<'a> {
348    pub const fn new(pin: IntPinNr) -> IntPin<'a> {
349        let pin_nr = (pin as u8) % PINS_PER_PORT;
350        let p = (pin as u8) / PINS_PER_PORT;
351        IntPin {
352            pin: pin_nr,
353            registers: GPIO_BASES[(p / 2) as usize],
354            reg_idx: (p % 2) as usize,
355            detect_both_edges: Cell::new(false),
356            client: OptionalCell::empty(),
357        }
358    }
359
360    fn switch_detecting_edge(&self) {
361        // Don't rely on the current configuration of the edge-detection, read the current state
362        // of the pin and set the detecting edge based on this information. It could be that we
363        // already missed one or more interrupts, so it doesn't make sense to just switch the edge.
364
365        let mut edge = self.registers.ies[self.reg_idx].get();
366        if self.read_level() {
367            // Pin is high -> detect falling edge
368            edge |= 1 << self.pin;
369        } else {
370            // Pin is low -> detect rising edge
371            edge &= !(1 << self.pin);
372        }
373        self.registers.ies[self.reg_idx].set(edge);
374    }
375
376    fn handle_interrupt(&self) {
377        self.client.map(|client| client.fired());
378
379        if self.detect_both_edges.get() {
380            self.switch_detecting_edge();
381        }
382    }
383}
384
385macro_rules! pin_implementation {
386    ($pin_type:ident) => {
387        impl<'a> $pin_type<'a> {
388            fn read_level(&self) -> bool {
389                (self.registers.input[self.reg_idx].get() & (1 << self.pin)) > 0
390            }
391
392            fn enable_module_function(&self, mode: ModuleFunction) {
393                let mut sel0 = self.registers.sel0[self.reg_idx].get();
394                let mut sel1 = self.registers.sel1[self.reg_idx].get();
395
396                match mode {
397                    ModuleFunction::Gpio => {
398                        sel0 &= !(1 << self.pin);
399                        sel1 &= !(1 << self.pin);
400                    }
401                    ModuleFunction::Primary => {
402                        sel0 |= 1 << self.pin;
403                        sel1 &= !(1 << self.pin);
404                    }
405                    ModuleFunction::Secondary => {
406                        sel0 &= !(1 << self.pin);
407                        sel1 |= 1 << self.pin;
408                    }
409                    ModuleFunction::Tertiary => {
410                        sel0 |= 1 << self.pin;
411                        sel1 |= 1 << self.pin;
412                    }
413                }
414
415                self.registers.sel0[self.reg_idx].set(sel0);
416                self.registers.sel1[self.reg_idx].set(sel1);
417            }
418
419            pub fn enable_primary_function(&self) {
420                self.enable_module_function(ModuleFunction::Primary);
421            }
422
423            pub fn enable_secondary_function(&self) {
424                self.enable_module_function(ModuleFunction::Secondary);
425            }
426
427            pub fn enable_tertiary_function(&self) {
428                self.enable_module_function(ModuleFunction::Tertiary);
429            }
430        }
431
432        impl<'a> gpio::Input for $pin_type<'a> {
433            fn read(&self) -> bool {
434                self.read_level()
435            }
436        }
437
438        impl<'a> gpio::Output for $pin_type<'a> {
439            fn set(&self) {
440                let mut val = self.registers.out[self.reg_idx].get();
441                val |= 1 << self.pin;
442                self.registers.out[self.reg_idx].set(val);
443            }
444
445            fn clear(&self) {
446                let mut val = self.registers.out[self.reg_idx].get();
447                val &= !(1 << self.pin);
448                self.registers.out[self.reg_idx].set(val);
449            }
450
451            fn toggle(&self) -> bool {
452                let mut val = self.registers.out[self.reg_idx].get();
453                val ^= 1 << self.pin;
454                self.registers.out[self.reg_idx].set(val);
455                (val & (1 << self.pin)) > 0
456            }
457        }
458
459        impl<'a> gpio::Configure for $pin_type<'a> {
460            fn configuration(&self) -> gpio::Configuration {
461                let regs = self.registers;
462                let dir = regs.dir[self.reg_idx].get();
463                let mut sel = ((regs.sel0[self.reg_idx].get() & (1 << self.pin)) > 0) as u8;
464                sel |= (((regs.sel1[self.reg_idx].get() & (1 << self.pin)) > 0) as u8) << 1;
465
466                if sel > 0 {
467                    gpio::Configuration::Function
468                } else {
469                    if (dir & (1 << self.pin)) > 0 {
470                        gpio::Configuration::Output
471                    } else {
472                        gpio::Configuration::Input
473                    }
474                }
475            }
476
477            fn make_output(&self) -> gpio::Configuration {
478                use gpio::Output;
479                self.enable_module_function(ModuleFunction::Gpio);
480
481                let mut val = self.registers.dir[self.reg_idx].get();
482                val |= 1 << self.pin;
483                self.registers.dir[self.reg_idx].set(val);
484
485                // Clear the output since the state of an output is undefined after a reset
486                self.clear();
487                gpio::Configuration::Output
488            }
489
490            fn disable_output(&self) -> gpio::Configuration {
491                self.make_input()
492            }
493
494            fn make_input(&self) -> gpio::Configuration {
495                self.enable_module_function(ModuleFunction::Gpio);
496
497                let mut val = self.registers.dir[self.reg_idx].get();
498                val &= !(1 << self.pin);
499                self.registers.dir[self.reg_idx].set(val);
500                gpio::Configuration::Input
501            }
502
503            fn disable_input(&self) -> gpio::Configuration {
504                // it's not possible to deactivate the pin at all, so just return the
505                // current configuration
506                self.configuration()
507            }
508
509            fn deactivate_to_low_power(&self) {
510                // the chip doesn't support any low-power, so set it to input with
511                // a pullup resistor which should not consume much current
512                self.make_input();
513                self.set_floating_state(gpio::FloatingState::PullUp);
514            }
515
516            fn set_floating_state(&self, state: gpio::FloatingState) {
517                let regs = self.registers;
518                let mut ren = regs.ren[self.reg_idx].get();
519                let mut out = regs.out[self.reg_idx].get();
520                match state {
521                    gpio::FloatingState::PullDown => {
522                        ren |= 1 << self.pin;
523                        out &= !(1 << self.pin);
524                    }
525                    gpio::FloatingState::PullUp => {
526                        ren |= 1 << self.pin;
527                        out |= 1 << self.pin;
528                    }
529                    gpio::FloatingState::PullNone => {
530                        ren &= !(1 << self.pin);
531                    }
532                }
533                regs.ren[self.reg_idx].set(ren);
534                regs.out[self.reg_idx].set(out);
535            }
536
537            fn floating_state(&self) -> gpio::FloatingState {
538                let ren = self.registers.ren[self.reg_idx].get();
539                let out = self.registers.out[self.reg_idx].get();
540
541                if (ren & (1 << self.pin)) > 0 {
542                    if (out & (1 << self.pin)) > 0 {
543                        gpio::FloatingState::PullUp
544                    } else {
545                        gpio::FloatingState::PullDown
546                    }
547                } else {
548                    gpio::FloatingState::PullNone
549                }
550            }
551        }
552    };
553}
554
555pin_implementation!(IntPin);
556pin_implementation!(Pin);
557
558impl<'a> gpio::Interrupt<'a> for IntPin<'a> {
559    fn set_client(&self, client: &'a dyn gpio::Client) {
560        self.client.set(client);
561    }
562
563    fn enable_interrupts(&self, mode: gpio::InterruptEdge) {
564        // disable the interrupt at the beginning because modifying the edge-select register
565        // could trigger an interrupt -> datasheet p. 680 section 12.2.7.1
566        self.disable_interrupts();
567
568        let mut edge = self.registers.ies[self.reg_idx].get();
569        match mode {
570            gpio::InterruptEdge::FallingEdge => {
571                self.detect_both_edges.set(false);
572                edge |= 1 << self.pin;
573            }
574            gpio::InterruptEdge::RisingEdge => {
575                self.detect_both_edges.set(false);
576                edge &= !(1 << self.pin);
577            }
578            gpio::InterruptEdge::EitherEdge => {
579                // Implement a software based implementation for detecting both edges since
580                // this controller doesn't support this feature by hardware
581                self.detect_both_edges.set(true);
582                if self.read_level() {
583                    // If the pin-level is high, configure for falling edges.
584                    edge |= 1 << self.pin;
585                } else {
586                    // If the pin-level is low, configure for rising edges.
587                    edge &= !(1 << self.pin);
588                }
589            }
590        }
591
592        // Set the edge detection
593        self.registers.ies[self.reg_idx].set(edge);
594        // Clear eventually caused interrupts
595        self.registers.ifg[self.reg_idx]
596            .set(self.registers.ifg[self.reg_idx].get() & !(1 << self.pin));
597        // Enable the interrupt
598        self.registers.ie[self.reg_idx]
599            .set(self.registers.ie[self.reg_idx].get() | (1 << self.pin));
600    }
601
602    fn disable_interrupts(&self) {
603        let mut enable = self.registers.ie[self.reg_idx].get();
604        enable &= !(1 << self.pin);
605        self.registers.ie[self.reg_idx].set(enable);
606    }
607
608    fn is_pending(&self) -> bool {
609        (self.registers.ifg[self.reg_idx].get() & (1 << self.pin)) > 0
610    }
611}
612
613impl GpioManager<'_> {
614    pub fn handle_interrupt(&self, port_idx: usize) {
615        let regs: StaticRef<GpioRegisters> = GPIO_BASES[port_idx / 2];
616        let ifgs: [u8; 2] = [regs.ifg[0].get(), regs.ifg[1].get()];
617
618        let handle_int = |ifg_idx: usize, i: usize| {
619            let bit = 1 << i;
620            if (ifgs[ifg_idx] & bit) > 0 {
621                self.int_pins[(port_idx * 8) + i].handle_interrupt();
622                // read back the current register value to avoid loosing interrupts which occured
623                // within this function
624                regs.ifg[ifg_idx].set(regs.ifg[ifg_idx].get() & !bit);
625            }
626        };
627
628        for i in 0..8 {
629            handle_int(0, i);
630            handle_int(1, i);
631        }
632    }
633}