diff options
| author | MathisDerooNXP <[email protected]> | 2025-11-21 10:00:01 -0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-21 10:00:01 -0800 |
| commit | eed314ebb58772476971af49b36b68301eb0d8cc (patch) | |
| tree | e89ac428dac9d24d96b0ef3cf2c96dc2e4f4dafe | |
| parent | a8eb124e47e633cd81e0863253d5f6bdd7545260 (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.rs | 8 | ||||
| -rw-r--r-- | examples/src/bin/button.rs | 21 | ||||
| -rw-r--r-- | src/gpio.rs | 285 | ||||
| -rw-r--r-- | src/lib.rs | 8 | ||||
| -rw-r--r-- | src/pins.rs | 61 |
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 | ||
| 4 | use embassy_executor::Spawner; | 4 | use embassy_executor::Spawner; |
| 5 | use embassy_time::Timer; | 5 | use embassy_time::Timer; |
| 6 | use hal::gpio::{Level, Output}; | 6 | use hal::gpio::{DriveStrength, Level, Output, SlewRate}; |
| 7 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | 7 | use {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 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_time::Timer; | ||
| 6 | use hal::gpio::{DriveStrength, Input, Pull, SlewRate}; | ||
| 7 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 8 | |||
| 9 | #[embassy_executor::main] | ||
| 10 | async 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; | |||
| 8 | use embassy_hal_internal::{Peri, PeripheralType}; | 8 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 9 | use paste::paste; | 9 | use paste::paste; |
| 10 | 10 | ||
| 11 | use 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))] | ||
| 13 | pub enum Level { | 16 | pub enum Level { |
| 14 | Low, | 17 | Low, |
| 15 | High, | 18 | High, |
| 16 | } | 19 | } |
| 17 | 20 | ||
| 21 | impl 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)] | ||
| 31 | pub enum Pull { | ||
| 32 | Disabled, | ||
| 33 | Up, | ||
| 34 | Down, | ||
| 35 | } | ||
| 36 | |||
| 37 | impl 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)] | ||
| 48 | pub enum SlewRate { | ||
| 49 | Fast, | ||
| 50 | Slow, | ||
| 51 | } | ||
| 52 | |||
| 53 | impl 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)] | ||
| 63 | pub enum DriveStrength { | ||
| 64 | Normal, | ||
| 65 | Double, | ||
| 66 | } | ||
| 67 | |||
| 68 | impl 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)] | ||
| 78 | pub enum Inverter { | ||
| 79 | Disabled, | ||
| 80 | Enabled, | ||
| 81 | } | ||
| 82 | |||
| 83 | impl 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 | |||
| 18 | pub type Gpio = crate::peripherals::GPIO0; | 92 | pub 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 | ||
| 27 | impl AnyPin { | 103 | impl 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 | ||
| 54 | embassy_hal_internal::impl_peripheral!(AnyPin); | 152 | embassy_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 | ||
| 82 | impl SealedPin for AnyPin { | 194 | impl 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 | ||
| 94 | impl GpioPin for AnyPin {} | 236 | impl GpioPin for AnyPin {} |
| 95 | 237 | ||
| 96 | macro_rules! impl_pin { | 238 | macro_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 | ||
| 405 | impl<'d> Output<'d> { | 606 | impl<'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 | ||
| 462 | impl<'d> Input<'d> { | 665 | impl<'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 | ||
| 6 | pub mod clocks; // still provide clock helpers | 8 | pub mod clocks; // still provide clock helpers |
| 7 | pub mod gpio; | 9 | pub 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) | ||
| 70 | pub 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) | ||
| 121 | pub unsafe fn set_pin_mux_gpio(port: u8, pin: u8) { | ||
| 122 | set_pin_mux(port, pin, 0); | ||
| 123 | } | ||
