aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-07-01 17:32:25 -0500
committerxoviat <[email protected]>2023-07-01 17:32:25 -0500
commit8141d53d94d6bec837c334d1e313d751bbebaac2 (patch)
tree627369dc612da0aba4ac8f82cc0b1a8615ab363b
parent21a86531955facbdba5583b5218e20f1ca6dc23e (diff)
parentba4344429264fa7beb99ab19c09059c2d531716d (diff)
Merge branch 'main' of https://github.com/embassy-rs/embassy into hrtim
-rw-r--r--.vscode/settings.json6
-rw-r--r--README.md4
-rw-r--r--cyw43/README.md12
-rw-r--r--embassy-boot/nrf/README.md2
-rw-r--r--embassy-net-driver-channel/Cargo.toml11
-rw-r--r--embassy-net-driver-channel/README.md96
-rw-r--r--embassy-net-driver-channel/src/lib.rs1
-rw-r--r--embassy-net-driver/Cargo.toml11
-rw-r--r--embassy-net-driver/README.md16
-rw-r--r--embassy-net-w5500/src/lib.rs5
-rw-r--r--embassy-net/Cargo.toml9
-rw-r--r--embassy-net/README.md64
-rw-r--r--embassy-net/src/lib.rs26
-rw-r--r--embassy-nrf/src/lib.rs6
-rw-r--r--embassy-nrf/src/ppi/mod.rs15
-rw-r--r--embassy-rp/Cargo.toml2
-rw-r--r--embassy-rp/src/clocks.rs92
-rw-r--r--embassy-rp/src/gpio.rs4
-rw-r--r--embassy-rp/src/pio.rs4
-rw-r--r--embassy-rp/src/usb.rs1
-rw-r--r--embassy-stm32/Cargo.toml2
-rw-r--r--embassy-stm32/build.rs2
-rw-r--r--embassy-stm32/src/adc/v3.rs8
-rw-r--r--embassy-stm32/src/can/bxcan.rs8
-rw-r--r--embassy-stm32/src/dac.rs260
-rw-r--r--embassy-stm32/src/dac/mod.rs570
-rw-r--r--embassy-stm32/src/dma/bdma.rs32
-rw-r--r--embassy-stm32/src/eth/v1/rx_desc.rs2
-rw-r--r--embassy-stm32/src/pwm/complementary_pwm.rs2
-rw-r--r--embassy-stm32/src/rcc/c0.rs10
-rw-r--r--embassy-stm32/src/rcc/f0.rs23
-rw-r--r--embassy-stm32/src/rcc/f1.rs36
-rw-r--r--embassy-stm32/src/rcc/f2.rs2
-rw-r--r--embassy-stm32/src/rcc/f4.rs12
-rw-r--r--embassy-stm32/src/rcc/f7.rs12
-rw-r--r--embassy-stm32/src/rcc/g0.rs10
-rw-r--r--embassy-stm32/src/rcc/g4.rs77
-rw-r--r--embassy-stm32/src/rcc/h7.rs17
-rw-r--r--embassy-stm32/src/rcc/l0.rs10
-rw-r--r--embassy-stm32/src/rcc/l1.rs6
-rw-r--r--embassy-stm32/src/rcc/l4.rs6
-rw-r--r--embassy-stm32/src/rcc/l5.rs6
-rw-r--r--embassy-stm32/src/rcc/u5.rs2
-rw-r--r--embassy-stm32/src/rtc/v2.rs4
-rw-r--r--embassy-stm32/src/rtc/v3.rs2
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs6
-rw-r--r--embassy-stm32/src/spi/mod.rs4
-rw-r--r--embassy-stm32/src/usart/mod.rs2
-rw-r--r--embassy-stm32/src/usb/usb.rs141
-rw-r--r--embassy-stm32/src/usb_otg/usb.rs519
-rw-r--r--embassy-stm32/src/wdg/mod.rs2
-rw-r--r--embassy-sync/src/pipe.rs4
-rw-r--r--embassy-usb/src/class/cdc_ncm/embassy_net.rs5
-rw-r--r--embassy-usb/src/class/cdc_ncm/mod.rs4
-rw-r--r--embassy-usb/src/lib.rs2
-rw-r--r--examples/boot/application/nrf/.cargo/config.toml4
-rw-r--r--examples/boot/application/rp/.cargo/config.toml2
-rw-r--r--examples/boot/application/stm32f3/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32f7/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32h7/.cargo/config.toml4
-rwxr-xr-xexamples/boot/application/stm32h7/flash-boot.sh2
-rw-r--r--examples/boot/application/stm32l0/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32l1/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32l4/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32wl/.cargo/config.toml4
-rw-r--r--examples/boot/bootloader/nrf/.cargo/config.toml2
-rw-r--r--examples/boot/bootloader/rp/.cargo/config.toml2
-rw-r--r--examples/nrf-rtos-trace/.cargo/config.toml4
-rw-r--r--examples/nrf52840-rtic/.cargo/config.toml4
-rw-r--r--examples/nrf52840/.cargo/config.toml4
-rw-r--r--examples/nrf52840/src/bin/nvmc.rs2
-rw-r--r--examples/nrf52840/src/bin/wdt.rs2
-rw-r--r--examples/nrf5340/.cargo/config.toml4
-rw-r--r--examples/rp/.cargo/config.toml2
-rw-r--r--examples/rp/src/bin/wifi_ap_tcp_server.rs4
-rw-r--r--examples/rp/src/bin/wifi_blinky.rs4
-rw-r--r--examples/rp/src/bin/wifi_scan.rs4
-rw-r--r--examples/rp/src/bin/wifi_tcp_server.rs4
-rw-r--r--examples/std/README.md23
-rw-r--r--examples/stm32c0/.cargo/config.toml4
-rw-r--r--examples/stm32f0/.cargo/config.toml2
-rw-r--r--examples/stm32f1/.cargo/config.toml4
-rw-r--r--examples/stm32f2/.cargo/config.toml4
-rw-r--r--examples/stm32f3/.cargo/config.toml4
-rw-r--r--examples/stm32f4/.cargo/config.toml4
-rw-r--r--examples/stm32f4/src/bin/dac.rs9
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs4
-rw-r--r--examples/stm32f4/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32f7/.cargo/config.toml4
-rw-r--r--examples/stm32f7/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32g0/.cargo/config.toml4
-rw-r--r--examples/stm32g4/.cargo/config.toml4
-rw-r--r--examples/stm32g4/src/bin/usb_serial.rs26
-rw-r--r--examples/stm32h5/.cargo/config.toml2
-rw-r--r--examples/stm32h7/.cargo/config.toml2
-rw-r--r--examples/stm32h7/src/bin/dac.rs9
-rw-r--r--examples/stm32h7/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32l0/.cargo/config.toml4
-rw-r--r--examples/stm32l1/.cargo/config.toml4
-rw-r--r--examples/stm32l4/.cargo/config.toml8
-rw-r--r--examples/stm32l4/src/bin/dac.rs17
-rw-r--r--examples/stm32l4/src/bin/dac_dma.rs137
-rw-r--r--examples/stm32l4/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32l5/.cargo/config.toml4
-rw-r--r--examples/stm32u5/.cargo/config.toml4
-rw-r--r--examples/stm32u5/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32wb/.cargo/config.toml4
-rw-r--r--examples/stm32wl/.cargo/config.toml4
-rw-r--r--tests/rp/src/bin/cyw43-perf.rs4
109 files changed, 1748 insertions, 846 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json
index fdfafafa9..29e8812e3 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -6,16 +6,16 @@
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": "thumbv7em-none-eabi", 9 "rust-analyzer.cargo.target": "thumbv7m-none-eabi",
10 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", 10 //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
11 "rust-analyzer.cargo.features": [ 11 "rust-analyzer.cargo.features": [
12 "nightly", 12 ///"nightly",
13 ], 13 ],
14 "rust-analyzer.linkedProjects": [ 14 "rust-analyzer.linkedProjects": [
15 // Declare for the target you wish to develop 15 // Declare for the target you wish to develop
16 // "embassy-executor/Cargo.toml", 16 // "embassy-executor/Cargo.toml",
17 // "embassy-sync/Cargo.toml", 17 // "embassy-sync/Cargo.toml",
18 "examples/nrf52840/Cargo.toml", 18 "examples/stm32wl/Cargo.toml",
19 // "examples/nrf5340/Cargo.toml", 19 // "examples/nrf5340/Cargo.toml",
20 // "examples/nrf-rtos-trace/Cargo.toml", 20 // "examples/nrf-rtos-trace/Cargo.toml",
21 // "examples/rp/Cargo.toml", 21 // "examples/rp/Cargo.toml",
diff --git a/README.md b/README.md
index 315d247ee..b05e55aa5 100644
--- a/README.md
+++ b/README.md
@@ -99,10 +99,10 @@ Examples are found in the `examples/` folder seperated by the chip manufacturer
99 99
100### Running examples 100### Running examples
101 101
102- Install `probe-rs-cli` with defmt support. 102- Install `probe-rs`.
103 103
104```bash 104```bash
105cargo install probe-rs-cli 105cargo install probe-rs --features cli
106``` 106```
107 107
108- Change directory to the sample's base directory. For example: 108- Change directory to the sample's base directory. For example:
diff --git a/cyw43/README.md b/cyw43/README.md
index defea489f..e4a81410d 100644
--- a/cyw43/README.md
+++ b/cyw43/README.md
@@ -1,6 +1,6 @@
1# cyw43 1# cyw43
2 2
3WIP driver for the CYW43439 wifi chip, used in the Raspberry Pi Pico W. Implementation based on [Infineon/wifi-host-driver](https://github.com/Infineon/wifi-host-driver). 3Rust driver for the CYW43439 wifi chip, used in the Raspberry Pi Pico W. Implementation based on [Infineon/wifi-host-driver](https://github.com/Infineon/wifi-host-driver).
4 4
5## Current status 5## Current status
6 6
@@ -19,18 +19,18 @@ Working:
19TODO: 19TODO:
20 20
21- Setting a custom MAC address. 21- Setting a custom MAC address.
22- Bus sleep (unclear what the benefit is. Is it needed for IRQs? or is it just power consumption optimization?) 22- Bus sleep (for power consumption optimization)
23 23
24## Running the examples 24## Running the examples
25 25
26- `cargo install probe-rs-cli` 26- `cargo install probe-rs --features cli`
27- `cd examples/rpi-pico-w` 27- `cd examples/rp`
28### Example 1: Scan the wifi stations 28### Example 1: Scan the wifi stations
29- `cargo run --release --bin wifi_scan` 29- `cargo run --release --bin wifi_scan`
30### Example 2: Create an access point (IP and credentials in the code) 30### Example 2: Create an access point (IP and credentials in the code)
31- `cargo run --release --bin tcp_server_ap` 31- `cargo run --release --bin wifi_ap_tcp_server`
32### Example 3: Connect to an existing network and create a server 32### Example 3: Connect to an existing network and create a server
33- `WIFI_NETWORK=MyWifiNetwork WIFI_PASSWORD=MyWifiPassword cargo run --release` 33- `WIFI_NETWORK=MyWifiNetwork WIFI_PASSWORD=MyWifiPassword cargo run --release --bin wifi_tcp_server`
34 34
35After a few seconds, you should see that DHCP picks up an IP address like this 35After a few seconds, you should see that DHCP picks up an IP address like this
36``` 36```
diff --git a/embassy-boot/nrf/README.md b/embassy-boot/nrf/README.md
index 7ce3c7021..fe581823d 100644
--- a/embassy-boot/nrf/README.md
+++ b/embassy-boot/nrf/README.md
@@ -6,7 +6,7 @@ An adaptation of `embassy-boot` for nRF.
6 6
7## Features 7## Features
8 8
9* Load applications with our without the softdevice. 9* Load applications with or without the softdevice.
10* Configure bootloader partitions based on linker script. 10* Configure bootloader partitions based on linker script.
11* Using watchdog timer to detect application failure. 11* Using watchdog timer to detect application failure.
12 12
diff --git a/embassy-net-driver-channel/Cargo.toml b/embassy-net-driver-channel/Cargo.toml
index e475551e1..bee2e3021 100644
--- a/embassy-net-driver-channel/Cargo.toml
+++ b/embassy-net-driver-channel/Cargo.toml
@@ -2,6 +2,14 @@
2name = "embassy-net-driver-channel" 2name = "embassy-net-driver-channel"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0"
6description = "High-level channel-based driver for the `embassy-net` async TCP/IP network stack."
7repository = "https://github.com/embassy-rs/embassy"
8categories = [
9 "embedded",
10 "no-std",
11 "asynchronous",
12]
5 13
6[package.metadata.embassy_docs] 14[package.metadata.embassy_docs]
7src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-driver-channel-v$VERSION/embassy-net-driver-channel/src/" 15src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-driver-channel-v$VERSION/embassy-net-driver-channel/src/"
@@ -9,6 +17,9 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-d
9features = ["defmt"] 17features = ["defmt"]
10target = "thumbv7em-none-eabi" 18target = "thumbv7em-none-eabi"
11 19
20[package.metadata.docs.rs]
21features = ["defmt"]
22
12[dependencies] 23[dependencies]
13defmt = { version = "0.3", optional = true } 24defmt = { version = "0.3", optional = true }
14log = { version = "0.4.14", optional = true } 25log = { version = "0.4.14", optional = true }
diff --git a/embassy-net-driver-channel/README.md b/embassy-net-driver-channel/README.md
new file mode 100644
index 000000000..dd90e7ad2
--- /dev/null
+++ b/embassy-net-driver-channel/README.md
@@ -0,0 +1,96 @@
1# embassy-net-driver-channel
2
3This crate provides a toolkit for implementing [`embassy-net`](https://crates.io/crates/embassy-net) drivers in a
4higher level way than implementing the [`embassy-net-driver`](https://crates.io/crates/embassy-net-driver) trait directly.
5
6The `embassy-net-driver` trait is polling-based. To implement it, you must write the packet receive/transmit state machines by
7hand, and hook up the `Waker`s provided by `embassy-net` to the right interrupt handlers so that `embassy-net`
8knows when to poll your driver again to make more progress.
9
10With `embassy-net-driver-channel`
11
12## A note about deadlocks
13
14When implementing a driver using this crate, it might be tempting to write it in the most straightforward way:
15
16```rust,ignore
17loop {
18 // Wait for either..
19 match select(
20 // ... the chip signaling an interrupt, indicating a packet is available to receive, or
21 irq_pin.wait_for_low(),
22 // ... a TX buffer becoming available, i.e. embassy-net wants to send a packet
23 tx_chan.tx_buf(),
24 ).await {
25 Either::First(_) => {
26 // a packet is ready to be received!
27 let buf = rx_chan.rx_buf().await; // allocate a rx buf from the packet queue
28 let n = receive_packet_over_spi(buf).await;
29 rx_chan.rx_done(n);
30 }
31 Either::Second(buf) => {
32 // a packet is ready to be sent!
33 send_packet_over_spi(buf).await;
34 tx_chan.tx_done();
35 }
36 }
37}
38```
39
40However, this code has a latent deadlock bug. The symptom is it can hang at `rx_chan.rx_buf().await` under load.
41
42The reason is that, under load, both the TX and RX queues can get full at the same time. When this happens, the `embassy-net` task stalls trying to send because the TX queue is full, therefore it stops processing packets in the RX queue. Your driver task also stalls because the RX queue is full, therefore it stops processing packets in the TX queue.
43
44The fix is to make sure to always service the TX queue while you're waiting for space to become available in the TX queue. For example, select on either "tx_chan.tx_buf() available" or "INT is low AND rx_chan.rx_buf() available":
45
46```rust,ignore
47loop {
48 // Wait for either..
49 match select(
50 async {
51 // ... the chip signaling an interrupt, indicating a packet is available to receive
52 irq_pin.wait_for_low().await;
53 // *AND* the buffer is ready...
54 rx_chan.rx_buf().await
55 },
56 // ... or a TX buffer becoming available, i.e. embassy-net wants to send a packet
57 tx_chan.tx_buf(),
58 ).await {
59 Either::First(buf) => {
60 // a packet is ready to be received!
61 let n = receive_packet_over_spi(buf).await;
62 rx_chan.rx_done(n);
63 }
64 Either::Second(buf) => {
65 // a packet is ready to be sent!
66 send_packet_over_spi(buf).await;
67 tx_chan.tx_done();
68 }
69 }
70}
71```
72
73## Examples
74
75These `embassy-net` drivers are implemented using this crate. You can look at them for inspiration.
76
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.
79- [`embassy-net-w5500`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-w5500) for Wiznet W5500 SPI Ethernet MAC+PHY chip.
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
82
83## Interoperability
84
85This crate can run on any executor.
86
87
88## License
89
90This work is licensed under either of
91
92- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
93 http://www.apache.org/licenses/LICENSE-2.0)
94- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
95
96at your option.
diff --git a/embassy-net-driver-channel/src/lib.rs b/embassy-net-driver-channel/src/lib.rs
index 0c8dcc22b..02a4c00d6 100644
--- a/embassy-net-driver-channel/src/lib.rs
+++ b/embassy-net-driver-channel/src/lib.rs
@@ -1,4 +1,5 @@
1#![no_std] 1#![no_std]
2#![doc = include_str!("../README.md")]
2 3
3// must go first! 4// must go first!
4mod fmt; 5mod fmt;
diff --git a/embassy-net-driver/Cargo.toml b/embassy-net-driver/Cargo.toml
index ff6f29355..da6d9ad62 100644
--- a/embassy-net-driver/Cargo.toml
+++ b/embassy-net-driver/Cargo.toml
@@ -3,7 +3,13 @@ name = "embassy-net-driver"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6description = "Driver trait for the `embassy-net` async TCP/IP network stack."
7repository = "https://github.com/embassy-rs/embassy"
8categories = [
9 "embedded",
10 "no-std",
11 "asynchronous",
12]
7 13
8[package.metadata.embassy_docs] 14[package.metadata.embassy_docs]
9src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-driver-v$VERSION/embassy-net-driver/src/" 15src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-driver-v$VERSION/embassy-net-driver/src/"
@@ -11,5 +17,8 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-d
11features = ["defmt"] 17features = ["defmt"]
12target = "thumbv7em-none-eabi" 18target = "thumbv7em-none-eabi"
13 19
20[package.metadata.docs.rs]
21features = ["defmt"]
22
14[dependencies] 23[dependencies]
15defmt = { version = "0.3", optional = true } \ No newline at end of file 24defmt = { version = "0.3", optional = true } \ No newline at end of file
diff --git a/embassy-net-driver/README.md b/embassy-net-driver/README.md
index 84f25492d..6a757380d 100644
--- a/embassy-net-driver/README.md
+++ b/embassy-net-driver/README.md
@@ -1,5 +1,21 @@
1# embassy-net-driver 1# embassy-net-driver
2 2
3This crate contains the driver trait necessary for adding [`embassy-net`](https://crates.io/crates/embassy-net) support
4for a new hardware platform.
5
6If you want to *use* `embassy-net` with already made drivers, you should depend on the main `embassy-net` crate, not on this crate.
7
8If you are writing a driver, you should depend only on this crate, not on the main `embassy-net` crate.
9This will allow your driver to continue working for newer `embassy-net` major versions, without needing an update,
10if the driver trait has not had breaking changes.
11
12See also [`embassy-net-driver-channel`](https://crates.io/crates/embassy-net-driver-channel), which provides a higer-level API
13to construct a driver that processes packets in its own background task and communicates with the `embassy-net` task via
14packet queues for RX and TX.
15
16## Interoperability
17
18This crate can run on any executor.
3 19
4## License 20## License
5 21
diff --git a/embassy-net-w5500/src/lib.rs b/embassy-net-w5500/src/lib.rs
index 6821373e3..efd9bed66 100644
--- a/embassy-net-w5500/src/lib.rs
+++ b/embassy-net-w5500/src/lib.rs
@@ -1,5 +1,6 @@
1//! [`embassy-net`](https://crates.io/crates/embassy-net) driver for the WIZnet W5500 ethernet chip.
1#![no_std] 2#![no_std]
2/// [`embassy-net`](crates.io/crates/embassy-net) driver for the WIZnet W5500 ethernet chip. 3
3mod device; 4mod device;
4mod socket; 5mod socket;
5mod spi; 6mod spi;
@@ -77,7 +78,7 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> {
77 } 78 }
78} 79}
79 80
80/// Obtain a driver for using the W5500 with [`embassy-net`](crates.io/crates/embassy-net). 81/// Obtain a driver for using the W5500 with [`embassy-net`](https://crates.io/crates/embassy-net).
81pub async fn new<'a, const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait, RST: OutputPin>( 82pub async fn new<'a, const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait, RST: OutputPin>(
82 mac_addr: [u8; 6], 83 mac_addr: [u8; 6],
83 state: &'a mut State<N_RX, N_TX>, 84 state: &'a mut State<N_RX, N_TX>,
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index cef8247eb..e89039daa 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -3,7 +3,13 @@ name = "embassy-net"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6description = "Async TCP/IP network stack for embedded systems"
7repository = "https://github.com/embassy-rs/embassy"
8categories = [
9 "embedded",
10 "no-std",
11 "asynchronous",
12]
7 13
8[package.metadata.embassy_docs] 14[package.metadata.embassy_docs]
9src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/" 15src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/"
@@ -44,7 +50,6 @@ smoltcp = { version = "0.10.0", default-features = false, features = [
44] } 50] }
45 51
46embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } 52embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
47embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" }
48embassy-time = { version = "0.1.0", path = "../embassy-time" } 53embassy-time = { version = "0.1.0", path = "../embassy-time" }
49embassy-sync = { version = "0.2.0", path = "../embassy-sync" } 54embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
50embedded-io = { version = "0.4.0", optional = true } 55embedded-io = { version = "0.4.0", optional = true }
diff --git a/embassy-net/README.md b/embassy-net/README.md
index 470926c58..48f9fd832 100644
--- a/embassy-net/README.md
+++ b/embassy-net/README.md
@@ -1,30 +1,56 @@
1# embassy-net 1# embassy-net
2 2
3embassy-net contains an async network API based on smoltcp and embassy, designed 3`embassy-net` is a no-std no-alloc async network stack, designed for embedded systems.
4for embedded systems.
5 4
6## Running the example 5It builds on [`smoltcp`](https://github.com/smoltcp-rs/smoltcp). It provides a higher-level and more opinionated
6API. It glues together the components provided by `smoltcp`, handling the low-level details with defaults and
7memory management designed to work well for embedded systems, aiiming for a more "Just Works" experience.
7 8
8First, create the tap0 interface. You only need to do this once. 9## Features
9 10
10```sh 11- IPv4, IPv6
11sudo ip tuntap add name tap0 mode tap user $USER 12- Ethernet and bare-IP mediums.
12sudo ip link set tap0 up 13- TCP, UDP, DNS, DHCPv4, IGMPv4
13sudo ip addr add 192.168.69.100/24 dev tap0 14- TCP sockets implement the `embedded-io` async traits.
14sudo ip -6 addr add fe80::100/64 dev tap0
15sudo ip -6 addr add fdaa::100/64 dev tap0
16sudo ip -6 route add fe80::/64 dev tap0
17sudo ip -6 route add fdaa::/64 dev tap0
18```
19 15
20Second, have something listening there. For example `nc -l 8000` 16See the [`smoltcp`](https://github.com/smoltcp-rs/smoltcp) README for a detailed list of implemented and
17unimplemented features of the network protocols.
21 18
22Then run the example located in the `examples` folder: 19## Hardware support
23 20
24```sh 21- [`esp-wifi`](https://github.com/esp-rs/esp-wifi) for WiFi support on bare-metal ESP32 chips. Maintained by Espressif.
25cd $EMBASSY_ROOT/examples/std/ 22- [`cyw43`](https://github.com/embassy-rs/embassy/tree/main/cyw43) for WiFi on CYW43xx chips, used in the Raspberry Pi Pico W
26cargo run --bin net -- --static-ip 23- [`embassy-usb`](https://github.com/embassy-rs/embassy/tree/main/embassy-usb) for Ethernet-over-USB (CDC NCM) support.
27``` 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.
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
28## Examples
29
30- For usage with Embassy HALs and network chip drivers, search [here](https://github.com/embassy-rs/embassy/tree/main/examples) for `eth` or `wifi`.
31- The [`esp-wifi` repo](https://github.com/esp-rs/esp-wifi) has examples for use on bare-metal ESP32 chips.
32- For usage on `std` platforms, see [the `std` examples](https://github.com/embassy-rs/embassy/tree/main/examples/std/src/bin)
33
34## Adding support for new hardware
35
36To add `embassy-net` support for new hardware (i.e. a new Ethernet or WiFi chip, or
37an Ethernet/WiFi MCU peripheral), you have to implement the [`embassy-net-driver`](https://crates.io/crates/embassy-net-driver)
38traits.
39
40Alternatively, [`embassy-net-driver-channel`](https://crates.io/crates/embassy-net-driver-channel) provides a higer-level API
41to construct a driver that processes packets in its own background task and communicates with the `embassy-net` task via
42packet queues for RX and TX.
43
44Drivers should depend only on `embassy-net-driver` or `embassy-net-driver-channel`. Never on the main `embassy-net` crate.
45This allows existing drivers to continue working for newer `embassy-net` major versions, without needing an update, if the driver
46trait has not had breaking changes.
47
48## Interoperability
49
50This crate can run on any executor.
51
52[`embassy-time`](https://crates.io/crates/embassy-net-driver) is used for timekeeping and timeouts. You must
53link an `embassy-time` driver in your project to use this crate.
28 54
29## License 55## License
30 56
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index 3e83da7aa..840d7a09a 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -57,7 +57,7 @@ pub struct StackResources<const SOCK: usize> {
57 57
58impl<const SOCK: usize> StackResources<SOCK> { 58impl<const SOCK: usize> StackResources<SOCK> {
59 /// Create a new set of stack resources. 59 /// Create a new set of stack resources.
60 pub fn new() -> Self { 60 pub const fn new() -> Self {
61 #[cfg(feature = "dns")] 61 #[cfg(feature = "dns")]
62 const INIT: Option<dns::DnsQuery> = None; 62 const INIT: Option<dns::DnsQuery> = None;
63 Self { 63 Self {
@@ -419,7 +419,29 @@ impl<D: Driver + 'static> Stack<D> {
419 }) 419 })
420 .await?; 420 .await?;
421 421
422 use embassy_hal_common::drop::OnDrop; 422 #[must_use = "to delay the drop handler invocation to the end of the scope"]
423 struct OnDrop<F: FnOnce()> {
424 f: core::mem::MaybeUninit<F>,
425 }
426
427 impl<F: FnOnce()> OnDrop<F> {
428 fn new(f: F) -> Self {
429 Self {
430 f: core::mem::MaybeUninit::new(f),
431 }
432 }
433
434 fn defuse(self) {
435 core::mem::forget(self)
436 }
437 }
438
439 impl<F: FnOnce()> Drop for OnDrop<F> {
440 fn drop(&mut self) {
441 unsafe { self.f.as_ptr().read()() }
442 }
443 }
444
423 let drop = OnDrop::new(|| { 445 let drop = OnDrop::new(|| {
424 self.with_mut(|s, i| { 446 self.with_mut(|s, i| {
425 let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket); 447 let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket);
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 691545662..d23759f9d 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -410,13 +410,13 @@ pub fn init(config: config::Config) -> Peripherals {
410 warn!( 410 warn!(
411 "You have requested enabling chip reset functionality on the reset pin, by not enabling the Cargo feature `reset-pin-as-gpio`.\n\ 411 "You have requested enabling chip reset functionality on the reset pin, by not enabling the Cargo feature `reset-pin-as-gpio`.\n\
412 However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ 412 However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\
413 To fix this, erase UICR manually, for example using `probe-rs-cli erase` or `nrfjprog --eraseuicr`." 413 To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`."
414 ); 414 );
415 #[cfg(feature = "reset-pin-as-gpio")] 415 #[cfg(feature = "reset-pin-as-gpio")]
416 warn!( 416 warn!(
417 "You have requested using the reset pin as GPIO, by enabling the Cargo feature `reset-pin-as-gpio`.\n\ 417 "You have requested using the reset pin as GPIO, by enabling the Cargo feature `reset-pin-as-gpio`.\n\
418 However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ 418 However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\
419 To fix this, erase UICR manually, for example using `probe-rs-cli erase` or `nrfjprog --eraseuicr`." 419 To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`."
420 ); 420 );
421 } 421 }
422 } 422 }
@@ -432,7 +432,7 @@ pub fn init(config: config::Config) -> Peripherals {
432 warn!( 432 warn!(
433 "You have requested to use P0.09 and P0.10 pins for NFC, by not enabling the Cargo feature `nfc-pins-as-gpio`.\n\ 433 "You have requested to use P0.09 and P0.10 pins for NFC, by not enabling the Cargo feature `nfc-pins-as-gpio`.\n\
434 However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ 434 However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\
435 To fix this, erase UICR manually, for example using `probe-rs-cli erase` or `nrfjprog --eraseuicr`." 435 To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`."
436 ); 436 );
437 } 437 }
438 } 438 }
diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs
index 7c18da6ee..76757a248 100644
--- a/embassy-nrf/src/ppi/mod.rs
+++ b/embassy-nrf/src/ppi/mod.rs
@@ -137,6 +137,11 @@ impl Task {
137 Self(ptr) 137 Self(ptr)
138 } 138 }
139 139
140 /// Triggers this task.
141 pub fn trigger(&mut self) {
142 unsafe { self.0.as_ptr().write_volatile(1) };
143 }
144
140 pub(crate) fn from_reg<T>(reg: &T) -> Self { 145 pub(crate) fn from_reg<T>(reg: &T) -> Self {
141 Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }) 146 Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) })
142 } 147 }
@@ -173,6 +178,16 @@ impl Event {
173 Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }) 178 Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) })
174 } 179 }
175 180
181 /// Describes whether this Event is currently in a triggered state.
182 pub fn is_triggered(&self) -> bool {
183 unsafe { self.0.as_ptr().read_volatile() == 1 }
184 }
185
186 /// Clear the current register's triggered state, reverting it to 0.
187 pub fn clear(&mut self) {
188 unsafe { self.0.as_ptr().write_volatile(0) };
189 }
190
176 /// Address of publish register for this event. 191 /// Address of publish register for this event.
177 #[cfg(feature = "_dppi")] 192 #[cfg(feature = "_dppi")]
178 pub fn publish_reg(&self) -> *mut u32 { 193 pub fn publish_reg(&self) -> *mut u32 {
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 49aa6a4d5..66823771a 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -76,7 +76,7 @@ embedded-storage = { version = "0.3" }
76rand_core = "0.6.4" 76rand_core = "0.6.4"
77fixed = "1.23.1" 77fixed = "1.23.1"
78 78
79rp-pac = { version = "5" } 79rp-pac = { version = "6" }
80 80
81embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 81embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
82embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} 82embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true}
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 4c6223107..ddd61d224 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -46,13 +46,13 @@ static CLOCKS: Clocks = Clocks {
46#[non_exhaustive] 46#[non_exhaustive]
47#[derive(Clone, Copy, Debug, PartialEq, Eq)] 47#[derive(Clone, Copy, Debug, PartialEq, Eq)]
48pub enum PeriClkSrc { 48pub enum PeriClkSrc {
49 Sys = ClkPeriCtrlAuxsrc::CLK_SYS.0, 49 Sys = ClkPeriCtrlAuxsrc::CLK_SYS as _,
50 PllSys = ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS.0, 50 PllSys = ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS as _,
51 PllUsb = ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB.0, 51 PllUsb = ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB as _,
52 Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH.0, 52 Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH as _,
53 Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC.0, 53 Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC as _,
54 // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0.0, 54 // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
55 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1.0, 55 // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
56} 56}
57 57
58#[non_exhaustive] 58#[non_exhaustive]
@@ -251,12 +251,12 @@ pub struct SysClkConfig {
251#[non_exhaustive] 251#[non_exhaustive]
252#[derive(Clone, Copy, Debug, PartialEq, Eq)] 252#[derive(Clone, Copy, Debug, PartialEq, Eq)]
253pub enum UsbClkSrc { 253pub enum UsbClkSrc {
254 PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB.0, 254 PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _,
255 PllSys = ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS.0, 255 PllSys = ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS as _,
256 Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH.0, 256 Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH as _,
257 Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC.0, 257 Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC as _,
258 // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0.0, 258 // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
259 // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1.0, 259 // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
260} 260}
261 261
262pub struct UsbClkConfig { 262pub struct UsbClkConfig {
@@ -269,12 +269,12 @@ pub struct UsbClkConfig {
269#[non_exhaustive] 269#[non_exhaustive]
270#[derive(Clone, Copy, Debug, PartialEq, Eq)] 270#[derive(Clone, Copy, Debug, PartialEq, Eq)]
271pub enum AdcClkSrc { 271pub enum AdcClkSrc {
272 PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB.0, 272 PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _,
273 PllSys = ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS.0, 273 PllSys = ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS as _,
274 Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH.0, 274 Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH as _,
275 Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC.0, 275 Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC as _,
276 // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0.0, 276 // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
277 // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1.0, 277 // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
278} 278}
279 279
280pub struct AdcClkConfig { 280pub struct AdcClkConfig {
@@ -287,12 +287,12 @@ pub struct AdcClkConfig {
287#[non_exhaustive] 287#[non_exhaustive]
288#[derive(Clone, Copy, Debug, PartialEq, Eq)] 288#[derive(Clone, Copy, Debug, PartialEq, Eq)]
289pub enum RtcClkSrc { 289pub enum RtcClkSrc {
290 PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB.0, 290 PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB as _,
291 PllSys = ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS.0, 291 PllSys = ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS as _,
292 Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH.0, 292 Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH as _,
293 Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC.0, 293 Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC as _,
294 // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0.0, 294 // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
295 // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1.0, 295 // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
296} 296}
297 297
298pub struct RtcClkConfig { 298pub struct RtcClkConfig {
@@ -396,7 +396,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
396 w.set_src(ref_src); 396 w.set_src(ref_src);
397 w.set_auxsrc(ref_aux); 397 w.set_auxsrc(ref_aux);
398 }); 398 });
399 while c.clk_ref_selected().read() != 1 << ref_src.0 {} 399 while c.clk_ref_selected().read() != 1 << ref_src as u32 {}
400 c.clk_ref_div().write(|w| { 400 c.clk_ref_div().write(|w| {
401 w.set_int(config.ref_clk.div); 401 w.set_int(config.ref_clk.div);
402 }); 402 });
@@ -425,13 +425,13 @@ pub(crate) unsafe fn init(config: ClockConfig) {
425 CLOCKS.sys.store(clk_sys_freq, Ordering::Relaxed); 425 CLOCKS.sys.store(clk_sys_freq, Ordering::Relaxed);
426 if sys_src != ClkSysCtrlSrc::CLK_REF { 426 if sys_src != ClkSysCtrlSrc::CLK_REF {
427 c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); 427 c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF));
428 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {} 428 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF as u32 {}
429 } 429 }
430 c.clk_sys_ctrl().write(|w| { 430 c.clk_sys_ctrl().write(|w| {
431 w.set_auxsrc(sys_aux); 431 w.set_auxsrc(sys_aux);
432 w.set_src(sys_src); 432 w.set_src(sys_src);
433 }); 433 });
434 while c.clk_sys_selected().read() != 1 << sys_src.0 {} 434 while c.clk_sys_selected().read() != 1 << sys_src as u32 {}
435 c.clk_sys_div().write(|w| { 435 c.clk_sys_div().write(|w| {
436 w.set_int(config.sys_clk.div_int); 436 w.set_int(config.sys_clk.div_int);
437 w.set_frac(config.sys_clk.div_frac); 437 w.set_frac(config.sys_clk.div_frac);
@@ -442,7 +442,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
442 if let Some(src) = config.peri_clk_src { 442 if let Some(src) = config.peri_clk_src {
443 c.clk_peri_ctrl().write(|w| { 443 c.clk_peri_ctrl().write(|w| {
444 w.set_enable(true); 444 w.set_enable(true);
445 w.set_auxsrc(ClkPeriCtrlAuxsrc(src as _)); 445 w.set_auxsrc(ClkPeriCtrlAuxsrc::from_bits(src as _));
446 }); 446 });
447 let peri_freq = match src { 447 let peri_freq = match src {
448 PeriClkSrc::Sys => clk_sys_freq, 448 PeriClkSrc::Sys => clk_sys_freq,
@@ -468,7 +468,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
468 c.clk_usb_ctrl().write(|w| { 468 c.clk_usb_ctrl().write(|w| {
469 w.set_phase(conf.phase); 469 w.set_phase(conf.phase);
470 w.set_enable(true); 470 w.set_enable(true);
471 w.set_auxsrc(ClkUsbCtrlAuxsrc(conf.src as _)); 471 w.set_auxsrc(ClkUsbCtrlAuxsrc::from_bits(conf.src as _));
472 }); 472 });
473 let usb_freq = match conf.src { 473 let usb_freq = match conf.src {
474 UsbClkSrc::PllUsb => pll_usb_freq, 474 UsbClkSrc::PllUsb => pll_usb_freq,
@@ -491,7 +491,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
491 c.clk_adc_ctrl().write(|w| { 491 c.clk_adc_ctrl().write(|w| {
492 w.set_phase(conf.phase); 492 w.set_phase(conf.phase);
493 w.set_enable(true); 493 w.set_enable(true);
494 w.set_auxsrc(ClkAdcCtrlAuxsrc(conf.src as _)); 494 w.set_auxsrc(ClkAdcCtrlAuxsrc::from_bits(conf.src as _));
495 }); 495 });
496 let adc_in_freq = match conf.src { 496 let adc_in_freq = match conf.src {
497 AdcClkSrc::PllUsb => pll_usb_freq, 497 AdcClkSrc::PllUsb => pll_usb_freq,
@@ -517,7 +517,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
517 c.clk_rtc_ctrl().write(|w| { 517 c.clk_rtc_ctrl().write(|w| {
518 w.set_phase(conf.phase); 518 w.set_phase(conf.phase);
519 w.set_enable(true); 519 w.set_enable(true);
520 w.set_auxsrc(ClkRtcCtrlAuxsrc(conf.src as _)); 520 w.set_auxsrc(ClkRtcCtrlAuxsrc::from_bits(conf.src as _));
521 }); 521 });
522 let rtc_in_freq = match conf.src { 522 let rtc_in_freq = match conf.src {
523 RtcClkSrc::PllUsb => pll_usb_freq, 523 RtcClkSrc::PllUsb => pll_usb_freq,
@@ -718,7 +718,7 @@ impl<'d, T: Pin> Drop for Gpin<'d, T> {
718 self.gpin 718 self.gpin
719 .io() 719 .io()
720 .ctrl() 720 .ctrl()
721 .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); 721 .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL as _));
722 } 722 }
723} 723}
724 724
@@ -743,17 +743,17 @@ impl_gpoutpin!(PIN_25, 3);
743 743
744#[repr(u8)] 744#[repr(u8)]
745pub enum GpoutSrc { 745pub enum GpoutSrc {
746 PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS.0, 746 PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS as _,
747 // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0.0, 747 // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
748 // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1.0, 748 // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
749 PllUsb = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB.0, 749 PllUsb = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB as _,
750 Rosc = ClkGpoutCtrlAuxsrc::ROSC_CLKSRC.0, 750 Rosc = ClkGpoutCtrlAuxsrc::ROSC_CLKSRC as _,
751 Xosc = ClkGpoutCtrlAuxsrc::XOSC_CLKSRC.0, 751 Xosc = ClkGpoutCtrlAuxsrc::XOSC_CLKSRC as _,
752 Sys = ClkGpoutCtrlAuxsrc::CLK_SYS.0, 752 Sys = ClkGpoutCtrlAuxsrc::CLK_SYS as _,
753 Usb = ClkGpoutCtrlAuxsrc::CLK_USB.0, 753 Usb = ClkGpoutCtrlAuxsrc::CLK_USB as _,
754 Adc = ClkGpoutCtrlAuxsrc::CLK_ADC.0, 754 Adc = ClkGpoutCtrlAuxsrc::CLK_ADC as _,
755 Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC.0, 755 Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _,
756 Ref = ClkGpoutCtrlAuxsrc::CLK_REF.0, 756 Ref = ClkGpoutCtrlAuxsrc::CLK_REF as _,
757} 757}
758 758
759pub struct Gpout<'d, T: GpoutPin> { 759pub struct Gpout<'d, T: GpoutPin> {
@@ -780,7 +780,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
780 pub fn set_src(&self, src: GpoutSrc) { 780 pub fn set_src(&self, src: GpoutSrc) {
781 let c = pac::CLOCKS; 781 let c = pac::CLOCKS;
782 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { 782 c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
783 w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _)); 783 w.set_auxsrc(ClkGpoutCtrlAuxsrc::from_bits(src as _));
784 }); 784 });
785 } 785 }
786 786
@@ -831,7 +831,7 @@ impl<'d, T: GpoutPin> Drop for Gpout<'d, T> {
831 self.gpout 831 self.gpout
832 .io() 832 .io()
833 .ctrl() 833 .ctrl()
834 .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); 834 .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL as _));
835 } 835 }
836} 836}
837 837
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index ce0d02557..f8048a4dd 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -452,7 +452,7 @@ impl<'d, T: Pin> Flex<'d, T> {
452 }); 452 });
453 453
454 pin.io().ctrl().write(|w| { 454 pin.io().ctrl().write(|w| {
455 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0.0); 455 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0 as _);
456 }); 456 });
457 457
458 Self { pin } 458 Self { pin }
@@ -618,7 +618,7 @@ impl<'d, T: Pin> Drop for Flex<'d, T> {
618 fn drop(&mut self) { 618 fn drop(&mut self) {
619 self.pin.pad_ctrl().write(|_| {}); 619 self.pin.pad_ctrl().write(|_| {});
620 self.pin.io().ctrl().write(|w| { 620 self.pin.io().ctrl().write(|w| {
621 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0); 621 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL as _);
622 }); 622 });
623 } 623 }
624} 624}
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs
index 1b36e0a54..30648e8ea 100644
--- a/embassy-rp/src/pio.rs
+++ b/embassy-rp/src/pio.rs
@@ -834,7 +834,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
834 /// of [`Pio`] do not keep pin registrations alive.** 834 /// of [`Pio`] do not keep pin registrations alive.**
835 pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> { 835 pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> {
836 into_ref!(pin); 836 into_ref!(pin);
837 pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0)); 837 pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL as _));
838 // we can be relaxed about this because we're &mut here and nothing is cached 838 // we can be relaxed about this because we're &mut here and nothing is cached
839 PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); 839 PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed);
840 Pin { 840 Pin {
@@ -998,7 +998,7 @@ fn on_pio_drop<PIO: Instance>() {
998 let state = PIO::state(); 998 let state = PIO::state();
999 if state.users.fetch_sub(1, Ordering::AcqRel) == 1 { 999 if state.users.fetch_sub(1, Ordering::AcqRel) == 1 {
1000 let used_pins = state.used_pins.load(Ordering::Relaxed); 1000 let used_pins = state.used_pins.load(Ordering::Relaxed);
1001 let null = Gpio0ctrlFuncsel::NULL.0; 1001 let null = Gpio0ctrlFuncsel::NULL as _;
1002 // we only have 30 pins. don't test the other two since gpio() asserts. 1002 // we only have 30 pins. don't test the other two since gpio() asserts.
1003 for i in 0..30 { 1003 for i in 0..30 {
1004 if used_pins & (1 << i) != 0 { 1004 if used_pins & (1 << i) != 0 {
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index 1900ab416..b3f3bd927 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -353,6 +353,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
353 poll_fn(move |cx| { 353 poll_fn(move |cx| {
354 BUS_WAKER.register(cx.waker()); 354 BUS_WAKER.register(cx.waker());
355 355
356 // TODO: implement VBUS detection.
356 if !self.inited { 357 if !self.inited {
357 self.inited = true; 358 self.inited = true;
358 return Poll::Ready(Event::PowerDetected); 359 return Poll::Ready(Event::PowerDetected);
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 551c09698..b3fe9c1f5 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] }
74[build-dependencies] 74[build-dependencies]
75proc-macro2 = "1.0.36" 75proc-macro2 = "1.0.36"
76quote = "1.0.15" 76quote = "1.0.15"
77stm32-metapac = { version = "10", default-features = false, features = ["metadata"]} 77stm32-metapac = { version = "12", default-features = false, features = ["metadata"]}
78 78
79[features] 79[features]
80default = ["rt"] 80default = ["rt"]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 4856047ce..d628bcf04 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -709,6 +709,8 @@ fn main() {
709 // SDMMCv1 uses the same channel for both directions, so just implement for RX 709 // SDMMCv1 uses the same channel for both directions, so just implement for RX
710 (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)), 710 (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)),
711 (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)), 711 (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)),
712 (("dac", "CH1"), quote!(crate::dac::DmaCh1)),
713 (("dac", "CH2"), quote!(crate::dac::DmaCh2)),
712 ] 714 ]
713 .into(); 715 .into();
714 716
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 94cdc86cd..3a6e58cf6 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -211,10 +211,8 @@ impl<'d, T: Instance> Adc<'d, T> {
211 #[cfg(not(stm32g0))] 211 #[cfg(not(stm32g0))]
212 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { 212 fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
213 let sample_time = sample_time.into(); 213 let sample_time = sample_time.into();
214 if ch <= 9 { 214 T::regs()
215 T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time)); 215 .smpr(ch as usize / 10)
216 } else { 216 .modify(|reg| reg.set_smp(ch as usize % 10, sample_time));
217 T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
218 }
219 } 217 }
220} 218}
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index 88eef528f..73861776a 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -116,10 +116,10 @@ impl<'d, T: Instance> Can<'d, T> {
116 T::regs().ier().write(|w| { 116 T::regs().ier().write(|w| {
117 // TODO: fix metapac 117 // TODO: fix metapac
118 118
119 w.set_errie(Errie(1)); 119 w.set_errie(Errie::from_bits(1));
120 w.set_fmpie(0, Fmpie(1)); 120 w.set_fmpie(0, Fmpie::from_bits(1));
121 w.set_fmpie(1, Fmpie(1)); 121 w.set_fmpie(1, Fmpie::from_bits(1));
122 w.set_tmeie(Tmeie(1)); 122 w.set_tmeie(Tmeie::from_bits(1));
123 }); 123 });
124 124
125 T::regs().mcr().write(|w| { 125 T::regs().mcr().write(|w| {
diff --git a/embassy-stm32/src/dac.rs b/embassy-stm32/src/dac.rs
deleted file mode 100644
index 631118877..000000000
--- a/embassy-stm32/src/dac.rs
+++ /dev/null
@@ -1,260 +0,0 @@
1#![macro_use]
2
3use embassy_hal_common::{into_ref, PeripheralRef};
4
5use crate::pac::dac;
6use crate::rcc::RccPeripheral;
7use crate::{peripherals, Peripheral};
8
9#[derive(Debug, Copy, Clone, Eq, PartialEq)]
10#[cfg_attr(feature = "defmt", derive(defmt::Format))]
11pub enum Error {
12 UnconfiguredChannel,
13 InvalidValue,
14}
15
16#[derive(Debug, Copy, Clone, Eq, PartialEq)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18pub enum Channel {
19 Ch1,
20 Ch2,
21}
22
23impl Channel {
24 fn index(&self) -> usize {
25 match self {
26 Channel::Ch1 => 0,
27 Channel::Ch2 => 1,
28 }
29 }
30}
31
32#[derive(Debug, Copy, Clone, Eq, PartialEq)]
33#[cfg_attr(feature = "defmt", derive(defmt::Format))]
34pub enum Ch1Trigger {
35 Tim6,
36 Tim3,
37 Tim7,
38 Tim15,
39 Tim2,
40 Exti9,
41 Software,
42}
43
44impl Ch1Trigger {
45 fn tsel(&self) -> dac::vals::Tsel1 {
46 match self {
47 Ch1Trigger::Tim6 => dac::vals::Tsel1::TIM6_TRGO,
48 Ch1Trigger::Tim3 => dac::vals::Tsel1::TIM3_TRGO,
49 Ch1Trigger::Tim7 => dac::vals::Tsel1::TIM7_TRGO,
50 Ch1Trigger::Tim15 => dac::vals::Tsel1::TIM15_TRGO,
51 Ch1Trigger::Tim2 => dac::vals::Tsel1::TIM2_TRGO,
52 Ch1Trigger::Exti9 => dac::vals::Tsel1::EXTI9,
53 Ch1Trigger::Software => dac::vals::Tsel1::SOFTWARE,
54 }
55 }
56}
57
58#[derive(Debug, Copy, Clone, Eq, PartialEq)]
59#[cfg_attr(feature = "defmt", derive(defmt::Format))]
60pub enum Ch2Trigger {
61 Tim6,
62 Tim8,
63 Tim7,
64 Tim5,
65 Tim2,
66 Tim4,
67 Exti9,
68 Software,
69}
70
71impl Ch2Trigger {
72 fn tsel(&self) -> dac::vals::Tsel2 {
73 match self {
74 Ch2Trigger::Tim6 => dac::vals::Tsel2::TIM6_TRGO,
75 Ch2Trigger::Tim8 => dac::vals::Tsel2::TIM8_TRGO,
76 Ch2Trigger::Tim7 => dac::vals::Tsel2::TIM7_TRGO,
77 Ch2Trigger::Tim5 => dac::vals::Tsel2::TIM5_TRGO,
78 Ch2Trigger::Tim2 => dac::vals::Tsel2::TIM2_TRGO,
79 Ch2Trigger::Tim4 => dac::vals::Tsel2::TIM4_TRGO,
80 Ch2Trigger::Exti9 => dac::vals::Tsel2::EXTI9,
81 Ch2Trigger::Software => dac::vals::Tsel2::SOFTWARE,
82 }
83 }
84}
85
86#[derive(Debug, Copy, Clone, Eq, PartialEq)]
87#[cfg_attr(feature = "defmt", derive(defmt::Format))]
88pub enum Alignment {
89 Left,
90 Right,
91}
92
93#[derive(Debug, Copy, Clone, Eq, PartialEq)]
94#[cfg_attr(feature = "defmt", derive(defmt::Format))]
95pub enum Value {
96 Bit8(u8),
97 Bit12(u16, Alignment),
98}
99
100pub struct Dac<'d, T: Instance> {
101 channels: u8,
102 _peri: PeripheralRef<'d, T>,
103}
104
105impl<'d, T: Instance> Dac<'d, T> {
106 pub fn new_1ch(peri: impl Peripheral<P = T> + 'd, _ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd) -> Self {
107 into_ref!(peri);
108 Self::new_inner(peri, 1)
109 }
110
111 pub fn new_2ch(
112 peri: impl Peripheral<P = T> + 'd,
113 _ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
114 _ch2: impl Peripheral<P = impl DacPin<T, 2>> + 'd,
115 ) -> Self {
116 into_ref!(peri);
117 Self::new_inner(peri, 2)
118 }
119
120 fn new_inner(peri: PeripheralRef<'d, T>, channels: u8) -> Self {
121 T::enable();
122 T::reset();
123
124 T::regs().cr().modify(|reg| {
125 for ch in 0..channels {
126 reg.set_en(ch as usize, true);
127 }
128 });
129
130 Self { channels, _peri: peri }
131 }
132
133 /// Check the channel is configured
134 fn check_channel_exists(&self, ch: Channel) -> Result<(), Error> {
135 if ch == Channel::Ch2 && self.channels < 2 {
136 Err(Error::UnconfiguredChannel)
137 } else {
138 Ok(())
139 }
140 }
141
142 fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> {
143 self.check_channel_exists(ch)?;
144 T::regs().cr().modify(|reg| {
145 reg.set_en(ch.index(), on);
146 });
147 Ok(())
148 }
149
150 pub fn enable_channel(&mut self, ch: Channel) -> Result<(), Error> {
151 self.set_channel_enable(ch, true)
152 }
153
154 pub fn disable_channel(&mut self, ch: Channel) -> Result<(), Error> {
155 self.set_channel_enable(ch, false)
156 }
157
158 pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
159 self.check_channel_exists(Channel::Ch1)?;
160 unwrap!(self.disable_channel(Channel::Ch1));
161 T::regs().cr().modify(|reg| {
162 reg.set_tsel1(trigger.tsel());
163 });
164 Ok(())
165 }
166
167 pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
168 self.check_channel_exists(Channel::Ch2)?;
169 unwrap!(self.disable_channel(Channel::Ch2));
170 T::regs().cr().modify(|reg| {
171 reg.set_tsel2(trigger.tsel());
172 });
173 Ok(())
174 }
175
176 pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> {
177 self.check_channel_exists(ch)?;
178 T::regs().swtrigr().write(|reg| {
179 reg.set_swtrig(ch.index(), true);
180 });
181 Ok(())
182 }
183
184 pub fn trigger_all(&mut self) {
185 T::regs().swtrigr().write(|reg| {
186 reg.set_swtrig(Channel::Ch1.index(), true);
187 reg.set_swtrig(Channel::Ch2.index(), true);
188 });
189 }
190
191 pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> {
192 self.check_channel_exists(ch)?;
193 match value {
194 Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)),
195 Value::Bit12(v, Alignment::Left) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)),
196 Value::Bit12(v, Alignment::Right) => T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)),
197 }
198 Ok(())
199 }
200}
201
202pub(crate) mod sealed {
203 pub trait Instance {
204 fn regs() -> &'static crate::pac::dac::Dac;
205 }
206}
207
208pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
209
210pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
211
212foreach_peripheral!(
213 (dac, $inst:ident) => {
214 // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
215 #[cfg(rcc_h7)]
216 impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
217 fn frequency() -> crate::time::Hertz {
218 critical_section::with(|_| unsafe {
219 crate::rcc::get_freqs().apb1
220 })
221 }
222
223 fn reset() {
224 critical_section::with(|_| {
225 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
226 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
227 })
228 }
229
230 fn enable() {
231 critical_section::with(|_| {
232 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
233 })
234 }
235
236 fn disable() {
237 critical_section::with(|_| {
238 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false));
239 })
240 }
241 }
242
243 #[cfg(rcc_h7)]
244 impl crate::rcc::RccPeripheral for peripherals::$inst {}
245
246 impl crate::dac::sealed::Instance for peripherals::$inst {
247 fn regs() -> &'static crate::pac::dac::Dac {
248 &crate::pac::$inst
249 }
250 }
251
252 impl crate::dac::Instance for peripherals::$inst {}
253 };
254);
255
256macro_rules! impl_dac_pin {
257 ($inst:ident, $pin:ident, $ch:expr) => {
258 impl crate::dac::DacPin<peripherals::$inst, $ch> for crate::peripherals::$pin {}
259 };
260}
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
new file mode 100644
index 000000000..1dc13949d
--- /dev/null
+++ b/embassy-stm32/src/dac/mod.rs
@@ -0,0 +1,570 @@
1#![macro_use]
2
3//! Provide access to the STM32 digital-to-analog converter (DAC).
4use core::marker::PhantomData;
5
6use embassy_hal_common::{into_ref, PeripheralRef};
7
8use crate::pac::dac;
9use crate::rcc::RccPeripheral;
10use crate::{peripherals, Peripheral};
11
12#[derive(Debug, Copy, Clone, Eq, PartialEq)]
13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
14/// Curstom Errors
15pub enum Error {
16 UnconfiguredChannel,
17 InvalidValue,
18}
19
20#[derive(Debug, Copy, Clone, Eq, PartialEq)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22/// DAC Channels
23pub enum Channel {
24 Ch1,
25 Ch2,
26}
27
28impl Channel {
29 const fn index(&self) -> usize {
30 match self {
31 Channel::Ch1 => 0,
32 Channel::Ch2 => 1,
33 }
34 }
35}
36
37#[derive(Debug, Copy, Clone, Eq, PartialEq)]
38#[cfg_attr(feature = "defmt", derive(defmt::Format))]
39/// Trigger sources for CH1
40pub enum Ch1Trigger {
41 Tim6,
42 Tim3,
43 Tim7,
44 Tim15,
45 Tim2,
46 Exti9,
47 Software,
48}
49
50impl Ch1Trigger {
51 fn tsel(&self) -> dac::vals::Tsel1 {
52 match self {
53 Ch1Trigger::Tim6 => dac::vals::Tsel1::TIM6_TRGO,
54 Ch1Trigger::Tim3 => dac::vals::Tsel1::TIM3_TRGO,
55 Ch1Trigger::Tim7 => dac::vals::Tsel1::TIM7_TRGO,
56 Ch1Trigger::Tim15 => dac::vals::Tsel1::TIM15_TRGO,
57 Ch1Trigger::Tim2 => dac::vals::Tsel1::TIM2_TRGO,
58 Ch1Trigger::Exti9 => dac::vals::Tsel1::EXTI9,
59 Ch1Trigger::Software => dac::vals::Tsel1::SOFTWARE,
60 }
61 }
62}
63
64#[derive(Debug, Copy, Clone, Eq, PartialEq)]
65#[cfg_attr(feature = "defmt", derive(defmt::Format))]
66/// Trigger sources for CH2
67pub enum Ch2Trigger {
68 Tim6,
69 Tim8,
70 Tim7,
71 Tim5,
72 Tim2,
73 Tim4,
74 Exti9,
75 Software,
76}
77
78impl Ch2Trigger {
79 fn tsel(&self) -> dac::vals::Tsel2 {
80 match self {
81 Ch2Trigger::Tim6 => dac::vals::Tsel2::TIM6_TRGO,
82 Ch2Trigger::Tim8 => dac::vals::Tsel2::TIM8_TRGO,
83 Ch2Trigger::Tim7 => dac::vals::Tsel2::TIM7_TRGO,
84 Ch2Trigger::Tim5 => dac::vals::Tsel2::TIM5_TRGO,
85 Ch2Trigger::Tim2 => dac::vals::Tsel2::TIM2_TRGO,
86 Ch2Trigger::Tim4 => dac::vals::Tsel2::TIM4_TRGO,
87 Ch2Trigger::Exti9 => dac::vals::Tsel2::EXTI9,
88 Ch2Trigger::Software => dac::vals::Tsel2::SOFTWARE,
89 }
90 }
91}
92
93#[derive(Debug, Copy, Clone, Eq, PartialEq)]
94#[cfg_attr(feature = "defmt", derive(defmt::Format))]
95/// Single 8 or 12 bit value that can be output by the DAC
96pub enum Value {
97 // 8 bit value
98 Bit8(u8),
99 // 12 bit value stored in a u16, left-aligned
100 Bit12Left(u16),
101 // 12 bit value stored in a u16, right-aligned
102 Bit12Right(u16),
103}
104
105#[derive(Debug, Copy, Clone, Eq, PartialEq)]
106#[cfg_attr(feature = "defmt", derive(defmt::Format))]
107/// Array variant of [`Value`]
108pub enum ValueArray<'a> {
109 // 8 bit values
110 Bit8(&'a [u8]),
111 // 12 bit value stored in a u16, left-aligned
112 Bit12Left(&'a [u16]),
113 // 12 bit values stored in a u16, right-aligned
114 Bit12Right(&'a [u16]),
115}
116/// Provide common functions for DAC channels
117pub trait DacChannel<T: Instance, Tx> {
118 const CHANNEL: Channel;
119
120 /// Enable trigger of the given channel
121 fn set_trigger_enable(&mut self, on: bool) -> Result<(), Error> {
122 T::regs().cr().modify(|reg| {
123 reg.set_ten(Self::CHANNEL.index(), on);
124 });
125 Ok(())
126 }
127
128 /// Set mode register of the given channel
129 #[cfg(dac_v2)]
130 fn set_channel_mode(&mut self, val: u8) -> Result<(), Error> {
131 T::regs().mcr().modify(|reg| {
132 reg.set_mode(Self::CHANNEL.index(), val);
133 });
134 Ok(())
135 }
136
137 /// Set enable register of the given channel
138 fn set_channel_enable(&mut self, on: bool) -> Result<(), Error> {
139 T::regs().cr().modify(|reg| {
140 reg.set_en(Self::CHANNEL.index(), on);
141 });
142 Ok(())
143 }
144
145 /// Enable the DAC channel `ch`
146 fn enable_channel(&mut self) -> Result<(), Error> {
147 self.set_channel_enable(true)
148 }
149
150 /// Disable the DAC channel `ch`
151 fn disable_channel(&mut self) -> Result<(), Error> {
152 self.set_channel_enable(false)
153 }
154
155 /// Perform a software trigger on `ch`
156 fn trigger(&mut self) {
157 T::regs().swtrigr().write(|reg| {
158 reg.set_swtrig(Self::CHANNEL.index(), true);
159 });
160 }
161
162 /// Set a value to be output by the DAC on trigger.
163 ///
164 /// The `value` is written to the corresponding "data holding register".
165 fn set(&mut self, value: Value) -> Result<(), Error> {
166 match value {
167 Value::Bit8(v) => T::regs().dhr8r(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
168 Value::Bit12Left(v) => T::regs().dhr12l(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
169 Value::Bit12Right(v) => T::regs().dhr12r(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
170 }
171 Ok(())
172 }
173}
174
175/// Hold two DAC channels
176///
177/// Note: This consumes the DAC `Instance` only once, allowing to get both channels simultaneously.
178///
179/// # Example for obtaining both DAC channels
180///
181/// ```ignore
182/// // DMA channels and pins may need to be changed for your controller
183/// let (dac_ch1, dac_ch2) =
184/// embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split();
185/// ```
186pub struct Dac<'d, T: Instance, TxCh1, TxCh2> {
187 ch1: DacCh1<'d, T, TxCh1>,
188 ch2: DacCh2<'d, T, TxCh2>,
189}
190
191/// DAC CH1
192///
193/// Note: This consumes the DAC `Instance`. Use [`Dac::new`] to get both channels simultaneously.
194pub struct DacCh1<'d, T: Instance, Tx> {
195 /// To consume T
196 _peri: PeripheralRef<'d, T>,
197 #[allow(unused)] // For chips whose DMA is not (yet) supported
198 dma: PeripheralRef<'d, Tx>,
199}
200
201/// DAC CH2
202///
203/// Note: This consumes the DAC `Instance`. Use [`Dac::new`] to get both channels simultaneously.
204pub struct DacCh2<'d, T: Instance, Tx> {
205 /// Instead of PeripheralRef to consume T
206 phantom: PhantomData<&'d mut T>,
207 #[allow(unused)] // For chips whose DMA is not (yet) supported
208 dma: PeripheralRef<'d, Tx>,
209}
210
211impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
212 /// Obtain DAC CH1
213 pub fn new(
214 peri: impl Peripheral<P = T> + 'd,
215 dma: impl Peripheral<P = Tx> + 'd,
216 _pin: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
217 ) -> Self {
218 into_ref!(peri, dma);
219 T::enable();
220 T::reset();
221
222 let mut dac = Self { _peri: peri, dma };
223
224 // Configure each activated channel. All results can be `unwrap`ed since they
225 // will only error if the channel is not configured (i.e. ch1, ch2 are false)
226 #[cfg(dac_v2)]
227 dac.set_channel_mode(0).unwrap();
228 dac.enable_channel().unwrap();
229 dac.set_trigger_enable(true).unwrap();
230
231 dac
232 }
233
234 /// Select a new trigger for this channel
235 ///
236 /// **Important**: This disables the channel!
237 pub fn select_trigger(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
238 unwrap!(self.disable_channel());
239 T::regs().cr().modify(|reg| {
240 reg.set_tsel1(trigger.tsel());
241 });
242 Ok(())
243 }
244
245 /// Write `data` to the DAC CH1 via DMA.
246 ///
247 /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
248 /// This will configure a circular DMA transfer that periodically outputs the `data`.
249 /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
250 ///
251 /// **Important:** Channel 1 has to be configured for the DAC instance!
252 #[cfg(all(bdma, not(dma)))] // It currently only works with BDMA-only chips (DMA should theoretically work though)
253 pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
254 where
255 Tx: DmaCh1<T>,
256 {
257 let channel = Channel::Ch1.index();
258 debug!("Writing to channel {}", channel);
259
260 // Enable DAC and DMA
261 T::regs().cr().modify(|w| {
262 w.set_en(channel, true);
263 w.set_dmaen(channel, true);
264 });
265
266 let tx_request = self.dma.request();
267 let dma_channel = &self.dma;
268
269 let tx_options = crate::dma::TransferOptions {
270 circular,
271 half_transfer_ir: false,
272 complete_transfer_ir: !circular,
273 ..Default::default()
274 };
275
276 // Initiate the correct type of DMA transfer depending on what data is passed
277 let tx_f = match data {
278 ValueArray::Bit8(buf) => unsafe {
279 crate::dma::Transfer::new_write(
280 dma_channel,
281 tx_request,
282 buf,
283 T::regs().dhr8r(channel).as_ptr() as *mut u8,
284 tx_options,
285 )
286 },
287 ValueArray::Bit12Left(buf) => unsafe {
288 crate::dma::Transfer::new_write(
289 dma_channel,
290 tx_request,
291 buf,
292 T::regs().dhr12l(channel).as_ptr() as *mut u16,
293 tx_options,
294 )
295 },
296 ValueArray::Bit12Right(buf) => unsafe {
297 crate::dma::Transfer::new_write(
298 dma_channel,
299 tx_request,
300 buf,
301 T::regs().dhr12r(channel).as_ptr() as *mut u16,
302 tx_options,
303 )
304 },
305 };
306
307 tx_f.await;
308
309 // finish dma
310 // TODO: Do we need to check any status registers here?
311 T::regs().cr().modify(|w| {
312 // Disable the DAC peripheral
313 w.set_en(channel, false);
314 // Disable the DMA. TODO: Is this necessary?
315 w.set_dmaen(channel, false);
316 });
317
318 Ok(())
319 }
320}
321
322impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
323 /// Obtain DAC CH2
324 pub fn new(
325 _peri: impl Peripheral<P = T> + 'd,
326 dma: impl Peripheral<P = Tx> + 'd,
327 _pin: impl Peripheral<P = impl DacPin<T, 2>> + 'd,
328 ) -> Self {
329 into_ref!(_peri, dma);
330 T::enable();
331 T::reset();
332
333 let mut dac = Self {
334 phantom: PhantomData,
335 dma,
336 };
337
338 // Configure each activated channel. All results can be `unwrap`ed since they
339 // will only error if the channel is not configured (i.e. ch1, ch2 are false)
340 #[cfg(dac_v2)]
341 dac.set_channel_mode(0).unwrap();
342 dac.enable_channel().unwrap();
343 dac.set_trigger_enable(true).unwrap();
344
345 dac
346 }
347
348 /// Select a new trigger for this channel
349 pub fn select_trigger(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
350 unwrap!(self.disable_channel());
351 T::regs().cr().modify(|reg| {
352 reg.set_tsel2(trigger.tsel());
353 });
354 Ok(())
355 }
356
357 /// Write `data` to the DAC CH2 via DMA.
358 ///
359 /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
360 /// This will configure a circular DMA transfer that periodically outputs the `data`.
361 /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
362 ///
363 /// **Important:** Channel 2 has to be configured for the DAC instance!
364 #[cfg(all(bdma, not(dma)))] // It currently only works with BDMA-only chips (DMA should theoretically work though)
365 pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
366 where
367 Tx: DmaCh2<T>,
368 {
369 let channel = Channel::Ch2.index();
370 debug!("Writing to channel {}", channel);
371
372 // Enable DAC and DMA
373 T::regs().cr().modify(|w| {
374 w.set_en(channel, true);
375 w.set_dmaen(channel, true);
376 });
377
378 let tx_request = self.dma.request();
379 let dma_channel = &self.dma;
380
381 let tx_options = crate::dma::TransferOptions {
382 circular,
383 half_transfer_ir: false,
384 complete_transfer_ir: !circular,
385 ..Default::default()
386 };
387
388 // Initiate the correct type of DMA transfer depending on what data is passed
389 let tx_f = match data {
390 ValueArray::Bit8(buf) => unsafe {
391 crate::dma::Transfer::new_write(
392 dma_channel,
393 tx_request,
394 buf,
395 T::regs().dhr8r(channel).as_ptr() as *mut u8,
396 tx_options,
397 )
398 },
399 ValueArray::Bit12Left(buf) => unsafe {
400 crate::dma::Transfer::new_write(
401 dma_channel,
402 tx_request,
403 buf,
404 T::regs().dhr12l(channel).as_ptr() as *mut u16,
405 tx_options,
406 )
407 },
408 ValueArray::Bit12Right(buf) => unsafe {
409 crate::dma::Transfer::new_write(
410 dma_channel,
411 tx_request,
412 buf,
413 T::regs().dhr12r(channel).as_ptr() as *mut u16,
414 tx_options,
415 )
416 },
417 };
418
419 tx_f.await;
420
421 // finish dma
422 // TODO: Do we need to check any status registers here?
423 T::regs().cr().modify(|w| {
424 // Disable the DAC peripheral
425 w.set_en(channel, false);
426 // Disable the DMA. TODO: Is this necessary?
427 w.set_dmaen(channel, false);
428 });
429
430 Ok(())
431 }
432}
433
434impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> {
435 /// Create a new DAC instance with both channels.
436 ///
437 /// This is used to obtain two independent channels via `split()` for use e.g. with DMA.
438 pub fn new(
439 peri: impl Peripheral<P = T> + 'd,
440 dma_ch1: impl Peripheral<P = TxCh1> + 'd,
441 dma_ch2: impl Peripheral<P = TxCh2> + 'd,
442 _pin_ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
443 _pin_ch2: impl Peripheral<P = impl DacPin<T, 2>> + 'd,
444 ) -> Self {
445 into_ref!(peri, dma_ch1, dma_ch2);
446 T::enable();
447 T::reset();
448
449 let mut dac_ch1 = DacCh1 {
450 _peri: peri,
451 dma: dma_ch1,
452 };
453
454 let mut dac_ch2 = DacCh2 {
455 phantom: PhantomData,
456 dma: dma_ch2,
457 };
458
459 // Configure each activated channel. All results can be `unwrap`ed since they
460 // will only error if the channel is not configured (i.e. ch1, ch2 are false)
461 #[cfg(dac_v2)]
462 dac_ch1.set_channel_mode(0).unwrap();
463 dac_ch1.enable_channel().unwrap();
464 dac_ch1.set_trigger_enable(true).unwrap();
465
466 #[cfg(dac_v2)]
467 dac_ch2.set_channel_mode(0).unwrap();
468 dac_ch2.enable_channel().unwrap();
469 dac_ch2.set_trigger_enable(true).unwrap();
470
471 Self {
472 ch1: dac_ch1,
473 ch2: dac_ch2,
474 }
475 }
476
477 /// Split the DAC into CH1 and CH2 for independent use.
478 pub fn split(self) -> (DacCh1<'d, T, TxCh1>, DacCh2<'d, T, TxCh2>) {
479 (self.ch1, self.ch2)
480 }
481
482 /// Get mutable reference to CH1
483 pub fn ch1_mut(&mut self) -> &mut DacCh1<'d, T, TxCh1> {
484 &mut self.ch1
485 }
486
487 /// Get mutable reference to CH2
488 pub fn ch2_mut(&mut self) -> &mut DacCh2<'d, T, TxCh2> {
489 &mut self.ch2
490 }
491
492 /// Get reference to CH1
493 pub fn ch1(&mut self) -> &DacCh1<'d, T, TxCh1> {
494 &self.ch1
495 }
496
497 /// Get reference to CH2
498 pub fn ch2(&mut self) -> &DacCh2<'d, T, TxCh2> {
499 &self.ch2
500 }
501}
502
503impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh1<'d, T, Tx> {
504 const CHANNEL: Channel = Channel::Ch1;
505}
506
507impl<'d, T: Instance, Tx> DacChannel<T, Tx> for DacCh2<'d, T, Tx> {
508 const CHANNEL: Channel = Channel::Ch2;
509}
510
511pub(crate) mod sealed {
512 pub trait Instance {
513 fn regs() -> &'static crate::pac::dac::Dac;
514 }
515}
516
517pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
518dma_trait!(DmaCh1, Instance);
519dma_trait!(DmaCh2, Instance);
520
521/// Marks a pin that can be used with the DAC
522pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
523
524foreach_peripheral!(
525 (dac, $inst:ident) => {
526 // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
527 #[cfg(rcc_h7)]
528 impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
529 fn frequency() -> crate::time::Hertz {
530 critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 })
531 }
532
533 fn reset() {
534 critical_section::with(|_| {
535 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
536 crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
537 })
538 }
539
540 fn enable() {
541 critical_section::with(|_| {
542 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
543 })
544 }
545
546 fn disable() {
547 critical_section::with(|_| {
548 crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false))
549 })
550 }
551 }
552
553 #[cfg(rcc_h7)]
554 impl crate::rcc::RccPeripheral for peripherals::$inst {}
555
556 impl crate::dac::sealed::Instance for peripherals::$inst {
557 fn regs() -> &'static crate::pac::dac::Dac {
558 &crate::pac::$inst
559 }
560 }
561
562 impl crate::dac::Instance for peripherals::$inst {}
563 };
564);
565
566macro_rules! impl_dac_pin {
567 ($inst:ident, $pin:ident, $ch:expr) => {
568 impl crate::dac::DacPin<peripherals::$inst, $ch> for crate::peripherals::$pin {}
569 };
570}
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index a307c803c..5a87888b7 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -21,11 +21,22 @@ use crate::pac::bdma::{regs, vals};
21#[derive(Debug, Copy, Clone, PartialEq, Eq)] 21#[derive(Debug, Copy, Clone, PartialEq, Eq)]
22#[cfg_attr(feature = "defmt", derive(defmt::Format))] 22#[cfg_attr(feature = "defmt", derive(defmt::Format))]
23#[non_exhaustive] 23#[non_exhaustive]
24pub struct TransferOptions {} 24pub struct TransferOptions {
25 /// Enable circular DMA
26 pub circular: bool,
27 /// Enable half transfer interrupt
28 pub half_transfer_ir: bool,
29 /// Enable transfer complete interrupt
30 pub complete_transfer_ir: bool,
31}
25 32
26impl Default for TransferOptions { 33impl Default for TransferOptions {
27 fn default() -> Self { 34 fn default() -> Self {
28 Self {} 35 Self {
36 circular: false,
37 half_transfer_ir: false,
38 complete_transfer_ir: true,
39 }
29 } 40 }
30} 41}
31 42
@@ -253,7 +264,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
253 mem_len: usize, 264 mem_len: usize,
254 incr_mem: bool, 265 incr_mem: bool,
255 data_size: WordSize, 266 data_size: WordSize,
256 _options: TransferOptions, 267 options: TransferOptions,
257 ) -> Self { 268 ) -> Self {
258 let ch = channel.regs().ch(channel.num()); 269 let ch = channel.regs().ch(channel.num());
259 270
@@ -283,7 +294,15 @@ impl<'a, C: Channel> Transfer<'a, C> {
283 } 294 }
284 w.set_dir(dir.into()); 295 w.set_dir(dir.into());
285 w.set_teie(true); 296 w.set_teie(true);
286 w.set_tcie(true); 297 w.set_tcie(options.complete_transfer_ir);
298 w.set_htie(options.half_transfer_ir);
299 if options.circular {
300 w.set_circ(vals::Circ::ENABLED);
301 debug!("Setting circular mode");
302 } else {
303 w.set_circ(vals::Circ::DISABLED);
304 }
305 w.set_pl(vals::Pl::VERYHIGH);
287 w.set_en(true); 306 w.set_en(true);
288 }); 307 });
289 308
@@ -310,8 +329,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
310 pub fn is_running(&mut self) -> bool { 329 pub fn is_running(&mut self) -> bool {
311 let ch = self.channel.regs().ch(self.channel.num()); 330 let ch = self.channel.regs().ch(self.channel.num());
312 let en = ch.cr().read().en(); 331 let en = ch.cr().read().en();
332 let circular = ch.cr().read().circ() == vals::Circ::ENABLED;
313 let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; 333 let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0;
314 en && !tcif 334 en && (circular || !tcif)
315 } 335 }
316 336
317 /// Gets the total remaining transfers for the channel 337 /// Gets the total remaining transfers for the channel
@@ -477,6 +497,8 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
477 let ch = self.channel.regs().ch(self.channel.num()); 497 let ch = self.channel.regs().ch(self.channel.num());
478 498
479 // Disable the channel. Keep the IEs enabled so the irqs still fire. 499 // Disable the channel. Keep the IEs enabled so the irqs still fire.
500 // If the channel is enabled and transfer is not completed, we need to perform
501 // two separate write access to the CR register to disable the channel.
480 ch.cr().write(|w| { 502 ch.cr().write(|w| {
481 w.set_teie(true); 503 w.set_teie(true);
482 w.set_htie(true); 504 w.set_htie(true);
diff --git a/embassy-stm32/src/eth/v1/rx_desc.rs b/embassy-stm32/src/eth/v1/rx_desc.rs
index 01a073bb9..668378bea 100644
--- a/embassy-stm32/src/eth/v1/rx_desc.rs
+++ b/embassy-stm32/src/eth/v1/rx_desc.rs
@@ -174,7 +174,7 @@ impl<'a> RDesRing<'a> {
174 // Receive descriptor unavailable 174 // Receive descriptor unavailable
175 Rps::SUSPENDED => RunningState::Stopped, 175 Rps::SUSPENDED => RunningState::Stopped,
176 // Closing receive descriptor 176 // Closing receive descriptor
177 Rps(0b101) => RunningState::Running, 177 Rps::_RESERVED_5 => RunningState::Running,
178 // Transferring the receive packet data from receive buffer to host memory 178 // Transferring the receive packet data from receive buffer to host memory
179 Rps::RUNNINGWRITING => RunningState::Running, 179 Rps::RUNNINGWRITING => RunningState::Running,
180 _ => RunningState::Unknown, 180 _ => RunningState::Unknown,
diff --git a/embassy-stm32/src/pwm/complementary_pwm.rs b/embassy-stm32/src/pwm/complementary_pwm.rs
index 0e153202e..4d64d005c 100644
--- a/embassy-stm32/src/pwm/complementary_pwm.rs
+++ b/embassy-stm32/src/pwm/complementary_pwm.rs
@@ -243,7 +243,7 @@ mod tests {
243 for test_run in fn_results { 243 for test_run in fn_results {
244 let (ckd, bits) = compute_dead_time_value(test_run.value); 244 let (ckd, bits) = compute_dead_time_value(test_run.value);
245 245
246 assert_eq!(ckd.0, test_run.ckd.0); 246 assert_eq!(ckd.to_bits(), test_run.ckd.to_bits());
247 assert_eq!(bits, test_run.bits); 247 assert_eq!(bits, test_run.bits);
248 } 248 }
249 } 249 }
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index 6c7b36647..df6e9047c 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -126,7 +126,7 @@ pub(crate) unsafe fn init(config: Config) {
126 }); 126 });
127 while !RCC.cr().read().hsirdy() {} 127 while !RCC.cr().read().hsirdy() {}
128 128
129 (HSI_FREQ.0 >> div.0, Sw::HSI) 129 (HSI_FREQ.0 >> div.to_bits(), Sw::HSI)
130 } 130 }
131 ClockSrc::HSE(freq) => { 131 ClockSrc::HSE(freq) => {
132 // Enable HSE 132 // Enable HSE
@@ -157,7 +157,7 @@ pub(crate) unsafe fn init(config: Config) {
157 let mut set_flash_latency_after = false; 157 let mut set_flash_latency_after = false;
158 FLASH.acr().modify(|w| { 158 FLASH.acr().modify(|w| {
159 // Is the current flash latency less than what we need at the new SYSCLK? 159 // Is the current flash latency less than what we need at the new SYSCLK?
160 if w.latency().0 <= target_flash_latency.0 { 160 if w.latency().to_bits() <= target_flash_latency.to_bits() {
161 // We must increase the number of wait states now 161 // We must increase the number of wait states now
162 w.set_latency(target_flash_latency) 162 w.set_latency(target_flash_latency)
163 } else { 163 } else {
@@ -171,12 +171,12 @@ pub(crate) unsafe fn init(config: Config) {
171 // > Flash memory. 171 // > Flash memory.
172 // 172 //
173 // Enable flash prefetching if we have at least one wait state, and disable it otherwise. 173 // Enable flash prefetching if we have at least one wait state, and disable it otherwise.
174 w.set_prften(target_flash_latency.0 > 0); 174 w.set_prften(target_flash_latency.to_bits() > 0);
175 }); 175 });
176 176
177 if !set_flash_latency_after { 177 if !set_flash_latency_after {
178 // Spin until the effective flash latency is compatible with the clock change 178 // Spin until the effective flash latency is compatible with the clock change
179 while FLASH.acr().read().latency().0 < target_flash_latency.0 {} 179 while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {}
180 } 180 }
181 181
182 // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once 182 // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
@@ -218,7 +218,7 @@ pub(crate) unsafe fn init(config: Config) {
218 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 218 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
219 pre => { 219 pre => {
220 let pre: Ppre = pre.into(); 220 let pre: Ppre = pre.into();
221 let pre: u8 = 1 << (pre.0 - 3); 221 let pre: u8 = 1 << (pre.to_bits() - 3);
222 let freq = ahb_freq / pre as u32; 222 let freq = ahb_freq / pre as u32;
223 (freq, freq * 2) 223 (freq, freq * 2)
224 } 224 }
diff --git a/embassy-stm32/src/rcc/f0.rs b/embassy-stm32/src/rcc/f0.rs
index eb62ab661..ca6eed284 100644
--- a/embassy-stm32/src/rcc/f0.rs
+++ b/embassy-stm32/src/rcc/f0.rs
@@ -1,3 +1,5 @@
1use stm32_metapac::flash::vals::Latency;
2
1use super::{set_freqs, Clocks}; 3use super::{set_freqs, Clocks};
2use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Sw, Usbsw}; 4use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Sw, Usbsw};
3use crate::pac::{FLASH, RCC}; 5use crate::pac::{FLASH, RCC};
@@ -85,14 +87,11 @@ pub(crate) unsafe fn init(config: Config) {
85 let timer_mul = if ppre == 1 { 1 } else { 2 }; 87 let timer_mul = if ppre == 1 { 1 } else { 2 };
86 88
87 FLASH.acr().write(|w| { 89 FLASH.acr().write(|w| {
88 let latency = if real_sysclk <= 24_000_000 { 90 w.set_latency(if real_sysclk <= 24_000_000 {
89 0 91 Latency::WS0
90 } else if real_sysclk <= 48_000_000 {
91 1
92 } else { 92 } else {
93 2 93 Latency::WS1
94 }; 94 });
95 w.latency().0 = latency;
96 }); 95 });
97 96
98 match (config.hse.is_some(), use_hsi48) { 97 match (config.hse.is_some(), use_hsi48) {
@@ -134,20 +133,20 @@ pub(crate) unsafe fn init(config: Config) {
134 // TODO: Option to use CRS (Clock Recovery) 133 // TODO: Option to use CRS (Clock Recovery)
135 134
136 if let Some(pllmul_bits) = pllmul_bits { 135 if let Some(pllmul_bits) = pllmul_bits {
137 RCC.cfgr().modify(|w| w.set_pllmul(Pllmul(pllmul_bits))); 136 RCC.cfgr().modify(|w| w.set_pllmul(Pllmul::from_bits(pllmul_bits)));
138 137
139 RCC.cr().modify(|w| w.set_pllon(true)); 138 RCC.cr().modify(|w| w.set_pllon(true));
140 while !RCC.cr().read().pllrdy() {} 139 while !RCC.cr().read().pllrdy() {}
141 140
142 RCC.cfgr().modify(|w| { 141 RCC.cfgr().modify(|w| {
143 w.set_ppre(Ppre(ppre_bits)); 142 w.set_ppre(Ppre::from_bits(ppre_bits));
144 w.set_hpre(Hpre(hpre_bits)); 143 w.set_hpre(Hpre::from_bits(hpre_bits));
145 w.set_sw(Sw::PLL) 144 w.set_sw(Sw::PLL)
146 }); 145 });
147 } else { 146 } else {
148 RCC.cfgr().modify(|w| { 147 RCC.cfgr().modify(|w| {
149 w.set_ppre(Ppre(ppre_bits)); 148 w.set_ppre(Ppre::from_bits(ppre_bits));
150 w.set_hpre(Hpre(hpre_bits)); 149 w.set_hpre(Hpre::from_bits(hpre_bits));
151 150
152 if config.hse.is_some() { 151 if config.hse.is_some() {
153 w.set_sw(Sw::HSE); 152 w.set_sw(Sw::HSE);
diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs
index 4769b7059..b6200231e 100644
--- a/embassy-stm32/src/rcc/f1.rs
+++ b/embassy-stm32/src/rcc/f1.rs
@@ -106,11 +106,11 @@ pub(crate) unsafe fn init(config: Config) {
106 // Only needed for stm32f103? 106 // Only needed for stm32f103?
107 FLASH.acr().write(|w| { 107 FLASH.acr().write(|w| {
108 w.set_latency(if real_sysclk <= 24_000_000 { 108 w.set_latency(if real_sysclk <= 24_000_000 {
109 Latency(0b000) 109 Latency::WS0
110 } else if real_sysclk <= 48_000_000 { 110 } else if real_sysclk <= 48_000_000 {
111 Latency(0b001) 111 Latency::WS1
112 } else { 112 } else {
113 Latency(0b010) 113 Latency::WS2
114 }); 114 });
115 }); 115 });
116 116
@@ -147,12 +147,13 @@ pub(crate) unsafe fn init(config: Config) {
147 147
148 if let Some(pllmul_bits) = pllmul_bits { 148 if let Some(pllmul_bits) = pllmul_bits {
149 let pllctpre_flag: u8 = if config.pllxtpre { 1 } else { 0 }; 149 let pllctpre_flag: u8 = if config.pllxtpre { 1 } else { 0 };
150 RCC.cfgr().modify(|w| w.set_pllxtpre(Pllxtpre(pllctpre_flag))); 150 RCC.cfgr()
151 .modify(|w| w.set_pllxtpre(Pllxtpre::from_bits(pllctpre_flag)));
151 152
152 // enable PLL and wait for it to be ready 153 // enable PLL and wait for it to be ready
153 RCC.cfgr().modify(|w| { 154 RCC.cfgr().modify(|w| {
154 w.set_pllmul(Pllmul(pllmul_bits)); 155 w.set_pllmul(Pllmul::from_bits(pllmul_bits));
155 w.set_pllsrc(Pllsrc(config.hse.is_some() as u8)); 156 w.set_pllsrc(Pllsrc::from_bits(config.hse.is_some() as u8));
156 }); 157 });
157 158
158 RCC.cr().modify(|w| w.set_pllon(true)); 159 RCC.cr().modify(|w| w.set_pllon(true));
@@ -161,22 +162,19 @@ pub(crate) unsafe fn init(config: Config) {
161 162
162 // Only needed for stm32f103? 163 // Only needed for stm32f103?
163 RCC.cfgr().modify(|w| { 164 RCC.cfgr().modify(|w| {
164 w.set_adcpre(Adcpre(apre_bits)); 165 w.set_adcpre(Adcpre::from_bits(apre_bits));
165 w.set_ppre2(Ppre1(ppre2_bits)); 166 w.set_ppre2(Ppre1::from_bits(ppre2_bits));
166 w.set_ppre1(Ppre1(ppre1_bits)); 167 w.set_ppre1(Ppre1::from_bits(ppre1_bits));
167 w.set_hpre(Hpre(hpre_bits)); 168 w.set_hpre(Hpre::from_bits(hpre_bits));
168 #[cfg(not(rcc_f100))] 169 #[cfg(not(rcc_f100))]
169 w.set_usbpre(Usbpre(usbpre as u8)); 170 w.set_usbpre(Usbpre::from_bits(usbpre as u8));
170 w.set_sw(Sw(if pllmul_bits.is_some() { 171 w.set_sw(if pllmul_bits.is_some() {
171 // PLL 172 Sw::PLL
172 0b10
173 } else if config.hse.is_some() { 173 } else if config.hse.is_some() {
174 // HSE 174 Sw::HSE
175 0b1
176 } else { 175 } else {
177 // HSI 176 Sw::HSI
178 0b0 177 });
179 }));
180 }); 178 });
181 179
182 set_freqs(Clocks { 180 set_freqs(Clocks {
diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs
index bcae64d0f..1525cc3c3 100644
--- a/embassy-stm32/src/rcc/f2.rs
+++ b/embassy-stm32/src/rcc/f2.rs
@@ -485,7 +485,7 @@ pub(crate) unsafe fn init(config: Config) {
485 w.set_ppre1(config.apb1_pre.into()); 485 w.set_ppre1(config.apb1_pre.into());
486 w.set_ppre2(config.apb2_pre.into()); 486 w.set_ppre2(config.apb2_pre.into());
487 }); 487 });
488 while RCC.cfgr().read().sws() != sw.0 {} 488 while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
489 489
490 // Turn off HSI to save power if we don't need it 490 // Turn off HSI to save power if we don't need it
491 if !config.hsi { 491 if !config.hsi {
diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs
index bc430afb2..b84470440 100644
--- a/embassy-stm32/src/rcc/f4.rs
+++ b/embassy-stm32/src/rcc/f4.rs
@@ -87,7 +87,7 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Opti
87 87
88 let sysclk = pllsysclk.unwrap_or(pllsrcclk); 88 let sysclk = pllsysclk.unwrap_or(pllsrcclk);
89 if pllsysclk.is_none() && !pll48clk { 89 if pllsysclk.is_none() && !pll48clk {
90 RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8))); 90 RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)));
91 91
92 return PllResults { 92 return PllResults {
93 use_pll: false, 93 use_pll: false,
@@ -141,9 +141,9 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Opti
141 RCC.pllcfgr().modify(|w| { 141 RCC.pllcfgr().modify(|w| {
142 w.set_pllm(pllm as u8); 142 w.set_pllm(pllm as u8);
143 w.set_plln(plln as u16); 143 w.set_plln(plln as u16);
144 w.set_pllp(Pllp(pllp as u8)); 144 w.set_pllp(Pllp::from_bits(pllp as u8));
145 w.set_pllq(pllq as u8); 145 w.set_pllq(pllq as u8);
146 w.set_pllsrc(Pllsrc(use_hse as u8)); 146 w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
147 }); 147 });
148 148
149 let real_pllsysclk = vco_in * plln / sysclk_div; 149 let real_pllsysclk = vco_in * plln / sysclk_div;
@@ -323,7 +323,7 @@ fn flash_setup(sysclk: u32) {
323 critical_section::with(|_| { 323 critical_section::with(|_| {
324 FLASH 324 FLASH
325 .acr() 325 .acr()
326 .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); 326 .modify(|w| w.set_latency(Latency::from_bits(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
327 }); 327 });
328} 328}
329 329
@@ -440,8 +440,8 @@ pub(crate) unsafe fn init(config: Config) {
440 } 440 }
441 441
442 RCC.cfgr().modify(|w| { 442 RCC.cfgr().modify(|w| {
443 w.set_ppre2(Ppre(ppre2_bits)); 443 w.set_ppre2(Ppre::from_bits(ppre2_bits));
444 w.set_ppre1(Ppre(ppre1_bits)); 444 w.set_ppre1(Ppre::from_bits(ppre1_bits));
445 w.set_hpre(hpre_bits); 445 w.set_hpre(hpre_bits);
446 }); 446 });
447 447
diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs
index 71215cac5..85cb9c661 100644
--- a/embassy-stm32/src/rcc/f7.rs
+++ b/embassy-stm32/src/rcc/f7.rs
@@ -30,7 +30,7 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bo
30 30
31 let sysclk = pllsysclk.unwrap_or(pllsrcclk); 31 let sysclk = pllsysclk.unwrap_or(pllsrcclk);
32 if pllsysclk.is_none() && !pll48clk { 32 if pllsysclk.is_none() && !pll48clk {
33 RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8))); 33 RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)));
34 34
35 return PllResults { 35 return PllResults {
36 use_pll: false, 36 use_pll: false,
@@ -83,9 +83,9 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bo
83 RCC.pllcfgr().modify(|w| { 83 RCC.pllcfgr().modify(|w| {
84 w.set_pllm(pllm as u8); 84 w.set_pllm(pllm as u8);
85 w.set_plln(plln as u16); 85 w.set_plln(plln as u16);
86 w.set_pllp(Pllp(pllp as u8)); 86 w.set_pllp(Pllp::from_bits(pllp as u8));
87 w.set_pllq(pllq as u8); 87 w.set_pllq(pllq as u8);
88 w.set_pllsrc(Pllsrc(use_hse as u8)); 88 w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
89 }); 89 });
90 90
91 let real_pllsysclk = vco_in * plln / sysclk_div; 91 let real_pllsysclk = vco_in * plln / sysclk_div;
@@ -106,7 +106,7 @@ fn flash_setup(sysclk: u32) {
106 critical_section::with(|_| { 106 critical_section::with(|_| {
107 FLASH 107 FLASH
108 .acr() 108 .acr()
109 .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); 109 .modify(|w| w.set_latency(Latency::from_bits(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
110 }); 110 });
111} 111}
112 112
@@ -246,8 +246,8 @@ pub(crate) unsafe fn init(config: Config) {
246 } 246 }
247 247
248 RCC.cfgr().modify(|w| { 248 RCC.cfgr().modify(|w| {
249 w.set_ppre2(Ppre(ppre2_bits)); 249 w.set_ppre2(Ppre::from_bits(ppre2_bits));
250 w.set_ppre1(Ppre(ppre1_bits)); 250 w.set_ppre1(Ppre::from_bits(ppre1_bits));
251 w.set_hpre(hpre_bits); 251 w.set_hpre(hpre_bits);
252 }); 252 });
253 253
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index 17c73c36b..5e3a7911a 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -344,7 +344,7 @@ pub(crate) unsafe fn init(config: Config) {
344 }); 344 });
345 while !RCC.cr().read().hsirdy() {} 345 while !RCC.cr().read().hsirdy() {}
346 346
347 (HSI_FREQ.0 >> div.0, Sw::HSI) 347 (HSI_FREQ.0 >> div.to_bits(), Sw::HSI)
348 } 348 }
349 ClockSrc::HSE(freq) => { 349 ClockSrc::HSE(freq) => {
350 // Enable HSE 350 // Enable HSE
@@ -381,7 +381,7 @@ pub(crate) unsafe fn init(config: Config) {
381 let mut set_flash_latency_after = false; 381 let mut set_flash_latency_after = false;
382 FLASH.acr().modify(|w| { 382 FLASH.acr().modify(|w| {
383 // Is the current flash latency less than what we need at the new SYSCLK? 383 // Is the current flash latency less than what we need at the new SYSCLK?
384 if w.latency().0 <= target_flash_latency.0 { 384 if w.latency().to_bits() <= target_flash_latency.to_bits() {
385 // We must increase the number of wait states now 385 // We must increase the number of wait states now
386 w.set_latency(target_flash_latency) 386 w.set_latency(target_flash_latency)
387 } else { 387 } else {
@@ -395,12 +395,12 @@ pub(crate) unsafe fn init(config: Config) {
395 // > Flash memory. 395 // > Flash memory.
396 // 396 //
397 // Enable flash prefetching if we have at least one wait state, and disable it otherwise. 397 // Enable flash prefetching if we have at least one wait state, and disable it otherwise.
398 w.set_prften(target_flash_latency.0 > 0); 398 w.set_prften(target_flash_latency.to_bits() > 0);
399 }); 399 });
400 400
401 if !set_flash_latency_after { 401 if !set_flash_latency_after {
402 // Spin until the effective flash latency is compatible with the clock change 402 // Spin until the effective flash latency is compatible with the clock change
403 while FLASH.acr().read().latency().0 < target_flash_latency.0 {} 403 while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {}
404 } 404 }
405 405
406 // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once 406 // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
@@ -442,7 +442,7 @@ pub(crate) unsafe fn init(config: Config) {
442 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 442 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
443 pre => { 443 pre => {
444 let pre: Ppre = pre.into(); 444 let pre: Ppre = pre.into();
445 let pre: u8 = 1 << (pre.0 - 3); 445 let pre: u8 = 1 << (pre.to_bits() - 3);
446 let freq = ahb_freq / pre as u32; 446 let freq = ahb_freq / pre as u32;
447 (freq, freq * 2) 447 (freq, freq * 2)
448 } 448 }
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index 9401af4c3..ff8f97541 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -3,6 +3,7 @@ use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw};
3use stm32_metapac::FLASH; 3use stm32_metapac::FLASH;
4 4
5use crate::pac::{PWR, RCC}; 5use crate::pac::{PWR, RCC};
6use crate::rcc::sealed::RccPeripheral;
6use crate::rcc::{set_freqs, Clocks}; 7use crate::rcc::{set_freqs, Clocks};
7use crate::time::Hertz; 8use crate::time::Hertz;
8 9
@@ -316,6 +317,27 @@ impl Into<Hpre> for AHBPrescaler {
316 } 317 }
317} 318}
318 319
320/// Sets the source for the 48MHz clock to the USB and RNG peripherals.
321pub enum Clock48MhzSrc {
322 /// Use the High Speed Internal Oscillator. For USB usage, the CRS must be used to calibrate the
323 /// oscillator to comply with the USB specification for oscillator tolerance.
324 Hsi48(Option<CrsConfig>),
325 /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. For USB usage the
326 /// PLL needs to be using the HSE source to comply with the USB specification for oscillator
327 /// tolerance.
328 PllQ,
329}
330
331/// Sets the sync source for the Clock Recovery System (CRS).
332pub enum CrsSyncSource {
333 /// Use an external GPIO to sync the CRS.
334 Gpio,
335 /// Use the Low Speed External oscillator to sync the CRS.
336 Lse,
337 /// Use the USB SOF to sync the CRS.
338 Usb,
339}
340
319/// Clocks configutation 341/// Clocks configutation
320pub struct Config { 342pub struct Config {
321 pub mux: ClockSrc, 343 pub mux: ClockSrc,
@@ -326,6 +348,14 @@ pub struct Config {
326 /// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration 348 /// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration
327 /// MUST turn on the PLLR output. 349 /// MUST turn on the PLLR output.
328 pub pll: Option<Pll>, 350 pub pll: Option<Pll>,
351 /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals.
352 pub clock_48mhz_src: Option<Clock48MhzSrc>,
353}
354
355/// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator.
356pub struct CrsConfig {
357 /// Sync source for the CRS.
358 pub sync_src: CrsSyncSource,
329} 359}
330 360
331impl Default for Config { 361impl Default for Config {
@@ -338,6 +368,7 @@ impl Default for Config {
338 apb2_pre: APBPrescaler::NotDivided, 368 apb2_pre: APBPrescaler::NotDivided,
339 low_power_run: false, 369 low_power_run: false,
340 pll: None, 370 pll: None,
371 clock_48mhz_src: None,
341 } 372 }
342 } 373 }
343} 374}
@@ -430,7 +461,7 @@ pub(crate) unsafe fn init(config: Config) {
430 assert!(pll_freq.is_some()); 461 assert!(pll_freq.is_some());
431 assert!(pll_freq.as_ref().unwrap().pll_r.is_some()); 462 assert!(pll_freq.as_ref().unwrap().pll_r.is_some());
432 463
433 let freq = pll_freq.unwrap().pll_r.unwrap().0; 464 let freq = pll_freq.as_ref().unwrap().pll_r.unwrap().0;
434 465
435 assert!(freq <= 170_000_000); 466 assert!(freq <= 170_000_000);
436 467
@@ -497,6 +528,50 @@ pub(crate) unsafe fn init(config: Config) {
497 } 528 }
498 }; 529 };
499 530
531 // Setup the 48 MHz clock if needed
532 if let Some(clock_48mhz_src) = config.clock_48mhz_src {
533 let source = match clock_48mhz_src {
534 Clock48MhzSrc::PllQ => {
535 // Make sure the PLLQ is enabled and running at 48Mhz
536 let pllq_freq = pll_freq.as_ref().and_then(|f| f.pll_q);
537 assert!(pllq_freq.is_some() && pllq_freq.unwrap().0 == 48_000_000);
538
539 crate::pac::rcc::vals::Clk48sel::PLLQCLK
540 }
541 Clock48MhzSrc::Hsi48(crs_config) => {
542 // Enable HSI48
543 RCC.crrcr().modify(|w| w.set_hsi48on(true));
544 // Wait for HSI48 to turn on
545 while RCC.crrcr().read().hsi48rdy() == false {}
546
547 // Enable and setup CRS if needed
548 if let Some(crs_config) = crs_config {
549 crate::peripherals::CRS::enable();
550
551 let sync_src = match crs_config.sync_src {
552 CrsSyncSource::Gpio => crate::pac::crs::vals::Syncsrc::GPIO,
553 CrsSyncSource::Lse => crate::pac::crs::vals::Syncsrc::LSE,
554 CrsSyncSource::Usb => crate::pac::crs::vals::Syncsrc::USB,
555 };
556
557 crate::pac::CRS.cfgr().modify(|w| {
558 w.set_syncsrc(sync_src);
559 });
560
561 // These are the correct settings for standard USB operation. If other settings
562 // are needed there will need to be additional config options for the CRS.
563 crate::pac::CRS.cr().modify(|w| {
564 w.set_autotrimen(true);
565 w.set_cen(true);
566 });
567 }
568 crate::pac::rcc::vals::Clk48sel::HSI48
569 }
570 };
571
572 RCC.ccipr().modify(|w| w.set_clk48sel(source));
573 }
574
500 if config.low_power_run { 575 if config.low_power_run {
501 assert!(sys_clk <= 2_000_000); 576 assert!(sys_clk <= 2_000_000);
502 PWR.cr1().modify(|w| w.set_lpr(true)); 577 PWR.cr1().modify(|w| w.set_lpr(true));
diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs
index daa1cd61f..f3a98c794 100644
--- a/embassy-stm32/src/rcc/h7.rs
+++ b/embassy-stm32/src/rcc/h7.rs
@@ -601,22 +601,22 @@ pub(crate) unsafe fn init(mut config: Config) {
601 601
602 // Core Prescaler / AHB Prescaler / APB3 Prescaler 602 // Core Prescaler / AHB Prescaler / APB3 Prescaler
603 RCC.d1cfgr().modify(|w| { 603 RCC.d1cfgr().modify(|w| {
604 w.set_d1cpre(Hpre(d1cpre_bits)); 604 w.set_d1cpre(Hpre::from_bits(d1cpre_bits));
605 w.set_d1ppre(Dppre(ppre3_bits)); 605 w.set_d1ppre(Dppre::from_bits(ppre3_bits));
606 w.set_hpre(hpre_bits) 606 w.set_hpre(hpre_bits)
607 }); 607 });
608 // Ensure core prescaler value is valid before future lower 608 // Ensure core prescaler value is valid before future lower
609 // core voltage 609 // core voltage
610 while RCC.d1cfgr().read().d1cpre().0 != d1cpre_bits {} 610 while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {}
611 611
612 // APB1 / APB2 Prescaler 612 // APB1 / APB2 Prescaler
613 RCC.d2cfgr().modify(|w| { 613 RCC.d2cfgr().modify(|w| {
614 w.set_d2ppre1(Dppre(ppre1_bits)); 614 w.set_d2ppre1(Dppre::from_bits(ppre1_bits));
615 w.set_d2ppre2(Dppre(ppre2_bits)); 615 w.set_d2ppre2(Dppre::from_bits(ppre2_bits));
616 }); 616 });
617 617
618 // APB4 Prescaler 618 // APB4 Prescaler
619 RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre(ppre4_bits))); 619 RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre::from_bits(ppre4_bits)));
620 620
621 // Peripheral Clock (per_ck) 621 // Peripheral Clock (per_ck)
622 RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel)); 622 RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel));
@@ -640,7 +640,7 @@ pub(crate) unsafe fn init(mut config: Config) {
640 _ => Sw::HSI, 640 _ => Sw::HSI,
641 }; 641 };
642 RCC.cfgr().modify(|w| w.set_sw(sw)); 642 RCC.cfgr().modify(|w| w.set_sw(sw));
643 while RCC.cfgr().read().sws() != sw.0 {} 643 while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
644 644
645 // IO compensation cell - Requires CSI clock and SYSCFG 645 // IO compensation cell - Requires CSI clock and SYSCFG
646 assert!(RCC.cr().read().csirdy()); 646 assert!(RCC.cr().read().csirdy());
@@ -806,7 +806,8 @@ mod pll {
806 RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false)); 806 RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false));
807 let vco_ck = ref_x_ck * pll_x_n; 807 let vco_ck = ref_x_ck * pll_x_n;
808 808
809 RCC.plldivr(plln).modify(|w| w.set_divp1(Divp((pll_x_p - 1) as u8))); 809 RCC.plldivr(plln)
810 .modify(|w| w.set_divp1(Divp::from_bits((pll_x_p - 1) as u8)));
810 RCC.pllcfgr().modify(|w| w.set_divpen(plln, true)); 811 RCC.pllcfgr().modify(|w| w.set_divpen(plln, true));
811 812
812 // Calulate additional output dividers 813 // Calulate additional output dividers
diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs
index 42a481a74..46a528e31 100644
--- a/embassy-stm32/src/rcc/l0.rs
+++ b/embassy-stm32/src/rcc/l0.rs
@@ -1,7 +1,7 @@
1use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; 1use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
2use crate::pac::RCC; 2use crate::pac::RCC;
3#[cfg(crs)] 3#[cfg(crs)]
4use crate::pac::{CRS, SYSCFG}; 4use crate::pac::{crs, CRS, SYSCFG};
5use crate::rcc::{set_freqs, Clocks}; 5use crate::rcc::{set_freqs, Clocks};
6use crate::time::Hertz; 6use crate::time::Hertz;
7 7
@@ -293,7 +293,7 @@ pub(crate) unsafe fn init(config: Config) {
293 AHBPrescaler::NotDivided => sys_clk, 293 AHBPrescaler::NotDivided => sys_clk,
294 pre => { 294 pre => {
295 let pre: Hpre = pre.into(); 295 let pre: Hpre = pre.into();
296 let pre = 1 << (pre.0 as u32 - 7); 296 let pre = 1 << (pre.to_bits() as u32 - 7);
297 sys_clk / pre 297 sys_clk / pre
298 } 298 }
299 }; 299 };
@@ -302,7 +302,7 @@ pub(crate) unsafe fn init(config: Config) {
302 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 302 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
303 pre => { 303 pre => {
304 let pre: Ppre = pre.into(); 304 let pre: Ppre = pre.into();
305 let pre: u8 = 1 << (pre.0 - 3); 305 let pre: u8 = 1 << (pre.to_bits() - 3);
306 let freq = ahb_freq / pre as u32; 306 let freq = ahb_freq / pre as u32;
307 (freq, freq * 2) 307 (freq, freq * 2)
308 } 308 }
@@ -312,7 +312,7 @@ pub(crate) unsafe fn init(config: Config) {
312 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 312 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
313 pre => { 313 pre => {
314 let pre: Ppre = pre.into(); 314 let pre: Ppre = pre.into();
315 let pre: u8 = 1 << (pre.0 - 3); 315 let pre: u8 = 1 << (pre.to_bits() - 3);
316 let freq = ahb_freq / pre as u32; 316 let freq = ahb_freq / pre as u32;
317 (freq, freq * 2) 317 (freq, freq * 2)
318 } 318 }
@@ -338,7 +338,7 @@ pub(crate) unsafe fn init(config: Config) {
338 CRS.cfgr().write(|w| 338 CRS.cfgr().write(|w|
339 339
340 // Select LSE as synchronization source 340 // Select LSE as synchronization source
341 w.set_syncsrc(0b01)); 341 w.set_syncsrc(crs::vals::Syncsrc::LSE));
342 CRS.cr().modify(|w| { 342 CRS.cr().modify(|w| {
343 w.set_autotrimen(true); 343 w.set_autotrimen(true);
344 w.set_cen(true); 344 w.set_cen(true);
diff --git a/embassy-stm32/src/rcc/l1.rs b/embassy-stm32/src/rcc/l1.rs
index c907fa88a..59a6eac8f 100644
--- a/embassy-stm32/src/rcc/l1.rs
+++ b/embassy-stm32/src/rcc/l1.rs
@@ -294,7 +294,7 @@ pub(crate) unsafe fn init(config: Config) {
294 AHBPrescaler::NotDivided => sys_clk, 294 AHBPrescaler::NotDivided => sys_clk,
295 pre => { 295 pre => {
296 let pre: Hpre = pre.into(); 296 let pre: Hpre = pre.into();
297 let pre = 1 << (pre.0 as u32 - 7); 297 let pre = 1 << (pre.to_bits() as u32 - 7);
298 sys_clk / pre 298 sys_clk / pre
299 } 299 }
300 }; 300 };
@@ -303,7 +303,7 @@ pub(crate) unsafe fn init(config: Config) {
303 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 303 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
304 pre => { 304 pre => {
305 let pre: Ppre = pre.into(); 305 let pre: Ppre = pre.into();
306 let pre: u8 = 1 << (pre.0 - 3); 306 let pre: u8 = 1 << (pre.to_bits() - 3);
307 let freq = ahb_freq / pre as u32; 307 let freq = ahb_freq / pre as u32;
308 (freq, freq * 2) 308 (freq, freq * 2)
309 } 309 }
@@ -313,7 +313,7 @@ pub(crate) unsafe fn init(config: Config) {
313 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 313 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
314 pre => { 314 pre => {
315 let pre: Ppre = pre.into(); 315 let pre: Ppre = pre.into();
316 let pre: u8 = 1 << (pre.0 - 3); 316 let pre: u8 = 1 << (pre.to_bits() - 3);
317 let freq = ahb_freq / pre as u32; 317 let freq = ahb_freq / pre as u32;
318 (freq, freq * 2) 318 (freq, freq * 2)
319 } 319 }
diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs
index f8c1a6e06..20cb8c91c 100644
--- a/embassy-stm32/src/rcc/l4.rs
+++ b/embassy-stm32/src/rcc/l4.rs
@@ -635,7 +635,7 @@ pub(crate) unsafe fn init(config: Config) {
635 AHBPrescaler::NotDivided => sys_clk, 635 AHBPrescaler::NotDivided => sys_clk,
636 pre => { 636 pre => {
637 let pre: Hpre = pre.into(); 637 let pre: Hpre = pre.into();
638 let pre = 1 << (pre.0 as u32 - 7); 638 let pre = 1 << (pre.to_bits() as u32 - 7);
639 sys_clk / pre 639 sys_clk / pre
640 } 640 }
641 }; 641 };
@@ -644,7 +644,7 @@ pub(crate) unsafe fn init(config: Config) {
644 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 644 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
645 pre => { 645 pre => {
646 let pre: Ppre = pre.into(); 646 let pre: Ppre = pre.into();
647 let pre: u8 = 1 << (pre.0 - 3); 647 let pre: u8 = 1 << (pre.to_bits() - 3);
648 let freq = ahb_freq / pre as u32; 648 let freq = ahb_freq / pre as u32;
649 (freq, freq * 2) 649 (freq, freq * 2)
650 } 650 }
@@ -654,7 +654,7 @@ pub(crate) unsafe fn init(config: Config) {
654 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 654 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
655 pre => { 655 pre => {
656 let pre: Ppre = pre.into(); 656 let pre: Ppre = pre.into();
657 let pre: u8 = 1 << (pre.0 - 3); 657 let pre: u8 = 1 << (pre.to_bits() - 3);
658 let freq = ahb_freq / pre as u32; 658 let freq = ahb_freq / pre as u32;
659 (freq, freq * 2) 659 (freq, freq * 2)
660 } 660 }
diff --git a/embassy-stm32/src/rcc/l5.rs b/embassy-stm32/src/rcc/l5.rs
index f56fce365..16da65d5e 100644
--- a/embassy-stm32/src/rcc/l5.rs
+++ b/embassy-stm32/src/rcc/l5.rs
@@ -461,7 +461,7 @@ pub(crate) unsafe fn init(config: Config) {
461 AHBPrescaler::NotDivided => sys_clk, 461 AHBPrescaler::NotDivided => sys_clk,
462 pre => { 462 pre => {
463 let pre: Hpre = pre.into(); 463 let pre: Hpre = pre.into();
464 let pre = 1 << (pre.0 as u32 - 7); 464 let pre = 1 << (pre.to_bits() as u32 - 7);
465 sys_clk / pre 465 sys_clk / pre
466 } 466 }
467 }; 467 };
@@ -470,7 +470,7 @@ pub(crate) unsafe fn init(config: Config) {
470 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 470 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
471 pre => { 471 pre => {
472 let pre: Ppre = pre.into(); 472 let pre: Ppre = pre.into();
473 let pre: u8 = 1 << (pre.0 - 3); 473 let pre: u8 = 1 << (pre.to_bits() - 3);
474 let freq = ahb_freq / pre as u32; 474 let freq = ahb_freq / pre as u32;
475 (freq, freq * 2) 475 (freq, freq * 2)
476 } 476 }
@@ -480,7 +480,7 @@ pub(crate) unsafe fn init(config: Config) {
480 APBPrescaler::NotDivided => (ahb_freq, ahb_freq), 480 APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
481 pre => { 481 pre => {
482 let pre: Ppre = pre.into(); 482 let pre: Ppre = pre.into();
483 let pre: u8 = 1 << (pre.0 - 3); 483 let pre: u8 = 1 << (pre.to_bits() - 3);
484 let freq = ahb_freq / pre as u32; 484 let freq = ahb_freq / pre as u32;
485 (freq, freq * 2) 485 (freq, freq * 2)
486 } 486 }
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index 81507a4d6..cfc07f069 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -126,7 +126,7 @@ pub enum PllM {
126 126
127impl Into<Pllm> for PllM { 127impl Into<Pllm> for PllM {
128 fn into(self) -> Pllm { 128 fn into(self) -> Pllm {
129 Pllm(self as u8) 129 Pllm::from_bits(self as u8)
130 } 130 }
131} 131}
132 132
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index e1615b34c..a2eace6d3 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -36,7 +36,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
36 #[cfg(rtc_v2wb)] 36 #[cfg(rtc_v2wb)]
37 let rtcsel = reg.rtcsel(); 37 let rtcsel = reg.rtcsel();
38 #[cfg(not(rtc_v2wb))] 38 #[cfg(not(rtc_v2wb))]
39 let rtcsel = reg.rtcsel().0; 39 let rtcsel = reg.rtcsel().to_bits();
40 40
41 if !reg.rtcen() || rtcsel != clock_config { 41 if !reg.rtcen() || rtcsel != clock_config {
42 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] 42 #[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
@@ -54,7 +54,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
54 54
55 // Select RTC source 55 // Select RTC source
56 #[cfg(not(rtc_v2wb))] 56 #[cfg(not(rtc_v2wb))]
57 w.set_rtcsel(Rtcsel(clock_config)); 57 w.set_rtcsel(Rtcsel::from_bits(clock_config));
58 #[cfg(rtc_v2wb)] 58 #[cfg(rtc_v2wb)]
59 w.set_rtcsel(clock_config); 59 w.set_rtcsel(clock_config);
60 w.set_rtcen(true); 60 w.set_rtcen(true);
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index 7c91046a2..7e5c64d90 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -26,7 +26,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
26 26
27 let config_rtcsel = rtc_config.clock_config as u8; 27 let config_rtcsel = rtc_config.clock_config as u8;
28 #[cfg(not(any(rcc_wl5, rcc_wle)))] 28 #[cfg(not(any(rcc_wl5, rcc_wle)))]
29 let config_rtcsel = crate::pac::rcc::vals::Rtcsel(config_rtcsel); 29 let config_rtcsel = crate::pac::rcc::vals::Rtcsel::from_bits(config_rtcsel);
30 30
31 if !reg.rtcen() || reg.rtcsel() != config_rtcsel { 31 if !reg.rtcen() || reg.rtcsel() != config_rtcsel {
32 crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); 32 crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 80a336a48..698292bff 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -227,7 +227,11 @@ const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOp
227 fifo_threshold: Some(crate::dma::FifoThreshold::Full), 227 fifo_threshold: Some(crate::dma::FifoThreshold::Full),
228}; 228};
229#[cfg(all(sdmmc_v1, not(dma)))] 229#[cfg(all(sdmmc_v1, not(dma)))]
230const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions {}; 230const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions {
231 circular: false,
232 half_transfer_ir: false,
233 complete_transfer_ir: true,
234};
231 235
232/// SDMMC configuration 236/// SDMMC configuration
233/// 237///
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 1cddac992..c3224073d 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -650,7 +650,7 @@ fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br {
650 _ => 0b111, 650 _ => 0b111,
651 }; 651 };
652 652
653 Br(val) 653 Br::from_bits(val)
654} 654}
655 655
656trait RegsExt { 656trait RegsExt {
@@ -772,7 +772,7 @@ fn set_rxdmaen(regs: Regs, val: bool) {
772 772
773fn finish_dma(regs: Regs) { 773fn finish_dma(regs: Regs) {
774 #[cfg(spi_v2)] 774 #[cfg(spi_v2)]
775 while regs.sr().read().ftlvl() > 0 {} 775 while regs.sr().read().ftlvl().to_bits() > 0 {}
776 776
777 #[cfg(any(spi_v3, spi_v4, spi_v5))] 777 #[cfg(any(spi_v3, spi_v4, spi_v5))]
778 while !regs.sr().read().txc() {} 778 while !regs.sr().read().txc() {}
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 47a79c187..c97efbf0a 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -869,7 +869,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
869 _ => vals::Ps::EVEN, 869 _ => vals::Ps::EVEN,
870 }); 870 });
871 #[cfg(not(usart_v1))] 871 #[cfg(not(usart_v1))]
872 w.set_over8(vals::Over8(over8 as _)); 872 w.set_over8(vals::Over8::from_bits(over8 as _));
873 }); 873 });
874 874
875 #[cfg(not(usart_v1))] 875 #[cfg(not(usart_v1))]
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 2367127e8..ecdd1d0b8 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -97,8 +97,8 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
97 } 97 }
98 epr.set_dtog_rx(false); 98 epr.set_dtog_rx(false);
99 epr.set_dtog_tx(false); 99 epr.set_dtog_tx(false);
100 epr.set_stat_rx(Stat(0)); 100 epr.set_stat_rx(Stat::from_bits(0));
101 epr.set_stat_tx(Stat(0)); 101 epr.set_stat_tx(Stat::from_bits(0));
102 epr.set_ctr_rx(!epr.ctr_rx()); 102 epr.set_ctr_rx(!epr.ctr_rx());
103 epr.set_ctr_tx(!epr.ctr_tx()); 103 epr.set_ctr_tx(!epr.ctr_tx());
104 regs.epr(index).write_value(epr); 104 regs.epr(index).write_value(epr);
@@ -143,8 +143,8 @@ fn invariant(mut r: regs::Epr) -> regs::Epr {
143 r.set_ctr_tx(true); // don't clear 143 r.set_ctr_tx(true); // don't clear
144 r.set_dtog_rx(false); // don't toggle 144 r.set_dtog_rx(false); // don't toggle
145 r.set_dtog_tx(false); // don't toggle 145 r.set_dtog_tx(false); // don't toggle
146 r.set_stat_rx(Stat(0)); 146 r.set_stat_rx(Stat::from_bits(0));
147 r.set_stat_tx(Stat(0)); 147 r.set_stat_tx(Stat::from_bits(0));
148 r 148 r
149} 149}
150 150
@@ -480,56 +480,57 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
480 poll_fn(move |cx| { 480 poll_fn(move |cx| {
481 BUS_WAKER.register(cx.waker()); 481 BUS_WAKER.register(cx.waker());
482 482
483 if self.inited { 483 // TODO: implement VBUS detection.
484 let regs = T::regs(); 484 if !self.inited {
485 485 self.inited = true;
486 if IRQ_RESUME.load(Ordering::Acquire) { 486 return Poll::Ready(Event::PowerDetected);
487 IRQ_RESUME.store(false, Ordering::Relaxed); 487 }
488 return Poll::Ready(Event::Resume);
489 }
490 488
491 if IRQ_RESET.load(Ordering::Acquire) { 489 let regs = T::regs();
492 IRQ_RESET.store(false, Ordering::Relaxed);
493
494 trace!("RESET");
495 regs.daddr().write(|w| {
496 w.set_ef(true);
497 w.set_add(0);
498 });
499
500 regs.epr(0).write(|w| {
501 w.set_ep_type(EpType::CONTROL);
502 w.set_stat_rx(Stat::NAK);
503 w.set_stat_tx(Stat::NAK);
504 });
505
506 for i in 1..EP_COUNT {
507 regs.epr(i).write(|w| {
508 w.set_ea(i as _);
509 w.set_ep_type(self.ep_types[i - 1]);
510 })
511 }
512 490
513 for w in &EP_IN_WAKERS { 491 if IRQ_RESUME.load(Ordering::Acquire) {
514 w.wake() 492 IRQ_RESUME.store(false, Ordering::Relaxed);
515 } 493 return Poll::Ready(Event::Resume);
516 for w in &EP_OUT_WAKERS { 494 }
517 w.wake()
518 }
519 495
520 return Poll::Ready(Event::Reset); 496 if IRQ_RESET.load(Ordering::Acquire) {
497 IRQ_RESET.store(false, Ordering::Relaxed);
498
499 trace!("RESET");
500 regs.daddr().write(|w| {
501 w.set_ef(true);
502 w.set_add(0);
503 });
504
505 regs.epr(0).write(|w| {
506 w.set_ep_type(EpType::CONTROL);
507 w.set_stat_rx(Stat::NAK);
508 w.set_stat_tx(Stat::NAK);
509 });
510
511 for i in 1..EP_COUNT {
512 regs.epr(i).write(|w| {
513 w.set_ea(i as _);
514 w.set_ep_type(self.ep_types[i - 1]);
515 })
521 } 516 }
522 517
523 if IRQ_SUSPEND.load(Ordering::Acquire) { 518 for w in &EP_IN_WAKERS {
524 IRQ_SUSPEND.store(false, Ordering::Relaxed); 519 w.wake()
525 return Poll::Ready(Event::Suspend); 520 }
521 for w in &EP_OUT_WAKERS {
522 w.wake()
526 } 523 }
527 524
528 Poll::Pending 525 return Poll::Ready(Event::Reset);
529 } else { 526 }
530 self.inited = true; 527
531 return Poll::Ready(Event::PowerDetected); 528 if IRQ_SUSPEND.load(Ordering::Acquire) {
529 IRQ_SUSPEND.store(false, Ordering::Relaxed);
530 return Poll::Ready(Event::Suspend);
532 } 531 }
532
533 Poll::Pending
533 }) 534 })
534 .await 535 .await
535 } 536 }
@@ -550,7 +551,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
550 true => Stat::STALL, 551 true => Stat::STALL,
551 }; 552 };
552 let mut w = invariant(r); 553 let mut w = invariant(r);
553 w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0)); 554 w.set_stat_tx(Stat::from_bits(r.stat_tx().to_bits() ^ want_stat.to_bits()));
554 reg.write_value(w); 555 reg.write_value(w);
555 } 556 }
556 } 557 }
@@ -569,7 +570,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
569 true => Stat::STALL, 570 true => Stat::STALL,
570 }; 571 };
571 let mut w = invariant(r); 572 let mut w = invariant(r);
572 w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0)); 573 w.set_stat_rx(Stat::from_bits(r.stat_rx().to_bits() ^ want_stat.to_bits()));
573 reg.write_value(w); 574 reg.write_value(w);
574 } 575 }
575 } 576 }
@@ -605,7 +606,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
605 break; 606 break;
606 } 607 }
607 let mut w = invariant(r); 608 let mut w = invariant(r);
608 w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0)); 609 w.set_stat_tx(Stat::from_bits(r.stat_tx().to_bits() ^ want_stat.to_bits()));
609 reg.write_value(w); 610 reg.write_value(w);
610 } 611 }
611 EP_IN_WAKERS[ep_addr.index()].wake(); 612 EP_IN_WAKERS[ep_addr.index()].wake();
@@ -621,7 +622,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
621 break; 622 break;
622 } 623 }
623 let mut w = invariant(r); 624 let mut w = invariant(r);
624 w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0)); 625 w.set_stat_rx(Stat::from_bits(r.stat_rx().to_bits() ^ want_stat.to_bits()));
625 reg.write_value(w); 626 reg.write_value(w);
626 } 627 }
627 EP_OUT_WAKERS[ep_addr.index()].wake(); 628 EP_OUT_WAKERS[ep_addr.index()].wake();
@@ -762,8 +763,8 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
762 regs.epr(index).write(|w| { 763 regs.epr(index).write(|w| {
763 w.set_ep_type(convert_type(self.info.ep_type)); 764 w.set_ep_type(convert_type(self.info.ep_type));
764 w.set_ea(self.info.addr.index() as _); 765 w.set_ea(self.info.addr.index() as _);
765 w.set_stat_rx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); 766 w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
766 w.set_stat_tx(Stat(0)); 767 w.set_stat_tx(Stat::from_bits(0));
767 w.set_ctr_rx(true); // don't clear 768 w.set_ctr_rx(true); // don't clear
768 w.set_ctr_tx(true); // don't clear 769 w.set_ctr_tx(true); // don't clear
769 }); 770 });
@@ -804,8 +805,8 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
804 regs.epr(index).write(|w| { 805 regs.epr(index).write(|w| {
805 w.set_ep_type(convert_type(self.info.ep_type)); 806 w.set_ep_type(convert_type(self.info.ep_type));
806 w.set_ea(self.info.addr.index() as _); 807 w.set_ea(self.info.addr.index() as _);
807 w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); 808 w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
808 w.set_stat_rx(Stat(0)); 809 w.set_stat_rx(Stat::from_bits(0));
809 w.set_ctr_rx(true); // don't clear 810 w.set_ctr_rx(true); // don't clear
810 w.set_ctr_tx(true); // don't clear 811 w.set_ctr_tx(true); // don't clear
811 }); 812 });
@@ -868,19 +869,19 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
868 let mut stat_tx = 0; 869 let mut stat_tx = 0;
869 if first { 870 if first {
870 // change NAK -> VALID 871 // change NAK -> VALID
871 stat_rx ^= Stat::NAK.0 ^ Stat::VALID.0; 872 stat_rx ^= Stat::NAK.to_bits() ^ Stat::VALID.to_bits();
872 stat_tx ^= Stat::NAK.0 ^ Stat::STALL.0; 873 stat_tx ^= Stat::NAK.to_bits() ^ Stat::STALL.to_bits();
873 } 874 }
874 if last { 875 if last {
875 // change STALL -> VALID 876 // change STALL -> VALID
876 stat_tx ^= Stat::STALL.0 ^ Stat::NAK.0; 877 stat_tx ^= Stat::STALL.to_bits() ^ Stat::NAK.to_bits();
877 } 878 }
878 // Note: if this is the first AND last transfer, the above effectively 879 // Note: if this is the first AND last transfer, the above effectively
879 // changes stat_tx like NAK -> NAK, so noop. 880 // changes stat_tx like NAK -> NAK, so noop.
880 regs.epr(0).write(|w| { 881 regs.epr(0).write(|w| {
881 w.set_ep_type(EpType::CONTROL); 882 w.set_ep_type(EpType::CONTROL);
882 w.set_stat_rx(Stat(stat_rx)); 883 w.set_stat_rx(Stat::from_bits(stat_rx));
883 w.set_stat_tx(Stat(stat_tx)); 884 w.set_stat_tx(Stat::from_bits(stat_tx));
884 w.set_ctr_rx(true); // don't clear 885 w.set_ctr_rx(true); // don't clear
885 w.set_ctr_tx(true); // don't clear 886 w.set_ctr_tx(true); // don't clear
886 }); 887 });
@@ -907,11 +908,11 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
907 908
908 regs.epr(0).write(|w| { 909 regs.epr(0).write(|w| {
909 w.set_ep_type(EpType::CONTROL); 910 w.set_ep_type(EpType::CONTROL);
910 w.set_stat_rx(Stat(match last { 911 w.set_stat_rx(Stat::from_bits(match last {
911 // If last, set STAT_RX=STALL. 912 // If last, set STAT_RX=STALL.
912 true => Stat::NAK.0 ^ Stat::STALL.0, 913 true => Stat::NAK.to_bits() ^ Stat::STALL.to_bits(),
913 // Otherwise, set STAT_RX=VALID, to allow the host to send the next packet. 914 // Otherwise, set STAT_RX=VALID, to allow the host to send the next packet.
914 false => Stat::NAK.0 ^ Stat::VALID.0, 915 false => Stat::NAK.to_bits() ^ Stat::VALID.to_bits(),
915 })); 916 }));
916 w.set_ctr_rx(true); // don't clear 917 w.set_ctr_rx(true); // don't clear
917 w.set_ctr_tx(true); // don't clear 918 w.set_ctr_tx(true); // don't clear
@@ -936,17 +937,17 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
936 let mut stat_rx = 0; 937 let mut stat_rx = 0;
937 if first { 938 if first {
938 // change NAK -> STALL 939 // change NAK -> STALL
939 stat_rx ^= Stat::NAK.0 ^ Stat::STALL.0; 940 stat_rx ^= Stat::NAK.to_bits() ^ Stat::STALL.to_bits();
940 } 941 }
941 if last { 942 if last {
942 // change STALL -> VALID 943 // change STALL -> VALID
943 stat_rx ^= Stat::STALL.0 ^ Stat::VALID.0; 944 stat_rx ^= Stat::STALL.to_bits() ^ Stat::VALID.to_bits();
944 } 945 }
945 // Note: if this is the first AND last transfer, the above effectively 946 // Note: if this is the first AND last transfer, the above effectively
946 // does a change of NAK -> VALID. 947 // does a change of NAK -> VALID.
947 regs.epr(0).write(|w| { 948 regs.epr(0).write(|w| {
948 w.set_ep_type(EpType::CONTROL); 949 w.set_ep_type(EpType::CONTROL);
949 w.set_stat_rx(Stat(stat_rx)); 950 w.set_stat_rx(Stat::from_bits(stat_rx));
950 w.set_ep_kind(last); // set OUT_STATUS if last. 951 w.set_ep_kind(last); // set OUT_STATUS if last.
951 w.set_ctr_rx(true); // don't clear 952 w.set_ctr_rx(true); // don't clear
952 w.set_ctr_tx(true); // don't clear 953 w.set_ctr_tx(true); // don't clear
@@ -976,7 +977,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
976 let regs = T::regs(); 977 let regs = T::regs();
977 regs.epr(0).write(|w| { 978 regs.epr(0).write(|w| {
978 w.set_ep_type(EpType::CONTROL); 979 w.set_ep_type(EpType::CONTROL);
979 w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); 980 w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
980 w.set_ep_kind(last); // set OUT_STATUS if last. 981 w.set_ep_kind(last); // set OUT_STATUS if last.
981 w.set_ctr_rx(true); // don't clear 982 w.set_ctr_rx(true); // don't clear
982 w.set_ctr_tx(true); // don't clear 983 w.set_ctr_tx(true); // don't clear
@@ -997,8 +998,8 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
997 let epr = regs.epr(0).read(); 998 let epr = regs.epr(0).read();
998 regs.epr(0).write(|w| { 999 regs.epr(0).write(|w| {
999 w.set_ep_type(EpType::CONTROL); 1000 w.set_ep_type(EpType::CONTROL);
1000 w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0)); 1001 w.set_stat_rx(Stat::from_bits(epr.stat_rx().to_bits() ^ Stat::STALL.to_bits()));
1001 w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::VALID.0)); 1002 w.set_stat_tx(Stat::from_bits(epr.stat_tx().to_bits() ^ Stat::VALID.to_bits()));
1002 w.set_ctr_rx(true); // don't clear 1003 w.set_ctr_rx(true); // don't clear
1003 w.set_ctr_tx(true); // don't clear 1004 w.set_ctr_tx(true); // don't clear
1004 }); 1005 });
@@ -1028,8 +1029,8 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
1028 let epr = regs.epr(0).read(); 1029 let epr = regs.epr(0).read();
1029 regs.epr(0).write(|w| { 1030 regs.epr(0).write(|w| {
1030 w.set_ep_type(EpType::CONTROL); 1031 w.set_ep_type(EpType::CONTROL);
1031 w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0)); 1032 w.set_stat_rx(Stat::from_bits(epr.stat_rx().to_bits() ^ Stat::STALL.to_bits()));
1032 w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::STALL.0)); 1033 w.set_stat_tx(Stat::from_bits(epr.stat_tx().to_bits() ^ Stat::STALL.to_bits()));
1033 w.set_ctr_rx(true); // don't clear 1034 w.set_ctr_rx(true); // don't clear
1034 w.set_ctr_tx(true); // don't clear 1035 w.set_ctr_tx(true); // don't clear
1035 }); 1036 });
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs
index 8af5c7bd5..6783db28d 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb_otg/usb.rs
@@ -6,8 +6,8 @@ use atomic_polyfill::{AtomicBool, AtomicU16, Ordering};
6use embassy_hal_common::{into_ref, Peripheral}; 6use embassy_hal_common::{into_ref, Peripheral};
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
8use embassy_usb_driver::{ 8use embassy_usb_driver::{
9 self, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, EndpointOut, 9 self, Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo,
10 EndpointType, Event, Unsupported, 10 EndpointOut, EndpointType, Event, Unsupported,
11}; 11};
12use futures::future::poll_fn; 12use futures::future::poll_fn;
13 13
@@ -31,7 +31,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
31 let state = T::state(); 31 let state = T::state();
32 32
33 let ints = r.gintsts().read(); 33 let ints = r.gintsts().read();
34 if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() { 34 if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() || ints.otgint() || ints.srqint() {
35 // Mask interrupts and notify `Bus` to process them 35 // Mask interrupts and notify `Bus` to process them
36 r.gintmsk().write(|_| {}); 36 r.gintmsk().write(|_| {});
37 T::state().bus_waker.wake(); 37 T::state().bus_waker.wake();
@@ -97,7 +97,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
97 vals::Pktstsd::SETUP_DATA_DONE => { 97 vals::Pktstsd::SETUP_DATA_DONE => {
98 trace!("SETUP_DATA_DONE ep={}", ep_num); 98 trace!("SETUP_DATA_DONE ep={}", ep_num);
99 } 99 }
100 x => trace!("unknown PKTSTS: {}", x.0), 100 x => trace!("unknown PKTSTS: {}", x.to_bits()),
101 } 101 }
102 } 102 }
103 103
@@ -124,7 +124,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
124 } 124 }
125 125
126 state.ep_in_wakers[ep_num].wake(); 126 state.ep_in_wakers[ep_num].wake();
127 trace!("in ep={} irq val={:b}", ep_num, ep_ints.0); 127 trace!("in ep={} irq val={:08x}", ep_num, ep_ints.0);
128 } 128 }
129 129
130 ep_mask >>= 1; 130 ep_mask >>= 1;
@@ -144,7 +144,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
144 // // clear all 144 // // clear all
145 // r.doepint(ep_num).write_value(ep_ints); 145 // r.doepint(ep_num).write_value(ep_ints);
146 // state.ep_out_wakers[ep_num].wake(); 146 // state.ep_out_wakers[ep_num].wake();
147 // trace!("out ep={} irq val={=u32:b}", ep_num, ep_ints.0); 147 // trace!("out ep={} irq val={:08x}", ep_num, ep_ints.0);
148 // } 148 // }
149 149
150 // ep_mask >>= 1; 150 // ep_mask >>= 1;
@@ -256,7 +256,34 @@ struct EndpointData {
256 fifo_size_words: u16, 256 fifo_size_words: u16,
257} 257}
258 258
259#[non_exhaustive]
260#[derive(Clone, Copy, PartialEq, Eq, Debug)]
261pub struct Config {
262 /// Enable VBUS detection.
263 ///
264 /// The USB spec requires USB devices monitor for USB cable plug/unplug and react accordingly.
265 /// This is done by checkihg whether there is 5V on the VBUS pin or not.
266 ///
267 /// If your device is bus-powered (powers itself from the USB host via VBUS), then this is optional.
268 /// (if there's no power in VBUS your device would be off anyway, so it's fine to always assume
269 /// there's power in VBUS, i.e. the USB cable is always plugged in.)
270 ///
271 /// If your device is self-powered (i.e. it gets power from a source other than the USB cable, and
272 /// therefore can stay powered through USB cable plug/unplug) then you MUST set this to true.
273 ///
274 /// If you set this to true, you must connect VBUS to PA9 for FS, PB13 for HS, possibly with a
275 /// voltage divider. See ST application note AN4879 and the reference manual for more details.
276 pub vbus_detection: bool,
277}
278
279impl Default for Config {
280 fn default() -> Self {
281 Self { vbus_detection: true }
282 }
283}
284
259pub struct Driver<'d, T: Instance> { 285pub struct Driver<'d, T: Instance> {
286 config: Config,
260 phantom: PhantomData<&'d mut T>, 287 phantom: PhantomData<&'d mut T>,
261 ep_in: [Option<EndpointData>; MAX_EP_COUNT], 288 ep_in: [Option<EndpointData>; MAX_EP_COUNT],
262 ep_out: [Option<EndpointData>; MAX_EP_COUNT], 289 ep_out: [Option<EndpointData>; MAX_EP_COUNT],
@@ -279,6 +306,7 @@ impl<'d, T: Instance> Driver<'d, T> {
279 dp: impl Peripheral<P = impl DpPin<T>> + 'd, 306 dp: impl Peripheral<P = impl DpPin<T>> + 'd,
280 dm: impl Peripheral<P = impl DmPin<T>> + 'd, 307 dm: impl Peripheral<P = impl DmPin<T>> + 'd,
281 ep_out_buffer: &'d mut [u8], 308 ep_out_buffer: &'d mut [u8],
309 config: Config,
282 ) -> Self { 310 ) -> Self {
283 into_ref!(dp, dm); 311 into_ref!(dp, dm);
284 312
@@ -286,6 +314,7 @@ impl<'d, T: Instance> Driver<'d, T> {
286 dm.set_as_af(dm.af_num(), AFType::OutputPushPull); 314 dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
287 315
288 Self { 316 Self {
317 config,
289 phantom: PhantomData, 318 phantom: PhantomData,
290 ep_in: [None; MAX_EP_COUNT], 319 ep_in: [None; MAX_EP_COUNT],
291 ep_out: [None; MAX_EP_COUNT], 320 ep_out: [None; MAX_EP_COUNT],
@@ -318,6 +347,7 @@ impl<'d, T: Instance> Driver<'d, T> {
318 ulpi_d6: impl Peripheral<P = impl UlpiD6Pin<T>> + 'd, 347 ulpi_d6: impl Peripheral<P = impl UlpiD6Pin<T>> + 'd,
319 ulpi_d7: impl Peripheral<P = impl UlpiD7Pin<T>> + 'd, 348 ulpi_d7: impl Peripheral<P = impl UlpiD7Pin<T>> + 'd,
320 ep_out_buffer: &'d mut [u8], 349 ep_out_buffer: &'d mut [u8],
350 config: Config,
321 ) -> Self { 351 ) -> Self {
322 assert!(T::HIGH_SPEED == true, "Peripheral is not capable of high-speed USB"); 352 assert!(T::HIGH_SPEED == true, "Peripheral is not capable of high-speed USB");
323 353
@@ -327,6 +357,7 @@ impl<'d, T: Instance> Driver<'d, T> {
327 ); 357 );
328 358
329 Self { 359 Self {
360 config,
330 phantom: PhantomData, 361 phantom: PhantomData,
331 ep_in: [None; MAX_EP_COUNT], 362 ep_in: [None; MAX_EP_COUNT],
332 ep_out: [None; MAX_EP_COUNT], 363 ep_out: [None; MAX_EP_COUNT],
@@ -464,11 +495,12 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
464 495
465 ( 496 (
466 Bus { 497 Bus {
498 config: self.config,
467 phantom: PhantomData, 499 phantom: PhantomData,
468 ep_in: self.ep_in, 500 ep_in: self.ep_in,
469 ep_out: self.ep_out, 501 ep_out: self.ep_out,
470 phy_type: self.phy_type, 502 phy_type: self.phy_type,
471 enabled: false, 503 inited: false,
472 }, 504 },
473 ControlPipe { 505 ControlPipe {
474 _phantom: PhantomData, 506 _phantom: PhantomData,
@@ -481,11 +513,12 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
481} 513}
482 514
483pub struct Bus<'d, T: Instance> { 515pub struct Bus<'d, T: Instance> {
516 config: Config,
484 phantom: PhantomData<&'d mut T>, 517 phantom: PhantomData<&'d mut T>,
485 ep_in: [Option<EndpointData>; MAX_EP_COUNT], 518 ep_in: [Option<EndpointData>; MAX_EP_COUNT],
486 ep_out: [Option<EndpointData>; MAX_EP_COUNT], 519 ep_out: [Option<EndpointData>; MAX_EP_COUNT],
487 phy_type: PhyType, 520 phy_type: PhyType,
488 enabled: bool, 521 inited: bool,
489} 522}
490 523
491impl<'d, T: Instance> Bus<'d, T> { 524impl<'d, T: Instance> Bus<'d, T> {
@@ -498,11 +531,202 @@ impl<'d, T: Instance> Bus<'d, T> {
498 w.set_iepint(true); 531 w.set_iepint(true);
499 w.set_oepint(true); 532 w.set_oepint(true);
500 w.set_rxflvlm(true); 533 w.set_rxflvlm(true);
534 w.set_srqim(true);
535 w.set_otgint(true);
501 }); 536 });
502 } 537 }
503} 538}
504 539
505impl<'d, T: Instance> Bus<'d, T> { 540impl<'d, T: Instance> Bus<'d, T> {
541 fn init(&mut self) {
542 #[cfg(stm32l4)]
543 {
544 crate::peripherals::PWR::enable();
545 critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
546 }
547
548 #[cfg(stm32f7)]
549 {
550 // Enable ULPI clock if external PHY is used
551 let ulpien = !self.phy_type.internal();
552 critical_section::with(|_| {
553 crate::pac::RCC.ahb1enr().modify(|w| {
554 if T::HIGH_SPEED {
555 w.set_usb_otg_hsulpien(ulpien);
556 } else {
557 w.set_usb_otg_hsen(ulpien);
558 }
559 });
560
561 // Low power mode
562 crate::pac::RCC.ahb1lpenr().modify(|w| {
563 if T::HIGH_SPEED {
564 w.set_usb_otg_hsulpilpen(ulpien);
565 } else {
566 w.set_usb_otg_hslpen(ulpien);
567 }
568 });
569 });
570 }
571
572 #[cfg(stm32h7)]
573 {
574 // If true, VDD33USB is generated by internal regulator from VDD50USB
575 // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
576 // TODO: unhardcode
577 let internal_regulator = false;
578
579 // Enable USB power
580 critical_section::with(|_| {
581 crate::pac::PWR.cr3().modify(|w| {
582 w.set_usb33den(true);
583 w.set_usbregen(internal_regulator);
584 })
585 });
586
587 // Wait for USB power to stabilize
588 while !crate::pac::PWR.cr3().read().usb33rdy() {}
589
590 // Use internal 48MHz HSI clock. Should be enabled in RCC by default.
591 critical_section::with(|_| {
592 crate::pac::RCC
593 .d2ccip2r()
594 .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48))
595 });
596
597 // Enable ULPI clock if external PHY is used
598 let ulpien = !self.phy_type.internal();
599 critical_section::with(|_| {
600 crate::pac::RCC.ahb1enr().modify(|w| {
601 if T::HIGH_SPEED {
602 w.set_usb_otg_hs_ulpien(ulpien);
603 } else {
604 w.set_usb_otg_fs_ulpien(ulpien);
605 }
606 });
607 crate::pac::RCC.ahb1lpenr().modify(|w| {
608 if T::HIGH_SPEED {
609 w.set_usb_otg_hs_ulpilpen(ulpien);
610 } else {
611 w.set_usb_otg_fs_ulpilpen(ulpien);
612 }
613 });
614 });
615 }
616
617 #[cfg(stm32u5)]
618 {
619 // Enable USB power
620 critical_section::with(|_| {
621 crate::pac::RCC.ahb3enr().modify(|w| {
622 w.set_pwren(true);
623 });
624 cortex_m::asm::delay(2);
625
626 crate::pac::PWR.svmcr().modify(|w| {
627 w.set_usv(true);
628 w.set_uvmen(true);
629 });
630 });
631
632 // Wait for USB power to stabilize
633 while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
634
635 // Select HSI48 as USB clock source.
636 critical_section::with(|_| {
637 crate::pac::RCC.ccipr1().modify(|w| {
638 w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48);
639 })
640 });
641 }
642
643 <T as RccPeripheral>::enable();
644 <T as RccPeripheral>::reset();
645
646 T::Interrupt::unpend();
647 unsafe { T::Interrupt::enable() };
648
649 let r = T::regs();
650 let core_id = r.cid().read().0;
651 info!("Core id {:08x}", core_id);
652
653 // Wait for AHB ready.
654 while !r.grstctl().read().ahbidl() {}
655
656 // Configure as device.
657 r.gusbcfg().write(|w| {
658 // Force device mode
659 w.set_fdmod(true);
660 // Enable internal full-speed PHY
661 w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed());
662 });
663
664 // Configuring Vbus sense and SOF output
665 match core_id {
666 0x0000_1200 | 0x0000_1100 => {
667 assert!(self.phy_type != PhyType::InternalHighSpeed);
668
669 r.gccfg_v1().modify(|w| {
670 // Enable internal full-speed PHY, logic is inverted
671 w.set_pwrdwn(self.phy_type.internal());
672 });
673
674 // F429-like chips have the GCCFG.NOVBUSSENS bit
675 r.gccfg_v1().modify(|w| {
676 w.set_novbussens(!self.config.vbus_detection);
677 w.set_vbusasen(false);
678 w.set_vbusbsen(self.config.vbus_detection);
679 w.set_sofouten(false);
680 });
681 }
682 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => {
683 // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning
684 r.gccfg_v2().modify(|w| {
685 // Enable internal full-speed PHY, logic is inverted
686 w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed());
687 w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed());
688 });
689
690 r.gccfg_v2().modify(|w| {
691 w.set_vbden(self.config.vbus_detection);
692 });
693
694 // Force B-peripheral session
695 r.gotgctl().modify(|w| {
696 w.set_bvaloen(!self.config.vbus_detection);
697 w.set_bvaloval(true);
698 });
699 }
700 _ => unimplemented!("Unknown USB core id {:X}", core_id),
701 }
702
703 // Soft disconnect.
704 r.dctl().write(|w| w.set_sdis(true));
705
706 // Set speed.
707 r.dcfg().write(|w| {
708 w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80);
709 w.set_dspd(self.phy_type.to_dspd());
710 });
711
712 // Unmask transfer complete EP interrupt
713 r.diepmsk().write(|w| {
714 w.set_xfrcm(true);
715 });
716
717 // Unmask and clear core interrupts
718 Bus::<T>::restore_irqs();
719 r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF));
720
721 // Unmask global interrupt
722 r.gahbcfg().write(|w| {
723 w.set_gint(true); // unmask global interrupt
724 });
725
726 // Connect
727 r.dctl().write(|w| w.set_sdis(false));
728 }
729
506 fn init_fifo(&mut self) { 730 fn init_fifo(&mut self) {
507 trace!("init_fifo"); 731 trace!("init_fifo");
508 732
@@ -540,6 +764,19 @@ impl<'d, T: Instance> Bus<'d, T> {
540 fifo_top <= T::FIFO_DEPTH_WORDS, 764 fifo_top <= T::FIFO_DEPTH_WORDS,
541 "FIFO allocations exceeded maximum capacity" 765 "FIFO allocations exceeded maximum capacity"
542 ); 766 );
767
768 // Flush fifos
769 r.grstctl().write(|w| {
770 w.set_rxfflsh(true);
771 w.set_txfflsh(true);
772 w.set_txfnum(0x10);
773 });
774 loop {
775 let x = r.grstctl().read();
776 if !x.rxfflsh() && !x.txfflsh() {
777 break;
778 }
779 }
543 } 780 }
544 781
545 fn configure_endpoints(&mut self) { 782 fn configure_endpoints(&mut self) {
@@ -558,6 +795,8 @@ impl<'d, T: Instance> Bus<'d, T> {
558 w.set_mpsiz(ep.max_packet_size); 795 w.set_mpsiz(ep.max_packet_size);
559 w.set_eptyp(to_eptyp(ep.ep_type)); 796 w.set_eptyp(to_eptyp(ep.ep_type));
560 w.set_sd0pid_sevnfrm(true); 797 w.set_sd0pid_sevnfrm(true);
798 w.set_txfnum(index as _);
799 w.set_snak(true);
561 } 800 }
562 }); 801 });
563 }); 802 });
@@ -598,6 +837,13 @@ impl<'d, T: Instance> Bus<'d, T> {
598 }); 837 });
599 } 838 }
600 839
840 fn disable_all_endpoints(&mut self) {
841 for i in 0..T::ENDPOINT_COUNT {
842 self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::In), false);
843 self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::Out), false);
844 }
845 }
846
601 fn disable(&mut self) { 847 fn disable(&mut self) {
602 T::Interrupt::disable(); 848 T::Interrupt::disable();
603 849
@@ -612,9 +858,14 @@ impl<'d, T: Instance> Bus<'d, T> {
612impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { 858impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
613 async fn poll(&mut self) -> Event { 859 async fn poll(&mut self) -> Event {
614 poll_fn(move |cx| { 860 poll_fn(move |cx| {
615 // TODO: implement VBUS detection 861 if !self.inited {
616 if !self.enabled { 862 self.init();
617 return Poll::Ready(Event::PowerDetected); 863 self.inited = true;
864
865 // If no vbus detection, just return a single PowerDetected event at startup.
866 if !self.config.vbus_detection {
867 return Poll::Ready(Event::PowerDetected);
868 }
618 } 869 }
619 870
620 let r = T::regs(); 871 let r = T::regs();
@@ -622,6 +873,32 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
622 T::state().bus_waker.register(cx.waker()); 873 T::state().bus_waker.register(cx.waker());
623 874
624 let ints = r.gintsts().read(); 875 let ints = r.gintsts().read();
876
877 if ints.srqint() {
878 trace!("vbus detected");
879
880 r.gintsts().write(|w| w.set_srqint(true)); // clear
881 Self::restore_irqs();
882
883 if self.config.vbus_detection {
884 return Poll::Ready(Event::PowerDetected);
885 }
886 }
887
888 if ints.otgint() {
889 let otgints = r.gotgint().read();
890 r.gotgint().write_value(otgints); // clear all
891 Self::restore_irqs();
892
893 if otgints.sedet() {
894 trace!("vbus removed");
895 if self.config.vbus_detection {
896 self.disable_all_endpoints();
897 return Poll::Ready(Event::PowerRemoved);
898 }
899 }
900 }
901
625 if ints.usbrst() { 902 if ints.usbrst() {
626 trace!("reset"); 903 trace!("reset");
627 904
@@ -643,7 +920,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
643 trace!("enumdne"); 920 trace!("enumdne");
644 921
645 let speed = r.dsts().read().enumspd(); 922 let speed = r.dsts().read().enumspd();
646 trace!(" speed={}", speed.0); 923 trace!(" speed={}", speed.to_bits());
647 924
648 r.gusbcfg().modify(|w| { 925 r.gusbcfg().modify(|w| {
649 w.set_trdt(calculate_trdt(speed, T::frequency())); 926 w.set_trdt(calculate_trdt(speed, T::frequency()));
@@ -744,7 +1021,19 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
744 1021
745 r.doepctl(ep_addr.index()).modify(|w| { 1022 r.doepctl(ep_addr.index()).modify(|w| {
746 w.set_usbaep(enabled); 1023 w.set_usbaep(enabled);
747 }) 1024 });
1025
1026 // Flush tx fifo
1027 r.grstctl().write(|w| {
1028 w.set_txfflsh(true);
1029 w.set_txfnum(ep_addr.index() as _);
1030 });
1031 loop {
1032 let x = r.grstctl().read();
1033 if !x.txfflsh() {
1034 break;
1035 }
1036 }
748 }); 1037 });
749 1038
750 // Wake `Endpoint::wait_enabled()` 1039 // Wake `Endpoint::wait_enabled()`
@@ -755,13 +1044,14 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
755 // cancel transfer if active 1044 // cancel transfer if active
756 if !enabled && r.diepctl(ep_addr.index()).read().epena() { 1045 if !enabled && r.diepctl(ep_addr.index()).read().epena() {
757 r.diepctl(ep_addr.index()).modify(|w| { 1046 r.diepctl(ep_addr.index()).modify(|w| {
758 w.set_snak(true); 1047 w.set_snak(true); // set NAK
759 w.set_epdis(true); 1048 w.set_epdis(true);
760 }) 1049 })
761 } 1050 }
762 1051
763 r.diepctl(ep_addr.index()).modify(|w| { 1052 r.diepctl(ep_addr.index()).modify(|w| {
764 w.set_usbaep(enabled); 1053 w.set_usbaep(enabled);
1054 w.set_cnak(enabled); // clear NAK that might've been set by SNAK above.
765 }) 1055 })
766 }); 1056 });
767 1057
@@ -773,203 +1063,14 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
773 1063
774 async fn enable(&mut self) { 1064 async fn enable(&mut self) {
775 trace!("enable"); 1065 trace!("enable");
776 1066 // TODO: enable the peripheral once enable/disable semantics are cleared up in embassy-usb
777 #[cfg(stm32l4)]
778 {
779 crate::peripherals::PWR::enable();
780 critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
781 }
782
783 #[cfg(stm32f7)]
784 {
785 // Enable ULPI clock if external PHY is used
786 let ulpien = !self.phy_type.internal();
787 critical_section::with(|_| {
788 crate::pac::RCC.ahb1enr().modify(|w| {
789 if T::HIGH_SPEED {
790 w.set_usb_otg_hsulpien(ulpien);
791 } else {
792 w.set_usb_otg_hsen(ulpien);
793 }
794 });
795
796 // Low power mode
797 crate::pac::RCC.ahb1lpenr().modify(|w| {
798 if T::HIGH_SPEED {
799 w.set_usb_otg_hsulpilpen(ulpien);
800 } else {
801 w.set_usb_otg_hslpen(ulpien);
802 }
803 });
804 });
805 }
806
807 #[cfg(stm32h7)]
808 {
809 // If true, VDD33USB is generated by internal regulator from VDD50USB
810 // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
811 // TODO: unhardcode
812 let internal_regulator = false;
813
814 // Enable USB power
815 critical_section::with(|_| {
816 crate::pac::PWR.cr3().modify(|w| {
817 w.set_usb33den(true);
818 w.set_usbregen(internal_regulator);
819 })
820 });
821
822 // Wait for USB power to stabilize
823 while !crate::pac::PWR.cr3().read().usb33rdy() {}
824
825 // Use internal 48MHz HSI clock. Should be enabled in RCC by default.
826 critical_section::with(|_| {
827 crate::pac::RCC
828 .d2ccip2r()
829 .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48))
830 });
831
832 // Enable ULPI clock if external PHY is used
833 let ulpien = !self.phy_type.internal();
834 critical_section::with(|_| {
835 crate::pac::RCC.ahb1enr().modify(|w| {
836 if T::HIGH_SPEED {
837 w.set_usb_otg_hs_ulpien(ulpien);
838 } else {
839 w.set_usb_otg_fs_ulpien(ulpien);
840 }
841 });
842 crate::pac::RCC.ahb1lpenr().modify(|w| {
843 if T::HIGH_SPEED {
844 w.set_usb_otg_hs_ulpilpen(ulpien);
845 } else {
846 w.set_usb_otg_fs_ulpilpen(ulpien);
847 }
848 });
849 });
850 }
851
852 #[cfg(stm32u5)]
853 {
854 // Enable USB power
855 critical_section::with(|_| {
856 crate::pac::RCC.ahb3enr().modify(|w| {
857 w.set_pwren(true);
858 });
859 cortex_m::asm::delay(2);
860
861 crate::pac::PWR.svmcr().modify(|w| {
862 w.set_usv(true);
863 w.set_uvmen(true);
864 });
865 });
866
867 // Wait for USB power to stabilize
868 while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
869
870 // Select HSI48 as USB clock source.
871 critical_section::with(|_| {
872 crate::pac::RCC.ccipr1().modify(|w| {
873 w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48);
874 })
875 });
876 }
877
878 <T as RccPeripheral>::enable();
879 <T as RccPeripheral>::reset();
880
881 T::Interrupt::unpend();
882 unsafe { T::Interrupt::enable() };
883
884 let r = T::regs();
885 let core_id = r.cid().read().0;
886 info!("Core id {:08x}", core_id);
887
888 // Wait for AHB ready.
889 while !r.grstctl().read().ahbidl() {}
890
891 // Configure as device.
892 r.gusbcfg().write(|w| {
893 // Force device mode
894 w.set_fdmod(true);
895 // Enable internal full-speed PHY
896 w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed());
897 });
898
899 // Configuring Vbus sense and SOF output
900 match core_id {
901 0x0000_1200 | 0x0000_1100 => {
902 assert!(self.phy_type != PhyType::InternalHighSpeed);
903
904 r.gccfg_v1().modify(|w| {
905 // Enable internal full-speed PHY, logic is inverted
906 w.set_pwrdwn(self.phy_type.internal());
907 });
908
909 // F429-like chips have the GCCFG.NOVBUSSENS bit
910 r.gccfg_v1().modify(|w| {
911 w.set_novbussens(true);
912 w.set_vbusasen(false);
913 w.set_vbusbsen(false);
914 w.set_sofouten(false);
915 });
916 }
917 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => {
918 // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning
919 r.gccfg_v2().modify(|w| {
920 // Enable internal full-speed PHY, logic is inverted
921 w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed());
922 w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed());
923 });
924
925 r.gccfg_v2().modify(|w| {
926 w.set_vbden(false);
927 });
928
929 // Force B-peripheral session
930 r.gotgctl().modify(|w| {
931 w.set_bvaloen(true);
932 w.set_bvaloval(true);
933 });
934 }
935 _ => unimplemented!("Unknown USB core id {:X}", core_id),
936 }
937
938 // Soft disconnect.
939 r.dctl().write(|w| w.set_sdis(true));
940
941 // Set speed.
942 r.dcfg().write(|w| {
943 w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80);
944 w.set_dspd(self.phy_type.to_dspd());
945 });
946
947 // Unmask transfer complete EP interrupt
948 r.diepmsk().write(|w| {
949 w.set_xfrcm(true);
950 });
951
952 // Unmask and clear core interrupts
953 Bus::<T>::restore_irqs();
954 r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF));
955
956 // Unmask global interrupt
957 r.gahbcfg().write(|w| {
958 w.set_gint(true); // unmask global interrupt
959 });
960
961 // Connect
962 r.dctl().write(|w| w.set_sdis(false));
963
964 self.enabled = true;
965 } 1067 }
966 1068
967 async fn disable(&mut self) { 1069 async fn disable(&mut self) {
968 trace!("disable"); 1070 trace!("disable");
969 1071
970 Bus::disable(self); 1072 // TODO: disable the peripheral once enable/disable semantics are cleared up in embassy-usb
971 1073 //Bus::disable(self);
972 self.enabled = false;
973 } 1074 }
974 1075
975 async fn remote_wakeup(&mut self) -> Result<(), Unsupported> { 1076 async fn remote_wakeup(&mut self) -> Result<(), Unsupported> {
@@ -1112,11 +1213,16 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
1112 state.ep_in_wakers[index].register(cx.waker()); 1213 state.ep_in_wakers[index].register(cx.waker());
1113 1214
1114 let diepctl = r.diepctl(index).read(); 1215 let diepctl = r.diepctl(index).read();
1216 let dtxfsts = r.dtxfsts(index).read();
1217 info!("diepctl {:08x} ftxfsts {:08x}", diepctl.0, dtxfsts.0);
1115 if !diepctl.usbaep() { 1218 if !diepctl.usbaep() {
1219 trace!("write ep={:?} wait for prev: error disabled", self.info.addr);
1116 Poll::Ready(Err(EndpointError::Disabled)) 1220 Poll::Ready(Err(EndpointError::Disabled))
1117 } else if !diepctl.epena() { 1221 } else if !diepctl.epena() {
1222 trace!("write ep={:?} wait for prev: ready", self.info.addr);
1118 Poll::Ready(Ok(())) 1223 Poll::Ready(Ok(()))
1119 } else { 1224 } else {
1225 trace!("write ep={:?} wait for prev: pending", self.info.addr);
1120 Poll::Pending 1226 Poll::Pending
1121 } 1227 }
1122 }) 1228 })
@@ -1141,6 +1247,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
1141 1247
1142 Poll::Pending 1248 Poll::Pending
1143 } else { 1249 } else {
1250 trace!("write ep={:?} wait for fifo: ready", self.info.addr);
1144 Poll::Ready(()) 1251 Poll::Ready(())
1145 } 1252 }
1146 }) 1253 })
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs
index 5907a4e54..b03e81d6e 100644
--- a/embassy-stm32/src/wdg/mod.rs
+++ b/embassy-stm32/src/wdg/mod.rs
@@ -49,7 +49,7 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
49 49
50 let wdg = T::regs(); 50 let wdg = T::regs();
51 wdg.kr().write(|w| w.set_key(Key::ENABLE)); 51 wdg.kr().write(|w| w.set_key(Key::ENABLE));
52 wdg.pr().write(|w| w.set_pr(Pr(pr))); 52 wdg.pr().write(|w| w.set_pr(Pr::from_bits(pr)));
53 wdg.rlr().write(|w| w.set_rl(rl)); 53 wdg.rlr().write(|w| w.set_rl(rl));
54 54
55 trace!( 55 trace!(
diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs
index db6ebb08b..13bf4ef01 100644
--- a/embassy-sync/src/pipe.rs
+++ b/embassy-sync/src/pipe.rs
@@ -282,7 +282,7 @@ where
282 /// returns the amount of bytes written. 282 /// returns the amount of bytes written.
283 /// 283 ///
284 /// If it is not possible to write a nonzero amount of bytes because the pipe's buffer is full, 284 /// If it is not possible to write a nonzero amount of bytes because the pipe's buffer is full,
285 /// this method will wait until it is. See [`try_write`](Self::try_write) for a variant that 285 /// this method will wait until it isn't. See [`try_write`](Self::try_write) for a variant that
286 /// returns an error instead of waiting. 286 /// returns an error instead of waiting.
287 /// 287 ///
288 /// It is not guaranteed that all bytes in the buffer are written, even if there's enough 288 /// It is not guaranteed that all bytes in the buffer are written, even if there's enough
@@ -319,7 +319,7 @@ where
319 /// returns the amount of bytes read. 319 /// returns the amount of bytes read.
320 /// 320 ///
321 /// If it is not possible to read a nonzero amount of bytes because the pipe's buffer is empty, 321 /// If it is not possible to read a nonzero amount of bytes because the pipe's buffer is empty,
322 /// this method will wait until it is. See [`try_read`](Self::try_read) for a variant that 322 /// this method will wait until it isn't. See [`try_read`](Self::try_read) for a variant that
323 /// returns an error instead of waiting. 323 /// returns an error instead of waiting.
324 /// 324 ///
325 /// It is not guaranteed that all bytes in the buffer are read, even if there's enough 325 /// It is not guaranteed that all bytes in the buffer are read, even if there's enough
diff --git a/embassy-usb/src/class/cdc_ncm/embassy_net.rs b/embassy-usb/src/class/cdc_ncm/embassy_net.rs
index bc79b3671..670709021 100644
--- a/embassy-usb/src/class/cdc_ncm/embassy_net.rs
+++ b/embassy-usb/src/class/cdc_ncm/embassy_net.rs
@@ -1,4 +1,5 @@
1//! [`embassy-net`](crates.io/crates/embassy-net) driver for the CDC-NCM class. 1//! [`embassy-net`](https://crates.io/crates/embassy-net) driver for the CDC-NCM class.
2
2use embassy_futures::select::{select, Either}; 3use embassy_futures::select::{select, Either};
3use embassy_net_driver_channel as ch; 4use embassy_net_driver_channel as ch;
4use embassy_net_driver_channel::driver::LinkState; 5use embassy_net_driver_channel::driver::LinkState;
@@ -79,7 +80,7 @@ impl<'d, D: Driver<'d>, const MTU: usize> Runner<'d, D, MTU> {
79pub type Device<'d, const MTU: usize> = embassy_net_driver_channel::Device<'d, MTU>; 80pub type Device<'d, const MTU: usize> = embassy_net_driver_channel::Device<'d, MTU>;
80 81
81impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> { 82impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> {
82 /// Obtain a driver for using the CDC-NCM class with [`embassy-net`](crates.io/crates/embassy-net). 83 /// Obtain a driver for using the CDC-NCM class with [`embassy-net`](https://crates.io/crates/embassy-net).
83 pub fn into_embassy_net_device<const MTU: usize, const N_RX: usize, const N_TX: usize>( 84 pub fn into_embassy_net_device<const MTU: usize, const N_RX: usize, const N_TX: usize>(
84 self, 85 self,
85 state: &'d mut State<MTU, N_RX, N_TX>, 86 state: &'d mut State<MTU, N_RX, N_TX>,
diff --git a/embassy-usb/src/class/cdc_ncm/mod.rs b/embassy-usb/src/class/cdc_ncm/mod.rs
index d5556dd0b..fcfa0bfcd 100644
--- a/embassy-usb/src/class/cdc_ncm/mod.rs
+++ b/embassy-usb/src/class/cdc_ncm/mod.rs
@@ -11,8 +11,8 @@
11//! - On Pixel 4a, it refused to work on Android 11, worked on Android 12. 11//! - On Pixel 4a, it refused to work on Android 11, worked on Android 12.
12//! - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte), 12//! - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte),
13//! it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled. 13//! it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled.
14//! This is due to regex spaghetti: https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-12.0.0_r84/core/res/res/values/config.xml#417 14//! This is due to regex spaghetti: <https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-12.0.0_r84/core/res/res/values/config.xml#417>
15//! and this nonsense in the linux kernel: https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757 15//! and this nonsense in the linux kernel: <https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757>
16 16
17use core::intrinsics::copy_nonoverlapping; 17use core::intrinsics::copy_nonoverlapping;
18use core::mem::{size_of, MaybeUninit}; 18use core::mem::{size_of, MaybeUninit};
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index d8563d59a..1180b9b66 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -23,7 +23,7 @@ mod config {
23use embassy_futures::select::{select, Either}; 23use embassy_futures::select::{select, Either};
24use heapless::Vec; 24use heapless::Vec;
25 25
26pub use crate::builder::{Builder, Config}; 26pub use crate::builder::{Builder, Config, FunctionBuilder, InterfaceAltBuilder, InterfaceBuilder};
27use crate::config::*; 27use crate::config::*;
28use crate::control::*; 28use crate::control::*;
29use crate::descriptor::*; 29use crate::descriptor::*;
diff --git a/examples/boot/application/nrf/.cargo/config.toml b/examples/boot/application/nrf/.cargo/config.toml
index 3872e7189..17616a054 100644
--- a/examples/boot/application/nrf/.cargo/config.toml
+++ b/examples/boot/application/nrf/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-rs-cli chip list` 2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip nRF52840_xxAA" 3runner = "probe-rs run --chip nRF52840_xxAA"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/examples/boot/application/rp/.cargo/config.toml b/examples/boot/application/rp/.cargo/config.toml
index 278c24a57..cd8d1ef02 100644
--- a/examples/boot/application/rp/.cargo/config.toml
+++ b/examples/boot/application/rp/.cargo/config.toml
@@ -3,7 +3,7 @@ build-std = ["core"]
3build-std-features = ["panic_immediate_abort"] 3build-std-features = ["panic_immediate_abort"]
4 4
5[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 5[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6runner = "probe-rs-cli run --chip RP2040" 6runner = "probe-rs run --chip RP2040"
7 7
8[build] 8[build]
9target = "thumbv6m-none-eabi" 9target = "thumbv6m-none-eabi"
diff --git a/examples/boot/application/stm32f3/.cargo/config.toml b/examples/boot/application/stm32f3/.cargo/config.toml
index 9fc2396e8..4a7ec0a5b 100644
--- a/examples/boot/application/stm32f3/.cargo/config.toml
+++ b/examples/boot/application/stm32f3/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32F303VCTx" 3runner = "probe-rs run --chip STM32F303VCTx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/boot/application/stm32f7/.cargo/config.toml b/examples/boot/application/stm32f7/.cargo/config.toml
index 7d6c88a99..9088eea6e 100644
--- a/examples/boot/application/stm32f7/.cargo/config.toml
+++ b/examples/boot/application/stm32f7/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32F767ZITx" 3runner = "probe-rs run --chip STM32F767ZITx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/boot/application/stm32h7/.cargo/config.toml b/examples/boot/application/stm32h7/.cargo/config.toml
index 067a5c89b..caa0d3a93 100644
--- a/examples/boot/application/stm32h7/.cargo/config.toml
+++ b/examples/boot/application/stm32h7/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32H743ZITx" 3runner = "probe-rs run --chip STM32H743ZITx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/boot/application/stm32h7/flash-boot.sh b/examples/boot/application/stm32h7/flash-boot.sh
index a3003681a..4912a50b7 100755
--- a/examples/boot/application/stm32h7/flash-boot.sh
+++ b/examples/boot/application/stm32h7/flash-boot.sh
@@ -1,5 +1,5 @@
1#!/bin/bash 1#!/bin/bash
2probe-rs-cli erase --chip STM32H743ZITx 2probe-rs erase --chip STM32H743ZITx
3mv ../../bootloader/stm32/memory.x ../../bootloader/stm32/memory-old.x 3mv ../../bootloader/stm32/memory.x ../../bootloader/stm32/memory-old.x
4cp memory-bl.x ../../bootloader/stm32/memory.x 4cp memory-bl.x ../../bootloader/stm32/memory.x
5 5
diff --git a/examples/boot/application/stm32l0/.cargo/config.toml b/examples/boot/application/stm32l0/.cargo/config.toml
index ce0e460bd..6099f015c 100644
--- a/examples/boot/application/stm32l0/.cargo/config.toml
+++ b/examples/boot/application/stm32l0/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs-cli chip list` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32L072CZTx" 3runner = "probe-rs run --chip STM32L072CZTx"
4 4
5[build] 5[build]
6target = "thumbv6m-none-eabi" 6target = "thumbv6m-none-eabi"
diff --git a/examples/boot/application/stm32l1/.cargo/config.toml b/examples/boot/application/stm32l1/.cargo/config.toml
index 1401500a0..9cabd14ba 100644
--- a/examples/boot/application/stm32l1/.cargo/config.toml
+++ b/examples/boot/application/stm32l1/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs-cli chip list` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32L151CBxxA" 3runner = "probe-rs run --chip STM32L151CBxxA"
4 4
5[build] 5[build]
6target = "thumbv7m-none-eabi" 6target = "thumbv7m-none-eabi"
diff --git a/examples/boot/application/stm32l4/.cargo/config.toml b/examples/boot/application/stm32l4/.cargo/config.toml
index 48ff3734b..c803215f6 100644
--- a/examples/boot/application/stm32l4/.cargo/config.toml
+++ b/examples/boot/application/stm32l4/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs-cli chip list` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32L475VG" 3runner = "probe-rs run --chip STM32L475VG"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/boot/application/stm32wl/.cargo/config.toml b/examples/boot/application/stm32wl/.cargo/config.toml
index b49b582e0..4f8094ff2 100644
--- a/examples/boot/application/stm32wl/.cargo/config.toml
+++ b/examples/boot/application/stm32wl/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs-cli chip list` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32WLE5JCIx" 3runner = "probe-rs run --chip STM32WLE5JCIx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/boot/bootloader/nrf/.cargo/config.toml b/examples/boot/bootloader/nrf/.cargo/config.toml
index d636b1d23..c292846aa 100644
--- a/examples/boot/bootloader/nrf/.cargo/config.toml
+++ b/examples/boot/bootloader/nrf/.cargo/config.toml
@@ -4,7 +4,7 @@ build-std-features = ["panic_immediate_abort"]
4 4
5[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 5[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6#runner = "./fruitrunner" 6#runner = "./fruitrunner"
7runner = "probe-rs-cli run --chip nrf52840_xxAA" 7runner = "probe-rs run --chip nrf52840_xxAA"
8 8
9rustflags = [ 9rustflags = [
10 # Code-size optimizations. 10 # Code-size optimizations.
diff --git a/examples/boot/bootloader/rp/.cargo/config.toml b/examples/boot/bootloader/rp/.cargo/config.toml
index 795ee043a..9d48ecdc9 100644
--- a/examples/boot/bootloader/rp/.cargo/config.toml
+++ b/examples/boot/bootloader/rp/.cargo/config.toml
@@ -1,5 +1,5 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-rs-cli run --chip RP2040" 2runner = "probe-rs run --chip RP2040"
3 3
4[build] 4[build]
5target = "thumbv6m-none-eabi" 5target = "thumbv6m-none-eabi"
diff --git a/examples/nrf-rtos-trace/.cargo/config.toml b/examples/nrf-rtos-trace/.cargo/config.toml
index 3872e7189..17616a054 100644
--- a/examples/nrf-rtos-trace/.cargo/config.toml
+++ b/examples/nrf-rtos-trace/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-rs-cli chip list` 2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip nRF52840_xxAA" 3runner = "probe-rs run --chip nRF52840_xxAA"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/examples/nrf52840-rtic/.cargo/config.toml b/examples/nrf52840-rtic/.cargo/config.toml
index 3872e7189..17616a054 100644
--- a/examples/nrf52840-rtic/.cargo/config.toml
+++ b/examples/nrf52840-rtic/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-rs-cli chip list` 2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip nRF52840_xxAA" 3runner = "probe-rs run --chip nRF52840_xxAA"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/examples/nrf52840/.cargo/config.toml b/examples/nrf52840/.cargo/config.toml
index 3872e7189..17616a054 100644
--- a/examples/nrf52840/.cargo/config.toml
+++ b/examples/nrf52840/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-rs-cli chip list` 2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip nRF52840_xxAA" 3runner = "probe-rs run --chip nRF52840_xxAA"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/examples/nrf52840/src/bin/nvmc.rs b/examples/nrf52840/src/bin/nvmc.rs
index 33a44516d..31c6fe4b6 100644
--- a/examples/nrf52840/src/bin/nvmc.rs
+++ b/examples/nrf52840/src/bin/nvmc.rs
@@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
14 let p = embassy_nrf::init(Default::default()); 14 let p = embassy_nrf::init(Default::default());
15 info!("Hello NVMC!"); 15 info!("Hello NVMC!");
16 16
17 // probe-rs-cli run breaks without this, I'm not sure why. 17 // probe-rs run breaks without this, I'm not sure why.
18 Timer::after(Duration::from_secs(1)).await; 18 Timer::after(Duration::from_secs(1)).await;
19 19
20 let mut f = Nvmc::new(p.NVMC); 20 let mut f = Nvmc::new(p.NVMC);
diff --git a/examples/nrf52840/src/bin/wdt.rs b/examples/nrf52840/src/bin/wdt.rs
index ccfd0e439..058746518 100644
--- a/examples/nrf52840/src/bin/wdt.rs
+++ b/examples/nrf52840/src/bin/wdt.rs
@@ -16,7 +16,7 @@ async fn main(_spawner: Spawner) {
16 let mut config = Config::default(); 16 let mut config = Config::default();
17 config.timeout_ticks = 32768 * 3; // 3 seconds 17 config.timeout_ticks = 32768 * 3; // 3 seconds
18 18
19 // This is needed for `probe-rs-cli run` to be able to catch the panic message 19 // This is needed for `probe-rs run` to be able to catch the panic message
20 // in the WDT interrupt. The core resets 2 ticks after firing the interrupt. 20 // in the WDT interrupt. The core resets 2 ticks after firing the interrupt.
21 config.run_during_debug_halt = false; 21 config.run_during_debug_halt = false;
22 22
diff --git a/examples/nrf5340/.cargo/config.toml b/examples/nrf5340/.cargo/config.toml
index d25355894..4c3cf3d32 100644
--- a/examples/nrf5340/.cargo/config.toml
+++ b/examples/nrf5340/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF5340_xxAA with your chip as listed in `probe-rs-cli chip list` 2# replace nRF5340_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip nRF5340_xxAA" 3runner = "probe-rs run --chip nRF5340_xxAA"
4 4
5[build] 5[build]
6target = "thumbv8m.main-none-eabihf" 6target = "thumbv8m.main-none-eabihf"
diff --git a/examples/rp/.cargo/config.toml b/examples/rp/.cargo/config.toml
index 2ee6fcb00..3d7d61740 100644
--- a/examples/rp/.cargo/config.toml
+++ b/examples/rp/.cargo/config.toml
@@ -1,5 +1,5 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-rs-cli run --chip RP2040" 2runner = "probe-rs run --chip RP2040"
3 3
4[build] 4[build]
5target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ 5target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs
index e8197390c..310e84d92 100644
--- a/examples/rp/src/bin/wifi_ap_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs
@@ -42,8 +42,8 @@ async fn main(spawner: Spawner) {
42 42
43 // To make flashing faster for development, you may want to flash the firmwares independently 43 // To make flashing faster for development, you may want to flash the firmwares independently
44 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: 44 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
45 // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 45 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
46 // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 46 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
47 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; 47 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
48 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; 48 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
49 49
diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs
index be965807b..bbcb1b5ec 100644
--- a/examples/rp/src/bin/wifi_blinky.rs
+++ b/examples/rp/src/bin/wifi_blinky.rs
@@ -27,8 +27,8 @@ async fn main(spawner: Spawner) {
27 27
28 // To make flashing faster for development, you may want to flash the firmwares independently 28 // To make flashing faster for development, you may want to flash the firmwares independently
29 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: 29 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
30 // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 30 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
31 // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 31 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
32 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; 32 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
33 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; 33 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
34 34
diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs
index 79534f229..391e12282 100644
--- a/examples/rp/src/bin/wifi_scan.rs
+++ b/examples/rp/src/bin/wifi_scan.rs
@@ -39,8 +39,8 @@ async fn main(spawner: Spawner) {
39 39
40 // To make flashing faster for development, you may want to flash the firmwares independently 40 // To make flashing faster for development, you may want to flash the firmwares independently
41 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: 41 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
42 // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 42 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
43 // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 43 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
44 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; 44 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
45 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; 45 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
46 46
diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs
index 026e056fa..e9d1079a6 100644
--- a/examples/rp/src/bin/wifi_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_tcp_server.rs
@@ -42,8 +42,8 @@ async fn main(spawner: Spawner) {
42 42
43 // To make flashing faster for development, you may want to flash the firmwares independently 43 // To make flashing faster for development, you may want to flash the firmwares independently
44 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: 44 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
45 // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 45 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
46 // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 46 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
47 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; 47 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
48 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; 48 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
49 49
diff --git a/examples/std/README.md b/examples/std/README.md
new file mode 100644
index 000000000..adc795928
--- /dev/null
+++ b/examples/std/README.md
@@ -0,0 +1,23 @@
1
2## Running the `embassy-net` examples
3
4First, create the tap0 interface. You only need to do this once.
5
6```sh
7sudo ip tuntap add name tap0 mode tap user $USER
8sudo ip link set tap0 up
9sudo ip addr add 192.168.69.100/24 dev tap0
10sudo ip -6 addr add fe80::100/64 dev tap0
11sudo ip -6 addr add fdaa::100/64 dev tap0
12sudo ip -6 route add fe80::/64 dev tap0
13sudo ip -6 route add fdaa::/64 dev tap0
14```
15
16Second, have something listening there. For example `nc -l 8000`
17
18Then run the example located in the `examples` folder:
19
20```sh
21cd $EMBASSY_ROOT/examples/std/
22cargo run --bin net -- --static-ip
23``` \ No newline at end of file
diff --git a/examples/stm32c0/.cargo/config.toml b/examples/stm32c0/.cargo/config.toml
index 517101fae..29a8be7e1 100644
--- a/examples/stm32c0/.cargo/config.toml
+++ b/examples/stm32c0/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32G071C8Rx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --speed 100 --chip STM32c031c6tx" 3runner = "probe-rs run --speed 100 --chip STM32c031c6tx"
4 4
5[build] 5[build]
6target = "thumbv6m-none-eabi" 6target = "thumbv6m-none-eabi"
diff --git a/examples/stm32f0/.cargo/config.toml b/examples/stm32f0/.cargo/config.toml
index bd0c0cd97..def4c8c92 100644
--- a/examples/stm32f0/.cargo/config.toml
+++ b/examples/stm32f0/.cargo/config.toml
@@ -1,5 +1,5 @@
1[target.thumbv6m-none-eabi] 1[target.thumbv6m-none-eabi]
2runner = 'probe-rs-cli run --chip STM32F091RCTX' 2runner = 'probe-rs run --chip STM32F091RCTX'
3 3
4[build] 4[build]
5target = "thumbv6m-none-eabi" 5target = "thumbv6m-none-eabi"
diff --git a/examples/stm32f1/.cargo/config.toml b/examples/stm32f1/.cargo/config.toml
index 81199c5aa..ce6fef11b 100644
--- a/examples/stm32f1/.cargo/config.toml
+++ b/examples/stm32f1/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F103C8 with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F103C8 with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32F103C8" 3runner = "probe-rs run --chip STM32F103C8"
4 4
5[build] 5[build]
6target = "thumbv7m-none-eabi" 6target = "thumbv7m-none-eabi"
diff --git a/examples/stm32f2/.cargo/config.toml b/examples/stm32f2/.cargo/config.toml
index 5532779c8..1198fcab8 100644
--- a/examples/stm32f2/.cargo/config.toml
+++ b/examples/stm32f2/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F207ZGTx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F207ZGTx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32F207ZGTx" 3runner = "probe-rs run --chip STM32F207ZGTx"
4 4
5[build] 5[build]
6target = "thumbv7m-none-eabi" 6target = "thumbv7m-none-eabi"
diff --git a/examples/stm32f3/.cargo/config.toml b/examples/stm32f3/.cargo/config.toml
index 7f3fda529..cb8a7c5af 100644
--- a/examples/stm32f3/.cargo/config.toml
+++ b/examples/stm32f3/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32F303ZETx" 3runner = "probe-rs run --chip STM32F303ZETx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/stm32f4/.cargo/config.toml b/examples/stm32f4/.cargo/config.toml
index bed04b68f..16efa8e6f 100644
--- a/examples/stm32f4/.cargo/config.toml
+++ b/examples/stm32f4/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32F429ZITx" 3runner = "probe-rs run --chip STM32F429ZITx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/examples/stm32f4/src/bin/dac.rs b/examples/stm32f4/src/bin/dac.rs
index d97ae7082..3a6216712 100644
--- a/examples/stm32f4/src/bin/dac.rs
+++ b/examples/stm32f4/src/bin/dac.rs
@@ -4,7 +4,8 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dac::{Channel, Dac, Value}; 7use embassy_stm32::dac::{DacCh1, DacChannel, Value};
8use embassy_stm32::dma::NoDma;
8use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
9 10
10#[embassy_executor::main] 11#[embassy_executor::main]
@@ -12,12 +13,12 @@ async fn main(_spawner: Spawner) -> ! {
12 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
13 info!("Hello World, dude!"); 14 info!("Hello World, dude!");
14 15
15 let mut dac = Dac::new_1ch(p.DAC, p.PA4); 16 let mut dac = DacCh1::new(p.DAC, NoDma, p.PA4);
16 17
17 loop { 18 loop {
18 for v in 0..=255 { 19 for v in 0..=255 {
19 unwrap!(dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v)))); 20 unwrap!(dac.set(Value::Bit8(to_sine_wave(v))));
20 unwrap!(dac.trigger(Channel::Ch1)); 21 dac.trigger();
21 } 22 }
22 } 23 }
23} 24}
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
index 953d99a45..b1f01417c 100644
--- a/examples/stm32f4/src/bin/usb_ethernet.rs
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -52,7 +52,9 @@ async fn main(spawner: Spawner) {
52 52
53 // Create the driver, from the HAL. 53 // Create the driver, from the HAL.
54 let ep_out_buffer = &mut make_static!([0; 256])[..]; 54 let ep_out_buffer = &mut make_static!([0; 256])[..];
55 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer); 55 let mut config = embassy_stm32::usb_otg::Config::default();
56 config.vbus_detection = true;
57 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config);
56 58
57 // Create embassy-usb Config 59 // Create embassy-usb Config
58 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 60 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs
index f8f5940a7..4ff6452ef 100644
--- a/examples/stm32f4/src/bin/usb_serial.rs
+++ b/examples/stm32f4/src/bin/usb_serial.rs
@@ -29,7 +29,9 @@ async fn main(_spawner: Spawner) {
29 29
30 // Create the driver, from the HAL. 30 // Create the driver, from the HAL.
31 let mut ep_out_buffer = [0u8; 256]; 31 let mut ep_out_buffer = [0u8; 256];
32 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); 32 let mut config = embassy_stm32::usb_otg::Config::default();
33 config.vbus_detection = true;
34 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
33 35
34 // Create embassy-usb Config 36 // Create embassy-usb Config
35 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 37 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32f7/.cargo/config.toml b/examples/stm32f7/.cargo/config.toml
index 7d6c88a99..9088eea6e 100644
--- a/examples/stm32f7/.cargo/config.toml
+++ b/examples/stm32f7/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32F767ZITx" 3runner = "probe-rs run --chip STM32F767ZITx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs
index 763309ce2..a2c76178b 100644
--- a/examples/stm32f7/src/bin/usb_serial.rs
+++ b/examples/stm32f7/src/bin/usb_serial.rs
@@ -30,7 +30,9 @@ async fn main(_spawner: Spawner) {
30 30
31 // Create the driver, from the HAL. 31 // Create the driver, from the HAL.
32 let mut ep_out_buffer = [0u8; 256]; 32 let mut ep_out_buffer = [0u8; 256];
33 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); 33 let mut config = embassy_stm32::usb_otg::Config::default();
34 config.vbus_detection = true;
35 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
34 36
35 // Create embassy-usb Config 37 // Create embassy-usb Config
36 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 38 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32g0/.cargo/config.toml b/examples/stm32g0/.cargo/config.toml
index a7a5fbd84..35cca5412 100644
--- a/examples/stm32g0/.cargo/config.toml
+++ b/examples/stm32g0/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32G071C8Rx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32G071RBTx" 3runner = "probe-rs run --chip STM32G071RBTx"
4 4
5[build] 5[build]
6target = "thumbv6m-none-eabi" 6target = "thumbv6m-none-eabi"
diff --git a/examples/stm32g4/.cargo/config.toml b/examples/stm32g4/.cargo/config.toml
index 606d7d5a3..d28ad069e 100644
--- a/examples/stm32g4/.cargo/config.toml
+++ b/examples/stm32g4/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32G071C8Rx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32G484VETx" 3runner = "probe-rs run --chip STM32G484VETx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
index c111a9787..77cfa67d3 100644
--- a/examples/stm32g4/src/bin/usb_serial.rs
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -4,10 +4,10 @@
4 4
5use defmt::{panic, *}; 5use defmt::{panic, *};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::rcc::{ClockSrc, Pll, PllM, PllN, PllQ, PllR, PllSrc}; 7use embassy_stm32::rcc::{Clock48MhzSrc, ClockSrc, CrsConfig, CrsSyncSource, Pll, PllM, PllN, PllQ, PllR, PllSrc};
8use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
9use embassy_stm32::usb::{self, Driver, Instance}; 9use embassy_stm32::usb::{self, Driver, Instance};
10use embassy_stm32::{bind_interrupts, pac, peripherals, Config}; 10use embassy_stm32::{bind_interrupts, peripherals, Config};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError; 12use embassy_usb::driver::EndpointError;
13use embassy_usb::Builder; 13use embassy_usb::Builder;
@@ -22,23 +22,35 @@ bind_interrupts!(struct Irqs {
22async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
23 let mut config = Config::default(); 23 let mut config = Config::default();
24 24
25 // Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE.
26 const USE_HSI48: bool = true;
27
28 let pllq_div = if USE_HSI48 { None } else { Some(PllQ::Div6) };
29
25 config.rcc.pll = Some(Pll { 30 config.rcc.pll = Some(Pll {
26 source: PllSrc::HSE(Hertz(8000000)), 31 source: PllSrc::HSE(Hertz(8_000_000)),
27 prediv_m: PllM::Div2, 32 prediv_m: PllM::Div2,
28 mul_n: PllN::Mul72, 33 mul_n: PllN::Mul72,
29 div_p: None, 34 div_p: None,
30 // USB and CAN at 48 MHz 35 div_q: pllq_div,
31 div_q: Some(PllQ::Div6),
32 // Main system clock at 144 MHz 36 // Main system clock at 144 MHz
33 div_r: Some(PllR::Div2), 37 div_r: Some(PllR::Div2),
34 }); 38 });
35 39
36 config.rcc.mux = ClockSrc::PLL; 40 config.rcc.mux = ClockSrc::PLL;
37 41
42 if USE_HSI48 {
43 // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator.
44 config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::Hsi48(Some(CrsConfig {
45 sync_src: CrsSyncSource::Usb,
46 })));
47 } else {
48 config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::PllQ);
49 }
50
38 let p = embassy_stm32::init(config); 51 let p = embassy_stm32::init(config);
39 info!("Hello World!");
40 52
41 pac::RCC.ccipr().write(|w| w.set_clk48sel(0b10)); 53 info!("Hello World!");
42 54
43 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); 55 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
44 56
diff --git a/examples/stm32h5/.cargo/config.toml b/examples/stm32h5/.cargo/config.toml
index c8b864b6c..478146142 100644
--- a/examples/stm32h5/.cargo/config.toml
+++ b/examples/stm32h5/.cargo/config.toml
@@ -1,5 +1,5 @@
1[target.thumbv8m.main-none-eabihf] 1[target.thumbv8m.main-none-eabihf]
2runner = 'probe-rs-cli run --chip STM32H563ZITx' 2runner = 'probe-rs run --chip STM32H563ZITx'
3 3
4[build] 4[build]
5target = "thumbv8m.main-none-eabihf" 5target = "thumbv8m.main-none-eabihf"
diff --git a/examples/stm32h7/.cargo/config.toml b/examples/stm32h7/.cargo/config.toml
index f08f57a54..5f680dbce 100644
--- a/examples/stm32h7/.cargo/config.toml
+++ b/examples/stm32h7/.cargo/config.toml
@@ -1,5 +1,5 @@
1[target.thumbv7em-none-eabihf] 1[target.thumbv7em-none-eabihf]
2runner = 'probe-rs-cli run --chip STM32H743ZITx' 2runner = 'probe-rs run --chip STM32H743ZITx'
3 3
4[build] 4[build]
5target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) 5target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs
index f12716370..586b4154b 100644
--- a/examples/stm32h7/src/bin/dac.rs
+++ b/examples/stm32h7/src/bin/dac.rs
@@ -4,7 +4,8 @@
4 4
5use cortex_m_rt::entry; 5use cortex_m_rt::entry;
6use defmt::*; 6use defmt::*;
7use embassy_stm32::dac::{Channel, Dac, Value}; 7use embassy_stm32::dac::{DacCh1, DacChannel, Value};
8use embassy_stm32::dma::NoDma;
8use embassy_stm32::time::mhz; 9use embassy_stm32::time::mhz;
9use embassy_stm32::Config; 10use embassy_stm32::Config;
10use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
@@ -19,12 +20,12 @@ fn main() -> ! {
19 config.rcc.pll1.q_ck = Some(mhz(100)); 20 config.rcc.pll1.q_ck = Some(mhz(100));
20 let p = embassy_stm32::init(config); 21 let p = embassy_stm32::init(config);
21 22
22 let mut dac = Dac::new_1ch(p.DAC1, p.PA4); 23 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
23 24
24 loop { 25 loop {
25 for v in 0..=255 { 26 for v in 0..=255 {
26 unwrap!(dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v)))); 27 unwrap!(dac.set(Value::Bit8(to_sine_wave(v))));
27 unwrap!(dac.trigger(Channel::Ch1)); 28 dac.trigger();
28 } 29 }
29 } 30 }
30} 31}
diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs
index c622f19f7..97291f60c 100644
--- a/examples/stm32h7/src/bin/usb_serial.rs
+++ b/examples/stm32h7/src/bin/usb_serial.rs
@@ -29,7 +29,9 @@ async fn main(_spawner: Spawner) {
29 29
30 // Create the driver, from the HAL. 30 // Create the driver, from the HAL.
31 let mut ep_out_buffer = [0u8; 256]; 31 let mut ep_out_buffer = [0u8; 256];
32 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); 32 let mut config = embassy_stm32::usb_otg::Config::default();
33 config.vbus_detection = true;
34 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
33 35
34 // Create embassy-usb Config 36 // Create embassy-usb Config
35 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 37 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32l0/.cargo/config.toml b/examples/stm32l0/.cargo/config.toml
index 526f5a1f7..b050334b2 100644
--- a/examples/stm32l0/.cargo/config.toml
+++ b/examples/stm32l0/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs-cli chip list` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32L053R8Tx" 3runner = "probe-rs run --chip STM32L053R8Tx"
4 4
5[build] 5[build]
6target = "thumbv6m-none-eabi" 6target = "thumbv6m-none-eabi"
diff --git a/examples/stm32l1/.cargo/config.toml b/examples/stm32l1/.cargo/config.toml
index 1401500a0..9cabd14ba 100644
--- a/examples/stm32l1/.cargo/config.toml
+++ b/examples/stm32l1/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs-cli chip list` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32L151CBxxA" 3runner = "probe-rs run --chip STM32L151CBxxA"
4 4
5[build] 5[build]
6target = "thumbv7m-none-eabi" 6target = "thumbv7m-none-eabi"
diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml
index abf55eb2e..36e74e5a5 100644
--- a/examples/stm32l4/.cargo/config.toml
+++ b/examples/stm32l4/.cargo/config.toml
@@ -1,8 +1,8 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3#runner = "probe-rs-cli run --chip STM32L475VGT6" 3#runner = "probe-rs run --chip STM32L475VGT6"
4#runner = "probe-rs-cli run --chip STM32L475VG" 4#runner = "probe-rs run --chip STM32L475VG"
5runner = "probe-rs-cli run --chip STM32L4S5VI" 5runner = "probe-rs run --chip STM32L4S5VI"
6 6
7[build] 7[build]
8target = "thumbv7em-none-eabi" 8target = "thumbv7em-none-eabi"
diff --git a/examples/stm32l4/src/bin/dac.rs b/examples/stm32l4/src/bin/dac.rs
index a36ed5d90..ade43eb35 100644
--- a/examples/stm32l4/src/bin/dac.rs
+++ b/examples/stm32l4/src/bin/dac.rs
@@ -3,26 +3,21 @@
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use defmt::*; 5use defmt::*;
6use embassy_stm32::dac::{Channel, Dac, Value}; 6use embassy_stm32::dac::{DacCh1, DacChannel, Value};
7use embassy_stm32::pac; 7use embassy_stm32::dma::NoDma;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[cortex_m_rt::entry] 10#[cortex_m_rt::entry]
11fn main() -> ! { 11fn main() -> ! {
12 info!("Hello World!");
13
14 pac::RCC.apb1enr1().modify(|w| {
15 w.set_dac1en(true);
16 });
17
18 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!");
19 14
20 let mut dac = Dac::new_1ch(p.DAC1, p.PA4); 15 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
21 16
22 loop { 17 loop {
23 for v in 0..=255 { 18 for v in 0..=255 {
24 unwrap!(dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v)))); 19 unwrap!(dac.set(Value::Bit8(to_sine_wave(v))));
25 unwrap!(dac.trigger(Channel::Ch1)); 20 dac.trigger();
26 } 21 }
27 } 22 }
28} 23}
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs
new file mode 100644
index 000000000..c27cc03e1
--- /dev/null
+++ b/examples/stm32l4/src/bin/dac_dma.rs
@@ -0,0 +1,137 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::dac::{DacChannel, ValueArray};
8use embassy_stm32::pac::timer::vals::{Mms, Opm};
9use embassy_stm32::peripherals::{TIM6, TIM7};
10use embassy_stm32::rcc::low_level::RccPeripheral;
11use embassy_stm32::time::Hertz;
12use embassy_stm32::timer::low_level::Basic16bitInstance;
13use micromath::F32Ext;
14use {defmt_rtt as _, panic_probe as _};
15
16pub type Dac1Type =
17 embassy_stm32::dac::DacCh1<'static, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH3>;
18
19pub type Dac2Type =
20 embassy_stm32::dac::DacCh2<'static, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH4>;
21
22#[embassy_executor::main]
23async fn main(spawner: Spawner) {
24 let config = embassy_stm32::Config::default();
25
26 // Initialize the board and obtain a Peripherals instance
27 let p: embassy_stm32::Peripherals = embassy_stm32::init(config);
28
29 // Obtain two independent channels (p.DAC1 can only be consumed once, though!)
30 let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split();
31
32 spawner.spawn(dac_task1(dac_ch1)).ok();
33 spawner.spawn(dac_task2(dac_ch2)).ok();
34}
35
36#[embassy_executor::task]
37async fn dac_task1(mut dac: Dac1Type) {
38 let data: &[u8; 256] = &calculate_array::<256>();
39
40 info!("TIM6 frequency is {}", TIM6::frequency());
41 const FREQUENCY: Hertz = Hertz::hz(200);
42
43 // Compute the reload value such that we obtain the FREQUENCY for the sine
44 let reload: u32 = (TIM6::frequency().0 / FREQUENCY.0) / data.len() as u32;
45
46 // Depends on your clock and on the specific chip used, you may need higher or lower values here
47 if reload < 10 {
48 error!("Reload value {} below threshold!", reload);
49 }
50
51 dac.select_trigger(embassy_stm32::dac::Ch1Trigger::Tim6).unwrap();
52 dac.enable_channel().unwrap();
53
54 TIM6::enable();
55 TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
56 TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE));
57 TIM6::regs().cr1().modify(|w| {
58 w.set_opm(Opm::DISABLED);
59 w.set_cen(true);
60 });
61
62 debug!(
63 "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}",
64 TIM6::frequency(),
65 FREQUENCY,
66 reload,
67 reload as u16,
68 data.len()
69 );
70
71 // Loop technically not necessary if DMA circular mode is enabled
72 loop {
73 info!("Loop DAC1");
74 if let Err(e) = dac.write(ValueArray::Bit8(data), true).await {
75 error!("Could not write to dac: {}", e);
76 }
77 }
78}
79
80#[embassy_executor::task]
81async fn dac_task2(mut dac: Dac2Type) {
82 let data: &[u8; 256] = &calculate_array::<256>();
83
84 info!("TIM7 frequency is {}", TIM7::frequency());
85
86 const FREQUENCY: Hertz = Hertz::hz(600);
87 let reload: u32 = (TIM7::frequency().0 / FREQUENCY.0) / data.len() as u32;
88
89 if reload < 10 {
90 error!("Reload value {} below threshold!", reload);
91 }
92
93 TIM7::enable();
94 TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
95 TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE));
96 TIM7::regs().cr1().modify(|w| {
97 w.set_opm(Opm::DISABLED);
98 w.set_cen(true);
99 });
100
101 dac.select_trigger(embassy_stm32::dac::Ch2Trigger::Tim7).unwrap();
102
103 debug!(
104 "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}",
105 TIM7::frequency(),
106 FREQUENCY,
107 reload,
108 reload as u16,
109 data.len()
110 );
111
112 if let Err(e) = dac.write(ValueArray::Bit8(data), true).await {
113 error!("Could not write to dac: {}", e);
114 }
115}
116
117fn to_sine_wave(v: u8) -> u8 {
118 if v >= 128 {
119 // top half
120 let r = 3.14 * ((v - 128) as f32 / 128.0);
121 (r.sin() * 128.0 + 127.0) as u8
122 } else {
123 // bottom half
124 let r = 3.14 + 3.14 * (v as f32 / 128.0);
125 (r.sin() * 128.0 + 127.0) as u8
126 }
127}
128
129fn calculate_array<const N: usize>() -> [u8; N] {
130 let mut res = [0; N];
131 let mut i = 0;
132 while i < N {
133 res[i] = to_sine_wave(i as u8);
134 i += 1;
135 }
136 res
137}
diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs
index 80811a43e..410d6891b 100644
--- a/examples/stm32l4/src/bin/usb_serial.rs
+++ b/examples/stm32l4/src/bin/usb_serial.rs
@@ -30,7 +30,9 @@ async fn main(_spawner: Spawner) {
30 30
31 // Create the driver, from the HAL. 31 // Create the driver, from the HAL.
32 let mut ep_out_buffer = [0u8; 256]; 32 let mut ep_out_buffer = [0u8; 256];
33 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); 33 let mut config = embassy_stm32::usb_otg::Config::default();
34 config.vbus_detection = true;
35 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
34 36
35 // Create embassy-usb Config 37 // Create embassy-usb Config
36 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 38 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32l5/.cargo/config.toml b/examples/stm32l5/.cargo/config.toml
index 1dc3a6fb7..86a145a27 100644
--- a/examples/stm32l5/.cargo/config.toml
+++ b/examples/stm32l5/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32L552ZETxQ with your chip as listed in `probe-rs-cli chip list` 2# replace STM32L552ZETxQ with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32L552ZETxQ" 3runner = "probe-rs run --chip STM32L552ZETxQ"
4 4
5[build] 5[build]
6target = "thumbv8m.main-none-eabihf" 6target = "thumbv8m.main-none-eabihf"
diff --git a/examples/stm32u5/.cargo/config.toml b/examples/stm32u5/.cargo/config.toml
index cecd01938..36c5b63a6 100644
--- a/examples/stm32u5/.cargo/config.toml
+++ b/examples/stm32u5/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32U585AIIx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32U585AIIx with your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32U585AIIx" 3runner = "probe-rs run --chip STM32U585AIIx"
4 4
5[build] 5[build]
6target = "thumbv8m.main-none-eabihf" 6target = "thumbv8m.main-none-eabihf"
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs
index f36daf91b..9e47fb18a 100644
--- a/examples/stm32u5/src/bin/usb_serial.rs
+++ b/examples/stm32u5/src/bin/usb_serial.rs
@@ -31,7 +31,9 @@ async fn main(_spawner: Spawner) {
31 31
32 // Create the driver, from the HAL. 32 // Create the driver, from the HAL.
33 let mut ep_out_buffer = [0u8; 256]; 33 let mut ep_out_buffer = [0u8; 256];
34 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); 34 let mut config = embassy_stm32::usb_otg::Config::default();
35 config.vbus_detection = true;
36 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
35 37
36 // Create embassy-usb Config 38 // Create embassy-usb Config
37 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 39 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32wb/.cargo/config.toml b/examples/stm32wb/.cargo/config.toml
index 35317a297..8b6d6d754 100644
--- a/examples/stm32wb/.cargo/config.toml
+++ b/examples/stm32wb/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32WB55CCUx with your chip as listed in `probe-rs-cli chip list` 2# replace STM32WB55CCUx with your chip as listed in `probe-rs chip list`
3# runner = "probe-rs-cli run --chip STM32WB55RGVx --speed 1000 --connect-under-reset" 3# runner = "probe-rs run --chip STM32WB55RGVx --speed 1000 --connect-under-reset"
4runner = "teleprobe local run --chip STM32WB55RG --elf" 4runner = "teleprobe local run --chip STM32WB55RG --elf"
5 5
6[build] 6[build]
diff --git a/examples/stm32wl/.cargo/config.toml b/examples/stm32wl/.cargo/config.toml
index b49b582e0..4f8094ff2 100644
--- a/examples/stm32wl/.cargo/config.toml
+++ b/examples/stm32wl/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-rs-cli chip list` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-rs-cli run --chip STM32WLE5JCIx" 3runner = "probe-rs run --chip STM32WLE5JCIx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs
index 9fc537a4b..1ecaab266 100644
--- a/tests/rp/src/bin/cyw43-perf.rs
+++ b/tests/rp/src/bin/cyw43-perf.rs
@@ -44,8 +44,8 @@ async fn main(spawner: Spawner) {
44 } 44 }
45 45
46 // cyw43 firmware needs to be flashed manually: 46 // cyw43 firmware needs to be flashed manually:
47 // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x101c0000 47 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x101c0000
48 // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x101f8000 48 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x101f8000
49 let fw = unsafe { core::slice::from_raw_parts(0x101c0000 as *const u8, 224190) }; 49 let fw = unsafe { core::slice::from_raw_parts(0x101c0000 as *const u8, 224190) };
50 let clm = unsafe { core::slice::from_raw_parts(0x101f8000 as *const u8, 4752) }; 50 let clm = unsafe { core::slice::from_raw_parts(0x101f8000 as *const u8, 4752) };
51 51