355 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			355 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
use embassy_hal_internal::{impl_peripheral, PeripheralType};
 | 
						||
 | 
						||
use crate::pac_utils::*;
 | 
						||
use crate::{peripherals, Peri};
 | 
						||
 | 
						||
pub(crate) fn init() {
 | 
						||
    // Enable clocks for GPIO, PINT, and IOCON
 | 
						||
    syscon_reg()
 | 
						||
        .ahbclkctrl0
 | 
						||
        .modify(|_, w| w.gpio0().enable().gpio1().enable().mux().enable().iocon().enable());
 | 
						||
}
 | 
						||
 | 
						||
/// The GPIO pin level for pins set on "Digital" mode.
 | 
						||
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
 | 
						||
pub enum Level {
 | 
						||
    /// Logical low. Corresponds to 0V.
 | 
						||
    Low,
 | 
						||
    /// Logical high. Corresponds to VDD.
 | 
						||
    High,
 | 
						||
}
 | 
						||
 | 
						||
/// Pull setting for a GPIO input set on "Digital" mode.
 | 
						||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
 | 
						||
pub enum Pull {
 | 
						||
    /// No pull.
 | 
						||
    None,
 | 
						||
    /// Internal pull-up resistor.
 | 
						||
    Up,
 | 
						||
    /// Internal pull-down resistor.
 | 
						||
    Down,
 | 
						||
}
 | 
						||
 | 
						||
/// The LPC55 boards have two GPIO banks, each with 32 pins. This enum represents the two banks.
 | 
						||
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
 | 
						||
pub enum Bank {
 | 
						||
    Bank0 = 0,
 | 
						||
    Bank1 = 1,
 | 
						||
}
 | 
						||
 | 
						||
/// GPIO output driver. Internally, this is a specialized [Flex] pin.
 | 
						||
pub struct Output<'d> {
 | 
						||
    pub(crate) pin: Flex<'d>,
 | 
						||
}
 | 
						||
 | 
						||
impl<'d> Output<'d> {
 | 
						||
    /// Create GPIO output driver for a [Pin] with the provided [initial output](Level).
 | 
						||
    #[inline]
 | 
						||
    pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level) -> Self {
 | 
						||
        let mut pin = Flex::new(pin);
 | 
						||
        pin.set_as_output();
 | 
						||
        let mut result = Self { pin };
 | 
						||
 | 
						||
        match initial_output {
 | 
						||
            Level::High => result.set_high(),
 | 
						||
            Level::Low => result.set_low(),
 | 
						||
        };
 | 
						||
 | 
						||
        result
 | 
						||
    }
 | 
						||
 | 
						||
    pub fn set_high(&mut self) {
 | 
						||
        gpio_reg().set[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) })
 | 
						||
    }
 | 
						||
 | 
						||
    pub fn set_low(&mut self) {
 | 
						||
        gpio_reg().clr[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) })
 | 
						||
    }
 | 
						||
 | 
						||
    pub fn toggle(&mut self) {
 | 
						||
        gpio_reg().not[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) })
 | 
						||
    }
 | 
						||
 | 
						||
    /// Get the current output level of the pin. Note that the value returned by this function is
 | 
						||
    /// the voltage level reported by the pin, not the value set by the output driver.
 | 
						||
    pub fn level(&self) -> Level {
 | 
						||
        let bits = gpio_reg().pin[self.pin.pin_bank() as usize].read().bits();
 | 
						||
        if bits & self.pin.bit() != 0 {
 | 
						||
            Level::High
 | 
						||
        } else {
 | 
						||
            Level::Low
 | 
						||
        }
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
/// GPIO input driver. Internally, this is a specialized [Flex] pin.
 | 
						||
pub struct Input<'d> {
 | 
						||
    pub(crate) pin: Flex<'d>,
 | 
						||
}
 | 
						||
 | 
						||
