aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordiondokter <[email protected]>2025-05-01 09:44:39 +0200
committerdiondokter <[email protected]>2025-05-01 09:44:39 +0200
commitf713f170a1a38a3eaa48ac535b211370f71d39aa (patch)
tree1a696bd6ecc94b363f59fccb3612409cb89a0180
parentae59d0acf4f7c7be028b1246aaa8033015985154 (diff)
parent52e4c7c30c5f59d10afbef2447b96da68f4be0bc (diff)
Merge branch 'main' into configurable-bank-support
-rwxr-xr-xci.sh1
-rw-r--r--embassy-nrf/src/twim.rs171
-rw-r--r--embassy-rp/src/pio_programs/onewire.rs312
-rw-r--r--embassy-rp/src/trng.rs104
-rw-r--r--embassy-stm32/build.rs5
-rw-r--r--embassy-stm32/src/adc/g4.rs2
-rw-r--r--embassy-stm32/src/adc/mod.rs4
-rw-r--r--embassy-stm32/src/adc/v3.rs20
-rw-r--r--embassy-stm32/src/adc/v4.rs2
-rw-r--r--embassy-stm32/src/can/bxcan/registers.rs4
-rw-r--r--embassy-stm32/src/can/fd/peripheral.rs4
-rw-r--r--embassy-stm32/src/can/frame.rs23
-rw-r--r--embassy-stm32/src/opamp.rs55
-rw-r--r--embassy-stm32/src/rcc/mod.rs2
-rw-r--r--embassy-stm32/src/spi/mod.rs8
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs8
-rw-r--r--embassy-stm32/src/usb/otg.rs2
-rw-r--r--embassy-sync/README.md2
-rw-r--r--embassy-sync/src/waitqueue/atomic_waker.rs3
-rw-r--r--embassy-sync/src/waitqueue/atomic_waker_turbo.rs3
-rw-r--r--embassy-sync/src/waitqueue/multi_waker.rs2
-rw-r--r--embassy-sync/src/waitqueue/waker_registration.rs4
-rw-r--r--embassy-time-driver/Cargo.toml2
-rw-r--r--embassy-time-driver/gen_tick.py1
-rw-r--r--embassy-time-driver/src/tick.rs3
-rw-r--r--embassy-time/Cargo.toml2
-rw-r--r--embassy-time/src/timer.rs61
-rw-r--r--embassy-usb-dfu/src/application.rs36
-rw-r--r--embassy-usb/src/builder.rs8
-rw-r--r--examples/nrf52840/src/bin/twim.rs4
-rw-r--r--examples/nrf52840/src/bin/twim_lowpower.rs2
-rw-r--r--examples/rp/src/bin/pio_onewire.rs102
32 files changed, 569 insertions, 393 deletions
diff --git a/ci.sh b/ci.sh
index e27ada508..5a438f0b1 100755
--- a/ci.sh
+++ b/ci.sh
@@ -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.
326rm -rf out/tests/stm32f103c8 326rm -rf out/tests/stm32f103c8
327rm -rf out/tests/stm32l073rz
328rm -rf out/tests/nrf52840-dk 327rm -rf out/tests/nrf52840-dk
329rm -rf out/tests/nrf52833-dk 328rm -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
5use core::future::{poll_fn, Future}; 5use core::future::{poll_fn, Future};
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::mem::MaybeUninit;
8use core::sync::atomic::compiler_fence; 7use core::sync::atomic::compiler_fence;
9use core::sync::atomic::Ordering::SeqCst; 8use core::sync::atomic::Ordering::SeqCst;
10use core::task::Poll; 9use core::task::Poll;
@@ -17,7 +16,7 @@ use embassy_time::{Duration, Instant};
17use embedded_hal_1::i2c::Operation; 16use embedded_hal_1::i2c::Operation;
18pub use pac::twim::vals::Frequency; 17pub use pac::twim::vals::Frequency;
19 18
20use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 19use crate::chip::EASY_DMA_SIZE;
21use crate::gpio::Pin as GpioPin; 20use crate::gpio::Pin as GpioPin;
22use crate::interrupt::typelevel::Interrupt; 21use crate::interrupt::typelevel::Interrupt;
23use crate::pac::gpio::vals as gpiovals; 22use crate::pac::gpio::vals as gpiovals;
@@ -75,8 +74,8 @@ pub enum Error {
75 Transmit, 74 Transmit,
76 /// Data reception failed. 75 /// Data reception failed.
77 Receive, 76 Receive,
78 /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash. 77 /// The buffer is not in data RAM and is larger than the RAM buffer. It's most likely in flash, and nRF's DMA cannot access flash.
79 BufferNotInRAM, 78 RAMBufferTooSmall,
80 /// Didn't receive an ACK bit after the address byte. Address might be wrong, or the i2c device chip might not be connected properly. 79 /// Didn't receive an ACK bit after the address byte. Address might be wrong, or the i2c device chip might not be connected properly.
81 AddressNack, 80 AddressNack,
82 /// Didn't receive an ACK bit after a data byte. 81 /// Didn't receive an ACK bit after a data byte.
@@ -115,16 +114,24 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
115/// TWI driver. 114/// TWI driver.
116pub struct Twim<'d, T: Instance> { 115pub struct Twim<'d, T: Instance> {
117 _p: Peri<'d, T>, 116 _p: Peri<'d, T>,
117 tx_ram_buffer: &'d mut [u8],
118} 118}
119 119
120impl<'d, T: Instance> Twim<'d, T> { 120impl<'d, T: Instance> Twim<'d, T> {
121 /// Create a new TWI driver. 121 /// Create a new TWI driver.
122 ///
123 /// `tx_ram_buffer` is required if any write operations will be performed with data that is not in RAM.
124 /// Usually this is static data that the compiler locates in flash instead of RAM. The `tx_ram_buffer`
125 /// needs to be at least as large as the largest write operation that will be executed with a buffer
126 /// that is not in RAM. If all write operations will be performed from RAM, an empty buffer (`&[]`) may
127 /// be used.
122 pub fn new( 128 pub fn new(
123 twim: Peri<'d, T>, 129 twim: Peri<'d, T>,
124 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 130 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
125 sda: Peri<'d, impl GpioPin>, 131 sda: Peri<'d, impl GpioPin>,
126 scl: Peri<'d, impl GpioPin>, 132 scl: Peri<'d, impl GpioPin>,
127 config: Config, 133 config: Config,
134 tx_ram_buffer: &'d mut [u8],
128 ) -> Self { 135 ) -> Self {
129 let r = T::regs(); 136 let r = T::regs();
130 137
@@ -159,7 +166,10 @@ impl<'d, T: Instance> Twim<'d, T> {
159 // Enable TWIM instance. 166 // Enable TWIM instance.
160 r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); 167 r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
161 168
162 let mut twim = Self { _p: twim }; 169 let mut twim = Self {
170 _p: twim,
171 tx_ram_buffer,
172 };
163 173
164 // Apply runtime peripheral configuration 174 // Apply runtime peripheral configuration
165 Self::set_config(&mut twim, &config).unwrap(); 175 Self::set_config(&mut twim, &config).unwrap();
@@ -174,21 +184,17 @@ impl<'d, T: Instance> Twim<'d, T> {
174 } 184 }
175 185
176 /// Set TX buffer, checking that it is in RAM and has suitable length. 186 /// Set TX buffer, checking that it is in RAM and has suitable length.
177 unsafe fn set_tx_buffer( 187 unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> {
178 &mut self,
179 buffer: &[u8],
180 ram_buffer: Option<&mut [MaybeUninit<u8>; FORCE_COPY_BUFFER_SIZE]>,
181 ) -> Result<(), Error> {
182 let buffer = if slice_in_ram(buffer) { 188 let buffer = if slice_in_ram(buffer) {
183 buffer 189 buffer
184 } else { 190 } else {
185 let ram_buffer = ram_buffer.ok_or(Error::BufferNotInRAM)?; 191 if buffer.len() > self.tx_ram_buffer.len() {
192 return Err(Error::RAMBufferTooSmall);
193 }
186 trace!("Copying TWIM tx buffer into RAM for DMA"); 194 trace!("Copying TWIM tx buffer into RAM for DMA");
187 let ram_buffer = &mut ram_buffer[..buffer.len()]; 195 let ram_buffer = &mut self.tx_ram_buffer[..buffer.len()];
188 // Inline implementation of the nightly API MaybeUninit::copy_from_slice(ram_buffer, buffer) 196 ram_buffer.copy_from_slice(buffer);
189 let uninit_src: &[MaybeUninit<u8>] = unsafe { core::mem::transmute(buffer) }; 197 &*ram_buffer
190 ram_buffer.copy_from_slice(uninit_src);
191 unsafe { &*(ram_buffer as *const [MaybeUninit<u8>] as *const [u8]) }
192 }; 198 };
193 199
194 if buffer.len() > EASY_DMA_SIZE { 200 if buffer.len() > EASY_DMA_SIZE {
@@ -358,7 +364,6 @@ impl<'d, T: Instance> Twim<'d, T> {
358 &mut self, 364 &mut self,
359 address: u8, 365 address: u8,
360 operations: &mut [Operation<'_>], 366 operations: &mut [Operation<'_>],
361 tx_ram_buffer: Option<&mut [MaybeUninit<u8>; FORCE_COPY_BUFFER_SIZE]>,
362 last_op: Option<&Operation<'_>>, 367 last_op: Option<&Operation<'_>>,
363 inten: bool, 368 inten: bool,
364 ) -> Result<usize, Error> { 369 ) -> Result<usize, Error> {
@@ -397,7 +402,7 @@ impl<'d, T: Instance> Twim<'d, T> {
397 402
398 // Set up DMA buffers. 403 // Set up DMA buffers.
399 unsafe { 404 unsafe {
400 self.set_tx_buffer(wr_buffer, tx_ram_buffer)?; 405 self.set_tx_buffer(wr_buffer)?;
401 self.set_rx_buffer(rd_buffer)?; 406 self.set_rx_buffer(rd_buffer)?;
402 } 407 }
403 408
@@ -450,7 +455,7 @@ impl<'d, T: Instance> Twim<'d, T> {
450 { 455 {
451 // Set up DMA buffers. 456 // Set up DMA buffers.
452 unsafe { 457 unsafe {
453 self.set_tx_buffer(wr_buffer, tx_ram_buffer)?; 458 self.set_tx_buffer(wr_buffer)?;
454 self.set_rx_buffer(rd_buffer)?; 459 self.set_rx_buffer(rd_buffer)?;
455 } 460 }
456 461
@@ -472,7 +477,7 @@ impl<'d, T: Instance> Twim<'d, T> {
472 477
473 // Set up DMA buffers. 478 // Set up DMA buffers.
474 unsafe { 479 unsafe {
475 self.set_tx_buffer(buffer, tx_ram_buffer)?; 480 self.set_tx_buffer(buffer)?;
476 } 481 }
477 482
478 // Start write operation. 483 // Start write operation.
@@ -539,28 +544,9 @@ impl<'d, T: Instance> Twim<'d, T> {
539 /// An `Operation::Write` following an `Operation::Read` must have a 544 /// An `Operation::Write` following an `Operation::Read` must have a
540 /// non-empty buffer. 545 /// non-empty buffer.
541 pub fn blocking_transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { 546 pub fn blocking_transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> {
542 let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE];
543 let mut last_op = None; 547 let mut last_op = None;
544 while !operations.is_empty() { 548 while !operations.is_empty() {
545 let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, false)?; 549 let ops = self.setup_operations(address, operations, last_op, false)?;
546 let (in_progress, rest) = operations.split_at_mut(ops);
547 self.blocking_wait();
548 self.check_operations(in_progress)?;
549 last_op = in_progress.last();
550 operations = rest;
551 }
552 Ok(())
553 }
554
555 /// Same as [`blocking_transaction`](Twim::blocking_transaction) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
556 pub fn blocking_transaction_from_ram(
557 &mut self,
558 address: u8,
559 mut operations: &mut [Operation<'_>],
560 ) -> Result<(), Error> {
561 let mut last_op = None;
562 while !operations.is_empty() {
563 let ops = self.setup_operations(address, operations, None, last_op, false)?;
564 let (in_progress, rest) = operations.split_at_mut(ops); 550 let (in_progress, rest) = operations.split_at_mut(ops);
565 self.blocking_wait(); 551 self.blocking_wait();
566 self.check_operations(in_progress)?; 552 self.check_operations(in_progress)?;
@@ -580,30 +566,9 @@ impl<'d, T: Instance> Twim<'d, T> {
580 mut operations: &mut [Operation<'_>], 566 mut operations: &mut [Operation<'_>],
581 timeout: Duration, 567 timeout: Duration,
582 ) -> Result<(), Error> { 568 ) -> Result<(), Error> {
583 let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE];
584 let mut last_op = None;
585 while !operations.is_empty() {
586 let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, false)?;
587 let (in_progress, rest) = operations.split_at_mut(ops);
588 self.blocking_wait_timeout(timeout)?;
589 self.check_operations(in_progress)?;
590 last_op = in_progress.last();
591 operations = rest;
592 }
593 Ok(())
594 }
595
596 /// Same as [`blocking_transaction_timeout`](Twim::blocking_transaction_timeout) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
597 #[cfg(feature = "time")]
598 pub fn blocking_transaction_from_ram_timeout(
599 &mut self,
600 address: u8,
601 mut operations: &mut [Operation<'_>],
602 timeout: Duration,
603 ) -> Result<(), Error> {
604 let mut last_op = None; 569 let mut last_op = None;
605 while !operations.is_empty() { 570 while !operations.is_empty() {
606 let ops = self.setup_operations(address, operations, None, last_op, false)?; 571 let ops = self.setup_operations(address, operations, last_op, false)?;
607 let (in_progress, rest) = operations.split_at_mut(ops); 572 let (in_progress, rest) = operations.split_at_mut(ops);
608 self.blocking_wait_timeout(timeout)?; 573 self.blocking_wait_timeout(timeout)?;
609 self.check_operations(in_progress)?; 574 self.check_operations(in_progress)?;
@@ -624,28 +589,9 @@ impl<'d, T: Instance> Twim<'d, T> {
624 /// An `Operation::Write` following an `Operation::Read` must have a 589 /// An `Operation::Write` following an `Operation::Read` must have a
625 /// non-empty buffer. 590 /// non-empty buffer.
626 pub async fn transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { 591 pub async fn transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> {
627 let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE];
628 let mut last_op = None;
629 while !operations.is_empty() {
630 let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, true)?;
631 let (in_progress, rest) = operations.split_at_mut(ops);
632 self.async_wait().await?;
633 self.check_operations(in_progress)?;
634 last_op = in_progress.last();
635 operations = rest;
636 }
637 Ok(())
638 }
639
640 /// Same as [`transaction`](Twim::transaction) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
641 pub async fn transaction_from_ram(
642 &mut self,
643 address: u8,
644 mut operations: &mut [Operation<'_>],
645 ) -> Result<(), Error> {
646 let mut last_op = None; 592 let mut last_op = None;
647 while !operations.is_empty() { 593 while !operations.is_empty() {
648 let ops = self.setup_operations(address, operations, None, last_op, true)?; 594 let ops = self.setup_operations(address, operations, last_op, true)?;
649 let (in_progress, rest) = operations.split_at_mut(ops); 595 let (in_progress, rest) = operations.split_at_mut(ops);
650 self.async_wait().await?; 596 self.async_wait().await?;
651 self.check_operations(in_progress)?; 597 self.check_operations(in_progress)?;
@@ -665,11 +611,6 @@ impl<'d, T: Instance> Twim<'d, T> {
665 self.blocking_transaction(address, &mut [Operation::Write(buffer)]) 611 self.blocking_transaction(address, &mut [Operation::Write(buffer)])
666 } 612 }
667 613
668 /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
669 pub fn blocking_write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
670 self.blocking_transaction_from_ram(address, &mut [Operation::Write(buffer)])
671 }
672
673 /// Read from an I2C slave. 614 /// Read from an I2C slave.
674 /// 615 ///
675 /// The buffer must have a length of at most 255 bytes on the nRF52832 616 /// The buffer must have a length of at most 255 bytes on the nRF52832
@@ -687,16 +628,6 @@ impl<'d, T: Instance> Twim<'d, T> {
687 self.blocking_transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) 628 self.blocking_transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
688 } 629 }
689 630
690 /// Same as [`blocking_write_read`](Twim::blocking_write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
691 pub fn blocking_write_read_from_ram(
692 &mut self,
693 address: u8,
694 wr_buffer: &[u8],
695 rd_buffer: &mut [u8],
696 ) -> Result<(), Error> {
697 self.blocking_transaction_from_ram(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
698 }
699
700 // =========================================== 631 // ===========================================
701 632
702 /// Write to an I2C slave with timeout. 633 /// Write to an I2C slave with timeout.
@@ -707,17 +638,6 @@ impl<'d, T: Instance> Twim<'d, T> {
707 self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], timeout) 638 self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], timeout)
708 } 639 }
709 640
710 /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
711 #[cfg(feature = "time")]
712 pub fn blocking_write_from_ram_timeout(
713 &mut self,
714 address: u8,
715 buffer: &[u8],
716 timeout: Duration,
717 ) -> Result<(), Error> {
718 self.blocking_transaction_from_ram_timeout(address, &mut [Operation::Write(buffer)], timeout)
719 }
720
721 /// Read from an I2C slave. 641 /// Read from an I2C slave.
722 /// 642 ///
723 /// The buffer must have a length of at most 255 bytes on the nRF52832 643 /// The buffer must have a length of at most 255 bytes on the nRF52832
@@ -747,22 +667,6 @@ impl<'d, T: Instance> Twim<'d, T> {
747 ) 667 )
748 } 668 }
749 669
750 /// Same as [`blocking_write_read`](Twim::blocking_write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
751 #[cfg(feature = "time")]
752 pub fn blocking_write_read_from_ram_timeout(
753 &mut self,
754 address: u8,
755 wr_buffer: &[u8],
756 rd_buffer: &mut [u8],
757 timeout: Duration,
758 ) -> Result<(), Error> {
759 self.blocking_transaction_from_ram_timeout(
760 address,
761 &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)],
762 timeout,
763 )
764 }
765
766 // =========================================== 670 // ===========================================
767 671
768 /// Read from an I2C slave. 672 /// Read from an I2C slave.
@@ -781,12 +685,6 @@ impl<'d, T: Instance> Twim<'d, T> {
781 self.transaction(address, &mut [Operation::Write(buffer)]).await 685 self.transaction(address, &mut [Operation::Write(buffer)]).await
782 } 686 }
783 687
784 /// Same as [`write`](Twim::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
785 pub async fn write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> {
786 self.transaction_from_ram(address, &mut [Operation::Write(buffer)])
787 .await
788 }
789
790 /// Write data to an I2C slave, then read data from the slave without 688 /// Write data to an I2C slave, then read data from the slave without
791 /// triggering a stop condition between the two. 689 /// triggering a stop condition between the two.
792 /// 690 ///
@@ -796,17 +694,6 @@ impl<'d, T: Instance> Twim<'d, T> {
796 self.transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) 694 self.transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
797 .await 695 .await
798 } 696 }
799
800 /// Same as [`write_read`](Twim::write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more.
801 pub async fn write_read_from_ram(
802 &mut self,
803 address: u8,
804 wr_buffer: &[u8],
805 rd_buffer: &mut [u8],
806 ) -> Result<(), Error> {
807 self.transaction_from_ram(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)])
808 .await
809 }
810} 697}
811 698
812impl<'a, T: Instance> Drop for Twim<'a, T> { 699impl<'a, T: Instance> Drop for Twim<'a, T> {
@@ -904,7 +791,7 @@ impl embedded_hal_1::i2c::Error for Error {
904 Self::RxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other, 791 Self::RxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other,
905 Self::Transmit => embedded_hal_1::i2c::ErrorKind::Other, 792 Self::Transmit => embedded_hal_1::i2c::ErrorKind::Other,
906 Self::Receive => embedded_hal_1::i2c::ErrorKind::Other, 793 Self::Receive => embedded_hal_1::i2c::ErrorKind::Other,
907 Self::BufferNotInRAM => embedded_hal_1::i2c::ErrorKind::Other, 794 Self::RAMBufferTooSmall => embedded_hal_1::i2c::ErrorKind::Other,
908 Self::AddressNack => { 795 Self::AddressNack => {
909 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) 796 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address)
910 } 797 }
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
3use crate::pio::{Common, Config, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine}; 3use crate::clocks::clk_sys_freq;
4use crate::gpio::Level;
5use crate::pio::{
6 Common, Config, Direction, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine,
7};
4use crate::Peri; 8use crate::Peri;
5 9
6/// This struct represents an onewire driver program 10/// This struct represents a onewire driver program
7pub struct PioOneWireProgram<'a, PIO: Instance> { 11pub 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
11impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> { 17impl<'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
64pub struct PioOneWire<'d, PIO: Instance, const SM: usize> { 78pub 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
68impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { 85impl<'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
267pub struct PioOneWireSearch {
268 last_rom: u64,
269 last_discrepancy: u8,
270 finished: bool,
271}
272
273impl 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 {
108impl Default for Config { 111impl 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/// ```
149pub struct Trng<'d, T: Instance> { 153pub 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;
159impl<'d, T: Instance> Trng<'d, T> { 164impl<'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
72cfg_if! { 72cfg_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))]
106pub struct ClassicData { 106pub struct ClassicData {
107 pub(crate) bytes: [u8; Self::MAX_DATA_LEN], 107 pub(crate) bytes: [u8; 8],
108} 108}
109 109
110impl ClassicData { 110impl 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)]
41pub enum OpAmpSpeed { 41pub enum OpAmpSpeed {
42 Normal, 42 Normal,
43 HighSpeed, 43 HighSpeed,
44} 44}
45 45
46#[cfg(opamp_g4)]
47impl 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
98pub(crate) trait SealedRccPeripheral { 98pub(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
551fn calculate_trdt<T: Instance>(speed: Dspd) -> u8 { 551fn 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};
5use crate::blocking_mutex::Mutex; 5use 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.
8pub struct GenericAtomicWaker<M: RawMutex> { 11pub 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};
4use core::task::Waker; 4use 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.
7pub struct AtomicWaker { 10pub 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;
3use heapless::Vec; 3use 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.
6pub struct MultiWakerRegistration<const N: usize> { 8pub 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;
2use core::task::Waker; 2use 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)]
6pub struct WakerRegistration { 10pub 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 = []
226tick-hz-130_000_000 = [] 226tick-hz-130_000_000 = []
227## 131.072MHz Tick Rate 227## 131.072MHz Tick Rate
228tick-hz-131_072_000 = [] 228tick-hz-131_072_000 = []
229## 133.0MHz Tick Rate
230tick-hz-133_000_000 = []
229## 140.0MHz Tick Rate 231## 140.0MHz Tick Rate
230tick-hz-140_000_000 = [] 232tick-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)
23for i in range(15, 50): 23for i in range(15, 50):
24 ticks.append(20 * i * 1_000_000) 24 ticks.append(20 * i * 1_000_000)
25ticks.append(133 * 1_000_000)
25 26
26seen = set() 27seen = set()
27ticks = sorted([x for x in ticks if not (x in seen or seen.add(x))]) 28ticks = 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;
182pub const TICK_HZ: u64 = 130_000_000; 182pub const TICK_HZ: u64 = 130_000_000;
183#[cfg(feature = "tick-hz-131_072_000")] 183#[cfg(feature = "tick-hz-131_072_000")]
184pub const TICK_HZ: u64 = 131_072_000; 184pub const TICK_HZ: u64 = 131_072_000;
185#[cfg(feature = "tick-hz-133_000_000")]
186pub const TICK_HZ: u64 = 133_000_000;
185#[cfg(feature = "tick-hz-140_000_000")] 187#[cfg(feature = "tick-hz-140_000_000")]
186pub const TICK_HZ: u64 = 140_000_000; 188pub 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"]
274tick-hz-130_000_000 = ["embassy-time-driver/tick-hz-130_000_000"] 274tick-hz-130_000_000 = ["embassy-time-driver/tick-hz-130_000_000"]
275## 131.072MHz Tick Rate 275## 131.072MHz Tick Rate
276tick-hz-131_072_000 = ["embassy-time-driver/tick-hz-131_072_000"] 276tick-hz-131_072_000 = ["embassy-time-driver/tick-hz-131_072_000"]
277## 133.0MHz Tick Rate
278tick-hz-133_000_000 = ["embassy-time-driver/tick-hz-133_000_000"]
277## 140.0MHz Tick Rate 279## 140.0MHz Tick Rate
278tick-hz-140_000_000 = ["embassy-time-driver/tick-hz-140_000_000"] 280tick-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 @@
1use core::future::{poll_fn, Future}; 1use core::future::{poll_fn, Future};
2use core::pin::{pin, Pin}; 2use core::pin::Pin;
3use core::task::{Context, Poll}; 3use core::task::{Context, Poll};
4 4
5use futures_util::future::{select, Either};
6use futures_util::stream::FusedStream; 5use futures_util::stream::FusedStream;
7use futures_util::Stream; 6use 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.
20pub async fn with_timeout<F: Future>(timeout: Duration, fut: F) -> Result<F::Output, TimeoutError> { 19pub 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.
32pub async fn with_deadline<F: Future>(at: Instant, fut: F) -> Result<F::Output, TimeoutError> { 30pub 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.
41pub trait WithTimeout { 38pub 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
58impl<F: Future> WithTimeout for F { 55impl<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"]
69pub struct TimeoutFuture<F> {
70 timer: Timer,
71 fut: F,
72}
73
74impl<F: Unpin> Unpin for TimeoutFuture<F> {}
75
76impl<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};
14use crate::Reset; 14use 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.
21pub 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
26impl<'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
17pub struct Control<'d, STATE: NorFlash, RST: Reset> { 33pub 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
26impl<'d, STATE: NorFlash, RST: Reset> Control<'d, STATE, RST> { 42impl<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
40impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> { 56impl<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.
112pub fn usb_dfu<'d, D: Driver<'d>, STATE: NorFlash, RST: Reset>( 126pub 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::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_nrf::twim::{self, Twim}; 10use embassy_nrf::twim::{self, Twim};
11use embassy_nrf::{bind_interrupts, peripherals}; 11use embassy_nrf::{bind_interrupts, peripherals};
12use static_cell::ConstStaticCell;
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
13 14
14const ADDRESS: u8 = 0x50; 15const 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::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_rp::bind_interrupts; 7use embassy_rp::bind_interrupts;
8use embassy_rp::peripherals::PIO0; 8use embassy_rp::peripherals::PIO0;
9use embassy_rp::pio::{self, InterruptHandler, Pio}; 9use embassy_rp::pio::{InterruptHandler, Pio};
10use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram}; 10use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram, PioOneWireSearch};
11use embassy_time::Timer; 11use embassy_time::Timer;
12use heapless::Vec;
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
13 14
14bind_interrupts!(struct Irqs { 15bind_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());
40pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> {
41 wire: PioOneWire<'d, PIO, SM>,
42}
43 45
44impl<'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. 73fn 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}