aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/i2c
diff options
context:
space:
mode:
authorHybridChild <[email protected]>2025-08-10 08:31:35 +0200
committerHybridChild <[email protected]>2025-08-23 08:52:03 +0200
commitb88c5195e030b6fac129ea9cb74eb169227f7335 (patch)
tree73b7e9c87fa2f9bae64e6de6b0fbc71ee95f6a6b /embassy-stm32/src/i2c
parentc531af42c8dd2eaeb56ef1891396ac559918560e (diff)
stm32/i2c_v1: Add MultiMaster (Slave) mode implementation
Diffstat (limited to 'embassy-stm32/src/i2c')
-rw-r--r--embassy-stm32/src/i2c/v1.rs341
1 files changed, 341 insertions, 0 deletions
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index f2fd0147e..7b6ecf869 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -32,6 +32,21 @@ impl State {
32 } 32 }
33} 33}
34 34
35#[derive(Debug, PartialEq)]
36enum SlaveSendResult {
37 Acked, // Byte sent and ACK received from master
38 Nacked, // Byte sent but NACK received (normal end of transmission)
39 Stopped, // STOP condition detected
40 Restart, // RESTART condition detected
41}
42
43#[derive(Debug, PartialEq)]
44enum SlaveReceiveResult {
45 Byte(u8), // Data byte received
46 Stop, // STOP condition detected
47 Restart, // RESTART condition (new ADDR) detected
48}
49
35// /!\ /!\ 50// /!\ /!\
36// /!\ Implementation note! /!\ 51// /!\ Implementation note! /!\
37// /!\ /!\ 52// /!\ /!\
@@ -370,6 +385,332 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
370 } 385 }
371} 386}
372 387
388impl<'d, M: Mode> I2c<'d, M, Master> {
389 /// Configure the I2C driver for slave operations, allowing for the driver to be used as a slave and a master (multimaster)
390 pub fn into_slave_multimaster(mut self, slave_addr_config: SlaveAddrConfig) -> I2c<'d, M, MultiMaster> {
391 let mut slave = I2c {
392 info: self.info,
393 state: self.state,
394 kernel_clock: self.kernel_clock,
395 tx_dma: self.tx_dma.take(), // Use take() to move ownership
396 rx_dma: self.rx_dma.take(), // Use take() to move ownership
397 #[cfg(feature = "time")]
398 timeout: self.timeout,
399 _phantom: PhantomData,
400 _phantom2: PhantomData,
401 _drop_guard: self._drop_guard, // Move the drop guard
402 };
403 slave.init_slave(slave_addr_config);
404 slave
405 }
406}
407
408impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
409 pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) {
410 // Disable peripheral for configuration
411 self.info.regs.cr1().modify(|reg| {
412 reg.set_pe(false);
413 });
414
415 // Configure v1-specific slave settings
416 self.configure_addresses(config);
417
418 // Enable slave mode interrupts and settings
419 self.info.regs.cr2().modify(|w| {
420 w.set_itevten(true); // Event interrupts
421 w.set_iterren(true); // Error interrupts
422 });
423
424 // Re-enable peripheral
425 self.info.regs.cr1().modify(|reg| {
426 reg.set_pe(true);
427 });
428 }
429
430 fn configure_oa1(&mut self, addr: Address) {
431 match addr {
432 Address::SevenBit(addr) => {
433 self.info.regs.oar1().write(|reg| {
434 // v1 uses left-shifted 7-bit address in bits [7:1]
435 // STM32 reference manual says bits 7:1 for address, bit 0 don't care for 7-bit
436 reg.set_add((addr as u16) << 1);
437 reg.set_addmode(i2c::vals::Addmode::BIT7);
438 });
439 },
440 Address::TenBit(addr) => {
441 self.info.regs.oar1().modify(|reg| {
442 reg.set_add(addr); // Set address bits [9:0]
443 reg.set_addmode(i2c::vals::Addmode::BIT10);
444 // Manually set bit 14 as required by reference manual
445 reg.0 |= 1 << 14;
446 });
447 }
448 }
449 }
450
451 fn configure_oa2_simple(&mut self, addr: u8) {
452 self.info.regs.oar2().write(|reg| {
453 // v1 OA2: 7-bit address only, no masking support
454 // Address goes in bits [7:1], enable dual addressing
455 reg.set_add2(addr);
456 reg.set_endual(i2c::vals::Endual::DUAL);
457 });
458 }
459
460 fn configure_addresses(&mut self, config: SlaveAddrConfig) {
461 match config.addr {
462 OwnAddresses::OA1(addr) => {
463 self.configure_oa1(addr);
464 // Disable OA2 if not needed
465 self.info.regs.oar2().write(|reg| {
466 reg.set_endual(i2c::vals::Endual::SINGLE);
467 });
468 },
469 OwnAddresses::OA2(oa2) => {
470 // v1 limitation: ignore mask, only support simple OA2
471 if !matches!(oa2.mask, AddrMask::NOMASK) {
472 // Could log a warning here that masking is ignored in v1
473 #[cfg(feature = "defmt")]
474 defmt::warn!("I2C v1 does not support OA2 address masking, ignoring mask setting");
475 }
476
477 // Must have a default OA1 when using OA2-only mode
478 // Set OA1 to a reserved address that won't conflict
479 self.info.regs.oar1().write(|reg| {
480 reg.set_add(0); // Address 0x00 is reserved, safe to use
481 reg.set_addmode(i2c::vals::Addmode::BIT7);
482 });
483
484 self.configure_oa2_simple(oa2.addr);
485 },
486 OwnAddresses::Both { oa1, oa2 } => {
487 self.configure_oa1(oa1);
488
489 // Same masking limitation applies
490 if !matches!(oa2.mask, AddrMask::NOMASK) {
491 #[cfg(feature = "defmt")]
492 defmt::warn!("I2C v1 does not support OA2 address masking, ignoring mask setting");
493 }
494
495 self.configure_oa2_simple(oa2.addr);
496 }
497 }
498
499 // Configure general call if requested
500 if config.general_call {
501 self.info.regs.cr1().modify(|w| w.set_engc(true));
502 }
503 }
504}
505
506impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
507 /// Listen for incoming I2C address match and return the command type
508 pub fn blocking_listen(&mut self) -> Result<SlaveCommand, Error> {
509 let timeout = self.timeout(); // Get timeout internally
510 self.blocking_listen_timeout(timeout)
511 }
512
513 /// Respond to master read request (master wants to read from us)
514 pub fn blocking_respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> {
515 let timeout = self.timeout(); // Get timeout internally
516 self.blocking_respond_to_read_timeout(data, timeout)
517 }
518
519 /// Respond to master write request (master wants to write to us)
520 pub fn blocking_respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
521 let timeout = self.timeout(); // Get timeout internally
522 self.blocking_respond_to_write_timeout(buffer, timeout)
523 }
524
525 // Private implementation methods with Timeout parameter
526 fn blocking_listen_timeout(&mut self, timeout: Timeout) -> Result<SlaveCommand, Error> {
527 // Enable address match interrupt for slave mode
528 self.info.regs.cr2().modify(|w| {
529 w.set_itevten(true); // Enable event interrupts
530 });
531
532 // Wait for address match (ADDR flag)
533 loop {
534 let sr1 = Self::check_and_clear_error_flags(self.info)?;
535
536 if sr1.addr() {
537 // Address matched! Read SR2 to get direction and clear ADDR
538 let sr2 = self.info.regs.sr2().read();
539 let direction = if sr2.tra() {
540 SlaveCommandKind::Read // Master wants to read from us (we transmit)
541 } else {
542 SlaveCommandKind::Write // Master wants to write to us (we receive)
543 };
544
545 // Determine which address was matched
546 let matched_address = self.determine_matched_address(sr2)?;
547
548 // ADDR is automatically cleared by reading SR1 then SR2
549 return Ok(SlaveCommand {
550 kind: direction,
551 address: matched_address,
552 });
553 }
554
555 timeout.check()?;
556 }
557 }
558
559 fn blocking_respond_to_read_timeout(&mut self, data: &[u8], timeout: Timeout) -> Result<usize, Error> {
560 let mut bytes_sent = 0;
561
562 for &byte in data {
563 match self.send_byte_or_nack(byte, timeout)? {
564 SlaveSendResult::Acked => {
565 bytes_sent += 1;
566 // Continue sending
567 },
568 SlaveSendResult::Nacked | SlaveSendResult::Stopped => {
569 // Master finished reading or sent STOP
570 break;
571 }
572 SlaveSendResult::Restart => {
573 // Master wants to change direction (rare but possible)
574 break;
575 }
576 }
577 }
578
579 Ok(bytes_sent)
580 }
581
582 fn blocking_respond_to_write_timeout(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result<usize, Error> {
583 let mut bytes_received = 0;
584 while bytes_received < buffer.len() {
585 match self.recv_byte_or_stop(timeout)? {
586 SlaveReceiveResult::Byte(b) => {
587 buffer[bytes_received] = b;
588 bytes_received += 1;
589 },
590 SlaveReceiveResult::Stop => break,
591 SlaveReceiveResult::Restart => break,
592 }
593 }
594 Ok(bytes_received)
595 }
596
597 fn determine_matched_address(&self, sr2: stm32_metapac::i2c::regs::Sr2) -> Result<Address, Error> {
598 // Check for general call first
599 if sr2.gencall() {
600 Ok(Address::SevenBit(0x00))
601 } else if sr2.dualf() {
602 // OA2 was matched - verify it's actually enabled
603 let oar2 = self.info.regs.oar2().read();
604 if oar2.endual() != i2c::vals::Endual::DUAL {
605 return Err(Error::Bus); // Hardware inconsistency
606 }
607 Ok(Address::SevenBit(oar2.add2()))
608 } else {
609 // OA1 was matched
610 let oar1 = self.info.regs.oar1().read();
611 match oar1.addmode() {
612 i2c::vals::Addmode::BIT7 => {
613 Ok(Address::SevenBit((oar1.add() >> 1) as u8))
614 },
615 i2c::vals::Addmode::BIT10 => {
616 Ok(Address::TenBit(oar1.add()))
617 },
618 }
619 }
620 }
621
622 /// Send a byte in slave transmitter mode and check for ACK/NACK/STOP
623 fn send_byte_or_nack(&mut self, byte: u8, timeout: Timeout) -> Result<SlaveSendResult, Error> {
624 // Wait until we're ready for sending (TXE flag set)
625 loop {
626 let sr1 = Self::check_and_clear_error_flags(self.info)?;
627
628 // Check for STOP condition first
629 if sr1.stopf() {
630 self.info.regs.cr1().modify(|_w| {});
631 return Ok(SlaveSendResult::Stopped);
632 }
633
634 // Check for RESTART (new ADDR)
635 if sr1.addr() {
636 // Don't clear ADDR here - let next blocking_listen() handle it
637 return Ok(SlaveSendResult::Restart);
638 }
639
640 // Check for NACK (AF flag)
641 if sr1.af() {
642 self.info.regs.sr1().modify(|w| w.set_af(false));
643 return Ok(SlaveSendResult::Nacked);
644 }
645
646 // Check if we can send data
647 if sr1.txe() {
648 break; // Ready to send
649 }
650
651 timeout.check()?;
652 }
653
654 // Send the byte
655 self.info.regs.dr().write(|w| w.set_dr(byte));
656
657 // Wait for byte transfer to complete (BTF flag or error)
658 loop {
659 let sr1 = Self::check_and_clear_error_flags(self.info)?;
660
661 // Check for STOP condition
662 if sr1.stopf() {
663 self.info.regs.cr1().modify(|_w| {});
664 return Ok(SlaveSendResult::Stopped);
665 }
666
667 // Check for RESTART (new ADDR)
668 if sr1.addr() {
669 return Ok(SlaveSendResult::Restart);
670 }
671
672 // Check for NACK (AF flag)
673 if sr1.af() {
674 self.info.regs.sr1().modify(|w| w.set_af(false));
675 return Ok(SlaveSendResult::Nacked);
676 }
677
678 // Check for byte transfer finished
679 if sr1.btf() {
680 return Ok(SlaveSendResult::Acked);
681 }
682
683 timeout.check()?;
684 }
685 }
686
687 /// Receive a byte in slave receiver mode or detect STOP condition
688 fn recv_byte_or_stop(&mut self, timeout: Timeout) -> Result<SlaveReceiveResult, Error> {
689 loop {
690 let sr1 = Self::check_and_clear_error_flags(self.info)?;
691
692 // Check for STOP condition first
693 if sr1.stopf() {
694 self.info.regs.cr1().modify(|_w| {});
695 return Ok(SlaveReceiveResult::Stop);
696 }
697
698 // Check for RESTART (new ADDR)
699 if sr1.addr() {
700 // Don't clear ADDR here - let next blocking_listen() handle it
701 return Ok(SlaveReceiveResult::Restart);
702 }
703
704 if sr1.rxne() {
705 let byte = self.info.regs.dr().read().dr();
706 return Ok(SlaveReceiveResult::Byte(byte));
707 }
708
709 timeout.check()?;
710 }
711 }
712}
713
373impl<'d, IM: MasterMode> I2c<'d, Async, IM> { 714impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
374 async fn write_with_framing(&mut self, address: u8, write_buffer: &[u8], framing: OperationFraming) -> Result<(), Error> { 715 async fn write_with_framing(&mut self, address: u8, write_buffer: &[u8], framing: OperationFraming) -> Result<(), Error> {
375 self.info.regs.cr2().modify(|w| { 716 self.info.regs.cr2().modify(|w| {