aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHybridChild <[email protected]>2025-08-22 13:18:52 +0200
committerHybridChild <[email protected]>2025-08-23 08:53:48 +0200
commit8111bbc54594706d26d02a22ad8f1853317d3495 (patch)
treed0c29bf6307cf7b04bb25da889dfba3bf9e9b663
parenta52497bd39701cd71a877a3d2bd264ae2dea716c (diff)
stm32/i2c_v1: Clean up Async MultiMaster implementation
-rw-r--r--embassy-stm32/src/i2c/v1.rs732
1 files changed, 340 insertions, 392 deletions
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index c37b48728..0f2953ef6 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -758,6 +758,17 @@ enum ReceiveResult {
758 Restarted, 758 Restarted,
759} 759}
760 760
761/// Enumeration of slave transaction termination conditions
762#[derive(Debug, Clone, Copy, PartialEq)]
763enum SlaveTermination {
764 /// STOP condition received - normal end of transaction
765 Stop,
766 /// RESTART condition received - master starting new transaction
767 Restart,
768 /// NACK received - normal end of read transaction
769 Nack,
770}
771
761impl<'d, M: Mode> I2c<'d, M, Master> { 772impl<'d, M: Mode> I2c<'d, M, Master> {
762 /// Configure the I2C driver for slave operations, allowing for the driver to be used as a slave and a master (multimaster) 773 /// Configure the I2C driver for slave operations, allowing for the driver to be used as a slave and a master (multimaster)
763 pub fn into_slave_multimaster(mut self, slave_addr_config: SlaveAddrConfig) -> I2c<'d, M, MultiMaster> { 774 pub fn into_slave_multimaster(mut self, slave_addr_config: SlaveAddrConfig) -> I2c<'d, M, MultiMaster> {
@@ -778,6 +789,98 @@ impl<'d, M: Mode> I2c<'d, M, Master> {
778 } 789 }
779} 790}
780 791
792// Address configuration methods
793impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
794 /// Initialize slave mode with address configuration
795 pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) {
796 trace!("I2C slave: initializing with config={:?}", config);
797
798 // Disable peripheral for configuration
799 self.info.regs.cr1().modify(|reg| reg.set_pe(false));
800
801 // Configure slave addresses
802 self.apply_address_configuration(config);
803
804 // Enable peripheral with slave settings
805 self.info.regs.cr1().modify(|reg| {
806 reg.set_pe(true);
807 reg.set_ack(true); // Enable acknowledgment for slave mode
808 reg.set_nostretch(false); // Allow clock stretching for processing time
809 });
810
811 trace!("I2C slave: initialization complete");
812 }
813
814 /// Apply the complete address configuration for slave mode
815 fn apply_address_configuration(&mut self, config: SlaveAddrConfig) {
816 match config.addr {
817 OwnAddresses::OA1(addr) => {
818 self.configure_primary_address(addr);
819 self.disable_secondary_address();
820 },
821 OwnAddresses::OA2(oa2) => {
822 self.configure_default_primary_address();
823 self.configure_secondary_address(oa2.addr); // v1 ignores mask
824 },
825 OwnAddresses::Both { oa1, oa2 } => {
826 self.configure_primary_address(oa1);
827 self.configure_secondary_address(oa2.addr); // v1 ignores mask
828 }
829 }
830
831 // Configure general call detection
832 if config.general_call {
833 self.info.regs.cr1().modify(|w| w.set_engc(true));
834 }
835 }
836
837 /// Configure the primary address (OA1) register
838 fn configure_primary_address(&mut self, addr: Address) {
839 match addr {
840 Address::SevenBit(addr) => {
841 self.info.regs.oar1().write(|reg| {
842 let hw_addr = (addr as u16) << 1; // Address in bits [7:1]
843 reg.set_add(hw_addr);
844 reg.set_addmode(i2c::vals::Addmode::BIT7);
845 });
846 },
847 Address::TenBit(addr) => {
848 self.info.regs.oar1().write(|reg| {
849 reg.set_add(addr);
850 reg.set_addmode(i2c::vals::Addmode::BIT10);
851 });
852 }
853 }
854
855 // Set required bit 14 as per reference manual
856 self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14);
857 }
858
859 /// Configure the secondary address (OA2) register
860 fn configure_secondary_address(&mut self, addr: u8) {
861 self.info.regs.oar2().write(|reg| {
862 reg.set_add2(addr);
863 reg.set_endual(i2c::vals::Endual::DUAL);
864 });
865 }
866
867 /// Set a default primary address when using OA2-only mode
868 fn configure_default_primary_address(&mut self) {
869 self.info.regs.oar1().write(|reg| {
870 reg.set_add(0); // Reserved address, safe to use
871 reg.set_addmode(i2c::vals::Addmode::BIT7);
872 });
873 self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14);
874 }
875
876 /// Disable secondary address when not needed
877 fn disable_secondary_address(&mut self) {
878 self.info.regs.oar2().write(|reg| {
879 reg.set_endual(i2c::vals::Endual::SINGLE);
880 });
881 }
882}
883
781impl<'d, M: Mode> I2c<'d, M, MultiMaster> { 884impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
782 /// Listen for incoming I2C address match and return the command type 885 /// Listen for incoming I2C address match and return the command type
783 /// 886 ///
@@ -1170,165 +1273,85 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
1170 reg.set_af(false); 1273 reg.set_af(false);
1171 }); 1274 });
1172 } 1275 }
1173}
1174 1276
1175// Address configuration methods 1277 /// Configure DMA settings for slave operations (shared between read/write)
1176impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { 1278 fn setup_slave_dma_base(&mut self) {
1177 /// Initialize slave mode with address configuration 1279 self.info.regs.cr2().modify(|w| {
1178 pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) { 1280 w.set_itbufen(false); // Always disable buffer interrupts when using DMA
1179 trace!("I2C slave: initializing with config={:?}", config); 1281 w.set_dmaen(true); // Enable DMA requests
1180 1282 w.set_last(false); // LAST bit not used in slave mode for v1 hardware
1181 // Disable peripheral for configuration
1182 self.info.regs.cr1().modify(|reg| reg.set_pe(false));
1183
1184 // Configure slave addresses
1185 self.apply_address_configuration(config);
1186
1187 // Enable peripheral with slave settings
1188 self.info.regs.cr1().modify(|reg| {
1189 reg.set_pe(true);
1190 reg.set_ack(true); // Enable acknowledgment for slave mode
1191 reg.set_nostretch(false); // Allow clock stretching for processing time
1192 });
1193
1194 trace!("I2C slave: initialization complete");
1195 }
1196
1197 /// Apply the complete address configuration for slave mode
1198 fn apply_address_configuration(&mut self, config: SlaveAddrConfig) {
1199 match config.addr {
1200 OwnAddresses::OA1(addr) => {
1201 self.configure_primary_address(addr);
1202 self.disable_secondary_address();
1203 },
1204 OwnAddresses::OA2(oa2) => {
1205 self.configure_default_primary_address();
1206 self.configure_secondary_address(oa2.addr); // v1 ignores mask
1207 },
1208 OwnAddresses::Both { oa1, oa2 } => {
1209 self.configure_primary_address(oa1);
1210 self.configure_secondary_address(oa2.addr); // v1 ignores mask
1211 }
1212 }
1213
1214 // Configure general call detection
1215 if config.general_call {
1216 self.info.regs.cr1().modify(|w| w.set_engc(true));
1217 }
1218 }
1219
1220 /// Configure the primary address (OA1) register
1221 fn configure_primary_address(&mut self, addr: Address) {
1222 match addr {
1223 Address::SevenBit(addr) => {
1224 self.info.regs.oar1().write(|reg| {
1225 let hw_addr = (addr as u16) << 1; // Address in bits [7:1]
1226 reg.set_add(hw_addr);
1227 reg.set_addmode(i2c::vals::Addmode::BIT7);
1228 });
1229 },
1230 Address::TenBit(addr) => {
1231 self.info.regs.oar1().write(|reg| {
1232 reg.set_add(addr);
1233 reg.set_addmode(i2c::vals::Addmode::BIT10);
1234 });
1235 }
1236 }
1237
1238 // Set required bit 14 as per reference manual
1239 self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14);
1240 }
1241
1242 /// Configure the secondary address (OA2) register
1243 fn configure_secondary_address(&mut self, addr: u8) {
1244 self.info.regs.oar2().write(|reg| {
1245 reg.set_add2(addr);
1246 reg.set_endual(i2c::vals::Endual::DUAL);
1247 }); 1283 });
1248 } 1284 }
1249 1285
1250 /// Set a default primary address when using OA2-only mode 1286 /// Disable DMA and interrupts in a critical section
1251 fn configure_default_primary_address(&mut self) { 1287 fn disable_dma_and_interrupts(info: &'static Info) {
1252 self.info.regs.oar1().write(|reg| { 1288 critical_section::with(|_| {
1253 reg.set_add(0); // Reserved address, safe to use 1289 info.regs.cr2().modify(|w| {
1254 reg.set_addmode(i2c::vals::Addmode::BIT7); 1290 w.set_dmaen(false);
1291 w.set_iterren(false);
1292 w.set_itevten(false);
1293 });
1255 }); 1294 });
1256 self.info.regs.oar1().modify(|reg| reg.0 |= 1 << 14);
1257 } 1295 }
1258 1296
1259 /// Disable secondary address when not needed 1297 /// Check for early termination conditions during slave operations
1260 fn disable_secondary_address(&mut self) { 1298 /// Returns Some(result) if termination detected, None to continue
1261 self.info.regs.oar2().write(|reg| { 1299 fn check_slave_termination_conditions(sr1: i2c::regs::Sr1) -> Option<SlaveTermination> {
1262 reg.set_endual(i2c::vals::Endual::SINGLE); 1300 if sr1.stopf() {
1263 }); 1301 Some(SlaveTermination::Stop)
1302 } else if sr1.addr() {
1303 Some(SlaveTermination::Restart)
1304 } else if sr1.af() {
1305 Some(SlaveTermination::Nack)
1306 } else {
1307 None
1308 }
1264 } 1309 }
1265} 1310}
1266 1311
1267impl<'d> I2c<'d, Async, MultiMaster> { 1312impl<'d> I2c<'d, Async, MultiMaster> {
1268 /// Async listen for incoming I2C messages using interrupts 1313 /// Async listen for incoming I2C messages using interrupts
1314 ///
1315 /// Waits for a master to address this slave and returns the command type
1316 /// (Read/Write) and the matched address. This method will suspend until
1317 /// an address match occurs.
1269 pub async fn listen(&mut self) -> Result<SlaveCommand, Error> { 1318 pub async fn listen(&mut self) -> Result<SlaveCommand, Error> {
1270 trace!("I2C slave: starting listen for address match");
1271
1272 // Extract references needed by the closure
1273 let state = self.state; 1319 let state = self.state;
1274 let info = self.info; 1320 let info = self.info;
1275 1321
1276 Self::enable_interrupts(info); 1322 Self::enable_interrupts(info);
1277 trace!("I2C slave: enabled event and error interrupts");
1278 1323
1279 // Sentinel to clean up interrupts on drop 1324 // Ensure interrupts are cleaned up on early exit
1280 let on_drop = OnDrop::new(|| { 1325 let on_drop = OnDrop::new(|| {
1281 critical_section::with(|_| { 1326 Self::disable_dma_and_interrupts(info);
1282 info.regs.cr2().modify(|w| {
1283 w.set_iterren(false);
1284 w.set_itevten(false);
1285 });
1286 });
1287 trace!("I2C slave: disabled interrupts on drop");
1288 }); 1327 });
1289 1328
1290 let result = poll_fn(|cx| { 1329 let result = poll_fn(|cx| {
1291 state.waker.register(cx.waker()); 1330 state.waker.register(cx.waker());
1292 1331
1293 match Self::check_and_clear_error_flags(info) { 1332 match Self::check_and_clear_error_flags(info) {
1294 Err(e) => { 1333 Err(e) => Poll::Ready(Err(e)),
1295 error!("I2C slave: error during listen: {:?}", e);
1296 Poll::Ready(Err(e))
1297 },
1298 Ok(sr1) => { 1334 Ok(sr1) => {
1299 if sr1.addr() { 1335 if sr1.addr() {
1300 trace!("I2C slave: ADDR flag detected - address matched"); 1336 // Address matched - determine direction and decode address
1301
1302 // Address matched - determine direction
1303 let sr2 = info.regs.sr2().read(); 1337 let sr2 = info.regs.sr2().read();
1304 let direction = if sr2.tra() { 1338 let direction = if sr2.tra() {
1305 trace!("I2C slave: direction = READ (master wants to read from us)");
1306 SlaveCommandKind::Read 1339 SlaveCommandKind::Read
1307 } else { 1340 } else {
1308 trace!("I2C slave: direction = WRITE (master wants to write to us)");
1309 SlaveCommandKind::Write 1341 SlaveCommandKind::Write
1310 }; 1342 };
1311 1343
1312 let matched_address = match Self::decode_matched_address(sr2, info) { 1344 let matched_address = match Self::decode_matched_address(sr2, info) {
1313 Ok(addr) => { 1345 Ok(addr) => addr,
1314 trace!("I2C slave: matched address decoded: {:?}", addr); 1346 Err(e) => return Poll::Ready(Err(e)),
1315 addr
1316 },
1317 Err(e) => {
1318 error!("I2C slave: failed to decode matched address: {:?}", e);
1319 return Poll::Ready(Err(e));
1320 }
1321 }; 1347 };
1322 1348
1323 trace!("I2C slave: listen complete - returning command"); 1349 // Don't clear ADDR here - leave it for DMA setup in respond methods
1324 // Don't clear ADDR here - leave it for DMA setup
1325 Poll::Ready(Ok(SlaveCommand { 1350 Poll::Ready(Ok(SlaveCommand {
1326 kind: direction, 1351 kind: direction,
1327 address: matched_address, 1352 address: matched_address,
1328 })) 1353 }))
1329 } else { 1354 } else {
1330 // Re-enable interrupts and continue waiting
1331 // Use safe method since handler disables them globally
1332 Self::enable_interrupts(info); 1355 Self::enable_interrupts(info);
1333 Poll::Pending 1356 Poll::Pending
1334 } 1357 }
@@ -1337,341 +1360,266 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1337 }).await; 1360 }).await;
1338 1361
1339 drop(on_drop); 1362 drop(on_drop);
1340 trace!("I2C slave: listen result: {:?}", result);
1341 result 1363 result
1342 } 1364 }
1343 1365
1344 /// Async respond to write command using RX DMA 1366 /// Async respond to write command using RX DMA
1367 ///
1368 /// Receives data from the master into the provided buffer using DMA.
1369 /// If the master sends more bytes than the buffer can hold, excess bytes
1370 /// are acknowledged but discarded to prevent interrupt flooding.
1371 ///
1372 /// Returns the number of bytes stored in the buffer (not total received).
1345 pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { 1373 pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
1346 trace!("I2C slave: starting respond_to_write, buffer_len={}", buffer.len());
1347
1348 if buffer.is_empty() { 1374 if buffer.is_empty() {
1349 warn!("I2C slave: respond_to_write called with empty buffer");
1350 return Err(Error::Overrun); 1375 return Err(Error::Overrun);
1351 } 1376 }
1352 1377
1353 // Extract references needed by closures
1354 let state = self.state; 1378 let state = self.state;
1355 let info = self.info; 1379 let info = self.info;
1356 1380
1357 trace!("I2C slave: configuring registers for RX DMA"); 1381 // Use shared DMA setup
1358 info.regs.cr2().modify(|w| { 1382 self.setup_slave_dma_base();
1359 w.set_itbufen(false); // Disable buffer interrupts for DMA
1360 w.set_dmaen(true); // Enable DMA
1361 w.set_last(false); // Not needed for slave writes
1362 });
1363 1383
1364 // Sentinel to clean up DMA on drop 1384 // Ensure proper cleanup on exit
1365 let on_drop = OnDrop::new(|| { 1385 let on_drop = OnDrop::new(|| {
1366 critical_section::with(|_| { 1386 Self::disable_dma_and_interrupts(info);
1367 info.regs.cr2().modify(|w| {
1368 w.set_dmaen(false);
1369 w.set_iterren(false);
1370 w.set_itevten(false);
1371 });
1372 });
1373 trace!("I2C slave: DMA and interrupts disabled on drop (respond_to_write)");
1374 }); 1387 });
1375 1388
1376 // Clear ADDR flag to release clock stretching - DMA is now ready 1389 // Clear ADDR flag to release clock stretching
1377 trace!("I2C slave: clearing ADDR flag to release clock stretching"); 1390 info.regs.sr2().read();
1378 info.regs.sr2().read(); // Clear ADDR by reading SR2
1379
1380 // Set up RX DMA transfer (I2C DR -> buffer)
1381 trace!("I2C slave: setting up RX DMA transfer");
1382 let dma_transfer = unsafe {
1383 let src = info.regs.dr().as_ptr() as *mut u8;
1384 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
1385 };
1386
1387 // Poll for I2C errors while DMA runs
1388 let poll_error = poll_fn(|cx| {
1389 state.waker.register(cx.waker());
1390 1391
1391 match Self::check_and_clear_error_flags(info) { 1392 // Start DMA transfer and monitor completion
1392 Err(e) => { 1393 let result = self.execute_slave_receive_transfer(buffer, state, info).await;
1393 error!("I2C slave: error during write operation: {:?}", e);
1394 Poll::Ready(Err::<(), Error>(e))
1395 },
1396 Ok(sr1) => {
1397 // Check for STOP condition (normal end of write)
1398 if sr1.stopf() {
1399 trace!("I2C slave: STOP condition detected - write transaction complete");
1400 Self::clear_stop_flag(info);
1401 Poll::Ready(Ok(()))
1402 } else if sr1.addr() {
1403 trace!("I2C slave: RESTART condition detected - transitioning to read phase");
1404 Poll::Ready(Ok(()))
1405 } else {
1406 // Re-enable interrupts and continue monitoring
1407 // Use safe method since handler disables them globally
1408 Self::enable_interrupts(info);
1409 Poll::Pending
1410 }
1411 }
1412 }
1413 });
1414 1394
1415 trace!("I2C slave: starting select between DMA completion and I2C events"); 1395 drop(on_drop);
1416 // Wait for either DMA completion or I2C termination condition (using master pattern) 1396 result
1417 let dma_result = match select(dma_transfer, poll_error).await {
1418 Either::Second(Err(e)) => {
1419 error!("I2C slave: I2C error occurred during write: {:?}", e);
1420 critical_section::with(|_| {
1421 info.regs.cr2().modify(|w| w.set_dmaen(false));
1422 });
1423 drop(on_drop);
1424 return Err(e);
1425 }
1426 Either::First(_) => {
1427 trace!("I2C slave: DMA transfer completed first - buffer full");
1428 critical_section::with(|_| {
1429 info.regs.cr2().modify(|w| w.set_dmaen(false));
1430 });
1431
1432 // DMA completed but master might still be sending more bytes
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
1476 let bytes_received = buffer.len();
1477 trace!("I2C slave: write complete after discarding excess, returning {} bytes", bytes_received);
1478 drop(on_drop);
1479 Ok(bytes_received)
1480 }
1481 Either::Second(Ok(())) => {
1482 trace!("I2C slave: I2C event (STOP/RESTART) occurred before DMA completion");
1483 critical_section::with(|_| {
1484 info.regs.cr2().modify(|w| w.set_dmaen(false));
1485 });
1486
1487 // Transaction ended normally before buffer was full
1488 let bytes_received = buffer.len();
1489 trace!("I2C slave: write complete via early I2C event, returning {} bytes", bytes_received);
1490 drop(on_drop);
1491 Ok(bytes_received)
1492 }
1493 };
1494
1495 dma_result
1496 } 1397 }
1497 1398
1498 /// Async respond to read command using TX DMA 1399 /// Async respond to read command using TX DMA
1400 ///
1401 /// Transmits data to the master using DMA. If the master requests more bytes
1402 /// than available in the data buffer, padding bytes (0x00) are sent until
1403 /// the master terminates the transaction with NACK, STOP, or RESTART.
1404 ///
1405 /// Returns the total number of bytes transmitted (data + padding).
1499 pub async fn respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> { 1406 pub async fn respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> {
1500 trace!("I2C slave: starting respond_to_read, data_len={}", data.len());
1501
1502 if data.is_empty() { 1407 if data.is_empty() {
1503 warn!("I2C slave: respond_to_read called with empty data");
1504 return Err(Error::Overrun); 1408 return Err(Error::Overrun);
1505 } 1409 }
1506 1410
1507 // Extract references needed by closures
1508 let state = self.state; 1411 let state = self.state;
1509 let info = self.info; 1412 let info = self.info;
1510 1413
1511 trace!("I2C slave: configuring registers for TX DMA"); 1414 // Use shared DMA setup
1512 info.regs.cr2().modify(|w| { 1415 self.setup_slave_dma_base();
1513 w.set_itbufen(false); // Disable buffer interrupts for DMA
1514 w.set_dmaen(true); // Enable DMA
1515 w.set_last(false); // Not applicable for slave transmit
1516 });
1517 1416
1518 // Sentinel to clean up DMA on drop 1417 // Ensure proper cleanup on exit
1519 let on_drop = OnDrop::new(|| { 1418 let on_drop = OnDrop::new(|| {
1520 critical_section::with(|_| { 1419 Self::disable_dma_and_interrupts(info);
1521 info.regs.cr2().modify(|w| {
1522 w.set_dmaen(false);
1523 w.set_iterren(false);
1524 w.set_itevten(false);
1525 });
1526 });
1527 trace!("I2C slave: DMA and interrupts disabled on drop (respond_to_read)");
1528 }); 1420 });
1529 1421
1530 // Clear ADDR flag to release clock stretching 1422 // Clear ADDR flag to release clock stretching
1531 trace!("I2C slave: clearing ADDR flag to release clock stretching");
1532 info.regs.sr2().read(); 1423 info.regs.sr2().read();
1533 1424
1534 // Set up TX DMA transfer (data -> I2C DR) 1425 // Start DMA transfer and monitor completion
1535 trace!("I2C slave: setting up TX DMA transfer"); 1426 let result = self.execute_slave_transmit_transfer(data, state, info).await;
1427
1428 drop(on_drop);
1429 result
1430 }
1431
1432 // === Private Transfer Execution Methods ===
1433
1434 /// Execute complete slave receive transfer with excess byte handling
1435 async fn execute_slave_receive_transfer(
1436 &mut self,
1437 buffer: &mut [u8],
1438 state: &'static State,
1439 info: &'static Info
1440 ) -> Result<usize, Error> {
1441 // Start DMA transfer
1442 let dma_transfer = unsafe {
1443 let src = info.regs.dr().as_ptr() as *mut u8;
1444 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
1445 };
1446
1447 // Monitor for I2C events during transfer
1448 let i2c_monitor = Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart]);
1449
1450 match select(dma_transfer, i2c_monitor).await {
1451 Either::Second(Err(e)) => {
1452 Self::disable_dma_and_interrupts(info);
1453 Err(e)
1454 }
1455 Either::First(_) => {
1456 // DMA completed first - handle potential excess bytes
1457 Self::disable_dma_and_interrupts(info);
1458 self.handle_excess_bytes(state, info).await?;
1459 Ok(buffer.len())
1460 }
1461 Either::Second(Ok(_)) => {
1462 // I2C event occurred first - normal transaction end
1463 Self::disable_dma_and_interrupts(info);
1464 Ok(buffer.len())
1465 }
1466 }
1467 }
1468
1469 /// Execute complete slave transmit transfer with padding byte handling
1470 async fn execute_slave_transmit_transfer(
1471 &mut self,
1472 data: &[u8],
1473 state: &'static State,
1474 info: &'static Info
1475 ) -> Result<usize, Error> {
1476 // Start DMA transfer
1536 let dma_transfer = unsafe { 1477 let dma_transfer = unsafe {
1537 let dst = info.regs.dr().as_ptr() as *mut u8; 1478 let dst = info.regs.dr().as_ptr() as *mut u8;
1538 self.tx_dma.as_mut().unwrap().write(data, dst, Default::default()) 1479 self.tx_dma.as_mut().unwrap().write(data, dst, Default::default())
1539 }; 1480 };
1540 1481
1541 // Monitor for I2C events while DMA runs 1482 // Monitor for I2C events during transfer (NACK is normal for slave transmit)
1542 let poll_completion = poll_fn(|cx| { 1483 let i2c_monitor = Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart, SlaveTermination::Nack]);
1543 state.waker.register(cx.waker());
1544 1484
1485 match select(dma_transfer, i2c_monitor).await {
1486 Either::Second(Err(e)) => {
1487 Self::disable_dma_and_interrupts(info);
1488 Err(e)
1489 }
1490 Either::First(_) => {
1491 // DMA completed first - handle potential padding bytes
1492 Self::disable_dma_and_interrupts(info);
1493 let padding_count = self.handle_padding_bytes(state, info).await?;
1494 Ok(data.len() + padding_count)
1495 }
1496 Either::Second(Ok(_)) => {
1497 // I2C event occurred first - normal transaction end
1498 Self::disable_dma_and_interrupts(info);
1499 Ok(data.len())
1500 }
1501 }
1502 }
1503
1504 /// Create a future that monitors for specific slave termination conditions
1505 fn create_termination_monitor(
1506 state: &'static State,
1507 info: &'static Info,
1508 allowed_terminations: &'static [SlaveTermination],
1509 ) -> impl Future<Output = Result<SlaveTermination, Error>> {
1510 poll_fn(move |cx| {
1511 state.waker.register(cx.waker());
1512
1545 match Self::check_and_clear_error_flags(info) { 1513 match Self::check_and_clear_error_flags(info) {
1546 Err(Error::Nack) => { 1514 Err(Error::Nack) if allowed_terminations.contains(&SlaveTermination::Nack) => {
1547 trace!("I2C slave: NACK received - master stopped reading (normal)"); 1515 Poll::Ready(Ok(SlaveTermination::Nack))
1548 Poll::Ready(Ok(()))
1549 } 1516 }
1550 Err(e) => { 1517 Err(e) => Poll::Ready(Err(e)),
1551 error!("I2C slave: error during read operation: {:?}", e);
1552 Poll::Ready(Err(e))
1553 },
1554 Ok(sr1) => { 1518 Ok(sr1) => {
1555 if sr1.stopf() { 1519 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1556 trace!("I2C slave: STOP condition detected - read transaction complete"); 1520 if allowed_terminations.contains(&termination) {
1557 Self::clear_stop_flag(info); 1521 // Handle the specific termination condition
1558 Poll::Ready(Ok(())) 1522 match termination {
1559 } else if sr1.addr() { 1523 SlaveTermination::Stop => Self::clear_stop_flag(info),
1560 trace!("I2C slave: RESTART condition detected during read"); 1524 SlaveTermination::Nack => {
1561 Poll::Ready(Ok(())) 1525 info.regs.sr1().write(|reg| {
1562 } else if sr1.af() { 1526 reg.0 = !0;
1563 trace!("I2C slave: acknowledge failure (NACK) - normal end of read"); 1527 reg.set_af(false);
1564 // Acknowledge failure (NACK) - normal end of read 1528 });
1565 info.regs.sr1().write(|reg| { 1529 }
1566 reg.0 = !0; 1530 SlaveTermination::Restart => {
1567 reg.set_af(false); 1531 // ADDR flag will be handled by next listen() call
1568 }); 1532 }
1569 Poll::Ready(Ok(())) 1533 }
1534 Poll::Ready(Ok(termination))
1535 } else {
1536 // Unexpected termination condition
1537 Poll::Ready(Err(Error::Bus))
1538 }
1570 } else { 1539 } else {
1571 Self::enable_interrupts(info); 1540 Self::enable_interrupts(info);
1572 Poll::Pending 1541 Poll::Pending
1573 } 1542 }
1574 } 1543 }
1575 } 1544 }
1576 }); 1545 })
1546 }
1577 1547
1578 trace!("I2C slave: starting select between DMA completion and I2C events"); 1548 /// Handle excess bytes after DMA buffer is full
1579 // Wait for either DMA completion or I2C termination (using master pattern) 1549 ///
1580 let dma_result = match select(dma_transfer, poll_completion).await { 1550 /// Reads and discards bytes until transaction termination to prevent interrupt flooding
1581 Either::Second(Err(e)) => { 1551 async fn handle_excess_bytes(&mut self, state: &'static State, info: &'static Info) -> Result<(), Error> {
1582 error!("I2C slave: I2C error occurred during read: {:?}", e); 1552 poll_fn(|cx| {
1583 critical_section::with(|_| { 1553 state.waker.register(cx.waker());
1584 info.regs.cr2().modify(|w| w.set_dmaen(false)); 1554
1585 }); 1555 match Self::check_and_clear_error_flags(info) {
1586 drop(on_drop); 1556 Err(e) => Poll::Ready(Err(e)),
1587 return Err(e); 1557 Ok(sr1) => {
1588 } 1558 // Check for transaction termination first
1589 Either::First(_) => { 1559 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1590 trace!("I2C slave: DMA transfer completed first - all data sent"); 1560 match termination {
1591 critical_section::with(|_| { 1561 SlaveTermination::Stop => Self::clear_stop_flag(info),
1592 info.regs.cr2().modify(|w| w.set_dmaen(false)); 1562 SlaveTermination::Restart => {}, // Leave ADDR for next operation
1593 }); 1563 SlaveTermination::Nack => unreachable!("NACK not expected during receive"),
1594 1564 }
1595 // DMA completed but master might still be requesting more bytes 1565 return Poll::Ready(Ok(()));
1596 // We need to send padding bytes (0x00) until NACK/STOP/RESTART 1566 }
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 1567
1603 match Self::check_and_clear_error_flags(info) { 1568 // If there's data to read, discard it
1604 Err(Error::Nack) => { 1569 if sr1.rxne() {
1605 trace!("I2C slave: NACK received during padding - normal end"); 1570 let _discarded_byte = info.regs.dr().read().dr();
1606 return Poll::Ready(Ok(())); 1571 Self::enable_interrupts(info);
1607 }, 1572 return Poll::Pending;
1608 Err(e) => { 1573 }
1609 error!("I2C slave: error while sending padding bytes: {:?}", e); 1574
1610 return Poll::Ready(Err::<(), Error>(e)); 1575 Self::enable_interrupts(info);
1611 }, 1576 Poll::Pending
1612 Ok(sr1) => { 1577 }
1613 // Check for transaction termination first 1578 }
1614 if sr1.af() { 1579 }).await
1615 trace!("I2C slave: acknowledge failure during padding - normal end"); 1580 }
1581
1582 /// Handle padding bytes after DMA data is exhausted
1583 ///
1584 /// Sends 0x00 bytes until transaction termination to prevent interrupt flooding
1585 async fn handle_padding_bytes(&mut self, state: &'static State, info: &'static Info) -> Result<usize, Error> {
1586 let mut padding_count = 0;
1587
1588 poll_fn(|cx| {
1589 state.waker.register(cx.waker());
1590
1591 match Self::check_and_clear_error_flags(info) {
1592 Err(Error::Nack) => Poll::Ready(Ok(padding_count)), // Normal termination
1593 Err(e) => Poll::Ready(Err(e)),
1594 Ok(sr1) => {
1595 // Check for transaction termination first
1596 if let Some(termination) = Self::check_slave_termination_conditions(sr1) {
1597 match termination {
1598 SlaveTermination::Stop => Self::clear_stop_flag(info),
1599 SlaveTermination::Restart => {}, // Leave ADDR for next operation
1600 SlaveTermination::Nack => {
1616 info.regs.sr1().write(|reg| { 1601 info.regs.sr1().write(|reg| {
1617 reg.0 = !0; 1602 reg.0 = !0;
1618 reg.set_af(false); 1603 reg.set_af(false);
1619 }); 1604 });
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 } 1605 }
1643
1644 // No immediate termination or transmit request, keep waiting
1645 Self::enable_interrupts(info);
1646 Poll::Pending
1647 } 1606 }
1607 return Poll::Ready(Ok(padding_count));
1648 } 1608 }
1649 }); 1609
1650 1610 // If transmit buffer is empty, send padding byte
1651 // Wait for transaction to actually end 1611 if sr1.txe() {
1652 padding_phase.await?; 1612 info.regs.dr().write(|w| w.set_dr(0x00));
1653 1613 padding_count += 1;
1654 let total_bytes_sent = data.len() + padding_bytes_sent; 1614 Self::enable_interrupts(info);
1655 trace!("I2C slave: read complete after sending {} padding bytes, total {} bytes sent", 1615 return Poll::Pending;
1656 padding_bytes_sent, total_bytes_sent); 1616 }
1657 drop(on_drop); 1617
1658 Ok(total_bytes_sent) 1618 Self::enable_interrupts(info);
1659 } 1619 Poll::Pending
1660 Either::Second(Ok(())) => { 1620 }
1661 trace!("I2C slave: I2C event (STOP/NACK/RESTART) occurred before DMA completion");
1662 critical_section::with(|_| {
1663 info.regs.cr2().modify(|w| w.set_dmaen(false));
1664 });
1665
1666 // Transaction ended normally before all data was sent
1667 let bytes_sent = data.len();
1668 trace!("I2C slave: read complete via early I2C event, sent {} bytes", bytes_sent);
1669 drop(on_drop);
1670 Ok(bytes_sent)
1671 } 1621 }
1672 }; 1622 }).await
1673
1674 dma_result
1675 } 1623 }
1676} 1624}
1677 1625