diff options
| author | xoviat <[email protected]> | 2023-08-22 16:58:43 -0500 |
|---|---|---|
| committer | xoviat <[email protected]> | 2023-08-22 16:58:43 -0500 |
| commit | 7d6edd7b15d2209ac0b96ff8814ecefce2964e36 (patch) | |
| tree | 7988a9b46855ac187a92cbfc5f38cbbbff695e8d | |
| parent | 9e3266b74554ea397bdd963ff12a26aa51e77b63 (diff) | |
| parent | 7bff2ebab3b36cc922505e9db961840109c509ed (diff) | |
Merge branch 'main' of https://github.com/embassy-rs/embassy into rtc-lp
145 files changed, 3930 insertions, 1273 deletions
diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh index 06c6fa00b..57184dc1d 100755 --- a/.github/ci/doc.sh +++ b/.github/ci/doc.sh | |||
| @@ -15,7 +15,6 @@ export BUILDER_COMPRESS=true | |||
| 15 | # which makes rustup very sad | 15 | # which makes rustup very sad |
| 16 | rustc --version > /dev/null | 16 | rustc --version > /dev/null |
| 17 | 17 | ||
| 18 | docserver-builder -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup | ||
| 19 | docserver-builder -i ./embassy-boot/boot -o webroot/crates/embassy-boot/git.zup | 18 | docserver-builder -i ./embassy-boot/boot -o webroot/crates/embassy-boot/git.zup |
| 20 | docserver-builder -i ./embassy-boot/nrf -o webroot/crates/embassy-boot-nrf/git.zup | 19 | docserver-builder -i ./embassy-boot/nrf -o webroot/crates/embassy-boot-nrf/git.zup |
| 21 | docserver-builder -i ./embassy-boot/rp -o webroot/crates/embassy-boot-rp/git.zup | 20 | docserver-builder -i ./embassy-boot/rp -o webroot/crates/embassy-boot-rp/git.zup |
| @@ -36,11 +35,20 @@ docserver-builder -i ./embassy-usb-driver -o webroot/crates/embassy-usb-driver/g | |||
| 36 | docserver-builder -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/git.zup | 35 | docserver-builder -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/git.zup |
| 37 | docserver-builder -i ./cyw43 -o webroot/crates/cyw43/git.zup | 36 | docserver-builder -i ./cyw43 -o webroot/crates/cyw43/git.zup |
| 38 | docserver-builder -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup | 37 | docserver-builder -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup |
| 39 | docserver-builder -i ./embassy-net-w5500 -o webroot/crates/embassy-net-w5500/git.zup | 38 | docserver-builder -i ./embassy-net-wiznet -o webroot/crates/embassy-net-wiznet/git.zup |
| 39 | docserver-builder -i ./embassy-net-enc28j60 -o webroot/crates/embassy-net-enc28j60/git.zup | ||
| 40 | docserver-builder -i ./embassy-net-esp-hosted -o webroot/crates/embassy-net-esp-hosted/git.zup | 40 | docserver-builder -i ./embassy-net-esp-hosted -o webroot/crates/embassy-net-esp-hosted/git.zup |
| 41 | docserver-builder -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static | 41 | docserver-builder -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static |
| 42 | 42 | ||
| 43 | export KUBECONFIG=/ci/secrets/kubeconfig.yml | 43 | export KUBECONFIG=/ci/secrets/kubeconfig.yml |
| 44 | POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) | 44 | POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) |
| 45 | kubectl cp webroot/crates $POD:/data | 45 | kubectl cp webroot/crates $POD:/data |
| 46 | kubectl cp webroot/static $POD:/data \ No newline at end of file | 46 | kubectl cp webroot/static $POD:/data |
| 47 | |||
| 48 | # build and upload stm32 last | ||
| 49 | # so that it doesn't prevent other crates from getting docs updates when it breaks. | ||
| 50 | rm -rf webroot | ||
| 51 | docserver-builder -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup | ||
| 52 | |||
| 53 | POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) | ||
| 54 | kubectl cp webroot/crates $POD:/data | ||
diff --git a/.vscode/settings.json b/.vscode/settings.json index 29e8812e3..d48f7ba1e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json | |||
| @@ -6,16 +6,21 @@ | |||
| 6 | "rust-analyzer.check.allTargets": false, | 6 | "rust-analyzer.check.allTargets": false, |
| 7 | "rust-analyzer.check.noDefaultFeatures": true, | 7 | "rust-analyzer.check.noDefaultFeatures": true, |
| 8 | "rust-analyzer.cargo.noDefaultFeatures": true, | 8 | "rust-analyzer.cargo.noDefaultFeatures": true, |
| 9 | "rust-analyzer.cargo.target": "thumbv7m-none-eabi", | 9 | "rust-analyzer.showUnlinkedFileNotification": false, |
| 10 | // uncomment the target of your chip. | ||
| 11 | //"rust-analyzer.cargo.target": "thumbv6m-none-eabi", | ||
| 12 | //"rust-analyzer.cargo.target": "thumbv7m-none-eabi", | ||
| 13 | "rust-analyzer.cargo.target": "thumbv7em-none-eabi", | ||
| 10 | //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", | 14 | //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", |
| 11 | "rust-analyzer.cargo.features": [ | 15 | "rust-analyzer.cargo.features": [ |
| 12 | ///"nightly", | 16 | // Uncomment if the example has a "nightly" feature. |
| 17 | "nightly", | ||
| 13 | ], | 18 | ], |
| 14 | "rust-analyzer.linkedProjects": [ | 19 | "rust-analyzer.linkedProjects": [ |
| 15 | // Declare for the target you wish to develop | 20 | // Uncomment ONE line for the chip you want to work on. |
| 16 | // "embassy-executor/Cargo.toml", | 21 | // This makes rust-analyzer work on the example crate and all its dependencies. |
| 17 | // "embassy-sync/Cargo.toml", | 22 | "examples/nrf52840/Cargo.toml", |
| 18 | "examples/stm32wl/Cargo.toml", | 23 | // "examples/nrf52840-rtic/Cargo.toml", |
| 19 | // "examples/nrf5340/Cargo.toml", | 24 | // "examples/nrf5340/Cargo.toml", |
| 20 | // "examples/nrf-rtos-trace/Cargo.toml", | 25 | // "examples/nrf-rtos-trace/Cargo.toml", |
| 21 | // "examples/rp/Cargo.toml", | 26 | // "examples/rp/Cargo.toml", |
| @@ -3,7 +3,7 @@ | |||
| 3 | set -euo pipefail | 3 | set -euo pipefail |
| 4 | 4 | ||
| 5 | export RUSTFLAGS=-Dwarnings | 5 | export RUSTFLAGS=-Dwarnings |
| 6 | export DEFMT_LOG=trace,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info | 6 | export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info |
| 7 | 7 | ||
| 8 | TARGET=$(rustc -vV | sed -n 's|host: ||p') | 8 | TARGET=$(rustc -vV | sed -n 's|host: ||p') |
| 9 | 9 | ||
| @@ -81,6 +81,7 @@ cargo batch \ | |||
| 81 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \ | 81 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \ |
| 82 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \ | 82 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \ |
| 83 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits \ | 83 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits \ |
| 84 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f378cc,defmt,exti,time-driver-any,unstable-traits \ | ||
| 84 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits \ | 85 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits \ |
| 85 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,unstable-traits \ | 86 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,unstable-traits \ |
| 86 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,unstable-traits \ | 87 | --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,unstable-traits \ |
diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 50fb7c5db..855d54b11 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml | |||
| @@ -24,7 +24,7 @@ cortex-m = "0.7.6" | |||
| 24 | cortex-m-rt = "0.7.0" | 24 | cortex-m-rt = "0.7.0" |
| 25 | futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } | 25 | futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } |
| 26 | 26 | ||
| 27 | embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.11" } | 27 | embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-rc.1" } |
| 28 | num_enum = { version = "0.5.7", default-features = false } | 28 | num_enum = { version = "0.5.7", default-features = false } |
| 29 | 29 | ||
| 30 | [package.metadata.embassy_docs] | 30 | [package.metadata.embassy_docs] |
diff --git a/cyw43/src/bus.rs b/cyw43/src/bus.rs index e26f11120..0b5632cf8 100644 --- a/cyw43/src/bus.rs +++ b/cyw43/src/bus.rs | |||
| @@ -102,7 +102,7 @@ where | |||
| 102 | cmd_buf[0] = cmd; | 102 | cmd_buf[0] = cmd; |
| 103 | cmd_buf[1..][..buf.len()].copy_from_slice(buf); | 103 | cmd_buf[1..][..buf.len()].copy_from_slice(buf); |
| 104 | 104 | ||
| 105 | self.status = self.spi.cmd_write(&cmd_buf).await; | 105 | self.status = self.spi.cmd_write(&cmd_buf[..buf.len() + 1]).await; |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | #[allow(unused)] | 108 | #[allow(unused)] |
diff --git a/embassy-boot/nrf/src/lib.rs b/embassy-boot/nrf/src/lib.rs index df94819fc..b9d86eb17 100644 --- a/embassy-boot/nrf/src/lib.rs +++ b/embassy-boot/nrf/src/lib.rs | |||
| @@ -14,28 +14,17 @@ use embassy_nrf::wdt; | |||
| 14 | use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; | 14 | use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; |
| 15 | 15 | ||
| 16 | /// A bootloader for nRF devices. | 16 | /// A bootloader for nRF devices. |
| 17 | pub struct BootLoader<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize = PAGE_SIZE> { | 17 | pub struct BootLoader<const BUFFER_SIZE: usize = PAGE_SIZE>; |
| 18 | boot: embassy_boot::BootLoader<ACTIVE, DFU, STATE>, | 18 | |
| 19 | aligned_buf: AlignedBuffer<BUFFER_SIZE>, | 19 | impl<const BUFFER_SIZE: usize> BootLoader<BUFFER_SIZE> { |
| 20 | } | 20 | /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware. |
| 21 | 21 | pub fn prepare<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash>( | |
| 22 | impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize> | 22 | config: BootLoaderConfig<ACTIVE, DFU, STATE>, |
| 23 | BootLoader<ACTIVE, DFU, STATE, BUFFER_SIZE> | 23 | ) -> Self { |
| 24 | { | 24 | let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]); |
| 25 | /// Create a new bootloader instance using the supplied partitions for active, dfu and state. | 25 | let mut boot = embassy_boot::BootLoader::new(config); |
| 26 | pub fn new(config: BootLoaderConfig<ACTIVE, DFU, STATE>) -> Self { | 26 | boot.prepare_boot(&mut aligned_buf.0).expect("Boot prepare error"); |
| 27 | Self { | 27 | Self |
| 28 | boot: embassy_boot::BootLoader::new(config), | ||
| 29 | aligned_buf: AlignedBuffer([0; BUFFER_SIZE]), | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | /// Inspect the bootloader state and perform actions required before booting, such as swapping | ||
| 34 | /// firmware. | ||
| 35 | pub fn prepare(&mut self) { | ||
| 36 | self.boot | ||
| 37 | .prepare_boot(&mut self.aligned_buf.0) | ||
| 38 | .expect("Boot prepare error"); | ||
| 39 | } | 28 | } |
| 40 | 29 | ||
| 41 | /// Boots the application without softdevice mechanisms. | 30 | /// Boots the application without softdevice mechanisms. |
| @@ -45,8 +34,6 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize> | |||
| 45 | /// This modifies the stack pointer and reset vector and will run code placed in the active partition. | 34 | /// This modifies the stack pointer and reset vector and will run code placed in the active partition. |
| 46 | #[cfg(not(feature = "softdevice"))] | 35 | #[cfg(not(feature = "softdevice"))] |
| 47 | pub unsafe fn load(self, start: u32) -> ! { | 36 | pub unsafe fn load(self, start: u32) -> ! { |
| 48 | core::mem::drop(self.boot); | ||
| 49 | |||
| 50 | let mut p = cortex_m::Peripherals::steal(); | 37 | let mut p = cortex_m::Peripherals::steal(); |
| 51 | p.SCB.invalidate_icache(); | 38 | p.SCB.invalidate_icache(); |
| 52 | p.SCB.vtor.write(start); | 39 | p.SCB.vtor.write(start); |
| @@ -59,7 +46,7 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize> | |||
| 59 | /// | 46 | /// |
| 60 | /// This modifies the stack pointer and reset vector and will run code placed in the active partition. | 47 | /// This modifies the stack pointer and reset vector and will run code placed in the active partition. |
| 61 | #[cfg(feature = "softdevice")] | 48 | #[cfg(feature = "softdevice")] |
| 62 | pub unsafe fn load(&mut self, _app: u32) -> ! { | 49 | pub unsafe fn load(self, _app: u32) -> ! { |
| 63 | use nrf_softdevice_mbr as mbr; | 50 | use nrf_softdevice_mbr as mbr; |
| 64 | const NRF_SUCCESS: u32 = 0; | 51 | const NRF_SUCCESS: u32 = 0; |
| 65 | 52 | ||
diff --git a/embassy-boot/rp/src/lib.rs b/embassy-boot/rp/src/lib.rs index f5aefa416..989e7521b 100644 --- a/embassy-boot/rp/src/lib.rs +++ b/embassy-boot/rp/src/lib.rs | |||
| @@ -15,28 +15,17 @@ use embassy_time::Duration; | |||
| 15 | use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; | 15 | use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; |
| 16 | 16 | ||
| 17 | /// A bootloader for RP2040 devices. | 17 | /// A bootloader for RP2040 devices. |
| 18 | pub struct BootLoader<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize = ERASE_SIZE> { | 18 | pub struct BootLoader<const BUFFER_SIZE: usize = ERASE_SIZE>; |
| 19 | boot: embassy_boot::BootLoader<ACTIVE, DFU, STATE>, | ||
| 20 | aligned_buf: AlignedBuffer<BUFFER_SIZE>, | ||
| 21 | } | ||
| 22 | |||
| 23 | impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize> | ||
| 24 | BootLoader<ACTIVE, DFU, STATE, BUFFER_SIZE> | ||
| 25 | { | ||
| 26 | /// Create a new bootloader instance using the supplied partitions for active, dfu and state. | ||
| 27 | pub fn new(config: BootLoaderConfig<ACTIVE, DFU, STATE>) -> Self { | ||
| 28 | Self { | ||
| 29 | boot: embassy_boot::BootLoader::new(config), | ||
| 30 | aligned_buf: AlignedBuffer([0; BUFFER_SIZE]), | ||
| 31 | } | ||
| 32 | } | ||
| 33 | 19 | ||
| 34 | /// Inspect the bootloader state and perform actions required before booting, such as swapping | 20 | impl<const BUFFER_SIZE: usize> BootLoader<BUFFER_SIZE> { |
| 35 | /// firmware. | 21 | /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware |
| 36 | pub fn prepare(&mut self) { | 22 | pub fn prepare<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash>( |
| 37 | self.boot | 23 | config: BootLoaderConfig<ACTIVE, DFU, STATE>, |
| 38 | .prepare_boot(self.aligned_buf.as_mut()) | 24 | ) -> Self { |
| 39 | .expect("Boot prepare error"); | 25 | let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]); |
| 26 | let mut boot = embassy_boot::BootLoader::new(config); | ||
| 27 | boot.prepare_boot(aligned_buf.as_mut()).expect("Boot prepare error"); | ||
| 28 | Self | ||
| 40 | } | 29 | } |
| 41 | 30 | ||
| 42 | /// Boots the application. | 31 | /// Boots the application. |
| @@ -45,8 +34,6 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize> | |||
| 45 | /// | 34 | /// |
| 46 | /// This modifies the stack pointer and reset vector and will run code placed in the active partition. | 35 | /// This modifies the stack pointer and reset vector and will run code placed in the active partition. |
| 47 | pub unsafe fn load(self, start: u32) -> ! { | 36 | pub unsafe fn load(self, start: u32) -> ! { |
| 48 | core::mem::drop(self.boot); | ||
| 49 | |||
| 50 | trace!("Loading app at 0x{:x}", start); | 37 | trace!("Loading app at 0x{:x}", start); |
| 51 | #[allow(unused_mut)] | 38 | #[allow(unused_mut)] |
| 52 | let mut p = cortex_m::Peripherals::steal(); | 39 | let mut p = cortex_m::Peripherals::steal(); |
| @@ -67,7 +54,7 @@ pub struct WatchdogFlash<'d, const SIZE: usize> { | |||
| 67 | impl<'d, const SIZE: usize> WatchdogFlash<'d, SIZE> { | 54 | impl<'d, const SIZE: usize> WatchdogFlash<'d, SIZE> { |
| 68 | /// Start a new watchdog with a given flash and watchdog peripheral and a timeout | 55 | /// Start a new watchdog with a given flash and watchdog peripheral and a timeout |
| 69 | pub fn start(flash: FLASH, watchdog: WATCHDOG, timeout: Duration) -> Self { | 56 | pub fn start(flash: FLASH, watchdog: WATCHDOG, timeout: Duration) -> Self { |
| 70 | let flash = Flash::<_, Blocking, SIZE>::new(flash); | 57 | let flash = Flash::<_, Blocking, SIZE>::new_blocking(flash); |
| 71 | let mut watchdog = Watchdog::new(watchdog); | 58 | let mut watchdog = Watchdog::new(watchdog); |
| 72 | watchdog.start(timeout); | 59 | watchdog.start(timeout); |
| 73 | Self { flash, watchdog } | 60 | Self { flash, watchdog } |
| @@ -84,11 +71,11 @@ impl<'d, const SIZE: usize> NorFlash for WatchdogFlash<'d, SIZE> { | |||
| 84 | 71 | ||
| 85 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | 72 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { |
| 86 | self.watchdog.feed(); | 73 | self.watchdog.feed(); |
| 87 | self.flash.erase(from, to) | 74 | self.flash.blocking_erase(from, to) |
| 88 | } | 75 | } |
| 89 | fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> { | 76 | fn write(&mut self, offset: u32, data: &[u8]) -> Result<(), Self::Error> { |
| 90 | self.watchdog.feed(); | 77 | self.watchdog.feed(); |
| 91 | self.flash.write(offset, data) | 78 | self.flash.blocking_write(offset, data) |
| 92 | } | 79 | } |
| 93 | } | 80 | } |
| 94 | 81 | ||
| @@ -96,7 +83,7 @@ impl<'d, const SIZE: usize> ReadNorFlash for WatchdogFlash<'d, SIZE> { | |||
| 96 | const READ_SIZE: usize = <Flash<'d, FLASH, Blocking, SIZE> as ReadNorFlash>::READ_SIZE; | 83 | const READ_SIZE: usize = <Flash<'d, FLASH, Blocking, SIZE> as ReadNorFlash>::READ_SIZE; |
| 97 | fn read(&mut self, offset: u32, data: &mut [u8]) -> Result<(), Self::Error> { | 84 | fn read(&mut self, offset: u32, data: &mut [u8]) -> Result<(), Self::Error> { |
| 98 | self.watchdog.feed(); | 85 | self.watchdog.feed(); |
| 99 | self.flash.read(offset, data) | 86 | self.flash.blocking_read(offset, data) |
| 100 | } | 87 | } |
| 101 | fn capacity(&self) -> usize { | 88 | fn capacity(&self) -> usize { |
| 102 | self.flash.capacity() | 89 | self.flash.capacity() |
diff --git a/embassy-boot/stm32/src/lib.rs b/embassy-boot/stm32/src/lib.rs index 25f029423..c6350c495 100644 --- a/embassy-boot/stm32/src/lib.rs +++ b/embassy-boot/stm32/src/lib.rs | |||
| @@ -11,28 +11,17 @@ pub use embassy_boot::{FirmwareState, FirmwareUpdater}; | |||
| 11 | use embedded_storage::nor_flash::NorFlash; | 11 | use embedded_storage::nor_flash::NorFlash; |
| 12 | 12 | ||
| 13 | /// A bootloader for STM32 devices. | 13 | /// A bootloader for STM32 devices. |
| 14 | pub struct BootLoader<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize> { | 14 | pub struct BootLoader; |
| 15 | boot: embassy_boot::BootLoader<ACTIVE, DFU, STATE>, | ||
| 16 | aligned_buf: AlignedBuffer<BUFFER_SIZE>, | ||
| 17 | } | ||
| 18 | |||
| 19 | impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize> | ||
| 20 | BootLoader<ACTIVE, DFU, STATE, BUFFER_SIZE> | ||
| 21 | { | ||
| 22 | /// Create a new bootloader instance using the supplied partitions for active, dfu and state. | ||
| 23 | pub fn new(config: BootLoaderConfig<ACTIVE, DFU, STATE>) -> Self { | ||
| 24 | Self { | ||
| 25 | boot: embassy_boot::BootLoader::new(config), | ||
| 26 | aligned_buf: AlignedBuffer([0; BUFFER_SIZE]), | ||
| 27 | } | ||
| 28 | } | ||
| 29 | 15 | ||
| 30 | /// Inspect the bootloader state and perform actions required before booting, such as swapping | 16 | impl BootLoader { |
| 31 | /// firmware. | 17 | /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware |
| 32 | pub fn prepare(&mut self) { | 18 | pub fn prepare<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize>( |
| 33 | self.boot | 19 | config: BootLoaderConfig<ACTIVE, DFU, STATE>, |
| 34 | .prepare_boot(self.aligned_buf.as_mut()) | 20 | ) -> Self { |
| 35 | .expect("Boot prepare error"); | 21 | let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]); |
| 22 | let mut boot = embassy_boot::BootLoader::new(config); | ||
| 23 | boot.prepare_boot(aligned_buf.as_mut()).expect("Boot prepare error"); | ||
| 24 | Self | ||
| 36 | } | 25 | } |
| 37 | 26 | ||
| 38 | /// Boots the application. | 27 | /// Boots the application. |
| @@ -41,8 +30,6 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash, const BUFFER_SIZE: usize> | |||
| 41 | /// | 30 | /// |
| 42 | /// This modifies the stack pointer and reset vector and will run code placed in the active partition. | 31 | /// This modifies the stack pointer and reset vector and will run code placed in the active partition. |
| 43 | pub unsafe fn load(self, start: u32) -> ! { | 32 | pub unsafe fn load(self, start: u32) -> ! { |
| 44 | core::mem::drop(self.boot); | ||
| 45 | |||
| 46 | trace!("Loading app at 0x{:x}", start); | 33 | trace!("Loading app at 0x{:x}", start); |
| 47 | #[allow(unused_mut)] | 34 | #[allow(unused_mut)] |
| 48 | let mut p = cortex_m::Peripherals::steal(); | 35 | let mut p = cortex_m::Peripherals::steal(); |
diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index bba3d48be..fd921d277 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml | |||
| @@ -25,8 +25,8 @@ embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true } | |||
| 25 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ | 25 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ |
| 26 | "unproven", | 26 | "unproven", |
| 27 | ] } | 27 | ] } |
| 28 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" } | 28 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } |
| 29 | embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true } | 29 | embedded-hal-async = { version = "=1.0.0-rc.1", optional = true } |
| 30 | embedded-storage = "0.3.0" | 30 | embedded-storage = "0.3.0" |
| 31 | embedded-storage-async = { version = "0.4.0", optional = true } | 31 | embedded-storage-async = { version = "0.4.0", optional = true } |
| 32 | nb = "1.0.0" | 32 | nb = "1.0.0" |
diff --git a/embassy-embedded-hal/src/adapter/blocking_async.rs b/embassy-embedded-hal/src/adapter/blocking_async.rs index 98ae2b02c..ae0d0a7f9 100644 --- a/embassy-embedded-hal/src/adapter/blocking_async.rs +++ b/embassy-embedded-hal/src/adapter/blocking_async.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | use embedded_hal_02::{blocking, serial}; | 1 | use embedded_hal_02::blocking; |
| 2 | 2 | ||
| 3 | /// Wrapper that implements async traits using blocking implementations. | 3 | /// Wrapper that implements async traits using blocking implementations. |
| 4 | /// | 4 | /// |
| @@ -103,15 +103,6 @@ where | |||
| 103 | } | 103 | } |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | // Uart implementatinos | ||
| 107 | impl<T, E> embedded_hal_1::serial::ErrorType for BlockingAsync<T> | ||
| 108 | where | ||
| 109 | T: serial::Read<u8, Error = E>, | ||
| 110 | E: embedded_hal_1::serial::Error + 'static, | ||
| 111 | { | ||
| 112 | type Error = E; | ||
| 113 | } | ||
| 114 | |||
| 115 | /// NOR flash wrapper | 106 | /// NOR flash wrapper |
| 116 | use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; | 107 | use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; |
| 117 | use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash}; | 108 | use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash}; |
diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index 4fd3dccf7..43d94e540 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md | |||
| @@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file. | |||
| 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), |
| 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). |
| 7 | 7 | ||
| 8 | ## Unreleased | ||
| 9 | |||
| 10 | - Replaced Pender. Implementations now must define an extern function called `__pender`. | ||
| 11 | - Made `raw::AvailableTask` public | ||
| 12 | - Made `SpawnToken::new_failed` public | ||
| 13 | |||
| 14 | ## 0.2.1 - 2023-08-10 | ||
| 15 | |||
| 16 | - Avoid calling `pend()` when waking expired timers | ||
| 17 | - Properly reset finished task state with `integrated-timers` enabled | ||
| 18 | - Introduce `InterruptExecutor::spawner()` | ||
| 19 | - Fix incorrect critical section in Xtensa executor | ||
| 20 | |||
| 8 | ## 0.2.0 - 2023-04-27 | 21 | ## 0.2.0 - 2023-04-27 |
| 9 | 22 | ||
| 10 | - Replace unnecessary atomics in runqueue | 23 | - Replace unnecessary atomics in runqueue |
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 590718e3e..d190c95a3 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | [package] | 1 | [package] |
| 2 | name = "embassy-executor" | 2 | name = "embassy-executor" |
| 3 | version = "0.2.0" | 3 | version = "0.2.1" |
| 4 | edition = "2021" | 4 | edition = "2021" |
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | description = "async/await executor designed for embedded usage" | 6 | description = "async/await executor designed for embedded usage" |
| @@ -14,7 +14,7 @@ categories = [ | |||
| 14 | [package.metadata.embassy_docs] | 14 | [package.metadata.embassy_docs] |
| 15 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/" | 15 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/" |
| 16 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/" | 16 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/" |
| 17 | features = ["nightly", "defmt", "pender-callback"] | 17 | features = ["nightly", "defmt"] |
| 18 | flavors = [ | 18 | flavors = [ |
| 19 | { name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] }, | 19 | { name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] }, |
| 20 | { name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] }, | 20 | { name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] }, |
| @@ -25,7 +25,7 @@ flavors = [ | |||
| 25 | [package.metadata.docs.rs] | 25 | [package.metadata.docs.rs] |
| 26 | default-target = "thumbv7em-none-eabi" | 26 | default-target = "thumbv7em-none-eabi" |
| 27 | targets = ["thumbv7em-none-eabi"] | 27 | targets = ["thumbv7em-none-eabi"] |
| 28 | features = ["nightly", "defmt", "pender-callback", "arch-cortex-m", "executor-thread", "executor-interrupt"] | 28 | features = ["nightly", "defmt", "arch-cortex-m", "executor-thread", "executor-interrupt"] |
| 29 | 29 | ||
| 30 | [features] | 30 | [features] |
| 31 | 31 | ||
| @@ -37,9 +37,6 @@ arch-xtensa = ["_arch"] | |||
| 37 | arch-riscv32 = ["_arch"] | 37 | arch-riscv32 = ["_arch"] |
| 38 | arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"] | 38 | arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"] |
| 39 | 39 | ||
| 40 | # Enable creating a `Pender` from an arbitrary function pointer callback. | ||
| 41 | pender-callback = [] | ||
| 42 | |||
| 43 | # Enable the thread-mode executor (using WFE/SEV in Cortex-M, WFI in other embedded archs) | 40 | # Enable the thread-mode executor (using WFE/SEV in Cortex-M, WFI in other embedded archs) |
| 44 | executor-thread = [] | 41 | executor-thread = [] |
| 45 | # Enable the interrupt-mode executor (available in Cortex-M only) | 42 | # Enable the interrupt-mode executor (available in Cortex-M only) |
diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs index 94c8134d6..0806a22ab 100644 --- a/embassy-executor/src/arch/cortex_m.rs +++ b/embassy-executor/src/arch/cortex_m.rs | |||
| @@ -1,3 +1,49 @@ | |||
| 1 | const THREAD_PENDER: usize = usize::MAX; | ||
| 2 | |||
| 3 | #[export_name = "__pender"] | ||
| 4 | #[cfg(any(feature = "executor-thread", feature = "executor-interrupt"))] | ||
| 5 | fn __pender(context: *mut ()) { | ||
| 6 | unsafe { | ||
| 7 | // Safety: `context` is either `usize::MAX` created by `Executor::run`, or a valid interrupt | ||
| 8 | // request number given to `InterruptExecutor::start`. | ||
| 9 | |||
| 10 | let context = context as usize; | ||
| 11 | |||
| 12 | #[cfg(feature = "executor-thread")] | ||
| 13 | // Try to make Rust optimize the branching away if we only use thread mode. | ||
| 14 | if !cfg!(feature = "executor-interrupt") || context == THREAD_PENDER { | ||
| 15 | core::arch::asm!("sev"); | ||
| 16 | return; | ||
| 17 | } | ||
| 18 | |||
| 19 | #[cfg(feature = "executor-interrupt")] | ||
| 20 | { | ||
| 21 | use cortex_m::interrupt::InterruptNumber; | ||
| 22 | use cortex_m::peripheral::NVIC; | ||
| 23 | |||
| 24 | #[derive(Clone, Copy)] | ||
| 25 | struct Irq(u16); | ||
| 26 | unsafe impl InterruptNumber for Irq { | ||
| 27 | fn number(self) -> u16 { | ||
| 28 | self.0 | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | let irq = Irq(context as u16); | ||
| 33 | |||
| 34 | // STIR is faster, but is only available in v7 and higher. | ||
| 35 | #[cfg(not(armv6m))] | ||
| 36 | { | ||
| 37 | let mut nvic: NVIC = core::mem::transmute(()); | ||
| 38 | nvic.request(irq); | ||
| 39 | } | ||
| 40 | |||
| 41 | #[cfg(armv6m)] | ||
| 42 | NVIC::pend(irq); | ||
| 43 | } | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 1 | #[cfg(feature = "executor-thread")] | 47 | #[cfg(feature = "executor-thread")] |
| 2 | pub use thread::*; | 48 | pub use thread::*; |
| 3 | #[cfg(feature = "executor-thread")] | 49 | #[cfg(feature = "executor-thread")] |
| @@ -8,18 +54,9 @@ mod thread { | |||
| 8 | #[cfg(feature = "nightly")] | 54 | #[cfg(feature = "nightly")] |
| 9 | pub use embassy_macros::main_cortex_m as main; | 55 | pub use embassy_macros::main_cortex_m as main; |
| 10 | 56 | ||
| 11 | use crate::raw::{Pender, PenderInner}; | 57 | use crate::arch::THREAD_PENDER; |
| 12 | use crate::{raw, Spawner}; | 58 | use crate::{raw, Spawner}; |
| 13 | 59 | ||
| 14 | #[derive(Copy, Clone)] | ||
| 15 | pub(crate) struct ThreadPender; | ||
| 16 | |||
| 17 | impl ThreadPender { | ||
| 18 | pub(crate) fn pend(self) { | ||
| 19 | unsafe { core::arch::asm!("sev") } | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | /// Thread mode executor, using WFE/SEV. | 60 | /// Thread mode executor, using WFE/SEV. |
| 24 | /// | 61 | /// |
| 25 | /// This is the simplest and most common kind of executor. It runs on | 62 | /// This is the simplest and most common kind of executor. It runs on |
| @@ -39,7 +76,7 @@ mod thread { | |||
| 39 | /// Create a new Executor. | 76 | /// Create a new Executor. |
| 40 | pub fn new() -> Self { | 77 | pub fn new() -> Self { |
| 41 | Self { | 78 | Self { |
| 42 | inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender))), | 79 | inner: raw::Executor::new(THREAD_PENDER as *mut ()), |
| 43 | not_send: PhantomData, | 80 | not_send: PhantomData, |
| 44 | } | 81 | } |
| 45 | } | 82 | } |
| @@ -86,30 +123,7 @@ mod interrupt { | |||
| 86 | use cortex_m::interrupt::InterruptNumber; | 123 | use cortex_m::interrupt::InterruptNumber; |
| 87 | use cortex_m::peripheral::NVIC; | 124 | use cortex_m::peripheral::NVIC; |
| 88 | 125 | ||
| 89 | use crate::raw::{self, Pender, PenderInner}; | 126 | use crate::raw; |
| 90 | |||
| 91 | #[derive(Clone, Copy)] | ||
| 92 | pub(crate) struct InterruptPender(u16); | ||
| 93 | |||
| 94 | impl InterruptPender { | ||
| 95 | pub(crate) fn pend(self) { | ||
| 96 | // STIR is faster, but is only available in v7 and higher. | ||
| 97 | #[cfg(not(armv6m))] | ||
| 98 | { | ||
| 99 | let mut nvic: cortex_m::peripheral::NVIC = unsafe { core::mem::transmute(()) }; | ||
| 100 | nvic.request(self); | ||
| 101 | } | ||
| 102 | |||
| 103 | #[cfg(armv6m)] | ||
| 104 | cortex_m::peripheral::NVIC::pend(self); | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | unsafe impl cortex_m::interrupt::InterruptNumber for InterruptPender { | ||
| 109 | fn number(self) -> u16 { | ||
| 110 | self.0 | ||
| 111 | } | ||
| 112 | } | ||
| 113 | 127 | ||
| 114 | /// Interrupt mode executor. | 128 | /// Interrupt mode executor. |
| 115 | /// | 129 | /// |
| @@ -194,9 +208,7 @@ mod interrupt { | |||
| 194 | unsafe { | 208 | unsafe { |
| 195 | (&mut *self.executor.get()) | 209 | (&mut *self.executor.get()) |
| 196 | .as_mut_ptr() | 210 | .as_mut_ptr() |
| 197 | .write(raw::Executor::new(Pender(PenderInner::Interrupt(InterruptPender( | 211 | .write(raw::Executor::new(irq.number() as *mut ())) |
| 198 | irq.number(), | ||
| 199 | ))))) | ||
| 200 | } | 212 | } |
| 201 | 213 | ||
| 202 | let executor = unsafe { (&*self.executor.get()).assume_init_ref() }; | 214 | let executor = unsafe { (&*self.executor.get()).assume_init_ref() }; |
diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs index ff7ec1575..40c6877e2 100644 --- a/embassy-executor/src/arch/riscv32.rs +++ b/embassy-executor/src/arch/riscv32.rs | |||
| @@ -11,22 +11,16 @@ mod thread { | |||
| 11 | #[cfg(feature = "nightly")] | 11 | #[cfg(feature = "nightly")] |
| 12 | pub use embassy_macros::main_riscv as main; | 12 | pub use embassy_macros::main_riscv as main; |
| 13 | 13 | ||
| 14 | use crate::raw::{Pender, PenderInner}; | ||
| 15 | use crate::{raw, Spawner}; | 14 | use crate::{raw, Spawner}; |
| 16 | 15 | ||
| 17 | #[derive(Copy, Clone)] | ||
| 18 | pub(crate) struct ThreadPender; | ||
| 19 | |||
| 20 | impl ThreadPender { | ||
| 21 | #[allow(unused)] | ||
| 22 | pub(crate) fn pend(self) { | ||
| 23 | SIGNAL_WORK_THREAD_MODE.store(true, core::sync::atomic::Ordering::SeqCst); | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | /// global atomic used to keep track of whether there is work to do since sev() is not available on RISCV | 16 | /// global atomic used to keep track of whether there is work to do since sev() is not available on RISCV |
| 28 | static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); | 17 | static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); |
| 29 | 18 | ||
| 19 | #[export_name = "__pender"] | ||
| 20 | fn __pender(_context: *mut ()) { | ||
| 21 | SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); | ||
| 22 | } | ||
| 23 | |||
| 30 | /// RISCV32 Executor | 24 | /// RISCV32 Executor |
| 31 | pub struct Executor { | 25 | pub struct Executor { |
| 32 | inner: raw::Executor, | 26 | inner: raw::Executor, |
| @@ -37,7 +31,7 @@ mod thread { | |||
| 37 | /// Create a new Executor. | 31 | /// Create a new Executor. |
| 38 | pub fn new() -> Self { | 32 | pub fn new() -> Self { |
| 39 | Self { | 33 | Self { |
| 40 | inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender))), | 34 | inner: raw::Executor::new(core::ptr::null_mut()), |
| 41 | not_send: PhantomData, | 35 | not_send: PhantomData, |
| 42 | } | 36 | } |
| 43 | } | 37 | } |
diff --git a/embassy-executor/src/arch/std.rs b/embassy-executor/src/arch/std.rs index 4e4a178f0..5b2f7e2e4 100644 --- a/embassy-executor/src/arch/std.rs +++ b/embassy-executor/src/arch/std.rs | |||
| @@ -11,17 +11,12 @@ mod thread { | |||
| 11 | #[cfg(feature = "nightly")] | 11 | #[cfg(feature = "nightly")] |
| 12 | pub use embassy_macros::main_std as main; | 12 | pub use embassy_macros::main_std as main; |
| 13 | 13 | ||
| 14 | use crate::raw::{Pender, PenderInner}; | ||
| 15 | use crate::{raw, Spawner}; | 14 | use crate::{raw, Spawner}; |
| 16 | 15 | ||
| 17 | #[derive(Copy, Clone)] | 16 | #[export_name = "__pender"] |
| 18 | pub(crate) struct ThreadPender(&'static Signaler); | 17 | fn __pender(context: *mut ()) { |
| 19 | 18 | let signaler: &'static Signaler = unsafe { std::mem::transmute(context) }; | |
| 20 | impl ThreadPender { | 19 | signaler.signal() |
| 21 | #[allow(unused)] | ||
| 22 | pub(crate) fn pend(self) { | ||
| 23 | self.0.signal() | ||
| 24 | } | ||
| 25 | } | 20 | } |
| 26 | 21 | ||
| 27 | /// Single-threaded std-based executor. | 22 | /// Single-threaded std-based executor. |
| @@ -34,9 +29,9 @@ mod thread { | |||
| 34 | impl Executor { | 29 | impl Executor { |
| 35 | /// Create a new Executor. | 30 | /// Create a new Executor. |
| 36 | pub fn new() -> Self { | 31 | pub fn new() -> Self { |
| 37 | let signaler = &*Box::leak(Box::new(Signaler::new())); | 32 | let signaler = Box::leak(Box::new(Signaler::new())); |
| 38 | Self { | 33 | Self { |
| 39 | inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender(signaler)))), | 34 | inner: raw::Executor::new(signaler as *mut Signaler as *mut ()), |
| 40 | not_send: PhantomData, | 35 | not_send: PhantomData, |
| 41 | signaler, | 36 | signaler, |
| 42 | } | 37 | } |
diff --git a/embassy-executor/src/arch/wasm.rs b/embassy-executor/src/arch/wasm.rs index 08ab16b99..934fd69e5 100644 --- a/embassy-executor/src/arch/wasm.rs +++ b/embassy-executor/src/arch/wasm.rs | |||
| @@ -14,14 +14,12 @@ mod thread { | |||
| 14 | use wasm_bindgen::prelude::*; | 14 | use wasm_bindgen::prelude::*; |
| 15 | 15 | ||
| 16 | use crate::raw::util::UninitCell; | 16 | use crate::raw::util::UninitCell; |
| 17 | use crate::raw::{Pender, PenderInner}; | ||
| 18 | use crate::{raw, Spawner}; | 17 | use crate::{raw, Spawner}; |
| 19 | 18 | ||
| 20 | /// WASM executor, wasm_bindgen to schedule tasks on the JS event loop. | 19 | #[export_name = "__pender"] |
| 21 | pub struct Executor { | 20 | fn __pender(context: *mut ()) { |
| 22 | inner: raw::Executor, | 21 | let signaler: &'static WasmContext = unsafe { std::mem::transmute(context) }; |
| 23 | ctx: &'static WasmContext, | 22 | let _ = signaler.promise.then(unsafe { signaler.closure.as_mut() }); |
| 24 | not_send: PhantomData<*mut ()>, | ||
| 25 | } | 23 | } |
| 26 | 24 | ||
| 27 | pub(crate) struct WasmContext { | 25 | pub(crate) struct WasmContext { |
| @@ -29,16 +27,6 @@ mod thread { | |||
| 29 | closure: UninitCell<Closure<dyn FnMut(JsValue)>>, | 27 | closure: UninitCell<Closure<dyn FnMut(JsValue)>>, |
| 30 | } | 28 | } |
| 31 | 29 | ||
| 32 | #[derive(Copy, Clone)] | ||
| 33 | pub(crate) struct ThreadPender(&'static WasmContext); | ||
| 34 | |||
| 35 | impl ThreadPender { | ||
| 36 | #[allow(unused)] | ||
| 37 | pub(crate) fn pend(self) { | ||
| 38 | let _ = self.0.promise.then(unsafe { self.0.closure.as_mut() }); | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | impl WasmContext { | 30 | impl WasmContext { |
| 43 | pub fn new() -> Self { | 31 | pub fn new() -> Self { |
| 44 | Self { | 32 | Self { |
| @@ -48,14 +36,21 @@ mod thread { | |||
| 48 | } | 36 | } |
| 49 | } | 37 | } |
| 50 | 38 | ||
| 39 | /// WASM executor, wasm_bindgen to schedule tasks on the JS event loop. | ||
| 40 | pub struct Executor { | ||
| 41 | inner: raw::Executor, | ||
| 42 | ctx: &'static WasmContext, | ||
| 43 | not_send: PhantomData<*mut ()>, | ||
| 44 | } | ||
| 45 | |||
| 51 | impl Executor { | 46 | impl Executor { |
| 52 | /// Create a new Executor. | 47 | /// Create a new Executor. |
| 53 | pub fn new() -> Self { | 48 | pub fn new() -> Self { |
| 54 | let ctx = &*Box::leak(Box::new(WasmContext::new())); | 49 | let ctx = Box::leak(Box::new(WasmContext::new())); |
| 55 | Self { | 50 | Self { |
| 56 | inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender(ctx)))), | 51 | inner: raw::Executor::new(ctx as *mut WasmContext as *mut ()), |
| 57 | not_send: PhantomData, | ||
| 58 | ctx, | 52 | ctx, |
| 53 | not_send: PhantomData, | ||
| 59 | } | 54 | } |
| 60 | } | 55 | } |
| 61 | 56 | ||
diff --git a/embassy-executor/src/arch/xtensa.rs b/embassy-executor/src/arch/xtensa.rs index 017b2c52b..601d85002 100644 --- a/embassy-executor/src/arch/xtensa.rs +++ b/embassy-executor/src/arch/xtensa.rs | |||
| @@ -8,22 +8,16 @@ mod thread { | |||
| 8 | use core::marker::PhantomData; | 8 | use core::marker::PhantomData; |
| 9 | use core::sync::atomic::{AtomicBool, Ordering}; | 9 | use core::sync::atomic::{AtomicBool, Ordering}; |
| 10 | 10 | ||
| 11 | use crate::raw::{Pender, PenderInner}; | ||
| 12 | use crate::{raw, Spawner}; | 11 | use crate::{raw, Spawner}; |
| 13 | 12 | ||
| 14 | #[derive(Copy, Clone)] | ||
| 15 | pub(crate) struct ThreadPender; | ||
| 16 | |||
| 17 | impl ThreadPender { | ||
| 18 | #[allow(unused)] | ||
| 19 | pub(crate) fn pend(self) { | ||
| 20 | SIGNAL_WORK_THREAD_MODE.store(true, core::sync::atomic::Ordering::SeqCst); | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 24 | /// global atomic used to keep track of whether there is work to do since sev() is not available on Xtensa | 13 | /// global atomic used to keep track of whether there is work to do since sev() is not available on Xtensa |
| 25 | static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); | 14 | static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); |
| 26 | 15 | ||
| 16 | #[export_name = "__pender"] | ||
| 17 | fn __pender(_context: *mut ()) { | ||
| 18 | SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); | ||
| 19 | } | ||
| 20 | |||
| 27 | /// Xtensa Executor | 21 | /// Xtensa Executor |
| 28 | pub struct Executor { | 22 | pub struct Executor { |
| 29 | inner: raw::Executor, | 23 | inner: raw::Executor, |
| @@ -34,7 +28,7 @@ mod thread { | |||
| 34 | /// Create a new Executor. | 28 | /// Create a new Executor. |
| 35 | pub fn new() -> Self { | 29 | pub fn new() -> Self { |
| 36 | Self { | 30 | Self { |
| 37 | inner: raw::Executor::new(Pender(PenderInner::Thread(ThreadPender))), | 31 | inner: raw::Executor::new(core::ptr::null_mut()), |
| 38 | not_send: PhantomData, | 32 | not_send: PhantomData, |
| 39 | } | 33 | } |
| 40 | } | 34 | } |
| @@ -77,8 +71,8 @@ mod thread { | |||
| 77 | SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst); | 71 | SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst); |
| 78 | 72 | ||
| 79 | core::arch::asm!( | 73 | core::arch::asm!( |
| 80 | "wsr.ps {0}", | 74 | "wsr.ps {0}", |
| 81 | "rsync", in(reg) token) | 75 | "rsync", in(reg) token) |
| 82 | } else { | 76 | } else { |
| 83 | // waiti sets the PS.INTLEVEL when slipping into sleep | 77 | // waiti sets the PS.INTLEVEL when slipping into sleep |
| 84 | // because critical sections in Xtensa are implemented via increasing | 78 | // because critical sections in Xtensa are implemented via increasing |
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index f3760f589..c1d82e18a 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs | |||
| @@ -147,10 +147,7 @@ impl<F: Future + 'static> TaskStorage<F> { | |||
| 147 | pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> { | 147 | pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> { |
| 148 | let task = AvailableTask::claim(self); | 148 | let task = AvailableTask::claim(self); |
| 149 | match task { | 149 | match task { |
| 150 | Some(task) => { | 150 | Some(task) => task.initialize(future), |
| 151 | let task = task.initialize(future); | ||
| 152 | unsafe { SpawnToken::<F>::new(task) } | ||
| 153 | } | ||
| 154 | None => SpawnToken::new_failed(), | 151 | None => SpawnToken::new_failed(), |
| 155 | } | 152 | } |
| 156 | } | 153 | } |
| @@ -186,12 +183,16 @@ impl<F: Future + 'static> TaskStorage<F> { | |||
| 186 | } | 183 | } |
| 187 | } | 184 | } |
| 188 | 185 | ||
| 189 | struct AvailableTask<F: Future + 'static> { | 186 | /// An uninitialized [`TaskStorage`]. |
| 187 | pub struct AvailableTask<F: Future + 'static> { | ||
| 190 | task: &'static TaskStorage<F>, | 188 | task: &'static TaskStorage<F>, |
| 191 | } | 189 | } |
| 192 | 190 | ||
| 193 | impl<F: Future + 'static> AvailableTask<F> { | 191 | impl<F: Future + 'static> AvailableTask<F> { |
| 194 | fn claim(task: &'static TaskStorage<F>) -> Option<Self> { | 192 | /// Try to claim a [`TaskStorage`]. |
| 193 | /// | ||
| 194 | /// This function returns `None` if a task has already been spawned and has not finished running. | ||
| 195 | pub fn claim(task: &'static TaskStorage<F>) -> Option<Self> { | ||
| 195 | task.raw | 196 | task.raw |
| 196 | .state | 197 | .state |
| 197 | .compare_exchange(0, STATE_SPAWNED | STATE_RUN_QUEUED, Ordering::AcqRel, Ordering::Acquire) | 198 | .compare_exchange(0, STATE_SPAWNED | STATE_RUN_QUEUED, Ordering::AcqRel, Ordering::Acquire) |
| @@ -199,61 +200,30 @@ impl<F: Future + 'static> AvailableTask<F> { | |||
| 199 | .map(|_| Self { task }) | 200 | .map(|_| Self { task }) |
| 200 | } | 201 | } |
| 201 | 202 | ||
| 202 | fn initialize(self, future: impl FnOnce() -> F) -> TaskRef { | 203 | fn initialize_impl<S>(self, future: impl FnOnce() -> F) -> SpawnToken<S> { |
| 203 | unsafe { | 204 | unsafe { |
| 204 | self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll)); | 205 | self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll)); |
| 205 | self.task.future.write(future()); | 206 | self.task.future.write(future()); |
| 206 | } | ||
| 207 | TaskRef::new(self.task) | ||
| 208 | } | ||
| 209 | } | ||
| 210 | 207 | ||
| 211 | /// Raw storage that can hold up to N tasks of the same type. | 208 | let task = TaskRef::new(self.task); |
| 212 | /// | ||
| 213 | /// This is essentially a `[TaskStorage<F>; N]`. | ||
| 214 | pub struct TaskPool<F: Future + 'static, const N: usize> { | ||
| 215 | pool: [TaskStorage<F>; N], | ||
| 216 | } | ||
| 217 | 209 | ||
| 218 | impl<F: Future + 'static, const N: usize> TaskPool<F, N> { | 210 | SpawnToken::new(task) |
| 219 | /// Create a new TaskPool, with all tasks in non-spawned state. | ||
| 220 | pub const fn new() -> Self { | ||
| 221 | Self { | ||
| 222 | pool: [TaskStorage::NEW; N], | ||
| 223 | } | 211 | } |
| 224 | } | 212 | } |
| 225 | 213 | ||
| 226 | /// Try to spawn a task in the pool. | 214 | /// Initialize the [`TaskStorage`] to run the given future. |
| 227 | /// | 215 | pub fn initialize(self, future: impl FnOnce() -> F) -> SpawnToken<F> { |
| 228 | /// See [`TaskStorage::spawn()`] for details. | 216 | self.initialize_impl::<F>(future) |
| 229 | /// | ||
| 230 | /// This will loop over the pool and spawn the task in the first storage that | ||
| 231 | /// is currently free. If none is free, a "poisoned" SpawnToken is returned, | ||
| 232 | /// which will cause [`Spawner::spawn()`](super::Spawner::spawn) to return the error. | ||
| 233 | pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> { | ||
| 234 | let task = self.pool.iter().find_map(AvailableTask::claim); | ||
| 235 | match task { | ||
| 236 | Some(task) => { | ||
| 237 | let task = task.initialize(future); | ||
| 238 | unsafe { SpawnToken::<F>::new(task) } | ||
| 239 | } | ||
| 240 | None => SpawnToken::new_failed(), | ||
| 241 | } | ||
| 242 | } | 217 | } |
| 243 | 218 | ||
| 244 | /// Like spawn(), but allows the task to be send-spawned if the args are Send even if | 219 | /// Initialize the [`TaskStorage`] to run the given future. |
| 245 | /// the future is !Send. | ||
| 246 | /// | 220 | /// |
| 247 | /// Not covered by semver guarantees. DO NOT call this directly. Intended to be used | 221 | /// # Safety |
| 248 | /// by the Embassy macros ONLY. | ||
| 249 | /// | 222 | /// |
| 250 | /// SAFETY: `future` must be a closure of the form `move || my_async_fn(args)`, where `my_async_fn` | 223 | /// `future` must be a closure of the form `move || my_async_fn(args)`, where `my_async_fn` |
| 251 | /// is an `async fn`, NOT a hand-written `Future`. | 224 | /// is an `async fn`, NOT a hand-written `Future`. |
| 252 | #[doc(hidden)] | 225 | #[doc(hidden)] |
| 253 | pub unsafe fn _spawn_async_fn<FutFn>(&'static self, future: FutFn) -> SpawnToken<impl Sized> | 226 | pub unsafe fn __initialize_async_fn<FutFn>(self, future: impl FnOnce() -> F) -> SpawnToken<FutFn> { |
| 254 | where | ||
| 255 | FutFn: FnOnce() -> F, | ||
| 256 | { | ||
| 257 | // When send-spawning a task, we construct the future in this thread, and effectively | 227 | // When send-spawning a task, we construct the future in this thread, and effectively |
| 258 | // "send" it to the executor thread by enqueuing it in its queue. Therefore, in theory, | 228 | // "send" it to the executor thread by enqueuing it in its queue. Therefore, in theory, |
| 259 | // send-spawning should require the future `F` to be `Send`. | 229 | // send-spawning should require the future `F` to be `Send`. |
| @@ -279,66 +249,73 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> { | |||
| 279 | // | 249 | // |
| 280 | // This ONLY holds for `async fn` futures. The other `spawn` methods can be called directly | 250 | // This ONLY holds for `async fn` futures. The other `spawn` methods can be called directly |
| 281 | // by the user, with arbitrary hand-implemented futures. This is why these return `SpawnToken<F>`. | 251 | // by the user, with arbitrary hand-implemented futures. This is why these return `SpawnToken<F>`. |
| 282 | 252 | self.initialize_impl::<FutFn>(future) | |
| 283 | let task = self.pool.iter().find_map(AvailableTask::claim); | ||
| 284 | match task { | ||
| 285 | Some(task) => { | ||
| 286 | let task = task.initialize(future); | ||
| 287 | unsafe { SpawnToken::<FutFn>::new(task) } | ||
| 288 | } | ||
| 289 | None => SpawnToken::new_failed(), | ||
| 290 | } | ||
| 291 | } | 253 | } |
| 292 | } | 254 | } |
| 293 | 255 | ||
| 294 | #[derive(Clone, Copy)] | 256 | /// Raw storage that can hold up to N tasks of the same type. |
| 295 | pub(crate) enum PenderInner { | 257 | /// |
| 296 | #[cfg(feature = "executor-thread")] | 258 | /// This is essentially a `[TaskStorage<F>; N]`. |
| 297 | Thread(crate::arch::ThreadPender), | 259 | pub struct TaskPool<F: Future + 'static, const N: usize> { |
| 298 | #[cfg(feature = "executor-interrupt")] | 260 | pool: [TaskStorage<F>; N], |
| 299 | Interrupt(crate::arch::InterruptPender), | ||
| 300 | #[cfg(feature = "pender-callback")] | ||
| 301 | Callback { func: fn(*mut ()), context: *mut () }, | ||
| 302 | } | 261 | } |
| 303 | 262 | ||
| 304 | unsafe impl Send for PenderInner {} | 263 | impl<F: Future + 'static, const N: usize> TaskPool<F, N> { |
| 305 | unsafe impl Sync for PenderInner {} | 264 | /// Create a new TaskPool, with all tasks in non-spawned state. |
| 265 | pub const fn new() -> Self { | ||
| 266 | Self { | ||
| 267 | pool: [TaskStorage::NEW; N], | ||
| 268 | } | ||
| 269 | } | ||
| 306 | 270 | ||
| 307 | /// Platform/architecture-specific action executed when an executor has pending work. | 271 | fn spawn_impl<T>(&'static self, future: impl FnOnce() -> F) -> SpawnToken<T> { |
| 308 | /// | 272 | match self.pool.iter().find_map(AvailableTask::claim) { |
| 309 | /// When a task within an executor is woken, the `Pender` is called. This does a | 273 | Some(task) => task.initialize_impl::<T>(future), |
| 310 | /// platform/architecture-specific action to signal there is pending work in the executor. | 274 | None => SpawnToken::new_failed(), |
| 311 | /// When this happens, you must arrange for [`Executor::poll`] to be called. | 275 | } |
| 312 | /// | 276 | } |
| 313 | /// You can think of it as a waker, but for the whole executor. | ||
| 314 | pub struct Pender(pub(crate) PenderInner); | ||
| 315 | 277 | ||
| 316 | impl Pender { | 278 | /// Try to spawn a task in the pool. |
| 317 | /// Create a `Pender` that will call an arbitrary function pointer. | 279 | /// |
| 280 | /// See [`TaskStorage::spawn()`] for details. | ||
| 281 | /// | ||
| 282 | /// This will loop over the pool and spawn the task in the first storage that | ||
| 283 | /// is currently free. If none is free, a "poisoned" SpawnToken is returned, | ||
| 284 | /// which will cause [`Spawner::spawn()`](super::Spawner::spawn) to return the error. | ||
| 285 | pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> { | ||
| 286 | self.spawn_impl::<F>(future) | ||
| 287 | } | ||
| 288 | |||
| 289 | /// Like spawn(), but allows the task to be send-spawned if the args are Send even if | ||
| 290 | /// the future is !Send. | ||
| 318 | /// | 291 | /// |
| 319 | /// # Arguments | 292 | /// Not covered by semver guarantees. DO NOT call this directly. Intended to be used |
| 293 | /// by the Embassy macros ONLY. | ||
| 320 | /// | 294 | /// |
| 321 | /// - `func`: The function pointer to call. | 295 | /// SAFETY: `future` must be a closure of the form `move || my_async_fn(args)`, where `my_async_fn` |
| 322 | /// - `context`: Opaque context pointer, that will be passed to the function pointer. | 296 | /// is an `async fn`, NOT a hand-written `Future`. |
| 323 | #[cfg(feature = "pender-callback")] | 297 | #[doc(hidden)] |
| 324 | pub fn new_from_callback(func: fn(*mut ()), context: *mut ()) -> Self { | 298 | pub unsafe fn _spawn_async_fn<FutFn>(&'static self, future: FutFn) -> SpawnToken<impl Sized> |
| 325 | Self(PenderInner::Callback { | 299 | where |
| 326 | func, | 300 | FutFn: FnOnce() -> F, |
| 327 | context: context.into(), | 301 | { |
| 328 | }) | 302 | // See the comment in AvailableTask::__initialize_async_fn for explanation. |
| 303 | self.spawn_impl::<FutFn>(future) | ||
| 329 | } | 304 | } |
| 330 | } | 305 | } |
| 331 | 306 | ||
| 307 | #[derive(Clone, Copy)] | ||
| 308 | pub(crate) struct Pender(*mut ()); | ||
| 309 | |||
| 310 | unsafe impl Send for Pender {} | ||
| 311 | unsafe impl Sync for Pender {} | ||
| 312 | |||
| 332 | impl Pender { | 313 | impl Pender { |
| 333 | pub(crate) fn pend(&self) { | 314 | pub(crate) fn pend(self) { |
| 334 | match self.0 { | 315 | extern "Rust" { |
| 335 | #[cfg(feature = "executor-thread")] | 316 | fn __pender(context: *mut ()); |
| 336 | PenderInner::Thread(x) => x.pend(), | ||
| 337 | #[cfg(feature = "executor-interrupt")] | ||
| 338 | PenderInner::Interrupt(x) => x.pend(), | ||
| 339 | #[cfg(feature = "pender-callback")] | ||
| 340 | PenderInner::Callback { func, context } => func(context), | ||
| 341 | } | 317 | } |
| 318 | unsafe { __pender(self.0) }; | ||
| 342 | } | 319 | } |
| 343 | } | 320 | } |
| 344 | 321 | ||
| @@ -409,7 +386,7 @@ impl SyncExecutor { | |||
| 409 | #[allow(clippy::never_loop)] | 386 | #[allow(clippy::never_loop)] |
| 410 | loop { | 387 | loop { |
| 411 | #[cfg(feature = "integrated-timers")] | 388 | #[cfg(feature = "integrated-timers")] |
| 412 | self.timer_queue.dequeue_expired(Instant::now(), |task| wake_task(task)); | 389 | self.timer_queue.dequeue_expired(Instant::now(), wake_task_no_pend); |
| 413 | 390 | ||
| 414 | self.run_queue.dequeue_all(|p| { | 391 | self.run_queue.dequeue_all(|p| { |
| 415 | let task = p.header(); | 392 | let task = p.header(); |
| @@ -472,15 +449,31 @@ impl SyncExecutor { | |||
| 472 | /// | 449 | /// |
| 473 | /// - To get the executor to do work, call `poll()`. This will poll all queued tasks (all tasks | 450 | /// - To get the executor to do work, call `poll()`. This will poll all queued tasks (all tasks |
| 474 | /// that "want to run"). | 451 | /// that "want to run"). |
| 475 | /// - You must supply a [`Pender`]. The executor will call it to notify you it has work | 452 | /// - You must supply a pender function, as shown below. The executor will call it to notify you |
| 476 | /// to do. You must arrange for `poll()` to be called as soon as possible. | 453 | /// it has work to do. You must arrange for `poll()` to be called as soon as possible. |
| 454 | /// - Enabling `arch-xx` features will define a pender function for you. This means that you | ||
| 455 | /// are limited to using the executors provided to you by the architecture/platform | ||
| 456 | /// implementation. If you need a different executor, you must not enable `arch-xx` features. | ||
| 477 | /// | 457 | /// |
| 478 | /// The [`Pender`] can be called from *any* context: any thread, any interrupt priority | 458 | /// The pender can be called from *any* context: any thread, any interrupt priority |
| 479 | /// level, etc. It may be called synchronously from any `Executor` method call as well. | 459 | /// level, etc. It may be called synchronously from any `Executor` method call as well. |
| 480 | /// You must deal with this correctly. | 460 | /// You must deal with this correctly. |
| 481 | /// | 461 | /// |
| 482 | /// In particular, you must NOT call `poll` directly from the pender callback, as this violates | 462 | /// In particular, you must NOT call `poll` directly from the pender callback, as this violates |
| 483 | /// the requirement for `poll` to not be called reentrantly. | 463 | /// the requirement for `poll` to not be called reentrantly. |
| 464 | /// | ||
| 465 | /// The pender function must be exported with the name `__pender` and have the following signature: | ||
| 466 | /// | ||
| 467 | /// ```rust | ||
| 468 | /// #[export_name = "__pender"] | ||
| 469 | /// fn pender(context: *mut ()) { | ||
| 470 | /// // schedule `poll()` to be called | ||
| 471 | /// } | ||
| 472 | /// ``` | ||
| 473 | /// | ||
| 474 | /// The `context` argument is a piece of arbitrary data the executor will pass to the pender. | ||
| 475 | /// You can set the `context` when calling [`Executor::new()`]. You can use it to, for example, | ||
| 476 | /// differentiate between executors, or to pass a pointer to a callback that should be called. | ||
| 484 | #[repr(transparent)] | 477 | #[repr(transparent)] |
| 485 | pub struct Executor { | 478 | pub struct Executor { |
| 486 | pub(crate) inner: SyncExecutor, | 479 | pub(crate) inner: SyncExecutor, |
| @@ -495,12 +488,12 @@ impl Executor { | |||
| 495 | 488 | ||
| 496 | /// Create a new executor. | 489 | /// Create a new executor. |
| 497 | /// | 490 | /// |
| 498 | /// When the executor has work to do, it will call the [`Pender`]. | 491 | /// When the executor has work to do, it will call the pender function and pass `context` to it. |
| 499 | /// | 492 | /// |
| 500 | /// See [`Executor`] docs for details on `Pender`. | 493 | /// See [`Executor`] docs for details on the pender. |
| 501 | pub fn new(pender: Pender) -> Self { | 494 | pub fn new(context: *mut ()) -> Self { |
| 502 | Self { | 495 | Self { |
| 503 | inner: SyncExecutor::new(pender), | 496 | inner: SyncExecutor::new(Pender(context)), |
| 504 | _not_sync: PhantomData, | 497 | _not_sync: PhantomData, |
| 505 | } | 498 | } |
| 506 | } | 499 | } |
| @@ -523,16 +516,16 @@ impl Executor { | |||
| 523 | /// This loops over all tasks that are queued to be polled (i.e. they're | 516 | /// This loops over all tasks that are queued to be polled (i.e. they're |
| 524 | /// freshly spawned or they've been woken). Other tasks are not polled. | 517 | /// freshly spawned or they've been woken). Other tasks are not polled. |
| 525 | /// | 518 | /// |
| 526 | /// You must call `poll` after receiving a call to the [`Pender`]. It is OK | 519 | /// You must call `poll` after receiving a call to the pender. It is OK |
| 527 | /// to call `poll` even when not requested by the `Pender`, but it wastes | 520 | /// to call `poll` even when not requested by the pender, but it wastes |
| 528 | /// energy. | 521 | /// energy. |
| 529 | /// | 522 | /// |
| 530 | /// # Safety | 523 | /// # Safety |
| 531 | /// | 524 | /// |
| 532 | /// You must NOT call `poll` reentrantly on the same executor. | 525 | /// You must NOT call `poll` reentrantly on the same executor. |
| 533 | /// | 526 | /// |
| 534 | /// In particular, note that `poll` may call the `Pender` synchronously. Therefore, you | 527 | /// In particular, note that `poll` may call the pender synchronously. Therefore, you |
| 535 | /// must NOT directly call `poll()` from the `Pender` callback. Instead, the callback has to | 528 | /// must NOT directly call `poll()` from the pender callback. Instead, the callback has to |
| 536 | /// somehow schedule for `poll()` to be called later, at a time you know for sure there's | 529 | /// somehow schedule for `poll()` to be called later, at a time you know for sure there's |
| 537 | /// no `poll()` already running. | 530 | /// no `poll()` already running. |
| 538 | pub unsafe fn poll(&'static self) { | 531 | pub unsafe fn poll(&'static self) { |
| @@ -573,6 +566,31 @@ pub fn wake_task(task: TaskRef) { | |||
| 573 | } | 566 | } |
| 574 | } | 567 | } |
| 575 | 568 | ||
| 569 | /// Wake a task by `TaskRef` without calling pend. | ||
| 570 | /// | ||
| 571 | /// You can obtain a `TaskRef` from a `Waker` using [`task_from_waker`]. | ||
| 572 | pub fn wake_task_no_pend(task: TaskRef) { | ||
| 573 | let header = task.header(); | ||
| 574 | |||
| 575 | let res = header.state.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| { | ||
| 576 | // If already scheduled, or if not started, | ||
| 577 | if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) { | ||
| 578 | None | ||
| 579 | } else { | ||
| 580 | // Mark it as scheduled | ||
| 581 | Some(state | STATE_RUN_QUEUED) | ||
| 582 | } | ||
| 583 | }); | ||
| 584 | |||
| 585 | if res.is_ok() { | ||
| 586 | // We have just marked the task as scheduled, so enqueue it. | ||
| 587 | unsafe { | ||
| 588 | let executor = header.executor.get().unwrap_unchecked(); | ||
| 589 | executor.run_queue.enqueue(task); | ||
| 590 | } | ||
| 591 | } | ||
| 592 | } | ||
| 593 | |||
| 576 | #[cfg(feature = "integrated-timers")] | 594 | #[cfg(feature = "integrated-timers")] |
| 577 | struct TimerQueue; | 595 | struct TimerQueue; |
| 578 | 596 | ||
diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index 2b6224045..5a3a0dee1 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs | |||
| @@ -33,7 +33,8 @@ impl<S> SpawnToken<S> { | |||
| 33 | } | 33 | } |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | pub(crate) fn new_failed() -> Self { | 36 | /// Return a SpawnToken that represents a failed spawn. |
| 37 | pub fn new_failed() -> Self { | ||
| 37 | Self { | 38 | Self { |
| 38 | raw_task: None, | 39 | raw_task: None, |
| 39 | phantom: PhantomData, | 40 | phantom: PhantomData, |
diff --git a/embassy-lora/Cargo.toml b/embassy-lora/Cargo.toml index 402ad2d70..feea06582 100644 --- a/embassy-lora/Cargo.toml +++ b/embassy-lora/Cargo.toml | |||
| @@ -23,9 +23,12 @@ log = { version = "0.4.14", optional = true } | |||
| 23 | embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true } | 23 | embassy-time = { version = "0.1.2", path = "../embassy-time", optional = true } |
| 24 | embassy-sync = { version = "0.2.0", path = "../embassy-sync" } | 24 | embassy-sync = { version = "0.2.0", path = "../embassy-sync" } |
| 25 | embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } | 25 | embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } |
| 26 | embedded-hal-async = { version = "=0.2.0-alpha.2" } | 26 | embedded-hal-async = { version = "=1.0.0-rc.1" } |
| 27 | embedded-hal = { version = "0.2", features = ["unproven"] } | 27 | embedded-hal = { version = "0.2", features = ["unproven"] } |
| 28 | 28 | ||
| 29 | futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } | 29 | futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } |
| 30 | lora-phy = { version = "1" } | 30 | lora-phy = { version = "1" } |
| 31 | lorawan-device = { version = "0.10.0", default-features = false, features = ["async"], optional = true } | 31 | lorawan-device = { version = "0.10.0", default-features = false, features = ["async"], optional = true } |
| 32 | |||
| 33 | [patch.crates-io] | ||
| 34 | lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} \ No newline at end of file | ||
diff --git a/embassy-net-driver-channel/README.md b/embassy-net-driver-channel/README.md index dd90e7ad2..8f904ce95 100644 --- a/embassy-net-driver-channel/README.md +++ b/embassy-net-driver-channel/README.md | |||
| @@ -76,7 +76,7 @@ These `embassy-net` drivers are implemented using this crate. You can look at th | |||
| 76 | 76 | ||
| 77 | - [`cyw43`](https://github.com/embassy-rs/embassy/tree/main/cyw43) for WiFi on CYW43xx chips, used in the Raspberry Pi Pico W | 77 | - [`cyw43`](https://github.com/embassy-rs/embassy/tree/main/cyw43) for WiFi on CYW43xx chips, used in the Raspberry Pi Pico W |
| 78 | - [`embassy-usb`](https://github.com/embassy-rs/embassy/tree/main/embassy-usb) for Ethernet-over-USB (CDC NCM) support. | 78 | - [`embassy-usb`](https://github.com/embassy-rs/embassy/tree/main/embassy-usb) for Ethernet-over-USB (CDC NCM) support. |
| 79 | - [`embassy-net-w5500`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-w5500) for Wiznet W5500 SPI Ethernet MAC+PHY chip. | 79 | - [`embassy-net-wiznet`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-wiznet) for Wiznet SPI Ethernet MAC+PHY chips. |
| 80 | - [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU. | 80 | - [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU. |
| 81 | 81 | ||
| 82 | 82 | ||
diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml new file mode 100644 index 000000000..e02c984e9 --- /dev/null +++ b/embassy-net-enc28j60/Cargo.toml | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | [package] | ||
| 2 | name = "embassy-net-enc28j60" | ||
| 3 | version = "0.1.0" | ||
| 4 | description = "embassy-net driver for the ENC28J60 ethernet chip" | ||
| 5 | keywords = ["embedded", "enc28j60", "embassy-net", "embedded-hal-async", "ethernet", "async"] | ||
| 6 | categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] | ||
| 7 | license = "MIT OR Apache-2.0" | ||
| 8 | edition = "2021" | ||
| 9 | |||
| 10 | [dependencies] | ||
| 11 | embedded-hal = { version = "1.0.0-rc.1" } | ||
| 12 | embedded-hal-async = { version = "=1.0.0-rc.1" } | ||
| 13 | embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } | ||
| 14 | embassy-time = { version = "0.1.2", path = "../embassy-time" } | ||
| 15 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } | ||
| 16 | |||
| 17 | defmt = { version = "0.3", optional = true } | ||
| 18 | log = { version = "0.4.14", optional = true } | ||
| 19 | |||
| 20 | [package.metadata.embassy_docs] | ||
| 21 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-enc28j60-v$VERSION/embassy-net-enc28j60/src/" | ||
| 22 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-enc28j60/src/" | ||
| 23 | target = "thumbv7em-none-eabi" \ No newline at end of file | ||
diff --git a/embassy-net-enc28j60/README.md b/embassy-net-enc28j60/README.md new file mode 100644 index 000000000..39011ca13 --- /dev/null +++ b/embassy-net-enc28j60/README.md | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | # `embassy-net-enc28j60` | ||
| 2 | |||
| 3 | [`embassy-net`](https://crates.io/crates/embassy-net) integration for the Microchip ENC28J60 Ethernet chip. | ||
| 4 | |||
| 5 | Based on [@japaric](https://github.com/japaric)'s [`enc28j60`](https://github.com/japaric/enc28j60) crate. | ||
| 6 | |||
| 7 | ## Interoperability | ||
| 8 | |||
| 9 | This crate can run on any executor. | ||
| 10 | |||
| 11 | ## License | ||
| 12 | |||
| 13 | This work is licensed under either of | ||
| 14 | |||
| 15 | - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or | ||
| 16 | http://www.apache.org/licenses/LICENSE-2.0) | ||
| 17 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) | ||
| 18 | |||
| 19 | at your option. | ||
diff --git a/embassy-net-enc28j60/src/bank0.rs b/embassy-net-enc28j60/src/bank0.rs new file mode 100644 index 000000000..1c1b3a7f6 --- /dev/null +++ b/embassy-net-enc28j60/src/bank0.rs | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | #[allow(dead_code)] | ||
| 2 | #[derive(Clone, Copy)] | ||
| 3 | pub enum Register { | ||
| 4 | ERDPTL = 0x00, | ||
| 5 | ERDPTH = 0x01, | ||
| 6 | EWRPTL = 0x02, | ||
| 7 | EWRPTH = 0x03, | ||
| 8 | ETXSTL = 0x04, | ||
| 9 | ETXSTH = 0x05, | ||
| 10 | ETXNDL = 0x06, | ||
| 11 | ETXNDH = 0x07, | ||
| 12 | ERXSTL = 0x08, | ||
| 13 | ERXSTH = 0x09, | ||
| 14 | ERXNDL = 0x0a, | ||
| 15 | ERXNDH = 0x0b, | ||
| 16 | ERXRDPTL = 0x0c, | ||
| 17 | ERXRDPTH = 0x0d, | ||
| 18 | ERXWRPTL = 0x0e, | ||
| 19 | ERXWRPTH = 0x0f, | ||
| 20 | EDMASTL = 0x10, | ||
| 21 | EDMASTH = 0x11, | ||
| 22 | EDMANDL = 0x12, | ||
| 23 | EDMANDH = 0x13, | ||
| 24 | EDMADSTL = 0x14, | ||
| 25 | EDMADSTH = 0x15, | ||
| 26 | EDMACSL = 0x16, | ||
| 27 | EDMACSH = 0x17, | ||
| 28 | } | ||
| 29 | |||
| 30 | impl Register { | ||
| 31 | pub(crate) fn addr(&self) -> u8 { | ||
| 32 | *self as u8 | ||
| 33 | } | ||
| 34 | |||
| 35 | pub(crate) fn is_eth_register(&self) -> bool { | ||
| 36 | match *self { | ||
| 37 | Register::ERDPTL => true, | ||
| 38 | Register::ERDPTH => true, | ||
| 39 | Register::EWRPTL => true, | ||
| 40 | Register::EWRPTH => true, | ||
| 41 | Register::ETXSTL => true, | ||
| 42 | Register::ETXSTH => true, | ||
| 43 | Register::ETXNDL => true, | ||
| 44 | Register::ETXNDH => true, | ||
| 45 | Register::ERXSTL => true, | ||
| 46 | Register::ERXSTH => true, | ||
| 47 | Register::ERXNDL => true, | ||
| 48 | Register::ERXNDH => true, | ||
| 49 | Register::ERXRDPTL => true, | ||
| 50 | Register::ERXRDPTH => true, | ||
| 51 | Register::ERXWRPTL => true, | ||
| 52 | Register::ERXWRPTH => true, | ||
| 53 | Register::EDMASTL => true, | ||
| 54 | Register::EDMASTH => true, | ||
| 55 | Register::EDMANDL => true, | ||
| 56 | Register::EDMANDH => true, | ||
| 57 | Register::EDMADSTL => true, | ||
| 58 | Register::EDMADSTH => true, | ||
| 59 | Register::EDMACSL => true, | ||
| 60 | Register::EDMACSH => true, | ||
| 61 | } | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | impl Into<super::Register> for Register { | ||
| 66 | fn into(self) -> super::Register { | ||
| 67 | super::Register::Bank0(self) | ||
| 68 | } | ||
| 69 | } | ||
diff --git a/embassy-net-enc28j60/src/bank1.rs b/embassy-net-enc28j60/src/bank1.rs new file mode 100644 index 000000000..30560edf6 --- /dev/null +++ b/embassy-net-enc28j60/src/bank1.rs | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | #[allow(dead_code)] | ||
| 2 | #[derive(Clone, Copy)] | ||
| 3 | pub enum Register { | ||
| 4 | EHT0 = 0x00, | ||
| 5 | EHT1 = 0x01, | ||
| 6 | EHT2 = 0x02, | ||
| 7 | EHT3 = 0x03, | ||
| 8 | EHT4 = 0x04, | ||
| 9 | EHT5 = 0x05, | ||
| 10 | EHT6 = 0x06, | ||
| 11 | EHT7 = 0x07, | ||
| 12 | EPMM0 = 0x08, | ||
| 13 | EPMM1 = 0x09, | ||
| 14 | EPMM2 = 0x0a, | ||
| 15 | EPMM3 = 0x0b, | ||
| 16 | EPMM4 = 0x0c, | ||
| 17 | EPMM5 = 0x0d, | ||
| 18 | EPMM6 = 0x0e, | ||
| 19 | EPMM7 = 0x0f, | ||
| 20 | EPMCSL = 0x10, | ||
| 21 | EPMCSH = 0x11, | ||
| 22 | EPMOL = 0x14, | ||
| 23 | EPMOH = 0x15, | ||
| 24 | ERXFCON = 0x18, | ||
| 25 | EPKTCNT = 0x19, | ||
| 26 | } | ||
| 27 | |||
| 28 | impl Register { | ||
| 29 | pub(crate) fn addr(&self) -> u8 { | ||
| 30 | *self as u8 | ||
| 31 | } | ||
| 32 | |||
| 33 | pub(crate) fn is_eth_register(&self) -> bool { | ||
| 34 | match *self { | ||
| 35 | Register::EHT0 => true, | ||
| 36 | Register::EHT1 => true, | ||
| 37 | Register::EHT2 => true, | ||
| 38 | Register::EHT3 => true, | ||
| 39 | Register::EHT4 => true, | ||
| 40 | Register::EHT5 => true, | ||
| 41 | Register::EHT6 => true, | ||
| 42 | Register::EHT7 => true, | ||
| 43 | Register::EPMM0 => true, | ||
| 44 | Register::EPMM1 => true, | ||
| 45 | Register::EPMM2 => true, | ||
| 46 | Register::EPMM3 => true, | ||
| 47 | Register::EPMM4 => true, | ||
| 48 | Register::EPMM5 => true, | ||
| 49 | Register::EPMM6 => true, | ||
| 50 | Register::EPMM7 => true, | ||
| 51 | Register::EPMCSL => true, | ||
| 52 | Register::EPMCSH => true, | ||
| 53 | Register::EPMOL => true, | ||
| 54 | Register::EPMOH => true, | ||
| 55 | Register::ERXFCON => true, | ||
| 56 | Register::EPKTCNT => true, | ||
| 57 | } | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | impl Into<super::Register> for Register { | ||
| 62 | fn into(self) -> super::Register { | ||
| 63 | super::Register::Bank1(self) | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | register!(ERXFCON, 0b1010_0001, u8, { | ||
| 68 | #[doc = "Broadcast Filter Enable bit"] | ||
| 69 | bcen @ 0, | ||
| 70 | #[doc = "Multicast Filter Enable bit"] | ||
| 71 | mcen @ 1, | ||
| 72 | #[doc = "Hash Table Filter Enable bit"] | ||
| 73 | hten @ 2, | ||
| 74 | #[doc = "Magic Packetâ„¢ Filter Enable bit"] | ||
| 75 | mpen @ 3, | ||
| 76 | #[doc = "Pattern Match Filter Enable bit"] | ||
| 77 | pmen @ 4, | ||
| 78 | #[doc = "Post-Filter CRC Check Enable bit"] | ||
| 79 | crcen @ 5, | ||
| 80 | #[doc = "AND/OR Filter Select bit"] | ||
| 81 | andor @ 6, | ||
| 82 | #[doc = "Unicast Filter Enable bit"] | ||
| 83 | ucen @ 7, | ||
| 84 | }); | ||
diff --git a/embassy-net-enc28j60/src/bank2.rs b/embassy-net-enc28j60/src/bank2.rs new file mode 100644 index 000000000..74a1d245f --- /dev/null +++ b/embassy-net-enc28j60/src/bank2.rs | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | #[allow(dead_code)] | ||
| 2 | #[derive(Clone, Copy)] | ||
| 3 | pub enum Register { | ||
| 4 | MACON1 = 0x00, | ||
| 5 | MACON3 = 0x02, | ||
| 6 | MACON4 = 0x03, | ||
| 7 | MABBIPG = 0x04, | ||
| 8 | MAIPGL = 0x06, | ||
| 9 | MAIPGH = 0x07, | ||
| 10 | MACLCON1 = 0x08, | ||
| 11 | MACLCON2 = 0x09, | ||
| 12 | MAMXFLL = 0x0a, | ||
| 13 | MAMXFLH = 0x0b, | ||
| 14 | MICMD = 0x12, | ||
| 15 | MIREGADR = 0x14, | ||
| 16 | MIWRL = 0x16, | ||
| 17 | MIWRH = 0x17, | ||
| 18 | MIRDL = 0x18, | ||
| 19 | MIRDH = 0x19, | ||
| 20 | } | ||
| 21 | |||
| 22 | impl Register { | ||
| 23 | pub(crate) fn addr(&self) -> u8 { | ||
| 24 | *self as u8 | ||
| 25 | } | ||
| 26 | |||
| 27 | pub(crate) fn is_eth_register(&self) -> bool { | ||
| 28 | match *self { | ||
| 29 | Register::MACON1 => false, | ||
| 30 | Register::MACON3 => false, | ||
| 31 | Register::MACON4 => false, | ||
| 32 | Register::MABBIPG => false, | ||
| 33 | Register::MAIPGL => false, | ||
| 34 | Register::MAIPGH => false, | ||
| 35 | Register::MACLCON1 => false, | ||
| 36 | Register::MACLCON2 => false, | ||
| 37 | Register::MAMXFLL => false, | ||
| 38 | Register::MAMXFLH => false, | ||
| 39 | Register::MICMD => false, | ||
| 40 | Register::MIREGADR => false, | ||
| 41 | Register::MIWRL => false, | ||
| 42 | Register::MIWRH => false, | ||
| 43 | Register::MIRDL => false, | ||
| 44 | Register::MIRDH => false, | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | impl Into<super::Register> for Register { | ||
| 50 | fn into(self) -> super::Register { | ||
| 51 | super::Register::Bank2(self) | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | register!(MACON1, 0, u8, { | ||
| 56 | #[doc = "Enable packets to be received by the MAC"] | ||
| 57 | marxen @ 0, | ||
| 58 | #[doc = "Control frames will be discarded after being processed by the MAC"] | ||
| 59 | passall @ 1, | ||
| 60 | #[doc = "Inhibit transmissions when pause control frames are received"] | ||
| 61 | rxpaus @ 2, | ||
| 62 | #[doc = "Allow the MAC to transmit pause control frames"] | ||
| 63 | txpaus @ 3, | ||
| 64 | }); | ||
| 65 | |||
| 66 | register!(MACON3, 0, u8, { | ||
| 67 | #[doc = "MAC will operate in Full-Duplex mode"] | ||
| 68 | fuldpx @ 0, | ||
| 69 | #[doc = "The type/length field of transmitted and received frames will be checked"] | ||
| 70 | frmlnen @ 1, | ||
| 71 | #[doc = "Frames bigger than MAMXFL will be aborted when transmitted or received"] | ||
| 72 | hfrmen @ 2, | ||
| 73 | #[doc = "No proprietary header is present"] | ||
| 74 | phdren @ 3, | ||
| 75 | #[doc = "MAC will append a valid CRC to all frames transmitted regardless of PADCFG bit"] | ||
| 76 | txcrcen @ 4, | ||
| 77 | #[doc = "All short frames will be zero-padded to 64 bytes and a valid CRC will then be appended"] | ||
| 78 | padcfg @ 5..7, | ||
| 79 | }); | ||
| 80 | |||
| 81 | register!(MICMD, 0, u8, { | ||
| 82 | #[doc = "MII Read Enable bit"] | ||
| 83 | miird @ 0, | ||
| 84 | #[doc = "MII Scan Enable bit"] | ||
| 85 | miiscan @ 1, | ||
| 86 | }); | ||
diff --git a/embassy-net-enc28j60/src/bank3.rs b/embassy-net-enc28j60/src/bank3.rs new file mode 100644 index 000000000..4f7eb9406 --- /dev/null +++ b/embassy-net-enc28j60/src/bank3.rs | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | #[allow(dead_code)] | ||
| 2 | #[derive(Clone, Copy)] | ||
| 3 | pub enum Register { | ||
| 4 | MAADR5 = 0x00, | ||
| 5 | MAADR6 = 0x01, | ||
| 6 | MAADR3 = 0x02, | ||
| 7 | MAADR4 = 0x03, | ||
| 8 | MAADR1 = 0x04, | ||
| 9 | MAADR2 = 0x05, | ||
| 10 | EBSTSD = 0x06, | ||
| 11 | EBSTCON = 0x07, | ||
| 12 | EBSTCSL = 0x08, | ||
| 13 | EBSTCSH = 0x09, | ||
| 14 | MISTAT = 0x0a, | ||
| 15 | EREVID = 0x12, | ||
| 16 | ECOCON = 0x15, | ||
| 17 | EFLOCON = 0x17, | ||
| 18 | EPAUSL = 0x18, | ||
| 19 | EPAUSH = 0x19, | ||
| 20 | } | ||
| 21 | |||
| 22 | impl Register { | ||
| 23 | pub(crate) fn addr(&self) -> u8 { | ||
| 24 | *self as u8 | ||
| 25 | } | ||
| 26 | |||
| 27 | pub(crate) fn is_eth_register(&self) -> bool { | ||
| 28 | match *self { | ||
| 29 | Register::MAADR5 => false, | ||
| 30 | Register::MAADR6 => false, | ||
| 31 | Register::MAADR3 => false, | ||
| 32 | Register::MAADR4 => false, | ||
| 33 | Register::MAADR1 => false, | ||
| 34 | Register::MAADR2 => false, | ||
| 35 | Register::EBSTSD => true, | ||
| 36 | Register::EBSTCON => true, | ||
| 37 | Register::EBSTCSL => true, | ||
| 38 | Register::EBSTCSH => true, | ||
| 39 | Register::MISTAT => false, | ||
| 40 | Register::EREVID => true, | ||
| 41 | Register::ECOCON => true, | ||
| 42 | Register::EFLOCON => true, | ||
| 43 | Register::EPAUSL => true, | ||
| 44 | Register::EPAUSH => true, | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | impl Into<super::Register> for Register { | ||
| 50 | fn into(self) -> super::Register { | ||
| 51 | super::Register::Bank3(self) | ||
| 52 | } | ||
| 53 | } | ||
diff --git a/embassy-net-enc28j60/src/common.rs b/embassy-net-enc28j60/src/common.rs new file mode 100644 index 000000000..ef339dd2a --- /dev/null +++ b/embassy-net-enc28j60/src/common.rs | |||
| @@ -0,0 +1,106 @@ | |||
| 1 | #[allow(dead_code)] | ||
| 2 | #[derive(Clone, Copy)] | ||
| 3 | pub enum Register { | ||
| 4 | ECON1 = 0x1f, | ||
| 5 | ECON2 = 0x1e, | ||
| 6 | EIE = 0x1b, | ||
| 7 | EIR = 0x1c, | ||
| 8 | ESTAT = 0x1d, | ||
| 9 | } | ||
| 10 | |||
| 11 | impl Register { | ||
| 12 | pub(crate) fn addr(&self) -> u8 { | ||
| 13 | *self as u8 | ||
| 14 | } | ||
| 15 | |||
| 16 | pub(crate) fn is_eth_register(&self) -> bool { | ||
| 17 | match *self { | ||
| 18 | Register::ECON1 => true, | ||
| 19 | Register::ECON2 => true, | ||
| 20 | Register::EIE => true, | ||
| 21 | Register::EIR => true, | ||
| 22 | Register::ESTAT => true, | ||
| 23 | } | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | impl Into<super::Register> for Register { | ||
| 28 | fn into(self) -> super::Register { | ||
| 29 | super::Register::Common(self) | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | register!(EIE, 0, u8, { | ||
| 34 | #[doc = "Receive Error Interrupt Enable bit"] | ||
| 35 | rxerie @ 0, | ||
| 36 | #[doc = "Transmit Error Interrupt Enable bit"] | ||
| 37 | txerie @ 1, | ||
| 38 | #[doc = "Transmit Enable bit"] | ||
| 39 | txie @ 3, | ||
| 40 | #[doc = "Link Status Change Interrupt Enable bit"] | ||
| 41 | linkie @ 4, | ||
| 42 | #[doc = "DMA Interrupt Enable bit"] | ||
| 43 | dmaie @ 5, | ||
| 44 | #[doc = "Receive Packet Pending Interrupt Enable bit"] | ||
| 45 | pktie @ 6, | ||
| 46 | #[doc = "Global INT Interrupt Enable bit"] | ||
| 47 | intie @ 7, | ||
| 48 | }); | ||
| 49 | |||
| 50 | register!(EIR, 0, u8, { | ||
| 51 | #[doc = "Receive Error Interrupt Flag bit"] | ||
| 52 | rxerif @ 0, | ||
| 53 | #[doc = "Transmit Error Interrupt Flag bit"] | ||
| 54 | txerif @ 1, | ||
| 55 | #[doc = "Transmit Interrupt Flag bit"] | ||
| 56 | txif @ 3, | ||
| 57 | #[doc = "Link Change Interrupt Flag bit"] | ||
| 58 | linkif @ 4, | ||
| 59 | #[doc = "DMA Interrupt Flag bit"] | ||
| 60 | dmaif @ 5, | ||
| 61 | #[doc = "Receive Packet Pending Interrupt Flag bit"] | ||
| 62 | pktif @ 6, | ||
| 63 | }); | ||
| 64 | |||
| 65 | register!(ESTAT, 0, u8, { | ||
| 66 | #[doc = "Clock Ready bit"] | ||
| 67 | clkrdy @ 0, | ||
| 68 | #[doc = "Transmit Abort Error bit"] | ||
| 69 | txabrt @ 1, | ||
| 70 | #[doc = "Receive Busy bit"] | ||
| 71 | rxbusy @ 2, | ||
| 72 | #[doc = "Late Collision Error bit"] | ||
| 73 | latecol @ 4, | ||
| 74 | #[doc = "Ethernet Buffer Error Status bit"] | ||
| 75 | bufer @ 6, | ||
| 76 | #[doc = "INT Interrupt Flag bit"] | ||
| 77 | int @ 7, | ||
| 78 | }); | ||
| 79 | |||
| 80 | register!(ECON2, 0b1000_0000, u8, { | ||
| 81 | #[doc = "Voltage Regulator Power Save Enable bit"] | ||
| 82 | vrps @ 3, | ||
| 83 | #[doc = "Power Save Enable bit"] | ||
| 84 | pwrsv @ 5, | ||
| 85 | #[doc = "Packet Decrement bit"] | ||
| 86 | pktdec @ 6, | ||
| 87 | #[doc = "Automatic Buffer Pointer Increment Enable bit"] | ||
| 88 | autoinc @ 7, | ||
| 89 | }); | ||
| 90 | |||
| 91 | register!(ECON1, 0, u8, { | ||
| 92 | #[doc = "Bank Select bits"] | ||
| 93 | bsel @ 0..1, | ||
| 94 | #[doc = "Receive Enable bi"] | ||
| 95 | rxen @ 2, | ||
| 96 | #[doc = "Transmit Request to Send bit"] | ||
| 97 | txrts @ 3, | ||
| 98 | #[doc = "DMA Checksum Enable bit"] | ||
| 99 | csumen @ 4, | ||
| 100 | #[doc = "DMA Start and Busy Status bit"] | ||
| 101 | dmast @ 5, | ||
| 102 | #[doc = "Receive Logic Reset bit"] | ||
| 103 | rxrst @ 6, | ||
| 104 | #[doc = "Transmit Logic Reset bit"] | ||
| 105 | txrst @ 7, | ||
| 106 | }); | ||
diff --git a/embassy-net-enc28j60/src/fmt.rs b/embassy-net-enc28j60/src/fmt.rs new file mode 100644 index 000000000..066970813 --- /dev/null +++ b/embassy-net-enc28j60/src/fmt.rs | |||
| @@ -0,0 +1,225 @@ | |||
| 1 | #![macro_use] | ||
| 2 | #![allow(unused_macros)] | ||
| 3 | |||
| 4 | #[cfg(all(feature = "defmt", feature = "log"))] | ||
| 5 | compile_error!("You may not enable both `defmt` and `log` features."); | ||
| 6 | |||
| 7 | macro_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 | |||
| 18 | macro_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 | |||
| 29 | macro_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 | |||
| 40 | macro_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 | |||
| 51 | macro_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 | |||
| 62 | macro_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 | |||
| 73 | macro_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 | |||
| 84 | macro_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 | |||
| 95 | macro_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 | |||
| 106 | macro_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 | |||
| 119 | macro_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 | |||
| 132 | macro_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 | |||
| 145 | macro_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 | |||
| 158 | macro_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")] | ||
| 172 | macro_rules! unwrap { | ||
| 173 | ($($x:tt)*) => { | ||
| 174 | ::defmt::unwrap!($($x)*) | ||
| 175 | }; | ||
| 176 | } | ||
| 177 | |||
| 178 | #[cfg(not(feature = "defmt"))] | ||
| 179 | macro_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)] | ||
| 199 | pub struct NoneError; | ||
| 200 | |||
| 201 | pub trait Try { | ||
| 202 | type Ok; | ||
| 203 | type Error; | ||
| 204 | fn into_result(self) -> Result<Self::Ok, Self::Error>; | ||
| 205 | } | ||
| 206 | |||
| 207 | impl<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 | |||
| 217 | impl<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-net-enc28j60/src/header.rs b/embassy-net-enc28j60/src/header.rs new file mode 100644 index 000000000..c2d4e468f --- /dev/null +++ b/embassy-net-enc28j60/src/header.rs | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | register!(RxStatus, 0, u32, { | ||
| 2 | #[doc = "Indicates length of the received frame"] | ||
| 3 | byte_count @ 0..15, | ||
| 4 | #[doc = "Indicates a packet over 50,000 bit times occurred or that a packet was dropped since the last receive"] | ||
| 5 | long_event @ 16, | ||
| 6 | #[doc = "Indicates that at some time since the last receive, a carrier event was detected"] | ||
| 7 | carrier_event @ 18, | ||
| 8 | #[doc = "Indicates that frame CRC field value does not match the CRC calculated by the MAC"] | ||
| 9 | crc_error @ 20, | ||
| 10 | #[doc = "Indicates that frame length field value in the packet does not match the actual data byte length and specifies a valid length"] | ||
| 11 | length_check_error @ 21, | ||
| 12 | #[doc = "Indicates that frame type/length field was larger than 1500 bytes (type field)"] | ||
| 13 | length_out_of_range @ 22, | ||
| 14 | #[doc = "Indicates that at the packet had a valid CRC and no symbol errors"] | ||
| 15 | received_ok @ 23, | ||
| 16 | #[doc = "Indicates packet received had a valid Multicast address"] | ||
| 17 | multicast @ 24, | ||
| 18 | #[doc = "Indicates packet received had a valid Broadcast address."] | ||
| 19 | broadcast @ 25, | ||
| 20 | #[doc = "Indicates that after the end of this packet, an additional 1 to 7 bits were received"] | ||
| 21 | dribble_nibble @ 26, | ||
| 22 | #[doc = "Current frame was recognized as a control frame for having a valid type/length designating it as a control frame"] | ||
| 23 | receive_control_frame @ 27, | ||
| 24 | #[doc = "Current frame was recognized as a control frame containing a valid pause frame opcode and a valid destination address"] | ||
| 25 | receive_pause_control_frame @ 28, | ||
| 26 | #[doc = "Current frame was recognized as a control frame but it contained an unknown opcode"] | ||
| 27 | receive_unknown_opcode @ 29, | ||
| 28 | #[doc = "Current frame was recognized as a VLAN tagged frame"] | ||
| 29 | receive_vlan_type_detected @ 30, | ||
| 30 | }); | ||
diff --git a/embassy-net-enc28j60/src/lib.rs b/embassy-net-enc28j60/src/lib.rs new file mode 100644 index 000000000..b44cefaf2 --- /dev/null +++ b/embassy-net-enc28j60/src/lib.rs | |||
| @@ -0,0 +1,717 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![doc = include_str!("../README.md")] | ||
| 3 | #![warn(missing_docs)] | ||
| 4 | |||
| 5 | // must go first. | ||
| 6 | mod fmt; | ||
| 7 | |||
| 8 | #[macro_use] | ||
| 9 | mod macros; | ||
| 10 | mod bank0; | ||
| 11 | mod bank1; | ||
| 12 | mod bank2; | ||
| 13 | mod bank3; | ||
| 14 | mod common; | ||
| 15 | mod header; | ||
| 16 | mod phy; | ||
| 17 | mod traits; | ||
| 18 | |||
| 19 | use core::cmp; | ||
| 20 | use core::convert::TryInto; | ||
| 21 | |||
| 22 | use embassy_net_driver::{Capabilities, HardwareAddress, LinkState, Medium}; | ||
| 23 | use embassy_time::Duration; | ||
| 24 | use embedded_hal::digital::OutputPin; | ||
| 25 | use embedded_hal::spi::{Operation, SpiDevice}; | ||
| 26 | use traits::U16Ext; | ||
| 27 | |||
| 28 | // Total buffer size (see section 3.2) | ||
| 29 | const BUF_SZ: u16 = 8 * 1024; | ||
| 30 | |||
| 31 | // Maximum frame length | ||
| 32 | const MAX_FRAME_LENGTH: u16 = 1518; // value recommended in the data sheet | ||
| 33 | |||
| 34 | // Size of the Frame check sequence (32-bit CRC) | ||
| 35 | const CRC_SZ: u16 = 4; | ||
| 36 | |||
| 37 | // define the boundaries of the TX and RX buffers | ||
| 38 | // to workaround errata #5 we do the opposite of what section 6.1 of the data sheet | ||
| 39 | // says: we place the RX buffer at address 0 and the TX buffer after it | ||
| 40 | const RXST: u16 = 0x0000; | ||
| 41 | const RXND: u16 = 0x19ff; | ||
| 42 | const TXST: u16 = 0x1a00; | ||
| 43 | const _TXND: u16 = 0x1fff; | ||
| 44 | |||
| 45 | const MTU: usize = 1514; // 1500 IP + 14 ethernet header | ||
| 46 | |||
| 47 | /// ENC28J60 embassy-net driver | ||
| 48 | pub struct Enc28j60<S, O> { | ||
| 49 | mac_addr: [u8; 6], | ||
| 50 | |||
| 51 | spi: S, | ||
| 52 | rst: Option<O>, | ||
| 53 | |||
| 54 | bank: Bank, | ||
| 55 | |||
| 56 | // address of the next packet in buffer memory | ||
| 57 | next_packet: u16, | ||
| 58 | } | ||
| 59 | |||
| 60 | impl<S, O> Enc28j60<S, O> | ||
| 61 | where | ||
| 62 | S: SpiDevice, | ||
| 63 | O: OutputPin, | ||
| 64 | { | ||
| 65 | /// Create a new ENC28J60 driver instance. | ||
| 66 | /// | ||
| 67 | /// The RST pin is optional. If None, reset will be done with a SPI | ||
| 68 | /// soft reset command, instead of via the RST pin. | ||
| 69 | pub fn new(spi: S, rst: Option<O>, mac_addr: [u8; 6]) -> Self { | ||
| 70 | let mut res = Self { | ||
| 71 | mac_addr, | ||
| 72 | spi, | ||
| 73 | rst, | ||
| 74 | |||
| 75 | bank: Bank::Bank0, | ||
| 76 | next_packet: RXST, | ||
| 77 | }; | ||
| 78 | res.init(); | ||
| 79 | res | ||
| 80 | } | ||
| 81 | |||
| 82 | fn init(&mut self) { | ||
| 83 | if let Some(rst) = &mut self.rst { | ||
| 84 | rst.set_low().unwrap(); | ||
| 85 | embassy_time::block_for(Duration::from_millis(5)); | ||
| 86 | rst.set_high().unwrap(); | ||
| 87 | embassy_time::block_for(Duration::from_millis(5)); | ||
| 88 | } else { | ||
| 89 | embassy_time::block_for(Duration::from_millis(5)); | ||
| 90 | self.soft_reset(); | ||
| 91 | embassy_time::block_for(Duration::from_millis(5)); | ||
| 92 | } | ||
| 93 | |||
| 94 | debug!( | ||
| 95 | "enc28j60: erevid {=u8:x}", | ||
| 96 | self.read_control_register(bank3::Register::EREVID) | ||
| 97 | ); | ||
| 98 | debug!("enc28j60: waiting for clk"); | ||
| 99 | while common::ESTAT(self.read_control_register(common::Register::ESTAT)).clkrdy() == 0 {} | ||
| 100 | debug!("enc28j60: clk ok"); | ||
| 101 | |||
| 102 | if self.read_control_register(bank3::Register::EREVID) == 0 { | ||
| 103 | panic!("ErevidIsZero"); | ||
| 104 | } | ||
| 105 | |||
| 106 | // disable CLKOUT output | ||
| 107 | self.write_control_register(bank3::Register::ECOCON, 0); | ||
| 108 | |||
| 109 | self.init_rx(); | ||
| 110 | |||
| 111 | // TX start | ||
| 112 | // "It is recommended that an even address be used for ETXST" | ||
| 113 | debug_assert_eq!(TXST % 2, 0); | ||
| 114 | self.write_control_register(bank0::Register::ETXSTL, TXST.low()); | ||
| 115 | self.write_control_register(bank0::Register::ETXSTH, TXST.high()); | ||
| 116 | |||
| 117 | // TX end is set in `transmit` | ||
| 118 | |||
| 119 | // MAC initialization (see section 6.5) | ||
| 120 | // 1. Set the MARXEN bit in MACON1 to enable the MAC to receive frames. | ||
| 121 | self.write_control_register( | ||
| 122 | bank2::Register::MACON1, | ||
| 123 | bank2::MACON1::default().marxen(1).passall(0).rxpaus(1).txpaus(1).bits(), | ||
| 124 | ); | ||
| 125 | |||
| 126 | // 2. Configure the PADCFG, TXCRCEN and FULDPX bits of MACON3. | ||
| 127 | self.write_control_register( | ||
| 128 | bank2::Register::MACON3, | ||
| 129 | bank2::MACON3::default().frmlnen(1).txcrcen(1).padcfg(0b001).bits(), | ||
| 130 | ); | ||
| 131 | |||
| 132 | // 4. Program the MAMXFL registers with the maximum frame length to be permitted to be | ||
| 133 | // received or transmitted | ||
| 134 | self.write_control_register(bank2::Register::MAMXFLL, MAX_FRAME_LENGTH.low()); | ||
| 135 | self.write_control_register(bank2::Register::MAMXFLH, MAX_FRAME_LENGTH.high()); | ||
| 136 | |||
| 137 | // 5. Configure the Back-to-Back Inter-Packet Gap register, MABBIPG. | ||
| 138 | // Use recommended value of 0x12 | ||
| 139 | self.write_control_register(bank2::Register::MABBIPG, 0x12); | ||
| 140 | |||
| 141 | // 6. Configure the Non-Back-to-Back Inter-Packet Gap register low byte, MAIPGL. | ||
| 142 | // Use recommended value of 0x12 | ||
| 143 | self.write_control_register(bank2::Register::MAIPGL, 0x12); | ||
| 144 | self.write_control_register(bank2::Register::MAIPGH, 0x0c); | ||
| 145 | |||
| 146 | // 9. Program the local MAC address into the MAADR1:MAADR6 registers | ||
| 147 | self.write_control_register(bank3::Register::MAADR1, self.mac_addr[0]); | ||
| 148 | self.write_control_register(bank3::Register::MAADR2, self.mac_addr[1]); | ||
| 149 | self.write_control_register(bank3::Register::MAADR3, self.mac_addr[2]); | ||
| 150 | self.write_control_register(bank3::Register::MAADR4, self.mac_addr[3]); | ||
| 151 | self.write_control_register(bank3::Register::MAADR5, self.mac_addr[4]); | ||
| 152 | self.write_control_register(bank3::Register::MAADR6, self.mac_addr[5]); | ||
| 153 | |||
| 154 | // Set the PHCON2.HDLDIS bit to prevent automatic loopback of the data which is transmitted | ||
| 155 | self.write_phy_register(phy::Register::PHCON2, phy::PHCON2::default().hdldis(1).bits()); | ||
| 156 | |||
| 157 | // Globally enable interrupts | ||
| 158 | //self.bit_field_set(common::Register::EIE, common::EIE::mask().intie()); | ||
| 159 | |||
| 160 | // Set the per packet control byte; we'll always use the value 0 | ||
| 161 | self.write_buffer_memory(Some(TXST), &mut [0]); | ||
| 162 | |||
| 163 | // Enable reception | ||
| 164 | self.bit_field_set(common::Register::ECON1, common::ECON1::mask().rxen()); | ||
| 165 | } | ||
| 166 | |||
| 167 | fn init_rx(&mut self) { | ||
| 168 | // RX start | ||
| 169 | // "It is recommended that the ERXST Pointer be programmed with an even address" | ||
| 170 | self.write_control_register(bank0::Register::ERXSTL, RXST.low()); | ||
| 171 | self.write_control_register(bank0::Register::ERXSTH, RXST.high()); | ||
| 172 | |||
| 173 | // RX read pointer | ||
| 174 | // NOTE Errata #14 so we are using an *odd* address here instead of ERXST | ||
| 175 | self.write_control_register(bank0::Register::ERXRDPTL, RXND.low()); | ||
| 176 | self.write_control_register(bank0::Register::ERXRDPTH, RXND.high()); | ||
| 177 | |||
| 178 | // RX end | ||
| 179 | self.write_control_register(bank0::Register::ERXNDL, RXND.low()); | ||
| 180 | self.write_control_register(bank0::Register::ERXNDH, RXND.high()); | ||
| 181 | |||
| 182 | // decrease the packet count to 0 | ||
| 183 | while self.read_control_register(bank1::Register::EPKTCNT) != 0 { | ||
| 184 | self.bit_field_set(common::Register::ECON2, common::ECON2::mask().pktdec()); | ||
| 185 | } | ||
| 186 | |||
| 187 | self.next_packet = RXST; | ||
| 188 | } | ||
| 189 | |||
| 190 | fn reset_rx(&mut self) { | ||
| 191 | self.bit_field_set(common::Register::ECON1, common::ECON1::mask().rxrst()); | ||
| 192 | self.bit_field_clear(common::Register::ECON1, common::ECON1::mask().rxrst()); | ||
| 193 | self.init_rx(); | ||
| 194 | self.bit_field_set(common::Register::ECON1, common::ECON1::mask().rxen()); | ||
| 195 | } | ||
| 196 | |||
| 197 | /// Flushes the transmit buffer, ensuring all pending transmissions have completed | ||
| 198 | /// NOTE: The returned packet *must* be `read` or `ignore`-d, otherwise this method will always | ||
| 199 | /// return `None` on subsequent invocations | ||
| 200 | pub fn receive<'a>(&mut self, buf: &'a mut [u8]) -> Option<&'a mut [u8]> { | ||
| 201 | if self.pending_packets() == 0 { | ||
| 202 | // Errata #6: we can't rely on PKTIF so we check PKTCNT | ||
| 203 | return None; | ||
| 204 | } | ||
| 205 | |||
| 206 | let curr_packet = self.next_packet; | ||
| 207 | |||
| 208 | // read out the first 6 bytes | ||
| 209 | let mut temp_buf = [0; 6]; | ||
| 210 | self.read_buffer_memory(Some(curr_packet), &mut temp_buf); | ||
| 211 | |||
| 212 | // next packet pointer | ||
| 213 | let next_packet = u16::from_parts(temp_buf[0], temp_buf[1]); | ||
| 214 | // status vector | ||
| 215 | let status = header::RxStatus(u32::from_le_bytes(temp_buf[2..].try_into().unwrap())); | ||
| 216 | let len_with_crc = status.byte_count() as u16; | ||
| 217 | |||
| 218 | if len_with_crc < CRC_SZ || len_with_crc > 1600 || next_packet > RXND { | ||
| 219 | warn!("RX buffer corrupted, resetting RX logic to recover..."); | ||
| 220 | self.reset_rx(); | ||
| 221 | return None; | ||
| 222 | } | ||
| 223 | |||
| 224 | let len = len_with_crc - CRC_SZ; | ||
| 225 | self.read_buffer_memory(None, &mut buf[..len as usize]); | ||
| 226 | |||
| 227 | // update ERXRDPT | ||
| 228 | // due to Errata #14 we must write an odd address to ERXRDPT | ||
| 229 | // we know that ERXST = 0, that ERXND is odd and that next_packet is even | ||
| 230 | let rxrdpt = if self.next_packet < 1 || self.next_packet > RXND + 1 { | ||
| 231 | RXND | ||
| 232 | } else { | ||
| 233 | self.next_packet - 1 | ||
| 234 | }; | ||
| 235 | // "To move ERXRDPT, the host controller must write to ERXRDPTL first." | ||
| 236 | self.write_control_register(bank0::Register::ERXRDPTL, rxrdpt.low()); | ||
| 237 | self.write_control_register(bank0::Register::ERXRDPTH, rxrdpt.high()); | ||
| 238 | |||
| 239 | // decrease the packet count | ||
| 240 | self.bit_field_set(common::Register::ECON2, common::ECON2::mask().pktdec()); | ||
| 241 | |||
| 242 | self.next_packet = next_packet; | ||
| 243 | |||
| 244 | Some(&mut buf[..len as usize]) | ||
| 245 | } | ||
| 246 | |||
| 247 | fn wait_tx_ready(&mut self) { | ||
| 248 | for _ in 0u32..10000 { | ||
| 249 | if common::ECON1(self.read_control_register(common::Register::ECON1)).txrts() == 0 { | ||
| 250 | return; | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | // work around errata #12 by resetting the transmit logic before every new | ||
| 255 | // transmission | ||
| 256 | self.bit_field_set(common::Register::ECON1, common::ECON1::mask().txrst()); | ||
| 257 | self.bit_field_clear(common::Register::ECON1, common::ECON1::mask().txrst()); | ||
| 258 | //self.bit_field_clear(common::Register::EIR, { | ||
| 259 | // let mask = common::EIR::mask(); | ||
| 260 | // mask.txerif() | mask.txif() | ||
| 261 | //}); | ||
| 262 | } | ||
| 263 | |||
| 264 | /// Starts the transmission of `bytes` | ||
| 265 | /// | ||
| 266 | /// It's up to the caller to ensure that `bytes` is a valid Ethernet frame. The interface will | ||
| 267 | /// take care of appending a (4 byte) CRC to the frame and of padding the frame to the minimum | ||
| 268 | /// size allowed by the Ethernet specification (64 bytes, or 46 bytes of payload). | ||
| 269 | /// | ||
| 270 | /// NOTE This method will flush any previous transmission that's in progress | ||
| 271 | /// | ||
| 272 | /// # Panics | ||
| 273 | /// | ||
| 274 | /// If `bytes` length is greater than 1514, the maximum frame length allowed by the interface, | ||
| 275 | /// or greater than the transmit buffer | ||
| 276 | pub fn transmit(&mut self, bytes: &[u8]) { | ||
| 277 | assert!(bytes.len() <= self.mtu() as usize); | ||
| 278 | |||
| 279 | self.wait_tx_ready(); | ||
| 280 | |||
| 281 | // NOTE the plus one is to not overwrite the per packet control byte | ||
| 282 | let wrpt = TXST + 1; | ||
| 283 | |||
| 284 | // 1. ETXST was set during initialization | ||
| 285 | |||
| 286 | // 2. write the frame to the IC memory | ||
| 287 | self.write_buffer_memory(Some(wrpt), bytes); | ||
| 288 | |||
| 289 | let txnd = wrpt + bytes.len() as u16 - 1; | ||
| 290 | |||
| 291 | // 3. Set the end address of the transmit buffer | ||
| 292 | self.write_control_register(bank0::Register::ETXNDL, txnd.low()); | ||
| 293 | self.write_control_register(bank0::Register::ETXNDH, txnd.high()); | ||
| 294 | |||
| 295 | // 4. reset interrupt flag | ||
| 296 | //self.bit_field_clear(common::Register::EIR, common::EIR::mask().txif()); | ||
| 297 | |||
| 298 | // 5. start transmission | ||
| 299 | self.bit_field_set(common::Register::ECON1, common::ECON1::mask().txrts()); | ||
| 300 | |||
| 301 | // Wait until transmission finishes | ||
| 302 | //while common::ECON1(self.read_control_register(common::Register::ECON1)).txrts() == 1 {} | ||
| 303 | |||
| 304 | /* | ||
| 305 | // read the transmit status vector | ||
| 306 | let mut tx_stat = [0; 7]; | ||
| 307 | self.read_buffer_memory(None, &mut tx_stat); | ||
| 308 | |||
| 309 | let stat = common::ESTAT(self.read_control_register(common::Register::ESTAT)); | ||
| 310 | |||
| 311 | if stat.txabrt() == 1 { | ||
| 312 | // work around errata #12 by reading the transmit status vector | ||
| 313 | if stat.latecol() == 1 || (tx_stat[2] & (1 << 5)) != 0 { | ||
| 314 | panic!("LateCollision") | ||
| 315 | } else { | ||
| 316 | panic!("TransmitAbort") | ||
| 317 | } | ||
| 318 | }*/ | ||
| 319 | } | ||
| 320 | |||
| 321 | /// Get whether the link is up | ||
| 322 | pub fn is_link_up(&mut self) -> bool { | ||
| 323 | let bits = self.read_phy_register(phy::Register::PHSTAT2); | ||
| 324 | phy::PHSTAT2(bits).lstat() == 1 | ||
| 325 | } | ||
| 326 | |||
| 327 | /// Returns the interface Maximum Transmission Unit (MTU) | ||
| 328 | /// | ||
| 329 | /// The value returned by this function will never exceed 1514 bytes. The actual value depends | ||
| 330 | /// on the memory assigned to the transmission buffer when initializing the device | ||
| 331 | pub fn mtu(&self) -> u16 { | ||
| 332 | cmp::min(BUF_SZ - RXND - 1, MAX_FRAME_LENGTH - CRC_SZ) | ||
| 333 | } | ||
| 334 | |||
| 335 | /* Miscellaneous */ | ||
| 336 | /// Returns the number of packets that have been received but have not been processed yet | ||
| 337 | pub fn pending_packets(&mut self) -> u8 { | ||
| 338 | self.read_control_register(bank1::Register::EPKTCNT) | ||
| 339 | } | ||
| 340 | |||
| 341 | /// Adjusts the receive filter to *accept* these packet types | ||
| 342 | pub fn accept(&mut self, packets: &[Packet]) { | ||
| 343 | let mask = bank1::ERXFCON::mask(); | ||
| 344 | let mut val = 0; | ||
| 345 | for packet in packets { | ||
| 346 | match packet { | ||
| 347 | Packet::Broadcast => val |= mask.bcen(), | ||
| 348 | Packet::Multicast => val |= mask.mcen(), | ||
| 349 | Packet::Unicast => val |= mask.ucen(), | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 353 | self.bit_field_set(bank1::Register::ERXFCON, val) | ||
| 354 | } | ||
| 355 | |||
| 356 | /// Adjusts the receive filter to *ignore* these packet types | ||
| 357 | pub fn ignore(&mut self, packets: &[Packet]) { | ||
| 358 | let mask = bank1::ERXFCON::mask(); | ||
| 359 | let mut val = 0; | ||
| 360 | for packet in packets { | ||
| 361 | match packet { | ||
| 362 | Packet::Broadcast => val |= mask.bcen(), | ||
| 363 | Packet::Multicast => val |= mask.mcen(), | ||
| 364 | Packet::Unicast => val |= mask.ucen(), | ||
| 365 | } | ||
| 366 | } | ||
| 367 | |||
| 368 | self.bit_field_clear(bank1::Register::ERXFCON, val) | ||
| 369 | } | ||
| 370 | |||
| 371 | /* Private */ | ||
| 372 | /* Read */ | ||
| 373 | fn read_control_register<R>(&mut self, register: R) -> u8 | ||
| 374 | where | ||
| 375 | R: Into<Register>, | ||
| 376 | { | ||
| 377 | self._read_control_register(register.into()) | ||
| 378 | } | ||
| 379 | |||
| 380 | fn _read_control_register(&mut self, register: Register) -> u8 { | ||
| 381 | self.change_bank(register); | ||
| 382 | |||
| 383 | if register.is_eth_register() { | ||
| 384 | let mut buffer = [Instruction::RCR.opcode() | register.addr(), 0]; | ||
| 385 | self.spi.transfer_in_place(&mut buffer).unwrap(); | ||
| 386 | buffer[1] | ||
| 387 | } else { | ||
| 388 | // MAC, MII regs need a dummy byte. | ||
| 389 | let mut buffer = [Instruction::RCR.opcode() | register.addr(), 0, 0]; | ||
| 390 | self.spi.transfer_in_place(&mut buffer).unwrap(); | ||
| 391 | buffer[2] | ||
| 392 | } | ||
| 393 | } | ||
| 394 | |||
| 395 | fn read_phy_register(&mut self, register: phy::Register) -> u16 { | ||
| 396 | // set PHY register address | ||
| 397 | self.write_control_register(bank2::Register::MIREGADR, register.addr()); | ||
| 398 | |||
| 399 | // start read operation | ||
| 400 | self.write_control_register(bank2::Register::MICMD, bank2::MICMD::default().miird(1).bits()); | ||
| 401 | |||
| 402 | // wait until the read operation finishes | ||
| 403 | while self.read_control_register(bank3::Register::MISTAT) & 0b1 != 0 {} | ||
| 404 | |||
| 405 | self.write_control_register(bank2::Register::MICMD, bank2::MICMD::default().miird(0).bits()); | ||
| 406 | |||
| 407 | let l = self.read_control_register(bank2::Register::MIRDL); | ||
| 408 | let h = self.read_control_register(bank2::Register::MIRDH); | ||
| 409 | (l as u16) | (h as u16) << 8 | ||
| 410 | } | ||
| 411 | |||
| 412 | /* Write */ | ||
| 413 | fn _write_control_register(&mut self, register: Register, value: u8) { | ||
| 414 | self.change_bank(register); | ||
| 415 | |||
| 416 | let buffer = [Instruction::WCR.opcode() | register.addr(), value]; | ||
| 417 | self.spi.write(&buffer).unwrap(); | ||
| 418 | } | ||
| 419 | |||
| 420 | fn write_control_register<R>(&mut self, register: R, value: u8) | ||
| 421 | where | ||
| 422 | R: Into<Register>, | ||
| 423 | { | ||
| 424 | self._write_control_register(register.into(), value) | ||
| 425 | } | ||
| 426 | |||
| 427 | fn write_phy_register(&mut self, register: phy::Register, value: u16) { | ||
| 428 | // set PHY register address | ||
| 429 | self.write_control_register(bank2::Register::MIREGADR, register.addr()); | ||
| 430 | |||
| 431 | self.write_control_register(bank2::Register::MIWRL, (value & 0xff) as u8); | ||
| 432 | // this starts the write operation | ||
| 433 | self.write_control_register(bank2::Register::MIWRH, (value >> 8) as u8); | ||
| 434 | |||
| 435 | // wait until the write operation finishes | ||
| 436 | while self.read_control_register(bank3::Register::MISTAT) & 0b1 != 0 {} | ||
| 437 | } | ||
| 438 | |||
| 439 | /* RMW */ | ||
| 440 | fn modify_control_register<R, F>(&mut self, register: R, f: F) | ||
| 441 | where | ||
| 442 | F: FnOnce(u8) -> u8, | ||
| 443 | R: Into<Register>, | ||
| 444 | { | ||
| 445 | self._modify_control_register(register.into(), f) | ||
| 446 | } | ||
| 447 | |||
| 448 | fn _modify_control_register<F>(&mut self, register: Register, f: F) | ||
| 449 | where | ||
| 450 | F: FnOnce(u8) -> u8, | ||
| 451 | { | ||
| 452 | let r = self._read_control_register(register); | ||
| 453 | self._write_control_register(register, f(r)) | ||
| 454 | } | ||
| 455 | |||
| 456 | /* Auxiliary */ | ||
| 457 | fn change_bank(&mut self, register: Register) { | ||
| 458 | let bank = register.bank(); | ||
| 459 | |||
| 460 | if let Some(bank) = bank { | ||
| 461 | if self.bank == bank { | ||
| 462 | // already on the register bank | ||
| 463 | return; | ||
| 464 | } | ||
| 465 | |||
| 466 | // change bank | ||
| 467 | self.bank = bank; | ||
| 468 | match bank { | ||
| 469 | Bank::Bank0 => self.bit_field_clear(common::Register::ECON1, 0b11), | ||
| 470 | Bank::Bank1 => self.modify_control_register(common::Register::ECON1, |r| (r & !0b11) | 0b01), | ||
| 471 | Bank::Bank2 => self.modify_control_register(common::Register::ECON1, |r| (r & !0b11) | 0b10), | ||
| 472 | Bank::Bank3 => self.bit_field_set(common::Register::ECON1, 0b11), | ||
| 473 | } | ||
| 474 | } else { | ||
| 475 | // common register | ||
| 476 | } | ||
| 477 | } | ||
| 478 | |||
| 479 | /* Primitive operations */ | ||
| 480 | fn bit_field_clear<R>(&mut self, register: R, mask: u8) | ||
| 481 | where | ||
| 482 | R: Into<Register>, | ||
| 483 | { | ||
| 484 | self._bit_field_clear(register.into(), mask) | ||
| 485 | } | ||
| 486 | |||
| 487 | fn _bit_field_clear(&mut self, register: Register, mask: u8) { | ||
| 488 | debug_assert!(register.is_eth_register()); | ||
| 489 | |||
| 490 | self.change_bank(register); | ||
| 491 | |||
| 492 | self.spi | ||
| 493 | .write(&[Instruction::BFC.opcode() | register.addr(), mask]) | ||
| 494 | .unwrap(); | ||
| 495 | } | ||
| 496 | |||
| 497 | fn bit_field_set<R>(&mut self, register: R, mask: u8) | ||
| 498 | where | ||
| 499 | R: Into<Register>, | ||
| 500 | { | ||
| 501 | self._bit_field_set(register.into(), mask) | ||
| 502 | } | ||
| 503 | |||
| 504 | fn _bit_field_set(&mut self, register: Register, mask: u8) { | ||
| 505 | debug_assert!(register.is_eth_register()); | ||
| 506 | |||
| 507 | self.change_bank(register); | ||
| 508 | |||
| 509 | self.spi | ||
| 510 | .write(&[Instruction::BFS.opcode() | register.addr(), mask]) | ||
| 511 | .unwrap(); | ||
| 512 | } | ||
| 513 | |||
| 514 | fn read_buffer_memory(&mut self, addr: Option<u16>, buf: &mut [u8]) { | ||
| 515 | if let Some(addr) = addr { | ||
| 516 | self.write_control_register(bank0::Register::ERDPTL, addr.low()); | ||
| 517 | self.write_control_register(bank0::Register::ERDPTH, addr.high()); | ||
| 518 | } | ||
| 519 | |||
| 520 | self.spi | ||
| 521 | .transaction(&mut [Operation::Write(&[Instruction::RBM.opcode()]), Operation::Read(buf)]) | ||
| 522 | .unwrap(); | ||
| 523 | } | ||
| 524 | |||
| 525 | fn soft_reset(&mut self) { | ||
| 526 | self.spi.write(&[Instruction::SRC.opcode()]).unwrap(); | ||
| 527 | } | ||
| 528 | |||
| 529 | fn write_buffer_memory(&mut self, addr: Option<u16>, buffer: &[u8]) { | ||
| 530 | if let Some(addr) = addr { | ||
| 531 | self.write_control_register(bank0::Register::EWRPTL, addr.low()); | ||
| 532 | self.write_control_register(bank0::Register::EWRPTH, addr.high()); | ||
| 533 | } | ||
| 534 | |||
| 535 | self.spi | ||
| 536 | .transaction(&mut [Operation::Write(&[Instruction::WBM.opcode()]), Operation::Write(buffer)]) | ||
| 537 | .unwrap(); | ||
| 538 | } | ||
| 539 | } | ||
| 540 | |||
| 541 | #[derive(Clone, Copy, PartialEq)] | ||
| 542 | enum Bank { | ||
| 543 | Bank0, | ||
| 544 | Bank1, | ||
| 545 | Bank2, | ||
| 546 | Bank3, | ||
| 547 | } | ||
| 548 | |||
| 549 | #[derive(Clone, Copy)] | ||
| 550 | enum Instruction { | ||
| 551 | /// Read Control Register | ||
| 552 | RCR = 0b000_00000, | ||
| 553 | /// Read Buffer Memory | ||
| 554 | RBM = 0b001_11010, | ||
| 555 | /// Write Control Register | ||
| 556 | WCR = 0b010_00000, | ||
| 557 | /// Write Buffer Memory | ||
| 558 | WBM = 0b011_11010, | ||
| 559 | /// Bit Field Set | ||
| 560 | BFS = 0b100_00000, | ||
| 561 | /// Bit Field Clear | ||
| 562 | BFC = 0b101_00000, | ||
| 563 | /// System Reset Command | ||
| 564 | SRC = 0b111_11111, | ||
| 565 | } | ||
| 566 | |||
| 567 | impl Instruction { | ||
| 568 | fn opcode(&self) -> u8 { | ||
| 569 | *self as u8 | ||
| 570 | } | ||
| 571 | } | ||
| 572 | |||
| 573 | #[derive(Clone, Copy)] | ||
| 574 | enum Register { | ||
| 575 | Bank0(bank0::Register), | ||
| 576 | Bank1(bank1::Register), | ||
| 577 | Bank2(bank2::Register), | ||
| 578 | Bank3(bank3::Register), | ||
| 579 | Common(common::Register), | ||
| 580 | } | ||
| 581 | |||
| 582 | impl Register { | ||
| 583 | fn addr(&self) -> u8 { | ||
| 584 | match *self { | ||
| 585 | Register::Bank0(r) => r.addr(), | ||
| 586 | Register::Bank1(r) => r.addr(), | ||
| 587 | Register::Bank2(r) => r.addr(), | ||
| 588 | Register::Bank3(r) => r.addr(), | ||
| 589 | Register::Common(r) => r.addr(), | ||
| 590 | } | ||
| 591 | } | ||
| 592 | |||
| 593 | fn bank(&self) -> Option<Bank> { | ||
| 594 | Some(match *self { | ||
| 595 | Register::Bank0(_) => Bank::Bank0, | ||
| 596 | Register::Bank1(_) => Bank::Bank1, | ||
| 597 | Register::Bank2(_) => Bank::Bank2, | ||
| 598 | Register::Bank3(_) => Bank::Bank3, | ||
| 599 | Register::Common(_) => return None, | ||
| 600 | }) | ||
| 601 | } | ||
| 602 | |||
| 603 | fn is_eth_register(&self) -> bool { | ||
| 604 | match *self { | ||
| 605 | Register::Bank0(r) => r.is_eth_register(), | ||
| 606 | Register::Bank1(r) => r.is_eth_register(), | ||
| 607 | Register::Bank2(r) => r.is_eth_register(), | ||
| 608 | Register::Bank3(r) => r.is_eth_register(), | ||
| 609 | Register::Common(r) => r.is_eth_register(), | ||
| 610 | } | ||
| 611 | } | ||
| 612 | } | ||
| 613 | |||
| 614 | /// Packet type, used to configure receive filters | ||
| 615 | #[non_exhaustive] | ||
| 616 | #[derive(Clone, Copy, Eq, PartialEq)] | ||
| 617 | pub enum Packet { | ||
| 618 | /// Broadcast packets | ||
| 619 | Broadcast, | ||
| 620 | /// Multicast packets | ||
| 621 | Multicast, | ||
| 622 | /// Unicast packets | ||
| 623 | Unicast, | ||
| 624 | } | ||
| 625 | |||
| 626 | static mut TX_BUF: [u8; MTU] = [0; MTU]; | ||
| 627 | static mut RX_BUF: [u8; MTU] = [0; MTU]; | ||
| 628 | |||
| 629 | impl<S, O> embassy_net_driver::Driver for Enc28j60<S, O> | ||
| 630 | where | ||
| 631 | S: SpiDevice, | ||
| 632 | O: OutputPin, | ||
| 633 | { | ||
| 634 | type RxToken<'a> = RxToken<'a> | ||
| 635 | where | ||
| 636 | Self: 'a; | ||
| 637 | |||
| 638 | type TxToken<'a> = TxToken<'a, S, O> | ||
| 639 | where | ||
| 640 | Self: 'a; | ||
| 641 | |||
| 642 | fn receive(&mut self, cx: &mut core::task::Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { | ||
| 643 | let rx_buf = unsafe { &mut RX_BUF }; | ||
| 644 | let tx_buf = unsafe { &mut TX_BUF }; | ||
| 645 | if let Some(pkt) = self.receive(rx_buf) { | ||
| 646 | let n = pkt.len(); | ||
| 647 | Some((RxToken { buf: &mut pkt[..n] }, TxToken { buf: tx_buf, eth: self })) | ||
| 648 | } else { | ||
| 649 | cx.waker().wake_by_ref(); | ||
| 650 | None | ||
| 651 | } | ||
| 652 | } | ||
| 653 | |||
| 654 | fn transmit(&mut self, _cx: &mut core::task::Context) -> Option<Self::TxToken<'_>> { | ||
| 655 | let tx_buf = unsafe { &mut TX_BUF }; | ||
| 656 | Some(TxToken { buf: tx_buf, eth: self }) | ||
| 657 | } | ||
| 658 | |||
| 659 | fn link_state(&mut self, cx: &mut core::task::Context) -> LinkState { | ||
| 660 | cx.waker().wake_by_ref(); | ||
| 661 | match self.is_link_up() { | ||
| 662 | true => LinkState::Up, | ||
| 663 | false => LinkState::Down, | ||
| 664 | } | ||
| 665 | } | ||
| 666 | |||
| 667 | fn capabilities(&self) -> Capabilities { | ||
| 668 | let mut caps = Capabilities::default(); | ||
| 669 | caps.max_transmission_unit = MTU; | ||
| 670 | caps.medium = Medium::Ethernet; | ||
| 671 | caps | ||
| 672 | } | ||
| 673 | |||
| 674 | fn hardware_address(&self) -> HardwareAddress { | ||
| 675 | HardwareAddress::Ethernet(self.mac_addr) | ||
| 676 | } | ||
| 677 | } | ||
| 678 | |||
| 679 | /// embassy-net RX token. | ||
| 680 | pub struct RxToken<'a> { | ||
| 681 | buf: &'a mut [u8], | ||
| 682 | } | ||
| 683 | |||
| 684 | impl<'a> embassy_net_driver::RxToken for RxToken<'a> { | ||
| 685 | fn consume<R, F>(self, f: F) -> R | ||
| 686 | where | ||
| 687 | F: FnOnce(&mut [u8]) -> R, | ||
| 688 | { | ||
| 689 | f(self.buf) | ||
| 690 | } | ||
| 691 | } | ||
| 692 | |||
| 693 | /// embassy-net TX token. | ||
| 694 | pub struct TxToken<'a, S, O> | ||
| 695 | where | ||
| 696 | S: SpiDevice, | ||
| 697 | O: OutputPin, | ||
| 698 | { | ||
| 699 | eth: &'a mut Enc28j60<S, O>, | ||
| 700 | buf: &'a mut [u8], | ||
| 701 | } | ||
| 702 | |||
| 703 | impl<'a, S, O> embassy_net_driver::TxToken for TxToken<'a, S, O> | ||
| 704 | where | ||
| 705 | S: SpiDevice, | ||
| 706 | O: OutputPin, | ||
| 707 | { | ||
| 708 | fn consume<R, F>(self, len: usize, f: F) -> R | ||
| 709 | where | ||
| 710 | F: FnOnce(&mut [u8]) -> R, | ||
| 711 | { | ||
| 712 | assert!(len <= self.buf.len()); | ||
| 713 | let r = f(&mut self.buf[..len]); | ||
| 714 | self.eth.transmit(&self.buf[..len]); | ||
| 715 | r | ||
| 716 | } | ||
| 717 | } | ||
diff --git a/embassy-net-enc28j60/src/macros.rs b/embassy-net-enc28j60/src/macros.rs new file mode 100644 index 000000000..8d0649572 --- /dev/null +++ b/embassy-net-enc28j60/src/macros.rs | |||
| @@ -0,0 +1,89 @@ | |||
| 1 | macro_rules! register { | ||
| 2 | ($REGISTER:ident, $reset_value:expr, $uxx:ty, { | ||
| 3 | $(#[$($attr:tt)*] $bitfield:ident @ $range:expr,)+ | ||
| 4 | }) => { | ||
| 5 | #[derive(Clone, Copy)] | ||
| 6 | pub(crate) struct $REGISTER<MODE> { | ||
| 7 | bits: $uxx, | ||
| 8 | _mode: ::core::marker::PhantomData<MODE>, | ||
| 9 | } | ||
| 10 | |||
| 11 | impl $REGISTER<super::traits::Mask> { | ||
| 12 | #[allow(dead_code)] | ||
| 13 | pub(crate) fn mask() -> $REGISTER<super::traits::Mask> { | ||
| 14 | $REGISTER { bits: 0, _mode: ::core::marker::PhantomData } | ||
| 15 | } | ||
| 16 | |||
| 17 | $( | ||
| 18 | #[allow(dead_code)] | ||
| 19 | pub(crate) fn $bitfield(&self) -> $uxx { | ||
| 20 | use super::traits::OffsetSize; | ||
| 21 | |||
| 22 | let size = $range.size(); | ||
| 23 | let offset = $range.offset(); | ||
| 24 | ((1 << size) - 1) << offset | ||
| 25 | } | ||
| 26 | )+ | ||
| 27 | } | ||
| 28 | |||
| 29 | impl ::core::default::Default for $REGISTER<super::traits::W> { | ||
| 30 | fn default() -> Self { | ||
| 31 | $REGISTER { bits: $reset_value, _mode: ::core::marker::PhantomData } | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | #[allow(non_snake_case)] | ||
| 36 | #[allow(dead_code)] | ||
| 37 | pub(crate) fn $REGISTER(bits: $uxx) -> $REGISTER<super::traits::R> { | ||
| 38 | $REGISTER { bits, _mode: ::core::marker::PhantomData } | ||
| 39 | } | ||
| 40 | |||
| 41 | impl $REGISTER<super::traits::R> { | ||
| 42 | #[allow(dead_code)] | ||
| 43 | pub(crate) fn modify(self) -> $REGISTER<super::traits::W> { | ||
| 44 | $REGISTER { bits: self.bits, _mode: ::core::marker::PhantomData } | ||
| 45 | } | ||
| 46 | |||
| 47 | $( | ||
| 48 | #[$($attr)*] | ||
| 49 | #[allow(dead_code)] | ||
| 50 | pub(crate) fn $bitfield(&self) -> $uxx { | ||
| 51 | use super::traits::OffsetSize; | ||
| 52 | |||
| 53 | let offset = $range.offset(); | ||
| 54 | let size = $range.size(); | ||
| 55 | let mask = (1 << size) - 1; | ||
| 56 | |||
| 57 | (self.bits >> offset) & mask | ||
| 58 | } | ||
| 59 | )+ | ||
| 60 | } | ||
| 61 | |||
| 62 | impl $REGISTER<super::traits::W> { | ||
| 63 | #[allow(dead_code)] | ||
| 64 | pub(crate) fn bits(self) -> $uxx { | ||
| 65 | self.bits | ||
| 66 | } | ||
| 67 | |||
| 68 | $( | ||
| 69 | #[$($attr)*] | ||
| 70 | #[allow(dead_code)] | ||
| 71 | pub(crate) fn $bitfield(&mut self, mut bits: $uxx) -> &mut Self { | ||
| 72 | use super::traits::OffsetSize; | ||
| 73 | |||
| 74 | let offset = $range.offset(); | ||
| 75 | let size = $range.size(); | ||
| 76 | let mask = (1 << size) - 1; | ||
| 77 | |||
| 78 | debug_assert!(bits <= mask); | ||
| 79 | bits &= mask; | ||
| 80 | |||
| 81 | self.bits &= !(mask << offset); | ||
| 82 | self.bits |= bits << offset; | ||
| 83 | |||
| 84 | self | ||
| 85 | } | ||
| 86 | )+ | ||
| 87 | } | ||
| 88 | } | ||
| 89 | } | ||
diff --git a/embassy-net-enc28j60/src/phy.rs b/embassy-net-enc28j60/src/phy.rs new file mode 100644 index 000000000..89144ada3 --- /dev/null +++ b/embassy-net-enc28j60/src/phy.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | #[allow(dead_code)] | ||
| 2 | #[derive(Clone, Copy)] | ||
| 3 | pub enum Register { | ||
| 4 | PHCON1 = 0x00, | ||
| 5 | PHSTAT1 = 0x01, | ||
| 6 | PHID1 = 0x02, | ||
| 7 | PHID2 = 0x03, | ||
| 8 | PHCON2 = 0x10, | ||
| 9 | PHSTAT2 = 0x11, | ||
| 10 | PHIE = 0x12, | ||
| 11 | PHIR = 0x13, | ||
| 12 | PHLCON = 0x14, | ||
| 13 | } | ||
| 14 | |||
| 15 | impl Register { | ||
| 16 | pub(crate) fn addr(&self) -> u8 { | ||
| 17 | *self as u8 | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | register!(PHCON2, 0, u16, { | ||
| 22 | #[doc = "PHY Half-Duplex Loopback Disable bit"] | ||
| 23 | hdldis @ 8, | ||
| 24 | #[doc = "Jabber Correction Disable bit"] | ||
| 25 | jabber @ 10, | ||
| 26 | #[doc = "Twisted-Pair Transmitter Disable bit"] | ||
| 27 | txdis @ 13, | ||
| 28 | #[doc = "PHY Force Linkup bit"] | ||
| 29 | frclnk @ 14, | ||
| 30 | }); | ||
| 31 | |||
| 32 | register!(PHSTAT2, 0, u16, { | ||
| 33 | #[doc = "Link Status bit"] | ||
| 34 | lstat @ 10, | ||
| 35 | }); | ||
diff --git a/embassy-net-enc28j60/src/traits.rs b/embassy-net-enc28j60/src/traits.rs new file mode 100644 index 000000000..08f94045a --- /dev/null +++ b/embassy-net-enc28j60/src/traits.rs | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | use core::ops::Range; | ||
| 2 | |||
| 3 | pub(crate) trait OffsetSize { | ||
| 4 | fn offset(self) -> u8; | ||
| 5 | fn size(self) -> u8; | ||
| 6 | } | ||
| 7 | |||
| 8 | impl OffsetSize for u8 { | ||
| 9 | fn offset(self) -> u8 { | ||
| 10 | self | ||
| 11 | } | ||
| 12 | |||
| 13 | fn size(self) -> u8 { | ||
| 14 | 1 | ||
| 15 | } | ||
| 16 | } | ||
| 17 | |||
| 18 | impl OffsetSize for Range<u8> { | ||
| 19 | fn offset(self) -> u8 { | ||
| 20 | self.start | ||
| 21 | } | ||
| 22 | |||
| 23 | fn size(self) -> u8 { | ||
| 24 | self.end - self.start | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | pub(crate) trait U16Ext { | ||
| 29 | fn from_parts(low: u8, high: u8) -> Self; | ||
| 30 | |||
| 31 | fn low(self) -> u8; | ||
| 32 | |||
| 33 | fn high(self) -> u8; | ||
| 34 | } | ||
| 35 | |||
| 36 | impl U16Ext for u16 { | ||
| 37 | fn from_parts(low: u8, high: u8) -> u16 { | ||
| 38 | ((high as u16) << 8) + low as u16 | ||
| 39 | } | ||
| 40 | |||
| 41 | fn low(self) -> u8 { | ||
| 42 | (self & 0xff) as u8 | ||
| 43 | } | ||
| 44 | |||
| 45 | fn high(self) -> u8 { | ||
| 46 | (self >> 8) as u8 | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | #[derive(Clone, Copy)] | ||
| 51 | pub struct Mask; | ||
| 52 | |||
| 53 | #[derive(Clone, Copy)] | ||
| 54 | pub struct R; | ||
| 55 | |||
| 56 | #[derive(Clone, Copy)] | ||
| 57 | pub struct W; | ||
diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index 0053c49a4..d334cf3fe 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml | |||
| @@ -12,8 +12,8 @@ embassy-sync = { version = "0.2.0", path = "../embassy-sync"} | |||
| 12 | embassy-futures = { version = "0.1.0", path = "../embassy-futures"} | 12 | embassy-futures = { version = "0.1.0", path = "../embassy-futures"} |
| 13 | embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"} | 13 | embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"} |
| 14 | 14 | ||
| 15 | embedded-hal = { version = "1.0.0-alpha.11" } | 15 | embedded-hal = { version = "1.0.0-rc.1" } |
| 16 | embedded-hal-async = { version = "=0.2.0-alpha.2" } | 16 | embedded-hal-async = { version = "=1.0.0-rc.1" } |
| 17 | 17 | ||
| 18 | noproto = { git="https://github.com/embassy-rs/noproto", default-features = false, features = ["derive"] } | 18 | noproto = { git="https://github.com/embassy-rs/noproto", default-features = false, features = ["derive"] } |
| 19 | #noproto = { version = "0.1", path = "/home/dirbaio/noproto", default-features = false, features = ["derive"] } | 19 | #noproto = { version = "0.1", path = "/home/dirbaio/noproto", default-features = false, features = ["derive"] } |
diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs index 37f220da0..b8026611b 100644 --- a/embassy-net-esp-hosted/src/control.rs +++ b/embassy-net-esp-hosted/src/control.rs | |||
| @@ -5,9 +5,12 @@ use heapless::String; | |||
| 5 | use crate::ioctl::Shared; | 5 | use crate::ioctl::Shared; |
| 6 | use crate::proto::{self, CtrlMsg}; | 6 | use crate::proto::{self, CtrlMsg}; |
| 7 | 7 | ||
| 8 | #[derive(Debug)] | 8 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] |
| 9 | pub struct Error { | 9 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 10 | pub status: u32, | 10 | pub enum Error { |
| 11 | Failed(u32), | ||
| 12 | Timeout, | ||
| 13 | Internal, | ||
| 11 | } | 14 | } |
| 12 | 15 | ||
| 13 | pub struct Control<'a> { | 16 | pub struct Control<'a> { |
| @@ -23,58 +26,78 @@ enum WifiMode { | |||
| 23 | ApSta = 3, | 26 | ApSta = 3, |
| 24 | } | 27 | } |
| 25 | 28 | ||
| 29 | macro_rules! ioctl { | ||
| 30 | ($self:ident, $req_variant:ident, $resp_variant:ident, $req:ident, $resp:ident) => { | ||
| 31 | let mut msg = proto::CtrlMsg { | ||
| 32 | msg_id: proto::CtrlMsgId::$req_variant as _, | ||
| 33 | msg_type: proto::CtrlMsgType::Req as _, | ||
| 34 | payload: Some(proto::CtrlMsgPayload::$req_variant($req)), | ||
| 35 | }; | ||
| 36 | $self.ioctl(&mut msg).await?; | ||
| 37 | let Some(proto::CtrlMsgPayload::$resp_variant($resp)) = msg.payload else { | ||
| 38 | warn!("unexpected response variant"); | ||
| 39 | return Err(Error::Internal); | ||
| 40 | }; | ||
| 41 | if $resp.resp != 0 { | ||
| 42 | return Err(Error::Failed($resp.resp)); | ||
| 43 | } | ||
| 44 | }; | ||
| 45 | } | ||
| 46 | |||
| 26 | impl<'a> Control<'a> { | 47 | impl<'a> Control<'a> { |
| 27 | pub(crate) fn new(state_ch: ch::StateRunner<'a>, shared: &'a Shared) -> Self { | 48 | pub(crate) fn new(state_ch: ch::StateRunner<'a>, shared: &'a Shared) -> Self { |
| 28 | Self { state_ch, shared } | 49 | Self { state_ch, shared } |
| 29 | } | 50 | } |
| 30 | 51 | ||
| 31 | pub async fn init(&mut self) { | 52 | pub async fn init(&mut self) -> Result<(), Error> { |
| 32 | debug!("wait for init event..."); | 53 | debug!("wait for init event..."); |
| 33 | self.shared.init_wait().await; | 54 | self.shared.init_wait().await; |
| 34 | 55 | ||
| 56 | debug!("set heartbeat"); | ||
| 57 | self.set_heartbeat(10).await?; | ||
| 58 | |||
| 35 | debug!("set wifi mode"); | 59 | debug!("set wifi mode"); |
| 36 | self.set_wifi_mode(WifiMode::Sta as _).await; | 60 | self.set_wifi_mode(WifiMode::Sta as _).await?; |
| 37 | 61 | ||
| 38 | let mac_addr = self.get_mac_addr().await; | 62 | let mac_addr = self.get_mac_addr().await?; |
| 39 | debug!("mac addr: {:02x}", mac_addr); | 63 | debug!("mac addr: {:02x}", mac_addr); |
| 40 | self.state_ch.set_ethernet_address(mac_addr); | 64 | self.state_ch.set_ethernet_address(mac_addr); |
| 65 | |||
| 66 | Ok(()) | ||
| 41 | } | 67 | } |
| 42 | 68 | ||
| 43 | pub async fn join(&mut self, ssid: &str, password: &str) { | 69 | pub async fn connect(&mut self, ssid: &str, password: &str) -> Result<(), Error> { |
| 44 | let req = proto::CtrlMsg { | 70 | let req = proto::CtrlMsgReqConnectAp { |
| 45 | msg_id: proto::CtrlMsgId::ReqConnectAp as _, | 71 | ssid: String::from(ssid), |
| 46 | msg_type: proto::CtrlMsgType::Req as _, | 72 | pwd: String::from(password), |
| 47 | payload: Some(proto::CtrlMsgPayload::ReqConnectAp(proto::CtrlMsgReqConnectAp { | 73 | bssid: String::new(), |
| 48 | ssid: String::from(ssid), | 74 | listen_interval: 3, |
| 49 | pwd: String::from(password), | 75 | is_wpa3_supported: false, |
| 50 | bssid: String::new(), | ||
| 51 | listen_interval: 3, | ||
| 52 | is_wpa3_supported: false, | ||
| 53 | })), | ||
| 54 | }; | 76 | }; |
| 55 | let resp = self.ioctl(req).await; | 77 | ioctl!(self, ReqConnectAp, RespConnectAp, req, resp); |
| 56 | let proto::CtrlMsgPayload::RespConnectAp(resp) = resp.payload.unwrap() else { | ||
| 57 | panic!("unexpected resp") | ||
| 58 | }; | ||
| 59 | assert_eq!(resp.resp, 0); | ||
| 60 | self.state_ch.set_link_state(LinkState::Up); | 78 | self.state_ch.set_link_state(LinkState::Up); |
| 79 | Ok(()) | ||
| 61 | } | 80 | } |
| 62 | 81 | ||
| 63 | async fn get_mac_addr(&mut self) -> [u8; 6] { | 82 | pub async fn disconnect(&mut self) -> Result<(), Error> { |
| 64 | let req = proto::CtrlMsg { | 83 | let req = proto::CtrlMsgReqGetStatus {}; |
| 65 | msg_id: proto::CtrlMsgId::ReqGetMacAddress as _, | 84 | ioctl!(self, ReqDisconnectAp, RespDisconnectAp, req, resp); |
| 66 | msg_type: proto::CtrlMsgType::Req as _, | 85 | self.state_ch.set_link_state(LinkState::Up); |
| 67 | payload: Some(proto::CtrlMsgPayload::ReqGetMacAddress( | 86 | Ok(()) |
| 68 | proto::CtrlMsgReqGetMacAddress { | 87 | } |
| 69 | mode: WifiMode::Sta as _, | 88 | |
| 70 | }, | 89 | /// duration in seconds, clamped to [10, 3600] |
| 71 | )), | 90 | async fn set_heartbeat(&mut self, duration: u32) -> Result<(), Error> { |
| 72 | }; | 91 | let req = proto::CtrlMsgReqConfigHeartbeat { enable: true, duration }; |
| 73 | let resp = self.ioctl(req).await; | 92 | ioctl!(self, ReqConfigHeartbeat, RespConfigHeartbeat, req, resp); |
| 74 | let proto::CtrlMsgPayload::RespGetMacAddress(resp) = resp.payload.unwrap() else { | 93 | Ok(()) |
| 75 | panic!("unexpected resp") | 94 | } |
| 95 | |||
| 96 | async fn get_mac_addr(&mut self) -> Result<[u8; 6], Error> { | ||
| 97 | let req = proto::CtrlMsgReqGetMacAddress { | ||
| 98 | mode: WifiMode::Sta as _, | ||
| 76 | }; | 99 | }; |
| 77 | assert_eq!(resp.resp, 0); | 100 | ioctl!(self, ReqGetMacAddress, RespGetMacAddress, req, resp); |
| 78 | 101 | ||
| 79 | // WHY IS THIS A STRING? WHYYYY | 102 | // WHY IS THIS A STRING? WHYYYY |
| 80 | fn nibble_from_hex(b: u8) -> u8 { | 103 | fn nibble_from_hex(b: u8) -> u8 { |
| @@ -88,32 +111,32 @@ impl<'a> Control<'a> { | |||
| 88 | 111 | ||
| 89 | let mac = resp.mac.as_bytes(); | 112 | let mac = resp.mac.as_bytes(); |
| 90 | let mut res = [0; 6]; | 113 | let mut res = [0; 6]; |
| 91 | assert_eq!(mac.len(), 17); | 114 | if mac.len() != 17 { |
| 115 | warn!("unexpected MAC respnse length"); | ||
| 116 | return Err(Error::Internal); | ||
| 117 | } | ||
| 92 | for (i, b) in res.iter_mut().enumerate() { | 118 | for (i, b) in res.iter_mut().enumerate() { |
| 93 | *b = (nibble_from_hex(mac[i * 3]) << 4) | nibble_from_hex(mac[i * 3 + 1]) | 119 | *b = (nibble_from_hex(mac[i * 3]) << 4) | nibble_from_hex(mac[i * 3 + 1]) |
| 94 | } | 120 | } |
| 95 | res | 121 | Ok(res) |
| 96 | } | 122 | } |
| 97 | 123 | ||
| 98 | async fn set_wifi_mode(&mut self, mode: u32) { | 124 | async fn set_wifi_mode(&mut self, mode: u32) -> Result<(), Error> { |
| 99 | let req = proto::CtrlMsg { | 125 | let req = proto::CtrlMsgReqSetMode { mode }; |
| 100 | msg_id: proto::CtrlMsgId::ReqSetWifiMode as _, | 126 | ioctl!(self, ReqSetWifiMode, RespSetWifiMode, req, resp); |
| 101 | msg_type: proto::CtrlMsgType::Req as _, | 127 | |
| 102 | payload: Some(proto::CtrlMsgPayload::ReqSetWifiMode(proto::CtrlMsgReqSetMode { mode })), | 128 | Ok(()) |
| 103 | }; | ||
| 104 | let resp = self.ioctl(req).await; | ||
| 105 | let proto::CtrlMsgPayload::RespSetWifiMode(resp) = resp.payload.unwrap() else { | ||
| 106 | panic!("unexpected resp") | ||
| 107 | }; | ||
| 108 | assert_eq!(resp.resp, 0); | ||
| 109 | } | 129 | } |
| 110 | 130 | ||
| 111 | async fn ioctl(&mut self, req: CtrlMsg) -> CtrlMsg { | 131 | async fn ioctl(&mut self, msg: &mut CtrlMsg) -> Result<(), Error> { |
| 112 | debug!("ioctl req: {:?}", &req); | 132 | debug!("ioctl req: {:?}", &msg); |
| 113 | 133 | ||
| 114 | let mut buf = [0u8; 128]; | 134 | let mut buf = [0u8; 128]; |
| 115 | 135 | ||
| 116 | let req_len = noproto::write(&req, &mut buf).unwrap(); | 136 | let req_len = noproto::write(msg, &mut buf).map_err(|_| { |
| 137 | warn!("failed to serialize control request"); | ||
| 138 | Error::Internal | ||
| 139 | })?; | ||
| 117 | 140 | ||
| 118 | struct CancelOnDrop<'a>(&'a Shared); | 141 | struct CancelOnDrop<'a>(&'a Shared); |
| 119 | 142 | ||
| @@ -135,9 +158,12 @@ impl<'a> Control<'a> { | |||
| 135 | 158 | ||
| 136 | ioctl.defuse(); | 159 | ioctl.defuse(); |
| 137 | 160 | ||
| 138 | let res = noproto::read(&buf[..resp_len]).unwrap(); | 161 | *msg = noproto::read(&buf[..resp_len]).map_err(|_| { |
| 139 | debug!("ioctl resp: {:?}", &res); | 162 | warn!("failed to serialize control request"); |
| 163 | Error::Internal | ||
| 164 | })?; | ||
| 165 | debug!("ioctl resp: {:?}", msg); | ||
| 140 | 166 | ||
| 141 | res | 167 | Ok(()) |
| 142 | } | 168 | } |
| 143 | } | 169 | } |
diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs index 96fddce58..4a318b20d 100644 --- a/embassy-net-esp-hosted/src/lib.rs +++ b/embassy-net-esp-hosted/src/lib.rs | |||
| @@ -1,17 +1,15 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | 2 | ||
| 3 | use control::Control; | 3 | use embassy_futures::select::{select4, Either4}; |
| 4 | use embassy_futures::select::{select3, Either3}; | ||
| 5 | use embassy_net_driver_channel as ch; | 4 | use embassy_net_driver_channel as ch; |
| 5 | use embassy_net_driver_channel::driver::LinkState; | ||
| 6 | use embassy_time::{Duration, Instant, Timer}; | 6 | use embassy_time::{Duration, Instant, Timer}; |
| 7 | use embedded_hal::digital::{InputPin, OutputPin}; | 7 | use embedded_hal::digital::{InputPin, OutputPin}; |
| 8 | use embedded_hal_async::digital::Wait; | 8 | use embedded_hal_async::digital::Wait; |
| 9 | use embedded_hal_async::spi::SpiDevice; | 9 | use embedded_hal_async::spi::SpiDevice; |
| 10 | use ioctl::Shared; | ||
| 11 | use proto::CtrlMsg; | ||
| 12 | 10 | ||
| 13 | use crate::ioctl::PendingIoctl; | 11 | use crate::ioctl::{PendingIoctl, Shared}; |
| 14 | use crate::proto::CtrlMsgPayload; | 12 | use crate::proto::{CtrlMsg, CtrlMsgPayload}; |
| 15 | 13 | ||
| 16 | mod proto; | 14 | mod proto; |
| 17 | 15 | ||
| @@ -21,6 +19,8 @@ mod fmt; | |||
| 21 | mod control; | 19 | mod control; |
| 22 | mod ioctl; | 20 | mod ioctl; |
| 23 | 21 | ||
| 22 | pub use control::*; | ||
| 23 | |||
| 24 | const MTU: usize = 1514; | 24 | const MTU: usize = 1514; |
| 25 | 25 | ||
| 26 | macro_rules! impl_bytes { | 26 | macro_rules! impl_bytes { |
| @@ -95,6 +95,7 @@ enum InterfaceType { | |||
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | const MAX_SPI_BUFFER_SIZE: usize = 1600; | 97 | const MAX_SPI_BUFFER_SIZE: usize = 1600; |
| 98 | const HEARTBEAT_MAX_GAP: Duration = Duration::from_secs(20); | ||
| 98 | 99 | ||
| 99 | pub struct State { | 100 | pub struct State { |
| 100 | shared: Shared, | 101 | shared: Shared, |
| @@ -129,12 +130,14 @@ where | |||
| 129 | 130 | ||
| 130 | let mut runner = Runner { | 131 | let mut runner = Runner { |
| 131 | ch: ch_runner, | 132 | ch: ch_runner, |
| 133 | state_ch, | ||
| 132 | shared: &state.shared, | 134 | shared: &state.shared, |
| 133 | next_seq: 1, | 135 | next_seq: 1, |
| 134 | handshake, | 136 | handshake, |
| 135 | ready, | 137 | ready, |
| 136 | reset, | 138 | reset, |
| 137 | spi, | 139 | spi, |
| 140 | heartbeat_deadline: Instant::now() + HEARTBEAT_MAX_GAP, | ||
| 138 | }; | 141 | }; |
| 139 | runner.init().await; | 142 | runner.init().await; |
| 140 | 143 | ||
| @@ -143,9 +146,11 @@ where | |||
| 143 | 146 | ||
| 144 | pub struct Runner<'a, SPI, IN, OUT> { | 147 | pub struct Runner<'a, SPI, IN, OUT> { |
| 145 | ch: ch::Runner<'a, MTU>, | 148 | ch: ch::Runner<'a, MTU>, |
| 149 | state_ch: ch::StateRunner<'a>, | ||
| 146 | shared: &'a Shared, | 150 | shared: &'a Shared, |
| 147 | 151 | ||
| 148 | next_seq: u16, | 152 | next_seq: u16, |
| 153 | heartbeat_deadline: Instant, | ||
| 149 | 154 | ||
| 150 | spi: SPI, | 155 | spi: SPI, |
| 151 | handshake: IN, | 156 | handshake: IN, |
| @@ -177,9 +182,10 @@ where | |||
| 177 | let ioctl = self.shared.ioctl_wait_pending(); | 182 | let ioctl = self.shared.ioctl_wait_pending(); |
| 178 | let tx = self.ch.tx_buf(); | 183 | let tx = self.ch.tx_buf(); |
| 179 | let ev = async { self.ready.wait_for_high().await.unwrap() }; | 184 | let ev = async { self.ready.wait_for_high().await.unwrap() }; |
| 185 | let hb = Timer::at(self.heartbeat_deadline); | ||
| 180 | 186 | ||
| 181 | match select3(ioctl, tx, ev).await { | 187 | match select4(ioctl, tx, ev, hb).await { |
| 182 | Either3::First(PendingIoctl { buf, req_len }) => { | 188 | Either4::First(PendingIoctl { buf, req_len }) => { |
| 183 | tx_buf[12..24].copy_from_slice(b"\x01\x08\x00ctrlResp\x02"); | 189 | tx_buf[12..24].copy_from_slice(b"\x01\x08\x00ctrlResp\x02"); |
| 184 | tx_buf[24..26].copy_from_slice(&(req_len as u16).to_le_bytes()); | 190 | tx_buf[24..26].copy_from_slice(&(req_len as u16).to_le_bytes()); |
| 185 | tx_buf[26..][..req_len].copy_from_slice(&unsafe { &*buf }[..req_len]); | 191 | tx_buf[26..][..req_len].copy_from_slice(&unsafe { &*buf }[..req_len]); |
| @@ -198,7 +204,7 @@ where | |||
| 198 | header.checksum = checksum(&tx_buf[..26 + req_len]); | 204 | header.checksum = checksum(&tx_buf[..26 + req_len]); |
| 199 | tx_buf[0..12].copy_from_slice(&header.to_bytes()); | 205 | tx_buf[0..12].copy_from_slice(&header.to_bytes()); |
| 200 | } | 206 | } |
| 201 | Either3::Second(packet) => { | 207 | Either4::Second(packet) => { |
| 202 | tx_buf[12..][..packet.len()].copy_from_slice(packet); | 208 | tx_buf[12..][..packet.len()].copy_from_slice(packet); |
| 203 | 209 | ||
| 204 | let mut header = PayloadHeader { | 210 | let mut header = PayloadHeader { |
| @@ -217,9 +223,12 @@ where | |||
| 217 | 223 | ||
| 218 | self.ch.tx_done(); | 224 | self.ch.tx_done(); |
| 219 | } | 225 | } |
| 220 | Either3::Third(()) => { | 226 | Either4::Third(()) => { |
| 221 | tx_buf[..PayloadHeader::SIZE].fill(0); | 227 | tx_buf[..PayloadHeader::SIZE].fill(0); |
| 222 | } | 228 | } |
| 229 | Either4::Fourth(()) => { | ||
| 230 | panic!("heartbeat from esp32 stopped") | ||
| 231 | } | ||
| 223 | } | 232 | } |
| 224 | 233 | ||
| 225 | if tx_buf[0] != 0 { | 234 | if tx_buf[0] != 0 { |
| @@ -308,7 +317,7 @@ where | |||
| 308 | } | 317 | } |
| 309 | } | 318 | } |
| 310 | 319 | ||
| 311 | fn handle_event(&self, data: &[u8]) { | 320 | fn handle_event(&mut self, data: &[u8]) { |
| 312 | let Ok(event) = noproto::read::<CtrlMsg>(data) else { | 321 | let Ok(event) = noproto::read::<CtrlMsg>(data) else { |
| 313 | warn!("failed to parse event"); | 322 | warn!("failed to parse event"); |
| 314 | return; | 323 | return; |
| @@ -323,6 +332,11 @@ where | |||
| 323 | 332 | ||
| 324 | match payload { | 333 | match payload { |
| 325 | CtrlMsgPayload::EventEspInit(_) => self.shared.init_done(), | 334 | CtrlMsgPayload::EventEspInit(_) => self.shared.init_done(), |
| 335 | CtrlMsgPayload::EventHeartbeat(_) => self.heartbeat_deadline = Instant::now() + HEARTBEAT_MAX_GAP, | ||
| 336 | CtrlMsgPayload::EventStationDisconnectFromAp(e) => { | ||
| 337 | info!("disconnected, code {}", e.resp); | ||
| 338 | self.state_ch.set_link_state(LinkState::Down); | ||
| 339 | } | ||
| 326 | _ => {} | 340 | _ => {} |
| 327 | } | 341 | } |
| 328 | } | 342 | } |
diff --git a/embassy-net-w5500/README.md b/embassy-net-w5500/README.md deleted file mode 100644 index 9eaf4b700..000000000 --- a/embassy-net-w5500/README.md +++ /dev/null | |||
| @@ -1,7 +0,0 @@ | |||
| 1 | # WIZnet W5500 `embassy-net` integration | ||
| 2 | |||
| 3 | [`embassy-net`](https://crates.io/crates/embassy-net) integration for the WIZnet W5500 SPI ethernet chip, operating in MACRAW mode. | ||
| 4 | |||
| 5 | Supports any SPI driver implementing [`embedded-hal-async`](https://crates.io/crates/embedded-hal-async) | ||
| 6 | |||
| 7 | See [`examples`](https://github.com/kalkyl/embassy-net-w5500/tree/main/examples) directory for usage examples with the rp2040 [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) module. \ No newline at end of file | ||
diff --git a/embassy-net-w5500/src/device.rs b/embassy-net-w5500/src/device.rs deleted file mode 100644 index 9874df0d6..000000000 --- a/embassy-net-w5500/src/device.rs +++ /dev/null | |||
| @@ -1,131 +0,0 @@ | |||
| 1 | use embedded_hal_async::spi::SpiDevice; | ||
| 2 | |||
| 3 | use crate::socket; | ||
| 4 | use crate::spi::SpiInterface; | ||
| 5 | |||
| 6 | pub const MODE: u16 = 0x00; | ||
| 7 | pub const MAC: u16 = 0x09; | ||
| 8 | pub const SOCKET_INTR: u16 = 0x18; | ||
| 9 | pub const PHY_CFG: u16 = 0x2E; | ||
| 10 | |||
| 11 | #[repr(u8)] | ||
| 12 | pub enum RegisterBlock { | ||
| 13 | Common = 0x00, | ||
| 14 | Socket0 = 0x01, | ||
| 15 | TxBuf = 0x02, | ||
| 16 | RxBuf = 0x03, | ||
| 17 | } | ||
| 18 | |||
| 19 | /// W5500 in MACRAW mode | ||
| 20 | #[derive(Debug)] | ||
| 21 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 22 | pub struct W5500<SPI> { | ||
| 23 | bus: SpiInterface<SPI>, | ||
| 24 | } | ||
| 25 | |||
| 26 | impl<SPI: SpiDevice> W5500<SPI> { | ||
| 27 | /// Create and initialize the W5500 driver | ||
| 28 | pub async fn new(spi: SPI, mac_addr: [u8; 6]) -> Result<W5500<SPI>, SPI::Error> { | ||
| 29 | let mut bus = SpiInterface(spi); | ||
| 30 | // Reset device | ||
| 31 | bus.write_frame(RegisterBlock::Common, MODE, &[0x80]).await?; | ||
| 32 | |||
| 33 | // Enable interrupt pin | ||
| 34 | bus.write_frame(RegisterBlock::Common, SOCKET_INTR, &[0x01]).await?; | ||
| 35 | // Enable receive interrupt | ||
| 36 | bus.write_frame( | ||
| 37 | RegisterBlock::Socket0, | ||
| 38 | socket::SOCKET_INTR_MASK, | ||
| 39 | &[socket::Interrupt::Receive as u8], | ||
| 40 | ) | ||
| 41 | .await?; | ||
| 42 | |||
| 43 | // Set MAC address | ||
| 44 | bus.write_frame(RegisterBlock::Common, MAC, &mac_addr).await?; | ||
| 45 | |||
| 46 | // Set the raw socket RX/TX buffer sizes to 16KB | ||
| 47 | bus.write_frame(RegisterBlock::Socket0, socket::TXBUF_SIZE, &[16]) | ||
| 48 | .await?; | ||
| 49 | bus.write_frame(RegisterBlock::Socket0, socket::RXBUF_SIZE, &[16]) | ||
| 50 | .await?; | ||
| 51 | |||
| 52 | // MACRAW mode with MAC filtering. | ||
| 53 | let mode: u8 = (1 << 2) | (1 << 7); | ||
| 54 | bus.write_frame(RegisterBlock::Socket0, socket::MODE, &[mode]).await?; | ||
| 55 | socket::command(&mut bus, socket::Command::Open).await?; | ||
| 56 | |||
| 57 | Ok(Self { bus }) | ||
| 58 | } | ||
| 59 | |||
| 60 | /// Read bytes from the RX buffer. Returns the number of bytes read. | ||
| 61 | async fn read_bytes(&mut self, buffer: &mut [u8], offset: u16) -> Result<usize, SPI::Error> { | ||
| 62 | let rx_size = socket::get_rx_size(&mut self.bus).await? as usize; | ||
| 63 | |||
| 64 | let read_buffer = if rx_size > buffer.len() + offset as usize { | ||
| 65 | buffer | ||
| 66 | } else { | ||
| 67 | &mut buffer[..rx_size - offset as usize] | ||
| 68 | }; | ||
| 69 | |||
| 70 | let read_ptr = socket::get_rx_read_ptr(&mut self.bus).await?.wrapping_add(offset); | ||
| 71 | self.bus.read_frame(RegisterBlock::RxBuf, read_ptr, read_buffer).await?; | ||
| 72 | socket::set_rx_read_ptr(&mut self.bus, read_ptr.wrapping_add(read_buffer.len() as u16)).await?; | ||
| 73 | |||
| 74 | Ok(read_buffer.len()) | ||
| 75 | } | ||
| 76 | |||
| 77 | /// Read an ethernet frame from the device. Returns the number of bytes read. | ||
| 78 | pub async fn read_frame(&mut self, frame: &mut [u8]) -> Result<usize, SPI::Error> { | ||
| 79 | let rx_size = socket::get_rx_size(&mut self.bus).await? as usize; | ||
| 80 | if rx_size == 0 { | ||
| 81 | return Ok(0); | ||
| 82 | } | ||
| 83 | |||
| 84 | socket::reset_interrupt(&mut self.bus, socket::Interrupt::Receive).await?; | ||
| 85 | |||
| 86 | // First two bytes gives the size of the received ethernet frame | ||
| 87 | let expected_frame_size: usize = { | ||
| 88 | let mut frame_bytes = [0u8; 2]; | ||
| 89 | assert!(self.read_bytes(&mut frame_bytes[..], 0).await? == 2); | ||
| 90 | u16::from_be_bytes(frame_bytes) as usize - 2 | ||
| 91 | }; | ||
| 92 | |||
| 93 | // Read the ethernet frame | ||
| 94 | let read_buffer = if frame.len() > expected_frame_size { | ||
| 95 | &mut frame[..expected_frame_size] | ||
| 96 | } else { | ||
| 97 | frame | ||
| 98 | }; | ||
| 99 | |||
| 100 | let recvd_frame_size = self.read_bytes(read_buffer, 2).await?; | ||
| 101 | |||
| 102 | // Register RX as completed | ||
| 103 | socket::command(&mut self.bus, socket::Command::Receive).await?; | ||
| 104 | |||
| 105 | // If the whole frame wasn't read, drop it | ||
| 106 | if recvd_frame_size < expected_frame_size { | ||
| 107 | Ok(0) | ||
| 108 | } else { | ||
| 109 | Ok(recvd_frame_size) | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | /// Write an ethernet frame to the device. Returns number of bytes written | ||
| 114 | pub async fn write_frame(&mut self, frame: &[u8]) -> Result<usize, SPI::Error> { | ||
| 115 | while socket::get_tx_free_size(&mut self.bus).await? < frame.len() as u16 {} | ||
| 116 | let write_ptr = socket::get_tx_write_ptr(&mut self.bus).await?; | ||
| 117 | self.bus.write_frame(RegisterBlock::TxBuf, write_ptr, frame).await?; | ||
| 118 | socket::set_tx_write_ptr(&mut self.bus, write_ptr.wrapping_add(frame.len() as u16)).await?; | ||
| 119 | socket::command(&mut self.bus, socket::Command::Send).await?; | ||
| 120 | Ok(frame.len()) | ||
| 121 | } | ||
| 122 | |||
| 123 | pub async fn is_link_up(&mut self) -> bool { | ||
| 124 | let mut link = [0]; | ||
| 125 | self.bus | ||
| 126 | .read_frame(RegisterBlock::Common, PHY_CFG, &mut link) | ||
| 127 | .await | ||
| 128 | .ok(); | ||
| 129 | link[0] & 1 == 1 | ||
| 130 | } | ||
| 131 | } | ||
diff --git a/embassy-net-w5500/src/socket.rs b/embassy-net-w5500/src/socket.rs deleted file mode 100644 index 3d65583c1..000000000 --- a/embassy-net-w5500/src/socket.rs +++ /dev/null | |||
| @@ -1,80 +0,0 @@ | |||
| 1 | use embedded_hal_async::spi::SpiDevice; | ||
| 2 | |||
| 3 | use crate::device::RegisterBlock; | ||
| 4 | use crate::spi::SpiInterface; | ||
| 5 | |||
| 6 | pub const MODE: u16 = 0x00; | ||
| 7 | pub const COMMAND: u16 = 0x01; | ||
| 8 | pub const RXBUF_SIZE: u16 = 0x1E; | ||
| 9 | pub const TXBUF_SIZE: u16 = 0x1F; | ||
| 10 | pub const TX_FREE_SIZE: u16 = 0x20; | ||
| 11 | pub const TX_DATA_WRITE_PTR: u16 = 0x24; | ||
| 12 | pub const RECVD_SIZE: u16 = 0x26; | ||
| 13 | pub const RX_DATA_READ_PTR: u16 = 0x28; | ||
| 14 | pub const SOCKET_INTR_MASK: u16 = 0x2C; | ||
| 15 | |||
| 16 | #[repr(u8)] | ||
| 17 | pub enum Command { | ||
| 18 | Open = 0x01, | ||
| 19 | Send = 0x20, | ||
| 20 | Receive = 0x40, | ||
| 21 | } | ||
| 22 | |||
| 23 | pub const INTR: u16 = 0x02; | ||
| 24 | #[repr(u8)] | ||
| 25 | pub enum Interrupt { | ||
| 26 | Receive = 0b00100_u8, | ||
| 27 | } | ||
| 28 | |||
| 29 | pub async fn reset_interrupt<SPI: SpiDevice>(bus: &mut SpiInterface<SPI>, code: Interrupt) -> Result<(), SPI::Error> { | ||
| 30 | let data = [code as u8]; | ||
| 31 | bus.write_frame(RegisterBlock::Socket0, INTR, &data).await | ||
| 32 | } | ||
| 33 | |||
| 34 | pub async fn get_tx_write_ptr<SPI: SpiDevice>(bus: &mut SpiInterface<SPI>) -> Result<u16, SPI::Error> { | ||
| 35 | let mut data = [0u8; 2]; | ||
| 36 | bus.read_frame(RegisterBlock::Socket0, TX_DATA_WRITE_PTR, &mut data) | ||
| 37 | .await?; | ||
| 38 | Ok(u16::from_be_bytes(data)) | ||
| 39 | } | ||
| 40 | |||
| 41 | pub async fn set_tx_write_ptr<SPI: SpiDevice>(bus: &mut SpiInterface<SPI>, ptr: u16) -> Result<(), SPI::Error> { | ||
| 42 | let data = ptr.to_be_bytes(); | ||
| 43 | bus.write_frame(RegisterBlock::Socket0, TX_DATA_WRITE_PTR, &data).await | ||
| 44 | } | ||
| 45 | |||
| 46 | pub async fn get_rx_read_ptr<SPI: SpiDevice>(bus: &mut SpiInterface<SPI>) -> Result<u16, SPI::Error> { | ||
| 47 | let mut data = [0u8; 2]; | ||
| 48 | bus.read_frame(RegisterBlock::Socket0, RX_DATA_READ_PTR, &mut data) | ||
| 49 | .await?; | ||
| 50 | Ok(u16::from_be_bytes(data)) | ||
| 51 | } | ||
| 52 | |||
| 53 | pub async fn set_rx_read_ptr<SPI: SpiDevice>(bus: &mut SpiInterface<SPI>, ptr: u16) -> Result<(), SPI::Error> { | ||
| 54 | let data = ptr.to_be_bytes(); | ||
| 55 | bus.write_frame(RegisterBlock::Socket0, RX_DATA_READ_PTR, &data).await | ||
| 56 | } | ||
| 57 | |||
| 58 | pub async fn command<SPI: SpiDevice>(bus: &mut SpiInterface<SPI>, command: Command) -> Result<(), SPI::Error> { | ||
| 59 | let data = [command as u8]; | ||
| 60 | bus.write_frame(RegisterBlock::Socket0, COMMAND, &data).await | ||
| 61 | } | ||
| 62 | |||
| 63 | pub async fn get_rx_size<SPI: SpiDevice>(bus: &mut SpiInterface<SPI>) -> Result<u16, SPI::Error> { | ||
| 64 | loop { | ||
| 65 | // Wait until two sequential reads are equal | ||
| 66 | let mut res0 = [0u8; 2]; | ||
| 67 | bus.read_frame(RegisterBlock::Socket0, RECVD_SIZE, &mut res0).await?; | ||
| 68 | let mut res1 = [0u8; 2]; | ||
| 69 | bus.read_frame(RegisterBlock::Socket0, RECVD_SIZE, &mut res1).await?; | ||
| 70 | if res0 == res1 { | ||
| 71 | break Ok(u16::from_be_bytes(res0)); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | pub async fn get_tx_free_size<SPI: SpiDevice>(bus: &mut SpiInterface<SPI>) -> Result<u16, SPI::Error> { | ||
| 77 | let mut data = [0; 2]; | ||
| 78 | bus.read_frame(RegisterBlock::Socket0, TX_FREE_SIZE, &mut data).await?; | ||
| 79 | Ok(u16::from_be_bytes(data)) | ||
| 80 | } | ||
diff --git a/embassy-net-w5500/src/spi.rs b/embassy-net-w5500/src/spi.rs deleted file mode 100644 index 07749d6be..000000000 --- a/embassy-net-w5500/src/spi.rs +++ /dev/null | |||
| @@ -1,32 +0,0 @@ | |||
| 1 | use embedded_hal_async::spi::{Operation, SpiDevice}; | ||
| 2 | |||
| 3 | use crate::device::RegisterBlock; | ||
| 4 | |||
| 5 | #[derive(Debug)] | ||
| 6 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 7 | pub struct SpiInterface<SPI>(pub SPI); | ||
| 8 | |||
| 9 | impl<SPI: SpiDevice> SpiInterface<SPI> { | ||
| 10 | pub async fn read_frame(&mut self, block: RegisterBlock, address: u16, data: &mut [u8]) -> Result<(), SPI::Error> { | ||
| 11 | let address_phase = address.to_be_bytes(); | ||
| 12 | let control_phase = [(block as u8) << 3]; | ||
| 13 | let operations = &mut [ | ||
| 14 | Operation::Write(&address_phase), | ||
| 15 | Operation::Write(&control_phase), | ||
| 16 | Operation::TransferInPlace(data), | ||
| 17 | ]; | ||
| 18 | self.0.transaction(operations).await | ||
| 19 | } | ||
| 20 | |||
| 21 | pub async fn write_frame(&mut self, block: RegisterBlock, address: u16, data: &[u8]) -> Result<(), SPI::Error> { | ||
| 22 | let address_phase = address.to_be_bytes(); | ||
| 23 | let control_phase = [(block as u8) << 3 | 0b0000_0100]; | ||
| 24 | let data_phase = data; | ||
| 25 | let operations = &mut [ | ||
| 26 | Operation::Write(&address_phase[..]), | ||
| 27 | Operation::Write(&control_phase), | ||
| 28 | Operation::Write(&data_phase), | ||
| 29 | ]; | ||
| 30 | self.0.transaction(operations).await | ||
| 31 | } | ||
| 32 | } | ||
diff --git a/embassy-net-w5500/Cargo.toml b/embassy-net-wiznet/Cargo.toml index 8972b814a..adf0b45fc 100644 --- a/embassy-net-w5500/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml | |||
| @@ -1,21 +1,22 @@ | |||
| 1 | [package] | 1 | [package] |
| 2 | name = "embassy-net-w5500" | 2 | name = "embassy-net-wiznet" |
| 3 | version = "0.1.0" | 3 | version = "0.1.0" |
| 4 | description = "embassy-net driver for the W5500 ethernet chip" | 4 | description = "embassy-net driver for WIZnet SPI Ethernet chips" |
| 5 | keywords = ["embedded", "w5500", "embassy-net", "embedded-hal-async", "ethernet", "async"] | 5 | keywords = ["embedded", "wiznet", "embassy-net", "embedded-hal-async", "ethernet", "async"] |
| 6 | categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] | 6 | categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] |
| 7 | license = "MIT OR Apache-2.0" | 7 | license = "MIT OR Apache-2.0" |
| 8 | edition = "2021" | 8 | edition = "2021" |
| 9 | 9 | ||
| 10 | [dependencies] | 10 | [dependencies] |
| 11 | embedded-hal = { version = "1.0.0-alpha.11" } | 11 | embedded-hal = { version = "1.0.0-rc.1" } |
| 12 | embedded-hal-async = { version = "=0.2.0-alpha.2" } | 12 | embedded-hal-async = { version = "=1.0.0-rc.1" } |
| 13 | embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" } | 13 | embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" } |
| 14 | embassy-time = { version = "0.1.2", path = "../embassy-time" } | 14 | embassy-time = { version = "0.1.2", path = "../embassy-time" } |
| 15 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } | 15 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } |
| 16 | defmt = { version = "0.3", optional = true } | 16 | defmt = { version = "0.3", optional = true } |
| 17 | 17 | ||
| 18 | [package.metadata.embassy_docs] | 18 | [package.metadata.embassy_docs] |
| 19 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-w5500-v$VERSION/embassy-net-w5500/src/" | 19 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-wiznet-v$VERSION/embassy-net-wiznet/src/" |
| 20 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-w5500/src/" | 20 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-wiznet/src/" |
| 21 | target = "thumbv7em-none-eabi" \ No newline at end of file | 21 | target = "thumbv7em-none-eabi" |
| 22 | features = ["defmt"] \ No newline at end of file | ||
diff --git a/embassy-net-wiznet/README.md b/embassy-net-wiznet/README.md new file mode 100644 index 000000000..b8e4bdc8e --- /dev/null +++ b/embassy-net-wiznet/README.md | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | # WIZnet `embassy-net` integration | ||
| 2 | |||
| 3 | [`embassy-net`](https://crates.io/crates/embassy-net) integration for the WIZnet SPI ethernet chips, operating in MACRAW mode. | ||
| 4 | |||
| 5 | See [`examples`](https://github.com/embassy-rs/embassy/tree/main/examples/rp) directory for usage examples with the rp2040 [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) module. | ||
| 6 | |||
| 7 | ## Supported chips | ||
| 8 | |||
| 9 | - W5500 | ||
| 10 | - W5100S | ||
| 11 | |||
| 12 | ## Interoperability | ||
| 13 | |||
| 14 | This crate can run on any executor. | ||
| 15 | |||
| 16 | It supports any SPI driver implementing [`embedded-hal-async`](https://crates.io/crates/embedded-hal-async). | ||
| 17 | |||
| 18 | |||
| 19 | ## License | ||
| 20 | |||
| 21 | This work is licensed under either of | ||
| 22 | |||
| 23 | - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or | ||
| 24 | http://www.apache.org/licenses/LICENSE-2.0) | ||
| 25 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) | ||
| 26 | |||
| 27 | at your option. | ||
diff --git a/embassy-net-wiznet/src/chip/mod.rs b/embassy-net-wiznet/src/chip/mod.rs new file mode 100644 index 000000000..562db515a --- /dev/null +++ b/embassy-net-wiznet/src/chip/mod.rs | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | mod w5500; | ||
| 2 | pub use w5500::W5500; | ||
| 3 | mod w5100s; | ||
| 4 | pub use w5100s::W5100S; | ||
| 5 | |||
| 6 | pub(crate) mod sealed { | ||
| 7 | use embedded_hal_async::spi::SpiDevice; | ||
| 8 | |||
| 9 | pub trait Chip { | ||
| 10 | type Address; | ||
| 11 | |||
| 12 | const COMMON_MODE: Self::Address; | ||
| 13 | const COMMON_MAC: Self::Address; | ||
| 14 | const COMMON_SOCKET_INTR: Self::Address; | ||
| 15 | const COMMON_PHY_CFG: Self::Address; | ||
| 16 | const SOCKET_MODE: Self::Address; | ||
| 17 | const SOCKET_COMMAND: Self::Address; | ||
| 18 | const SOCKET_RXBUF_SIZE: Self::Address; | ||
| 19 | const SOCKET_TXBUF_SIZE: Self::Address; | ||
| 20 | const SOCKET_TX_FREE_SIZE: Self::Address; | ||
| 21 | const SOCKET_TX_DATA_WRITE_PTR: Self::Address; | ||
| 22 | const SOCKET_RECVD_SIZE: Self::Address; | ||
| 23 | const SOCKET_RX_DATA_READ_PTR: Self::Address; | ||
| 24 | const SOCKET_INTR_MASK: Self::Address; | ||
| 25 | const SOCKET_INTR: Self::Address; | ||
| 26 | |||
| 27 | const SOCKET_MODE_VALUE: u8; | ||
| 28 | |||
| 29 | const BUF_SIZE: u16; | ||
| 30 | const AUTO_WRAP: bool; | ||
| 31 | |||
| 32 | fn rx_addr(addr: u16) -> Self::Address; | ||
| 33 | fn tx_addr(addr: u16) -> Self::Address; | ||
| 34 | |||
| 35 | async fn bus_read<SPI: SpiDevice>( | ||
| 36 | spi: &mut SPI, | ||
| 37 | address: Self::Address, | ||
| 38 | data: &mut [u8], | ||
| 39 | ) -> Result<(), SPI::Error>; | ||
| 40 | async fn bus_write<SPI: SpiDevice>( | ||
| 41 | spi: &mut SPI, | ||
| 42 | address: Self::Address, | ||
| 43 | data: &[u8], | ||
| 44 | ) -> Result<(), SPI::Error>; | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | pub trait Chip: sealed::Chip {} | ||
diff --git a/embassy-net-wiznet/src/chip/w5100s.rs b/embassy-net-wiznet/src/chip/w5100s.rs new file mode 100644 index 000000000..07a840370 --- /dev/null +++ b/embassy-net-wiznet/src/chip/w5100s.rs | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | use embedded_hal_async::spi::{Operation, SpiDevice}; | ||
| 2 | |||
| 3 | const SOCKET_BASE: u16 = 0x400; | ||
| 4 | const TX_BASE: u16 = 0x4000; | ||
| 5 | const RX_BASE: u16 = 0x6000; | ||
| 6 | |||
| 7 | pub enum W5100S {} | ||
| 8 | |||
| 9 | impl super::Chip for W5100S {} | ||
| 10 | impl super::sealed::Chip for W5100S { | ||
| 11 | type Address = u16; | ||
| 12 | |||
| 13 | const COMMON_MODE: Self::Address = 0x00; | ||
| 14 | const COMMON_MAC: Self::Address = 0x09; | ||
| 15 | const COMMON_SOCKET_INTR: Self::Address = 0x16; | ||
| 16 | const COMMON_PHY_CFG: Self::Address = 0x3c; | ||
| 17 | |||
| 18 | const SOCKET_MODE: Self::Address = SOCKET_BASE + 0x00; | ||
| 19 | const SOCKET_COMMAND: Self::Address = SOCKET_BASE + 0x01; | ||
| 20 | const SOCKET_RXBUF_SIZE: Self::Address = SOCKET_BASE + 0x1E; | ||
| 21 | const SOCKET_TXBUF_SIZE: Self::Address = SOCKET_BASE + 0x1F; | ||
| 22 | const SOCKET_TX_FREE_SIZE: Self::Address = SOCKET_BASE + 0x20; | ||
| 23 | const SOCKET_TX_DATA_WRITE_PTR: Self::Address = SOCKET_BASE + 0x24; | ||
| 24 | const SOCKET_RECVD_SIZE: Self::Address = SOCKET_BASE + 0x26; | ||
| 25 | const SOCKET_RX_DATA_READ_PTR: Self::Address = SOCKET_BASE + 0x28; | ||
| 26 | const SOCKET_INTR_MASK: Self::Address = SOCKET_BASE + 0x2C; | ||
| 27 | const SOCKET_INTR: Self::Address = SOCKET_BASE + 0x02; | ||
| 28 | |||
| 29 | const SOCKET_MODE_VALUE: u8 = (1 << 2) | (1 << 6); | ||
| 30 | |||
| 31 | const BUF_SIZE: u16 = 0x2000; | ||
| 32 | const AUTO_WRAP: bool = false; | ||
| 33 | |||
| 34 | fn rx_addr(addr: u16) -> Self::Address { | ||
| 35 | RX_BASE + addr | ||
| 36 | } | ||
| 37 | |||
| 38 | fn tx_addr(addr: u16) -> Self::Address { | ||
| 39 | TX_BASE + addr | ||
| 40 | } | ||
| 41 | |||
| 42 | async fn bus_read<SPI: SpiDevice>( | ||
| 43 | spi: &mut SPI, | ||
| 44 | address: Self::Address, | ||
| 45 | data: &mut [u8], | ||
| 46 | ) -> Result<(), SPI::Error> { | ||
| 47 | spi.transaction(&mut [ | ||
| 48 | Operation::Write(&[0x0F, (address >> 8) as u8, address as u8]), | ||
| 49 | Operation::Read(data), | ||
| 50 | ]) | ||
| 51 | .await | ||
| 52 | } | ||
| 53 | |||
| 54 | async fn bus_write<SPI: SpiDevice>(spi: &mut SPI, address: Self::Address, data: &[u8]) -> Result<(), SPI::Error> { | ||
| 55 | spi.transaction(&mut [ | ||
| 56 | Operation::Write(&[0xF0, (address >> 8) as u8, address as u8]), | ||
| 57 | Operation::Write(data), | ||
| 58 | ]) | ||
| 59 | .await | ||
| 60 | } | ||
| 61 | } | ||
diff --git a/embassy-net-wiznet/src/chip/w5500.rs b/embassy-net-wiznet/src/chip/w5500.rs new file mode 100644 index 000000000..61e512946 --- /dev/null +++ b/embassy-net-wiznet/src/chip/w5500.rs | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | use embedded_hal_async::spi::{Operation, SpiDevice}; | ||
| 2 | |||
| 3 | #[repr(u8)] | ||
| 4 | pub enum RegisterBlock { | ||
| 5 | Common = 0x00, | ||
| 6 | Socket0 = 0x01, | ||
| 7 | TxBuf = 0x02, | ||
| 8 | RxBuf = 0x03, | ||
| 9 | } | ||
| 10 | |||
| 11 | pub enum W5500 {} | ||
| 12 | |||
| 13 | impl super::Chip for W5500 {} | ||
| 14 | impl super::sealed::Chip for W5500 { | ||
| 15 | type Address = (RegisterBlock, u16); | ||
| 16 | |||
| 17 | const COMMON_MODE: Self::Address = (RegisterBlock::Common, 0x00); | ||
| 18 | const COMMON_MAC: Self::Address = (RegisterBlock::Common, 0x09); | ||
| 19 | const COMMON_SOCKET_INTR: Self::Address = (RegisterBlock::Common, 0x18); | ||
| 20 | const COMMON_PHY_CFG: Self::Address = (RegisterBlock::Common, 0x2E); | ||
| 21 | |||
| 22 | const SOCKET_MODE: Self::Address = (RegisterBlock::Socket0, 0x00); | ||
| 23 | const SOCKET_COMMAND: Self::Address = (RegisterBlock::Socket0, 0x01); | ||
| 24 | const SOCKET_RXBUF_SIZE: Self::Address = (RegisterBlock::Socket0, 0x1E); | ||
| 25 | const SOCKET_TXBUF_SIZE: Self::Address = (RegisterBlock::Socket0, 0x1F); | ||
| 26 | const SOCKET_TX_FREE_SIZE: Self::Address = (RegisterBlock::Socket0, 0x20); | ||
| 27 | const SOCKET_TX_DATA_WRITE_PTR: Self::Address = (RegisterBlock::Socket0, 0x24); | ||
| 28 | const SOCKET_RECVD_SIZE: Self::Address = (RegisterBlock::Socket0, 0x26); | ||
| 29 | const SOCKET_RX_DATA_READ_PTR: Self::Address = (RegisterBlock::Socket0, 0x28); | ||
| 30 | const SOCKET_INTR_MASK: Self::Address = (RegisterBlock::Socket0, 0x2C); | ||
| 31 | const SOCKET_INTR: Self::Address = (RegisterBlock::Socket0, 0x02); | ||
| 32 | |||
| 33 | const SOCKET_MODE_VALUE: u8 = (1 << 2) | (1 << 7); | ||
| 34 | |||
| 35 | const BUF_SIZE: u16 = 0x4000; | ||
| 36 | const AUTO_WRAP: bool = true; | ||
| 37 | |||
| 38 | fn rx_addr(addr: u16) -> Self::Address { | ||
| 39 | (RegisterBlock::RxBuf, addr) | ||
| 40 | } | ||
| 41 | |||
| 42 | fn tx_addr(addr: u16) -> Self::Address { | ||
| 43 | (RegisterBlock::TxBuf, addr) | ||
| 44 | } | ||
| 45 | |||
| 46 | async fn bus_read<SPI: SpiDevice>( | ||
| 47 | spi: &mut SPI, | ||
| 48 | address: Self::Address, | ||
| 49 | data: &mut [u8], | ||
| 50 | ) -> Result<(), SPI::Error> { | ||
| 51 | let address_phase = address.1.to_be_bytes(); | ||
| 52 | let control_phase = [(address.0 as u8) << 3]; | ||
| 53 | let operations = &mut [ | ||
| 54 | Operation::Write(&address_phase), | ||
| 55 | Operation::Write(&control_phase), | ||
| 56 | Operation::TransferInPlace(data), | ||
| 57 | ]; | ||
| 58 | spi.transaction(operations).await | ||
| 59 | } | ||
| 60 | |||
| 61 | async fn bus_write<SPI: SpiDevice>(spi: &mut SPI, address: Self::Address, data: &[u8]) -> Result<(), SPI::Error> { | ||
| 62 | let address_phase = address.1.to_be_bytes(); | ||
| 63 | let control_phase = [(address.0 as u8) << 3 | 0b0000_0100]; | ||
| 64 | let data_phase = data; | ||
| 65 | let operations = &mut [ | ||
| 66 | Operation::Write(&address_phase[..]), | ||
| 67 | Operation::Write(&control_phase), | ||
| 68 | Operation::Write(&data_phase), | ||
| 69 | ]; | ||
| 70 | spi.transaction(operations).await | ||
| 71 | } | ||
| 72 | } | ||
diff --git a/embassy-net-wiznet/src/device.rs b/embassy-net-wiznet/src/device.rs new file mode 100644 index 000000000..43f9512a3 --- /dev/null +++ b/embassy-net-wiznet/src/device.rs | |||
| @@ -0,0 +1,195 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use embedded_hal_async::spi::SpiDevice; | ||
| 4 | |||
| 5 | use crate::chip::Chip; | ||
| 6 | |||
| 7 | #[repr(u8)] | ||
| 8 | enum Command { | ||
| 9 | Open = 0x01, | ||
| 10 | Send = 0x20, | ||
| 11 | Receive = 0x40, | ||
| 12 | } | ||
| 13 | |||
| 14 | #[repr(u8)] | ||
| 15 | enum Interrupt { | ||
| 16 | Receive = 0b00100_u8, | ||
| 17 | } | ||
| 18 | |||
| 19 | /// Wiznet chip in MACRAW mode | ||
| 20 | #[derive(Debug)] | ||
| 21 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 22 | pub(crate) struct WiznetDevice<C, SPI> { | ||
| 23 | spi: SPI, | ||
| 24 | _phantom: PhantomData<C>, | ||
| 25 | } | ||
| 26 | |||
| 27 | impl<C: Chip, SPI: SpiDevice> WiznetDevice<C, SPI> { | ||
| 28 | /// Create and initialize the driver | ||
| 29 | pub async fn new(spi: SPI, mac_addr: [u8; 6]) -> Result<Self, SPI::Error> { | ||
| 30 | let mut this = Self { | ||
| 31 | spi, | ||
| 32 | _phantom: PhantomData, | ||
| 33 | }; | ||
| 34 | |||
| 35 | // Reset device | ||
| 36 | this.bus_write(C::COMMON_MODE, &[0x80]).await?; | ||
| 37 | |||
| 38 | // Enable interrupt pin | ||
| 39 | this.bus_write(C::COMMON_SOCKET_INTR, &[0x01]).await?; | ||
| 40 | // Enable receive interrupt | ||
| 41 | this.bus_write(C::SOCKET_INTR_MASK, &[Interrupt::Receive as u8]).await?; | ||
| 42 | |||
| 43 | // Set MAC address | ||
| 44 | this.bus_write(C::COMMON_MAC, &mac_addr).await?; | ||
| 45 | |||
| 46 | // Set the raw socket RX/TX buffer sizes. | ||
| 47 | let buf_kbs = (C::BUF_SIZE / 1024) as u8; | ||
| 48 | this.bus_write(C::SOCKET_TXBUF_SIZE, &[buf_kbs]).await?; | ||
| 49 | this.bus_write(C::SOCKET_RXBUF_SIZE, &[buf_kbs]).await?; | ||
| 50 | |||
| 51 | // MACRAW mode with MAC filtering. | ||
| 52 | this.bus_write(C::SOCKET_MODE, &[C::SOCKET_MODE_VALUE]).await?; | ||
| 53 | this.command(Command::Open).await?; | ||
| 54 | |||
| 55 | Ok(this) | ||
| 56 | } | ||
| 57 | |||
| 58 | async fn bus_read(&mut self, address: C::Address, data: &mut [u8]) -> Result<(), SPI::Error> { | ||
| 59 | C::bus_read(&mut self.spi, address, data).await | ||
| 60 | } | ||
| 61 | |||
| 62 | async fn bus_write(&mut self, address: C::Address, data: &[u8]) -> Result<(), SPI::Error> { | ||
| 63 | C::bus_write(&mut self.spi, address, data).await | ||
| 64 | } | ||
| 65 | |||
| 66 | async fn reset_interrupt(&mut self, code: Interrupt) -> Result<(), SPI::Error> { | ||
| 67 | let data = [code as u8]; | ||
| 68 | self.bus_write(C::SOCKET_INTR, &data).await | ||
| 69 | } | ||
| 70 | |||
| 71 | async fn get_tx_write_ptr(&mut self) -> Result<u16, SPI::Error> { | ||
| 72 | let mut data = [0u8; 2]; | ||
| 73 | self.bus_read(C::SOCKET_TX_DATA_WRITE_PTR, &mut data).await?; | ||
| 74 | Ok(u16::from_be_bytes(data)) | ||
| 75 | } | ||
| 76 | |||
| 77 | async fn set_tx_write_ptr(&mut self, ptr: u16) -> Result<(), SPI::Error> { | ||
| 78 | let data = ptr.to_be_bytes(); | ||
| 79 | self.bus_write(C::SOCKET_TX_DATA_WRITE_PTR, &data).await | ||
| 80 | } | ||
| 81 | |||
| 82 | async fn get_rx_read_ptr(&mut self) -> Result<u16, SPI::Error> { | ||
| 83 | let mut data = [0u8; 2]; | ||
| 84 | self.bus_read(C::SOCKET_RX_DATA_READ_PTR, &mut data).await?; | ||
| 85 | Ok(u16::from_be_bytes(data)) | ||
| 86 | } | ||
| 87 | |||
| 88 | async fn set_rx_read_ptr(&mut self, ptr: u16) -> Result<(), SPI::Error> { | ||
| 89 | let data = ptr.to_be_bytes(); | ||
| 90 | self.bus_write(C::SOCKET_RX_DATA_READ_PTR, &data).await | ||
| 91 | } | ||
| 92 | |||
| 93 | async fn command(&mut self, command: Command) -> Result<(), SPI::Error> { | ||
| 94 | let data = [command as u8]; | ||
| 95 | self.bus_write(C::SOCKET_COMMAND, &data).await | ||
| 96 | } | ||
| 97 | |||
| 98 | async fn get_rx_size(&mut self) -> Result<u16, SPI::Error> { | ||
| 99 | loop { | ||
| 100 | // Wait until two sequential reads are equal | ||
| 101 | let mut res0 = [0u8; 2]; | ||
| 102 | self.bus_read(C::SOCKET_RECVD_SIZE, &mut res0).await?; | ||
| 103 | let mut res1 = [0u8; 2]; | ||
| 104 | self.bus_read(C::SOCKET_RECVD_SIZE, &mut res1).await?; | ||
| 105 | if res0 == res1 { | ||
| 106 | break Ok(u16::from_be_bytes(res0)); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | async fn get_tx_free_size(&mut self) -> Result<u16, SPI::Error> { | ||
| 112 | let mut data = [0; 2]; | ||
| 113 | self.bus_read(C::SOCKET_TX_FREE_SIZE, &mut data).await?; | ||
| 114 | Ok(u16::from_be_bytes(data)) | ||
| 115 | } | ||
| 116 | |||
| 117 | /// Read bytes from the RX buffer. | ||
| 118 | async fn read_bytes(&mut self, read_ptr: &mut u16, buffer: &mut [u8]) -> Result<(), SPI::Error> { | ||
| 119 | if C::AUTO_WRAP { | ||
| 120 | self.bus_read(C::rx_addr(*read_ptr), buffer).await?; | ||
| 121 | } else { | ||
| 122 | let addr = *read_ptr % C::BUF_SIZE; | ||
| 123 | if addr as usize + buffer.len() <= C::BUF_SIZE as usize { | ||
| 124 | self.bus_read(C::rx_addr(addr), buffer).await?; | ||
| 125 | } else { | ||
| 126 | let n = C::BUF_SIZE - addr; | ||
| 127 | self.bus_read(C::rx_addr(addr), &mut buffer[..n as usize]).await?; | ||
| 128 | self.bus_read(C::rx_addr(0), &mut buffer[n as usize..]).await?; | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | *read_ptr = (*read_ptr).wrapping_add(buffer.len() as u16); | ||
| 133 | |||
| 134 | Ok(()) | ||
| 135 | } | ||
| 136 | |||
| 137 | /// Read an ethernet frame from the device. Returns the number of bytes read. | ||
| 138 | pub async fn read_frame(&mut self, frame: &mut [u8]) -> Result<usize, SPI::Error> { | ||
| 139 | let rx_size = self.get_rx_size().await? as usize; | ||
| 140 | if rx_size == 0 { | ||
| 141 | return Ok(0); | ||
| 142 | } | ||
| 143 | |||
| 144 | self.reset_interrupt(Interrupt::Receive).await?; | ||
| 145 | |||
| 146 | let mut read_ptr = self.get_rx_read_ptr().await?; | ||
| 147 | |||
| 148 | // First two bytes gives the size of the received ethernet frame | ||
| 149 | let expected_frame_size: usize = { | ||
| 150 | let mut frame_bytes = [0u8; 2]; | ||
| 151 | self.read_bytes(&mut read_ptr, &mut frame_bytes).await?; | ||
| 152 | u16::from_be_bytes(frame_bytes) as usize - 2 | ||
| 153 | }; | ||
| 154 | |||
| 155 | // Read the ethernet frame | ||
| 156 | self.read_bytes(&mut read_ptr, &mut frame[..expected_frame_size]) | ||
| 157 | .await?; | ||
| 158 | |||
| 159 | // Register RX as completed | ||
| 160 | self.set_rx_read_ptr(read_ptr).await?; | ||
| 161 | self.command(Command::Receive).await?; | ||
| 162 | |||
| 163 | Ok(expected_frame_size) | ||
| 164 | } | ||
| 165 | |||
| 166 | /// Write an ethernet frame to the device. Returns number of bytes written | ||
| 167 | pub async fn write_frame(&mut self, frame: &[u8]) -> Result<usize, SPI::Error> { | ||
| 168 | while self.get_tx_free_size().await? < frame.len() as u16 {} | ||
| 169 | let write_ptr = self.get_tx_write_ptr().await?; | ||
| 170 | |||
| 171 | if C::AUTO_WRAP { | ||
| 172 | self.bus_write(C::tx_addr(write_ptr), frame).await?; | ||
| 173 | } else { | ||
| 174 | let addr = write_ptr % C::BUF_SIZE; | ||
| 175 | if addr as usize + frame.len() <= C::BUF_SIZE as usize { | ||
| 176 | self.bus_write(C::tx_addr(addr), frame).await?; | ||
| 177 | } else { | ||
| 178 | let n = C::BUF_SIZE - addr; | ||
| 179 | self.bus_write(C::tx_addr(addr), &frame[..n as usize]).await?; | ||
| 180 | self.bus_write(C::tx_addr(0), &frame[n as usize..]).await?; | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | self.set_tx_write_ptr(write_ptr.wrapping_add(frame.len() as u16)) | ||
| 185 | .await?; | ||
| 186 | self.command(Command::Send).await?; | ||
| 187 | Ok(frame.len()) | ||
| 188 | } | ||
| 189 | |||
| 190 | pub async fn is_link_up(&mut self) -> bool { | ||
| 191 | let mut link = [0]; | ||
| 192 | self.bus_read(C::COMMON_PHY_CFG, &mut link).await.ok(); | ||
| 193 | link[0] & 1 == 1 | ||
| 194 | } | ||
| 195 | } | ||
diff --git a/embassy-net-w5500/src/lib.rs b/embassy-net-wiznet/src/lib.rs index 52494b443..3030dfb90 100644 --- a/embassy-net-w5500/src/lib.rs +++ b/embassy-net-wiznet/src/lib.rs | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | //! [`embassy-net`](https://crates.io/crates/embassy-net) driver for the WIZnet W5500 ethernet chip. | 1 | //! [`embassy-net`](https://crates.io/crates/embassy-net) driver for WIZnet ethernet chips. |
| 2 | #![no_std] | 2 | #![no_std] |
| 3 | #![feature(async_fn_in_trait)] | ||
| 3 | 4 | ||
| 5 | pub mod chip; | ||
| 4 | mod device; | 6 | mod device; |
| 5 | mod socket; | ||
| 6 | mod spi; | ||
| 7 | 7 | ||
| 8 | use embassy_futures::select::{select, Either}; | 8 | use embassy_futures::select::{select, Either}; |
| 9 | use embassy_net_driver_channel as ch; | 9 | use embassy_net_driver_channel as ch; |
| @@ -13,10 +13,12 @@ use embedded_hal::digital::OutputPin; | |||
| 13 | use embedded_hal_async::digital::Wait; | 13 | use embedded_hal_async::digital::Wait; |
| 14 | use embedded_hal_async::spi::SpiDevice; | 14 | use embedded_hal_async::spi::SpiDevice; |
| 15 | 15 | ||
| 16 | use crate::device::W5500; | 16 | use crate::chip::Chip; |
| 17 | use crate::device::WiznetDevice; | ||
| 18 | |||
| 17 | const MTU: usize = 1514; | 19 | const MTU: usize = 1514; |
| 18 | 20 | ||
| 19 | /// Type alias for the embassy-net driver for W5500 | 21 | /// Type alias for the embassy-net driver. |
| 20 | pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>; | 22 | pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>; |
| 21 | 23 | ||
| 22 | /// Internal state for the embassy-net integration. | 24 | /// Internal state for the embassy-net integration. |
| @@ -33,18 +35,18 @@ impl<const N_RX: usize, const N_TX: usize> State<N_RX, N_TX> { | |||
| 33 | } | 35 | } |
| 34 | } | 36 | } |
| 35 | 37 | ||
| 36 | /// Background runner for the W5500. | 38 | /// Background runner for the driver. |
| 37 | /// | 39 | /// |
| 38 | /// You must call `.run()` in a background task for the W5500 to operate. | 40 | /// You must call `.run()` in a background task for the driver to operate. |
| 39 | pub struct Runner<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> { | 41 | pub struct Runner<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> { |
| 40 | mac: W5500<SPI>, | 42 | mac: WiznetDevice<C, SPI>, |
| 41 | ch: ch::Runner<'d, MTU>, | 43 | ch: ch::Runner<'d, MTU>, |
| 42 | int: INT, | 44 | int: INT, |
| 43 | _reset: RST, | 45 | _reset: RST, |
| 44 | } | 46 | } |
| 45 | 47 | ||
| 46 | /// You must call this in a background task for the W5500 to operate. | 48 | /// You must call this in a background task for the driver to operate. |
| 47 | impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { | 49 | impl<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, C, SPI, INT, RST> { |
| 48 | pub async fn run(mut self) -> ! { | 50 | pub async fn run(mut self) -> ! { |
| 49 | let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); | 51 | let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); |
| 50 | loop { | 52 | loop { |
| @@ -78,23 +80,29 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { | |||
| 78 | } | 80 | } |
| 79 | } | 81 | } |
| 80 | 82 | ||
| 81 | /// Obtain a driver for using the W5500 with [`embassy-net`](https://crates.io/crates/embassy-net). | 83 | /// Create a Wiznet ethernet chip driver for [`embassy-net`](https://crates.io/crates/embassy-net). |
| 82 | pub async fn new<'a, const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait, RST: OutputPin>( | 84 | /// |
| 85 | /// This returns two structs: | ||
| 86 | /// - a `Device` that you must pass to the `embassy-net` stack. | ||
| 87 | /// - a `Runner`. You must call `.run()` on it in a background task. | ||
| 88 | pub async fn new<'a, const N_RX: usize, const N_TX: usize, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin>( | ||
| 83 | mac_addr: [u8; 6], | 89 | mac_addr: [u8; 6], |
| 84 | state: &'a mut State<N_RX, N_TX>, | 90 | state: &'a mut State<N_RX, N_TX>, |
| 85 | spi_dev: SPI, | 91 | spi_dev: SPI, |
| 86 | int: INT, | 92 | int: INT, |
| 87 | mut reset: RST, | 93 | mut reset: RST, |
| 88 | ) -> (Device<'a>, Runner<'a, SPI, INT, RST>) { | 94 | ) -> (Device<'a>, Runner<'a, C, SPI, INT, RST>) { |
| 89 | // Reset the W5500. | 95 | // Reset the chip. |
| 90 | reset.set_low().ok(); | 96 | reset.set_low().ok(); |
| 91 | // Ensure the reset is registered. | 97 | // Ensure the reset is registered. |
| 92 | Timer::after(Duration::from_millis(1)).await; | 98 | Timer::after(Duration::from_millis(1)).await; |
| 93 | reset.set_high().ok(); | 99 | reset.set_high().ok(); |
| 94 | // Wait for the W5500 to achieve PLL lock. | ||
| 95 | Timer::after(Duration::from_millis(2)).await; | ||
| 96 | 100 | ||
| 97 | let mac = W5500::new(spi_dev, mac_addr).await.unwrap(); | 101 | // Wait for PLL lock. Some chips are slower than others. |
| 102 | // Slowest is w5100s which is 100ms, so let's just wait that. | ||
| 103 | Timer::after(Duration::from_millis(100)).await; | ||
| 104 | |||
| 105 | let mac = WiznetDevice::new(spi_dev, mac_addr).await.unwrap(); | ||
| 98 | 106 | ||
| 99 | let (runner, device) = ch::new(&mut state.ch_state, ch::driver::HardwareAddress::Ethernet(mac_addr)); | 107 | let (runner, device) = ch::new(&mut state.ch_state, ch::driver::HardwareAddress::Ethernet(mac_addr)); |
| 100 | ( | 108 | ( |
diff --git a/embassy-net/README.md b/embassy-net/README.md index 811321ca4..7bb2283c4 100644 --- a/embassy-net/README.md +++ b/embassy-net/README.md | |||
| @@ -22,7 +22,7 @@ unimplemented features of the network protocols. | |||
| 22 | - [`cyw43`](https://github.com/embassy-rs/embassy/tree/main/cyw43) for WiFi on CYW43xx chips, used in the Raspberry Pi Pico W | 22 | - [`cyw43`](https://github.com/embassy-rs/embassy/tree/main/cyw43) for WiFi on CYW43xx chips, used in the Raspberry Pi Pico W |
| 23 | - [`embassy-usb`](https://github.com/embassy-rs/embassy/tree/main/embassy-usb) for Ethernet-over-USB (CDC NCM) support. | 23 | - [`embassy-usb`](https://github.com/embassy-rs/embassy/tree/main/embassy-usb) for Ethernet-over-USB (CDC NCM) support. |
| 24 | - [`embassy-stm32`](https://github.com/embassy-rs/embassy/tree/main/embassy-stm32) for the builtin Ethernet MAC in all STM32 chips (STM32F1, STM32F2, STM32F4, STM32F7, STM32H7, STM32H5). | 24 | - [`embassy-stm32`](https://github.com/embassy-rs/embassy/tree/main/embassy-stm32) for the builtin Ethernet MAC in all STM32 chips (STM32F1, STM32F2, STM32F4, STM32F7, STM32H7, STM32H5). |
| 25 | - [`embassy-net-w5500`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-w5500) for Wiznet W5500 SPI Ethernet MAC+PHY chip. | 25 | - [`embassy-net-wiznet`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-wiznet) for Wiznet SPI Ethernet MAC+PHY chips (W5100S, W5500) |
| 26 | - [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU. | 26 | - [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU. |
| 27 | 27 | ||
| 28 | ## Examples | 28 | ## Examples |
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index c903fb245..c92ad2d2e 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs | |||
| @@ -82,6 +82,22 @@ impl<'a> TcpReader<'a> { | |||
| 82 | pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { | 82 | pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { |
| 83 | self.io.read(buf).await | 83 | self.io.read(buf).await |
| 84 | } | 84 | } |
| 85 | |||
| 86 | /// Call `f` with the largest contiguous slice of octets in the receive buffer, | ||
| 87 | /// and dequeue the amount of elements returned by `f`. | ||
| 88 | /// | ||
| 89 | /// If no data is available, it waits until there is at least one byte available. | ||
| 90 | pub async fn read_with<F, R>(&mut self, f: F) -> Result<R, Error> | ||
| 91 | where | ||
| 92 | F: FnOnce(&mut [u8]) -> (usize, R), | ||
| 93 | { | ||
| 94 | self.io.read_with(f).await | ||
| 95 | } | ||
| 96 | |||
| 97 | /// Return the maximum number of bytes inside the transmit buffer. | ||
| 98 | pub fn recv_capacity(&self) -> usize { | ||
| 99 | self.io.recv_capacity() | ||
| 100 | } | ||
| 85 | } | 101 | } |
| 86 | 102 | ||
| 87 | impl<'a> TcpWriter<'a> { | 103 | impl<'a> TcpWriter<'a> { |
| @@ -100,6 +116,22 @@ impl<'a> TcpWriter<'a> { | |||
| 100 | pub async fn flush(&mut self) -> Result<(), Error> { | 116 | pub async fn flush(&mut self) -> Result<(), Error> { |
| 101 | self.io.flush().await | 117 | self.io.flush().await |
| 102 | } | 118 | } |
| 119 | |||
| 120 | /// Call `f` with the largest contiguous slice of octets in the transmit buffer, | ||
| 121 | /// and enqueue the amount of elements returned by `f`. | ||
| 122 | /// | ||
| 123 | /// If the socket is not ready to accept data, it waits until it is. | ||
| 124 | pub async fn write_with<F, R>(&mut self, f: F) -> Result<R, Error> | ||
| 125 | where | ||
| 126 | F: FnOnce(&mut [u8]) -> (usize, R), | ||
| 127 | { | ||
| 128 | self.io.write_with(f).await | ||
| 129 | } | ||
| 130 | |||
| 131 | /// Return the maximum number of bytes inside the transmit buffer. | ||
| 132 | pub fn send_capacity(&self) -> usize { | ||
| 133 | self.io.send_capacity() | ||
| 134 | } | ||
| 103 | } | 135 | } |
| 104 | 136 | ||
| 105 | impl<'a> TcpSocket<'a> { | 137 | impl<'a> TcpSocket<'a> { |
| @@ -121,6 +153,38 @@ impl<'a> TcpSocket<'a> { | |||
| 121 | } | 153 | } |
| 122 | } | 154 | } |
| 123 | 155 | ||
| 156 | /// Return the maximum number of bytes inside the recv buffer. | ||
| 157 | pub fn recv_capacity(&self) -> usize { | ||
| 158 | self.io.recv_capacity() | ||
| 159 | } | ||
| 160 | |||
| 161 | /// Return the maximum number of bytes inside the transmit buffer. | ||
| 162 | pub fn send_capacity(&self) -> usize { | ||
| 163 | self.io.send_capacity() | ||
| 164 | } | ||
| 165 | |||
| 166 | /// Call `f` with the largest contiguous slice of octets in the transmit buffer, | ||
| 167 | /// and enqueue the amount of elements returned by `f`. | ||
| 168 | /// | ||
| 169 | /// If the socket is not ready to accept data, it waits until it is. | ||
| 170 | pub async fn write_with<F, R>(&mut self, f: F) -> Result<R, Error> | ||
| 171 | where | ||
| 172 | F: FnOnce(&mut [u8]) -> (usize, R), | ||
| 173 | { | ||
| 174 | self.io.write_with(f).await | ||
| 175 | } | ||
| 176 | |||
| 177 | /// Call `f` with the largest contiguous slice of octets in the receive buffer, | ||
| 178 | /// and dequeue the amount of elements returned by `f`. | ||
| 179 | /// | ||
| 180 | /// If no data is available, it waits until there is at least one byte available. | ||
| 181 | pub async fn read_with<F, R>(&mut self, f: F) -> Result<R, Error> | ||
| 182 | where | ||
| 183 | F: FnOnce(&mut [u8]) -> (usize, R), | ||
| 184 | { | ||
| 185 | self.io.read_with(f).await | ||
| 186 | } | ||
| 187 | |||
| 124 | /// Split the socket into reader and a writer halves. | 188 | /// Split the socket into reader and a writer halves. |
| 125 | pub fn split(&mut self) -> (TcpReader<'_>, TcpWriter<'_>) { | 189 | pub fn split(&mut self) -> (TcpReader<'_>, TcpWriter<'_>) { |
| 126 | (TcpReader { io: self.io }, TcpWriter { io: self.io }) | 190 | (TcpReader { io: self.io }, TcpWriter { io: self.io }) |
| @@ -359,6 +423,64 @@ impl<'d> TcpIo<'d> { | |||
| 359 | .await | 423 | .await |
| 360 | } | 424 | } |
| 361 | 425 | ||
| 426 | async fn write_with<F, R>(&mut self, f: F) -> Result<R, Error> | ||
| 427 | where | ||
| 428 | F: FnOnce(&mut [u8]) -> (usize, R), | ||
| 429 | { | ||
| 430 | let mut f = Some(f); | ||
| 431 | poll_fn(move |cx| { | ||
| 432 | self.with_mut(|s, _| { | ||
| 433 | if !s.can_send() { | ||
| 434 | if s.may_send() { | ||
| 435 | // socket buffer is full wait until it has atleast one byte free | ||
| 436 | s.register_send_waker(cx.waker()); | ||
| 437 | Poll::Pending | ||
| 438 | } else { | ||
| 439 | // if we can't transmit because the transmit half of the duplex connection is closed then return an error | ||
| 440 | Poll::Ready(Err(Error::ConnectionReset)) | ||
| 441 | } | ||
| 442 | } else { | ||
| 443 | Poll::Ready(match s.send(f.take().unwrap()) { | ||
| 444 | // Connection reset. TODO: this can also be timeouts etc, investigate. | ||
| 445 | Err(tcp::SendError::InvalidState) => Err(Error::ConnectionReset), | ||
| 446 | Ok(r) => Ok(r), | ||
| 447 | }) | ||
| 448 | } | ||
| 449 | }) | ||
| 450 | }) | ||
| 451 | .await | ||
| 452 | } | ||
| 453 | |||
| 454 | async fn read_with<F, R>(&mut self, f: F) -> Result<R, Error> | ||
| 455 | where | ||
| 456 | F: FnOnce(&mut [u8]) -> (usize, R), | ||
| 457 | { | ||
| 458 | let mut f = Some(f); | ||
| 459 | poll_fn(move |cx| { | ||
| 460 | self.with_mut(|s, _| { | ||
| 461 | if !s.can_recv() { | ||
| 462 | if s.may_recv() { | ||
| 463 | // socket buffer is empty wait until it has atleast one byte has arrived | ||
| 464 | s.register_recv_waker(cx.waker()); | ||
| 465 | Poll::Pending | ||
| 466 | } else { | ||
| 467 | // if we can't receive because the recieve half of the duplex connection is closed then return an error | ||
| 468 | Poll::Ready(Err(Error::ConnectionReset)) | ||
| 469 | } | ||
| 470 | } else { | ||
| 471 | Poll::Ready(match s.recv(f.take().unwrap()) { | ||
| 472 | // Connection reset. TODO: this can also be timeouts etc, investigate. | ||
| 473 | Err(tcp::RecvError::Finished) | Err(tcp::RecvError::InvalidState) => { | ||
| 474 | Err(Error::ConnectionReset) | ||
| 475 | } | ||
| 476 | Ok(r) => Ok(r), | ||
| 477 | }) | ||
| 478 | } | ||
| 479 | }) | ||
| 480 | }) | ||
| 481 | .await | ||
| 482 | } | ||
| 483 | |||
| 362 | async fn flush(&mut self) -> Result<(), Error> { | 484 | async fn flush(&mut self) -> Result<(), Error> { |
| 363 | poll_fn(move |cx| { | 485 | poll_fn(move |cx| { |
| 364 | self.with_mut(|s, _| { | 486 | self.with_mut(|s, _| { |
| @@ -376,6 +498,14 @@ impl<'d> TcpIo<'d> { | |||
| 376 | }) | 498 | }) |
| 377 | .await | 499 | .await |
| 378 | } | 500 | } |
| 501 | |||
| 502 | fn recv_capacity(&self) -> usize { | ||
| 503 | self.with(|s, _| s.recv_capacity()) | ||
| 504 | } | ||
| 505 | |||
| 506 | fn send_capacity(&self) -> usize { | ||
| 507 | self.with(|s, _| s.send_capacity()) | ||
| 508 | } | ||
| 379 | } | 509 | } |
| 380 | 510 | ||
| 381 | #[cfg(feature = "nightly")] | 511 | #[cfg(feature = "nightly")] |
| @@ -384,13 +514,20 @@ mod embedded_io_impls { | |||
| 384 | 514 | ||
| 385 | impl embedded_io_async::Error for ConnectError { | 515 | impl embedded_io_async::Error for ConnectError { |
| 386 | fn kind(&self) -> embedded_io_async::ErrorKind { | 516 | fn kind(&self) -> embedded_io_async::ErrorKind { |
| 387 | embedded_io_async::ErrorKind::Other | 517 | match self { |
| 518 | ConnectError::ConnectionReset => embedded_io_async::ErrorKind::ConnectionReset, | ||
| 519 | ConnectError::TimedOut => embedded_io_async::ErrorKind::TimedOut, | ||
| 520 | ConnectError::NoRoute => embedded_io_async::ErrorKind::NotConnected, | ||
| 521 | ConnectError::InvalidState => embedded_io_async::ErrorKind::Other, | ||
| 522 | } | ||
| 388 | } | 523 | } |
| 389 | } | 524 | } |
| 390 | 525 | ||
| 391 | impl embedded_io_async::Error for Error { | 526 | impl embedded_io_async::Error for Error { |
| 392 | fn kind(&self) -> embedded_io_async::ErrorKind { | 527 | fn kind(&self) -> embedded_io_async::ErrorKind { |
| 393 | embedded_io_async::ErrorKind::Other | 528 | match self { |
| 529 | Error::ConnectionReset => embedded_io_async::ErrorKind::ConnectionReset, | ||
| 530 | } | ||
| 394 | } | 531 | } |
| 395 | } | 532 | } |
| 396 | 533 | ||
diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 0d97b6db1..0a5a7b8f6 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs | |||
| @@ -184,6 +184,26 @@ impl<'a> UdpSocket<'a> { | |||
| 184 | pub fn may_recv(&self) -> bool { | 184 | pub fn may_recv(&self) -> bool { |
| 185 | self.with(|s, _| s.can_recv()) | 185 | self.with(|s, _| s.can_recv()) |
| 186 | } | 186 | } |
| 187 | |||
| 188 | /// Return the maximum number packets the socket can receive. | ||
| 189 | pub fn packet_recv_capacity(&self) -> usize { | ||
| 190 | self.with(|s, _| s.packet_recv_capacity()) | ||
| 191 | } | ||
| 192 | |||
| 193 | /// Return the maximum number packets the socket can receive. | ||
| 194 | pub fn packet_send_capacity(&self) -> usize { | ||
| 195 | self.with(|s, _| s.packet_send_capacity()) | ||
| 196 | } | ||
| 197 | |||
| 198 | /// Return the maximum number of bytes inside the recv buffer. | ||
| 199 | pub fn payload_recv_capacity(&self) -> usize { | ||
| 200 | self.with(|s, _| s.payload_recv_capacity()) | ||
| 201 | } | ||
| 202 | |||
| 203 | /// Return the maximum number of bytes inside the transmit buffer. | ||
| 204 | pub fn payload_send_capacity(&self) -> usize { | ||
| 205 | self.with(|s, _| s.payload_send_capacity()) | ||
| 206 | } | ||
| 187 | } | 207 | } |
| 188 | 208 | ||
| 189 | impl Drop for UdpSocket<'_> { | 209 | impl Drop for UdpSocket<'_> { |
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index da1cd38e1..67ec4eb93 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml | |||
| @@ -32,7 +32,7 @@ rt = [ | |||
| 32 | 32 | ||
| 33 | time = ["dep:embassy-time"] | 33 | time = ["dep:embassy-time"] |
| 34 | 34 | ||
| 35 | defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-usb-driver?/defmt", "embassy-embedded-hal/defmt"] | 35 | defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "embassy-usb-driver?/defmt", "embassy-embedded-hal/defmt"] |
| 36 | 36 | ||
| 37 | # Enable nightly-only features | 37 | # Enable nightly-only features |
| 38 | nightly = ["embedded-hal-1", "embedded-hal-async", "dep:embassy-usb-driver", "embedded-storage-async", "dep:embedded-io-async", "embassy-embedded-hal/nightly"] | 38 | nightly = ["embedded-hal-1", "embedded-hal-async", "dep:embassy-usb-driver", "embedded-storage-async", "dep:embedded-io-async", "embassy-embedded-hal/nightly"] |
| @@ -98,8 +98,8 @@ embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } | |||
| 98 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true } | 98 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true } |
| 99 | 99 | ||
| 100 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 100 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 101 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11", optional = true} | 101 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = true} |
| 102 | embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true} | 102 | embedded-hal-async = { version = "=1.0.0-rc.1", optional = true} |
| 103 | embedded-io = { version = "0.5.0" } | 103 | embedded-io = { version = "0.5.0" } |
| 104 | embedded-io-async = { version = "0.5.0", optional = true } | 104 | embedded-io-async = { version = "0.5.0", optional = true } |
| 105 | 105 | ||
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index 4673a0175..d131a43dd 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs | |||
| @@ -378,6 +378,9 @@ impl<'d, T: Instance> Drop for Spim<'d, T> { | |||
| 378 | gpio::deconfigure_pin(r.psel.miso.read().bits()); | 378 | gpio::deconfigure_pin(r.psel.miso.read().bits()); |
| 379 | gpio::deconfigure_pin(r.psel.mosi.read().bits()); | 379 | gpio::deconfigure_pin(r.psel.mosi.read().bits()); |
| 380 | 380 | ||
| 381 | // Disable all events interrupts | ||
| 382 | T::Interrupt::disable(); | ||
| 383 | |||
| 381 | trace!("spim drop: done"); | 384 | trace!("spim drop: done"); |
| 382 | } | 385 | } |
| 383 | } | 386 | } |
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index e79df3561..95434e7a7 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs | |||
| @@ -949,51 +949,3 @@ mod eh02 { | |||
| 949 | } | 949 | } |
| 950 | } | 950 | } |
| 951 | } | 951 | } |
| 952 | |||
| 953 | #[cfg(feature = "unstable-traits")] | ||
| 954 | mod eh1 { | ||
| 955 | use super::*; | ||
| 956 | |||
| 957 | impl embedded_hal_1::serial::Error for Error { | ||
| 958 | fn kind(&self) -> embedded_hal_1::serial::ErrorKind { | ||
| 959 | match *self { | ||
| 960 | Self::BufferTooLong => embedded_hal_1::serial::ErrorKind::Other, | ||
| 961 | Self::BufferNotInRAM => embedded_hal_1::serial::ErrorKind::Other, | ||
| 962 | } | ||
| 963 | } | ||
| 964 | } | ||
| 965 | |||
| 966 | // ===================== | ||
| 967 | |||
| 968 | impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for Uarte<'d, T> { | ||
| 969 | type Error = Error; | ||
| 970 | } | ||
| 971 | |||
| 972 | impl<'d, T: Instance> embedded_hal_1::serial::Write for Uarte<'d, T> { | ||
| 973 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 974 | self.blocking_write(buffer) | ||
| 975 | } | ||
| 976 | |||
| 977 | fn flush(&mut self) -> Result<(), Self::Error> { | ||
| 978 | Ok(()) | ||
| 979 | } | ||
| 980 | } | ||
| 981 | |||
| 982 | impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteTx<'d, T> { | ||
| 983 | type Error = Error; | ||
| 984 | } | ||
| 985 | |||
| 986 | impl<'d, T: Instance> embedded_hal_1::serial::Write for UarteTx<'d, T> { | ||
| 987 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 988 | self.blocking_write(buffer) | ||
| 989 | } | ||
| 990 | |||
| 991 | fn flush(&mut self) -> Result<(), Self::Error> { | ||
| 992 | Ok(()) | ||
| 993 | } | ||
| 994 | } | ||
| 995 | |||
| 996 | impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteRx<'d, T> { | ||
| 997 | type Error = Error; | ||
| 998 | } | ||
| 999 | } | ||
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index b1680d487..b9ebcc866 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml | |||
| @@ -85,9 +85,9 @@ fixed = "1.23.1" | |||
| 85 | rp-pac = { version = "6" } | 85 | rp-pac = { version = "6" } |
| 86 | 86 | ||
| 87 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 87 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 88 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11", optional = true} | 88 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = true} |
| 89 | embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true} | 89 | embedded-hal-async = { version = "=1.0.0-rc.1", optional = true} |
| 90 | embedded-hal-nb = { version = "=1.0.0-alpha.3", optional = true} | 90 | embedded-hal-nb = { version = "=1.0.0-rc.1", optional = true} |
| 91 | 91 | ||
| 92 | paste = "1.0" | 92 | paste = "1.0" |
| 93 | pio-proc = {version= "0.2" } | 93 | pio-proc = {version= "0.2" } |
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index c8f741804..45ca21a75 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs | |||
| @@ -76,7 +76,8 @@ pub unsafe fn write<'a, C: Channel, W: Word>( | |||
| 76 | ) | 76 | ) |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | static DUMMY: u32 = 0; | 79 | // static mut so that this is allocated in RAM. |
| 80 | static mut DUMMY: u32 = 0; | ||
| 80 | 81 | ||
| 81 | pub unsafe fn write_repeated<'a, C: Channel, W: Word>( | 82 | pub unsafe fn write_repeated<'a, C: Channel, W: Word>( |
| 82 | ch: impl Peripheral<P = C> + 'a, | 83 | ch: impl Peripheral<P = C> + 'a, |
| @@ -86,7 +87,7 @@ pub unsafe fn write_repeated<'a, C: Channel, W: Word>( | |||
| 86 | ) -> Transfer<'a, C> { | 87 | ) -> Transfer<'a, C> { |
| 87 | copy_inner( | 88 | copy_inner( |
| 88 | ch, | 89 | ch, |
| 89 | &DUMMY as *const u32, | 90 | &mut DUMMY as *const u32, |
| 90 | to as *mut u32, | 91 | to as *mut u32, |
| 91 | len, | 92 | len, |
| 92 | W::size(), | 93 | W::size(), |
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 70d867319..1c1c2449e 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs | |||
| @@ -102,7 +102,7 @@ pub struct Flash<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> { | |||
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SIZE> { | 104 | impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SIZE> { |
| 105 | pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { | 105 | pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { |
| 106 | trace!( | 106 | trace!( |
| 107 | "Reading from 0x{:x} to 0x{:x}", | 107 | "Reading from 0x{:x} to 0x{:x}", |
| 108 | FLASH_BASE as u32 + offset, | 108 | FLASH_BASE as u32 + offset, |
| @@ -120,7 +120,7 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI | |||
| 120 | FLASH_SIZE | 120 | FLASH_SIZE |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | pub fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { | 123 | pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> { |
| 124 | check_erase(self, from, to)?; | 124 | check_erase(self, from, to)?; |
| 125 | 125 | ||
| 126 | trace!( | 126 | trace!( |
| @@ -136,7 +136,7 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI | |||
| 136 | Ok(()) | 136 | Ok(()) |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | pub fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { | 139 | pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { |
| 140 | check_write(self, offset, bytes.len())?; | 140 | check_write(self, offset, bytes.len())?; |
| 141 | 141 | ||
| 142 | trace!("Writing {:?} bytes to 0x{:x}", bytes.len(), FLASH_BASE as u32 + offset); | 142 | trace!("Writing {:?} bytes to 0x{:x}", bytes.len(), FLASH_BASE as u32 + offset); |
| @@ -233,13 +233,13 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI | |||
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | /// Read SPI flash unique ID | 235 | /// Read SPI flash unique ID |
| 236 | pub fn unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> { | 236 | pub fn blocking_unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> { |
| 237 | unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid))? }; | 237 | unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid))? }; |
| 238 | Ok(()) | 238 | Ok(()) |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | /// Read SPI flash JEDEC ID | 241 | /// Read SPI flash JEDEC ID |
| 242 | pub fn jedec_id(&mut self) -> Result<u32, Error> { | 242 | pub fn blocking_jedec_id(&mut self) -> Result<u32, Error> { |
| 243 | let mut jedec = None; | 243 | let mut jedec = None; |
| 244 | unsafe { | 244 | unsafe { |
| 245 | self.in_ram(|| { | 245 | self.in_ram(|| { |
| @@ -251,7 +251,7 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI | |||
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Blocking, FLASH_SIZE> { | 253 | impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Blocking, FLASH_SIZE> { |
| 254 | pub fn new(_flash: impl Peripheral<P = T> + 'd) -> Self { | 254 | pub fn new_blocking(_flash: impl Peripheral<P = T> + 'd) -> Self { |
| 255 | Self { | 255 | Self { |
| 256 | dma: None, | 256 | dma: None, |
| 257 | phantom: PhantomData, | 257 | phantom: PhantomData, |
| @@ -310,47 +310,8 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> { | |||
| 310 | transfer, | 310 | transfer, |
| 311 | }) | 311 | }) |
| 312 | } | 312 | } |
| 313 | } | ||
| 314 | |||
| 315 | impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> ErrorType for Flash<'d, T, M, FLASH_SIZE> { | ||
| 316 | type Error = Error; | ||
| 317 | } | ||
| 318 | |||
| 319 | impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> ReadNorFlash for Flash<'d, T, M, FLASH_SIZE> { | ||
| 320 | const READ_SIZE: usize = READ_SIZE; | ||
| 321 | |||
| 322 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | ||
| 323 | self.read(offset, bytes) | ||
| 324 | } | ||
| 325 | |||
| 326 | fn capacity(&self) -> usize { | ||
| 327 | self.capacity() | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<'d, T, M, FLASH_SIZE> {} | ||
| 332 | |||
| 333 | impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, M, FLASH_SIZE> { | ||
| 334 | const WRITE_SIZE: usize = WRITE_SIZE; | ||
| 335 | |||
| 336 | const ERASE_SIZE: usize = ERASE_SIZE; | ||
| 337 | |||
| 338 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | ||
| 339 | self.erase(from, to) | ||
| 340 | } | ||
| 341 | 313 | ||
| 342 | fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { | 314 | pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { |
| 343 | self.write(offset, bytes) | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | #[cfg(feature = "nightly")] | ||
| 348 | impl<'d, T: Instance, const FLASH_SIZE: usize> embedded_storage_async::nor_flash::ReadNorFlash | ||
| 349 | for Flash<'d, T, Async, FLASH_SIZE> | ||
| 350 | { | ||
| 351 | const READ_SIZE: usize = ASYNC_READ_SIZE; | ||
| 352 | |||
| 353 | async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | ||
| 354 | use core::mem::MaybeUninit; | 315 | use core::mem::MaybeUninit; |
| 355 | 316 | ||
| 356 | // Checked early to simplify address validity checks | 317 | // Checked early to simplify address validity checks |
| @@ -389,6 +350,49 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> embedded_storage_async::nor_flash | |||
| 389 | 350 | ||
| 390 | Ok(()) | 351 | Ok(()) |
| 391 | } | 352 | } |
| 353 | } | ||
| 354 | |||
| 355 | impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> ErrorType for Flash<'d, T, M, FLASH_SIZE> { | ||
| 356 | type Error = Error; | ||
| 357 | } | ||
| 358 | |||
| 359 | impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> ReadNorFlash for Flash<'d, T, M, FLASH_SIZE> { | ||
| 360 | const READ_SIZE: usize = READ_SIZE; | ||
| 361 | |||
| 362 | fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | ||
| 363 | self.blocking_read(offset, bytes) | ||
| 364 | } | ||
| 365 | |||
| 366 | fn capacity(&self) -> usize { | ||
| 367 | self.capacity() | ||
| 368 | } | ||
| 369 | } | ||
| 370 | |||
| 371 | impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<'d, T, M, FLASH_SIZE> {} | ||
| 372 | |||
| 373 | impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, M, FLASH_SIZE> { | ||
| 374 | const WRITE_SIZE: usize = WRITE_SIZE; | ||
| 375 | |||
| 376 | const ERASE_SIZE: usize = ERASE_SIZE; | ||
| 377 | |||
| 378 | fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | ||
| 379 | self.blocking_erase(from, to) | ||
| 380 | } | ||
| 381 | |||
| 382 | fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { | ||
| 383 | self.blocking_write(offset, bytes) | ||
| 384 | } | ||
| 385 | } | ||
| 386 | |||
| 387 | #[cfg(feature = "nightly")] | ||
| 388 | impl<'d, T: Instance, const FLASH_SIZE: usize> embedded_storage_async::nor_flash::ReadNorFlash | ||
| 389 | for Flash<'d, T, Async, FLASH_SIZE> | ||
| 390 | { | ||
| 391 | const READ_SIZE: usize = ASYNC_READ_SIZE; | ||
| 392 | |||
| 393 | async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { | ||
| 394 | self.read(offset, bytes).await | ||
| 395 | } | ||
| 392 | 396 | ||
| 393 | fn capacity(&self) -> usize { | 397 | fn capacity(&self) -> usize { |
| 394 | self.capacity() | 398 | self.capacity() |
| @@ -404,11 +408,11 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> embedded_storage_async::nor_flash | |||
| 404 | const ERASE_SIZE: usize = ERASE_SIZE; | 408 | const ERASE_SIZE: usize = ERASE_SIZE; |
| 405 | 409 | ||
| 406 | async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { | 410 | async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { |
| 407 | self.erase(from, to) | 411 | self.blocking_erase(from, to) |
| 408 | } | 412 | } |
| 409 | 413 | ||
| 410 | async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { | 414 | async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { |
| 411 | self.write(offset, bytes) | 415 | self.blocking_write(offset, bytes) |
| 412 | } | 416 | } |
| 413 | } | 417 | } |
| 414 | 418 | ||
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 58dc0bf1a..e57b72599 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs | |||
| @@ -749,15 +749,15 @@ mod eh02 { | |||
| 749 | mod eh1 { | 749 | mod eh1 { |
| 750 | use super::*; | 750 | use super::*; |
| 751 | 751 | ||
| 752 | impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for BufferedUart<'d, T> { | 752 | impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUartRx<'d, T> { |
| 753 | type Error = Error; | 753 | type Error = Error; |
| 754 | } | 754 | } |
| 755 | 755 | ||
| 756 | impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for BufferedUartTx<'d, T> { | 756 | impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUartTx<'d, T> { |
| 757 | type Error = Error; | 757 | type Error = Error; |
| 758 | } | 758 | } |
| 759 | 759 | ||
| 760 | impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for BufferedUartRx<'d, T> { | 760 | impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUart<'d, T> { |
| 761 | type Error = Error; | 761 | type Error = Error; |
| 762 | } | 762 | } |
| 763 | 763 | ||
| @@ -767,16 +767,6 @@ mod eh1 { | |||
| 767 | } | 767 | } |
| 768 | } | 768 | } |
| 769 | 769 | ||
| 770 | impl<'d, T: Instance> embedded_hal_1::serial::Write for BufferedUartTx<'d, T> { | ||
| 771 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 772 | self.blocking_write(buffer).map(drop) | ||
| 773 | } | ||
| 774 | |||
| 775 | fn flush(&mut self) -> Result<(), Self::Error> { | ||
| 776 | self.blocking_flush() | ||
| 777 | } | ||
| 778 | } | ||
| 779 | |||
| 780 | impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> { | 770 | impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> { |
| 781 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { | 771 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { |
| 782 | self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) | 772 | self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) |
| @@ -793,16 +783,6 @@ mod eh1 { | |||
| 793 | } | 783 | } |
| 794 | } | 784 | } |
| 795 | 785 | ||
| 796 | impl<'d, T: Instance> embedded_hal_1::serial::Write for BufferedUart<'d, T> { | ||
| 797 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 798 | self.blocking_write(buffer).map(drop) | ||
| 799 | } | ||
| 800 | |||
| 801 | fn flush(&mut self) -> Result<(), Self::Error> { | ||
| 802 | self.blocking_flush() | ||
| 803 | } | ||
| 804 | } | ||
| 805 | |||
| 806 | impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUart<'d, T> { | 786 | impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUart<'d, T> { |
| 807 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { | 787 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { |
| 808 | self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) | 788 | self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) |
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 00070b80a..202b0883e 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs | |||
| @@ -807,26 +807,26 @@ mod eh02 { | |||
| 807 | mod eh1 { | 807 | mod eh1 { |
| 808 | use super::*; | 808 | use super::*; |
| 809 | 809 | ||
| 810 | impl embedded_hal_1::serial::Error for Error { | 810 | impl embedded_hal_nb::serial::Error for Error { |
| 811 | fn kind(&self) -> embedded_hal_1::serial::ErrorKind { | 811 | fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { |
| 812 | match *self { | 812 | match *self { |
| 813 | Self::Framing => embedded_hal_1::serial::ErrorKind::FrameFormat, | 813 | Self::Framing => embedded_hal_nb::serial::ErrorKind::FrameFormat, |
| 814 | Self::Break => embedded_hal_1::serial::ErrorKind::Other, | 814 | Self::Break => embedded_hal_nb::serial::ErrorKind::Other, |
| 815 | Self::Overrun => embedded_hal_1::serial::ErrorKind::Overrun, | 815 | Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun, |
| 816 | Self::Parity => embedded_hal_1::serial::ErrorKind::Parity, | 816 | Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity, |
| 817 | } | 817 | } |
| 818 | } | 818 | } |
| 819 | } | 819 | } |
| 820 | 820 | ||
| 821 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for Uart<'d, T, M> { | 821 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, M> { |
| 822 | type Error = Error; | 822 | type Error = Error; |
| 823 | } | 823 | } |
| 824 | 824 | ||
| 825 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartTx<'d, T, M> { | 825 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, M> { |
| 826 | type Error = Error; | 826 | type Error = Error; |
| 827 | } | 827 | } |
| 828 | 828 | ||
| 829 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::ErrorType for UartRx<'d, T, M> { | 829 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, T, M> { |
| 830 | type Error = Error; | 830 | type Error = Error; |
| 831 | } | 831 | } |
| 832 | 832 | ||
| @@ -851,16 +851,6 @@ mod eh1 { | |||
| 851 | } | 851 | } |
| 852 | } | 852 | } |
| 853 | 853 | ||
| 854 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::Write for UartTx<'d, T, M> { | ||
| 855 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 856 | self.blocking_write(buffer) | ||
| 857 | } | ||
| 858 | |||
| 859 | fn flush(&mut self) -> Result<(), Self::Error> { | ||
| 860 | self.blocking_flush() | ||
| 861 | } | ||
| 862 | } | ||
| 863 | |||
| 864 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, M> { | 854 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, M> { |
| 865 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { | 855 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { |
| 866 | self.blocking_write(&[char]).map_err(nb::Error::Other) | 856 | self.blocking_write(&[char]).map_err(nb::Error::Other) |
| @@ -877,16 +867,6 @@ mod eh1 { | |||
| 877 | } | 867 | } |
| 878 | } | 868 | } |
| 879 | 869 | ||
| 880 | impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::Write for Uart<'d, T, M> { | ||
| 881 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 882 | self.blocking_write(buffer) | ||
| 883 | } | ||
| 884 | |||
| 885 | fn flush(&mut self) -> Result<(), Self::Error> { | ||
| 886 | self.blocking_flush() | ||
| 887 | } | ||
| 888 | } | ||
| 889 | |||
| 890 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> { | 870 | impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> { |
| 891 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { | 871 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { |
| 892 | self.blocking_write(&[char]).map_err(nb::Error::Other) | 872 | self.blocking_write(&[char]).map_err(nb::Error::Other) |
diff --git a/embassy-stm32-wpan/src/mac/driver.rs b/embassy-stm32-wpan/src/mac/driver.rs index f8e3a2b08..bfc4f1ee8 100644 --- a/embassy-stm32-wpan/src/mac/driver.rs +++ b/embassy-stm32-wpan/src/mac/driver.rs | |||
| @@ -28,7 +28,9 @@ impl<'d> embassy_net_driver::Driver for Driver<'d> { | |||
| 28 | type TxToken<'a> = TxToken<'d> where Self: 'a; | 28 | type TxToken<'a> = TxToken<'d> where Self: 'a; |
| 29 | 29 | ||
| 30 | fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { | 30 | fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { |
| 31 | if self.runner.rx_channel.poll_ready_to_receive(cx) && self.runner.tx_buf_channel.poll_ready_to_receive(cx) { | 31 | if self.runner.rx_channel.poll_ready_to_receive(cx).is_ready() |
| 32 | && self.runner.tx_buf_channel.poll_ready_to_receive(cx).is_ready() | ||
| 33 | { | ||
| 32 | Some(( | 34 | Some(( |
| 33 | RxToken { | 35 | RxToken { |
| 34 | rx: &self.runner.rx_channel, | 36 | rx: &self.runner.rx_channel, |
| @@ -44,7 +46,7 @@ impl<'d> embassy_net_driver::Driver for Driver<'d> { | |||
| 44 | } | 46 | } |
| 45 | 47 | ||
| 46 | fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> { | 48 | fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> { |
| 47 | if self.runner.tx_buf_channel.poll_ready_to_receive(cx) { | 49 | if self.runner.tx_buf_channel.poll_ready_to_receive(cx).is_ready() { |
| 48 | Some(TxToken { | 50 | Some(TxToken { |
| 49 | tx: &self.runner.tx_channel, | 51 | tx: &self.runner.tx_channel, |
| 50 | tx_buf: &self.runner.tx_buf_channel, | 52 | tx_buf: &self.runner.tx_buf_channel, |
| @@ -91,7 +93,7 @@ impl<'d> embassy_net_driver::RxToken for RxToken<'d> { | |||
| 91 | { | 93 | { |
| 92 | // Only valid data events should be put into the queue | 94 | // Only valid data events should be put into the queue |
| 93 | 95 | ||
| 94 | let data_event = match self.rx.try_recv().unwrap() { | 96 | let data_event = match self.rx.try_receive().unwrap() { |
| 95 | MacEvent::McpsDataInd(data_event) => data_event, | 97 | MacEvent::McpsDataInd(data_event) => data_event, |
| 96 | _ => unreachable!(), | 98 | _ => unreachable!(), |
| 97 | }; | 99 | }; |
| @@ -111,7 +113,7 @@ impl<'d> embassy_net_driver::TxToken for TxToken<'d> { | |||
| 111 | F: FnOnce(&mut [u8]) -> R, | 113 | F: FnOnce(&mut [u8]) -> R, |
| 112 | { | 114 | { |
| 113 | // Only valid tx buffers should be put into the queue | 115 | // Only valid tx buffers should be put into the queue |
| 114 | let buf = self.tx_buf.try_recv().unwrap(); | 116 | let buf = self.tx_buf.try_receive().unwrap(); |
| 115 | let r = f(&mut buf[..len]); | 117 | let r = f(&mut buf[..len]); |
| 116 | 118 | ||
| 117 | // The tx channel should always be of equal capacity to the tx_buf channel | 119 | // The tx channel should always be of equal capacity to the tx_buf channel |
diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs index 1be6df8a4..d3099b6b7 100644 --- a/embassy-stm32-wpan/src/mac/runner.rs +++ b/embassy-stm32-wpan/src/mac/runner.rs | |||
| @@ -73,7 +73,7 @@ impl<'a> Runner<'a> { | |||
| 73 | let mut msdu_handle = 0x02; | 73 | let mut msdu_handle = 0x02; |
| 74 | 74 | ||
| 75 | loop { | 75 | loop { |
| 76 | let (buf, len) = self.tx_channel.recv().await; | 76 | let (buf, len) = self.tx_channel.receive().await; |
| 77 | let _wm = self.write_mutex.lock().await; | 77 | let _wm = self.write_mutex.lock().await; |
| 78 | 78 | ||
| 79 | // The mutex should be dropped on the next loop iteration | 79 | // The mutex should be dropped on the next loop iteration |
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 0d713f60d..fe5dc443a 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml | |||
| @@ -40,9 +40,9 @@ embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } | |||
| 40 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } | 40 | embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true } |
| 41 | 41 | ||
| 42 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } | 42 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } |
| 43 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11", optional = true} | 43 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = true} |
| 44 | embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true} | 44 | embedded-hal-async = { version = "=1.0.0-rc.1", optional = true} |
| 45 | embedded-hal-nb = { version = "=1.0.0-alpha.3", optional = true} | 45 | embedded-hal-nb = { version = "=1.0.0-rc.1", optional = true} |
| 46 | 46 | ||
| 47 | embedded-storage = "0.3.0" | 47 | embedded-storage = "0.3.0" |
| 48 | embedded-storage-async = { version = "0.4.0", optional = true } | 48 | embedded-storage-async = { version = "0.4.0", optional = true } |
| @@ -57,7 +57,7 @@ sdio-host = "0.5.0" | |||
| 57 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } | 57 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } |
| 58 | critical-section = "1.1" | 58 | critical-section = "1.1" |
| 59 | atomic-polyfill = "1.0.1" | 59 | atomic-polyfill = "1.0.1" |
| 60 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-82a24863823a3daf0ca664c7fdf008379d0a0d42" } | 60 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2b87e34c661e19ff6dc603fabfe7fe99ab7261f7" } |
| 61 | vcell = "0.1.3" | 61 | vcell = "0.1.3" |
| 62 | bxcan = "0.7.0" | 62 | bxcan = "0.7.0" |
| 63 | nb = "1.0.0" | 63 | nb = "1.0.0" |
| @@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 76 | [build-dependencies] | 76 | [build-dependencies] |
| 77 | proc-macro2 = "1.0.36" | 77 | proc-macro2 = "1.0.36" |
| 78 | quote = "1.0.15" | 78 | quote = "1.0.15" |
| 79 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-82a24863823a3daf0ca664c7fdf008379d0a0d42", default-features = false, features = ["metadata"]} | 79 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2b87e34c661e19ff6dc603fabfe7fe99ab7261f7", default-features = false, features = ["metadata"]} |
| 80 | 80 | ||
| 81 | [features] | 81 | [features] |
| 82 | default = ["rt"] | 82 | default = ["rt"] |
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 30e25aefd..8a731620f 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -310,7 +310,11 @@ fn main() { | |||
| 310 | 310 | ||
| 311 | for p in METADATA.peripherals { | 311 | for p in METADATA.peripherals { |
| 312 | // generating RccPeripheral impl for H7 ADC3 would result in bad frequency | 312 | // generating RccPeripheral impl for H7 ADC3 would result in bad frequency |
| 313 | if !singletons.contains(&p.name.to_string()) || (p.name == "ADC3" && METADATA.line.starts_with("STM32H7")) { | 313 | if !singletons.contains(&p.name.to_string()) |
| 314 | || (p.name == "ADC3" && METADATA.line.starts_with("STM32H7")) | ||
| 315 | || (p.name.starts_with("ADC") && p.registers.as_ref().map_or(false, |r| r.version == "f3")) | ||
| 316 | || (p.name.starts_with("ADC") && p.registers.as_ref().map_or(false, |r| r.version == "v4")) | ||
| 317 | { | ||
| 314 | continue; | 318 | continue; |
| 315 | } | 319 | } |
| 316 | 320 | ||
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 94a8538bf..e57889aa6 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | #[cfg(not(adc_f3))] | 3 | #[cfg(not(any(adc_f3, adc_f3_v2)))] |
| 4 | #[cfg_attr(adc_f1, path = "f1.rs")] | 4 | #[cfg_attr(adc_f1, path = "f1.rs")] |
| 5 | #[cfg_attr(adc_v1, path = "v1.rs")] | 5 | #[cfg_attr(adc_v1, path = "v1.rs")] |
| 6 | #[cfg_attr(adc_v2, path = "v2.rs")] | 6 | #[cfg_attr(adc_v2, path = "v2.rs")] |
| @@ -8,16 +8,16 @@ | |||
| 8 | #[cfg_attr(adc_v4, path = "v4.rs")] | 8 | #[cfg_attr(adc_v4, path = "v4.rs")] |
| 9 | mod _version; | 9 | mod _version; |
| 10 | 10 | ||
| 11 | #[cfg(not(any(adc_f1, adc_f3)))] | 11 | #[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))] |
| 12 | mod resolution; | 12 | mod resolution; |
| 13 | mod sample_time; | 13 | mod sample_time; |
| 14 | 14 | ||
| 15 | #[cfg(not(adc_f3))] | 15 | #[cfg(not(any(adc_f3, adc_f3_v2)))] |
| 16 | #[allow(unused)] | 16 | #[allow(unused)] |
| 17 | pub use _version::*; | 17 | pub use _version::*; |
| 18 | #[cfg(not(any(adc_f1, adc_f3)))] | 18 | #[cfg(not(any(adc_f1, adc_f3, adc_f3_v2)))] |
| 19 | pub use resolution::Resolution; | 19 | pub use resolution::Resolution; |
| 20 | #[cfg(not(adc_f3))] | 20 | #[cfg(not(any(adc_f3, adc_f3_v2)))] |
| 21 | pub use sample_time::SampleTime; | 21 | pub use sample_time::SampleTime; |
| 22 | 22 | ||
| 23 | use crate::peripherals; | 23 | use crate::peripherals; |
| @@ -25,14 +25,14 @@ use crate::peripherals; | |||
| 25 | pub struct Adc<'d, T: Instance> { | 25 | pub struct Adc<'d, T: Instance> { |
| 26 | #[allow(unused)] | 26 | #[allow(unused)] |
| 27 | adc: crate::PeripheralRef<'d, T>, | 27 | adc: crate::PeripheralRef<'d, T>, |
| 28 | #[cfg(not(adc_f3))] | 28 | #[cfg(not(any(adc_f3, adc_f3_v2)))] |
| 29 | sample_time: SampleTime, | 29 | sample_time: SampleTime, |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | pub(crate) mod sealed { | 32 | pub(crate) mod sealed { |
| 33 | pub trait Instance { | 33 | pub trait Instance { |
| 34 | fn regs() -> crate::pac::adc::Adc; | 34 | fn regs() -> crate::pac::adc::Adc; |
| 35 | #[cfg(not(any(adc_f1, adc_v1, adc_f3)))] | 35 | #[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))] |
| 36 | fn common_regs() -> crate::pac::adccommon::AdcCommon; | 36 | fn common_regs() -> crate::pac::adccommon::AdcCommon; |
| 37 | } | 37 | } |
| 38 | 38 | ||
| @@ -60,7 +60,7 @@ foreach_peripheral!( | |||
| 60 | fn regs() -> crate::pac::adc::Adc { | 60 | fn regs() -> crate::pac::adc::Adc { |
| 61 | crate::pac::$inst | 61 | crate::pac::$inst |
| 62 | } | 62 | } |
| 63 | #[cfg(not(any(adc_f1, adc_v1, adc_f3)))] | 63 | #[cfg(not(any(adc_f1, adc_v1, adc_f3, adc_f3_v2)))] |
| 64 | fn common_regs() -> crate::pac::adccommon::AdcCommon { | 64 | fn common_regs() -> crate::pac::adccommon::AdcCommon { |
| 65 | foreach_peripheral!{ | 65 | foreach_peripheral!{ |
| 66 | (adccommon, $common_inst:ident) => { | 66 | (adccommon, $common_inst:ident) => { |
diff --git a/embassy-stm32/src/adc/sample_time.rs b/embassy-stm32/src/adc/sample_time.rs index df0525560..5480e7a77 100644 --- a/embassy-stm32/src/adc/sample_time.rs +++ b/embassy-stm32/src/adc/sample_time.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | #[cfg(not(adc_f3))] | 1 | #[cfg(not(any(adc_f3, adc_f3_v2)))] |
| 2 | macro_rules! impl_sample_time { | 2 | macro_rules! impl_sample_time { |
| 3 | ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => { | 3 | ($default_doc:expr, $default:ident, ($(($doc:expr, $variant:ident, $pac_variant:ident)),*)) => { |
| 4 | #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")] | 4 | #[doc = concat!("ADC sample time\n\nThe default setting is ", $default_doc, " ADC clock cycles.")] |
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index fb223e4a9..7ad13cece 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs | |||
| @@ -478,7 +478,7 @@ impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> { | |||
| 478 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | 478 | pub async fn read(&mut self) -> Result<Envelope, BusError> { |
| 479 | poll_fn(|cx| { | 479 | poll_fn(|cx| { |
| 480 | T::state().err_waker.register(cx.waker()); | 480 | T::state().err_waker.register(cx.waker()); |
| 481 | if let Poll::Ready(envelope) = T::state().rx_queue.recv().poll_unpin(cx) { | 481 | if let Poll::Ready(envelope) = T::state().rx_queue.receive().poll_unpin(cx) { |
| 482 | return Poll::Ready(Ok(envelope)); | 482 | return Poll::Ready(Ok(envelope)); |
| 483 | } else if let Some(err) = self.curr_error() { | 483 | } else if let Some(err) = self.curr_error() { |
| 484 | return Poll::Ready(Err(err)); | 484 | return Poll::Ready(Err(err)); |
| @@ -493,7 +493,7 @@ impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> { | |||
| 493 | /// | 493 | /// |
| 494 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | 494 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. |
| 495 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | 495 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { |
| 496 | if let Ok(envelope) = T::state().rx_queue.try_recv() { | 496 | if let Ok(envelope) = T::state().rx_queue.try_receive() { |
| 497 | return Ok(envelope); | 497 | return Ok(envelope); |
| 498 | } | 498 | } |
| 499 | 499 | ||
| @@ -506,14 +506,7 @@ impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> { | |||
| 506 | 506 | ||
| 507 | /// Waits while receive queue is empty. | 507 | /// Waits while receive queue is empty. |
| 508 | pub async fn wait_not_empty(&mut self) { | 508 | pub async fn wait_not_empty(&mut self) { |
| 509 | poll_fn(|cx| { | 509 | poll_fn(|cx| T::state().rx_queue.poll_ready_to_receive(cx)).await |
| 510 | if T::state().rx_queue.poll_ready_to_receive(cx) { | ||
| 511 | Poll::Ready(()) | ||
| 512 | } else { | ||
| 513 | Poll::Pending | ||
| 514 | } | ||
| 515 | }) | ||
| 516 | .await | ||
| 517 | } | 510 | } |
| 518 | 511 | ||
| 519 | fn curr_error(&self) -> Option<BusError> { | 512 | fn curr_error(&self) -> Option<BusError> { |
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 60f4fbd09..20ff29bef 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs | |||
| @@ -393,6 +393,10 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { | |||
| 393 | fn reset_complete_count(&mut self) -> usize { | 393 | fn reset_complete_count(&mut self) -> usize { |
| 394 | STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel) | 394 | STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel) |
| 395 | } | 395 | } |
| 396 | |||
| 397 | fn set_waker(&mut self, waker: &Waker) { | ||
| 398 | STATE.ch_wakers[self.0.index()].register(waker); | ||
| 399 | } | ||
| 396 | } | 400 | } |
| 397 | 401 | ||
| 398 | pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { | 402 | pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { |
| @@ -463,7 +467,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 463 | } | 467 | } |
| 464 | 468 | ||
| 465 | pub fn clear(&mut self) { | 469 | pub fn clear(&mut self) { |
| 466 | self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow())); | 470 | self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); |
| 467 | } | 471 | } |
| 468 | 472 | ||
| 469 | /// Read elements from the ring buffer | 473 | /// Read elements from the ring buffer |
| @@ -472,7 +476,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 472 | /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read | 476 | /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read |
| 473 | /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. | 477 | /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. |
| 474 | pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { | 478 | pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { |
| 475 | self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf) | 479 | self.ringbuf.read(&mut DmaCtrlImpl(self.channel.reborrow()), buf) |
| 476 | } | 480 | } |
| 477 | 481 | ||
| 478 | /// Read an exact number of elements from the ringbuffer. | 482 | /// Read an exact number of elements from the ringbuffer. |
| @@ -487,39 +491,18 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 487 | /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source. | 491 | /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source. |
| 488 | /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. | 492 | /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. |
| 489 | pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> { | 493 | pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> { |
| 490 | use core::future::poll_fn; | 494 | self.ringbuf |
| 491 | use core::sync::atomic::compiler_fence; | 495 | .read_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) |
| 492 | 496 | .await | |
| 493 | let mut read_data = 0; | ||
| 494 | let buffer_len = buffer.len(); | ||
| 495 | |||
| 496 | poll_fn(|cx| { | ||
| 497 | self.set_waker(cx.waker()); | ||
| 498 | |||
| 499 | compiler_fence(Ordering::SeqCst); | ||
| 500 | |||
| 501 | match self.read(&mut buffer[read_data..buffer_len]) { | ||
| 502 | Ok((len, remaining)) => { | ||
| 503 | read_data += len; | ||
| 504 | if read_data == buffer_len { | ||
| 505 | Poll::Ready(Ok(remaining)) | ||
| 506 | } else { | ||
| 507 | Poll::Pending | ||
| 508 | } | ||
| 509 | } | ||
| 510 | Err(e) => Poll::Ready(Err(e)), | ||
| 511 | } | ||
| 512 | }) | ||
| 513 | .await | ||
| 514 | } | 497 | } |
| 515 | 498 | ||
| 516 | /// The capacity of the ringbuffer. | 499 | /// The capacity of the ringbuffer. |
| 517 | pub fn cap(&self) -> usize { | 500 | pub const fn cap(&self) -> usize { |
| 518 | self.ringbuf.cap() | 501 | self.ringbuf.cap() |
| 519 | } | 502 | } |
| 520 | 503 | ||
| 521 | pub fn set_waker(&mut self, waker: &Waker) { | 504 | pub fn set_waker(&mut self, waker: &Waker) { |
| 522 | STATE.ch_wakers[self.channel.index()].register(waker); | 505 | DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); |
| 523 | } | 506 | } |
| 524 | 507 | ||
| 525 | fn clear_irqs(&mut self) { | 508 | fn clear_irqs(&mut self) { |
| @@ -628,50 +611,29 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { | |||
| 628 | } | 611 | } |
| 629 | 612 | ||
| 630 | pub fn clear(&mut self) { | 613 | pub fn clear(&mut self) { |
| 631 | self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow())); | 614 | self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); |
| 632 | } | 615 | } |
| 633 | 616 | ||
| 634 | /// Write elements to the ring buffer | 617 | /// Write elements to the ring buffer |
| 635 | /// Return a tuple of the length written and the length remaining in the buffer | 618 | /// Return a tuple of the length written and the length remaining in the buffer |
| 636 | pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { | 619 | pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { |
| 637 | self.ringbuf.write(DmaCtrlImpl(self.channel.reborrow()), buf) | 620 | self.ringbuf.write(&mut DmaCtrlImpl(self.channel.reborrow()), buf) |
| 638 | } | 621 | } |
| 639 | 622 | ||
| 640 | /// Write an exact number of elements to the ringbuffer. | 623 | /// Write an exact number of elements to the ringbuffer. |
| 641 | pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> { | 624 | pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> { |
| 642 | use core::future::poll_fn; | 625 | self.ringbuf |
| 643 | use core::sync::atomic::compiler_fence; | 626 | .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) |
| 644 | 627 | .await | |
| 645 | let mut written_data = 0; | ||
| 646 | let buffer_len = buffer.len(); | ||
| 647 | |||
| 648 | poll_fn(|cx| { | ||
| 649 | self.set_waker(cx.waker()); | ||
| 650 | |||
| 651 | compiler_fence(Ordering::SeqCst); | ||
| 652 | |||
| 653 | match self.write(&buffer[written_data..buffer_len]) { | ||
| 654 | Ok((len, remaining)) => { | ||
| 655 | written_data += len; | ||
| 656 | if written_data == buffer_len { | ||
| 657 | Poll::Ready(Ok(remaining)) | ||
| 658 | } else { | ||
| 659 | Poll::Pending | ||
| 660 | } | ||
| 661 | } | ||
| 662 | Err(e) => Poll::Ready(Err(e)), | ||
| 663 | } | ||
| 664 | }) | ||
| 665 | .await | ||
| 666 | } | 628 | } |
| 667 | 629 | ||
| 668 | /// The capacity of the ringbuffer. | 630 | /// The capacity of the ringbuffer. |
| 669 | pub fn cap(&self) -> usize { | 631 | pub const fn cap(&self) -> usize { |
| 670 | self.ringbuf.cap() | 632 | self.ringbuf.cap() |
| 671 | } | 633 | } |
| 672 | 634 | ||
| 673 | pub fn set_waker(&mut self, waker: &Waker) { | 635 | pub fn set_waker(&mut self, waker: &Waker) { |
| 674 | STATE.ch_wakers[self.channel.index()].register(waker); | 636 | DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); |
| 675 | } | 637 | } |
| 676 | 638 | ||
| 677 | fn clear_irqs(&mut self) { | 639 | fn clear_irqs(&mut self) { |
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 9cd7aa8d5..5033ae477 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs | |||
| @@ -623,6 +623,10 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { | |||
| 623 | fn reset_complete_count(&mut self) -> usize { | 623 | fn reset_complete_count(&mut self) -> usize { |
| 624 | STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel) | 624 | STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel) |
| 625 | } | 625 | } |
| 626 | |||
| 627 | fn set_waker(&mut self, waker: &Waker) { | ||
| 628 | STATE.ch_wakers[self.0.index()].register(waker); | ||
| 629 | } | ||
| 626 | } | 630 | } |
| 627 | 631 | ||
| 628 | pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { | 632 | pub struct ReadableRingBuffer<'a, C: Channel, W: Word> { |
| @@ -708,7 +712,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 708 | } | 712 | } |
| 709 | 713 | ||
| 710 | pub fn clear(&mut self) { | 714 | pub fn clear(&mut self) { |
| 711 | self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow())); | 715 | self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); |
| 712 | } | 716 | } |
| 713 | 717 | ||
| 714 | /// Read elements from the ring buffer | 718 | /// Read elements from the ring buffer |
| @@ -717,7 +721,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 717 | /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read | 721 | /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read |
| 718 | /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. | 722 | /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. |
| 719 | pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { | 723 | pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { |
| 720 | self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf) | 724 | self.ringbuf.read(&mut DmaCtrlImpl(self.channel.reborrow()), buf) |
| 721 | } | 725 | } |
| 722 | 726 | ||
| 723 | /// Read an exact number of elements from the ringbuffer. | 727 | /// Read an exact number of elements from the ringbuffer. |
| @@ -732,39 +736,18 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> { | |||
| 732 | /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source. | 736 | /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source. |
| 733 | /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. | 737 | /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. |
| 734 | pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> { | 738 | pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> { |
| 735 | use core::future::poll_fn; | 739 | self.ringbuf |
| 736 | use core::sync::atomic::compiler_fence; | 740 | .read_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) |
| 737 | 741 | .await | |
| 738 | let mut read_data = 0; | ||
| 739 | let buffer_len = buffer.len(); | ||
| 740 | |||
| 741 | poll_fn(|cx| { | ||
| 742 | self.set_waker(cx.waker()); | ||
| 743 | |||
| 744 | compiler_fence(Ordering::SeqCst); | ||
| 745 | |||
| 746 | match self.read(&mut buffer[read_data..buffer_len]) { | ||
| 747 | Ok((len, remaining)) => { | ||
| 748 | read_data += len; | ||
| 749 | if read_data == buffer_len { | ||
| 750 | Poll::Ready(Ok(remaining)) | ||
| 751 | } else { | ||
| 752 | Poll::Pending | ||
| 753 | } | ||
| 754 | } | ||
| 755 | Err(e) => Poll::Ready(Err(e)), | ||
| 756 | } | ||
| 757 | }) | ||
| 758 | .await | ||
| 759 | } | 742 | } |
| 760 | 743 | ||
| 761 | // The capacity of the ringbuffer | 744 | // The capacity of the ringbuffer |
| 762 | pub fn cap(&self) -> usize { | 745 | pub const fn cap(&self) -> usize { |
| 763 | self.ringbuf.cap() | 746 | self.ringbuf.cap() |
| 764 | } | 747 | } |
| 765 | 748 | ||
| 766 | pub fn set_waker(&mut self, waker: &Waker) { | 749 | pub fn set_waker(&mut self, waker: &Waker) { |
| 767 | STATE.ch_wakers[self.channel.index()].register(waker); | 750 | DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); |
| 768 | } | 751 | } |
| 769 | 752 | ||
| 770 | fn clear_irqs(&mut self) { | 753 | fn clear_irqs(&mut self) { |
| @@ -890,50 +873,29 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> { | |||
| 890 | } | 873 | } |
| 891 | 874 | ||
| 892 | pub fn clear(&mut self) { | 875 | pub fn clear(&mut self) { |
| 893 | self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow())); | 876 | self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); |
| 894 | } | 877 | } |
| 895 | 878 | ||
| 896 | /// Write elements from the ring buffer | 879 | /// Write elements from the ring buffer |
| 897 | /// Return a tuple of the length written and the length remaining in the buffer | 880 | /// Return a tuple of the length written and the length remaining in the buffer |
| 898 | pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { | 881 | pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { |
| 899 | self.ringbuf.write(DmaCtrlImpl(self.channel.reborrow()), buf) | 882 | self.ringbuf.write(&mut DmaCtrlImpl(self.channel.reborrow()), buf) |
| 900 | } | 883 | } |
| 901 | 884 | ||
| 902 | /// Write an exact number of elements to the ringbuffer. | 885 | /// Write an exact number of elements to the ringbuffer. |
| 903 | pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> { | 886 | pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> { |
| 904 | use core::future::poll_fn; | 887 | self.ringbuf |
| 905 | use core::sync::atomic::compiler_fence; | 888 | .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) |
| 906 | 889 | .await | |
| 907 | let mut written_data = 0; | ||
| 908 | let buffer_len = buffer.len(); | ||
| 909 | |||
| 910 | poll_fn(|cx| { | ||
| 911 | self.set_waker(cx.waker()); | ||
| 912 | |||
| 913 | compiler_fence(Ordering::SeqCst); | ||
| 914 | |||
| 915 | match self.write(&buffer[written_data..buffer_len]) { | ||
| 916 | Ok((len, remaining)) => { | ||
| 917 | written_data += len; | ||
| 918 | if written_data == buffer_len { | ||
| 919 | Poll::Ready(Ok(remaining)) | ||
| 920 | } else { | ||
| 921 | Poll::Pending | ||
| 922 | } | ||
| 923 | } | ||
| 924 | Err(e) => Poll::Ready(Err(e)), | ||
| 925 | } | ||
| 926 | }) | ||
| 927 | .await | ||
| 928 | } | 890 | } |
| 929 | 891 | ||
| 930 | // The capacity of the ringbuffer | 892 | // The capacity of the ringbuffer |
| 931 | pub fn cap(&self) -> usize { | 893 | pub const fn cap(&self) -> usize { |
| 932 | self.ringbuf.cap() | 894 | self.ringbuf.cap() |
| 933 | } | 895 | } |
| 934 | 896 | ||
| 935 | pub fn set_waker(&mut self, waker: &Waker) { | 897 | pub fn set_waker(&mut self, waker: &Waker) { |
| 936 | STATE.ch_wakers[self.channel.index()].register(waker); | 898 | DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); |
| 937 | } | 899 | } |
| 938 | 900 | ||
| 939 | fn clear_irqs(&mut self) { | 901 | fn clear_irqs(&mut self) { |
diff --git a/embassy-stm32/src/dma/ringbuffer.rs b/embassy-stm32/src/dma/ringbuffer.rs index 6ce59e455..c9f7a3026 100644 --- a/embassy-stm32/src/dma/ringbuffer.rs +++ b/embassy-stm32/src/dma/ringbuffer.rs | |||
| @@ -1,7 +1,9 @@ | |||
| 1 | #![cfg_attr(gpdma, allow(unused))] | 1 | #![cfg_attr(gpdma, allow(unused))] |
| 2 | 2 | ||
| 3 | use core::future::poll_fn; | ||
| 3 | use core::ops::Range; | 4 | use core::ops::Range; |
| 4 | use core::sync::atomic::{compiler_fence, Ordering}; | 5 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 6 | use core::task::{Poll, Waker}; | ||
| 5 | 7 | ||
| 6 | use super::word::Word; | 8 | use super::word::Word; |
| 7 | 9 | ||
| @@ -49,6 +51,9 @@ pub trait DmaCtrl { | |||
| 49 | 51 | ||
| 50 | /// Reset the transfer completed counter to 0 and return the value just prior to the reset. | 52 | /// Reset the transfer completed counter to 0 and return the value just prior to the reset. |
| 51 | fn reset_complete_count(&mut self) -> usize; | 53 | fn reset_complete_count(&mut self) -> usize; |
| 54 | |||
| 55 | /// Set the waker for a running poll_fn | ||
| 56 | fn set_waker(&mut self, waker: &Waker); | ||
| 52 | } | 57 | } |
| 53 | 58 | ||
| 54 | impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { | 59 | impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { |
| @@ -57,7 +62,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { | |||
| 57 | } | 62 | } |
| 58 | 63 | ||
| 59 | /// Reset the ring buffer to its initial state | 64 | /// Reset the ring buffer to its initial state |
| 60 | pub fn clear(&mut self, mut dma: impl DmaCtrl) { | 65 | pub fn clear(&mut self, dma: &mut impl DmaCtrl) { |
| 61 | self.start = 0; | 66 | self.start = 0; |
| 62 | dma.reset_complete_count(); | 67 | dma.reset_complete_count(); |
| 63 | } | 68 | } |
| @@ -68,8 +73,43 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { | |||
| 68 | } | 73 | } |
| 69 | 74 | ||
| 70 | /// The current position of the ringbuffer | 75 | /// The current position of the ringbuffer |
| 71 | fn pos(&self, remaining_transfers: usize) -> usize { | 76 | fn pos(&self, dma: &mut impl DmaCtrl) -> usize { |
| 72 | self.cap() - remaining_transfers | 77 | self.cap() - dma.get_remaining_transfers() |
| 78 | } | ||
| 79 | |||
| 80 | /// Read an exact number of elements from the ringbuffer. | ||
| 81 | /// | ||
| 82 | /// Returns the remaining number of elements available for immediate reading. | ||
| 83 | /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. | ||
| 84 | /// | ||
| 85 | /// Async/Wake Behavior: | ||
| 86 | /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point, | ||
| 87 | /// and when it wraps around. This means that when called with a buffer of length 'M', when this | ||
| 88 | /// ring buffer was created with a buffer of size 'N': | ||
| 89 | /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source. | ||
| 90 | /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. | ||
| 91 | pub async fn read_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &mut [W]) -> Result<usize, OverrunError> { | ||
| 92 | let mut read_data = 0; | ||
| 93 | let buffer_len = buffer.len(); | ||
| 94 | |||
| 95 | poll_fn(|cx| { | ||
| 96 | dma.set_waker(cx.waker()); | ||
| 97 | |||
| 98 | compiler_fence(Ordering::SeqCst); | ||
| 99 | |||
| 100 | match self.read(dma, &mut buffer[read_data..buffer_len]) { | ||
| 101 | Ok((len, remaining)) => { | ||
| 102 | read_data += len; | ||
| 103 | if read_data == buffer_len { | ||
| 104 | Poll::Ready(Ok(remaining)) | ||
| 105 | } else { | ||
| 106 | Poll::Pending | ||
| 107 | } | ||
| 108 | } | ||
| 109 | Err(e) => Poll::Ready(Err(e)), | ||
| 110 | } | ||
| 111 | }) | ||
| 112 | .await | ||
| 73 | } | 113 | } |
| 74 | 114 | ||
| 75 | /// Read elements from the ring buffer | 115 | /// Read elements from the ring buffer |
| @@ -77,7 +117,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { | |||
| 77 | /// If not all of the elements were read, then there will be some elements in the buffer remaining | 117 | /// If not all of the elements were read, then there will be some elements in the buffer remaining |
| 78 | /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read | 118 | /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read |
| 79 | /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. | 119 | /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. |
| 80 | pub fn read(&mut self, mut dma: impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { | 120 | pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { |
| 81 | /* | 121 | /* |
| 82 | This algorithm is optimistic: we assume we haven't overrun more than a full buffer and then check | 122 | This algorithm is optimistic: we assume we haven't overrun more than a full buffer and then check |
| 83 | after we've done our work to see we have. This is because on stm32, an interrupt is not guaranteed | 123 | after we've done our work to see we have. This is because on stm32, an interrupt is not guaranteed |
| @@ -93,7 +133,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { | |||
| 93 | rather than the data we actually copied because it costs nothing and confirms an error condition | 133 | rather than the data we actually copied because it costs nothing and confirms an error condition |
| 94 | earlier. | 134 | earlier. |
| 95 | */ | 135 | */ |
| 96 | let end = self.pos(dma.get_remaining_transfers()); | 136 | let end = self.pos(dma); |
| 97 | if self.start == end && dma.get_complete_count() == 0 { | 137 | if self.start == end && dma.get_complete_count() == 0 { |
| 98 | // No elements are available in the buffer | 138 | // No elements are available in the buffer |
| 99 | Ok((0, self.cap())) | 139 | Ok((0, self.cap())) |
| @@ -114,8 +154,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { | |||
| 114 | then, get the current position of of the dma write and check | 154 | then, get the current position of of the dma write and check |
| 115 | if it's inside data we could have copied | 155 | if it's inside data we could have copied |
| 116 | */ | 156 | */ |
| 117 | let (pos, complete_count) = | 157 | let (pos, complete_count) = critical_section::with(|_| (self.pos(dma), dma.get_complete_count())); |
| 118 | critical_section::with(|_| (self.pos(dma.get_remaining_transfers()), dma.get_complete_count())); | ||
| 119 | if (pos >= self.start && pos < end) || (complete_count > 0 && pos >= end) || complete_count > 1 { | 158 | if (pos >= self.start && pos < end) || (complete_count > 0 && pos >= end) || complete_count > 1 { |
| 120 | Err(OverrunError) | 159 | Err(OverrunError) |
| 121 | } else { | 160 | } else { |
| @@ -141,7 +180,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { | |||
| 141 | then, get the current position of of the dma write and check | 180 | then, get the current position of of the dma write and check |
| 142 | if it's inside data we could have copied | 181 | if it's inside data we could have copied |
| 143 | */ | 182 | */ |
| 144 | let pos = self.pos(dma.get_remaining_transfers()); | 183 | let pos = self.pos(dma); |
| 145 | if pos > self.start || pos < end || dma.get_complete_count() > 1 { | 184 | if pos > self.start || pos < end || dma.get_complete_count() > 1 { |
| 146 | Err(OverrunError) | 185 | Err(OverrunError) |
| 147 | } else { | 186 | } else { |
| @@ -169,7 +208,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { | |||
| 169 | then, get the current position of of the dma write and check | 208 | then, get the current position of of the dma write and check |
| 170 | if it's inside data we could have copied | 209 | if it's inside data we could have copied |
| 171 | */ | 210 | */ |
| 172 | let pos = self.pos(dma.get_remaining_transfers()); | 211 | let pos = self.pos(dma); |
| 173 | if pos > self.start || pos < end || dma.reset_complete_count() > 1 { | 212 | if pos > self.start || pos < end || dma.reset_complete_count() > 1 { |
| 174 | Err(OverrunError) | 213 | Err(OverrunError) |
| 175 | } else { | 214 | } else { |
| @@ -209,7 +248,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { | |||
| 209 | } | 248 | } |
| 210 | 249 | ||
| 211 | /// Reset the ring buffer to its initial state | 250 | /// Reset the ring buffer to its initial state |
| 212 | pub fn clear(&mut self, mut dma: impl DmaCtrl) { | 251 | pub fn clear(&mut self, dma: &mut impl DmaCtrl) { |
| 213 | self.end = 0; | 252 | self.end = 0; |
| 214 | dma.reset_complete_count(); | 253 | dma.reset_complete_count(); |
| 215 | } | 254 | } |
| @@ -220,14 +259,39 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { | |||
| 220 | } | 259 | } |
| 221 | 260 | ||
| 222 | /// The current position of the ringbuffer | 261 | /// The current position of the ringbuffer |
| 223 | fn pos(&self, remaining_transfers: usize) -> usize { | 262 | fn pos(&self, dma: &mut impl DmaCtrl) -> usize { |
| 224 | self.cap() - remaining_transfers | 263 | self.cap() - dma.get_remaining_transfers() |
| 264 | } | ||
| 265 | |||
| 266 | /// Write an exact number of elements to the ringbuffer. | ||
| 267 | pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result<usize, OverrunError> { | ||
| 268 | let mut written_data = 0; | ||
| 269 | let buffer_len = buffer.len(); | ||
| 270 | |||
| 271 | poll_fn(|cx| { | ||
| 272 | dma.set_waker(cx.waker()); | ||
| 273 | |||
| 274 | compiler_fence(Ordering::SeqCst); | ||
| 275 | |||
| 276 | match self.write(dma, &buffer[written_data..buffer_len]) { | ||
| 277 | Ok((len, remaining)) => { | ||
| 278 | written_data += len; | ||
| 279 | if written_data == buffer_len { | ||
| 280 | Poll::Ready(Ok(remaining)) | ||
| 281 | } else { | ||
| 282 | Poll::Pending | ||
| 283 | } | ||
| 284 | } | ||
| 285 | Err(e) => Poll::Ready(Err(e)), | ||
| 286 | } | ||
| 287 | }) | ||
| 288 | .await | ||
| 225 | } | 289 | } |
| 226 | 290 | ||
| 227 | /// Write elements from the ring buffer | 291 | /// Write elements from the ring buffer |
| 228 | /// Return a tuple of the length written and the capacity remaining to be written in the buffer | 292 | /// Return a tuple of the length written and the capacity remaining to be written in the buffer |
| 229 | pub fn write(&mut self, mut dma: impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { | 293 | pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { |
| 230 | let start = self.pos(dma.get_remaining_transfers()); | 294 | let start = self.pos(dma); |
| 231 | if start > self.end { | 295 | if start > self.end { |
| 232 | // The occupied portion in the ring buffer DOES wrap | 296 | // The occupied portion in the ring buffer DOES wrap |
| 233 | let len = self.copy_from(buf, self.end..start); | 297 | let len = self.copy_from(buf, self.end..start); |
| @@ -235,8 +299,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { | |||
| 235 | compiler_fence(Ordering::SeqCst); | 299 | compiler_fence(Ordering::SeqCst); |
| 236 | 300 | ||
| 237 | // Confirm that the DMA is not inside data we could have written | 301 | // Confirm that the DMA is not inside data we could have written |
| 238 | let (pos, complete_count) = | 302 | let (pos, complete_count) = critical_section::with(|_| (self.pos(dma), dma.get_complete_count())); |
| 239 | critical_section::with(|_| (self.pos(dma.get_remaining_transfers()), dma.get_complete_count())); | ||
| 240 | if (pos >= self.end && pos < start) || (complete_count > 0 && pos >= start) || complete_count > 1 { | 303 | if (pos >= self.end && pos < start) || (complete_count > 0 && pos >= start) || complete_count > 1 { |
| 241 | Err(OverrunError) | 304 | Err(OverrunError) |
| 242 | } else { | 305 | } else { |
| @@ -256,7 +319,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { | |||
| 256 | compiler_fence(Ordering::SeqCst); | 319 | compiler_fence(Ordering::SeqCst); |
| 257 | 320 | ||
| 258 | // Confirm that the DMA is not inside data we could have written | 321 | // Confirm that the DMA is not inside data we could have written |
| 259 | let pos = self.pos(dma.get_remaining_transfers()); | 322 | let pos = self.pos(dma); |
| 260 | if pos > self.end || pos < start || dma.get_complete_count() > 1 { | 323 | if pos > self.end || pos < start || dma.get_complete_count() > 1 { |
| 261 | Err(OverrunError) | 324 | Err(OverrunError) |
| 262 | } else { | 325 | } else { |
| @@ -274,7 +337,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { | |||
| 274 | compiler_fence(Ordering::SeqCst); | 337 | compiler_fence(Ordering::SeqCst); |
| 275 | 338 | ||
| 276 | // Confirm that the DMA is not inside data we could have written | 339 | // Confirm that the DMA is not inside data we could have written |
| 277 | let pos = self.pos(dma.get_remaining_transfers()); | 340 | let pos = self.pos(dma); |
| 278 | if pos > self.end || pos < start || dma.reset_complete_count() > 1 { | 341 | if pos > self.end || pos < start || dma.reset_complete_count() > 1 { |
| 279 | Err(OverrunError) | 342 | Err(OverrunError) |
| 280 | } else { | 343 | } else { |
| @@ -323,7 +386,7 @@ mod tests { | |||
| 323 | requests: cell::RefCell<vec::Vec<TestCircularTransferRequest>>, | 386 | requests: cell::RefCell<vec::Vec<TestCircularTransferRequest>>, |
| 324 | } | 387 | } |
| 325 | 388 | ||
| 326 | impl DmaCtrl for &mut TestCircularTransfer { | 389 | impl DmaCtrl for TestCircularTransfer { |
| 327 | fn get_remaining_transfers(&self) -> usize { | 390 | fn get_remaining_transfers(&self) -> usize { |
| 328 | match self.requests.borrow_mut().pop().unwrap() { | 391 | match self.requests.borrow_mut().pop().unwrap() { |
| 329 | TestCircularTransferRequest::PositionRequest(pos) => { | 392 | TestCircularTransferRequest::PositionRequest(pos) => { |
| @@ -350,6 +413,8 @@ mod tests { | |||
| 350 | _ => unreachable!(), | 413 | _ => unreachable!(), |
| 351 | } | 414 | } |
| 352 | } | 415 | } |
| 416 | |||
| 417 | fn set_waker(&mut self, waker: &Waker) {} | ||
| 353 | } | 418 | } |
| 354 | 419 | ||
| 355 | impl TestCircularTransfer { | 420 | impl TestCircularTransfer { |
diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index bb429d773..625bf13fc 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs | |||
| @@ -11,7 +11,7 @@ pub const fn is_default_layout() -> bool { | |||
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | const fn is_dual_bank() -> bool { | 13 | const fn is_dual_bank() -> bool { |
| 14 | FLASH_REGIONS.len() == 2 | 14 | FLASH_REGIONS.len() >= 2 |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | pub fn get_flash_regions() -> &'static [&'static FlashRegion] { | 17 | pub fn get_flash_regions() -> &'static [&'static FlashRegion] { |
| @@ -49,6 +49,7 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) | |||
| 49 | }; | 49 | }; |
| 50 | bank.cr().write(|w| { | 50 | bank.cr().write(|w| { |
| 51 | w.set_pg(true); | 51 | w.set_pg(true); |
| 52 | #[cfg(flash_h7)] | ||
| 52 | w.set_psize(2); // 32 bits at once | 53 | w.set_psize(2); // 32 bits at once |
| 53 | }); | 54 | }); |
| 54 | cortex_m::asm::isb(); | 55 | cortex_m::asm::isb(); |
| @@ -85,7 +86,10 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E | |||
| 85 | let bank = pac::FLASH.bank(sector.bank as usize); | 86 | let bank = pac::FLASH.bank(sector.bank as usize); |
| 86 | bank.cr().modify(|w| { | 87 | bank.cr().modify(|w| { |
| 87 | w.set_ser(true); | 88 | w.set_ser(true); |
| 88 | w.set_snb(sector.index_in_bank) | 89 | #[cfg(flash_h7)] |
| 90 | w.set_snb(sector.index_in_bank); | ||
| 91 | #[cfg(flash_h7ab)] | ||
| 92 | w.set_ssn(sector.index_in_bank); | ||
| 89 | }); | 93 | }); |
| 90 | 94 | ||
| 91 | bank.cr().modify(|w| { | 95 | bank.cr().modify(|w| { |
| @@ -126,6 +130,10 @@ unsafe fn blocking_wait_ready(bank: pac::flash::Bank) -> Result<(), Error> { | |||
| 126 | error!("incerr"); | 130 | error!("incerr"); |
| 127 | return Err(Error::Seq); | 131 | return Err(Error::Seq); |
| 128 | } | 132 | } |
| 133 | if sr.crcrderr() { | ||
| 134 | error!("crcrderr"); | ||
| 135 | return Err(Error::Seq); | ||
| 136 | } | ||
| 129 | if sr.operr() { | 137 | if sr.operr() { |
| 130 | return Err(Error::Prog); | 138 | return Err(Error::Prog); |
| 131 | } | 139 | } |
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 4308037f2..fb20dcd38 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs | |||
| @@ -65,9 +65,11 @@ impl FlashRegion { | |||
| 65 | #[cfg_attr(flash_f7, path = "f7.rs")] | 65 | #[cfg_attr(flash_f7, path = "f7.rs")] |
| 66 | #[cfg_attr(flash_g0, path = "g0.rs")] | 66 | #[cfg_attr(flash_g0, path = "g0.rs")] |
| 67 | #[cfg_attr(flash_h7, path = "h7.rs")] | 67 | #[cfg_attr(flash_h7, path = "h7.rs")] |
| 68 | #[cfg_attr(flash_h7ab, path = "h7.rs")] | ||
| 68 | #[cfg_attr( | 69 | #[cfg_attr( |
| 69 | not(any( | 70 | not(any( |
| 70 | flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f3, flash_f4, flash_f7, flash_g0, flash_h7 | 71 | flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f3, flash_f4, flash_f7, flash_g0, flash_h7, |
| 72 | flash_h7ab | ||
| 71 | )), | 73 | )), |
| 72 | path = "other.rs" | 74 | path = "other.rs" |
| 73 | )] | 75 | )] |
diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index d016d1dea..ec4ed99b8 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs | |||
| @@ -378,22 +378,6 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 378 | // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions | 378 | // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions |
| 379 | assert!(ahb_freq <= Hertz(120_000_000)); | 379 | assert!(ahb_freq <= Hertz(120_000_000)); |
| 380 | 380 | ||
| 381 | let flash_ws = unwrap!(config.voltage.wait_states(ahb_freq)); | ||
| 382 | FLASH.acr().modify(|w| w.set_latency(flash_ws)); | ||
| 383 | |||
| 384 | RCC.cfgr().modify(|w| { | ||
| 385 | w.set_sw(sw.into()); | ||
| 386 | w.set_hpre(config.ahb_pre.into()); | ||
| 387 | w.set_ppre1(config.apb1_pre.into()); | ||
| 388 | w.set_ppre2(config.apb2_pre.into()); | ||
| 389 | }); | ||
| 390 | while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {} | ||
| 391 | |||
| 392 | // Turn off HSI to save power if we don't need it | ||
| 393 | if !config.hsi { | ||
| 394 | RCC.cr().modify(|w| w.set_hsion(false)); | ||
| 395 | } | ||
| 396 | |||
| 397 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { | 381 | let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { |
| 398 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), | 382 | APBPrescaler::NotDivided => (ahb_freq, ahb_freq), |
| 399 | pre => { | 383 | pre => { |
| @@ -414,6 +398,22 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 414 | // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions | 398 | // Reference: STM32F215xx/217xx datasheet Table 13. General operating conditions |
| 415 | assert!(apb2_freq <= Hertz(60_000_000)); | 399 | assert!(apb2_freq <= Hertz(60_000_000)); |
| 416 | 400 | ||
| 401 | let flash_ws = unwrap!(config.voltage.wait_states(ahb_freq)); | ||
| 402 | FLASH.acr().modify(|w| w.set_latency(flash_ws)); | ||
| 403 | |||
| 404 | RCC.cfgr().modify(|w| { | ||
| 405 | w.set_sw(sw.into()); | ||
| 406 | w.set_hpre(config.ahb_pre.into()); | ||
| 407 | w.set_ppre1(config.apb1_pre.into()); | ||
| 408 | w.set_ppre2(config.apb2_pre.into()); | ||
| 409 | }); | ||
| 410 | while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {} | ||
| 411 | |||
| 412 | // Turn off HSI to save power if we don't need it | ||
| 413 | if !config.hsi { | ||
| 414 | RCC.cr().modify(|w| w.set_hsion(false)); | ||
| 415 | } | ||
| 416 | |||
| 417 | set_freqs(Clocks { | 417 | set_freqs(Clocks { |
| 418 | sys: sys_clk, | 418 | sys: sys_clk, |
| 419 | ahb1: ahb_freq, | 419 | ahb1: ahb_freq, |
diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs index 0788b0640..7fb4fb95b 100644 --- a/embassy-stm32/src/rcc/h7.rs +++ b/embassy-stm32/src/rcc/h7.rs | |||
| @@ -200,6 +200,7 @@ fn flash_setup(rcc_aclk: u32, vos: VoltageScale) { | |||
| 200 | 200 | ||
| 201 | // See RM0433 Rev 7 Table 17. FLASH recommended number of wait | 201 | // See RM0433 Rev 7 Table 17. FLASH recommended number of wait |
| 202 | // states and programming delay | 202 | // states and programming delay |
| 203 | #[cfg(flash_h7)] | ||
| 203 | let (wait_states, progr_delay) = match vos { | 204 | let (wait_states, progr_delay) = match vos { |
| 204 | // VOS 0 range VCORE 1.26V - 1.40V | 205 | // VOS 0 range VCORE 1.26V - 1.40V |
| 205 | VoltageScale::Scale0 => match rcc_aclk_mhz { | 206 | VoltageScale::Scale0 => match rcc_aclk_mhz { |
| @@ -239,6 +240,50 @@ fn flash_setup(rcc_aclk: u32, vos: VoltageScale) { | |||
| 239 | }, | 240 | }, |
| 240 | }; | 241 | }; |
| 241 | 242 | ||
| 243 | // See RM0455 Rev 10 Table 16. FLASH recommended number of wait | ||
| 244 | // states and programming delay | ||
| 245 | #[cfg(flash_h7ab)] | ||
| 246 | let (wait_states, progr_delay) = match vos { | ||
| 247 | // VOS 0 range VCORE 1.25V - 1.35V | ||
| 248 | VoltageScale::Scale0 => match rcc_aclk_mhz { | ||
| 249 | 0..=42 => (0, 0), | ||
| 250 | 43..=84 => (1, 0), | ||
| 251 | 85..=126 => (2, 1), | ||
| 252 | 127..=168 => (3, 1), | ||
| 253 | 169..=210 => (4, 2), | ||
| 254 | 211..=252 => (5, 2), | ||
| 255 | 253..=280 => (6, 3), | ||
| 256 | _ => (7, 3), | ||
| 257 | }, | ||
| 258 | // VOS 1 range VCORE 1.15V - 1.25V | ||
| 259 | VoltageScale::Scale1 => match rcc_aclk_mhz { | ||
| 260 | 0..=38 => (0, 0), | ||
| 261 | 39..=76 => (1, 0), | ||
| 262 | 77..=114 => (2, 1), | ||
| 263 | 115..=152 => (3, 1), | ||
| 264 | 153..=190 => (4, 2), | ||
| 265 | 191..=225 => (5, 2), | ||
| 266 | _ => (7, 3), | ||
| 267 | }, | ||
| 268 | // VOS 2 range VCORE 1.05V - 1.15V | ||
| 269 | VoltageScale::Scale2 => match rcc_aclk_mhz { | ||
| 270 | 0..=34 => (0, 0), | ||
| 271 | 35..=68 => (1, 0), | ||
| 272 | 69..=102 => (2, 1), | ||
| 273 | 103..=136 => (3, 1), | ||
| 274 | 137..=160 => (4, 2), | ||
| 275 | _ => (7, 3), | ||
| 276 | }, | ||
| 277 | // VOS 3 range VCORE 0.95V - 1.05V | ||
| 278 | VoltageScale::Scale3 => match rcc_aclk_mhz { | ||
| 279 | 0..=22 => (0, 0), | ||
| 280 | 23..=44 => (1, 0), | ||
| 281 | 45..=66 => (2, 1), | ||
| 282 | 67..=88 => (3, 1), | ||
| 283 | _ => (7, 3), | ||
| 284 | }, | ||
| 285 | }; | ||
| 286 | |||
| 242 | FLASH.acr().write(|w| { | 287 | FLASH.acr().write(|w| { |
| 243 | w.set_wrhighfreq(progr_delay); | 288 | w.set_wrhighfreq(progr_delay); |
| 244 | w.set_latency(wait_states) | 289 | w.set_latency(wait_states) |
| @@ -538,8 +583,6 @@ pub(crate) unsafe fn init(mut config: Config) { | |||
| 538 | let requested_pclk4 = config.pclk4.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); | 583 | let requested_pclk4 = config.pclk4.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2)); |
| 539 | let (rcc_pclk4, ppre4_bits, ppre4, _) = ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None); | 584 | let (rcc_pclk4, ppre4_bits, ppre4, _) = ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None); |
| 540 | 585 | ||
| 541 | flash_setup(rcc_aclk, pwr_vos); | ||
| 542 | |||
| 543 | // Start switching clocks ------------------- | 586 | // Start switching clocks ------------------- |
| 544 | 587 | ||
| 545 | // Ensure CSI is on and stable | 588 | // Ensure CSI is on and stable |
| @@ -595,6 +638,8 @@ pub(crate) unsafe fn init(mut config: Config) { | |||
| 595 | // core voltage | 638 | // core voltage |
| 596 | while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {} | 639 | while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {} |
| 597 | 640 | ||
| 641 | flash_setup(rcc_aclk, pwr_vos); | ||
| 642 | |||
| 598 | // APB1 / APB2 Prescaler | 643 | // APB1 / APB2 Prescaler |
| 599 | RCC.d2cfgr().modify(|w| { | 644 | RCC.d2cfgr().modify(|w| { |
| 600 | w.set_d2ppre1(Dppre::from_bits(ppre1_bits)); | 645 | w.set_d2ppre1(Dppre::from_bits(ppre1_bits)); |
diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index b2828e58e..b34b8caab 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs | |||
| @@ -410,10 +410,11 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 410 | while RCC.cfgr().read().sws() != Sw::MSI {} | 410 | while RCC.cfgr().read().sws() != Sw::MSI {} |
| 411 | } | 411 | } |
| 412 | 412 | ||
| 413 | RCC.apb1enr1().modify(|w| w.set_pwren(true)); | ||
| 414 | |||
| 413 | match config.rtc_mux { | 415 | match config.rtc_mux { |
| 414 | RtcClockSource::LSE32 => { | 416 | RtcClockSource::LSE32 => { |
| 415 | // 1. Unlock the backup domain | 417 | // 1. Unlock the backup domain |
| 416 | RCC.apb1enr1().modify(|w| w.set_pwren(true)); | ||
| 417 | PWR.cr1().modify(|w| w.set_dbp(true)); | 418 | PWR.cr1().modify(|w| w.set_dbp(true)); |
| 418 | 419 | ||
| 419 | // 2. Setup the LSE | 420 | // 2. Setup the LSE |
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 4d4c6b610..ac9ae9c6a 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs | |||
| @@ -9,7 +9,7 @@ use crate::time::Hertz; | |||
| 9 | #[cfg_attr(rcc_f0, path = "f0.rs")] | 9 | #[cfg_attr(rcc_f0, path = "f0.rs")] |
| 10 | #[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")] | 10 | #[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")] |
| 11 | #[cfg_attr(rcc_f2, path = "f2.rs")] | 11 | #[cfg_attr(rcc_f2, path = "f2.rs")] |
| 12 | #[cfg_attr(rcc_f3, path = "f3.rs")] | 12 | #[cfg_attr(any(rcc_f3, rcc_f3_v2), path = "f3.rs")] |
| 13 | #[cfg_attr(any(rcc_f4, rcc_f410), path = "f4.rs")] | 13 | #[cfg_attr(any(rcc_f4, rcc_f410), path = "f4.rs")] |
| 14 | #[cfg_attr(rcc_f7, path = "f7.rs")] | 14 | #[cfg_attr(rcc_f7, path = "f7.rs")] |
| 15 | #[cfg_attr(rcc_c0, path = "c0.rs")] | 15 | #[cfg_attr(rcc_c0, path = "c0.rs")] |
diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index ea6e8dde6..f1dd2bd7e 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs | |||
| @@ -2,6 +2,7 @@ pub use super::common::{AHBPrescaler, APBPrescaler, VoltageScale}; | |||
| 2 | use crate::pac::pwr::vals::Dbp; | 2 | use crate::pac::pwr::vals::Dbp; |
| 3 | use crate::pac::{FLASH, PWR, RCC}; | 3 | use crate::pac::{FLASH, PWR, RCC}; |
| 4 | use crate::rcc::{set_freqs, Clocks}; | 4 | use crate::rcc::{set_freqs, Clocks}; |
| 5 | use crate::rtc::{Rtc, RtcClockSource as RCS}; | ||
| 5 | use crate::time::Hertz; | 6 | use crate::time::Hertz; |
| 6 | 7 | ||
| 7 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, | 8 | /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC, |
| @@ -229,6 +230,8 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 229 | 230 | ||
| 230 | // Wait until LSE is running | 231 | // Wait until LSE is running |
| 231 | while !RCC.bdcr().read().lserdy() {} | 232 | while !RCC.bdcr().read().lserdy() {} |
| 233 | |||
| 234 | Rtc::set_clock_source(RCS::LSE); | ||
| 232 | } | 235 | } |
| 233 | RtcClockSource::LSI32 => { | 236 | RtcClockSource::LSI32 => { |
| 234 | // Turn on the internal 32 kHz LSI oscillator | 237 | // Turn on the internal 32 kHz LSI oscillator |
| @@ -236,6 +239,8 @@ pub(crate) unsafe fn init(config: Config) { | |||
| 236 | 239 | ||
| 237 | // Wait until LSI is running | 240 | // Wait until LSI is running |
| 238 | while !RCC.csr().read().lsirdy() {} | 241 | while !RCC.csr().read().lsirdy() {} |
| 242 | |||
| 243 | Rtc::set_clock_source(RCS::LSI); | ||
| 239 | } | 244 | } |
| 240 | } | 245 | } |
| 241 | 246 | ||
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 2a4978ec5..30816e436 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs | |||
| @@ -73,15 +73,20 @@ impl<'d, T: Instance> Rng<'d, T> { | |||
| 73 | #[cfg(not(rng_v1))] | 73 | #[cfg(not(rng_v1))] |
| 74 | pub fn reset(&mut self) { | 74 | pub fn reset(&mut self) { |
| 75 | T::regs().cr().write(|reg| { | 75 | T::regs().cr().write(|reg| { |
| 76 | reg.set_rngen(false); | ||
| 77 | reg.set_condrst(true); | 76 | reg.set_condrst(true); |
| 77 | reg.set_nistc(pac::rng::vals::Nistc::CUSTOM); | ||
| 78 | // set RNG config "A" according to reference manual | 78 | // set RNG config "A" according to reference manual |
| 79 | // this has to be written within the same write access as setting the CONDRST bit | 79 | // this has to be written within the same write access as setting the CONDRST bit |
| 80 | reg.set_nistc(pac::rng::vals::Nistc::DEFAULT); | ||
| 81 | reg.set_rng_config1(pac::rng::vals::RngConfig1::CONFIGA); | 80 | reg.set_rng_config1(pac::rng::vals::RngConfig1::CONFIGA); |
| 81 | reg.set_clkdiv(pac::rng::vals::Clkdiv::NODIV); | ||
| 82 | reg.set_rng_config2(pac::rng::vals::RngConfig2::CONFIGA_B); | 82 | reg.set_rng_config2(pac::rng::vals::RngConfig2::CONFIGA_B); |
| 83 | reg.set_rng_config3(pac::rng::vals::RngConfig3::CONFIGA); | 83 | reg.set_rng_config3(pac::rng::vals::RngConfig3::CONFIGA); |
| 84 | reg.set_clkdiv(pac::rng::vals::Clkdiv::NODIV); | 84 | reg.set_ced(true); |
| 85 | reg.set_ie(false); | ||
| 86 | reg.set_rngen(true); | ||
| 87 | }); | ||
| 88 | T::regs().cr().write(|reg| { | ||
| 89 | reg.set_ced(false); | ||
| 85 | }); | 90 | }); |
| 86 | // wait for CONDRST to be set | 91 | // wait for CONDRST to be set |
| 87 | while !T::regs().cr().read().condrst() {} | 92 | while !T::regs().cr().read().condrst() {} |
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 4a166e195..744e9a114 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs | |||
| @@ -72,6 +72,7 @@ impl core::ops::Sub for RtcInstant { | |||
| 72 | } | 72 | } |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | #[allow(dead_code)] | ||
| 75 | #[derive(Clone, Copy)] | 76 | #[derive(Clone, Copy)] |
| 76 | pub(crate) enum WakeupPrescaler { | 77 | pub(crate) enum WakeupPrescaler { |
| 77 | Div2, | 78 | Div2, |
| @@ -120,6 +121,7 @@ impl From<WakeupPrescaler> for u32 { | |||
| 120 | } | 121 | } |
| 121 | } | 122 | } |
| 122 | 123 | ||
| 124 | #[allow(dead_code)] | ||
| 123 | impl WakeupPrescaler { | 125 | impl WakeupPrescaler { |
| 124 | pub fn compute_min(val: u32) -> Self { | 126 | pub fn compute_min(val: u32) -> Self { |
| 125 | *[ | 127 | *[ |
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index acd67048d..4f033e3a2 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs | |||
| @@ -100,14 +100,19 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | pub fn get_max_duty(&self) -> u16 { | 102 | pub fn get_max_duty(&self) -> u16 { |
| 103 | self.inner.get_max_compare_value() | 103 | self.inner.get_max_compare_value() + 1 |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | 106 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { |
| 107 | assert!(duty < self.get_max_duty()); | 107 | assert!(duty <= self.get_max_duty()); |
| 108 | self.inner.set_compare_value(channel, duty) | 108 | self.inner.set_compare_value(channel, duty) |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | ||
| 112 | self.inner.set_output_polarity(channel, polarity); | ||
| 113 | self.inner.set_complementary_output_polarity(channel, polarity); | ||
| 114 | } | ||
| 115 | |||
| 111 | /// Set the dead time as a proportion of max_duty | 116 | /// Set the dead time as a proportion of max_duty |
| 112 | pub fn set_dead_time(&mut self, value: u16) { | 117 | pub fn set_dead_time(&mut self, value: u16) { |
| 113 | let (ckd, value) = compute_dead_time_value(value); | 118 | let (ckd, value) = compute_dead_time_value(value); |
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 6c2d6d827..4ffb2a289 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs | |||
| @@ -53,6 +53,8 @@ pub(crate) mod sealed { | |||
| 53 | 53 | ||
| 54 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); | 54 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); |
| 55 | 55 | ||
| 56 | fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity); | ||
| 57 | |||
| 56 | fn enable_channel(&mut self, channel: Channel, enable: bool); | 58 | fn enable_channel(&mut self, channel: Channel, enable: bool); |
| 57 | 59 | ||
| 58 | fn set_compare_value(&mut self, channel: Channel, value: u16); | 60 | fn set_compare_value(&mut self, channel: Channel, value: u16); |
| @@ -61,6 +63,8 @@ pub(crate) mod sealed { | |||
| 61 | } | 63 | } |
| 62 | 64 | ||
| 63 | pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance { | 65 | pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance { |
| 66 | fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity); | ||
| 67 | |||
| 64 | fn set_dead_time_clock_division(&mut self, value: vals::Ckd); | 68 | fn set_dead_time_clock_division(&mut self, value: vals::Ckd); |
| 65 | 69 | ||
| 66 | fn set_dead_time_value(&mut self, value: u8); | 70 | fn set_dead_time_value(&mut self, value: u8); |
| @@ -71,6 +75,8 @@ pub(crate) mod sealed { | |||
| 71 | pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance { | 75 | pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance { |
| 72 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); | 76 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); |
| 73 | 77 | ||
| 78 | fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity); | ||
| 79 | |||
| 74 | fn enable_channel(&mut self, channel: Channel, enable: bool); | 80 | fn enable_channel(&mut self, channel: Channel, enable: bool); |
| 75 | 81 | ||
| 76 | fn set_compare_value(&mut self, channel: Channel, value: u32); | 82 | fn set_compare_value(&mut self, channel: Channel, value: u32); |
| @@ -125,6 +131,21 @@ impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { | |||
| 125 | } | 131 | } |
| 126 | } | 132 | } |
| 127 | 133 | ||
| 134 | #[derive(Clone, Copy)] | ||
| 135 | pub enum OutputPolarity { | ||
| 136 | ActiveHigh, | ||
| 137 | ActiveLow, | ||
| 138 | } | ||
| 139 | |||
| 140 | impl From<OutputPolarity> for bool { | ||
| 141 | fn from(mode: OutputPolarity) -> Self { | ||
| 142 | match mode { | ||
| 143 | OutputPolarity::ActiveHigh => false, | ||
| 144 | OutputPolarity::ActiveLow => true, | ||
| 145 | } | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 128 | pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} | 149 | pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} |
| 129 | 150 | ||
| 130 | pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} | 151 | pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} |
| @@ -265,6 +286,13 @@ macro_rules! impl_compare_capable_16bit { | |||
| 265 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | 286 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); |
| 266 | } | 287 | } |
| 267 | 288 | ||
| 289 | fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | ||
| 290 | use sealed::GeneralPurpose16bitInstance; | ||
| 291 | Self::regs_gp16() | ||
| 292 | .ccer() | ||
| 293 | .modify(|w| w.set_ccp(channel.raw(), polarity.into())); | ||
| 294 | } | ||
| 295 | |||
| 268 | fn enable_channel(&mut self, channel: Channel, enable: bool) { | 296 | fn enable_channel(&mut self, channel: Channel, enable: bool) { |
| 269 | use sealed::GeneralPurpose16bitInstance; | 297 | use sealed::GeneralPurpose16bitInstance; |
| 270 | Self::regs_gp16() | 298 | Self::regs_gp16() |
| @@ -325,6 +353,13 @@ foreach_interrupt! { | |||
| 325 | Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | 353 | Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into())); |
| 326 | } | 354 | } |
| 327 | 355 | ||
| 356 | fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | ||
| 357 | use crate::timer::sealed::GeneralPurpose32bitInstance; | ||
| 358 | Self::regs_gp32() | ||
| 359 | .ccer() | ||
| 360 | .modify(|w| w.set_ccp(channel.raw(), polarity.into())); | ||
| 361 | } | ||
| 362 | |||
| 328 | fn enable_channel(&mut self, channel: Channel, enable: bool) { | 363 | fn enable_channel(&mut self, channel: Channel, enable: bool) { |
| 329 | use crate::timer::sealed::GeneralPurpose32bitInstance; | 364 | use crate::timer::sealed::GeneralPurpose32bitInstance; |
| 330 | Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable)); | 365 | Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable)); |
| @@ -388,6 +423,13 @@ foreach_interrupt! { | |||
| 388 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | 423 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); |
| 389 | } | 424 | } |
| 390 | 425 | ||
| 426 | fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | ||
| 427 | use crate::timer::sealed::AdvancedControlInstance; | ||
| 428 | Self::regs_advanced() | ||
| 429 | .ccer() | ||
| 430 | .modify(|w| w.set_ccp(channel.raw(), polarity.into())); | ||
| 431 | } | ||
| 432 | |||
| 391 | fn enable_channel(&mut self, channel: Channel, enable: bool) { | 433 | fn enable_channel(&mut self, channel: Channel, enable: bool) { |
| 392 | use crate::timer::sealed::AdvancedControlInstance; | 434 | use crate::timer::sealed::AdvancedControlInstance; |
| 393 | Self::regs_advanced() | 435 | Self::regs_advanced() |
| @@ -409,6 +451,13 @@ foreach_interrupt! { | |||
| 409 | } | 451 | } |
| 410 | 452 | ||
| 411 | impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { | 453 | impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { |
| 454 | fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | ||
| 455 | use crate::timer::sealed::AdvancedControlInstance; | ||
| 456 | Self::regs_advanced() | ||
| 457 | .ccer() | ||
| 458 | .modify(|w| w.set_ccnp(channel.raw(), polarity.into())); | ||
| 459 | } | ||
| 460 | |||
| 412 | fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { | 461 | fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { |
| 413 | use crate::timer::sealed::AdvancedControlInstance; | 462 | use crate::timer::sealed::AdvancedControlInstance; |
| 414 | Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); | 463 | Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); |
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index e0a817929..9e28878b1 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs | |||
| @@ -97,11 +97,15 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | pub fn get_max_duty(&self) -> u16 { | 99 | pub fn get_max_duty(&self) -> u16 { |
| 100 | self.inner.get_max_compare_value() | 100 | self.inner.get_max_compare_value() + 1 |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | 103 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { |
| 104 | assert!(duty < self.get_max_duty()); | 104 | assert!(duty <= self.get_max_duty()); |
| 105 | self.inner.set_compare_value(channel, duty) | 105 | self.inner.set_compare_value(channel, duty) |
| 106 | } | 106 | } |
| 107 | |||
| 108 | pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | ||
| 109 | self.inner.set_output_polarity(channel, polarity); | ||
| 110 | } | ||
| 107 | } | 111 | } |
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 329fc7da6..596d40bf9 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs | |||
| @@ -584,15 +584,15 @@ mod eh02 { | |||
| 584 | mod eh1 { | 584 | mod eh1 { |
| 585 | use super::*; | 585 | use super::*; |
| 586 | 586 | ||
| 587 | impl<'d, T: BasicInstance> embedded_hal_1::serial::ErrorType for BufferedUart<'d, T> { | 587 | impl<'d, T: BasicInstance> embedded_hal_nb::serial::ErrorType for BufferedUart<'d, T> { |
| 588 | type Error = Error; | 588 | type Error = Error; |
| 589 | } | 589 | } |
| 590 | 590 | ||
| 591 | impl<'d, T: BasicInstance> embedded_hal_1::serial::ErrorType for BufferedUartTx<'d, T> { | 591 | impl<'d, T: BasicInstance> embedded_hal_nb::serial::ErrorType for BufferedUartTx<'d, T> { |
| 592 | type Error = Error; | 592 | type Error = Error; |
| 593 | } | 593 | } |
| 594 | 594 | ||
| 595 | impl<'d, T: BasicInstance> embedded_hal_1::serial::ErrorType for BufferedUartRx<'d, T> { | 595 | impl<'d, T: BasicInstance> embedded_hal_nb::serial::ErrorType for BufferedUartRx<'d, T> { |
| 596 | type Error = Error; | 596 | type Error = Error; |
| 597 | } | 597 | } |
| 598 | 598 | ||
| @@ -602,16 +602,6 @@ mod eh1 { | |||
| 602 | } | 602 | } |
| 603 | } | 603 | } |
| 604 | 604 | ||
| 605 | impl<'d, T: BasicInstance> embedded_hal_1::serial::Write for BufferedUartTx<'d, T> { | ||
| 606 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 607 | self.blocking_write(buffer).map(drop) | ||
| 608 | } | ||
| 609 | |||
| 610 | fn flush(&mut self) -> Result<(), Self::Error> { | ||
| 611 | self.blocking_flush() | ||
| 612 | } | ||
| 613 | } | ||
| 614 | |||
| 615 | impl<'d, T: BasicInstance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> { | 605 | impl<'d, T: BasicInstance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> { |
| 616 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { | 606 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { |
| 617 | self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) | 607 | self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) |
| @@ -628,16 +618,6 @@ mod eh1 { | |||
| 628 | } | 618 | } |
| 629 | } | 619 | } |
| 630 | 620 | ||
| 631 | impl<'d, T: BasicInstance> embedded_hal_1::serial::Write for BufferedUart<'d, T> { | ||
| 632 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 633 | self.tx.blocking_write(buffer).map(drop) | ||
| 634 | } | ||
| 635 | |||
| 636 | fn flush(&mut self) -> Result<(), Self::Error> { | ||
| 637 | self.tx.blocking_flush() | ||
| 638 | } | ||
| 639 | } | ||
| 640 | |||
| 641 | impl<'d, T: BasicInstance> embedded_hal_nb::serial::Write for BufferedUart<'d, T> { | 621 | impl<'d, T: BasicInstance> embedded_hal_nb::serial::Write for BufferedUart<'d, T> { |
| 642 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { | 622 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { |
| 643 | self.tx.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) | 623 | self.tx.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) |
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 0c69a4882..255ddfd4b 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs | |||
| @@ -809,45 +809,57 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: | |||
| 809 | Kind::Uart => (1, 0x10, 0x1_0000), | 809 | Kind::Uart => (1, 0x10, 0x1_0000), |
| 810 | }; | 810 | }; |
| 811 | 811 | ||
| 812 | fn calculate_brr(baud: u32, pclk: u32, presc: u32, mul: u32) -> u32 { | ||
| 813 | // The calculation to be done to get the BRR is `mul * pclk / presc / baud` | ||
| 814 | // To do this in 32-bit only we can't multiply `mul` and `pclk` | ||
| 815 | let clock = pclk / presc; | ||
| 816 | |||
| 817 | // The mul is applied as the last operation to prevent overflow | ||
| 818 | let brr = clock / baud * mul; | ||
| 819 | |||
| 820 | // The BRR calculation will be a bit off because of integer rounding. | ||
| 821 | // Because we multiplied our inaccuracy with mul, our rounding now needs to be in proportion to mul. | ||
| 822 | let rounding = ((clock % baud) * mul + (baud / 2)) / baud; | ||
| 823 | |||
| 824 | brr + rounding | ||
| 825 | } | ||
| 826 | |||
| 812 | #[cfg(not(usart_v1))] | 827 | #[cfg(not(usart_v1))] |
| 813 | let mut over8 = false; | 828 | let mut over8 = false; |
| 814 | let mut found = None; | 829 | let mut found_brr = None; |
| 815 | for &(presc, _presc_val) in &DIVS { | 830 | for &(presc, _presc_val) in &DIVS { |
| 816 | let denom = (config.baudrate * presc as u32) as u64; | 831 | let brr = calculate_brr(config.baudrate, pclk_freq.0, presc as u32, mul); |
| 817 | let div = (pclk_freq.0 as u64 * mul + (denom / 2)) / denom; | ||
| 818 | trace!( | 832 | trace!( |
| 819 | "USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})", | 833 | "USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})", |
| 820 | presc, | 834 | presc, |
| 821 | div, | 835 | brr, |
| 822 | div >> 4, | 836 | brr >> 4, |
| 823 | div & 0x0F | 837 | brr & 0x0F |
| 824 | ); | 838 | ); |
| 825 | 839 | ||
| 826 | if div < brr_min { | 840 | if brr < brr_min { |
| 827 | #[cfg(not(usart_v1))] | 841 | #[cfg(not(usart_v1))] |
| 828 | if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) { | 842 | if brr * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) { |
| 829 | over8 = true; | 843 | over8 = true; |
| 830 | let div = div as u32; | 844 | r.brr().write_value(regs::Brr(((brr << 1) & !0xF) | (brr & 0x07))); |
| 831 | r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07))); | ||
| 832 | #[cfg(usart_v4)] | 845 | #[cfg(usart_v4)] |
| 833 | r.presc().write(|w| w.set_prescaler(_presc_val)); | 846 | r.presc().write(|w| w.set_prescaler(_presc_val)); |
| 834 | found = Some(div); | 847 | found_brr = Some(brr); |
| 835 | break; | 848 | break; |
| 836 | } | 849 | } |
| 837 | panic!("USART: baudrate too high"); | 850 | panic!("USART: baudrate too high"); |
| 838 | } | 851 | } |
| 839 | 852 | ||
| 840 | if div < brr_max { | 853 | if brr < brr_max { |
| 841 | let div = div as u32; | 854 | r.brr().write_value(regs::Brr(brr)); |
| 842 | r.brr().write_value(regs::Brr(div)); | ||
| 843 | #[cfg(usart_v4)] | 855 | #[cfg(usart_v4)] |
| 844 | r.presc().write(|w| w.set_prescaler(_presc_val)); | 856 | r.presc().write(|w| w.set_prescaler(_presc_val)); |
| 845 | found = Some(div); | 857 | found_brr = Some(brr); |
| 846 | break; | 858 | break; |
| 847 | } | 859 | } |
| 848 | } | 860 | } |
| 849 | 861 | ||
| 850 | let div = found.expect("USART: baudrate too low"); | 862 | let brr = found_brr.expect("USART: baudrate too low"); |
| 851 | 863 | ||
| 852 | #[cfg(not(usart_v1))] | 864 | #[cfg(not(usart_v1))] |
| 853 | let oversampling = if over8 { "8 bit" } else { "16 bit" }; | 865 | let oversampling = if over8 { "8 bit" } else { "16 bit" }; |
| @@ -857,7 +869,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: | |||
| 857 | "Using {} oversampling, desired baudrate: {}, actual baudrate: {}", | 869 | "Using {} oversampling, desired baudrate: {}, actual baudrate: {}", |
| 858 | oversampling, | 870 | oversampling, |
| 859 | config.baudrate, | 871 | config.baudrate, |
| 860 | (pclk_freq.0 * mul as u32) / div | 872 | pclk_freq.0 / brr * mul |
| 861 | ); | 873 | ); |
| 862 | 874 | ||
| 863 | r.cr2().write(|w| { | 875 | r.cr2().write(|w| { |
| @@ -943,27 +955,27 @@ mod eh02 { | |||
| 943 | mod eh1 { | 955 | mod eh1 { |
| 944 | use super::*; | 956 | use super::*; |
| 945 | 957 | ||
| 946 | impl embedded_hal_1::serial::Error for Error { | 958 | impl embedded_hal_nb::serial::Error for Error { |
| 947 | fn kind(&self) -> embedded_hal_1::serial::ErrorKind { | 959 | fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { |
| 948 | match *self { | 960 | match *self { |
| 949 | Self::Framing => embedded_hal_1::serial::ErrorKind::FrameFormat, | 961 | Self::Framing => embedded_hal_nb::serial::ErrorKind::FrameFormat, |
| 950 | Self::Noise => embedded_hal_1::serial::ErrorKind::Noise, | 962 | Self::Noise => embedded_hal_nb::serial::ErrorKind::Noise, |
| 951 | Self::Overrun => embedded_hal_1::serial::ErrorKind::Overrun, | 963 | Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun, |
| 952 | Self::Parity => embedded_hal_1::serial::ErrorKind::Parity, | 964 | Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity, |
| 953 | Self::BufferTooLong => embedded_hal_1::serial::ErrorKind::Other, | 965 | Self::BufferTooLong => embedded_hal_nb::serial::ErrorKind::Other, |
| 954 | } | 966 | } |
| 955 | } | 967 | } |
| 956 | } | 968 | } |
| 957 | 969 | ||
| 958 | impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_1::serial::ErrorType for Uart<'d, T, TxDma, RxDma> { | 970 | impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::ErrorType for Uart<'d, T, TxDma, RxDma> { |
| 959 | type Error = Error; | 971 | type Error = Error; |
| 960 | } | 972 | } |
| 961 | 973 | ||
| 962 | impl<'d, T: BasicInstance, TxDma> embedded_hal_1::serial::ErrorType for UartTx<'d, T, TxDma> { | 974 | impl<'d, T: BasicInstance, TxDma> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, TxDma> { |
| 963 | type Error = Error; | 975 | type Error = Error; |
| 964 | } | 976 | } |
| 965 | 977 | ||
| 966 | impl<'d, T: BasicInstance, RxDma> embedded_hal_1::serial::ErrorType for UartRx<'d, T, RxDma> { | 978 | impl<'d, T: BasicInstance, RxDma> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, RxDma> { |
| 967 | type Error = Error; | 979 | type Error = Error; |
| 968 | } | 980 | } |
| 969 | 981 | ||
| @@ -973,16 +985,6 @@ mod eh1 { | |||
| 973 | } | 985 | } |
| 974 | } | 986 | } |
| 975 | 987 | ||
| 976 | impl<'d, T: BasicInstance, TxDma> embedded_hal_1::serial::Write for UartTx<'d, T, TxDma> { | ||
| 977 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 978 | self.blocking_write(buffer) | ||
| 979 | } | ||
| 980 | |||
| 981 | fn flush(&mut self) -> Result<(), Self::Error> { | ||
| 982 | self.blocking_flush() | ||
| 983 | } | ||
| 984 | } | ||
| 985 | |||
| 986 | impl<'d, T: BasicInstance, TxDma> embedded_hal_nb::serial::Write for UartTx<'d, T, TxDma> { | 988 | impl<'d, T: BasicInstance, TxDma> embedded_hal_nb::serial::Write for UartTx<'d, T, TxDma> { |
| 987 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { | 989 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { |
| 988 | self.blocking_write(&[char]).map_err(nb::Error::Other) | 990 | self.blocking_write(&[char]).map_err(nb::Error::Other) |
| @@ -999,16 +1001,6 @@ mod eh1 { | |||
| 999 | } | 1001 | } |
| 1000 | } | 1002 | } |
| 1001 | 1003 | ||
| 1002 | impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_1::serial::Write for Uart<'d, T, TxDma, RxDma> { | ||
| 1003 | fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { | ||
| 1004 | self.blocking_write(buffer) | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | fn flush(&mut self) -> Result<(), Self::Error> { | ||
| 1008 | self.blocking_flush() | ||
| 1009 | } | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::Write for Uart<'d, T, TxDma, RxDma> { | 1004 | impl<'d, T: BasicInstance, TxDma, RxDma> embedded_hal_nb::serial::Write for Uart<'d, T, TxDma, RxDma> { |
| 1013 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { | 1005 | fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { |
| 1014 | self.blocking_write(&[char]).map_err(nb::Error::Other) | 1006 | self.blocking_write(&[char]).map_err(nb::Error::Other) |
diff --git a/embassy-sync/src/blocking_mutex/raw.rs b/embassy-sync/src/blocking_mutex/raw.rs index 15796f1b2..a8afcad34 100644 --- a/embassy-sync/src/blocking_mutex/raw.rs +++ b/embassy-sync/src/blocking_mutex/raw.rs | |||
| @@ -11,7 +11,7 @@ use core::marker::PhantomData; | |||
| 11 | /// | 11 | /// |
| 12 | /// Note that, unlike other mutexes, implementations only guarantee no | 12 | /// Note that, unlike other mutexes, implementations only guarantee no |
| 13 | /// concurrent access from other threads: concurrent access from the current | 13 | /// concurrent access from other threads: concurrent access from the current |
| 14 | /// thread is allwed. For example, it's possible to lock the same mutex multiple times reentrantly. | 14 | /// thread is allowed. For example, it's possible to lock the same mutex multiple times reentrantly. |
| 15 | /// | 15 | /// |
| 16 | /// Therefore, locking a `RawMutex` is only enough to guarantee safe shared (`&`) access | 16 | /// Therefore, locking a `RawMutex` is only enough to guarantee safe shared (`&`) access |
| 17 | /// to the data, it is not enough to guarantee exclusive (`&mut`) access. | 17 | /// to the data, it is not enough to guarantee exclusive (`&mut`) access. |
diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index d6f36f53d..62ea1307d 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs | |||
| @@ -65,6 +65,13 @@ where | |||
| 65 | pub fn try_send(&self, message: T) -> Result<(), TrySendError<T>> { | 65 | pub fn try_send(&self, message: T) -> Result<(), TrySendError<T>> { |
| 66 | self.channel.try_send(message) | 66 | self.channel.try_send(message) |
| 67 | } | 67 | } |
| 68 | |||
| 69 | /// Allows a poll_fn to poll until the channel is ready to send | ||
| 70 | /// | ||
| 71 | /// See [`Channel::poll_ready_to_send()`] | ||
| 72 | pub fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()> { | ||
| 73 | self.channel.poll_ready_to_send(cx) | ||
| 74 | } | ||
| 68 | } | 75 | } |
| 69 | 76 | ||
| 70 | /// Send-only access to a [`Channel`] without knowing channel size. | 77 | /// Send-only access to a [`Channel`] without knowing channel size. |
| @@ -106,6 +113,13 @@ impl<'ch, T> DynamicSender<'ch, T> { | |||
| 106 | pub fn try_send(&self, message: T) -> Result<(), TrySendError<T>> { | 113 | pub fn try_send(&self, message: T) -> Result<(), TrySendError<T>> { |
| 107 | self.channel.try_send_with_context(message, None) | 114 | self.channel.try_send_with_context(message, None) |
| 108 | } | 115 | } |
| 116 | |||
| 117 | /// Allows a poll_fn to poll until the channel is ready to send | ||
| 118 | /// | ||
| 119 | /// See [`Channel::poll_ready_to_send()`] | ||
| 120 | pub fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()> { | ||
| 121 | self.channel.poll_ready_to_send(cx) | ||
| 122 | } | ||
| 109 | } | 123 | } |
| 110 | 124 | ||
| 111 | /// Receive-only access to a [`Channel`]. | 125 | /// Receive-only access to a [`Channel`]. |
| @@ -133,16 +147,30 @@ where | |||
| 133 | { | 147 | { |
| 134 | /// Receive the next value. | 148 | /// Receive the next value. |
| 135 | /// | 149 | /// |
| 136 | /// See [`Channel::recv()`]. | 150 | /// See [`Channel::receive()`]. |
| 137 | pub fn recv(&self) -> RecvFuture<'_, M, T, N> { | 151 | pub fn receive(&self) -> ReceiveFuture<'_, M, T, N> { |
| 138 | self.channel.recv() | 152 | self.channel.receive() |
| 139 | } | 153 | } |
| 140 | 154 | ||
| 141 | /// Attempt to immediately receive the next value. | 155 | /// Attempt to immediately receive the next value. |
| 142 | /// | 156 | /// |
| 143 | /// See [`Channel::try_recv()`] | 157 | /// See [`Channel::try_receive()`] |
| 144 | pub fn try_recv(&self) -> Result<T, TryRecvError> { | 158 | pub fn try_receive(&self) -> Result<T, TryReceiveError> { |
| 145 | self.channel.try_recv() | 159 | self.channel.try_receive() |
| 160 | } | ||
| 161 | |||
| 162 | /// Allows a poll_fn to poll until the channel is ready to receive | ||
| 163 | /// | ||
| 164 | /// See [`Channel::poll_ready_to_receive()`] | ||
| 165 | pub fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> Poll<()> { | ||
| 166 | self.channel.poll_ready_to_receive(cx) | ||
| 167 | } | ||
| 168 | |||
| 169 | /// Poll the channel for the next item | ||
| 170 | /// | ||
| 171 | /// See [`Channel::poll_receive()`] | ||
| 172 | pub fn poll_receive(&self, cx: &mut Context<'_>) -> Poll<T> { | ||
| 173 | self.channel.poll_receive(cx) | ||
| 146 | } | 174 | } |
| 147 | } | 175 | } |
| 148 | 176 | ||
| @@ -162,16 +190,30 @@ impl<'ch, T> Copy for DynamicReceiver<'ch, T> {} | |||
| 162 | impl<'ch, T> DynamicReceiver<'ch, T> { | 190 | impl<'ch, T> DynamicReceiver<'ch, T> { |
| 163 | /// Receive the next value. | 191 | /// Receive the next value. |
| 164 | /// | 192 | /// |
| 165 | /// See [`Channel::recv()`]. | 193 | /// See [`Channel::receive()`]. |
| 166 | pub fn recv(&self) -> DynamicRecvFuture<'_, T> { | 194 | pub fn receive(&self) -> DynamicReceiveFuture<'_, T> { |
| 167 | DynamicRecvFuture { channel: self.channel } | 195 | DynamicReceiveFuture { channel: self.channel } |
| 168 | } | 196 | } |
| 169 | 197 | ||
| 170 | /// Attempt to immediately receive the next value. | 198 | /// Attempt to immediately receive the next value. |
| 171 | /// | 199 | /// |
| 172 | /// See [`Channel::try_recv()`] | 200 | /// See [`Channel::try_receive()`] |
| 173 | pub fn try_recv(&self) -> Result<T, TryRecvError> { | 201 | pub fn try_receive(&self) -> Result<T, TryReceiveError> { |
| 174 | self.channel.try_recv_with_context(None) | 202 | self.channel.try_receive_with_context(None) |
| 203 | } | ||
| 204 | |||
| 205 | /// Allows a poll_fn to poll until the channel is ready to receive | ||
| 206 | /// | ||
| 207 | /// See [`Channel::poll_ready_to_receive()`] | ||
| 208 | pub fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> Poll<()> { | ||
| 209 | self.channel.poll_ready_to_receive(cx) | ||
| 210 | } | ||
| 211 | |||
| 212 | /// Poll the channel for the next item | ||
| 213 | /// | ||
| 214 | /// See [`Channel::poll_receive()`] | ||
| 215 | pub fn poll_receive(&self, cx: &mut Context<'_>) -> Poll<T> { | ||
| 216 | self.channel.poll_receive(cx) | ||
| 175 | } | 217 | } |
| 176 | } | 218 | } |
| 177 | 219 | ||
| @@ -184,42 +226,39 @@ where | |||
| 184 | } | 226 | } |
| 185 | } | 227 | } |
| 186 | 228 | ||
| 187 | /// Future returned by [`Channel::recv`] and [`Receiver::recv`]. | 229 | /// Future returned by [`Channel::receive`] and [`Receiver::receive`]. |
| 188 | #[must_use = "futures do nothing unless you `.await` or poll them"] | 230 | #[must_use = "futures do nothing unless you `.await` or poll them"] |
| 189 | pub struct RecvFuture<'ch, M, T, const N: usize> | 231 | pub struct ReceiveFuture<'ch, M, T, const N: usize> |
| 190 | where | 232 | where |
| 191 | M: RawMutex, | 233 | M: RawMutex, |
| 192 | { | 234 | { |
| 193 | channel: &'ch Channel<M, T, N>, | 235 | channel: &'ch Channel<M, T, N>, |
| 194 | } | 236 | } |
| 195 | 237 | ||
| 196 | impl<'ch, M, T, const N: usize> Future for RecvFuture<'ch, M, T, N> | 238 | impl<'ch, M, T, const N: usize> Future for ReceiveFuture<'ch, M, T, N> |
| 197 | where | 239 | where |
| 198 | M: RawMutex, | 240 | M: RawMutex, |
| 199 | { | 241 | { |
| 200 | type Output = T; | 242 | type Output = T; |
| 201 | 243 | ||
| 202 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> { | 244 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> { |
| 203 | match self.channel.try_recv_with_context(Some(cx)) { | 245 | self.channel.poll_receive(cx) |
| 204 | Ok(v) => Poll::Ready(v), | ||
| 205 | Err(TryRecvError::Empty) => Poll::Pending, | ||
| 206 | } | ||
| 207 | } | 246 | } |
| 208 | } | 247 | } |
| 209 | 248 | ||
| 210 | /// Future returned by [`DynamicReceiver::recv`]. | 249 | /// Future returned by [`DynamicReceiver::receive`]. |
| 211 | #[must_use = "futures do nothing unless you `.await` or poll them"] | 250 | #[must_use = "futures do nothing unless you `.await` or poll them"] |
| 212 | pub struct DynamicRecvFuture<'ch, T> { | 251 | pub struct DynamicReceiveFuture<'ch, T> { |
| 213 | channel: &'ch dyn DynamicChannel<T>, | 252 | channel: &'ch dyn DynamicChannel<T>, |
| 214 | } | 253 | } |
| 215 | 254 | ||
| 216 | impl<'ch, T> Future for DynamicRecvFuture<'ch, T> { | 255 | impl<'ch, T> Future for DynamicReceiveFuture<'ch, T> { |
| 217 | type Output = T; | 256 | type Output = T; |
| 218 | 257 | ||
| 219 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> { | 258 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> { |
| 220 | match self.channel.try_recv_with_context(Some(cx)) { | 259 | match self.channel.try_receive_with_context(Some(cx)) { |
| 221 | Ok(v) => Poll::Ready(v), | 260 | Ok(v) => Poll::Ready(v), |
| 222 | Err(TryRecvError::Empty) => Poll::Pending, | 261 | Err(TryReceiveError::Empty) => Poll::Pending, |
| 223 | } | 262 | } |
| 224 | } | 263 | } |
| 225 | } | 264 | } |
| @@ -285,13 +324,18 @@ impl<'ch, T> Unpin for DynamicSendFuture<'ch, T> {} | |||
| 285 | trait DynamicChannel<T> { | 324 | trait DynamicChannel<T> { |
| 286 | fn try_send_with_context(&self, message: T, cx: Option<&mut Context<'_>>) -> Result<(), TrySendError<T>>; | 325 | fn try_send_with_context(&self, message: T, cx: Option<&mut Context<'_>>) -> Result<(), TrySendError<T>>; |
| 287 | 326 | ||
| 288 | fn try_recv_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<T, TryRecvError>; | 327 | fn try_receive_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<T, TryReceiveError>; |
| 328 | |||
| 329 | fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()>; | ||
| 330 | fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> Poll<()>; | ||
| 331 | |||
| 332 | fn poll_receive(&self, cx: &mut Context<'_>) -> Poll<T>; | ||
| 289 | } | 333 | } |
| 290 | 334 | ||
| 291 | /// Error returned by [`try_recv`](Channel::try_recv). | 335 | /// Error returned by [`try_receive`](Channel::try_receive). |
| 292 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] | 336 | #[derive(PartialEq, Eq, Clone, Copy, Debug)] |
| 293 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 337 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 294 | pub enum TryRecvError { | 338 | pub enum TryReceiveError { |
| 295 | /// A message could not be received because the channel is empty. | 339 | /// A message could not be received because the channel is empty. |
| 296 | Empty, | 340 | Empty, |
| 297 | } | 341 | } |
| @@ -320,11 +364,11 @@ impl<T, const N: usize> ChannelState<T, N> { | |||
| 320 | } | 364 | } |
| 321 | } | 365 | } |
| 322 | 366 | ||
| 323 | fn try_recv(&mut self) -> Result<T, TryRecvError> { | 367 | fn try_receive(&mut self) -> Result<T, TryReceiveError> { |
| 324 | self.try_recv_with_context(None) | 368 | self.try_receive_with_context(None) |
| 325 | } | 369 | } |
| 326 | 370 | ||
| 327 | fn try_recv_with_context(&mut self, cx: Option<&mut Context<'_>>) -> Result<T, TryRecvError> { | 371 | fn try_receive_with_context(&mut self, cx: Option<&mut Context<'_>>) -> Result<T, TryReceiveError> { |
| 328 | if self.queue.is_full() { | 372 | if self.queue.is_full() { |
| 329 | self.senders_waker.wake(); | 373 | self.senders_waker.wake(); |
| 330 | } | 374 | } |
| @@ -335,14 +379,31 @@ impl<T, const N: usize> ChannelState<T, N> { | |||
| 335 | if let Some(cx) = cx { | 379 | if let Some(cx) = cx { |
| 336 | self.receiver_waker.register(cx.waker()); | 380 | self.receiver_waker.register(cx.waker()); |
| 337 | } | 381 | } |
| 338 | Err(TryRecvError::Empty) | 382 | Err(TryReceiveError::Empty) |
| 383 | } | ||
| 384 | } | ||
| 385 | |||
| 386 | fn poll_receive(&mut self, cx: &mut Context<'_>) -> Poll<T> { | ||
| 387 | if self.queue.is_full() { | ||
| 388 | self.senders_waker.wake(); | ||
| 389 | } | ||
| 390 | |||
| 391 | if let Some(message) = self.queue.pop_front() { | ||
| 392 | Poll::Ready(message) | ||
| 393 | } else { | ||
| 394 | self.receiver_waker.register(cx.waker()); | ||
| 395 | Poll::Pending | ||
| 339 | } | 396 | } |
| 340 | } | 397 | } |
| 341 | 398 | ||
| 342 | fn poll_ready_to_receive(&mut self, cx: &mut Context<'_>) -> bool { | 399 | fn poll_ready_to_receive(&mut self, cx: &mut Context<'_>) -> Poll<()> { |
| 343 | self.receiver_waker.register(cx.waker()); | 400 | self.receiver_waker.register(cx.waker()); |
| 344 | 401 | ||
| 345 | !self.queue.is_empty() | 402 | if !self.queue.is_empty() { |
| 403 | Poll::Ready(()) | ||
| 404 | } else { | ||
| 405 | Poll::Pending | ||
| 406 | } | ||
| 346 | } | 407 | } |
| 347 | 408 | ||
| 348 | fn try_send(&mut self, message: T) -> Result<(), TrySendError<T>> { | 409 | fn try_send(&mut self, message: T) -> Result<(), TrySendError<T>> { |
| @@ -364,10 +425,14 @@ impl<T, const N: usize> ChannelState<T, N> { | |||
| 364 | } | 425 | } |
| 365 | } | 426 | } |
| 366 | 427 | ||
| 367 | fn poll_ready_to_send(&mut self, cx: &mut Context<'_>) -> bool { | 428 | fn poll_ready_to_send(&mut self, cx: &mut Context<'_>) -> Poll<()> { |
| 368 | self.senders_waker.register(cx.waker()); | 429 | self.senders_waker.register(cx.waker()); |
| 369 | 430 | ||
| 370 | !self.queue.is_full() | 431 | if !self.queue.is_full() { |
| 432 | Poll::Ready(()) | ||
| 433 | } else { | ||
| 434 | Poll::Pending | ||
| 435 | } | ||
| 371 | } | 436 | } |
| 372 | } | 437 | } |
| 373 | 438 | ||
| @@ -409,8 +474,13 @@ where | |||
| 409 | self.inner.lock(|rc| f(&mut *rc.borrow_mut())) | 474 | self.inner.lock(|rc| f(&mut *rc.borrow_mut())) |
| 410 | } | 475 | } |
| 411 | 476 | ||
| 412 | fn try_recv_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<T, TryRecvError> { | 477 | fn try_receive_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<T, TryReceiveError> { |
| 413 | self.lock(|c| c.try_recv_with_context(cx)) | 478 | self.lock(|c| c.try_receive_with_context(cx)) |
| 479 | } | ||
| 480 | |||
| 481 | /// Poll the channel for the next message | ||
| 482 | pub fn poll_receive(&self, cx: &mut Context<'_>) -> Poll<T> { | ||
| 483 | self.lock(|c| c.poll_receive(cx)) | ||
| 414 | } | 484 | } |
| 415 | 485 | ||
| 416 | fn try_send_with_context(&self, m: T, cx: Option<&mut Context<'_>>) -> Result<(), TrySendError<T>> { | 486 | fn try_send_with_context(&self, m: T, cx: Option<&mut Context<'_>>) -> Result<(), TrySendError<T>> { |
| @@ -418,12 +488,12 @@ where | |||
| 418 | } | 488 | } |
| 419 | 489 | ||
| 420 | /// Allows a poll_fn to poll until the channel is ready to receive | 490 | /// Allows a poll_fn to poll until the channel is ready to receive |
| 421 | pub fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> bool { | 491 | pub fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> Poll<()> { |
| 422 | self.lock(|c| c.poll_ready_to_receive(cx)) | 492 | self.lock(|c| c.poll_ready_to_receive(cx)) |
| 423 | } | 493 | } |
| 424 | 494 | ||
| 425 | /// Allows a poll_fn to poll until the channel is ready to send | 495 | /// Allows a poll_fn to poll until the channel is ready to send |
| 426 | pub fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> bool { | 496 | pub fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()> { |
| 427 | self.lock(|c| c.poll_ready_to_send(cx)) | 497 | self.lock(|c| c.poll_ready_to_send(cx)) |
| 428 | } | 498 | } |
| 429 | 499 | ||
| @@ -466,16 +536,16 @@ where | |||
| 466 | /// | 536 | /// |
| 467 | /// If there are no messages in the channel's buffer, this method will | 537 | /// If there are no messages in the channel's buffer, this method will |
| 468 | /// wait until a message is sent. | 538 | /// wait until a message is sent. |
| 469 | pub fn recv(&self) -> RecvFuture<'_, M, T, N> { | 539 | pub fn receive(&self) -> ReceiveFuture<'_, M, T, N> { |
| 470 | RecvFuture { channel: self } | 540 | ReceiveFuture { channel: self } |
| 471 | } | 541 | } |
| 472 | 542 | ||
| 473 | /// Attempt to immediately receive a message. | 543 | /// Attempt to immediately receive a message. |
| 474 | /// | 544 | /// |
| 475 | /// This method will either receive a message from the channel immediately or return an error | 545 | /// This method will either receive a message from the channel immediately or return an error |
| 476 | /// if the channel is empty. | 546 | /// if the channel is empty. |
| 477 | pub fn try_recv(&self) -> Result<T, TryRecvError> { | 547 | pub fn try_receive(&self) -> Result<T, TryReceiveError> { |
| 478 | self.lock(|c| c.try_recv()) | 548 | self.lock(|c| c.try_receive()) |
| 479 | } | 549 | } |
| 480 | } | 550 | } |
| 481 | 551 | ||
| @@ -489,8 +559,20 @@ where | |||
| 489 | Channel::try_send_with_context(self, m, cx) | 559 | Channel::try_send_with_context(self, m, cx) |
| 490 | } | 560 | } |
| 491 | 561 | ||
| 492 | fn try_recv_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<T, TryRecvError> { | 562 | fn try_receive_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<T, TryReceiveError> { |
| 493 | Channel::try_recv_with_context(self, cx) | 563 | Channel::try_receive_with_context(self, cx) |
| 564 | } | ||
| 565 | |||
| 566 | fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()> { | ||
| 567 | Channel::poll_ready_to_send(self, cx) | ||
| 568 | } | ||
| 569 | |||
| 570 | fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> Poll<()> { | ||
| 571 | Channel::poll_ready_to_receive(self, cx) | ||
| 572 | } | ||
| 573 | |||
| 574 | fn poll_receive(&self, cx: &mut Context<'_>) -> Poll<T> { | ||
| 575 | Channel::poll_receive(self, cx) | ||
| 494 | } | 576 | } |
| 495 | } | 577 | } |
| 496 | 578 | ||
| @@ -534,15 +616,15 @@ mod tests { | |||
| 534 | fn receiving_once_with_one_send() { | 616 | fn receiving_once_with_one_send() { |
| 535 | let mut c = ChannelState::<u32, 3>::new(); | 617 | let mut c = ChannelState::<u32, 3>::new(); |
| 536 | assert!(c.try_send(1).is_ok()); | 618 | assert!(c.try_send(1).is_ok()); |
| 537 | assert_eq!(c.try_recv().unwrap(), 1); | 619 | assert_eq!(c.try_receive().unwrap(), 1); |
| 538 | assert_eq!(capacity(&c), 3); | 620 | assert_eq!(capacity(&c), 3); |
| 539 | } | 621 | } |
| 540 | 622 | ||
| 541 | #[test] | 623 | #[test] |
| 542 | fn receiving_when_empty() { | 624 | fn receiving_when_empty() { |
| 543 | let mut c = ChannelState::<u32, 3>::new(); | 625 | let mut c = ChannelState::<u32, 3>::new(); |
| 544 | match c.try_recv() { | 626 | match c.try_receive() { |
| 545 | Err(TryRecvError::Empty) => assert!(true), | 627 | Err(TryReceiveError::Empty) => assert!(true), |
| 546 | _ => assert!(false), | 628 | _ => assert!(false), |
| 547 | } | 629 | } |
| 548 | assert_eq!(capacity(&c), 3); | 630 | assert_eq!(capacity(&c), 3); |
| @@ -552,7 +634,7 @@ mod tests { | |||
| 552 | fn simple_send_and_receive() { | 634 | fn simple_send_and_receive() { |
| 553 | let c = Channel::<NoopRawMutex, u32, 3>::new(); | 635 | let c = Channel::<NoopRawMutex, u32, 3>::new(); |
| 554 | assert!(c.try_send(1).is_ok()); | 636 | assert!(c.try_send(1).is_ok()); |
| 555 | assert_eq!(c.try_recv().unwrap(), 1); | 637 | assert_eq!(c.try_receive().unwrap(), 1); |
| 556 | } | 638 | } |
| 557 | 639 | ||
| 558 | #[test] | 640 | #[test] |
| @@ -572,7 +654,7 @@ mod tests { | |||
| 572 | let r: DynamicReceiver<'_, u32> = c.receiver().into(); | 654 | let r: DynamicReceiver<'_, u32> = c.receiver().into(); |
| 573 | 655 | ||
| 574 | assert!(s.try_send(1).is_ok()); | 656 | assert!(s.try_send(1).is_ok()); |
| 575 | assert_eq!(r.try_recv().unwrap(), 1); | 657 | assert_eq!(r.try_receive().unwrap(), 1); |
| 576 | } | 658 | } |
| 577 | 659 | ||
| 578 | #[futures_test::test] | 660 | #[futures_test::test] |
| @@ -587,14 +669,14 @@ mod tests { | |||
| 587 | assert!(c2.try_send(1).is_ok()); | 669 | assert!(c2.try_send(1).is_ok()); |
| 588 | }) | 670 | }) |
| 589 | .is_ok()); | 671 | .is_ok()); |
| 590 | assert_eq!(c.recv().await, 1); | 672 | assert_eq!(c.receive().await, 1); |
| 591 | } | 673 | } |
| 592 | 674 | ||
| 593 | #[futures_test::test] | 675 | #[futures_test::test] |
| 594 | async fn sender_send_completes_if_capacity() { | 676 | async fn sender_send_completes_if_capacity() { |
| 595 | let c = Channel::<CriticalSectionRawMutex, u32, 1>::new(); | 677 | let c = Channel::<CriticalSectionRawMutex, u32, 1>::new(); |
| 596 | c.send(1).await; | 678 | c.send(1).await; |
| 597 | assert_eq!(c.recv().await, 1); | 679 | assert_eq!(c.receive().await, 1); |
| 598 | } | 680 | } |
| 599 | 681 | ||
| 600 | #[futures_test::test] | 682 | #[futures_test::test] |
| @@ -612,11 +694,11 @@ mod tests { | |||
| 612 | // Wish I could think of a means of determining that the async send is waiting instead. | 694 | // Wish I could think of a means of determining that the async send is waiting instead. |
| 613 | // However, I've used the debugger to observe that the send does indeed wait. | 695 | // However, I've used the debugger to observe that the send does indeed wait. |
| 614 | Delay::new(Duration::from_millis(500)).await; | 696 | Delay::new(Duration::from_millis(500)).await; |
| 615 | assert_eq!(c.recv().await, 1); | 697 | assert_eq!(c.receive().await, 1); |
| 616 | assert!(executor | 698 | assert!(executor |
| 617 | .spawn(async move { | 699 | .spawn(async move { |
| 618 | loop { | 700 | loop { |
| 619 | c.recv().await; | 701 | c.receive().await; |
| 620 | } | 702 | } |
| 621 | }) | 703 | }) |
| 622 | .is_ok()); | 704 | .is_ok()); |
diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 0afb1103d..ec1f2ec3f 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml | |||
| @@ -152,8 +152,8 @@ defmt = { version = "0.3", optional = true } | |||
| 152 | log = { version = "0.4.14", optional = true } | 152 | log = { version = "0.4.14", optional = true } |
| 153 | 153 | ||
| 154 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } | 154 | embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } |
| 155 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11", optional = true} | 155 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = true} |
| 156 | embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true} | 156 | embedded-hal-async = { version = "=1.0.0-rc.1", optional = true} |
| 157 | 157 | ||
| 158 | futures-util = { version = "0.3.17", default-features = false } | 158 | futures-util = { version = "0.3.17", default-features = false } |
| 159 | atomic-polyfill = "1.0.1" | 159 | atomic-polyfill = "1.0.1" |
diff --git a/embassy-usb/src/class/cdc_ncm/mod.rs b/embassy-usb/src/class/cdc_ncm/mod.rs index fcfa0bfcd..830e9b768 100644 --- a/embassy-usb/src/class/cdc_ncm/mod.rs +++ b/embassy-usb/src/class/cdc_ncm/mod.rs | |||
| @@ -248,6 +248,8 @@ pub struct CdcNcmClass<'d, D: Driver<'d>> { | |||
| 248 | write_ep: D::EndpointIn, | 248 | write_ep: D::EndpointIn, |
| 249 | 249 | ||
| 250 | _control: &'d ControlShared, | 250 | _control: &'d ControlShared, |
| 251 | |||
| 252 | max_packet_size: usize, | ||
| 251 | } | 253 | } |
| 252 | 254 | ||
| 253 | impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> { | 255 | impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> { |
| @@ -338,6 +340,7 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> { | |||
| 338 | read_ep, | 340 | read_ep, |
| 339 | write_ep, | 341 | write_ep, |
| 340 | _control: &state.shared, | 342 | _control: &state.shared, |
| 343 | max_packet_size: max_packet_size as usize, | ||
| 341 | } | 344 | } |
| 342 | } | 345 | } |
| 343 | 346 | ||
| @@ -349,6 +352,7 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> { | |||
| 349 | Sender { | 352 | Sender { |
| 350 | write_ep: self.write_ep, | 353 | write_ep: self.write_ep, |
| 351 | seq: 0, | 354 | seq: 0, |
| 355 | max_packet_size: self.max_packet_size, | ||
| 352 | }, | 356 | }, |
| 353 | Receiver { | 357 | Receiver { |
| 354 | data_if: self.data_if, | 358 | data_if: self.data_if, |
| @@ -365,6 +369,7 @@ impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> { | |||
| 365 | pub struct Sender<'d, D: Driver<'d>> { | 369 | pub struct Sender<'d, D: Driver<'d>> { |
| 366 | write_ep: D::EndpointIn, | 370 | write_ep: D::EndpointIn, |
| 367 | seq: u16, | 371 | seq: u16, |
| 372 | max_packet_size: usize, | ||
| 368 | } | 373 | } |
| 369 | 374 | ||
| 370 | impl<'d, D: Driver<'d>> Sender<'d, D> { | 375 | impl<'d, D: Driver<'d>> Sender<'d, D> { |
| @@ -375,8 +380,8 @@ impl<'d, D: Driver<'d>> Sender<'d, D> { | |||
| 375 | let seq = self.seq; | 380 | let seq = self.seq; |
| 376 | self.seq = self.seq.wrapping_add(1); | 381 | self.seq = self.seq.wrapping_add(1); |
| 377 | 382 | ||
| 378 | const MAX_PACKET_SIZE: usize = 64; // TODO unhardcode | ||
| 379 | const OUT_HEADER_LEN: usize = 28; | 383 | const OUT_HEADER_LEN: usize = 28; |
| 384 | const ABS_MAX_PACKET_SIZE: usize = 512; | ||
| 380 | 385 | ||
| 381 | let header = NtbOutHeader { | 386 | let header = NtbOutHeader { |
| 382 | nth_sig: SIG_NTH, | 387 | nth_sig: SIG_NTH, |
| @@ -395,27 +400,27 @@ impl<'d, D: Driver<'d>> Sender<'d, D> { | |||
| 395 | }; | 400 | }; |
| 396 | 401 | ||
| 397 | // Build first packet on a buffer, send next packets straight from `data`. | 402 | // Build first packet on a buffer, send next packets straight from `data`. |
| 398 | let mut buf = [0; MAX_PACKET_SIZE]; | 403 | let mut buf = [0; ABS_MAX_PACKET_SIZE]; |
| 399 | let n = byteify(&mut buf, header); | 404 | let n = byteify(&mut buf, header); |
| 400 | assert_eq!(n.len(), OUT_HEADER_LEN); | 405 | assert_eq!(n.len(), OUT_HEADER_LEN); |
| 401 | 406 | ||
| 402 | if OUT_HEADER_LEN + data.len() < MAX_PACKET_SIZE { | 407 | if OUT_HEADER_LEN + data.len() < self.max_packet_size { |
| 403 | // First packet is not full, just send it. | 408 | // First packet is not full, just send it. |
| 404 | // No need to send ZLP because it's short for sure. | 409 | // No need to send ZLP because it's short for sure. |
| 405 | buf[OUT_HEADER_LEN..][..data.len()].copy_from_slice(data); | 410 | buf[OUT_HEADER_LEN..][..data.len()].copy_from_slice(data); |
| 406 | self.write_ep.write(&buf[..OUT_HEADER_LEN + data.len()]).await?; | 411 | self.write_ep.write(&buf[..OUT_HEADER_LEN + data.len()]).await?; |
| 407 | } else { | 412 | } else { |
| 408 | let (d1, d2) = data.split_at(MAX_PACKET_SIZE - OUT_HEADER_LEN); | 413 | let (d1, d2) = data.split_at(self.max_packet_size - OUT_HEADER_LEN); |
| 409 | 414 | ||
| 410 | buf[OUT_HEADER_LEN..].copy_from_slice(d1); | 415 | buf[OUT_HEADER_LEN..self.max_packet_size].copy_from_slice(d1); |
| 411 | self.write_ep.write(&buf).await?; | 416 | self.write_ep.write(&buf[..self.max_packet_size]).await?; |
| 412 | 417 | ||
| 413 | for chunk in d2.chunks(MAX_PACKET_SIZE) { | 418 | for chunk in d2.chunks(self.max_packet_size) { |
| 414 | self.write_ep.write(&chunk).await?; | 419 | self.write_ep.write(&chunk).await?; |
| 415 | } | 420 | } |
| 416 | 421 | ||
| 417 | // Send ZLP if needed. | 422 | // Send ZLP if needed. |
| 418 | if d2.len() % MAX_PACKET_SIZE == 0 { | 423 | if d2.len() % self.max_packet_size == 0 { |
| 419 | self.write_ep.write(&[]).await?; | 424 | self.write_ep.write(&[]).await?; |
| 420 | } | 425 | } |
| 421 | } | 426 | } |
diff --git a/embassy-usb/src/msos.rs b/embassy-usb/src/msos.rs index 187b2ff8e..847338e5f 100644 --- a/embassy-usb/src/msos.rs +++ b/embassy-usb/src/msos.rs | |||
| @@ -526,7 +526,7 @@ impl<'a> PropertyData<'a> { | |||
| 526 | PropertyData::Binary(val) => val.len(), | 526 | PropertyData::Binary(val) => val.len(), |
| 527 | PropertyData::DwordLittleEndian(val) | PropertyData::DwordBigEndian(val) => core::mem::size_of_val(val), | 527 | PropertyData::DwordLittleEndian(val) | PropertyData::DwordBigEndian(val) => core::mem::size_of_val(val), |
| 528 | PropertyData::RegMultiSz(val) => { | 528 | PropertyData::RegMultiSz(val) => { |
| 529 | core::mem::size_of::<u16>() * val.iter().map(|x| x.encode_utf16().count() + 1).sum::<usize>() + 1 | 529 | core::mem::size_of::<u16>() * (val.iter().map(|x| x.encode_utf16().count() + 1).sum::<usize>() + 1) |
| 530 | } | 530 | } |
| 531 | } | 531 | } |
| 532 | } | 532 | } |
diff --git a/examples/boot/application/rp/src/bin/a.rs b/examples/boot/application/rp/src/bin/a.rs index f0dda39d0..15fdaca82 100644 --- a/examples/boot/application/rp/src/bin/a.rs +++ b/examples/boot/application/rp/src/bin/a.rs | |||
| @@ -7,7 +7,7 @@ use core::cell::RefCell; | |||
| 7 | use defmt_rtt as _; | 7 | use defmt_rtt as _; |
| 8 | use embassy_boot_rp::*; | 8 | use embassy_boot_rp::*; |
| 9 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| 10 | use embassy_rp::flash::{self, Flash}; | 10 | use embassy_rp::flash::Flash; |
| 11 | use embassy_rp::gpio::{Level, Output}; | 11 | use embassy_rp::gpio::{Level, Output}; |
| 12 | use embassy_rp::watchdog::Watchdog; | 12 | use embassy_rp::watchdog::Watchdog; |
| 13 | use embassy_sync::blocking_mutex::Mutex; | 13 | use embassy_sync::blocking_mutex::Mutex; |
| @@ -34,7 +34,7 @@ async fn main(_s: Spawner) { | |||
| 34 | let mut watchdog = Watchdog::new(p.WATCHDOG); | 34 | let mut watchdog = Watchdog::new(p.WATCHDOG); |
| 35 | watchdog.start(Duration::from_secs(8)); | 35 | watchdog.start(Duration::from_secs(8)); |
| 36 | 36 | ||
| 37 | let flash = Flash::<_, flash::Blocking, FLASH_SIZE>::new(p.FLASH); | 37 | let flash = Flash::<_, _, FLASH_SIZE>::new_blocking(p.FLASH); |
| 38 | let flash = Mutex::new(RefCell::new(flash)); | 38 | let flash = Mutex::new(RefCell::new(flash)); |
| 39 | 39 | ||
| 40 | let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); | 40 | let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash); |
diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs index 72c95c02a..74e2e293f 100644 --- a/examples/boot/bootloader/nrf/src/main.rs +++ b/examples/boot/bootloader/nrf/src/main.rs | |||
| @@ -33,9 +33,7 @@ fn main() -> ! { | |||
| 33 | 33 | ||
| 34 | let config = BootLoaderConfig::from_linkerfile_blocking(&flash); | 34 | let config = BootLoaderConfig::from_linkerfile_blocking(&flash); |
| 35 | let active_offset = config.active.offset(); | 35 | let active_offset = config.active.offset(); |
| 36 | let mut bl: BootLoader<_, _, _> = BootLoader::new(config); | 36 | let bl: BootLoader = BootLoader::prepare(config); |
| 37 | |||
| 38 | bl.prepare(); | ||
| 39 | 37 | ||
| 40 | unsafe { bl.load(active_offset) } | 38 | unsafe { bl.load(active_offset) } |
| 41 | } | 39 | } |
diff --git a/examples/boot/bootloader/rp/src/main.rs b/examples/boot/bootloader/rp/src/main.rs index 6a81db804..c0e75d1ea 100644 --- a/examples/boot/bootloader/rp/src/main.rs +++ b/examples/boot/bootloader/rp/src/main.rs | |||
| @@ -29,9 +29,7 @@ fn main() -> ! { | |||
| 29 | 29 | ||
| 30 | let config = BootLoaderConfig::from_linkerfile_blocking(&flash); | 30 | let config = BootLoaderConfig::from_linkerfile_blocking(&flash); |
| 31 | let active_offset = config.active.offset(); | 31 | let active_offset = config.active.offset(); |
| 32 | let mut bl: BootLoader<_, _, _> = BootLoader::new(config); | 32 | let bl: BootLoader = BootLoader::prepare(config); |
| 33 | |||
| 34 | bl.prepare(); | ||
| 35 | 33 | ||
| 36 | unsafe { bl.load(embassy_rp::flash::FLASH_BASE as u32 + active_offset) } | 34 | unsafe { bl.load(embassy_rp::flash::FLASH_BASE as u32 + active_offset) } |
| 37 | } | 35 | } |
diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs index 262eed200..5fd9ea588 100644 --- a/examples/boot/bootloader/stm32/src/main.rs +++ b/examples/boot/bootloader/stm32/src/main.rs | |||
| @@ -27,9 +27,7 @@ fn main() -> ! { | |||
| 27 | 27 | ||
| 28 | let config = BootLoaderConfig::from_linkerfile_blocking(&flash); | 28 | let config = BootLoaderConfig::from_linkerfile_blocking(&flash); |
| 29 | let active_offset = config.active.offset(); | 29 | let active_offset = config.active.offset(); |
| 30 | let mut bl: BootLoader<_, _, _, 2048> = BootLoader::new(config); | 30 | let bl = BootLoader::prepare::<_, _, _, 2048>(config); |
| 31 | |||
| 32 | bl.prepare(); | ||
| 33 | 31 | ||
| 34 | unsafe { bl.load(BANK1_REGION.base + active_offset) } | 32 | unsafe { bl.load(BANK1_REGION.base + active_offset) } |
| 35 | } | 33 | } |
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 15fe22d3a..2ce44b516 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml | |||
| @@ -12,12 +12,14 @@ nightly = [ | |||
| 12 | "embassy-nrf/nightly", | 12 | "embassy-nrf/nightly", |
| 13 | "embassy-net/nightly", | 13 | "embassy-net/nightly", |
| 14 | "embassy-net-esp-hosted", | 14 | "embassy-net-esp-hosted", |
| 15 | "embassy-net-enc28j60", | ||
| 15 | "embassy-nrf/unstable-traits", | 16 | "embassy-nrf/unstable-traits", |
| 16 | "embassy-time/nightly", | 17 | "embassy-time/nightly", |
| 17 | "embassy-time/unstable-traits", | 18 | "embassy-time/unstable-traits", |
| 18 | "static_cell/nightly", | 19 | "static_cell/nightly", |
| 19 | "embassy-usb", | 20 | "embassy-usb", |
| 20 | "embedded-io-async", | 21 | "embedded-io-async", |
| 22 | "embedded-hal-bus/async", | ||
| 21 | "embassy-net", | 23 | "embassy-net", |
| 22 | "embassy-lora", | 24 | "embassy-lora", |
| 23 | "lora-phy", | 25 | "lora-phy", |
| @@ -40,6 +42,7 @@ lora-phy = { version = "1", optional = true } | |||
| 40 | lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } | 42 | lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } |
| 41 | lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true } | 43 | lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true } |
| 42 | embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"], optional = true } | 44 | embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"], optional = true } |
| 45 | embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"], optional = true } | ||
| 43 | 46 | ||
| 44 | defmt = "0.3" | 47 | defmt = "0.3" |
| 45 | defmt-rtt = "0.4" | 48 | defmt-rtt = "0.4" |
| @@ -54,9 +57,14 @@ rand = { version = "0.8.4", default-features = false } | |||
| 54 | embedded-storage = "0.3.0" | 57 | embedded-storage = "0.3.0" |
| 55 | usbd-hid = "0.6.0" | 58 | usbd-hid = "0.6.0" |
| 56 | serde = { version = "1.0.136", default-features = false } | 59 | serde = { version = "1.0.136", default-features = false } |
| 57 | embedded-hal-async = { version = "0.2.0-alpha.2", optional = true } | 60 | embedded-hal = { version = "1.0.0-rc.1" } |
| 61 | embedded-hal-async = { version = "1.0.0-rc.1", optional = true } | ||
| 62 | embedded-hal-bus = { version = "0.1.0-rc.1" } | ||
| 58 | num-integer = { version = "0.1.45", default-features = false } | 63 | num-integer = { version = "0.1.45", default-features = false } |
| 59 | microfft = "0.5.0" | 64 | microfft = "0.5.0" |
| 60 | 65 | ||
| 61 | [profile.release] | 66 | [profile.release] |
| 62 | debug = 2 | 67 | debug = 2 |
| 68 | |||
| 69 | [patch.crates-io] | ||
| 70 | lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} \ No newline at end of file | ||
diff --git a/examples/nrf52840/src/bin/channel.rs b/examples/nrf52840/src/bin/channel.rs index d782a79e7..bd9c909da 100644 --- a/examples/nrf52840/src/bin/channel.rs +++ b/examples/nrf52840/src/bin/channel.rs | |||
| @@ -35,7 +35,7 @@ async fn main(spawner: Spawner) { | |||
| 35 | unwrap!(spawner.spawn(my_task())); | 35 | unwrap!(spawner.spawn(my_task())); |
| 36 | 36 | ||
| 37 | loop { | 37 | loop { |
| 38 | match CHANNEL.recv().await { | 38 | match CHANNEL.receive().await { |
| 39 | LedState::On => led.set_high(), | 39 | LedState::On => led.set_high(), |
| 40 | LedState::Off => led.set_low(), | 40 | LedState::Off => led.set_low(), |
| 41 | } | 41 | } |
diff --git a/examples/nrf52840/src/bin/channel_sender_receiver.rs b/examples/nrf52840/src/bin/channel_sender_receiver.rs index fcccdaed5..ec4f1d800 100644 --- a/examples/nrf52840/src/bin/channel_sender_receiver.rs +++ b/examples/nrf52840/src/bin/channel_sender_receiver.rs | |||
| @@ -33,7 +33,7 @@ async fn recv_task(led: AnyPin, receiver: Receiver<'static, NoopRawMutex, LedSta | |||
| 33 | let mut led = Output::new(led, Level::Low, OutputDrive::Standard); | 33 | let mut led = Output::new(led, Level::Low, OutputDrive::Standard); |
| 34 | 34 | ||
| 35 | loop { | 35 | loop { |
| 36 | match receiver.recv().await { | 36 | match receiver.receive().await { |
| 37 | LedState::On => led.set_high(), | 37 | LedState::On => led.set_high(), |
| 38 | LedState::Off => led.set_low(), | 38 | LedState::Off => led.set_low(), |
| 39 | } | 39 | } |
diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs new file mode 100644 index 000000000..d1b796fab --- /dev/null +++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_net::tcp::TcpSocket; | ||
| 8 | use embassy_net::{Stack, StackResources}; | ||
| 9 | use embassy_net_enc28j60::Enc28j60; | ||
| 10 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | ||
| 11 | use embassy_nrf::rng::Rng; | ||
| 12 | use embassy_nrf::spim::Spim; | ||
| 13 | use embassy_nrf::{bind_interrupts, peripherals, spim}; | ||
| 14 | use embassy_time::Delay; | ||
| 15 | use embedded_hal_bus::spi::ExclusiveDevice; | ||
| 16 | use embedded_io_async::Write; | ||
| 17 | use static_cell::make_static; | ||
| 18 | use {defmt_rtt as _, panic_probe as _}; | ||
| 19 | |||
| 20 | bind_interrupts!(struct Irqs { | ||
| 21 | SPIM3 => spim::InterruptHandler<peripherals::SPI3>; | ||
| 22 | RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>; | ||
| 23 | }); | ||
| 24 | |||
| 25 | #[embassy_executor::task] | ||
| 26 | async fn net_task( | ||
| 27 | stack: &'static Stack< | ||
| 28 | Enc28j60< | ||
| 29 | ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_15>, Delay>, | ||
| 30 | Output<'static, peripherals::P0_13>, | ||
| 31 | >, | ||
| 32 | >, | ||
| 33 | ) -> ! { | ||
| 34 | stack.run().await | ||
| 35 | } | ||
| 36 | |||
| 37 | #[embassy_executor::main] | ||
| 38 | async fn main(spawner: Spawner) { | ||
| 39 | let p = embassy_nrf::init(Default::default()); | ||
| 40 | info!("running!"); | ||
| 41 | |||
| 42 | let eth_sck = p.P0_20; | ||
| 43 | let eth_mosi = p.P0_22; | ||
| 44 | let eth_miso = p.P0_24; | ||
| 45 | let eth_cs = p.P0_15; | ||
| 46 | let eth_rst = p.P0_13; | ||
| 47 | let _eth_irq = p.P0_12; | ||
| 48 | |||
| 49 | let mut config = spim::Config::default(); | ||
| 50 | config.frequency = spim::Frequency::M16; | ||
| 51 | let spi = spim::Spim::new(p.SPI3, Irqs, eth_sck, eth_miso, eth_mosi, config); | ||
| 52 | let cs = Output::new(eth_cs, Level::High, OutputDrive::Standard); | ||
| 53 | let spi = ExclusiveDevice::new(spi, cs, Delay); | ||
| 54 | |||
| 55 | let rst = Output::new(eth_rst, Level::High, OutputDrive::Standard); | ||
| 56 | let mac_addr = [2, 3, 4, 5, 6, 7]; | ||
| 57 | let device = Enc28j60::new(spi, Some(rst), mac_addr); | ||
| 58 | |||
| 59 | let config = embassy_net::Config::dhcpv4(Default::default()); | ||
| 60 | // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { | ||
| 61 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), | ||
| 62 | // dns_servers: Vec::new(), | ||
| 63 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), | ||
| 64 | // }); | ||
| 65 | |||
| 66 | // Generate random seed | ||
| 67 | let mut rng = Rng::new(p.RNG, Irqs); | ||
| 68 | let mut seed = [0; 8]; | ||
| 69 | rng.blocking_fill_bytes(&mut seed); | ||
| 70 | let seed = u64::from_le_bytes(seed); | ||
| 71 | |||
| 72 | // Init network stack | ||
| 73 | let stack = &*make_static!(Stack::new( | ||
| 74 | device, | ||
| 75 | config, | ||
| 76 | make_static!(StackResources::<2>::new()), | ||
| 77 | seed | ||
| 78 | )); | ||
| 79 | |||
| 80 | unwrap!(spawner.spawn(net_task(stack))); | ||
| 81 | |||
| 82 | // And now we can use it! | ||
| 83 | |||
| 84 | let mut rx_buffer = [0; 4096]; | ||
| 85 | let mut tx_buffer = [0; 4096]; | ||
| 86 | let mut buf = [0; 4096]; | ||
| 87 | |||
| 88 | loop { | ||
| 89 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 90 | socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); | ||
| 91 | |||
| 92 | info!("Listening on TCP:1234..."); | ||
| 93 | if let Err(e) = socket.accept(1234).await { | ||
| 94 | warn!("accept error: {:?}", e); | ||
| 95 | continue; | ||
| 96 | } | ||
| 97 | |||
| 98 | info!("Received connection from {:?}", socket.remote_endpoint()); | ||
| 99 | |||
| 100 | loop { | ||
| 101 | let n = match socket.read(&mut buf).await { | ||
| 102 | Ok(0) => { | ||
| 103 | warn!("read EOF"); | ||
| 104 | break; | ||
| 105 | } | ||
| 106 | Ok(n) => n, | ||
| 107 | Err(e) => { | ||
| 108 | warn!("read error: {:?}", e); | ||
| 109 | break; | ||
| 110 | } | ||
| 111 | }; | ||
| 112 | |||
| 113 | info!("rxd {:02x}", &buf[..n]); | ||
| 114 | |||
| 115 | match socket.write_all(&buf[..n]).await { | ||
| 116 | Ok(()) => {} | ||
| 117 | Err(e) => { | ||
| 118 | warn!("write error: {:?}", e); | ||
| 119 | break; | ||
| 120 | } | ||
| 121 | }; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | } | ||
diff --git a/examples/nrf52840/src/bin/uart_split.rs b/examples/nrf52840/src/bin/uart_split.rs index 9979a1d53..b748bfcd8 100644 --- a/examples/nrf52840/src/bin/uart_split.rs +++ b/examples/nrf52840/src/bin/uart_split.rs | |||
| @@ -46,7 +46,7 @@ async fn main(spawner: Spawner) { | |||
| 46 | // back out the buffer we receive from the read | 46 | // back out the buffer we receive from the read |
| 47 | // task. | 47 | // task. |
| 48 | loop { | 48 | loop { |
| 49 | let buf = CHANNEL.recv().await; | 49 | let buf = CHANNEL.receive().await; |
| 50 | info!("writing..."); | 50 | info!("writing..."); |
| 51 | unwrap!(tx.write(&buf).await); | 51 | unwrap!(tx.write(&buf).await); |
| 52 | } | 52 | } |
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs index e3b80d821..a60822fd9 100644 --- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs | |||
| @@ -11,7 +11,7 @@ use embassy_nrf::rng::Rng; | |||
| 11 | use embassy_nrf::spim::{self, Spim}; | 11 | use embassy_nrf::spim::{self, Spim}; |
| 12 | use embassy_nrf::{bind_interrupts, peripherals}; | 12 | use embassy_nrf::{bind_interrupts, peripherals}; |
| 13 | use embassy_time::Delay; | 13 | use embassy_time::Delay; |
| 14 | use embedded_hal_async::spi::ExclusiveDevice; | 14 | use embedded_hal_bus::spi::ExclusiveDevice; |
| 15 | use embedded_io_async::Write; | 15 | use embedded_io_async::Write; |
| 16 | use static_cell::make_static; | 16 | use static_cell::make_static; |
| 17 | use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _}; | 17 | use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _}; |
| @@ -72,8 +72,8 @@ async fn main(spawner: Spawner) { | |||
| 72 | 72 | ||
| 73 | unwrap!(spawner.spawn(wifi_task(runner))); | 73 | unwrap!(spawner.spawn(wifi_task(runner))); |
| 74 | 74 | ||
| 75 | control.init().await; | 75 | unwrap!(control.init().await); |
| 76 | control.join(WIFI_NETWORK, WIFI_PASSWORD).await; | 76 | unwrap!(control.connect(WIFI_NETWORK, WIFI_PASSWORD).await); |
| 77 | 77 | ||
| 78 | let config = embassy_net::Config::dhcpv4(Default::default()); | 78 | let config = embassy_net::Config::dhcpv4(Default::default()); |
| 79 | // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { | 79 | // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { |
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index d83e370df..102611bc0 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml | |||
| @@ -13,7 +13,7 @@ embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["ni | |||
| 13 | embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] } | 13 | embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] } |
| 14 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } | 14 | embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } |
| 15 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] } | 15 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] } |
| 16 | embassy-net-w5500 = { version = "0.1.0", path = "../../embassy-net-w5500", features = ["defmt"] } | 16 | embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } |
| 17 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 17 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 18 | embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" } | 18 | embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" } |
| 19 | embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"] } | 19 | embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"] } |
| @@ -42,8 +42,9 @@ smart-leds = "0.3.0" | |||
| 42 | heapless = "0.7.15" | 42 | heapless = "0.7.15" |
| 43 | usbd-hid = "0.6.1" | 43 | usbd-hid = "0.6.1" |
| 44 | 44 | ||
| 45 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" } | 45 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } |
| 46 | embedded-hal-async = "0.2.0-alpha.2" | 46 | embedded-hal-async = "1.0.0-rc.1" |
| 47 | embedded-hal-bus = { version = "0.1.0-rc.1", features = ["async"] } | ||
| 47 | embedded-io-async = { version = "0.5.0", features = ["defmt-03"] } | 48 | embedded-io-async = { version = "0.5.0", features = ["defmt-03"] } |
| 48 | embedded-storage = { version = "0.3" } | 49 | embedded-storage = { version = "0.3" } |
| 49 | static_cell = { version = "1.1", features = ["nightly"]} | 50 | static_cell = { version = "1.1", features = ["nightly"]} |
| @@ -53,4 +54,7 @@ pio = "0.2.1" | |||
| 53 | rand = { version = "0.8.5", default-features = false } | 54 | rand = { version = "0.8.5", default-features = false } |
| 54 | 55 | ||
| 55 | [profile.release] | 56 | [profile.release] |
| 56 | debug = 2 \ No newline at end of file | 57 | debug = 2 |
| 58 | |||
| 59 | [patch.crates-io] | ||
| 60 | lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} \ No newline at end of file | ||
diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs index 9f800d0d9..c0fde62ab 100644 --- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs +++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs | |||
| @@ -10,13 +10,14 @@ use defmt::*; | |||
| 10 | use embassy_executor::Spawner; | 10 | use embassy_executor::Spawner; |
| 11 | use embassy_futures::yield_now; | 11 | use embassy_futures::yield_now; |
| 12 | use embassy_net::{Stack, StackResources}; | 12 | use embassy_net::{Stack, StackResources}; |
| 13 | use embassy_net_w5500::*; | 13 | use embassy_net_wiznet::chip::W5500; |
| 14 | use embassy_net_wiznet::*; | ||
| 14 | use embassy_rp::clocks::RoscRng; | 15 | use embassy_rp::clocks::RoscRng; |
| 15 | use embassy_rp::gpio::{Input, Level, Output, Pull}; | 16 | use embassy_rp::gpio::{Input, Level, Output, Pull}; |
| 16 | use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; | 17 | use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; |
| 17 | use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; | 18 | use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; |
| 18 | use embassy_time::{Delay, Duration}; | 19 | use embassy_time::{Delay, Duration}; |
| 19 | use embedded_hal_async::spi::ExclusiveDevice; | 20 | use embedded_hal_bus::spi::ExclusiveDevice; |
| 20 | use embedded_io_async::Write; | 21 | use embedded_io_async::Write; |
| 21 | use rand::RngCore; | 22 | use rand::RngCore; |
| 22 | use static_cell::make_static; | 23 | use static_cell::make_static; |
| @@ -26,6 +27,7 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 26 | async fn ethernet_task( | 27 | async fn ethernet_task( |
| 27 | runner: Runner< | 28 | runner: Runner< |
| 28 | 'static, | 29 | 'static, |
| 30 | W5500, | ||
| 29 | ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, | 31 | ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, |
| 30 | Input<'static, PIN_21>, | 32 | Input<'static, PIN_21>, |
| 31 | Output<'static, PIN_20>, | 33 | Output<'static, PIN_20>, |
| @@ -54,7 +56,7 @@ async fn main(spawner: Spawner) { | |||
| 54 | 56 | ||
| 55 | let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; | 57 | let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; |
| 56 | let state = make_static!(State::<8, 8>::new()); | 58 | let state = make_static!(State::<8, 8>::new()); |
| 57 | let (device, runner) = embassy_net_w5500::new( | 59 | let (device, runner) = embassy_net_wiznet::new( |
| 58 | mac_addr, | 60 | mac_addr, |
| 59 | state, | 61 | state, |
| 60 | ExclusiveDevice::new(spi, cs, Delay), | 62 | ExclusiveDevice::new(spi, cs, Delay), |
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs index fee84b613..e593acae4 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs | |||
| @@ -12,13 +12,14 @@ use defmt::*; | |||
| 12 | use embassy_executor::Spawner; | 12 | use embassy_executor::Spawner; |
| 13 | use embassy_futures::yield_now; | 13 | use embassy_futures::yield_now; |
| 14 | use embassy_net::{Stack, StackResources}; | 14 | use embassy_net::{Stack, StackResources}; |
| 15 | use embassy_net_w5500::*; | 15 | use embassy_net_wiznet::chip::W5500; |
| 16 | use embassy_net_wiznet::*; | ||
| 16 | use embassy_rp::clocks::RoscRng; | 17 | use embassy_rp::clocks::RoscRng; |
| 17 | use embassy_rp::gpio::{Input, Level, Output, Pull}; | 18 | use embassy_rp::gpio::{Input, Level, Output, Pull}; |
| 18 | use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; | 19 | use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; |
| 19 | use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; | 20 | use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; |
| 20 | use embassy_time::{Delay, Duration, Timer}; | 21 | use embassy_time::{Delay, Duration, Timer}; |
| 21 | use embedded_hal_async::spi::ExclusiveDevice; | 22 | use embedded_hal_bus::spi::ExclusiveDevice; |
| 22 | use embedded_io_async::Write; | 23 | use embedded_io_async::Write; |
| 23 | use rand::RngCore; | 24 | use rand::RngCore; |
| 24 | use static_cell::make_static; | 25 | use static_cell::make_static; |
| @@ -28,6 +29,7 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 28 | async fn ethernet_task( | 29 | async fn ethernet_task( |
| 29 | runner: Runner< | 30 | runner: Runner< |
| 30 | 'static, | 31 | 'static, |
| 32 | W5500, | ||
| 31 | ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, | 33 | ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, |
| 32 | Input<'static, PIN_21>, | 34 | Input<'static, PIN_21>, |
| 33 | Output<'static, PIN_20>, | 35 | Output<'static, PIN_20>, |
| @@ -57,7 +59,7 @@ async fn main(spawner: Spawner) { | |||
| 57 | 59 | ||
| 58 | let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; | 60 | let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; |
| 59 | let state = make_static!(State::<8, 8>::new()); | 61 | let state = make_static!(State::<8, 8>::new()); |
| 60 | let (device, runner) = embassy_net_w5500::new( | 62 | let (device, runner) = embassy_net_wiznet::new( |
| 61 | mac_addr, | 63 | mac_addr, |
| 62 | state, | 64 | state, |
| 63 | ExclusiveDevice::new(spi, cs, Delay), | 65 | ExclusiveDevice::new(spi, cs, Delay), |
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs index 024574267..c62caed7a 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs | |||
| @@ -11,21 +11,24 @@ use defmt::*; | |||
| 11 | use embassy_executor::Spawner; | 11 | use embassy_executor::Spawner; |
| 12 | use embassy_futures::yield_now; | 12 | use embassy_futures::yield_now; |
| 13 | use embassy_net::{Stack, StackResources}; | 13 | use embassy_net::{Stack, StackResources}; |
| 14 | use embassy_net_w5500::*; | 14 | use embassy_net_wiznet::chip::W5500; |
| 15 | use embassy_net_wiznet::*; | ||
| 15 | use embassy_rp::clocks::RoscRng; | 16 | use embassy_rp::clocks::RoscRng; |
| 16 | use embassy_rp::gpio::{Input, Level, Output, Pull}; | 17 | use embassy_rp::gpio::{Input, Level, Output, Pull}; |
| 17 | use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; | 18 | use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; |
| 18 | use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; | 19 | use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; |
| 19 | use embassy_time::{Delay, Duration}; | 20 | use embassy_time::{Delay, Duration}; |
| 20 | use embedded_hal_async::spi::ExclusiveDevice; | 21 | use embedded_hal_bus::spi::ExclusiveDevice; |
| 21 | use embedded_io_async::Write; | 22 | use embedded_io_async::Write; |
| 22 | use rand::RngCore; | 23 | use rand::RngCore; |
| 23 | use static_cell::make_static; | 24 | use static_cell::make_static; |
| 24 | use {defmt_rtt as _, panic_probe as _}; | 25 | use {defmt_rtt as _, panic_probe as _}; |
| 26 | |||
| 25 | #[embassy_executor::task] | 27 | #[embassy_executor::task] |
| 26 | async fn ethernet_task( | 28 | async fn ethernet_task( |
| 27 | runner: Runner< | 29 | runner: Runner< |
| 28 | 'static, | 30 | 'static, |
| 31 | W5500, | ||
| 29 | ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, | 32 | ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, |
| 30 | Input<'static, PIN_21>, | 33 | Input<'static, PIN_21>, |
| 31 | Output<'static, PIN_20>, | 34 | Output<'static, PIN_20>, |
| @@ -55,7 +58,7 @@ async fn main(spawner: Spawner) { | |||
| 55 | 58 | ||
| 56 | let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; | 59 | let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; |
| 57 | let state = make_static!(State::<8, 8>::new()); | 60 | let state = make_static!(State::<8, 8>::new()); |
| 58 | let (device, runner) = embassy_net_w5500::new( | 61 | let (device, runner) = embassy_net_wiznet::new( |
| 59 | mac_addr, | 62 | mac_addr, |
| 60 | state, | 63 | state, |
| 61 | ExclusiveDevice::new(spi, cs, Delay), | 64 | ExclusiveDevice::new(spi, cs, Delay), |
diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs index 038432b17..76dabce1c 100644 --- a/examples/rp/src/bin/ethernet_w5500_udp.rs +++ b/examples/rp/src/bin/ethernet_w5500_udp.rs | |||
| @@ -11,20 +11,23 @@ use embassy_executor::Spawner; | |||
| 11 | use embassy_futures::yield_now; | 11 | use embassy_futures::yield_now; |
| 12 | use embassy_net::udp::{PacketMetadata, UdpSocket}; | 12 | use embassy_net::udp::{PacketMetadata, UdpSocket}; |
| 13 | use embassy_net::{Stack, StackResources}; | 13 | use embassy_net::{Stack, StackResources}; |
| 14 | use embassy_net_w5500::*; | 14 | use embassy_net_wiznet::chip::W5500; |
| 15 | use embassy_net_wiznet::*; | ||
| 15 | use embassy_rp::clocks::RoscRng; | 16 | use embassy_rp::clocks::RoscRng; |
| 16 | use embassy_rp::gpio::{Input, Level, Output, Pull}; | 17 | use embassy_rp::gpio::{Input, Level, Output, Pull}; |
| 17 | use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; | 18 | use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; |
| 18 | use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; | 19 | use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; |
| 19 | use embassy_time::Delay; | 20 | use embassy_time::Delay; |
| 20 | use embedded_hal_async::spi::ExclusiveDevice; | 21 | use embedded_hal_bus::spi::ExclusiveDevice; |
| 21 | use rand::RngCore; | 22 | use rand::RngCore; |
| 22 | use static_cell::make_static; | 23 | use static_cell::make_static; |
| 23 | use {defmt_rtt as _, panic_probe as _}; | 24 | use {defmt_rtt as _, panic_probe as _}; |
| 25 | |||
| 24 | #[embassy_executor::task] | 26 | #[embassy_executor::task] |
| 25 | async fn ethernet_task( | 27 | async fn ethernet_task( |
| 26 | runner: Runner< | 28 | runner: Runner< |
| 27 | 'static, | 29 | 'static, |
| 30 | W5500, | ||
| 28 | ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, | 31 | ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, |
| 29 | Input<'static, PIN_21>, | 32 | Input<'static, PIN_21>, |
| 30 | Output<'static, PIN_20>, | 33 | Output<'static, PIN_20>, |
| @@ -53,7 +56,7 @@ async fn main(spawner: Spawner) { | |||
| 53 | 56 | ||
| 54 | let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; | 57 | let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; |
| 55 | let state = make_static!(State::<8, 8>::new()); | 58 | let state = make_static!(State::<8, 8>::new()); |
| 56 | let (device, runner) = embassy_net_w5500::new( | 59 | let (device, runner) = embassy_net_wiznet::new( |
| 57 | mac_addr, | 60 | mac_addr, |
| 58 | state, | 61 | state, |
| 59 | ExclusiveDevice::new(spi, cs, Delay), | 62 | ExclusiveDevice::new(spi, cs, Delay), |
diff --git a/examples/rp/src/bin/flash.rs b/examples/rp/src/bin/flash.rs index 88bb931d2..911a657eb 100644 --- a/examples/rp/src/bin/flash.rs +++ b/examples/rp/src/bin/flash.rs | |||
| @@ -28,12 +28,12 @@ async fn main(_spawner: Spawner) { | |||
| 28 | let mut flash = embassy_rp::flash::Flash::<_, Async, FLASH_SIZE>::new(p.FLASH, p.DMA_CH0); | 28 | let mut flash = embassy_rp::flash::Flash::<_, Async, FLASH_SIZE>::new(p.FLASH, p.DMA_CH0); |
| 29 | 29 | ||
| 30 | // Get JEDEC id | 30 | // Get JEDEC id |
| 31 | let jedec = flash.jedec_id().unwrap(); | 31 | let jedec = flash.blocking_jedec_id().unwrap(); |
| 32 | info!("jedec id: 0x{:x}", jedec); | 32 | info!("jedec id: 0x{:x}", jedec); |
| 33 | 33 | ||
| 34 | // Get unique id | 34 | // Get unique id |
| 35 | let mut uid = [0; 8]; | 35 | let mut uid = [0; 8]; |
| 36 | flash.unique_id(&mut uid).unwrap(); | 36 | flash.blocking_unique_id(&mut uid).unwrap(); |
| 37 | info!("unique id: {:?}", uid); | 37 | info!("unique id: {:?}", uid); |
| 38 | 38 | ||
| 39 | erase_write_sector(&mut flash, 0x00); | 39 | erase_write_sector(&mut flash, 0x00); |
| @@ -48,25 +48,25 @@ async fn main(_spawner: Spawner) { | |||
| 48 | fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) { | 48 | fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) { |
| 49 | info!(">>>> [multiwrite_bytes]"); | 49 | info!(">>>> [multiwrite_bytes]"); |
| 50 | let mut read_buf = [0u8; ERASE_SIZE]; | 50 | let mut read_buf = [0u8; ERASE_SIZE]; |
| 51 | defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf)); | 51 | defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf)); |
| 52 | 52 | ||
| 53 | info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32); | 53 | info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32); |
| 54 | info!("Contents start with {=[u8]}", read_buf[0..4]); | 54 | info!("Contents start with {=[u8]}", read_buf[0..4]); |
| 55 | 55 | ||
| 56 | defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32)); | 56 | defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32)); |
| 57 | 57 | ||
| 58 | defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf)); | 58 | defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf)); |
| 59 | info!("Contents after erase starts with {=[u8]}", read_buf[0..4]); | 59 | info!("Contents after erase starts with {=[u8]}", read_buf[0..4]); |
| 60 | if read_buf.iter().any(|x| *x != 0xFF) { | 60 | if read_buf.iter().any(|x| *x != 0xFF) { |
| 61 | defmt::panic!("unexpected"); | 61 | defmt::panic!("unexpected"); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | defmt::unwrap!(flash.write(ADDR_OFFSET + offset, &[0x01])); | 64 | defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, &[0x01])); |
| 65 | defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 1, &[0x02])); | 65 | defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 1, &[0x02])); |
| 66 | defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 2, &[0x03])); | 66 | defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 2, &[0x03])); |
| 67 | defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 3, &[0x04])); | 67 | defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 3, &[0x04])); |
| 68 | 68 | ||
| 69 | defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf)); | 69 | defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf)); |
| 70 | info!("Contents after write starts with {=[u8]}", read_buf[0..4]); | 70 | info!("Contents after write starts with {=[u8]}", read_buf[0..4]); |
| 71 | if &read_buf[0..4] != &[0x01, 0x02, 0x03, 0x04] { | 71 | if &read_buf[0..4] != &[0x01, 0x02, 0x03, 0x04] { |
| 72 | defmt::panic!("unexpected"); | 72 | defmt::panic!("unexpected"); |
| @@ -76,14 +76,14 @@ fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH | |||
| 76 | fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) { | 76 | fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) { |
| 77 | info!(">>>> [erase_write_sector]"); | 77 | info!(">>>> [erase_write_sector]"); |
| 78 | let mut buf = [0u8; ERASE_SIZE]; | 78 | let mut buf = [0u8; ERASE_SIZE]; |
| 79 | defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf)); | 79 | defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf)); |
| 80 | 80 | ||
| 81 | info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32); | 81 | info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32); |
| 82 | info!("Contents start with {=[u8]}", buf[0..4]); | 82 | info!("Contents start with {=[u8]}", buf[0..4]); |
| 83 | 83 | ||
| 84 | defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32)); | 84 | defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32)); |
| 85 | 85 | ||
| 86 | defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf)); | 86 | defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf)); |
| 87 | info!("Contents after erase starts with {=[u8]}", buf[0..4]); | 87 | info!("Contents after erase starts with {=[u8]}", buf[0..4]); |
| 88 | if buf.iter().any(|x| *x != 0xFF) { | 88 | if buf.iter().any(|x| *x != 0xFF) { |
| 89 | defmt::panic!("unexpected"); | 89 | defmt::panic!("unexpected"); |
| @@ -93,9 +93,9 @@ fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLA | |||
| 93 | *b = 0xDA; | 93 | *b = 0xDA; |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | defmt::unwrap!(flash.write(ADDR_OFFSET + offset, &buf)); | 96 | defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, &buf)); |
| 97 | 97 | ||
| 98 | defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf)); | 98 | defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf)); |
| 99 | info!("Contents after write starts with {=[u8]}", buf[0..4]); | 99 | info!("Contents after write starts with {=[u8]}", buf[0..4]); |
| 100 | if buf.iter().any(|x| *x != 0xDA) { | 100 | if buf.iter().any(|x| *x != 0xDA) { |
| 101 | defmt::panic!("unexpected"); | 101 | defmt::panic!("unexpected"); |
| @@ -111,7 +111,7 @@ async fn background_read(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, | |||
| 111 | info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32); | 111 | info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32); |
| 112 | info!("Contents start with {=u32:x}", buf[0]); | 112 | info!("Contents start with {=u32:x}", buf[0]); |
| 113 | 113 | ||
| 114 | defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32)); | 114 | defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32)); |
| 115 | 115 | ||
| 116 | defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await; | 116 | defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await; |
| 117 | info!("Contents after erase starts with {=u32:x}", buf[0]); | 117 | info!("Contents after erase starts with {=u32:x}", buf[0]); |
| @@ -123,7 +123,7 @@ async fn background_read(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, | |||
| 123 | *b = 0xDABA1234; | 123 | *b = 0xDABA1234; |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | defmt::unwrap!(flash.write(ADDR_OFFSET + offset, unsafe { | 126 | defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, unsafe { |
| 127 | core::slice::from_raw_parts(buf.as_ptr() as *const u8, buf.len() * 4) | 127 | core::slice::from_raw_parts(buf.as_ptr() as *const u8, buf.len() * 4) |
| 128 | })); | 128 | })); |
| 129 | 129 | ||
diff --git a/examples/rp/src/bin/lora_p2p_send_multicore.rs b/examples/rp/src/bin/lora_p2p_send_multicore.rs index 89a62818d..b54cc92f6 100644 --- a/examples/rp/src/bin/lora_p2p_send_multicore.rs +++ b/examples/rp/src/bin/lora_p2p_send_multicore.rs | |||
| @@ -113,7 +113,7 @@ async fn core1_task( | |||
| 113 | }; | 113 | }; |
| 114 | 114 | ||
| 115 | loop { | 115 | loop { |
| 116 | let buffer: [u8; 3] = CHANNEL.recv().await; | 116 | let buffer: [u8; 3] = CHANNEL.receive().await; |
| 117 | match lora.prepare_for_tx(&mdltn_params, 20, false).await { | 117 | match lora.prepare_for_tx(&mdltn_params, 20, false).await { |
| 118 | Ok(()) => {} | 118 | Ok(()) => {} |
| 119 | Err(err) => { | 119 | Err(err) => { |
diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs index 893b724bf..bf017f6a7 100644 --- a/examples/rp/src/bin/multicore.rs +++ b/examples/rp/src/bin/multicore.rs | |||
| @@ -56,7 +56,7 @@ async fn core0_task() { | |||
| 56 | async fn core1_task(mut led: Output<'static, PIN_25>) { | 56 | async fn core1_task(mut led: Output<'static, PIN_25>) { |
| 57 | info!("Hello from core 1"); | 57 | info!("Hello from core 1"); |
| 58 | loop { | 58 | loop { |
| 59 | match CHANNEL.recv().await { | 59 | match CHANNEL.receive().await { |
| 60 | LedState::On => led.set_high(), | 60 | LedState::On => led.set_high(), |
| 61 | LedState::Off => led.set_low(), | 61 | LedState::Off => led.set_low(), |
| 62 | } | 62 | } |
diff --git a/examples/stm32f3/src/bin/button_events.rs b/examples/stm32f3/src/bin/button_events.rs index 02c475f66..8e97e85eb 100644 --- a/examples/stm32f3/src/bin/button_events.rs +++ b/examples/stm32f3/src/bin/button_events.rs | |||
| @@ -49,12 +49,12 @@ impl<'a> Leds<'a> { | |||
| 49 | 49 | ||
| 50 | async fn show(&mut self) { | 50 | async fn show(&mut self) { |
| 51 | self.leds[self.current_led].set_high(); | 51 | self.leds[self.current_led].set_high(); |
| 52 | if let Ok(new_message) = with_timeout(Duration::from_millis(500), CHANNEL.recv()).await { | 52 | if let Ok(new_message) = with_timeout(Duration::from_millis(500), CHANNEL.receive()).await { |
| 53 | self.leds[self.current_led].set_low(); | 53 | self.leds[self.current_led].set_low(); |
| 54 | self.process_event(new_message).await; | 54 | self.process_event(new_message).await; |
| 55 | } else { | 55 | } else { |
| 56 | self.leds[self.current_led].set_low(); | 56 | self.leds[self.current_led].set_low(); |
| 57 | if let Ok(new_message) = with_timeout(Duration::from_millis(200), CHANNEL.recv()).await { | 57 | if let Ok(new_message) = with_timeout(Duration::from_millis(200), CHANNEL.receive()).await { |
| 58 | self.process_event(new_message).await; | 58 | self.process_event(new_message).await; |
| 59 | } | 59 | } |
| 60 | } | 60 | } |
diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 44d0a9574..5d73e435e 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml | |||
| @@ -20,8 +20,8 @@ defmt-rtt = "0.4" | |||
| 20 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 20 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 21 | cortex-m-rt = "0.7.0" | 21 | cortex-m-rt = "0.7.0" |
| 22 | embedded-hal = "0.2.6" | 22 | embedded-hal = "0.2.6" |
| 23 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" } | 23 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } |
| 24 | embedded-hal-async = { version = "=0.2.0-alpha.2" } | 24 | embedded-hal-async = { version = "=1.0.0-rc.1" } |
| 25 | embedded-nal-async = { version = "0.5.0" } | 25 | embedded-nal-async = { version = "0.5.0" } |
| 26 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 26 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 27 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 27 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
diff --git a/examples/stm32h5/src/bin/usart_split.rs b/examples/stm32h5/src/bin/usart_split.rs index debd6f454..a6b2e690b 100644 --- a/examples/stm32h5/src/bin/usart_split.rs +++ b/examples/stm32h5/src/bin/usart_split.rs | |||
| @@ -44,7 +44,7 @@ async fn main(spawner: Spawner) -> ! { | |||
| 44 | unwrap!(spawner.spawn(reader(rx))); | 44 | unwrap!(spawner.spawn(reader(rx))); |
| 45 | 45 | ||
| 46 | loop { | 46 | loop { |
| 47 | let buf = CHANNEL.recv().await; | 47 | let buf = CHANNEL.receive().await; |
| 48 | info!("writing..."); | 48 | info!("writing..."); |
| 49 | unwrap!(tx.write(&buf).await); | 49 | unwrap!(tx.write(&buf).await); |
| 50 | } | 50 | } |
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index e2e5f9364..c78c4c602 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml | |||
| @@ -20,8 +20,8 @@ defmt-rtt = "0.4" | |||
| 20 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | 20 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } |
| 21 | cortex-m-rt = "0.7.0" | 21 | cortex-m-rt = "0.7.0" |
| 22 | embedded-hal = "0.2.6" | 22 | embedded-hal = "0.2.6" |
| 23 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" } | 23 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } |
| 24 | embedded-hal-async = { version = "=0.2.0-alpha.2" } | 24 | embedded-hal-async = { version = "=1.0.0-rc.1" } |
| 25 | embedded-nal-async = { version = "0.5.0" } | 25 | embedded-nal-async = { version = "0.5.0" } |
| 26 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 26 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 27 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 27 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs index 330d1ce09..aa0753450 100644 --- a/examples/stm32h7/src/bin/usart_split.rs +++ b/examples/stm32h7/src/bin/usart_split.rs | |||
| @@ -44,7 +44,7 @@ async fn main(spawner: Spawner) -> ! { | |||
| 44 | unwrap!(spawner.spawn(reader(rx))); | 44 | unwrap!(spawner.spawn(reader(rx))); |
| 45 | 45 | ||
| 46 | loop { | 46 | loop { |
| 47 | let buf = CHANNEL.recv().await; | 47 | let buf = CHANNEL.receive().await; |
| 48 | info!("writing..."); | 48 | info!("writing..."); |
| 49 | unwrap!(tx.write(&buf).await); | 49 | unwrap!(tx.write(&buf).await); |
| 50 | } | 50 | } |
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 33aa05e65..332a6c5e5 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml | |||
| @@ -37,3 +37,6 @@ static_cell = "1.1" | |||
| 37 | 37 | ||
| 38 | [profile.release] | 38 | [profile.release] |
| 39 | debug = 2 | 39 | debug = 2 |
| 40 | |||
| 41 | [patch.crates-io] | ||
| 42 | lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} \ No newline at end of file | ||
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 3b27d8e81..944c8c27b 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml | |||
| @@ -19,8 +19,8 @@ defmt-rtt = "0.4" | |||
| 19 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 19 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 20 | cortex-m-rt = "0.7.0" | 20 | cortex-m-rt = "0.7.0" |
| 21 | embedded-hal = "0.2.6" | 21 | embedded-hal = "0.2.6" |
| 22 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" } | 22 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } |
| 23 | embedded-hal-async = { version = "=0.2.0-alpha.2" } | 23 | embedded-hal-async = { version = "=1.0.0-rc.1" } |
| 24 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 24 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 25 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 25 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 26 | heapless = { version = "0.7.5", default-features = false } | 26 | heapless = { version = "0.7.5", default-features = false } |
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 48b69c8d0..5440807f6 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml | |||
| @@ -30,3 +30,6 @@ chrono = { version = "^0.4", default-features = false } | |||
| 30 | 30 | ||
| 31 | [profile.release] | 31 | [profile.release] |
| 32 | debug = 2 | 32 | debug = 2 |
| 33 | |||
| 34 | [patch.crates-io] | ||
| 35 | lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"} \ No newline at end of file | ||
diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 179ed1d6a..7b34afa2b 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | # Before upgrading check that everything is available on all tier1 targets here: | 1 | # Before upgrading check that everything is available on all tier1 targets here: |
| 2 | # https://rust-lang.github.io/rustup-components-history | 2 | # https://rust-lang.github.io/rustup-components-history |
| 3 | [toolchain] | 3 | [toolchain] |
| 4 | channel = "nightly-2023-06-28" | 4 | channel = "nightly-2023-08-19" |
| 5 | components = [ "rust-src", "rustfmt", "llvm-tools-preview" ] | 5 | components = [ "rust-src", "rustfmt", "llvm-tools-preview" ] |
| 6 | targets = [ | 6 | targets = [ |
| 7 | "thumbv7em-none-eabi", | 7 | "thumbv7em-none-eabi", |
diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 974a9413f..034ed85ea 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml | |||
| @@ -15,7 +15,9 @@ embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defm | |||
| 15 | embedded-io-async = { version = "0.5.0" } | 15 | embedded-io-async = { version = "0.5.0" } |
| 16 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] } | 16 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] } |
| 17 | embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } | 17 | embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } |
| 18 | embedded-hal-async = { version = "0.2.0-alpha.2" } | 18 | embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } |
| 19 | embedded-hal-async = { version = "1.0.0-rc.1" } | ||
| 20 | embedded-hal-bus = { version = "0.1.0-rc.1", features = ["async"] } | ||
| 19 | static_cell = { version = "1.1", features = [ "nightly" ] } | 21 | static_cell = { version = "1.1", features = [ "nightly" ] } |
| 20 | 22 | ||
| 21 | defmt = "0.3" | 23 | defmt = "0.3" |
diff --git a/tests/nrf/src/bin/buffered_uart.rs b/tests/nrf/src/bin/buffered_uart.rs index 72a4cb4ef..932e59264 100644 --- a/tests/nrf/src/bin/buffered_uart.rs +++ b/tests/nrf/src/bin/buffered_uart.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"nrf52840-dk"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::{assert_eq, *}; | 6 | use defmt::{assert_eq, *}; |
| 8 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
diff --git a/tests/nrf/src/bin/buffered_uart_spam.rs b/tests/nrf/src/bin/buffered_uart_spam.rs index 50960206f..8abeae6d4 100644 --- a/tests/nrf/src/bin/buffered_uart_spam.rs +++ b/tests/nrf/src/bin/buffered_uart_spam.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"nrf52840-dk"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use core::mem; | 6 | use core::mem; |
| 8 | use core::ptr::NonNull; | 7 | use core::ptr::NonNull; |
diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs new file mode 100644 index 000000000..0446d39ac --- /dev/null +++ b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs | |||
| @@ -0,0 +1,250 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | teleprobe_meta::target!(b"ak-gwe-r7"); | ||
| 5 | teleprobe_meta::timeout!(120); | ||
| 6 | |||
| 7 | use defmt::{error, info, unwrap}; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_futures::join::join; | ||
| 10 | use embassy_net::tcp::TcpSocket; | ||
| 11 | use embassy_net::{Ipv4Address, Stack, StackResources}; | ||
| 12 | use embassy_net_enc28j60::Enc28j60; | ||
| 13 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | ||
| 14 | use embassy_nrf::rng::Rng; | ||
| 15 | use embassy_nrf::spim::{self, Spim}; | ||
| 16 | use embassy_nrf::{bind_interrupts, peripherals}; | ||
| 17 | use embassy_time::{with_timeout, Delay, Duration, Timer}; | ||
| 18 | use embedded_hal_bus::spi::ExclusiveDevice; | ||
| 19 | use static_cell::make_static; | ||
| 20 | use {defmt_rtt as _, panic_probe as _}; | ||
| 21 | |||
| 22 | bind_interrupts!(struct Irqs { | ||
| 23 | SPIM3 => spim::InterruptHandler<peripherals::SPI3>; | ||
| 24 | RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>; | ||
| 25 | }); | ||
| 26 | |||
| 27 | type MyDriver = Enc28j60< | ||
| 28 | ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_15>, Delay>, | ||
| 29 | Output<'static, peripherals::P0_13>, | ||
| 30 | >; | ||
| 31 | |||
| 32 | #[embassy_executor::task] | ||
| 33 | async fn net_task(stack: &'static Stack<MyDriver>) -> ! { | ||
| 34 | stack.run().await | ||
| 35 | } | ||
| 36 | |||
| 37 | #[embassy_executor::main] | ||
| 38 | async fn main(spawner: Spawner) { | ||
| 39 | let p = embassy_nrf::init(Default::default()); | ||
| 40 | info!("running!"); | ||
| 41 | |||
| 42 | let eth_sck = p.P0_20; | ||
| 43 | let eth_mosi = p.P0_22; | ||
| 44 | let eth_miso = p.P0_24; | ||
| 45 | let eth_cs = p.P0_15; | ||
| 46 | let eth_rst = p.P0_13; | ||
| 47 | let _eth_irq = p.P0_12; | ||
| 48 | |||
| 49 | let mut config = spim::Config::default(); | ||
| 50 | config.frequency = spim::Frequency::M16; | ||
| 51 | let spi = spim::Spim::new(p.SPI3, Irqs, eth_sck, eth_miso, eth_mosi, config); | ||
| 52 | let cs = Output::new(eth_cs, Level::High, OutputDrive::Standard); | ||
| 53 | let spi = ExclusiveDevice::new(spi, cs, Delay); | ||
| 54 | |||
| 55 | let rst = Output::new(eth_rst, Level::High, OutputDrive::Standard); | ||
| 56 | let mac_addr = [2, 3, 4, 5, 6, 7]; | ||
| 57 | let device = Enc28j60::new(spi, Some(rst), mac_addr); | ||
| 58 | |||
| 59 | let config = embassy_net::Config::dhcpv4(Default::default()); | ||
| 60 | // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { | ||
| 61 | // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), | ||
| 62 | // dns_servers: Vec::new(), | ||
| 63 | // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), | ||
| 64 | // }); | ||
| 65 | |||
| 66 | // Generate random seed | ||
| 67 | let mut rng = Rng::new(p.RNG, Irqs); | ||
| 68 | let mut seed = [0; 8]; | ||
| 69 | rng.blocking_fill_bytes(&mut seed); | ||
| 70 | let seed = u64::from_le_bytes(seed); | ||
| 71 | |||
| 72 | // Init network stack | ||
| 73 | let stack = &*make_static!(Stack::new( | ||
| 74 | device, | ||
| 75 | config, | ||
| 76 | make_static!(StackResources::<2>::new()), | ||
| 77 | seed | ||
| 78 | )); | ||
| 79 | |||
| 80 | unwrap!(spawner.spawn(net_task(stack))); | ||
| 81 | |||
| 82 | info!("Waiting for DHCP up..."); | ||
| 83 | while stack.config_v4().is_none() { | ||
| 84 | Timer::after(Duration::from_millis(100)).await; | ||
| 85 | } | ||
| 86 | info!("IP addressing up!"); | ||
| 87 | |||
| 88 | let down = test_download(stack).await; | ||
| 89 | let up = test_upload(stack).await; | ||
| 90 | let updown = test_upload_download(stack).await; | ||
| 91 | |||
| 92 | assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS); | ||
| 93 | assert!(up > TEST_EXPECTED_UPLOAD_KBPS); | ||
| 94 | assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS); | ||
| 95 | |||
| 96 | info!("Test OK"); | ||
| 97 | cortex_m::asm::bkpt(); | ||
| 98 | } | ||
| 99 | |||
| 100 | const TEST_DURATION: usize = 10; | ||
| 101 | const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 200; | ||
| 102 | const TEST_EXPECTED_UPLOAD_KBPS: usize = 200; | ||
| 103 | const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 150; | ||
| 104 | const RX_BUFFER_SIZE: usize = 4096; | ||
| 105 | const TX_BUFFER_SIZE: usize = 4096; | ||
| 106 | const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2); | ||
| 107 | const DOWNLOAD_PORT: u16 = 4321; | ||
| 108 | const UPLOAD_PORT: u16 = 4322; | ||
| 109 | const UPLOAD_DOWNLOAD_PORT: u16 = 4323; | ||
| 110 | |||
| 111 | async fn test_download(stack: &'static Stack<MyDriver>) -> usize { | ||
| 112 | info!("Testing download..."); | ||
| 113 | |||
| 114 | let mut rx_buffer = [0; RX_BUFFER_SIZE]; | ||
| 115 | let mut tx_buffer = [0; TX_BUFFER_SIZE]; | ||
| 116 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 117 | socket.set_timeout(Some(Duration::from_secs(10))); | ||
| 118 | |||
| 119 | info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT); | ||
| 120 | if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await { | ||
| 121 | error!("connect error: {:?}", e); | ||
| 122 | return 0; | ||
| 123 | } | ||
| 124 | info!("connected, testing..."); | ||
| 125 | |||
| 126 | let mut rx_buf = [0; 4096]; | ||
| 127 | let mut total: usize = 0; | ||
| 128 | with_timeout(Duration::from_secs(TEST_DURATION as _), async { | ||
| 129 | loop { | ||
| 130 | match socket.read(&mut rx_buf).await { | ||
| 131 | Ok(0) => { | ||
| 132 | error!("read EOF"); | ||
| 133 | return 0; | ||
| 134 | } | ||
| 135 | Ok(n) => total += n, | ||
| 136 | Err(e) => { | ||
| 137 | error!("read error: {:?}", e); | ||
| 138 | return 0; | ||
| 139 | } | ||
| 140 | } | ||
| 141 | } | ||
| 142 | }) | ||
| 143 | .await | ||
| 144 | .ok(); | ||
| 145 | |||
| 146 | let kbps = (total + 512) / 1024 / TEST_DURATION; | ||
| 147 | info!("download: {} kB/s", kbps); | ||
| 148 | kbps | ||
| 149 | } | ||
| 150 | |||
| 151 | async fn test_upload(stack: &'static Stack<MyDriver>) -> usize { | ||
| 152 | info!("Testing upload..."); | ||
| 153 | |||
| 154 | let mut rx_buffer = [0; RX_BUFFER_SIZE]; | ||
| 155 | let mut tx_buffer = [0; TX_BUFFER_SIZE]; | ||
| 156 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 157 | socket.set_timeout(Some(Duration::from_secs(10))); | ||
| 158 | |||
| 159 | info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT); | ||
| 160 | if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await { | ||
| 161 | error!("connect error: {:?}", e); | ||
| 162 | return 0; | ||
| 163 | } | ||
| 164 | info!("connected, testing..."); | ||
| 165 | |||
| 166 | let buf = [0; 4096]; | ||
| 167 | let mut total: usize = 0; | ||
| 168 | with_timeout(Duration::from_secs(TEST_DURATION as _), async { | ||
| 169 | loop { | ||
| 170 | match socket.write(&buf).await { | ||
| 171 | Ok(0) => { | ||
| 172 | error!("write zero?!??!?!"); | ||
| 173 | return 0; | ||
| 174 | } | ||
| 175 | Ok(n) => total += n, | ||
| 176 | Err(e) => { | ||
| 177 | error!("write error: {:?}", e); | ||
| 178 | return 0; | ||
| 179 | } | ||
| 180 | } | ||
| 181 | } | ||
| 182 | }) | ||
| 183 | .await | ||
| 184 | .ok(); | ||
| 185 | |||
| 186 | let kbps = (total + 512) / 1024 / TEST_DURATION; | ||
| 187 | info!("upload: {} kB/s", kbps); | ||
| 188 | kbps | ||
| 189 | } | ||
| 190 | |||
| 191 | async fn test_upload_download(stack: &'static Stack<MyDriver>) -> usize { | ||
| 192 | info!("Testing upload+download..."); | ||
| 193 | |||
| 194 | let mut rx_buffer = [0; RX_BUFFER_SIZE]; | ||
| 195 | let mut tx_buffer = [0; TX_BUFFER_SIZE]; | ||
| 196 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 197 | socket.set_timeout(Some(Duration::from_secs(10))); | ||
| 198 | |||
| 199 | info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT); | ||
| 200 | if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await { | ||
| 201 | error!("connect error: {:?}", e); | ||
| 202 | return 0; | ||
| 203 | } | ||
| 204 | info!("connected, testing..."); | ||
| 205 | |||
| 206 | let (mut reader, mut writer) = socket.split(); | ||
| 207 | |||
| 208 | let tx_buf = [0; 4096]; | ||
| 209 | let mut rx_buf = [0; 4096]; | ||
| 210 | let mut total: usize = 0; | ||
| 211 | let tx_fut = async { | ||
| 212 | loop { | ||
| 213 | match writer.write(&tx_buf).await { | ||
| 214 | Ok(0) => { | ||
| 215 | error!("write zero?!??!?!"); | ||
| 216 | return 0; | ||
| 217 | } | ||
| 218 | Ok(_) => {} | ||
| 219 | Err(e) => { | ||
| 220 | error!("write error: {:?}", e); | ||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | } | ||
| 225 | }; | ||
| 226 | |||
| 227 | let rx_fut = async { | ||
| 228 | loop { | ||
| 229 | match reader.read(&mut rx_buf).await { | ||
| 230 | Ok(0) => { | ||
| 231 | error!("read EOF"); | ||
| 232 | return 0; | ||
| 233 | } | ||
| 234 | Ok(n) => total += n, | ||
| 235 | Err(e) => { | ||
| 236 | error!("read error: {:?}", e); | ||
| 237 | return 0; | ||
| 238 | } | ||
| 239 | } | ||
| 240 | } | ||
| 241 | }; | ||
| 242 | |||
| 243 | with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut)) | ||
| 244 | .await | ||
| 245 | .ok(); | ||
| 246 | |||
| 247 | let kbps = (total + 512) / 1024 / TEST_DURATION; | ||
| 248 | info!("upload+download: {} kB/s", kbps); | ||
| 249 | kbps | ||
| 250 | } | ||
diff --git a/tests/nrf/src/bin/timer.rs b/tests/nrf/src/bin/timer.rs index 607c5bbf1..c00f35fd1 100644 --- a/tests/nrf/src/bin/timer.rs +++ b/tests/nrf/src/bin/timer.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"nrf52840-dk"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::{assert, info}; | 6 | use defmt::{assert, info}; |
| 8 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs index e2adfe0be..97ebafec8 100644 --- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs +++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs | |||
| @@ -1,9 +1,8 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | 4 | teleprobe_meta::target!(b"nrf52840-dk"); | |
| 5 | #[path = "../common.rs"] | 5 | teleprobe_meta::timeout!(120); |
| 6 | mod common; | ||
| 7 | 6 | ||
| 8 | use defmt::{error, info, unwrap}; | 7 | use defmt::{error, info, unwrap}; |
| 9 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| @@ -15,12 +14,10 @@ use embassy_nrf::rng::Rng; | |||
| 15 | use embassy_nrf::spim::{self, Spim}; | 14 | use embassy_nrf::spim::{self, Spim}; |
| 16 | use embassy_nrf::{bind_interrupts, peripherals}; | 15 | use embassy_nrf::{bind_interrupts, peripherals}; |
| 17 | use embassy_time::{with_timeout, Delay, Duration, Timer}; | 16 | use embassy_time::{with_timeout, Delay, Duration, Timer}; |
| 18 | use embedded_hal_async::spi::ExclusiveDevice; | 17 | use embedded_hal_bus::spi::ExclusiveDevice; |
| 19 | use static_cell::make_static; | 18 | use static_cell::make_static; |
| 20 | use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _}; | 19 | use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _}; |
| 21 | 20 | ||
| 22 | teleprobe_meta::timeout!(120); | ||
| 23 | |||
| 24 | bind_interrupts!(struct Irqs { | 21 | bind_interrupts!(struct Irqs { |
| 25 | SPIM3 => spim::InterruptHandler<peripherals::SPI3>; | 22 | SPIM3 => spim::InterruptHandler<peripherals::SPI3>; |
| 26 | RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>; | 23 | RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>; |
| @@ -76,8 +73,8 @@ async fn main(spawner: Spawner) { | |||
| 76 | 73 | ||
| 77 | unwrap!(spawner.spawn(wifi_task(runner))); | 74 | unwrap!(spawner.spawn(wifi_task(runner))); |
| 78 | 75 | ||
| 79 | control.init().await; | 76 | unwrap!(control.init().await); |
| 80 | control.join(WIFI_NETWORK, WIFI_PASSWORD).await; | 77 | unwrap!(control.connect(WIFI_NETWORK, WIFI_PASSWORD).await); |
| 81 | 78 | ||
| 82 | // Generate random seed | 79 | // Generate random seed |
| 83 | let mut rng = Rng::new(p.RNG, Irqs); | 80 | let mut rng = Rng::new(p.RNG, Irqs); |
diff --git a/tests/nrf/src/common.rs b/tests/nrf/src/common.rs deleted file mode 100644 index 1a05ac1c5..000000000 --- a/tests/nrf/src/common.rs +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | teleprobe_meta::target!(b"nrf52840-dk"); | ||
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 90a3bd0cf..6a3df4b9c 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml | |||
| @@ -9,10 +9,11 @@ teleprobe-meta = "1.1" | |||
| 9 | 9 | ||
| 10 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } |
| 12 | embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt"] } | 12 | embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits"] } |
| 13 | embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } | 13 | embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } |
| 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 15 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] } | 15 | embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] } |
| 16 | embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } | ||
| 16 | cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } | 17 | cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } |
| 17 | cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } | 18 | cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } |
| 18 | 19 | ||
| @@ -22,8 +23,9 @@ defmt-rtt = "0.4" | |||
| 22 | cortex-m = { version = "0.7.6" } | 23 | cortex-m = { version = "0.7.6" } |
| 23 | cortex-m-rt = "0.7.0" | 24 | cortex-m-rt = "0.7.0" |
| 24 | embedded-hal = "0.2.6" | 25 | embedded-hal = "0.2.6" |
| 25 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" } | 26 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } |
| 26 | embedded-hal-async = { version = "=0.2.0-alpha.2" } | 27 | embedded-hal-async = { version = "=1.0.0-rc.1" } |
| 28 | embedded-hal-bus = { version = "=0.1.0-rc.1", features = ["async"] } | ||
| 27 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } | 29 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } |
| 28 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } | 30 | futures = { version = "0.3.17", default-features = false, features = ["async-await"] } |
| 29 | embedded-io-async = { version = "0.5.0" } | 31 | embedded-io-async = { version = "0.5.0" } |
| @@ -31,6 +33,7 @@ embedded-storage = { version = "0.3" } | |||
| 31 | static_cell = { version = "1.1", features = ["nightly"]} | 33 | static_cell = { version = "1.1", features = ["nightly"]} |
| 32 | pio = "0.2" | 34 | pio = "0.2" |
| 33 | pio-proc = "0.2" | 35 | pio-proc = "0.2" |
| 36 | rand = { version = "0.8.5", default-features = false } | ||
| 34 | 37 | ||
| 35 | [profile.dev] | 38 | [profile.dev] |
| 36 | debug = 2 | 39 | debug = 2 |
diff --git a/tests/rp/src/bin/adc.rs b/tests/rp/src/bin/adc.rs index b29a3a7cb..0250fd5f4 100644 --- a/tests/rp/src/bin/adc.rs +++ b/tests/rp/src/bin/adc.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"rpi-pico"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::*; | 6 | use defmt::*; |
| 8 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs index fffdabc9b..1c665f95d 100644 --- a/tests/rp/src/bin/cyw43-perf.rs +++ b/tests/rp/src/bin/cyw43-perf.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"rpi-pico"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use cyw43_pio::PioSpi; | 6 | use cyw43_pio::PioSpi; |
| 8 | use defmt::{assert, panic, *}; | 7 | use defmt::{assert, panic, *}; |
diff --git a/tests/rp/src/bin/dma_copy_async.rs b/tests/rp/src/bin/dma_copy_async.rs index 2c0b559a9..b071ed9df 100644 --- a/tests/rp/src/bin/dma_copy_async.rs +++ b/tests/rp/src/bin/dma_copy_async.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"rpi-pico"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::{assert_eq, *}; | 6 | use defmt::{assert_eq, *}; |
| 8 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
diff --git a/tests/rp/src/bin/ethernet_w5100s_perf.rs b/tests/rp/src/bin/ethernet_w5100s_perf.rs new file mode 100644 index 000000000..faa8638c0 --- /dev/null +++ b/tests/rp/src/bin/ethernet_w5100s_perf.rs | |||
| @@ -0,0 +1,249 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | teleprobe_meta::target!(b"w5100s-evb-pico"); | ||
| 5 | teleprobe_meta::timeout!(120); | ||
| 6 | |||
| 7 | use defmt::{assert, *}; | ||
| 8 | use embassy_executor::Spawner; | ||
| 9 | use embassy_futures::join::join; | ||
| 10 | use embassy_net::tcp::TcpSocket; | ||
| 11 | use embassy_net::{Ipv4Address, Stack, StackResources}; | ||
| 12 | use embassy_net_wiznet::chip::W5100S; | ||
| 13 | use embassy_net_wiznet::*; | ||
| 14 | use embassy_rp::clocks::RoscRng; | ||
| 15 | use embassy_rp::gpio::{Input, Level, Output, Pull}; | ||
| 16 | use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0}; | ||
| 17 | use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; | ||
| 18 | use embassy_time::{with_timeout, Delay, Duration, Timer}; | ||
| 19 | use embedded_hal_bus::spi::ExclusiveDevice; | ||
| 20 | use rand::RngCore; | ||
| 21 | use static_cell::make_static; | ||
| 22 | use {defmt_rtt as _, panic_probe as _}; | ||
| 23 | |||
| 24 | #[embassy_executor::task] | ||
| 25 | async fn ethernet_task( | ||
| 26 | runner: Runner< | ||
| 27 | 'static, | ||
| 28 | W5100S, | ||
| 29 | ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, | ||
| 30 | Input<'static, PIN_21>, | ||
| 31 | Output<'static, PIN_20>, | ||
| 32 | >, | ||
| 33 | ) -> ! { | ||
| 34 | runner.run().await | ||
| 35 | } | ||
| 36 | |||
| 37 | #[embassy_executor::task] | ||
| 38 | async fn net_task(stack: &'static Stack<Device<'static>>) -> ! { | ||
| 39 | stack.run().await | ||
| 40 | } | ||
| 41 | |||
| 42 | #[embassy_executor::main] | ||
| 43 | async fn main(spawner: Spawner) { | ||
| 44 | let p = embassy_rp::init(Default::default()); | ||
| 45 | let mut rng = RoscRng; | ||
| 46 | |||
| 47 | let mut spi_cfg = SpiConfig::default(); | ||
| 48 | spi_cfg.frequency = 50_000_000; | ||
| 49 | let (miso, mosi, clk) = (p.PIN_16, p.PIN_19, p.PIN_18); | ||
| 50 | let spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg); | ||
| 51 | let cs = Output::new(p.PIN_17, Level::High); | ||
| 52 | let w5500_int = Input::new(p.PIN_21, Pull::Up); | ||
| 53 | let w5500_reset = Output::new(p.PIN_20, Level::High); | ||
| 54 | |||
| 55 | let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; | ||
| 56 | let state = make_static!(State::<8, 8>::new()); | ||
| 57 | let (device, runner) = embassy_net_wiznet::new( | ||
| 58 | mac_addr, | ||
| 59 | state, | ||
| 60 | ExclusiveDevice::new(spi, cs, Delay), | ||
| 61 | w5500_int, | ||
| 62 | w5500_reset, | ||
| 63 | ) | ||
| 64 | .await; | ||
| 65 | unwrap!(spawner.spawn(ethernet_task(runner))); | ||
| 66 | |||
| 67 | // Generate random seed | ||
| 68 | let seed = rng.next_u64(); | ||
| 69 | |||
| 70 | // Init network stack | ||
| 71 | let stack = &*make_static!(Stack::new( | ||
| 72 | device, | ||
| 73 | embassy_net::Config::dhcpv4(Default::default()), | ||
| 74 | make_static!(StackResources::<2>::new()), | ||
| 75 | seed | ||
| 76 | )); | ||
| 77 | |||
| 78 | // Launch network task | ||
| 79 | unwrap!(spawner.spawn(net_task(&stack))); | ||
| 80 | |||
| 81 | info!("Waiting for DHCP up..."); | ||
| 82 | while stack.config_v4().is_none() { | ||
| 83 | Timer::after(Duration::from_millis(100)).await; | ||
| 84 | } | ||
| 85 | info!("IP addressing up!"); | ||
| 86 | |||
| 87 | let down = test_download(stack).await; | ||
| 88 | let up = test_upload(stack).await; | ||
| 89 | let updown = test_upload_download(stack).await; | ||
| 90 | |||
| 91 | assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS); | ||
| 92 | assert!(up > TEST_EXPECTED_UPLOAD_KBPS); | ||
| 93 | assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS); | ||
| 94 | |||
| 95 | info!("Test OK"); | ||
| 96 | cortex_m::asm::bkpt(); | ||
| 97 | } | ||
| 98 | |||
| 99 | const TEST_DURATION: usize = 10; | ||
| 100 | const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 500; | ||
| 101 | const TEST_EXPECTED_UPLOAD_KBPS: usize = 500; | ||
| 102 | const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 300; | ||
| 103 | const RX_BUFFER_SIZE: usize = 4096; | ||
| 104 | const TX_BUFFER_SIZE: usize = 4096; | ||
| 105 | const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2); | ||
| 106 | const DOWNLOAD_PORT: u16 = 4321; | ||
| 107 | const UPLOAD_PORT: u16 = 4322; | ||
| 108 | const UPLOAD_DOWNLOAD_PORT: u16 = 4323; | ||
| 109 | |||
| 110 | async fn test_download(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize { | ||
| 111 | info!("Testing download..."); | ||
| 112 | |||
| 113 | let mut rx_buffer = [0; RX_BUFFER_SIZE]; | ||
| 114 | let mut tx_buffer = [0; TX_BUFFER_SIZE]; | ||
| 115 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 116 | socket.set_timeout(Some(Duration::from_secs(10))); | ||
| 117 | |||
| 118 | info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT); | ||
| 119 | if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await { | ||
| 120 | error!("connect error: {:?}", e); | ||
| 121 | return 0; | ||
| 122 | } | ||
| 123 | info!("connected, testing..."); | ||
| 124 | |||
| 125 | let mut rx_buf = [0; 4096]; | ||
| 126 | let mut total: usize = 0; | ||
| 127 | with_timeout(Duration::from_secs(TEST_DURATION as _), async { | ||
| 128 | loop { | ||
| 129 | match socket.read(&mut rx_buf).await { | ||
| 130 | Ok(0) => { | ||
| 131 | error!("read EOF"); | ||
| 132 | return 0; | ||
| 133 | } | ||
| 134 | Ok(n) => total += n, | ||
| 135 | Err(e) => { | ||
| 136 | error!("read error: {:?}", e); | ||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | } | ||
| 141 | }) | ||
| 142 | .await | ||
| 143 | .ok(); | ||
| 144 | |||
| 145 | let kbps = (total + 512) / 1024 / TEST_DURATION; | ||
| 146 | info!("download: {} kB/s", kbps); | ||
| 147 | kbps | ||
| 148 | } | ||
| 149 | |||
| 150 | async fn test_upload(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize { | ||
| 151 | info!("Testing upload..."); | ||
| 152 | |||
| 153 | let mut rx_buffer = [0; RX_BUFFER_SIZE]; | ||
| 154 | let mut tx_buffer = [0; TX_BUFFER_SIZE]; | ||
| 155 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 156 | socket.set_timeout(Some(Duration::from_secs(10))); | ||
| 157 | |||
| 158 | info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT); | ||
| 159 | if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await { | ||
| 160 | error!("connect error: {:?}", e); | ||
| 161 | return 0; | ||
| 162 | } | ||
| 163 | info!("connected, testing..."); | ||
| 164 | |||
| 165 | let buf = [0; 4096]; | ||
| 166 | let mut total: usize = 0; | ||
| 167 | with_timeout(Duration::from_secs(TEST_DURATION as _), async { | ||
| 168 | loop { | ||
| 169 | match socket.write(&buf).await { | ||
| 170 | Ok(0) => { | ||
| 171 | error!("write zero?!??!?!"); | ||
| 172 | return 0; | ||
| 173 | } | ||
| 174 | Ok(n) => total += n, | ||
| 175 | Err(e) => { | ||
| 176 | error!("write error: {:?}", e); | ||
| 177 | return 0; | ||
| 178 | } | ||
| 179 | } | ||
| 180 | } | ||
| 181 | }) | ||
| 182 | .await | ||
| 183 | .ok(); | ||
| 184 | |||
| 185 | let kbps = (total + 512) / 1024 / TEST_DURATION; | ||
| 186 | info!("upload: {} kB/s", kbps); | ||
| 187 | kbps | ||
| 188 | } | ||
| 189 | |||
| 190 | async fn test_upload_download(stack: &'static Stack<cyw43::NetDriver<'static>>) -> usize { | ||
| 191 | info!("Testing upload+download..."); | ||
| 192 | |||
| 193 | let mut rx_buffer = [0; RX_BUFFER_SIZE]; | ||
| 194 | let mut tx_buffer = [0; TX_BUFFER_SIZE]; | ||
| 195 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | ||
| 196 | socket.set_timeout(Some(Duration::from_secs(10))); | ||
| 197 | |||
| 198 | info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT); | ||
| 199 | if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await { | ||
| 200 | error!("connect error: {:?}", e); | ||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | info!("connected, testing..."); | ||
| 204 | |||
| 205 | let (mut reader, mut writer) = socket.split(); | ||
| 206 | |||
| 207 | let tx_buf = [0; 4096]; | ||
| 208 | let mut rx_buf = [0; 4096]; | ||
| 209 | let mut total: usize = 0; | ||
| 210 | let tx_fut = async { | ||
| 211 | loop { | ||
| 212 | match writer.write(&tx_buf).await { | ||
| 213 | Ok(0) => { | ||
| 214 | error!("write zero?!??!?!"); | ||
| 215 | return 0; | ||
| 216 | } | ||
| 217 | Ok(_) => {} | ||
| 218 | Err(e) => { | ||
| 219 | error!("write error: {:?}", e); | ||
| 220 | return 0; | ||
| 221 | } | ||
| 222 | } | ||
| 223 | } | ||
| 224 | }; | ||
| 225 | |||
| 226 | let rx_fut = async { | ||
| 227 | loop { | ||
| 228 | match reader.read(&mut rx_buf).await { | ||
| 229 | Ok(0) => { | ||
| 230 | error!("read EOF"); | ||
| 231 | return 0; | ||
| 232 | } | ||
| 233 | Ok(n) => total += n, | ||
| 234 | Err(e) => { | ||
| 235 | error!("read error: {:?}", e); | ||
| 236 | return 0; | ||
| 237 | } | ||
| 238 | } | ||
| 239 | } | ||
| 240 | }; | ||
| 241 | |||
| 242 | with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut)) | ||
| 243 | .await | ||
| 244 | .ok(); | ||
| 245 | |||
| 246 | let kbps = (total + 512) / 1024 / TEST_DURATION; | ||
| 247 | info!("upload+download: {} kB/s", kbps); | ||
| 248 | kbps | ||
| 249 | } | ||
diff --git a/tests/rp/src/bin/flash.rs b/tests/rp/src/bin/flash.rs index c31d6decf..75be2bf06 100644 --- a/tests/rp/src/bin/flash.rs +++ b/tests/rp/src/bin/flash.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"rpi-pico"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::*; | 6 | use defmt::*; |
| 8 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| @@ -26,23 +25,23 @@ async fn main(_spawner: Spawner) { | |||
| 26 | let mut flash = embassy_rp::flash::Flash::<_, Async, { 2 * 1024 * 1024 }>::new(p.FLASH, p.DMA_CH0); | 25 | let mut flash = embassy_rp::flash::Flash::<_, Async, { 2 * 1024 * 1024 }>::new(p.FLASH, p.DMA_CH0); |
| 27 | 26 | ||
| 28 | // Get JEDEC id | 27 | // Get JEDEC id |
| 29 | let jedec = defmt::unwrap!(flash.jedec_id()); | 28 | let jedec = defmt::unwrap!(flash.blocking_jedec_id()); |
| 30 | info!("jedec id: 0x{:x}", jedec); | 29 | info!("jedec id: 0x{:x}", jedec); |
| 31 | 30 | ||
| 32 | // Get unique id | 31 | // Get unique id |
| 33 | let mut uid = [0; 8]; | 32 | let mut uid = [0; 8]; |
| 34 | defmt::unwrap!(flash.unique_id(&mut uid)); | 33 | defmt::unwrap!(flash.blocking_unique_id(&mut uid)); |
| 35 | info!("unique id: {:?}", uid); | 34 | info!("unique id: {:?}", uid); |
| 36 | 35 | ||
| 37 | let mut buf = [0u8; ERASE_SIZE]; | 36 | let mut buf = [0u8; ERASE_SIZE]; |
| 38 | defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf)); | 37 | defmt::unwrap!(flash.blocking_read(ADDR_OFFSET, &mut buf)); |
| 39 | 38 | ||
| 40 | info!("Addr of flash block is {:x}", ADDR_OFFSET + FLASH_BASE as u32); | 39 | info!("Addr of flash block is {:x}", ADDR_OFFSET + FLASH_BASE as u32); |
| 41 | info!("Contents start with {=[u8]}", buf[0..4]); | 40 | info!("Contents start with {=[u8]}", buf[0..4]); |
| 42 | 41 | ||
| 43 | defmt::unwrap!(flash.erase(ADDR_OFFSET, ADDR_OFFSET + ERASE_SIZE as u32)); | 42 | defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET, ADDR_OFFSET + ERASE_SIZE as u32)); |
| 44 | 43 | ||
| 45 | defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf)); | 44 | defmt::unwrap!(flash.blocking_read(ADDR_OFFSET, &mut buf)); |
| 46 | info!("Contents after erase starts with {=[u8]}", buf[0..4]); | 45 | info!("Contents after erase starts with {=[u8]}", buf[0..4]); |
| 47 | if buf.iter().any(|x| *x != 0xFF) { | 46 | if buf.iter().any(|x| *x != 0xFF) { |
| 48 | defmt::panic!("unexpected"); | 47 | defmt::panic!("unexpected"); |
| @@ -52,9 +51,9 @@ async fn main(_spawner: Spawner) { | |||
| 52 | *b = 0xDA; | 51 | *b = 0xDA; |
| 53 | } | 52 | } |
| 54 | 53 | ||
| 55 | defmt::unwrap!(flash.write(ADDR_OFFSET, &mut buf)); | 54 | defmt::unwrap!(flash.blocking_write(ADDR_OFFSET, &mut buf)); |
| 56 | 55 | ||
| 57 | defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf)); | 56 | defmt::unwrap!(flash.blocking_read(ADDR_OFFSET, &mut buf)); |
| 58 | info!("Contents after write starts with {=[u8]}", buf[0..4]); | 57 | info!("Contents after write starts with {=[u8]}", buf[0..4]); |
| 59 | if buf.iter().any(|x| *x != 0xDA) { | 58 | if buf.iter().any(|x| *x != 0xDA) { |
| 60 | defmt::panic!("unexpected"); | 59 | defmt::panic!("unexpected"); |
diff --git a/tests/rp/src/bin/float.rs b/tests/rp/src/bin/float.rs index 0e0de85fa..2874aa910 100644 --- a/tests/rp/src/bin/float.rs +++ b/tests/rp/src/bin/float.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"rpi-pico"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::*; | 6 | use defmt::*; |
| 8 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
diff --git a/tests/rp/src/bin/gpio.rs b/tests/rp/src/bin/gpio.rs index 946b7dc88..1a43a9283 100644 --- a/tests/rp/src/bin/gpio.rs +++ b/tests/rp/src/bin/gpio.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"rpi-pico"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::{assert, *}; | 6 | use defmt::{assert, *}; |
| 8 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
diff --git a/tests/rp/src/bin/gpio_async.rs b/tests/rp/src/bin/gpio_async.rs index 532494de5..60c65b7a0 100644 --- a/tests/rp/src/bin/gpio_async.rs +++ b/tests/rp/src/bin/gpio_async.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"rpi-pico"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::{assert, *}; | 6 | use defmt::{assert, *}; |
| 8 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
diff --git a/tests/rp/src/bin/gpio_multicore.rs b/tests/rp/src/bin/gpio_multicore.rs index 780112bc1..6ab7f6717 100644 --- a/tests/rp/src/bin/gpio_multicore.rs +++ b/tests/rp/src/bin/gpio_multicore.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"rpi-pico"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::{info, unwrap}; | 6 | use defmt::{info, unwrap}; |
| 8 | use embassy_executor::Executor; | 7 | use embassy_executor::Executor; |
| @@ -38,11 +37,11 @@ async fn core0_task(p: PIN_0) { | |||
| 38 | let mut pin = Output::new(p, Level::Low); | 37 | let mut pin = Output::new(p, Level::Low); |
| 39 | 38 | ||
| 40 | CHANNEL0.send(()).await; | 39 | CHANNEL0.send(()).await; |
| 41 | CHANNEL1.recv().await; | 40 | CHANNEL1.receive().await; |
| 42 | 41 | ||
| 43 | pin.set_high(); | 42 | pin.set_high(); |
| 44 | 43 | ||
| 45 | CHANNEL1.recv().await; | 44 | CHANNEL1.receive().await; |
| 46 | 45 | ||
| 47 | info!("Test OK"); | 46 | info!("Test OK"); |
| 48 | cortex_m::asm::bkpt(); | 47 | cortex_m::asm::bkpt(); |
| @@ -52,7 +51,7 @@ async fn core0_task(p: PIN_0) { | |||
| 52 | async fn core1_task(p: PIN_1) { | 51 | async fn core1_task(p: PIN_1) { |
| 53 | info!("CORE1 is running"); | 52 | info!("CORE1 is running"); |
| 54 | 53 | ||
| 55 | CHANNEL0.recv().await; | 54 | CHANNEL0.receive().await; |
| 56 | 55 | ||
| 57 | let mut pin = Input::new(p, Pull::Down); | 56 | let mut pin = Input::new(p, Pull::Down); |
| 58 | let wait = pin.wait_for_rising_edge(); | 57 | let wait = pin.wait_for_rising_edge(); |
diff --git a/tests/rp/src/bin/multicore.rs b/tests/rp/src/bin/multicore.rs index 114889dec..f4188135e 100644 --- a/tests/rp/src/bin/multicore.rs +++ b/tests/rp/src/bin/multicore.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"rpi-pico"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::{info, unwrap}; | 6 | use defmt::{info, unwrap}; |
| 8 | use embassy_executor::Executor; | 7 | use embassy_executor::Executor; |
| @@ -34,7 +33,7 @@ async fn core0_task() { | |||
| 34 | info!("CORE0 is running"); | 33 | info!("CORE0 is running"); |
| 35 | let ping = true; | 34 | let ping = true; |
| 36 | CHANNEL0.send(ping).await; | 35 | CHANNEL0.send(ping).await; |
| 37 | let pong = CHANNEL1.recv().await; | 36 | let pong = CHANNEL1.receive().await; |
| 38 | assert_eq!(ping, pong); | 37 | assert_eq!(ping, pong); |
| 39 | 38 | ||
| 40 | info!("Test OK"); | 39 | info!("Test OK"); |
| @@ -44,6 +43,6 @@ async fn core0_task() { | |||
| 44 | #[embassy_executor::task] | 43 | #[embassy_executor::task] |
| 45 | async fn core1_task() { | 44 | async fn core1_task() { |
| 46 | info!("CORE1 is running"); | 45 | info!("CORE1 is running"); |
| 47 | let ping = CHANNEL0.recv().await; | 46 | let ping = CHANNEL0.receive().await; |
| 48 | CHANNEL1.send(ping).await; | 47 | CHANNEL1.send(ping).await; |
| 49 | } | 48 | } |
diff --git a/tests/rp/src/bin/pio_irq.rs b/tests/rp/src/bin/pio_irq.rs index bdea63eaa..c71e55d91 100644 --- a/tests/rp/src/bin/pio_irq.rs +++ b/tests/rp/src/bin/pio_irq.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"rpi-pico"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::info; | 6 | use defmt::info; |
| 8 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
diff --git a/tests/rp/src/bin/pio_multi_load.rs b/tests/rp/src/bin/pio_multi_load.rs index 356f16795..6343ff3a9 100644 --- a/tests/rp/src/bin/pio_multi_load.rs +++ b/tests/rp/src/bin/pio_multi_load.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"rpi-pico"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::info; | 6 | use defmt::info; |
| 8 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
diff --git a/tests/rp/src/bin/pwm.rs b/tests/rp/src/bin/pwm.rs index c71d21ef9..8c02b8441 100644 --- a/tests/rp/src/bin/pwm.rs +++ b/tests/rp/src/bin/pwm.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"rpi-pico"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::{assert, assert_eq, assert_ne, *}; | 6 | use defmt::{assert, assert_eq, assert_ne, *}; |
| 8 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
diff --git a/tests/rp/src/bin/spi.rs b/tests/rp/src/bin/spi.rs index 84dfa5a2c..f347b80ca 100644 --- a/tests/rp/src/bin/spi.rs +++ b/tests/rp/src/bin/spi.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"rpi-pico"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::{assert_eq, *}; | 6 | use defmt::{assert_eq, *}; |
| 8 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
diff --git a/tests/rp/src/bin/spi_async.rs b/tests/rp/src/bin/spi_async.rs index a4080b03d..80d5a7147 100644 --- a/tests/rp/src/bin/spi_async.rs +++ b/tests/rp/src/bin/spi_async.rs | |||
| @@ -4,8 +4,7 @@ | |||
| 4 | #![no_std] | 4 | #![no_std] |
| 5 | #![no_main] | 5 | #![no_main] |
| 6 | #![feature(type_alias_impl_trait)] | 6 | #![feature(type_alias_impl_trait)] |
| 7 | #[path = "../common.rs"] | 7 | teleprobe_meta::target!(b"rpi-pico"); |
| 8 | mod common; | ||
| 9 | 8 | ||
| 10 | use defmt::{assert_eq, *}; | 9 | use defmt::{assert_eq, *}; |
| 11 | use embassy_executor::Spawner; | 10 | use embassy_executor::Spawner; |
diff --git a/tests/rp/src/bin/uart.rs b/tests/rp/src/bin/uart.rs index 2331c7d36..00f3e1949 100644 --- a/tests/rp/src/bin/uart.rs +++ b/tests/rp/src/bin/uart.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"rpi-pico"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::{assert_eq, *}; | 6 | use defmt::{assert_eq, *}; |
| 8 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs index edabf55b7..6ab7de29e 100644 --- a/tests/rp/src/bin/uart_buffered.rs +++ b/tests/rp/src/bin/uart_buffered.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"rpi-pico"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::{assert_eq, panic, *}; | 6 | use defmt::{assert_eq, panic, *}; |
| 8 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
diff --git a/tests/rp/src/bin/uart_dma.rs b/tests/rp/src/bin/uart_dma.rs index fee6c825d..cd4af1ef2 100644 --- a/tests/rp/src/bin/uart_dma.rs +++ b/tests/rp/src/bin/uart_dma.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"rpi-pico"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::{assert_eq, *}; | 6 | use defmt::{assert_eq, *}; |
| 8 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
diff --git a/tests/rp/src/bin/uart_upgrade.rs b/tests/rp/src/bin/uart_upgrade.rs index effd0bc49..c07fc08cd 100644 --- a/tests/rp/src/bin/uart_upgrade.rs +++ b/tests/rp/src/bin/uart_upgrade.rs | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | #![feature(type_alias_impl_trait)] | 3 | #![feature(type_alias_impl_trait)] |
| 4 | #[path = "../common.rs"] | 4 | teleprobe_meta::target!(b"rpi-pico"); |
| 5 | mod common; | ||
| 6 | 5 | ||
| 7 | use defmt::{assert_eq, *}; | 6 | use defmt::{assert_eq, *}; |
| 8 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
diff --git a/tests/rp/src/common.rs b/tests/rp/src/common.rs deleted file mode 100644 index 955674f27..000000000 --- a/tests/rp/src/common.rs +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | teleprobe_meta::target!(b"rpi-pico"); | ||
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 17320649e..e26388976 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml | |||
| @@ -41,8 +41,8 @@ defmt-rtt = "0.4" | |||
| 41 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } | 41 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } |
| 42 | cortex-m-rt = "0.7.0" | 42 | cortex-m-rt = "0.7.0" |
| 43 | embedded-hal = "0.2.6" | 43 | embedded-hal = "0.2.6" |
| 44 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" } | 44 | embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } |
| 45 | embedded-hal-async = { version = "=0.2.0-alpha.2" } | 45 | embedded-hal-async = { version = "=1.0.0-rc.1" } |
| 46 | micromath = "2.0.0" | 46 | micromath = "2.0.0" |
| 47 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } | 47 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } |
| 48 | rand_core = { version = "0.6", default-features = false } | 48 | rand_core = { version = "0.6", default-features = false } |
diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs index 8737ca8ee..acf545216 100644 --- a/tests/stm32/src/bin/can.rs +++ b/tests/stm32/src/bin/can.rs | |||
| @@ -80,8 +80,8 @@ async fn main(_spawner: Spawner) { | |||
| 80 | const MIN_LATENCY: Duration = Duration::from_micros(50); | 80 | const MIN_LATENCY: Duration = Duration::from_micros(50); |
| 81 | const MAX_LATENCY: Duration = Duration::from_micros(150); | 81 | const MAX_LATENCY: Duration = Duration::from_micros(150); |
| 82 | assert!( | 82 | assert!( |
| 83 | MIN_LATENCY < latency && latency < MAX_LATENCY, | 83 | MIN_LATENCY <= latency && latency <= MAX_LATENCY, |
| 84 | "{} < {} < {}", | 84 | "{} <= {} <= {}", |
| 85 | MIN_LATENCY, | 85 | MIN_LATENCY, |
| 86 | latency, | 86 | latency, |
| 87 | MAX_LATENCY | 87 | MAX_LATENCY |
