diff options
32 files changed, 569 insertions, 393 deletions
| @@ -324,7 +324,6 @@ DEFMT_RTT_BUFFER_SIZE="72" cargo batch \ | |||
| 324 | 324 | ||
| 325 | # temporarily disabled, these boards are dead. | 325 | # temporarily disabled, these boards are dead. |
| 326 | rm -rf out/tests/stm32f103c8 | 326 | rm -rf out/tests/stm32f103c8 |
| 327 | rm -rf out/tests/stm32l073rz | ||
| 328 | rm -rf out/tests/nrf52840-dk | 327 | rm -rf out/tests/nrf52840-dk |
| 329 | rm -rf out/tests/nrf52833-dk | 328 | rm -rf out/tests/nrf52833-dk |
| 330 | 329 | ||
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 | ||
| 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; | ||
| 8 | use core::sync::atomic::compiler_fence; | 7 | use core::sync::atomic::compiler_fence; |
| 9 | use core::sync::atomic::Ordering::SeqCst; | 8 | use core::sync::atomic::Ordering::SeqCst; |
| 10 | use core::task::Poll; | 9 | use core::task::Poll; |
| @@ -17,7 +16,7 @@ use embassy_time::{Duration, Instant}; | |||
| 17 | use embedded_hal_1::i2c::Operation; | 16 | use embedded_hal_1::i2c::Operation; |
| 18 | pub use pac::twim::vals::Frequency; | 17 | pub use pac::twim::vals::Frequency; |
| 19 | 18 | ||
| 20 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | 19 | use crate::chip::EASY_DMA_SIZE; |
| 21 | use crate::gpio::Pin as GpioPin; | 20 | use crate::gpio::Pin as GpioPin; |
| 22 | use crate::interrupt::typelevel::Interrupt; | 21 | use crate::interrupt::typelevel::Interrupt; |
| 23 | use crate::pac::gpio::vals as gpiovals; | 22 | use 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. |
| 116 | pub struct Twim<'d, T: Instance> { | 115 | pub 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 | ||
| 120 | impl<'d, T: Instance> Twim<'d, T> { | 120 | impl<'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 | ||
| 812 | impl<'a, T: Instance> Drop for Twim<'a, T> { | 699 | impl<'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 | } |
diff --git a/embassy-rp/src/pio_programs/onewire.rs b/embassy-rp/src/pio_programs/onewire.rs index 00783aab0..287ddab41 100644 --- a/embassy-rp/src/pio_programs/onewire.rs +++ b/embassy-rp/src/pio_programs/onewire.rs | |||
| @@ -1,11 +1,17 @@ | |||
| 1 | //! OneWire pio driver | 1 | //! OneWire pio driver |
| 2 | 2 | ||
| 3 | use crate::pio::{Common, Config, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine}; | 3 | use crate::clocks::clk_sys_freq; |
| 4 | use crate::gpio::Level; | ||
| 5 | use crate::pio::{ | ||
| 6 | Common, Config, Direction, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, | ||
| 7 | }; | ||
| 4 | use crate::Peri; | 8 | use crate::Peri; |
| 5 | 9 | ||
| 6 | /// This struct represents an onewire driver program | 10 | /// This struct represents a onewire driver program |
| 7 | pub struct PioOneWireProgram<'a, PIO: Instance> { | 11 | pub struct PioOneWireProgram<'a, PIO: Instance> { |
| 8 | prg: LoadedProgram<'a, PIO>, | 12 | prg: LoadedProgram<'a, PIO>, |
| 13 | reset_addr: u8, | ||
| 14 | next_bit_addr: u8, | ||
| 9 | } | 15 | } |
| 10 | 16 | ||
| 11 | impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> { | 17 | impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> { |
| @@ -13,56 +19,67 @@ impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> { | |||
| 13 | pub fn new(common: &mut Common<'a, PIO>) -> Self { | 19 | pub fn new(common: &mut Common<'a, PIO>) -> Self { |
| 14 | let prg = pio::pio_asm!( | 20 | let prg = pio::pio_asm!( |
| 15 | r#" | 21 | r#" |
| 16 | .wrap_target | 22 | ; We need to use the pins direction to simulate open drain output |
| 17 | again: | 23 | ; This results in all the side-set values being swapped from the actual pin value |
| 18 | pull block | 24 | .side_set 1 pindirs |
| 19 | mov x, osr | 25 | |
| 20 | jmp !x, read | 26 | ; Set the origin to 0 so we can correctly use jmp instructions externally |
| 21 | write: | 27 | .origin 0 |
| 22 | set pindirs, 1 | 28 | |
| 23 | set pins, 0 | 29 | ; Tick rate is 1 tick per 6us, so all delays should be calculated back to that |
| 24 | loop1: | 30 | ; All the instructions have a calculated delay XX in us as [(XX / CLK) - 1]. |
| 25 | jmp x--,loop1 | 31 | ; The - 1 is for the instruction which also takes one clock cyle. |
| 26 | set pindirs, 0 [31] | 32 | ; The delay can be 0 which will result in just 6us for the instruction itself |
| 27 | wait 1 pin 0 [31] | 33 | .define CLK 6 |
| 28 | pull block | 34 | |
| 29 | mov x, osr | 35 | ; Write the reset block after trigger |
| 30 | bytes1: | 36 | public reset: |
| 31 | pull block | 37 | set x, 4 side 0 [(60 / CLK) - 1] ; idle before reset |
| 32 | set y, 7 | 38 | reset_inner: ; Repeat the following 5 times, so 5*96us = 480us in total |
| 33 | set pindirs, 1 | 39 | nop side 1 [(90 / CLK) - 1] |
| 34 | bit1: | 40 | jmp x--, reset_inner side 1 [( 6 / CLK) - 1] |
| 35 | set pins, 0 [1] | 41 | ; Fallthrough |
| 36 | out pins,1 [31] | 42 | |
| 37 | set pins, 1 [20] | 43 | ; Check for presence of one or more devices. |
| 38 | jmp y--,bit1 | 44 | ; This samples 32 times with an interval of 12us after a 18us delay. |
| 39 | jmp x--,bytes1 | 45 | ; If any bit is zero in the end value, there is a detection |
| 40 | set pindirs, 0 [31] | 46 | ; This whole function takes 480us |
| 41 | jmp again | 47 | set x, 31 side 0 [(24 / CLK) - 1] ; Loop 32 times -> 32*12us = 384us |
| 42 | read: | 48 | presence_check: |
| 43 | pull block | 49 | in pins, 1 side 0 [( 6 / CLK) - 1] ; poll pin and push to isr |
| 44 | mov x, osr | 50 | jmp x--, presence_check side 0 [( 6 / CLK) - 1] |
| 45 | bytes2: | 51 | jmp next_bit side 0 [(72 / CLK) - 1] |
| 46 | set y, 7 | 52 | |
| 47 | bit2: | 53 | ; The low pulse was already done, we only need to delay and poll the bit in case we are reading |
| 48 | set pindirs, 1 | 54 | write_1: |
| 49 | set pins, 0 [1] | 55 | nop side 0 [( 6 / CLK) - 1] ; Delay before sampling the input pin |
| 50 | set pindirs, 0 [5] | 56 | in pins, 1 side 0 [(48 / CLK) - 1] ; This writes the state of the pin into the ISR |
| 51 | in pins,1 [10] | 57 | ; Fallthrough |
| 52 | jmp y--,bit2 | 58 | |
| 53 | jmp x--,bytes2 | 59 | ; This is the entry point when reading and writing data |
| 54 | .wrap | 60 | public next_bit: |
| 55 | "#, | 61 | .wrap_target |
| 62 | out x, 1 side 0 [(12 / CLK) - 1] ; Stalls if no data available in TX FIFO and OSR | ||
| 63 | jmp x--, write_1 side 1 [( 6 / CLK) - 1] ; Do the always low part of a bit, jump to write_1 if we want to write a 1 bit | ||
| 64 | in null, 1 side 1 [(54 / CLK) - 1] ; Do the remainder of the low part of a 0 bit | ||
| 65 | ; This writes 0 into the ISR so that the shift count stays in sync | ||
| 66 | .wrap | ||
| 67 | "# | ||
| 56 | ); | 68 | ); |
| 57 | let prg = common.load_program(&prg.program); | ||
| 58 | 69 | ||
| 59 | Self { prg } | 70 | Self { |
| 71 | prg: common.load_program(&prg.program), | ||
| 72 | reset_addr: prg.public_defines.reset as u8, | ||
| 73 | next_bit_addr: prg.public_defines.next_bit as u8, | ||
| 74 | } | ||
| 60 | } | 75 | } |
| 61 | } | 76 | } |
| 62 | |||
| 63 | /// Pio backed OneWire driver | 77 | /// Pio backed OneWire driver |
| 64 | pub struct PioOneWire<'d, PIO: Instance, const SM: usize> { | 78 | pub struct PioOneWire<'d, PIO: Instance, const SM: usize> { |
| 65 | sm: StateMachine<'d, PIO, SM>, | 79 | sm: StateMachine<'d, PIO, SM>, |
| 80 | cfg: Config<'d, PIO>, | ||
| 81 | reset_addr: u8, | ||
| 82 | next_bit_addr: u8, | ||
| 66 | } | 83 | } |
| 67 | 84 | ||
| 68 | impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { | 85 | impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { |
| @@ -74,37 +91,206 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { | |||
| 74 | program: &PioOneWireProgram<'d, PIO>, | 91 | program: &PioOneWireProgram<'d, PIO>, |
| 75 | ) -> Self { | 92 | ) -> Self { |
| 76 | let pin = common.make_pio_pin(pin); | 93 | let pin = common.make_pio_pin(pin); |
| 94 | |||
| 95 | sm.set_pin_dirs(Direction::In, &[&pin]); | ||
| 96 | sm.set_pins(Level::Low, &[&pin]); | ||
| 97 | |||
| 77 | let mut cfg = Config::default(); | 98 | let mut cfg = Config::default(); |
| 78 | cfg.use_program(&program.prg, &[]); | 99 | cfg.use_program(&program.prg, &[&pin]); |
| 79 | cfg.set_out_pins(&[&pin]); | ||
| 80 | cfg.set_in_pins(&[&pin]); | 100 | cfg.set_in_pins(&[&pin]); |
| 81 | cfg.set_set_pins(&[&pin]); | 101 | |
| 82 | cfg.shift_in = ShiftConfig { | 102 | let shift_cfg = ShiftConfig { |
| 83 | auto_fill: true, | 103 | auto_fill: true, |
| 84 | direction: ShiftDirection::Right, | 104 | direction: ShiftDirection::Right, |
| 85 | threshold: 8, | 105 | threshold: 8, |
| 86 | }; | 106 | }; |
| 87 | cfg.clock_divider = 255_u8.into(); | 107 | cfg.shift_in = shift_cfg; |
| 108 | cfg.shift_out = shift_cfg; | ||
| 109 | |||
| 110 | let divider = (clk_sys_freq() / 1000000) as u16 * 6; | ||
| 111 | cfg.clock_divider = divider.into(); | ||
| 112 | |||
| 88 | sm.set_config(&cfg); | 113 | sm.set_config(&cfg); |
| 114 | sm.clear_fifos(); | ||
| 115 | sm.restart(); | ||
| 116 | unsafe { | ||
| 117 | sm.exec_jmp(program.next_bit_addr); | ||
| 118 | } | ||
| 89 | sm.set_enable(true); | 119 | sm.set_enable(true); |
| 90 | Self { sm } | 120 | |
| 121 | Self { | ||
| 122 | sm, | ||
| 123 | cfg, | ||
| 124 | reset_addr: program.reset_addr, | ||
| 125 | next_bit_addr: program.next_bit_addr, | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | /// Perform an initialization sequence, will return true if a presence pulse was detected from a device | ||
| 130 | pub async fn reset(&mut self) -> bool { | ||
| 131 | // The state machine immediately starts running when jumping to this address | ||
| 132 | unsafe { | ||
| 133 | self.sm.exec_jmp(self.reset_addr); | ||
| 134 | } | ||
| 135 | |||
| 136 | let rx = self.sm.rx(); | ||
| 137 | let mut found = false; | ||
| 138 | for _ in 0..4 { | ||
| 139 | if rx.wait_pull().await != 0 { | ||
| 140 | found = true; | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | found | ||
| 91 | } | 145 | } |
| 92 | 146 | ||
| 93 | /// Write bytes over the wire | 147 | /// Write bytes to the onewire bus |
| 94 | pub async fn write_bytes(&mut self, bytes: &[u8]) { | 148 | pub async fn write_bytes(&mut self, data: &[u8]) { |
| 95 | self.sm.tx().wait_push(250).await; | 149 | let (rx, tx) = self.sm.rx_tx(); |
| 96 | self.sm.tx().wait_push(bytes.len() as u32 - 1).await; | 150 | for b in data { |
| 97 | for b in bytes { | 151 | tx.wait_push(*b as u32).await; |
| 98 | self.sm.tx().wait_push(*b as u32).await; | 152 | |
| 153 | // Empty the buffer that is being filled with every write | ||
| 154 | let _ = rx.wait_pull().await; | ||
| 99 | } | 155 | } |
| 100 | } | 156 | } |
| 101 | 157 | ||
| 102 | /// Read bytes from the wire | 158 | /// Read bytes from the onewire bus |
| 103 | pub async fn read_bytes(&mut self, bytes: &mut [u8]) { | 159 | pub async fn read_bytes(&mut self, data: &mut [u8]) { |
| 104 | self.sm.tx().wait_push(0).await; | 160 | let (rx, tx) = self.sm.rx_tx(); |
| 105 | self.sm.tx().wait_push(bytes.len() as u32 - 1).await; | 161 | for b in data { |
| 106 | for b in bytes.iter_mut() { | 162 | // Write all 1's so that we can read what the device responds |
| 107 | *b = (self.sm.rx().wait_pull().await >> 24) as u8; | 163 | tx.wait_push(0xff).await; |
| 164 | |||
| 165 | *b = (rx.wait_pull().await >> 24) as u8; | ||
| 108 | } | 166 | } |
| 109 | } | 167 | } |
| 168 | |||
| 169 | async fn search(&mut self, state: &mut PioOneWireSearch) -> Option<u64> { | ||
| 170 | if !self.reset().await { | ||
| 171 | // No device present, no use in searching | ||
| 172 | state.finished = true; | ||
| 173 | return None; | ||
| 174 | } | ||
| 175 | self.write_bytes(&[0xF0]).await; // 0xF0 is the search rom command | ||
| 176 | |||
| 177 | self.prepare_search(); | ||
| 178 | |||
| 179 | let (rx, tx) = self.sm.rx_tx(); | ||
| 180 | |||
| 181 | let mut value = 0; | ||
| 182 | let mut last_zero = 0; | ||
| 183 | |||
| 184 | for bit in 0..64 { | ||
| 185 | // Write 2 dummy bits to read a bit and its complement | ||
| 186 | tx.wait_push(0x1).await; | ||
| 187 | tx.wait_push(0x1).await; | ||
| 188 | let in1 = rx.wait_pull().await; | ||
| 189 | let in2 = rx.wait_pull().await; | ||
| 190 | let push = match (in1, in2) { | ||
| 191 | (0, 0) => { | ||
| 192 | // If both are 0, it means we have devices with 0 and 1 bits in this position | ||
| 193 | let write_value = if bit < state.last_discrepancy { | ||
| 194 | (state.last_rom & (1 << bit)) != 0 | ||
| 195 | } else { | ||
| 196 | bit == state.last_discrepancy | ||
| 197 | }; | ||
| 198 | |||
| 199 | if write_value { | ||
| 200 | 1 | ||
| 201 | } else { | ||
| 202 | last_zero = bit; | ||
| 203 | 0 | ||
| 204 | } | ||
| 205 | } | ||
| 206 | (0, 1) => 0, // Only devices with a 0 bit in this position | ||
| 207 | (1, 0) => 1, // Only devices with a 1 bit in this position | ||
| 208 | _ => { | ||
| 209 | // If both are 1, it means there is no device active and there is no point in continuing | ||
| 210 | self.restore_after_search(); | ||
| 211 | state.finished = true; | ||
| 212 | return None; | ||
| 213 | } | ||
| 214 | }; | ||
| 215 | value >>= 1; | ||
| 216 | if push == 1 { | ||
| 217 | value |= 1 << 63; | ||
| 218 | } | ||
| 219 | tx.wait_push(push).await; | ||
| 220 | let _ = rx.wait_pull().await; // Discard the result of the write action | ||
| 221 | } | ||
| 222 | |||
| 223 | self.restore_after_search(); | ||
| 224 | |||
| 225 | state.last_discrepancy = last_zero; | ||
| 226 | state.finished = last_zero == 0; | ||
| 227 | state.last_rom = value; | ||
| 228 | Some(value) | ||
| 229 | } | ||
| 230 | |||
| 231 | fn prepare_search(&mut self) { | ||
| 232 | self.cfg.shift_in.threshold = 1; | ||
| 233 | self.cfg.shift_in.direction = ShiftDirection::Left; | ||
| 234 | self.cfg.shift_out.threshold = 1; | ||
| 235 | |||
| 236 | self.sm.set_enable(false); | ||
| 237 | self.sm.set_config(&self.cfg); | ||
| 238 | |||
| 239 | // set_config jumps to the wrong address so jump to the right one here | ||
| 240 | unsafe { | ||
| 241 | self.sm.exec_jmp(self.next_bit_addr); | ||
| 242 | } | ||
| 243 | self.sm.set_enable(true); | ||
| 244 | } | ||
| 245 | |||
| 246 | fn restore_after_search(&mut self) { | ||
| 247 | self.cfg.shift_in.threshold = 8; | ||
| 248 | self.cfg.shift_in.direction = ShiftDirection::Right; | ||
| 249 | self.cfg.shift_out.threshold = 8; | ||
| 250 | |||
| 251 | self.sm.set_enable(false); | ||
| 252 | self.sm.set_config(&self.cfg); | ||
| 253 | |||
| 254 | // Clear the state in case we aborted prematurely with some bits still in the shift registers | ||
| 255 | self.sm.clear_fifos(); | ||
| 256 | self.sm.restart(); | ||
| 257 | |||
| 258 | // set_config jumps to the wrong address so jump to the right one here | ||
| 259 | unsafe { | ||
| 260 | self.sm.exec_jmp(self.next_bit_addr); | ||
| 261 | } | ||
| 262 | self.sm.set_enable(true); | ||
| 263 | } | ||
| 264 | } | ||
| 265 | |||
| 266 | /// Onewire search state | ||
| 267 | pub struct PioOneWireSearch { | ||
| 268 | last_rom: u64, | ||
| 269 | last_discrepancy: u8, | ||
| 270 | finished: bool, | ||
| 271 | } | ||
| 272 | |||
| 273 | impl PioOneWireSearch { | ||
| 274 | /// Create a new Onewire search state | ||
| 275 | pub fn new() -> Self { | ||
| 276 | Self { | ||
| 277 | last_rom: 0, | ||
| 278 | last_discrepancy: 0, | ||
| 279 | finished: false, | ||
| 280 | } | ||
| 281 | } | ||
| 282 | |||
| 283 | /// Search for the next address on the bus | ||
| 284 | pub async fn next<PIO: Instance, const SM: usize>(&mut self, pio: &mut PioOneWire<'_, PIO, SM>) -> Option<u64> { | ||
| 285 | if self.finished { | ||
| 286 | None | ||
| 287 | } else { | ||
| 288 | pio.search(self).await | ||
| 289 | } | ||
| 290 | } | ||
| 291 | |||
| 292 | /// Is finished when all devices have been found | ||
| 293 | pub fn is_finished(&self) -> bool { | ||
| 294 | self.finished | ||
| 295 | } | ||
| 110 | } | 296 | } |
diff --git a/embassy-rp/src/trng.rs b/embassy-rp/src/trng.rs index 611fee83b..a8a0172be 100644 --- a/embassy-rp/src/trng.rs +++ b/embassy-rp/src/trng.rs | |||
| @@ -78,6 +78,9 @@ impl From<InverterChainLength> for u8 { | |||
| 78 | /// failed entropy checks. | 78 | /// failed entropy checks. |
| 79 | /// For acceptable results with an average generation time of about 2 milliseconds, use ROSC chain length settings of 0 or | 79 | /// For acceptable results with an average generation time of about 2 milliseconds, use ROSC chain length settings of 0 or |
| 80 | /// 1 and sample count settings of 20-25. | 80 | /// 1 and sample count settings of 20-25. |
| 81 | /// Larger sample count settings (e.g. 100) provide proportionately slower average generation times. These settings | ||
| 82 | /// significantly reduce, but do not eliminate NIST test failures and entropy check failures. Results occasionally take an | ||
| 83 | /// especially long time to generate. | ||
| 81 | /// | 84 | /// |
| 82 | /// --- | 85 | /// --- |
| 83 | /// | 86 | /// |
| @@ -108,9 +111,10 @@ pub struct Config { | |||
| 108 | impl Default for Config { | 111 | impl Default for Config { |
| 109 | fn default() -> Self { | 112 | fn default() -> Self { |
| 110 | Config { | 113 | Config { |
| 111 | disable_autocorrelation_test: true, | 114 | // WARNING: Disabling these tests increases likelihood of poor rng results. |
| 112 | disable_crngt_test: true, | 115 | disable_autocorrelation_test: false, |
| 113 | disable_von_neumann_balancer: true, | 116 | disable_crngt_test: false, |
| 117 | disable_von_neumann_balancer: false, | ||
| 114 | sample_count: 25, | 118 | sample_count: 25, |
| 115 | inverter_chain_length: InverterChainLength::One, | 119 | inverter_chain_length: InverterChainLength::One, |
| 116 | } | 120 | } |
| @@ -148,6 +152,7 @@ impl Default for Config { | |||
| 148 | /// ``` | 152 | /// ``` |
| 149 | pub struct Trng<'d, T: Instance> { | 153 | pub struct Trng<'d, T: Instance> { |
| 150 | phantom: PhantomData<&'d mut T>, | 154 | phantom: PhantomData<&'d mut T>, |
| 155 | config: Config, | ||
| 151 | } | 156 | } |
| 152 | 157 | ||
| 153 | /// 12.12.1. Overview | 158 | /// 12.12.1. Overview |
| @@ -159,28 +164,12 @@ const TRNG_BLOCK_SIZE_BYTES: usize = TRNG_BLOCK_SIZE_BITS / 8; | |||
| 159 | impl<'d, T: Instance> Trng<'d, T> { | 164 | impl<'d, T: Instance> Trng<'d, T> { |
| 160 | /// Create a new TRNG driver. | 165 | /// Create a new TRNG driver. |
| 161 | pub fn new(_trng: Peri<'d, T>, _irq: impl Binding<T::Interrupt, InterruptHandler<T>> + 'd, config: Config) -> Self { | 166 | pub fn new(_trng: Peri<'d, T>, _irq: impl Binding<T::Interrupt, InterruptHandler<T>> + 'd, config: Config) -> Self { |
| 162 | let regs = T::regs(); | 167 | let trng = Trng { |
| 163 | 168 | phantom: PhantomData, | |
| 164 | regs.rng_imr().write(|w| w.set_ehr_valid_int_mask(false)); | 169 | config: config, |
| 165 | 170 | }; | |
| 166 | let trng_config_register = regs.trng_config(); | 171 | trng.initialize_rng(); |
| 167 | trng_config_register.write(|w| { | 172 | trng |
| 168 | w.set_rnd_src_sel(config.inverter_chain_length.clone().into()); | ||
| 169 | }); | ||
| 170 | |||
| 171 | let sample_count_register = regs.sample_cnt1(); | ||
| 172 | sample_count_register.write(|w| { | ||
| 173 | *w = config.sample_count; | ||
| 174 | }); | ||
| 175 | |||
| 176 | let debug_control_register = regs.trng_debug_control(); | ||
| 177 | debug_control_register.write(|w| { | ||
| 178 | w.set_auto_correlate_bypass(config.disable_autocorrelation_test); | ||
| 179 | w.set_trng_crngt_bypass(config.disable_crngt_test); | ||
| 180 | w.set_vnc_bypass(config.disable_von_neumann_balancer) | ||
| 181 | }); | ||
| 182 | |||
| 183 | Trng { phantom: PhantomData } | ||
| 184 | } | 173 | } |
| 185 | 174 | ||
| 186 | fn start_rng(&self) { | 175 | fn start_rng(&self) { |
| @@ -198,6 +187,29 @@ impl<'d, T: Instance> Trng<'d, T> { | |||
| 198 | reset_bits_counter_register.write(|w| w.set_rst_bits_counter(true)); | 187 | reset_bits_counter_register.write(|w| w.set_rst_bits_counter(true)); |
| 199 | } | 188 | } |
| 200 | 189 | ||
| 190 | fn initialize_rng(&self) { | ||
| 191 | let regs = T::regs(); | ||
| 192 | |||
| 193 | regs.rng_imr().write(|w| w.set_ehr_valid_int_mask(false)); | ||
| 194 | |||
| 195 | let trng_config_register = regs.trng_config(); | ||
| 196 | trng_config_register.write(|w| { | ||
| 197 | w.set_rnd_src_sel(self.config.inverter_chain_length.clone().into()); | ||
| 198 | }); | ||
| 199 | |||
| 200 | let sample_count_register = regs.sample_cnt1(); | ||
| 201 | sample_count_register.write(|w| { | ||
| 202 | *w = self.config.sample_count; | ||
| 203 | }); | ||
| 204 | |||
| 205 | let debug_control_register = regs.trng_debug_control(); | ||
| 206 | debug_control_register.write(|w| { | ||
| 207 | w.set_auto_correlate_bypass(self.config.disable_autocorrelation_test); | ||
| 208 | w.set_trng_crngt_bypass(self.config.disable_crngt_test); | ||
| 209 | w.set_vnc_bypass(self.config.disable_von_neumann_balancer); | ||
| 210 | }); | ||
| 211 | } | ||
| 212 | |||
| 201 | fn enable_irq(&self) { | 213 | fn enable_irq(&self) { |
| 202 | unsafe { T::Interrupt::enable() } | 214 | unsafe { T::Interrupt::enable() } |
| 203 | } | 215 | } |
| @@ -218,6 +230,10 @@ impl<'d, T: Instance> Trng<'d, T> { | |||
| 218 | if trng_valid_register.read().ehr_valid().not() { | 230 | if trng_valid_register.read().ehr_valid().not() { |
| 219 | if regs.rng_isr().read().autocorr_err() { | 231 | if regs.rng_isr().read().autocorr_err() { |
| 220 | regs.trng_sw_reset().write(|w| w.set_trng_sw_reset(true)); | 232 | regs.trng_sw_reset().write(|w| w.set_trng_sw_reset(true)); |
| 233 | // Fixed delay is required after TRNG soft reset. This read is sufficient. | ||
| 234 | regs.trng_sw_reset().read(); | ||
| 235 | self.initialize_rng(); | ||
| 236 | self.start_rng(); | ||
| 221 | } else { | 237 | } else { |
| 222 | panic!("RNG not busy, but ehr is not valid!") | 238 | panic!("RNG not busy, but ehr is not valid!") |
| 223 | } | 239 | } |
| @@ -279,8 +295,11 @@ impl<'d, T: Instance> Trng<'d, T> { | |||
| 279 | if trng_busy_register.read().trng_busy() { | 295 | if trng_busy_register.read().trng_busy() { |
| 280 | Poll::Pending | 296 | Poll::Pending |
| 281 | } else { | 297 | } else { |
| 298 | // If woken up and EHR is *not* valid, assume the trng has been reset and reinitialize, restart. | ||
| 282 | if trng_valid_register.read().ehr_valid().not() { | 299 | if trng_valid_register.read().ehr_valid().not() { |
| 283 | panic!("RNG not busy, but ehr is not valid!") | 300 | self.initialize_rng(); |
| 301 | self.start_rng(); | ||
| 302 | return Poll::Pending; | ||
| 284 | } | 303 | } |
| 285 | self.read_ehr_registers_into_array(&mut buffer); | 304 | self.read_ehr_registers_into_array(&mut buffer); |
| 286 | let remaining = destination_length - bytes_transferred; | 305 | let remaining = destination_length - bytes_transferred; |
| @@ -380,25 +399,36 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||
| 380 | unsafe fn on_interrupt() { | 399 | unsafe fn on_interrupt() { |
| 381 | let regs = T::regs(); | 400 | let regs = T::regs(); |
| 382 | let isr = regs.rng_isr().read(); | 401 | let isr = regs.rng_isr().read(); |
| 383 | // Clear ehr bit | ||
| 384 | regs.rng_icr().write(|w| { | ||
| 385 | w.set_ehr_valid(true); | ||
| 386 | }); | ||
| 387 | if isr.ehr_valid() { | 402 | if isr.ehr_valid() { |
| 403 | regs.rng_icr().write(|w| { | ||
| 404 | w.set_ehr_valid(true); | ||
| 405 | }); | ||
| 388 | T::waker().wake(); | 406 | T::waker().wake(); |
| 389 | } else { | 407 | } else if isr.crngt_err() { |
| 408 | warn!("TRNG CRNGT error! Increase sample count to reduce likelihood"); | ||
| 409 | regs.rng_icr().write(|w| { | ||
| 410 | w.set_crngt_err(true); | ||
| 411 | }); | ||
| 412 | } else if isr.vn_err() { | ||
| 413 | warn!("TRNG Von-Neumann balancer error! Increase sample count to reduce likelihood"); | ||
| 414 | regs.rng_icr().write(|w| { | ||
| 415 | w.set_vn_err(true); | ||
| 416 | }); | ||
| 417 | } else if isr.autocorr_err() { | ||
| 390 | // 12.12.5. List of Registers | 418 | // 12.12.5. List of Registers |
| 391 | // ... | 419 | // ... |
| 392 | // TRNG: RNG_ISR Register | 420 | // TRNG: RNG_ISR Register |
| 393 | // ... | 421 | // ... |
| 394 | // AUTOCORR_ERR: 1 indicates Autocorrelation test failed four times in a row. | 422 | // AUTOCORR_ERR: 1 indicates Autocorrelation test failed four times in a row. |
| 395 | // When set, RNG ceases functioning until next reset | 423 | // When set, RNG ceases functioning until next reset |
| 396 | if isr.autocorr_err() { | 424 | warn!("TRNG Autocorrect error! Resetting TRNG. Increase sample count to reduce likelihood"); |
| 397 | warn!("TRNG Autocorrect error! Resetting TRNG"); | 425 | regs.trng_sw_reset().write(|w| { |
| 398 | regs.trng_sw_reset().write(|w| { | 426 | w.set_trng_sw_reset(true); |
| 399 | w.set_trng_sw_reset(true); | 427 | }); |
| 400 | }); | 428 | // Fixed delay is required after TRNG soft reset, this read is sufficient. |
| 401 | } | 429 | regs.trng_sw_reset().read(); |
| 430 | // Wake up to reinitialize and restart the TRNG. | ||
| 431 | T::waker().wake(); | ||
| 402 | } | 432 | } |
| 403 | } | 433 | } |
| 404 | } | 434 | } |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 946aa0399..b00b6a7ac 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -684,6 +684,8 @@ fn main() { | |||
| 684 | PeripheralRccKernelClock::Clock(clock) => clock_gen.gen_clock(p.name, clock), | 684 | PeripheralRccKernelClock::Clock(clock) => clock_gen.gen_clock(p.name, clock), |
| 685 | }; | 685 | }; |
| 686 | 686 | ||
| 687 | let bus_clock_frequency = clock_gen.gen_clock(p.name, &rcc.bus_clock); | ||
| 688 | |||
| 687 | // A refcount leak can result if the same field is shared by peripherals with different stop modes | 689 | // A refcount leak can result if the same field is shared by peripherals with different stop modes |
| 688 | // This condition should be checked in stm32-data | 690 | // This condition should be checked in stm32-data |
| 689 | let stop_mode = match rcc.stop_mode { | 691 | let stop_mode = match rcc.stop_mode { |
| @@ -697,6 +699,9 @@ fn main() { | |||
| 697 | fn frequency() -> crate::time::Hertz { | 699 | fn frequency() -> crate::time::Hertz { |
| 698 | #clock_frequency | 700 | #clock_frequency |
| 699 | } | 701 | } |
| 702 | fn bus_frequency() -> crate::time::Hertz { | ||
| 703 | #bus_clock_frequency | ||
| 704 | } | ||
| 700 | 705 | ||
| 701 | const RCC_INFO: crate::rcc::RccInfo = unsafe { | 706 | const RCC_INFO: crate::rcc::RccInfo = unsafe { |
| 702 | crate::rcc::RccInfo::new( | 707 | crate::rcc::RccInfo::new( |
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 91be53607..8ed102c1b 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs | |||
| @@ -143,7 +143,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 143 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); | 143 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); |
| 144 | 144 | ||
| 145 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); | 145 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); |
| 146 | info!("ADC frequency set to {}", frequency); | 146 | trace!("ADC frequency set to {}", frequency); |
| 147 | 147 | ||
| 148 | if frequency > MAX_ADC_CLK_FREQ { | 148 | if frequency > MAX_ADC_CLK_FREQ { |
| 149 | panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); | 149 | panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); |
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 321db7431..f46e87f38 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | #[cfg_attr(adc_v1, path = "v1.rs")] | 11 | #[cfg_attr(adc_v1, path = "v1.rs")] |
| 12 | #[cfg_attr(adc_l0, path = "v1.rs")] | 12 | #[cfg_attr(adc_l0, path = "v1.rs")] |
| 13 | #[cfg_attr(adc_v2, path = "v2.rs")] | 13 | #[cfg_attr(adc_v2, path = "v2.rs")] |
| 14 | #[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_u0), path = "v3.rs")] | 14 | #[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0), path = "v3.rs")] |
| 15 | #[cfg_attr(any(adc_v4, adc_u5), path = "v4.rs")] | 15 | #[cfg_attr(any(adc_v4, adc_u5), path = "v4.rs")] |
| 16 | #[cfg_attr(adc_g4, path = "g4.rs")] | 16 | #[cfg_attr(adc_g4, path = "g4.rs")] |
| 17 | #[cfg_attr(adc_c0, path = "c0.rs")] | 17 | #[cfg_attr(adc_c0, path = "c0.rs")] |
| @@ -108,6 +108,7 @@ pub(crate) fn blocking_delay_us(us: u32) { | |||
| 108 | adc_g0, | 108 | adc_g0, |
| 109 | adc_u0, | 109 | adc_u0, |
| 110 | adc_h5, | 110 | adc_h5, |
| 111 | adc_h7rs, | ||
| 111 | adc_u5, | 112 | adc_u5, |
| 112 | adc_c0 | 113 | adc_c0 |
| 113 | )))] | 114 | )))] |
| @@ -129,6 +130,7 @@ pub trait Instance: SealedInstance + crate::PeripheralType { | |||
| 129 | adc_g0, | 130 | adc_g0, |
| 130 | adc_u0, | 131 | adc_u0, |
| 131 | adc_h5, | 132 | adc_h5, |
| 133 | adc_h7rs, | ||
| 132 | adc_u5, | 134 | adc_u5, |
| 133 | adc_c0 | 135 | adc_c0 |
| 134 | ))] | 136 | ))] |
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 2de12d1d6..1c5ad16e9 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -19,7 +19,7 @@ impl<T: Instance> SealedAdcChannel<T> for VrefInt { | |||
| 19 | cfg_if! { | 19 | cfg_if! { |
| 20 | if #[cfg(adc_g0)] { | 20 | if #[cfg(adc_g0)] { |
| 21 | let val = 13; | 21 | let val = 13; |
| 22 | } else if #[cfg(adc_h5)] { | 22 | } else if #[cfg(any(adc_h5, adc_h7rs))] { |
| 23 | let val = 17; | 23 | let val = 17; |
| 24 | } else if #[cfg(adc_u0)] { | 24 | } else if #[cfg(adc_u0)] { |
| 25 | let val = 12; | 25 | let val = 12; |
| @@ -38,7 +38,7 @@ impl<T: Instance> SealedAdcChannel<T> for Temperature { | |||
| 38 | cfg_if! { | 38 | cfg_if! { |
| 39 | if #[cfg(adc_g0)] { | 39 | if #[cfg(adc_g0)] { |
| 40 | let val = 12; | 40 | let val = 12; |
| 41 | } else if #[cfg(adc_h5)] { | 41 | } else if #[cfg(any(adc_h5, adc_h7rs))] { |
| 42 | let val = 16; | 42 | let val = 16; |
| 43 | } else if #[cfg(adc_u0)] { | 43 | } else if #[cfg(adc_u0)] { |
| 44 | let val = 11; | 44 | let val = 11; |
| @@ -57,9 +57,9 @@ impl<T: Instance> SealedAdcChannel<T> for Vbat { | |||
| 57 | cfg_if! { | 57 | cfg_if! { |
| 58 | if #[cfg(adc_g0)] { | 58 | if #[cfg(adc_g0)] { |
| 59 | let val = 14; | 59 | let val = 14; |
| 60 | } else if #[cfg(adc_h5)] { | 60 | } else if #[cfg(any(adc_h5, adc_h7rs))] { |
| 61 | let val = 2; | 61 | let val = 2; |
| 62 | } else if #[cfg(adc_h5)] { | 62 | } else if #[cfg(any(adc_h5, adc_h7rs))] { |
| 63 | let val = 13; | 63 | let val = 13; |
| 64 | } else { | 64 | } else { |
| 65 | let val = 18; | 65 | let val = 18; |
| @@ -70,7 +70,7 @@ impl<T: Instance> SealedAdcChannel<T> for Vbat { | |||
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | cfg_if! { | 72 | cfg_if! { |
| 73 | if #[cfg(adc_h5)] { | 73 | if #[cfg(any(adc_h5, adc_h7rs))] { |
| 74 | pub struct VddCore; | 74 | pub struct VddCore; |
| 75 | impl<T: Instance> AdcChannel<T> for VddCore {} | 75 | impl<T: Instance> AdcChannel<T> for VddCore {} |
| 76 | impl<T: Instance> super::SealedAdcChannel<T> for VddCore { | 76 | impl<T: Instance> super::SealedAdcChannel<T> for VddCore { |
| @@ -171,7 +171,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 171 | T::regs().ccr().modify(|reg| { | 171 | T::regs().ccr().modify(|reg| { |
| 172 | reg.set_tsen(true); | 172 | reg.set_tsen(true); |
| 173 | }); | 173 | }); |
| 174 | } else if #[cfg(adc_h5)] { | 174 | } else if #[cfg(any(adc_h5, adc_h7rs))] { |
| 175 | T::common_regs().ccr().modify(|reg| { | 175 | T::common_regs().ccr().modify(|reg| { |
| 176 | reg.set_tsen(true); | 176 | reg.set_tsen(true); |
| 177 | }); | 177 | }); |
| @@ -191,7 +191,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 191 | T::regs().ccr().modify(|reg| { | 191 | T::regs().ccr().modify(|reg| { |
| 192 | reg.set_vbaten(true); | 192 | reg.set_vbaten(true); |
| 193 | }); | 193 | }); |
| 194 | } else if #[cfg(adc_h5)] { | 194 | } else if #[cfg(any(adc_h5, adc_h7rs))] { |
| 195 | T::common_regs().ccr().modify(|reg| { | 195 | T::common_regs().ccr().modify(|reg| { |
| 196 | reg.set_vbaten(true); | 196 | reg.set_vbaten(true); |
| 197 | }); | 197 | }); |
| @@ -414,7 +414,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 414 | fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { | 414 | fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { |
| 415 | // RM0492, RM0481, etc. | 415 | // RM0492, RM0481, etc. |
| 416 | // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." | 416 | // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." |
| 417 | #[cfg(adc_h5)] | 417 | #[cfg(any(adc_h5, adc_h7rs))] |
| 418 | if channel.channel() == 0 { | 418 | if channel.channel() == 0 { |
| 419 | T::regs().or().modify(|reg| reg.set_op0(true)); | 419 | T::regs().or().modify(|reg| reg.set_op0(true)); |
| 420 | } | 420 | } |
| @@ -447,7 +447,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 447 | 447 | ||
| 448 | // RM0492, RM0481, etc. | 448 | // RM0492, RM0481, etc. |
| 449 | // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." | 449 | // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." |
| 450 | #[cfg(adc_h5)] | 450 | #[cfg(any(adc_h5, adc_h7rs))] |
| 451 | if channel.channel() == 0 { | 451 | if channel.channel() == 0 { |
| 452 | T::regs().or().modify(|reg| reg.set_op0(false)); | 452 | T::regs().or().modify(|reg| reg.set_op0(false)); |
| 453 | } | 453 | } |
| @@ -475,7 +475,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 475 | if #[cfg(any(adc_g0, adc_u0))] { | 475 | if #[cfg(any(adc_g0, adc_u0))] { |
| 476 | // On G0 and U6 all channels use the same sampling time. | 476 | // On G0 and U6 all channels use the same sampling time. |
| 477 | T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); | 477 | T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); |
| 478 | } else if #[cfg(adc_h5)] { | 478 | } else if #[cfg(any(adc_h5, adc_h7rs))] { |
| 479 | match _ch { | 479 | match _ch { |
| 480 | 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), | 480 | 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), |
| 481 | _ => T::regs().smpr2().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), | 481 | _ => T::regs().smpr2().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), |
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 4d2e0f0df..e455b275c 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs | |||
| @@ -305,7 +305,7 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 305 | 305 | ||
| 306 | T::regs().cfgr2().modify(|reg| { | 306 | T::regs().cfgr2().modify(|reg| { |
| 307 | reg.set_rovse(enable); | 307 | reg.set_rovse(enable); |
| 308 | reg.set_osvr(samples); | 308 | reg.set_ovsr(samples); |
| 309 | reg.set_ovss(right_shift); | 309 | reg.set_ovss(right_shift); |
| 310 | }) | 310 | }) |
| 311 | } | 311 | } |
diff --git a/embassy-stm32/src/can/bxcan/registers.rs b/embassy-stm32/src/can/bxcan/registers.rs index c5467dfe8..c295b0f50 100644 --- a/embassy-stm32/src/can/bxcan/registers.rs +++ b/embassy-stm32/src/can/bxcan/registers.rs | |||
| @@ -299,9 +299,9 @@ impl Registers { | |||
| 299 | mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8)); | 299 | mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8)); |
| 300 | 300 | ||
| 301 | mb.tdlr() | 301 | mb.tdlr() |
| 302 | .write(|w| w.0 = u32::from_ne_bytes(unwrap!(frame.data()[0..4].try_into()))); | 302 | .write(|w| w.0 = u32::from_ne_bytes(unwrap!(frame.raw_data()[0..4].try_into()))); |
| 303 | mb.tdhr() | 303 | mb.tdhr() |
| 304 | .write(|w| w.0 = u32::from_ne_bytes(unwrap!(frame.data()[4..8].try_into()))); | 304 | .write(|w| w.0 = u32::from_ne_bytes(unwrap!(frame.raw_data()[4..8].try_into()))); |
| 305 | let id: IdReg = frame.id().into(); | 305 | let id: IdReg = frame.id().into(); |
| 306 | mb.tir().write(|w| { | 306 | mb.tir().write(|w| { |
| 307 | w.0 = id.0; | 307 | w.0 = id.0; |
diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 39c4112ad..4873ee444 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs | |||
| @@ -75,7 +75,7 @@ impl Registers { | |||
| 75 | let mailbox = self.tx_buffer_element(bufidx); | 75 | let mailbox = self.tx_buffer_element(bufidx); |
| 76 | mailbox.reset(); | 76 | mailbox.reset(); |
| 77 | put_tx_header(mailbox, header); | 77 | put_tx_header(mailbox, header); |
| 78 | put_tx_data(mailbox, &buffer[..header.len() as usize]); | 78 | put_tx_data(mailbox, buffer); |
| 79 | 79 | ||
| 80 | // Set <idx as Mailbox> as ready to transmit | 80 | // Set <idx as Mailbox> as ready to transmit |
| 81 | self.regs.txbar().modify(|w| w.set_ar(bufidx, true)); | 81 | self.regs.txbar().modify(|w| w.set_ar(bufidx, true)); |
| @@ -190,7 +190,7 @@ impl Registers { | |||
| 190 | DataLength::Fdcan(len) => len, | 190 | DataLength::Fdcan(len) => len, |
| 191 | DataLength::Classic(len) => len, | 191 | DataLength::Classic(len) => len, |
| 192 | }; | 192 | }; |
| 193 | if len as usize > ClassicData::MAX_DATA_LEN { | 193 | if len as usize > 8 { |
| 194 | return None; | 194 | return None; |
| 195 | } | 195 | } |
| 196 | 196 | ||
diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs index f621b8bd5..0fbab053b 100644 --- a/embassy-stm32/src/can/frame.rs +++ b/embassy-stm32/src/can/frame.rs | |||
| @@ -104,15 +104,13 @@ pub trait CanHeader: Sized { | |||
| 104 | #[derive(Debug, Copy, Clone)] | 104 | #[derive(Debug, Copy, Clone)] |
| 105 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 105 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 106 | pub struct ClassicData { | 106 | pub struct ClassicData { |
| 107 | pub(crate) bytes: [u8; Self::MAX_DATA_LEN], | 107 | pub(crate) bytes: [u8; 8], |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | impl ClassicData { | 110 | impl ClassicData { |
| 111 | pub(crate) const MAX_DATA_LEN: usize = 8; | ||
| 112 | /// Creates a data payload from a raw byte slice. | 111 | /// Creates a data payload from a raw byte slice. |
| 113 | /// | 112 | /// |
| 114 | /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or | 113 | /// Returns `FrameCreateError` if `data` is more than 8 bytes (which is the maximum). |
| 115 | /// cannot be represented with an FDCAN DLC. | ||
| 116 | pub fn new(data: &[u8]) -> Result<Self, FrameCreateError> { | 114 | pub fn new(data: &[u8]) -> Result<Self, FrameCreateError> { |
| 117 | if data.len() > 8 { | 115 | if data.len() > 8 { |
| 118 | return Err(FrameCreateError::InvalidDataLength); | 116 | return Err(FrameCreateError::InvalidDataLength); |
| @@ -211,12 +209,17 @@ impl Frame { | |||
| 211 | 209 | ||
| 212 | /// Get reference to data | 210 | /// Get reference to data |
| 213 | pub fn data(&self) -> &[u8] { | 211 | pub fn data(&self) -> &[u8] { |
| 214 | &self.data.raw() | 212 | &self.data.raw()[..self.can_header.len as usize] |
| 213 | } | ||
| 214 | |||
| 215 | /// Get reference to underlying 8-byte raw data buffer, some bytes on the tail might be undefined. | ||
| 216 | pub fn raw_data(&self) -> &[u8] { | ||
| 217 | self.data.raw() | ||
| 215 | } | 218 | } |
| 216 | 219 | ||
| 217 | /// Get mutable reference to data | 220 | /// Get mutable reference to data |
| 218 | pub fn data_mut(&mut self) -> &mut [u8] { | 221 | pub fn data_mut(&mut self) -> &mut [u8] { |
| 219 | self.data.raw_mut() | 222 | &mut self.data.raw_mut()[..self.can_header.len as usize] |
| 220 | } | 223 | } |
| 221 | 224 | ||
| 222 | /// Get priority of frame | 225 | /// Get priority of frame |
| @@ -260,7 +263,7 @@ impl embedded_can::Frame for Frame { | |||
| 260 | self.can_header.len as usize | 263 | self.can_header.len as usize |
| 261 | } | 264 | } |
| 262 | fn data(&self) -> &[u8] { | 265 | fn data(&self) -> &[u8] { |
| 263 | &self.data.raw() | 266 | &self.data() |
| 264 | } | 267 | } |
| 265 | } | 268 | } |
| 266 | 269 | ||
| @@ -405,12 +408,12 @@ impl FdFrame { | |||
| 405 | 408 | ||
| 406 | /// Get reference to data | 409 | /// Get reference to data |
| 407 | pub fn data(&self) -> &[u8] { | 410 | pub fn data(&self) -> &[u8] { |
| 408 | &self.data.raw() | 411 | &self.data.raw()[..self.can_header.len as usize] |
| 409 | } | 412 | } |
| 410 | 413 | ||
| 411 | /// Get mutable reference to data | 414 | /// Get mutable reference to data |
| 412 | pub fn data_mut(&mut self) -> &mut [u8] { | 415 | pub fn data_mut(&mut self) -> &mut [u8] { |
| 413 | self.data.raw_mut() | 416 | &mut self.data.raw_mut()[..self.can_header.len as usize] |
| 414 | } | 417 | } |
| 415 | } | 418 | } |
| 416 | 419 | ||
| @@ -448,7 +451,7 @@ impl embedded_can::Frame for FdFrame { | |||
| 448 | self.can_header.len as usize | 451 | self.can_header.len as usize |
| 449 | } | 452 | } |
| 450 | fn data(&self) -> &[u8] { | 453 | fn data(&self) -> &[u8] { |
| 451 | &self.data.raw() | 454 | &self.data() |
| 452 | } | 455 | } |
| 453 | } | 456 | } |
| 454 | 457 | ||
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index 82de4a89b..b368df6c3 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs | |||
| @@ -37,22 +37,12 @@ enum OpAmpDifferentialPair { | |||
| 37 | 37 | ||
| 38 | /// Speed | 38 | /// Speed |
| 39 | #[allow(missing_docs)] | 39 | #[allow(missing_docs)] |
| 40 | #[derive(Clone, Copy)] | 40 | #[derive(Clone, Copy, PartialEq)] |
| 41 | pub enum OpAmpSpeed { | 41 | pub enum OpAmpSpeed { |
| 42 | Normal, | 42 | Normal, |
| 43 | HighSpeed, | 43 | HighSpeed, |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | #[cfg(opamp_g4)] | ||
| 47 | impl From<OpAmpSpeed> for crate::pac::opamp::vals::Opahsm { | ||
| 48 | fn from(v: OpAmpSpeed) -> Self { | ||
| 49 | match v { | ||
| 50 | OpAmpSpeed::Normal => crate::pac::opamp::vals::Opahsm::NORMAL, | ||
| 51 | OpAmpSpeed::HighSpeed => crate::pac::opamp::vals::Opahsm::HIGH_SPEED, | ||
| 52 | } | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | /// OpAmp external outputs, wired to a GPIO pad. | 46 | /// OpAmp external outputs, wired to a GPIO pad. |
| 57 | /// | 47 | /// |
| 58 | /// This struct can also be used as an ADC input. | 48 | /// This struct can also be used as an ADC input. |
| @@ -80,7 +70,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 80 | pub fn new(opamp: Peri<'d, T>, #[cfg(opamp_g4)] speed: OpAmpSpeed) -> Self { | 70 | pub fn new(opamp: Peri<'d, T>, #[cfg(opamp_g4)] speed: OpAmpSpeed) -> Self { |
| 81 | #[cfg(opamp_g4)] | 71 | #[cfg(opamp_g4)] |
| 82 | T::regs().csr().modify(|w| { | 72 | T::regs().csr().modify(|w| { |
| 83 | w.set_opahsm(speed.into()); | 73 | w.set_opahsm(speed == OpAmpSpeed::HighSpeed); |
| 84 | }); | 74 | }); |
| 85 | 75 | ||
| 86 | Self { _inner: opamp } | 76 | Self { _inner: opamp } |
| @@ -113,7 +103,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 113 | w.set_vp_sel(VpSel::from_bits(in_pin.channel())); | 103 | w.set_vp_sel(VpSel::from_bits(in_pin.channel())); |
| 114 | w.set_vm_sel(vm_sel); | 104 | w.set_vm_sel(vm_sel); |
| 115 | #[cfg(opamp_g4)] | 105 | #[cfg(opamp_g4)] |
| 116 | w.set_opaintoen(Opaintoen::OUTPUT_PIN); | 106 | w.set_opaintoen(false); |
| 117 | w.set_opampen(true); | 107 | w.set_opampen(true); |
| 118 | }); | 108 | }); |
| 119 | 109 | ||
| @@ -166,7 +156,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 166 | w.set_vm_sel(vm_sel); | 156 | w.set_vm_sel(vm_sel); |
| 167 | w.set_pga_gain(pga_gain); | 157 | w.set_pga_gain(pga_gain); |
| 168 | #[cfg(opamp_g4)] | 158 | #[cfg(opamp_g4)] |
| 169 | w.set_opaintoen(Opaintoen::OUTPUT_PIN); | 159 | w.set_opaintoen(false); |
| 170 | w.set_opampen(true); | 160 | w.set_opampen(true); |
| 171 | }); | 161 | }); |
| 172 | 162 | ||
| @@ -189,7 +179,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 189 | 179 | ||
| 190 | w.set_vm_sel(VmSel::OUTPUT); | 180 | w.set_vm_sel(VmSel::OUTPUT); |
| 191 | w.set_vp_sel(VpSel::DAC3_CH1); | 181 | w.set_vp_sel(VpSel::DAC3_CH1); |
| 192 | w.set_opaintoen(Opaintoen::OUTPUT_PIN); | 182 | w.set_opaintoen(false); |
| 193 | w.set_opampen(true); | 183 | w.set_opampen(true); |
| 194 | }); | 184 | }); |
| 195 | 185 | ||
| @@ -215,7 +205,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 215 | w.set_vp_sel(VpSel::from_bits(pin.channel())); | 205 | w.set_vp_sel(VpSel::from_bits(pin.channel())); |
| 216 | w.set_vm_sel(VmSel::OUTPUT); | 206 | w.set_vm_sel(VmSel::OUTPUT); |
| 217 | #[cfg(opamp_g4)] | 207 | #[cfg(opamp_g4)] |
| 218 | w.set_opaintoen(Opaintoen::ADCCHANNEL); | 208 | w.set_opaintoen(true); |
| 219 | w.set_opampen(true); | 209 | w.set_opampen(true); |
| 220 | }); | 210 | }); |
| 221 | 211 | ||
| @@ -251,7 +241,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 251 | w.set_vp_sel(VpSel::from_bits(pin.channel())); | 241 | w.set_vp_sel(VpSel::from_bits(pin.channel())); |
| 252 | w.set_vm_sel(VmSel::OUTPUT); | 242 | w.set_vm_sel(VmSel::OUTPUT); |
| 253 | w.set_pga_gain(pga_gain); | 243 | w.set_pga_gain(pga_gain); |
| 254 | w.set_opaintoen(Opaintoen::ADCCHANNEL); | 244 | w.set_opaintoen(true); |
| 255 | w.set_opampen(true); | 245 | w.set_opampen(true); |
| 256 | }); | 246 | }); |
| 257 | 247 | ||
| @@ -278,7 +268,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 278 | use crate::pac::opamp::vals::*; | 268 | use crate::pac::opamp::vals::*; |
| 279 | w.set_vp_sel(VpSel::DAC3_CH1); // Actually DAC3_CHx | 269 | w.set_vp_sel(VpSel::DAC3_CH1); // Actually DAC3_CHx |
| 280 | w.set_vm_sel(VmSel::from_bits(m_pin.channel())); | 270 | w.set_vm_sel(VmSel::from_bits(m_pin.channel())); |
| 281 | w.set_opaintoen(Opaintoen::ADCCHANNEL); | 271 | w.set_opaintoen(true); |
| 282 | w.set_opampen(true); | 272 | w.set_opampen(true); |
| 283 | }); | 273 | }); |
| 284 | 274 | ||
| @@ -308,7 +298,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 308 | use crate::pac::opamp::vals::*; | 298 | use crate::pac::opamp::vals::*; |
| 309 | w.set_vp_sel(VpSel::DAC3_CH1); // Actually DAC3_CHx | 299 | w.set_vp_sel(VpSel::DAC3_CH1); // Actually DAC3_CHx |
| 310 | w.set_vm_sel(VmSel::from_bits(m_pin.channel())); | 300 | w.set_vm_sel(VmSel::from_bits(m_pin.channel())); |
| 311 | w.set_opaintoen(Opaintoen::OUTPUT_PIN); | 301 | w.set_opaintoen(false); |
| 312 | w.set_opampen(true); | 302 | w.set_opampen(true); |
| 313 | }); | 303 | }); |
| 314 | 304 | ||
| @@ -340,7 +330,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 340 | use crate::pac::opamp::vals::*; | 330 | use crate::pac::opamp::vals::*; |
| 341 | w.set_vp_sel(VpSel::from_bits(p_pin.channel())); | 331 | w.set_vp_sel(VpSel::from_bits(p_pin.channel())); |
| 342 | w.set_vm_sel(VmSel::from_bits(m_pin.channel())); | 332 | w.set_vm_sel(VmSel::from_bits(m_pin.channel())); |
| 343 | w.set_opaintoen(Opaintoen::OUTPUT_PIN); | 333 | w.set_opaintoen(false); |
| 344 | w.set_opampen(true); | 334 | w.set_opampen(true); |
| 345 | }); | 335 | }); |
| 346 | 336 | ||
| @@ -369,7 +359,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 369 | use crate::pac::opamp::vals::*; | 359 | use crate::pac::opamp::vals::*; |
| 370 | w.set_vp_sel(VpSel::from_bits(p_pin.channel())); | 360 | w.set_vp_sel(VpSel::from_bits(p_pin.channel())); |
| 371 | w.set_vm_sel(VmSel::from_bits(m_pin.channel())); | 361 | w.set_vm_sel(VmSel::from_bits(m_pin.channel())); |
| 372 | w.set_opaintoen(Opaintoen::ADCCHANNEL); | 362 | w.set_opaintoen(true); |
| 373 | w.set_opampen(true); | 363 | w.set_opampen(true); |
| 374 | }); | 364 | }); |
| 375 | 365 | ||
| @@ -389,17 +379,14 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 389 | T::regs().csr().modify(|w| { | 379 | T::regs().csr().modify(|w| { |
| 390 | w.set_opampen(true); | 380 | w.set_opampen(true); |
| 391 | w.set_calon(true); | 381 | w.set_calon(true); |
| 392 | w.set_usertrim(Usertrim::USER); | 382 | w.set_usertrim(true); |
| 393 | }); | 383 | }); |
| 394 | 384 | ||
| 395 | match T::regs().csr().read().opahsm() { | 385 | if T::regs().csr().read().opahsm() { |
| 396 | Opahsm::NORMAL => { | 386 | self.calibrate_differential_pair(OpAmpDifferentialPair::P); |
| 397 | self.calibrate_differential_pair(OpAmpDifferentialPair::P); | 387 | } else { |
| 398 | self.calibrate_differential_pair(OpAmpDifferentialPair::N); | 388 | self.calibrate_differential_pair(OpAmpDifferentialPair::P); |
| 399 | } | 389 | self.calibrate_differential_pair(OpAmpDifferentialPair::N); |
| 400 | Opahsm::HIGH_SPEED => { | ||
| 401 | self.calibrate_differential_pair(OpAmpDifferentialPair::P); | ||
| 402 | } | ||
| 403 | } | 390 | } |
| 404 | 391 | ||
| 405 | T::regs().csr().modify(|w| { | 392 | T::regs().csr().modify(|w| { |
| @@ -435,11 +422,13 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 435 | 422 | ||
| 436 | T::regs().csr().modify(|w| match pair { | 423 | T::regs().csr().modify(|w| match pair { |
| 437 | OpAmpDifferentialPair::P => { | 424 | OpAmpDifferentialPair::P => { |
| 438 | defmt::info!("p calibration. offset: {}", mid); | 425 | #[cfg(feature = "defmt")] |
| 426 | defmt::debug!("opamp p calibration. offset: {}", mid); | ||
| 439 | w.set_trimoffsetp(mid); | 427 | w.set_trimoffsetp(mid); |
| 440 | } | 428 | } |
| 441 | OpAmpDifferentialPair::N => { | 429 | OpAmpDifferentialPair::N => { |
| 442 | defmt::info!("n calibration. offset: {}", mid); | 430 | #[cfg(feature = "defmt")] |
| 431 | defmt::debug!("opamp n calibration. offset: {}", mid); | ||
| 443 | w.set_trimoffsetn(mid); | 432 | w.set_trimoffsetn(mid); |
| 444 | } | 433 | } |
| 445 | }); | 434 | }); |
| @@ -448,7 +437,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { | |||
| 448 | // (with a maximum stabilization time remaining below 2 ms in any case) -- RM0440 25.3.7 | 437 | // (with a maximum stabilization time remaining below 2 ms in any case) -- RM0440 25.3.7 |
| 449 | blocking_delay_ms(2); | 438 | blocking_delay_ms(2); |
| 450 | 439 | ||
| 451 | if T::regs().csr().read().outcal() == Outcal::LOW { | 440 | if !T::regs().csr().read().calout() { |
| 452 | if mid == 0 { | 441 | if mid == 0 { |
| 453 | break; | 442 | break; |
| 454 | } | 443 | } |
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 4f43d3748..150daa4a7 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -97,6 +97,8 @@ pub(crate) unsafe fn get_freqs() -> &'static Clocks { | |||
| 97 | 97 | ||
| 98 | pub(crate) trait SealedRccPeripheral { | 98 | pub(crate) trait SealedRccPeripheral { |
| 99 | fn frequency() -> Hertz; | 99 | fn frequency() -> Hertz; |
| 100 | #[allow(dead_code)] | ||
| 101 | fn bus_frequency() -> Hertz; | ||
| 100 | const RCC_INFO: RccInfo; | 102 | const RCC_INFO: RccInfo; |
| 101 | } | 103 | } |
| 102 | 104 | ||
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 6578aa1aa..9e2ba093a 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs | |||
| @@ -284,6 +284,10 @@ impl<'d, M: PeriMode> Spi<'d, M> { | |||
| 284 | 284 | ||
| 285 | #[cfg(any(spi_v3, spi_v4, spi_v5))] | 285 | #[cfg(any(spi_v3, spi_v4, spi_v5))] |
| 286 | { | 286 | { |
| 287 | self.info.regs.cr1().modify(|w| { | ||
| 288 | w.set_spe(false); | ||
| 289 | }); | ||
| 290 | |||
| 287 | self.info.regs.cfg2().modify(|w| { | 291 | self.info.regs.cfg2().modify(|w| { |
| 288 | w.set_cpha(cpha); | 292 | w.set_cpha(cpha); |
| 289 | w.set_cpol(cpol); | 293 | w.set_cpol(cpol); |
| @@ -292,6 +296,10 @@ impl<'d, M: PeriMode> Spi<'d, M> { | |||
| 292 | self.info.regs.cfg1().modify(|w| { | 296 | self.info.regs.cfg1().modify(|w| { |
| 293 | w.set_mbr(br); | 297 | w.set_mbr(br); |
| 294 | }); | 298 | }); |
| 299 | |||
| 300 | self.info.regs.cr1().modify(|w| { | ||
| 301 | w.set_spe(true); | ||
| 302 | }); | ||
| 295 | } | 303 | } |
| 296 | Ok(()) | 304 | Ok(()) |
| 297 | } | 305 | } |
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index f543bafab..8eec6c0c7 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs | |||
| @@ -240,11 +240,11 @@ fn compute_dead_time_value(value: u16) -> (Ckd, u8) { | |||
| 240 | let (these_bits, result) = if target < 128 { | 240 | let (these_bits, result) = if target < 128 { |
| 241 | (target as u8, target) | 241 | (target as u8, target) |
| 242 | } else if target < 255 { | 242 | } else if target < 255 { |
| 243 | (64 + (target / 2) as u8, (target - target % 2)) | 243 | ((64 + (target / 2) as u8) | 128, (target - target % 2)) |
| 244 | } else if target < 508 { | 244 | } else if target < 508 { |
| 245 | (32 + (target / 8) as u8, (target - target % 8)) | 245 | ((32 + (target / 8) as u8) | 192, (target - target % 8)) |
| 246 | } else if target < 1008 { | 246 | } else if target < 1008 { |
| 247 | (32 + (target / 16) as u8, (target - target % 16)) | 247 | ((32 + (target / 16) as u8) | 224, (target - target % 16)) |
| 248 | } else { | 248 | } else { |
| 249 | (u8::MAX, 1008) | 249 | (u8::MAX, 1008) |
| 250 | }; | 250 | }; |
| @@ -300,7 +300,7 @@ mod tests { | |||
| 300 | TestRun { | 300 | TestRun { |
| 301 | value: 400, | 301 | value: 400, |
| 302 | ckd: Ckd::DIV1, | 302 | ckd: Ckd::DIV1, |
| 303 | bits: 32 + (400u16 / 8) as u8, | 303 | bits: 210, |
| 304 | }, | 304 | }, |
| 305 | TestRun { | 305 | TestRun { |
| 306 | value: 600, | 306 | value: 600, |
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 2aca3d929..590d1a427 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs | |||
| @@ -549,7 +549,7 @@ foreach_interrupt!( | |||
| 549 | ); | 549 | ); |
| 550 | 550 | ||
| 551 | fn calculate_trdt<T: Instance>(speed: Dspd) -> u8 { | 551 | fn calculate_trdt<T: Instance>(speed: Dspd) -> u8 { |
| 552 | let ahb_freq = T::frequency().0; | 552 | let ahb_freq = T::bus_frequency().0; |
| 553 | match speed { | 553 | match speed { |
| 554 | Dspd::HIGH_SPEED => { | 554 | Dspd::HIGH_SPEED => { |
| 555 | // From RM0431 (F72xx), RM0090 (F429), RM0390 (F446) | 555 | // From RM0431 (F72xx), RM0090 (F429), RM0390 (F446) |
diff --git a/embassy-sync/README.md b/embassy-sync/README.md index 6871bcabc..91c59884f 100644 --- a/embassy-sync/README.md +++ b/embassy-sync/README.md | |||
| @@ -12,7 +12,7 @@ Synchronization primitives and data structures with async support: | |||
| 12 | - [`Mutex`](mutex::Mutex) - Mutex for synchronizing state between asynchronous tasks. | 12 | - [`Mutex`](mutex::Mutex) - Mutex for synchronizing state between asynchronous tasks. |
| 13 | - [`Pipe`](pipe::Pipe) - Byte stream implementing `embedded_io` traits. | 13 | - [`Pipe`](pipe::Pipe) - Byte stream implementing `embedded_io` traits. |
| 14 | - [`WakerRegistration`](waitqueue::WakerRegistration) - Utility to register and wake a `Waker`. | 14 | - [`WakerRegistration`](waitqueue::WakerRegistration) - Utility to register and wake a `Waker`. |
| 15 | - [`AtomicWaker`](waitqueue::AtomicWaker) - A variant of `WakerRegistration` accessible using a non-mut API. | 15 | - [`AtomicWaker`](waitqueue::AtomicWaker) - Utility to register and wake a `Waker` from interrupt context. |
| 16 | - [`MultiWakerRegistration`](waitqueue::MultiWakerRegistration) - Utility registering and waking multiple `Waker`'s. | 16 | - [`MultiWakerRegistration`](waitqueue::MultiWakerRegistration) - Utility registering and waking multiple `Waker`'s. |
| 17 | - [`LazyLock`](lazy_lock::LazyLock) - A value which is initialized on the first access | 17 | - [`LazyLock`](lazy_lock::LazyLock) - A value which is initialized on the first access |
| 18 | 18 | ||
diff --git a/embassy-sync/src/waitqueue/atomic_waker.rs b/embassy-sync/src/waitqueue/atomic_waker.rs index 231902c5a..5a9910e7f 100644 --- a/embassy-sync/src/waitqueue/atomic_waker.rs +++ b/embassy-sync/src/waitqueue/atomic_waker.rs | |||
| @@ -5,6 +5,9 @@ use crate::blocking_mutex::raw::{CriticalSectionRawMutex, RawMutex}; | |||
| 5 | use crate::blocking_mutex::Mutex; | 5 | use crate::blocking_mutex::Mutex; |
| 6 | 6 | ||
| 7 | /// Utility struct to register and wake a waker. | 7 | /// Utility struct to register and wake a waker. |
| 8 | /// If a waker is registered, registering another waker will replace the previous one without waking it. | ||
| 9 | /// Intended to wake a task from an interrupt. Therefore, it is generally not expected, | ||
| 10 | /// that multiple tasks register try to register a waker simultaneously. | ||
| 8 | pub struct GenericAtomicWaker<M: RawMutex> { | 11 | pub struct GenericAtomicWaker<M: RawMutex> { |
| 9 | waker: Mutex<M, Cell<Option<Waker>>>, | 12 | waker: Mutex<M, Cell<Option<Waker>>>, |
| 10 | } | 13 | } |
diff --git a/embassy-sync/src/waitqueue/atomic_waker_turbo.rs b/embassy-sync/src/waitqueue/atomic_waker_turbo.rs index 5c6a96ec8..c06b83056 100644 --- a/embassy-sync/src/waitqueue/atomic_waker_turbo.rs +++ b/embassy-sync/src/waitqueue/atomic_waker_turbo.rs | |||
| @@ -4,6 +4,9 @@ use core::sync::atomic::{AtomicPtr, Ordering}; | |||
| 4 | use core::task::Waker; | 4 | use core::task::Waker; |
| 5 | 5 | ||
| 6 | /// Utility struct to register and wake a waker. | 6 | /// Utility struct to register and wake a waker. |
| 7 | /// If a waker is registered, registering another waker will replace the previous one without waking it. | ||
| 8 | /// The intended use case is to wake tasks from interrupts. Therefore, it is generally not expected, | ||
| 9 | /// that multiple tasks register try to register a waker simultaneously. | ||
| 7 | pub struct AtomicWaker { | 10 | pub struct AtomicWaker { |
| 8 | waker: AtomicPtr<()>, | 11 | waker: AtomicPtr<()>, |
| 9 | } | 12 | } |
diff --git a/embassy-sync/src/waitqueue/multi_waker.rs b/embassy-sync/src/waitqueue/multi_waker.rs index 0e520bf40..0384d6bed 100644 --- a/embassy-sync/src/waitqueue/multi_waker.rs +++ b/embassy-sync/src/waitqueue/multi_waker.rs | |||
| @@ -3,6 +3,8 @@ use core::task::Waker; | |||
| 3 | use heapless::Vec; | 3 | use heapless::Vec; |
| 4 | 4 | ||
| 5 | /// Utility struct to register and wake multiple wakers. | 5 | /// Utility struct to register and wake multiple wakers. |
| 6 | /// Queue of wakers with a maximum length of `N`. | ||
| 7 | /// Intended for waking multiple tasks. | ||
| 6 | pub struct MultiWakerRegistration<const N: usize> { | 8 | pub struct MultiWakerRegistration<const N: usize> { |
| 7 | wakers: Vec<Waker, N>, | 9 | wakers: Vec<Waker, N>, |
| 8 | } | 10 | } |
diff --git a/embassy-sync/src/waitqueue/waker_registration.rs b/embassy-sync/src/waitqueue/waker_registration.rs index 9b666e7c4..7f24f8fb6 100644 --- a/embassy-sync/src/waitqueue/waker_registration.rs +++ b/embassy-sync/src/waitqueue/waker_registration.rs | |||
| @@ -2,6 +2,10 @@ use core::mem; | |||
| 2 | use core::task::Waker; | 2 | use core::task::Waker; |
| 3 | 3 | ||
| 4 | /// Utility struct to register and wake a waker. | 4 | /// Utility struct to register and wake a waker. |
| 5 | /// If a waker is registered, registering another waker will replace the previous one. | ||
| 6 | /// The previous waker will be woken in this case, giving it a chance to reregister itself. | ||
| 7 | /// Although it is possible to wake multiple tasks this way, | ||
| 8 | /// this will cause them to wake each other in a loop registering themselves. | ||
| 5 | #[derive(Debug, Default)] | 9 | #[derive(Debug, Default)] |
| 6 | pub struct WakerRegistration { | 10 | pub struct WakerRegistration { |
| 7 | waker: Option<Waker>, | 11 | waker: Option<Waker>, |
diff --git a/embassy-time-driver/Cargo.toml b/embassy-time-driver/Cargo.toml index b709cafc1..16213cb75 100644 --- a/embassy-time-driver/Cargo.toml +++ b/embassy-time-driver/Cargo.toml | |||
| @@ -226,6 +226,8 @@ tick-hz-128_000_000 = [] | |||
| 226 | tick-hz-130_000_000 = [] | 226 | tick-hz-130_000_000 = [] |
| 227 | ## 131.072MHz Tick Rate | 227 | ## 131.072MHz Tick Rate |
| 228 | tick-hz-131_072_000 = [] | 228 | tick-hz-131_072_000 = [] |
| 229 | ## 133.0MHz Tick Rate | ||
| 230 | tick-hz-133_000_000 = [] | ||
| 229 | ## 140.0MHz Tick Rate | 231 | ## 140.0MHz Tick Rate |
| 230 | tick-hz-140_000_000 = [] | 232 | tick-hz-140_000_000 = [] |
| 231 | ## 144.0MHz Tick Rate | 233 | ## 144.0MHz Tick Rate |
diff --git a/embassy-time-driver/gen_tick.py b/embassy-time-driver/gen_tick.py index af194c31f..080434457 100644 --- a/embassy-time-driver/gen_tick.py +++ b/embassy-time-driver/gen_tick.py | |||
| @@ -22,6 +22,7 @@ for i in range(1, 30): | |||
| 22 | ticks.append(10 * i * 1_000_000) | 22 | ticks.append(10 * i * 1_000_000) |
| 23 | for i in range(15, 50): | 23 | for i in range(15, 50): |
| 24 | ticks.append(20 * i * 1_000_000) | 24 | ticks.append(20 * i * 1_000_000) |
| 25 | ticks.append(133 * 1_000_000) | ||
| 25 | 26 | ||
| 26 | seen = set() | 27 | seen = set() |
| 27 | ticks = sorted([x for x in ticks if not (x in seen or seen.add(x))]) | 28 | ticks = sorted([x for x in ticks if not (x in seen or seen.add(x))]) |
diff --git a/embassy-time-driver/src/tick.rs b/embassy-time-driver/src/tick.rs index 916ae9498..5059e1628 100644 --- a/embassy-time-driver/src/tick.rs +++ b/embassy-time-driver/src/tick.rs | |||
| @@ -182,6 +182,8 @@ pub const TICK_HZ: u64 = 128_000_000; | |||
| 182 | pub const TICK_HZ: u64 = 130_000_000; | 182 | pub const TICK_HZ: u64 = 130_000_000; |
| 183 | #[cfg(feature = "tick-hz-131_072_000")] | 183 | #[cfg(feature = "tick-hz-131_072_000")] |
| 184 | pub const TICK_HZ: u64 = 131_072_000; | 184 | pub const TICK_HZ: u64 = 131_072_000; |
| 185 | #[cfg(feature = "tick-hz-133_000_000")] | ||
| 186 | pub const TICK_HZ: u64 = 133_000_000; | ||
| 185 | #[cfg(feature = "tick-hz-140_000_000")] | 187 | #[cfg(feature = "tick-hz-140_000_000")] |
| 186 | pub const TICK_HZ: u64 = 140_000_000; | 188 | pub const TICK_HZ: u64 = 140_000_000; |
| 187 | #[cfg(feature = "tick-hz-144_000_000")] | 189 | #[cfg(feature = "tick-hz-144_000_000")] |
| @@ -410,6 +412,7 @@ pub const TICK_HZ: u64 = 5_242_880_000; | |||
| 410 | feature = "tick-hz-128_000_000", | 412 | feature = "tick-hz-128_000_000", |
| 411 | feature = "tick-hz-130_000_000", | 413 | feature = "tick-hz-130_000_000", |
| 412 | feature = "tick-hz-131_072_000", | 414 | feature = "tick-hz-131_072_000", |
| 415 | feature = "tick-hz-133_000_000", | ||
| 413 | feature = "tick-hz-140_000_000", | 416 | feature = "tick-hz-140_000_000", |
| 414 | feature = "tick-hz-144_000_000", | 417 | feature = "tick-hz-144_000_000", |
| 415 | feature = "tick-hz-150_000_000", | 418 | feature = "tick-hz-150_000_000", |
diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 80a39dbf5..dc144ec3c 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml | |||
| @@ -274,6 +274,8 @@ tick-hz-128_000_000 = ["embassy-time-driver/tick-hz-128_000_000"] | |||
| 274 | tick-hz-130_000_000 = ["embassy-time-driver/tick-hz-130_000_000"] | 274 | tick-hz-130_000_000 = ["embassy-time-driver/tick-hz-130_000_000"] |
| 275 | ## 131.072MHz Tick Rate | 275 | ## 131.072MHz Tick Rate |
| 276 | tick-hz-131_072_000 = ["embassy-time-driver/tick-hz-131_072_000"] | 276 | tick-hz-131_072_000 = ["embassy-time-driver/tick-hz-131_072_000"] |
| 277 | ## 133.0MHz Tick Rate | ||
| 278 | tick-hz-133_000_000 = ["embassy-time-driver/tick-hz-133_000_000"] | ||
| 277 | ## 140.0MHz Tick Rate | 279 | ## 140.0MHz Tick Rate |
| 278 | tick-hz-140_000_000 = ["embassy-time-driver/tick-hz-140_000_000"] | 280 | tick-hz-140_000_000 = ["embassy-time-driver/tick-hz-140_000_000"] |
| 279 | ## 144.0MHz Tick Rate | 281 | ## 144.0MHz Tick Rate |
diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index 34e5762d2..d1162eadd 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | use core::future::{poll_fn, Future}; | 1 | use core::future::{poll_fn, Future}; |
| 2 | use core::pin::{pin, Pin}; | 2 | use core::pin::Pin; |
| 3 | use core::task::{Context, Poll}; | 3 | use core::task::{Context, Poll}; |
| 4 | 4 | ||
| 5 | use futures_util::future::{select, Either}; | ||
| 6 | use futures_util::stream::FusedStream; | 5 | use futures_util::stream::FusedStream; |
| 7 | use futures_util::Stream; | 6 | use futures_util::Stream; |
| 8 | 7 | ||
| @@ -17,11 +16,10 @@ pub struct TimeoutError; | |||
| 17 | /// | 16 | /// |
| 18 | /// If the future completes before the timeout, its output is returned. Otherwise, on timeout, | 17 | /// If the future completes before the timeout, its output is returned. Otherwise, on timeout, |
| 19 | /// work on the future is stopped (`poll` is no longer called), the future is dropped and `Err(TimeoutError)` is returned. | 18 | /// work on the future is stopped (`poll` is no longer called), the future is dropped and `Err(TimeoutError)` is returned. |
| 20 | pub async fn with_timeout<F: Future>(timeout: Duration, fut: F) -> Result<F::Output, TimeoutError> { | 19 | pub fn with_timeout<F: Future>(timeout: Duration, fut: F) -> TimeoutFuture<F> { |
| 21 | let timeout_fut = Timer::after(timeout); | 20 | TimeoutFuture { |
| 22 | match select(pin!(fut), timeout_fut).await { | 21 | timer: Timer::after(timeout), |
| 23 | Either::Left((r, _)) => Ok(r), | 22 | fut, |
| 24 | Either::Right(_) => Err(TimeoutError), | ||
| 25 | } | 23 | } |
| 26 | } | 24 | } |
| 27 | 25 | ||
| @@ -29,16 +27,15 @@ pub async fn with_timeout<F: Future>(timeout: Duration, fut: F) -> Result<F::Out | |||
| 29 | /// | 27 | /// |
| 30 | /// If the future completes before the deadline, its output is returned. Otherwise, on timeout, | 28 | /// If the future completes before the deadline, its output is returned. Otherwise, on timeout, |
| 31 | /// work on the future is stopped (`poll` is no longer called), the future is dropped and `Err(TimeoutError)` is returned. | 29 | /// work on the future is stopped (`poll` is no longer called), the future is dropped and `Err(TimeoutError)` is returned. |
| 32 | pub async fn with_deadline<F: Future>(at: Instant, fut: F) -> Result<F::Output, TimeoutError> { | 30 | pub fn with_deadline<F: Future>(at: Instant, fut: F) -> TimeoutFuture<F> { |
| 33 | let timeout_fut = Timer::at(at); | 31 | TimeoutFuture { |
| 34 | match select(pin!(fut), timeout_fut).await { | 32 | timer: Timer::at(at), |
| 35 | Either::Left((r, _)) => Ok(r), | 33 | fut, |
| 36 | Either::Right(_) => Err(TimeoutError), | ||
| 37 | } | 34 | } |
| 38 | } | 35 | } |
| 39 | 36 | ||
| 40 | /// Provides functions to run a given future with a timeout or a deadline. | 37 | /// Provides functions to run a given future with a timeout or a deadline. |
| 41 | pub trait WithTimeout { | 38 | pub trait WithTimeout: Sized { |
| 42 | /// Output type of the future. | 39 | /// Output type of the future. |
| 43 | type Output; | 40 | type Output; |
| 44 | 41 | ||
| @@ -46,24 +43,50 @@ pub trait WithTimeout { | |||
| 46 | /// | 43 | /// |
| 47 | /// If the future completes before the timeout, its output is returned. Otherwise, on timeout, | 44 | /// If the future completes before the timeout, its output is returned. Otherwise, on timeout, |
| 48 | /// work on the future is stopped (`poll` is no longer called), the future is dropped and `Err(TimeoutError)` is returned. | 45 | /// work on the future is stopped (`poll` is no longer called), the future is dropped and `Err(TimeoutError)` is returned. |
| 49 | async fn with_timeout(self, timeout: Duration) -> Result<Self::Output, TimeoutError>; | 46 | fn with_timeout(self, timeout: Duration) -> TimeoutFuture<Self>; |
| 50 | 47 | ||
| 51 | /// Runs a given future with a deadline time. | 48 | /// Runs a given future with a deadline time. |
| 52 | /// | 49 | /// |
| 53 | /// If the future completes before the deadline, its output is returned. Otherwise, on timeout, | 50 | /// If the future completes before the deadline, its output is returned. Otherwise, on timeout, |
| 54 | /// work on the future is stopped (`poll` is no longer called), the future is dropped and `Err(TimeoutError)` is returned. | 51 | /// work on the future is stopped (`poll` is no longer called), the future is dropped and `Err(TimeoutError)` is returned. |
| 55 | async fn with_deadline(self, at: Instant) -> Result<Self::Output, TimeoutError>; | 52 | fn with_deadline(self, at: Instant) -> TimeoutFuture<Self>; |
| 56 | } | 53 | } |
| 57 | 54 | ||
| 58 | impl<F: Future> WithTimeout for F { | 55 | impl<F: Future> WithTimeout for F { |
| 59 | type Output = F::Output; | 56 | type Output = F::Output; |
| 60 | 57 | ||
| 61 | async fn with_timeout(self, timeout: Duration) -> Result<Self::Output, TimeoutError> { | 58 | fn with_timeout(self, timeout: Duration) -> TimeoutFuture<Self> { |
| 62 | with_timeout(timeout, self).await | 59 | with_timeout(timeout, self) |
| 63 | } | 60 | } |
| 64 | 61 | ||
| 65 | async fn with_deadline(self, at: Instant) -> Result<Self::Output, TimeoutError> { | 62 | fn with_deadline(self, at: Instant) -> TimeoutFuture<Self> { |
| 66 | with_deadline(at, self).await | 63 | with_deadline(at, self) |
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | /// Future for the [`with_timeout`] and [`with_deadline`] functions. | ||
| 68 | #[must_use = "futures do nothing unless you `.await` or poll them"] | ||
| 69 | pub struct TimeoutFuture<F> { | ||
| 70 | timer: Timer, | ||
| 71 | fut: F, | ||
| 72 | } | ||
| 73 | |||
| 74 | impl<F: Unpin> Unpin for TimeoutFuture<F> {} | ||
| 75 | |||
| 76 | impl<F: Future> Future for TimeoutFuture<F> { | ||
| 77 | type Output = Result<F::Output, TimeoutError>; | ||
| 78 | |||
| 79 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
| 80 | let this = unsafe { self.get_unchecked_mut() }; | ||
| 81 | let fut = unsafe { Pin::new_unchecked(&mut this.fut) }; | ||
| 82 | let timer = unsafe { Pin::new_unchecked(&mut this.timer) }; | ||
| 83 | if let Poll::Ready(x) = fut.poll(cx) { | ||
| 84 | return Poll::Ready(Ok(x)); | ||
| 85 | } | ||
| 86 | if let Poll::Ready(_) = timer.poll(cx) { | ||
| 87 | return Poll::Ready(Err(TimeoutError)); | ||
| 88 | } | ||
| 89 | Poll::Pending | ||
| 67 | } | 90 | } |
| 68 | } | 91 | } |
| 69 | 92 | ||
diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs index f0d7626f6..e93c241ad 100644 --- a/embassy-usb-dfu/src/application.rs +++ b/embassy-usb-dfu/src/application.rs | |||
| @@ -13,9 +13,25 @@ use crate::consts::{ | |||
| 13 | }; | 13 | }; |
| 14 | use crate::Reset; | 14 | use crate::Reset; |
| 15 | 15 | ||
| 16 | /// Generic interface for a system that can signal to the bootloader that USB DFU mode is needed on the next boot. | ||
| 17 | /// | ||
| 18 | /// By default this trait is implemented for `BlockingFirmwareState<'d, STATE>` but you could also implement this generic | ||
| 19 | /// interface yourself instead in more complex situations. This could for instance be when you cannot hand ownership of a | ||
| 20 | /// `BlockingFirmwareState` instance over directly to the DFU `Control` instance and need to use a more complex mechanism. | ||
| 21 | pub trait DfuMarker { | ||
| 22 | /// Signal to the bootloader that DFU mode should be used on the next boot. | ||
| 23 | fn mark_dfu(&mut self); | ||
| 24 | } | ||
| 25 | |||
| 26 | impl<'d, STATE: NorFlash> DfuMarker for BlockingFirmwareState<'d, STATE> { | ||
| 27 | fn mark_dfu(&mut self) { | ||
| 28 | self.mark_dfu().expect("Failed to mark DFU mode in bootloader") | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 16 | /// Internal state for the DFU class | 32 | /// Internal state for the DFU class |
| 17 | pub struct Control<'d, STATE: NorFlash, RST: Reset> { | 33 | pub struct Control<MARK: DfuMarker, RST: Reset> { |
| 18 | firmware_state: BlockingFirmwareState<'d, STATE>, | 34 | dfu_marker: MARK, |
| 19 | attrs: DfuAttributes, | 35 | attrs: DfuAttributes, |
| 20 | state: State, | 36 | state: State, |
| 21 | timeout: Option<Duration>, | 37 | timeout: Option<Duration>, |
| @@ -23,11 +39,11 @@ pub struct Control<'d, STATE: NorFlash, RST: Reset> { | |||
| 23 | _rst: PhantomData<RST>, | 39 | _rst: PhantomData<RST>, |
| 24 | } | 40 | } |
| 25 | 41 | ||
| 26 | impl<'d, STATE: NorFlash, RST: Reset> Control<'d, STATE, RST> { | 42 | impl<MARK: DfuMarker, RST: Reset> Control<MARK, RST> { |
| 27 | /// Create a new DFU instance to expose a DFU interface. | 43 | /// Create a new DFU instance to expose a DFU interface. |
| 28 | pub fn new(firmware_state: BlockingFirmwareState<'d, STATE>, attrs: DfuAttributes) -> Self { | 44 | pub fn new(dfu_marker: MARK, attrs: DfuAttributes) -> Self { |
| 29 | Control { | 45 | Control { |
| 30 | firmware_state, | 46 | dfu_marker, |
| 31 | attrs, | 47 | attrs, |
| 32 | state: State::AppIdle, | 48 | state: State::AppIdle, |
| 33 | detach_start: None, | 49 | detach_start: None, |
| @@ -37,7 +53,7 @@ impl<'d, STATE: NorFlash, RST: Reset> Control<'d, STATE, RST> { | |||
| 37 | } | 53 | } |
| 38 | } | 54 | } |
| 39 | 55 | ||
| 40 | impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> { | 56 | impl<MARK: DfuMarker, RST: Reset> Handler for Control<MARK, RST> { |
| 41 | fn reset(&mut self) { | 57 | fn reset(&mut self) { |
| 42 | if let Some(start) = self.detach_start { | 58 | if let Some(start) = self.detach_start { |
| 43 | let delta = Instant::now() - start; | 59 | let delta = Instant::now() - start; |
| @@ -48,9 +64,7 @@ impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> { | |||
| 48 | timeout.as_millis() | 64 | timeout.as_millis() |
| 49 | ); | 65 | ); |
| 50 | if delta < timeout { | 66 | if delta < timeout { |
| 51 | self.firmware_state | 67 | self.dfu_marker.mark_dfu(); |
| 52 | .mark_dfu() | ||
| 53 | .expect("Failed to mark DFU mode in bootloader"); | ||
| 54 | RST::sys_reset() | 68 | RST::sys_reset() |
| 55 | } | 69 | } |
| 56 | } | 70 | } |
| @@ -109,9 +123,9 @@ impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> { | |||
| 109 | /// it should expose a DFU device, and a software reset will be issued. | 123 | /// it should expose a DFU device, and a software reset will be issued. |
| 110 | /// | 124 | /// |
| 111 | /// To apply USB DFU updates, the bootloader must be capable of recognizing the DFU magic and exposing a device to handle the full DFU transaction with the host. | 125 | /// To apply USB DFU updates, the bootloader must be capable of recognizing the DFU magic and exposing a device to handle the full DFU transaction with the host. |
| 112 | pub fn usb_dfu<'d, D: Driver<'d>, STATE: NorFlash, RST: Reset>( | 126 | pub fn usb_dfu<'d, D: Driver<'d>, MARK: DfuMarker, RST: Reset>( |
| 113 | builder: &mut Builder<'d, D>, | 127 | builder: &mut Builder<'d, D>, |
| 114 | handler: &'d mut Control<'d, STATE, RST>, | 128 | handler: &'d mut Control<MARK, RST>, |
| 115 | timeout: Duration, | 129 | timeout: Duration, |
| 116 | ) { | 130 | ) { |
| 117 | let mut func = builder.function(0x00, 0x00, 0x00); | 131 | let mut func = builder.function(0x00, 0x00, 0x00); |
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index 9a21b9a3b..6c4b3f9a4 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs | |||
| @@ -218,10 +218,10 @@ impl<'d, D: Driver<'d>> Builder<'d, D> { | |||
| 218 | self.bos_descriptor.end_bos(); | 218 | self.bos_descriptor.end_bos(); |
| 219 | 219 | ||
| 220 | // Log the number of allocator bytes actually used in descriptor buffers | 220 | // Log the number of allocator bytes actually used in descriptor buffers |
| 221 | info!("USB: config_descriptor used: {}", self.config_descriptor.position()); | 221 | trace!("USB: config_descriptor used: {}", self.config_descriptor.position()); |
| 222 | info!("USB: bos_descriptor used: {}", self.bos_descriptor.writer.position()); | 222 | trace!("USB: bos_descriptor used: {}", self.bos_descriptor.writer.position()); |
| 223 | info!("USB: msos_descriptor used: {}", msos_descriptor.len()); | 223 | trace!("USB: msos_descriptor used: {}", msos_descriptor.len()); |
| 224 | info!("USB: control_buf size: {}", self.control_buf.len()); | 224 | trace!("USB: control_buf size: {}", self.control_buf.len()); |
| 225 | 225 | ||
| 226 | UsbDevice::build( | 226 | UsbDevice::build( |
| 227 | self.driver, | 227 | self.driver, |
diff --git a/examples/nrf52840/src/bin/twim.rs b/examples/nrf52840/src/bin/twim.rs index ceaafd784..e30a3855d 100644 --- a/examples/nrf52840/src/bin/twim.rs +++ b/examples/nrf52840/src/bin/twim.rs | |||
| @@ -9,6 +9,7 @@ use defmt::*; | |||
| 9 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| 10 | use embassy_nrf::twim::{self, Twim}; | 10 | use embassy_nrf::twim::{self, Twim}; |
| 11 | use embassy_nrf::{bind_interrupts, peripherals}; | 11 | use embassy_nrf::{bind_interrupts, peripherals}; |
| 12 | use static_cell::ConstStaticCell; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | 14 | ||
| 14 | const ADDRESS: u8 = 0x50; | 15 | const ADDRESS: u8 = 0x50; |
| @@ -22,7 +23,8 @@ async fn main(_spawner: Spawner) { | |||
| 22 | let p = embassy_nrf::init(Default::default()); | 23 | let p = embassy_nrf::init(Default::default()); |
| 23 | info!("Initializing TWI..."); | 24 | info!("Initializing TWI..."); |
| 24 | let config = twim::Config::default(); | 25 | let config = twim::Config::default(); |
| 25 | let mut twi = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config); | 26 | static RAM_BUFFER: ConstStaticCell<[u8; 16]> = ConstStaticCell::new([0; 16]); |
| 27 | let mut twi = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config, RAM_BUFFER.take()); | ||
| 26 | 28 | ||
| 27 | info!("Reading..."); | 29 | info!("Reading..."); |
| 28 | 30 | ||
diff --git a/examples/nrf52840/src/bin/twim_lowpower.rs b/examples/nrf52840/src/bin/twim_lowpower.rs index 8a6f958eb..f7380e20d 100644 --- a/examples/nrf52840/src/bin/twim_lowpower.rs +++ b/examples/nrf52840/src/bin/twim_lowpower.rs | |||
| @@ -30,6 +30,7 @@ async fn main(_p: Spawner) { | |||
| 30 | loop { | 30 | loop { |
| 31 | info!("Initializing TWI..."); | 31 | info!("Initializing TWI..."); |
| 32 | let config = twim::Config::default(); | 32 | let config = twim::Config::default(); |
| 33 | let mut ram_buffer = [0u8; 16]; | ||
| 33 | 34 | ||
| 34 | // Create the TWIM instance with borrowed singletons, so they're not consumed. | 35 | // Create the TWIM instance with borrowed singletons, so they're not consumed. |
| 35 | let mut twi = Twim::new( | 36 | let mut twi = Twim::new( |
| @@ -38,6 +39,7 @@ async fn main(_p: Spawner) { | |||
| 38 | p.P0_03.reborrow(), | 39 | p.P0_03.reborrow(), |
| 39 | p.P0_04.reborrow(), | 40 | p.P0_04.reborrow(), |
| 40 | config, | 41 | config, |
| 42 | &mut ram_buffer, | ||
| 41 | ); | 43 | ); |
| 42 | 44 | ||
| 43 | info!("Reading..."); | 45 | info!("Reading..."); |
diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs index 991510851..379e2b8f9 100644 --- a/examples/rp/src/bin/pio_onewire.rs +++ b/examples/rp/src/bin/pio_onewire.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | //! This example shows how you can use PIO to read a `DS18B20` one-wire temperature sensor. | 1 | //! This example shows how you can use PIO to read one or more `DS18B20` one-wire temperature sensors. |
| 2 | 2 | ||
| 3 | #![no_std] | 3 | #![no_std] |
| 4 | #![no_main] | 4 | #![no_main] |
| @@ -6,9 +6,10 @@ use defmt::*; | |||
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_rp::bind_interrupts; | 7 | use embassy_rp::bind_interrupts; |
| 8 | use embassy_rp::peripherals::PIO0; | 8 | use embassy_rp::peripherals::PIO0; |
| 9 | use embassy_rp::pio::{self, InterruptHandler, Pio}; | 9 | use embassy_rp::pio::{InterruptHandler, Pio}; |
| 10 | use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram}; | 10 | use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram, PioOneWireSearch}; |
| 11 | use embassy_time::Timer; | 11 | use embassy_time::Timer; |
| 12 | use heapless::Vec; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | 14 | ||
| 14 | bind_interrupts!(struct Irqs { | 15 | bind_interrupts!(struct Irqs { |
| @@ -21,63 +22,66 @@ async fn main(_spawner: Spawner) { | |||
| 21 | let mut pio = Pio::new(p.PIO0, Irqs); | 22 | let mut pio = Pio::new(p.PIO0, Irqs); |
| 22 | 23 | ||
| 23 | let prg = PioOneWireProgram::new(&mut pio.common); | 24 | let prg = PioOneWireProgram::new(&mut pio.common); |
| 24 | let onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg); | 25 | let mut onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg); |
| 25 | 26 | ||
| 26 | let mut sensor = Ds18b20::new(onewire); | 27 | info!("Starting onewire search"); |
| 27 | 28 | ||
| 28 | loop { | 29 | let mut devices = Vec::<u64, 10>::new(); |
| 29 | sensor.start().await; // Start a new measurement | 30 | let mut search = PioOneWireSearch::new(); |
| 30 | Timer::after_secs(1).await; // Allow 1s for the measurement to finish | 31 | for _ in 0..10 { |
| 31 | match sensor.temperature().await { | 32 | if !search.is_finished() { |
| 32 | Ok(temp) => info!("temp = {:?} deg C", temp), | 33 | if let Some(address) = search.next(&mut onewire).await { |
| 33 | _ => error!("sensor error"), | 34 | if crc8(&address.to_le_bytes()) == 0 { |
| 35 | info!("Found addres: {:x}", address); | ||
| 36 | let _ = devices.push(address); | ||
| 37 | } else { | ||
| 38 | warn!("Found invalid address: {:x}", address); | ||
| 39 | } | ||
| 40 | } | ||
| 34 | } | 41 | } |
| 35 | Timer::after_secs(1).await; | ||
| 36 | } | 42 | } |
| 37 | } | ||
| 38 | 43 | ||
| 39 | /// DS18B20 temperature sensor driver | 44 | info!("Search done, found {} devices", devices.len()); |
| 40 | pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> { | ||
| 41 | wire: PioOneWire<'d, PIO, SM>, | ||
| 42 | } | ||
| 43 | 45 | ||
| 44 | impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> { | 46 | loop { |
| 45 | pub fn new(wire: PioOneWire<'d, PIO, SM>) -> Self { | 47 | onewire.reset().await; |
| 46 | Self { wire } | 48 | // Skip rom and trigger conversion, we can trigger all devices on the bus immediately |
| 47 | } | 49 | onewire.write_bytes(&[0xCC, 0x44]).await; |
| 48 | 50 | ||
| 49 | /// Calculate CRC8 of the data | 51 | Timer::after_secs(1).await; // Allow 1s for the measurement to finish |
| 50 | fn crc8(data: &[u8]) -> u8 { | 52 | |
| 51 | let mut temp; | 53 | // Read all devices one by one |
| 52 | let mut data_byte; | 54 | for device in &devices { |
| 53 | let mut crc = 0; | 55 | onewire.reset().await; |
| 54 | for b in data { | 56 | onewire.write_bytes(&[0x55]).await; // Match rom |
| 55 | data_byte = *b; | 57 | onewire.write_bytes(&device.to_le_bytes()).await; |
| 56 | for _ in 0..8 { | 58 | onewire.write_bytes(&[0xBE]).await; // Read scratchpad |
| 57 | temp = (crc ^ data_byte) & 0x01; | 59 | |
| 58 | crc >>= 1; | 60 | let mut data = [0; 9]; |
| 59 | if temp != 0 { | 61 | onewire.read_bytes(&mut data).await; |
| 60 | crc ^= 0x8C; | 62 | if crc8(&data) == 0 { |
| 61 | } | 63 | let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.; |
| 62 | data_byte >>= 1; | 64 | info!("Read device {:x}: {} deg C", device, temp); |
| 65 | } else { | ||
| 66 | warn!("Reading device {:x} failed", device); | ||
| 63 | } | 67 | } |
| 64 | } | 68 | } |
| 65 | crc | 69 | Timer::after_secs(1).await; |
| 66 | } | ||
| 67 | |||
| 68 | /// Start a new measurement. Allow at least 1000ms before getting `temperature`. | ||
| 69 | pub async fn start(&mut self) { | ||
| 70 | self.wire.write_bytes(&[0xCC, 0x44]).await; | ||
| 71 | } | 70 | } |
| 71 | } | ||
| 72 | 72 | ||
| 73 | /// Read the temperature. Ensure >1000ms has passed since `start` before calling this. | 73 | fn crc8(data: &[u8]) -> u8 { |
| 74 | pub async fn temperature(&mut self) -> Result<f32, ()> { | 74 | let mut crc = 0; |
| 75 | self.wire.write_bytes(&[0xCC, 0xBE]).await; | 75 | for b in data { |
| 76 | let mut data = [0; 9]; | 76 | let mut data_byte = *b; |
| 77 | self.wire.read_bytes(&mut data).await; | 77 | for _ in 0..8 { |
| 78 | match Self::crc8(&data) == 0 { | 78 | let temp = (crc ^ data_byte) & 0x01; |
| 79 | true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.), | 79 | crc >>= 1; |
| 80 | false => Err(()), | 80 | if temp != 0 { |
| 81 | crc ^= 0x8C; | ||
| 82 | } | ||
| 83 | data_byte >>= 1; | ||
| 81 | } | 84 | } |
| 82 | } | 85 | } |
| 86 | crc | ||
| 83 | } | 87 | } |
