aboutsummaryrefslogtreecommitdiff
path: root/examples/stm32f4/src/bin/i2c_slave_async.rs
diff options
context:
space:
mode:
authorHybridChild <[email protected]>2025-08-23 08:31:41 +0200
committerHybridChild <[email protected]>2025-08-23 09:07:14 +0200
commit572a40b4eee99b177733f50b08e29ff9b5ab6fa5 (patch)
treeec4707ca547dc9ec764155d41d14ad4474aa344b /examples/stm32f4/src/bin/i2c_slave_async.rs
parente630e1a6d48ca25a92bc0479608ca75b7179c869 (diff)
stm32/i2c_v1: Add async and blocking example code
Diffstat (limited to 'examples/stm32f4/src/bin/i2c_slave_async.rs')
-rw-r--r--examples/stm32f4/src/bin/i2c_slave_async.rs123
1 files changed, 123 insertions, 0 deletions
diff --git a/examples/stm32f4/src/bin/i2c_slave_async.rs b/examples/stm32f4/src/bin/i2c_slave_async.rs
new file mode 100644
index 000000000..072c9875e
--- /dev/null
+++ b/examples/stm32f4/src/bin/i2c_slave_async.rs
@@ -0,0 +1,123 @@
1//! I2C slave example using async operations with DMA
2//!
3//! This example demonstrates DMA-accelerated I2C slave operations,
4//! which provide better performance and lower CPU overhead for
5//! high-frequency I2C transactions.
6
7#![no_std]
8#![no_main]
9
10use defmt_rtt as _;
11use defmt::{error, info};
12use embassy_executor::Spawner;
13use embassy_stm32::{bind_interrupts, peripherals};
14use embassy_stm32::i2c::{self, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind, Address};
15use embassy_stm32::time::Hertz;
16use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
17use embassy_sync::mutex::Mutex;
18use embassy_time::{Duration, Timer};
19use panic_probe as _;
20
21pub const I2C_SLAVE_ADDR: u8 = 0x42;
22pub const BUFFER_SIZE: usize = 8;
23static I2C_BUFFER: Mutex<ThreadModeRawMutex, [u8; BUFFER_SIZE]> = Mutex::new([0; BUFFER_SIZE]);
24
25bind_interrupts!(struct Irqs {
26 I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
27 I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
28});
29
30#[embassy_executor::main]
31async fn main(spawner: Spawner) {
32 let p = embassy_stm32::init(Default::default());
33
34 // Configure I2C
35 let mut i2c_config = i2c::Config::default();
36 i2c_config.sda_pullup = false;
37 i2c_config.scl_pullup = false;
38 i2c_config.frequency = Hertz(100_000); // 100kHz I2C speed
39
40 // Initialize I2C as master first
41 let i2c_master = I2c::new(
42 p.I2C1,
43 p.PB8, // SCL
44 p.PB9, // SDA
45 Irqs,
46 p.DMA1_CH6, // TX DMA
47 p.DMA1_CH0, // RX DMA
48 i2c_config,
49 );
50
51 // Convert to MultiMaster mode
52 let slave_config = SlaveAddrConfig::basic(I2C_SLAVE_ADDR);
53 let i2c_slave = i2c_master.into_slave_multimaster(slave_config);
54
55 spawner.spawn(i2c_slave_task(i2c_slave)).unwrap();
56}
57
58#[embassy_executor::task]
59pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Async, i2c::mode::MultiMaster>) {
60 info!("Async I2C slave ready at address 0x{:02X}", I2C_SLAVE_ADDR);
61
62 loop {
63 match i2c_slave.listen().await {
64 Ok(SlaveCommand { kind: SlaveCommandKind::Write, address }) => {
65 let addr_val = match address {
66 Address::SevenBit(addr) => addr,
67 Address::TenBit(addr) => (addr & 0xFF) as u8,
68 };
69
70 info!("I2C: Received write command - Address 0x{:02X}", addr_val);
71
72 let mut data_buffer = I2C_BUFFER.lock().await;
73
74 match i2c_slave.respond_to_write(&mut *data_buffer).await {
75 Ok(_) => {
76 info!("I2C: Data received - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}",
77 data_buffer[0], data_buffer[1], data_buffer[2], data_buffer[3], data_buffer[4], data_buffer[5], data_buffer[6], data_buffer[7]);
78 }
79 Err(e) => {
80 error!("I2C: Write error: {}", format_i2c_error(&e));
81 }
82 }
83 }
84
85 Ok(SlaveCommand { kind: SlaveCommandKind::Read, address }) => {
86 let addr_val = match address {
87 Address::SevenBit(addr) => addr,
88 Address::TenBit(addr) => (addr & 0xFF) as u8, // Show low byte for 10-bit
89 };
90
91 info!("I2C: Received read command - Address 0x{:02X}", addr_val);
92
93 let data_buffer = I2C_BUFFER.lock().await;
94
95 match i2c_slave.respond_to_read(&data_buffer[..BUFFER_SIZE]).await {
96 Ok(_) => {
97 info!("I2C: Responded to read command");
98 }
99 Err(e) => {
100 error!("I2C: Read error: {}", format_i2c_error(&e));
101 }
102 }
103 }
104
105 Err(e) => {
106 error!("I2C: Listen error: {}", format_i2c_error(&e));
107 Timer::after(Duration::from_millis(100)).await;
108 }
109 }
110 }
111}
112
113fn format_i2c_error(e: &embassy_stm32::i2c::Error) -> &'static str {
114 match e {
115 embassy_stm32::i2c::Error::Bus => "Bus",
116 embassy_stm32::i2c::Error::Arbitration => "Arbitration",
117 embassy_stm32::i2c::Error::Nack => "Nack",
118 embassy_stm32::i2c::Error::Timeout => "Timeout",
119 embassy_stm32::i2c::Error::Crc => "Crc",
120 embassy_stm32::i2c::Error::Overrun => "Overrun",
121 embassy_stm32::i2c::Error::ZeroLengthTransfer => "ZeroLengthTransfer",
122 }
123}