From 8c7f8a61e327078cf68a32a5f282f301f335ffd1 Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Wed, 7 Jul 2021 21:35:56 -0300 Subject: [PATCH 1/4] i2c-v2: Support transfers with more than 255 bytes --- embassy-stm32/src/i2c/v2.rs | 203 +++++++++++++++++++----------------- 1 file changed, 105 insertions(+), 98 deletions(-) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 2f70d426..b7aa8458 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -81,30 +81,40 @@ impl<'d, T: Instance> I2c<'d, T> { } } - fn master_read(&mut self, address: u8, length: usize, stop: Stop) { + fn master_read(&mut self, address: u8, length: usize, stop: Stop, reload: bool, restart: bool) { assert!(length < 256 && length > 0); - // Wait for any previous address sequence to end - // automatically. This could be up to 50% of a bus - // cycle (ie. up to 0.5/freq) - while unsafe { T::regs().cr2().read().start() == i2c::vals::Start::START } {} + if !restart { + // Wait for any previous address sequence to end + // automatically. This could be up to 50% of a bus + // cycle (ie. up to 0.5/freq) + while unsafe { T::regs().cr2().read().start() == i2c::vals::Start::START } {} + } // Set START and prepare to receive bytes into // `buffer`. The START bit can be set even if the bus // is BUSY or I2C is in slave mode. + let reload = if reload { + i2c::vals::Reload::NOTCOMPLETED + } else { + i2c::vals::Reload::COMPLETED + }; + unsafe { T::regs().cr2().modify(|w| { w.set_sadd((address << 1 | 0) as u16); + w.set_add10(i2c::vals::Add::BIT7); w.set_rd_wrn(i2c::vals::RdWrn::READ); w.set_nbytes(length as u8); w.set_start(i2c::vals::Start::START); w.set_autoend(stop.autoend()); + w.set_reload(reload); }); } } - fn master_write(&mut self, address: u8, length: usize, stop: Stop) { + fn master_write(&mut self, address: u8, length: usize, stop: Stop, reload: bool) { assert!(length < 256 && length > 0); // Wait for any previous address sequence to end @@ -112,6 +122,12 @@ impl<'d, T: Instance> I2c<'d, T> { // cycle (ie. up to 0.5/freq) while unsafe { T::regs().cr2().read().start() == i2c::vals::Start::START } {} + let reload = if reload { + i2c::vals::Reload::NOTCOMPLETED + } else { + i2c::vals::Reload::COMPLETED + }; + // Set START and prepare to send `bytes`. The // START bit can be set even if the bus is BUSY or // I2C is in slave mode. @@ -123,21 +139,24 @@ impl<'d, T: Instance> I2c<'d, T> { w.set_nbytes(length as u8); w.set_start(i2c::vals::Start::START); w.set_autoend(stop.autoend()); + w.set_reload(reload); }); } } - fn master_re_start(&mut self, address: u8, length: usize, stop: Stop) { + fn master_continue(&mut self, length: usize, reload: bool) { assert!(length < 256 && length > 0); + let reload = if reload { + i2c::vals::Reload::NOTCOMPLETED + } else { + i2c::vals::Reload::COMPLETED + }; + unsafe { T::regs().cr2().modify(|w| { - w.set_sadd((address << 1 | 1) as u16); - w.set_add10(i2c::vals::Add::BIT7); - w.set_rd_wrn(i2c::vals::RdWrn::READ); w.set_nbytes(length as u8); - w.set_start(i2c::vals::Start::START); - w.set_autoend(stop.autoend()); + w.set_reload(reload); }); } } @@ -224,28 +243,82 @@ impl<'d, T: Instance> I2c<'d, T> { } } } + + fn read(&mut self, address: u8, buffer: &mut [u8], restart: bool) -> Result<(), Error> { + let last_chunk = (buffer.len() / 255).saturating_sub(1); + + self.master_read( + address, + buffer.len().min(255), + Stop::Automatic, + last_chunk != 0, + restart, + ); + + for (number, chunk) in buffer.chunks_mut(255).enumerate() { + if number != 0 { + self.master_continue(chunk.len(), number != last_chunk); + } + + for byte in chunk { + // Wait until we have received something + self.wait_rxne()?; + + unsafe { + *byte = T::regs().rxdr().read().rxdata(); + } + } + } + Ok(()) + } + + fn write(&mut self, address: u8, bytes: &[u8], send_stop: bool) -> Result<(), Error> { + let last_chunk = (bytes.len() / 255).saturating_sub(1); + + // I2C start + // + // ST SAD+W + self.master_write( + address, + bytes.len().min(255), + Stop::Software, + last_chunk != 0, + ); + + for (number, chunk) in bytes.chunks(255).enumerate() { + if number != 0 { + self.master_continue(chunk.len(), number != last_chunk); + } + + for byte in chunk { + // Wait until we are allowed to send data + // (START has been ACKed or last byte when + // through) + self.wait_txe()?; + + // Put byte on the wire + //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); + unsafe { + T::regs().txdr().write(|w| w.set_txdata(*byte)); + } + } + } + // Wait until the write finishes + self.wait_tc()?; + + if send_stop { + self.master_stop(); + } + Ok(()) + } } impl<'d, T: Instance> Read for I2c<'d, T> { type Error = Error; fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { - assert!(buffer.len() < 256 && buffer.len() > 0); - - self.master_read(address, buffer.len(), Stop::Automatic); - - for byte in buffer { - // Wait until we have received something - self.wait_rxne()?; - - //*byte = self.i2c.rxdr.read().rxdata().bits(); - unsafe { - *byte = T::regs().rxdr().read().rxdata(); - } - } - - // automatic STOP - Ok(()) + self.read(address, buffer, false) + // Automatic Stop } } @@ -253,34 +326,7 @@ impl<'d, T: Instance> Write for I2c<'d, T> { type Error = Error; fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { - // TODO support transfers of more than 255 bytes - assert!(bytes.len() < 256 && bytes.len() > 0); - - // I2C start - // - // ST SAD+W - self.master_write(address, bytes.len(), Stop::Software); - - for byte in bytes { - // Wait until we are allowed to send data - // (START has been ACKed or last byte when - // through) - self.wait_txe()?; - - // Put byte on the wire - //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); - unsafe { - T::regs().txdr().write(|w| w.set_txdata(*byte)); - } - } - - // Wait until the write finishes - self.wait_tc()?; - - // Stop - self.master_stop(); - - Ok(()) + self.write(address, bytes, true) } } @@ -293,48 +339,9 @@ impl<'d, T: Instance> WriteRead for I2c<'d, T> { bytes: &[u8], buffer: &mut [u8], ) -> Result<(), Self::Error> { - // TODO support transfers of more than 255 bytes - assert!(bytes.len() < 256 && bytes.len() > 0); - assert!(buffer.len() < 256 && buffer.len() > 0); - - // I2C start - // - // ST SAD+W - self.master_write(address, bytes.len(), Stop::Software); - - for byte in bytes { - // Wait until we are allowed to send data - // (START has been ACKed or last byte went through) - self.wait_txe()?; - - // Put byte on the wire - //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); - unsafe { - T::regs().txdr().write(|w| w.set_txdata(*byte)); - } - } - - // Wait until the write finishes before beginning to read. - self.wait_tc()?; - - // I2C re-start - // - // SR SAD+R - self.master_re_start(address, buffer.len(), Stop::Automatic); - - for byte in buffer { - // Wait until we have received something - self.wait_rxne()?; - - //*byte = self.i2c.rxdr.read().rxdata().bits(); - unsafe { - *byte = T::regs().rxdr().read().rxdata(); - } - } - - // automatic STOP - - Ok(()) + self.write(address, bytes, false)?; + self.read(address, buffer, true) + // Automatic Stop } } From f2e78e9c3413994fa264345ceacc44463e5bb0ec Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Thu, 8 Jul 2021 19:53:47 -0300 Subject: [PATCH 2/4] i2c-v2: Correct number of chunks calculation --- embassy-stm32/src/i2c/mod.rs | 1 + embassy-stm32/src/i2c/v2.rs | 26 ++++++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index d2da8c31..fc154a95 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -6,6 +6,7 @@ mod _version; use crate::peripherals; pub use _version::*; +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { Bus, Arbitration, diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index b7aa8458..787bf679 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -147,6 +147,8 @@ impl<'d, T: Instance> I2c<'d, T> { fn master_continue(&mut self, length: usize, reload: bool) { assert!(length < 256 && length > 0); + while unsafe { !T::regs().isr().read().tcr() } {} + let reload = if reload { i2c::vals::Reload::NOTCOMPLETED } else { @@ -245,19 +247,25 @@ impl<'d, T: Instance> I2c<'d, T> { } fn read(&mut self, address: u8, buffer: &mut [u8], restart: bool) -> Result<(), Error> { - let last_chunk = (buffer.len() / 255).saturating_sub(1); + let completed_chunks = buffer.len() / 255; + let total_chunks = if completed_chunks * 255 == buffer.len() { + completed_chunks + } else { + completed_chunks + 1 + }; + let last_chunk_idx = total_chunks.saturating_sub(1); self.master_read( address, buffer.len().min(255), Stop::Automatic, - last_chunk != 0, + last_chunk_idx != 0, restart, ); for (number, chunk) in buffer.chunks_mut(255).enumerate() { if number != 0 { - self.master_continue(chunk.len(), number != last_chunk); + self.master_continue(chunk.len(), number != last_chunk_idx); } for byte in chunk { @@ -273,7 +281,13 @@ impl<'d, T: Instance> I2c<'d, T> { } fn write(&mut self, address: u8, bytes: &[u8], send_stop: bool) -> Result<(), Error> { - let last_chunk = (bytes.len() / 255).saturating_sub(1); + let completed_chunks = bytes.len() / 255; + let total_chunks = if completed_chunks * 255 == bytes.len() { + completed_chunks + } else { + completed_chunks + 1 + }; + let last_chunk_idx = total_chunks.saturating_sub(1); // I2C start // @@ -282,12 +296,12 @@ impl<'d, T: Instance> I2c<'d, T> { address, bytes.len().min(255), Stop::Software, - last_chunk != 0, + last_chunk_idx != 0, ); for (number, chunk) in bytes.chunks(255).enumerate() { if number != 0 { - self.master_continue(chunk.len(), number != last_chunk); + self.master_continue(chunk.len(), number != last_chunk_idx); } for byte in chunk { From aa8c7f990f3d00ddf8305dae7d278399d9573ecb Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Fri, 9 Jul 2021 02:57:34 -0300 Subject: [PATCH 3/4] i2c-v2: Implement write_vectored --- embassy-stm32/src/i2c/mod.rs | 1 + embassy-stm32/src/i2c/v2.rs | 60 ++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index fc154a95..daf7e31e 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -14,6 +14,7 @@ pub enum Error { Timeout, Crc, Overrun, + ZeroLengthTransfer, } pub(crate) mod sealed { diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 787bf679..a5eb5612 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -325,6 +325,66 @@ impl<'d, T: Instance> I2c<'d, T> { } Ok(()) } + + pub fn write_vectored(&mut self, address: u8, bytes: &[&[u8]]) -> Result<(), Error> { + if bytes.is_empty() { + return Err(Error::ZeroLengthTransfer); + } + let first_length = bytes[0].len(); + let last_slice_index = bytes.len() - 1; + + self.master_write( + address, + first_length.min(255), + Stop::Software, + (first_length > 255) || (last_slice_index != 0), + ); + + for (idx, slice) in bytes.iter().enumerate() { + let slice_len = slice.len(); + let completed_chunks = slice_len / 255; + let total_chunks = if completed_chunks * 255 == slice_len { + completed_chunks + } else { + completed_chunks + 1 + }; + let last_chunk_idx = total_chunks.saturating_sub(1); + + if idx != 0 { + self.master_continue( + slice_len.min(255), + (idx != last_slice_index) || (slice_len > 255), + ); + } + + for (number, chunk) in slice.chunks(255).enumerate() { + if number != 0 { + self.master_continue( + chunk.len(), + (number != last_chunk_idx) || (idx != last_slice_index), + ); + } + + for byte in chunk { + // Wait until we are allowed to send data + // (START has been ACKed or last byte when + // through) + self.wait_txe()?; + + // Put byte on the wire + //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); + unsafe { + T::regs().txdr().write(|w| w.set_txdata(*byte)); + } + } + } + } + // Wait until the write finishes + self.wait_tc()?; + self.master_stop(); + + Ok(()) + } } impl<'d, T: Instance> Read for I2c<'d, T> { From e06628cdfb3beba766c93b1ab09c237115c77d9c Mon Sep 17 00:00:00 2001 From: Thales Fragoso Date: Wed, 14 Jul 2021 12:11:11 -0300 Subject: [PATCH 4/4] Update stm32-data --- embassy-stm32/src/i2c/v2.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index a5eb5612..3179211e 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -310,8 +310,6 @@ impl<'d, T: Instance> I2c<'d, T> { // through) self.wait_txe()?; - // Put byte on the wire - //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); unsafe { T::regs().txdr().write(|w| w.set_txdata(*byte)); }