diff options
| author | HybridChild <[email protected]> | 2025-08-13 20:11:55 +0200 |
|---|---|---|
| committer | HybridChild <[email protected]> | 2025-08-23 08:53:48 +0200 |
| commit | 0ab366e28af266795106cb254b4a0d63f723d476 (patch) | |
| tree | ab4826ee2c29fc9a07975d6439d641331ea18452 | |
| parent | 03496864d765590744582c00a1b8f010d5014a0c (diff) | |
stm32/i2c_v1: Add async slave implementation
| -rw-r--r-- | embassy-stm32/src/i2c/v1.rs | 359 |
1 files changed, 339 insertions, 20 deletions
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 9b5a524df..10a307396 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs | |||
| @@ -362,14 +362,30 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 362 | } | 362 | } |
| 363 | 363 | ||
| 364 | // Async | 364 | // Async |
| 365 | 365 | ||
| 366 | /// Can be used by both blocking and async implementations | ||
| 366 | #[inline] // pretty sure this should always be inlined | 367 | #[inline] // pretty sure this should always be inlined |
| 367 | fn enable_interrupts(info: &'static Info) -> () { | 368 | fn enable_interrupts(info: &'static Info) { |
| 368 | info.regs.cr2().modify(|w| { | 369 | // The interrupt handler disables interrupts globally, so we need to re-enable them |
| 369 | w.set_iterren(true); | 370 | // This must be done in a critical section to avoid races |
| 370 | w.set_itevten(true); | 371 | critical_section::with(|_| { |
| 372 | info.regs.cr2().modify(|w| { | ||
| 373 | w.set_iterren(true); | ||
| 374 | w.set_itevten(true); | ||
| 375 | }); | ||
| 371 | }); | 376 | }); |
| 377 | trace!("I2C slave: safely enabled interrupts"); | ||
| 372 | } | 378 | } |
| 379 | |||
| 380 | /// Can be used by both blocking and async implementations | ||
| 381 | fn clear_stop_flag(info: &'static Info) { | ||
| 382 | trace!("I2C slave: clearing STOPF flag (v1 sequence)"); | ||
| 383 | // v1 requires: READ SR1 then WRITE CR1 to clear STOPF | ||
| 384 | let _ = info.regs.sr1().read(); | ||
| 385 | info.regs.cr1().modify(|_| {}); // Dummy write to clear STOPF | ||
| 386 | trace!("I2C slave: STOPF flag cleared"); | ||
| 387 | } | ||
| 388 | |||
| 373 | } | 389 | } |
| 374 | 390 | ||
| 375 | impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | 391 | impl<'d, IM: MasterMode> I2c<'d, Async, IM> { |
| @@ -829,7 +845,8 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 829 | SlaveCommandKind::Write | 845 | SlaveCommandKind::Write |
| 830 | }; | 846 | }; |
| 831 | 847 | ||
| 832 | let matched_address = self.decode_matched_address(sr2)?; | 848 | // Use the static method instead of the instance method |
| 849 | let matched_address = Self::decode_matched_address(sr2, self.info)?; | ||
| 833 | trace!("I2C slave: address matched, direction={:?}, addr={:?}", direction, matched_address); | 850 | trace!("I2C slave: address matched, direction={:?}, addr={:?}", direction, matched_address); |
| 834 | 851 | ||
| 835 | return Ok(SlaveCommand { | 852 | return Ok(SlaveCommand { |
| @@ -916,13 +933,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 916 | 933 | ||
| 917 | // Check for immediate STOP (alternative zero-length pattern) | 934 | // Check for immediate STOP (alternative zero-length pattern) |
| 918 | if sr1.stopf() { | 935 | if sr1.stopf() { |
| 919 | self.clear_stop_flag(); | 936 | Self::clear_stop_flag(self.info); |
| 920 | return Ok(Some(0)); | 937 | return Ok(Some(0)); |
| 921 | } | 938 | } |
| 922 | 939 | ||
| 923 | // Give a brief window for master to send termination signals | 940 | // Give a brief window for master to send termination signals |
| 924 | // This handles masters that have slight delays between address ACK and NACK | 941 | // This handles masters that have slight delays between address ACK and NACK |
| 925 | const ZERO_LENGTH_DETECTION_CYCLES: u32 = 100; // ~5-10µs window | 942 | const ZERO_LENGTH_DETECTION_CYCLES: u32 = 20; // ~5-10µs window |
| 926 | 943 | ||
| 927 | for _ in 0..ZERO_LENGTH_DETECTION_CYCLES { | 944 | for _ in 0..ZERO_LENGTH_DETECTION_CYCLES { |
| 928 | let sr1 = self.info.regs.sr1().read(); | 945 | let sr1 = self.info.regs.sr1().read(); |
| @@ -935,7 +952,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 935 | 952 | ||
| 936 | // Immediate STOP indicates zero-length read | 953 | // Immediate STOP indicates zero-length read |
| 937 | if sr1.stopf() { | 954 | if sr1.stopf() { |
| 938 | self.clear_stop_flag(); | 955 | Self::clear_stop_flag(self.info); |
| 939 | return Ok(Some(0)); | 956 | return Ok(Some(0)); |
| 940 | } | 957 | } |
| 941 | 958 | ||
| @@ -1016,7 +1033,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 1016 | } | 1033 | } |
| 1017 | 1034 | ||
| 1018 | if sr1.stopf() { | 1035 | if sr1.stopf() { |
| 1019 | self.clear_stop_flag(); | 1036 | Self::clear_stop_flag(self.info); |
| 1020 | return Ok(TransmitResult::Stopped); | 1037 | return Ok(TransmitResult::Stopped); |
| 1021 | } | 1038 | } |
| 1022 | 1039 | ||
| @@ -1048,7 +1065,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 1048 | } | 1065 | } |
| 1049 | 1066 | ||
| 1050 | if sr1.stopf() { | 1067 | if sr1.stopf() { |
| 1051 | self.clear_stop_flag(); | 1068 | Self::clear_stop_flag(self.info); |
| 1052 | return Ok(ReceiveResult::Stopped); | 1069 | return Ok(ReceiveResult::Stopped); |
| 1053 | } | 1070 | } |
| 1054 | 1071 | ||
| @@ -1057,19 +1074,19 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 1057 | } | 1074 | } |
| 1058 | 1075 | ||
| 1059 | /// Determine which slave address was matched based on SR2 flags | 1076 | /// Determine which slave address was matched based on SR2 flags |
| 1060 | fn decode_matched_address(&self, sr2: i2c::regs::Sr2) -> Result<Address, Error> { | 1077 | fn decode_matched_address(sr2: i2c::regs::Sr2, info: &'static Info) -> Result<Address, Error> { |
| 1061 | if sr2.gencall() { | 1078 | if sr2.gencall() { |
| 1062 | Ok(Address::SevenBit(0x00)) // General call address | 1079 | Ok(Address::SevenBit(0x00)) // General call address |
| 1063 | } else if sr2.dualf() { | 1080 | } else if sr2.dualf() { |
| 1064 | // OA2 (secondary address) was matched | 1081 | // OA2 (secondary address) was matched |
| 1065 | let oar2 = self.info.regs.oar2().read(); | 1082 | let oar2 = info.regs.oar2().read(); |
| 1066 | if oar2.endual() != i2c::vals::Endual::DUAL { | 1083 | if oar2.endual() != i2c::vals::Endual::DUAL { |
| 1067 | return Err(Error::Bus); // Hardware inconsistency | 1084 | return Err(Error::Bus); // Hardware inconsistency |
| 1068 | } | 1085 | } |
| 1069 | Ok(Address::SevenBit(oar2.add2())) | 1086 | Ok(Address::SevenBit(oar2.add2())) |
| 1070 | } else { | 1087 | } else { |
| 1071 | // OA1 (primary address) was matched | 1088 | // OA1 (primary address) was matched |
| 1072 | let oar1 = self.info.regs.oar1().read(); | 1089 | let oar1 = info.regs.oar1().read(); |
| 1073 | match oar1.addmode() { | 1090 | match oar1.addmode() { |
| 1074 | i2c::vals::Addmode::BIT7 => { | 1091 | i2c::vals::Addmode::BIT7 => { |
| 1075 | let addr = (oar1.add() >> 1) as u8; | 1092 | let addr = (oar1.add() >> 1) as u8; |
| @@ -1113,7 +1130,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 1113 | fn handle_early_termination(&mut self, result: TransmitResult) -> Error { | 1130 | fn handle_early_termination(&mut self, result: TransmitResult) -> Error { |
| 1114 | match result { | 1131 | match result { |
| 1115 | TransmitResult::Stopped => { | 1132 | TransmitResult::Stopped => { |
| 1116 | self.clear_stop_flag(); | 1133 | Self::clear_stop_flag(self.info); |
| 1117 | Error::Bus // Unexpected STOP during setup | 1134 | Error::Bus // Unexpected STOP during setup |
| 1118 | }, | 1135 | }, |
| 1119 | TransmitResult::Restarted => { | 1136 | TransmitResult::Restarted => { |
| @@ -1153,11 +1170,6 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 1153 | reg.set_af(false); | 1170 | reg.set_af(false); |
| 1154 | }); | 1171 | }); |
| 1155 | } | 1172 | } |
| 1156 | |||
| 1157 | /// Clear the stop condition flag | ||
| 1158 | fn clear_stop_flag(&mut self) { | ||
| 1159 | self.info.regs.cr1().modify(|_w| {}); | ||
| 1160 | } | ||
| 1161 | } | 1173 | } |
| 1162 | 1174 | ||
| 1163 | // Address configuration methods | 1175 | // Address configuration methods |
| @@ -1176,6 +1188,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 1176 | self.info.regs.cr1().modify(|reg| { | 1188 | self.info.regs.cr1().modify(|reg| { |
| 1177 | reg.set_pe(true); | 1189 | reg.set_pe(true); |
| 1178 | reg.set_ack(true); // Enable acknowledgment for slave mode | 1190 | reg.set_ack(true); // Enable acknowledgment for slave mode |
| 1191 | reg.set_nostretch(false); // Allow clock stretching for processing time | ||
| 1179 | }); | 1192 | }); |
| 1180 | 1193 | ||
| 1181 | trace!("I2C slave: initialization complete"); | 1194 | trace!("I2C slave: initialization complete"); |
| @@ -1251,6 +1264,312 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 1251 | } | 1264 | } |
| 1252 | } | 1265 | } |
| 1253 | 1266 | ||
| 1267 | impl<'d> I2c<'d, Async, MultiMaster> { | ||
| 1268 | /// Async listen for incoming I2C messages using interrupts | ||
| 1269 | 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; | ||
| 1274 | let info = self.info; | ||
| 1275 | |||
| 1276 | Self::enable_interrupts(info); | ||
| 1277 | trace!("I2C slave: enabled event and error interrupts"); | ||
| 1278 | |||
| 1279 | // Sentinel to clean up interrupts on drop | ||
| 1280 | let on_drop = OnDrop::new(|| { | ||
| 1281 | critical_section::with(|_| { | ||
| 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 | }); | ||
| 1289 | |||
| 1290 | let result = poll_fn(|cx| { | ||
| 1291 | state.waker.register(cx.waker()); | ||
| 1292 | |||
| 1293 | match Self::check_and_clear_error_flags(info) { | ||
| 1294 | Err(e) => { | ||
| 1295 | error!("I2C slave: error during listen: {:?}", e); | ||
| 1296 | Poll::Ready(Err(e)) | ||
| 1297 | }, | ||
| 1298 | Ok(sr1) => { | ||
| 1299 | if sr1.addr() { | ||
| 1300 | trace!("I2C slave: ADDR flag detected - address matched"); | ||
| 1301 | |||
| 1302 | // Address matched - determine direction | ||
| 1303 | let sr2 = info.regs.sr2().read(); | ||
| 1304 | let direction = if sr2.tra() { | ||
| 1305 | trace!("I2C slave: direction = READ (master wants to read from us)"); | ||
| 1306 | SlaveCommandKind::Read | ||
| 1307 | } else { | ||
| 1308 | trace!("I2C slave: direction = WRITE (master wants to write to us)"); | ||
| 1309 | SlaveCommandKind::Write | ||
| 1310 | }; | ||
| 1311 | |||
| 1312 | let matched_address = match Self::decode_matched_address(sr2, info) { | ||
| 1313 | Ok(addr) => { | ||
| 1314 | trace!("I2C slave: matched address decoded: {:?}", addr); | ||
| 1315 | addr | ||
| 1316 | }, | ||
| 1317 | Err(e) => { | ||
| 1318 | error!("I2C slave: failed to decode matched address: {:?}", e); | ||
| 1319 | return Poll::Ready(Err(e)); | ||
| 1320 | } | ||
| 1321 | }; | ||
| 1322 | |||
| 1323 | trace!("I2C slave: listen complete - returning command"); | ||
| 1324 | // Don't clear ADDR here - leave it for DMA setup | ||
| 1325 | Poll::Ready(Ok(SlaveCommand { | ||
| 1326 | kind: direction, | ||
| 1327 | address: matched_address, | ||
| 1328 | })) | ||
| 1329 | } else { | ||
| 1330 | // Re-enable interrupts and continue waiting | ||
| 1331 | // Use safe method since handler disables them globally | ||
| 1332 | Self::enable_interrupts(info); | ||
| 1333 | Poll::Pending | ||
| 1334 | } | ||
| 1335 | } | ||
| 1336 | } | ||
| 1337 | }).await; | ||
| 1338 | |||
| 1339 | drop(on_drop); | ||
| 1340 | trace!("I2C slave: listen result: {:?}", result); | ||
| 1341 | result | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | /// Async respond to write command using RX DMA | ||
| 1345 | 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() { | ||
| 1349 | warn!("I2C slave: respond_to_write called with empty buffer"); | ||
| 1350 | return Err(Error::Overrun); | ||
| 1351 | } | ||
| 1352 | |||
| 1353 | // Extract references needed by closures | ||
| 1354 | let state = self.state; | ||
| 1355 | let info = self.info; | ||
| 1356 | |||
| 1357 | trace!("I2C slave: configuring registers for RX DMA"); | ||
| 1358 | info.regs.cr2().modify(|w| { | ||
| 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 | |||
| 1364 | // Sentinel to clean up DMA on drop | ||
| 1365 | let on_drop = OnDrop::new(|| { | ||
| 1366 | critical_section::with(|_| { | ||
| 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 | }); | ||
| 1375 | |||
| 1376 | // Clear ADDR flag to release clock stretching - DMA is now ready | ||
| 1377 | trace!("I2C slave: clearing ADDR flag to release clock stretching"); | ||
| 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 | match Self::check_and_clear_error_flags(info) { | ||
| 1392 | Err(e) => { | ||
| 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 | |||
| 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) | ||
| 1417 | 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 | Err(e) | ||
| 1425 | } | ||
| 1426 | Either::First(_) => { | ||
| 1427 | trace!("I2C slave: DMA transfer completed first"); | ||
| 1428 | critical_section::with(|_| { | ||
| 1429 | info.regs.cr2().modify(|w| w.set_dmaen(false)); | ||
| 1430 | }); | ||
| 1431 | drop(on_drop); | ||
| 1432 | |||
| 1433 | // For v1 hardware, determining exact bytes received is complex | ||
| 1434 | // Return the buffer length as an approximation | ||
| 1435 | let bytes_received = buffer.len(); | ||
| 1436 | trace!("I2C slave: write complete, returning {} bytes (buffer length)", bytes_received); | ||
| 1437 | Ok(bytes_received) | ||
| 1438 | } | ||
| 1439 | Either::Second(Ok(())) => { | ||
| 1440 | trace!("I2C slave: I2C event (STOP/RESTART) occurred first"); | ||
| 1441 | critical_section::with(|_| { | ||
| 1442 | info.regs.cr2().modify(|w| w.set_dmaen(false)); | ||
| 1443 | }); | ||
| 1444 | drop(on_drop); | ||
| 1445 | |||
| 1446 | // Transaction ended normally, return buffer length | ||
| 1447 | let bytes_received = buffer.len(); | ||
| 1448 | trace!("I2C slave: write complete via I2C event, returning {} bytes", bytes_received); | ||
| 1449 | Ok(bytes_received) | ||
| 1450 | } | ||
| 1451 | } | ||
| 1452 | } | ||
| 1453 | |||
| 1454 | /// Async respond to read command using TX DMA | ||
| 1455 | pub async fn respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> { | ||
| 1456 | trace!("I2C slave: starting respond_to_read, data_len={}", data.len()); | ||
| 1457 | |||
| 1458 | if data.is_empty() { | ||
| 1459 | warn!("I2C slave: respond_to_read called with empty data"); | ||
| 1460 | return Err(Error::Overrun); | ||
| 1461 | } | ||
| 1462 | |||
| 1463 | // Extract references needed by closures | ||
| 1464 | let state = self.state; | ||
| 1465 | let info = self.info; | ||
| 1466 | |||
| 1467 | trace!("I2C slave: configuring registers for TX DMA"); | ||
| 1468 | info.regs.cr2().modify(|w| { | ||
| 1469 | w.set_itbufen(false); // Disable buffer interrupts for DMA | ||
| 1470 | w.set_dmaen(true); // Enable DMA | ||
| 1471 | w.set_last(false); // Not applicable for slave transmit | ||
| 1472 | }); | ||
| 1473 | |||
| 1474 | // Sentinel to clean up DMA on drop | ||
| 1475 | let on_drop = OnDrop::new(|| { | ||
| 1476 | critical_section::with(|_| { | ||
| 1477 | info.regs.cr2().modify(|w| { | ||
| 1478 | w.set_dmaen(false); | ||
| 1479 | w.set_iterren(false); | ||
| 1480 | w.set_itevten(false); | ||
| 1481 | }); | ||
| 1482 | }); | ||
| 1483 | trace!("I2C slave: DMA and interrupts disabled on drop (respond_to_read)"); | ||
| 1484 | }); | ||
| 1485 | |||
| 1486 | // Clear ADDR flag to release clock stretching | ||
| 1487 | trace!("I2C slave: clearing ADDR flag to release clock stretching"); | ||
| 1488 | info.regs.sr2().read(); | ||
| 1489 | |||
| 1490 | // Set up TX DMA transfer (data -> I2C DR) | ||
| 1491 | trace!("I2C slave: setting up TX DMA transfer"); | ||
| 1492 | let dma_transfer = unsafe { | ||
| 1493 | let dst = info.regs.dr().as_ptr() as *mut u8; | ||
| 1494 | self.tx_dma.as_mut().unwrap().write(data, dst, Default::default()) | ||
| 1495 | }; | ||
| 1496 | |||
| 1497 | // Monitor for I2C events while DMA runs | ||
| 1498 | let poll_completion = poll_fn(|cx| { | ||
| 1499 | state.waker.register(cx.waker()); | ||
| 1500 | |||
| 1501 | match Self::check_and_clear_error_flags(info) { | ||
| 1502 | Err(Error::Nack) => { | ||
| 1503 | trace!("I2C slave: NACK received - master stopped reading (normal)"); | ||
| 1504 | Poll::Ready(Ok(())) | ||
| 1505 | } | ||
| 1506 | Err(e) => { | ||
| 1507 | error!("I2C slave: error during read operation: {:?}", e); | ||
| 1508 | Poll::Ready(Err(e)) | ||
| 1509 | }, | ||
| 1510 | Ok(sr1) => { | ||
| 1511 | if sr1.stopf() { | ||
| 1512 | trace!("I2C slave: STOP condition detected - read transaction complete"); | ||
| 1513 | Self::clear_stop_flag(info); | ||
| 1514 | Poll::Ready(Ok(())) | ||
| 1515 | } else if sr1.addr() { | ||
| 1516 | trace!("I2C slave: RESTART condition detected during read"); | ||
| 1517 | Poll::Ready(Ok(())) | ||
| 1518 | } else if sr1.af() { | ||
| 1519 | trace!("I2C slave: acknowledge failure (NACK) - normal end of read"); | ||
| 1520 | // Acknowledge failure (NACK) - normal end of read | ||
| 1521 | info.regs.sr1().write(|reg| { | ||
| 1522 | reg.0 = !0; | ||
| 1523 | reg.set_af(false); | ||
| 1524 | }); | ||
| 1525 | Poll::Ready(Ok(())) | ||
| 1526 | } else { | ||
| 1527 | Self::enable_interrupts(info); | ||
| 1528 | Poll::Pending | ||
| 1529 | } | ||
| 1530 | } | ||
| 1531 | } | ||
| 1532 | }); | ||
| 1533 | |||
| 1534 | trace!("I2C slave: starting select between DMA completion and I2C events"); | ||
| 1535 | // Wait for either DMA completion or I2C termination (using master pattern) | ||
| 1536 | match select(dma_transfer, poll_completion).await { | ||
| 1537 | Either::Second(Err(e)) => { | ||
| 1538 | error!("I2C slave: I2C error occurred during read: {:?}", e); | ||
| 1539 | critical_section::with(|_| { | ||
| 1540 | info.regs.cr2().modify(|w| w.set_dmaen(false)); | ||
| 1541 | }); | ||
| 1542 | drop(on_drop); | ||
| 1543 | Err(e) | ||
| 1544 | } | ||
| 1545 | Either::First(_) => { | ||
| 1546 | trace!("I2C slave: DMA transfer completed first - all data sent"); | ||
| 1547 | critical_section::with(|_| { | ||
| 1548 | info.regs.cr2().modify(|w| w.set_dmaen(false)); | ||
| 1549 | }); | ||
| 1550 | drop(on_drop); | ||
| 1551 | |||
| 1552 | let bytes_sent = data.len(); | ||
| 1553 | trace!("I2C slave: read complete via DMA, sent {} bytes", bytes_sent); | ||
| 1554 | Ok(bytes_sent) | ||
| 1555 | } | ||
| 1556 | Either::Second(Ok(())) => { | ||
| 1557 | trace!("I2C slave: I2C event (STOP/NACK/RESTART) occurred first"); | ||
| 1558 | critical_section::with(|_| { | ||
| 1559 | info.regs.cr2().modify(|w| w.set_dmaen(false)); | ||
| 1560 | }); | ||
| 1561 | drop(on_drop); | ||
| 1562 | |||
| 1563 | // For slave read, we can't easily determine exact bytes sent in v1 | ||
| 1564 | // Return the full data length if no error occurred | ||
| 1565 | let bytes_sent = data.len(); | ||
| 1566 | trace!("I2C slave: read complete via I2C event, reporting {} bytes sent", bytes_sent); | ||
| 1567 | Ok(bytes_sent) | ||
| 1568 | } | ||
| 1569 | } | ||
| 1570 | } | ||
| 1571 | } | ||
| 1572 | |||
| 1254 | /// Timing configuration for I2C v1 hardware | 1573 | /// Timing configuration for I2C v1 hardware |
| 1255 | /// | 1574 | /// |
| 1256 | /// This struct encapsulates the complex timing calculations required for STM32 I2C v1 | 1575 | /// This struct encapsulates the complex timing calculations required for STM32 I2C v1 |
