aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2025-04-30 11:40:40 +0200
committerGitHub <[email protected]>2025-04-30 11:40:40 +0200
commit5f0196cb29be2edd2de300f8a42a031062441f1a (patch)
tree1de57d944426e30f687fae1005dba1084e56c06e /embassy-nrf
parent1d2f0add77f7344f0060150f1ff4d56f50d5eed5 (diff)
parentfb7504c2930a3f177a33f1dcc736da0d548d6e97 (diff)
Merge pull request #4113 from alexmoon/twim-ram-buffer
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.rs171
1 files changed, 29 insertions, 142 deletions
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index 083b54b99..3d5e841d1 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,16 +114,24 @@ 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> {
121 /// Create a new TWI driver. 121 /// Create a new TWI driver.
122 ///
123 /// `tx_ram_buffer` is required if any write operations will be performed with data that is not in RAM.
124 /// Usually this is static data that the compiler locates in flash instead of RAM. The `tx_ram_buffer`
125 /// needs to be at least as large as the largest write operation that will be executed with a buffer
126 /// that is not in RAM. If all write operations will be performed from RAM, an empty buffer (`&[]`) may
127 /// be used.
122 pub fn new( 128 pub fn new(
123 twim: Peri<'d, T>, 129 twim: Peri<'d, T>,
124 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 130 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
125 sda: Peri<'d, impl GpioPin>, 131 sda: Peri<'d, impl GpioPin>,
126 scl: Peri<'d, impl GpioPin>, 132 scl: Peri<'d, impl GpioPin>,
127 config: Config, 133 config: Config,
134 tx_ram_buffer: &'d mut [u8],
128 ) -> Self { 135 ) -> Self {
129 let r = T::regs(); 136 let r = T::regs();
130 137
@@ -159,7 +166,10 @@ impl<'d, T: Instance> Twim<'d, T> {
159 // Enable TWIM instance. 166 // Enable TWIM instance.
160 r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); 167 r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
161 168
162 let mut twim = Self { _p: twim }; 169 let mut twim = Self {
170 _p: twim,
171 tx_ram_buffer,
172 };
163 173
164 // Apply runtime peripheral configuration 174 // Apply runtime peripheral configuration
165 Self::set_config(&mut twim, &config).unwrap(); 175 Self::set_config(&mut twim, &config).unwrap();
@@ -174,21 +184,17 @@ impl<'d, T: Instance> Twim<'d, T> {
174 } 184 }
175 185
176 /// Set TX buffer, checking that it is in RAM and has suitable length. 186 /// Set TX buffer, checking that it is in RAM and has suitable length.
177 unsafe fn set_tx_buffer( 187 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) { 188 let buffer = if slice_in_ram(buffer) {
183 buffer 189 buffer
184 } else { 190 } else {
185 let ram_buffer = ram_buffer.ok_or(Error::BufferNotInRAM)?; 191 if buffer.len() > self.tx_ram_buffer.len() {
192 return Err(Error::RAMBufferTooSmall);
193 }
186 trace!("Copying TWIM tx buffer into RAM for DMA"); 194 trace!("Copying TWIM tx buffer into RAM for DMA");
187 let ram_buffer = &mut ram_buffer[..buffer.len()]; 195 let ram_buffer = &mut self.tx_ram_buffer[..buffer.len()];
188 // Inline implementation of the nightly API MaybeUninit::copy_from_slice(ram_buffer, buffer) 196 ram_buffer.copy_from_slice(buffer);
189 let uninit_src: &[MaybeUninit<u8>] = unsafe { core::mem::transmute(buffer) }; 197 &*ram_buffer
190 ram_buffer.copy_from_slice(uninit_src);
191 unsafe { &*(ram_buffer as *const [MaybeUninit<u8>] as *const [u8]) }
192 }; 198 };
193 199
194 if buffer.len() > EASY_DMA_SIZE { 200 if buffer.len() > EASY_DMA_SIZE {
@@ -358,7 +364,6 @@ impl<'d, T: Instance> Twim<'d, T> {
358 &mut self, 364 &mut self,
359 address: u8, 365 address: u8,
360 operations: &mut [Operation<'_>], 366 operations: &mut [Operation<'_>],
361 tx_ram_buffer: Option<&mut [MaybeUninit<u8>; FORCE_COPY_BUFFER_SIZE]>,
362 last_op: Option<&Operation<'_>>, 367 last_op: Option<&Operation<'_>>,
363 inten: bool, 368 inten: bool,
364 ) -> Result<usize, Error> { 369 ) -> Result<usize, Error> {
@@ -397,7 +402,7 @@ impl<'d, T: Instance> Twim<'d, T> {
397 402
398 // Set up DMA buffers. 403 // Set up DMA buffers.
399 unsafe { 404 unsafe {
400 self.set_tx_buffer(wr_buffer, tx_ram_buffer)?; 405 self.set_tx_buffer(wr_buffer)?;
401 self.set_rx_buffer(rd_buffer)?; 406 self.set_rx_buffer(rd_buffer)?;
402 } 407 }
403 408
@@ -450,7 +455,7 @@ impl<'d, T: Instance> Twim<'d, T> {
450 { 455 {
451 // Set up DMA buffers. 456 // Set up DMA buffers.
452 unsafe { 457 unsafe {
453 self.set_tx_buffer(wr_buffer, tx_ram_buffer)?; 458 self.set_tx_buffer(wr_buffer)?;
454 self.set_rx_buffer(rd_buffer)?; 459 self.set_rx_buffer(rd_buffer)?;
455 } 460 }
456 461
@@ -472,7 +477,7 @@ impl<'d, T: Instance> Twim<'d, T> {
472 477
473 // Set up DMA buffers. 478 // Set up DMA buffers.
474 unsafe { 479 unsafe {
475 self.set_tx_buffer(buffer, tx_ram_buffer)?; 480 self.set_tx_buffer(buffer)?;
476 } 481 }
477 482
478 // Start write operation. 483 // Start write operation.
@@ -539,28 +544,9 @@ impl<'d, T: Instance> Twim<'d, T> {
539 /// An `Operation::Write` following an `Operation::Read` must have a 544 /// An `Operation::Write` following an `Operation::Read` must have a
540 /// non-empty buffer. 545 /// non-empty buffer.
541 pub fn blocking_transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { 546 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; 547 let mut last_op = None;
544 while !operations.is_empty() { 548 while !operations.is_empty() {
545 let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, false)?; 549 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); 550 let (in_progress, rest) = operations.split_at_mut(ops);
565 self.blocking_wait(); 551 self.blocking_wait();
566 self.check_operations(in_progress)?; 552 self.check_operations(in_progress)?;
@@ -580,30 +566,9 @@ impl<'d, T: Instance> Twim<'d, T> {
580 mut operations: &mut [Operation<'_>], 566 mut operations: &mut [Operation<'_>],
581 timeout: Duration, 567 timeout: Duration,
582 ) -> Result<(), Error> { 568 ) -> 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; 569 let mut last_op = None;
605 while !operations.is_empty() { 570 while !operations.is_empty() {
606 let ops = self.setup_operations(address, operations, None, last_op, false)?; 571 let ops = self.setup_operations(address, operations, last_op, false)?;
607 let (in_progress, rest) = operations.split_at_mut(ops); 572 let (in_progress, rest) = operations.split_at_mut(ops);
608 self.blocking_wait_timeout(timeout)?; 573 self.blocking_wait_timeout(timeout)?;
609 self.check_operations(in_progress)?; 574 self.check_operations(in_progress)?;
@@ -624,28 +589,9 @@ impl<'d, T: Instance> Twim<'d, T> {
624 /// An `Operation::Write` following an `Operation::Read` must have a 589 /// An `Operation::Write` following an `Operation::Read` must have a
625 /// non-empty buffer. 590 /// non-empty buffer.
626 pub async fn transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { 591 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;
629 while !operations.is_empty() {
630 let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), 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; 592 let mut last_op = None;
647 while !operations.is_empty() { 593 while !operations.is_empty() {
648 let ops = self.setup_operations(address, operations, None, last_op, true)?; 594 let ops = self.setup_operations(address, operations, last_op, true)?;
649 let (in_progress, rest) = operations.split_at_mut(ops); 595 let (in_progress, rest) = operations.split_at_mut(ops);
650 self.async_wait().await?; 596 self.async_wait().await?;
651 self.check_operations(in_progress)?; 597 self.check_operations(in_progress)?;
@@ -665,11 +611,6 @@ impl<'d, T: Instance> Twim<'d, T> {
665 self.blocking_transaction(address, &mut [Operation::Write(buffer)]) 611 self.blocking_transaction(address, &mut [Operation::Write(buffer)])
666 } 612 }
667 613
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. 614 /// Read from an I2C slave.
674 /// 615 ///
675 /// The buffer must have a length of at most 255 bytes on the nRF52832 616 /// The buffer must have a length of at most 255 bytes on the nRF52832
@@ -687,16 +628,6 @@ impl<'d, T: Instance> Twim<'d, T> {
687 self.blocking_transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) 628 self.blocking_transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
688 } 629 }
689 630
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 // =========================================== 631 // ===========================================
701 632
702 /// Write to an I2C slave with timeout. 633 /// Write to an I2C slave with timeout.
@@ -707,17 +638,6 @@ impl<'d, T: Instance> Twim<'d, T> {
707 self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], timeout) 638 self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], timeout)
708 } 639 }
709 640
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. 641 /// Read from an I2C slave.
722 /// 642 ///
723 /// The buffer must have a length of at most 255 bytes on the nRF52832 643 /// The buffer must have a length of at most 255 bytes on the nRF52832
@@ -747,22 +667,6 @@ impl<'d, T: Instance> Twim<'d, T> {
747 ) 667 )
748 } 668 }
749 669
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 // =========================================== 670 // ===========================================
767 671
768 /// Read from an I2C slave. 672 /// Read from an I2C slave.
@@ -781,12 +685,6 @@ impl<'d, T: Instance> Twim<'d, T> {
781 self.transaction(address, &mut [Operation::Write(buffer)]).await 685 self.transaction(address, &mut [Operation::Write(buffer)]).await
782 } 686 }
783 687
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 688 /// Write data to an I2C slave, then read data from the slave without
791 /// triggering a stop condition between the two. 689 /// triggering a stop condition between the two.
792 /// 690 ///
@@ -796,17 +694,6 @@ impl<'d, T: Instance> Twim<'d, T> {
796 self.transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) 694 self.transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
797 .await 695 .await
798 } 696 }
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} 697}
811 698
812impl<'a, T: Instance> Drop for Twim<'a, T> { 699impl<'a, T: Instance> Drop for Twim<'a, T> {
@@ -904,7 +791,7 @@ impl embedded_hal_1::i2c::Error for Error {
904 Self::RxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other, 791 Self::RxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other,
905 Self::Transmit => embedded_hal_1::i2c::ErrorKind::Other, 792 Self::Transmit => embedded_hal_1::i2c::ErrorKind::Other,
906 Self::Receive => embedded_hal_1::i2c::ErrorKind::Other, 793 Self::Receive => embedded_hal_1::i2c::ErrorKind::Other,
907 Self::BufferNotInRAM => embedded_hal_1::i2c::ErrorKind::Other, 794 Self::RAMBufferTooSmall => embedded_hal_1::i2c::ErrorKind::Other,
908 Self::AddressNack => { 795 Self::AddressNack => {
909 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) 796 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address)
910 } 797 }