aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathisDerooNXP <[email protected]>2025-11-21 10:00:01 -0800
committerGitHub <[email protected]>2025-11-21 10:00:01 -0800
commiteed314ebb58772476971af49b36b68301eb0d8cc (patch)
treee89ac428dac9d24d96b0ef3cf2c96dc2e4f4dafe
parenta8eb124e47e633cd81e0863253d5f6bdd7545260 (diff)
Gpio support v2 (#26)
* Improve GPIO driver and add button example - port and pcr registers are defined using paste! - added pin configuration for slew rate, drive strength, mux function, etc... - added button example to showcase input gpio feature Signed-off-by: Mathis Deroo <[email protected]> * Add pull-up pull-down config support for input gpio Signed-off-by: Mathis Deroo <[email protected]> * Replace GPIOs enum with existing ones in the PAC Signed-off-by: Mathis Deroo <[email protected]> * Remove init_gpio_pin function as it is done in hal init config Signed-off-by: Mathis Deroo <[email protected]> * Integrate feedback for the GPIO driver - Add again missing IO peripherals - Added function to configure separately slew rate, drive strength, pull. - Revert comment changes Signed-off-by: Mathis Deroo <[email protected]> * Create user-readable field for the pin configuration Signed-off-by: Mathis Deroo <[email protected]> * examples: button: remove left-over OSTIMER initialization While at that, also cargo fmt * Fix warnings * Add documentation for public functions Signed-off-by: Mathis Deroo <[email protected]> * Expose port and pcr registers to AnyPin implementation Signed-off-by: Mathis Deroo <[email protected]> * Remove unnecessary change Signed-off-by: Mathis Deroo <[email protected]> * Run cargo fmt --------- Signed-off-by: Mathis Deroo <[email protected]> Co-authored-by: Felipe Balbi <[email protected]>
-rw-r--r--examples/src/bin/blinky.rs8
-rw-r--r--examples/src/bin/button.rs21
-rw-r--r--src/gpio.rs285
-rw-r--r--src/lib.rs8
-rw-r--r--src/pins.rs61
5 files changed, 278 insertions, 105 deletions
diff --git a/examples/src/bin/blinky.rs b/examples/src/bin/blinky.rs
index ab1e59bdb..dd08ec0d9 100644
--- a/examples/src/bin/blinky.rs
+++ b/examples/src/bin/blinky.rs
@@ -3,7 +3,7 @@
3 3
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_time::Timer; 5use embassy_time::Timer;
6use hal::gpio::{Level, Output}; 6use hal::gpio::{DriveStrength, Level, Output, SlewRate};
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8 8
9#[embassy_executor::main] 9#[embassy_executor::main]
@@ -12,9 +12,9 @@ async fn main(_spawner: Spawner) {
12 12
13 defmt::info!("Blink example"); 13 defmt::info!("Blink example");
14 14
15 let mut red = Output::new(p.P3_18, Level::High); 15 let mut red = Output::new(p.P3_18, Level::High, DriveStrength::Normal, SlewRate::Fast);
16 let mut green = Output::new(p.P3_19, Level::High); 16 let mut green = Output::new(p.P3_19, Level::High, DriveStrength::Normal, SlewRate::Fast);
17 let mut blue = Output::new(p.P3_21, Level::High); 17 let mut blue = Output::new(p.P3_21, Level::High, DriveStrength::Normal, SlewRate::Fast);
18 18
19 loop { 19 loop {
20 defmt::info!("Toggle LEDs"); 20 defmt::info!("Toggle LEDs");
diff --git a/examples/src/bin/button.rs b/examples/src/bin/button.rs
new file mode 100644
index 000000000..2abfe0a9f
--- /dev/null
+++ b/examples/src/bin/button.rs
@@ -0,0 +1,21 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_time::Timer;
6use hal::gpio::{DriveStrength, Input, Pull, SlewRate};
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = hal::init(hal::config::Config::default());
12
13 defmt::info!("Button example");
14
15 let monitor = Input::new(p.P1_7, Pull::Disabled, DriveStrength::Normal, SlewRate::Slow);
16
17 loop {
18 defmt::info!("Pin level is {:?}", monitor.get_level());
19 Timer::after_millis(1000).await;
20 }
21}
diff --git a/src/gpio.rs b/src/gpio.rs
index 09a414d3b..9565fbb6e 100644
--- a/src/gpio.rs
+++ b/src/gpio.rs
@@ -8,13 +8,87 @@ use core::marker::PhantomData;
8use embassy_hal_internal::{Peri, PeripheralType}; 8use embassy_hal_internal::{Peri, PeripheralType};
9use paste::paste; 9use paste::paste;
10 10
11use crate::pac::port0::pcr0::{Dse, Inv, Mux, Pe, Ps, Sre};
12
11/// Logical level for GPIO pins. 13/// Logical level for GPIO pins.
12#[derive(Copy, Clone, Eq, PartialEq, Debug)] 14#[derive(Copy, Clone, Eq, PartialEq, Debug)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub enum Level { 16pub enum Level {
14 Low, 17 Low,
15 High, 18 High,
16} 19}
17 20
21impl From<bool> for Level {
22 fn from(val: bool) -> Self {
23 match val {
24 true => Self::High,
25 false => Self::Low,
26 }
27 }
28}
29
30#[derive(Copy, Clone, Eq, PartialEq, Debug)]
31pub enum Pull {
32 Disabled,
33 Up,
34 Down,
35}
36
37impl From<Pull> for (Pe, Ps) {
38 fn from(pull: Pull) -> Self {
39 match pull {
40 Pull::Disabled => (Pe::Pe0, Ps::Ps0),
41 Pull::Up => (Pe::Pe1, Ps::Ps1),
42 Pull::Down => (Pe::Pe1, Ps::Ps0),
43 }
44 }
45}
46
47#[derive(Copy, Clone, Eq, PartialEq, Debug)]
48pub enum SlewRate {
49 Fast,
50 Slow,
51}
52
53impl From<SlewRate> for Sre {
54 fn from(slew_rate: SlewRate) -> Self {
55 match slew_rate {
56 SlewRate::Fast => Sre::Sre0,
57 SlewRate::Slow => Sre::Sre1,
58 }
59 }
60}
61
62#[derive(Copy, Clone, Eq, PartialEq, Debug)]
63pub enum DriveStrength {
64 Normal,
65 Double,
66}
67
68impl From<DriveStrength> for Dse {
69 fn from(strength: DriveStrength) -> Self {
70 match strength {
71 DriveStrength::Normal => Dse::Dse0,
72 DriveStrength::Double => Dse::Dse1,
73 }
74 }
75}
76
77#[derive(Copy, Clone, Eq, PartialEq, Debug)]
78pub enum Inverter {
79 Disabled,
80 Enabled,
81}
82
83impl From<Inverter> for Inv {
84 fn from(strength: Inverter) -> Self {
85 match strength {
86 Inverter::Disabled => Inv::Inv0,
87 Inverter::Enabled => Inv::Inv1,
88 }
89 }
90}
91
18pub type Gpio = crate::peripherals::GPIO0; 92pub type Gpio = crate::peripherals::GPIO0;
19 93
20/// Type-erased representation of a GPIO pin. 94/// Type-erased representation of a GPIO pin.
@@ -22,12 +96,26 @@ pub struct AnyPin {
22 port: usize, 96 port: usize,
23 pin: usize, 97 pin: usize,
24 gpio: &'static crate::pac::gpio0::RegisterBlock, 98 gpio: &'static crate::pac::gpio0::RegisterBlock,
99 port_reg: &'static crate::pac::port0::RegisterBlock,
100 pcr_reg: &'static crate::pac::port0::Pcr0,
25} 101}
26 102
27impl AnyPin { 103impl AnyPin {
28 /// Create an `AnyPin` from raw components. 104 /// Create an `AnyPin` from raw components.
29 pub fn new(port: usize, pin: usize, gpio: &'static crate::pac::gpio0::RegisterBlock) -> Self { 105 pub fn new(
30 Self { port, pin, gpio } 106 port: usize,
107 pin: usize,
108 gpio: &'static crate::pac::gpio0::RegisterBlock,
109 port_reg: &'static crate::pac::port0::RegisterBlock,
110 pcr_reg: &'static crate::pac::port0::Pcr0,
111 ) -> Self {
112 Self {
113 port,
114 pin,
115 gpio,
116 port_reg,
117 pcr_reg,
118 }
31 } 119 }
32 120
33 #[inline(always)] 121 #[inline(always)]
@@ -49,6 +137,16 @@ impl AnyPin {
49 pub fn pin_index(&self) -> usize { 137 pub fn pin_index(&self) -> usize {
50 self.pin 138 self.pin
51 } 139 }
140
141 #[inline(always)]
142 fn port_reg(&self) -> &'static crate::pac::port0::RegisterBlock {
143 self.port_reg
144 }
145
146 #[inline(always)]
147 fn pcr_reg(&self) -> &'static crate::pac::port0::Pcr0 {
148 self.pcr_reg
149 }
52} 150}
53 151
54embassy_hal_internal::impl_peripheral!(AnyPin); 152embassy_hal_internal::impl_peripheral!(AnyPin);
@@ -65,6 +163,20 @@ trait SealedPin {
65 } 163 }
66 164
67 fn gpio(&self) -> &'static crate::pac::gpio0::RegisterBlock; 165 fn gpio(&self) -> &'static crate::pac::gpio0::RegisterBlock;
166
167 fn port_reg(&self) -> &'static crate::pac::port0::RegisterBlock;
168
169 fn pcr_reg(&self) -> &'static crate::pac::port0::Pcr0;
170
171 fn set_function(&self, function: Mux);
172
173 fn set_pull(&self, pull: Pull);
174
175 fn set_drive_strength(&self, strength: Dse);
176
177 fn set_slew_rate(&self, slew_rate: Sre);
178
179 fn set_enable_input_buffer(&self);
68} 180}
69 181
70/// GPIO pin trait. 182/// GPIO pin trait.
@@ -75,57 +187,120 @@ pub trait GpioPin: SealedPin + Sized + PeripheralType + Into<AnyPin> + 'static {
75 // SAFETY: This is only called within the GpioPin trait, which is only 187 // SAFETY: This is only called within the GpioPin trait, which is only
76 // implemented within this module on valid pin peripherals and thus 188 // implemented within this module on valid pin peripherals and thus
77 // has been verified to be correct. 189 // has been verified to be correct.
78 AnyPin::new(self.port(), self.pin(), self.gpio()) 190 AnyPin::new(self.port(), self.pin(), self.gpio(), self.port_reg(), self.pcr_reg())
79 } 191 }
80} 192}
81 193
82impl SealedPin for AnyPin { 194impl SealedPin for AnyPin {
83 #[inline]
84 fn pin_port(&self) -> usize { 195 fn pin_port(&self) -> usize {
85 self.port * 32 + self.pin 196 self.port * 32 + self.pin
86 } 197 }
87 198
88 #[inline]
89 fn gpio(&self) -> &'static crate::pac::gpio0::RegisterBlock { 199 fn gpio(&self) -> &'static crate::pac::gpio0::RegisterBlock {
90 self.gpio() 200 self.gpio()
91 } 201 }
202
203 fn port_reg(&self) -> &'static crate::pac::port0::RegisterBlock {
204 self.port_reg()
205 }
206
207 fn pcr_reg(&self) -> &'static crate::pac::port0::Pcr0 {
208 self.pcr_reg()
209 }
210
211 fn set_function(&self, function: Mux) {
212 self.pcr_reg().modify(|_, w| w.mux().variant(function));
213 }
214
215 fn set_pull(&self, pull: Pull) {
216 let (pull_enable, pull_select) = pull.into();
217 self.pcr_reg().modify(|_, w| {
218 w.pe().variant(pull_enable);
219 w.ps().variant(pull_select)
220 });
221 }
222
223 fn set_drive_strength(&self, strength: Dse) {
224 self.pcr_reg().modify(|_, w| w.dse().variant(strength));
225 }
226
227 fn set_slew_rate(&self, slew_rate: Sre) {
228 self.pcr_reg().modify(|_, w| w.sre().variant(slew_rate));
229 }
230
231 fn set_enable_input_buffer(&self) {
232 self.pcr_reg().modify(|_, w| w.ibe().ibe1());
233 }
92} 234}
93 235
94impl GpioPin for AnyPin {} 236impl GpioPin for AnyPin {}
95 237
96macro_rules! impl_pin { 238macro_rules! impl_pin {
97 ($peri:ident, $port:expr, $pin:expr, $block:ident) => { 239 ($peri:ident, $port:expr, $pin:expr, $block:ident) => {
98 impl SealedPin for crate::peripherals::$peri { 240 paste! {
99 #[inline] 241 impl SealedPin for crate::peripherals::$peri {
100 fn pin_port(&self) -> usize { 242 fn pin_port(&self) -> usize {
101 $port * 32 + $pin 243 $port * 32 + $pin
102 } 244 }
103 245
104 #[inline] 246 fn gpio(&self) -> &'static crate::pac::gpio0::RegisterBlock {
105 fn gpio(&self) -> &'static crate::pac::gpio0::RegisterBlock { 247 unsafe { &*crate::pac::$block::ptr() }
106 unsafe { &*crate::pac::$block::ptr() } 248 }
107 } 249
108 } 250 fn port_reg(&self) -> &'static crate::pac::port0::RegisterBlock {
251 unsafe { &*crate::pac::[<Port $port>]::ptr() }
252 }
253
254 fn pcr_reg(&self) -> &'static crate::pac::port0::Pcr0 {
255 self.port_reg().[<pcr $pin>]()
256 }
257
258 fn set_function(&self, function: Mux) {
259 unsafe {
260 let port_reg = &*crate::pac::[<Port $port>]::ptr();
261 port_reg.[<pcr $pin>]().modify(|_, w| {
262 w.mux().variant(function)
263 });
264 }
265 }
266
267 fn set_pull(&self, pull: Pull) {
268 let port_reg = unsafe {&*crate::pac::[<Port $port>]::ptr()};
269 let (pull_enable, pull_select) = pull.into();
270 port_reg.[<pcr $pin>]().modify(|_, w| {
271 w.pe().variant(pull_enable);
272 w.ps().variant(pull_select)
273 });
274 }
275
276 fn set_drive_strength(&self, strength: Dse) {
277 let port_reg = unsafe {&*crate::pac::[<Port $port>]::ptr()};
278 port_reg.[<pcr $pin>]().modify(|_, w| w.dse().variant(strength));
279 }
109 280
110 impl GpioPin for crate::peripherals::$peri {} 281 fn set_slew_rate(&self, slew_rate: Sre) {
282 let port_reg = unsafe {&*crate::pac::[<Port $port>]::ptr()};
283 port_reg.[<pcr $pin>]().modify(|_, w| w.sre().variant(slew_rate));
284 }
111 285
112 impl From<crate::peripherals::$peri> for AnyPin { 286 fn set_enable_input_buffer(&self) {
113 fn from(value: crate::peripherals::$peri) -> Self { 287 let port_reg = unsafe {&*crate::pac::[<Port $port>]::ptr()};
114 value.degrade() 288 port_reg.[<pcr $pin>]().modify(|_, w| w.ibe().ibe1());
289 }
115 } 290 }
116 }
117 291
118 impl crate::peripherals::$peri { 292 impl GpioPin for crate::peripherals::$peri {}
119 /// Convenience helper to obtain a type-erased handle to this pin. 293
120 pub fn degrade(&self) -> AnyPin { 294 impl From<crate::peripherals::$peri> for AnyPin {
121 AnyPin::new(self.port(), self.pin(), self.gpio()) 295 fn from(value: crate::peripherals::$peri) -> Self {
296 value.degrade()
297 }
122 } 298 }
123 299
124 #[inline] 300 impl crate::peripherals::$peri {
125 pub fn set_mux_gpio() { 301 /// Convenience helper to obtain a type-erased handle to this pin.
126 paste! { 302 pub fn degrade(&self) -> AnyPin {
127 let port = unsafe { crate::pac::[<Port $port>]::steal()}; 303 AnyPin::new(self.port(), self.pin(), self.gpio(), self.port_reg(), self.pcr_reg())
128 port.[<pcr $pin>]().write(|w| w.mux().mux00());
129 } 304 }
130 } 305 }
131 } 306 }
@@ -309,6 +484,7 @@ impl<'d> Flex<'d> {
309 /// The pin remains unmodified. The initial output level is unspecified, but 484 /// The pin remains unmodified. The initial output level is unspecified, but
310 /// can be changed before the pin is put into output mode. 485 /// can be changed before the pin is put into output mode.
311 pub fn new(pin: Peri<'d, impl GpioPin>) -> Self { 486 pub fn new(pin: Peri<'d, impl GpioPin>) -> Self {
487 pin.set_function(Mux::Mux00);
312 Self { 488 Self {
313 pin: pin.into(), 489 pin: pin.into(),
314 _marker: PhantomData, 490 _marker: PhantomData,
@@ -326,22 +502,22 @@ impl<'d> Flex<'d> {
326 } 502 }
327 503
328 /// Put the pin into input mode. 504 /// Put the pin into input mode.
329 ///
330 /// The pull setting is left unchanged.
331 #[inline]
332 pub fn set_as_input(&mut self) { 505 pub fn set_as_input(&mut self) {
333 let mask = self.mask(); 506 let mask = self.mask();
334 let gpio = self.gpio(); 507 let gpio = self.gpio();
508
509 self.set_enable_input_buffer();
510
335 gpio.pddr().modify(|r, w| unsafe { w.bits(r.bits() & !mask) }); 511 gpio.pddr().modify(|r, w| unsafe { w.bits(r.bits() & !mask) });
336 } 512 }
337 513
338 /// Put the pin into output mode. 514 /// Put the pin into output mode.
339 ///
340 /// The initial output level is left unchanged.
341 #[inline]
342 pub fn set_as_output(&mut self) { 515 pub fn set_as_output(&mut self) {
343 let mask = self.mask(); 516 let mask = self.mask();
344 let gpio = self.gpio(); 517 let gpio = self.gpio();
518
519 self.set_pull(Pull::Disabled);
520
345 gpio.pddr().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); 521 gpio.pddr().modify(|r, w| unsafe { w.bits(r.bits() | mask) });
346 } 522 }
347 523
@@ -395,6 +571,31 @@ impl<'d> Flex<'d> {
395 pub fn is_set_low(&self) -> bool { 571 pub fn is_set_low(&self) -> bool {
396 !self.is_set_high() 572 !self.is_set_high()
397 } 573 }
574
575 /// Configure the pin pull up/down level.
576 pub fn set_pull(&mut self, pull_select: Pull) {
577 self.pin.set_pull(pull_select);
578 }
579
580 /// Configure the pin drive strength.
581 pub fn set_drive_strength(&mut self, strength: DriveStrength) {
582 self.pin.set_drive_strength(strength.into());
583 }
584
585 /// Configure the pin slew rate.
586 pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
587 self.pin.set_slew_rate(slew_rate.into());
588 }
589
590 /// Enable input buffer for the pin.
591 pub fn set_enable_input_buffer(&mut self) {
592 self.pin.set_enable_input_buffer();
593 }
594
595 /// Get pin level.
596 pub fn get_level(&self) -> Level {
597 self.is_high().into()
598 }
398} 599}
399 600
400/// GPIO output driver that owns a `Flex` pin. 601/// GPIO output driver that owns a `Flex` pin.
@@ -404,10 +605,12 @@ pub struct Output<'d> {
404 605
405impl<'d> Output<'d> { 606impl<'d> Output<'d> {
406 /// Create a GPIO output driver for a [GpioPin] with the provided [Level]. 607 /// Create a GPIO output driver for a [GpioPin] with the provided [Level].
407 pub fn new(pin: Peri<'d, impl GpioPin>, initial: Level) -> Self { 608 pub fn new(pin: Peri<'d, impl GpioPin>, initial: Level, strength: DriveStrength, slew_rate: SlewRate) -> Self {
408 let mut flex = Flex::new(pin); 609 let mut flex = Flex::new(pin);
409 flex.set_level(initial); 610 flex.set_level(initial);
410 flex.set_as_output(); 611 flex.set_as_output();
612 flex.set_drive_strength(strength);
613 flex.set_slew_rate(slew_rate);
411 Self { flex } 614 Self { flex }
412 } 615 }
413 616
@@ -461,9 +664,12 @@ pub struct Input<'d> {
461 664
462impl<'d> Input<'d> { 665impl<'d> Input<'d> {
463 /// Create a GPIO input driver for a [GpioPin]. 666 /// Create a GPIO input driver for a [GpioPin].
464 pub fn new(pin: Peri<'d, impl GpioPin>) -> Self { 667 pub fn new(pin: Peri<'d, impl GpioPin>, pull_select: Pull, strength: DriveStrength, slew_rate: SlewRate) -> Self {
465 let mut flex = Flex::new(pin); 668 let mut flex = Flex::new(pin);
466 flex.set_as_input(); 669 flex.set_as_input();
670 flex.set_drive_strength(strength);
671 flex.set_slew_rate(slew_rate);
672 flex.set_pull(pull_select);
467 Self { flex } 673 Self { flex }
468 } 674 }
469 675
@@ -484,6 +690,11 @@ impl<'d> Input<'d> {
484 pub fn into_flex(self) -> Flex<'d> { 690 pub fn into_flex(self) -> Flex<'d> {
485 self.flex 691 self.flex
486 } 692 }
693
694 // Get the pin level.
695 pub fn get_level(&self) -> Level {
696 self.flex.get_level()
697 }
487} 698}
488 699
489// Both embedded_hal 0.2 and 1.0 must be supported by embassy HALs. 700// Both embedded_hal 0.2 and 1.0 must be supported by embassy HALs.
diff --git a/src/lib.rs b/src/lib.rs
index e93ff61a6..175642f75 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,7 +1,9 @@
1#![no_std] 1#![no_std]
2// TODO(AJM): As of 2025-11-13, we need to do a pass to ensure safety docs 2#![allow(async_fn_in_trait)]
3// are complete prior to release. 3#![doc = include_str!("../README.md")]
4#![allow(clippy::missing_safety_doc)] 4
5// //! ## Feature flags
6// #![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
5 7
6pub mod clocks; // still provide clock helpers 8pub mod clocks; // still provide clock helpers
7pub mod gpio; 9pub mod gpio;
diff --git a/src/pins.rs b/src/pins.rs
index f802568f3..f65195dd2 100644
--- a/src/pins.rs
+++ b/src/pins.rs
@@ -60,64 +60,3 @@ pub unsafe fn configure_adc_pins() {
60 }); 60 });
61 core::arch::asm!("dsb sy; isb sy"); 61 core::arch::asm!("dsb sy; isb sy");
62} 62}
63
64/// Configure a pin for a specific mux alternative.
65///
66/// # Arguments
67/// * `port` - Port number (0-4)
68/// * `pin` - Pin number (varies by port: PORT0=0-7, PORT1=0-19, PORT2=0-26, PORT3=0-31, PORT4=0-7)
69/// * `mux` - Mux alternative (0-15, where 0 = GPIO, 1-15 = other functions)
70pub unsafe fn set_pin_mux(port: u8, pin: u8, mux: u8) {
71 // Validate mux value (0-15)
72 if mux > 15 {
73 panic!("Invalid mux value: {}, must be 0-15", mux);
74 }
75
76 // Validate pin number based on port
77 let max_pin = match port {
78 0 => 7, // PORT0: pins 0-7
79 1 => 19, // PORT1: pins 0-19
80 2 => 26, // PORT2: pins 0-26
81 3 => 31, // PORT3: pins 0-31
82 4 => 7, // PORT4: pins 0-7
83 _ => panic!("Unsupported GPIO port: {}", port),
84 };
85
86 if pin > max_pin {
87 panic!("Invalid pin {} for PORT{}, max pin is {}", pin, port, max_pin);
88 }
89
90 // Get the base address for the port
91 let port_base: *mut u32 = match port {
92 0 => pac::Port0::ptr() as *mut u32,
93 1 => pac::Port1::ptr() as *mut u32,
94 2 => pac::Port2::ptr() as *mut u32,
95 3 => pac::Port3::ptr() as *mut u32,
96 4 => pac::Port4::ptr() as *mut u32,
97 _ => panic!("Unsupported GPIO port: {}", port),
98 };
99
100 // PCR registers are 4 bytes apart, starting at offset 0 for PCR0
101 let pcr_addr = port_base.add(pin as usize);
102
103 // Read current PCR value
104 let current_val = pcr_addr.read_volatile();
105
106 // Clear mux bits (bits 8-11) and set new mux value
107 let new_val = (current_val & !(0xF << 8)) | ((mux as u32) << 8);
108
109 // Write back the new value
110 pcr_addr.write_volatile(new_val);
111
112 core::arch::asm!("dsb sy; isb sy");
113}
114
115/// Configure a pin for GPIO mode (ALT0).
116/// This is a convenience function that calls set_pin_mux with mux=0.
117///
118/// # Arguments
119/// * `port` - Port number (0-4)
120/// * `pin` - Pin number (varies by port: PORT0=0-7, PORT1=0-19, PORT2=0-26, PORT3=0-31, PORT4=0-7)
121pub unsafe fn set_pin_mux_gpio(port: u8, pin: u8) {
122 set_pin_mux(port, pin, 0);
123}