aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/twim.rs181
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 }