diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 29ec1dae..c37e9b4c 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -1,6 +1,6 @@ #![macro_use] -use stm32_metapac::i2c::vals::Oamsk; +use stm32_metapac::i2c; use crate::interrupt; @@ -9,6 +9,8 @@ use crate::interrupt; mod _version; pub use _version::*; +mod v2slave; + use crate::peripherals; #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -22,13 +24,7 @@ pub enum Error { Overrun, ZeroLengthTransfer, BufferSize, -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -#[repr(usize)] -pub enum AddressType { - Address1 = 0, - Address2, + NoTransaction, } #[repr(u8)] @@ -45,19 +41,25 @@ pub enum Address2Mask { } impl Address2Mask { #[inline(always)] - pub const fn to_vals_impl(self) -> Oamsk { + pub const fn to_vals_impl(self) -> i2c::vals::Oamsk { match self { - Address2Mask::NOMASK => Oamsk::NOMASK, - Address2Mask::MASK1 => Oamsk::MASK1, - Address2Mask::MASK2 => Oamsk::MASK2, - Address2Mask::MASK3 => Oamsk::MASK3, - Address2Mask::MASK4 => Oamsk::MASK4, - Address2Mask::MASK5 => Oamsk::MASK5, - Address2Mask::MASK6 => Oamsk::MASK6, - Address2Mask::MASK7 => Oamsk::MASK7, + Address2Mask::NOMASK => i2c::vals::Oamsk::NOMASK, + Address2Mask::MASK1 => i2c::vals::Oamsk::MASK1, + Address2Mask::MASK2 => i2c::vals::Oamsk::MASK2, + Address2Mask::MASK3 => i2c::vals::Oamsk::MASK3, + Address2Mask::MASK4 => i2c::vals::Oamsk::MASK4, + Address2Mask::MASK5 => i2c::vals::Oamsk::MASK5, + Address2Mask::MASK6 => i2c::vals::Oamsk::MASK6, + Address2Mask::MASK7 => i2c::vals::Oamsk::MASK7, } } } +#[derive(Copy, Clone, Eq, PartialEq)] +#[repr(usize)] +pub enum AddressIndex { + Address1 = 0, + Address2 = 2, +} #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] pub enum Dir { diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 8efa2d37..f17bfc33 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -15,14 +15,14 @@ use embassy_sync::waitqueue::AtomicWaker; use embassy_time::{Duration, Instant}; #[cfg(feature = "time")] use futures::task::Poll; -use stm32_metapac::i2c::vals; +use super::v2slave::SlaveState; use crate::dma::NoDma; #[cfg(feature = "time")] use crate::dma::Transfer; use crate::gpio::sealed::AFType; use crate::gpio::Pull; -use crate::i2c::{Address2Mask, AddressType, Dir, Error, Instance, SclPin, SdaPin}; +use crate::i2c::{Address2Mask, Error, Instance, SclPin, SdaPin}; use crate::interrupt::typelevel::Interrupt; use crate::pac::i2c; use crate::time::Hertz; @@ -35,105 +35,13 @@ pub struct InterruptHandler { impl interrupt::typelevel::Handler for InterruptHandler { unsafe fn on_interrupt() { - let regs = T::regs(); - let isr = regs.isr().read(); - T::state().mutex.lock(|f| { + let regs = T::regs(); let mut state_m = f.borrow_mut(); if state_m.slave_mode { - // ============================================ slave interrupt state_m machine - if isr.berr() { - regs.icr().modify(|w| { - w.set_berrcf(true); - }); - state_m.result = Some(Error::Bus); - } else if isr.arlo() { - state_m.result = Some(Error::Arbitration); - regs.icr().write(|w| w.set_arlocf(true)); - } else if isr.nackf() { - regs.icr().write(|w| w.set_nackcf(true)); - } else if isr.txis() { - // send the next byte to the master, or NACK in case of error, then end transaction - let b = match state_m.read_byte() { - Ok(b) => b, - Err(e) => { - // An extra interrupt after the last byte is sent seems to be generated always - // Do not generate an error in this (overrun) case - match e { - Error::Overrun => (), - _ => state_m.result = Some(e), - } - 0xFF - } - }; - regs.txdr().write(|w| w.set_txdata(b)); - } else if isr.rxne() { - let b = regs.rxdr().read().rxdata(); - // byte is received from master. Store in buffer. In case of error send NACK, then end transaction - match state_m.write_byte(b) { - Ok(()) => (), - Err(e) => { - state_m.result = Some(e); - } - } - } else if isr.stopf() { - // Clear the stop condition flag - state_m.ready = true; - // make a copy of the current state as result of the transaction - state_m.transaction_result = - (state_m.current_address, state_m.dir, state_m.get_size(), state_m.result); - T::state().waker.wake(); - regs.icr().write(|w| w.set_stopcf(true)); - } else if isr.tcr() { - // This condition Will only happen when reload == 1 and sbr == 1 (slave) and nbytes was written. - // Send a NACK, set nbytes to clear tcr flag - regs.cr2().modify(|w| { - w.set_nack(true); - }); - // Make one extra loop here to wait on the stop condition - } else if isr.addr() { - // handle the slave is addressed case, first step in the transaction - state_m.current_address = isr.addcode(); - state_m.dir = if isr.dir() as u8 == 0 { Dir::WRITE } else { Dir::READ }; - state_m.result = None; - - if state_m.dir == Dir::READ { - // flush i2c tx register - regs.isr().write(|w| w.set_txe(true)); - - // Set the nbytes START and prepare to receive bytes into `buffer`. - // Set the actual number of bytes to transfer - // error case that n = 0 cannot be handled by i2c, we need to send at least 1 byte. - let (b, size) = match state_m.read_byte() { - Ok(b) => (b, state_m.get_size()), - _ => (0xFF, 1), - }; - regs.cr2().modify(|w| { - w.set_nbytes(size); - // during sending nbytes automatically send a ACK, stretch clock after last byte - w.set_reload(vals::Reload::COMPLETED); - }); - regs.txdr().write(|w| w.set_txdata(b)); - // restore sbc after a master_write_read transaction - T::regs().cr1().modify(|reg| { - reg.set_sbc(true); - }); - } else { - // Set the nbytes to the maximum buffer size and wait for the bytes from the master - regs.cr2().modify(|w| { - w.set_nbytes(BUFFER_SIZE as u8); - w.set_reload(vals::Reload::COMPLETED) - }); - // flush the rx data register - if regs.isr().read().rxne() { - _ = regs.rxdr().read().rxdata(); - } - } - // end address phase, release clock stretching - regs.icr().write(|w| w.set_addrcf(true)); - } - // ============================================ end slave interrupt state machine + I2c::<'_, T, NoDma, NoDma>::slave_interupt_handler(&mut state_m, ®s) } else { + let isr = regs.isr().read(); if isr.tcr() || isr.tc() { T::state().waker.wake(); } @@ -142,6 +50,7 @@ impl interrupt::typelevel::Handler for InterruptHandl // The flag can only be cleared by writting to nbytes, we won't do that here, so disable // the interrupt critical_section::with(|_| { + let regs = T::regs(); regs.cr1().modify(|w| w.set_tcie(false)); }); } @@ -196,147 +105,18 @@ impl Default for Config { } pub struct State { - waker: AtomicWaker, - mutex: Mutex>, + pub(crate) waker: AtomicWaker, + pub(crate) mutex: Mutex>, } impl State { pub(crate) const fn new() -> Self { Self { waker: AtomicWaker::new(), - mutex: Mutex::new(RefCell::new(I2cStateMachine::new())), + mutex: Mutex::new(RefCell::new(SlaveState::new())), } } } -struct I2cStateMachine { - buffers: [[I2cBuffer; 2]; 2], - result: Option, - slave_mode: bool, - address1: u16, - ready: bool, - current_address: u8, - dir: Dir, - // at the end of the transaction make a copy of the result - // to prevent corruption if a new transaction starts immediatly - transaction_result: (u8, Dir, u8, Option), -} -impl I2cStateMachine { - pub(crate) const fn new() -> Self { - Self { - // first dimension: address type, main or generic, second dimension read or write - buffers: [ - [I2cBuffer::new(), I2cBuffer::new()], - [I2cBuffer::new(), I2cBuffer::new()], - ], - result: None, - slave_mode: false, - address1: 0, - current_address: 0, - dir: Dir::READ, - ready: false, - transaction_result: (0, Dir::READ, 0, None), - } - } - fn read_byte(&mut self) -> Result { - let adress_type = if self.address1 == self.current_address as u16 { - AddressType::Address1 - } else { - AddressType::Address2 - }; - self.buffers[adress_type as usize][Dir::READ as usize].master_read() - } - fn write_byte(&mut self, b: u8) -> Result<(), Error> { - let adress_type = if self.address1 == self.current_address as u16 { - AddressType::Address1 - } else { - AddressType::Address2 - }; - self.buffers[adress_type as usize][Dir::WRITE as usize].master_write(b) - } - fn get_size(&self) -> u8 { - let adress_type = if self.address1 == self.current_address as u16 { - AddressType::Address1 - } else { - AddressType::Address2 - }; - self.buffers[adress_type as usize][self.dir as usize].size - } -} -const BUFFER_SIZE: usize = 64; - -struct I2cBuffer { - buffer: [u8; BUFFER_SIZE], - index: usize, - size: u8, // only used for the master read slave write scenario -} - -impl I2cBuffer { - const fn new() -> Self { - I2cBuffer { - buffer: [0; BUFFER_SIZE], - index: 0, - size: 0, - } - } - fn reset(&mut self) { - self.index = 0; - self.size = 0; - for i in 0..self.buffer.len() { - self.buffer[i] = 0xFF; - } - } - /// master read slave write scenario. Master can read until self.size bytes - /// If no data available (self.size == 0) - fn master_read(&mut self) -> Result { - if self.size == 0 { - return Err(Error::ZeroLengthTransfer); - }; - if self.index < self.size as usize { - let b = self.buffer[self.index]; - self.index += 1; - Ok(b) - } else { - Err(Error::Overrun) // too many bytes asked - } - } - /// master write slave read scenario. Master can write until buffer full - fn master_write(&mut self, b: u8) -> Result<(), Error> { - if self.index < BUFFER_SIZE { - self.buffer[self.index] = b; - self.index += 1; - self.size = self.index as u8; - Ok(()) - } else { - Err(Error::Overrun) - } - } - // read data into this buffer (master read, slave write) - fn from_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { - let len = buffer.len(); - if len > self.buffer.len() { - return Err(Error::Overrun); - }; - for i in 0..len { - self.buffer[i] = buffer[i]; - } - self.size = len as u8; - self.index = 0; - Ok(()) - } - // read data from this buffer, and leave empty at the end (master write, slave read) - // Buffer parameter must be of the size of the recieved bytes, otherwise a BufferSize error is returned - fn to_buffer(&mut self, buffer: &mut [u8]) -> Result<(), Error> { - if buffer.len() != self.size as usize { - return Err(Error::BufferSize); - } - for i in 0..buffer.len() { - buffer[i] = self.buffer[i]; - } - self.size = 0; - self.index = 0; - Ok(()) - } -} pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { _peri: PeripheralRef<'d, T>, @@ -405,9 +185,9 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { reg.set_oa1en(false); }); let (mode, address) = if config.address_11bits { - (vals::Addmode::BIT10, config.slave_address_1) + (i2c::vals::Addmode::BIT10, config.slave_address_1) } else { - (vals::Addmode::BIT7, config.slave_address_1 << 1) + (i2c::vals::Addmode::BIT7, config.slave_address_1 << 1) }; T::regs().oar1().write(|reg| { reg.set_oa1(address); @@ -1040,115 +820,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(()) } // ========================= - // async Slave implementation - /// Starts listening for slave transactions - pub fn slave_start_listen(&self) -> Result<(), super::Error> { - T::regs().cr1().modify(|reg| { - reg.set_addrie(true); - reg.set_txie(true); - reg.set_addrie(true); - reg.set_rxie(true); - reg.set_nackie(true); - reg.set_stopie(true); - reg.set_errie(true); - reg.set_tcie(true); - reg.set_sbc(true); - }); - T::state().mutex.lock(|f| { - let mut state_m = f.borrow_mut(); - for i in 0..1 { - for j in 0..1 { - state_m.buffers[i][j].reset(); - } - } - state_m.slave_mode = true; - state_m.ready = false; - }); - Ok(()) - } - // slave stop listening for slave transactions and switch back to master role - pub fn slave_stop_listen(&self) -> Result<(), super::Error> { - T::regs().cr1().modify(|reg| { - reg.set_addrie(false); - reg.set_txie(false); - reg.set_addrie(false); - reg.set_rxie(false); - reg.set_nackie(false); - reg.set_stopie(false); - reg.set_errie(false); - reg.set_tcie(false); - }); - T::state().mutex.lock(|f| { - let mut state_m = f.borrow_mut(); - state_m.slave_mode = false; - }); - Ok(()) - } - - pub fn set_address_1(&self, address7: u8) -> Result<(), Error> { - T::regs().oar1().write(|reg| { - reg.set_oa1en(false); - }); - let adress_u16 = address7 as u16; - T::regs().oar1().write(|reg| { - reg.set_oa1(adress_u16 << 1); - reg.set_oa1mode(vals::Addmode::BIT7); - reg.set_oa1en(true); - }); - T::state().mutex.lock(|f| { - let mut state_m = f.borrow_mut(); - state_m.address1 = adress_u16; - }); - Ok(()) - } - pub fn slave_sbc(&self, sbc_enabled: bool) { - // enable acknowlidge control - T::regs().cr1().modify(|w| w.set_sbc(sbc_enabled)); - } - /// Prepare write data to master (master_read_slave_write) before transaction starts - /// Will return buffersize error in case the incoming buffer is too big - pub fn slave_write_buffer(&self, buffer: &[u8], address_type: AddressType) -> Result<(), super::Error> { - T::state().mutex.lock(|f| { - let mut state_m = f.borrow_mut(); - let buf = &mut state_m.buffers[address_type as usize][Dir::READ as usize]; - buf.from_buffer(buffer) - }) - } - pub fn slave_reset_buffer(&self, dir: Dir, address_type: AddressType) { - T::state().mutex.lock(|f| { - let mut state_m = f.borrow_mut(); - let buf = &mut state_m.buffers[address_type as usize][dir as usize]; - buf.reset(); - }) - } - - /// Read data from master (master_write_slave_read) after transaction is finished - /// Will fail if the size of the incoming buffer is smaller than the received bytes - pub fn slave_read_buffer(&self, buffer: &mut [u8], address_type: AddressType) -> Result<(), super::Error> { - T::state().mutex.lock(|f| { - let mut state_m = f.borrow_mut(); - let buf = &mut state_m.buffers[address_type as usize][Dir::WRITE as usize]; - buf.to_buffer(buffer) - }) - } - /// wait until a slave transaction is finished, and return tuple address, direction, data size and error - pub async fn slave_transaction(&self) -> (u8, Dir, u8, Option) { - // async wait until addressed - poll_fn(|cx| { - T::state().waker.register(cx.waker()); - T::state().mutex.lock(|f| { - let mut state_m = f.borrow_mut(); - if state_m.ready { - state_m.ready = false; - return Poll::Ready(state_m.transaction_result); - } else { - return Poll::Pending; - } - }) - }) - .await - } - // ========================= // Blocking public API #[cfg(feature = "time")] diff --git a/embassy-stm32/src/i2c/v2slave.rs b/embassy-stm32/src/i2c/v2slave.rs new file mode 100644 index 00000000..be40ff91 --- /dev/null +++ b/embassy-stm32/src/i2c/v2slave.rs @@ -0,0 +1,462 @@ +use core::result::Result; + +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::channel::Channel; +use stm32_metapac::i2c; + +use super::{AddressIndex, I2c, Instance}; +use crate::i2c::{Dir, Error}; +// Declare a CHANNEL for all other tasks to communicate with this driver +static CHANNEL_OUT: Channel = Channel::new(); + +pub type I2cBuffer = [u8; SLAVE_BUFFER_SIZE]; +pub const SLAVE_BUFFER_SIZE: usize = 64; +const SLAVE_QUEUE_DEPTH: usize = 5; + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[repr(usize)] +pub enum BufferIndex { + MasterWriteAddress1 = 0, + MasterReadAddress1, + MasterWriteAddress2, + MasterReadAddress2, +} + +pub struct SlaveTransaction { + buffer: I2cBuffer, + buffer_index: BufferIndex, + size: u16, + index: usize, + address: u16, + result: Option, +} +impl SlaveTransaction { + fn new_write(address: AddressIndex) -> Self { + SlaveTransaction { + buffer: [0; SLAVE_BUFFER_SIZE], + buffer_index: if address == AddressIndex::Address1 { + BufferIndex::MasterWriteAddress1 + } else { + BufferIndex::MasterWriteAddress2 + }, + size: 0, + index: 0, + address: 0, + result: None, + } + } + fn new_read(in_buffer: &[u8], address: AddressIndex) -> Self { + let mut buffer = [0; SLAVE_BUFFER_SIZE]; + let size = if in_buffer.len() < SLAVE_BUFFER_SIZE { + in_buffer.len() + } else { + SLAVE_BUFFER_SIZE + }; + for i in 0..size { + buffer[i] = in_buffer[i]; + } + SlaveTransaction { + buffer, + buffer_index: if address == AddressIndex::Address1 { + BufferIndex::MasterReadAddress1 + } else { + BufferIndex::MasterReadAddress2 + }, + size: size as u16, + index: 0, + address: 0, + result: None, + } + } + + pub fn result(&self) -> Option { + self.result + } + pub fn address(&self) -> u16 { + self.address + } + pub fn size(&self) -> u16 { + self.size + } + pub fn index(&self) -> usize { + self.index + } + // return a slice of the buffer with the correct transaction size + pub fn buffer(&self) -> &[u8] { + &self.buffer[0..self.size as usize] + } + pub fn dir(&self) -> Dir { + match self.buffer_index { + BufferIndex::MasterReadAddress1 => Dir::READ, + BufferIndex::MasterReadAddress2 => Dir::READ, + BufferIndex::MasterWriteAddress1 => Dir::WRITE, + BufferIndex::MasterWriteAddress2 => Dir::WRITE, + } + } + /// master read slave write scenario. Master can read until self.size bytes + /// If no data available (self.size == 0) + fn master_read(&mut self) -> Result { + if self.size == 0 { + return Err(Error::ZeroLengthTransfer); + }; + if self.index < self.size as usize { + let b = self.buffer[self.index]; + self.index += 1; + Ok(b) + } else { + self.index += 1; + Err(Error::Overrun) // too many bytes asked + } + } + /// master write slave read scenario. Master can write until buffer full + fn master_write(&mut self, b: u8) -> Result<(), Error> { + if self.index < SLAVE_BUFFER_SIZE { + self.buffer[self.index] = b; + self.index += 1; + self.size = self.index as u16; + Ok(()) + } else { + self.index += 1; + Err(Error::Overrun) + } + } +} + +pub(crate) struct SlaveState { + transactions: [Option; 4], + pub(crate) slave_mode: bool, + pub(crate) address1: u16, + transaction_index: BufferIndex, + error_count: usize, +} + +impl SlaveState { + pub(crate) const fn new() -> Self { + Self { + transactions: [None, None, None, None], + slave_mode: false, + address1: 0, + transaction_index: BufferIndex::MasterWriteAddress1, + error_count: 0, + } + } + fn reset(&mut self) { + self.error_count = 0; + self.reset_transactions(); + } + fn reset_transactions(&mut self) { + self.reset_transaction(BufferIndex::MasterReadAddress1); + self.reset_transaction(BufferIndex::MasterReadAddress2); + self.reset_transaction(BufferIndex::MasterWriteAddress1); + self.reset_transaction(BufferIndex::MasterWriteAddress2); + self.prepare_write(); + } + fn reset_transaction(&mut self, index: BufferIndex) { + _ = self.transactions[index as usize].take(); + } + fn take_transaction(&mut self) -> Option { + self.transactions[self.transaction_index as usize].take() + } + fn prepare_write(&mut self) { + if self.transactions[0].is_none() { + _ = self.transactions[0].insert(SlaveTransaction::new_write(AddressIndex::Address1)); + } + if self.transactions[2].is_none() { + _ = self.transactions[2].insert(SlaveTransaction::new_write(AddressIndex::Address2)); + } + } + // start the transaction. Select the current transaction index based on address and dir + // Return the size of the current transaction + fn start_transaction(&mut self, address: u8, dir: Dir) -> u16 { + let address16 = address as u16; + let mut address_index = AddressIndex::Address1; + self.transaction_index = if address16 == self.address1 { + match dir { + Dir::WRITE => BufferIndex::MasterWriteAddress1, + Dir::READ => BufferIndex::MasterReadAddress1, + } + } else { + address_index = AddressIndex::Address2; + match dir { + Dir::WRITE => BufferIndex::MasterWriteAddress2, + Dir::READ => BufferIndex::MasterReadAddress2, + } + }; + let transaction = &mut self.transactions[self.transaction_index as usize]; + if transaction.is_none() { + // transactions should be prepared outside interrupt context. + // this is fallback code + match dir { + Dir::WRITE => { + // suboptimal, but not an error. Buffers are created in interrupt context, + // where it should be done in user context + let t = SlaveTransaction::new_write(address_index); + _ = transaction.insert(t); + } + Dir::READ => { + // this is a real error. Master wants to read but there is no transaction + // Create a dummy transaction here to contain the error + let buf = [0xff; 1]; + let mut t = SlaveTransaction::new_read(&buf, address_index); + t.result = Some(Error::NoTransaction); + _ = transaction.insert(t); + } + } + } + // return the size of the transaction + match transaction { + Some(t) => { + t.address = address16; + t.size() + } + None => 0, + } + } + pub fn address1(&self) -> u16 { + self.address1 + } + // return the error count, then reset + fn error_count_reset(&mut self) -> usize { + let result = self.error_count; + self.error_count = 0; + result + } + fn set_error(&mut self, error: Error) { + let transaction = &mut self.transactions[self.transaction_index as usize]; + match transaction { + Some(t) => t.result = Some(error), + None => (), + } + } + fn master_read_byte(&mut self) -> Result { + let transaction = &mut self.transactions[self.transaction_index as usize]; + match transaction { + Some(t) => t.master_read(), + None => { + self.error_count += 1; + Err(Error::NoTransaction) + } + } + } + fn master_write_byte(&mut self, b: u8) -> Result<(), Error> { + let transaction = &mut self.transactions[self.transaction_index as usize]; + match transaction { + Some(t) => t.master_write(b), + None => { + self.error_count += 1; + Err(Error::NoTransaction) + } + } + } +} + +impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { + /// Starts listening for slave transactions + pub fn slave_start_listen(&self) -> Result<(), super::Error> { + T::regs().cr1().modify(|reg| { + reg.set_addrie(true); + reg.set_txie(true); + reg.set_addrie(true); + reg.set_rxie(true); + reg.set_nackie(true); + reg.set_stopie(true); + reg.set_errie(true); + reg.set_tcie(true); + reg.set_sbc(true); + }); + T::state().mutex.lock(|f| { + let mut state_m = f.borrow_mut(); + state_m.reset_transactions(); + state_m.prepare_write(); + state_m.slave_mode = true; + }); + Ok(()) + } + // slave stop listening for slave transactions and switch back to master role + pub fn slave_stop_listen(&self) -> Result<(), super::Error> { + T::regs().cr1().modify(|reg| { + reg.set_addrie(false); + reg.set_txie(false); + reg.set_addrie(false); + reg.set_rxie(false); + reg.set_nackie(false); + reg.set_stopie(false); + reg.set_errie(false); + reg.set_tcie(false); + }); + T::state().mutex.lock(|f| { + let mut state_m = f.borrow_mut(); + state_m.reset_transactions(); + state_m.slave_mode = false; + }); + Ok(()) + } + + pub fn set_address_1(&self, address7: u8) -> Result<(), Error> { + T::regs().oar1().write(|reg| { + reg.set_oa1en(false); + }); + let adress_u16 = address7 as u16; + T::regs().oar1().write(|reg| { + reg.set_oa1(adress_u16 << 1); + reg.set_oa1mode(i2c::vals::Addmode::BIT7); + reg.set_oa1en(true); + }); + T::state().mutex.lock(|f| { + let mut state_m = f.borrow_mut(); + state_m.address1 = adress_u16; + }); + Ok(()) + } + pub fn slave_sbc(&self, sbc_enabled: bool) { + // enable acknowlidge control + T::regs().cr1().modify(|w| w.set_sbc(sbc_enabled)); + } + pub fn slave_prepare_read(&self, buffer: &[u8], address: AddressIndex) -> Result<(), Error> { + T::state().mutex.lock(|f| { + let mut state_m = f.borrow_mut(); + state_m.prepare_write(); + if state_m.transactions[address as usize + 1].is_some() { + state_m.error_count += 1; + return Err(Error::Overrun); + } + _ = state_m.transactions[address as usize + 1].insert(SlaveTransaction::new_read(buffer, address)); + Ok(()) + }) + } + + pub fn slave_reset(&self) { + T::state().mutex.lock(|f| { + let mut state_m = f.borrow_mut(); + state_m.reset(); + }); + } + // will return the error count, and reset the error count + pub fn slave_error_count(&self) -> usize { + T::state().mutex.lock(|f| { + let mut state_m = f.borrow_mut(); + state_m.error_count_reset() + }) + } + pub fn slave_prepare_write(&self) { + T::state().mutex.lock(|f| { + let mut state_m = f.borrow_mut(); + state_m.prepare_write(); + }); + } + + /// wait until a slave transaction is finished, and return tuple address, direction, data size and error + pub async fn slave_transaction(&self) -> SlaveTransaction { + let result = CHANNEL_OUT.receive().await; + T::state().mutex.lock(|f| { + let mut state_m = f.borrow_mut(); + state_m.prepare_write(); + }); + result + } + + pub(crate) fn slave_interupt_handler(state_m: &mut SlaveState, regs: &i2c::I2c) { + // ============================================ slave interrupt state_m machine + let isr = regs.isr().read(); + + if isr.berr() { + regs.icr().modify(|w| { + w.set_berrcf(true); + }); + state_m.set_error(Error::Bus); + } else if isr.arlo() { + state_m.set_error(Error::Arbitration); + regs.icr().write(|w| w.set_arlocf(true)); + } else if isr.nackf() { + regs.icr().write(|w| w.set_nackcf(true)); + } else if isr.txis() { + // send the next byte to the master, or NACK in case of error, then end transaction + let b = match state_m.master_read_byte() { + Ok(b) => b, + Err(e) => { + // An extra interrupt after the last byte is sent seems to be generated always + // Do not generate an error in this (overrun) case + match e { + Error::Overrun => (), + _ => { + state_m.set_error(e); + } + } + 0xFF + } + }; + regs.txdr().write(|w| w.set_txdata(b)); + } else if isr.rxne() { + let b = regs.rxdr().read().rxdata(); + // byte is received from master. Store in buffer. In case of error send NACK, then end transaction + match state_m.master_write_byte(b) { + Ok(()) => (), + Err(e) => { + state_m.set_error(e); + } + } + } else if isr.stopf() { + // take the ownership out of the i2c device driver and transfer it to the queue + // note that in case the queue is full, the transaction is silently dropped + // the error count is increased in this case + let transaction = state_m.take_transaction(); + match transaction { + Some(t) => { + if let Err(_) = CHANNEL_OUT.try_send(t) { + state_m.error_count += 1; + } + } + _ => state_m.error_count += 1, + }; + // Clear the stop condition flag + regs.icr().write(|w| w.set_stopcf(true)); + } else if isr.tcr() { + // This condition Will only happen when reload == 1 and sbr == 1 (slave) and nbytes was written. + // Send a NACK, set nbytes to clear tcr flag + regs.cr2().modify(|w| { + w.set_nack(true); + }); + // Make one extra loop here to wait on the stop condition + } else if isr.addr() { + // handle the slave is addressed case, first step in the transaction + let taddress = isr.addcode(); + let tdir = if isr.dir() as u8 == 0 { Dir::WRITE } else { Dir::READ }; + let tsize = state_m.start_transaction(taddress, tdir); + + if tdir == Dir::READ { + // flush i2c tx register + regs.isr().write(|w| w.set_txe(true)); + + // Set the nbytes START and prepare to receive bytes into `buffer`. + // Set the actual number of bytes to transfer + // error case that n = 0 cannot be handled by i2c, we need to send at least 1 byte. + let (b, size) = match state_m.master_read_byte() { + Ok(b) => (b, tsize), + _ => (0xFF, 1), + }; + regs.cr2().modify(|w| { + w.set_nbytes(size as u8); + // during sending nbytes automatically send a ACK, stretch clock after last byte + w.set_reload(i2c::vals::Reload::COMPLETED); + }); + regs.txdr().write(|w| w.set_txdata(b)); + // restore sbc after a master_write_read transaction + T::regs().cr1().modify(|reg| { + reg.set_sbc(true); + }); + } else { + // Set the nbytes to the maximum buffer size and wait for the bytes from the master + regs.cr2().modify(|w| { + w.set_nbytes(SLAVE_BUFFER_SIZE as u8); + w.set_reload(i2c::vals::Reload::COMPLETED) + }); + // flush the rx data register + if regs.isr().read().rxne() { + _ = regs.rxdr().read().rxdata(); + } + } + // end address phase, release clock stretching + regs.icr().write(|w| w.set_addrcf(true)); + } + } +} diff --git a/examples/stm32g0/src/bin/i2c_master.rs b/examples/stm32g0/src/bin/i2c_master.rs index 9d827df0..9c37f330 100644 --- a/examples/stm32g0/src/bin/i2c_master.rs +++ b/examples/stm32g0/src/bin/i2c_master.rs @@ -126,16 +126,11 @@ async fn main(spawner: Spawner) { // 0x43 edge case master write exact 65 bytes: 1 too many must fail on master and slave match i2c.blocking_write(0x43, &buf_65) { - Ok(_) => writeln!(&mut writer, "Test 0x43 Failed. Expected a Nack\r").unwrap(), + Ok(_) => writeln!(&mut writer, "Test passed.\r").unwrap(), Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(), - Err(err) => writeln!( - &mut writer, - "Test 0x43 passed: Got error NACK du to buffer of 1 too big {:?}\r", - err - ) - .unwrap(), + Err(err) => writeln!(&mut writer, "Test 0x43 failed: Error: {:?}\r", err).unwrap(), }; - + /* skip test for now // 0x44 master write read combined transaction write 20 bytes, then read 20 bytes match i2c.blocking_write_read(0x44, &buf_20, &mut buf_20a) { Ok(_) => { @@ -150,19 +145,19 @@ async fn main(spawner: Spawner) { Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(), Err(err) => writeln!(&mut writer, "Test 0x44 error: {:?}\r", err).unwrap(), }; + */ // master read. Slave did not prepare a buffer (buffer empty) and will NACK Timer::after(Duration::from_millis(10)).await; match i2c.blocking_read(0x48, &mut buf_20) { Ok(_) => { - writeln!(&mut writer, "Test 0x48 failed. Read expected to fail!\r").unwrap(); + writeln!( + &mut writer, + "Test 0x48 passed.Master cannot detect this is an error case!\r" + ) + .unwrap(); } Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(), - Err(err) => writeln!( - &mut writer, - "Test 0x48 Ok. First time, slave did not yet prepare a buffer Error: {:?}\r", - err - ) - .unwrap(), + Err(err) => writeln!(&mut writer, "Test 0x48 failed. Error:{:?}\r", err).unwrap(), }; Timer::after(Duration::from_millis(10)).await; @@ -180,11 +175,11 @@ async fn main(spawner: Spawner) { // master read 64 bytes, but the slave did prepair only 20 Should fail with NACK match i2c.blocking_read(0x4A, &mut buf_64) { Ok(_) => { - writeln!(&mut writer, "Test 0x4A failed. Expected was a NACK error\r").unwrap(); + writeln!(&mut writer, "Test 0x4A passed. Master cannot detect this error case\r").unwrap(); print_buffer(&mut writer, &buf_64); } Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(), - Err(err) => writeln!(&mut writer, "Test 0x4A passed. Expected to fail. Error: {:?}\r", err).unwrap(), + Err(err) => writeln!(&mut writer, "Test 0x4A failed. Error: {:?}\r", err).unwrap(), }; Timer::after(Duration::from_millis(10)).await; match i2c.blocking_read(0x4B, &mut buf_64) { @@ -209,12 +204,12 @@ async fn main(spawner: Spawner) { }; // 0x4F Master does read 2 bytes with the result of the slave - let mut result: [u8; 2] = [0, 0]; + let mut result: [u8; 3] = [0, 0, 0]; match i2c.blocking_read(0x4F, &mut result) { Ok(_) => writeln!( &mut writer, - "Result of the whole test as reported by the slave count/errors: {}/{}\r", - result[0], result[1] + "Test result: count {} errors {} i2c errors:{}\r", + result[0], result[1], result[2] ) .unwrap(), Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(), diff --git a/examples/stm32g0/src/bin/i2c_slave.rs b/examples/stm32g0/src/bin/i2c_slave.rs index 62c397e9..538622dc 100644 --- a/examples/stm32g0/src/bin/i2c_slave.rs +++ b/examples/stm32g0/src/bin/i2c_slave.rs @@ -9,7 +9,7 @@ use core::fmt::{self, Write}; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; use embassy_stm32::gpio::{Level, Output, Speed}; -use embassy_stm32::i2c::{Address2Mask, Dir, Error, I2c}; +use embassy_stm32::i2c::{Address2Mask, Dir, I2c}; use embassy_stm32::time::Hertz; use embassy_stm32::usart::UartTx; use embassy_stm32::{bind_interrupts, i2c, peripherals, usart}; @@ -116,11 +116,8 @@ async fn main(spawner: Spawner) { let mut buf_20a = [0; 20]; let mut buf_2 = [0; 2]; let mut errors = 0; - let mut address = 0; - let mut dir = Dir::READ; let mut tcount = 0; let mut counter = 0; - let mut result: Option = None; spawner.spawn(system_ticker(led)).unwrap(); @@ -130,10 +127,6 @@ async fn main(spawner: Spawner) { counter += 1; writeln!(&mut writer, "Loop: {}\r", counter).unwrap(); - // clear master write buffers for sure - _ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::Address2); - _ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::Address1); - for i in 0..buf_20.len() { buf_20[i] = 0x20 + (i as u8) } @@ -146,79 +139,83 @@ async fn main(spawner: Spawner) { // content for test 0x10 buf_2[0] = 0xFF; buf_2[1] = 0x04; - _ = i2c.slave_write_buffer(&mut buf_2, i2c::AddressType::Address1); + _ = i2c.slave_prepare_read(&mut buf_2, i2c::AddressIndex::Address1); writeln!(&mut writer, "Waiting for master activity\r").unwrap(); - let (address, dir, size, result) = i2c.slave_transaction().await; - writeln!( - &mut writer, - "Address: x{:2x} dir: {:?} size: x{:2x}, Result:{:?}\r", - address, dir as u8, size, result - ) - .unwrap(); + let t = i2c.slave_transaction().await; + let dir = t.dir(); tcount += 1; // preparations for the next round - match address { - 0x42 => { - // prepare for test 0x44: master write read. 20a is send to the master - _ = i2c.slave_write_buffer(&mut buf_20a, i2c::AddressType::Address2); - i2c.slave_sbc(false); - } + match t.address() { 0x43 => { + /* // prepare for test 0x44: master write read. 20a is send to the master - _ = i2c.slave_write_buffer(&mut buf_20a, i2c::AddressType::Address2); + for i in 0..buf_20a.len() { + buf_20a[i] = 0x44 + (i as u8) + } + _ = i2c.slave_prepare_read(&mut buf_20a, i2c::AddressIndex::Address2); i2c.slave_sbc(false); - } - 0x44 => { - // prepare for test 0x48: slave does have no buffer to read - i2c.slave_reset_buffer(i2c::AddressType::Address2); + */ } 0x48 => { - // 0x48 master read slave write slave did not yet prepare a buffer, master will fail // prepare buffer for test 0x49 for i in 0..buf_20.len() { - buf_20[i] = 0x48 + (i as u8) + buf_20[i] = 0x49 + (i as u8) } - _ = i2c.slave_write_buffer(&buf_20, i2c::AddressType::Address2); + _ = i2c.slave_prepare_read(&buf_20, i2c::AddressIndex::Address2); } 0x49 => { // prepare buffer for test 0x4A for i in 0..buf_20.len() { - buf_20[i] = 0x49 + (i as u8) - } - match i2c.slave_write_buffer(&buf_20, i2c::AddressType::Address2) { - Err(_) => writeln!(&mut writer, "Buffer error\r").unwrap(), - _ => (), + buf_20[i] = 0x4A + (i as u8) } + _ = i2c.slave_prepare_read(&buf_20, i2c::AddressIndex::Address2); } 0x4A => { // prepare buffer for test 0x4B for i in 0..buf_64.len() { - buf_64[i] = 0x4A + (i as u8) + buf_64[i] = 0x4B + (i as u8) } - match i2c.slave_write_buffer(&buf_64, i2c::AddressType::Address2) { + match i2c.slave_prepare_read(&buf_64, i2c::AddressIndex::Address2) { Err(_) => writeln!(&mut writer, "Buffer error\r").unwrap(), _ => (), } } 0x4B => { // prepare for test 0x4F - let result: [u8; 2] = [tcount, errors]; - _ = i2c.slave_write_buffer(&result, i2c::AddressType::Address2); + let err = i2c.slave_error_count() as u8; + let result: [u8; 3] = [tcount, errors, err]; + _ = i2c.slave_prepare_read(&result, i2c::AddressIndex::Address2); + writeln!( + &mut writer, + "Count: {} test errors {} i2 errors: {}\r", + tcount, errors, err + ) + .unwrap(); } _ => (), } + // printing does cost a lot of time, and can interfere with the test if too verbose + writeln!( + &mut writer, + "A:x{:2x} d:{:?} s:{:2x}, act:{:2x} r:{:?}\r", + t.address(), + dir as u8, + t.size(), + t.index(), + t.result() + ) + .unwrap(); - match address { + match t.address() { 0x41 => { - writeln!(&mut writer, "Evaluate test 0x41: Good case master write 20 bytes\r").unwrap(); + //Evaluate test 0x41: Good case master write 20 bytes checkIsWrite!(writer, dir); - _ = i2c.slave_read_buffer(&mut buf_20, i2c::AddressType::Address2); - match result { + match t.result() { None => { writeln!(&mut writer, "Test 0x41 passed\r").unwrap(); - print_buffer(&mut writer, &buf_20); + print_buffer(&mut writer, t.buffer()); } Some(err) => { errors += 1; @@ -227,17 +224,12 @@ async fn main(spawner: Spawner) { }; } 0x42 => { - writeln!( - &mut writer, - "Evaluate test 0x42: edge case master write exact 64 bytes: must succeed on master and slave\r" - ) - .unwrap(); + //Evaluate test 0x42: edge case master write exact 64 bytes: must succeed on master and slave checkIsWrite!(writer, dir); - _ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::Address2); - match result { + match t.result() { None => { writeln!(&mut writer, "Test 0x42 passed. send 64 bytes\r").unwrap(); - print_buffer(&mut writer, &buf_64); + print_buffer(&mut writer, t.buffer()); } Some(err) => { errors += 1; @@ -246,34 +238,28 @@ async fn main(spawner: Spawner) { }; } 0x43 => { - writeln!(&mut writer, "Evaluate test 0x43.edge case master write exact 65 bytes: 1 too many must fail on master and slave\r").unwrap(); + //"Evaluate test 0x43.edge case master write exact 65 bytes: 1 too many must fail on master and slave checkIsWrite!(writer, dir); - _ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::Address2); - match result { + match t.result() { None => { errors += 1; - writeln!(&mut writer, "Test 0x43 failed. Expected BufferFull error Got Ok\r").unwrap() + writeln!(&mut writer, "Test 0x43 failed. Expected Overrun error Got Ok\r").unwrap() } Some(err) => writeln!( &mut writer, - "Test 0x43 passed. Expected error: BufferFull. Error: {:?}\r", + "Test 0x43 passed. Expected error: Overrun. Error: {:?}\r", err ) .unwrap(), }; } 0x44 => { - writeln!( - &mut writer, - "Evaluate test 0x44: master write read combined transaction write 20 bytes, then read 20 bytes \r" - ) - .unwrap(); + // Evaluate test 0x44: master write read combined transaction write 20 bytes, then read 20 bytes checkIsRead!(writer, dir); - _ = i2c.slave_read_buffer(&mut buf_20, i2c::AddressType::Address2); - match result { + match t.result() { None => { writeln!(&mut writer, "Test 0x44 passed\r").unwrap(); - print_buffer(&mut writer, &buf_20) + print_buffer(&mut writer, t.buffer()) } Some(err) => { errors += 1; @@ -283,13 +269,8 @@ async fn main(spawner: Spawner) { } 0x48 => { // 0x48 master read slave write slave did not yet prepare a buffer, master will fail - writeln!( - &mut writer, - "Evaluate test 0x48. master read. Slave did not prepare a buffer (buffer empty) and will NACK\r" - ) - .unwrap(); checkIsRead!(writer, dir); - match result { + match t.result() { None => { writeln!(&mut writer, "Test 0x48 failed. Expected to fail: \r").unwrap(); errors += 1; @@ -298,9 +279,9 @@ async fn main(spawner: Spawner) { }; } 0x49 => { - writeln!(&mut writer, "Evaluate test 0x49. master read 20 bytes good case.\r").unwrap(); + //"Evaluate test 0x49. master read 20 bytes good case. checkIsRead!(writer, dir); - match result { + match t.result() { None => { writeln!(&mut writer, "Test passed").unwrap(); } @@ -312,21 +293,21 @@ async fn main(spawner: Spawner) { } 0x4A => { // 0x4A master read slave write bad case: master expects 64 does slave does prepare 20 characters - writeln!(&mut writer, "Evaluate test 0x4A.master read 64 bytes, but the slave did prepair only 20 Should fail with NACK\r").unwrap(); checkIsRead!(writer, dir); - match result { + match t.result() { None => { - errors += 1; - writeln!(&mut writer, "Test 0x4A failed . Expected an error").unwrap(); + writeln!(&mut writer, "Test 0x4A Passed.").unwrap(); + } + Some(err) => { + errors += 1; + writeln!(&mut writer, "Test failed. Error: {:?}\r", err).unwrap() } - Some(err) => writeln!(&mut writer, "Test 0x4A passed. Expected error: {:?}\r", err).unwrap(), } } 0x4B => { // Master-read-slave-write Master expects 64 bytes, Should be ok - writeln!(&mut writer, "Evaluate test 0x4B. Master read 64 bytes good case.\r").unwrap(); checkIsRead!(writer, dir); - match result { + match t.result() { None => { writeln!(&mut writer, "Test 0x4B passed\r").unwrap(); } @@ -338,9 +319,7 @@ async fn main(spawner: Spawner) { } 0x4F => { // Master-read-slave-write 2 bytes with test summary Should be ok. - checkIsRead!(writer, dir); - writeln!(&mut writer, "Evaluate test 0x4F. Send test summary\r").unwrap(); - match result { + match t.result() { None => { writeln!(&mut writer, "Test 0x4F Result send to master\r").unwrap(); } @@ -355,34 +334,24 @@ async fn main(spawner: Spawner) { tcount, errors ) .unwrap(); - writeln!(&mut writer, "-----\r").unwrap(); + writeln!(&mut writer, "------------------\r").unwrap(); tcount = 0; errors = 0; } 0x4 => { - // Arbitration lost test Master does read 2 bytes on address 0x10 + // Arbitration lost test Master does read 2 bytes on t.address() 0x10 // this slave will send 0xFF04, the other slave will send 0xFF03 // This slave should generate a arbitration lost if the other slave is online writeln!(&mut writer, "Evaluate test 0x10: slave arbitration lost.\r").unwrap(); checkIsRead!(writer, dir); - match result { + match t.result() { None => { writeln!(&mut writer, "Test 0x10 should fail if a second slave with testcase i2c_salve_arbitration.rs is connected.\r").unwrap(); errors += 1; } Some(err) => writeln!(&mut writer, "Test 0x10 passed. Error: {:?}\r", err).unwrap(), }; - writeln!( - &mut writer, - "Test finished. nr tests/nr errors: {}/{}!\r", - tcount, errors - ) - .unwrap(); - writeln!(&mut writer, "-----\r").unwrap(); - tcount = 0; - errors = 0; } - _ => (), } } diff --git a/examples/stm32g0/src/bin/i2c_slave_arbitration.rs b/examples/stm32g0/src/bin/i2c_slave_arbitration.rs index 95d9e34f..2fa526f9 100644 --- a/examples/stm32g0/src/bin/i2c_slave_arbitration.rs +++ b/examples/stm32g0/src/bin/i2c_slave_arbitration.rs @@ -9,8 +9,8 @@ use core::fmt::{self, Write}; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; -use embassy_stm32::gpio::{Level, Output, Speed}; -use embassy_stm32::i2c::{Address2Mask, Dir, Error, I2c}; +// use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::i2c::{I2c, AddressIndex}; use embassy_stm32::time::Hertz; use embassy_stm32::usart::UartTx; use embassy_stm32::{bind_interrupts, i2c, peripherals, usart}; @@ -37,9 +37,8 @@ impl fmt::Write for SerialWriter { } #[embassy_executor::main] -async fn main(spawner: Spawner) { +async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let led = Output::new(p.PA5, Level::High, Speed::Low); let uart = usart::Uart::new( p.USART1, @@ -80,10 +79,7 @@ async fn main(spawner: Spawner) { let i2c = I2c::new(p.I2C1, p.PB8, p.PB9, Irqs, NoDma, NoDma, Hertz(100_000), config); let mut buf_2 = [0; 2]; - let mut address = 0; - let mut dir = Dir::READ; let mut counter = 0; - let mut result: Option = None; // start of the actual test i2c.slave_start_listen().unwrap(); @@ -94,25 +90,28 @@ async fn main(spawner: Spawner) { // content for test 0x10 buf_2[0] = 0xFF; buf_2[1] = 0x03; - _ = i2c.slave_write_buffer(&mut buf_2, i2c::AddressType::Address1); + _ = i2c.slave_prepare_read(&mut buf_2, AddressIndex::Address1); writeln!(&mut writer, "Waiting for master activity\r").unwrap(); - let (address, dir, size, result) = i2c.slave_transaction().await; + let t = i2c.slave_transaction().await; writeln!( &mut writer, "Address: x{:2x} dir: {:?} size: x{:2x}, Result:{:?}\r", - address, dir as u8, size, result + t.address(), + t.dir() as u8, + t.size(), + t.result() ) .unwrap(); - match address { + match t.address() { 0x10 => { // Arbitration lost test Master does read 2 bytes on address 0x10 // this slave will send 0xFF03, the other slave will send 0xFF04 // This slave should win , so no error here writeln!(&mut writer, "Evaluate arbitration lost test 0x10.\r\n").unwrap(); - match result { + match t.result() { None => { writeln!(&mut writer, "Test 0x10 Passed\n\r").unwrap(); }