diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index ae880a5c..5358106f 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -19,12 +19,16 @@ pub enum Error { Crc, Overrun, ZeroLengthTransfer, - Collission, // in case of slave mode, during sending data to master - BufferEmpty, - BufferFull, BufferSize, } +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[repr(usize)] +pub enum AddressType { + Address1 = 0, + Address2, +} + pub(crate) mod sealed { use super::*; pub trait Instance: crate::rcc::RccPeripheral { diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 63361939..7933f692 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -22,7 +22,7 @@ use crate::dma::NoDma; use crate::dma::Transfer; use crate::gpio::sealed::AFType; use crate::gpio::Pull; -use crate::i2c::{Error, Instance, SclPin, SdaPin}; +use crate::i2c::{AddressType, Error, Instance, SclPin, SdaPin}; use crate::interrupt::typelevel::Interrupt; use crate::pac::i2c; use crate::time::Hertz; @@ -57,10 +57,12 @@ impl interrupt::typelevel::Handler for InterruptHandl let b = match state_m.read_byte() { Ok(b) => b, Err(e) => { - state_m.result = Some(e); - regs.cr2().modify(|w| { - w.set_nack(true); - }); + // 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 } }; @@ -72,10 +74,6 @@ impl interrupt::typelevel::Handler for InterruptHandl Ok(()) => (), Err(e) => { state_m.result = Some(e); - // Send a NACK - regs.cr2().modify(|w| { - w.set_nack(true); - }) } } } else if isr.stopf() { @@ -104,6 +102,10 @@ impl interrupt::typelevel::Handler for InterruptHandl // during sending nbytes automatically send a ACK, stretch clock after last byte w.set_reload(vals::Reload::COMPLETED); }); + // restore sbc after a master_write_read transaction + T::regs().cr1().modify(|reg| { + reg.set_sbc(true); + }); // flush i2c tx register regs.isr().write(|w| w.set_txe(true)); // fill rx data with the first byte @@ -232,37 +234,31 @@ impl I2cStateMachine { } fn read_byte(&mut self) -> Result { let adress_type = if self.address1 == self.current_address as u16 { - AddressType::MainAddress + AddressType::Address1 } else { - AddressType::GenericAddress + AddressType::Address2 }; self.buffers[adress_type as usize][vals::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::MainAddress + AddressType::Address1 } else { - AddressType::GenericAddress + AddressType::Address2 }; 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 + AddressType::Address1 } else { - AddressType::GenericAddress + AddressType::Address2 }; 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, @@ -280,12 +276,15 @@ impl I2cBuffer { 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::BufferEmpty); + return Err(Error::ZeroLengthTransfer); }; if self.index < self.size as usize { let b = self.buffer[self.index]; @@ -303,14 +302,14 @@ impl I2cBuffer { self.size = self.index as u8; Ok(()) } else { - Err(Error::BufferFull) + 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::BufferSize); + return Err(Error::Overrun); }; for i in 0..len { self.buffer[i] = buffer[i]; @@ -400,13 +399,13 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { T::regs().oar1().write(|reg| { reg.set_oa1en(false); }); - let mode = if config.address_11bits { - vals::Addmode::BIT10 + let (mode, address) = if config.address_11bits { + (vals::Addmode::BIT10, config.slave_address_1) } else { - vals::Addmode::BIT7 + (vals::Addmode::BIT7, config.slave_address_1 << 1) }; T::regs().oar1().write(|reg| { - reg.set_oa1(config.slave_address_1); + reg.set_oa1(address); reg.set_oa1mode(mode); reg.set_oa1en(true); }); @@ -1038,7 +1037,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // ========================= // async Slave implementation /// Starts listening for slave transactions - pub fn slave_start_listen(&mut self) -> Result<(), super::Error> { + pub fn slave_start_listen(&self) -> Result<(), super::Error> { T::regs().cr1().modify(|reg| { reg.set_addrie(true); reg.set_txie(true); @@ -1063,7 +1062,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(()) } // slave stop listening for slave transactions and switch back to master role - pub fn slave_stop_listen(&mut self) -> Result<(), super::Error> { + pub fn slave_stop_listen(&self) -> Result<(), super::Error> { T::regs().cr1().modify(|reg| { reg.set_addrie(false); reg.set_txie(false); @@ -1080,22 +1079,32 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { }); Ok(()) } - pub fn slave_sbc(&mut self, sbc_enabled: bool) { + 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(&mut self, buffer: &[u8], address_type: AddressType) -> Result<(), super::Error> { + 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][vals::Dir::READ as usize]; buf.from_buffer(buffer) }) } + pub fn slave_reset_buffer(&self, address_type: AddressType) { + T::state().mutex.lock(|f| { + let mut state_m = f.borrow_mut(); + let buf_r = &mut state_m.buffers[address_type as usize][vals::Dir::READ as usize]; + buf_r.reset(); + let buf_w = &mut state_m.buffers[address_type as usize][vals::Dir::WRITE as usize]; + buf_w.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(&mut self, buffer: &mut [u8], address_type: AddressType) -> Result<(), super::Error> { + 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][vals::Dir::WRITE as usize]; @@ -1103,7 +1112,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { }) } /// wait until a slave transaction is finished, and return tuple address, direction, data size and error - pub async fn slave_transaction(&mut self) -> (u8, vals::Dir, u8, Option) { + pub async fn slave_transaction(&self) -> (u8, vals::Dir, u8, Option) { // async wait until addressed poll_fn(|cx| { T::state().waker.register(cx.waker()); diff --git a/examples/stm32g0/src/bin/i2c_master.rs b/examples/stm32g0/src/bin/i2c_master.rs index 3905e65f..9d827df0 100644 --- a/examples/stm32g0/src/bin/i2c_master.rs +++ b/examples/stm32g0/src/bin/i2c_master.rs @@ -9,6 +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::{Error, I2c}; use embassy_stm32::time::Hertz; use embassy_stm32::usart::UartTx; @@ -35,10 +36,21 @@ impl fmt::Write for SerialWriter { Ok(()) } } +#[embassy_executor::task] +pub async fn system_ticker(mut led: Output<'static, peripherals::PA6>) { + loop { + Timer::after(Duration::from_millis(200)).await; + led.set_high(); + Timer::after(Duration::from_millis(100)).await; + led.set_low(); + } +} #[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); // nucleog070rb board + let led = Output::new(p.PA6, Level::High, Speed::Low); let uart = usart::Uart::new( p.USART1, @@ -71,19 +83,21 @@ async fn main(_spawner: Spawner) { Default::default(), ); Timer::after(Duration::from_millis(1000)).await; + spawner.spawn(system_ticker(led)).unwrap(); // start of the acutal test let mut counter = 0; loop { counter += 1; - writeln!(&mut writer, "Loop counter: {:?}", counter).unwrap(); + writeln!(&mut writer, "Loop counter: {:?}\r", counter).unwrap(); let mut buf_20 = [0_u8; 20]; let mut buf_20a = [0_u8; 20]; let mut buf_64 = [0_u8; 64]; let mut buf_65 = [0_u8; 65]; + let mut buf_2 = [0_u8; 2]; - writeln!(&mut writer, "Start of test\n\r").unwrap(); + writeln!(&mut writer, "Start of test\r").unwrap(); for i in 0..buf_20.len() { buf_20[i] = 0x20 + (i as u8) @@ -94,117 +108,126 @@ async fn main(_spawner: Spawner) { 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_20) { - Ok(_) => writeln!(&mut writer, "Test 1 failed: would expect nack\n\r").unwrap(), - Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\n\r").unwrap(), - Err(err) => writeln!(&mut writer, "Test 1 passed: expected NACK error: {:?}", err).unwrap(), - }; - // 0x41 good case master write slave read: master does send 20 bytes slave receives 20 bytes + // 0x41 good case master write 20 bytes match i2c.blocking_write(0x41, &buf_20) { - Ok(_) => writeln!(&mut writer, "Test 0x41 passed\n\r").unwrap(), - Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\n\r").unwrap(), - Err(err) => writeln!(&mut writer, "Test 0x41 failed. Error: {:?}", err).unwrap(), + Ok(_) => writeln!(&mut writer, "Test 0x41 passed\r").unwrap(), + Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(), + Err(err) => writeln!(&mut writer, "Test 0x41 failed. Error: {:?}\r", err).unwrap(), }; Timer::after(Duration::from_millis(10)).await; + // 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 passed. Master write exact 64 bytes\n\r").unwrap(), - Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\n\r").unwrap(), - Err(err) => writeln!(&mut writer, "Test 0x42 failed. Got error: {:?}\r\n", err).unwrap(), + Ok(_) => writeln!(&mut writer, "Test 0x42 passed. Master write exact 64 bytes\r").unwrap(), + Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(), + Err(err) => writeln!(&mut writer, "Test 0x42 failed. Got error: {:?}\r", err).unwrap(), }; Timer::after(Duration::from_millis(10)).await; + // 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\n\r").unwrap(), - Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\n\r").unwrap(), + Ok(_) => writeln!(&mut writer, "Test 0x43 Failed. Expected a Nack\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\n", + "Test 0x43 passed: Got error NACK du to buffer of 1 too big {:?}\r", err ) .unwrap(), }; + // 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(_) => { + writeln!(&mut writer, "Test 0x44 Ok \r").unwrap(); + writeln!( + &mut writer, + "Uppercase input should be transformed to lowercase, A -> b \r" + ) + .unwrap(); + print_buffer(&mut writer, &buf_20a); + } + 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!\n\r").unwrap(); + writeln!(&mut writer, "Test 0x48 failed. Read expected to fail!\r").unwrap(); } - Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\n\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\n", + "Test 0x48 Ok. First time, slave did not yet prepare a buffer Error: {:?}\r", err ) .unwrap(), }; Timer::after(Duration::from_millis(10)).await; + + // master read 20 bytes good case. match i2c.blocking_read(0x49, &mut buf_20) { Ok(_) => { - writeln!(&mut writer, "Test 0x49 Read Ok\n\r").unwrap(); + writeln!(&mut writer, "Test 0x49 Read Ok\r").unwrap(); print_buffer(&mut writer, &buf_20); } - Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\n\r").unwrap(), - Err(err) => writeln!(&mut writer, "Test 0x49 Error: {:?}\r\n", err).unwrap(), + Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(), + Err(err) => writeln!(&mut writer, "Test 0x49 Error: {:?}\r", err).unwrap(), }; Timer::after(Duration::from_millis(10)).await; + + // 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\n\r").unwrap(); + writeln!(&mut writer, "Test 0x4A failed. Expected was a NACK error\r").unwrap(); print_buffer(&mut writer, &buf_64); } - Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\n\r").unwrap(), - Err(err) => writeln!(&mut writer, "Test 0x4A passed. Expected to fail. Error: {:?}\r\n", err).unwrap(), + 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(), }; Timer::after(Duration::from_millis(10)).await; match i2c.blocking_read(0x4B, &mut buf_64) { Ok(_) => { - writeln!(&mut writer, "Test 0x4B passed\n\r").unwrap(); + writeln!(&mut writer, "Test 0x4B passed\r").unwrap(); print_buffer(&mut writer, &buf_64); } - Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\n\r").unwrap(), - Err(err) => writeln!(&mut writer, "Test 0x4B failed. Error: {:?}\r\n", err).unwrap(), + Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(), + Err(err) => writeln!(&mut writer, "Test 0x4B failed. Error: {:?}\r", err).unwrap(), }; - /* - match i2c.blocking_write_read(0x44, &buf_20, &mut buf_20a) { - Ok(_) => { - writeln!(&mut writer, "Test 0x44 Ok \n\r").unwrap(); - writeln!( - &mut writer, - "Uppercase input should be transformed to lowercase, A -> b " - ) - .unwrap(); - - for i in 0..buf_20a.len() { - writeln!(&mut writer, "{}", buf_20[i]).unwrap(); - } - writeln!(&mut writer, "\n\r").unwrap() - } - Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\n\r").unwrap(), - Err(err) => writeln!(&mut writer, "Test 0x44 error: {:?}", err).unwrap(), - }; - */ Timer::after(Duration::from_millis(10)).await; - // 0x4F test end and slave will present results + + // test for arbitration lost. 2 slaves respond on address 10 one with 0xFF03, on with 0xFF04 + // if both are online the one with 0xFF04 should report arbitration loss, here we read 0xFF03 + match i2c.blocking_read(0x10, &mut buf_2) { + Ok(_) => { + writeln!(&mut writer, "Test 0x10 Received {:2x}:{:2x}\r", buf_2[0], buf_2[1]).unwrap(); + writeln!(&mut writer, "Look in the log of the slaves to evaluate the result\r").unwrap(); + } + Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(), + Err(err) => writeln!(&mut writer, "Test 0x10 Failed: Error: {:?}", err).unwrap(), + }; + + // 0x4F Master does read 2 bytes with the result of the slave let mut result: [u8; 2] = [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\n", + "Result of the whole test as reported by the slave count/errors: {}/{}\r", result[0], result[1] ) .unwrap(), - Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\n\r").unwrap(), - Err(err) => writeln!(&mut writer, "Test 0x4F unexpected error: {:?}\r\n", err).unwrap(), + Err(Error::Timeout) => writeln!(&mut writer, "Operation timed out\r").unwrap(), + Err(err) => writeln!(&mut writer, "Test 0x4F unexpected error: {:?}\r", err).unwrap(), }; - writeln!(&mut writer, "\n\r").unwrap(); + writeln!(&mut writer, "\r").unwrap(); + 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\n\r").unwrap() + writeln!(writer, "\r\r").unwrap() } } diff --git a/examples/stm32g0/src/bin/i2c_slave.rs b/examples/stm32g0/src/bin/i2c_slave.rs index 8424d7fa..b49b4f28 100644 --- a/examples/stm32g0/src/bin/i2c_slave.rs +++ b/examples/stm32g0/src/bin/i2c_slave.rs @@ -72,7 +72,7 @@ impl fmt::Write for SerialWriter { #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let mut led = Output::new(p.PA5, Level::High, Speed::Low); + let led = Output::new(p.PA5, Level::High, Speed::Low); /* let uart = usart::Uart::new( @@ -107,15 +107,15 @@ async fn main(spawner: Spawner) { .unwrap(); let mut config = i2c::Config::default(); - config.slave_address_7bits(0x4); + config.slave_address_7bits(0x10); // for arbitration lost test 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 i2c = I2c::new(p.I2C1, p.PB8, p.PB9, Irqs, NoDma, NoDma, Hertz(100_000), config); 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 buf_20a = [0; 20]; + let mut buf_2 = [0; 2]; let mut errors = 0; let mut address = 0; let mut dir = vals::Dir::READ; @@ -131,19 +131,26 @@ 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) } + for i in 0..buf_20a.len() { + buf_20a[i] = 0x40 - (i as u8) + } for i in 0..buf_64.len() { buf_64[i] = 0x60 + (i as u8) } + // content for test 0x10 + buf_2[0] = 0xFF; + buf_2[1] = 0x04; + _ = i2c.slave_write_buffer(&mut buf_2, i2c::AddressType::Address1); writeln!(&mut writer, "Waiting for master activity\r").unwrap(); - // clear write buffers for sure - _ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::GenericAddress); - _ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::MainAddress); - let (address, dir, size, result) = i2c.slave_transaction().await; writeln!( &mut writer, @@ -152,30 +159,85 @@ async fn main(spawner: Spawner) { ) .unwrap(); 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); + } + 0x43 => { + // 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); + } + 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) + } + _ = i2c.slave_write_buffer(&buf_20, i2c::AddressType::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(), + _ => (), + } + } + 0x4A => { + // prepare buffer for test 0x4B + for i in 0..buf_64.len() { + buf_64[i] = 0x4A + (i as u8) + } + match i2c.slave_write_buffer(&buf_64, i2c::AddressType::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); + } + _ => (), + } match address { 0x41 => { - writeln!(&mut writer, "Evaluate test 0x41.\r\n").unwrap(); + writeln!(&mut writer, "Evaluate test 0x41: Good case master write 20 bytes\r").unwrap(); checkIsWrite!(writer, dir); - _ = i2c.slave_read_buffer(&mut buf_20, i2c::AddressType::GenericAddress); + _ = i2c.slave_read_buffer(&mut buf_20, i2c::AddressType::Address2); match result { None => { - writeln!(&mut writer, "Test 0x41 passed\r\n").unwrap(); + writeln!(&mut writer, "Test 0x41 passed\r").unwrap(); print_buffer(&mut writer, &buf_20); } Some(err) => { errors += 1; - writeln!(&mut writer, "Test 0x41 failed. Error: {:?}\r\n", err).unwrap() + writeln!(&mut writer, "Test 0x41 failed. Error: {:?}\r", err).unwrap() } }; } 0x42 => { - writeln!(&mut writer, "Evaluate test 0x42.\r\n").unwrap(); + writeln!( + &mut writer, + "Evaluate test 0x42: edge case master write exact 64 bytes: must succeed on master and slave\r" + ) + .unwrap(); checkIsWrite!(writer, dir); - _ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::GenericAddress); + _ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::Address2); match result { None => { - writeln!(&mut writer, "Test 0x42 passed. send 64 bytes\r\n").unwrap(); + writeln!(&mut writer, "Test 0x42 passed. send 64 bytes\r").unwrap(); print_buffer(&mut writer, &buf_64); } Some(err) => { @@ -185,9 +247,9 @@ async fn main(spawner: Spawner) { }; } 0x43 => { - writeln!(&mut writer, "Evaluate test 0x43.\r\n").unwrap(); + writeln!(&mut writer, "Evaluate test 0x43.edge case master write exact 65 bytes: 1 too many must fail on master and slave\r").unwrap(); checkIsWrite!(writer, dir); - _ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::GenericAddress); + _ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::Address2); match result { None => { errors += 1; @@ -201,9 +263,32 @@ async fn main(spawner: Spawner) { .unwrap(), }; } + 0x44 => { + writeln!( + &mut writer, + "Evaluate test 0x44: master write read combined transaction write 20 bytes, then read 20 bytes \r" + ) + .unwrap(); + checkIsRead!(writer, dir); + _ = i2c.slave_read_buffer(&mut buf_20, i2c::AddressType::Address2); + match result { + None => { + writeln!(&mut writer, "Test 0x44 passed\r").unwrap(); + print_buffer(&mut writer, &buf_20) + } + Some(err) => { + errors += 1; + writeln!(&mut writer, "Test 0x44 failed. Error:{:?}\r", err).unwrap() + } + }; + } 0x48 => { // 0x48 master read slave write slave did not yet prepare a buffer, master will fail - writeln!(&mut writer, "Evaluate test 0x48.\r\n").unwrap(); + 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 { None => { @@ -212,16 +297,9 @@ async fn main(spawner: Spawner) { } Some(err) => writeln!(&mut writer, "Test 0x48 passed. Got expected error: {:?}\r", err).unwrap(), }; - // prepare buffer for test 0x49 - _ = i2c.slave_write_buffer(&buf_20, i2c::AddressType::GenericAddress); } 0x49 => { - // prepare buffer for test 0x4A - for i in 0..buf_20.len() { - buf_20[i] = 0x50 + (i as u8) - } - _ = i2c.slave_write_buffer(&buf_20, i2c::AddressType::GenericAddress); - writeln!(&mut writer, "Evaluate test 0x49\r\n").unwrap(); + writeln!(&mut writer, "Evaluate test 0x49. master read 20 bytes good case.\r").unwrap(); checkIsRead!(writer, dir); match result { None => { @@ -232,33 +310,22 @@ async fn main(spawner: Spawner) { writeln!(&mut writer, "Test 0x49 failed. Error: {:?}\r", err).unwrap() } }; - // prepare buffer for test 0x4A - _ = 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 - // prepare buffer for test 0x4B - for i in 0..buf_64.len() { - buf_64[i] = 0x40 + (i as u8) - } - _ = i2c.slave_write_buffer(&buf_64, i2c::AddressType::GenericAddress); - - writeln!(&mut writer, "Evaluate test 0x4A.\r\n").unwrap(); + 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 { None => { + errors += 1; writeln!(&mut writer, "Test 0x4A failed . Expected an error").unwrap(); } - Some(err) => { - errors += 1; - writeln!(&mut writer, "Test 0x4A passed. Expected error: {:?}\r", err).unwrap() - } + Some(err) => writeln!(&mut writer, "Test 0x4A passed. Expected error: {:?}\r", err).unwrap(), } - _ = i2c.slave_write_buffer(&buf_20, i2c::AddressType::GenericAddress); } 0x4B => { // Master-read-slave-write Master expects 64 bytes, Should be ok - writeln!(&mut writer, "Evaluate test 0x4B. .\r\n").unwrap(); + writeln!(&mut writer, "Evaluate test 0x4B. Master read 64 bytes good case.\r").unwrap(); checkIsRead!(writer, dir); match result { None => { @@ -269,14 +336,11 @@ async fn main(spawner: Spawner) { writeln!(&mut writer, "Test 0x4B failed. Error: {:?}\r", err).unwrap() } }; - // prepare for test 0x4F - let result: [u8; 2] = [tcount, errors]; - _ = i2c.slave_write_buffer(&result, i2c::AddressType::GenericAddress); } 0x4F => { // Master-read-slave-write 2 bytes with test summary Should be ok. checkIsRead!(writer, dir); - writeln!(&mut writer, "Evaluate test 0x4F.\r\n").unwrap(); + writeln!(&mut writer, "Evaluate test 0x4F. Send test summary\r").unwrap(); match result { None => { writeln!(&mut writer, "Test 0x4F Result send to master\r").unwrap(); @@ -296,6 +360,30 @@ async fn main(spawner: Spawner) { tcount = 0; errors = 0; } + 0x10 => { + // Arbitration lost test Master does read 2 bytes on 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 { + 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; + } + _ => (), } } @@ -303,6 +391,6 @@ async fn main(spawner: Spawner) { for i in 0..buf.len() { write!(writer, " {:2x} ", buf[i]).unwrap(); } - writeln!(writer, "\n\r").unwrap() + writeln!(writer, "\r").unwrap() } } diff --git a/examples/stm32g0/src/bin/i2c_slave_arbitration.rs b/examples/stm32g0/src/bin/i2c_slave_arbitration.rs new file mode 100644 index 00000000..70d7dd43 --- /dev/null +++ b/examples/stm32g0/src/bin/i2c_slave_arbitration.rs @@ -0,0 +1,153 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +// test is targeted for nucleo-g070RB board +// this test will only respond to address 0x10, master read with 0xFF03 + +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::{Error, 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 embassy_time::{Duration, Timer}; +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 led = Output::new(p.PA5, Level::High, Speed::Low); + + let uart = usart::Uart::new( + p.USART1, + p.PB7, + p.PB6, + Irqs, + p.DMA1_CH1, + p.DMA1_CH2, + usart::Config::default(), + ) + .unwrap(); + + /* + let uart = usart::Uart::new( + p.USART2, + p.PA3, + p.PA2, + 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, + "i2c slave test for arbitration lost. Will respond to address 0x10\r" + ) + .unwrap(); + + let mut config = i2c::Config::default(); + config.slave_address_7bits(0x10); // for arbitration lost test + + 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 = vals::Dir::READ; + let mut counter = 0; + let mut result: Option = None; + + // start of the actual test + i2c.slave_start_listen().unwrap(); + loop { + counter += 1; + writeln!(&mut writer, "Loop: {}\r", counter).unwrap(); + + // content for test 0x10 + buf_2[0] = 0xFF; + buf_2[1] = 0x03; + _ = i2c.slave_write_buffer(&mut buf_2, i2c::AddressType::MainAddress); + + 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(); + + match 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(); + checkIsRead!(writer, dir); + match result { + None => { + writeln!(&mut writer, "Test 0x10 Passed\n\r").unwrap(); + } + Some(err) => writeln!(&mut writer, "Test 0x10 Failed. Error: {:?}\r", err).unwrap(), + }; + writeln!(&mut writer, "-----\r").unwrap(); + } + + _ => (), + } + } +}