aboutsummaryrefslogtreecommitdiff
path: root/examples/stm32f4/src
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
parente630e1a6d48ca25a92bc0479608ca75b7179c869 (diff)
stm32/i2c_v1: Add async and blocking example code
Diffstat (limited to 'examples/stm32f4/src')
-rw-r--r--examples/stm32f4/src/bin/i2c_slave_async.rs123
-rw-r--r--examples/stm32f4/src/bin/i2c_slave_blocking.rs118
2 files changed, 241 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}
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}