aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf
diff options
context:
space:
mode:
authorAlex Moon <[email protected]>2025-04-18 15:08:18 -0400
committerAlex Moon <[email protected]>2025-04-18 15:14:18 -0400
commit77d355e0ecb3f5eab4a563981552fdb69175c8c5 (patch)
tree9d00c7e1cdbce3f0d01c49c022f4620286ee25ad /embassy-nrf
parentca40dc7ff75cabaa6c52c98b4712cc3f64696d62 (diff)
Make the nrf Twim RAM buffer a instance variable instead of stack allocated
Diffstat (limited to 'embassy-nrf')
-rw-r--r--embassy-nrf/src/twim.rs165
1 files changed, 23 insertions, 142 deletions
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index 083b54b99..95b24c616 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -4,7 +4,6 @@
4 4
5use core::future::{poll_fn, Future}; 5use core::future::{poll_fn, Future};
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::mem::MaybeUninit;
8use core::sync::atomic::compiler_fence; 7use core::sync::atomic::compiler_fence;
9use core::sync::atomic::Ordering::SeqCst; 8use core::sync::atomic::Ordering::SeqCst;
10use core::task::Poll; 9use core::task::Poll;
@@ -17,7 +16,7 @@ use embassy_time::{Duration, Instant};
17use embedded_hal_1::i2c::Operation; 16use embedded_hal_1::i2c::Operation;
18pub use pac::twim::vals::Frequency; 17pub use pac::twim::vals::Frequency;
19 18
20use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 19use crate::chip::EASY_DMA_SIZE;
21use crate::gpio::Pin as GpioPin; 20use crate::gpio::Pin as GpioPin;
22use crate::interrupt::typelevel::Interrupt; 21use crate::interrupt::typelevel::Interrupt;
23use crate::pac::gpio::vals as gpiovals; 22use crate::pac::gpio::vals as gpiovals;
@@ -75,8 +74,8 @@ pub enum Error {
75 Transmit, 74 Transmit,
76 /// Data reception failed. 75 /// Data reception failed.
77 Receive, 76 Receive,
78 /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash. 77 /// The buffer is not in data RAM and is larger than the RAM buffer. It's most likely in flash, and nRF's DMA cannot access flash.
79 BufferNotInRAM, 78 RAMBufferTooSmall,
80 /// Didn't receive an ACK bit after the address byte. Address might be wrong, or the i2c device chip might not be connected properly. 79 /// Didn't receive an ACK bit after the address byte. Address might be wrong, or the i2c device chip might not be connected properly.
81 AddressNack, 80 AddressNack,
82 /// Didn't receive an ACK bit after a data byte. 81 /// Didn't receive an ACK bit after a data byte.
@@ -115,6 +114,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
115/// TWI driver. 114/// TWI driver.
116pub struct Twim<'d, T: Instance> { 115pub struct Twim<'d, T: Instance> {
117 _p: Peri<'d, T>, 116 _p: Peri<'d, T>,
117 tx_ram_buffer: &'d mut [u8],
118} 118}
119 119
120impl<'d, T: Instance> Twim<'d, T> { 120impl<'d, T: Instance> Twim<'d, T> {
@@ -125,6 +125,7 @@ impl<'d, T: Instance> Twim<'d, T> {
125 sda: Peri<'d, impl GpioPin>, 125 sda: Peri<'d, impl GpioPin>,
126 scl: Peri<'d, impl GpioPin>, 126 scl: Peri<'d, impl GpioPin>,
127 config: Config, 127 config: Config,
128 tx_ram_buffer: &'d mut [u8],
128 ) -> Self { 129 ) -> Self {
129 let r = T::regs(); 130 let r = T::regs();
130 131
@@ -159,7 +160,10 @@ impl<'d, T: Instance> Twim<'d, T> {
159 // Enable TWIM instance. 160 // Enable TWIM instance.
160 r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); 161 r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
161 162
162 let mut twim = Self { _p: twim }; 163 let mut twim = Self {
164 _p: twim,
165 tx_ram_buffer,
166 };
163 167
164 // Apply runtime peripheral configuration 168 // Apply runtime peripheral configuration
165 Self::set_config(&mut twim, &config).unwrap(); 169 Self::set_config(&mut twim, &config).unwrap();
@@ -174,21 +178,17 @@ impl<'d, T: Instance> Twim<'d, T> {
174 } 178 }
175 179
176 /// Set TX buffer, checking that it is in RAM and has suitable length. 180 /// Set TX buffer, checking that it is in RAM and has suitable length.
177 unsafe fn set_tx_buffer( 181 unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
178 &mut self,
179 buffer: &[u8],
180 ram_buffer: Option<&mut [MaybeUninit<u8>; FORCE_COPY_BUFFER_SIZE]>,
181 ) -> Result<(), Error> {
182 let buffer = if slice_in_ram(buffer) { 182 let buffer = if slice_in_ram(buffer) {
183 buffer 183 buffer
184 } else { 184 } else {
185 let ram_buffer = ram_buffer.ok_or(Error::BufferNotInRAM)?; 185 if buffer.len() > self.tx_ram_buffer.len() {
186 return Err(Error::RAMBufferTooSmall);
187 }
186 trace!("Copying TWIM tx buffer into RAM for DMA"); 188 trace!("Copying TWIM tx buffer into RAM for DMA");
187 let ram_buffer = &mut ram_buffer[..buffer.len()]; 189 let ram_buffer = &mut self.tx_ram_buffer[..buffer.len()];
188 // Inline implementation of the nightly API MaybeUninit::copy_from_slice(ram_buffer, buffer) 190 ram_buffer.copy_from_slice(buffer);
189 let uninit_src: &[MaybeUninit<u8>] = unsafe { core::mem::transmute(buffer) }; 191 &*ram_buffer
190 ram_buffer.copy_from_slice(uninit_src);
191 unsafe { &*(ram_buffer as *const [MaybeUninit<u8>] as *const [u8]) }
192 }; 192 };
193 193
194 if buffer.len() > EASY_DMA_SIZE { 194 if buffer.len() > EASY_DMA_SIZE {
@@ -358,7 +358,6 @@ impl<'d, T: Instance> Twim<'d, T> {
358 &mut self, 358 &mut self,
359 address: u8, 359 address: u8,
360 operations: &mut [Operation<'_>], 360 operations: &mut [Operation<'_>],
361 tx_ram_buffer: Option<&mut [MaybeUninit<u8>; FORCE_COPY_BUFFER_SIZE]>,
362 last_op: Option<&Operation<'_>>, 361 last_op: Option<&Operation<'_>>,
363 inten: bool, 362 inten: bool,
364 ) -> Result<usize, Error> { 363 ) -> Result<usize, Error> {
@@ -397,7 +396,7 @@ impl<'d, T: Instance> Twim<'d, T> {
397 396
398 // Set up DMA buffers. 397 // Set up DMA buffers.
399 unsafe { 398 unsafe {
400 self.set_tx_buffer(wr_buffer, tx_ram_buffer)?; 399 self.set_tx_buffer(wr_buffer)?;
401 self.set_rx_buffer(rd_buffer)?; 400 self.set_rx_buffer(rd_buffer)?;
402 } 401 }
403 402
@@ -450,7 +449,7 @@ impl<'d, T: Instance> Twim<'d, T> {
450 { 449 {
451 // Set up DMA buffers. 450 // Set up DMA buffers.
452 unsafe { 451 unsafe {
453 self.set_tx_buffer(wr_buffer, tx_ram_buffer)?; 452 self.set_tx_buffer(wr_buffer)?;
454 self.set_rx_buffer(rd_buffer)?; 453 self.set_rx_buffer(rd_buffer)?;
455 } 454 }
456 455
@@ -472,7 +471,7 @@ impl<'d, T: Instance> Twim<'d, T> {
472 471
473 // Set up DMA buffers. 472 // Set up DMA buffers.
474 unsafe { 473 unsafe {
475 self.set_tx_buffer(buffer, tx_ram_buffer)?; 474 self.set_tx_buffer(buffer)?;
476 } 475 }
477 476
478 // Start write operation. 477 // Start write operation.
@@ -539,28 +538,9 @@ impl<'d, T: Instance> Twim<'d, T> {
539 /// An `Operation::Write` following an `Operation::Read` must have a 538 /// An `Operation::Write` following an `Operation::Read` must have a
540 /// non-empty buffer. 539 /// non-empty buffer.
541 pub fn blocking_transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { 540 pub fn blocking_transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> {
542 let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE];
543 let mut last_op = None; 541 let mut last_op = None;
544 while !operations.is_empty() { 542 while !operations.is_empty() {
545 let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, false)?; 543 let ops = self.setup_operations(address, operations, last_op, false)?;
546 let (in_progress, rest) = operations.split_at_mut(ops);
547 self.blocking_wait();
548 self.check_operations(in_progress)?;
549 last_op = in_progress.last();
550 operations = rest;
551 }
552 Ok(())
553 }
554
555 /// Same as [`blocking_transaction`](Twim::blocking_transaction) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
556 pub fn blocking_transaction_from_ram(
557 &mut self,
558 address: u8,
559 mut operations: &mut [Operation<'_>],
560 ) -> Result<(), Error> {
561 let mut last_op = None;
562 while !operations.is_empty() {
563 let ops = self.setup_operations(address, operations, None, last_op, false)?;
564 let (in_progress, rest) = operations.split_at_mut(ops); 544 let (in_progress, rest) = operations.split_at_mut(ops);
565 self.blocking_wait(); 545 self.blocking_wait();
566 self.check_operations(in_progress)?; 546 self.check_operations(in_progress)?;
@@ -580,30 +560,9 @@ impl<'d, T: Instance> Twim<'d, T> {
580 mut operations: &mut [Operation<'_>], 560 mut operations: &mut [Operation<'_>],
581 timeout: Duration, 561 timeout: Duration,
582 ) -> Result<(), Error> { 562 ) -> Result<(), Error> {
583 let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE];
584 let mut last_op = None;
585 while !operations.is_empty() {
586 let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, false)?;
587 let (in_progress, rest) = operations.split_at_mut(ops);
588 self.blocking_wait_timeout(timeout)?;
589 self.check_operations(in_progress)?;
590 last_op = in_progress.last();
591 operations = rest;
592 }
593 Ok(())
594 }
595
596 /// 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.
597 #[cfg(feature = "time")]
598 pub fn blocking_transaction_from_ram_timeout(
599 &mut self,
600 address: u8,
601 mut operations: &mut [Operation<'_>],
602 timeout: Duration,
603 ) -> Result<(), Error> {
604 let mut last_op = None; 563 let mut last_op = None;
605 while !operations.is_empty() { 564 while !operations.is_empty() {
606 let ops = self.setup_operations(address, operations, None, last_op, false)?; 565 let ops = self.setup_operations(address, operations, last_op, false)?;
607 let (in_progress, rest) = operations.split_at_mut(ops); 566 let (in_progress, rest) = operations.split_at_mut(ops);
608 self.blocking_wait_timeout(timeout)?; 567 self.blocking_wait_timeout(timeout)?;
609 self.check_operations(in_progress)?; 568 self.check_operations(in_progress)?;
@@ -624,28 +583,9 @@ impl<'d, T: Instance> Twim<'d, T> {
624 /// An `Operation::Write` following an `Operation::Read` must have a 583 /// An `Operation::Write` following an `Operation::Read` must have a
625 /// non-empty buffer. 584 /// non-empty buffer.
626 pub async fn transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { 585 pub async fn transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> {
627 let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE];
628 let mut last_op = None; 586 let mut last_op = None;
629 while !operations.is_empty() { 587 while !operations.is_empty() {
630 let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, true)?; 588 let ops = self.setup_operations(address, operations, last_op, true)?;
631 let (in_progress, rest) = operations.split_at_mut(ops);
632 self.async_wait().await?;
633 self.check_operations(in_progress)?;
634 last_op = in_progress.last();
635 operations = rest;
636 }
637 Ok(())
638 }
639
640 /// Same as [`transaction`](Twim::transaction) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
641 pub async fn transaction_from_ram(
642 &mut self,
643 address: u8,
644 mut operations: &mut [Operation<'_>],
645 ) -> Result<(), Error> {
646 let mut last_op = None;
647 while !operations.is_empty() {
648 let ops = self.setup_operations(address, operations, None, last_op, true)?;
649 let (in_progress, rest) = operations.split_at_mut(ops); 589 let (in_progress, rest) = operations.split_at_mut(ops);
650 self.async_wait().await?; 590 self.async_wait().await?;
651 self.check_operations(in_progress)?; 591 self.check_operations(in_progress)?;
@@ -665,11 +605,6 @@ impl<'d, T: Instance> Twim<'d, T> {
665 self.blocking_transaction(address, &mut [Operation::Write(buffer)]) 605 self.blocking_transaction(address, &mut [Operation::Write(buffer)])
666 } 606 }
667 607
668 /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
669 pub fn blocking_write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
670 self.blocking_transaction_from_ram(address, &mut [Operation::Write(buffer)])
671 }
672
673 /// Read from an I2C slave. 608 /// Read from an I2C slave.
674 /// 609 ///
675 /// The buffer must have a length of at most 255 bytes on the nRF52832 610 /// The buffer must have a length of at most 255 bytes on the nRF52832
@@ -687,16 +622,6 @@ impl<'d, T: Instance> Twim<'d, T> {
687 self.blocking_transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) 622 self.blocking_transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
688 } 623 }
689 624
690 /// 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.
691 pub fn blocking_write_read_from_ram(
692 &mut self,
693 address: u8,
694 wr_buffer: &[u8],
695 rd_buffer: &mut [u8],
696 ) -> Result<(), Error> {
697 self.blocking_transaction_from_ram(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
698 }
699
700 // =========================================== 625 // ===========================================
701 626
702 /// Write to an I2C slave with timeout. 627 /// Write to an I2C slave with timeout.
@@ -707,17 +632,6 @@ impl<'d, T: Instance> Twim<'d, T> {
707 self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], timeout) 632 self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], timeout)
708 } 633 }
709 634
710 /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
711 #[cfg(feature = "time")]
712 pub fn blocking_write_from_ram_timeout(
713 &mut self,
714 address: u8,
715 buffer: &[u8],
716 timeout: Duration,
717 ) -> Result<(), Error> {
718 self.blocking_transaction_from_ram_timeout(address, &mut [Operation::Write(buffer)], timeout)
719 }
720
721 /// Read from an I2C slave. 635 /// Read from an I2C slave.
722 /// 636 ///
723 /// The buffer must have a length of at most 255 bytes on the nRF52832 637 /// The buffer must have a length of at most 255 bytes on the nRF52832
@@ -747,22 +661,6 @@ impl<'d, T: Instance> Twim<'d, T> {
747 ) 661 )
748 } 662 }
749 663
750 /// 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.
751 #[cfg(feature = "time")]
752 pub fn blocking_write_read_from_ram_timeout(
753 &mut self,
754 address: u8,
755 wr_buffer: &[u8],
756 rd_buffer: &mut [u8],
757 timeout: Duration,
758 ) -> Result<(), Error> {
759 self.blocking_transaction_from_ram_timeout(
760 address,
761 &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)],
762 timeout,
763 )
764 }
765
766 // =========================================== 664 // ===========================================
767 665
768 /// Read from an I2C slave. 666 /// Read from an I2C slave.
@@ -781,12 +679,6 @@ impl<'d, T: Instance> Twim<'d, T> {
781 self.transaction(address, &mut [Operation::Write(buffer)]).await 679 self.transaction(address, &mut [Operation::Write(buffer)]).await
782 } 680 }
783 681
784 /// Same as [`write`](Twim::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
785 pub async fn write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
786 self.transaction_from_ram(address, &mut [Operation::Write(buffer)])
787 .await
788 }
789
790 /// Write data to an I2C slave, then read data from the slave without 682 /// Write data to an I2C slave, then read data from the slave without
791 /// triggering a stop condition between the two. 683 /// triggering a stop condition between the two.
792 /// 684 ///
@@ -796,17 +688,6 @@ impl<'d, T: Instance> Twim<'d, T> {
796 self.transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) 688 self.transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
797 .await 689 .await
798 } 690 }
799
800 /// Same as [`write_read`](Twim::write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
801 pub async fn write_read_from_ram(
802 &mut self,
803 address: u8,
804 wr_buffer: &[u8],
805 rd_buffer: &mut [u8],
806 ) -> Result<(), Error> {
807 self.transaction_from_ram(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
808 .await
809 }
810} 691}
811 692
812impl<'a, T: Instance> Drop for Twim<'a, T> { 693impl<'a, T: Instance> Drop for Twim<'a, T> {
@@ -904,7 +785,7 @@ impl embedded_hal_1::i2c::Error for Error {
904 Self::RxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other, 785 Self::RxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other,
905 Self::Transmit => embedded_hal_1::i2c::ErrorKind::Other, 786 Self::Transmit => embedded_hal_1::i2c::ErrorKind::Other,
906 Self::Receive => embedded_hal_1::i2c::ErrorKind::Other, 787 Self::Receive => embedded_hal_1::i2c::ErrorKind::Other,
907 Self::BufferNotInRAM => embedded_hal_1::i2c::ErrorKind::Other, 788 Self::RAMBufferTooSmall => embedded_hal_1::i2c::ErrorKind::Other,
908 Self::AddressNack => { 789 Self::AddressNack => {
909 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) 790 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address)
910 } 791 }