From 22f7f9ce4f41b1c5e8d553ed89b87ed814e67220 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Mon, 31 Jan 2022 18:02:53 +0300 Subject: [PATCH 1/9] both embedded-hals for gpio --- CHANGELOG.md | 1 + Cargo.toml | 4 + src/gpio.rs | 1 + src/gpio/hal_1.rs | 333 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 339 insertions(+) create mode 100644 src/gpio/hal_1.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index f004b597..f2da704d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Pwm channels now constants [#432] - Add channel events, make Event use bitflags (simplify interrupt handling) [#425] - reexport `digital::v2::PinState` again [#428] +- reexport `digital::v2::PinState` again - Timer impls with time based on `fugit` moved to `fugit` module, added `Pwm` and `fugit-timer` impls [#423] ### Fixed diff --git a/Cargo.toml b/Cargo.toml index 05d66d44..571d6b96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,10 @@ embedded-storage = "0.2" version = "0.3" default-features = false +[dependencies.embedded-hal-one] +version = "=1.0.0-alpha.6" +package = "embedded-hal" + [dependencies.stm32_i2s_v12x] version = "0.2.0" optional = true diff --git a/src/gpio.rs b/src/gpio.rs index 0d711dc2..5181db35 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -70,6 +70,7 @@ pub use erased::{EPin, ErasedPin}; mod dynamic; pub use dynamic::{Dynamic, DynamicPin}; mod hal_02; +mod hal_1; pub use embedded_hal::digital::v2::PinState; diff --git a/src/gpio/hal_1.rs b/src/gpio/hal_1.rs new file mode 100644 index 00000000..91a06155 --- /dev/null +++ b/src/gpio/hal_1.rs @@ -0,0 +1,333 @@ +use core::convert::Infallible; + +use super::{ + ErasedPin, Floating, Input, OpenDrain, Output, PartiallyErasedPin, Pin, PullDown, PullUp, + PushPull, +}; + +use embedded_hal_one::digital::blocking::{ + InputPin, IoPin, OutputPin, StatefulOutputPin, ToggleableOutputPin, +}; +pub use embedded_hal_one::digital::PinState; + +fn into_state(state: PinState) -> super::PinState { + match state { + PinState::Low => super::PinState::Low, + PinState::High => super::PinState::High, + } +} + +// Implementations for `Pin` + +impl OutputPin for Pin, 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 Pin, P, N> { + #[inline(always)] + fn is_set_high(&self) -> Result { + Ok(self.is_set_high()) + } + + #[inline(always)] + fn is_set_low(&self) -> Result { + Ok(self.is_set_low()) + } +} + +impl ToggleableOutputPin for Pin, P, N> { + type Error = Infallible; + + #[inline(always)] + fn toggle(&mut self) -> Result<(), Self::Error> { + self.toggle(); + Ok(()) + } +} + +impl InputPin for Pin, P, N> { + type Error = Infallible; + + #[inline(always)] + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + #[inline(always)] + fn is_low(&self) -> Result { + Ok(self.is_low()) + } +} + +impl InputPin for Pin, P, N> { + type Error = Infallible; + + #[inline(always)] + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + #[inline(always)] + fn is_low(&self) -> Result { + Ok(self.is_low()) + } +} + +impl IoPin for Pin, P, N> { + type Error = Infallible; + fn into_input_pin(self) -> Result { + Ok(self) + } + fn into_output_pin(mut self, state: PinState) -> Result { + self.set_state(into_state(state)); + Ok(self) + } +} + +impl IoPin, P, N>, Self> + for Pin, P, N> +{ + type Error = Infallible; + fn into_input_pin(self) -> Result, P, N>, Self::Error> { + Ok(self.into_floating_input()) + } + fn into_output_pin(mut self, state: PinState) -> Result { + self.set_state(into_state(state)); + Ok(self) + } +} + +impl IoPin, P, N>> + for Pin, P, N> +{ + type Error = Infallible; + fn into_input_pin(self) -> Result { + Ok(self) + } + fn into_output_pin(self, state: PinState) -> Result, P, N>, Self::Error> { + Ok(self.into_open_drain_output_in_state(into_state(state))) + } +} + +impl IoPin, P, N>, Self> + for Pin, P, N> +{ + type Error = Infallible; + fn into_input_pin(self) -> Result, P, N>, Self::Error> { + Ok(self.into_floating_input()) + } + fn into_output_pin(mut self, state: PinState) -> Result { + self.set_state(into_state(state)); + Ok(self) + } +} + +impl IoPin, P, N>> + for Pin, P, N> +{ + type Error = Infallible; + fn into_input_pin(self) -> Result { + Ok(self) + } + fn into_output_pin(self, state: PinState) -> Result, P, N>, Self::Error> { + Ok(self.into_push_pull_output_in_state(into_state(state))) + } +} + +impl IoPin, P, N>, Self> + for Pin, P, N> +{ + type Error = Infallible; + fn into_input_pin(self) -> Result, P, N>, Self::Error> { + Ok(self.into_pull_up_input()) + } + fn into_output_pin(mut self, state: PinState) -> Result { + self.set_state(into_state(state)); + Ok(self) + } +} + +impl IoPin, P, N>> + for Pin, P, N> +{ + type Error = Infallible; + fn into_input_pin(self) -> Result { + Ok(self) + } + fn into_output_pin(self, state: PinState) -> Result, P, N>, Self::Error> { + Ok(self.into_push_pull_output_in_state(into_state(state))) + } +} + +impl IoPin, P, N>, Self> + for Pin, P, N> +{ + type Error = Infallible; + fn into_input_pin(self) -> Result, P, N>, Self::Error> { + Ok(self.into_pull_down_input()) + } + fn into_output_pin(mut self, state: PinState) -> Result { + self.set_state(into_state(state)); + Ok(self) + } +} + +impl IoPin, P, N>> + for Pin, P, N> +{ + type Error = Infallible; + fn into_input_pin(self) -> Result { + Ok(self) + } + fn into_output_pin(self, state: PinState) -> Result, P, N>, Self::Error> { + Ok(self.into_push_pull_output_in_state(into_state(state))) + } +} + +// Implementations for `ErasedPin` + +impl OutputPin for ErasedPin> { + type Error = core::convert::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 ErasedPin> { + #[inline(always)] + fn is_set_high(&self) -> Result { + Ok(self.is_set_high()) + } + + #[inline(always)] + fn is_set_low(&self) -> Result { + Ok(self.is_set_low()) + } +} + +impl ToggleableOutputPin for ErasedPin> { + type Error = Infallible; + + #[inline(always)] + fn toggle(&mut self) -> Result<(), Self::Error> { + self.toggle(); + Ok(()) + } +} + +impl InputPin for ErasedPin> { + type Error = core::convert::Infallible; + + #[inline(always)] + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + #[inline(always)] + fn is_low(&self) -> Result { + Ok(self.is_low()) + } +} + +impl InputPin for ErasedPin> { + type Error = core::convert::Infallible; + + #[inline(always)] + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + #[inline(always)] + fn is_low(&self) -> Result { + Ok(self.is_low()) + } +} + +// Implementations for `PartiallyErasedPin` + +impl OutputPin for PartiallyErasedPin, 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 PartiallyErasedPin, P> { + #[inline(always)] + fn is_set_high(&self) -> Result { + Ok(self.is_set_high()) + } + + #[inline(always)] + fn is_set_low(&self) -> Result { + Ok(self.is_set_low()) + } +} + +impl ToggleableOutputPin for PartiallyErasedPin, P> { + type Error = Infallible; + + #[inline(always)] + fn toggle(&mut self) -> Result<(), Self::Error> { + self.toggle(); + Ok(()) + } +} + +impl InputPin for PartiallyErasedPin, P> { + type Error = Infallible; + + #[inline(always)] + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + #[inline(always)] + fn is_low(&self) -> Result { + Ok(self.is_low()) + } +} + +impl InputPin for PartiallyErasedPin, P> { + type Error = Infallible; + + #[inline(always)] + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + #[inline(always)] + fn is_low(&self) -> Result { + Ok(self.is_low()) + } +} From 80867154cc5a6fba6f5e0f3d6e1d78508607e9d1 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 19 Nov 2021 11:19:01 +0300 Subject: [PATCH 2/9] both embedded-hals for serial --- src/serial.rs | 1 + src/serial/hal_02.rs | 40 ++------ src/serial/hal_1.rs | 222 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 231 insertions(+), 32 deletions(-) create mode 100644 src/serial/hal_1.rs diff --git a/src/serial.rs b/src/serial.rs index d24aebfc..77ffc315 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -23,6 +23,7 @@ use crate::rcc; use nb::block; mod hal_02; +mod hal_1; use crate::gpio::{Const, PinA, PushPull, SetAlternate}; diff --git a/src/serial/hal_02.rs b/src/serial/hal_02.rs index e08fcb56..d1baf90d 100644 --- a/src/serial/hal_02.rs +++ b/src/serial/hal_02.rs @@ -14,10 +14,7 @@ mod nb { } } - impl Read for Rx - where - USART: Instance, - { + impl Read for Rx { type Error = Error; fn read(&mut self) -> nb::Result { @@ -31,10 +28,7 @@ mod nb { /// If the UART/USART was configured with `WordLength::DataBits9`, the returned value will contain /// 9 received data bits and all other bits set to zero. Otherwise, the returned value will contain /// 8 received data bits and all other bits set to zero. - impl Read for Rx - where - USART: Instance, - { + impl Read for Rx { type Error = Error; fn read(&mut self) -> nb::Result { @@ -83,10 +77,7 @@ mod nb { } } - impl Write for Tx - where - USART: Instance, - { + impl Write for Tx { type Error = Error; fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { @@ -105,10 +96,7 @@ mod nb { /// If the UART/USART was configured with `WordLength::DataBits9`, the 9 least significant bits will /// be transmitted and the other 7 bits will be ignored. Otherwise, the 8 least significant bits /// will be transmitted and the other 8 bits will be ignored. - impl Write for Tx - where - USART: Instance, - { + impl Write for Tx { type Error = Error; fn write(&mut self, word: u16) -> nb::Result<(), Self::Error> { @@ -141,10 +129,7 @@ mod blocking { use super::super::{Error, Instance, Serial, Tx}; use embedded_hal::{blocking::serial::Write, serial}; - impl Write for Tx - where - USART: Instance, - { + impl Write for Tx { type Error = Error; fn bwrite_all(&mut self, bytes: &[u8]) -> Result<(), Self::Error> { @@ -171,10 +156,7 @@ mod blocking { } } - impl Write for Serial - where - USART: Instance, - { + impl Write for Serial { type Error = Error; fn bwrite_all(&mut self, bytes: &[u8]) -> Result<(), Self::Error> { @@ -186,10 +168,7 @@ mod blocking { } } - impl Write for Tx - where - USART: Instance, - { + impl Write for Tx { type Error = Error; fn bwrite_all(&mut self, buffer: &[u16]) -> Result<(), Self::Error> { @@ -216,10 +195,7 @@ mod blocking { } } - impl Write for Serial - where - USART: Instance, - { + impl Write for Serial { type Error = Error; fn bwrite_all(&mut self, bytes: &[u16]) -> Result<(), Self::Error> { diff --git a/src/serial/hal_1.rs b/src/serial/hal_1.rs new file mode 100644 index 00000000..3510c425 --- /dev/null +++ b/src/serial/hal_1.rs @@ -0,0 +1,222 @@ +use embedded_hal_one::serial::{Error, ErrorKind}; + +impl Error for super::Error { + fn kind(&self) -> ErrorKind { + match self { + Self::Overrun => ErrorKind::Overrun, + Self::Framing => ErrorKind::FrameFormat, + Self::Parity => ErrorKind::Parity, + Self::Noise => ErrorKind::Noise, + } + } +} + +mod nb { + use super::super::{Error, Instance, Rx, Serial, Tx}; + use embedded_hal_one::serial::nb::{Read, Write}; + + impl Read for Serial + where + USART: Instance, + Rx: Read, + { + type Error = Error; + + fn read(&mut self) -> nb::Result { + self.rx.read() + } + } + + impl Read for Rx { + type Error = Error; + + fn read(&mut self) -> nb::Result { + // Delegate to the Read implementation, then truncate to 8 bits + Rx::::new().read().map(|word16| word16 as u8) + } + } + + /// Reads 9-bit words from the UART/USART + /// + /// If the UART/USART was configured with `WordLength::DataBits9`, the returned value will contain + /// 9 received data bits and all other bits set to zero. Otherwise, the returned value will contain + /// 8 received data bits and all other bits set to zero. + impl Read for Rx { + type Error = Error; + + fn read(&mut self) -> nb::Result { + // NOTE(unsafe) atomic read with no side effects + let sr = unsafe { (*USART::ptr()).sr.read() }; + + // Any error requires the dr to be read to clear + if sr.pe().bit_is_set() + || sr.fe().bit_is_set() + || sr.nf().bit_is_set() + || sr.ore().bit_is_set() + { + unsafe { (*USART::ptr()).dr.read() }; + } + + Err(if sr.pe().bit_is_set() { + Error::Parity.into() + } else if sr.fe().bit_is_set() { + Error::Framing.into() + } else if sr.nf().bit_is_set() { + Error::Noise.into() + } else if sr.ore().bit_is_set() { + Error::Overrun.into() + } else if sr.rxne().bit_is_set() { + // NOTE(unsafe) atomic read from stateless register + return Ok(unsafe { &*USART::ptr() }.dr.read().dr().bits()); + } else { + nb::Error::WouldBlock + }) + } + } + + impl Write for Serial + where + USART: Instance, + Tx: Write, + { + type Error = Error; + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + self.tx.flush() + } + + fn write(&mut self, byte: WORD) -> nb::Result<(), Self::Error> { + self.tx.write(byte) + } + } + + impl Write for Tx { + type Error = Error; + + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + // Delegate to u16 version + Tx::::new().write(u16::from(word)) + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + // Delegate to u16 version + Tx::::new().flush() + } + } + + /// Writes 9-bit words to the UART/USART + /// + /// If the UART/USART was configured with `WordLength::DataBits9`, the 9 least significant bits will + /// be transmitted and the other 7 bits will be ignored. Otherwise, the 8 least significant bits + /// will be transmitted and the other 8 bits will be ignored. + impl Write for Tx { + type Error = Error; + + fn write(&mut self, word: u16) -> nb::Result<(), Self::Error> { + // NOTE(unsafe) atomic read with no side effects + let sr = unsafe { (*USART::ptr()).sr.read() }; + + if sr.txe().bit_is_set() { + // NOTE(unsafe) atomic write to stateless register + unsafe { &*USART::ptr() }.dr.write(|w| w.dr().bits(word)); + Ok(()) + } else { + Err(nb::Error::WouldBlock) + } + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + // NOTE(unsafe) atomic read with no side effects + let sr = unsafe { (*USART::ptr()).sr.read() }; + + if sr.tc().bit_is_set() { + Ok(()) + } else { + Err(nb::Error::WouldBlock) + } + } + } +} + +mod blocking { + use super::super::{Error, Instance, Serial, Tx}; + use embedded_hal_one::serial::{self, blocking::Write}; + + impl Write for Tx { + type Error = Error; + + fn write(&mut self, bytes: &[u8]) -> Result<(), Self::Error> { + for &b in bytes { + loop { + match >::write(self, b) { + Err(nb::Error::WouldBlock) => continue, + Err(nb::Error::Other(err)) => return Err(err), + Ok(()) => break, + } + } + } + Ok(()) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + loop { + match >::flush(self) { + Ok(()) => return Ok(()), + Err(nb::Error::WouldBlock) => continue, + Err(nb::Error::Other(err)) => return Err(err), + } + } + } + } + + impl Write for Serial { + type Error = Error; + + fn write(&mut self, bytes: &[u8]) -> Result<(), Self::Error> { + self.tx.write(bytes) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.tx.flush() + } + } + + impl Write for Tx { + type Error = Error; + + fn write(&mut self, buffer: &[u16]) -> Result<(), Self::Error> { + for &b in buffer { + loop { + match >::write(self, b) { + Err(nb::Error::WouldBlock) => continue, + Err(nb::Error::Other(err)) => return Err(err), + Ok(()) => break, + } + } + } + Ok(()) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + loop { + match >::flush(self) { + Ok(()) => return Ok(()), + Err(nb::Error::WouldBlock) => continue, + Err(nb::Error::Other(err)) => return Err(err), + } + } + } + } + + impl Write for Serial { + type Error = Error; + + fn write(&mut self, bytes: &[u16]) -> Result<(), Self::Error> { + self.tx.write(bytes) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.tx.flush() + } + } +} From 68f11c7dd6ab6f2d0b64ab1a4aebd8992e43821f Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 19 Nov 2021 12:05:22 +0300 Subject: [PATCH 3/9] both embedded-hals for ADC --- src/adc.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/adc.rs b/src/adc.rs index 2ca130e1..21bcc030 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -34,6 +34,11 @@ macro_rules! adc_pins { type ID = u8; fn channel() -> u8 { $chan } } + + impl embedded_hal_one::adc::nb::Channel for $pin { + type ID = u8; + fn channel(&self) -> u8 { $chan } + } )+ }; } @@ -1070,6 +1075,17 @@ macro_rules! adc { } } + impl embedded_hal_one::adc::nb::OneShot for Adc + where + PIN: embedded_hal::adc::Channel + embedded_hal_one::adc::nb::Channel, + { + type Error = (); + + fn read(&mut self, pin: &mut PIN) -> nb::Result { + self.read::(pin) + } + } + unsafe impl PeriAddress for Adc { #[inline(always)] fn address(&self) -> u32 { From ece537f924a6f59c970a6b5befdebbd6f80dcb4f Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 19 Nov 2021 14:26:30 +0300 Subject: [PATCH 4/9] both embedded-hals for I2C --- src/fmpi2c.rs | 43 +++++++------ src/fmpi2c/hal_1.rs | 148 ++++++++++++++++++++++++++++++++++++++++++++ src/i2c.rs | 43 +++++++++++-- src/i2c/hal_1.rs | 91 +++++++++++++++++++++++++++ 4 files changed, 301 insertions(+), 24 deletions(-) create mode 100644 src/fmpi2c/hal_1.rs create mode 100644 src/i2c/hal_1.rs diff --git a/src/fmpi2c.rs b/src/fmpi2c.rs index 4f01cd4d..3a8b9044 100644 --- a/src/fmpi2c.rs +++ b/src/fmpi2c.rs @@ -1,12 +1,12 @@ use core::ops::Deref; -use crate::gpio::{Const, OpenDrain, PinA, SetAlternate}; -use crate::i2c::{Error, Scl, Sda}; +use crate::i2c::{Error, Pins}; use crate::pac::{fmpi2c1, FMPI2C1, RCC}; use crate::rcc::{Enable, Reset}; use crate::time::{Hertz, U32Ext}; mod hal_02; +mod hal_1; /// I2C FastMode+ abstraction pub struct FMPI2c { @@ -67,12 +67,11 @@ where } } -impl FMPI2c +impl FMPI2c where - SCL: PinA> + SetAlternate, - SDA: PinA> + SetAlternate, + PINS: Pins, { - pub fn new>(i2c: FMPI2C1, mut pins: (SCL, SDA), mode: M) -> Self { + pub fn new>(i2c: FMPI2C1, mut pins: PINS, mode: M) -> Self { unsafe { // NOTE(unsafe) this reference will only be used for atomic writes with no side effects. let rcc = &(*RCC::ptr()); @@ -84,17 +83,15 @@ where rcc.dckcfgr2.modify(|_, w| w.fmpi2c1sel().hsi()); } - pins.0.set_alt_mode(); - pins.1.set_alt_mode(); + pins.set_alt_mode(); let i2c = FMPI2c { i2c, pins }; i2c.i2c_init(mode); i2c } - pub fn release(mut self) -> (FMPI2C1, (SCL, SDA)) { - self.pins.0.restore_mode(); - self.pins.1.restore_mode(); + pub fn release(mut self) -> (FMPI2C1, PINS) { + self.pins.restore_mode(); (self.i2c, self.pins) } @@ -181,21 +178,24 @@ where // Wait until we're ready for sending while { let isr = self.i2c.isr.read(); - self.check_and_clear_error_flags(&isr)?; + self.check_and_clear_error_flags(&isr) + .map_err(Error::nack_addr)?; isr.txis().bit_is_clear() } {} // Push out a byte of data self.i2c.txdr.write(|w| unsafe { w.bits(u32::from(byte)) }); - self.check_and_clear_error_flags(&self.i2c.isr.read())?; + self.check_and_clear_error_flags(&self.i2c.isr.read()) + .map_err(Error::nack_data)?; Ok(()) } fn recv_byte(&self) -> Result { while { let isr = self.i2c.isr.read(); - self.check_and_clear_error_flags(&isr)?; + self.check_and_clear_error_flags(&isr) + .map_err(Error::nack_data)?; isr.rxne().bit_is_clear() } {} @@ -226,7 +226,8 @@ where } // Check and clear flags if they somehow ended up set - self.check_and_clear_error_flags(&self.i2c.isr.read())?; + self.check_and_clear_error_flags(&self.i2c.isr.read()) + .map_err(Error::nack_data)?; Ok(()) } @@ -253,7 +254,8 @@ where } // Check and clear flags if they somehow ended up set - self.check_and_clear_error_flags(&self.i2c.isr.read())?; + self.check_and_clear_error_flags(&self.i2c.isr.read()) + .map_err(Error::nack_data)?; Ok(()) } @@ -277,7 +279,8 @@ where // Wait until the transmit buffer is empty and there hasn't been any error condition while { let isr = self.i2c.isr.read(); - self.check_and_clear_error_flags(&isr)?; + self.check_and_clear_error_flags(&isr) + .map_err(Error::nack_addr)?; isr.txis().bit_is_clear() && isr.tc().bit_is_clear() } {} @@ -289,7 +292,8 @@ where // Wait until data was sent while { let isr = self.i2c.isr.read(); - self.check_and_clear_error_flags(&isr)?; + self.check_and_clear_error_flags(&isr) + .map_err(Error::nack_data)?; isr.tc().bit_is_clear() } {} @@ -315,7 +319,8 @@ where } // Check and clear flags if they somehow ended up set - self.check_and_clear_error_flags(&self.i2c.isr.read())?; + self.check_and_clear_error_flags(&self.i2c.isr.read()) + .map_err(Error::nack_data)?; Ok(()) } diff --git a/src/fmpi2c/hal_1.rs b/src/fmpi2c/hal_1.rs new file mode 100644 index 00000000..9a7237a5 --- /dev/null +++ b/src/fmpi2c/hal_1.rs @@ -0,0 +1,148 @@ +mod blocking { + use super::super::{fmpi2c1, Error, FMPI2c}; + use core::ops::Deref; + use embedded_hal_one::i2c::blocking::{Read, Write, WriteRead}; + + impl WriteRead for FMPI2c + where + I2C: Deref, + { + type Error = Error; + + fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { + // Set up current slave address for writing and disable autoending + self.i2c.cr2.modify(|_, w| { + w.sadd() + .bits(u16::from(addr) << 1) + .nbytes() + .bits(bytes.len() as u8) + .rd_wrn() + .clear_bit() + .autoend() + .clear_bit() + }); + + // Send a START condition + self.i2c.cr2.modify(|_, w| w.start().set_bit()); + + // Wait until the transmit buffer is empty and there hasn't been any error condition + while { + let isr = self.i2c.isr.read(); + self.check_and_clear_error_flags(&isr) + .map_err(Error::nack_addr)?; + isr.txis().bit_is_clear() && isr.tc().bit_is_clear() + } {} + + // Send out all individual bytes + for c in bytes { + self.send_byte(*c)?; + } + + // Wait until data was sent + while { + let isr = self.i2c.isr.read(); + self.check_and_clear_error_flags(&isr) + .map_err(Error::nack_data)?; + isr.tc().bit_is_clear() + } {} + + // Set up current address for reading + self.i2c.cr2.modify(|_, w| { + w.sadd() + .bits(u16::from(addr) << 1) + .nbytes() + .bits(buffer.len() as u8) + .rd_wrn() + .set_bit() + }); + + // Send another START condition + self.i2c.cr2.modify(|_, w| w.start().set_bit()); + + // Send the autoend after setting the start to get a restart + self.i2c.cr2.modify(|_, w| w.autoend().set_bit()); + + // Now read in all bytes + for c in buffer.iter_mut() { + *c = self.recv_byte()?; + } + + // Check and clear flags if they somehow ended up set + self.check_and_clear_error_flags(&self.i2c.isr.read()) + .map_err(Error::nack_data)?; + + Ok(()) + } + } + + impl Read for FMPI2c + where + I2C: Deref, + { + type Error = Error; + + fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> { + // Set up current address for reading + self.i2c.cr2.modify(|_, w| { + w.sadd() + .bits(u16::from(addr) << 1) + .nbytes() + .bits(buffer.len() as u8) + .rd_wrn() + .set_bit() + }); + + // Send a START condition + self.i2c.cr2.modify(|_, w| w.start().set_bit()); + + // Send the autoend after setting the start to get a restart + self.i2c.cr2.modify(|_, w| w.autoend().set_bit()); + + // Now read in all bytes + for c in buffer.iter_mut() { + *c = self.recv_byte()?; + } + + // Check and clear flags if they somehow ended up set + self.check_and_clear_error_flags(&self.i2c.isr.read()) + .map_err(Error::nack_data)?; + + Ok(()) + } + } + + impl Write for FMPI2c + where + I2C: Deref, + { + type Error = Error; + + fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { + // Set up current slave address for writing and enable autoending + self.i2c.cr2.modify(|_, w| { + w.sadd() + .bits(u16::from(addr) << 1) + .nbytes() + .bits(bytes.len() as u8) + .rd_wrn() + .clear_bit() + .autoend() + .set_bit() + }); + + // Send a START condition + self.i2c.cr2.modify(|_, w| w.start().set_bit()); + + // Send out all individual bytes + for c in bytes { + self.send_byte(*c)?; + } + + // Check and clear flags if they somehow ended up set + self.check_and_clear_error_flags(&self.i2c.isr.read()) + .map_err(Error::nack_data)?; + + Ok(()) + } + } +} diff --git a/src/i2c.rs b/src/i2c.rs index 579cfa17..f1cde145 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -10,6 +10,7 @@ use crate::rcc::Clocks; use crate::time::{Hertz, U32Ext}; mod hal_02; +mod hal_1; #[derive(Debug, Eq, PartialEq)] pub enum DutyCycle { @@ -99,9 +100,12 @@ where } #[derive(Debug, Eq, PartialEq, Copy, Clone)] +#[non_exhaustive] pub enum Error { OVERRUN, NACK, + NACK_ADDR, + NACK_DATA, TIMEOUT, // Note: The BUS error type is not currently returned, but is maintained for backwards // compatibility. @@ -110,6 +114,21 @@ pub enum Error { ARBITRATION, } +impl Error { + pub(crate) fn nack_addr(self) -> Self { + match self { + Error::NACK => Error::NACK_ADDR, + e => e, + } + } + pub(crate) fn nack_data(self) -> Self { + match self { + Error::NACK => Error::NACK_DATA, + e => e, + } + } +} + pub trait Instance: crate::Sealed + Deref + Enable + Reset {} impl Instance for pac::I2C1 {} @@ -281,7 +300,9 @@ impl I2c { // Wait until address was sent loop { // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. - let sr1 = self.check_and_clear_error_flags()?; + let sr1 = self + .check_and_clear_error_flags() + .map_err(Error::nack_addr)?; // Wait for the address to be acknowledged if sr1.addr().bit_is_set() { @@ -304,14 +325,24 @@ impl I2c { fn send_byte(&self, byte: u8) -> Result<(), Error> { // Wait until we're ready for sending // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. - while self.check_and_clear_error_flags()?.tx_e().bit_is_clear() {} + while self + .check_and_clear_error_flags() + .map_err(Error::nack_addr)? + .tx_e() + .bit_is_clear() + {} // Push out a byte of data self.i2c.dr.write(|w| unsafe { w.bits(u32::from(byte)) }); // Wait until byte is transferred // Check for any potential error conditions. - while self.check_and_clear_error_flags()?.btf().bit_is_clear() {} + while self + .check_and_clear_error_flags() + .map_err(Error::nack_data)? + .btf() + .bit_is_clear() + {} Ok(()) } @@ -319,7 +350,8 @@ impl I2c { fn recv_byte(&self) -> Result { loop { // Check for any potential error conditions. - self.check_and_clear_error_flags()?; + self.check_and_clear_error_flags() + .map_err(Error::nack_data)?; if self.i2c.sr1.read().rx_ne().bit_is_set() { break; @@ -353,7 +385,8 @@ impl I2c { // Wait until address was sent loop { - self.check_and_clear_error_flags()?; + self.check_and_clear_error_flags() + .map_err(Error::nack_addr)?; if self.i2c.sr1.read().addr().bit_is_set() { break; } diff --git a/src/i2c/hal_1.rs b/src/i2c/hal_1.rs new file mode 100644 index 00000000..9d95f81b --- /dev/null +++ b/src/i2c/hal_1.rs @@ -0,0 +1,91 @@ +use embedded_hal_one::i2c::{Error, ErrorKind, NoAcknowledgeSource}; + +impl Error for super::Error { + fn kind(&self) -> ErrorKind { + match self { + Self::OVERRUN => ErrorKind::Overrun, + Self::BUS => ErrorKind::Bus, + Self::ARBITRATION => ErrorKind::ArbitrationLoss, + Self::NACK_ADDR => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Address), + Self::NACK_DATA => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Data), + Self::NACK => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Unknown), + Self::CRC | Self::TIMEOUT => ErrorKind::Other, + } + } +} + +mod blocking { + use super::super::{Error, I2c, Instance}; + use embedded_hal_one::i2c::blocking::{Read, Write, WriteIter, WriteIterRead, WriteRead}; + + impl WriteRead for I2c + where + I2C: Instance, + { + type Error = Error; + + fn write_read( + &mut self, + addr: u8, + bytes: &[u8], + buffer: &mut [u8], + ) -> Result<(), Self::Error> { + self.write_read(addr, bytes, buffer) + } + } + + impl WriteIterRead for I2c + where + I2C: Instance, + { + type Error = Error; + + fn write_iter_read( + &mut self, + addr: u8, + bytes: B, + buffer: &mut [u8], + ) -> Result<(), Self::Error> + where + B: IntoIterator, + { + self.write_iter_read(addr, bytes, buffer) + } + } + + impl Write for I2c + where + I2C: Instance, + { + type Error = Error; + + fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { + self.write(addr, bytes) + } + } + + impl WriteIter for I2c + where + I2C: Instance, + { + type Error = Error; + + fn write_iter(&mut self, addr: u8, bytes: B) -> Result<(), Self::Error> + where + B: IntoIterator, + { + self.write_iter(addr, bytes) + } + } + + impl Read for I2c + where + I2C: Instance, + { + type Error = Error; + + fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { + self.read(addr, buffer) + } + } +} From 3f24a9dd2764b9a2478ce19d29a174d526192029 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 19 Nov 2021 15:02:06 +0300 Subject: [PATCH 5/9] both embedded-hals for PwmPin --- src/pwm.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/pwm.rs b/src/pwm.rs index fa1749f0..25b4b8ae 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -2,7 +2,7 @@ use crate::{ time::{Hertz, U32Ext}, timer::{compute_arr_presc, Channel, Instance, Ocm, Timer, WithPwm}, }; -use core::marker::PhantomData; +use core::{convert::Infallible, marker::PhantomData}; pub trait Pins { const C1: bool = false; @@ -146,6 +146,27 @@ impl embedded_hal::PwmPin for PwmChannel { } } +impl embedded_hal_one::pwm::blocking::PwmPin for PwmChannel { + type Error = Infallible; + type Duty = u16; + + fn disable(&mut self) -> Result<(), Self::Error> { + Ok(self.disable()) + } + fn enable(&mut self) -> Result<(), Self::Error> { + Ok(self.enable()) + } + fn get_duty(&self) -> Result { + Ok(self.get_duty()) + } + fn get_max_duty(&self) -> Result { + Ok(self.get_max_duty()) + } + fn set_duty(&mut self, duty: Self::Duty) -> Result<(), Self::Error> { + Ok(self.set_duty(duty)) + } +} + impl Timer { pub fn pwm(mut self, _pins: PINS, freq: T) -> Pwm where From 7bd7ff43207810337f34859c84719f9b0cfe756c Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 19 Nov 2021 15:41:50 +0300 Subject: [PATCH 6/9] both embedded-hals for Delay --- src/delay/hal_1.rs | 96 ++++++++++++++++++++++++++++++++++++++++++++++ src/delay/mod.rs | 1 + src/dwt.rs | 20 ++++++++++ 3 files changed, 117 insertions(+) create mode 100644 src/delay/hal_1.rs diff --git a/src/delay/hal_1.rs b/src/delay/hal_1.rs new file mode 100644 index 00000000..3faae666 --- /dev/null +++ b/src/delay/hal_1.rs @@ -0,0 +1,96 @@ +//! Delay implementation based on general-purpose 32 bit timers and System timer (SysTick). +//! +//! TIM2 and TIM5 are a general purpose 32-bit auto-reload up/downcounter with +//! a 16-bit prescaler. + +use cast::u16; +use core::convert::Infallible; +use cortex_m::peripheral::SYST; +use embedded_hal_one::delay::blocking::DelayUs; + +use super::{Delay, Wait}; + +impl DelayUs for Delay { + type Error = Infallible; + + fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> { + // The SysTick Reload Value register supports values between 1 and 0x00FFFFFF. + const MAX_RVR: u32 = 0x00FF_FFFF; + + let mut total_rvr = us * (self.clk.0 / 8_000_000); + + while total_rvr != 0 { + let current_rvr = if total_rvr <= MAX_RVR { + total_rvr + } else { + MAX_RVR + }; + + self.tim.set_reload(current_rvr); + self.tim.clear_current(); + self.tim.enable_counter(); + + // Update the tracking variable while we are waiting... + total_rvr -= current_rvr; + + while !self.tim.has_wrapped() {} + + self.tim.disable_counter(); + } + + Ok(()) + } + + fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> { + self.delay_us(ms * 1_000) + } +} + +impl DelayUs for Delay +where + Self: Wait, +{ + type Error = Infallible; + + /// Sleep for up to 2^32-1 microseconds (~71 minutes). + fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> { + // Set up prescaler so that a tick takes exactly 1 µs. + // + // For example, if the clock is set to 48 MHz, with a prescaler of 48 + // we'll get ticks that are 1 µs long. This means that we can write the + // delay value directly to the auto-reload register (ARR). + let psc = u16(self.clk.0 / 1_000_000).expect("Prescaler does not fit in u16"); + let arr = us; + self.wait(psc, arr); + + Ok(()) + } + + /// Sleep for up to (2^32)/2-1 milliseconds (~24 days). + /// If the `ms` value is larger than 2147483647, the code will panic. + fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> { + // See next section for explanation why the usable range is reduced. + assert!(ms <= 2_147_483_647); // (2^32)/2-1 + + // Set up prescaler so that a tick takes exactly 0.5 ms. + // + // For example, if the clock is set to 48 MHz, with a prescaler of 24'000 + // we'll get ticks that are 0.5 ms long. This means that we can write the + // delay value multipled by two to the auto-reload register (ARR). + // + // Note that we cannot simply use a prescaler value where the tick corresponds + // to 1 ms, because then a clock of 100 MHz would correspond to a prescaler + // value of 100'000, which doesn't fit in the 16-bit PSC register. + // + // Unfortunately this means that only one half of the full 32-bit range + // can be used, but 24 days should be plenty of usable delay time. + let psc = u16(self.clk.0 / 1000 / 2).expect("Prescaler does not fit in u16"); + + // Since PSC = 0.5 ms, double the value for the ARR + let arr = ms << 1; + + self.wait(psc, arr); + + Ok(()) + } +} diff --git a/src/delay/mod.rs b/src/delay/mod.rs index 08a8a7dc..6a54aa18 100644 --- a/src/delay/mod.rs +++ b/src/delay/mod.rs @@ -1,6 +1,7 @@ //! Delays mod hal_02; +mod hal_1; use crate::{ pac, diff --git a/src/dwt.rs b/src/dwt.rs index cd472c9c..497224db 100644 --- a/src/dwt.rs +++ b/src/dwt.rs @@ -114,6 +114,26 @@ impl> embedded_hal::blocking::delay::DelayMs for Delay { } } +impl embedded_hal_one::delay::blocking::DelayUs for Delay { + type Error = core::convert::Infallible; + + fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> { + // Convert us to ticks + let start = DWT::cycle_count(); + let ticks = (us as u64 * self.clock.0 as u64) / 1_000_000; + Delay::delay_ticks(start, ticks); + Ok(()) + } + + fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> { + // Convert ms to ticks + let start = DWT::cycle_count(); + let ticks = (ms as u64 * self.clock.0 as u64) / 1_000; + Delay::delay_ticks(start, ticks); + Ok(()) + } +} + /// Very simple stopwatch which reads from DWT Cycle Counter to record timing. /// /// Since DWT Cycle Counter is a 32-bit counter that wraps around to 0 on overflow, From c9d58c6d39cc7ff41f423e122602615a10e01574 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 19 Nov 2021 16:42:45 +0300 Subject: [PATCH 7/9] both embedded-hals for Qei --- src/qei.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/qei.rs b/src/qei.rs index 8328a061..6ad27262 100644 --- a/src/qei.rs +++ b/src/qei.rs @@ -59,6 +59,23 @@ impl embedded_hal::Qei for Qei { } } +impl embedded_hal_one::qei::blocking::Qei for Qei { + type Error = core::convert::Infallible; + type Count = TIM::Width; + + fn count(&self) -> Result { + Ok(self.tim.read_count() as Self::Count) + } + + fn direction(&self) -> Result { + Ok(if self.tim.read_direction() { + embedded_hal_one::qei::Direction::Upcounting + } else { + embedded_hal_one::qei::Direction::Downcounting + }) + } +} + pub trait Instance: crate::Sealed + rcc::Enable + rcc::Reset + General { fn setup_qei(&mut self); From 4ccd6851bcc7329151234b7711b5ee0f3e2039b0 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 19 Nov 2021 13:13:48 +0300 Subject: [PATCH 8/9] both embedded-hals for SPI --- src/spi.rs | 1 + src/spi/hal_1.rs | 191 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 src/spi/hal_1.rs diff --git a/src/spi.rs b/src/spi.rs index 14d019ef..b26c17b7 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -34,6 +34,7 @@ pub struct Mode { } mod hal_02; +mod hal_1; use crate::pac::{spi1, RCC}; use crate::rcc; diff --git a/src/spi/hal_1.rs b/src/spi/hal_1.rs new file mode 100644 index 00000000..24c4a807 --- /dev/null +++ b/src/spi/hal_1.rs @@ -0,0 +1,191 @@ +pub use embedded_hal_one::spi::{Error, ErrorKind, Mode, Phase, Polarity}; + +impl From for super::Polarity { + fn from(p: Polarity) -> Self { + match p { + Polarity::IdleLow => Self::IdleLow, + Polarity::IdleHigh => Self::IdleHigh, + } + } +} + +impl From for super::Phase { + fn from(p: Phase) -> Self { + match p { + Phase::CaptureOnFirstTransition => Self::CaptureOnFirstTransition, + Phase::CaptureOnSecondTransition => Self::CaptureOnSecondTransition, + } + } +} + +impl From for super::Mode { + fn from(m: Mode) -> Self { + Self { + polarity: m.polarity.into(), + phase: m.phase.into(), + } + } +} + +impl Error for super::Error { + fn kind(&self) -> ErrorKind { + match self { + Self::Overrun => ErrorKind::Overrun, + Self::ModeFault => ErrorKind::ModeFault, + Self::Crc => ErrorKind::Other, + } + } +} + +mod nb { + use super::super::{Error, Instance, Spi, TransferModeBidi, TransferModeNormal}; + use embedded_hal_one::spi::nb::FullDuplex; + + impl FullDuplex for Spi + where + SPI: Instance, + { + type Error = Error; + + fn read(&mut self) -> nb::Result { + self.check_read() + } + + fn write(&mut self, byte: u8) -> nb::Result<(), Error> { + self.check_send(byte) + } + } + + impl FullDuplex for Spi + where + SPI: Instance, + { + type Error = Error; + + fn read(&mut self) -> nb::Result { + self.spi.cr1.modify(|_, w| w.bidioe().clear_bit()); + self.check_read() + } + + fn write(&mut self, byte: u8) -> nb::Result<(), Error> { + self.spi.cr1.modify(|_, w| w.bidioe().set_bit()); + self.check_send(byte) + } + } +} + +mod blocking { + use super::super::{Error, Instance, Spi, TransferModeBidi, TransferModeNormal}; + use embedded_hal_one::spi::{ + blocking::{Operation, Transactional, TransferInplace, Write, WriteIter}, + nb::FullDuplex, + }; + + impl TransferInplace for Spi + where + Self: FullDuplex, + SPI: Instance, + { + type Error = Error; + + fn transfer_inplace(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + for word in words.iter_mut() { + nb::block!(self.write(*word))?; + *word = nb::block!(self.read())?; + } + + Ok(()) + } + } + + impl Write for Spi + where + Self: FullDuplex, + SPI: Instance, + { + type Error = Error; + + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + for word in words { + nb::block!(>::write(self, *word))?; + nb::block!(self.read())?; + } + + Ok(()) + } + } + + impl Write for Spi + where + Self: FullDuplex, + SPI: Instance, + { + type Error = Error; + + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + for word in words { + nb::block!(>::write(self, *word))?; + } + + Ok(()) + } + } + + impl WriteIter for Spi + where + Self: FullDuplex, + SPI: Instance, + { + type Error = Error; + + fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> + where + WI: IntoIterator, + { + for word in words.into_iter() { + nb::block!(>::write(self, word))?; + nb::block!(self.read())?; + } + + Ok(()) + } + } + + impl WriteIter for Spi + where + Self: FullDuplex, + SPI: Instance, + { + type Error = Error; + + fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> + where + WI: IntoIterator, + { + for word in words.into_iter() { + nb::block!(>::write(self, word))?; + } + + Ok(()) + } + } + + impl Transactional for Spi + where + Self: Write + TransferInplace, + { + type Error = Error; + + fn exec<'a>(&mut self, operations: &mut [Operation<'a, W>]) -> Result<(), Error> { + for op in operations { + match op { + Operation::Write(w) => self.write(w)?, + Operation::TransferInplace(t) => self.transfer_inplace(t)?, + _ => todo!(), + } + } + + Ok(()) + } + } +} From 46ed47edd738f85eadb76d4817d95002d0873f71 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 19 Nov 2021 17:01:10 +0300 Subject: [PATCH 9/9] changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2da704d..441f0759 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added + +- Support of embedded-hal 1.0.0-alpha.6 [#388] + +[#388]: https://github.com/stm32-rs/stm32f4xx-hal/pull/388 + ### Changed - Add inherent impl of `embedded_hal::Pwm` methods on `Pwm`s [#439]