|
| 1 | +//! I2C Async Slave Example |
| 2 | +//! |
| 3 | +//! Demonstrates the async I2C slave (multimaster) implementation using DMA. |
| 4 | +//! The device listens for I2C transactions from an external master. |
| 5 | +//! |
| 6 | +//! # Hardware Setup |
| 7 | +//! |
| 8 | +//! - PB8 (SCL) and PB9 (SDA) with 4.7k pull-up resistors to 3.3V |
| 9 | +//! - Connect an I2C master device with clock stretching enabled |
| 10 | +//! - Default slave address: 0x42 (7-bit) |
| 11 | +//! |
| 12 | +//! # Behavior |
| 13 | +//! |
| 14 | +//! - Master WRITE: Receives up to BUFFER_SIZE bytes via DMA, excess bytes are drained |
| 15 | +//! - Master READ: Sends an 8-byte response pattern (0xA0-0xA7) via DMA |
| 16 | +
|
| 17 | +#![no_std] |
| 18 | +#![no_main] |
| 19 | + |
| 20 | +use defmt::*; |
| 21 | +use embassy_executor::Spawner; |
| 22 | +use embassy_stm32::i2c::{self, I2c, SendStatus, SlaveAddrConfig, SlaveCommandKind}; |
| 23 | +use embassy_stm32::{bind_interrupts, dma, peripherals}; |
| 24 | +use embassy_time::Duration; |
| 25 | +use {defmt_rtt as _, panic_probe as _}; |
| 26 | + |
| 27 | +const I2C_ADDR: u8 = 0x42; |
| 28 | +const BUFFER_SIZE: usize = 32; |
| 29 | + |
| 30 | +bind_interrupts!(struct Irqs { |
| 31 | + I2C1 => i2c::EventInterruptHandler<peripherals::I2C1>, i2c::ErrorInterruptHandler<peripherals::I2C1>; |
| 32 | + DMA1_CHANNEL2_3 => dma::InterruptHandler<peripherals::DMA1_CH2>, dma::InterruptHandler<peripherals::DMA1_CH3>; |
| 33 | +}); |
| 34 | + |
| 35 | +#[embassy_executor::main] |
| 36 | +async fn main(_spawner: Spawner) { |
| 37 | + let p = embassy_stm32::init(Default::default()); |
| 38 | + |
| 39 | + info!("I2C Async Slave Example"); |
| 40 | + info!("Address: 0x{:02X}, Buffer: {} bytes", I2C_ADDR, BUFFER_SIZE); |
| 41 | + |
| 42 | + let mut config = i2c::Config::default(); |
| 43 | + config.timeout = Duration::from_secs(30); |
| 44 | + |
| 45 | + let mut i2c = I2c::new(p.I2C1, p.PB8, p.PB9, p.DMA1_CH2, p.DMA1_CH3, Irqs, config) |
| 46 | + .into_slave_multimaster(SlaveAddrConfig::basic(I2C_ADDR)); |
| 47 | + |
| 48 | + info!("Slave ready, listening..."); |
| 49 | + |
| 50 | + let mut count: u32 = 0; |
| 51 | + loop { |
| 52 | + match i2c.listen().await { |
| 53 | + Ok(cmd) => { |
| 54 | + count += 1; |
| 55 | + match cmd.kind { |
| 56 | + SlaveCommandKind::Write => { |
| 57 | + let mut buffer = [0u8; BUFFER_SIZE]; |
| 58 | + match i2c.respond_to_write(&mut buffer).await { |
| 59 | + Ok(len) => info!("[{}] Write: {} bytes: {:02X}", count, len, &buffer[..len]), |
| 60 | + Err(e) => error!("[{}] Write error: {:?}", count, e), |
| 61 | + } |
| 62 | + } |
| 63 | + SlaveCommandKind::Read => { |
| 64 | + let response: [u8; 8] = [0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7]; |
| 65 | + match i2c.respond_to_read(&response).await { |
| 66 | + Ok(SendStatus::Done) => info!("[{}] Read: {} bytes", count, response.len()), |
| 67 | + Ok(SendStatus::LeftoverBytes(n)) => { |
| 68 | + info!("[{}] Read: {} of {} bytes", count, response.len() - n, response.len()) |
| 69 | + } |
| 70 | + Err(e) => error!("[{}] Read error: {:?}", count, e), |
| 71 | + } |
| 72 | + } |
| 73 | + } |
| 74 | + } |
| 75 | + Err(e) => error!("Listen error: {:?}", e), |
| 76 | + } |
| 77 | + } |
| 78 | +} |
0 commit comments