aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xci.sh1
-rw-r--r--embassy-boot/boot/src/lib.rs262
-rw-r--r--embassy-boot/nrf/src/lib.rs1
-rw-r--r--embassy-boot/stm32/src/lib.rs1
-rw-r--r--embassy-embedded-hal/src/lib.rs2
-rw-r--r--embassy-executor/src/spawner.rs3
-rw-r--r--embassy-lora/src/lib.rs1
-rw-r--r--embassy-lora/src/stm32wl/mod.rs3
-rw-r--r--embassy-net/src/lib.rs2
-rw-r--r--embassy-net/src/stack.rs3
-rw-r--r--embassy-net/src/tcp.rs6
-rw-r--r--embassy-net/src/udp.rs2
-rw-r--r--embassy-nrf/src/buffered_uarte.rs45
-rw-r--r--embassy-nrf/src/gpiote.rs3
-rw-r--r--embassy-nrf/src/lib.rs2
-rw-r--r--embassy-nrf/src/qdec.rs2
-rw-r--r--embassy-nrf/src/qspi.rs2
-rw-r--r--embassy-nrf/src/rng.rs2
-rw-r--r--embassy-nrf/src/saadc.rs2
-rw-r--r--embassy-nrf/src/spim.rs2
-rw-r--r--embassy-nrf/src/temp.rs2
-rw-r--r--embassy-nrf/src/timer.rs2
-rw-r--r--embassy-nrf/src/twim.rs3
-rw-r--r--embassy-nrf/src/uarte.rs2
-rw-r--r--embassy-nrf/src/usb.rs20
-rw-r--r--embassy-rp/Cargo.toml10
-rw-r--r--embassy-rp/src/clocks.rs2
-rw-r--r--embassy-rp/src/dma.rs21
-rw-r--r--embassy-rp/src/gpio.rs18
-rw-r--r--embassy-rp/src/intrinsics.rs276
-rw-r--r--embassy-rp/src/lib.rs10
-rw-r--r--embassy-rp/src/rom_data.rs733
-rw-r--r--embassy-rp/src/rtc/datetime_chrono.rs62
-rw-r--r--embassy-rp/src/rtc/datetime_no_deps.rs127
-rw-r--r--embassy-rp/src/rtc/filter.rs100
-rw-r--r--embassy-rp/src/rtc/mod.rs188
-rw-r--r--embassy-rp/src/spi.rs56
-rw-r--r--embassy-rp/src/usb.rs30
-rw-r--r--embassy-stm32/Cargo.toml1
-rw-r--r--embassy-stm32/src/can/bxcan.rs23
-rw-r--r--embassy-stm32/src/dcmi.rs6
-rw-r--r--embassy-stm32/src/eth/v1/mod.rs2
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs2
-rw-r--r--embassy-stm32/src/i2c/v2.rs2
-rw-r--r--embassy-stm32/src/lib.rs2
-rw-r--r--embassy-stm32/src/rng.rs2
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs2
-rw-r--r--embassy-stm32/src/spi/mod.rs2
-rw-r--r--embassy-stm32/src/usart/buffered.rs5
-rw-r--r--embassy-stm32/src/usb/usb.rs38
-rw-r--r--embassy-sync/src/lib.rs2
-rw-r--r--embassy-sync/src/mutex.rs19
-rw-r--r--embassy-sync/src/signal.rs81
-rw-r--r--embassy-time/src/lib.rs2
-rw-r--r--embassy-usb-driver/Cargo.toml (renamed from embassy-usb-ncm/Cargo.toml)13
-rw-r--r--embassy-usb-driver/src/lib.rs (renamed from embassy-usb/src/driver.rs)100
-rw-r--r--embassy-usb-hid/Cargo.toml24
-rw-r--r--embassy-usb-hid/src/fmt.rs225
-rw-r--r--embassy-usb-ncm/src/fmt.rs225
-rw-r--r--embassy-usb-serial/Cargo.toml17
-rw-r--r--embassy-usb-serial/src/fmt.rs225
-rw-r--r--embassy-usb/Cargo.toml13
-rw-r--r--embassy-usb/src/builder.rs11
-rw-r--r--embassy-usb/src/class/cdc_acm.rs (renamed from embassy-usb-serial/src/lib.rs)22
-rw-r--r--embassy-usb/src/class/cdc_ncm.rs (renamed from embassy-usb-ncm/src/lib.rs)13
-rw-r--r--embassy-usb/src/class/hid.rs (renamed from embassy-usb-hid/src/lib.rs)24
-rw-r--r--embassy-usb/src/class/mod.rs3
-rw-r--r--embassy-usb/src/control.rs7
-rw-r--r--embassy-usb/src/descriptor.rs7
-rw-r--r--embassy-usb/src/descriptor_reader.rs2
-rw-r--r--embassy-usb/src/lib.rs22
-rw-r--r--embassy-usb/src/types.rs105
-rw-r--r--examples/boot/application/nrf/src/bin/a.rs1
-rw-r--r--examples/boot/application/nrf/src/bin/b.rs1
-rw-r--r--examples/boot/bootloader/nrf/src/main.rs2
-rw-r--r--examples/boot/bootloader/stm32/src/main.rs7
-rw-r--r--examples/nrf-rtos-trace/src/bin/rtos_trace.rs3
-rw-r--r--examples/nrf/Cargo.toml5
-rw-r--r--examples/nrf/src/bin/executor_fairness_test.rs3
-rw-r--r--examples/nrf/src/bin/usb_ethernet.rs3
-rw-r--r--examples/nrf/src/bin/usb_hid_keyboard.rs10
-rw-r--r--examples/nrf/src/bin/usb_hid_mouse.rs7
-rw-r--r--examples/nrf/src/bin/usb_serial.rs5
-rw-r--r--examples/nrf/src/bin/usb_serial_multitask.rs3
-rw-r--r--examples/rp/Cargo.toml5
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs3
-rw-r--r--examples/rp/src/bin/usb_serial.rs5
-rw-r--r--examples/stm32f1/Cargo.toml2
-rw-r--r--examples/stm32f1/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32f3/Cargo.toml3
-rw-r--r--examples/stm32f3/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32h7/src/bin/signal.rs3
-rw-r--r--examples/stm32l0/src/bin/lorawan.rs1
-rw-r--r--examples/stm32l5/Cargo.toml4
-rw-r--r--examples/stm32l5/src/bin/usb_ethernet.rs3
-rw-r--r--examples/stm32l5/src/bin/usb_hid_mouse.rs7
-rw-r--r--examples/stm32l5/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32wl/src/bin/lorawan.rs1
-rw-r--r--examples/stm32wl/src/bin/subghz.rs4
-rw-r--r--rust-toolchain.toml2
-rw-r--r--tests/rp/.cargo/config.toml2
-rw-r--r--tests/rp/Cargo.toml3
-rw-r--r--tests/rp/src/bin/gpio_async.rs2
103 files changed, 2211 insertions, 1159 deletions
diff --git a/ci.sh b/ci.sh
index fa24d5268..cd1c0786c 100755
--- a/ci.sh
+++ b/ci.sh
@@ -58,6 +58,7 @@ cargo batch \
58 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,log \ 58 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,log \
59 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits \ 59 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits \
60 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly \ 60 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly \
61 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,intrinsics \
61 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f410tb,defmt,exti,time-driver-any,unstable-traits \ 62 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f410tb,defmt,exti,time-driver-any,unstable-traits \
62 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits \ 63 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits \
63 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits \ 64 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits \
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs
index 4a2b112a9..8286601ec 100644
--- a/embassy-boot/boot/src/lib.rs
+++ b/embassy-boot/boot/src/lib.rs
@@ -1,5 +1,4 @@
1#![feature(type_alias_impl_trait)] 1#![feature(type_alias_impl_trait)]
2#![feature(generic_associated_types)]
3#![no_std] 2#![no_std]
4#![warn(missing_docs)] 3#![warn(missing_docs)]
5#![doc = include_str!("../../README.md")] 4#![doc = include_str!("../../README.md")]
@@ -222,10 +221,7 @@ impl BootLoader {
222 page: &mut [u8], 221 page: &mut [u8],
223 ) -> Result<State, BootError> { 222 ) -> Result<State, BootError> {
224 // Ensure we have enough progress pages to store copy progress 223 // Ensure we have enough progress pages to store copy progress
225 assert_eq!(self.active.len() % page.len(), 0); 224 assert_partitions(self.active, self.dfu, self.state, page.len(), P::STATE::WRITE_SIZE);
226 assert_eq!(self.dfu.len() % page.len(), 0);
227 assert!(self.dfu.len() - self.active.len() >= page.len());
228 assert!(self.active.len() / page.len() <= (self.state.len() - P::STATE::WRITE_SIZE) / P::STATE::WRITE_SIZE);
229 assert_eq!(magic.len(), P::STATE::WRITE_SIZE); 225 assert_eq!(magic.len(), P::STATE::WRITE_SIZE);
230 226
231 // Copy contents from partition N to active 227 // Copy contents from partition N to active
@@ -409,6 +405,13 @@ impl BootLoader {
409 } 405 }
410} 406}
411 407
408fn assert_partitions(active: Partition, dfu: Partition, state: Partition, page_size: usize, write_size: usize) {
409 assert_eq!(active.len() % page_size, 0);
410 assert_eq!(dfu.len() % page_size, 0);
411 assert!(dfu.len() - active.len() >= page_size);
412 assert!(2 * (active.len() / page_size) <= (state.len() - write_size) / write_size);
413}
414
412/// Convenience provider that uses a single flash for all partitions. 415/// Convenience provider that uses a single flash for all partitions.
413pub struct SingleFlashConfig<'a, F> 416pub struct SingleFlashConfig<'a, F>
414where 417where
@@ -447,24 +450,24 @@ where
447} 450}
448 451
449/// A flash wrapper implementing the Flash and embedded_storage traits. 452/// A flash wrapper implementing the Flash and embedded_storage traits.
450pub struct BootFlash<'a, F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8 = 0xFF> 453pub struct BootFlash<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8 = 0xFF>
451where 454where
452 F: NorFlash + ReadNorFlash, 455 F: NorFlash + ReadNorFlash,
453{ 456{
454 flash: &'a mut F, 457 flash: F,
455} 458}
456 459
457impl<'a, F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> BootFlash<'a, F, BLOCK_SIZE, ERASE_VALUE> 460impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> BootFlash<F, BLOCK_SIZE, ERASE_VALUE>
458where 461where
459 F: NorFlash + ReadNorFlash, 462 F: NorFlash + ReadNorFlash,
460{ 463{
461 /// Create a new instance of a bootable flash 464 /// Create a new instance of a bootable flash
462 pub fn new(flash: &'a mut F) -> Self { 465 pub fn new(flash: F) -> Self {
463 Self { flash } 466 Self { flash }
464 } 467 }
465} 468}
466 469
467impl<'a, F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> Flash for BootFlash<'a, F, BLOCK_SIZE, ERASE_VALUE> 470impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> Flash for BootFlash<F, BLOCK_SIZE, ERASE_VALUE>
468where 471where
469 F: NorFlash + ReadNorFlash, 472 F: NorFlash + ReadNorFlash,
470{ 473{
@@ -472,14 +475,14 @@ where
472 const ERASE_VALUE: u8 = ERASE_VALUE; 475 const ERASE_VALUE: u8 = ERASE_VALUE;
473} 476}
474 477
475impl<'a, F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> ErrorType for BootFlash<'a, F, BLOCK_SIZE, ERASE_VALUE> 478impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> ErrorType for BootFlash<F, BLOCK_SIZE, ERASE_VALUE>
476where 479where
477 F: ReadNorFlash + NorFlash, 480 F: ReadNorFlash + NorFlash,
478{ 481{
479 type Error = F::Error; 482 type Error = F::Error;
480} 483}
481 484
482impl<'a, F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> NorFlash for BootFlash<'a, F, BLOCK_SIZE, ERASE_VALUE> 485impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> NorFlash for BootFlash<F, BLOCK_SIZE, ERASE_VALUE>
483where 486where
484 F: ReadNorFlash + NorFlash, 487 F: ReadNorFlash + NorFlash,
485{ 488{
@@ -487,26 +490,26 @@ where
487 const ERASE_SIZE: usize = F::ERASE_SIZE; 490 const ERASE_SIZE: usize = F::ERASE_SIZE;
488 491
489 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { 492 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
490 F::erase(self.flash, from, to) 493 F::erase(&mut self.flash, from, to)
491 } 494 }
492 495
493 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { 496 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
494 F::write(self.flash, offset, bytes) 497 F::write(&mut self.flash, offset, bytes)
495 } 498 }
496} 499}
497 500
498impl<'a, F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> ReadNorFlash for BootFlash<'a, F, BLOCK_SIZE, ERASE_VALUE> 501impl<F, const BLOCK_SIZE: usize, const ERASE_VALUE: u8> ReadNorFlash for BootFlash<F, BLOCK_SIZE, ERASE_VALUE>
499where 502where
500 F: ReadNorFlash + NorFlash, 503 F: ReadNorFlash + NorFlash,
501{ 504{
502 const READ_SIZE: usize = F::READ_SIZE; 505 const READ_SIZE: usize = F::READ_SIZE;
503 506
504 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { 507 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
505 F::read(self.flash, offset, bytes) 508 F::read(&mut self.flash, offset, bytes)
506 } 509 }
507 510
508 fn capacity(&self) -> usize { 511 fn capacity(&self) -> usize {
509 F::capacity(self.flash) 512 F::capacity(&self.flash)
510 } 513 }
511} 514}
512 515
@@ -601,6 +604,21 @@ impl FirmwareUpdater {
601 self.dfu.len() 604 self.dfu.len()
602 } 605 }
603 606
607 /// Obtain the current state.
608 ///
609 /// This is useful to check if the bootloader has just done a swap, in order
610 /// to do verifications and self-tests of the new image before calling
611 /// `mark_booted`.
612 pub async fn get_state<F: AsyncNorFlash>(&mut self, flash: &mut F, aligned: &mut [u8]) -> Result<State, F::Error> {
613 flash.read(self.state.from as u32, aligned).await?;
614
615 if !aligned.iter().any(|&b| b != SWAP_MAGIC) {
616 Ok(State::Swap)
617 } else {
618 Ok(State::Boot)
619 }
620 }
621
604 /// Mark to trigger firmware swap on next boot. 622 /// Mark to trigger firmware swap on next boot.
605 /// 623 ///
606 /// # Safety 624 /// # Safety
@@ -657,12 +675,6 @@ impl FirmwareUpdater {
657 ) -> Result<(), F::Error> { 675 ) -> Result<(), F::Error> {
658 assert!(data.len() >= F::ERASE_SIZE); 676 assert!(data.len() >= F::ERASE_SIZE);
659 677
660 trace!(
661 "Writing firmware at offset 0x{:x} len {}",
662 self.dfu.from + offset,
663 data.len()
664 );
665
666 flash 678 flash
667 .erase( 679 .erase(
668 (self.dfu.from + offset) as u32, 680 (self.dfu.from + offset) as u32,
@@ -676,7 +688,156 @@ impl FirmwareUpdater {
676 self.dfu.from + offset + data.len() 688 self.dfu.from + offset + data.len()
677 ); 689 );
678 690
679 let mut write_offset = self.dfu.from + offset; 691 FirmwareWriter(self.dfu)
692 .write_block(offset, data, flash, block_size)
693 .await?;
694
695 Ok(())
696 }
697
698 /// Prepare for an incoming DFU update by erasing the entire DFU area and
699 /// returning a `FirmwareWriter`.
700 ///
701 /// Using this instead of `write_firmware` allows for an optimized API in
702 /// exchange for added complexity.
703 pub async fn prepare_update<F: AsyncNorFlash>(&mut self, flash: &mut F) -> Result<FirmwareWriter, F::Error> {
704 flash.erase((self.dfu.from) as u32, (self.dfu.to) as u32).await?;
705
706 trace!("Erased from {} to {}", self.dfu.from, self.dfu.to);
707
708 Ok(FirmwareWriter(self.dfu))
709 }
710
711 //
712 // Blocking API
713 //
714
715 /// Obtain the current state.
716 ///
717 /// This is useful to check if the bootloader has just done a swap, in order
718 /// to do verifications and self-tests of the new image before calling
719 /// `mark_booted`.
720 pub fn get_state_blocking<F: NorFlash>(&mut self, flash: &mut F, aligned: &mut [u8]) -> Result<State, F::Error> {
721 flash.read(self.state.from as u32, aligned)?;
722
723 if !aligned.iter().any(|&b| b != SWAP_MAGIC) {
724 Ok(State::Swap)
725 } else {
726 Ok(State::Boot)
727 }
728 }
729
730 /// Mark to trigger firmware swap on next boot.
731 ///
732 /// # Safety
733 ///
734 /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to.
735 pub fn mark_updated_blocking<F: NorFlash>(&mut self, flash: &mut F, aligned: &mut [u8]) -> Result<(), F::Error> {
736 assert_eq!(aligned.len(), F::WRITE_SIZE);
737 self.set_magic_blocking(aligned, SWAP_MAGIC, flash)
738 }
739
740 /// Mark firmware boot successful and stop rollback on reset.
741 ///
742 /// # Safety
743 ///
744 /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to.
745 pub fn mark_booted_blocking<F: NorFlash>(&mut self, flash: &mut F, aligned: &mut [u8]) -> Result<(), F::Error> {
746 assert_eq!(aligned.len(), F::WRITE_SIZE);
747 self.set_magic_blocking(aligned, BOOT_MAGIC, flash)
748 }
749
750 fn set_magic_blocking<F: NorFlash>(
751 &mut self,
752 aligned: &mut [u8],
753 magic: u8,
754 flash: &mut F,
755 ) -> Result<(), F::Error> {
756 flash.read(self.state.from as u32, aligned)?;
757
758 if aligned.iter().any(|&b| b != magic) {
759 aligned.fill(0);
760
761 flash.write(self.state.from as u32, aligned)?;
762 flash.erase(self.state.from as u32, self.state.to as u32)?;
763
764 aligned.fill(magic);
765 flash.write(self.state.from as u32, aligned)?;
766 }
767 Ok(())
768 }
769
770 /// Write data to a flash page.
771 ///
772 /// The buffer must follow alignment requirements of the target flash and a multiple of page size big.
773 ///
774 /// # Safety
775 ///
776 /// Failing to meet alignment and size requirements may result in a panic.
777 pub fn write_firmware_blocking<F: NorFlash>(
778 &mut self,
779 offset: usize,
780 data: &[u8],
781 flash: &mut F,
782 block_size: usize,
783 ) -> Result<(), F::Error> {
784 assert!(data.len() >= F::ERASE_SIZE);
785
786 flash.erase(
787 (self.dfu.from + offset) as u32,
788 (self.dfu.from + offset + data.len()) as u32,
789 )?;
790
791 trace!(
792 "Erased from {} to {}",
793 self.dfu.from + offset,
794 self.dfu.from + offset + data.len()
795 );
796
797 FirmwareWriter(self.dfu).write_block_blocking(offset, data, flash, block_size)?;
798
799 Ok(())
800 }
801
802 /// Prepare for an incoming DFU update by erasing the entire DFU area and
803 /// returning a `FirmwareWriter`.
804 ///
805 /// Using this instead of `write_firmware_blocking` allows for an optimized
806 /// API in exchange for added complexity.
807 pub fn prepare_update_blocking<F: NorFlash>(&mut self, flash: &mut F) -> Result<FirmwareWriter, F::Error> {
808 flash.erase((self.dfu.from) as u32, (self.dfu.to) as u32)?;
809
810 trace!("Erased from {} to {}", self.dfu.from, self.dfu.to);
811
812 Ok(FirmwareWriter(self.dfu))
813 }
814}
815
816/// FirmwareWriter allows writing blocks to an already erased flash.
817pub struct FirmwareWriter(Partition);
818
819impl FirmwareWriter {
820 /// Write data to a flash page.
821 ///
822 /// The buffer must follow alignment requirements of the target flash and a multiple of page size big.
823 ///
824 /// # Safety
825 ///
826 /// Failing to meet alignment and size requirements may result in a panic.
827 pub async fn write_block<F: AsyncNorFlash>(
828 &mut self,
829 offset: usize,
830 data: &[u8],
831 flash: &mut F,
832 block_size: usize,
833 ) -> Result<(), F::Error> {
834 trace!(
835 "Writing firmware at offset 0x{:x} len {}",
836 self.0.from + offset,
837 data.len()
838 );
839
840 let mut write_offset = self.0.from + offset;
680 for chunk in data.chunks(block_size) { 841 for chunk in data.chunks(block_size) {
681 trace!("Wrote chunk at {}: {:?}", write_offset, chunk); 842 trace!("Wrote chunk at {}: {:?}", write_offset, chunk);
682 flash.write(write_offset as u32, chunk).await?; 843 flash.write(write_offset as u32, chunk).await?;
@@ -699,6 +860,50 @@ impl FirmwareUpdater {
699 860
700 Ok(()) 861 Ok(())
701 } 862 }
863
864 /// Write data to a flash page.
865 ///
866 /// The buffer must follow alignment requirements of the target flash and a multiple of page size big.
867 ///
868 /// # Safety
869 ///
870 /// Failing to meet alignment and size requirements may result in a panic.
871 pub fn write_block_blocking<F: NorFlash>(
872 &mut self,
873 offset: usize,
874 data: &[u8],
875 flash: &mut F,
876 block_size: usize,
877 ) -> Result<(), F::Error> {
878 trace!(
879 "Writing firmware at offset 0x{:x} len {}",
880 self.0.from + offset,
881 data.len()
882 );
883
884 let mut write_offset = self.0.from + offset;
885 for chunk in data.chunks(block_size) {
886 trace!("Wrote chunk at {}: {:?}", write_offset, chunk);
887 flash.write(write_offset as u32, chunk)?;
888 write_offset += chunk.len();
889 }
890 /*
891 trace!("Wrote data, reading back for verification");
892
893 let mut buf: [u8; 4096] = [0; 4096];
894 let mut data_offset = 0;
895 let mut read_offset = self.dfu.from + offset;
896 for chunk in buf.chunks_mut(block_size) {
897 flash.read(read_offset as u32, chunk).await?;
898 trace!("Read chunk at {}: {:?}", read_offset, chunk);
899 assert_eq!(&data[data_offset..data_offset + block_size], chunk);
900 read_offset += chunk.len();
901 data_offset += chunk.len();
902 }
903 */
904
905 Ok(())
906 }
702} 907}
703 908
704#[cfg(test)] 909#[cfg(test)]
@@ -919,6 +1124,15 @@ mod tests {
919 } 1124 }
920 } 1125 }
921 1126
1127 #[test]
1128 #[should_panic]
1129 fn test_range_asserts() {
1130 const ACTIVE: Partition = Partition::new(4096, 4194304);
1131 const DFU: Partition = Partition::new(4194304, 2 * 4194304);
1132 const STATE: Partition = Partition::new(0, 4096);
1133 assert_partitions(ACTIVE, DFU, STATE, 4096, 4);
1134 }
1135
922 struct MemFlash<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize>([u8; SIZE]); 1136 struct MemFlash<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize>([u8; SIZE]);
923 1137
924 impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> NorFlash 1138 impl<const SIZE: usize, const ERASE_SIZE: usize, const WRITE_SIZE: usize> NorFlash
diff --git a/embassy-boot/nrf/src/lib.rs b/embassy-boot/nrf/src/lib.rs
index 0c14781a2..385e089fe 100644
--- a/embassy-boot/nrf/src/lib.rs
+++ b/embassy-boot/nrf/src/lib.rs
@@ -1,5 +1,4 @@
1#![no_std] 1#![no_std]
2#![feature(generic_associated_types)]
3#![feature(type_alias_impl_trait)] 2#![feature(type_alias_impl_trait)]
4#![warn(missing_docs)] 3#![warn(missing_docs)]
5#![doc = include_str!("../../README.md")] 4#![doc = include_str!("../../README.md")]
diff --git a/embassy-boot/stm32/src/lib.rs b/embassy-boot/stm32/src/lib.rs
index 39f080517..edba39cca 100644
--- a/embassy-boot/stm32/src/lib.rs
+++ b/embassy-boot/stm32/src/lib.rs
@@ -1,5 +1,4 @@
1#![no_std] 1#![no_std]
2#![feature(generic_associated_types)]
3#![feature(type_alias_impl_trait)] 2#![feature(type_alias_impl_trait)]
4#![warn(missing_docs)] 3#![warn(missing_docs)]
5#![doc = include_str!("../../README.md")] 4#![doc = include_str!("../../README.md")]
diff --git a/embassy-embedded-hal/src/lib.rs b/embassy-embedded-hal/src/lib.rs
index 0c6f2786a..a12a3a3a0 100644
--- a/embassy-embedded-hal/src/lib.rs
+++ b/embassy-embedded-hal/src/lib.rs
@@ -1,5 +1,5 @@
1#![cfg_attr(not(feature = "std"), no_std)] 1#![cfg_attr(not(feature = "std"), no_std)]
2#![cfg_attr(feature = "nightly", feature(generic_associated_types, type_alias_impl_trait))] 2#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))]
3#![warn(missing_docs)] 3#![warn(missing_docs)]
4 4
5//! Utilities to use `embedded-hal` traits with Embassy. 5//! Utilities to use `embedded-hal` traits with Embassy.
diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs
index 25a0d7dbb..400d973ff 100644
--- a/embassy-executor/src/spawner.rs
+++ b/embassy-executor/src/spawner.rs
@@ -1,10 +1,9 @@
1use core::future::poll_fn;
1use core::marker::PhantomData; 2use core::marker::PhantomData;
2use core::mem; 3use core::mem;
3use core::ptr::NonNull; 4use core::ptr::NonNull;
4use core::task::Poll; 5use core::task::Poll;
5 6
6use futures_util::future::poll_fn;
7
8use super::raw; 7use super::raw;
9 8
10/// Token to spawn a newly-created task in an executor. 9/// Token to spawn a newly-created task in an executor.
diff --git a/embassy-lora/src/lib.rs b/embassy-lora/src/lib.rs
index 2483dcb2e..90ba0d1d4 100644
--- a/embassy-lora/src/lib.rs
+++ b/embassy-lora/src/lib.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![feature(type_alias_impl_trait)] 2#![feature(type_alias_impl_trait)]
3#![feature(generic_associated_types)]
4//! embassy-lora is a collection of async radio drivers that integrate with the lorawan-device 3//! embassy-lora is a collection of async radio drivers that integrate with the lorawan-device
5//! crate's async LoRaWAN MAC implementation. 4//! crate's async LoRaWAN MAC implementation.
6 5
diff --git a/embassy-lora/src/stm32wl/mod.rs b/embassy-lora/src/stm32wl/mod.rs
index 4d11244b6..e28fa2c1a 100644
--- a/embassy-lora/src/stm32wl/mod.rs
+++ b/embassy-lora/src/stm32wl/mod.rs
@@ -1,5 +1,5 @@
1//! A radio driver integration for the radio found on STM32WL family devices. 1//! A radio driver integration for the radio found on STM32WL family devices.
2use core::future::Future; 2use core::future::{poll_fn, Future};
3use core::task::Poll; 3use core::task::Poll;
4 4
5use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; 5use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
@@ -11,7 +11,6 @@ use embassy_stm32::subghz::{
11 Status, SubGhz, TcxoMode, TcxoTrim, Timeout, TxParams, 11 Status, SubGhz, TcxoMode, TcxoTrim, Timeout, TxParams,
12}; 12};
13use embassy_sync::waitqueue::AtomicWaker; 13use embassy_sync::waitqueue::AtomicWaker;
14use futures::future::poll_fn;
15use lorawan_device::async_device::radio::{Bandwidth, PhyRxTx, RfConfig, RxQuality, SpreadingFactor, TxConfig}; 14use lorawan_device::async_device::radio::{Bandwidth, PhyRxTx, RfConfig, RxQuality, SpreadingFactor, TxConfig};
16use lorawan_device::async_device::Timings; 15use lorawan_device::async_device::Timings;
17 16
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index 8eebc798e..4d30550d3 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -1,5 +1,5 @@
1#![cfg_attr(not(feature = "std"), no_std)] 1#![cfg_attr(not(feature = "std"), no_std)]
2#![cfg_attr(feature = "nightly", feature(generic_associated_types, type_alias_impl_trait))] 2#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))]
3 3
4// This mod MUST go first, so that the others see its macros. 4// This mod MUST go first, so that the others see its macros.
5pub(crate) mod fmt; 5pub(crate) mod fmt;
diff --git a/embassy-net/src/stack.rs b/embassy-net/src/stack.rs
index 8d2dd4bca..3a7610758 100644
--- a/embassy-net/src/stack.rs
+++ b/embassy-net/src/stack.rs
@@ -1,10 +1,9 @@
1use core::cell::UnsafeCell; 1use core::cell::UnsafeCell;
2use core::future::Future; 2use core::future::{poll_fn, Future};
3use core::task::{Context, Poll}; 3use core::task::{Context, Poll};
4 4
5use embassy_sync::waitqueue::WakerRegistration; 5use embassy_sync::waitqueue::WakerRegistration;
6use embassy_time::{Instant, Timer}; 6use embassy_time::{Instant, Timer};
7use futures::future::poll_fn;
8use futures::pin_mut; 7use futures::pin_mut;
9use heapless::Vec; 8use heapless::Vec;
10#[cfg(feature = "dhcpv4")] 9#[cfg(feature = "dhcpv4")]
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs
index 0fa873602..f8fff3e2d 100644
--- a/embassy-net/src/tcp.rs
+++ b/embassy-net/src/tcp.rs
@@ -1,8 +1,8 @@
1use core::cell::UnsafeCell; 1use core::cell::UnsafeCell;
2use core::future::poll_fn;
2use core::mem; 3use core::mem;
3use core::task::Poll; 4use core::task::Poll;
4 5
5use futures::future::poll_fn;
6use smoltcp::iface::{Interface, SocketHandle}; 6use smoltcp::iface::{Interface, SocketHandle};
7use smoltcp::socket::tcp; 7use smoltcp::socket::tcp;
8use smoltcp::time::Duration; 8use smoltcp::time::Duration;
@@ -103,7 +103,7 @@ impl<'a> TcpSocket<'a> {
103 Err(tcp::ConnectError::Unaddressable) => return Err(ConnectError::NoRoute), 103 Err(tcp::ConnectError::Unaddressable) => return Err(ConnectError::NoRoute),
104 } 104 }
105 105
106 futures::future::poll_fn(|cx| unsafe { 106 poll_fn(|cx| unsafe {
107 self.io.with_mut(|s, _| match s.state() { 107 self.io.with_mut(|s, _| match s.state() {
108 tcp::State::Closed | tcp::State::TimeWait => Poll::Ready(Err(ConnectError::ConnectionReset)), 108 tcp::State::Closed | tcp::State::TimeWait => Poll::Ready(Err(ConnectError::ConnectionReset)),
109 tcp::State::Listen => unreachable!(), 109 tcp::State::Listen => unreachable!(),
@@ -128,7 +128,7 @@ impl<'a> TcpSocket<'a> {
128 Err(tcp::ListenError::Unaddressable) => return Err(AcceptError::InvalidPort), 128 Err(tcp::ListenError::Unaddressable) => return Err(AcceptError::InvalidPort),
129 } 129 }
130 130
131 futures::future::poll_fn(|cx| unsafe { 131 poll_fn(|cx| unsafe {
132 self.io.with_mut(|s, _| match s.state() { 132 self.io.with_mut(|s, _| match s.state() {
133 tcp::State::Listen | tcp::State::SynSent | tcp::State::SynReceived => { 133 tcp::State::Listen | tcp::State::SynSent | tcp::State::SynReceived => {
134 s.register_send_waker(cx.waker()); 134 s.register_send_waker(cx.waker());
diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs
index 78b09a492..f2e33493c 100644
--- a/embassy-net/src/udp.rs
+++ b/embassy-net/src/udp.rs
@@ -1,8 +1,8 @@
1use core::cell::UnsafeCell; 1use core::cell::UnsafeCell;
2use core::future::poll_fn;
2use core::mem; 3use core::mem;
3use core::task::Poll; 4use core::task::Poll;
4 5
5use futures::future::poll_fn;
6use smoltcp::iface::{Interface, SocketHandle}; 6use smoltcp::iface::{Interface, SocketHandle};
7use smoltcp::socket::udp::{self, PacketMetadata}; 7use smoltcp::socket::udp::{self, PacketMetadata};
8use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; 8use smoltcp::wire::{IpEndpoint, IpListenEndpoint};
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index c3cba2470..6e85a159f 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -15,7 +15,7 @@
15 15
16use core::cell::RefCell; 16use core::cell::RefCell;
17use core::cmp::min; 17use core::cmp::min;
18use core::future::Future; 18use core::future::{poll_fn, Future};
19use core::sync::atomic::{compiler_fence, Ordering}; 19use core::sync::atomic::{compiler_fence, Ordering};
20use core::task::Poll; 20use core::task::Poll;
21 21
@@ -23,11 +23,10 @@ use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorag
23use embassy_hal_common::ring_buffer::RingBuffer; 23use embassy_hal_common::ring_buffer::RingBuffer;
24use embassy_hal_common::{into_ref, PeripheralRef}; 24use embassy_hal_common::{into_ref, PeripheralRef};
25use embassy_sync::waitqueue::WakerRegistration; 25use embassy_sync::waitqueue::WakerRegistration;
26use futures::future::poll_fn;
27// Re-export SVD variants to allow user to directly set values 26// Re-export SVD variants to allow user to directly set values
28pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; 27pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
29 28
30use crate::gpio::Pin as GpioPin; 29use crate::gpio::{self, Pin as GpioPin};
31use crate::interrupt::InterruptExt; 30use crate::interrupt::InterruptExt;
32use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; 31use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
33use crate::timer::{Frequency, Instance as TimerInstance, Timer}; 32use crate::timer::{Frequency, Instance as TimerInstance, Timer};
@@ -429,21 +428,23 @@ impl<'a, U: UarteInstance, T: TimerInstance> Drop for StateInner<'a, U, T> {
429 fn drop(&mut self) { 428 fn drop(&mut self) {
430 let r = U::regs(); 429 let r = U::regs();
431 430
432 // TODO this probably deadlocks. do like Uarte instead.
433
434 self.timer.stop(); 431 self.timer.stop();
435 if let RxState::Receiving = self.rx_state { 432
436 r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); 433 r.inten.reset();
437 } 434 r.events_rxto.reset();
438 if let TxState::Transmitting(_) = self.tx_state { 435 r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
439 r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); 436 r.events_txstopped.reset();
440 } 437 r.tasks_stoptx.write(|w| unsafe { w.bits(1) });
441 if let RxState::Receiving = self.rx_state { 438
442 low_power_wait_until(|| r.events_endrx.read().bits() == 1); 439 while r.events_txstopped.read().bits() == 0 {}
443 } 440 while r.events_rxto.read().bits() == 0 {}
444 if let TxState::Transmitting(_) = self.tx_state { 441
445 low_power_wait_until(|| r.events_endtx.read().bits() == 1); 442 r.enable.write(|w| w.enable().disabled());
446 } 443
444 gpio::deconfigure_pin(r.psel.rxd.read().bits());
445 gpio::deconfigure_pin(r.psel.txd.read().bits());
446 gpio::deconfigure_pin(r.psel.rts.read().bits());
447 gpio::deconfigure_pin(r.psel.cts.read().bits());
447 } 448 }
448} 449}
449 450
@@ -549,13 +550,3 @@ impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for StateInner<'a,
549 trace!("irq: end"); 550 trace!("irq: end");
550 } 551 }
551} 552}
552
553/// Low power blocking wait loop using WFE/SEV.
554fn low_power_wait_until(mut condition: impl FnMut() -> bool) {
555 while !condition() {
556 // WFE might "eat" an event that would have otherwise woken the executor.
557 cortex_m::asm::wfe();
558 }
559 // Retrigger an event to be transparent to the executor.
560 cortex_m::asm::sev();
561}
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index d99f592b0..b418be9d5 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -1,10 +1,9 @@
1use core::convert::Infallible; 1use core::convert::Infallible;
2use core::future::Future; 2use core::future::{poll_fn, Future};
3use core::task::{Context, Poll}; 3use core::task::{Context, Poll};
4 4
5use embassy_hal_common::{impl_peripheral, Peripheral, PeripheralRef}; 5use embassy_hal_common::{impl_peripheral, Peripheral, PeripheralRef};
6use embassy_sync::waitqueue::AtomicWaker; 6use embassy_sync::waitqueue::AtomicWaker;
7use futures::future::poll_fn;
8 7
9use crate::gpio::sealed::Pin as _; 8use crate::gpio::sealed::Pin as _;
10use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin}; 9use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin};
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index f3b3ca0ca..d7bd21702 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -43,7 +43,7 @@
43//! mutable slices always reside in RAM. 43//! mutable slices always reside in RAM.
44 44
45#![no_std] 45#![no_std]
46#![cfg_attr(feature = "nightly", feature(generic_associated_types, type_alias_impl_trait))] 46#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))]
47 47
48#[cfg(not(any( 48#[cfg(not(any(
49 feature = "nrf51", 49 feature = "nrf51",
diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs
index 762e09715..253c85c32 100644
--- a/embassy-nrf/src/qdec.rs
+++ b/embassy-nrf/src/qdec.rs
@@ -1,10 +1,10 @@
1//! Quadrature decoder interface 1//! Quadrature decoder interface
2 2
3use core::future::poll_fn;
3use core::task::Poll; 4use core::task::Poll;
4 5
5use embassy_hal_common::{into_ref, PeripheralRef}; 6use embassy_hal_common::{into_ref, PeripheralRef};
6use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
7use futures::future::poll_fn;
8 8
9use crate::gpio::sealed::Pin as _; 9use crate::gpio::sealed::Pin as _;
10use crate::gpio::{AnyPin, Pin as GpioPin}; 10use crate::gpio::{AnyPin, Pin as GpioPin};
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs
index c97cb1656..ea0a17031 100644
--- a/embassy-nrf/src/qspi.rs
+++ b/embassy-nrf/src/qspi.rs
@@ -1,11 +1,11 @@
1#![macro_use] 1#![macro_use]
2 2
3use core::future::poll_fn;
3use core::ptr; 4use core::ptr;
4use core::task::Poll; 5use core::task::Poll;
5 6
6use embassy_hal_common::drop::DropBomb; 7use embassy_hal_common::drop::DropBomb;
7use embassy_hal_common::{into_ref, PeripheralRef}; 8use embassy_hal_common::{into_ref, PeripheralRef};
8use futures::future::poll_fn;
9 9
10use crate::gpio::{self, Pin as GpioPin}; 10use crate::gpio::{self, Pin as GpioPin};
11use crate::interrupt::{Interrupt, InterruptExt}; 11use crate::interrupt::{Interrupt, InterruptExt};
diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs
index 42da51d0f..e0caeaaee 100644
--- a/embassy-nrf/src/rng.rs
+++ b/embassy-nrf/src/rng.rs
@@ -1,3 +1,4 @@
1use core::future::poll_fn;
1use core::ptr; 2use core::ptr;
2use core::sync::atomic::{AtomicPtr, Ordering}; 3use core::sync::atomic::{AtomicPtr, Ordering};
3use core::task::Poll; 4use core::task::Poll;
@@ -5,7 +6,6 @@ use core::task::Poll;
5use embassy_hal_common::drop::OnDrop; 6use embassy_hal_common::drop::OnDrop;
6use embassy_hal_common::{into_ref, PeripheralRef}; 7use embassy_hal_common::{into_ref, PeripheralRef};
7use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
8use futures::future::poll_fn;
9 9
10use crate::interrupt::InterruptExt; 10use crate::interrupt::InterruptExt;
11use crate::peripherals::RNG; 11use crate::peripherals::RNG;
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs
index 9bc89eb38..d1c82423e 100644
--- a/embassy-nrf/src/saadc.rs
+++ b/embassy-nrf/src/saadc.rs
@@ -1,12 +1,12 @@
1#![macro_use] 1#![macro_use]
2 2
3use core::future::poll_fn;
3use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
4use core::task::Poll; 5use core::task::Poll;
5 6
6use embassy_hal_common::drop::OnDrop; 7use embassy_hal_common::drop::OnDrop;
7use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef}; 8use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
8use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
9use futures::future::poll_fn;
10use pac::{saadc, SAADC}; 10use pac::{saadc, SAADC};
11use saadc::ch::config::{GAIN_A, REFSEL_A, RESP_A, TACQ_A}; 11use saadc::ch::config::{GAIN_A, REFSEL_A, RESP_A, TACQ_A};
12// We treat the positive and negative channels with the same enum values to keep our type tidy and given they are the same 12// We treat the positive and negative channels with the same enum values to keep our type tidy and given they are the same
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index 2955182e4..51cd73a47 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -1,12 +1,12 @@
1#![macro_use] 1#![macro_use]
2 2
3use core::future::poll_fn;
3use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
4use core::task::Poll; 5use core::task::Poll;
5 6
6use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
7use embassy_hal_common::{into_ref, PeripheralRef}; 8use embassy_hal_common::{into_ref, PeripheralRef};
8pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 9pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
9use futures::future::poll_fn;
10pub use pac::spim0::frequency::FREQUENCY_A as Frequency; 10pub use pac::spim0::frequency::FREQUENCY_A as Frequency;
11 11
12use crate::chip::FORCE_COPY_BUFFER_SIZE; 12use crate::chip::FORCE_COPY_BUFFER_SIZE;
diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs
index d520fd686..7a7f61b51 100644
--- a/embassy-nrf/src/temp.rs
+++ b/embassy-nrf/src/temp.rs
@@ -1,12 +1,12 @@
1//! Temperature sensor interface. 1//! Temperature sensor interface.
2 2
3use core::future::poll_fn;
3use core::task::Poll; 4use core::task::Poll;
4 5
5use embassy_hal_common::drop::OnDrop; 6use embassy_hal_common::drop::OnDrop;
6use embassy_hal_common::{into_ref, PeripheralRef}; 7use embassy_hal_common::{into_ref, PeripheralRef};
7use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
8use fixed::types::I30F2; 9use fixed::types::I30F2;
9use futures::future::poll_fn;
10 10
11use crate::interrupt::InterruptExt; 11use crate::interrupt::InterruptExt;
12use crate::peripherals::TEMP; 12use crate::peripherals::TEMP;
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs
index 3de5a8962..bc8710640 100644
--- a/embassy-nrf/src/timer.rs
+++ b/embassy-nrf/src/timer.rs
@@ -1,12 +1,12 @@
1#![macro_use] 1#![macro_use]
2 2
3use core::future::poll_fn;
3use core::marker::PhantomData; 4use core::marker::PhantomData;
4use core::task::Poll; 5use core::task::Poll;
5 6
6use embassy_hal_common::drop::OnDrop; 7use embassy_hal_common::drop::OnDrop;
7use embassy_hal_common::{into_ref, PeripheralRef}; 8use embassy_hal_common::{into_ref, PeripheralRef};
8use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
9use futures::future::poll_fn;
10 10
11use crate::interrupt::{Interrupt, InterruptExt}; 11use crate::interrupt::{Interrupt, InterruptExt};
12use crate::ppi::{Event, Task}; 12use crate::ppi::{Event, Task};
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index 3d4af753a..7c6ca1d30 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -6,7 +6,7 @@
6//! 6//!
7//! - nRF52832: Section 33 7//! - nRF52832: Section 33
8//! - nRF52840: Section 6.31 8//! - nRF52840: Section 6.31
9use core::future::Future; 9use core::future::{poll_fn, Future};
10use core::sync::atomic::compiler_fence; 10use core::sync::atomic::compiler_fence;
11use core::sync::atomic::Ordering::SeqCst; 11use core::sync::atomic::Ordering::SeqCst;
12use core::task::Poll; 12use core::task::Poll;
@@ -16,7 +16,6 @@ use embassy_hal_common::{into_ref, PeripheralRef};
16use embassy_sync::waitqueue::AtomicWaker; 16use embassy_sync::waitqueue::AtomicWaker;
17#[cfg(feature = "time")] 17#[cfg(feature = "time")]
18use embassy_time::{Duration, Instant}; 18use embassy_time::{Duration, Instant};
19use futures::future::poll_fn;
20 19
21use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; 20use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
22use crate::gpio::Pin as GpioPin; 21use crate::gpio::Pin as GpioPin;
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index c250e24ca..5f9c4f17d 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -13,12 +13,12 @@
13//! memory may be used given that buffers are passed in directly to its read and write 13//! memory may be used given that buffers are passed in directly to its read and write
14//! methods. 14//! methods.
15 15
16use core::future::poll_fn;
16use core::sync::atomic::{compiler_fence, Ordering}; 17use core::sync::atomic::{compiler_fence, Ordering};
17use core::task::Poll; 18use core::task::Poll;
18 19
19use embassy_hal_common::drop::OnDrop; 20use embassy_hal_common::drop::OnDrop;
20use embassy_hal_common::{into_ref, PeripheralRef}; 21use embassy_hal_common::{into_ref, PeripheralRef};
21use futures::future::poll_fn;
22use pac::uarte0::RegisterBlock; 22use pac::uarte0::RegisterBlock;
23// Re-export SVD variants to allow user to directly set values. 23// Re-export SVD variants to allow user to directly set values.
24pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; 24pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity};
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs
index 688326e9c..20510eb49 100644
--- a/embassy-nrf/src/usb.rs
+++ b/embassy-nrf/src/usb.rs
@@ -1,5 +1,6 @@
1#![macro_use] 1#![macro_use]
2 2
3use core::future::{poll_fn, Future};
3use core::marker::PhantomData; 4use core::marker::PhantomData;
4use core::mem::MaybeUninit; 5use core::mem::MaybeUninit;
5use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; 6use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering};
@@ -9,10 +10,9 @@ use cortex_m::peripheral::NVIC;
9use embassy_hal_common::{into_ref, PeripheralRef}; 10use embassy_hal_common::{into_ref, PeripheralRef};
10use embassy_sync::waitqueue::AtomicWaker; 11use embassy_sync::waitqueue::AtomicWaker;
11pub use embassy_usb; 12pub use embassy_usb;
12use embassy_usb::driver::{self, EndpointError, Event, Unsupported}; 13use embassy_usb::driver::{
13use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; 14 self, Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
14use futures::future::poll_fn; 15};
15use futures::Future;
16use pac::usbd::RegisterBlock; 16use pac::usbd::RegisterBlock;
17 17
18use crate::interrupt::{Interrupt, InterruptExt}; 18use crate::interrupt::{Interrupt, InterruptExt};
@@ -244,7 +244,7 @@ impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P>
244 interval: u8, 244 interval: u8,
245 ) -> Result<Self::EndpointIn, driver::EndpointAllocError> { 245 ) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
246 let index = self.alloc_in.allocate(ep_type)?; 246 let index = self.alloc_in.allocate(ep_type)?;
247 let ep_addr = EndpointAddress::from_parts(index, UsbDirection::In); 247 let ep_addr = EndpointAddress::from_parts(index, Direction::In);
248 Ok(Endpoint::new(EndpointInfo { 248 Ok(Endpoint::new(EndpointInfo {
249 addr: ep_addr, 249 addr: ep_addr,
250 ep_type, 250 ep_type,
@@ -260,7 +260,7 @@ impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P>
260 interval: u8, 260 interval: u8,
261 ) -> Result<Self::EndpointOut, driver::EndpointAllocError> { 261 ) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
262 let index = self.alloc_out.allocate(ep_type)?; 262 let index = self.alloc_out.allocate(ep_type)?;
263 let ep_addr = EndpointAddress::from_parts(index, UsbDirection::Out); 263 let ep_addr = EndpointAddress::from_parts(index, Direction::Out);
264 Ok(Endpoint::new(EndpointInfo { 264 Ok(Endpoint::new(EndpointInfo {
265 addr: ep_addr, 265 addr: ep_addr,
266 ep_type, 266 ep_type,
@@ -429,8 +429,8 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
429 let regs = T::regs(); 429 let regs = T::regs();
430 let i = ep_addr.index(); 430 let i = ep_addr.index();
431 match ep_addr.direction() { 431 match ep_addr.direction() {
432 UsbDirection::Out => regs.halted.epout[i].read().getstatus().is_halted(), 432 Direction::Out => regs.halted.epout[i].read().getstatus().is_halted(),
433 UsbDirection::In => regs.halted.epin[i].read().getstatus().is_halted(), 433 Direction::In => regs.halted.epin[i].read().getstatus().is_halted(),
434 } 434 }
435 } 435 }
436 436
@@ -443,7 +443,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
443 debug!("endpoint_set_enabled {:?} {}", ep_addr, enabled); 443 debug!("endpoint_set_enabled {:?} {}", ep_addr, enabled);
444 444
445 match ep_addr.direction() { 445 match ep_addr.direction() {
446 UsbDirection::In => { 446 Direction::In => {
447 let mut was_enabled = false; 447 let mut was_enabled = false;
448 regs.epinen.modify(|r, w| { 448 regs.epinen.modify(|r, w| {
449 let mut bits = r.bits(); 449 let mut bits = r.bits();
@@ -467,7 +467,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
467 467
468 In::waker(i).wake(); 468 In::waker(i).wake();
469 } 469 }
470 UsbDirection::Out => { 470 Direction::Out => {
471 regs.epouten.modify(|r, w| { 471 regs.epouten.modify(|r, w| {
472 let mut bits = r.bits(); 472 let mut bits = r.bits();
473 if enabled { 473 if enabled {
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 3debca710..d0cf8025c 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
6[package.metadata.embassy_docs] 6[package.metadata.embassy_docs]
7src_base = "https://github.com/embassy-rs/embassy/blob/embassy-rp-v$VERSION/embassy-rp/src/" 7src_base = "https://github.com/embassy-rs/embassy/blob/embassy-rp-v$VERSION/embassy-rp/src/"
8src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-rp/src/" 8src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-rp/src/"
9features = ["nightly", "defmt", "unstable-pac", "unstable-traits"] 9features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver"]
10flavors = [ 10flavors = [
11 { name = "rp2040", target = "thumbv6m-none-eabi" }, 11 { name = "rp2040", target = "thumbv6m-none-eabi" },
12] 12]
@@ -20,6 +20,12 @@ defmt = ["dep:defmt", "embassy-usb?/defmt"]
20# There are no plans to make this stable. 20# There are no plans to make this stable.
21unstable-pac = [] 21unstable-pac = []
22 22
23time-driver = []
24
25rom-func-cache = []
26intrinsics = []
27rom-v2-intrinsics = []
28
23# Enable nightly-only features 29# Enable nightly-only features
24nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb", "dep:embedded-io"] 30nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb", "dep:embedded-io"]
25 31
@@ -31,6 +37,7 @@ unstable-traits = ["embedded-hal-1"]
31embassy-sync = { version = "0.1.0", path = "../embassy-sync" } 37embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
32embassy-executor = { version = "0.1.0", path = "../embassy-executor" } 38embassy-executor = { version = "0.1.0", path = "../embassy-executor" }
33embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } 39embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
40embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
34embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-2"]} 41embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-2"]}
35embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } 42embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
36embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 43embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
@@ -44,6 +51,7 @@ cortex-m-rt = ">=0.6.15,<0.8"
44cortex-m = "0.7.6" 51cortex-m = "0.7.6"
45critical-section = "1.1" 52critical-section = "1.1"
46futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 53futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
54chrono = { version = "0.4", default-features = false, optional = true }
47embedded-io = { version = "0.3.0", features = ["async"], optional = true } 55embedded-io = { version = "0.3.0", features = ["async"], optional = true }
48 56
49rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] } 57rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] }
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 3ad1e5d82..1c446f389 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -122,7 +122,7 @@ pub(crate) fn clk_peri_freq() -> u32 {
122 125_000_000 122 125_000_000
123} 123}
124 124
125pub(crate) fn _clk_rtc_freq() -> u32 { 125pub(crate) fn clk_rtc_freq() -> u32 {
126 46875 126 46875
127} 127}
128 128
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs
index acf338225..410c48666 100644
--- a/embassy-rp/src/dma.rs
+++ b/embassy-rp/src/dma.rs
@@ -1,3 +1,4 @@
1use core::future::Future;
1use core::pin::Pin; 2use core::pin::Pin;
2use core::sync::atomic::{compiler_fence, Ordering}; 3use core::sync::atomic::{compiler_fence, Ordering};
3use core::task::{Context, Poll}; 4use core::task::{Context, Poll};
@@ -5,7 +6,6 @@ use core::task::{Context, Poll};
5use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; 6use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
6use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; 7use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef};
7use embassy_sync::waitqueue::AtomicWaker; 8use embassy_sync::waitqueue::AtomicWaker;
8use futures::Future;
9use pac::dma::vals::DataSize; 9use pac::dma::vals::DataSize;
10 10
11use crate::pac::dma::vals; 11use crate::pac::dma::vals;
@@ -75,6 +75,25 @@ pub unsafe fn write<'a, C: Channel, W: Word>(
75 ) 75 )
76} 76}
77 77
78pub unsafe fn write_repeated<'a, C: Channel, W: Word>(
79 ch: impl Peripheral<P = C> + 'a,
80 to: *mut W,
81 len: usize,
82 dreq: u8,
83) -> Transfer<'a, C> {
84 let dummy: u32 = 0;
85 copy_inner(
86 ch,
87 &dummy as *const u32,
88 to as *mut u32,
89 len,
90 W::size(),
91 false,
92 false,
93 dreq,
94 )
95}
96
78pub unsafe fn copy<'a, C: Channel, W: Word>( 97pub unsafe fn copy<'a, C: Channel, W: Word>(
79 ch: impl Peripheral<P = C> + 'a, 98 ch: impl Peripheral<P = C> + 'a,
80 from: &[W], 99 from: &[W],
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index a0328302a..9b9a08110 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -159,7 +159,7 @@ unsafe fn IO_IRQ_BANK0() {
159 w.set_edge_low(pin_group, false); 159 w.set_edge_low(pin_group, false);
160 } 160 }
161 InterruptTrigger::LevelHigh => { 161 InterruptTrigger::LevelHigh => {
162 debug!("IO_IRQ_BANK0 pin {} LevelHigh triggered\n", pin); 162 debug!("IO_IRQ_BANK0 pin {} LevelHigh triggered", pin);
163 w.set_level_high(pin_group, false); 163 w.set_level_high(pin_group, false);
164 } 164 }
165 InterruptTrigger::LevelLow => { 165 InterruptTrigger::LevelLow => {
@@ -198,7 +198,7 @@ impl<'d, T: Pin> InputFuture<'d, T> {
198 critical_section::with(|_| { 198 critical_section::with(|_| {
199 pin.int_proc().inte((pin.pin() / 8) as usize).modify(|w| match level { 199 pin.int_proc().inte((pin.pin() / 8) as usize).modify(|w| match level {
200 InterruptTrigger::LevelHigh => { 200 InterruptTrigger::LevelHigh => {
201 debug!("InputFuture::new enable LevelHigh for pin {} \n", pin.pin()); 201 debug!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
202 w.set_level_high(pin_group, true); 202 w.set_level_high(pin_group, true);
203 } 203 }
204 InterruptTrigger::LevelLow => { 204 InterruptTrigger::LevelLow => {
@@ -245,45 +245,45 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> {
245 // the pin and if it has been disabled that means it was done by the 245 // the pin and if it has been disabled that means it was done by the
246 // interrupt service routine, so we then know that the event/trigger 246 // interrupt service routine, so we then know that the event/trigger
247 // happened and Poll::Ready will be returned. 247 // happened and Poll::Ready will be returned.
248 debug!("{:?} for pin {}\n", self.level, self.pin.pin()); 248 debug!("{:?} for pin {}", self.level, self.pin.pin());
249 match self.level { 249 match self.level {
250 InterruptTrigger::AnyEdge => { 250 InterruptTrigger::AnyEdge => {
251 if !inte.edge_high(pin_group) && !inte.edge_low(pin_group) { 251 if !inte.edge_high(pin_group) && !inte.edge_low(pin_group) {
252 #[rustfmt::skip] 252 #[rustfmt::skip]
253 debug!("{:?} for pin {} was cleared, return Poll::Ready\n", self.level, self.pin.pin()); 253 debug!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
254 return Poll::Ready(()); 254 return Poll::Ready(());
255 } 255 }
256 } 256 }
257 InterruptTrigger::LevelHigh => { 257 InterruptTrigger::LevelHigh => {
258 if !inte.level_high(pin_group) { 258 if !inte.level_high(pin_group) {
259 #[rustfmt::skip] 259 #[rustfmt::skip]
260 debug!("{:?} for pin {} was cleared, return Poll::Ready\n", self.level, self.pin.pin()); 260 debug!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
261 return Poll::Ready(()); 261 return Poll::Ready(());
262 } 262 }
263 } 263 }
264 InterruptTrigger::LevelLow => { 264 InterruptTrigger::LevelLow => {
265 if !inte.level_low(pin_group) { 265 if !inte.level_low(pin_group) {
266 #[rustfmt::skip] 266 #[rustfmt::skip]
267 debug!("{:?} for pin {} was cleared, return Poll::Ready\n", self.level, self.pin.pin()); 267 debug!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
268 return Poll::Ready(()); 268 return Poll::Ready(());
269 } 269 }
270 } 270 }
271 InterruptTrigger::EdgeHigh => { 271 InterruptTrigger::EdgeHigh => {
272 if !inte.edge_high(pin_group) { 272 if !inte.edge_high(pin_group) {
273 #[rustfmt::skip] 273 #[rustfmt::skip]
274 debug!("{:?} for pin {} was cleared, return Poll::Ready\n", self.level, self.pin.pin()); 274 debug!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
275 return Poll::Ready(()); 275 return Poll::Ready(());
276 } 276 }
277 } 277 }
278 InterruptTrigger::EdgeLow => { 278 InterruptTrigger::EdgeLow => {
279 if !inte.edge_low(pin_group) { 279 if !inte.edge_low(pin_group) {
280 #[rustfmt::skip] 280 #[rustfmt::skip]
281 debug!("{:?} for pin {} was cleared, return Poll::Ready\n", self.level, self.pin.pin()); 281 debug!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
282 return Poll::Ready(()); 282 return Poll::Ready(());
283 } 283 }
284 } 284 }
285 } 285 }
286 debug!("InputFuture::poll return Poll::Pending\n"); 286 debug!("InputFuture::poll return Poll::Pending");
287 Poll::Pending 287 Poll::Pending
288 } 288 }
289} 289}
diff --git a/embassy-rp/src/intrinsics.rs b/embassy-rp/src/intrinsics.rs
new file mode 100644
index 000000000..3e75fb7fc
--- /dev/null
+++ b/embassy-rp/src/intrinsics.rs
@@ -0,0 +1,276 @@
1#![macro_use]
2
3// Credit: taken from `rp-hal` (also licensed Apache+MIT)
4// https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/intrinsics.rs
5
6/// Generate a series of aliases for an intrinsic function.
7macro_rules! intrinsics_aliases {
8 (
9 extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty,
10 ) => {};
11 (
12 unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty,
13 ) => {};
14
15 (
16 extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty,
17 $alias:ident
18 $($rest:ident)*
19 ) => {
20 #[cfg(all(target_arch = "arm", feature = "intrinsics"))]
21 intrinsics! {
22 extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
23 $name($($argname),*)
24 }
25 }
26
27 intrinsics_aliases! {
28 extern $abi fn $name( $($argname: $ty),* ) -> $ret,
29 $($rest)*
30 }
31 };
32
33 (
34 unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty,
35 $alias:ident
36 $($rest:ident)*
37 ) => {
38 #[cfg(all(target_arch = "arm", feature = "intrinsics"))]
39 intrinsics! {
40 unsafe extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
41 $name($($argname),*)
42 }
43 }
44
45 intrinsics_aliases! {
46 unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret,
47 $($rest)*
48 }
49 };
50}
51
52/// The macro used to define overridden intrinsics.
53///
54/// This is heavily inspired by the macro used by compiler-builtins. The idea
55/// is to abstract anything special that needs to be done to override an
56/// intrinsic function. Intrinsic generation is disabled for non-ARM targets
57/// so things like CI and docs generation do not have problems. Additionally
58/// they can be disabled by disabling the crate feature `intrinsics` for
59/// testing or comparing performance.
60///
61/// Like the compiler-builtins macro, it accepts a series of functions that
62/// looks like normal Rust code:
63///
64/// intrinsics! {
65/// extern "C" fn foo(a: i32) -> u32 {
66/// // ...
67/// }
68///
69/// #[nonstandard_attribute]
70/// extern "C" fn bar(a: i32) -> u32 {
71/// // ...
72/// }
73/// }
74///
75/// Each function can also be decorated with nonstandard attributes to control
76/// additional behaviour:
77///
78/// * `slower_than_default` - indicates that the override is slower than the
79/// default implementation. Currently this just disables the override
80/// entirely.
81/// * `bootrom_v2` - indicates that the override is only available
82/// on a V2 bootrom or higher. Only enabled when the feature
83/// `rom-v2-intrinsics` is set.
84/// * `alias` - accepts a list of names to alias the intrinsic to.
85/// * `aeabi` - accepts a list of ARM EABI names to alias to.
86///
87macro_rules! intrinsics {
88 () => {};
89
90 (
91 #[slower_than_default]
92 $(#[$($attr:tt)*])*
93 extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
94 $($body:tt)*
95 }
96
97 $($rest:tt)*
98 ) => {
99 // Not exported, but defined so the actual implementation is
100 // considered used
101 #[allow(dead_code)]
102 fn $name( $($argname: $ty),* ) -> $ret {
103 $($body)*
104 }
105
106 intrinsics!($($rest)*);
107 };
108
109 (
110 #[bootrom_v2]
111 $(#[$($attr:tt)*])*
112 extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
113 $($body:tt)*
114 }
115
116 $($rest:tt)*
117 ) => {
118 // Not exported, but defined so the actual implementation is
119 // considered used
120 #[cfg(not(feature = "rom-v2-intrinsics"))]
121 #[allow(dead_code)]
122 fn $name( $($argname: $ty),* ) -> $ret {
123 $($body)*
124 }
125
126 #[cfg(feature = "rom-v2-intrinsics")]
127 intrinsics! {
128 $(#[$($attr)*])*
129 extern $abi fn $name( $($argname: $ty),* ) -> $ret {
130 $($body)*
131 }
132 }
133
134 intrinsics!($($rest)*);
135 };
136
137 (
138 #[alias = $($alias:ident),*]
139 $(#[$($attr:tt)*])*
140 extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
141 $($body:tt)*
142 }
143
144 $($rest:tt)*
145 ) => {
146 intrinsics! {
147 $(#[$($attr)*])*
148 extern $abi fn $name( $($argname: $ty),* ) -> $ret {
149 $($body)*
150 }
151 }
152
153 intrinsics_aliases! {
154 extern $abi fn $name( $($argname: $ty),* ) -> $ret,
155 $($alias) *
156 }
157
158 intrinsics!($($rest)*);
159 };
160
161 (
162 #[alias = $($alias:ident),*]
163 $(#[$($attr:tt)*])*
164 unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
165 $($body:tt)*
166 }
167
168 $($rest:tt)*
169 ) => {
170 intrinsics! {
171 $(#[$($attr)*])*
172 unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret {
173 $($body)*
174 }
175 }
176
177 intrinsics_aliases! {
178 unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret,
179 $($alias) *
180 }
181
182 intrinsics!($($rest)*);
183 };
184
185 (
186 #[aeabi = $($alias:ident),*]
187 $(#[$($attr:tt)*])*
188 extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
189 $($body:tt)*
190 }
191
192 $($rest:tt)*
193 ) => {
194 intrinsics! {
195 $(#[$($attr)*])*
196 extern $abi fn $name( $($argname: $ty),* ) -> $ret {
197 $($body)*
198 }
199 }
200
201 intrinsics_aliases! {
202 extern "aapcs" fn $name( $($argname: $ty),* ) -> $ret,
203 $($alias) *
204 }
205
206 intrinsics!($($rest)*);
207 };
208
209 (
210 $(#[$($attr:tt)*])*
211 extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
212 $($body:tt)*
213 }
214
215 $($rest:tt)*
216 ) => {
217 #[cfg(all(target_arch = "arm", feature = "intrinsics"))]
218 $(#[$($attr)*])*
219 extern $abi fn $name( $($argname: $ty),* ) -> $ret {
220 $($body)*
221 }
222
223 #[cfg(all(target_arch = "arm", feature = "intrinsics"))]
224 mod $name {
225 #[no_mangle]
226 $(#[$($attr)*])*
227 pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
228 super::$name($($argname),*)
229 }
230 }
231
232 // Not exported, but defined so the actual implementation is
233 // considered used
234 #[cfg(not(all(target_arch = "arm", feature = "intrinsics")))]
235 #[allow(dead_code)]
236 fn $name( $($argname: $ty),* ) -> $ret {
237 $($body)*
238 }
239
240 intrinsics!($($rest)*);
241 };
242
243 (
244 $(#[$($attr:tt)*])*
245 unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
246 $($body:tt)*
247 }
248
249 $($rest:tt)*
250 ) => {
251 #[cfg(all(target_arch = "arm", feature = "intrinsics"))]
252 $(#[$($attr)*])*
253 unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret {
254 $($body)*
255 }
256
257 #[cfg(all(target_arch = "arm", feature = "intrinsics"))]
258 mod $name {
259 #[no_mangle]
260 $(#[$($attr)*])*
261 pub unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret {
262 super::$name($($argname),*)
263 }
264 }
265
266 // Not exported, but defined so the actual implementation is
267 // considered used
268 #[cfg(not(all(target_arch = "arm", feature = "intrinsics")))]
269 #[allow(dead_code)]
270 unsafe fn $name( $($argname: $ty),* ) -> $ret {
271 $($body)*
272 }
273
274 intrinsics!($($rest)*);
275 };
276}
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index aebbbf567..9ac98d226 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -1,13 +1,18 @@
1#![no_std] 1#![no_std]
2#![cfg_attr(feature = "nightly", feature(generic_associated_types, type_alias_impl_trait))] 2#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))]
3 3
4// This mod MUST go first, so that the others see its macros. 4// This mod MUST go first, so that the others see its macros.
5pub(crate) mod fmt; 5pub(crate) mod fmt;
6 6
7mod intrinsics;
8
7pub mod dma; 9pub mod dma;
8pub mod gpio; 10pub mod gpio;
9pub mod interrupt; 11pub mod interrupt;
12pub mod rom_data;
13pub mod rtc;
10pub mod spi; 14pub mod spi;
15#[cfg(feature = "time-driver")]
11pub mod timer; 16pub mod timer;
12pub mod uart; 17pub mod uart;
13#[cfg(feature = "nightly")] 18#[cfg(feature = "nightly")]
@@ -84,6 +89,8 @@ embassy_hal_common::peripherals! {
84 DMA_CH11, 89 DMA_CH11,
85 90
86 USB, 91 USB,
92
93 RTC,
87} 94}
88 95
89#[link_section = ".boot2"] 96#[link_section = ".boot2"]
@@ -108,6 +115,7 @@ pub fn init(_config: config::Config) -> Peripherals {
108 115
109 unsafe { 116 unsafe {
110 clocks::init(); 117 clocks::init();
118 #[cfg(feature = "time-driver")]
111 timer::init(); 119 timer::init();
112 dma::init(); 120 dma::init();
113 } 121 }
diff --git a/embassy-rp/src/rom_data.rs b/embassy-rp/src/rom_data.rs
new file mode 100644
index 000000000..757a27114
--- /dev/null
+++ b/embassy-rp/src/rom_data.rs
@@ -0,0 +1,733 @@
1//! Functions and data from the RPI Bootrom.
2//!
3//! From the [RP2040 datasheet](https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf), Section 2.8.2.1:
4//!
5//! > The Bootrom contains a number of public functions that provide useful
6//! > RP2040 functionality that might be needed in the absence of any other code
7//! > on the device, as well as highly optimized versions of certain key
8//! > functionality that would otherwise have to take up space in most user
9//! > binaries.
10
11// Credit: taken from `rp-hal` (also licensed Apache+MIT)
12// https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/rom_data.rs
13
14/// A bootrom function table code.
15pub type RomFnTableCode = [u8; 2];
16
17/// This function searches for (table)
18type RomTableLookupFn<T> = unsafe extern "C" fn(*const u16, u32) -> T;
19
20/// The following addresses are described at `2.8.2. Bootrom Contents`
21/// Pointer to the lookup table function supplied by the rom.
22const ROM_TABLE_LOOKUP_PTR: *const u16 = 0x0000_0018 as _;
23
24/// Pointer to helper functions lookup table.
25const FUNC_TABLE: *const u16 = 0x0000_0014 as _;
26
27/// Pointer to the public data lookup table.
28const DATA_TABLE: *const u16 = 0x0000_0016 as _;
29
30/// Address of the version number of the ROM.
31const VERSION_NUMBER: *const u8 = 0x0000_0013 as _;
32
33/// Retrive rom content from a table using a code.
34fn rom_table_lookup<T>(table: *const u16, tag: RomFnTableCode) -> T {
35 unsafe {
36 let rom_table_lookup_ptr: *const u32 = rom_hword_as_ptr(ROM_TABLE_LOOKUP_PTR);
37 let rom_table_lookup: RomTableLookupFn<T> = core::mem::transmute(rom_table_lookup_ptr);
38 rom_table_lookup(rom_hword_as_ptr(table) as *const u16, u16::from_le_bytes(tag) as u32)
39 }
40}
41
42/// To save space, the ROM likes to store memory pointers (which are 32-bit on
43/// the Cortex-M0+) using only the bottom 16-bits. The assumption is that the
44/// values they point at live in the first 64 KiB of ROM, and the ROM is mapped
45/// to address `0x0000_0000` and so 16-bits are always sufficient.
46///
47/// This functions grabs a 16-bit value from ROM and expands it out to a full 32-bit pointer.
48unsafe fn rom_hword_as_ptr(rom_address: *const u16) -> *const u32 {
49 let ptr: u16 = *rom_address;
50 ptr as *const u32
51}
52
53macro_rules! declare_rom_function {
54 (
55 $(#[$outer:meta])*
56 fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty
57 $lookup:block
58 ) => {
59 #[doc = r"Additional access for the `"]
60 #[doc = stringify!($name)]
61 #[doc = r"` ROM function."]
62 pub mod $name {
63 /// Retrieve a function pointer.
64 #[cfg(not(feature = "rom-func-cache"))]
65 pub fn ptr() -> extern "C" fn( $($argname: $ty),* ) -> $ret {
66 let p: *const u32 = $lookup;
67 unsafe {
68 let func : extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p);
69 func
70 }
71 }
72
73 /// Retrieve a function pointer.
74 #[cfg(feature = "rom-func-cache")]
75 pub fn ptr() -> extern "C" fn( $($argname: $ty),* ) -> $ret {
76 use core::sync::atomic::{AtomicU16, Ordering};
77
78 // All pointers in the ROM fit in 16 bits, so we don't need a
79 // full width word to store the cached value.
80 static CACHED_PTR: AtomicU16 = AtomicU16::new(0);
81 // This is safe because the lookup will always resolve
82 // to the same value. So even if an interrupt or another
83 // core starts at the same time, it just repeats some
84 // work and eventually writes back the correct value.
85 let p: *const u32 = match CACHED_PTR.load(Ordering::Relaxed) {
86 0 => {
87 let raw: *const u32 = $lookup;
88 CACHED_PTR.store(raw as u16, Ordering::Relaxed);
89 raw
90 },
91 val => val as *const u32,
92 };
93 unsafe {
94 let func : extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p);
95 func
96 }
97 }
98 }
99
100 $(#[$outer])*
101 pub extern "C" fn $name( $($argname: $ty),* ) -> $ret {
102 $name::ptr()($($argname),*)
103 }
104 };
105
106 (
107 $(#[$outer:meta])*
108 unsafe fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty
109 $lookup:block
110 ) => {
111 #[doc = r"Additional access for the `"]
112 #[doc = stringify!($name)]
113 #[doc = r"` ROM function."]
114 pub mod $name {
115 /// Retrieve a function pointer.
116 #[cfg(not(feature = "rom-func-cache"))]
117 pub fn ptr() -> unsafe extern "C" fn( $($argname: $ty),* ) -> $ret {
118 let p: *const u32 = $lookup;
119 unsafe {
120 let func : unsafe extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p);
121 func
122 }
123 }
124
125 /// Retrieve a function pointer.
126 #[cfg(feature = "rom-func-cache")]
127 pub fn ptr() -> unsafe extern "C" fn( $($argname: $ty),* ) -> $ret {
128 use core::sync::atomic::{AtomicU16, Ordering};
129
130 // All pointers in the ROM fit in 16 bits, so we don't need a
131 // full width word to store the cached value.
132 static CACHED_PTR: AtomicU16 = AtomicU16::new(0);
133 // This is safe because the lookup will always resolve
134 // to the same value. So even if an interrupt or another
135 // core starts at the same time, it just repeats some
136 // work and eventually writes back the correct value.
137 let p: *const u32 = match CACHED_PTR.load(Ordering::Relaxed) {
138 0 => {
139 let raw: *const u32 = $lookup;
140 CACHED_PTR.store(raw as u16, Ordering::Relaxed);
141 raw
142 },
143 val => val as *const u32,
144 };
145 unsafe {
146 let func : unsafe extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p);
147 func
148 }
149 }
150 }
151
152 $(#[$outer])*
153 pub unsafe extern "C" fn $name( $($argname: $ty),* ) -> $ret {
154 $name::ptr()($($argname),*)
155 }
156 };
157}
158
159macro_rules! rom_functions {
160 () => {};
161
162 (
163 $(#[$outer:meta])*
164 $c:literal fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty;
165
166 $($rest:tt)*
167 ) => {
168 declare_rom_function! {
169 $(#[$outer])*
170 fn $name( $($argname: $ty),* ) -> $ret {
171 $crate::rom_data::rom_table_lookup($crate::rom_data::FUNC_TABLE, *$c)
172 }
173 }
174
175 rom_functions!($($rest)*);
176 };
177
178 (
179 $(#[$outer:meta])*
180 $c:literal unsafe fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty;
181
182 $($rest:tt)*
183 ) => {
184 declare_rom_function! {
185 $(#[$outer])*
186 unsafe fn $name( $($argname: $ty),* ) -> $ret {
187 $crate::rom_data::rom_table_lookup($crate::rom_data::FUNC_TABLE, *$c)
188 }
189 }
190
191 rom_functions!($($rest)*);
192 };
193}
194
195rom_functions! {
196 /// Return a count of the number of 1 bits in value.
197 b"P3" fn popcount32(value: u32) -> u32;
198
199 /// Return the bits of value in the reverse order.
200 b"R3" fn reverse32(value: u32) -> u32;
201
202 /// Return the number of consecutive high order 0 bits of value. If value is zero, returns 32.
203 b"L3" fn clz32(value: u32) -> u32;
204
205 /// Return the number of consecutive low order 0 bits of value. If value is zero, returns 32.
206 b"T3" fn ctz32(value: u32) -> u32;
207
208 /// Resets the RP2040 and uses the watchdog facility to re-start in BOOTSEL mode:
209 /// * gpio_activity_pin_mask is provided to enable an 'activity light' via GPIO attached LED
210 /// for the USB Mass Storage Device:
211 /// * 0 No pins are used as per cold boot.
212 /// * Otherwise a single bit set indicating which GPIO pin should be set to output and
213 /// raised whenever there is mass storage activity from the host.
214 /// * disable_interface_mask may be used to control the exposed USB interfaces:
215 /// * 0 To enable both interfaces (as per cold boot).
216 /// * 1 To disable the USB Mass Storage Interface.
217 /// * 2 to Disable the USB PICOBOOT Interface.
218 b"UB" fn reset_to_usb_boot(gpio_activity_pin_mask: u32, disable_interface_mask: u32) -> ();
219
220 /// Sets n bytes start at ptr to the value c and returns ptr
221 b"MS" unsafe fn memset(ptr: *mut u8, c: u8, n: u32) -> *mut u8;
222
223 /// Sets n bytes start at ptr to the value c and returns ptr.
224 ///
225 /// Note this is a slightly more efficient variant of _memset that may only
226 /// be used if ptr is word aligned.
227 // Note the datasheet does not match the actual ROM for the code here, see
228 // https://github.com/raspberrypi/pico-feedback/issues/217
229 b"S4" unsafe fn memset4(ptr: *mut u32, c: u8, n: u32) -> *mut u32;
230
231 /// Copies n bytes starting at src to dest and returns dest. The results are undefined if the
232 /// regions overlap.
233 b"MC" unsafe fn memcpy(dest: *mut u8, src: *const u8, n: u32) -> *mut u8;
234
235 /// Copies n bytes starting at src to dest and returns dest. The results are undefined if the
236 /// regions overlap.
237 ///
238 /// Note this is a slightly more efficient variant of _memcpy that may only be
239 /// used if dest and src are word aligned.
240 b"C4" unsafe fn memcpy44(dest: *mut u32, src: *const u32, n: u32) -> *mut u8;
241
242 /// Restore all QSPI pad controls to their default state, and connect the SSI to the QSPI pads.
243 b"IF" unsafe fn connect_internal_flash() -> ();
244
245 /// First set up the SSI for serial-mode operations, then issue the fixed XIP exit sequence.
246 ///
247 /// Note that the bootrom code uses the IO forcing logic to drive the CS pin, which must be
248 /// cleared before returning the SSI to XIP mode (e.g. by a call to _flash_flush_cache). This
249 /// function configures the SSI with a fixed SCK clock divisor of /6.
250 b"EX" unsafe fn flash_exit_xip() -> ();
251
252 /// Erase a count bytes, starting at addr (offset from start of flash). Optionally, pass a
253 /// block erase command e.g. D8h block erase, and the size of the block erased by this
254 /// command — this function will use the larger block erase where possible, for much higher
255 /// erase speed. addr must be aligned to a 4096-byte sector, and count must be a multiple of
256 /// 4096 bytes.
257 b"RE" unsafe fn flash_range_erase(addr: u32, count: usize, block_size: u32, block_cmd: u8) -> ();
258
259 /// Program data to a range of flash addresses starting at `addr` (and
260 /// offset from the start of flash) and `count` bytes in size. The value
261 /// `addr` must be aligned to a 256-byte boundary, and `count` must be a
262 /// multiple of 256.
263 b"RP" unsafe fn flash_range_program(addr: u32, data: *const u8, count: usize) -> ();
264
265 /// Flush and enable the XIP cache. Also clears the IO forcing on QSPI CSn, so that the SSI can
266 /// drive the flashchip select as normal.
267 b"FC" unsafe fn flash_flush_cache() -> ();
268
269 /// Configure the SSI to generate a standard 03h serial read command, with 24 address bits,
270 /// upon each XIP access. This is a very slow XIP configuration, but is very widely supported.
271 /// The debugger calls this function after performing a flash erase/programming operation, so
272 /// that the freshly-programmed code and data is visible to the debug host, without having to
273 /// know exactly what kind of flash device is connected.
274 b"CX" unsafe fn flash_enter_cmd_xip() -> ();
275
276 /// This is the method that is entered by core 1 on reset to wait to be launched by core 0.
277 /// There are few cases where you should call this method (resetting core 1 is much better).
278 /// This method does not return and should only ever be called on core 1.
279 b"WV" unsafe fn wait_for_vector() -> !;
280}
281
282// Various C intrinsics in the ROM
283intrinsics! {
284 #[alias = __popcountdi2]
285 extern "C" fn __popcountsi2(x: u32) -> u32 {
286 popcount32(x)
287 }
288
289 #[alias = __clzdi2]
290 extern "C" fn __clzsi2(x: u32) -> u32 {
291 clz32(x)
292 }
293
294 #[alias = __ctzdi2]
295 extern "C" fn __ctzsi2(x: u32) -> u32 {
296 ctz32(x)
297 }
298
299 // __rbit is only unofficial, but it show up in the ARM documentation,
300 // so may as well hook it up.
301 #[alias = __rbitl]
302 extern "C" fn __rbit(x: u32) -> u32 {
303 reverse32(x)
304 }
305
306 unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) -> () {
307 // Different argument order
308 memset(dest, c as u8, n as u32);
309 }
310
311 #[alias = __aeabi_memset8]
312 unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) -> () {
313 // Different argument order
314 memset4(dest as *mut u32, c as u8, n as u32);
315 }
316
317 unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) -> () {
318 memset(dest, 0, n as u32);
319 }
320
321 #[alias = __aeabi_memclr8]
322 unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) -> () {
323 memset4(dest as *mut u32, 0, n as u32);
324 }
325
326 unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) -> () {
327 memcpy(dest, src, n as u32);
328 }
329
330 #[alias = __aeabi_memcpy8]
331 unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) -> () {
332 memcpy44(dest as *mut u32, src as *const u32, n as u32);
333 }
334}
335
336unsafe fn convert_str(s: *const u8) -> &'static str {
337 let mut end = s;
338 while *end != 0 {
339 end = end.add(1);
340 }
341 let s = core::slice::from_raw_parts(s, end.offset_from(s) as usize);
342 core::str::from_utf8_unchecked(s)
343}
344
345/// The version number of the rom.
346pub fn rom_version_number() -> u8 {
347 unsafe { *VERSION_NUMBER }
348}
349
350/// The Raspberry Pi Trading Ltd copyright string.
351pub fn copyright_string() -> &'static str {
352 let s: *const u8 = rom_table_lookup(DATA_TABLE, *b"CR");
353 unsafe { convert_str(s) }
354}
355
356/// The 8 most significant hex digits of the Bootrom git revision.
357pub fn git_revision() -> u32 {
358 let s: *const u32 = rom_table_lookup(DATA_TABLE, *b"GR");
359 unsafe { *s }
360}
361
362/// The start address of the floating point library code and data.
363///
364/// This and fplib_end along with the individual function pointers in
365/// soft_float_table can be used to copy the floating point implementation into
366/// RAM if desired.
367pub fn fplib_start() -> *const u8 {
368 rom_table_lookup(DATA_TABLE, *b"FS")
369}
370
371/// See Table 180 in the RP2040 datasheet for the contents of this table.
372pub fn soft_float_table() -> *const usize {
373 rom_table_lookup(DATA_TABLE, *b"SF")
374}
375
376/// The end address of the floating point library code and data.
377pub fn fplib_end() -> *const u8 {
378 rom_table_lookup(DATA_TABLE, *b"FE")
379}
380
381/// This entry is only present in the V2 bootrom. See Table 182 in the RP2040 datasheet for the contents of this table.
382pub fn soft_double_table() -> *const usize {
383 if rom_version_number() < 2 {
384 panic!(
385 "Double precision operations require V2 bootrom (found: V{})",
386 rom_version_number()
387 );
388 }
389 rom_table_lookup(DATA_TABLE, *b"SD")
390}
391
392/// ROM functions using single-precision arithmetic (i.e. 'f32' in Rust terms)
393pub mod float_funcs {
394
395 macro_rules! make_functions {
396 (
397 $(
398 $(#[$outer:meta])*
399 $offset:literal $name:ident (
400 $( $aname:ident : $aty:ty ),*
401 ) -> $ret:ty;
402 )*
403 ) => {
404 $(
405 declare_rom_function! {
406 $(#[$outer])*
407 fn $name( $( $aname : $aty ),* ) -> $ret {
408 let table: *const usize = $crate::rom_data::soft_float_table();
409 unsafe {
410 // This is the entry in the table. Our offset is given as a
411 // byte offset, but we want the table index (each pointer in
412 // the table is 4 bytes long)
413 let entry: *const usize = table.offset($offset / 4);
414 // Read the pointer from the table
415 core::ptr::read(entry) as *const u32
416 }
417 }
418 }
419 )*
420 }
421 }
422
423 make_functions! {
424 /// Calculates `a + b`
425 0x00 fadd(a: f32, b: f32) -> f32;
426 /// Calculates `a - b`
427 0x04 fsub(a: f32, b: f32) -> f32;
428 /// Calculates `a * b`
429 0x08 fmul(a: f32, b: f32) -> f32;
430 /// Calculates `a / b`
431 0x0c fdiv(a: f32, b: f32) -> f32;
432
433 // 0x10 and 0x14 are deprecated
434
435 /// Calculates `sqrt(v)` (or return -Infinity if v is negative)
436 0x18 fsqrt(v: f32) -> f32;
437 /// Converts an f32 to a signed integer,
438 /// rounding towards -Infinity, and clamping the result to lie within the
439 /// range `-0x80000000` to `0x7FFFFFFF`
440 0x1c float_to_int(v: f32) -> i32;
441 /// Converts an f32 to an signed fixed point
442 /// integer representation where n specifies the position of the binary
443 /// point in the resulting fixed point representation, e.g.
444 /// `f(0.5f, 16) == 0x8000`. This method rounds towards -Infinity,
445 /// and clamps the resulting integer to lie within the range `0x00000000` to
446 /// `0xFFFFFFFF`
447 0x20 float_to_fix(v: f32, n: i32) -> i32;
448 /// Converts an f32 to an unsigned integer,
449 /// rounding towards -Infinity, and clamping the result to lie within the
450 /// range `0x00000000` to `0xFFFFFFFF`
451 0x24 float_to_uint(v: f32) -> u32;
452 /// Converts an f32 to an unsigned fixed point
453 /// integer representation where n specifies the position of the binary
454 /// point in the resulting fixed point representation, e.g.
455 /// `f(0.5f, 16) == 0x8000`. This method rounds towards -Infinity,
456 /// and clamps the resulting integer to lie within the range `0x00000000` to
457 /// `0xFFFFFFFF`
458 0x28 float_to_ufix(v: f32, n: i32) -> u32;
459 /// Converts a signed integer to the nearest
460 /// f32 value, rounding to even on tie
461 0x2c int_to_float(v: i32) -> f32;
462 /// Converts a signed fixed point integer
463 /// representation to the nearest f32 value, rounding to even on tie. `n`
464 /// specifies the position of the binary point in fixed point, so `f =
465 /// nearest(v/(2^n))`
466 0x30 fix_to_float(v: i32, n: i32) -> f32;
467 /// Converts an unsigned integer to the nearest
468 /// f32 value, rounding to even on tie
469 0x34 uint_to_float(v: u32) -> f32;
470 /// Converts an unsigned fixed point integer
471 /// representation to the nearest f32 value, rounding to even on tie. `n`
472 /// specifies the position of the binary point in fixed point, so `f =
473 /// nearest(v/(2^n))`
474 0x38 ufix_to_float(v: u32, n: i32) -> f32;
475 /// Calculates the cosine of `angle`. The value
476 /// of `angle` is in radians, and must be in the range `-1024` to `1024`
477 0x3c fcos(angle: f32) -> f32;
478 /// Calculates the sine of `angle`. The value of
479 /// `angle` is in radians, and must be in the range `-1024` to `1024`
480 0x40 fsin(angle: f32) -> f32;
481 /// Calculates the tangent of `angle`. The value
482 /// of `angle` is in radians, and must be in the range `-1024` to `1024`
483 0x44 ftan(angle: f32) -> f32;
484
485 // 0x48 is deprecated
486
487 /// Calculates the exponential value of `v`,
488 /// i.e. `e ** v`
489 0x4c fexp(v: f32) -> f32;
490 /// Calculates the natural logarithm of `v`. If `v <= 0` return -Infinity
491 0x50 fln(v: f32) -> f32;
492 }
493
494 macro_rules! make_functions_v2 {
495 (
496 $(
497 $(#[$outer:meta])*
498 $offset:literal $name:ident (
499 $( $aname:ident : $aty:ty ),*
500 ) -> $ret:ty;
501 )*
502 ) => {
503 $(
504 declare_rom_function! {
505 $(#[$outer])*
506 fn $name( $( $aname : $aty ),* ) -> $ret {
507 if $crate::rom_data::rom_version_number() < 2 {
508 panic!(
509 "Floating point function requires V2 bootrom (found: V{})",
510 $crate::rom_data::rom_version_number()
511 );
512 }
513 let table: *const usize = $crate::rom_data::soft_float_table();
514 unsafe {
515 // This is the entry in the table. Our offset is given as a
516 // byte offset, but we want the table index (each pointer in
517 // the table is 4 bytes long)
518 let entry: *const usize = table.offset($offset / 4);
519 // Read the pointer from the table
520 core::ptr::read(entry) as *const u32
521 }
522 }
523 }
524 )*
525 }
526 }
527
528 // These are only on BootROM v2 or higher
529 make_functions_v2! {
530 /// Compares two floating point numbers, returning:
531 /// • 0 if a == b
532 /// • -1 if a < b
533 /// • 1 if a > b
534 0x54 fcmp(a: f32, b: f32) -> i32;
535 /// Computes the arc tangent of `y/x` using the
536 /// signs of arguments to determine the correct quadrant
537 0x58 fatan2(y: f32, x: f32) -> f32;
538 /// Converts a signed 64-bit integer to the
539 /// nearest f32 value, rounding to even on tie
540 0x5c int64_to_float(v: i64) -> f32;
541 /// Converts a signed fixed point 64-bit integer
542 /// representation to the nearest f32 value, rounding to even on tie. `n`
543 /// specifies the position of the binary point in fixed point, so `f =
544 /// nearest(v/(2^n))`
545 0x60 fix64_to_float(v: i64, n: i32) -> f32;
546 /// Converts an unsigned 64-bit integer to the
547 /// nearest f32 value, rounding to even on tie
548 0x64 uint64_to_float(v: u64) -> f32;
549 /// Converts an unsigned fixed point 64-bit
550 /// integer representation to the nearest f32 value, rounding to even on
551 /// tie. `n` specifies the position of the binary point in fixed point, so
552 /// `f = nearest(v/(2^n))`
553 0x68 ufix64_to_float(v: u64, n: i32) -> f32;
554 /// Convert an f32 to a signed 64-bit integer, rounding towards -Infinity,
555 /// and clamping the result to lie within the range `-0x8000000000000000` to
556 /// `0x7FFFFFFFFFFFFFFF`
557 0x6c float_to_int64(v: f32) -> i64;
558 /// Converts an f32 to a signed fixed point
559 /// 64-bit integer representation where n specifies the position of the
560 /// binary point in the resulting fixed point representation - e.g. `f(0.5f,
561 /// 16) == 0x8000`. This method rounds towards -Infinity, and clamps the
562 /// resulting integer to lie within the range `-0x8000000000000000` to
563 /// `0x7FFFFFFFFFFFFFFF`
564 0x70 float_to_fix64(v: f32, n: i32) -> f32;
565 /// Converts an f32 to an unsigned 64-bit
566 /// integer, rounding towards -Infinity, and clamping the result to lie
567 /// within the range `0x0000000000000000` to `0xFFFFFFFFFFFFFFFF`
568 0x74 float_to_uint64(v: f32) -> u64;
569 /// Converts an f32 to an unsigned fixed point
570 /// 64-bit integer representation where n specifies the position of the
571 /// binary point in the resulting fixed point representation, e.g. `f(0.5f,
572 /// 16) == 0x8000`. This method rounds towards -Infinity, and clamps the
573 /// resulting integer to lie within the range `0x0000000000000000` to
574 /// `0xFFFFFFFFFFFFFFFF`
575 0x78 float_to_ufix64(v: f32, n: i32) -> u64;
576 /// Converts an f32 to an f64.
577 0x7c float_to_double(v: f32) -> f64;
578 }
579}
580
581/// Functions using double-precision arithmetic (i.e. 'f64' in Rust terms)
582pub mod double_funcs {
583
584 macro_rules! make_double_funcs {
585 (
586 $(
587 $(#[$outer:meta])*
588 $offset:literal $name:ident (
589 $( $aname:ident : $aty:ty ),*
590 ) -> $ret:ty;
591 )*
592 ) => {
593 $(
594 declare_rom_function! {
595 $(#[$outer])*
596 fn $name( $( $aname : $aty ),* ) -> $ret {
597 let table: *const usize = $crate::rom_data::soft_double_table();
598 unsafe {
599 // This is the entry in the table. Our offset is given as a
600 // byte offset, but we want the table index (each pointer in
601 // the table is 4 bytes long)
602 let entry: *const usize = table.offset($offset / 4);
603 // Read the pointer from the table
604 core::ptr::read(entry) as *const u32
605 }
606 }
607 }
608 )*
609 }
610 }
611
612 make_double_funcs! {
613 /// Calculates `a + b`
614 0x00 dadd(a: f64, b: f64) -> f64;
615 /// Calculates `a - b`
616 0x04 dsub(a: f64, b: f64) -> f64;
617 /// Calculates `a * b`
618 0x08 dmul(a: f64, b: f64) -> f64;
619 /// Calculates `a / b`
620 0x0c ddiv(a: f64, b: f64) -> f64;
621
622 // 0x10 and 0x14 are deprecated
623
624 /// Calculates `sqrt(v)` (or return -Infinity if v is negative)
625 0x18 dsqrt(v: f64) -> f64;
626 /// Converts an f64 to a signed integer,
627 /// rounding towards -Infinity, and clamping the result to lie within the
628 /// range `-0x80000000` to `0x7FFFFFFF`
629 0x1c double_to_int(v: f64) -> i32;
630 /// Converts an f64 to an signed fixed point
631 /// integer representation where n specifies the position of the binary
632 /// point in the resulting fixed point representation, e.g.
633 /// `f(0.5f, 16) == 0x8000`. This method rounds towards -Infinity,
634 /// and clamps the resulting integer to lie within the range `0x00000000` to
635 /// `0xFFFFFFFF`
636 0x20 double_to_fix(v: f64, n: i32) -> i32;
637 /// Converts an f64 to an unsigned integer,
638 /// rounding towards -Infinity, and clamping the result to lie within the
639 /// range `0x00000000` to `0xFFFFFFFF`
640 0x24 double_to_uint(v: f64) -> u32;
641 /// Converts an f64 to an unsigned fixed point
642 /// integer representation where n specifies the position of the binary
643 /// point in the resulting fixed point representation, e.g.
644 /// `f(0.5f, 16) == 0x8000`. This method rounds towards -Infinity,
645 /// and clamps the resulting integer to lie within the range `0x00000000` to
646 /// `0xFFFFFFFF`
647 0x28 double_to_ufix(v: f64, n: i32) -> u32;
648 /// Converts a signed integer to the nearest
649 /// double value, rounding to even on tie
650 0x2c int_to_double(v: i32) -> f64;
651 /// Converts a signed fixed point integer
652 /// representation to the nearest double value, rounding to even on tie. `n`
653 /// specifies the position of the binary point in fixed point, so `f =
654 /// nearest(v/(2^n))`
655 0x30 fix_to_double(v: i32, n: i32) -> f64;
656 /// Converts an unsigned integer to the nearest
657 /// double value, rounding to even on tie
658 0x34 uint_to_double(v: u32) -> f64;
659 /// Converts an unsigned fixed point integer
660 /// representation to the nearest double value, rounding to even on tie. `n`
661 /// specifies the position of the binary point in fixed point, so f =
662 /// nearest(v/(2^n))
663 0x38 ufix_to_double(v: u32, n: i32) -> f64;
664 /// Calculates the cosine of `angle`. The value
665 /// of `angle` is in radians, and must be in the range `-1024` to `1024`
666 0x3c dcos(angle: f64) -> f64;
667 /// Calculates the sine of `angle`. The value of
668 /// `angle` is in radians, and must be in the range `-1024` to `1024`
669 0x40 dsin(angle: f64) -> f64;
670 /// Calculates the tangent of `angle`. The value
671 /// of `angle` is in radians, and must be in the range `-1024` to `1024`
672 0x44 dtan(angle: f64) -> f64;
673
674 // 0x48 is deprecated
675
676 /// Calculates the exponential value of `v`,
677 /// i.e. `e ** v`
678 0x4c dexp(v: f64) -> f64;
679 /// Calculates the natural logarithm of v. If v <= 0 return -Infinity
680 0x50 dln(v: f64) -> f64;
681
682 // These are only on BootROM v2 or higher
683
684 /// Compares two floating point numbers, returning:
685 /// • 0 if a == b
686 /// • -1 if a < b
687 /// • 1 if a > b
688 0x54 dcmp(a: f64, b: f64) -> i32;
689 /// Computes the arc tangent of `y/x` using the
690 /// signs of arguments to determine the correct quadrant
691 0x58 datan2(y: f64, x: f64) -> f64;
692 /// Converts a signed 64-bit integer to the
693 /// nearest double value, rounding to even on tie
694 0x5c int64_to_double(v: i64) -> f64;
695 /// Converts a signed fixed point 64-bit integer
696 /// representation to the nearest double value, rounding to even on tie. `n`
697 /// specifies the position of the binary point in fixed point, so `f =
698 /// nearest(v/(2^n))`
699 0x60 fix64_to_doubl(v: i64, n: i32) -> f64;
700 /// Converts an unsigned 64-bit integer to the
701 /// nearest double value, rounding to even on tie
702 0x64 uint64_to_double(v: u64) -> f64;
703 /// Converts an unsigned fixed point 64-bit
704 /// integer representation to the nearest double value, rounding to even on
705 /// tie. `n` specifies the position of the binary point in fixed point, so
706 /// `f = nearest(v/(2^n))`
707 0x68 ufix64_to_double(v: u64, n: i32) -> f64;
708 /// Convert an f64 to a signed 64-bit integer, rounding towards -Infinity,
709 /// and clamping the result to lie within the range `-0x8000000000000000` to
710 /// `0x7FFFFFFFFFFFFFFF`
711 0x6c double_to_int64(v: f64) -> i64;
712 /// Converts an f64 to a signed fixed point
713 /// 64-bit integer representation where n specifies the position of the
714 /// binary point in the resulting fixed point representation - e.g. `f(0.5f,
715 /// 16) == 0x8000`. This method rounds towards -Infinity, and clamps the
716 /// resulting integer to lie within the range `-0x8000000000000000` to
717 /// `0x7FFFFFFFFFFFFFFF`
718 0x70 double_to_fix64(v: f64, n: i32) -> i64;
719 /// Converts an f64 to an unsigned 64-bit
720 /// integer, rounding towards -Infinity, and clamping the result to lie
721 /// within the range `0x0000000000000000` to `0xFFFFFFFFFFFFFFFF`
722 0x74 double_to_uint64(v: f64) -> u64;
723 /// Converts an f64 to an unsigned fixed point
724 /// 64-bit integer representation where n specifies the position of the
725 /// binary point in the resulting fixed point representation, e.g. `f(0.5f,
726 /// 16) == 0x8000`. This method rounds towards -Infinity, and clamps the
727 /// resulting integer to lie within the range `0x0000000000000000` to
728 /// `0xFFFFFFFFFFFFFFFF`
729 0x78 double_to_ufix64(v: f64, n: i32) -> u64;
730 /// Converts an f64 to an f32
731 0x7c double_to_float(v: f64) -> f32;
732 }
733}
diff --git a/embassy-rp/src/rtc/datetime_chrono.rs b/embassy-rp/src/rtc/datetime_chrono.rs
new file mode 100644
index 000000000..b3c78dd47
--- /dev/null
+++ b/embassy-rp/src/rtc/datetime_chrono.rs
@@ -0,0 +1,62 @@
1use chrono::{Datelike, Timelike};
2
3use crate::pac::rtc::regs::{Rtc0, Rtc1, Setup0, Setup1};
4
5/// Alias for [`chrono::NaiveDateTime`]
6pub type DateTime = chrono::NaiveDateTime;
7/// Alias for [`chrono::Weekday`]
8pub type DayOfWeek = chrono::Weekday;
9
10/// Errors regarding the [`DateTime`] and [`DateTimeFilter`] structs.
11///
12/// [`DateTimeFilter`]: struct.DateTimeFilter.html
13#[derive(Clone, Debug, PartialEq, Eq)]
14pub enum Error {
15 /// The [DateTime] has an invalid year. The year must be between 0 and 4095.
16 InvalidYear,
17 /// The [DateTime] contains an invalid date.
18 InvalidDate,
19 /// The [DateTime] contains an invalid time.
20 InvalidTime,
21}
22
23pub(super) fn day_of_week_to_u8(dotw: DayOfWeek) -> u8 {
24 dotw.num_days_from_sunday() as u8
25}
26
27pub(crate) fn validate_datetime(dt: &DateTime) -> Result<(), Error> {
28 if dt.year() < 0 || dt.year() > 4095 {
29 // rp2040 can't hold these years
30 Err(Error::InvalidYear)
31 } else {
32 // The rest of the chrono date is assumed to be valid
33 Ok(())
34 }
35}
36
37pub(super) fn write_setup_0(dt: &DateTime, w: &mut Setup0) {
38 w.set_year(dt.year() as u16);
39 w.set_month(dt.month() as u8);
40 w.set_day(dt.day() as u8);
41}
42
43pub(super) fn write_setup_1(dt: &DateTime, w: &mut Setup1) {
44 w.set_dotw(dt.weekday().num_days_from_sunday() as u8);
45 w.set_hour(dt.hour() as u8);
46 w.set_min(dt.minute() as u8);
47 w.set_sec(dt.second() as u8);
48}
49
50pub(super) fn datetime_from_registers(rtc_0: Rtc0, rtc_1: Rtc1) -> Result<DateTime, Error> {
51 let year = rtc_1.year() as i32;
52 let month = rtc_1.month() as u32;
53 let day = rtc_1.day() as u32;
54
55 let hour = rtc_0.hour() as u32;
56 let minute = rtc_0.min() as u32;
57 let second = rtc_0.sec() as u32;
58
59 let date = chrono::NaiveDate::from_ymd_opt(year, month, day).ok_or(Error::InvalidDate)?;
60 let time = chrono::NaiveTime::from_hms_opt(hour, minute, second).ok_or(Error::InvalidTime)?;
61 Ok(DateTime::new(date, time))
62}
diff --git a/embassy-rp/src/rtc/datetime_no_deps.rs b/embassy-rp/src/rtc/datetime_no_deps.rs
new file mode 100644
index 000000000..92770e984
--- /dev/null
+++ b/embassy-rp/src/rtc/datetime_no_deps.rs
@@ -0,0 +1,127 @@
1use crate::pac::rtc::regs::{Rtc0, Rtc1, Setup0, Setup1};
2
3/// Errors regarding the [`DateTime`] and [`DateTimeFilter`] structs.
4///
5/// [`DateTimeFilter`]: struct.DateTimeFilter.html
6#[derive(Clone, Debug, PartialEq, Eq)]
7pub enum Error {
8 /// The [DateTime] contains an invalid year value. Must be between `0..=4095`.
9 InvalidYear,
10 /// The [DateTime] contains an invalid month value. Must be between `1..=12`.
11 InvalidMonth,
12 /// The [DateTime] contains an invalid day value. Must be between `1..=31`.
13 InvalidDay,
14 /// The [DateTime] contains an invalid day of week. Must be between `0..=6` where 0 is Sunday.
15 InvalidDayOfWeek(
16 /// The value of the DayOfWeek that was given.
17 u8,
18 ),
19 /// The [DateTime] contains an invalid hour value. Must be between `0..=23`.
20 InvalidHour,
21 /// The [DateTime] contains an invalid minute value. Must be between `0..=59`.
22 InvalidMinute,
23 /// The [DateTime] contains an invalid second value. Must be between `0..=59`.
24 InvalidSecond,
25}
26
27/// Structure containing date and time information
28pub struct DateTime {
29 /// 0..4095
30 pub year: u16,
31 /// 1..12, 1 is January
32 pub month: u8,
33 /// 1..28,29,30,31 depending on month
34 pub day: u8,
35 ///
36 pub day_of_week: DayOfWeek,
37 /// 0..23
38 pub hour: u8,
39 /// 0..59
40 pub minute: u8,
41 /// 0..59
42 pub second: u8,
43}
44
45/// A day of the week
46#[repr(u8)]
47#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
48#[allow(missing_docs)]
49pub enum DayOfWeek {
50 Sunday = 0,
51 Monday = 1,
52 Tuesday = 2,
53 Wednesday = 3,
54 Thursday = 4,
55 Friday = 5,
56 Saturday = 6,
57}
58
59fn day_of_week_from_u8(v: u8) -> Result<DayOfWeek, Error> {
60 Ok(match v {
61 0 => DayOfWeek::Sunday,
62 1 => DayOfWeek::Monday,
63 2 => DayOfWeek::Tuesday,
64 3 => DayOfWeek::Wednesday,
65 4 => DayOfWeek::Thursday,
66 5 => DayOfWeek::Friday,
67 6 => DayOfWeek::Saturday,
68 x => return Err(Error::InvalidDayOfWeek(x)),
69 })
70}
71
72pub(super) fn day_of_week_to_u8(dotw: DayOfWeek) -> u8 {
73 dotw as u8
74}
75
76pub(super) fn validate_datetime(dt: &DateTime) -> Result<(), Error> {
77 if dt.year > 4095 {
78 Err(Error::InvalidYear)
79 } else if dt.month < 1 || dt.month > 12 {
80 Err(Error::InvalidMonth)
81 } else if dt.day < 1 || dt.day > 31 {
82 Err(Error::InvalidDay)
83 } else if dt.hour > 23 {
84 Err(Error::InvalidHour)
85 } else if dt.minute > 59 {
86 Err(Error::InvalidMinute)
87 } else if dt.second > 59 {
88 Err(Error::InvalidSecond)
89 } else {
90 Ok(())
91 }
92}
93
94pub(super) fn write_setup_0(dt: &DateTime, w: &mut Setup0) {
95 w.set_year(dt.year);
96 w.set_month(dt.month);
97 w.set_day(dt.day);
98}
99
100pub(super) fn write_setup_1(dt: &DateTime, w: &mut Setup1) {
101 w.set_dotw(dt.day_of_week as u8);
102 w.set_hour(dt.hour);
103 w.set_min(dt.minute);
104 w.set_sec(dt.second);
105}
106
107pub(super) fn datetime_from_registers(rtc_0: Rtc0, rtc_1: Rtc1) -> Result<DateTime, Error> {
108 let year = rtc_1.year();
109 let month = rtc_1.month();
110 let day = rtc_1.day();
111
112 let day_of_week = rtc_0.dotw();
113 let hour = rtc_0.hour();
114 let minute = rtc_0.min();
115 let second = rtc_0.sec();
116
117 let day_of_week = day_of_week_from_u8(day_of_week)?;
118 Ok(DateTime {
119 year,
120 month,
121 day,
122 day_of_week,
123 hour,
124 minute,
125 second,
126 })
127}
diff --git a/embassy-rp/src/rtc/filter.rs b/embassy-rp/src/rtc/filter.rs
new file mode 100644
index 000000000..d4a3bab2f
--- /dev/null
+++ b/embassy-rp/src/rtc/filter.rs
@@ -0,0 +1,100 @@
1use super::DayOfWeek;
2use crate::pac::rtc::regs::{IrqSetup0, IrqSetup1};
3
4/// A filter used for [`RealTimeClock::schedule_alarm`].
5///
6/// [`RealTimeClock::schedule_alarm`]: struct.RealTimeClock.html#method.schedule_alarm
7#[derive(Default)]
8pub struct DateTimeFilter {
9 /// The year that this alarm should trigger on, `None` if the RTC alarm should not trigger on a year value.
10 pub year: Option<u16>,
11 /// The month that this alarm should trigger on, `None` if the RTC alarm should not trigger on a month value.
12 pub month: Option<u8>,
13 /// The day that this alarm should trigger on, `None` if the RTC alarm should not trigger on a day value.
14 pub day: Option<u8>,
15 /// The day of week that this alarm should trigger on, `None` if the RTC alarm should not trigger on a day of week value.
16 pub day_of_week: Option<DayOfWeek>,
17 /// The hour that this alarm should trigger on, `None` if the RTC alarm should not trigger on a hour value.
18 pub hour: Option<u8>,
19 /// The minute that this alarm should trigger on, `None` if the RTC alarm should not trigger on a minute value.
20 pub minute: Option<u8>,
21 /// The second that this alarm should trigger on, `None` if the RTC alarm should not trigger on a second value.
22 pub second: Option<u8>,
23}
24
25impl DateTimeFilter {
26 /// Set a filter on the given year
27 pub fn year(mut self, year: u16) -> Self {
28 self.year = Some(year);
29 self
30 }
31 /// Set a filter on the given month
32 pub fn month(mut self, month: u8) -> Self {
33 self.month = Some(month);
34 self
35 }
36 /// Set a filter on the given day
37 pub fn day(mut self, day: u8) -> Self {
38 self.day = Some(day);
39 self
40 }
41 /// Set a filter on the given day of the week
42 pub fn day_of_week(mut self, day_of_week: DayOfWeek) -> Self {
43 self.day_of_week = Some(day_of_week);
44 self
45 }
46 /// Set a filter on the given hour
47 pub fn hour(mut self, hour: u8) -> Self {
48 self.hour = Some(hour);
49 self
50 }
51 /// Set a filter on the given minute
52 pub fn minute(mut self, minute: u8) -> Self {
53 self.minute = Some(minute);
54 self
55 }
56 /// Set a filter on the given second
57 pub fn second(mut self, second: u8) -> Self {
58 self.second = Some(second);
59 self
60 }
61}
62
63// register helper functions
64impl DateTimeFilter {
65 pub(super) fn write_setup_0(&self, w: &mut IrqSetup0) {
66 if let Some(year) = self.year {
67 w.set_year_ena(true);
68
69 w.set_year(year);
70 }
71 if let Some(month) = self.month {
72 w.set_month_ena(true);
73 w.set_month(month);
74 }
75 if let Some(day) = self.day {
76 w.set_day_ena(true);
77 w.set_day(day);
78 }
79 }
80 pub(super) fn write_setup_1(&self, w: &mut IrqSetup1) {
81 if let Some(day_of_week) = self.day_of_week {
82 w.set_dotw_ena(true);
83 let bits = super::datetime::day_of_week_to_u8(day_of_week);
84
85 w.set_dotw(bits);
86 }
87 if let Some(hour) = self.hour {
88 w.set_hour_ena(true);
89 w.set_hour(hour);
90 }
91 if let Some(minute) = self.minute {
92 w.set_min_ena(true);
93 w.set_min(minute);
94 }
95 if let Some(second) = self.second {
96 w.set_sec_ena(true);
97 w.set_sec(second);
98 }
99 }
100}
diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs
new file mode 100644
index 000000000..7f3bbbe73
--- /dev/null
+++ b/embassy-rp/src/rtc/mod.rs
@@ -0,0 +1,188 @@
1mod filter;
2
3use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
4
5pub use self::filter::DateTimeFilter;
6
7#[cfg_attr(feature = "chrono", path = "datetime_chrono.rs")]
8#[cfg_attr(not(feature = "chrono"), path = "datetime_no_deps.rs")]
9mod datetime;
10
11pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
12use crate::clocks::clk_rtc_freq;
13
14/// A reference to the real time clock of the system
15pub struct RealTimeClock<'d, T: Instance> {
16 inner: PeripheralRef<'d, T>,
17}
18
19impl<'d, T: Instance> RealTimeClock<'d, T> {
20 /// Create a new instance of the real time clock, with the given date as an initial value.
21 ///
22 /// # Errors
23 ///
24 /// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range.
25 pub fn new(inner: impl Peripheral<P = T> + 'd, initial_date: DateTime) -> Result<Self, RtcError> {
26 into_ref!(inner);
27
28 // Set the RTC divider
29 unsafe {
30 inner
31 .regs()
32 .clkdiv_m1()
33 .write(|w| w.set_clkdiv_m1(clk_rtc_freq() as u16 - 1))
34 };
35
36 let mut result = Self { inner };
37 result.set_leap_year_check(true); // should be on by default, make sure this is the case.
38 result.set_datetime(initial_date)?;
39 Ok(result)
40 }
41
42 /// Enable or disable the leap year check. The rp2040 chip will always add a Feb 29th on every year that is divisable by 4, but this may be incorrect (e.g. on century years). This function allows you to disable this check.
43 ///
44 /// Leap year checking is enabled by default.
45 pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) {
46 unsafe {
47 self.inner
48 .regs()
49 .ctrl()
50 .modify(|w| w.set_force_notleapyear(!leap_year_check_enabled))
51 };
52 }
53
54 /// Checks to see if this RealTimeClock is running
55 pub fn is_running(&self) -> bool {
56 unsafe { self.inner.regs().ctrl().read().rtc_active() }
57 }
58
59 /// Set the datetime to a new value.
60 ///
61 /// # Errors
62 ///
63 /// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range.
64 pub fn set_datetime(&mut self, t: DateTime) -> Result<(), RtcError> {
65 self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?;
66
67 // disable RTC while we configure it
68 unsafe {
69 self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false));
70 while self.inner.regs().ctrl().read().rtc_active() {
71 core::hint::spin_loop();
72 }
73
74 self.inner.regs().setup_0().write(|w| {
75 self::datetime::write_setup_0(&t, w);
76 });
77 self.inner.regs().setup_1().write(|w| {
78 self::datetime::write_setup_1(&t, w);
79 });
80
81 // Load the new datetime and re-enable RTC
82 self.inner.regs().ctrl().write(|w| w.set_load(true));
83 self.inner.regs().ctrl().write(|w| w.set_rtc_enable(true));
84 while !self.inner.regs().ctrl().read().rtc_active() {
85 core::hint::spin_loop();
86 }
87 }
88 Ok(())
89 }
90
91 /// Return the current datetime.
92 ///
93 /// # Errors
94 ///
95 /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
96 pub fn now(&self) -> Result<DateTime, RtcError> {
97 if !self.is_running() {
98 return Err(RtcError::NotRunning);
99 }
100
101 let rtc_0 = unsafe { self.inner.regs().rtc_0().read() };
102 let rtc_1 = unsafe { self.inner.regs().rtc_1().read() };
103
104 self::datetime::datetime_from_registers(rtc_0, rtc_1).map_err(RtcError::InvalidDateTime)
105 }
106
107 /// Disable the alarm that was scheduled with [`schedule_alarm`].
108 ///
109 /// [`schedule_alarm`]: #method.schedule_alarm
110 pub fn disable_alarm(&mut self) {
111 unsafe {
112 self.inner.regs().irq_setup_0().modify(|s| s.set_match_ena(false));
113
114 while self.inner.regs().irq_setup_0().read().match_active() {
115 core::hint::spin_loop();
116 }
117 }
118 }
119
120 /// Schedule an alarm. The `filter` determines at which point in time this alarm is set.
121 ///
122 /// Keep in mind that the filter only triggers on the specified time. If you want to schedule this alarm every minute, you have to call:
123 /// ```no_run
124 /// # #[cfg(feature = "chrono")]
125 /// # fn main() { }
126 /// # #[cfg(not(feature = "chrono"))]
127 /// # fn main() {
128 /// # use embassy_rp::rtc::{RealTimeClock, DateTimeFilter};
129 /// # let mut real_time_clock: RealTimeClock = unsafe { core::mem::zeroed() };
130 /// let now = real_time_clock.now().unwrap();
131 /// real_time_clock.schedule_alarm(
132 /// DateTimeFilter::default()
133 /// .minute(if now.minute == 59 { 0 } else { now.minute + 1 })
134 /// );
135 /// # }
136 /// ```
137 pub fn schedule_alarm(&mut self, filter: DateTimeFilter) {
138 self.disable_alarm();
139
140 unsafe {
141 self.inner.regs().irq_setup_0().write(|w| {
142 filter.write_setup_0(w);
143 });
144 self.inner.regs().irq_setup_1().write(|w| {
145 filter.write_setup_1(w);
146 });
147
148 // Set the enable bit and check if it is set
149 self.inner.regs().irq_setup_0().modify(|w| w.set_match_ena(true));
150 while !self.inner.regs().irq_setup_0().read().match_active() {
151 core::hint::spin_loop();
152 }
153 }
154 }
155
156 /// Clear the interrupt. This should be called every time the `RTC_IRQ` interrupt is triggered,
157 /// or the next [`schedule_alarm`] will never fire.
158 ///
159 /// [`schedule_alarm`]: #method.schedule_alarm
160 pub fn clear_interrupt(&mut self) {
161 self.disable_alarm();
162 }
163}
164
165/// Errors that can occur on methods on [RtcClock]
166#[derive(Clone, Debug, PartialEq, Eq)]
167pub enum RtcError {
168 /// An invalid DateTime was given or stored on the hardware.
169 InvalidDateTime(DateTimeError),
170
171 /// The RTC clock is not running
172 NotRunning,
173}
174
175mod sealed {
176 pub trait Instance {
177 fn regs(&self) -> crate::pac::rtc::Rtc;
178 }
179}
180
181pub trait Instance: sealed::Instance {}
182
183impl sealed::Instance for crate::peripherals::RTC {
184 fn regs(&self) -> crate::pac::rtc::Rtc {
185 crate::pac::RTC
186 }
187}
188impl Instance for crate::peripherals::RTC {}
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs
index 74f0b04de..03293e064 100644
--- a/embassy-rp/src/spi.rs
+++ b/embassy-rp/src/spi.rs
@@ -1,9 +1,9 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2 2
3use embassy_embedded_hal::SetConfig; 3use embassy_embedded_hal::SetConfig;
4use embassy_futures::join::join;
4use embassy_hal_common::{into_ref, PeripheralRef}; 5use embassy_hal_common::{into_ref, PeripheralRef};
5pub use embedded_hal_02::spi::{Phase, Polarity}; 6pub use embedded_hal_02::spi::{Phase, Polarity};
6use futures::future::join;
7 7
8use crate::dma::{AnyChannel, Channel}; 8use crate::dma::{AnyChannel, Channel};
9use crate::gpio::sealed::Pin as _; 9use crate::gpio::sealed::Pin as _;
@@ -325,30 +325,52 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
325 } 325 }
326 326
327 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { 327 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
328 let ch = self.tx_dma.as_mut().unwrap(); 328 let tx_ch = self.tx_dma.as_mut().unwrap();
329 let transfer = unsafe { 329 let tx_transfer = unsafe {
330 self.inner.regs().dmacr().modify(|reg| { 330 self.inner.regs().dmacr().modify(|reg| {
331 reg.set_txdmae(true); 331 reg.set_txdmae(true);
332 }); 332 });
333 // If we don't assign future to a variable, the data register pointer 333 // If we don't assign future to a variable, the data register pointer
334 // is held across an await and makes the future non-Send. 334 // is held across an await and makes the future non-Send.
335 crate::dma::write(ch, buffer, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ) 335 crate::dma::write(tx_ch, buffer, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ)
336 }; 336 };
337 transfer.await; 337 tx_transfer.await;
338
339 let p = self.inner.regs();
340 unsafe {
341 while p.sr().read().bsy() {}
342
343 // clear RX FIFO contents to prevent stale reads
344 while p.sr().read().rne() {
345 let _: u16 = p.dr().read().data();
346 }
347 // clear RX overrun interrupt
348 p.icr().write(|w| w.set_roric(true));
349 }
350
338 Ok(()) 351 Ok(())
339 } 352 }
340 353
341 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 354 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
342 let ch = self.rx_dma.as_mut().unwrap(); 355 unsafe {
343 let transfer = unsafe { 356 self.inner.regs().dmacr().write(|reg| {
344 self.inner.regs().dmacr().modify(|reg| {
345 reg.set_rxdmae(true); 357 reg.set_rxdmae(true);
346 }); 358 reg.set_txdmae(true);
359 })
360 };
361 let tx_ch = self.tx_dma.as_mut().unwrap();
362 let tx_transfer = unsafe {
347 // If we don't assign future to a variable, the data register pointer 363 // If we don't assign future to a variable, the data register pointer
348 // is held across an await and makes the future non-Send. 364 // is held across an await and makes the future non-Send.
349 crate::dma::read(ch, self.inner.regs().dr().ptr() as *const _, buffer, T::RX_DREQ) 365 crate::dma::write_repeated(tx_ch, self.inner.regs().dr().ptr() as *mut u8, buffer.len(), T::TX_DREQ)
350 }; 366 };
351 transfer.await; 367 let rx_ch = self.rx_dma.as_mut().unwrap();
368 let rx_transfer = unsafe {
369 // If we don't assign future to a variable, the data register pointer
370 // is held across an await and makes the future non-Send.
371 crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, buffer, T::RX_DREQ)
372 };
373 join(tx_transfer, rx_transfer).await;
352 Ok(()) 374 Ok(())
353 } 375 }
354 376
@@ -364,20 +386,20 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
364 let (_, from_len) = crate::dma::slice_ptr_parts(tx_ptr); 386 let (_, from_len) = crate::dma::slice_ptr_parts(tx_ptr);
365 let (_, to_len) = crate::dma::slice_ptr_parts_mut(rx_ptr); 387 let (_, to_len) = crate::dma::slice_ptr_parts_mut(rx_ptr);
366 assert_eq!(from_len, to_len); 388 assert_eq!(from_len, to_len);
389 unsafe {
390 self.inner.regs().dmacr().write(|reg| {
391 reg.set_rxdmae(true);
392 reg.set_txdmae(true);
393 })
394 };
367 let tx_ch = self.tx_dma.as_mut().unwrap(); 395 let tx_ch = self.tx_dma.as_mut().unwrap();
368 let tx_transfer = unsafe { 396 let tx_transfer = unsafe {
369 self.inner.regs().dmacr().modify(|reg| {
370 reg.set_txdmae(true);
371 });
372 // If we don't assign future to a variable, the data register pointer 397 // If we don't assign future to a variable, the data register pointer
373 // is held across an await and makes the future non-Send. 398 // is held across an await and makes the future non-Send.
374 crate::dma::write(tx_ch, tx_ptr, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ) 399 crate::dma::write(tx_ch, tx_ptr, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ)
375 }; 400 };
376 let rx_ch = self.rx_dma.as_mut().unwrap(); 401 let rx_ch = self.rx_dma.as_mut().unwrap();
377 let rx_transfer = unsafe { 402 let rx_transfer = unsafe {
378 self.inner.regs().dmacr().modify(|reg| {
379 reg.set_rxdmae(true);
380 });
381 // If we don't assign future to a variable, the data register pointer 403 // If we don't assign future to a variable, the data register pointer
382 // is held across an await and makes the future non-Send. 404 // is held across an await and makes the future non-Send.
383 crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, rx_ptr, T::RX_DREQ) 405 crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, rx_ptr, T::RX_DREQ)
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index 82eafdefd..ce473b21d 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -1,3 +1,4 @@
1use core::future::{poll_fn, Future};
1use core::marker::PhantomData; 2use core::marker::PhantomData;
2use core::slice; 3use core::slice;
3use core::sync::atomic::Ordering; 4use core::sync::atomic::Ordering;
@@ -6,10 +7,9 @@ use core::task::Poll;
6use atomic_polyfill::compiler_fence; 7use atomic_polyfill::compiler_fence;
7use embassy_hal_common::into_ref; 8use embassy_hal_common::into_ref;
8use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
9use embassy_usb::driver::{self, EndpointAllocError, EndpointError, Event, Unsupported}; 10use embassy_usb::driver::{
10use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; 11 self, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
11use futures::future::poll_fn; 12};
12use futures::Future;
13 13
14use crate::interrupt::{Interrupt, InterruptExt}; 14use crate::interrupt::{Interrupt, InterruptExt};
15use crate::{pac, peripherals, Peripheral, RegExt}; 15use crate::{pac, peripherals, Peripheral, RegExt};
@@ -205,8 +205,8 @@ impl<'d, T: Instance> Driver<'d, T> {
205 ); 205 );
206 206
207 let alloc = match D::dir() { 207 let alloc = match D::dir() {
208 UsbDirection::Out => &mut self.ep_out, 208 Direction::Out => &mut self.ep_out,
209 UsbDirection::In => &mut self.ep_in, 209 Direction::In => &mut self.ep_in,
210 }; 210 };
211 211
212 let index = alloc.iter_mut().enumerate().find(|(i, ep)| { 212 let index = alloc.iter_mut().enumerate().find(|(i, ep)| {
@@ -255,7 +255,7 @@ impl<'d, T: Instance> Driver<'d, T> {
255 }; 255 };
256 256
257 match D::dir() { 257 match D::dir() {
258 UsbDirection::Out => unsafe { 258 Direction::Out => unsafe {
259 T::dpram().ep_out_control(index - 1).write(|w| { 259 T::dpram().ep_out_control(index - 1).write(|w| {
260 w.set_enable(false); 260 w.set_enable(false);
261 w.set_buffer_address(addr); 261 w.set_buffer_address(addr);
@@ -263,7 +263,7 @@ impl<'d, T: Instance> Driver<'d, T> {
263 w.set_endpoint_type(ep_type_reg); 263 w.set_endpoint_type(ep_type_reg);
264 }) 264 })
265 }, 265 },
266 UsbDirection::In => unsafe { 266 Direction::In => unsafe {
267 T::dpram().ep_in_control(index - 1).write(|w| { 267 T::dpram().ep_in_control(index - 1).write(|w| {
268 w.set_enable(false); 268 w.set_enable(false);
269 w.set_buffer_address(addr); 269 w.set_buffer_address(addr);
@@ -430,14 +430,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
430 430
431 let n = ep_addr.index(); 431 let n = ep_addr.index();
432 match ep_addr.direction() { 432 match ep_addr.direction() {
433 UsbDirection::In => unsafe { 433 Direction::In => unsafe {
434 T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled)); 434 T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled));
435 T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| { 435 T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| {
436 w.set_pid(0, true); // first packet is DATA0, but PID is flipped before 436 w.set_pid(0, true); // first packet is DATA0, but PID is flipped before
437 }); 437 });
438 EP_IN_WAKERS[n].wake(); 438 EP_IN_WAKERS[n].wake();
439 }, 439 },
440 UsbDirection::Out => unsafe { 440 Direction::Out => unsafe {
441 T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled)); 441 T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled));
442 442
443 T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| { 443 T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| {
@@ -475,14 +475,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
475} 475}
476 476
477trait Dir { 477trait Dir {
478 fn dir() -> UsbDirection; 478 fn dir() -> Direction;
479 fn waker(i: usize) -> &'static AtomicWaker; 479 fn waker(i: usize) -> &'static AtomicWaker;
480} 480}
481 481
482pub enum In {} 482pub enum In {}
483impl Dir for In { 483impl Dir for In {
484 fn dir() -> UsbDirection { 484 fn dir() -> Direction {
485 UsbDirection::In 485 Direction::In
486 } 486 }
487 487
488 #[inline] 488 #[inline]
@@ -493,8 +493,8 @@ impl Dir for In {
493 493
494pub enum Out {} 494pub enum Out {}
495impl Dir for Out { 495impl Dir for Out {
496 fn dir() -> UsbDirection { 496 fn dir() -> Direction {
497 UsbDirection::Out 497 Direction::Out
498 } 498 }
499 499
500 #[inline] 500 #[inline]
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index b4c19f32e..484496f24 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -34,6 +34,7 @@ flavors = [
34embassy-sync = { version = "0.1.0", path = "../embassy-sync" } 34embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
35embassy-executor = { version = "0.1.0", path = "../embassy-executor" } 35embassy-executor = { version = "0.1.0", path = "../embassy-executor" }
36embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true } 36embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
37embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
37embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-4"]} 38embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-4"]}
38embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } 39embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
39embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 40embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index c0bd44e0f..bd92b35a0 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -12,6 +12,7 @@ pub struct Can<'d, T: Instance> {
12} 12}
13 13
14impl<'d, T: Instance> Can<'d, T> { 14impl<'d, T: Instance> Can<'d, T> {
15 /// Creates a new Bxcan instance, blocking for 11 recessive bits to sync with the CAN bus.
15 pub fn new( 16 pub fn new(
16 peri: impl Peripheral<P = T> + 'd, 17 peri: impl Peripheral<P = T> + 'd,
17 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 18 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@@ -31,6 +32,28 @@ impl<'d, T: Instance> Can<'d, T> {
31 can: bxcan::Can::builder(BxcanInstance(peri)).enable(), 32 can: bxcan::Can::builder(BxcanInstance(peri)).enable(),
32 } 33 }
33 } 34 }
35
36 /// Creates a new Bxcan instance, keeping the peripheral in sleep mode.
37 /// You must call [Can::enable_non_blocking] to use the peripheral.
38 pub fn new_disabled(
39 peri: impl Peripheral<P = T> + 'd,
40 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
41 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
42 ) -> Self {
43 into_ref!(peri, rx, tx);
44
45 unsafe {
46 rx.set_as_af(rx.af_num(), AFType::Input);
47 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
48 }
49
50 T::enable();
51 T::reset();
52
53 Self {
54 can: bxcan::Can::builder(BxcanInstance(peri)).leave_disabled(),
55 }
56 }
34} 57}
35 58
36impl<'d, T: Instance> Drop for Can<'d, T> { 59impl<'d, T: Instance> Drop for Can<'d, T> {
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
index fb9dc9d08..20e1a4070 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -1,8 +1,8 @@
1use core::future::poll_fn;
1use core::task::Poll; 2use core::task::Poll;
2 3
3use embassy_hal_common::{into_ref, PeripheralRef}; 4use embassy_hal_common::{into_ref, PeripheralRef};
4use embassy_sync::waitqueue::AtomicWaker; 5use embassy_sync::waitqueue::AtomicWaker;
5use futures::future::poll_fn;
6 6
7use crate::gpio::sealed::AFType; 7use crate::gpio::sealed::AFType;
8use crate::gpio::Speed; 8use crate::gpio::Speed;
@@ -429,7 +429,7 @@ where
429 } 429 }
430 }); 430 });
431 431
432 let (_, result) = futures::future::join(dma_read, result).await; 432 let (_, result) = embassy_futures::join::join(dma_read, result).await;
433 433
434 unsafe { Self::toggle(false) }; 434 unsafe { Self::toggle(false) };
435 435
@@ -537,7 +537,7 @@ where
537 537
538 unsafe { Self::toggle(true) }; 538 unsafe { Self::toggle(true) };
539 539
540 let (_, result) = futures::future::join(dma_result, result).await; 540 let (_, result) = embassy_futures::join::join(dma_result, result).await;
541 541
542 unsafe { Self::toggle(false) }; 542 unsafe { Self::toggle(false) };
543 543
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs
index 1ab0438ad..38629a932 100644
--- a/embassy-stm32/src/eth/v1/mod.rs
+++ b/embassy-stm32/src/eth/v1/mod.rs
@@ -29,7 +29,7 @@ use super::*;
29 29
30pub struct State<'d, T: Instance, const TX: usize, const RX: usize>(StateStorage<Inner<'d, T, TX, RX>>); 30pub struct State<'d, T: Instance, const TX: usize, const RX: usize>(StateStorage<Inner<'d, T, TX, RX>>);
31impl<'d, T: Instance, const TX: usize, const RX: usize> State<'d, T, TX, RX> { 31impl<'d, T: Instance, const TX: usize, const RX: usize> State<'d, T, TX, RX> {
32 pub fn new() -> Self { 32 pub const fn new() -> Self {
33 Self(StateStorage::new()) 33 Self(StateStorage::new())
34 } 34 }
35} 35}
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index d67c3c5e4..a81ee1183 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -19,7 +19,7 @@ use super::*;
19 19
20pub struct State<'d, T: Instance, const TX: usize, const RX: usize>(StateStorage<Inner<'d, T, TX, RX>>); 20pub struct State<'d, T: Instance, const TX: usize, const RX: usize>(StateStorage<Inner<'d, T, TX, RX>>);
21impl<'d, T: Instance, const TX: usize, const RX: usize> State<'d, T, TX, RX> { 21impl<'d, T: Instance, const TX: usize, const RX: usize> State<'d, T, TX, RX> {
22 pub fn new() -> Self { 22 pub const fn new() -> Self {
23 Self(StateStorage::new()) 23 Self(StateStorage::new())
24 } 24 }
25} 25}
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index db4924461..b7c89931c 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -1,4 +1,5 @@
1use core::cmp; 1use core::cmp;
2use core::future::poll_fn;
2use core::task::Poll; 3use core::task::Poll;
3 4
4use atomic_polyfill::{AtomicUsize, Ordering}; 5use atomic_polyfill::{AtomicUsize, Ordering};
@@ -6,7 +7,6 @@ use embassy_embedded_hal::SetConfig;
6use embassy_hal_common::drop::OnDrop; 7use embassy_hal_common::drop::OnDrop;
7use embassy_hal_common::{into_ref, PeripheralRef}; 8use embassy_hal_common::{into_ref, PeripheralRef};
8use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
9use futures::future::poll_fn;
10 10
11use crate::dma::NoDma; 11use crate::dma::NoDma;
12use crate::gpio::sealed::AFType; 12use crate::gpio::sealed::AFType;
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 30ff02d56..0392e8086 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -1,5 +1,5 @@
1#![no_std] 1#![no_std]
2#![cfg_attr(feature = "nightly", feature(generic_associated_types, type_alias_impl_trait))] 2#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))]
3 3
4// This must go FIRST so that all the other modules see its macros. 4// This must go FIRST so that all the other modules see its macros.
5pub mod fmt; 5pub mod fmt;
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs
index 520f2ab9a..10fc4a75e 100644
--- a/embassy-stm32/src/rng.rs
+++ b/embassy-stm32/src/rng.rs
@@ -1,10 +1,10 @@
1#![macro_use] 1#![macro_use]
2 2
3use core::future::poll_fn;
3use core::task::Poll; 4use core::task::Poll;
4 5
5use embassy_hal_common::{into_ref, PeripheralRef}; 6use embassy_hal_common::{into_ref, PeripheralRef};
6use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
7use futures::future::poll_fn;
8use rand_core::{CryptoRng, RngCore}; 8use rand_core::{CryptoRng, RngCore};
9 9
10use crate::{pac, peripherals, Peripheral}; 10use crate::{pac, peripherals, Peripheral};
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 67758c492..a8bc6385f 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -1,12 +1,12 @@
1#![macro_use] 1#![macro_use]
2 2
3use core::default::Default; 3use core::default::Default;
4use core::future::poll_fn;
4use core::task::Poll; 5use core::task::Poll;
5 6
6use embassy_hal_common::drop::OnDrop; 7use embassy_hal_common::drop::OnDrop;
7use embassy_hal_common::{into_ref, PeripheralRef}; 8use embassy_hal_common::{into_ref, PeripheralRef};
8use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
9use futures::future::poll_fn;
10use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; 10use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR};
11 11
12use crate::dma::NoDma; 12use crate::dma::NoDma;
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 02e6020b0..556d12305 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -3,9 +3,9 @@
3use core::ptr; 3use core::ptr;
4 4
5use embassy_embedded_hal::SetConfig; 5use embassy_embedded_hal::SetConfig;
6use embassy_futures::join::join;
6use embassy_hal_common::{into_ref, PeripheralRef}; 7use embassy_hal_common::{into_ref, PeripheralRef};
7pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; 8pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3};
8use futures::future::join;
9 9
10use self::sealed::WordSize; 10use self::sealed::WordSize;
11use crate::dma::{slice_ptr_parts, NoDma, Transfer}; 11use crate::dma::{slice_ptr_parts, NoDma, Transfer};
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index a7fa43894..46c49a997 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -1,17 +1,16 @@
1use core::future::Future; 1use core::future::{poll_fn, Future};
2use core::task::Poll; 2use core::task::Poll;
3 3
4use atomic_polyfill::{compiler_fence, Ordering}; 4use atomic_polyfill::{compiler_fence, Ordering};
5use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; 5use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
6use embassy_hal_common::ring_buffer::RingBuffer; 6use embassy_hal_common::ring_buffer::RingBuffer;
7use embassy_sync::waitqueue::WakerRegistration; 7use embassy_sync::waitqueue::WakerRegistration;
8use futures::future::poll_fn;
9 8
10use super::*; 9use super::*;
11 10
12pub struct State<'d, T: BasicInstance>(StateStorage<StateInner<'d, T>>); 11pub struct State<'d, T: BasicInstance>(StateStorage<StateInner<'d, T>>);
13impl<'d, T: BasicInstance> State<'d, T> { 12impl<'d, T: BasicInstance> State<'d, T> {
14 pub fn new() -> Self { 13 pub const fn new() -> Self {
15 Self(StateStorage::new()) 14 Self(StateStorage::new())
16 } 15 }
17} 16}
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index db965824a..39809a3e1 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -1,5 +1,6 @@
1#![macro_use] 1#![macro_use]
2 2
3use core::future::{poll_fn, Future};
3use core::marker::PhantomData; 4use core::marker::PhantomData;
4use core::sync::atomic::Ordering; 5use core::sync::atomic::Ordering;
5use core::task::Poll; 6use core::task::Poll;
@@ -8,10 +9,9 @@ use atomic_polyfill::{AtomicBool, AtomicU8};
8use embassy_hal_common::into_ref; 9use embassy_hal_common::into_ref;
9use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
10use embassy_time::{block_for, Duration}; 11use embassy_time::{block_for, Duration};
11use embassy_usb::driver::{self, EndpointAllocError, EndpointError, Event, Unsupported}; 12use embassy_usb::driver::{
12use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; 13 self, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
13use futures::future::poll_fn; 14};
14use futures::Future;
15use pac::common::{Reg, RW}; 15use pac::common::{Reg, RW};
16use pac::usb::vals::{EpType, Stat}; 16use pac::usb::vals::{EpType, Stat};
17 17
@@ -280,8 +280,8 @@ impl<'d, T: Instance> Driver<'d, T> {
280 } 280 }
281 let used = ep.used_out || ep.used_in; 281 let used = ep.used_out || ep.used_in;
282 let used_dir = match D::dir() { 282 let used_dir = match D::dir() {
283 UsbDirection::Out => ep.used_out, 283 Direction::Out => ep.used_out,
284 UsbDirection::In => ep.used_in, 284 Direction::In => ep.used_in,
285 }; 285 };
286 !used || (ep.ep_type == ep_type && !used_dir) 286 !used || (ep.ep_type == ep_type && !used_dir)
287 }); 287 });
@@ -294,7 +294,7 @@ impl<'d, T: Instance> Driver<'d, T> {
294 ep.ep_type = ep_type; 294 ep.ep_type = ep_type;
295 295
296 let buf = match D::dir() { 296 let buf = match D::dir() {
297 UsbDirection::Out => { 297 Direction::Out => {
298 assert!(!ep.used_out); 298 assert!(!ep.used_out);
299 ep.used_out = true; 299 ep.used_out = true;
300 300
@@ -313,7 +313,7 @@ impl<'d, T: Instance> Driver<'d, T> {
313 _phantom: PhantomData, 313 _phantom: PhantomData,
314 } 314 }
315 } 315 }
316 UsbDirection::In => { 316 Direction::In => {
317 assert!(!ep.used_in); 317 assert!(!ep.used_in);
318 ep.used_in = true; 318 ep.used_in = true;
319 319
@@ -505,7 +505,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
505 // This can race, so do a retry loop. 505 // This can race, so do a retry loop.
506 let reg = T::regs().epr(ep_addr.index() as _); 506 let reg = T::regs().epr(ep_addr.index() as _);
507 match ep_addr.direction() { 507 match ep_addr.direction() {
508 UsbDirection::In => { 508 Direction::In => {
509 loop { 509 loop {
510 let r = unsafe { reg.read() }; 510 let r = unsafe { reg.read() };
511 match r.stat_tx() { 511 match r.stat_tx() {
@@ -524,7 +524,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
524 } 524 }
525 EP_IN_WAKERS[ep_addr.index()].wake(); 525 EP_IN_WAKERS[ep_addr.index()].wake();
526 } 526 }
527 UsbDirection::Out => { 527 Direction::Out => {
528 loop { 528 loop {
529 let r = unsafe { reg.read() }; 529 let r = unsafe { reg.read() };
530 match r.stat_rx() { 530 match r.stat_rx() {
@@ -550,8 +550,8 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
550 let regs = T::regs(); 550 let regs = T::regs();
551 let epr = unsafe { regs.epr(ep_addr.index() as _).read() }; 551 let epr = unsafe { regs.epr(ep_addr.index() as _).read() };
552 match ep_addr.direction() { 552 match ep_addr.direction() {
553 UsbDirection::In => epr.stat_tx() == Stat::STALL, 553 Direction::In => epr.stat_tx() == Stat::STALL,
554 UsbDirection::Out => epr.stat_rx() == Stat::STALL, 554 Direction::Out => epr.stat_rx() == Stat::STALL,
555 } 555 }
556 } 556 }
557 557
@@ -561,7 +561,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
561 let reg = T::regs().epr(ep_addr.index() as _); 561 let reg = T::regs().epr(ep_addr.index() as _);
562 trace!("EPR before: {:04x}", unsafe { reg.read() }.0); 562 trace!("EPR before: {:04x}", unsafe { reg.read() }.0);
563 match ep_addr.direction() { 563 match ep_addr.direction() {
564 UsbDirection::In => { 564 Direction::In => {
565 loop { 565 loop {
566 let want_stat = match enabled { 566 let want_stat = match enabled {
567 false => Stat::DISABLED, 567 false => Stat::DISABLED,
@@ -577,7 +577,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
577 } 577 }
578 EP_IN_WAKERS[ep_addr.index()].wake(); 578 EP_IN_WAKERS[ep_addr.index()].wake();
579 } 579 }
580 UsbDirection::Out => { 580 Direction::Out => {
581 loop { 581 loop {
582 let want_stat = match enabled { 582 let want_stat = match enabled {
583 false => Stat::DISABLED, 583 false => Stat::DISABLED,
@@ -617,14 +617,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
617} 617}
618 618
619trait Dir { 619trait Dir {
620 fn dir() -> UsbDirection; 620 fn dir() -> Direction;
621 fn waker(i: usize) -> &'static AtomicWaker; 621 fn waker(i: usize) -> &'static AtomicWaker;
622} 622}
623 623
624pub enum In {} 624pub enum In {}
625impl Dir for In { 625impl Dir for In {
626 fn dir() -> UsbDirection { 626 fn dir() -> Direction {
627 UsbDirection::In 627 Direction::In
628 } 628 }
629 629
630 #[inline] 630 #[inline]
@@ -635,8 +635,8 @@ impl Dir for In {
635 635
636pub enum Out {} 636pub enum Out {}
637impl Dir for Out { 637impl Dir for Out {
638 fn dir() -> UsbDirection { 638 fn dir() -> Direction {
639 UsbDirection::Out 639 Direction::Out
640 } 640 }
641 641
642 #[inline] 642 #[inline]
diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs
index 25150e8aa..80bb907a3 100644
--- a/embassy-sync/src/lib.rs
+++ b/embassy-sync/src/lib.rs
@@ -1,5 +1,5 @@
1#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)] 1#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)]
2#![cfg_attr(feature = "nightly", feature(generic_associated_types, type_alias_impl_trait))] 2#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))]
3#![allow(clippy::new_without_default)] 3#![allow(clippy::new_without_default)]
4#![doc = include_str!("../README.md")] 4#![doc = include_str!("../README.md")]
5#![warn(missing_docs)] 5#![warn(missing_docs)]
diff --git a/embassy-sync/src/mutex.rs b/embassy-sync/src/mutex.rs
index 75a6e8dd3..fcf056d36 100644
--- a/embassy-sync/src/mutex.rs
+++ b/embassy-sync/src/mutex.rs
@@ -2,11 +2,10 @@
2//! 2//!
3//! This module provides a mutex that can be used to synchronize data between asynchronous tasks. 3//! This module provides a mutex that can be used to synchronize data between asynchronous tasks.
4use core::cell::{RefCell, UnsafeCell}; 4use core::cell::{RefCell, UnsafeCell};
5use core::future::poll_fn;
5use core::ops::{Deref, DerefMut}; 6use core::ops::{Deref, DerefMut};
6use core::task::Poll; 7use core::task::Poll;
7 8
8use futures_util::future::poll_fn;
9
10use crate::blocking_mutex::raw::RawMutex; 9use crate::blocking_mutex::raw::RawMutex;
11use crate::blocking_mutex::Mutex as BlockingMutex; 10use crate::blocking_mutex::Mutex as BlockingMutex;
12use crate::waitqueue::WakerRegistration; 11use crate::waitqueue::WakerRegistration;
@@ -111,6 +110,22 @@ where
111 110
112 Ok(MutexGuard { mutex: self }) 111 Ok(MutexGuard { mutex: self })
113 } 112 }
113
114 /// Consumes this mutex, returning the underlying data.
115 pub fn into_inner(self) -> T
116 where
117 T: Sized,
118 {
119 self.inner.into_inner()
120 }
121
122 /// Returns a mutable reference to the underlying data.
123 ///
124 /// Since this call borrows the Mutex mutably, no actual locking needs to
125 /// take place -- the mutable borrow statically guarantees no locks exist.
126 pub fn get_mut(&mut self) -> &mut T {
127 self.inner.get_mut()
128 }
114} 129}
115 130
116/// Async mutex guard. 131/// Async mutex guard.
diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs
index f6ebeb9b9..c3c10a8af 100644
--- a/embassy-sync/src/signal.rs
+++ b/embassy-sync/src/signal.rs
@@ -1,9 +1,11 @@
1//! A synchronization primitive for passing the latest value to a task. 1//! A synchronization primitive for passing the latest value to a task.
2use core::cell::UnsafeCell; 2use core::cell::Cell;
3use core::future::Future; 3use core::future::{poll_fn, Future};
4use core::mem;
5use core::task::{Context, Poll, Waker}; 4use core::task::{Context, Poll, Waker};
6 5
6use crate::blocking_mutex::raw::RawMutex;
7use crate::blocking_mutex::Mutex;
8
7/// Single-slot signaling primitive. 9/// Single-slot signaling primitive.
8/// 10///
9/// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except 11/// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except
@@ -20,16 +22,20 @@ use core::task::{Context, Poll, Waker};
20/// 22///
21/// ``` 23/// ```
22/// use embassy_sync::signal::Signal; 24/// use embassy_sync::signal::Signal;
25/// use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
23/// 26///
24/// enum SomeCommand { 27/// enum SomeCommand {
25/// On, 28/// On,
26/// Off, 29/// Off,
27/// } 30/// }
28/// 31///
29/// static SOME_SIGNAL: Signal<SomeCommand> = Signal::new(); 32/// static SOME_SIGNAL: Signal<CriticalSectionRawMutex, SomeCommand> = Signal::new();
30/// ``` 33/// ```
31pub struct Signal<T> { 34pub struct Signal<M, T>
32 state: UnsafeCell<State<T>>, 35where
36 M: RawMutex,
37{
38 state: Mutex<M, Cell<State<T>>>,
33} 39}
34 40
35enum State<T> { 41enum State<T> {
@@ -38,24 +44,27 @@ enum State<T> {
38 Signaled(T), 44 Signaled(T),
39} 45}
40 46
41unsafe impl<T: Send> Send for Signal<T> {} 47impl<M, T> Signal<M, T>
42unsafe impl<T: Send> Sync for Signal<T> {} 48where
43 49 M: RawMutex,
44impl<T> Signal<T> { 50{
45 /// Create a new `Signal`. 51 /// Create a new `Signal`.
46 pub const fn new() -> Self { 52 pub const fn new() -> Self {
47 Self { 53 Self {
48 state: UnsafeCell::new(State::None), 54 state: Mutex::new(Cell::new(State::None)),
49 } 55 }
50 } 56 }
51} 57}
52 58
53impl<T: Send> Signal<T> { 59impl<M, T: Send> Signal<M, T>
60where
61 M: RawMutex,
62{
54 /// Mark this Signal as signaled. 63 /// Mark this Signal as signaled.
55 pub fn signal(&self, val: T) { 64 pub fn signal(&self, val: T) {
56 critical_section::with(|_| unsafe { 65 self.state.lock(|cell| {
57 let state = &mut *self.state.get(); 66 let state = cell.replace(State::Signaled(val));
58 if let State::Waiting(waker) = mem::replace(state, State::Signaled(val)) { 67 if let State::Waiting(waker) = state {
59 waker.wake(); 68 waker.wake();
60 } 69 }
61 }) 70 })
@@ -63,38 +72,46 @@ impl<T: Send> Signal<T> {
63 72
64 /// Remove the queued value in this `Signal`, if any. 73 /// Remove the queued value in this `Signal`, if any.
65 pub fn reset(&self) { 74 pub fn reset(&self) {
66 critical_section::with(|_| unsafe { 75 self.state.lock(|cell| cell.set(State::None));
67 let state = &mut *self.state.get();
68 *state = State::None
69 })
70 } 76 }
71 77
72 /// Manually poll the Signal future. 78 fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<T> {
73 pub fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<T> { 79 self.state.lock(|cell| {
74 critical_section::with(|_| unsafe { 80 let state = cell.replace(State::None);
75 let state = &mut *self.state.get();
76 match state { 81 match state {
77 State::None => { 82 State::None => {
78 *state = State::Waiting(cx.waker().clone()); 83 cell.set(State::Waiting(cx.waker().clone()));
79 Poll::Pending 84 Poll::Pending
80 } 85 }
81 State::Waiting(w) if w.will_wake(cx.waker()) => Poll::Pending, 86 State::Waiting(w) if w.will_wake(cx.waker()) => {
82 State::Waiting(_) => panic!("waker overflow"), 87 cell.set(State::Waiting(w));
83 State::Signaled(_) => match mem::replace(state, State::None) { 88 Poll::Pending
84 State::Signaled(res) => Poll::Ready(res), 89 }
85 _ => unreachable!(), 90 State::Waiting(w) => {
86 }, 91 cell.set(State::Waiting(cx.waker().clone()));
92 w.wake();
93 Poll::Pending
94 }
95 State::Signaled(res) => Poll::Ready(res),
87 } 96 }
88 }) 97 })
89 } 98 }
90 99
91 /// Future that completes when this Signal has been signaled. 100 /// Future that completes when this Signal has been signaled.
92 pub fn wait(&self) -> impl Future<Output = T> + '_ { 101 pub fn wait(&self) -> impl Future<Output = T> + '_ {
93 futures_util::future::poll_fn(move |cx| self.poll_wait(cx)) 102 poll_fn(move |cx| self.poll_wait(cx))
94 } 103 }
95 104
96 /// non-blocking method to check whether this signal has been signaled. 105 /// non-blocking method to check whether this signal has been signaled.
97 pub fn signaled(&self) -> bool { 106 pub fn signaled(&self) -> bool {
98 critical_section::with(|_| matches!(unsafe { &*self.state.get() }, State::Signaled(_))) 107 self.state.lock(|cell| {
108 let state = cell.replace(State::None);
109
110 let res = matches!(state, State::Signaled(_));
111
112 cell.set(state);
113
114 res
115 })
99 } 116 }
100} 117}
diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs
index 5b2620986..4edc883fe 100644
--- a/embassy-time/src/lib.rs
+++ b/embassy-time/src/lib.rs
@@ -1,5 +1,5 @@
1#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)] 1#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)]
2#![cfg_attr(feature = "nightly", feature(generic_associated_types, type_alias_impl_trait))] 2#![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))]
3#![doc = include_str!("../README.md")] 3#![doc = include_str!("../README.md")]
4#![allow(clippy::new_without_default)] 4#![allow(clippy::new_without_default)]
5#![warn(missing_docs)] 5#![warn(missing_docs)]
diff --git a/embassy-usb-ncm/Cargo.toml b/embassy-usb-driver/Cargo.toml
index 15d3db96f..b525df337 100644
--- a/embassy-usb-ncm/Cargo.toml
+++ b/embassy-usb-driver/Cargo.toml
@@ -1,17 +1,16 @@
1[package] 1[package]
2name = "embassy-usb-ncm" 2name = "embassy-usb-driver"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5 5
6# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7
6[package.metadata.embassy_docs] 8[package.metadata.embassy_docs]
7src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-ncm-v$VERSION/embassy-usb-ncm/src/" 9src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-driver-v$VERSION/embassy-usb/src/"
8src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-ncm/src/" 10src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-driver/src/"
9features = ["defmt"] 11features = ["defmt"]
10target = "thumbv7em-none-eabi" 12target = "thumbv7em-none-eabi"
11 13
12[dependencies] 14[dependencies]
13embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
14embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
15
16defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
17log = { version = "0.4.14", optional = true } 16log = { version = "0.4.14", optional = true } \ No newline at end of file
diff --git a/embassy-usb/src/driver.rs b/embassy-usb-driver/src/lib.rs
index 7888f1639..fc29786fc 100644
--- a/embassy-usb/src/driver.rs
+++ b/embassy-usb-driver/src/lib.rs
@@ -1,6 +1,104 @@
1#![no_std]
2
1use core::future::Future; 3use core::future::Future;
2 4
3use super::types::*; 5/// Direction of USB traffic. Note that in the USB standard the direction is always indicated from
6/// the perspective of the host, which is backward for devices, but the standard directions are used
7/// for consistency.
8///
9/// The values of the enum also match the direction bit used in endpoint addresses and control
10/// request types.
11#[derive(Copy, Clone, Eq, PartialEq, Debug)]
12#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub enum Direction {
14 /// Host to device (OUT)
15 Out,
16 /// Device to host (IN)
17 In,
18}
19
20/// USB endpoint transfer type. The values of this enum can be directly cast into `u8` to get the
21/// transfer bmAttributes transfer type bits.
22#[repr(u8)]
23#[derive(Copy, Clone, Eq, PartialEq, Debug)]
24#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25pub enum EndpointType {
26 /// Control endpoint. Used for device management. Only the host can initiate requests. Usually
27 /// used only endpoint 0.
28 Control = 0b00,
29 /// Isochronous endpoint. Used for time-critical unreliable data. Not implemented yet.
30 Isochronous = 0b01,
31 /// Bulk endpoint. Used for large amounts of best-effort reliable data.
32 Bulk = 0b10,
33 /// Interrupt endpoint. Used for small amounts of time-critical reliable data.
34 Interrupt = 0b11,
35}
36
37/// Type-safe endpoint address.
38#[derive(Debug, Clone, Copy, Eq, PartialEq)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub struct EndpointAddress(u8);
41
42impl From<u8> for EndpointAddress {
43 #[inline]
44 fn from(addr: u8) -> EndpointAddress {
45 EndpointAddress(addr)
46 }
47}
48
49impl From<EndpointAddress> for u8 {
50 #[inline]
51 fn from(addr: EndpointAddress) -> u8 {
52 addr.0
53 }
54}
55
56impl EndpointAddress {
57 const INBITS: u8 = Direction::In as u8;
58
59 /// Constructs a new EndpointAddress with the given index and direction.
60 #[inline]
61 pub fn from_parts(index: usize, dir: Direction) -> Self {
62 EndpointAddress(index as u8 | dir as u8)
63 }
64
65 /// Gets the direction part of the address.
66 #[inline]
67 pub fn direction(&self) -> Direction {
68 if (self.0 & Self::INBITS) != 0 {
69 Direction::In
70 } else {
71 Direction::Out
72 }
73 }
74
75 /// Returns true if the direction is IN, otherwise false.
76 #[inline]
77 pub fn is_in(&self) -> bool {
78 (self.0 & Self::INBITS) != 0
79 }
80
81 /// Returns true if the direction is OUT, otherwise false.
82 #[inline]
83 pub fn is_out(&self) -> bool {
84 (self.0 & Self::INBITS) == 0
85 }
86
87 /// Gets the index part of the endpoint address.
88 #[inline]
89 pub fn index(&self) -> usize {
90 (self.0 & !Self::INBITS) as usize
91 }
92}
93
94#[derive(Copy, Clone, Eq, PartialEq, Debug)]
95#[cfg_attr(feature = "defmt", derive(defmt::Format))]
96pub struct EndpointInfo {
97 pub addr: EndpointAddress,
98 pub ep_type: EndpointType,
99 pub max_packet_size: u16,
100 pub interval: u8,
101}
4 102
5/// Driver for a specific USB peripheral. Implement this to add support for a new hardware 103/// Driver for a specific USB peripheral. Implement this to add support for a new hardware
6/// platform. 104/// platform.
diff --git a/embassy-usb-hid/Cargo.toml b/embassy-usb-hid/Cargo.toml
deleted file mode 100644
index 2f7733dc6..000000000
--- a/embassy-usb-hid/Cargo.toml
+++ /dev/null
@@ -1,24 +0,0 @@
1[package]
2name = "embassy-usb-hid"
3version = "0.1.0"
4edition = "2021"
5
6[package.metadata.embassy_docs]
7src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-hid-v$VERSION/embassy-usb-hid/src/"
8src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-hid/src/"
9features = ["defmt"]
10target = "thumbv7em-none-eabi"
11
12[features]
13default = ["usbd-hid"]
14usbd-hid = ["dep:usbd-hid", "ssmarshal"]
15
16[dependencies]
17embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
18embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
19
20defmt = { version = "0.3", optional = true }
21log = { version = "0.4.14", optional = true }
22usbd-hid = { version = "0.6.0", optional = true }
23ssmarshal = { version = "1.0", default-features = false, optional = true }
24futures-util = { version = "0.3.21", default-features = false }
diff --git a/embassy-usb-hid/src/fmt.rs b/embassy-usb-hid/src/fmt.rs
deleted file mode 100644
index 066970813..000000000
--- a/embassy-usb-hid/src/fmt.rs
+++ /dev/null
@@ -1,225 +0,0 @@
1#![macro_use]
2#![allow(unused_macros)]
3
4#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features.");
6
7macro_rules! assert {
8 ($($x:tt)*) => {
9 {
10 #[cfg(not(feature = "defmt"))]
11 ::core::assert!($($x)*);
12 #[cfg(feature = "defmt")]
13 ::defmt::assert!($($x)*);
14 }
15 };
16}
17
18macro_rules! assert_eq {
19 ($($x:tt)*) => {
20 {
21 #[cfg(not(feature = "defmt"))]
22 ::core::assert_eq!($($x)*);
23 #[cfg(feature = "defmt")]
24 ::defmt::assert_eq!($($x)*);
25 }
26 };
27}
28
29macro_rules! assert_ne {
30 ($($x:tt)*) => {
31 {
32 #[cfg(not(feature = "defmt"))]
33 ::core::assert_ne!($($x)*);
34 #[cfg(feature = "defmt")]
35 ::defmt::assert_ne!($($x)*);
36 }
37 };
38}
39
40macro_rules! debug_assert {
41 ($($x:tt)*) => {
42 {
43 #[cfg(not(feature = "defmt"))]
44 ::core::debug_assert!($($x)*);
45 #[cfg(feature = "defmt")]
46 ::defmt::debug_assert!($($x)*);
47 }
48 };
49}
50
51macro_rules! debug_assert_eq {
52 ($($x:tt)*) => {
53 {
54 #[cfg(not(feature = "defmt"))]
55 ::core::debug_assert_eq!($($x)*);
56 #[cfg(feature = "defmt")]
57 ::defmt::debug_assert_eq!($($x)*);
58 }
59 };
60}
61
62macro_rules! debug_assert_ne {
63 ($($x:tt)*) => {
64 {
65 #[cfg(not(feature = "defmt"))]
66 ::core::debug_assert_ne!($($x)*);
67 #[cfg(feature = "defmt")]
68 ::defmt::debug_assert_ne!($($x)*);
69 }
70 };
71}
72
73macro_rules! todo {
74 ($($x:tt)*) => {
75 {
76 #[cfg(not(feature = "defmt"))]
77 ::core::todo!($($x)*);
78 #[cfg(feature = "defmt")]
79 ::defmt::todo!($($x)*);
80 }
81 };
82}
83
84macro_rules! unreachable {
85 ($($x:tt)*) => {
86 {
87 #[cfg(not(feature = "defmt"))]
88 ::core::unreachable!($($x)*);
89 #[cfg(feature = "defmt")]
90 ::defmt::unreachable!($($x)*);
91 }
92 };
93}
94
95macro_rules! panic {
96 ($($x:tt)*) => {
97 {
98 #[cfg(not(feature = "defmt"))]
99 ::core::panic!($($x)*);
100 #[cfg(feature = "defmt")]
101 ::defmt::panic!($($x)*);
102 }
103 };
104}
105
106macro_rules! trace {
107 ($s:literal $(, $x:expr)* $(,)?) => {
108 {
109 #[cfg(feature = "log")]
110 ::log::trace!($s $(, $x)*);
111 #[cfg(feature = "defmt")]
112 ::defmt::trace!($s $(, $x)*);
113 #[cfg(not(any(feature = "log", feature="defmt")))]
114 let _ = ($( & $x ),*);
115 }
116 };
117}
118
119macro_rules! debug {
120 ($s:literal $(, $x:expr)* $(,)?) => {
121 {
122 #[cfg(feature = "log")]
123 ::log::debug!($s $(, $x)*);
124 #[cfg(feature = "defmt")]
125 ::defmt::debug!($s $(, $x)*);
126 #[cfg(not(any(feature = "log", feature="defmt")))]
127 let _ = ($( & $x ),*);
128 }
129 };
130}
131
132macro_rules! info {
133 ($s:literal $(, $x:expr)* $(,)?) => {
134 {
135 #[cfg(feature = "log")]
136 ::log::info!($s $(, $x)*);
137 #[cfg(feature = "defmt")]
138 ::defmt::info!($s $(, $x)*);
139 #[cfg(not(any(feature = "log", feature="defmt")))]
140 let _ = ($( & $x ),*);
141 }
142 };
143}
144
145macro_rules! warn {
146 ($s:literal $(, $x:expr)* $(,)?) => {
147 {
148 #[cfg(feature = "log")]
149 ::log::warn!($s $(, $x)*);
150 #[cfg(feature = "defmt")]
151 ::defmt::warn!($s $(, $x)*);
152 #[cfg(not(any(feature = "log", feature="defmt")))]
153 let _ = ($( & $x ),*);
154 }
155 };
156}
157
158macro_rules! error {
159 ($s:literal $(, $x:expr)* $(,)?) => {
160 {
161 #[cfg(feature = "log")]
162 ::log::error!($s $(, $x)*);
163 #[cfg(feature = "defmt")]
164 ::defmt::error!($s $(, $x)*);
165 #[cfg(not(any(feature = "log", feature="defmt")))]
166 let _ = ($( & $x ),*);
167 }
168 };
169}
170
171#[cfg(feature = "defmt")]
172macro_rules! unwrap {
173 ($($x:tt)*) => {
174 ::defmt::unwrap!($($x)*)
175 };
176}
177
178#[cfg(not(feature = "defmt"))]
179macro_rules! unwrap {
180 ($arg:expr) => {
181 match $crate::fmt::Try::into_result($arg) {
182 ::core::result::Result::Ok(t) => t,
183 ::core::result::Result::Err(e) => {
184 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
185 }
186 }
187 };
188 ($arg:expr, $($msg:expr),+ $(,)? ) => {
189 match $crate::fmt::Try::into_result($arg) {
190 ::core::result::Result::Ok(t) => t,
191 ::core::result::Result::Err(e) => {
192 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
193 }
194 }
195 }
196}
197
198#[derive(Debug, Copy, Clone, Eq, PartialEq)]
199pub struct NoneError;
200
201pub trait Try {
202 type Ok;
203 type Error;
204 fn into_result(self) -> Result<Self::Ok, Self::Error>;
205}
206
207impl<T> Try for Option<T> {
208 type Ok = T;
209 type Error = NoneError;
210
211 #[inline]
212 fn into_result(self) -> Result<T, NoneError> {
213 self.ok_or(NoneError)
214 }
215}
216
217impl<T, E> Try for Result<T, E> {
218 type Ok = T;
219 type Error = E;
220
221 #[inline]
222 fn into_result(self) -> Self {
223 self
224 }
225}
diff --git a/embassy-usb-ncm/src/fmt.rs b/embassy-usb-ncm/src/fmt.rs
deleted file mode 100644
index 066970813..000000000
--- a/embassy-usb-ncm/src/fmt.rs
+++ /dev/null
@@ -1,225 +0,0 @@
1#![macro_use]
2#![allow(unused_macros)]
3
4#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features.");
6
7macro_rules! assert {
8 ($($x:tt)*) => {
9 {
10 #[cfg(not(feature = "defmt"))]
11 ::core::assert!($($x)*);
12 #[cfg(feature = "defmt")]
13 ::defmt::assert!($($x)*);
14 }
15 };
16}
17
18macro_rules! assert_eq {
19 ($($x:tt)*) => {
20 {
21 #[cfg(not(feature = "defmt"))]
22 ::core::assert_eq!($($x)*);
23 #[cfg(feature = "defmt")]
24 ::defmt::assert_eq!($($x)*);
25 }
26 };
27}
28
29macro_rules! assert_ne {
30 ($($x:tt)*) => {
31 {
32 #[cfg(not(feature = "defmt"))]
33 ::core::assert_ne!($($x)*);
34 #[cfg(feature = "defmt")]
35 ::defmt::assert_ne!($($x)*);
36 }
37 };
38}
39
40macro_rules! debug_assert {
41 ($($x:tt)*) => {
42 {
43 #[cfg(not(feature = "defmt"))]
44 ::core::debug_assert!($($x)*);
45 #[cfg(feature = "defmt")]
46 ::defmt::debug_assert!($($x)*);
47 }
48 };
49}
50
51macro_rules! debug_assert_eq {
52 ($($x:tt)*) => {
53 {
54 #[cfg(not(feature = "defmt"))]
55 ::core::debug_assert_eq!($($x)*);
56 #[cfg(feature = "defmt")]
57 ::defmt::debug_assert_eq!($($x)*);
58 }
59 };
60}
61
62macro_rules! debug_assert_ne {
63 ($($x:tt)*) => {
64 {
65 #[cfg(not(feature = "defmt"))]
66 ::core::debug_assert_ne!($($x)*);
67 #[cfg(feature = "defmt")]
68 ::defmt::debug_assert_ne!($($x)*);
69 }
70 };
71}
72
73macro_rules! todo {
74 ($($x:tt)*) => {
75 {
76 #[cfg(not(feature = "defmt"))]
77 ::core::todo!($($x)*);
78 #[cfg(feature = "defmt")]
79 ::defmt::todo!($($x)*);
80 }
81 };
82}
83
84macro_rules! unreachable {
85 ($($x:tt)*) => {
86 {
87 #[cfg(not(feature = "defmt"))]
88 ::core::unreachable!($($x)*);
89 #[cfg(feature = "defmt")]
90 ::defmt::unreachable!($($x)*);
91 }
92 };
93}
94
95macro_rules! panic {
96 ($($x:tt)*) => {
97 {
98 #[cfg(not(feature = "defmt"))]
99 ::core::panic!($($x)*);
100 #[cfg(feature = "defmt")]
101 ::defmt::panic!($($x)*);
102 }
103 };
104}
105
106macro_rules! trace {
107 ($s:literal $(, $x:expr)* $(,)?) => {
108 {
109 #[cfg(feature = "log")]
110 ::log::trace!($s $(, $x)*);
111 #[cfg(feature = "defmt")]
112 ::defmt::trace!($s $(, $x)*);
113 #[cfg(not(any(feature = "log", feature="defmt")))]
114 let _ = ($( & $x ),*);
115 }
116 };
117}
118
119macro_rules! debug {
120 ($s:literal $(, $x:expr)* $(,)?) => {
121 {
122 #[cfg(feature = "log")]
123 ::log::debug!($s $(, $x)*);
124 #[cfg(feature = "defmt")]
125 ::defmt::debug!($s $(, $x)*);
126 #[cfg(not(any(feature = "log", feature="defmt")))]
127 let _ = ($( & $x ),*);
128 }
129 };
130}
131
132macro_rules! info {
133 ($s:literal $(, $x:expr)* $(,)?) => {
134 {
135 #[cfg(feature = "log")]
136 ::log::info!($s $(, $x)*);
137 #[cfg(feature = "defmt")]
138 ::defmt::info!($s $(, $x)*);
139 #[cfg(not(any(feature = "log", feature="defmt")))]
140 let _ = ($( & $x ),*);
141 }
142 };
143}
144
145macro_rules! warn {
146 ($s:literal $(, $x:expr)* $(,)?) => {
147 {
148 #[cfg(feature = "log")]
149 ::log::warn!($s $(, $x)*);
150 #[cfg(feature = "defmt")]
151 ::defmt::warn!($s $(, $x)*);
152 #[cfg(not(any(feature = "log", feature="defmt")))]
153 let _ = ($( & $x ),*);
154 }
155 };
156}
157
158macro_rules! error {
159 ($s:literal $(, $x:expr)* $(,)?) => {
160 {
161 #[cfg(feature = "log")]
162 ::log::error!($s $(, $x)*);
163 #[cfg(feature = "defmt")]
164 ::defmt::error!($s $(, $x)*);
165 #[cfg(not(any(feature = "log", feature="defmt")))]
166 let _ = ($( & $x ),*);
167 }
168 };
169}
170
171#[cfg(feature = "defmt")]
172macro_rules! unwrap {
173 ($($x:tt)*) => {
174 ::defmt::unwrap!($($x)*)
175 };
176}
177
178#[cfg(not(feature = "defmt"))]
179macro_rules! unwrap {
180 ($arg:expr) => {
181 match $crate::fmt::Try::into_result($arg) {
182 ::core::result::Result::Ok(t) => t,
183 ::core::result::Result::Err(e) => {
184 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
185 }
186 }
187 };
188 ($arg:expr, $($msg:expr),+ $(,)? ) => {
189 match $crate::fmt::Try::into_result($arg) {
190 ::core::result::Result::Ok(t) => t,
191 ::core::result::Result::Err(e) => {
192 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
193 }
194 }
195 }
196}
197
198#[derive(Debug, Copy, Clone, Eq, PartialEq)]
199pub struct NoneError;
200
201pub trait Try {
202 type Ok;
203 type Error;
204 fn into_result(self) -> Result<Self::Ok, Self::Error>;
205}
206
207impl<T> Try for Option<T> {
208 type Ok = T;
209 type Error = NoneError;
210
211 #[inline]
212 fn into_result(self) -> Result<T, NoneError> {
213 self.ok_or(NoneError)
214 }
215}
216
217impl<T, E> Try for Result<T, E> {
218 type Ok = T;
219 type Error = E;
220
221 #[inline]
222 fn into_result(self) -> Self {
223 self
224 }
225}
diff --git a/embassy-usb-serial/Cargo.toml b/embassy-usb-serial/Cargo.toml
deleted file mode 100644
index 9788588e9..000000000
--- a/embassy-usb-serial/Cargo.toml
+++ /dev/null
@@ -1,17 +0,0 @@
1[package]
2name = "embassy-usb-serial"
3version = "0.1.0"
4edition = "2021"
5
6[package.metadata.embassy_docs]
7src_base = "https://github.com/embassy-rs/embassy/blob/embassy-usb-serial-v$VERSION/embassy-usb-serial/src/"
8src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-serial/src/"
9features = ["defmt"]
10target = "thumbv7em-none-eabi"
11
12[dependencies]
13embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
14embassy-usb = { version = "0.1.0", path = "../embassy-usb" }
15
16defmt = { version = "0.3", optional = true }
17log = { version = "0.4.14", optional = true }
diff --git a/embassy-usb-serial/src/fmt.rs b/embassy-usb-serial/src/fmt.rs
deleted file mode 100644
index 066970813..000000000
--- a/embassy-usb-serial/src/fmt.rs
+++ /dev/null
@@ -1,225 +0,0 @@
1#![macro_use]
2#![allow(unused_macros)]
3
4#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features.");
6
7macro_rules! assert {
8 ($($x:tt)*) => {
9 {
10 #[cfg(not(feature = "defmt"))]
11 ::core::assert!($($x)*);
12 #[cfg(feature = "defmt")]
13 ::defmt::assert!($($x)*);
14 }
15 };
16}
17
18macro_rules! assert_eq {
19 ($($x:tt)*) => {
20 {
21 #[cfg(not(feature = "defmt"))]
22 ::core::assert_eq!($($x)*);
23 #[cfg(feature = "defmt")]
24 ::defmt::assert_eq!($($x)*);
25 }
26 };
27}
28
29macro_rules! assert_ne {
30 ($($x:tt)*) => {
31 {
32 #[cfg(not(feature = "defmt"))]
33 ::core::assert_ne!($($x)*);
34 #[cfg(feature = "defmt")]
35 ::defmt::assert_ne!($($x)*);
36 }
37 };
38}
39
40macro_rules! debug_assert {
41 ($($x:tt)*) => {
42 {
43 #[cfg(not(feature = "defmt"))]
44 ::core::debug_assert!($($x)*);
45 #[cfg(feature = "defmt")]
46 ::defmt::debug_assert!($($x)*);
47 }
48 };
49}
50
51macro_rules! debug_assert_eq {
52 ($($x:tt)*) => {
53 {
54 #[cfg(not(feature = "defmt"))]
55 ::core::debug_assert_eq!($($x)*);
56 #[cfg(feature = "defmt")]
57 ::defmt::debug_assert_eq!($($x)*);
58 }
59 };
60}
61
62macro_rules! debug_assert_ne {
63 ($($x:tt)*) => {
64 {
65 #[cfg(not(feature = "defmt"))]
66 ::core::debug_assert_ne!($($x)*);
67 #[cfg(feature = "defmt")]
68 ::defmt::debug_assert_ne!($($x)*);
69 }
70 };
71}
72
73macro_rules! todo {
74 ($($x:tt)*) => {
75 {
76 #[cfg(not(feature = "defmt"))]
77 ::core::todo!($($x)*);
78 #[cfg(feature = "defmt")]
79 ::defmt::todo!($($x)*);
80 }
81 };
82}
83
84macro_rules! unreachable {
85 ($($x:tt)*) => {
86 {
87 #[cfg(not(feature = "defmt"))]
88 ::core::unreachable!($($x)*);
89 #[cfg(feature = "defmt")]
90 ::defmt::unreachable!($($x)*);
91 }
92 };
93}
94
95macro_rules! panic {
96 ($($x:tt)*) => {
97 {
98 #[cfg(not(feature = "defmt"))]
99 ::core::panic!($($x)*);
100 #[cfg(feature = "defmt")]
101 ::defmt::panic!($($x)*);
102 }
103 };
104}
105
106macro_rules! trace {
107 ($s:literal $(, $x:expr)* $(,)?) => {
108 {
109 #[cfg(feature = "log")]
110 ::log::trace!($s $(, $x)*);
111 #[cfg(feature = "defmt")]
112 ::defmt::trace!($s $(, $x)*);
113 #[cfg(not(any(feature = "log", feature="defmt")))]
114 let _ = ($( & $x ),*);
115 }
116 };
117}
118
119macro_rules! debug {
120 ($s:literal $(, $x:expr)* $(,)?) => {
121 {
122 #[cfg(feature = "log")]
123 ::log::debug!($s $(, $x)*);
124 #[cfg(feature = "defmt")]
125 ::defmt::debug!($s $(, $x)*);
126 #[cfg(not(any(feature = "log", feature="defmt")))]
127 let _ = ($( & $x ),*);
128 }
129 };
130}
131
132macro_rules! info {
133 ($s:literal $(, $x:expr)* $(,)?) => {
134 {
135 #[cfg(feature = "log")]
136 ::log::info!($s $(, $x)*);
137 #[cfg(feature = "defmt")]
138 ::defmt::info!($s $(, $x)*);
139 #[cfg(not(any(feature = "log", feature="defmt")))]
140 let _ = ($( & $x ),*);
141 }
142 };
143}
144
145macro_rules! warn {
146 ($s:literal $(, $x:expr)* $(,)?) => {
147 {
148 #[cfg(feature = "log")]
149 ::log::warn!($s $(, $x)*);
150 #[cfg(feature = "defmt")]
151 ::defmt::warn!($s $(, $x)*);
152 #[cfg(not(any(feature = "log", feature="defmt")))]
153 let _ = ($( & $x ),*);
154 }
155 };
156}
157
158macro_rules! error {
159 ($s:literal $(, $x:expr)* $(,)?) => {
160 {
161 #[cfg(feature = "log")]
162 ::log::error!($s $(, $x)*);
163 #[cfg(feature = "defmt")]
164 ::defmt::error!($s $(, $x)*);
165 #[cfg(not(any(feature = "log", feature="defmt")))]
166 let _ = ($( & $x ),*);
167 }
168 };
169}
170
171#[cfg(feature = "defmt")]
172macro_rules! unwrap {
173 ($($x:tt)*) => {
174 ::defmt::unwrap!($($x)*)
175 };
176}
177
178#[cfg(not(feature = "defmt"))]
179macro_rules! unwrap {
180 ($arg:expr) => {
181 match $crate::fmt::Try::into_result($arg) {
182 ::core::result::Result::Ok(t) => t,
183 ::core::result::Result::Err(e) => {
184 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
185 }
186 }
187 };
188 ($arg:expr, $($msg:expr),+ $(,)? ) => {
189 match $crate::fmt::Try::into_result($arg) {
190 ::core::result::Result::Ok(t) => t,
191 ::core::result::Result::Err(e) => {
192 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
193 }
194 }
195 }
196}
197
198#[derive(Debug, Copy, Clone, Eq, PartialEq)]
199pub struct NoneError;
200
201pub trait Try {
202 type Ok;
203 type Error;
204 fn into_result(self) -> Result<Self::Ok, Self::Error>;
205}
206
207impl<T> Try for Option<T> {
208 type Ok = T;
209 type Error = NoneError;
210
211 #[inline]
212 fn into_result(self) -> Result<T, NoneError> {
213 self.ok_or(NoneError)
214 }
215}
216
217impl<T, E> Try for Result<T, E> {
218 type Ok = T;
219 type Error = E;
220
221 #[inline]
222 fn into_result(self) -> Self {
223 self
224 }
225}
diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml
index 8cad4d314..aad54dbaf 100644
--- a/embassy-usb/Cargo.toml
+++ b/embassy-usb/Cargo.toml
@@ -9,9 +9,20 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb/s
9features = ["defmt"] 9features = ["defmt"]
10target = "thumbv7em-none-eabi" 10target = "thumbv7em-none-eabi"
11 11
12[features]
13defmt = ["dep:defmt", "embassy-usb-driver/defmt"]
14usbd-hid = ["dep:usbd-hid", "dep:ssmarshal"]
15default = ["usbd-hid"]
16
12[dependencies] 17[dependencies]
13embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 18embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
19embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" }
20embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
14 21
15defmt = { version = "0.3", optional = true } 22defmt = { version = "0.3", optional = true }
16log = { version = "0.4.14", optional = true } 23log = { version = "0.4.14", optional = true }
17heapless = "0.7.10" \ No newline at end of file 24heapless = "0.7.10"
25
26# for HID
27usbd-hid = { version = "0.6.0", optional = true }
28ssmarshal = { version = "1.0", default-features = false, optional = true }
diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs
index 6be88bc76..87a8333bb 100644
--- a/embassy-usb/src/builder.rs
+++ b/embassy-usb/src/builder.rs
@@ -1,11 +1,10 @@
1use heapless::Vec; 1use heapless::Vec;
2 2
3use super::control::ControlHandler; 3use crate::control::ControlHandler;
4use super::descriptor::{BosWriter, DescriptorWriter}; 4use crate::descriptor::{BosWriter, DescriptorWriter};
5use super::driver::{Driver, Endpoint}; 5use crate::driver::{Driver, Endpoint, EndpointType};
6use super::types::*; 6use crate::types::*;
7use super::{DeviceStateHandler, UsbDevice, MAX_INTERFACE_COUNT}; 7use crate::{DeviceStateHandler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START};
8use crate::{Interface, STRING_INDEX_CUSTOM_START};
9 8
10#[derive(Debug, Copy, Clone)] 9#[derive(Debug, Copy, Clone)]
11#[cfg_attr(feature = "defmt", derive(defmt::Format))] 10#[cfg_attr(feature = "defmt", derive(defmt::Format))]
diff --git a/embassy-usb-serial/src/lib.rs b/embassy-usb/src/class/cdc_acm.rs
index f3de2ec1b..09bb1cc8d 100644
--- a/embassy-usb-serial/src/lib.rs
+++ b/embassy-usb/src/class/cdc_acm.rs
@@ -1,19 +1,13 @@
1#![no_std]
2#![feature(generic_associated_types)]
3#![feature(type_alias_impl_trait)]
4
5// This mod MUST go first, so that the others see its macros.
6pub(crate) mod fmt;
7
8use core::cell::Cell; 1use core::cell::Cell;
9use core::mem::{self, MaybeUninit}; 2use core::mem::{self, MaybeUninit};
10use core::sync::atomic::{AtomicBool, Ordering}; 3use core::sync::atomic::{AtomicBool, Ordering};
11 4
12use embassy_sync::blocking_mutex::CriticalSectionMutex; 5use embassy_sync::blocking_mutex::CriticalSectionMutex;
13use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request}; 6
14use embassy_usb::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; 7use crate::control::{self, ControlHandler, InResponse, OutResponse, Request};
15use embassy_usb::types::*; 8use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
16use embassy_usb::Builder; 9use crate::types::*;
10use crate::Builder;
17 11
18/// This should be used as `device_class` when building the `UsbDevice`. 12/// This should be used as `device_class` when building the `UsbDevice`.
19pub const USB_CLASS_CDC: u8 = 0x02; 13pub const USB_CLASS_CDC: u8 = 0x02;
@@ -269,7 +263,7 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
269} 263}
270 264
271/// Number of stop bits for LineCoding 265/// Number of stop bits for LineCoding
272#[derive(Copy, Clone, PartialEq, Eq)] 266#[derive(Copy, Clone, Debug, PartialEq, Eq)]
273#[cfg_attr(feature = "defmt", derive(defmt::Format))] 267#[cfg_attr(feature = "defmt", derive(defmt::Format))]
274pub enum StopBits { 268pub enum StopBits {
275 /// 1 stop bit 269 /// 1 stop bit
@@ -293,7 +287,7 @@ impl From<u8> for StopBits {
293} 287}
294 288
295/// Parity for LineCoding 289/// Parity for LineCoding
296#[derive(Copy, Clone, PartialEq, Eq)] 290#[derive(Copy, Clone, Debug, PartialEq, Eq)]
297#[cfg_attr(feature = "defmt", derive(defmt::Format))] 291#[cfg_attr(feature = "defmt", derive(defmt::Format))]
298pub enum ParityType { 292pub enum ParityType {
299 None = 0, 293 None = 0,
@@ -317,7 +311,7 @@ impl From<u8> for ParityType {
317/// 311///
318/// This is provided by the host for specifying the standard UART parameters such as baud rate. Can 312/// This is provided by the host for specifying the standard UART parameters such as baud rate. Can
319/// be ignored if you don't plan to interface with a physical UART. 313/// be ignored if you don't plan to interface with a physical UART.
320#[derive(Clone, Copy)] 314#[derive(Clone, Copy, Debug)]
321#[cfg_attr(feature = "defmt", derive(defmt::Format))] 315#[cfg_attr(feature = "defmt", derive(defmt::Format))]
322pub struct LineCoding { 316pub struct LineCoding {
323 stop_bits: StopBits, 317 stop_bits: StopBits,
diff --git a/embassy-usb-ncm/src/lib.rs b/embassy-usb/src/class/cdc_ncm.rs
index e796af28f..a39b87e9b 100644
--- a/embassy-usb-ncm/src/lib.rs
+++ b/embassy-usb/src/class/cdc_ncm.rs
@@ -1,15 +1,10 @@
1#![no_std]
2
3// This mod MUST go first, so that the others see its macros.
4pub(crate) mod fmt;
5
6use core::intrinsics::copy_nonoverlapping; 1use core::intrinsics::copy_nonoverlapping;
7use core::mem::{size_of, MaybeUninit}; 2use core::mem::{size_of, MaybeUninit};
8 3
9use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request}; 4use crate::control::{self, ControlHandler, InResponse, OutResponse, Request};
10use embassy_usb::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; 5use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
11use embassy_usb::types::*; 6use crate::types::*;
12use embassy_usb::Builder; 7use crate::Builder;
13 8
14/// This should be used as `device_class` when building the `UsbDevice`. 9/// This should be used as `device_class` when building the `UsbDevice`.
15pub const USB_CLASS_CDC: u8 = 0x02; 10pub const USB_CLASS_CDC: u8 = 0x02;
diff --git a/embassy-usb-hid/src/lib.rs b/embassy-usb/src/class/hid.rs
index 5fee60bbc..4d1fa995f 100644
--- a/embassy-usb-hid/src/lib.rs
+++ b/embassy-usb/src/class/hid.rs
@@ -1,24 +1,16 @@
1#![no_std]
2#![feature(generic_associated_types)]
3#![feature(type_alias_impl_trait)]
4
5//! Implements HID functionality for a usb-device device.
6
7// This mod MUST go first, so that the others see its macros.
8pub(crate) mod fmt;
9
10use core::mem::MaybeUninit; 1use core::mem::MaybeUninit;
11use core::ops::Range; 2use core::ops::Range;
12use core::sync::atomic::{AtomicUsize, Ordering}; 3use core::sync::atomic::{AtomicUsize, Ordering};
13 4
14use embassy_usb::control::{ControlHandler, InResponse, OutResponse, Request, RequestType};
15use embassy_usb::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
16use embassy_usb::Builder;
17#[cfg(feature = "usbd-hid")] 5#[cfg(feature = "usbd-hid")]
18use ssmarshal::serialize; 6use ssmarshal::serialize;
19#[cfg(feature = "usbd-hid")] 7#[cfg(feature = "usbd-hid")]
20use usbd_hid::descriptor::AsInputReport; 8use usbd_hid::descriptor::AsInputReport;
21 9
10use crate::control::{ControlHandler, InResponse, OutResponse, Request, RequestType};
11use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
12use crate::Builder;
13
22const USB_CLASS_HID: u8 = 0x03; 14const USB_CLASS_HID: u8 = 0x03;
23const USB_SUBCLASS_NONE: u8 = 0x00; 15const USB_SUBCLASS_NONE: u8 = 0x00;
24const USB_PROTOCOL_NONE: u8 = 0x00; 16const USB_PROTOCOL_NONE: u8 = 0x00;
@@ -205,9 +197,9 @@ pub enum ReadError {
205 Sync(Range<usize>), 197 Sync(Range<usize>),
206} 198}
207 199
208impl From<embassy_usb::driver::EndpointError> for ReadError { 200impl From<EndpointError> for ReadError {
209 fn from(val: embassy_usb::driver::EndpointError) -> Self { 201 fn from(val: EndpointError) -> Self {
210 use embassy_usb::driver::EndpointError::*; 202 use EndpointError::*;
211 match val { 203 match val {
212 BufferOverflow => ReadError::BufferOverflow, 204 BufferOverflow => ReadError::BufferOverflow,
213 Disabled => ReadError::Disabled, 205 Disabled => ReadError::Disabled,
@@ -438,7 +430,7 @@ impl<'d> ControlHandler for Control<'d> {
438 } 430 }
439 } 431 }
440 432
441 fn control_out(&mut self, req: embassy_usb::control::Request, data: &[u8]) -> OutResponse { 433 fn control_out(&mut self, req: Request, data: &[u8]) -> OutResponse {
442 trace!("HID control_out {:?} {=[u8]:x}", req, data); 434 trace!("HID control_out {:?} {=[u8]:x}", req, data);
443 if let RequestType::Class = req.request_type { 435 if let RequestType::Class = req.request_type {
444 match req.request { 436 match req.request {
diff --git a/embassy-usb/src/class/mod.rs b/embassy-usb/src/class/mod.rs
new file mode 100644
index 000000000..af27577a6
--- /dev/null
+++ b/embassy-usb/src/class/mod.rs
@@ -0,0 +1,3 @@
1pub mod cdc_acm;
2pub mod cdc_ncm;
3pub mod hid;
diff --git a/embassy-usb/src/control.rs b/embassy-usb/src/control.rs
index 3e5749a01..d6d0c6565 100644
--- a/embassy-usb/src/control.rs
+++ b/embassy-usb/src/control.rs
@@ -1,7 +1,8 @@
1//! USB control data types. 1//! USB control data types.
2use core::mem; 2use core::mem;
3 3
4use super::types::*; 4use crate::driver::Direction;
5use crate::types::StringIndex;
5 6
6/// Control request type. 7/// Control request type.
7#[repr(u8)] 8#[repr(u8)]
@@ -42,7 +43,7 @@ pub enum Recipient {
42#[cfg_attr(feature = "defmt", derive(defmt::Format))] 43#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43pub struct Request { 44pub struct Request {
44 /// Direction of the request. 45 /// Direction of the request.
45 pub direction: UsbDirection, 46 pub direction: Direction,
46 /// Type of the request. 47 /// Type of the request.
47 pub request_type: RequestType, 48 pub request_type: RequestType,
48 /// Recipient of the request. 49 /// Recipient of the request.
@@ -105,7 +106,7 @@ impl Request {
105 let recipient = rt & 0b11111; 106 let recipient = rt & 0b11111;
106 107
107 Request { 108 Request {
108 direction: rt.into(), 109 direction: if rt & 0x80 == 0 { Direction::Out } else { Direction::In },
109 request_type: unsafe { mem::transmute((rt >> 5) & 0b11) }, 110 request_type: unsafe { mem::transmute((rt >> 5) & 0b11) },
110 recipient: if recipient <= 3 { 111 recipient: if recipient <= 3 {
111 unsafe { mem::transmute(recipient) } 112 unsafe { mem::transmute(recipient) }
diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs
index b94a4b161..497f03196 100644
--- a/embassy-usb/src/descriptor.rs
+++ b/embassy-usb/src/descriptor.rs
@@ -1,6 +1,7 @@
1use super::builder::Config; 1use crate::builder::Config;
2use super::types::*; 2use crate::driver::EndpointInfo;
3use super::CONFIGURATION_VALUE; 3use crate::types::*;
4use crate::CONFIGURATION_VALUE;
4 5
5/// Standard descriptor types 6/// Standard descriptor types
6#[allow(missing_docs)] 7#[allow(missing_docs)]
diff --git a/embassy-usb/src/descriptor_reader.rs b/embassy-usb/src/descriptor_reader.rs
index 0a12b566c..d64bcb73b 100644
--- a/embassy-usb/src/descriptor_reader.rs
+++ b/embassy-usb/src/descriptor_reader.rs
@@ -1,5 +1,5 @@
1use crate::descriptor::descriptor_type; 1use crate::descriptor::descriptor_type;
2use crate::types::EndpointAddress; 2use crate::driver::EndpointAddress;
3 3
4#[derive(Copy, Clone, PartialEq, Eq, Debug)] 4#[derive(Copy, Clone, PartialEq, Eq, Debug)]
5#[cfg_attr(feature = "defmt", derive(defmt::Format))] 5#[cfg_attr(feature = "defmt", derive(defmt::Format))]
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index b165804ef..661b84119 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -1,27 +1,27 @@
1#![no_std] 1#![no_std]
2#![feature(generic_associated_types)]
3#![feature(type_alias_impl_trait)] 2#![feature(type_alias_impl_trait)]
4 3
5// This mod MUST go first, so that the others see its macros. 4// This mod MUST go first, so that the others see its macros.
6pub(crate) mod fmt; 5pub(crate) mod fmt;
7 6
7pub use embassy_usb_driver as driver;
8
8mod builder; 9mod builder;
10pub mod class;
9pub mod control; 11pub mod control;
10pub mod descriptor; 12pub mod descriptor;
11mod descriptor_reader; 13mod descriptor_reader;
12pub mod driver;
13pub mod types; 14pub mod types;
14 15
15use embassy_futures::select::{select, Either}; 16use embassy_futures::select::{select, Either};
16use heapless::Vec; 17use heapless::Vec;
17 18
18pub use self::builder::{Builder, Config}; 19pub use crate::builder::{Builder, Config};
19use self::control::*; 20use crate::control::*;
20use self::descriptor::*; 21use crate::descriptor::*;
21use self::driver::{Bus, Driver, Event};
22use self::types::*;
23use crate::descriptor_reader::foreach_endpoint; 22use crate::descriptor_reader::foreach_endpoint;
24use crate::driver::ControlPipe; 23use crate::driver::{Bus, ControlPipe, Direction, Driver, EndpointAddress, Event};
24use crate::types::*;
25 25
26/// The global state of the USB device. 26/// The global state of the USB device.
27/// 27///
@@ -248,11 +248,11 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
248 async fn handle_control(&mut self, req: [u8; 8]) { 248 async fn handle_control(&mut self, req: [u8; 8]) {
249 let req = Request::parse(&req); 249 let req = Request::parse(&req);
250 250
251 trace!("control request: {:02x}", req); 251 trace!("control request: {:?}", req);
252 252
253 match req.direction { 253 match req.direction {
254 UsbDirection::In => self.handle_control_in(req).await, 254 Direction::In => self.handle_control_in(req).await,
255 UsbDirection::Out => self.handle_control_out(req).await, 255 Direction::Out => self.handle_control_out(req).await,
256 } 256 }
257 257
258 if self.inner.set_address_pending { 258 if self.inner.set_address_pending {
diff --git a/embassy-usb/src/types.rs b/embassy-usb/src/types.rs
index b8717ffa9..aeab063d1 100644
--- a/embassy-usb/src/types.rs
+++ b/embassy-usb/src/types.rs
@@ -1,108 +1,3 @@
1/// Direction of USB traffic. Note that in the USB standard the direction is always indicated from
2/// the perspective of the host, which is backward for devices, but the standard directions are used
3/// for consistency.
4///
5/// The values of the enum also match the direction bit used in endpoint addresses and control
6/// request types.
7#[repr(u8)]
8#[derive(Copy, Clone, Eq, PartialEq, Debug)]
9#[cfg_attr(feature = "defmt", derive(defmt::Format))]
10pub enum UsbDirection {
11 /// Host to device (OUT)
12 Out = 0x00,
13 /// Device to host (IN)
14 In = 0x80,
15}
16
17impl From<u8> for UsbDirection {
18 fn from(value: u8) -> Self {
19 unsafe { core::mem::transmute(value & 0x80) }
20 }
21}
22
23/// USB endpoint transfer type. The values of this enum can be directly cast into `u8` to get the
24/// transfer bmAttributes transfer type bits.
25#[repr(u8)]
26#[derive(Copy, Clone, Eq, PartialEq, Debug)]
27#[cfg_attr(feature = "defmt", derive(defmt::Format))]
28pub enum EndpointType {
29 /// Control endpoint. Used for device management. Only the host can initiate requests. Usually
30 /// used only endpoint 0.
31 Control = 0b00,
32 /// Isochronous endpoint. Used for time-critical unreliable data. Not implemented yet.
33 Isochronous = 0b01,
34 /// Bulk endpoint. Used for large amounts of best-effort reliable data.
35 Bulk = 0b10,
36 /// Interrupt endpoint. Used for small amounts of time-critical reliable data.
37 Interrupt = 0b11,
38}
39
40/// Type-safe endpoint address.
41#[derive(Debug, Clone, Copy, Eq, PartialEq)]
42#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43pub struct EndpointAddress(u8);
44
45impl From<u8> for EndpointAddress {
46 #[inline]
47 fn from(addr: u8) -> EndpointAddress {
48 EndpointAddress(addr)
49 }
50}
51
52impl From<EndpointAddress> for u8 {
53 #[inline]
54 fn from(addr: EndpointAddress) -> u8 {
55 addr.0
56 }
57}
58
59impl EndpointAddress {
60 const INBITS: u8 = UsbDirection::In as u8;
61
62 /// Constructs a new EndpointAddress with the given index and direction.
63 #[inline]
64 pub fn from_parts(index: usize, dir: UsbDirection) -> Self {
65 EndpointAddress(index as u8 | dir as u8)
66 }
67
68 /// Gets the direction part of the address.
69 #[inline]
70 pub fn direction(&self) -> UsbDirection {
71 if (self.0 & Self::INBITS) != 0 {
72 UsbDirection::In
73 } else {
74 UsbDirection::Out
75 }
76 }
77
78 /// Returns true if the direction is IN, otherwise false.
79 #[inline]
80 pub fn is_in(&self) -> bool {
81 (self.0 & Self::INBITS) != 0
82 }
83
84 /// Returns true if the direction is OUT, otherwise false.
85 #[inline]
86 pub fn is_out(&self) -> bool {
87 (self.0 & Self::INBITS) == 0
88 }
89
90 /// Gets the index part of the endpoint address.
91 #[inline]
92 pub fn index(&self) -> usize {
93 (self.0 & !Self::INBITS) as usize
94 }
95}
96
97#[derive(Copy, Clone, Eq, PartialEq, Debug)]
98#[cfg_attr(feature = "defmt", derive(defmt::Format))]
99pub struct EndpointInfo {
100 pub addr: EndpointAddress,
101 pub ep_type: EndpointType,
102 pub max_packet_size: u16,
103 pub interval: u8,
104}
105
106/// A handle for a USB interface that contains its number. 1/// A handle for a USB interface that contains its number.
107#[derive(Copy, Clone, Eq, PartialEq)] 2#[derive(Copy, Clone, Eq, PartialEq)]
108#[cfg_attr(feature = "defmt", derive(defmt::Format))] 3#[cfg_attr(feature = "defmt", derive(defmt::Format))]
diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs
index 133a3e678..7a404a914 100644
--- a/examples/boot/application/nrf/src/bin/a.rs
+++ b/examples/boot/application/nrf/src/bin/a.rs
@@ -1,7 +1,6 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![macro_use] 3#![macro_use]
4#![feature(generic_associated_types)]
5#![feature(type_alias_impl_trait)] 4#![feature(type_alias_impl_trait)]
6 5
7use embassy_boot_nrf::FirmwareUpdater; 6use embassy_boot_nrf::FirmwareUpdater;
diff --git a/examples/boot/application/nrf/src/bin/b.rs b/examples/boot/application/nrf/src/bin/b.rs
index 5394bf0c7..1373f277d 100644
--- a/examples/boot/application/nrf/src/bin/b.rs
+++ b/examples/boot/application/nrf/src/bin/b.rs
@@ -1,7 +1,6 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![macro_use] 3#![macro_use]
4#![feature(generic_associated_types)]
5#![feature(type_alias_impl_trait)] 4#![feature(type_alias_impl_trait)]
6 5
7use embassy_executor::Spawner; 6use embassy_executor::Spawner;
diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs
index 9031997c2..8266206b3 100644
--- a/examples/boot/bootloader/nrf/src/main.rs
+++ b/examples/boot/bootloader/nrf/src/main.rs
@@ -21,7 +21,7 @@ fn main() -> ! {
21 21
22 let mut bl = BootLoader::default(); 22 let mut bl = BootLoader::default();
23 let start = bl.prepare(&mut SingleFlashConfig::new(&mut BootFlash::<_, 4096>::new( 23 let start = bl.prepare(&mut SingleFlashConfig::new(&mut BootFlash::<_, 4096>::new(
24 &mut WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, 5), 24 WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, 5),
25 ))); 25 )));
26 unsafe { bl.load(start) } 26 unsafe { bl.load(start) }
27} 27}
diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs
index bb5d3e531..294464d1c 100644
--- a/examples/boot/bootloader/stm32/src/main.rs
+++ b/examples/boot/bootloader/stm32/src/main.rs
@@ -20,10 +20,9 @@ fn main() -> ! {
20 */ 20 */
21 21
22 let mut bl: BootLoader<ERASE_SIZE, WRITE_SIZE> = BootLoader::default(); 22 let mut bl: BootLoader<ERASE_SIZE, WRITE_SIZE> = BootLoader::default();
23 let mut flash = Flash::unlock(p.FLASH); 23 let flash = Flash::unlock(p.FLASH);
24 let start = bl.prepare(&mut SingleFlashConfig::new( 24 let mut flash = BootFlash::<_, ERASE_SIZE, ERASE_VALUE>::new(flash);
25 &mut BootFlash::<_, ERASE_SIZE, ERASE_VALUE>::new(&mut flash), 25 let start = bl.prepare(&mut SingleFlashConfig::new(&mut flash));
26 ));
27 core::mem::drop(flash); 26 core::mem::drop(flash);
28 unsafe { bl.load(start) } 27 unsafe { bl.load(start) }
29} 28}
diff --git a/examples/nrf-rtos-trace/src/bin/rtos_trace.rs b/examples/nrf-rtos-trace/src/bin/rtos_trace.rs
index 7d1ad87c8..cf8b2f808 100644
--- a/examples/nrf-rtos-trace/src/bin/rtos_trace.rs
+++ b/examples/nrf-rtos-trace/src/bin/rtos_trace.rs
@@ -2,6 +2,7 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use core::future::poll_fn;
5use core::task::Poll; 6use core::task::Poll;
6 7
7use embassy_executor::Spawner; 8use embassy_executor::Spawner;
@@ -46,7 +47,7 @@ async fn run2() {
46 47
47#[embassy_executor::task] 48#[embassy_executor::task]
48async fn run3() { 49async fn run3() {
49 futures::future::poll_fn(|cx| { 50 poll_fn(|cx| {
50 cx.waker().wake_by_ref(); 51 cx.waker().wake_by_ref();
51 Poll::<()>::Pending 52 Poll::<()>::Pending
52 }) 53 })
diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml
index dbc659cda..a5d340c69 100644
--- a/examples/nrf/Cargo.toml
+++ b/examples/nrf/Cargo.toml
@@ -5,7 +5,7 @@ version = "0.1.0"
5 5
6[features] 6[features]
7default = ["nightly"] 7default = ["nightly"]
8nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embassy-usb-serial", "embassy-usb-hid", "embassy-usb-ncm", "embedded-io/async", "embassy-net"] 8nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net"]
9 9
10[dependencies] 10[dependencies]
11embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 11embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
@@ -15,9 +15,6 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de
15embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } 15embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
16embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true } 16embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true }
17embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } 17embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true }
18embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"], optional = true }
19embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"], optional = true }
20embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", features = ["defmt"], optional = true }
21embedded-io = "0.3.0" 18embedded-io = "0.3.0"
22 19
23defmt = "0.3" 20defmt = "0.3"
diff --git a/examples/nrf/src/bin/executor_fairness_test.rs b/examples/nrf/src/bin/executor_fairness_test.rs
index 9ae030d07..2a28f2763 100644
--- a/examples/nrf/src/bin/executor_fairness_test.rs
+++ b/examples/nrf/src/bin/executor_fairness_test.rs
@@ -2,6 +2,7 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use core::future::poll_fn;
5use core::task::Poll; 6use core::task::Poll;
6 7
7use defmt::{info, unwrap}; 8use defmt::{info, unwrap};
@@ -26,7 +27,7 @@ async fn run2() {
26 27
27#[embassy_executor::task] 28#[embassy_executor::task]
28async fn run3() { 29async fn run3() {
29 futures::future::poll_fn(|cx| { 30 poll_fn(|cx| {
30 cx.waker().wake_by_ref(); 31 cx.waker().wake_by_ref();
31 Poll::<()>::Pending 32 Poll::<()>::Pending
32 }) 33 })
diff --git a/examples/nrf/src/bin/usb_ethernet.rs b/examples/nrf/src/bin/usb_ethernet.rs
index 352660b59..de93a2b45 100644
--- a/examples/nrf/src/bin/usb_ethernet.rs
+++ b/examples/nrf/src/bin/usb_ethernet.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
5 4
6use core::mem; 5use core::mem;
@@ -16,8 +15,8 @@ use embassy_nrf::usb::{Driver, PowerUsb};
16use embassy_nrf::{interrupt, pac, peripherals}; 15use embassy_nrf::{interrupt, pac, peripherals};
17use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 16use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
18use embassy_sync::channel::Channel; 17use embassy_sync::channel::Channel;
18use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State};
19use embassy_usb::{Builder, Config, UsbDevice}; 19use embassy_usb::{Builder, Config, UsbDevice};
20use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
21use embedded_io::asynch::Write; 20use embedded_io::asynch::Write;
22use static_cell::StaticCell; 21use static_cell::StaticCell;
23use {defmt_rtt as _, panic_probe as _}; 22use {defmt_rtt as _, panic_probe as _};
diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf/src/bin/usb_hid_keyboard.rs
index 7fdb0b685..76e198719 100644
--- a/examples/nrf/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf/src/bin/usb_hid_keyboard.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
5 4
6use core::mem; 5use core::mem;
@@ -8,15 +7,16 @@ use core::sync::atomic::{AtomicBool, Ordering};
8 7
9use defmt::*; 8use defmt::*;
10use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_futures::join::join;
11use embassy_futures::select::{select, Either}; 11use embassy_futures::select::{select, Either};
12use embassy_nrf::gpio::{Input, Pin, Pull}; 12use embassy_nrf::gpio::{Input, Pin, Pull};
13use embassy_nrf::usb::{Driver, PowerUsb}; 13use embassy_nrf::usb::{Driver, PowerUsb};
14use embassy_nrf::{interrupt, pac}; 14use embassy_nrf::{interrupt, pac};
15use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
15use embassy_sync::signal::Signal; 16use embassy_sync::signal::Signal;
17use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
16use embassy_usb::control::OutResponse; 18use embassy_usb::control::OutResponse;
17use embassy_usb::{Builder, Config, DeviceStateHandler}; 19use embassy_usb::{Builder, Config, DeviceStateHandler};
18use embassy_usb_hid::{HidReaderWriter, ReportId, RequestHandler, State};
19use futures::future::join;
20use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 20use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
21use {defmt_rtt as _, panic_probe as _}; 21use {defmt_rtt as _, panic_probe as _};
22 22
@@ -67,7 +67,7 @@ async fn main(_spawner: Spawner) {
67 ); 67 );
68 68
69 // Create classes on the builder. 69 // Create classes on the builder.
70 let config = embassy_usb_hid::Config { 70 let config = embassy_usb::class::hid::Config {
71 report_descriptor: KeyboardReport::desc(), 71 report_descriptor: KeyboardReport::desc(),
72 request_handler: Some(&request_handler), 72 request_handler: Some(&request_handler),
73 poll_ms: 60, 73 poll_ms: 60,
@@ -78,7 +78,7 @@ async fn main(_spawner: Spawner) {
78 // Build the builder. 78 // Build the builder.
79 let mut usb = builder.build(); 79 let mut usb = builder.build();
80 80
81 let remote_wakeup = Signal::new(); 81 let remote_wakeup: Signal<CriticalSectionRawMutex, _> = Signal::new();
82 82
83 // Run the USB device. 83 // Run the USB device.
84 let usb_fut = async { 84 let usb_fut = async {
diff --git a/examples/nrf/src/bin/usb_hid_mouse.rs b/examples/nrf/src/bin/usb_hid_mouse.rs
index 7cd2ece17..4916a38d4 100644
--- a/examples/nrf/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf/src/bin/usb_hid_mouse.rs
@@ -1,19 +1,18 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
5 4
6use core::mem; 5use core::mem;
7 6
8use defmt::*; 7use defmt::*;
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_futures::join::join;
10use embassy_nrf::usb::{Driver, PowerUsb}; 10use embassy_nrf::usb::{Driver, PowerUsb};
11use embassy_nrf::{interrupt, pac}; 11use embassy_nrf::{interrupt, pac};
12use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
13use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
13use embassy_usb::control::OutResponse; 14use embassy_usb::control::OutResponse;
14use embassy_usb::{Builder, Config}; 15use embassy_usb::{Builder, Config};
15use embassy_usb_hid::{HidWriter, ReportId, RequestHandler, State};
16use futures::future::join;
17use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; 16use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
18use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
19 18
@@ -60,7 +59,7 @@ async fn main(_spawner: Spawner) {
60 ); 59 );
61 60
62 // Create classes on the builder. 61 // Create classes on the builder.
63 let config = embassy_usb_hid::Config { 62 let config = embassy_usb::class::hid::Config {
64 report_descriptor: MouseReport::desc(), 63 report_descriptor: MouseReport::desc(),
65 request_handler: Some(&request_handler), 64 request_handler: Some(&request_handler),
66 poll_ms: 60, 65 poll_ms: 60,
diff --git a/examples/nrf/src/bin/usb_serial.rs b/examples/nrf/src/bin/usb_serial.rs
index a68edb329..7c9c4184b 100644
--- a/examples/nrf/src/bin/usb_serial.rs
+++ b/examples/nrf/src/bin/usb_serial.rs
@@ -1,18 +1,17 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
5 4
6use core::mem; 5use core::mem;
7 6
8use defmt::{info, panic}; 7use defmt::{info, panic};
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_futures::join::join;
10use embassy_nrf::usb::{Driver, Instance, PowerUsb, UsbSupply}; 10use embassy_nrf::usb::{Driver, Instance, PowerUsb, UsbSupply};
11use embassy_nrf::{interrupt, pac}; 11use embassy_nrf::{interrupt, pac};
12use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError; 13use embassy_usb::driver::EndpointError;
13use embassy_usb::{Builder, Config}; 14use embassy_usb::{Builder, Config};
14use embassy_usb_serial::{CdcAcmClass, State};
15use futures::future::join;
16use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
17 16
18#[embassy_executor::main] 17#[embassy_executor::main]
diff --git a/examples/nrf/src/bin/usb_serial_multitask.rs b/examples/nrf/src/bin/usb_serial_multitask.rs
index d62d7e520..93efc2fe6 100644
--- a/examples/nrf/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf/src/bin/usb_serial_multitask.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
5 4
6use core::mem; 5use core::mem;
@@ -9,9 +8,9 @@ use defmt::{info, panic, unwrap};
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
10use embassy_nrf::usb::{Driver, PowerUsb}; 9use embassy_nrf::usb::{Driver, PowerUsb};
11use embassy_nrf::{interrupt, pac, peripherals}; 10use embassy_nrf::{interrupt, pac, peripherals};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError; 12use embassy_usb::driver::EndpointError;
13use embassy_usb::{Builder, Config, UsbDevice}; 13use embassy_usb::{Builder, Config, UsbDevice};
14use embassy_usb_serial::{CdcAcmClass, State};
15use static_cell::StaticCell; 14use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
17 16
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 18a92b094..3c8f923e7 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -8,11 +8,10 @@ version = "0.1.0"
8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
11embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac"] } 11embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver"] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
13embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] }
14embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } 13embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
15embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", features = ["defmt"] } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
16 15
17defmt = "0.3" 16defmt = "0.3"
18defmt-rtt = "0.3" 17defmt-rtt = "0.3"
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
index 2df7f62f6..1057fe7fd 100644
--- a/examples/rp/src/bin/usb_ethernet.rs
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
5 4
6use core::sync::atomic::{AtomicBool, Ordering}; 5use core::sync::atomic::{AtomicBool, Ordering};
@@ -14,8 +13,8 @@ use embassy_rp::usb::Driver;
14use embassy_rp::{interrupt, peripherals}; 13use embassy_rp::{interrupt, peripherals};
15use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 14use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
16use embassy_sync::channel::Channel; 15use embassy_sync::channel::Channel;
16use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State};
17use embassy_usb::{Builder, Config, UsbDevice}; 17use embassy_usb::{Builder, Config, UsbDevice};
18use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
19use embedded_io::asynch::Write; 18use embedded_io::asynch::Write;
20use static_cell::StaticCell; 19use static_cell::StaticCell;
21use {defmt_rtt as _, panic_probe as _}; 20use {defmt_rtt as _, panic_probe as _};
diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs
index 74be1f598..b7d6493b4 100644
--- a/examples/rp/src/bin/usb_serial.rs
+++ b/examples/rp/src/bin/usb_serial.rs
@@ -1,16 +1,15 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
5 4
6use defmt::{info, panic}; 5use defmt::{info, panic};
7use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_futures::join::join;
8use embassy_rp::interrupt; 8use embassy_rp::interrupt;
9use embassy_rp::usb::{Driver, Instance}; 9use embassy_rp::usb::{Driver, Instance};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
10use embassy_usb::driver::EndpointError; 11use embassy_usb::driver::EndpointError;
11use embassy_usb::{Builder, Config}; 12use embassy_usb::{Builder, Config};
12use embassy_usb_serial::{CdcAcmClass, State};
13use futures::future::join;
14use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
15 14
16#[embassy_executor::main] 15#[embassy_executor::main]
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index 33ac63db1..e6553789a 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -9,7 +9,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
10embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any"] } 10embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any"] }
11embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 11embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
12embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] } 12embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
13 13
14defmt = "0.3" 14defmt = "0.3"
15defmt-rtt = "0.3" 15defmt-rtt = "0.3"
diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs
index a9c46068f..ad92cdeb2 100644
--- a/examples/stm32f1/src/bin/usb_serial.rs
+++ b/examples/stm32f1/src/bin/usb_serial.rs
@@ -4,15 +4,15 @@
4 4
5use defmt::{panic, *}; 5use defmt::{panic, *};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_futures::join::join;
7use embassy_stm32::gpio::{Level, Output, Speed}; 8use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::time::Hertz; 9use embassy_stm32::time::Hertz;
9use embassy_stm32::usb::{Driver, Instance}; 10use embassy_stm32::usb::{Driver, Instance};
10use embassy_stm32::{interrupt, Config}; 11use embassy_stm32::{interrupt, Config};
11use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
13use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError; 14use embassy_usb::driver::EndpointError;
13use embassy_usb::Builder; 15use embassy_usb::Builder;
14use embassy_usb_serial::{CdcAcmClass, State};
15use futures::future::join;
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
17 17
18#[embassy_executor::main] 18#[embassy_executor::main]
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml
index 208f39080..f5b0b880c 100644
--- a/examples/stm32f3/Cargo.toml
+++ b/examples/stm32f3/Cargo.toml
@@ -9,8 +9,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
10embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 10embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
11embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 11embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
12embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] } 12embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
13embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"] }
14 13
15defmt = "0.3" 14defmt = "0.3"
16defmt-rtt = "0.3" 15defmt-rtt = "0.3"
diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs
index d3702fc35..f6d27c860 100644
--- a/examples/stm32f3/src/bin/usb_serial.rs
+++ b/examples/stm32f3/src/bin/usb_serial.rs
@@ -4,15 +4,15 @@
4 4
5use defmt::{panic, *}; 5use defmt::{panic, *};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_futures::join::join;
7use embassy_stm32::gpio::{Level, Output, Speed}; 8use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::time::mhz; 9use embassy_stm32::time::mhz;
9use embassy_stm32::usb::{Driver, Instance}; 10use embassy_stm32::usb::{Driver, Instance};
10use embassy_stm32::{interrupt, Config}; 11use embassy_stm32::{interrupt, Config};
11use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
13use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError; 14use embassy_usb::driver::EndpointError;
13use embassy_usb::Builder; 15use embassy_usb::Builder;
14use embassy_usb_serial::{CdcAcmClass, State};
15use futures::future::join;
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
17 17
18#[embassy_executor::main] 18#[embassy_executor::main]
diff --git a/examples/stm32h7/src/bin/signal.rs b/examples/stm32h7/src/bin/signal.rs
index cc3e4e3ca..6d7c168d5 100644
--- a/examples/stm32h7/src/bin/signal.rs
+++ b/examples/stm32h7/src/bin/signal.rs
@@ -4,11 +4,12 @@
4 4
5use defmt::{info, unwrap}; 5use defmt::{info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
7use embassy_sync::signal::Signal; 8use embassy_sync::signal::Signal;
8use embassy_time::{Duration, Timer}; 9use embassy_time::{Duration, Timer};
9use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
10 11
11static SIGNAL: Signal<u32> = Signal::new(); 12static SIGNAL: Signal<CriticalSectionRawMutex, u32> = Signal::new();
12 13
13#[embassy_executor::task] 14#[embassy_executor::task]
14async fn my_sending_task() { 15async fn my_sending_task() {
diff --git a/examples/stm32l0/src/bin/lorawan.rs b/examples/stm32l0/src/bin/lorawan.rs
index 00ff67f3f..27d7c29c2 100644
--- a/examples/stm32l0/src/bin/lorawan.rs
+++ b/examples/stm32l0/src/bin/lorawan.rs
@@ -3,7 +3,6 @@
3#![no_main] 3#![no_main]
4#![macro_use] 4#![macro_use]
5#![allow(dead_code)] 5#![allow(dead_code)]
6#![feature(generic_associated_types)]
7#![feature(type_alias_impl_trait)] 6#![feature(type_alias_impl_trait)]
8 7
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index c451bd221..9ebab6476 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -11,10 +11,8 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
11embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 11embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
12embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] } 12embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] }
15embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"] }
16embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", features = ["defmt"] }
17embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } 14embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
18usbd-hid = "0.6.0" 16usbd-hid = "0.6.0"
19 17
20defmt = "0.3" 18defmt = "0.3"
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index 2c8706e41..4f36d3f5a 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
5 4
6use core::sync::atomic::{AtomicBool, Ordering}; 5use core::sync::atomic::{AtomicBool, Ordering};
@@ -16,8 +15,8 @@ use embassy_stm32::usb::Driver;
16use embassy_stm32::{interrupt, Config}; 15use embassy_stm32::{interrupt, Config};
17use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 16use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
18use embassy_sync::channel::Channel; 17use embassy_sync::channel::Channel;
18use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State};
19use embassy_usb::{Builder, UsbDevice}; 19use embassy_usb::{Builder, UsbDevice};
20use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
21use embedded_io::asynch::Write; 20use embedded_io::asynch::Write;
22use rand_core::RngCore; 21use rand_core::RngCore;
23use static_cell::StaticCell; 22use static_cell::StaticCell;
diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs
index 7d763e7fd..d38ed7496 100644
--- a/examples/stm32l5/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs
@@ -1,18 +1,17 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
5 4
6use defmt::*; 5use defmt::*;
7use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_futures::join::join;
8use embassy_stm32::rcc::*; 8use embassy_stm32::rcc::*;
9use embassy_stm32::usb::Driver; 9use embassy_stm32::usb::Driver;
10use embassy_stm32::{interrupt, Config}; 10use embassy_stm32::{interrupt, Config};
11use embassy_time::{Duration, Timer}; 11use embassy_time::{Duration, Timer};
12use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
12use embassy_usb::control::OutResponse; 13use embassy_usb::control::OutResponse;
13use embassy_usb::Builder; 14use embassy_usb::Builder;
14use embassy_usb_hid::{HidWriter, ReportId, RequestHandler, State};
15use futures::future::join;
16use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; 15use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
17use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
18 17
@@ -56,7 +55,7 @@ async fn main(_spawner: Spawner) {
56 ); 55 );
57 56
58 // Create classes on the builder. 57 // Create classes on the builder.
59 let config = embassy_usb_hid::Config { 58 let config = embassy_usb::class::hid::Config {
60 report_descriptor: MouseReport::desc(), 59 report_descriptor: MouseReport::desc(),
61 request_handler: Some(&request_handler), 60 request_handler: Some(&request_handler),
62 poll_ms: 60, 61 poll_ms: 60,
diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs
index b576a7353..7562a4e96 100644
--- a/examples/stm32l5/src/bin/usb_serial.rs
+++ b/examples/stm32l5/src/bin/usb_serial.rs
@@ -4,13 +4,13 @@
4 4
5use defmt::{panic, *}; 5use defmt::{panic, *};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_futures::join::join;
7use embassy_stm32::rcc::*; 8use embassy_stm32::rcc::*;
8use embassy_stm32::usb::{Driver, Instance}; 9use embassy_stm32::usb::{Driver, Instance};
9use embassy_stm32::{interrupt, Config}; 10use embassy_stm32::{interrupt, Config};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
10use embassy_usb::driver::EndpointError; 12use embassy_usb::driver::EndpointError;
11use embassy_usb::Builder; 13use embassy_usb::Builder;
12use embassy_usb_serial::{CdcAcmClass, State};
13use futures::future::join;
14use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
15 15
16#[embassy_executor::main] 16#[embassy_executor::main]
diff --git a/examples/stm32wl/src/bin/lorawan.rs b/examples/stm32wl/src/bin/lorawan.rs
index 9143e64da..7f34dd306 100644
--- a/examples/stm32wl/src/bin/lorawan.rs
+++ b/examples/stm32wl/src/bin/lorawan.rs
@@ -2,7 +2,6 @@
2#![no_main] 2#![no_main]
3#![macro_use] 3#![macro_use]
4#![allow(dead_code)] 4#![allow(dead_code)]
5#![feature(generic_associated_types)]
6#![feature(type_alias_impl_trait)] 5#![feature(type_alias_impl_trait)]
7 6
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
diff --git a/examples/stm32wl/src/bin/subghz.rs b/examples/stm32wl/src/bin/subghz.rs
index 8f674d796..32c8b5515 100644
--- a/examples/stm32wl/src/bin/subghz.rs
+++ b/examples/stm32wl/src/bin/subghz.rs
@@ -2,7 +2,6 @@
2#![no_main] 2#![no_main]
3#![macro_use] 3#![macro_use]
4#![allow(dead_code)] 4#![allow(dead_code)]
5#![feature(generic_associated_types)]
6#![feature(type_alias_impl_trait)] 5#![feature(type_alias_impl_trait)]
7 6
8use defmt::*; 7use defmt::*;
@@ -13,6 +12,7 @@ use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
13use embassy_stm32::interrupt; 12use embassy_stm32::interrupt;
14use embassy_stm32::interrupt::{Interrupt, InterruptExt}; 13use embassy_stm32::interrupt::{Interrupt, InterruptExt};
15use embassy_stm32::subghz::*; 14use embassy_stm32::subghz::*;
15use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
16use embassy_sync::signal::Signal; 16use embassy_sync::signal::Signal;
17use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
18 18
@@ -65,7 +65,7 @@ async fn main(_spawner: Spawner) {
65 let button = Input::new(p.PA0, Pull::Up); 65 let button = Input::new(p.PA0, Pull::Up);
66 let mut pin = ExtiInput::new(button, p.EXTI0); 66 let mut pin = ExtiInput::new(button, p.EXTI0);
67 67
68 static IRQ_SIGNAL: Signal<()> = Signal::new(); 68 static IRQ_SIGNAL: Signal<CriticalSectionRawMutex, ()> = Signal::new();
69 let radio_irq = interrupt::take!(SUBGHZ_RADIO); 69 let radio_irq = interrupt::take!(SUBGHZ_RADIO);
70 radio_irq.set_handler(|_| { 70 radio_irq.set_handler(|_| {
71 IRQ_SIGNAL.signal(()); 71 IRQ_SIGNAL.signal(());
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index f5e342edc..1ec19e58b 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,7 +1,7 @@
1# Before upgrading check that everything is available on all tier1 targets here: 1# Before upgrading check that everything is available on all tier1 targets here:
2# https://rust-lang.github.io/rustup-components-history 2# https://rust-lang.github.io/rustup-components-history
3[toolchain] 3[toolchain]
4channel = "nightly-2022-08-16" 4channel = "nightly-2022-09-22"
5components = [ "rust-src", "rustfmt" ] 5components = [ "rust-src", "rustfmt" ]
6targets = [ 6targets = [
7 "thumbv7em-none-eabi", 7 "thumbv7em-none-eabi",
diff --git a/tests/rp/.cargo/config.toml b/tests/rp/.cargo/config.toml
index 0330025e4..9611db3a0 100644
--- a/tests/rp/.cargo/config.toml
+++ b/tests/rp/.cargo/config.toml
@@ -3,7 +3,7 @@ build-std = ["core"]
3build-std-features = ["panic_immediate_abort"] 3build-std-features = ["panic_immediate_abort"]
4 4
5[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 5[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6#runner = "teleprobe client run --target bluepill-stm32f103c8 --elf" 6#runner = "teleprobe client run --target rpi-pico --elf"
7runner = "teleprobe local run --chip RP2040 --elf" 7runner = "teleprobe local run --chip RP2040 --elf"
8 8
9rustflags = [ 9rustflags = [
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index 70fd95557..503373759 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -7,7 +7,8 @@ version = "0.1.0"
7embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 7embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 8embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] } 9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] }
10embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits"] } 10embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver"] }
11embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
11 12
12defmt = "0.3.0" 13defmt = "0.3.0"
13defmt-rtt = "0.3.0" 14defmt-rtt = "0.3.0"
diff --git a/tests/rp/src/bin/gpio_async.rs b/tests/rp/src/bin/gpio_async.rs
index 1eeaac1f6..f20b8fcbd 100644
--- a/tests/rp/src/bin/gpio_async.rs
+++ b/tests/rp/src/bin/gpio_async.rs
@@ -4,9 +4,9 @@
4 4
5use defmt::{assert, *}; 5use defmt::{assert, *};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_futures::join::join;
7use embassy_rp::gpio::{Input, Level, Output, Pull}; 8use embassy_rp::gpio::{Input, Level, Output, Pull};
8use embassy_time::{Duration, Instant, Timer}; 9use embassy_time::{Duration, Instant, Timer};
9use futures::future::join;
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12#[embassy_executor::main] 12#[embassy_executor::main]