nrf51-hal 0.4.4

Peripheral access API for nRF51 microcontrollers
Documentation
//! General Purpose Input / Output

use core::marker::PhantomData;

/// Extension trait to split a GPIO peripheral in independent pins and registers
pub trait GpioExt {
    /// The to split the GPIO into
    type Parts;

    /// Splits the GPIO block into independent pins and registers
    fn split(self) -> Self::Parts;
}

/// Input mode (type state)
pub struct Input<MODE> {
    _mode: PhantomData<MODE>,
}

/// Floating input (type state)
pub struct Floating;

/// Pulled down input (type state)
pub struct PullDown;

/// Pulled up input (type state)
pub struct PullUp;

/// Open drain input or output (type state)
pub struct OpenDrain;

/// Output mode (type state)
pub struct Output<MODE> {
    _mode: PhantomData<MODE>,
}

/// Push pull output (type state)
pub struct PushPull;

macro_rules! gpio {
    ($GPIOX:ident, $gpiox:ident, $PXx:ident, [
        $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty),)+
    ]) => {
        /// GPIO
        pub mod $gpiox {
            use core::marker::PhantomData;

            use hal::digital::{InputPin, OutputPin};
            use nrf51::$GPIOX;

            use super::{
                Floating, GpioExt, Input, OpenDrain, Output,
                PullDown, PullUp, PushPull,
            };

            /// GPIO parts
            pub struct Parts {
                $(
                    /// Pin
                    pub $pxi: $PXi<$MODE>,
                )+
            }

            impl GpioExt for $GPIOX {
                type Parts = Parts;

                fn split(self) -> Parts {
                    Parts {
                        $(
                            $pxi: $PXi { _mode: PhantomData },
                        )+
                    }
                }
            }

            /// Partially erased pin
            pub struct $PXx<MODE> {
                i: u8,
                _mode: PhantomData<MODE>,
            }

            impl<MODE> OutputPin for $PXx<Output<MODE>> {
                fn is_high(&self) -> bool {
                    !self.is_low()
                }

                fn is_low(&self) -> bool {
                    // NOTE(unsafe) atomic read with no side effects
                    unsafe { (*GPIO::ptr()).out.read().bits() & (1 << self.i) == 0 }
                }

                fn set_high(&mut self) {
                    // NOTE(unsafe) atomic write to a stateless register
                    unsafe { (*GPIO::ptr()).outset.write(|w| w.bits(1 << self.i)) }
                }

                fn set_low(&mut self) {
                    // NOTE(unsafe) atomic write to a stateless register
                    unsafe { (*GPIO::ptr()).outclr.write(|w| w.bits(1 << self.i)) }
                }
            }

            impl<MODE> InputPin for $PXx<Input<MODE>> {
                fn is_high(&self) -> bool {
                    !self.is_low()
                }

                fn is_low(&self) -> bool {
                    // NOTE(unsafe) atomic read with no side effects
                    unsafe { (*GPIO::ptr()).in_.read().bits() & (1 << self.i) == 0 }
                }
            }

            $(
                /// Pin
                pub struct $PXi<MODE> {
                    _mode: PhantomData<MODE>,
                }

                impl<MODE> $PXi<MODE> {
                    /// Configures the pin to operate as a floating input pin
                    pub fn into_floating_input(
                        self,
                    ) -> $PXi<Input<Floating>> {
                        let pincnf = unsafe { &(*GPIO::ptr()).pin_cnf[$i] };
                        pincnf.write(|w| {
                            w.dir()
                                .input()
                                .drive()
                                .s0s1()
                                .pull()
                                .disabled()
                                .sense()
                                .disabled()
                                .input()
                                .connect()
                        });
                        $PXi { _mode: PhantomData }
                    }

                    /// Configures the pin to operate as a open drain input pin
                    pub fn into_open_drain_input(
                        self,
                    ) -> $PXi<Input<OpenDrain>> {
                        let pincnf = unsafe { &(*GPIO::ptr()).pin_cnf[$i] };
                        pincnf.write(|w| {
                            w.dir()
                                .input()
                                .drive()
                                .s0d1()
                                .pull()
                                .disabled()
                                .sense()
                                .disabled()
                                .input()
                                .connect()
                        });
                        $PXi { _mode: PhantomData }
                    }

                    /// Configures the pin to operate as a pulled down input pin
                    pub fn into_pull_down_input(
                        self,
                        ) -> $PXi<Input<PullDown>> {
                        let pincnf = unsafe { &(*GPIO::ptr()).pin_cnf[$i] };
                        pincnf.write(|w| {
                            w.dir()
                                .input()
                                .drive()
                                .s0s1()
                                .pull()
                                .pulldown()
                                .sense()
                                .disabled()
                                .input()
                                .connect()
                        });

                        $PXi { _mode: PhantomData }
                    }

                    /// Configures the pin to operate as a pulled up input pin
                    pub fn into_pull_up_input(
                        self,
                    ) -> $PXi<Input<PullUp>> {
                        let pincnf = unsafe { &(*GPIO::ptr()).pin_cnf[$i] };
                        pincnf.write(|w| {
                            w.dir()
                                .input()
                                .drive()
                                .s0s1()
                                .pull()
                                .pullup()
                                .sense()
                                .disabled()
                                .input()
                                .connect()
                        });

                        $PXi { _mode: PhantomData }
                    }

                    /// Configures the pin to operate as an open drain output pin
                    pub fn into_open_drain_output(
                        self,
                    ) -> $PXi<Output<OpenDrain>> {
                        let pincnf = unsafe { &(*GPIO::ptr()).pin_cnf[$i] };
                        pincnf.write(|w| {
                            w.dir()
                                .output()
                                .drive()
                                .s0d1()
                                .pull()
                                .disabled()
                                .sense()
                                .disabled()
                                .input()
                                .disconnect()
                        });

                        $PXi { _mode: PhantomData }
                    }

                    /// Configures the pin to operate as an push pull output pin
                    pub fn into_push_pull_output(
                        self,
                    ) -> $PXi<Output<PushPull>> {

                        let pincnf = unsafe { &(*GPIO::ptr()).pin_cnf[$i] };
                        pincnf.write(|w| {
                            w.dir()
                                .output()
                                .drive()
                                .s0s1()
                                .pull()
                                .disabled()
                                .sense()
                                .disabled()
                                .input()
                                .disconnect()
                        });

                        $PXi { _mode: PhantomData }
                    }
                }

                impl $PXi<Output<OpenDrain>> {
                    /// Enables / disables the internal pull up
                    pub fn internal_pull_up(&mut self, on: bool) {
                        let pincnf = unsafe { &(*GPIO::ptr()).pin_cnf[$i] };
                        if on {
                            pincnf.modify(|_, w| w.pull().pullup());
                        } else {
                            pincnf.modify(|_, w| w.pull().disabled());
                        }
                    }
                }

                impl<MODE> $PXi<Output<MODE>> {
                    /// Erases the pin number from the type
                    ///
                    /// This is useful when you want to collect the pins into an array where you
                    /// need all the elements to have the same type
                    pub fn downgrade(self) -> $PXx<Output<MODE>> {
                        $PXx {
                            i: $i,
                            _mode: self._mode,
                        }
                    }
                }

                impl<MODE> OutputPin for $PXi<Output<MODE>> {
                    fn is_high(&self) -> bool {
                        !self.is_low()
                    }

                    fn is_low(&self) -> bool {
                        // NOTE(unsafe) atomic read with no side effects
                        unsafe { (*GPIO::ptr()).out.read().bits() & (1 << $i) == 0 }
                    }

                    fn set_high(&mut self) {
                        // NOTE(unsafe) atomic write to a stateless register
                        //unsafe { (*GPIO::ptr()).outset.write(|w| w.bits(1 << $i)) }
                        unsafe { (*GPIO::ptr()).outset.write(|w| w.bits(1 << $i)) }
                    }

                    fn set_low(&mut self) {
                        // NOTE(unsafe) atomic write to a stateless register
                        unsafe { (*GPIO::ptr()).outclr.write(|w| w.bits(1 << $i)) }
                    }
                }

                impl<MODE> $PXi<Input<MODE>> {
                    /// Erases the pin number from the type
                    ///
                    /// This is useful when you want to collect the pins into an array where you
                    /// need all the elements to have the same type
                    pub fn downgrade(self) -> $PXx<Input<MODE>> {
                        $PXx {
                            i: $i,
                            _mode: self._mode,
                        }
                    }
                }

                impl<MODE> InputPin for $PXi<Input<MODE>> {
                    fn is_high(&self) -> bool {
                        !self.is_low()
                    }

                    fn is_low(&self) -> bool {
                        // NOTE(unsafe) atomic read with no side effects
                        unsafe { (*GPIO::ptr()).in_.read().bits() & (1 << $i) == 0 }
                    }
                }
            )+

                impl<TYPE> $PXx<TYPE> {
                    pub fn get_id (&self) -> u8
                    {
                        self.i
                    }
                }
        }
    }
}

