diff options
| author | HybridChild <[email protected]> | 2025-08-22 12:44:06 +0200 |
|---|---|---|
| committer | HybridChild <[email protected]> | 2025-08-23 08:53:48 +0200 |
| commit | a52497bd39701cd71a877a3d2bd264ae2dea716c (patch) | |
| tree | 1a7479eed16b2e1f37c9da71d2db59d769715f0f /embassy-stm32/src/i2c | |
| parent | 0ab366e28af266795106cb254b4a0d63f723d476 (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.rs | 153 |
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 | ||