impl<'d> Input<'d> {
 | 
						||
    /// Create GPIO output driver for a [Pin] with the provided [Pull].
 | 
						||
    #[inline]
 | 
						||
    pub fn new(pin: Peri<'d, impl Pin>, pull: Pull) -> Self {
 | 
						||
        let mut pin = Flex::new(pin);
 | 
						||
        pin.set_as_input();
 | 
						||
        let mut result = Self { pin };
 | 
						||
        result.set_pull(pull);
 | 
						||
 | 
						||
        result
 | 
						||
    }
 | 
						||
 | 
						||
    /// Set the pull configuration for the pin. To disable the pull, use [Pull::None].
 | 
						||
    pub fn set_pull(&mut self, pull: Pull) {
 | 
						||
        match_iocon!(register, iocon_reg(), self.pin.pin_bank(), self.pin.pin_number(), {
 | 
						||
            register.modify(|_, w| match pull {
 | 
						||
                Pull::None => w.mode().inactive(),
 | 
						||
                Pull::Up => w.mode().pull_up(),
 | 
						||
                Pull::Down => w.mode().pull_down(),
 | 
						||
            });
 | 
						||
        });
 | 
						||
    }
 | 
						||
 | 
						||
    /// Get the current input level of the pin.
 | 
						||
    pub fn read(&self) -> Level {
 | 
						||
        let bits = gpio_reg().pin[self.pin.pin_bank() as usize].read().bits();
 | 
						||
        if bits & self.pin.bit() != 0 {
 | 
						||
            Level::High
 | 
						||
        } else {
 | 
						||
            Level::Low
 | 
						||
        }
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
/// A flexible GPIO (digital mode) pin whose mode is not yet determined. Under the hood, this is a
 | 
						||
/// reference to a type-erased pin called ["AnyPin"](AnyPin).
 | 
						||
pub struct Flex<'d> {
 | 
						||
    pub(crate) pin: Peri<'d, AnyPin>,
 | 
						||
}
 | 
						||
 | 
						||
impl<'d> Flex<'d> {
 | 
						||
    /// Wrap the pin in a `Flex`.
 | 
						||
    ///
 | 
						||
    /// Note: you cannot assume that the pin will be in Digital mode after this call.
 | 
						||
    #[inline]
 | 
						||
    pub fn new(pin: Peri<'d, impl Pin>) -> Self {
 | 
						||
        Self { pin: pin.into() }
 | 
						||
    }
 | 
						||
 | 
						||
    /// Get the bank of this pin. See also [Bank].
 | 
						||
    ///
 | 
						||
    /// # Example
 | 
						||
    ///
 | 
						||
    /// ```
 | 
						||
    /// use embassy_nxp::gpio::{Bank, Flex};
 | 
						||
    ///
 | 
						||
    /// let p = embassy_nxp::init(Default::default());
 | 
						||
    /// let pin = Flex::new(p.PIO1_15);
 | 
						||
    ///
 | 
						||
    /// assert_eq!(pin.pin_bank(), Bank::Bank1);
 | 
						||
    /// ```
 | 
						||
    pub fn pin_bank(&self) -> Bank {
 | 
						||
        self.pin.pin_bank()
 | 
						||
    }
 | 
						||
 | 
						||
    /// Get the number of this pin within its bank. See also [Bank].
 | 
						||
    ///
 | 
						||
    /// # Example
 | 
						||
    ///
 | 
						||
    /// ```
 | 
						||
    /// use embassy_nxp::gpio::Flex;
 | 
						||
    ///
 | 
						||
    /// let p = embassy_nxp::init(Default::default());
 | 
						||
    /// let pin = Flex::new(p.PIO1_15);
 | 
						||
    ///
 | 
						||
    /// assert_eq!(pin.pin_number(), 15 as u8);
 | 
						||
    /// ```
 | 
						||
    pub fn pin_number(&self) -> u8 {
 | 
						||
        self.pin.pin_number()
 | 
						||
    }
 | 
						||
 | 
						||
    /// Get the bit mask for this pin. Useful for setting or clearing bits in a register. Note:
 | 
						||
    /// PIOx_0 is bit 0, PIOx_1 is bit 1, etc.
 | 
						||
    ///
 | 
						||
    /// # Example
 | 
						||
    ///
 | 
						||
    /// ```
 | 
						||
    /// use embassy_nxp::gpio::Flex;
 | 
						||
    ///
 | 
						||
    /// let p = embassy_nxp::init(Default::default());
 | 
						||
    /// let pin = Flex::new(p.PIO1_3);
 | 
						||
    ///
 | 
						||
    /// assert_eq!(pin.bit(), 0b0000_1000);
 | 
						||
    /// ```
 | 
						||
    pub fn bit(&self) -> u32 {
 | 
						||
        1 << self.pin.pin_number()
 | 
						||
    }
 | 
						||
 | 
						||
    /// Set the pin to digital mode. This is required for using a pin as a GPIO pin. The default
 | 
						||
    /// setting for pins is (usually) non-digital.
 | 
						||
    fn set_as_digital(&mut self) {
 | 
						||
        match_iocon!(register, iocon_reg(), self.pin_bank(), self.pin_number(), {
 | 
						||
            register.modify(|_, w| w.digimode().digital());
 | 
						||
        });
 | 
						||
    }
 | 
						||
 | 
						||
    /// Set the pin in output mode. This implies setting the pin to digital mode, which this
 | 
						||
    /// function handles itself.
 | 
						||
    pub fn set_as_output(&mut self) {
 | 
						||
        self.set_as_digital();
 | 
						||
        gpio_reg().dirset[self.pin.pin_bank() as usize].write(|w| unsafe { w.dirsetp().bits(self.bit()) })
 | 
						||
    }
 | 
						||
 | 
						||
    pub fn set_as_input(&mut self) {
 | 
						||
        self.set_as_digital();
 | 
						||
        gpio_reg().dirclr[self.pin.pin_bank() as usize].write(|w| unsafe { w.dirclrp().bits(self.bit()) })
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
/// Sealed trait for pins. This trait is sealed and cannot be implemented outside of this crate.
 | 
						||
pub(crate) trait SealedPin: Sized {
 | 
						||
    fn pin_bank(&self) -> Bank;
 | 
						||
    fn pin_number(&self) -> u8;
 | 
						||
}
 | 
						||
 | 
						||
/// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an
 | 
						||
/// [AnyPin]. By default, this trait is sealed and cannot be implemented outside of the
 | 
						||
/// `embassy-nxp` crate due to the [SealedPin] trait.
 | 
						||
#[allow(private_bounds)]
 | 
						||
pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static {
 | 
						||
    /// Returns the pin number within a bank
 | 
						||
    #[inline]
 | 
						||
    fn pin(&self) -> u8 {
 | 
						||
        self.pin_number()
 | 
						||
    }
 | 
						||
 | 
						||
    /// Returns the bank of this pin
 | 
						||
    #[inline]
 | 
						||
    fn bank(&self) -> Bank {
 | 
						||
        self.pin_bank()
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
/// Type-erased GPIO pin.
 | 
						||
pub struct AnyPin {
 | 
						||
    pin_bank: Bank,
 | 
						||
    pin_number: u8,
 | 
						||
}
 | 
						||
 | 
						||
impl AnyPin {
 | 
						||
    /// Unsafely create a new type-erased pin.
 | 
						||
    ///
 | 
						||
    /// # Safety
 | 
						||
    ///
 | 
						||
    /// You must ensure that you’re only using one instance of this type at a time.
 | 
						||
    pub unsafe fn steal(pin_bank: Bank, pin_number: u8) -> Peri<'static, Self> {
 | 
						||
        Peri::new_unchecked(Self { pin_bank, pin_number })
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
impl_peripheral!(AnyPin);
 | 
						||
 | 
						||
impl Pin for AnyPin {}
 | 
						||
impl SealedPin for AnyPin {
 | 
						||
    #[inline]
 | 
						||
    fn pin_bank(&self) -> Bank {
 | 
						||
        self.pin_bank
 | 
						||
    }
 | 
						||
 | 
						||
    #[inline]
 | 
						||
    fn pin_number(&self) -> u8 {
 | 
						||
        self.pin_number
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
macro_rules! impl_pin {
 | 
						||
    ($name:ident, $bank:expr, $pin_num:expr) => {
 | 
						||
        impl Pin for peripherals::$name {}
 | 
						||
        impl SealedPin for peripherals::$name {
 | 
						||
            #[inline]
 | 
						||
            fn pin_bank(&self) -> Bank {
 | 
						||
                $bank
 | 
						||
            }
 | 
						||
 | 
						||
            #[inline]
 | 
						||
            fn pin_number(&self) -> u8 {
 | 
						||
                $pin_num
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
        impl From<peripherals::$name> for crate::gpio::AnyPin {
 | 
						||
            fn from(val: peripherals::$name) -> Self {
 | 
						||
                Self {
 | 
						||
                    pin_bank: val.pin_bank(),
 | 
						||
                    pin_number: val.pin_number(),
 | 
						||
                }
 | 
						||
            }
 | 
						||
        }
 | 
						||
    };
 | 
						||
}
 | 
						||
 | 
						||
impl_pin!(PIO0_0, Bank::Bank0, 0);
 | 
						||
impl_pin!(PIO0_1, Bank::Bank0, 1);
 | 
						||
impl_pin!(PIO0_2, Bank::Bank0, 2);
 | 
						||
impl_pin!(PIO0_3, Bank::Bank0, 3);
 | 
						||
impl_pin!(PIO0_4, Bank::Bank0, 4);
 | 
						||
impl_pin!(PIO0_5, Bank::Bank0, 5);
 | 
						||
impl_pin!(PIO0_6, Bank::Bank0, 6);
 | 
						||
impl_pin!(PIO0_7, Bank::Bank0, 7);
 | 
						||
impl_pin!(PIO0_8, Bank::Bank0, 8);
 | 
						||
impl_pin!(PIO0_9, Bank::Bank0, 9);
 | 
						||
impl_pin!(PIO0_10, Bank::Bank0, 10);
 | 
						||
impl_pin!(PIO0_11, Bank::Bank0, 11);
 | 
						||
impl_pin!(PIO0_12, Bank::Bank0, 12);
 | 
						||
impl_pin!(PIO0_13, Bank::Bank0, 13);
 | 
						||
impl_pin!(PIO0_14, Bank::Bank0, 14);
 | 
						||
impl_pin!(PIO0_15, Bank::Bank0, 15);
 | 
						||
impl_pin!(PIO0_16, Bank::Bank0, 16);
 | 
						||
impl_pin!(PIO0_17, Bank::Bank0, 17);
 | 
						||
impl_pin!(PIO0_18, Bank::Bank0, 18);
 | 
						||
impl_pin!(PIO0_19, Bank::Bank0, 19);
 | 
						||
impl_pin!(PIO0_20, Bank::Bank0, 20);
 | 
						||
impl_pin!(PIO0_21, Bank::Bank0, 21);
 | 
						||
impl_pin!(PIO0_22, Bank::Bank0, 22);
 | 
						||
impl_pin!(PIO0_23, Bank::Bank0, 23);
 | 
						||
impl_pin!(PIO0_24, Bank::Bank0, 24);
 | 
						||
impl_pin!(PIO0_25, Bank::Bank0, 25);
 | 
						||
impl_pin!(PIO0_26, Bank::Bank0, 26);
 | 
						||
impl_pin!(PIO0_27, Bank::Bank0, 27);
 | 
						||
impl_pin!(PIO0_28, Bank::Bank0, 28);
 | 
						||
impl_pin!(PIO0_29, Bank::Bank0, 29);
 | 
						||
impl_pin!(PIO0_30, Bank::Bank0, 30);
 | 
						||
impl_pin!(PIO0_31, Bank::Bank0, 31);
 | 
						||
impl_pin!(PIO1_0, Bank::Bank1, 0);
 | 
						||
impl_pin!(PIO1_1, Bank::Bank1, 1);
 | 
						||
impl_pin!(PIO1_2, Bank::Bank1, 2);
 | 
						||
impl_pin!(PIO1_3, Bank::Bank1, 3);
 | 
						||
impl_pin!(PIO1_4, Bank::Bank1, 4);
 | 
						||
impl_pin!(PIO1_5, Bank::Bank1, 5);
 | 
						||
impl_pin!(PIO1_6, Bank::Bank1, 6);
 | 
						||
impl_pin!(PIO1_7, Bank::Bank1, 7);
 | 
						||
impl_pin!(PIO1_8, Bank::Bank1, 8);
 | 
						||
impl_pin!(PIO1_9, Bank::Bank1, 9);
 | 
						||
impl_pin!(PIO1_10, Bank::Bank1, 10);
 | 
						||
impl_pin!(PIO1_11, Bank::Bank1, 11);
 | 
						||
impl_pin!(PIO1_12, Bank::Bank1, 12);
 | 
						||
impl_pin!(PIO1_13, Bank::Bank1, 13);
 | 
						||
impl_pin!(PIO1_14, Bank::Bank1, 14);
 | 
						||
impl_pin!(PIO1_15, Bank::Bank1, 15);
 | 
						||
impl_pin!(PIO1_16, Bank::Bank1, 16);
 | 
						||
impl_pin!(PIO1_17, Bank::Bank1, 17);
 | 
						||
impl_pin!(PIO1_18, Bank::Bank1, 18);
 | 
						||
impl_pin!(PIO1_19, Bank::Bank1, 19);
 | 
						||
impl_pin!(PIO1_20, Bank::Bank1, 20);
 | 
						||
impl_pin!(PIO1_21, Bank::Bank1, 21);
 | 
						||
impl_pin!(PIO1_22, Bank::Bank1, 22);
 | 
						||
impl_pin!(PIO1_23, Bank::Bank1, 23);
 | 
						||
impl_pin!(PIO1_24, Bank::Bank1, 24);
 | 
						||
impl_pin!(PIO1_25, Bank::Bank1, 25);
 | 
						||
impl_pin!(PIO1_26, Bank::Bank1, 26);
 | 
						||
impl_pin!(PIO1_27, Bank::Bank1, 27);
 | 
						||
impl_pin!(PIO1_28, Bank::Bank1, 28);
 | 
						||
impl_pin!(PIO1_29, Bank::Bank1, 29);
 | 
						||
impl_pin!(PIO1_30, Bank::Bank1, 30);
 | 
						||
impl_pin!(PIO1_31, Bank::Bank1, 31);
 |