From b1d2595860384e9d63ef0bdab8ee64576ad9be8c Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Mon, 31 Jan 2022 18:02:53 +0300 Subject: [PATCH 01/10] 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 ca0c0aa2..cbcdb9a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,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 4e0d245056fbf1961ca3d2bc23b7fc4bf8601202 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 19 Nov 2021 11:19:01 +0300 Subject: [PATCH 02/10] 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 e5eaa829180da02af92f4cec8aa5f5c996ffb0c5 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 19 Nov 2021 12:05:22 +0300 Subject: [PATCH 03/10] 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 0116cafd3d1735f5792fa60b33e92ff0c25317ee Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 19 Nov 2021 14:26:30 +0300 Subject: [PATCH 04/10] 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 cd8f93bff6b139cd38e36602db16f56bb11983d3 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 19 Nov 2021 15:02:06 +0300 Subject: [PATCH 05/10] 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 723d3eee14c348cab3005d4b930c4ff9ef152a7b Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 19 Nov 2021 15:41:50 +0300 Subject: [PATCH 06/10] 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 723620dbf618bcbbfec50d816e0b0b25ddaedcd9 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 19 Nov 2021 16:42:45 +0300 Subject: [PATCH 07/10] 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 119ed38aeb9d036abf30437d368f4b2c0f5e00f9 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 19 Nov 2021 13:13:48 +0300 Subject: [PATCH 08/10] 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 e6cee3b92156a55dc5cd117314f63a8c274069ed Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 19 Nov 2021 17:01:10 +0300 Subject: [PATCH 09/10] alpha.7 --- CHANGELOG.md | 2 +- Cargo.toml | 4 +- src/fmpi2c/hal_1.rs | 181 ++++++++++++-------------------------------- src/fugit/hal_1.rs | 17 +++++ src/fugit/mod.rs | 1 + src/gpio/hal_1.rs | 40 ++++------ src/i2c/hal_1.rs | 76 ++++++++----------- src/pwm.rs | 23 +----- src/qei.rs | 17 ----- src/serial/hal_1.rs | 49 ++++++------ src/spi/hal_1.rs | 24 ++---- 11 files changed, 144 insertions(+), 290 deletions(-) create mode 100644 src/fugit/hal_1.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index cbcdb9a0..a2c72af7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,6 @@ 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 @@ -29,6 +28,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added - Missing `DelayMs` / `DelayUs` impls for fugit::Delay +- Support of embedded-hal 1.0.0-alpha.7 - Aliases for peripheral wrappers [#434] - `WithPwm` trait implemented for timers with channels (internals) [#425] - `Pwm` struct with `split` method and implementation of embedded-hal::Pwm (similar to f1xx-hal) [#425] diff --git a/Cargo.toml b/Cargo.toml index 571d6b96..88a5a8b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ embedded-dma = "0.2.0" bare-metal = { version = "1" } cast = { default-features = false, version = "0.3.0" } void = { default-features = false, version = "1.0.2" } -embedded-hal = { features = ["unproven"], version = "0.2.6" } +embedded-hal = { features = ["unproven"], version = "0.2.7" } display-interface = { version = "0.4.1", optional = true } fugit = "0.3.3" fugit-timer = "0.1.3" @@ -52,7 +52,7 @@ version = "0.3" default-features = false [dependencies.embedded-hal-one] -version = "=1.0.0-alpha.6" +version = "1.0.0-alpha.7" package = "embedded-hal" [dependencies.stm32_i2s_v12x] diff --git a/src/fmpi2c/hal_1.rs b/src/fmpi2c/hal_1.rs index 9a7237a5..9567ca2b 100644 --- a/src/fmpi2c/hal_1.rs +++ b/src/fmpi2c/hal_1.rs @@ -1,148 +1,67 @@ +use embedded_hal_one::i2c::ErrorType; + +impl ErrorType for super::FMPI2c { + type Error = super::Error; +} + mod blocking { - use super::super::{fmpi2c1, Error, FMPI2c}; + use super::super::{fmpi2c1, FMPI2c}; use core::ops::Deref; - use embedded_hal_one::i2c::blocking::{Read, Write, WriteRead}; + use embedded_hal_one::i2c::blocking::Operation; - impl WriteRead for FMPI2c + impl embedded_hal_one::i2c::blocking::I2c 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(()) + fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { + self.read(addr, buffer) } - } - 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(()) + fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { + self.write(addr, bytes) } - } - 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() - }); + fn write_iter(&mut self, _addr: u8, _bytes: B) -> Result<(), Self::Error> + where + B: IntoIterator, + { + todo!() + } - // Send a START condition - self.i2c.cr2.modify(|_, w| w.start().set_bit()); + fn write_read( + &mut self, + addr: u8, + bytes: &[u8], + buffer: &mut [u8], + ) -> Result<(), Self::Error> { + self.write_read(addr, bytes, buffer) + } - // Send out all individual bytes - for c in bytes { - self.send_byte(*c)?; - } + fn write_iter_read( + &mut self, + _addr: u8, + _bytes: B, + _buffer: &mut [u8], + ) -> Result<(), Self::Error> + where + B: IntoIterator, + { + todo!() + } - // 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)?; + fn transaction<'a>( + &mut self, + _addr: u8, + _operations: &mut [Operation<'a>], + ) -> Result<(), Self::Error> { + todo!() + } - Ok(()) + fn transaction_iter<'a, O>(&mut self, _addr: u8, _operations: O) -> Result<(), Self::Error> + where + O: IntoIterator>, + { + todo!() } } } diff --git a/src/fugit/hal_1.rs b/src/fugit/hal_1.rs new file mode 100644 index 00000000..cd9f6df7 --- /dev/null +++ b/src/fugit/hal_1.rs @@ -0,0 +1,17 @@ +use super::{Delay, Error, Instance}; + +use embedded_hal_one::delay::blocking::DelayUs; + +use fugit::ExtU32; + +impl DelayUs for Delay { + type Error = Error; + + fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> { + self.delay(us.micros()) + } + + fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> { + self.delay(ms.millis()) + } +} diff --git a/src/fugit/mod.rs b/src/fugit/mod.rs index 318a9d7a..75bb8298 100644 --- a/src/fugit/mod.rs +++ b/src/fugit/mod.rs @@ -25,6 +25,7 @@ pub mod pwm; pub use pwm::*; mod hal_02; +mod hal_1; /// Timer wrapper pub struct Timer { diff --git a/src/gpio/hal_1.rs b/src/gpio/hal_1.rs index 91a06155..0998d3a3 100644 --- a/src/gpio/hal_1.rs +++ b/src/gpio/hal_1.rs @@ -5,10 +5,11 @@ use super::{ PushPull, }; -use embedded_hal_one::digital::blocking::{ - InputPin, IoPin, OutputPin, StatefulOutputPin, ToggleableOutputPin, -}; pub use embedded_hal_one::digital::PinState; +use embedded_hal_one::digital::{ + blocking::{InputPin, IoPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}, + ErrorType, +}; fn into_state(state: PinState) -> super::PinState { match state { @@ -18,10 +19,11 @@ fn into_state(state: PinState) -> super::PinState { } // Implementations for `Pin` - -impl OutputPin for Pin, P, N> { +impl ErrorType for Pin { type Error = Infallible; +} +impl OutputPin for Pin, P, N> { #[inline(always)] fn set_high(&mut self) -> Result<(), Self::Error> { self.set_high(); @@ -48,8 +50,6 @@ impl StatefulOutputPin for Pin, P } impl ToggleableOutputPin for Pin, P, N> { - type Error = Infallible; - #[inline(always)] fn toggle(&mut self) -> Result<(), Self::Error> { self.toggle(); @@ -58,8 +58,6 @@ impl ToggleableOutputPin for Pin, } impl InputPin for Pin, P, N> { - type Error = Infallible; - #[inline(always)] fn is_high(&self) -> Result { Ok(self.is_high()) @@ -72,8 +70,6 @@ impl InputPin for Pin, P, N> { } impl InputPin for Pin, P, N> { - type Error = Infallible; - #[inline(always)] fn is_high(&self) -> Result { Ok(self.is_high()) @@ -197,10 +193,11 @@ impl IoPin, P, N>> } // Implementations for `ErasedPin` - -impl OutputPin for ErasedPin> { +impl ErrorType for ErasedPin { type Error = core::convert::Infallible; +} +impl OutputPin for ErasedPin> { #[inline(always)] fn set_high(&mut self) -> Result<(), Self::Error> { self.set_high(); @@ -227,8 +224,6 @@ impl StatefulOutputPin for ErasedPin> { } impl ToggleableOutputPin for ErasedPin> { - type Error = Infallible; - #[inline(always)] fn toggle(&mut self) -> Result<(), Self::Error> { self.toggle(); @@ -237,8 +232,6 @@ impl ToggleableOutputPin for ErasedPin> { } impl InputPin for ErasedPin> { - type Error = core::convert::Infallible; - #[inline(always)] fn is_high(&self) -> Result { Ok(self.is_high()) @@ -251,8 +244,6 @@ impl InputPin for ErasedPin> { } impl InputPin for ErasedPin> { - type Error = core::convert::Infallible; - #[inline(always)] fn is_high(&self) -> Result { Ok(self.is_high()) @@ -265,10 +256,11 @@ impl InputPin for ErasedPin> { } // Implementations for `PartiallyErasedPin` - -impl OutputPin for PartiallyErasedPin, P> { +impl ErrorType for PartiallyErasedPin { type Error = Infallible; +} +impl OutputPin for PartiallyErasedPin, P> { #[inline(always)] fn set_high(&mut self) -> Result<(), Self::Error> { self.set_high(); @@ -295,8 +287,6 @@ impl StatefulOutputPin for PartiallyErasedPin, } impl ToggleableOutputPin for PartiallyErasedPin, P> { - type Error = Infallible; - #[inline(always)] fn toggle(&mut self) -> Result<(), Self::Error> { self.toggle(); @@ -305,8 +295,6 @@ impl ToggleableOutputPin for PartiallyErasedPin InputPin for PartiallyErasedPin, P> { - type Error = Infallible; - #[inline(always)] fn is_high(&self) -> Result { Ok(self.is_high()) @@ -319,8 +307,6 @@ impl InputPin for PartiallyErasedPin, P> { } impl InputPin for PartiallyErasedPin, P> { - type Error = Infallible; - #[inline(always)] fn is_high(&self) -> Result { Ok(self.is_high()) diff --git a/src/i2c/hal_1.rs b/src/i2c/hal_1.rs index 9d95f81b..30ea3260 100644 --- a/src/i2c/hal_1.rs +++ b/src/i2c/hal_1.rs @@ -1,4 +1,4 @@ -use embedded_hal_one::i2c::{Error, ErrorKind, NoAcknowledgeSource}; +use embedded_hal_one::i2c::{Error, ErrorKind, ErrorType, NoAcknowledgeSource}; impl Error for super::Error { fn kind(&self) -> ErrorKind { @@ -14,15 +14,29 @@ impl Error for super::Error { } } +impl ErrorType for super::I2c { + type Error = super::Error; +} + mod blocking { - use super::super::{Error, I2c, Instance}; - use embedded_hal_one::i2c::blocking::{Read, Write, WriteIter, WriteIterRead, WriteRead}; + use super::super::{I2c, Instance}; + use embedded_hal_one::i2c::blocking::Operation; + + impl embedded_hal_one::i2c::blocking::I2c for I2c { + fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { + self.read(addr, buffer) + } + + fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { + self.write(addr, bytes) + } - impl WriteRead 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) + } fn write_read( &mut self, @@ -32,13 +46,6 @@ mod blocking { ) -> 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, @@ -51,41 +58,20 @@ mod blocking { { 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) + fn transaction<'a>( + &mut self, + _addr: u8, + _operations: &mut [Operation<'a>], + ) -> Result<(), Self::Error> { + todo!() } - } - impl WriteIter for I2c - where - I2C: Instance, - { - type Error = Error; - - fn write_iter(&mut self, addr: u8, bytes: B) -> Result<(), Self::Error> + fn transaction_iter<'a, O>(&mut self, _addr: u8, _operations: O) -> Result<(), Self::Error> where - B: IntoIterator, + O: 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) + todo!() } } } diff --git a/src/pwm.rs b/src/pwm.rs index 25b4b8ae..fa1749f0 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::{convert::Infallible, marker::PhantomData}; +use core::marker::PhantomData; pub trait Pins { const C1: bool = false; @@ -146,27 +146,6 @@ 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 diff --git a/src/qei.rs b/src/qei.rs index 6ad27262..8328a061 100644 --- a/src/qei.rs +++ b/src/qei.rs @@ -59,23 +59,6 @@ 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); diff --git a/src/serial/hal_1.rs b/src/serial/hal_1.rs index 3510c425..1f698b46 100644 --- a/src/serial/hal_1.rs +++ b/src/serial/hal_1.rs @@ -1,4 +1,4 @@ -use embedded_hal_one::serial::{Error, ErrorKind}; +use embedded_hal_one::serial::{Error, ErrorKind, ErrorType}; impl Error for super::Error { fn kind(&self) -> ErrorKind { @@ -11,25 +11,36 @@ impl Error for super::Error { } } +impl ErrorType for super::Serial { + type Error = super::Error; +} + +impl ErrorType for super::Rx { + type Error = super::Error; +} + +impl ErrorType for super::Tx { + type Error = super::Error; +} + mod nb { use super::super::{Error, Instance, Rx, Serial, Tx}; - use embedded_hal_one::serial::nb::{Read, Write}; + use embedded_hal_one::serial::{ + nb::{Read, Write}, + ErrorType, + }; - impl Read for Serial + impl Read for Serial where USART: Instance, - Rx: Read, + Rx: Read + ErrorType, { - 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) @@ -42,8 +53,6 @@ mod nb { /// 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() }; @@ -74,13 +83,11 @@ mod nb { } } - impl Write for Serial + impl Write for Serial where USART: Instance, - Tx: Write, + Tx: Write + ErrorType, { - type Error = Error; - fn flush(&mut self) -> nb::Result<(), Self::Error> { self.tx.flush() } @@ -91,8 +98,6 @@ mod nb { } 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)) @@ -110,8 +115,6 @@ mod nb { /// 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() }; @@ -139,12 +142,10 @@ mod nb { } mod blocking { - use super::super::{Error, Instance, Serial, Tx}; + use super::super::{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 { @@ -170,8 +171,6 @@ mod blocking { } impl Write for Serial { - type Error = Error; - fn write(&mut self, bytes: &[u8]) -> Result<(), Self::Error> { self.tx.write(bytes) } @@ -182,8 +181,6 @@ mod blocking { } impl Write for Tx { - type Error = Error; - fn write(&mut self, buffer: &[u16]) -> Result<(), Self::Error> { for &b in buffer { loop { @@ -209,8 +206,6 @@ mod blocking { } impl Write for Serial { - type Error = Error; - fn write(&mut self, bytes: &[u16]) -> Result<(), Self::Error> { self.tx.write(bytes) } diff --git a/src/spi/hal_1.rs b/src/spi/hal_1.rs index 24c4a807..c6d2f686 100644 --- a/src/spi/hal_1.rs +++ b/src/spi/hal_1.rs @@ -1,4 +1,4 @@ -pub use embedded_hal_one::spi::{Error, ErrorKind, Mode, Phase, Polarity}; +pub use embedded_hal_one::spi::{Error, ErrorKind, ErrorType, Mode, Phase, Polarity}; impl From for super::Polarity { fn from(p: Polarity) -> Self { @@ -37,6 +37,10 @@ impl Error for super::Error { } } +impl ErrorType for super::Spi { + type Error = super::Error; +} + mod nb { use super::super::{Error, Instance, Spi, TransferModeBidi, TransferModeNormal}; use embedded_hal_one::spi::nb::FullDuplex; @@ -45,8 +49,6 @@ mod nb { where SPI: Instance, { - type Error = Error; - fn read(&mut self) -> nb::Result { self.check_read() } @@ -60,8 +62,6 @@ mod nb { where SPI: Instance, { - type Error = Error; - fn read(&mut self) -> nb::Result { self.spi.cr1.modify(|_, w| w.bidioe().clear_bit()); self.check_read() @@ -86,8 +86,6 @@ mod blocking { 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))?; @@ -103,8 +101,6 @@ mod blocking { 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))?; @@ -120,8 +116,6 @@ mod blocking { 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))?; @@ -136,8 +130,6 @@ mod blocking { Self: FullDuplex, SPI: Instance, { - type Error = Error; - fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> where WI: IntoIterator, @@ -156,8 +148,6 @@ mod blocking { Self: FullDuplex, SPI: Instance, { - type Error = Error; - fn write_iter(&mut self, words: WI) -> Result<(), Self::Error> where WI: IntoIterator, @@ -170,12 +160,10 @@ mod blocking { } } - impl Transactional for Spi + 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 { From c9f823ef68a08a4b6c1cd83e35beab026756e4dc Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 12 Feb 2022 12:29:50 +0300 Subject: [PATCH 10/10] use ErrorKind-like error names for I2c::Error --- CHANGELOG.md | 3 ++- src/fmpi2c.rs | 33 +++++++++++++-------------------- src/i2c.rs | 47 +++++++++++++++++++++++------------------------ src/i2c/hal_1.rs | 16 +++++++--------- 4 files changed, 45 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2c72af7..c7337d1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added - Missing `DelayMs` / `DelayUs` impls for fugit::Delay -- Support of embedded-hal 1.0.0-alpha.7 +- Support of embedded-hal 1.0.0-alpha.7 [#443] - Aliases for peripheral wrappers [#434] - `WithPwm` trait implemented for timers with channels (internals) [#425] - `Pwm` struct with `split` method and implementation of embedded-hal::Pwm (similar to f1xx-hal) [#425] @@ -51,6 +51,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). [#438]: https://github.com/stm32-rs/stm32f4xx-hal/pull/438 [#439]: https://github.com/stm32-rs/stm32f4xx-hal/pull/439 [#440]: https://github.com/stm32-rs/stm32f4xx-hal/pull/440 +[#443]: https://github.com/stm32-rs/stm32f4xx-hal/pull/443 ### Changed diff --git a/src/fmpi2c.rs b/src/fmpi2c.rs index 3a8b9044..1e7166db 100644 --- a/src/fmpi2c.rs +++ b/src/fmpi2c.rs @@ -1,6 +1,6 @@ use core::ops::Deref; -use crate::i2c::{Error, Pins}; +use crate::i2c::{Error, NoAcknowledgeSource, Pins}; use crate::pac::{fmpi2c1, FMPI2C1, RCC}; use crate::rcc::{Enable, Reset}; use crate::time::{Hertz, U32Ext}; @@ -168,12 +168,19 @@ where self.i2c .icr .write(|w| w.stopcf().set_bit().nackcf().set_bit()); - return Err(Error::NACK); + return Err(Error::NoAcknowledge(NoAcknowledgeSource::Unknown)); } Ok(()) } + fn end_transaction(&self) -> Result<(), Error> { + // 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(()) + } + fn send_byte(&self, byte: u8) -> Result<(), Error> { // Wait until we're ready for sending while { @@ -186,9 +193,7 @@ where // 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()) - .map_err(Error::nack_data)?; - Ok(()) + self.end_transaction() } fn recv_byte(&self) -> Result { @@ -225,11 +230,7 @@ where *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(()) + self.end_transaction() } pub fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { @@ -253,11 +254,7 @@ where 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(()) + self.end_transaction() } pub fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { @@ -318,10 +315,6 @@ where *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(()) + self.end_transaction() } } diff --git a/src/i2c.rs b/src/i2c.rs index f1cde145..525e2016 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -99,31 +99,34 @@ where } } +pub use embedded_hal_one::i2c::NoAcknowledgeSource; + #[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. - BUS, - CRC, - ARBITRATION, + Overrun, + NoAcknowledge(NoAcknowledgeSource), + Timeout, + // Note: The Bus error type is not currently returned, but is maintained for compatibility. + Bus, + Crc, + ArbitrationLoss, } impl Error { pub(crate) fn nack_addr(self) -> Self { match self { - Error::NACK => Error::NACK_ADDR, + Error::NoAcknowledge(NoAcknowledgeSource::Unknown) => { + Error::NoAcknowledge(NoAcknowledgeSource::Address) + } e => e, } } pub(crate) fn nack_data(self) -> Self { match self { - Error::NACK => Error::NACK_DATA, + Error::NoAcknowledge(NoAcknowledgeSource::Unknown) => { + Error::NoAcknowledge(NoAcknowledgeSource::Data) + } e => e, } } @@ -243,27 +246,27 @@ impl I2c { if sr1.timeout().bit_is_set() { self.i2c.sr1.modify(|_, w| w.timeout().clear_bit()); - return Err(Error::TIMEOUT); + return Err(Error::Timeout); } if sr1.pecerr().bit_is_set() { self.i2c.sr1.modify(|_, w| w.pecerr().clear_bit()); - return Err(Error::CRC); + return Err(Error::Crc); } if sr1.ovr().bit_is_set() { self.i2c.sr1.modify(|_, w| w.ovr().clear_bit()); - return Err(Error::OVERRUN); + return Err(Error::Overrun); } if sr1.af().bit_is_set() { self.i2c.sr1.modify(|_, w| w.af().clear_bit()); - return Err(Error::NACK); + return Err(Error::NoAcknowledge(NoAcknowledgeSource::Unknown)); } if sr1.arlo().bit_is_set() { self.i2c.sr1.modify(|_, w| w.arlo().clear_bit()); - return Err(Error::ARBITRATION); + return Err(Error::ArbitrationLoss); } // The errata indicates that BERR may be incorrectly detected. It recommends ignoring and @@ -414,7 +417,7 @@ impl I2c { // Fallthrough is success Ok(()) } else { - Err(Error::OVERRUN) + Err(Error::Overrun) } } @@ -449,9 +452,7 @@ impl I2c { pub fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { self.write_bytes(addr, bytes.iter().cloned())?; - self.read(addr, buffer)?; - - Ok(()) + self.read(addr, buffer) } pub fn write_iter_read(&mut self, addr: u8, bytes: B, buffer: &mut [u8]) -> Result<(), Error> @@ -459,8 +460,6 @@ impl I2c { B: IntoIterator, { self.write_bytes(addr, bytes.into_iter())?; - self.read(addr, buffer)?; - - Ok(()) + self.read(addr, buffer) } } diff --git a/src/i2c/hal_1.rs b/src/i2c/hal_1.rs index 30ea3260..0e0eedc1 100644 --- a/src/i2c/hal_1.rs +++ b/src/i2c/hal_1.rs @@ -1,15 +1,13 @@ -use embedded_hal_one::i2c::{Error, ErrorKind, ErrorType, NoAcknowledgeSource}; +use embedded_hal_one::i2c::{Error, ErrorKind, ErrorType}; 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, + match *self { + Self::Overrun => ErrorKind::Overrun, + Self::Bus => ErrorKind::Bus, + Self::ArbitrationLoss => ErrorKind::ArbitrationLoss, + Self::NoAcknowledge(nack) => ErrorKind::NoAcknowledge(nack), + Self::Crc | Self::Timeout => ErrorKind::Other, } } }