aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHybridChild <[email protected]>2025-08-13 20:11:55 +0200
committerHybridChild <[email protected]>2025-08-23 08:53:48 +0200
commit0ab366e28af266795106cb254b4a0d63f723d476 (patch)
treeab4826ee2c29fc9a07975d6439d641331ea18452
parent03496864d765590744582c00a1b8f010d5014a0c (diff)
stm32/i2c_v1: Add async slave implementation
-rw-r--r--embassy-stm32/src/i2c/v1.rs359
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
375impl<'d, IM: MasterMode> I2c<'d, Async, IM> { 391impl<'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
1267impl<'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