diff options
| -rw-r--r-- | embassy-nrf/src/twim.rs | 557 |
1 files changed, 312 insertions, 245 deletions
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index c64743ecc..187fce021 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,10 @@ 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 | if r.events_suspended.read().bits() != 0 { | ||
| 109 | s.end_waker.wake(); | ||
| 110 | r.intenclr.write(|w| w.suspended().clear()); | ||
| 111 | } | ||
| 106 | if r.events_stopped.read().bits() != 0 { | 112 | if r.events_stopped.read().bits() != 0 { |
| 107 | s.end_waker.wake(); | 113 | s.end_waker.wake(); |
| 108 | r.intenclr.write(|w| w.stopped().clear()); | 114 | r.intenclr.write(|w| w.stopped().clear()); |
| @@ -182,8 +188,22 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 182 | } | 188 | } |
| 183 | 189 | ||
| 184 | /// Set TX buffer, checking that it is in RAM and has suitable length. | 190 | /// 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> { | 191 | unsafe fn set_tx_buffer( |
| 186 | slice_in_ram_or(buffer, Error::BufferNotInRAM)?; | 192 | &mut self, |
| 193 | buffer: &[u8], | ||
| 194 | ram_buffer: Option<&mut [MaybeUninit<u8>; FORCE_COPY_BUFFER_SIZE]>, | ||
| 195 | ) -> Result<(), Error> { | ||
| 196 | let buffer = if slice_in_ram(buffer) { | ||
| 197 | buffer | ||
| 198 | } else { | ||
| 199 | let ram_buffer = ram_buffer.ok_or(Error::BufferNotInRAM)?; | ||
| 200 | trace!("Copying TWIM tx buffer into RAM for DMA"); | ||
| 201 | let ram_buffer = &mut ram_buffer[..buffer.len()]; | ||
| 202 | // Inline implementation of the nightly API MaybeUninit::copy_from_slice(ram_buffer, buffer) | ||
| 203 | let uninit_src: &[MaybeUninit<u8>] = unsafe { core::mem::transmute(buffer) }; | ||
| 204 | ram_buffer.copy_from_slice(uninit_src); | ||
| 205 | unsafe { &*(ram_buffer as *const [MaybeUninit<u8>] as *const [u8]) } | ||
| 206 | }; | ||
| 187 | 207 | ||
| 188 | if buffer.len() > EASY_DMA_SIZE { | 208 | if buffer.len() > EASY_DMA_SIZE { |
| 189 | return Err(Error::TxBufferTooLong); | 209 | return Err(Error::TxBufferTooLong); |
| @@ -290,7 +310,8 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 290 | fn blocking_wait(&mut self) { | 310 | fn blocking_wait(&mut self) { |
| 291 | let r = T::regs(); | 311 | let r = T::regs(); |
| 292 | loop { | 312 | loop { |
| 293 | if r.events_stopped.read().bits() != 0 { | 313 | if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 { |
| 314 | r.events_suspended.reset(); | ||
| 294 | r.events_stopped.reset(); | 315 | r.events_stopped.reset(); |
| 295 | break; | 316 | break; |
| 296 | } | 317 | } |
| @@ -307,7 +328,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 307 | let r = T::regs(); | 328 | let r = T::regs(); |
| 308 | let deadline = Instant::now() + timeout; | 329 | let deadline = Instant::now() + timeout; |
| 309 | loop { | 330 | loop { |
| 310 | if r.events_stopped.read().bits() != 0 { | 331 | if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 { |
| 311 | r.events_stopped.reset(); | 332 | r.events_stopped.reset(); |
| 312 | break; | 333 | break; |
| 313 | } | 334 | } |
| @@ -331,7 +352,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 331 | let s = T::state(); | 352 | let s = T::state(); |
| 332 | 353 | ||
| 333 | s.end_waker.register(cx.waker()); | 354 | s.end_waker.register(cx.waker()); |
| 334 | if r.events_stopped.read().bits() != 0 { | 355 | if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 { |
| 335 | r.events_stopped.reset(); | 356 | r.events_stopped.reset(); |
| 336 | 357 | ||
| 337 | return Poll::Ready(()); | 358 | return Poll::Ready(()); |
| @@ -347,168 +368,316 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 347 | }) | 368 | }) |
| 348 | } | 369 | } |
| 349 | 370 | ||
| 350 | fn setup_write_from_ram(&mut self, address: u8, buffer: &[u8], inten: bool) -> Result<(), Error> { | 371 | fn setup_operations( |
| 372 | &mut self, | ||
| 373 | address: u8, | ||
| 374 | operations: &mut [Operation<'_>], | ||
| 375 | tx_ram_buffer: Option<&mut [MaybeUninit<u8>; FORCE_COPY_BUFFER_SIZE]>, | ||
| 376 | last_op: Option<&Operation<'_>>, | ||
| 377 | inten: bool, | ||
| 378 | ) -> Result<usize, Error> { | ||
| 351 | let r = T::regs(); | 379 | let r = T::regs(); |
| 352 | 380 | ||
| 353 | compiler_fence(SeqCst); | 381 | compiler_fence(SeqCst); |
| 354 | 382 | ||
| 355 | r.address.write(|w| unsafe { w.address().bits(address) }); | 383 | r.address.write(|w| unsafe { w.address().bits(address) }); |
| 356 | 384 | ||
| 357 | // Set up the DMA write. | 385 | r.events_suspended.reset(); |
| 358 | unsafe { self.set_tx_buffer(buffer)? }; | ||
| 359 | |||
| 360 | // Clear events | ||
| 361 | r.events_stopped.reset(); | 386 | r.events_stopped.reset(); |
| 362 | r.events_error.reset(); | 387 | r.events_error.reset(); |
| 363 | r.events_lasttx.reset(); | ||
| 364 | self.clear_errorsrc(); | 388 | self.clear_errorsrc(); |
| 365 | 389 | ||
| 366 | if inten { | 390 | if inten { |
| 367 | r.intenset.write(|w| w.stopped().set().error().set()); | 391 | r.intenset.write(|w| w.suspended().set().stopped().set().error().set()); |
| 368 | } else { | 392 | } else { |
| 369 | r.intenclr.write(|w| w.stopped().clear().error().clear()); | 393 | r.intenclr |
| 394 | .write(|w| w.suspended().clear().stopped().clear().error().clear()); | ||
| 370 | } | 395 | } |
| 371 | 396 | ||
| 372 | // Start write operation. | 397 | assert!(!operations.is_empty()); |
| 373 | r.shorts.write(|w| w.lasttx_stop().enabled()); | 398 | match operations { |
| 374 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | 399 | [Operation::Read(_), Operation::Read(_), ..] => { |
| 375 | if buffer.is_empty() { | 400 | panic!("Consecutive read operations are not supported!") |
| 376 | // With a zero-length buffer, LASTTX doesn't fire (because there's no last byte!), so do the STOP ourselves. | 401 | } |
| 377 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | 402 | [Operation::Read(rd_buffer), Operation::Write(wr_buffer), rest @ ..] => { |
| 378 | } | 403 | let stop = rest.is_empty(); |
| 379 | Ok(()) | ||
| 380 | } | ||
| 381 | 404 | ||
| 382 | fn setup_read(&mut self, address: u8, buffer: &mut [u8], inten: bool) -> Result<(), Error> { | 405 | // Set up DMA buffers. |
| 383 | let r = T::regs(); | 406 | unsafe { |
| 407 | self.set_tx_buffer(wr_buffer, tx_ram_buffer)?; | ||
| 408 | self.set_rx_buffer(rd_buffer)?; | ||
| 409 | } | ||
| 384 | 410 | ||
| 385 | compiler_fence(SeqCst); | 411 | r.shorts.write(|w| { |
| 412 | w.lastrx_starttx().enabled(); | ||
| 413 | if stop { | ||
| 414 | w.lasttx_stop().enabled(); | ||
| 415 | } else { | ||
| 416 | w.lasttx_suspend().enabled(); | ||
| 417 | } | ||
| 418 | w | ||
| 419 | }); | ||
| 420 | |||
| 421 | // Start read+write operation. | ||
| 422 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||
| 423 | if last_op.is_some() { | ||
| 424 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); | ||
| 425 | } | ||
| 386 | 426 | ||
| 387 | r.address.write(|w| unsafe { w.address().bits(address) }); | 427 | // TODO: Handle empty write buffer |
| 428 | if rd_buffer.is_empty() { | ||
| 429 | // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STARTTX ourselves. | ||
| 430 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||
| 431 | } | ||
| 432 | |||
| 433 | Ok(2) | ||
| 434 | } | ||
| 435 | [Operation::Read(buffer)] => { | ||
| 436 | // Set up DMA buffers. | ||
| 437 | unsafe { | ||
| 438 | self.set_rx_buffer(buffer)?; | ||
| 439 | } | ||
| 388 | 440 | ||
| 389 | // Set up the DMA read. | 441 | r.shorts.write(|w| w.lastrx_stop().enabled()); |
| 390 | unsafe { self.set_rx_buffer(buffer)? }; | ||
| 391 | 442 | ||
| 392 | // Clear events | 443 | // Start read operation. |
| 393 | r.events_stopped.reset(); | 444 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); |
| 394 | r.events_error.reset(); | 445 | if last_op.is_some() { |
| 395 | self.clear_errorsrc(); | 446 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); |
| 447 | } | ||
| 396 | 448 | ||
| 397 | if inten { | 449 | if buffer.is_empty() { |
| 398 | r.intenset.write(|w| w.stopped().set().error().set()); | 450 | // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP ourselves. |
| 399 | } else { | 451 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); |
| 400 | r.intenclr.write(|w| w.stopped().clear().error().clear()); | 452 | } |
| 401 | } | 453 | |
| 454 | Ok(1) | ||
| 455 | } | ||
| 456 | [Operation::Write(wr_buffer), Operation::Read(rd_buffer)] | ||
| 457 | if !wr_buffer.is_empty() && !rd_buffer.is_empty() => | ||
| 458 | { | ||
| 459 | // Set up DMA buffers. | ||
| 460 | unsafe { | ||
| 461 | self.set_tx_buffer(wr_buffer, tx_ram_buffer)?; | ||
| 462 | self.set_rx_buffer(rd_buffer)?; | ||
| 463 | } | ||
| 464 | |||
| 465 | // Start write+read operation. | ||
| 466 | r.shorts.write(|w| { | ||
| 467 | w.lasttx_startrx().enabled(); | ||
| 468 | w.lastrx_stop().enabled(); | ||
| 469 | w | ||
| 470 | }); | ||
| 471 | |||
| 472 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||
| 473 | if last_op.is_some() { | ||
| 474 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); | ||
| 475 | } | ||
| 476 | |||
| 477 | Ok(2) | ||
| 478 | } | ||
| 479 | [Operation::Write(buffer), rest @ ..] => { | ||
| 480 | let stop = rest.is_empty(); | ||
| 402 | 481 | ||
| 403 | // Start read operation. | 482 | // Set up DMA buffers. |
| 404 | r.shorts.write(|w| w.lastrx_stop().enabled()); | 483 | unsafe { |
| 405 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | 484 | self.set_tx_buffer(buffer, tx_ram_buffer)?; |
| 406 | if buffer.is_empty() { | 485 | } |
| 407 | // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP ourselves. | 486 | |
| 408 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | 487 | // Start write operation. |
| 488 | r.shorts.write(|w| { | ||
| 489 | if stop { | ||
| 490 | w.lasttx_stop().enabled(); | ||
| 491 | } else { | ||
| 492 | w.lasttx_suspend().enabled(); | ||
| 493 | } | ||
| 494 | w | ||
| 495 | }); | ||
| 496 | |||
| 497 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | ||
| 498 | if last_op.is_some() { | ||
| 499 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); | ||
| 500 | } | ||
| 501 | |||
| 502 | if buffer.is_empty() { | ||
| 503 | // With a zero-length buffer, LASTTX doesn't fire (because there's no last byte!), so do the STOP/SUSPEND ourselves. | ||
| 504 | if stop { | ||
| 505 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 506 | } else { | ||
| 507 | r.tasks_suspend.write(|w| unsafe { w.bits(1) }); | ||
| 508 | } | ||
| 509 | } | ||
| 510 | |||
| 511 | Ok(1) | ||
| 512 | } | ||
| 513 | [] => unreachable!(), | ||
| 409 | } | 514 | } |
| 410 | Ok(()) | ||
| 411 | } | 515 | } |
| 412 | 516 | ||
| 413 | fn setup_write_read_from_ram( | 517 | fn check_operations(&mut self, operations: &[Operation<'_>]) -> Result<(), 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); | 518 | compiler_fence(SeqCst); |
| 519 | self.check_errorsrc()?; | ||
| 423 | 520 | ||
| 424 | r.address.write(|w| unsafe { w.address().bits(address) }); | 521 | assert!(operations.len() == 1 || operations.len() == 2); |
| 425 | 522 | match operations { | |
| 426 | // Set up DMA buffers. | 523 | [Operation::Read(rd_buffer), Operation::Write(wr_buffer)] |
| 427 | unsafe { | 524 | | [Operation::Write(wr_buffer), Operation::Read(rd_buffer)] => { |
| 428 | self.set_tx_buffer(wr_buffer)?; | 525 | self.check_rx(rd_buffer.len())?; |
| 429 | self.set_rx_buffer(rd_buffer)?; | 526 | self.check_tx(wr_buffer.len())?; |
| 527 | } | ||
| 528 | [Operation::Read(buffer)] => { | ||
| 529 | self.check_rx(buffer.len())?; | ||
| 530 | } | ||
| 531 | [Operation::Write(buffer), ..] => { | ||
| 532 | self.check_tx(buffer.len())?; | ||
| 533 | } | ||
| 534 | _ => unreachable!(), | ||
| 430 | } | 535 | } |
| 536 | Ok(()) | ||
| 537 | } | ||
| 431 | 538 | ||
| 432 | // Clear events | 539 | // =========================================== |
| 433 | r.events_stopped.reset(); | ||
| 434 | r.events_error.reset(); | ||
| 435 | self.clear_errorsrc(); | ||
| 436 | 540 | ||
| 437 | if inten { | 541 | /// Execute the provided operations on the I2C bus. |
| 438 | r.intenset.write(|w| w.stopped().set().error().set()); | 542 | /// |
| 439 | } else { | 543 | /// Each buffer must have a length of at most 255 bytes on the nRF52832 |
| 440 | r.intenclr.write(|w| w.stopped().clear().error().clear()); | 544 | /// and at most 65535 bytes on the nRF52840. |
| 545 | /// | ||
| 546 | /// Consecutive `Operation::Read`s are not supported due to hardware | ||
| 547 | /// limitations. | ||
| 548 | /// | ||
| 549 | /// An `Operation::Write` following an `Operation::Read` must have a | ||
| 550 | /// non-empty buffer. | ||
| 551 | pub fn blocking_transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { | ||
| 552 | let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; | ||
| 553 | let mut last_op = None; | ||
| 554 | while !operations.is_empty() { | ||
| 555 | let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, false)?; | ||
| 556 | let (in_progress, rest) = operations.split_at_mut(ops); | ||
| 557 | self.blocking_wait(); | ||
| 558 | self.check_operations(in_progress)?; | ||
| 559 | last_op = in_progress.last(); | ||
| 560 | operations = rest; | ||
| 441 | } | 561 | } |
| 562 | Ok(()) | ||
| 563 | } | ||
| 442 | 564 | ||
| 443 | // Start write+read operation. | 565 | /// Same as [`blocking_transaction`](Twim::blocking_transaction) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. |
| 444 | r.shorts.write(|w| { | 566 | pub fn blocking_transaction_from_ram( |
| 445 | w.lasttx_startrx().enabled(); | 567 | &mut self, |
| 446 | w.lastrx_stop().enabled(); | 568 | address: u8, |
| 447 | w | 569 | mut operations: &mut [Operation<'_>], |
| 448 | }); | 570 | ) -> Result<(), Error> { |
| 449 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | 571 | let mut last_op = None; |
| 450 | if wr_buffer.is_empty() && rd_buffer.is_empty() { | 572 | while !operations.is_empty() { |
| 451 | // With a zero-length buffer, LASTRX/LASTTX doesn't fire (because there's no last byte!), so do the STOP ourselves. | 573 | let ops = self.setup_operations(address, operations, None, last_op, false)?; |
| 452 | // TODO handle when only one of the buffers is zero length | 574 | let (in_progress, rest) = operations.split_at_mut(ops); |
| 453 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | 575 | self.blocking_wait(); |
| 576 | self.check_operations(in_progress)?; | ||
| 577 | last_op = in_progress.last(); | ||
| 578 | operations = rest; | ||
| 454 | } | 579 | } |
| 580 | Ok(()) | ||
| 581 | } | ||
| 455 | 582 | ||
| 583 | /// Execute the provided operations on the I2C bus with timeout. | ||
| 584 | /// | ||
| 585 | /// See [`blocking_transaction`]. | ||
| 586 | #[cfg(feature = "time")] | ||
| 587 | pub fn blocking_transaction_timeout( | ||
| 588 | &mut self, | ||
| 589 | address: u8, | ||
| 590 | mut operations: &mut [Operation<'_>], | ||
| 591 | timeout: Duration, | ||
| 592 | ) -> Result<(), Error> { | ||
| 593 | let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; | ||
| 594 | let mut last_op = None; | ||
| 595 | while !operations.is_empty() { | ||
| 596 | let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, false)?; | ||
| 597 | let (in_progress, rest) = operations.split_at_mut(ops); | ||
| 598 | self.blocking_wait_timeout(timeout)?; | ||
| 599 | self.check_operations(in_progress)?; | ||
| 600 | last_op = in_progress.last(); | ||
| 601 | operations = rest; | ||
| 602 | } | ||
| 456 | Ok(()) | 603 | Ok(()) |
| 457 | } | 604 | } |
| 458 | 605 | ||
| 459 | fn setup_write_read( | 606 | /// 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. |
| 607 | #[cfg(feature = "time")] | ||
| 608 | pub fn blocking_transaction_from_ram_timeout( | ||
| 460 | &mut self, | 609 | &mut self, |
| 461 | address: u8, | 610 | address: u8, |
| 462 | wr_buffer: &[u8], | 611 | mut operations: &mut [Operation<'_>], |
| 463 | rd_buffer: &mut [u8], | 612 | timeout: Duration, |
| 464 | inten: bool, | ||
| 465 | ) -> Result<(), Error> { | 613 | ) -> Result<(), Error> { |
| 466 | match self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, inten) { | 614 | let mut last_op = None; |
| 467 | Ok(_) => Ok(()), | 615 | while !operations.is_empty() { |
| 468 | Err(Error::BufferNotInRAM) => { | 616 | let ops = self.setup_operations(address, operations, None, last_op, false)?; |
| 469 | trace!("Copying TWIM tx buffer into RAM for DMA"); | 617 | let (in_progress, rest) = operations.split_at_mut(ops); |
| 470 | let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; | 618 | self.blocking_wait_timeout(timeout)?; |
| 471 | tx_ram_buf.copy_from_slice(wr_buffer); | 619 | self.check_operations(in_progress)?; |
| 472 | self.setup_write_read_from_ram(address, tx_ram_buf, rd_buffer, inten) | 620 | last_op = in_progress.last(); |
| 473 | } | 621 | operations = rest; |
| 474 | Err(error) => Err(error), | ||
| 475 | } | 622 | } |
| 623 | Ok(()) | ||
| 476 | } | 624 | } |
| 477 | 625 | ||
| 478 | fn setup_write(&mut self, address: u8, wr_buffer: &[u8], inten: bool) -> Result<(), Error> { | 626 | /// Execute the provided operations on the I2C bus. |
| 479 | match self.setup_write_from_ram(address, wr_buffer, inten) { | 627 | /// |
| 480 | Ok(_) => Ok(()), | 628 | /// Each buffer must have a length of at most 255 bytes on the nRF52832 |
| 481 | Err(Error::BufferNotInRAM) => { | 629 | /// and at most 65535 bytes on the nRF52840. |
| 482 | trace!("Copying TWIM tx buffer into RAM for DMA"); | 630 | /// |
| 483 | let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; | 631 | /// Consecutive `Operation::Read`s are not supported due to hardware |
| 484 | tx_ram_buf.copy_from_slice(wr_buffer); | 632 | /// limitations. |
| 485 | self.setup_write_from_ram(address, tx_ram_buf, inten) | 633 | /// |
| 486 | } | 634 | /// An `Operation::Write` following an `Operation::Read` must have a |
| 487 | Err(error) => Err(error), | 635 | /// non-empty buffer. |
| 636 | pub async fn transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { | ||
| 637 | let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; | ||
| 638 | let mut last_op = None; | ||
| 639 | while !operations.is_empty() { | ||
| 640 | let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, true)?; | ||
| 641 | let (in_progress, rest) = operations.split_at_mut(ops); | ||
| 642 | self.async_wait().await; | ||
| 643 | self.check_operations(in_progress)?; | ||
| 644 | last_op = in_progress.last(); | ||
| 645 | operations = rest; | ||
| 488 | } | 646 | } |
| 647 | Ok(()) | ||
| 648 | } | ||
| 649 | |||
| 650 | /// Same as [`transaction`](Twim::transaction) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | ||
| 651 | pub async fn transaction_from_ram( | ||
| 652 | &mut self, | ||
| 653 | address: u8, | ||
| 654 | mut operations: &mut [Operation<'_>], | ||
| 655 | ) -> Result<(), Error> { | ||
| 656 | let mut last_op = None; | ||
| 657 | while !operations.is_empty() { | ||
| 658 | let ops = self.setup_operations(address, operations, None, last_op, true)?; | ||
| 659 | let (in_progress, rest) = operations.split_at_mut(ops); | ||
| 660 | self.async_wait().await; | ||
| 661 | self.check_operations(in_progress)?; | ||
| 662 | last_op = in_progress.last(); | ||
| 663 | operations = rest; | ||
| 664 | } | ||
| 665 | Ok(()) | ||
| 489 | } | 666 | } |
| 490 | 667 | ||
| 668 | // =========================================== | ||
| 669 | |||
| 491 | /// Write to an I2C slave. | 670 | /// Write to an I2C slave. |
| 492 | /// | 671 | /// |
| 493 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | 672 | /// The buffer must have a length of at most 255 bytes on the nRF52832 |
| 494 | /// and at most 65535 bytes on the nRF52840. | 673 | /// and at most 65535 bytes on the nRF52840. |
| 495 | pub fn blocking_write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { | 674 | pub fn blocking_write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { |
| 496 | self.setup_write(address, buffer, false)?; | 675 | self.blocking_transaction(address, &mut [Operation::Write(buffer)]) |
| 497 | self.blocking_wait(); | ||
| 498 | compiler_fence(SeqCst); | ||
| 499 | self.check_errorsrc()?; | ||
| 500 | self.check_tx(buffer.len())?; | ||
| 501 | Ok(()) | ||
| 502 | } | 676 | } |
| 503 | 677 | ||
| 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. | 678 | /// 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> { | 679 | pub fn blocking_write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { |
| 506 | self.setup_write_from_ram(address, buffer, false)?; | 680 | self.blocking_transaction_from_ram(address, &mut [Operation::Write(buffer)]) |
| 507 | self.blocking_wait(); | ||
| 508 | compiler_fence(SeqCst); | ||
| 509 | self.check_errorsrc()?; | ||
| 510 | self.check_tx(buffer.len())?; | ||
| 511 | Ok(()) | ||
| 512 | } | 681 | } |
| 513 | 682 | ||
| 514 | /// Read from an I2C slave. | 683 | /// Read from an I2C slave. |
| @@ -516,12 +685,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 516 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | 685 | /// The buffer must have a length of at most 255 bytes on the nRF52832 |
| 517 | /// and at most 65535 bytes on the nRF52840. | 686 | /// and at most 65535 bytes on the nRF52840. |
| 518 | pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | 687 | pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { |
| 519 | self.setup_read(address, buffer, false)?; | 688 | self.blocking_transaction(address, &mut [Operation::Read(buffer)]) |
| 520 | self.blocking_wait(); | ||
| 521 | compiler_fence(SeqCst); | ||
| 522 | self.check_errorsrc()?; | ||
| 523 | self.check_rx(buffer.len())?; | ||
| 524 | Ok(()) | ||
| 525 | } | 689 | } |
| 526 | 690 | ||
| 527 | /// Write data to an I2C slave, then read data from the slave without | 691 | /// Write data to an I2C slave, then read data from the slave without |
| @@ -530,13 +694,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 530 | /// The buffers must have a length of at most 255 bytes on the nRF52832 | 694 | /// The buffers must have a length of at most 255 bytes on the nRF52832 |
| 531 | /// and at most 65535 bytes on the nRF52840. | 695 | /// 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> { | 696 | 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)?; | 697 | self.blocking_transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) |
| 534 | self.blocking_wait(); | ||
| 535 | compiler_fence(SeqCst); | ||
| 536 | self.check_errorsrc()?; | ||
| 537 | self.check_tx(wr_buffer.len())?; | ||
| 538 | self.check_rx(rd_buffer.len())?; | ||
| 539 | Ok(()) | ||
| 540 | } | 698 | } |
| 541 | 699 | ||
| 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. | 700 | /// 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 +704,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 546 | wr_buffer: &[u8], | 704 | wr_buffer: &[u8], |
| 547 | rd_buffer: &mut [u8], | 705 | rd_buffer: &mut [u8], |
| 548 | ) -> Result<(), Error> { | 706 | ) -> Result<(), Error> { |
| 549 | self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, false)?; | 707 | self.blocking_transaction_from_ram(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) |
| 550 | self.blocking_wait(); | ||
| 551 | compiler_fence(SeqCst); | ||
| 552 | self.check_errorsrc()?; | ||
| 553 | self.check_tx(wr_buffer.len())?; | ||
| 554 | self.check_rx(rd_buffer.len())?; | ||
| 555 | Ok(()) | ||
| 556 | } | 708 | } |
| 557 | 709 | ||
| 558 | // =========================================== | 710 | // =========================================== |
| @@ -562,12 +714,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 562 | /// See [`blocking_write`]. | 714 | /// See [`blocking_write`]. |
| 563 | #[cfg(feature = "time")] | 715 | #[cfg(feature = "time")] |
| 564 | pub fn blocking_write_timeout(&mut self, address: u8, buffer: &[u8], timeout: Duration) -> Result<(), Error> { | 716 | pub fn blocking_write_timeout(&mut self, address: u8, buffer: &[u8], timeout: Duration) -> Result<(), Error> { |
| 565 | self.setup_write(address, buffer, false)?; | 717 | self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], timeout) |
| 566 | self.blocking_wait_timeout(timeout)?; | ||
| 567 | compiler_fence(SeqCst); | ||
| 568 | self.check_errorsrc()?; | ||
| 569 | self.check_tx(buffer.len())?; | ||
| 570 | Ok(()) | ||
| 571 | } | 718 | } |
| 572 | 719 | ||
| 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. | 720 | /// 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 +725,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 578 | buffer: &[u8], | 725 | buffer: &[u8], |
| 579 | timeout: Duration, | 726 | timeout: Duration, |
| 580 | ) -> Result<(), Error> { | 727 | ) -> Result<(), Error> { |
| 581 | self.setup_write_from_ram(address, buffer, false)?; | 728 | self.blocking_transaction_from_ram_timeout(address, &mut [Operation::Write(buffer)], timeout) |
| 582 | self.blocking_wait_timeout(timeout)?; | ||
| 583 | compiler_fence(SeqCst); | ||
| 584 | self.check_errorsrc()?; | ||
| 585 | self.check_tx(buffer.len())?; | ||
| 586 | Ok(()) | ||
| 587 | } | 729 | } |
| 588 | 730 | ||
| 589 | /// Read from an I2C slave. | 731 | /// Read from an I2C slave. |
| @@ -592,12 +734,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 592 | /// and at most 65535 bytes on the nRF52840. | 734 | /// and at most 65535 bytes on the nRF52840. |
| 593 | #[cfg(feature = "time")] | 735 | #[cfg(feature = "time")] |
| 594 | pub fn blocking_read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> { | 736 | pub fn blocking_read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> { |
| 595 | self.setup_read(address, buffer, false)?; | 737 | self.blocking_transaction_timeout(address, &mut [Operation::Read(buffer)], timeout) |
| 596 | self.blocking_wait_timeout(timeout)?; | ||
| 597 | compiler_fence(SeqCst); | ||
| 598 | self.check_errorsrc()?; | ||
| 599 | self.check_rx(buffer.len())?; | ||
| 600 | Ok(()) | ||
| 601 | } | 738 | } |
| 602 | 739 | ||
| 603 | /// Write data to an I2C slave, then read data from the slave without | 740 | /// Write data to an I2C slave, then read data from the slave without |
| @@ -613,13 +750,11 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 613 | rd_buffer: &mut [u8], | 750 | rd_buffer: &mut [u8], |
| 614 | timeout: Duration, | 751 | timeout: Duration, |
| 615 | ) -> Result<(), Error> { | 752 | ) -> Result<(), Error> { |
| 616 | self.setup_write_read(address, wr_buffer, rd_buffer, false)?; | 753 | self.blocking_transaction_timeout( |
| 617 | self.blocking_wait_timeout(timeout)?; | 754 | address, |
| 618 | compiler_fence(SeqCst); | 755 | &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], |
| 619 | self.check_errorsrc()?; | 756 | timeout, |
| 620 | self.check_tx(wr_buffer.len())?; | 757 | ) |
| 621 | self.check_rx(rd_buffer.len())?; | ||
| 622 | Ok(()) | ||
| 623 | } | 758 | } |
| 624 | 759 | ||
| 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. | 760 | /// 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 +766,11 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 631 | rd_buffer: &mut [u8], | 766 | rd_buffer: &mut [u8], |
| 632 | timeout: Duration, | 767 | timeout: Duration, |
| 633 | ) -> Result<(), Error> { | 768 | ) -> Result<(), Error> { |
| 634 | self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, false)?; | 769 | self.blocking_transaction_from_ram_timeout( |
| 635 | self.blocking_wait_timeout(timeout)?; | 770 | address, |
| 636 | compiler_fence(SeqCst); | 771 | &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], |
| 637 | self.check_errorsrc()?; | 772 | timeout, |
| 638 | self.check_tx(wr_buffer.len())?; | 773 | ) |
| 639 | self.check_rx(rd_buffer.len())?; | ||
| 640 | Ok(()) | ||
| 641 | } | 774 | } |
| 642 | 775 | ||
| 643 | // =========================================== | 776 | // =========================================== |
| @@ -647,12 +780,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 647 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | 780 | /// The buffer must have a length of at most 255 bytes on the nRF52832 |
| 648 | /// and at most 65535 bytes on the nRF52840. | 781 | /// and at most 65535 bytes on the nRF52840. |
| 649 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | 782 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { |
| 650 | self.setup_read(address, buffer, true)?; | 783 | self.transaction(address, &mut [Operation::Read(buffer)]).await |
| 651 | self.async_wait().await; | ||
| 652 | compiler_fence(SeqCst); | ||
| 653 | self.check_errorsrc()?; | ||
| 654 | self.check_rx(buffer.len())?; | ||
| 655 | Ok(()) | ||
| 656 | } | 784 | } |
| 657 | 785 | ||
| 658 | /// Write to an I2C slave. | 786 | /// Write to an I2C slave. |
| @@ -660,22 +788,13 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 660 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | 788 | /// The buffer must have a length of at most 255 bytes on the nRF52832 |
| 661 | /// and at most 65535 bytes on the nRF52840. | 789 | /// and at most 65535 bytes on the nRF52840. |
| 662 | pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { | 790 | pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { |
| 663 | self.setup_write(address, buffer, true)?; | 791 | self.transaction(address, &mut [Operation::Write(buffer)]).await |
| 664 | self.async_wait().await; | ||
| 665 | compiler_fence(SeqCst); | ||
| 666 | self.check_errorsrc()?; | ||
| 667 | self.check_tx(buffer.len())?; | ||
| 668 | Ok(()) | ||
| 669 | } | 792 | } |
| 670 | 793 | ||
| 671 | /// Same as [`write`](Twim::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | 794 | /// 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> { | 795 | pub async fn write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { |
| 673 | self.setup_write_from_ram(address, buffer, true)?; | 796 | self.transaction_from_ram(address, &mut [Operation::Write(buffer)]) |
| 674 | self.async_wait().await; | 797 | .await |
| 675 | compiler_fence(SeqCst); | ||
| 676 | self.check_errorsrc()?; | ||
| 677 | self.check_tx(buffer.len())?; | ||
| 678 | Ok(()) | ||
| 679 | } | 798 | } |
| 680 | 799 | ||
| 681 | /// Write data to an I2C slave, then read data from the slave without | 800 | /// Write data to an I2C slave, then read data from the slave without |
| @@ -684,13 +803,8 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 684 | /// The buffers must have a length of at most 255 bytes on the nRF52832 | 803 | /// The buffers must have a length of at most 255 bytes on the nRF52832 |
| 685 | /// and at most 65535 bytes on the nRF52840. | 804 | /// 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> { | 805 | 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)?; | 806 | self.transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) |
| 688 | self.async_wait().await; | 807 | .await |
| 689 | compiler_fence(SeqCst); | ||
| 690 | self.check_errorsrc()?; | ||
| 691 | self.check_tx(wr_buffer.len())?; | ||
| 692 | self.check_rx(rd_buffer.len())?; | ||
| 693 | Ok(()) | ||
| 694 | } | 808 | } |
| 695 | 809 | ||
| 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. | 810 | /// 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 +814,8 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 700 | wr_buffer: &[u8], | 814 | wr_buffer: &[u8], |
| 701 | rd_buffer: &mut [u8], | 815 | rd_buffer: &mut [u8], |
| 702 | ) -> Result<(), Error> { | 816 | ) -> Result<(), Error> { |
| 703 | self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, true)?; | 817 | self.transaction_from_ram(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) |
| 704 | self.async_wait().await; | 818 | .await |
| 705 | compiler_fence(SeqCst); | ||
| 706 | self.check_errorsrc()?; | ||
| 707 | self.check_tx(wr_buffer.len())?; | ||
| 708 | self.check_rx(rd_buffer.len())?; | ||
| 709 | Ok(()) | ||
| 710 | } | 819 | } |
| 711 | } | 820 | } |
| 712 | 821 | ||
| @@ -777,16 +886,7 @@ mod eh02 { | |||
| 777 | type Error = Error; | 886 | type Error = Error; |
| 778 | 887 | ||
| 779 | fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { | 888 | fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { |
| 780 | if slice_in_ram(bytes) { | 889 | 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 | } | 890 | } |
| 791 | } | 891 | } |
| 792 | 892 | ||
| @@ -832,47 +932,14 @@ impl<'d, T: Instance> embedded_hal_1::i2c::ErrorType for Twim<'d, T> { | |||
| 832 | } | 932 | } |
| 833 | 933 | ||
| 834 | impl<'d, T: Instance> embedded_hal_1::i2c::I2c for Twim<'d, T> { | 934 | 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> { | 935 | fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { |
| 836 | self.blocking_read(address, buffer) | 936 | self.blocking_transaction(address, operations) |
| 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 | } | 937 | } |
| 854 | } | 938 | } |
| 855 | 939 | ||
| 856 | impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> { | 940 | 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> { | 941 | async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { |
| 858 | self.read(address, read).await | 942 | self.transaction(address, operations).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 | } | 943 | } |
| 877 | } | 944 | } |
| 878 | 945 | ||
