diff options
| author | Alex Moon <[email protected]> | 2024-08-14 17:07:57 -0400 |
|---|---|---|
| committer | Alex Moon <[email protected]> | 2024-10-23 16:44:07 -0400 |
| commit | 528a3e43550b5d2ce4a5f44d890feaa3e56c113a (patch) | |
| tree | 8d1c9b7c14d21178cc0932d1c773efd2c63ca656 | |
| parent | 8803128707b8bd9fc9dcea392a62dfd42aa822d2 (diff) | |
Add support for transactions to Twim in embassy-nrf
| -rw-r--r-- | embassy-nrf/src/twim.rs | 621 |
1 files changed, 377 insertions, 244 deletions
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index c64743ecc..d0518807c 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | use core::future::{poll_fn, Future}; | 5 | use core::future::{poll_fn, Future}; |
| 6 | use core::marker::PhantomData; | 6 | use core::marker::PhantomData; |
| 7 | use core::mem::MaybeUninit; | ||
| 7 | use core::sync::atomic::compiler_fence; | 8 | use core::sync::atomic::compiler_fence; |
| 8 | use core::sync::atomic::Ordering::SeqCst; | 9 | use core::sync::atomic::Ordering::SeqCst; |
| 9 | use core::task::Poll; | 10 | use core::task::Poll; |
| @@ -13,11 +14,12 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; | |||
| 13 | use embassy_sync::waitqueue::AtomicWaker; | 14 | use embassy_sync::waitqueue::AtomicWaker; |
| 14 | #[cfg(feature = "time")] | 15 | #[cfg(feature = "time")] |
| 15 | use embassy_time::{Duration, Instant}; | 16 | use embassy_time::{Duration, Instant}; |
| 17 | use embedded_hal_1::i2c::Operation; | ||
| 16 | 18 | ||
| 17 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | 19 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; |
| 18 | use crate::gpio::Pin as GpioPin; | 20 | use crate::gpio::Pin as GpioPin; |
| 19 | use crate::interrupt::typelevel::Interrupt; | 21 | use crate::interrupt::typelevel::Interrupt; |
| 20 | use crate::util::{slice_in_ram, slice_in_ram_or}; | 22 | use crate::util::slice_in_ram; |
| 21 | use crate::{gpio, interrupt, pac, Peripheral}; | 23 | use crate::{gpio, interrupt, pac, Peripheral}; |
| 22 | 24 | ||
| 23 | /// TWI frequency | 25 | /// TWI frequency |
| @@ -103,6 +105,18 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 103 | let r = T::regs(); | 105 | let r = T::regs(); |
| 104 | let s = T::state(); | 106 | let s = T::state(); |
| 105 | 107 | ||
| 108 | // Workaround for lack of LASTRX_SUSPEND short in some nRF chips | ||
| 109 | // Do this first to minimize latency | ||
| 110 | #[cfg(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120"))] | ||
| 111 | if r.events_lastrx.read().bits() != 0 { | ||
| 112 | r.tasks_suspend.write(|w| unsafe { w.bits(1) }); | ||
| 113 | r.events_lastrx.reset(); | ||
| 114 | } | ||
| 115 | |||
| 116 | if r.events_suspended.read().bits() != 0 { | ||
| 117 | s.end_waker.wake(); | ||
| 118 | r.intenclr.write(|w| w.suspended().clear()); | ||
| 119 | } | ||
| 106 | if r.events_stopped.read().bits() != 0 { | 120 | if r.events_stopped.read().bits() != 0 { |
| 107 | s.end_waker.wake(); | 121 | s.end_waker.wake(); |
| 108 | r.intenclr.write(|w| w.stopped().clear()); | 122 | r.intenclr.write(|w| w.stopped().clear()); |
| @@ -182,8 +196,22 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 182 | } | 196 | } |
| 183 | 197 | ||
| 184 | /// Set TX buffer, checking that it is in RAM and has suitable length. | 198 | /// Set TX buffer, checking that it is in RAM and has suitable length. |
| 185 | unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { | 199 | unsafe fn set_tx_buffer( |
| 186 | slice_in_ram_or(buffer, Error::BufferNotInRAM)?; | 200 | &mut self, |
| 201 | buffer: &[u8], | ||
| 202 | ram_buffer: Option<&mut [MaybeUninit<u8>; FORCE_COPY_BUFFER_SIZE]>, | ||
| 203 | ) -> Result<(), Error> { | ||
| 204 | let buffer = if slice_in_ram(buffer) { | ||
| 205 | buffer | ||
| 206 | } else { | ||
| 207 | let ram_buffer = ram_buffer.ok_or(Error::BufferNotInRAM)?; | ||
| 208 | trace!("Copying TWIM tx buffer into RAM for DMA"); | ||
| 209 | let ram_buffer = &mut ram_buffer[..buffer.len()]; | ||
| 210 | // Inline implementation of the nightly API MaybeUninit::copy_from_slice(ram_buffer, buffer) | ||
| 211 | let uninit_src: &[MaybeUninit<u8>] = unsafe { core::mem::transmute(buffer) }; | ||
| 212 | ram_buffer.copy_from_slice(uninit_src); | ||
| 213 | unsafe { &*(ram_buffer as *const [MaybeUninit<u8>] as *const [u8]) } | ||
| 214 | }; | ||
| 187 | 215 | ||
| 188 | if buffer.len() > EASY_DMA_SIZE { | 216 | if buffer.len() > EASY_DMA_SIZE { |
| 189 | return Err(Error::TxBufferTooLong); | 217 | return Err(Error::TxBufferTooLong); |
| @@ -290,7 +318,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 290 | fn blocking_wait(&mut self) { | 318 | fn blocking_wait(&mut self) { |
| 291 | let r = T::regs(); | 319 | let r = T::regs(); |
| 292 | loop { | 320 | loop { |
| 293 | if r.events_stopped.read().bits() != 0 { | 321 | if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 { |
| 294 | r.events_stopped.reset(); | 322 | r.events_stopped.reset(); |
| 295 | break; | 323 | break; |
| 296 | } | 324 | } |
| @@ -307,7 +335,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 307 | let r = T::regs(); | 335 | let r = T::regs(); |
| 308 | let deadline = Instant::now() + timeout; | 336 | let deadline = Instant::now() + timeout; |
| 309 | loop { | 337 | loop { |
| 310 | if r.events_stopped.read().bits() != 0 { | 338 | if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 { |
| 311 | r.events_stopped.reset(); | 339 | r.events_stopped.reset(); |
| 312 | break; | 340 | break; |
| 313 | } | 341 | } |
| @@ -331,7 +359,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 331 | let s = T::state(); | 359 | let s = T::state(); |
| 332 | 360 | ||
| 333 | s.end_waker.register(cx.waker()); | 361 | s.end_waker.register(cx.waker()); |
| 334 | if r.events_stopped.read().bits() != 0 { | 362 | if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 { |
| 335 | r.events_stopped.reset(); | 363 | r.events_stopped.reset(); |
| 336 | 364 | ||
| 337 | return Poll::Ready(()); | 365 | return Poll::Ready(()); |
| @@ -347,168 +375,357 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 347 | }) | 375 | }) |
| 348 | } | 376 | } |
| 349 | 377 | ||
| 350 | fn setup_write_from_ram(&mut self, address: u8, buffer: &[u8], inten: bool) -> Result<(), Error> { | 378 | fn setup_operations( |
| 379 | &mut self, | ||
| 380 | address: u8, | ||
| 381 | operations: &mut [Operation<'_>], | ||
| 382 | tx_ram_buffer: Option<&mut [MaybeUninit<u8>; FORCE_COPY_BUFFER_SIZE]>, | ||
| 383 | inten: bool, | ||
| 384 | stop: bool, | ||
| 385 | ) -> Result<(), Error> { | ||
| 351 | let r = T::regs(); | 386 | let r = T::regs(); |
| 352 | 387 | ||
| 353 | compiler_fence(SeqCst); | 388 | compiler_fence(SeqCst); |
| 354 | 389 | ||
| 355 | r.address.write(|w| unsafe { w.address().bits(address) }); | 390 | r.address.write(|w| unsafe { w.address().bits(address) }); |
| 356 | 391 | ||
| 357 | // Set up the DMA write. | 392 | let was_suspended = r.events_suspended.read().bits() != 0; |
| 358 | unsafe { self.set_tx_buffer(buffer)? }; | 393 | r.events_suspended.reset(); |
| 359 | |||
| 360 | // Clear events | ||
| 361 | r.events_stopped.reset(); | 394 | r.events_stopped.reset(); |
| 362 | r.events_error.reset(); | 395 | r.events_error.reset(); |
| 363 | r.events_lasttx.reset(); | ||
| 364 | self.clear_errorsrc(); | 396 | self.clear_errorsrc(); |
| 365 | 397 | ||
| 366 | if inten { | 398 | if inten { |
| 367 | r.intenset.write(|w| w.stopped().set().error().set()); | 399 | r.intenset.write(|w| w.suspended().set().stopped().set().error().set()); |
| 368 | } else { | 400 | } else { |
| 369 | r.intenclr.write(|w| w.stopped().clear().error().clear()); | 401 | r.intenclr |
| 402 | .write(|w| w.suspended().clear().stopped().clear().error().clear()); | ||
| 370 | } | 403 | } |
| 404 | #[cfg(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120"))] | ||
| 405 | r.intenclr.write(|w| w.lastrx().clear()); | ||
| 406 | |||
| 407 | match operations { | ||
| 408 | [Operation::Read(rd_buffer), Operation::Write(wr_buffer), rest @ ..] | ||
| 409 | if !rd_buffer.is_empty() && !wr_buffer.is_empty() => | ||
| 410 | { | ||
| 411 | let stop = stop && rest.is_empty(); | ||
| 412 | |||
| 413 | // Set up DMA buffers. | ||
| 414 | unsafe { | ||
| 415 | self.set_tx_buffer(wr_buffer, tx_ram_buffer)?; | ||
| 416 | self.set_rx_buffer(rd_buffer)?; | ||
| 417 | } | ||
| 371 | 418 | ||
| 372 | // Start write operation. | 419 | r.shorts.write(|w| { |
| 373 | r.shorts.write(|w| w.lasttx_stop().enabled()); | 420 | w.lastrx_starttx().enabled(); |
| 374 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | 421 | if stop { |
| 375 | if buffer.is_empty() { | 422 | w.lasttx_stop().enabled(); |
| 376 | // With a zero-length buffer, LASTTX doesn't fire (because there's no last byte!), so do the STOP ourselves. | 423 | } else { |
| 377 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | 424 | w.lasttx_suspend().enabled(); |
| 378 | } | 425 | } |
| 379 | Ok(()) | 426 | w |
| 380 | } | 427 | }); |
| 428 | |||
| 429 | // Start read+write operation. | ||
| 430 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||
| 431 | |||
| 432 | if was_suspended { | ||
| 433 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); | ||
| 434 | } | ||
| 435 | } | ||
| 436 | [Operation::Write(wr_buffer), Operation::Read(rd_buffer), rest @ ..] | ||
| 437 | if !wr_buffer.is_empty() && !rd_buffer.is_empty() => | ||
| 438 | { | ||
| 439 | let stop = stop && rest.is_empty(); | ||
| 440 | |||
| 441 | // Set up DMA buffers. | ||
| 442 | unsafe { | ||
| 443 | self.set_tx_buffer(wr_buffer, tx_ram_buffer)?; | ||
| 444 | self.set_rx_buffer(rd_buffer)?; | ||
| 445 | } | ||
| 381 | 446 | ||
| 382 | fn setup_read(&mut self, address: u8, buffer: &mut [u8], inten: bool) -> Result<(), Error> { | 447 | // Start write+read operation. |
| 383 | let r = T::regs(); | 448 | r.shorts.write(|w| { |
| 449 | w.lasttx_startrx().enabled(); | ||
| 450 | if stop { | ||
| 451 | w.lastrx_stop().enabled(); | ||
| 452 | } else { | ||
| 453 | #[cfg(not(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120")))] | ||
| 454 | w.lastrx_suspend().enabled(); | ||
| 455 | } | ||
| 456 | w | ||
| 457 | }); | ||
| 458 | #[cfg(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120"))] | ||
| 459 | if !stop { | ||
| 460 | r.intenset.write(|w| w.lastrx().set()); | ||
| 461 | } | ||
| 384 | 462 | ||
| 385 | compiler_fence(SeqCst); | 463 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); |
| 386 | 464 | ||
| 387 | r.address.write(|w| unsafe { w.address().bits(address) }); | 465 | if was_suspended { |
| 466 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); | ||
| 467 | } | ||
| 468 | } | ||
| 469 | [Operation::Read(buffer), rest @ ..] => { | ||
| 470 | let stop = stop && rest.is_empty(); | ||
| 388 | 471 | ||
| 389 | // Set up the DMA read. | 472 | // Set up DMA buffers. |
| 390 | unsafe { self.set_rx_buffer(buffer)? }; | 473 | unsafe { |
| 474 | self.set_rx_buffer(buffer)?; | ||
| 475 | } | ||
| 391 | 476 | ||
| 392 | // Clear events | 477 | // Start read operation. |
| 393 | r.events_stopped.reset(); | 478 | r.shorts.write(|w| { |
| 394 | r.events_error.reset(); | 479 | if stop { |
| 395 | self.clear_errorsrc(); | 480 | w.lastrx_stop().enabled(); |
| 481 | } else { | ||
| 482 | #[cfg(not(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120")))] | ||
| 483 | w.lastrx_suspend().enabled(); | ||
| 484 | } | ||
| 485 | w | ||
| 486 | }); | ||
| 487 | #[cfg(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120"))] | ||
| 488 | if !stop { | ||
| 489 | r.intenset.write(|w| w.lastrx().set()); | ||
| 490 | } | ||
| 396 | 491 | ||
| 397 | if inten { | 492 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); |
| 398 | r.intenset.write(|w| w.stopped().set().error().set()); | ||
| 399 | } else { | ||
| 400 | r.intenclr.write(|w| w.stopped().clear().error().clear()); | ||
| 401 | } | ||
| 402 | 493 | ||
| 403 | // Start read operation. | 494 | if was_suspended { |
| 404 | r.shorts.write(|w| w.lastrx_stop().enabled()); | 495 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); |
| 405 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | 496 | } |
| 406 | if buffer.is_empty() { | 497 | |
| 407 | // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP ourselves. | 498 | if buffer.is_empty() { |
| 408 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | 499 | // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP/SUSPEND ourselves. |
| 500 | if stop { | ||
| 501 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 502 | } else { | ||
| 503 | r.tasks_suspend.write(|w| unsafe { w.bits(1) }); | ||
| 504 | } | ||
| 505 | } | ||
| 506 | } | ||
| 507 | [Operation::Write(buffer), rest @ ..] => { | ||
| 508 | let stop = stop && rest.is_empty(); | ||
| 509 | |||
| 510 | // Set up DMA buffers. | ||
| 511 | unsafe { | ||
| 512 | self.set_tx_buffer(buffer, tx_ram_buffer)?; | ||
| 513 | } | ||
| 514 | |||
| 515 | // Start write operation. | ||
| 516 | r.shorts.write(|w| { | ||
| 517 | if stop { | ||
| 518 | w.lasttx_stop().enabled(); | ||
| 519 | } else { | ||
| 520 | w.lasttx_suspend().enabled(); | ||
| 521 | } | ||
| 522 | w | ||
| 523 | }); | ||
| 524 | |||
| 525 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||
| 526 | |||
| 527 | if was_suspended { | ||
| 528 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); | ||
| 529 | } | ||
| 530 | |||
| 531 | if buffer.is_empty() { | ||
| 532 | // With a zero-length buffer, LASTTX doesn't fire (because there's no last byte!), so do the STOP/SUSPEND ourselves. | ||
| 533 | if stop { | ||
| 534 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 535 | } else { | ||
| 536 | r.tasks_suspend.write(|w| unsafe { w.bits(1) }); | ||
| 537 | } | ||
| 538 | } | ||
| 539 | } | ||
| 540 | [] => { | ||
| 541 | if stop { | ||
| 542 | if was_suspended { | ||
| 543 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); | ||
| 544 | } | ||
| 545 | |||
| 546 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 547 | } | ||
| 548 | } | ||
| 409 | } | 549 | } |
| 550 | |||
| 410 | Ok(()) | 551 | Ok(()) |
| 411 | } | 552 | } |
| 412 | 553 | ||
| 413 | fn setup_write_read_from_ram( | 554 | fn check_operations(&mut self, operations: &mut [Operation<'_>]) -> Result<usize, Error> { |
| 414 | &mut self, | ||
| 415 | address: u8, | ||
| 416 | wr_buffer: &[u8], | ||
| 417 | rd_buffer: &mut [u8], | ||
| 418 | inten: bool, | ||
| 419 | ) -> Result<(), Error> { | ||
| 420 | let r = T::regs(); | ||
| 421 | |||
| 422 | compiler_fence(SeqCst); | 555 | compiler_fence(SeqCst); |
| 556 | self.check_errorsrc()?; | ||
| 423 | 557 | ||
| 424 | r.address.write(|w| unsafe { w.address().bits(address) }); | 558 | match operations { |
| 425 | 559 | [Operation::Read(rd_buffer), Operation::Write(wr_buffer), ..] | |
| 426 | // Set up DMA buffers. | 560 | | [Operation::Write(wr_buffer), Operation::Read(rd_buffer), ..] |
| 427 | unsafe { | 561 | if !rd_buffer.is_empty() && !wr_buffer.is_empty() => |
| 428 | self.set_tx_buffer(wr_buffer)?; | 562 | { |
| 429 | self.set_rx_buffer(rd_buffer)?; | 563 | self.check_tx(wr_buffer.len())?; |
| 564 | self.check_rx(rd_buffer.len())?; | ||
| 565 | Ok(2) | ||
| 566 | } | ||
| 567 | [Operation::Read(buffer), ..] => { | ||
| 568 | self.check_rx(buffer.len())?; | ||
| 569 | Ok(1) | ||
| 570 | } | ||
| 571 | [Operation::Write(buffer), ..] => { | ||
| 572 | self.check_tx(buffer.len())?; | ||
| 573 | Ok(1) | ||
| 574 | } | ||
| 575 | [] => Ok(0), | ||
| 430 | } | 576 | } |
| 577 | } | ||
| 431 | 578 | ||
| 432 | // Clear events | 579 | // =========================================== |
| 433 | r.events_stopped.reset(); | ||
| 434 | r.events_error.reset(); | ||
| 435 | self.clear_errorsrc(); | ||
| 436 | 580 | ||
| 437 | if inten { | 581 | /// Execute the provided operations on the I2C bus. |
| 438 | r.intenset.write(|w| w.stopped().set().error().set()); | 582 | /// |
| 439 | } else { | 583 | /// Each buffer must have a length of at most 255 bytes on the nRF52832 |
| 440 | r.intenclr.write(|w| w.stopped().clear().error().clear()); | 584 | /// and at most 65535 bytes on the nRF52840. |
| 585 | /// | ||
| 586 | /// If `stop` is set, the transaction will be terminated with a STOP | ||
| 587 | /// condition and the Twim will be stopped. Otherwise, the bus will be | ||
| 588 | /// left busy via clock stretching and Twim will be suspended. | ||
| 589 | /// | ||
| 590 | /// The nrf52832, nrf5340, and nrf9120 do not have hardware support for | ||
| 591 | /// suspending following a read operation therefore it is emulated by the | ||
| 592 | /// interrupt handler. If the latency of servicing that interrupt is | ||
| 593 | /// longer than a byte worth of clocks on the bus, the SCL clock will | ||
| 594 | /// continue to run for one or more additional bytes. This applies to | ||
| 595 | /// consecutive read operations, certain write-read-write sequences, or | ||
| 596 | /// any sequence of operations ending in a read when `stop == false`. | ||
| 597 | pub fn blocking_transaction( | ||
| 598 | &mut self, | ||
| 599 | address: u8, | ||
| 600 | mut operations: &mut [Operation<'_>], | ||
| 601 | stop: bool, | ||
| 602 | ) -> Result<(), Error> { | ||
| 603 | let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; | ||
| 604 | while !operations.is_empty() { | ||
| 605 | self.setup_operations(address, operations, Some(&mut tx_ram_buffer), false, stop)?; | ||
| 606 | self.blocking_wait(); | ||
| 607 | let consumed = self.check_operations(operations)?; | ||
| 608 | operations = &mut operations[consumed..]; | ||
| 609 | } | ||
| 610 | Ok(()) | ||
| 611 | } | ||
| 612 | |||
| 613 | /// Same as [`blocking_transaction`](Twim::blocking_transaction) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | ||
| 614 | pub fn blocking_transaction_from_ram( | ||
| 615 | &mut self, | ||
| 616 | address: u8, | ||
| 617 | mut operations: &mut [Operation<'_>], | ||
| 618 | stop: bool, | ||
| 619 | ) -> Result<(), Error> { | ||
| 620 | while !operations.is_empty() { | ||
| 621 | self.setup_operations(address, operations, None, false, stop)?; | ||
| 622 | self.blocking_wait(); | ||
| 623 | let consumed = self.check_operations(operations)?; | ||
| 624 | operations = &mut operations[consumed..]; | ||
| 441 | } | 625 | } |
| 626 | Ok(()) | ||
| 627 | } | ||
| 442 | 628 | ||
| 443 | // Start write+read operation. | 629 | /// Execute the provided operations on the I2C bus with timeout. |
| 444 | r.shorts.write(|w| { | 630 | /// |
| 445 | w.lasttx_startrx().enabled(); | 631 | /// See [`blocking_transaction`]. |
| 446 | w.lastrx_stop().enabled(); | 632 | #[cfg(feature = "time")] |
| 447 | w | 633 | pub fn blocking_transaction_timeout( |
| 448 | }); | 634 | &mut self, |
| 449 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | 635 | address: u8, |
| 450 | if wr_buffer.is_empty() && rd_buffer.is_empty() { | 636 | mut operations: &mut [Operation<'_>], |
| 451 | // With a zero-length buffer, LASTRX/LASTTX doesn't fire (because there's no last byte!), so do the STOP ourselves. | 637 | stop: bool, |
| 452 | // TODO handle when only one of the buffers is zero length | 638 | timeout: Duration, |
| 453 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | 639 | ) -> Result<(), Error> { |
| 640 | let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; | ||
| 641 | while !operations.is_empty() { | ||
| 642 | self.setup_operations(address, operations, Some(&mut tx_ram_buffer), false, stop)?; | ||
| 643 | self.blocking_wait_timeout(timeout)?; | ||
| 644 | let consumed = self.check_operations(operations)?; | ||
| 645 | operations = &mut operations[consumed..]; | ||
| 454 | } | 646 | } |
| 647 | Ok(()) | ||
| 648 | } | ||
| 455 | 649 | ||
| 650 | /// Same as [`blocking_transaction_timeout`](Twim::blocking_transaction_timeout) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | ||
| 651 | #[cfg(feature = "time")] | ||
| 652 | pub fn blocking_transaction_from_ram_timeout( | ||
| 653 | &mut self, | ||
| 654 | address: u8, | ||
| 655 | mut operations: &mut [Operation<'_>], | ||
| 656 | stop: bool, | ||
| 657 | timeout: Duration, | ||
| 658 | ) -> Result<(), Error> { | ||
| 659 | while !operations.is_empty() { | ||
| 660 | self.setup_operations(address, operations, None, false, stop)?; | ||
| 661 | self.blocking_wait_timeout(timeout)?; | ||
| 662 | let consumed = self.check_operations(operations)?; | ||
| 663 | operations = &mut operations[consumed..]; | ||
| 664 | } | ||
| 456 | Ok(()) | 665 | Ok(()) |
| 457 | } | 666 | } |
| 458 | 667 | ||
| 459 | fn setup_write_read( | 668 | /// Execute the provided operations on the I2C bus. |
| 669 | /// | ||
| 670 | /// Each buffer must have a length of at most 255 bytes on the nRF52832 | ||
| 671 | /// and at most 65535 bytes on the nRF52840. | ||
| 672 | /// | ||
| 673 | /// If `stop` is set, the transaction will be terminated with a STOP | ||
| 674 | /// condition and the Twim will be stopped. Otherwise, the bus will be | ||
| 675 | /// left busy via clock stretching and Twim will be suspended. | ||
| 676 | /// | ||
| 677 | /// The nrf52832, nrf5340, and nrf9120 do not have hardware support for | ||
| 678 | /// suspending following a read operation therefore it is emulated by the | ||
| 679 | /// interrupt handler. If the latency of servicing that interrupt is | ||
| 680 | /// longer than a byte worth of clocks on the bus, the SCL clock will | ||
| 681 | /// continue to run for one or more additional bytes. This applies to | ||
| 682 | /// consecutive read operations, certain write-read-write sequences, or | ||
| 683 | /// any sequence of operations ending in a read when `stop == false`. | ||
| 684 | pub async fn transaction( | ||
| 460 | &mut self, | 685 | &mut self, |
| 461 | address: u8, | 686 | address: u8, |
| 462 | wr_buffer: &[u8], | 687 | mut operations: &mut [Operation<'_>], |
| 463 | rd_buffer: &mut [u8], | 688 | stop: bool, |
| 464 | inten: bool, | ||
| 465 | ) -> Result<(), Error> { | 689 | ) -> Result<(), Error> { |
| 466 | match self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, inten) { | 690 | let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; |
| 467 | Ok(_) => Ok(()), | 691 | while !operations.is_empty() { |
| 468 | Err(Error::BufferNotInRAM) => { | 692 | self.setup_operations(address, operations, Some(&mut tx_ram_buffer), true, stop)?; |
| 469 | trace!("Copying TWIM tx buffer into RAM for DMA"); | 693 | self.async_wait().await; |
| 470 | let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; | 694 | let consumed = self.check_operations(operations)?; |
| 471 | tx_ram_buf.copy_from_slice(wr_buffer); | 695 | operations = &mut operations[consumed..]; |
| 472 | self.setup_write_read_from_ram(address, tx_ram_buf, rd_buffer, inten) | ||
| 473 | } | ||
| 474 | Err(error) => Err(error), | ||
| 475 | } | 696 | } |
| 697 | Ok(()) | ||
| 476 | } | 698 | } |
| 477 | 699 | ||
| 478 | fn setup_write(&mut self, address: u8, wr_buffer: &[u8], inten: bool) -> Result<(), Error> { | 700 | /// Same as [`transaction`](Twim::transaction) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. |
| 479 | match self.setup_write_from_ram(address, wr_buffer, inten) { | 701 | pub async fn transaction_from_ram( |
| 480 | Ok(_) => Ok(()), | 702 | &mut self, |
| 481 | Err(Error::BufferNotInRAM) => { | 703 | address: u8, |
| 482 | trace!("Copying TWIM tx buffer into RAM for DMA"); | 704 | mut operations: &mut [Operation<'_>], |
| 483 | let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; | 705 | stop: bool, |
| 484 | tx_ram_buf.copy_from_slice(wr_buffer); | 706 | ) -> Result<(), Error> { |
| 485 | self.setup_write_from_ram(address, tx_ram_buf, inten) | 707 | while !operations.is_empty() { |
| 486 | } | 708 | self.setup_operations(address, operations, None, true, stop)?; |
| 487 | Err(error) => Err(error), | 709 | self.async_wait().await; |
| 710 | let consumed = self.check_operations(operations)?; | ||
| 711 | operations = &mut operations[consumed..]; | ||
| 488 | } | 712 | } |
| 713 | Ok(()) | ||
| 489 | } | 714 | } |
| 490 | 715 | ||
| 716 | // =========================================== | ||
| 717 | |||
| 491 | /// Write to an I2C slave. | 718 | /// Write to an I2C slave. |
| 492 | /// | 719 | /// |
| 493 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | 720 | /// The buffer must have a length of at most 255 bytes on the nRF52832 |
| 494 | /// and at most 65535 bytes on the nRF52840. | 721 | /// and at most 65535 bytes on the nRF52840. |
| 495 | pub fn blocking_write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { | 722 | pub fn blocking_write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { |
| 496 | self.setup_write(address, buffer, false)?; | 723 | self.blocking_transaction(address, &mut [Operation::Write(buffer)], true) |
| 497 | self.blocking_wait(); | ||
| 498 | compiler_fence(SeqCst); | ||
| 499 | self.check_errorsrc()?; | ||
| 500 | self.check_tx(buffer.len())?; | ||
| 501 | Ok(()) | ||
| 502 | } | 724 | } |
| 503 | 725 | ||
| 504 | /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | 726 | /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. |
| 505 | pub fn blocking_write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { | 727 | pub fn blocking_write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { |
| 506 | self.setup_write_from_ram(address, buffer, false)?; | 728 | self.blocking_transaction_from_ram(address, &mut [Operation::Write(buffer)], true) |
| 507 | self.blocking_wait(); | ||
| 508 | compiler_fence(SeqCst); | ||
| 509 | self.check_errorsrc()?; | ||
| 510 | self.check_tx(buffer.len())?; | ||
| 511 | Ok(()) | ||
| 512 | } | 729 | } |
| 513 | 730 | ||
| 514 | /// Read from an I2C slave. | 731 | /// Read from an I2C slave. |
| @@ -516,12 +733,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 516 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | 733 | /// The buffer must have a length of at most 255 bytes on the nRF52832 |
| 517 | /// and at most 65535 bytes on the nRF52840. | 734 | /// and at most 65535 bytes on the nRF52840. |
| 518 | pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | 735 | pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { |
| 519 | self.setup_read(address, buffer, false)?; | 736 | self.blocking_transaction(address, &mut [Operation::Read(buffer)], true) |
| 520 | self.blocking_wait(); | ||
| 521 | compiler_fence(SeqCst); | ||
| 522 | self.check_errorsrc()?; | ||
| 523 | self.check_rx(buffer.len())?; | ||
| 524 | Ok(()) | ||
| 525 | } | 737 | } |
| 526 | 738 | ||
| 527 | /// Write data to an I2C slave, then read data from the slave without | 739 | /// Write data to an I2C slave, then read data from the slave without |
| @@ -530,13 +742,11 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 530 | /// The buffers must have a length of at most 255 bytes on the nRF52832 | 742 | /// The buffers must have a length of at most 255 bytes on the nRF52832 |
| 531 | /// and at most 65535 bytes on the nRF52840. | 743 | /// and at most 65535 bytes on the nRF52840. |
| 532 | pub fn blocking_write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Error> { | 744 | pub fn blocking_write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Error> { |
| 533 | self.setup_write_read(address, wr_buffer, rd_buffer, false)?; | 745 | self.blocking_transaction( |
| 534 | self.blocking_wait(); | 746 | address, |
| 535 | compiler_fence(SeqCst); | 747 | &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], |
| 536 | self.check_errorsrc()?; | 748 | true, |
| 537 | self.check_tx(wr_buffer.len())?; | 749 | ) |
| 538 | self.check_rx(rd_buffer.len())?; | ||
| 539 | Ok(()) | ||
| 540 | } | 750 | } |
| 541 | 751 | ||
| 542 | /// Same as [`blocking_write_read`](Twim::blocking_write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | 752 | /// Same as [`blocking_write_read`](Twim::blocking_write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. |
| @@ -546,13 +756,11 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 546 | wr_buffer: &[u8], | 756 | wr_buffer: &[u8], |
| 547 | rd_buffer: &mut [u8], | 757 | rd_buffer: &mut [u8], |
| 548 | ) -> Result<(), Error> { | 758 | ) -> Result<(), Error> { |
| 549 | self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, false)?; | 759 | self.blocking_transaction_from_ram( |
| 550 | self.blocking_wait(); | 760 | address, |
| 551 | compiler_fence(SeqCst); | 761 | &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], |
| 552 | self.check_errorsrc()?; | 762 | true, |
| 553 | self.check_tx(wr_buffer.len())?; | 763 | ) |
| 554 | self.check_rx(rd_buffer.len())?; | ||
| 555 | Ok(()) | ||
| 556 | } | 764 | } |
| 557 | 765 | ||
| 558 | // =========================================== | 766 | // =========================================== |
| @@ -562,12 +770,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 562 | /// See [`blocking_write`]. | 770 | /// See [`blocking_write`]. |
| 563 | #[cfg(feature = "time")] | 771 | #[cfg(feature = "time")] |
| 564 | pub fn blocking_write_timeout(&mut self, address: u8, buffer: &[u8], timeout: Duration) -> Result<(), Error> { | 772 | pub fn blocking_write_timeout(&mut self, address: u8, buffer: &[u8], timeout: Duration) -> Result<(), Error> { |
| 565 | self.setup_write(address, buffer, false)?; | 773 | self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], true, timeout) |
| 566 | self.blocking_wait_timeout(timeout)?; | ||
| 567 | compiler_fence(SeqCst); | ||
| 568 | self.check_errorsrc()?; | ||
| 569 | self.check_tx(buffer.len())?; | ||
| 570 | Ok(()) | ||
| 571 | } | 774 | } |
| 572 | 775 | ||
| 573 | /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | 776 | /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. |
| @@ -578,12 +781,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 578 | buffer: &[u8], | 781 | buffer: &[u8], |
| 579 | timeout: Duration, | 782 | timeout: Duration, |
| 580 | ) -> Result<(), Error> { | 783 | ) -> Result<(), Error> { |
| 581 | self.setup_write_from_ram(address, buffer, false)?; | 784 | self.blocking_transaction_from_ram_timeout(address, &mut [Operation::Write(buffer)], true, timeout) |
| 582 | self.blocking_wait_timeout(timeout)?; | ||
| 583 | compiler_fence(SeqCst); | ||
| 584 | self.check_errorsrc()?; | ||
| 585 | self.check_tx(buffer.len())?; | ||
| 586 | Ok(()) | ||
| 587 | } | 785 | } |
| 588 | 786 | ||
| 589 | /// Read from an I2C slave. | 787 | /// Read from an I2C slave. |
| @@ -592,12 +790,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 592 | /// and at most 65535 bytes on the nRF52840. | 790 | /// and at most 65535 bytes on the nRF52840. |
| 593 | #[cfg(feature = "time")] | 791 | #[cfg(feature = "time")] |
| 594 | pub fn blocking_read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> { | 792 | pub fn blocking_read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> { |
| 595 | self.setup_read(address, buffer, false)?; | 793 | self.blocking_transaction_timeout(address, &mut [Operation::Read(buffer)], true, timeout) |
| 596 | self.blocking_wait_timeout(timeout)?; | ||
| 597 | compiler_fence(SeqCst); | ||
| 598 | self.check_errorsrc()?; | ||
| 599 | self.check_rx(buffer.len())?; | ||
| 600 | Ok(()) | ||
| 601 | } | 794 | } |
| 602 | 795 | ||
| 603 | /// Write data to an I2C slave, then read data from the slave without | 796 | /// Write data to an I2C slave, then read data from the slave without |
| @@ -613,13 +806,12 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 613 | rd_buffer: &mut [u8], | 806 | rd_buffer: &mut [u8], |
| 614 | timeout: Duration, | 807 | timeout: Duration, |
| 615 | ) -> Result<(), Error> { | 808 | ) -> Result<(), Error> { |
| 616 | self.setup_write_read(address, wr_buffer, rd_buffer, false)?; | 809 | self.blocking_transaction_timeout( |
| 617 | self.blocking_wait_timeout(timeout)?; | 810 | address, |
| 618 | compiler_fence(SeqCst); | 811 | &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], |
| 619 | self.check_errorsrc()?; | 812 | true, |
| 620 | self.check_tx(wr_buffer.len())?; | 813 | timeout, |
| 621 | self.check_rx(rd_buffer.len())?; | 814 | ) |
| 622 | Ok(()) | ||
| 623 | } | 815 | } |
| 624 | 816 | ||
| 625 | /// Same as [`blocking_write_read`](Twim::blocking_write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | 817 | /// Same as [`blocking_write_read`](Twim::blocking_write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. |
| @@ -631,13 +823,12 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 631 | rd_buffer: &mut [u8], | 823 | rd_buffer: &mut [u8], |
| 632 | timeout: Duration, | 824 | timeout: Duration, |
| 633 | ) -> Result<(), Error> { | 825 | ) -> Result<(), Error> { |
| 634 | self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, false)?; | 826 | self.blocking_transaction_from_ram_timeout( |
| 635 | self.blocking_wait_timeout(timeout)?; | 827 | address, |
| 636 | compiler_fence(SeqCst); | 828 | &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], |
| 637 | self.check_errorsrc()?; | 829 | true, |
| 638 | self.check_tx(wr_buffer.len())?; | 830 | timeout, |
| 639 | self.check_rx(rd_buffer.len())?; | 831 | ) |
| 640 | Ok(()) | ||
| 641 | } | 832 | } |
| 642 | 833 | ||
| 643 | // =========================================== | 834 | // =========================================== |
| @@ -647,12 +838,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 647 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | 838 | /// The buffer must have a length of at most 255 bytes on the nRF52832 |
| 648 | /// and at most 65535 bytes on the nRF52840. | 839 | /// and at most 65535 bytes on the nRF52840. |
| 649 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | 840 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { |
| 650 | self.setup_read(address, buffer, true)?; | 841 | self.transaction(address, &mut [Operation::Read(buffer)], true).await |
| 651 | self.async_wait().await; | ||
| 652 | compiler_fence(SeqCst); | ||
| 653 | self.check_errorsrc()?; | ||
| 654 | self.check_rx(buffer.len())?; | ||
| 655 | Ok(()) | ||
| 656 | } | 842 | } |
| 657 | 843 | ||
| 658 | /// Write to an I2C slave. | 844 | /// Write to an I2C slave. |
| @@ -660,22 +846,13 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 660 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | 846 | /// The buffer must have a length of at most 255 bytes on the nRF52832 |
| 661 | /// and at most 65535 bytes on the nRF52840. | 847 | /// and at most 65535 bytes on the nRF52840. |
| 662 | pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { | 848 | pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { |
| 663 | self.setup_write(address, buffer, true)?; | 849 | self.transaction(address, &mut [Operation::Write(buffer)], true).await |
| 664 | self.async_wait().await; | ||
| 665 | compiler_fence(SeqCst); | ||
| 666 | self.check_errorsrc()?; | ||
| 667 | self.check_tx(buffer.len())?; | ||
| 668 | Ok(()) | ||
| 669 | } | 850 | } |
| 670 | 851 | ||
| 671 | /// Same as [`write`](Twim::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | 852 | /// Same as [`write`](Twim::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. |
| 672 | pub async fn write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { | 853 | pub async fn write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { |
| 673 | self.setup_write_from_ram(address, buffer, true)?; | 854 | self.transaction_from_ram(address, &mut [Operation::Write(buffer)], true) |
| 674 | self.async_wait().await; | 855 | .await |
| 675 | compiler_fence(SeqCst); | ||
| 676 | self.check_errorsrc()?; | ||
| 677 | self.check_tx(buffer.len())?; | ||
| 678 | Ok(()) | ||
| 679 | } | 856 | } |
| 680 | 857 | ||
| 681 | /// Write data to an I2C slave, then read data from the slave without | 858 | /// Write data to an I2C slave, then read data from the slave without |
| @@ -684,13 +861,12 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 684 | /// The buffers must have a length of at most 255 bytes on the nRF52832 | 861 | /// The buffers must have a length of at most 255 bytes on the nRF52832 |
| 685 | /// and at most 65535 bytes on the nRF52840. | 862 | /// and at most 65535 bytes on the nRF52840. |
| 686 | pub async fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Error> { | 863 | pub async fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Error> { |
| 687 | self.setup_write_read(address, wr_buffer, rd_buffer, true)?; | 864 | self.transaction( |
| 688 | self.async_wait().await; | 865 | address, |
| 689 | compiler_fence(SeqCst); | 866 | &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], |
| 690 | self.check_errorsrc()?; | 867 | true, |
| 691 | self.check_tx(wr_buffer.len())?; | 868 | ) |
| 692 | self.check_rx(rd_buffer.len())?; | 869 | .await |
| 693 | Ok(()) | ||
| 694 | } | 870 | } |
| 695 | 871 | ||
| 696 | /// Same as [`write_read`](Twim::write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | 872 | /// Same as [`write_read`](Twim::write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. |
| @@ -700,13 +876,12 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 700 | wr_buffer: &[u8], | 876 | wr_buffer: &[u8], |
| 701 | rd_buffer: &mut [u8], | 877 | rd_buffer: &mut [u8], |
| 702 | ) -> Result<(), Error> { | 878 | ) -> Result<(), Error> { |
| 703 | self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, true)?; | 879 | self.transaction_from_ram( |
| 704 | self.async_wait().await; | 880 | address, |
| 705 | compiler_fence(SeqCst); | 881 | &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], |
| 706 | self.check_errorsrc()?; | 882 | true, |
| 707 | self.check_tx(wr_buffer.len())?; | 883 | ) |
| 708 | self.check_rx(rd_buffer.len())?; | 884 | .await |
| 709 | Ok(()) | ||
| 710 | } | 885 | } |
| 711 | } | 886 | } |
| 712 | 887 | ||
| @@ -777,16 +952,7 @@ mod eh02 { | |||
| 777 | type Error = Error; | 952 | type Error = Error; |
| 778 | 953 | ||
| 779 | fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { | 954 | fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { |
| 780 | if slice_in_ram(bytes) { | 955 | self.blocking_write(addr, bytes) |
| 781 | self.blocking_write(addr, bytes) | ||
| 782 | } else { | ||
| 783 | let buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..]; | ||
| 784 | for chunk in bytes.chunks(FORCE_COPY_BUFFER_SIZE) { | ||
| 785 | buf[..chunk.len()].copy_from_slice(chunk); | ||
| 786 | self.blocking_write(addr, &buf[..chunk.len()])?; | ||
| 787 | } | ||
| 788 | Ok(()) | ||
| 789 | } | ||
| 790 | } | 956 | } |
| 791 | } | 957 | } |
| 792 | 958 | ||
| @@ -832,47 +998,14 @@ impl<'d, T: Instance> embedded_hal_1::i2c::ErrorType for Twim<'d, T> { | |||
| 832 | } | 998 | } |
| 833 | 999 | ||
| 834 | impl<'d, T: Instance> embedded_hal_1::i2c::I2c for Twim<'d, T> { | 1000 | impl<'d, T: Instance> embedded_hal_1::i2c::I2c for Twim<'d, T> { |
| 835 | fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { | 1001 | fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { |
| 836 | self.blocking_read(address, buffer) | 1002 | self.blocking_transaction(address, operations, true) |
| 837 | } | ||
| 838 | |||
| 839 | fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 840 | self.blocking_write(address, buffer) | ||
| 841 | } | ||
| 842 | |||
| 843 | fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
| 844 | self.blocking_write_read(address, wr_buffer, rd_buffer) | ||
| 845 | } | ||
| 846 | |||
| 847 | fn transaction( | ||
| 848 | &mut self, | ||
| 849 | _address: u8, | ||
| 850 | _operations: &mut [embedded_hal_1::i2c::Operation<'_>], | ||
| 851 | ) -> Result<(), Self::Error> { | ||
| 852 | todo!(); | ||
| 853 | } | 1003 | } |
| 854 | } | 1004 | } |
| 855 | 1005 | ||
| 856 | impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> { | 1006 | impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> { |
| 857 | async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { | 1007 | async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { |
| 858 | self.read(address, read).await | 1008 | self.transaction(address, operations, true).await |
| 859 | } | ||
| 860 | |||
| 861 | async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { | ||
| 862 | self.write(address, write).await | ||
| 863 | } | ||
| 864 | async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { | ||
| 865 | self.write_read(address, write, read).await | ||
| 866 | } | ||
| 867 | |||
| 868 | async fn transaction( | ||
| 869 | &mut self, | ||
| 870 | address: u8, | ||
| 871 | operations: &mut [embedded_hal_1::i2c::Operation<'_>], | ||
| 872 | ) -> Result<(), Self::Error> { | ||
| 873 | let _ = address; | ||
| 874 | let _ = operations; | ||
| 875 | todo!() | ||
| 876 | } | 1009 | } |
| 877 | } | 1010 | } |
| 878 | 1011 | ||
