aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHybridChild <[email protected]>2025-11-12 21:55:20 +0100
committerHybridChild <[email protected]>2025-11-12 21:55:20 +0100
commit9e2a4161b32154f19963a222b3eb8f956b60d820 (patch)
tree258bb3d874202fe9f9bae73ac6ed743c9b862981
parent18a43908725366a230c990b8dee4a1d89fef11d0 (diff)
stm32/i2c: Fix v2 async transaction implementation
-rw-r--r--embassy-stm32/src/i2c/v2.rs261
-rw-r--r--tests/stm32/build.rs1
-rw-r--r--tests/stm32/src/bin/i2c_v2.rs238
-rw-r--r--tests/stm32/src/common.rs2
4 files changed, 363 insertions, 139 deletions
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 3c43887c0..c9656d2c2 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -225,7 +225,14 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
225 fn reload(info: &'static Info, length: usize, will_reload: bool, stop: Stop, timeout: Timeout) -> Result<(), Error> { 225 fn reload(info: &'static Info, length: usize, will_reload: bool, stop: Stop, timeout: Timeout) -> Result<(), Error> {
226 assert!(length < 256 && length > 0); 226 assert!(length < 256 && length > 0);
227 227
228 while !info.regs.isr().read().tcr() { 228 // Wait for either TCR (Transfer Complete Reload) or TC (Transfer Complete)
229 // TCR occurs when RELOAD=1, TC occurs when RELOAD=0
230 // Both indicate the peripheral is ready for the next transfer
231 loop {
232 let isr = info.regs.isr().read();
233 if isr.tcr() || isr.tc() {
234 break;
235 }
229 timeout.check()?; 236 timeout.check()?;
230 } 237 }
231 238
@@ -885,12 +892,12 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
885 address, 892 address,
886 total_len.min(255), 893 total_len.min(255),
887 Stop::Software, 894 Stop::Software,
888 (total_len > 255) || !last_slice, 895 total_len > 255,
889 restart, 896 restart,
890 timeout, 897 timeout,
891 )?; 898 )?;
892 } else { 899 } else {
893 Self::reload(self.info, total_len.min(255), (total_len > 255) || !last_slice, Stop::Software, timeout)?; 900 Self::reload(self.info, total_len.min(255), total_len > 255, Stop::Software, timeout)?;
894 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 901 self.info.regs.cr1().modify(|w| w.set_tcie(true));
895 } 902 }
896 } else if !(isr.tcr() || isr.tc()) { 903 } else if !(isr.tcr() || isr.tc()) {
@@ -899,9 +906,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
899 } else if remaining_len == 0 { 906 } else if remaining_len == 0 {
900 return Poll::Ready(Ok(())); 907 return Poll::Ready(Ok(()));
901 } else { 908 } else {
902 let last_piece = (remaining_len <= 255) && last_slice; 909 if let Err(e) = Self::reload(self.info, remaining_len.min(255), remaining_len > 255, Stop::Software, timeout) {
903
904 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, Stop::Software, timeout) {
905 return Poll::Ready(Err(e)); 910 return Poll::Ready(Err(e));
906 } 911 }
907 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 912 self.info.regs.cr1().modify(|w| w.set_tcie(true));
@@ -913,10 +918,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
913 .await?; 918 .await?;
914 919
915 dma_transfer.await; 920 dma_transfer.await;
916 if last_slice { 921
917 // This should be done already 922 // Always wait for TC after DMA completes - needed for consecutive buffers
918 self.wait_tc(timeout)?; 923 self.wait_tc(timeout)?;
919 }
920 924
921 if last_slice & send_stop { 925 if last_slice & send_stop {
922 self.master_stop(); 926 self.master_stop();
@@ -1173,56 +1177,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
1173 is_last_group: bool, 1177 is_last_group: bool,
1174 timeout: Timeout, 1178 timeout: Timeout,
1175 ) -> Result<(), Error> { 1179 ) -> Result<(), Error> {
1176 // Calculate total bytes across all operations in this group 1180 // For now, use blocking implementation for write groups
1177 let total_bytes = Self::total_operation_bytes(operations); 1181 // This avoids complexity of handling multiple non-contiguous buffers with DMA
1178 1182 self.execute_write_group(address, operations, is_first_group, is_last_group, timeout)
1179 if total_bytes == 0 {
1180 // Handle empty write group using blocking call
1181 if is_first_group {
1182 Self::master_write(self.info, address, 0, Stop::Software, false, !is_first_group, timeout)?;
1183 }
1184 if is_last_group {
1185 self.master_stop();
1186 }
1187 return Ok(());
1188 }
1189
1190 let send_stop = is_last_group;
1191
1192 // Use DMA for each operation in the group
1193 let mut first_in_group = true;
1194 let mut remaining_operations = operations.len();
1195
1196 for operation in operations {
1197 if let Operation::Write(buffer) = operation {
1198 remaining_operations -= 1;
1199 let is_last_in_group = remaining_operations == 0;
1200
1201 if buffer.is_empty() {
1202 // Skip empty buffers
1203 continue;
1204 }
1205
1206 let fut = self.write_dma_internal(
1207 address,
1208 buffer,
1209 first_in_group && is_first_group, // first_slice
1210 is_last_in_group && is_last_group, // last_slice
1211 send_stop && is_last_in_group, // send_stop
1212 !is_first_group && first_in_group, // restart
1213 timeout,
1214 );
1215 timeout.with(fut).await?;
1216 first_in_group = false;
1217 }
1218 }
1219
1220 // If not last group, wait for TC to enable RESTART
1221 if !is_last_group {
1222 self.wait_tc(timeout)?;
1223 }
1224
1225 Ok(())
1226 } 1183 }
1227 1184
1228 async fn execute_read_group_async( 1185 async fn execute_read_group_async(
@@ -1255,10 +1212,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
1255 return Ok(()); 1212 return Ok(());
1256 } 1213 }
1257 1214
1258 // For read operations, we need to handle them differently since read_dma_internal 1215 // Use DMA for read operations - need to handle multiple buffers
1259 // expects a single buffer. We'll iterate through operations and use DMA for each.
1260 let mut total_remaining = total_bytes;
1261 let restart = !is_first_group; 1216 let restart = !is_first_group;
1217 let mut total_remaining = total_bytes;
1218 let mut is_first_in_group = true;
1262 1219
1263 for operation in operations { 1220 for operation in operations {
1264 if let Operation::Read(buffer) = operation { 1221 if let Operation::Read(buffer) = operation {
@@ -1267,57 +1224,46 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
1267 continue; 1224 continue;
1268 } 1225 }
1269 1226
1270 let is_first_read = total_remaining == total_bytes;
1271 let buf_len = buffer.len(); 1227 let buf_len = buffer.len();
1272 total_remaining -= buf_len; 1228 total_remaining -= buf_len;
1273 let is_last_read = total_remaining == 0; 1229 let is_last_in_group = total_remaining == 0;
1274 1230
1275 if is_first_read { 1231 // Perform DMA read
1276 // First read in the group 1232 if is_first_in_group {
1277 let completed_chunks = buf_len / 255; 1233 // First buffer: use read_dma_internal which handles restart properly
1278 let total_chunks = if completed_chunks * 255 == buf_len { 1234 // Only use Automatic stop if this is the last buffer in the last group
1279 completed_chunks 1235 let stop_mode = if is_last_group && is_last_in_group {
1236 Stop::Automatic
1280 } else { 1237 } else {
1281 completed_chunks + 1 1238 Stop::Software
1282 }; 1239 };
1283 let last_chunk_idx = total_chunks.saturating_sub(1);
1284 1240
1285 // Use master_read to initiate, then DMA for data 1241 // We need a custom DMA read that respects our stop mode
1286 Self::master_read( 1242 self.read_dma_group_internal(
1287 self.info,
1288 address, 1243 address,
1289 buf_len.min(255), 1244 buffer,
1290 if is_last_group && is_last_read {
1291 Stop::Automatic
1292 } else {
1293 Stop::Software
1294 },
1295 last_chunk_idx != 0 || !is_last_read, // reload
1296 restart, 1245 restart,
1246 stop_mode,
1297 timeout, 1247 timeout,
1298 )?; 1248 )
1299 } 1249 .await?;
1300 1250 is_first_in_group = false;
1301 // Use the existing read_dma_internal, but we need to handle the reload logic ourselves 1251 } else {
1302 // For simplicity with consecutive reads, fall back to blocking for now 1252 // Subsequent buffers: need to reload and continue
1303 // This maintains correctness while keeping complexity manageable 1253 let stop_mode = if is_last_group && is_last_in_group {
1304 for (chunk_idx, chunk) in buffer.chunks_mut(255).enumerate() { 1254 Stop::Automatic
1305 let chunk_len = chunk.len(); 1255 } else {
1306 let is_very_last = total_remaining == 0 && chunk_len == chunk.len(); 1256 Stop::Software
1307 1257 };
1308 if !is_first_read || chunk_idx != 0 {
1309 let stop = if is_last_group && is_very_last {
1310 Stop::Automatic
1311 } else {
1312 Stop::Software
1313 };
1314 Self::reload(self.info, chunk_len, !(is_last_group && is_very_last), stop, timeout)?;
1315 }
1316 1258
1317 for byte in chunk { 1259 self.read_dma_group_internal(
1318 self.wait_rxne(timeout)?; 1260 address,
1319 *byte = self.info.regs.rxdr().read().rxdata(); 1261 buffer,
1320 } 1262 false, // no restart for subsequent buffers in same group
1263 stop_mode,
1264 timeout,
1265 )
1266 .await?;
1321 } 1267 }
1322 } 1268 }
1323 } 1269 }
@@ -1326,9 +1272,108 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
1326 if is_last_group { 1272 if is_last_group {
1327 self.wait_stop(timeout)?; 1273 self.wait_stop(timeout)?;
1328 } 1274 }
1329 // For non-last read groups, don't wait for TC - the peripheral may hold SCL low 1275
1330 // in Software AUTOEND mode until the next START is issued. Just proceed directly 1276 Ok(())
1331 // to the next group which will issue RESTART and release the clock. 1277 }
1278
1279 /// Internal DMA read helper for transaction groups
1280 async fn read_dma_group_internal(
1281 &mut self,
1282 address: Address,
1283 buffer: &mut [u8],
1284 restart: bool,
1285 stop_mode: Stop,
1286 timeout: Timeout,
1287 ) -> Result<(), Error> {
1288 let total_len = buffer.len();
1289
1290 let dma_transfer = unsafe {
1291 let regs = self.info.regs;
1292 regs.cr1().modify(|w| {
1293 w.set_rxdmaen(true);
1294 w.set_tcie(true);
1295 w.set_nackie(true);
1296 w.set_errie(true);
1297 });
1298 let src = regs.rxdr().as_ptr() as *mut u8;
1299
1300 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
1301 };
1302
1303 let mut remaining_len = total_len;
1304
1305 let on_drop = OnDrop::new(|| {
1306 let regs = self.info.regs;
1307 regs.cr1().modify(|w| {
1308 w.set_rxdmaen(false);
1309 w.set_tcie(false);
1310 w.set_nackie(false);
1311 w.set_errie(false);
1312 });
1313 regs.icr().write(|w| {
1314 w.set_nackcf(true);
1315 w.set_berrcf(true);
1316 w.set_arlocf(true);
1317 w.set_ovrcf(true);
1318 });
1319 });
1320
1321 poll_fn(|cx| {
1322 self.state.waker.register(cx.waker());
1323
1324 let isr = self.info.regs.isr().read();
1325
1326 if isr.nackf() {
1327 return Poll::Ready(Err(Error::Nack));
1328 }
1329 if isr.arlo() {
1330 return Poll::Ready(Err(Error::Arbitration));
1331 }
1332 if isr.berr() {
1333 return Poll::Ready(Err(Error::Bus));
1334 }
1335 if isr.ovr() {
1336 return Poll::Ready(Err(Error::Overrun));
1337 }
1338
1339 if remaining_len == total_len {
1340 Self::master_read(
1341 self.info,
1342 address,
1343 total_len.min(255),
1344 stop_mode,
1345 total_len > 255, // reload
1346 restart,
1347 timeout,
1348 )?;
1349 if total_len <= 255 {
1350 return Poll::Ready(Ok(()));
1351 }
1352 } else if isr.tcr() {
1353 // Transfer Complete Reload - need to set up next chunk
1354 let last_piece = remaining_len <= 255;
1355
1356 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, stop_mode, timeout) {
1357 return Poll::Ready(Err(e));
1358 }
1359 // Return here if we are on last chunk,
1360 // end of transfer will be awaited with the DMA below
1361 if last_piece {
1362 return Poll::Ready(Ok(()));
1363 }
1364 self.info.regs.cr1().modify(|w| w.set_tcie(true));
1365 } else {
1366 // poll_fn was woken without TCR interrupt
1367 return Poll::Pending;
1368 }
1369
1370 remaining_len = remaining_len.saturating_sub(255);
1371 Poll::Pending
1372 })
1373 .await?;
1374
1375 dma_transfer.await;
1376 drop(on_drop);
1332 1377
1333 Ok(()) 1378 Ok(())
1334 } 1379 }
diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs
index 556d77a20..34030c206 100644
--- a/tests/stm32/build.rs
+++ b/tests/stm32/build.rs
@@ -15,6 +15,7 @@ fn main() -> Result<(), Box<dyn Error>> {
15 feature = "stm32c071rb", // 24 kb 15 feature = "stm32c071rb", // 24 kb
16 feature = "stm32l073rz", // 20 kb 16 feature = "stm32l073rz", // 20 kb
17 feature = "stm32h503rb", // 32 kb 17 feature = "stm32h503rb", // 32 kb
18 feature = "stm32f072rb", // 16 kb - I2C v2 test with async too large for RAM
18 // no VTOR, so interrupts can't work when running from RAM 19 // no VTOR, so interrupts can't work when running from RAM
19 feature = "stm32f091rc", 20 feature = "stm32f091rc",
20 )) { 21 )) {
diff --git a/tests/stm32/src/bin/i2c_v2.rs b/tests/stm32/src/bin/i2c_v2.rs
index 9a23e28e1..087b8bbd9 100644
--- a/tests/stm32/src/bin/i2c_v2.rs
+++ b/tests/stm32/src/bin/i2c_v2.rs
@@ -7,7 +7,7 @@
7// - Connect to I2C slave device (e.g., Digilent Analog Discovery I2C slave, or EEPROM) 7// - Connect to I2C slave device (e.g., Digilent Analog Discovery I2C slave, or EEPROM)
8// - Default slave address: 0x50 8// - Default slave address: 0x50
9// - Pull-up resistors: 4.7kΩ on both SCL and SDA 9// - Pull-up resistors: 4.7kΩ on both SCL and SDA
10// - CN5 Pin 5 (PB8/SCL) and CN5 Pin 9 (PB9/SDA) 10// - CN5 Pin 10 (PB8/SCL) and CN5 Pin 9 (PB9/SDA)
11// 11//
12// Analog Discovery Setup: 12// Analog Discovery Setup:
13// - Configure as I2C Slave at address 0x50 13// - Configure as I2C Slave at address 0x50
@@ -21,9 +21,9 @@ mod common;
21use common::*; 21use common::*;
22use embassy_executor::Spawner; 22use embassy_executor::Spawner;
23use embassy_stm32::i2c::{Config, I2c, Master}; 23use embassy_stm32::i2c::{Config, I2c, Master};
24use embassy_stm32::mode::Blocking; 24use embassy_stm32::mode::{Async, Blocking};
25use embassy_stm32::time::Hertz; 25use embassy_stm32::time::Hertz;
26use embassy_time::block_for; 26use embassy_time::Timer;
27use embedded_hal_1::i2c::Operation; 27use embedded_hal_1::i2c::Operation;
28 28
29#[embassy_executor::main] 29#[embassy_executor::main]
@@ -38,42 +38,80 @@ async fn main(_spawner: Spawner) {
38 let mut config = Config::default(); 38 let mut config = Config::default();
39 config.frequency = Hertz(100_000); 39 config.frequency = Hertz(100_000);
40 40
41 let mut i2c = I2c::new_blocking(
42 i2c_peri.reborrow(),
43 scl.reborrow(),
44 sda.reborrow(),
45 config,
46 );
47
48 // I2C slave address for Analog Discovery or test EEPROM 41 // I2C slave address for Analog Discovery or test EEPROM
49 let slave_addr = 0x50u8; 42 let slave_addr = 0x50u8;
50 43
51 // Wait for slave device to be ready 44 // Wait for slave device to be ready
52 block_for(embassy_time::Duration::from_millis(100)); 45 Timer::after_millis(100).await;
46
47 // ========== BLOCKING TESTS ==========
48 info!("========== BLOCKING TRANSACTION TESTS ==========");
49 {
50 let mut i2c = I2c::new_blocking(
51 i2c_peri.reborrow(),
52 scl.reborrow(),
53 sda.reborrow(),
54 config,
55 );
56
57 info!("=== Test 1: Consecutive Writes (Should Merge) ===");
58 test_consecutive_writes_blocking(&mut i2c, slave_addr);
59
60 info!("=== Test 2: Consecutive Reads (Should Merge) ===");
61 test_consecutive_reads_blocking(&mut i2c, slave_addr);
62
63 info!("=== Test 3: Write then Read (RESTART) ===");
64 test_write_then_read_blocking(&mut i2c, slave_addr);
65
66 info!("=== Test 4: Read then Write (RESTART) ===");
67 test_read_then_write_blocking(&mut i2c, slave_addr);
68
69 info!("=== Test 5: Complex Mixed Sequence ===");
70 test_mixed_sequence_blocking(&mut i2c, slave_addr);
71
72 info!("=== Test 6: Single Operations ===");
73 test_single_operations_blocking(&mut i2c, slave_addr);
74
75 info!("Blocking tests OK");
76 }
77
78 Timer::after_millis(100).await;
79
80 // ========== ASYNC TESTS ==========
81 info!("========== ASYNC TRANSACTION TESTS (DMA) ==========");
82 {
83 let tx_dma = peri!(p, I2C_TX_DMA);
84 let rx_dma = peri!(p, I2C_RX_DMA);
85 let irq = irqs!(I2C);
53 86
54 info!("=== Test 1: Consecutive Writes (Should Merge) ==="); 87 let mut i2c = I2c::new(i2c_peri, scl, sda, irq, tx_dma, rx_dma, config);
55 test_consecutive_writes(&mut i2c, slave_addr);
56 88
57 info!("=== Test 2: Consecutive Reads (Should Merge) ==="); 89 info!("=== Test 1: Consecutive Writes (Should Merge) ===");
58 test_consecutive_reads(&mut i2c, slave_addr); 90 test_consecutive_writes_async(&mut i2c, slave_addr).await;
59 91
60 info!("=== Test 3: Write then Read (RESTART) ==="); 92 info!("=== Test 2: Consecutive Reads (Should Merge) ===");
61 test_write_then_read(&mut i2c, slave_addr); 93 test_consecutive_reads_async(&mut i2c, slave_addr).await;
62 94
63 info!("=== Test 4: Read then Write (RESTART) ==="); 95 info!("=== Test 3: Write then Read (RESTART) ===");
64 test_read_then_write(&mut i2c, slave_addr); 96 test_write_then_read_async(&mut i2c, slave_addr).await;
65 97
66 info!("=== Test 5: Complex Mixed Sequence ==="); 98 info!("=== Test 4: Read then Write (RESTART) ===");
67 test_mixed_sequence(&mut i2c, slave_addr); 99 test_read_then_write_async(&mut i2c, slave_addr).await;
68 100
69 info!("=== Test 6: Single Operations ==="); 101 info!("=== Test 5: Complex Mixed Sequence ===");
70 test_single_operations(&mut i2c, slave_addr); 102 test_mixed_sequence_async(&mut i2c, slave_addr).await;
71 103
72 info!("Test OK"); 104 info!("=== Test 6: Single Operations ===");
105 test_single_operations_async(&mut i2c, slave_addr).await;
106
107 info!("Async tests OK");
108 }
109
110 info!("All tests OK");
73 cortex_m::asm::bkpt(); 111 cortex_m::asm::bkpt();
74} 112}
75 113
76fn test_consecutive_writes(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { 114fn test_consecutive_writes_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
77 // Expected on bus: START, ADDR+W, data1, data2, data3, STOP 115 // Expected on bus: START, ADDR+W, data1, data2, data3, STOP
78 // NO intermediate RESTART/STOP between writes - they should be merged 116 // NO intermediate RESTART/STOP between writes - they should be merged
79 let data1 = [0x10, 0x11, 0x12]; 117 let data1 = [0x10, 0x11, 0x12];
@@ -95,7 +133,7 @@ fn test_consecutive_writes(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
95 } 133 }
96} 134}
97 135
98fn test_consecutive_reads(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { 136fn test_consecutive_reads_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
99 // Expected on bus: START, ADDR+R, data1, data2, data3, NACK, STOP 137 // Expected on bus: START, ADDR+R, data1, data2, data3, NACK, STOP
100 // NO intermediate RESTART/STOP between reads - they should be merged 138 // NO intermediate RESTART/STOP between reads - they should be merged
101 let mut buf1 = [0u8; 4]; 139 let mut buf1 = [0u8; 4];
@@ -122,7 +160,7 @@ fn test_consecutive_reads(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
122 } 160 }
123} 161}
124 162
125fn test_write_then_read(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { 163fn test_write_then_read_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
126 // Expected: START, ADDR+W, data, RESTART, ADDR+R, data, NACK, STOP 164 // Expected: START, ADDR+W, data, RESTART, ADDR+R, data, NACK, STOP
127 let write_data = [0xAA, 0xBB]; 165 let write_data = [0xAA, 0xBB];
128 let mut read_buf = [0u8; 4]; 166 let mut read_buf = [0u8; 4];
@@ -142,7 +180,7 @@ fn test_write_then_read(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
142 } 180 }
143} 181}
144 182
145fn test_read_then_write(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { 183fn test_read_then_write_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
146 // Expected: START, ADDR+R, data, NACK, RESTART, ADDR+W, data, STOP 184 // Expected: START, ADDR+R, data, NACK, RESTART, ADDR+W, data, STOP
147 let mut read_buf = [0u8; 3]; 185 let mut read_buf = [0u8; 3];
148 let write_data = [0xCC, 0xDD, 0xEE]; 186 let write_data = [0xCC, 0xDD, 0xEE];
@@ -162,7 +200,7 @@ fn test_read_then_write(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
162 } 200 }
163} 201}
164 202
165fn test_mixed_sequence(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { 203fn test_mixed_sequence_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
166 // Complex: W, W, R, R, W, R 204 // Complex: W, W, R, R, W, R
167 // Groups: [W,W] RESTART [R,R] RESTART [W] RESTART [R] 205 // Groups: [W,W] RESTART [R,R] RESTART [W] RESTART [R]
168 let w1 = [0x01, 0x02]; 206 let w1 = [0x01, 0x02];
@@ -193,7 +231,7 @@ fn test_mixed_sequence(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
193 } 231 }
194} 232}
195 233
196fn test_single_operations(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) { 234fn test_single_operations_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
197 // Test single write 235 // Test single write
198 let write_data = [0xFF]; 236 let write_data = [0xFF];
199 let mut ops = [Operation::Write(&write_data)]; 237 let mut ops = [Operation::Write(&write_data)];
@@ -218,3 +256,143 @@ fn test_single_operations(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
218 } 256 }
219 } 257 }
220} 258}
259
260// ==================== ASYNC TEST FUNCTIONS ====================
261
262async fn test_consecutive_writes_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
263 let data1 = [0x10, 0x11, 0x12];
264 let data2 = [0x20, 0x21];
265 let data3 = [0x30, 0x31, 0x32, 0x33];
266
267 let mut ops = [
268 Operation::Write(&data1),
269 Operation::Write(&data2),
270 Operation::Write(&data3),
271 ];
272
273 match i2c.transaction(addr, &mut ops).await {
274 Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"),
275 Err(e) => {
276 error!("✗ Consecutive writes failed: {:?}", e);
277 defmt::panic!("Test failed: consecutive writes");
278 }
279 }
280}
281
282async fn test_consecutive_reads_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
283 let mut buf1 = [0u8; 4];
284 let mut buf2 = [0u8; 3];
285 let mut buf3 = [0u8; 2];
286
287 let mut ops = [
288 Operation::Read(&mut buf1),
289 Operation::Read(&mut buf2),
290 Operation::Read(&mut buf3),
291 ];
292
293 match i2c.transaction(addr, &mut ops).await {
294 Ok(_) => {
295 info!("✓ Consecutive reads succeeded (merged 9 bytes)");
296 info!(" buf1: {:02x}", buf1);
297 info!(" buf2: {:02x}", buf2);
298 info!(" buf3: {:02x}", buf3);
299 }
300 Err(e) => {
301 error!("✗ Consecutive reads failed: {:?}", e);
302 defmt::panic!("Test failed: consecutive reads");
303 }
304 }
305}
306
307async fn test_write_then_read_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
308 let write_data = [0xAA, 0xBB];
309 let mut read_buf = [0u8; 4];
310
311 let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)];
312
313 match i2c.transaction(addr, &mut ops).await {
314 Ok(_) => {
315 info!("✓ Write-then-read succeeded with RESTART");
316 info!(" Written: {:02x}", write_data);
317 info!(" Read: {:02x}", read_buf);
318 }
319 Err(e) => {
320 error!("✗ Write-then-read failed: {:?}", e);
321 defmt::panic!("Test failed: write-then-read");
322 }
323 }
324}
325
326async fn test_read_then_write_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
327 let mut read_buf = [0u8; 3];
328 let write_data = [0xCC, 0xDD, 0xEE];
329
330 let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)];
331
332 match i2c.transaction(addr, &mut ops).await {
333 Ok(_) => {
334 info!("✓ Read-then-write succeeded with RESTART");
335 info!(" Read: {:02x}", read_buf);
336 info!(" Written: {:02x}", write_data);
337 }
338 Err(e) => {
339 error!("✗ Read-then-write failed: {:?}", e);
340 defmt::panic!("Test failed: read-then-write");
341 }
342 }
343}
344
345async fn test_mixed_sequence_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
346 let w1 = [0x01, 0x02];
347 let w2 = [0x03, 0x04];
348 let mut r1 = [0u8; 2];
349 let mut r2 = [0u8; 2];
350 let w3 = [0x05];
351 let mut r3 = [0u8; 1];
352
353 let mut ops = [
354 Operation::Write(&w1),
355 Operation::Write(&w2),
356 Operation::Read(&mut r1),
357 Operation::Read(&mut r2),
358 Operation::Write(&w3),
359 Operation::Read(&mut r3),
360 ];
361
362 match i2c.transaction(addr, &mut ops).await {
363 Ok(_) => {
364 info!("✓ Mixed sequence succeeded");
365 info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]");
366 }
367 Err(e) => {
368 error!("✗ Mixed sequence failed: {:?}", e);
369 defmt::panic!("Test failed: mixed sequence");
370 }
371 }
372}
373
374async fn test_single_operations_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
375 // Test single write
376 let write_data = [0xFF];
377 let mut ops = [Operation::Write(&write_data)];
378
379 match i2c.transaction(addr, &mut ops).await {
380 Ok(_) => info!("✓ Single write succeeded"),
381 Err(e) => {
382 error!("✗ Single write failed: {:?}", e);
383 defmt::panic!("Test failed: single write");
384 }
385 }
386
387 // Test single read
388 let mut read_buf = [0u8; 1];
389 let mut ops = [Operation::Read(&mut read_buf)];
390
391 match i2c.transaction(addr, &mut ops).await {
392 Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]),
393 Err(e) => {
394 error!("✗ Single read failed: {:?}", e);
395 defmt::panic!("Test failed: single read");
396 }
397 }
398}
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index 07b667ade..de06cb267 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -109,7 +109,7 @@ define_peris!(
109define_peris!( 109define_peris!(
110 UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5, 110 UART = USART1, UART_TX = PA9, UART_RX = PA10, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5,
111 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, 111 SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2,
112 I2C = I2C1, I2C_SCL = PB8, I2C_SDA = PB9, 112 I2C = I2C1, I2C_SCL = PB8, I2C_SDA = PB9, I2C_TX_DMA = DMA1_CH6, I2C_RX_DMA = DMA1_CH7,
113 @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;}, 113 @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler<embassy_stm32::peripherals::USART1>;},
114 @irq I2C = {I2C1 => embassy_stm32::i2c::EventInterruptHandler<embassy_stm32::peripherals::I2C1>, embassy_stm32::i2c::ErrorInterruptHandler<embassy_stm32::peripherals::I2C1>;}, 114 @irq I2C = {I2C1 => embassy_stm32::i2c::EventInterruptHandler<embassy_stm32::peripherals::I2C1>, embassy_stm32::i2c::ErrorInterruptHandler<embassy_stm32::peripherals::I2C1>;},
115); 115);