diff --git a/CHANGELOG.md b/CHANGELOG.md index 59c2e164..cd732316 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- `PinState` and `get/set_state`. +- Inherent methods for infallible digital operations. - Generic `into_alternate` and `into_alternate_open_drain`. Non-generic ones are deprecated - Internal implementation of GPIO Pin API changed to use Const Generics - `PinExt` trait. Make `ExtiPin` implementation generic diff --git a/examples/analog-stopwatch-with-spi-ssd1306.rs b/examples/analog-stopwatch-with-spi-ssd1306.rs index 3e219544..80bf15b7 100644 --- a/examples/analog-stopwatch-with-spi-ssd1306.rs +++ b/examples/analog-stopwatch-with-spi-ssd1306.rs @@ -118,9 +118,9 @@ fn main() -> ! { let mut ss = gpioe.pe4.into_push_pull_output(); let mut delay = hal::delay::Delay::new(cp.SYST, clocks); - ss.set_high().unwrap(); + ss.set_high(); delay.delay_ms(100_u32); - ss.set_low().unwrap(); + ss.set_low(); // Set up the display let interface = SPIInterfaceNoCS::new(spi, dc); @@ -164,21 +164,21 @@ fn main() -> ! { match state { StopwatchState::Ready => { - led3.set_high().unwrap(); - led4.set_low().unwrap(); + led3.set_high(); + led4.set_low(); } StopwatchState::Running => { if state_led { - led4.set_low().unwrap(); - led3.set_high().unwrap(); + led4.set_low(); + led3.set_high(); } else { - led4.set_low().unwrap(); - led3.set_low().unwrap(); + led4.set_low(); + led3.set_low(); } } StopwatchState::Stopped => { - led3.set_low().unwrap(); - led4.set_high().unwrap(); + led3.set_low(); + led4.set_high(); } }; @@ -282,7 +282,7 @@ fn TIM2() { StopwatchState::Stopped => { let mut btn_ref = BUTTON.borrow(cs).borrow_mut(); if let Some(ref mut btn) = btn_ref.deref_mut() { - if btn.is_high().unwrap() { + if btn.is_high() { cell_reset.replace(val_reset + 1); } } diff --git a/examples/blinky-timer-irq.rs b/examples/blinky-timer-irq.rs index ddc937ab..58085a57 100644 --- a/examples/blinky-timer-irq.rs +++ b/examples/blinky-timer-irq.rs @@ -20,7 +20,6 @@ use crate::hal::{ use core::cell::RefCell; use cortex_m::{asm::wfi, interrupt::Mutex}; use cortex_m_rt::entry; -use embedded_hal::digital::v2::OutputPin; use embedded_hal::timer::CountDown; // NOTE You can uncomment 'hprintln' here and in the code below for a bit more diff --git a/examples/delay-blinky.rs b/examples/delay-blinky.rs index cee386af..8b6c9359 100644 --- a/examples/delay-blinky.rs +++ b/examples/delay-blinky.rs @@ -30,9 +30,9 @@ fn main() -> ! { loop { // On for 1s, off for 1s. - led.set_high().unwrap(); + led.set_high(); delay.delay_ms(1000_u32); - led.set_low().unwrap(); + led.set_low(); delay.delay_ms(1000_u32); } } diff --git a/examples/dwt-blinky.rs b/examples/dwt-blinky.rs index 9613078a..36bff2ea 100644 --- a/examples/dwt-blinky.rs +++ b/examples/dwt-blinky.rs @@ -38,12 +38,12 @@ fn main() -> ! { let mut sw = dwt.stopwatch(&mut lap_times); loop { // On for 1s, off for 1s. - led1.set_high().unwrap(); - led2.set_low().unwrap(); + led1.set_high(); + led2.set_low(); delay.delay_ms(1000_u32); sw.lap(); - led1.set_low().unwrap(); - led2.set_high().unwrap(); + led1.set_low(); + led2.set_high(); delay.delay_ms(900_u32); // Also you can measure with almost clock precision let cd: ClockDuration = dwt.measure(|| delay.delay_ms(100_u32)); diff --git a/examples/f413disco_lcd_ferris.rs b/examples/f413disco_lcd_ferris.rs index 45b85295..3b5ce633 100644 --- a/examples/f413disco_lcd_ferris.rs +++ b/examples/f413disco_lcd_ferris.rs @@ -743,7 +743,7 @@ fn main() -> ! { let mut _te = gpiob.pb14.into_floating_input(); // Enable backlight - gpioe.pe5.into_push_pull_output().set_high().ok(); + gpioe.pe5.into_push_pull_output().set_high(); // Get delay provider let mut delay = Delay::new(cp.SYST, clocks); diff --git a/examples/i2s-audio-out-dma.rs b/examples/i2s-audio-out-dma.rs index 8c59e2b2..ecdcec9c 100644 --- a/examples/i2s-audio-out-dma.rs +++ b/examples/i2s-audio-out-dma.rs @@ -148,7 +148,7 @@ fn main() -> ! { // Keep DAC reset low for at least one millisecond delay.delay_ms(1u8); // Release the DAC from reset - dac_reset.set_high().unwrap(); + dac_reset.set_high(); // Wait at least 550 ns before starting I2C communication delay.delay_us(1u8); diff --git a/examples/i2s-audio-out.rs b/examples/i2s-audio-out.rs index b2699aaa..41822887 100644 --- a/examples/i2s-audio-out.rs +++ b/examples/i2s-audio-out.rs @@ -145,7 +145,7 @@ fn main() -> ! { // Keep DAC reset low for at least one millisecond delay.delay_ms(1u8); // Release the DAC from reset - dac_reset.set_high().unwrap(); + dac_reset.set_high(); // Wait at least 550 ns before starting I2C communication delay.delay_us(1u8); diff --git a/examples/qei.rs b/examples/qei.rs index 673eafe4..04ab1b65 100644 --- a/examples/qei.rs +++ b/examples/qei.rs @@ -52,8 +52,8 @@ fn main() -> ! { // Light up the LED when turning clockwise, turn it off // when turning counter-clockwise. match rotary_encoder.direction() { - RotaryDirection::Upcounting => led.set_low().unwrap(), - RotaryDirection::Downcounting => led.set_high().unwrap(), + RotaryDirection::Upcounting => led.set_low(), + RotaryDirection::Downcounting => led.set_high(), } current_count = new_count; diff --git a/examples/rtic.rs b/examples/rtic.rs index 2f23c056..6caace8d 100644 --- a/examples/rtic.rs +++ b/examples/rtic.rs @@ -38,6 +38,6 @@ const APP: () = { #[task(binds = EXTI0, resources = [button, led])] fn button_click(ctx: button_click::Context) { ctx.resources.button.clear_interrupt_pending_bit(); - ctx.resources.led.toggle().unwrap(); + ctx.resources.led.toggle(); } }; diff --git a/examples/serial-9bit.rs b/examples/serial-9bit.rs index 3d1dda50..cf93d5ab 100644 --- a/examples/serial-9bit.rs +++ b/examples/serial-9bit.rs @@ -84,24 +84,24 @@ fn main() -> ! { // Update LEDs to display what was received if ((received >> 5) & 1) == 1 { - led_bit5.set_high().unwrap(); + led_bit5.set_high(); } else { - led_bit5.set_low().unwrap(); + led_bit5.set_low(); } if ((received >> 6) & 1) == 1 { - led_bit6.set_high().unwrap(); + led_bit6.set_high(); } else { - led_bit6.set_low().unwrap(); + led_bit6.set_low(); } if ((received >> 7) & 1) == 1 { - led_bit7.set_high().unwrap(); + led_bit7.set_high(); } else { - led_bit7.set_low().unwrap(); + led_bit7.set_low(); } if ((received >> 8) & 1) == 1 { - led_bit8.set_high().unwrap(); + led_bit8.set_high(); } else { - led_bit8.set_low().unwrap(); + led_bit8.set_low(); } delay.delay_ms(10u32); diff --git a/examples/ssd1306-image.rs b/examples/ssd1306-image.rs index 83d4d555..73458a77 100644 --- a/examples/ssd1306-image.rs +++ b/examples/ssd1306-image.rs @@ -60,13 +60,13 @@ fn main() -> ! { // Set up state for the loop let mut orientation = DisplayRotation::Rotate0; - let mut was_pressed = btn.is_low().unwrap(); + let mut was_pressed = btn.is_low(); // This runs continuously, as fast as possible loop { // Check if the button has just been pressed. // Remember, active low. - let is_pressed = btn.is_low().unwrap(); + let is_pressed = btn.is_low(); if !was_pressed && is_pressed { // Since the button was pressed, flip the screen upside down orientation = get_next_rotation(orientation); diff --git a/examples/st7789-lcd.rs b/examples/st7789-lcd.rs index 85331aca..7ea1aa5e 100644 --- a/examples/st7789-lcd.rs +++ b/examples/st7789-lcd.rs @@ -109,14 +109,14 @@ fn main() -> ! { // https://github.com/STMicroelectronics/STM32CubeF4/blob/e084518f363e04344dc37822210a75e87377b200/Drivers/BSP/Components/st7789h2/st7789h2.c // Reset LCD controller - lcd_reset.set_low().unwrap(); + lcd_reset.set_low(); delay.delay_ms(5u16); - lcd_reset.set_high().unwrap(); + lcd_reset.set_high(); delay.delay_ms(10u16); - lcd_reset.set_low().unwrap(); + lcd_reset.set_low(); delay.delay_ms(20u16); // Release from reset - lcd_reset.set_high().unwrap(); + lcd_reset.set_high(); delay.delay_ms(10u16); // Add LCD controller driver @@ -140,7 +140,7 @@ fn main() -> ! { lcd.write(0x29, &[]); // Turn on backlight - backlight_control.set_high().unwrap(); + backlight_control.set_high(); // Draw some circles let test_colors = [ diff --git a/src/gpio.rs b/src/gpio.rs index f855190c..fb636113 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -3,7 +3,7 @@ use core::convert::Infallible; use core::marker::PhantomData; -use embedded_hal::digital::v2::{toggleable, InputPin, OutputPin, StatefulOutputPin}; +use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}; use crate::pac::EXTI; use crate::syscfg::SysCfg; @@ -81,7 +81,17 @@ pub struct PushPull; /// Analog mode (type state) pub struct Analog; +/// Digital output pin state +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum PinState { + /// Low pin state + Low, + /// High pin state + High, +} + /// GPIO Pin speed selection +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Speed { Low = 0, Medium = 1, @@ -89,7 +99,7 @@ pub enum Speed { VeryHigh = 3, } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Edge { RISING, FALLING, @@ -223,62 +233,150 @@ impl PinExt for PXx { } } -impl OutputPin for PXx, P> { - type Error = Infallible; - - fn set_high(&mut self) -> Result<(), Self::Error> { +impl PXx, P> { + #[inline(always)] + pub fn set_high(&mut self) { // NOTE(unsafe) atomic write to a stateless register - unsafe { (*Gpio::

::ptr()).bsrr.write(|w| w.bits(1 << self.i)) }; - Ok(()) + unsafe { (*Gpio::

::ptr()).bsrr.write(|w| w.bits(1 << self.i)) } } - fn set_low(&mut self) -> Result<(), Self::Error> { + #[inline(always)] + pub fn set_low(&mut self) { // NOTE(unsafe) atomic write to a stateless register unsafe { (*Gpio::

::ptr()) .bsrr .write(|w| w.bits(1 << (self.i + 16))) - }; + } + } + + #[inline(always)] + pub fn get_state(&self) -> PinState { + if self.is_set_low() { + PinState::Low + } else { + PinState::High + } + } + + #[inline(always)] + pub fn set_state(&mut self, state: PinState) { + match state { + PinState::Low => self.set_low(), + PinState::High => self.set_high(), + } + } + + #[inline(always)] + pub fn is_set_high(&self) -> bool { + !self.is_set_low() + } + + #[inline(always)] + pub fn is_set_low(&self) -> bool { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Gpio::

