aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/i2c
diff options
context:
space:
mode:
authorHybridChild <[email protected]>2025-08-22 12:44:06 +0200
committerHybridChild <[email protected]>2025-08-23 08:53:48 +0200
commita52497bd39701cd71a877a3d2bd264ae2dea716c (patch)
tree1a7479eed16b2e1f37c9da71d2db59d769715f0f /embassy-stm32/src/i2c
parent0ab366e28af266795106cb254b4a0d63f723d476 (diff)
stm32/i2c_v1: Add handling of excess Write and Read from Master
Diffstat (limited to 'embassy-stm32/src/i2c')
-rw-r--r--embassy-stm32/src/i2c/v1.rs153
1 files changed, 129 insertions, 24 deletions
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index 10a307396..c37b48728 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -1414,41 +1414,85 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1414 1414
1415 trace!("I2C slave: starting select between DMA completion and I2C events"); 1415 trace!("I2C slave: starting select between DMA completion and I2C events");
1416 // Wait for either DMA completion or I2C termination condition (using master pattern) 1416 // Wait for either DMA completion or I2C termination condition (using master pattern)
1417 match select(dma_transfer, poll_error).await { 1417 let dma_result = match select(dma_transfer, poll_error).await {
1418 Either::Second(Err(e)) => { 1418 Either::Second(Err(e)) => {
1419 error!("I2C slave: I2C error occurred during write: {:?}", e); 1419 error!("I2C slave: I2C error occurred during write: {:?}", e);
1420 critical_section::with(|_| { 1420 critical_section::with(|_| {
1421 info.regs.cr2().modify(|w| w.set_dmaen(false)); 1421 info.regs.cr2().modify(|w| w.set_dmaen(false));
1422 }); 1422 });
1423 drop(on_drop); 1423 drop(on_drop);
1424 Err(e) 1424 return Err(e);
1425 } 1425 }
1426 Either::First(_) => { 1426 Either::First(_) => {
1427 trace!("I2C slave: DMA transfer completed first"); 1427 trace!("I2C slave: DMA transfer completed first - buffer full");
1428 critical_section::with(|_| { 1428 critical_section::with(|_| {
1429 info.regs.cr2().modify(|w| w.set_dmaen(false)); 1429 info.regs.cr2().modify(|w| w.set_dmaen(false));
1430 }); 1430 });
1431 drop(on_drop);
1432 1431
1433 // For v1 hardware, determining exact bytes received is complex 1432 // DMA completed but master might still be sending more bytes
1434 // Return the buffer length as an approximation 1433 // We need to discard any excess bytes until STOP/RESTART
1434 trace!("I2C slave: DMA complete, checking for excess bytes to discard");
1435
1436 let excess_discard = poll_fn(|cx| {
1437 state.waker.register(cx.waker());
1438
1439 match Self::check_and_clear_error_flags(info) {
1440 Err(e) => {
1441 error!("I2C slave: error while discarding excess bytes: {:?}", e);
1442 Poll::Ready(Err::<(), Error>(e))
1443 },
1444 Ok(sr1) => {
1445 // Check for transaction termination first
1446 if sr1.stopf() {
1447 trace!("I2C slave: STOP condition detected while discarding excess");
1448 Self::clear_stop_flag(info);
1449 return Poll::Ready(Ok(()));
1450 }
1451
1452 if sr1.addr() {
1453 trace!("I2C slave: RESTART condition detected while discarding excess");
1454 return Poll::Ready(Ok(()));
1455 }
1456
1457 // If there's data to read, read and discard it
1458 if sr1.rxne() {
1459 let discarded_byte = info.regs.dr().read().dr();
1460 trace!("I2C slave: discarded excess byte: 0x{:02X}", discarded_byte);
1461 // Continue polling for more bytes or termination
1462 Self::enable_interrupts(info);
1463 return Poll::Pending;
1464 }
1465
1466 // No immediate termination or data, keep waiting
1467 Self::enable_interrupts(info);
1468 Poll::Pending
1469 }
1470 }
1471 });
1472
1473 // Wait for transaction to actually end
1474 excess_discard.await?;
1475
1435 let bytes_received = buffer.len(); 1476 let bytes_received = buffer.len();
1436 trace!("I2C slave: write complete, returning {} bytes (buffer length)", bytes_received); 1477 trace!("I2C slave: write complete after discarding excess, returning {} bytes", bytes_received);
1478 drop(on_drop);
1437 Ok(bytes_received) 1479 Ok(bytes_received)
1438 } 1480 }
1439 Either::Second(Ok(())) => { 1481 Either::Second(Ok(())) => {
1440 trace!("I2C slave: I2C event (STOP/RESTART) occurred first"); 1482 trace!("I2C slave: I2C event (STOP/RESTART) occurred before DMA completion");
1441 critical_section::with(|_| { 1483 critical_section::with(|_| {
1442 info.regs.cr2().modify(|w| w.set_dmaen(false)); 1484 info.regs.cr2().modify(|w| w.set_dmaen(false));
1443 }); 1485 });
1444 drop(on_drop);
1445 1486
1446 // Transaction ended normally, return buffer length 1487 // Transaction ended normally before buffer was full
1447 let bytes_received = buffer.len(); 1488 let bytes_received = buffer.len();
1448 trace!("I2C slave: write complete via I2C event, returning {} bytes", bytes_received); 1489 trace!("I2C slave: write complete via early I2C event, returning {} bytes", bytes_received);
1490 drop(on_drop);
1449 Ok(bytes_received) 1491 Ok(bytes_received)
1450 } 1492 }
1451 } 1493 };
1494
1495 dma_result
1452 } 1496 }
1453 1497
1454 /// Async respond to read command using TX DMA 1498 /// Async respond to read command using TX DMA
@@ -1533,40 +1577,101 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1533 1577
1534 trace!("I2C slave: starting select between DMA completion and I2C events"); 1578 trace!("I2C slave: starting select between DMA completion and I2C events");
1535 // Wait for either DMA completion or I2C termination (using master pattern) 1579 // Wait for either DMA completion or I2C termination (using master pattern)
1536 match select(dma_transfer, poll_completion).await { 1580 let dma_result = match select(dma_transfer, poll_completion).await {
1537 Either::Second(Err(e)) => { 1581 Either::Second(Err(e)) => {
1538 error!("I2C slave: I2C error occurred during read: {:?}", e); 1582 error!("I2C slave: I2C error occurred during read: {:?}", e);
1539 critical_section::with(|_| { 1583 critical_section::with(|_| {
1540 info.regs.cr2().modify(|w| w.set_dmaen(false)); 1584 info.regs.cr2().modify(|w| w.set_dmaen(false));
1541 }); 1585 });
1542 drop(on_drop); 1586 drop(on_drop);
1543 Err(e) 1587 return Err(e);
1544 } 1588 }
1545 Either::First(_) => { 1589 Either::First(_) => {
1546 trace!("I2C slave: DMA transfer completed first - all data sent"); 1590 trace!("I2C slave: DMA transfer completed first - all data sent");
1547 critical_section::with(|_| { 1591 critical_section::with(|_| {
1548 info.regs.cr2().modify(|w| w.set_dmaen(false)); 1592 info.regs.cr2().modify(|w| w.set_dmaen(false));
1549 }); 1593 });
1550 drop(on_drop);
1551 1594
1552 let bytes_sent = data.len(); 1595 // DMA completed but master might still be requesting more bytes
1553 trace!("I2C slave: read complete via DMA, sent {} bytes", bytes_sent); 1596 // We need to send padding bytes (0x00) until NACK/STOP/RESTART
1554 Ok(bytes_sent) 1597 trace!("I2C slave: DMA complete, entering padding phase");
1598 let mut padding_bytes_sent = 0;
1599
1600 let padding_phase = poll_fn(|cx| {
1601 state.waker.register(cx.waker());
1602
1603 match Self::check_and_clear_error_flags(info) {
1604 Err(Error::Nack) => {
1605 trace!("I2C slave: NACK received during padding - normal end");
1606 return Poll::Ready(Ok(()));
1607 },
1608 Err(e) => {
1609 error!("I2C slave: error while sending padding bytes: {:?}", e);
1610 return Poll::Ready(Err::<(), Error>(e));
1611 },
1612 Ok(sr1) => {
1613 // Check for transaction termination first
1614 if sr1.af() {
1615 trace!("I2C slave: acknowledge failure during padding - normal end");
1616 info.regs.sr1().write(|reg| {
1617 reg.0 = !0;
1618 reg.set_af(false);
1619 });
1620 return Poll::Ready(Ok(()));
1621 }
1622
1623 if sr1.stopf() {
1624 trace!("I2C slave: STOP condition detected during padding");
1625 Self::clear_stop_flag(info);
1626 return Poll::Ready(Ok(()));
1627 }
1628
1629 if sr1.addr() {
1630 trace!("I2C slave: RESTART condition detected during padding");
1631 return Poll::Ready(Ok(()));
1632 }
1633
1634 // If transmit buffer is empty, send a padding byte
1635 if sr1.txe() {
1636 info.regs.dr().write(|w| w.set_dr(0x00));
1637 padding_bytes_sent += 1;
1638 trace!("I2C slave: sent padding byte #{}", padding_bytes_sent);
1639 // Continue padding until transaction ends
1640 Self::enable_interrupts(info);
1641 return Poll::Pending;
1642 }
1643
1644 // No immediate termination or transmit request, keep waiting
1645 Self::enable_interrupts(info);
1646 Poll::Pending
1647 }
1648 }
1649 });
1650
1651 // Wait for transaction to actually end
1652 padding_phase.await?;
1653
1654 let total_bytes_sent = data.len() + padding_bytes_sent;
1655 trace!("I2C slave: read complete after sending {} padding bytes, total {} bytes sent",
1656 padding_bytes_sent, total_bytes_sent);
1657 drop(on_drop);
1658 Ok(total_bytes_sent)
1555 } 1659 }
1556 Either::Second(Ok(())) => { 1660 Either::Second(Ok(())) => {
1557 trace!("I2C slave: I2C event (STOP/NACK/RESTART) occurred first"); 1661 trace!("I2C slave: I2C event (STOP/NACK/RESTART) occurred before DMA completion");
1558 critical_section::with(|_| { 1662 critical_section::with(|_| {
1559 info.regs.cr2().modify(|w| w.set_dmaen(false)); 1663 info.regs.cr2().modify(|w| w.set_dmaen(false));
1560 }); 1664 });
1561 drop(on_drop);
1562 1665
1563 // For slave read, we can't easily determine exact bytes sent in v1 1666 // Transaction ended normally before all data was sent
1564 // Return the full data length if no error occurred
1565 let bytes_sent = data.len(); 1667 let bytes_sent = data.len();
1566 trace!("I2C slave: read complete via I2C event, reporting {} bytes sent", bytes_sent); 1668 trace!("I2C slave: read complete via early I2C event, sent {} bytes", bytes_sent);
1669 drop(on_drop);
1567 Ok(bytes_sent) 1670 Ok(bytes_sent)
1568 } 1671 }
1569 } 1672 };
1673
1674 dma_result
1570 } 1675 }
1571} 1676}
1572 1677