aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-rp/src/i2c.rs84
-rw-r--r--embassy-rp/src/i2c_slave.rs115
-rw-r--r--tests/rp/Cargo.toml1
-rw-r--r--tests/rp/src/bin/i2c.rs94
4 files changed, 177 insertions, 117 deletions
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index 74d015792..ac0eac96d 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -43,6 +43,18 @@ pub enum Error {
43 AddressReserved(u16), 43 AddressReserved(u16),
44} 44}
45 45
46/// I2C Config error
47#[derive(Debug, PartialEq, Eq)]
48#[cfg_attr(feature = "defmt", derive(defmt::Format))]
49pub enum ConfigError {
50 /// Max i2c speed is 1MHz
51 FrequencyTooHigh,
52 /// The sys clock is too slow to support given frequency
53 ClockTooSlow,
54 /// The sys clock is too fast to support given frequency
55 ClockTooFast,
56}
57
46/// I2C config. 58/// I2C config.
47#[non_exhaustive] 59#[non_exhaustive]
48#[derive(Copy, Clone)] 60#[derive(Copy, Clone)]
@@ -365,37 +377,32 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
365 ) -> Self { 377 ) -> Self {
366 into_ref!(_peri); 378 into_ref!(_peri);
367 379
368 assert!(config.frequency <= 1_000_000);
369 assert!(config.frequency > 0);
370
371 let p = T::regs();
372
373 let reset = T::reset(); 380 let reset = T::reset();
374 crate::reset::reset(reset); 381 crate::reset::reset(reset);
375 crate::reset::unreset_wait(reset); 382 crate::reset::unreset_wait(reset);
376 383
377 p.ic_enable().write(|w| w.set_enable(false));
378
379 // Select controller mode & speed
380 p.ic_con().modify(|w| {
381 // Always use "fast" mode (<= 400 kHz, works fine for standard
382 // mode too)
383 w.set_speed(i2c::vals::Speed::FAST);
384 w.set_master_mode(true);
385 w.set_ic_slave_disable(true);
386 w.set_ic_restart_en(true);
387 w.set_tx_empty_ctrl(true);
388 });
389
390 // Set FIFO watermarks to 1 to make things simpler. This is encoded
391 // by a register value of 0.
392 p.ic_tx_tl().write(|w| w.set_tx_tl(0));
393 p.ic_rx_tl().write(|w| w.set_rx_tl(0));
394
395 // Configure SCL & SDA pins 384 // Configure SCL & SDA pins
396 set_up_i2c_pin(&scl); 385 set_up_i2c_pin(&scl);
397 set_up_i2c_pin(&sda); 386 set_up_i2c_pin(&sda);
398 387
388 let mut me = Self { phantom: PhantomData };
389
390 if let Err(e) = me.set_config_inner(&config) {
391 panic!("Error configuring i2c: {:?}", e);
392 }
393
394 me
395 }
396
397 fn set_config_inner(&mut self, config: &Config) -> Result<(), ConfigError> {
398 if config.frequency > 1_000_000 {
399 return Err(ConfigError::FrequencyTooHigh);
400 }
401
402 let p = T::regs();
403
404 p.ic_enable().write(|w| w.set_enable(false));
405
399 // Configure baudrate 406 // Configure baudrate
400 407
401 // There are some subtleties to I2C timing which we are completely 408 // There are some subtleties to I2C timing which we are completely
@@ -408,10 +415,12 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
408 let hcnt = period - lcnt; // and 2/5 (40%) of the period high 415 let hcnt = period - lcnt; // and 2/5 (40%) of the period high
409 416
410 // Check for out-of-range divisors: 417 // Check for out-of-range divisors:
411 assert!(hcnt <= 0xffff); 418 if hcnt > 0xffff || lcnt > 0xffff {
412 assert!(lcnt <= 0xffff); 419 return Err(ConfigError::ClockTooFast);
413 assert!(hcnt >= 8); 420 }
414 assert!(lcnt >= 8); 421 if hcnt < 8 || lcnt < 8 {
422 return Err(ConfigError::ClockTooSlow);
423 }
415 424
416 // Per I2C-bus specification a device in standard or fast mode must 425 // Per I2C-bus specification a device in standard or fast mode must
417 // internally provide a hold time of at least 300ns for the SDA 426 // internally provide a hold time of at least 300ns for the SDA
@@ -424,14 +433,19 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
424 ((clk_base * 3) / 10_000_000) + 1 433 ((clk_base * 3) / 10_000_000) + 1
425 } else { 434 } else {
426 // fast mode plus requires a clk_base > 32MHz 435 // fast mode plus requires a clk_base > 32MHz
427 assert!(clk_base >= 32_000_000); 436 if clk_base <= 32_000_000 {
437 return Err(ConfigError::ClockTooSlow);
438 }
428 439
429 // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s / 440 // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s /
430 // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't 441 // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't
431 // fit in uint. Add 1 to avoid division truncation. 442 // fit in uint. Add 1 to avoid division truncation.
432 ((clk_base * 3) / 25_000_000) + 1 443 ((clk_base * 3) / 25_000_000) + 1
433 }; 444 };
434 assert!(sda_tx_hold_count <= lcnt - 2); 445
446 if sda_tx_hold_count > lcnt - 2 {
447 return Err(ConfigError::ClockTooSlow);
448 }
435 449
436 p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16)); 450 p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16));
437 p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16)); 451 p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16));
@@ -440,10 +454,9 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
440 p.ic_sda_hold() 454 p.ic_sda_hold()
441 .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16)); 455 .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16));
442 456
443 // Enable I2C block
444 p.ic_enable().write(|w| w.set_enable(true)); 457 p.ic_enable().write(|w| w.set_enable(true));
445 458
446 Self { phantom: PhantomData } 459 Ok(())
447 } 460 }
448 461
449 fn setup(addr: u16) -> Result<(), Error> { 462 fn setup(addr: u16) -> Result<(), Error> {
@@ -757,6 +770,15 @@ where
757 } 770 }
758} 771}
759 772
773impl<'d, T: Instance, M: Mode> embassy_embedded_hal::SetConfig for I2c<'d, T, M> {
774 type Config = Config;
775 type ConfigError = ConfigError;
776
777 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
778 self.set_config_inner(config)
779 }
780}
781
760/// Check if address is reserved. 782/// Check if address is reserved.
761pub fn i2c_reserved_addr(addr: u16) -> bool { 783pub fn i2c_reserved_addr(addr: u16) -> bool {
762 ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0 784 ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0
diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs
index 979686627..97ca17295 100644
--- a/embassy-rp/src/i2c_slave.rs
+++ b/embassy-rp/src/i2c_slave.rs
@@ -83,6 +83,7 @@ impl Default for Config {
83pub struct I2cSlave<'d, T: Instance> { 83pub struct I2cSlave<'d, T: Instance> {
84 phantom: PhantomData<&'d mut T>, 84 phantom: PhantomData<&'d mut T>,
85 pending_byte: Option<u8>, 85 pending_byte: Option<u8>,
86 config: Config,
86} 87}
87 88
88impl<'d, T: Instance> I2cSlave<'d, T> { 89impl<'d, T: Instance> I2cSlave<'d, T> {
@@ -99,6 +100,25 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
99 assert!(!i2c_reserved_addr(config.addr)); 100 assert!(!i2c_reserved_addr(config.addr));
100 assert!(config.addr != 0); 101 assert!(config.addr != 0);
101 102
103 // Configure SCL & SDA pins
104 set_up_i2c_pin(&scl);
105 set_up_i2c_pin(&sda);
106
107 let mut ret = Self {
108 phantom: PhantomData,
109 pending_byte: None,
110 config,
111 };
112
113 ret.reset();
114
115 ret
116 }
117
118 /// Reset the i2c peripheral. If you cancel a respond_to_read, you may stall the bus.
119 /// You can recover the bus by calling this function, but doing so will almost certainly cause
120 /// an i/o error in the master.
121 pub fn reset(&mut self) {
102 let p = T::regs(); 122 let p = T::regs();
103 123
104 let reset = T::reset(); 124 let reset = T::reset();
@@ -107,7 +127,7 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
107 127
108 p.ic_enable().write(|w| w.set_enable(false)); 128 p.ic_enable().write(|w| w.set_enable(false));
109 129
110 p.ic_sar().write(|w| w.set_ic_sar(config.addr)); 130 p.ic_sar().write(|w| w.set_ic_sar(self.config.addr));
111 p.ic_con().modify(|w| { 131 p.ic_con().modify(|w| {
112 w.set_master_mode(false); 132 w.set_master_mode(false);
113 w.set_ic_slave_disable(false); 133 w.set_ic_slave_disable(false);
@@ -121,10 +141,10 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
121 // Generate stop interrupts for general calls 141 // Generate stop interrupts for general calls
122 // This also causes stop interrupts for other devices on the bus but those will not be 142 // This also causes stop interrupts for other devices on the bus but those will not be
123 // propagated up to the application. 143 // propagated up to the application.
124 w.set_stop_det_ifaddressed(!config.general_call); 144 w.set_stop_det_ifaddressed(!self.config.general_call);
125 }); 145 });
126 p.ic_ack_general_call() 146 p.ic_ack_general_call()
127 .write(|w| w.set_ack_gen_call(config.general_call)); 147 .write(|w| w.set_ack_gen_call(self.config.general_call));
128 148
129 // Set FIFO watermarks to 1 to make things simpler. This is encoded 149 // Set FIFO watermarks to 1 to make things simpler. This is encoded
130 // by a register value of 0. Rx watermark should never change, but Tx watermark will be 150 // by a register value of 0. Rx watermark should never change, but Tx watermark will be
@@ -132,10 +152,6 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
132 p.ic_tx_tl().write(|w| w.set_tx_tl(0)); 152 p.ic_tx_tl().write(|w| w.set_tx_tl(0));
133 p.ic_rx_tl().write(|w| w.set_rx_tl(0)); 153 p.ic_rx_tl().write(|w| w.set_rx_tl(0));
134 154
135 // Configure SCL & SDA pins
136 set_up_i2c_pin(&scl);
137 set_up_i2c_pin(&sda);
138
139 // Clear interrupts 155 // Clear interrupts
140 p.ic_clr_intr().read(); 156 p.ic_clr_intr().read();
141 157
@@ -146,11 +162,6 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
146 p.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)); 162 p.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0));
147 T::Interrupt::unpend(); 163 T::Interrupt::unpend();
148 unsafe { T::Interrupt::enable() }; 164 unsafe { T::Interrupt::enable() };
149
150 Self {
151 phantom: PhantomData,
152 pending_byte: None,
153 }
154 } 165 }
155 166
156 /// Calls `f` to check if we are ready or not. 167 /// Calls `f` to check if we are ready or not.
@@ -178,15 +189,13 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
178 fn drain_fifo(&mut self, buffer: &mut [u8], offset: &mut usize) { 189 fn drain_fifo(&mut self, buffer: &mut [u8], offset: &mut usize) {
179 let p = T::regs(); 190 let p = T::regs();
180 191
181 for b in &mut buffer[*offset..] { 192 if let Some(pending) = self.pending_byte.take() {
182 if let Some(pending) = self.pending_byte.take() { 193 buffer[*offset] = pending;
183 *b = pending; 194 *offset += 1;
184 *offset += 1; 195 }
185 continue;
186 }
187 196
188 let status = p.ic_status().read(); 197 for b in &mut buffer[*offset..] {
189 if !status.rfne() { 198 if !p.ic_status().read().rfne() {
190 break; 199 break;
191 } 200 }
192 201
@@ -207,14 +216,6 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
207 } 216 }
208 } 217 }
209 218
210 #[inline(always)]
211 fn write_to_fifo(&mut self, buffer: &[u8]) {
212 let p = T::regs();
213 for byte in buffer {
214 p.ic_data_cmd().write(|w| w.set_dat(*byte));
215 }
216 }
217
218 /// Wait asynchronously for commands from an I2C master. 219 /// Wait asynchronously for commands from an I2C master.
219 /// `buffer` is provided in case master does a 'write', 'write read', or 'general call' and is unused for 'read'. 220 /// `buffer` is provided in case master does a 'write', 'write read', or 'general call' and is unused for 'read'.
220 pub async fn listen(&mut self, buffer: &mut [u8]) -> Result<Command, Error> { 221 pub async fn listen(&mut self, buffer: &mut [u8]) -> Result<Command, Error> {
@@ -227,8 +228,9 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
227 self.wait_on( 228 self.wait_on(
228 |me| { 229 |me| {
229 let stat = p.ic_raw_intr_stat().read(); 230 let stat = p.ic_raw_intr_stat().read();
231 trace!("ls:{:013b} len:{}", stat.0, len);
230 232
231 if p.ic_rxflr().read().rxflr() > 0 { 233 if p.ic_rxflr().read().rxflr() > 0 || me.pending_byte.is_some() {
232 me.drain_fifo(buffer, &mut len); 234 me.drain_fifo(buffer, &mut len);
233 // we're recieving data, set rx fifo watermark to 12 bytes (3/4 full) to reduce interrupt noise 235 // we're recieving data, set rx fifo watermark to 12 bytes (3/4 full) to reduce interrupt noise
234 p.ic_rx_tl().write(|w| w.set_rx_tl(11)); 236 p.ic_rx_tl().write(|w| w.set_rx_tl(11));
@@ -241,6 +243,10 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
241 return Poll::Ready(Err(Error::PartialWrite(buffer.len()))); 243 return Poll::Ready(Err(Error::PartialWrite(buffer.len())));
242 } 244 }
243 } 245 }
246 trace!("len:{}, pend:{:?}", len, me.pending_byte);
247 if me.pending_byte.is_some() {
248 warn!("pending")
249 }
244 250
245 if stat.restart_det() && stat.rd_req() { 251 if stat.restart_det() && stat.rd_req() {
246 p.ic_clr_restart_det().read(); 252 p.ic_clr_restart_det().read();
@@ -257,12 +263,17 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
257 p.ic_clr_restart_det().read(); 263 p.ic_clr_restart_det().read();
258 p.ic_clr_gen_call().read(); 264 p.ic_clr_gen_call().read();
259 Poll::Ready(Ok(Command::Read)) 265 Poll::Ready(Ok(Command::Read))
266 } else if stat.stop_det() {
267 // clear stuck stop bit
268 // This can happen if the SDA/SCL pullups are enabled after calling this func
269 p.ic_clr_stop_det().read();
270 Poll::Pending
260 } else { 271 } else {
261 Poll::Pending 272 Poll::Pending
262 } 273 }
263 }, 274 },
264 |_me| { 275 |_me| {
265 p.ic_intr_mask().modify(|w| { 276 p.ic_intr_mask().write(|w| {
266 w.set_m_stop_det(true); 277 w.set_m_stop_det(true);
267 w.set_m_restart_det(true); 278 w.set_m_restart_det(true);
268 w.set_m_gen_call(true); 279 w.set_m_gen_call(true);
@@ -286,27 +297,30 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
286 297
287 self.wait_on( 298 self.wait_on(
288 |me| { 299 |me| {
289 if let Err(abort_reason) = me.read_and_clear_abort_reason() { 300 let stat = p.ic_raw_intr_stat().read();
290 if let Error::Abort(AbortReason::TxNotEmpty(bytes)) = abort_reason { 301 trace!("rs:{:013b}", stat.0);
291 p.ic_clr_intr().read(); 302
292 return Poll::Ready(Ok(ReadStatus::LeftoverBytes(bytes))); 303 if stat.tx_abrt() {
293 } else { 304 if let Err(abort_reason) = me.read_and_clear_abort_reason() {
294 return Poll::Ready(Err(abort_reason)); 305 if let Error::Abort(AbortReason::TxNotEmpty(bytes)) = abort_reason {
306 p.ic_clr_intr().read();
307 return Poll::Ready(Ok(ReadStatus::LeftoverBytes(bytes)));
308 } else {
309 return Poll::Ready(Err(abort_reason));
310 }
295 } 311 }
296 } 312 }
297 313
298 if let Some(chunk) = chunks.next() { 314 if let Some(chunk) = chunks.next() {
299 me.write_to_fifo(chunk); 315 for byte in chunk {
300 316 p.ic_clr_rd_req().read();
301 p.ic_clr_rd_req().read(); 317 p.ic_data_cmd().write(|w| w.set_dat(*byte));
318 }
302 319
303 Poll::Pending 320 Poll::Pending
304 } else { 321 } else {
305 let stat = p.ic_raw_intr_stat().read(); 322 if stat.rx_done() {
306
307 if stat.rx_done() && stat.stop_det() {
308 p.ic_clr_rx_done().read(); 323 p.ic_clr_rx_done().read();
309 p.ic_clr_stop_det().read();
310 Poll::Ready(Ok(ReadStatus::Done)) 324 Poll::Ready(Ok(ReadStatus::Done))
311 } else if stat.rd_req() && stat.tx_empty() { 325 } else if stat.rd_req() && stat.tx_empty() {
312 Poll::Ready(Ok(ReadStatus::NeedMoreBytes)) 326 Poll::Ready(Ok(ReadStatus::NeedMoreBytes))
@@ -316,8 +330,7 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
316 } 330 }
317 }, 331 },
318 |_me| { 332 |_me| {
319 p.ic_intr_mask().modify(|w| { 333 p.ic_intr_mask().write(|w| {
320 w.set_m_stop_det(true);
321 w.set_m_rx_done(true); 334 w.set_m_rx_done(true);
322 w.set_m_tx_empty(true); 335 w.set_m_tx_empty(true);
323 w.set_m_tx_abrt(true); 336 w.set_m_tx_abrt(true);
@@ -329,9 +342,14 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
329 342
330 /// Respond to reads with the fill byte until the controller stops asking 343 /// Respond to reads with the fill byte until the controller stops asking
331 pub async fn respond_till_stop(&mut self, fill: u8) -> Result<(), Error> { 344 pub async fn respond_till_stop(&mut self, fill: u8) -> Result<(), Error> {
345 // Send fill bytes a full fifo at a time, to reduce interrupt noise.
346 // This does mean we'll almost certainly abort the write, but since these are fill bytes,
347 // we don't care.
348 let buff = [fill; FIFO_SIZE as usize];
332 loop { 349 loop {
333 match self.respond_to_read(&[fill]).await { 350 match self.respond_to_read(&buff).await {
334 Ok(ReadStatus::NeedMoreBytes) => (), 351 Ok(ReadStatus::NeedMoreBytes) => (),
352 Ok(ReadStatus::LeftoverBytes(_)) => break Ok(()),
335 Ok(_) => break Ok(()), 353 Ok(_) => break Ok(()),
336 Err(e) => break Err(e), 354 Err(e) => break Err(e),
337 } 355 }
@@ -353,10 +371,7 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
353 #[inline(always)] 371 #[inline(always)]
354 fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { 372 fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> {
355 let p = T::regs(); 373 let p = T::regs();
356 let mut abort_reason = p.ic_tx_abrt_source().read(); 374 let abort_reason = p.ic_tx_abrt_source().read();
357
358 // Mask off master_dis
359 abort_reason.set_abrt_master_dis(false);
360 375
361 if abort_reason.0 != 0 { 376 if abort_reason.0 != 0 {
362 // Note clearing the abort flag also clears the reason, and this 377 // Note clearing the abort flag also clears the reason, and this
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index 46e1e9a5f..e67f2117d 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -14,6 +14,7 @@ embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = [ "defmt
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } 15embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] }
16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } 16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
17embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal/"}
17cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } 18cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] }
18cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } 19cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] }
19perf-client = { path = "../perf-client" } 20perf-client = { path = "../perf-client" }
diff --git a/tests/rp/src/bin/i2c.rs b/tests/rp/src/bin/i2c.rs
index a0aed1a42..153b37999 100644
--- a/tests/rp/src/bin/i2c.rs
+++ b/tests/rp/src/bin/i2c.rs
@@ -3,7 +3,10 @@
3teleprobe_meta::target!(b"rpi-pico"); 3teleprobe_meta::target!(b"rpi-pico");
4 4
5use defmt::{assert_eq, info, panic, unwrap}; 5use defmt::{assert_eq, info, panic, unwrap};
6use embassy_executor::Executor; 6use embassy_embedded_hal::SetConfig;
7use embassy_executor::{Executor, Spawner};
8use embassy_rp::clocks::{PllConfig, XoscConfig};
9use embassy_rp::config::Config as rpConfig;
7use embassy_rp::multicore::{spawn_core1, Stack}; 10use embassy_rp::multicore::{spawn_core1, Stack};
8use embassy_rp::peripherals::{I2C0, I2C1}; 11use embassy_rp::peripherals::{I2C0, I2C1};
9use embassy_rp::{bind_interrupts, i2c, i2c_slave}; 12use embassy_rp::{bind_interrupts, i2c, i2c_slave};
@@ -13,7 +16,6 @@ use static_cell::StaticCell;
13use {defmt_rtt as _, panic_probe as _, panic_probe as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _, panic_probe as _, panic_probe as _};
14 17
15static mut CORE1_STACK: Stack<1024> = Stack::new(); 18static mut CORE1_STACK: Stack<1024> = Stack::new();
16static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
17static EXECUTOR1: StaticCell<Executor> = StaticCell::new(); 19static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
18 20
19use crate::i2c::AbortReason; 21use crate::i2c::AbortReason;
@@ -44,10 +46,7 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
44 Ok(x) => match x { 46 Ok(x) => match x {
45 i2c_slave::ReadStatus::Done => break, 47 i2c_slave::ReadStatus::Done => break,
46 i2c_slave::ReadStatus::NeedMoreBytes => count += 1, 48 i2c_slave::ReadStatus::NeedMoreBytes => count += 1,
47 i2c_slave::ReadStatus::LeftoverBytes(x) => { 49 i2c_slave::ReadStatus::LeftoverBytes(x) => panic!("tried to write {} extra bytes", x),
48 info!("tried to write {} extra bytes", x);
49 break;
50 }
51 }, 50 },
52 Err(e) => match e { 51 Err(e) => match e {
53 embassy_rp::i2c_slave::Error::Abort(AbortReason::Other(n)) => panic!("Other {:b}", n), 52 embassy_rp::i2c_slave::Error::Abort(AbortReason::Other(n)) => panic!("Other {:b}", n),
@@ -92,6 +91,8 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
92 resp_buff[i] = i as u8; 91 resp_buff[i] = i as u8;
93 } 92 }
94 dev.respond_to_read(&resp_buff).await.unwrap(); 93 dev.respond_to_read(&resp_buff).await.unwrap();
94 // reset count for next round of tests
95 count = 0xD0;
95 } 96 }
96 x => panic!("Invalid Write Read {:x}", x), 97 x => panic!("Invalid Write Read {:x}", x),
97 } 98 }
@@ -104,8 +105,7 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
104 } 105 }
105} 106}
106 107
107#[embassy_executor::task] 108async fn controller_task(con: &mut i2c::I2c<'static, I2C0, i2c::Async>) {
108async fn controller_task(mut con: i2c::I2c<'static, I2C0, i2c::Async>) {
109 info!("Device start"); 109 info!("Device start");
110 110
111 { 111 {
@@ -179,33 +179,55 @@ async fn controller_task(mut con: i2c::I2c<'static, I2C0, i2c::Async>) {
179 info!("large write_read - OK") 179 info!("large write_read - OK")
180 } 180 }
181 181
182 info!("Test OK"); 182 #[embassy_executor::main]
183 cortex_m::asm::bkpt(); 183 async fn main(_core0_spawner: Spawner) {
184} 184 let mut config = rpConfig::default();
185 185 // Configure clk_sys to 48MHz to support 1kHz scl.
186#[cortex_m_rt::entry] 186 // In theory it can go lower, but we won't bother to test below 1kHz.
187fn main() -> ! { 187 config.clocks.xosc = Some(XoscConfig {
188 let p = embassy_rp::init(Default::default()); 188 hz: 12_000_000,
189 info!("Hello World!"); 189 delay_multiplier: 128,
190 190 sys_pll: Some(PllConfig {
191 let d_sda = p.PIN_19; 191 refdiv: 1,
192 let d_scl = p.PIN_18; 192 fbdiv: 120,
193 let mut config = i2c_slave::Config::default(); 193 post_div1: 6,
194 config.addr = DEV_ADDR as u16; 194 post_div2: 5,
195 let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config); 195 }),
196 196 usb_pll: Some(PllConfig {
197 spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || { 197 refdiv: 1,
198 let executor1 = EXECUTOR1.init(Executor::new()); 198 fbdiv: 120,
199 executor1.run(|spawner| unwrap!(spawner.spawn(device_task(device)))); 199 post_div1: 6,
200 }); 200 post_div2: 5,
201 201 }),
202 let executor0 = EXECUTOR0.init(Executor::new()); 202 });
203 203
204 let c_sda = p.PIN_21; 204 let p = embassy_rp::init(config);
205 let c_scl = p.PIN_20; 205 info!("Hello World!");
206 let mut config = i2c::Config::default(); 206
207 config.frequency = 5_000; 207 let d_sda = p.PIN_19;
208 let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config); 208 let d_scl = p.PIN_18;
209 let mut config = i2c_slave::Config::default();
210 config.addr = DEV_ADDR as u16;
211 let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config);
212
213 spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || {
214 let executor1 = EXECUTOR1.init(Executor::new());
215 executor1.run(|spawner| unwrap!(spawner.spawn(device_task(device))));
216 });
217
218 let c_sda = p.PIN_21;
219 let c_scl = p.PIN_20;
220 let mut controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, Default::default());
221
222 for freq in [1000, 100_000, 400_000, 1_000_000] {
223 info!("testing at {}hz", freq);
224 let mut config = i2c::Config::default();
225 config.frequency = freq;
226 controller.set_config(&config).unwrap();
227 controller_task(&mut controller).await;
228 }
209 229
210 executor0.run(|spawner| unwrap!(spawner.spawn(controller_task(controller)))); 230 info!("Test OK");
231 cortex_m::asm::bkpt();
232 }
211} 233}