diff options
| -rw-r--r-- | embassy-stm32/Cargo.toml | 5 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/mod.rs | 5 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/timeout.rs | 142 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v1.rs | 123 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 221 | ||||
| -rw-r--r-- | embassy-stm32/src/lib.rs | 2 | ||||
| -rw-r--r-- | embassy-stm32/src/subghz/timeout.rs | 1 | ||||
| -rw-r--r-- | embassy-stm32/src/subghz/tx_params.rs | 1 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/i2c.rs | 45 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/i2c.rs | 44 |
10 files changed, 508 insertions, 81 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 0b88e89c9..6b00518a6 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -82,9 +82,12 @@ memory-x = ["stm32-metapac/memory-x"] | |||
| 82 | subghz = [] | 82 | subghz = [] |
| 83 | exti = [] | 83 | exti = [] |
| 84 | 84 | ||
| 85 | # Enables additional driver features that depend on embassy-time | ||
| 86 | time = ["dep:embassy-time"] | ||
| 87 | |||
| 85 | # Features starting with `_` are for internal use only. They're not intended | 88 | # Features starting with `_` are for internal use only. They're not intended |
| 86 | # to be enabled by other crates, and are not covered by semver guarantees. | 89 | # to be enabled by other crates, and are not covered by semver guarantees. |
| 87 | _time-driver = ["dep:embassy-time"] | 90 | _time-driver = ["time"] |
| 88 | time-driver-any = ["_time-driver"] | 91 | time-driver-any = ["_time-driver"] |
| 89 | time-driver-tim2 = ["_time-driver"] | 92 | time-driver-tim2 = ["_time-driver"] |
| 90 | time-driver-tim3 = ["_time-driver"] | 93 | time-driver-tim3 = ["_time-driver"] |
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 9d314f411..f898fcc8b 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs | |||
| @@ -7,6 +7,11 @@ use crate::interrupt::Interrupt; | |||
| 7 | mod _version; | 7 | mod _version; |
| 8 | pub use _version::*; | 8 | pub use _version::*; |
| 9 | 9 | ||
| 10 | #[cfg(feature = "time")] | ||
| 11 | mod timeout; | ||
| 12 | #[cfg(feature = "time")] | ||
| 13 | pub use timeout::*; | ||
| 14 | |||
| 10 | use crate::peripherals; | 15 | use crate::peripherals; |
| 11 | 16 | ||
| 12 | #[derive(Debug)] | 17 | #[derive(Debug)] |
diff --git a/embassy-stm32/src/i2c/timeout.rs b/embassy-stm32/src/i2c/timeout.rs new file mode 100644 index 000000000..4fca1ca2b --- /dev/null +++ b/embassy-stm32/src/i2c/timeout.rs | |||
| @@ -0,0 +1,142 @@ | |||
| 1 | use embassy_time::{Duration, Instant}; | ||
| 2 | |||
| 3 | use super::{Error, I2c, Instance}; | ||
| 4 | |||
| 5 | /// An I2C wrapper, which provides `embassy-time` based timeouts for all `embedded-hal` trait methods. | ||
| 6 | /// | ||
| 7 | /// This is useful for recovering from a shorted bus or a device stuck in a clock stretching state. | ||
| 8 | /// A regular [I2c] would freeze until condition is removed. | ||
| 9 | pub struct TimeoutI2c<'d, T: Instance, TXDMA, RXDMA> { | ||
| 10 | i2c: &'d mut I2c<'d, T, TXDMA, RXDMA>, | ||
| 11 | timeout: Duration, | ||
| 12 | } | ||
| 13 | |||
| 14 | fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> { | ||
| 15 | let deadline = Instant::now() + timeout; | ||
| 16 | move || { | ||
| 17 | if Instant::now() > deadline { | ||
| 18 | Err(Error::Timeout) | ||
| 19 | } else { | ||
| 20 | Ok(()) | ||
| 21 | } | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | impl<'d, T: Instance, TXDMA, RXDMA> TimeoutI2c<'d, T, TXDMA, RXDMA> { | ||
| 26 | pub fn new(i2c: &'d mut I2c<'d, T, TXDMA, RXDMA>, timeout: Duration) -> Self { | ||
| 27 | Self { i2c, timeout } | ||
| 28 | } | ||
| 29 | |||
| 30 | /// Blocking read with a custom timeout | ||
| 31 | pub fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> { | ||
| 32 | self.i2c.blocking_read_timeout(addr, buffer, timeout_fn(timeout)) | ||
| 33 | } | ||
| 34 | |||
| 35 | /// Blocking read with default timeout, provided in [`TimeoutI2c::new()`] | ||
| 36 | pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 37 | self.blocking_read_timeout(addr, buffer, self.timeout) | ||
| 38 | } | ||
| 39 | |||
| 40 | /// Blocking write with a custom timeout | ||
| 41 | pub fn blocking_write_timeout(&mut self, addr: u8, bytes: &[u8], timeout: Duration) -> Result<(), Error> { | ||
| 42 | self.i2c.blocking_write_timeout(addr, bytes, timeout_fn(timeout)) | ||
| 43 | } | ||
| 44 | |||
| 45 | /// Blocking write with default timeout, provided in [`TimeoutI2c::new()`] | ||
| 46 | pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { | ||
| 47 | self.blocking_write_timeout(addr, bytes, self.timeout) | ||
| 48 | } | ||
| 49 | |||
| 50 | /// Blocking write-read with a custom timeout | ||
| 51 | pub fn blocking_write_read_timeout( | ||
| 52 | &mut self, | ||
| 53 | addr: u8, | ||
| 54 | bytes: &[u8], | ||
| 55 | buffer: &mut [u8], | ||
| 56 | timeout: Duration, | ||
| 57 | ) -> Result<(), Error> { | ||
| 58 | self.i2c | ||
| 59 | .blocking_write_read_timeout(addr, bytes, buffer, timeout_fn(timeout)) | ||
| 60 | } | ||
| 61 | |||
| 62 | /// Blocking write-read with default timeout, provided in [`TimeoutI2c::new()`] | ||
| 63 | pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { | ||
| 64 | self.blocking_write_read_timeout(addr, bytes, buffer, self.timeout) | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read for TimeoutI2c<'d, T, TXDMA, RXDMA> { | ||
| 69 | type Error = Error; | ||
| 70 | |||
| 71 | fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
| 72 | self.blocking_read(addr, buffer) | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write for TimeoutI2c<'d, T, TXDMA, RXDMA> { | ||
| 77 | type Error = Error; | ||
| 78 | |||
| 79 | fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { | ||
| 80 | self.blocking_write(addr, bytes) | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead for TimeoutI2c<'d, T, TXDMA, RXDMA> { | ||
| 85 | type Error = Error; | ||
| 86 | |||
| 87 | fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
| 88 | self.blocking_write_read(addr, bytes, buffer) | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | #[cfg(feature = "unstable-traits")] | ||
| 93 | mod eh1 { | ||
| 94 | use super::*; | ||
| 95 | |||
| 96 | impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for TimeoutI2c<'d, T, TXDMA, RXDMA> { | ||
| 97 | type Error = Error; | ||
| 98 | } | ||
| 99 | |||
| 100 | impl<'d, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::I2c for TimeoutI2c<'d, T, TXDMA, RXDMA> { | ||
| 101 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
| 102 | self.blocking_read(address, buffer) | ||
| 103 | } | ||
| 104 | |||
| 105 | fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 106 | self.blocking_write(address, buffer) | ||
| 107 | } | ||
| 108 | |||
| 109 | fn write_iter<B>(&mut self, _address: u8, _bytes: B) -> Result<(), Self::Error> | ||
| 110 | where | ||
| 111 | B: IntoIterator<Item = u8>, | ||
| 112 | { | ||
| 113 | todo!(); | ||
| 114 | } | ||
| 115 | |||
| 116 | fn write_iter_read<B>(&mut self, _address: u8, _bytes: B, _buffer: &mut [u8]) -> Result<(), Self::Error> | ||
| 117 | where | ||
| 118 | B: IntoIterator<Item = u8>, | ||
| 119 | { | ||
| 120 | todo!(); | ||
| 121 | } | ||
| 122 | |||
| 123 | fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
| 124 | self.blocking_write_read(address, wr_buffer, rd_buffer) | ||
| 125 | } | ||
| 126 | |||
| 127 | fn transaction<'a>( | ||
| 128 | &mut self, | ||
| 129 | _address: u8, | ||
| 130 | _operations: &mut [embedded_hal_1::i2c::Operation<'a>], | ||
| 131 | ) -> Result<(), Self::Error> { | ||
| 132 | todo!(); | ||
| 133 | } | ||
| 134 | |||
| 135 | fn transaction_iter<'a, O>(&mut self, _address: u8, _operations: O) -> Result<(), Self::Error> | ||
| 136 | where | ||
| 137 | O: IntoIterator<Item = embedded_hal_1::i2c::Operation<'a>>, | ||
| 138 | { | ||
| 139 | todo!(); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | } | ||
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index f39a37df6..f140e2b0d 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs | |||
| @@ -1,8 +1,9 @@ | |||
| 1 | use core::marker::PhantomData; | 1 | use core::marker::PhantomData; |
| 2 | 2 | ||
| 3 | use embassy_embedded_hal::SetConfig; | 3 | use embassy_embedded_hal::SetConfig; |
| 4 | use embassy_hal_common::into_ref; | 4 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 5 | 5 | ||
| 6 | use crate::dma::NoDma; | ||
| 6 | use crate::gpio::sealed::AFType; | 7 | use crate::gpio::sealed::AFType; |
| 7 | use crate::gpio::Pull; | 8 | use crate::gpio::Pull; |
| 8 | use crate::i2c::{Error, Instance, SclPin, SdaPin}; | 9 | use crate::i2c::{Error, Instance, SclPin, SdaPin}; |
| @@ -34,19 +35,26 @@ impl State { | |||
| 34 | } | 35 | } |
| 35 | } | 36 | } |
| 36 | 37 | ||
| 37 | pub struct I2c<'d, T: Instance> { | 38 | pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { |
| 38 | phantom: PhantomData<&'d mut T>, | 39 | phantom: PhantomData<&'d mut T>, |
| 40 | #[allow(dead_code)] | ||
| 41 | tx_dma: PeripheralRef<'d, TXDMA>, | ||
| 42 | #[allow(dead_code)] | ||
| 43 | rx_dma: PeripheralRef<'d, RXDMA>, | ||
| 39 | } | 44 | } |
| 40 | 45 | ||
| 41 | impl<'d, T: Instance> I2c<'d, T> { | 46 | impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { |
| 42 | pub fn new( | 47 | pub fn new( |
| 43 | _peri: impl Peripheral<P = T> + 'd, | 48 | _peri: impl Peripheral<P = T> + 'd, |
| 44 | scl: impl Peripheral<P = impl SclPin<T>> + 'd, | 49 | scl: impl Peripheral<P = impl SclPin<T>> + 'd, |
| 45 | sda: impl Peripheral<P = impl SdaPin<T>> + 'd, | 50 | sda: impl Peripheral<P = impl SdaPin<T>> + 'd, |
| 51 | _irq: impl Peripheral<P = T::Interrupt> + 'd, | ||
| 52 | tx_dma: impl Peripheral<P = TXDMA> + 'd, | ||
| 53 | rx_dma: impl Peripheral<P = RXDMA> + 'd, | ||
| 46 | freq: Hertz, | 54 | freq: Hertz, |
| 47 | config: Config, | 55 | config: Config, |
| 48 | ) -> Self { | 56 | ) -> Self { |
| 49 | into_ref!(scl, sda); | 57 | into_ref!(scl, sda, tx_dma, rx_dma); |
| 50 | 58 | ||
| 51 | T::enable(); | 59 | T::enable(); |
| 52 | T::reset(); | 60 | T::reset(); |
| @@ -99,7 +107,11 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 99 | }); | 107 | }); |
| 100 | } | 108 | } |
| 101 | 109 | ||
| 102 | Self { phantom: PhantomData } | 110 | Self { |
| 111 | phantom: PhantomData, | ||
| 112 | tx_dma, | ||
| 113 | rx_dma, | ||
| 114 | } | ||
| 103 | } | 115 | } |
| 104 | 116 | ||
| 105 | unsafe fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> { | 117 | unsafe fn check_and_clear_error_flags(&self) -> Result<i2c::regs::Sr1, Error> { |
| @@ -141,7 +153,12 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 141 | Ok(sr1) | 153 | Ok(sr1) |
| 142 | } | 154 | } |
| 143 | 155 | ||
| 144 | unsafe fn write_bytes(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { | 156 | unsafe fn write_bytes( |
| 157 | &mut self, | ||
| 158 | addr: u8, | ||
| 159 | bytes: &[u8], | ||
| 160 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 161 | ) -> Result<(), Error> { | ||
| 145 | // Send a START condition | 162 | // Send a START condition |
| 146 | 163 | ||
| 147 | T::regs().cr1().modify(|reg| { | 164 | T::regs().cr1().modify(|reg| { |
| @@ -149,7 +166,9 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 149 | }); | 166 | }); |
| 150 | 167 | ||
| 151 | // Wait until START condition was generated | 168 | // Wait until START condition was generated |
| 152 | while !self.check_and_clear_error_flags()?.start() {} | 169 | while !self.check_and_clear_error_flags()?.start() { |
| 170 | check_timeout()?; | ||
| 171 | } | ||
| 153 | 172 | ||
| 154 | // Also wait until signalled we're master and everything is waiting for us | 173 | // Also wait until signalled we're master and everything is waiting for us |
| 155 | while { | 174 | while { |
| @@ -157,7 +176,9 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 157 | 176 | ||
| 158 | let sr2 = T::regs().sr2().read(); | 177 | let sr2 = T::regs().sr2().read(); |
| 159 | !sr2.msl() && !sr2.busy() | 178 | !sr2.msl() && !sr2.busy() |
| 160 | } {} | 179 | } { |
| 180 | check_timeout()?; | ||
| 181 | } | ||
| 161 | 182 | ||
| 162 | // Set up current address, we're trying to talk to | 183 | // Set up current address, we're trying to talk to |
| 163 | T::regs().dr().write(|reg| reg.set_dr(addr << 1)); | 184 | T::regs().dr().write(|reg| reg.set_dr(addr << 1)); |
| @@ -165,26 +186,30 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 165 | // Wait until address was sent | 186 | // Wait until address was sent |
| 166 | // Wait for the address to be acknowledged | 187 | // Wait for the address to be acknowledged |
| 167 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. | 188 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. |
| 168 | while !self.check_and_clear_error_flags()?.addr() {} | 189 | while !self.check_and_clear_error_flags()?.addr() { |
| 190 | check_timeout()?; | ||
| 191 | } | ||
| 169 | 192 | ||
| 170 | // Clear condition by reading SR2 | 193 | // Clear condition by reading SR2 |
| 171 | let _ = T::regs().sr2().read(); | 194 | let _ = T::regs().sr2().read(); |
| 172 | 195 | ||
| 173 | // Send bytes | 196 | // Send bytes |
| 174 | for c in bytes { | 197 | for c in bytes { |
| 175 | self.send_byte(*c)?; | 198 | self.send_byte(*c, &check_timeout)?; |
| 176 | } | 199 | } |
| 177 | 200 | ||
| 178 | // Fallthrough is success | 201 | // Fallthrough is success |
| 179 | Ok(()) | 202 | Ok(()) |
| 180 | } | 203 | } |
| 181 | 204 | ||
| 182 | unsafe fn send_byte(&self, byte: u8) -> Result<(), Error> { | 205 | unsafe fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 183 | // Wait until we're ready for sending | 206 | // Wait until we're ready for sending |
| 184 | while { | 207 | while { |
| 185 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. | 208 | // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. |
| 186 | !self.check_and_clear_error_flags()?.txe() | 209 | !self.check_and_clear_error_flags()?.txe() |
| 187 | } {} | 210 | } { |
| 211 | check_timeout()?; | ||
| 212 | } | ||
| 188 | 213 | ||
| 189 | // Push out a byte of data | 214 | // Push out a byte of data |
| 190 | T::regs().dr().write(|reg| reg.set_dr(byte)); | 215 | T::regs().dr().write(|reg| reg.set_dr(byte)); |
| @@ -193,24 +218,33 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 193 | while { | 218 | while { |
| 194 | // Check for any potential error conditions. | 219 | // Check for any potential error conditions. |
| 195 | !self.check_and_clear_error_flags()?.btf() | 220 | !self.check_and_clear_error_flags()?.btf() |
| 196 | } {} | 221 | } { |
| 222 | check_timeout()?; | ||
| 223 | } | ||
| 197 | 224 | ||
| 198 | Ok(()) | 225 | Ok(()) |
| 199 | } | 226 | } |
| 200 | 227 | ||
| 201 | unsafe fn recv_byte(&self) -> Result<u8, Error> { | 228 | unsafe fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> { |
| 202 | while { | 229 | while { |
| 203 | // Check for any potential error conditions. | 230 | // Check for any potential error conditions. |
| 204 | self.check_and_clear_error_flags()?; | 231 | self.check_and_clear_error_flags()?; |
| 205 | 232 | ||
| 206 | !T::regs().sr1().read().rxne() | 233 | !T::regs().sr1().read().rxne() |
| 207 | } {} | 234 | } { |
| 235 | check_timeout()?; | ||
| 236 | } | ||
| 208 | 237 | ||
| 209 | let value = T::regs().dr().read().dr(); | 238 | let value = T::regs().dr().read().dr(); |
| 210 | Ok(value) | 239 | Ok(value) |
| 211 | } | 240 | } |
| 212 | 241 | ||
| 213 | pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> { | 242 | pub fn blocking_read_timeout( |
| 243 | &mut self, | ||
| 244 | addr: u8, | ||
| 245 | buffer: &mut [u8], | ||
| 246 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 247 | ) -> Result<(), Error> { | ||
| 214 | if let Some((last, buffer)) = buffer.split_last_mut() { | 248 | if let Some((last, buffer)) = buffer.split_last_mut() { |
| 215 | // Send a START condition and set ACK bit | 249 | // Send a START condition and set ACK bit |
| 216 | unsafe { | 250 | unsafe { |
| @@ -221,27 +255,33 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 221 | } | 255 | } |
| 222 | 256 | ||
| 223 | // Wait until START condition was generated | 257 | // Wait until START condition was generated |
| 224 | while unsafe { !T::regs().sr1().read().start() } {} | 258 | while unsafe { !self.check_and_clear_error_flags()?.start() } { |
| 259 | check_timeout()?; | ||
| 260 | } | ||
| 225 | 261 | ||
| 226 | // Also wait until signalled we're master and everything is waiting for us | 262 | // Also wait until signalled we're master and everything is waiting for us |
| 227 | while { | 263 | while { |
| 228 | let sr2 = unsafe { T::regs().sr2().read() }; | 264 | let sr2 = unsafe { T::regs().sr2().read() }; |
| 229 | !sr2.msl() && !sr2.busy() | 265 | !sr2.msl() && !sr2.busy() |
| 230 | } {} | 266 | } { |
| 267 | check_timeout()?; | ||
| 268 | } | ||
| 231 | 269 | ||
| 232 | // Set up current address, we're trying to talk to | 270 | // Set up current address, we're trying to talk to |
| 233 | unsafe { T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)) } | 271 | unsafe { T::regs().dr().write(|reg| reg.set_dr((addr << 1) + 1)) } |
| 234 | 272 | ||
| 235 | // Wait until address was sent | 273 | // Wait until address was sent |
| 236 | // Wait for the address to be acknowledged | 274 | // Wait for the address to be acknowledged |
| 237 | while unsafe { !self.check_and_clear_error_flags()?.addr() } {} | 275 | while unsafe { !self.check_and_clear_error_flags()?.addr() } { |
| 276 | check_timeout()?; | ||
| 277 | } | ||
| 238 | 278 | ||
| 239 | // Clear condition by reading SR2 | 279 | // Clear condition by reading SR2 |
| 240 | let _ = unsafe { T::regs().sr2().read() }; | 280 | let _ = unsafe { T::regs().sr2().read() }; |
| 241 | 281 | ||
| 242 | // Receive bytes into buffer | 282 | // Receive bytes into buffer |
| 243 | for c in buffer { | 283 | for c in buffer { |
| 244 | *c = unsafe { self.recv_byte()? }; | 284 | *c = unsafe { self.recv_byte(&check_timeout)? }; |
| 245 | } | 285 | } |
| 246 | 286 | ||
| 247 | // Prepare to send NACK then STOP after next byte | 287 | // Prepare to send NACK then STOP after next byte |
| @@ -253,10 +293,12 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 253 | } | 293 | } |
| 254 | 294 | ||
| 255 | // Receive last byte | 295 | // Receive last byte |
| 256 | *last = unsafe { self.recv_byte()? }; | 296 | *last = unsafe { self.recv_byte(&check_timeout)? }; |
| 257 | 297 | ||
| 258 | // Wait for the STOP to be sent. | 298 | // Wait for the STOP to be sent. |
| 259 | while unsafe { T::regs().cr1().read().stop() } {} | 299 | while unsafe { T::regs().cr1().read().stop() } { |
| 300 | check_timeout()?; | ||
| 301 | } | ||
| 260 | 302 | ||
| 261 | // Fallthrough is success | 303 | // Fallthrough is success |
| 262 | Ok(()) | 304 | Ok(()) |
| @@ -265,25 +307,50 @@ impl<'d, T: Instance> I2c<'d, T> { | |||
| 265 | } | 307 | } |
| 266 | } | 308 | } |
| 267 | 309 | ||
| 268 | pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { | 310 | pub fn blocking_read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> { |
| 311 | self.blocking_read_timeout(addr, buffer, || Ok(())) | ||
| 312 | } | ||
| 313 | |||
| 314 | pub fn blocking_write_timeout( | ||
| 315 | &mut self, | ||
| 316 | addr: u8, | ||
| 317 | bytes: &[u8], | ||
| 318 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 319 | ) -> Result<(), Error> { | ||
| 269 | unsafe { | 320 | unsafe { |
| 270 | self.write_bytes(addr, bytes)?; | 321 | self.write_bytes(addr, bytes, &check_timeout)?; |
| 271 | // Send a STOP condition | 322 | // Send a STOP condition |
| 272 | T::regs().cr1().modify(|reg| reg.set_stop(true)); | 323 | T::regs().cr1().modify(|reg| reg.set_stop(true)); |
| 273 | // Wait for STOP condition to transmit. | 324 | // Wait for STOP condition to transmit. |
| 274 | while T::regs().cr1().read().stop() {} | 325 | while T::regs().cr1().read().stop() { |
| 326 | check_timeout()?; | ||
| 327 | } | ||
| 275 | }; | 328 | }; |
| 276 | 329 | ||
| 277 | // Fallthrough is success | 330 | // Fallthrough is success |
| 278 | Ok(()) | 331 | Ok(()) |
| 279 | } | 332 | } |
| 280 | 333 | ||
| 281 | pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { | 334 | pub fn blocking_write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { |
| 282 | unsafe { self.write_bytes(addr, bytes)? }; | 335 | self.blocking_write_timeout(addr, bytes, || Ok(())) |
| 283 | self.blocking_read(addr, buffer)?; | 336 | } |
| 337 | |||
| 338 | pub fn blocking_write_read_timeout( | ||
| 339 | &mut self, | ||
| 340 | addr: u8, | ||
| 341 | bytes: &[u8], | ||
| 342 | buffer: &mut [u8], | ||
| 343 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 344 | ) -> Result<(), Error> { | ||
| 345 | unsafe { self.write_bytes(addr, bytes, &check_timeout)? }; | ||
| 346 | self.blocking_read_timeout(addr, buffer, &check_timeout)?; | ||
| 284 | 347 | ||
| 285 | Ok(()) | 348 | Ok(()) |
| 286 | } | 349 | } |
| 350 | |||
| 351 | pub fn blocking_write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { | ||
| 352 | self.blocking_write_read_timeout(addr, bytes, buffer, || Ok(())) | ||
| 353 | } | ||
| 287 | } | 354 | } |
| 288 | 355 | ||
| 289 | impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { | 356 | impl<'d, T: Instance> embedded_hal_02::blocking::i2c::Read for I2c<'d, T> { |
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 89b52da98..aa4e6bb08 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -147,14 +147,23 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 147 | } | 147 | } |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | unsafe fn master_read(address: u8, length: usize, stop: Stop, reload: bool, restart: bool) { | 150 | unsafe fn master_read( |
| 151 | address: u8, | ||
| 152 | length: usize, | ||
| 153 | stop: Stop, | ||
| 154 | reload: bool, | ||
| 155 | restart: bool, | ||
| 156 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 157 | ) -> Result<(), Error> { | ||
| 151 | assert!(length < 256); | 158 | assert!(length < 256); |
| 152 | 159 | ||
| 153 | if !restart { | 160 | if !restart { |
| 154 | // Wait for any previous address sequence to end | 161 | // Wait for any previous address sequence to end |
| 155 | // automatically. This could be up to 50% of a bus | 162 | // automatically. This could be up to 50% of a bus |
| 156 | // cycle (ie. up to 0.5/freq) | 163 | // cycle (ie. up to 0.5/freq) |
| 157 | while T::regs().cr2().read().start() {} | 164 | while T::regs().cr2().read().start() { |
| 165 | check_timeout()?; | ||
| 166 | } | ||
| 158 | } | 167 | } |
| 159 | 168 | ||
| 160 | // Set START and prepare to receive bytes into | 169 | // Set START and prepare to receive bytes into |
| @@ -176,15 +185,25 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 176 | w.set_autoend(stop.autoend()); | 185 | w.set_autoend(stop.autoend()); |
| 177 | w.set_reload(reload); | 186 | w.set_reload(reload); |
| 178 | }); | 187 | }); |
| 188 | |||
| 189 | Ok(()) | ||
| 179 | } | 190 | } |
| 180 | 191 | ||
| 181 | unsafe fn master_write(address: u8, length: usize, stop: Stop, reload: bool) { | 192 | unsafe fn master_write( |
| 193 | address: u8, | ||
| 194 | length: usize, | ||
| 195 | stop: Stop, | ||
| 196 | reload: bool, | ||
| 197 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 198 | ) -> Result<(), Error> { | ||
| 182 | assert!(length < 256); | 199 | assert!(length < 256); |
| 183 | 200 | ||
| 184 | // Wait for any previous address sequence to end | 201 | // Wait for any previous address sequence to end |
| 185 | // automatically. This could be up to 50% of a bus | 202 | // automatically. This could be up to 50% of a bus |
| 186 | // cycle (ie. up to 0.5/freq) | 203 | // cycle (ie. up to 0.5/freq) |
| 187 | while T::regs().cr2().read().start() {} | 204 | while T::regs().cr2().read().start() { |
| 205 | check_timeout()?; | ||
| 206 | } | ||
| 188 | 207 | ||
| 189 | let reload = if reload { | 208 | let reload = if reload { |
| 190 | i2c::vals::Reload::NOTCOMPLETED | 209 | i2c::vals::Reload::NOTCOMPLETED |
| @@ -204,12 +223,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 204 | w.set_autoend(stop.autoend()); | 223 | w.set_autoend(stop.autoend()); |
| 205 | w.set_reload(reload); | 224 | w.set_reload(reload); |
| 206 | }); | 225 | }); |
| 226 | |||
| 227 | Ok(()) | ||
| 207 | } | 228 | } |
| 208 | 229 | ||
| 209 | unsafe fn master_continue(length: usize, reload: bool) { | 230 | unsafe fn master_continue( |
| 231 | length: usize, | ||
| 232 | reload: bool, | ||
| 233 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 234 | ) -> Result<(), Error> { | ||
| 210 | assert!(length < 256 && length > 0); | 235 | assert!(length < 256 && length > 0); |
| 211 | 236 | ||
| 212 | while !T::regs().isr().read().tcr() {} | 237 | while !T::regs().isr().read().tcr() { |
| 238 | check_timeout()?; | ||
| 239 | } | ||
| 213 | 240 | ||
| 214 | let reload = if reload { | 241 | let reload = if reload { |
| 215 | i2c::vals::Reload::NOTCOMPLETED | 242 | i2c::vals::Reload::NOTCOMPLETED |
| @@ -221,6 +248,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 221 | w.set_nbytes(length as u8); | 248 | w.set_nbytes(length as u8); |
| 222 | w.set_reload(reload); | 249 | w.set_reload(reload); |
| 223 | }); | 250 | }); |
| 251 | |||
| 252 | Ok(()) | ||
| 224 | } | 253 | } |
| 225 | 254 | ||
| 226 | fn flush_txdr(&self) { | 255 | fn flush_txdr(&self) { |
| @@ -243,7 +272,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 243 | //} | 272 | //} |
| 244 | } | 273 | } |
| 245 | 274 | ||
| 246 | fn wait_txe(&self) -> Result<(), Error> { | 275 | fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 247 | loop { | 276 | loop { |
| 248 | unsafe { | 277 | unsafe { |
| 249 | let isr = T::regs().isr().read(); | 278 | let isr = T::regs().isr().read(); |
| @@ -261,10 +290,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 261 | return Err(Error::Nack); | 290 | return Err(Error::Nack); |
| 262 | } | 291 | } |
| 263 | } | 292 | } |
| 293 | |||
| 294 | check_timeout()?; | ||
| 264 | } | 295 | } |
| 265 | } | 296 | } |
| 266 | 297 | ||
| 267 | fn wait_rxne(&self) -> Result<(), Error> { | 298 | fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 268 | loop { | 299 | loop { |
| 269 | unsafe { | 300 | unsafe { |
| 270 | let isr = T::regs().isr().read(); | 301 | let isr = T::regs().isr().read(); |
| @@ -282,10 +313,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 282 | return Err(Error::Nack); | 313 | return Err(Error::Nack); |
| 283 | } | 314 | } |
| 284 | } | 315 | } |
| 316 | |||
| 317 | check_timeout()?; | ||
| 285 | } | 318 | } |
| 286 | } | 319 | } |
| 287 | 320 | ||
| 288 | fn wait_tc(&self) -> Result<(), Error> { | 321 | fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| 289 | loop { | 322 | loop { |
| 290 | unsafe { | 323 | unsafe { |
| 291 | let isr = T::regs().isr().read(); | 324 | let isr = T::regs().isr().read(); |
| @@ -303,10 +336,18 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 303 | return Err(Error::Nack); | 336 | return Err(Error::Nack); |
| 304 | } | 337 | } |
| 305 | } | 338 | } |
| 339 | |||
| 340 | check_timeout()?; | ||
| 306 | } | 341 | } |
| 307 | } | 342 | } |
| 308 | 343 | ||
| 309 | fn read_internal(&mut self, address: u8, buffer: &mut [u8], restart: bool) -> Result<(), Error> { | 344 | fn read_internal( |
| 345 | &mut self, | ||
| 346 | address: u8, | ||
| 347 | buffer: &mut [u8], | ||
| 348 | restart: bool, | ||
| 349 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 350 | ) -> Result<(), Error> { | ||
| 310 | let completed_chunks = buffer.len() / 255; | 351 | let completed_chunks = buffer.len() / 255; |
| 311 | let total_chunks = if completed_chunks * 255 == buffer.len() { | 352 | let total_chunks = if completed_chunks * 255 == buffer.len() { |
| 312 | completed_chunks | 353 | completed_chunks |
| @@ -322,20 +363,21 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 322 | Stop::Automatic, | 363 | Stop::Automatic, |
| 323 | last_chunk_idx != 0, | 364 | last_chunk_idx != 0, |
| 324 | restart, | 365 | restart, |
| 325 | ); | 366 | &check_timeout, |
| 367 | )?; | ||
| 326 | } | 368 | } |
| 327 | 369 | ||
| 328 | for (number, chunk) in buffer.chunks_mut(255).enumerate() { | 370 | for (number, chunk) in buffer.chunks_mut(255).enumerate() { |
| 329 | if number != 0 { | 371 | if number != 0 { |
| 330 | // NOTE(unsafe) We have &mut self | 372 | // NOTE(unsafe) We have &mut self |
| 331 | unsafe { | 373 | unsafe { |
| 332 | Self::master_continue(chunk.len(), number != last_chunk_idx); | 374 | Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; |
| 333 | } | 375 | } |
| 334 | } | 376 | } |
| 335 | 377 | ||
| 336 | for byte in chunk { | 378 | for byte in chunk { |
| 337 | // Wait until we have received something | 379 | // Wait until we have received something |
| 338 | self.wait_rxne()?; | 380 | self.wait_rxne(&check_timeout)?; |
| 339 | 381 | ||
| 340 | unsafe { | 382 | unsafe { |
| 341 | *byte = T::regs().rxdr().read().rxdata(); | 383 | *byte = T::regs().rxdr().read().rxdata(); |
| @@ -345,7 +387,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 345 | Ok(()) | 387 | Ok(()) |
| 346 | } | 388 | } |
| 347 | 389 | ||
| 348 | fn write_internal(&mut self, address: u8, bytes: &[u8], send_stop: bool) -> Result<(), Error> { | 390 | fn write_internal( |
| 391 | &mut self, | ||
| 392 | address: u8, | ||
| 393 | bytes: &[u8], | ||
| 394 | send_stop: bool, | ||
| 395 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 396 | ) -> Result<(), Error> { | ||
| 349 | let completed_chunks = bytes.len() / 255; | 397 | let completed_chunks = bytes.len() / 255; |
| 350 | let total_chunks = if completed_chunks * 255 == bytes.len() { | 398 | let total_chunks = if completed_chunks * 255 == bytes.len() { |
| 351 | completed_chunks | 399 | completed_chunks |
| @@ -359,14 +407,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 359 | // ST SAD+W | 407 | // ST SAD+W |
| 360 | // NOTE(unsafe) We have &mut self | 408 | // NOTE(unsafe) We have &mut self |
| 361 | unsafe { | 409 | unsafe { |
| 362 | Self::master_write(address, bytes.len().min(255), Stop::Software, last_chunk_idx != 0); | 410 | Self::master_write( |
| 411 | address, | ||
| 412 | bytes.len().min(255), | ||
| 413 | Stop::Software, | ||
| 414 | last_chunk_idx != 0, | ||
| 415 | &check_timeout, | ||
| 416 | )?; | ||
| 363 | } | 417 | } |
| 364 | 418 | ||
| 365 | for (number, chunk) in bytes.chunks(255).enumerate() { | 419 | for (number, chunk) in bytes.chunks(255).enumerate() { |
| 366 | if number != 0 { | 420 | if number != 0 { |
| 367 | // NOTE(unsafe) We have &mut self | 421 | // NOTE(unsafe) We have &mut self |
| 368 | unsafe { | 422 | unsafe { |
| 369 | Self::master_continue(chunk.len(), number != last_chunk_idx); | 423 | Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; |
| 370 | } | 424 | } |
| 371 | } | 425 | } |
| 372 | 426 | ||
| @@ -374,7 +428,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 374 | // Wait until we are allowed to send data | 428 | // Wait until we are allowed to send data |
| 375 | // (START has been ACKed or last byte when | 429 | // (START has been ACKed or last byte when |
| 376 | // through) | 430 | // through) |
| 377 | self.wait_txe()?; | 431 | self.wait_txe(&check_timeout)?; |
| 378 | 432 | ||
| 379 | unsafe { | 433 | unsafe { |
| 380 | T::regs().txdr().write(|w| w.set_txdata(*byte)); | 434 | T::regs().txdr().write(|w| w.set_txdata(*byte)); |
| @@ -382,7 +436,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 382 | } | 436 | } |
| 383 | } | 437 | } |
| 384 | // Wait until the write finishes | 438 | // Wait until the write finishes |
| 385 | self.wait_tc()?; | 439 | self.wait_tc(&check_timeout)?; |
| 386 | 440 | ||
| 387 | if send_stop { | 441 | if send_stop { |
| 388 | self.master_stop(); | 442 | self.master_stop(); |
| @@ -396,6 +450,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 396 | bytes: &[u8], | 450 | bytes: &[u8], |
| 397 | first_slice: bool, | 451 | first_slice: bool, |
| 398 | last_slice: bool, | 452 | last_slice: bool, |
| 453 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 399 | ) -> Result<(), Error> | 454 | ) -> Result<(), Error> |
| 400 | where | 455 | where |
| 401 | TXDMA: crate::i2c::TxDma<T>, | 456 | TXDMA: crate::i2c::TxDma<T>, |
| @@ -447,11 +502,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 447 | total_len.min(255), | 502 | total_len.min(255), |
| 448 | Stop::Software, | 503 | Stop::Software, |
| 449 | (total_chunks != 1) || !last_slice, | 504 | (total_chunks != 1) || !last_slice, |
| 450 | ); | 505 | &check_timeout, |
| 506 | )?; | ||
| 451 | } | 507 | } |
| 452 | } else { | 508 | } else { |
| 453 | unsafe { | 509 | unsafe { |
| 454 | Self::master_continue(total_len.min(255), (total_chunks != 1) || !last_slice); | 510 | Self::master_continue(total_len.min(255), (total_chunks != 1) || !last_slice, &check_timeout)?; |
| 455 | T::regs().cr1().modify(|w| w.set_tcie(true)); | 511 | T::regs().cr1().modify(|w| w.set_tcie(true)); |
| 456 | } | 512 | } |
| 457 | } | 513 | } |
| @@ -461,32 +517,40 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 461 | let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed); | 517 | let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed); |
| 462 | 518 | ||
| 463 | if chunks_transferred == total_chunks { | 519 | if chunks_transferred == total_chunks { |
| 464 | return Poll::Ready(()); | 520 | return Poll::Ready(Ok(())); |
| 465 | } else if chunks_transferred != 0 { | 521 | } else if chunks_transferred != 0 { |
| 466 | remaining_len = remaining_len.saturating_sub(255); | 522 | remaining_len = remaining_len.saturating_sub(255); |
| 467 | let last_piece = (chunks_transferred + 1 == total_chunks) && last_slice; | 523 | let last_piece = (chunks_transferred + 1 == total_chunks) && last_slice; |
| 468 | 524 | ||
| 469 | // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers | 525 | // NOTE(unsafe) self.tx_dma does not fiddle with the i2c registers |
| 470 | unsafe { | 526 | unsafe { |
| 471 | Self::master_continue(remaining_len.min(255), !last_piece); | 527 | if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { |
| 528 | return Poll::Ready(Err(e)); | ||
| 529 | } | ||
| 472 | T::regs().cr1().modify(|w| w.set_tcie(true)); | 530 | T::regs().cr1().modify(|w| w.set_tcie(true)); |
| 473 | } | 531 | } |
| 474 | } | 532 | } |
| 475 | Poll::Pending | 533 | Poll::Pending |
| 476 | }) | 534 | }) |
| 477 | .await; | 535 | .await?; |
| 478 | 536 | ||
| 479 | dma_transfer.await; | 537 | dma_transfer.await; |
| 480 | 538 | ||
| 481 | if last_slice { | 539 | if last_slice { |
| 482 | // This should be done already | 540 | // This should be done already |
| 483 | self.wait_tc()?; | 541 | self.wait_tc(&check_timeout)?; |
| 484 | self.master_stop(); | 542 | self.master_stop(); |
| 485 | } | 543 | } |
| 486 | Ok(()) | 544 | Ok(()) |
| 487 | } | 545 | } |
| 488 | 546 | ||
| 489 | async fn read_dma_internal(&mut self, address: u8, buffer: &mut [u8], restart: bool) -> Result<(), Error> | 547 | async fn read_dma_internal( |
| 548 | &mut self, | ||
| 549 | address: u8, | ||
| 550 | buffer: &mut [u8], | ||
| 551 | restart: bool, | ||
| 552 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 553 | ) -> Result<(), Error> | ||
| 490 | where | 554 | where |
| 491 | RXDMA: crate::i2c::RxDma<T>, | 555 | RXDMA: crate::i2c::RxDma<T>, |
| 492 | { | 556 | { |
| @@ -527,7 +591,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 527 | 591 | ||
| 528 | // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers | 592 | // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers |
| 529 | unsafe { | 593 | unsafe { |
| 530 | Self::master_read(address, total_len.min(255), Stop::Software, total_chunks != 1, restart); | 594 | Self::master_read( |
| 595 | address, | ||
| 596 | total_len.min(255), | ||
| 597 | Stop::Software, | ||
| 598 | total_chunks != 1, | ||
| 599 | restart, | ||
| 600 | &check_timeout, | ||
| 601 | )?; | ||
| 531 | } | 602 | } |
| 532 | 603 | ||
| 533 | poll_fn(|cx| { | 604 | poll_fn(|cx| { |
| @@ -535,25 +606,27 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 535 | let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed); | 606 | let chunks_transferred = state.chunks_transferred.load(Ordering::Relaxed); |
| 536 | 607 | ||
| 537 | if chunks_transferred == total_chunks { | 608 | if chunks_transferred == total_chunks { |
| 538 | return Poll::Ready(()); | 609 | return Poll::Ready(Ok(())); |
| 539 | } else if chunks_transferred != 0 { | 610 | } else if chunks_transferred != 0 { |
| 540 | remaining_len = remaining_len.saturating_sub(255); | 611 | remaining_len = remaining_len.saturating_sub(255); |
| 541 | let last_piece = chunks_transferred + 1 == total_chunks; | 612 | let last_piece = chunks_transferred + 1 == total_chunks; |
| 542 | 613 | ||
| 543 | // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers | 614 | // NOTE(unsafe) self.rx_dma does not fiddle with the i2c registers |
| 544 | unsafe { | 615 | unsafe { |
| 545 | Self::master_continue(remaining_len.min(255), !last_piece); | 616 | if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { |
| 617 | return Poll::Ready(Err(e)); | ||
| 618 | } | ||
| 546 | T::regs().cr1().modify(|w| w.set_tcie(true)); | 619 | T::regs().cr1().modify(|w| w.set_tcie(true)); |
| 547 | } | 620 | } |
| 548 | } | 621 | } |
| 549 | Poll::Pending | 622 | Poll::Pending |
| 550 | }) | 623 | }) |
| 551 | .await; | 624 | .await?; |
| 552 | 625 | ||
| 553 | dma_transfer.await; | 626 | dma_transfer.await; |
| 554 | 627 | ||
| 555 | // This should be done already | 628 | // This should be done already |
| 556 | self.wait_tc()?; | 629 | self.wait_tc(&check_timeout)?; |
| 557 | self.master_stop(); | 630 | self.master_stop(); |
| 558 | Ok(()) | 631 | Ok(()) |
| 559 | } | 632 | } |
| @@ -566,9 +639,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 566 | TXDMA: crate::i2c::TxDma<T>, | 639 | TXDMA: crate::i2c::TxDma<T>, |
| 567 | { | 640 | { |
| 568 | if bytes.is_empty() { | 641 | if bytes.is_empty() { |
| 569 | self.write_internal(address, bytes, true) | 642 | self.write_internal(address, bytes, true, || Ok(())) |
| 570 | } else { | 643 | } else { |
| 571 | self.write_dma_internal(address, bytes, true, true).await | 644 | self.write_dma_internal(address, bytes, true, true, || Ok(())).await |
| 572 | } | 645 | } |
| 573 | } | 646 | } |
| 574 | 647 | ||
| @@ -587,7 +660,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 587 | let next = iter.next(); | 660 | let next = iter.next(); |
| 588 | let is_last = next.is_none(); | 661 | let is_last = next.is_none(); |
| 589 | 662 | ||
| 590 | self.write_dma_internal(address, c, first, is_last).await?; | 663 | self.write_dma_internal(address, c, first, is_last, || Ok(())).await?; |
| 591 | first = false; | 664 | first = false; |
| 592 | current = next; | 665 | current = next; |
| 593 | } | 666 | } |
| @@ -599,9 +672,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 599 | RXDMA: crate::i2c::RxDma<T>, | 672 | RXDMA: crate::i2c::RxDma<T>, |
| 600 | { | 673 | { |
| 601 | if buffer.is_empty() { | 674 | if buffer.is_empty() { |
| 602 | self.read_internal(address, buffer, false) | 675 | self.read_internal(address, buffer, false, || Ok(())) |
| 603 | } else { | 676 | } else { |
| 604 | self.read_dma_internal(address, buffer, false).await | 677 | self.read_dma_internal(address, buffer, false, || Ok(())).await |
| 605 | } | 678 | } |
| 606 | } | 679 | } |
| 607 | 680 | ||
| @@ -611,15 +684,15 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 611 | RXDMA: super::RxDma<T>, | 684 | RXDMA: super::RxDma<T>, |
| 612 | { | 685 | { |
| 613 | if bytes.is_empty() { | 686 | if bytes.is_empty() { |
| 614 | self.write_internal(address, bytes, false)?; | 687 | self.write_internal(address, bytes, false, || Ok(()))?; |
| 615 | } else { | 688 | } else { |
| 616 | self.write_dma_internal(address, bytes, true, true).await?; | 689 | self.write_dma_internal(address, bytes, true, true, || Ok(())).await?; |
| 617 | } | 690 | } |
| 618 | 691 | ||
| 619 | if buffer.is_empty() { | 692 | if buffer.is_empty() { |
| 620 | self.read_internal(address, buffer, true)?; | 693 | self.read_internal(address, buffer, true, || Ok(()))?; |
| 621 | } else { | 694 | } else { |
| 622 | self.read_dma_internal(address, buffer, true).await?; | 695 | self.read_dma_internal(address, buffer, true, || Ok(())).await?; |
| 623 | } | 696 | } |
| 624 | 697 | ||
| 625 | Ok(()) | 698 | Ok(()) |
| @@ -628,22 +701,55 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 628 | // ========================= | 701 | // ========================= |
| 629 | // Blocking public API | 702 | // Blocking public API |
| 630 | 703 | ||
| 631 | pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | 704 | pub fn blocking_read_timeout( |
| 632 | self.read_internal(address, buffer, false) | 705 | &mut self, |
| 706 | address: u8, | ||
| 707 | buffer: &mut [u8], | ||
| 708 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 709 | ) -> Result<(), Error> { | ||
| 710 | self.read_internal(address, buffer, false, &check_timeout) | ||
| 633 | // Automatic Stop | 711 | // Automatic Stop |
| 634 | } | 712 | } |
| 635 | 713 | ||
| 714 | pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | ||
| 715 | self.blocking_read_timeout(address, buffer, || Ok(())) | ||
| 716 | } | ||
| 717 | |||
| 718 | pub fn blocking_write_timeout( | ||
| 719 | &mut self, | ||
| 720 | address: u8, | ||
| 721 | bytes: &[u8], | ||
| 722 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 723 | ) -> Result<(), Error> { | ||
| 724 | self.write_internal(address, bytes, true, &check_timeout) | ||
| 725 | } | ||
| 726 | |||
| 636 | pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> { | 727 | pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> { |
| 637 | self.write_internal(address, bytes, true) | 728 | self.blocking_write_timeout(address, bytes, || Ok(())) |
| 638 | } | 729 | } |
| 639 | 730 | ||
| 640 | pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { | 731 | pub fn blocking_write_read_timeout( |
| 641 | self.write_internal(address, bytes, false)?; | 732 | &mut self, |
| 642 | self.read_internal(address, buffer, true) | 733 | address: u8, |
| 734 | bytes: &[u8], | ||
| 735 | buffer: &mut [u8], | ||
| 736 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 737 | ) -> Result<(), Error> { | ||
| 738 | self.write_internal(address, bytes, false, &check_timeout)?; | ||
| 739 | self.read_internal(address, buffer, true, &check_timeout) | ||
| 643 | // Automatic Stop | 740 | // Automatic Stop |
| 644 | } | 741 | } |
| 645 | 742 | ||
| 646 | pub fn blocking_write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> { | 743 | pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { |
| 744 | self.blocking_write_read_timeout(address, bytes, buffer, || Ok(())) | ||
| 745 | } | ||
| 746 | |||
| 747 | pub fn blocking_write_vectored_timeout( | ||
| 748 | &mut self, | ||
| 749 | address: u8, | ||
| 750 | bytes: &[&[u8]], | ||
| 751 | check_timeout: impl Fn() -> Result<(), Error>, | ||
| 752 | ) -> Result<(), Error> { | ||
| 647 | if bytes.is_empty() { | 753 | if bytes.is_empty() { |
| 648 | return Err(Error::ZeroLengthTransfer); | 754 | return Err(Error::ZeroLengthTransfer); |
| 649 | } | 755 | } |
| @@ -657,7 +763,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 657 | first_length.min(255), | 763 | first_length.min(255), |
| 658 | Stop::Software, | 764 | Stop::Software, |
| 659 | (first_length > 255) || (last_slice_index != 0), | 765 | (first_length > 255) || (last_slice_index != 0), |
| 660 | ); | 766 | &check_timeout, |
| 767 | )?; | ||
| 661 | } | 768 | } |
| 662 | 769 | ||
| 663 | for (idx, slice) in bytes.iter().enumerate() { | 770 | for (idx, slice) in bytes.iter().enumerate() { |
| @@ -673,7 +780,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 673 | if idx != 0 { | 780 | if idx != 0 { |
| 674 | // NOTE(unsafe) We have &mut self | 781 | // NOTE(unsafe) We have &mut self |
| 675 | unsafe { | 782 | unsafe { |
| 676 | Self::master_continue(slice_len.min(255), (idx != last_slice_index) || (slice_len > 255)); | 783 | Self::master_continue( |
| 784 | slice_len.min(255), | ||
| 785 | (idx != last_slice_index) || (slice_len > 255), | ||
| 786 | &check_timeout, | ||
| 787 | )?; | ||
| 677 | } | 788 | } |
| 678 | } | 789 | } |
| 679 | 790 | ||
| @@ -681,7 +792,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 681 | if number != 0 { | 792 | if number != 0 { |
| 682 | // NOTE(unsafe) We have &mut self | 793 | // NOTE(unsafe) We have &mut self |
| 683 | unsafe { | 794 | unsafe { |
| 684 | Self::master_continue(chunk.len(), (number != last_chunk_idx) || (idx != last_slice_index)); | 795 | Self::master_continue( |
| 796 | chunk.len(), | ||
| 797 | (number != last_chunk_idx) || (idx != last_slice_index), | ||
| 798 | &check_timeout, | ||
| 799 | )?; | ||
| 685 | } | 800 | } |
| 686 | } | 801 | } |
| 687 | 802 | ||
| @@ -689,7 +804,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 689 | // Wait until we are allowed to send data | 804 | // Wait until we are allowed to send data |
| 690 | // (START has been ACKed or last byte when | 805 | // (START has been ACKed or last byte when |
| 691 | // through) | 806 | // through) |
| 692 | self.wait_txe()?; | 807 | self.wait_txe(&check_timeout)?; |
| 693 | 808 | ||
| 694 | // Put byte on the wire | 809 | // Put byte on the wire |
| 695 | //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); | 810 | //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); |
| @@ -700,11 +815,15 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 700 | } | 815 | } |
| 701 | } | 816 | } |
| 702 | // Wait until the write finishes | 817 | // Wait until the write finishes |
| 703 | self.wait_tc()?; | 818 | self.wait_tc(&check_timeout)?; |
| 704 | self.master_stop(); | 819 | self.master_stop(); |
| 705 | 820 | ||
| 706 | Ok(()) | 821 | Ok(()) |
| 707 | } | 822 | } |
| 823 | |||
| 824 | pub fn blocking_write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> { | ||
| 825 | self.blocking_write_vectored_timeout(address, bytes, || Ok(())) | ||
| 826 | } | ||
| 708 | } | 827 | } |
| 709 | 828 | ||
| 710 | mod eh02 { | 829 | mod eh02 { |
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 0392e8086..bcf2feee8 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs | |||
| @@ -52,7 +52,7 @@ pub mod sdmmc; | |||
| 52 | pub mod spi; | 52 | pub mod spi; |
| 53 | #[cfg(usart)] | 53 | #[cfg(usart)] |
| 54 | pub mod usart; | 54 | pub mod usart; |
| 55 | #[cfg(usb)] | 55 | #[cfg(all(usb, feature = "time"))] |
| 56 | pub mod usb; | 56 | pub mod usb; |
| 57 | #[cfg(any(otgfs, otghs))] | 57 | #[cfg(any(otgfs, otghs))] |
| 58 | pub mod usb_otg; | 58 | pub mod usb_otg; |
diff --git a/embassy-stm32/src/subghz/timeout.rs b/embassy-stm32/src/subghz/timeout.rs index 28b3b0c21..0ae49dd90 100644 --- a/embassy-stm32/src/subghz/timeout.rs +++ b/embassy-stm32/src/subghz/timeout.rs | |||
| @@ -439,6 +439,7 @@ impl From<Timeout> for [u8; 3] { | |||
| 439 | } | 439 | } |
| 440 | } | 440 | } |
| 441 | 441 | ||
| 442 | #[cfg(feature = "time")] | ||
| 442 | impl From<Timeout> for embassy_time::Duration { | 443 | impl From<Timeout> for embassy_time::Duration { |
| 443 | fn from(to: Timeout) -> Self { | 444 | fn from(to: Timeout) -> Self { |
| 444 | embassy_time::Duration::from_micros(to.as_micros().into()) | 445 | embassy_time::Duration::from_micros(to.as_micros().into()) |
diff --git a/embassy-stm32/src/subghz/tx_params.rs b/embassy-stm32/src/subghz/tx_params.rs index cede6f2c1..03bdb1ea8 100644 --- a/embassy-stm32/src/subghz/tx_params.rs +++ b/embassy-stm32/src/subghz/tx_params.rs | |||
| @@ -44,6 +44,7 @@ impl From<RampTime> for core::time::Duration { | |||
| 44 | } | 44 | } |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | #[cfg(feature = "time")] | ||
| 47 | impl From<RampTime> for embassy_time::Duration { | 48 | impl From<RampTime> for embassy_time::Duration { |
| 48 | fn from(rt: RampTime) -> Self { | 49 | fn from(rt: RampTime) -> Self { |
| 49 | match rt { | 50 | match rt { |
diff --git a/examples/stm32f4/src/bin/i2c.rs b/examples/stm32f4/src/bin/i2c.rs new file mode 100644 index 000000000..6e51c211d --- /dev/null +++ b/examples/stm32f4/src/bin/i2c.rs | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::dma::NoDma; | ||
| 8 | use embassy_stm32::i2c::{Error, I2c, TimeoutI2c}; | ||
| 9 | use embassy_stm32::interrupt; | ||
| 10 | use embassy_stm32::time::Hertz; | ||
| 11 | use embassy_time::Duration; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | const ADDRESS: u8 = 0x5F; | ||
| 15 | const WHOAMI: u8 = 0x0F; | ||
| 16 | |||
| 17 | #[embassy_executor::main] | ||
| 18 | async fn main(_spawner: Spawner) -> ! { | ||
| 19 | info!("Hello world!"); | ||
| 20 | let p = embassy_stm32::init(Default::default()); | ||
| 21 | |||
| 22 | let irq = interrupt::take!(I2C2_EV); | ||
| 23 | let mut i2c = I2c::new( | ||
| 24 | p.I2C2, | ||
| 25 | p.PB10, | ||
| 26 | p.PB11, | ||
| 27 | irq, | ||
| 28 | NoDma, | ||
| 29 | NoDma, | ||
| 30 | Hertz(100_000), | ||
| 31 | Default::default(), | ||
| 32 | ); | ||
| 33 | |||
| 34 | // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long. | ||
| 35 | // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay. | ||
| 36 | let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000)); | ||
| 37 | |||
| 38 | let mut data = [0u8; 1]; | ||
| 39 | |||
| 40 | match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) { | ||
| 41 | Ok(()) => info!("Whoami: {}", data[0]), | ||
| 42 | Err(Error::Timeout) => error!("Operation timed out"), | ||
| 43 | Err(e) => error!("I2c Error: {:?}", e), | ||
| 44 | } | ||
| 45 | } | ||
diff --git a/examples/stm32h7/src/bin/i2c.rs b/examples/stm32h7/src/bin/i2c.rs new file mode 100644 index 000000000..d44319ae6 --- /dev/null +++ b/examples/stm32h7/src/bin/i2c.rs | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::i2c::{Error, I2c, TimeoutI2c}; | ||
| 8 | use embassy_stm32::interrupt; | ||
| 9 | use embassy_stm32::time::Hertz; | ||
| 10 | use embassy_time::Duration; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | const ADDRESS: u8 = 0x5F; | ||
| 14 | const WHOAMI: u8 = 0x0F; | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async fn main(_spawner: Spawner) -> ! { | ||
| 18 | info!("Hello world!"); | ||
| 19 | let p = embassy_stm32::init(Default::default()); | ||
| 20 | |||
| 21 | let irq = interrupt::take!(I2C2_EV); | ||
| 22 | let mut i2c = I2c::new( | ||
| 23 | p.I2C2, | ||
| 24 | p.PB10, | ||
| 25 | p.PB11, | ||
| 26 | irq, | ||
| 27 | p.DMA1_CH4, | ||
| 28 | p.DMA1_CH5, | ||
| 29 | Hertz(100_000), | ||
| 30 | Default::default(), | ||
| 31 | ); | ||
| 32 | |||
| 33 | // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long. | ||
| 34 | // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay. | ||
| 35 | let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000)); | ||
| 36 | |||
| 37 | let mut data = [0u8; 1]; | ||
| 38 | |||
| 39 | match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) { | ||
| 40 | Ok(()) => info!("Whoami: {}", data[0]), | ||
| 41 | Err(Error::Timeout) => error!("Operation timed out"), | ||
| 42 | Err(e) => error!("I2c Error: {:?}", e), | ||
| 43 | } | ||
| 44 | } | ||
