diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b7b9e15f..427404c76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ([#99](https://github.com/stm32-rs/stm32f3xx-hal/pull/99)) - SPI4 peripheral for supported devices. ([#99](https://github.com/stm32-rs/stm32f3xx-hal/pull/99)) +- Support for I2C transfer of more than 255 bytes, and 0 byte write ([#154](https://github.com/stm32-rs/stm32f3xx-hal/pull/154)) ### Changed diff --git a/src/i2c.rs b/src/i2c.rs index 96dfafb66..6030b814e 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -13,10 +13,14 @@ use cast::u8; #[derive(Debug)] #[non_exhaustive] pub enum Error { - /// Bus error - Bus, /// Arbitration loss Arbitration, + /// Bus error + Bus, + /// Bus busy + Busy, + /// Not Acknowledge received + Nack, // Overrun, // slave mode only // Pec, // SMBUS mode only // Timeout, // SMBUS mode only @@ -57,15 +61,21 @@ macro_rules! busy_wait { ($i2c:expr, $flag:ident, $variant:ident) => { loop { let isr = $i2c.isr.read(); + let icr = &$i2c.icr; - if isr.$flag().$variant() { - break; + if isr.arlo().is_lost() { + icr.write(|w| w.arlocf().clear()); + return Err(Error::Arbitration); } else if isr.berr().is_error() { + icr.write(|w| w.berrcf().clear()); return Err(Error::Bus); - } else if isr.arlo().is_lost() { - return Err(Error::Arbitration); - } else { - // try again + } else if isr.nackf().is_nack() { + while $i2c.isr.read().stopf().is_no_stop() {} + icr.write(|w| w.nackcf().clear()); + icr.write(|w| w.stopcf().clear()); + return Err(Error::Nack); + } else if isr.$flag().$variant() { + break; } } }; @@ -181,34 +191,52 @@ macro_rules! hal { impl Read for I2c<$I2CX, PINS> { type Error = Error; fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { - // TODO support transfers of more than 255 bytes - assert!(buffer.len() < 256 && buffer.len() > 0); - - // TODO do we have to explicitly wait here if the bus is busy (e.g. another - // master is communicating)? - - // START and prepare to receive `bytes` - self.i2c.cr2.write(|w| { - w.sadd() - .bits(u16::from(addr << 1)) - .rd_wrn() - .read() - .nbytes() - .bits(buffer.len() as u8) - .start() - .start() - .autoend() - .automatic() - }); + assert!(buffer.len() > 0); - for byte in buffer { - // Wait until we have received something - busy_wait!(self.i2c, rxne, is_not_empty); + // Detect Bus busy + if self.i2c.isr.read().busy().is_busy() { + return Err(Error::Busy); + } - *byte = self.i2c.rxdr.read().rxdata().bits(); + let end = buffer.len() / 0xFF; + + // Process 255 bytes at a time + for (i, buffer) in buffer.chunks_mut(0xFF).enumerate() { + // Prepare to receive `bytes` + self.i2c.cr2.modify(|_, w| { + if i == 0 { + w + .add10().bit7() + .sadd().bits((addr << 1) as u16) + .rd_wrn().read() + .start().start(); + } + w.nbytes().bits(buffer.len() as u8); + if i != end { + w.reload().not_completed() + } else { + w.reload().completed().autoend().automatic() + } + }); + + for byte in buffer { + // Wait until we have received something + busy_wait!(self.i2c, rxne, is_not_empty); + + *byte = self.i2c.rxdr.read().rxdata().bits(); + } + + if i != end { + // Wait until the last transmission is finished + busy_wait!(self.i2c, tcr, is_complete); + } } // automatic STOP + // Wait until the last transmission is finished + busy_wait!(self.i2c, stopf, is_stop); + + self.i2c.icr.write(|w| w.stopcf().clear()); Ok(()) } @@ -218,37 +246,67 @@ macro_rules! hal { type Error = Error; fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { - // TODO support transfers of more than 255 bytes - assert!(bytes.len() < 256 && bytes.len() > 0); - - // START and prepare to send `bytes` - self.i2c.cr2.modify(|_, w| { - w.sadd() - .bits(u16::from(addr << 1)) - .rd_wrn() - .write() - .nbytes() - .bits(bytes.len() as u8) - .start() - .start() - .autoend() - .automatic() - }); - - for byte in bytes { - // Wait until we are allowed to send data (START has been ACKed or last byte - // when through) - busy_wait!(self.i2c, txis, is_empty); - - // put byte on the wire - // NOTE(write): writes all non-reserved bits. - self.i2c.txdr.write(|w| w.txdata().bits(*byte)); + // Detect Bus busy + if self.i2c.isr.read().busy().is_busy() { + return Err(Error::Busy); } - // Wait until the last transmission is finished ??? - // busy_wait!(self.i2c, busy); + if bytes.len() == 0 { + // 0 byte write + self.i2c.cr2.modify(|_, w| { + w + .add10().bit7() + .sadd().bits((addr << 1) as u16) + .rd_wrn().write() + .nbytes().bits(0) + .reload().completed() + .autoend().automatic() + .start().start() + }); + } else { + let end = bytes.len() / 0xFF; + + // Process 255 bytes at a time + for (i, bytes) in bytes.chunks(0xFF).enumerate() { + // Prepare to send `bytes` + self.i2c.cr2.modify(|_, w| { + if i == 0 { + w + .add10().bit7() + .sadd().bits((addr << 1) as u16) + .rd_wrn().write() + .start().start(); + } + w.nbytes().bits(bytes.len() as u8); + if i != end { + w.reload().not_completed() + } else { + w.reload().completed().autoend().automatic() + } + }); + + for byte in bytes { + // Wait until we are allowed to send data + // (START has been ACKed or last byte went through) + busy_wait!(self.i2c, txis, is_empty); + + // Put byte on the wire + // NOTE(write): Writes all non-reserved bits. + self.i2c.txdr.write(|w| w.txdata().bits(*byte)); + } + + if i != end { + // Wait until the last transmission is finished + busy_wait!(self.i2c, tcr, is_complete); + } + } + } // automatic STOP + // Wait until the last transmission is finished + busy_wait!(self.i2c, stopf, is_stop); + + self.i2c.icr.write(|w| w.stopcf().clear()); Ok(()) } @@ -263,62 +321,94 @@ macro_rules! hal { bytes: &[u8], buffer: &mut [u8], ) -> Result<(), Error> { - // TODO support transfers of more than 255 bytes - assert!(bytes.len() < 256 && bytes.len() > 0); - assert!(buffer.len() < 256 && buffer.len() > 0); - - // TODO do we have to explicitly wait here if the bus is busy (e.g. another - // master is communicating)? - - // START and prepare to send `bytes` - self.i2c.cr2.modify(|_, w| { - w.sadd() - .bits(u16::from(addr << 1)) - .rd_wrn() - .write() - .nbytes() - .bits(bytes.len() as u8) - .start() - .start() - .autoend() - .software() - }); + assert!(bytes.len() > 0 && buffer.len() > 0); - for byte in bytes { - // Wait until we are allowed to send data - // (START has been ACKed or last byte went through): - busy_wait!(self.i2c, txis, is_empty); + // Detect Bus busy + if self.i2c.isr.read().busy().is_busy() { + return Err(Error::Busy); + } - // put byte into TXDR - // NOTE(write): writes all non-reserved bits. - self.i2c.txdr.write(|w| w.txdata().bits(*byte)); + let end = buffer.len() / 0xFF; + + // Process 255 bytes at a time + for (i, bytes) in bytes.chunks(0xFF).enumerate() { + // Prepare to send `bytes` + self.i2c.cr2.modify(|_, w| { + if i == 0 { + w + .add10().bit7() + .sadd().bits((addr << 1) as u16) + .rd_wrn().write() + .start().start(); + } + w.nbytes().bits(bytes.len() as u8); + if i != end { + w.reload().not_completed() + } else { + w.reload().completed().autoend().software() + } + }); + + for byte in bytes { + // Wait until we are allowed to send data + // (START has been ACKed or last byte went through) + busy_wait!(self.i2c, txis, is_empty); + + // Put byte on the wire + // NOTE(write): Writes all non-reserved bits. + self.i2c.txdr.write(|w| w.txdata().bits(*byte)); + } + + if i != end { + // Wait until the last transmission is finished + busy_wait!(self.i2c, tcr, is_complete); + } } - // Wait until the last byte transmission is finished: + // Wait until the last transmission is finished busy_wait!(self.i2c, tc, is_complete); - // reSTART and prepare to receive bytes into `buffer` - self.i2c.cr2.modify(|_, w| { - w.sadd() - .bits(u16::from(addr << 1)) - .rd_wrn() - .read() - .nbytes() - .bits(buffer.len() as u8) - .start() - .start() - .autoend() - .automatic() - }); - - for byte in buffer { - // Wait until we have received something - busy_wait!(self.i2c, rxne, is_not_empty); - - *byte = self.i2c.rxdr.read().rxdata().bits(); + // restart + + let end = buffer.len() / 0xFF; + + // Process 255 bytes at a time + for (i, buffer) in buffer.chunks_mut(0xFF).enumerate() { + // Prepare to receive `bytes` + self.i2c.cr2.modify(|_, w| { + if i == 0 { + w + .add10().bit7() + .sadd().bits((addr << 1) as u16) + .rd_wrn().read() + .start().start(); + } + w.nbytes().bits(buffer.len() as u8); + if i != end { + w.reload().not_completed() + } else { + w.reload().completed().autoend().automatic() + } + }); + + for byte in buffer { + // Wait until we have received something + busy_wait!(self.i2c, rxne, is_not_empty); + + *byte = self.i2c.rxdr.read().rxdata().bits(); + } + + if i != end { + // Wait until the last transmission is finished + busy_wait!(self.i2c, tcr, is_complete); + } } // automatic STOP + // Wait until the last transmission is finished + busy_wait!(self.i2c, stopf, is_stop); + + self.i2c.icr.write(|w| w.stopcf().clear()); Ok(()) }