::ptr()).odr.read().bits() & (1 << self.i) == 0 } + } + + #[inline(always)] + pub fn toggle(&mut self) { + if self.is_set_low() { + self.set_high() + } else { + self.set_low() + } + } +} + +impl OutputPin for PXx, P> { + type Error = Infallible; + + #[inline(always)] + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high(); + Ok(()) + } + + #[inline(always)] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low(); Ok(()) } } impl StatefulOutputPin for PXx, P> { + #[inline(always)] fn is_set_high(&self) -> Result { - self.is_set_low().map(|v| !v) + Ok(self.is_set_high()) } + #[inline(always)] fn is_set_low(&self) -> Result { - // NOTE(unsafe) atomic read with no side effects - Ok(unsafe { (*Gpio::

::ptr()).odr.read().bits() & (1 << self.i) == 0 }) + Ok(self.is_set_low()) + } +} + +impl ToggleableOutputPin for PXx, P> { + type Error = Infallible; + + #[inline(always)] + fn toggle(&mut self) -> Result<(), Self::Error> { + self.toggle(); + Ok(()) } } -impl toggleable::Default for PXx, P> {} +impl PXx, P> { + #[inline(always)] + fn is_high(&self) -> bool { + !self.is_low() + } + + #[inline(always)] + fn is_low(&self) -> bool { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Gpio::

::ptr()).idr.read().bits() & (1 << self.i) == 0 } + } +} impl InputPin for PXx, P> { type Error = Infallible; + #[inline(always)] fn is_high(&self) -> Result { - self.is_low().map(|v| !v) + Ok(self.is_high()) } + #[inline(always)] fn is_low(&self) -> Result { + Ok(self.is_low()) + } +} + +impl PXx, P> { + #[inline(always)] + fn is_high(&self) -> bool { + !self.is_low() + } + + #[inline(always)] + fn is_low(&self) -> bool { // NOTE(unsafe) atomic read with no side effects - Ok(unsafe { (*Gpio::

::ptr()).idr.read().bits() & (1 << self.i) == 0 }) + unsafe { (*Gpio::

::ptr()).idr.read().bits() & (1 << self.i) == 0 } } } impl InputPin for PXx, P> { type Error = Infallible; + #[inline(always)] fn is_high(&self) -> Result { - self.is_low().map(|v| !v) + Ok(self.is_high()) } + #[inline(always)] fn is_low(&self) -> Result { - // NOTE(unsafe) atomic read with no side effects - Ok(unsafe { (*Gpio::

::ptr()).idr.read().bits() & (1 << self.i) == 0 }) + Ok(self.is_low()) } } @@ -326,17 +424,337 @@ impl PinExt for PX { } } +impl From, P, N>> + for PX>, P, N> +{ + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_alternate::() + } +} + +impl From, P, N>> + for PX>, P, N> +{ + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_alternate::() + } +} + +impl From> + for PX>, P, N> +{ + #[inline(always)] + fn from(f: PX) -> Self { + f.into_alternate::() + } +} + +impl From>, P, N>> + for PX>, P, N> +{ + #[inline(always)] + fn from(f: PX>, P, N>) -> Self { + f.into_alternate::() + } +} + +impl From, P, N>> + for PX>, P, N> +{ + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_alternate_open_drain::() + } +} + +impl From, P, N>> + for PX>, P, N> +{ + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_alternate_open_drain::() + } +} + +impl From> + for PX>, P, N> +{ + #[inline(always)] + fn from(f: PX) -> Self { + f.into_alternate_open_drain::() + } +} + +impl From>, P, N>> + for PX>, P, N> +{ + #[inline(always)] + fn from(f: PX>, P, N>) -> Self { + f.into_alternate_open_drain::() + } +} + +impl From, P, N>> for PX, P, N> { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_pull_down_input() + } +} + +impl From, P, N>> for PX, P, N> { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_pull_down_input() + } +} + +impl From, P, N>> for PX, P, N> { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_pull_down_input() + } +} + +impl From> for PX, P, N> { + #[inline(always)] + fn from(f: PX) -> Self { + f.into_pull_down_input() + } +} + +impl From, P, N>> + for PX, P, N> +{ + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_pull_down_input() + } +} + +impl From, P, N>> + for PX, P, N> +{ + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_pull_down_input() + } +} + +impl From, P, N>> for PX, P, N> { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_pull_up_input() + } +} + +impl From, P, N>> for PX, P, N> { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_pull_up_input() + } +} + +impl From, P, N>> for PX, P, N> { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_pull_up_input() + } +} + +impl From> for PX, P, N> { + #[inline(always)] + fn from(f: PX) -> Self { + f.into_pull_up_input() + } +} + +impl From, P, N>> for PX, P, N> { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_pull_up_input() + } +} + +impl From, P, N>> + for PX, P, N> +{ + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_pull_up_input() + } +} + +impl From, P, N>> for PX, P, N> { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_floating_input() + } +} + +impl From, P, N>> for PX, P, N> { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_floating_input() + } +} + +impl From, P, N>> for PX, P, N> { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_floating_input() + } +} + +impl From> for PX, P, N> { + #[inline(always)] + fn from(f: PX) -> Self { + f.into_floating_input() + } +} + +impl From, P, N>> + for PX, P, N> +{ + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_floating_input() + } +} + +impl From, P, N>> + for PX, P, N> +{ + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_floating_input() + } +} + +impl From, P, N>> for PX, P, N> { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_open_drain_output() + } +} + +impl From, P, N>> for PX, P, N> { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_open_drain_output() + } +} + +impl From> for PX, P, N> { + #[inline(always)] + fn from(f: PX) -> Self { + f.into_open_drain_output() + } +} + +impl From, P, N>> + for PX, P, N> +{ + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_open_drain_output() + } +} + +impl From, P, N>> + for PX, P, N> +{ + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_open_drain_output() + } +} + +impl From, P, N>> for PX, P, N> { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_push_pull_output() + } +} + +impl From, P, N>> for PX, P, N> { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_push_pull_output() + } +} + +impl From> for PX, P, N> { + #[inline(always)] + fn from(f: PX) -> Self { + f.into_push_pull_output() + } +} + +impl From, P, N>> + for PX, P, N> +{ + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_push_pull_output() + } +} + +impl From, P, N>> + for PX, P, N> +{ + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_push_pull_output() + } +} + +impl From, P, N>> for PX { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_analog() + } +} + +impl From, P, N>> for PX { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_analog() + } +} + +impl From, P, N>> for PX { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_analog() + } +} + +impl From, P, N>> for PX { + #[inline(always)] + fn from(f: PX, P, N>) -> Self { + f.into_analog() + } +} impl PX { /// Configures the pin to operate alternate mode pub fn into_alternate(self) -> PX>, P, N> { - less_than_16::(); + #[allow(path_statements, clippy::no_effect)] + { + Assert::::LESS; + } _set_alternate_mode::(); PX::new() } /// Configures the pin to operate in alternate open drain mode + #[allow(path_statements)] pub fn into_alternate_open_drain(self) -> PX>, P, N> { - less_than_16::(); + #[allow(path_statements, clippy::no_effect)] + { + Assert::::LESS; + } _set_alternate_mode::(); PX::new().set_open_drain() } @@ -754,62 +1172,150 @@ impl PX { } } -impl OutputPin for PX, P, N> { - type Error = Infallible; - - fn set_high(&mut self) -> Result<(), Self::Error> { +impl PX, P, N> { + #[inline(always)] + pub fn set_high(&mut self) { // NOTE(unsafe) atomic write to a stateless register - unsafe { (*Gpio::

::ptr()).bsrr.write(|w| w.bits(1 << { N })) }; - Ok(()) + unsafe { (*Gpio::

::ptr()).bsrr.write(|w| w.bits(1 << { N })) } } - fn set_low(&mut self) -> Result<(), Self::Error> { + #[inline(always)] + pub fn set_low(&mut self) { // NOTE(unsafe) atomic write to a stateless register unsafe { (*Gpio::

::ptr()) .bsrr .write(|w| w.bits(1 << ({ N } + 16))) - }; + } + } + + #[inline(always)] + pub fn get_state(&self) -> PinState { + if self.is_set_low() { + PinState::Low + } else { + PinState::High + } + } + + #[inline(always)] + pub fn set_state(&mut self, state: PinState) { + match state { + PinState::Low => self.set_low(), + PinState::High => self.set_high(), + } + } + + #[inline(always)] + pub fn is_set_high(&self) -> bool { + !self.is_set_low() + } + + #[inline(always)] + pub fn is_set_low(&self) -> bool { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Gpio::

