From 9015920a34ab8793b16b2fb1732fb857fc717aca Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Thu, 1 Jul 2021 06:00:57 +0300 Subject: [PATCH 1/5] inherent gpio impls --- src/gpio.rs | 323 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 264 insertions(+), 59 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index f855190c..1642782d 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; @@ -223,62 +223,130 @@ 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)] + 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)] + 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))) - }; - Ok(()) + } + } + + #[inline(always)] + fn is_set_high(&self) -> bool { + !self.is_set_low() + } + + #[inline(always)] + 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> { + Ok(self.set_high()) + } + + #[inline(always)] + fn set_low(&mut self) -> Result<(), Self::Error> { + Ok(self.set_low()) } } 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 toggleable::Default for PXx, P> {} +impl ToggleableOutputPin for PXx, P> { + type Error = Infallible; + + #[inline(always)] + fn toggle(&mut self) -> Result<(), Self::Error> { + Ok(self.toggle()) + } +} + +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()) } } @@ -329,14 +397,21 @@ impl PinExt for PX { impl PX { /// Configures the pin to operate alternate mode pub fn into_alternate(self) -> PX>, P, N> { - less_than_16::(); + #[allow(path_statements)] + { + 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)] + { + Assert::::LESS; + } _set_alternate_mode::(); PX::new().set_open_drain() } @@ -754,62 +829,130 @@ 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)] + 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)] + fn set_low(&mut self) { // NOTE(unsafe) atomic write to a stateless register unsafe { (*Gpio::

::ptr()) .bsrr .write(|w| w.bits(1 << ({ N } + 16))) - }; - Ok(()) + } + } + + #[inline(always)] + fn is_set_high(&self) -> bool { + !self.is_set_low() + } + + #[inline(always)] + 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> { + Ok(self.set_high()) + } + + #[inline(always)] + fn set_low(&mut self) -> Result<(), Self::Error> { + Ok(self.set_low()) } } 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> { + Ok(self.toggle()) + } +} + +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 +1269,127 @@ impl Pin { } } -impl OutputPin for Pin> { - type Error = core::convert::Infallible; +impl Pin> { + #[inline(always)] + 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)] + 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)] + fn is_set_high(&self) -> bool { + !self.is_set_low() + } + + #[inline(always)] + 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())) }; - Ok(()) + Ok(self.set_high()) + } + + #[inline(always)] + fn set_low(&mut self) -> Result<(), Self::Error> { + Ok(self.set_low()) } } 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 ToggleableOutputPin for Pin> { + type Error = Infallible; + + #[inline(always)] + fn toggle(&mut self) -> Result<(), Self::Error> { + Ok(self.toggle()) } } -impl toggleable::Default for Pin> {} +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 +1420,6 @@ impl Gpio

{ } } -#[allow(path_statements)] -const fn less_than_16() { - Assert::::LESS; -} - /// Const assert hack struct Assert; From 84c881d7371b315914f0cf9a5438cb0f35cf6756 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Thu, 1 Jul 2021 17:58:20 +0300 Subject: [PATCH 2/5] prelude & examples --- examples/analog-stopwatch-with-spi-ssd1306.rs | 22 +++++++-------- examples/blinky-timer-irq.rs | 1 - examples/delay-blinky.rs | 4 +-- examples/dwt-blinky.rs | 8 +++--- examples/f413disco_lcd_ferris.rs | 2 +- examples/i2s-audio-out-dma.rs | 2 +- examples/i2s-audio-out.rs | 2 +- examples/qei.rs | 4 +-- examples/rtic.rs | 2 +- examples/serial-9bit.rs | 16 +++++------ examples/ssd1306-image.rs | 4 +-- examples/st7789-lcd.rs | 10 +++---- src/gpio.rs | 24 ++++++++--------- src/prelude.rs | 27 +++++++++++++++---- 14 files changed, 72 insertions(+), 56 deletions(-) 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 1642782d..436ad4d7 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -225,13 +225,13 @@ impl PinExt for PXx { impl PXx, P> { #[inline(always)] - fn set_high(&mut self) { + 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)) } } #[inline(always)] - fn set_low(&mut self) { + pub fn set_low(&mut self) { // NOTE(unsafe) atomic write to a stateless register unsafe { (*Gpio::

::ptr()) @@ -241,12 +241,12 @@ impl PXx, P> { } #[inline(always)] - fn is_set_high(&self) -> bool { + pub fn is_set_high(&self) -> bool { !self.is_set_low() } #[inline(always)] - fn is_set_low(&self) -> bool { + 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 } } @@ -831,13 +831,13 @@ impl PX { impl PX, P, N> { #[inline(always)] - fn set_high(&mut self) { + pub fn set_high(&mut self) { // NOTE(unsafe) atomic write to a stateless register unsafe { (*Gpio::

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

::ptr()) @@ -847,12 +847,12 @@ impl PX, P, N> { } #[inline(always)] - fn is_set_high(&self) -> bool { + pub fn is_set_high(&self) -> bool { !self.is_set_low() } #[inline(always)] - fn is_set_low(&self) -> bool { + pub fn is_set_low(&self) -> bool { // NOTE(unsafe) atomic read with no side effects unsafe { (*Gpio::

