aboutsummaryrefslogtreecommitdiff
path: root/examples/stm32f4/src/bin/i2c_slave_blocking.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_blocking.rs
parente630e1a6d48ca25a92bc0479608ca75b7179c869 (diff)
stm32/i2c_v1: Add async and blocking example code
Diffstat (limited to 'examples/stm32f4/src/bin/i2c_slave_blocking.rs')
-rw-r--r--examples/stm32f4/src/bin/i2c_slave_blocking.rs118
1 files changed, 118 insertions, 0 deletions
diff --git a/examples/stm32f4/src/bin/i2c_slave_blocking.rs b/examples/stm32f4/src/bin/i2c_slave_blocking.rs
new file mode 100644
index 000000000..c55f2f6c1
--- /dev/null
+++ b/examples/stm32f4/src/bin/i2c_slave_blocking.rs
@@ -0,0 +1,118 @@
1//! Complete I2C slave example using blocking operations
2//!
3//! This example shows how to set up an STM32F4 as an I2C slave device
4//! that can handle both read and write transactions from master devices.
5
6#![no_std]
7#![no_main]
8
9use defmt_rtt as _;
10use defmt::{error, info};
11use embassy_executor::Spawner;
12use embassy_stm32::i2c::{self, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind, Address};
13use embassy_stm32::{bind_interrupts, peripherals};
14use embassy_stm32::time::Hertz;
15use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
16use embassy_sync::mutex::Mutex;
17use embassy_time::{Duration, Timer};
18use panic_probe as _;
19
20pub const I2C_SLAVE_ADDR: u8 = 0x42;
21pub const BUFFER_SIZE: usize = 8;
22static I2C_BUFFER: Mutex<ThreadModeRawMutex, [u8; BUFFER_SIZE]> = Mutex::new([0; BUFFER_SIZE]);
23
24bind_interrupts!(struct Irqs {
25 I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
26 I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
27});
28
29#[embassy_executor::main]
30async fn main(spawner: Spawner) {
31 let p = embassy_stm32::init(Default::default());
32
33 // Configure I2C
34 let mut i2c_config = i2c::Config::default();
35 i2c_config.sda_pullup = false;
36 i2c_config.scl_pullup = false;
37 i2c_config.frequency = Hertz(100_000);
38 i2c_config.timeout = embassy_time::Duration::from_millis(30000);
39
40 // Initialize I2C as master first
41 let i2c_master = I2c::new_blocking(
42 p.I2C1,
43 p.PB8, // SCL
44 p.PB9, // SDA
45 i2c_config,
46 );
47
48 // Convert to slave+master mode
49 let slave_config = SlaveAddrConfig::basic(I2C_SLAVE_ADDR);
50 let i2c_slave = i2c_master.into_slave_multimaster(slave_config);
51
52 spawner.spawn(i2c_slave_task(i2c_slave)).unwrap();
53}
54
55#[embassy_executor::task]
56pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Blocking, i2c::mode::MultiMaster>) {
57 info!("Blocking I2C slave ready at address 0x{:02X}", I2C_SLAVE_ADDR);
58
59 loop {
60 match i2c_slave.blocking_listen() {
61 Ok(SlaveCommand { kind: SlaveCommandKind::Write, address }) => {
62 let addr_val = match address {
63 Address::SevenBit(addr) => addr,
64 Address::TenBit(addr) => (addr & 0xFF) as u8,
65 };
66
67 info!("I2C: Received write command - Address 0x{:02X}", addr_val);
68 let mut data_buffer = I2C_BUFFER.lock().await;
69
70 match i2c_slave.blocking_respond_to_write(&mut *data_buffer) {
71 Ok(bytes_received) => {
72 info!("I2C: Received {} bytes - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}",
73 bytes_received, data_buffer[0], data_buffer[1], data_buffer[2], data_buffer[3], data_buffer[4], data_buffer[5], data_buffer[6], data_buffer[7]);
74 }
75 Err(e) => {
76 error!("I2C: Write error: {}", format_i2c_error(&e));
77 }
78 }
79 }
80
81 Ok(SlaveCommand { kind: SlaveCommandKind::Read, address }) => {
82 let addr_val = match address {
83 Address::SevenBit(addr) => addr,
84 Address::TenBit(addr) => (addr & 0xFF) as u8, // Show low byte for 10-bit
85 };
86
87 info!("I2C: Received read command - Address 0x{:02X}", addr_val);
88 let data_buffer = I2C_BUFFER.lock().await;
89
90 match i2c_slave.blocking_respond_to_read(&data_buffer[..BUFFER_SIZE]) {
91 Ok(bytes_sent) => {
92 info!("I2C: Responded to read - {} bytes sent", bytes_sent);
93 }
94 Err(e) => {
95 error!("I2C: Read error: {}", format_i2c_error(&e));
96 }
97 }
98 }
99
100 Err(e) => {
101 error!("I2C: Listen error: {}", format_i2c_error(&e));
102 Timer::after(Duration::from_millis(100)).await;
103 }
104 }
105 }
106}
107
108fn format_i2c_error(e: &embassy_stm32::i2c::Error) -> &'static str {
109 match e {
110 embassy_stm32::i2c::Error::Bus => "Bus",
111 embassy_stm32::i2c::Error::Arbitration => "Arbitration",
112 embassy_stm32::i2c::Error::Nack => "Nack",
113 embassy_stm32::i2c::Error::Timeout => "Timeout",
114 embassy_stm32::i2c::Error::Crc => "Crc",
115 embassy_stm32::i2c::Error::Overrun => "Overrun",
116 embassy_stm32::i2c::Error::ZeroLengthTransfer => "ZeroLengthTransfer",
117 }
118}