use embassy_hal_internal::impl_peripheral; use crate::pac_utils::*; use crate::{peripherals, Peripheral, PeripheralRef}; 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: impl Peripheral
+ 'd, 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: impl Peripheral
+ 'd, 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: PeripheralRef<'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: impl Peripheral
+ 'd) -> Self { Self { pin: pin.into_ref().map_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: Peripheral
+ Into