gpio!(GPIO, gpio, PIN, [
    PIN0: (pin0, 0, Input<Floating>),
    PIN1: (pin1, 1, Input<Floating>),
    PIN2: (pin2, 2, Input<Floating>),
    PIN3: (pin3, 3, Input<Floating>),
    PIN4: (pin4, 4, Input<Floating>),
    PIN5: (pin5, 5, Input<Floating>),
    PIN6: (pin6, 6, Input<Floating>),
    PIN7: (pin7, 7, Input<Floating>),
    PIN8: (pin8, 8, Input<Floating>),
    PIN9: (pin9, 9, Input<Floating>),
    PIN10: (pin10, 10, Input<Floating>),
    PIN11: (pin11, 11, Input<Floating>),
    PIN12: (pin12, 12, Input<Floating>),
    PIN13: (pin13, 13, Input<Floating>),
    PIN14: (pin14, 14, Input<Floating>),
    PIN15: (pin15, 15, Input<Floating>),
    PIN16: (pin16, 16, Input<Floating>),
    PIN17: (pin17, 17, Input<Floating>),
    PIN18: (pin18, 18, Input<Floating>),
    PIN19: (pin19, 19, Input<Floating>),
    PIN20: (pin20, 20, Input<Floating>),
    PIN21: (pin21, 21, Input<Floating>),
    PIN22: (pin22, 22, Input<Floating>),
    PIN23: (pin23, 23, Input<Floating>),
    PIN24: (pin24, 24, Input<Floating>),
    PIN25: (pin25, 25, Input<Floating>),
    PIN26: (pin26, 26, Input<Floating>),
    PIN27: (pin27, 27, Input<Floating>),
    PIN28: (pin28, 28, Input<Floating>),
    PIN29: (pin29, 29, Input<Floating>),
    PIN30: (pin30, 30, Input<Floating>),
    PIN31: (pin31, 31, Input<Floating>),
]);