diff options
| -rw-r--r-- | embassy-stm32/src/i2c/v1.rs | 128 |
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 | ||
| 410 | impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | 410 | impl<'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 | ||
| 551 | impl<'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 | |||
| 510 | impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | 596 | impl<'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> { |
