diff options
| author | HybridChild <[email protected]> | 2025-08-22 13:45:43 +0200 |
|---|---|---|
| committer | HybridChild <[email protected]> | 2025-08-23 08:54:27 +0200 |
| commit | e630e1a6d48ca25a92bc0479608ca75b7179c869 (patch) | |
| tree | 6d018e7e9335c3b02fa2e8f53c34d048ef45be4f | |
| parent | 8111bbc54594706d26d02a22ad8f1853317d3495 (diff) | |
stm32/i2c_v1: Update defmt logging for MultiMaster
| -rw-r--r-- | embassy-stm32/src/i2c/v1.rs | 128 |
1 files changed, 75 insertions, 53 deletions
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 0f2953ef6..b362ab017 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs | |||
| @@ -45,7 +45,7 @@ impl State { | |||
| 45 | // hit a case like this! | 45 | // hit a case like this! |
| 46 | pub unsafe fn on_interrupt<T: Instance>() { | 46 | pub unsafe fn on_interrupt<T: Instance>() { |
| 47 | let regs = T::info().regs; | 47 | let regs = T::info().regs; |
| 48 | trace!("i2c v1 interrupt triggered"); | 48 | trace!("I2C interrupt triggered"); |
| 49 | // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of | 49 | // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of |
| 50 | // other stuff, so we wake the task on every interrupt. | 50 | // other stuff, so we wake the task on every interrupt. |
| 51 | T::state().waker.wake(); | 51 | T::state().waker.wake(); |
| @@ -360,8 +360,6 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 360 | 360 | ||
| 361 | Ok(()) | 361 | Ok(()) |
| 362 | } | 362 | } |
| 363 | |||
| 364 | // Async | ||
| 365 | 363 | ||
| 366 | /// Can be used by both blocking and async implementations | 364 | /// Can be used by both blocking and async implementations |
| 367 | #[inline] // pretty sure this should always be inlined | 365 | #[inline] // pretty sure this should always be inlined |
| @@ -374,7 +372,6 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 374 | w.set_itevten(true); | 372 | w.set_itevten(true); |
| 375 | }); | 373 | }); |
| 376 | }); | 374 | }); |
| 377 | trace!("I2C slave: safely enabled interrupts"); | ||
| 378 | } | 375 | } |
| 379 | 376 | ||
| 380 | /// Can be used by both blocking and async implementations | 377 | /// Can be used by both blocking and async implementations |
| @@ -383,7 +380,6 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | |||
| 383 | // v1 requires: READ SR1 then WRITE CR1 to clear STOPF | 380 | // v1 requires: READ SR1 then WRITE CR1 to clear STOPF |
| 384 | let _ = info.regs.sr1().read(); | 381 | let _ = info.regs.sr1().read(); |
| 385 | info.regs.cr1().modify(|_| {}); // Dummy write to clear STOPF | 382 | info.regs.cr1().modify(|_| {}); // Dummy write to clear STOPF |
| 386 | trace!("I2C slave: STOPF flag cleared"); | ||
| 387 | } | 383 | } |
| 388 | 384 | ||
| 389 | } | 385 | } |
| @@ -760,6 +756,7 @@ enum ReceiveResult { | |||
| 760 | 756 | ||
| 761 | /// Enumeration of slave transaction termination conditions | 757 | /// Enumeration of slave transaction termination conditions |
| 762 | #[derive(Debug, Clone, Copy, PartialEq)] | 758 | #[derive(Debug, Clone, Copy, PartialEq)] |
| 759 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 763 | enum SlaveTermination { | 760 | enum SlaveTermination { |
| 764 | /// STOP condition received - normal end of transaction | 761 | /// STOP condition received - normal end of transaction |
| 765 | Stop, | 762 | Stop, |
| @@ -887,9 +884,9 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 887 | /// This method blocks until the slave address is matched by a master. | 884 | /// This method blocks until the slave address is matched by a master. |
| 888 | /// Returns the command type (Read/Write) and the matched address. | 885 | /// Returns the command type (Read/Write) and the matched address. |
| 889 | pub fn blocking_listen(&mut self) -> Result<SlaveCommand, Error> { | 886 | pub fn blocking_listen(&mut self) -> Result<SlaveCommand, Error> { |
| 890 | trace!("I2C slave: listening for address match"); | 887 | trace!("I2C slave: starting blocking listen for address match"); |
| 891 | let result = self.blocking_listen_with_timeout(self.timeout()); | 888 | let result = self.blocking_listen_with_timeout(self.timeout()); |
| 892 | trace!("I2C slave: listen result={:?}", result); | 889 | trace!("I2C slave: blocking listen complete, result={:?}", result); |
| 893 | result | 890 | result |
| 894 | } | 891 | } |
| 895 | 892 | ||
| @@ -901,16 +898,15 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 901 | /// | 898 | /// |
| 902 | /// Returns the total number of bytes transmitted (including padding). | 899 | /// Returns the total number of bytes transmitted (including padding). |
| 903 | pub fn blocking_respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> { | 900 | pub fn blocking_respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> { |
| 904 | trace!("I2C slave: responding to read, data_len={}", data.len()); | 901 | trace!("I2C slave: starting blocking respond_to_read, data_len={}", data.len()); |
| 905 | 902 | ||
| 906 | // Check for zero-length read BEFORE any transmission setup | ||
| 907 | if let Some(zero_length_result) = self.detect_zero_length_read(self.timeout())? { | 903 | if let Some(zero_length_result) = self.detect_zero_length_read(self.timeout())? { |
| 908 | trace!("I2C slave: zero-length read detected"); | 904 | trace!("I2C slave: zero-length read detected"); |
| 909 | return Ok(zero_length_result); | 905 | return Ok(zero_length_result); |
| 910 | } | 906 | } |
| 911 | 907 | ||
| 912 | let result = self.transmit_to_master(data, self.timeout()); | 908 | let result = self.transmit_to_master(data, self.timeout()); |
| 913 | trace!("I2C slave: read response complete, result={:?}", result); | 909 | trace!("I2C slave: blocking respond_to_read complete, result={:?}", result); |
| 914 | result | 910 | result |
| 915 | } | 911 | } |
| 916 | 912 | ||
| @@ -922,9 +918,9 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 922 | /// | 918 | /// |
| 923 | /// Returns the number of bytes stored in the buffer (not total received). | 919 | /// Returns the number of bytes stored in the buffer (not total received). |
| 924 | pub fn blocking_respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | 920 | pub fn blocking_respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { |
| 925 | trace!("I2C slave: responding to write, buffer_len={}", buffer.len()); | 921 | trace!("I2C slave: starting blocking respond_to_write, buffer_len={}", buffer.len()); |
| 926 | let result = self.receive_from_master(buffer, self.timeout()); | 922 | let result = self.receive_from_master(buffer, self.timeout()); |
| 927 | trace!("I2C slave: write response complete, result={:?}", result); | 923 | trace!("I2C slave: blocking respond_to_write complete, result={:?}", result); |
| 928 | result | 924 | result |
| 929 | } | 925 | } |
| 930 | 926 | ||
| @@ -965,31 +961,35 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 965 | /// Transmit data to master in response to read request | 961 | /// Transmit data to master in response to read request |
| 966 | fn transmit_to_master(&mut self, data: &[u8], timeout: Timeout) -> Result<usize, Error> { | 962 | fn transmit_to_master(&mut self, data: &[u8], timeout: Timeout) -> Result<usize, Error> { |
| 967 | let mut bytes_transmitted = 0; | 963 | let mut bytes_transmitted = 0; |
| 964 | let mut padding_count = 0; | ||
| 968 | 965 | ||
| 969 | loop { | 966 | loop { |
| 970 | // Determine next byte to send | ||
| 971 | let byte_to_send = if bytes_transmitted < data.len() { | 967 | let byte_to_send = if bytes_transmitted < data.len() { |
| 972 | data[bytes_transmitted] | 968 | data[bytes_transmitted] |
| 973 | } else { | 969 | } else { |
| 970 | padding_count += 1; | ||
| 974 | 0x00 // Send padding bytes when data is exhausted | 971 | 0x00 // Send padding bytes when data is exhausted |
| 975 | }; | 972 | }; |
| 976 | 973 | ||
| 977 | // Attempt to send the byte | ||
| 978 | match self.transmit_byte(byte_to_send, timeout)? { | 974 | match self.transmit_byte(byte_to_send, timeout)? { |
| 979 | TransmitResult::Acknowledged => { | 975 | TransmitResult::Acknowledged => { |
| 980 | bytes_transmitted += 1; | 976 | bytes_transmitted += 1; |
| 981 | // Continue transmission | ||
| 982 | }, | 977 | }, |
| 983 | TransmitResult::NotAcknowledged => { | 978 | TransmitResult::NotAcknowledged => { |
| 984 | bytes_transmitted += 1; // Count the NACKed byte | 979 | bytes_transmitted += 1; // Count the NACKed byte |
| 985 | break; // Normal end of read transaction | 980 | break; |
| 986 | }, | 981 | }, |
| 987 | TransmitResult::Stopped | TransmitResult::Restarted => { | 982 | TransmitResult::Stopped | TransmitResult::Restarted => { |
| 988 | break; // Transaction terminated by master | 983 | break; |
| 989 | } | 984 | } |
| 990 | } | 985 | } |
| 991 | } | 986 | } |
| 992 | 987 | ||
| 988 | if padding_count > 0 { | ||
| 989 | trace!("I2C slave: sent {} data bytes + {} padding bytes = {} total", | ||
| 990 | data.len(), padding_count, bytes_transmitted); | ||
| 991 | } | ||
| 992 | |||
| 993 | Ok(bytes_transmitted) | 993 | Ok(bytes_transmitted) |
| 994 | } | 994 | } |
| 995 | 995 | ||
| @@ -1076,14 +1076,19 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 1076 | 1076 | ||
| 1077 | /// Discard excess bytes when buffer is full | 1077 | /// Discard excess bytes when buffer is full |
| 1078 | fn discard_excess_bytes(&mut self, timeout: Timeout) -> Result<(), Error> { | 1078 | fn discard_excess_bytes(&mut self, timeout: Timeout) -> Result<(), Error> { |
| 1079 | let mut discarded_count = 0; | ||
| 1080 | |||
| 1079 | loop { | 1081 | loop { |
| 1080 | match self.receive_byte(timeout)? { | 1082 | match self.receive_byte(timeout)? { |
| 1081 | ReceiveResult::Data(_) => { | 1083 | ReceiveResult::Data(_) => { |
| 1082 | // Byte received and ACKed, but discarded | 1084 | discarded_count += 1; |
| 1083 | continue; | 1085 | continue; |
| 1084 | }, | 1086 | }, |
| 1085 | ReceiveResult::Stopped | ReceiveResult::Restarted => { | 1087 | ReceiveResult::Stopped | ReceiveResult::Restarted => { |
| 1086 | break; // Transaction completed | 1088 | if discarded_count > 0 { |
| 1089 | trace!("I2C slave: discarded {} excess bytes", discarded_count); | ||
| 1090 | } | ||
| 1091 | break; | ||
| 1087 | }, | 1092 | }, |
| 1088 | } | 1093 | } |
| 1089 | } | 1094 | } |
| @@ -1316,12 +1321,12 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1316 | /// (Read/Write) and the matched address. This method will suspend until | 1321 | /// (Read/Write) and the matched address. This method will suspend until |
| 1317 | /// an address match occurs. | 1322 | /// an address match occurs. |
| 1318 | pub async fn listen(&mut self) -> Result<SlaveCommand, Error> { | 1323 | pub async fn listen(&mut self) -> Result<SlaveCommand, Error> { |
| 1324 | trace!("I2C slave: starting async listen for address match"); | ||
| 1319 | let state = self.state; | 1325 | let state = self.state; |
| 1320 | let info = self.info; | 1326 | let info = self.info; |
| 1321 | 1327 | ||
| 1322 | Self::enable_interrupts(info); | 1328 | Self::enable_interrupts(info); |
| 1323 | 1329 | ||
| 1324 | // Ensure interrupts are cleaned up on early exit | ||
| 1325 | let on_drop = OnDrop::new(|| { | 1330 | let on_drop = OnDrop::new(|| { |
| 1326 | Self::disable_dma_and_interrupts(info); | 1331 | Self::disable_dma_and_interrupts(info); |
| 1327 | }); | 1332 | }); |
| @@ -1330,10 +1335,12 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1330 | state.waker.register(cx.waker()); | 1335 | state.waker.register(cx.waker()); |
| 1331 | 1336 | ||
| 1332 | match Self::check_and_clear_error_flags(info) { | 1337 | match Self::check_and_clear_error_flags(info) { |
| 1333 | Err(e) => Poll::Ready(Err(e)), | 1338 | Err(e) => { |
| 1339 | error!("I2C slave: error during listen: {:?}", e); | ||
| 1340 | Poll::Ready(Err(e)) | ||
| 1341 | }, | ||
| 1334 | Ok(sr1) => { | 1342 | Ok(sr1) => { |
| 1335 | if sr1.addr() { | 1343 | if sr1.addr() { |
| 1336 | // Address matched - determine direction and decode address | ||
| 1337 | let sr2 = info.regs.sr2().read(); | 1344 | let sr2 = info.regs.sr2().read(); |
| 1338 | let direction = if sr2.tra() { | 1345 | let direction = if sr2.tra() { |
| 1339 | SlaveCommandKind::Read | 1346 | SlaveCommandKind::Read |
| @@ -1342,11 +1349,16 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1342 | }; | 1349 | }; |
| 1343 | 1350 | ||
| 1344 | let matched_address = match Self::decode_matched_address(sr2, info) { | 1351 | let matched_address = match Self::decode_matched_address(sr2, info) { |
| 1345 | Ok(addr) => addr, | 1352 | Ok(addr) => { |
| 1346 | Err(e) => return Poll::Ready(Err(e)), | 1353 | trace!("I2C slave: address matched, direction={:?}, addr={:?}", direction, addr); |
| 1354 | addr | ||
| 1355 | }, | ||
| 1356 | Err(e) => { | ||
| 1357 | error!("I2C slave: failed to decode matched address: {:?}", e); | ||
| 1358 | return Poll::Ready(Err(e)); | ||
| 1359 | } | ||
| 1347 | }; | 1360 | }; |
| 1348 | 1361 | ||
| 1349 | // Don't clear ADDR here - leave it for DMA setup in respond methods | ||
| 1350 | Poll::Ready(Ok(SlaveCommand { | 1362 | Poll::Ready(Ok(SlaveCommand { |
| 1351 | kind: direction, | 1363 | kind: direction, |
| 1352 | address: matched_address, | 1364 | address: matched_address, |
| @@ -1360,6 +1372,7 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1360 | }).await; | 1372 | }).await; |
| 1361 | 1373 | ||
| 1362 | drop(on_drop); | 1374 | drop(on_drop); |
| 1375 | trace!("I2C slave: listen complete, result={:?}", result); | ||
| 1363 | result | 1376 | result |
| 1364 | } | 1377 | } |
| 1365 | 1378 | ||
| @@ -1371,28 +1384,28 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1371 | /// | 1384 | /// |
| 1372 | /// Returns the number of bytes stored in the buffer (not total received). | 1385 | /// Returns the number of bytes stored in the buffer (not total received). |
| 1373 | pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { | 1386 | pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { |
| 1387 | trace!("I2C slave: starting respond_to_write, buffer_len={}", buffer.len()); | ||
| 1388 | |||
| 1374 | if buffer.is_empty() { | 1389 | if buffer.is_empty() { |
| 1390 | warn!("I2C slave: respond_to_write called with empty buffer"); | ||
| 1375 | return Err(Error::Overrun); | 1391 | return Err(Error::Overrun); |
| 1376 | } | 1392 | } |
| 1377 | 1393 | ||
| 1378 | let state = self.state; | 1394 | let state = self.state; |
| 1379 | let info = self.info; | 1395 | let info = self.info; |
| 1380 | 1396 | ||
| 1381 | // Use shared DMA setup | ||
| 1382 | self.setup_slave_dma_base(); | 1397 | self.setup_slave_dma_base(); |
| 1383 | 1398 | ||
| 1384 | // Ensure proper cleanup on exit | ||
| 1385 | let on_drop = OnDrop::new(|| { | 1399 | let on_drop = OnDrop::new(|| { |
| 1386 | Self::disable_dma_and_interrupts(info); | 1400 | Self::disable_dma_and_interrupts(info); |
| 1387 | }); | 1401 | }); |
| 1388 | 1402 | ||
| 1389 | // Clear ADDR flag to release clock stretching | ||
| 1390 | info.regs.sr2().read(); | 1403 | info.regs.sr2().read(); |
| 1391 | 1404 | ||
| 1392 | // Start DMA transfer and monitor completion | ||
| 1393 | let result = self.execute_slave_receive_transfer(buffer, state, info).await; | 1405 | let result = self.execute_slave_receive_transfer(buffer, state, info).await; |
| 1394 | 1406 | ||
| 1395 | drop(on_drop); | 1407 | drop(on_drop); |
| 1408 | trace!("I2C slave: respond_to_write complete, result={:?}", result); | ||
| 1396 | result | 1409 | result |
| 1397 | } | 1410 | } |
| 1398 | 1411 | ||
| @@ -1404,28 +1417,28 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1404 | /// | 1417 | /// |
| 1405 | /// Returns the total number of bytes transmitted (data + padding). | 1418 | /// Returns the total number of bytes transmitted (data + padding). |
| 1406 | pub async fn respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> { | 1419 | pub async fn respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> { |
| 1420 | trace!("I2C slave: starting respond_to_read, data_len={}", data.len()); | ||
| 1421 | |||
| 1407 | if data.is_empty() { | 1422 | if data.is_empty() { |
| 1423 | warn!("I2C slave: respond_to_read called with empty data"); | ||
| 1408 | return Err(Error::Overrun); | 1424 | return Err(Error::Overrun); |
| 1409 | } | 1425 | } |
| 1410 | 1426 | ||
| 1411 | let state = self.state; | 1427 | let state = self.state; |
| 1412 | let info = self.info; | 1428 | let info = self.info; |
| 1413 | 1429 | ||
| 1414 | // Use shared DMA setup | ||
| 1415 | self.setup_slave_dma_base(); | 1430 | self.setup_slave_dma_base(); |
| 1416 | 1431 | ||
| 1417 | // Ensure proper cleanup on exit | ||
| 1418 | let on_drop = OnDrop::new(|| { | 1432 | let on_drop = OnDrop::new(|| { |
| 1419 | Self::disable_dma_and_interrupts(info); | 1433 | Self::disable_dma_and_interrupts(info); |
| 1420 | }); | 1434 | }); |
| 1421 | 1435 | ||
| 1422 | // Clear ADDR flag to release clock stretching | ||
| 1423 | info.regs.sr2().read(); | 1436 | info.regs.sr2().read(); |
| 1424 | 1437 | ||
| 1425 | // Start DMA transfer and monitor completion | ||
| 1426 | let result = self.execute_slave_transmit_transfer(data, state, info).await; | 1438 | let result = self.execute_slave_transmit_transfer(data, state, info).await; |
| 1427 | 1439 | ||
| 1428 | drop(on_drop); | 1440 | drop(on_drop); |
| 1441 | trace!("I2C slave: respond_to_read complete, result={:?}", result); | ||
| 1429 | result | 1442 | result |
| 1430 | } | 1443 | } |
| 1431 | 1444 | ||
| @@ -1438,28 +1451,27 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1438 | state: &'static State, | 1451 | state: &'static State, |
| 1439 | info: &'static Info | 1452 | info: &'static Info |
| 1440 | ) -> Result<usize, Error> { | 1453 | ) -> Result<usize, Error> { |
| 1441 | // Start DMA transfer | ||
| 1442 | let dma_transfer = unsafe { | 1454 | let dma_transfer = unsafe { |
| 1443 | let src = info.regs.dr().as_ptr() as *mut u8; | 1455 | let src = info.regs.dr().as_ptr() as *mut u8; |
| 1444 | self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) | 1456 | self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) |
| 1445 | }; | 1457 | }; |
| 1446 | 1458 | ||
| 1447 | // Monitor for I2C events during transfer | ||
| 1448 | let i2c_monitor = Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart]); | 1459 | let i2c_monitor = Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart]); |
| 1449 | 1460 | ||
| 1450 | match select(dma_transfer, i2c_monitor).await { | 1461 | match select(dma_transfer, i2c_monitor).await { |
| 1451 | Either::Second(Err(e)) => { | 1462 | Either::Second(Err(e)) => { |
| 1463 | error!("I2C slave: error during receive transfer: {:?}", e); | ||
| 1452 | Self::disable_dma_and_interrupts(info); | 1464 | Self::disable_dma_and_interrupts(info); |
| 1453 | Err(e) | 1465 | Err(e) |
| 1454 | } | 1466 | } |
| 1455 | Either::First(_) => { | 1467 | Either::First(_) => { |
| 1456 | // DMA completed first - handle potential excess bytes | 1468 | trace!("I2C slave: DMA receive completed, handling excess bytes"); |
| 1457 | Self::disable_dma_and_interrupts(info); | 1469 | Self::disable_dma_and_interrupts(info); |
| 1458 | self.handle_excess_bytes(state, info).await?; | 1470 | self.handle_excess_bytes(state, info).await?; |
| 1459 | Ok(buffer.len()) | 1471 | Ok(buffer.len()) |
| 1460 | } | 1472 | } |
| 1461 | Either::Second(Ok(_)) => { | 1473 | Either::Second(Ok(termination)) => { |
| 1462 | // I2C event occurred first - normal transaction end | 1474 | trace!("I2C slave: receive terminated by I2C event: {:?}", termination); |
| 1463 | Self::disable_dma_and_interrupts(info); | 1475 | Self::disable_dma_and_interrupts(info); |
| 1464 | Ok(buffer.len()) | 1476 | Ok(buffer.len()) |
| 1465 | } | 1477 | } |
| @@ -1473,28 +1485,30 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1473 | state: &'static State, | 1485 | state: &'static State, |
| 1474 | info: &'static Info | 1486 | info: &'static Info |
| 1475 | ) -> Result<usize, Error> { | 1487 | ) -> Result<usize, Error> { |
| 1476 | // Start DMA transfer | ||
| 1477 | let dma_transfer = unsafe { | 1488 | let dma_transfer = unsafe { |
| 1478 | let dst = info.regs.dr().as_ptr() as *mut u8; | 1489 | let dst = info.regs.dr().as_ptr() as *mut u8; |
| 1479 | self.tx_dma.as_mut().unwrap().write(data, dst, Default::default()) | 1490 | self.tx_dma.as_mut().unwrap().write(data, dst, Default::default()) |
| 1480 | }; | 1491 | }; |
| 1481 | 1492 | ||
| 1482 | // Monitor for I2C events during transfer (NACK is normal for slave transmit) | ||
| 1483 | let i2c_monitor = Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart, SlaveTermination::Nack]); | 1493 | let i2c_monitor = Self::create_termination_monitor(state, info, &[SlaveTermination::Stop, SlaveTermination::Restart, SlaveTermination::Nack]); |
| 1484 | 1494 | ||
| 1485 | match select(dma_transfer, i2c_monitor).await { | 1495 | match select(dma_transfer, i2c_monitor).await { |
| 1486 | Either::Second(Err(e)) => { | 1496 | Either::Second(Err(e)) => { |
| 1497 | error!("I2C slave: error during transmit transfer: {:?}", e); | ||
| 1487 | Self::disable_dma_and_interrupts(info); | 1498 | Self::disable_dma_and_interrupts(info); |
| 1488 | Err(e) | 1499 | Err(e) |
| 1489 | } | 1500 | } |
| 1490 | Either::First(_) => { | 1501 | Either::First(_) => { |
| 1491 | // DMA completed first - handle potential padding bytes | 1502 | trace!("I2C slave: DMA transmit completed, handling padding bytes"); |
| 1492 | Self::disable_dma_and_interrupts(info); | 1503 | Self::disable_dma_and_interrupts(info); |
| 1493 | let padding_count = self.handle_padding_bytes(state, info).await?; | 1504 | let padding_count = self.handle_padding_bytes(state, info).await?; |
| 1494 | Ok(data.len() + padding_count) | 1505 | let total_bytes = data.len() + padding_count; |
| 1506 | trace!("I2C slave: sent {} data bytes + {} padding bytes = {} total", | ||
| 1507 | data.len(), padding_count, total_bytes); | ||
| 1508 | Ok(total_bytes) | ||
| 1495 | } | 1509 | } |
| 1496 | Either::Second(Ok(_)) => { | 1510 | Either::Second(Ok(termination)) => { |
| 1497 | // I2C event occurred first - normal transaction end | 1511 | trace!("I2C slave: transmit terminated by I2C event: {:?}", termination); |
| 1498 | Self::disable_dma_and_interrupts(info); | 1512 | Self::disable_dma_and_interrupts(info); |
| 1499 | Ok(data.len()) | 1513 | Ok(data.len()) |
| 1500 | } | 1514 | } |
| @@ -1549,25 +1563,32 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1549 | /// | 1563 | /// |
| 1550 | /// Reads and discards bytes until transaction termination to prevent interrupt flooding | 1564 | /// Reads and discards bytes until transaction termination to prevent interrupt flooding |
| 1551 | async fn handle_excess_bytes(&mut self, state: &'static State, info: &'static Info) -> Result<(), Error> { | 1565 | async fn handle_excess_bytes(&mut self, state: &'static State, info: &'static Info) -> Result<(), Error> { |
| 1566 | let mut discarded_count = 0; | ||
| 1567 | |||
| 1552 | poll_fn(|cx| { | 1568 | poll_fn(|cx| { |
| 1553 | state.waker.register(cx.waker()); | 1569 | state.waker.register(cx.waker()); |
| 1554 | 1570 | ||
| 1555 | match Self::check_and_clear_error_flags(info) { | 1571 | match Self::check_and_clear_error_flags(info) { |
| 1556 | Err(e) => Poll::Ready(Err(e)), | 1572 | Err(e) => { |
| 1573 | error!("I2C slave: error while discarding excess bytes: {:?}", e); | ||
| 1574 | Poll::Ready(Err(e)) | ||
| 1575 | }, | ||
| 1557 | Ok(sr1) => { | 1576 | Ok(sr1) => { |
| 1558 | // Check for transaction termination first | ||
| 1559 | if let Some(termination) = Self::check_slave_termination_conditions(sr1) { | 1577 | if let Some(termination) = Self::check_slave_termination_conditions(sr1) { |
| 1560 | match termination { | 1578 | match termination { |
| 1561 | SlaveTermination::Stop => Self::clear_stop_flag(info), | 1579 | SlaveTermination::Stop => Self::clear_stop_flag(info), |
| 1562 | SlaveTermination::Restart => {}, // Leave ADDR for next operation | 1580 | SlaveTermination::Restart => {}, |
| 1563 | SlaveTermination::Nack => unreachable!("NACK not expected during receive"), | 1581 | SlaveTermination::Nack => unreachable!("NACK not expected during receive"), |
| 1564 | } | 1582 | } |
| 1583 | if discarded_count > 0 { | ||
| 1584 | trace!("I2C slave: discarded {} excess bytes", discarded_count); | ||
| 1585 | } | ||
| 1565 | return Poll::Ready(Ok(())); | 1586 | return Poll::Ready(Ok(())); |
| 1566 | } | 1587 | } |
| 1567 | 1588 | ||
| 1568 | // If there's data to read, discard it | ||
| 1569 | if sr1.rxne() { | 1589 | if sr1.rxne() { |
| 1570 | let _discarded_byte = info.regs.dr().read().dr(); | 1590 | let _discarded_byte = info.regs.dr().read().dr(); |
| 1591 | discarded_count += 1; | ||
| 1571 | Self::enable_interrupts(info); | 1592 | Self::enable_interrupts(info); |
| 1572 | return Poll::Pending; | 1593 | return Poll::Pending; |
| 1573 | } | 1594 | } |
| @@ -1589,14 +1610,16 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1589 | state.waker.register(cx.waker()); | 1610 | state.waker.register(cx.waker()); |
| 1590 | 1611 | ||
| 1591 | match Self::check_and_clear_error_flags(info) { | 1612 | match Self::check_and_clear_error_flags(info) { |
| 1592 | Err(Error::Nack) => Poll::Ready(Ok(padding_count)), // Normal termination | 1613 | Err(Error::Nack) => Poll::Ready(Ok(padding_count)), |
| 1593 | Err(e) => Poll::Ready(Err(e)), | 1614 | Err(e) => { |
| 1615 | error!("I2C slave: error while sending padding bytes: {:?}", e); | ||
| 1616 | Poll::Ready(Err(e)) | ||
| 1617 | }, | ||
| 1594 | Ok(sr1) => { | 1618 | Ok(sr1) => { |
| 1595 | // Check for transaction termination first | ||
| 1596 | if let Some(termination) = Self::check_slave_termination_conditions(sr1) { | 1619 | if let Some(termination) = Self::check_slave_termination_conditions(sr1) { |
| 1597 | match termination { | 1620 | match termination { |
| 1598 | SlaveTermination::Stop => Self::clear_stop_flag(info), | 1621 | SlaveTermination::Stop => Self::clear_stop_flag(info), |
| 1599 | SlaveTermination::Restart => {}, // Leave ADDR for next operation | 1622 | SlaveTermination::Restart => {}, |
| 1600 | SlaveTermination::Nack => { | 1623 | SlaveTermination::Nack => { |
| 1601 | info.regs.sr1().write(|reg| { | 1624 | info.regs.sr1().write(|reg| { |
| 1602 | reg.0 = !0; | 1625 | reg.0 = !0; |
| @@ -1607,7 +1630,6 @@ impl<'d> I2c<'d, Async, MultiMaster> { | |||
| 1607 | return Poll::Ready(Ok(padding_count)); | 1630 | return Poll::Ready(Ok(padding_count)); |
| 1608 | } | 1631 | } |
| 1609 | 1632 | ||
| 1610 | // If transmit buffer is empty, send padding byte | ||
| 1611 | if sr1.txe() { | 1633 | if sr1.txe() { |
| 1612 | info.regs.dr().write(|w| w.set_dr(0x00)); | 1634 | info.regs.dr().write(|w| w.set_dr(0x00)); |
| 1613 | padding_count += 1; | 1635 | padding_count += 1; |
