From 70a64e8dcbe018b52b3bdefc20a8978ce0b3397e Mon Sep 17 00:00:00 2001 From: anton smeenk Date: Wed, 25 Oct 2023 21:25:38 +0200 Subject: [PATCH] I2c slave is working now. Todo: enable and test master write-read transaction --- embassy-stm32/src/i2c/mod.rs | 2 - embassy-stm32/src/i2c/v2.rs | 45 +++++--- examples/stm32g0/src/bin/i2c_master.rs | 36 ++++--- examples/stm32g0/src/bin/i2c_slave.rs | 140 ++++++++++++------------- 4 files changed, 120 insertions(+), 103 deletions(-) diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 2844d007..ae880a5c 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -22,8 +22,6 @@ pub enum Error { Collission, // in case of slave mode, during sending data to master BufferEmpty, BufferFull, - BufferNotEmpty, - BufferNotFilled, BufferSize, } diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 6d6b60d3..63361939 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -52,19 +52,19 @@ impl interrupt::typelevel::Handler for InterruptHandl state_m.result = Some(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)), + let b = match state_m.read_byte() { + Ok(b) => b, Err(e) => { state_m.result = Some(e); - // Send a NACK, set nbytes to clear tcr flag regs.cr2().modify(|w| { w.set_nack(true); - }) + }); + 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 @@ -72,7 +72,7 @@ impl interrupt::typelevel::Handler for InterruptHandl Ok(()) => (), Err(e) => { state_m.result = Some(e); - // Send a NACK, set nbytes to clear tcr flag + // Send a NACK regs.cr2().modify(|w| { w.set_nack(true); }) @@ -104,14 +104,27 @@ impl interrupt::typelevel::Handler for InterruptHandl // during sending nbytes automatically send a ACK, stretch clock after last byte w.set_reload(vals::Reload::COMPLETED); }); + // flush i2c tx register + regs.isr().write(|w| w.set_txe(true)); + // fill rx data with the first byte + let b = match state_m.read_byte() { + Ok(b) => b, + Err(e) => { + state_m.result = Some(e); + 0xFF + } + }; + regs.txdr().write(|w| w.set_txdata(b)); } 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)); + // 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)); @@ -223,7 +236,7 @@ impl I2cStateMachine { } else { AddressType::GenericAddress }; - self.buffers[adress_type as usize][vals::Dir::READ as usize as usize].master_read() + 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 { @@ -279,7 +292,6 @@ impl I2cBuffer { self.index += 1; Ok(b) } else { - self.size = 0; // mark buffer empty Err(Error::Overrun) // too many bytes asked } } @@ -308,11 +320,9 @@ impl I2cBuffer { 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 self.size == 0 { - return Err(Error::BufferNotFilled); - } - if buffer.len() < self.size as usize { + if buffer.len() != self.size as usize { return Err(Error::BufferSize); } for i in 0..buffer.len() { @@ -1038,6 +1048,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { 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(); @@ -1069,6 +1080,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { }); Ok(()) } + pub fn slave_sbc(&mut 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> { @@ -1079,7 +1094,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { }) } /// Read data from master (master_write_slave_read) after transaction is finished - /// Will fail if the size if the incoming buffer is smaller than the received bytes + /// 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> { T::state().mutex.lock(|f| { let mut state_m = f.borrow_mut(); diff --git a/examples/stm32g0/src/bin/i2c_master.rs b/examples/stm32g0/src/bin/i2c_master.rs index 36f6794a..3905e65f 100644 --- a/examples/stm32g0/src/bin/i2c_master.rs +++ b/examples/stm32g0/src/bin/i2c_master.rs @@ -2,6 +2,9 @@ #![no_main] #![feature(type_alias_impl_trait)] +// test is targeted for a specific board. Can simple be rewritten for a nucleo-070rb board +// by setting the uart to uart2 (see i2c_slave.rs) + use core::fmt::{self, Write}; use embassy_executor::Spawner; @@ -76,6 +79,7 @@ async fn main(_spawner: Spawner) { writeln!(&mut writer, "Loop counter: {:?}", 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]; @@ -163,23 +167,23 @@ async fn main(_spawner: Spawner) { Err(err) => writeln!(&mut writer, "Test 0x4B failed. Error: {:?}\r\n", err).unwrap(), }; /* - match i2c.blocking_write_read(0x44, &buf_20, &mut buf_64) { - Ok(_) => { - writeln!(&mut writer, "Test 0x44 Ok \n\r").unwrap(); - writeln!( - &mut writer, - "Uppercase input should be transformed to lowercase, A -> b " - ) - .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_rcv.len() { - writeln!(&mut writer, "{}", buf_rcv[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(), - }; + 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 diff --git a/examples/stm32g0/src/bin/i2c_slave.rs b/examples/stm32g0/src/bin/i2c_slave.rs index 3a48b2ae..8424d7fa 100644 --- a/examples/stm32g0/src/bin/i2c_slave.rs +++ b/examples/stm32g0/src/bin/i2c_slave.rs @@ -2,20 +2,24 @@ #![no_main] #![feature(type_alias_impl_trait)] +// test is targeted for nucleo-g070RB board + 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; + USART2 => usart::InterruptHandler; }); macro_rules! checkIsWrite { @@ -41,11 +45,20 @@ macro_rules! checkIsRead { }; } +#[embassy_executor::task] +pub async fn system_ticker(mut led: Output<'static, peripherals::PA5>) { + loop { + Timer::after(Duration::from_millis(200)).await; + led.set_high(); + Timer::after(Duration::from_millis(100)).await; + led.set_low(); + } +} pub struct SerialWriter { - tx: UartTx<'static, peripherals::USART1, peripherals::DMA1_CH1>, + tx: UartTx<'static, peripherals::USART2, peripherals::DMA1_CH1>, } impl SerialWriter { - pub fn new(tx: UartTx<'static, peripherals::USART1, peripherals::DMA1_CH1>) -> Self { + pub fn new(tx: UartTx<'static, peripherals::USART2, peripherals::DMA1_CH1>) -> Self { SerialWriter { tx } } } @@ -57,13 +70,26 @@ 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 mut 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.USART1, - p.PB7, - p.PB6, + p.USART2, + p.PA3, + p.PA2, Irqs, p.DMA1_CH1, p.DMA1_CH2, @@ -97,6 +123,8 @@ async fn main(_spawner: Spawner) { let mut counter = 0; let mut result: Option = None; + spawner.spawn(system_ticker(led)).unwrap(); + // start of the actual test i2c.slave_start_listen().unwrap(); loop { @@ -104,10 +132,10 @@ async fn main(_spawner: Spawner) { writeln!(&mut writer, "Loop: {}\r", counter).unwrap(); for i in 0..buf_20.len() { - buf_20[i] = 0x61 + (i as u8) + buf_20[i] = 0x20 + (i as u8) } for i in 0..buf_64.len() { - buf_64[i] = 0x41 + (i as u8) + buf_64[i] = 0x60 + (i as u8) } writeln!(&mut writer, "Waiting for master activity\r").unwrap(); @@ -127,11 +155,7 @@ async fn main(_spawner: Spawner) { match address { 0x41 => { - writeln!( - &mut writer, - "Start test 0x41. Master-write-slave-read 20 bytes. Should be ok\r\n" - ) - .unwrap(); + writeln!(&mut writer, "Evaluate test 0x41.\r\n").unwrap(); checkIsWrite!(writer, dir); _ = i2c.slave_read_buffer(&mut buf_20, i2c::AddressType::GenericAddress); match result { @@ -146,16 +170,12 @@ async fn main(_spawner: Spawner) { }; } 0x42 => { - writeln!( - &mut writer, - "Start test 0x42. Master-write-slave-read 64 bytes. Should be ok\r\n" - ) - .unwrap(); + writeln!(&mut writer, "Evaluate test 0x42.\r\n").unwrap(); checkIsWrite!(writer, dir); _ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::GenericAddress); match result { None => { - writeln!(&mut writer, "Test 0x42 passed. send 64 bytes").unwrap(); + writeln!(&mut writer, "Test 0x42 passed. send 64 bytes\r\n").unwrap(); print_buffer(&mut writer, &buf_64); } Some(err) => { @@ -165,32 +185,25 @@ async fn main(_spawner: Spawner) { }; } 0x43 => { - writeln!( - &mut writer, - "Start test 0x43. Master-write-slave-read 65 bytes. Slave should NACK at 65 byte\r\n" - ) - .unwrap(); + writeln!(&mut writer, "Evaluate test 0x43.\r\n").unwrap(); checkIsWrite!(writer, dir); _ = i2c.slave_read_buffer(&mut buf_64, i2c::AddressType::GenericAddress); match result { None => { - { - writeln!(&mut writer, "Test 0x43 failed. Expected to fail Got Ok\r").unwrap() - }; - } - Some(err) => { errors += 1; - writeln!(&mut writer, "Test 0x43 passed. Get expected error. Error: {:?}\r", err).unwrap() + writeln!(&mut writer, "Test 0x43 failed. Expected BufferFull error Got Ok\r").unwrap() } + Some(err) => writeln!( + &mut writer, + "Test 0x43 passed. Expected error: BufferFull. Error: {:?}\r", + err + ) + .unwrap(), }; } 0x48 => { // 0x48 master read slave write slave did not yet prepare a buffer, master will fail - writeln!( - &mut writer, - "Start test 0x48. Master-read-slave-write 20 bytes. Should first time (buffer empty)\r\n" - ) - .unwrap(); + writeln!(&mut writer, "Evaluate test 0x48.\r\n").unwrap(); checkIsRead!(writer, dir); match result { None => { @@ -199,18 +212,16 @@ async fn main(_spawner: Spawner) { } Some(err) => writeln!(&mut writer, "Test 0x48 passed. Got expected error: {:?}\r", err).unwrap(), }; - // prepare buffer for next round - for i in 0..buf_20.len() { - buf_20[i] = 0x61 + (i as u8) - } + // prepare buffer for test 0x49 _ = i2c.slave_write_buffer(&buf_20, i2c::AddressType::GenericAddress); } 0x49 => { - writeln!( - &mut writer, - "Start test 0x49. Master-read-slave-write 20 bytes. Should be ok\r\n" - ) - .unwrap(); + // 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(); checkIsRead!(writer, dir); match result { None => { @@ -221,19 +232,18 @@ async fn main(_spawner: Spawner) { 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) - } + // 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 - writeln!( - &mut writer, - "Start test 0x4A. Master-read-slave-write Master expects 64 bytes, slave sends 20.\r\n" - ) - .unwrap(); + // 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(); checkIsRead!(writer, dir); match result { None => { @@ -241,22 +251,14 @@ async fn main(_spawner: Spawner) { } Some(err) => { errors += 1; - writeln!(&mut writer, "Test 0x4A passed. Expected errore rror: {:?}\r", err).unwrap() + writeln!(&mut writer, "Test 0x4A passed. Expected error: {:?}\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 => { - writeln!( - &mut writer, - "Start test 0x4B. Master-read-slave-write Master expects 64 bytes, Should be ok.\r\n" - ) - .unwrap(); + // Master-read-slave-write Master expects 64 bytes, Should be ok + writeln!(&mut writer, "Evaluate test 0x4B. .\r\n").unwrap(); checkIsRead!(writer, dir); match result { None => { @@ -267,16 +269,14 @@ 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, - "Start test 0x4B. Master-read-slave-write 2 bytes with test summary Should be ok.\r\n" - ) - .unwrap(); + writeln!(&mut writer, "Evaluate test 0x4F.\r\n").unwrap(); match result { None => { writeln!(&mut writer, "Test 0x4F Result send to master\r").unwrap();