aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xci.sh1
-rw-r--r--embassy-boot/boot/src/lib.rs216
-rw-r--r--embassy-lora/src/stm32wl/mod.rs6
-rw-r--r--embassy-nrf/Cargo.toml6
-rw-r--r--embassy-nrf/src/buffered_uarte.rs42
-rw-r--r--embassy-nrf/src/usb.rs17
-rw-r--r--embassy-rp/Cargo.toml9
-rw-r--r--embassy-rp/src/i2c.rs556
-rw-r--r--embassy-rp/src/intrinsics.rs20
-rw-r--r--embassy-rp/src/lib.rs4
-rw-r--r--embassy-rp/src/rom_data.rs2
-rw-r--r--embassy-rp/src/uart/buffered.rs489
-rw-r--r--embassy-rp/src/uart/mod.rs (renamed from embassy-rp/src/uart.rs)92
-rw-r--r--embassy-rp/src/usb.rs28
-rw-r--r--embassy-stm32/Cargo.toml6
-rw-r--r--embassy-stm32/src/can/bxcan.rs23
-rw-r--r--embassy-stm32/src/usart/buffered.rs252
-rw-r--r--embassy-stm32/src/usb/usb.rs36
-rw-r--r--embassy-sync/src/signal.rs73
-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)21
-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)23
-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.rs21
-rw-r--r--embassy-usb/src/types.rs105
-rw-r--r--examples/boot/application/stm32f7/src/bin/a.rs17
-rw-r--r--examples/boot/application/stm32h7/src/bin/a.rs17
-rw-r--r--examples/nrf/Cargo.toml5
-rw-r--r--examples/nrf/src/bin/usb_ethernet.rs2
-rw-r--r--examples/nrf/src/bin/usb_hid_keyboard.rs7
-rw-r--r--examples/nrf/src/bin/usb_hid_mouse.rs4
-rw-r--r--examples/nrf/src/bin/usb_serial.rs2
-rw-r--r--examples/nrf/src/bin/usb_serial_multitask.rs2
-rw-r--r--examples/rp/Cargo.toml2
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs2
-rw-r--r--examples/rp/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32f1/Cargo.toml1
-rw-r--r--examples/stm32f1/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32f3/Cargo.toml2
-rw-r--r--examples/stm32f3/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32h7/src/bin/signal.rs3
-rw-r--r--examples/stm32l5/Cargo.toml3
-rw-r--r--examples/stm32l5/src/bin/usb_ethernet.rs2
-rw-r--r--examples/stm32l5/src/bin/usb_hid_mouse.rs4
-rw-r--r--examples/stm32l5/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32wl/src/bin/subghz.rs3
-rw-r--r--tests/rp/.cargo/config.toml2
-rw-r--r--tests/rp/Cargo.toml3
-rw-r--r--tests/rp/src/bin/uart_buffered.rs44
61 files changed, 1923 insertions, 1145 deletions
diff --git a/ci.sh b/ci.sh
index ae1b44281..69440ec36 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 96878ace9..8286601ec 100644
--- a/embassy-boot/boot/src/lib.rs
+++ b/embassy-boot/boot/src/lib.rs
@@ -604,6 +604,21 @@ impl FirmwareUpdater {
604 self.dfu.len() 604 self.dfu.len()
605 } 605 }
606 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
607 /// Mark to trigger firmware swap on next boot. 622 /// Mark to trigger firmware swap on next boot.
608 /// 623 ///
609 /// # Safety 624 /// # Safety
@@ -660,12 +675,6 @@ impl FirmwareUpdater {
660 ) -> Result<(), F::Error> { 675 ) -> Result<(), F::Error> {
661 assert!(data.len() >= F::ERASE_SIZE); 676 assert!(data.len() >= F::ERASE_SIZE);
662 677
663 trace!(
664 "Writing firmware at offset 0x{:x} len {}",
665 self.dfu.from + offset,
666 data.len()
667 );
668
669 flash 678 flash
670 .erase( 679 .erase(
671 (self.dfu.from + offset) as u32, 680 (self.dfu.from + offset) as u32,
@@ -679,7 +688,156 @@ impl FirmwareUpdater {
679 self.dfu.from + offset + data.len() 688 self.dfu.from + offset + data.len()
680 ); 689 );
681 690
682 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;
683 for chunk in data.chunks(block_size) { 841 for chunk in data.chunks(block_size) {
684 trace!("Wrote chunk at {}: {:?}", write_offset, chunk); 842 trace!("Wrote chunk at {}: {:?}", write_offset, chunk);
685 flash.write(write_offset as u32, chunk).await?; 843 flash.write(write_offset as u32, chunk).await?;
@@ -702,6 +860,50 @@ impl FirmwareUpdater {
702 860
703 Ok(()) 861 Ok(())
704 } 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 }
705} 907}
706 908
707#[cfg(test)] 909#[cfg(test)]
diff --git a/embassy-lora/src/stm32wl/mod.rs b/embassy-lora/src/stm32wl/mod.rs
index e28fa2c1a..8d5d19531 100644
--- a/embassy-lora/src/stm32wl/mod.rs
+++ b/embassy-lora/src/stm32wl/mod.rs
@@ -234,15 +234,15 @@ fn configure_radio(radio: &mut SubGhz<'_, NoDma, NoDma>, config: SubGhzRadioConf
234 Ok(()) 234 Ok(())
235} 235}
236 236
237impl<RS: RadioSwitch> PhyRxTx for SubGhzRadio<'static, RS> { 237impl<'d, RS: RadioSwitch> PhyRxTx for SubGhzRadio<'d, RS> {
238 type PhyError = RadioError; 238 type PhyError = RadioError;
239 239
240 type TxFuture<'m> = impl Future<Output = Result<u32, Self::PhyError>> + 'm where RS: 'm; 240 type TxFuture<'m> = impl Future<Output = Result<u32, Self::PhyError>> + 'm where Self: 'm;
241 fn tx<'m>(&'m mut self, config: TxConfig, buf: &'m [u8]) -> Self::TxFuture<'m> { 241 fn tx<'m>(&'m mut self, config: TxConfig, buf: &'m [u8]) -> Self::TxFuture<'m> {
242 async move { self.do_tx(config, buf).await } 242 async move { self.do_tx(config, buf).await }
243 } 243 }
244 244
245 type RxFuture<'m> = impl Future<Output = Result<(usize, RxQuality), Self::PhyError>> + 'm where RS: 'm; 245 type RxFuture<'m> = impl Future<Output = Result<(usize, RxQuality), Self::PhyError>> + 'm where Self: 'm;
246 fn rx<'m>(&'m mut self, config: RfConfig, buf: &'m mut [u8]) -> Self::RxFuture<'m> { 246 fn rx<'m>(&'m mut self, config: RfConfig, buf: &'m mut [u8]) -> Self::RxFuture<'m> {
247 async move { self.do_rx(config, buf).await } 247 async move { self.do_rx(config, buf).await }
248 } 248 }
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 6fbbc8d9b..d80281fa3 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -18,10 +18,10 @@ flavors = [
18 18
19time = ["dep:embassy-time"] 19time = ["dep:embassy-time"]
20 20
21defmt = ["dep:defmt", "embassy-executor/defmt", "embassy-sync/defmt", "embassy-usb?/defmt", "embedded-io?/defmt", "embassy-embedded-hal/defmt"] 21defmt = ["dep:defmt", "embassy-executor/defmt", "embassy-sync/defmt", "embassy-usb-driver?/defmt", "embedded-io?/defmt", "embassy-embedded-hal/defmt"]
22 22
23# Enable nightly-only features 23# Enable nightly-only features
24nightly = ["embedded-hal-1", "embedded-hal-async", "embassy-usb", "embedded-storage-async", "dep:embedded-io", "embassy-embedded-hal/nightly"] 24nightly = ["embedded-hal-1", "embedded-hal-async", "dep:embassy-usb-driver", "embedded-storage-async", "dep:embedded-io", "embassy-embedded-hal/nightly"]
25 25
26# Reexport the PAC for the currently enabled chip at `embassy_nrf::pac`. 26# Reexport the PAC for the currently enabled chip at `embassy_nrf::pac`.
27# This is unstable because semver-minor (non-breaking) releases of embassy-nrf may major-bump (breaking) the PAC version. 27# This is unstable because semver-minor (non-breaking) releases of embassy-nrf may major-bump (breaking) the PAC version.
@@ -70,7 +70,7 @@ embassy-sync = { version = "0.1.0", path = "../embassy-sync" }
70embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-3"]} 70embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-3"]}
71embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } 71embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
72embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 72embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
73embassy-usb = {version = "0.1.0", path = "../embassy-usb", optional=true } 73embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true }
74 74
75embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 75embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
76embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true} 76embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true}
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index fec875cb8..6e85a159f 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -26,7 +26,7 @@ use embassy_sync::waitqueue::WakerRegistration;
26// Re-export SVD variants to allow user to directly set values 26// Re-export SVD variants to allow user to directly set values
27pub 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};
28 28
29use crate::gpio::Pin as GpioPin; 29use crate::gpio::{self, Pin as GpioPin};
30use crate::interrupt::InterruptExt; 30use crate::interrupt::InterruptExt;
31use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; 31use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
32use crate::timer::{Frequency, Instance as TimerInstance, Timer}; 32use crate::timer::{Frequency, Instance as TimerInstance, Timer};
@@ -428,21 +428,23 @@ impl<'a, U: UarteInstance, T: TimerInstance> Drop for StateInner<'a, U, T> {
428 fn drop(&mut self) { 428 fn drop(&mut self) {
429 let r = U::regs(); 429 let r = U::regs();
430 430
431 // TODO this probably deadlocks. do like Uarte instead.
432
433 self.timer.stop(); 431 self.timer.stop();
434 if let RxState::Receiving = self.rx_state { 432
435 r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); 433 r.inten.reset();
436 } 434 r.events_rxto.reset();
437 if let TxState::Transmitting(_) = self.tx_state { 435 r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
438 r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); 436 r.events_txstopped.reset();
439 } 437 r.tasks_stoptx.write(|w| unsafe { w.bits(1) });
440 if let RxState::Receiving = self.rx_state { 438
441 low_power_wait_until(|| r.events_endrx.read().bits() == 1); 439 while r.events_txstopped.read().bits() == 0 {}
442 } 440 while r.events_rxto.read().bits() == 0 {}
443 if let TxState::Transmitting(_) = self.tx_state { 441
444 low_power_wait_until(|| r.events_endtx.read().bits() == 1); 442 r.enable.write(|w| w.enable().disabled());
445 } 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());
446 } 448 }
447} 449}
448 450
@@ -548,13 +550,3 @@ impl<'a, U: UarteInstance, T: TimerInstance> PeripheralState for StateInner<'a,
548 trace!("irq: end"); 550 trace!("irq: end");
549 } 551 }
550} 552}
551
552/// Low power blocking wait loop using WFE/SEV.
553fn low_power_wait_until(mut condition: impl FnMut() -> bool) {
554 while !condition() {
555 // WFE might "eat" an event that would have otherwise woken the executor.
556 cortex_m::asm::wfe();
557 }
558 // Retrigger an event to be transparent to the executor.
559 cortex_m::asm::sev();
560}
diff --git a/embassy-nrf/src/usb.rs b/embassy-nrf/src/usb.rs
index 0685d419c..00da5c9dd 100644
--- a/embassy-nrf/src/usb.rs
+++ b/embassy-nrf/src/usb.rs
@@ -9,9 +9,8 @@ use core::task::Poll;
9use cortex_m::peripheral::NVIC; 9use cortex_m::peripheral::NVIC;
10use embassy_hal_common::{into_ref, PeripheralRef}; 10use embassy_hal_common::{into_ref, PeripheralRef};
11use embassy_sync::waitqueue::AtomicWaker; 11use embassy_sync::waitqueue::AtomicWaker;
12pub use embassy_usb; 12use embassy_usb_driver as driver;
13use embassy_usb::driver::{self, EndpointError, Event, Unsupported}; 13use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported};
14use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection};
15use pac::usbd::RegisterBlock; 14use pac::usbd::RegisterBlock;
16 15
17use crate::interrupt::{Interrupt, InterruptExt}; 16use crate::interrupt::{Interrupt, InterruptExt};
@@ -243,7 +242,7 @@ impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P>
243 interval: u8, 242 interval: u8,
244 ) -> Result<Self::EndpointIn, driver::EndpointAllocError> { 243 ) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
245 let index = self.alloc_in.allocate(ep_type)?; 244 let index = self.alloc_in.allocate(ep_type)?;
246 let ep_addr = EndpointAddress::from_parts(index, UsbDirection::In); 245 let ep_addr = EndpointAddress::from_parts(index, Direction::In);
247 Ok(Endpoint::new(EndpointInfo { 246 Ok(Endpoint::new(EndpointInfo {
248 addr: ep_addr, 247 addr: ep_addr,
249 ep_type, 248 ep_type,
@@ -259,7 +258,7 @@ impl<'d, T: Instance, P: UsbSupply + 'd> driver::Driver<'d> for Driver<'d, T, P>
259 interval: u8, 258 interval: u8,
260 ) -> Result<Self::EndpointOut, driver::EndpointAllocError> { 259 ) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
261 let index = self.alloc_out.allocate(ep_type)?; 260 let index = self.alloc_out.allocate(ep_type)?;
262 let ep_addr = EndpointAddress::from_parts(index, UsbDirection::Out); 261 let ep_addr = EndpointAddress::from_parts(index, Direction::Out);
263 Ok(Endpoint::new(EndpointInfo { 262 Ok(Endpoint::new(EndpointInfo {
264 addr: ep_addr, 263 addr: ep_addr,
265 ep_type, 264 ep_type,
@@ -428,8 +427,8 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
428 let regs = T::regs(); 427 let regs = T::regs();
429 let i = ep_addr.index(); 428 let i = ep_addr.index();
430 match ep_addr.direction() { 429 match ep_addr.direction() {
431 UsbDirection::Out => regs.halted.epout[i].read().getstatus().is_halted(), 430 Direction::Out => regs.halted.epout[i].read().getstatus().is_halted(),
432 UsbDirection::In => regs.halted.epin[i].read().getstatus().is_halted(), 431 Direction::In => regs.halted.epin[i].read().getstatus().is_halted(),
433 } 432 }
434 } 433 }
435 434
@@ -442,7 +441,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
442 debug!("endpoint_set_enabled {:?} {}", ep_addr, enabled); 441 debug!("endpoint_set_enabled {:?} {}", ep_addr, enabled);
443 442
444 match ep_addr.direction() { 443 match ep_addr.direction() {
445 UsbDirection::In => { 444 Direction::In => {
446 let mut was_enabled = false; 445 let mut was_enabled = false;
447 regs.epinen.modify(|r, w| { 446 regs.epinen.modify(|r, w| {
448 let mut bits = r.bits(); 447 let mut bits = r.bits();
@@ -466,7 +465,7 @@ impl<'d, T: Instance, P: UsbSupply> driver::Bus for Bus<'d, T, P> {
466 465
467 In::waker(i).wake(); 466 In::waker(i).wake();
468 } 467 }
469 UsbDirection::Out => { 468 Direction::Out => {
470 regs.epouten.modify(|r, w| { 469 regs.epouten.modify(|r, w| {
471 let mut bits = r.bits(); 470 let mut bits = r.bits();
472 if enabled { 471 if enabled {
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index ce78acd3c..a7c2daa56 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -12,7 +12,7 @@ flavors = [
12] 12]
13 13
14[features] 14[features]
15defmt = ["dep:defmt", "embassy-usb?/defmt"] 15defmt = ["dep:defmt", "embassy-usb-driver?/defmt"]
16 16
17# Reexport the PAC for the currently enabled chip at `embassy_rp::pac`. 17# Reexport the PAC for the currently enabled chip at `embassy_rp::pac`.
18# This is unstable because semver-minor (non-breaking) releases of embassy-rp may major-bump (breaking) the PAC version. 18# This is unstable because semver-minor (non-breaking) releases of embassy-rp may major-bump (breaking) the PAC version.
@@ -23,11 +23,11 @@ unstable-pac = []
23time-driver = [] 23time-driver = []
24 24
25rom-func-cache = [] 25rom-func-cache = []
26disable-intrinsics = [] 26intrinsics = []
27rom-v2-intrinsics = [] 27rom-v2-intrinsics = []
28 28
29# Enable nightly-only features 29# Enable nightly-only features
30nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb"] 30nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"]
31 31
32# Implement embedded-hal 1.0 alpha traits. 32# Implement embedded-hal 1.0 alpha traits.
33# Implement embedded-hal-async traits if `nightly` is set as well. 33# Implement embedded-hal-async traits if `nightly` is set as well.
@@ -41,7 +41,7 @@ embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
41embassy-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"]}
42embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } 42embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
43embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 43embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
44embassy-usb = {version = "0.1.0", path = "../embassy-usb", optional = true } 44embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
45atomic-polyfill = "1.0.1" 45atomic-polyfill = "1.0.1"
46defmt = { version = "0.3", optional = true } 46defmt = { version = "0.3", optional = true }
47log = { version = "0.4.14", optional = true } 47log = { version = "0.4.14", optional = true }
@@ -53,6 +53,7 @@ critical-section = "1.1"
53futures = { 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 } 54chrono = { version = "0.4", default-features = false, optional = true }
55embedded-storage = { version = "0.3" } 55embedded-storage = { version = "0.3" }
56embedded-io = { version = "0.3.0", features = ["async"], optional = true }
56 57
57rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] } 58rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="017e3c9007b2d3b6965f0d85b5bf8ce3fa6d7364", features = ["rt"] }
58#rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] } 59#rp2040-pac2 = { path = "../../rp2040-pac2", features = ["rt"] }
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
new file mode 100644
index 000000000..9596d661d
--- /dev/null
+++ b/embassy-rp/src/i2c.rs
@@ -0,0 +1,556 @@
1use core::marker::PhantomData;
2
3use embassy_hal_common::{into_ref, PeripheralRef};
4use pac::i2c;
5
6use crate::dma::AnyChannel;
7use crate::gpio::sealed::Pin;
8use crate::gpio::AnyPin;
9use crate::{pac, peripherals, Peripheral};
10
11/// I2C error abort reason
12#[derive(Debug)]
13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
14pub enum AbortReason {
15 /// A bus operation was not acknowledged, e.g. due to the addressed device
16 /// not being available on the bus or the device not being ready to process
17 /// requests at the moment
18 NoAcknowledge,
19 /// The arbitration was lost, e.g. electrical problems with the clock signal
20 ArbitrationLoss,
21 Other(u32),
22}
23
24/// I2C error
25#[derive(Debug)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
27pub enum Error {
28 /// I2C abort with error
29 Abort(AbortReason),
30 /// User passed in a read buffer that was 0 length
31 InvalidReadBufferLength,
32 /// User passed in a write buffer that was 0 length
33 InvalidWriteBufferLength,
34 /// Target i2c address is out of range
35 AddressOutOfRange(u16),
36 /// Target i2c address is reserved
37 AddressReserved(u16),
38}
39
40#[non_exhaustive]
41#[derive(Copy, Clone)]
42pub struct Config {
43 pub frequency: u32,
44}
45
46impl Default for Config {
47 fn default() -> Self {
48 Self { frequency: 100_000 }
49 }
50}
51
52const FIFO_SIZE: u8 = 16;
53
54pub struct I2c<'d, T: Instance, M: Mode> {
55 _tx_dma: Option<PeripheralRef<'d, AnyChannel>>,
56 _rx_dma: Option<PeripheralRef<'d, AnyChannel>>,
57 _dma_buf: [u16; 256],
58 phantom: PhantomData<(&'d mut T, M)>,
59}
60
61impl<'d, T: Instance> I2c<'d, T, Blocking> {
62 pub fn new_blocking(
63 _peri: impl Peripheral<P = T> + 'd,
64 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
65 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
66 config: Config,
67 ) -> Self {
68 into_ref!(scl, sda);
69 Self::new_inner(_peri, scl.map_into(), sda.map_into(), None, None, config)
70 }
71}
72
73impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
74 fn new_inner(
75 _peri: impl Peripheral<P = T> + 'd,
76 scl: PeripheralRef<'d, AnyPin>,
77 sda: PeripheralRef<'d, AnyPin>,
78 _tx_dma: Option<PeripheralRef<'d, AnyChannel>>,
79 _rx_dma: Option<PeripheralRef<'d, AnyChannel>>,
80 config: Config,
81 ) -> Self {
82 into_ref!(_peri);
83
84 assert!(config.frequency <= 1_000_000);
85 assert!(config.frequency > 0);
86
87 let p = T::regs();
88
89 unsafe {
90 p.ic_enable().write(|w| w.set_enable(false));
91
92 // Select controller mode & speed
93 p.ic_con().modify(|w| {
94 // Always use "fast" mode (<= 400 kHz, works fine for standard
95 // mode too)
96 w.set_speed(i2c::vals::Speed::FAST);
97 w.set_master_mode(true);
98 w.set_ic_slave_disable(true);
99 w.set_ic_restart_en(true);
100 w.set_tx_empty_ctrl(true);
101 });
102
103 // Set FIFO watermarks to 1 to make things simpler. This is encoded
104 // by a register value of 0.
105 p.ic_tx_tl().write(|w| w.set_tx_tl(0));
106 p.ic_rx_tl().write(|w| w.set_rx_tl(0));
107
108 // Configure SCL & SDA pins
109 scl.io().ctrl().write(|w| w.set_funcsel(3));
110 sda.io().ctrl().write(|w| w.set_funcsel(3));
111
112 scl.pad_ctrl().write(|w| {
113 w.set_schmitt(true);
114 w.set_ie(true);
115 w.set_od(false);
116 w.set_pue(true);
117 w.set_pde(false);
118 });
119 sda.pad_ctrl().write(|w| {
120 w.set_schmitt(true);
121 w.set_ie(true);
122 w.set_od(false);
123 w.set_pue(true);
124 w.set_pde(false);
125 });
126
127 // Configure baudrate
128
129 // There are some subtleties to I2C timing which we are completely
130 // ignoring here See:
131 // https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69
132 let clk_base = crate::clocks::clk_peri_freq();
133
134 let period = (clk_base + config.frequency / 2) / config.frequency;
135 let lcnt = period * 3 / 5; // spend 3/5 (60%) of the period low
136 let hcnt = period - lcnt; // and 2/5 (40%) of the period high
137
138 // Check for out-of-range divisors:
139 assert!(hcnt <= 0xffff);
140 assert!(lcnt <= 0xffff);
141 assert!(hcnt >= 8);
142 assert!(lcnt >= 8);
143
144 // Per I2C-bus specification a device in standard or fast mode must
145 // internally provide a hold time of at least 300ns for the SDA
146 // signal to bridge the undefined region of the falling edge of SCL.
147 // A smaller hold time of 120ns is used for fast mode plus.
148 let sda_tx_hold_count = if config.frequency < 1_000_000 {
149 // sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s /
150 // 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't
151 // fit in uint. Add 1 to avoid division truncation.
152 ((clk_base * 3) / 10_000_000) + 1
153 } else {
154 // fast mode plus requires a clk_base > 32MHz
155 assert!(clk_base >= 32_000_000);
156
157 // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s /
158 // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't
159 // fit in uint. Add 1 to avoid division truncation.
160 ((clk_base * 3) / 25_000_000) + 1
161 };
162 assert!(sda_tx_hold_count <= lcnt - 2);
163
164 p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16));
165 p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16));
166 p.ic_fs_spklen()
167 .write(|w| w.set_ic_fs_spklen(if lcnt < 16 { 1 } else { (lcnt / 16) as u8 }));
168 p.ic_sda_hold()
169 .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16));
170
171 // Enable I2C block
172 p.ic_enable().write(|w| w.set_enable(true));
173 }
174
175 Self {
176 _tx_dma,
177 _rx_dma,
178 _dma_buf: [0; 256],
179 phantom: PhantomData,
180 }
181 }
182
183 fn setup(addr: u16) -> Result<(), Error> {
184 if addr >= 0x80 {
185 return Err(Error::AddressOutOfRange(addr));
186 }
187
188 if i2c_reserved_addr(addr) {
189 return Err(Error::AddressReserved(addr));
190 }
191
192 let p = T::regs();
193 unsafe {
194 p.ic_enable().write(|w| w.set_enable(false));
195 p.ic_tar().write(|w| w.set_ic_tar(addr));
196 p.ic_enable().write(|w| w.set_enable(true));
197 }
198 Ok(())
199 }
200
201 fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> {
202 let p = T::regs();
203 unsafe {
204 let abort_reason = p.ic_tx_abrt_source().read();
205 if abort_reason.0 != 0 {
206 // Note clearing the abort flag also clears the reason, and this
207 // instance of flag is clear-on-read! Note also the
208 // IC_CLR_TX_ABRT register always reads as 0.
209 p.ic_clr_tx_abrt().read();
210
211 let reason = if abort_reason.abrt_7b_addr_noack()
212 | abort_reason.abrt_10addr1_noack()
213 | abort_reason.abrt_10addr2_noack()
214 {
215 AbortReason::NoAcknowledge
216 } else if abort_reason.arb_lost() {
217 AbortReason::ArbitrationLoss
218 } else {
219 AbortReason::Other(abort_reason.0)
220 };
221
222 Err(Error::Abort(reason))
223 } else {
224 Ok(())
225 }
226 }
227 }
228
229 fn read_blocking_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> {
230 if buffer.is_empty() {
231 return Err(Error::InvalidReadBufferLength);
232 }
233
234 let p = T::regs();
235 let lastindex = buffer.len() - 1;
236 for (i, byte) in buffer.iter_mut().enumerate() {
237 let first = i == 0;
238 let last = i == lastindex;
239
240 // NOTE(unsafe) We have &mut self
241 unsafe {
242 // wait until there is space in the FIFO to write the next byte
243 while p.ic_txflr().read().txflr() == FIFO_SIZE {}
244
245 p.ic_data_cmd().write(|w| {
246 w.set_restart(restart && first);
247 w.set_stop(send_stop && last);
248
249 w.set_cmd(true);
250 });
251
252 while p.ic_rxflr().read().rxflr() == 0 {
253 self.read_and_clear_abort_reason()?;
254 }
255
256 *byte = p.ic_data_cmd().read().dat();
257 }
258 }
259
260 Ok(())
261 }
262
263 fn write_blocking_internal(&mut self, bytes: &[u8], send_stop: bool) -> Result<(), Error> {
264 if bytes.is_empty() {
265 return Err(Error::InvalidWriteBufferLength);
266 }
267
268 let p = T::regs();
269
270 for (i, byte) in bytes.iter().enumerate() {
271 let last = i == bytes.len() - 1;
272
273 // NOTE(unsafe) We have &mut self
274 unsafe {
275 p.ic_data_cmd().write(|w| {
276 w.set_stop(send_stop && last);
277 w.set_dat(*byte);
278 });
279
280 // Wait until the transmission of the address/data from the
281 // internal shift register has completed. For this to function
282 // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The
283 // TX_EMPTY_CTRL flag was set in i2c_init.
284 while !p.ic_raw_intr_stat().read().tx_empty() {}
285
286 let abort_reason = self.read_and_clear_abort_reason();
287
288 if abort_reason.is_err() || (send_stop && last) {
289 // If the transaction was aborted or if it completed
290 // successfully wait until the STOP condition has occured.
291
292 while !p.ic_raw_intr_stat().read().stop_det() {}
293
294 p.ic_clr_stop_det().read().clr_stop_det();
295 }
296
297 // Note the hardware issues a STOP automatically on an abort
298 // condition. Note also the hardware clears RX FIFO as well as
299 // TX on abort, ecause we set hwparam
300 // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
301 abort_reason?;
302 }
303 }
304 Ok(())
305 }
306
307 // =========================
308 // Blocking public API
309 // =========================
310
311 pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
312 Self::setup(address.into())?;
313 self.read_blocking_internal(buffer, true, true)
314 // Automatic Stop
315 }
316
317 pub fn blocking_write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> {
318 Self::setup(address.into())?;
319 self.write_blocking_internal(bytes, true)
320 }
321
322 pub fn blocking_write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
323 Self::setup(address.into())?;
324 self.write_blocking_internal(bytes, false)?;
325 self.read_blocking_internal(buffer, true, true)
326 // Automatic Stop
327 }
328}
329
330mod eh02 {
331 use super::*;
332
333 impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, M> {
334 type Error = Error;
335
336 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
337 self.blocking_read(address, buffer)
338 }
339 }
340
341 impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, T, M> {
342 type Error = Error;
343
344 fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
345 self.blocking_write(address, bytes)
346 }
347 }
348
349 impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T, M> {
350 type Error = Error;
351
352 fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> {
353 self.blocking_write_read(address, bytes, buffer)
354 }
355 }
356}
357
358#[cfg(feature = "unstable-traits")]
359mod eh1 {
360 use super::*;
361
362 impl embedded_hal_1::i2c::Error for Error {
363 fn kind(&self) -> embedded_hal_1::i2c::ErrorKind {
364 match *self {
365 Self::Abort(AbortReason::ArbitrationLoss) => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss,
366 Self::Abort(AbortReason::NoAcknowledge) => {
367 embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address)
368 }
369 Self::Abort(AbortReason::Other(_)) => embedded_hal_1::i2c::ErrorKind::Other,
370 Self::InvalidReadBufferLength => embedded_hal_1::i2c::ErrorKind::Other,
371 Self::InvalidWriteBufferLength => embedded_hal_1::i2c::ErrorKind::Other,
372 Self::AddressOutOfRange(_) => embedded_hal_1::i2c::ErrorKind::Other,
373 Self::AddressReserved(_) => embedded_hal_1::i2c::ErrorKind::Other,
374 }
375 }
376 }
377
378 impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::ErrorType for I2c<'d, T, M> {
379 type Error = Error;
380 }
381
382 impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::blocking::I2c for I2c<'d, T, M> {
383 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
384 self.blocking_read(address, buffer)
385 }
386
387 fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> {
388 self.blocking_write(address, buffer)
389 }
390
391 fn write_iter<B>(&mut self, address: u8, bytes: B) -> Result<(), Self::Error>
392 where
393 B: IntoIterator<Item = u8>,
394 {
395 let mut peekable = bytes.into_iter().peekable();
396 Self::setup(address.into())?;
397
398 while let Some(tx) = peekable.next() {
399 self.write_blocking_internal(&[tx], peekable.peek().is_none())?;
400 }
401 Ok(())
402 }
403
404 fn write_iter_read<B>(&mut self, address: u8, bytes: B, buffer: &mut [u8]) -> Result<(), Self::Error>
405 where
406 B: IntoIterator<Item = u8>,
407 {
408 let peekable = bytes.into_iter().peekable();
409 Self::setup(address.into())?;
410
411 for tx in peekable {
412 self.write_blocking_internal(&[tx], false)?
413 }
414 self.read_blocking_internal(buffer, true, true)
415 }
416
417 fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> {
418 self.blocking_write_read(address, wr_buffer, rd_buffer)
419 }
420
421 fn transaction<'a>(
422 &mut self,
423 address: u8,
424 operations: &mut [embedded_hal_1::i2c::blocking::Operation<'a>],
425 ) -> Result<(), Self::Error> {
426 Self::setup(address.into())?;
427 for i in 0..operations.len() {
428 let last = i == operations.len() - 1;
429 match &mut operations[i] {
430 embedded_hal_1::i2c::blocking::Operation::Read(buf) => {
431 self.read_blocking_internal(buf, false, last)?
432 }
433 embedded_hal_1::i2c::blocking::Operation::Write(buf) => self.write_blocking_internal(buf, last)?,
434 }
435 }
436 Ok(())
437 }
438
439 fn transaction_iter<'a, O>(&mut self, address: u8, operations: O) -> Result<(), Self::Error>
440 where
441 O: IntoIterator<Item = embedded_hal_1::i2c::blocking::Operation<'a>>,
442 {
443 Self::setup(address.into())?;
444 let mut peekable = operations.into_iter().peekable();
445 while let Some(operation) = peekable.next() {
446 let last = peekable.peek().is_none();
447 match operation {
448 embedded_hal_1::i2c::blocking::Operation::Read(buf) => {
449 self.read_blocking_internal(buf, false, last)?
450 }
451 embedded_hal_1::i2c::blocking::Operation::Write(buf) => self.write_blocking_internal(buf, last)?,
452 }
453 }
454 Ok(())
455 }
456 }
457}
458
459fn i2c_reserved_addr(addr: u16) -> bool {
460 (addr & 0x78) == 0 || (addr & 0x78) == 0x78
461}
462
463mod sealed {
464 use embassy_cortex_m::interrupt::Interrupt;
465
466 pub trait Instance {
467 const TX_DREQ: u8;
468 const RX_DREQ: u8;
469
470 type Interrupt: Interrupt;
471
472 fn regs() -> crate::pac::i2c::I2c;
473 }
474
475 pub trait Mode {}
476
477 pub trait SdaPin<T: Instance> {}
478 pub trait SclPin<T: Instance> {}
479}
480
481pub trait Mode: sealed::Mode {}
482
483macro_rules! impl_mode {
484 ($name:ident) => {
485 impl sealed::Mode for $name {}
486 impl Mode for $name {}
487 };
488}
489
490pub struct Blocking;
491pub struct Async;
492
493impl_mode!(Blocking);
494impl_mode!(Async);
495
496pub trait Instance: sealed::Instance {}
497
498macro_rules! impl_instance {
499 ($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
500 impl sealed::Instance for peripherals::$type {
501 const TX_DREQ: u8 = $tx_dreq;
502 const RX_DREQ: u8 = $rx_dreq;
503
504 type Interrupt = crate::interrupt::$irq;
505
506 fn regs() -> pac::i2c::I2c {
507 pac::$type
508 }
509 }
510 impl Instance for peripherals::$type {}
511 };
512}
513
514impl_instance!(I2C0, I2C0_IRQ, 32, 33);
515impl_instance!(I2C1, I2C1_IRQ, 34, 35);
516
517pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {}
518pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {}
519
520macro_rules! impl_pin {
521 ($pin:ident, $instance:ident, $function:ident) => {
522 impl sealed::$function<peripherals::$instance> for peripherals::$pin {}
523 impl $function<peripherals::$instance> for peripherals::$pin {}
524 };
525}
526
527impl_pin!(PIN_0, I2C0, SdaPin);
528impl_pin!(PIN_1, I2C0, SclPin);
529impl_pin!(PIN_2, I2C1, SdaPin);
530impl_pin!(PIN_3, I2C1, SclPin);
531impl_pin!(PIN_4, I2C0, SdaPin);
532impl_pin!(PIN_5, I2C0, SclPin);
533impl_pin!(PIN_6, I2C1, SdaPin);
534impl_pin!(PIN_7, I2C1, SclPin);
535impl_pin!(PIN_8, I2C0, SdaPin);
536impl_pin!(PIN_9, I2C0, SclPin);
537impl_pin!(PIN_10, I2C1, SdaPin);
538impl_pin!(PIN_11, I2C1, SclPin);
539impl_pin!(PIN_12, I2C0, SdaPin);
540impl_pin!(PIN_13, I2C0, SclPin);
541impl_pin!(PIN_14, I2C1, SdaPin);
542impl_pin!(PIN_15, I2C1, SclPin);
543impl_pin!(PIN_16, I2C0, SdaPin);
544impl_pin!(PIN_17, I2C0, SclPin);
545impl_pin!(PIN_18, I2C1, SdaPin);
546impl_pin!(PIN_19, I2C1, SclPin);
547impl_pin!(PIN_20, I2C0, SdaPin);
548impl_pin!(PIN_21, I2C0, SclPin);
549impl_pin!(PIN_22, I2C1, SdaPin);
550impl_pin!(PIN_23, I2C1, SclPin);
551impl_pin!(PIN_24, I2C0, SdaPin);
552impl_pin!(PIN_25, I2C0, SclPin);
553impl_pin!(PIN_26, I2C1, SdaPin);
554impl_pin!(PIN_27, I2C1, SclPin);
555impl_pin!(PIN_28, I2C0, SdaPin);
556impl_pin!(PIN_29, I2C0, SclPin);
diff --git a/embassy-rp/src/intrinsics.rs b/embassy-rp/src/intrinsics.rs
index 9e6624cf0..67e8202a4 100644
--- a/embassy-rp/src/intrinsics.rs
+++ b/embassy-rp/src/intrinsics.rs
@@ -1,4 +1,6 @@
1#![macro_use] 1#![macro_use]
2// Credit: taken from `rp-hal` (also licensed Apache+MIT)
3// https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/intrinsics.rs
2 4
3/// Generate a series of aliases for an intrinsic function. 5/// Generate a series of aliases for an intrinsic function.
4macro_rules! intrinsics_aliases { 6macro_rules! intrinsics_aliases {
@@ -14,7 +16,7 @@ macro_rules! intrinsics_aliases {
14 $alias:ident 16 $alias:ident
15 $($rest:ident)* 17 $($rest:ident)*
16 ) => { 18 ) => {
17 #[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))] 19 #[cfg(all(target_arch = "arm", feature = "intrinsics"))]
18 intrinsics! { 20 intrinsics! {
19 extern $abi fn $alias( $($argname: $ty),* ) -> $ret { 21 extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
20 $name($($argname),*) 22 $name($($argname),*)
@@ -32,7 +34,7 @@ macro_rules! intrinsics_aliases {
32 $alias:ident 34 $alias:ident
33 $($rest:ident)* 35 $($rest:ident)*
34 ) => { 36 ) => {
35 #[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))] 37 #[cfg(all(target_arch = "arm", feature = "intrinsics"))]
36 intrinsics! { 38 intrinsics! {
37 unsafe extern $abi fn $alias( $($argname: $ty),* ) -> $ret { 39 unsafe extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
38 $name($($argname),*) 40 $name($($argname),*)
@@ -52,7 +54,7 @@ macro_rules! intrinsics_aliases {
52/// is to abstract anything special that needs to be done to override an 54/// is to abstract anything special that needs to be done to override an
53/// intrinsic function. Intrinsic generation is disabled for non-ARM targets 55/// intrinsic function. Intrinsic generation is disabled for non-ARM targets
54/// so things like CI and docs generation do not have problems. Additionally 56/// so things like CI and docs generation do not have problems. Additionally
55/// they can be disabled with the crate feature `disable-intrinsics` for 57/// they can be disabled by disabling the crate feature `intrinsics` for
56/// testing or comparing performance. 58/// testing or comparing performance.
57/// 59///
58/// Like the compiler-builtins macro, it accepts a series of functions that 60/// Like the compiler-builtins macro, it accepts a series of functions that
@@ -211,13 +213,13 @@ macro_rules! intrinsics {
211 213
212 $($rest:tt)* 214 $($rest:tt)*
213 ) => { 215 ) => {
214 #[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))] 216 #[cfg(all(target_arch = "arm", feature = "intrinsics"))]
215 $(#[$($attr)*])* 217 $(#[$($attr)*])*
216 extern $abi fn $name( $($argname: $ty),* ) -> $ret { 218 extern $abi fn $name( $($argname: $ty),* ) -> $ret {
217 $($body)* 219 $($body)*
218 } 220 }
219 221
220 #[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))] 222 #[cfg(all(target_arch = "arm", feature = "intrinsics"))]
221 mod $name { 223 mod $name {
222 #[no_mangle] 224 #[no_mangle]
223 $(#[$($attr)*])* 225 $(#[$($attr)*])*
@@ -228,7 +230,7 @@ macro_rules! intrinsics {
228 230
229 // Not exported, but defined so the actual implementation is 231 // Not exported, but defined so the actual implementation is
230 // considered used 232 // considered used
231 #[cfg(not(all(target_arch = "arm", not(feature = "disable-intrinsics"))))] 233 #[cfg(not(all(target_arch = "arm", feature = "intrinsics")))]
232 #[allow(dead_code)] 234 #[allow(dead_code)]
233 fn $name( $($argname: $ty),* ) -> $ret { 235 fn $name( $($argname: $ty),* ) -> $ret {
234 $($body)* 236 $($body)*
@@ -245,13 +247,13 @@ macro_rules! intrinsics {
245 247
246 $($rest:tt)* 248 $($rest:tt)*
247 ) => { 249 ) => {
248 #[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))] 250 #[cfg(all(target_arch = "arm", feature = "intrinsics"))]
249 $(#[$($attr)*])* 251 $(#[$($attr)*])*
250 unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret { 252 unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret {
251 $($body)* 253 $($body)*
252 } 254 }
253 255
254 #[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))] 256 #[cfg(all(target_arch = "arm", feature = "intrinsics"))]
255 mod $name { 257 mod $name {
256 #[no_mangle] 258 #[no_mangle]
257 $(#[$($attr)*])* 259 $(#[$($attr)*])*
@@ -262,7 +264,7 @@ macro_rules! intrinsics {
262 264
263 // Not exported, but defined so the actual implementation is 265 // Not exported, but defined so the actual implementation is
264 // considered used 266 // considered used
265 #[cfg(not(all(target_arch = "arm", not(feature = "disable-intrinsics"))))] 267 #[cfg(not(all(target_arch = "arm", feature = "intrinsics")))]
266 #[allow(dead_code)] 268 #[allow(dead_code)]
267 unsafe fn $name( $($argname: $ty),* ) -> $ret { 269 unsafe fn $name( $($argname: $ty),* ) -> $ret {
268 $($body)* 270 $($body)*
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index ce013b09c..445639618 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -8,6 +8,7 @@ mod intrinsics;
8 8
9pub mod dma; 9pub mod dma;
10pub mod gpio; 10pub mod gpio;
11pub mod i2c;
11pub mod interrupt; 12pub mod interrupt;
12pub mod rom_data; 13pub mod rom_data;
13pub mod rtc; 14pub mod rtc;
@@ -76,6 +77,9 @@ embassy_hal_common::peripherals! {
76 SPI0, 77 SPI0,
77 SPI1, 78 SPI1,
78 79
80 I2C0,
81 I2C1,
82
79 DMA_CH0, 83 DMA_CH0,
80 DMA_CH1, 84 DMA_CH1,
81 DMA_CH2, 85 DMA_CH2,
diff --git a/embassy-rp/src/rom_data.rs b/embassy-rp/src/rom_data.rs
index 93a3632a5..8e953dcf2 100644
--- a/embassy-rp/src/rom_data.rs
+++ b/embassy-rp/src/rom_data.rs
@@ -7,6 +7,8 @@
7//! > on the device, as well as highly optimized versions of certain key 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 8//! > functionality that would otherwise have to take up space in most user
9//! > binaries. 9//! > binaries.
10// Credit: taken from `rp-hal` (also licensed Apache+MIT)
11// https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/rom_data.rs
10 12
11/// A bootrom function table code. 13/// A bootrom function table code.
12pub type RomFnTableCode = [u8; 2]; 14pub type RomFnTableCode = [u8; 2];
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
new file mode 100644
index 000000000..87e16f0eb
--- /dev/null
+++ b/embassy-rp/src/uart/buffered.rs
@@ -0,0 +1,489 @@
1use core::future::{poll_fn, Future};
2use core::task::{Poll, Waker};
3
4use atomic_polyfill::{compiler_fence, Ordering};
5use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage};
6use embassy_hal_common::ring_buffer::RingBuffer;
7use embassy_sync::waitqueue::WakerRegistration;
8
9use super::*;
10
11pub struct State<'d, T: Instance>(StateStorage<FullStateInner<'d, T>>);
12impl<'d, T: Instance> State<'d, T> {
13 pub const fn new() -> Self {
14 Self(StateStorage::new())
15 }
16}
17
18pub struct RxState<'d, T: Instance>(StateStorage<RxStateInner<'d, T>>);
19impl<'d, T: Instance> RxState<'d, T> {
20 pub const fn new() -> Self {
21 Self(StateStorage::new())
22 }
23}
24
25pub struct TxState<'d, T: Instance>(StateStorage<TxStateInner<'d, T>>);
26impl<'d, T: Instance> TxState<'d, T> {
27 pub const fn new() -> Self {
28 Self(StateStorage::new())
29 }
30}
31
32struct RxStateInner<'d, T: Instance> {
33 phantom: PhantomData<&'d mut T>,
34
35 waker: WakerRegistration,
36 buf: RingBuffer<'d>,
37}
38
39struct TxStateInner<'d, T: Instance> {
40 phantom: PhantomData<&'d mut T>,
41
42 waker: WakerRegistration,
43 buf: RingBuffer<'d>,
44}
45
46struct FullStateInner<'d, T: Instance> {
47 rx: RxStateInner<'d, T>,
48 tx: TxStateInner<'d, T>,
49}
50
51unsafe impl<'d, T: Instance> Send for RxStateInner<'d, T> {}
52unsafe impl<'d, T: Instance> Sync for RxStateInner<'d, T> {}
53
54unsafe impl<'d, T: Instance> Send for TxStateInner<'d, T> {}
55unsafe impl<'d, T: Instance> Sync for TxStateInner<'d, T> {}
56
57unsafe impl<'d, T: Instance> Send for FullStateInner<'d, T> {}
58unsafe impl<'d, T: Instance> Sync for FullStateInner<'d, T> {}
59
60pub struct BufferedUart<'d, T: Instance> {
61 inner: PeripheralMutex<'d, FullStateInner<'d, T>>,
62}
63
64pub struct BufferedUartRx<'d, T: Instance> {
65 inner: PeripheralMutex<'d, RxStateInner<'d, T>>,
66}
67
68pub struct BufferedUartTx<'d, T: Instance> {
69 inner: PeripheralMutex<'d, TxStateInner<'d, T>>,
70}
71
72impl<'d, T: Instance> Unpin for BufferedUart<'d, T> {}
73impl<'d, T: Instance> Unpin for BufferedUartRx<'d, T> {}
74impl<'d, T: Instance> Unpin for BufferedUartTx<'d, T> {}
75
76impl<'d, T: Instance> BufferedUart<'d, T> {
77 pub fn new<M: Mode>(
78 state: &'d mut State<'d, T>,
79 _uart: Uart<'d, T, M>,
80 irq: impl Peripheral<P = T::Interrupt> + 'd,
81 tx_buffer: &'d mut [u8],
82 rx_buffer: &'d mut [u8],
83 ) -> BufferedUart<'d, T> {
84 into_ref!(irq);
85
86 let r = T::regs();
87 unsafe {
88 r.uartimsc().modify(|w| {
89 w.set_rxim(true);
90 w.set_rtim(true);
91 w.set_txim(true);
92 });
93 }
94
95 Self {
96 inner: PeripheralMutex::new(irq, &mut state.0, move || FullStateInner {
97 tx: TxStateInner {
98 phantom: PhantomData,
99 waker: WakerRegistration::new(),
100 buf: RingBuffer::new(tx_buffer),
101 },
102 rx: RxStateInner {
103 phantom: PhantomData,
104 waker: WakerRegistration::new(),
105 buf: RingBuffer::new(rx_buffer),
106 },
107 }),
108 }
109 }
110}
111
112impl<'d, T: Instance> BufferedUartRx<'d, T> {
113 pub fn new<M: Mode>(
114 state: &'d mut RxState<'d, T>,
115 _uart: UartRx<'d, T, M>,
116 irq: impl Peripheral<P = T::Interrupt> + 'd,
117 rx_buffer: &'d mut [u8],
118 ) -> BufferedUartRx<'d, T> {
119 into_ref!(irq);
120
121 let r = T::regs();
122 unsafe {
123 r.uartimsc().modify(|w| {
124 w.set_rxim(true);
125 w.set_rtim(true);
126 });
127 }
128
129 Self {
130 inner: PeripheralMutex::new(irq, &mut state.0, move || RxStateInner {
131 phantom: PhantomData,
132
133 buf: RingBuffer::new(rx_buffer),
134 waker: WakerRegistration::new(),
135 }),
136 }
137 }
138}
139
140impl<'d, T: Instance> BufferedUartTx<'d, T> {
141 pub fn new<M: Mode>(
142 state: &'d mut TxState<'d, T>,
143 _uart: UartTx<'d, T, M>,
144 irq: impl Peripheral<P = T::Interrupt> + 'd,
145 tx_buffer: &'d mut [u8],
146 ) -> BufferedUartTx<'d, T> {
147 into_ref!(irq);
148
149 let r = T::regs();
150 unsafe {
151 r.uartimsc().modify(|w| {
152 w.set_txim(true);
153 });
154 }
155
156 Self {
157 inner: PeripheralMutex::new(irq, &mut state.0, move || TxStateInner {
158 phantom: PhantomData,
159
160 buf: RingBuffer::new(tx_buffer),
161 waker: WakerRegistration::new(),
162 }),
163 }
164 }
165}
166
167impl<'d, T: Instance> PeripheralState for FullStateInner<'d, T>
168where
169 Self: 'd,
170{
171 type Interrupt = T::Interrupt;
172 fn on_interrupt(&mut self) {
173 self.rx.on_interrupt();
174 self.tx.on_interrupt();
175 }
176}
177
178impl<'d, T: Instance> RxStateInner<'d, T>
179where
180 Self: 'd,
181{
182 fn read(&mut self, buf: &mut [u8], waker: &Waker) -> (Poll<Result<usize, Error>>, bool) {
183 // We have data ready in buffer? Return it.
184 let mut do_pend = false;
185 let data = self.buf.pop_buf();
186 if !data.is_empty() {
187 let len = data.len().min(buf.len());
188 buf[..len].copy_from_slice(&data[..len]);
189
190 if self.buf.is_full() {
191 do_pend = true;
192 }
193 self.buf.pop(len);
194
195 return (Poll::Ready(Ok(len)), do_pend);
196 }
197
198 self.waker.register(waker);
199 (Poll::Pending, do_pend)
200 }
201
202 fn fill_buf<'a>(&mut self, waker: &Waker) -> Poll<Result<&'a [u8], Error>> {
203 // We have data ready in buffer? Return it.
204 let buf = self.buf.pop_buf();
205 if !buf.is_empty() {
206 let buf: &[u8] = buf;
207 // Safety: buffer lives as long as uart
208 let buf: &[u8] = unsafe { core::mem::transmute(buf) };
209 return Poll::Ready(Ok(buf));
210 }
211
212 self.waker.register(waker);
213 Poll::Pending
214 }
215
216 fn consume(&mut self, amt: usize) -> bool {
217 let full = self.buf.is_full();
218 self.buf.pop(amt);
219 full
220 }
221}
222
223impl<'d, T: Instance> PeripheralState for RxStateInner<'d, T>
224where
225 Self: 'd,
226{
227 type Interrupt = T::Interrupt;
228 fn on_interrupt(&mut self) {
229 let r = T::regs();
230 unsafe {
231 let ris = r.uartris().read();
232 // Clear interrupt flags
233 r.uarticr().modify(|w| {
234 w.set_rxic(true);
235 w.set_rtic(true);
236 });
237
238 if ris.peris() {
239 warn!("Parity error");
240 r.uarticr().modify(|w| {
241 w.set_peic(true);
242 });
243 }
244 if ris.feris() {
245 warn!("Framing error");
246 r.uarticr().modify(|w| {
247 w.set_feic(true);
248 });
249 }
250 if ris.beris() {
251 warn!("Break error");
252 r.uarticr().modify(|w| {
253 w.set_beic(true);
254 });
255 }
256 if ris.oeris() {
257 warn!("Overrun error");
258 r.uarticr().modify(|w| {
259 w.set_oeic(true);
260 });
261 }
262
263 if !r.uartfr().read().rxfe() {
264 let buf = self.buf.push_buf();
265 if !buf.is_empty() {
266 buf[0] = r.uartdr().read().data();
267 self.buf.push(1);
268 } else {
269 warn!("RX buffer full, discard received byte");
270 }
271
272 if self.buf.is_full() {
273 self.waker.wake();
274 }
275 }
276
277 if ris.rtris() {
278 self.waker.wake();
279 };
280 }
281 }
282}
283
284impl<'d, T: Instance> TxStateInner<'d, T>
285where
286 Self: 'd,
287{
288 fn write(&mut self, buf: &[u8], waker: &Waker) -> (Poll<Result<usize, Error>>, bool) {
289 let empty = self.buf.is_empty();
290 let tx_buf = self.buf.push_buf();
291 if tx_buf.is_empty() {
292 self.waker.register(waker);
293 return (Poll::Pending, empty);
294 }
295
296 let n = core::cmp::min(tx_buf.len(), buf.len());
297 tx_buf[..n].copy_from_slice(&buf[..n]);
298 self.buf.push(n);
299
300 (Poll::Ready(Ok(n)), empty)
301 }
302
303 fn flush(&mut self, waker: &Waker) -> Poll<Result<(), Error>> {
304 if !self.buf.is_empty() {
305 self.waker.register(waker);
306 return Poll::Pending;
307 }
308
309 Poll::Ready(Ok(()))
310 }
311}
312
313impl<'d, T: Instance> PeripheralState for TxStateInner<'d, T>
314where
315 Self: 'd,
316{
317 type Interrupt = T::Interrupt;
318 fn on_interrupt(&mut self) {
319 let r = T::regs();
320 unsafe {
321 let buf = self.buf.pop_buf();
322 if !buf.is_empty() {
323 r.uartimsc().modify(|w| {
324 w.set_txim(true);
325 });
326 r.uartdr().write(|w| w.set_data(buf[0].into()));
327 self.buf.pop(1);
328 self.waker.wake();
329 } else {
330 // Disable interrupt until we have something to transmit again
331 r.uartimsc().modify(|w| {
332 w.set_txim(false);
333 });
334 }
335 }
336 }
337}
338
339impl embedded_io::Error for Error {
340 fn kind(&self) -> embedded_io::ErrorKind {
341 embedded_io::ErrorKind::Other
342 }
343}
344
345impl<'d, T: Instance> embedded_io::Io for BufferedUart<'d, T> {
346 type Error = Error;
347}
348
349impl<'d, T: Instance> embedded_io::Io for BufferedUartRx<'d, T> {
350 type Error = Error;
351}
352
353impl<'d, T: Instance> embedded_io::Io for BufferedUartTx<'d, T> {
354 type Error = Error;
355}
356
357impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUart<'d, T> {
358 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
359 where
360 Self: 'a;
361
362 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
363 poll_fn(move |cx| {
364 let (res, do_pend) = self.inner.with(|state| {
365 compiler_fence(Ordering::SeqCst);
366 state.rx.read(buf, cx.waker())
367 });
368
369 if do_pend {
370 self.inner.pend();
371 }
372
373 res
374 })
375 }
376}
377
378impl<'d, T: Instance + 'd> embedded_io::asynch::Read for BufferedUartRx<'d, T> {
379 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
380 where
381 Self: 'a;
382
383 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
384 poll_fn(move |cx| {
385 let (res, do_pend) = self.inner.with(|state| {
386 compiler_fence(Ordering::SeqCst);
387 state.read(buf, cx.waker())
388 });
389
390 if do_pend {
391 self.inner.pend();
392 }
393
394 res
395 })
396 }
397}
398
399impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUart<'d, T> {
400 type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>>
401 where
402 Self: 'a;
403
404 fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> {
405 poll_fn(move |cx| {
406 self.inner.with(|state| {
407 compiler_fence(Ordering::SeqCst);
408 state.rx.fill_buf(cx.waker())
409 })
410 })
411 }
412
413 fn consume(&mut self, amt: usize) {
414 let signal = self.inner.with(|state| state.rx.consume(amt));
415 if signal {
416 self.inner.pend();
417 }
418 }
419}
420
421impl<'d, T: Instance + 'd> embedded_io::asynch::BufRead for BufferedUartRx<'d, T> {
422 type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>>
423 where
424 Self: 'a;
425
426 fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> {
427 poll_fn(move |cx| {
428 self.inner.with(|state| {
429 compiler_fence(Ordering::SeqCst);
430 state.fill_buf(cx.waker())
431 })
432 })
433 }
434
435 fn consume(&mut self, amt: usize) {
436 let signal = self.inner.with(|state| state.consume(amt));
437 if signal {
438 self.inner.pend();
439 }
440 }
441}
442
443impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUart<'d, T> {
444 type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
445 where
446 Self: 'a;
447
448 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
449 poll_fn(move |cx| {
450 let (poll, empty) = self.inner.with(|state| state.tx.write(buf, cx.waker()));
451 if empty {
452 self.inner.pend();
453 }
454 poll
455 })
456 }
457
458 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
459 where
460 Self: 'a;
461
462 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
463 poll_fn(move |cx| self.inner.with(|state| state.tx.flush(cx.waker())))
464 }
465}
466
467impl<'d, T: Instance + 'd> embedded_io::asynch::Write for BufferedUartTx<'d, T> {
468 type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
469 where
470 Self: 'a;
471
472 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
473 poll_fn(move |cx| {
474 let (poll, empty) = self.inner.with(|state| state.write(buf, cx.waker()));
475 if empty {
476 self.inner.pend();
477 }
478 poll
479 })
480 }
481
482 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
483 where
484 Self: 'a;
485
486 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
487 poll_fn(move |cx| self.inner.with(|state| state.flush(cx.waker())))
488 }
489}
diff --git a/embassy-rp/src/uart.rs b/embassy-rp/src/uart/mod.rs
index 987b716b4..567c79db3 100644
--- a/embassy-rp/src/uart.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -346,6 +346,11 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
346 w.set_fen(true); 346 w.set_fen(true);
347 }); 347 });
348 348
349 r.uartifls().write(|w| {
350 w.set_rxiflsel(0b000);
351 w.set_txiflsel(0b000);
352 });
353
349 r.uartcr().write(|w| { 354 r.uartcr().write(|w| {
350 w.set_uarten(true); 355 w.set_uarten(true);
351 w.set_rxe(true); 356 w.set_rxe(true);
@@ -423,9 +428,11 @@ mod eh02 {
423 428
424 impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, M> { 429 impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UartTx<'d, T, M> {
425 type Error = Error; 430 type Error = Error;
431
426 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 432 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
427 self.blocking_write(buffer) 433 self.blocking_write(buffer)
428 } 434 }
435
429 fn bflush(&mut self) -> Result<(), Self::Error> { 436 fn bflush(&mut self) -> Result<(), Self::Error> {
430 self.blocking_flush() 437 self.blocking_flush()
431 } 438 }
@@ -433,6 +440,7 @@ mod eh02 {
433 440
434 impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T, M> { 441 impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for Uart<'d, T, M> {
435 type Error = Error; 442 type Error = Error;
443
436 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> { 444 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
437 embedded_hal_02::serial::Read::read(&mut self.rx) 445 embedded_hal_02::serial::Read::read(&mut self.rx)
438 } 446 }
@@ -440,9 +448,11 @@ mod eh02 {
440 448
441 impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, M> { 449 impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Uart<'d, T, M> {
442 type Error = Error; 450 type Error = Error;
451
443 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 452 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
444 self.blocking_write(buffer) 453 self.blocking_write(buffer)
445 } 454 }
455
446 fn bflush(&mut self) -> Result<(), Self::Error> { 456 fn bflush(&mut self) -> Result<(), Self::Error> {
447 self.blocking_flush() 457 self.blocking_flush()
448 } 458 }
@@ -475,6 +485,75 @@ mod eh1 {
475 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartRx<'d, T, M> { 485 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartRx<'d, T, M> {
476 type Error = Error; 486 type Error = Error;
477 } 487 }
488
489 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Read for UartRx<'d, T, M> {
490 fn read(&mut self) -> nb::Result<u8, Self::Error> {
491 let r = T::regs();
492 unsafe {
493 let dr = r.uartdr().read();
494
495 if dr.oe() {
496 Err(nb::Error::Other(Error::Overrun))
497 } else if dr.be() {
498 Err(nb::Error::Other(Error::Break))
499 } else if dr.pe() {
500 Err(nb::Error::Other(Error::Parity))
501 } else if dr.fe() {
502 Err(nb::Error::Other(Error::Framing))
503 } else if dr.fe() {
504 Ok(dr.data())
505 } else {
506 Err(nb::Error::WouldBlock)
507 }
508 }
509 }
510 }
511
512 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::blocking::Write for UartTx<'d, T, M> {
513 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
514 self.blocking_write(buffer)
515 }
516
517 fn flush(&mut self) -> Result<(), Self::Error> {
518 self.blocking_flush()
519 }
520 }
521
522 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Write for UartTx<'d, T, M> {
523 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
524 self.blocking_write(&[char]).map_err(nb::Error::Other)
525 }
526
527 fn flush(&mut self) -> nb::Result<(), Self::Error> {
528 self.blocking_flush().map_err(nb::Error::Other)
529 }
530 }
531
532 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Read for Uart<'d, T, M> {
533 fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
534 embedded_hal_02::serial::Read::read(&mut self.rx)
535 }
536 }
537
538 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::blocking::Write for Uart<'d, T, M> {
539 fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
540 self.blocking_write(buffer)
541 }
542
543 fn flush(&mut self) -> Result<(), Self::Error> {
544 self.blocking_flush()
545 }
546 }
547
548 impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::nb::Write for Uart<'d, T, M> {
549 fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> {
550 self.blocking_write(&[char]).map_err(nb::Error::Other)
551 }
552
553 fn flush(&mut self) -> nb::Result<(), Self::Error> {
554 self.blocking_flush().map_err(nb::Error::Other)
555 }
556 }
478} 557}
479 558
480#[cfg(all( 559#[cfg(all(
@@ -532,6 +611,11 @@ mod eha {
532 } 611 }
533} 612}
534 613
614#[cfg(feature = "nightly")]
615mod buffered;
616#[cfg(feature = "nightly")]
617pub use buffered::*;
618
535mod sealed { 619mod sealed {
536 use super::*; 620 use super::*;
537 621
@@ -541,6 +625,8 @@ mod sealed {
541 const TX_DREQ: u8; 625 const TX_DREQ: u8;
542 const RX_DREQ: u8; 626 const RX_DREQ: u8;
543 627
628 type Interrupt: crate::interrupt::Interrupt;
629
544 fn regs() -> pac::uart::Uart; 630 fn regs() -> pac::uart::Uart;
545 } 631 }
546 pub trait TxPin<T: Instance> {} 632 pub trait TxPin<T: Instance> {}
@@ -572,6 +658,8 @@ macro_rules! impl_instance {
572 const TX_DREQ: u8 = $tx_dreq; 658 const TX_DREQ: u8 = $tx_dreq;
573 const RX_DREQ: u8 = $rx_dreq; 659 const RX_DREQ: u8 = $rx_dreq;
574 660
661 type Interrupt = crate::interrupt::$irq;
662
575 fn regs() -> pac::uart::Uart { 663 fn regs() -> pac::uart::Uart {
576 pac::$inst 664 pac::$inst
577 } 665 }
@@ -580,8 +668,8 @@ macro_rules! impl_instance {
580 }; 668 };
581} 669}
582 670
583impl_instance!(UART0, UART0, 20, 21); 671impl_instance!(UART0, UART0_IRQ, 20, 21);
584impl_instance!(UART1, UART1, 22, 23); 672impl_instance!(UART1, UART1_IRQ, 22, 23);
585 673
586pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} 674pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {}
587pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} 675pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {}
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index a7ec5fb79..0a904aab3 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -7,8 +7,10 @@ use core::task::Poll;
7use atomic_polyfill::compiler_fence; 7use atomic_polyfill::compiler_fence;
8use embassy_hal_common::into_ref; 8use embassy_hal_common::into_ref;
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10use embassy_usb::driver::{self, EndpointAllocError, EndpointError, Event, Unsupported}; 10use embassy_usb_driver as driver;
11use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; 11use embassy_usb_driver::{
12 Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
13};
12 14
13use crate::interrupt::{Interrupt, InterruptExt}; 15use crate::interrupt::{Interrupt, InterruptExt};
14use crate::{pac, peripherals, Peripheral, RegExt}; 16use crate::{pac, peripherals, Peripheral, RegExt};
@@ -204,8 +206,8 @@ impl<'d, T: Instance> Driver<'d, T> {
204 ); 206 );
205 207
206 let alloc = match D::dir() { 208 let alloc = match D::dir() {
207 UsbDirection::Out => &mut self.ep_out, 209 Direction::Out => &mut self.ep_out,
208 UsbDirection::In => &mut self.ep_in, 210 Direction::In => &mut self.ep_in,
209 }; 211 };
210 212
211 let index = alloc.iter_mut().enumerate().find(|(i, ep)| { 213 let index = alloc.iter_mut().enumerate().find(|(i, ep)| {
@@ -254,7 +256,7 @@ impl<'d, T: Instance> Driver<'d, T> {
254 }; 256 };
255 257
256 match D::dir() { 258 match D::dir() {
257 UsbDirection::Out => unsafe { 259 Direction::Out => unsafe {
258 T::dpram().ep_out_control(index - 1).write(|w| { 260 T::dpram().ep_out_control(index - 1).write(|w| {
259 w.set_enable(false); 261 w.set_enable(false);
260 w.set_buffer_address(addr); 262 w.set_buffer_address(addr);
@@ -262,7 +264,7 @@ impl<'d, T: Instance> Driver<'d, T> {
262 w.set_endpoint_type(ep_type_reg); 264 w.set_endpoint_type(ep_type_reg);
263 }) 265 })
264 }, 266 },
265 UsbDirection::In => unsafe { 267 Direction::In => unsafe {
266 T::dpram().ep_in_control(index - 1).write(|w| { 268 T::dpram().ep_in_control(index - 1).write(|w| {
267 w.set_enable(false); 269 w.set_enable(false);
268 w.set_buffer_address(addr); 270 w.set_buffer_address(addr);
@@ -429,14 +431,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
429 431
430 let n = ep_addr.index(); 432 let n = ep_addr.index();
431 match ep_addr.direction() { 433 match ep_addr.direction() {
432 UsbDirection::In => unsafe { 434 Direction::In => unsafe {
433 T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled)); 435 T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled));
434 T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| { 436 T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| {
435 w.set_pid(0, true); // first packet is DATA0, but PID is flipped before 437 w.set_pid(0, true); // first packet is DATA0, but PID is flipped before
436 }); 438 });
437 EP_IN_WAKERS[n].wake(); 439 EP_IN_WAKERS[n].wake();
438 }, 440 },
439 UsbDirection::Out => unsafe { 441 Direction::Out => unsafe {
440 T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled)); 442 T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled));
441 443
442 T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| { 444 T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| {
@@ -474,14 +476,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
474} 476}
475 477
476trait Dir { 478trait Dir {
477 fn dir() -> UsbDirection; 479 fn dir() -> Direction;
478 fn waker(i: usize) -> &'static AtomicWaker; 480 fn waker(i: usize) -> &'static AtomicWaker;
479} 481}
480 482
481pub enum In {} 483pub enum In {}
482impl Dir for In { 484impl Dir for In {
483 fn dir() -> UsbDirection { 485 fn dir() -> Direction {
484 UsbDirection::In 486 Direction::In
485 } 487 }
486 488
487 #[inline] 489 #[inline]
@@ -492,8 +494,8 @@ impl Dir for In {
492 494
493pub enum Out {} 495pub enum Out {}
494impl Dir for Out { 496impl Dir for Out {
495 fn dir() -> UsbDirection { 497 fn dir() -> Direction {
496 UsbDirection::Out 498 Direction::Out
497 } 499 }
498 500
499 #[inline] 501 #[inline]
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 484496f24..a4a232f51 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -39,7 +39,7 @@ embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features =
39embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" } 39embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
40embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 40embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
41embassy-net = { version = "0.1.0", path = "../embassy-net", optional = true } 41embassy-net = { version = "0.1.0", path = "../embassy-net", optional = true }
42embassy-usb = {version = "0.1.0", path = "../embassy-usb", optional = true } 42embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
43 43
44embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 44embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
45embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true} 45embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8", optional = true}
@@ -73,7 +73,7 @@ quote = "1.0.15"
73stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false, features = ["metadata"]} 73stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false, features = ["metadata"]}
74 74
75[features] 75[features]
76defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embedded-io?/defmt", "embassy-usb?/defmt"] 76defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt"]
77sdmmc-rs = ["embedded-sdmmc"] 77sdmmc-rs = ["embedded-sdmmc"]
78net = ["embassy-net" ] 78net = ["embassy-net" ]
79memory-x = ["stm32-metapac/memory-x"] 79memory-x = ["stm32-metapac/memory-x"]
@@ -92,7 +92,7 @@ time-driver-tim12 = ["_time-driver"]
92time-driver-tim15 = ["_time-driver"] 92time-driver-tim15 = ["_time-driver"]
93 93
94# Enable nightly-only features 94# Enable nightly-only features
95nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb", "embassy-embedded-hal/nightly"] 95nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"]
96 96
97# Reexport stm32-metapac at `embassy_stm32::pac`. 97# Reexport stm32-metapac at `embassy_stm32::pac`.
98# This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version. 98# This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version.
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/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 46c49a997..2a711bc06 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -1,3 +1,4 @@
1use core::cell::RefCell;
1use core::future::{poll_fn, Future}; 2use core::future::{poll_fn, Future};
2use core::task::Poll; 3use core::task::Poll;
3 4
@@ -29,7 +30,15 @@ unsafe impl<'d, T: BasicInstance> Send for StateInner<'d, T> {}
29unsafe impl<'d, T: BasicInstance> Sync for StateInner<'d, T> {} 30unsafe impl<'d, T: BasicInstance> Sync for StateInner<'d, T> {}
30 31
31pub struct BufferedUart<'d, T: BasicInstance> { 32pub struct BufferedUart<'d, T: BasicInstance> {
32 inner: PeripheralMutex<'d, StateInner<'d, T>>, 33 inner: RefCell<PeripheralMutex<'d, StateInner<'d, T>>>,
34}
35
36pub struct BufferedUartTx<'u, 'd, T: BasicInstance> {
37 inner: &'u BufferedUart<'d, T>,
38}
39
40pub struct BufferedUartRx<'u, 'd, T: BasicInstance> {
41 inner: &'u BufferedUart<'d, T>,
33} 42}
34 43
35impl<'d, T: BasicInstance> Unpin for BufferedUart<'d, T> {} 44impl<'d, T: BasicInstance> Unpin for BufferedUart<'d, T> {}
@@ -53,14 +62,124 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
53 } 62 }
54 63
55 Self { 64 Self {
56 inner: PeripheralMutex::new(irq, &mut state.0, move || StateInner { 65 inner: RefCell::new(PeripheralMutex::new(irq, &mut state.0, move || StateInner {
57 phantom: PhantomData, 66 phantom: PhantomData,
58 tx: RingBuffer::new(tx_buffer), 67 tx: RingBuffer::new(tx_buffer),
59 tx_waker: WakerRegistration::new(), 68 tx_waker: WakerRegistration::new(),
60 69
61 rx: RingBuffer::new(rx_buffer), 70 rx: RingBuffer::new(rx_buffer),
62 rx_waker: WakerRegistration::new(), 71 rx_waker: WakerRegistration::new(),
63 }), 72 })),
73 }
74 }
75
76 pub fn split<'u>(&'u mut self) -> (BufferedUartRx<'u, 'd, T>, BufferedUartTx<'u, 'd, T>) {
77 (BufferedUartRx { inner: self }, BufferedUartTx { inner: self })
78 }
79
80 async fn inner_read<'a>(&'a self, buf: &'a mut [u8]) -> Result<usize, Error> {
81 poll_fn(move |cx| {
82 let mut do_pend = false;
83 let mut inner = self.inner.borrow_mut();
84 let res = inner.with(|state| {
85 compiler_fence(Ordering::SeqCst);
86
87 // We have data ready in buffer? Return it.
88 let data = state.rx.pop_buf();
89 if !data.is_empty() {
90 let len = data.len().min(buf.len());
91 buf[..len].copy_from_slice(&data[..len]);
92
93 if state.rx.is_full() {
94 do_pend = true;
95 }
96 state.rx.pop(len);
97
98 return Poll::Ready(Ok(len));
99 }
100
101 state.rx_waker.register(cx.waker());
102 Poll::Pending
103 });
104
105 if do_pend {
106 inner.pend();
107 }
108
109 res
110 })
111 .await
112 }
113
114 async fn inner_write<'a>(&'a self, buf: &'a [u8]) -> Result<usize, Error> {
115 poll_fn(move |cx| {
116 let mut inner = self.inner.borrow_mut();
117 let (poll, empty) = inner.with(|state| {
118 let empty = state.tx.is_empty();
119 let tx_buf = state.tx.push_buf();
120 if tx_buf.is_empty() {
121 state.tx_waker.register(cx.waker());
122 return (Poll::Pending, empty);
123 }
124
125 let n = core::cmp::min(tx_buf.len(), buf.len());
126 tx_buf[..n].copy_from_slice(&buf[..n]);
127 state.tx.push(n);
128
129 (Poll::Ready(Ok(n)), empty)
130 });
131 if empty {
132 inner.pend();
133 }
134 poll
135 })
136 .await
137 }
138
139 async fn inner_flush<'a>(&'a self) -> Result<(), Error> {
140 poll_fn(move |cx| {
141 self.inner.borrow_mut().with(|state| {
142 if !state.tx.is_empty() {
143 state.tx_waker.register(cx.waker());
144 return Poll::Pending;
145 }
146
147 Poll::Ready(Ok(()))
148 })
149 })
150 .await
151 }
152
153 async fn inner_fill_buf<'a>(&'a self) -> Result<&'a [u8], Error> {
154 poll_fn(move |cx| {
155 self.inner.borrow_mut().with(|state| {
156 compiler_fence(Ordering::SeqCst);
157
158 // We have data ready in buffer? Return it.
159 let buf = state.rx.pop_buf();
160 if !buf.is_empty() {
161 let buf: &[u8] = buf;
162 // Safety: buffer lives as long as uart
163 let buf: &[u8] = unsafe { core::mem::transmute(buf) };
164 return Poll::Ready(Ok(buf));
165 }
166
167 state.rx_waker.register(cx.waker());
168 Poll::<Result<&[u8], Error>>::Pending
169 })
170 })
171 .await
172 }
173
174 fn inner_consume(&self, amt: usize) {
175 let mut inner = self.inner.borrow_mut();
176 let signal = inner.with(|state| {
177 let full = state.rx.is_full();
178 state.rx.pop(amt);
179 full
180 });
181 if signal {
182 inner.pend();
64 } 183 }
65 } 184 }
66} 185}
@@ -155,41 +274,31 @@ impl<'d, T: BasicInstance> embedded_io::Io for BufferedUart<'d, T> {
155 type Error = Error; 274 type Error = Error;
156} 275}
157 276
277impl<'u, 'd, T: BasicInstance> embedded_io::Io for BufferedUartRx<'u, 'd, T> {
278 type Error = Error;
279}
280
281impl<'u, 'd, T: BasicInstance> embedded_io::Io for BufferedUartTx<'u, 'd, T> {
282 type Error = Error;
283}
284
158impl<'d, T: BasicInstance> embedded_io::asynch::Read for BufferedUart<'d, T> { 285impl<'d, T: BasicInstance> embedded_io::asynch::Read for BufferedUart<'d, T> {
159 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>> 286 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
160 where 287 where
161 Self: 'a; 288 Self: 'a;
162 289
163 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> { 290 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
164 poll_fn(move |cx| { 291 self.inner_read(buf)
165 let mut do_pend = false; 292 }
166 let res = self.inner.with(|state| { 293}
167 compiler_fence(Ordering::SeqCst);
168
169 // We have data ready in buffer? Return it.
170 let data = state.rx.pop_buf();
171 if !data.is_empty() {
172 let len = data.len().min(buf.len());
173 buf[..len].copy_from_slice(&data[..len]);
174
175 if state.rx.is_full() {
176 do_pend = true;
177 }
178 state.rx.pop(len);
179
180 return Poll::Ready(Ok(len));
181 }
182
183 state.rx_waker.register(cx.waker());
184 Poll::Pending
185 });
186 294
187 if do_pend { 295impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Read for BufferedUartRx<'u, 'd, T> {
188 self.inner.pend(); 296 type ReadFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
189 } 297 where
298 Self: 'a;
190 299
191 res 300 fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::ReadFuture<'a> {
192 }) 301 self.inner.inner_read(buf)
193 } 302 }
194} 303}
195 304
@@ -199,34 +308,25 @@ impl<'d, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUart<'d, T>
199 Self: 'a; 308 Self: 'a;
200 309
201 fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> { 310 fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> {
202 poll_fn(move |cx| { 311 self.inner_fill_buf()
203 self.inner.with(|state| { 312 }
204 compiler_fence(Ordering::SeqCst);
205 313
206 // We have data ready in buffer? Return it. 314 fn consume(&mut self, amt: usize) {
207 let buf = state.rx.pop_buf(); 315 self.inner_consume(amt)
208 if !buf.is_empty() { 316 }
209 let buf: &[u8] = buf; 317}
210 // Safety: buffer lives as long as uart
211 let buf: &[u8] = unsafe { core::mem::transmute(buf) };
212 return Poll::Ready(Ok(buf));
213 }
214 318
215 state.rx_waker.register(cx.waker()); 319impl<'u, 'd, T: BasicInstance> embedded_io::asynch::BufRead for BufferedUartRx<'u, 'd, T> {
216 Poll::<Result<&[u8], Self::Error>>::Pending 320 type FillBufFuture<'a> = impl Future<Output = Result<&'a [u8], Self::Error>>
217 }) 321 where
218 }) 322 Self: 'a;
323
324 fn fill_buf<'a>(&'a mut self) -> Self::FillBufFuture<'a> {
325 self.inner.inner_fill_buf()
219 } 326 }
220 327
221 fn consume(&mut self, amt: usize) { 328 fn consume(&mut self, amt: usize) {
222 let signal = self.inner.with(|state| { 329 self.inner.inner_consume(amt)
223 let full = state.rx.is_full();
224 state.rx.pop(amt);
225 full
226 });
227 if signal {
228 self.inner.pend();
229 }
230 } 330 }
231} 331}
232 332
@@ -236,26 +336,25 @@ impl<'d, T: BasicInstance> embedded_io::asynch::Write for BufferedUart<'d, T> {
236 Self: 'a; 336 Self: 'a;
237 337
238 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> { 338 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
239 poll_fn(move |cx| { 339 self.inner_write(buf)
240 let (poll, empty) = self.inner.with(|state| { 340 }
241 let empty = state.tx.is_empty();
242 let tx_buf = state.tx.push_buf();
243 if tx_buf.is_empty() {
244 state.tx_waker.register(cx.waker());
245 return (Poll::Pending, empty);
246 }
247 341
248 let n = core::cmp::min(tx_buf.len(), buf.len()); 342 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
249 tx_buf[..n].copy_from_slice(&buf[..n]); 343 where
250 state.tx.push(n); 344 Self: 'a;
251 345
252 (Poll::Ready(Ok(n)), empty) 346 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
253 }); 347 self.inner_flush()
254 if empty { 348 }
255 self.inner.pend(); 349}
256 } 350
257 poll 351impl<'u, 'd, T: BasicInstance> embedded_io::asynch::Write for BufferedUartTx<'u, 'd, T> {
258 }) 352 type WriteFuture<'a> = impl Future<Output = Result<usize, Self::Error>>
353 where
354 Self: 'a;
355
356 fn write<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteFuture<'a> {
357 self.inner.inner_write(buf)
259 } 358 }
260 359
261 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> 360 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>>
@@ -263,15 +362,6 @@ impl<'d, T: BasicInstance> embedded_io::asynch::Write for BufferedUart<'d, T> {
263 Self: 'a; 362 Self: 'a;
264 363
265 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> { 364 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
266 poll_fn(move |cx| { 365 self.inner.inner_flush()
267 self.inner.with(|state| {
268 if !state.tx.is_empty() {
269 state.tx_waker.register(cx.waker());
270 return Poll::Pending;
271 }
272
273 Poll::Ready(Ok(()))
274 })
275 })
276 } 366 }
277} 367}
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index e5ee1181c..2654f156a 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -9,8 +9,10 @@ use atomic_polyfill::{AtomicBool, AtomicU8};
9use embassy_hal_common::into_ref; 9use embassy_hal_common::into_ref;
10use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
11use embassy_time::{block_for, Duration}; 11use embassy_time::{block_for, Duration};
12use embassy_usb::driver::{self, EndpointAllocError, EndpointError, Event, Unsupported}; 12use embassy_usb_driver as driver;
13use embassy_usb::types::{EndpointAddress, EndpointInfo, EndpointType, UsbDirection}; 13use embassy_usb_driver::{
14 Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
15};
14use pac::common::{Reg, RW}; 16use pac::common::{Reg, RW};
15use pac::usb::vals::{EpType, Stat}; 17use pac::usb::vals::{EpType, Stat};
16 18
@@ -279,8 +281,8 @@ impl<'d, T: Instance> Driver<'d, T> {
279 } 281 }
280 let used = ep.used_out || ep.used_in; 282 let used = ep.used_out || ep.used_in;
281 let used_dir = match D::dir() { 283 let used_dir = match D::dir() {
282 UsbDirection::Out => ep.used_out, 284 Direction::Out => ep.used_out,
283 UsbDirection::In => ep.used_in, 285 Direction::In => ep.used_in,
284 }; 286 };
285 !used || (ep.ep_type == ep_type && !used_dir) 287 !used || (ep.ep_type == ep_type && !used_dir)
286 }); 288 });
@@ -293,7 +295,7 @@ impl<'d, T: Instance> Driver<'d, T> {
293 ep.ep_type = ep_type; 295 ep.ep_type = ep_type;
294 296
295 let buf = match D::dir() { 297 let buf = match D::dir() {
296 UsbDirection::Out => { 298 Direction::Out => {
297 assert!(!ep.used_out); 299 assert!(!ep.used_out);
298 ep.used_out = true; 300 ep.used_out = true;
299 301
@@ -312,7 +314,7 @@ impl<'d, T: Instance> Driver<'d, T> {
312 _phantom: PhantomData, 314 _phantom: PhantomData,
313 } 315 }
314 } 316 }
315 UsbDirection::In => { 317 Direction::In => {
316 assert!(!ep.used_in); 318 assert!(!ep.used_in);
317 ep.used_in = true; 319 ep.used_in = true;
318 320
@@ -504,7 +506,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
504 // This can race, so do a retry loop. 506 // This can race, so do a retry loop.
505 let reg = T::regs().epr(ep_addr.index() as _); 507 let reg = T::regs().epr(ep_addr.index() as _);
506 match ep_addr.direction() { 508 match ep_addr.direction() {
507 UsbDirection::In => { 509 Direction::In => {
508 loop { 510 loop {
509 let r = unsafe { reg.read() }; 511 let r = unsafe { reg.read() };
510 match r.stat_tx() { 512 match r.stat_tx() {
@@ -523,7 +525,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
523 } 525 }
524 EP_IN_WAKERS[ep_addr.index()].wake(); 526 EP_IN_WAKERS[ep_addr.index()].wake();
525 } 527 }
526 UsbDirection::Out => { 528 Direction::Out => {
527 loop { 529 loop {
528 let r = unsafe { reg.read() }; 530 let r = unsafe { reg.read() };
529 match r.stat_rx() { 531 match r.stat_rx() {
@@ -549,8 +551,8 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
549 let regs = T::regs(); 551 let regs = T::regs();
550 let epr = unsafe { regs.epr(ep_addr.index() as _).read() }; 552 let epr = unsafe { regs.epr(ep_addr.index() as _).read() };
551 match ep_addr.direction() { 553 match ep_addr.direction() {
552 UsbDirection::In => epr.stat_tx() == Stat::STALL, 554 Direction::In => epr.stat_tx() == Stat::STALL,
553 UsbDirection::Out => epr.stat_rx() == Stat::STALL, 555 Direction::Out => epr.stat_rx() == Stat::STALL,
554 } 556 }
555 } 557 }
556 558
@@ -560,7 +562,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
560 let reg = T::regs().epr(ep_addr.index() as _); 562 let reg = T::regs().epr(ep_addr.index() as _);
561 trace!("EPR before: {:04x}", unsafe { reg.read() }.0); 563 trace!("EPR before: {:04x}", unsafe { reg.read() }.0);
562 match ep_addr.direction() { 564 match ep_addr.direction() {
563 UsbDirection::In => { 565 Direction::In => {
564 loop { 566 loop {
565 let want_stat = match enabled { 567 let want_stat = match enabled {
566 false => Stat::DISABLED, 568 false => Stat::DISABLED,
@@ -576,7 +578,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
576 } 578 }
577 EP_IN_WAKERS[ep_addr.index()].wake(); 579 EP_IN_WAKERS[ep_addr.index()].wake();
578 } 580 }
579 UsbDirection::Out => { 581 Direction::Out => {
580 loop { 582 loop {
581 let want_stat = match enabled { 583 let want_stat = match enabled {
582 false => Stat::DISABLED, 584 false => Stat::DISABLED,
@@ -616,14 +618,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
616} 618}
617 619
618trait Dir { 620trait Dir {
619 fn dir() -> UsbDirection; 621 fn dir() -> Direction;
620 fn waker(i: usize) -> &'static AtomicWaker; 622 fn waker(i: usize) -> &'static AtomicWaker;
621} 623}
622 624
623pub enum In {} 625pub enum In {}
624impl Dir for In { 626impl Dir for In {
625 fn dir() -> UsbDirection { 627 fn dir() -> Direction {
626 UsbDirection::In 628 Direction::In
627 } 629 }
628 630
629 #[inline] 631 #[inline]
@@ -634,8 +636,8 @@ impl Dir for In {
634 636
635pub enum Out {} 637pub enum Out {}
636impl Dir for Out { 638impl Dir for Out {
637 fn dir() -> UsbDirection { 639 fn dir() -> Direction {
638 UsbDirection::Out 640 Direction::Out
639 } 641 }
640 642
641 #[inline] 643 #[inline]
diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs
index b4d99513a..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::{poll_fn, 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,31 +72,27 @@ 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()));
84 Poll::Pending
85 }
86 State::Waiting(w) if w.will_wake(cx.waker()) => {
87 cell.set(State::Waiting(w));
79 Poll::Pending 88 Poll::Pending
80 } 89 }
81 State::Waiting(w) if w.will_wake(cx.waker()) => Poll::Pending,
82 State::Waiting(w) => { 90 State::Waiting(w) => {
83 let w = mem::replace(w, cx.waker().clone()); 91 cell.set(State::Waiting(cx.waker().clone()));
84 w.wake(); 92 w.wake();
85 Poll::Pending 93 Poll::Pending
86 } 94 }
87 State::Signaled(_) => match mem::replace(state, State::None) { 95 State::Signaled(res) => Poll::Ready(res),
88 State::Signaled(res) => Poll::Ready(res),
89 _ => unreachable!(),
90 },
91 } 96 }
92 }) 97 })
93 } 98 }
@@ -99,6 +104,14 @@ impl<T: Send> Signal<T> {
99 104
100 /// non-blocking method to check whether this signal has been signaled. 105 /// non-blocking method to check whether this signal has been signaled.
101 pub fn signaled(&self) -> bool { 106 pub fn signaled(&self) -> bool {
102 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 })
103 } 116 }
104} 117}
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 27b536a6b..09bb1cc8d 100644
--- a/embassy-usb-serial/src/lib.rs
+++ b/embassy-usb/src/class/cdc_acm.rs
@@ -1,18 +1,13 @@
1#![no_std]
2#![feature(type_alias_impl_trait)]
3
4// This mod MUST go first, so that the others see its macros.
5pub(crate) mod fmt;
6
7use core::cell::Cell; 1use core::cell::Cell;
8use core::mem::{self, MaybeUninit}; 2use core::mem::{self, MaybeUninit};
9use core::sync::atomic::{AtomicBool, Ordering}; 3use core::sync::atomic::{AtomicBool, Ordering};
10 4
11use embassy_sync::blocking_mutex::CriticalSectionMutex; 5use embassy_sync::blocking_mutex::CriticalSectionMutex;
12use embassy_usb::control::{self, ControlHandler, InResponse, OutResponse, Request}; 6
13use embassy_usb::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; 7use crate::control::{self, ControlHandler, InResponse, OutResponse, Request};
14use embassy_usb::types::*; 8use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
15use embassy_usb::Builder; 9use crate::types::*;
10use crate::Builder;
16 11
17/// This should be used as `device_class` when building the `UsbDevice`. 12/// This should be used as `device_class` when building the `UsbDevice`.
18pub const USB_CLASS_CDC: u8 = 0x02; 13pub const USB_CLASS_CDC: u8 = 0x02;
@@ -268,7 +263,7 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> {
268} 263}
269 264
270/// Number of stop bits for LineCoding 265/// Number of stop bits for LineCoding
271#[derive(Copy, Clone, PartialEq, Eq)] 266#[derive(Copy, Clone, Debug, PartialEq, Eq)]
272#[cfg_attr(feature = "defmt", derive(defmt::Format))] 267#[cfg_attr(feature = "defmt", derive(defmt::Format))]
273pub enum StopBits { 268pub enum StopBits {
274 /// 1 stop bit 269 /// 1 stop bit
@@ -292,7 +287,7 @@ impl From<u8> for StopBits {
292} 287}
293 288
294/// Parity for LineCoding 289/// Parity for LineCoding
295#[derive(Copy, Clone, PartialEq, Eq)] 290#[derive(Copy, Clone, Debug, PartialEq, Eq)]
296#[cfg_attr(feature = "defmt", derive(defmt::Format))] 291#[cfg_attr(feature = "defmt", derive(defmt::Format))]
297pub enum ParityType { 292pub enum ParityType {
298 None = 0, 293 None = 0,
@@ -316,7 +311,7 @@ impl From<u8> for ParityType {
316/// 311///
317/// 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
318/// 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.
319#[derive(Clone, Copy)] 314#[derive(Clone, Copy, Debug)]
320#[cfg_attr(feature = "defmt", derive(defmt::Format))] 315#[cfg_attr(feature = "defmt", derive(defmt::Format))]
321pub struct LineCoding { 316pub struct LineCoding {
322 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 8b181aec8..4d1fa995f 100644
--- a/embassy-usb-hid/src/lib.rs
+++ b/embassy-usb/src/class/hid.rs
@@ -1,23 +1,16 @@
1#![no_std]
2#![feature(type_alias_impl_trait)]
3
4//! Implements HID functionality for a usb-device device.
5
6// This mod MUST go first, so that the others see its macros.
7pub(crate) mod fmt;
8
9use core::mem::MaybeUninit; 1use core::mem::MaybeUninit;
10use core::ops::Range; 2use core::ops::Range;
11use core::sync::atomic::{AtomicUsize, Ordering}; 3use core::sync::atomic::{AtomicUsize, Ordering};
12 4
13use embassy_usb::control::{ControlHandler, InResponse, OutResponse, Request, RequestType};
14use embassy_usb::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
15use embassy_usb::Builder;
16#[cfg(feature = "usbd-hid")] 5#[cfg(feature = "usbd-hid")]
17use ssmarshal::serialize; 6use ssmarshal::serialize;
18#[cfg(feature = "usbd-hid")] 7#[cfg(feature = "usbd-hid")]
19use usbd_hid::descriptor::AsInputReport; 8use usbd_hid::descriptor::AsInputReport;
20 9
10use crate::control::{ControlHandler, InResponse, OutResponse, Request, RequestType};
11use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut};
12use crate::Builder;
13
21const USB_CLASS_HID: u8 = 0x03; 14const USB_CLASS_HID: u8 = 0x03;
22const USB_SUBCLASS_NONE: u8 = 0x00; 15const USB_SUBCLASS_NONE: u8 = 0x00;
23const USB_PROTOCOL_NONE: u8 = 0x00; 16const USB_PROTOCOL_NONE: u8 = 0x00;
@@ -204,9 +197,9 @@ pub enum ReadError {
204 Sync(Range<usize>), 197 Sync(Range<usize>),
205} 198}
206 199
207impl From<embassy_usb::driver::EndpointError> for ReadError { 200impl From<EndpointError> for ReadError {
208 fn from(val: embassy_usb::driver::EndpointError) -> Self { 201 fn from(val: EndpointError) -> Self {
209 use embassy_usb::driver::EndpointError::*; 202 use EndpointError::*;
210 match val { 203 match val {
211 BufferOverflow => ReadError::BufferOverflow, 204 BufferOverflow => ReadError::BufferOverflow,
212 Disabled => ReadError::Disabled, 205 Disabled => ReadError::Disabled,
@@ -437,7 +430,7 @@ impl<'d> ControlHandler for Control<'d> {
437 } 430 }
438 } 431 }
439 432
440 fn control_out(&mut self, req: embassy_usb::control::Request, data: &[u8]) -> OutResponse { 433 fn control_out(&mut self, req: Request, data: &[u8]) -> OutResponse {
441 trace!("HID control_out {:?} {=[u8]:x}", req, data); 434 trace!("HID control_out {:?} {=[u8]:x}", req, data);
442 if let RequestType::Class = req.request_type { 435 if let RequestType::Class = req.request_type {
443 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 ca7dde627..661b84119 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -4,23 +4,24 @@
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
7pub use embassy_usb_driver as driver;
8
7mod builder; 9mod builder;
10pub mod class;
8pub mod control; 11pub mod control;
9pub mod descriptor; 12pub mod descriptor;
10mod descriptor_reader; 13mod descriptor_reader;
11pub mod driver;
12pub mod types; 14pub mod types;
13 15
14use embassy_futures::select::{select, Either}; 16use embassy_futures::select::{select, Either};
15use heapless::Vec; 17use heapless::Vec;
16 18
17pub use self::builder::{Builder, Config}; 19pub use crate::builder::{Builder, Config};
18use self::control::*; 20use crate::control::*;
19use self::descriptor::*; 21use crate::descriptor::*;
20use self::driver::{Bus, Driver, Event};
21use self::types::*;
22use crate::descriptor_reader::foreach_endpoint; 22use crate::descriptor_reader::foreach_endpoint;
23use crate::driver::ControlPipe; 23use crate::driver::{Bus, ControlPipe, Direction, Driver, EndpointAddress, Event};
24use crate::types::*;
24 25
25/// The global state of the USB device. 26/// The global state of the USB device.
26/// 27///
@@ -247,11 +248,11 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
247 async fn handle_control(&mut self, req: [u8; 8]) { 248 async fn handle_control(&mut self, req: [u8; 8]) {
248 let req = Request::parse(&req); 249 let req = Request::parse(&req);
249 250
250 trace!("control request: {:02x}", req); 251 trace!("control request: {:?}", req);
251 252
252 match req.direction { 253 match req.direction {
253 UsbDirection::In => self.handle_control_in(req).await, 254 Direction::In => self.handle_control_in(req).await,
254 UsbDirection::Out => self.handle_control_out(req).await, 255 Direction::Out => self.handle_control_out(req).await,
255 } 256 }
256 257
257 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/stm32f7/src/bin/a.rs b/examples/boot/application/stm32f7/src/bin/a.rs
index c08880fb3..77b897b0f 100644
--- a/examples/boot/application/stm32f7/src/bin/a.rs
+++ b/examples/boot/application/stm32f7/src/bin/a.rs
@@ -5,7 +5,6 @@
5#[cfg(feature = "defmt-rtt")] 5#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 6use defmt_rtt::*;
7use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater}; 7use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater};
8use embassy_embedded_hal::adapter::BlockingAsync;
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
10use embassy_stm32::exti::ExtiInput; 9use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::flash::{Flash, WRITE_SIZE}; 10use embassy_stm32::flash::{Flash, WRITE_SIZE};
@@ -17,8 +16,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
17#[embassy_executor::main] 16#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
19 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(Default::default());
20 let flash = Flash::unlock(p.FLASH); 19 let mut flash = Flash::unlock(p.FLASH);
21 let mut flash = BlockingAsync::new(flash);
22 20
23 let button = Input::new(p.PC13, Pull::Down); 21 let button = Input::new(p.PC13, Pull::Down);
24 let mut button = ExtiInput::new(button, p.EXTI13); 22 let mut button = ExtiInput::new(button, p.EXTI13);
@@ -27,16 +25,19 @@ async fn main(_spawner: Spawner) {
27 led.set_high(); 25 led.set_high();
28 26
29 let mut updater = FirmwareUpdater::default(); 27 let mut updater = FirmwareUpdater::default();
28 let mut writer = updater.prepare_update_blocking(&mut flash).unwrap();
30 button.wait_for_rising_edge().await; 29 button.wait_for_rising_edge().await;
31 let mut offset = 0; 30 let mut offset = 0;
32 let mut buf: [u8; 256 * 1024] = [0; 256 * 1024]; 31 let mut buf = AlignedBuffer([0; 4096]);
33 for chunk in APP_B.chunks(256 * 1024) { 32 for chunk in APP_B.chunks(4096) {
34 buf[..chunk.len()].copy_from_slice(chunk); 33 buf.as_mut()[..chunk.len()].copy_from_slice(chunk);
35 updater.write_firmware(offset, &buf, &mut flash, 2048).await.unwrap(); 34 writer
35 .write_block_blocking(offset, buf.as_ref(), &mut flash, chunk.len())
36 .unwrap();
36 offset += chunk.len(); 37 offset += chunk.len();
37 } 38 }
38 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 39 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
39 updater.mark_updated(&mut flash, magic.as_mut()).await.unwrap(); 40 updater.mark_updated_blocking(&mut flash, magic.as_mut()).unwrap();
40 led.set_low(); 41 led.set_low();
41 cortex_m::peripheral::SCB::sys_reset(); 42 cortex_m::peripheral::SCB::sys_reset();
42} 43}
diff --git a/examples/boot/application/stm32h7/src/bin/a.rs b/examples/boot/application/stm32h7/src/bin/a.rs
index f5a8fdb61..0fe598a5d 100644
--- a/examples/boot/application/stm32h7/src/bin/a.rs
+++ b/examples/boot/application/stm32h7/src/bin/a.rs
@@ -5,7 +5,6 @@
5#[cfg(feature = "defmt-rtt")] 5#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 6use defmt_rtt::*;
7use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater}; 7use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater};
8use embassy_embedded_hal::adapter::BlockingAsync;
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
10use embassy_stm32::exti::ExtiInput; 9use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::flash::{Flash, WRITE_SIZE}; 10use embassy_stm32::flash::{Flash, WRITE_SIZE};
@@ -17,8 +16,7 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
17#[embassy_executor::main] 16#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
19 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(Default::default());
20 let flash = Flash::unlock(p.FLASH); 19 let mut flash = Flash::unlock(p.FLASH);
21 let mut flash = BlockingAsync::new(flash);
22 20
23 let button = Input::new(p.PC13, Pull::Down); 21 let button = Input::new(p.PC13, Pull::Down);
24 let mut button = ExtiInput::new(button, p.EXTI13); 22 let mut button = ExtiInput::new(button, p.EXTI13);
@@ -27,19 +25,20 @@ async fn main(_spawner: Spawner) {
27 led.set_high(); 25 led.set_high();
28 26
29 let mut updater = FirmwareUpdater::default(); 27 let mut updater = FirmwareUpdater::default();
28
29 let mut writer = updater.prepare_update_blocking(&mut flash).unwrap();
30 button.wait_for_rising_edge().await; 30 button.wait_for_rising_edge().await;
31 let mut offset = 0; 31 let mut offset = 0;
32 let mut buf = AlignedBuffer([0; 128 * 1024]); 32 let mut buf = AlignedBuffer([0; 4096]);
33 for chunk in APP_B.chunks(128 * 1024) { 33 for chunk in APP_B.chunks(4096) {
34 buf.as_mut()[..chunk.len()].copy_from_slice(chunk); 34 buf.as_mut()[..chunk.len()].copy_from_slice(chunk);
35 updater 35 writer
36 .write_firmware(offset, buf.as_ref(), &mut flash, 2048) 36 .write_block_blocking(offset, buf.as_ref(), &mut flash, 4096)
37 .await
38 .unwrap(); 37 .unwrap();
39 offset += chunk.len(); 38 offset += chunk.len();
40 } 39 }
41 let mut magic = AlignedBuffer([0; WRITE_SIZE]); 40 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
42 updater.mark_updated(&mut flash, magic.as_mut()).await.unwrap(); 41 updater.mark_updated_blocking(&mut flash, magic.as_mut()).unwrap();
43 led.set_low(); 42 led.set_low();
44 cortex_m::peripheral::SCB::sys_reset(); 43 cortex_m::peripheral::SCB::sys_reset();
45} 44}
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/usb_ethernet.rs b/examples/nrf/src/bin/usb_ethernet.rs
index 33ca380ff..de93a2b45 100644
--- a/examples/nrf/src/bin/usb_ethernet.rs
+++ b/examples/nrf/src/bin/usb_ethernet.rs
@@ -15,8 +15,8 @@ use embassy_nrf::usb::{Driver, PowerUsb};
15use embassy_nrf::{interrupt, pac, peripherals}; 15use embassy_nrf::{interrupt, pac, peripherals};
16use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 16use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
17use embassy_sync::channel::Channel; 17use embassy_sync::channel::Channel;
18use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State};
18use embassy_usb::{Builder, Config, UsbDevice}; 19use embassy_usb::{Builder, Config, UsbDevice};
19use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
20use embedded_io::asynch::Write; 20use embedded_io::asynch::Write;
21use static_cell::StaticCell; 21use static_cell::StaticCell;
22use {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 70318b78f..76e198719 100644
--- a/examples/nrf/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf/src/bin/usb_hid_keyboard.rs
@@ -12,10 +12,11 @@ use 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 usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 20use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
20use {defmt_rtt as _, panic_probe as _}; 21use {defmt_rtt as _, panic_probe as _};
21 22
@@ -66,7 +67,7 @@ async fn main(_spawner: Spawner) {
66 ); 67 );
67 68
68 // Create classes on the builder. 69 // Create classes on the builder.
69 let config = embassy_usb_hid::Config { 70 let config = embassy_usb::class::hid::Config {
70 report_descriptor: KeyboardReport::desc(), 71 report_descriptor: KeyboardReport::desc(),
71 request_handler: Some(&request_handler), 72 request_handler: Some(&request_handler),
72 poll_ms: 60, 73 poll_ms: 60,
@@ -77,7 +78,7 @@ async fn main(_spawner: Spawner) {
77 // Build the builder. 78 // Build the builder.
78 let mut usb = builder.build(); 79 let mut usb = builder.build();
79 80
80 let remote_wakeup = Signal::new(); 81 let remote_wakeup: Signal<CriticalSectionRawMutex, _> = Signal::new();
81 82
82 // Run the USB device. 83 // Run the USB device.
83 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 65fbda1cf..4916a38d4 100644
--- a/examples/nrf/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf/src/bin/usb_hid_mouse.rs
@@ -10,9 +10,9 @@ use 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 usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; 16use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
17use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
18 18
@@ -59,7 +59,7 @@ async fn main(_spawner: Spawner) {
59 ); 59 );
60 60
61 // Create classes on the builder. 61 // Create classes on the builder.
62 let config = embassy_usb_hid::Config { 62 let config = embassy_usb::class::hid::Config {
63 report_descriptor: MouseReport::desc(), 63 report_descriptor: MouseReport::desc(),
64 request_handler: Some(&request_handler), 64 request_handler: Some(&request_handler),
65 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 a740b4e0a..7c9c4184b 100644
--- a/examples/nrf/src/bin/usb_serial.rs
+++ b/examples/nrf/src/bin/usb_serial.rs
@@ -9,9 +9,9 @@ use embassy_executor::Spawner;
9use embassy_futures::join::join; 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 {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
17#[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 c646c0bbd..93efc2fe6 100644
--- a/examples/nrf/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf/src/bin/usb_serial_multitask.rs
@@ -8,9 +8,9 @@ use defmt::{info, panic, unwrap};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_nrf::usb::{Driver, PowerUsb}; 9use embassy_nrf::usb::{Driver, PowerUsb};
10use embassy_nrf::{interrupt, pac, peripherals}; 10use embassy_nrf::{interrupt, pac, peripherals};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError; 12use embassy_usb::driver::EndpointError;
12use embassy_usb::{Builder, Config, UsbDevice}; 13use embassy_usb::{Builder, Config, UsbDevice};
13use embassy_usb_serial::{CdcAcmClass, State};
14use static_cell::StaticCell; 14use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 24c3cdd67..3c8f923e7 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -10,9 +10,7 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
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", "time-driver"] } 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"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
17 15
18defmt = "0.3" 16defmt = "0.3"
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
index 166ffe175..1057fe7fd 100644
--- a/examples/rp/src/bin/usb_ethernet.rs
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -13,8 +13,8 @@ use embassy_rp::usb::Driver;
13use embassy_rp::{interrupt, peripherals}; 13use embassy_rp::{interrupt, peripherals};
14use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 14use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
15use embassy_sync::channel::Channel; 15use embassy_sync::channel::Channel;
16use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State};
16use embassy_usb::{Builder, Config, UsbDevice}; 17use embassy_usb::{Builder, Config, UsbDevice};
17use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
18use embedded_io::asynch::Write; 18use embedded_io::asynch::Write;
19use static_cell::StaticCell; 19use static_cell::StaticCell;
20use {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 bf92a1636..b7d6493b4 100644
--- a/examples/rp/src/bin/usb_serial.rs
+++ b/examples/rp/src/bin/usb_serial.rs
@@ -7,9 +7,9 @@ use embassy_executor::Spawner;
7use embassy_futures::join::join; 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 {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
15#[embassy_executor::main] 15#[embassy_executor::main]
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index 895e043dd..e6553789a 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -9,7 +9,6 @@ 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"] }
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 12embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
14 13
15defmt = "0.3" 14defmt = "0.3"
diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs
index a14e728ba..ad92cdeb2 100644
--- a/examples/stm32f1/src/bin/usb_serial.rs
+++ b/examples/stm32f1/src/bin/usb_serial.rs
@@ -10,9 +10,9 @@ use embassy_stm32::time::Hertz;
10use embassy_stm32::usb::{Driver, Instance}; 10use embassy_stm32::usb::{Driver, Instance};
11use embassy_stm32::{interrupt, Config}; 11use embassy_stm32::{interrupt, Config};
12use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
13use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
13use embassy_usb::driver::EndpointError; 14use embassy_usb::driver::EndpointError;
14use embassy_usb::Builder; 15use embassy_usb::Builder;
15use embassy_usb_serial::{CdcAcmClass, State};
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 27f5c260a..f5b0b880c 100644
--- a/examples/stm32f3/Cargo.toml
+++ b/examples/stm32f3/Cargo.toml
@@ -9,8 +9,6 @@ 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"] }
13embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 12embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15 13
16defmt = "0.3" 14defmt = "0.3"
diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs
index b9fd20e2b..f6d27c860 100644
--- a/examples/stm32f3/src/bin/usb_serial.rs
+++ b/examples/stm32f3/src/bin/usb_serial.rs
@@ -10,9 +10,9 @@ use embassy_stm32::time::mhz;
10use embassy_stm32::usb::{Driver, Instance}; 10use embassy_stm32::usb::{Driver, Instance};
11use embassy_stm32::{interrupt, Config}; 11use embassy_stm32::{interrupt, Config};
12use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
13use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
13use embassy_usb::driver::EndpointError; 14use embassy_usb::driver::EndpointError;
14use embassy_usb::Builder; 15use embassy_usb::Builder;
15use embassy_usb_serial::{CdcAcmClass, State};
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/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index 05945f6bf..9ebab6476 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -11,9 +11,6 @@ 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"] }
18embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
19usbd-hid = "0.6.0" 16usbd-hid = "0.6.0"
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index c96a83ead..4f36d3f5a 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -15,8 +15,8 @@ use embassy_stm32::usb::Driver;
15use embassy_stm32::{interrupt, Config}; 15use embassy_stm32::{interrupt, Config};
16use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 16use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
17use embassy_sync::channel::Channel; 17use embassy_sync::channel::Channel;
18use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State};
18use embassy_usb::{Builder, UsbDevice}; 19use embassy_usb::{Builder, UsbDevice};
19use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
20use embedded_io::asynch::Write; 20use embedded_io::asynch::Write;
21use rand_core::RngCore; 21use rand_core::RngCore;
22use 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 fa92ceae3..d38ed7496 100644
--- a/examples/stm32l5/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs
@@ -9,9 +9,9 @@ use 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 usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; 15use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
17 17
@@ -55,7 +55,7 @@ async fn main(_spawner: Spawner) {
55 ); 55 );
56 56
57 // Create classes on the builder. 57 // Create classes on the builder.
58 let config = embassy_usb_hid::Config { 58 let config = embassy_usb::class::hid::Config {
59 report_descriptor: MouseReport::desc(), 59 report_descriptor: MouseReport::desc(),
60 request_handler: Some(&request_handler), 60 request_handler: Some(&request_handler),
61 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 7484dc832..7562a4e96 100644
--- a/examples/stm32l5/src/bin/usb_serial.rs
+++ b/examples/stm32l5/src/bin/usb_serial.rs
@@ -8,9 +8,9 @@ use embassy_futures::join::join;
8use embassy_stm32::rcc::*; 8use embassy_stm32::rcc::*;
9use embassy_stm32::usb::{Driver, Instance}; 9use embassy_stm32::usb::{Driver, Instance};
10use embassy_stm32::{interrupt, Config}; 10use embassy_stm32::{interrupt, Config};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError; 12use embassy_usb::driver::EndpointError;
12use embassy_usb::Builder; 13use embassy_usb::Builder;
13use embassy_usb_serial::{CdcAcmClass, State};
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/subghz.rs b/examples/stm32wl/src/bin/subghz.rs
index 3c60a8de4..32c8b5515 100644
--- a/examples/stm32wl/src/bin/subghz.rs
+++ b/examples/stm32wl/src/bin/subghz.rs
@@ -12,6 +12,7 @@ use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
12use embassy_stm32::interrupt; 12use embassy_stm32::interrupt;
13use embassy_stm32::interrupt::{Interrupt, InterruptExt}; 13use embassy_stm32::interrupt::{Interrupt, InterruptExt};
14use embassy_stm32::subghz::*; 14use embassy_stm32::subghz::*;
15use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
15use embassy_sync::signal::Signal; 16use embassy_sync::signal::Signal;
16use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
17 18
@@ -64,7 +65,7 @@ async fn main(_spawner: Spawner) {
64 let button = Input::new(p.PA0, Pull::Up); 65 let button = Input::new(p.PA0, Pull::Up);
65 let mut pin = ExtiInput::new(button, p.EXTI0); 66 let mut pin = ExtiInput::new(button, p.EXTI0);
66 67
67 static IRQ_SIGNAL: Signal<()> = Signal::new(); 68 static IRQ_SIGNAL: Signal<CriticalSectionRawMutex, ()> = Signal::new();
68 let radio_irq = interrupt::take!(SUBGHZ_RADIO); 69 let radio_irq = interrupt::take!(SUBGHZ_RADIO);
69 radio_irq.set_handler(|_| { 70 radio_irq.set_handler(|_| {
70 IRQ_SIGNAL.signal(()); 71 IRQ_SIGNAL.signal(());
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 11ecb9169..503373759 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -7,7 +7,7 @@ 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" } 11embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
12 12
13defmt = "0.3.0" 13defmt = "0.3.0"
@@ -20,6 +20,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" }
20embedded-hal-async = { version = "0.1.0-alpha.1" } 20embedded-hal-async = { version = "0.1.0-alpha.1" }
21panic-probe = { version = "0.3.0", features = ["print-defmt"] } 21panic-probe = { version = "0.3.0", features = ["print-defmt"] }
22futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 22futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
23embedded-io = { version = "0.3.0", features = ["async"] }
23 24
24[profile.dev] 25[profile.dev]
25debug = 2 26debug = 2
diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs
new file mode 100644
index 000000000..9cc20bb98
--- /dev/null
+++ b/tests/rp/src/bin/uart_buffered.rs
@@ -0,0 +1,44 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{assert_eq, *};
6use embassy_executor::Spawner;
7use embassy_rp::interrupt;
8use embassy_rp::uart::{BufferedUart, Config, State, Uart};
9use embedded_io::asynch::{Read, Write};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let p = embassy_rp::init(Default::default());
15 info!("Hello World!");
16
17 let (tx, rx, uart) = (p.PIN_0, p.PIN_1, p.UART0);
18
19 let config = Config::default();
20 let uart = Uart::new_blocking(uart, tx, rx, config);
21
22 let irq = interrupt::take!(UART0_IRQ);
23 let tx_buf = &mut [0u8; 16];
24 let rx_buf = &mut [0u8; 16];
25 let mut state = State::new();
26 let mut uart = BufferedUart::new(&mut state, uart, irq, tx_buf, rx_buf);
27
28 // Make sure we send more bytes than fits in the FIFO, to test the actual
29 // bufferedUart.
30
31 let data = [
32 1_u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
33 30, 31, 32,
34 ];
35 uart.write_all(&data).await.unwrap();
36 info!("Done writing");
37
38 let mut buf = [0; 32];
39 uart.read_exact(&mut buf).await.unwrap();
40 assert_eq!(buf, data);
41
42 info!("Test OK");
43 cortex_m::asm::bkpt();
44}