aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKnaifhogg <[email protected]>2025-06-18 08:26:12 +0200
committerDario Nieuwenhuis <[email protected]>2025-07-24 23:56:49 +0200
commit9863406346fdf5defcb8fe8de4bb5d122fa0b05f (patch)
treeabe3089de5e0ab524ab73db4916b3303b706916e
parent915513753aea689f73d1300acc069ac985be3a0b (diff)
fix: stm32 i2c slave blocking r/w
This fixes an issue where the slave interface would time out when the master goes from a short write to a read (e.g. when accessing memory registers) with a START signal between. The previous implementation would expect the full buffer length to be written before starting to listen to new commands. This also adds debug trace printing which helped during implemention and testing. Places error checking into a function inspired from a C implementation of HAL.
-rw-r--r--embassy-stm32/Cargo.toml1
-rw-r--r--embassy-stm32/src/i2c/v2.rs278
2 files changed, 221 insertions, 58 deletions
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 38254ee40..02e75733e 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -129,6 +129,7 @@ defmt = [
129 "embassy-net-driver/defmt", 129 "embassy-net-driver/defmt",
130 "embassy-time?/defmt", 130 "embassy-time?/defmt",
131 "embassy-usb-synopsys-otg/defmt", 131 "embassy-usb-synopsys-otg/defmt",
132 "stm32-metapac/defmt"
132] 133]
133 134
134exti = [] 135exti = []
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 35dc91c86..e24cce5c6 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -36,11 +36,46 @@ impl Address {
36 } 36 }
37} 37}
38 38
39enum ReceiveResult {
40 DataAvailable,
41 StopReceived,
42 NewStart,
43}
44
45fn debug_print_interrupts(isr: stm32_metapac::i2c::regs::Isr) {
46 if isr.tcr() {
47 trace!("interrupt: tcr");
48 }
49 if isr.tc() {
50 trace!("interrupt: tc");
51 }
52 if isr.addr() {
53 trace!("interrupt: addr");
54 }
55 if isr.stopf() {
56 trace!("interrupt: stopf");
57 }
58 if isr.nackf() {
59 trace!("interrupt: nackf");
60 }
61 if isr.berr() {
62 trace!("interrupt: berr");
63 }
64 if isr.arlo() {
65 trace!("interrupt: arlo");
66 }
67 if isr.ovr() {
68 trace!("interrupt: ovr");
69 }
70}
71
39pub(crate) unsafe fn on_interrupt<T: Instance>() { 72pub(crate) unsafe fn on_interrupt<T: Instance>() {
40 let regs = T::info().regs; 73 let regs = T::info().regs;
41 let isr = regs.isr().read(); 74 let isr = regs.isr().read();
42 75
43 if isr.tcr() || isr.tc() || isr.addr() || isr.stopf() || isr.nackf() || isr.berr() || isr.arlo() || isr.ovr() { 76 if isr.tcr() || isr.tc() || isr.addr() || isr.stopf() || isr.nackf() || isr.berr() || isr.arlo() || isr.ovr() {
77 debug_print_interrupts(isr);
78
44 T::state().waker.wake(); 79 T::state().waker.wake();
45 } 80 }
46 81
@@ -193,49 +228,132 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
193 228
194 fn flush_txdr(&self) { 229 fn flush_txdr(&self) {
195 if self.info.regs.isr().read().txis() { 230 if self.info.regs.isr().read().txis() {
196 self.info.regs.txdr().write(|w| w.set_txdata(0)); 231 trace!("Flush TXDATA with zeroes");
232 self.info.regs.txdr().modify(|w| w.set_txdata(0));
197 } 233 }
198 if !self.info.regs.isr().read().txe() { 234 if !self.info.regs.isr().read().txe() {
235 trace!("Flush TXDR");
199 self.info.regs.isr().modify(|w| w.set_txe(true)) 236 self.info.regs.isr().modify(|w| w.set_txe(true))
200 } 237 }
201 } 238 }
202 239
203 fn wait_txe(&self, timeout: Timeout) -> Result<(), Error> { 240 fn error_occurred(&self, isr: &i2c::regs::Isr, timeout: Timeout) -> Result<(), Error> {
241 if isr.nackf() {
242 trace!("NACK triggered.");
243 self.info.regs.icr().modify(|reg| reg.set_nackcf(true));
244 // NACK should be followed by STOP
245 if let Ok(()) = self.wait_stop(timeout) {
246 trace!("Got STOP after NACK, clearing flag.");
247 self.info.regs.icr().modify(|reg| reg.set_stopcf(true));
248 }
249 self.flush_txdr();
250 return Err(Error::Nack);
251 } else if isr.berr() {
252 trace!("BERR triggered.");
253 self.info.regs.icr().modify(|reg| reg.set_berrcf(true));
254 self.flush_txdr();
255 return Err(Error::Bus);
256 } else if isr.arlo() {
257 trace!("ARLO triggered.");
258 self.info.regs.icr().modify(|reg| reg.set_arlocf(true));
259 self.flush_txdr();
260 return Err(Error::Arbitration);
261 } else if isr.ovr() {
262 trace!("OVR triggered.");
263 self.info.regs.icr().modify(|reg| reg.set_ovrcf(true));
264 return Err(Error::Overrun);
265 }
266 return Ok(());
267 }
268
269 fn wait_txis(&self, timeout: Timeout) -> Result<(), Error> {
270 let mut first_loop = true;
271
204 loop { 272 loop {
205 let isr = self.info.regs.isr().read(); 273 let isr = self.info.regs.isr().read();
206 if isr.txe() { 274 self.error_occurred(&isr, timeout)?;
275 if isr.txis() {
276 trace!("TXIS");
207 return Ok(()); 277 return Ok(());
208 } else if isr.berr() {
209 self.info.regs.icr().write(|reg| reg.set_berrcf(true));
210 return Err(Error::Bus);
211 } else if isr.arlo() {
212 self.info.regs.icr().write(|reg| reg.set_arlocf(true));
213 return Err(Error::Arbitration);
214 } else if isr.nackf() {
215 self.info.regs.icr().write(|reg| reg.set_nackcf(true));
216 self.flush_txdr();
217 return Err(Error::Nack);
218 } 278 }
219 279
280 {
281 if first_loop {
282 trace!("Waiting for TXIS...");
283 first_loop = false;
284 }
285 }
220 timeout.check()?; 286 timeout.check()?;
221 } 287 }
222 } 288 }
223 289
224 fn wait_rxne(&self, timeout: Timeout) -> Result<(), Error> { 290 fn wait_stop_or_err(&self, timeout: Timeout) -> Result<(), Error> {
291 loop {
292 let isr = self.info.regs.isr().read();
293 self.error_occurred(&isr, timeout)?;
294 if isr.stopf() {
295 trace!("STOP triggered.");
296 self.info.regs.icr().modify(|reg| reg.set_stopcf(true));
297 return Ok(());
298 }
299 timeout.check()?;
300 }
301 }
302 fn wait_stop(&self, timeout: Timeout) -> Result<(), Error> {
225 loop { 303 loop {
226 let isr = self.info.regs.isr().read(); 304 let isr = self.info.regs.isr().read();
227 if isr.rxne() { 305 if isr.stopf() {
306 trace!("STOP triggered.");
307 self.info.regs.icr().modify(|reg| reg.set_stopcf(true));
228 return Ok(()); 308 return Ok(());
229 } else if isr.berr() { 309 }
230 self.info.regs.icr().write(|reg| reg.set_berrcf(true)); 310 timeout.check()?;
231 return Err(Error::Bus); 311 }
232 } else if isr.arlo() { 312 }
233 self.info.regs.icr().write(|reg| reg.set_arlocf(true)); 313
234 return Err(Error::Arbitration); 314 fn wait_af(&self, timeout: Timeout) -> Result<(), Error> {
235 } else if isr.nackf() { 315 loop {
236 self.info.regs.icr().write(|reg| reg.set_nackcf(true)); 316 let isr = self.info.regs.isr().read();
237 self.flush_txdr(); 317 if isr.nackf() {
238 return Err(Error::Nack); 318 trace!("AF triggered.");
319 self.info.regs.icr().modify(|reg| reg.set_nackcf(true));
320 return Ok(());
321 }
322 timeout.check()?;
323 }
324 }
325
326 fn wait_rxne(&self, timeout: Timeout) -> Result<ReceiveResult, Error> {
327 let mut first_loop = true;
328
329 loop {
330 let isr = self.info.regs.isr().read();
331 self.error_occurred(&isr, timeout)?;
332 if isr.stopf() {
333 trace!("STOP when waiting for RXNE.");
334 if self.info.regs.isr().read().rxne() {
335 trace!("Data received with STOP.");
336 return Ok(ReceiveResult::DataAvailable);
337 }
338 trace!("STOP triggered without data.");
339 return Ok(ReceiveResult::StopReceived);
340 } else if isr.rxne() {
341 trace!("RXNE.");
342 return Ok(ReceiveResult::DataAvailable);
343 } else if isr.addr() {
344 // Another addr event received, which means START was sent again
345 // which happens when accessing memory registers (common i2c interface design)
346 // e.g. master sends: START, write 1 byte (register index), START, read N bytes (until NACK)
347 // Possible to receive this flag at the same time as rxne, so check rxne first
348 trace!("START when waiting for RXNE. Ending receive loop.");
349 // Return without clearing ADDR so `listen` can catch it
350 return Ok(ReceiveResult::NewStart);
351 }
352 {
353 if first_loop {
354 trace!("Waiting for RXNE...");
355 first_loop = false;
356 }
239 } 357 }
240 358
241 timeout.check()?; 359 timeout.check()?;
@@ -245,20 +363,10 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
245 fn wait_tc(&self, timeout: Timeout) -> Result<(), Error> { 363 fn wait_tc(&self, timeout: Timeout) -> Result<(), Error> {
246 loop { 364 loop {
247 let isr = self.info.regs.isr().read(); 365 let isr = self.info.regs.isr().read();
366 self.error_occurred(&isr, timeout)?;
248 if isr.tc() { 367 if isr.tc() {
249 return Ok(()); 368 return Ok(());
250 } else if isr.berr() {
251 self.info.regs.icr().write(|reg| reg.set_berrcf(true));
252 return Err(Error::Bus);
253 } else if isr.arlo() {
254 self.info.regs.icr().write(|reg| reg.set_arlocf(true));
255 return Err(Error::Arbitration);
256 } else if isr.nackf() {
257 self.info.regs.icr().write(|reg| reg.set_nackcf(true));
258 self.flush_txdr();
259 return Err(Error::Nack);
260 } 369 }
261
262 timeout.check()?; 370 timeout.check()?;
263 } 371 }
264 } 372 }
@@ -344,7 +452,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
344 // Wait until we are allowed to send data 452 // Wait until we are allowed to send data
345 // (START has been ACKed or last byte when 453 // (START has been ACKed or last byte when
346 // through) 454 // through)
347 if let Err(err) = self.wait_txe(timeout) { 455 if let Err(err) = self.wait_txis(timeout) {
348 if send_stop { 456 if send_stop {
349 self.master_stop(); 457 self.master_stop();
350 } 458 }
@@ -459,7 +567,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
459 // Wait until we are allowed to send data 567 // Wait until we are allowed to send data
460 // (START has been ACKed or last byte when 568 // (START has been ACKed or last byte when
461 // through) 569 // through)
462 if let Err(err) = self.wait_txe(timeout) { 570 if let Err(err) = self.wait_txis(timeout) {
463 self.master_stop(); 571 self.master_stop();
464 return Err(err); 572 return Err(err);
465 } 573 }
@@ -884,10 +992,11 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
884 // clear the address flag, will stop the clock stretching. 992 // clear the address flag, will stop the clock stretching.
885 // this should only be done after the dma transfer has been set up. 993 // this should only be done after the dma transfer has been set up.
886 info.regs.icr().modify(|reg| reg.set_addrcf(true)); 994 info.regs.icr().modify(|reg| reg.set_addrcf(true));
995 trace!("ADDRCF cleared (ADDR interrupt enabled, clock stretching ended)");
887 } 996 }
888 997
889 // A blocking read operation 998 // A blocking read operation
890 fn slave_read_internal(&self, read: &mut [u8], timeout: Timeout) -> Result<(), Error> { 999 fn slave_read_internal(&self, read: &mut [u8], timeout: Timeout) -> Result<usize, Error> {
891 let completed_chunks = read.len() / 255; 1000 let completed_chunks = read.len() / 255;
892 let total_chunks = if completed_chunks * 255 == read.len() { 1001 let total_chunks = if completed_chunks * 255 == read.len() {
893 completed_chunks 1002 completed_chunks
@@ -895,20 +1004,46 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
895 completed_chunks + 1 1004 completed_chunks + 1
896 }; 1005 };
897 let last_chunk_idx = total_chunks.saturating_sub(1); 1006 let last_chunk_idx = total_chunks.saturating_sub(1);
1007 let total_len = read.len();
1008 let mut remaining_len = total_len;
1009
898 for (number, chunk) in read.chunks_mut(255).enumerate() { 1010 for (number, chunk) in read.chunks_mut(255).enumerate() {
899 if number != 0 { 1011 trace!(
1012 "--- Slave RX transmission start - chunk: {}, expected (max) size: {}",
1013 number,
1014 chunk.len()
1015 );
1016 if number == 0 {
1017 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx);
1018 } else {
900 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 1019 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?;
901 } 1020 }
902 1021
1022 let mut index = 0;
1023
903 for byte in chunk { 1024 for byte in chunk {
904 // Wait until we have received something 1025 // Wait until we have received something
905 self.wait_rxne(timeout)?; 1026 match self.wait_rxne(timeout) {
906 1027 Ok(ReceiveResult::StopReceived) | Ok(ReceiveResult::NewStart) => {
907 *byte = self.info.regs.rxdr().read().rxdata(); 1028 trace!("--- Slave RX transmission end (early)");
1029 return Ok(total_len - remaining_len); // Return N bytes read
1030 }
1031 Ok(ReceiveResult::DataAvailable) => {
1032 *byte = self.info.regs.rxdr().read().rxdata();
1033 remaining_len = remaining_len.saturating_sub(1);
1034 {
1035 trace!("Slave RX data {}: {:#04x}", index, byte);
1036 index = index + 1;
1037 }
1038 }
1039 Err(e) => return Err(e),
1040 };
908 } 1041 }
909 } 1042 }
1043 self.wait_stop_or_err(timeout)?;
910 1044
911 Ok(()) 1045 trace!("--- Slave RX transmission end");
1046 Ok(total_len - remaining_len) // Return N bytes read
912 } 1047 }
913 1048
914 // A blocking write operation 1049 // A blocking write operation
@@ -922,19 +1057,36 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
922 let last_chunk_idx = total_chunks.saturating_sub(1); 1057 let last_chunk_idx = total_chunks.saturating_sub(1);
923 1058
924 for (number, chunk) in write.chunks(255).enumerate() { 1059 for (number, chunk) in write.chunks(255).enumerate() {
925 if number != 0 { 1060 trace!(
1061 "--- Slave TX transmission start - chunk: {}, size: {}",
1062 number,
1063 chunk.len()
1064 );
1065 if number == 0 {
1066 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx);
1067 } else {
926 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 1068 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?;
927 } 1069 }
928 1070
1071 let mut index = 0;
1072
929 for byte in chunk { 1073 for byte in chunk {
930 // Wait until we are allowed to send data 1074 // Wait until we are allowed to send data
931 // (START has been ACKed or last byte when 1075 // (START has been ACKed or last byte when through)
932 // through) 1076 self.wait_txis(timeout)?;
933 self.wait_txe(timeout)?;
934 1077
1078 {
1079 trace!("Slave TX data {}: {:#04x}", index, byte);
1080 index = index + 1;
1081 }
935 self.info.regs.txdr().write(|w| w.set_txdata(*byte)); 1082 self.info.regs.txdr().write(|w| w.set_txdata(*byte));
936 } 1083 }
937 } 1084 }
1085 self.wait_af(timeout)?;
1086 self.flush_txdr();
1087 self.wait_stop_or_err(timeout)?;
1088
1089 trace!("--- Slave TX transmission end");
938 Ok(()) 1090 Ok(())
939 } 1091 }
940 1092
@@ -945,6 +1097,7 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
945 let state = self.state; 1097 let state = self.state;
946 self.info.regs.cr1().modify(|reg| { 1098 self.info.regs.cr1().modify(|reg| {
947 reg.set_addrie(true); 1099 reg.set_addrie(true);
1100 trace!("Enable ADDRIE");
948 }); 1101 });
949 1102
950 poll_fn(|cx| { 1103 poll_fn(|cx| {
@@ -953,17 +1106,24 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
953 if !isr.addr() { 1106 if !isr.addr() {
954 Poll::Pending 1107 Poll::Pending
955 } else { 1108 } else {
1109 trace!("ADDR triggered (address match)");
956 // we do not clear the address flag here as it will be cleared by the dma read/write 1110 // we do not clear the address flag here as it will be cleared by the dma read/write
957 // if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it 1111 // if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it
958 match isr.dir() { 1112 match isr.dir() {
959 i2c::vals::Dir::WRITE => Poll::Ready(Ok(SlaveCommand { 1113 i2c::vals::Dir::WRITE => {
960 kind: SlaveCommandKind::Write, 1114 trace!("DIR: write");
961 address: self.determine_matched_address()?, 1115 Poll::Ready(Ok(SlaveCommand {
962 })), 1116 kind: SlaveCommandKind::Write,
963 i2c::vals::Dir::READ => Poll::Ready(Ok(SlaveCommand { 1117 address: self.determine_matched_address()?,
964 kind: SlaveCommandKind::Read, 1118 }))
965 address: self.determine_matched_address()?, 1119 }
966 })), 1120 i2c::vals::Dir::READ => {
1121 trace!("DIR: read");
1122 Poll::Ready(Ok(SlaveCommand {
1123 kind: SlaveCommandKind::Read,
1124 address: self.determine_matched_address()?,
1125 }))
1126 }
967 } 1127 }
968 } 1128 }
969 }) 1129 })
@@ -971,7 +1131,9 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
971 } 1131 }
972 1132
973 /// Respond to a write command. 1133 /// Respond to a write command.
974 pub fn blocking_respond_to_write(&self, read: &mut [u8]) -> Result<(), Error> { 1134 ///
1135 /// Returns total number of bytes received.
1136 pub fn blocking_respond_to_write(&self, read: &mut [u8]) -> Result<usize, Error> {
975 let timeout = self.timeout(); 1137 let timeout = self.timeout();
976 self.slave_read_internal(read, timeout) 1138 self.slave_read_internal(read, timeout)
977 } 1139 }
@@ -1025,7 +1187,7 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1025 w.set_rxdmaen(false); 1187 w.set_rxdmaen(false);
1026 w.set_stopie(false); 1188 w.set_stopie(false);
1027 w.set_tcie(false); 1189 w.set_tcie(false);
1028 }) 1190 });
1029 }); 1191 });
1030 1192
1031 let total_received = poll_fn(|cx| { 1193 let total_received = poll_fn(|cx| {