From 007855423e602798d1065cc047abcd0ff2e0a3f0 Mon Sep 17 00:00:00 2001 From: anton smeenk Date: Fri, 20 Oct 2023 22:12:37 +0200 Subject: [PATCH] Slave: write Starts working work in progress --- embassy-stm32/src/i2c/mod.rs | 11 +- embassy-stm32/src/i2c/v2.rs | 391 ++++++++++++++++++++++++- examples/stm32g0/src/bin/i2c_master.rs | 170 +++++------ examples/stm32g0/src/bin/i2c_slave.rs | 279 ++++++++++++++++++ 4 files changed, 743 insertions(+), 108 deletions(-) create mode 100644 examples/stm32g0/src/bin/i2c_slave.rs diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index dde1a504..37b33fe9 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -9,16 +9,23 @@ pub use _version::*; use crate::peripherals; -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { Bus, - Arbitration, + Arbitration, // in case of master mode: lost arbitration to another master Nack, Timeout, Crc, Overrun, ZeroLengthTransfer, + Collission, // in case of slave mode, during sending data to master + BufferEmpty, + BufferFull, + BufferNotEmpty, + BufferNotFilled, + BufferSize, + OkBufferTransferred, // not really an error, but signalling that the slave does nack the last byte } pub(crate) mod sealed { diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index fc6dcd6e..b4ff7e89 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -1,3 +1,4 @@ +use core::cell::RefCell; use core::cmp; #[cfg(feature = "time")] use core::future::poll_fn; @@ -9,9 +10,12 @@ use embassy_embedded_hal::SetConfig; #[cfg(feature = "time")] use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::blocking_mutex::Mutex; use embassy_sync::waitqueue::AtomicWaker; #[cfg(feature = "time")] use embassy_time::{Duration, Instant}; +use stm32_metapac::i2c::vals; use crate::dma::NoDma; #[cfg(feature = "time")] @@ -34,11 +38,101 @@ impl interrupt::typelevel::Handler for InterruptHandl let regs = T::regs(); let isr = regs.isr().read(); - if isr.tcr() || isr.tc() { - T::state().waker.wake(); - } - // The flag can only be cleared by writting to nbytes, we won't do that here, so disable - // the interrupt + T::state().mutex.lock(|f| { + 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.errors += 1; + state_m.result = Err(Error::Bus); + } else if isr.arlo() { + regs.icr().write(|w| w.set_arlocf(true)); + state_m.result = Err(Error::Arbitration); + } else if isr.nackf() { + regs.icr().write(|w| w.set_nackcf(true)); + // Make one extra loop to wait on the stop condition + } else if isr.txis() { + // send the next byte to the master, or NACK in case of error, then end transaction + match state_m.read_byte() { + Ok(b) => regs.txdr().write(|w| w.set_txdata(b)), + Err(Error::OkBufferTransferred) => { + state_m.result = Ok(()); + // Send a NACK, set nbytes to clear tcr flag + regs.cr2().modify(|w| { + w.set_nack(true); + }) + } + Err(e) => { + state_m.result = Err(e); + state_m.errors += 1; + // Send a NACK, set nbytes to clear tcr flag + regs.cr2().modify(|w| { + w.set_nack(true); + }) + } + }; + } 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 = Err(e); + state_m.errors += 1; + // Send a NACK, set nbytes to clear tcr flag + regs.cr2().modify(|w| { + w.set_nack(true); + }) + } + } + } else if isr.stopf() { + // Clear the stop condition flag + regs.icr().write(|w| w.set_stopcf(true)); + state_m.ready = true; + T::state().waker.wake(); + } 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 = isr.dir(); + if state_m.dir == vals::Dir::READ { + // Set the nbytes START and prepare to receive bytes into `buffer`. + regs.cr2().modify(|w| { + // Set number of bytes to transfer: maximum as all incoming bytes will be ACK'ed + w.set_nbytes(state_m.get_size()); + // during sending nbytes automatically send a ACK, stretch clock after last byte + w.set_reload(vals::Reload::COMPLETED); + }); + } 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 i2c tx register + regs.isr().write(|w| w.set_txe(true)); + } + // end address phase, release clock stretching + regs.icr().write(|w| w.set_addrcf(true)); + } + // ============================================ end slave interrupt state machine + } else { + if isr.tcr() || isr.tc() { + T::state().waker.wake(); + } + } + }); // end of mutex + // The flag can only be cleared by writting to nbytes, we won't do that here, so disable + // the interrupt critical_section::with(|_| { regs.cr1().modify(|w| w.set_tcie(false)); }); @@ -50,15 +144,43 @@ impl interrupt::typelevel::Handler for InterruptHandl pub struct Config { pub sda_pullup: bool, pub scl_pullup: bool, + pub slave_address_1: u16, + pub slave_address_2: u8, + pub slave_address_mask: vals::Oamsk, + pub address_11bits: bool, #[cfg(feature = "time")] pub transaction_timeout: Duration, } - +impl Config { + /// Slave address 1 as 7 bit address, in range 0 .. 127 + pub fn slave_address_7bits(&mut self, address: u8) { + // assert!(address < (2 ^ 7)); + self.slave_address_1 = address as u16; + self.address_11bits = false; + } + /// Slave address 1 as 11 bit address in range 0 .. 2047 + pub fn slave_address_11bits(&mut self, address: u16) { + // assert!(address < (2 ^ 11)); + self.slave_address_1 = address; + self.address_11bits = true; + } + /// Slave address 2 as 7 bit address in range 0 .. 127. + /// The mask makes all slaves within the mask addressable + pub fn slave_address_2(&mut self, address: u8, mask: vals::Oamsk) { + // assert!(address < (2 ^ 7)); + self.slave_address_2 = address; + self.slave_address_mask = mask; + } +} impl Default for Config { fn default() -> Self { Self { sda_pullup: false, scl_pullup: false, + slave_address_1: 0, + slave_address_2: 0, + slave_address_mask: vals::Oamsk::NOMASK, + address_11bits: false, #[cfg(feature = "time")] transaction_timeout: Duration::from_millis(100), } @@ -67,15 +189,150 @@ impl Default for Config { pub struct State { waker: AtomicWaker, + mutex: Mutex>, } impl State { pub(crate) const fn new() -> Self { Self { waker: AtomicWaker::new(), + mutex: Mutex::new(RefCell::new(I2cStateMachine::new())), } } } +struct I2cStateMachine { + buffers: [[I2cBuffer; 2]; 2], + result: Result<(), Error>, + slave_mode: bool, + dir: vals::Dir, + address1: u16, + current_address: u8, + errors: u32, + ready: bool, +} +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: Ok(()), + slave_mode: false, + dir: vals::Dir::READ, + address1: 0, + current_address: 0, + errors: 0, + ready: false, + } + } + fn read_byte(&mut self) -> Result { + let adress_type = if self.address1 == self.current_address as u16 { + AddressType::MainAddress + } else { + AddressType::GenericAddress + }; + self.buffers[adress_type as usize][vals::Dir::READ as usize 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::MainAddress + } else { + AddressType::GenericAddress + }; + self.buffers[adress_type as usize][vals::Dir::WRITE as usize].master_write(b) + } + fn get_size(&self) -> u8 { + let adress_type = if self.address1 == self.current_address as u16 { + AddressType::MainAddress + } else { + AddressType::GenericAddress + }; + self.buffers[adress_type as usize][self.dir as usize].size + } +} +const BUFFER_SIZE: usize = 64; + +#[repr(usize)] +pub enum AddressType { + MainAddress = 0, + GenericAddress, +} + +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; + } + /// 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::BufferEmpty); + }; + if self.index < self.size as usize { + let b = self.buffer[self.index]; + self.index += 1; + Ok(b) + } else { + self.size = 0; // mark buffer empty + Err(Error::OkBufferTransferred) // not really an error, but to signal slave should send NACK + } + } + /// 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::BufferFull) + } + } + // 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::BufferSize); + }; + 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) + fn to_buffer(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + if self.size == 0 { + return Err(Error::BufferNotFilled); + } + 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>, @@ -136,7 +393,39 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { T::regs().cr1().modify(|reg| { reg.set_pe(true); + reg.set_nostretch(false); + reg.set_sbc(true); }); + if config.slave_address_1 > 0 { + T::regs().oar1().write(|reg| { + reg.set_oa1en(false); + }); + let mode = if config.address_11bits { + vals::Addmode::BIT10 + } else { + vals::Addmode::BIT7 + }; + T::regs().oar1().write(|reg| { + reg.set_oa1(config.slave_address_1); + reg.set_oa1mode(mode); + reg.set_oa1en(true); + }); + T::state().mutex.lock(|f| { + let mut state_m = f.borrow_mut(); + state_m.address1 = config.slave_address_1; + }); + } + + if config.slave_address_2 > 0 { + T::regs().oar2().write(|reg| { + reg.set_oa2en(false); + }); + T::regs().oar2().write(|reg| { + reg.set_oa2msk(config.slave_address_mask); + reg.set_oa2(config.slave_address_2); + reg.set_oa2en(true); + }); + } T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; @@ -746,7 +1035,95 @@ 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(&mut 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); + }); + 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(&mut 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(()) + } + /// Prepare write data to master (master_read_slave_write) before transaction starts + /// Only possible if the buffer is empty, other wise error BufferNotEmpty error + pub fn slave_write_buffer(&mut 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][vals::Dir::READ as usize]; + if buf.size > 0 { + return Err(Error::BufferNotEmpty); + }; + buf.from_buffer(buffer) + }) + } + /// Read data from master (master_write_slave_read) after transaction is finished + /// Only possible if the buffer is not empty, other wise error BufferNotFilled error + pub fn slave_read_buffer(&mut 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][vals::Dir::WRITE as usize]; + if buf.size == 0 { + return Err(Error::BufferEmpty); + }; + buf.to_buffer(buffer) + }) + } + /// wait until a slave transaction is finished, and return tuple address, direction and data size + pub async fn slave_transaction(&mut self) -> Result<(u8, vals::Dir, u8), Error> { + // 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; + // if the dir bit is set it is a master write slave read operation + match state_m.result { + Ok(()) => return Poll::Ready(Ok((state_m.current_address, state_m.dir, state_m.get_size()))), + Err(e) => return Poll::Ready(Err(e)), + } + } else { + return Poll::Pending; + } + }) + }) + .await + } // ========================= // Blocking public API diff --git a/examples/stm32g0/src/bin/i2c_master.rs b/examples/stm32g0/src/bin/i2c_master.rs index 36d08124..b8bed848 100644 --- a/examples/stm32g0/src/bin/i2c_master.rs +++ b/examples/stm32g0/src/bin/i2c_master.rs @@ -75,60 +75,89 @@ async fn main(_spawner: Spawner) { counter += 1; writeln!(&mut writer, "Loop counter: {:?}", counter).unwrap(); - let mut buf_long: [u8; 50] = [0; 50]; - let mut buf_short: [u8; 20] = [0; 20]; - let mut buf_rcv: [u8; 20] = [0; 20]; - let mut buf_10: [u8; 10] = [0; 10]; - let mut buf_io = [0_u8; 1]; + let mut buf_20 = [0_u8; 20]; + let mut buf_64 = [0_u8; 64]; + let mut buf_65 = [0_u8; 65]; writeln!(&mut writer, "Start of test").unwrap(); - for i in 0..buf_short.len() { - buf_short[i] = 0x41 + (i as u8) + for i in 0..buf_20.len() { + buf_20[i] = 0x20 + (i as u8) + } + for i in 0..buf_64.len() { + buf_64[i] = 0x40 + (i as u8) + } + for i in 0..buf_65.len() { + buf_65[i] = 0x60 + (i as u8) } - // test 1: slave address 0x61 should not be addressable - match i2c.blocking_write(0x61, &buf_short) { + match i2c.blocking_write(0x61, &buf_20) { Ok(_) => writeln!(&mut writer, "Test 1 Error: would expect nack").unwrap(), Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out").unwrap(), Err(err) => writeln!(&mut writer, "Test 1 OK: expected NACK error: {:?}", err).unwrap(), }; // 0x41 good case master write slave read: master does send 20 bytes slave receives 20 bytes - match i2c.blocking_write(0x41, &buf_short) { + match i2c.blocking_write(0x41, &buf_20) { Ok(_) => writeln!(&mut writer, "Test 0x41 Ok").unwrap(), Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out").unwrap(), Err(err) => writeln!(&mut writer, "Test 0x41 Error: {:?}", err).unwrap(), }; - // 0x42 bad case master write slave read: master does send less than 20 bytes - for i in 0..buf_10.len() { - buf_10[i] = 0x20 + (i as u8) - } - match i2c.blocking_write(0x42, &buf_10) { - Ok(_) => writeln!( - &mut writer, - "Test 0x42 Ok. (Master cannot detect that frame is too short) " - ) - .unwrap(), + // 0x42 edge case master write exact 64 bytes: must succeed on master and slave + match i2c.blocking_write(0x42, &buf_64) { + Ok(_) => writeln!(&mut writer, "Test 0x42 Ok. Master write exact 64 bytes").unwrap(), Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out").unwrap(), Err(err) => writeln!(&mut writer, "Test 0x42 error IncorrectFramesize: {:?}", err).unwrap(), }; - // 0x43 bad case master write slave read: master does send more than 20 bytes, slave does NACK - for i in 0..buf_long.len() { - buf_long[i] = 0x61 + (i as u8) - } - match i2c.blocking_write(0x43, &buf_long) { - Ok(_) => writeln!(&mut writer, "Test 0x43 not ok expected error IncorrectFramesize: ").unwrap(), + // 0x43 edge case master write exact 65 bytes: 1 too manyu must fail on master and slave + match i2c.blocking_write(0x43, &buf_64) { + Ok(_) => writeln!(&mut writer, "Test 0x42 Failed. Expected a Nack").unwrap(), Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out").unwrap(), - Err(err) => writeln!(&mut writer, "Test 0x43 Ok Expected IncorrectFrameSize: {:?}", err).unwrap(), + Err(err) => writeln!( + &mut writer, + "Test 0x43 Ok: Got error NACK du to buffer of 1 too big {:?}", + err + ) + .unwrap(), }; - // 0x44 master write_read good case: master sends and expects 20 bytes - for i in 0..buf_short.len() { - buf_short[i] = 0x41 + (i as u8) - } - for i in 0..buf_rcv.len() { - buf_rcv[i] = 0x30 + (i as u8) - } - match i2c.blocking_write_read(0x44, &buf_short, &mut buf_rcv) { + + match i2c.blocking_read(0x48, &mut buf_20) { + Ok(_) => { + writeln!(&mut writer, "Test 0x48 Read expected to fail!").unwrap(); + } + Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out").unwrap(), + Err(err) => writeln!( + &mut writer, + "Test 0x48 Ok. First time, slave did not yet prepare a buffer Error: {:?}", + err + ) + .unwrap(), + }; + match i2c.blocking_read(0x49, &mut buf_20) { + Ok(_) => { + writeln!(&mut writer, "Test 0x49 Read Ok").unwrap(); + print_buffer(&mut writer, &buf_20); + } + Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out").unwrap(), + Err(err) => writeln!(&mut writer, "Test 0x49 Error: {:?}", err).unwrap(), + }; + match i2c.blocking_read(0x4A, &mut buf_64) { + Ok(_) => { + writeln!(&mut writer, "Test 0x4A failed. Expected was a NACK error").unwrap(); + print_buffer(&mut writer, &buf_64); + } + Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out").unwrap(), + Err(err) => writeln!(&mut writer, "Test 0x4A Ok. Expected to fail. Error: {:?}", err).unwrap(), + }; + match i2c.blocking_read(0x4B, &mut buf_64) { + Ok(_) => { + writeln!(&mut writer, "Test 0x4B succeeded: edge case read exact the buffer size").unwrap(); + print_buffer(&mut writer, &buf_64); + } + Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out").unwrap(), + Err(err) => writeln!(&mut writer, "Test 0x4B failed. Error: {:?}", err).unwrap(), + }; + /* + match i2c.blocking_write_read(0x44, &buf_20, &mut buf_64) { Ok(_) => { writeln!(&mut writer, "Test 0x44 Ok ").unwrap(); writeln!( @@ -145,52 +174,7 @@ async fn main(_spawner: Spawner) { Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out").unwrap(), Err(err) => writeln!(&mut writer, "Test 0x44 error: {:?}", err).unwrap(), }; - // 0x48 master read slave write good case: exact 20 characters - for i in 0..buf_short.len() { - buf_short[i] = 0x61 + (i as u8) - } - match i2c.blocking_read(0x48, &mut buf_short) { - Ok(_) => { - writeln!(&mut writer, "Test 0x48 Ok ").unwrap(); - for i in 0..buf_short.len() { - writeln!(&mut writer, "{}", buf_short[i]).unwrap(); - } - writeln!(&mut writer, "").unwrap() - } - Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out").unwrap(), - Err(err) => writeln!(&mut writer, "Test 0x48 unexpected error: {:?}", err).unwrap(), - }; - // 0x49 master read slave write bad case: master expects 50 slave does send 20 characters - for i in 0..buf_long.len() { - buf_long[i] = 0x61 + (i as u8) - } - match i2c.blocking_read(0x49, &mut buf_long) { - Ok(_) => { - writeln!(&mut writer, "Test 0x49 Ok ").unwrap(); - for i in 0..buf_long.len() { - writeln!(&mut writer, "{}", buf_long[i]).unwrap(); - } - writeln!(&mut writer, "").unwrap() - } - Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out").unwrap(), - Err(err) => writeln!(&mut writer, "Test 0x49 error: {:?}", err).unwrap(), - }; - // 0x4A master read slave write bad case: master expects 20 does slave does send 50 characters - for i in 0..buf_short.len() { - buf_short[i] = 0x41 + (i as u8) - } - match i2c.blocking_read(0x4A, &mut buf_short) { - Ok(_) => { - writeln!(&mut writer, "Test 0x4A Ok ").unwrap(); - - for i in 0..buf_short.len() { - writeln!(&mut writer, "{}", buf_short[i]).unwrap(); - } - writeln!(&mut writer, "").unwrap() - } - Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out").unwrap(), - Err(err) => writeln!(&mut writer, "Test 0x4A error: {:?}", err).unwrap(), - }; + */ // 0x4F test end and slave will present results let mut result: [u8; 2] = [0, 0]; match i2c.blocking_read(0x4F, &mut result) { @@ -204,24 +188,12 @@ async fn main(_spawner: Spawner) { Err(err) => writeln!(&mut writer, "Test 0x4F unexpected error: {:?}", err).unwrap(), }; writeln!(&mut writer, "").unwrap(); - let mut joyb = [0_u8; 3]; - match i2c.blocking_read(0x52, &mut joyb) { - Ok(_) => { - writeln!(&mut writer, "Test 0x52 Ok ").unwrap(); - for i in 0..joyb.len() { - writeln!(&mut writer, " {} ", joyb[i]).unwrap(); - } - writeln!(&mut writer, "").unwrap() - } - Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out").unwrap(), - Err(err) => writeln!(&mut writer, "Test 0x52 unexpected error: {:?}", err).unwrap(), - }; - match i2c.blocking_write(0x21, &mut buf_io) { - Ok(_) => (), - Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out").unwrap(), - Err(err) => writeln!(&mut writer, "Test 0x21 unexpected error: {:?}", err).unwrap(), - }; - buf_io[0] += 1; Timer::after(Duration::from_millis(10_000)).await; } + fn print_buffer(writer: &mut SerialWriter, buf: &[u8]) { + for i in 0..buf.len() { + write!(writer, " {:2x} ", buf[i]).unwrap(); + } + writeln!(writer, "\n\r").unwrap() + } } diff --git a/examples/stm32g0/src/bin/i2c_slave.rs b/examples/stm32g0/src/bin/i2c_slave.rs new file mode 100644 index 00000000..48e91175 --- /dev/null +++ b/examples/stm32g0/src/bin/i2c_slave.rs @@ -0,0 +1,279 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use core::fmt::{self, Write}; + +use embassy_executor::Spawner; +use embassy_stm32::dma::NoDma; +use embassy_stm32::i2c::I2c; +use embassy_stm32::pac::i2c::vals; +use embassy_stm32::time::Hertz; +use embassy_stm32::usart::UartTx; +use embassy_stm32::{bind_interrupts, i2c, peripherals, usart}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + I2C1 => i2c::InterruptHandler; + USART1 => usart::InterruptHandler; +}); + +macro_rules! checkIsWrite { + ($writer:ident, $direction:ident) => { + match $direction { + vals::Dir::WRITE => (), + _ => { + write!($writer, "Error incorrect direction {:?}\r", $direction as usize).unwrap(); + continue; + } + } + }; +} +macro_rules! checkIsRead { + ($writer:ident, $direction:ident) => { + match $direction { + vals::Dir::READ => (), + _ => { + write!($writer, "Error incorrect direction {:?}\r", $direction as usize).unwrap(); + continue; + } + } + }; +} + +pub struct SerialWriter { + tx: UartTx<'static, peripherals::USART1, peripherals::DMA1_CH1>, +} +impl SerialWriter { + pub fn new(tx: UartTx<'static, peripherals::USART1, peripherals::DMA1_CH1>) -> Self { + SerialWriter { tx } + } +} +impl fmt::Write for SerialWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { + _ = self.tx.blocking_write(s.as_bytes()); + Ok(()) + } +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + + let uart = usart::Uart::new( + p.USART1, + p.PB7, + p.PB6, + Irqs, + p.DMA1_CH1, + p.DMA1_CH2, + usart::Config::default(), + ) + .unwrap(); + let (tx, _rx) = uart.split(); + + let mut writer = SerialWriter::new(tx); + + writeln!( + &mut writer, + "async i2c slave test. Should be used together with i2c_master test\r" + ) + .unwrap(); + + let mut config = i2c::Config::default(); + config.slave_address_7bits(0x4); + config.slave_address_2(0x41, vals::Oamsk::MASK4); + writeln!(&mut writer, "After config:\r",).unwrap(); + + let mut i2c = I2c::new(p.I2C1, p.PB8, p.PB9, Irqs, NoDma, NoDma, Hertz(100_000), config); + writeln!(&mut writer, "After i2c init\r").unwrap(); + + let mut buf_64 = [0; 64]; // buffer is longer than master will send: wait for STOP condition + let mut buf_20 = [0; 20]; // buffer is shorter than master will send: wait for STOP condition + let mut errors = 0; + let mut address = 0; + let mut dir = vals::Dir::READ; + let mut tcount = 0; + let mut counter = 0; + let mut error = Ok((0, vals::Dir::READ, 0)); + + // start of the actual test + i2c.slave_start_listen().unwrap(); + loop { + counter += 1; + writeln!(&mut writer, "Loop: {}\r", counter).unwrap(); + + for i in 0..buf_20.len() { + buf_20[i] = 0x61 + (i as u8) + } + for i in 0..buf_64.len() { + buf_64[i] = 0x41 + (i as u8) + } + + writeln!(&mut writer, "Waiting for master activity\r").unwrap(); + + error = Ok((0, vals::Dir::WRITE, 0)); + match i2c.slave_transaction().await { + Ok((taddr, tdir, tsize)) => { + address = taddr; + dir = tdir; + writeln!( + &mut writer, + "Test ok. Address: x{:2x} dir: {:?} size: x{:2x}\r", + taddr, tdir as u8, tsize + ) + .unwrap(); + } + Err(e) => { + error = Err(e); + writeln!(&mut writer, "Test failed: Error: {:?}", e).unwrap() + } + } + tcount += 1; + + match address { + 0x41 => { + // 0x41 good case master write slave read: master does send 20 bytes slave receives 20 bytes + checkIsWrite!(writer, dir); + _ = i2c.slave_read_buffer(&mut buf_20, i2c::AddressType::GenericAddress); + match error { + Ok(_) => { + writeln!(&mut writer, "Test 0x41 Ok. send 20 bytes").unwrap(); + print_buffer(&mut writer, &buf_20); + } + Err(err) => { + errors += 1; + writeln!(&mut writer, "Test 0x41 failed. Error: {:?}\r", err).unwrap() + } + }; + } + 0x42 => { + // 0x42 good case edge case: exact 64 bytes master write slave read: + checkIsWrite!(writer, dir); + _ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::GenericAddress); + match error { + Ok(_) => { + writeln!(&mut writer, "Test 0x42 Ok. send 64 bytes").unwrap(); + print_buffer(&mut writer, &buf_64); + } + Err(err) => { + errors += 1; + writeln!(&mut writer, "Test 0x42 failed. Error: {:?}\r", err).unwrap() + } + }; + } + 0x43 => { + // 0x43 bad case master write slave read: master does send more than 64 bytes, slave does NACK + checkIsWrite!(writer, dir); + _ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::GenericAddress); + match i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::GenericAddress) { + Ok(_) => { + { + writeln!(&mut writer, "Test 0x43 failed. Expected to fail. with FrameError\r").unwrap() + }; + } + Err(err) => { + errors += 1; + writeln!(&mut writer, "Test 0x43 Ok Expected error. Error: {:?}\r", err).unwrap() + } + }; + } + 0x48 => { + // 0x48 master read slave write slave did not yet prepare a buffer, master will fail + checkIsRead!(writer, dir); + match error { + Ok(_) => { + writeln!(&mut writer, "Test 0x48 fail expected to fail: \r").unwrap(); + errors += 1; + } + Err(err) => writeln!(&mut writer, "Test 0x48 Ok. Expected error: {:?}\r", err).unwrap(), + }; + // prepare buffer for next round + for i in 0..buf_20.len() { + buf_20[i] = 0x61 + (i as u8) + } + _ = i2c.slave_write_buffer(&buf_20, i2c::AddressType::GenericAddress); + } + 0x49 => { + // 0x49 master read slave write bad case: master expects 50 does slave does send 20 characters + checkIsRead!(writer, dir); + match error { + Ok(_) => { + writeln!(&mut writer, "Test 0x49 Ok. master did read 20 bytes").unwrap(); + } + Err(err) => { + errors += 1; + writeln!(&mut writer, "Test 0x49 failed. Error: {:?}\r", err).unwrap() + } + }; + // prepare buffer for next round + for i in 0..buf_20.len() { + buf_20[i] = 0x41 + (i as u8) + } + _ = i2c.slave_write_buffer(&buf_20, i2c::AddressType::GenericAddress); + } + 0x4A => { + // 0x4A master read slave write bad case: master expects 64 does slave does prepare 20 characters + checkIsRead!(writer, dir); + match error { + Ok(_) => { + writeln!(&mut writer, "Test 0x4A failed . Expected an errpr").unwrap(); + } + Err(err) => { + errors += 1; + writeln!(&mut writer, "Test 0x4A ok. Expected errore rror: {:?}\r", err).unwrap() + } + } + _ = i2c.slave_write_buffer(&buf_20, i2c::AddressType::GenericAddress); + // prepare buffer for next round + for i in 0..buf_64.len() { + buf_64[i] = 0x41 + (i as u8) + } + _ = i2c.slave_write_buffer(&buf_64, i2c::AddressType::GenericAddress); + } + 0x4B => { + // 0x4B master write_read good case each 20 chars + checkIsRead!(writer, dir); + match error { + Ok(_) => { + writeln!(&mut writer, "Test 0x4B Ok\r").unwrap(); + } + Err(err) => { + errors += 1; + writeln!(&mut writer, "Test 0x4B failed. Error: {:?}\r", err).unwrap() + } + }; + let result: [u8; 2] = [tcount, errors]; + _ = i2c.slave_write_buffer(&result, i2c::AddressType::GenericAddress); + } + 0x4F => { + checkIsRead!(writer, dir); + match error { + Ok(_) => { + writeln!(&mut writer, "Test 0x4F Result send to master\r").unwrap(); + } + Err(err) => { + errors += 1; + writeln!(&mut writer, "Test 0x4F failed. 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; + } + _ => (), + } + } + fn print_buffer(writer: &mut SerialWriter, buf: &[u8]) { + for i in 0..buf.len() { + write!(writer, " {:2x} ", buf[i]).unwrap(); + } + writeln!(writer, "\n\r").unwrap() + } +}