aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-04 13:22:19 +0000
committerGitHub <[email protected]>2025-11-04 13:22:19 +0000
commitb867072c7eefdd2cf0a19bacd86f4be820624ed9 (patch)
tree8a26ba0e703d82ec70c0cc3487a8ebc56273d1b6
parent51f8aeaa0dd2359a669a3c38d194a8a70f26441f (diff)
parentf8f7820ab98cc1f49d7b2a623566f836354916bc (diff)
Merge pull request #4812 from xoviat/i2c
i2cv1 slave mode
-rw-r--r--embassy-stm32/CHANGELOG.md1
-rw-r--r--embassy-stm32/src/i2c/config.rs8
-rw-r--r--embassy-stm32/src/i2c/mod.rs102
-rw-r--r--embassy-stm32/src/i2c/v1.rs1080
-rw-r--r--examples/stm32f4/src/bin/i2c_slave_async.rs135
-rw-r--r--examples/stm32f4/src/bin/i2c_slave_blocking.rs132
6 files changed, 1360 insertions, 98 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 8d5f603c7..3d6a41f14 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -36,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
36- feat: timer: add ability to set master mode 36- feat: timer: add ability to set master mode
37- fix: sdmmc: don't wait for DBCKEND flag on sdmmc_v2 devices as it never fires (Fixes #4723) 37- fix: sdmmc: don't wait for DBCKEND flag on sdmmc_v2 devices as it never fires (Fixes #4723)
38- fix: usart: fix race condition in ringbuffered usart 38- fix: usart: fix race condition in ringbuffered usart
39- feat: Add I2C MultiMaster (Slave) support for I2C v1
39- feat: stm32/fdcan: add ability to control automatic recovery from bus off ([#4821](https://github.com/embassy-rs/embassy/pull/4821)) 40- feat: stm32/fdcan: add ability to control automatic recovery from bus off ([#4821](https://github.com/embassy-rs/embassy/pull/4821))
40- low-power: update rtc api to allow reconfig 41- low-power: update rtc api to allow reconfig
41- adc: consolidate ringbuffer 42- adc: consolidate ringbuffer
diff --git a/embassy-stm32/src/i2c/config.rs b/embassy-stm32/src/i2c/config.rs
index 4e3b736c7..74fac14b2 100644
--- a/embassy-stm32/src/i2c/config.rs
+++ b/embassy-stm32/src/i2c/config.rs
@@ -4,7 +4,7 @@ use crate::gpio::{AfType, OutputType, Speed};
4use crate::time::Hertz; 4use crate::time::Hertz;
5 5
6#[repr(u8)] 6#[repr(u8)]
7#[derive(Copy, Clone)] 7#[derive(Debug, Copy, Clone)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))] 8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9/// Bits of the I2C OA2 register to mask out. 9/// Bits of the I2C OA2 register to mask out.
10pub enum AddrMask { 10pub enum AddrMask {
@@ -60,7 +60,7 @@ impl Address {
60 } 60 }
61} 61}
62 62
63#[derive(Copy, Clone)] 63#[derive(Debug, Copy, Clone)]
64#[cfg_attr(feature = "defmt", derive(defmt::Format))] 64#[cfg_attr(feature = "defmt", derive(defmt::Format))]
65/// The second Own Address register. 65/// The second Own Address register.
66pub struct OA2 { 66pub struct OA2 {
@@ -70,7 +70,7 @@ pub struct OA2 {
70 pub mask: AddrMask, 70 pub mask: AddrMask,
71} 71}
72 72
73#[derive(Copy, Clone)] 73#[derive(Debug, Copy, Clone)]
74#[cfg_attr(feature = "defmt", derive(defmt::Format))] 74#[cfg_attr(feature = "defmt", derive(defmt::Format))]
75/// The Own Address(es) of the I2C peripheral. 75/// The Own Address(es) of the I2C peripheral.
76pub enum OwnAddresses { 76pub enum OwnAddresses {
@@ -88,7 +88,7 @@ pub enum OwnAddresses {
88} 88}
89 89
90/// Slave Configuration 90/// Slave Configuration
91#[derive(Copy, Clone)] 91#[derive(Debug, Copy, Clone)]
92#[cfg_attr(feature = "defmt", derive(defmt::Format))] 92#[cfg_attr(feature = "defmt", derive(defmt::Format))]
93pub struct SlaveAddrConfig { 93pub struct SlaveAddrConfig {
94 /// Target Address(es) 94 /// Target Address(es)
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index f4bf55d34..ee60c3f44 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -219,6 +219,7 @@ impl<'d, M: Mode> I2c<'d, M, Master> {
219 sda, 219 sda,
220 }, 220 },
221 }; 221 };
222
222 this.enable_and_init(config); 223 this.enable_and_init(config);
223 224
224 this 225 this
@@ -437,15 +438,15 @@ impl<'d, IM: MasterMode> embedded_hal_async::i2c::I2c for I2c<'d, Async, IM> {
437 438
438/// Frame type in I2C transaction. 439/// Frame type in I2C transaction.
439/// 440///
440/// This tells each method what kind of framing to use, to generate a (repeated) start condition (ST 441/// This tells each method what kind of frame to use, to generate a (repeated) start condition (ST
441/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an 442/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an
442/// ACK or NACK after the last byte received. 443/// ACK or NACK after the last byte received.
443/// 444///
444/// For write operations, the following options are identical because they differ only in the (N)ACK 445/// For write operations, the following options are identical because they differ only in the (N)ACK
445/// treatment relevant for read operations: 446/// treatment relevant for read operations:
446/// 447///
447/// - `FirstFrame` and `FirstAndNextFrame` 448/// - `FirstFrame` and `FirstAndNextFrame` behave identically for writes
448/// - `NextFrame` and `LastFrameNoStop` 449/// - `NextFrame` and `LastFrameNoStop` behave identically for writes
449/// 450///
450/// Abbreviations used below: 451/// Abbreviations used below:
451/// 452///
@@ -474,7 +475,7 @@ enum FrameOptions {
474 475
475#[allow(dead_code)] 476#[allow(dead_code)]
476impl FrameOptions { 477impl FrameOptions {
477 /// Sends start or repeated start condition before transfer. 478 /// Returns true if a start or repeated start condition should be generated before this operation.
478 fn send_start(self) -> bool { 479 fn send_start(self) -> bool {
479 match self { 480 match self {
480 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true, 481 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true,
@@ -482,7 +483,7 @@ impl FrameOptions {
482 } 483 }
483 } 484 }
484 485
485 /// Sends stop condition after transfer. 486 /// Returns true if a stop condition should be generated after this operation.
486 fn send_stop(self) -> bool { 487 fn send_stop(self) -> bool {
487 match self { 488 match self {
488 Self::FirstAndLastFrame | Self::LastFrame => true, 489 Self::FirstAndLastFrame | Self::LastFrame => true,
@@ -490,7 +491,10 @@ impl FrameOptions {
490 } 491 }
491 } 492 }
492 493
493 /// Sends NACK after last byte received, indicating end of read operation. 494 /// Returns true if NACK should be sent after the last byte received in a read operation.
495 ///
496 /// This signals the end of a read sequence and releases the bus for the master's
497 /// next transmission (or stop condition).
494 fn send_nack(self) -> bool { 498 fn send_nack(self) -> bool {
495 match self { 499 match self {
496 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true, 500 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true,
@@ -499,24 +503,44 @@ impl FrameOptions {
499 } 503 }
500} 504}
501 505
502/// Iterates over operations in transaction. 506/// Analyzes I2C transaction operations and assigns appropriate frame to each.
507///
508/// This function processes a sequence of I2C operations and determines the correct
509/// frame configuration for each operation to ensure proper I2C protocol compliance.
510/// It handles the complex logic of:
511///
512/// - Generating start conditions for the first operation of each type (read/write)
513/// - Generating stop conditions for the final operation in the entire transaction
514/// - Managing ACK/NACK behavior for read operations, including merging consecutive reads
515/// - Ensuring proper bus handoff between different operation types
516///
517/// **Transaction Contract Compliance:**
518/// The frame assignments ensure compliance with the embedded-hal I2C transaction contract,
519/// where consecutive operations of the same type are logically merged while maintaining
520/// proper protocol boundaries.
503/// 521///
504/// Returns necessary frame options for each operation to uphold the [transaction contract] and have 522/// **Error Handling:**
505/// the right start/stop/(N)ACK conditions on the wire. 523/// Returns an error if any read operation has an empty buffer, as this would create
524/// an invalid I2C transaction that could halt mid-execution.
525///
526/// # Arguments
527/// * `operations` - Mutable slice of I2C operations from embedded-hal
528///
529/// # Returns
530/// An iterator over (operation, frame) pairs, or an error if the transaction is invalid
506/// 531///
507/// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
508#[allow(dead_code)] 532#[allow(dead_code)]
509fn operation_frames<'a, 'b: 'a>( 533fn operation_frames<'a, 'b: 'a>(
510 operations: &'a mut [embedded_hal_1::i2c::Operation<'b>], 534 operations: &'a mut [embedded_hal_1::i2c::Operation<'b>],
511) -> Result<impl IntoIterator<Item = (&'a mut embedded_hal_1::i2c::Operation<'b>, FrameOptions)>, Error> { 535) -> Result<impl IntoIterator<Item = (&'a mut embedded_hal_1::i2c::Operation<'b>, FrameOptions)>, Error> {
512 use embedded_hal_1::i2c::Operation::{Read, Write}; 536 use embedded_hal_1::i2c::Operation::{Read, Write};
513 537
514 // Check empty read buffer before starting transaction. Otherwise, we would risk halting with an 538 // Validate that no read operations have empty buffers before starting the transaction.
515 // error in the middle of the transaction. 539 // Empty read operations would risk halting with an error mid-transaction.
516 // 540 //
517 // In principle, we could allow empty read frames within consecutive read operations, as long as 541 // Note: We could theoretically allow empty read operations within consecutive read
518 // at least one byte remains in the final (merged) read operation, but that makes the logic more 542 // sequences as long as the final merged read has at least one byte, but this would
519 // complicated and error-prone. 543 // complicate the logic significantly and create error-prone edge cases.
520 if operations.iter().any(|op| match op { 544 if operations.iter().any(|op| match op {
521 Read(read) => read.is_empty(), 545 Read(read) => read.is_empty(),
522 Write(_) => false, 546 Write(_) => false,
@@ -525,46 +549,52 @@ fn operation_frames<'a, 'b: 'a>(
525 } 549 }
526 550
527 let mut operations = operations.iter_mut().peekable(); 551 let mut operations = operations.iter_mut().peekable();
528 552 let mut next_first_operation = true;
529 let mut next_first_frame = true;
530 553
531 Ok(iter::from_fn(move || { 554 Ok(iter::from_fn(move || {
532 let op = operations.next()?; 555 let current_op = operations.next()?;
533 556
534 // Is `op` first frame of its type? 557 // Determine if this is the first operation of its type (read or write)
535 let first_frame = next_first_frame; 558 let is_first_of_type = next_first_operation;
536 let next_op = operations.peek(); 559 let next_op = operations.peek();
537 560
538 // Get appropriate frame options as combination of the following properties: 561 // Compute the appropriate frame based on three key properties:
539 // 562 //
540 // - For each first operation of its type, generate a (repeated) start condition. 563 // 1. **Start Condition**: Generate (repeated) start for first operation of each type
541 // - For the last operation overall in the entire transaction, generate a stop condition. 564 // 2. **Stop Condition**: Generate stop for the final operation in the entire transaction
542 // - For read operations, check the next operation: if it is also a read operation, we merge 565 // 3. **ACK/NACK for Reads**: For read operations, send ACK if more reads follow in the
543 // these and send ACK for all bytes in the current operation; send NACK only for the final 566 // sequence, or NACK for the final read in a sequence (before write or transaction end)
544 // read operation's last byte (before write or end of entire transaction) to indicate last
545 // byte read and release the bus for transmission of the bus master's next byte (or stop).
546 // 567 //
547 // We check the third property unconditionally, i.e. even for write opeartions. This is okay 568 // The third property is checked for all operations since the resulting frame
548 // because the resulting frame options are identical for write operations. 569 // configurations are identical for write operations regardless of ACK/NACK treatment.
549 let frame = match (first_frame, next_op) { 570 let frame = match (is_first_of_type, next_op) {
571 // First operation of type, and it's also the final operation overall
550 (true, None) => FrameOptions::FirstAndLastFrame, 572 (true, None) => FrameOptions::FirstAndLastFrame,
573 // First operation of type, next operation is also a read (continue read sequence)
551 (true, Some(Read(_))) => FrameOptions::FirstAndNextFrame, 574 (true, Some(Read(_))) => FrameOptions::FirstAndNextFrame,
575 // First operation of type, next operation is write (end current sequence)
552 (true, Some(Write(_))) => FrameOptions::FirstFrame, 576 (true, Some(Write(_))) => FrameOptions::FirstFrame,
553 // 577
578 // Continuation operation, and it's the final operation overall
554 (false, None) => FrameOptions::LastFrame, 579 (false, None) => FrameOptions::LastFrame,
580 // Continuation operation, next operation is also a read (continue read sequence)
555 (false, Some(Read(_))) => FrameOptions::NextFrame, 581 (false, Some(Read(_))) => FrameOptions::NextFrame,
582 // Continuation operation, next operation is write (end current sequence, no stop)
556 (false, Some(Write(_))) => FrameOptions::LastFrameNoStop, 583 (false, Some(Write(_))) => FrameOptions::LastFrameNoStop,
557 }; 584 };
558 585
559 // Pre-calculate if `next_op` is the first operation of its type. We do this here and not at 586 // Pre-calculate whether the next operation will be the first of its type.
560 // the beginning of the loop because we hand out `op` as iterator value and cannot access it 587 // This is done here because we consume `current_op` as the iterator value
561 // anymore in the next iteration. 588 // and cannot access it in the next iteration.
562 next_first_frame = match (&op, next_op) { 589 next_first_operation = match (&current_op, next_op) {
590 // No next operation
563 (_, None) => false, 591 (_, None) => false,
592 // Operation type changes: next will be first of its type
564 (Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true, 593 (Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true,
594 // Operation type continues: next will not be first of its type
565 (Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false, 595 (Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false,
566 }; 596 };
567 597
568 Some((op, frame)) 598 Some((current_op, frame))
569 })) 599 }))
570} 600}
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index e6b6c7c42..128a58db7 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -30,6 +30,7 @@ use crate::pac::i2c;
30// hit a case like this! 30// hit a case like this!
31pub unsafe fn on_interrupt<T: Instance>() { 31pub unsafe fn on_interrupt<T: Instance>() {
32 let regs = T::info().regs; 32 let regs = T::info().regs;
33 trace!("I2C interrupt triggered");
33 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of 34 // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of
34 // other stuff, so we wake the task on every interrupt. 35 // other stuff, so we wake the task on every interrupt.
35 T::state().waker.wake(); 36 T::state().waker.wake();
@@ -92,6 +93,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
92 self.info.regs.cr1().modify(|reg| { 93 self.info.regs.cr1().modify(|reg| {
93 reg.set_pe(true); 94 reg.set_pe(true);
94 }); 95 });
96 trace!("i2c v1 init complete");
95 } 97 }
96 98
97 fn check_and_clear_error_flags(info: &'static Info) -> Result<i2c::regs::Sr1, Error> { 99 fn check_and_clear_error_flags(info: &'static Info) -> Result<i2c::regs::Sr1, Error> {
@@ -151,7 +153,13 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
151 Ok(sr1) 153 Ok(sr1)
152 } 154 }
153 155
154 fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout, frame: FrameOptions) -> Result<(), Error> { 156 fn write_bytes(
157 &mut self,
158 address: u8,
159 write_buffer: &[u8],
160 timeout: Timeout,
161 frame: FrameOptions,
162 ) -> Result<(), Error> {
155 if frame.send_start() { 163 if frame.send_start() {
156 // Send a START condition 164 // Send a START condition
157 165
@@ -170,7 +178,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
170 } 178 }
171 179
172 // Set up current address we're trying to talk to 180 // Set up current address we're trying to talk to
173 self.info.regs.dr().write(|reg| reg.set_dr(addr << 1)); 181 self.info.regs.dr().write(|reg| reg.set_dr(address << 1));
174 182
175 // Wait until address was sent 183 // Wait until address was sent
176 // Wait for the address to be acknowledged 184 // Wait for the address to be acknowledged
@@ -184,7 +192,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
184 } 192 }
185 193
186 // Send bytes 194 // Send bytes
187 for c in bytes { 195 for c in write_buffer {
188 self.send_byte(*c, timeout)?; 196 self.send_byte(*c, timeout)?;
189 } 197 }
190 198
@@ -236,12 +244,12 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
236 244
237 fn blocking_read_timeout( 245 fn blocking_read_timeout(
238 &mut self, 246 &mut self,
239 addr: u8, 247 address: u8,
240 buffer: &mut [u8], 248 read_buffer: &mut [u8],
241 timeout: Timeout, 249 timeout: Timeout,
242 frame: FrameOptions, 250 frame: FrameOptions,
243 ) -> Result<(), Error> { 251 ) -> Result<(), Error> {
244 let Some((last, buffer)) = buffer.split_last_mut() else { 252 let Some((last_byte, read_buffer)) = read_buffer.split_last_mut() else {
245 return Err(Error::Overrun); 253 return Err(Error::Overrun);
246 }; 254 };
247 255
@@ -263,7 +271,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
263 } 271 }
264 272
265 // Set up current address we're trying to talk to 273 // Set up current address we're trying to talk to
266 self.info.regs.dr().write(|reg| reg.set_dr((addr << 1) + 1)); 274 self.info.regs.dr().write(|reg| reg.set_dr((address << 1) + 1));
267 275
268 // Wait until address was sent 276 // Wait until address was sent
269 // Wait for the address to be acknowledged 277 // Wait for the address to be acknowledged
@@ -276,7 +284,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
276 } 284 }
277 285
278 // Receive bytes into buffer 286 // Receive bytes into buffer
279 for c in buffer { 287 for c in read_buffer {
280 *c = self.recv_byte(timeout)?; 288 *c = self.recv_byte(timeout)?;
281 } 289 }
282 290
@@ -291,37 +299,42 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
291 }); 299 });
292 300
293 // Receive last byte 301 // Receive last byte
294 *last = self.recv_byte(timeout)?; 302 *last_byte = self.recv_byte(timeout)?;
295 303
296 // Fallthrough is success 304 // Fallthrough is success
297 Ok(()) 305 Ok(())
298 } 306 }
299 307
300 /// Blocking read. 308 /// Blocking read.
301 pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { 309 pub fn blocking_read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> {
302 self.blocking_read_timeout(addr, read, self.timeout(), FrameOptions::FirstAndLastFrame) 310 self.blocking_read_timeout(address, read_buffer, self.timeout(), FrameOptions::FirstAndLastFrame)
303 } 311 }
304 312
305 /// Blocking write. 313 /// Blocking write.
306 pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { 314 pub fn blocking_write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> {
307 self.write_bytes(addr, write, self.timeout(), FrameOptions::FirstAndLastFrame)?; 315 self.write_bytes(address, write_buffer, self.timeout(), FrameOptions::FirstAndLastFrame)?;
308 316
309 // Fallthrough is success 317 // Fallthrough is success
310 Ok(()) 318 Ok(())
311 } 319 }
312 320
313 /// Blocking write, restart, read. 321 /// Blocking write, restart, read.
314 pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 322 pub fn blocking_write_read(
323 &mut self,
324 address: u8,
325 write_buffer: &[u8],
326 read_buffer: &mut [u8],
327 ) -> Result<(), Error> {
315 // Check empty read buffer before starting transaction. Otherwise, we would not generate the 328 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
316 // stop condition below. 329 // stop condition below.
317 if read.is_empty() { 330 if read_buffer.is_empty() {
318 return Err(Error::Overrun); 331 return Err(Error::Overrun);
319 } 332 }
320 333
321 let timeout = self.timeout(); 334 let timeout = self.timeout();
322 335
323 self.write_bytes(addr, write, timeout, FrameOptions::FirstFrame)?; 336 self.write_bytes(address, write_buffer, timeout, FrameOptions::FirstFrame)?;
324 self.blocking_read_timeout(addr, read, timeout, FrameOptions::FirstAndLastFrame)?; 337 self.blocking_read_timeout(address, read_buffer, timeout, FrameOptions::FirstAndLastFrame)?;
325 338
326 Ok(()) 339 Ok(())
327 } 340 }
@@ -331,32 +344,43 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
331 /// Consecutive operations of same type are merged. See [transaction contract] for details. 344 /// Consecutive operations of same type are merged. See [transaction contract] for details.
332 /// 345 ///
333 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 346 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
334 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 347 pub fn blocking_transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
335 let timeout = self.timeout(); 348 let timeout = self.timeout();
336 349
337 for (op, frame) in operation_frames(operations)? { 350 for (op, frame) in operation_frames(operations)? {
338 match op { 351 match op {
339 Operation::Read(read) => self.blocking_read_timeout(addr, read, timeout, frame)?, 352 Operation::Read(read_buffer) => self.blocking_read_timeout(address, read_buffer, timeout, frame)?,
340 Operation::Write(write) => self.write_bytes(addr, write, timeout, frame)?, 353 Operation::Write(write_buffer) => self.write_bytes(address, write_buffer, timeout, frame)?,
341 } 354 }
342 } 355 }
343 356
344 Ok(()) 357 Ok(())
345 } 358 }
346 359
347 // Async 360 /// Can be used by both blocking and async implementations
348
349 #[inline] // pretty sure this should always be inlined 361 #[inline] // pretty sure this should always be inlined
350 fn enable_interrupts(info: &'static Info) -> () { 362 fn enable_interrupts(info: &'static Info) {
351 info.regs.cr2().modify(|w| { 363 // The interrupt handler disables interrupts globally, so we need to re-enable them
352 w.set_iterren(true); 364 // This must be done in a critical section to avoid races
353 w.set_itevten(true); 365 critical_section::with(|_| {
366 info.regs.cr2().modify(|w| {
367 w.set_iterren(true);
368 w.set_itevten(true);
369 });
354 }); 370 });
355 } 371 }
372
373 /// Can be used by both blocking and async implementations
374 fn clear_stop_flag(info: &'static Info) {
375 trace!("I2C slave: clearing STOPF flag (v1 sequence)");
376 // v1 requires: READ SR1 then WRITE CR1 to clear STOPF
377 let _ = info.regs.sr1().read();
378 info.regs.cr1().modify(|_| {}); // Dummy write to clear STOPF
379 }
356} 380}
357 381
358impl<'d, IM: MasterMode> I2c<'d, Async, IM> { 382impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
359 async fn write_frame(&mut self, address: u8, write: &[u8], frame: FrameOptions) -> Result<(), Error> { 383 async fn write_frame(&mut self, address: u8, write_buffer: &[u8], frame: FrameOptions) -> Result<(), Error> {
360 self.info.regs.cr2().modify(|w| { 384 self.info.regs.cr2().modify(|w| {
361 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for 385 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for
362 // reception. 386 // reception.
@@ -439,7 +463,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
439 // this address from the memory after each TxE event. 463 // this address from the memory after each TxE event.
440 let dst = self.info.regs.dr().as_ptr() as *mut u8; 464 let dst = self.info.regs.dr().as_ptr() as *mut u8;
441 465
442 self.tx_dma.as_mut().unwrap().write(write, dst, Default::default()) 466 self.tx_dma
467 .as_mut()
468 .unwrap()
469 .write(write_buffer, dst, Default::default())
443 }; 470 };
444 471
445 // Wait for bytes to be sent, or an error to occur. 472 // Wait for bytes to be sent, or an error to occur.
@@ -501,28 +528,28 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
501 } 528 }
502 529
503 /// Write. 530 /// Write.
504 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { 531 pub async fn write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> {
505 self.write_frame(address, write, FrameOptions::FirstAndLastFrame) 532 self.write_frame(address, write_buffer, FrameOptions::FirstAndLastFrame)
506 .await?; 533 .await?;
507 534
508 Ok(()) 535 Ok(())
509 } 536 }
510 537
511 /// Read. 538 /// Read.
512 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { 539 pub async fn read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> {
513 self.read_frame(address, buffer, FrameOptions::FirstAndLastFrame) 540 self.read_frame(address, read_buffer, FrameOptions::FirstAndLastFrame)
514 .await?; 541 .await?;
515 542
516 Ok(()) 543 Ok(())
517 } 544 }
518 545
519 async fn read_frame(&mut self, address: u8, buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> { 546 async fn read_frame(&mut self, address: u8, read_buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> {
520 if buffer.is_empty() { 547 if read_buffer.is_empty() {
521 return Err(Error::Overrun); 548 return Err(Error::Overrun);
522 } 549 }
523 550
524 // Some branches below depend on whether the buffer contains only a single byte. 551 // Some branches below depend on whether the buffer contains only a single byte.
525 let single_byte = buffer.len() == 1; 552 let single_byte = read_buffer.len() == 1;
526 553
527 self.info.regs.cr2().modify(|w| { 554 self.info.regs.cr2().modify(|w| {
528 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for 555 // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for
@@ -612,7 +639,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
612 self.info.regs.sr2().read(); 639 self.info.regs.sr2().read();
613 } else { 640 } else {
614 // Before starting reception of single byte (but without START condition, i.e. in case 641 // Before starting reception of single byte (but without START condition, i.e. in case
615 // of continued frame), program NACK to emit at end of this byte. 642 // of merged operations), program NACK to emit at end of this byte.
616 if frame.send_nack() && single_byte { 643 if frame.send_nack() && single_byte {
617 self.info.regs.cr1().modify(|w| { 644 self.info.regs.cr1().modify(|w| {
618 w.set_ack(false); 645 w.set_ack(false);
@@ -634,7 +661,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
634 // from this address from the memory after each RxE event. 661 // from this address from the memory after each RxE event.
635 let src = self.info.regs.dr().as_ptr() as *mut u8; 662 let src = self.info.regs.dr().as_ptr() as *mut u8;
636 663
637 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) 664 self.rx_dma.as_mut().unwrap().read(src, read_buffer, Default::default())
638 }; 665 };
639 666
640 // Wait for bytes to be received, or an error to occur. 667 // Wait for bytes to be received, or an error to occur.
@@ -673,15 +700,17 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
673 } 700 }
674 701
675 /// Write, restart, read. 702 /// Write, restart, read.
676 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { 703 pub async fn write_read(&mut self, address: u8, write_buffer: &[u8], read_buffer: &mut [u8]) -> Result<(), Error> {
677 // Check empty read buffer before starting transaction. Otherwise, we would not generate the 704 // Check empty read buffer before starting transaction. Otherwise, we would not generate the
678 // stop condition below. 705 // stop condition below.
679 if read.is_empty() { 706 if read_buffer.is_empty() {
680 return Err(Error::Overrun); 707 return Err(Error::Overrun);
681 } 708 }
682 709
683 self.write_frame(address, write, FrameOptions::FirstFrame).await?; 710 self.write_frame(address, write_buffer, FrameOptions::FirstFrame)
684 self.read_frame(address, read, FrameOptions::FirstAndLastFrame).await 711 .await?;
712 self.read_frame(address, read_buffer, FrameOptions::FirstAndLastFrame)
713 .await
685 } 714 }
686 715
687 /// Transaction with operations. 716 /// Transaction with operations.
@@ -689,11 +718,11 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
689 /// Consecutive operations of same type are merged. See [transaction contract] for details. 718 /// Consecutive operations of same type are merged. See [transaction contract] for details.
690 /// 719 ///
691 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 720 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
692 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 721 pub async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
693 for (op, frame) in operation_frames(operations)? { 722 for (op, frame) in operation_frames(operations)? {
694 match op { 723 match op {
695 Operation::Read(read) => self.read_frame(addr, read, frame).await?, 724 Operation::Read(read_buffer) => self.read_frame(address, read_buffer, frame).await?,
696 Operation::Write(write) => self.write_frame(addr, write, frame).await?, 725 Operation::Write(write_buffer) => self.write_frame(address, write_buffer, frame).await?,
697 } 726 }
698 } 727 }
699 728
@@ -729,12 +758,956 @@ impl Duty {
729 } 758 }
730} 759}
731 760
761/// Result of attempting to send a byte in slave transmitter mode
762#[derive(Debug, PartialEq)]
763enum TransmitResult {
764 /// Byte sent and ACKed by master - continue transmission
765 Acknowledged,
766 /// Byte sent but NACKed by master - normal end of read transaction
767 NotAcknowledged,
768 /// STOP condition detected - master terminated transaction
769 Stopped,
770 /// RESTART condition detected - master starting new transaction
771 Restarted,
772}
773
774/// Result of attempting to receive a byte in slave receiver mode
775#[derive(Debug, PartialEq)]
776enum ReceiveResult {
777 /// Data byte successfully received
778 Data(u8),
779 /// STOP condition detected - end of write transaction
780 Stopped,
781 /// RESTART condition detected - master starting new transaction
782 Restarted,
783}
784
785/// Enumeration of slave transaction termination conditions
786#[derive(Debug, Clone, Copy, PartialEq)]
787#[cfg_attr(feature = "defmt", derive(defmt::Format))]
788enum SlaveTermination {
789 /// STOP condition received - normal end of transaction
790 Stop,
791 /// RESTART condition received - master starting new transaction
792 Restart,
793 /// NACK received - normal end of read transaction
794 Nack,
795}
796
797impl<'d, M: PeriMode> I2c<'d, M, Master> {
798 /// Configure the I2C driver for slave operations, allowing for the driver to be used as a slave and a master (multimaster)
799 pub fn into_slave_multimaster(mut self, slave_addr_config: SlaveAddrConfig) -> I2c<'d, M, MultiMaster> {
800 let mut slave = I2c {
801 info: self.info,
802 state: self.state,
803 kernel_clock: self.kernel_clock,
804 tx_dma: self.tx_dma.take(), // Use take() to move ownership
805 rx_dma: self.rx_dma.take(), // Use take() to move ownership
806 #[cfg(feature = "time")]
807 timeout: self.timeout,
808 _phantom: PhantomData,
809 _phantom2: PhantomData,
810 _drop_guard: self._drop_guard, // Move the drop guard
811 };
812 slave.init_slave(slave_addr_config);
813 slave
814 }
815}
816
817// Address configuration methods
818impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> {
819 /// Initialize slave mode with address configuration
820 pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) {
821 trace!("I2C slave: initializing with config={:?}", config);
822
823 // Disable peripheral for configuration
824 self.info.regs.cr1().modify(|reg| reg.set_pe(false));
825
826 // Configure slave addresses
827 self.apply_address_configuration(config);
828
829 // Enable peripheral with slave settings
830 self.info.regs.cr1().modify(|reg| {
831 reg.set_pe(true);
832 reg.set_ack(true); // Enable acknowledgment for slave mode
833 reg.set_nostretch(false); // Allow clock stretching for processing time
834 });
835
836 trace!("I2C slave: initialization complete");
837 }
838
839 /// Apply the complete address configuration for slave mode
840 fn apply_address_configuration(&mut self, config: SlaveAddrConfig) {
841 match config.addr {
842 OwnAddresses::OA1(addr) => {
843 self.configure_primary_address(addr);
844 self.disable_secondary_address();
845 }
846 OwnAddresses::OA2(oa2) => {
847 self.configure_default_primary_address();
848 self.configure_secondary_address(oa2.addr); // v1 ignores mask
849 }
850 OwnAddresses::Both { oa1, oa2 } => {
851 self.configure_primary_address(oa1);
852 self.configure_secondary_address(oa2.addr); // v1 ignores mask
853 }
854 }
855
856 // Configure general call detection
857 if config.general_call {
858 self.info.regs.cr1().modify(|w| w.set_engc(true));
859 }
860 }
861
862 /// Configure the primary address (OA1) register
863 fn configure_primary_address(&mut self, addr: Address) {
864 match addr {
865 Address::SevenBit(addr) => {
866 self.info.regs.oar1().write(|reg| {
867 let hw_addr = (addr as u16) << 1; // Address in bits [7:1]
868 reg.set_add(hw_addr);
869 reg.set_addmode(i2c::vals::Addmode::BIT7);
870 });
871 }
872 Address::TenBit(addr) => {
873 self.info.regs.oar1().write(|reg| {
874 reg.set_add(addr);
875 reg.set_addmode(i2c::vals::Addmode::BIT10);
876 });
877 }
878 }
879
880 // Set required bit 14 as per reference manual
881 self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14);
882 }
883
884 /// Configure the secondary address (OA2) register
885 fn configure_secondary_address(&mut self, addr: u8) {
886 self.info.regs.oar2().write(|reg| {
887 reg.set_add2(addr);
888 reg.set_endual(i2c::vals::Endual::DUAL);
889 });
890 }
891
892 /// Set a default primary address when using OA2-only mode
893 fn configure_default_primary_address(&mut self) {
894 self.info.regs.oar1().write(|reg| {
895 reg.set_add(0); // Reserved address, safe to use
896 reg.set_addmode(i2c::vals::Addmode::BIT7);
897 });
898 self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14);
899 }
900
901 /// Disable secondary address when not needed
902 fn disable_secondary_address(&mut self) {
903 self.info.regs.oar2().write(|reg| {
904 reg.set_endual(i2c::vals::Endual::SINGLE);
905 });
906 }
907}
908
909impl<'d, M: PeriMode> I2c<'d, M, MultiMaster> {
910 /// Listen for incoming I2C address match and return the command type
911 ///
912 /// This method blocks until the slave address is matched by a master.
913 /// Returns the command type (Read/Write) and the matched address.
914 pub fn blocking_listen(&mut self) -> Result<SlaveCommand, Error> {
915 trace!("I2C slave: starting blocking listen for address match");
916 let result = self.blocking_listen_with_timeout(self.timeout());
917 trace!("I2C slave: blocking listen complete, result={:?}", result);
918 result
919 }
920
921 /// Respond to a master read request by transmitting data
922 ///
923 /// Sends the provided data to the master. If the master requests more bytes
924 /// than available, padding bytes (0x00) are sent until the master terminates
925 /// the transaction with NACK.
926 ///
927 /// Returns the total number of bytes transmitted (including padding).
928 pub fn blocking_respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> {
929 trace!("I2C slave: starting blocking respond_to_read, data_len={}", data.len());
930
931 if let Some(zero_length_result) = self.detect_zero_length_read(self.timeout())? {
932 trace!("I2C slave: zero-length read detected");
933 return Ok(zero_length_result);
934 }
935
936 let result = self.transmit_to_master(data, self.timeout());
937 trace!("I2C slave: blocking respond_to_read complete, result={:?}", result);
938 result
939 }
940
941 /// Respond to a master write request by receiving data
942 ///
943 /// Receives data from the master into the provided buffer. If the master
944 /// sends more bytes than the buffer can hold, excess bytes are acknowledged
945 /// but discarded.
946 ///
947 /// Returns the number of bytes stored in the buffer (not total received).
948 pub fn blocking_respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
949 trace!(
950 "I2C slave: starting blocking respond_to_write, buffer_len={}",
951 buffer.len()
952 );
953 let result = self.receive_from_master(buffer, self.timeout());
954 trace!("I2C slave: blocking respond_to_write complete, result={:?}", result);
955 result
956 }
957
958 // Private implementation methods
959
960 /// Wait for address match and determine transaction type
961 fn blocking_listen_with_timeout(&mut self, timeout: Timeout) -> Result<SlaveCommand, Error> {
962 // Ensure interrupts are disabled for blocking operation
963 self.disable_i2c_interrupts();
964
965 // Wait for address match (ADDR flag)
966 loop {
967 let sr1 = Self::read_status_and_handle_errors(self.info)?;
968
969 if sr1.addr() {
970 // Address matched - read SR2 to get direction and clear ADDR flag
971 let sr2 = self.info.regs.sr2().read();
972 let direction = if sr2.tra() {
973 SlaveCommandKind::Read
974 } else {
975 SlaveCommandKind::Write
976 };
977
978 // Use the static method instead of the instance method
979 let matched_address = Self::decode_matched_address(sr2, self.info)?;
980 trace!(
981 "I2C slave: address matched, direction={:?}, addr={:?}",
982 direction, matched_address
983 );
984
985 return Ok(SlaveCommand {
986 kind: direction,
987 address: matched_address,
988 });
989 }
990
991 timeout.check()?;
992 }
993 }
994
995 /// Transmit data to master in response to read request
996 fn transmit_to_master(&mut self, data: &[u8], timeout: Timeout) -> Result<usize, Error> {
997 let mut bytes_transmitted = 0;
998 let mut padding_count = 0;
999
1000 loop {
1001 let byte_to_send = if bytes_transmitted < data.len() {
1002 data[bytes_transmitted]
1003 } else {
1004 padding_count += 1;
1005 0x00 // Send padding bytes when data is exhausted
1006 };
1007
1008 match self.transmit_byte(byte_to_send, timeout)? {
1009 TransmitResult::Acknowledged => {
1010 bytes_transmitted += 1;
1011 }
1012 TransmitResult::NotAcknowledged => {
1013 bytes_transmitted += 1; // Count the NACKed byte
1014 break;
1015 }
1016 TransmitResult::Stopped | TransmitResult::Restarted => {
1017 break;
1018 }
1019 }
1020 }
1021
1022 if padding_count > 0 {
1023 trace!(
1024 "I2C slave: sent {} data bytes + {} padding bytes = {} total",
1025 data.len(),
1026 padding_count,
1027 bytes_transmitted
1028 );
1029 }
1030
1031 Ok(bytes_transmitted)
1032 }
1033
1034 /// Receive data from master during write request
1035 fn receive_from_master(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result<usize, Error> {
1036 let mut bytes_stored = 0;
1037
1038 // Receive bytes that fit in buffer
1039 while bytes_stored < buffer.len() {
1040 match self.receive_byte(timeout)? {
1041 ReceiveResult::Data(byte) => {
1042 buffer[bytes_stored] = byte;
1043 bytes_stored += 1;
1044 }
1045 ReceiveResult::Stopped | ReceiveResult::Restarted => {
1046 return Ok(bytes_stored);
1047 }
1048 }
1049 }
1050
1051 // Handle buffer overflow by discarding excess bytes
1052 if bytes_stored == buffer.len() {
1053 trace!("I2C slave: buffer full, discarding excess bytes");
1054 self.discard_excess_bytes(timeout)?;
1055 }
1056
1057 Ok(bytes_stored)
1058 }
1059
1060 /// Detect zero-length read pattern early
1061 ///
1062 /// Zero-length reads occur when a master sends START+ADDR+R followed immediately
1063 /// by NACK+STOP without wanting any data. This must be detected before attempting
1064 /// to transmit any bytes to avoid SDA line issues.
1065 fn detect_zero_length_read(&mut self, _timeout: Timeout) -> Result<Option<usize>, Error> {
1066 // Quick check for immediate termination signals
1067 let sr1 = self.info.regs.sr1().read();
1068
1069 // Check for immediate NACK (fastest zero-length pattern)
1070 if sr1.af() {
1071 self.clear_acknowledge_failure();
1072 return Ok(Some(0));
1073 }
1074
1075 // Check for immediate STOP (alternative zero-length pattern)
1076 if sr1.stopf() {
1077 Self::clear_stop_flag(self.info);
1078 return Ok(Some(0));
1079 }
1080
1081 // Give a brief window for master to send termination signals
1082 // This handles masters that have slight delays between address ACK and NACK
1083 const ZERO_LENGTH_DETECTION_CYCLES: u32 = 20; // ~5-10µs window
1084
1085 for _ in 0..ZERO_LENGTH_DETECTION_CYCLES {
1086 let sr1 = self.info.regs.sr1().read();
1087
1088 // Immediate NACK indicates zero-length read
1089 if sr1.af() {
1090 self.clear_acknowledge_failure();
1091 return Ok(Some(0));
1092 }
1093
1094 // Immediate STOP indicates zero-length read
1095 if sr1.stopf() {
1096 Self::clear_stop_flag(self.info);
1097 return Ok(Some(0));
1098 }
1099
1100 // If TXE becomes ready, master is waiting for data - not zero-length
1101 if sr1.txe() {
1102 return Ok(None); // Proceed with normal transmission
1103 }
1104
1105 // If RESTART detected, handle as zero-length
1106 if sr1.addr() {
1107 return Ok(Some(0));
1108 }
1109 }
1110
1111 // No zero-length pattern detected within the window
1112 Ok(None)
1113 }
1114
1115 /// Discard excess bytes when buffer is full
1116 fn discard_excess_bytes(&mut self, timeout: Timeout) -> Result<(), Error> {
1117 let mut discarded_count = 0;
1118
1119 loop {
1120 match self.receive_byte(timeout)? {
1121 ReceiveResult::Data(_) => {
1122 discarded_count += 1;
1123 continue;
1124 }
1125 ReceiveResult::Stopped | ReceiveResult::Restarted => {
1126 if discarded_count > 0 {
1127 trace!("I2C slave: discarded {} excess bytes", discarded_count);
1128 }
1129 break;
1130 }
1131 }
1132 }
1133 Ok(())
1134 }
1135
1136 /// Send a single byte and wait for master's response
1137 fn transmit_byte(&mut self, byte: u8, timeout: Timeout) -> Result<TransmitResult, Error> {
1138 // Wait for transmit buffer ready
1139 self.wait_for_transmit_ready(timeout)?;
1140
1141 // Send the byte
1142 self.info.regs.dr().write(|w| w.set_dr(byte));
1143
1144 // Wait for transmission completion or master response
1145 self.wait_for_transmit_completion(timeout)
1146 }
1147
1148 /// Wait until transmit buffer is ready (TXE flag set)
1149 fn wait_for_transmit_ready(&mut self, timeout: Timeout) -> Result<(), Error> {
1150 loop {
1151 let sr1 = Self::read_status_and_handle_errors(self.info)?;
1152
1153 // Check for early termination conditions
1154 if let Some(result) = Self::check_early_termination(sr1) {
1155 return Err(self.handle_early_termination(result));
1156 }
1157
1158 if sr1.txe() {
1159 return Ok(()); // Ready to transmit
1160 }
1161
1162 timeout.check()?;
1163 }
1164 }
1165
1166 /// Wait for byte transmission completion or master response
1167 fn wait_for_transmit_completion(&mut self, timeout: Timeout) -> Result<TransmitResult, Error> {
1168 loop {
1169 let sr1 = self.info.regs.sr1().read();
1170
1171 // Check flags in priority order
1172 if sr1.af() {
1173 self.clear_acknowledge_failure();
1174 return Ok(TransmitResult::NotAcknowledged);
1175 }
1176
1177 if sr1.btf() {
1178 return Ok(TransmitResult::Acknowledged);
1179 }
1180
1181 if sr1.stopf() {
1182 Self::clear_stop_flag(self.info);
1183 return Ok(TransmitResult::Stopped);
1184 }
1185
1186 if sr1.addr() {
1187 return Ok(TransmitResult::Restarted);
1188 }
1189
1190 // Check for other error conditions
1191 self.check_for_hardware_errors(sr1)?;
1192
1193 timeout.check()?;
1194 }
1195 }
1196
1197 /// Receive a single byte or detect transaction termination
1198 fn receive_byte(&mut self, timeout: Timeout) -> Result<ReceiveResult, Error> {
1199 loop {
1200 let sr1 = Self::read_status_and_handle_errors(self.info)?;
1201
1202 // Check for received data first (prioritize data over control signals)
1203 if sr1.rxne() {
1204 let byte = self.info.regs.dr().read().dr();
1205 return Ok(ReceiveResult::Data(byte));
1206 }
1207
1208 // Check for transaction termination
1209 if sr1.addr() {
1210 return Ok(ReceiveResult::Restarted);
1211 }
1212
1213 if sr1.stopf() {
1214 Self::clear_stop_flag(self.info);
1215 return Ok(ReceiveResult::Stopped);
1216 }
1217
1218 timeout.check()?;
1219 }
1220 }
1221
1222 /// Determine which slave address was matched based on SR2 flags
1223 fn decode_matched_address(sr2: i2c::regs::Sr2, info: &'static Info) -> Result<Address, Error> {
1224 if sr2.gencall() {
1225 Ok(Address::SevenBit(0x00)) // General call address
1226 } else if sr2.dualf() {
1227 // OA2 (secondary address) was matched
1228 let oar2 = info.regs.oar2().read();
1229 if oar2.endual() != i2c::vals::Endual::DUAL {
1230 return Err(Error::Bus); // Hardware inconsistency
1231 }
1232 Ok(Address::SevenBit(oar2.add2()))
1233 } else {
1234 // OA1 (primary address) was matched
1235 let oar1 = info.regs.oar1().read();
1236 match oar1.addmode() {
1237 i2c::vals::Addmode::BIT7 => {
1238 let addr = (oar1.add() >> 1) as u8;
1239 Ok(Address::SevenBit(addr))
1240 }
1241 i2c::vals::Addmode::BIT10 => Ok(Address::TenBit(oar1.add())),
1242 }
1243 }
1244 }
1245
1246 // Helper methods for hardware interaction
1247
1248 /// Read status register and handle I2C errors (except NACK in slave mode)
1249 fn read_status_and_handle_errors(info: &'static Info) -> Result<i2c::regs::Sr1, Error> {
1250 match Self::check_and_clear_error_flags(info) {
1251 Ok(sr1) => Ok(sr1),
1252 Err(Error::Nack) => {
1253 // In slave mode, NACK is normal protocol behavior, not an error
1254 Ok(info.regs.sr1().read())
1255 }
1256 Err(other_error) => Err(other_error),
1257 }
1258 }
1259
1260 /// Check for conditions that cause early termination of operations
1261 fn check_early_termination(sr1: i2c::regs::Sr1) -> Option<TransmitResult> {
1262 if sr1.stopf() {
1263 Some(TransmitResult::Stopped)
1264 } else if sr1.addr() {
1265 Some(TransmitResult::Restarted)
1266 } else if sr1.af() {
1267 Some(TransmitResult::NotAcknowledged)
1268 } else {
1269 None
1270 }
1271 }
1272
1273 /// Convert early termination to appropriate error
1274 fn handle_early_termination(&mut self, result: TransmitResult) -> Error {
1275 match result {
1276 TransmitResult::Stopped => {
1277 Self::clear_stop_flag(self.info);
1278 Error::Bus // Unexpected STOP during setup
1279 }
1280 TransmitResult::Restarted => {
1281 Error::Bus // Unexpected RESTART during setup
1282 }
1283 TransmitResult::NotAcknowledged => {
1284 self.clear_acknowledge_failure();
1285 Error::Bus // Unexpected NACK during setup
1286 }
1287 TransmitResult::Acknowledged => {
1288 unreachable!() // This should never be passed to this function
1289 }
1290 }
1291 }
1292
1293 /// Check for hardware-level I2C errors during transmission
1294 fn check_for_hardware_errors(&self, sr1: i2c::regs::Sr1) -> Result<(), Error> {
1295 if sr1.timeout() || sr1.ovr() || sr1.arlo() || sr1.berr() {
1296 // Delegate to existing error handling
1297 Self::check_and_clear_error_flags(self.info)?;
1298 }
1299 Ok(())
1300 }
1301
1302 /// Disable I2C event and error interrupts for blocking operations
1303 fn disable_i2c_interrupts(&mut self) {
1304 self.info.regs.cr2().modify(|w| {
1305 w.set_itevten(false);
1306 w.set_iterren(false);
1307 });
1308 }
1309
1310 /// Clear the acknowledge failure flag
1311 fn clear_acknowledge_failure(&mut self) {
1312 self.info.regs.sr1().write(|reg| {
1313 reg.0 = !0;
1314 reg.set_af(false);
1315 });
1316 }
1317
1318 /// Configure DMA settings for slave operations (shared between read/write)
1319 fn setup_slave_dma_base(&mut self) {
1320 self.info.regs.cr2().modify(|w| {
1321 w.set_itbufen(false); // Always disable buffer interrupts when using DMA
1322 w.set_dmaen(true); // Enable DMA requests
1323 w.set_last(false); // LAST bit not used in slave mode for v1 hardware
1324 });
1325 }
1326
1327 /// Disable DMA and interrupts in a critical section
1328 fn disable_dma_and_interrupts(info: &'static Info) {
1329 critical_section::with(|_| {
1330 info.regs.cr2().modify(|w| {
1331 w.set_dmaen(false);
1332 w.set_iterren(false);
1333 w.set_itevten(false);
1334 });
1335 });
1336 }
1337
1338 /// Check for early termination conditions during slave operations
1339 /// Returns Some(result) if termination detected, None to continue
1340 fn check_slave_termination_conditions(sr1: i2c::regs::Sr1) -> Option<SlaveTermination> {
1341 if sr1.stopf() {
1342 Some(SlaveTermination::Stop)
1343 } else if sr1.addr() {
1344 Some(SlaveTermination::Restart)
1345 } else if sr1.af() {
1346 Some(SlaveTermination::Nack)
1347 } else {
1348 None
1349 }
1350 }
1351}
1352
1353impl<'d> I2c<'d, Async, MultiMaster> {
1354 /// Async listen for incoming I2C messages using interrupts
1355 ///
1356 /// Waits for a master to address this slave and returns the command type
1357 /// (Read/Write) and the matched address. This method will suspend until
1358 /// an address match occurs.
1359 pub async fn listen(&mut self) -> Result<SlaveCommand, Error> {
1360 trace!("I2C slave: starting async listen for address match");
1361 let state = self.state;
1362 let info = self.info;
1363
1364 Self::enable_interrupts(info);
1365
1366 let on_drop = OnDrop::new(|| {
1367 Self::disable_dma_and_interrupts(info);
1368 });
1369
1370 let result = poll_fn(|cx| {
1371 state.waker.register(cx.waker());
1372
1373 match Self::check_and_clear_error_flags(info) {
1374 Err(e) => {
1375 error!("I2C slave: error during listen: {:?}", e);
1376 Poll::Ready(Err(e))
1377 }
1378 Ok(sr1) => {
1379 if sr1.addr() {
1380 let sr2 = info.regs.sr2().read();
1381 let direction = if sr2.tra() {
1382 SlaveCommandKind::Read
1383 } else {
1384 SlaveCommandKind::Write
1385 };
1386
1387 let matched_address = match Self::decode_matched_address(sr2, info) {
1388 Ok(addr) => {
1389 trace!("I2C slave: address matched, direction={:?}, addr={:?}", direction, addr);
1390 addr
1391 }
1392 Err(e) => {
1393 error!("I2C slave: failed to decode matched address: {:?}", e);
1394 return Poll::Ready(Err(e));
1395 }
1396 };
1397
1398 Poll::Ready(Ok(SlaveCommand {
1399 kind: direction,
1400 address: matched_address,
1401 }))
1402 } else {
1403 Self::enable_interrupts(info);
1404 Poll::Pending
1405 }
1406 }
1407 }
1408 })
1409 .await;
1410
1411 drop(on_drop);
1412 trace!("I2C slave: listen complete, result={:?}", result);
1413 result
1414 }
1415
1416 /// Async respond to write command using RX DMA
1417 ///
1418 /// Receives data from the master into the provided buffer using DMA.
1419 /// If the master sends more bytes than the buffer can hold, excess bytes
1420 /// are acknowledged but discarded to prevent interrupt flooding.
1421 ///
1422 /// Returns the number of bytes stored in the buffer (not total received).
1423 pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
1424 trace!("I2C slave: starting respond_to_write, buffer_len={}", buffer.len());
1425
1426 if buffer.is_empty() {
1427 warn!("I2C slave: respond_to_write called with empty buffer");
1428 return Err(Error::Overrun);
1429 }
1430
1431 let state = self.state;
1432 let info = self.info;
1433
1434 self.setup_slave_dma_base();
1435
1436 let on_drop = OnDrop::new(|| {
1437 Self::disable_dma_and_interrupts(info);
1438 });
1439
1440 info.regs.sr2().read();
1441
1442 let result = self.execute_slave_receive_transfer(buffer, state, info).await;
1443
1444 drop(on_drop);
1445 trace!("I2C slave: respond_to_write complete, result={:?}", result);
1446 result
1447 }
1448
1449 /// Async respond to read command using TX DMA
1450 ///
1451 /// Transmits data to the master using DMA. If the master requests more bytes
1452 /// than available in the data buffer, padding bytes (0x00) are sent until
1453 /// the master terminates the transaction with NACK, STOP, or RESTART.
1454 ///
1455 /// Returns the total number of bytes transmitted (data + padding).
1456 pub async fn respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> {
1457 trace!("I2C slave: starting respond_to_read, data_len={}", data.len());
1458
1459 if data.is_empty() {
1460 warn!("I2C slave: respond_to_read called with empty data");
1461 return Err(Error::Overrun);
1462 }
1463
1464 let state = self.state;
1465 let info = self.info;
1466
1467 self.setup_slave_dma_base();
1468
1469 let on_drop = OnDrop::new(|| {
1470 Self::disable_dma_and_interrupts(info);
1471 });
1472
1473 info.regs.sr2().read();
1474
1475 let result = self.execute_slave_transmit_transfer(data, state, info).await;
1476
1477 drop(on_drop);
1478 trace!("I2C slave: respond_to_read complete, result={:?}", result);
1479 result
1480 }
1481
1482 // === Private Transfer Execution Methods ===
1483
1484 /// Execute complete slave receive transfer with excess byte handling
1485 async fn execute_slave_receive_transfer(
1486 &mut self,
1487 buffer: &mut [u8],
1488 state: &'static State,
1489 info: &'static Info,
1490 ) -> Result<usize, Error> {
1491 let dma_transfer = unsafe {
1492 let src = info.regs.dr().as_ptr() as *mut u8;
1493 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
1494 };
1495
1496 let i2c_monitor =
1497 Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart]);
1498
1499 match select(dma_transfer, i2c_monitor).await {
1500 Either::Second(Err(e)) => {
1501 error!("I2C slave: error during receive transfer: {:?}", e);
1502 Self::disable_dma_and_interrupts(info);
1503 Err(e)
1504 }
1505 Either::First(_) => {
1506 trace!("I2C slave: DMA receive completed, handling excess bytes");
1507 Self::disable_dma_and_interrupts(info);
1508 self.handle_excess_bytes(state, info).await?;
1509 Ok(buffer.len())
1510 }
1511 Either::Second(Ok(termination)) => {
1512 trace!("I2C slave: receive terminated by I2C event: {:?}", termination);
1513 Self::disable_dma_and_interrupts(info);
1514 Ok(buffer.len())
1515 }
1516 }
1517 }
1518
1519 /// Execute complete slave transmit transfer with padding byte handling
1520 async fn execute_slave_transmit_transfer(
1521 &mut self,
1522 data: &[u8],
1523 state: &'static State,
1524 info: &'static Info,
1525 ) -> Result<usize, Error> {
1526 let dma_transfer = unsafe {
1527 let dst = info.regs.dr().as_ptr() as *mut u8;
1528 self.tx_dma.as_mut().unwrap().write(data, dst, Default::default())
1529 };
1530
1531 let i2c_monitor = Self::create_termination_monitor(
1532 state,
1533 info,
1534 &[
1535 SlaveTermination::Stop,
1536 SlaveTermination::Restart,
1537 SlaveTermination::Nack,
1538 ],
1539 );
1540
1541 match select(dma_transfer, i2c_monitor).await {
1542 Either::Second(Err(e)) => {
1543 error!("I2C slave: error during transmit transfer: {:?}", e);
1544 Self::disable_dma_and_interrupts(info);
1545 Err(e)
1546 }
1547 Either::First(_) => {
1548 trace!("I2C slave: DMA transmit completed, handling padding bytes");
1549 Self::disable_dma_and_interrupts(info);
1550 let padding_count = self.handle_padding_bytes(state, info).await?;
1551 let total_bytes = data.len() + padding_count;
1552 trace!(
1553 "I2C slave: sent {} data bytes + {} padding bytes = {} total",
1554 data.len(),
1555 padding_count,
1556 total_bytes
1557 );
1558 Ok(total_bytes)
1559 }
1560 Either::Second(Ok(termination)) => {
1561 trace!("I2C slave: transmit terminated by I2C event: {:?}", termination);
1562 Self::disable_dma_and_interrupts(info);
1563 Ok(data.len())
1564 }
1565 }
1566 }
1567
1568 /// Create a future that monitors for specific slave termination conditions
1569 fn create_termination_monitor(
1570 state: &'static State,
1571 info: &'static Info,
1572 allowed_terminations: &'static [SlaveTermination],
1573 ) -> impl Future<Output = Result<SlaveTermination, Error>> {
1574 poll_fn(move |cx| {
1575 state.waker.register(cx.waker());
1576
1577 match Self::check_and_clear_error_flags(info) {
1578 Err(Error::Nack) if allowed_terminations.contains(&SlaveTermination::Nack) => {
1579 Poll::Ready(Ok(SlaveTermination::Nack))
1580 }
1581 Err(e) => Poll::Ready(Err(e)),
1582 Ok(sr1) => {
1583 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1584 if allowed_terminations.contains(&termination) {
1585 // Handle the specific termination condition
1586 match termination {
1587 SlaveTermination::Stop => Self::clear_stop_flag(info),
1588 SlaveTermination::Nack => {
1589 info.regs.sr1().write(|reg| {
1590 reg.0 = !0;
1591 reg.set_af(false);
1592 });
1593 }
1594 SlaveTermination::Restart => {
1595 // ADDR flag will be handled by next listen() call
1596 }
1597 }
1598 Poll::Ready(Ok(termination))
1599 } else {
1600 // Unexpected termination condition
1601 Poll::Ready(Err(Error::Bus))
1602 }
1603 } else {
1604 Self::enable_interrupts(info);
1605 Poll::Pending
1606 }
1607 }
1608 }
1609 })
1610 }
1611
1612 /// Handle excess bytes after DMA buffer is full
1613 ///
1614 /// Reads and discards bytes until transaction termination to prevent interrupt flooding
1615 async fn handle_excess_bytes(&mut self, state: &'static State, info: &'static Info) -> Result<(), Error> {
1616 let mut discarded_count = 0;
1617
1618 poll_fn(|cx| {
1619 state.waker.register(cx.waker());
1620
1621 match Self::check_and_clear_error_flags(info) {
1622 Err(e) => {
1623 error!("I2C slave: error while discarding excess bytes: {:?}", e);
1624 Poll::Ready(Err(e))
1625 }
1626 Ok(sr1) => {
1627 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1628 match termination {
1629 SlaveTermination::Stop => Self::clear_stop_flag(info),
1630 SlaveTermination::Restart => {}
1631 SlaveTermination::Nack => unreachable!("NACK not expected during receive"),
1632 }
1633 if discarded_count > 0 {
1634 trace!("I2C slave: discarded {} excess bytes", discarded_count);
1635 }
1636 return Poll::Ready(Ok(()));
1637 }
1638
1639 if sr1.rxne() {
1640 let _discarded_byte = info.regs.dr().read().dr();
1641 discarded_count += 1;
1642 Self::enable_interrupts(info);
1643 return Poll::Pending;
1644 }
1645
1646 Self::enable_interrupts(info);
1647 Poll::Pending
1648 }
1649 }
1650 })
1651 .await
1652 }
1653
1654 /// Handle padding bytes after DMA data is exhausted
1655 ///
1656 /// Sends 0x00 bytes until transaction termination to prevent interrupt flooding
1657 async fn handle_padding_bytes(&mut self, state: &'static State, info: &'static Info) -> Result<usize, Error> {
1658 let mut padding_count = 0;
1659
1660 poll_fn(|cx| {
1661 state.waker.register(cx.waker());
1662
1663 match Self::check_and_clear_error_flags(info) {
1664 Err(Error::Nack) => Poll::Ready(Ok(padding_count)),
1665 Err(e) => {
1666 error!("I2C slave: error while sending padding bytes: {:?}", e);
1667 Poll::Ready(Err(e))
1668 }
1669 Ok(sr1) => {
1670 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1671 match termination {
1672 SlaveTermination::Stop => Self::clear_stop_flag(info),
1673 SlaveTermination::Restart => {}
1674 SlaveTermination::Nack => {
1675 info.regs.sr1().write(|reg| {
1676 reg.0 = !0;
1677 reg.set_af(false);
1678 });
1679 }
1680 }
1681 return Poll::Ready(Ok(padding_count));
1682 }
1683
1684 if sr1.txe() {
1685 info.regs.dr().write(|w| w.set_dr(0x00));
1686 padding_count += 1;
1687 Self::enable_interrupts(info);
1688 return Poll::Pending;
1689 }
1690
1691 Self::enable_interrupts(info);
1692 Poll::Pending
1693 }
1694 }
1695 })
1696 .await
1697 }
1698}
1699
1700/// Timing configuration for I2C v1 hardware
1701///
1702/// This struct encapsulates the complex timing calculations required for STM32 I2C v1
1703/// peripherals, which use three separate registers (CR2.FREQ, CCR, TRISE) instead of
1704/// the unified TIMINGR register found in v2 hardware.
732struct Timings { 1705struct Timings {
733 freq: u8, 1706 freq: u8, // APB frequency in MHz for CR2.FREQ register
734 mode: Mode, 1707 mode: Mode, // Standard or Fast mode selection
735 trise: u8, 1708 trise: u8, // Rise time compensation value
736 ccr: u16, 1709 ccr: u16, // Clock control register value
737 duty: Duty, 1710 duty: Duty, // Fast mode duty cycle selection
738} 1711}
739 1712
740impl Timings { 1713impl Timings {
@@ -771,14 +1744,10 @@ impl Timings {
771 duty = Duty::Duty2_1; 1744 duty = Duty::Duty2_1;
772 ccr = clock / (frequency * 3); 1745 ccr = clock / (frequency * 3);
773 ccr = if ccr < 1 { 1 } else { ccr }; 1746 ccr = if ccr < 1 { 1 } else { ccr };
774
775 // Set clock to fast mode with appropriate parameters for selected speed (2:1 duty cycle)
776 } else { 1747 } else {
777 duty = Duty::Duty16_9; 1748 duty = Duty::Duty16_9;
778 ccr = clock / (frequency * 25); 1749 ccr = clock / (frequency * 25);
779 ccr = if ccr < 1 { 1 } else { ccr }; 1750 ccr = if ccr < 1 { 1 } else { ccr };
780
781 // Set clock to fast mode with appropriate parameters for selected speed (16:9 duty cycle)
782 } 1751 }
783 } 1752 }
784 1753
@@ -788,11 +1757,6 @@ impl Timings {
788 ccr: ccr as u16, 1757 ccr: ccr as u16,
789 duty, 1758 duty,
790 mode, 1759 mode,
791 //prescale: presc_reg,
792 //scll,
793 //sclh,
794 //sdadel,
795 //scldel,
796 } 1760 }
797 } 1761 }
798} 1762}
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..5065bcdd8
--- /dev/null
+++ b/examples/stm32f4/src/bin/i2c_slave_async.rs
@@ -0,0 +1,135 @@
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::{error, info};
11use embassy_executor::Spawner;
12use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind};
13use embassy_stm32::time::Hertz;
14use embassy_stm32::{bind_interrupts, peripherals};
15use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
16use embassy_sync::mutex::Mutex;
17use embassy_time::{Duration, Timer};
18use {defmt_rtt as _, 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); // 100kHz I2C speed
38
39 // Initialize I2C as master first
40 let i2c_master = I2c::new(
41 p.I2C1, p.PB8, // SCL
42 p.PB9, // SDA
43 Irqs, p.DMA1_CH6, // TX DMA
44 p.DMA1_CH0, // RX DMA
45 i2c_config,
46 );
47
48 // Convert to MultiMaster 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::Async, i2c::mode::MultiMaster>) {
57 info!("Async I2C slave ready at address 0x{:02X}", I2C_SLAVE_ADDR);
58
59 loop {
60 match i2c_slave.listen().await {
61 Ok(SlaveCommand {
62 kind: SlaveCommandKind::Write,
63 address,
64 }) => {
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!(
77 "I2C: Data received - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}",
78 data_buffer[0],
79 data_buffer[1],
80 data_buffer[2],
81 data_buffer[3],
82 data_buffer[4],
83 data_buffer[5],
84 data_buffer[6],
85 data_buffer[7]
86 );
87 }
88 Err(e) => {
89 error!("I2C: Write error: {}", format_i2c_error(&e));
90 }
91 }
92 }
93
94 Ok(SlaveCommand {
95 kind: SlaveCommandKind::Read,
96 address,
97 }) => {
98 let addr_val = match address {
99 Address::SevenBit(addr) => addr,
100 Address::TenBit(addr) => (addr & 0xFF) as u8, // Show low byte for 10-bit
101 };
102
103 info!("I2C: Received read command - Address 0x{:02X}", addr_val);
104
105 let data_buffer = I2C_BUFFER.lock().await;
106
107 match i2c_slave.respond_to_read(&data_buffer[..BUFFER_SIZE]).await {
108 Ok(_) => {
109 info!("I2C: Responded to read command");
110 }
111 Err(e) => {
112 error!("I2C: Read error: {}", format_i2c_error(&e));
113 }
114 }
115 }
116
117 Err(e) => {
118 error!("I2C: Listen error: {}", format_i2c_error(&e));
119 Timer::after(Duration::from_millis(100)).await;
120 }
121 }
122 }
123}
124
125fn format_i2c_error(e: &embassy_stm32::i2c::Error) -> &'static str {
126 match e {
127 embassy_stm32::i2c::Error::Bus => "Bus",
128 embassy_stm32::i2c::Error::Arbitration => "Arbitration",
129 embassy_stm32::i2c::Error::Nack => "Nack",
130 embassy_stm32::i2c::Error::Timeout => "Timeout",
131 embassy_stm32::i2c::Error::Crc => "Crc",
132 embassy_stm32::i2c::Error::Overrun => "Overrun",
133 embassy_stm32::i2c::Error::ZeroLengthTransfer => "ZeroLengthTransfer",
134 }
135}
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..ee06d4ac4
--- /dev/null
+++ b/examples/stm32f4/src/bin/i2c_slave_blocking.rs
@@ -0,0 +1,132 @@
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::{error, info};
10use embassy_executor::Spawner;
11use embassy_stm32::i2c::{self, Address, I2c, SlaveAddrConfig, SlaveCommand, SlaveCommandKind};
12use embassy_stm32::time::Hertz;
13use embassy_stm32::{bind_interrupts, peripherals};
14use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
15use embassy_sync::mutex::Mutex;
16use embassy_time::{Duration, Timer};
17use {defmt_rtt as _, panic_probe as _};
18
19pub const I2C_SLAVE_ADDR: u8 = 0x42;
20pub const BUFFER_SIZE: usize = 8;
21static I2C_BUFFER: Mutex<ThreadModeRawMutex, [u8; BUFFER_SIZE]> = Mutex::new([0; BUFFER_SIZE]);
22
23bind_interrupts!(struct Irqs {
24 I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
25 I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
26});
27
28#[embassy_executor::main]
29async fn main(spawner: Spawner) {
30 let p = embassy_stm32::init(Default::default());
31
32 // Configure I2C
33 let mut i2c_config = i2c::Config::default();
34 i2c_config.sda_pullup = false;
35 i2c_config.scl_pullup = false;
36 i2c_config.frequency = Hertz(100_000);
37 i2c_config.timeout = embassy_time::Duration::from_millis(30000);
38
39 // Initialize I2C as master first
40 let i2c_master = I2c::new_blocking(
41 p.I2C1, p.PB8, // SCL
42 p.PB9, // SDA
43 i2c_config,
44 );
45
46 // Convert to slave+master mode
47 let slave_config = SlaveAddrConfig::basic(I2C_SLAVE_ADDR);
48 let i2c_slave = i2c_master.into_slave_multimaster(slave_config);
49
50 spawner.spawn(i2c_slave_task(i2c_slave).unwrap());
51}
52
53#[embassy_executor::task]
54pub async fn i2c_slave_task(mut i2c_slave: I2c<'static, embassy_stm32::mode::Blocking, i2c::mode::MultiMaster>) {
55 info!("Blocking I2C slave ready at address 0x{:02X}", I2C_SLAVE_ADDR);
56
57 loop {
58 match i2c_slave.blocking_listen() {
59 Ok(SlaveCommand {
60 kind: SlaveCommandKind::Write,
61 address,
62 }) => {
63 let addr_val = match address {
64 Address::SevenBit(addr) => addr,
65 Address::TenBit(addr) => (addr & 0xFF) as u8,
66 };
67
68 info!("I2C: Received write command - Address 0x{:02X}", addr_val);
69 let mut data_buffer = I2C_BUFFER.lock().await;
70
71 match i2c_slave.blocking_respond_to_write(&mut *data_buffer) {
72 Ok(bytes_received) => {
73 info!(
74 "I2C: Received {} bytes - Buffer now contains: 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}, 0x{:02X}",
75 bytes_received,
76 data_buffer[0],
77 data_buffer[1],
78 data_buffer[2],
79 data_buffer[3],
80 data_buffer[4],
81 data_buffer[5],
82 data_buffer[6],
83 data_buffer[7]
84 );
85 }
86 Err(e) => {
87 error!("I2C: Write error: {}", format_i2c_error(&e));
88 }
89 }
90 }
91
92 Ok(SlaveCommand {
93 kind: SlaveCommandKind::Read,
94 address,
95 }) => {
96 let addr_val = match address {
97 Address::SevenBit(addr) => addr,
98 Address::TenBit(addr) => (addr & 0xFF) as u8, // Show low byte for 10-bit
99 };
100
101 info!("I2C: Received read command - Address 0x{:02X}", addr_val);
102 let data_buffer = I2C_BUFFER.lock().await;
103
104 match i2c_slave.blocking_respond_to_read(&data_buffer[..BUFFER_SIZE]) {
105 Ok(bytes_sent) => {
106 info!("I2C: Responded to read - {} bytes sent", bytes_sent);
107 }
108 Err(e) => {
109 error!("I2C: Read error: {}", format_i2c_error(&e));
110 }
111 }
112 }
113
114 Err(e) => {
115 error!("I2C: Listen error: {}", format_i2c_error(&e));
116 Timer::after(Duration::from_millis(100)).await;
117 }
118 }
119 }
120}
121
122fn format_i2c_error(e: &embassy_stm32::i2c::Error) -> &'static str {
123 match e {
124 embassy_stm32::i2c::Error::Bus => "Bus",
125 embassy_stm32::i2c::Error::Arbitration => "Arbitration",
126 embassy_stm32::i2c::Error::Nack => "Nack",
127 embassy_stm32::i2c::Error::Timeout => "Timeout",
128 embassy_stm32::i2c::Error::Crc => "Crc",
129 embassy_stm32::i2c::Error::Overrun => "Overrun",
130 embassy_stm32::i2c::Error::ZeroLengthTransfer => "ZeroLengthTransfer",
131 }
132}