//! This example shows how to use an stm32 as both a master and a slave. #![no_std] #![no_main] use defmt::*; use embassy_executor::Spawner; use embassy_stm32::i2c::{Address, OwnAddresses, SlaveCommandKind}; use embassy_stm32::mode::Async; use embassy_stm32::time::Hertz; use embassy_stm32::{bind_interrupts, i2c, peripherals}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { I2C1_ER => i2c::ErrorInterruptHandler; I2C1_EV => i2c::EventInterruptHandler; I2C2_ER => i2c::ErrorInterruptHandler; I2C2_EV => i2c::EventInterruptHandler; }); const DEV_ADDR: u8 = 0x42; #[embassy_executor::task] async fn device_task(mut dev: i2c::I2c<'static, Async, i2c::MultiMaster>) -> ! { info!("Device start"); let mut state = 0; loop { let mut buf = [0u8; 128]; match dev.listen().await { Ok(i2c::SlaveCommand { kind: SlaveCommandKind::Read, address: Address::SevenBit(DEV_ADDR), }) => match dev.respond_to_read(&[state]).await { Ok(i2c::SendStatus::LeftoverBytes(x)) => info!("tried to write {} extra bytes", x), Ok(i2c::SendStatus::Done) => {} Err(e) => error!("error while responding {}", e), }, Ok(i2c::SlaveCommand { kind: SlaveCommandKind::Write, address: Address::SevenBit(DEV_ADDR), }) => match dev.respond_to_write(&mut buf).await { Ok(len) => { info!("Device received write: {}", buf[..len]); if match buf[0] { // Set the state 0xC2 => { state = buf[1]; true } // Reset State 0xC8 => { state = 0; true } x => { error!("Invalid Write Read {:x}", x); false } } { match dev.respond_to_read(&[state]).await { Ok(read_status) => info!( "This read is part of a write/read transaction. The response read status {}", read_status ), Err(i2c::Error::Timeout) => { info!("The device only performed a write and it not also do a read") } Err(e) => error!("error while responding {}", e), } } } Err(e) => error!("error while receiving {}", e), }, Ok(i2c::SlaveCommand { address, .. }) => { defmt::unreachable!( "The slave matched address: {}, which it was not configured for", address ); } Err(e) => error!("{}", e), } } } #[embassy_executor::task] async fn controller_task(mut con: i2c::I2c<'static, Async, i2c::Master>) { info!("Controller start"); loop { let mut resp_buff = [0u8; 1]; for i in 0..10 { match con.write_read(DEV_ADDR, &[0xC2, i], &mut resp_buff).await { Ok(_) => { info!("write_read response: {}", resp_buff); defmt::assert_eq!(resp_buff[0], i); } Err(e) => error!("Error writing {}", e), } Timer::after_millis(100).await; } match con.read(DEV_ADDR, &mut resp_buff).await { Ok(_) => { info!("read response: {}", resp_buff); // assert that the state is the last index that was written defmt::assert_eq!(resp_buff[0], 9); } Err(e) => error!("Error writing {}", e), } match con.write_read(DEV_ADDR, &[0xC8], &mut resp_buff).await { Ok(_) => { info!("write_read response: {}", resp_buff); // assert that the state has been reset defmt::assert_eq!(resp_buff[0], 0); } Err(e) => error!("Error writing {}", e), } Timer::after_millis(100).await; } } #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); let mut config = i2c::Config::default(); config.frequency = Hertz::khz(400); let d_addr_config = i2c::SlaveAddrConfig { addr: OwnAddresses::OA1(Address::SevenBit(DEV_ADDR)), general_call: false, }; let d_sda = p.PA8; let d_scl = p.PA9; let device = i2c::I2c::new(p.I2C2, d_scl, d_sda, Irqs, p.DMA1_CH1, p.DMA1_CH2, config).into_slave_multimaster(d_addr_config); unwrap!(spawner.spawn(device_task(device))); let c_sda = p.PB8; let c_scl = p.PB7; let controller = i2c::I2c::new(p.I2C1, c_sda, c_scl, Irqs, p.DMA1_CH3, p.DMA1_CH4, config); unwrap!(spawner.spawn(controller_task(controller))); }