aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorMathias <[email protected]>2023-02-13 14:55:15 +0100
committerMathias <[email protected]>2023-02-13 14:55:15 +0100
commit218b44652c149f895919b606a660b6eff30e8177 (patch)
tree5f985f6edd12926a6f374c17a3a0c3a4226088e7 /examples
parent86113e199f37fe0888979608a08bfdaf21bff19a (diff)
parent41a563aae3e474955892b27487e185f5f486f525 (diff)
Rebase on master
Diffstat (limited to 'examples')
-rw-r--r--examples/boot/application/nrf/Cargo.toml9
-rw-r--r--examples/boot/application/nrf/README.md14
-rw-r--r--examples/boot/application/nrf/memory-bl-nrf91.x19
-rw-r--r--examples/boot/application/nrf/memory-bl.x2
-rw-r--r--examples/boot/application/nrf/memory-nrf91.x16
-rw-r--r--examples/boot/application/nrf/memory.x2
-rw-r--r--examples/boot/application/nrf/src/bin/a.rs24
-rw-r--r--examples/boot/application/nrf/src/bin/b.rs5
-rw-r--r--examples/boot/application/rp/.cargo/config.toml12
-rw-r--r--examples/boot/application/rp/Cargo.toml33
-rw-r--r--examples/boot/application/rp/README.md28
-rw-r--r--examples/boot/application/rp/build.rs (renamed from examples/nrf/build.rs)0
-rw-r--r--examples/boot/application/rp/memory.x15
-rw-r--r--examples/boot/application/rp/src/bin/a.rs59
-rw-r--r--examples/boot/application/rp/src/bin/b.rs23
-rw-r--r--examples/boot/application/stm32f3/Cargo.toml2
-rw-r--r--examples/boot/application/stm32f7/Cargo.toml2
-rw-r--r--examples/boot/application/stm32h7/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l0/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l1/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l4/Cargo.toml2
-rw-r--r--examples/boot/application/stm32wl/Cargo.toml2
-rw-r--r--examples/boot/bootloader/nrf/Cargo.toml2
-rw-r--r--examples/boot/bootloader/nrf/memory-bm.x2
-rw-r--r--examples/boot/bootloader/nrf/memory.x2
-rw-r--r--examples/boot/bootloader/nrf/src/main.rs9
-rw-r--r--examples/boot/bootloader/rp/.cargo/config.toml8
-rw-r--r--examples/boot/bootloader/rp/Cargo.toml31
-rw-r--r--examples/boot/bootloader/rp/README.md17
-rw-r--r--examples/boot/bootloader/rp/build.rs28
-rw-r--r--examples/boot/bootloader/rp/memory.x19
-rw-r--r--examples/boot/bootloader/rp/src/main.rs51
-rw-r--r--examples/boot/bootloader/stm32/Cargo.toml2
-rw-r--r--examples/nrf/src/bin/usb_ethernet.rs274
-rw-r--r--examples/nrf52840/.cargo/config.toml (renamed from examples/nrf/.cargo/config.toml)0
-rw-r--r--examples/nrf52840/Cargo.toml (renamed from examples/nrf/Cargo.toml)22
-rw-r--r--examples/nrf52840/build.rs35
-rw-r--r--examples/nrf52840/memory.x (renamed from examples/nrf/memory.x)0
-rw-r--r--examples/nrf52840/src/bin/awaitable_timer.rs (renamed from examples/nrf/src/bin/awaitable_timer.rs)0
-rw-r--r--examples/nrf52840/src/bin/blinky.rs (renamed from examples/nrf/src/bin/blinky.rs)0
-rw-r--r--examples/nrf52840/src/bin/buffered_uart.rs (renamed from examples/nrf/src/bin/buffered_uart.rs)0
-rw-r--r--examples/nrf52840/src/bin/channel.rs (renamed from examples/nrf/src/bin/channel.rs)0
-rw-r--r--examples/nrf52840/src/bin/channel_sender_receiver.rs (renamed from examples/nrf/src/bin/channel_sender_receiver.rs)0
-rw-r--r--examples/nrf52840/src/bin/executor_fairness_test.rs (renamed from examples/nrf/src/bin/executor_fairness_test.rs)0
-rw-r--r--examples/nrf52840/src/bin/gpiote_channel.rs (renamed from examples/nrf/src/bin/gpiote_channel.rs)0
-rw-r--r--examples/nrf52840/src/bin/gpiote_port.rs (renamed from examples/nrf/src/bin/gpiote_port.rs)0
-rw-r--r--examples/nrf52840/src/bin/i2s_effect.rs117
-rw-r--r--examples/nrf52840/src/bin/i2s_monitor.rs115
-rw-r--r--examples/nrf52840/src/bin/i2s_waveform.rs151
-rw-r--r--examples/nrf52840/src/bin/lora_p2p_report.rs78
-rw-r--r--examples/nrf52840/src/bin/lora_p2p_sense.rs125
-rw-r--r--examples/nrf52840/src/bin/manually_create_executor.rs49
-rw-r--r--examples/nrf52840/src/bin/multiprio.rs (renamed from examples/nrf/src/bin/multiprio.rs)0
-rw-r--r--examples/nrf52840/src/bin/mutex.rs (renamed from examples/nrf/src/bin/mutex.rs)0
-rw-r--r--examples/nrf52840/src/bin/nvmc.rs (renamed from examples/nrf/src/bin/nvmc.rs)0
-rw-r--r--examples/nrf52840/src/bin/pdm.rs33
-rw-r--r--examples/nrf52840/src/bin/ppi.rs (renamed from examples/nrf/src/bin/ppi.rs)0
-rw-r--r--examples/nrf52840/src/bin/pubsub.rs (renamed from examples/nrf/src/bin/pubsub.rs)0
-rw-r--r--examples/nrf52840/src/bin/pwm.rs (renamed from examples/nrf/src/bin/pwm.rs)0
-rw-r--r--examples/nrf52840/src/bin/pwm_double_sequence.rs (renamed from examples/nrf/src/bin/pwm_double_sequence.rs)0
-rw-r--r--examples/nrf52840/src/bin/pwm_sequence.rs (renamed from examples/nrf/src/bin/pwm_sequence.rs)0
-rw-r--r--examples/nrf52840/src/bin/pwm_sequence_ppi.rs (renamed from examples/nrf/src/bin/pwm_sequence_ppi.rs)0
-rw-r--r--examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs (renamed from examples/nrf/src/bin/pwm_sequence_ws2812b.rs)0
-rw-r--r--examples/nrf52840/src/bin/pwm_servo.rs (renamed from examples/nrf/src/bin/pwm_servo.rs)0
-rw-r--r--examples/nrf52840/src/bin/qdec.rs (renamed from examples/nrf/src/bin/qdec.rs)0
-rw-r--r--examples/nrf52840/src/bin/qspi.rs (renamed from examples/nrf/src/bin/qspi.rs)0
-rw-r--r--examples/nrf52840/src/bin/qspi_lowpower.rs (renamed from examples/nrf/src/bin/qspi_lowpower.rs)0
-rw-r--r--examples/nrf52840/src/bin/raw_spawn.rs (renamed from examples/nrf/src/bin/raw_spawn.rs)0
-rw-r--r--examples/nrf52840/src/bin/rng.rs (renamed from examples/nrf/src/bin/rng.rs)0
-rw-r--r--examples/nrf52840/src/bin/saadc.rs (renamed from examples/nrf/src/bin/saadc.rs)0
-rw-r--r--examples/nrf52840/src/bin/saadc_continuous.rs (renamed from examples/nrf/src/bin/saadc_continuous.rs)4
-rw-r--r--examples/nrf52840/src/bin/self_spawn.rs (renamed from examples/nrf/src/bin/self_spawn.rs)0
-rw-r--r--examples/nrf52840/src/bin/self_spawn_current_executor.rs (renamed from examples/nrf/src/bin/self_spawn_current_executor.rs)0
-rw-r--r--examples/nrf52840/src/bin/spim.rs (renamed from examples/nrf/src/bin/spim.rs)0
-rw-r--r--examples/nrf52840/src/bin/spis.rs27
-rw-r--r--examples/nrf52840/src/bin/temp.rs (renamed from examples/nrf/src/bin/temp.rs)0
-rw-r--r--examples/nrf52840/src/bin/timer.rs (renamed from examples/nrf/src/bin/timer.rs)0
-rw-r--r--examples/nrf52840/src/bin/twim.rs (renamed from examples/nrf/src/bin/twim.rs)0
-rw-r--r--examples/nrf52840/src/bin/twim_lowpower.rs (renamed from examples/nrf/src/bin/twim_lowpower.rs)0
-rw-r--r--examples/nrf52840/src/bin/twis.rs46
-rw-r--r--examples/nrf52840/src/bin/uart.rs (renamed from examples/nrf/src/bin/uart.rs)0
-rw-r--r--examples/nrf52840/src/bin/uart_idle.rs (renamed from examples/nrf/src/bin/uart_idle.rs)7
-rw-r--r--examples/nrf52840/src/bin/uart_split.rs (renamed from examples/nrf/src/bin/uart_split.rs)0
-rw-r--r--examples/nrf52840/src/bin/usb_ethernet.rs186
-rw-r--r--examples/nrf52840/src/bin/usb_hid_keyboard.rs (renamed from examples/nrf/src/bin/usb_hid_keyboard.rs)29
-rw-r--r--examples/nrf52840/src/bin/usb_hid_mouse.rs (renamed from examples/nrf/src/bin/usb_hid_mouse.rs)5
-rw-r--r--examples/nrf52840/src/bin/usb_serial.rs (renamed from examples/nrf/src/bin/usb_serial.rs)7
-rw-r--r--examples/nrf52840/src/bin/usb_serial_multitask.rs (renamed from examples/nrf/src/bin/usb_serial_multitask.rs)7
-rw-r--r--examples/nrf52840/src/bin/usb_serial_winusb.rs130
-rw-r--r--examples/nrf52840/src/bin/wdt.rs (renamed from examples/nrf/src/bin/wdt.rs)0
-rw-r--r--examples/nrf5340/.cargo/config.toml9
-rw-r--r--examples/nrf5340/Cargo.toml64
-rw-r--r--examples/nrf5340/build.rs35
-rw-r--r--examples/nrf5340/memory.x7
-rw-r--r--examples/nrf5340/src/bin/blinky.rs21
-rw-r--r--examples/nrf5340/src/bin/gpiote_channel.rs66
-rw-r--r--examples/nrf5340/src/bin/uart.rs35
-rw-r--r--examples/rp/.cargo/config.toml2
-rw-r--r--examples/rp/Cargo.toml21
-rw-r--r--examples/rp/src/bin/adc.rs38
-rw-r--r--examples/rp/src/bin/flash.rs89
-rw-r--r--examples/rp/src/bin/i2c_async.rs102
-rw-r--r--examples/rp/src/bin/multicore.rs60
-rw-r--r--examples/rp/src/bin/pio_async.rs112
-rw-r--r--examples/rp/src/bin/pio_dma.rs69
-rw-r--r--examples/rp/src/bin/uart_buffered_split.rs57
-rw-r--r--examples/rp/src/bin/uart_unidir.rs42
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs152
-rw-r--r--examples/rp/src/bin/usb_logger.rs30
-rw-r--r--examples/rp/src/bin/usb_serial.rs1
-rw-r--r--examples/rp/src/bin/watchdog.rs48
-rw-r--r--examples/std/Cargo.toml7
-rw-r--r--examples/std/src/bin/net.rs15
-rw-r--r--examples/std/src/bin/net_dns.rs98
-rw-r--r--examples/std/src/bin/net_udp.rs13
-rw-r--r--examples/std/src/tuntap.rs119
-rw-r--r--examples/stm32c0/.cargo/config.toml9
-rw-r--r--examples/stm32c0/Cargo.toml21
-rw-r--r--examples/stm32c0/build.rs5
-rw-r--r--examples/stm32c0/src/bin/blinky.rs27
-rw-r--r--examples/stm32c0/src/bin/button.rs25
-rw-r--r--examples/stm32c0/src/bin/button_exti.rs27
-rw-r--r--examples/stm32f0/.cargo/config.toml2
-rw-r--r--examples/stm32f0/Cargo.toml6
-rw-r--r--examples/stm32f0/src/bin/blinky.rs28
-rw-r--r--examples/stm32f0/src/bin/button_controlled_blink.rs64
-rw-r--r--examples/stm32f0/src/bin/button_exti.rs27
-rw-r--r--examples/stm32f0/src/bin/priority.rs139
-rw-r--r--examples/stm32f0/src/bin/wdg.rs25
-rw-r--r--examples/stm32f1/Cargo.toml2
-rw-r--r--examples/stm32f1/src/bin/adc.rs14
-rw-r--r--examples/stm32f1/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32f2/Cargo.toml2
-rw-r--r--examples/stm32f3/Cargo.toml2
-rw-r--r--examples/stm32f3/src/bin/usart_dma.rs4
-rw-r--r--examples/stm32f3/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32f4/Cargo.toml15
-rw-r--r--examples/stm32f4/src/bin/adc.rs31
-rw-r--r--examples/stm32f4/src/bin/i2c.rs45
-rw-r--r--examples/stm32f4/src/bin/usart.rs4
-rw-r--r--examples/stm32f4/src/bin/usart_buffered.rs15
-rw-r--r--examples/stm32f4/src/bin/usart_dma.rs4
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs168
-rw-r--r--examples/stm32f4/src/bin/usb_serial.rs105
-rw-r--r--examples/stm32f7/Cargo.toml9
-rw-r--r--examples/stm32f7/src/bin/adc.rs12
-rw-r--r--examples/stm32f7/src/bin/eth.rs63
-rw-r--r--examples/stm32f7/src/bin/usart_dma.rs4
-rw-r--r--examples/stm32f7/src/bin/usb_serial.rs106
-rw-r--r--examples/stm32g0/Cargo.toml2
-rw-r--r--examples/stm32g4/Cargo.toml2
-rw-r--r--examples/stm32h7/Cargo.toml13
-rw-r--r--examples/stm32h7/src/bin/eth.rs56
-rw-r--r--examples/stm32h7/src/bin/eth_client.rs56
-rw-r--r--examples/stm32h7/src/bin/i2c.rs44
-rw-r--r--examples/stm32h7/src/bin/usart.rs4
-rw-r--r--examples/stm32h7/src/bin/usart_dma.rs4
-rw-r--r--examples/stm32h7/src/bin/usart_split.rs4
-rw-r--r--examples/stm32h7/src/bin/usb_serial.rs105
-rw-r--r--examples/stm32h7/src/bin/wdg.rs24
-rw-r--r--examples/stm32l0/Cargo.toml4
-rw-r--r--examples/stm32l0/src/bin/usart_dma.rs4
-rw-r--r--examples/stm32l0/src/bin/usart_irq.rs12
-rw-r--r--examples/stm32l1/Cargo.toml2
-rw-r--r--examples/stm32l4/Cargo.toml8
-rw-r--r--examples/stm32l4/src/bin/usart.rs4
-rw-r--r--examples/stm32l4/src/bin/usart_dma.rs4
-rw-r--r--examples/stm32l4/src/bin/usb_serial.rs107
-rw-r--r--examples/stm32l5/Cargo.toml6
-rw-r--r--examples/stm32l5/src/bin/usb_ethernet.rs152
-rw-r--r--examples/stm32l5/src/bin/usb_hid_mouse.rs1
-rw-r--r--examples/stm32l5/src/bin/usb_serial.rs1
-rw-r--r--examples/stm32u5/Cargo.toml8
-rw-r--r--examples/stm32u5/src/bin/usb_serial.rs107
-rw-r--r--examples/stm32wb/Cargo.toml2
-rw-r--r--examples/stm32wl/Cargo.toml2
-rw-r--r--examples/stm32wl/src/bin/random.rs33
-rw-r--r--examples/stm32wl/src/bin/uart_async.rs60
178 files changed, 4196 insertions, 852 deletions
diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml
index a5d82b601..888993255 100644
--- a/examples/boot/application/nrf/Cargo.toml
+++ b/examples/boot/application/nrf/Cargo.toml
@@ -8,14 +8,19 @@ license = "MIT OR Apache-2.0"
8embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } 9embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly"] } 10embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly"] }
11embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly", "nrf52840"] } 11embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly"] }
12embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot" }
12embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot/nrf" } 13embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot/nrf" }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 14embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14 15
15defmt = { version = "0.3", optional = true } 16defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.3", optional = true } 17defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 18panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 19embedded-hal = { version = "0.2.6" }
19 20
20cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 21cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
21cortex-m-rt = "0.7.0" 22cortex-m-rt = "0.7.0"
23
24[features]
25ed25519-dalek = ["embassy-boot/ed25519-dalek"]
26ed25519-salty = ["embassy-boot/ed25519-salty"] \ No newline at end of file
diff --git a/examples/boot/application/nrf/README.md b/examples/boot/application/nrf/README.md
index 703377a20..9d6d20336 100644
--- a/examples/boot/application/nrf/README.md
+++ b/examples/boot/application/nrf/README.md
@@ -1,6 +1,6 @@
1# Examples using bootloader 1# Examples using bootloader
2 2
3Example for nRF52 demonstrating the bootloader. The example consists of application binaries, 'a' 3Example for nRF demonstrating the bootloader. The example consists of application binaries, 'a'
4which allows you to press a button to start the DFU process, and 'b' which is the updated 4which allows you to press a button to start the DFU process, and 'b' which is the updated
5application. 5application.
6 6
@@ -20,15 +20,19 @@ application.
20cp memory-bl.x ../../bootloader/nrf/memory.x 20cp memory-bl.x ../../bootloader/nrf/memory.x
21 21
22# Flash bootloader 22# Flash bootloader
23cargo flash --manifest-path ../../bootloader/nrf/Cargo.toml --features embassy-nrf/nrf52840 --release --chip nRF52840_xxAA 23cargo flash --manifest-path ../../bootloader/nrf/Cargo.toml --features embassy-nrf/nrf52840 --target thumbv7em-none-eabi --release --chip nRF52840_xxAA
24# Build 'b' 24# Build 'b'
25cargo build --release --bin b 25cargo build --release --bin b --features embassy-nrf/nrf52840
26# Generate binary for 'b' 26# Generate binary for 'b'
27cargo objcopy --release --bin b -- -O binary b.bin 27cargo objcopy --release --bin b --features embassy-nrf/nrf52840 --target thumbv7em-none-eabi -- -O binary b.bin
28``` 28```
29 29
30# Flash `a` (which includes b.bin) 30# Flash `a` (which includes b.bin)
31 31
32``` 32```
33cargo flash --release --bin a --chip nRF52840_xxAA 33cargo flash --release --bin a --features embassy-nrf/nrf52840 --target thumbv7em-none-eabi --chip nRF52840_xxAA
34``` 34```
35
36You should then see a solid LED. Pressing button 1 will cause the DFU to be loaded by the bootloader. Upon
37successfully loading, you'll see the LED flash. After 5 seconds, because there is no petting of the watchdog,
38you'll see the LED go solid again. This indicates that the bootloader has reverted the update.
diff --git a/examples/boot/application/nrf/memory-bl-nrf91.x b/examples/boot/application/nrf/memory-bl-nrf91.x
new file mode 100644
index 000000000..14ceffa73
--- /dev/null
+++ b/examples/boot/application/nrf/memory-bl-nrf91.x
@@ -0,0 +1,19 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 /* Assumes Secure Partition Manager (SPM) flashed at the start */
5 FLASH : ORIGIN = 0x00050000, LENGTH = 24K
6 BOOTLOADER_STATE : ORIGIN = 0x00056000, LENGTH = 4K
7 ACTIVE : ORIGIN = 0x00057000, LENGTH = 64K
8 DFU : ORIGIN = 0x00067000, LENGTH = 68K
9 RAM (rwx) : ORIGIN = 0x20018000, LENGTH = 32K
10}
11
12__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
13__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE);
14
15__bootloader_active_start = ORIGIN(ACTIVE);
16__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE);
17
18__bootloader_dfu_start = ORIGIN(DFU);
19__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU);
diff --git a/examples/boot/application/nrf/memory-bl.x b/examples/boot/application/nrf/memory-bl.x
index 8a32b905f..257d65644 100644
--- a/examples/boot/application/nrf/memory-bl.x
+++ b/examples/boot/application/nrf/memory-bl.x
@@ -5,7 +5,7 @@ MEMORY
5 BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K
6 ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K 6 ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K
7 DFU : ORIGIN = 0x00017000, LENGTH = 68K 7 DFU : ORIGIN = 0x00017000, LENGTH = 68K
8 RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
9} 9}
10 10
11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE); 11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
diff --git a/examples/boot/application/nrf/memory-nrf91.x b/examples/boot/application/nrf/memory-nrf91.x
new file mode 100644
index 000000000..2bc13c0d6
--- /dev/null
+++ b/examples/boot/application/nrf/memory-nrf91.x
@@ -0,0 +1,16 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 /* Assumes Secure Partition Manager (SPM) flashed at the start */
5 BOOTLOADER : ORIGIN = 0x00050000, LENGTH = 24K
6 BOOTLOADER_STATE : ORIGIN = 0x00056000, LENGTH = 4K
7 FLASH : ORIGIN = 0x00057000, LENGTH = 64K
8 DFU : ORIGIN = 0x00067000, LENGTH = 68K
9 RAM (rwx) : ORIGIN = 0x20018000, LENGTH = 32K
10}
11
12__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
13__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE);
14
15__bootloader_dfu_start = ORIGIN(DFU);
16__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU);
diff --git a/examples/boot/application/nrf/memory.x b/examples/boot/application/nrf/memory.x
index 3a54ca460..c6926e422 100644
--- a/examples/boot/application/nrf/memory.x
+++ b/examples/boot/application/nrf/memory.x
@@ -5,7 +5,7 @@ MEMORY
5 BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K
6 FLASH : ORIGIN = 0x00007000, LENGTH = 64K 6 FLASH : ORIGIN = 0x00007000, LENGTH = 64K
7 DFU : ORIGIN = 0x00017000, LENGTH = 68K 7 DFU : ORIGIN = 0x00017000, LENGTH = 68K
8 RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
9} 9}
10 10
11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE); 11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs
index 7a404a914..090a05b23 100644
--- a/examples/boot/application/nrf/src/bin/a.rs
+++ b/examples/boot/application/nrf/src/bin/a.rs
@@ -8,6 +8,7 @@ use embassy_embedded_hal::adapter::BlockingAsync;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; 9use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
10use embassy_nrf::nvmc::Nvmc; 10use embassy_nrf::nvmc::Nvmc;
11use embassy_nrf::wdt::{self, Watchdog};
11use panic_reset as _; 12use panic_reset as _;
12 13
13static APP_B: &[u8] = include_bytes!("../../b.bin"); 14static APP_B: &[u8] = include_bytes!("../../b.bin");
@@ -15,11 +16,34 @@ static APP_B: &[u8] = include_bytes!("../../b.bin");
15#[embassy_executor::main] 16#[embassy_executor::main]
16async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
17 let p = embassy_nrf::init(Default::default()); 18 let p = embassy_nrf::init(Default::default());
19
18 let mut button = Input::new(p.P0_11, Pull::Up); 20 let mut button = Input::new(p.P0_11, Pull::Up);
19 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); 21 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
22
20 //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); 23 //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard);
21 //let mut button = Input::new(p.P1_02, Pull::Up); 24 //let mut button = Input::new(p.P1_02, Pull::Up);
22 25
26 // nRF91 DK
27 // let mut led = Output::new(p.P0_02, Level::Low, OutputDrive::Standard);
28 // let mut button = Input::new(p.P0_06, Pull::Up);
29
30 // The following code block illustrates how to obtain a watchdog that is configured
31 // as per the existing watchdog. Ordinarily, we'd use the handle returned to "pet" the
32 // watchdog periodically. If we don't, and we're not going to for this example, then
33 // the watchdog will cause the device to reset as per its configured timeout in the bootloader.
34 // This helps is avoid a situation where new firmware might be bad and block our executor.
35 // If firmware is bad in this way then the bootloader will revert to any previous version.
36 let wdt_config = wdt::Config::try_new(&p.WDT).unwrap();
37 let (_wdt, [_wdt_handle]) = match Watchdog::try_new(p.WDT, wdt_config) {
38 Ok(x) => x,
39 Err(_) => {
40 // Watchdog already active with the wrong number of handles, waiting for it to timeout...
41 loop {
42 cortex_m::asm::wfe();
43 }
44 }
45 };
46
23 let nvmc = Nvmc::new(p.NVMC); 47 let nvmc = Nvmc::new(p.NVMC);
24 let mut nvmc = BlockingAsync::new(nvmc); 48 let mut nvmc = BlockingAsync::new(nvmc);
25 49
diff --git a/examples/boot/application/nrf/src/bin/b.rs b/examples/boot/application/nrf/src/bin/b.rs
index 1373f277d..15ebce5fa 100644
--- a/examples/boot/application/nrf/src/bin/b.rs
+++ b/examples/boot/application/nrf/src/bin/b.rs
@@ -12,7 +12,10 @@ use panic_reset as _;
12async fn main(_spawner: Spawner) { 12async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default()); 13 let p = embassy_nrf::init(Default::default());
14 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); 14 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
15 //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); 15 // let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard);
16
17 // nRF91 DK
18 // let mut led = Output::new(p.P0_02, Level::Low, OutputDrive::Standard);
16 19
17 loop { 20 loop {
18 led.set_high(); 21 led.set_high();
diff --git a/examples/boot/application/rp/.cargo/config.toml b/examples/boot/application/rp/.cargo/config.toml
new file mode 100644
index 000000000..edbd0a867
--- /dev/null
+++ b/examples/boot/application/rp/.cargo/config.toml
@@ -0,0 +1,12 @@
1[unstable]
2build-std = ["core"]
3build-std-features = ["panic_immediate_abort"]
4
5[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6runner = "probe-run --chip RP2040"
7
8[build]
9target = "thumbv6m-none-eabi"
10
11[env]
12DEFMT_LOG = "trace"
diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml
new file mode 100644
index 000000000..8d826790b
--- /dev/null
+++ b/examples/boot/application/rp/Cargo.toml
@@ -0,0 +1,33 @@
1[package]
2edition = "2021"
3name = "embassy-boot-rp-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly"] }
11embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", "unstable-traits", "nightly"] }
12embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp" }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14
15defmt = "0.3"
16defmt-rtt = "0.4"
17panic-probe = { version = "0.3", features = ["print-defmt"], optional = true }
18panic-reset = { version = "0.1.1", optional = true }
19embedded-hal = { version = "0.2.6" }
20
21cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
22cortex-m-rt = "0.7.0"
23
24[features]
25default = ["panic-reset"]
26debug = [
27 "embassy-rp/defmt",
28 "embassy-boot-rp/defmt",
29 "panic-probe"
30]
31
32[profile.release]
33debug = true
diff --git a/examples/boot/application/rp/README.md b/examples/boot/application/rp/README.md
new file mode 100644
index 000000000..41304c526
--- /dev/null
+++ b/examples/boot/application/rp/README.md
@@ -0,0 +1,28 @@
1# Examples using bootloader
2
3Example for Raspberry Pi Pico demonstrating the bootloader. The example consists of application binaries, 'a'
4which waits for 5 seconds before flashing the 'b' binary, which blinks the LED.
5
6NOTE: The 'b' binary does not mark the new binary as active, so if you reset the device, it will roll back to the 'a' binary before automatically updating it again.
7
8## Prerequisites
9
10* `cargo-binutils`
11* `cargo-flash`
12* `embassy-boot-rp`
13
14## Usage
15
16```
17# Flash bootloader
18cargo flash --manifest-path ../../bootloader/rp/Cargo.toml --release --chip RP2040
19
20# Build 'b'
21cargo build --release --bin b
22
23# Generate binary for 'b'
24cargo objcopy --release --bin b -- -O binary b.bin
25
26# Flash `a` (which includes b.bin)
27cargo flash --release --bin a --chip RP2040
28```
diff --git a/examples/nrf/build.rs b/examples/boot/application/rp/build.rs
index 30691aa97..30691aa97 100644
--- a/examples/nrf/build.rs
+++ b/examples/boot/application/rp/build.rs
diff --git a/examples/boot/application/rp/memory.x b/examples/boot/application/rp/memory.x
new file mode 100644
index 000000000..c19473114
--- /dev/null
+++ b/examples/boot/application/rp/memory.x
@@ -0,0 +1,15 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
5 BOOTLOADER_STATE : ORIGIN = 0x10006000, LENGTH = 4K
6 FLASH : ORIGIN = 0x10007000, LENGTH = 512K
7 DFU : ORIGIN = 0x10087000, LENGTH = 516K
8 RAM : ORIGIN = 0x20000000, LENGTH = 256K
9}
10
11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOT2);
12__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(BOOT2);
13
14__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOT2);
15__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOT2);
diff --git a/examples/boot/application/rp/src/bin/a.rs b/examples/boot/application/rp/src/bin/a.rs
new file mode 100644
index 000000000..e3ac634c2
--- /dev/null
+++ b/examples/boot/application/rp/src/bin/a.rs
@@ -0,0 +1,59 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt_rtt as _;
6use embassy_boot_rp::*;
7use embassy_executor::Spawner;
8use embassy_rp::flash::Flash;
9use embassy_rp::gpio::{Level, Output};
10use embassy_rp::watchdog::Watchdog;
11use embassy_time::{Duration, Timer};
12#[cfg(feature = "panic-probe")]
13use panic_probe as _;
14#[cfg(feature = "panic-reset")]
15use panic_reset as _;
16
17static APP_B: &[u8] = include_bytes!("../../b.bin");
18const FLASH_SIZE: usize = 2 * 1024 * 1024;
19
20#[embassy_executor::main]
21async fn main(_s: Spawner) {
22 let p = embassy_rp::init(Default::default());
23 let mut led = Output::new(p.PIN_25, Level::Low);
24
25 // Override bootloader watchdog
26 let mut watchdog = Watchdog::new(p.WATCHDOG);
27 watchdog.start(Duration::from_secs(8));
28
29 let mut flash: Flash<_, FLASH_SIZE> = Flash::new(p.FLASH);
30
31 let mut updater = FirmwareUpdater::default();
32
33 Timer::after(Duration::from_secs(5)).await;
34 watchdog.feed();
35 led.set_high();
36 let mut offset = 0;
37 let mut buf: AlignedBuffer<4096> = AlignedBuffer([0; 4096]);
38 defmt::info!("preparing update");
39 let mut writer = updater
40 .prepare_update_blocking(&mut flash)
41 .map_err(|e| defmt::warn!("E: {:?}", defmt::Debug2Format(&e)))
42 .unwrap();
43 defmt::info!("writer created, starting write");
44 for chunk in APP_B.chunks(4096) {
45 buf.0[..chunk.len()].copy_from_slice(chunk);
46 defmt::info!("writing block at offset {}", offset);
47 writer
48 .write_block_blocking(offset, &buf.0[..], &mut flash, 256)
49 .unwrap();
50 offset += chunk.len();
51 }
52 watchdog.feed();
53 defmt::info!("firmware written, marking update");
54 updater.mark_updated_blocking(&mut flash, &mut buf.0[..1]).unwrap();
55 Timer::after(Duration::from_secs(2)).await;
56 led.set_low();
57 defmt::info!("update marked, resetting");
58 cortex_m::peripheral::SCB::sys_reset();
59}
diff --git a/examples/boot/application/rp/src/bin/b.rs b/examples/boot/application/rp/src/bin/b.rs
new file mode 100644
index 000000000..47dec329c
--- /dev/null
+++ b/examples/boot/application/rp/src/bin/b.rs
@@ -0,0 +1,23 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use embassy_executor::Spawner;
6use embassy_rp::gpio;
7use embassy_time::{Duration, Timer};
8use gpio::{Level, Output};
9use {defmt_rtt as _, panic_reset as _};
10
11#[embassy_executor::main]
12async fn main(_s: Spawner) {
13 let p = embassy_rp::init(Default::default());
14 let mut led = Output::new(p.PIN_25, Level::Low);
15
16 loop {
17 led.set_high();
18 Timer::after(Duration::from_millis(100)).await;
19
20 led.set_low();
21 Timer::after(Duration::from_millis(100)).await;
22 }
23}
diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml
index 3a1843562..aa279fb76 100644
--- a/examples/boot/application/stm32f3/Cargo.toml
+++ b/examples/boot/application/stm32f3/Cargo.toml
@@ -13,7 +13,7 @@ embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml
index 8d9c4490e..1ec0643a6 100644
--- a/examples/boot/application/stm32f7/Cargo.toml
+++ b/examples/boot/application/stm32f7/Cargo.toml
@@ -13,7 +13,7 @@ embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml
index b4314aa72..a4eefe2a5 100644
--- a/examples/boot/application/stm32h7/Cargo.toml
+++ b/examples/boot/application/stm32h7/Cargo.toml
@@ -13,7 +13,7 @@ embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml
index a17d336a6..36eada29b 100644
--- a/examples/boot/application/stm32l0/Cargo.toml
+++ b/examples/boot/application/stm32l0/Cargo.toml
@@ -13,7 +13,7 @@ embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml
index 683f2c860..67efda748 100644
--- a/examples/boot/application/stm32l1/Cargo.toml
+++ b/examples/boot/application/stm32l1/Cargo.toml
@@ -13,7 +13,7 @@ embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml
index b879c0d76..4b2e02dd2 100644
--- a/examples/boot/application/stm32l4/Cargo.toml
+++ b/examples/boot/application/stm32l4/Cargo.toml
@@ -13,7 +13,7 @@ embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml
index e3bc0e49c..fecbfc51d 100644
--- a/examples/boot/application/stm32wl/Cargo.toml
+++ b/examples/boot/application/stm32wl/Cargo.toml
@@ -13,7 +13,7 @@ embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
17panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
18embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19 19
diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml
index b417a40d1..8a6f53643 100644
--- a/examples/boot/bootloader/nrf/Cargo.toml
+++ b/examples/boot/bootloader/nrf/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7 7
8[dependencies] 8[dependencies]
9defmt = { version = "0.3", optional = true } 9defmt = { version = "0.3", optional = true }
10defmt-rtt = { version = "0.3", optional = true } 10defmt-rtt = { version = "0.4", optional = true }
11 11
12embassy-nrf = { path = "../../../../embassy-nrf", default-features = false, features = ["nightly"] } 12embassy-nrf = { path = "../../../../embassy-nrf", default-features = false, features = ["nightly"] }
13embassy-boot-nrf = { path = "../../../../embassy-boot/nrf", default-features = false } 13embassy-boot-nrf = { path = "../../../../embassy-boot/nrf", default-features = false }
diff --git a/examples/boot/bootloader/nrf/memory-bm.x b/examples/boot/bootloader/nrf/memory-bm.x
index 8a32b905f..257d65644 100644
--- a/examples/boot/bootloader/nrf/memory-bm.x
+++ b/examples/boot/bootloader/nrf/memory-bm.x
@@ -5,7 +5,7 @@ MEMORY
5 BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K
6 ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K 6 ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K
7 DFU : ORIGIN = 0x00017000, LENGTH = 68K 7 DFU : ORIGIN = 0x00017000, LENGTH = 68K
8 RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
9} 9}
10 10
11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE); 11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
diff --git a/examples/boot/bootloader/nrf/memory.x b/examples/boot/bootloader/nrf/memory.x
index 8a32b905f..257d65644 100644
--- a/examples/boot/bootloader/nrf/memory.x
+++ b/examples/boot/bootloader/nrf/memory.x
@@ -5,7 +5,7 @@ MEMORY
5 BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x00006000, LENGTH = 4K
6 ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K 6 ACTIVE : ORIGIN = 0x00007000, LENGTH = 64K
7 DFU : ORIGIN = 0x00017000, LENGTH = 68K 7 DFU : ORIGIN = 0x00017000, LENGTH = 68K
8 RAM (rwx) : ORIGIN = 0x20000008, LENGTH = 32K 8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
9} 9}
10 10
11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE); 11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs
index 8266206b3..aca3b857a 100644
--- a/examples/boot/bootloader/nrf/src/main.rs
+++ b/examples/boot/bootloader/nrf/src/main.rs
@@ -6,6 +6,7 @@ use cortex_m_rt::{entry, exception};
6use defmt_rtt as _; 6use defmt_rtt as _;
7use embassy_boot_nrf::*; 7use embassy_boot_nrf::*;
8use embassy_nrf::nvmc::Nvmc; 8use embassy_nrf::nvmc::Nvmc;
9use embassy_nrf::wdt;
9 10
10#[entry] 11#[entry]
11fn main() -> ! { 12fn main() -> ! {
@@ -20,8 +21,14 @@ fn main() -> ! {
20 */ 21 */
21 22
22 let mut bl = BootLoader::default(); 23 let mut bl = BootLoader::default();
24
25 let mut wdt_config = wdt::Config::default();
26 wdt_config.timeout_ticks = 32768 * 5; // timeout seconds
27 wdt_config.run_during_sleep = true;
28 wdt_config.run_during_debug_halt = false;
29
23 let start = bl.prepare(&mut SingleFlashConfig::new(&mut BootFlash::<_, 4096>::new( 30 let start = bl.prepare(&mut SingleFlashConfig::new(&mut BootFlash::<_, 4096>::new(
24 WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, 5), 31 WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config),
25 ))); 32 )));
26 unsafe { bl.load(start) } 33 unsafe { bl.load(start) }
27} 34}
diff --git a/examples/boot/bootloader/rp/.cargo/config.toml b/examples/boot/bootloader/rp/.cargo/config.toml
new file mode 100644
index 000000000..18bd4dfe8
--- /dev/null
+++ b/examples/boot/bootloader/rp/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-run --chip RP2040"
3
4[build]
5target = "thumbv6m-none-eabi"
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml
new file mode 100644
index 000000000..c0b576cff
--- /dev/null
+++ b/examples/boot/bootloader/rp/Cargo.toml
@@ -0,0 +1,31 @@
1[package]
2edition = "2021"
3name = "rp-bootloader-example"
4version = "0.1.0"
5description = "Example bootloader for RP2040 chips"
6license = "MIT OR Apache-2.0"
7
8[dependencies]
9defmt = { version = "0.3", optional = true }
10defmt-rtt = { version = "0.4", optional = true }
11
12embassy-rp = { path = "../../../../embassy-rp", default-features = false, features = ["nightly"] }
13embassy-boot-rp = { path = "../../../../embassy-boot/rp", default-features = false }
14embassy-time = { path = "../../../../embassy-time", features = ["nightly"] }
15
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = { version = "0.7" }
18embedded-storage = "0.3.0"
19embedded-storage-async = "0.3.0"
20cfg-if = "1.0.0"
21
22[features]
23defmt = [
24 "dep:defmt",
25 "embassy-boot-rp/defmt",
26 "embassy-rp/defmt",
27]
28debug = ["defmt-rtt", "defmt"]
29
30[profile.release]
31debug = true
diff --git a/examples/boot/bootloader/rp/README.md b/examples/boot/bootloader/rp/README.md
new file mode 100644
index 000000000..064e87273
--- /dev/null
+++ b/examples/boot/bootloader/rp/README.md
@@ -0,0 +1,17 @@
1# Bootloader for RP2040
2
3The bootloader uses `embassy-boot` to interact with the flash.
4
5# Usage
6
7Flashing the bootloader
8
9```
10cargo flash --release --chip RP2040
11```
12
13To debug, use `cargo run` and enable the debug feature flag
14
15``` rust
16cargo run --release --features debug
17```
diff --git a/examples/boot/bootloader/rp/build.rs b/examples/boot/bootloader/rp/build.rs
new file mode 100644
index 000000000..c201704ad
--- /dev/null
+++ b/examples/boot/bootloader/rp/build.rs
@@ -0,0 +1,28 @@
1use std::env;
2use std::fs::File;
3use std::io::Write;
4use std::path::PathBuf;
5
6fn main() {
7 // Put `memory.x` in our output directory and ensure it's
8 // on the linker search path.
9 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
10 File::create(out.join("memory.x"))
11 .unwrap()
12 .write_all(include_bytes!("memory.x"))
13 .unwrap();
14 println!("cargo:rustc-link-search={}", out.display());
15
16 // By default, Cargo will re-run a build script whenever
17 // any file in the project changes. By specifying `memory.x`
18 // here, we ensure the build script is only re-run when
19 // `memory.x` is changed.
20 println!("cargo:rerun-if-changed=memory.x");
21
22 println!("cargo:rustc-link-arg-bins=--nmagic");
23 println!("cargo:rustc-link-arg-bins=-Tlink.x");
24 println!("cargo:rustc-link-arg-bins=-Tlink-rp.x");
25 if env::var("CARGO_FEATURE_DEFMT").is_ok() {
26 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
27 }
28}
diff --git a/examples/boot/bootloader/rp/memory.x b/examples/boot/bootloader/rp/memory.x
new file mode 100644
index 000000000..d6ef38469
--- /dev/null
+++ b/examples/boot/bootloader/rp/memory.x
@@ -0,0 +1,19 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
5 FLASH : ORIGIN = 0x10000100, LENGTH = 24K
6 BOOTLOADER_STATE : ORIGIN = 0x10006000, LENGTH = 4K
7 ACTIVE : ORIGIN = 0x10007000, LENGTH = 512K
8 DFU : ORIGIN = 0x10087000, LENGTH = 516K
9 RAM : ORIGIN = 0x20000000, LENGTH = 256K
10}
11
12__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOT2);
13__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(BOOT2);
14
15__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(BOOT2);
16__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(BOOT2);
17
18__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOT2);
19__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOT2);
diff --git a/examples/boot/bootloader/rp/src/main.rs b/examples/boot/bootloader/rp/src/main.rs
new file mode 100644
index 000000000..fb7f0522b
--- /dev/null
+++ b/examples/boot/bootloader/rp/src/main.rs
@@ -0,0 +1,51 @@
1#![no_std]
2#![no_main]
3
4use cortex_m_rt::{entry, exception};
5#[cfg(feature = "defmt")]
6use defmt_rtt as _;
7use embassy_boot_rp::*;
8use embassy_rp::flash::ERASE_SIZE;
9use embassy_time::Duration;
10
11const FLASH_SIZE: usize = 2 * 1024 * 1024;
12
13#[entry]
14fn main() -> ! {
15 let p = embassy_rp::init(Default::default());
16
17 // Uncomment this if you are debugging the bootloader with debugger/RTT attached,
18 // as it prevents a hard fault when accessing flash 'too early' after boot.
19 /*
20 for i in 0..10000000 {
21 cortex_m::asm::nop();
22 }
23 */
24
25 let mut bl: BootLoader = BootLoader::default();
26 let flash = WatchdogFlash::<FLASH_SIZE>::start(p.FLASH, p.WATCHDOG, Duration::from_secs(8));
27 let mut flash = BootFlash::<_, ERASE_SIZE>::new(flash);
28 let start = bl.prepare(&mut SingleFlashConfig::new(&mut flash));
29 core::mem::drop(flash);
30
31 unsafe { bl.load(start) }
32}
33
34#[no_mangle]
35#[cfg_attr(target_os = "none", link_section = ".HardFault.user")]
36unsafe extern "C" fn HardFault() {
37 cortex_m::peripheral::SCB::sys_reset();
38}
39
40#[exception]
41unsafe fn DefaultHandler(_: i16) -> ! {
42 const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
43 let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16;
44
45 panic!("DefaultHandler #{:?}", irqn);
46}
47
48#[panic_handler]
49fn panic(_info: &core::panic::PanicInfo) -> ! {
50 cortex_m::asm::udf();
51}
diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml
index 4ddd1c99c..be659e02a 100644
--- a/examples/boot/bootloader/stm32/Cargo.toml
+++ b/examples/boot/bootloader/stm32/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7 7
8[dependencies] 8[dependencies]
9defmt = { version = "0.3", optional = true } 9defmt = { version = "0.3", optional = true }
10defmt-rtt = { version = "0.3", optional = true } 10defmt-rtt = { version = "0.4", optional = true }
11 11
12embassy-stm32 = { path = "../../../../embassy-stm32", default-features = false, features = ["nightly"] } 12embassy-stm32 = { path = "../../../../embassy-stm32", default-features = false, features = ["nightly"] }
13embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32", default-features = false } 13embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32", default-features = false }
diff --git a/examples/nrf/src/bin/usb_ethernet.rs b/examples/nrf/src/bin/usb_ethernet.rs
deleted file mode 100644
index de93a2b45..000000000
--- a/examples/nrf/src/bin/usb_ethernet.rs
+++ /dev/null
@@ -1,274 +0,0 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::mem;
6use core::sync::atomic::{AtomicBool, Ordering};
7use core::task::Waker;
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_net::tcp::TcpSocket;
12use embassy_net::{PacketBox, PacketBoxExt, PacketBuf, Stack, StackResources};
13use embassy_nrf::rng::Rng;
14use embassy_nrf::usb::{Driver, PowerUsb};
15use embassy_nrf::{interrupt, pac, peripherals};
16use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
17use embassy_sync::channel::Channel;
18use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State};
19use embassy_usb::{Builder, Config, UsbDevice};
20use embedded_io::asynch::Write;
21use static_cell::StaticCell;
22use {defmt_rtt as _, panic_probe as _};
23
24type MyDriver = Driver<'static, peripherals::USBD, PowerUsb>;
25
26macro_rules! singleton {
27 ($val:expr) => {{
28 type T = impl Sized;
29 static STATIC_CELL: StaticCell<T> = StaticCell::new();
30 STATIC_CELL.init_with(move || $val)
31 }};
32}
33
34#[embassy_executor::task]
35async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! {
36 device.run().await
37}
38
39#[embassy_executor::task]
40async fn usb_ncm_rx_task(mut class: Receiver<'static, MyDriver>) {
41 loop {
42 warn!("WAITING for connection");
43 LINK_UP.store(false, Ordering::Relaxed);
44
45 class.wait_connection().await.unwrap();
46
47 warn!("Connected");
48 LINK_UP.store(true, Ordering::Relaxed);
49
50 loop {
51 let mut p = unwrap!(PacketBox::new(embassy_net::Packet::new()));
52 let n = match class.read_packet(&mut p[..]).await {
53 Ok(n) => n,
54 Err(e) => {
55 warn!("error reading packet: {:?}", e);
56 break;
57 }
58 };
59
60 let buf = p.slice(0..n);
61 if RX_CHANNEL.try_send(buf).is_err() {
62 warn!("Failed pushing rx'd packet to channel.");
63 }
64 }
65 }
66}
67
68#[embassy_executor::task]
69async fn usb_ncm_tx_task(mut class: Sender<'static, MyDriver>) {
70 loop {
71 let pkt = TX_CHANNEL.recv().await;
72 if let Err(e) = class.write_packet(&pkt[..]).await {
73 warn!("Failed to TX packet: {:?}", e);
74 }
75 }
76}
77
78#[embassy_executor::task]
79async fn net_task(stack: &'static Stack<Device>) -> ! {
80 stack.run().await
81}
82
83#[embassy_executor::main]
84async fn main(spawner: Spawner) {
85 let p = embassy_nrf::init(Default::default());
86 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
87
88 info!("Enabling ext hfosc...");
89 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
90 while clock.events_hfclkstarted.read().bits() != 1 {}
91
92 // Create the driver, from the HAL.
93 let irq = interrupt::take!(USBD);
94 let power_irq = interrupt::take!(POWER_CLOCK);
95 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq));
96
97 // Create embassy-usb Config
98 let mut config = Config::new(0xc0de, 0xcafe);
99 config.manufacturer = Some("Embassy");
100 config.product = Some("USB-Ethernet example");
101 config.serial_number = Some("12345678");
102 config.max_power = 100;
103 config.max_packet_size_0 = 64;
104
105 // Required for Windows support.
106 config.composite_with_iads = true;
107 config.device_class = 0xEF;
108 config.device_sub_class = 0x02;
109 config.device_protocol = 0x01;
110
111 struct Resources {
112 device_descriptor: [u8; 256],
113 config_descriptor: [u8; 256],
114 bos_descriptor: [u8; 256],
115 control_buf: [u8; 128],
116 serial_state: State<'static>,
117 }
118 let res: &mut Resources = singleton!(Resources {
119 device_descriptor: [0; 256],
120 config_descriptor: [0; 256],
121 bos_descriptor: [0; 256],
122 control_buf: [0; 128],
123 serial_state: State::new(),
124 });
125
126 // Create embassy-usb DeviceBuilder using the driver and config.
127 let mut builder = Builder::new(
128 driver,
129 config,
130 &mut res.device_descriptor,
131 &mut res.config_descriptor,
132 &mut res.bos_descriptor,
133 &mut res.control_buf,
134 None,
135 );
136
137 // WARNINGS for Android ethernet tethering:
138 // - On Pixel 4a, it refused to work on Android 11, worked on Android 12.
139 // - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte),
140 // it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled.
141 // 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
142 // and this nonsense in the linux kernel: https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757
143
144 // Our MAC addr.
145 let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC];
146 // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has.
147 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
148
149 // Create classes on the builder.
150 let class = CdcNcmClass::new(&mut builder, &mut res.serial_state, host_mac_addr, 64);
151
152 // Build the builder.
153 let usb = builder.build();
154
155 unwrap!(spawner.spawn(usb_task(usb)));
156
157 let (tx, rx) = class.split();
158 unwrap!(spawner.spawn(usb_ncm_rx_task(rx)));
159 unwrap!(spawner.spawn(usb_ncm_tx_task(tx)));
160
161 let config = embassy_net::ConfigStrategy::Dhcp;
162 //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config {
163 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
164 // dns_servers: Vec::new(),
165 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
166 //});
167
168 // Generate random seed
169 let mut rng = Rng::new(p.RNG, interrupt::take!(RNG));
170 let mut seed = [0; 8];
171 rng.blocking_fill_bytes(&mut seed);
172 let seed = u64::from_le_bytes(seed);
173
174 // Init network stack
175 let device = Device { mac_addr: our_mac_addr };
176 let stack = &*singleton!(Stack::new(
177 device,
178 config,
179 singleton!(StackResources::<1, 2, 8>::new()),
180 seed
181 ));
182
183 unwrap!(spawner.spawn(net_task(stack)));
184
185 // And now we can use it!
186
187 let mut rx_buffer = [0; 4096];
188 let mut tx_buffer = [0; 4096];
189 let mut buf = [0; 4096];
190
191 loop {
192 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
193 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
194
195 info!("Listening on TCP:1234...");
196 if let Err(e) = socket.accept(1234).await {
197 warn!("accept error: {:?}", e);
198 continue;
199 }
200
201 info!("Received connection from {:?}", socket.remote_endpoint());
202
203 loop {
204 let n = match socket.read(&mut buf).await {
205 Ok(0) => {
206 warn!("read EOF");
207 break;
208 }
209 Ok(n) => n,
210 Err(e) => {
211 warn!("read error: {:?}", e);
212 break;
213 }
214 };
215
216 info!("rxd {:02x}", &buf[..n]);
217
218 match socket.write_all(&buf[..n]).await {
219 Ok(()) => {}
220 Err(e) => {
221 warn!("write error: {:?}", e);
222 break;
223 }
224 };
225 }
226 }
227}
228
229static TX_CHANNEL: Channel<ThreadModeRawMutex, PacketBuf, 8> = Channel::new();
230static RX_CHANNEL: Channel<ThreadModeRawMutex, PacketBuf, 8> = Channel::new();
231static LINK_UP: AtomicBool = AtomicBool::new(false);
232
233struct Device {
234 mac_addr: [u8; 6],
235}
236
237impl embassy_net::Device for Device {
238 fn register_waker(&mut self, waker: &Waker) {
239 // loopy loopy wakey wakey
240 waker.wake_by_ref()
241 }
242
243 fn link_state(&mut self) -> embassy_net::LinkState {
244 match LINK_UP.load(Ordering::Relaxed) {
245 true => embassy_net::LinkState::Up,
246 false => embassy_net::LinkState::Down,
247 }
248 }
249
250 fn capabilities(&self) -> embassy_net::DeviceCapabilities {
251 let mut caps = embassy_net::DeviceCapabilities::default();
252 caps.max_transmission_unit = 1514; // 1500 IP + 14 ethernet header
253 caps.medium = embassy_net::Medium::Ethernet;
254 caps
255 }
256
257 fn is_transmit_ready(&mut self) -> bool {
258 true
259 }
260
261 fn transmit(&mut self, pkt: PacketBuf) {
262 if TX_CHANNEL.try_send(pkt).is_err() {
263 warn!("TX failed")
264 }
265 }
266
267 fn receive<'a>(&mut self) -> Option<PacketBuf> {
268 RX_CHANNEL.try_recv().ok()
269 }
270
271 fn ethernet_address(&self) -> [u8; 6] {
272 self.mac_addr
273 }
274}
diff --git a/examples/nrf/.cargo/config.toml b/examples/nrf52840/.cargo/config.toml
index 8ca28df39..8ca28df39 100644
--- a/examples/nrf/.cargo/config.toml
+++ b/examples/nrf52840/.cargo/config.toml
diff --git a/examples/nrf/Cargo.toml b/examples/nrf52840/Cargo.toml
index 9ebd04845..cfdda076e 100644
--- a/examples/nrf/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -1,25 +1,31 @@
1[package] 1[package]
2edition = "2021" 2edition = "2021"
3name = "embassy-nrf-examples" 3name = "embassy-nrf52840-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[features] 7[features]
8default = ["nightly"] 8default = ["nightly"]
9nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net"] 9msos-descriptor = ["embassy-usb/msos-descriptor"]
10nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-usb", "embedded-io/async", "embassy-net",
11 "embassy-lora", "lorawan-device", "lorawan"]
10 12
11[dependencies] 13[dependencies]
12embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
13embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 15embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
14embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 16embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
15embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 17embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
16embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } 18embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
17embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"], optional = true } 19embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true }
18embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true } 20embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"], optional = true }
19embedded-io = "0.3.0" 21embedded-io = "0.4.0"
22embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx126x", "time", "defmt"], optional = true }
23
24lorawan-device = { version = "0.8.0", default-features = false, features = ["async"], optional = true }
25lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"], optional = true }
20 26
21defmt = "0.3" 27defmt = "0.3"
22defmt-rtt = "0.3" 28defmt-rtt = "0.4"
23 29
24static_cell = "1.0" 30static_cell = "1.0"
25cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 31cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
@@ -30,3 +36,7 @@ rand = { version = "0.8.4", default-features = false }
30embedded-storage = "0.3.0" 36embedded-storage = "0.3.0"
31usbd-hid = "0.6.0" 37usbd-hid = "0.6.0"
32serde = { version = "1.0.136", default-features = false } 38serde = { version = "1.0.136", default-features = false }
39
40[[bin]]
41name = "usb_serial_winusb"
42required-features = ["msos-descriptor"]
diff --git a/examples/nrf52840/build.rs b/examples/nrf52840/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/nrf52840/build.rs
@@ -0,0 +1,35 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
35}
diff --git a/examples/nrf/memory.x b/examples/nrf52840/memory.x
index 9b04edec0..9b04edec0 100644
--- a/examples/nrf/memory.x
+++ b/examples/nrf52840/memory.x
diff --git a/examples/nrf/src/bin/awaitable_timer.rs b/examples/nrf52840/src/bin/awaitable_timer.rs
index b32af236c..b32af236c 100644
--- a/examples/nrf/src/bin/awaitable_timer.rs
+++ b/examples/nrf52840/src/bin/awaitable_timer.rs
diff --git a/examples/nrf/src/bin/blinky.rs b/examples/nrf52840/src/bin/blinky.rs
index 513f6cd82..513f6cd82 100644
--- a/examples/nrf/src/bin/blinky.rs
+++ b/examples/nrf52840/src/bin/blinky.rs
diff --git a/examples/nrf/src/bin/buffered_uart.rs b/examples/nrf52840/src/bin/buffered_uart.rs
index ea566f4b2..ea566f4b2 100644
--- a/examples/nrf/src/bin/buffered_uart.rs
+++ b/examples/nrf52840/src/bin/buffered_uart.rs
diff --git a/examples/nrf/src/bin/channel.rs b/examples/nrf52840/src/bin/channel.rs
index d782a79e7..d782a79e7 100644
--- a/examples/nrf/src/bin/channel.rs
+++ b/examples/nrf52840/src/bin/channel.rs
diff --git a/examples/nrf/src/bin/channel_sender_receiver.rs b/examples/nrf52840/src/bin/channel_sender_receiver.rs
index fcccdaed5..fcccdaed5 100644
--- a/examples/nrf/src/bin/channel_sender_receiver.rs
+++ b/examples/nrf52840/src/bin/channel_sender_receiver.rs
diff --git a/examples/nrf/src/bin/executor_fairness_test.rs b/examples/nrf52840/src/bin/executor_fairness_test.rs
index 2a28f2763..2a28f2763 100644
--- a/examples/nrf/src/bin/executor_fairness_test.rs
+++ b/examples/nrf52840/src/bin/executor_fairness_test.rs
diff --git a/examples/nrf/src/bin/gpiote_channel.rs b/examples/nrf52840/src/bin/gpiote_channel.rs
index 5bfd02465..5bfd02465 100644
--- a/examples/nrf/src/bin/gpiote_channel.rs
+++ b/examples/nrf52840/src/bin/gpiote_channel.rs
diff --git a/examples/nrf/src/bin/gpiote_port.rs b/examples/nrf52840/src/bin/gpiote_port.rs
index 0155d539e..0155d539e 100644
--- a/examples/nrf/src/bin/gpiote_port.rs
+++ b/examples/nrf52840/src/bin/gpiote_port.rs
diff --git a/examples/nrf52840/src/bin/i2s_effect.rs b/examples/nrf52840/src/bin/i2s_effect.rs
new file mode 100644
index 000000000..52d46e4f9
--- /dev/null
+++ b/examples/nrf52840/src/bin/i2s_effect.rs
@@ -0,0 +1,117 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::f32::consts::PI;
6
7use defmt::{error, info};
8use embassy_executor::Spawner;
9use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S};
10use embassy_nrf::interrupt;
11use {defmt_rtt as _, panic_probe as _};
12
13type Sample = i16;
14
15const NUM_BUFFERS: usize = 2;
16const NUM_SAMPLES: usize = 4;
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) {
20 let p = embassy_nrf::init(Default::default());
21
22 let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
23
24 let sample_rate = master_clock.sample_rate();
25 info!("Sample rate: {}", sample_rate);
26
27 let mut config = Config::default();
28 config.sample_width = SampleWidth::_16bit;
29 config.channels = Channels::MonoLeft;
30
31 let irq = interrupt::take!(I2S);
32 let buffers_out = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
33 let buffers_in = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
34 let mut full_duplex_stream = I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).full_duplex(
35 p.P0_29,
36 p.P0_28,
37 buffers_out,
38 buffers_in,
39 );
40
41 let mut modulator = SineOsc::new();
42 modulator.set_frequency(8.0, 1.0 / sample_rate as f32);
43 modulator.set_amplitude(1.0);
44
45 full_duplex_stream.start().await.expect("I2S Start");
46
47 loop {
48 let (buff_out, buff_in) = full_duplex_stream.buffers();
49 for i in 0..NUM_SAMPLES {
50 let modulation = (Sample::SCALE as f32 * bipolar_to_unipolar(modulator.generate())) as Sample;
51 buff_out[i] = buff_in[i] * modulation;
52 }
53
54 if let Err(err) = full_duplex_stream.send_and_receive().await {
55 error!("{}", err);
56 }
57 }
58}
59
60struct SineOsc {
61 amplitude: f32,
62 modulo: f32,
63 phase_inc: f32,
64}
65
66impl SineOsc {
67 const B: f32 = 4.0 / PI;
68 const C: f32 = -4.0 / (PI * PI);
69 const P: f32 = 0.225;
70
71 pub fn new() -> Self {
72 Self {
73 amplitude: 1.0,
74 modulo: 0.0,
75 phase_inc: 0.0,
76 }
77 }
78
79 pub fn set_frequency(&mut self, freq: f32, inv_sample_rate: f32) {
80 self.phase_inc = freq * inv_sample_rate;
81 }
82
83 pub fn set_amplitude(&mut self, amplitude: f32) {
84 self.amplitude = amplitude;
85 }
86
87 pub fn generate(&mut self) -> f32 {
88 let signal = self.parabolic_sin(self.modulo);
89 self.modulo += self.phase_inc;
90 if self.modulo < 0.0 {
91 self.modulo += 1.0;
92 } else if self.modulo > 1.0 {
93 self.modulo -= 1.0;
94 }
95 signal * self.amplitude
96 }
97
98 fn parabolic_sin(&mut self, modulo: f32) -> f32 {
99 let angle = PI - modulo * 2.0 * PI;
100 let y = Self::B * angle + Self::C * angle * abs(angle);
101 Self::P * (y * abs(y) - y) + y
102 }
103}
104
105#[inline]
106fn abs(value: f32) -> f32 {
107 if value < 0.0 {
108 -value
109 } else {
110 value
111 }
112}
113
114#[inline]
115fn bipolar_to_unipolar(value: f32) -> f32 {
116 (value + 1.0) / 2.0
117}
diff --git a/examples/nrf52840/src/bin/i2s_monitor.rs b/examples/nrf52840/src/bin/i2s_monitor.rs
new file mode 100644
index 000000000..5ebfd9542
--- /dev/null
+++ b/examples/nrf52840/src/bin/i2s_monitor.rs
@@ -0,0 +1,115 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{debug, error, info};
6use embassy_executor::Spawner;
7use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
8use embassy_nrf::interrupt;
9use embassy_nrf::pwm::{Prescaler, SimplePwm};
10use {defmt_rtt as _, panic_probe as _};
11
12type Sample = i16;
13
14const NUM_SAMPLES: usize = 500;
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let p = embassy_nrf::init(Default::default());
19
20 let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
21
22 let sample_rate = master_clock.sample_rate();
23 info!("Sample rate: {}", sample_rate);
24
25 let mut config = Config::default();
26 config.sample_width = SampleWidth::_16bit;
27 config.channels = Channels::MonoLeft;
28
29 let irq = interrupt::take!(I2S);
30 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
31 let mut input_stream =
32 I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers);
33
34 // Configure the PWM to use the pins corresponding to the RGB leds
35 let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24);
36 pwm.set_prescaler(Prescaler::Div1);
37 pwm.set_max_duty(255);
38
39 let mut rms_online = RmsOnline::<NUM_SAMPLES>::default();
40
41 input_stream.start().await.expect("I2S Start");
42
43 loop {
44 let rms = rms_online.process(input_stream.buffer());
45 let rgb = rgb_from_rms(rms);
46
47 debug!("RMS: {}, RGB: {:?}", rms, rgb);
48 for i in 0..3 {
49 pwm.set_duty(i, rgb[i].into());
50 }
51
52 if let Err(err) = input_stream.receive().await {
53 error!("{}", err);
54 }
55 }
56}
57
58/// RMS from 0.0 until 0.75 will give green with a proportional intensity
59/// RMS from 0.75 until 0.9 will give a blend between orange and red proportionally to the intensity
60/// RMS above 0.9 will give a red with a proportional intensity
61fn rgb_from_rms(rms: f32) -> [u8; 3] {
62 if rms < 0.75 {
63 let intensity = rms / 0.75;
64 [0, (intensity * 165.0) as u8, 0]
65 } else if rms < 0.9 {
66 let intensity = (rms - 0.75) / 0.15;
67 [200, 165 - (165.0 * intensity) as u8, 0]
68 } else {
69 let intensity = (rms - 0.9) / 0.1;
70 [200 + (55.0 * intensity) as u8, 0, 0]
71 }
72}
73
74pub struct RmsOnline<const N: usize> {
75 pub squares: [f32; N],
76 pub head: usize,
77}
78
79impl<const N: usize> Default for RmsOnline<N> {
80 fn default() -> Self {
81 RmsOnline {
82 squares: [0.0; N],
83 head: 0,
84 }
85 }
86}
87
88impl<const N: usize> RmsOnline<N> {
89 pub fn reset(&mut self) {
90 self.squares = [0.0; N];
91 self.head = 0;
92 }
93
94 pub fn process(&mut self, buf: &[Sample]) -> f32 {
95 buf.iter()
96 .for_each(|sample| self.push(*sample as f32 / Sample::SCALE as f32));
97
98 let sum_of_squares = self.squares.iter().fold(0.0, |acc, v| acc + *v);
99 Self::approx_sqrt(sum_of_squares / N as f32)
100 }
101
102 pub fn push(&mut self, signal: f32) {
103 let square = signal * signal;
104 self.squares[self.head] = square;
105 self.head = (self.head + 1) % N;
106 }
107
108 /// Approximated sqrt taken from [micromath]
109 ///
110 /// [micromath]: https://docs.rs/micromath/latest/src/micromath/float/sqrt.rs.html#11-17
111 ///
112 fn approx_sqrt(value: f32) -> f32 {
113 f32::from_bits((value.to_bits() + 0x3f80_0000) >> 1)
114 }
115}
diff --git a/examples/nrf52840/src/bin/i2s_waveform.rs b/examples/nrf52840/src/bin/i2s_waveform.rs
new file mode 100644
index 000000000..eda930677
--- /dev/null
+++ b/examples/nrf52840/src/bin/i2s_waveform.rs
@@ -0,0 +1,151 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::f32::consts::PI;
6
7use defmt::{error, info};
8use embassy_executor::Spawner;
9use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
10use embassy_nrf::interrupt;
11use {defmt_rtt as _, panic_probe as _};
12
13type Sample = i16;
14
15const NUM_SAMPLES: usize = 50;
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_nrf::init(Default::default());
20
21 let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
22
23 let sample_rate = master_clock.sample_rate();
24 info!("Sample rate: {}", sample_rate);
25
26 let mut config = Config::default();
27 config.sample_width = SampleWidth::_16bit;
28 config.channels = Channels::MonoLeft;
29
30 let irq = interrupt::take!(I2S);
31 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
32 let mut output_stream =
33 I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28, buffers);
34
35 let mut waveform = Waveform::new(1.0 / sample_rate as f32);
36
37 waveform.process(output_stream.buffer());
38
39 output_stream.start().await.expect("I2S Start");
40
41 loop {
42 waveform.process(output_stream.buffer());
43
44 if let Err(err) = output_stream.send().await {
45 error!("{}", err);
46 }
47 }
48}
49
50struct Waveform {
51 inv_sample_rate: f32,
52 carrier: SineOsc,
53 freq_mod: SineOsc,
54 amp_mod: SineOsc,
55}
56
57impl Waveform {
58 fn new(inv_sample_rate: f32) -> Self {
59 let mut carrier = SineOsc::new();
60 carrier.set_frequency(110.0, inv_sample_rate);
61
62 let mut freq_mod = SineOsc::new();
63 freq_mod.set_frequency(1.0, inv_sample_rate);
64 freq_mod.set_amplitude(1.0);
65
66 let mut amp_mod = SineOsc::new();
67 amp_mod.set_frequency(16.0, inv_sample_rate);
68 amp_mod.set_amplitude(0.5);
69
70 Self {
71 inv_sample_rate,
72 carrier,
73 freq_mod,
74 amp_mod,
75 }
76 }
77
78 fn process(&mut self, buf: &mut [Sample]) {
79 for sample in buf.chunks_mut(1) {
80 let freq_modulation = bipolar_to_unipolar(self.freq_mod.generate());
81 self.carrier
82 .set_frequency(110.0 + 440.0 * freq_modulation, self.inv_sample_rate);
83
84 let amp_modulation = bipolar_to_unipolar(self.amp_mod.generate());
85 self.carrier.set_amplitude(amp_modulation);
86
87 let signal = self.carrier.generate();
88
89 sample[0] = (Sample::SCALE as f32 * signal) as Sample;
90 }
91 }
92}
93
94struct SineOsc {
95 amplitude: f32,
96 modulo: f32,
97 phase_inc: f32,
98}
99
100impl SineOsc {
101 const B: f32 = 4.0 / PI;
102 const C: f32 = -4.0 / (PI * PI);
103 const P: f32 = 0.225;
104
105 pub fn new() -> Self {
106 Self {
107 amplitude: 1.0,
108 modulo: 0.0,
109 phase_inc: 0.0,
110 }
111 }
112
113 pub fn set_frequency(&mut self, freq: f32, inv_sample_rate: f32) {
114 self.phase_inc = freq * inv_sample_rate;
115 }
116
117 pub fn set_amplitude(&mut self, amplitude: f32) {
118 self.amplitude = amplitude;
119 }
120
121 pub fn generate(&mut self) -> f32 {
122 let signal = self.parabolic_sin(self.modulo);
123 self.modulo += self.phase_inc;
124 if self.modulo < 0.0 {
125 self.modulo += 1.0;
126 } else if self.modulo > 1.0 {
127 self.modulo -= 1.0;
128 }
129 signal * self.amplitude
130 }
131
132 fn parabolic_sin(&mut self, modulo: f32) -> f32 {
133 let angle = PI - modulo * 2.0 * PI;
134 let y = Self::B * angle + Self::C * angle * abs(angle);
135 Self::P * (y * abs(y) - y) + y
136 }
137}
138
139#[inline]
140fn abs(value: f32) -> f32 {
141 if value < 0.0 {
142 -value
143 } else {
144 value
145 }
146}
147
148#[inline]
149fn bipolar_to_unipolar(value: f32) -> f32 {
150 (value + 1.0) / 2.0
151}
diff --git a/examples/nrf52840/src/bin/lora_p2p_report.rs b/examples/nrf52840/src/bin/lora_p2p_report.rs
new file mode 100644
index 000000000..d512b83f6
--- /dev/null
+++ b/examples/nrf52840/src/bin/lora_p2p_report.rs
@@ -0,0 +1,78 @@
1//! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio.
2//! Other nrf/sx126x combinations may work with appropriate pin modifications.
3//! It demonstates LORA P2P functionality in conjunction with example lora_p2p_sense.rs.
4#![no_std]
5#![no_main]
6#![macro_use]
7#![allow(dead_code)]
8#![feature(type_alias_impl_trait)]
9
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_lora::sx126x::*;
13use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
14use embassy_nrf::{interrupt, spim};
15use embassy_time::{Duration, Timer};
16use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor};
17use {defmt_rtt as _, panic_probe as _};
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 let p = embassy_nrf::init(Default::default());
22 let mut spi_config = spim::Config::default();
23 spi_config.frequency = spim::Frequency::M16;
24
25 let mut radio = {
26 let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
27 let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config);
28
29 let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
30 let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
31 let dio1 = Input::new(p.P1_15.degrade(), Pull::Down);
32 let busy = Input::new(p.P1_14.degrade(), Pull::Down);
33 let antenna_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard);
34 let antenna_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard);
35
36 match Sx126xRadio::new(spim, cs, reset, antenna_rx, antenna_tx, dio1, busy, false).await {
37 Ok(r) => r,
38 Err(err) => {
39 info!("Sx126xRadio error = {}", err);
40 return;
41 }
42 }
43 };
44
45 let mut debug_indicator = Output::new(p.P1_03, Level::Low, OutputDrive::Standard);
46 let mut start_indicator = Output::new(p.P1_04, Level::Low, OutputDrive::Standard);
47
48 start_indicator.set_high();
49 Timer::after(Duration::from_secs(5)).await;
50 start_indicator.set_low();
51
52 loop {
53 let rf_config = RfConfig {
54 frequency: 903900000, // channel in Hz
55 bandwidth: Bandwidth::_250KHz,
56 spreading_factor: SpreadingFactor::_10,
57 coding_rate: CodingRate::_4_8,
58 };
59
60 let mut buffer = [00u8; 100];
61
62 // P2P receive
63 match radio.rx(rf_config, &mut buffer).await {
64 Ok((buffer_len, rx_quality)) => info!(
65 "RX received = {:?} with length = {} rssi = {} snr = {}",
66 &buffer[0..buffer_len],
67 buffer_len,
68 rx_quality.rssi(),
69 rx_quality.snr()
70 ),
71 Err(err) => info!("RX error = {}", err),
72 }
73
74 debug_indicator.set_high();
75 Timer::after(Duration::from_secs(2)).await;
76 debug_indicator.set_low();
77 }
78}
diff --git a/examples/nrf52840/src/bin/lora_p2p_sense.rs b/examples/nrf52840/src/bin/lora_p2p_sense.rs
new file mode 100644
index 000000000..b9768874b
--- /dev/null
+++ b/examples/nrf52840/src/bin/lora_p2p_sense.rs
@@ -0,0 +1,125 @@
1//! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio.
2//! Other nrf/sx126x combinations may work with appropriate pin modifications.
3//! It demonstates LORA P2P functionality in conjunction with example lora_p2p_report.rs.
4#![no_std]
5#![no_main]
6#![macro_use]
7#![feature(type_alias_impl_trait)]
8#![feature(alloc_error_handler)]
9#![allow(incomplete_features)]
10
11use defmt::*;
12use embassy_executor::Spawner;
13use embassy_lora::sx126x::*;
14use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
15use embassy_nrf::{interrupt, spim};
16use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
17use embassy_sync::pubsub::{PubSubChannel, Publisher};
18use embassy_time::{Duration, Timer};
19use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor, TxConfig};
20use {defmt_rtt as _, panic_probe as _, panic_probe as _};
21
22// Message bus: queue of 2, 1 subscriber (Lora P2P), 2 publishers (temperature, motion detection)
23static MESSAGE_BUS: PubSubChannel<CriticalSectionRawMutex, Message, 2, 1, 2> = PubSubChannel::new();
24
25#[derive(Clone, defmt::Format)]
26enum Message {
27 Temperature(i32),
28 MotionDetected,
29}
30
31#[embassy_executor::task]
32async fn temperature_task(publisher: Publisher<'static, CriticalSectionRawMutex, Message, 2, 1, 2>) {
33 // Publish a fake temperature every 43 seconds, minimizing LORA traffic.
34 loop {
35 Timer::after(Duration::from_secs(43)).await;
36 publisher.publish(Message::Temperature(9)).await;
37 }
38}
39
40#[embassy_executor::task]
41async fn motion_detection_task(publisher: Publisher<'static, CriticalSectionRawMutex, Message, 2, 1, 2>) {
42 // Publish a fake motion detection every 79 seconds, minimizing LORA traffic.
43 loop {
44 Timer::after(Duration::from_secs(79)).await;
45 publisher.publish(Message::MotionDetected).await;
46 }
47}
48
49#[embassy_executor::main]
50async fn main(spawner: Spawner) {
51 let p = embassy_nrf::init(Default::default());
52 // set up to funnel temperature and motion detection events to the Lora Tx task
53 let mut lora_tx_subscriber = unwrap!(MESSAGE_BUS.subscriber());
54 let temperature_publisher = unwrap!(MESSAGE_BUS.publisher());
55 let motion_detection_publisher = unwrap!(MESSAGE_BUS.publisher());
56
57 let mut spi_config = spim::Config::default();
58 spi_config.frequency = spim::Frequency::M16;
59
60 let mut radio = {
61 let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
62 let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config);
63
64 let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
65 let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
66 let dio1 = Input::new(p.P1_15.degrade(), Pull::Down);
67 let busy = Input::new(p.P1_14.degrade(), Pull::Down);
68 let antenna_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard);
69 let antenna_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard);
70
71 match Sx126xRadio::new(spim, cs, reset, antenna_rx, antenna_tx, dio1, busy, false).await {
72 Ok(r) => r,
73 Err(err) => {
74 info!("Sx126xRadio error = {}", err);
75 return;
76 }
77 }
78 };
79
80 let mut start_indicator = Output::new(p.P1_04, Level::Low, OutputDrive::Standard);
81
82 start_indicator.set_high();
83 Timer::after(Duration::from_secs(5)).await;
84 start_indicator.set_low();
85
86 match radio.lora.sleep().await {
87 Ok(()) => info!("Sleep successful"),
88 Err(err) => info!("Sleep unsuccessful = {}", err),
89 }
90
91 unwrap!(spawner.spawn(temperature_task(temperature_publisher)));
92 unwrap!(spawner.spawn(motion_detection_task(motion_detection_publisher)));
93
94 loop {
95 let message = lora_tx_subscriber.next_message_pure().await;
96
97 let tx_config = TxConfig {
98 // 11 byte maximum payload for Bandwidth 125 and SF 10
99 pw: 10, // up to 20
100 rf: RfConfig {
101 frequency: 903900000, // channel in Hz, not MHz
102 bandwidth: Bandwidth::_250KHz,
103 spreading_factor: SpreadingFactor::_10,
104 coding_rate: CodingRate::_4_8,
105 },
106 };
107
108 let mut buffer = [0x00u8];
109 match message {
110 Message::Temperature(temperature) => buffer[0] = temperature as u8,
111 Message::MotionDetected => buffer[0] = 0x01u8,
112 };
113
114 // unencrypted
115 match radio.tx(tx_config, &buffer).await {
116 Ok(ret_val) => info!("TX ret_val = {}", ret_val),
117 Err(err) => info!("TX error = {}", err),
118 }
119
120 match radio.lora.sleep().await {
121 Ok(()) => info!("Sleep successful"),
122 Err(err) => info!("Sleep unsuccessful = {}", err),
123 }
124 }
125}
diff --git a/examples/nrf52840/src/bin/manually_create_executor.rs b/examples/nrf52840/src/bin/manually_create_executor.rs
new file mode 100644
index 000000000..12ce660f9
--- /dev/null
+++ b/examples/nrf52840/src/bin/manually_create_executor.rs
@@ -0,0 +1,49 @@
1// This example showcases how to manually create an executor.
2// This is what the #[embassy::main] macro does behind the scenes.
3
4#![no_std]
5#![no_main]
6#![feature(type_alias_impl_trait)]
7
8use cortex_m_rt::entry;
9use defmt::{info, unwrap};
10use embassy_executor::Executor;
11use embassy_time::{Duration, Timer};
12use static_cell::StaticCell;
13use {defmt_rtt as _, panic_probe as _};
14
15#[embassy_executor::task]
16async fn run1() {
17 loop {
18 info!("BIG INFREQUENT TICK");
19 Timer::after(Duration::from_ticks(64000)).await;
20 }
21}
22
23#[embassy_executor::task]
24async fn run2() {
25 loop {
26 info!("tick");
27 Timer::after(Duration::from_ticks(13000)).await;
28 }
29}
30
31static EXECUTOR: StaticCell<Executor> = StaticCell::new();
32
33#[entry]
34fn main() -> ! {
35 info!("Hello World!");
36
37 let _p = embassy_nrf::init(Default::default());
38
39 // Create the executor and put it in a StaticCell, because `run` needs `&'static mut Executor`.
40 let executor = EXECUTOR.init(Executor::new());
41
42 // Run it.
43 // `run` calls the closure then runs the executor forever. It never returns.
44 executor.run(|spawner| {
45 // Here we get access to a spawner to spawn the initial tasks.
46 unwrap!(spawner.spawn(run1()));
47 unwrap!(spawner.spawn(run2()));
48 });
49}
diff --git a/examples/nrf/src/bin/multiprio.rs b/examples/nrf52840/src/bin/multiprio.rs
index 25806ae48..25806ae48 100644
--- a/examples/nrf/src/bin/multiprio.rs
+++ b/examples/nrf52840/src/bin/multiprio.rs
diff --git a/examples/nrf/src/bin/mutex.rs b/examples/nrf52840/src/bin/mutex.rs
index c402c6ba1..c402c6ba1 100644
--- a/examples/nrf/src/bin/mutex.rs
+++ b/examples/nrf52840/src/bin/mutex.rs
diff --git a/examples/nrf/src/bin/nvmc.rs b/examples/nrf52840/src/bin/nvmc.rs
index 75d090fbb..75d090fbb 100644
--- a/examples/nrf/src/bin/nvmc.rs
+++ b/examples/nrf52840/src/bin/nvmc.rs
diff --git a/examples/nrf52840/src/bin/pdm.rs b/examples/nrf52840/src/bin/pdm.rs
new file mode 100644
index 000000000..7388580fb
--- /dev/null
+++ b/examples/nrf52840/src/bin/pdm.rs
@@ -0,0 +1,33 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::pdm::{Config, Pdm};
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_p: Spawner) {
14 let p = embassy_nrf::init(Default::default());
15 let config = Config::default();
16 let mut pdm = Pdm::new(p.PDM, interrupt::take!(PDM), p.P0_01, p.P0_00, config);
17
18 loop {
19 pdm.start().await;
20
21 // wait some time till the microphon settled
22 Timer::after(Duration::from_millis(1000)).await;
23
24 const SAMPLES: usize = 2048;
25 let mut buf = [0i16; SAMPLES];
26 pdm.sample(&mut buf).await.unwrap();
27
28 info!("samples: {:?}", &buf);
29
30 pdm.stop().await;
31 Timer::after(Duration::from_millis(100)).await;
32 }
33}
diff --git a/examples/nrf/src/bin/ppi.rs b/examples/nrf52840/src/bin/ppi.rs
index d74ce4064..d74ce4064 100644
--- a/examples/nrf/src/bin/ppi.rs
+++ b/examples/nrf52840/src/bin/ppi.rs
diff --git a/examples/nrf/src/bin/pubsub.rs b/examples/nrf52840/src/bin/pubsub.rs
index 688e6d075..688e6d075 100644
--- a/examples/nrf/src/bin/pubsub.rs
+++ b/examples/nrf52840/src/bin/pubsub.rs
diff --git a/examples/nrf/src/bin/pwm.rs b/examples/nrf52840/src/bin/pwm.rs
index 1698c0bc8..1698c0bc8 100644
--- a/examples/nrf/src/bin/pwm.rs
+++ b/examples/nrf52840/src/bin/pwm.rs
diff --git a/examples/nrf/src/bin/pwm_double_sequence.rs b/examples/nrf52840/src/bin/pwm_double_sequence.rs
index 16e50e909..16e50e909 100644
--- a/examples/nrf/src/bin/pwm_double_sequence.rs
+++ b/examples/nrf52840/src/bin/pwm_double_sequence.rs
diff --git a/examples/nrf/src/bin/pwm_sequence.rs b/examples/nrf52840/src/bin/pwm_sequence.rs
index b9aca9aaa..b9aca9aaa 100644
--- a/examples/nrf/src/bin/pwm_sequence.rs
+++ b/examples/nrf52840/src/bin/pwm_sequence.rs
diff --git a/examples/nrf/src/bin/pwm_sequence_ppi.rs b/examples/nrf52840/src/bin/pwm_sequence_ppi.rs
index 6594fa348..6594fa348 100644
--- a/examples/nrf/src/bin/pwm_sequence_ppi.rs
+++ b/examples/nrf52840/src/bin/pwm_sequence_ppi.rs
diff --git a/examples/nrf/src/bin/pwm_sequence_ws2812b.rs b/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs
index 711c8a17b..711c8a17b 100644
--- a/examples/nrf/src/bin/pwm_sequence_ws2812b.rs
+++ b/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs
diff --git a/examples/nrf/src/bin/pwm_servo.rs b/examples/nrf52840/src/bin/pwm_servo.rs
index 19228f433..19228f433 100644
--- a/examples/nrf/src/bin/pwm_servo.rs
+++ b/examples/nrf52840/src/bin/pwm_servo.rs
diff --git a/examples/nrf/src/bin/qdec.rs b/examples/nrf52840/src/bin/qdec.rs
index 600bba07a..600bba07a 100644
--- a/examples/nrf/src/bin/qdec.rs
+++ b/examples/nrf52840/src/bin/qdec.rs
diff --git a/examples/nrf/src/bin/qspi.rs b/examples/nrf52840/src/bin/qspi.rs
index bdcf710b8..bdcf710b8 100644
--- a/examples/nrf/src/bin/qspi.rs
+++ b/examples/nrf52840/src/bin/qspi.rs
diff --git a/examples/nrf/src/bin/qspi_lowpower.rs b/examples/nrf52840/src/bin/qspi_lowpower.rs
index 9341a2376..9341a2376 100644
--- a/examples/nrf/src/bin/qspi_lowpower.rs
+++ b/examples/nrf52840/src/bin/qspi_lowpower.rs
diff --git a/examples/nrf/src/bin/raw_spawn.rs b/examples/nrf52840/src/bin/raw_spawn.rs
index 1b067f5e4..1b067f5e4 100644
--- a/examples/nrf/src/bin/raw_spawn.rs
+++ b/examples/nrf52840/src/bin/raw_spawn.rs
diff --git a/examples/nrf/src/bin/rng.rs b/examples/nrf52840/src/bin/rng.rs
index 647073949..647073949 100644
--- a/examples/nrf/src/bin/rng.rs
+++ b/examples/nrf52840/src/bin/rng.rs
diff --git a/examples/nrf/src/bin/saadc.rs b/examples/nrf52840/src/bin/saadc.rs
index 7cf588090..7cf588090 100644
--- a/examples/nrf/src/bin/saadc.rs
+++ b/examples/nrf52840/src/bin/saadc.rs
diff --git a/examples/nrf/src/bin/saadc_continuous.rs b/examples/nrf52840/src/bin/saadc_continuous.rs
index bb50ac65e..2551d15fd 100644
--- a/examples/nrf/src/bin/saadc_continuous.rs
+++ b/examples/nrf52840/src/bin/saadc_continuous.rs
@@ -5,7 +5,7 @@
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::interrupt; 7use embassy_nrf::interrupt;
8use embassy_nrf::saadc::{ChannelConfig, Config, Saadc, SamplerState}; 8use embassy_nrf::saadc::{CallbackResult, ChannelConfig, Config, Saadc};
9use embassy_nrf::timer::Frequency; 9use embassy_nrf::timer::Frequency;
10use embassy_time::Duration; 10use embassy_time::Duration;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
@@ -61,7 +61,7 @@ async fn main(_p: Spawner) {
61 c = 0; 61 c = 0;
62 a = 0; 62 a = 0;
63 } 63 }
64 SamplerState::Sampled 64 CallbackResult::Continue
65 }, 65 },
66 ) 66 )
67 .await; 67 .await;
diff --git a/examples/nrf/src/bin/self_spawn.rs b/examples/nrf52840/src/bin/self_spawn.rs
index 196255a52..196255a52 100644
--- a/examples/nrf/src/bin/self_spawn.rs
+++ b/examples/nrf52840/src/bin/self_spawn.rs
diff --git a/examples/nrf/src/bin/self_spawn_current_executor.rs b/examples/nrf52840/src/bin/self_spawn_current_executor.rs
index 8a179886c..8a179886c 100644
--- a/examples/nrf/src/bin/self_spawn_current_executor.rs
+++ b/examples/nrf52840/src/bin/self_spawn_current_executor.rs
diff --git a/examples/nrf/src/bin/spim.rs b/examples/nrf52840/src/bin/spim.rs
index 132e01660..132e01660 100644
--- a/examples/nrf/src/bin/spim.rs
+++ b/examples/nrf52840/src/bin/spim.rs
diff --git a/examples/nrf52840/src/bin/spis.rs b/examples/nrf52840/src/bin/spis.rs
new file mode 100644
index 000000000..fe3b0c53d
--- /dev/null
+++ b/examples/nrf52840/src/bin/spis.rs
@@ -0,0 +1,27 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::spis::{Config, Spis};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default());
14 info!("Running!");
15
16 let irq = interrupt::take!(SPIM2_SPIS2_SPI2);
17 let mut spis = Spis::new(p.SPI2, irq, p.P0_31, p.P0_29, p.P0_28, p.P0_30, Config::default());
18
19 loop {
20 let mut rx_buf = [0_u8; 64];
21 let tx_buf = [1_u8, 2, 3, 4, 5, 6, 7, 8];
22 if let Ok((n_rx, n_tx)) = spis.transfer(&mut rx_buf, &tx_buf).await {
23 info!("RX: {:?}", rx_buf[..n_rx]);
24 info!("TX: {:?}", tx_buf[..n_tx]);
25 }
26 }
27}
diff --git a/examples/nrf/src/bin/temp.rs b/examples/nrf52840/src/bin/temp.rs
index b06ac709e..b06ac709e 100644
--- a/examples/nrf/src/bin/temp.rs
+++ b/examples/nrf52840/src/bin/temp.rs
diff --git a/examples/nrf/src/bin/timer.rs b/examples/nrf52840/src/bin/timer.rs
index c22b5acd5..c22b5acd5 100644
--- a/examples/nrf/src/bin/timer.rs
+++ b/examples/nrf52840/src/bin/timer.rs
diff --git a/examples/nrf/src/bin/twim.rs b/examples/nrf52840/src/bin/twim.rs
index a027cc1e7..a027cc1e7 100644
--- a/examples/nrf/src/bin/twim.rs
+++ b/examples/nrf52840/src/bin/twim.rs
diff --git a/examples/nrf/src/bin/twim_lowpower.rs b/examples/nrf52840/src/bin/twim_lowpower.rs
index e30cc9688..e30cc9688 100644
--- a/examples/nrf/src/bin/twim_lowpower.rs
+++ b/examples/nrf52840/src/bin/twim_lowpower.rs
diff --git a/examples/nrf52840/src/bin/twis.rs b/examples/nrf52840/src/bin/twis.rs
new file mode 100644
index 000000000..54cba9494
--- /dev/null
+++ b/examples/nrf52840/src/bin/twis.rs
@@ -0,0 +1,46 @@
1//! TWIS example
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_nrf::interrupt;
10use embassy_nrf::twis::{self, Command, Twis};
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = embassy_nrf::init(Default::default());
16
17 let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
18 let mut config = twis::Config::default();
19 // Set i2c address
20 config.address0 = 0x55;
21 let mut i2c = Twis::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
22
23 info!("Listening...");
24 loop {
25 let response = [1, 2, 3, 4, 5, 6, 7, 8];
26 // This buffer is used if the i2c master performs a Write or WriteRead
27 let mut buf = [0u8; 16];
28 match i2c.listen(&mut buf).await {
29 Ok(Command::Read) => {
30 info!("Got READ command. Respond with data:\n{:?}\n", response);
31 if let Err(e) = i2c.respond_to_read(&response).await {
32 error!("{:?}", e);
33 }
34 }
35 Ok(Command::Write(n)) => info!("Got WRITE command with data:\n{:?}\n", buf[..n]),
36 Ok(Command::WriteRead(n)) => {
37 info!("Got WRITE/READ command with data:\n{:?}", buf[..n]);
38 info!("Respond with data:\n{:?}\n", response);
39 if let Err(e) = i2c.respond_to_read(&response).await {
40 error!("{:?}", e);
41 }
42 }
43 Err(e) => error!("{:?}", e),
44 }
45 }
46}
diff --git a/examples/nrf/src/bin/uart.rs b/examples/nrf52840/src/bin/uart.rs
index 600f7a6ef..600f7a6ef 100644
--- a/examples/nrf/src/bin/uart.rs
+++ b/examples/nrf52840/src/bin/uart.rs
diff --git a/examples/nrf/src/bin/uart_idle.rs b/examples/nrf52840/src/bin/uart_idle.rs
index 09ec624c0..6af4f7097 100644
--- a/examples/nrf/src/bin/uart_idle.rs
+++ b/examples/nrf52840/src/bin/uart_idle.rs
@@ -15,7 +15,8 @@ async fn main(_spawner: Spawner) {
15 config.baudrate = uarte::Baudrate::BAUD115200; 15 config.baudrate = uarte::Baudrate::BAUD115200;
16 16
17 let irq = interrupt::take!(UARTE0_UART0); 17 let irq = interrupt::take!(UARTE0_UART0);
18 let mut uart = uarte::UarteWithIdle::new(p.UARTE0, p.TIMER0, p.PPI_CH0, p.PPI_CH1, irq, p.P0_08, p.P0_06, config); 18 let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
19 let (mut tx, mut rx) = uart.split_with_idle(p.TIMER0, p.PPI_CH0, p.PPI_CH1);
19 20
20 info!("uarte initialized!"); 21 info!("uarte initialized!");
21 22
@@ -23,12 +24,12 @@ async fn main(_spawner: Spawner) {
23 let mut buf = [0; 8]; 24 let mut buf = [0; 8];
24 buf.copy_from_slice(b"Hello!\r\n"); 25 buf.copy_from_slice(b"Hello!\r\n");
25 26
26 unwrap!(uart.write(&buf).await); 27 unwrap!(tx.write(&buf).await);
27 info!("wrote hello in uart!"); 28 info!("wrote hello in uart!");
28 29
29 loop { 30 loop {
30 info!("reading..."); 31 info!("reading...");
31 let n = unwrap!(uart.read_until_idle(&mut buf).await); 32 let n = unwrap!(rx.read_until_idle(&mut buf).await);
32 info!("got {} bytes", n); 33 info!("got {} bytes", n);
33 } 34 }
34} 35}
diff --git a/examples/nrf/src/bin/uart_split.rs b/examples/nrf52840/src/bin/uart_split.rs
index 1adaf53fd..1adaf53fd 100644
--- a/examples/nrf/src/bin/uart_split.rs
+++ b/examples/nrf52840/src/bin/uart_split.rs
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs
new file mode 100644
index 000000000..430468adf
--- /dev/null
+++ b/examples/nrf52840/src/bin/usb_ethernet.rs
@@ -0,0 +1,186 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::mem;
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_net::tcp::TcpSocket;
10use embassy_net::{Stack, StackResources};
11use embassy_nrf::rng::Rng;
12use embassy_nrf::usb::{Driver, HardwareVbusDetect};
13use embassy_nrf::{interrupt, pac, peripherals};
14use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
15use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
16use embassy_usb::{Builder, Config, UsbDevice};
17use embedded_io::asynch::Write;
18use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _};
20
21type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
22
23macro_rules! singleton {
24 ($val:expr) => {{
25 type T = impl Sized;
26 static STATIC_CELL: StaticCell<T> = StaticCell::new();
27 let (x,) = STATIC_CELL.init(($val,));
28 x
29 }};
30}
31
32const MTU: usize = 1514;
33
34#[embassy_executor::task]
35async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! {
36 device.run().await
37}
38
39#[embassy_executor::task]
40async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
41 class.run().await
42}
43
44#[embassy_executor::task]
45async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
46 stack.run().await
47}
48
49#[inline(never)]
50pub fn test_function() -> (usize, u32, [u32; 2]) {
51 let mut array = [3; 2];
52
53 let mut index = 0;
54 let mut result = 0;
55
56 for x in [1, 2] {
57 if x == 1 {
58 array[1] = 99;
59 } else {
60 index = if x == 2 { 1 } else { 0 };
61
62 // grabs value from array[0], not array[1]
63 result = array[index];
64 }
65 }
66
67 (index, result, array)
68}
69
70#[embassy_executor::main]
71async fn main(spawner: Spawner) {
72 info!("{:?}", test_function());
73
74 let p = embassy_nrf::init(Default::default());
75 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
76
77 info!("Enabling ext hfosc...");
78 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
79 while clock.events_hfclkstarted.read().bits() != 1 {}
80
81 // Create the driver, from the HAL.
82 let irq = interrupt::take!(USBD);
83 let power_irq = interrupt::take!(POWER_CLOCK);
84 let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
85
86 // Create embassy-usb Config
87 let mut config = Config::new(0xc0de, 0xcafe);
88 config.manufacturer = Some("Embassy");
89 config.product = Some("USB-Ethernet example");
90 config.serial_number = Some("12345678");
91 config.max_power = 100;
92 config.max_packet_size_0 = 64;
93
94 // Required for Windows support.
95 config.composite_with_iads = true;
96 config.device_class = 0xEF;
97 config.device_sub_class = 0x02;
98 config.device_protocol = 0x01;
99
100 // Create embassy-usb DeviceBuilder using the driver and config.
101 let mut builder = Builder::new(
102 driver,
103 config,
104 &mut singleton!([0; 256])[..],
105 &mut singleton!([0; 256])[..],
106 &mut singleton!([0; 256])[..],
107 &mut singleton!([0; 128])[..],
108 );
109
110 // Our MAC addr.
111 let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC];
112 // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has.
113 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
114
115 // Create classes on the builder.
116 let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64);
117
118 // Build the builder.
119 let usb = builder.build();
120
121 unwrap!(spawner.spawn(usb_task(usb)));
122
123 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr);
124 unwrap!(spawner.spawn(usb_ncm_task(runner)));
125
126 let config = embassy_net::Config::Dhcp(Default::default());
127 //let config = embassy_net::Config::Static(embassy_net::StaticConfig {
128 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
129 // dns_servers: Vec::new(),
130 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
131 //});
132
133 // Generate random seed
134 let mut rng = Rng::new(p.RNG, interrupt::take!(RNG));
135 let mut seed = [0; 8];
136 rng.blocking_fill_bytes(&mut seed);
137 let seed = u64::from_le_bytes(seed);
138
139 // Init network stack
140 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
141
142 unwrap!(spawner.spawn(net_task(stack)));
143
144 // And now we can use it!
145
146 let mut rx_buffer = [0; 4096];
147 let mut tx_buffer = [0; 4096];
148 let mut buf = [0; 4096];
149
150 loop {
151 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
152 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
153
154 info!("Listening on TCP:1234...");
155 if let Err(e) = socket.accept(1234).await {
156 warn!("accept error: {:?}", e);
157 continue;
158 }
159
160 info!("Received connection from {:?}", socket.remote_endpoint());
161
162 loop {
163 let n = match socket.read(&mut buf).await {
164 Ok(0) => {
165 warn!("read EOF");
166 break;
167 }
168 Ok(n) => n,
169 Err(e) => {
170 warn!("read error: {:?}", e);
171 break;
172 }
173 };
174
175 info!("rxd {:02x}", &buf[..n]);
176
177 match socket.write_all(&buf[..n]).await {
178 Ok(()) => {}
179 Err(e) => {
180 warn!("write error: {:?}", e);
181 break;
182 }
183 };
184 }
185 }
186}
diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
index 76e198719..3d8a114cd 100644
--- a/examples/nrf/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
@@ -10,13 +10,13 @@ use embassy_executor::Spawner;
10use embassy_futures::join::join; 10use embassy_futures::join::join;
11use embassy_futures::select::{select, Either}; 11use embassy_futures::select::{select, Either};
12use embassy_nrf::gpio::{Input, Pin, Pull}; 12use embassy_nrf::gpio::{Input, Pin, Pull};
13use embassy_nrf::usb::{Driver, PowerUsb}; 13use embassy_nrf::usb::{Driver, HardwareVbusDetect};
14use embassy_nrf::{interrupt, pac}; 14use embassy_nrf::{interrupt, pac};
15use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 15use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
16use embassy_sync::signal::Signal; 16use embassy_sync::signal::Signal;
17use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; 17use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
18use embassy_usb::control::OutResponse; 18use embassy_usb::control::OutResponse;
19use embassy_usb::{Builder, Config, DeviceStateHandler}; 19use embassy_usb::{Builder, Config, Handler};
20use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 20use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
21use {defmt_rtt as _, panic_probe as _}; 21use {defmt_rtt as _, panic_probe as _};
22 22
@@ -34,7 +34,7 @@ async fn main(_spawner: Spawner) {
34 // Create the driver, from the HAL. 34 // Create the driver, from the HAL.
35 let irq = interrupt::take!(USBD); 35 let irq = interrupt::take!(USBD);
36 let power_irq = interrupt::take!(POWER_CLOCK); 36 let power_irq = interrupt::take!(POWER_CLOCK);
37 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq)); 37 let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
38 38
39 // Create embassy-usb Config 39 // Create embassy-usb Config
40 let mut config = Config::new(0xc0de, 0xcafe); 40 let mut config = Config::new(0xc0de, 0xcafe);
@@ -52,7 +52,7 @@ async fn main(_spawner: Spawner) {
52 let mut bos_descriptor = [0; 256]; 52 let mut bos_descriptor = [0; 256];
53 let mut control_buf = [0; 64]; 53 let mut control_buf = [0; 64];
54 let request_handler = MyRequestHandler {}; 54 let request_handler = MyRequestHandler {};
55 let device_state_handler = MyDeviceStateHandler::new(); 55 let mut device_handler = MyDeviceHandler::new();
56 56
57 let mut state = State::new(); 57 let mut state = State::new();
58 58
@@ -63,9 +63,10 @@ async fn main(_spawner: Spawner) {
63 &mut config_descriptor, 63 &mut config_descriptor,
64 &mut bos_descriptor, 64 &mut bos_descriptor,
65 &mut control_buf, 65 &mut control_buf,
66 Some(&device_state_handler),
67 ); 66 );
68 67
68 builder.handler(&mut device_handler);
69
69 // Create classes on the builder. 70 // Create classes on the builder.
70 let config = embassy_usb::class::hid::Config { 71 let config = embassy_usb::class::hid::Config {
71 report_descriptor: KeyboardReport::desc(), 72 report_descriptor: KeyboardReport::desc(),
@@ -164,20 +165,20 @@ impl RequestHandler for MyRequestHandler {
164 } 165 }
165} 166}
166 167
167struct MyDeviceStateHandler { 168struct MyDeviceHandler {
168 configured: AtomicBool, 169 configured: AtomicBool,
169} 170}
170 171
171impl MyDeviceStateHandler { 172impl MyDeviceHandler {
172 fn new() -> Self { 173 fn new() -> Self {
173 MyDeviceStateHandler { 174 MyDeviceHandler {
174 configured: AtomicBool::new(false), 175 configured: AtomicBool::new(false),
175 } 176 }
176 } 177 }
177} 178}
178 179
179impl DeviceStateHandler for MyDeviceStateHandler { 180impl Handler for MyDeviceHandler {
180 fn enabled(&self, enabled: bool) { 181 fn enabled(&mut self, enabled: bool) {
181 self.configured.store(false, Ordering::Relaxed); 182 self.configured.store(false, Ordering::Relaxed);
182 SUSPENDED.store(false, Ordering::Release); 183 SUSPENDED.store(false, Ordering::Release);
183 if enabled { 184 if enabled {
@@ -187,17 +188,17 @@ impl DeviceStateHandler for MyDeviceStateHandler {
187 } 188 }
188 } 189 }
189 190
190 fn reset(&self) { 191 fn reset(&mut self) {
191 self.configured.store(false, Ordering::Relaxed); 192 self.configured.store(false, Ordering::Relaxed);
192 info!("Bus reset, the Vbus current limit is 100mA"); 193 info!("Bus reset, the Vbus current limit is 100mA");
193 } 194 }
194 195
195 fn addressed(&self, addr: u8) { 196 fn addressed(&mut self, addr: u8) {
196 self.configured.store(false, Ordering::Relaxed); 197 self.configured.store(false, Ordering::Relaxed);
197 info!("USB address set to: {}", addr); 198 info!("USB address set to: {}", addr);
198 } 199 }
199 200
200 fn configured(&self, configured: bool) { 201 fn configured(&mut self, configured: bool) {
201 self.configured.store(configured, Ordering::Relaxed); 202 self.configured.store(configured, Ordering::Relaxed);
202 if configured { 203 if configured {
203 info!("Device configured, it may now draw up to the configured current limit from Vbus.") 204 info!("Device configured, it may now draw up to the configured current limit from Vbus.")
@@ -206,7 +207,7 @@ impl DeviceStateHandler for MyDeviceStateHandler {
206 } 207 }
207 } 208 }
208 209
209 fn suspended(&self, suspended: bool) { 210 fn suspended(&mut self, suspended: bool) {
210 if suspended { 211 if suspended {
211 info!("Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled)."); 212 info!("Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled).");
212 SUSPENDED.store(true, Ordering::Release); 213 SUSPENDED.store(true, Ordering::Release);
diff --git a/examples/nrf/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs
index 4916a38d4..d7c9d55b7 100644
--- a/examples/nrf/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs
@@ -7,7 +7,7 @@ use core::mem;
7use defmt::*; 7use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_futures::join::join; 9use embassy_futures::join::join;
10use embassy_nrf::usb::{Driver, PowerUsb}; 10use embassy_nrf::usb::{Driver, HardwareVbusDetect};
11use embassy_nrf::{interrupt, pac}; 11use embassy_nrf::{interrupt, pac};
12use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
13use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; 13use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
@@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
28 // Create the driver, from the HAL. 28 // Create the driver, from the HAL.
29 let irq = interrupt::take!(USBD); 29 let irq = interrupt::take!(USBD);
30 let power_irq = interrupt::take!(POWER_CLOCK); 30 let power_irq = interrupt::take!(POWER_CLOCK);
31 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq)); 31 let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
32 32
33 // Create embassy-usb Config 33 // Create embassy-usb Config
34 let mut config = Config::new(0xc0de, 0xcafe); 34 let mut config = Config::new(0xc0de, 0xcafe);
@@ -55,7 +55,6 @@ async fn main(_spawner: Spawner) {
55 &mut config_descriptor, 55 &mut config_descriptor,
56 &mut bos_descriptor, 56 &mut bos_descriptor,
57 &mut control_buf, 57 &mut control_buf,
58 None,
59 ); 58 );
60 59
61 // Create classes on the builder. 60 // Create classes on the builder.
diff --git a/examples/nrf/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs
index 7c9c4184b..102d7ea60 100644
--- a/examples/nrf/src/bin/usb_serial.rs
+++ b/examples/nrf52840/src/bin/usb_serial.rs
@@ -7,7 +7,7 @@ use core::mem;
7use defmt::{info, panic}; 7use defmt::{info, panic};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_futures::join::join; 9use embassy_futures::join::join;
10use embassy_nrf::usb::{Driver, Instance, PowerUsb, UsbSupply}; 10use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect};
11use embassy_nrf::{interrupt, pac}; 11use embassy_nrf::{interrupt, pac};
12use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 12use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
13use embassy_usb::driver::EndpointError; 13use embassy_usb::driver::EndpointError;
@@ -26,7 +26,7 @@ async fn main(_spawner: Spawner) {
26 // Create the driver, from the HAL. 26 // Create the driver, from the HAL.
27 let irq = interrupt::take!(USBD); 27 let irq = interrupt::take!(USBD);
28 let power_irq = interrupt::take!(POWER_CLOCK); 28 let power_irq = interrupt::take!(POWER_CLOCK);
29 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq)); 29 let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
30 30
31 // Create embassy-usb Config 31 // Create embassy-usb Config
32 let mut config = Config::new(0xc0de, 0xcafe); 32 let mut config = Config::new(0xc0de, 0xcafe);
@@ -59,7 +59,6 @@ async fn main(_spawner: Spawner) {
59 &mut config_descriptor, 59 &mut config_descriptor,
60 &mut bos_descriptor, 60 &mut bos_descriptor,
61 &mut control_buf, 61 &mut control_buf,
62 None,
63 ); 62 );
64 63
65 // Create classes on the builder. 64 // Create classes on the builder.
@@ -97,7 +96,7 @@ impl From<EndpointError> for Disconnected {
97 } 96 }
98} 97}
99 98
100async fn echo<'d, T: Instance + 'd, P: UsbSupply + 'd>( 99async fn echo<'d, T: Instance + 'd, P: VbusDetect + 'd>(
101 class: &mut CdcAcmClass<'d, Driver<'d, T, P>>, 100 class: &mut CdcAcmClass<'d, Driver<'d, T, P>>,
102) -> Result<(), Disconnected> { 101) -> Result<(), Disconnected> {
103 let mut buf = [0; 64]; 102 let mut buf = [0; 64];
diff --git a/examples/nrf/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs
index 93efc2fe6..558d4ba60 100644
--- a/examples/nrf/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs
@@ -6,7 +6,7 @@ use core::mem;
6 6
7use defmt::{info, panic, unwrap}; 7use defmt::{info, panic, unwrap};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_nrf::usb::{Driver, PowerUsb}; 9use embassy_nrf::usb::{Driver, HardwareVbusDetect};
10use embassy_nrf::{interrupt, pac, peripherals}; 10use embassy_nrf::{interrupt, pac, peripherals};
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;
@@ -14,7 +14,7 @@ use embassy_usb::{Builder, Config, UsbDevice};
14use static_cell::StaticCell; 14use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
16 16
17type MyDriver = Driver<'static, peripherals::USBD, PowerUsb>; 17type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
18 18
19#[embassy_executor::task] 19#[embassy_executor::task]
20async fn usb_task(mut device: UsbDevice<'static, MyDriver>) { 20async fn usb_task(mut device: UsbDevice<'static, MyDriver>) {
@@ -42,7 +42,7 @@ async fn main(spawner: Spawner) {
42 // Create the driver, from the HAL. 42 // Create the driver, from the HAL.
43 let irq = interrupt::take!(USBD); 43 let irq = interrupt::take!(USBD);
44 let power_irq = interrupt::take!(POWER_CLOCK); 44 let power_irq = interrupt::take!(POWER_CLOCK);
45 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq)); 45 let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
46 46
47 // Create embassy-usb Config 47 // Create embassy-usb Config
48 let mut config = Config::new(0xc0de, 0xcafe); 48 let mut config = Config::new(0xc0de, 0xcafe);
@@ -83,7 +83,6 @@ async fn main(spawner: Spawner) {
83 &mut res.config_descriptor, 83 &mut res.config_descriptor,
84 &mut res.bos_descriptor, 84 &mut res.bos_descriptor,
85 &mut res.control_buf, 85 &mut res.control_buf,
86 None,
87 ); 86 );
88 87
89 // Create classes on the builder. 88 // Create classes on the builder.
diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs
new file mode 100644
index 000000000..6561fc3b4
--- /dev/null
+++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs
@@ -0,0 +1,130 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::mem;
6
7use defmt::{info, panic};
8use embassy_executor::Spawner;
9use embassy_futures::join::join;
10use embassy_nrf::usb::{Driver, HardwareVbusDetect, Instance, VbusDetect};
11use embassy_nrf::{interrupt, pac};
12use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
13use embassy_usb::driver::EndpointError;
14use embassy_usb::msos::{self, windows_version};
15use embassy_usb::types::InterfaceNumber;
16use embassy_usb::{Builder, Config};
17use {defmt_rtt as _, panic_probe as _};
18
19// This is a randomly generated GUID to allow clients on Windows to find our device
20const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"];
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
24 let p = embassy_nrf::init(Default::default());
25 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
26
27 info!("Enabling ext hfosc...");
28 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
29 while clock.events_hfclkstarted.read().bits() != 1 {}
30
31 // Create the driver, from the HAL.
32 let irq = interrupt::take!(USBD);
33 let power_irq = interrupt::take!(POWER_CLOCK);
34 let driver = Driver::new(p.USBD, irq, HardwareVbusDetect::new(power_irq));
35
36 // Create embassy-usb Config
37 let mut config = Config::new(0xc0de, 0xcafe);
38 config.manufacturer = Some("Embassy");
39 config.product = Some("USB-serial example");
40 config.serial_number = Some("12345678");
41 config.max_power = 100;
42 config.max_packet_size_0 = 64;
43
44 // Required for windows compatiblity.
45 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
46 config.device_class = 0xEF;
47 config.device_sub_class = 0x02;
48 config.device_protocol = 0x01;
49 config.composite_with_iads = true;
50
51 // Create embassy-usb DeviceBuilder using the driver and config.
52 // It needs some buffers for building the descriptors.
53 let mut device_descriptor = [0; 256];
54 let mut config_descriptor = [0; 256];
55 let mut bos_descriptor = [0; 256];
56 let mut msos_descriptor = [0; 256];
57 let mut control_buf = [0; 64];
58
59 let mut state = State::new();
60
61 let mut builder = Builder::new(
62 driver,
63 config,
64 &mut device_descriptor,
65 &mut config_descriptor,
66 &mut bos_descriptor,
67 &mut msos_descriptor,
68 &mut control_buf,
69 );
70
71 builder.msos_descriptor(windows_version::WIN8_1, 2);
72
73 // Create classes on the builder.
74 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
75
76 // Since we want to create MS OS feature descriptors that apply to a function that has already been added to the
77 // builder, need to get the MsOsDescriptorWriter from the builder and manually add those descriptors.
78 // Inside a class constructor, you would just need to call `FunctionBuilder::msos_feature` instead.
79 let msos_writer = builder.msos_writer();
80 msos_writer.configuration(0);
81 msos_writer.function(InterfaceNumber(0));
82 msos_writer.function_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
83 msos_writer.function_feature(msos::RegistryPropertyFeatureDescriptor::new(
84 "DeviceInterfaceGUIDs",
85 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
86 ));
87
88 // Build the builder.
89 let mut usb = builder.build();
90
91 // Run the USB device.
92 let usb_fut = usb.run();
93
94 // Do stuff with the class!
95 let echo_fut = async {
96 loop {
97 class.wait_connection().await;
98 info!("Connected");
99 let _ = echo(&mut class).await;
100 info!("Disconnected");
101 }
102 };
103
104 // Run everything concurrently.
105 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
106 join(usb_fut, echo_fut).await;
107}
108
109struct Disconnected {}
110
111impl From<EndpointError> for Disconnected {
112 fn from(val: EndpointError) -> Self {
113 match val {
114 EndpointError::BufferOverflow => panic!("Buffer overflow"),
115 EndpointError::Disabled => Disconnected {},
116 }
117 }
118}
119
120async fn echo<'d, T: Instance + 'd, P: VbusDetect + 'd>(
121 class: &mut CdcAcmClass<'d, Driver<'d, T, P>>,
122) -> Result<(), Disconnected> {
123 let mut buf = [0; 64];
124 loop {
125 let n = class.read_packet(&mut buf).await?;
126 let data = &buf[..n];
127 info!("data: {:x}", data);
128 class.write_packet(data).await?;
129 }
130}
diff --git a/examples/nrf/src/bin/wdt.rs b/examples/nrf52840/src/bin/wdt.rs
index b0b9c3b81..b0b9c3b81 100644
--- a/examples/nrf/src/bin/wdt.rs
+++ b/examples/nrf52840/src/bin/wdt.rs
diff --git a/examples/nrf5340/.cargo/config.toml b/examples/nrf5340/.cargo/config.toml
new file mode 100644
index 000000000..ff0879c8c
--- /dev/null
+++ b/examples/nrf5340/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF5340_xxAA with your chip as listed in `probe-run --list-chips`
3runner = "probe-run --chip nRF5340_xxAA"
4
5[build]
6target = "thumbv8m.main-none-eabihf"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml
new file mode 100644
index 000000000..eed493012
--- /dev/null
+++ b/examples/nrf5340/Cargo.toml
@@ -0,0 +1,64 @@
1[package]
2edition = "2021"
3name = "embassy-nrf5340-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[features]
8default = ["nightly"]
9nightly = [
10 "embassy-executor/nightly",
11 "embassy-nrf/nightly",
12 "embassy-net/nightly",
13 "embassy-nrf/unstable-traits",
14 "embassy-usb",
15 "embedded-io/async",
16 "embassy-net",
17]
18
19[dependencies]
20embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
21embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = [
22 "defmt",
23] }
24embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = [
25 "defmt",
26 "integrated-timers",
27] }
28embassy-time = { version = "0.1.0", path = "../../embassy-time", features = [
29 "defmt",
30 "defmt-timestamp-uptime",
31] }
32embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [
33 "defmt",
34 "nrf5340-app-s",
35 "time-driver-rtc1",
36 "gpiote",
37 "unstable-pac",
38] }
39embassy-net = { version = "0.1.0", path = "../../embassy-net", features = [
40 "defmt",
41 "tcp",
42 "dhcpv4",
43 "medium-ethernet",
44], optional = true }
45embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = [
46 "defmt",
47], optional = true }
48embedded-io = "0.4.0"
49
50
51defmt = "0.3"
52defmt-rtt = "0.4"
53
54static_cell = "1.0"
55cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
56cortex-m-rt = "0.7.0"
57panic-probe = { version = "0.3", features = ["print-defmt"] }
58futures = { version = "0.3.17", default-features = false, features = [
59 "async-await",
60] }
61rand = { version = "0.8.4", default-features = false }
62embedded-storage = "0.3.0"
63usbd-hid = "0.6.0"
64serde = { version = "1.0.136", default-features = false }
diff --git a/examples/nrf5340/build.rs b/examples/nrf5340/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/nrf5340/build.rs
@@ -0,0 +1,35 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
35}
diff --git a/examples/nrf5340/memory.x b/examples/nrf5340/memory.x
new file mode 100644
index 000000000..a122dc24a
--- /dev/null
+++ b/examples/nrf5340/memory.x
@@ -0,0 +1,7 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 /* These values correspond to the NRF5340 */
5 FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
6 RAM : ORIGIN = 0x20000000, LENGTH = 256K
7}
diff --git a/examples/nrf5340/src/bin/blinky.rs b/examples/nrf5340/src/bin/blinky.rs
new file mode 100644
index 000000000..3422cedf0
--- /dev/null
+++ b/examples/nrf5340/src/bin/blinky.rs
@@ -0,0 +1,21 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use embassy_executor::Spawner;
6use embassy_nrf::gpio::{Level, Output, OutputDrive};
7use embassy_time::{Duration, Timer};
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_nrf::init(Default::default());
13 let mut led = Output::new(p.P0_28, Level::Low, OutputDrive::Standard);
14
15 loop {
16 led.set_high();
17 Timer::after(Duration::from_millis(300)).await;
18 led.set_low();
19 Timer::after(Duration::from_millis(300)).await;
20 }
21}
diff --git a/examples/nrf5340/src/bin/gpiote_channel.rs b/examples/nrf5340/src/bin/gpiote_channel.rs
new file mode 100644
index 000000000..ceab1194a
--- /dev/null
+++ b/examples/nrf5340/src/bin/gpiote_channel.rs
@@ -0,0 +1,66 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_nrf::gpio::{Input, Pull};
8use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default());
14 info!("Starting!");
15
16 let ch1 = InputChannel::new(
17 p.GPIOTE_CH0,
18 Input::new(p.P0_23, Pull::Up),
19 InputChannelPolarity::HiToLo,
20 );
21 let ch2 = InputChannel::new(
22 p.GPIOTE_CH1,
23 Input::new(p.P0_24, Pull::Up),
24 InputChannelPolarity::LoToHi,
25 );
26 let ch3 = InputChannel::new(
27 p.GPIOTE_CH2,
28 Input::new(p.P0_08, Pull::Up),
29 InputChannelPolarity::Toggle,
30 );
31 let ch4 = InputChannel::new(
32 p.GPIOTE_CH3,
33 Input::new(p.P0_09, Pull::Up),
34 InputChannelPolarity::Toggle,
35 );
36
37 let button1 = async {
38 loop {
39 ch1.wait().await;
40 info!("Button 1 pressed")
41 }
42 };
43
44 let button2 = async {
45 loop {
46 ch2.wait().await;
47 info!("Button 2 released")
48 }
49 };
50
51 let button3 = async {
52 loop {
53 ch3.wait().await;
54 info!("Button 3 toggled")
55 }
56 };
57
58 let button4 = async {
59 loop {
60 ch4.wait().await;
61 info!("Button 4 toggled")
62 }
63 };
64
65 futures::join!(button1, button2, button3, button4);
66}
diff --git a/examples/nrf5340/src/bin/uart.rs b/examples/nrf5340/src/bin/uart.rs
new file mode 100644
index 000000000..0f2b7b1e3
--- /dev/null
+++ b/examples/nrf5340/src/bin/uart.rs
@@ -0,0 +1,35 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_nrf::{interrupt, uarte};
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_nrf::init(Default::default());
13 let mut config = uarte::Config::default();
14 config.parity = uarte::Parity::EXCLUDED;
15 config.baudrate = uarte::Baudrate::BAUD115200;
16
17 let irq = interrupt::take!(SERIAL0);
18 let mut uart = uarte::Uarte::new(p.UARTETWISPI0, irq, p.P1_00, p.P1_01, config);
19
20 info!("uarte initialized!");
21
22 // Message must be in SRAM
23 let mut buf = [0; 8];
24 buf.copy_from_slice(b"Hello!\r\n");
25
26 unwrap!(uart.write(&buf).await);
27 info!("wrote hello in uart!");
28
29 loop {
30 info!("reading...");
31 unwrap!(uart.read(&mut buf).await);
32 info!("writing...");
33 unwrap!(uart.write(&buf).await);
34 }
35}
diff --git a/examples/rp/.cargo/config.toml b/examples/rp/.cargo/config.toml
index 3d6051389..d1c8c1c5a 100644
--- a/examples/rp/.cargo/config.toml
+++ b/examples/rp/.cargo/config.toml
@@ -5,4 +5,4 @@ runner = "probe-run --chip RP2040"
5target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ 5target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
6 6
7[env] 7[env]
8DEFMT_LOG = "trace" 8DEFMT_LOG = "debug"
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index a5af8b2f0..f07684f29 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -9,15 +9,17 @@ license = "MIT OR Apache-2.0"
9embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 10embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
11embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver"] } 12embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "pio", "critical-section-impl"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } 14embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
16embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" }
16 17
17defmt = "0.3" 18defmt = "0.3"
18defmt-rtt = "0.3" 19defmt-rtt = "0.4"
19 20
20cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 21#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
22cortex-m = { version = "0.7.6" }
21cortex-m-rt = "0.7.0" 23cortex-m-rt = "0.7.0"
22panic-probe = { version = "0.3", features = ["print-defmt"] } 24panic-probe = { version = "0.3", features = ["print-defmt"] }
23futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } 25futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] }
@@ -28,6 +30,13 @@ display-interface = "0.4.1"
28byte-slice-cast = { version = "1.2.0", default-features = false } 30byte-slice-cast = { version = "1.2.0", default-features = false }
29 31
30embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } 32embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
31embedded-hal-async = { version = "0.1.0-alpha.1" } 33embedded-hal-async = "0.2.0-alpha.0"
32embedded-io = { version = "0.3.0", features = ["async", "defmt"] } 34embedded-io = { version = "0.4.0", features = ["async", "defmt"] }
35embedded-storage = { version = "0.3" }
33static_cell = "1.0.0" 36static_cell = "1.0.0"
37log = "0.4"
38pio-proc = "0.2"
39pio = "0.2.1"
40
41[profile.release]
42debug = true
diff --git a/examples/rp/src/bin/adc.rs b/examples/rp/src/bin/adc.rs
new file mode 100644
index 000000000..4202fd394
--- /dev/null
+++ b/examples/rp/src/bin/adc.rs
@@ -0,0 +1,38 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_rp::adc::{Adc, Config};
8use embassy_rp::interrupt;
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let p = embassy_rp::init(Default::default());
15 let irq = interrupt::take!(ADC_IRQ_FIFO);
16 let mut adc = Adc::new(p.ADC, irq, Config::default());
17
18 let mut p26 = p.PIN_26;
19 let mut p27 = p.PIN_27;
20 let mut p28 = p.PIN_28;
21
22 loop {
23 let level = adc.read(&mut p26).await;
24 info!("Pin 26 ADC: {}", level);
25 let level = adc.read(&mut p27).await;
26 info!("Pin 27 ADC: {}", level);
27 let level = adc.read(&mut p28).await;
28 info!("Pin 28 ADC: {}", level);
29 let temp = adc.read_temperature().await;
30 info!("Temp: {} degrees", convert_to_celsius(temp));
31 Timer::after(Duration::from_secs(1)).await;
32 }
33}
34
35fn convert_to_celsius(raw_temp: u16) -> f32 {
36 // According to chapter 4.9.5. Temperature Sensor in RP2040 datasheet
37 27.0 - (raw_temp as f32 * 3.3 / 4096.0 - 0.706) / 0.001721 as f32
38}
diff --git a/examples/rp/src/bin/flash.rs b/examples/rp/src/bin/flash.rs
new file mode 100644
index 000000000..8d6b379f4
--- /dev/null
+++ b/examples/rp/src/bin/flash.rs
@@ -0,0 +1,89 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_rp::flash::{ERASE_SIZE, FLASH_BASE};
8use embassy_rp::peripherals::FLASH;
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12const ADDR_OFFSET: u32 = 0x100000;
13const FLASH_SIZE: usize = 2 * 1024 * 1024;
14
15#[embassy_executor::main]
16async fn main(_spawner: Spawner) {
17 let p = embassy_rp::init(Default::default());
18 info!("Hello World!");
19
20 // add some delay to give an attached debug probe time to parse the
21 // defmt RTT header. Reading that header might touch flash memory, which
22 // interferes with flash write operations.
23 // https://github.com/knurling-rs/defmt/pull/683
24 Timer::after(Duration::from_millis(10)).await;
25
26 let mut flash = embassy_rp::flash::Flash::<_, FLASH_SIZE>::new(p.FLASH);
27 erase_write_sector(&mut flash, 0x00);
28
29 multiwrite_bytes(&mut flash, ERASE_SIZE as u32);
30
31 loop {}
32}
33
34fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, FLASH_SIZE>, offset: u32) {
35 info!(">>>> [multiwrite_bytes]");
36 let mut read_buf = [0u8; ERASE_SIZE];
37 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf));
38
39 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
40 info!("Contents start with {=[u8]}", read_buf[0..4]);
41
42 defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
43
44 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf));
45 info!("Contents after erase starts with {=[u8]}", read_buf[0..4]);
46 if read_buf.iter().any(|x| *x != 0xFF) {
47 defmt::panic!("unexpected");
48 }
49
50 defmt::unwrap!(flash.write(ADDR_OFFSET + offset, &[0x01]));
51 defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 1, &[0x02]));
52 defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 2, &[0x03]));
53 defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 3, &[0x04]));
54
55 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf));
56 info!("Contents after write starts with {=[u8]}", read_buf[0..4]);
57 if &read_buf[0..4] != &[0x01, 0x02, 0x03, 0x04] {
58 defmt::panic!("unexpected");
59 }
60}
61
62fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, FLASH_SIZE>, offset: u32) {
63 info!(">>>> [erase_write_sector]");
64 let mut buf = [0u8; ERASE_SIZE];
65 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf));
66
67 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
68 info!("Contents start with {=[u8]}", buf[0..4]);
69
70 defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
71
72 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf));
73 info!("Contents after erase starts with {=[u8]}", buf[0..4]);
74 if buf.iter().any(|x| *x != 0xFF) {
75 defmt::panic!("unexpected");
76 }
77
78 for b in buf.iter_mut() {
79 *b = 0xDA;
80 }
81
82 defmt::unwrap!(flash.write(ADDR_OFFSET + offset, &buf));
83
84 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf));
85 info!("Contents after write starts with {=[u8]}", buf[0..4]);
86 if buf.iter().any(|x| *x != 0xDA) {
87 defmt::panic!("unexpected");
88 }
89}
diff --git a/examples/rp/src/bin/i2c_async.rs b/examples/rp/src/bin/i2c_async.rs
new file mode 100644
index 000000000..d1a2e3cd7
--- /dev/null
+++ b/examples/rp/src/bin/i2c_async.rs
@@ -0,0 +1,102 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_rp::i2c::{self, Config};
8use embassy_rp::interrupt;
9use embassy_time::{Duration, Timer};
10use embedded_hal_async::i2c::I2c;
11use {defmt_rtt as _, panic_probe as _};
12
13#[allow(dead_code)]
14mod mcp23017 {
15 pub const ADDR: u8 = 0x20; // default addr
16
17 macro_rules! mcpregs {
18 ($($name:ident : $val:expr),* $(,)?) => {
19 $(
20 pub const $name: u8 = $val;
21 )*
22
23 pub fn regname(reg: u8) -> &'static str {
24 match reg {
25 $(
26 $val => stringify!($name),
27 )*
28 _ => panic!("bad reg"),
29 }
30 }
31 }
32 }
33
34 // These are correct for IOCON.BANK=0
35 mcpregs! {
36 IODIRA: 0x00,
37 IPOLA: 0x02,
38 GPINTENA: 0x04,
39 DEFVALA: 0x06,
40 INTCONA: 0x08,
41 IOCONA: 0x0A,
42 GPPUA: 0x0C,
43 INTFA: 0x0E,
44 INTCAPA: 0x10,
45 GPIOA: 0x12,
46 OLATA: 0x14,
47 IODIRB: 0x01,
48 IPOLB: 0x03,
49 GPINTENB: 0x05,
50 DEFVALB: 0x07,
51 INTCONB: 0x09,
52 IOCONB: 0x0B,
53 GPPUB: 0x0D,
54 INTFB: 0x0F,
55 INTCAPB: 0x11,
56 GPIOB: 0x13,
57 OLATB: 0x15,
58 }
59}
60
61#[embassy_executor::main]
62async fn main(_spawner: Spawner) {
63 let p = embassy_rp::init(Default::default());
64
65 let sda = p.PIN_14;
66 let scl = p.PIN_15;
67 let irq = interrupt::take!(I2C1_IRQ);
68
69 info!("set up i2c ");
70 let mut i2c = i2c::I2c::new_async(p.I2C1, scl, sda, irq, Config::default());
71
72 use mcp23017::*;
73
74 info!("init mcp23017 config for IxpandO");
75 // init - a outputs, b inputs
76 i2c.write(ADDR, &[IODIRA, 0x00]).await.unwrap();
77 i2c.write(ADDR, &[IODIRB, 0xff]).await.unwrap();
78 i2c.write(ADDR, &[GPPUB, 0xff]).await.unwrap(); // pullups
79
80 let mut val = 1;
81 loop {
82 let mut portb = [0];
83
84 i2c.write_read(mcp23017::ADDR, &[GPIOB], &mut portb).await.unwrap();
85 info!("portb = {:02x}", portb[0]);
86 i2c.write(mcp23017::ADDR, &[GPIOA, val | portb[0]]).await.unwrap();
87 val = val.rotate_left(1);
88
89 // get a register dump
90 info!("getting register dump");
91 let mut regs = [0; 22];
92 i2c.write_read(ADDR, &[0], &mut regs).await.unwrap();
93 // always get the regdump but only display it if portb'0 is set
94 if portb[0] & 1 != 0 {
95 for (idx, reg) in regs.into_iter().enumerate() {
96 info!("{} => {:02x}", regname(idx as u8), reg);
97 }
98 }
99
100 Timer::after(Duration::from_millis(100)).await;
101 }
102}
diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs
new file mode 100644
index 000000000..376b2b61e
--- /dev/null
+++ b/examples/rp/src/bin/multicore.rs
@@ -0,0 +1,60 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Executor;
7use embassy_executor::_export::StaticCell;
8use embassy_rp::gpio::{Level, Output};
9use embassy_rp::multicore::{spawn_core1, Stack};
10use embassy_rp::peripherals::PIN_25;
11use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
12use embassy_sync::channel::Channel;
13use embassy_time::{Duration, Timer};
14use {defmt_rtt as _, panic_probe as _};
15
16static mut CORE1_STACK: Stack<4096> = Stack::new();
17static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
18static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
19static CHANNEL: Channel<CriticalSectionRawMutex, LedState, 1> = Channel::new();
20
21enum LedState {
22 On,
23 Off,
24}
25
26#[cortex_m_rt::entry]
27fn main() -> ! {
28 let p = embassy_rp::init(Default::default());
29 let led = Output::new(p.PIN_25, Level::Low);
30
31 spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || {
32 let executor1 = EXECUTOR1.init(Executor::new());
33 executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(led))));
34 });
35
36 let executor0 = EXECUTOR0.init(Executor::new());
37 executor0.run(|spawner| unwrap!(spawner.spawn(core0_task())));
38}
39
40#[embassy_executor::task]
41async fn core0_task() {
42 info!("Hello from core 0");
43 loop {
44 CHANNEL.send(LedState::On).await;
45 Timer::after(Duration::from_millis(100)).await;
46 CHANNEL.send(LedState::Off).await;
47 Timer::after(Duration::from_millis(400)).await;
48 }
49}
50
51#[embassy_executor::task]
52async fn core1_task(mut led: Output<'static, PIN_25>) {
53 info!("Hello from core 1");
54 loop {
55 match CHANNEL.recv().await {
56 LedState::On => led.set_high(),
57 LedState::Off => led.set_low(),
58 }
59 }
60}
diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs
new file mode 100644
index 000000000..45a8c73f7
--- /dev/null
+++ b/examples/rp/src/bin/pio_async.rs
@@ -0,0 +1,112 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4use defmt::info;
5use embassy_executor::Spawner;
6use embassy_rp::gpio::{AnyPin, Pin};
7use embassy_rp::pio::{Pio0, PioPeripherial, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, Sm1, Sm2};
8use embassy_rp::pio_instr_util;
9use embassy_rp::relocate::RelocatedProgram;
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::task]
13async fn pio_task_sm0(mut sm: PioStateMachineInstance<Pio0, Sm0>, pin: AnyPin) {
14 // Setup sm0
15
16 // Send data serially to pin
17 let prg = pio_proc::pio_asm!(
18 ".origin 16",
19 "set pindirs, 1",
20 ".wrap_target",
21 "out pins,1 [19]",
22 ".wrap",
23 );
24
25 let relocated = RelocatedProgram::new(&prg.program);
26 let out_pin = sm.make_pio_pin(pin);
27 let pio_pins = [&out_pin];
28 sm.set_out_pins(&pio_pins);
29 sm.write_instr(relocated.origin() as usize, relocated.code());
30 pio_instr_util::exec_jmp(&mut sm, relocated.origin());
31 sm.set_clkdiv((125e6 / 20.0 / 2e2 * 256.0) as u32);
32 sm.set_set_range(0, 1);
33 let pio::Wrap { source, target } = relocated.wrap();
34 sm.set_wrap(source, target);
35
36 sm.set_autopull(true);
37 sm.set_out_shift_dir(ShiftDirection::Left);
38
39 sm.set_enable(true);
40
41 let mut v = 0x0f0caffa;
42 loop {
43 sm.wait_push(v).await;
44 v ^= 0xffff;
45 info!("Pushed {:032b} to FIFO", v);
46 }
47}
48
49#[embassy_executor::task]
50async fn pio_task_sm1(mut sm: PioStateMachineInstance<Pio0, Sm1>) {
51 // Setupm sm1
52
53 // Read 0b10101 repeatedly until ISR is full
54 let prg = pio_proc::pio_asm!(".origin 8", "set x, 0x15", ".wrap_target", "in x, 5 [31]", ".wrap",);
55
56 let relocated = RelocatedProgram::new(&prg.program);
57 sm.write_instr(relocated.origin() as usize, relocated.code());
58 pio_instr_util::exec_jmp(&mut sm, relocated.origin());
59 sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32);
60 sm.set_set_range(0, 0);
61 let pio::Wrap { source, target } = relocated.wrap();
62 sm.set_wrap(source, target);
63
64 sm.set_autopush(true);
65 sm.set_in_shift_dir(ShiftDirection::Right);
66 sm.set_enable(true);
67 loop {
68 let rx = sm.wait_pull().await;
69 info!("Pulled {:032b} from FIFO", rx);
70 }
71}
72
73#[embassy_executor::task]
74async fn pio_task_sm2(mut sm: PioStateMachineInstance<Pio0, Sm2>) {
75 // Setup sm2
76
77 // Repeatedly trigger IRQ 3
78 let prg = pio_proc::pio_asm!(
79 ".origin 0",
80 ".wrap_target",
81 "set x,10",
82 "delay:",
83 "jmp x-- delay [15]",
84 "irq 3 [15]",
85 ".wrap",
86 );
87 let relocated = RelocatedProgram::new(&prg.program);
88 sm.write_instr(relocated.origin() as usize, relocated.code());
89
90 let pio::Wrap { source, target } = relocated.wrap();
91 sm.set_wrap(source, target);
92
93 pio_instr_util::exec_jmp(&mut sm, relocated.origin());
94 sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32);
95 sm.set_enable(true);
96 loop {
97 sm.wait_irq(3).await;
98 info!("IRQ trigged");
99 }
100}
101
102#[embassy_executor::main]
103async fn main(spawner: Spawner) {
104 let p = embassy_rp::init(Default::default());
105 let pio = p.PIO0;
106
107 let (_, sm0, sm1, sm2, ..) = pio.split();
108
109 spawner.spawn(pio_task_sm0(sm0, p.PIN_0.degrade())).unwrap();
110 spawner.spawn(pio_task_sm1(sm1)).unwrap();
111 spawner.spawn(pio_task_sm2(sm2)).unwrap();
112}
diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs
new file mode 100644
index 000000000..b19ef4083
--- /dev/null
+++ b/examples/rp/src/bin/pio_dma.rs
@@ -0,0 +1,69 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4use defmt::info;
5use embassy_executor::Spawner;
6use embassy_futures::join::join;
7use embassy_rp::pio::{PioPeripherial, PioStateMachine, ShiftDirection};
8use embassy_rp::relocate::RelocatedProgram;
9use embassy_rp::{pio_instr_util, Peripheral};
10use {defmt_rtt as _, panic_probe as _};
11
12fn swap_nibbles(v: u32) -> u32 {
13 let v = (v & 0x0f0f_0f0f) << 4 | (v & 0xf0f0_f0f0) >> 4;
14 let v = (v & 0x00ff_00ff) << 8 | (v & 0xff00_ff00) >> 8;
15 (v & 0x0000_ffff) << 16 | (v & 0xffff_0000) >> 16
16}
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) {
20 let p = embassy_rp::init(Default::default());
21 let pio = p.PIO0;
22 let (_, mut sm, ..) = pio.split();
23
24 let prg = pio_proc::pio_asm!(
25 ".origin 0",
26 "set pindirs,1",
27 ".wrap_target",
28 "set y,7",
29 "loop:",
30 "out x,4",
31 "in x,4",
32 "jmp y--, loop",
33 ".wrap",
34 );
35
36 let relocated = RelocatedProgram::new(&prg.program);
37 sm.write_instr(relocated.origin() as usize, relocated.code());
38 pio_instr_util::exec_jmp(&mut sm, relocated.origin());
39 sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32);
40 let pio::Wrap { source, target } = relocated.wrap();
41 sm.set_wrap(source, target);
42 sm.set_autopull(true);
43 sm.set_autopush(true);
44 sm.set_pull_threshold(32);
45 sm.set_push_threshold(32);
46 sm.set_out_shift_dir(ShiftDirection::Right);
47 sm.set_in_shift_dir(ShiftDirection::Left);
48
49 sm.set_enable(true);
50
51 let mut dma_out_ref = p.DMA_CH0.into_ref();
52 let mut dma_in_ref = p.DMA_CH1.into_ref();
53 let mut dout = [0x12345678u32; 29];
54 for i in 1..dout.len() {
55 dout[i] = (dout[i - 1] & 0x0fff_ffff) * 13 + 7;
56 }
57 let mut din = [0u32; 29];
58 loop {
59 join(
60 sm.dma_push(dma_out_ref.reborrow(), &dout),
61 sm.dma_pull(dma_in_ref.reborrow(), &mut din),
62 )
63 .await;
64 for i in 0..din.len() {
65 assert_eq!(din[i], swap_nibbles(dout[i]));
66 }
67 info!("Swapped {} words", dout.len());
68 }
69}
diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs
new file mode 100644
index 000000000..a8a682274
--- /dev/null
+++ b/examples/rp/src/bin/uart_buffered_split.rs
@@ -0,0 +1,57 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_executor::_export::StaticCell;
8use embassy_rp::interrupt;
9use embassy_rp::peripherals::UART0;
10use embassy_rp::uart::{BufferedUart, BufferedUartRx, Config};
11use embassy_time::{Duration, Timer};
12use embedded_io::asynch::{Read, Write};
13use {defmt_rtt as _, panic_probe as _};
14
15macro_rules! singleton {
16 ($val:expr) => {{
17 type T = impl Sized;
18 static STATIC_CELL: StaticCell<T> = StaticCell::new();
19 let (x,) = STATIC_CELL.init(($val,));
20 x
21 }};
22}
23
24#[embassy_executor::main]
25async fn main(spawner: Spawner) {
26 let p = embassy_rp::init(Default::default());
27 let (tx_pin, rx_pin, uart) = (p.PIN_0, p.PIN_1, p.UART0);
28
29 let irq = interrupt::take!(UART0_IRQ);
30 let tx_buf = &mut singleton!([0u8; 16])[..];
31 let rx_buf = &mut singleton!([0u8; 16])[..];
32 let uart = BufferedUart::new(uart, irq, tx_pin, rx_pin, tx_buf, rx_buf, Config::default());
33 let (rx, mut tx) = uart.split();
34
35 unwrap!(spawner.spawn(reader(rx)));
36
37 info!("Writing...");
38 loop {
39 let data = [
40 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
41 29, 30, 31,
42 ];
43 info!("TX {:?}", data);
44 tx.write_all(&data).await.unwrap();
45 Timer::after(Duration::from_secs(1)).await;
46 }
47}
48
49#[embassy_executor::task]
50async fn reader(mut rx: BufferedUartRx<'static, UART0>) {
51 info!("Reading...");
52 loop {
53 let mut buf = [0; 31];
54 rx.read_exact(&mut buf).await.unwrap();
55 info!("RX {:?}", buf);
56 }
57}
diff --git a/examples/rp/src/bin/uart_unidir.rs b/examples/rp/src/bin/uart_unidir.rs
new file mode 100644
index 000000000..f56e7009f
--- /dev/null
+++ b/examples/rp/src/bin/uart_unidir.rs
@@ -0,0 +1,42 @@
1//! test TX-only and RX-only UARTs. You need to connect GPIO0 to GPIO5 for
2//! this to work
3
4#![no_std]
5#![no_main]
6#![feature(type_alias_impl_trait)]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::peripherals::UART1;
11use embassy_rp::uart::{Async, Config, UartRx, UartTx};
12use embassy_time::{Duration, Timer};
13use {defmt_rtt as _, panic_probe as _};
14
15#[embassy_executor::main]
16async fn main(spawner: Spawner) {
17 let p = embassy_rp::init(Default::default());
18
19 let mut uart_tx = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, Config::default());
20 let uart_rx = UartRx::new(p.UART1, p.PIN_5, p.DMA_CH1, Config::default());
21
22 unwrap!(spawner.spawn(reader(uart_rx)));
23
24 info!("Writing...");
25 loop {
26 let data = [1u8, 2, 3, 4, 5, 6, 7, 8];
27 info!("TX {:?}", data);
28 uart_tx.write(&data).await.unwrap();
29 Timer::after(Duration::from_secs(1)).await;
30 }
31}
32
33#[embassy_executor::task]
34async fn reader(mut rx: UartRx<'static, UART1, Async>) {
35 info!("Reading...");
36 loop {
37 // read a total of 4 transmissions (32 / 8) and then print the result
38 let mut buf = [0; 32];
39 rx.read(&mut buf).await.unwrap();
40 info!("RX {:?}", buf);
41 }
42}
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
index 1057fe7fd..66a6ed4d0 100644
--- a/examples/rp/src/bin/usb_ethernet.rs
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -2,18 +2,14 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use core::sync::atomic::{AtomicBool, Ordering};
6use core::task::Waker;
7
8use defmt::*; 5use defmt::*;
9use embassy_executor::Spawner; 6use embassy_executor::Spawner;
10use embassy_net::tcp::TcpSocket; 7use embassy_net::tcp::TcpSocket;
11use embassy_net::{PacketBox, PacketBoxExt, PacketBuf, Stack, StackResources}; 8use embassy_net::{Stack, StackResources};
12use embassy_rp::usb::Driver; 9use embassy_rp::usb::Driver;
13use embassy_rp::{interrupt, peripherals}; 10use embassy_rp::{interrupt, peripherals};
14use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 11use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
15use embassy_sync::channel::Channel; 12use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
16use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State};
17use embassy_usb::{Builder, Config, UsbDevice}; 13use embassy_usb::{Builder, Config, UsbDevice};
18use embedded_io::asynch::Write; 14use embedded_io::asynch::Write;
19use static_cell::StaticCell; 15use static_cell::StaticCell;
@@ -25,56 +21,25 @@ macro_rules! singleton {
25 ($val:expr) => {{ 21 ($val:expr) => {{
26 type T = impl Sized; 22 type T = impl Sized;
27 static STATIC_CELL: StaticCell<T> = StaticCell::new(); 23 static STATIC_CELL: StaticCell<T> = StaticCell::new();
28 STATIC_CELL.init_with(move || $val) 24 let (x,) = STATIC_CELL.init(($val,));
25 x
29 }}; 26 }};
30} 27}
31 28
29const MTU: usize = 1514;
30
32#[embassy_executor::task] 31#[embassy_executor::task]
33async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! { 32async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! {
34 device.run().await 33 device.run().await
35} 34}
36 35
37#[embassy_executor::task] 36#[embassy_executor::task]
38async fn usb_ncm_rx_task(mut class: Receiver<'static, MyDriver>) { 37async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
39 loop { 38 class.run().await
40 warn!("WAITING for connection");
41 LINK_UP.store(false, Ordering::Relaxed);
42
43 class.wait_connection().await.unwrap();
44
45 warn!("Connected");
46 LINK_UP.store(true, Ordering::Relaxed);
47
48 loop {
49 let mut p = unwrap!(PacketBox::new(embassy_net::Packet::new()));
50 let n = match class.read_packet(&mut p[..]).await {
51 Ok(n) => n,
52 Err(e) => {
53 warn!("error reading packet: {:?}", e);
54 break;
55 }
56 };
57
58 let buf = p.slice(0..n);
59 if RX_CHANNEL.try_send(buf).is_err() {
60 warn!("Failed pushing rx'd packet to channel.");
61 }
62 }
63 }
64} 39}
65 40
66#[embassy_executor::task] 41#[embassy_executor::task]
67async fn usb_ncm_tx_task(mut class: Sender<'static, MyDriver>) { 42async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
68 loop {
69 let pkt = TX_CHANNEL.recv().await;
70 if let Err(e) = class.write_packet(&pkt[..]).await {
71 warn!("Failed to TX packet: {:?}", e);
72 }
73 }
74}
75
76#[embassy_executor::task]
77async fn net_task(stack: &'static Stack<Device>) -> ! {
78 stack.run().await 43 stack.run().await
79} 44}
80 45
@@ -100,58 +65,34 @@ async fn main(spawner: Spawner) {
100 config.device_sub_class = 0x02; 65 config.device_sub_class = 0x02;
101 config.device_protocol = 0x01; 66 config.device_protocol = 0x01;
102 67
103 struct Resources {
104 device_descriptor: [u8; 256],
105 config_descriptor: [u8; 256],
106 bos_descriptor: [u8; 256],
107 control_buf: [u8; 128],
108 serial_state: State<'static>,
109 }
110 let res: &mut Resources = singleton!(Resources {
111 device_descriptor: [0; 256],
112 config_descriptor: [0; 256],
113 bos_descriptor: [0; 256],
114 control_buf: [0; 128],
115 serial_state: State::new(),
116 });
117
118 // Create embassy-usb DeviceBuilder using the driver and config. 68 // Create embassy-usb DeviceBuilder using the driver and config.
119 let mut builder = Builder::new( 69 let mut builder = Builder::new(
120 driver, 70 driver,
121 config, 71 config,
122 &mut res.device_descriptor, 72 &mut singleton!([0; 256])[..],
123 &mut res.config_descriptor, 73 &mut singleton!([0; 256])[..],
124 &mut res.bos_descriptor, 74 &mut singleton!([0; 256])[..],
125 &mut res.control_buf, 75 &mut singleton!([0; 128])[..],
126 None,
127 ); 76 );
128 77
129 // WARNINGS for Android ethernet tethering:
130 // - On Pixel 4a, it refused to work on Android 11, worked on Android 12.
131 // - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte),
132 // it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled.
133 // 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
134 // and this nonsense in the linux kernel: https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757
135
136 // Our MAC addr. 78 // Our MAC addr.
137 let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC]; 79 let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC];
138 // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has. 80 // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has.
139 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; 81 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
140 82
141 // Create classes on the builder. 83 // Create classes on the builder.
142 let class = CdcNcmClass::new(&mut builder, &mut res.serial_state, host_mac_addr, 64); 84 let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64);
143 85
144 // Build the builder. 86 // Build the builder.
145 let usb = builder.build(); 87 let usb = builder.build();
146 88
147 unwrap!(spawner.spawn(usb_task(usb))); 89 unwrap!(spawner.spawn(usb_task(usb)));
148 90
149 let (tx, rx) = class.split(); 91 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr);
150 unwrap!(spawner.spawn(usb_ncm_rx_task(rx))); 92 unwrap!(spawner.spawn(usb_ncm_task(runner)));
151 unwrap!(spawner.spawn(usb_ncm_tx_task(tx)));
152 93
153 let config = embassy_net::ConfigStrategy::Dhcp; 94 let config = embassy_net::Config::Dhcp(Default::default());
154 //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { 95 //let config = embassy_net::Config::Static(embassy_net::StaticConfig {
155 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 96 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
156 // dns_servers: Vec::new(), 97 // dns_servers: Vec::new(),
157 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 98 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
@@ -161,13 +102,7 @@ async fn main(spawner: Spawner) {
161 let seed = 1234; // guaranteed random, chosen by a fair dice roll 102 let seed = 1234; // guaranteed random, chosen by a fair dice roll
162 103
163 // Init network stack 104 // Init network stack
164 let device = Device { mac_addr: our_mac_addr }; 105 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
165 let stack = &*singleton!(Stack::new(
166 device,
167 config,
168 singleton!(StackResources::<1, 2, 8>::new()),
169 seed
170 ));
171 106
172 unwrap!(spawner.spawn(net_task(stack))); 107 unwrap!(spawner.spawn(net_task(stack)));
173 108
@@ -214,50 +149,3 @@ async fn main(spawner: Spawner) {
214 } 149 }
215 } 150 }
216} 151}
217
218static TX_CHANNEL: Channel<ThreadModeRawMutex, PacketBuf, 8> = Channel::new();
219static RX_CHANNEL: Channel<ThreadModeRawMutex, PacketBuf, 8> = Channel::new();
220static LINK_UP: AtomicBool = AtomicBool::new(false);
221
222struct Device {
223 mac_addr: [u8; 6],
224}
225
226impl embassy_net::Device for Device {
227 fn register_waker(&mut self, waker: &Waker) {
228 // loopy loopy wakey wakey
229 waker.wake_by_ref()
230 }
231
232 fn link_state(&mut self) -> embassy_net::LinkState {
233 match LINK_UP.load(Ordering::Relaxed) {
234 true => embassy_net::LinkState::Up,
235 false => embassy_net::LinkState::Down,
236 }
237 }
238
239 fn capabilities(&self) -> embassy_net::DeviceCapabilities {
240 let mut caps = embassy_net::DeviceCapabilities::default();
241 caps.max_transmission_unit = 1514; // 1500 IP + 14 ethernet header
242 caps.medium = embassy_net::Medium::Ethernet;
243 caps
244 }
245
246 fn is_transmit_ready(&mut self) -> bool {
247 true
248 }
249
250 fn transmit(&mut self, pkt: PacketBuf) {
251 if TX_CHANNEL.try_send(pkt).is_err() {
252 warn!("TX failed")
253 }
254 }
255
256 fn receive<'a>(&mut self) -> Option<PacketBuf> {
257 RX_CHANNEL.try_recv().ok()
258 }
259
260 fn ethernet_address(&self) -> [u8; 6] {
261 self.mac_addr
262 }
263}
diff --git a/examples/rp/src/bin/usb_logger.rs b/examples/rp/src/bin/usb_logger.rs
new file mode 100644
index 000000000..52417a02e
--- /dev/null
+++ b/examples/rp/src/bin/usb_logger.rs
@@ -0,0 +1,30 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use embassy_executor::Spawner;
6use embassy_rp::interrupt;
7use embassy_rp::peripherals::USB;
8use embassy_rp::usb::Driver;
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::task]
13async fn logger_task(driver: Driver<'static, USB>) {
14 embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver);
15}
16
17#[embassy_executor::main]
18async fn main(spawner: Spawner) {
19 let p = embassy_rp::init(Default::default());
20 let irq = interrupt::take!(USBCTRL_IRQ);
21 let driver = Driver::new(p.USB, irq);
22 spawner.spawn(logger_task(driver)).unwrap();
23
24 let mut counter = 0;
25 loop {
26 counter += 1;
27 log::info!("Tick {}", counter);
28 Timer::after(Duration::from_secs(1)).await;
29 }
30}
diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs
index b7d6493b4..a991082ee 100644
--- a/examples/rp/src/bin/usb_serial.rs
+++ b/examples/rp/src/bin/usb_serial.rs
@@ -53,7 +53,6 @@ async fn main(_spawner: Spawner) {
53 &mut config_descriptor, 53 &mut config_descriptor,
54 &mut bos_descriptor, 54 &mut bos_descriptor,
55 &mut control_buf, 55 &mut control_buf,
56 None,
57 ); 56 );
58 57
59 // Create classes on the builder. 58 // Create classes on the builder.
diff --git a/examples/rp/src/bin/watchdog.rs b/examples/rp/src/bin/watchdog.rs
new file mode 100644
index 000000000..ece5cfe38
--- /dev/null
+++ b/examples/rp/src/bin/watchdog.rs
@@ -0,0 +1,48 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_rp::gpio;
8use embassy_rp::watchdog::*;
9use embassy_time::{Duration, Timer};
10use gpio::{Level, Output};
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = embassy_rp::init(Default::default());
16 info!("Hello world!");
17
18 let mut watchdog = Watchdog::new(p.WATCHDOG);
19 let mut led = Output::new(p.PIN_25, Level::Low);
20
21 // Set the LED high for 2 seconds so we know when we're about to start the watchdog
22 led.set_high();
23 Timer::after(Duration::from_secs(2)).await;
24
25 // Set to watchdog to reset if it's not fed within 1.05 seconds, and start it
26 watchdog.start(Duration::from_millis(1_050));
27 info!("Started the watchdog timer");
28
29 // Blink once a second for 5 seconds, feed the watchdog timer once a second to avoid a reset
30 for _ in 1..=5 {
31 led.set_low();
32 Timer::after(Duration::from_millis(500)).await;
33 led.set_high();
34 Timer::after(Duration::from_millis(500)).await;
35 info!("Feeding watchdog");
36 watchdog.feed();
37 }
38
39 info!("Stopped feeding, device will reset in 1.05 seconds");
40 // Blink 10 times per second, not feeding the watchdog.
41 // The processor should reset in 1.05 seconds.
42 loop {
43 led.set_low();
44 Timer::after(Duration::from_millis(100)).await;
45 led.set_high();
46 Timer::after(Duration::from_millis(100)).await;
47 }
48}
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml
index b9bd1e718..8087df09a 100644
--- a/examples/std/Cargo.toml
+++ b/examples/std/Cargo.toml
@@ -8,15 +8,16 @@ license = "MIT OR Apache-2.0"
8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["log"] } 8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["log"] }
9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "std", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "std", "nightly", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "std", "nightly"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "std", "nightly"] }
11embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "tcp", "udp", "dhcpv4", "pool-16"] } 11embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "tcp", "udp", "dns", "dhcpv4", "unstable-traits", "proto-ipv6"] }
12embedded-io = { version = "0.3.0", features = ["async", "std", "futures"] } 12embassy-net-driver = { version = "0.1.0", path = "../../embassy-net-driver" }
13embedded-io = { version = "0.4.0", features = ["async", "std", "futures"] }
13critical-section = { version = "1.1", features = ["std"] } 14critical-section = { version = "1.1", features = ["std"] }
14 15
15async-io = "1.6.0" 16async-io = "1.6.0"
16env_logger = "0.9.0" 17env_logger = "0.9.0"
17futures = { version = "0.3.17" } 18futures = { version = "0.3.17" }
18log = "0.4.14" 19log = "0.4.14"
19nix = "0.22.1" 20nix = "0.26.2"
20libc = "0.2.101" 21libc = "0.2.101"
21clap = { version = "3.0.0-beta.5", features = ["derive"] } 22clap = { version = "3.0.0-beta.5", features = ["derive"] }
22rand_core = { version = "0.6.3", features = ["std"] } 23rand_core = { version = "0.6.3", features = ["std"] }
diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs
index 9b1450b72..451850d99 100644
--- a/examples/std/src/bin/net.rs
+++ b/examples/std/src/bin/net.rs
@@ -1,9 +1,11 @@
1#![feature(type_alias_impl_trait)] 1#![feature(type_alias_impl_trait)]
2 2
3use std::default::Default;
4
3use clap::Parser; 5use clap::Parser;
4use embassy_executor::{Executor, Spawner}; 6use embassy_executor::{Executor, Spawner};
5use embassy_net::tcp::TcpSocket; 7use embassy_net::tcp::TcpSocket;
6use embassy_net::{ConfigStrategy, Ipv4Address, Ipv4Cidr, Stack, StackResources}; 8use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources};
7use embedded_io::asynch::Write; 9use embedded_io::asynch::Write;
8use heapless::Vec; 10use heapless::Vec;
9use log::*; 11use log::*;
@@ -48,13 +50,13 @@ async fn main_task(spawner: Spawner) {
48 50
49 // Choose between dhcp or static ip 51 // Choose between dhcp or static ip
50 let config = if opts.static_ip { 52 let config = if opts.static_ip {
51 ConfigStrategy::Static(embassy_net::Config { 53 Config::Static(embassy_net::StaticConfig {
52 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), 54 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
53 dns_servers: Vec::new(), 55 dns_servers: Vec::new(),
54 gateway: Some(Ipv4Address::new(192, 168, 69, 1)), 56 gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
55 }) 57 })
56 } else { 58 } else {
57 ConfigStrategy::Dhcp 59 Config::Dhcp(Default::default())
58 }; 60 };
59 61
60 // Generate random seed 62 // Generate random seed
@@ -63,12 +65,7 @@ async fn main_task(spawner: Spawner) {
63 let seed = u64::from_le_bytes(seed); 65 let seed = u64::from_le_bytes(seed);
64 66
65 // Init network stack 67 // Init network stack
66 let stack = &*singleton!(Stack::new( 68 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
67 device,
68 config,
69 singleton!(StackResources::<1, 2, 8>::new()),
70 seed
71 ));
72 69
73 // Launch network task 70 // Launch network task
74 spawner.spawn(net_task(stack)).unwrap(); 71 spawner.spawn(net_task(stack)).unwrap();
diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs
new file mode 100644
index 000000000..e1cc45a38
--- /dev/null
+++ b/examples/std/src/bin/net_dns.rs
@@ -0,0 +1,98 @@
1#![feature(type_alias_impl_trait)]
2
3use std::default::Default;
4
5use clap::Parser;
6use embassy_executor::{Executor, Spawner};
7use embassy_net::dns::DnsQueryType;
8use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources};
9use heapless::Vec;
10use log::*;
11use rand_core::{OsRng, RngCore};
12use static_cell::StaticCell;
13
14#[path = "../tuntap.rs"]
15mod tuntap;
16
17use crate::tuntap::TunTapDevice;
18
19macro_rules! singleton {
20 ($val:expr) => {{
21 type T = impl Sized;
22 static STATIC_CELL: StaticCell<T> = StaticCell::new();
23 STATIC_CELL.init_with(move || $val)
24 }};
25}
26
27#[derive(Parser)]
28#[clap(version = "1.0")]
29struct Opts {
30 /// TAP device name
31 #[clap(long, default_value = "tap0")]
32 tap: String,
33 /// use a static IP instead of DHCP
34 #[clap(long)]
35 static_ip: bool,
36}
37
38#[embassy_executor::task]
39async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! {
40 stack.run().await
41}
42
43#[embassy_executor::task]
44async fn main_task(spawner: Spawner) {
45 let opts: Opts = Opts::parse();
46
47 // Init network device
48 let device = TunTapDevice::new(&opts.tap).unwrap();
49
50 // Choose between dhcp or static ip
51 let config = if opts.static_ip {
52 Config::Static(embassy_net::StaticConfig {
53 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 1), 24),
54 dns_servers: Vec::from_slice(&[Ipv4Address::new(8, 8, 4, 4).into(), Ipv4Address::new(8, 8, 8, 8).into()])
55 .unwrap(),
56 gateway: Some(Ipv4Address::new(192, 168, 69, 100)),
57 })
58 } else {
59 Config::Dhcp(Default::default())
60 };
61
62 // Generate random seed
63 let mut seed = [0; 8];
64 OsRng.fill_bytes(&mut seed);
65 let seed = u64::from_le_bytes(seed);
66
67 // Init network stack
68 let stack: &Stack<_> = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
69
70 // Launch network task
71 spawner.spawn(net_task(stack)).unwrap();
72
73 let host = "example.com";
74 info!("querying host {:?}...", host);
75 match stack.dns_query(host, DnsQueryType::A).await {
76 Ok(r) => {
77 info!("query response: {:?}", r);
78 }
79 Err(e) => {
80 warn!("query error: {:?}", e);
81 }
82 };
83}
84
85static EXECUTOR: StaticCell<Executor> = StaticCell::new();
86
87fn main() {
88 env_logger::builder()
89 .filter_level(log::LevelFilter::Debug)
90 .filter_module("async_io", log::LevelFilter::Info)
91 .format_timestamp_nanos()
92 .init();
93
94 let executor = EXECUTOR.init(Executor::new());
95 executor.run(|spawner| {
96 spawner.spawn(main_task(spawner)).unwrap();
97 });
98}
diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs
index 392a97f0d..f1923f180 100644
--- a/examples/std/src/bin/net_udp.rs
+++ b/examples/std/src/bin/net_udp.rs
@@ -3,7 +3,7 @@
3use clap::Parser; 3use clap::Parser;
4use embassy_executor::{Executor, Spawner}; 4use embassy_executor::{Executor, Spawner};
5use embassy_net::udp::UdpSocket; 5use embassy_net::udp::UdpSocket;
6use embassy_net::{ConfigStrategy, Ipv4Address, Ipv4Cidr, PacketMetadata, Stack, StackResources}; 6use embassy_net::{Config, Ipv4Address, Ipv4Cidr, PacketMetadata, Stack, StackResources};
7use heapless::Vec; 7use heapless::Vec;
8use log::*; 8use log::*;
9use rand_core::{OsRng, RngCore}; 9use rand_core::{OsRng, RngCore};
@@ -47,13 +47,13 @@ async fn main_task(spawner: Spawner) {
47 47
48 // Choose between dhcp or static ip 48 // Choose between dhcp or static ip
49 let config = if opts.static_ip { 49 let config = if opts.static_ip {
50 ConfigStrategy::Static(embassy_net::Config { 50 Config::Static(embassy_net::StaticConfig {
51 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), 51 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
52 dns_servers: Vec::new(), 52 dns_servers: Vec::new(),
53 gateway: Some(Ipv4Address::new(192, 168, 69, 1)), 53 gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
54 }) 54 })
55 } else { 55 } else {
56 ConfigStrategy::Dhcp 56 Config::Dhcp(Default::default())
57 }; 57 };
58 58
59 // Generate random seed 59 // Generate random seed
@@ -62,12 +62,7 @@ async fn main_task(spawner: Spawner) {
62 let seed = u64::from_le_bytes(seed); 62 let seed = u64::from_le_bytes(seed);
63 63
64 // Init network stack 64 // Init network stack
65 let stack = &*singleton!(Stack::new( 65 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
66 device,
67 config,
68 singleton!(StackResources::<1, 2, 8>::new()),
69 seed
70 ));
71 66
72 // Launch network task 67 // Launch network task
73 spawner.spawn(net_task(stack)).unwrap(); 68 spawner.spawn(net_task(stack)).unwrap();
diff --git a/examples/std/src/tuntap.rs b/examples/std/src/tuntap.rs
index a0cace7f7..d918a2e62 100644
--- a/examples/std/src/tuntap.rs
+++ b/examples/std/src/tuntap.rs
@@ -1,8 +1,10 @@
1use std::io; 1use std::io;
2use std::io::{Read, Write}; 2use std::io::{Read, Write};
3use std::os::unix::io::{AsRawFd, RawFd}; 3use std::os::unix::io::{AsRawFd, RawFd};
4use std::task::Context;
4 5
5use async_io::Async; 6use async_io::Async;
7use embassy_net_driver::{self, Capabilities, Driver, LinkState};
6use log::*; 8use log::*;
7 9
8pub const SIOCGIFMTU: libc::c_ulong = 0x8921; 10pub const SIOCGIFMTU: libc::c_ulong = 0x8921;
@@ -125,54 +127,35 @@ impl io::Write for TunTap {
125 127
126pub struct TunTapDevice { 128pub struct TunTapDevice {
127 device: Async<TunTap>, 129 device: Async<TunTap>,
128 waker: Option<Waker>,
129} 130}
130 131
131impl TunTapDevice { 132impl TunTapDevice {
132 pub fn new(name: &str) -> io::Result<TunTapDevice> { 133 pub fn new(name: &str) -> io::Result<TunTapDevice> {
133 Ok(Self { 134 Ok(Self {
134 device: Async::new(TunTap::new(name)?)?, 135 device: Async::new(TunTap::new(name)?)?,
135 waker: None,
136 }) 136 })
137 } 137 }
138} 138}
139 139
140use core::task::Waker; 140impl Driver for TunTapDevice {
141use std::task::Context; 141 type RxToken<'a> = RxToken where Self: 'a;
142 142 type TxToken<'a> = TxToken<'a> where Self: 'a;
143use embassy_net::{Device, DeviceCapabilities, LinkState, Packet, PacketBox, PacketBoxExt, PacketBuf};
144
145impl Device for TunTapDevice {
146 fn is_transmit_ready(&mut self) -> bool {
147 true
148 }
149 143
150 fn transmit(&mut self, pkt: PacketBuf) { 144 fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
151 // todo handle WouldBlock 145 let mut buf = vec![0; self.device.get_ref().mtu];
152 match self.device.get_mut().write(&pkt) {
153 Ok(_) => {}
154 Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
155 info!("transmit WouldBlock");
156 }
157 Err(e) => panic!("transmit error: {:?}", e),
158 }
159 }
160
161 fn receive(&mut self) -> Option<PacketBuf> {
162 let mut pkt = PacketBox::new(Packet::new()).unwrap();
163 loop { 146 loop {
164 match self.device.get_mut().read(&mut pkt[..]) { 147 match self.device.get_mut().read(&mut buf) {
165 Ok(n) => { 148 Ok(n) => {
166 return Some(pkt.slice(0..n)); 149 buf.truncate(n);
150 return Some((
151 RxToken { buffer: buf },
152 TxToken {
153 device: &mut self.device,
154 },
155 ));
167 } 156 }
168 Err(e) if e.kind() == io::ErrorKind::WouldBlock => { 157 Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
169 let ready = if let Some(w) = self.waker.as_ref() { 158 if !self.device.poll_readable(cx).is_ready() {
170 let mut cx = Context::from_waker(w);
171 self.device.poll_readable(&mut cx).is_ready()
172 } else {
173 false
174 };
175 if !ready {
176 return None; 159 return None;
177 } 160 }
178 } 161 }
@@ -181,37 +164,19 @@ impl Device for TunTapDevice {
181 } 164 }
182 } 165 }
183 166
184 fn register_waker(&mut self, w: &Waker) { 167 fn transmit(&mut self, _cx: &mut Context) -> Option<Self::TxToken<'_>> {
185 match self.waker { 168 Some(TxToken {
186 // Optimization: If both the old and new Wakers wake the same task, we can simply 169 device: &mut self.device,
187 // keep the old waker, skipping the clone. (In most executor implementations, 170 })
188 // cloning a waker is somewhat expensive, comparable to cloning an Arc).
189 Some(ref w2) if (w2.will_wake(w)) => {}
190 _ => {
191 // clone the new waker and store it
192 if let Some(old_waker) = core::mem::replace(&mut self.waker, Some(w.clone())) {
193 // We had a waker registered for another task. Wake it, so the other task can
194 // reregister itself if it's still interested.
195 //
196 // If two tasks are waiting on the same thing concurrently, this will cause them
197 // to wake each other in a loop fighting over this WakerRegistration. This wastes
198 // CPU but things will still work.
199 //
200 // If the user wants to have two tasks waiting on the same thing they should use
201 // a more appropriate primitive that can store multiple wakers.
202 old_waker.wake()
203 }
204 }
205 }
206 } 171 }
207 172
208 fn capabilities(&self) -> DeviceCapabilities { 173 fn capabilities(&self) -> Capabilities {
209 let mut caps = DeviceCapabilities::default(); 174 let mut caps = Capabilities::default();
210 caps.max_transmission_unit = self.device.get_ref().mtu; 175 caps.max_transmission_unit = self.device.get_ref().mtu;
211 caps 176 caps
212 } 177 }
213 178
214 fn link_state(&mut self) -> LinkState { 179 fn link_state(&mut self, _cx: &mut Context) -> LinkState {
215 LinkState::Up 180 LinkState::Up
216 } 181 }
217 182
@@ -219,3 +184,41 @@ impl Device for TunTapDevice {
219 [0x02, 0x03, 0x04, 0x05, 0x06, 0x07] 184 [0x02, 0x03, 0x04, 0x05, 0x06, 0x07]
220 } 185 }
221} 186}
187
188#[doc(hidden)]
189pub struct RxToken {
190 buffer: Vec<u8>,
191}
192
193impl embassy_net_driver::RxToken for RxToken {
194 fn consume<R, F>(mut self, f: F) -> R
195 where
196 F: FnOnce(&mut [u8]) -> R,
197 {
198 f(&mut self.buffer)
199 }
200}
201
202#[doc(hidden)]
203pub struct TxToken<'a> {
204 device: &'a mut Async<TunTap>,
205}
206
207impl<'a> embassy_net_driver::TxToken for TxToken<'a> {
208 fn consume<R, F>(self, len: usize, f: F) -> R
209 where
210 F: FnOnce(&mut [u8]) -> R,
211 {
212 let mut buffer = vec![0; len];
213 let result = f(&mut buffer);
214
215 // todo handle WouldBlock with async
216 match self.device.get_mut().write(&buffer) {
217 Ok(_) => {}
218 Err(e) if e.kind() == io::ErrorKind::WouldBlock => info!("transmit WouldBlock"),
219 Err(e) => panic!("transmit error: {:?}", e),
220 }
221
222 result
223 }
224}
diff --git a/examples/stm32c0/.cargo/config.toml b/examples/stm32c0/.cargo/config.toml
new file mode 100644
index 000000000..eb07f6190
--- /dev/null
+++ b/examples/stm32c0/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32G071C8Rx with your chip as listed in `probe-run --list-chips`
3runner = "probe-rs-cli run --speed 100 --chip STM32c031c6tx"
4
5[build]
6target = "thumbv6m-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml
new file mode 100644
index 000000000..0095a680c
--- /dev/null
+++ b/examples/stm32c0/Cargo.toml
@@ -0,0 +1,21 @@
1[package]
2edition = "2021"
3name = "embassy-stm32c0-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] }
12
13defmt = "0.3"
14defmt-rtt = "0.4"
15
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = "0.7.0"
18embedded-hal = "0.2.6"
19panic-probe = { version = "0.3", features = ["print-defmt"] }
20futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
21heapless = { version = "0.7.5", default-features = false }
diff --git a/examples/stm32c0/build.rs b/examples/stm32c0/build.rs
new file mode 100644
index 000000000..8cd32d7ed
--- /dev/null
+++ b/examples/stm32c0/build.rs
@@ -0,0 +1,5 @@
1fn main() {
2 println!("cargo:rustc-link-arg-bins=--nmagic");
3 println!("cargo:rustc-link-arg-bins=-Tlink.x");
4 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
5}
diff --git a/examples/stm32c0/src/bin/blinky.rs b/examples/stm32c0/src/bin/blinky.rs
new file mode 100644
index 000000000..8a65b0692
--- /dev/null
+++ b/examples/stm32c0/src/bin/blinky.rs
@@ -0,0 +1,27 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_time::{Duration, Timer};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default());
14 info!("Hello World!");
15
16 let mut led = Output::new(p.PA5, Level::High, Speed::Low);
17
18 loop {
19 info!("high");
20 led.set_high();
21 Timer::after(Duration::from_millis(300)).await;
22
23 info!("low");
24 led.set_low();
25 Timer::after(Duration::from_millis(300)).await;
26 }
27}
diff --git a/examples/stm32c0/src/bin/button.rs b/examples/stm32c0/src/bin/button.rs
new file mode 100644
index 000000000..72a3f5cbf
--- /dev/null
+++ b/examples/stm32c0/src/bin/button.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use cortex_m_rt::entry;
6use defmt::*;
7use embassy_stm32::gpio::{Input, Pull};
8use {defmt_rtt as _, panic_probe as _};
9
10#[entry]
11fn main() -> ! {
12 info!("Hello World!");
13
14 let p = embassy_stm32::init(Default::default());
15
16 let button = Input::new(p.PC13, Pull::Up);
17
18 loop {
19 if button.is_high() {
20 info!("high");
21 } else {
22 info!("low");
23 }
24 }
25}
diff --git a/examples/stm32c0/src/bin/button_exti.rs b/examples/stm32c0/src/bin/button_exti.rs
new file mode 100644
index 000000000..ef32d4c4a
--- /dev/null
+++ b/examples/stm32c0/src/bin/button_exti.rs
@@ -0,0 +1,27 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::exti::ExtiInput;
8use embassy_stm32::gpio::{Input, Pull};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default());
14 info!("Hello World!");
15
16 let button = Input::new(p.PC13, Pull::Up);
17 let mut button = ExtiInput::new(button, p.EXTI13);
18
19 info!("Press the USER button...");
20
21 loop {
22 button.wait_for_falling_edge().await;
23 info!("Pressed!");
24 button.wait_for_rising_edge().await;
25 info!("Released!");
26 }
27}
diff --git a/examples/stm32f0/.cargo/config.toml b/examples/stm32f0/.cargo/config.toml
index d1b1cd0bf..16abc29bc 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-run --chip STM32F030F4Px' 2runner = 'probe-run --chip STM32F091RCTX'
3 3
4[build] 4[build]
5target = "thumbv6m-none-eabi" 5target = "thumbv6m-none-eabi"
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml
index a56c546ee..d4afbb8f8 100644
--- a/examples/stm32f0/Cargo.toml
+++ b/examples/stm32f0/Cargo.toml
@@ -10,10 +10,10 @@ license = "MIT OR Apache-2.0"
10cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 10cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
11cortex-m-rt = "0.7.0" 11cortex-m-rt = "0.7.0"
12defmt = "0.3" 12defmt = "0.3"
13defmt-rtt = "0.3" 13defmt-rtt = "0.4"
14panic-probe = "0.3" 14panic-probe = "0.3"
15embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 15embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
16embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 16embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
17embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 17embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
18embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f030f4", "time-driver-any"] } 18embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti"] }
19 19static_cell = "1.0"
diff --git a/examples/stm32f0/src/bin/blinky.rs b/examples/stm32f0/src/bin/blinky.rs
new file mode 100644
index 000000000..9f923399c
--- /dev/null
+++ b/examples/stm32f0/src/bin/blinky.rs
@@ -0,0 +1,28 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_time::{Duration, Timer};
9use {defmt_rtt as _, panic_probe as _};
10
11// main is itself an async function.
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let p = embassy_stm32::init(Default::default());
15 info!("Hello World!");
16 //PA5 is the onboard LED on the Nucleo F091RC
17 let mut led = Output::new(p.PA5, Level::High, Speed::Low);
18
19 loop {
20 info!("high");
21 led.set_high();
22 Timer::after(Duration::from_millis(300)).await;
23
24 info!("low");
25 led.set_low();
26 Timer::after(Duration::from_millis(300)).await;
27 }
28}
diff --git a/examples/stm32f0/src/bin/button_controlled_blink.rs b/examples/stm32f0/src/bin/button_controlled_blink.rs
new file mode 100644
index 000000000..e1f223433
--- /dev/null
+++ b/examples/stm32f0/src/bin/button_controlled_blink.rs
@@ -0,0 +1,64 @@
1//! This example showcases how to create task
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6
7use core::sync::atomic::{AtomicU32, Ordering};
8
9use defmt::info;
10use embassy_executor::Spawner;
11use embassy_stm32::exti::ExtiInput;
12use embassy_stm32::gpio::{AnyPin, Input, Level, Output, Pin, Pull, Speed};
13use embassy_time::{Duration, Timer};
14use {defmt_rtt as _, panic_probe as _};
15
16static BLINK_MS: AtomicU32 = AtomicU32::new(0);
17
18#[embassy_executor::task]
19async fn led_task(led: AnyPin) {
20 // Configure the LED pin as a push pull ouput and obtain handler.
21 // On the Nucleo F091RC theres an on-board LED connected to pin PA5.
22 let mut led = Output::new(led, Level::Low, Speed::Low);
23
24 loop {
25 let del = BLINK_MS.load(Ordering::Relaxed);
26 info!("Value of del is {}", del);
27 Timer::after(Duration::from_millis(del.into())).await;
28 info!("LED toggling");
29 led.toggle();
30 }
31}
32
33#[embassy_executor::main]
34async fn main(spawner: Spawner) {
35 // Initialize and create handle for devicer peripherals
36 let p = embassy_stm32::init(Default::default());
37
38 // Configure the button pin and obtain handler.
39 // On the Nucleo F091RC there is a button connected to pin PC13.
40 let button = Input::new(p.PC13, Pull::None);
41 let mut button = ExtiInput::new(button, p.EXTI13);
42
43 // Create and initialize a delay variable to manage delay loop
44 let mut del_var = 2000;
45
46 // Blink duration value to global context
47 BLINK_MS.store(del_var, Ordering::Relaxed);
48
49 // Spawn LED blinking task
50 spawner.spawn(led_task(p.PA5.degrade())).unwrap();
51
52 loop {
53 // Check if button got pressed
54 button.wait_for_rising_edge().await;
55 info!("rising_edge");
56 del_var = del_var - 200;
57 // If updated delay value drops below 200 then reset it back to starting value
58 if del_var < 200 {
59 del_var = 2000;
60 }
61 // Updated delay value to global context
62 BLINK_MS.store(del_var, Ordering::Relaxed);
63 }
64}
diff --git a/examples/stm32f0/src/bin/button_exti.rs b/examples/stm32f0/src/bin/button_exti.rs
new file mode 100644
index 000000000..40c0d5848
--- /dev/null
+++ b/examples/stm32f0/src/bin/button_exti.rs
@@ -0,0 +1,27 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::exti::ExtiInput;
8use embassy_stm32::gpio::{Input, Pull};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 // Initialize and create handle for devicer peripherals
14 let p = embassy_stm32::init(Default::default());
15 // Configure the button pin and obtain handler.
16 // On the Nucleo F091RC there is a button connected to pin PC13.
17 let button = Input::new(p.PC13, Pull::Down);
18 let mut button = ExtiInput::new(button, p.EXTI13);
19
20 info!("Press the USER button...");
21 loop {
22 button.wait_for_falling_edge().await;
23 info!("Pressed!");
24 button.wait_for_rising_edge().await;
25 info!("Released!");
26 }
27}
diff --git a/examples/stm32f0/src/bin/priority.rs b/examples/stm32f0/src/bin/priority.rs
new file mode 100644
index 000000000..7fed6a773
--- /dev/null
+++ b/examples/stm32f0/src/bin/priority.rs
@@ -0,0 +1,139 @@
1//! This example showcases how to create multiple Executor instances to run tasks at
2//! different priority levels.
3//!
4//! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling
5//! there's work in the queue, and `wfe` for waiting for work.
6//!
7//! Medium and high priority executors run in two interrupts with different priorities.
8//! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since
9//! when there's work the interrupt will trigger and run the executor.
10//!
11//! Sample output below. Note that high priority ticks can interrupt everything else, and
12//! medium priority computations can interrupt low priority computations, making them to appear
13//! to take significantly longer time.
14//!
15//! ```not_rust
16//! [med] Starting long computation
17//! [med] done in 992 ms
18//! [high] tick!
19//! [low] Starting long computation
20//! [med] Starting long computation
21//! [high] tick!
22//! [high] tick!
23//! [med] done in 993 ms
24//! [med] Starting long computation
25//! [high] tick!
26//! [high] tick!
27//! [med] done in 993 ms
28//! [low] done in 3972 ms
29//! [med] Starting long computation
30//! [high] tick!
31//! [high] tick!
32//! [med] done in 993 ms
33//! ```
34//!
35//! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor.
36//! You will get an output like the following. Note that no computation is ever interrupted.
37//!
38//! ```not_rust
39//! [high] tick!
40//! [med] Starting long computation
41//! [med] done in 496 ms
42//! [low] Starting long computation
43//! [low] done in 992 ms
44//! [med] Starting long computation
45//! [med] done in 496 ms
46//! [high] tick!
47//! [low] Starting long computation
48//! [low] done in 992 ms
49//! [high] tick!
50//! [med] Starting long computation
51//! [med] done in 496 ms
52//! [high] tick!
53//! ```
54//!
55
56#![no_std]
57#![no_main]
58#![feature(type_alias_impl_trait)]
59
60use cortex_m_rt::entry;
61use defmt::*;
62use embassy_stm32::executor::{Executor, InterruptExecutor};
63use embassy_stm32::interrupt;
64use embassy_stm32::interrupt::InterruptExt;
65use embassy_time::{Duration, Instant, Timer};
66use static_cell::StaticCell;
67use {defmt_rtt as _, panic_probe as _};
68
69#[embassy_executor::task]
70async fn run_high() {
71 loop {
72 // info!(" [high] tick!");
73 Timer::after(Duration::from_ticks(27374)).await;
74 }
75}
76
77#[embassy_executor::task]
78async fn run_med() {
79 loop {
80 let start = Instant::now();
81 info!(" [med] Starting long computation");
82
83 // Spin-wait to simulate a long CPU computation
84 cortex_m::asm::delay(8_000_000); // ~1 second
85
86 let end = Instant::now();
87 let ms = end.duration_since(start).as_ticks() / 33;
88 info!(" [med] done in {} ms", ms);
89
90 Timer::after(Duration::from_ticks(23421)).await;
91 }
92}
93
94#[embassy_executor::task]
95async fn run_low() {
96 loop {
97 let start = Instant::now();
98 info!("[low] Starting long computation");
99
100 // Spin-wait to simulate a long CPU computation
101 cortex_m::asm::delay(16_000_000); // ~2 seconds
102
103 let end = Instant::now();
104 let ms = end.duration_since(start).as_ticks() / 33;
105 info!("[low] done in {} ms", ms);
106
107 Timer::after(Duration::from_ticks(32983)).await;
108 }
109}
110
111static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::USART1>> = StaticCell::new();
112static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::USART2>> = StaticCell::new();
113static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
114
115#[entry]
116fn main() -> ! {
117 // Initialize and create handle for devicer peripherals
118 let _p = embassy_stm32::init(Default::default());
119
120 // High-priority executor: USART1, priority level 6
121 let irq = interrupt::take!(USART1);
122 irq.set_priority(interrupt::Priority::P6);
123 let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
124 let spawner = executor.start();
125 unwrap!(spawner.spawn(run_high()));
126
127 // Medium-priority executor: USART2, priority level 7
128 let irq = interrupt::take!(USART2);
129 irq.set_priority(interrupt::Priority::P7);
130 let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
131 let spawner = executor.start();
132 unwrap!(spawner.spawn(run_med()));
133
134 // Low priority executor: runs in thread mode, using WFE/SEV
135 let executor = EXECUTOR_LOW.init(Executor::new());
136 executor.run(|spawner| {
137 unwrap!(spawner.spawn(run_low()));
138 });
139}
diff --git a/examples/stm32f0/src/bin/wdg.rs b/examples/stm32f0/src/bin/wdg.rs
new file mode 100644
index 000000000..80e76f901
--- /dev/null
+++ b/examples/stm32f0/src/bin/wdg.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::wdg::IndependentWatchdog;
8use embassy_time::{Duration, Timer};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 // Initialize and create handle for devicer peripherals
14 let p = embassy_stm32::init(Default::default());
15 // Configure the independent watchdog timer
16 let mut wdg = IndependentWatchdog::new(p.IWDG, 20_000_00);
17
18 info!("Watchdog start");
19 unsafe { wdg.unleash() };
20
21 loop {
22 Timer::after(Duration::from_secs(1)).await;
23 unsafe { wdg.pet() };
24 }
25}
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index 6be131f30..53f369b3a 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -13,7 +13,7 @@ embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defm
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
14 14
15defmt = "0.3" 15defmt = "0.3"
16defmt-rtt = "0.3" 16defmt-rtt = "0.4"
17 17
18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
19cortex-m-rt = "0.7.0" 19cortex-m-rt = "0.7.0"
diff --git a/examples/stm32f1/src/bin/adc.rs b/examples/stm32f1/src/bin/adc.rs
index 2d6b4a0e9..ed59e2799 100644
--- a/examples/stm32f1/src/bin/adc.rs
+++ b/examples/stm32f1/src/bin/adc.rs
@@ -16,11 +16,19 @@ async fn main(_spawner: Spawner) {
16 let mut adc = Adc::new(p.ADC1, &mut Delay); 16 let mut adc = Adc::new(p.ADC1, &mut Delay);
17 let mut pin = p.PB1; 17 let mut pin = p.PB1;
18 18
19 let mut vref = adc.enable_vref(&mut Delay); 19 let mut vrefint = adc.enable_vref(&mut Delay);
20 adc.calibrate(&mut vref); 20 let vrefint_sample = adc.read(&mut vrefint);
21 let convert_to_millivolts = |sample| {
22 // From http://www.st.com/resource/en/datasheet/CD00161566.pdf
23 // 5.3.4 Embedded reference voltage
24 const VREFINT_MV: u32 = 1200; // mV
25
26 (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
27 };
28
21 loop { 29 loop {
22 let v = adc.read(&mut pin); 30 let v = adc.read(&mut pin);
23 info!("--> {} - {} mV", v, adc.to_millivolts(v)); 31 info!("--> {} - {} mV", v, convert_to_millivolts(v));
24 Timer::after(Duration::from_millis(100)).await; 32 Timer::after(Duration::from_millis(100)).await;
25 } 33 }
26} 34}
diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs
index ad92cdeb2..07cad84ef 100644
--- a/examples/stm32f1/src/bin/usb_serial.rs
+++ b/examples/stm32f1/src/bin/usb_serial.rs
@@ -58,7 +58,6 @@ async fn main(_spawner: Spawner) {
58 &mut config_descriptor, 58 &mut config_descriptor,
59 &mut bos_descriptor, 59 &mut bos_descriptor,
60 &mut control_buf, 60 &mut control_buf,
61 None,
62 ); 61 );
63 62
64 // Create classes on the builder. 63 // Create classes on the builder.
diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml
index f6adda2a3..afaf9a0c9 100644
--- a/examples/stm32f2/Cargo.toml
+++ b/examples/stm32f2/Cargo.toml
@@ -11,7 +11,7 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
12 12
13defmt = "0.3" 13defmt = "0.3"
14defmt-rtt = "0.3" 14defmt-rtt = "0.4"
15 15
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = "0.7.0" 17cortex-m-rt = "0.7.0"
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml
index 27188dd19..69ebef786 100644
--- a/examples/stm32f3/Cargo.toml
+++ b/examples/stm32f3/Cargo.toml
@@ -13,7 +13,7 @@ embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defm
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
14 14
15defmt = "0.3" 15defmt = "0.3"
16defmt-rtt = "0.3" 16defmt-rtt = "0.4"
17 17
18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
19cortex-m-rt = "0.7.0" 19cortex-m-rt = "0.7.0"
diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs
index 3bc5a287f..47121acf1 100644
--- a/examples/stm32f3/src/bin/usart_dma.rs
+++ b/examples/stm32f3/src/bin/usart_dma.rs
@@ -7,6 +7,7 @@ use core::fmt::Write;
7use defmt::*; 7use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma; 9use embassy_stm32::dma::NoDma;
10use embassy_stm32::interrupt;
10use embassy_stm32::usart::{Config, Uart}; 11use embassy_stm32::usart::{Config, Uart};
11use heapless::String; 12use heapless::String;
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
@@ -17,7 +18,8 @@ async fn main(_spawner: Spawner) {
17 info!("Hello World!"); 18 info!("Hello World!");
18 19
19 let config = Config::default(); 20 let config = Config::default();
20 let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, p.DMA1_CH4, NoDma, config); 21 let irq = interrupt::take!(USART1);
22 let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, irq, p.DMA1_CH4, NoDma, config);
21 23
22 for n in 0u32.. { 24 for n in 0u32.. {
23 let mut s: String<128> = String::new(); 25 let mut s: String<128> = String::new();
diff --git a/examples/stm32f3/src/bin/usb_serial.rs b/examples/stm32f3/src/bin/usb_serial.rs
index f6d27c860..5b4e0a91a 100644
--- a/examples/stm32f3/src/bin/usb_serial.rs
+++ b/examples/stm32f3/src/bin/usb_serial.rs
@@ -55,7 +55,6 @@ async fn main(_spawner: Spawner) {
55 &mut config_descriptor, 55 &mut config_descriptor,
56 &mut bos_descriptor, 56 &mut bos_descriptor,
57 &mut control_buf, 57 &mut control_buf,
58 None,
59 ); 58 );
60 59
61 // Create classes on the builder. 60 // Create classes on the builder.
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index 6d4f09fba..e2b17bfcb 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -4,20 +4,21 @@ name = "embassy-stm32f4-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7
8[dependencies] 7[dependencies]
9embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
11embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
12embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
13embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"], optional = true }
13 14
14defmt = "0.3" 15defmt = "0.3"
15defmt-rtt = "0.3" 16defmt-rtt = "0.4"
16 17
17cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
18cortex-m-rt = "0.7.0" 19cortex-m-rt = "0.7.0"
19embedded-hal = "0.2.6" 20embedded-hal = "0.2.6"
20embedded-io = "0.3.0" 21embedded-io = "0.4.0"
21panic-probe = { version = "0.3", features = ["print-defmt"] } 22panic-probe = { version = "0.3", features = ["print-defmt"] }
22futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 23futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
23heapless = { version = "0.7.5", default-features = false } 24heapless = { version = "0.7.5", default-features = false }
@@ -26,5 +27,9 @@ embedded-storage = "0.3.0"
26micromath = "2.0.0" 27micromath = "2.0.0"
27static_cell = "1.0" 28static_cell = "1.0"
28 29
29usb-device = "0.2" 30[[bin]]
30usbd-serial = "0.1.1" 31name = "usb_ethernet"
32required-features = ["embassy-net"]
33
34[profile.release]
35debug = 2
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs
index 1d030f7dc..1c9a0b35d 100644
--- a/examples/stm32f4/src/bin/adc.rs
+++ b/examples/stm32f4/src/bin/adc.rs
@@ -24,19 +24,44 @@ async fn main(_spawner: Spawner) {
24 // Startup delay can be combined to the maximum of either 24 // Startup delay can be combined to the maximum of either
25 delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us())); 25 delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us()));
26 26
27 let vrefint_sample = adc.read_internal(&mut vrefint);
28
29 let convert_to_millivolts = |sample| {
30 // From http://www.st.com/resource/en/datasheet/DM00071990.pdf
31 // 6.3.24 Reference voltage
32 const VREFINT_MV: u32 = 1210; // mV
33
34 (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
35 };
36
37 let convert_to_celcius = |sample| {
38 // From http://www.st.com/resource/en/datasheet/DM00071990.pdf
39 // 6.3.22 Temperature sensor characteristics
40 const V25: i32 = 760; // mV
41 const AVG_SLOPE: f32 = 2.5; // mV/C
42
43 let sample_mv = convert_to_millivolts(sample) as i32;
44
45 (sample_mv - V25) as f32 / AVG_SLOPE + 25.0
46 };
47
48 info!("VrefInt: {}", vrefint_sample);
49 const MAX_ADC_SAMPLE: u16 = (1 << 12) - 1;
50 info!("VCCA: {} mV", convert_to_millivolts(MAX_ADC_SAMPLE));
51
27 loop { 52 loop {
28 // Read pin 53 // Read pin
29 let v = adc.read(&mut pin); 54 let v = adc.read(&mut pin);
30 info!("PC1: {} ({} mV)", v, adc.to_millivolts(v)); 55 info!("PC1: {} ({} mV)", v, convert_to_millivolts(v));
31 56
32 // Read internal temperature 57 // Read internal temperature
33 let v = adc.read_internal(&mut temp); 58 let v = adc.read_internal(&mut temp);
34 let celcius = Temperature::to_celcius(adc.to_millivolts(v)); 59 let celcius = convert_to_celcius(v);
35 info!("Internal temp: {} ({} C)", v, celcius); 60 info!("Internal temp: {} ({} C)", v, celcius);
36 61
37 // Read internal voltage reference 62 // Read internal voltage reference
38 let v = adc.read_internal(&mut vrefint); 63 let v = adc.read_internal(&mut vrefint);
39 info!("VrefInt: {} ({} mV)", v, adc.to_millivolts(v)); 64 info!("VrefInt: {}", v);
40 65
41 Timer::after(Duration::from_millis(100)).await; 66 Timer::after(Duration::from_millis(100)).await;
42 } 67 }
diff --git a/examples/stm32f4/src/bin/i2c.rs b/examples/stm32f4/src/bin/i2c.rs
new file mode 100644
index 000000000..6e51c211d
--- /dev/null
+++ b/examples/stm32f4/src/bin/i2c.rs
@@ -0,0 +1,45 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::i2c::{Error, I2c, TimeoutI2c};
9use embassy_stm32::interrupt;
10use embassy_stm32::time::Hertz;
11use embassy_time::Duration;
12use {defmt_rtt as _, panic_probe as _};
13
14const ADDRESS: u8 = 0x5F;
15const WHOAMI: u8 = 0x0F;
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) -> ! {
19 info!("Hello world!");
20 let p = embassy_stm32::init(Default::default());
21
22 let irq = interrupt::take!(I2C2_EV);
23 let mut i2c = I2c::new(
24 p.I2C2,
25 p.PB10,
26 p.PB11,
27 irq,
28 NoDma,
29 NoDma,
30 Hertz(100_000),
31 Default::default(),
32 );
33
34 // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long.
35 // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay.
36 let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000));
37
38 let mut data = [0u8; 1];
39
40 match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) {
41 Ok(()) => info!("Whoami: {}", data[0]),
42 Err(Error::Timeout) => error!("Operation timed out"),
43 Err(e) => error!("I2c Error: {:?}", e),
44 }
45}
diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs
index 90ad882b8..8f41bb6c4 100644
--- a/examples/stm32f4/src/bin/usart.rs
+++ b/examples/stm32f4/src/bin/usart.rs
@@ -5,6 +5,7 @@
5use cortex_m_rt::entry; 5use cortex_m_rt::entry;
6use defmt::*; 6use defmt::*;
7use embassy_stm32::dma::NoDma; 7use embassy_stm32::dma::NoDma;
8use embassy_stm32::interrupt;
8use embassy_stm32::usart::{Config, Uart}; 9use embassy_stm32::usart::{Config, Uart};
9use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
10 11
@@ -15,7 +16,8 @@ fn main() -> ! {
15 let p = embassy_stm32::init(Default::default()); 16 let p = embassy_stm32::init(Default::default());
16 17
17 let config = Config::default(); 18 let config = Config::default();
18 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, NoDma, NoDma, config); 19 let irq = interrupt::take!(USART3);
20 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, irq, NoDma, NoDma, config);
19 21
20 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 22 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
21 info!("wrote Hello, starting echo"); 23 info!("wrote Hello, starting echo");
diff --git a/examples/stm32f4/src/bin/usart_buffered.rs b/examples/stm32f4/src/bin/usart_buffered.rs
index 7bcecbd26..dd171fe13 100644
--- a/examples/stm32f4/src/bin/usart_buffered.rs
+++ b/examples/stm32f4/src/bin/usart_buffered.rs
@@ -4,9 +4,8 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::interrupt; 7use embassy_stm32::interrupt;
9use embassy_stm32::usart::{BufferedUart, Config, State, Uart}; 8use embassy_stm32::usart::{BufferedUart, Config, State};
10use embedded_io::asynch::BufRead; 9use embedded_io::asynch::BufRead;
11use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
12 11
@@ -16,13 +15,21 @@ async fn main(_spawner: Spawner) {
16 info!("Hello World!"); 15 info!("Hello World!");
17 16
18 let config = Config::default(); 17 let config = Config::default();
19 let usart = Uart::new(p.USART3, p.PD9, p.PD8, NoDma, NoDma, config);
20 18
21 let mut state = State::new(); 19 let mut state = State::new();
22 let irq = interrupt::take!(USART3); 20 let irq = interrupt::take!(USART3);
23 let mut tx_buf = [0u8; 32]; 21 let mut tx_buf = [0u8; 32];
24 let mut rx_buf = [0u8; 32]; 22 let mut rx_buf = [0u8; 32];
25 let mut buf_usart = BufferedUart::new(&mut state, usart, irq, &mut tx_buf, &mut rx_buf); 23 let mut buf_usart = BufferedUart::new(
24 &mut state,
25 p.USART3,
26 p.PD9,
27 p.PD8,
28 irq,
29 &mut tx_buf,
30 &mut rx_buf,
31 config,
32 );
26 33
27 loop { 34 loop {
28 let buf = buf_usart.fill_buf().await.unwrap(); 35 let buf = buf_usart.fill_buf().await.unwrap();
diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs
index bb41b8b4f..78baeaa0d 100644
--- a/examples/stm32f4/src/bin/usart_dma.rs
+++ b/examples/stm32f4/src/bin/usart_dma.rs
@@ -7,6 +7,7 @@ use core::fmt::Write;
7use defmt::*; 7use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma; 9use embassy_stm32::dma::NoDma;
10use embassy_stm32::interrupt;
10use embassy_stm32::usart::{Config, Uart}; 11use embassy_stm32::usart::{Config, Uart};
11use heapless::String; 12use heapless::String;
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
@@ -17,7 +18,8 @@ async fn main(_spawner: Spawner) {
17 info!("Hello World!"); 18 info!("Hello World!");
18 19
19 let config = Config::default(); 20 let config = Config::default();
20 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, p.DMA1_CH3, NoDma, config); 21 let irq = interrupt::take!(USART3);
22 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, irq, p.DMA1_CH3, NoDma, config);
21 23
22 for n in 0u32.. { 24 for n in 0u32.. {
23 let mut s: String<128> = String::new(); 25 let mut s: String<128> = String::new();
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
new file mode 100644
index 000000000..4a16aac07
--- /dev/null
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -0,0 +1,168 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_net::tcp::TcpSocket;
8use embassy_net::{Stack, StackResources};
9use embassy_stm32::rng::Rng;
10use embassy_stm32::time::mhz;
11use embassy_stm32::usb_otg::Driver;
12use embassy_stm32::{interrupt, Config};
13use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
14use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
15use embassy_usb::{Builder, UsbDevice};
16use embedded_io::asynch::Write;
17use static_cell::StaticCell;
18use {defmt_rtt as _, panic_probe as _};
19
20type UsbDriver = Driver<'static, embassy_stm32::peripherals::USB_OTG_FS>;
21
22macro_rules! singleton {
23 ($val:expr) => {{
24 type T = impl Sized;
25 static STATIC_CELL: StaticCell<T> = StaticCell::new();
26 let (x,) = STATIC_CELL.init(($val,));
27 x
28 }};
29}
30
31const MTU: usize = 1514;
32
33#[embassy_executor::task]
34async fn usb_task(mut device: UsbDevice<'static, UsbDriver>) -> ! {
35 device.run().await
36}
37
38#[embassy_executor::task]
39async fn usb_ncm_task(class: Runner<'static, UsbDriver, MTU>) -> ! {
40 class.run().await
41}
42
43#[embassy_executor::task]
44async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
45 stack.run().await
46}
47
48#[embassy_executor::main]
49async fn main(spawner: Spawner) {
50 info!("Hello World!");
51
52 let mut config = Config::default();
53 config.rcc.pll48 = true;
54 config.rcc.sys_ck = Some(mhz(48));
55
56 let p = embassy_stm32::init(config);
57
58 // Create the driver, from the HAL.
59 let irq = interrupt::take!(OTG_FS);
60 let ep_out_buffer = &mut singleton!([0; 256])[..];
61 let driver = Driver::new_fs(p.USB_OTG_FS, irq, p.PA12, p.PA11, ep_out_buffer);
62
63 // Create embassy-usb Config
64 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
65 config.manufacturer = Some("Embassy");
66 config.product = Some("USB-Ethernet example");
67 config.serial_number = Some("12345678");
68 config.max_power = 100;
69 config.max_packet_size_0 = 64;
70
71 // Required for Windows support.
72 config.composite_with_iads = true;
73 config.device_class = 0xEF;
74 config.device_sub_class = 0x02;
75 config.device_protocol = 0x01;
76
77 // Create embassy-usb DeviceBuilder using the driver and config.
78 let mut builder = Builder::new(
79 driver,
80 config,
81 &mut singleton!([0; 256])[..],
82 &mut singleton!([0; 256])[..],
83 &mut singleton!([0; 256])[..],
84 &mut singleton!([0; 128])[..],
85 );
86
87 // Our MAC addr.
88 let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC];
89 // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has.
90 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
91
92 // Create classes on the builder.
93 let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64);
94
95 // Build the builder.
96 let usb = builder.build();
97
98 unwrap!(spawner.spawn(usb_task(usb)));
99
100 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr);
101 unwrap!(spawner.spawn(usb_ncm_task(runner)));
102
103 let config = embassy_net::ConfigStrategy::Dhcp;
104 //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config {
105 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
106 // dns_servers: Vec::new(),
107 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
108 //});
109
110 // Generate random seed
111 let mut rng = Rng::new(p.RNG);
112 let mut seed = [0; 8];
113 unwrap!(rng.async_fill_bytes(&mut seed).await);
114 let seed = u64::from_le_bytes(seed);
115
116 // Init network stack
117 let stack = &*singleton!(Stack::new(
118 device,
119 config,
120 singleton!(StackResources::<1, 2, 8>::new()),
121 seed
122 ));
123
124 unwrap!(spawner.spawn(net_task(stack)));
125
126 // And now we can use it!
127
128 let mut rx_buffer = [0; 4096];
129 let mut tx_buffer = [0; 4096];
130 let mut buf = [0; 4096];
131
132 loop {
133 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
134 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
135
136 info!("Listening on TCP:1234...");
137 if let Err(e) = socket.accept(1234).await {
138 warn!("accept error: {:?}", e);
139 continue;
140 }
141
142 info!("Received connection from {:?}", socket.remote_endpoint());
143
144 loop {
145 let n = match socket.read(&mut buf).await {
146 Ok(0) => {
147 warn!("read EOF");
148 break;
149 }
150 Ok(n) => n,
151 Err(e) => {
152 warn!("read error: {:?}", e);
153 break;
154 }
155 };
156
157 info!("rxd {:02x}", &buf[..n]);
158
159 match socket.write_all(&buf[..n]).await {
160 Ok(()) => {}
161 Err(e) => {
162 warn!("write error: {:?}", e);
163 break;
164 }
165 };
166 }
167 }
168}
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs
new file mode 100644
index 000000000..baabc1a2d
--- /dev/null
+++ b/examples/stm32f4/src/bin/usb_serial.rs
@@ -0,0 +1,105 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{panic, *};
6use embassy_executor::Spawner;
7use embassy_stm32::time::mhz;
8use embassy_stm32::usb_otg::{Driver, Instance};
9use embassy_stm32::{interrupt, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError;
12use embassy_usb::Builder;
13use futures::future::join;
14use {defmt_rtt as _, panic_probe as _};
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 info!("Hello World!");
19
20 let mut config = Config::default();
21 config.rcc.pll48 = true;
22 config.rcc.sys_ck = Some(mhz(48));
23
24 let p = embassy_stm32::init(config);
25
26 // Create the driver, from the HAL.
27 let irq = interrupt::take!(OTG_FS);
28 let mut ep_out_buffer = [0u8; 256];
29 let driver = Driver::new_fs(p.USB_OTG_FS, irq, p.PA12, p.PA11, &mut ep_out_buffer);
30
31 // Create embassy-usb Config
32 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
33 config.manufacturer = Some("Embassy");
34 config.product = Some("USB-serial example");
35 config.serial_number = Some("12345678");
36
37 // Required for windows compatiblity.
38 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
39 config.device_class = 0xEF;
40 config.device_sub_class = 0x02;
41 config.device_protocol = 0x01;
42 config.composite_with_iads = true;
43
44 // Create embassy-usb DeviceBuilder using the driver and config.
45 // It needs some buffers for building the descriptors.
46 let mut device_descriptor = [0; 256];
47 let mut config_descriptor = [0; 256];
48 let mut bos_descriptor = [0; 256];
49 let mut control_buf = [0; 64];
50
51 let mut state = State::new();
52
53 let mut builder = Builder::new(
54 driver,
55 config,
56 &mut device_descriptor,
57 &mut config_descriptor,
58 &mut bos_descriptor,
59 &mut control_buf,
60 );
61
62 // Create classes on the builder.
63 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
64
65 // Build the builder.
66 let mut usb = builder.build();
67
68 // Run the USB device.
69 let usb_fut = usb.run();
70
71 // Do stuff with the class!
72 let echo_fut = async {
73 loop {
74 class.wait_connection().await;
75 info!("Connected");
76 let _ = echo(&mut class).await;
77 info!("Disconnected");
78 }
79 };
80
81 // Run everything concurrently.
82 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
83 join(usb_fut, echo_fut).await;
84}
85
86struct Disconnected {}
87
88impl From<EndpointError> for Disconnected {
89 fn from(val: EndpointError) -> Self {
90 match val {
91 EndpointError::BufferOverflow => panic!("Buffer overflow"),
92 EndpointError::Disabled => Disconnected {},
93 }
94 }
95}
96
97async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
98 let mut buf = [0; 64];
99 loop {
100 let n = class.read_packet(&mut buf).await?;
101 let data = &buf[..n];
102 info!("data: {:x}", data);
103 class.write_packet(data).await?;
104 }
105}
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index dad92c0fc..ea4cbd808 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -8,12 +8,13 @@ license = "MIT OR Apache-2.0"
8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "net", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "unstable-pac", "time-driver-any", "exti"] }
12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } 12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
13embedded-io = { version = "0.3.0", features = ["async"] } 13embedded-io = { version = "0.4.0", features = ["async"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14 15
15defmt = "0.3" 16defmt = "0.3"
16defmt-rtt = "0.3" 17defmt-rtt = "0.4"
17 18
18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
19cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
diff --git a/examples/stm32f7/src/bin/adc.rs b/examples/stm32f7/src/bin/adc.rs
index 80fad8c41..70b3b2a75 100644
--- a/examples/stm32f7/src/bin/adc.rs
+++ b/examples/stm32f7/src/bin/adc.rs
@@ -16,9 +16,19 @@ async fn main(_spawner: Spawner) {
16 let mut adc = Adc::new(p.ADC1, &mut Delay); 16 let mut adc = Adc::new(p.ADC1, &mut Delay);
17 let mut pin = p.PA3; 17 let mut pin = p.PA3;
18 18
19 let mut vrefint = adc.enable_vrefint();
20 let vrefint_sample = adc.read_internal(&mut vrefint);
21 let convert_to_millivolts = |sample| {
22 // From http://www.st.com/resource/en/datasheet/DM00273119.pdf
23 // 6.3.27 Reference voltage
24 const VREFINT_MV: u32 = 1210; // mV
25
26 (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
27 };
28
19 loop { 29 loop {
20 let v = adc.read(&mut pin); 30 let v = adc.read(&mut pin);
21 info!("--> {} - {} mV", v, adc.to_millivolts(v)); 31 info!("--> {} - {} mV", v, convert_to_millivolts(v));
22 Timer::after(Duration::from_millis(100)).await; 32 Timer::after(Duration::from_millis(100)).await;
23 } 33 }
24} 34}
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs
index 5202edf62..571a6c1b9 100644
--- a/examples/stm32f7/src/bin/eth.rs
+++ b/examples/stm32f7/src/bin/eth.rs
@@ -7,7 +7,7 @@ use embassy_executor::Spawner;
7use embassy_net::tcp::TcpSocket; 7use embassy_net::tcp::TcpSocket;
8use embassy_net::{Ipv4Address, Stack, StackResources}; 8use embassy_net::{Ipv4Address, Stack, StackResources};
9use embassy_stm32::eth::generic_smi::GenericSMI; 9use embassy_stm32::eth::generic_smi::GenericSMI;
10use embassy_stm32::eth::{Ethernet, State}; 10use embassy_stm32::eth::{Ethernet, PacketQueue};
11use embassy_stm32::peripherals::ETH; 11use embassy_stm32::peripherals::ETH;
12use embassy_stm32::rng::Rng; 12use embassy_stm32::rng::Rng;
13use embassy_stm32::time::mhz; 13use embassy_stm32::time::mhz;
@@ -22,11 +22,12 @@ macro_rules! singleton {
22 ($val:expr) => {{ 22 ($val:expr) => {{
23 type T = impl Sized; 23 type T = impl Sized;
24 static STATIC_CELL: StaticCell<T> = StaticCell::new(); 24 static STATIC_CELL: StaticCell<T> = StaticCell::new();
25 STATIC_CELL.init_with(move || $val) 25 let (x,) = STATIC_CELL.init(($val,));
26 x
26 }}; 27 }};
27} 28}
28 29
29type Device = Ethernet<'static, ETH, GenericSMI, 4, 4>; 30type Device = Ethernet<'static, ETH, GenericSMI>;
30 31
31#[embassy_executor::task] 32#[embassy_executor::task]
32async fn net_task(stack: &'static Stack<Device>) -> ! { 33async fn net_task(stack: &'static Stack<Device>) -> ! {
@@ -50,40 +51,33 @@ async fn main(spawner: Spawner) -> ! {
50 let eth_int = interrupt::take!(ETH); 51 let eth_int = interrupt::take!(ETH);
51 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 52 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
52 53
53 let device = unsafe { 54 let device = Ethernet::new(
54 Ethernet::new( 55 singleton!(PacketQueue::<16, 16>::new()),
55 singleton!(State::new()), 56 p.ETH,
56 p.ETH, 57 eth_int,
57 eth_int, 58 p.PA1,
58 p.PA1, 59 p.PA2,
59 p.PA2, 60 p.PC1,
60 p.PC1, 61 p.PA7,
61 p.PA7, 62 p.PC4,
62 p.PC4, 63 p.PC5,
63 p.PC5, 64 p.PG13,
64 p.PG13, 65 p.PB13,
65 p.PB13, 66 p.PG11,
66 p.PG11, 67 GenericSMI,
67 GenericSMI, 68 mac_addr,
68 mac_addr, 69 0,
69 0, 70 );
70 ) 71
71 }; 72 let config = embassy_net::Config::Dhcp(Default::default());
72 73 //let config = embassy_net::Config::Static(embassy_net::StaticConfig {
73 let config = embassy_net::ConfigStrategy::Dhcp;
74 //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config {
75 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 74 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
76 // dns_servers: Vec::new(), 75 // dns_servers: Vec::new(),
77 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 76 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
78 //}); 77 //});
79 78
80 // Init network stack 79 // Init network stack
81 let stack = &*singleton!(Stack::new( 80 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
82 device,
83 config,
84 singleton!(StackResources::<1, 2, 8>::new()),
85 seed
86 ));
87 81
88 // Launch network task 82 // Launch network task
89 unwrap!(spawner.spawn(net_task(&stack))); 83 unwrap!(spawner.spawn(net_task(&stack)));
@@ -91,8 +85,8 @@ async fn main(spawner: Spawner) -> ! {
91 info!("Network task initialized"); 85 info!("Network task initialized");
92 86
93 // Then we can use it! 87 // Then we can use it!
94 let mut rx_buffer = [0; 1024]; 88 let mut rx_buffer = [0; 4096];
95 let mut tx_buffer = [0; 1024]; 89 let mut tx_buffer = [0; 4096];
96 90
97 loop { 91 loop {
98 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); 92 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer);
@@ -107,8 +101,9 @@ async fn main(spawner: Spawner) -> ! {
107 continue; 101 continue;
108 } 102 }
109 info!("connected!"); 103 info!("connected!");
104 let buf = [0; 1024];
110 loop { 105 loop {
111 let r = socket.write_all(b"Hello\n").await; 106 let r = socket.write_all(&buf).await;
112 if let Err(e) = r { 107 if let Err(e) = r {
113 info!("write error: {:?}", e); 108 info!("write error: {:?}", e);
114 return; 109 return;
diff --git a/examples/stm32f7/src/bin/usart_dma.rs b/examples/stm32f7/src/bin/usart_dma.rs
index 07270479c..4827c52ae 100644
--- a/examples/stm32f7/src/bin/usart_dma.rs
+++ b/examples/stm32f7/src/bin/usart_dma.rs
@@ -7,6 +7,7 @@ use core::fmt::Write;
7use defmt::*; 7use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma; 9use embassy_stm32::dma::NoDma;
10use embassy_stm32::interrupt;
10use embassy_stm32::usart::{Config, Uart}; 11use embassy_stm32::usart::{Config, Uart};
11use heapless::String; 12use heapless::String;
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
@@ -15,7 +16,8 @@ use {defmt_rtt as _, panic_probe as _};
15async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
16 let p = embassy_stm32::init(Default::default()); 17 let p = embassy_stm32::init(Default::default());
17 let config = Config::default(); 18 let config = Config::default();
18 let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, p.DMA1_CH1, NoDma, config); 19 let irq = interrupt::take!(UART7);
20 let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, irq, p.DMA1_CH1, NoDma, config);
19 21
20 for n in 0u32.. { 22 for n in 0u32.. {
21 let mut s: String<128> = String::new(); 23 let mut s: String<128> = String::new();
diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs
new file mode 100644
index 000000000..5fd9d2ec9
--- /dev/null
+++ b/examples/stm32f7/src/bin/usb_serial.rs
@@ -0,0 +1,106 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{panic, *};
6use embassy_executor::Spawner;
7use embassy_stm32::time::mhz;
8use embassy_stm32::usb_otg::{Driver, Instance};
9use embassy_stm32::{interrupt, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError;
12use embassy_usb::Builder;
13use futures::future::join;
14use {defmt_rtt as _, panic_probe as _};
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 info!("Hello World!");
19
20 let mut config = Config::default();
21 config.rcc.hse = Some(mhz(8));
22 config.rcc.pll48 = true;
23 config.rcc.sys_ck = Some(mhz(200));
24
25 let p = embassy_stm32::init(config);
26
27 // Create the driver, from the HAL.
28 let irq = interrupt::take!(OTG_FS);
29 let mut ep_out_buffer = [0u8; 256];
30 let driver = Driver::new_fs(p.USB_OTG_FS, irq, p.PA12, p.PA11, &mut ep_out_buffer);
31
32 // Create embassy-usb Config
33 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
34 config.manufacturer = Some("Embassy");
35 config.product = Some("USB-serial example");
36 config.serial_number = Some("12345678");
37
38 // Required for windows compatiblity.
39 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
40 config.device_class = 0xEF;
41 config.device_sub_class = 0x02;
42 config.device_protocol = 0x01;
43 config.composite_with_iads = true;
44
45 // Create embassy-usb DeviceBuilder using the driver and config.
46 // It needs some buffers for building the descriptors.
47 let mut device_descriptor = [0; 256];
48 let mut config_descriptor = [0; 256];
49 let mut bos_descriptor = [0; 256];
50 let mut control_buf = [0; 64];
51
52 let mut state = State::new();
53
54 let mut builder = Builder::new(
55 driver,
56 config,
57 &mut device_descriptor,
58 &mut config_descriptor,
59 &mut bos_descriptor,
60 &mut control_buf,
61 );
62
63 // Create classes on the builder.
64 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
65
66 // Build the builder.
67 let mut usb = builder.build();
68
69 // Run the USB device.
70 let usb_fut = usb.run();
71
72 // Do stuff with the class!
73 let echo_fut = async {
74 loop {
75 class.wait_connection().await;
76 info!("Connected");
77 let _ = echo(&mut class).await;
78 info!("Disconnected");
79 }
80 };
81
82 // Run everything concurrently.
83 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
84 join(usb_fut, echo_fut).await;
85}
86
87struct Disconnected {}
88
89impl From<EndpointError> for Disconnected {
90 fn from(val: EndpointError) -> Self {
91 match val {
92 EndpointError::BufferOverflow => panic!("Buffer overflow"),
93 EndpointError::Disabled => Disconnected {},
94 }
95 }
96}
97
98async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
99 let mut buf = [0; 64];
100 loop {
101 let n = class.read_packet(&mut buf).await?;
102 let data = &buf[..n];
103 info!("data: {:x}", data);
104 class.write_packet(data).await?;
105 }
106}
diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml
index f5673718d..e7273c9fc 100644
--- a/examples/stm32g0/Cargo.toml
+++ b/examples/stm32g0/Cargo.toml
@@ -11,7 +11,7 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] }
12 12
13defmt = "0.3" 13defmt = "0.3"
14defmt-rtt = "0.3" 14defmt-rtt = "0.4"
15 15
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = "0.7.0" 17cortex-m-rt = "0.7.0"
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index ecda28805..8a57a8ef0 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -12,7 +12,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["
12embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } 12embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" }
13 13
14defmt = "0.3" 14defmt = "0.3"
15defmt-rtt = "0.3" 15defmt-rtt = "0.4"
16 16
17cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 17cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
18cortex-m-rt = "0.7.0" 18cortex-m-rt = "0.7.0"
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index 1a05b9ecb..a04134789 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -8,19 +8,20 @@ license = "MIT OR Apache-2.0"
8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "net", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16", "unstable-traits"] } 12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] }
13embedded-io = { version = "0.3.0", features = ["async"] } 13embedded-io = { version = "0.4.0", features = ["async"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14 15
15defmt = "0.3" 16defmt = "0.3"
16defmt-rtt = "0.3" 17defmt-rtt = "0.4"
17 18
18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
19cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
20embedded-hal = "0.2.6" 21embedded-hal = "0.2.6"
21embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } 22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
22embedded-hal-async = { version = "=0.1.0-alpha.2" } 23embedded-hal-async = { version = "=0.2.0-alpha.0" }
23embedded-nal-async = "0.2.0" 24embedded-nal-async = "0.4.0"
24panic-probe = { version = "0.3", features = ["print-defmt"] } 25panic-probe = { version = "0.3", features = ["print-defmt"] }
25futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 26futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
26heapless = { version = "0.7.5", default-features = false } 27heapless = { version = "0.7.5", default-features = false }
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index 4ccc0b5ef..cb245c325 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -7,7 +7,7 @@ use embassy_executor::Spawner;
7use embassy_net::tcp::TcpSocket; 7use embassy_net::tcp::TcpSocket;
8use embassy_net::{Ipv4Address, Stack, StackResources}; 8use embassy_net::{Ipv4Address, Stack, StackResources};
9use embassy_stm32::eth::generic_smi::GenericSMI; 9use embassy_stm32::eth::generic_smi::GenericSMI;
10use embassy_stm32::eth::{Ethernet, State}; 10use embassy_stm32::eth::{Ethernet, PacketQueue};
11use embassy_stm32::peripherals::ETH; 11use embassy_stm32::peripherals::ETH;
12use embassy_stm32::rng::Rng; 12use embassy_stm32::rng::Rng;
13use embassy_stm32::time::mhz; 13use embassy_stm32::time::mhz;
@@ -22,11 +22,12 @@ macro_rules! singleton {
22 ($val:expr) => {{ 22 ($val:expr) => {{
23 type T = impl Sized; 23 type T = impl Sized;
24 static STATIC_CELL: StaticCell<T> = StaticCell::new(); 24 static STATIC_CELL: StaticCell<T> = StaticCell::new();
25 STATIC_CELL.init_with(move || $val) 25 let (x,) = STATIC_CELL.init(($val,));
26 x
26 }}; 27 }};
27} 28}
28 29
29type Device = Ethernet<'static, ETH, GenericSMI, 4, 4>; 30type Device = Ethernet<'static, ETH, GenericSMI>;
30 31
31#[embassy_executor::task] 32#[embassy_executor::task]
32async fn net_task(stack: &'static Stack<Device>) -> ! { 33async fn net_task(stack: &'static Stack<Device>) -> ! {
@@ -51,40 +52,33 @@ async fn main(spawner: Spawner) -> ! {
51 let eth_int = interrupt::take!(ETH); 52 let eth_int = interrupt::take!(ETH);
52 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 53 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
53 54
54 let device = unsafe { 55 let device = Ethernet::new(
55 Ethernet::new( 56 singleton!(PacketQueue::<16, 16>::new()),
56 singleton!(State::new()), 57 p.ETH,
57 p.ETH, 58 eth_int,
58 eth_int, 59 p.PA1,
59 p.PA1, 60 p.PA2,
60 p.PA2, 61 p.PC1,
61 p.PC1, 62 p.PA7,
62 p.PA7, 63 p.PC4,
63 p.PC4, 64 p.PC5,
64 p.PC5, 65 p.PG13,
65 p.PG13, 66 p.PB13,
66 p.PB13, 67 p.PG11,
67 p.PG11, 68 GenericSMI,
68 GenericSMI, 69 mac_addr,
69 mac_addr, 70 0,
70 0, 71 );
71 ) 72
72 }; 73 let config = embassy_net::Config::Dhcp(Default::default());
73 74 //let config = embassy_net::Config::Static(embassy_net::StaticConfig {
74 let config = embassy_net::ConfigStrategy::Dhcp;
75 //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config {
76 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 75 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
77 // dns_servers: Vec::new(), 76 // dns_servers: Vec::new(),
78 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 77 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
79 //}); 78 //});
80 79
81 // Init network stack 80 // Init network stack
82 let stack = &*singleton!(Stack::new( 81 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
83 device,
84 config,
85 singleton!(StackResources::<1, 2, 8>::new()),
86 seed
87 ));
88 82
89 // Launch network task 83 // Launch network task
90 unwrap!(spawner.spawn(net_task(&stack))); 84 unwrap!(spawner.spawn(net_task(&stack)));
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index 64fd84141..cce85a083 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -7,7 +7,7 @@ use embassy_executor::Spawner;
7use embassy_net::tcp::client::{TcpClient, TcpClientState}; 7use embassy_net::tcp::client::{TcpClient, TcpClientState};
8use embassy_net::{Stack, StackResources}; 8use embassy_net::{Stack, StackResources};
9use embassy_stm32::eth::generic_smi::GenericSMI; 9use embassy_stm32::eth::generic_smi::GenericSMI;
10use embassy_stm32::eth::{Ethernet, State}; 10use embassy_stm32::eth::{Ethernet, PacketQueue};
11use embassy_stm32::peripherals::ETH; 11use embassy_stm32::peripherals::ETH;
12use embassy_stm32::rng::Rng; 12use embassy_stm32::rng::Rng;
13use embassy_stm32::time::mhz; 13use embassy_stm32::time::mhz;
@@ -23,11 +23,12 @@ macro_rules! singleton {
23 ($val:expr) => {{ 23 ($val:expr) => {{
24 type T = impl Sized; 24 type T = impl Sized;
25 static STATIC_CELL: StaticCell<T> = StaticCell::new(); 25 static STATIC_CELL: StaticCell<T> = StaticCell::new();
26 STATIC_CELL.init_with(move || $val) 26 let (x,) = STATIC_CELL.init(($val,));
27 x
27 }}; 28 }};
28} 29}
29 30
30type Device = Ethernet<'static, ETH, GenericSMI, 4, 4>; 31type Device = Ethernet<'static, ETH, GenericSMI>;
31 32
32#[embassy_executor::task] 33#[embassy_executor::task]
33async fn net_task(stack: &'static Stack<Device>) -> ! { 34async fn net_task(stack: &'static Stack<Device>) -> ! {
@@ -52,40 +53,33 @@ async fn main(spawner: Spawner) -> ! {
52 let eth_int = interrupt::take!(ETH); 53 let eth_int = interrupt::take!(ETH);
53 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 54 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
54 55
55 let device = unsafe { 56 let device = Ethernet::new(
56 Ethernet::new( 57 singleton!(PacketQueue::<16, 16>::new()),
57 singleton!(State::new()), 58 p.ETH,
58 p.ETH, 59 eth_int,
59 eth_int, 60 p.PA1,
60 p.PA1, 61 p.PA2,
61 p.PA2, 62 p.PC1,
62 p.PC1, 63 p.PA7,
63 p.PA7, 64 p.PC4,
64 p.PC4, 65 p.PC5,
65 p.PC5, 66 p.PG13,
66 p.PG13, 67 p.PB13,
67 p.PB13, 68 p.PG11,
68 p.PG11, 69 GenericSMI,
69 GenericSMI, 70 mac_addr,
70 mac_addr, 71 0,
71 0, 72 );
72 ) 73
73 }; 74 let config = embassy_net::Config::Dhcp(Default::default());
74 75 //let config = embassy_net::Config::StaticConfig(embassy_net::Config {
75 let config = embassy_net::ConfigStrategy::Dhcp;
76 //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config {
77 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 76 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
78 // dns_servers: Vec::new(), 77 // dns_servers: Vec::new(),
79 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 78 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
80 //}); 79 //});
81 80
82 // Init network stack 81 // Init network stack
83 let stack = &*singleton!(Stack::new( 82 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
84 device,
85 config,
86 singleton!(StackResources::<1, 2, 8>::new()),
87 seed
88 ));
89 83
90 // Launch network task 84 // Launch network task
91 unwrap!(spawner.spawn(net_task(&stack))); 85 unwrap!(spawner.spawn(net_task(&stack)));
diff --git a/examples/stm32h7/src/bin/i2c.rs b/examples/stm32h7/src/bin/i2c.rs
new file mode 100644
index 000000000..d44319ae6
--- /dev/null
+++ b/examples/stm32h7/src/bin/i2c.rs
@@ -0,0 +1,44 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::i2c::{Error, I2c, TimeoutI2c};
8use embassy_stm32::interrupt;
9use embassy_stm32::time::Hertz;
10use embassy_time::Duration;
11use {defmt_rtt as _, panic_probe as _};
12
13const ADDRESS: u8 = 0x5F;
14const WHOAMI: u8 = 0x0F;
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) -> ! {
18 info!("Hello world!");
19 let p = embassy_stm32::init(Default::default());
20
21 let irq = interrupt::take!(I2C2_EV);
22 let mut i2c = I2c::new(
23 p.I2C2,
24 p.PB10,
25 p.PB11,
26 irq,
27 p.DMA1_CH4,
28 p.DMA1_CH5,
29 Hertz(100_000),
30 Default::default(),
31 );
32
33 // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long.
34 // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay.
35 let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000));
36
37 let mut data = [0u8; 1];
38
39 match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) {
40 Ok(()) => info!("Whoami: {}", data[0]),
41 Err(Error::Timeout) => error!("Operation timed out"),
42 Err(e) => error!("I2c Error: {:?}", e),
43 }
44}
diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs
index 87c2b1253..405f18ec7 100644
--- a/examples/stm32h7/src/bin/usart.rs
+++ b/examples/stm32h7/src/bin/usart.rs
@@ -6,6 +6,7 @@ use cortex_m_rt::entry;
6use defmt::*; 6use defmt::*;
7use embassy_executor::Executor; 7use embassy_executor::Executor;
8use embassy_stm32::dma::NoDma; 8use embassy_stm32::dma::NoDma;
9use embassy_stm32::interrupt;
9use embassy_stm32::usart::{Config, Uart}; 10use embassy_stm32::usart::{Config, Uart};
10use static_cell::StaticCell; 11use static_cell::StaticCell;
11use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
@@ -15,7 +16,8 @@ async fn main_task() {
15 let p = embassy_stm32::init(Default::default()); 16 let p = embassy_stm32::init(Default::default());
16 17
17 let config = Config::default(); 18 let config = Config::default();
18 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, NoDma, NoDma, config); 19 let irq = interrupt::take!(UART7);
20 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, NoDma, NoDma, config);
19 21
20 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 22 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
21 info!("wrote Hello, starting echo"); 23 info!("wrote Hello, starting echo");
diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs
index 3adffcbeb..6e3491e55 100644
--- a/examples/stm32h7/src/bin/usart_dma.rs
+++ b/examples/stm32h7/src/bin/usart_dma.rs
@@ -8,6 +8,7 @@ use cortex_m_rt::entry;
8use defmt::*; 8use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_stm32::dma::NoDma; 10use embassy_stm32::dma::NoDma;
11use embassy_stm32::interrupt;
11use embassy_stm32::usart::{Config, Uart}; 12use embassy_stm32::usart::{Config, Uart};
12use heapless::String; 13use heapless::String;
13use static_cell::StaticCell; 14use static_cell::StaticCell;
@@ -18,7 +19,8 @@ async fn main_task() {
18 let p = embassy_stm32::init(Default::default()); 19 let p = embassy_stm32::init(Default::default());
19 20
20 let config = Config::default(); 21 let config = Config::default();
21 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_CH0, NoDma, config); 22 let irq = interrupt::take!(UART7);
23 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.DMA1_CH0, NoDma, config);
22 24
23 for n in 0u32.. { 25 for n in 0u32.. {
24 let mut s: String<128> = String::new(); 26 let mut s: String<128> = String::new();
diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs
index df2b600f8..f97176ecb 100644
--- a/examples/stm32h7/src/bin/usart_split.rs
+++ b/examples/stm32h7/src/bin/usart_split.rs
@@ -5,6 +5,7 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma; 7use embassy_stm32::dma::NoDma;
8use embassy_stm32::interrupt;
8use embassy_stm32::peripherals::{DMA1_CH1, UART7}; 9use embassy_stm32::peripherals::{DMA1_CH1, UART7};
9use embassy_stm32::usart::{Config, Uart, UartRx}; 10use embassy_stm32::usart::{Config, Uart, UartRx};
10use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 11use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
@@ -31,7 +32,8 @@ async fn main(spawner: Spawner) -> ! {
31 info!("Hello World!"); 32 info!("Hello World!");
32 33
33 let config = Config::default(); 34 let config = Config::default();
34 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_CH0, p.DMA1_CH1, config); 35 let irq = interrupt::take!(UART7);
36 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, irq, p.DMA1_CH0, p.DMA1_CH1, config);
35 unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); 37 unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n"));
36 38
37 let (mut tx, rx) = usart.split(); 39 let (mut tx, rx) = usart.split();
diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs
new file mode 100644
index 000000000..9ef520ae2
--- /dev/null
+++ b/examples/stm32h7/src/bin/usb_serial.rs
@@ -0,0 +1,105 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{panic, *};
6use embassy_executor::Spawner;
7use embassy_stm32::time::mhz;
8use embassy_stm32::usb_otg::{Driver, Instance};
9use embassy_stm32::{interrupt, Config};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError;
12use embassy_usb::Builder;
13use futures::future::join;
14use {defmt_rtt as _, panic_probe as _};
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 info!("Hello World!");
19
20 let mut config = Config::default();
21 config.rcc.sys_ck = Some(mhz(400));
22 config.rcc.hclk = Some(mhz(200));
23 config.rcc.pll1.q_ck = Some(mhz(100));
24 let p = embassy_stm32::init(config);
25
26 // Create the driver, from the HAL.
27 let irq = interrupt::take!(OTG_FS);
28 let mut ep_out_buffer = [0u8; 256];
29 let driver = Driver::new_fs(p.USB_OTG_FS, irq, p.PA12, p.PA11, &mut ep_out_buffer);
30
31 // Create embassy-usb Config
32 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
33 config.manufacturer = Some("Embassy");
34 config.product = Some("USB-serial example");
35 config.serial_number = Some("12345678");
36
37 // Required for windows compatiblity.
38 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
39 config.device_class = 0xEF;
40 config.device_sub_class = 0x02;
41 config.device_protocol = 0x01;
42 config.composite_with_iads = true;
43
44 // Create embassy-usb DeviceBuilder using the driver and config.
45 // It needs some buffers for building the descriptors.
46 let mut device_descriptor = [0; 256];
47 let mut config_descriptor = [0; 256];
48 let mut bos_descriptor = [0; 256];
49 let mut control_buf = [0; 64];
50
51 let mut state = State::new();
52
53 let mut builder = Builder::new(
54 driver,
55 config,
56 &mut device_descriptor,
57 &mut config_descriptor,
58 &mut bos_descriptor,
59 &mut control_buf,
60 );
61
62 // Create classes on the builder.
63 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
64
65 // Build the builder.
66 let mut usb = builder.build();
67
68 // Run the USB device.
69 let usb_fut = usb.run();
70
71 // Do stuff with the class!
72 let echo_fut = async {
73 loop {
74 class.wait_connection().await;
75 info!("Connected");
76 let _ = echo(&mut class).await;
77 info!("Disconnected");
78 }
79 };
80
81 // Run everything concurrently.
82 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
83 join(usb_fut, echo_fut).await;
84}
85
86struct Disconnected {}
87
88impl From<EndpointError> for Disconnected {
89 fn from(val: EndpointError) -> Self {
90 match val {
91 EndpointError::BufferOverflow => panic!("Buffer overflow"),
92 EndpointError::Disabled => Disconnected {},
93 }
94 }
95}
96
97async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
98 let mut buf = [0; 64];
99 loop {
100 let n = class.read_packet(&mut buf).await?;
101 let data = &buf[..n];
102 info!("data: {:x}", data);
103 class.write_packet(data).await?;
104 }
105}
diff --git a/examples/stm32h7/src/bin/wdg.rs b/examples/stm32h7/src/bin/wdg.rs
new file mode 100644
index 000000000..2b0301aad
--- /dev/null
+++ b/examples/stm32h7/src/bin/wdg.rs
@@ -0,0 +1,24 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::wdg::IndependentWatchdog;
8use embassy_time::{Duration, Timer};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default());
14 info!("Hello World!");
15
16 let mut wdg = IndependentWatchdog::new(p.IWDG1, 20_000_000);
17
18 unsafe { wdg.unleash() };
19
20 loop {
21 Timer::after(Duration::from_secs(1)).await;
22 unsafe { wdg.pet() };
23 }
24}
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index 7e1120f48..86933a629 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -19,10 +19,10 @@ lorawan-device = { version = "0.8.0", default-features = false, features = ["asy
19lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"], optional = true } 19lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"], optional = true }
20 20
21defmt = "0.3" 21defmt = "0.3"
22defmt-rtt = "0.3" 22defmt-rtt = "0.4"
23 23
24embedded-storage = "0.3.0" 24embedded-storage = "0.3.0"
25embedded-io = "0.3.0" 25embedded-io = "0.4.0"
26 26
27cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 27cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
28cortex-m-rt = "0.7.0" 28cortex-m-rt = "0.7.0"
diff --git a/examples/stm32l0/src/bin/usart_dma.rs b/examples/stm32l0/src/bin/usart_dma.rs
index 66657d0f0..c307f857a 100644
--- a/examples/stm32l0/src/bin/usart_dma.rs
+++ b/examples/stm32l0/src/bin/usart_dma.rs
@@ -4,13 +4,15 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::interrupt;
7use embassy_stm32::usart::{Config, Uart}; 8use embassy_stm32::usart::{Config, Uart};
8use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
9 10
10#[embassy_executor::main] 11#[embassy_executor::main]
11async fn main(_spawner: Spawner) { 12async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
13 let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, p.DMA1_CH2, p.DMA1_CH3, Config::default()); 14 let irq = interrupt::take!(USART1);
15 let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, irq, p.DMA1_CH2, p.DMA1_CH3, Config::default());
14 16
15 usart.write(b"Hello Embassy World!\r\n").await.unwrap(); 17 usart.write(b"Hello Embassy World!\r\n").await.unwrap();
16 info!("wrote Hello, starting echo"); 18 info!("wrote Hello, starting echo");
diff --git a/examples/stm32l0/src/bin/usart_irq.rs b/examples/stm32l0/src/bin/usart_irq.rs
index 0e2237388..8e84cd092 100644
--- a/examples/stm32l0/src/bin/usart_irq.rs
+++ b/examples/stm32l0/src/bin/usart_irq.rs
@@ -4,9 +4,8 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma;
8use embassy_stm32::interrupt; 7use embassy_stm32::interrupt;
9use embassy_stm32::usart::{BufferedUart, Config, State, Uart}; 8use embassy_stm32::usart::{BufferedUart, Config, State};
10use embedded_io::asynch::{Read, Write}; 9use embedded_io::asynch::{Read, Write};
11use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
12 11
@@ -21,15 +20,18 @@ async fn main(_spawner: Spawner) {
21 let mut config = Config::default(); 20 let mut config = Config::default();
22 config.baudrate = 9600; 21 config.baudrate = 9600;
23 22
24 let usart = Uart::new(p.USART2, p.PA3, p.PA2, NoDma, NoDma, config);
25 let mut state = State::new(); 23 let mut state = State::new();
24 let irq = interrupt::take!(USART2);
26 let mut usart = unsafe { 25 let mut usart = unsafe {
27 BufferedUart::new( 26 BufferedUart::new(
28 &mut state, 27 &mut state,
29 usart, 28 p.USART2,
30 interrupt::take!(USART2), 29 p.PA3,
30 p.PA2,
31 irq,
31 &mut TX_BUFFER, 32 &mut TX_BUFFER,
32 &mut RX_BUFFER, 33 &mut RX_BUFFER,
34 config,
33 ) 35 )
34 }; 36 };
35 37
diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml
index 9460febf5..6e3b2103c 100644
--- a/examples/stm32l1/Cargo.toml
+++ b/examples/stm32l1/Cargo.toml
@@ -11,7 +11,7 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] }
12 12
13defmt = "0.3" 13defmt = "0.3"
14defmt-rtt = "0.3" 14defmt-rtt = "0.4"
15 15
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = "0.7.0" 17cortex-m-rt = "0.7.0"
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index 657605ebe..5627760ef 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -12,20 +12,18 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
14embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits"] } 14embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits"] }
15embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
15 16
16defmt = "0.3" 17defmt = "0.3"
17defmt-rtt = "0.3" 18defmt-rtt = "0.4"
18 19
19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 20cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 21cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6" 22embedded-hal = "0.2.6"
22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" } 23embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
23embedded-hal-async = { version = "=0.1.0-alpha.2" } 24embedded-hal-async = { version = "=0.2.0-alpha.0" }
24panic-probe = { version = "0.3", features = ["print-defmt"] } 25panic-probe = { version = "0.3", features = ["print-defmt"] }
25futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 26futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
26heapless = { version = "0.7.5", default-features = false } 27heapless = { version = "0.7.5", default-features = false }
27 28
28micromath = "2.0.0" 29micromath = "2.0.0"
29usb-device = "0.2"
30usbd-serial = "0.1.1"
31
diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs
index 4a4b46c53..7d874d9d7 100644
--- a/examples/stm32l4/src/bin/usart.rs
+++ b/examples/stm32l4/src/bin/usart.rs
@@ -4,6 +4,7 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_stm32::dma::NoDma; 6use embassy_stm32::dma::NoDma;
7use embassy_stm32::interrupt;
7use embassy_stm32::usart::{Config, Uart}; 8use embassy_stm32::usart::{Config, Uart};
8use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
9 10
@@ -14,7 +15,8 @@ fn main() -> ! {
14 let p = embassy_stm32::init(Default::default()); 15 let p = embassy_stm32::init(Default::default());
15 16
16 let config = Config::default(); 17 let config = Config::default();
17 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, NoDma, NoDma, config); 18 let irq = interrupt::take!(UART4);
19 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, irq, NoDma, NoDma, config);
18 20
19 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 21 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
20 info!("wrote Hello, starting echo"); 22 info!("wrote Hello, starting echo");
diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs
index 728906897..452bede30 100644
--- a/examples/stm32l4/src/bin/usart_dma.rs
+++ b/examples/stm32l4/src/bin/usart_dma.rs
@@ -7,6 +7,7 @@ use core::fmt::Write;
7use defmt::*; 7use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma; 9use embassy_stm32::dma::NoDma;
10use embassy_stm32::interrupt;
10use embassy_stm32::usart::{Config, Uart}; 11use embassy_stm32::usart::{Config, Uart};
11use heapless::String; 12use heapless::String;
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
@@ -17,7 +18,8 @@ async fn main(_spawner: Spawner) {
17 info!("Hello World!"); 18 info!("Hello World!");
18 19
19 let config = Config::default(); 20 let config = Config::default();
20 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, p.DMA1_CH3, NoDma, config); 21 let irq = interrupt::take!(UART4);
22 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, irq, p.DMA1_CH3, NoDma, config);
21 23
22 for n in 0u32.. { 24 for n in 0u32.. {
23 let mut s: String<128> = String::new(); 25 let mut s: String<128> = String::new();
diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs
new file mode 100644
index 000000000..663f60d52
--- /dev/null
+++ b/examples/stm32l4/src/bin/usb_serial.rs
@@ -0,0 +1,107 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{panic, *};
6use defmt_rtt as _; // global logger
7use embassy_executor::Spawner;
8use embassy_stm32::rcc::*;
9use embassy_stm32::usb_otg::{Driver, Instance};
10use embassy_stm32::{interrupt, Config};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError;
13use embassy_usb::Builder;
14use futures::future::join;
15use panic_probe as _;
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 info!("Hello World!");
20
21 let mut config = Config::default();
22 config.rcc.mux = ClockSrc::PLL(PLLSource::HSI16, PLLClkDiv::Div2, PLLSrcDiv::Div1, PLLMul::Mul10, None);
23 config.rcc.hsi48 = true;
24
25 let p = embassy_stm32::init(config);
26
27 // Create the driver, from the HAL.
28 let irq = interrupt::take!(OTG_FS);
29 let mut ep_out_buffer = [0u8; 256];
30 let driver = Driver::new_fs(p.USB_OTG_FS, irq, p.PA12, p.PA11, &mut ep_out_buffer);
31
32 // Create embassy-usb Config
33 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
34 config.max_packet_size_0 = 64;
35 config.manufacturer = Some("Embassy");
36 config.product = Some("USB-serial example");
37 config.serial_number = Some("12345678");
38
39 // Required for windows compatiblity.
40 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
41 config.device_class = 0xEF;
42 config.device_sub_class = 0x02;
43 config.device_protocol = 0x01;
44 config.composite_with_iads = true;
45
46 // Create embassy-usb DeviceBuilder using the driver and config.
47 // It needs some buffers for building the descriptors.
48 let mut device_descriptor = [0; 256];
49 let mut config_descriptor = [0; 256];
50 let mut bos_descriptor = [0; 256];
51 let mut control_buf = [0; 64];
52
53 let mut state = State::new();
54
55 let mut builder = Builder::new(
56 driver,
57 config,
58 &mut device_descriptor,
59 &mut config_descriptor,
60 &mut bos_descriptor,
61 &mut control_buf,
62 );
63
64 // Create classes on the builder.
65 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
66
67 // Build the builder.
68 let mut usb = builder.build();
69
70 // Run the USB device.
71 let usb_fut = usb.run();
72
73 // Do stuff with the class!
74 let echo_fut = async {
75 loop {
76 class.wait_connection().await;
77 info!("Connected");
78 let _ = echo(&mut class).await;
79 info!("Disconnected");
80 }
81 };
82
83 // Run everything concurrently.
84 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
85 join(usb_fut, echo_fut).await;
86}
87
88struct Disconnected {}
89
90impl From<EndpointError> for Disconnected {
91 fn from(val: EndpointError) -> Self {
92 match val {
93 EndpointError::BufferOverflow => panic!("Buffer overflow"),
94 EndpointError::Disabled => Disconnected {},
95 }
96 }
97}
98
99async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
100 let mut buf = [0; 64];
101 loop {
102 let n = class.read_packet(&mut buf).await?;
103 let data = &buf[..n];
104 info!("data: {:x}", data);
105 class.write_packet(data).await?;
106 }
107}
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index 63eac3ed2..c0accb0d6 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -12,12 +12,12 @@ embassy-executor = { version = "0.1.0", path = "../../embassy-executor", feature
12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] } 13embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } 15embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
17usbd-hid = "0.6.0" 17usbd-hid = "0.6.0"
18 18
19defmt = "0.3" 19defmt = "0.3"
20defmt-rtt = "0.3" 20defmt-rtt = "0.4"
21panic-probe = { version = "0.3", features = ["print-defmt"] } 21panic-probe = { version = "0.3", features = ["print-defmt"] }
22 22
23cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 23cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
@@ -26,5 +26,5 @@ embedded-hal = "0.2.6"
26futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 26futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
27heapless = { version = "0.7.5", default-features = false } 27heapless = { version = "0.7.5", default-features = false }
28rand_core = { version = "0.6.3", default-features = false } 28rand_core = { version = "0.6.3", default-features = false }
29embedded-io = { version = "0.3.0", features = ["async"] } 29embedded-io = { version = "0.4.0", features = ["async"] }
30static_cell = "1.0" 30static_cell = "1.0"
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index 4f36d3f5a..98ec0e836 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -2,20 +2,16 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use core::sync::atomic::{AtomicBool, Ordering};
6use core::task::Waker;
7
8use defmt::*; 5use defmt::*;
9use embassy_executor::Spawner; 6use embassy_executor::Spawner;
10use embassy_net::tcp::TcpSocket; 7use embassy_net::tcp::TcpSocket;
11use embassy_net::{PacketBox, PacketBoxExt, PacketBuf, Stack, StackResources}; 8use embassy_net::{Stack, StackResources};
12use embassy_stm32::rcc::*; 9use embassy_stm32::rcc::*;
13use embassy_stm32::rng::Rng; 10use embassy_stm32::rng::Rng;
14use embassy_stm32::usb::Driver; 11use embassy_stm32::usb::Driver;
15use embassy_stm32::{interrupt, Config}; 12use embassy_stm32::{interrupt, Config};
16use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 13use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
17use embassy_sync::channel::Channel; 14use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
18use embassy_usb::class::cdc_ncm::{CdcNcmClass, Receiver, Sender, State};
19use embassy_usb::{Builder, UsbDevice}; 15use embassy_usb::{Builder, UsbDevice};
20use embedded_io::asynch::Write; 16use embedded_io::asynch::Write;
21use rand_core::RngCore; 17use rand_core::RngCore;
@@ -28,56 +24,25 @@ macro_rules! singleton {
28 ($val:expr) => {{ 24 ($val:expr) => {{
29 type T = impl Sized; 25 type T = impl Sized;
30 static STATIC_CELL: StaticCell<T> = StaticCell::new(); 26 static STATIC_CELL: StaticCell<T> = StaticCell::new();
31 STATIC_CELL.init_with(move || $val) 27 let (x,) = STATIC_CELL.init(($val,));
28 x
32 }}; 29 }};
33} 30}
34 31
32const MTU: usize = 1514;
33
35#[embassy_executor::task] 34#[embassy_executor::task]
36async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! { 35async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! {
37 device.run().await 36 device.run().await
38} 37}
39 38
40#[embassy_executor::task] 39#[embassy_executor::task]
41async fn usb_ncm_rx_task(mut class: Receiver<'static, MyDriver>) { 40async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
42 loop { 41 class.run().await
43 warn!("WAITING for connection");
44 LINK_UP.store(false, Ordering::Relaxed);
45
46 class.wait_connection().await.unwrap();
47
48 warn!("Connected");
49 LINK_UP.store(true, Ordering::Relaxed);
50
51 loop {
52 let mut p = unwrap!(PacketBox::new(embassy_net::Packet::new()));
53 let n = match class.read_packet(&mut p[..]).await {
54 Ok(n) => n,
55 Err(e) => {
56 warn!("error reading packet: {:?}", e);
57 break;
58 }
59 };
60
61 let buf = p.slice(0..n);
62 if RX_CHANNEL.try_send(buf).is_err() {
63 warn!("Failed pushing rx'd packet to channel.");
64 }
65 }
66 }
67} 42}
68 43
69#[embassy_executor::task] 44#[embassy_executor::task]
70async fn usb_ncm_tx_task(mut class: Sender<'static, MyDriver>) { 45async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
71 loop {
72 let pkt = TX_CHANNEL.recv().await;
73 if let Err(e) = class.write_packet(&pkt[..]).await {
74 warn!("Failed to TX packet: {:?}", e);
75 }
76 }
77}
78
79#[embassy_executor::task]
80async fn net_task(stack: &'static Stack<Device>) -> ! {
81 stack.run().await 46 stack.run().await
82} 47}
83 48
@@ -106,58 +71,34 @@ async fn main(spawner: Spawner) {
106 config.device_sub_class = 0x02; 71 config.device_sub_class = 0x02;
107 config.device_protocol = 0x01; 72 config.device_protocol = 0x01;
108 73
109 struct Resources {
110 device_descriptor: [u8; 256],
111 config_descriptor: [u8; 256],
112 bos_descriptor: [u8; 256],
113 control_buf: [u8; 128],
114 serial_state: State<'static>,
115 }
116 let res: &mut Resources = singleton!(Resources {
117 device_descriptor: [0; 256],
118 config_descriptor: [0; 256],
119 bos_descriptor: [0; 256],
120 control_buf: [0; 128],
121 serial_state: State::new(),
122 });
123
124 // Create embassy-usb DeviceBuilder using the driver and config. 74 // Create embassy-usb DeviceBuilder using the driver and config.
125 let mut builder = Builder::new( 75 let mut builder = Builder::new(
126 driver, 76 driver,
127 config, 77 config,
128 &mut res.device_descriptor, 78 &mut singleton!([0; 256])[..],
129 &mut res.config_descriptor, 79 &mut singleton!([0; 256])[..],
130 &mut res.bos_descriptor, 80 &mut singleton!([0; 256])[..],
131 &mut res.control_buf, 81 &mut singleton!([0; 128])[..],
132 None,
133 ); 82 );
134 83
135 // WARNINGS for Android ethernet tethering:
136 // - On Pixel 4a, it refused to work on Android 11, worked on Android 12.
137 // - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte),
138 // it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled.
139 // 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
140 // and this nonsense in the linux kernel: https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757
141
142 // Our MAC addr. 84 // Our MAC addr.
143 let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC]; 85 let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC];
144 // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has. 86 // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has.
145 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88]; 87 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
146 88
147 // Create classes on the builder. 89 // Create classes on the builder.
148 let class = CdcNcmClass::new(&mut builder, &mut res.serial_state, host_mac_addr, 64); 90 let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64);
149 91
150 // Build the builder. 92 // Build the builder.
151 let usb = builder.build(); 93 let usb = builder.build();
152 94
153 unwrap!(spawner.spawn(usb_task(usb))); 95 unwrap!(spawner.spawn(usb_task(usb)));
154 96
155 let (tx, rx) = class.split(); 97 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr);
156 unwrap!(spawner.spawn(usb_ncm_rx_task(rx))); 98 unwrap!(spawner.spawn(usb_ncm_task(runner)));
157 unwrap!(spawner.spawn(usb_ncm_tx_task(tx)));
158 99
159 let config = embassy_net::ConfigStrategy::Dhcp; 100 let config = embassy_net::Config::Dhcp(Default::default());
160 //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { 101 //let config = embassy_net::Config::Static(embassy_net::StaticConfig {
161 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 102 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
162 // dns_servers: Vec::new(), 103 // dns_servers: Vec::new(),
163 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 104 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
@@ -168,13 +109,7 @@ async fn main(spawner: Spawner) {
168 let seed = rng.next_u64(); 109 let seed = rng.next_u64();
169 110
170 // Init network stack 111 // Init network stack
171 let device = Device { mac_addr: our_mac_addr }; 112 let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
172 let stack = &*singleton!(Stack::new(
173 device,
174 config,
175 singleton!(StackResources::<1, 2, 8>::new()),
176 seed
177 ));
178 113
179 unwrap!(spawner.spawn(net_task(stack))); 114 unwrap!(spawner.spawn(net_task(stack)));
180 115
@@ -221,50 +156,3 @@ async fn main(spawner: Spawner) {
221 } 156 }
222 } 157 }
223} 158}
224
225static TX_CHANNEL: Channel<ThreadModeRawMutex, PacketBuf, 8> = Channel::new();
226static RX_CHANNEL: Channel<ThreadModeRawMutex, PacketBuf, 8> = Channel::new();
227static LINK_UP: AtomicBool = AtomicBool::new(false);
228
229struct Device {
230 mac_addr: [u8; 6],
231}
232
233impl embassy_net::Device for Device {
234 fn register_waker(&mut self, waker: &Waker) {
235 // loopy loopy wakey wakey
236 waker.wake_by_ref()
237 }
238
239 fn link_state(&mut self) -> embassy_net::LinkState {
240 match LINK_UP.load(Ordering::Relaxed) {
241 true => embassy_net::LinkState::Up,
242 false => embassy_net::LinkState::Down,
243 }
244 }
245
246 fn capabilities(&self) -> embassy_net::DeviceCapabilities {
247 let mut caps = embassy_net::DeviceCapabilities::default();
248 caps.max_transmission_unit = 1514; // 1500 IP + 14 ethernet header
249 caps.medium = embassy_net::Medium::Ethernet;
250 caps
251 }
252
253 fn is_transmit_ready(&mut self) -> bool {
254 true
255 }
256
257 fn transmit(&mut self, pkt: PacketBuf) {
258 if TX_CHANNEL.try_send(pkt).is_err() {
259 warn!("TX failed")
260 }
261 }
262
263 fn receive<'a>(&mut self) -> Option<PacketBuf> {
264 RX_CHANNEL.try_recv().ok()
265 }
266
267 fn ethernet_address(&self) -> [u8; 6] {
268 self.mac_addr
269 }
270}
diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs
index d38ed7496..e3bbe9d09 100644
--- a/examples/stm32l5/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs
@@ -51,7 +51,6 @@ async fn main(_spawner: Spawner) {
51 &mut config_descriptor, 51 &mut config_descriptor,
52 &mut bos_descriptor, 52 &mut bos_descriptor,
53 &mut control_buf, 53 &mut control_buf,
54 None,
55 ); 54 );
56 55
57 // Create classes on the builder. 56 // Create classes on the builder.
diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs
index 7562a4e96..66ccacb73 100644
--- a/examples/stm32l5/src/bin/usb_serial.rs
+++ b/examples/stm32l5/src/bin/usb_serial.rs
@@ -46,7 +46,6 @@ async fn main(_spawner: Spawner) {
46 &mut config_descriptor, 46 &mut config_descriptor,
47 &mut bos_descriptor, 47 &mut bos_descriptor,
48 &mut control_buf, 48 &mut control_buf,
49 None,
50 ); 49 );
51 50
52 // Create classes on the builder. 51 // Create classes on the builder.
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml
index 3d704011b..2b02eda92 100644
--- a/examples/stm32u5/Cargo.toml
+++ b/examples/stm32u5/Cargo.toml
@@ -9,9 +9,10 @@ embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["de
9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] }
12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
12 13
13defmt = "0.3" 14defmt = "0.3"
14defmt-rtt = "0.3" 15defmt-rtt = "0.4"
15 16
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 17cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = "0.7.0" 18cortex-m-rt = "0.7.0"
@@ -21,8 +22,3 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
21heapless = { version = "0.7.5", default-features = false } 22heapless = { version = "0.7.5", default-features = false }
22 23
23micromath = "2.0.0" 24micromath = "2.0.0"
24
25#[patch.crates-io]
26#defmt = { git="https://github.com/knurling-rs/defmt.git" }
27#defmt-rtt = { git="https://github.com/knurling-rs/defmt.git" }
28
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs
new file mode 100644
index 000000000..8cd3bf2f4
--- /dev/null
+++ b/examples/stm32u5/src/bin/usb_serial.rs
@@ -0,0 +1,107 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{panic, *};
6use defmt_rtt as _; // global logger
7use embassy_executor::Spawner;
8use embassy_stm32::rcc::*;
9use embassy_stm32::usb_otg::{Driver, Instance};
10use embassy_stm32::{interrupt, Config};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError;
13use embassy_usb::Builder;
14use futures::future::join;
15use panic_probe as _;
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 info!("Hello World!");
20
21 let mut config = Config::default();
22 config.rcc.mux = ClockSrc::PLL1R(PllSrc::HSI16, PllM::Div2, PllN::Mul10, PllClkDiv::NotDivided);
23 //config.rcc.mux = ClockSrc::MSI(MSIRange::Range48mhz);
24 config.rcc.hsi48 = true;
25
26 let p = embassy_stm32::init(config);
27
28 // Create the driver, from the HAL.
29 let irq = interrupt::take!(OTG_FS);
30 let mut ep_out_buffer = [0u8; 256];
31 let driver = Driver::new_fs(p.USB_OTG_FS, irq, p.PA12, p.PA11, &mut ep_out_buffer);
32
33 // Create embassy-usb Config
34 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
35 config.manufacturer = Some("Embassy");
36 config.product = Some("USB-serial example");
37 config.serial_number = Some("12345678");
38
39 // Required for windows compatiblity.
40 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
41 config.device_class = 0xEF;
42 config.device_sub_class = 0x02;
43 config.device_protocol = 0x01;
44 config.composite_with_iads = true;
45
46 // Create embassy-usb DeviceBuilder using the driver and config.
47 // It needs some buffers for building the descriptors.
48 let mut device_descriptor = [0; 256];
49 let mut config_descriptor = [0; 256];
50 let mut bos_descriptor = [0; 256];
51 let mut control_buf = [0; 64];
52
53 let mut state = State::new();
54
55 let mut builder = Builder::new(
56 driver,
57 config,
58 &mut device_descriptor,
59 &mut config_descriptor,
60 &mut bos_descriptor,
61 &mut control_buf,
62 );
63
64 // Create classes on the builder.
65 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
66
67 // Build the builder.
68 let mut usb = builder.build();
69
70 // Run the USB device.
71 let usb_fut = usb.run();
72
73 // Do stuff with the class!
74 let echo_fut = async {
75 loop {
76 class.wait_connection().await;
77 info!("Connected");
78 let _ = echo(&mut class).await;
79 info!("Disconnected");
80 }
81 };
82
83 // Run everything concurrently.
84 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
85 join(usb_fut, echo_fut).await;
86}
87
88struct Disconnected {}
89
90impl From<EndpointError> for Disconnected {
91 fn from(val: EndpointError) -> Self {
92 match val {
93 EndpointError::BufferOverflow => panic!("Buffer overflow"),
94 EndpointError::Disabled => Disconnected {},
95 }
96 }
97}
98
99async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
100 let mut buf = [0; 64];
101 loop {
102 let n = class.read_packet(&mut buf).await?;
103 let data = &buf[..n];
104 info!("data: {:x}", data);
105 class.write_packet(data).await?;
106 }
107}
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index 5b96fa191..e27b4527c 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -11,7 +11,7 @@ embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["de
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55cc", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wb55cc", "time-driver-any", "exti"] }
12 12
13defmt = "0.3" 13defmt = "0.3"
14defmt-rtt = "0.3" 14defmt-rtt = "0.4"
15 15
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = "0.7.0" 17cortex-m-rt = "0.7.0"
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml
index c827d2b71..690481bbf 100644
--- a/examples/stm32wl/Cargo.toml
+++ b/examples/stm32wl/Cargo.toml
@@ -15,7 +15,7 @@ lorawan-device = { version = "0.8.0", default-features = false, features = ["asy
15lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"] } 15lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"] }
16 16
17defmt = "0.3" 17defmt = "0.3"
18defmt-rtt = "0.3" 18defmt-rtt = "0.4"
19 19
20cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 20cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
21cortex-m-rt = "0.7.0" 21cortex-m-rt = "0.7.0"
diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs
new file mode 100644
index 000000000..182c607f9
--- /dev/null
+++ b/examples/stm32wl/src/bin/random.rs
@@ -0,0 +1,33 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::pac;
8use embassy_stm32::rng::Rng;
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let mut config = embassy_stm32::Config::default();
14 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32;
15 config.rcc.enable_lsi = true; //Needed for RNG to work
16
17 let p = embassy_stm32::init(config);
18 unsafe {
19 pac::RCC.ccipr().modify(|w| {
20 w.set_rngsel(0b01);
21 });
22 }
23
24 info!("Hello World!");
25
26 let mut rng = Rng::new(p.RNG);
27
28 let mut buf = [0u8; 16];
29 unwrap!(rng.async_fill_bytes(&mut buf).await);
30 info!("random bytes: {:02x}", buf);
31
32 loop {}
33}
diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs
new file mode 100644
index 000000000..f12fec4c8
--- /dev/null
+++ b/examples/stm32wl/src/bin/uart_async.rs
@@ -0,0 +1,60 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::interrupt;
8use embassy_stm32::usart::{Config, Uart};
9use {defmt_rtt as _, panic_probe as _};
10
11/*
12Pass Incoming data from LPUART1 to USART1
13Example is written for the LoRa-E5 mini v1.0,
14but can be surely changed for your needs.
15*/
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut config = embassy_stm32::Config::default();
19 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32;
20 let p = embassy_stm32::init(config);
21
22 defmt::info!("Starting system");
23
24 let mut config1 = Config::default();
25 config1.baudrate = 9600;
26
27 let mut config2 = Config::default();
28 config2.baudrate = 9600;
29
30 //RX/TX connected to USB/UART Bridge on LoRa-E5 mini v1.0
31 let irq = interrupt::take!(USART1);
32 let mut usart1 = Uart::new(p.USART1, p.PB7, p.PB6, irq, p.DMA1_CH3, p.DMA1_CH4, config1);
33
34 //RX1/TX1 (LPUART) on LoRa-E5 mini v1.0
35 let irq = interrupt::take!(LPUART1);
36 let mut usart2 = Uart::new(p.LPUART1, p.PC0, p.PC1, irq, p.DMA1_CH5, p.DMA1_CH6, config2);
37
38 unwrap!(usart1.write(b"Hello Embassy World!\r\n").await);
39 unwrap!(usart2.write(b"Hello Embassy World!\r\n").await);
40
41 let mut buf = [0u8; 300];
42 loop {
43 let result = usart2.read_until_idle(&mut buf).await;
44 match result {
45 Ok(size) => {
46 match usart1.write(&buf[0..size]).await {
47 Ok(()) => {
48 //Write suc.
49 }
50 Err(..) => {
51 //Wasnt able to write
52 }
53 }
54 }
55 Err(_err) => {
56 //Ignore eg. framing errors
57 }
58 }
59 }
60}