aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/i2c/controller.rs130
1 files changed, 91 insertions, 39 deletions
diff --git a/src/i2c/controller.rs b/src/i2c/controller.rs
index 818024bc9..182a53aea 100644
--- a/src/i2c/controller.rs
+++ b/src/i2c/controller.rs
@@ -3,6 +3,7 @@
3use core::future::Future; 3use core::future::Future;
4use core::marker::PhantomData; 4use core::marker::PhantomData;
5 5
6use embassy_hal_internal::drop::OnDrop;
6use embassy_hal_internal::Peri; 7use embassy_hal_internal::Peri;
7use mcxa_pac::lpi2c0::mtdr::Cmd; 8use mcxa_pac::lpi2c0::mtdr::Cmd;
8 9
@@ -118,10 +119,9 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
118 critical_section::with(|_| T::regs().mcr().modify(|_, w| w.men().disabled())); 119 critical_section::with(|_| T::regs().mcr().modify(|_, w| w.men().disabled()));
119 120
120 // Soft-reset the controller, read and write FIFOs. 121 // Soft-reset the controller, read and write FIFOs.
122 Self::reset_fifos();
121 critical_section::with(|_| { 123 critical_section::with(|_| {
122 T::regs() 124 T::regs().mcr().modify(|_, w| w.rst().reset());
123 .mcr()
124 .modify(|_, w| w.rst().reset().rtf().reset().rrf().reset());
125 // According to Reference Manual section 40.7.1.4, "There 125 // According to Reference Manual section 40.7.1.4, "There
126 // is no minimum delay required before clearing the 126 // is no minimum delay required before clearing the
127 // software reset", therefore we clear it immediately. 127 // software reset", therefore we clear it immediately.
@@ -187,20 +187,32 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
187 } 187 }
188 } 188 }
189 189
190 fn is_tx_fifo_full(&mut self) -> bool { 190 /// Resets both TX and RX FIFOs dropping their contents.
191 fn reset_fifos() {
192 critical_section::with(|_| {
193 T::regs().mcr().modify(|_, w| w.rtf().reset().rrf().reset());
194 });
195 }
196
197 /// Checks whether the TX FIFO is full
198 fn is_tx_fifo_full() -> bool {
191 let txfifo_size = 1 << T::regs().param().read().mtxfifo().bits(); 199 let txfifo_size = 1 << T::regs().param().read().mtxfifo().bits();
192 T::regs().mfsr().read().txcount().bits() == txfifo_size 200 T::regs().mfsr().read().txcount().bits() == txfifo_size
193 } 201 }
194 202
195 fn is_tx_fifo_empty(&mut self) -> bool { 203 /// Checks whether the TX FIFO is empty
204 fn is_tx_fifo_empty() -> bool {
196 T::regs().mfsr().read().txcount() == 0 205 T::regs().mfsr().read().txcount() == 0
197 } 206 }
198 207
199 fn is_rx_fifo_empty(&mut self) -> bool { 208 /// Checks whether the RX FIFO is empty.
209 fn is_rx_fifo_empty() -> bool {
200 T::regs().mfsr().read().rxcount() == 0 210 T::regs().mfsr().read().rxcount() == 0
201 } 211 }
202 212
203 fn status(&mut self) -> Result<()> { 213 /// Reads and parses the controller status producing an
214 /// appropriate `Result<(), Error>` variant.
215 fn status() -> Result<()> {
204 let msr = T::regs().msr().read(); 216 let msr = T::regs().msr().read();
205 T::regs().msr().write(|w| { 217 T::regs().msr().write(|w| {
206 w.epf() 218 w.epf()
@@ -234,7 +246,11 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
234 } 246 }
235 } 247 }
236 248
237 fn send_cmd(&mut self, cmd: Cmd, data: u8) { 249 /// Inserts the given command into the outgoing FIFO.
250 ///
251 /// Caller must ensure there is space in the FIFO for the new
252 /// command.
253 fn send_cmd(cmd: Cmd, data: u8) {
238 #[cfg(feature = "defmt")] 254 #[cfg(feature = "defmt")]
239 defmt::trace!( 255 defmt::trace!(
240 "Sending cmd '{}' ({}) with data '{:08x}' MSR: {:08x}", 256 "Sending cmd '{}' ({}) with data '{:08x}' MSR: {:08x}",
@@ -249,34 +265,46 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
249 .write(|w| unsafe { w.data().bits(data) }.cmd().variant(cmd)); 265 .write(|w| unsafe { w.data().bits(data) }.cmd().variant(cmd));
250 } 266 }
251 267
268 /// Prepares an appropriate Start condition on bus by issuing a
269 /// `Start` command together with the device address and R/w bit.
270 ///
271 /// Blocks waiting for space in the FIFO to become available, then
272 /// sends the command and blocks waiting for the FIFO to become
273 /// empty ensuring the command was sent.
252 fn start(&mut self, address: u8, read: bool) -> Result<()> { 274 fn start(&mut self, address: u8, read: bool) -> Result<()> {
253 if address >= 0x80 { 275 if address >= 0x80 {
254 return Err(Error::AddressOutOfRange(address)); 276 return Err(Error::AddressOutOfRange(address));
255 } 277 }
256 278
257 // Wait until we have space in the TxFIFO 279 // Wait until we have space in the TxFIFO
258 while self.is_tx_fifo_full() {} 280 while Self::is_tx_fifo_full() {}
259 281
260 let addr_rw = address << 1 | if read { 1 } else { 0 }; 282 let addr_rw = address << 1 | if read { 1 } else { 0 };
261 self.send_cmd(if self.is_hs { Cmd::StartHs } else { Cmd::Start }, addr_rw); 283 Self::send_cmd(if self.is_hs { Cmd::StartHs } else { Cmd::Start }, addr_rw);
262 284
263 // Wait for TxFIFO to be drained 285 // Wait for TxFIFO to be drained
264 while !self.is_tx_fifo_empty() {} 286 while !Self::is_tx_fifo_empty() {}
265 287
266 // Check controller status 288 // Check controller status
267 self.status() 289 Self::status()
268 } 290 }
269 291
270 fn stop(&mut self) -> Result<()> { 292 /// Prepares a Stop condition on the bus.
293 ///
294 /// Analogous to `start`, this blocks waiting for space in the
295 /// FIFO to become available, then sends the command and blocks
296 /// waiting for the FIFO to become empty ensuring the command was
297 /// sent.
298 fn stop() -> Result<()> {
271 // Wait until we have space in the TxFIFO 299 // Wait until we have space in the TxFIFO
272 while self.is_tx_fifo_full() {} 300 while Self::is_tx_fifo_full() {}
273 301
274 self.send_cmd(Cmd::Stop, 0); 302 Self::send_cmd(Cmd::Stop, 0);
275 303
276 // Wait for TxFIFO to be drained 304 // Wait for TxFIFO to be drained
277 while !self.is_tx_fifo_empty() {} 305 while !Self::is_tx_fifo_empty() {}
278 306
279 self.status() 307 Self::status()
280 } 308 }
281 309
282 fn blocking_read_internal(&mut self, address: u8, read: &mut [u8], send_stop: SendStop) -> Result<()> { 310 fn blocking_read_internal(&mut self, address: u8, read: &mut [u8], send_stop: SendStop) -> Result<()> {
@@ -288,20 +316,20 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
288 self.start(address, true)?; 316 self.start(address, true)?;
289 317
290 // Wait until we have space in the TxFIFO 318 // Wait until we have space in the TxFIFO
291 while self.is_tx_fifo_full() {} 319 while Self::is_tx_fifo_full() {}
292 320
293 self.send_cmd(Cmd::Receive, (chunk.len() - 1) as u8); 321 Self::send_cmd(Cmd::Receive, (chunk.len() - 1) as u8);
294 322
295 for byte in chunk.iter_mut() { 323 for byte in chunk.iter_mut() {
296 // Wait until there's data in the RxFIFO 324 // Wait until there's data in the RxFIFO
297 while self.is_rx_fifo_empty() {} 325 while Self::is_rx_fifo_empty() {}
298 326
299 *byte = T::regs().mrdr().read().data().bits(); 327 *byte = T::regs().mrdr().read().data().bits();
300 } 328 }
301 } 329 }
302 330
303 if send_stop == SendStop::Yes { 331 if send_stop == SendStop::Yes {
304 self.stop()?; 332 Self::stop()?;
305 } 333 }
306 334
307 Ok(()) 335 Ok(())
@@ -327,13 +355,13 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
327 355
328 for byte in write { 356 for byte in write {
329 // Wait until we have space in the TxFIFO 357 // Wait until we have space in the TxFIFO
330 while self.is_tx_fifo_full() {} 358 while Self::is_tx_fifo_full() {}
331 359
332 self.send_cmd(Cmd::Transmit, *byte); 360 Self::send_cmd(Cmd::Transmit, *byte);
333 } 361 }
334 362
335 if send_stop == SendStop::Yes { 363 if send_stop == SendStop::Yes {
336 self.stop()?; 364 Self::stop()?;
337 } 365 }
338 366
339 Ok(()) 367 Ok(())
@@ -344,7 +372,6 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
344 /// Read from address into buffer blocking caller until done. 372 /// Read from address into buffer blocking caller until done.
345 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<()> { 373 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<()> {
346 self.blocking_read_internal(address, read, SendStop::Yes) 374 self.blocking_read_internal(address, read, SendStop::Yes)
347 // Automatic Stop
348 } 375 }
349 376
350 /// Write to address from buffer blocking caller until done. 377 /// Write to address from buffer blocking caller until done.
@@ -376,6 +403,19 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
376 Self::new_inner(peri, scl, sda, config) 403 Self::new_inner(peri, scl, sda, config)
377 } 404 }
378 405
406 fn remediation() {
407 #[cfg(feature = "defmt")]
408 defmt::trace!("Future dropped, issuing stop",);
409
410 // if the FIFO is not empty, drop its contents.
411 if !Self::is_tx_fifo_empty() {
412 Self::reset_fifos();
413 }
414
415 // send a stop command
416 let _ = Self::stop();
417 }
418
379 fn enable_rx_ints(&mut self) { 419 fn enable_rx_ints(&mut self) {
380 T::regs().mier().write(|w| { 420 T::regs().mier().write(|w| {
381 w.rdie() 421 w.rdie()
@@ -413,36 +453,36 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
413 453
414 // send the start command 454 // send the start command
415 let addr_rw = address << 1 | if read { 1 } else { 0 }; 455 let addr_rw = address << 1 | if read { 1 } else { 0 };
416 self.send_cmd(if self.is_hs { Cmd::StartHs } else { Cmd::Start }, addr_rw); 456 Self::send_cmd(if self.is_hs { Cmd::StartHs } else { Cmd::Start }, addr_rw);
417 457
418 T::wait_cell() 458 T::wait_cell()
419 .wait_for(|| { 459 .wait_for(|| {
420 // enable interrupts 460 // enable interrupts
421 self.enable_tx_ints(); 461 self.enable_tx_ints();
422 // if the command FIFO is empty, we're done sending start 462 // if the command FIFO is empty, we're done sending start
423 self.is_tx_fifo_empty() 463 Self::is_tx_fifo_empty()
424 }) 464 })
425 .await 465 .await
426 .map_err(|_| Error::Other)?; 466 .map_err(|_| Error::Other)?;
427 467
428 self.status() 468 Self::status()
429 } 469 }
430 470
431 async fn async_stop(&mut self) -> Result<()> { 471 async fn async_stop(&mut self) -> Result<()> {
432 // send the stop command 472 // send the stop command
433 self.send_cmd(Cmd::Stop, 0); 473 Self::send_cmd(Cmd::Stop, 0);
434 474
435 T::wait_cell() 475 T::wait_cell()
436 .wait_for(|| { 476 .wait_for(|| {
437 // enable interrupts 477 // enable interrupts
438 self.enable_tx_ints(); 478 self.enable_tx_ints();
439 // if the command FIFO is empty, we're done sending stop 479 // if the command FIFO is empty, we're done sending stop
440 self.is_tx_fifo_empty() 480 Self::is_tx_fifo_empty()
441 }) 481 })
442 .await 482 .await
443 .map_err(|_| Error::Other)?; 483 .map_err(|_| Error::Other)?;
444 484
445 self.status() 485 Self::status()
446 } 486 }
447 487
448 async fn async_read_internal(&mut self, address: u8, read: &mut [u8], send_stop: SendStop) -> Result<()> { 488 async fn async_read_internal(&mut self, address: u8, read: &mut [u8], send_stop: SendStop) -> Result<()> {
@@ -450,18 +490,21 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
450 return Err(Error::InvalidReadBufferLength); 490 return Err(Error::InvalidReadBufferLength);
451 } 491 }
452 492
493 // perform corrective action if the future is dropped
494 let on_drop = OnDrop::new(|| Self::remediation());
495
453 for chunk in read.chunks_mut(256) { 496 for chunk in read.chunks_mut(256) {
454 self.async_start(address, true).await?; 497 self.async_start(address, true).await?;
455 498
456 // send receive command 499 // send receive command
457 self.send_cmd(Cmd::Receive, (chunk.len() - 1) as u8); 500 Self::send_cmd(Cmd::Receive, (chunk.len() - 1) as u8);
458 501
459 T::wait_cell() 502 T::wait_cell()
460 .wait_for(|| { 503 .wait_for(|| {
461 // enable interrupts 504 // enable interrupts
462 self.enable_tx_ints(); 505 self.enable_tx_ints();
463 // if the command FIFO is empty, we're done sending start 506 // if the command FIFO is empty, we're done sending start
464 self.is_tx_fifo_empty() 507 Self::is_tx_fifo_empty()
465 }) 508 })
466 .await 509 .await
467 .map_err(|_| Error::Other)?; 510 .map_err(|_| Error::Other)?;
@@ -471,8 +514,8 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
471 .wait_for(|| { 514 .wait_for(|| {
472 // enable interrupts 515 // enable interrupts
473 self.enable_rx_ints(); 516 self.enable_rx_ints();
474 // it the rx FIFO is not empty, we need to read a byte 517 // if the rx FIFO is not empty, we need to read a byte
475 !self.is_rx_fifo_empty() 518 !Self::is_rx_fifo_empty()
476 }) 519 })
477 .await 520 .await
478 .map_err(|_| Error::ReadFail)?; 521 .map_err(|_| Error::ReadFail)?;
@@ -485,12 +528,18 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
485 self.async_stop().await?; 528 self.async_stop().await?;
486 } 529 }
487 530
531 // defuse it if the future is not dropped
532 on_drop.defuse();
533
488 Ok(()) 534 Ok(())
489 } 535 }
490 536
491 async fn async_write_internal(&mut self, address: u8, write: &[u8], send_stop: SendStop) -> Result<()> { 537 async fn async_write_internal(&mut self, address: u8, write: &[u8], send_stop: SendStop) -> Result<()> {
492 self.async_start(address, false).await?; 538 self.async_start(address, false).await?;
493 539
540 // perform corrective action if the future is dropped
541 let on_drop = OnDrop::new(|| Self::remediation());
542
494 // Usually, embassy HALs error out with an empty write, 543 // Usually, embassy HALs error out with an empty write,
495 // however empty writes are useful for writing I2C scanning 544 // however empty writes are useful for writing I2C scanning
496 // logic through write probing. That is, we send a start with 545 // logic through write probing. That is, we send a start with
@@ -511,10 +560,10 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
511 .wait_for(|| { 560 .wait_for(|| {
512 // enable interrupts 561 // enable interrupts
513 self.enable_tx_ints(); 562 self.enable_tx_ints();
514 // initiate trasmit 563 // initiate transmit
515 self.send_cmd(Cmd::Transmit, *byte); 564 Self::send_cmd(Cmd::Transmit, *byte);
516 // it the rx FIFO is not empty, we're done transmiting 565 // if the tx FIFO is empty, we're done transmiting
517 self.is_tx_fifo_empty() 566 Self::is_tx_fifo_empty()
518 }) 567 })
519 .await 568 .await
520 .map_err(|_| Error::WriteFail)?; 569 .map_err(|_| Error::WriteFail)?;
@@ -524,6 +573,9 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
524 self.async_stop().await?; 573 self.async_stop().await?;
525 } 574 }
526 575
576 // defuse it if the future is not dropped
577 on_drop.defuse();
578
527 Ok(()) 579 Ok(())
528 } 580 }
529 581