aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/i2c
diff options
context:
space:
mode:
authorHybridChild <[email protected]>2025-08-10 10:48:12 +0200
committerHybridChild <[email protected]>2025-08-23 08:53:48 +0200
commitd6d54392f15cb0430a50ba85e45d746aa09fc6ac (patch)
tree978509a8c4e63e7e6db2449837beec737a5ad6a1 /embassy-stm32/src/i2c
parent6570036f141befc76fd5f5237db0045c0b0f9a71 (diff)
stm32/i2c_v1: Fix bugs with slave address initialization and missing ACK bit
Diffstat (limited to 'embassy-stm32/src/i2c')
-rw-r--r--embassy-stm32/src/i2c/v1.rs128
1 files changed, 107 insertions, 21 deletions
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index 3aa003fa5..2bc309258 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -408,57 +408,97 @@ impl<'d, M: Mode> I2c<'d, M, Master> {
408} 408}
409 409
410impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { 410impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
411 /// Enhanced slave configuration with proper v1 address setup
411 pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) { 412 pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) {
412 trace!("i2c v1 slave init: config={:?}", config); 413 trace!("i2c v1 slave init: config={:?}", config);
414
413 // Disable peripheral for configuration 415 // Disable peripheral for configuration
414 self.info.regs.cr1().modify(|reg| { 416 self.info.regs.cr1().modify(|reg| {
415 reg.set_pe(false); 417 reg.set_pe(false);
416 }); 418 });
417 419
418 // Configure v1-specific slave settings 420 // Configure addresses with proper v1 format
419 self.configure_addresses(config); 421 self.configure_addresses(config);
420 422
421 // Enable slave mode interrupts and settings 423 // Configure general call if requested
422 self.info.regs.cr2().modify(|w| { 424 if config.general_call {
423 w.set_itevten(true); // Event interrupts 425 self.info.regs.cr1().modify(|w| w.set_engc(true));
424 w.set_iterren(true); // Error interrupts 426 trace!("i2c v1 slave: General call enabled");
425 }); 427 }
428
429 // Log final configuration before enabling
430 let cr1 = self.info.regs.cr1().read();
431 let oar1 = self.info.regs.oar1().read();
432 let oar2 = self.info.regs.oar2().read();
433 trace!("i2c v1 slave: Pre-enable state - CR1={:#x}, OAR1={:#x}, OAR2={:#x}",
434 cr1.0, oar1.0, oar2.0);
435 trace!("i2c v1 slave: Address details - OAR1.ADD={:#x}, OAR1.ADDMODE={}, bit14={}",
436 oar1.add(), oar1.addmode() as u8, (oar1.0 >> 14) & 1);
426 437
427 // Re-enable peripheral
428 self.info.regs.cr1().modify(|reg| { 438 self.info.regs.cr1().modify(|reg| {
429 reg.set_pe(true); 439 reg.set_pe(true); // Re-enable peripheral
440 reg.set_ack(true); // Critical for slave to ACK its address
430 }); 441 });
442
443 // Verify peripheral is enabled and ready
444 let cr1_final = self.info.regs.cr1().read();
445 trace!("i2c v1 slave: Final state - CR1={:#x}, PE={}", cr1_final.0, cr1_final.pe());
446
431 trace!("i2c v1 slave init complete"); 447 trace!("i2c v1 slave init complete");
432 } 448 }
433 449
434 fn configure_oa1(&mut self, addr: Address) { 450 fn configure_oa1(&mut self, addr: Address) {
435 match addr { 451 match addr {
436 Address::SevenBit(addr) => { 452 Address::SevenBit(addr) => {
453 trace!("i2c v1 slave: Setting OA1 7-bit address: input={:#x}", addr);
437 self.info.regs.oar1().write(|reg| { 454 self.info.regs.oar1().write(|reg| {
438 // v1 uses left-shifted 7-bit address in bits [7:1] 455 // For I2C v1, the 7-bit address goes in bits [7:1] of the ADD field
439 // STM32 reference manual says bits 7:1 for address, bit 0 don't care for 7-bit 456 // The ADD field spans bits [9:0], so we put the address in the correct position
440 reg.set_add((addr as u16) << 1); 457 let hw_addr = (addr as u16) << 1; // This puts address in bits [7:1], bit [0] = 0
458 reg.set_add(hw_addr);
441 reg.set_addmode(i2c::vals::Addmode::BIT7); 459 reg.set_addmode(i2c::vals::Addmode::BIT7);
442 }); 460 });
461
462 // CRITICAL: Set bit 14 as required by the reference manual
463 // "Bit 14: Should always be kept at 1 by software"
464 self.info.regs.oar1().modify(|reg| {
465 reg.0 |= 1 << 14; // Set bit 14
466 });
467
468 let oar1_verify = self.info.regs.oar1().read();
469 trace!("i2c v1 slave: OA1 configured - OAR1={:#x}, stored_addr={:#x}, bit14={}",
470 oar1_verify.0, oar1_verify.add(), (oar1_verify.0 >> 14) & 1);
443 }, 471 },
444 Address::TenBit(addr) => { 472 Address::TenBit(addr) => {
445 self.info.regs.oar1().modify(|reg| { 473 trace!("i2c v1 slave: Setting OA1 10-bit address: {:#x}", addr);
446 reg.set_add(addr); // Set address bits [9:0] 474 self.info.regs.oar1().write(|reg| {
475 reg.set_add(addr); // For 10-bit, full address goes in ADD field
447 reg.set_addmode(i2c::vals::Addmode::BIT10); 476 reg.set_addmode(i2c::vals::Addmode::BIT10);
448 // Manually set bit 14 as required by reference manual
449 reg.0 |= 1 << 14;
450 }); 477 });
478
479 // Set required bit 14 for 10-bit mode too
480 self.info.regs.oar1().modify(|reg| {
481 reg.0 |= 1 << 14; // Set bit 14
482 });
483
484 let oar1_verify = self.info.regs.oar1().read();
485 trace!("i2c v1 slave: OA1 10-bit configured - OAR1={:#x}, bit14={}",
486 oar1_verify.0, (oar1_verify.0 >> 14) & 1);
451 } 487 }
452 } 488 }
453 } 489 }
454 490
455 fn configure_oa2_simple(&mut self, addr: u8) { 491 fn configure_oa2_simple(&mut self, addr: u8) {
492 trace!("i2c v1 slave: Setting OA2 address: {:#x}", addr);
456 self.info.regs.oar2().write(|reg| { 493 self.info.regs.oar2().write(|reg| {
457 // v1 OA2: 7-bit address only, no masking support 494 // For OA2, the address goes in bits [7:1] of the ADD2 field
458 // Address goes in bits [7:1], enable dual addressing 495 reg.set_add2(addr); // ADD2 field automatically handles bits [7:1] placement
459 reg.set_add2(addr); 496 reg.set_endual(i2c::vals::Endual::DUAL); // Enable dual addressing
460 reg.set_endual(i2c::vals::Endual::DUAL);
461 }); 497 });
498
499 let oar2_verify = self.info.regs.oar2().read();
500 trace!("i2c v1 slave: OA2 configured - OAR2={:#x}, ADD2={:#x}, ENDUAL={}",
501 oar2_verify.0, oar2_verify.add2(), oar2_verify.endual() as u8);
462 } 502 }
463 503
464 fn configure_addresses(&mut self, config: SlaveAddrConfig) { 504 fn configure_addresses(&mut self, config: SlaveAddrConfig) {
@@ -507,6 +547,52 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
507 } 547 }
508} 548}
509 549
550// Also add a verification function to check address configuration
551impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
552 /// Verify the slave address configuration is correct
553 pub fn verify_slave_config(&self) -> Result<(), Error> {
554 let oar1 = self.info.regs.oar1().read();
555 let oar2 = self.info.regs.oar2().read();
556 let cr1 = self.info.regs.cr1().read();
557
558 info!("I2C v1 Slave Configuration Verification:");
559 info!(" CR1: {:#x} (PE={})", cr1.0, cr1.pe());
560 info!(" OAR1: {:#x}", oar1.0);
561 info!(" ADD: {:#x}", oar1.add());
562 info!(" ADDMODE: {} ({})", oar1.addmode() as u8,
563 if oar1.addmode() as u8 == 0 { "7-bit" } else { "10-bit" });
564 info!(" Bit 14: {}", (oar1.0 >> 14) & 1);
565 info!(" OAR2: {:#x}", oar2.0);
566 info!(" ADD2: {:#x}", oar2.add2());
567 info!(" ENDUAL: {} ({})", oar2.endual() as u8,
568 if oar2.endual() as u8 == 0 { "Single" } else { "Dual" });
569
570 // Check critical requirements
571 if !cr1.pe() {
572 error!("ERROR: I2C peripheral not enabled (PE=0)");
573 return Err(Error::Bus);
574 }
575
576 if (oar1.0 >> 14) & 1 == 0 {
577 error!("ERROR: OAR1 bit 14 not set (required by reference manual)");
578 return Err(Error::Bus);
579 }
580
581 // For 7-bit mode, verify address is in correct position
582 if oar1.addmode() as u8 == 0 { // 7-bit mode
583 let expected_addr = 0x42u16 << 1; // 0x84
584 if oar1.add() != expected_addr {
585 error!("ERROR: OAR1 address mismatch - expected {:#x}, got {:#x}",
586 expected_addr, oar1.add());
587 return Err(Error::Bus);
588 }
589 }
590
591 info!("✓ Slave configuration appears correct");
592 Ok(())
593 }
594}
595
510impl<'d, M: Mode> I2c<'d, M, MultiMaster> { 596impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
511 /// Listen for incoming I2C address match and return the command type 597 /// Listen for incoming I2C address match and return the command type
512 pub fn blocking_listen(&mut self) -> Result<SlaveCommand, Error> { 598 pub fn blocking_listen(&mut self) -> Result<SlaveCommand, Error> {