diff options
| author | Alex Moon <[email protected]> | 2024-08-21 10:57:14 -0400 |
|---|---|---|
| committer | Alex Moon <[email protected]> | 2024-10-23 16:44:07 -0400 |
| commit | 55805de05b4be39546c0b4c5e2ebc97cd3b1f75c (patch) | |
| tree | fcecbebfb67496fa75edaecc86fbc82612ca4bb3 /embassy-nrf | |
| parent | 110d87bbd2c4e5b60ed99c0a259b8366e5164d41 (diff) | |
Refactoring and cleanup
Diffstat (limited to 'embassy-nrf')
| -rw-r--r-- | embassy-nrf/src/twim.rs | 181 |
1 files changed, 95 insertions, 86 deletions
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 4a239e8b5..187fce021 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs | |||
| @@ -311,6 +311,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 311 | let r = T::regs(); | 311 | let r = T::regs(); |
| 312 | loop { | 312 | loop { |
| 313 | if r.events_suspended.read().bits() != 0 || 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(); | ||
| 314 | r.events_stopped.reset(); | 315 | r.events_stopped.reset(); |
| 315 | break; | 316 | break; |
| 316 | } | 317 | } |
| @@ -372,15 +373,15 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 372 | address: u8, | 373 | address: u8, |
| 373 | operations: &mut [Operation<'_>], | 374 | operations: &mut [Operation<'_>], |
| 374 | tx_ram_buffer: Option<&mut [MaybeUninit<u8>; FORCE_COPY_BUFFER_SIZE]>, | 375 | tx_ram_buffer: Option<&mut [MaybeUninit<u8>; FORCE_COPY_BUFFER_SIZE]>, |
| 376 | last_op: Option<&Operation<'_>>, | ||
| 375 | inten: bool, | 377 | inten: bool, |
| 376 | ) -> Result<(), Error> { | 378 | ) -> Result<usize, Error> { |
| 377 | let r = T::regs(); | 379 | let r = T::regs(); |
| 378 | 380 | ||
| 379 | compiler_fence(SeqCst); | 381 | compiler_fence(SeqCst); |
| 380 | 382 | ||
| 381 | r.address.write(|w| unsafe { w.address().bits(address) }); | 383 | r.address.write(|w| unsafe { w.address().bits(address) }); |
| 382 | 384 | ||
| 383 | let was_suspended = r.events_suspended.read().bits() != 0; | ||
| 384 | r.events_suspended.reset(); | 385 | r.events_suspended.reset(); |
| 385 | r.events_stopped.reset(); | 386 | r.events_stopped.reset(); |
| 386 | r.events_error.reset(); | 387 | r.events_error.reset(); |
| @@ -393,10 +394,12 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 393 | .write(|w| w.suspended().clear().stopped().clear().error().clear()); | 394 | .write(|w| w.suspended().clear().stopped().clear().error().clear()); |
| 394 | } | 395 | } |
| 395 | 396 | ||
| 397 | assert!(!operations.is_empty()); | ||
| 396 | match operations { | 398 | match operations { |
| 397 | [Operation::Read(rd_buffer), Operation::Write(wr_buffer), rest @ ..] | 399 | [Operation::Read(_), Operation::Read(_), ..] => { |
| 398 | if !rd_buffer.is_empty() && !wr_buffer.is_empty() => | 400 | panic!("Consecutive read operations are not supported!") |
| 399 | { | 401 | } |
| 402 | [Operation::Read(rd_buffer), Operation::Write(wr_buffer), rest @ ..] => { | ||
| 400 | let stop = rest.is_empty(); | 403 | let stop = rest.is_empty(); |
| 401 | 404 | ||
| 402 | // Set up DMA buffers. | 405 | // Set up DMA buffers. |
| @@ -417,10 +420,38 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 417 | 420 | ||
| 418 | // Start read+write operation. | 421 | // Start read+write operation. |
| 419 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | 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 | } | ||
| 420 | 426 | ||
| 421 | if was_suspended { | 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 | } | ||
| 440 | |||
| 441 | r.shorts.write(|w| w.lastrx_stop().enabled()); | ||
| 442 | |||
| 443 | // Start read operation. | ||
| 444 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||
| 445 | if last_op.is_some() { | ||
| 422 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); | 446 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); |
| 423 | } | 447 | } |
| 448 | |||
| 449 | if buffer.is_empty() { | ||
| 450 | // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP ourselves. | ||
| 451 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 452 | } | ||
| 453 | |||
| 454 | Ok(1) | ||
| 424 | } | 455 | } |
| 425 | [Operation::Write(wr_buffer), Operation::Read(rd_buffer)] | 456 | [Operation::Write(wr_buffer), Operation::Read(rd_buffer)] |
| 426 | if !wr_buffer.is_empty() && !rd_buffer.is_empty() => | 457 | if !wr_buffer.is_empty() && !rd_buffer.is_empty() => |
| @@ -439,36 +470,11 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 439 | }); | 470 | }); |
| 440 | 471 | ||
| 441 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | 472 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); |
| 442 | 473 | if last_op.is_some() { | |
| 443 | if was_suspended { | ||
| 444 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); | ||
| 445 | } | ||
| 446 | } | ||
| 447 | [Operation::Read(buffer)] => { | ||
| 448 | // Set up DMA buffers. | ||
| 449 | unsafe { | ||
| 450 | self.set_rx_buffer(buffer)?; | ||
| 451 | } | ||
| 452 | |||
| 453 | // Start read operation. | ||
| 454 | r.shorts.write(|w| { | ||
| 455 | w.lastrx_stop().enabled(); | ||
| 456 | w | ||
| 457 | }); | ||
| 458 | |||
| 459 | r.tasks_startrx.write(|w| unsafe { w.bits(1) }); | ||
| 460 | |||
| 461 | if was_suspended { | ||
| 462 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); | 474 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); |
| 463 | } | 475 | } |
| 464 | 476 | ||
| 465 | if buffer.is_empty() { | 477 | Ok(2) |
| 466 | // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP ourselves. | ||
| 467 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 468 | } | ||
| 469 | } | ||
| 470 | [Operation::Read(_), ..] => { | ||
| 471 | panic!("Suspending after a read is not supported!"); | ||
| 472 | } | 478 | } |
| 473 | [Operation::Write(buffer), rest @ ..] => { | 479 | [Operation::Write(buffer), rest @ ..] => { |
| 474 | let stop = rest.is_empty(); | 480 | let stop = rest.is_empty(); |
| @@ -489,8 +495,7 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 489 | }); | 495 | }); |
| 490 | 496 | ||
| 491 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); | 497 | r.tasks_starttx.write(|w| unsafe { w.bits(1) }); |
| 492 | 498 | if last_op.is_some() { | |
| 493 | if was_suspended { | ||
| 494 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); | 499 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); |
| 495 | } | 500 | } |
| 496 | 501 | ||
| @@ -502,43 +507,33 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 502 | r.tasks_suspend.write(|w| unsafe { w.bits(1) }); | 507 | r.tasks_suspend.write(|w| unsafe { w.bits(1) }); |
| 503 | } | 508 | } |
| 504 | } | 509 | } |
| 505 | } | ||
| 506 | [] => { | ||
| 507 | if was_suspended { | ||
| 508 | r.tasks_resume.write(|w| unsafe { w.bits(1) }); | ||
| 509 | } | ||
| 510 | 510 | ||
| 511 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | 511 | Ok(1) |
| 512 | } | 512 | } |
| 513 | [] => unreachable!(), | ||
| 513 | } | 514 | } |
| 514 | |||
| 515 | Ok(()) | ||
| 516 | } | 515 | } |
| 517 | 516 | ||
| 518 | fn check_operations(&mut self, operations: &mut [Operation<'_>]) -> Result<usize, Error> { | 517 | fn check_operations(&mut self, operations: &[Operation<'_>]) -> Result<(), Error> { |
| 519 | compiler_fence(SeqCst); | 518 | compiler_fence(SeqCst); |
| 520 | self.check_errorsrc()?; | 519 | self.check_errorsrc()?; |
| 521 | 520 | ||
| 521 | assert!(operations.len() == 1 || operations.len() == 2); | ||
| 522 | match operations { | 522 | match operations { |
| 523 | [Operation::Read(rd_buffer), Operation::Write(wr_buffer), ..] | 523 | [Operation::Read(rd_buffer), Operation::Write(wr_buffer)] |
| 524 | | [Operation::Write(wr_buffer), Operation::Read(rd_buffer)] | 524 | | [Operation::Write(wr_buffer), Operation::Read(rd_buffer)] => { |
| 525 | if !rd_buffer.is_empty() && !wr_buffer.is_empty() => | ||
| 526 | { | ||
| 527 | self.check_tx(wr_buffer.len())?; | ||
| 528 | self.check_rx(rd_buffer.len())?; | 525 | self.check_rx(rd_buffer.len())?; |
| 529 | Ok(2) | 526 | self.check_tx(wr_buffer.len())?; |
| 530 | } | 527 | } |
| 531 | [Operation::Read(buffer)] => { | 528 | [Operation::Read(buffer)] => { |
| 532 | self.check_rx(buffer.len())?; | 529 | self.check_rx(buffer.len())?; |
| 533 | Ok(1) | ||
| 534 | } | 530 | } |
| 535 | [Operation::Read(_), ..] => unreachable!(), | ||
| 536 | [Operation::Write(buffer), ..] => { | 531 | [Operation::Write(buffer), ..] => { |
| 537 | self.check_tx(buffer.len())?; | 532 | self.check_tx(buffer.len())?; |
| 538 | Ok(1) | ||
| 539 | } | 533 | } |
| 540 | [] => Ok(0), | 534 | _ => unreachable!(), |
| 541 | } | 535 | } |
| 536 | Ok(()) | ||
| 542 | } | 537 | } |
| 543 | 538 | ||
| 544 | // =========================================== | 539 | // =========================================== |
| @@ -548,20 +543,21 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 548 | /// Each buffer must have a length of at most 255 bytes on the nRF52832 | 543 | /// Each buffer must have a length of at most 255 bytes on the nRF52832 |
| 549 | /// and at most 65535 bytes on the nRF52840. | 544 | /// and at most 65535 bytes on the nRF52840. |
| 550 | /// | 545 | /// |
| 551 | /// Consecutive `Read` operations are not supported because the Twim | 546 | /// Consecutive `Operation::Read`s are not supported due to hardware |
| 552 | /// hardware does not support suspending after a read operation. (Setting | 547 | /// limitations. |
| 553 | /// the SUSPEND task in response to a LASTRX event causes the final byte of | 548 | /// |
| 554 | /// the operation to be ACKed instead of NAKed. When the TWIM is resumed, | 549 | /// An `Operation::Write` following an `Operation::Read` must have a |
| 555 | /// one more byte will be read before the new operation is started, leading | 550 | /// non-empty buffer. |
| 556 | /// to an Overrun error if the RXD has not been updated, or an extraneous | ||
| 557 | /// byte read into the new buffer if the RXD has been updated.) | ||
| 558 | pub fn blocking_transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { | 551 | pub fn blocking_transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { |
| 559 | let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; | 552 | let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; |
| 553 | let mut last_op = None; | ||
| 560 | while !operations.is_empty() { | 554 | while !operations.is_empty() { |
| 561 | self.setup_operations(address, operations, Some(&mut tx_ram_buffer), false)?; | 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); | ||
| 562 | self.blocking_wait(); | 557 | self.blocking_wait(); |
| 563 | let consumed = self.check_operations(operations)?; | 558 | self.check_operations(in_progress)?; |
| 564 | operations = &mut operations[consumed..]; | 559 | last_op = in_progress.last(); |
| 560 | operations = rest; | ||
| 565 | } | 561 | } |
| 566 | Ok(()) | 562 | Ok(()) |
| 567 | } | 563 | } |
| @@ -572,11 +568,14 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 572 | address: u8, | 568 | address: u8, |
| 573 | mut operations: &mut [Operation<'_>], | 569 | mut operations: &mut [Operation<'_>], |
| 574 | ) -> Result<(), Error> { | 570 | ) -> Result<(), Error> { |
| 571 | let mut last_op = None; | ||
| 575 | while !operations.is_empty() { | 572 | while !operations.is_empty() { |
| 576 | self.setup_operations(address, operations, None, false)?; | 573 | let ops = self.setup_operations(address, operations, None, last_op, false)?; |
| 574 | let (in_progress, rest) = operations.split_at_mut(ops); | ||
| 577 | self.blocking_wait(); | 575 | self.blocking_wait(); |
| 578 | let consumed = self.check_operations(operations)?; | 576 | self.check_operations(in_progress)?; |
| 579 | operations = &mut operations[consumed..]; | 577 | last_op = in_progress.last(); |
| 578 | operations = rest; | ||
| 580 | } | 579 | } |
| 581 | Ok(()) | 580 | Ok(()) |
| 582 | } | 581 | } |
| @@ -592,11 +591,14 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 592 | timeout: Duration, | 591 | timeout: Duration, |
| 593 | ) -> Result<(), Error> { | 592 | ) -> Result<(), Error> { |
| 594 | let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; | 593 | let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; |
| 594 | let mut last_op = None; | ||
| 595 | while !operations.is_empty() { | 595 | while !operations.is_empty() { |
| 596 | self.setup_operations(address, operations, Some(&mut tx_ram_buffer), false)?; | 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); | ||
| 597 | self.blocking_wait_timeout(timeout)?; | 598 | self.blocking_wait_timeout(timeout)?; |
| 598 | let consumed = self.check_operations(operations)?; | 599 | self.check_operations(in_progress)?; |
| 599 | operations = &mut operations[consumed..]; | 600 | last_op = in_progress.last(); |
| 601 | operations = rest; | ||
| 600 | } | 602 | } |
| 601 | Ok(()) | 603 | Ok(()) |
| 602 | } | 604 | } |
| @@ -609,11 +611,14 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 609 | mut operations: &mut [Operation<'_>], | 611 | mut operations: &mut [Operation<'_>], |
| 610 | timeout: Duration, | 612 | timeout: Duration, |
| 611 | ) -> Result<(), Error> { | 613 | ) -> Result<(), Error> { |
| 614 | let mut last_op = None; | ||
| 612 | while !operations.is_empty() { | 615 | while !operations.is_empty() { |
| 613 | self.setup_operations(address, operations, None, false)?; | 616 | let ops = self.setup_operations(address, operations, None, last_op, false)?; |
| 617 | let (in_progress, rest) = operations.split_at_mut(ops); | ||
| 614 | self.blocking_wait_timeout(timeout)?; | 618 | self.blocking_wait_timeout(timeout)?; |
| 615 | let consumed = self.check_operations(operations)?; | 619 | self.check_operations(in_progress)?; |
| 616 | operations = &mut operations[consumed..]; | 620 | last_op = in_progress.last(); |
| 621 | operations = rest; | ||
| 617 | } | 622 | } |
| 618 | Ok(()) | 623 | Ok(()) |
| 619 | } | 624 | } |
| @@ -623,20 +628,21 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 623 | /// Each buffer must have a length of at most 255 bytes on the nRF52832 | 628 | /// Each buffer must have a length of at most 255 bytes on the nRF52832 |
| 624 | /// and at most 65535 bytes on the nRF52840. | 629 | /// and at most 65535 bytes on the nRF52840. |
| 625 | /// | 630 | /// |
| 626 | /// Consecutive `Read` operations are not supported because the Twim | 631 | /// Consecutive `Operation::Read`s are not supported due to hardware |
| 627 | /// hardware does not support suspending after a read operation. (Setting | 632 | /// limitations. |
| 628 | /// the SUSPEND task in response to a LASTRX event causes the final byte of | 633 | /// |
| 629 | /// the operation to be ACKed instead of NAKed. When the TWIM is resumed, | 634 | /// An `Operation::Write` following an `Operation::Read` must have a |
| 630 | /// one more byte will be read before the new operation is started, leading | 635 | /// non-empty buffer. |
| 631 | /// to an Overrun error if the RXD has not been updated, or an extraneous | ||
| 632 | /// byte read into the new buffer if the RXD has been updated.) | ||
| 633 | pub async fn transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { | 636 | pub async fn transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { |
| 634 | let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; | 637 | let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; |
| 638 | let mut last_op = None; | ||
| 635 | while !operations.is_empty() { | 639 | while !operations.is_empty() { |
| 636 | self.setup_operations(address, operations, Some(&mut tx_ram_buffer), true)?; | 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); | ||
| 637 | self.async_wait().await; | 642 | self.async_wait().await; |
| 638 | let consumed = self.check_operations(operations)?; | 643 | self.check_operations(in_progress)?; |
| 639 | operations = &mut operations[consumed..]; | 644 | last_op = in_progress.last(); |
| 645 | operations = rest; | ||
| 640 | } | 646 | } |
| 641 | Ok(()) | 647 | Ok(()) |
| 642 | } | 648 | } |
| @@ -647,11 +653,14 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 647 | address: u8, | 653 | address: u8, |
| 648 | mut operations: &mut [Operation<'_>], | 654 | mut operations: &mut [Operation<'_>], |
| 649 | ) -> Result<(), Error> { | 655 | ) -> Result<(), Error> { |
| 656 | let mut last_op = None; | ||
| 650 | while !operations.is_empty() { | 657 | while !operations.is_empty() { |
| 651 | self.setup_operations(address, operations, None, true)?; | 658 | let ops = self.setup_operations(address, operations, None, last_op, true)?; |
| 659 | let (in_progress, rest) = operations.split_at_mut(ops); | ||
| 652 | self.async_wait().await; | 660 | self.async_wait().await; |
| 653 | let consumed = self.check_operations(operations)?; | 661 | self.check_operations(in_progress)?; |
| 654 | operations = &mut operations[consumed..]; | 662 | last_op = in_progress.last(); |
| 663 | operations = rest; | ||
| 655 | } | 664 | } |
| 656 | Ok(()) | 665 | Ok(()) |
| 657 | } | 666 | } |