::ptr()).odr.read().bits() & (1 << { N }) == 0 } } @@ -1271,13 +1271,13 @@ impl Pin { impl Pin> { #[inline(always)] - fn set_high(&mut self) { + 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())) }; } #[inline(always)] - fn set_low(&mut self) { + pub fn set_low(&mut self) { // NOTE(unsafe) atomic write to a stateless register unsafe { self.block() @@ -1287,12 +1287,12 @@ impl Pin> { } #[inline(always)] - fn is_set_high(&self) -> bool { + pub fn is_set_high(&self) -> bool { !self.is_set_low() } #[inline(always)] - fn is_set_low(&self) -> bool { + pub fn is_set_low(&self) -> bool { self.block().odr.read().bits() & (1 << self.pin_id()) == 0 } 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; From 47964cab74be1c1fab823d02a9215fac95796e22 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Thu, 1 Jul 2021 18:46:08 +0300 Subject: [PATCH 3/5] PinState --- CHANGELOG.md | 2 ++ src/gpio.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) 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/src/gpio.rs b/src/gpio.rs index 436ad4d7..89d87e48 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -81,6 +81,15 @@ 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 pub enum Speed { Low = 0, @@ -240,6 +249,23 @@ impl PXx, P> { } } + #[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() @@ -846,6 +872,23 @@ impl PX, P, N> { } } + #[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() @@ -1286,6 +1329,23 @@ impl Pin> { }; } + #[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() From 7886776383a50dc809d482ade7c908b73c98a5da Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 2 Jul 2021 06:08:16 +0300 Subject: [PATCH 4/5] clippy --- src/gpio.rs | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index 89d87e48..70cc2d4d 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -91,6 +91,7 @@ pub enum PinState { } /// GPIO Pin speed selection +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Speed { Low = 0, Medium = 1, @@ -98,7 +99,7 @@ pub enum Speed { VeryHigh = 3, } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Edge { RISING, FALLING, @@ -292,12 +293,14 @@ impl OutputPin for PXx, P> { #[inline(always)] fn set_high(&mut self) -> Result<(), Self::Error> { - Ok(self.set_high()) + self.set_high(); + Ok(()) } #[inline(always)] fn set_low(&mut self) -> Result<(), Self::Error> { - Ok(self.set_low()) + self.set_low(); + Ok(()) } } @@ -318,7 +321,8 @@ impl ToggleableOutputPin for PXx, P> { #[inline(always)] fn toggle(&mut self) -> Result<(), Self::Error> { - Ok(self.toggle()) + self.toggle(); + Ok(()) } } @@ -423,7 +427,7 @@ impl PinExt for PX { impl PX { /// Configures the pin to operate alternate mode pub fn into_alternate(self) -> PX>, P, N> { - #[allow(path_statements)] + #[allow(path_statements, clippy::no_effect)] { Assert::::LESS; } @@ -434,7 +438,7 @@ impl PX { /// Configures the pin to operate in alternate open drain mode #[allow(path_statements)] pub fn into_alternate_open_drain(self) -> PX>, P, N> { - #[allow(path_statements)] + #[allow(path_statements, clippy::no_effect)] { Assert::::LESS; } @@ -915,12 +919,14 @@ impl OutputPin for PX, P, N> { #[inline(always)] fn set_high(&mut self) -> Result<(), Self::Error> { - Ok(self.set_high()) + self.set_high(); + Ok(()) } #[inline(always)] fn set_low(&mut self) -> Result<(), Self::Error> { - Ok(self.set_low()) + self.set_low(); + Ok(()) } } @@ -941,7 +947,8 @@ impl ToggleableOutputPin for PX, #[inline(always)] fn toggle(&mut self) -> Result<(), Self::Error> { - Ok(self.toggle()) + self.toggle(); + Ok(()) } } @@ -1371,12 +1378,14 @@ impl OutputPin for Pin> { #[inline(always)] fn set_high(&mut self) -> Result<(), Self::Error> { - Ok(self.set_high()) + self.set_high(); + Ok(()) } #[inline(always)] fn set_low(&mut self) -> Result<(), Self::Error> { - Ok(self.set_low()) + self.set_low(); + Ok(()) } } @@ -1397,7 +1406,8 @@ impl ToggleableOutputPin for Pin> { #[inline(always)] fn toggle(&mut self) -> Result<(), Self::Error> { - Ok(self.toggle()) + self.toggle(); + Ok(()) } } From 747f1e6a156c8f19d3e23abb035aeb6d38d80508 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 2 Jul 2021 06:48:56 +0300 Subject: [PATCH 5/5] impl From for MODEs --- src/gpio.rs | 313 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 313 insertions(+) diff --git a/src/gpio.rs b/src/gpio.rs index 70cc2d4d..fb636113 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -424,6 +424,319 @@ 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> {