From ffe3e5acae6c0038db4176dc7d031b57f865e07f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 18 Nov 2025 12:16:14 -0800 Subject: Correct gpio driver (#9) * Correct gpio driver Signed-off-by: Felipe Balbi * Simplify blinky example Make it look like every other HAL for consistency. While at that, also rename the example to match the name used by other HALs. Signed-off-by: Felipe Balbi * Add some documentation to GPIO driver Signed-off-by: Felipe Balbi * Enable GPIO clocks during HAL initialization Provide the user with working GPIO clocks. Signed-off-by: Felipe Balbi --------- Signed-off-by: Felipe Balbi Co-authored-by: Felipe Balbi --- Cargo.toml | 2 +- examples/src/bin/adc_interrupt.rs | 6 +- examples/src/bin/adc_polling.rs | 6 +- examples/src/bin/blink.rs | 81 ------ examples/src/bin/blinky.rs | 49 ++++ examples/src/bin/hello.rs | 6 +- examples/src/bin/lpuart_buffered.rs | 4 +- examples/src/bin/lpuart_polling.rs | 6 +- examples/src/bin/ostimer_alarm.rs | 6 +- examples/src/bin/ostimer_async.rs | 6 +- examples/src/bin/ostimer_counter.rs | 6 +- examples/src/bin/ostimer_race_test.rs | 6 +- examples/src/bin/rtc_alarm.rs | 6 +- examples/src/lib.rs | 6 - src/clocks/mod.rs | 7 + src/gpio.rs | 480 +++++++++++++++++++++++++++++----- src/lib.rs | 315 +++++++++++++++++++++- src/lpuart/mod.rs | 14 +- 18 files changed, 827 insertions(+), 185 deletions(-) delete mode 100644 examples/src/bin/blink.rs create mode 100644 examples/src/bin/blinky.rs diff --git a/Cargo.toml b/Cargo.toml index 841ce1903..60f836ac3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ embassy-hal-internal = { version = "0.3.0", features = ["cortex-m", "prio-bits-3 embassy-sync = "0.7.2" embassy-time = "0.5.0" embassy-time-driver = "0.2.1" -embedded-hal = { package = "embedded-hal", version = "1.0" } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-async = { version = "1.0" } embedded-hal-nb = { version = "1.0" } diff --git a/examples/src/bin/adc_interrupt.rs b/examples/src/bin/adc_interrupt.rs index 6812ba5d3..9fed052fd 100644 --- a/examples/src/bin/adc_interrupt.rs +++ b/examples/src/bin/adc_interrupt.rs @@ -34,14 +34,14 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { embassy_mcxa_examples::init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/bin/adc_polling.rs b/examples/src/bin/adc_polling.rs index 421306e9b..545f8f77a 100644 --- a/examples/src/bin/adc_polling.rs +++ b/examples/src/bin/adc_polling.rs @@ -34,14 +34,14 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/bin/blink.rs b/examples/src/bin/blink.rs deleted file mode 100644 index d8b158d50..000000000 --- a/examples/src/bin/blink.rs +++ /dev/null @@ -1,81 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa as hal; -use embassy_mcxa::bind_interrupts; -use embassy_mcxa_examples::init_led_gpio_clocks; -use embassy_time::{Duration, Timer}; -use hal::gpio::pins::PIO3_18; -use hal::gpio::{Level, Output}; - -// Bind only OS_EVENT for timer interrupts -bind_interrupts!(struct Irqs { - OS_EVENT => hal::ostimer::time_driver::OsEventHandler; -}); - -#[used] -#[no_mangle] -static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let _p = hal::init(hal::config::Config::default()); - - unsafe { - init_led_gpio_clocks(hal::pac()); - } - - defmt::info!("Blink example"); - - // Initialize embassy-time global driver backed by OSTIMER0 - hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); - - // Configure LED pin for GPIO mode - PIO3_18::set_mux_gpio(); - - let mut led = Output::new(PIO3_18::degrade(), Level::High); - - // Complex blinking pattern: SOS in Morse code - // S: ... (3 short) - // O: --- (3 long) - // S: ... (3 short) - // With pauses between letters and words - - loop { - defmt::info!("SOS"); - - // S: three short blinks - for _ in 0..3 { - led.set_low(); - Timer::after(Duration::from_millis(150)).await; - led.set_high(); - Timer::after(Duration::from_millis(150)).await; - } - - // Pause between letters - Timer::after(Duration::from_millis(300)).await; - - // O: three long blinks - for _ in 0..3 { - led.set_low(); - Timer::after(Duration::from_millis(450)).await; - led.set_high(); - Timer::after(Duration::from_millis(150)).await; - } - - // Pause between letters - Timer::after(Duration::from_millis(300)).await; - - // S: three short blinks - for _ in 0..3 { - led.set_low(); - Timer::after(Duration::from_millis(150)).await; - led.set_high(); - Timer::after(Duration::from_millis(150)).await; - } - - // Long pause between words (SOS repeats) - Timer::after(Duration::from_millis(1000)).await; - } -} diff --git a/examples/src/bin/blinky.rs b/examples/src/bin/blinky.rs new file mode 100644 index 000000000..28d83a12e --- /dev/null +++ b/examples/src/bin/blinky.rs @@ -0,0 +1,49 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::bind_interrupts; +use embassy_time::Timer; +use hal::gpio::{Level, Output}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind only OS_EVENT for timer interrupts +bind_interrupts!(struct Irqs { + OS_EVENT => hal::ostimer::time_driver::OsEventHandler; +}); + +#[used] +#[no_mangle] +static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + defmt::info!("Blink example"); + + // Initialize embassy-time global driver backed by OSTIMER0 + hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); + + let mut red = Output::new(p.P3_18, Level::High); + let mut green = Output::new(p.P3_19, Level::High); + let mut blue = Output::new(p.P3_21, Level::High); + + loop { + defmt::info!("Toggle LEDs"); + + red.toggle(); + Timer::after_millis(250).await; + + red.toggle(); + green.toggle(); + Timer::after_millis(250).await; + + green.toggle(); + blue.toggle(); + Timer::after_millis(250).await; + blue.toggle(); + + Timer::after_millis(250).await; + } +} diff --git a/examples/src/bin/hello.rs b/examples/src/bin/hello.rs index 207c157c3..e2d0b413d 100644 --- a/examples/src/bin/hello.rs +++ b/examples/src/bin/hello.rs @@ -26,14 +26,14 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { embassy_mcxa_examples::init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/bin/lpuart_buffered.rs b/examples/src/bin/lpuart_buffered.rs index 642d4af65..b0d19ef16 100644 --- a/examples/src/bin/lpuart_buffered.rs +++ b/examples/src/bin/lpuart_buffered.rs @@ -51,8 +51,8 @@ async fn main(_spawner: Spawner) { // Create a buffered LPUART2 instance with both TX and RX let mut uart = BufferedLpuart::new( p.LPUART2, - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin Irqs, &mut tx_buf, &mut rx_buf, diff --git a/examples/src/bin/lpuart_polling.rs b/examples/src/bin/lpuart_polling.rs index bea82c33e..525d42e2c 100644 --- a/examples/src/bin/lpuart_polling.rs +++ b/examples/src/bin/lpuart_polling.rs @@ -26,11 +26,11 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX let lpuart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/bin/ostimer_alarm.rs b/examples/src/bin/ostimer_alarm.rs index 03fb93319..6d38741b7 100644 --- a/examples/src/bin/ostimer_alarm.rs +++ b/examples/src/bin/ostimer_alarm.rs @@ -40,14 +40,14 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/bin/ostimer_async.rs b/examples/src/bin/ostimer_async.rs index 881f09374..f043184e7 100644 --- a/examples/src/bin/ostimer_async.rs +++ b/examples/src/bin/ostimer_async.rs @@ -29,14 +29,14 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/bin/ostimer_counter.rs b/examples/src/bin/ostimer_counter.rs index 2fbc251b9..f36915ff2 100644 --- a/examples/src/bin/ostimer_counter.rs +++ b/examples/src/bin/ostimer_counter.rs @@ -30,14 +30,14 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { embassy_mcxa_examples::init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/bin/ostimer_race_test.rs b/examples/src/bin/ostimer_race_test.rs index 168a952cd..0106b92a7 100644 --- a/examples/src/bin/ostimer_race_test.rs +++ b/examples/src/bin/ostimer_race_test.rs @@ -80,14 +80,14 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { embassy_mcxa_examples::init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/bin/rtc_alarm.rs b/examples/src/bin/rtc_alarm.rs index 40a1207df..a54b4a817 100644 --- a/examples/src/bin/rtc_alarm.rs +++ b/examples/src/bin/rtc_alarm.rs @@ -32,14 +32,14 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { embassy_mcxa_examples::init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/lib.rs b/examples/src/lib.rs index 4bb334da5..66b93450a 100644 --- a/examples/src/lib.rs +++ b/examples/src/lib.rs @@ -16,12 +16,6 @@ pub unsafe fn init_uart2_pins(_p: &hal::pac::Peripherals) { pins::configure_uart2_pins_port2(); } -/// Initialize clocks for the LED GPIO/PORT used by the blink example. -pub unsafe fn init_led_gpio_clocks(_p: &hal::pac::Peripherals) { - _ = clocks::enable_and_reset::(&clocks::periph_helpers::NoConfig); - _ = clocks::enable_and_reset::(&clocks::periph_helpers::NoConfig); -} - /// Initialize clocks and pin muxing for ADC. pub unsafe fn init_adc_pins(_p: &hal::pac::Peripherals) { // NOTE: Lpuart has been updated to properly enable + reset its own clocks. diff --git a/src/clocks/mod.rs b/src/clocks/mod.rs index e02840592..558fb0278 100644 --- a/src/clocks/mod.rs +++ b/src/clocks/mod.rs @@ -874,10 +874,17 @@ pub(crate) mod gate { // other than enabling through the MRCC gate. Currently, these peripherals will // ALWAYS return `Ok(0)` when calling [`enable_and_reset()`] and/or // [`SPConfHelper::post_enable_config()`]. + impl_cc_gate!(PORT0, mrcc_glb_cc1, mrcc_glb_rst1, port0, NoConfig); impl_cc_gate!(PORT1, mrcc_glb_cc1, mrcc_glb_rst1, port1, NoConfig); impl_cc_gate!(PORT2, mrcc_glb_cc1, mrcc_glb_rst1, port2, NoConfig); impl_cc_gate!(PORT3, mrcc_glb_cc1, mrcc_glb_rst1, port3, NoConfig); + impl_cc_gate!(PORT4, mrcc_glb_cc1, mrcc_glb_rst1, port4, NoConfig); + + impl_cc_gate!(GPIO0, mrcc_glb_cc2, mrcc_glb_rst2, gpio0, NoConfig); + impl_cc_gate!(GPIO1, mrcc_glb_cc2, mrcc_glb_rst2, gpio1, NoConfig); + impl_cc_gate!(GPIO2, mrcc_glb_cc2, mrcc_glb_rst2, gpio2, NoConfig); impl_cc_gate!(GPIO3, mrcc_glb_cc2, mrcc_glb_rst2, gpio3, NoConfig); + impl_cc_gate!(GPIO4, mrcc_glb_cc2, mrcc_glb_rst2, gpio4, NoConfig); // These peripherals DO have meaningful configuration, and could fail if the system // clocks do not match their needs. diff --git a/src/gpio.rs b/src/gpio.rs index 1e7214b28..09a414d3b 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -2,9 +2,11 @@ //! The exported `Output`/`Input` drivers own a `Flex` so they no longer depend on the //! concrete pin type. +use core::convert::Infallible; use core::marker::PhantomData; -use crate::{pac, pins as pin_config}; +use embassy_hal_internal::{Peri, PeripheralType}; +use paste::paste; /// Logical level for GPIO pins. #[derive(Copy, Clone, Eq, PartialEq, Debug)] @@ -13,140 +15,350 @@ pub enum Level { High, } -pub type Gpio = crate::peripherals::GPIO; +pub type Gpio = crate::peripherals::GPIO0; /// Type-erased representation of a GPIO pin. -#[derive(Copy, Clone)] pub struct AnyPin { - port: u8, - pin: u8, - gpio: *const pac::gpio0::RegisterBlock, + port: usize, + pin: usize, + gpio: &'static crate::pac::gpio0::RegisterBlock, } impl AnyPin { /// Create an `AnyPin` from raw components. - pub fn new(port: u8, pin: u8, gpio: *const pac::gpio0::RegisterBlock) -> Self { + pub fn new(port: usize, pin: usize, gpio: &'static crate::pac::gpio0::RegisterBlock) -> Self { Self { port, pin, gpio } } #[inline(always)] fn mask(&self) -> u32 { - 1u32 << self.pin + 1 << self.pin } #[inline(always)] - fn gpio(&self) -> &'static pac::gpio0::RegisterBlock { - unsafe { &*self.gpio } + fn gpio(&self) -> &'static crate::pac::gpio0::RegisterBlock { + self.gpio } #[inline(always)] - pub fn port_index(&self) -> u8 { + pub fn port_index(&self) -> usize { self.port } #[inline(always)] - pub fn pin_index(&self) -> u8 { + pub fn pin_index(&self) -> usize { self.pin } } -/// Type-level trait implemented by concrete pin ZSTs. -pub trait PinId { - fn port_index() -> u8; - fn pin_index() -> u8; - fn gpio_ptr() -> *const pac::gpio0::RegisterBlock; +embassy_hal_internal::impl_peripheral!(AnyPin); - fn set_mux_gpio() { - unsafe { pin_config::set_pin_mux_gpio(Self::port_index(), Self::pin_index()) } +trait SealedPin { + fn pin_port(&self) -> usize; + + fn port(&self) -> usize { + self.pin_port() / 32 } - fn degrade() -> AnyPin { - AnyPin::new(Self::port_index(), Self::pin_index(), Self::gpio_ptr()) + fn pin(&self) -> usize { + self.pin_port() % 32 } + + fn gpio(&self) -> &'static crate::pac::gpio0::RegisterBlock; } -pub mod pins { - use super::{pac, AnyPin, PinId}; +/// GPIO pin trait. +#[allow(private_bounds)] +pub trait GpioPin: SealedPin + Sized + PeripheralType + Into + 'static { + /// Type-erase the pin. + fn degrade(self) -> AnyPin { + // SAFETY: This is only called within the GpioPin trait, which is only + // implemented within this module on valid pin peripherals and thus + // has been verified to be correct. + AnyPin::new(self.port(), self.pin(), self.gpio()) + } +} - macro_rules! define_pin { - ($Name:ident, $port:literal, $pin:literal, $GpioBlk:ident) => { - pub struct $Name; - impl super::PinId for $Name { - #[inline(always)] - fn port_index() -> u8 { - $port - } - #[inline(always)] - fn pin_index() -> u8 { - $pin - } - #[inline(always)] - fn gpio_ptr() -> *const pac::gpio0::RegisterBlock { - pac::$GpioBlk::ptr() - } +impl SealedPin for AnyPin { + #[inline] + fn pin_port(&self) -> usize { + self.port * 32 + self.pin + } + + #[inline] + fn gpio(&self) -> &'static crate::pac::gpio0::RegisterBlock { + self.gpio() + } +} + +impl GpioPin for AnyPin {} + +macro_rules! impl_pin { + ($peri:ident, $port:expr, $pin:expr, $block:ident) => { + impl SealedPin for crate::peripherals::$peri { + #[inline] + fn pin_port(&self) -> usize { + $port * 32 + $pin } - impl $Name { - /// Convenience helper to obtain a type-erased handle to this pin. - pub fn degrade() -> AnyPin { - ::degrade() - } + #[inline] + fn gpio(&self) -> &'static crate::pac::gpio0::RegisterBlock { + unsafe { &*crate::pac::$block::ptr() } + } + } - pub fn set_mux_gpio() { - ::set_mux_gpio() - } + impl GpioPin for crate::peripherals::$peri {} + + impl From for AnyPin { + fn from(value: crate::peripherals::$peri) -> Self { + value.degrade() } - }; - } + } - // Extend this list as more pins are needed. - define_pin!(PIO3_18, 3, 18, Gpio3); + impl crate::peripherals::$peri { + /// Convenience helper to obtain a type-erased handle to this pin. + pub fn degrade(&self) -> AnyPin { + AnyPin::new(self.port(), self.pin(), self.gpio()) + } + + #[inline] + pub fn set_mux_gpio() { + paste! { + let port = unsafe { crate::pac::[]::steal()}; + port.[]().write(|w| w.mux().mux00()); + } + } + } + }; } +impl_pin!(P0_0, 0, 0, Gpio0); +impl_pin!(P0_1, 0, 1, Gpio0); +impl_pin!(P0_2, 0, 2, Gpio0); +impl_pin!(P0_3, 0, 3, Gpio0); +impl_pin!(P0_4, 0, 4, Gpio0); +impl_pin!(P0_5, 0, 5, Gpio0); +impl_pin!(P0_6, 0, 6, Gpio0); +impl_pin!(P0_7, 0, 7, Gpio0); +impl_pin!(P0_8, 0, 8, Gpio0); +impl_pin!(P0_9, 0, 9, Gpio0); +impl_pin!(P0_10, 0, 10, Gpio0); +impl_pin!(P0_11, 0, 11, Gpio0); +impl_pin!(P0_12, 0, 12, Gpio0); +impl_pin!(P0_13, 0, 13, Gpio0); +impl_pin!(P0_14, 0, 14, Gpio0); +impl_pin!(P0_15, 0, 15, Gpio0); +impl_pin!(P0_16, 0, 16, Gpio0); +impl_pin!(P0_17, 0, 17, Gpio0); +impl_pin!(P0_18, 0, 18, Gpio0); +impl_pin!(P0_19, 0, 19, Gpio0); +impl_pin!(P0_20, 0, 20, Gpio0); +impl_pin!(P0_21, 0, 21, Gpio0); +impl_pin!(P0_22, 0, 22, Gpio0); +impl_pin!(P0_23, 0, 23, Gpio0); +impl_pin!(P0_24, 0, 24, Gpio0); +impl_pin!(P0_25, 0, 25, Gpio0); +impl_pin!(P0_26, 0, 26, Gpio0); +impl_pin!(P0_27, 0, 27, Gpio0); +impl_pin!(P0_28, 0, 28, Gpio0); +impl_pin!(P0_29, 0, 29, Gpio0); +impl_pin!(P0_30, 0, 30, Gpio0); +impl_pin!(P0_31, 0, 31, Gpio0); + +impl_pin!(P1_0, 1, 0, Gpio1); +impl_pin!(P1_1, 1, 1, Gpio1); +impl_pin!(P1_2, 1, 2, Gpio1); +impl_pin!(P1_3, 1, 3, Gpio1); +impl_pin!(P1_4, 1, 4, Gpio1); +impl_pin!(P1_5, 1, 5, Gpio1); +impl_pin!(P1_6, 1, 6, Gpio1); +impl_pin!(P1_7, 1, 7, Gpio1); +impl_pin!(P1_8, 1, 8, Gpio1); +impl_pin!(P1_9, 1, 9, Gpio1); +impl_pin!(P1_10, 1, 10, Gpio1); +impl_pin!(P1_11, 1, 11, Gpio1); +impl_pin!(P1_12, 1, 12, Gpio1); +impl_pin!(P1_13, 1, 13, Gpio1); +impl_pin!(P1_14, 1, 14, Gpio1); +impl_pin!(P1_15, 1, 15, Gpio1); +impl_pin!(P1_16, 1, 16, Gpio1); +impl_pin!(P1_17, 1, 17, Gpio1); +impl_pin!(P1_18, 1, 18, Gpio1); +impl_pin!(P1_19, 1, 19, Gpio1); +impl_pin!(P1_20, 1, 20, Gpio1); +impl_pin!(P1_21, 1, 21, Gpio1); +impl_pin!(P1_22, 1, 22, Gpio1); +impl_pin!(P1_23, 1, 23, Gpio1); +impl_pin!(P1_24, 1, 24, Gpio1); +impl_pin!(P1_25, 1, 25, Gpio1); +impl_pin!(P1_26, 1, 26, Gpio1); +impl_pin!(P1_27, 1, 27, Gpio1); +impl_pin!(P1_28, 1, 28, Gpio1); +impl_pin!(P1_29, 1, 29, Gpio1); +impl_pin!(P1_30, 1, 30, Gpio1); +impl_pin!(P1_31, 1, 31, Gpio1); + +impl_pin!(P2_0, 2, 0, Gpio2); +impl_pin!(P2_1, 2, 1, Gpio2); +impl_pin!(P2_2, 2, 2, Gpio2); +impl_pin!(P2_3, 2, 3, Gpio2); +impl_pin!(P2_4, 2, 4, Gpio2); +impl_pin!(P2_5, 2, 5, Gpio2); +impl_pin!(P2_6, 2, 6, Gpio2); +impl_pin!(P2_7, 2, 7, Gpio2); +impl_pin!(P2_8, 2, 8, Gpio2); +impl_pin!(P2_9, 2, 9, Gpio2); +impl_pin!(P2_10, 2, 10, Gpio2); +impl_pin!(P2_11, 2, 11, Gpio2); +impl_pin!(P2_12, 2, 12, Gpio2); +impl_pin!(P2_13, 2, 13, Gpio2); +impl_pin!(P2_14, 2, 14, Gpio2); +impl_pin!(P2_15, 2, 15, Gpio2); +impl_pin!(P2_16, 2, 16, Gpio2); +impl_pin!(P2_17, 2, 17, Gpio2); +impl_pin!(P2_18, 2, 18, Gpio2); +impl_pin!(P2_19, 2, 19, Gpio2); +impl_pin!(P2_20, 2, 20, Gpio2); +impl_pin!(P2_21, 2, 21, Gpio2); +impl_pin!(P2_22, 2, 22, Gpio2); +impl_pin!(P2_23, 2, 23, Gpio2); +impl_pin!(P2_24, 2, 24, Gpio2); +impl_pin!(P2_25, 2, 25, Gpio2); +impl_pin!(P2_26, 2, 26, Gpio2); +impl_pin!(P2_27, 2, 27, Gpio2); +impl_pin!(P2_28, 2, 28, Gpio2); +impl_pin!(P2_29, 2, 29, Gpio2); +impl_pin!(P2_30, 2, 30, Gpio2); +impl_pin!(P2_31, 2, 31, Gpio2); + +impl_pin!(P3_0, 3, 0, Gpio3); +impl_pin!(P3_1, 3, 1, Gpio3); +impl_pin!(P3_2, 3, 2, Gpio3); +impl_pin!(P3_3, 3, 3, Gpio3); +impl_pin!(P3_4, 3, 4, Gpio3); +impl_pin!(P3_5, 3, 5, Gpio3); +impl_pin!(P3_6, 3, 6, Gpio3); +impl_pin!(P3_7, 3, 7, Gpio3); +impl_pin!(P3_8, 3, 8, Gpio3); +impl_pin!(P3_9, 3, 9, Gpio3); +impl_pin!(P3_10, 3, 10, Gpio3); +impl_pin!(P3_11, 3, 11, Gpio3); +impl_pin!(P3_12, 3, 12, Gpio3); +impl_pin!(P3_13, 3, 13, Gpio3); +impl_pin!(P3_14, 3, 14, Gpio3); +impl_pin!(P3_15, 3, 15, Gpio3); +impl_pin!(P3_16, 3, 16, Gpio3); +impl_pin!(P3_17, 3, 17, Gpio3); +impl_pin!(P3_18, 3, 18, Gpio3); +impl_pin!(P3_19, 3, 19, Gpio3); +impl_pin!(P3_20, 3, 20, Gpio3); +impl_pin!(P3_21, 3, 21, Gpio3); +impl_pin!(P3_22, 3, 22, Gpio3); +impl_pin!(P3_23, 3, 23, Gpio3); +impl_pin!(P3_24, 3, 24, Gpio3); +impl_pin!(P3_25, 3, 25, Gpio3); +impl_pin!(P3_26, 3, 26, Gpio3); +impl_pin!(P3_27, 3, 27, Gpio3); +impl_pin!(P3_28, 3, 28, Gpio3); +impl_pin!(P3_29, 3, 29, Gpio3); +impl_pin!(P3_30, 3, 30, Gpio3); +impl_pin!(P3_31, 3, 31, Gpio3); + +impl_pin!(P4_0, 4, 0, Gpio4); +impl_pin!(P4_1, 4, 1, Gpio4); +impl_pin!(P4_2, 4, 2, Gpio4); +impl_pin!(P4_3, 4, 3, Gpio4); +impl_pin!(P4_4, 4, 4, Gpio4); +impl_pin!(P4_5, 4, 5, Gpio4); +impl_pin!(P4_6, 4, 6, Gpio4); +impl_pin!(P4_7, 4, 7, Gpio4); +impl_pin!(P4_8, 4, 8, Gpio4); +impl_pin!(P4_9, 4, 9, Gpio4); +impl_pin!(P4_10, 4, 10, Gpio4); +impl_pin!(P4_11, 4, 11, Gpio4); +impl_pin!(P4_12, 4, 12, Gpio4); +impl_pin!(P4_13, 4, 13, Gpio4); +impl_pin!(P4_14, 4, 14, Gpio4); +impl_pin!(P4_15, 4, 15, Gpio4); +impl_pin!(P4_16, 4, 16, Gpio4); +impl_pin!(P4_17, 4, 17, Gpio4); +impl_pin!(P4_18, 4, 18, Gpio4); +impl_pin!(P4_19, 4, 19, Gpio4); +impl_pin!(P4_20, 4, 20, Gpio4); +impl_pin!(P4_21, 4, 21, Gpio4); +impl_pin!(P4_22, 4, 22, Gpio4); +impl_pin!(P4_23, 4, 23, Gpio4); +impl_pin!(P4_24, 4, 24, Gpio4); +impl_pin!(P4_25, 4, 25, Gpio4); +impl_pin!(P4_26, 4, 26, Gpio4); +impl_pin!(P4_27, 4, 27, Gpio4); +impl_pin!(P4_28, 4, 28, Gpio4); +impl_pin!(P4_29, 4, 29, Gpio4); +impl_pin!(P4_30, 4, 30, Gpio4); +impl_pin!(P4_31, 4, 31, Gpio4); + /// A flexible pin that can be configured as input or output. pub struct Flex<'d> { - pin: AnyPin, + pin: Peri<'d, AnyPin>, _marker: PhantomData<&'d mut ()>, } impl<'d> Flex<'d> { - pub fn new(pin: AnyPin) -> Self { + /// Wrap the pin in a `Flex`. + /// + /// The pin remains unmodified. The initial output level is unspecified, but + /// can be changed before the pin is put into output mode. + pub fn new(pin: Peri<'d, impl GpioPin>) -> Self { Self { - pin, + pin: pin.into(), _marker: PhantomData, } } - #[inline(always)] - fn gpio(&self) -> &'static pac::gpio0::RegisterBlock { + #[inline] + fn gpio(&self) -> &'static crate::pac::gpio0::RegisterBlock { self.pin.gpio() } - #[inline(always)] + #[inline] fn mask(&self) -> u32 { self.pin.mask() } + /// Put the pin into input mode. + /// + /// The pull setting is left unchanged. + #[inline] pub fn set_as_input(&mut self) { let mask = self.mask(); let gpio = self.gpio(); gpio.pddr().modify(|r, w| unsafe { w.bits(r.bits() & !mask) }); } + /// Put the pin into output mode. + /// + /// The initial output level is left unchanged. + #[inline] pub fn set_as_output(&mut self) { let mask = self.mask(); let gpio = self.gpio(); gpio.pddr().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); } + /// Set output level to High. + #[inline] pub fn set_high(&mut self) { self.gpio().psor().write(|w| unsafe { w.bits(self.mask()) }); } + /// Set output level to Low. + #[inline] pub fn set_low(&mut self) { self.gpio().pcor().write(|w| unsafe { w.bits(self.mask()) }); } + /// Set output level to the given `Level`. + #[inline] pub fn set_level(&mut self, level: Level) { match level { Level::High => self.set_high(), @@ -154,17 +366,35 @@ impl<'d> Flex<'d> { } } + /// Toggle output level. + #[inline] pub fn toggle(&mut self) { self.gpio().ptor().write(|w| unsafe { w.bits(self.mask()) }); } + /// Get whether the pin input level is high. + #[inline] pub fn is_high(&self) -> bool { (self.gpio().pdir().read().bits() & self.mask()) != 0 } + /// Get whether the pin input level is low. + #[inline] pub fn is_low(&self) -> bool { !self.is_high() } + + /// Is the output pin set as high? + #[inline] + pub fn is_set_high(&self) -> bool { + self.is_high() + } + + /// Is the output pin set as low? + #[inline] + pub fn is_set_low(&self) -> bool { + !self.is_set_high() + } } /// GPIO output driver that owns a `Flex` pin. @@ -173,44 +403,52 @@ pub struct Output<'d> { } impl<'d> Output<'d> { - pub fn new(pin: AnyPin, initial: Level) -> Self { + /// Create a GPIO output driver for a [GpioPin] with the provided [Level]. + pub fn new(pin: Peri<'d, impl GpioPin>, initial: Level) -> Self { let mut flex = Flex::new(pin); flex.set_level(initial); flex.set_as_output(); Self { flex } } + /// Set the output as high. #[inline] pub fn set_high(&mut self) { self.flex.set_high(); } + /// Set the output as low. #[inline] pub fn set_low(&mut self) { self.flex.set_low(); } + /// Set the output level. #[inline] pub fn set_level(&mut self, level: Level) { self.flex.set_level(level); } + /// Toggle the output level. #[inline] pub fn toggle(&mut self) { self.flex.toggle(); } + /// Is the output pin set as high? #[inline] pub fn is_set_high(&self) -> bool { self.flex.is_high() } + /// Is the output pin set as low? #[inline] pub fn is_set_low(&self) -> bool { !self.is_set_high() } /// Expose the inner `Flex` if callers need to reconfigure the pin. + #[inline] pub fn into_flex(self) -> Flex<'d> { self.flex } @@ -222,23 +460,147 @@ pub struct Input<'d> { } impl<'d> Input<'d> { - pub fn new(pin: AnyPin) -> Self { + /// Create a GPIO input driver for a [GpioPin]. + pub fn new(pin: Peri<'d, impl GpioPin>) -> Self { let mut flex = Flex::new(pin); flex.set_as_input(); Self { flex } } + /// Get whether the pin input level is high. #[inline] pub fn is_high(&self) -> bool { self.flex.is_high() } + /// Get whether the pin input level is low. #[inline] pub fn is_low(&self) -> bool { self.flex.is_low() } + /// Expose the inner `Flex` if callers need to reconfigure the pin. + #[inline] pub fn into_flex(self) -> Flex<'d> { self.flex } } + +// Both embedded_hal 0.2 and 1.0 must be supported by embassy HALs. +impl embedded_hal_02::digital::v2::InputPin for Flex<'_> { + // GPIO operations on this block cannot fail, therefor we set the error type + // to Infallible to guarantee that we can only produce Ok variants. + type Error = Infallible; + + #[inline] + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + #[inline] + fn is_low(&self) -> Result { + Ok(self.is_low()) + } +} + +impl embedded_hal_02::digital::v2::InputPin for Input<'_> { + type Error = Infallible; + + #[inline] + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + #[inline] + fn is_low(&self) -> Result { + Ok(self.is_low()) + } +} + +impl embedded_hal_02::digital::v2::OutputPin for Flex<'_> { + type Error = Infallible; + + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high(); + Ok(()) + } + + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low(); + Ok(()) + } +} + +impl embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'_> { + #[inline] + fn is_set_high(&self) -> Result { + Ok(self.is_set_high()) + } + + #[inline] + fn is_set_low(&self) -> Result { + Ok(self.is_set_low()) + } +} + +impl embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'_> { + type Error = Infallible; + + #[inline] + fn toggle(&mut self) -> Result<(), Self::Error> { + self.toggle(); + Ok(()) + } +} + +impl embedded_hal_1::digital::ErrorType for Flex<'_> { + type Error = Infallible; +} + +impl embedded_hal_1::digital::ErrorType for Input<'_> { + type Error = Infallible; +} + +impl embedded_hal_1::digital::ErrorType for Output<'_> { + type Error = Infallible; +} + +impl embedded_hal_1::digital::InputPin for Input<'_> { + #[inline] + fn is_high(&mut self) -> Result { + Ok((*self).is_high()) + } + + #[inline] + fn is_low(&mut self) -> Result { + Ok((*self).is_low()) + } +} + +impl embedded_hal_1::digital::OutputPin for Flex<'_> { + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high(); + Ok(()) + } + + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low(); + Ok(()) + } +} + +impl embedded_hal_1::digital::StatefulOutputPin for Flex<'_> { + #[inline] + fn is_set_high(&mut self) -> Result { + Ok((*self).is_set_high()) + } + + #[inline] + fn is_set_low(&mut self) -> Result { + Ok((*self).is_set_low()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 86c0dc45b..c885ecc50 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,301 @@ pub mod lpuart; pub mod ostimer; pub mod rtc; -embassy_hal_internal::peripherals!(PORT1, PORT2, PORT3, LPUART2, OSTIMER0, GPIO, PIO2_2, PIO2_3, GPIO3, RTC0, ADC1,); +#[rustfmt::skip] +embassy_hal_internal::peripherals!( + ADC0, + ADC1, + + AOI0, + AOI1, + + CAN0, + CAN1, + + CDOG0, + CDOG1, + + CMC, + CMP0, + CMP1, + CRC0, + + CTIMER0, + CTIMER1, + CTIMER2, + CTIMER3, + CTIMER4, + + DBGMAILBOX, + DMA0, + EDMA0_TCD0, + EIM0, + EQDC0, + EQDC1, + ERM0, + FLEXIO0, + FLEXPWM0, + FLEXPWM1, + FMC0, + FMU0, + FREQME0, + GLIKEY0, + + GPIO0, + GPIO1, + GPIO2, + GPIO3, + GPIO4, + + I3C0, + INPUTMUX0, + + LPI2C0, + LPI2C1, + LPI2C2, + LPI2C3, + + LPSPI0, + LPSPI1, + + LPTMR0, + + LPUART0, + LPUART1, + LPUART2, + LPUART3, + LPUART4, + + MAU0, + MBC0, + MRCC0, + OPAMP0, + OSTIMER0, + + P0_0, + P0_1, + P0_2, + P0_3, + P0_4, + P0_5, + P0_6, + P0_7, + P0_8, + P0_9, + P0_10, + P0_11, + P0_12, + P0_13, + P0_14, + P0_15, + P0_16, + P0_17, + P0_18, + P0_19, + P0_20, + P0_21, + P0_22, + P0_23, + P0_24, + P0_25, + P0_26, + P0_27, + P0_28, + P0_29, + P0_30, + P0_31, + + P1_0, + P1_1, + P1_2, + P1_3, + P1_4, + P1_5, + P1_6, + P1_7, + P1_8, + P1_9, + P1_10, + P1_11, + P1_12, + P1_13, + P1_14, + P1_15, + P1_16, + P1_17, + P1_18, + P1_19, + P1_20, + P1_21, + P1_22, + P1_23, + P1_24, + P1_25, + P1_26, + P1_27, + P1_28, + P1_29, + P1_30, + P1_31, + + P2_0, + P2_1, + P2_2, + P2_3, + P2_4, + P2_5, + P2_6, + P2_7, + P2_8, + P2_9, + P2_10, + P2_11, + P2_12, + P2_13, + P2_14, + P2_15, + P2_16, + P2_17, + P2_18, + P2_19, + P2_20, + P2_21, + P2_22, + P2_23, + P2_24, + P2_25, + P2_26, + P2_27, + P2_28, + P2_29, + P2_30, + P2_31, + + P3_0, + P3_1, + P3_2, + P3_3, + P3_4, + P3_5, + P3_6, + P3_7, + P3_8, + P3_9, + P3_10, + P3_11, + P3_12, + P3_13, + P3_14, + P3_15, + P3_16, + P3_17, + P3_18, + P3_19, + P3_20, + P3_21, + P3_22, + P3_23, + P3_24, + P3_25, + P3_26, + P3_27, + P3_28, + P3_29, + P3_30, + P3_31, + + P4_0, + P4_1, + P4_2, + P4_3, + P4_4, + P4_5, + P4_6, + P4_7, + P4_8, + P4_9, + P4_10, + P4_11, + P4_12, + P4_13, + P4_14, + P4_15, + P4_16, + P4_17, + P4_18, + P4_19, + P4_20, + P4_21, + P4_22, + P4_23, + P4_24, + P4_25, + P4_26, + P4_27, + P4_28, + P4_29, + P4_30, + P4_31, + + P5_0, + P5_1, + P5_2, + P5_3, + P5_4, + P5_5, + P5_6, + P5_7, + P5_8, + P5_9, + P5_10, + P5_11, + P5_12, + P5_13, + P5_14, + P5_15, + P5_16, + P5_17, + P5_18, + P5_19, + P5_20, + P5_21, + P5_22, + P5_23, + P5_24, + P5_25, + P5_26, + P5_27, + P5_28, + P5_29, + P5_30, + P5_31, + + PKC0, + + PORT0, + PORT1, + PORT2, + PORT3, + PORT4, + + RTC0, + SAU, + SCG0, + SCN_SCB, + SGI0, + SMARTDMA0, + SPC0, + SYSCON, + TDET0, + TRNG0, + UDF0, + USB0, + UTICK0, + VBAT0, + WAKETIMER0, + WUU0, + WWDT0, +); /// Get access to the PAC Peripherals for low-level register access. /// This is a lazy-initialized singleton that can be called after init(). @@ -35,7 +329,6 @@ pub fn pac() -> &'static pac::Peripherals { // Re-export interrupt traits and types pub use adc::Adc1 as Adc1Token; -pub use gpio::pins::*; pub use gpio::{AnyPin, Flex, Gpio as GpioToken, Input, Level, Output}; pub use interrupt::InterruptExt; #[cfg(feature = "unstable-pac")] @@ -59,6 +352,24 @@ pub fn init(cfg: crate::config::Config) -> Peripherals { // Configure clocks crate::clocks::init(cfg.clock_cfg).unwrap(); + // Enable GPIO clocks + unsafe { + _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); + _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); + + _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); + _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); + + _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); + _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); + + _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); + _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); + + _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); + _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); + } + peripherals } diff --git a/src/lpuart/mod.rs b/src/lpuart/mod.rs index b3d7c4885..f069f6567 100644 --- a/src/lpuart/mod.rs +++ b/src/lpuart/mod.rs @@ -53,7 +53,7 @@ mod gpio { } // Implement GpioPin for all pins from lib.rs - impl_gpio_pin!(PIO2_2, PIO2_3); + impl_gpio_pin!(P2_2, P2_3); #[derive(Debug, Clone, Copy)] pub struct AnyPin; @@ -433,12 +433,12 @@ macro_rules! impl_pin_trait { } // Document identifier: MCXA343/344 Rev. 1DraftB ReleaseCandidate, 2025-07-10 - 6.1 MCX A173, A174 Signal Multiplexing and Pin Assignments -// impl_pin_trait!(LPUART0, rx, PIO2_0, ALT2, PIO0_2, ALT2, PIO0_20, ALT3); -// impl_pin_trait!(LPUART0, tx, PIO2_1, ALT2, PIO0_3, ALT2, PIO0_21, ALT3); -// impl_pin_trait!(LPUART0, rts, PIO2_2, ALT2, PIO0_0, ALT2, PIO0_22, ALT3); -// impl_pin_trait!(LPUART0, cts, PIO2_3, ALT2, PIO0_1, ALT2, PIO0_23, ALT3); -impl_pin_trait!(LPUART2, rx, PIO2_3, ALT3); -impl_pin_trait!(LPUART2, tx, PIO2_2, ALT3); +// impl_pin_trait!(LPUART0, rx, P2_0, ALT2, P0_2, ALT2, P0_20, ALT3); +// impl_pin_trait!(LPUART0, tx, P2_1, ALT2, P0_3, ALT2, P0_21, ALT3); +// impl_pin_trait!(LPUART0, rts, P2_2, ALT2, P0_0, ALT2, P0_22, ALT3); +// impl_pin_trait!(LPUART0, cts, P2_3, ALT2, P0_1, ALT2, P0_23, ALT3); +impl_pin_trait!(LPUART2, rx, P2_3, ALT3); +impl_pin_trait!(LPUART2, tx, P2_2, ALT3); // ============================================================================ // ERROR TYPES AND RESULTS -- cgit