diff --git a/Cargo.toml b/Cargo.toml index 6004c7d..0fc5c58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stm32-hal2" -version = "1.8.3" +version = "1.8.4" edition = "2021" authors = ["David O'Connor "] description = "Hardware abstraction layer for the STM32 MCUs" diff --git a/src/clocks/mod.rs b/src/clocks/mod.rs index 420add3..7b4c5e0 100644 --- a/src/clocks/mod.rs +++ b/src/clocks/mod.rs @@ -36,7 +36,7 @@ cfg_if::cfg_if! { // todo: Continue working through DRY between the clock modules. /// Speed out of limits. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, defmt::Format)] pub enum RccError { Speed, Hardware, diff --git a/src/crc.rs b/src/crc.rs index 6cac30c..664893e 100644 --- a/src/crc.rs +++ b/src/crc.rs @@ -313,7 +313,7 @@ impl Default for Polynomial { } /// Errors generated when trying to create invalid polynomials. -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq, defmt::Format)] pub enum PolynomialError { /// Tried to create an even polynomial. /// The hardware CRC unit only supports odd polynomials. diff --git a/src/flash/non_trustzone.rs b/src/flash/non_trustzone.rs index 5481bc2..61bda6e 100644 --- a/src/flash/non_trustzone.rs +++ b/src/flash/non_trustzone.rs @@ -32,7 +32,7 @@ pub enum Bank { B2 = 1, } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, defmt::Format)] /// Possible error states for flash operations. pub enum Error { /// Flash controller is not done yet diff --git a/src/flash/trustzone.rs b/src/flash/trustzone.rs index 7ebba4e..4baa3fb 100644 --- a/src/flash/trustzone.rs +++ b/src/flash/trustzone.rs @@ -32,7 +32,7 @@ pub enum Bank { B2 = 1, } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, defmt::Format)] /// Possible error states for flash operations. pub enum Error { /// Flash controller is not done yet diff --git a/src/i2c.rs b/src/i2c.rs index 684e13a..92ec5af 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -4,8 +4,6 @@ use core::ops::Deref; -// #[cfg(feature = "embedded_hal")] -// use embedded_hal::blocking::i2c::{Read, Write, WriteRead}; #[cfg(any(feature = "f3", feature = "l4"))] use crate::dma::DmaInput; #[cfg(not(any(feature = "l552", feature = "h5")))] @@ -20,6 +18,8 @@ use crate::{ util::RccPeriph, MAX_ITERS, }; +#[cfg(feature = "embedded_hal")] +use embedded_hal::i2c; macro_rules! busy_wait { ($regs:expr, $flag:ident) => { @@ -63,7 +63,7 @@ macro_rules! busy_wait { /// I2C error #[non_exhaustive] -#[derive(Debug)] +#[derive(Debug, defmt::Format)] pub enum Error { /// Bus error Bus, @@ -399,12 +399,8 @@ where Ok(()) } - /// Read multiple words to a buffer. Can return an error due to Bus, Arbitration, or NACK. - pub fn read(&mut self, addr: u8, bytes: &mut [u8]) -> Result<(), Error> { - // 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) - + /// 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). + fn wait_for_idle(&self) -> Result<(), Error> { let mut i = 0; while self.regs.cr2.read().start().bit_is_set() { i += 1; @@ -412,123 +408,71 @@ where return Err(Error::Hardware); } } + Ok(()) + } - // 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. - self.set_cr2_read(addr, bytes.len() as u8); - - for byte in bytes { - // Wait until we have received something - busy_wait!(self.regs, rxne); - - *byte = self.regs.rxdr.read().rxdata().bits(); - } + /// Read multiple words to a buffer. Can return an error due to Bus, Arbitration, or NACK. + pub fn read(&mut self, addr: u8, bytes: &mut [u8]) -> Result<(), Error> { + self.wait_for_idle()?; + self.set_cr2_read(addr, bytes.len(), true); + self.read_bytes(bytes)?; Ok(()) } /// Write an array of words. Can return an error due to Bus, Arbitration, or NACK. pub fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { - // 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) - let mut i = 0; - while self.regs.cr2.read().start().bit_is_set() { - i += 1; - if i >= MAX_ITERS { - return Err(Error::Hardware); - } - } - - self.set_cr2_write(addr, bytes.len() as u8, true); - - for byte in bytes { - // Wait until we are allowed to send data - // (START has been ACKed or last byte when - // through) - busy_wait!(self.regs, txis); // TXDR register is empty - - // Put byte on the wire - self.regs.txdr.write(|w| unsafe { w.txdata().bits(*byte) }); - } + self.wait_for_idle()?; + self.set_cr2_write(addr, bytes.len(), true); + self.write_bytes(bytes)?; Ok(()) } /// Write and read an array of words. Can return an error due to Bus, Arbitration, or NACK. pub fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { - // 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) - let mut i = 0; - while self.regs.cr2.read().start().bit_is_set() { - i += 1; - if i >= MAX_ITERS { - return Err(Error::Hardware); - } - } - - self.set_cr2_write(addr, bytes.len() as u8, false); - - for byte in bytes { - // Wait until we are allowed to send data - // (START has been ACKed or last byte went through) - - busy_wait!(self.regs, txis); // TXDR register is empty + self.wait_for_idle()?; - // Put byte on the wire - self.regs.txdr.write(|w| unsafe { w.txdata().bits(*byte) }); - } - - // Wait until the write finishes before beginning to read. - busy_wait!(self.regs, tc); // transfer is complete + self.set_cr2_write(addr, bytes.len(), false); + self.write_bytes(bytes)?; // reSTART and prepare to receive bytes into `buffer` - - self.set_cr2_read(addr, buffer.len() as u8); - - for byte in buffer { - // Wait until we have received something - busy_wait!(self.regs, rxne); - - *byte = self.regs.rxdr.read().rxdata().bits(); - } + self.set_cr2_read(addr, buffer.len(), true); + self.read_bytes(buffer)?; Ok(()) } /// Helper function to prevent repetition between `write`, `write_read`, and `write_dma`. - fn set_cr2_write(&mut self, addr: u8, len: u8, autoend: bool) { + fn set_cr2_write(&mut self, addr: u8, len: usize, autoend: bool) { // L44 RM: "Master communication initialization (address phase) // In order to initiate the communication, the user must program the following parameters for // the addressed slave in the I2C_CR2 register: self.regs.cr2.write(|w| { - unsafe { - // Addressing mode (7-bit or 10-bit): ADD10 - w.add10().bit(self.cfg.address_bits as u8 != 0); - // Slave address to be sent: SADD[9:0] - // SADD0: "This bit is don’t care" - // SADD[7:1]: "These bits should be written with the 7-bit slave address to be sent" - w.sadd().bits((addr << 1) as u16); - // Transfer direction: RD_WRN - w.rd_wrn().clear_bit(); // write - // The number of bytes to be transferred: NBYTES[7:0]. If the number of bytes is equal to - // or greater than 255 bytes, NBYTES[7:0] must initially be filled with 0xFF. - w.nbytes().bits(len); - w.autoend().bit(autoend); // software end mode - // The user must then set the START bit in I2C_CR2 register. Changing all the above bits is - // not allowed when START bit is set. - // When the SMBus master wants to transmit the PEC, the PECBYTE bit must be set and the - // number of bytes must be programmed in the NBYTES[7:0] field, before setting the START - // bit. In this case the total number of TXIS interrupts is NBYTES-1. So if the PECBYTE bit is - // set when NBYTES=0x1, the content of the I2C_PECR register is automatically transmitted. - // If the SMBus master wants to send a STOP condition after the PEC, automatic end mode - // must be selected (AUTOEND=1). In this case, the STOP condition automatically follows the - // PEC transmission. - w.pecbyte().bit(self.cfg.smbus); - w.start().set_bit() - } + // Addressing mode (7-bit or 10-bit): ADD10 + w.add10().bit(self.cfg.address_bits as u8 != 0); + // Slave address to be sent: SADD[9:0] + // SADD0: "This bit is don’t care" + // SADD[7:1]: "These bits should be written with the 7-bit slave address to be sent" + #[cfg(not(any(feature = "wb", feature = "l5")))] + w.sadd().bits((addr << 1) as u16); + // Transfer direction: RD_WRN + w.rd_wrn().write(); + // The number of bytes to be transferred: NBYTES[7:0]. If the number of bytes is equal to + // or greater than 255 bytes, NBYTES[7:0] must initially be filled with 0xFF. + w.nbytes().bits(len as u8); + w.autoend().bit(autoend); // software end mode + // The user must then set the START bit in I2C_CR2 register. Changing all the above bits is + // not allowed when START bit is set. + // When the SMBus master wants to transmit the PEC, the PECBYTE bit must be set and the + // number of bytes must be programmed in the NBYTES[7:0] field, before setting the START + // bit. In this case the total number of TXIS interrupts is NBYTES-1. So if the PECBYTE bit is + // set when NBYTES=0x1, the content of the I2C_PECR register is automatically transmitted. + // If the SMBus master wants to send a STOP condition after the PEC, automatic end mode + // must be selected (AUTOEND=1). In this case, the STOP condition automatically follows the + // PEC transmission. + w.pecbyte().bit(self.cfg.smbus); + w.start().set_bit() }); // Note on start bit (RM): // If the I2C is already in master mode with AUTOEND = 0, setting this bit generates a @@ -538,26 +482,55 @@ where } /// Helper function to prevent repetition between `read`, `write_read`, and `read_dma`. - fn set_cr2_read(&mut self, addr: u8, len: u8) { + fn set_cr2_read(&mut self, addr: u8, len: usize, autoend: bool) { + // 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. self.regs.cr2.write(|w| { - unsafe { - w.add10().bit(self.cfg.address_bits as u8 != 0); - w.sadd().bits((addr << 1) as u16); - w.rd_wrn().set_bit(); // read - w.nbytes().bits(len); - w.autoend().set_bit(); // automatic end mode - // When the SMBus master wants to receive the PEC followed by a STOP at the end of the - // transfer, automatic end mode can be selected (AUTOEND=1). The PECBYTE bit must be - // set and the slave address must be programmed, before setting the START bit. In this case, - // after NBYTES-1 data have been received, the next received byte is automatically checked - // versus the I2C_PECR register content. A NACK response is given to the PEC byte, followed - // by a STOP condition. - w.pecbyte().bit(self.cfg.smbus); - w.start().set_bit() - } + w.add10().bit(self.cfg.address_bits as u8 != 0); + w.sadd().bits((addr << 1) as u16); + w.rd_wrn().read(); + w.nbytes().bits(len as u8); + w.autoend().bit(autoend); // automatic end mode + // When the SMBus master wants to receive the PEC followed by a STOP at the end of the + // transfer, automatic end mode can be selected (AUTOEND=1). The PECBYTE bit must be + // set and the slave address must be programmed, before setting the START bit. In this case, + // after NBYTES-1 data have been received, the next received byte is automatically checked + // versus the I2C_PECR register content. A NACK response is given to the PEC byte, followed + // by a STOP condition. + w.pecbyte().bit(self.cfg.smbus); + w.start().set_bit() }); } + fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), Error> { + for byte in buf { + // Wait until we have received something + busy_wait!(self.regs, rxne); + *byte = self.regs.rxdr.read().rxdata().bits(); + } + Ok(()) + } + + fn write_bytes(&mut self, buf: &[u8]) -> Result<(), Error> { + for byte in buf { + // Wait until we are allowed to send data + // (START has been ACKed or last byte went through) + busy_wait!(self.regs, txis); // TXDR register is empty + + // Put byte on the wire + self.regs.txdr.write(|w| unsafe { w.txdata().bits(*byte) }); + } + // Wait until the write finishes. + busy_wait!(self.regs, tc); + Ok(()) + } + + fn stop(&mut self) { + self.regs.cr2.write(|w| w.stop().set_bit()); + while self.regs.isr.read().busy().is_busy() {} + } + #[cfg(not(feature = "g0"))] /// Read data, using DMA. See L44 RM, 37.4.16: "Transmission using DMA" /// Note that the `channel` argument is unused on F3 and L4, since it is hard-coded, @@ -597,7 +570,7 @@ where // initialized before setting the START bit. The end of transfer is managed with the // NBYTES counter. Refer to Master transmitter on page 1151. // (The steps above are handled in the write this function performs.) - self.set_cr2_write(addr, len as u8, autoend); + self.set_cr2_write(addr, len, autoend); // • In slave mode: // – With NOSTRETCH=0, when all data are transferred using DMA, the DMA must be @@ -682,7 +655,7 @@ where // START bit are programmed by software. When all data are transferred using DMA, the // DMA must be initialized before setting the START bit. The end of transfer is managed // with the NBYTES counter. - self.set_cr2_read(addr, len as u8); + self.set_cr2_read(addr, len, true); // • In slave mode with NOSTRETCH=0, when all data are transferred using DMA, the // DMA must be initialized before the address match event, or in the ADDR interrupt @@ -735,42 +708,77 @@ where unsafe { self.regs.isr.read().bits() } } } -// -// #[cfg(feature = "embedded_hal")] -// // #[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))] -// impl Write for I2c -// where -// R: Deref + RccPeriph, -// { -// type Error = Error; -// -// fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { -// I2c::write(self, addr, bytes) -// } -// } -// -// #[cfg(feature = "embedded_hal")] -// // #[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))] -// impl Read for I2c -// where -// R: Deref + RccPeriph, -// { -// type Error = Error; -// -// fn read(&mut self, addr: u8, bytes: &mut [u8]) -> Result<(), Error> { -// I2c::read(self, addr, bytes) -// } -// } -// -// #[cfg(feature = "embedded_hal")] -// // #[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))] -// impl WriteRead for I2c -// where -// R: Deref + RccPeriph, -// { -// type Error = Error; -// -// fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> { -// I2c::write_read(self, addr, bytes, buffer) -// } -// } + +#[cfg(feature = "embedded_hal")] +impl i2c::Error for Error { + fn kind(&self) -> i2c::ErrorKind { + use i2c::{ErrorKind, NoAcknowledgeSource}; + + match self { + Error::Bus => ErrorKind::Bus, + Error::Arbitration => ErrorKind::ArbitrationLoss, + Error::Nack => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Unknown), + Error::Hardware => ErrorKind::Other, + } + } +} + +#[cfg(feature = "embedded_hal")] +impl i2c::ErrorType for I2c +where + R: Deref + RccPeriph, +{ + type Error = Error; +} + +#[cfg(feature = "embedded_hal")] +impl i2c::I2c for I2c +where + R: Deref + RccPeriph, +{ + fn transaction( + &mut self, + addr: u8, + operations: &mut [i2c::Operation<'_>], + ) -> Result<(), Self::Error> { + let mut ops = operations.iter_mut(); + let Some(mut prev_op) = ops.next() else { + return Ok(()); + }; + // Generate ST + self.wait_for_idle()?; + match &prev_op { + i2c::Operation::Write(rb) => self.set_cr2_write(addr, rb.len(), false), + i2c::Operation::Read(wb) => self.set_cr2_read(addr, wb.len(), false), + } + // Execute the first operation + match &mut prev_op { + i2c::Operation::Write(rb) => self.write_bytes(rb), + i2c::Operation::Read(wb) => self.read_bytes(wb), + }?; + + for op in ops { + // If operation type changes, generate SR and SAD+R/W + match (&prev_op, &op) { + (i2c::Operation::Read(_), i2c::Operation::Write(wb)) => { + self.wait_for_idle()?; + self.set_cr2_write(addr, wb.len(), false); + } + (i2c::Operation::Write(_), i2c::Operation::Read(rb)) => { + self.wait_for_idle()?; + self.set_cr2_read(addr, rb.len(), false); + } + _ => {} + } + + // Execute the operation + match op { + i2c::Operation::Write(rb) => self.write_bytes(rb), + i2c::Operation::Read(wb) => self.read_bytes(wb), + }?; + } + + self.stop(); + Ok(()) + } +} diff --git a/src/i2c_f4.rs b/src/i2c_f4.rs index a1c72fd..01f2e1b 100644 --- a/src/i2c_f4.rs +++ b/src/i2c_f4.rs @@ -25,7 +25,7 @@ pub enum I2cDevice { Three, } -#[derive(Debug)] +#[derive(Debug, defmt::Format)] pub enum Error { OVERRUN, NACK, diff --git a/src/qspi.rs b/src/qspi.rs index 9743c59..ebfa90b 100644 --- a/src/qspi.rs +++ b/src/qspi.rs @@ -89,7 +89,7 @@ pub enum SamplingEdge { } /// Indicates an error with the QSPI peripheral. -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, PartialEq, defmt::Format)] pub enum QspiError { Busy, Underflow, diff --git a/src/rtc.rs b/src/rtc.rs index 484d19b..25abe08 100644 --- a/src/rtc.rs +++ b/src/rtc.rs @@ -26,7 +26,7 @@ pub enum RtcClockSource { } /// RTC error type -#[derive(Debug)] +#[derive(Debug, defmt::Format)] pub enum Error { /// Invalid input error InvalidInputData, diff --git a/src/spi/mod.rs b/src/spi/mod.rs index 8e8e11b..78135c7 100644 --- a/src/spi/mod.rs +++ b/src/spi/mod.rs @@ -53,7 +53,7 @@ macro_rules! check_errors { /// SPI error #[non_exhaustive] -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, defmt::Format)] pub enum SpiError { /// Overrun occurred Overrun, diff --git a/src/timer.rs b/src/timer.rs index 9ebf5c2..4156e47 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -53,7 +53,7 @@ pub static TICK_OVERFLOW_COUNT: AtomicU32 = AtomicU32::new(0); // todo: Low power timer enabling etc. eg on L4, RCC_APB1ENR1.LPTIM1EN -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, defmt::Format)] /// Used for when attempting to set a timer period that is out of range. pub struct ValueError {} @@ -2033,9 +2033,25 @@ pub fn clear_update_interrupt(tim_num: u8) { let bits = 0xffff_ffff; match tim_num { + #[cfg(not(any(feature = "f373")))] 1 => periphs.TIM1.sr.write(|w| w.bits(bits).uif().clear_bit()), + #[cfg(not(any( + feature = "f410", + feature = "g070", + feature = "l5", // todo PAC bug? + feature = "wb55", // todo PAC bug? + )))] 2 => periphs.TIM2.sr.write(|w| w.bits(bits).uif().clear_bit()), - #[cfg(not(any(feature = "wl")))] + #[cfg(not(any( + feature = "f301", + feature = "l4x1", + // feature = "l412", + feature = "l5", // todo PAC bug? + feature = "l4x3", + feature = "f410", + feature = "wb", + feature = "wl" + )))] 3 => periphs.TIM3.sr.write(|w| w.bits(bits).uif().clear_bit()), #[cfg(not(any( feature = "f301", diff --git a/src/usart.rs b/src/usart.rs index a6bef21..1e28083 100644 --- a/src/usart.rs +++ b/src/usart.rs @@ -93,7 +93,7 @@ pub enum IrdaMode { /// Serial error #[non_exhaustive] -#[derive(Debug)] +#[derive(Debug, defmt::Format)] pub enum UartError { /// Framing error Framing, diff --git a/src/util.rs b/src/util.rs index 18c0458..86dd05f 100644 --- a/src/util.rs +++ b/src/util.rs @@ -416,6 +416,13 @@ impl RccPeriph for pac::I2C3 { } } +#[cfg(feature = "h7")] +impl RccPeriph for pac::I2C4 { + fn en_reset(rcc: &RegisterBlock) { + rcc_en_reset!(apb4, i2c4, rcc); + } +} + #[cfg(not(feature = "f301"))] // todo: Not sure what's going on here. impl RccPeriph for pac::SPI1 { fn en_reset(rcc: &RegisterBlock) {