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 + 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 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);