::ptr()).odr.read().bits() & (1 << { N }) == 0 } + } + + #[inline(always)] + pub fn toggle(&mut self) { + if self.is_set_low() { + self.set_high() + } else { + self.set_low() + } + } +} + +impl OutputPin for PX, P, N> { + type Error = Infallible; + + #[inline(always)] + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high(); + Ok(()) + } + + #[inline(always)] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low(); Ok(()) } } impl StatefulOutputPin for PX, P, N> { + #[inline(always)] fn is_set_high(&self) -> Result { - self.is_set_low().map(|v| !v) + Ok(self.is_set_high()) } + #[inline(always)] fn is_set_low(&self) -> Result { - // NOTE(unsafe) atomic read with no side effects - Ok(unsafe { (*Gpio::

::ptr()).odr.read().bits() & (1 << { N }) == 0 }) + Ok(self.is_set_low()) } } -impl toggleable::Default for PX, P, N> {} +impl ToggleableOutputPin for PX, P, N> { + type Error = Infallible; + + #[inline(always)] + fn toggle(&mut self) -> Result<(), Self::Error> { + self.toggle(); + Ok(()) + } +} + +impl PX, P, N> { + #[inline(always)] + pub fn is_high(&self) -> bool { + !self.is_low() + } + + #[inline(always)] + pub fn is_low(&self) -> bool { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Gpio::

::ptr()).idr.read().bits() & (1 << { N }) == 0 } + } +} impl InputPin for PX, P, N> { type Error = Infallible; + #[inline(always)] fn is_high(&self) -> Result { - self.is_low().map(|v| !v) + Ok(self.is_high()) } + #[inline(always)] fn is_low(&self) -> Result { + Ok(self.is_low()) + } +} + +impl PX, P, N> { + #[inline(always)] + pub fn is_high(&self) -> bool { + !self.is_low() + } + + #[inline(always)] + pub fn is_low(&self) -> bool { // NOTE(unsafe) atomic read with no side effects - Ok(unsafe { (*Gpio::

::ptr()).idr.read().bits() & (1 << { N }) == 0 }) + unsafe { (*Gpio::

::ptr()).idr.read().bits() & (1 << { N }) == 0 } } } impl InputPin for PX, P, N> { type Error = Infallible; + #[inline(always)] fn is_high(&self) -> Result { - self.is_low().map(|v| !v) + Ok(self.is_high()) } + #[inline(always)] fn is_low(&self) -> Result { - // NOTE(unsafe) atomic read with no side effects - Ok(unsafe { (*Gpio::

::ptr()).idr.read().bits() & (1 << { N }) == 0 }) + Ok(self.is_low()) } } @@ -1126,60 +1632,147 @@ impl Pin { } } -impl OutputPin for Pin> { - type Error = core::convert::Infallible; +impl Pin> { + #[inline(always)] + pub fn set_high(&mut self) { + // NOTE(unsafe) atomic write to a stateless register + unsafe { self.block().bsrr.write(|w| w.bits(1 << self.pin_id())) }; + } - fn set_low(&mut self) -> Result<(), Self::Error> { + #[inline(always)] + pub fn set_low(&mut self) { // NOTE(unsafe) atomic write to a stateless register unsafe { self.block() .bsrr .write(|w| w.bits(1 << (self.pin_id() + 16))) }; - Ok(()) } + #[inline(always)] + pub fn get_state(&self) -> PinState { + if self.is_set_low() { + PinState::Low + } else { + PinState::High + } + } + + #[inline(always)] + pub fn set_state(&mut self, state: PinState) { + match state { + PinState::Low => self.set_low(), + PinState::High => self.set_high(), + } + } + + #[inline(always)] + pub fn is_set_high(&self) -> bool { + !self.is_set_low() + } + + #[inline(always)] + pub fn is_set_low(&self) -> bool { + self.block().odr.read().bits() & (1 << self.pin_id()) == 0 + } + + #[inline(always)] + pub fn toggle(&mut self) { + if self.is_set_low() { + self.set_high() + } else { + self.set_low() + } + } +} + +impl OutputPin for Pin> { + type Error = core::convert::Infallible; + + #[inline(always)] fn set_high(&mut self) -> Result<(), Self::Error> { - // NOTE(unsafe) atomic write to a stateless register - unsafe { self.block().bsrr.write(|w| w.bits(1 << self.pin_id())) }; + self.set_high(); + Ok(()) + } + + #[inline(always)] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low(); Ok(()) } } impl StatefulOutputPin for Pin> { + #[inline(always)] fn is_set_high(&self) -> Result { - self.is_set_low().map(|v| !v) + Ok(self.is_set_high()) } + #[inline(always)] fn is_set_low(&self) -> Result { - // NOTE(unsafe) atomic read with no side effects - Ok(self.block().odr.read().bits() & (1 << self.pin_id()) == 0) + Ok(self.is_set_low()) } } -impl toggleable::Default for Pin> {} +impl ToggleableOutputPin for Pin> { + type Error = Infallible; + + #[inline(always)] + fn toggle(&mut self) -> Result<(), Self::Error> { + self.toggle(); + Ok(()) + } +} + +impl Pin> { + #[inline(always)] + fn is_high(&self) -> bool { + !self.is_low() + } + + #[inline(always)] + fn is_low(&self) -> bool { + self.block().idr.read().bits() & (1 << self.pin_id()) == 0 + } +} impl InputPin for Pin> { type Error = core::convert::Infallible; + #[inline(always)] fn is_high(&self) -> Result { - self.is_low().map(|v| !v) + Ok(self.is_high()) } + #[inline(always)] fn is_low(&self) -> Result { - Ok(self.block().idr.read().bits() & (1 << self.pin_id()) == 0) + Ok(self.is_low()) + } +} + +impl Pin> { + #[inline(always)] + fn is_high(&self) -> bool { + !self.is_low() + } + + #[inline(always)] + fn is_low(&self) -> bool { + self.block().idr.read().bits() & (1 << self.pin_id()) == 0 } } impl InputPin for Pin> { type Error = core::convert::Infallible; + #[inline(always)] fn is_high(&self) -> Result { - self.is_low().map(|v| !v) + Ok(self.is_high()) } + #[inline(always)] fn is_low(&self) -> Result { - Ok(self.block().idr.read().bits() & (1 << self.pin_id()) == 0) + Ok(self.is_low()) } } @@ -1210,11 +1803,6 @@ impl Gpio

{ } } -#[allow(path_statements)] -const fn less_than_16() { - Assert::::LESS; -} - /// Const assert hack struct Assert; diff --git a/src/prelude.rs b/src/prelude.rs index afd54394..bd1c4eda 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -36,11 +36,28 @@ //! ``` //! use stm32f4xx_hal::prelude::*; //! ``` -pub use embedded_hal::digital::v2::InputPin as _embedded_hal_digital_v2_InputPin; -pub use embedded_hal::digital::v2::OutputPin as _embedded_hal_digital_v2_OutputPin; -pub use embedded_hal::digital::v2::StatefulOutputPin as _embedded_hal_digital_v2_StatefulOutputPin; -pub use embedded_hal::digital::v2::ToggleableOutputPin as _embedded_hal_digital_v2_ToggleableOutputPin; -pub use embedded_hal::prelude::*; +pub use embedded_hal::adc::OneShot as _embedded_hal_adc_OneShot; +pub use embedded_hal::blocking::delay::DelayMs as _embedded_hal_blocking_delay_DelayMs; +pub use embedded_hal::blocking::delay::DelayUs as _embedded_hal_blocking_delay_DelayUs; +pub use embedded_hal::blocking::i2c::{ + Read as _embedded_hal_blocking_i2c_Read, Write as _embedded_hal_blocking_i2c_Write, + WriteRead as _embedded_hal_blocking_i2c_WriteRead, +}; +pub use embedded_hal::blocking::serial::Write as _embedded_hal_blocking_serial_Write; +pub use embedded_hal::blocking::spi::{ + Transfer as _embedded_hal_blocking_spi_Transfer, Write as _embedded_hal_blocking_spi_Write, +}; +pub use embedded_hal::serial::Read as _embedded_hal_serial_Read; +pub use embedded_hal::serial::Write as _embedded_hal_serial_Write; +pub use embedded_hal::spi::FullDuplex as _embedded_hal_spi_FullDuplex; +pub use embedded_hal::timer::CountDown as _embedded_hal_timer_CountDown; +pub use embedded_hal::watchdog::Watchdog as _embedded_hal_watchdog_Watchdog; +pub use embedded_hal::watchdog::WatchdogDisable as _embedded_hal_watchdog_WatchdogDisable; +pub use embedded_hal::watchdog::WatchdogEnable as _embedded_hal_watchdog_WatchdogEnable; +pub use embedded_hal::Capture as _embedded_hal_Capture; +pub use embedded_hal::Pwm as _embedded_hal_Pwm; +pub use embedded_hal::PwmPin as _embedded_hal_PwmPin; +pub use embedded_hal::Qei as _embedded_hal_Qei; #[cfg(all(feature = "device-selected", feature = "dac"))] pub use crate::dac::DacExt as _stm32f4xx_hal_dac_DacExt;