aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorQuentin Smith <[email protected]>2023-07-17 21:31:43 -0400
committerQuentin Smith <[email protected]>2023-07-17 21:31:43 -0400
commit6f02403184eb7fb7990fb88fc9df9c4328a690a3 (patch)
tree748f510e190bb2724750507a6e69ed1a8e08cb20 /examples
parentd896f80405aa8963877049ed999e4aba25d6e2bb (diff)
parent6b5df4523aa1c4902f02e803450ae4b418e0e3ca (diff)
Merge remote-tracking branch 'origin/main' into nrf-pdm
Diffstat (limited to 'examples')
-rw-r--r--examples/.cargo/config.toml3
-rw-r--r--examples/boot/application/nrf/.cargo/config.toml4
-rw-r--r--examples/boot/application/nrf/Cargo.toml21
-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.rs41
-rw-r--r--examples/boot/application/nrf/src/bin/b.rs6
-rw-r--r--examples/boot/application/rp/.cargo/config.toml12
-rw-r--r--examples/boot/application/rp/Cargo.toml35
-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.rs67
-rw-r--r--examples/boot/application/rp/src/bin/b.rs23
-rw-r--r--examples/boot/application/stm32f3/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32f3/Cargo.toml14
-rw-r--r--examples/boot/application/stm32f3/src/bin/a.rs20
-rw-r--r--examples/boot/application/stm32f7/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32f7/Cargo.toml15
-rw-r--r--examples/boot/application/stm32f7/src/bin/a.rs33
-rw-r--r--examples/boot/application/stm32h7/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32h7/Cargo.toml15
-rwxr-xr-xexamples/boot/application/stm32h7/flash-boot.sh3
-rw-r--r--examples/boot/application/stm32h7/src/bin/a.rs33
-rw-r--r--examples/boot/application/stm32l0/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32l0/Cargo.toml14
-rw-r--r--examples/boot/application/stm32l0/src/bin/a.rs20
-rw-r--r--examples/boot/application/stm32l1/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32l1/Cargo.toml14
-rw-r--r--examples/boot/application/stm32l1/src/bin/a.rs20
-rw-r--r--examples/boot/application/stm32l4/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32l4/Cargo.toml14
-rw-r--r--examples/boot/application/stm32l4/src/bin/a.rs20
-rw-r--r--examples/boot/application/stm32wl/.cargo/config.toml4
-rw-r--r--examples/boot/application/stm32wl/Cargo.toml14
-rw-r--r--examples/boot/application/stm32wl/src/bin/a.rs20
-rw-r--r--examples/boot/bootloader/nrf/.cargo/config.toml2
-rw-r--r--examples/boot/bootloader/nrf/Cargo.toml10
-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.rs26
-rw-r--r--examples/boot/bootloader/rp/.cargo/config.toml8
-rw-r--r--examples/boot/bootloader/rp/Cargo.toml33
-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.rs56
-rw-r--r--examples/boot/bootloader/stm32/Cargo.toml12
-rw-r--r--examples/boot/bootloader/stm32/src/main.rs20
-rw-r--r--examples/nrf-rtos-trace/.cargo/config.toml4
-rw-r--r--examples/nrf-rtos-trace/Cargo.toml9
-rw-r--r--examples/nrf-rtos-trace/src/bin/rtos_trace.rs3
-rw-r--r--examples/nrf/src/bin/awaitable_timer.rs26
-rw-r--r--examples/nrf/src/bin/pdm.rs46
-rw-r--r--examples/nrf/src/bin/usb_ethernet.rs275
-rw-r--r--examples/nrf52840-rtic/.cargo/config.toml (renamed from examples/nrf/.cargo/config.toml)4
-rw-r--r--examples/nrf52840-rtic/Cargo.toml21
-rw-r--r--examples/nrf52840-rtic/build.rs35
-rw-r--r--examples/nrf52840-rtic/memory.x (renamed from examples/nrf/memory.x)0
-rw-r--r--examples/nrf52840-rtic/src/bin/blinky.rs43
-rw-r--r--examples/nrf52840/.cargo/config.toml9
-rw-r--r--examples/nrf52840/Cargo.toml61
-rw-r--r--examples/nrf52840/build.rs35
-rw-r--r--examples/nrf52840/memory.x7
-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)23
-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)3
-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.rs116
-rw-r--r--examples/nrf52840/src/bin/i2s_monitor.rs118
-rw-r--r--examples/nrf52840/src/bin/i2s_waveform.rs154
-rw-r--r--examples/nrf52840/src/bin/lora_cad.rs99
-rw-r--r--examples/nrf52840/src/bin/lora_lorawan.rs83
-rw-r--r--examples/nrf52840/src/bin/lora_p2p_receive.rs121
-rw-r--r--examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs131
-rw-r--r--examples/nrf52840/src/bin/lora_p2p_send.rs104
-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)30
-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)2
-rw-r--r--examples/nrf52840/src/bin/pdm.rs55
-rw-r--r--examples/nrf52840/src/bin/pdm_continuous.rs (renamed from examples/nrf/src/bin/pdm_continuous.rs)14
-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)4
-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)9
-rw-r--r--examples/nrf52840/src/bin/qspi.rs (renamed from examples/nrf/src/bin/qspi.rs)24
-rw-r--r--examples/nrf52840/src/bin/qspi_lowpower.rs (renamed from examples/nrf/src/bin/qspi_lowpower.rs)14
-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)8
-rw-r--r--examples/nrf52840/src/bin/saadc.rs (renamed from examples/nrf/src/bin/saadc.rs)8
-rw-r--r--examples/nrf52840/src/bin/saadc_continuous.rs (renamed from examples/nrf/src/bin/saadc_continuous.rs)12
-rw-r--r--examples/nrf52840/src/bin/self_spawn.rs (renamed from examples/nrf/src/bin/self_spawn.rs)6
-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)9
-rw-r--r--examples/nrf52840/src/bin/spis.rs30
-rw-r--r--examples/nrf52840/src/bin/temp.rs (renamed from examples/nrf/src/bin/temp.rs)9
-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)9
-rw-r--r--examples/nrf52840/src/bin/twim_lowpower.rs (renamed from examples/nrf/src/bin/twim_lowpower.rs)9
-rw-r--r--examples/nrf52840/src/bin/twis.rs48
-rw-r--r--examples/nrf52840/src/bin/uart.rs (renamed from examples/nrf/src/bin/uart.rs)9
-rw-r--r--examples/nrf52840/src/bin/uart_idle.rs39
-rw-r--r--examples/nrf52840/src/bin/uart_split.rs (renamed from examples/nrf/src/bin/uart_split.rs)9
-rw-r--r--examples/nrf52840/src/bin/usb_ethernet.rs165
-rw-r--r--examples/nrf52840/src/bin/usb_hid_keyboard.rs (renamed from examples/nrf/src/bin/usb_hid_keyboard.rs)53
-rw-r--r--examples/nrf52840/src/bin/usb_hid_mouse.rs (renamed from examples/nrf/src/bin/usb_hid_mouse.rs)24
-rw-r--r--examples/nrf52840/src/bin/usb_serial.rs (renamed from examples/nrf/src/bin/usb_serial.rs)26
-rw-r--r--examples/nrf52840/src/bin/usb_serial_multitask.rs (renamed from examples/nrf/src/bin/usb_serial_multitask.rs)52
-rw-r--r--examples/nrf52840/src/bin/usb_serial_winusb.rs134
-rw-r--r--examples/nrf52840/src/bin/wdt.rs (renamed from examples/nrf/src/bin/wdt.rs)2
-rw-r--r--examples/nrf52840/src/bin/wifi_esp_hosted.rs143
-rw-r--r--examples/nrf5340/.cargo/config.toml9
-rw-r--r--examples/nrf5340/Cargo.toml55
-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.rs (renamed from examples/nrf/src/bin/uart_idle.rs)15
-rw-r--r--examples/rp/.cargo/config.toml4
-rw-r--r--examples/rp/Cargo.toml48
-rw-r--r--examples/rp/src/bin/adc.rs48
-rw-r--r--examples/rp/src/bin/blinky.rs4
-rw-r--r--examples/rp/src/bin/button.rs9
-rw-r--r--examples/rp/src/bin/ethernet_w5500_multisocket.rs136
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_client.rs124
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_server.rs132
-rw-r--r--examples/rp/src/bin/ethernet_w5500_udp.rs112
-rw-r--r--examples/rp/src/bin/flash.rs101
-rw-r--r--examples/rp/src/bin/gpio_async.rs6
-rw-r--r--examples/rp/src/bin/gpout.rs38
-rw-r--r--examples/rp/src/bin/i2c_async.rs111
-rw-r--r--examples/rp/src/bin/i2c_blocking.rs75
-rw-r--r--examples/rp/src/bin/lora_lorawan.rs81
-rw-r--r--examples/rp/src/bin/lora_p2p_receive.rs116
-rw-r--r--examples/rp/src/bin/lora_p2p_send.rs104
-rw-r--r--examples/rp/src/bin/lora_p2p_send_multicore.rs140
-rw-r--r--examples/rp/src/bin/multicore.rs64
-rw-r--r--examples/rp/src/bin/multiprio.rs146
-rw-r--r--examples/rp/src/bin/pio_async.rs135
-rw-r--r--examples/rp/src/bin/pio_dma.rs86
-rw-r--r--examples/rp/src/bin/pio_hd44780.rs244
-rw-r--r--examples/rp/src/bin/pio_ws2812.rs160
-rw-r--r--examples/rp/src/bin/pwm.rs30
-rw-r--r--examples/rp/src/bin/rtc.rs46
-rw-r--r--examples/rp/src/bin/spi.rs6
-rw-r--r--examples/rp/src/bin/spi_async.rs32
-rw-r--r--examples/rp/src/bin/spi_display.rs162
-rw-r--r--examples/rp/src/bin/uart.rs8
-rw-r--r--examples/rp/src/bin/uart_buffered_split.rs57
-rw-r--r--examples/rp/src/bin/uart_unidir.rs51
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs155
-rw-r--r--examples/rp/src/bin/usb_hid_keyboard.rs188
-rw-r--r--examples/rp/src/bin/usb_logger.rs37
-rw-r--r--examples/rp/src/bin/usb_serial.rs109
-rw-r--r--examples/rp/src/bin/watchdog.rs52
-rw-r--r--examples/rp/src/bin/wifi_ap_tcp_server.rs139
-rw-r--r--examples/rp/src/bin/wifi_blinky.rs68
-rw-r--r--examples/rp/src/bin/wifi_scan.rs75
-rw-r--r--examples/rp/src/bin/wifi_tcp_server.rs149
-rw-r--r--examples/std/Cargo.toml16
-rw-r--r--examples/std/README.md23
-rw-r--r--examples/std/src/bin/net.rs26
-rw-r--r--examples/std/src/bin/net_dns.rs94
-rw-r--r--examples/std/src/bin/net_udp.rs23
-rw-r--r--examples/std/src/bin/tcp_accept.rs129
-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.toml15
-rw-r--r--examples/stm32f0/src/bin/adc.rs35
-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/multiprio.rs145
-rw-r--r--examples/stm32f0/src/bin/wdg.rs25
-rw-r--r--examples/stm32f1/.cargo/config.toml4
-rw-r--r--examples/stm32f1/Cargo.toml15
-rw-r--r--examples/stm32f1/src/bin/adc.rs14
-rw-r--r--examples/stm32f1/src/bin/usb_serial.rs14
-rw-r--r--examples/stm32f2/.cargo/config.toml4
-rw-r--r--examples/stm32f2/Cargo.toml11
-rw-r--r--examples/stm32f3/.cargo/config.toml4
-rw-r--r--examples/stm32f3/Cargo.toml16
-rw-r--r--examples/stm32f3/src/bin/flash.rs13
-rw-r--r--examples/stm32f3/src/bin/multiprio.rs34
-rw-r--r--examples/stm32f3/src/bin/usart_dma.rs7
-rw-r--r--examples/stm32f3/src/bin/usb_serial.rs14
-rw-r--r--examples/stm32f4/.cargo/config.toml4
-rw-r--r--examples/stm32f4/Cargo.toml25
-rw-r--r--examples/stm32f4/src/bin/adc.rs50
-rw-r--r--examples/stm32f4/src/bin/can.rs31
-rw-r--r--examples/stm32f4/src/bin/dac.rs9
-rw-r--r--examples/stm32f4/src/bin/eth.rs111
-rw-r--r--examples/stm32f4/src/bin/flash.rs13
-rw-r--r--examples/stm32f4/src/bin/flash_async.rs85
-rw-r--r--examples/stm32f4/src/bin/i2c.rs48
-rw-r--r--examples/stm32f4/src/bin/i2s_dma.rs36
-rw-r--r--examples/stm32f4/src/bin/mco.rs30
-rw-r--r--examples/stm32f4/src/bin/multiprio.rs34
-rw-r--r--examples/stm32f4/src/bin/pwm_complementary.rs52
-rw-r--r--examples/stm32f4/src/bin/rtc.rs30
-rw-r--r--examples/stm32f4/src/bin/sdmmc.rs63
-rw-r--r--examples/stm32f4/src/bin/usart.rs7
-rw-r--r--examples/stm32f4/src/bin/usart_buffered.rs14
-rw-r--r--examples/stm32f4/src/bin/usart_dma.rs7
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs164
-rw-r--r--examples/stm32f4/src/bin/usb_serial.rs110
-rw-r--r--examples/stm32f4/src/bin/wdt.rs8
-rw-r--r--examples/stm32f7/.cargo/config.toml4
-rw-r--r--examples/stm32f7/Cargo.toml20
-rw-r--r--examples/stm32f7/build.rs3
-rw-r--r--examples/stm32f7/src/bin/adc.rs12
-rw-r--r--examples/stm32f7/src/bin/can.rs66
-rw-r--r--examples/stm32f7/src/bin/eth.rs77
-rw-r--r--examples/stm32f7/src/bin/flash.rs15
-rw-r--r--examples/stm32f7/src/bin/sdmmc.rs15
-rw-r--r--examples/stm32f7/src/bin/usart_dma.rs7
-rw-r--r--examples/stm32f7/src/bin/usb_serial.rs111
-rw-r--r--examples/stm32g0/.cargo/config.toml4
-rw-r--r--examples/stm32g0/Cargo.toml11
-rw-r--r--examples/stm32g0/src/bin/spi_neopixel.rs101
-rw-r--r--examples/stm32g4/.cargo/config.toml4
-rw-r--r--examples/stm32g4/Cargo.toml10
-rw-r--r--examples/stm32g4/src/bin/pll.rs35
-rw-r--r--examples/stm32g4/src/bin/pwm.rs4
-rw-r--r--examples/stm32g4/src/bin/usb_serial.rs120
-rw-r--r--examples/stm32h5/.cargo/config.toml8
-rw-r--r--examples/stm32h5/Cargo.toml71
-rw-r--r--examples/stm32h5/build.rs5
-rw-r--r--examples/stm32h5/memory.x5
-rw-r--r--examples/stm32h5/src/bin/blinky.rs27
-rw-r--r--examples/stm32h5/src/bin/button_exti.rs27
-rw-r--r--examples/stm32h5/src/bin/eth.rs131
-rw-r--r--examples/stm32h5/src/bin/i2c.rs47
-rw-r--r--examples/stm32h5/src/bin/rng.rs20
-rw-r--r--examples/stm32h5/src/bin/usart.rs46
-rw-r--r--examples/stm32h5/src/bin/usart_dma.rs49
-rw-r--r--examples/stm32h5/src/bin/usart_split.rs61
-rw-r--r--examples/stm32h5/src/bin/usb_serial.rs129
-rw-r--r--examples/stm32h7/.cargo/config.toml2
-rw-r--r--examples/stm32h7/Cargo.toml26
-rw-r--r--examples/stm32h7/src/bin/camera.rs14
-rw-r--r--examples/stm32h7/src/bin/dac.rs9
-rw-r--r--examples/stm32h7/src/bin/eth.rs70
-rw-r--r--examples/stm32h7/src/bin/eth_client.rs68
-rw-r--r--examples/stm32h7/src/bin/flash.rs15
-rw-r--r--examples/stm32h7/src/bin/i2c.rs47
-rw-r--r--examples/stm32h7/src/bin/low_level_timer_api.rs54
-rw-r--r--examples/stm32h7/src/bin/sdmmc.rs10
-rw-r--r--examples/stm32h7/src/bin/signal.rs3
-rw-r--r--examples/stm32h7/src/bin/usart.rs7
-rw-r--r--examples/stm32h7/src/bin/usart_dma.rs7
-rw-r--r--examples/stm32h7/src/bin/usart_split.rs7
-rw-r--r--examples/stm32h7/src/bin/usb_serial.rs110
-rw-r--r--examples/stm32h7/src/bin/wdg.rs24
-rw-r--r--examples/stm32l0/.cargo/config.toml4
-rw-r--r--examples/stm32l0/Cargo.toml29
-rw-r--r--examples/stm32l0/src/bin/flash.rs13
-rw-r--r--examples/stm32l0/src/bin/lora_cad.rs105
-rw-r--r--examples/stm32l0/src/bin/lora_lorawan.rs88
-rw-r--r--examples/stm32l0/src/bin/lora_p2p_receive.rs127
-rw-r--r--examples/stm32l0/src/bin/lora_p2p_send.rs110
-rw-r--r--examples/stm32l0/src/bin/lorawan.rs75
-rw-r--r--examples/stm32l0/src/bin/usart_dma.rs7
-rw-r--r--examples/stm32l0/src/bin/usart_irq.rs21
-rw-r--r--examples/stm32l1/.cargo/config.toml4
-rw-r--r--examples/stm32l1/Cargo.toml11
-rw-r--r--examples/stm32l1/src/bin/flash.rs13
-rw-r--r--examples/stm32l4/.cargo/config.toml8
-rw-r--r--examples/stm32l4/Cargo.toml22
-rw-r--r--examples/stm32l4/src/bin/adc.rs10
-rw-r--r--examples/stm32l4/src/bin/dac.rs19
-rw-r--r--examples/stm32l4/src/bin/dac_dma.rs137
-rw-r--r--examples/stm32l4/src/bin/i2c.rs11
-rw-r--r--examples/stm32l4/src/bin/i2c_blocking_async.rs11
-rw-r--r--examples/stm32l4/src/bin/i2c_dma.rs11
-rw-r--r--examples/stm32l4/src/bin/mco.rs27
-rw-r--r--examples/stm32l4/src/bin/rtc.rs49
-rw-r--r--examples/stm32l4/src/bin/usart.rs7
-rw-r--r--examples/stm32l4/src/bin/usart_dma.rs7
-rw-r--r--examples/stm32l4/src/bin/usb_serial.rs112
-rw-r--r--examples/stm32l5/.cargo/config.toml4
-rw-r--r--examples/stm32l5/Cargo.toml25
-rw-r--r--examples/stm32l5/src/bin/usb_ethernet.rs169
-rw-r--r--examples/stm32l5/src/bin/usb_hid_mouse.rs22
-rw-r--r--examples/stm32l5/src/bin/usb_serial.rs15
-rw-r--r--examples/stm32u5/.cargo/config.toml4
-rw-r--r--examples/stm32u5/Cargo.toml17
-rw-r--r--examples/stm32u5/src/bin/usb_serial.rs112
-rw-r--r--examples/stm32wb/.cargo/config.toml5
-rw-r--r--examples/stm32wb/Cargo.toml40
-rw-r--r--examples/stm32wb/build.rs36
-rw-r--r--examples/stm32wb/memory.x41
-rw-r--r--examples/stm32wb/src/bin/eddystone_beacon.rs249
-rw-r--r--examples/stm32wb/src/bin/gatt_server.rs397
-rw-r--r--examples/stm32wb/src/bin/mac_ffd.rs206
-rw-r--r--examples/stm32wb/src/bin/mac_rfd.rs186
-rw-r--r--examples/stm32wb/src/bin/tl_mbox.rs76
-rw-r--r--examples/stm32wb/src/bin/tl_mbox_ble.rs64
-rw-r--r--examples/stm32wb/src/bin/tl_mbox_mac.rs76
-rw-r--r--examples/stm32wl/.cargo/config.toml6
-rw-r--r--examples/stm32wl/Cargo.toml24
-rw-r--r--examples/stm32wl/src/bin/flash.rs13
-rw-r--r--examples/stm32wl/src/bin/lora_lorawan.rs80
-rw-r--r--examples/stm32wl/src/bin/lora_p2p_receive.rs117
-rw-r--r--examples/stm32wl/src/bin/lora_p2p_send.rs100
-rw-r--r--examples/stm32wl/src/bin/lorawan.rs78
-rw-r--r--examples/stm32wl/src/bin/random.rs31
-rw-r--r--examples/stm32wl/src/bin/rtc.rs43
-rw-r--r--examples/stm32wl/src/bin/subghz.rs119
-rw-r--r--examples/stm32wl/src/bin/uart_async.rs63
-rw-r--r--examples/wasm/Cargo.toml7
-rw-r--r--examples/wasm/src/lib.rs1
330 files changed, 12366 insertions, 1953 deletions
diff --git a/examples/.cargo/config.toml b/examples/.cargo/config.toml
new file mode 100644
index 000000000..84d266320
--- /dev/null
+++ b/examples/.cargo/config.toml
@@ -0,0 +1,3 @@
1[profile.release]
2# Allows defmt to display log locations even in release
3debug = true \ No newline at end of file
diff --git a/examples/boot/application/nrf/.cargo/config.toml b/examples/boot/application/nrf/.cargo/config.toml
index 8ca28df39..17616a054 100644
--- a/examples/boot/application/nrf/.cargo/config.toml
+++ b/examples/boot/application/nrf/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-run --list-chips` 2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip nRF52840_xxAA" 3runner = "probe-rs run --chip nRF52840_xxAA"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml
index b9ff92578..2a0cf7818 100644
--- a/examples/boot/application/nrf/Cargo.toml
+++ b/examples/boot/application/nrf/Cargo.toml
@@ -2,19 +2,26 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-boot-nrf-examples" 3name = "embassy-boot-nrf-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" }
8embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
9embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly"] } 10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly"] }
10embassy-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"] }
11embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot/nrf" } 12embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = ["nightly"] }
13embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot/nrf", features = ["nightly"] }
12embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 14embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
13 15
14defmt = { version = "0.3", optional = true } 16defmt = { version = "0.3", optional = true }
15defmt-rtt = { version = "0.3", optional = true } 17defmt-rtt = { version = "0.4", optional = true }
16panic-reset = { version = "0.1.1" } 18panic-reset = { version = "0.1.1" }
17embedded-hal = { version = "0.2.6" } 19embedded-hal = { version = "0.2.6" }
18 20
19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-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"]
27skip-include = []
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 bd8fa3246..021d77f3b 100644
--- a/examples/boot/application/nrf/src/bin/a.rs
+++ b/examples/boot/application/nrf/src/bin/a.rs
@@ -1,42 +1,71 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![macro_use] 3#![macro_use]
4#![feature(generic_associated_types)]
5#![feature(type_alias_impl_trait)] 4#![feature(type_alias_impl_trait)]
6 5
7use embassy_boot_nrf::FirmwareUpdater; 6use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig};
8use embassy_embedded_hal::adapter::BlockingAsync; 7use embassy_embedded_hal::adapter::BlockingAsync;
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
10use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; 9use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
11use embassy_nrf::nvmc::Nvmc; 10use embassy_nrf::nvmc::Nvmc;
11use embassy_nrf::wdt::{self, Watchdog};
12use embassy_sync::mutex::Mutex;
12use panic_reset as _; 13use panic_reset as _;
13 14
15#[cfg(feature = "skip-include")]
16static APP_B: &[u8] = &[0, 1, 2, 3];
17#[cfg(not(feature = "skip-include"))]
14static APP_B: &[u8] = include_bytes!("../../b.bin"); 18static APP_B: &[u8] = include_bytes!("../../b.bin");
15 19
16#[embassy_executor::main] 20#[embassy_executor::main]
17async fn main(_spawner: Spawner) { 21async fn main(_spawner: Spawner) {
18 let p = embassy_nrf::init(Default::default()); 22 let p = embassy_nrf::init(Default::default());
23
19 let mut button = Input::new(p.P0_11, Pull::Up); 24 let mut button = Input::new(p.P0_11, Pull::Up);
20 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); 25 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
26
21 //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); 27 //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard);
22 //let mut button = Input::new(p.P1_02, Pull::Up); 28 //let mut button = Input::new(p.P1_02, Pull::Up);
23 29
30 // nRF91 DK
31 // let mut led = Output::new(p.P0_02, Level::Low, OutputDrive::Standard);
32 // let mut button = Input::new(p.P0_06, Pull::Up);
33
34 // The following code block illustrates how to obtain a watchdog that is configured
35 // as per the existing watchdog. Ordinarily, we'd use the handle returned to "pet" the
36 // watchdog periodically. If we don't, and we're not going to for this example, then
37 // the watchdog will cause the device to reset as per its configured timeout in the bootloader.
38 // This helps is avoid a situation where new firmware might be bad and block our executor.
39 // If firmware is bad in this way then the bootloader will revert to any previous version.
40 let wdt_config = wdt::Config::try_new(&p.WDT).unwrap();
41 let (_wdt, [_wdt_handle]) = match Watchdog::try_new(p.WDT, wdt_config) {
42 Ok(x) => x,
43 Err(_) => {
44 // Watchdog already active with the wrong number of handles, waiting for it to timeout...
45 loop {
46 cortex_m::asm::wfe();
47 }
48 }
49 };
50
24 let nvmc = Nvmc::new(p.NVMC); 51 let nvmc = Nvmc::new(p.NVMC);
25 let mut nvmc = BlockingAsync::new(nvmc); 52 let nvmc = Mutex::new(BlockingAsync::new(nvmc));
26 53
27 let mut updater = FirmwareUpdater::default(); 54 let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc);
55 let mut updater = FirmwareUpdater::new(config);
28 loop { 56 loop {
29 led.set_low(); 57 led.set_low();
30 button.wait_for_any_edge().await; 58 button.wait_for_any_edge().await;
31 if button.is_low() { 59 if button.is_low() {
32 let mut offset = 0; 60 let mut offset = 0;
61 let mut magic = [0; 4];
33 for chunk in APP_B.chunks(4096) { 62 for chunk in APP_B.chunks(4096) {
34 let mut buf: [u8; 4096] = [0; 4096]; 63 let mut buf: [u8; 4096] = [0; 4096];
35 buf[..chunk.len()].copy_from_slice(chunk); 64 buf[..chunk.len()].copy_from_slice(chunk);
36 updater.write_firmware(offset, &buf, &mut nvmc, 4096).await.unwrap(); 65 updater.write_firmware(&mut magic, offset, &buf).await.unwrap();
37 offset += chunk.len(); 66 offset += chunk.len();
38 } 67 }
39 updater.update(&mut nvmc).await.unwrap(); 68 updater.mark_updated(&mut magic).await.unwrap();
40 led.set_high(); 69 led.set_high();
41 cortex_m::peripheral::SCB::sys_reset(); 70 cortex_m::peripheral::SCB::sys_reset();
42 } 71 }
diff --git a/examples/boot/application/nrf/src/bin/b.rs b/examples/boot/application/nrf/src/bin/b.rs
index 5394bf0c7..15ebce5fa 100644
--- a/examples/boot/application/nrf/src/bin/b.rs
+++ b/examples/boot/application/nrf/src/bin/b.rs
@@ -1,7 +1,6 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![macro_use] 3#![macro_use]
4#![feature(generic_associated_types)]
5#![feature(type_alias_impl_trait)] 4#![feature(type_alias_impl_trait)]
6 5
7use embassy_executor::Spawner; 6use embassy_executor::Spawner;
@@ -13,7 +12,10 @@ use panic_reset as _;
13async fn main(_spawner: Spawner) { 12async fn main(_spawner: Spawner) {
14 let p = embassy_nrf::init(Default::default()); 13 let p = embassy_nrf::init(Default::default());
15 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);
16 //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);
17 19
18 loop { 20 loop {
19 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..cd8d1ef02
--- /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-rs 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..95b2da954
--- /dev/null
+++ b/examples/boot/application/rp/Cargo.toml
@@ -0,0 +1,35 @@
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.2.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.1.2", 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", features = ["nightly"] }
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 = ["inline-asm", "critical-section-single-core"] }
22cortex-m-rt = "0.7.0"
23embedded-storage = "0.3.0"
24
25[features]
26default = ["panic-reset"]
27debug = [
28 "embassy-rp/defmt",
29 "embassy-boot-rp/defmt",
30 "panic-probe"
31]
32skip-include = []
33
34[profile.release]
35debug = 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..c8497494c
--- /dev/null
+++ b/examples/boot/application/rp/src/bin/a.rs
@@ -0,0 +1,67 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::cell::RefCell;
6
7use defmt_rtt as _;
8use embassy_boot_rp::*;
9use embassy_executor::Spawner;
10use embassy_rp::flash::Flash;
11use embassy_rp::gpio::{Level, Output};
12use embassy_rp::watchdog::Watchdog;
13use embassy_sync::blocking_mutex::Mutex;
14use embassy_time::{Duration, Timer};
15use embedded_storage::nor_flash::NorFlash;
16#[cfg(feature = "panic-probe")]
17use panic_probe as _;
18#[cfg(feature = "panic-reset")]
19use panic_reset as _;
20
21#[cfg(feature = "skip-include")]
22static APP_B: &[u8] = &[0, 1, 2, 3];
23#[cfg(not(feature = "skip-include"))]
24static APP_B: &[u8] = include_bytes!("../../b.bin");
25
26const FLASH_SIZE: usize = 2 * 1024 * 1024;
27
28#[embassy_executor::main]
29async fn main(_s: Spawner) {
30 let p = embassy_rp::init(Default::default());
31 let mut led = Output::new(p.PIN_25, Level::Low);
32
33 // Override bootloader watchdog
34 let mut watchdog = Watchdog::new(p.WATCHDOG);
35 watchdog.start(Duration::from_secs(8));
36
37 let flash: Flash<_, FLASH_SIZE> = Flash::new(p.FLASH);
38 let flash = Mutex::new(RefCell::new(flash));
39
40 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash);
41 let mut updater = BlockingFirmwareUpdater::new(config);
42
43 Timer::after(Duration::from_secs(5)).await;
44 watchdog.feed();
45 led.set_high();
46 let mut offset = 0;
47 let mut buf: AlignedBuffer<4096> = AlignedBuffer([0; 4096]);
48 defmt::info!("preparing update");
49 let writer = updater
50 .prepare_update(&mut buf.0[..1])
51 .map_err(|e| defmt::warn!("E: {:?}", defmt::Debug2Format(&e)))
52 .unwrap();
53 defmt::info!("writer created, starting write");
54 for chunk in APP_B.chunks(4096) {
55 buf.0[..chunk.len()].copy_from_slice(chunk);
56 defmt::info!("writing block at offset {}", offset);
57 writer.write(offset, &buf.0[..]).unwrap();
58 offset += chunk.len() as u32;
59 }
60 watchdog.feed();
61 defmt::info!("firmware written, marking update");
62 updater.mark_updated(&mut buf.0[..1]).unwrap();
63 Timer::after(Duration::from_secs(2)).await;
64 led.set_low();
65 defmt::info!("update marked, resetting");
66 cortex_m::peripheral::SCB::sys_reset();
67}
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/config.toml b/examples/boot/application/stm32f3/.cargo/config.toml
index a76d6cab4..4a7ec0a5b 100644
--- a/examples/boot/application/stm32f3/.cargo/config.toml
+++ b/examples/boot/application/stm32f3/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-run --list-chips` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32F303VCTx" 3runner = "probe-rs run --chip STM32F303VCTx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml
index f143d1e8d..3b0fc4d9d 100644
--- a/examples/boot/application/stm32f3/Cargo.toml
+++ b/examples/boot/application/stm32f3/Cargo.toml
@@ -2,21 +2,22 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-boot-stm32f3-examples" 3name = "embassy-boot-stm32f3-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
10embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f303re", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f303re", "time-driver-any", "exti"] }
11embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
12embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
13 14
14defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
15defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
16panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
17embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
18 19
19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 21cortex-m-rt = "0.7.0"
21 22
22[features] 23[features]
@@ -25,3 +26,4 @@ defmt = [
25 "embassy-stm32/defmt", 26 "embassy-stm32/defmt",
26 "embassy-boot-stm32/defmt", 27 "embassy-boot-stm32/defmt",
27] 28]
29skip-include = []
diff --git a/examples/boot/application/stm32f3/src/bin/a.rs b/examples/boot/application/stm32f3/src/bin/a.rs
index 11eecc5e2..c0a11d699 100644
--- a/examples/boot/application/stm32f3/src/bin/a.rs
+++ b/examples/boot/application/stm32f3/src/bin/a.rs
@@ -4,21 +4,25 @@
4 4
5#[cfg(feature = "defmt-rtt")] 5#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 6use defmt_rtt::*;
7use embassy_boot_stm32::FirmwareUpdater; 7use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
8use embassy_embedded_hal::adapter::BlockingAsync; 8use embassy_embedded_hal::adapter::BlockingAsync;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::exti::ExtiInput; 10use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::flash::Flash; 11use embassy_stm32::flash::{Flash, WRITE_SIZE};
12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
13use embassy_sync::mutex::Mutex;
13use panic_reset as _; 14use panic_reset as _;
14 15
16#[cfg(feature = "skip-include")]
17static APP_B: &[u8] = &[0, 1, 2, 3];
18#[cfg(not(feature = "skip-include"))]
15static APP_B: &[u8] = include_bytes!("../../b.bin"); 19static APP_B: &[u8] = include_bytes!("../../b.bin");
16 20
17#[embassy_executor::main] 21#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
19 let p = embassy_stm32::init(Default::default()); 23 let p = embassy_stm32::init(Default::default());
20 let flash = Flash::unlock(p.FLASH); 24 let flash = Flash::new_blocking(p.FLASH);
21 let mut flash = BlockingAsync::new(flash); 25 let flash = Mutex::new(BlockingAsync::new(flash));
22 26
23 let button = Input::new(p.PC13, Pull::Up); 27 let button = Input::new(p.PC13, Pull::Up);
24 let mut button = ExtiInput::new(button, p.EXTI13); 28 let mut button = ExtiInput::new(button, p.EXTI13);
@@ -26,16 +30,18 @@ async fn main(_spawner: Spawner) {
26 let mut led = Output::new(p.PA5, Level::Low, Speed::Low); 30 let mut led = Output::new(p.PA5, Level::Low, Speed::Low);
27 led.set_high(); 31 led.set_high();
28 32
29 let mut updater = FirmwareUpdater::default(); 33 let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
34 let mut updater = FirmwareUpdater::new(config);
30 button.wait_for_falling_edge().await; 35 button.wait_for_falling_edge().await;
31 let mut offset = 0; 36 let mut offset = 0;
37 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
32 for chunk in APP_B.chunks(2048) { 38 for chunk in APP_B.chunks(2048) {
33 let mut buf: [u8; 2048] = [0; 2048]; 39 let mut buf: [u8; 2048] = [0; 2048];
34 buf[..chunk.len()].copy_from_slice(chunk); 40 buf[..chunk.len()].copy_from_slice(chunk);
35 updater.write_firmware(offset, &buf, &mut flash, 2048).await.unwrap(); 41 updater.write_firmware(magic.as_mut(), offset, &buf).await.unwrap();
36 offset += chunk.len(); 42 offset += chunk.len();
37 } 43 }
38 updater.update(&mut flash).await.unwrap(); 44 updater.mark_updated(magic.as_mut()).await.unwrap();
39 led.set_low(); 45 led.set_low();
40 cortex_m::peripheral::SCB::sys_reset(); 46 cortex_m::peripheral::SCB::sys_reset();
41} 47}
diff --git a/examples/boot/application/stm32f7/.cargo/config.toml b/examples/boot/application/stm32f7/.cargo/config.toml
index a90e1ccbb..9088eea6e 100644
--- a/examples/boot/application/stm32f7/.cargo/config.toml
+++ b/examples/boot/application/stm32f7/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-run --list-chips` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32F767ZITx -v" 3runner = "probe-rs run --chip STM32F767ZITx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml
index 29c87eee1..323b4ab2c 100644
--- a/examples/boot/application/stm32f7/Cargo.toml
+++ b/examples/boot/application/stm32f7/Cargo.toml
@@ -2,21 +2,23 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-boot-stm32f7-examples" 3name = "embassy-boot-stm32f7-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
10embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f767zi", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f767zi", "time-driver-any", "exti"] }
11embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
12embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
13 14
14defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
15defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
16panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
17embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19embedded-storage = "0.3.0"
18 20
19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 22cortex-m-rt = "0.7.0"
21 23
22[features] 24[features]
@@ -25,3 +27,4 @@ defmt = [
25 "embassy-stm32/defmt", 27 "embassy-stm32/defmt",
26 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
27] 29]
30skip-include = []
diff --git a/examples/boot/application/stm32f7/src/bin/a.rs b/examples/boot/application/stm32f7/src/bin/a.rs
index a3b66e7c9..dea682a96 100644
--- a/examples/boot/application/stm32f7/src/bin/a.rs
+++ b/examples/boot/application/stm32f7/src/bin/a.rs
@@ -2,23 +2,29 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use core::cell::RefCell;
6
5#[cfg(feature = "defmt-rtt")] 7#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 8use defmt_rtt::*;
7use embassy_boot_stm32::FirmwareUpdater; 9use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig};
8use embassy_embedded_hal::adapter::BlockingAsync;
9use embassy_executor::Spawner; 10use embassy_executor::Spawner;
10use embassy_stm32::exti::ExtiInput; 11use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::flash::Flash; 12use embassy_stm32::flash::{Flash, WRITE_SIZE};
12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 13use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
14use embassy_sync::blocking_mutex::Mutex;
15use embedded_storage::nor_flash::NorFlash;
13use panic_reset as _; 16use panic_reset as _;
14 17
18#[cfg(feature = "skip-include")]
19static APP_B: &[u8] = &[0, 1, 2, 3];
20#[cfg(not(feature = "skip-include"))]
15static APP_B: &[u8] = include_bytes!("../../b.bin"); 21static APP_B: &[u8] = include_bytes!("../../b.bin");
16 22
17#[embassy_executor::main] 23#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 24async fn main(_spawner: Spawner) {
19 let p = embassy_stm32::init(Default::default()); 25 let p = embassy_stm32::init(Default::default());
20 let flash = Flash::unlock(p.FLASH); 26 let flash = Flash::new_blocking(p.FLASH);
21 let mut flash = BlockingAsync::new(flash); 27 let flash = Mutex::new(RefCell::new(flash));
22 28
23 let button = Input::new(p.PC13, Pull::Down); 29 let button = Input::new(p.PC13, Pull::Down);
24 let mut button = ExtiInput::new(button, p.EXTI13); 30 let mut button = ExtiInput::new(button, p.EXTI13);
@@ -26,16 +32,19 @@ async fn main(_spawner: Spawner) {
26 let mut led = Output::new(p.PB7, Level::Low, Speed::Low); 32 let mut led = Output::new(p.PB7, Level::Low, Speed::Low);
27 led.set_high(); 33 led.set_high();
28 34
29 let mut updater = FirmwareUpdater::default(); 35 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash);
36 let mut updater = BlockingFirmwareUpdater::new(config);
37 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
38 let writer = updater.prepare_update(magic.as_mut()).unwrap();
30 button.wait_for_rising_edge().await; 39 button.wait_for_rising_edge().await;
31 let mut offset = 0; 40 let mut offset = 0;
32 let mut buf: [u8; 256 * 1024] = [0; 256 * 1024]; 41 let mut buf = AlignedBuffer([0; 4096]);
33 for chunk in APP_B.chunks(256 * 1024) { 42 for chunk in APP_B.chunks(4096) {
34 buf[..chunk.len()].copy_from_slice(chunk); 43 buf.as_mut()[..chunk.len()].copy_from_slice(chunk);
35 updater.write_firmware(offset, &buf, &mut flash, 2048).await.unwrap(); 44 writer.write(offset, buf.as_ref()).unwrap();
36 offset += chunk.len(); 45 offset += chunk.len() as u32;
37 } 46 }
38 updater.update(&mut flash).await.unwrap(); 47 updater.mark_updated(magic.as_mut()).unwrap();
39 led.set_low(); 48 led.set_low();
40 cortex_m::peripheral::SCB::sys_reset(); 49 cortex_m::peripheral::SCB::sys_reset();
41} 50}
diff --git a/examples/boot/application/stm32h7/.cargo/config.toml b/examples/boot/application/stm32h7/.cargo/config.toml
index fefdd370e..caa0d3a93 100644
--- a/examples/boot/application/stm32h7/.cargo/config.toml
+++ b/examples/boot/application/stm32h7/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-run --list-chips` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32H743ZITx" 3runner = "probe-rs run --chip STM32H743ZITx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml
index 5669527fe..b2abdc891 100644
--- a/examples/boot/application/stm32h7/Cargo.toml
+++ b/examples/boot/application/stm32h7/Cargo.toml
@@ -2,21 +2,23 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-boot-stm32h7-examples" 3name = "embassy-boot-stm32h7-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync" }
8embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
10embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32h743zi", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32h743zi", "time-driver-any", "exti"] }
11embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
12embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
13 14
14defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
15defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
16panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
17embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
19embedded-storage = "0.3.0"
18 20
19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 22cortex-m-rt = "0.7.0"
21 23
22[features] 24[features]
@@ -25,3 +27,4 @@ defmt = [
25 "embassy-stm32/defmt", 27 "embassy-stm32/defmt",
26 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
27] 29]
30skip-include = []
diff --git a/examples/boot/application/stm32h7/flash-boot.sh b/examples/boot/application/stm32h7/flash-boot.sh
index debdb17a7..4912a50b7 100755
--- a/examples/boot/application/stm32h7/flash-boot.sh
+++ b/examples/boot/application/stm32h7/flash-boot.sh
@@ -1,8 +1,9 @@
1#!/bin/bash 1#!/bin/bash
2probe-rs erase --chip STM32H743ZITx
2mv ../../bootloader/stm32/memory.x ../../bootloader/stm32/memory-old.x 3mv ../../bootloader/stm32/memory.x ../../bootloader/stm32/memory-old.x
3cp memory-bl.x ../../bootloader/stm32/memory.x 4cp memory-bl.x ../../bootloader/stm32/memory.x
4 5
5cargo flash --manifest-path ../../bootloader/stm32/Cargo.toml --release --features embassy-stm32/stm32f767zi --chip STM32F767ZITx --target thumbv7em-none-eabihf 6cargo flash --manifest-path ../../bootloader/stm32/Cargo.toml --release --features embassy-stm32/stm32h743zi --chip STM32H743ZITx --target thumbv7em-none-eabihf
6 7
7rm ../../bootloader/stm32/memory.x 8rm ../../bootloader/stm32/memory.x
8mv ../../bootloader/stm32/memory-old.x ../../bootloader/stm32/memory.x 9mv ../../bootloader/stm32/memory-old.x ../../bootloader/stm32/memory.x
diff --git a/examples/boot/application/stm32h7/src/bin/a.rs b/examples/boot/application/stm32h7/src/bin/a.rs
index 0ecf60348..719176692 100644
--- a/examples/boot/application/stm32h7/src/bin/a.rs
+++ b/examples/boot/application/stm32h7/src/bin/a.rs
@@ -2,23 +2,29 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use core::cell::RefCell;
6
5#[cfg(feature = "defmt-rtt")] 7#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 8use defmt_rtt::*;
7use embassy_boot_stm32::FirmwareUpdater; 9use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig};
8use embassy_embedded_hal::adapter::BlockingAsync;
9use embassy_executor::Spawner; 10use embassy_executor::Spawner;
10use embassy_stm32::exti::ExtiInput; 11use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::flash::Flash; 12use embassy_stm32::flash::{Flash, WRITE_SIZE};
12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 13use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
14use embassy_sync::blocking_mutex::Mutex;
15use embedded_storage::nor_flash::NorFlash;
13use panic_reset as _; 16use panic_reset as _;
14 17
18#[cfg(feature = "skip-include")]
19static APP_B: &[u8] = &[0, 1, 2, 3];
20#[cfg(not(feature = "skip-include"))]
15static APP_B: &[u8] = include_bytes!("../../b.bin"); 21static APP_B: &[u8] = include_bytes!("../../b.bin");
16 22
17#[embassy_executor::main] 23#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 24async fn main(_spawner: Spawner) {
19 let p = embassy_stm32::init(Default::default()); 25 let p = embassy_stm32::init(Default::default());
20 let flash = Flash::unlock(p.FLASH); 26 let flash = Flash::new_blocking(p.FLASH);
21 let mut flash = BlockingAsync::new(flash); 27 let flash = Mutex::new(RefCell::new(flash));
22 28
23 let button = Input::new(p.PC13, Pull::Down); 29 let button = Input::new(p.PC13, Pull::Down);
24 let mut button = ExtiInput::new(button, p.EXTI13); 30 let mut button = ExtiInput::new(button, p.EXTI13);
@@ -26,16 +32,19 @@ async fn main(_spawner: Spawner) {
26 let mut led = Output::new(p.PB14, Level::Low, Speed::Low); 32 let mut led = Output::new(p.PB14, Level::Low, Speed::Low);
27 led.set_high(); 33 led.set_high();
28 34
29 let mut updater = FirmwareUpdater::default(); 35 let config = FirmwareUpdaterConfig::from_linkerfile_blocking(&flash);
36 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
37 let mut updater = BlockingFirmwareUpdater::new(config);
38 let writer = updater.prepare_update(magic.as_mut()).unwrap();
30 button.wait_for_rising_edge().await; 39 button.wait_for_rising_edge().await;
31 let mut offset = 0; 40 let mut offset = 0;
32 let mut buf: [u8; 128 * 1024] = [0; 128 * 1024]; 41 let mut buf = AlignedBuffer([0; 4096]);
33 for chunk in APP_B.chunks(128 * 1024) { 42 for chunk in APP_B.chunks(4096) {
34 buf[..chunk.len()].copy_from_slice(chunk); 43 buf.as_mut()[..chunk.len()].copy_from_slice(chunk);
35 updater.write_firmware(offset, &buf, &mut flash, 2048).await.unwrap(); 44 writer.write(offset, buf.as_ref()).unwrap();
36 offset += chunk.len(); 45 offset += chunk.len() as u32;
37 } 46 }
38 updater.update(&mut flash).await.unwrap(); 47 updater.mark_updated(magic.as_mut()).unwrap();
39 led.set_low(); 48 led.set_low();
40 cortex_m::peripheral::SCB::sys_reset(); 49 cortex_m::peripheral::SCB::sys_reset();
41} 50}
diff --git a/examples/boot/application/stm32l0/.cargo/config.toml b/examples/boot/application/stm32l0/.cargo/config.toml
index 2627967ab..6099f015c 100644
--- a/examples/boot/application/stm32l0/.cargo/config.toml
+++ b/examples/boot/application/stm32l0/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-run --list-chips` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32L072CZTx" 3runner = "probe-rs run --chip STM32L072CZTx"
4 4
5[build] 5[build]
6target = "thumbv6m-none-eabi" 6target = "thumbv6m-none-eabi"
diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml
index 48624d5ec..0b7e72d5e 100644
--- a/examples/boot/application/stm32l0/Cargo.toml
+++ b/examples/boot/application/stm32l0/Cargo.toml
@@ -2,21 +2,22 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-boot-stm32l0-examples" 3name = "embassy-boot-stm32l0-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
10embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l072cz", "time-driver-any", "exti", "memory-x"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l072cz", "time-driver-any", "exti", "memory-x"] }
11embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
12embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
13 14
14defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
15defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
16panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
17embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
18 19
19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 21cortex-m-rt = "0.7.0"
21 22
22[features] 23[features]
@@ -25,3 +26,4 @@ defmt = [
25 "embassy-stm32/defmt", 26 "embassy-stm32/defmt",
26 "embassy-boot-stm32/defmt", 27 "embassy-boot-stm32/defmt",
27] 28]
29skip-include = []
diff --git a/examples/boot/application/stm32l0/src/bin/a.rs b/examples/boot/application/stm32l0/src/bin/a.rs
index f4f1d7119..ce80056e6 100644
--- a/examples/boot/application/stm32l0/src/bin/a.rs
+++ b/examples/boot/application/stm32l0/src/bin/a.rs
@@ -4,22 +4,26 @@
4 4
5#[cfg(feature = "defmt-rtt")] 5#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 6use defmt_rtt::*;
7use embassy_boot_stm32::FirmwareUpdater; 7use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
8use embassy_embedded_hal::adapter::BlockingAsync; 8use embassy_embedded_hal::adapter::BlockingAsync;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::exti::ExtiInput; 10use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::flash::Flash; 11use embassy_stm32::flash::{Flash, WRITE_SIZE};
12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
13use embassy_sync::mutex::Mutex;
13use embassy_time::{Duration, Timer}; 14use embassy_time::{Duration, Timer};
14use panic_reset as _; 15use panic_reset as _;
15 16
17#[cfg(feature = "skip-include")]
18static APP_B: &[u8] = &[0, 1, 2, 3];
19#[cfg(not(feature = "skip-include"))]
16static APP_B: &[u8] = include_bytes!("../../b.bin"); 20static APP_B: &[u8] = include_bytes!("../../b.bin");
17 21
18#[embassy_executor::main] 22#[embassy_executor::main]
19async fn main(_spawner: Spawner) { 23async fn main(_spawner: Spawner) {
20 let p = embassy_stm32::init(Default::default()); 24 let p = embassy_stm32::init(Default::default());
21 let flash = Flash::unlock(p.FLASH); 25 let flash = Flash::new_blocking(p.FLASH);
22 let mut flash = BlockingAsync::new(flash); 26 let flash = Mutex::new(BlockingAsync::new(flash));
23 27
24 let button = Input::new(p.PB2, Pull::Up); 28 let button = Input::new(p.PB2, Pull::Up);
25 let mut button = ExtiInput::new(button, p.EXTI2); 29 let mut button = ExtiInput::new(button, p.EXTI2);
@@ -28,17 +32,19 @@ async fn main(_spawner: Spawner) {
28 32
29 led.set_high(); 33 led.set_high();
30 34
31 let mut updater = FirmwareUpdater::default(); 35 let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
36 let mut updater = FirmwareUpdater::new(config);
32 button.wait_for_falling_edge().await; 37 button.wait_for_falling_edge().await;
33 let mut offset = 0; 38 let mut offset = 0;
39 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
34 for chunk in APP_B.chunks(128) { 40 for chunk in APP_B.chunks(128) {
35 let mut buf: [u8; 128] = [0; 128]; 41 let mut buf: [u8; 128] = [0; 128];
36 buf[..chunk.len()].copy_from_slice(chunk); 42 buf[..chunk.len()].copy_from_slice(chunk);
37 updater.write_firmware(offset, &buf, &mut flash, 128).await.unwrap(); 43 updater.write_firmware(magic.as_mut(), offset, &buf).await.unwrap();
38 offset += chunk.len(); 44 offset += chunk.len();
39 } 45 }
40 46
41 updater.update(&mut flash).await.unwrap(); 47 updater.mark_updated(magic.as_mut()).await.unwrap();
42 led.set_low(); 48 led.set_low();
43 Timer::after(Duration::from_secs(1)).await; 49 Timer::after(Duration::from_secs(1)).await;
44 cortex_m::peripheral::SCB::sys_reset(); 50 cortex_m::peripheral::SCB::sys_reset();
diff --git a/examples/boot/application/stm32l1/.cargo/config.toml b/examples/boot/application/stm32l1/.cargo/config.toml
index 404b6b55c..9cabd14ba 100644
--- a/examples/boot/application/stm32l1/.cargo/config.toml
+++ b/examples/boot/application/stm32l1/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-run --list-chips` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32L151CBxxA" 3runner = "probe-rs run --chip STM32L151CBxxA"
4 4
5[build] 5[build]
6target = "thumbv7m-none-eabi" 6target = "thumbv7m-none-eabi"
diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml
index 00b638ca5..5f3f365c1 100644
--- a/examples/boot/application/stm32l1/Cargo.toml
+++ b/examples/boot/application/stm32l1/Cargo.toml
@@ -2,21 +2,22 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-boot-stm32l1-examples" 3name = "embassy-boot-stm32l1-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
10embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l151cb-a", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l151cb-a", "time-driver-any", "exti"] }
11embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
12embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
13 14
14defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
15defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
16panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
17embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
18 19
19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 21cortex-m-rt = "0.7.0"
21 22
22[features] 23[features]
@@ -25,3 +26,4 @@ defmt = [
25 "embassy-stm32/defmt", 26 "embassy-stm32/defmt",
26 "embassy-boot-stm32/defmt", 27 "embassy-boot-stm32/defmt",
27] 28]
29skip-include = []
diff --git a/examples/boot/application/stm32l1/src/bin/a.rs b/examples/boot/application/stm32l1/src/bin/a.rs
index f4f1d7119..1e9bf3cb9 100644
--- a/examples/boot/application/stm32l1/src/bin/a.rs
+++ b/examples/boot/application/stm32l1/src/bin/a.rs
@@ -4,22 +4,26 @@
4 4
5#[cfg(feature = "defmt-rtt")] 5#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 6use defmt_rtt::*;
7use embassy_boot_stm32::FirmwareUpdater; 7use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
8use embassy_embedded_hal::adapter::BlockingAsync; 8use embassy_embedded_hal::adapter::BlockingAsync;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::exti::ExtiInput; 10use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::flash::Flash; 11use embassy_stm32::flash::{Flash, WRITE_SIZE};
12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
13use embassy_sync::mutex::Mutex;
13use embassy_time::{Duration, Timer}; 14use embassy_time::{Duration, Timer};
14use panic_reset as _; 15use panic_reset as _;
15 16
17#[cfg(feature = "skip-include")]
18static APP_B: &[u8] = &[0, 1, 2, 3];
19#[cfg(not(feature = "skip-include"))]
16static APP_B: &[u8] = include_bytes!("../../b.bin"); 20static APP_B: &[u8] = include_bytes!("../../b.bin");
17 21
18#[embassy_executor::main] 22#[embassy_executor::main]
19async fn main(_spawner: Spawner) { 23async fn main(_spawner: Spawner) {
20 let p = embassy_stm32::init(Default::default()); 24 let p = embassy_stm32::init(Default::default());
21 let flash = Flash::unlock(p.FLASH); 25 let flash = Flash::new_blocking(p.FLASH);
22 let mut flash = BlockingAsync::new(flash); 26 let flash = Mutex::new(BlockingAsync::new(flash));
23 27
24 let button = Input::new(p.PB2, Pull::Up); 28 let button = Input::new(p.PB2, Pull::Up);
25 let mut button = ExtiInput::new(button, p.EXTI2); 29 let mut button = ExtiInput::new(button, p.EXTI2);
@@ -28,17 +32,19 @@ async fn main(_spawner: Spawner) {
28 32
29 led.set_high(); 33 led.set_high();
30 34
31 let mut updater = FirmwareUpdater::default(); 35 let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
36 let mut updater = FirmwareUpdater::new(config);
32 button.wait_for_falling_edge().await; 37 button.wait_for_falling_edge().await;
38 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
33 let mut offset = 0; 39 let mut offset = 0;
34 for chunk in APP_B.chunks(128) { 40 for chunk in APP_B.chunks(128) {
35 let mut buf: [u8; 128] = [0; 128]; 41 let mut buf: [u8; 128] = [0; 128];
36 buf[..chunk.len()].copy_from_slice(chunk); 42 buf[..chunk.len()].copy_from_slice(chunk);
37 updater.write_firmware(offset, &buf, &mut flash, 128).await.unwrap(); 43 updater.write_firmware(magic.as_mut(), offset, &buf).await.unwrap();
38 offset += chunk.len(); 44 offset += chunk.len();
39 } 45 }
40 46
41 updater.update(&mut flash).await.unwrap(); 47 updater.mark_updated(magic.as_mut()).await.unwrap();
42 led.set_low(); 48 led.set_low();
43 Timer::after(Duration::from_secs(1)).await; 49 Timer::after(Duration::from_secs(1)).await;
44 cortex_m::peripheral::SCB::sys_reset(); 50 cortex_m::peripheral::SCB::sys_reset();
diff --git a/examples/boot/application/stm32l4/.cargo/config.toml b/examples/boot/application/stm32l4/.cargo/config.toml
index 43520e323..c803215f6 100644
--- a/examples/boot/application/stm32l4/.cargo/config.toml
+++ b/examples/boot/application/stm32l4/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-run --list-chips` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32L475VG" 3runner = "probe-rs run --chip STM32L475VG"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml
index 51ba730d5..44eb5aba8 100644
--- a/examples/boot/application/stm32l4/Cargo.toml
+++ b/examples/boot/application/stm32l4/Cargo.toml
@@ -2,21 +2,22 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-boot-stm32l4-examples" 3name = "embassy-boot-stm32l4-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
10embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l475vg", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l475vg", "time-driver-any", "exti"] }
11embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
12embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
13 14
14defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
15defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
16panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
17embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
18 19
19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 21cortex-m-rt = "0.7.0"
21 22
22[features] 23[features]
@@ -25,3 +26,4 @@ defmt = [
25 "embassy-stm32/defmt", 26 "embassy-stm32/defmt",
26 "embassy-boot-stm32/defmt", 27 "embassy-boot-stm32/defmt",
27] 28]
29skip-include = []
diff --git a/examples/boot/application/stm32l4/src/bin/a.rs b/examples/boot/application/stm32l4/src/bin/a.rs
index 178b2e04a..a514ab5be 100644
--- a/examples/boot/application/stm32l4/src/bin/a.rs
+++ b/examples/boot/application/stm32l4/src/bin/a.rs
@@ -4,21 +4,25 @@
4 4
5#[cfg(feature = "defmt-rtt")] 5#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 6use defmt_rtt::*;
7use embassy_boot_stm32::FirmwareUpdater; 7use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
8use embassy_embedded_hal::adapter::BlockingAsync; 8use embassy_embedded_hal::adapter::BlockingAsync;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::exti::ExtiInput; 10use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::flash::Flash; 11use embassy_stm32::flash::{Flash, WRITE_SIZE};
12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
13use embassy_sync::mutex::Mutex;
13use panic_reset as _; 14use panic_reset as _;
14 15
16#[cfg(feature = "skip-include")]
17static APP_B: &[u8] = &[0, 1, 2, 3];
18#[cfg(not(feature = "skip-include"))]
15static APP_B: &[u8] = include_bytes!("../../b.bin"); 19static APP_B: &[u8] = include_bytes!("../../b.bin");
16 20
17#[embassy_executor::main] 21#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
19 let p = embassy_stm32::init(Default::default()); 23 let p = embassy_stm32::init(Default::default());
20 let flash = Flash::unlock(p.FLASH); 24 let flash = Flash::new_blocking(p.FLASH);
21 let mut flash = BlockingAsync::new(flash); 25 let flash = Mutex::new(BlockingAsync::new(flash));
22 26
23 let button = Input::new(p.PC13, Pull::Up); 27 let button = Input::new(p.PC13, Pull::Up);
24 let mut button = ExtiInput::new(button, p.EXTI13); 28 let mut button = ExtiInput::new(button, p.EXTI13);
@@ -26,16 +30,18 @@ async fn main(_spawner: Spawner) {
26 let mut led = Output::new(p.PB14, Level::Low, Speed::Low); 30 let mut led = Output::new(p.PB14, Level::Low, Speed::Low);
27 led.set_high(); 31 led.set_high();
28 32
29 let mut updater = FirmwareUpdater::default(); 33 let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
34 let mut updater = FirmwareUpdater::new(config);
30 button.wait_for_falling_edge().await; 35 button.wait_for_falling_edge().await;
36 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
31 let mut offset = 0; 37 let mut offset = 0;
32 for chunk in APP_B.chunks(2048) { 38 for chunk in APP_B.chunks(2048) {
33 let mut buf: [u8; 2048] = [0; 2048]; 39 let mut buf: [u8; 2048] = [0; 2048];
34 buf[..chunk.len()].copy_from_slice(chunk); 40 buf[..chunk.len()].copy_from_slice(chunk);
35 updater.write_firmware(offset, &buf, &mut flash, 2048).await.unwrap(); 41 updater.write_firmware(magic.as_mut(), offset, &buf).await.unwrap();
36 offset += chunk.len(); 42 offset += chunk.len();
37 } 43 }
38 updater.update(&mut flash).await.unwrap(); 44 updater.mark_updated(magic.as_mut()).await.unwrap();
39 led.set_low(); 45 led.set_low();
40 cortex_m::peripheral::SCB::sys_reset(); 46 cortex_m::peripheral::SCB::sys_reset();
41} 47}
diff --git a/examples/boot/application/stm32wl/.cargo/config.toml b/examples/boot/application/stm32wl/.cargo/config.toml
index e395d75b4..4f8094ff2 100644
--- a/examples/boot/application/stm32wl/.cargo/config.toml
+++ b/examples/boot/application/stm32wl/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-run --list-chips` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32WLE5JCIx" 3runner = "probe-rs run --chip STM32WLE5JCIx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml
index 182acf694..fdad55060 100644
--- a/examples/boot/application/stm32wl/Cargo.toml
+++ b/examples/boot/application/stm32wl/Cargo.toml
@@ -2,21 +2,22 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-boot-stm32wl-examples" 3name = "embassy-boot-stm32wl-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../../../embassy-executor", features = ["nightly", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../../../embassy-time", features = ["nightly", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] }
10embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32wl55jc-cm4", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32wl55jc-cm4", "time-driver-any", "exti"] }
11embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } 12embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] }
12embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" }
13 14
14defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
15defmt-rtt = { version = "0.3", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
16panic-reset = { version = "0.1.1" } 17panic-reset = { version = "0.1.1" }
17embedded-hal = { version = "0.2.6" } 18embedded-hal = { version = "0.2.6" }
18 19
19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 20cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 21cortex-m-rt = "0.7.0"
21 22
22[features] 23[features]
@@ -25,3 +26,4 @@ defmt = [
25 "embassy-stm32/defmt", 26 "embassy-stm32/defmt",
26 "embassy-boot-stm32/defmt", 27 "embassy-boot-stm32/defmt",
27] 28]
29skip-include = []
diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs
index c71a42654..52a197a5c 100644
--- a/examples/boot/application/stm32wl/src/bin/a.rs
+++ b/examples/boot/application/stm32wl/src/bin/a.rs
@@ -4,21 +4,25 @@
4 4
5#[cfg(feature = "defmt-rtt")] 5#[cfg(feature = "defmt-rtt")]
6use defmt_rtt::*; 6use defmt_rtt::*;
7use embassy_boot_stm32::FirmwareUpdater; 7use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
8use embassy_embedded_hal::adapter::BlockingAsync; 8use embassy_embedded_hal::adapter::BlockingAsync;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::exti::ExtiInput; 10use embassy_stm32::exti::ExtiInput;
11use embassy_stm32::flash::Flash; 11use embassy_stm32::flash::{Flash, WRITE_SIZE};
12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
13use embassy_sync::mutex::Mutex;
13use panic_reset as _; 14use panic_reset as _;
14 15
16#[cfg(feature = "skip-include")]
17static APP_B: &[u8] = &[0, 1, 2, 3];
18#[cfg(not(feature = "skip-include"))]
15static APP_B: &[u8] = include_bytes!("../../b.bin"); 19static APP_B: &[u8] = include_bytes!("../../b.bin");
16 20
17#[embassy_executor::main] 21#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
19 let p = embassy_stm32::init(Default::default()); 23 let p = embassy_stm32::init(Default::default());
20 let flash = Flash::unlock(p.FLASH); 24 let flash = Flash::new_blocking(p.FLASH);
21 let mut flash = BlockingAsync::new(flash); 25 let flash = Mutex::new(BlockingAsync::new(flash));
22 26
23 let button = Input::new(p.PA0, Pull::Up); 27 let button = Input::new(p.PA0, Pull::Up);
24 let mut button = ExtiInput::new(button, p.EXTI0); 28 let mut button = ExtiInput::new(button, p.EXTI0);
@@ -26,18 +30,20 @@ async fn main(_spawner: Spawner) {
26 let mut led = Output::new(p.PB9, Level::Low, Speed::Low); 30 let mut led = Output::new(p.PB9, Level::Low, Speed::Low);
27 led.set_high(); 31 led.set_high();
28 32
29 let mut updater = FirmwareUpdater::default(); 33 let config = FirmwareUpdaterConfig::from_linkerfile(&flash);
34 let mut updater = FirmwareUpdater::new(config);
30 button.wait_for_falling_edge().await; 35 button.wait_for_falling_edge().await;
31 //defmt::info!("Starting update"); 36 //defmt::info!("Starting update");
37 let mut magic = AlignedBuffer([0; WRITE_SIZE]);
32 let mut offset = 0; 38 let mut offset = 0;
33 for chunk in APP_B.chunks(2048) { 39 for chunk in APP_B.chunks(2048) {
34 let mut buf: [u8; 2048] = [0; 2048]; 40 let mut buf: [u8; 2048] = [0; 2048];
35 buf[..chunk.len()].copy_from_slice(chunk); 41 buf[..chunk.len()].copy_from_slice(chunk);
36 // defmt::info!("Writing chunk at 0x{:x}", offset); 42 // defmt::info!("Writing chunk at 0x{:x}", offset);
37 updater.write_firmware(offset, &buf, &mut flash, 2048).await.unwrap(); 43 updater.write_firmware(magic.as_mut(), offset, &buf).await.unwrap();
38 offset += chunk.len(); 44 offset += chunk.len();
39 } 45 }
40 updater.update(&mut flash).await.unwrap(); 46 updater.mark_updated(magic.as_mut()).await.unwrap();
41 //defmt::info!("Marked as updated"); 47 //defmt::info!("Marked as updated");
42 led.set_low(); 48 led.set_low();
43 cortex_m::peripheral::SCB::sys_reset(); 49 cortex_m::peripheral::SCB::sys_reset();
diff --git a/examples/boot/bootloader/nrf/.cargo/config.toml b/examples/boot/bootloader/nrf/.cargo/config.toml
index 1060800a3..c292846aa 100644
--- a/examples/boot/bootloader/nrf/.cargo/config.toml
+++ b/examples/boot/bootloader/nrf/.cargo/config.toml
@@ -4,7 +4,7 @@ build-std-features = ["panic_immediate_abort"]
4 4
5[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 5[target.'cfg(all(target_arch = "arm", target_os = "none"))']
6#runner = "./fruitrunner" 6#runner = "./fruitrunner"
7runner = "probe-run --chip nrf52840_xxAA" 7runner = "probe-rs run --chip nrf52840_xxAA"
8 8
9rustflags = [ 9rustflags = [
10 # Code-size optimizations. 10 # Code-size optimizations.
diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml
index aa2a13ecb..40656f359 100644
--- a/examples/boot/bootloader/nrf/Cargo.toml
+++ b/examples/boot/bootloader/nrf/Cargo.toml
@@ -3,14 +3,16 @@ edition = "2021"
3name = "nrf-bootloader-example" 3name = "nrf-bootloader-example"
4version = "0.1.0" 4version = "0.1.0"
5description = "Bootloader for nRF chips" 5description = "Bootloader for nRF chips"
6license = "MIT OR Apache-2.0"
6 7
7[dependencies] 8[dependencies]
8defmt = { version = "0.3", optional = true } 9defmt = { version = "0.3", optional = true }
9defmt-rtt = { version = "0.3", optional = true } 10defmt-rtt = { version = "0.4", optional = true }
10 11
11embassy-nrf = { path = "../../../../embassy-nrf", default-features = false, features = ["nightly"] } 12embassy-nrf = { path = "../../../../embassy-nrf", features = ["nightly"] }
12embassy-boot-nrf = { path = "../../../../embassy-boot/nrf", default-features = false } 13embassy-boot-nrf = { path = "../../../../embassy-boot/nrf" }
13cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
15embassy-sync = { path = "../../../../embassy-sync" }
14cortex-m-rt = { version = "0.7" } 16cortex-m-rt = { version = "0.7" }
15cfg-if = "1.0.0" 17cfg-if = "1.0.0"
16 18
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 bc7e0755f..72c95c02a 100644
--- a/examples/boot/bootloader/nrf/src/main.rs
+++ b/examples/boot/bootloader/nrf/src/main.rs
@@ -1,11 +1,15 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::cell::RefCell;
5
4use cortex_m_rt::{entry, exception}; 6use cortex_m_rt::{entry, exception};
5#[cfg(feature = "defmt")] 7#[cfg(feature = "defmt")]
6use defmt_rtt as _; 8use defmt_rtt as _;
7use embassy_boot_nrf::*; 9use embassy_boot_nrf::*;
8use embassy_nrf::nvmc::Nvmc; 10use embassy_nrf::nvmc::Nvmc;
11use embassy_nrf::wdt;
12use embassy_sync::blocking_mutex::Mutex;
9 13
10#[entry] 14#[entry]
11fn main() -> ! { 15fn main() -> ! {
@@ -19,13 +23,21 @@ fn main() -> ! {
19 } 23 }
20 */ 24 */
21 25
22 let mut bl = BootLoader::default(); 26 let mut wdt_config = wdt::Config::default();
23 let start = bl.prepare(&mut SingleFlashProvider::new(&mut WatchdogFlash::start( 27 wdt_config.timeout_ticks = 32768 * 5; // timeout seconds
24 Nvmc::new(p.NVMC), 28 wdt_config.run_during_sleep = true;
25 p.WDT, 29 wdt_config.run_during_debug_halt = false;
26 5, 30
27 ))); 31 let flash = WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config);
28 unsafe { bl.load(start) } 32 let flash = Mutex::new(RefCell::new(flash));
33
34 let config = BootLoaderConfig::from_linkerfile_blocking(&flash);
35 let active_offset = config.active.offset();
36 let mut bl: BootLoader<_, _, _> = BootLoader::new(config);
37
38 bl.prepare();
39
40 unsafe { bl.load(active_offset) }
29} 41}
30 42
31#[no_mangle] 43#[no_mangle]
diff --git a/examples/boot/bootloader/rp/.cargo/config.toml b/examples/boot/bootloader/rp/.cargo/config.toml
new file mode 100644
index 000000000..9d48ecdc9
--- /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-rs 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..c1dc99eec
--- /dev/null
+++ b/examples/boot/bootloader/rp/Cargo.toml
@@ -0,0 +1,33 @@
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", features = ["nightly"] }
13embassy-boot-rp = { path = "../../../../embassy-boot/rp" }
14embassy-sync = { path = "../../../../embassy-sync" }
15embassy-time = { path = "../../../../embassy-time", features = ["nightly"] }
16
17cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
18cortex-m-rt = { version = "0.7" }
19embedded-storage = "0.3.0"
20embedded-storage-async = "0.4.0"
21cfg-if = "1.0.0"
22
23[features]
24defmt = [
25 "dep:defmt",
26 "embassy-boot-rp/defmt",
27 "embassy-rp/defmt",
28]
29debug = ["defmt-rtt", "defmt"]
30
31[profile.release]
32debug = true
33opt-level = 's'
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..6a81db804
--- /dev/null
+++ b/examples/boot/bootloader/rp/src/main.rs
@@ -0,0 +1,56 @@
1#![no_std]
2#![no_main]
3
4use core::cell::RefCell;
5
6use cortex_m_rt::{entry, exception};
7#[cfg(feature = "defmt")]
8use defmt_rtt as _;
9use embassy_boot_rp::*;
10use embassy_sync::blocking_mutex::Mutex;
11use embassy_time::Duration;
12
13const FLASH_SIZE: usize = 2 * 1024 * 1024;
14
15#[entry]
16fn main() -> ! {
17 let p = embassy_rp::init(Default::default());
18
19 // Uncomment this if you are debugging the bootloader with debugger/RTT attached,
20 // as it prevents a hard fault when accessing flash 'too early' after boot.
21 /*
22 for i in 0..10000000 {
23 cortex_m::asm::nop();
24 }
25 */
26
27 let flash = WatchdogFlash::<FLASH_SIZE>::start(p.FLASH, p.WATCHDOG, Duration::from_secs(8));
28 let flash = Mutex::new(RefCell::new(flash));
29
30 let config = BootLoaderConfig::from_linkerfile_blocking(&flash);
31 let active_offset = config.active.offset();
32 let mut bl: BootLoader<_, _, _> = BootLoader::new(config);
33
34 bl.prepare();
35
36 unsafe { bl.load(embassy_rp::flash::FLASH_BASE as u32 + active_offset) }
37}
38
39#[no_mangle]
40#[cfg_attr(target_os = "none", link_section = ".HardFault.user")]
41unsafe extern "C" fn HardFault() {
42 cortex_m::peripheral::SCB::sys_reset();
43}
44
45#[exception]
46unsafe fn DefaultHandler(_: i16) -> ! {
47 const SCB_ICSR: *const u32 = 0xE000_ED04 as *const u32;
48 let irqn = core::ptr::read_volatile(SCB_ICSR) as u8 as i16 - 16;
49
50 panic!("DefaultHandler #{:?}", irqn);
51}
52
53#[panic_handler]
54fn panic(_info: &core::panic::PanicInfo) -> ! {
55 cortex_m::asm::udf();
56}
diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml
index 491777103..6436f2fee 100644
--- a/examples/boot/bootloader/stm32/Cargo.toml
+++ b/examples/boot/bootloader/stm32/Cargo.toml
@@ -3,17 +3,19 @@ edition = "2021"
3name = "stm32-bootloader-example" 3name = "stm32-bootloader-example"
4version = "0.1.0" 4version = "0.1.0"
5description = "Example bootloader for STM32 chips" 5description = "Example bootloader for STM32 chips"
6license = "MIT OR Apache-2.0"
6 7
7[dependencies] 8[dependencies]
8defmt = { version = "0.3", optional = true } 9defmt = { version = "0.3", optional = true }
9defmt-rtt = { version = "0.3", optional = true } 10defmt-rtt = { version = "0.4", optional = true }
10 11
11embassy-stm32 = { path = "../../../../embassy-stm32", default-features = false, features = ["nightly"] } 12embassy-stm32 = { path = "../../../../embassy-stm32", features = ["nightly"] }
12embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32", default-features = false } 13embassy-boot-stm32 = { path = "../../../../embassy-boot/stm32" }
13cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 14cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
15embassy-sync = { path = "../../../../embassy-sync" }
14cortex-m-rt = { version = "0.7" } 16cortex-m-rt = { version = "0.7" }
15embedded-storage = "0.3.0" 17embedded-storage = "0.3.0"
16embedded-storage-async = "0.3.0" 18embedded-storage-async = "0.4.0"
17cfg-if = "1.0.0" 19cfg-if = "1.0.0"
18 20
19[features] 21[features]
diff --git a/examples/boot/bootloader/stm32/src/main.rs b/examples/boot/bootloader/stm32/src/main.rs
index 45c511ced..262eed200 100644
--- a/examples/boot/bootloader/stm32/src/main.rs
+++ b/examples/boot/bootloader/stm32/src/main.rs
@@ -1,11 +1,14 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::cell::RefCell;
5
4use cortex_m_rt::{entry, exception}; 6use cortex_m_rt::{entry, exception};
5#[cfg(feature = "defmt")] 7#[cfg(feature = "defmt")]
6use defmt_rtt as _; 8use defmt_rtt as _;
7use embassy_boot_stm32::*; 9use embassy_boot_stm32::*;
8use embassy_stm32::flash::{Flash, ERASE_SIZE}; 10use embassy_stm32::flash::{Flash, BANK1_REGION};
11use embassy_sync::blocking_mutex::Mutex;
9 12
10#[entry] 13#[entry]
11fn main() -> ! { 14fn main() -> ! {
@@ -19,11 +22,16 @@ fn main() -> ! {
19 } 22 }
20 */ 23 */
21 24
22 let mut bl: BootLoader<ERASE_SIZE> = BootLoader::default(); 25 let layout = Flash::new_blocking(p.FLASH).into_blocking_regions();
23 let mut flash = Flash::unlock(p.FLASH); 26 let flash = Mutex::new(RefCell::new(layout.bank1_region));
24 let start = bl.prepare(&mut SingleFlashProvider::new(&mut flash)); 27
25 core::mem::drop(flash); 28 let config = BootLoaderConfig::from_linkerfile_blocking(&flash);
26 unsafe { bl.load(start) } 29 let active_offset = config.active.offset();
30 let mut bl: BootLoader<_, _, _, 2048> = BootLoader::new(config);
31
32 bl.prepare();
33
34 unsafe { bl.load(BANK1_REGION.base + active_offset) }
27} 35}
28 36
29#[no_mangle] 37#[no_mangle]
diff --git a/examples/nrf-rtos-trace/.cargo/config.toml b/examples/nrf-rtos-trace/.cargo/config.toml
index 8ca28df39..17616a054 100644
--- a/examples/nrf-rtos-trace/.cargo/config.toml
+++ b/examples/nrf-rtos-trace/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-run --list-chips` 2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip nRF52840_xxAA" 3runner = "probe-rs run --chip nRF52840_xxAA"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml
index 87c9f33f5..30b67b7b2 100644
--- a/examples/nrf-rtos-trace/Cargo.toml
+++ b/examples/nrf-rtos-trace/Cargo.toml
@@ -2,6 +2,7 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-nrf-rtos-trace-examples" 3name = "embassy-nrf-rtos-trace-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[features] 7[features]
7default = ["log", "nightly"] 8default = ["log", "nightly"]
@@ -15,12 +16,12 @@ log = [
15] 16]
16 17
17[dependencies] 18[dependencies]
18embassy-sync = { version = "0.1.0", path = "../../embassy-sync" } 19embassy-sync = { version = "0.2.0", path = "../../embassy-sync" }
19embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features=["rtos-trace", "rtos-trace-interrupt", "integrated-timers"] } 20embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "rtos-trace-interrupt", "integrated-timers"] }
20embassy-time = { version = "0.1.0", path = "../../embassy-time" } 21embassy-time = { version = "0.1.2", path = "../../embassy-time" }
21embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } 22embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
22 23
23cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 24cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
24cortex-m-rt = "0.7.0" 25cortex-m-rt = "0.7.0"
25panic-probe = { version = "0.3" } 26panic-probe = { version = "0.3" }
26futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 27futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
diff --git a/examples/nrf-rtos-trace/src/bin/rtos_trace.rs b/examples/nrf-rtos-trace/src/bin/rtos_trace.rs
index 7d1ad87c8..cf8b2f808 100644
--- a/examples/nrf-rtos-trace/src/bin/rtos_trace.rs
+++ b/examples/nrf-rtos-trace/src/bin/rtos_trace.rs
@@ -2,6 +2,7 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use core::future::poll_fn;
5use core::task::Poll; 6use core::task::Poll;
6 7
7use embassy_executor::Spawner; 8use embassy_executor::Spawner;
@@ -46,7 +47,7 @@ async fn run2() {
46 47
47#[embassy_executor::task] 48#[embassy_executor::task]
48async fn run3() { 49async fn run3() {
49 futures::future::poll_fn(|cx| { 50 poll_fn(|cx| {
50 cx.waker().wake_by_ref(); 51 cx.waker().wake_by_ref();
51 Poll::<()>::Pending 52 Poll::<()>::Pending
52 }) 53 })
diff --git a/examples/nrf/src/bin/awaitable_timer.rs b/examples/nrf/src/bin/awaitable_timer.rs
deleted file mode 100644
index b32af236c..000000000
--- a/examples/nrf/src/bin/awaitable_timer.rs
+++ /dev/null
@@ -1,26 +0,0 @@
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::timer::Timer;
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 let mut t = Timer::new_awaitable(p.TIMER0, interrupt::take!(TIMER0));
15 // default frequency is 1MHz, so this triggers every second
16 t.cc(0).write(1_000_000);
17 // clear the timer value on cc[0] compare match
18 t.cc(0).short_compare_clear();
19 t.start();
20
21 loop {
22 // wait for compare match
23 t.cc(0).wait().await;
24 info!("hardware timer tick");
25 }
26}
diff --git a/examples/nrf/src/bin/pdm.rs b/examples/nrf/src/bin/pdm.rs
deleted file mode 100644
index 605eca59e..000000000
--- a/examples/nrf/src/bin/pdm.rs
+++ /dev/null
@@ -1,46 +0,0 @@
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, Channels, Pdm};
9use embassy_time::{Duration, Timer};
10use fixed::types::I7F1;
11use num_integer::Roots;
12use {defmt_rtt as _, panic_probe as _};
13
14#[embassy_executor::main]
15async fn main(_p: Spawner) {
16 let mut p = embassy_nrf::init(Default::default());
17 let mut config = Config::default();
18 // Pins are correct for the onboard microphone on the Feather nRF52840 Sense.
19 config.channels = Channels::Mono;
20 config.gain_left = I7F1::from_bits(5); // 2.5 dB
21 let mut pdm = Pdm::new(p.PDM, interrupt::take!(PDM), &mut p.P0_00, &mut p.P0_01, config);
22
23 loop {
24 for gain in [I7F1::from_num(-20), I7F1::from_num(0), I7F1::from_num(20)] {
25 pdm.set_gain(gain, gain);
26 info!("Gain = {} dB", defmt::Debug2Format(&gain));
27 for _ in 0..10 {
28 let mut buf = [0; 1500];
29 pdm.sample(5, &mut buf).await;
30 let mean = (buf.iter().map(|v| i32::from(*v)).sum::<i32>() / buf.len() as i32) as i16;
31 info!(
32 "{} samples, min {=i16}, max {=i16}, mean {=i16}, AC RMS {=i16}",
33 buf.len(),
34 buf.iter().min().unwrap(),
35 buf.iter().max().unwrap(),
36 mean,
37 (
38 buf.iter().map(|v| i32::from(*v - mean).pow(2)).fold(0i32, |a,b| a.saturating_add(b))
39 / buf.len() as i32).sqrt() as i16,
40 );
41 info!("samples = {}", &buf);
42 Timer::after(Duration::from_millis(100)).await;
43 }
44 }
45 }
46}
diff --git a/examples/nrf/src/bin/usb_ethernet.rs b/examples/nrf/src/bin/usb_ethernet.rs
deleted file mode 100644
index ca6c7e0d1..000000000
--- a/examples/nrf/src/bin/usb_ethernet.rs
+++ /dev/null
@@ -1,275 +0,0 @@
1#![no_std]
2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)]
5
6use core::mem;
7use core::sync::atomic::{AtomicBool, Ordering};
8use core::task::Waker;
9
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_net::tcp::TcpSocket;
13use embassy_net::{PacketBox, PacketBoxExt, PacketBuf, Stack, StackResources};
14use embassy_nrf::rng::Rng;
15use embassy_nrf::usb::{Driver, PowerUsb};
16use embassy_nrf::{interrupt, pac, peripherals};
17use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
18use embassy_sync::channel::Channel;
19use embassy_usb::{Builder, Config, UsbDevice};
20use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
21use embedded_io::asynch::{Read, Write};
22use static_cell::StaticCell;
23use {defmt_rtt as _, panic_probe as _};
24
25type MyDriver = Driver<'static, peripherals::USBD, PowerUsb>;
26
27macro_rules! singleton {
28 ($val:expr) => {{
29 type T = impl Sized;
30 static STATIC_CELL: StaticCell<T> = StaticCell::new();
31 STATIC_CELL.init_with(move || $val)
32 }};
33}
34
35#[embassy_executor::task]
36async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! {
37 device.run().await
38}
39
40#[embassy_executor::task]
41async fn usb_ncm_rx_task(mut class: Receiver<'static, MyDriver>) {
42 loop {
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}
68
69#[embassy_executor::task]
70async fn usb_ncm_tx_task(mut class: Sender<'static, MyDriver>) {
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
82}
83
84#[embassy_executor::main]
85async fn main(spawner: Spawner) {
86 let p = embassy_nrf::init(Default::default());
87 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
88
89 info!("Enabling ext hfosc...");
90 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
91 while clock.events_hfclkstarted.read().bits() != 1 {}
92
93 // Create the driver, from the HAL.
94 let irq = interrupt::take!(USBD);
95 let power_irq = interrupt::take!(POWER_CLOCK);
96 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq));
97
98 // Create embassy-usb Config
99 let mut config = Config::new(0xc0de, 0xcafe);
100 config.manufacturer = Some("Embassy");
101 config.product = Some("USB-Ethernet example");
102 config.serial_number = Some("12345678");
103 config.max_power = 100;
104 config.max_packet_size_0 = 64;
105
106 // Required for Windows support.
107 config.composite_with_iads = true;
108 config.device_class = 0xEF;
109 config.device_sub_class = 0x02;
110 config.device_protocol = 0x01;
111
112 struct Resources {
113 device_descriptor: [u8; 256],
114 config_descriptor: [u8; 256],
115 bos_descriptor: [u8; 256],
116 control_buf: [u8; 128],
117 serial_state: State<'static>,
118 }
119 let res: &mut Resources = singleton!(Resources {
120 device_descriptor: [0; 256],
121 config_descriptor: [0; 256],
122 bos_descriptor: [0; 256],
123 control_buf: [0; 128],
124 serial_state: State::new(),
125 });
126
127 // Create embassy-usb DeviceBuilder using the driver and config.
128 let mut builder = Builder::new(
129 driver,
130 config,
131 &mut res.device_descriptor,
132 &mut res.config_descriptor,
133 &mut res.bos_descriptor,
134 &mut res.control_buf,
135 None,
136 );
137
138 // WARNINGS for Android ethernet tethering:
139 // - On Pixel 4a, it refused to work on Android 11, worked on Android 12.
140 // - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte),
141 // it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled.
142 // 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
143 // and this nonsense in the linux kernel: https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757
144
145 // Our MAC addr.
146 let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC];
147 // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has.
148 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
149
150 // Create classes on the builder.
151 let class = CdcNcmClass::new(&mut builder, &mut res.serial_state, host_mac_addr, 64);
152
153 // Build the builder.
154 let usb = builder.build();
155
156 unwrap!(spawner.spawn(usb_task(usb)));
157
158 let (tx, rx) = class.split();
159 unwrap!(spawner.spawn(usb_ncm_rx_task(rx)));
160 unwrap!(spawner.spawn(usb_ncm_tx_task(tx)));
161
162 let config = embassy_net::ConfigStrategy::Dhcp;
163 //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config {
164 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
165 // dns_servers: Vec::new(),
166 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
167 //});
168
169 // Generate random seed
170 let mut rng = Rng::new(p.RNG, interrupt::take!(RNG));
171 let mut seed = [0; 8];
172 rng.blocking_fill_bytes(&mut seed);
173 let seed = u64::from_le_bytes(seed);
174
175 // Init network stack
176 let device = Device { mac_addr: our_mac_addr };
177 let stack = &*singleton!(Stack::new(
178 device,
179 config,
180 singleton!(StackResources::<1, 2, 8>::new()),
181 seed
182 ));
183
184 unwrap!(spawner.spawn(net_task(stack)));
185
186 // And now we can use it!
187
188 let mut rx_buffer = [0; 4096];
189 let mut tx_buffer = [0; 4096];
190 let mut buf = [0; 4096];
191
192 loop {
193 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
194 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
195
196 info!("Listening on TCP:1234...");
197 if let Err(e) = socket.accept(1234).await {
198 warn!("accept error: {:?}", e);
199 continue;
200 }
201
202 info!("Received connection from {:?}", socket.remote_endpoint());
203
204 loop {
205 let n = match socket.read(&mut buf).await {
206 Ok(0) => {
207 warn!("read EOF");
208 break;
209 }
210 Ok(n) => n,
211 Err(e) => {
212 warn!("read error: {:?}", e);
213 break;
214 }
215 };
216
217 info!("rxd {:02x}", &buf[..n]);
218
219 match socket.write_all(&buf[..n]).await {
220 Ok(()) => {}
221 Err(e) => {
222 warn!("write error: {:?}", e);
223 break;
224 }
225 };
226 }
227 }
228}
229
230static TX_CHANNEL: Channel<ThreadModeRawMutex, PacketBuf, 8> = Channel::new();
231static RX_CHANNEL: Channel<ThreadModeRawMutex, PacketBuf, 8> = Channel::new();
232static LINK_UP: AtomicBool = AtomicBool::new(false);
233
234struct Device {
235 mac_addr: [u8; 6],
236}
237
238impl embassy_net::Device for Device {
239 fn register_waker(&mut self, waker: &Waker) {
240 // loopy loopy wakey wakey
241 waker.wake_by_ref()
242 }
243
244 fn link_state(&mut self) -> embassy_net::LinkState {
245 match LINK_UP.load(Ordering::Relaxed) {
246 true => embassy_net::LinkState::Up,
247 false => embassy_net::LinkState::Down,
248 }
249 }
250
251 fn capabilities(&self) -> embassy_net::DeviceCapabilities {
252 let mut caps = embassy_net::DeviceCapabilities::default();
253 caps.max_transmission_unit = 1514; // 1500 IP + 14 ethernet header
254 caps.medium = embassy_net::Medium::Ethernet;
255 caps
256 }
257
258 fn is_transmit_ready(&mut self) -> bool {
259 true
260 }
261
262 fn transmit(&mut self, pkt: PacketBuf) {
263 if TX_CHANNEL.try_send(pkt).is_err() {
264 warn!("TX failed")
265 }
266 }
267
268 fn receive<'a>(&mut self) -> Option<PacketBuf> {
269 RX_CHANNEL.try_recv().ok()
270 }
271
272 fn ethernet_address(&self) -> [u8; 6] {
273 self.mac_addr
274 }
275}
diff --git a/examples/nrf/.cargo/config.toml b/examples/nrf52840-rtic/.cargo/config.toml
index 8ca28df39..17616a054 100644
--- a/examples/nrf/.cargo/config.toml
+++ b/examples/nrf52840-rtic/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-run --list-chips` 2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip nRF52840_xxAA" 3runner = "probe-rs run --chip nRF52840_xxAA"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml
new file mode 100644
index 000000000..ded3b7db8
--- /dev/null
+++ b/examples/nrf52840-rtic/Cargo.toml
@@ -0,0 +1,21 @@
1[package]
2edition = "2021"
3name = "embassy-nrf52840-rtic-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8rtic = { version = "2", features = ["thumbv7-backend"] }
9
10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
11embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "generic-queue"] }
13embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nightly", "unstable-traits", "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
14
15defmt = "0.3"
16defmt-rtt = "0.4"
17
18cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
19cortex-m-rt = "0.7.0"
20panic-probe = { version = "0.3", features = ["print-defmt"] }
21futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
diff --git a/examples/nrf52840-rtic/build.rs b/examples/nrf52840-rtic/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/nrf52840-rtic/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-rtic/memory.x
index 9b04edec0..9b04edec0 100644
--- a/examples/nrf/memory.x
+++ b/examples/nrf52840-rtic/memory.x
diff --git a/examples/nrf52840-rtic/src/bin/blinky.rs b/examples/nrf52840-rtic/src/bin/blinky.rs
new file mode 100644
index 000000000..a682c1932
--- /dev/null
+++ b/examples/nrf52840-rtic/src/bin/blinky.rs
@@ -0,0 +1,43 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use {defmt_rtt as _, panic_probe as _};
6
7#[rtic::app(device = embassy_nrf, peripherals = false, dispatchers = [SWI0_EGU0, SWI1_EGU1])]
8mod app {
9 use defmt::info;
10 use embassy_nrf::gpio::{Level, Output, OutputDrive};
11 use embassy_nrf::peripherals;
12 use embassy_time::{Duration, Timer};
13
14 #[shared]
15 struct Shared {}
16
17 #[local]
18 struct Local {}
19
20 #[init]
21 fn init(_: init::Context) -> (Shared, Local) {
22 info!("Hello World!");
23
24 let p = embassy_nrf::init(Default::default());
25 blink::spawn(p.P0_13).map_err(|_| ()).unwrap();
26
27 (Shared {}, Local {})
28 }
29
30 #[task(priority = 1)]
31 async fn blink(_cx: blink::Context, pin: peripherals::P0_13) {
32 let mut led = Output::new(pin, Level::Low, OutputDrive::Standard);
33
34 loop {
35 info!("off!");
36 led.set_high();
37 Timer::after(Duration::from_millis(300)).await;
38 info!("on!");
39 led.set_low();
40 Timer::after(Duration::from_millis(300)).await;
41 }
42 }
43}
diff --git a/examples/nrf52840/.cargo/config.toml b/examples/nrf52840/.cargo/config.toml
new file mode 100644
index 000000000..17616a054
--- /dev/null
+++ b/examples/nrf52840/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip nRF52840_xxAA"
4
5[build]
6target = "thumbv7em-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
new file mode 100644
index 000000000..9b41ec5ab
--- /dev/null
+++ b/examples/nrf52840/Cargo.toml
@@ -0,0 +1,61 @@
1[package]
2edition = "2021"
3name = "embassy-nrf52840-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[features]
8default = ["nightly"]
9nightly = [
10 "embedded-hal-async",
11 "embassy-executor/nightly",
12 "embassy-nrf/nightly",
13 "embassy-net/nightly",
14 "embassy-net-esp-hosted",
15 "embassy-nrf/unstable-traits",
16 "embassy-time/nightly",
17 "embassy-time/unstable-traits",
18 "static_cell/nightly",
19 "embassy-usb",
20 "embedded-io/async",
21 "embassy-net",
22 "embassy-lora",
23 "lora-phy",
24 "lorawan-device",
25 "lorawan",
26]
27
28[dependencies]
29embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
30embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
31embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
32embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
33embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
34embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true }
35embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor",], optional = true }
36embedded-io = "0.4.0"
37embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true }
38lora-phy = { version = "1", optional = true }
39lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true }
40lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true }
41embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"], optional = true }
42
43defmt = "0.3"
44defmt-rtt = "0.4"
45
46fixed = "1.10.0"
47static_cell = "1.1"
48cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
49cortex-m-rt = "0.7.0"
50panic-probe = { version = "0.3", features = ["print-defmt"] }
51futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
52rand = { version = "0.8.4", default-features = false }
53embedded-storage = "0.3.0"
54usbd-hid = "0.6.0"
55serde = { version = "1.0.136", default-features = false }
56embedded-hal-async = { version = "0.2.0-alpha.2", optional = true }
57num-integer = { version = "0.1.45", default-features = false }
58microfft = "0.5.0"
59
60[patch.crates-io]
61lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "ad289428fd44b02788e2fa2116445cc8f640a265" }
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/nrf52840/memory.x b/examples/nrf52840/memory.x
new file mode 100644
index 000000000..9b04edec0
--- /dev/null
+++ b/examples/nrf52840/memory.x
@@ -0,0 +1,7 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 /* These values correspond to the NRF52840 with Softdevices S140 7.0.1 */
5 FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
6 RAM : ORIGIN = 0x20000000, LENGTH = 256K
7}
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..238695371 100644
--- a/examples/nrf/src/bin/buffered_uart.rs
+++ b/examples/nrf52840/src/bin/buffered_uart.rs
@@ -4,12 +4,15 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::buffered_uarte::{BufferedUarte, State}; 7use embassy_nrf::buffered_uarte::{self, BufferedUarte};
8use embassy_nrf::{interrupt, uarte}; 8use embassy_nrf::{bind_interrupts, peripherals, uarte};
9use embedded_io::asynch::{BufRead, Write}; 9use embedded_io::asynch::Write;
10use futures::pin_mut;
11use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
12 11
12bind_interrupts!(struct Irqs {
13 UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
14});
15
13#[embassy_executor::main] 16#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
15 let p = embassy_nrf::init(Default::default()); 18 let p = embassy_nrf::init(Default::default());
@@ -20,25 +23,19 @@ async fn main(_spawner: Spawner) {
20 let mut tx_buffer = [0u8; 4096]; 23 let mut tx_buffer = [0u8; 4096];
21 let mut rx_buffer = [0u8; 4096]; 24 let mut rx_buffer = [0u8; 4096];
22 25
23 let irq = interrupt::take!(UARTE0_UART0); 26 let mut u = BufferedUarte::new(
24 let mut state = State::new();
25 // Please note - important to have hardware flow control (https://github.com/embassy-rs/embassy/issues/536)
26 let u = BufferedUarte::new(
27 &mut state,
28 p.UARTE0, 27 p.UARTE0,
29 p.TIMER0, 28 p.TIMER0,
30 p.PPI_CH0, 29 p.PPI_CH0,
31 p.PPI_CH1, 30 p.PPI_CH1,
32 irq, 31 p.PPI_GROUP0,
32 Irqs,
33 p.P0_08, 33 p.P0_08,
34 p.P0_06, 34 p.P0_06,
35 p.P0_07,
36 p.P0_05,
37 config, 35 config,
38 &mut rx_buffer, 36 &mut rx_buffer,
39 &mut tx_buffer, 37 &mut tx_buffer,
40 ); 38 );
41 pin_mut!(u);
42 39
43 info!("uarte initialized!"); 40 info!("uarte initialized!");
44 41
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 9ae030d07..2a28f2763 100644
--- a/examples/nrf/src/bin/executor_fairness_test.rs
+++ b/examples/nrf52840/src/bin/executor_fairness_test.rs
@@ -2,6 +2,7 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use core::future::poll_fn;
5use core::task::Poll; 6use core::task::Poll;
6 7
7use defmt::{info, unwrap}; 8use defmt::{info, unwrap};
@@ -26,7 +27,7 @@ async fn run2() {
26 27
27#[embassy_executor::task] 28#[embassy_executor::task]
28async fn run3() { 29async fn run3() {
29 futures::future::poll_fn(|cx| { 30 poll_fn(|cx| {
30 cx.waker().wake_by_ref(); 31 cx.waker().wake_by_ref();
31 Poll::<()>::Pending 32 Poll::<()>::Pending
32 }) 33 })
diff --git a/examples/nrf/src/bin/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..391514d93
--- /dev/null
+++ b/examples/nrf52840/src/bin/i2s_effect.rs
@@ -0,0 +1,116 @@
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::{bind_interrupts, peripherals};
11use {defmt_rtt as _, panic_probe as _};
12
13type Sample = i16;
14
15const NUM_BUFFERS: usize = 2;
16const NUM_SAMPLES: usize = 4;
17
18bind_interrupts!(struct Irqs {
19 I2S => i2s::InterruptHandler<peripherals::I2S>;
20});
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
24 let p = embassy_nrf::init(Default::default());
25
26 let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
27
28 let sample_rate = master_clock.sample_rate();
29 info!("Sample rate: {}", sample_rate);
30
31 let mut config = Config::default();
32 config.sample_width = SampleWidth::_16bit;
33 config.channels = Channels::MonoLeft;
34
35 let buffers_out = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
36 let buffers_in = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
37 let mut full_duplex_stream = I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config)
38 .full_duplex(p.P0_29, p.P0_28, buffers_out, buffers_in);
39
40 let mut modulator = SineOsc::new();
41 modulator.set_frequency(8.0, 1.0 / sample_rate as f32);
42 modulator.set_amplitude(1.0);
43
44 full_duplex_stream.start().await.expect("I2S Start");
45
46 loop {
47 let (buff_out, buff_in) = full_duplex_stream.buffers();
48 for i in 0..NUM_SAMPLES {
49 let modulation = (Sample::SCALE as f32 * bipolar_to_unipolar(modulator.generate())) as Sample;
50 buff_out[i] = buff_in[i] * modulation;
51 }
52
53 if let Err(err) = full_duplex_stream.send_and_receive().await {
54 error!("{}", err);
55 }
56 }
57}
58
59struct SineOsc {
60 amplitude: f32,
61 modulo: f32,
62 phase_inc: f32,
63}
64
65impl SineOsc {
66 const B: f32 = 4.0 / PI;
67 const C: f32 = -4.0 / (PI * PI);
68 const P: f32 = 0.225;
69
70 pub fn new() -> Self {
71 Self {
72 amplitude: 1.0,
73 modulo: 0.0,
74 phase_inc: 0.0,
75 }
76 }
77
78 pub fn set_frequency(&mut self, freq: f32, inv_sample_rate: f32) {
79 self.phase_inc = freq * inv_sample_rate;
80 }
81
82 pub fn set_amplitude(&mut self, amplitude: f32) {
83 self.amplitude = amplitude;
84 }
85
86 pub fn generate(&mut self) -> f32 {
87 let signal = self.parabolic_sin(self.modulo);
88 self.modulo += self.phase_inc;
89 if self.modulo < 0.0 {
90 self.modulo += 1.0;
91 } else if self.modulo > 1.0 {
92 self.modulo -= 1.0;
93 }
94 signal * self.amplitude
95 }
96
97 fn parabolic_sin(&mut self, modulo: f32) -> f32 {
98 let angle = PI - modulo * 2.0 * PI;
99 let y = Self::B * angle + Self::C * angle * abs(angle);
100 Self::P * (y * abs(y) - y) + y
101 }
102}
103
104#[inline]
105fn abs(value: f32) -> f32 {
106 if value < 0.0 {
107 -value
108 } else {
109 value
110 }
111}
112
113#[inline]
114fn bipolar_to_unipolar(value: f32) -> f32 {
115 (value + 1.0) / 2.0
116}
diff --git a/examples/nrf52840/src/bin/i2s_monitor.rs b/examples/nrf52840/src/bin/i2s_monitor.rs
new file mode 100644
index 000000000..4ed597c0d
--- /dev/null
+++ b/examples/nrf52840/src/bin/i2s_monitor.rs
@@ -0,0 +1,118 @@
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::pwm::{Prescaler, SimplePwm};
9use embassy_nrf::{bind_interrupts, peripherals};
10use {defmt_rtt as _, panic_probe as _};
11
12type Sample = i16;
13
14const NUM_SAMPLES: usize = 500;
15
16bind_interrupts!(struct Irqs {
17 I2S => i2s::InterruptHandler<peripherals::I2S>;
18});
19
20#[embassy_executor::main]
21async fn main(_spawner: Spawner) {
22 let p = embassy_nrf::init(Default::default());
23
24 let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
25
26 let sample_rate = master_clock.sample_rate();
27 info!("Sample rate: {}", sample_rate);
28
29 let mut config = Config::default();
30 config.sample_width = SampleWidth::_16bit;
31 config.channels = Channels::MonoLeft;
32
33 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
34 let mut input_stream =
35 I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers);
36
37 // Configure the PWM to use the pins corresponding to the RGB leds
38 let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24);
39 pwm.set_prescaler(Prescaler::Div1);
40 pwm.set_max_duty(255);
41
42 let mut rms_online = RmsOnline::<NUM_SAMPLES>::default();
43
44 input_stream.start().await.expect("I2S Start");
45
46 loop {
47 let rms = rms_online.process(input_stream.buffer());
48 let rgb = rgb_from_rms(rms);
49
50 debug!("RMS: {}, RGB: {:?}", rms, rgb);
51 for i in 0..3 {
52 pwm.set_duty(i, rgb[i].into());
53 }
54
55 if let Err(err) = input_stream.receive().await {
56 error!("{}", err);
57 }
58 }
59}
60
61/// RMS from 0.0 until 0.75 will give green with a proportional intensity
62/// RMS from 0.75 until 0.9 will give a blend between orange and red proportionally to the intensity
63/// RMS above 0.9 will give a red with a proportional intensity
64fn rgb_from_rms(rms: f32) -> [u8; 3] {
65 if rms < 0.75 {
66 let intensity = rms / 0.75;
67 [0, (intensity * 165.0) as u8, 0]
68 } else if rms < 0.9 {
69 let intensity = (rms - 0.75) / 0.15;
70 [200, 165 - (165.0 * intensity) as u8, 0]
71 } else {
72 let intensity = (rms - 0.9) / 0.1;
73 [200 + (55.0 * intensity) as u8, 0, 0]
74 }
75}
76
77pub struct RmsOnline<const N: usize> {
78 pub squares: [f32; N],
79 pub head: usize,
80}
81
82impl<const N: usize> Default for RmsOnline<N> {
83 fn default() -> Self {
84 RmsOnline {
85 squares: [0.0; N],
86 head: 0,
87 }
88 }
89}
90
91impl<const N: usize> RmsOnline<N> {
92 pub fn reset(&mut self) {
93 self.squares = [0.0; N];
94 self.head = 0;
95 }
96
97 pub fn process(&mut self, buf: &[Sample]) -> f32 {
98 buf.iter()
99 .for_each(|sample| self.push(*sample as f32 / Sample::SCALE as f32));
100
101 let sum_of_squares = self.squares.iter().fold(0.0, |acc, v| acc + *v);
102 Self::approx_sqrt(sum_of_squares / N as f32)
103 }
104
105 pub fn push(&mut self, signal: f32) {
106 let square = signal * signal;
107 self.squares[self.head] = square;
108 self.head = (self.head + 1) % N;
109 }
110
111 /// Approximated sqrt taken from [micromath]
112 ///
113 /// [micromath]: https://docs.rs/micromath/latest/src/micromath/float/sqrt.rs.html#11-17
114 ///
115 fn approx_sqrt(value: f32) -> f32 {
116 f32::from_bits((value.to_bits() + 0x3f80_0000) >> 1)
117 }
118}
diff --git a/examples/nrf52840/src/bin/i2s_waveform.rs b/examples/nrf52840/src/bin/i2s_waveform.rs
new file mode 100644
index 000000000..f2c1166b1
--- /dev/null
+++ b/examples/nrf52840/src/bin/i2s_waveform.rs
@@ -0,0 +1,154 @@
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::{bind_interrupts, peripherals};
11use {defmt_rtt as _, panic_probe as _};
12
13type Sample = i16;
14
15const NUM_SAMPLES: usize = 50;
16
17bind_interrupts!(struct Irqs {
18 I2S => i2s::InterruptHandler<peripherals::I2S>;
19});
20
21#[embassy_executor::main]
22async fn main(_spawner: Spawner) {
23 let p = embassy_nrf::init(Default::default());
24
25 let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
26
27 let sample_rate = master_clock.sample_rate();
28 info!("Sample rate: {}", sample_rate);
29
30 let mut config = Config::default();
31 config.sample_width = SampleWidth::_16bit;
32 config.channels = Channels::MonoLeft;
33
34 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
35 let mut output_stream =
36 I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28, buffers);
37
38 let mut waveform = Waveform::new(1.0 / sample_rate as f32);
39
40 waveform.process(output_stream.buffer());
41
42 output_stream.start().await.expect("I2S Start");
43
44 loop {
45 waveform.process(output_stream.buffer());
46
47 if let Err(err) = output_stream.send().await {
48 error!("{}", err);
49 }
50 }
51}
52
53struct Waveform {
54 inv_sample_rate: f32,
55 carrier: SineOsc,
56 freq_mod: SineOsc,
57 amp_mod: SineOsc,
58}
59
60impl Waveform {
61 fn new(inv_sample_rate: f32) -> Self {
62 let mut carrier = SineOsc::new();
63 carrier.set_frequency(110.0, inv_sample_rate);
64
65 let mut freq_mod = SineOsc::new();
66 freq_mod.set_frequency(1.0, inv_sample_rate);
67 freq_mod.set_amplitude(1.0);
68
69 let mut amp_mod = SineOsc::new();
70 amp_mod.set_frequency(16.0, inv_sample_rate);
71 amp_mod.set_amplitude(0.5);
72
73 Self {
74 inv_sample_rate,
75 carrier,
76 freq_mod,
77 amp_mod,
78 }
79 }
80
81 fn process(&mut self, buf: &mut [Sample]) {
82 for sample in buf.chunks_mut(1) {
83 let freq_modulation = bipolar_to_unipolar(self.freq_mod.generate());
84 self.carrier
85 .set_frequency(110.0 + 440.0 * freq_modulation, self.inv_sample_rate);
86
87 let amp_modulation = bipolar_to_unipolar(self.amp_mod.generate());
88 self.carrier.set_amplitude(amp_modulation);
89
90 let signal = self.carrier.generate();
91
92 sample[0] = (Sample::SCALE as f32 * signal) as Sample;
93 }
94 }
95}
96
97struct SineOsc {
98 amplitude: f32,
99 modulo: f32,
100 phase_inc: f32,
101}
102
103impl SineOsc {
104 const B: f32 = 4.0 / PI;
105 const C: f32 = -4.0 / (PI * PI);
106 const P: f32 = 0.225;
107
108 pub fn new() -> Self {
109 Self {
110 amplitude: 1.0,
111 modulo: 0.0,
112 phase_inc: 0.0,
113 }
114 }
115
116 pub fn set_frequency(&mut self, freq: f32, inv_sample_rate: f32) {
117 self.phase_inc = freq * inv_sample_rate;
118 }
119
120 pub fn set_amplitude(&mut self, amplitude: f32) {
121 self.amplitude = amplitude;
122 }
123
124 pub fn generate(&mut self) -> f32 {
125 let signal = self.parabolic_sin(self.modulo);
126 self.modulo += self.phase_inc;
127 if self.modulo < 0.0 {
128 self.modulo += 1.0;
129 } else if self.modulo > 1.0 {
130 self.modulo -= 1.0;
131 }
132 signal * self.amplitude
133 }
134
135 fn parabolic_sin(&mut self, modulo: f32) -> f32 {
136 let angle = PI - modulo * 2.0 * PI;
137 let y = Self::B * angle + Self::C * angle * abs(angle);
138 Self::P * (y * abs(y) - y) + y
139 }
140}
141
142#[inline]
143fn abs(value: f32) -> f32 {
144 if value < 0.0 {
145 -value
146 } else {
147 value
148 }
149}
150
151#[inline]
152fn bipolar_to_unipolar(value: f32) -> f32 {
153 (value + 1.0) / 2.0
154}
diff --git a/examples/nrf52840/src/bin/lora_cad.rs b/examples/nrf52840/src/bin/lora_cad.rs
new file mode 100644
index 000000000..beca061ed
--- /dev/null
+++ b/examples/nrf52840/src/bin/lora_cad.rs
@@ -0,0 +1,99 @@
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 demonstrates LORA CAD functionality.
4#![no_std]
5#![no_main]
6#![macro_use]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_lora::iv::GenericSx126xInterfaceVariant;
12use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
13use embassy_nrf::{bind_interrupts, peripherals, spim};
14use embassy_time::{Delay, Duration, Timer};
15use lora_phy::mod_params::*;
16use lora_phy::sx1261_2::SX1261_2;
17use lora_phy::LoRa;
18use {defmt_rtt as _, panic_probe as _};
19
20const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
21
22bind_interrupts!(struct Irqs {
23 SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
24});
25
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 let p = embassy_nrf::init(Default::default());
29 let mut spi_config = spim::Config::default();
30 spi_config.frequency = spim::Frequency::M16;
31
32 let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
33
34 let nss = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
35 let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
36 let dio1 = Input::new(p.P1_15.degrade(), Pull::Down);
37 let busy = Input::new(p.P1_14.degrade(), Pull::Down);
38 let rf_switch_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard);
39 let rf_switch_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard);
40
41 let iv =
42 GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap();
43
44 let mut delay = Delay;
45
46 let mut lora = {
47 match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await {
48 Ok(l) => l,
49 Err(err) => {
50 info!("Radio error = {}", err);
51 return;
52 }
53 }
54 };
55
56 let mut debug_indicator = Output::new(p.P1_03, Level::Low, OutputDrive::Standard);
57 let mut start_indicator = Output::new(p.P1_04, Level::Low, OutputDrive::Standard);
58
59 start_indicator.set_high();
60 Timer::after(Duration::from_secs(5)).await;
61 start_indicator.set_low();
62
63 let mdltn_params = {
64 match lora.create_modulation_params(
65 SpreadingFactor::_10,
66 Bandwidth::_250KHz,
67 CodingRate::_4_8,
68 LORA_FREQUENCY_IN_HZ,
69 ) {
70 Ok(mp) => mp,
71 Err(err) => {
72 info!("Radio error = {}", err);
73 return;
74 }
75 }
76 };
77
78 match lora.prepare_for_cad(&mdltn_params, true).await {
79 Ok(()) => {}
80 Err(err) => {
81 info!("Radio error = {}", err);
82 return;
83 }
84 };
85
86 match lora.cad().await {
87 Ok(cad_activity_detected) => {
88 if cad_activity_detected {
89 info!("cad successful with activity detected")
90 } else {
91 info!("cad successful without activity detected")
92 }
93 debug_indicator.set_high();
94 Timer::after(Duration::from_secs(5)).await;
95 debug_indicator.set_low();
96 }
97 Err(err) => info!("cad unsuccessful = {}", err),
98 }
99}
diff --git a/examples/nrf52840/src/bin/lora_lorawan.rs b/examples/nrf52840/src/bin/lora_lorawan.rs
new file mode 100644
index 000000000..c953680c6
--- /dev/null
+++ b/examples/nrf52840/src/bin/lora_lorawan.rs
@@ -0,0 +1,83 @@
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 demonstrates LoRaWAN join functionality.
4#![no_std]
5#![no_main]
6#![macro_use]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_lora::iv::GenericSx126xInterfaceVariant;
12use embassy_lora::LoraTimer;
13use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
14use embassy_nrf::rng::Rng;
15use embassy_nrf::{bind_interrupts, peripherals, rng, spim};
16use embassy_time::Delay;
17use lora_phy::mod_params::*;
18use lora_phy::sx1261_2::SX1261_2;
19use lora_phy::LoRa;
20use lorawan::default_crypto::DefaultFactory as Crypto;
21use lorawan_device::async_device::lora_radio::LoRaRadio;
22use lorawan_device::async_device::{region, Device, JoinMode};
23use {defmt_rtt as _, panic_probe as _};
24
25const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set this appropriately for the region
26
27bind_interrupts!(struct Irqs {
28 SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
29 RNG => rng::InterruptHandler<peripherals::RNG>;
30});
31
32#[embassy_executor::main]
33async fn main(_spawner: Spawner) {
34 let p = embassy_nrf::init(Default::default());
35 let mut spi_config = spim::Config::default();
36 spi_config.frequency = spim::Frequency::M16;
37
38 let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
39
40 let nss = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
41 let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
42 let dio1 = Input::new(p.P1_15.degrade(), Pull::Down);
43 let busy = Input::new(p.P1_14.degrade(), Pull::Down);
44 let rf_switch_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard);
45 let rf_switch_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard);
46
47 let iv =
48 GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap();
49
50 let mut delay = Delay;
51
52 let lora = {
53 match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), true, &mut delay).await {
54 Ok(l) => l,
55 Err(err) => {
56 info!("Radio error = {}", err);
57 return;
58 }
59 }
60 };
61
62 let radio = LoRaRadio::new(lora);
63 let region: region::Configuration = region::Configuration::new(LORAWAN_REGION);
64 let mut device: Device<_, Crypto, _, _> = Device::new(region, radio, LoraTimer::new(), Rng::new(p.RNG, Irqs));
65
66 defmt::info!("Joining LoRaWAN network");
67
68 // TODO: Adjust the EUI and Keys according to your network credentials
69 match device
70 .join(&JoinMode::OTAA {
71 deveui: [0, 0, 0, 0, 0, 0, 0, 0],
72 appeui: [0, 0, 0, 0, 0, 0, 0, 0],
73 appkey: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
74 })
75 .await
76 {
77 Ok(()) => defmt::info!("LoRaWAN network joined"),
78 Err(err) => {
79 info!("Radio error = {}", err);
80 return;
81 }
82 };
83}
diff --git a/examples/nrf52840/src/bin/lora_p2p_receive.rs b/examples/nrf52840/src/bin/lora_p2p_receive.rs
new file mode 100644
index 000000000..563fe42ec
--- /dev/null
+++ b/examples/nrf52840/src/bin/lora_p2p_receive.rs
@@ -0,0 +1,121 @@
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 demonstrates LORA P2P receive functionality in conjunction with the lora_p2p_send example.
4#![no_std]
5#![no_main]
6#![macro_use]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_lora::iv::GenericSx126xInterfaceVariant;
12use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
13use embassy_nrf::{bind_interrupts, peripherals, spim};
14use embassy_time::{Delay, Duration, Timer};
15use lora_phy::mod_params::*;
16use lora_phy::sx1261_2::SX1261_2;
17use lora_phy::LoRa;
18use {defmt_rtt as _, panic_probe as _};
19
20const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
21
22bind_interrupts!(struct Irqs {
23 SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
24});
25
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 let p = embassy_nrf::init(Default::default());
29 let mut spi_config = spim::Config::default();
30 spi_config.frequency = spim::Frequency::M16;
31
32 let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
33
34 let nss = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
35 let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
36 let dio1 = Input::new(p.P1_15.degrade(), Pull::Down);
37 let busy = Input::new(p.P1_14.degrade(), Pull::Down);
38 let rf_switch_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard);
39 let rf_switch_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard);
40
41 let iv =
42 GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap();
43
44 let mut delay = Delay;
45
46 let mut lora = {
47 match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await {
48 Ok(l) => l,
49 Err(err) => {
50 info!("Radio error = {}", err);
51 return;
52 }
53 }
54 };
55
56 let mut debug_indicator = Output::new(p.P1_03, Level::Low, OutputDrive::Standard);
57 let mut start_indicator = Output::new(p.P1_04, Level::Low, OutputDrive::Standard);
58
59 start_indicator.set_high();
60 Timer::after(Duration::from_secs(5)).await;
61 start_indicator.set_low();
62
63 let mut receiving_buffer = [00u8; 100];
64
65 let mdltn_params = {
66 match lora.create_modulation_params(
67 SpreadingFactor::_10,
68 Bandwidth::_250KHz,
69 CodingRate::_4_8,
70 LORA_FREQUENCY_IN_HZ,
71 ) {
72 Ok(mp) => mp,
73 Err(err) => {
74 info!("Radio error = {}", err);
75 return;
76 }
77 }
78 };
79
80 let rx_pkt_params = {
81 match lora.create_rx_packet_params(4, false, receiving_buffer.len() as u8, true, false, &mdltn_params) {
82 Ok(pp) => pp,
83 Err(err) => {
84 info!("Radio error = {}", err);
85 return;
86 }
87 }
88 };
89
90 match lora
91 .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, true, false, 0, 0x00ffffffu32)
92 .await
93 {
94 Ok(()) => {}
95 Err(err) => {
96 info!("Radio error = {}", err);
97 return;
98 }
99 };
100
101 loop {
102 receiving_buffer = [00u8; 100];
103 match lora.rx(&rx_pkt_params, &mut receiving_buffer).await {
104 Ok((received_len, _rx_pkt_status)) => {
105 if (received_len == 3)
106 && (receiving_buffer[0] == 0x01u8)
107 && (receiving_buffer[1] == 0x02u8)
108 && (receiving_buffer[2] == 0x03u8)
109 {
110 info!("rx successful");
111 debug_indicator.set_high();
112 Timer::after(Duration::from_secs(5)).await;
113 debug_indicator.set_low();
114 } else {
115 info!("rx unknown packet");
116 }
117 }
118 Err(err) => info!("rx unsuccessful = {}", err),
119 }
120 }
121}
diff --git a/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs b/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs
new file mode 100644
index 000000000..1fd8f61a2
--- /dev/null
+++ b/examples/nrf52840/src/bin/lora_p2p_receive_duty_cycle.rs
@@ -0,0 +1,131 @@
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 demonstrates LoRa Rx duty cycle functionality in conjunction with the lora_p2p_send example.
4#![no_std]
5#![no_main]
6#![macro_use]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_lora::iv::GenericSx126xInterfaceVariant;
12use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
13use embassy_nrf::{bind_interrupts, peripherals, spim};
14use embassy_time::{Delay, Duration, Timer};
15use lora_phy::mod_params::*;
16use lora_phy::sx1261_2::SX1261_2;
17use lora_phy::LoRa;
18use {defmt_rtt as _, panic_probe as _};
19
20const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
21
22bind_interrupts!(struct Irqs {
23 SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
24});
25
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 let p = embassy_nrf::init(Default::default());
29 let mut spi_config = spim::Config::default();
30 spi_config.frequency = spim::Frequency::M16;
31
32 let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
33
34 let nss = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
35 let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
36 let dio1 = Input::new(p.P1_15.degrade(), Pull::Down);
37 let busy = Input::new(p.P1_14.degrade(), Pull::Down);
38 let rf_switch_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard);
39 let rf_switch_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard);
40
41 let iv =
42 GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap();
43
44 let mut delay = Delay;
45
46 let mut lora = {
47 match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await {
48 Ok(l) => l,
49 Err(err) => {
50 info!("Radio error = {}", err);
51 return;
52 }
53 }
54 };
55
56 let mut debug_indicator = Output::new(p.P1_03, Level::Low, OutputDrive::Standard);
57 let mut start_indicator = Output::new(p.P1_04, Level::Low, OutputDrive::Standard);
58
59 start_indicator.set_high();
60 Timer::after(Duration::from_secs(5)).await;
61 start_indicator.set_low();
62
63 let mut receiving_buffer = [00u8; 100];
64
65 let mdltn_params = {
66 match lora.create_modulation_params(
67 SpreadingFactor::_10,
68 Bandwidth::_250KHz,
69 CodingRate::_4_8,
70 LORA_FREQUENCY_IN_HZ,
71 ) {
72 Ok(mp) => mp,
73 Err(err) => {
74 info!("Radio error = {}", err);
75 return;
76 }
77 }
78 };
79
80 let rx_pkt_params = {
81 match lora.create_rx_packet_params(4, false, receiving_buffer.len() as u8, true, false, &mdltn_params) {
82 Ok(pp) => pp,
83 Err(err) => {
84 info!("Radio error = {}", err);
85 return;
86 }
87 }
88 };
89
90 // See "RM0453 Reference manual STM32WL5x advanced Arm®-based 32-bit MCUs with sub-GHz radio solution" for the best explanation of Rx duty cycle processing.
91 match lora
92 .prepare_for_rx(
93 &mdltn_params,
94 &rx_pkt_params,
95 Some(&DutyCycleParams {
96 rx_time: 300_000, // 300_000 units * 15.625 us/unit = 4.69 s
97 sleep_time: 200_000, // 200_000 units * 15.625 us/unit = 3.13 s
98 }),
99 false,
100 false,
101 0,
102 0,
103 )
104 .await
105 {
106 Ok(()) => {}
107 Err(err) => {
108 info!("Radio error = {}", err);
109 return;
110 }
111 };
112
113 receiving_buffer = [00u8; 100];
114 match lora.rx(&rx_pkt_params, &mut receiving_buffer).await {
115 Ok((received_len, _rx_pkt_status)) => {
116 if (received_len == 3)
117 && (receiving_buffer[0] == 0x01u8)
118 && (receiving_buffer[1] == 0x02u8)
119 && (receiving_buffer[2] == 0x03u8)
120 {
121 info!("rx successful");
122 debug_indicator.set_high();
123 Timer::after(Duration::from_secs(5)).await;
124 debug_indicator.set_low();
125 } else {
126 info!("rx unknown packet")
127 }
128 }
129 Err(err) => info!("rx unsuccessful = {}", err),
130 }
131}
diff --git a/examples/nrf52840/src/bin/lora_p2p_send.rs b/examples/nrf52840/src/bin/lora_p2p_send.rs
new file mode 100644
index 000000000..1c8bbc27a
--- /dev/null
+++ b/examples/nrf52840/src/bin/lora_p2p_send.rs
@@ -0,0 +1,104 @@
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 demonstrates LORA P2P send functionality.
4#![no_std]
5#![no_main]
6#![macro_use]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_lora::iv::GenericSx126xInterfaceVariant;
12use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
13use embassy_nrf::{bind_interrupts, peripherals, spim};
14use embassy_time::Delay;
15use lora_phy::mod_params::*;
16use lora_phy::sx1261_2::SX1261_2;
17use lora_phy::LoRa;
18use {defmt_rtt as _, panic_probe as _};
19
20const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
21
22bind_interrupts!(struct Irqs {
23 SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 => spim::InterruptHandler<peripherals::TWISPI1>;
24});
25
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 let p = embassy_nrf::init(Default::default());
29 let mut spi_config = spim::Config::default();
30 spi_config.frequency = spim::Frequency::M16;
31
32 let spim = spim::Spim::new(p.TWISPI1, Irqs, p.P1_11, p.P1_13, p.P1_12, spi_config);
33
34 let nss = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
35 let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
36 let dio1 = Input::new(p.P1_15.degrade(), Pull::Down);
37 let busy = Input::new(p.P1_14.degrade(), Pull::Down);
38 let rf_switch_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard);
39 let rf_switch_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard);
40
41 let iv =
42 GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, Some(rf_switch_rx), Some(rf_switch_tx)).unwrap();
43
44 let mut delay = Delay;
45
46 let mut lora = {
47 match LoRa::new(SX1261_2::new(BoardType::Rak4631Sx1262, spim, iv), false, &mut delay).await {
48 Ok(l) => l,
49 Err(err) => {
50 info!("Radio error = {}", err);
51 return;
52 }
53 }
54 };
55
56 let mdltn_params = {
57 match lora.create_modulation_params(
58 SpreadingFactor::_10,
59 Bandwidth::_250KHz,
60 CodingRate::_4_8,
61 LORA_FREQUENCY_IN_HZ,
62 ) {
63 Ok(mp) => mp,
64 Err(err) => {
65 info!("Radio error = {}", err);
66 return;
67 }
68 }
69 };
70
71 let mut tx_pkt_params = {
72 match lora.create_tx_packet_params(4, false, true, false, &mdltn_params) {
73 Ok(pp) => pp,
74 Err(err) => {
75 info!("Radio error = {}", err);
76 return;
77 }
78 }
79 };
80
81 match lora.prepare_for_tx(&mdltn_params, 20, false).await {
82 Ok(()) => {}
83 Err(err) => {
84 info!("Radio error = {}", err);
85 return;
86 }
87 };
88
89 let buffer = [0x01u8, 0x02u8, 0x03u8];
90 match lora.tx(&mdltn_params, &mut tx_pkt_params, &buffer, 0xffffff).await {
91 Ok(()) => {
92 info!("TX DONE");
93 }
94 Err(err) => {
95 info!("Radio error = {}", err);
96 return;
97 }
98 };
99
100 match lora.sleep(&mut delay).await {
101 Ok(()) => info!("Sleep successful"),
102 Err(err) => info!("Sleep unsuccessful = {}", err),
103 }
104}
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..aab819117 100644
--- a/examples/nrf/src/bin/multiprio.rs
+++ b/examples/nrf52840/src/bin/multiprio.rs
@@ -59,9 +59,9 @@
59 59
60use cortex_m_rt::entry; 60use cortex_m_rt::entry;
61use defmt::{info, unwrap}; 61use defmt::{info, unwrap};
62use embassy_nrf::executor::{Executor, InterruptExecutor}; 62use embassy_executor::{Executor, InterruptExecutor};
63use embassy_nrf::interrupt; 63use embassy_nrf::interrupt;
64use embassy_nrf::interrupt::InterruptExt; 64use embassy_nrf::interrupt::{InterruptExt, Priority};
65use embassy_time::{Duration, Instant, Timer}; 65use embassy_time::{Duration, Instant, Timer};
66use static_cell::StaticCell; 66use static_cell::StaticCell;
67use {defmt_rtt as _, panic_probe as _}; 67use {defmt_rtt as _, panic_probe as _};
@@ -108,10 +108,20 @@ async fn run_low() {
108 } 108 }
109} 109}
110 110
111static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::SWI1_EGU1>> = StaticCell::new(); 111static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
112static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::SWI0_EGU0>> = StaticCell::new(); 112static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
113static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); 113static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
114 114
115#[interrupt]
116unsafe fn SWI1_EGU1() {
117 EXECUTOR_HIGH.on_interrupt()
118}
119
120#[interrupt]
121unsafe fn SWI0_EGU0() {
122 EXECUTOR_MED.on_interrupt()
123}
124
115#[entry] 125#[entry]
116fn main() -> ! { 126fn main() -> ! {
117 info!("Hello World!"); 127 info!("Hello World!");
@@ -119,17 +129,13 @@ fn main() -> ! {
119 let _p = embassy_nrf::init(Default::default()); 129 let _p = embassy_nrf::init(Default::default());
120 130
121 // High-priority executor: SWI1_EGU1, priority level 6 131 // High-priority executor: SWI1_EGU1, priority level 6
122 let irq = interrupt::take!(SWI1_EGU1); 132 interrupt::SWI1_EGU1.set_priority(Priority::P6);
123 irq.set_priority(interrupt::Priority::P6); 133 let spawner = EXECUTOR_HIGH.start(interrupt::SWI1_EGU1);
124 let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
125 let spawner = executor.start();
126 unwrap!(spawner.spawn(run_high())); 134 unwrap!(spawner.spawn(run_high()));
127 135
128 // Medium-priority executor: SWI0_EGU0, priority level 7 136 // Medium-priority executor: SWI0_EGU0, priority level 7
129 let irq = interrupt::take!(SWI0_EGU0); 137 interrupt::SWI0_EGU0.set_priority(Priority::P7);
130 irq.set_priority(interrupt::Priority::P7); 138 let spawner = EXECUTOR_MED.start(interrupt::SWI0_EGU0);
131 let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
132 let spawner = executor.start();
133 unwrap!(spawner.spawn(run_med())); 139 unwrap!(spawner.spawn(run_med()));
134 140
135 // Low priority executor: runs in thread mode, using WFE/SEV 141 // Low priority executor: runs in thread mode, using WFE/SEV
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..31c6fe4b6 100644
--- a/examples/nrf/src/bin/nvmc.rs
+++ b/examples/nrf52840/src/bin/nvmc.rs
@@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
14 let p = embassy_nrf::init(Default::default()); 14 let p = embassy_nrf::init(Default::default());
15 info!("Hello NVMC!"); 15 info!("Hello NVMC!");
16 16
17 // probe-run breaks without this, I'm not sure why. 17 // probe-rs run breaks without this, I'm not sure why.
18 Timer::after(Duration::from_secs(1)).await; 18 Timer::after(Duration::from_secs(1)).await;
19 19
20 let mut f = Nvmc::new(p.NVMC); 20 let mut f = Nvmc::new(p.NVMC);
diff --git a/examples/nrf52840/src/bin/pdm.rs b/examples/nrf52840/src/bin/pdm.rs
new file mode 100644
index 000000000..47fe67733
--- /dev/null
+++ b/examples/nrf52840/src/bin/pdm.rs
@@ -0,0 +1,55 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_nrf::pdm::{self, Config, Pdm};
8use embassy_nrf::{bind_interrupts, peripherals};
9use embassy_time::{Duration, Timer};
10use fixed::types::I7F1;
11use num_integer::Roots;
12use {defmt_rtt as _, panic_probe as _};
13
14bind_interrupts!(struct Irqs {
15 PDM => pdm::InterruptHandler<peripherals::PDM>;
16});
17
18#[embassy_executor::main]
19async fn main(_p: Spawner) {
20 let p = embassy_nrf::init(Default::default());
21 let config = Config::default();
22 let mut pdm = Pdm::new(p.PDM, Irqs, p.P0_01, p.P0_00, config);
23
24 loop {
25 for gain in [I7F1::from_num(-20), I7F1::from_num(0), I7F1::from_num(20)] {
26 pdm.set_gain(gain, gain);
27 info!("Gain = {} dB", defmt::Debug2Format(&gain));
28 pdm.start().await;
29
30 // wait some time till the microphon settled
31 Timer::after(Duration::from_millis(1000)).await;
32
33 const SAMPLES: usize = 2048;
34 let mut buf = [0i16; SAMPLES];
35 pdm.sample(&mut buf).await.unwrap();
36
37 let mean = (buf.iter().map(|v| i32::from(*v)).sum::<i32>() / buf.len() as i32) as i16;
38 info!(
39 "{} samples, min {=i16}, max {=i16}, mean {=i16}, AC RMS {=i16}",
40 buf.len(),
41 buf.iter().min().unwrap(),
42 buf.iter().max().unwrap(),
43 mean,
44 (
45 buf.iter().map(|v| i32::from(*v - mean).pow(2)).fold(0i32, |a,b| a.saturating_add(b))
46 / buf.len() as i32).sqrt() as i16,
47 );
48
49 info!("samples: {:?}", &buf);
50
51 pdm.stop().await;
52 Timer::after(Duration::from_millis(100)).await;
53 }
54 }
55}
diff --git a/examples/nrf/src/bin/pdm_continuous.rs b/examples/nrf52840/src/bin/pdm_continuous.rs
index 284a68af2..9eaf30717 100644
--- a/examples/nrf/src/bin/pdm_continuous.rs
+++ b/examples/nrf52840/src/bin/pdm_continuous.rs
@@ -5,8 +5,8 @@
5use defmt::info; 5use defmt::info;
6use core::cmp::Ordering; 6use core::cmp::Ordering;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_nrf::interrupt; 8use embassy_nrf::{bind_interrupts, peripherals};
9use embassy_nrf::pdm::{Config, Channels, Pdm, SamplerState, Frequency, Ratio}; 9use embassy_nrf::pdm::{self, Config, OperationMode, Pdm, SamplerState, Frequency, Ratio};
10use fixed::types::I7F1; 10use fixed::types::I7F1;
11use num_integer::Roots; 11use num_integer::Roots;
12use microfft::real::rfft_1024; 12use microfft::real::rfft_1024;
@@ -14,6 +14,10 @@ use {defmt_rtt as _, panic_probe as _};
14 14
15// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer 15// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer
16 16
17bind_interrupts!(struct Irqs {
18 PDM => pdm::InterruptHandler<peripherals::PDM>;
19});
20
17#[embassy_executor::main] 21#[embassy_executor::main]
18async fn main(_p: Spawner) { 22async fn main(_p: Spawner) {
19 let mut p = embassy_nrf::init(Default::default()); 23 let mut p = embassy_nrf::init(Default::default());
@@ -21,9 +25,9 @@ async fn main(_p: Spawner) {
21 // Pins are correct for the onboard microphone on the Feather nRF52840 Sense. 25 // Pins are correct for the onboard microphone on the Feather nRF52840 Sense.
22 config.frequency = Frequency::_1280K; // 16 kHz sample rate 26 config.frequency = Frequency::_1280K; // 16 kHz sample rate
23 config.ratio = Ratio::RATIO80; 27 config.ratio = Ratio::RATIO80;
24 config.channels = Channels::Mono; 28 config.operation_mode = OperationMode::Mono;
25 config.gain_left = I7F1::from_bits(5); // 2.5 dB 29 config.gain_left = I7F1::from_bits(5); // 2.5 dB
26 let mut pdm = Pdm::new(p.PDM, interrupt::take!(PDM), &mut p.P0_00, &mut p.P0_01, config); 30 let mut pdm = Pdm::new(p.PDM, Irqs, &mut p.P0_00, &mut p.P0_01, config);
27 31
28 let mut bufs = [[0; 1024]; 2]; 32 let mut bufs = [[0; 1024]; 2];
29 33
@@ -54,7 +58,7 @@ async fn main(_p: Spawner) {
54 SamplerState::Sampled 58 SamplerState::Sampled
55 }, 59 },
56 ) 60 )
57 .await; 61 .await.unwrap();
58} 62}
59 63
60fn fft_peak_freq(input: &[i16; 1024]) -> (usize, u32) { 64fn fft_peak_freq(input: &[i16; 1024]) -> (usize, u32) {
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..cca60ebc9 100644
--- a/examples/nrf/src/bin/pubsub.rs
+++ b/examples/nrf52840/src/bin/pubsub.rs
@@ -74,9 +74,9 @@ async fn fast_logger(mut messages: Subscriber<'static, ThreadModeRawMutex, Messa
74} 74}
75 75
76/// A logger task that awaits the messages, but also does some other work. 76/// A logger task that awaits the messages, but also does some other work.
77/// Because of this, depeding on how the messages were published, the subscriber might miss some messages 77/// Because of this, depending on how the messages were published, the subscriber might miss some messages.
78/// 78///
79/// This takes the dynamic `DynSubscriber`. This is not as performant as the generic version, but let's you ignore some of the generics 79/// This takes the dynamic `DynSubscriber`. This is not as performant as the generic version, but let's you ignore some of the generics.
80#[embassy_executor::task] 80#[embassy_executor::task]
81async fn slow_logger(mut messages: DynSubscriber<'static, Message>) { 81async fn slow_logger(mut messages: DynSubscriber<'static, Message>) {
82 loop { 82 loop {
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..59783d312 100644
--- a/examples/nrf/src/bin/qdec.rs
+++ b/examples/nrf52840/src/bin/qdec.rs
@@ -4,16 +4,19 @@
4 4
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::qdec::{self, Qdec}; 7use embassy_nrf::qdec::{self, Qdec};
8use embassy_nrf::{bind_interrupts, peripherals};
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11bind_interrupts!(struct Irqs {
12 QDEC => qdec::InterruptHandler<peripherals::QDEC>;
13});
14
11#[embassy_executor::main] 15#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default()); 17 let p = embassy_nrf::init(Default::default());
14 let irq = interrupt::take!(QDEC);
15 let config = qdec::Config::default(); 18 let config = qdec::Config::default();
16 let mut rotary_enc = Qdec::new(p.QDEC, irq, p.P0_31, p.P0_30, config); 19 let mut rotary_enc = Qdec::new(p.QDEC, Irqs, p.P0_31, p.P0_30, config);
17 20
18 info!("Turn rotary encoder!"); 21 info!("Turn rotary encoder!");
19 let mut value = 0; 22 let mut value = 0;
diff --git a/examples/nrf/src/bin/qspi.rs b/examples/nrf52840/src/bin/qspi.rs
index bdcf710b8..9e8a01f4e 100644
--- a/examples/nrf/src/bin/qspi.rs
+++ b/examples/nrf52840/src/bin/qspi.rs
@@ -4,7 +4,8 @@
4 4
5use defmt::{assert_eq, info, unwrap}; 5use defmt::{assert_eq, info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::{interrupt, qspi}; 7use embassy_nrf::qspi::Frequency;
8use embassy_nrf::{bind_interrupts, peripherals, qspi};
8use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
9 10
10const PAGE_SIZE: usize = 4096; 11const PAGE_SIZE: usize = 4096;
@@ -14,18 +15,23 @@ const PAGE_SIZE: usize = 4096;
14#[repr(C, align(4))] 15#[repr(C, align(4))]
15struct AlignedBuf([u8; 4096]); 16struct AlignedBuf([u8; 4096]);
16 17
18bind_interrupts!(struct Irqs {
19 QSPI => qspi::InterruptHandler<peripherals::QSPI>;
20});
21
17#[embassy_executor::main] 22#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 23async fn main(_spawner: Spawner) {
19 let p = embassy_nrf::init(Default::default()); 24 let p = embassy_nrf::init(Default::default());
20 // Config for the MX25R64 present in the nRF52840 DK 25 // Config for the MX25R64 present in the nRF52840 DK
21 let mut config = qspi::Config::default(); 26 let mut config = qspi::Config::default();
27 config.capacity = 8 * 1024 * 1024; // 8 MB
28 config.frequency = Frequency::M32;
22 config.read_opcode = qspi::ReadOpcode::READ4IO; 29 config.read_opcode = qspi::ReadOpcode::READ4IO;
23 config.write_opcode = qspi::WriteOpcode::PP4IO; 30 config.write_opcode = qspi::WriteOpcode::PP4IO;
24 config.write_page_size = qspi::WritePageSize::_256BYTES; 31 config.write_page_size = qspi::WritePageSize::_256BYTES;
25 32
26 let irq = interrupt::take!(QSPI); 33 let mut q = qspi::Qspi::new(
27 let mut q: qspi::Qspi<_, 67108864> = qspi::Qspi::new( 34 p.QSPI, Irqs, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config,
28 p.QSPI, irq, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config,
29 ); 35 );
30 36
31 let mut id = [1; 3]; 37 let mut id = [1; 3];
@@ -52,23 +58,23 @@ async fn main(_spawner: Spawner) {
52 58
53 for i in 0..8 { 59 for i in 0..8 {
54 info!("page {:?}: erasing... ", i); 60 info!("page {:?}: erasing... ", i);
55 unwrap!(q.erase(i * PAGE_SIZE).await); 61 unwrap!(q.erase(i * PAGE_SIZE as u32).await);
56 62
57 for j in 0..PAGE_SIZE { 63 for j in 0..PAGE_SIZE {
58 buf.0[j] = pattern((j + i * PAGE_SIZE) as u32); 64 buf.0[j] = pattern((j as u32 + i * PAGE_SIZE as u32) as u32);
59 } 65 }
60 66
61 info!("programming..."); 67 info!("programming...");
62 unwrap!(q.write(i * PAGE_SIZE, &buf.0).await); 68 unwrap!(q.write(i * PAGE_SIZE as u32, &buf.0).await);
63 } 69 }
64 70
65 for i in 0..8 { 71 for i in 0..8 {
66 info!("page {:?}: reading... ", i); 72 info!("page {:?}: reading... ", i);
67 unwrap!(q.read(i * PAGE_SIZE, &mut buf.0).await); 73 unwrap!(q.read(i * PAGE_SIZE as u32, &mut buf.0).await);
68 74
69 info!("verifying..."); 75 info!("verifying...");
70 for j in 0..PAGE_SIZE { 76 for j in 0..PAGE_SIZE {
71 assert_eq!(buf.0[j], pattern((j + i * PAGE_SIZE) as u32)); 77 assert_eq!(buf.0[j], pattern((j as u32 + i * PAGE_SIZE as u32) as u32));
72 } 78 }
73 } 79 }
74 80
diff --git a/examples/nrf/src/bin/qspi_lowpower.rs b/examples/nrf52840/src/bin/qspi_lowpower.rs
index 9341a2376..22a5c0c6d 100644
--- a/examples/nrf/src/bin/qspi_lowpower.rs
+++ b/examples/nrf52840/src/bin/qspi_lowpower.rs
@@ -6,7 +6,8 @@ use core::mem;
6 6
7use defmt::{info, unwrap}; 7use defmt::{info, unwrap};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_nrf::{interrupt, qspi}; 9use embassy_nrf::qspi::Frequency;
10use embassy_nrf::{bind_interrupts, peripherals, qspi};
10use embassy_time::{Duration, Timer}; 11use embassy_time::{Duration, Timer};
11use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
12 13
@@ -15,14 +16,19 @@ use {defmt_rtt as _, panic_probe as _};
15#[repr(C, align(4))] 16#[repr(C, align(4))]
16struct AlignedBuf([u8; 64]); 17struct AlignedBuf([u8; 64]);
17 18
19bind_interrupts!(struct Irqs {
20 QSPI => qspi::InterruptHandler<peripherals::QSPI>;
21});
22
18#[embassy_executor::main] 23#[embassy_executor::main]
19async fn main(_p: Spawner) { 24async fn main(_p: Spawner) {
20 let mut p = embassy_nrf::init(Default::default()); 25 let mut p = embassy_nrf::init(Default::default());
21 let mut irq = interrupt::take!(QSPI);
22 26
23 loop { 27 loop {
24 // Config for the MX25R64 present in the nRF52840 DK 28 // Config for the MX25R64 present in the nRF52840 DK
25 let mut config = qspi::Config::default(); 29 let mut config = qspi::Config::default();
30 config.capacity = 8 * 1024 * 1024; // 8 MB
31 config.frequency = Frequency::M32;
26 config.read_opcode = qspi::ReadOpcode::READ4IO; 32 config.read_opcode = qspi::ReadOpcode::READ4IO;
27 config.write_opcode = qspi::WriteOpcode::PP4IO; 33 config.write_opcode = qspi::WriteOpcode::PP4IO;
28 config.write_page_size = qspi::WritePageSize::_256BYTES; 34 config.write_page_size = qspi::WritePageSize::_256BYTES;
@@ -31,9 +37,9 @@ async fn main(_p: Spawner) {
31 exit_time: 3, // tRDP = 35uS 37 exit_time: 3, // tRDP = 35uS
32 }); 38 });
33 39
34 let mut q: qspi::Qspi<_, 67108864> = qspi::Qspi::new( 40 let mut q = qspi::Qspi::new(
35 &mut p.QSPI, 41 &mut p.QSPI,
36 &mut irq, 42 Irqs,
37 &mut p.P0_19, 43 &mut p.P0_19,
38 &mut p.P0_17, 44 &mut p.P0_17,
39 &mut p.P0_20, 45 &mut p.P0_20,
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..855743f50 100644
--- a/examples/nrf/src/bin/rng.rs
+++ b/examples/nrf52840/src/bin/rng.rs
@@ -3,15 +3,19 @@
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_nrf::interrupt;
7use embassy_nrf::rng::Rng; 6use embassy_nrf::rng::Rng;
7use embassy_nrf::{bind_interrupts, peripherals, rng};
8use rand::Rng as _; 8use rand::Rng as _;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11bind_interrupts!(struct Irqs {
12 RNG => rng::InterruptHandler<peripherals::RNG>;
13});
14
11#[embassy_executor::main] 15#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default()); 17 let p = embassy_nrf::init(Default::default());
14 let mut rng = Rng::new(p.RNG, interrupt::take!(RNG)); 18 let mut rng = Rng::new(p.RNG, Irqs);
15 19
16 // Async API 20 // Async API
17 let mut bytes = [0; 4]; 21 let mut bytes = [0; 4];
diff --git a/examples/nrf/src/bin/saadc.rs b/examples/nrf52840/src/bin/saadc.rs
index 7cf588090..ffd9a7f4b 100644
--- a/examples/nrf/src/bin/saadc.rs
+++ b/examples/nrf52840/src/bin/saadc.rs
@@ -4,17 +4,21 @@
4 4
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::saadc::{ChannelConfig, Config, Saadc}; 7use embassy_nrf::saadc::{ChannelConfig, Config, Saadc};
8use embassy_nrf::{bind_interrupts, saadc};
9use embassy_time::{Duration, Timer}; 9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12bind_interrupts!(struct Irqs {
13 SAADC => saadc::InterruptHandler;
14});
15
12#[embassy_executor::main] 16#[embassy_executor::main]
13async fn main(_p: Spawner) { 17async fn main(_p: Spawner) {
14 let mut p = embassy_nrf::init(Default::default()); 18 let mut p = embassy_nrf::init(Default::default());
15 let config = Config::default(); 19 let config = Config::default();
16 let channel_config = ChannelConfig::single_ended(&mut p.P0_02); 20 let channel_config = ChannelConfig::single_ended(&mut p.P0_02);
17 let mut saadc = Saadc::new(p.SAADC, interrupt::take!(SAADC), config, [channel_config]); 21 let mut saadc = Saadc::new(p.SAADC, Irqs, config, [channel_config]);
18 22
19 loop { 23 loop {
20 let mut buf = [0; 1]; 24 let mut buf = [0; 1];
diff --git a/examples/nrf/src/bin/saadc_continuous.rs b/examples/nrf52840/src/bin/saadc_continuous.rs
index bb50ac65e..a25e17465 100644
--- a/examples/nrf/src/bin/saadc_continuous.rs
+++ b/examples/nrf52840/src/bin/saadc_continuous.rs
@@ -4,14 +4,18 @@
4 4
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::interrupt; 7use embassy_nrf::saadc::{CallbackResult, ChannelConfig, Config, Saadc};
8use embassy_nrf::saadc::{ChannelConfig, Config, Saadc, SamplerState};
9use embassy_nrf::timer::Frequency; 8use embassy_nrf::timer::Frequency;
9use embassy_nrf::{bind_interrupts, saadc};
10use embassy_time::Duration; 10use embassy_time::Duration;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer 13// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer
14 14
15bind_interrupts!(struct Irqs {
16 SAADC => saadc::InterruptHandler;
17});
18
15#[embassy_executor::main] 19#[embassy_executor::main]
16async fn main(_p: Spawner) { 20async fn main(_p: Spawner) {
17 let mut p = embassy_nrf::init(Default::default()); 21 let mut p = embassy_nrf::init(Default::default());
@@ -21,7 +25,7 @@ async fn main(_p: Spawner) {
21 let channel_3_config = ChannelConfig::single_ended(&mut p.P0_04); 25 let channel_3_config = ChannelConfig::single_ended(&mut p.P0_04);
22 let mut saadc = Saadc::new( 26 let mut saadc = Saadc::new(
23 p.SAADC, 27 p.SAADC,
24 interrupt::take!(SAADC), 28 Irqs,
25 config, 29 config,
26 [channel_1_config, channel_2_config, channel_3_config], 30 [channel_1_config, channel_2_config, channel_3_config],
27 ); 31 );
@@ -61,7 +65,7 @@ async fn main(_p: Spawner) {
61 c = 0; 65 c = 0;
62 a = 0; 66 a = 0;
63 } 67 }
64 SamplerState::Sampled 68 CallbackResult::Continue
65 }, 69 },
66 ) 70 )
67 .await; 71 .await;
diff --git a/examples/nrf/src/bin/self_spawn.rs b/examples/nrf52840/src/bin/self_spawn.rs
index 196255a52..31ea6c81e 100644
--- a/examples/nrf/src/bin/self_spawn.rs
+++ b/examples/nrf52840/src/bin/self_spawn.rs
@@ -7,7 +7,11 @@ use embassy_executor::Spawner;
7use embassy_time::{Duration, Timer}; 7use embassy_time::{Duration, Timer};
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::task(pool_size = 2)] 10mod config {
11 pub const MY_TASK_POOL_SIZE: usize = 2;
12}
13
14#[embassy_executor::task(pool_size = config::MY_TASK_POOL_SIZE)]
11async fn my_task(spawner: Spawner, n: u32) { 15async fn my_task(spawner: Spawner, n: u32) {
12 Timer::after(Duration::from_secs(1)).await; 16 Timer::after(Duration::from_secs(1)).await;
13 info!("Spawning self! {}", n); 17 info!("Spawning self! {}", n);
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..9d1843a8f 100644
--- a/examples/nrf/src/bin/spim.rs
+++ b/examples/nrf52840/src/bin/spim.rs
@@ -5,9 +5,13 @@
5use defmt::{info, unwrap}; 5use defmt::{info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::gpio::{Level, Output, OutputDrive}; 7use embassy_nrf::gpio::{Level, Output, OutputDrive};
8use embassy_nrf::{interrupt, spim}; 8use embassy_nrf::{bind_interrupts, peripherals, spim};
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11bind_interrupts!(struct Irqs {
12 SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
13});
14
11#[embassy_executor::main] 15#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default()); 17 let p = embassy_nrf::init(Default::default());
@@ -16,8 +20,7 @@ async fn main(_spawner: Spawner) {
16 let mut config = spim::Config::default(); 20 let mut config = spim::Config::default();
17 config.frequency = spim::Frequency::M16; 21 config.frequency = spim::Frequency::M16;
18 22
19 let irq = interrupt::take!(SPIM3); 23 let mut spim = spim::Spim::new(p.SPI3, Irqs, p.P0_29, p.P0_28, p.P0_30, config);
20 let mut spim = spim::Spim::new(p.SPI3, irq, p.P0_29, p.P0_28, p.P0_30, config);
21 24
22 let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard); 25 let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard);
23 26
diff --git a/examples/nrf52840/src/bin/spis.rs b/examples/nrf52840/src/bin/spis.rs
new file mode 100644
index 000000000..77b6e8b64
--- /dev/null
+++ b/examples/nrf52840/src/bin/spis.rs
@@ -0,0 +1,30 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_nrf::spis::{Config, Spis};
8use embassy_nrf::{bind_interrupts, peripherals, spis};
9use {defmt_rtt as _, panic_probe as _};
10
11bind_interrupts!(struct Irqs {
12 SPIM2_SPIS2_SPI2 => spis::InterruptHandler<peripherals::SPI2>;
13});
14
15#[embassy_executor::main]
16async fn main(_spawner: Spawner) {
17 let p = embassy_nrf::init(Default::default());
18 info!("Running!");
19
20 let mut spis = Spis::new(p.SPI2, Irqs, p.P0_31, p.P0_29, p.P0_28, p.P0_30, Config::default());
21
22 loop {
23 let mut rx_buf = [0_u8; 64];
24 let tx_buf = [1_u8, 2, 3, 4, 5, 6, 7, 8];
25 if let Ok((n_rx, n_tx)) = spis.transfer(&mut rx_buf, &tx_buf).await {
26 info!("RX: {:?}", rx_buf[..n_rx]);
27 info!("TX: {:?}", tx_buf[..n_tx]);
28 }
29 }
30}
diff --git a/examples/nrf/src/bin/temp.rs b/examples/nrf52840/src/bin/temp.rs
index b06ac709e..70957548f 100644
--- a/examples/nrf/src/bin/temp.rs
+++ b/examples/nrf52840/src/bin/temp.rs
@@ -4,16 +4,19 @@
4 4
5use defmt::info; 5use defmt::info;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::temp::Temp; 7use embassy_nrf::temp::Temp;
8use embassy_nrf::{bind_interrupts, temp};
9use embassy_time::{Duration, Timer}; 9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12bind_interrupts!(struct Irqs {
13 TEMP => temp::InterruptHandler;
14});
15
12#[embassy_executor::main] 16#[embassy_executor::main]
13async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
14 let p = embassy_nrf::init(Default::default()); 18 let p = embassy_nrf::init(Default::default());
15 let irq = interrupt::take!(TEMP); 19 let mut temp = Temp::new(p.TEMP, Irqs);
16 let mut temp = Temp::new(p.TEMP, irq);
17 20
18 loop { 21 loop {
19 let value = temp.read().await; 22 let value = temp.read().await;
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..959e3a4be 100644
--- a/examples/nrf/src/bin/twim.rs
+++ b/examples/nrf52840/src/bin/twim.rs
@@ -8,19 +8,22 @@
8 8
9use defmt::*; 9use defmt::*;
10use embassy_executor::Spawner; 10use embassy_executor::Spawner;
11use embassy_nrf::interrupt;
12use embassy_nrf::twim::{self, Twim}; 11use embassy_nrf::twim::{self, Twim};
12use embassy_nrf::{bind_interrupts, peripherals};
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
15const ADDRESS: u8 = 0x50; 15const ADDRESS: u8 = 0x50;
16 16
17bind_interrupts!(struct Irqs {
18 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>;
19});
20
17#[embassy_executor::main] 21#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
19 let p = embassy_nrf::init(Default::default()); 23 let p = embassy_nrf::init(Default::default());
20 info!("Initializing TWI..."); 24 info!("Initializing TWI...");
21 let config = twim::Config::default(); 25 let config = twim::Config::default();
22 let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); 26 let mut twi = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config);
23 let mut twi = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
24 27
25 info!("Reading..."); 28 info!("Reading...");
26 29
diff --git a/examples/nrf/src/bin/twim_lowpower.rs b/examples/nrf52840/src/bin/twim_lowpower.rs
index e30cc9688..0970d3c3c 100644
--- a/examples/nrf/src/bin/twim_lowpower.rs
+++ b/examples/nrf52840/src/bin/twim_lowpower.rs
@@ -12,25 +12,28 @@ use core::mem;
12 12
13use defmt::*; 13use defmt::*;
14use embassy_executor::Spawner; 14use embassy_executor::Spawner;
15use embassy_nrf::interrupt;
16use embassy_nrf::twim::{self, Twim}; 15use embassy_nrf::twim::{self, Twim};
16use embassy_nrf::{bind_interrupts, peripherals};
17use embassy_time::{Duration, Timer}; 17use embassy_time::{Duration, Timer};
18use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
19 19
20const ADDRESS: u8 = 0x50; 20const ADDRESS: u8 = 0x50;
21 21
22bind_interrupts!(struct Irqs {
23 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>;
24});
25
22#[embassy_executor::main] 26#[embassy_executor::main]
23async fn main(_p: Spawner) { 27async fn main(_p: Spawner) {
24 let mut p = embassy_nrf::init(Default::default()); 28 let mut p = embassy_nrf::init(Default::default());
25 info!("Started!"); 29 info!("Started!");
26 let mut irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
27 30
28 loop { 31 loop {
29 info!("Initializing TWI..."); 32 info!("Initializing TWI...");
30 let config = twim::Config::default(); 33 let config = twim::Config::default();
31 34
32 // Create the TWIM instance with borrowed singletons, so they're not consumed. 35 // Create the TWIM instance with borrowed singletons, so they're not consumed.
33 let mut twi = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config); 36 let mut twi = Twim::new(&mut p.TWISPI0, Irqs, &mut p.P0_03, &mut p.P0_04, config);
34 37
35 info!("Reading..."); 38 info!("Reading...");
36 39
diff --git a/examples/nrf52840/src/bin/twis.rs b/examples/nrf52840/src/bin/twis.rs
new file mode 100644
index 000000000..aa42b679e
--- /dev/null
+++ b/examples/nrf52840/src/bin/twis.rs
@@ -0,0 +1,48 @@
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::twis::{self, Command, Twis};
10use embassy_nrf::{bind_interrupts, peripherals};
11use {defmt_rtt as _, panic_probe as _};
12
13bind_interrupts!(struct Irqs {
14 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twis::InterruptHandler<peripherals::TWISPI0>;
15});
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_nrf::init(Default::default());
20
21 let mut config = twis::Config::default();
22 config.address0 = 0x55; // Set i2c address
23 let mut i2c = Twis::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config);
24
25 info!("Listening...");
26 loop {
27 let response = [1, 2, 3, 4, 5, 6, 7, 8];
28 // This buffer is used if the i2c master performs a Write or WriteRead
29 let mut buf = [0u8; 16];
30 match i2c.listen(&mut buf).await {
31 Ok(Command::Read) => {
32 info!("Got READ command. Respond with data:\n{:?}\n", response);
33 if let Err(e) = i2c.respond_to_read(&response).await {
34 error!("{:?}", e);
35 }
36 }
37 Ok(Command::Write(n)) => info!("Got WRITE command with data:\n{:?}\n", buf[..n]),
38 Ok(Command::WriteRead(n)) => {
39 info!("Got WRITE/READ command with data:\n{:?}", buf[..n]);
40 info!("Respond with data:\n{:?}\n", response);
41 if let Err(e) = i2c.respond_to_read(&response).await {
42 error!("{:?}", e);
43 }
44 }
45 Err(e) => error!("{:?}", e),
46 }
47 }
48}
diff --git a/examples/nrf/src/bin/uart.rs b/examples/nrf52840/src/bin/uart.rs
index 600f7a6ef..50d5cab8c 100644
--- a/examples/nrf/src/bin/uart.rs
+++ b/examples/nrf52840/src/bin/uart.rs
@@ -4,9 +4,13 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::{interrupt, uarte}; 7use embassy_nrf::{bind_interrupts, peripherals, uarte};
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10bind_interrupts!(struct Irqs {
11 UARTE0_UART0 => uarte::InterruptHandler<peripherals::UARTE0>;
12});
13
10#[embassy_executor::main] 14#[embassy_executor::main]
11async fn main(_spawner: Spawner) { 15async fn main(_spawner: Spawner) {
12 let p = embassy_nrf::init(Default::default()); 16 let p = embassy_nrf::init(Default::default());
@@ -14,8 +18,7 @@ async fn main(_spawner: Spawner) {
14 config.parity = uarte::Parity::EXCLUDED; 18 config.parity = uarte::Parity::EXCLUDED;
15 config.baudrate = uarte::Baudrate::BAUD115200; 19 config.baudrate = uarte::Baudrate::BAUD115200;
16 20
17 let irq = interrupt::take!(UARTE0_UART0); 21 let mut uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config);
18 let mut uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
19 22
20 info!("uarte initialized!"); 23 info!("uarte initialized!");
21 24
diff --git a/examples/nrf52840/src/bin/uart_idle.rs b/examples/nrf52840/src/bin/uart_idle.rs
new file mode 100644
index 000000000..e1f42fa6c
--- /dev/null
+++ b/examples/nrf52840/src/bin/uart_idle.rs
@@ -0,0 +1,39 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_nrf::peripherals::UARTE0;
8use embassy_nrf::{bind_interrupts, uarte};
9use {defmt_rtt as _, panic_probe as _};
10
11bind_interrupts!(struct Irqs {
12 UARTE0_UART0 => uarte::InterruptHandler<UARTE0>;
13});
14
15#[embassy_executor::main]
16async fn main(_spawner: Spawner) {
17 let p = embassy_nrf::init(Default::default());
18 let mut config = uarte::Config::default();
19 config.parity = uarte::Parity::EXCLUDED;
20 config.baudrate = uarte::Baudrate::BAUD115200;
21
22 let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config);
23 let (mut tx, mut rx) = uart.split_with_idle(p.TIMER0, p.PPI_CH0, p.PPI_CH1);
24
25 info!("uarte initialized!");
26
27 // Message must be in SRAM
28 let mut buf = [0; 8];
29 buf.copy_from_slice(b"Hello!\r\n");
30
31 unwrap!(tx.write(&buf).await);
32 info!("wrote hello in uart!");
33
34 loop {
35 info!("reading...");
36 let n = unwrap!(rx.read_until_idle(&mut buf).await);
37 info!("got {} bytes", n);
38 }
39}
diff --git a/examples/nrf/src/bin/uart_split.rs b/examples/nrf52840/src/bin/uart_split.rs
index 1adaf53fd..9979a1d53 100644
--- a/examples/nrf/src/bin/uart_split.rs
+++ b/examples/nrf52840/src/bin/uart_split.rs
@@ -6,13 +6,17 @@ use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::peripherals::UARTE0; 7use embassy_nrf::peripherals::UARTE0;
8use embassy_nrf::uarte::UarteRx; 8use embassy_nrf::uarte::UarteRx;
9use embassy_nrf::{interrupt, uarte}; 9use embassy_nrf::{bind_interrupts, uarte};
10use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 10use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
11use embassy_sync::channel::Channel; 11use embassy_sync::channel::Channel;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
14static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); 14static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
15 15
16bind_interrupts!(struct Irqs {
17 UARTE0_UART0 => uarte::InterruptHandler<UARTE0>;
18});
19
16#[embassy_executor::main] 20#[embassy_executor::main]
17async fn main(spawner: Spawner) { 21async fn main(spawner: Spawner) {
18 let p = embassy_nrf::init(Default::default()); 22 let p = embassy_nrf::init(Default::default());
@@ -20,8 +24,7 @@ async fn main(spawner: Spawner) {
20 config.parity = uarte::Parity::EXCLUDED; 24 config.parity = uarte::Parity::EXCLUDED;
21 config.baudrate = uarte::Baudrate::BAUD115200; 25 config.baudrate = uarte::Baudrate::BAUD115200;
22 26
23 let irq = interrupt::take!(UARTE0_UART0); 27 let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config);
24 let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
25 let (mut tx, rx) = uart.split(); 28 let (mut tx, rx) = uart.split();
26 29
27 info!("uarte initialized!"); 30 info!("uarte initialized!");
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs
new file mode 100644
index 000000000..f527c0d7f
--- /dev/null
+++ b/examples/nrf52840/src/bin/usb_ethernet.rs
@@ -0,0 +1,165 @@
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::vbus_detect::HardwareVbusDetect;
13use embassy_nrf::usb::Driver;
14use embassy_nrf::{bind_interrupts, pac, peripherals, rng, usb};
15use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
16use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
17use embassy_usb::{Builder, Config, UsbDevice};
18use embedded_io::asynch::Write;
19use static_cell::make_static;
20use {defmt_rtt as _, panic_probe as _};
21
22bind_interrupts!(struct Irqs {
23 USBD => usb::InterruptHandler<peripherals::USBD>;
24 POWER_CLOCK => usb::vbus_detect::InterruptHandler;
25 RNG => rng::InterruptHandler<peripherals::RNG>;
26});
27
28type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
29
30const MTU: usize = 1514;
31
32#[embassy_executor::task]
33async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! {
34 device.run().await
35}
36
37#[embassy_executor::task]
38async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
39 class.run().await
40}
41
42#[embassy_executor::task]
43async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
44 stack.run().await
45}
46
47#[embassy_executor::main]
48async fn main(spawner: Spawner) {
49 let p = embassy_nrf::init(Default::default());
50 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
51
52 info!("Enabling ext hfosc...");
53 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
54 while clock.events_hfclkstarted.read().bits() != 1 {}
55
56 // Create the driver, from the HAL.
57 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
58
59 // Create embassy-usb Config
60 let mut config = Config::new(0xc0de, 0xcafe);
61 config.manufacturer = Some("Embassy");
62 config.product = Some("USB-Ethernet example");
63 config.serial_number = Some("12345678");
64 config.max_power = 100;
65 config.max_packet_size_0 = 64;
66
67 // Required for Windows support.
68 config.composite_with_iads = true;
69 config.device_class = 0xEF;
70 config.device_sub_class = 0x02;
71 config.device_protocol = 0x01;
72
73 // Create embassy-usb DeviceBuilder using the driver and config.
74 let mut builder = Builder::new(
75 driver,
76 config,
77 &mut make_static!([0; 256])[..],
78 &mut make_static!([0; 256])[..],
79 &mut make_static!([0; 256])[..],
80 &mut make_static!([0; 128])[..],
81 &mut make_static!([0; 128])[..],
82 );
83
84 // Our MAC addr.
85 let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC];
86 // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has.
87 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
88
89 // Create classes on the builder.
90 let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64);
91
92 // Build the builder.
93 let usb = builder.build();
94
95 unwrap!(spawner.spawn(usb_task(usb)));
96
97 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr);
98 unwrap!(spawner.spawn(usb_ncm_task(runner)));
99
100 let config = embassy_net::Config::dhcpv4(Default::default());
101 // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
102 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
103 // dns_servers: Vec::new(),
104 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
105 // });
106
107 // Generate random seed
108 let mut rng = Rng::new(p.RNG, Irqs);
109 let mut seed = [0; 8];
110 rng.blocking_fill_bytes(&mut seed);
111 let seed = u64::from_le_bytes(seed);
112
113 // Init network stack
114 let stack = &*make_static!(Stack::new(
115 device,
116 config,
117 make_static!(StackResources::<2>::new()),
118 seed
119 ));
120
121 unwrap!(spawner.spawn(net_task(stack)));
122
123 // And now we can use it!
124
125 let mut rx_buffer = [0; 4096];
126 let mut tx_buffer = [0; 4096];
127 let mut buf = [0; 4096];
128
129 loop {
130 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
131 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
132
133 info!("Listening on TCP:1234...");
134 if let Err(e) = socket.accept(1234).await {
135 warn!("accept error: {:?}", e);
136 continue;
137 }
138
139 info!("Received connection from {:?}", socket.remote_endpoint());
140
141 loop {
142 let n = match socket.read(&mut buf).await {
143 Ok(0) => {
144 warn!("read EOF");
145 break;
146 }
147 Ok(n) => n,
148 Err(e) => {
149 warn!("read error: {:?}", e);
150 break;
151 }
152 };
153
154 info!("rxd {:02x}", &buf[..n]);
155
156 match socket.write_all(&buf[..n]).await {
157 Ok(()) => {}
158 Err(e) => {
159 warn!("write error: {:?}", e);
160 break;
161 }
162 };
163 }
164 }
165}
diff --git a/examples/nrf/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
index ba2159c72..7ccd2946a 100644
--- a/examples/nrf/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
5 4
6use core::mem; 5use core::mem;
@@ -8,18 +7,25 @@ use core::sync::atomic::{AtomicBool, Ordering};
8 7
9use defmt::*; 8use defmt::*;
10use embassy_executor::Spawner; 9use embassy_executor::Spawner;
11use embassy_futures::{select, Either}; 10use embassy_futures::join::join;
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::vbus_detect::HardwareVbusDetect;
14use embassy_nrf::{interrupt, pac}; 14use embassy_nrf::usb::Driver;
15use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
16use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
15use embassy_sync::signal::Signal; 17use embassy_sync::signal::Signal;
18use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
16use embassy_usb::control::OutResponse; 19use embassy_usb::control::OutResponse;
17use embassy_usb::{Builder, Config, DeviceStateHandler}; 20use embassy_usb::{Builder, Config, Handler};
18use embassy_usb_hid::{HidReaderWriter, ReportId, RequestHandler, State};
19use futures::future::join;
20use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 21use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
21use {defmt_rtt as _, panic_probe as _}; 22use {defmt_rtt as _, panic_probe as _};
22 23
24bind_interrupts!(struct Irqs {
25 USBD => usb::InterruptHandler<peripherals::USBD>;
26 POWER_CLOCK => usb::vbus_detect::InterruptHandler;
27});
28
23static SUSPENDED: AtomicBool = AtomicBool::new(false); 29static SUSPENDED: AtomicBool = AtomicBool::new(false);
24 30
25#[embassy_executor::main] 31#[embassy_executor::main]
@@ -32,9 +38,7 @@ async fn main(_spawner: Spawner) {
32 while clock.events_hfclkstarted.read().bits() != 1 {} 38 while clock.events_hfclkstarted.read().bits() != 1 {}
33 39
34 // Create the driver, from the HAL. 40 // Create the driver, from the HAL.
35 let irq = interrupt::take!(USBD); 41 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
36 let power_irq = interrupt::take!(POWER_CLOCK);
37 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq));
38 42
39 // Create embassy-usb Config 43 // Create embassy-usb Config
40 let mut config = Config::new(0xc0de, 0xcafe); 44 let mut config = Config::new(0xc0de, 0xcafe);
@@ -50,9 +54,10 @@ async fn main(_spawner: Spawner) {
50 let mut device_descriptor = [0; 256]; 54 let mut device_descriptor = [0; 256];
51 let mut config_descriptor = [0; 256]; 55 let mut config_descriptor = [0; 256];
52 let mut bos_descriptor = [0; 256]; 56 let mut bos_descriptor = [0; 256];
57 let mut msos_descriptor = [0; 256];
53 let mut control_buf = [0; 64]; 58 let mut control_buf = [0; 64];
54 let request_handler = MyRequestHandler {}; 59 let request_handler = MyRequestHandler {};
55 let device_state_handler = MyDeviceStateHandler::new(); 60 let mut device_handler = MyDeviceHandler::new();
56 61
57 let mut state = State::new(); 62 let mut state = State::new();
58 63
@@ -62,12 +67,14 @@ async fn main(_spawner: Spawner) {
62 &mut device_descriptor, 67 &mut device_descriptor,
63 &mut config_descriptor, 68 &mut config_descriptor,
64 &mut bos_descriptor, 69 &mut bos_descriptor,
70 &mut msos_descriptor,
65 &mut control_buf, 71 &mut control_buf,
66 Some(&device_state_handler),
67 ); 72 );
68 73
74 builder.handler(&mut device_handler);
75
69 // Create classes on the builder. 76 // Create classes on the builder.
70 let config = embassy_usb_hid::Config { 77 let config = embassy_usb::class::hid::Config {
71 report_descriptor: KeyboardReport::desc(), 78 report_descriptor: KeyboardReport::desc(),
72 request_handler: Some(&request_handler), 79 request_handler: Some(&request_handler),
73 poll_ms: 60, 80 poll_ms: 60,
@@ -78,7 +85,7 @@ async fn main(_spawner: Spawner) {
78 // Build the builder. 85 // Build the builder.
79 let mut usb = builder.build(); 86 let mut usb = builder.build();
80 87
81 let remote_wakeup = Signal::new(); 88 let remote_wakeup: Signal<CriticalSectionRawMutex, _> = Signal::new();
82 89
83 // Run the USB device. 90 // Run the USB device.
84 let usb_fut = async { 91 let usb_fut = async {
@@ -164,20 +171,20 @@ impl RequestHandler for MyRequestHandler {
164 } 171 }
165} 172}
166 173
167struct MyDeviceStateHandler { 174struct MyDeviceHandler {
168 configured: AtomicBool, 175 configured: AtomicBool,
169} 176}
170 177
171impl MyDeviceStateHandler { 178impl MyDeviceHandler {
172 fn new() -> Self { 179 fn new() -> Self {
173 MyDeviceStateHandler { 180 MyDeviceHandler {
174 configured: AtomicBool::new(false), 181 configured: AtomicBool::new(false),
175 } 182 }
176 } 183 }
177} 184}
178 185
179impl DeviceStateHandler for MyDeviceStateHandler { 186impl Handler for MyDeviceHandler {
180 fn enabled(&self, enabled: bool) { 187 fn enabled(&mut self, enabled: bool) {
181 self.configured.store(false, Ordering::Relaxed); 188 self.configured.store(false, Ordering::Relaxed);
182 SUSPENDED.store(false, Ordering::Release); 189 SUSPENDED.store(false, Ordering::Release);
183 if enabled { 190 if enabled {
@@ -187,17 +194,17 @@ impl DeviceStateHandler for MyDeviceStateHandler {
187 } 194 }
188 } 195 }
189 196
190 fn reset(&self) { 197 fn reset(&mut self) {
191 self.configured.store(false, Ordering::Relaxed); 198 self.configured.store(false, Ordering::Relaxed);
192 info!("Bus reset, the Vbus current limit is 100mA"); 199 info!("Bus reset, the Vbus current limit is 100mA");
193 } 200 }
194 201
195 fn addressed(&self, addr: u8) { 202 fn addressed(&mut self, addr: u8) {
196 self.configured.store(false, Ordering::Relaxed); 203 self.configured.store(false, Ordering::Relaxed);
197 info!("USB address set to: {}", addr); 204 info!("USB address set to: {}", addr);
198 } 205 }
199 206
200 fn configured(&self, configured: bool) { 207 fn configured(&mut self, configured: bool) {
201 self.configured.store(configured, Ordering::Relaxed); 208 self.configured.store(configured, Ordering::Relaxed);
202 if configured { 209 if configured {
203 info!("Device configured, it may now draw up to the configured current limit from Vbus.") 210 info!("Device configured, it may now draw up to the configured current limit from Vbus.")
@@ -206,7 +213,7 @@ impl DeviceStateHandler for MyDeviceStateHandler {
206 } 213 }
207 } 214 }
208 215
209 fn suspended(&self, suspended: bool) { 216 fn suspended(&mut self, suspended: bool) {
210 if suspended { 217 if suspended {
211 info!("Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled)."); 218 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); 219 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 7cd2ece17..edf634a5e 100644
--- a/examples/nrf/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs
@@ -1,22 +1,27 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
5 4
6use core::mem; 5use core::mem;
7 6
8use defmt::*; 7use defmt::*;
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
10use embassy_nrf::usb::{Driver, PowerUsb}; 9use embassy_futures::join::join;
11use embassy_nrf::{interrupt, pac}; 10use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
11use embassy_nrf::usb::Driver;
12use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
12use embassy_time::{Duration, Timer}; 13use embassy_time::{Duration, Timer};
14use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
13use embassy_usb::control::OutResponse; 15use embassy_usb::control::OutResponse;
14use embassy_usb::{Builder, Config}; 16use embassy_usb::{Builder, Config};
15use embassy_usb_hid::{HidWriter, ReportId, RequestHandler, State};
16use futures::future::join;
17use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; 17use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
18use {defmt_rtt as _, panic_probe as _}; 18use {defmt_rtt as _, panic_probe as _};
19 19
20bind_interrupts!(struct Irqs {
21 USBD => usb::InterruptHandler<peripherals::USBD>;
22 POWER_CLOCK => usb::vbus_detect::InterruptHandler;
23});
24
20#[embassy_executor::main] 25#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 26async fn main(_spawner: Spawner) {
22 let p = embassy_nrf::init(Default::default()); 27 let p = embassy_nrf::init(Default::default());
@@ -27,9 +32,7 @@ async fn main(_spawner: Spawner) {
27 while clock.events_hfclkstarted.read().bits() != 1 {} 32 while clock.events_hfclkstarted.read().bits() != 1 {}
28 33
29 // Create the driver, from the HAL. 34 // Create the driver, from the HAL.
30 let irq = interrupt::take!(USBD); 35 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
31 let power_irq = interrupt::take!(POWER_CLOCK);
32 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq));
33 36
34 // Create embassy-usb Config 37 // Create embassy-usb Config
35 let mut config = Config::new(0xc0de, 0xcafe); 38 let mut config = Config::new(0xc0de, 0xcafe);
@@ -44,6 +47,7 @@ async fn main(_spawner: Spawner) {
44 let mut device_descriptor = [0; 256]; 47 let mut device_descriptor = [0; 256];
45 let mut config_descriptor = [0; 256]; 48 let mut config_descriptor = [0; 256];
46 let mut bos_descriptor = [0; 256]; 49 let mut bos_descriptor = [0; 256];
50 let mut msos_descriptor = [0; 256];
47 let mut control_buf = [0; 64]; 51 let mut control_buf = [0; 64];
48 let request_handler = MyRequestHandler {}; 52 let request_handler = MyRequestHandler {};
49 53
@@ -55,12 +59,12 @@ async fn main(_spawner: Spawner) {
55 &mut device_descriptor, 59 &mut device_descriptor,
56 &mut config_descriptor, 60 &mut config_descriptor,
57 &mut bos_descriptor, 61 &mut bos_descriptor,
62 &mut msos_descriptor,
58 &mut control_buf, 63 &mut control_buf,
59 None,
60 ); 64 );
61 65
62 // Create classes on the builder. 66 // Create classes on the builder.
63 let config = embassy_usb_hid::Config { 67 let config = embassy_usb::class::hid::Config {
64 report_descriptor: MouseReport::desc(), 68 report_descriptor: MouseReport::desc(),
65 request_handler: Some(&request_handler), 69 request_handler: Some(&request_handler),
66 poll_ms: 60, 70 poll_ms: 60,
diff --git a/examples/nrf/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs
index a68edb329..dc95cde84 100644
--- a/examples/nrf/src/bin/usb_serial.rs
+++ b/examples/nrf52840/src/bin/usb_serial.rs
@@ -1,20 +1,25 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
5 4
6use core::mem; 5use core::mem;
7 6
8use defmt::{info, panic}; 7use defmt::{info, panic};
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
10use embassy_nrf::usb::{Driver, Instance, PowerUsb, UsbSupply}; 9use embassy_futures::join::join;
11use embassy_nrf::{interrupt, pac}; 10use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect};
11use embassy_nrf::usb::{Driver, Instance};
12use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
13use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError; 14use embassy_usb::driver::EndpointError;
13use embassy_usb::{Builder, Config}; 15use embassy_usb::{Builder, Config};
14use embassy_usb_serial::{CdcAcmClass, State};
15use futures::future::join;
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
17 17
18bind_interrupts!(struct Irqs {
19 USBD => usb::InterruptHandler<peripherals::USBD>;
20 POWER_CLOCK => usb::vbus_detect::InterruptHandler;
21});
22
18#[embassy_executor::main] 23#[embassy_executor::main]
19async fn main(_spawner: Spawner) { 24async fn main(_spawner: Spawner) {
20 let p = embassy_nrf::init(Default::default()); 25 let p = embassy_nrf::init(Default::default());
@@ -25,9 +30,7 @@ async fn main(_spawner: Spawner) {
25 while clock.events_hfclkstarted.read().bits() != 1 {} 30 while clock.events_hfclkstarted.read().bits() != 1 {}
26 31
27 // Create the driver, from the HAL. 32 // Create the driver, from the HAL.
28 let irq = interrupt::take!(USBD); 33 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
29 let power_irq = interrupt::take!(POWER_CLOCK);
30 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq));
31 34
32 // Create embassy-usb Config 35 // Create embassy-usb Config
33 let mut config = Config::new(0xc0de, 0xcafe); 36 let mut config = Config::new(0xc0de, 0xcafe);
@@ -37,7 +40,7 @@ async fn main(_spawner: Spawner) {
37 config.max_power = 100; 40 config.max_power = 100;
38 config.max_packet_size_0 = 64; 41 config.max_packet_size_0 = 64;
39 42
40 // Required for windows compatiblity. 43 // Required for windows compatibility.
41 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help 44 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
42 config.device_class = 0xEF; 45 config.device_class = 0xEF;
43 config.device_sub_class = 0x02; 46 config.device_sub_class = 0x02;
@@ -49,6 +52,7 @@ async fn main(_spawner: Spawner) {
49 let mut device_descriptor = [0; 256]; 52 let mut device_descriptor = [0; 256];
50 let mut config_descriptor = [0; 256]; 53 let mut config_descriptor = [0; 256];
51 let mut bos_descriptor = [0; 256]; 54 let mut bos_descriptor = [0; 256];
55 let mut msos_descriptor = [0; 256];
52 let mut control_buf = [0; 64]; 56 let mut control_buf = [0; 64];
53 57
54 let mut state = State::new(); 58 let mut state = State::new();
@@ -59,8 +63,8 @@ async fn main(_spawner: Spawner) {
59 &mut device_descriptor, 63 &mut device_descriptor,
60 &mut config_descriptor, 64 &mut config_descriptor,
61 &mut bos_descriptor, 65 &mut bos_descriptor,
66 &mut msos_descriptor,
62 &mut control_buf, 67 &mut control_buf,
63 None,
64 ); 68 );
65 69
66 // Create classes on the builder. 70 // Create classes on the builder.
@@ -98,7 +102,7 @@ impl From<EndpointError> for Disconnected {
98 } 102 }
99} 103}
100 104
101async fn echo<'d, T: Instance + 'd, P: UsbSupply + 'd>( 105async fn echo<'d, T: Instance + 'd, P: VbusDetect + 'd>(
102 class: &mut CdcAcmClass<'d, Driver<'d, T, P>>, 106 class: &mut CdcAcmClass<'d, Driver<'d, T, P>>,
103) -> Result<(), Disconnected> { 107) -> Result<(), Disconnected> {
104 let mut buf = [0; 64]; 108 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 d62d7e520..cd4392903 100644
--- a/examples/nrf/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs
@@ -1,21 +1,26 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
5 4
6use core::mem; 5use core::mem;
7 6
8use defmt::{info, panic, unwrap}; 7use defmt::{info, panic, unwrap};
9use embassy_executor::Spawner; 8use embassy_executor::Spawner;
10use embassy_nrf::usb::{Driver, PowerUsb}; 9use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
11use embassy_nrf::{interrupt, pac, peripherals}; 10use embassy_nrf::usb::Driver;
11use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
12use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError; 13use embassy_usb::driver::EndpointError;
13use embassy_usb::{Builder, Config, UsbDevice}; 14use embassy_usb::{Builder, Config, UsbDevice};
14use embassy_usb_serial::{CdcAcmClass, State}; 15use static_cell::make_static;
15use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
17 17
18type MyDriver = Driver<'static, peripherals::USBD, PowerUsb>; 18bind_interrupts!(struct Irqs {
19 USBD => usb::InterruptHandler<peripherals::USBD>;
20 POWER_CLOCK => usb::vbus_detect::InterruptHandler;
21});
22
23type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>;
19 24
20#[embassy_executor::task] 25#[embassy_executor::task]
21async fn usb_task(mut device: UsbDevice<'static, MyDriver>) { 26async fn usb_task(mut device: UsbDevice<'static, MyDriver>) {
@@ -40,10 +45,9 @@ async fn main(spawner: Spawner) {
40 info!("Enabling ext hfosc..."); 45 info!("Enabling ext hfosc...");
41 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 46 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
42 while clock.events_hfclkstarted.read().bits() != 1 {} 47 while clock.events_hfclkstarted.read().bits() != 1 {}
48
43 // Create the driver, from the HAL. 49 // Create the driver, from the HAL.
44 let irq = interrupt::take!(USBD); 50 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
45 let power_irq = interrupt::take!(POWER_CLOCK);
46 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq));
47 51
48 // Create embassy-usb Config 52 // Create embassy-usb Config
49 let mut config = Config::new(0xc0de, 0xcafe); 53 let mut config = Config::new(0xc0de, 0xcafe);
@@ -53,42 +57,28 @@ async fn main(spawner: Spawner) {
53 config.max_power = 100; 57 config.max_power = 100;
54 config.max_packet_size_0 = 64; 58 config.max_packet_size_0 = 64;
55 59
56 // Required for windows compatiblity. 60 // Required for windows compatibility.
57 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help 61 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
58 config.device_class = 0xEF; 62 config.device_class = 0xEF;
59 config.device_sub_class = 0x02; 63 config.device_sub_class = 0x02;
60 config.device_protocol = 0x01; 64 config.device_protocol = 0x01;
61 config.composite_with_iads = true; 65 config.composite_with_iads = true;
62 66
63 struct Resources { 67 let state = make_static!(State::new());
64 device_descriptor: [u8; 256],
65 config_descriptor: [u8; 256],
66 bos_descriptor: [u8; 256],
67 control_buf: [u8; 64],
68 serial_state: State<'static>,
69 }
70 static RESOURCES: StaticCell<Resources> = StaticCell::new();
71 let res = RESOURCES.init(Resources {
72 device_descriptor: [0; 256],
73 config_descriptor: [0; 256],
74 bos_descriptor: [0; 256],
75 control_buf: [0; 64],
76 serial_state: State::new(),
77 });
78 68
79 // Create embassy-usb DeviceBuilder using the driver and config. 69 // Create embassy-usb DeviceBuilder using the driver and config.
80 let mut builder = Builder::new( 70 let mut builder = Builder::new(
81 driver, 71 driver,
82 config, 72 config,
83 &mut res.device_descriptor, 73 &mut make_static!([0; 256])[..],
84 &mut res.config_descriptor, 74 &mut make_static!([0; 256])[..],
85 &mut res.bos_descriptor, 75 &mut make_static!([0; 256])[..],
86 &mut res.control_buf, 76 &mut make_static!([0; 128])[..],
87 None, 77 &mut make_static!([0; 128])[..],
88 ); 78 );
89 79
90 // Create classes on the builder. 80 // Create classes on the builder.
91 let class = CdcAcmClass::new(&mut builder, &mut res.serial_state, 64); 81 let class = CdcAcmClass::new(&mut builder, state, 64);
92 82
93 // Build the builder. 83 // Build the builder.
94 let usb = builder.build(); 84 let usb = builder.build();
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..1d39d3841
--- /dev/null
+++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs
@@ -0,0 +1,134 @@
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::vbus_detect::{HardwareVbusDetect, VbusDetect};
11use embassy_nrf::usb::{Driver, Instance};
12use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
13use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
14use embassy_usb::driver::EndpointError;
15use embassy_usb::msos::{self, windows_version};
16use embassy_usb::types::InterfaceNumber;
17use embassy_usb::{Builder, Config};
18use {defmt_rtt as _, panic_probe as _};
19
20bind_interrupts!(struct Irqs {
21 USBD => usb::InterruptHandler<peripherals::USBD>;
22 POWER_CLOCK => usb::vbus_detect::InterruptHandler;
23});
24
25// This is a randomly generated GUID to allow clients on Windows to find our device
26const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"];
27
28#[embassy_executor::main]
29async fn main(_spawner: Spawner) {
30 let p = embassy_nrf::init(Default::default());
31 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
32
33 info!("Enabling ext hfosc...");
34 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
35 while clock.events_hfclkstarted.read().bits() != 1 {}
36
37 // Create the driver, from the HAL.
38 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
39
40 // Create embassy-usb Config
41 let mut config = Config::new(0xc0de, 0xcafe);
42 config.manufacturer = Some("Embassy");
43 config.product = Some("USB-serial example");
44 config.serial_number = Some("12345678");
45 config.max_power = 100;
46 config.max_packet_size_0 = 64;
47
48 // Required for windows compatibility.
49 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
50 config.device_class = 0xEF;
51 config.device_sub_class = 0x02;
52 config.device_protocol = 0x01;
53 config.composite_with_iads = true;
54
55 // Create embassy-usb DeviceBuilder using the driver and config.
56 // It needs some buffers for building the descriptors.
57 let mut device_descriptor = [0; 256];
58 let mut config_descriptor = [0; 256];
59 let mut bos_descriptor = [0; 256];
60 let mut msos_descriptor = [0; 256];
61 let mut control_buf = [0; 64];
62
63 let mut state = State::new();
64
65 let mut builder = Builder::new(
66 driver,
67 config,
68 &mut device_descriptor,
69 &mut config_descriptor,
70 &mut bos_descriptor,
71 &mut msos_descriptor,
72 &mut control_buf,
73 );
74
75 builder.msos_descriptor(windows_version::WIN8_1, 2);
76
77 // Create classes on the builder.
78 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
79
80 // Since we want to create MS OS feature descriptors that apply to a function that has already been added to the
81 // builder, need to get the MsOsDescriptorWriter from the builder and manually add those descriptors.
82 // Inside a class constructor, you would just need to call `FunctionBuilder::msos_feature` instead.
83 let msos_writer = builder.msos_writer();
84 msos_writer.configuration(0);
85 msos_writer.function(InterfaceNumber(0));
86 msos_writer.function_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
87 msos_writer.function_feature(msos::RegistryPropertyFeatureDescriptor::new(
88 "DeviceInterfaceGUIDs",
89 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
90 ));
91
92 // Build the builder.
93 let mut usb = builder.build();
94
95 // Run the USB device.
96 let usb_fut = usb.run();
97
98 // Do stuff with the class!
99 let echo_fut = async {
100 loop {
101 class.wait_connection().await;
102 info!("Connected");
103 let _ = echo(&mut class).await;
104 info!("Disconnected");
105 }
106 };
107
108 // Run everything concurrently.
109 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
110 join(usb_fut, echo_fut).await;
111}
112
113struct Disconnected {}
114
115impl From<EndpointError> for Disconnected {
116 fn from(val: EndpointError) -> Self {
117 match val {
118 EndpointError::BufferOverflow => panic!("Buffer overflow"),
119 EndpointError::Disabled => Disconnected {},
120 }
121 }
122}
123
124async fn echo<'d, T: Instance + 'd, P: VbusDetect + 'd>(
125 class: &mut CdcAcmClass<'d, Driver<'d, T, P>>,
126) -> Result<(), Disconnected> {
127 let mut buf = [0; 64];
128 loop {
129 let n = class.read_packet(&mut buf).await?;
130 let data = &buf[..n];
131 info!("data: {:x}", data);
132 class.write_packet(data).await?;
133 }
134}
diff --git a/examples/nrf/src/bin/wdt.rs b/examples/nrf52840/src/bin/wdt.rs
index b0b9c3b81..058746518 100644
--- a/examples/nrf/src/bin/wdt.rs
+++ b/examples/nrf52840/src/bin/wdt.rs
@@ -16,7 +16,7 @@ async fn main(_spawner: Spawner) {
16 let mut config = Config::default(); 16 let mut config = Config::default();
17 config.timeout_ticks = 32768 * 3; // 3 seconds 17 config.timeout_ticks = 32768 * 3; // 3 seconds
18 18
19 // This is needed for `probe-run` to be able to catch the panic message 19 // This is needed for `probe-rs run` to be able to catch the panic message
20 // in the WDT interrupt. The core resets 2 ticks after firing the interrupt. 20 // in the WDT interrupt. The core resets 2 ticks after firing the interrupt.
21 config.run_during_debug_halt = false; 21 config.run_during_debug_halt = false;
22 22
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
new file mode 100644
index 000000000..112e41bcd
--- /dev/null
+++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
@@ -0,0 +1,143 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{info, unwrap, warn};
6use embassy_executor::Spawner;
7use embassy_net::tcp::TcpSocket;
8use embassy_net::{Stack, StackResources};
9use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull};
10use embassy_nrf::rng::Rng;
11use embassy_nrf::spim::{self, Spim};
12use embassy_nrf::{bind_interrupts, peripherals};
13use embassy_time::Delay;
14use embedded_hal_async::spi::ExclusiveDevice;
15use embedded_io::asynch::Write;
16use static_cell::make_static;
17use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _};
18
19const WIFI_NETWORK: &str = "EmbassyTest";
20const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
21
22bind_interrupts!(struct Irqs {
23 SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
24 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>;
25});
26
27#[embassy_executor::task]
28async fn wifi_task(
29 runner: hosted::Runner<
30 'static,
31 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static, peripherals::P0_31>, Delay>,
32 Input<'static, AnyPin>,
33 Output<'static, peripherals::P1_05>,
34 >,
35) -> ! {
36 runner.run().await
37}
38
39#[embassy_executor::task]
40async fn net_task(stack: &'static Stack<hosted::NetDriver<'static>>) -> ! {
41 stack.run().await
42}
43
44#[embassy_executor::main]
45async fn main(spawner: Spawner) {
46 info!("Hello World!");
47
48 let p = embassy_nrf::init(Default::default());
49
50 let miso = p.P0_28;
51 let sck = p.P0_29;
52 let mosi = p.P0_30;
53 let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive);
54 let handshake = Input::new(p.P1_01.degrade(), Pull::Up);
55 let ready = Input::new(p.P1_04.degrade(), Pull::None);
56 let reset = Output::new(p.P1_05, Level::Low, OutputDrive::Standard);
57
58 let mut config = spim::Config::default();
59 config.frequency = spim::Frequency::M32;
60 config.mode = spim::MODE_2; // !!!
61 let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config);
62 let spi = ExclusiveDevice::new(spi, cs, Delay);
63
64 let (device, mut control, runner) = embassy_net_esp_hosted::new(
65 make_static!(embassy_net_esp_hosted::State::new()),
66 spi,
67 handshake,
68 ready,
69 reset,
70 )
71 .await;
72
73 unwrap!(spawner.spawn(wifi_task(runner)));
74
75 control.init().await;
76 control.join(WIFI_NETWORK, WIFI_PASSWORD).await;
77
78 let config = embassy_net::Config::dhcpv4(Default::default());
79 // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
80 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
81 // dns_servers: Vec::new(),
82 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
83 // });
84
85 // Generate random seed
86 let mut rng = Rng::new(p.RNG, Irqs);
87 let mut seed = [0; 8];
88 rng.blocking_fill_bytes(&mut seed);
89 let seed = u64::from_le_bytes(seed);
90
91 // Init network stack
92 let stack = &*make_static!(Stack::new(
93 device,
94 config,
95 make_static!(StackResources::<2>::new()),
96 seed
97 ));
98
99 unwrap!(spawner.spawn(net_task(stack)));
100
101 // And now we can use it!
102
103 let mut rx_buffer = [0; 4096];
104 let mut tx_buffer = [0; 4096];
105 let mut buf = [0; 4096];
106
107 loop {
108 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
109 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
110
111 info!("Listening on TCP:1234...");
112 if let Err(e) = socket.accept(1234).await {
113 warn!("accept error: {:?}", e);
114 continue;
115 }
116
117 info!("Received connection from {:?}", socket.remote_endpoint());
118
119 loop {
120 let n = match socket.read(&mut buf).await {
121 Ok(0) => {
122 warn!("read EOF");
123 break;
124 }
125 Ok(n) => n,
126 Err(e) => {
127 warn!("read error: {:?}", e);
128 break;
129 }
130 };
131
132 info!("rxd {:02x}", &buf[..n]);
133
134 match socket.write_all(&buf[..n]).await {
135 Ok(()) => {}
136 Err(e) => {
137 warn!("write error: {:?}", e);
138 break;
139 }
140 };
141 }
142 }
143}
diff --git a/examples/nrf5340/.cargo/config.toml b/examples/nrf5340/.cargo/config.toml
new file mode 100644
index 000000000..4c3cf3d32
--- /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-rs chip list`
3runner = "probe-rs 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..f1d45f336
--- /dev/null
+++ b/examples/nrf5340/Cargo.toml
@@ -0,0 +1,55 @@
1[package]
2edition = "2021"
3name = "embassy-nrf5340-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
9embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = [
10 "defmt",
11] }
12embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread",
13 "nightly",
14 "defmt",
15 "integrated-timers",
16] }
17embassy-time = { version = "0.1.2", path = "../../embassy-time", features = [
18 "defmt",
19 "defmt-timestamp-uptime",
20] }
21embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [
22 "nightly",
23 "unstable-traits",
24 "defmt",
25 "nrf5340-app-s",
26 "time-driver-rtc1",
27 "gpiote",
28 "unstable-pac",
29] }
30embassy-net = { version = "0.1.0", path = "../../embassy-net", features = [
31 "nightly",
32 "defmt",
33 "tcp",
34 "dhcpv4",
35 "medium-ethernet",
36] }
37embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = [
38 "defmt",
39] }
40embedded-io = { version = "0.4.0", features = [ "async" ]}
41
42defmt = "0.3"
43defmt-rtt = "0.4"
44
45static_cell = { version = "1.1", features = ["nightly"]}
46cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
47cortex-m-rt = "0.7.0"
48panic-probe = { version = "0.3", features = ["print-defmt"] }
49futures = { version = "0.3.17", default-features = false, features = [
50 "async-await",
51] }
52rand = { version = "0.8.4", default-features = false }
53embedded-storage = "0.3.0"
54usbd-hid = "0.6.0"
55serde = { 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/nrf/src/bin/uart_idle.rs b/examples/nrf5340/src/bin/uart.rs
index 09ec624c0..d68539702 100644
--- a/examples/nrf/src/bin/uart_idle.rs
+++ b/examples/nrf5340/src/bin/uart.rs
@@ -4,9 +4,14 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_nrf::{interrupt, uarte}; 7use embassy_nrf::peripherals::SERIAL0;
8use embassy_nrf::{bind_interrupts, uarte};
8use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
9 10
11bind_interrupts!(struct Irqs {
12 SERIAL0 => uarte::InterruptHandler<SERIAL0>;
13});
14
10#[embassy_executor::main] 15#[embassy_executor::main]
11async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
12 let p = embassy_nrf::init(Default::default()); 17 let p = embassy_nrf::init(Default::default());
@@ -14,8 +19,7 @@ async fn main(_spawner: Spawner) {
14 config.parity = uarte::Parity::EXCLUDED; 19 config.parity = uarte::Parity::EXCLUDED;
15 config.baudrate = uarte::Baudrate::BAUD115200; 20 config.baudrate = uarte::Baudrate::BAUD115200;
16 21
17 let irq = interrupt::take!(UARTE0_UART0); 22 let mut uart = uarte::Uarte::new(p.SERIAL0, Irqs, p.P1_00, p.P1_01, config);
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);
19 23
20 info!("uarte initialized!"); 24 info!("uarte initialized!");
21 25
@@ -28,7 +32,8 @@ async fn main(_spawner: Spawner) {
28 32
29 loop { 33 loop {
30 info!("reading..."); 34 info!("reading...");
31 let n = unwrap!(uart.read_until_idle(&mut buf).await); 35 unwrap!(uart.read(&mut buf).await);
32 info!("got {} bytes", n); 36 info!("writing...");
37 unwrap!(uart.write(&buf).await);
33 } 38 }
34} 39}
diff --git a/examples/rp/.cargo/config.toml b/examples/rp/.cargo/config.toml
index 3d6051389..3d7d61740 100644
--- a/examples/rp/.cargo/config.toml
+++ b/examples/rp/.cargo/config.toml
@@ -1,8 +1,8 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-run --chip RP2040" 2runner = "probe-rs run --chip RP2040"
3 3
4[build] 4[build]
5target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ 5target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
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 d804a660b..c812cb3ee 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -2,18 +2,34 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-rp-examples" 3name = "embassy-rp-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6 7
7[dependencies] 8[dependencies]
8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] }
9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
11embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac"] } 12embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] }
13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] }
16embassy-net-w5500 = { version = "0.1.0", path = "../../embassy-net-w5500", features = ["defmt"] }
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
18embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" }
19embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"] }
20lora-phy = { version = "1" }
21lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"] }
22lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"] }
23cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] }
24cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] }
12 25
13defmt = "0.3" 26defmt = "0.3"
14defmt-rtt = "0.3" 27defmt-rtt = "0.4"
28fixed = "1.23.1"
29fixed-macro = "1.2"
15 30
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 31#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
32cortex-m = { version = "0.7.6", features = ["inline-asm"] }
17cortex-m-rt = "0.7.0" 33cortex-m-rt = "0.7.0"
18panic-probe = { version = "0.3", features = ["print-defmt"] } 34panic-probe = { version = "0.3", features = ["print-defmt"] }
19futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } 35futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] }
@@ -22,6 +38,22 @@ embedded-graphics = "0.7.1"
22st7789 = "0.6.1" 38st7789 = "0.6.1"
23display-interface = "0.4.1" 39display-interface = "0.4.1"
24byte-slice-cast = { version = "1.2.0", default-features = false } 40byte-slice-cast = { version = "1.2.0", default-features = false }
41smart-leds = "0.3.0"
42heapless = "0.7.15"
43usbd-hid = "0.6.1"
25 44
26embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" } 45embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" }
27embedded-hal-async = { version = "0.1.0-alpha.1" } 46embedded-hal-async = "0.2.0-alpha.2"
47embedded-io = { version = "0.4.0", features = ["async", "defmt"] }
48embedded-storage = { version = "0.3" }
49static_cell = { version = "1.1", features = ["nightly"]}
50log = "0.4"
51pio-proc = "0.2"
52pio = "0.2.1"
53rand = { version = "0.8.5", default-features = false }
54
55[profile.release]
56debug = true
57
58[patch.crates-io]
59lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "ad289428fd44b02788e2fa2116445cc8f640a265" }
diff --git a/examples/rp/src/bin/adc.rs b/examples/rp/src/bin/adc.rs
new file mode 100644
index 000000000..81a8b8340
--- /dev/null
+++ b/examples/rp/src/bin/adc.rs
@@ -0,0 +1,48 @@
1//! This example test the ADC (Analog to Digital Conversion) of the RS2040 pin 26, 27 and 28.
2//! It also reads the temperature sensor in the chip.
3
4#![no_std]
5#![no_main]
6#![feature(type_alias_impl_trait)]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::adc::{Adc, Config, InterruptHandler, Pin};
11use embassy_rp::bind_interrupts;
12use embassy_rp::gpio::Pull;
13use embassy_time::{Duration, Timer};
14use {defmt_rtt as _, panic_probe as _};
15
16bind_interrupts!(struct Irqs {
17 ADC_IRQ_FIFO => InterruptHandler;
18});
19
20#[embassy_executor::main]
21async fn main(_spawner: Spawner) {
22 let p = embassy_rp::init(Default::default());
23 let mut adc = Adc::new(p.ADC, Irqs, Config::default());
24
25 let mut p26 = Pin::new(p.PIN_26, Pull::None);
26 let mut p27 = Pin::new(p.PIN_27, Pull::None);
27 let mut p28 = Pin::new(p.PIN_28, Pull::None);
28
29 loop {
30 let level = adc.read(&mut p26).await.unwrap();
31 info!("Pin 26 ADC: {}", level);
32 let level = adc.read(&mut p27).await.unwrap();
33 info!("Pin 27 ADC: {}", level);
34 let level = adc.read(&mut p28).await.unwrap();
35 info!("Pin 28 ADC: {}", level);
36 let temp = adc.read_temperature().await.unwrap();
37 info!("Temp: {} degrees", convert_to_celsius(temp));
38 Timer::after(Duration::from_secs(1)).await;
39 }
40}
41
42fn convert_to_celsius(raw_temp: u16) -> f32 {
43 // According to chapter 4.9.5. Temperature Sensor in RP2040 datasheet
44 let temp = 27.0 - (raw_temp as f32 * 3.3 / 4096.0 - 0.706) / 0.001721;
45 let sign = if temp < 0.0 { -1.0 } else { 1.0 };
46 let rounded_temp_x10: i16 = ((temp * 10.0) + 0.5 * sign) as i16;
47 (rounded_temp_x10 as f32) / 10.0
48}
diff --git a/examples/rp/src/bin/blinky.rs b/examples/rp/src/bin/blinky.rs
index 7aa36a19f..295b000f3 100644
--- a/examples/rp/src/bin/blinky.rs
+++ b/examples/rp/src/bin/blinky.rs
@@ -1,3 +1,7 @@
1//! This example test the RP Pico on board LED.
2//!
3//! It does not work with the RP Pico W board. See wifi_blinky.rs.
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/button.rs b/examples/rp/src/bin/button.rs
index c5422c616..d7aa89410 100644
--- a/examples/rp/src/bin/button.rs
+++ b/examples/rp/src/bin/button.rs
@@ -1,3 +1,7 @@
1//! This example uses the RP Pico on board LED to test input pin 28. This is not the button on the board.
2//!
3//! It does not work with the RP Pico W board. Use wifi_blinky.rs and add input pin.
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
@@ -9,9 +13,12 @@ use {defmt_rtt as _, panic_probe as _};
9#[embassy_executor::main] 13#[embassy_executor::main]
10async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
11 let p = embassy_rp::init(Default::default()); 15 let p = embassy_rp::init(Default::default());
12 let button = Input::new(p.PIN_28, Pull::Up);
13 let mut led = Output::new(p.PIN_25, Level::Low); 16 let mut led = Output::new(p.PIN_25, Level::Low);
14 17
18 // Use PIN_28, Pin34 on J0 for RP Pico, as a input.
19 // You need to add your own button.
20 let button = Input::new(p.PIN_28, Pull::Up);
21
15 loop { 22 loop {
16 if button.is_high() { 23 if button.is_high() {
17 led.set_high(); 24 led.set_high();
diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
new file mode 100644
index 000000000..e81da177b
--- /dev/null
+++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
@@ -0,0 +1,136 @@
1//! This example shows how you can allow multiple simultaneous TCP connections, by having multiple sockets listening on the same port.
2//!
3//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_futures::yield_now;
12use embassy_net::{Stack, StackResources};
13use embassy_net_w5500::*;
14use embassy_rp::clocks::RoscRng;
15use embassy_rp::gpio::{Input, Level, Output, Pull};
16use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0};
17use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
18use embassy_time::{Delay, Duration};
19use embedded_hal_async::spi::ExclusiveDevice;
20use embedded_io::asynch::Write;
21use rand::RngCore;
22use static_cell::make_static;
23use {defmt_rtt as _, panic_probe as _};
24
25#[embassy_executor::task]
26async fn ethernet_task(
27 runner: Runner<
28 'static,
29 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>,
30 Input<'static, PIN_21>,
31 Output<'static, PIN_20>,
32 >,
33) -> ! {
34 runner.run().await
35}
36
37#[embassy_executor::task]
38async fn net_task(stack: &'static Stack<Device<'static>>) -> ! {
39 stack.run().await
40}
41
42#[embassy_executor::main]
43async fn main(spawner: Spawner) {
44 let p = embassy_rp::init(Default::default());
45 let mut rng = RoscRng;
46
47 let mut spi_cfg = SpiConfig::default();
48 spi_cfg.frequency = 50_000_000;
49 let (miso, mosi, clk) = (p.PIN_16, p.PIN_19, p.PIN_18);
50 let spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg);
51 let cs = Output::new(p.PIN_17, Level::High);
52 let w5500_int = Input::new(p.PIN_21, Pull::Up);
53 let w5500_reset = Output::new(p.PIN_20, Level::High);
54
55 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
56 let state = make_static!(State::<8, 8>::new());
57 let (device, runner) = embassy_net_w5500::new(
58 mac_addr,
59 state,
60 ExclusiveDevice::new(spi, cs, Delay),
61 w5500_int,
62 w5500_reset,
63 )
64 .await;
65 unwrap!(spawner.spawn(ethernet_task(runner)));
66
67 // Generate random seed
68 let seed = rng.next_u64();
69
70 // Init network stack
71 let stack = &*make_static!(Stack::new(
72 device,
73 embassy_net::Config::dhcpv4(Default::default()),
74 make_static!(StackResources::<3>::new()),
75 seed
76 ));
77
78 // Launch network task
79 unwrap!(spawner.spawn(net_task(&stack)));
80
81 info!("Waiting for DHCP...");
82 let cfg = wait_for_config(stack).await;
83 let local_addr = cfg.address.address();
84 info!("IP address: {:?}", local_addr);
85
86 // Create two sockets listening to the same port, to handle simultaneous connections
87 unwrap!(spawner.spawn(listen_task(&stack, 0, 1234)));
88 unwrap!(spawner.spawn(listen_task(&stack, 1, 1234)));
89}
90
91#[embassy_executor::task(pool_size = 2)]
92async fn listen_task(stack: &'static Stack<Device<'static>>, id: u8, port: u16) {
93 let mut rx_buffer = [0; 4096];
94 let mut tx_buffer = [0; 4096];
95 let mut buf = [0; 4096];
96 loop {
97 let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
98 socket.set_timeout(Some(Duration::from_secs(10)));
99
100 info!("SOCKET {}: Listening on TCP:{}...", id, port);
101 if let Err(e) = socket.accept(port).await {
102 warn!("accept error: {:?}", e);
103 continue;
104 }
105 info!("SOCKET {}: Received connection from {:?}", id, socket.remote_endpoint());
106
107 loop {
108 let n = match socket.read(&mut buf).await {
109 Ok(0) => {
110 warn!("read EOF");
111 break;
112 }
113 Ok(n) => n,
114 Err(e) => {
115 warn!("SOCKET {}: {:?}", id, e);
116 break;
117 }
118 };
119 info!("SOCKET {}: rxd {}", id, core::str::from_utf8(&buf[..n]).unwrap());
120
121 if let Err(e) = socket.write_all(&buf[..n]).await {
122 warn!("write error: {:?}", e);
123 break;
124 }
125 }
126 }
127}
128
129async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 {
130 loop {
131 if let Some(config) = stack.config_v4() {
132 return config.clone();
133 }
134 yield_now().await;
135 }
136}
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
new file mode 100644
index 000000000..9dd7ae973
--- /dev/null
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
@@ -0,0 +1,124 @@
1//! This example implements a TCP client that attempts to connect to a host on port 1234 and send it some data once per second.
2//!
3//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use core::str::FromStr;
10
11use defmt::*;
12use embassy_executor::Spawner;
13use embassy_futures::yield_now;
14use embassy_net::{Stack, StackResources};
15use embassy_net_w5500::*;
16use embassy_rp::clocks::RoscRng;
17use embassy_rp::gpio::{Input, Level, Output, Pull};
18use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0};
19use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
20use embassy_time::{Delay, Duration, Timer};
21use embedded_hal_async::spi::ExclusiveDevice;
22use embedded_io::asynch::Write;
23use rand::RngCore;
24use static_cell::make_static;
25use {defmt_rtt as _, panic_probe as _};
26
27#[embassy_executor::task]
28async fn ethernet_task(
29 runner: Runner<
30 'static,
31 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>,
32 Input<'static, PIN_21>,
33 Output<'static, PIN_20>,
34 >,
35) -> ! {
36 runner.run().await
37}
38
39#[embassy_executor::task]
40async fn net_task(stack: &'static Stack<Device<'static>>) -> ! {
41 stack.run().await
42}
43
44#[embassy_executor::main]
45async fn main(spawner: Spawner) {
46 let p = embassy_rp::init(Default::default());
47 let mut rng = RoscRng;
48 let mut led = Output::new(p.PIN_25, Level::Low);
49
50 let mut spi_cfg = SpiConfig::default();
51 spi_cfg.frequency = 50_000_000;
52 let (miso, mosi, clk) = (p.PIN_16, p.PIN_19, p.PIN_18);
53 let spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg);
54 let cs = Output::new(p.PIN_17, Level::High);
55 let w5500_int = Input::new(p.PIN_21, Pull::Up);
56 let w5500_reset = Output::new(p.PIN_20, Level::High);
57
58 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
59 let state = make_static!(State::<8, 8>::new());
60 let (device, runner) = embassy_net_w5500::new(
61 mac_addr,
62 state,
63 ExclusiveDevice::new(spi, cs, Delay),
64 w5500_int,
65 w5500_reset,
66 )
67 .await;
68 unwrap!(spawner.spawn(ethernet_task(runner)));
69
70 // Generate random seed
71 let seed = rng.next_u64();
72
73 // Init network stack
74 let stack = &*make_static!(Stack::new(
75 device,
76 embassy_net::Config::dhcpv4(Default::default()),
77 make_static!(StackResources::<2>::new()),
78 seed
79 ));
80
81 // Launch network task
82 unwrap!(spawner.spawn(net_task(&stack)));
83
84 info!("Waiting for DHCP...");
85 let cfg = wait_for_config(stack).await;
86 let local_addr = cfg.address.address();
87 info!("IP address: {:?}", local_addr);
88
89 let mut rx_buffer = [0; 4096];
90 let mut tx_buffer = [0; 4096];
91 loop {
92 let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
93 socket.set_timeout(Some(Duration::from_secs(10)));
94
95 led.set_low();
96 info!("Connecting...");
97 let host_addr = embassy_net::Ipv4Address::from_str("192.168.1.110").unwrap();
98 if let Err(e) = socket.connect((host_addr, 1234)).await {
99 warn!("connect error: {:?}", e);
100 continue;
101 }
102 info!("Connected to {:?}", socket.remote_endpoint());
103 led.set_high();
104
105 let msg = b"Hello world!\n";
106 loop {
107 if let Err(e) = socket.write_all(msg).await {
108 warn!("write error: {:?}", e);
109 break;
110 }
111 info!("txd: {}", core::str::from_utf8(msg).unwrap());
112 Timer::after(Duration::from_secs(1)).await;
113 }
114 }
115}
116
117async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 {
118 loop {
119 if let Some(config) = stack.config_v4() {
120 return config.clone();
121 }
122 yield_now().await;
123 }
124}
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
new file mode 100644
index 000000000..db21c2b6f
--- /dev/null
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
@@ -0,0 +1,132 @@
1//! This example implements a TCP echo server on port 1234 and using DHCP.
2//! Send it some data, you should see it echoed back and printed in the console.
3//!
4//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board.
5
6#![no_std]
7#![no_main]
8#![feature(type_alias_impl_trait)]
9
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_futures::yield_now;
13use embassy_net::{Stack, StackResources};
14use embassy_net_w5500::*;
15use embassy_rp::clocks::RoscRng;
16use embassy_rp::gpio::{Input, Level, Output, Pull};
17use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0};
18use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
19use embassy_time::{Delay, Duration};
20use embedded_hal_async::spi::ExclusiveDevice;
21use embedded_io::asynch::Write;
22use rand::RngCore;
23use static_cell::make_static;
24use {defmt_rtt as _, panic_probe as _};
25#[embassy_executor::task]
26async fn ethernet_task(
27 runner: Runner<
28 'static,
29 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>,
30 Input<'static, PIN_21>,
31 Output<'static, PIN_20>,
32 >,
33) -> ! {
34 runner.run().await
35}
36
37#[embassy_executor::task]
38async fn net_task(stack: &'static Stack<Device<'static>>) -> ! {
39 stack.run().await
40}
41
42#[embassy_executor::main]
43async fn main(spawner: Spawner) {
44 let p = embassy_rp::init(Default::default());
45 let mut rng = RoscRng;
46 let mut led = Output::new(p.PIN_25, Level::Low);
47
48 let mut spi_cfg = SpiConfig::default();
49 spi_cfg.frequency = 50_000_000;
50 let (miso, mosi, clk) = (p.PIN_16, p.PIN_19, p.PIN_18);
51 let spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg);
52 let cs = Output::new(p.PIN_17, Level::High);
53 let w5500_int = Input::new(p.PIN_21, Pull::Up);
54 let w5500_reset = Output::new(p.PIN_20, Level::High);
55
56 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
57 let state = make_static!(State::<8, 8>::new());
58 let (device, runner) = embassy_net_w5500::new(
59 mac_addr,
60 state,
61 ExclusiveDevice::new(spi, cs, Delay),
62 w5500_int,
63 w5500_reset,
64 )
65 .await;
66 unwrap!(spawner.spawn(ethernet_task(runner)));
67
68 // Generate random seed
69 let seed = rng.next_u64();
70
71 // Init network stack
72 let stack = &*make_static!(Stack::new(
73 device,
74 embassy_net::Config::dhcpv4(Default::default()),
75 make_static!(StackResources::<2>::new()),
76 seed
77 ));
78
79 // Launch network task
80 unwrap!(spawner.spawn(net_task(&stack)));
81
82 info!("Waiting for DHCP...");
83 let cfg = wait_for_config(stack).await;
84 let local_addr = cfg.address.address();
85 info!("IP address: {:?}", local_addr);
86
87 let mut rx_buffer = [0; 4096];
88 let mut tx_buffer = [0; 4096];
89 let mut buf = [0; 4096];
90 loop {
91 let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
92 socket.set_timeout(Some(Duration::from_secs(10)));
93
94 led.set_low();
95 info!("Listening on TCP:1234...");
96 if let Err(e) = socket.accept(1234).await {
97 warn!("accept error: {:?}", e);
98 continue;
99 }
100 info!("Received connection from {:?}", socket.remote_endpoint());
101 led.set_high();
102
103 loop {
104 let n = match socket.read(&mut buf).await {
105 Ok(0) => {
106 warn!("read EOF");
107 break;
108 }
109 Ok(n) => n,
110 Err(e) => {
111 warn!("{:?}", e);
112 break;
113 }
114 };
115 info!("rxd {}", core::str::from_utf8(&buf[..n]).unwrap());
116
117 if let Err(e) = socket.write_all(&buf[..n]).await {
118 warn!("write error: {:?}", e);
119 break;
120 }
121 }
122 }
123}
124
125async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 {
126 loop {
127 if let Some(config) = stack.config_v4() {
128 return config.clone();
129 }
130 yield_now().await;
131 }
132}
diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs
new file mode 100644
index 000000000..038432b17
--- /dev/null
+++ b/examples/rp/src/bin/ethernet_w5500_udp.rs
@@ -0,0 +1,112 @@
1//! This example implements a UDP server listening on port 1234 and echoing back the data.
2//!
3//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_futures::yield_now;
12use embassy_net::udp::{PacketMetadata, UdpSocket};
13use embassy_net::{Stack, StackResources};
14use embassy_net_w5500::*;
15use embassy_rp::clocks::RoscRng;
16use embassy_rp::gpio::{Input, Level, Output, Pull};
17use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0};
18use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
19use embassy_time::Delay;
20use embedded_hal_async::spi::ExclusiveDevice;
21use rand::RngCore;
22use static_cell::make_static;
23use {defmt_rtt as _, panic_probe as _};
24#[embassy_executor::task]
25async fn ethernet_task(
26 runner: Runner<
27 'static,
28 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>,
29 Input<'static, PIN_21>,
30 Output<'static, PIN_20>,
31 >,
32) -> ! {
33 runner.run().await
34}
35
36#[embassy_executor::task]
37async fn net_task(stack: &'static Stack<Device<'static>>) -> ! {
38 stack.run().await
39}
40
41#[embassy_executor::main]
42async fn main(spawner: Spawner) {
43 let p = embassy_rp::init(Default::default());
44 let mut rng = RoscRng;
45
46 let mut spi_cfg = SpiConfig::default();
47 spi_cfg.frequency = 50_000_000;
48 let (miso, mosi, clk) = (p.PIN_16, p.PIN_19, p.PIN_18);
49 let spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg);
50 let cs = Output::new(p.PIN_17, Level::High);
51 let w5500_int = Input::new(p.PIN_21, Pull::Up);
52 let w5500_reset = Output::new(p.PIN_20, Level::High);
53
54 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
55 let state = make_static!(State::<8, 8>::new());
56 let (device, runner) = embassy_net_w5500::new(
57 mac_addr,
58 state,
59 ExclusiveDevice::new(spi, cs, Delay),
60 w5500_int,
61 w5500_reset,
62 )
63 .await;
64 unwrap!(spawner.spawn(ethernet_task(runner)));
65
66 // Generate random seed
67 let seed = rng.next_u64();
68
69 // Init network stack
70 let stack = &*make_static!(Stack::new(
71 device,
72 embassy_net::Config::dhcpv4(Default::default()),
73 make_static!(StackResources::<2>::new()),
74 seed
75 ));
76
77 // Launch network task
78 unwrap!(spawner.spawn(net_task(&stack)));
79
80 info!("Waiting for DHCP...");
81 let cfg = wait_for_config(stack).await;
82 let local_addr = cfg.address.address();
83 info!("IP address: {:?}", local_addr);
84
85 // Then we can use it!
86 let mut rx_buffer = [0; 4096];
87 let mut tx_buffer = [0; 4096];
88 let mut rx_meta = [PacketMetadata::EMPTY; 16];
89 let mut tx_meta = [PacketMetadata::EMPTY; 16];
90 let mut buf = [0; 4096];
91 loop {
92 let mut socket = UdpSocket::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer);
93 socket.bind(1234).unwrap();
94
95 loop {
96 let (n, ep) = socket.recv_from(&mut buf).await.unwrap();
97 if let Ok(s) = core::str::from_utf8(&buf[..n]) {
98 info!("rxd from {}: {}", ep, s);
99 }
100 socket.send_to(&buf[..n], ep).await.unwrap();
101 }
102 }
103}
104
105async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 {
106 loop {
107 if let Some(config) = stack.config_v4() {
108 return config.clone();
109 }
110 yield_now().await;
111 }
112}
diff --git a/examples/rp/src/bin/flash.rs b/examples/rp/src/bin/flash.rs
new file mode 100644
index 000000000..4c4982acc
--- /dev/null
+++ b/examples/rp/src/bin/flash.rs
@@ -0,0 +1,101 @@
1//! This example test the flash connected to the RP2040 chip.
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::flash::{ERASE_SIZE, FLASH_BASE};
10use embassy_rp::peripherals::FLASH;
11use embassy_time::{Duration, Timer};
12use {defmt_rtt as _, panic_probe as _};
13
14const ADDR_OFFSET: u32 = 0x100000;
15const FLASH_SIZE: usize = 2 * 1024 * 1024;
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_rp::init(Default::default());
20 info!("Hello World!");
21
22 // add some delay to give an attached debug probe time to parse the
23 // defmt RTT header. Reading that header might touch flash memory, which
24 // interferes with flash write operations.
25 // https://github.com/knurling-rs/defmt/pull/683
26 Timer::after(Duration::from_millis(10)).await;
27
28 let mut flash = embassy_rp::flash::Flash::<_, FLASH_SIZE>::new(p.FLASH);
29
30 // Get JEDEC id
31 let jedec = flash.jedec_id().unwrap();
32 info!("jedec id: 0x{:x}", jedec);
33
34 // Get unique id
35 let mut uid = [0; 8];
36 flash.unique_id(&mut uid).unwrap();
37 info!("unique id: {:?}", uid);
38
39 erase_write_sector(&mut flash, 0x00);
40
41 multiwrite_bytes(&mut flash, ERASE_SIZE as u32);
42
43 loop {}
44}
45
46fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, FLASH_SIZE>, offset: u32) {
47 info!(">>>> [multiwrite_bytes]");
48 let mut read_buf = [0u8; ERASE_SIZE];
49 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf));
50
51 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
52 info!("Contents start with {=[u8]}", read_buf[0..4]);
53
54 defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
55
56 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf));
57 info!("Contents after erase starts with {=[u8]}", read_buf[0..4]);
58 if read_buf.iter().any(|x| *x != 0xFF) {
59 defmt::panic!("unexpected");
60 }
61
62 defmt::unwrap!(flash.write(ADDR_OFFSET + offset, &[0x01]));
63 defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 1, &[0x02]));
64 defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 2, &[0x03]));
65 defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 3, &[0x04]));
66
67 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf));
68 info!("Contents after write starts with {=[u8]}", read_buf[0..4]);
69 if &read_buf[0..4] != &[0x01, 0x02, 0x03, 0x04] {
70 defmt::panic!("unexpected");
71 }
72}
73
74fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, FLASH_SIZE>, offset: u32) {
75 info!(">>>> [erase_write_sector]");
76 let mut buf = [0u8; ERASE_SIZE];
77 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf));
78
79 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
80 info!("Contents start with {=[u8]}", buf[0..4]);
81
82 defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
83
84 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf));
85 info!("Contents after erase starts with {=[u8]}", buf[0..4]);
86 if buf.iter().any(|x| *x != 0xFF) {
87 defmt::panic!("unexpected");
88 }
89
90 for b in buf.iter_mut() {
91 *b = 0xDA;
92 }
93
94 defmt::unwrap!(flash.write(ADDR_OFFSET + offset, &buf));
95
96 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf));
97 info!("Contents after write starts with {=[u8]}", buf[0..4]);
98 if buf.iter().any(|x| *x != 0xDA) {
99 defmt::panic!("unexpected");
100 }
101}
diff --git a/examples/rp/src/bin/gpio_async.rs b/examples/rp/src/bin/gpio_async.rs
index 52d13a9d5..bf58044d5 100644
--- a/examples/rp/src/bin/gpio_async.rs
+++ b/examples/rp/src/bin/gpio_async.rs
@@ -1,3 +1,7 @@
1//! This example shows how async gpio can be used with a RP2040.
2//!
3//! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs.
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
@@ -9,8 +13,6 @@ use embassy_time::{Duration, Timer};
9use gpio::{Input, Level, Output, Pull}; 13use gpio::{Input, Level, Output, Pull};
10use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
11 15
12/// This example shows how async gpio can be used with a RP2040.
13///
14/// It requires an external signal to be manually triggered on PIN 16. For 16/// It requires an external signal to be manually triggered on PIN 16. For
15/// example, this could be accomplished using an external power source with a 17/// example, this could be accomplished using an external power source with a
16/// button so that it is possible to toggle the signal from low to high. 18/// button so that it is possible to toggle the signal from low to high.
diff --git a/examples/rp/src/bin/gpout.rs b/examples/rp/src/bin/gpout.rs
new file mode 100644
index 000000000..0a3b5fa98
--- /dev/null
+++ b/examples/rp/src/bin/gpout.rs
@@ -0,0 +1,38 @@
1//! This example shows how GPOUT (General purpose clock outputs) can toggle a output pin.
2//!
3//! The LED on the RP Pico W board is connected differently. Add a LED and resistor to another pin.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_rp::clocks;
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 gpout3 = clocks::Gpout::new(p.PIN_25);
20 gpout3.set_div(1000, 0);
21 gpout3.enable();
22
23 loop {
24 gpout3.set_src(clocks::GpoutSrc::Sys);
25 info!(
26 "Pin 25 is now outputing CLK_SYS/1000, should be toggling at {}",
27 gpout3.get_freq()
28 );
29 Timer::after(Duration::from_secs(2)).await;
30
31 gpout3.set_src(clocks::GpoutSrc::Ref);
32 info!(
33 "Pin 25 is now outputing CLK_REF/1000, should be toggling at {}",
34 gpout3.get_freq()
35 );
36 Timer::after(Duration::from_secs(2)).await;
37 }
38}
diff --git a/examples/rp/src/bin/i2c_async.rs b/examples/rp/src/bin/i2c_async.rs
new file mode 100644
index 000000000..93224bc43
--- /dev/null
+++ b/examples/rp/src/bin/i2c_async.rs
@@ -0,0 +1,111 @@
1//! This example shows how to communicate asynchronous using i2c with external chips.
2//!
3//! Example written for the [`MCP23017 16-Bit I2C I/O Expander with Serial Interface`] chip.
4//! (https://www.microchip.com/en-us/product/mcp23017)
5
6#![no_std]
7#![no_main]
8#![feature(type_alias_impl_trait)]
9
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_rp::bind_interrupts;
13use embassy_rp::i2c::{self, Config, InterruptHandler};
14use embassy_rp::peripherals::I2C1;
15use embassy_time::{Duration, Timer};
16use embedded_hal_async::i2c::I2c;
17use {defmt_rtt as _, panic_probe as _};
18
19bind_interrupts!(struct Irqs {
20 I2C1_IRQ => InterruptHandler<I2C1>;
21});
22
23#[allow(dead_code)]
24mod mcp23017 {
25 pub const ADDR: u8 = 0x20; // default addr
26
27 macro_rules! mcpregs {
28 ($($name:ident : $val:expr),* $(,)?) => {
29 $(
30 pub const $name: u8 = $val;
31 )*
32
33 pub fn regname(reg: u8) -> &'static str {
34 match reg {
35 $(
36 $val => stringify!($name),
37 )*
38 _ => panic!("bad reg"),
39 }
40 }
41 }
42 }
43
44 // These are correct for IOCON.BANK=0
45 mcpregs! {
46 IODIRA: 0x00,
47 IPOLA: 0x02,
48 GPINTENA: 0x04,
49 DEFVALA: 0x06,
50 INTCONA: 0x08,
51 IOCONA: 0x0A,
52 GPPUA: 0x0C,
53 INTFA: 0x0E,
54 INTCAPA: 0x10,
55 GPIOA: 0x12,
56 OLATA: 0x14,
57 IODIRB: 0x01,
58 IPOLB: 0x03,
59 GPINTENB: 0x05,
60 DEFVALB: 0x07,
61 INTCONB: 0x09,
62 IOCONB: 0x0B,
63 GPPUB: 0x0D,
64 INTFB: 0x0F,
65 INTCAPB: 0x11,
66 GPIOB: 0x13,
67 OLATB: 0x15,
68 }
69}
70
71#[embassy_executor::main]
72async fn main(_spawner: Spawner) {
73 let p = embassy_rp::init(Default::default());
74
75 let sda = p.PIN_14;
76 let scl = p.PIN_15;
77
78 info!("set up i2c ");
79 let mut i2c = i2c::I2c::new_async(p.I2C1, scl, sda, Irqs, Config::default());
80
81 use mcp23017::*;
82
83 info!("init mcp23017 config for IxpandO");
84 // init - a outputs, b inputs
85 i2c.write(ADDR, &[IODIRA, 0x00]).await.unwrap();
86 i2c.write(ADDR, &[IODIRB, 0xff]).await.unwrap();
87 i2c.write(ADDR, &[GPPUB, 0xff]).await.unwrap(); // pullups
88
89 let mut val = 1;
90 loop {
91 let mut portb = [0];
92
93 i2c.write_read(mcp23017::ADDR, &[GPIOB], &mut portb).await.unwrap();
94 info!("portb = {:02x}", portb[0]);
95 i2c.write(mcp23017::ADDR, &[GPIOA, val | portb[0]]).await.unwrap();
96 val = val.rotate_left(1);
97
98 // get a register dump
99 info!("getting register dump");
100 let mut regs = [0; 22];
101 i2c.write_read(ADDR, &[0], &mut regs).await.unwrap();
102 // always get the regdump but only display it if portb'0 is set
103 if portb[0] & 1 != 0 {
104 for (idx, reg) in regs.into_iter().enumerate() {
105 info!("{} => {:02x}", regname(idx as u8), reg);
106 }
107 }
108
109 Timer::after(Duration::from_millis(100)).await;
110 }
111}
diff --git a/examples/rp/src/bin/i2c_blocking.rs b/examples/rp/src/bin/i2c_blocking.rs
new file mode 100644
index 000000000..1c8c2039d
--- /dev/null
+++ b/examples/rp/src/bin/i2c_blocking.rs
@@ -0,0 +1,75 @@
1//! This example shows how to communicate using i2c with external chips.
2//!
3//! Example written for the [`MCP23017 16-Bit I2C I/O Expander with Serial Interface`] chip.
4//! (https://www.microchip.com/en-us/product/mcp23017)
5
6#![no_std]
7#![no_main]
8#![feature(type_alias_impl_trait)]
9
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_rp::i2c::{self, Config};
13use embassy_time::{Duration, Timer};
14use embedded_hal_1::i2c::I2c;
15use {defmt_rtt as _, panic_probe as _};
16
17#[allow(dead_code)]
18mod mcp23017 {
19 pub const ADDR: u8 = 0x20; // default addr
20
21 pub const IODIRA: u8 = 0x00;
22 pub const IPOLA: u8 = 0x02;
23 pub const GPINTENA: u8 = 0x04;
24 pub const DEFVALA: u8 = 0x06;
25 pub const INTCONA: u8 = 0x08;
26 pub const IOCONA: u8 = 0x0A;
27 pub const GPPUA: u8 = 0x0C;
28 pub const INTFA: u8 = 0x0E;
29 pub const INTCAPA: u8 = 0x10;
30 pub const GPIOA: u8 = 0x12;
31 pub const OLATA: u8 = 0x14;
32 pub const IODIRB: u8 = 0x01;
33 pub const IPOLB: u8 = 0x03;
34 pub const GPINTENB: u8 = 0x05;
35 pub const DEFVALB: u8 = 0x07;
36 pub const INTCONB: u8 = 0x09;
37 pub const IOCONB: u8 = 0x0B;
38 pub const GPPUB: u8 = 0x0D;
39 pub const INTFB: u8 = 0x0F;
40 pub const INTCAPB: u8 = 0x11;
41 pub const GPIOB: u8 = 0x13;
42 pub const OLATB: u8 = 0x15;
43}
44
45#[embassy_executor::main]
46async fn main(_spawner: Spawner) {
47 let p = embassy_rp::init(Default::default());
48
49 let sda = p.PIN_14;
50 let scl = p.PIN_15;
51
52 info!("set up i2c ");
53 let mut i2c = i2c::I2c::new_blocking(p.I2C1, scl, sda, Config::default());
54
55 use mcp23017::*;
56
57 info!("init mcp23017 config for IxpandO");
58 // init - a outputs, b inputs
59 i2c.write(ADDR, &[IODIRA, 0x00]).unwrap();
60 i2c.write(ADDR, &[IODIRB, 0xff]).unwrap();
61 i2c.write(ADDR, &[GPPUB, 0xff]).unwrap(); // pullups
62
63 let mut val = 0xaa;
64 loop {
65 let mut portb = [0];
66
67 i2c.write(mcp23017::ADDR, &[GPIOA, val]).unwrap();
68 i2c.write_read(mcp23017::ADDR, &[GPIOB], &mut portb).unwrap();
69
70 info!("portb = {:02x}", portb[0]);
71 val = !val;
72
73 Timer::after(Duration::from_secs(1)).await;
74 }
75}
diff --git a/examples/rp/src/bin/lora_lorawan.rs b/examples/rp/src/bin/lora_lorawan.rs
new file mode 100644
index 000000000..d631fafa1
--- /dev/null
+++ b/examples/rp/src/bin/lora_lorawan.rs
@@ -0,0 +1,81 @@
1//! This example runs on the Raspberry Pi Pico with a Waveshare board containing a Semtech Sx1262 radio.
2//! It demonstrates LoRaWAN join functionality.
3
4#![no_std]
5#![no_main]
6#![macro_use]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_lora::iv::GenericSx126xInterfaceVariant;
12use embassy_lora::LoraTimer;
13use embassy_rp::gpio::{Input, Level, Output, Pin, Pull};
14use embassy_rp::spi::{Config, Spi};
15use embassy_time::Delay;
16use lora_phy::mod_params::*;
17use lora_phy::sx1261_2::SX1261_2;
18use lora_phy::LoRa;
19use lorawan::default_crypto::DefaultFactory as Crypto;
20use lorawan_device::async_device::lora_radio::LoRaRadio;
21use lorawan_device::async_device::{region, Device, JoinMode};
22use {defmt_rtt as _, panic_probe as _};
23
24const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set this appropriately for the region
25
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 let p = embassy_rp::init(Default::default());
29
30 let miso = p.PIN_12;
31 let mosi = p.PIN_11;
32 let clk = p.PIN_10;
33 let spi = Spi::new(p.SPI1, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default());
34
35 let nss = Output::new(p.PIN_3.degrade(), Level::High);
36 let reset = Output::new(p.PIN_15.degrade(), Level::High);
37 let dio1 = Input::new(p.PIN_20.degrade(), Pull::None);
38 let busy = Input::new(p.PIN_2.degrade(), Pull::None);
39
40 let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, None, None).unwrap();
41
42 let mut delay = Delay;
43
44 let lora = {
45 match LoRa::new(
46 SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv),
47 true,
48 &mut delay,
49 )
50 .await
51 {
52 Ok(l) => l,
53 Err(err) => {
54 info!("Radio error = {}", err);
55 return;
56 }
57 }
58 };
59
60 let radio = LoRaRadio::new(lora);
61 let region: region::Configuration = region::Configuration::new(LORAWAN_REGION);
62 let mut device: Device<_, Crypto, _, _> = Device::new(region, radio, LoraTimer::new(), embassy_rp::clocks::RoscRng);
63
64 defmt::info!("Joining LoRaWAN network");
65
66 // TODO: Adjust the EUI and Keys according to your network credentials
67 match device
68 .join(&JoinMode::OTAA {
69 deveui: [0, 0, 0, 0, 0, 0, 0, 0],
70 appeui: [0, 0, 0, 0, 0, 0, 0, 0],
71 appkey: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
72 })
73 .await
74 {
75 Ok(()) => defmt::info!("LoRaWAN network joined"),
76 Err(err) => {
77 info!("Radio error = {}", err);
78 return;
79 }
80 };
81}
diff --git a/examples/rp/src/bin/lora_p2p_receive.rs b/examples/rp/src/bin/lora_p2p_receive.rs
new file mode 100644
index 000000000..396d669de
--- /dev/null
+++ b/examples/rp/src/bin/lora_p2p_receive.rs
@@ -0,0 +1,116 @@
1//! This example runs on the Raspberry Pi Pico with a Waveshare board containing a Semtech Sx1262 radio.
2//! It demonstrates LORA P2P receive functionality in conjunction with the lora_p2p_send example.
3
4#![no_std]
5#![no_main]
6#![macro_use]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_lora::iv::GenericSx126xInterfaceVariant;
12use embassy_rp::gpio::{Input, Level, Output, Pin, Pull};
13use embassy_rp::spi::{Config, Spi};
14use embassy_time::{Delay, Duration, Timer};
15use lora_phy::mod_params::*;
16use lora_phy::sx1261_2::SX1261_2;
17use lora_phy::LoRa;
18use {defmt_rtt as _, panic_probe as _};
19
20const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
24 let p = embassy_rp::init(Default::default());
25
26 let miso = p.PIN_12;
27 let mosi = p.PIN_11;
28 let clk = p.PIN_10;
29 let spi = Spi::new(p.SPI1, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default());
30
31 let nss = Output::new(p.PIN_3.degrade(), Level::High);
32 let reset = Output::new(p.PIN_15.degrade(), Level::High);
33 let dio1 = Input::new(p.PIN_20.degrade(), Pull::None);
34 let busy = Input::new(p.PIN_2.degrade(), Pull::None);
35
36 let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, None, None).unwrap();
37
38 let mut delay = Delay;
39
40 let mut lora = {
41 match LoRa::new(
42 SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv),
43 false,
44 &mut delay,
45 )
46 .await
47 {
48 Ok(l) => l,
49 Err(err) => {
50 info!("Radio error = {}", err);
51 return;
52 }
53 }
54 };
55
56 let mut debug_indicator = Output::new(p.PIN_25, Level::Low);
57
58 let mut receiving_buffer = [00u8; 100];
59
60 let mdltn_params = {
61 match lora.create_modulation_params(
62 SpreadingFactor::_10,
63 Bandwidth::_250KHz,
64 CodingRate::_4_8,
65 LORA_FREQUENCY_IN_HZ,
66 ) {
67 Ok(mp) => mp,
68 Err(err) => {
69 info!("Radio error = {}", err);
70 return;
71 }
72 }
73 };
74
75 let rx_pkt_params = {
76 match lora.create_rx_packet_params(4, false, receiving_buffer.len() as u8, true, false, &mdltn_params) {
77 Ok(pp) => pp,
78 Err(err) => {
79 info!("Radio error = {}", err);
80 return;
81 }
82 }
83 };
84
85 match lora
86 .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, true, false, 0, 0x00ffffffu32)
87 .await
88 {
89 Ok(()) => {}
90 Err(err) => {
91 info!("Radio error = {}", err);
92 return;
93 }
94 };
95
96 loop {
97 receiving_buffer = [00u8; 100];
98 match lora.rx(&rx_pkt_params, &mut receiving_buffer).await {
99 Ok((received_len, _rx_pkt_status)) => {
100 if (received_len == 3)
101 && (receiving_buffer[0] == 0x01u8)
102 && (receiving_buffer[1] == 0x02u8)
103 && (receiving_buffer[2] == 0x03u8)
104 {
105 info!("rx successful");
106 debug_indicator.set_high();
107 Timer::after(Duration::from_secs(5)).await;
108 debug_indicator.set_low();
109 } else {
110 info!("rx unknown packet");
111 }
112 }
113 Err(err) => info!("rx unsuccessful = {}", err),
114 }
115 }
116}
diff --git a/examples/rp/src/bin/lora_p2p_send.rs b/examples/rp/src/bin/lora_p2p_send.rs
new file mode 100644
index 000000000..a0f70fa5c
--- /dev/null
+++ b/examples/rp/src/bin/lora_p2p_send.rs
@@ -0,0 +1,104 @@
1//! This example runs on the Raspberry Pi Pico with a Waveshare board containing a Semtech Sx1262 radio.
2//! It demonstrates LORA P2P send functionality.
3
4#![no_std]
5#![no_main]
6#![macro_use]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_lora::iv::GenericSx126xInterfaceVariant;
12use embassy_rp::gpio::{Input, Level, Output, Pin, Pull};
13use embassy_rp::spi::{Config, Spi};
14use embassy_time::Delay;
15use lora_phy::mod_params::*;
16use lora_phy::sx1261_2::SX1261_2;
17use lora_phy::LoRa;
18use {defmt_rtt as _, panic_probe as _};
19
20const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
24 let p = embassy_rp::init(Default::default());
25
26 let miso = p.PIN_12;
27 let mosi = p.PIN_11;
28 let clk = p.PIN_10;
29 let spi = Spi::new(p.SPI1, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default());
30
31 let nss = Output::new(p.PIN_3.degrade(), Level::High);
32 let reset = Output::new(p.PIN_15.degrade(), Level::High);
33 let dio1 = Input::new(p.PIN_20.degrade(), Pull::None);
34 let busy = Input::new(p.PIN_2.degrade(), Pull::None);
35
36 let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, None, None).unwrap();
37
38 let mut delay = Delay;
39
40 let mut lora = {
41 match LoRa::new(
42 SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv),
43 false,
44 &mut delay,
45 )
46 .await
47 {
48 Ok(l) => l,
49 Err(err) => {
50 info!("Radio error = {}", err);
51 return;
52 }
53 }
54 };
55
56 let mdltn_params = {
57 match lora.create_modulation_params(
58 SpreadingFactor::_10,
59 Bandwidth::_250KHz,
60 CodingRate::_4_8,
61 LORA_FREQUENCY_IN_HZ,
62 ) {
63 Ok(mp) => mp,
64 Err(err) => {
65 info!("Radio error = {}", err);
66 return;
67 }
68 }
69 };
70
71 let mut tx_pkt_params = {
72 match lora.create_tx_packet_params(4, false, true, false, &mdltn_params) {
73 Ok(pp) => pp,
74 Err(err) => {
75 info!("Radio error = {}", err);
76 return;
77 }
78 }
79 };
80
81 match lora.prepare_for_tx(&mdltn_params, 20, false).await {
82 Ok(()) => {}
83 Err(err) => {
84 info!("Radio error = {}", err);
85 return;
86 }
87 };
88
89 let buffer = [0x01u8, 0x02u8, 0x03u8];
90 match lora.tx(&mdltn_params, &mut tx_pkt_params, &buffer, 0xffffff).await {
91 Ok(()) => {
92 info!("TX DONE");
93 }
94 Err(err) => {
95 info!("Radio error = {}", err);
96 return;
97 }
98 };
99
100 match lora.sleep(&mut delay).await {
101 Ok(()) => info!("Sleep successful"),
102 Err(err) => info!("Sleep unsuccessful = {}", err),
103 }
104}
diff --git a/examples/rp/src/bin/lora_p2p_send_multicore.rs b/examples/rp/src/bin/lora_p2p_send_multicore.rs
new file mode 100644
index 000000000..89a62818d
--- /dev/null
+++ b/examples/rp/src/bin/lora_p2p_send_multicore.rs
@@ -0,0 +1,140 @@
1//! This example runs on the Raspberry Pi Pico with a Waveshare board containing a Semtech Sx1262 radio.
2//! It demonstrates LORA P2P send functionality using the second core, with data provided by the first core.
3
4#![no_std]
5#![no_main]
6#![macro_use]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Executor;
11use embassy_lora::iv::GenericSx126xInterfaceVariant;
12use embassy_rp::gpio::{AnyPin, Input, Level, Output, Pin, Pull};
13use embassy_rp::multicore::{spawn_core1, Stack};
14use embassy_rp::peripherals::SPI1;
15use embassy_rp::spi::{Async, Config, Spi};
16use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
17use embassy_sync::channel::Channel;
18use embassy_time::{Delay, Duration, Timer};
19use lora_phy::mod_params::*;
20use lora_phy::sx1261_2::SX1261_2;
21use lora_phy::LoRa;
22use static_cell::StaticCell;
23use {defmt_rtt as _, panic_probe as _};
24
25static mut CORE1_STACK: Stack<4096> = Stack::new();
26static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
27static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
28static CHANNEL: Channel<CriticalSectionRawMutex, [u8; 3], 1> = Channel::new();
29
30const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
31
32#[cortex_m_rt::entry]
33fn main() -> ! {
34 let p = embassy_rp::init(Default::default());
35
36 let miso = p.PIN_12;
37 let mosi = p.PIN_11;
38 let clk = p.PIN_10;
39 let spi = Spi::new(p.SPI1, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default());
40
41 let nss = Output::new(p.PIN_3.degrade(), Level::High);
42 let reset = Output::new(p.PIN_15.degrade(), Level::High);
43 let dio1 = Input::new(p.PIN_20.degrade(), Pull::None);
44 let busy = Input::new(p.PIN_2.degrade(), Pull::None);
45
46 let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, None, None).unwrap();
47
48 spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || {
49 let executor1 = EXECUTOR1.init(Executor::new());
50 executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(spi, iv))));
51 });
52
53 let executor0 = EXECUTOR0.init(Executor::new());
54 executor0.run(|spawner| unwrap!(spawner.spawn(core0_task())));
55}
56
57#[embassy_executor::task]
58async fn core0_task() {
59 info!("Hello from core 0");
60 loop {
61 CHANNEL.send([0x01u8, 0x02u8, 0x03u8]).await;
62 Timer::after(Duration::from_millis(60 * 1000)).await;
63 }
64}
65
66#[embassy_executor::task]
67async fn core1_task(
68 spi: Spi<'static, SPI1, Async>,
69 iv: GenericSx126xInterfaceVariant<Output<'static, AnyPin>, Input<'static, AnyPin>>,
70) {
71 info!("Hello from core 1");
72 let mut delay = Delay;
73
74 let mut lora = {
75 match LoRa::new(
76 SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv),
77 false,
78 &mut delay,
79 )
80 .await
81 {
82 Ok(l) => l,
83 Err(err) => {
84 info!("Radio error = {}", err);
85 return;
86 }
87 }
88 };
89
90 let mdltn_params = {
91 match lora.create_modulation_params(
92 SpreadingFactor::_10,
93 Bandwidth::_250KHz,
94 CodingRate::_4_8,
95 LORA_FREQUENCY_IN_HZ,
96 ) {
97 Ok(mp) => mp,
98 Err(err) => {
99 info!("Radio error = {}", err);
100 return;
101 }
102 }
103 };
104
105 let mut tx_pkt_params = {
106 match lora.create_tx_packet_params(4, false, true, false, &mdltn_params) {
107 Ok(pp) => pp,
108 Err(err) => {
109 info!("Radio error = {}", err);
110 return;
111 }
112 }
113 };
114
115 loop {
116 let buffer: [u8; 3] = CHANNEL.recv().await;
117 match lora.prepare_for_tx(&mdltn_params, 20, false).await {
118 Ok(()) => {}
119 Err(err) => {
120 info!("Radio error = {}", err);
121 return;
122 }
123 };
124
125 match lora.tx(&mdltn_params, &mut tx_pkt_params, &buffer, 0xffffff).await {
126 Ok(()) => {
127 info!("TX DONE");
128 }
129 Err(err) => {
130 info!("Radio error = {}", err);
131 return;
132 }
133 };
134
135 match lora.sleep(&mut delay).await {
136 Ok(()) => info!("Sleep successful"),
137 Err(err) => info!("Sleep unsuccessful = {}", err),
138 }
139 }
140}
diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs
new file mode 100644
index 000000000..893b724bf
--- /dev/null
+++ b/examples/rp/src/bin/multicore.rs
@@ -0,0 +1,64 @@
1//! This example shows how to send messages between the two cores in the RP2040 chip.
2//!
3//! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Executor;
11use embassy_rp::gpio::{Level, Output};
12use embassy_rp::multicore::{spawn_core1, Stack};
13use embassy_rp::peripherals::PIN_25;
14use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
15use embassy_sync::channel::Channel;
16use embassy_time::{Duration, Timer};
17use static_cell::StaticCell;
18use {defmt_rtt as _, panic_probe as _};
19
20static mut CORE1_STACK: Stack<4096> = Stack::new();
21static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
22static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
23static CHANNEL: Channel<CriticalSectionRawMutex, LedState, 1> = Channel::new();
24
25enum LedState {
26 On,
27 Off,
28}
29
30#[cortex_m_rt::entry]
31fn main() -> ! {
32 let p = embassy_rp::init(Default::default());
33 let led = Output::new(p.PIN_25, Level::Low);
34
35 spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || {
36 let executor1 = EXECUTOR1.init(Executor::new());
37 executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(led))));
38 });
39
40 let executor0 = EXECUTOR0.init(Executor::new());
41 executor0.run(|spawner| unwrap!(spawner.spawn(core0_task())));
42}
43
44#[embassy_executor::task]
45async fn core0_task() {
46 info!("Hello from core 0");
47 loop {
48 CHANNEL.send(LedState::On).await;
49 Timer::after(Duration::from_millis(100)).await;
50 CHANNEL.send(LedState::Off).await;
51 Timer::after(Duration::from_millis(400)).await;
52 }
53}
54
55#[embassy_executor::task]
56async fn core1_task(mut led: Output<'static, PIN_25>) {
57 info!("Hello from core 1");
58 loop {
59 match CHANNEL.recv().await {
60 LedState::On => led.set_high(),
61 LedState::Off => led.set_low(),
62 }
63 }
64}
diff --git a/examples/rp/src/bin/multiprio.rs b/examples/rp/src/bin/multiprio.rs
new file mode 100644
index 000000000..9ace4cd68
--- /dev/null
+++ b/examples/rp/src/bin/multiprio.rs
@@ -0,0 +1,146 @@
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::{info, unwrap};
62use embassy_executor::{Executor, InterruptExecutor};
63use embassy_rp::interrupt;
64use embassy_rp::interrupt::{InterruptExt, Priority};
65use embassy_time::{Duration, Instant, Timer, TICK_HZ};
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(673740)).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(125_000_000); // ~1 second
85
86 let end = Instant::now();
87 let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ;
88 info!(" [med] done in {} ms", ms);
89
90 Timer::after(Duration::from_ticks(53421)).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(250_000_000); // ~2 seconds
102
103 let end = Instant::now();
104 let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ;
105 info!("[low] done in {} ms", ms);
106
107 Timer::after(Duration::from_ticks(82983)).await;
108 }
109}
110
111static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
112static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
113static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
114
115#[interrupt]
116unsafe fn SWI_IRQ_1() {
117 EXECUTOR_HIGH.on_interrupt()
118}
119
120#[interrupt]
121unsafe fn SWI_IRQ_0() {
122 EXECUTOR_MED.on_interrupt()
123}
124
125#[entry]
126fn main() -> ! {
127 info!("Hello World!");
128
129 let _p = embassy_rp::init(Default::default());
130
131 // High-priority executor: SWI_IRQ_1, priority level 2
132 interrupt::SWI_IRQ_1.set_priority(Priority::P2);
133 let spawner = EXECUTOR_HIGH.start(interrupt::SWI_IRQ_1);
134 unwrap!(spawner.spawn(run_high()));
135
136 // Medium-priority executor: SWI_IRQ_0, priority level 3
137 interrupt::SWI_IRQ_0.set_priority(Priority::P3);
138 let spawner = EXECUTOR_MED.start(interrupt::SWI_IRQ_0);
139 unwrap!(spawner.spawn(run_med()));
140
141 // Low priority executor: runs in thread mode, using WFE/SEV
142 let executor = EXECUTOR_LOW.init(Executor::new());
143 executor.run(|spawner| {
144 unwrap!(spawner.spawn(run_low()));
145 });
146}
diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs
new file mode 100644
index 000000000..c001d6440
--- /dev/null
+++ b/examples/rp/src/bin/pio_async.rs
@@ -0,0 +1,135 @@
1//! This example shows powerful PIO module in the RP2040 chip.
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6use defmt::info;
7use embassy_executor::Spawner;
8use embassy_rp::bind_interrupts;
9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine};
11use embassy_rp::relocate::RelocatedProgram;
12use fixed::traits::ToFixed;
13use fixed_macro::types::U56F8;
14use {defmt_rtt as _, panic_probe as _};
15
16bind_interrupts!(struct Irqs {
17 PIO0_IRQ_0 => InterruptHandler<PIO0>;
18});
19
20fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) {
21 // Setup sm0
22
23 // Send data serially to pin
24 let prg = pio_proc::pio_asm!(
25 ".origin 16",
26 "set pindirs, 1",
27 ".wrap_target",
28 "out pins,1 [19]",
29 ".wrap",
30 );
31
32 let relocated = RelocatedProgram::new(&prg.program);
33 let mut cfg = Config::default();
34 cfg.use_program(&pio.load_program(&relocated), &[]);
35 let out_pin = pio.make_pio_pin(pin);
36 cfg.set_out_pins(&[&out_pin]);
37 cfg.set_set_pins(&[&out_pin]);
38 cfg.clock_divider = (U56F8!(125_000_000) / 20 / 200).to_fixed();
39 cfg.shift_out.auto_fill = true;
40 sm.set_config(&cfg);
41}
42
43#[embassy_executor::task]
44async fn pio_task_sm0(mut sm: StateMachine<'static, PIO0, 0>) {
45 sm.set_enable(true);
46
47 let mut v = 0x0f0caffa;
48 loop {
49 sm.tx().wait_push(v).await;
50 v ^= 0xffff;
51 info!("Pushed {:032b} to FIFO", v);
52 }
53}
54
55fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 1>) {
56 // Setupm sm1
57
58 // Read 0b10101 repeatedly until ISR is full
59 let prg = pio_proc::pio_asm!(
60 //
61 ".origin 8",
62 "set x, 0x15",
63 ".wrap_target",
64 "in x, 5 [31]",
65 ".wrap",
66 );
67
68 let relocated = RelocatedProgram::new(&prg.program);
69 let mut cfg = Config::default();
70 cfg.use_program(&pio.load_program(&relocated), &[]);
71 cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed();
72 cfg.shift_in.auto_fill = true;
73 cfg.shift_in.direction = ShiftDirection::Right;
74 sm.set_config(&cfg);
75}
76
77#[embassy_executor::task]
78async fn pio_task_sm1(mut sm: StateMachine<'static, PIO0, 1>) {
79 sm.set_enable(true);
80 loop {
81 let rx = sm.rx().wait_pull().await;
82 info!("Pulled {:032b} from FIFO", rx);
83 }
84}
85
86fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 2>) {
87 // Setup sm2
88
89 // Repeatedly trigger IRQ 3
90 let prg = pio_proc::pio_asm!(
91 ".origin 0",
92 ".wrap_target",
93 "set x,10",
94 "delay:",
95 "jmp x-- delay [15]",
96 "irq 3 [15]",
97 ".wrap",
98 );
99 let relocated = RelocatedProgram::new(&prg.program);
100 let mut cfg = Config::default();
101 cfg.use_program(&pio.load_program(&relocated), &[]);
102 cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed();
103 sm.set_config(&cfg);
104}
105
106#[embassy_executor::task]
107async fn pio_task_sm2(mut irq: Irq<'static, PIO0, 3>, mut sm: StateMachine<'static, PIO0, 2>) {
108 sm.set_enable(true);
109 loop {
110 irq.wait().await;
111 info!("IRQ trigged");
112 }
113}
114
115#[embassy_executor::main]
116async fn main(spawner: Spawner) {
117 let p = embassy_rp::init(Default::default());
118 let pio = p.PIO0;
119
120 let Pio {
121 mut common,
122 irq3,
123 mut sm0,
124 mut sm1,
125 mut sm2,
126 ..
127 } = Pio::new(pio, Irqs);
128
129 setup_pio_task_sm0(&mut common, &mut sm0, p.PIN_0);
130 setup_pio_task_sm1(&mut common, &mut sm1);
131 setup_pio_task_sm2(&mut common, &mut sm2);
132 spawner.spawn(pio_task_sm0(sm0)).unwrap();
133 spawner.spawn(pio_task_sm1(sm1)).unwrap();
134 spawner.spawn(pio_task_sm2(irq3, sm2)).unwrap();
135}
diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs
new file mode 100644
index 000000000..9ab72e1f3
--- /dev/null
+++ b/examples/rp/src/bin/pio_dma.rs
@@ -0,0 +1,86 @@
1//! This example shows powerful PIO module in the RP2040 chip.
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6use defmt::info;
7use embassy_executor::Spawner;
8use embassy_futures::join::join;
9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection};
11use embassy_rp::relocate::RelocatedProgram;
12use embassy_rp::{bind_interrupts, Peripheral};
13use fixed::traits::ToFixed;
14use fixed_macro::types::U56F8;
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 PIO0_IRQ_0 => InterruptHandler<PIO0>;
19});
20
21fn swap_nibbles(v: u32) -> u32 {
22 let v = (v & 0x0f0f_0f0f) << 4 | (v & 0xf0f0_f0f0) >> 4;
23 let v = (v & 0x00ff_00ff) << 8 | (v & 0xff00_ff00) >> 8;
24 (v & 0x0000_ffff) << 16 | (v & 0xffff_0000) >> 16
25}
26
27#[embassy_executor::main]
28async fn main(_spawner: Spawner) {
29 let p = embassy_rp::init(Default::default());
30 let pio = p.PIO0;
31 let Pio {
32 mut common,
33 sm0: mut sm,
34 ..
35 } = Pio::new(pio, Irqs);
36
37 let prg = pio_proc::pio_asm!(
38 ".origin 0",
39 "set pindirs,1",
40 ".wrap_target",
41 "set y,7",
42 "loop:",
43 "out x,4",
44 "in x,4",
45 "jmp y--, loop",
46 ".wrap",
47 );
48
49 let relocated = RelocatedProgram::new(&prg.program);
50 let mut cfg = Config::default();
51 cfg.use_program(&common.load_program(&relocated), &[]);
52 cfg.clock_divider = (U56F8!(125_000_000) / U56F8!(10_000)).to_fixed();
53 cfg.shift_in = ShiftConfig {
54 auto_fill: true,
55 threshold: 32,
56 direction: ShiftDirection::Left,
57 };
58 cfg.shift_out = ShiftConfig {
59 auto_fill: true,
60 threshold: 32,
61 direction: ShiftDirection::Right,
62 };
63
64 sm.set_config(&cfg);
65 sm.set_enable(true);
66
67 let mut dma_out_ref = p.DMA_CH0.into_ref();
68 let mut dma_in_ref = p.DMA_CH1.into_ref();
69 let mut dout = [0x12345678u32; 29];
70 for i in 1..dout.len() {
71 dout[i] = (dout[i - 1] & 0x0fff_ffff) * 13 + 7;
72 }
73 let mut din = [0u32; 29];
74 loop {
75 let (rx, tx) = sm.rx_tx();
76 join(
77 tx.dma_push(dma_out_ref.reborrow(), &dout),
78 rx.dma_pull(dma_in_ref.reborrow(), &mut din),
79 )
80 .await;
81 for i in 0..din.len() {
82 assert_eq!(din[i], swap_nibbles(dout[i]));
83 }
84 info!("Swapped {} words", dout.len());
85 }
86}
diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs
new file mode 100644
index 000000000..8aedd24b6
--- /dev/null
+++ b/examples/rp/src/bin/pio_hd44780.rs
@@ -0,0 +1,244 @@
1//! This example shows powerful PIO module in the RP2040 chip to communicate with a HD44780 display.
2//! See (https://www.sparkfun.com/datasheets/LCD/HD44780.pdf)
3
4#![no_std]
5#![no_main]
6#![feature(type_alias_impl_trait)]
7
8use core::fmt::Write;
9
10use embassy_executor::Spawner;
11use embassy_rp::dma::{AnyChannel, Channel};
12use embassy_rp::peripherals::PIO0;
13use embassy_rp::pio::{
14 Config, Direction, FifoJoin, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine,
15};
16use embassy_rp::pwm::{self, Pwm};
17use embassy_rp::relocate::RelocatedProgram;
18use embassy_rp::{bind_interrupts, into_ref, Peripheral, PeripheralRef};
19use embassy_time::{Duration, Instant, Timer};
20use {defmt_rtt as _, panic_probe as _};
21
22bind_interrupts!(pub struct Irqs {
23 PIO0_IRQ_0 => InterruptHandler<PIO0>;
24});
25
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 // this test assumes a 2x16 HD44780 display attached as follow:
29 // rs = PIN0
30 // rw = PIN1
31 // e = PIN2
32 // db4 = PIN3
33 // db5 = PIN4
34 // db6 = PIN5
35 // db7 = PIN6
36 // additionally a pwm signal for a bias voltage charge pump is provided on pin 15,
37 // allowing direct connection of the display to the RP2040 without level shifters.
38 let p = embassy_rp::init(Default::default());
39
40 let _pwm = Pwm::new_output_b(p.PWM_CH7, p.PIN_15, {
41 let mut c = pwm::Config::default();
42 c.divider = 125.into();
43 c.top = 100;
44 c.compare_b = 50;
45 c
46 });
47
48 let mut hd = HD44780::new(
49 p.PIO0, Irqs, p.DMA_CH3, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, p.PIN_4, p.PIN_5, p.PIN_6,
50 )
51 .await;
52
53 loop {
54 struct Buf<const N: usize>([u8; N], usize);
55 impl<const N: usize> Write for Buf<N> {
56 fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
57 for b in s.as_bytes() {
58 if self.1 >= N {
59 return Err(core::fmt::Error);
60 }
61 self.0[self.1] = *b;
62 self.1 += 1;
63 }
64 Ok(())
65 }
66 }
67 let mut buf = Buf([0; 16], 0);
68 write!(buf, "up {}s", Instant::now().as_micros() as f32 / 1e6).unwrap();
69 hd.add_line(&buf.0[0..buf.1]).await;
70 Timer::after(Duration::from_secs(1)).await;
71 }
72}
73
74pub struct HD44780<'l> {
75 dma: PeripheralRef<'l, AnyChannel>,
76 sm: StateMachine<'l, PIO0, 0>,
77
78 buf: [u8; 40],
79}
80
81impl<'l> HD44780<'l> {
82 pub async fn new(
83 pio: impl Peripheral<P = PIO0> + 'l,
84 irq: Irqs,
85 dma: impl Peripheral<P = impl Channel> + 'l,
86 rs: impl PioPin,
87 rw: impl PioPin,
88 e: impl PioPin,
89 db4: impl PioPin,
90 db5: impl PioPin,
91 db6: impl PioPin,
92 db7: impl PioPin,
93 ) -> HD44780<'l> {
94 into_ref!(dma);
95
96 let Pio {
97 mut common,
98 mut irq0,
99 mut sm0,
100 ..
101 } = Pio::new(pio, irq);
102
103 // takes command words (<wait:24> <command:4> <0:4>)
104 let prg = pio_proc::pio_asm!(
105 r#"
106 .side_set 1 opt
107 .origin 20
108
109 loop:
110 out x, 24
111 delay:
112 jmp x--, delay
113 out pins, 4 side 1
114 out null, 4 side 0
115 jmp !osre, loop
116 irq 0
117 "#,
118 );
119
120 let rs = common.make_pio_pin(rs);
121 let rw = common.make_pio_pin(rw);
122 let e = common.make_pio_pin(e);
123 let db4 = common.make_pio_pin(db4);
124 let db5 = common.make_pio_pin(db5);
125 let db6 = common.make_pio_pin(db6);
126 let db7 = common.make_pio_pin(db7);
127
128 sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]);
129
130 let relocated = RelocatedProgram::new(&prg.program);
131 let mut cfg = Config::default();
132 cfg.use_program(&common.load_program(&relocated), &[&e]);
133 cfg.clock_divider = 125u8.into();
134 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
135 cfg.shift_out = ShiftConfig {
136 auto_fill: true,
137 direction: ShiftDirection::Left,
138 threshold: 32,
139 };
140 cfg.fifo_join = FifoJoin::TxOnly;
141 sm0.set_config(&cfg);
142
143 sm0.set_enable(true);
144 // init to 8 bit thrice
145 sm0.tx().push((50000 << 8) | 0x30);
146 sm0.tx().push((5000 << 8) | 0x30);
147 sm0.tx().push((200 << 8) | 0x30);
148 // init 4 bit
149 sm0.tx().push((200 << 8) | 0x20);
150 // set font and lines
151 sm0.tx().push((50 << 8) | 0x20);
152 sm0.tx().push(0b1100_0000);
153
154 irq0.wait().await;
155 sm0.set_enable(false);
156
157 // takes command sequences (<rs:1> <count:7>, data...)
158 // many side sets are only there to free up a delay bit!
159 let prg = pio_proc::pio_asm!(
160 r#"
161 .origin 27
162 .side_set 1
163
164 .wrap_target
165 pull side 0
166 out x 1 side 0 ; !rs
167 out y 7 side 0 ; #data - 1
168
169 ; rs/rw to e: >= 60ns
170 ; e high time: >= 500ns
171 ; e low time: >= 500ns
172 ; read data valid after e falling: ~5ns
173 ; write data hold after e falling: ~10ns
174
175 loop:
176 pull side 0
177 jmp !x data side 0
178 command:
179 set pins 0b00 side 0
180 jmp shift side 0
181 data:
182 set pins 0b01 side 0
183 shift:
184 out pins 4 side 1 [9]
185 nop side 0 [9]
186 out pins 4 side 1 [9]
187 mov osr null side 0 [7]
188 out pindirs 4 side 0
189 set pins 0b10 side 0
190 busy:
191 nop side 1 [9]
192 jmp pin more side 0 [9]
193 mov osr ~osr side 1 [9]
194 nop side 0 [4]
195 out pindirs 4 side 0
196 jmp y-- loop side 0
197 .wrap
198 more:
199 nop side 1 [9]
200 jmp busy side 0 [9]
201 "#
202 );
203
204 let relocated = RelocatedProgram::new(&prg.program);
205 let mut cfg = Config::default();
206 cfg.use_program(&common.load_program(&relocated), &[&e]);
207 cfg.clock_divider = 8u8.into(); // ~64ns/insn
208 cfg.set_jmp_pin(&db7);
209 cfg.set_set_pins(&[&rs, &rw]);
210 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
211 cfg.shift_out.direction = ShiftDirection::Left;
212 cfg.fifo_join = FifoJoin::TxOnly;
213 sm0.set_config(&cfg);
214
215 sm0.set_enable(true);
216
217 // display on and cursor on and blinking, reset display
218 sm0.tx().dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await;
219
220 Self {
221 dma: dma.map_into(),
222 sm: sm0,
223 buf: [0x20; 40],
224 }
225 }
226
227 pub async fn add_line(&mut self, s: &[u8]) {
228 // move cursor to 0:0, prepare 16 characters
229 self.buf[..3].copy_from_slice(&[0x80, 0x80, 15]);
230 // move line 2 up
231 self.buf.copy_within(22..38, 3);
232 // move cursor to 1:0, prepare 16 characters
233 self.buf[19..22].copy_from_slice(&[0x80, 0xc0, 15]);
234 // file line 2 with spaces
235 self.buf[22..38].fill(0x20);
236 // copy input line
237 let len = s.len().min(16);
238 self.buf[22..22 + len].copy_from_slice(&s[0..len]);
239 // set cursor to 1:15
240 self.buf[38..].copy_from_slice(&[0x80, 0xcf]);
241
242 self.sm.tx().dma_push(self.dma.reborrow(), &self.buf).await;
243 }
244}
diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs
new file mode 100644
index 000000000..3de2bd48d
--- /dev/null
+++ b/examples/rp/src/bin/pio_ws2812.rs
@@ -0,0 +1,160 @@
1//! This example shows powerful PIO module in the RP2040 chip to communicate with WS2812 LED modules.
2//! See (https://www.sparkfun.com/categories/tags/ws2812)
3
4#![no_std]
5#![no_main]
6#![feature(type_alias_impl_trait)]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::dma::{AnyChannel, Channel};
11use embassy_rp::peripherals::PIO0;
12use embassy_rp::pio::{
13 Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine,
14};
15use embassy_rp::relocate::RelocatedProgram;
16use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef};
17use embassy_time::{Duration, Timer};
18use fixed::types::U24F8;
19use fixed_macro::fixed;
20use smart_leds::RGB8;
21use {defmt_rtt as _, panic_probe as _};
22
23bind_interrupts!(struct Irqs {
24 PIO0_IRQ_0 => InterruptHandler<PIO0>;
25});
26
27pub struct Ws2812<'d, P: Instance, const S: usize, const N: usize> {
28 dma: PeripheralRef<'d, AnyChannel>,
29 sm: StateMachine<'d, P, S>,
30}
31
32impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> {
33 pub fn new(
34 pio: &mut Common<'d, P>,
35 mut sm: StateMachine<'d, P, S>,
36 dma: impl Peripheral<P = impl Channel> + 'd,
37 pin: impl PioPin,
38 ) -> Self {
39 into_ref!(dma);
40
41 // Setup sm0
42
43 // prepare the PIO program
44 let side_set = pio::SideSet::new(false, 1, false);
45 let mut a: pio::Assembler<32> = pio::Assembler::new_with_side_set(side_set);
46
47 const T1: u8 = 2; // start bit
48 const T2: u8 = 5; // data bit
49 const T3: u8 = 3; // stop bit
50 const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32;
51
52 let mut wrap_target = a.label();
53 let mut wrap_source = a.label();
54 let mut do_zero = a.label();
55 a.set_with_side_set(pio::SetDestination::PINDIRS, 1, 0);
56 a.bind(&mut wrap_target);
57 // Do stop bit
58 a.out_with_delay_and_side_set(pio::OutDestination::X, 1, T3 - 1, 0);
59 // Do start bit
60 a.jmp_with_delay_and_side_set(pio::JmpCondition::XIsZero, &mut do_zero, T1 - 1, 1);
61 // Do data bit = 1
62 a.jmp_with_delay_and_side_set(pio::JmpCondition::Always, &mut wrap_target, T2 - 1, 1);
63 a.bind(&mut do_zero);
64 // Do data bit = 0
65 a.nop_with_delay_and_side_set(T2 - 1, 0);
66 a.bind(&mut wrap_source);
67
68 let prg = a.assemble_with_wrap(wrap_source, wrap_target);
69 let mut cfg = Config::default();
70
71 // Pin config
72 let out_pin = pio.make_pio_pin(pin);
73 cfg.set_out_pins(&[&out_pin]);
74 cfg.set_set_pins(&[&out_pin]);
75
76 let relocated = RelocatedProgram::new(&prg);
77 cfg.use_program(&pio.load_program(&relocated), &[&out_pin]);
78
79 // Clock config, measured in kHz to avoid overflows
80 // TODO CLOCK_FREQ should come from embassy_rp
81 let clock_freq = U24F8::from_num(clocks::clk_sys_freq() / 1000);
82 let ws2812_freq = fixed!(800: U24F8);
83 let bit_freq = ws2812_freq * CYCLES_PER_BIT;
84 cfg.clock_divider = clock_freq / bit_freq;
85
86 // FIFO config
87 cfg.fifo_join = FifoJoin::TxOnly;
88 cfg.shift_out = ShiftConfig {
89 auto_fill: true,
90 threshold: 24,
91 direction: ShiftDirection::Left,
92 };
93
94 sm.set_config(&cfg);
95 sm.set_enable(true);
96
97 Self {
98 dma: dma.map_into(),
99 sm,
100 }
101 }
102
103 pub async fn write(&mut self, colors: &[RGB8; N]) {
104 // Precompute the word bytes from the colors
105 let mut words = [0u32; N];
106 for i in 0..N {
107 let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8);
108 words[i] = word;
109 }
110
111 // DMA transfer
112 self.sm.tx().dma_push(self.dma.reborrow(), &words).await;
113 }
114}
115
116/// Input a value 0 to 255 to get a color value
117/// The colours are a transition r - g - b - back to r.
118fn wheel(mut wheel_pos: u8) -> RGB8 {
119 wheel_pos = 255 - wheel_pos;
120 if wheel_pos < 85 {
121 return (255 - wheel_pos * 3, 0, wheel_pos * 3).into();
122 }
123 if wheel_pos < 170 {
124 wheel_pos -= 85;
125 return (0, wheel_pos * 3, 255 - wheel_pos * 3).into();
126 }
127 wheel_pos -= 170;
128 (wheel_pos * 3, 255 - wheel_pos * 3, 0).into()
129}
130
131#[embassy_executor::main]
132async fn main(_spawner: Spawner) {
133 info!("Start");
134 let p = embassy_rp::init(Default::default());
135
136 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
137
138 // This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit
139 // feather boards for the 2040 both have one built in.
140 const NUM_LEDS: usize = 1;
141 let mut data = [RGB8::default(); NUM_LEDS];
142
143 // For the thing plus, use pin 8
144 // For the feather, use pin 16
145 let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16);
146
147 // Loop forever making RGB values and pushing them out to the WS2812.
148 loop {
149 for j in 0..(256 * 5) {
150 debug!("New Colors:");
151 for i in 0..NUM_LEDS {
152 data[i] = wheel((((i * 256) as u16 / NUM_LEDS as u16 + j as u16) & 255) as u8);
153 debug!("R: {} G: {} B: {}", data[i].r, data[i].g, data[i].b);
154 }
155 ws2812.write(&data).await;
156
157 Timer::after(Duration::from_micros(5)).await;
158 }
159 }
160}
diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs
new file mode 100644
index 000000000..9d919287c
--- /dev/null
+++ b/examples/rp/src/bin/pwm.rs
@@ -0,0 +1,30 @@
1//! This example shows how to use PWM (Pulse Width Modulation) in the RP2040 chip.
2//!
3//! The LED on the RP Pico W board is connected differently. Add a LED and resistor to another pin.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_rp::pwm::{Config, Pwm};
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 c: Config = Default::default();
20 c.top = 0x8000;
21 c.compare_b = 8;
22 let mut pwm = Pwm::new_output_b(p.PWM_CH4, p.PIN_25, c.clone());
23
24 loop {
25 info!("current LED duty cycle: {}/32768", c.compare_b);
26 Timer::after(Duration::from_secs(1)).await;
27 c.compare_b = c.compare_b.rotate_left(4);
28 pwm.set_config(&c);
29 }
30}
diff --git a/examples/rp/src/bin/rtc.rs b/examples/rp/src/bin/rtc.rs
new file mode 100644
index 000000000..15aa8243f
--- /dev/null
+++ b/examples/rp/src/bin/rtc.rs
@@ -0,0 +1,46 @@
1//! This example shows how to use RTC (Real Time Clock) in the RP2040 chip.
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::rtc::{DateTime, DayOfWeek, Rtc};
10use embassy_time::{Duration, Timer};
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!("Wait for 20s");
17
18 let mut rtc = Rtc::new(p.RTC);
19
20 if !rtc.is_running() {
21 info!("Start RTC");
22 let now = DateTime {
23 year: 2000,
24 month: 1,
25 day: 1,
26 day_of_week: DayOfWeek::Saturday,
27 hour: 0,
28 minute: 0,
29 second: 0,
30 };
31 rtc.set_datetime(now).unwrap();
32 }
33
34 Timer::after(Duration::from_millis(20000)).await;
35
36 if let Ok(dt) = rtc.now() {
37 info!(
38 "Now: {}-{:02}-{:02} {}:{:02}:{:02}",
39 dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second,
40 );
41 }
42
43 info!("Reboot.");
44 Timer::after(Duration::from_millis(200)).await;
45 cortex_m::peripheral::SCB::sys_reset();
46}
diff --git a/examples/rp/src/bin/spi.rs b/examples/rp/src/bin/spi.rs
index 88003ee17..602348f7a 100644
--- a/examples/rp/src/bin/spi.rs
+++ b/examples/rp/src/bin/spi.rs
@@ -1,3 +1,7 @@
1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip.
2//!
3//! Example for resistive touch sensor in Waveshare Pico-ResTouch
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
@@ -24,7 +28,7 @@ async fn main(_spawner: Spawner) {
24 // create SPI 28 // create SPI
25 let mut config = spi::Config::default(); 29 let mut config = spi::Config::default();
26 config.frequency = 2_000_000; 30 config.frequency = 2_000_000;
27 let mut spi = Spi::new(p.SPI1, clk, mosi, miso, config); 31 let mut spi = Spi::new_blocking(p.SPI1, clk, mosi, miso, config);
28 32
29 // Configure CS 33 // Configure CS
30 let mut cs = Output::new(touch_cs, Level::Low); 34 let mut cs = Output::new(touch_cs, Level::Low);
diff --git a/examples/rp/src/bin/spi_async.rs b/examples/rp/src/bin/spi_async.rs
new file mode 100644
index 000000000..328074e8b
--- /dev/null
+++ b/examples/rp/src/bin/spi_async.rs
@@ -0,0 +1,32 @@
1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip.
2//! No specific hardware is specified in this example. If you connect pin 11 and 12 you should get the same data back.
3
4#![no_std]
5#![no_main]
6#![feature(type_alias_impl_trait)]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::spi::{Config, Spi};
11use embassy_time::{Duration, Timer};
12use {defmt_rtt as _, panic_probe as _};
13
14#[embassy_executor::main]
15async fn main(_spawner: Spawner) {
16 let p = embassy_rp::init(Default::default());
17 info!("Hello World!");
18
19 let miso = p.PIN_12;
20 let mosi = p.PIN_11;
21 let clk = p.PIN_10;
22
23 let mut spi = Spi::new(p.SPI1, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default());
24
25 loop {
26 let tx_buf = [1_u8, 2, 3, 4, 5, 6];
27 let mut rx_buf = [0_u8; 6];
28 spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
29 info!("{:?}", rx_buf);
30 Timer::after(Duration::from_secs(1)).await;
31 }
32}
diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs
index f0e54d87f..26c258e1c 100644
--- a/examples/rp/src/bin/spi_display.rs
+++ b/examples/rp/src/bin/spi_display.rs
@@ -1,3 +1,8 @@
1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip.
2//!
3//! Example written for a display using the ST7789 chip. Possibly the Waveshare Pico-ResTouch
4//! (https://www.waveshare.com/wiki/Pico-ResTouch-LCD-2.8)
5
1#![no_std] 6#![no_std]
2#![no_main] 7#![no_main]
3#![feature(type_alias_impl_trait)] 8#![feature(type_alias_impl_trait)]
@@ -5,10 +10,13 @@
5use core::cell::RefCell; 10use core::cell::RefCell;
6 11
7use defmt::*; 12use defmt::*;
13use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig;
8use embassy_executor::Spawner; 14use embassy_executor::Spawner;
9use embassy_rp::gpio::{Level, Output}; 15use embassy_rp::gpio::{Level, Output};
10use embassy_rp::spi; 16use embassy_rp::spi;
11use embassy_rp::spi::Spi; 17use embassy_rp::spi::{Blocking, Spi};
18use embassy_sync::blocking_mutex::raw::NoopRawMutex;
19use embassy_sync::blocking_mutex::Mutex;
12use embassy_time::Delay; 20use embassy_time::Delay;
13use embedded_graphics::image::{Image, ImageRawLE}; 21use embedded_graphics::image::{Image, ImageRawLE};
14use embedded_graphics::mono_font::ascii::FONT_10X20; 22use embedded_graphics::mono_font::ascii::FONT_10X20;
@@ -21,10 +29,9 @@ use st7789::{Orientation, ST7789};
21use {defmt_rtt as _, panic_probe as _}; 29use {defmt_rtt as _, panic_probe as _};
22 30
23use crate::my_display_interface::SPIDeviceInterface; 31use crate::my_display_interface::SPIDeviceInterface;
24use crate::shared_spi::SpiDeviceWithCs;
25use crate::touch::Touch; 32use crate::touch::Touch;
26 33
27//const DISPLAY_FREQ: u32 = 64_000_000; 34const DISPLAY_FREQ: u32 = 64_000_000;
28const TOUCH_FREQ: u32 = 200_000; 35const TOUCH_FREQ: u32 = 200_000;
29 36
30#[embassy_executor::main] 37#[embassy_executor::main]
@@ -43,15 +50,20 @@ async fn main(_spawner: Spawner) {
43 //let touch_irq = p.PIN_17; 50 //let touch_irq = p.PIN_17;
44 51
45 // create SPI 52 // create SPI
46 let mut config = spi::Config::default(); 53 let mut display_config = spi::Config::default();
47 config.frequency = TOUCH_FREQ; // use the lowest freq 54 display_config.frequency = DISPLAY_FREQ;
48 config.phase = spi::Phase::CaptureOnSecondTransition; 55 display_config.phase = spi::Phase::CaptureOnSecondTransition;
49 config.polarity = spi::Polarity::IdleHigh; 56 display_config.polarity = spi::Polarity::IdleHigh;
57 let mut touch_config = spi::Config::default();
58 touch_config.frequency = TOUCH_FREQ;
59 touch_config.phase = spi::Phase::CaptureOnSecondTransition;
60 touch_config.polarity = spi::Polarity::IdleHigh;
50 61
51 let spi_bus = RefCell::new(Spi::new(p.SPI1, clk, mosi, miso, config)); 62 let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone());
63 let spi_bus: Mutex<NoopRawMutex, _> = Mutex::new(RefCell::new(spi));
52 64
53 let display_spi = SpiDeviceWithCs::new(&spi_bus, Output::new(display_cs, Level::High)); 65 let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config);
54 let touch_spi = SpiDeviceWithCs::new(&spi_bus, Output::new(touch_cs, Level::High)); 66 let touch_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(touch_cs, Level::High), touch_config);
55 67
56 let mut touch = Touch::new(touch_spi); 68 let mut touch = Touch::new(touch_spi);
57 69
@@ -103,85 +115,9 @@ async fn main(_spawner: Spawner) {
103 } 115 }
104} 116}
105 117
106mod shared_spi {
107 use core::cell::RefCell;
108 use core::fmt::Debug;
109
110 use embedded_hal_1::digital::blocking::OutputPin;
111 use embedded_hal_1::spi;
112 use embedded_hal_1::spi::blocking::SpiDevice;
113
114 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
115 pub enum SpiDeviceWithCsError<BUS, CS> {
116 #[allow(unused)] // will probably use in the future when adding a flush() to SpiBus
117 Spi(BUS),
118 Cs(CS),
119 }
120
121 impl<BUS, CS> spi::Error for SpiDeviceWithCsError<BUS, CS>
122 where
123 BUS: spi::Error + Debug,
124 CS: Debug,
125 {
126 fn kind(&self) -> spi::ErrorKind {
127 match self {
128 Self::Spi(e) => e.kind(),
129 Self::Cs(_) => spi::ErrorKind::Other,
130 }
131 }
132 }
133
134 pub struct SpiDeviceWithCs<'a, BUS, CS> {
135 bus: &'a RefCell<BUS>,
136 cs: CS,
137 }
138
139 impl<'a, BUS, CS> SpiDeviceWithCs<'a, BUS, CS> {
140 pub fn new(bus: &'a RefCell<BUS>, cs: CS) -> Self {
141 Self { bus, cs }
142 }
143 }
144
145 impl<'a, BUS, CS> spi::ErrorType for SpiDeviceWithCs<'a, BUS, CS>
146 where
147 BUS: spi::ErrorType,
148 CS: OutputPin,
149 {
150 type Error = SpiDeviceWithCsError<BUS::Error, CS::Error>;
151 }
152
153 impl<'a, BUS, CS> SpiDevice for SpiDeviceWithCs<'a, BUS, CS>
154 where
155 BUS: spi::blocking::SpiBusFlush,
156 CS: OutputPin,
157 {
158 type Bus = BUS;
159
160 fn transaction<R>(
161 &mut self,
162 f: impl FnOnce(&mut Self::Bus) -> Result<R, BUS::Error>,
163 ) -> Result<R, Self::Error> {
164 let mut bus = self.bus.borrow_mut();
165 self.cs.set_low().map_err(SpiDeviceWithCsError::Cs)?;
166
167 let f_res = f(&mut bus);
168
169 // On failure, it's important to still flush and deassert CS.
170 let flush_res = bus.flush();
171 let cs_res = self.cs.set_high();
172
173 let f_res = f_res.map_err(SpiDeviceWithCsError::Spi)?;
174 flush_res.map_err(SpiDeviceWithCsError::Spi)?;
175 cs_res.map_err(SpiDeviceWithCsError::Cs)?;
176
177 Ok(f_res)
178 }
179 }
180}
181
182/// Driver for the XPT2046 resistive touchscreen sensor 118/// Driver for the XPT2046 resistive touchscreen sensor
183mod touch { 119mod touch {
184 use embedded_hal_1::spi::blocking::{SpiBus, SpiBusRead, SpiBusWrite, SpiDevice}; 120 use embedded_hal_1::spi::{Operation, SpiDevice};
185 121
186 struct Calibration { 122 struct Calibration {
187 x1: i32, 123 x1: i32,
@@ -208,7 +144,6 @@ mod touch {
208 impl<SPI> Touch<SPI> 144 impl<SPI> Touch<SPI>
209 where 145 where
210 SPI: SpiDevice, 146 SPI: SpiDevice,
211 SPI::Bus: SpiBus,
212 { 147 {
213 pub fn new(spi: SPI) -> Self { 148 pub fn new(spi: SPI) -> Self {
214 Self { spi } 149 Self { spi }
@@ -218,13 +153,12 @@ mod touch {
218 let mut x = [0; 2]; 153 let mut x = [0; 2];
219 let mut y = [0; 2]; 154 let mut y = [0; 2];
220 self.spi 155 self.spi
221 .transaction(|bus| { 156 .transaction(&mut [
222 bus.write(&[0x90])?; 157 Operation::Write(&[0x90]),
223 bus.read(&mut x)?; 158 Operation::Read(&mut x),
224 bus.write(&[0xd0])?; 159 Operation::Write(&[0xd0]),
225 bus.read(&mut y)?; 160 Operation::Read(&mut y),
226 Ok(()) 161 ])
227 })
228 .unwrap(); 162 .unwrap();
229 163
230 let x = (u16::from_be_bytes(x) >> 3) as i32; 164 let x = (u16::from_be_bytes(x) >> 3) as i32;
@@ -245,8 +179,8 @@ mod touch {
245 179
246mod my_display_interface { 180mod my_display_interface {
247 use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand}; 181 use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand};
248 use embedded_hal_1::digital::blocking::OutputPin; 182 use embedded_hal_1::digital::OutputPin;
249 use embedded_hal_1::spi::blocking::{SpiBusWrite, SpiDevice}; 183 use embedded_hal_1::spi::SpiDevice;
250 184
251 /// SPI display interface. 185 /// SPI display interface.
252 /// 186 ///
@@ -259,7 +193,6 @@ mod my_display_interface {
259 impl<SPI, DC> SPIDeviceInterface<SPI, DC> 193 impl<SPI, DC> SPIDeviceInterface<SPI, DC>
260 where 194 where
261 SPI: SpiDevice, 195 SPI: SpiDevice,
262 SPI::Bus: SpiBusWrite,
263 DC: OutputPin, 196 DC: OutputPin,
264 { 197 {
265 /// Create new SPI interface for communciation with a display driver 198 /// Create new SPI interface for communciation with a display driver
@@ -271,41 +204,26 @@ mod my_display_interface {
271 impl<SPI, DC> WriteOnlyDataCommand for SPIDeviceInterface<SPI, DC> 204 impl<SPI, DC> WriteOnlyDataCommand for SPIDeviceInterface<SPI, DC>
272 where 205 where
273 SPI: SpiDevice, 206 SPI: SpiDevice,
274 SPI::Bus: SpiBusWrite,
275 DC: OutputPin, 207 DC: OutputPin,
276 { 208 {
277 fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> { 209 fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> {
278 let r = self.spi.transaction(|bus| { 210 // 1 = data, 0 = command
279 // 1 = data, 0 = command 211 self.dc.set_low().map_err(|_| DisplayError::DCError)?;
280 if let Err(_) = self.dc.set_low() {
281 return Ok(Err(DisplayError::DCError));
282 }
283
284 // Send words over SPI
285 send_u8(bus, cmds)?;
286 212
287 Ok(Ok(())) 213 send_u8(&mut self.spi, cmds).map_err(|_| DisplayError::BusWriteError)?;
288 }); 214 Ok(())
289 r.map_err(|_| DisplayError::BusWriteError)?
290 } 215 }
291 216
292 fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> { 217 fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> {
293 let r = self.spi.transaction(|bus| { 218 // 1 = data, 0 = command
294 // 1 = data, 0 = command 219 self.dc.set_high().map_err(|_| DisplayError::DCError)?;
295 if let Err(_) = self.dc.set_high() {
296 return Ok(Err(DisplayError::DCError));
297 }
298
299 // Send words over SPI
300 send_u8(bus, buf)?;
301 220
302 Ok(Ok(())) 221 send_u8(&mut self.spi, buf).map_err(|_| DisplayError::BusWriteError)?;
303 }); 222 Ok(())
304 r.map_err(|_| DisplayError::BusWriteError)?
305 } 223 }
306 } 224 }
307 225
308 fn send_u8<T: SpiBusWrite>(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> { 226 fn send_u8<T: SpiDevice>(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> {
309 match words { 227 match words {
310 DataFormat::U8(slice) => spi.write(slice), 228 DataFormat::U8(slice) => spi.write(slice),
311 DataFormat::U16(slice) => { 229 DataFormat::U16(slice) => {
diff --git a/examples/rp/src/bin/uart.rs b/examples/rp/src/bin/uart.rs
index c63b31cae..451c3c396 100644
--- a/examples/rp/src/bin/uart.rs
+++ b/examples/rp/src/bin/uart.rs
@@ -1,3 +1,9 @@
1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip.
2//!
3//! No specific hardware is specified in this example. Only output on pin 0 is tested.
4//! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used
5//! with its UART port.
6
1#![no_std] 7#![no_std]
2#![no_main] 8#![no_main]
3#![feature(type_alias_impl_trait)] 9#![feature(type_alias_impl_trait)]
@@ -10,7 +16,7 @@ use {defmt_rtt as _, panic_probe as _};
10async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
11 let p = embassy_rp::init(Default::default()); 17 let p = embassy_rp::init(Default::default());
12 let config = uart::Config::default(); 18 let config = uart::Config::default();
13 let mut uart = uart::Uart::new_with_rtscts(p.UART0, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, config); 19 let mut uart = uart::Uart::new_with_rtscts_blocking(p.UART0, p.PIN_0, p.PIN_1, p.PIN_3, p.PIN_2, config);
14 uart.blocking_write("Hello World!\r\n".as_bytes()).unwrap(); 20 uart.blocking_write("Hello World!\r\n".as_bytes()).unwrap();
15 21
16 loop { 22 loop {
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..735201718
--- /dev/null
+++ b/examples/rp/src/bin/uart_buffered_split.rs
@@ -0,0 +1,57 @@
1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip.
2//!
3//! No specific hardware is specified in this example. If you connect pin 0 and 1 you should get the same data back.
4//! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used
5//! with its UART port.
6
7#![no_std]
8#![no_main]
9#![feature(type_alias_impl_trait)]
10
11use defmt::*;
12use embassy_executor::Spawner;
13use embassy_rp::bind_interrupts;
14use embassy_rp::peripherals::UART0;
15use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config};
16use embassy_time::{Duration, Timer};
17use embedded_io::asynch::{Read, Write};
18use static_cell::make_static;
19use {defmt_rtt as _, panic_probe as _};
20
21bind_interrupts!(struct Irqs {
22 UART0_IRQ => BufferedInterruptHandler<UART0>;
23});
24
25#[embassy_executor::main]
26async fn main(spawner: Spawner) {
27 let p = embassy_rp::init(Default::default());
28 let (tx_pin, rx_pin, uart) = (p.PIN_0, p.PIN_1, p.UART0);
29
30 let tx_buf = &mut make_static!([0u8; 16])[..];
31 let rx_buf = &mut make_static!([0u8; 16])[..];
32 let uart = BufferedUart::new(uart, Irqs, 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..c1515a911
--- /dev/null
+++ b/examples/rp/src/bin/uart_unidir.rs
@@ -0,0 +1,51 @@
1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip.
2//!
3//! Test TX-only and RX-only on two different UARTs. You need to connect GPIO0 to GPIO5 for
4//! this to work
5//! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used
6//! with its UART port.
7
8#![no_std]
9#![no_main]
10#![feature(type_alias_impl_trait)]
11
12use defmt::*;
13use embassy_executor::Spawner;
14use embassy_rp::bind_interrupts;
15use embassy_rp::peripherals::UART1;
16use embassy_rp::uart::{Async, Config, InterruptHandler, UartRx, UartTx};
17use embassy_time::{Duration, Timer};
18use {defmt_rtt as _, panic_probe as _};
19
20bind_interrupts!(struct Irqs {
21 UART1_IRQ => InterruptHandler<UART1>;
22});
23
24#[embassy_executor::main]
25async fn main(spawner: Spawner) {
26 let p = embassy_rp::init(Default::default());
27
28 let mut uart_tx = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, Config::default());
29 let uart_rx = UartRx::new(p.UART1, p.PIN_5, Irqs, p.DMA_CH1, Config::default());
30
31 unwrap!(spawner.spawn(reader(uart_rx)));
32
33 info!("Writing...");
34 loop {
35 let data = [1u8, 2, 3, 4, 5, 6, 7, 8];
36 info!("TX {:?}", data);
37 uart_tx.write(&data).await.unwrap();
38 Timer::after(Duration::from_secs(1)).await;
39 }
40}
41
42#[embassy_executor::task]
43async fn reader(mut rx: UartRx<'static, UART1, Async>) {
44 info!("Reading...");
45 loop {
46 // read a total of 4 transmissions (32 / 8) and then print the result
47 let mut buf = [0; 32];
48 rx.read(&mut buf).await.unwrap();
49 info!("RX {:?}", buf);
50 }
51}
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
new file mode 100644
index 000000000..0a08f667e
--- /dev/null
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -0,0 +1,155 @@
1//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip.
2//!
3//! This is a CDC-NCM class implementation, aka Ethernet over USB.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_net::tcp::TcpSocket;
12use embassy_net::{Stack, StackResources};
13use embassy_rp::peripherals::USB;
14use embassy_rp::usb::{Driver, InterruptHandler};
15use embassy_rp::{bind_interrupts, peripherals};
16use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
17use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
18use embassy_usb::{Builder, Config, UsbDevice};
19use embedded_io::asynch::Write;
20use static_cell::make_static;
21use {defmt_rtt as _, panic_probe as _};
22
23bind_interrupts!(struct Irqs {
24 USBCTRL_IRQ => InterruptHandler<USB>;
25});
26
27type MyDriver = Driver<'static, peripherals::USB>;
28
29const MTU: usize = 1514;
30
31#[embassy_executor::task]
32async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! {
33 device.run().await
34}
35
36#[embassy_executor::task]
37async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
38 class.run().await
39}
40
41#[embassy_executor::task]
42async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
43 stack.run().await
44}
45
46#[embassy_executor::main]
47async fn main(spawner: Spawner) {
48 let p = embassy_rp::init(Default::default());
49
50 // Create the driver, from the HAL.
51 let driver = Driver::new(p.USB, Irqs);
52
53 // Create embassy-usb Config
54 let mut config = Config::new(0xc0de, 0xcafe);
55 config.manufacturer = Some("Embassy");
56 config.product = Some("USB-Ethernet example");
57 config.serial_number = Some("12345678");
58 config.max_power = 100;
59 config.max_packet_size_0 = 64;
60
61 // Required for Windows support.
62 config.composite_with_iads = true;
63 config.device_class = 0xEF;
64 config.device_sub_class = 0x02;
65 config.device_protocol = 0x01;
66
67 // Create embassy-usb DeviceBuilder using the driver and config.
68 let mut builder = Builder::new(
69 driver,
70 config,
71 &mut make_static!([0; 256])[..],
72 &mut make_static!([0; 256])[..],
73 &mut make_static!([0; 256])[..],
74 &mut make_static!([0; 128])[..],
75 );
76
77 // Our MAC addr.
78 let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC];
79 // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has.
80 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
81
82 // Create classes on the builder.
83 let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64);
84
85 // Build the builder.
86 let usb = builder.build();
87
88 unwrap!(spawner.spawn(usb_task(usb)));
89
90 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr);
91 unwrap!(spawner.spawn(usb_ncm_task(runner)));
92
93 let config = embassy_net::Config::dhcpv4(Default::default());
94 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
95 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
96 // dns_servers: Vec::new(),
97 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
98 //});
99
100 // Generate random seed
101 let seed = 1234; // guaranteed random, chosen by a fair dice roll
102
103 // Init network stack
104 let stack = &*make_static!(Stack::new(
105 device,
106 config,
107 make_static!(StackResources::<2>::new()),
108 seed
109 ));
110
111 unwrap!(spawner.spawn(net_task(stack)));
112
113 // And now we can use it!
114
115 let mut rx_buffer = [0; 4096];
116 let mut tx_buffer = [0; 4096];
117 let mut buf = [0; 4096];
118
119 loop {
120 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
121 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
122
123 info!("Listening on TCP:1234...");
124 if let Err(e) = socket.accept(1234).await {
125 warn!("accept error: {:?}", e);
126 continue;
127 }
128
129 info!("Received connection from {:?}", socket.remote_endpoint());
130
131 loop {
132 let n = match socket.read(&mut buf).await {
133 Ok(0) => {
134 warn!("read EOF");
135 break;
136 }
137 Ok(n) => n,
138 Err(e) => {
139 warn!("read error: {:?}", e);
140 break;
141 }
142 };
143
144 info!("rxd {:02x}", &buf[..n]);
145
146 match socket.write_all(&buf[..n]).await {
147 Ok(()) => {}
148 Err(e) => {
149 warn!("write error: {:?}", e);
150 break;
151 }
152 };
153 }
154 }
155}
diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs
new file mode 100644
index 000000000..99af1f02f
--- /dev/null
+++ b/examples/rp/src/bin/usb_hid_keyboard.rs
@@ -0,0 +1,188 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::sync::atomic::{AtomicBool, Ordering};
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_futures::join::join;
10use embassy_rp::bind_interrupts;
11use embassy_rp::gpio::{Input, Pull};
12use embassy_rp::peripherals::USB;
13use embassy_rp::usb::{Driver, InterruptHandler};
14use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
15use embassy_usb::control::OutResponse;
16use embassy_usb::{Builder, Config, Handler};
17use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
18use {defmt_rtt as _, panic_probe as _};
19
20bind_interrupts!(struct Irqs {
21 USBCTRL_IRQ => InterruptHandler<USB>;
22});
23
24#[embassy_executor::main]
25async fn main(_spawner: Spawner) {
26 let p = embassy_rp::init(Default::default());
27 // Create the driver, from the HAL.
28 let driver = Driver::new(p.USB, Irqs);
29
30 // Create embassy-usb Config
31 let mut config = Config::new(0xc0de, 0xcafe);
32 config.manufacturer = Some("Embassy");
33 config.product = Some("HID keyboard example");
34 config.serial_number = Some("12345678");
35 config.max_power = 100;
36 config.max_packet_size_0 = 64;
37
38 // Create embassy-usb DeviceBuilder using the driver and config.
39 // It needs some buffers for building the descriptors.
40 let mut device_descriptor = [0; 256];
41 let mut config_descriptor = [0; 256];
42 let mut bos_descriptor = [0; 256];
43 // You can also add a Microsoft OS descriptor.
44 // let mut msos_descriptor = [0; 256];
45 let mut control_buf = [0; 64];
46 let request_handler = MyRequestHandler {};
47 let mut device_handler = MyDeviceHandler::new();
48
49 let mut state = State::new();
50
51 let mut builder = Builder::new(
52 driver,
53 config,
54 &mut device_descriptor,
55 &mut config_descriptor,
56 &mut bos_descriptor,
57 // &mut msos_descriptor,
58 &mut control_buf,
59 );
60
61 builder.handler(&mut device_handler);
62
63 // Create classes on the builder.
64 let config = embassy_usb::class::hid::Config {
65 report_descriptor: KeyboardReport::desc(),
66 request_handler: Some(&request_handler),
67 poll_ms: 60,
68 max_packet_size: 64,
69 };
70 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
71
72 // Build the builder.
73 let mut usb = builder.build();
74
75 // Run the USB device.
76 let usb_fut = usb.run();
77
78 // Set up the signal pin that will be used to trigger the keyboard.
79 let mut signal_pin = Input::new(p.PIN_16, Pull::None);
80
81 let (reader, mut writer) = hid.split();
82
83 // Do stuff with the class!
84 let in_fut = async {
85 loop {
86 info!("Waiting for HIGH on pin 16");
87 signal_pin.wait_for_high().await;
88 info!("HIGH DETECTED");
89 // Create a report with the A key pressed. (no shift modifier)
90 let report = KeyboardReport {
91 keycodes: [4, 0, 0, 0, 0, 0],
92 leds: 0,
93 modifier: 0,
94 reserved: 0,
95 };
96 // Send the report.
97 match writer.write_serialize(&report).await {
98 Ok(()) => {}
99 Err(e) => warn!("Failed to send report: {:?}", e),
100 };
101 signal_pin.wait_for_low().await;
102 info!("LOW DETECTED");
103 let report = KeyboardReport {
104 keycodes: [0, 0, 0, 0, 0, 0],
105 leds: 0,
106 modifier: 0,
107 reserved: 0,
108 };
109 match writer.write_serialize(&report).await {
110 Ok(()) => {}
111 Err(e) => warn!("Failed to send report: {:?}", e),
112 };
113 }
114 };
115
116 let out_fut = async {
117 reader.run(false, &request_handler).await;
118 };
119
120 // Run everything concurrently.
121 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
122 join(usb_fut, join(in_fut, out_fut)).await;
123}
124
125struct MyRequestHandler {}
126
127impl RequestHandler for MyRequestHandler {
128 fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
129 info!("Get report for {:?}", id);
130 None
131 }
132
133 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
134 info!("Set report for {:?}: {=[u8]}", id, data);
135 OutResponse::Accepted
136 }
137
138 fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) {
139 info!("Set idle rate for {:?} to {:?}", id, dur);
140 }
141
142 fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> {
143 info!("Get idle rate for {:?}", id);
144 None
145 }
146}
147
148struct MyDeviceHandler {
149 configured: AtomicBool,
150}
151
152impl MyDeviceHandler {
153 fn new() -> Self {
154 MyDeviceHandler {
155 configured: AtomicBool::new(false),
156 }
157 }
158}
159
160impl Handler for MyDeviceHandler {
161 fn enabled(&mut self, enabled: bool) {
162 self.configured.store(false, Ordering::Relaxed);
163 if enabled {
164 info!("Device enabled");
165 } else {
166 info!("Device disabled");
167 }
168 }
169
170 fn reset(&mut self) {
171 self.configured.store(false, Ordering::Relaxed);
172 info!("Bus reset, the Vbus current limit is 100mA");
173 }
174
175 fn addressed(&mut self, addr: u8) {
176 self.configured.store(false, Ordering::Relaxed);
177 info!("USB address set to: {}", addr);
178 }
179
180 fn configured(&mut self, configured: bool) {
181 self.configured.store(configured, Ordering::Relaxed);
182 if configured {
183 info!("Device configured, it may now draw up to the configured current limit from Vbus.")
184 } else {
185 info!("Device is no longer configured, the Vbus current limit is 100mA.");
186 }
187 }
188}
diff --git a/examples/rp/src/bin/usb_logger.rs b/examples/rp/src/bin/usb_logger.rs
new file mode 100644
index 000000000..9c5e6897d
--- /dev/null
+++ b/examples/rp/src/bin/usb_logger.rs
@@ -0,0 +1,37 @@
1//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip.
2//!
3//! This creates the possibility to send log::info/warn/error/debug! to USB serial port.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts;
11use embassy_rp::peripherals::USB;
12use embassy_rp::usb::{Driver, InterruptHandler};
13use embassy_time::{Duration, Timer};
14use {defmt_rtt as _, panic_probe as _};
15
16bind_interrupts!(struct Irqs {
17 USBCTRL_IRQ => InterruptHandler<USB>;
18});
19
20#[embassy_executor::task]
21async fn logger_task(driver: Driver<'static, USB>) {
22 embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver);
23}
24
25#[embassy_executor::main]
26async fn main(spawner: Spawner) {
27 let p = embassy_rp::init(Default::default());
28 let driver = Driver::new(p.USB, Irqs);
29 spawner.spawn(logger_task(driver)).unwrap();
30
31 let mut counter = 0;
32 loop {
33 counter += 1;
34 log::info!("Tick {}", counter);
35 Timer::after(Duration::from_secs(1)).await;
36 }
37}
diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs
new file mode 100644
index 000000000..164e2052d
--- /dev/null
+++ b/examples/rp/src/bin/usb_serial.rs
@@ -0,0 +1,109 @@
1//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip.
2//!
3//! This creates a USB serial port that echos.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use defmt::{info, panic};
10use embassy_executor::Spawner;
11use embassy_futures::join::join;
12use embassy_rp::bind_interrupts;
13use embassy_rp::peripherals::USB;
14use embassy_rp::usb::{Driver, Instance, InterruptHandler};
15use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
16use embassy_usb::driver::EndpointError;
17use embassy_usb::{Builder, Config};
18use {defmt_rtt as _, panic_probe as _};
19
20bind_interrupts!(struct Irqs {
21 USBCTRL_IRQ => InterruptHandler<USB>;
22});
23
24#[embassy_executor::main]
25async fn main(_spawner: Spawner) {
26 info!("Hello there!");
27
28 let p = embassy_rp::init(Default::default());
29
30 // Create the driver, from the HAL.
31 let driver = Driver::new(p.USB, Irqs);
32
33 // Create embassy-usb Config
34 let mut config = Config::new(0xc0de, 0xcafe);
35 config.manufacturer = Some("Embassy");
36 config.product = Some("USB-serial example");
37 config.serial_number = Some("12345678");
38 config.max_power = 100;
39 config.max_packet_size_0 = 64;
40
41 // Required for windows compatibility.
42 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
43 config.device_class = 0xEF;
44 config.device_sub_class = 0x02;
45 config.device_protocol = 0x01;
46 config.composite_with_iads = true;
47
48 // Create embassy-usb DeviceBuilder using the driver and config.
49 // It needs some buffers for building the descriptors.
50 let mut device_descriptor = [0; 256];
51 let mut config_descriptor = [0; 256];
52 let mut bos_descriptor = [0; 256];
53 let mut control_buf = [0; 64];
54
55 let mut state = State::new();
56
57 let mut builder = Builder::new(
58 driver,
59 config,
60 &mut device_descriptor,
61 &mut config_descriptor,
62 &mut bos_descriptor,
63 &mut control_buf,
64 );
65
66 // Create classes on the builder.
67 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
68
69 // Build the builder.
70 let mut usb = builder.build();
71
72 // Run the USB device.
73 let usb_fut = usb.run();
74
75 // Do stuff with the class!
76 let echo_fut = async {
77 loop {
78 class.wait_connection().await;
79 info!("Connected");
80 let _ = echo(&mut class).await;
81 info!("Disconnected");
82 }
83 };
84
85 // Run everything concurrently.
86 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
87 join(usb_fut, echo_fut).await;
88}
89
90struct Disconnected {}
91
92impl From<EndpointError> for Disconnected {
93 fn from(val: EndpointError) -> Self {
94 match val {
95 EndpointError::BufferOverflow => panic!("Buffer overflow"),
96 EndpointError::Disabled => Disconnected {},
97 }
98 }
99}
100
101async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
102 let mut buf = [0; 64];
103 loop {
104 let n = class.read_packet(&mut buf).await?;
105 let data = &buf[..n];
106 info!("data: {:x}", data);
107 class.write_packet(data).await?;
108 }
109}
diff --git a/examples/rp/src/bin/watchdog.rs b/examples/rp/src/bin/watchdog.rs
new file mode 100644
index 000000000..fe5eaf926
--- /dev/null
+++ b/examples/rp/src/bin/watchdog.rs
@@ -0,0 +1,52 @@
1//! This example shows how to use Watchdog in the RP2040 chip.
2//!
3//! It does not work with the RP Pico W board. See wifi_blinky.rs or connect external LED and resistor.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use defmt::info;
10use embassy_executor::Spawner;
11use embassy_rp::gpio;
12use embassy_rp::watchdog::*;
13use embassy_time::{Duration, Timer};
14use gpio::{Level, Output};
15use {defmt_rtt as _, panic_probe as _};
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_rp::init(Default::default());
20 info!("Hello world!");
21
22 let mut watchdog = Watchdog::new(p.WATCHDOG);
23 let mut led = Output::new(p.PIN_25, Level::Low);
24
25 // Set the LED high for 2 seconds so we know when we're about to start the watchdog
26 led.set_high();
27 Timer::after(Duration::from_secs(2)).await;
28
29 // Set to watchdog to reset if it's not fed within 1.05 seconds, and start it
30 watchdog.start(Duration::from_millis(1_050));
31 info!("Started the watchdog timer");
32
33 // Blink once a second for 5 seconds, feed the watchdog timer once a second to avoid a reset
34 for _ in 1..=5 {
35 led.set_low();
36 Timer::after(Duration::from_millis(500)).await;
37 led.set_high();
38 Timer::after(Duration::from_millis(500)).await;
39 info!("Feeding watchdog");
40 watchdog.feed();
41 }
42
43 info!("Stopped feeding, device will reset in 1.05 seconds");
44 // Blink 10 times per second, not feeding the watchdog.
45 // The processor should reset in 1.05 seconds.
46 loop {
47 led.set_low();
48 Timer::after(Duration::from_millis(100)).await;
49 led.set_high();
50 Timer::after(Duration::from_millis(100)).await;
51 }
52}
diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs
new file mode 100644
index 000000000..e3e393445
--- /dev/null
+++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs
@@ -0,0 +1,139 @@
1//! This example uses the RP Pico W board Wifi chip (cyw43).
2//! Creates an Access point Wifi network and creates a TCP endpoint on port 1234.
3
4#![no_std]
5#![no_main]
6#![feature(type_alias_impl_trait)]
7#![feature(async_fn_in_trait)]
8#![allow(incomplete_features)]
9
10use core::str::from_utf8;
11
12use cyw43_pio::PioSpi;
13use defmt::*;
14use embassy_executor::Spawner;
15use embassy_net::tcp::TcpSocket;
16use embassy_net::{Config, Stack, StackResources};
17use embassy_rp::bind_interrupts;
18use embassy_rp::gpio::{Level, Output};
19use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
20use embassy_rp::pio::{InterruptHandler, Pio};
21use embassy_time::Duration;
22use embedded_io::asynch::Write;
23use static_cell::make_static;
24use {defmt_rtt as _, panic_probe as _};
25
26bind_interrupts!(struct Irqs {
27 PIO0_IRQ_0 => InterruptHandler<PIO0>;
28});
29
30#[embassy_executor::task]
31async fn wifi_task(
32 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
33) -> ! {
34 runner.run().await
35}
36
37#[embassy_executor::task]
38async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! {
39 stack.run().await
40}
41
42#[embassy_executor::main]
43async fn main(spawner: Spawner) {
44 info!("Hello World!");
45
46 let p = embassy_rp::init(Default::default());
47
48 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
49 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
50
51 // To make flashing faster for development, you may want to flash the firmwares independently
52 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
53 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
54 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
55 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
56 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
57
58 let pwr = Output::new(p.PIN_23, Level::Low);
59 let cs = Output::new(p.PIN_25, Level::High);
60 let mut pio = Pio::new(p.PIO0, Irqs);
61 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
62
63 let state = make_static!(cyw43::State::new());
64 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
65 unwrap!(spawner.spawn(wifi_task(runner)));
66
67 control.init(clm).await;
68 control
69 .set_power_management(cyw43::PowerManagementMode::PowerSave)
70 .await;
71
72 // Use a link-local address for communication without DHCP server
73 let config = Config::ipv4_static(embassy_net::StaticConfigV4 {
74 address: embassy_net::Ipv4Cidr::new(embassy_net::Ipv4Address::new(169, 254, 1, 1), 16),
75 dns_servers: heapless::Vec::new(),
76 gateway: None,
77 });
78
79 // Generate random seed
80 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random.
81
82 // Init network stack
83 let stack = &*make_static!(Stack::new(
84 net_device,
85 config,
86 make_static!(StackResources::<2>::new()),
87 seed
88 ));
89
90 unwrap!(spawner.spawn(net_task(stack)));
91
92 //control.start_ap_open("cyw43", 5).await;
93 control.start_ap_wpa2("cyw43", "password", 5).await;
94
95 // And now we can use it!
96
97 let mut rx_buffer = [0; 4096];
98 let mut tx_buffer = [0; 4096];
99 let mut buf = [0; 4096];
100
101 loop {
102 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
103 socket.set_timeout(Some(Duration::from_secs(10)));
104
105 control.gpio_set(0, false).await;
106 info!("Listening on TCP:1234...");
107 if let Err(e) = socket.accept(1234).await {
108 warn!("accept error: {:?}", e);
109 continue;
110 }
111
112 info!("Received connection from {:?}", socket.remote_endpoint());
113 control.gpio_set(0, true).await;
114
115 loop {
116 let n = match socket.read(&mut buf).await {
117 Ok(0) => {
118 warn!("read EOF");
119 break;
120 }
121 Ok(n) => n,
122 Err(e) => {
123 warn!("read error: {:?}", e);
124 break;
125 }
126 };
127
128 info!("rxd {}", from_utf8(&buf[..n]).unwrap());
129
130 match socket.write_all(&buf[..n]).await {
131 Ok(()) => {}
132 Err(e) => {
133 warn!("write error: {:?}", e);
134 break;
135 }
136 };
137 }
138 }
139}
diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs
new file mode 100644
index 000000000..33d43788c
--- /dev/null
+++ b/examples/rp/src/bin/wifi_blinky.rs
@@ -0,0 +1,68 @@
1//! This example test the RP Pico W on board LED.
2//!
3//! It does not work with the RP Pico board. See blinky.rs.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use cyw43_pio::PioSpi;
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_rp::bind_interrupts;
13use embassy_rp::gpio::{Level, Output};
14use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
15use embassy_rp::pio::{InterruptHandler, Pio};
16use embassy_time::{Duration, Timer};
17use static_cell::make_static;
18use {defmt_rtt as _, panic_probe as _};
19
20bind_interrupts!(struct Irqs {
21 PIO0_IRQ_0 => InterruptHandler<PIO0>;
22});
23
24#[embassy_executor::task]
25async fn wifi_task(
26 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
27) -> ! {
28 runner.run().await
29}
30
31#[embassy_executor::main]
32async fn main(spawner: Spawner) {
33 let p = embassy_rp::init(Default::default());
34 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
35 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
36
37 // To make flashing faster for development, you may want to flash the firmwares independently
38 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
39 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
40 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
41 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
42 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
43
44 let pwr = Output::new(p.PIN_23, Level::Low);
45 let cs = Output::new(p.PIN_25, Level::High);
46 let mut pio = Pio::new(p.PIO0, Irqs);
47 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
48
49 let state = make_static!(cyw43::State::new());
50 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
51 unwrap!(spawner.spawn(wifi_task(runner)));
52
53 control.init(clm).await;
54 control
55 .set_power_management(cyw43::PowerManagementMode::PowerSave)
56 .await;
57
58 let delay = Duration::from_secs(1);
59 loop {
60 info!("led on!");
61 control.gpio_set(0, true).await;
62 Timer::after(delay).await;
63
64 info!("led off!");
65 control.gpio_set(0, false).await;
66 Timer::after(delay).await;
67 }
68}
diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs
new file mode 100644
index 000000000..743fab617
--- /dev/null
+++ b/examples/rp/src/bin/wifi_scan.rs
@@ -0,0 +1,75 @@
1//! This example uses the RP Pico W board Wifi chip (cyw43).
2//! Scans Wifi for ssid names.
3
4#![no_std]
5#![no_main]
6#![feature(type_alias_impl_trait)]
7#![feature(async_fn_in_trait)]
8#![allow(incomplete_features)]
9
10use core::str;
11
12use cyw43_pio::PioSpi;
13use defmt::*;
14use embassy_executor::Spawner;
15use embassy_net::Stack;
16use embassy_rp::bind_interrupts;
17use embassy_rp::gpio::{Level, Output};
18use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
19use embassy_rp::pio::{InterruptHandler, Pio};
20use static_cell::make_static;
21use {defmt_rtt as _, panic_probe as _};
22
23bind_interrupts!(struct Irqs {
24 PIO0_IRQ_0 => InterruptHandler<PIO0>;
25});
26
27#[embassy_executor::task]
28async fn wifi_task(
29 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
30) -> ! {
31 runner.run().await
32}
33
34#[embassy_executor::task]
35async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! {
36 stack.run().await
37}
38
39#[embassy_executor::main]
40async fn main(spawner: Spawner) {
41 info!("Hello World!");
42
43 let p = embassy_rp::init(Default::default());
44
45 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
46 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
47
48 // To make flashing faster for development, you may want to flash the firmwares independently
49 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
50 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
51 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
52 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
53 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
54
55 let pwr = Output::new(p.PIN_23, Level::Low);
56 let cs = Output::new(p.PIN_25, Level::High);
57 let mut pio = Pio::new(p.PIO0, Irqs);
58 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
59
60 let state = make_static!(cyw43::State::new());
61 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
62 unwrap!(spawner.spawn(wifi_task(runner)));
63
64 control.init(clm).await;
65 control
66 .set_power_management(cyw43::PowerManagementMode::PowerSave)
67 .await;
68
69 let mut scanner = control.scan().await;
70 while let Some(bss) = scanner.next().await {
71 if let Ok(ssid_str) = str::from_utf8(&bss.ssid) {
72 info!("scanned {} == {:x}", ssid_str, bss.bssid);
73 }
74 }
75}
diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs
new file mode 100644
index 000000000..0223a3636
--- /dev/null
+++ b/examples/rp/src/bin/wifi_tcp_server.rs
@@ -0,0 +1,149 @@
1//! This example uses the RP Pico W board Wifi chip (cyw43).
2//! Connects to specified Wifi network and creates a TCP endpoint on port 1234.
3
4#![no_std]
5#![no_main]
6#![feature(type_alias_impl_trait)]
7#![feature(async_fn_in_trait)]
8#![allow(incomplete_features)]
9
10use core::str::from_utf8;
11
12use cyw43_pio::PioSpi;
13use defmt::*;
14use embassy_executor::Spawner;
15use embassy_net::tcp::TcpSocket;
16use embassy_net::{Config, Stack, StackResources};
17use embassy_rp::bind_interrupts;
18use embassy_rp::gpio::{Level, Output};
19use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
20use embassy_rp::pio::{InterruptHandler, Pio};
21use embassy_time::Duration;
22use embedded_io::asynch::Write;
23use static_cell::make_static;
24use {defmt_rtt as _, panic_probe as _};
25
26bind_interrupts!(struct Irqs {
27 PIO0_IRQ_0 => InterruptHandler<PIO0>;
28});
29
30const WIFI_NETWORK: &str = "EmbassyTest";
31const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
32
33#[embassy_executor::task]
34async fn wifi_task(
35 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
36) -> ! {
37 runner.run().await
38}
39
40#[embassy_executor::task]
41async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! {
42 stack.run().await
43}
44
45#[embassy_executor::main]
46async fn main(spawner: Spawner) {
47 info!("Hello World!");
48
49 let p = embassy_rp::init(Default::default());
50
51 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
52 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
53
54 // To make flashing faster for development, you may want to flash the firmwares independently
55 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
56 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
57 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
58 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
59 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
60
61 let pwr = Output::new(p.PIN_23, Level::Low);
62 let cs = Output::new(p.PIN_25, Level::High);
63 let mut pio = Pio::new(p.PIO0, Irqs);
64 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
65
66 let state = make_static!(cyw43::State::new());
67 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
68 unwrap!(spawner.spawn(wifi_task(runner)));
69
70 control.init(clm).await;
71 control
72 .set_power_management(cyw43::PowerManagementMode::PowerSave)
73 .await;
74
75 let config = Config::dhcpv4(Default::default());
76 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
77 // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
78 // dns_servers: Vec::new(),
79 // gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
80 //});
81
82 // Generate random seed
83 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random.
84
85 // Init network stack
86 let stack = &*make_static!(Stack::new(
87 net_device,
88 config,
89 make_static!(StackResources::<2>::new()),
90 seed
91 ));
92
93 unwrap!(spawner.spawn(net_task(stack)));
94
95 loop {
96 //control.join_open(WIFI_NETWORK).await;
97 match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await {
98 Ok(_) => break,
99 Err(err) => {
100 info!("join failed with status={}", err.status);
101 }
102 }
103 }
104
105 // And now we can use it!
106
107 let mut rx_buffer = [0; 4096];
108 let mut tx_buffer = [0; 4096];
109 let mut buf = [0; 4096];
110
111 loop {
112 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
113 socket.set_timeout(Some(Duration::from_secs(10)));
114
115 control.gpio_set(0, false).await;
116 info!("Listening on TCP:1234...");
117 if let Err(e) = socket.accept(1234).await {
118 warn!("accept error: {:?}", e);
119 continue;
120 }
121
122 info!("Received connection from {:?}", socket.remote_endpoint());
123 control.gpio_set(0, true).await;
124
125 loop {
126 let n = match socket.read(&mut buf).await {
127 Ok(0) => {
128 warn!("read EOF");
129 break;
130 }
131 Ok(n) => n,
132 Err(e) => {
133 warn!("read error: {:?}", e);
134 break;
135 }
136 };
137
138 info!("rxd {}", from_utf8(&buf[..n]).unwrap());
139
140 match socket.write_all(&buf[..n]).await {
141 Ok(()) => {}
142 Err(e) => {
143 warn!("write error: {:?}", e);
144 break;
145 }
146 };
147 }
148 }
149}
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml
index c7cec6b19..92933ab50 100644
--- a/examples/std/Cargo.toml
+++ b/examples/std/Cargo.toml
@@ -2,22 +2,24 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-std-examples" 3name = "embassy-std-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["log"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["log"] }
8embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "std", "nightly", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "nightly", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "std", "nightly"] } 10embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["log", "std", "nightly"] }
10embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "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"] }
11embedded-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"] }
12critical-section = { version = "1.1", features = ["std"] } 14critical-section = { version = "1.1", features = ["std"] }
13 15
14async-io = "1.6.0" 16async-io = "1.6.0"
15env_logger = "0.9.0" 17env_logger = "0.9.0"
16futures = { version = "0.3.17" } 18futures = { version = "0.3.17" }
17log = "0.4.14" 19log = "0.4.14"
18nix = "0.22.1" 20nix = "0.26.2"
19libc = "0.2.101" 21libc = "0.2.101"
20clap = { version = "3.0.0-beta.5", features = ["derive"] } 22clap = { version = "3.0.0-beta.5", features = ["derive"] }
21rand_core = { version = "0.6.3", features = ["std"] } 23rand_core = { version = "0.6.3", features = ["std"] }
22heapless = { version = "0.7.5", default-features = false } 24heapless = { version = "0.7.5", default-features = false }
23static_cell = "1.0" 25static_cell = { version = "1.1", features = ["nightly"]}
diff --git a/examples/std/README.md b/examples/std/README.md
new file mode 100644
index 000000000..adc795928
--- /dev/null
+++ b/examples/std/README.md
@@ -0,0 +1,23 @@
1
2## Running the `embassy-net` examples
3
4First, create the tap0 interface. You only need to do this once.
5
6```sh
7sudo ip tuntap add name tap0 mode tap user $USER
8sudo ip link set tap0 up
9sudo ip addr add 192.168.69.100/24 dev tap0
10sudo ip -6 addr add fe80::100/64 dev tap0
11sudo ip -6 addr add fdaa::100/64 dev tap0
12sudo ip -6 route add fe80::/64 dev tap0
13sudo ip -6 route add fdaa::/64 dev tap0
14```
15
16Second, have something listening there. For example `nc -l 8000`
17
18Then run the example located in the `examples` folder:
19
20```sh
21cd $EMBASSY_ROOT/examples/std/
22cargo run --bin net -- --static-ip
23``` \ No newline at end of file
diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs
index 9b1450b72..3aadb029d 100644
--- a/examples/std/src/bin/net.rs
+++ b/examples/std/src/bin/net.rs
@@ -1,28 +1,22 @@
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};
9use embassy_time::Duration;
7use embedded_io::asynch::Write; 10use embedded_io::asynch::Write;
8use heapless::Vec; 11use heapless::Vec;
9use log::*; 12use log::*;
10use rand_core::{OsRng, RngCore}; 13use rand_core::{OsRng, RngCore};
11use static_cell::StaticCell; 14use static_cell::{make_static, StaticCell};
12 15
13#[path = "../tuntap.rs"] 16#[path = "../tuntap.rs"]
14mod tuntap; 17mod tuntap;
15 18
16use crate::tuntap::TunTapDevice; 19use crate::tuntap::TunTapDevice;
17
18macro_rules! singleton {
19 ($val:expr) => {{
20 type T = impl Sized;
21 static STATIC_CELL: StaticCell<T> = StaticCell::new();
22 STATIC_CELL.init_with(move || $val)
23 }};
24}
25
26#[derive(Parser)] 20#[derive(Parser)]
27#[clap(version = "1.0")] 21#[clap(version = "1.0")]
28struct Opts { 22struct Opts {
@@ -48,13 +42,13 @@ async fn main_task(spawner: Spawner) {
48 42
49 // Choose between dhcp or static ip 43 // Choose between dhcp or static ip
50 let config = if opts.static_ip { 44 let config = if opts.static_ip {
51 ConfigStrategy::Static(embassy_net::Config { 45 Config::ipv4_static(embassy_net::StaticConfigV4 {
52 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), 46 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
53 dns_servers: Vec::new(), 47 dns_servers: Vec::new(),
54 gateway: Some(Ipv4Address::new(192, 168, 69, 1)), 48 gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
55 }) 49 })
56 } else { 50 } else {
57 ConfigStrategy::Dhcp 51 Config::dhcpv4(Default::default())
58 }; 52 };
59 53
60 // Generate random seed 54 // Generate random seed
@@ -63,10 +57,10 @@ async fn main_task(spawner: Spawner) {
63 let seed = u64::from_le_bytes(seed); 57 let seed = u64::from_le_bytes(seed);
64 58
65 // Init network stack 59 // Init network stack
66 let stack = &*singleton!(Stack::new( 60 let stack = &*make_static!(Stack::new(
67 device, 61 device,
68 config, 62 config,
69 singleton!(StackResources::<1, 2, 8>::new()), 63 make_static!(StackResources::<3>::new()),
70 seed 64 seed
71 )); 65 ));
72 66
@@ -78,7 +72,7 @@ async fn main_task(spawner: Spawner) {
78 let mut tx_buffer = [0; 4096]; 72 let mut tx_buffer = [0; 4096];
79 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); 73 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
80 74
81 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10))); 75 socket.set_timeout(Some(Duration::from_secs(10)));
82 76
83 let remote_endpoint = (Ipv4Address::new(192, 168, 69, 100), 8000); 77 let remote_endpoint = (Ipv4Address::new(192, 168, 69, 100), 8000);
84 info!("connecting to {:?}...", remote_endpoint); 78 info!("connecting to {:?}...", remote_endpoint);
diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs
new file mode 100644
index 000000000..65b5a2cd9
--- /dev/null
+++ b/examples/std/src/bin/net_dns.rs
@@ -0,0 +1,94 @@
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::{make_static, StaticCell};
13
14#[path = "../tuntap.rs"]
15mod tuntap;
16
17use crate::tuntap::TunTapDevice;
18#[derive(Parser)]
19#[clap(version = "1.0")]
20struct Opts {
21 /// TAP device name
22 #[clap(long, default_value = "tap0")]
23 tap: String,
24 /// use a static IP instead of DHCP
25 #[clap(long)]
26 static_ip: bool,
27}
28
29#[embassy_executor::task]
30async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! {
31 stack.run().await
32}
33
34#[embassy_executor::task]
35async fn main_task(spawner: Spawner) {
36 let opts: Opts = Opts::parse();
37
38 // Init network device
39 let device = TunTapDevice::new(&opts.tap).unwrap();
40
41 // Choose between dhcp or static ip
42 let config = if opts.static_ip {
43 Config::ipv4_static(embassy_net::StaticConfigV4 {
44 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 1), 24),
45 dns_servers: Vec::from_slice(&[Ipv4Address::new(8, 8, 4, 4).into(), Ipv4Address::new(8, 8, 8, 8).into()])
46 .unwrap(),
47 gateway: Some(Ipv4Address::new(192, 168, 69, 100)),
48 })
49 } else {
50 Config::dhcpv4(Default::default())
51 };
52
53 // Generate random seed
54 let mut seed = [0; 8];
55 OsRng.fill_bytes(&mut seed);
56 let seed = u64::from_le_bytes(seed);
57
58 // Init network stack
59 let stack: &Stack<_> = &*make_static!(Stack::new(
60 device,
61 config,
62 make_static!(StackResources::<3>::new()),
63 seed
64 ));
65
66 // Launch network task
67 spawner.spawn(net_task(stack)).unwrap();
68
69 let host = "example.com";
70 info!("querying host {:?}...", host);
71 match stack.dns_query(host, DnsQueryType::A).await {
72 Ok(r) => {
73 info!("query response: {:?}", r);
74 }
75 Err(e) => {
76 warn!("query error: {:?}", e);
77 }
78 };
79}
80
81static EXECUTOR: StaticCell<Executor> = StaticCell::new();
82
83fn main() {
84 env_logger::builder()
85 .filter_level(log::LevelFilter::Debug)
86 .filter_module("async_io", log::LevelFilter::Info)
87 .format_timestamp_nanos()
88 .init();
89
90 let executor = EXECUTOR.init(Executor::new());
91 executor.run(|spawner| {
92 spawner.spawn(main_task(spawner)).unwrap();
93 });
94}
diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs
index 392a97f0d..3fc46156c 100644
--- a/examples/std/src/bin/net_udp.rs
+++ b/examples/std/src/bin/net_udp.rs
@@ -2,26 +2,17 @@
2 2
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::{PacketMetadata, UdpSocket};
6use embassy_net::{ConfigStrategy, Ipv4Address, Ipv4Cidr, PacketMetadata, Stack, StackResources}; 6use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources};
7use heapless::Vec; 7use heapless::Vec;
8use log::*; 8use log::*;
9use rand_core::{OsRng, RngCore}; 9use rand_core::{OsRng, RngCore};
10use static_cell::StaticCell; 10use static_cell::{make_static, StaticCell};
11 11
12#[path = "../tuntap.rs"] 12#[path = "../tuntap.rs"]
13mod tuntap; 13mod tuntap;
14 14
15use crate::tuntap::TunTapDevice; 15use crate::tuntap::TunTapDevice;
16
17macro_rules! singleton {
18 ($val:expr) => {{
19 type T = impl Sized;
20 static STATIC_CELL: StaticCell<T> = StaticCell::new();
21 STATIC_CELL.init_with(move || $val)
22 }};
23}
24
25#[derive(Parser)] 16#[derive(Parser)]
26#[clap(version = "1.0")] 17#[clap(version = "1.0")]
27struct Opts { 18struct Opts {
@@ -47,13 +38,13 @@ async fn main_task(spawner: Spawner) {
47 38
48 // Choose between dhcp or static ip 39 // Choose between dhcp or static ip
49 let config = if opts.static_ip { 40 let config = if opts.static_ip {
50 ConfigStrategy::Static(embassy_net::Config { 41 Config::ipv4_static(embassy_net::StaticConfigV4 {
51 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), 42 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
52 dns_servers: Vec::new(), 43 dns_servers: Vec::new(),
53 gateway: Some(Ipv4Address::new(192, 168, 69, 1)), 44 gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
54 }) 45 })
55 } else { 46 } else {
56 ConfigStrategy::Dhcp 47 Config::dhcpv4(Default::default())
57 }; 48 };
58 49
59 // Generate random seed 50 // Generate random seed
@@ -62,10 +53,10 @@ async fn main_task(spawner: Spawner) {
62 let seed = u64::from_le_bytes(seed); 53 let seed = u64::from_le_bytes(seed);
63 54
64 // Init network stack 55 // Init network stack
65 let stack = &*singleton!(Stack::new( 56 let stack = &*make_static!(Stack::new(
66 device, 57 device,
67 config, 58 config,
68 singleton!(StackResources::<1, 2, 8>::new()), 59 make_static!(StackResources::<3>::new()),
69 seed 60 seed
70 )); 61 ));
71 62
diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs
new file mode 100644
index 000000000..df09986ac
--- /dev/null
+++ b/examples/std/src/bin/tcp_accept.rs
@@ -0,0 +1,129 @@
1#![feature(type_alias_impl_trait)]
2
3use core::fmt::Write as _;
4use std::default::Default;
5
6use clap::Parser;
7use embassy_executor::{Executor, Spawner};
8use embassy_net::tcp::TcpSocket;
9use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources};
10use embassy_time::{Duration, Timer};
11use embedded_io::asynch::Write as _;
12use heapless::Vec;
13use log::*;
14use rand_core::{OsRng, RngCore};
15use static_cell::{make_static, StaticCell};
16
17#[path = "../tuntap.rs"]
18mod tuntap;
19
20use crate::tuntap::TunTapDevice;
21#[derive(Parser)]
22#[clap(version = "1.0")]
23struct Opts {
24 /// TAP device name
25 #[clap(long, default_value = "tap0")]
26 tap: String,
27 /// use a static IP instead of DHCP
28 #[clap(long)]
29 static_ip: bool,
30}
31
32#[embassy_executor::task]
33async fn net_task(stack: &'static Stack<TunTapDevice>) -> ! {
34 stack.run().await
35}
36
37#[derive(Default)]
38struct StrWrite(pub heapless::Vec<u8, 30>);
39
40impl core::fmt::Write for StrWrite {
41 fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
42 self.0.extend_from_slice(s.as_bytes()).unwrap();
43 Ok(())
44 }
45}
46
47#[embassy_executor::task]
48async fn main_task(spawner: Spawner) {
49 let opts: Opts = Opts::parse();
50
51 // Init network device
52 let device = TunTapDevice::new(&opts.tap).unwrap();
53
54 // Choose between dhcp or static ip
55 let config = if opts.static_ip {
56 Config::ipv4_static(embassy_net::StaticConfigV4 {
57 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
58 dns_servers: Vec::new(),
59 gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
60 })
61 } else {
62 Config::dhcpv4(Default::default())
63 };
64
65 // Generate random seed
66 let mut seed = [0; 8];
67 OsRng.fill_bytes(&mut seed);
68 let seed = u64::from_le_bytes(seed);
69
70 // Init network stack
71 let stack = &*make_static!(Stack::new(
72 device,
73 config,
74 make_static!(StackResources::<3>::new()),
75 seed
76 ));
77
78 // Launch network task
79 spawner.spawn(net_task(stack)).unwrap();
80
81 // Then we can use it!
82 let mut rx_buffer = [0; 4096];
83 let mut tx_buffer = [0; 4096];
84
85 loop {
86 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
87 socket.set_timeout(Some(Duration::from_secs(10)));
88 info!("Listening on TCP:9999...");
89 if let Err(_) = socket.accept(9999).await {
90 warn!("accept error");
91 continue;
92 }
93
94 info!("Accepted a connection");
95
96 // Write some quick output
97 for i in 1..=5 {
98 let mut w = StrWrite::default();
99 write!(w, "{}! ", i).unwrap();
100 let r = socket.write_all(&w.0).await;
101 if let Err(e) = r {
102 warn!("write error: {:?}", e);
103 return;
104 }
105
106 Timer::after(Duration::from_millis(500)).await;
107 }
108 info!("Closing the connection");
109 socket.abort();
110 info!("Flushing the RST out...");
111 _ = socket.flush().await;
112 info!("Finished with the socket");
113 }
114}
115
116static EXECUTOR: StaticCell<Executor> = StaticCell::new();
117
118fn main() {
119 env_logger::builder()
120 .filter_level(log::LevelFilter::Debug)
121 .filter_module("async_io", log::LevelFilter::Info)
122 .format_timestamp_nanos()
123 .init();
124
125 let executor = EXECUTOR.init(Executor::new());
126 executor.run(|spawner| {
127 spawner.spawn(main_task(spawner)).unwrap();
128 });
129}
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..29a8be7e1
--- /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-rs chip list`
3runner = "probe-rs 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..26837abef
--- /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.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.2", 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..def4c8c92 100644
--- a/examples/stm32f0/.cargo/config.toml
+++ b/examples/stm32f0/.cargo/config.toml
@@ -1,5 +1,5 @@
1[target.thumbv6m-none-eabi] 1[target.thumbv6m-none-eabi]
2runner = 'probe-run --chip STM32F030F4Px' 2runner = 'probe-rs 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 cd2995d2c..b7b5eaa99 100644
--- a/examples/stm32f0/Cargo.toml
+++ b/examples/stm32f0/Cargo.toml
@@ -2,17 +2,18 @@
2name = "embassy-stm32f0-examples" 2name = "embassy-stm32f0-examples"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0"
5 6
6# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 8
8[dependencies] 9[dependencies]
9cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 10cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
10cortex-m-rt = "0.7.0" 11cortex-m-rt = "0.7.0"
11defmt = "0.3" 12defmt = "0.3"
12defmt-rtt = "0.3" 13defmt-rtt = "0.4"
13panic-probe = "0.3" 14panic-probe = "0.3"
14embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 15embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
15embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 16embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
16embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] } 17embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
17embassy-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", "unstable-pac"] }
18 19static_cell = { version = "1.1", features = ["nightly"]}
diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs
new file mode 100644
index 000000000..8ed9f98f8
--- /dev/null
+++ b/examples/stm32f0/src/bin/adc.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_stm32::adc::{Adc, SampleTime};
8use embassy_time::{Delay, 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 adc = Adc::new(p.ADC, &mut Delay);
17 adc.set_sample_time(SampleTime::Cycles71_5);
18 let mut pin = p.PA1;
19
20 let mut vrefint = adc.enable_vref(&mut Delay);
21 let vrefint_sample = adc.read_internal(&mut vrefint);
22 let convert_to_millivolts = |sample| {
23 // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf
24 // 6.3.4 Embedded reference voltage
25 const VREFINT_MV: u32 = 1230; // mV
26
27 (u32::from(sample) * VREFINT_MV / u32::from(vrefint_sample)) as u16
28 };
29
30 loop {
31 let v = adc.read(&mut pin);
32 info!("--> {} - {} mV", v, convert_to_millivolts(v));
33 Timer::after(Duration::from_millis(100)).await;
34 }
35}
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..f362c53f5
--- /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 output and obtain handler.
21 // On the Nucleo F091RC there's 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/multiprio.rs b/examples/stm32f0/src/bin/multiprio.rs
new file mode 100644
index 000000000..988ffeef1
--- /dev/null
+++ b/examples/stm32f0/src/bin/multiprio.rs
@@ -0,0 +1,145 @@
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_executor::{Executor, InterruptExecutor};
63use embassy_stm32::interrupt;
64use embassy_stm32::interrupt::{InterruptExt, Priority};
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: InterruptExecutor = InterruptExecutor::new();
112static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
113static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
114
115#[interrupt]
116unsafe fn USART1() {
117 EXECUTOR_HIGH.on_interrupt()
118}
119
120#[interrupt]
121unsafe fn USART2() {
122 EXECUTOR_MED.on_interrupt()
123}
124
125#[entry]
126fn main() -> ! {
127 // Initialize and create handle for devicer peripherals
128 let _p = embassy_stm32::init(Default::default());
129
130 // High-priority executor: USART1, priority level 6
131 interrupt::USART1.set_priority(Priority::P6);
132 let spawner = EXECUTOR_HIGH.start(interrupt::USART1);
133 unwrap!(spawner.spawn(run_high()));
134
135 // Medium-priority executor: USART2, priority level 7
136 interrupt::USART2.set_priority(Priority::P7);
137 let spawner = EXECUTOR_MED.start(interrupt::USART2);
138 unwrap!(spawner.spawn(run_med()));
139
140 // Low priority executor: runs in thread mode, using WFE/SEV
141 let executor = EXECUTOR_LOW.init(Executor::new());
142 executor.run(|spawner| {
143 unwrap!(spawner.spawn(run_low()));
144 });
145}
diff --git a/examples/stm32f0/src/bin/wdg.rs b/examples/stm32f0/src/bin/wdg.rs
new file mode 100644
index 000000000..a44b17528
--- /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 wdg.unleash();
20
21 loop {
22 Timer::after(Duration::from_secs(1)).await;
23 wdg.pet();
24 }
25}
diff --git a/examples/stm32f1/.cargo/config.toml b/examples/stm32f1/.cargo/config.toml
index e61e739fe..ce6fef11b 100644
--- a/examples/stm32f1/.cargo/config.toml
+++ b/examples/stm32f1/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F103C8 with your chip as listed in `probe-run --list-chips` 2# replace STM32F103C8 with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32F103C8" 3runner = "probe-rs run --chip STM32F103C8"
4 4
5[build] 5[build]
6target = "thumbv7m-none-eabi" 6target = "thumbv7m-none-eabi"
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index 8660e743d..29cad5b67 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -2,19 +2,20 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32f1-examples" 3name = "embassy-stm32f1-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
10embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any", "unstable-traits" ] }
11embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
12embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] } 13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
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 = ["inline-asm", "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"
20panic-probe = { version = "0.3", features = ["print-defmt"] } 21panic-probe = { version = "0.3", features = ["print-defmt"] }
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 a9c46068f..663099ff7 100644
--- a/examples/stm32f1/src/bin/usb_serial.rs
+++ b/examples/stm32f1/src/bin/usb_serial.rs
@@ -4,17 +4,21 @@
4 4
5use defmt::{panic, *}; 5use defmt::{panic, *};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_futures::join::join;
7use embassy_stm32::gpio::{Level, Output, Speed}; 8use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::time::Hertz; 9use embassy_stm32::time::Hertz;
9use embassy_stm32::usb::{Driver, Instance}; 10use embassy_stm32::usb::{Driver, Instance};
10use embassy_stm32::{interrupt, Config}; 11use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
11use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
13use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError; 14use embassy_usb::driver::EndpointError;
13use embassy_usb::Builder; 15use embassy_usb::Builder;
14use embassy_usb_serial::{CdcAcmClass, State};
15use futures::future::join;
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
17 17
18bind_interrupts!(struct Irqs {
19 USB_LP_CAN1_RX0 => usb::InterruptHandler<peripherals::USB>;
20});
21
18#[embassy_executor::main] 22#[embassy_executor::main]
19async fn main(_spawner: Spawner) { 23async fn main(_spawner: Spawner) {
20 let mut config = Config::default(); 24 let mut config = Config::default();
@@ -35,8 +39,7 @@ async fn main(_spawner: Spawner) {
35 } 39 }
36 40
37 // Create the driver, from the HAL. 41 // Create the driver, from the HAL.
38 let irq = interrupt::take!(USB_LP_CAN1_RX0); 42 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
39 let driver = Driver::new(p.USB, irq, p.PA12, p.PA11);
40 43
41 // Create embassy-usb Config 44 // Create embassy-usb Config
42 let config = embassy_usb::Config::new(0xc0de, 0xcafe); 45 let config = embassy_usb::Config::new(0xc0de, 0xcafe);
@@ -58,7 +61,6 @@ async fn main(_spawner: Spawner) {
58 &mut config_descriptor, 61 &mut config_descriptor,
59 &mut bos_descriptor, 62 &mut bos_descriptor,
60 &mut control_buf, 63 &mut control_buf,
61 None,
62 ); 64 );
63 65
64 // Create classes on the builder. 66 // Create classes on the builder.
diff --git a/examples/stm32f2/.cargo/config.toml b/examples/stm32f2/.cargo/config.toml
index 197fadf92..1198fcab8 100644
--- a/examples/stm32f2/.cargo/config.toml
+++ b/examples/stm32f2/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F207ZGTx with your chip as listed in `probe-run --list-chips` 2# replace STM32F207ZGTx with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32F207ZGTx" 3runner = "probe-rs run --chip STM32F207ZGTx"
4 4
5[build] 5[build]
6target = "thumbv7m-none-eabi" 6target = "thumbv7m-none-eabi"
diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml
index b4bff4d85..652210c7f 100644
--- a/examples/stm32f2/Cargo.toml
+++ b/examples/stm32f2/Cargo.toml
@@ -2,17 +2,18 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32f2-examples" 3name = "embassy-stm32f2-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
10embassy-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"] }
11 12
12defmt = "0.3" 13defmt = "0.3"
13defmt-rtt = "0.3" 14defmt-rtt = "0.4"
14 15
15cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 16cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
16cortex-m-rt = "0.7.0" 17cortex-m-rt = "0.7.0"
17embedded-hal = "0.2.6" 18embedded-hal = "0.2.6"
18panic-probe = { version = "0.3", features = ["print-defmt"] } 19panic-probe = { version = "0.3", features = ["print-defmt"] }
diff --git a/examples/stm32f3/.cargo/config.toml b/examples/stm32f3/.cargo/config.toml
index d4bcd263d..cb8a7c5af 100644
--- a/examples/stm32f3/.cargo/config.toml
+++ b/examples/stm32f3/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-run --list-chips` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32F303ZETx" 3runner = "probe-rs run --chip STM32F303ZETx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml
index d152b145f..489d0ff4c 100644
--- a/examples/stm32f3/Cargo.toml
+++ b/examples/stm32f3/Cargo.toml
@@ -2,20 +2,20 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32f3-examples" 3name = "embassy-stm32f3-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
10embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
11embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
12embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] } 13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
13embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"] }
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 = ["inline-asm", "critical-section-single-core"] }
19cortex-m-rt = "0.7.0" 19cortex-m-rt = "0.7.0"
20embedded-hal = "0.2.6" 20embedded-hal = "0.2.6"
21panic-probe = { version = "0.3", features = ["print-defmt"] } 21panic-probe = { version = "0.3", features = ["print-defmt"] }
@@ -23,4 +23,4 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
23heapless = { version = "0.7.5", default-features = false } 23heapless = { version = "0.7.5", default-features = false }
24nb = "1.0.0" 24nb = "1.0.0"
25embedded-storage = "0.3.0" 25embedded-storage = "0.3.0"
26static_cell = "1.0" 26static_cell = { version = "1.1", features = ["nightly"]}
diff --git a/examples/stm32f3/src/bin/flash.rs b/examples/stm32f3/src/bin/flash.rs
index 2cf24dbd3..236fb36c1 100644
--- a/examples/stm32f3/src/bin/flash.rs
+++ b/examples/stm32f3/src/bin/flash.rs
@@ -5,7 +5,6 @@
5use defmt::{info, unwrap}; 5use defmt::{info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::flash::Flash; 7use embassy_stm32::flash::Flash;
8use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
10 9
11#[embassy_executor::main] 10#[embassy_executor::main]
@@ -15,27 +14,27 @@ async fn main(_spawner: Spawner) {
15 14
16 const ADDR: u32 = 0x26000; 15 const ADDR: u32 = 0x26000;
17 16
18 let mut f = Flash::unlock(p.FLASH); 17 let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region;
19 18
20 info!("Reading..."); 19 info!("Reading...");
21 let mut buf = [0u8; 8]; 20 let mut buf = [0u8; 8];
22 unwrap!(f.read(ADDR, &mut buf)); 21 unwrap!(f.blocking_read(ADDR, &mut buf));
23 info!("Read: {=[u8]:x}", buf); 22 info!("Read: {=[u8]:x}", buf);
24 23
25 info!("Erasing..."); 24 info!("Erasing...");
26 unwrap!(f.erase(ADDR, ADDR + 2048)); 25 unwrap!(f.blocking_erase(ADDR, ADDR + 2048));
27 26
28 info!("Reading..."); 27 info!("Reading...");
29 let mut buf = [0u8; 8]; 28 let mut buf = [0u8; 8];
30 unwrap!(f.read(ADDR, &mut buf)); 29 unwrap!(f.blocking_read(ADDR, &mut buf));
31 info!("Read after erase: {=[u8]:x}", buf); 30 info!("Read after erase: {=[u8]:x}", buf);
32 31
33 info!("Writing..."); 32 info!("Writing...");
34 unwrap!(f.write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); 33 unwrap!(f.blocking_write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8]));
35 34
36 info!("Reading..."); 35 info!("Reading...");
37 let mut buf = [0u8; 8]; 36 let mut buf = [0u8; 8];
38 unwrap!(f.read(ADDR, &mut buf)); 37 unwrap!(f.blocking_read(ADDR, &mut buf));
39 info!("Read: {=[u8]:x}", buf); 38 info!("Read: {=[u8]:x}", buf);
40 assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]); 39 assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
41} 40}
diff --git a/examples/stm32f3/src/bin/multiprio.rs b/examples/stm32f3/src/bin/multiprio.rs
index 9e8228a4b..80bf59deb 100644
--- a/examples/stm32f3/src/bin/multiprio.rs
+++ b/examples/stm32f3/src/bin/multiprio.rs
@@ -59,9 +59,9 @@
59 59
60use cortex_m_rt::entry; 60use cortex_m_rt::entry;
61use defmt::*; 61use defmt::*;
62use embassy_stm32::executor::{Executor, InterruptExecutor}; 62use embassy_executor::{Executor, InterruptExecutor};
63use embassy_stm32::interrupt; 63use embassy_stm32::interrupt;
64use embassy_stm32::interrupt::InterruptExt; 64use embassy_stm32::interrupt::{InterruptExt, Priority};
65use embassy_time::{Duration, Instant, Timer}; 65use embassy_time::{Duration, Instant, Timer};
66use static_cell::StaticCell; 66use static_cell::StaticCell;
67use {defmt_rtt as _, panic_probe as _}; 67use {defmt_rtt as _, panic_probe as _};
@@ -108,28 +108,34 @@ async fn run_low() {
108 } 108 }
109} 109}
110 110
111static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::UART4>> = StaticCell::new(); 111static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
112static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::UART5>> = StaticCell::new(); 112static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
113static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); 113static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
114 114
115#[interrupt]
116unsafe fn UART4() {
117 EXECUTOR_HIGH.on_interrupt()
118}
119
120#[interrupt]
121unsafe fn UART5() {
122 EXECUTOR_MED.on_interrupt()
123}
124
115#[entry] 125#[entry]
116fn main() -> ! { 126fn main() -> ! {
117 info!("Hello World!"); 127 info!("Hello World!");
118 128
119 let _p = embassy_stm32::init(Default::default()); 129 let _p = embassy_stm32::init(Default::default());
120 130
121 // High-priority executor: SWI1_EGU1, priority level 6 131 // High-priority executor: UART4, priority level 6
122 let irq = interrupt::take!(UART4); 132 interrupt::UART4.set_priority(Priority::P6);
123 irq.set_priority(interrupt::Priority::P6); 133 let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
124 let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
125 let spawner = executor.start();
126 unwrap!(spawner.spawn(run_high())); 134 unwrap!(spawner.spawn(run_high()));
127 135
128 // Medium-priority executor: SWI0_EGU0, priority level 7 136 // Medium-priority executor: UART5, priority level 7
129 let irq = interrupt::take!(UART5); 137 interrupt::UART5.set_priority(Priority::P7);
130 irq.set_priority(interrupt::Priority::P7); 138 let spawner = EXECUTOR_MED.start(interrupt::UART5);
131 let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
132 let spawner = executor.start();
133 unwrap!(spawner.spawn(run_med())); 139 unwrap!(spawner.spawn(run_med()));
134 140
135 // Low priority executor: runs in thread mode, using WFE/SEV 141 // Low priority executor: runs in thread mode, using WFE/SEV
diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs
index 3bc5a287f..85f01a69e 100644
--- a/examples/stm32f3/src/bin/usart_dma.rs
+++ b/examples/stm32f3/src/bin/usart_dma.rs
@@ -8,16 +8,21 @@ use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma; 9use embassy_stm32::dma::NoDma;
10use embassy_stm32::usart::{Config, Uart}; 10use embassy_stm32::usart::{Config, Uart};
11use embassy_stm32::{bind_interrupts, peripherals, usart};
11use heapless::String; 12use heapless::String;
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
13 14
15bind_interrupts!(struct Irqs {
16 USART1 => usart::InterruptHandler<peripherals::USART1>;
17});
18
14#[embassy_executor::main] 19#[embassy_executor::main]
15async fn main(_spawner: Spawner) { 20async fn main(_spawner: Spawner) {
16 let p = embassy_stm32::init(Default::default()); 21 let p = embassy_stm32::init(Default::default());
17 info!("Hello World!"); 22 info!("Hello World!");
18 23
19 let config = Config::default(); 24 let config = Config::default();
20 let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, p.DMA1_CH4, NoDma, config); 25 let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, NoDma, config);
21 26
22 for n in 0u32.. { 27 for n in 0u32.. {
23 let mut s: String<128> = String::new(); 28 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 d3702fc35..f15f333b7 100644
--- a/examples/stm32f3/src/bin/usb_serial.rs
+++ b/examples/stm32f3/src/bin/usb_serial.rs
@@ -4,17 +4,21 @@
4 4
5use defmt::{panic, *}; 5use defmt::{panic, *};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_futures::join::join;
7use embassy_stm32::gpio::{Level, Output, Speed}; 8use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::time::mhz; 9use embassy_stm32::time::mhz;
9use embassy_stm32::usb::{Driver, Instance}; 10use embassy_stm32::usb::{Driver, Instance};
10use embassy_stm32::{interrupt, Config}; 11use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
11use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
13use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError; 14use embassy_usb::driver::EndpointError;
13use embassy_usb::Builder; 15use embassy_usb::Builder;
14use embassy_usb_serial::{CdcAcmClass, State};
15use futures::future::join;
16use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
17 17
18bind_interrupts!(struct Irqs {
19 USB_LP_CAN_RX0 => usb::InterruptHandler<peripherals::USB>;
20});
21
18#[embassy_executor::main] 22#[embassy_executor::main]
19async fn main(_spawner: Spawner) { 23async fn main(_spawner: Spawner) {
20 let mut config = Config::default(); 24 let mut config = Config::default();
@@ -33,8 +37,7 @@ async fn main(_spawner: Spawner) {
33 dp_pullup.set_high(); 37 dp_pullup.set_high();
34 38
35 // Create the driver, from the HAL. 39 // Create the driver, from the HAL.
36 let irq = interrupt::take!(USB_LP_CAN_RX0); 40 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
37 let driver = Driver::new(p.USB, irq, p.PA12, p.PA11);
38 41
39 // Create embassy-usb Config 42 // Create embassy-usb Config
40 let config = embassy_usb::Config::new(0xc0de, 0xcafe); 43 let config = embassy_usb::Config::new(0xc0de, 0xcafe);
@@ -55,7 +58,6 @@ async fn main(_spawner: Spawner) {
55 &mut config_descriptor, 58 &mut config_descriptor,
56 &mut bos_descriptor, 59 &mut bos_descriptor,
57 &mut control_buf, 60 &mut control_buf,
58 None,
59 ); 61 );
60 62
61 // Create classes on the builder. 63 // Create classes on the builder.
diff --git a/examples/stm32f4/.cargo/config.toml b/examples/stm32f4/.cargo/config.toml
index 4d4363c05..16efa8e6f 100644
--- a/examples/stm32f4/.cargo/config.toml
+++ b/examples/stm32f4/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-run --list-chips` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32F429ZITx" 3runner = "probe-rs run --chip STM32F429ZITx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index 9bfdda92d..c1c821364 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -2,28 +2,31 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32f4-examples" 3name = "embassy-stm32f4-examples"
4version = "0.1.0" 4version = "0.1.0"
5 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers", "arch-cortex-m", "executor-thread", "executor-interrupt"] }
10embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", 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", "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", "embedded-sdmmc", "chrono"] }
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"] }
12 14
13defmt = "0.3" 15defmt = "0.3"
14defmt-rtt = "0.3" 16defmt-rtt = "0.4"
15 17
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 18cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
17cortex-m-rt = "0.7.0" 19cortex-m-rt = "0.7.0"
18embedded-hal = "0.2.6" 20embedded-hal = "0.2.6"
19embedded-io = "0.3.0" 21embedded-io = "0.4.0"
20panic-probe = { version = "0.3", features = ["print-defmt"] } 22panic-probe = { version = "0.3", features = ["print-defmt"] }
21futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 23futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
22heapless = { version = "0.7.5", default-features = false } 24heapless = { version = "0.7.5", default-features = false }
23nb = "1.0.0" 25nb = "1.0.0"
24embedded-storage = "0.3.0" 26embedded-storage = "0.3.0"
25micromath = "2.0.0" 27micromath = "2.0.0"
26static_cell = "1.0" 28static_cell = { version = "1.1", features = ["nightly"]}
29chrono = { version = "^0.4", default-features = false}
27 30
28usb-device = "0.2" 31[profile.release]
29usbd-serial = "0.1.1" 32debug = 2
diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs
index 871185074..1c9a0b35d 100644
--- a/examples/stm32f4/src/bin/adc.rs
+++ b/examples/stm32f4/src/bin/adc.rs
@@ -2,9 +2,10 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use cortex_m::prelude::_embedded_hal_blocking_delay_DelayUs;
5use defmt::*; 6use defmt::*;
6use embassy_executor::Spawner; 7use embassy_executor::Spawner;
7use embassy_stm32::adc::Adc; 8use embassy_stm32::adc::{Adc, Temperature, VrefInt};
8use embassy_time::{Delay, Duration, Timer}; 9use embassy_time::{Delay, Duration, Timer};
9use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
10 11
@@ -13,12 +14,55 @@ async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default()); 14 let p = embassy_stm32::init(Default::default());
14 info!("Hello World!"); 15 info!("Hello World!");
15 16
16 let mut adc = Adc::new(p.ADC1, &mut Delay); 17 let mut delay = Delay;
18 let mut adc = Adc::new(p.ADC1, &mut delay);
17 let mut pin = p.PC1; 19 let mut pin = p.PC1;
18 20
21 let mut vrefint = adc.enable_vrefint();
22 let mut temp = adc.enable_temperature();
23
24 // Startup delay can be combined to the maximum of either
25 delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us()));
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
19 loop { 52 loop {
53 // Read pin
20 let v = adc.read(&mut pin); 54 let v = adc.read(&mut pin);
21 info!("--> {} - {} mV", v, adc.to_millivolts(v)); 55 info!("PC1: {} ({} mV)", v, convert_to_millivolts(v));
56
57 // Read internal temperature
58 let v = adc.read_internal(&mut temp);
59 let celcius = convert_to_celcius(v);
60 info!("Internal temp: {} ({} C)", v, celcius);
61
62 // Read internal voltage reference
63 let v = adc.read_internal(&mut vrefint);
64 info!("VrefInt: {}", v);
65
22 Timer::after(Duration::from_millis(100)).await; 66 Timer::after(Duration::from_millis(100)).await;
23 } 67 }
24} 68}
diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs
index e8377b9a1..08bed88db 100644
--- a/examples/stm32f4/src/bin/can.rs
+++ b/examples/stm32f4/src/bin/can.rs
@@ -2,16 +2,25 @@
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use cortex_m_rt::entry;
6use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts;
7use embassy_stm32::can::bxcan::filter::Mask32; 8use embassy_stm32::can::bxcan::filter::Mask32;
8use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId}; 9use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId};
9use embassy_stm32::can::Can; 10use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler};
10use embassy_stm32::gpio::{Input, Pull}; 11use embassy_stm32::gpio::{Input, Pull};
12use embassy_stm32::peripherals::CAN1;
11use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
12 14
13#[entry] 15bind_interrupts!(struct Irqs {
14fn main() -> ! { 16 CAN1_RX0 => Rx0InterruptHandler<CAN1>;
17 CAN1_RX1 => Rx1InterruptHandler<CAN1>;
18 CAN1_SCE => SceInterruptHandler<CAN1>;
19 CAN1_TX => TxInterruptHandler<CAN1>;
20});
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
15 info!("Hello World!"); 24 info!("Hello World!");
16 25
17 let mut p = embassy_stm32::init(Default::default()); 26 let mut p = embassy_stm32::init(Default::default());
@@ -23,11 +32,14 @@ fn main() -> ! {
23 let rx_pin = Input::new(&mut p.PA11, Pull::Up); 32 let rx_pin = Input::new(&mut p.PA11, Pull::Up);
24 core::mem::forget(rx_pin); 33 core::mem::forget(rx_pin);
25 34
26 let mut can = Can::new(p.CAN1, p.PA11, p.PA12); 35 let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs);
27 36
28 can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); 37 can.as_mut()
38 .modify_filters()
39 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
29 40
30 can.modify_config() 41 can.as_mut()
42 .modify_config()
31 .set_bit_timing(0x001c0003) // http://www.bittiming.can-wiki.info/ 43 .set_bit_timing(0x001c0003) // http://www.bittiming.can-wiki.info/
32 .set_loopback(true) // Receive own frames 44 .set_loopback(true) // Receive own frames
33 .set_silent(true) 45 .set_silent(true)
@@ -36,9 +48,8 @@ fn main() -> ! {
36 let mut i: u8 = 0; 48 let mut i: u8 = 0;
37 loop { 49 loop {
38 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); 50 let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]);
39 unwrap!(nb::block!(can.transmit(&tx_frame))); 51 can.write(&tx_frame).await;
40 while !can.is_transmitter_idle() {} 52 let (_, rx_frame) = can.read().await.unwrap();
41 let rx_frame = unwrap!(nb::block!(can.receive()));
42 info!("loopback frame {=u8}", unwrap!(rx_frame.data())[0]); 53 info!("loopback frame {=u8}", unwrap!(rx_frame.data())[0]);
43 i += 1; 54 i += 1;
44 } 55 }
diff --git a/examples/stm32f4/src/bin/dac.rs b/examples/stm32f4/src/bin/dac.rs
index d97ae7082..3a6216712 100644
--- a/examples/stm32f4/src/bin/dac.rs
+++ b/examples/stm32f4/src/bin/dac.rs
@@ -4,7 +4,8 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dac::{Channel, Dac, Value}; 7use embassy_stm32::dac::{DacCh1, DacChannel, Value};
8use embassy_stm32::dma::NoDma;
8use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
9 10
10#[embassy_executor::main] 11#[embassy_executor::main]
@@ -12,12 +13,12 @@ async fn main(_spawner: Spawner) -> ! {
12 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
13 info!("Hello World, dude!"); 14 info!("Hello World, dude!");
14 15
15 let mut dac = Dac::new_1ch(p.DAC, p.PA4); 16 let mut dac = DacCh1::new(p.DAC, NoDma, p.PA4);
16 17
17 loop { 18 loop {
18 for v in 0..=255 { 19 for v in 0..=255 {
19 unwrap!(dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v)))); 20 unwrap!(dac.set(Value::Bit8(to_sine_wave(v))));
20 unwrap!(dac.trigger(Channel::Ch1)); 21 dac.trigger();
21 } 22 }
22 } 23 }
23} 24}
diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs
new file mode 100644
index 000000000..d0b164393
--- /dev/null
+++ b/examples/stm32f4/src/bin/eth.rs
@@ -0,0 +1,111 @@
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::{Ipv4Address, Stack, StackResources};
9use embassy_stm32::eth::generic_smi::GenericSMI;
10use embassy_stm32::eth::{Ethernet, PacketQueue};
11use embassy_stm32::peripherals::ETH;
12use embassy_stm32::rng::Rng;
13use embassy_stm32::time::mhz;
14use embassy_stm32::{bind_interrupts, eth, Config};
15use embassy_time::{Duration, Timer};
16use embedded_io::asynch::Write;
17use static_cell::make_static;
18use {defmt_rtt as _, panic_probe as _};
19bind_interrupts!(struct Irqs {
20 ETH => eth::InterruptHandler;
21});
22
23type Device = Ethernet<'static, ETH, GenericSMI>;
24
25#[embassy_executor::task]
26async fn net_task(stack: &'static Stack<Device>) -> ! {
27 stack.run().await
28}
29
30#[embassy_executor::main]
31async fn main(spawner: Spawner) -> ! {
32 let mut config = Config::default();
33 config.rcc.sys_ck = Some(mhz(200));
34 let p = embassy_stm32::init(config);
35
36 info!("Hello World!");
37
38 // Generate random seed.
39 let mut rng = Rng::new(p.RNG);
40 let mut seed = [0; 8];
41 let _ = rng.async_fill_bytes(&mut seed).await;
42 let seed = u64::from_le_bytes(seed);
43
44 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
45
46 let device = Ethernet::new(
47 make_static!(PacketQueue::<16, 16>::new()),
48 p.ETH,
49 Irqs,
50 p.PA1,
51 p.PA2,
52 p.PC1,
53 p.PA7,
54 p.PC4,
55 p.PC5,
56 p.PG13,
57 p.PB13,
58 p.PG11,
59 GenericSMI::new(),
60 mac_addr,
61 0,
62 );
63
64 let config = embassy_net::Config::dhcpv4(Default::default());
65 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
66 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
67 // dns_servers: Vec::new(),
68 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
69 //});
70
71 // Init network stack
72 let stack = &*make_static!(Stack::new(
73 device,
74 config,
75 make_static!(StackResources::<2>::new()),
76 seed
77 ));
78
79 // Launch network task
80 unwrap!(spawner.spawn(net_task(&stack)));
81
82 info!("Network task initialized");
83
84 // Then we can use it!
85 let mut rx_buffer = [0; 4096];
86 let mut tx_buffer = [0; 4096];
87
88 loop {
89 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer);
90
91 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
92
93 let remote_endpoint = (Ipv4Address::new(10, 42, 0, 1), 8000);
94 info!("connecting...");
95 let r = socket.connect(remote_endpoint).await;
96 if let Err(e) = r {
97 info!("connect error: {:?}", e);
98 continue;
99 }
100 info!("connected!");
101 let buf = [0; 1024];
102 loop {
103 let r = socket.write_all(&buf).await;
104 if let Err(e) = r {
105 info!("write error: {:?}", e);
106 continue;
107 }
108 Timer::after(Duration::from_secs(1)).await;
109 }
110 }
111}
diff --git a/examples/stm32f4/src/bin/flash.rs b/examples/stm32f4/src/bin/flash.rs
index 393d61e86..93c54e943 100644
--- a/examples/stm32f4/src/bin/flash.rs
+++ b/examples/stm32f4/src/bin/flash.rs
@@ -4,8 +4,7 @@
4 4
5use defmt::{info, unwrap}; 5use defmt::{info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::flash::Flash; 7use embassy_stm32::flash::{Blocking, Flash};
8use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
10 9
11#[embassy_executor::main] 10#[embassy_executor::main]
@@ -13,7 +12,9 @@ async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
14 info!("Hello Flash!"); 13 info!("Hello Flash!");
15 14
16 let mut f = Flash::unlock(p.FLASH); 15 // Once can also call `into_regions()` to get access to NorFlash implementations
16 // for each of the unique characteristics.
17 let mut f = Flash::new_blocking(p.FLASH);
17 18
18 // Sector 5 19 // Sector 5
19 test_flash(&mut f, 128 * 1024, 128 * 1024); 20 test_flash(&mut f, 128 * 1024, 128 * 1024);
@@ -25,7 +26,7 @@ async fn main(_spawner: Spawner) {
25 test_flash(&mut f, (2048 - 128) * 1024, 128 * 1024); 26 test_flash(&mut f, (2048 - 128) * 1024, 128 * 1024);
26} 27}
27 28
28fn test_flash(f: &mut Flash, offset: u32, size: u32) { 29fn test_flash(f: &mut Flash<'_, Blocking>, offset: u32, size: u32) {
29 info!("Testing offset: {=u32:#X}, size: {=u32:#X}", offset, size); 30 info!("Testing offset: {=u32:#X}, size: {=u32:#X}", offset, size);
30 31
31 info!("Reading..."); 32 info!("Reading...");
@@ -34,7 +35,7 @@ fn test_flash(f: &mut Flash, offset: u32, size: u32) {
34 info!("Read: {=[u8]:x}", buf); 35 info!("Read: {=[u8]:x}", buf);
35 36
36 info!("Erasing..."); 37 info!("Erasing...");
37 unwrap!(f.erase(offset, offset + size)); 38 unwrap!(f.blocking_erase(offset, offset + size));
38 39
39 info!("Reading..."); 40 info!("Reading...");
40 let mut buf = [0u8; 32]; 41 let mut buf = [0u8; 32];
@@ -42,7 +43,7 @@ fn test_flash(f: &mut Flash, offset: u32, size: u32) {
42 info!("Read after erase: {=[u8]:x}", buf); 43 info!("Read after erase: {=[u8]:x}", buf);
43 44
44 info!("Writing..."); 45 info!("Writing...");
45 unwrap!(f.write( 46 unwrap!(f.blocking_write(
46 offset, 47 offset,
47 &[ 48 &[
48 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 49 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
diff --git a/examples/stm32f4/src/bin/flash_async.rs b/examples/stm32f4/src/bin/flash_async.rs
new file mode 100644
index 000000000..6c9689d9c
--- /dev/null
+++ b/examples/stm32f4/src/bin/flash_async.rs
@@ -0,0 +1,85 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{info, unwrap};
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts;
8use embassy_stm32::flash::{Flash, InterruptHandler};
9use embassy_stm32::gpio::{AnyPin, Level, Output, Pin, Speed};
10use embassy_time::{Duration, Timer};
11use {defmt_rtt as _, panic_probe as _};
12
13bind_interrupts!(struct Irqs {
14 FLASH => InterruptHandler;
15});
16
17#[embassy_executor::main]
18async fn main(spawner: Spawner) {
19 let p = embassy_stm32::init(Default::default());
20 info!("Hello Flash!");
21
22 let mut f = Flash::new(p.FLASH, Irqs);
23
24 // Led should blink uninterrupted during ~2sec erase operation
25 spawner.spawn(blinky(p.PB7.degrade())).unwrap();
26
27 // Test on bank 2 in order not to stall CPU.
28 test_flash(&mut f, 1024 * 1024, 128 * 1024).await;
29}
30
31#[embassy_executor::task]
32async fn blinky(p: AnyPin) {
33 let mut led = Output::new(p, Level::High, Speed::Low);
34
35 loop {
36 info!("high");
37 led.set_high();
38 Timer::after(Duration::from_millis(300)).await;
39
40 info!("low");
41 led.set_low();
42 Timer::after(Duration::from_millis(300)).await;
43 }
44}
45
46async fn test_flash<'a>(f: &mut Flash<'a>, offset: u32, size: u32) {
47 info!("Testing offset: {=u32:#X}, size: {=u32:#X}", offset, size);
48
49 info!("Reading...");
50 let mut buf = [0u8; 32];
51 unwrap!(f.read(offset, &mut buf));
52 info!("Read: {=[u8]:x}", buf);
53
54 info!("Erasing...");
55 unwrap!(f.erase(offset, offset + size).await);
56
57 info!("Reading...");
58 let mut buf = [0u8; 32];
59 unwrap!(f.read(offset, &mut buf));
60 info!("Read after erase: {=[u8]:x}", buf);
61
62 info!("Writing...");
63 unwrap!(
64 f.write(
65 offset,
66 &[
67 1, 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,
68 29, 30, 31, 32
69 ]
70 )
71 .await
72 );
73
74 info!("Reading...");
75 let mut buf = [0u8; 32];
76 unwrap!(f.read(offset, &mut buf));
77 info!("Read: {=[u8]:x}", buf);
78 assert_eq!(
79 &buf[..],
80 &[
81 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
82 30, 31, 32
83 ]
84 );
85}
diff --git a/examples/stm32f4/src/bin/i2c.rs b/examples/stm32f4/src/bin/i2c.rs
new file mode 100644
index 000000000..a92957325
--- /dev/null
+++ b/examples/stm32f4/src/bin/i2c.rs
@@ -0,0 +1,48 @@
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::time::Hertz;
10use embassy_stm32::{bind_interrupts, i2c, peripherals};
11use embassy_time::Duration;
12use {defmt_rtt as _, panic_probe as _};
13
14const ADDRESS: u8 = 0x5F;
15const WHOAMI: u8 = 0x0F;
16
17bind_interrupts!(struct Irqs {
18 I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>;
19});
20
21#[embassy_executor::main]
22async fn main(_spawner: Spawner) {
23 info!("Hello world!");
24 let p = embassy_stm32::init(Default::default());
25
26 let mut i2c = I2c::new(
27 p.I2C2,
28 p.PB10,
29 p.PB11,
30 Irqs,
31 NoDma,
32 NoDma,
33 Hertz(100_000),
34 Default::default(),
35 );
36
37 // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long.
38 // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay.
39 let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000));
40
41 let mut data = [0u8; 1];
42
43 match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) {
44 Ok(()) => info!("Whoami: {}", data[0]),
45 Err(Error::Timeout) => error!("Operation timed out"),
46 Err(e) => error!("I2c Error: {:?}", e),
47 }
48}
diff --git a/examples/stm32f4/src/bin/i2s_dma.rs b/examples/stm32f4/src/bin/i2s_dma.rs
new file mode 100644
index 000000000..e8d7b5f77
--- /dev/null
+++ b/examples/stm32f4/src/bin/i2s_dma.rs
@@ -0,0 +1,36 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::fmt::Write;
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_stm32::i2s::{Config, I2S};
10use embassy_stm32::time::Hertz;
11use heapless::String;
12use {defmt_rtt as _, panic_probe as _};
13
14#[embassy_executor::main]
15async fn main(_spawner: Spawner) {
16 let p = embassy_stm32::init(Default::default());
17 info!("Hello World!");
18
19 let mut i2s = I2S::new(
20 p.SPI2,
21 p.PC3, // sd
22 p.PB12, // ws
23 p.PB10, // ck
24 p.PC6, // mck
25 p.DMA1_CH4,
26 p.DMA1_CH3,
27 Hertz(1_000_000),
28 Config::default(),
29 );
30
31 for n in 0u32.. {
32 let mut write: String<128> = String::new();
33 core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap();
34 i2s.write(&mut write.as_bytes()).await.ok();
35 }
36}
diff --git a/examples/stm32f4/src/bin/mco.rs b/examples/stm32f4/src/bin/mco.rs
new file mode 100644
index 000000000..2b9ceebc3
--- /dev/null
+++ b/examples/stm32f4/src/bin/mco.rs
@@ -0,0 +1,30 @@
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_stm32::rcc::{Mco, Mco1Source, Mco2Source, McoClock};
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_stm32::init(Default::default());
15 info!("Hello World!");
16
17 let _mco1 = Mco::new(p.MCO1, p.PA8, Mco1Source::Hsi, McoClock::DIV1);
18 let _mco2 = Mco::new(p.MCO2, p.PC9, Mco2Source::Pll, McoClock::DIV4);
19 let mut led = Output::new(p.PB7, Level::High, Speed::Low);
20
21 loop {
22 info!("high");
23 led.set_high();
24 Timer::after(Duration::from_millis(300)).await;
25
26 info!("low");
27 led.set_low();
28 Timer::after(Duration::from_millis(300)).await;
29 }
30}
diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs
index 9e8228a4b..80bf59deb 100644
--- a/examples/stm32f4/src/bin/multiprio.rs
+++ b/examples/stm32f4/src/bin/multiprio.rs
@@ -59,9 +59,9 @@
59 59
60use cortex_m_rt::entry; 60use cortex_m_rt::entry;
61use defmt::*; 61use defmt::*;
62use embassy_stm32::executor::{Executor, InterruptExecutor}; 62use embassy_executor::{Executor, InterruptExecutor};
63use embassy_stm32::interrupt; 63use embassy_stm32::interrupt;
64use embassy_stm32::interrupt::InterruptExt; 64use embassy_stm32::interrupt::{InterruptExt, Priority};
65use embassy_time::{Duration, Instant, Timer}; 65use embassy_time::{Duration, Instant, Timer};
66use static_cell::StaticCell; 66use static_cell::StaticCell;
67use {defmt_rtt as _, panic_probe as _}; 67use {defmt_rtt as _, panic_probe as _};
@@ -108,28 +108,34 @@ async fn run_low() {
108 } 108 }
109} 109}
110 110
111static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::UART4>> = StaticCell::new(); 111static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
112static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::UART5>> = StaticCell::new(); 112static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
113static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); 113static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
114 114
115#[interrupt]
116unsafe fn UART4() {
117 EXECUTOR_HIGH.on_interrupt()
118}
119
120#[interrupt]
121unsafe fn UART5() {
122 EXECUTOR_MED.on_interrupt()
123}
124
115#[entry] 125#[entry]
116fn main() -> ! { 126fn main() -> ! {
117 info!("Hello World!"); 127 info!("Hello World!");
118 128
119 let _p = embassy_stm32::init(Default::default()); 129 let _p = embassy_stm32::init(Default::default());
120 130
121 // High-priority executor: SWI1_EGU1, priority level 6 131 // High-priority executor: UART4, priority level 6
122 let irq = interrupt::take!(UART4); 132 interrupt::UART4.set_priority(Priority::P6);
123 irq.set_priority(interrupt::Priority::P6); 133 let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
124 let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
125 let spawner = executor.start();
126 unwrap!(spawner.spawn(run_high())); 134 unwrap!(spawner.spawn(run_high()));
127 135
128 // Medium-priority executor: SWI0_EGU0, priority level 7 136 // Medium-priority executor: UART5, priority level 7
129 let irq = interrupt::take!(UART5); 137 interrupt::UART5.set_priority(Priority::P7);
130 irq.set_priority(interrupt::Priority::P7); 138 let spawner = EXECUTOR_MED.start(interrupt::UART5);
131 let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
132 let spawner = executor.start();
133 unwrap!(spawner.spawn(run_med())); 139 unwrap!(spawner.spawn(run_med()));
134 140
135 // Low priority executor: runs in thread mode, using WFE/SEV 141 // Low priority executor: runs in thread mode, using WFE/SEV
diff --git a/examples/stm32f4/src/bin/pwm_complementary.rs b/examples/stm32f4/src/bin/pwm_complementary.rs
new file mode 100644
index 000000000..a8a68ed6e
--- /dev/null
+++ b/examples/stm32f4/src/bin/pwm_complementary.rs
@@ -0,0 +1,52 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::pwm::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin};
8use embassy_stm32::pwm::simple_pwm::PwmPin;
9use embassy_stm32::pwm::Channel;
10use embassy_stm32::time::khz;
11use embassy_time::{Duration, Timer};
12use {defmt_rtt as _, panic_probe as _};
13
14#[embassy_executor::main]
15async fn main(_spawner: Spawner) {
16 let p = embassy_stm32::init(Default::default());
17 info!("Hello World!");
18
19 let ch1 = PwmPin::new_ch1(p.PE9);
20 let ch1n = ComplementaryPwmPin::new_ch1(p.PA7);
21 let mut pwm = ComplementaryPwm::new(
22 p.TIM1,
23 Some(ch1),
24 Some(ch1n),
25 None,
26 None,
27 None,
28 None,
29 None,
30 None,
31 khz(10),
32 );
33
34 let max = pwm.get_max_duty();
35 pwm.set_dead_time(max / 1024);
36
37 pwm.enable(Channel::Ch1);
38
39 info!("PWM initialized");
40 info!("PWM max duty {}", max);
41
42 loop {
43 pwm.set_duty(Channel::Ch1, 0);
44 Timer::after(Duration::from_millis(300)).await;
45 pwm.set_duty(Channel::Ch1, max / 4);
46 Timer::after(Duration::from_millis(300)).await;
47 pwm.set_duty(Channel::Ch1, max / 2);
48 Timer::after(Duration::from_millis(300)).await;
49 pwm.set_duty(Channel::Ch1, max - 1);
50 Timer::after(Duration::from_millis(300)).await;
51 }
52}
diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs
new file mode 100644
index 000000000..0eca58203
--- /dev/null
+++ b/examples/stm32f4/src/bin/rtc.rs
@@ -0,0 +1,30 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use chrono::{NaiveDate, NaiveDateTime};
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_stm32::rtc::{Rtc, RtcConfig};
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_stm32::init(Default::default());
15 info!("Hello World!");
16
17 let now = NaiveDate::from_ymd_opt(2020, 5, 15)
18 .unwrap()
19 .and_hms_opt(10, 30, 15)
20 .unwrap();
21
22 let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
23
24 rtc.set_datetime(now.into()).expect("datetime not set");
25
26 // In reality the delay would be much longer
27 Timer::after(Duration::from_millis(20000)).await;
28
29 let _then: NaiveDateTime = rtc.now().unwrap().into();
30}
diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs
index 0edd8a61a..6ec7d0fec 100644
--- a/examples/stm32f4/src/bin/sdmmc.rs
+++ b/examples/stm32f4/src/bin/sdmmc.rs
@@ -4,23 +4,30 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::sdmmc::Sdmmc; 7use embassy_stm32::sdmmc::{DataBlock, Sdmmc};
8use embassy_stm32::time::mhz; 8use embassy_stm32::time::mhz;
9use embassy_stm32::{interrupt, Config}; 9use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12/// This is a safeguard to not overwrite any data on the SD card.
13/// If you don't care about SD card contents, set this to `true` to test writes.
14const ALLOW_WRITES: bool = false;
15
16bind_interrupts!(struct Irqs {
17 SDIO => sdmmc::InterruptHandler<peripherals::SDIO>;
18});
19
12#[embassy_executor::main] 20#[embassy_executor::main]
13async fn main(_spawner: Spawner) -> ! { 21async fn main(_spawner: Spawner) {
14 let mut config = Config::default(); 22 let mut config = Config::default();
15 config.rcc.sys_ck = Some(mhz(48)); 23 config.rcc.sys_ck = Some(mhz(48));
24 config.rcc.pll48 = true;
16 let p = embassy_stm32::init(config); 25 let p = embassy_stm32::init(config);
17 info!("Hello World!"); 26 info!("Hello World!");
18 27
19 let irq = interrupt::take!(SDIO);
20
21 let mut sdmmc = Sdmmc::new_4bit( 28 let mut sdmmc = Sdmmc::new_4bit(
22 p.SDIO, 29 p.SDIO,
23 irq, 30 Irqs,
24 p.DMA2_CH3, 31 p.DMA2_CH3,
25 p.PC12, 32 p.PC12,
26 p.PD2, 33 p.PD2,
@@ -34,11 +41,51 @@ async fn main(_spawner: Spawner) -> ! {
34 // Should print 400kHz for initialization 41 // Should print 400kHz for initialization
35 info!("Configured clock: {}", sdmmc.clock().0); 42 info!("Configured clock: {}", sdmmc.clock().0);
36 43
37 unwrap!(sdmmc.init_card(mhz(25)).await); 44 let mut err = None;
45 loop {
46 match sdmmc.init_card(mhz(24)).await {
47 Ok(_) => break,
48 Err(e) => {
49 if err != Some(e) {
50 info!("waiting for card error, retrying: {:?}", e);
51 err = Some(e);
52 }
53 }
54 }
55 }
38 56
39 let card = unwrap!(sdmmc.card()); 57 let card = unwrap!(sdmmc.card());
40 58
41 info!("Card: {:#?}", Debug2Format(card)); 59 info!("Card: {:#?}", Debug2Format(card));
60 info!("Clock: {}", sdmmc.clock());
61
62 // Arbitrary block index
63 let block_idx = 16;
64
65 // SDMMC uses `DataBlock` instead of `&[u8]` to ensure 4 byte alignment required by the hardware.
66 let mut block = DataBlock([0u8; 512]);
67
68 sdmmc.read_block(block_idx, &mut block).await.unwrap();
69 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]);
70
71 if !ALLOW_WRITES {
72 info!("Writing is disabled.");
73 loop {}
74 }
75
76 info!("Filling block with 0x55");
77 block.fill(0x55);
78 sdmmc.write_block(block_idx, &block).await.unwrap();
79 info!("Write done");
80
81 sdmmc.read_block(block_idx, &mut block).await.unwrap();
82 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]);
83
84 info!("Filling block with 0xAA");
85 block.fill(0xAA);
86 sdmmc.write_block(block_idx, &block).await.unwrap();
87 info!("Write done");
42 88
43 loop {} 89 sdmmc.read_block(block_idx, &mut block).await.unwrap();
90 info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]);
44} 91}
diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs
index 90ad882b8..7680fe845 100644
--- a/examples/stm32f4/src/bin/usart.rs
+++ b/examples/stm32f4/src/bin/usart.rs
@@ -6,8 +6,13 @@ use cortex_m_rt::entry;
6use defmt::*; 6use defmt::*;
7use embassy_stm32::dma::NoDma; 7use embassy_stm32::dma::NoDma;
8use embassy_stm32::usart::{Config, Uart}; 8use embassy_stm32::usart::{Config, Uart};
9use embassy_stm32::{bind_interrupts, peripherals, usart};
9use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
10 11
12bind_interrupts!(struct Irqs {
13 USART3 => usart::InterruptHandler<peripherals::USART3>;
14});
15
11#[entry] 16#[entry]
12fn main() -> ! { 17fn main() -> ! {
13 info!("Hello World!"); 18 info!("Hello World!");
@@ -15,7 +20,7 @@ fn main() -> ! {
15 let p = embassy_stm32::init(Default::default()); 20 let p = embassy_stm32::init(Default::default());
16 21
17 let config = Config::default(); 22 let config = Config::default();
18 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, NoDma, NoDma, config); 23 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, NoDma, NoDma, config);
19 24
20 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 25 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
21 info!("wrote Hello, starting echo"); 26 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..c573dc3a3 100644
--- a/examples/stm32f4/src/bin/usart_buffered.rs
+++ b/examples/stm32f4/src/bin/usart_buffered.rs
@@ -4,25 +4,25 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma; 7use embassy_stm32::usart::{BufferedUart, Config};
8use embassy_stm32::interrupt; 8use embassy_stm32::{bind_interrupts, peripherals, usart};
9use embassy_stm32::usart::{BufferedUart, Config, State, Uart};
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
12bind_interrupts!(struct Irqs {
13 USART3 => usart::BufferedInterruptHandler<peripherals::USART3>;
14});
15
13#[embassy_executor::main] 16#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
15 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(Default::default());
16 info!("Hello World!"); 19 info!("Hello World!");
17 20
18 let config = Config::default(); 21 let config = Config::default();
19 let usart = Uart::new(p.USART3, p.PD9, p.PD8, NoDma, NoDma, config);
20 22
21 let mut state = State::new();
22 let irq = interrupt::take!(USART3);
23 let mut tx_buf = [0u8; 32]; 23 let mut tx_buf = [0u8; 32];
24 let mut rx_buf = [0u8; 32]; 24 let mut rx_buf = [0u8; 32];
25 let mut buf_usart = BufferedUart::new(&mut state, usart, irq, &mut tx_buf, &mut rx_buf); 25 let mut buf_usart = BufferedUart::new(p.USART3, Irqs, p.PD9, p.PD8, &mut tx_buf, &mut rx_buf, config);
26 26
27 loop { 27 loop {
28 let buf = buf_usart.fill_buf().await.unwrap(); 28 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..3408ec370 100644
--- a/examples/stm32f4/src/bin/usart_dma.rs
+++ b/examples/stm32f4/src/bin/usart_dma.rs
@@ -8,16 +8,21 @@ use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma; 9use embassy_stm32::dma::NoDma;
10use embassy_stm32::usart::{Config, Uart}; 10use embassy_stm32::usart::{Config, Uart};
11use embassy_stm32::{bind_interrupts, peripherals, usart};
11use heapless::String; 12use heapless::String;
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
13 14
15bind_interrupts!(struct Irqs {
16 USART3 => usart::InterruptHandler<peripherals::USART3>;
17});
18
14#[embassy_executor::main] 19#[embassy_executor::main]
15async fn main(_spawner: Spawner) { 20async fn main(_spawner: Spawner) {
16 let p = embassy_stm32::init(Default::default()); 21 let p = embassy_stm32::init(Default::default());
17 info!("Hello World!"); 22 info!("Hello World!");
18 23
19 let config = Config::default(); 24 let config = Config::default();
20 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, p.DMA1_CH3, NoDma, config); 25 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, NoDma, config);
21 26
22 for n in 0u32.. { 27 for n in 0u32.. {
23 let mut s: String<128> = String::new(); 28 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..b1f01417c
--- /dev/null
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -0,0 +1,164 @@
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::{bind_interrupts, peripherals, usb_otg, 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::make_static;
18use {defmt_rtt as _, panic_probe as _};
19
20type UsbDriver = Driver<'static, embassy_stm32::peripherals::USB_OTG_FS>;
21
22const MTU: usize = 1514;
23
24#[embassy_executor::task]
25async fn usb_task(mut device: UsbDevice<'static, UsbDriver>) -> ! {
26 device.run().await
27}
28
29#[embassy_executor::task]
30async fn usb_ncm_task(class: Runner<'static, UsbDriver, MTU>) -> ! {
31 class.run().await
32}
33
34#[embassy_executor::task]
35async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
36 stack.run().await
37}
38
39bind_interrupts!(struct Irqs {
40 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
41});
42
43#[embassy_executor::main]
44async fn main(spawner: Spawner) {
45 info!("Hello World!");
46
47 let mut config = Config::default();
48 config.rcc.pll48 = true;
49 config.rcc.sys_ck = Some(mhz(48));
50
51 let p = embassy_stm32::init(config);
52
53 // Create the driver, from the HAL.
54 let ep_out_buffer = &mut make_static!([0; 256])[..];
55 let mut config = embassy_stm32::usb_otg::Config::default();
56 config.vbus_detection = true;
57 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config);
58
59 // Create embassy-usb Config
60 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
61 config.manufacturer = Some("Embassy");
62 config.product = Some("USB-Ethernet example");
63 config.serial_number = Some("12345678");
64 config.max_power = 100;
65 config.max_packet_size_0 = 64;
66
67 // Required for Windows support.
68 config.composite_with_iads = true;
69 config.device_class = 0xEF;
70 config.device_sub_class = 0x02;
71 config.device_protocol = 0x01;
72
73 // Create embassy-usb DeviceBuilder using the driver and config.
74 let mut builder = Builder::new(
75 driver,
76 config,
77 &mut make_static!([0; 256])[..],
78 &mut make_static!([0; 256])[..],
79 &mut make_static!([0; 256])[..],
80 &mut make_static!([0; 128])[..],
81 );
82
83 // Our MAC addr.
84 let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC];
85 // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has.
86 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
87
88 // Create classes on the builder.
89 let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64);
90
91 // Build the builder.
92 let usb = builder.build();
93
94 unwrap!(spawner.spawn(usb_task(usb)));
95
96 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr);
97 unwrap!(spawner.spawn(usb_ncm_task(runner)));
98
99 let config = embassy_net::Config::dhcpv4(Default::default());
100 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
101 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
102 // dns_servers: Vec::new(),
103 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
104 //});
105
106 // Generate random seed
107 let mut rng = Rng::new(p.RNG);
108 let mut seed = [0; 8];
109 unwrap!(rng.async_fill_bytes(&mut seed).await);
110 let seed = u64::from_le_bytes(seed);
111
112 // Init network stack
113 let stack = &*make_static!(Stack::new(
114 device,
115 config,
116 make_static!(StackResources::<2>::new()),
117 seed
118 ));
119
120 unwrap!(spawner.spawn(net_task(stack)));
121
122 // And now we can use it!
123
124 let mut rx_buffer = [0; 4096];
125 let mut tx_buffer = [0; 4096];
126 let mut buf = [0; 4096];
127
128 loop {
129 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
130 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
131
132 info!("Listening on TCP:1234...");
133 if let Err(e) = socket.accept(1234).await {
134 warn!("accept error: {:?}", e);
135 continue;
136 }
137
138 info!("Received connection from {:?}", socket.remote_endpoint());
139
140 loop {
141 let n = match socket.read(&mut buf).await {
142 Ok(0) => {
143 warn!("read EOF");
144 break;
145 }
146 Ok(n) => n,
147 Err(e) => {
148 warn!("read error: {:?}", e);
149 break;
150 }
151 };
152
153 info!("rxd {:02x}", &buf[..n]);
154
155 match socket.write_all(&buf[..n]).await {
156 Ok(()) => {}
157 Err(e) => {
158 warn!("write error: {:?}", e);
159 break;
160 }
161 };
162 }
163 }
164}
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs
new file mode 100644
index 000000000..4ff6452ef
--- /dev/null
+++ b/examples/stm32f4/src/bin/usb_serial.rs
@@ -0,0 +1,110 @@
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::{bind_interrupts, peripherals, usb_otg, 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
16bind_interrupts!(struct Irqs {
17 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
18});
19
20#[embassy_executor::main]
21async fn main(_spawner: Spawner) {
22 info!("Hello World!");
23
24 let mut config = Config::default();
25 config.rcc.pll48 = true;
26 config.rcc.sys_ck = Some(mhz(48));
27
28 let p = embassy_stm32::init(config);
29
30 // Create the driver, from the HAL.
31 let mut ep_out_buffer = [0u8; 256];
32 let mut config = embassy_stm32::usb_otg::Config::default();
33 config.vbus_detection = true;
34 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
35
36 // Create embassy-usb Config
37 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
38 config.manufacturer = Some("Embassy");
39 config.product = Some("USB-serial example");
40 config.serial_number = Some("12345678");
41
42 // Required for windows compatibility.
43 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
44 config.device_class = 0xEF;
45 config.device_sub_class = 0x02;
46 config.device_protocol = 0x01;
47 config.composite_with_iads = true;
48
49 // Create embassy-usb DeviceBuilder using the driver and config.
50 // It needs some buffers for building the descriptors.
51 let mut device_descriptor = [0; 256];
52 let mut config_descriptor = [0; 256];
53 let mut bos_descriptor = [0; 256];
54 let mut control_buf = [0; 64];
55
56 let mut state = State::new();
57
58 let mut builder = Builder::new(
59 driver,
60 config,
61 &mut device_descriptor,
62 &mut config_descriptor,
63 &mut bos_descriptor,
64 &mut control_buf,
65 );
66
67 // Create classes on the builder.
68 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
69
70 // Build the builder.
71 let mut usb = builder.build();
72
73 // Run the USB device.
74 let usb_fut = usb.run();
75
76 // Do stuff with the class!
77 let echo_fut = async {
78 loop {
79 class.wait_connection().await;
80 info!("Connected");
81 let _ = echo(&mut class).await;
82 info!("Disconnected");
83 }
84 };
85
86 // Run everything concurrently.
87 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
88 join(usb_fut, echo_fut).await;
89}
90
91struct Disconnected {}
92
93impl From<EndpointError> for Disconnected {
94 fn from(val: EndpointError) -> Self {
95 match val {
96 EndpointError::BufferOverflow => panic!("Buffer overflow"),
97 EndpointError::Disabled => Disconnected {},
98 }
99 }
100}
101
102async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
103 let mut buf = [0; 64];
104 loop {
105 let n = class.read_packet(&mut buf).await?;
106 let data = &buf[..n];
107 info!("data: {:x}", data);
108 class.write_packet(data).await?;
109 }
110}
diff --git a/examples/stm32f4/src/bin/wdt.rs b/examples/stm32f4/src/bin/wdt.rs
index b2c587fa1..e5d122af7 100644
--- a/examples/stm32f4/src/bin/wdt.rs
+++ b/examples/stm32f4/src/bin/wdt.rs
@@ -17,9 +17,7 @@ async fn main(_spawner: Spawner) {
17 let mut led = Output::new(p.PB7, Level::High, Speed::Low); 17 let mut led = Output::new(p.PB7, Level::High, Speed::Low);
18 18
19 let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000); 19 let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000);
20 unsafe { 20 wdt.unleash();
21 wdt.unleash();
22 }
23 21
24 let mut i = 0; 22 let mut i = 0;
25 23
@@ -36,9 +34,7 @@ async fn main(_spawner: Spawner) {
36 // MCU should restart in 1 second after the last pet. 34 // MCU should restart in 1 second after the last pet.
37 if i < 5 { 35 if i < 5 {
38 info!("Petting watchdog"); 36 info!("Petting watchdog");
39 unsafe { 37 wdt.pet();
40 wdt.pet();
41 }
42 } 38 }
43 39
44 i += 1; 40 i += 1;
diff --git a/examples/stm32f7/.cargo/config.toml b/examples/stm32f7/.cargo/config.toml
index b07ad158c..9088eea6e 100644
--- a/examples/stm32f7/.cargo/config.toml
+++ b/examples/stm32f7/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-run --list-chips` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32F767ZITx" 3runner = "probe-rs run --chip STM32F767ZITx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabihf"
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index a446fe3fb..84d7b79c5 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -2,19 +2,21 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32f7-examples" 3name = "embassy-stm32f7-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
10embassy-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"] }
11embassy-net = { path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] } 12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
12embedded-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"] }
13 15
14defmt = "0.3" 16defmt = "0.3"
15defmt-rtt = "0.3" 17defmt-rtt = "0.4"
16 18
17cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
18cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
19embedded-hal = "0.2.6" 21embedded-hal = "0.2.6"
20panic-probe = { version = "0.3", features = ["print-defmt"] } 22panic-probe = { version = "0.3", features = ["print-defmt"] }
@@ -24,4 +26,4 @@ nb = "1.0.0"
24rand_core = "0.6.3" 26rand_core = "0.6.3"
25critical-section = "1.1" 27critical-section = "1.1"
26embedded-storage = "0.3.0" 28embedded-storage = "0.3.0"
27static_cell = "1.0" 29static_cell = { version = "1.1", features = ["nightly"]}
diff --git a/examples/stm32f7/build.rs b/examples/stm32f7/build.rs
index c4e15f19c..2b5d412a9 100644
--- a/examples/stm32f7/build.rs
+++ b/examples/stm32f7/build.rs
@@ -1,9 +1,8 @@
1//! adapted from https://github.com/stm32-rs/stm32f7xx-hal/blob/master/build.rs 1//! adapted from https://github.com/stm32-rs/stm32f7xx-hal/blob/master/build.rs
2use std::env;
3use std::fs::File; 2use std::fs::File;
4use std::io::prelude::*; 3use std::io::prelude::*;
5use std::io::{self};
6use std::path::PathBuf; 4use std::path::PathBuf;
5use std::{env, io};
7 6
8#[derive(Debug)] 7#[derive(Debug)]
9enum Error { 8enum Error {
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/can.rs b/examples/stm32f7/src/bin/can.rs
new file mode 100644
index 000000000..1b5b377ea
--- /dev/null
+++ b/examples/stm32f7/src/bin/can.rs
@@ -0,0 +1,66 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts;
8use embassy_stm32::can::bxcan::filter::Mask32;
9use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId};
10use embassy_stm32::can::{
11 Can, CanTx, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler,
12};
13use embassy_stm32::gpio::{Input, Pull};
14use embassy_stm32::peripherals::CAN3;
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 CAN3_RX0 => Rx0InterruptHandler<CAN3>;
19 CAN3_RX1 => Rx1InterruptHandler<CAN3>;
20 CAN3_SCE => SceInterruptHandler<CAN3>;
21 CAN3_TX => TxInterruptHandler<CAN3>;
22});
23
24#[embassy_executor::task]
25pub async fn send_can_message(tx: &'static mut CanTx<'static, 'static, CAN3>) {
26 loop {
27 let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), [0]);
28 tx.write(&frame).await;
29 embassy_time::Timer::after(embassy_time::Duration::from_secs(1)).await;
30 }
31}
32
33#[embassy_executor::main]
34async fn main(spawner: Spawner) {
35 info!("Hello World!");
36
37 let mut p = embassy_stm32::init(Default::default());
38
39 // The next two lines are a workaround for testing without transceiver.
40 // To synchronise to the bus the RX input needs to see a high level.
41 // Use `mem::forget()` to release the borrow on the pin but keep the
42 // pull-up resistor enabled.
43 let rx_pin = Input::new(&mut p.PA15, Pull::Up);
44 core::mem::forget(rx_pin);
45
46 let can: &'static mut Can<'static, CAN3> = static_cell::make_static!(Can::new(p.CAN3, p.PA8, p.PA15, Irqs));
47 can.as_mut()
48 .modify_filters()
49 .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
50
51 can.as_mut()
52 .modify_config()
53 .set_bit_timing(0x001c0001) // http://www.bittiming.can-wiki.info/
54 .set_loopback(true)
55 .enable();
56
57 let (tx, mut rx) = can.split();
58
59 let tx: &'static mut CanTx<'static, 'static, CAN3> = static_cell::make_static!(tx);
60 spawner.spawn(send_can_message(tx)).unwrap();
61
62 loop {
63 let frame = rx.read().await.unwrap();
64 println!("Received: {:?}", frame);
65 }
66}
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs
index 5202edf62..c6b2ba45c 100644
--- a/examples/stm32f7/src/bin/eth.rs
+++ b/examples/stm32f7/src/bin/eth.rs
@@ -7,26 +7,21 @@ 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;
14use embassy_stm32::{interrupt, Config}; 14use embassy_stm32::{bind_interrupts, eth, Config};
15use embassy_time::{Duration, Timer}; 15use embassy_time::{Duration, Timer};
16use embedded_io::asynch::Write; 16use embedded_io::asynch::Write;
17use rand_core::RngCore; 17use rand_core::RngCore;
18use static_cell::StaticCell; 18use static_cell::make_static;
19use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
20bind_interrupts!(struct Irqs {
21 ETH => eth::InterruptHandler;
22});
20 23
21macro_rules! singleton { 24type Device = Ethernet<'static, ETH, GenericSMI>;
22 ($val:expr) => {{
23 type T = impl Sized;
24 static STATIC_CELL: StaticCell<T> = StaticCell::new();
25 STATIC_CELL.init_with(move || $val)
26 }};
27}
28
29type Device = Ethernet<'static, ETH, GenericSMI, 4, 4>;
30 25
31#[embassy_executor::task] 26#[embassy_executor::task]
32async fn net_task(stack: &'static Stack<Device>) -> ! { 27async fn net_task(stack: &'static Stack<Device>) -> ! {
@@ -47,41 +42,38 @@ async fn main(spawner: Spawner) -> ! {
47 rng.fill_bytes(&mut seed); 42 rng.fill_bytes(&mut seed);
48 let seed = u64::from_le_bytes(seed); 43 let seed = u64::from_le_bytes(seed);
49 44
50 let eth_int = interrupt::take!(ETH);
51 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 45 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
52 46
53 let device = unsafe { 47 let device = Ethernet::new(
54 Ethernet::new( 48 make_static!(PacketQueue::<16, 16>::new()),
55 singleton!(State::new()), 49 p.ETH,
56 p.ETH, 50 Irqs,
57 eth_int, 51 p.PA1,
58 p.PA1, 52 p.PA2,
59 p.PA2, 53 p.PC1,
60 p.PC1, 54 p.PA7,
61 p.PA7, 55 p.PC4,
62 p.PC4, 56 p.PC5,
63 p.PC5, 57 p.PG13,
64 p.PG13, 58 p.PB13,
65 p.PB13, 59 p.PG11,
66 p.PG11, 60 GenericSMI::new(),
67 GenericSMI, 61 mac_addr,
68 mac_addr, 62 0,
69 0, 63 );
70 ) 64
71 }; 65 let config = embassy_net::Config::dhcpv4(Default::default());
72 66 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
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), 67 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
76 // dns_servers: Vec::new(), 68 // dns_servers: Vec::new(),
77 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 69 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
78 //}); 70 //});
79 71
80 // Init network stack 72 // Init network stack
81 let stack = &*singleton!(Stack::new( 73 let stack = &*make_static!(Stack::new(
82 device, 74 device,
83 config, 75 config,
84 singleton!(StackResources::<1, 2, 8>::new()), 76 make_static!(StackResources::<2>::new()),
85 seed 77 seed
86 )); 78 ));
87 79
@@ -91,13 +83,13 @@ async fn main(spawner: Spawner) -> ! {
91 info!("Network task initialized"); 83 info!("Network task initialized");
92 84
93 // Then we can use it! 85 // Then we can use it!
94 let mut rx_buffer = [0; 1024]; 86 let mut rx_buffer = [0; 4096];
95 let mut tx_buffer = [0; 1024]; 87 let mut tx_buffer = [0; 4096];
96 88
97 loop { 89 loop {
98 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); 90 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer);
99 91
100 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10))); 92 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
101 93
102 let remote_endpoint = (Ipv4Address::new(10, 42, 0, 1), 8000); 94 let remote_endpoint = (Ipv4Address::new(10, 42, 0, 1), 8000);
103 info!("connecting..."); 95 info!("connecting...");
@@ -107,11 +99,12 @@ async fn main(spawner: Spawner) -> ! {
107 continue; 99 continue;
108 } 100 }
109 info!("connected!"); 101 info!("connected!");
102 let buf = [0; 1024];
110 loop { 103 loop {
111 let r = socket.write_all(b"Hello\n").await; 104 let r = socket.write_all(&buf).await;
112 if let Err(e) = r { 105 if let Err(e) = r {
113 info!("write error: {:?}", e); 106 info!("write error: {:?}", e);
114 return; 107 continue;
115 } 108 }
116 Timer::after(Duration::from_secs(1)).await; 109 Timer::after(Duration::from_secs(1)).await;
117 } 110 }
diff --git a/examples/stm32f7/src/bin/flash.rs b/examples/stm32f7/src/bin/flash.rs
index c10781d0c..35d3059be 100644
--- a/examples/stm32f7/src/bin/flash.rs
+++ b/examples/stm32f7/src/bin/flash.rs
@@ -6,7 +6,6 @@ use defmt::{info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::flash::Flash; 7use embassy_stm32::flash::Flash;
8use embassy_time::{Duration, Timer}; 8use embassy_time::{Duration, Timer};
9use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
10use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
11 10
12#[embassy_executor::main] 11#[embassy_executor::main]
@@ -14,28 +13,28 @@ async fn main(_spawner: Spawner) {
14 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
15 info!("Hello Flash!"); 14 info!("Hello Flash!");
16 15
17 const ADDR: u32 = 0x8_0000; 16 const ADDR: u32 = 0x8_0000; // This is the offset into the third region, the absolute address is 4x32K + 128K + 0x8_0000.
18 17
19 // wait a bit before accessing the flash 18 // wait a bit before accessing the flash
20 Timer::after(Duration::from_millis(300)).await; 19 Timer::after(Duration::from_millis(300)).await;
21 20
22 let mut f = Flash::unlock(p.FLASH); 21 let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region3;
23 22
24 info!("Reading..."); 23 info!("Reading...");
25 let mut buf = [0u8; 32]; 24 let mut buf = [0u8; 32];
26 unwrap!(f.read(ADDR, &mut buf)); 25 unwrap!(f.blocking_read(ADDR, &mut buf));
27 info!("Read: {=[u8]:x}", buf); 26 info!("Read: {=[u8]:x}", buf);
28 27
29 info!("Erasing..."); 28 info!("Erasing...");
30 unwrap!(f.erase(ADDR, ADDR + 256 * 1024)); 29 unwrap!(f.blocking_erase(ADDR, ADDR + 256 * 1024));
31 30
32 info!("Reading..."); 31 info!("Reading...");
33 let mut buf = [0u8; 32]; 32 let mut buf = [0u8; 32];
34 unwrap!(f.read(ADDR, &mut buf)); 33 unwrap!(f.blocking_read(ADDR, &mut buf));
35 info!("Read after erase: {=[u8]:x}", buf); 34 info!("Read after erase: {=[u8]:x}", buf);
36 35
37 info!("Writing..."); 36 info!("Writing...");
38 unwrap!(f.write( 37 unwrap!(f.blocking_write(
39 ADDR, 38 ADDR,
40 &[ 39 &[
41 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 40 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
@@ -45,7 +44,7 @@ async fn main(_spawner: Spawner) {
45 44
46 info!("Reading..."); 45 info!("Reading...");
47 let mut buf = [0u8; 32]; 46 let mut buf = [0u8; 32];
48 unwrap!(f.read(ADDR, &mut buf)); 47 unwrap!(f.blocking_read(ADDR, &mut buf));
49 info!("Read: {=[u8]:x}", buf); 48 info!("Read: {=[u8]:x}", buf);
50 assert_eq!( 49 assert_eq!(
51 &buf[..], 50 &buf[..],
diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs
index 3bf427eca..9d43892a0 100644
--- a/examples/stm32f7/src/bin/sdmmc.rs
+++ b/examples/stm32f7/src/bin/sdmmc.rs
@@ -6,22 +6,25 @@ use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::sdmmc::Sdmmc; 7use embassy_stm32::sdmmc::Sdmmc;
8use embassy_stm32::time::mhz; 8use embassy_stm32::time::mhz;
9use embassy_stm32::{interrupt, Config}; 9use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12bind_interrupts!(struct Irqs {
13 SDMMC1 => sdmmc::InterruptHandler<peripherals::SDMMC1>;
14});
15
12#[embassy_executor::main] 16#[embassy_executor::main]
13async fn main(_spawner: Spawner) -> ! { 17async fn main(_spawner: Spawner) {
14 let mut config = Config::default(); 18 let mut config = Config::default();
15 config.rcc.sys_ck = Some(mhz(200)); 19 config.rcc.sys_ck = Some(mhz(200));
20 config.rcc.pll48 = true;
16 let p = embassy_stm32::init(config); 21 let p = embassy_stm32::init(config);
17 22
18 info!("Hello World!"); 23 info!("Hello World!");
19 24
20 let irq = interrupt::take!(SDMMC1);
21
22 let mut sdmmc = Sdmmc::new_4bit( 25 let mut sdmmc = Sdmmc::new_4bit(
23 p.SDMMC1, 26 p.SDMMC1,
24 irq, 27 Irqs,
25 p.DMA2_CH3, 28 p.DMA2_CH3,
26 p.PC12, 29 p.PC12,
27 p.PD2, 30 p.PD2,
@@ -40,6 +43,4 @@ async fn main(_spawner: Spawner) -> ! {
40 let card = unwrap!(sdmmc.card()); 43 let card = unwrap!(sdmmc.card());
41 44
42 info!("Card: {:#?}", Debug2Format(card)); 45 info!("Card: {:#?}", Debug2Format(card));
43
44 loop {}
45} 46}
diff --git a/examples/stm32f7/src/bin/usart_dma.rs b/examples/stm32f7/src/bin/usart_dma.rs
index 07270479c..4700287a7 100644
--- a/examples/stm32f7/src/bin/usart_dma.rs
+++ b/examples/stm32f7/src/bin/usart_dma.rs
@@ -8,14 +8,19 @@ use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma; 9use embassy_stm32::dma::NoDma;
10use embassy_stm32::usart::{Config, Uart}; 10use embassy_stm32::usart::{Config, Uart};
11use embassy_stm32::{bind_interrupts, peripherals, usart};
11use heapless::String; 12use heapless::String;
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
13 14
15bind_interrupts!(struct Irqs {
16 UART7 => usart::InterruptHandler<peripherals::UART7>;
17});
18
14#[embassy_executor::main] 19#[embassy_executor::main]
15async fn main(_spawner: Spawner) { 20async fn main(_spawner: Spawner) {
16 let p = embassy_stm32::init(Default::default()); 21 let p = embassy_stm32::init(Default::default());
17 let config = Config::default(); 22 let config = Config::default();
18 let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, p.DMA1_CH1, NoDma, config); 23 let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, NoDma, config);
19 24
20 for n in 0u32.. { 25 for n in 0u32.. {
21 let mut s: String<128> = String::new(); 26 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..a2c76178b
--- /dev/null
+++ b/examples/stm32f7/src/bin/usb_serial.rs
@@ -0,0 +1,111 @@
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::{bind_interrupts, peripherals, usb_otg, 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
16bind_interrupts!(struct Irqs {
17 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
18});
19
20#[embassy_executor::main]
21async fn main(_spawner: Spawner) {
22 info!("Hello World!");
23
24 let mut config = Config::default();
25 config.rcc.hse = Some(mhz(8));
26 config.rcc.pll48 = true;
27 config.rcc.sys_ck = Some(mhz(200));
28
29 let p = embassy_stm32::init(config);
30
31 // Create the driver, from the HAL.
32 let mut ep_out_buffer = [0u8; 256];
33 let mut config = embassy_stm32::usb_otg::Config::default();
34 config.vbus_detection = true;
35 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
36
37 // Create embassy-usb Config
38 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
39 config.manufacturer = Some("Embassy");
40 config.product = Some("USB-serial example");
41 config.serial_number = Some("12345678");
42
43 // Required for windows compatibility.
44 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
45 config.device_class = 0xEF;
46 config.device_sub_class = 0x02;
47 config.device_protocol = 0x01;
48 config.composite_with_iads = true;
49
50 // Create embassy-usb DeviceBuilder using the driver and config.
51 // It needs some buffers for building the descriptors.
52 let mut device_descriptor = [0; 256];
53 let mut config_descriptor = [0; 256];
54 let mut bos_descriptor = [0; 256];
55 let mut control_buf = [0; 64];
56
57 let mut state = State::new();
58
59 let mut builder = Builder::new(
60 driver,
61 config,
62 &mut device_descriptor,
63 &mut config_descriptor,
64 &mut bos_descriptor,
65 &mut control_buf,
66 );
67
68 // Create classes on the builder.
69 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
70
71 // Build the builder.
72 let mut usb = builder.build();
73
74 // Run the USB device.
75 let usb_fut = usb.run();
76
77 // Do stuff with the class!
78 let echo_fut = async {
79 loop {
80 class.wait_connection().await;
81 info!("Connected");
82 let _ = echo(&mut class).await;
83 info!("Disconnected");
84 }
85 };
86
87 // Run everything concurrently.
88 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
89 join(usb_fut, echo_fut).await;
90}
91
92struct Disconnected {}
93
94impl From<EndpointError> for Disconnected {
95 fn from(val: EndpointError) -> Self {
96 match val {
97 EndpointError::BufferOverflow => panic!("Buffer overflow"),
98 EndpointError::Disabled => Disconnected {},
99 }
100 }
101}
102
103async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
104 let mut buf = [0; 64];
105 loop {
106 let n = class.read_packet(&mut buf).await?;
107 let data = &buf[..n];
108 info!("data: {:x}", data);
109 class.write_packet(data).await?;
110 }
111}
diff --git a/examples/stm32g0/.cargo/config.toml b/examples/stm32g0/.cargo/config.toml
index 4f776d68f..35cca5412 100644
--- a/examples/stm32g0/.cargo/config.toml
+++ b/examples/stm32g0/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32G071C8Rx with your chip as listed in `probe-run --list-chips` 2# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32G071RBTx" 3runner = "probe-rs run --chip STM32G071RBTx"
4 4
5[build] 5[build]
6target = "thumbv6m-none-eabi" 6target = "thumbv6m-none-eabi"
diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml
index 30f2b86f8..c88282d91 100644
--- a/examples/stm32g0/Cargo.toml
+++ b/examples/stm32g0/Cargo.toml
@@ -2,17 +2,18 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32g0-examples" 3name = "embassy-stm32g0-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
10embassy-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"] }
11 12
12defmt = "0.3" 13defmt = "0.3"
13defmt-rtt = "0.3" 14defmt-rtt = "0.4"
14 15
15cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 16cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
16cortex-m-rt = "0.7.0" 17cortex-m-rt = "0.7.0"
17embedded-hal = "0.2.6" 18embedded-hal = "0.2.6"
18panic-probe = { version = "0.3", features = ["print-defmt"] } 19panic-probe = { version = "0.3", features = ["print-defmt"] }
diff --git a/examples/stm32g0/src/bin/spi_neopixel.rs b/examples/stm32g0/src/bin/spi_neopixel.rs
new file mode 100644
index 000000000..81fdd15cb
--- /dev/null
+++ b/examples/stm32g0/src/bin/spi_neopixel.rs
@@ -0,0 +1,101 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::dma::word::U5;
8use embassy_stm32::dma::NoDma;
9use embassy_stm32::spi::{Config, Spi};
10use embassy_stm32::time::Hertz;
11use embassy_time::{Duration, Timer};
12use {defmt_rtt as _, panic_probe as _};
13
14const NR_PIXELS: usize = 15;
15const BITS_PER_PIXEL: usize = 24; // 24 for rgb, 32 for rgbw
16const TOTAL_BITS: usize = NR_PIXELS * BITS_PER_PIXEL;
17
18struct RGB {
19 r: u8,
20 g: u8,
21 b: u8,
22}
23impl Default for RGB {
24 fn default() -> RGB {
25 RGB { r: 0, g: 0, b: 0 }
26 }
27}
28pub struct Ws2812 {
29 // Note that the U5 type controls the selection of 5 bits to output
30 bitbuffer: [U5; TOTAL_BITS],
31}
32
33impl Ws2812 {
34 pub fn new() -> Ws2812 {
35 Ws2812 {
36 bitbuffer: [U5(0); TOTAL_BITS],
37 }
38 }
39 fn len(&self) -> usize {
40 return NR_PIXELS;
41 }
42 fn set(&mut self, idx: usize, rgb: RGB) {
43 self.render_color(idx, 0, rgb.g);
44 self.render_color(idx, 8, rgb.r);
45 self.render_color(idx, 16, rgb.b);
46 }
47 // transform one color byte into an array of 8 byte. Each byte in the array does represent 1 neopixel bit pattern
48 fn render_color(&mut self, pixel_idx: usize, offset: usize, color: u8) {
49 let mut bits = color as usize;
50 let mut idx = pixel_idx * BITS_PER_PIXEL + offset;
51
52 // render one bit in one spi byte. High time first, then the low time
53 // clock should be 4 Mhz, 5 bits, each bit is 0.25 us.
54 // a one bit is send as a pulse of 0.75 high -- 0.50 low
55 // a zero bit is send as a pulse of 0.50 high -- 0.75 low
56 // clock frequency for the neopixel is exact 800 khz
57 // note that the mosi output should have a resistor to ground of 10k,
58 // to assure that between the bursts the line is low
59 for _i in 0..8 {
60 if idx >= TOTAL_BITS {
61 return;
62 }
63 let pattern = match bits & 0x80 {
64 0x80 => 0b0000_1110,
65 _ => 0b000_1100,
66 };
67 bits = bits << 1;
68 self.bitbuffer[idx] = U5(pattern);
69 idx += 1;
70 }
71 }
72}
73
74#[embassy_executor::main]
75async fn main(_spawner: Spawner) {
76 let p = embassy_stm32::init(Default::default());
77 info!("Start test using spi as neopixel driver");
78
79 let mut spi = Spi::new_txonly_nosck(p.SPI1, p.PB5, p.DMA1_CH3, NoDma, Hertz(4_000_000), Config::default());
80
81 let mut neopixels = Ws2812::new();
82
83 loop {
84 let mut cnt: usize = 0;
85 for _i in 0..10 {
86 for idx in 0..neopixels.len() {
87 let color = match (cnt + idx) % 3 {
88 0 => RGB { r: 0x21, g: 0, b: 0 },
89 1 => RGB { r: 0, g: 0x31, b: 0 },
90 _ => RGB { r: 0, g: 0, b: 0x41 },
91 };
92 neopixels.set(idx, color);
93 }
94 cnt += 1;
95 // start sending the neopixel bit patters over spi to the neopixel string
96 spi.write(&neopixels.bitbuffer).await.ok();
97 Timer::after(Duration::from_millis(500)).await;
98 }
99 Timer::after(Duration::from_millis(1000)).await;
100 }
101}
diff --git a/examples/stm32g4/.cargo/config.toml b/examples/stm32g4/.cargo/config.toml
index 99feae119..d28ad069e 100644
--- a/examples/stm32g4/.cargo/config.toml
+++ b/examples/stm32g4/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32G071C8Rx with your chip as listed in `probe-run --list-chips` 2# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32G484VETx" 3runner = "probe-rs run --chip STM32G484VETx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabi" 6target = "thumbv7em-none-eabi"
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index f81df0b70..18bd03c39 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -2,16 +2,18 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32g4-examples" 3name = "embassy-stm32g4-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
10embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] }
11embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } 12embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
12 14
13defmt = "0.3" 15defmt = "0.3"
14defmt-rtt = "0.3" 16defmt-rtt = "0.4"
15 17
16cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 18cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
17cortex-m-rt = "0.7.0" 19cortex-m-rt = "0.7.0"
diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs
new file mode 100644
index 000000000..ef7d4800c
--- /dev/null
+++ b/examples/stm32g4/src/bin/pll.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_stm32::rcc::{ClockSrc, Pll, PllM, PllN, PllR, PllSrc};
8use embassy_stm32::Config;
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let mut config = Config::default();
15
16 config.rcc.pll = Some(Pll {
17 source: PllSrc::HSI16,
18 prediv_m: PllM::Div4,
19 mul_n: PllN::Mul85,
20 div_p: None,
21 div_q: None,
22 // Main system clock at 170 MHz
23 div_r: Some(PllR::Div2),
24 });
25
26 config.rcc.mux = ClockSrc::PLL;
27
28 let _p = embassy_stm32::init(config);
29 info!("Hello World!");
30
31 loop {
32 Timer::after(Duration::from_millis(1000)).await;
33 info!("1s elapsed");
34 }
35}
diff --git a/examples/stm32g4/src/bin/pwm.rs b/examples/stm32g4/src/bin/pwm.rs
index 017e89e41..8f7842ed7 100644
--- a/examples/stm32g4/src/bin/pwm.rs
+++ b/examples/stm32g4/src/bin/pwm.rs
@@ -15,8 +15,8 @@ async fn main(_spawner: Spawner) {
15 let p = embassy_stm32::init(Default::default()); 15 let p = embassy_stm32::init(Default::default());
16 info!("Hello World!"); 16 info!("Hello World!");
17 17
18 let ch1 = PwmPin::new_ch1(p.PA5); 18 let ch1 = PwmPin::new_ch1(p.PC0);
19 let mut pwm = SimplePwm::new(p.TIM2, Some(ch1), None, None, None, khz(10)); 19 let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(10));
20 let max = pwm.get_max_duty(); 20 let max = pwm.get_max_duty();
21 pwm.enable(Channel::Ch1); 21 pwm.enable(Channel::Ch1);
22 22
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
new file mode 100644
index 000000000..77cfa67d3
--- /dev/null
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -0,0 +1,120 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{panic, *};
6use embassy_executor::Spawner;
7use embassy_stm32::rcc::{Clock48MhzSrc, ClockSrc, CrsConfig, CrsSyncSource, Pll, PllM, PllN, PllQ, PllR, PllSrc};
8use embassy_stm32::time::Hertz;
9use embassy_stm32::usb::{self, Driver, Instance};
10use embassy_stm32::{bind_interrupts, peripherals, Config};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError;
13use embassy_usb::Builder;
14use futures::future::join;
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 USB_LP => usb::InterruptHandler<peripherals::USB>;
19});
20
21#[embassy_executor::main]
22async fn main(_spawner: Spawner) {
23 let mut config = Config::default();
24
25 // Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE.
26 const USE_HSI48: bool = true;
27
28 let pllq_div = if USE_HSI48 { None } else { Some(PllQ::Div6) };
29
30 config.rcc.pll = Some(Pll {
31 source: PllSrc::HSE(Hertz(8_000_000)),
32 prediv_m: PllM::Div2,
33 mul_n: PllN::Mul72,
34 div_p: None,
35 div_q: pllq_div,
36 // Main system clock at 144 MHz
37 div_r: Some(PllR::Div2),
38 });
39
40 config.rcc.mux = ClockSrc::PLL;
41
42 if USE_HSI48 {
43 // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator.
44 config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::Hsi48(Some(CrsConfig {
45 sync_src: CrsSyncSource::Usb,
46 })));
47 } else {
48 config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::PllQ);
49 }
50
51 let p = embassy_stm32::init(config);
52
53 info!("Hello World!");
54
55 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
56
57 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
58 config.manufacturer = Some("Embassy");
59 config.product = Some("USB-Serial Example");
60 config.serial_number = Some("123456");
61
62 config.device_class = 0xEF;
63 config.device_sub_class = 0x02;
64 config.device_protocol = 0x01;
65 config.composite_with_iads = true;
66
67 let mut device_descriptor = [0; 256];
68 let mut config_descriptor = [0; 256];
69 let mut bos_descriptor = [0; 256];
70 let mut control_buf = [0; 64];
71
72 let mut state = State::new();
73
74 let mut builder = Builder::new(
75 driver,
76 config,
77 &mut device_descriptor,
78 &mut config_descriptor,
79 &mut bos_descriptor,
80 &mut control_buf,
81 );
82
83 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
84
85 let mut usb = builder.build();
86
87 let usb_fut = usb.run();
88
89 let echo_fut = async {
90 loop {
91 class.wait_connection().await;
92 info!("Connected");
93 let _ = echo(&mut class).await;
94 info!("Disconnected");
95 }
96 };
97
98 join(usb_fut, echo_fut).await;
99}
100
101struct Disconnected {}
102
103impl From<EndpointError> for Disconnected {
104 fn from(val: EndpointError) -> Self {
105 match val {
106 EndpointError::BufferOverflow => panic!("Buffer overflow"),
107 EndpointError::Disabled => Disconnected {},
108 }
109 }
110}
111
112async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
113 let mut buf = [0; 64];
114 loop {
115 let n = class.read_packet(&mut buf).await?;
116 let data = &buf[..n];
117 info!("data: {:x}", data);
118 class.write_packet(data).await?;
119 }
120}
diff --git a/examples/stm32h5/.cargo/config.toml b/examples/stm32h5/.cargo/config.toml
new file mode 100644
index 000000000..478146142
--- /dev/null
+++ b/examples/stm32h5/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.thumbv8m.main-none-eabihf]
2runner = 'probe-rs run --chip STM32H563ZITx'
3
4[build]
5target = "thumbv8m.main-none-eabihf"
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml
new file mode 100644
index 000000000..227bc28b4
--- /dev/null
+++ b/examples/stm32h5/Cargo.toml
@@ -0,0 +1,71 @@
1[package]
2edition = "2021"
3name = "embassy-stm32h5-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.1.2", 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", "stm32h563zi", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] }
12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] }
13embedded-io = { version = "0.4.0", features = ["async"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
15
16defmt = "0.3"
17defmt-rtt = "0.4"
18
19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6"
22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" }
23embedded-hal-async = { version = "=0.2.0-alpha.2" }
24embedded-nal-async = "0.4.0"
25panic-probe = { version = "0.3", features = ["print-defmt"] }
26futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
27heapless = { version = "0.7.5", default-features = false }
28rand_core = "0.6.3"
29critical-section = "1.1"
30micromath = "2.0.0"
31stm32-fmc = "0.2.4"
32embedded-storage = "0.3.0"
33static_cell = { version = "1.1", features = ["nightly"]}
34
35# cargo build/run
36[profile.dev]
37codegen-units = 1
38debug = 2
39debug-assertions = true # <-
40incremental = false
41opt-level = 3 # <-
42overflow-checks = true # <-
43
44# cargo test
45[profile.test]
46codegen-units = 1
47debug = 2
48debug-assertions = true # <-
49incremental = false
50opt-level = 3 # <-
51overflow-checks = true # <-
52
53# cargo build/run --release
54[profile.release]
55codegen-units = 1
56debug = 2
57debug-assertions = false # <-
58incremental = false
59lto = 'fat'
60opt-level = 3 # <-
61overflow-checks = false # <-
62
63# cargo test --release
64[profile.bench]
65codegen-units = 1
66debug = 2
67debug-assertions = false # <-
68incremental = false
69lto = 'fat'
70opt-level = 3 # <-
71overflow-checks = false # <-
diff --git a/examples/stm32h5/build.rs b/examples/stm32h5/build.rs
new file mode 100644
index 000000000..8cd32d7ed
--- /dev/null
+++ b/examples/stm32h5/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/stm32h5/memory.x b/examples/stm32h5/memory.x
new file mode 100644
index 000000000..456061509
--- /dev/null
+++ b/examples/stm32h5/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x08000000, LENGTH = 0x200000
4 RAM : ORIGIN = 0x20000000, LENGTH = 0x50000
5}
diff --git a/examples/stm32h5/src/bin/blinky.rs b/examples/stm32h5/src/bin/blinky.rs
new file mode 100644
index 000000000..f9bf90d2e
--- /dev/null
+++ b/examples/stm32h5/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.PB0, Level::High, Speed::Low);
17
18 loop {
19 info!("high");
20 led.set_high();
21 Timer::after(Duration::from_millis(500)).await;
22
23 info!("low");
24 led.set_low();
25 Timer::after(Duration::from_millis(500)).await;
26 }
27}
diff --git a/examples/stm32h5/src/bin/button_exti.rs b/examples/stm32h5/src/bin/button_exti.rs
new file mode 100644
index 000000000..dfe587d41
--- /dev/null
+++ b/examples/stm32h5/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::Down);
17 let mut button = ExtiInput::new(button, p.EXTI13);
18
19 info!("Press the USER button...");
20
21 loop {
22 button.wait_for_rising_edge().await;
23 info!("Pressed!");
24 button.wait_for_falling_edge().await;
25 info!("Released!");
26 }
27}
diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs
new file mode 100644
index 000000000..0bff85ed8
--- /dev/null
+++ b/examples/stm32h5/src/bin/eth.rs
@@ -0,0 +1,131 @@
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::{Ipv4Address, Stack, StackResources};
9use embassy_stm32::eth::generic_smi::GenericSMI;
10use embassy_stm32::eth::{Ethernet, PacketQueue};
11use embassy_stm32::peripherals::ETH;
12use embassy_stm32::rcc::{AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllSource, Sysclk, VoltageScale};
13use embassy_stm32::rng::Rng;
14use embassy_stm32::time::Hertz;
15use embassy_stm32::{bind_interrupts, eth, Config};
16use embassy_time::{Duration, Timer};
17use embedded_io::asynch::Write;
18use rand_core::RngCore;
19use static_cell::make_static;
20use {defmt_rtt as _, panic_probe as _};
21bind_interrupts!(struct Irqs {
22 ETH => eth::InterruptHandler;
23});
24
25type Device = Ethernet<'static, ETH, GenericSMI>;
26
27#[embassy_executor::task]
28async fn net_task(stack: &'static Stack<Device>) -> ! {
29 stack.run().await
30}
31
32#[embassy_executor::main]
33async fn main(spawner: Spawner) -> ! {
34 let mut config = Config::default();
35 config.rcc.hsi = None;
36 config.rcc.hsi48 = true; // needed for rng
37 config.rcc.hse = Some(Hse {
38 freq: Hertz(8_000_000),
39 mode: HseMode::BypassDigital,
40 });
41 config.rcc.pll1 = Some(Pll {
42 source: PllSource::Hse,
43 prediv: 2,
44 mul: 125,
45 divp: Some(2),
46 divq: Some(2),
47 divr: None,
48 });
49 config.rcc.ahb_pre = AHBPrescaler::NotDivided;
50 config.rcc.apb1_pre = APBPrescaler::NotDivided;
51 config.rcc.apb2_pre = APBPrescaler::NotDivided;
52 config.rcc.apb3_pre = APBPrescaler::NotDivided;
53 config.rcc.sys = Sysclk::Pll1P;
54 config.rcc.voltage_scale = VoltageScale::Scale0;
55 let p = embassy_stm32::init(config);
56 info!("Hello World!");
57
58 // Generate random seed.
59 let mut rng = Rng::new(p.RNG);
60 let mut seed = [0; 8];
61 rng.fill_bytes(&mut seed);
62 let seed = u64::from_le_bytes(seed);
63
64 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
65
66 let device = Ethernet::new(
67 make_static!(PacketQueue::<4, 4>::new()),
68 p.ETH,
69 Irqs,
70 p.PA1,
71 p.PA2,
72 p.PC1,
73 p.PA7,
74 p.PC4,
75 p.PC5,
76 p.PG13,
77 p.PB15,
78 p.PG11,
79 GenericSMI::new(),
80 mac_addr,
81 0,
82 );
83
84 let config = embassy_net::Config::dhcpv4(Default::default());
85 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
86 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
87 // dns_servers: Vec::new(),
88 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
89 //});
90
91 // Init network stack
92 let stack = &*make_static!(Stack::new(
93 device,
94 config,
95 make_static!(StackResources::<2>::new()),
96 seed
97 ));
98
99 // Launch network task
100 unwrap!(spawner.spawn(net_task(&stack)));
101
102 info!("Network task initialized");
103
104 // Then we can use it!
105 let mut rx_buffer = [0; 1024];
106 let mut tx_buffer = [0; 1024];
107
108 loop {
109 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer);
110
111 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
112
113 let remote_endpoint = (Ipv4Address::new(10, 42, 0, 1), 8000);
114 info!("connecting...");
115 let r = socket.connect(remote_endpoint).await;
116 if let Err(e) = r {
117 info!("connect error: {:?}", e);
118 Timer::after(Duration::from_secs(3)).await;
119 continue;
120 }
121 info!("connected!");
122 loop {
123 let r = socket.write_all(b"Hello\n").await;
124 if let Err(e) = r {
125 info!("write error: {:?}", e);
126 continue;
127 }
128 Timer::after(Duration::from_secs(1)).await;
129 }
130 }
131}
diff --git a/examples/stm32h5/src/bin/i2c.rs b/examples/stm32h5/src/bin/i2c.rs
new file mode 100644
index 000000000..8b6fe71ae
--- /dev/null
+++ b/examples/stm32h5/src/bin/i2c.rs
@@ -0,0 +1,47 @@
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::time::Hertz;
9use embassy_stm32::{bind_interrupts, i2c, peripherals};
10use embassy_time::Duration;
11use {defmt_rtt as _, panic_probe as _};
12
13const ADDRESS: u8 = 0x5F;
14const WHOAMI: u8 = 0x0F;
15
16bind_interrupts!(struct Irqs {
17 I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>;
18});
19
20#[embassy_executor::main]
21async fn main(_spawner: Spawner) {
22 info!("Hello world!");
23 let p = embassy_stm32::init(Default::default());
24
25 let mut i2c = I2c::new(
26 p.I2C2,
27 p.PB10,
28 p.PB11,
29 Irqs,
30 p.GPDMA1_CH4,
31 p.GPDMA1_CH5,
32 Hertz(100_000),
33 Default::default(),
34 );
35
36 // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long.
37 // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay.
38 let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000));
39
40 let mut data = [0u8; 1];
41
42 match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) {
43 Ok(()) => info!("Whoami: {}", data[0]),
44 Err(Error::Timeout) => error!("Operation timed out"),
45 Err(e) => error!("I2c Error: {:?}", e),
46 }
47}
diff --git a/examples/stm32h5/src/bin/rng.rs b/examples/stm32h5/src/bin/rng.rs
new file mode 100644
index 000000000..af9be0b62
--- /dev/null
+++ b/examples/stm32h5/src/bin/rng.rs
@@ -0,0 +1,20 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::rng::Rng;
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!");
14
15 let mut rng = Rng::new(p.RNG);
16
17 let mut buf = [0u8; 16];
18 unwrap!(rng.async_fill_bytes(&mut buf).await);
19 info!("random bytes: {:02x}", buf);
20}
diff --git a/examples/stm32h5/src/bin/usart.rs b/examples/stm32h5/src/bin/usart.rs
new file mode 100644
index 000000000..0abb94abb
--- /dev/null
+++ b/examples/stm32h5/src/bin/usart.rs
@@ -0,0 +1,46 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use cortex_m_rt::entry;
6use defmt::*;
7use embassy_executor::Executor;
8use embassy_stm32::dma::NoDma;
9use embassy_stm32::usart::{Config, Uart};
10use embassy_stm32::{bind_interrupts, peripherals, usart};
11use static_cell::StaticCell;
12use {defmt_rtt as _, panic_probe as _};
13
14bind_interrupts!(struct Irqs {
15 UART7 => usart::InterruptHandler<peripherals::UART7>;
16});
17
18#[embassy_executor::task]
19async fn main_task() {
20 let p = embassy_stm32::init(Default::default());
21
22 let config = Config::default();
23 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config);
24
25 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
26 info!("wrote Hello, starting echo");
27
28 let mut buf = [0u8; 1];
29 loop {
30 unwrap!(usart.blocking_read(&mut buf));
31 unwrap!(usart.blocking_write(&buf));
32 }
33}
34
35static EXECUTOR: StaticCell<Executor> = StaticCell::new();
36
37#[entry]
38fn main() -> ! {
39 info!("Hello World!");
40
41 let executor = EXECUTOR.init(Executor::new());
42
43 executor.run(|spawner| {
44 unwrap!(spawner.spawn(main_task()));
45 })
46}
diff --git a/examples/stm32h5/src/bin/usart_dma.rs b/examples/stm32h5/src/bin/usart_dma.rs
new file mode 100644
index 000000000..48264f884
--- /dev/null
+++ b/examples/stm32h5/src/bin/usart_dma.rs
@@ -0,0 +1,49 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::fmt::Write;
6
7use cortex_m_rt::entry;
8use defmt::*;
9use embassy_executor::Executor;
10use embassy_stm32::dma::NoDma;
11use embassy_stm32::usart::{Config, Uart};
12use embassy_stm32::{bind_interrupts, peripherals, usart};
13use heapless::String;
14use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 UART7 => usart::InterruptHandler<peripherals::UART7>;
19});
20
21#[embassy_executor::task]
22async fn main_task() {
23 let p = embassy_stm32::init(Default::default());
24
25 let config = Config::default();
26 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, NoDma, config);
27
28 for n in 0u32.. {
29 let mut s: String<128> = String::new();
30 core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap();
31
32 usart.write(s.as_bytes()).await.ok();
33
34 info!("wrote DMA");
35 }
36}
37
38static EXECUTOR: StaticCell<Executor> = StaticCell::new();
39
40#[entry]
41fn main() -> ! {
42 info!("Hello World!");
43
44 let executor = EXECUTOR.init(Executor::new());
45
46 executor.run(|spawner| {
47 unwrap!(spawner.spawn(main_task()));
48 })
49}
diff --git a/examples/stm32h5/src/bin/usart_split.rs b/examples/stm32h5/src/bin/usart_split.rs
new file mode 100644
index 000000000..debd6f454
--- /dev/null
+++ b/examples/stm32h5/src/bin/usart_split.rs
@@ -0,0 +1,61 @@
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::peripherals::{GPDMA1_CH1, UART7};
9use embassy_stm32::usart::{Config, Uart, UartRx};
10use embassy_stm32::{bind_interrupts, peripherals, usart};
11use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
12use embassy_sync::channel::Channel;
13use {defmt_rtt as _, panic_probe as _};
14
15bind_interrupts!(struct Irqs {
16 UART7 => usart::InterruptHandler<peripherals::UART7>;
17});
18
19#[embassy_executor::task]
20async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) {
21 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
22 info!("wrote Hello, starting echo");
23
24 let mut buf = [0u8; 1];
25 loop {
26 unwrap!(usart.blocking_read(&mut buf));
27 unwrap!(usart.blocking_write(&buf));
28 }
29}
30
31static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
32
33#[embassy_executor::main]
34async fn main(spawner: Spawner) -> ! {
35 let p = embassy_stm32::init(Default::default());
36 info!("Hello World!");
37
38 let config = Config::default();
39 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config);
40 unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n"));
41
42 let (mut tx, rx) = usart.split();
43
44 unwrap!(spawner.spawn(reader(rx)));
45
46 loop {
47 let buf = CHANNEL.recv().await;
48 info!("writing...");
49 unwrap!(tx.write(&buf).await);
50 }
51}
52
53#[embassy_executor::task]
54async fn reader(mut rx: UartRx<'static, UART7, GPDMA1_CH1>) {
55 let mut buf = [0; 8];
56 loop {
57 info!("reading...");
58 unwrap!(rx.read(&mut buf).await);
59 CHANNEL.send(buf).await;
60 }
61}
diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs
new file mode 100644
index 000000000..336eed644
--- /dev/null
+++ b/examples/stm32h5/src/bin/usb_serial.rs
@@ -0,0 +1,129 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{panic, *};
6use embassy_executor::Spawner;
7use embassy_stm32::rcc::{AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllSource, Sysclk, VoltageScale};
8use embassy_stm32::time::Hertz;
9use embassy_stm32::usb::{Driver, Instance};
10use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError;
13use embassy_usb::Builder;
14use futures::future::join;
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 USB_DRD_FS => usb::InterruptHandler<peripherals::USB>;
19});
20
21#[embassy_executor::main]
22async fn main(_spawner: Spawner) {
23 let mut config = Config::default();
24 config.rcc.hsi = None;
25 config.rcc.hsi48 = true; // needed for usb
26 config.rcc.hse = Some(Hse {
27 freq: Hertz(8_000_000),
28 mode: HseMode::BypassDigital,
29 });
30 config.rcc.pll1 = Some(Pll {
31 source: PllSource::Hse,
32 prediv: 2,
33 mul: 125,
34 divp: Some(2), // 250mhz
35 divq: None,
36 divr: None,
37 });
38 config.rcc.ahb_pre = AHBPrescaler::Div2;
39 config.rcc.apb1_pre = APBPrescaler::Div4;
40 config.rcc.apb2_pre = APBPrescaler::Div2;
41 config.rcc.apb3_pre = APBPrescaler::Div4;
42 config.rcc.sys = Sysclk::Pll1P;
43 config.rcc.voltage_scale = VoltageScale::Scale0;
44 let p = embassy_stm32::init(config);
45
46 info!("Hello World!");
47
48 pac::RCC.ccipr4().write(|w| {
49 w.set_usbsel(pac::rcc::vals::Usbsel::HSI48);
50 });
51
52 // Create the driver, from the HAL.
53 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
54
55 // Create embassy-usb Config
56 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
57 config.manufacturer = Some("Embassy");
58 config.product = Some("USB-serial example");
59 config.serial_number = Some("12345678");
60
61 // Required for windows compatibility.
62 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
63 config.device_class = 0xEF;
64 config.device_sub_class = 0x02;
65 config.device_protocol = 0x01;
66 config.composite_with_iads = true;
67
68 // Create embassy-usb DeviceBuilder using the driver and config.
69 // It needs some buffers for building the descriptors.
70 let mut device_descriptor = [0; 256];
71 let mut config_descriptor = [0; 256];
72 let mut bos_descriptor = [0; 256];
73 let mut control_buf = [0; 64];
74
75 let mut state = State::new();
76
77 let mut builder = Builder::new(
78 driver,
79 config,
80 &mut device_descriptor,
81 &mut config_descriptor,
82 &mut bos_descriptor,
83 &mut control_buf,
84 );
85
86 // Create classes on the builder.
87 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
88
89 // Build the builder.
90 let mut usb = builder.build();
91
92 // Run the USB device.
93 let usb_fut = usb.run();
94
95 // Do stuff with the class!
96 let echo_fut = async {
97 loop {
98 class.wait_connection().await;
99 info!("Connected");
100 let _ = echo(&mut class).await;
101 info!("Disconnected");
102 }
103 };
104
105 // Run everything concurrently.
106 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
107 join(usb_fut, echo_fut).await;
108}
109
110struct Disconnected {}
111
112impl From<EndpointError> for Disconnected {
113 fn from(val: EndpointError) -> Self {
114 match val {
115 EndpointError::BufferOverflow => panic!("Buffer overflow"),
116 EndpointError::Disabled => Disconnected {},
117 }
118 }
119}
120
121async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
122 let mut buf = [0; 64];
123 loop {
124 let n = class.read_packet(&mut buf).await?;
125 let data = &buf[..n];
126 info!("data: {:x}", data);
127 class.write_packet(data).await?;
128 }
129}
diff --git a/examples/stm32h7/.cargo/config.toml b/examples/stm32h7/.cargo/config.toml
index d38be23e0..5f680dbce 100644
--- a/examples/stm32h7/.cargo/config.toml
+++ b/examples/stm32h7/.cargo/config.toml
@@ -1,5 +1,5 @@
1[target.thumbv7em-none-eabihf] 1[target.thumbv7em-none-eabihf]
2runner = 'probe-run --chip STM32H743ZITx' 2runner = 'probe-rs run --chip STM32H743ZITx'
3 3
4[build] 4[build]
5target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) 5target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index 0f76f3226..768702fa9 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -2,24 +2,26 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32h7-examples" 3name = "embassy-stm32h7-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
10embassy-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"] }
11embassy-net = { path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16", "unstable-traits"] } 12embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "proto-ipv6"] }
12embedded-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"] }
13 15
14defmt = "0.3" 16defmt = "0.3"
15defmt-rtt = "0.3" 17defmt-rtt = "0.4"
16 18
17cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 19cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
18cortex-m-rt = "0.7.0" 20cortex-m-rt = "0.7.0"
19embedded-hal = "0.2.6" 21embedded-hal = "0.2.6"
20embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" } 22embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" }
21embedded-hal-async = { version = "0.1.0-alpha.1" } 23embedded-hal-async = { version = "=0.2.0-alpha.2" }
22embedded-nal-async = "0.2.0" 24embedded-nal-async = "0.4.0"
23panic-probe = { version = "0.3", features = ["print-defmt"] } 25panic-probe = { version = "0.3", features = ["print-defmt"] }
24futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 26futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
25heapless = { version = "0.7.5", default-features = false } 27heapless = { version = "0.7.5", default-features = false }
@@ -28,7 +30,7 @@ critical-section = "1.1"
28micromath = "2.0.0" 30micromath = "2.0.0"
29stm32-fmc = "0.2.4" 31stm32-fmc = "0.2.4"
30embedded-storage = "0.3.0" 32embedded-storage = "0.3.0"
31static_cell = "1.0" 33static_cell = { version = "1.1", features = ["nightly"]}
32 34
33# cargo build/run 35# cargo build/run
34[profile.dev] 36[profile.dev]
diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs
index 9c443b83a..6f75a0630 100644
--- a/examples/stm32h7/src/bin/camera.rs
+++ b/examples/stm32h7/src/bin/camera.rs
@@ -8,7 +8,7 @@ use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::i2c::I2c; 8use embassy_stm32::i2c::I2c;
9use embassy_stm32::rcc::{Mco, Mco1Source, McoClock}; 9use embassy_stm32::rcc::{Mco, Mco1Source, McoClock};
10use embassy_stm32::time::{khz, mhz}; 10use embassy_stm32::time::{khz, mhz};
11use embassy_stm32::{interrupt, Config}; 11use embassy_stm32::{bind_interrupts, i2c, peripherals, Config};
12use embassy_time::{Duration, Timer}; 12use embassy_time::{Duration, Timer};
13use ov7725::*; 13use ov7725::*;
14use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
@@ -18,6 +18,11 @@ const HEIGHT: usize = 100;
18 18
19static mut FRAME: [u32; WIDTH * HEIGHT / 2] = [0u32; WIDTH * HEIGHT / 2]; 19static mut FRAME: [u32; WIDTH * HEIGHT / 2] = [0u32; WIDTH * HEIGHT / 2];
20 20
21bind_interrupts!(struct Irqs {
22 I2C1_EV => i2c::InterruptHandler<peripherals::I2C1>;
23 DCMI => dcmi::InterruptHandler<peripherals::DCMI>;
24});
25
21#[embassy_executor::main] 26#[embassy_executor::main]
22async fn main(_spawner: Spawner) { 27async fn main(_spawner: Spawner) {
23 let mut config = Config::default(); 28 let mut config = Config::default();
@@ -34,12 +39,11 @@ async fn main(_spawner: Spawner) {
34 let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::Hsi, McoClock::Divided(3)); 39 let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::Hsi, McoClock::Divided(3));
35 40
36 let mut led = Output::new(p.PE3, Level::High, Speed::Low); 41 let mut led = Output::new(p.PE3, Level::High, Speed::Low);
37 let i2c_irq = interrupt::take!(I2C1_EV);
38 let cam_i2c = I2c::new( 42 let cam_i2c = I2c::new(
39 p.I2C1, 43 p.I2C1,
40 p.PB8, 44 p.PB8,
41 p.PB9, 45 p.PB9,
42 i2c_irq, 46 Irqs,
43 p.DMA1_CH1, 47 p.DMA1_CH1,
44 p.DMA1_CH2, 48 p.DMA1_CH2,
45 khz(100), 49 khz(100),
@@ -55,11 +59,9 @@ async fn main(_spawner: Spawner) {
55 59
56 defmt::info!("manufacturer: 0x{:x}, pid: 0x{:x}", manufacturer_id, camera_id); 60 defmt::info!("manufacturer: 0x{:x}, pid: 0x{:x}", manufacturer_id, camera_id);
57 61
58 let dcmi_irq = interrupt::take!(DCMI);
59 let config = dcmi::Config::default(); 62 let config = dcmi::Config::default();
60 let mut dcmi = Dcmi::new_8bit( 63 let mut dcmi = Dcmi::new_8bit(
61 p.DCMI, p.DMA1_CH0, dcmi_irq, p.PC6, p.PC7, p.PE0, p.PE1, p.PE4, p.PD3, p.PE5, p.PE6, p.PB7, p.PA4, p.PA6, 64 p.DCMI, p.DMA1_CH0, Irqs, p.PC6, p.PC7, p.PE0, p.PE1, p.PE4, p.PD3, p.PE5, p.PE6, p.PB7, p.PA4, p.PA6, config,
62 config,
63 ); 65 );
64 66
65 defmt::info!("attempting capture"); 67 defmt::info!("attempting capture");
diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs
index f12716370..586b4154b 100644
--- a/examples/stm32h7/src/bin/dac.rs
+++ b/examples/stm32h7/src/bin/dac.rs
@@ -4,7 +4,8 @@
4 4
5use cortex_m_rt::entry; 5use cortex_m_rt::entry;
6use defmt::*; 6use defmt::*;
7use embassy_stm32::dac::{Channel, Dac, Value}; 7use embassy_stm32::dac::{DacCh1, DacChannel, Value};
8use embassy_stm32::dma::NoDma;
8use embassy_stm32::time::mhz; 9use embassy_stm32::time::mhz;
9use embassy_stm32::Config; 10use embassy_stm32::Config;
10use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
@@ -19,12 +20,12 @@ fn main() -> ! {
19 config.rcc.pll1.q_ck = Some(mhz(100)); 20 config.rcc.pll1.q_ck = Some(mhz(100));
20 let p = embassy_stm32::init(config); 21 let p = embassy_stm32::init(config);
21 22
22 let mut dac = Dac::new_1ch(p.DAC1, p.PA4); 23 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
23 24
24 loop { 25 loop {
25 for v in 0..=255 { 26 for v in 0..=255 {
26 unwrap!(dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v)))); 27 unwrap!(dac.set(Value::Bit8(to_sine_wave(v))));
27 unwrap!(dac.trigger(Channel::Ch1)); 28 dac.trigger();
28 } 29 }
29 } 30 }
30} 31}
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index 4ccc0b5ef..cfafcaed1 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -7,26 +7,21 @@ 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;
14use embassy_stm32::{interrupt, Config}; 14use embassy_stm32::{bind_interrupts, eth, Config};
15use embassy_time::{Duration, Timer}; 15use embassy_time::{Duration, Timer};
16use embedded_io::asynch::Write; 16use embedded_io::asynch::Write;
17use rand_core::RngCore; 17use rand_core::RngCore;
18use static_cell::StaticCell; 18use static_cell::make_static;
19use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
20bind_interrupts!(struct Irqs {
21 ETH => eth::InterruptHandler;
22});
20 23
21macro_rules! singleton { 24type Device = Ethernet<'static, ETH, GenericSMI>;
22 ($val:expr) => {{
23 type T = impl Sized;
24 static STATIC_CELL: StaticCell<T> = StaticCell::new();
25 STATIC_CELL.init_with(move || $val)
26 }};
27}
28
29type Device = Ethernet<'static, ETH, GenericSMI, 4, 4>;
30 25
31#[embassy_executor::task] 26#[embassy_executor::task]
32async fn net_task(stack: &'static Stack<Device>) -> ! { 27async fn net_task(stack: &'static Stack<Device>) -> ! {
@@ -48,41 +43,38 @@ async fn main(spawner: Spawner) -> ! {
48 rng.fill_bytes(&mut seed); 43 rng.fill_bytes(&mut seed);
49 let seed = u64::from_le_bytes(seed); 44 let seed = u64::from_le_bytes(seed);
50 45
51 let eth_int = interrupt::take!(ETH);
52 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 46 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
53 47
54 let device = unsafe { 48 let device = Ethernet::new(
55 Ethernet::new( 49 make_static!(PacketQueue::<16, 16>::new()),
56 singleton!(State::new()), 50 p.ETH,
57 p.ETH, 51 Irqs,
58 eth_int, 52 p.PA1,
59 p.PA1, 53 p.PA2,
60 p.PA2, 54 p.PC1,
61 p.PC1, 55 p.PA7,
62 p.PA7, 56 p.PC4,
63 p.PC4, 57 p.PC5,
64 p.PC5, 58 p.PG13,
65 p.PG13, 59 p.PB13,
66 p.PB13, 60 p.PG11,
67 p.PG11, 61 GenericSMI::new(),
68 GenericSMI, 62 mac_addr,
69 mac_addr, 63 0,
70 0, 64 );
71 ) 65
72 }; 66 let config = embassy_net::Config::dhcpv4(Default::default());
73 67 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
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), 68 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
77 // dns_servers: Vec::new(), 69 // dns_servers: Vec::new(),
78 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 70 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
79 //}); 71 //});
80 72
81 // Init network stack 73 // Init network stack
82 let stack = &*singleton!(Stack::new( 74 let stack = &*make_static!(Stack::new(
83 device, 75 device,
84 config, 76 config,
85 singleton!(StackResources::<1, 2, 8>::new()), 77 make_static!(StackResources::<2>::new()),
86 seed 78 seed
87 )); 79 ));
88 80
@@ -98,7 +90,7 @@ async fn main(spawner: Spawner) -> ! {
98 loop { 90 loop {
99 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); 91 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer);
100 92
101 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10))); 93 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
102 94
103 let remote_endpoint = (Ipv4Address::new(10, 42, 0, 1), 8000); 95 let remote_endpoint = (Ipv4Address::new(10, 42, 0, 1), 8000);
104 info!("connecting..."); 96 info!("connecting...");
@@ -112,7 +104,7 @@ async fn main(spawner: Spawner) -> ! {
112 let r = socket.write_all(b"Hello\n").await; 104 let r = socket.write_all(b"Hello\n").await;
113 if let Err(e) = r { 105 if let Err(e) = r {
114 info!("write error: {:?}", e); 106 info!("write error: {:?}", e);
115 return; 107 continue;
116 } 108 }
117 Timer::after(Duration::from_secs(1)).await; 109 Timer::after(Duration::from_secs(1)).await;
118 } 110 }
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index 64fd84141..4ed737578 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -7,27 +7,22 @@ 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;
14use embassy_stm32::{interrupt, Config}; 14use embassy_stm32::{bind_interrupts, eth, Config};
15use embassy_time::{Duration, Timer}; 15use embassy_time::{Duration, Timer};
16use embedded_io::asynch::Write; 16use embedded_io::asynch::Write;
17use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect}; 17use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect};
18use rand_core::RngCore; 18use rand_core::RngCore;
19use static_cell::StaticCell; 19use static_cell::make_static;
20use {defmt_rtt as _, panic_probe as _}; 20use {defmt_rtt as _, panic_probe as _};
21bind_interrupts!(struct Irqs {
22 ETH => eth::InterruptHandler;
23});
21 24
22macro_rules! singleton { 25type Device = Ethernet<'static, ETH, GenericSMI>;
23 ($val:expr) => {{
24 type T = impl Sized;
25 static STATIC_CELL: StaticCell<T> = StaticCell::new();
26 STATIC_CELL.init_with(move || $val)
27 }};
28}
29
30type Device = Ethernet<'static, ETH, GenericSMI, 4, 4>;
31 26
32#[embassy_executor::task] 27#[embassy_executor::task]
33async fn net_task(stack: &'static Stack<Device>) -> ! { 28async fn net_task(stack: &'static Stack<Device>) -> ! {
@@ -49,41 +44,38 @@ async fn main(spawner: Spawner) -> ! {
49 rng.fill_bytes(&mut seed); 44 rng.fill_bytes(&mut seed);
50 let seed = u64::from_le_bytes(seed); 45 let seed = u64::from_le_bytes(seed);
51 46
52 let eth_int = interrupt::take!(ETH);
53 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 47 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
54 48
55 let device = unsafe { 49 let device = Ethernet::new(
56 Ethernet::new( 50 make_static!(PacketQueue::<16, 16>::new()),
57 singleton!(State::new()), 51 p.ETH,
58 p.ETH, 52 Irqs,
59 eth_int, 53 p.PA1,
60 p.PA1, 54 p.PA2,
61 p.PA2, 55 p.PC1,
62 p.PC1, 56 p.PA7,
63 p.PA7, 57 p.PC4,
64 p.PC4, 58 p.PC5,
65 p.PC5, 59 p.PG13,
66 p.PG13, 60 p.PB13,
67 p.PB13, 61 p.PG11,
68 p.PG11, 62 GenericSMI::new(),
69 GenericSMI, 63 mac_addr,
70 mac_addr, 64 0,
71 0, 65 );
72 ) 66
73 }; 67 let config = embassy_net::Config::dhcpv4(Default::default());
74 68 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
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), 69 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
78 // dns_servers: Vec::new(), 70 // dns_servers: Vec::new(),
79 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 71 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
80 //}); 72 //});
81 73
82 // Init network stack 74 // Init network stack
83 let stack = &*singleton!(Stack::new( 75 let stack = &*make_static!(Stack::new(
84 device, 76 device,
85 config, 77 config,
86 singleton!(StackResources::<1, 2, 8>::new()), 78 make_static!(StackResources::<2>::new()),
87 seed 79 seed
88 )); 80 ));
89 81
@@ -114,7 +106,7 @@ async fn main(spawner: Spawner) -> ! {
114 let r = connection.write_all(b"Hello\n").await; 106 let r = connection.write_all(b"Hello\n").await;
115 if let Err(e) = r { 107 if let Err(e) = r {
116 info!("write error: {:?}", e); 108 info!("write error: {:?}", e);
117 return; 109 continue;
118 } 110 }
119 Timer::after(Duration::from_secs(1)).await; 111 Timer::after(Duration::from_secs(1)).await;
120 } 112 }
diff --git a/examples/stm32h7/src/bin/flash.rs b/examples/stm32h7/src/bin/flash.rs
index 6682c64d5..f66df770b 100644
--- a/examples/stm32h7/src/bin/flash.rs
+++ b/examples/stm32h7/src/bin/flash.rs
@@ -6,7 +6,6 @@ use defmt::{info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::flash::Flash; 7use embassy_stm32::flash::Flash;
8use embassy_time::{Duration, Timer}; 8use embassy_time::{Duration, Timer};
9use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
10use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
11 10
12#[embassy_executor::main] 11#[embassy_executor::main]
@@ -14,28 +13,28 @@ async fn main(_spawner: Spawner) {
14 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
15 info!("Hello Flash!"); 14 info!("Hello Flash!");
16 15
17 const ADDR: u32 = 0x08_0000; 16 const ADDR: u32 = 0; // This is the offset into bank 2, the absolute address is 0x8_0000
18 17
19 // wait a bit before accessing the flash 18 // wait a bit before accessing the flash
20 Timer::after(Duration::from_millis(300)).await; 19 Timer::after(Duration::from_millis(300)).await;
21 20
22 let mut f = Flash::unlock(p.FLASH); 21 let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank2_region;
23 22
24 info!("Reading..."); 23 info!("Reading...");
25 let mut buf = [0u8; 32]; 24 let mut buf = [0u8; 32];
26 unwrap!(f.read(ADDR, &mut buf)); 25 unwrap!(f.blocking_read(ADDR, &mut buf));
27 info!("Read: {=[u8]:x}", buf); 26 info!("Read: {=[u8]:x}", buf);
28 27
29 info!("Erasing..."); 28 info!("Erasing...");
30 unwrap!(f.erase(ADDR, ADDR + 128 * 1024)); 29 unwrap!(f.blocking_erase(ADDR, ADDR + 128 * 1024));
31 30
32 info!("Reading..."); 31 info!("Reading...");
33 let mut buf = [0u8; 32]; 32 let mut buf = [0u8; 32];
34 unwrap!(f.read(ADDR, &mut buf)); 33 unwrap!(f.blocking_read(ADDR, &mut buf));
35 info!("Read after erase: {=[u8]:x}", buf); 34 info!("Read after erase: {=[u8]:x}", buf);
36 35
37 info!("Writing..."); 36 info!("Writing...");
38 unwrap!(f.write( 37 unwrap!(f.blocking_write(
39 ADDR, 38 ADDR,
40 &[ 39 &[
41 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 40 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
@@ -45,7 +44,7 @@ async fn main(_spawner: Spawner) {
45 44
46 info!("Reading..."); 45 info!("Reading...");
47 let mut buf = [0u8; 32]; 46 let mut buf = [0u8; 32];
48 unwrap!(f.read(ADDR, &mut buf)); 47 unwrap!(f.blocking_read(ADDR, &mut buf));
49 info!("Read: {=[u8]:x}", buf); 48 info!("Read: {=[u8]:x}", buf);
50 assert_eq!( 49 assert_eq!(
51 &buf[..], 50 &buf[..],
diff --git a/examples/stm32h7/src/bin/i2c.rs b/examples/stm32h7/src/bin/i2c.rs
new file mode 100644
index 000000000..c2979c59b
--- /dev/null
+++ b/examples/stm32h7/src/bin/i2c.rs
@@ -0,0 +1,47 @@
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::time::Hertz;
9use embassy_stm32::{bind_interrupts, i2c, peripherals};
10use embassy_time::Duration;
11use {defmt_rtt as _, panic_probe as _};
12
13const ADDRESS: u8 = 0x5F;
14const WHOAMI: u8 = 0x0F;
15
16bind_interrupts!(struct Irqs {
17 I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>;
18});
19
20#[embassy_executor::main]
21async fn main(_spawner: Spawner) {
22 info!("Hello world!");
23 let p = embassy_stm32::init(Default::default());
24
25 let mut i2c = I2c::new(
26 p.I2C2,
27 p.PB10,
28 p.PB11,
29 Irqs,
30 p.DMA1_CH4,
31 p.DMA1_CH5,
32 Hertz(100_000),
33 Default::default(),
34 );
35
36 // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long.
37 // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay.
38 let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000));
39
40 let mut data = [0u8; 1];
41
42 match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) {
43 Ok(()) => info!("Whoami: {}", data[0]),
44 Err(Error::Timeout) => error!("Operation timed out"),
45 Err(e) => error!("I2c Error: {:?}", e),
46 }
47}
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs
index 1972f8ff2..d360df085 100644
--- a/examples/stm32h7/src/bin/low_level_timer_api.rs
+++ b/examples/stm32h7/src/bin/low_level_timer_api.rs
@@ -62,49 +62,39 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
62 T::enable(); 62 T::enable();
63 <T as embassy_stm32::rcc::low_level::RccPeripheral>::reset(); 63 <T as embassy_stm32::rcc::low_level::RccPeripheral>::reset();
64 64
65 unsafe { 65 ch1.set_speed(Speed::VeryHigh);
66 ch1.set_speed(Speed::VeryHigh); 66 ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull);
67 ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull); 67 ch2.set_speed(Speed::VeryHigh);
68 ch2.set_speed(Speed::VeryHigh); 68 ch2.set_as_af(ch1.af_num(), AFType::OutputPushPull);
69 ch2.set_as_af(ch1.af_num(), AFType::OutputPushPull); 69 ch3.set_speed(Speed::VeryHigh);
70 ch3.set_speed(Speed::VeryHigh); 70 ch3.set_as_af(ch1.af_num(), AFType::OutputPushPull);
71 ch3.set_as_af(ch1.af_num(), AFType::OutputPushPull); 71 ch4.set_speed(Speed::VeryHigh);
72 ch4.set_speed(Speed::VeryHigh); 72 ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull);
73 ch4.set_as_af(ch1.af_num(), AFType::OutputPushPull);
74 }
75 73
76 let mut this = Self { inner: tim }; 74 let mut this = Self { inner: tim };
77 75
78 this.set_freq(freq); 76 this.set_freq(freq);
79 this.inner.start(); 77 this.inner.start();
80 78
81 unsafe { 79 let r = T::regs_gp32();
82 T::regs_gp32() 80 r.ccmr_output(0)
83 .ccmr_output(0) 81 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into()));
84 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); 82 r.ccmr_output(0)
85 T::regs_gp32() 83 .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into()));
86 .ccmr_output(0) 84 r.ccmr_output(1)
87 .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into())); 85 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into()));
88 T::regs_gp32() 86 r.ccmr_output(1)
89 .ccmr_output(1) 87 .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into()));
90 .modify(|w| w.set_ocm(0, OutputCompareMode::PwmMode1.into())); 88
91 T::regs_gp32()
92 .ccmr_output(1)
93 .modify(|w| w.set_ocm(1, OutputCompareMode::PwmMode1.into()));
94 }
95 this 89 this
96 } 90 }
97 91
98 pub fn enable(&mut self, channel: Channel) { 92 pub fn enable(&mut self, channel: Channel) {
99 unsafe { 93 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true));
100 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true));
101 }
102 } 94 }
103 95
104 pub fn disable(&mut self, channel: Channel) { 96 pub fn disable(&mut self, channel: Channel) {
105 unsafe { 97 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false));
106 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false));
107 }
108 } 98 }
109 99
110 pub fn set_freq(&mut self, freq: Hertz) { 100 pub fn set_freq(&mut self, freq: Hertz) {
@@ -112,11 +102,11 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
112 } 102 }
113 103
114 pub fn get_max_duty(&self) -> u32 { 104 pub fn get_max_duty(&self) -> u32 {
115 unsafe { T::regs_gp32().arr().read().arr() } 105 T::regs_gp32().arr().read().arr()
116 } 106 }
117 107
118 pub fn set_duty(&mut self, channel: Channel, duty: u32) { 108 pub fn set_duty(&mut self, channel: Channel, duty: u32) {
119 defmt::assert!(duty < self.get_max_duty()); 109 defmt::assert!(duty < self.get_max_duty());
120 unsafe { T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty)) } 110 T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty))
121 } 111 }
122} 112}
diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs
index 26d1db01e..ce91b6b1c 100644
--- a/examples/stm32h7/src/bin/sdmmc.rs
+++ b/examples/stm32h7/src/bin/sdmmc.rs
@@ -6,9 +6,13 @@ use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::sdmmc::Sdmmc; 7use embassy_stm32::sdmmc::Sdmmc;
8use embassy_stm32::time::mhz; 8use embassy_stm32::time::mhz;
9use embassy_stm32::{interrupt, Config}; 9use embassy_stm32::{bind_interrupts, peripherals, sdmmc, Config};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12bind_interrupts!(struct Irqs {
13 SDMMC1 => sdmmc::InterruptHandler<peripherals::SDMMC1>;
14});
15
12#[embassy_executor::main] 16#[embassy_executor::main]
13async fn main(_spawner: Spawner) -> ! { 17async fn main(_spawner: Spawner) -> ! {
14 let mut config = Config::default(); 18 let mut config = Config::default();
@@ -16,11 +20,9 @@ async fn main(_spawner: Spawner) -> ! {
16 let p = embassy_stm32::init(config); 20 let p = embassy_stm32::init(config);
17 info!("Hello World!"); 21 info!("Hello World!");
18 22
19 let irq = interrupt::take!(SDMMC1);
20
21 let mut sdmmc = Sdmmc::new_4bit( 23 let mut sdmmc = Sdmmc::new_4bit(
22 p.SDMMC1, 24 p.SDMMC1,
23 irq, 25 Irqs,
24 p.PC12, 26 p.PC12,
25 p.PD2, 27 p.PD2,
26 p.PC8, 28 p.PC8,
diff --git a/examples/stm32h7/src/bin/signal.rs b/examples/stm32h7/src/bin/signal.rs
index cc3e4e3ca..6d7c168d5 100644
--- a/examples/stm32h7/src/bin/signal.rs
+++ b/examples/stm32h7/src/bin/signal.rs
@@ -4,11 +4,12 @@
4 4
5use defmt::{info, unwrap}; 5use defmt::{info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
7use embassy_sync::signal::Signal; 8use embassy_sync::signal::Signal;
8use embassy_time::{Duration, Timer}; 9use embassy_time::{Duration, Timer};
9use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
10 11
11static SIGNAL: Signal<u32> = Signal::new(); 12static SIGNAL: Signal<CriticalSectionRawMutex, u32> = Signal::new();
12 13
13#[embassy_executor::task] 14#[embassy_executor::task]
14async fn my_sending_task() { 15async fn my_sending_task() {
diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs
index 87c2b1253..0abb94abb 100644
--- a/examples/stm32h7/src/bin/usart.rs
+++ b/examples/stm32h7/src/bin/usart.rs
@@ -7,15 +7,20 @@ use defmt::*;
7use embassy_executor::Executor; 7use embassy_executor::Executor;
8use embassy_stm32::dma::NoDma; 8use embassy_stm32::dma::NoDma;
9use embassy_stm32::usart::{Config, Uart}; 9use embassy_stm32::usart::{Config, Uart};
10use embassy_stm32::{bind_interrupts, peripherals, usart};
10use static_cell::StaticCell; 11use static_cell::StaticCell;
11use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
12 13
14bind_interrupts!(struct Irqs {
15 UART7 => usart::InterruptHandler<peripherals::UART7>;
16});
17
13#[embassy_executor::task] 18#[embassy_executor::task]
14async fn main_task() { 19async fn main_task() {
15 let p = embassy_stm32::init(Default::default()); 20 let p = embassy_stm32::init(Default::default());
16 21
17 let config = Config::default(); 22 let config = Config::default();
18 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, NoDma, NoDma, config); 23 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config);
19 24
20 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 25 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
21 info!("wrote Hello, starting echo"); 26 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..f1fe7fce6 100644
--- a/examples/stm32h7/src/bin/usart_dma.rs
+++ b/examples/stm32h7/src/bin/usart_dma.rs
@@ -9,16 +9,21 @@ use defmt::*;
9use embassy_executor::Executor; 9use embassy_executor::Executor;
10use embassy_stm32::dma::NoDma; 10use embassy_stm32::dma::NoDma;
11use embassy_stm32::usart::{Config, Uart}; 11use embassy_stm32::usart::{Config, Uart};
12use embassy_stm32::{bind_interrupts, peripherals, usart};
12use heapless::String; 13use heapless::String;
13use static_cell::StaticCell; 14use static_cell::StaticCell;
14use {defmt_rtt as _, panic_probe as _}; 15use {defmt_rtt as _, panic_probe as _};
15 16
17bind_interrupts!(struct Irqs {
18 UART7 => usart::InterruptHandler<peripherals::UART7>;
19});
20
16#[embassy_executor::task] 21#[embassy_executor::task]
17async fn main_task() { 22async fn main_task() {
18 let p = embassy_stm32::init(Default::default()); 23 let p = embassy_stm32::init(Default::default());
19 24
20 let config = Config::default(); 25 let config = Config::default();
21 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_CH0, NoDma, config); 26 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, NoDma, config);
22 27
23 for n in 0u32.. { 28 for n in 0u32.. {
24 let mut s: String<128> = String::new(); 29 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..330d1ce09 100644
--- a/examples/stm32h7/src/bin/usart_split.rs
+++ b/examples/stm32h7/src/bin/usart_split.rs
@@ -7,10 +7,15 @@ use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma; 7use embassy_stm32::dma::NoDma;
8use embassy_stm32::peripherals::{DMA1_CH1, UART7}; 8use embassy_stm32::peripherals::{DMA1_CH1, UART7};
9use embassy_stm32::usart::{Config, Uart, UartRx}; 9use embassy_stm32::usart::{Config, Uart, UartRx};
10use embassy_stm32::{bind_interrupts, peripherals, usart};
10use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 11use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
11use embassy_sync::channel::Channel; 12use embassy_sync::channel::Channel;
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
13 14
15bind_interrupts!(struct Irqs {
16 UART7 => usart::InterruptHandler<peripherals::UART7>;
17});
18
14#[embassy_executor::task] 19#[embassy_executor::task]
15async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) { 20async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) {
16 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 21 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
@@ -31,7 +36,7 @@ async fn main(spawner: Spawner) -> ! {
31 info!("Hello World!"); 36 info!("Hello World!");
32 37
33 let config = Config::default(); 38 let config = Config::default();
34 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, p.DMA1_CH0, p.DMA1_CH1, config); 39 let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, p.DMA1_CH1, config);
35 unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); 40 unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n"));
36 41
37 let (mut tx, rx) = usart.split(); 42 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..97291f60c
--- /dev/null
+++ b/examples/stm32h7/src/bin/usb_serial.rs
@@ -0,0 +1,110 @@
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::{bind_interrupts, peripherals, usb_otg, 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
16bind_interrupts!(struct Irqs {
17 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
18});
19
20#[embassy_executor::main]
21async fn main(_spawner: Spawner) {
22 info!("Hello World!");
23
24 let mut config = Config::default();
25 config.rcc.sys_ck = Some(mhz(400));
26 config.rcc.hclk = Some(mhz(200));
27 config.rcc.pll1.q_ck = Some(mhz(100));
28 let p = embassy_stm32::init(config);
29
30 // Create the driver, from the HAL.
31 let mut ep_out_buffer = [0u8; 256];
32 let mut config = embassy_stm32::usb_otg::Config::default();
33 config.vbus_detection = true;
34 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
35
36 // Create embassy-usb Config
37 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
38 config.manufacturer = Some("Embassy");
39 config.product = Some("USB-serial example");
40 config.serial_number = Some("12345678");
41
42 // Required for windows compatibility.
43 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
44 config.device_class = 0xEF;
45 config.device_sub_class = 0x02;
46 config.device_protocol = 0x01;
47 config.composite_with_iads = true;
48
49 // Create embassy-usb DeviceBuilder using the driver and config.
50 // It needs some buffers for building the descriptors.
51 let mut device_descriptor = [0; 256];
52 let mut config_descriptor = [0; 256];
53 let mut bos_descriptor = [0; 256];
54 let mut control_buf = [0; 64];
55
56 let mut state = State::new();
57
58 let mut builder = Builder::new(
59 driver,
60 config,
61 &mut device_descriptor,
62 &mut config_descriptor,
63 &mut bos_descriptor,
64 &mut control_buf,
65 );
66
67 // Create classes on the builder.
68 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
69
70 // Build the builder.
71 let mut usb = builder.build();
72
73 // Run the USB device.
74 let usb_fut = usb.run();
75
76 // Do stuff with the class!
77 let echo_fut = async {
78 loop {
79 class.wait_connection().await;
80 info!("Connected");
81 let _ = echo(&mut class).await;
82 info!("Disconnected");
83 }
84 };
85
86 // Run everything concurrently.
87 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
88 join(usb_fut, echo_fut).await;
89}
90
91struct Disconnected {}
92
93impl From<EndpointError> for Disconnected {
94 fn from(val: EndpointError) -> Self {
95 match val {
96 EndpointError::BufferOverflow => panic!("Buffer overflow"),
97 EndpointError::Disabled => Disconnected {},
98 }
99 }
100}
101
102async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
103 let mut buf = [0; 64];
104 loop {
105 let n = class.read_packet(&mut buf).await?;
106 let data = &buf[..n];
107 info!("data: {:x}", data);
108 class.write_packet(data).await?;
109 }
110}
diff --git a/examples/stm32h7/src/bin/wdg.rs b/examples/stm32h7/src/bin/wdg.rs
new file mode 100644
index 000000000..9181dfd67
--- /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 wdg.unleash();
19
20 loop {
21 Timer::after(Duration::from_secs(1)).await;
22 wdg.pet();
23 }
24}
diff --git a/examples/stm32l0/.cargo/config.toml b/examples/stm32l0/.cargo/config.toml
index a81a48f97..b050334b2 100644
--- a/examples/stm32l0/.cargo/config.toml
+++ b/examples/stm32l0/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-run --list-chips` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32L053R8Tx" 3runner = "probe-rs run --chip STM32L053R8Tx"
4 4
5[build] 5[build]
6target = "thumbv6m-none-eabi" 6target = "thumbv6m-none-eabi"
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index 11751a21d..747cec7bf 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -2,31 +2,36 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32l0-examples" 3name = "embassy-stm32l0-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[features] 7[features]
7default = ["nightly"] 8default = ["nightly"]
8nightly = ["embassy-stm32/nightly", "embassy-lora", "lorawan-device", "lorawan", "embedded-io/async"] 9nightly = ["embassy-stm32/nightly", "embassy-time/nightly", "embassy-time/unstable-traits", "embassy-executor/nightly",
10 "embassy-lora", "lora-phy", "lorawan-device", "lorawan", "embedded-io/async"]
9 11
10[dependencies] 12[dependencies]
11embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 13embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
12embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 14embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
13embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] } 15embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "unstable-traits", "memory-x"] } 16embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
15embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["sx127x", "time", "defmt"], optional = true} 17embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true }
16 18lora-phy = { version = "1", optional = true }
17lorawan-device = { version = "0.7.1", default-features = false, features = ["async"], optional = true } 19lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true }
18lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"], optional = true } 20lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true }
19 21
20defmt = "0.3" 22defmt = "0.3"
21defmt-rtt = "0.3" 23defmt-rtt = "0.4"
22 24
23embedded-storage = "0.3.0" 25embedded-storage = "0.3.0"
24embedded-io = "0.3.0" 26embedded-io = "0.4.0"
25 27
26cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 28cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
27cortex-m-rt = "0.7.0" 29cortex-m-rt = "0.7.0"
28panic-probe = { version = "0.3", features = ["print-defmt"] } 30panic-probe = { version = "0.3", features = ["print-defmt"] }
29futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 31futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
30heapless = { version = "0.7.5", default-features = false } 32heapless = { version = "0.7.5", default-features = false }
31embedded-hal = "0.2.6" 33embedded-hal = "0.2.6"
32static_cell = "1.0" 34static_cell = "1.1"
35
36[patch.crates-io]
37lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "ad289428fd44b02788e2fa2116445cc8f640a265" }
diff --git a/examples/stm32l0/src/bin/flash.rs b/examples/stm32l0/src/bin/flash.rs
index 867cb4d3e..86f6c70b9 100644
--- a/examples/stm32l0/src/bin/flash.rs
+++ b/examples/stm32l0/src/bin/flash.rs
@@ -5,7 +5,6 @@
5use defmt::{info, unwrap}; 5use defmt::{info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::flash::Flash; 7use embassy_stm32::flash::Flash;
8use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
10 9
11#[embassy_executor::main] 10#[embassy_executor::main]
@@ -15,27 +14,27 @@ async fn main(_spawner: Spawner) {
15 14
16 const ADDR: u32 = 0x26000; 15 const ADDR: u32 = 0x26000;
17 16
18 let mut f = Flash::unlock(p.FLASH); 17 let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region;
19 18
20 info!("Reading..."); 19 info!("Reading...");
21 let mut buf = [0u8; 8]; 20 let mut buf = [0u8; 8];
22 unwrap!(f.read(ADDR, &mut buf)); 21 unwrap!(f.blocking_read(ADDR, &mut buf));
23 info!("Read: {=[u8]:x}", buf); 22 info!("Read: {=[u8]:x}", buf);
24 23
25 info!("Erasing..."); 24 info!("Erasing...");
26 unwrap!(f.erase(ADDR, ADDR + 128)); 25 unwrap!(f.blocking_erase(ADDR, ADDR + 128));
27 26
28 info!("Reading..."); 27 info!("Reading...");
29 let mut buf = [0u8; 8]; 28 let mut buf = [0u8; 8];
30 unwrap!(f.read(ADDR, &mut buf)); 29 unwrap!(f.blocking_read(ADDR, &mut buf));
31 info!("Read after erase: {=[u8]:x}", buf); 30 info!("Read after erase: {=[u8]:x}", buf);
32 31
33 info!("Writing..."); 32 info!("Writing...");
34 unwrap!(f.write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); 33 unwrap!(f.blocking_write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8]));
35 34
36 info!("Reading..."); 35 info!("Reading...");
37 let mut buf = [0u8; 8]; 36 let mut buf = [0u8; 8];
38 unwrap!(f.read(ADDR, &mut buf)); 37 unwrap!(f.blocking_read(ADDR, &mut buf));
39 info!("Read: {=[u8]:x}", buf); 38 info!("Read: {=[u8]:x}", buf);
40 assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]); 39 assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
41} 40}
diff --git a/examples/stm32l0/src/bin/lora_cad.rs b/examples/stm32l0/src/bin/lora_cad.rs
new file mode 100644
index 000000000..588cea1e5
--- /dev/null
+++ b/examples/stm32l0/src/bin/lora_cad.rs
@@ -0,0 +1,105 @@
1//! This example runs on the STM32 LoRa Discovery board, which has a builtin Semtech Sx1276 radio.
2//! It demonstrates LORA P2P CAD functionality.
3#![no_std]
4#![no_main]
5#![macro_use]
6#![feature(type_alias_impl_trait)]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_lora::iv::Stm32l0InterfaceVariant;
11use embassy_stm32::exti::{Channel, ExtiInput};
12use embassy_stm32::gpio::{Input, Level, Output, Pin, Pull, Speed};
13use embassy_stm32::spi;
14use embassy_stm32::time::khz;
15use embassy_time::{Delay, Duration, Timer};
16use lora_phy::mod_params::*;
17use lora_phy::sx1276_7_8_9::SX1276_7_8_9;
18use lora_phy::LoRa;
19use {defmt_rtt as _, panic_probe as _};
20
21const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
22
23#[embassy_executor::main]
24async fn main(_spawner: Spawner) {
25 let mut config = embassy_stm32::Config::default();
26 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16;
27 config.rcc.enable_hsi48 = true;
28 let p = embassy_stm32::init(config);
29
30 // SPI for sx1276
31 let spi = spi::Spi::new(
32 p.SPI1,
33 p.PB3,
34 p.PA7,
35 p.PA6,
36 p.DMA1_CH3,
37 p.DMA1_CH2,
38 khz(200),
39 spi::Config::default(),
40 );
41
42 let nss = Output::new(p.PA15.degrade(), Level::High, Speed::Low);
43 let reset = Output::new(p.PC0.degrade(), Level::High, Speed::Low);
44
45 let irq_pin = Input::new(p.PB4.degrade(), Pull::Up);
46 let irq = ExtiInput::new(irq_pin, p.EXTI4.degrade());
47
48 let iv = Stm32l0InterfaceVariant::new(nss, reset, irq, None, None).unwrap();
49
50 let mut delay = Delay;
51
52 let mut lora = {
53 match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), false, &mut delay).await {
54 Ok(l) => l,
55 Err(err) => {
56 info!("Radio error = {}", err);
57 return;
58 }
59 }
60 };
61
62 let mut debug_indicator = Output::new(p.PB5, Level::Low, Speed::Low);
63 let mut start_indicator = Output::new(p.PB6, Level::Low, Speed::Low);
64
65 start_indicator.set_high();
66 Timer::after(Duration::from_secs(5)).await;
67 start_indicator.set_low();
68
69 let mdltn_params = {
70 match lora.create_modulation_params(
71 SpreadingFactor::_10,
72 Bandwidth::_250KHz,
73 CodingRate::_4_8,
74 LORA_FREQUENCY_IN_HZ,
75 ) {
76 Ok(mp) => mp,
77 Err(err) => {
78 info!("Radio error = {}", err);
79 return;
80 }
81 }
82 };
83
84 match lora.prepare_for_cad(&mdltn_params, true).await {
85 Ok(()) => {}
86 Err(err) => {
87 info!("Radio error = {}", err);
88 return;
89 }
90 };
91
92 match lora.cad().await {
93 Ok(cad_activity_detected) => {
94 if cad_activity_detected {
95 info!("cad successful with activity detected")
96 } else {
97 info!("cad successful without activity detected")
98 }
99 debug_indicator.set_high();
100 Timer::after(Duration::from_secs(5)).await;
101 debug_indicator.set_low();
102 }
103 Err(err) => info!("cad unsuccessful = {}", err),
104 }
105}
diff --git a/examples/stm32l0/src/bin/lora_lorawan.rs b/examples/stm32l0/src/bin/lora_lorawan.rs
new file mode 100644
index 000000000..c397edd58
--- /dev/null
+++ b/examples/stm32l0/src/bin/lora_lorawan.rs
@@ -0,0 +1,88 @@
1//! This example runs on the STM32 LoRa Discovery board, which has a builtin Semtech Sx1276 radio.
2//! It demonstrates LoRaWAN join functionality.
3#![no_std]
4#![no_main]
5#![macro_use]
6#![feature(type_alias_impl_trait)]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_lora::iv::Stm32l0InterfaceVariant;
11use embassy_lora::LoraTimer;
12use embassy_stm32::exti::{Channel, ExtiInput};
13use embassy_stm32::gpio::{Input, Level, Output, Pin, Pull, Speed};
14use embassy_stm32::rng::Rng;
15use embassy_stm32::spi;
16use embassy_stm32::time::khz;
17use embassy_time::Delay;
18use lora_phy::mod_params::*;
19use lora_phy::sx1276_7_8_9::SX1276_7_8_9;
20use lora_phy::LoRa;
21use lorawan::default_crypto::DefaultFactory as Crypto;
22use lorawan_device::async_device::lora_radio::LoRaRadio;
23use lorawan_device::async_device::{region, Device, JoinMode};
24use {defmt_rtt as _, panic_probe as _};
25
26const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set this appropriately for the region
27
28#[embassy_executor::main]
29async fn main(_spawner: Spawner) {
30 let mut config = embassy_stm32::Config::default();
31 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16;
32 config.rcc.enable_hsi48 = true;
33 let p = embassy_stm32::init(config);
34
35 // SPI for sx1276
36 let spi = spi::Spi::new(
37 p.SPI1,
38 p.PB3,
39 p.PA7,
40 p.PA6,
41 p.DMA1_CH3,
42 p.DMA1_CH2,
43 khz(200),
44 spi::Config::default(),
45 );
46
47 let nss = Output::new(p.PA15.degrade(), Level::High, Speed::Low);
48 let reset = Output::new(p.PC0.degrade(), Level::High, Speed::Low);
49
50 let irq_pin = Input::new(p.PB4.degrade(), Pull::Up);
51 let irq = ExtiInput::new(irq_pin, p.EXTI4.degrade());
52
53 let iv = Stm32l0InterfaceVariant::new(nss, reset, irq, None, None).unwrap();
54
55 let mut delay = Delay;
56
57 let lora = {
58 match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), true, &mut delay).await {
59 Ok(l) => l,
60 Err(err) => {
61 info!("Radio error = {}", err);
62 return;
63 }
64 }
65 };
66
67 let radio = LoRaRadio::new(lora);
68 let region: region::Configuration = region::Configuration::new(LORAWAN_REGION);
69 let mut device: Device<_, Crypto, _, _> = Device::new(region, radio, LoraTimer::new(), Rng::new(p.RNG));
70
71 defmt::info!("Joining LoRaWAN network");
72
73 // TODO: Adjust the EUI and Keys according to your network credentials
74 match device
75 .join(&JoinMode::OTAA {
76 deveui: [0, 0, 0, 0, 0, 0, 0, 0],
77 appeui: [0, 0, 0, 0, 0, 0, 0, 0],
78 appkey: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
79 })
80 .await
81 {
82 Ok(()) => defmt::info!("LoRaWAN network joined"),
83 Err(err) => {
84 info!("Radio error = {}", err);
85 return;
86 }
87 };
88}
diff --git a/examples/stm32l0/src/bin/lora_p2p_receive.rs b/examples/stm32l0/src/bin/lora_p2p_receive.rs
new file mode 100644
index 000000000..bb7509509
--- /dev/null
+++ b/examples/stm32l0/src/bin/lora_p2p_receive.rs
@@ -0,0 +1,127 @@
1//! This example runs on the STM32 LoRa Discovery board, which has a builtin Semtech Sx1276 radio.
2//! It demonstrates LORA P2P receive functionality in conjunction with the lora_p2p_send example.
3#![no_std]
4#![no_main]
5#![macro_use]
6#![feature(type_alias_impl_trait)]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_lora::iv::Stm32l0InterfaceVariant;
11use embassy_stm32::exti::{Channel, ExtiInput};
12use embassy_stm32::gpio::{Input, Level, Output, Pin, Pull, Speed};
13use embassy_stm32::spi;
14use embassy_stm32::time::khz;
15use embassy_time::{Delay, Duration, Timer};
16use lora_phy::mod_params::*;
17use lora_phy::sx1276_7_8_9::SX1276_7_8_9;
18use lora_phy::LoRa;
19use {defmt_rtt as _, panic_probe as _};
20
21const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
22
23#[embassy_executor::main]
24async fn main(_spawner: Spawner) {
25 let mut config = embassy_stm32::Config::default();
26 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16;
27 config.rcc.enable_hsi48 = true;
28 let p = embassy_stm32::init(config);
29
30 // SPI for sx1276
31 let spi = spi::Spi::new(
32 p.SPI1,
33 p.PB3,
34 p.PA7,
35 p.PA6,
36 p.DMA1_CH3,
37 p.DMA1_CH2,
38 khz(200),
39 spi::Config::default(),
40 );
41
42 let nss = Output::new(p.PA15.degrade(), Level::High, Speed::Low);
43 let reset = Output::new(p.PC0.degrade(), Level::High, Speed::Low);
44
45 let irq_pin = Input::new(p.PB4.degrade(), Pull::Up);
46 let irq = ExtiInput::new(irq_pin, p.EXTI4.degrade());
47
48 let iv = Stm32l0InterfaceVariant::new(nss, reset, irq, None, None).unwrap();
49
50 let mut delay = Delay;
51
52 let mut lora = {
53 match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), false, &mut delay).await {
54 Ok(l) => l,
55 Err(err) => {
56 info!("Radio error = {}", err);
57 return;
58 }
59 }
60 };
61
62 let mut debug_indicator = Output::new(p.PB5, Level::Low, Speed::Low);
63 let mut start_indicator = Output::new(p.PB6, Level::Low, Speed::Low);
64
65 start_indicator.set_high();
66 Timer::after(Duration::from_secs(5)).await;
67 start_indicator.set_low();
68
69 let mut receiving_buffer = [00u8; 100];
70
71 let mdltn_params = {
72 match lora.create_modulation_params(
73 SpreadingFactor::_10,
74 Bandwidth::_250KHz,
75 CodingRate::_4_8,
76 LORA_FREQUENCY_IN_HZ,
77 ) {
78 Ok(mp) => mp,
79 Err(err) => {
80 info!("Radio error = {}", err);
81 return;
82 }
83 }
84 };
85
86 let rx_pkt_params = {
87 match lora.create_rx_packet_params(4, false, receiving_buffer.len() as u8, true, false, &mdltn_params) {
88 Ok(pp) => pp,
89 Err(err) => {
90 info!("Radio error = {}", err);
91 return;
92 }
93 }
94 };
95
96 match lora
97 .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, true, false, 0, 0x00ffffffu32)
98 .await
99 {
100 Ok(()) => {}
101 Err(err) => {
102 info!("Radio error = {}", err);
103 return;
104 }
105 };
106
107 loop {
108 receiving_buffer = [00u8; 100];
109 match lora.rx(&rx_pkt_params, &mut receiving_buffer).await {
110 Ok((received_len, _rx_pkt_status)) => {
111 if (received_len == 3)
112 && (receiving_buffer[0] == 0x01u8)
113 && (receiving_buffer[1] == 0x02u8)
114 && (receiving_buffer[2] == 0x03u8)
115 {
116 info!("rx successful");
117 debug_indicator.set_high();
118 Timer::after(Duration::from_secs(5)).await;
119 debug_indicator.set_low();
120 } else {
121 info!("rx unknown packet");
122 }
123 }
124 Err(err) => info!("rx unsuccessful = {}", err),
125 }
126 }
127}
diff --git a/examples/stm32l0/src/bin/lora_p2p_send.rs b/examples/stm32l0/src/bin/lora_p2p_send.rs
new file mode 100644
index 000000000..e6fadc01d
--- /dev/null
+++ b/examples/stm32l0/src/bin/lora_p2p_send.rs
@@ -0,0 +1,110 @@
1//! This example runs on the STM32 LoRa Discovery board, which has a builtin Semtech Sx1276 radio.
2//! It demonstrates LORA P2P send functionality.
3#![no_std]
4#![no_main]
5#![macro_use]
6#![feature(type_alias_impl_trait)]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_lora::iv::Stm32l0InterfaceVariant;
11use embassy_stm32::exti::{Channel, ExtiInput};
12use embassy_stm32::gpio::{Input, Level, Output, Pin, Pull, Speed};
13use embassy_stm32::spi;
14use embassy_stm32::time::khz;
15use embassy_time::Delay;
16use lora_phy::mod_params::*;
17use lora_phy::sx1276_7_8_9::SX1276_7_8_9;
18use lora_phy::LoRa;
19use {defmt_rtt as _, panic_probe as _};
20
21const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
22
23#[embassy_executor::main]
24async fn main(_spawner: Spawner) {
25 let mut config = embassy_stm32::Config::default();
26 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16;
27 config.rcc.enable_hsi48 = true;
28 let p = embassy_stm32::init(config);
29
30 // SPI for sx1276
31 let spi = spi::Spi::new(
32 p.SPI1,
33 p.PB3,
34 p.PA7,
35 p.PA6,
36 p.DMA1_CH3,
37 p.DMA1_CH2,
38 khz(200),
39 spi::Config::default(),
40 );
41
42 let nss = Output::new(p.PA15.degrade(), Level::High, Speed::Low);
43 let reset = Output::new(p.PC0.degrade(), Level::High, Speed::Low);
44
45 let irq_pin = Input::new(p.PB4.degrade(), Pull::Up);
46 let irq = ExtiInput::new(irq_pin, p.EXTI4.degrade());
47
48 let iv = Stm32l0InterfaceVariant::new(nss, reset, irq, None, None).unwrap();
49
50 let mut delay = Delay;
51
52 let mut lora = {
53 match LoRa::new(SX1276_7_8_9::new(BoardType::Stm32l0Sx1276, spi, iv), false, &mut delay).await {
54 Ok(l) => l,
55 Err(err) => {
56 info!("Radio error = {}", err);
57 return;
58 }
59 }
60 };
61
62 let mdltn_params = {
63 match lora.create_modulation_params(
64 SpreadingFactor::_10,
65 Bandwidth::_250KHz,
66 CodingRate::_4_8,
67 LORA_FREQUENCY_IN_HZ,
68 ) {
69 Ok(mp) => mp,
70 Err(err) => {
71 info!("Radio error = {}", err);
72 return;
73 }
74 }
75 };
76
77 let mut tx_pkt_params = {
78 match lora.create_tx_packet_params(4, false, true, false, &mdltn_params) {
79 Ok(pp) => pp,
80 Err(err) => {
81 info!("Radio error = {}", err);
82 return;
83 }
84 }
85 };
86
87 match lora.prepare_for_tx(&mdltn_params, 17, true).await {
88 Ok(()) => {}
89 Err(err) => {
90 info!("Radio error = {}", err);
91 return;
92 }
93 };
94
95 let buffer = [0x01u8, 0x02u8, 0x03u8];
96 match lora.tx(&mdltn_params, &mut tx_pkt_params, &buffer, 0xffffff).await {
97 Ok(()) => {
98 info!("TX DONE");
99 }
100 Err(err) => {
101 info!("Radio error = {}", err);
102 return;
103 }
104 };
105
106 match lora.sleep(&mut delay).await {
107 Ok(()) => info!("Sleep successful"),
108 Err(err) => info!("Sleep unsuccessful = {}", err),
109 }
110}
diff --git a/examples/stm32l0/src/bin/lorawan.rs b/examples/stm32l0/src/bin/lorawan.rs
deleted file mode 100644
index 303558b96..000000000
--- a/examples/stm32l0/src/bin/lorawan.rs
+++ /dev/null
@@ -1,75 +0,0 @@
1//! This example runs on the STM32 LoRa Discovery board which has a builtin Semtech Sx127x radio
2#![no_std]
3#![no_main]
4#![macro_use]
5#![allow(dead_code)]
6#![feature(generic_associated_types)]
7#![feature(type_alias_impl_trait)]
8
9use embassy_executor::Spawner;
10use embassy_lora::sx127x::*;
11use embassy_lora::LoraTimer;
12use embassy_stm32::exti::ExtiInput;
13use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
14use embassy_stm32::rng::Rng;
15use embassy_stm32::spi;
16use embassy_stm32::time::khz;
17use lorawan::default_crypto::DefaultFactory as Crypto;
18use lorawan_device::async_device::{region, Device, JoinMode};
19use {defmt_rtt as _, panic_probe as _};
20
21#[embassy_executor::main]
22async fn main(_spawner: Spawner) {
23 let mut config = embassy_stm32::Config::default();
24 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16;
25 config.rcc.enable_hsi48 = true;
26 let p = embassy_stm32::init(config);
27
28 // SPI for sx127x
29 let spi = spi::Spi::new(
30 p.SPI1,
31 p.PB3,
32 p.PA7,
33 p.PA6,
34 p.DMA1_CH3,
35 p.DMA1_CH2,
36 khz(200),
37 spi::Config::default(),
38 );
39
40 let cs = Output::new(p.PA15, Level::High, Speed::Low);
41 let reset = Output::new(p.PC0, Level::High, Speed::Low);
42 let _ = Input::new(p.PB1, Pull::None);
43
44 let ready = Input::new(p.PB4, Pull::Up);
45 let ready_pin = ExtiInput::new(ready, p.EXTI4);
46
47 let radio = Sx127xRadio::new(spi, cs, reset, ready_pin, DummySwitch).await.unwrap();
48
49 let region = region::EU868::default().into();
50 let mut device: Device<_, Crypto, _, _> = Device::new(region, radio, LoraTimer, Rng::new(p.RNG));
51
52 defmt::info!("Joining LoRaWAN network");
53
54 // TODO: Adjust the EUI and Keys according to your network credentials
55 device
56 .join(&JoinMode::OTAA {
57 deveui: [0, 0, 0, 0, 0, 0, 0, 0],
58 appeui: [0, 0, 0, 0, 0, 0, 0, 0],
59 appkey: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
60 })
61 .await
62 .ok()
63 .unwrap();
64 defmt::info!("LoRaWAN network joined");
65
66 defmt::info!("Sending 'PING'");
67 device.send(b"PING", 1, false).await.ok().unwrap();
68 defmt::info!("Message sent!");
69}
70
71pub struct DummySwitch;
72impl RadioSwitch for DummySwitch {
73 fn set_rx(&mut self) {}
74 fn set_tx(&mut self) {}
75}
diff --git a/examples/stm32l0/src/bin/usart_dma.rs b/examples/stm32l0/src/bin/usart_dma.rs
index 66657d0f0..eae8f3452 100644
--- a/examples/stm32l0/src/bin/usart_dma.rs
+++ b/examples/stm32l0/src/bin/usart_dma.rs
@@ -5,12 +5,17 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::usart::{Config, Uart}; 7use embassy_stm32::usart::{Config, Uart};
8use embassy_stm32::{bind_interrupts, peripherals, usart};
8use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
9 10
11bind_interrupts!(struct Irqs {
12 USART1 => usart::InterruptHandler<peripherals::USART1>;
13});
14
10#[embassy_executor::main] 15#[embassy_executor::main]
11async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 17 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()); 18 let mut usart = Uart::new(p.USART1, p.PB7, p.PB6, Irqs, p.DMA1_CH2, p.DMA1_CH3, Config::default());
14 19
15 usart.write(b"Hello Embassy World!\r\n").await.unwrap(); 20 usart.write(b"Hello Embassy World!\r\n").await.unwrap();
16 info!("wrote Hello, starting echo"); 21 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..f2c72a107 100644
--- a/examples/stm32l0/src/bin/usart_irq.rs
+++ b/examples/stm32l0/src/bin/usart_irq.rs
@@ -4,12 +4,15 @@
4 4
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma; 7use embassy_stm32::usart::{BufferedUart, Config};
8use embassy_stm32::interrupt; 8use embassy_stm32::{bind_interrupts, peripherals, usart};
9use embassy_stm32::usart::{BufferedUart, Config, State, Uart};
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
12bind_interrupts!(struct Irqs {
13 USART2 => usart::BufferedInterruptHandler<peripherals::USART2>;
14});
15
13#[embassy_executor::main] 16#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
15 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init(Default::default());
@@ -21,17 +24,7 @@ async fn main(_spawner: Spawner) {
21 let mut config = Config::default(); 24 let mut config = Config::default();
22 config.baudrate = 9600; 25 config.baudrate = 9600;
23 26
24 let usart = Uart::new(p.USART2, p.PA3, p.PA2, NoDma, NoDma, config); 27 let mut usart = unsafe { BufferedUart::new(p.USART2, Irqs, p.PA3, p.PA2, &mut TX_BUFFER, &mut RX_BUFFER, config) };
25 let mut state = State::new();
26 let mut usart = unsafe {
27 BufferedUart::new(
28 &mut state,
29 usart,
30 interrupt::take!(USART2),
31 &mut TX_BUFFER,
32 &mut RX_BUFFER,
33 )
34 };
35 28
36 usart.write_all(b"Hello Embassy World!\r\n").await.unwrap(); 29 usart.write_all(b"Hello Embassy World!\r\n").await.unwrap();
37 info!("wrote Hello, starting echo"); 30 info!("wrote Hello, starting echo");
diff --git a/examples/stm32l1/.cargo/config.toml b/examples/stm32l1/.cargo/config.toml
index 404b6b55c..9cabd14ba 100644
--- a/examples/stm32l1/.cargo/config.toml
+++ b/examples/stm32l1/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-run --list-chips` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32L151CBxxA" 3runner = "probe-rs run --chip STM32L151CBxxA"
4 4
5[build] 5[build]
6target = "thumbv7m-none-eabi" 6target = "thumbv7m-none-eabi"
diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml
index 18b35b305..dcca1cc3d 100644
--- a/examples/stm32l1/Cargo.toml
+++ b/examples/stm32l1/Cargo.toml
@@ -2,17 +2,18 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32l1-examples" 3name = "embassy-stm32l1-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
10embassy-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"] }
11 12
12defmt = "0.3" 13defmt = "0.3"
13defmt-rtt = "0.3" 14defmt-rtt = "0.4"
14 15
15cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 16cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
16cortex-m-rt = "0.7.0" 17cortex-m-rt = "0.7.0"
17embedded-hal = "0.2.6" 18embedded-hal = "0.2.6"
18panic-probe = { version = "0.3", features = ["print-defmt"] } 19panic-probe = { version = "0.3", features = ["print-defmt"] }
diff --git a/examples/stm32l1/src/bin/flash.rs b/examples/stm32l1/src/bin/flash.rs
index a76b9879f..aeb535cca 100644
--- a/examples/stm32l1/src/bin/flash.rs
+++ b/examples/stm32l1/src/bin/flash.rs
@@ -5,7 +5,6 @@
5use defmt::{info, unwrap}; 5use defmt::{info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::flash::Flash; 7use embassy_stm32::flash::Flash;
8use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
10 9
11#[embassy_executor::main] 10#[embassy_executor::main]
@@ -15,27 +14,27 @@ async fn main(_spawner: Spawner) {
15 14
16 const ADDR: u32 = 0x26000; 15 const ADDR: u32 = 0x26000;
17 16
18 let mut f = Flash::unlock(p.FLASH); 17 let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region;
19 18
20 info!("Reading..."); 19 info!("Reading...");
21 let mut buf = [0u8; 8]; 20 let mut buf = [0u8; 8];
22 unwrap!(f.read(ADDR, &mut buf)); 21 unwrap!(f.blocking_read(ADDR, &mut buf));
23 info!("Read: {=[u8]:x}", buf); 22 info!("Read: {=[u8]:x}", buf);
24 23
25 info!("Erasing..."); 24 info!("Erasing...");
26 unwrap!(f.erase(ADDR, ADDR + 256)); 25 unwrap!(f.blocking_erase(ADDR, ADDR + 256));
27 26
28 info!("Reading..."); 27 info!("Reading...");
29 let mut buf = [0u8; 8]; 28 let mut buf = [0u8; 8];
30 unwrap!(f.read(ADDR, &mut buf)); 29 unwrap!(f.blocking_read(ADDR, &mut buf));
31 info!("Read after erase: {=[u8]:x}", buf); 30 info!("Read after erase: {=[u8]:x}", buf);
32 31
33 info!("Writing..."); 32 info!("Writing...");
34 unwrap!(f.write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); 33 unwrap!(f.blocking_write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8]));
35 34
36 info!("Reading..."); 35 info!("Reading...");
37 let mut buf = [0u8; 8]; 36 let mut buf = [0u8; 8];
38 unwrap!(f.read(ADDR, &mut buf)); 37 unwrap!(f.blocking_read(ADDR, &mut buf));
39 info!("Read: {=[u8]:x}", buf); 38 info!("Read: {=[u8]:x}", buf);
40 assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]); 39 assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
41} 40}
diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml
index 5534053c5..36e74e5a5 100644
--- a/examples/stm32l4/.cargo/config.toml
+++ b/examples/stm32l4/.cargo/config.toml
@@ -1,8 +1,8 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32F429ZITx with your chip as listed in `probe-run --list-chips` 2# replace STM32F429ZITx with your chip as listed in `probe-rs chip list`
3#runner = "probe-run --chip STM32L475VGT6" 3#runner = "probe-rs run --chip STM32L475VGT6"
4#runner = "probe-run --chip STM32L475VG" 4#runner = "probe-rs run --chip STM32L475VG"
5runner = "probe-run --chip STM32L4S5VI" 5runner = "probe-rs run --chip STM32L4S5VI"
6 6
7[build] 7[build]
8target = "thumbv7em-none-eabi" 8target = "thumbv7em-none-eabi"
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index cb7238e4c..c55558518 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -2,29 +2,27 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32l4-examples" 3name = "embassy-stm32l4-examples"
4version = "0.1.0" 4version = "0.1.0"
5 5license = "MIT OR Apache-2.0"
6[features]
7 6
8[dependencies] 7[dependencies]
9embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
11embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
12embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 11embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
13embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits"] } 12embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5vi", "time-driver-any", "exti", "unstable-traits", "chrono"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
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"
20embedded-hal = "0.2.6" 20embedded-hal = "0.2.6"
21embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.8" } 21embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.11" }
22embedded-hal-async = { version = "0.1.0-alpha.1" } 22embedded-hal-async = { version = "=0.2.0-alpha.2" }
23panic-probe = { version = "0.3", features = ["print-defmt"] } 23panic-probe = { version = "0.3", features = ["print-defmt"] }
24futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 24futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
25heapless = { version = "0.7.5", default-features = false } 25heapless = { version = "0.7.5", default-features = false }
26chrono = { version = "^0.4", default-features = false }
26 27
27micromath = "2.0.0" 28micromath = "2.0.0"
28usb-device = "0.2"
29usbd-serial = "0.1.1"
30
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs
index 281346e5f..1771e5202 100644
--- a/examples/stm32l4/src/bin/adc.rs
+++ b/examples/stm32l4/src/bin/adc.rs
@@ -12,12 +12,10 @@ use {defmt_rtt as _, panic_probe as _};
12fn main() -> ! { 12fn main() -> ! {
13 info!("Hello World!"); 13 info!("Hello World!");
14 14
15 unsafe { 15 pac::RCC.ccipr().modify(|w| {
16 pac::RCC.ccipr().modify(|w| { 16 w.set_adcsel(0b11);
17 w.set_adcsel(0b11); 17 });
18 }); 18 pac::RCC.ahb2enr().modify(|w| w.set_adcen(true));
19 pac::RCC.ahb2enr().modify(|w| w.set_adcen(true));
20 }
21 19
22 let p = embassy_stm32::init(Default::default()); 20 let p = embassy_stm32::init(Default::default());
23 21
diff --git a/examples/stm32l4/src/bin/dac.rs b/examples/stm32l4/src/bin/dac.rs
index d6e744aa6..ade43eb35 100644
--- a/examples/stm32l4/src/bin/dac.rs
+++ b/examples/stm32l4/src/bin/dac.rs
@@ -3,28 +3,21 @@
3#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
4 4
5use defmt::*; 5use defmt::*;
6use embassy_stm32::dac::{Channel, Dac, Value}; 6use embassy_stm32::dac::{DacCh1, DacChannel, Value};
7use embassy_stm32::pac; 7use embassy_stm32::dma::NoDma;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[cortex_m_rt::entry] 10#[cortex_m_rt::entry]
11fn main() -> ! { 11fn main() -> ! {
12 info!("Hello World!");
13
14 unsafe {
15 pac::RCC.apb1enr1().modify(|w| {
16 w.set_dac1en(true);
17 });
18 }
19
20 let p = embassy_stm32::init(Default::default()); 12 let p = embassy_stm32::init(Default::default());
13 info!("Hello World!");
21 14
22 let mut dac = Dac::new_1ch(p.DAC1, p.PA4); 15 let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
23 16
24 loop { 17 loop {
25 for v in 0..=255 { 18 for v in 0..=255 {
26 unwrap!(dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v)))); 19 unwrap!(dac.set(Value::Bit8(to_sine_wave(v))));
27 unwrap!(dac.trigger(Channel::Ch1)); 20 dac.trigger();
28 } 21 }
29 } 22 }
30} 23}
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs
new file mode 100644
index 000000000..c27cc03e1
--- /dev/null
+++ b/examples/stm32l4/src/bin/dac_dma.rs
@@ -0,0 +1,137 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::dac::{DacChannel, ValueArray};
8use embassy_stm32::pac::timer::vals::{Mms, Opm};
9use embassy_stm32::peripherals::{TIM6, TIM7};
10use embassy_stm32::rcc::low_level::RccPeripheral;
11use embassy_stm32::time::Hertz;
12use embassy_stm32::timer::low_level::Basic16bitInstance;
13use micromath::F32Ext;
14use {defmt_rtt as _, panic_probe as _};
15
16pub type Dac1Type =
17 embassy_stm32::dac::DacCh1<'static, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH3>;
18
19pub type Dac2Type =
20 embassy_stm32::dac::DacCh2<'static, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH4>;
21
22#[embassy_executor::main]
23async fn main(spawner: Spawner) {
24 let config = embassy_stm32::Config::default();
25
26 // Initialize the board and obtain a Peripherals instance
27 let p: embassy_stm32::Peripherals = embassy_stm32::init(config);
28
29 // Obtain two independent channels (p.DAC1 can only be consumed once, though!)
30 let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split();
31
32 spawner.spawn(dac_task1(dac_ch1)).ok();
33 spawner.spawn(dac_task2(dac_ch2)).ok();
34}
35
36#[embassy_executor::task]
37async fn dac_task1(mut dac: Dac1Type) {
38 let data: &[u8; 256] = &calculate_array::<256>();
39
40 info!("TIM6 frequency is {}", TIM6::frequency());
41 const FREQUENCY: Hertz = Hertz::hz(200);
42
43 // Compute the reload value such that we obtain the FREQUENCY for the sine
44 let reload: u32 = (TIM6::frequency().0 / FREQUENCY.0) / data.len() as u32;
45
46 // Depends on your clock and on the specific chip used, you may need higher or lower values here
47 if reload < 10 {
48 error!("Reload value {} below threshold!", reload);
49 }
50
51 dac.select_trigger(embassy_stm32::dac::Ch1Trigger::Tim6).unwrap();
52 dac.enable_channel().unwrap();
53
54 TIM6::enable();
55 TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
56 TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE));
57 TIM6::regs().cr1().modify(|w| {
58 w.set_opm(Opm::DISABLED);
59 w.set_cen(true);
60 });
61
62 debug!(
63 "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}",
64 TIM6::frequency(),
65 FREQUENCY,
66 reload,
67 reload as u16,
68 data.len()
69 );
70
71 // Loop technically not necessary if DMA circular mode is enabled
72 loop {
73 info!("Loop DAC1");
74 if let Err(e) = dac.write(ValueArray::Bit8(data), true).await {
75 error!("Could not write to dac: {}", e);
76 }
77 }
78}
79
80#[embassy_executor::task]
81async fn dac_task2(mut dac: Dac2Type) {
82 let data: &[u8; 256] = &calculate_array::<256>();
83
84 info!("TIM7 frequency is {}", TIM7::frequency());
85
86 const FREQUENCY: Hertz = Hertz::hz(600);
87 let reload: u32 = (TIM7::frequency().0 / FREQUENCY.0) / data.len() as u32;
88
89 if reload < 10 {
90 error!("Reload value {} below threshold!", reload);
91 }
92
93 TIM7::enable();
94 TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
95 TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE));
96 TIM7::regs().cr1().modify(|w| {
97 w.set_opm(Opm::DISABLED);
98 w.set_cen(true);
99 });
100
101 dac.select_trigger(embassy_stm32::dac::Ch2Trigger::Tim7).unwrap();
102
103 debug!(
104 "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}",
105 TIM7::frequency(),
106 FREQUENCY,
107 reload,
108 reload as u16,
109 data.len()
110 );
111
112 if let Err(e) = dac.write(ValueArray::Bit8(data), true).await {
113 error!("Could not write to dac: {}", e);
114 }
115}
116
117fn to_sine_wave(v: u8) -> u8 {
118 if v >= 128 {
119 // top half
120 let r = 3.14 * ((v - 128) as f32 / 128.0);
121 (r.sin() * 128.0 + 127.0) as u8
122 } else {
123 // bottom half
124 let r = 3.14 + 3.14 * (v as f32 / 128.0);
125 (r.sin() * 128.0 + 127.0) as u8
126 }
127}
128
129fn calculate_array<const N: usize>() -> [u8; N] {
130 let mut res = [0; N];
131 let mut i = 0;
132 while i < N {
133 res[i] = to_sine_wave(i as u8);
134 i += 1;
135 }
136 res
137}
diff --git a/examples/stm32l4/src/bin/i2c.rs b/examples/stm32l4/src/bin/i2c.rs
index d54c080c7..d0060d20c 100644
--- a/examples/stm32l4/src/bin/i2c.rs
+++ b/examples/stm32l4/src/bin/i2c.rs
@@ -6,22 +6,25 @@ use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::dma::NoDma; 7use embassy_stm32::dma::NoDma;
8use embassy_stm32::i2c::I2c; 8use embassy_stm32::i2c::I2c;
9use embassy_stm32::interrupt;
10use embassy_stm32::time::Hertz; 9use embassy_stm32::time::Hertz;
10use embassy_stm32::{bind_interrupts, i2c, peripherals};
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13const ADDRESS: u8 = 0x5F; 13const ADDRESS: u8 = 0x5F;
14const WHOAMI: u8 = 0x0F; 14const WHOAMI: u8 = 0x0F;
15 15
16bind_interrupts!(struct Irqs {
17 I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>;
18});
19
16#[embassy_executor::main] 20#[embassy_executor::main]
17async fn main(_spawner: Spawner) -> ! { 21async fn main(_spawner: Spawner) {
18 let p = embassy_stm32::init(Default::default()); 22 let p = embassy_stm32::init(Default::default());
19 let irq = interrupt::take!(I2C2_EV);
20 let mut i2c = I2c::new( 23 let mut i2c = I2c::new(
21 p.I2C2, 24 p.I2C2,
22 p.PB10, 25 p.PB10,
23 p.PB11, 26 p.PB11,
24 irq, 27 Irqs,
25 NoDma, 28 NoDma,
26 NoDma, 29 NoDma,
27 Hertz(100_000), 30 Hertz(100_000),
diff --git a/examples/stm32l4/src/bin/i2c_blocking_async.rs b/examples/stm32l4/src/bin/i2c_blocking_async.rs
index 35a86660d..eca59087b 100644
--- a/examples/stm32l4/src/bin/i2c_blocking_async.rs
+++ b/examples/stm32l4/src/bin/i2c_blocking_async.rs
@@ -7,23 +7,26 @@ use embassy_embedded_hal::adapter::BlockingAsync;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_stm32::dma::NoDma; 8use embassy_stm32::dma::NoDma;
9use embassy_stm32::i2c::I2c; 9use embassy_stm32::i2c::I2c;
10use embassy_stm32::interrupt;
11use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
11use embassy_stm32::{bind_interrupts, i2c, peripherals};
12use embedded_hal_async::i2c::I2c as I2cTrait; 12use embedded_hal_async::i2c::I2c as I2cTrait;
13use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
14 14
15const ADDRESS: u8 = 0x5F; 15const ADDRESS: u8 = 0x5F;
16const WHOAMI: u8 = 0x0F; 16const WHOAMI: u8 = 0x0F;
17 17
18bind_interrupts!(struct Irqs {
19 I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>;
20});
21
18#[embassy_executor::main] 22#[embassy_executor::main]
19async fn main(_spawner: Spawner) -> ! { 23async fn main(_spawner: Spawner) {
20 let p = embassy_stm32::init(Default::default()); 24 let p = embassy_stm32::init(Default::default());
21 let irq = interrupt::take!(I2C2_EV);
22 let i2c = I2c::new( 25 let i2c = I2c::new(
23 p.I2C2, 26 p.I2C2,
24 p.PB10, 27 p.PB10,
25 p.PB11, 28 p.PB11,
26 irq, 29 Irqs,
27 NoDma, 30 NoDma,
28 NoDma, 31 NoDma,
29 Hertz(100_000), 32 Hertz(100_000),
diff --git a/examples/stm32l4/src/bin/i2c_dma.rs b/examples/stm32l4/src/bin/i2c_dma.rs
index 3ce9398a4..cf6f3da67 100644
--- a/examples/stm32l4/src/bin/i2c_dma.rs
+++ b/examples/stm32l4/src/bin/i2c_dma.rs
@@ -5,22 +5,25 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::i2c::I2c; 7use embassy_stm32::i2c::I2c;
8use embassy_stm32::interrupt;
9use embassy_stm32::time::Hertz; 8use embassy_stm32::time::Hertz;
9use embassy_stm32::{bind_interrupts, i2c, peripherals};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12const ADDRESS: u8 = 0x5F; 12const ADDRESS: u8 = 0x5F;
13const WHOAMI: u8 = 0x0F; 13const WHOAMI: u8 = 0x0F;
14 14
15bind_interrupts!(struct Irqs {
16 I2C2_EV => i2c::InterruptHandler<peripherals::I2C2>;
17});
18
15#[embassy_executor::main] 19#[embassy_executor::main]
16async fn main(_spawner: Spawner) -> ! { 20async fn main(_spawner: Spawner) {
17 let p = embassy_stm32::init(Default::default()); 21 let p = embassy_stm32::init(Default::default());
18 let irq = interrupt::take!(I2C2_EV);
19 let mut i2c = I2c::new( 22 let mut i2c = I2c::new(
20 p.I2C2, 23 p.I2C2,
21 p.PB10, 24 p.PB10,
22 p.PB11, 25 p.PB11,
23 irq, 26 Irqs,
24 p.DMA1_CH4, 27 p.DMA1_CH4,
25 p.DMA1_CH5, 28 p.DMA1_CH5,
26 Hertz(100_000), 29 Hertz(100_000),
diff --git a/examples/stm32l4/src/bin/mco.rs b/examples/stm32l4/src/bin/mco.rs
new file mode 100644
index 000000000..dea0c66e0
--- /dev/null
+++ b/examples/stm32l4/src/bin/mco.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_stm32::rcc::{Mco, Mco1Source, McoClock};
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_stm32::init(Default::default());
15 info!("Hello World!");
16
17 let _mco = Mco::new(p.MCO, p.PA8, Mco1Source::Hsi16, McoClock::DIV1);
18
19 let mut led = Output::new(p.PB14, Level::High, Speed::Low);
20
21 loop {
22 led.set_high();
23 Timer::after(Duration::from_millis(300)).await;
24 led.set_low();
25 Timer::after(Duration::from_millis(300)).await;
26 }
27}
diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs
new file mode 100644
index 000000000..d72d5ddb6
--- /dev/null
+++ b/examples/stm32l4/src/bin/rtc.rs
@@ -0,0 +1,49 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use chrono::{NaiveDate, NaiveDateTime};
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_stm32::rcc::{self, ClockSrc, PLLClkDiv, PLLMul, PLLSource, PLLSrcDiv};
9use embassy_stm32::rtc::{Rtc, RtcConfig};
10use embassy_stm32::time::Hertz;
11use embassy_stm32::Config;
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 = {
18 let mut config = Config::default();
19 config.rcc.mux = ClockSrc::PLL(
20 PLLSource::HSE(Hertz::mhz(8)),
21 PLLClkDiv::Div2,
22 PLLSrcDiv::Div1,
23 PLLMul::Mul20,
24 None,
25 );
26 config.rcc.rtc_mux = rcc::RtcClockSource::LSE32;
27 embassy_stm32::init(config)
28 };
29 info!("Hello World!");
30
31 let now = NaiveDate::from_ymd_opt(2020, 5, 15)
32 .unwrap()
33 .and_hms_opt(10, 30, 15)
34 .unwrap();
35
36 let mut rtc = Rtc::new(
37 p.RTC,
38 RtcConfig::default().clock_config(embassy_stm32::rtc::RtcClockSource::LSE),
39 );
40 info!("Got RTC! {:?}", now.timestamp());
41
42 rtc.set_datetime(now.into()).expect("datetime not set");
43
44 // In reality the delay would be much longer
45 Timer::after(Duration::from_millis(20000)).await;
46
47 let then: NaiveDateTime = rtc.now().unwrap().into();
48 info!("Got RTC! {:?}", then.timestamp());
49}
diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs
index 4a4b46c53..beb5ec558 100644
--- a/examples/stm32l4/src/bin/usart.rs
+++ b/examples/stm32l4/src/bin/usart.rs
@@ -5,8 +5,13 @@
5use defmt::*; 5use defmt::*;
6use embassy_stm32::dma::NoDma; 6use embassy_stm32::dma::NoDma;
7use embassy_stm32::usart::{Config, Uart}; 7use embassy_stm32::usart::{Config, Uart};
8use embassy_stm32::{bind_interrupts, peripherals, usart};
8use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
9 10
11bind_interrupts!(struct Irqs {
12 UART4 => usart::InterruptHandler<peripherals::UART4>;
13});
14
10#[cortex_m_rt::entry] 15#[cortex_m_rt::entry]
11fn main() -> ! { 16fn main() -> ! {
12 info!("Hello World!"); 17 info!("Hello World!");
@@ -14,7 +19,7 @@ fn main() -> ! {
14 let p = embassy_stm32::init(Default::default()); 19 let p = embassy_stm32::init(Default::default());
15 20
16 let config = Config::default(); 21 let config = Config::default();
17 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, NoDma, NoDma, config); 22 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, NoDma, NoDma, config);
18 23
19 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); 24 unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n"));
20 info!("wrote Hello, starting echo"); 25 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..b7d4cb01e 100644
--- a/examples/stm32l4/src/bin/usart_dma.rs
+++ b/examples/stm32l4/src/bin/usart_dma.rs
@@ -8,16 +8,21 @@ use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::dma::NoDma; 9use embassy_stm32::dma::NoDma;
10use embassy_stm32::usart::{Config, Uart}; 10use embassy_stm32::usart::{Config, Uart};
11use embassy_stm32::{bind_interrupts, peripherals, usart};
11use heapless::String; 12use heapless::String;
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
13 14
15bind_interrupts!(struct Irqs {
16 UART4 => usart::InterruptHandler<peripherals::UART4>;
17});
18
14#[embassy_executor::main] 19#[embassy_executor::main]
15async fn main(_spawner: Spawner) { 20async fn main(_spawner: Spawner) {
16 let p = embassy_stm32::init(Default::default()); 21 let p = embassy_stm32::init(Default::default());
17 info!("Hello World!"); 22 info!("Hello World!");
18 23
19 let config = Config::default(); 24 let config = Config::default();
20 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, p.DMA1_CH3, NoDma, config); 25 let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, NoDma, config);
21 26
22 for n in 0u32.. { 27 for n in 0u32.. {
23 let mut s: String<128> = String::new(); 28 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..410d6891b
--- /dev/null
+++ b/examples/stm32l4/src/bin/usb_serial.rs
@@ -0,0 +1,112 @@
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::{bind_interrupts, peripherals, usb_otg, 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
17bind_interrupts!(struct Irqs {
18 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
19});
20
21#[embassy_executor::main]
22async fn main(_spawner: Spawner) {
23 info!("Hello World!");
24
25 let mut config = Config::default();
26 config.rcc.mux = ClockSrc::PLL(PLLSource::HSI16, PLLClkDiv::Div2, PLLSrcDiv::Div1, PLLMul::Mul10, None);
27 config.rcc.hsi48 = true;
28
29 let p = embassy_stm32::init(config);
30
31 // Create the driver, from the HAL.
32 let mut ep_out_buffer = [0u8; 256];
33 let mut config = embassy_stm32::usb_otg::Config::default();
34 config.vbus_detection = true;
35 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
36
37 // Create embassy-usb Config
38 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
39 config.max_packet_size_0 = 64;
40 config.manufacturer = Some("Embassy");
41 config.product = Some("USB-serial example");
42 config.serial_number = Some("12345678");
43
44 // Required for windows compatibility.
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 control_buf = [0; 64];
57
58 let mut state = State::new();
59
60 let mut builder = Builder::new(
61 driver,
62 config,
63 &mut device_descriptor,
64 &mut config_descriptor,
65 &mut bos_descriptor,
66 &mut control_buf,
67 );
68
69 // Create classes on the builder.
70 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
71
72 // Build the builder.
73 let mut usb = builder.build();
74
75 // Run the USB device.
76 let usb_fut = usb.run();
77
78 // Do stuff with the class!
79 let echo_fut = async {
80 loop {
81 class.wait_connection().await;
82 info!("Connected");
83 let _ = echo(&mut class).await;
84 info!("Disconnected");
85 }
86 };
87
88 // Run everything concurrently.
89 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
90 join(usb_fut, echo_fut).await;
91}
92
93struct Disconnected {}
94
95impl From<EndpointError> for Disconnected {
96 fn from(val: EndpointError) -> Self {
97 match val {
98 EndpointError::BufferOverflow => panic!("Buffer overflow"),
99 EndpointError::Disabled => Disconnected {},
100 }
101 }
102}
103
104async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
105 let mut buf = [0; 64];
106 loop {
107 let n = class.read_packet(&mut buf).await?;
108 let data = &buf[..n];
109 info!("data: {:x}", data);
110 class.write_packet(data).await?;
111 }
112}
diff --git a/examples/stm32l5/.cargo/config.toml b/examples/stm32l5/.cargo/config.toml
index f2af6b556..86a145a27 100644
--- a/examples/stm32l5/.cargo/config.toml
+++ b/examples/stm32l5/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32L552ZETxQ with your chip as listed in `probe-run --list-chips` 2# replace STM32L552ZETxQ with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32L552ZETxQ" 3runner = "probe-rs run --chip STM32L552ZETxQ"
4 4
5[build] 5[build]
6target = "thumbv8m.main-none-eabihf" 6target = "thumbv8m.main-none-eabihf"
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index 624c73c26..54911482e 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -2,30 +2,27 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32l5-examples" 3name = "embassy-stm32l5-examples"
4version = "0.1.0" 4version = "0.1.0"
5 5license = "MIT OR Apache-2.0"
6[features]
7 6
8[dependencies] 7[dependencies]
9embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
11embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
12embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] }
13embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-usb-serial = { version = "0.1.0", path = "../../embassy-usb-serial", features = ["defmt"] } 13embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
15embassy-usb-hid = { version = "0.1.0", path = "../../embassy-usb-hid", features = ["defmt"] } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
16embassy-usb-ncm = { version = "0.1.0", path = "../../embassy-usb-ncm", features = ["defmt"] } 15usbd-hid = "0.6.0"
17embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "pool-16"] }
18usbd-hid = "0.5.2"
19 16
20defmt = "0.3" 17defmt = "0.3"
21defmt-rtt = "0.3" 18defmt-rtt = "0.4"
22panic-probe = { version = "0.3", features = ["print-defmt"] } 19panic-probe = { version = "0.3", features = ["print-defmt"] }
23 20
24cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
25cortex-m-rt = "0.7.0" 22cortex-m-rt = "0.7.0"
26embedded-hal = "0.2.6" 23embedded-hal = "0.2.6"
27futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 24futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
28heapless = { version = "0.7.5", default-features = false } 25heapless = { version = "0.7.5", default-features = false }
29rand_core = { version = "0.6.3", default-features = false } 26rand_core = { version = "0.6.3", default-features = false }
30embedded-io = { version = "0.3.0", features = ["async"] } 27embedded-io = { version = "0.4.0", features = ["async"] }
31static_cell = "1.0" 28static_cell = { version = "1.1", features = ["nightly"]}
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index 3286f5c4d..32eba4277 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -1,38 +1,30 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
5 4
6use core::sync::atomic::{AtomicBool, Ordering};
7use core::task::Waker;
8
9use defmt::*; 5use defmt::*;
10use embassy_executor::Spawner; 6use embassy_executor::Spawner;
11use embassy_net::tcp::TcpSocket; 7use embassy_net::tcp::TcpSocket;
12use embassy_net::{PacketBox, PacketBoxExt, PacketBuf, Stack, StackResources}; 8use embassy_net::{Stack, StackResources};
13use embassy_stm32::rcc::*; 9use embassy_stm32::rcc::*;
14use embassy_stm32::rng::Rng; 10use embassy_stm32::rng::Rng;
15use embassy_stm32::time::Hertz;
16use embassy_stm32::usb::Driver; 11use embassy_stm32::usb::Driver;
17use embassy_stm32::{interrupt, Config}; 12use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
18use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; 13use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
19use embassy_sync::channel::Channel; 14use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
20use embassy_usb::{Builder, UsbDevice}; 15use embassy_usb::{Builder, UsbDevice};
21use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State}; 16use embedded_io::asynch::Write;
22use embedded_io::asynch::{Read, Write};
23use rand_core::RngCore; 17use rand_core::RngCore;
24use static_cell::StaticCell; 18use static_cell::make_static;
25use {defmt_rtt as _, panic_probe as _}; 19use {defmt_rtt as _, panic_probe as _};
26 20
27type MyDriver = Driver<'static, embassy_stm32::peripherals::USB>; 21type MyDriver = Driver<'static, embassy_stm32::peripherals::USB>;
28 22
29macro_rules! singleton { 23const MTU: usize = 1514;
30 ($val:expr) => {{ 24
31 type T = impl Sized; 25bind_interrupts!(struct Irqs {
32 static STATIC_CELL: StaticCell<T> = StaticCell::new(); 26 USB_FS => usb::InterruptHandler<peripherals::USB>;
33 STATIC_CELL.init_with(move || $val) 27});
34 }};
35}
36 28
37#[embassy_executor::task] 29#[embassy_executor::task]
38async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! { 30async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! {
@@ -40,46 +32,12 @@ async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! {
40} 32}
41 33
42#[embassy_executor::task] 34#[embassy_executor::task]
43async fn usb_ncm_rx_task(mut class: Receiver<'static, MyDriver>) { 35async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
44 loop { 36 class.run().await
45 warn!("WAITING for connection");
46 LINK_UP.store(false, Ordering::Relaxed);
47
48 class.wait_connection().await.unwrap();
49
50 warn!("Connected");
51 LINK_UP.store(true, Ordering::Relaxed);
52
53 loop {
54 let mut p = unwrap!(PacketBox::new(embassy_net::Packet::new()));
55 let n = match class.read_packet(&mut p[..]).await {
56 Ok(n) => n,
57 Err(e) => {
58 warn!("error reading packet: {:?}", e);
59 break;
60 }
61 };
62
63 let buf = p.slice(0..n);
64 if RX_CHANNEL.try_send(buf).is_err() {
65 warn!("Failed pushing rx'd packet to channel.");
66 }
67 }
68 }
69} 37}
70 38
71#[embassy_executor::task] 39#[embassy_executor::task]
72async fn usb_ncm_tx_task(mut class: Sender<'static, MyDriver>) { 40async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
73 loop {
74 let pkt = TX_CHANNEL.recv().await;
75 if let Err(e) = class.write_packet(&pkt[..]).await {
76 warn!("Failed to TX packet: {:?}", e);
77 }
78 }
79}
80
81#[embassy_executor::task]
82async fn net_task(stack: &'static Stack<Device>) -> ! {
83 stack.run().await 41 stack.run().await
84} 42}
85 43
@@ -91,8 +49,7 @@ async fn main(spawner: Spawner) {
91 let p = embassy_stm32::init(config); 49 let p = embassy_stm32::init(config);
92 50
93 // Create the driver, from the HAL. 51 // Create the driver, from the HAL.
94 let irq = interrupt::take!(USB_FS); 52 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
95 let driver = Driver::new(p.USB, irq, p.PA12, p.PA11);
96 53
97 // Create embassy-usb Config 54 // Create embassy-usb Config
98 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 55 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
@@ -108,58 +65,34 @@ async fn main(spawner: Spawner) {
108 config.device_sub_class = 0x02; 65 config.device_sub_class = 0x02;
109 config.device_protocol = 0x01; 66 config.device_protocol = 0x01;
110 67
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. 68 // Create embassy-usb DeviceBuilder using the driver and config.
127 let mut builder = Builder::new( 69 let mut builder = Builder::new(
128 driver, 70 driver,
129 config, 71 config,
130 &mut res.device_descriptor, 72 &mut make_static!([0; 256])[..],
131 &mut res.config_descriptor, 73 &mut make_static!([0; 256])[..],
132 &mut res.bos_descriptor, 74 &mut make_static!([0; 256])[..],
133 &mut res.control_buf, 75 &mut make_static!([0; 128])[..],
134 None,
135 ); 76 );
136 77
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. 78 // Our MAC addr.
145 let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC]; 79 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. 80 // 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]; 81 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
148 82
149 // Create classes on the builder. 83 // Create classes on the builder.
150 let class = CdcNcmClass::new(&mut builder, &mut res.serial_state, host_mac_addr, 64); 84 let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64);
151 85
152 // Build the builder. 86 // Build the builder.
153 let usb = builder.build(); 87 let usb = builder.build();
154 88
155 unwrap!(spawner.spawn(usb_task(usb))); 89 unwrap!(spawner.spawn(usb_task(usb)));
156 90
157 let (tx, rx) = class.split(); 91 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr);
158 unwrap!(spawner.spawn(usb_ncm_rx_task(rx))); 92 unwrap!(spawner.spawn(usb_ncm_task(runner)));
159 unwrap!(spawner.spawn(usb_ncm_tx_task(tx)));
160 93
161 let config = embassy_net::ConfigStrategy::Dhcp; 94 let config = embassy_net::Config::dhcpv4(Default::default());
162 //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { 95 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
163 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), 96 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
164 // dns_servers: Vec::new(), 97 // dns_servers: Vec::new(),
165 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), 98 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
@@ -170,11 +103,10 @@ async fn main(spawner: Spawner) {
170 let seed = rng.next_u64(); 103 let seed = rng.next_u64();
171 104
172 // Init network stack 105 // Init network stack
173 let device = Device { mac_addr: our_mac_addr }; 106 let stack = &*make_static!(Stack::new(
174 let stack = &*singleton!(Stack::new(
175 device, 107 device,
176 config, 108 config,
177 singleton!(StackResources::<1, 2, 8>::new()), 109 make_static!(StackResources::<2>::new()),
178 seed 110 seed
179 )); 111 ));
180 112
@@ -188,7 +120,7 @@ async fn main(spawner: Spawner) {
188 120
189 loop { 121 loop {
190 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); 122 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
191 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10))); 123 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
192 124
193 info!("Listening on TCP:1234..."); 125 info!("Listening on TCP:1234...");
194 if let Err(e) = socket.accept(1234).await { 126 if let Err(e) = socket.accept(1234).await {
@@ -223,50 +155,3 @@ async fn main(spawner: Spawner) {
223 } 155 }
224 } 156 }
225} 157}
226
227static TX_CHANNEL: Channel<ThreadModeRawMutex, PacketBuf, 8> = Channel::new();
228static RX_CHANNEL: Channel<ThreadModeRawMutex, PacketBuf, 8> = Channel::new();
229static LINK_UP: AtomicBool = AtomicBool::new(false);
230
231struct Device {
232 mac_addr: [u8; 6],
233}
234
235impl embassy_net::Device for Device {
236 fn register_waker(&mut self, waker: &Waker) {
237 // loopy loopy wakey wakey
238 waker.wake_by_ref()
239 }
240
241 fn link_state(&mut self) -> embassy_net::LinkState {
242 match LINK_UP.load(Ordering::Relaxed) {
243 true => embassy_net::LinkState::Up,
244 false => embassy_net::LinkState::Down,
245 }
246 }
247
248 fn capabilities(&self) -> embassy_net::DeviceCapabilities {
249 let mut caps = embassy_net::DeviceCapabilities::default();
250 caps.max_transmission_unit = 1514; // 1500 IP + 14 ethernet header
251 caps.medium = embassy_net::Medium::Ethernet;
252 caps
253 }
254
255 fn is_transmit_ready(&mut self) -> bool {
256 true
257 }
258
259 fn transmit(&mut self, pkt: PacketBuf) {
260 if TX_CHANNEL.try_send(pkt).is_err() {
261 warn!("TX failed")
262 }
263 }
264
265 fn receive<'a>(&mut self) -> Option<PacketBuf> {
266 RX_CHANNEL.try_recv().ok()
267 }
268
269 fn ethernet_address(&self) -> [u8; 6] {
270 self.mac_addr
271 }
272}
diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs
index f7e3d93e3..7e894e407 100644
--- a/examples/stm32l5/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs
@@ -1,22 +1,24 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)] 3#![feature(type_alias_impl_trait)]
5 4
6use defmt::*; 5use defmt::*;
7use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_futures::join::join;
8use embassy_stm32::rcc::*; 8use embassy_stm32::rcc::*;
9use embassy_stm32::time::Hertz;
10use embassy_stm32::usb::Driver; 9use embassy_stm32::usb::Driver;
11use embassy_stm32::{interrupt, Config, Peripherals}; 10use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
12use embassy_time::{Duration, Timer}; 11use embassy_time::{Duration, Timer};
12use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
13use embassy_usb::control::OutResponse; 13use embassy_usb::control::OutResponse;
14use embassy_usb::Builder; 14use embassy_usb::Builder;
15use embassy_usb_hid::{HidWriter, ReportId, RequestHandler, State};
16use futures::future::join;
17use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; 15use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
18use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
19 17
18bind_interrupts!(struct Irqs {
19 USB_FS => usb::InterruptHandler<peripherals::USB>;
20});
21
20#[embassy_executor::main] 22#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 23async fn main(_spawner: Spawner) {
22 let mut config = Config::default(); 24 let mut config = Config::default();
@@ -25,8 +27,7 @@ async fn main(_spawner: Spawner) {
25 let p = embassy_stm32::init(config); 27 let p = embassy_stm32::init(config);
26 28
27 // Create the driver, from the HAL. 29 // Create the driver, from the HAL.
28 let irq = interrupt::take!(USB_FS); 30 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
29 let driver = Driver::new(p.USB, irq, p.PA12, p.PA11);
30 31
31 // Create embassy-usb Config 32 // Create embassy-usb Config
32 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 33 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
@@ -53,11 +54,10 @@ async fn main(_spawner: Spawner) {
53 &mut config_descriptor, 54 &mut config_descriptor,
54 &mut bos_descriptor, 55 &mut bos_descriptor,
55 &mut control_buf, 56 &mut control_buf,
56 None,
57 ); 57 );
58 58
59 // Create classes on the builder. 59 // Create classes on the builder.
60 let config = embassy_usb_hid::Config { 60 let config = embassy_usb::class::hid::Config {
61 report_descriptor: MouseReport::desc(), 61 report_descriptor: MouseReport::desc(),
62 request_handler: Some(&request_handler), 62 request_handler: Some(&request_handler),
63 poll_ms: 60, 63 poll_ms: 60,
@@ -111,11 +111,11 @@ impl RequestHandler for MyRequestHandler {
111 OutResponse::Accepted 111 OutResponse::Accepted
112 } 112 }
113 113
114 fn set_idle(&self, id: Option<ReportId>, dur: Duration) { 114 fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) {
115 info!("Set idle rate for {:?} to {:?}", id, dur); 115 info!("Set idle rate for {:?} to {:?}", id, dur);
116 } 116 }
117 117
118 fn get_idle(&self, id: Option<ReportId>) -> Option<Duration> { 118 fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> {
119 info!("Get idle rate for {:?}", id); 119 info!("Get idle rate for {:?}", id);
120 None 120 None
121 } 121 }
diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs
index 323db6557..0c719560f 100644
--- a/examples/stm32l5/src/bin/usb_serial.rs
+++ b/examples/stm32l5/src/bin/usb_serial.rs
@@ -4,16 +4,19 @@
4 4
5use defmt::{panic, *}; 5use defmt::{panic, *};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_futures::join::join;
7use embassy_stm32::rcc::*; 8use embassy_stm32::rcc::*;
8use embassy_stm32::time::Hertz;
9use embassy_stm32::usb::{Driver, Instance}; 9use embassy_stm32::usb::{Driver, Instance};
10use embassy_stm32::{interrupt, Config}; 10use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError; 12use embassy_usb::driver::EndpointError;
12use embassy_usb::Builder; 13use embassy_usb::Builder;
13use embassy_usb_serial::{CdcAcmClass, State};
14use futures::future::join;
15use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
16 15
16bind_interrupts!(struct Irqs {
17 USB_FS => usb::InterruptHandler<peripherals::USB>;
18});
19
17#[embassy_executor::main] 20#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 21async fn main(_spawner: Spawner) {
19 let mut config = Config::default(); 22 let mut config = Config::default();
@@ -24,8 +27,7 @@ async fn main(_spawner: Spawner) {
24 info!("Hello World!"); 27 info!("Hello World!");
25 28
26 // Create the driver, from the HAL. 29 // Create the driver, from the HAL.
27 let irq = interrupt::take!(USB_FS); 30 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
28 let driver = Driver::new(p.USB, irq, p.PA12, p.PA11);
29 31
30 // Create embassy-usb Config 32 // Create embassy-usb Config
31 let config = embassy_usb::Config::new(0xc0de, 0xcafe); 33 let config = embassy_usb::Config::new(0xc0de, 0xcafe);
@@ -47,7 +49,6 @@ async fn main(_spawner: Spawner) {
47 &mut config_descriptor, 49 &mut config_descriptor,
48 &mut bos_descriptor, 50 &mut bos_descriptor,
49 &mut control_buf, 51 &mut control_buf,
50 None,
51 ); 52 );
52 53
53 // Create classes on the builder. 54 // Create classes on the builder.
diff --git a/examples/stm32u5/.cargo/config.toml b/examples/stm32u5/.cargo/config.toml
index 975630a14..36c5b63a6 100644
--- a/examples/stm32u5/.cargo/config.toml
+++ b/examples/stm32u5/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32U585AIIx with your chip as listed in `probe-run --list-chips` 2# replace STM32U585AIIx with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32U585AIIx" 3runner = "probe-rs run --chip STM32U585AIIx"
4 4
5[build] 5[build]
6target = "thumbv8m.main-none-eabihf" 6target = "thumbv8m.main-none-eabihf"
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml
index ff0ec9f42..835e32940 100644
--- a/examples/stm32u5/Cargo.toml
+++ b/examples/stm32u5/Cargo.toml
@@ -2,17 +2,19 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32u5-examples" 3name = "embassy-stm32u5-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
10embassy-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"] }
11 13
12defmt = "0.3" 14defmt = "0.3"
13defmt-rtt = "0.3" 15defmt-rtt = "0.4"
14 16
15cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 17cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
16cortex-m-rt = "0.7.0" 18cortex-m-rt = "0.7.0"
17embedded-hal = "0.2.6" 19embedded-hal = "0.2.6"
18panic-probe = { version = "0.3", features = ["print-defmt"] } 20panic-probe = { version = "0.3", features = ["print-defmt"] }
@@ -20,8 +22,3 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
20heapless = { version = "0.7.5", default-features = false } 22heapless = { version = "0.7.5", default-features = false }
21 23
22micromath = "2.0.0" 24micromath = "2.0.0"
23
24#[patch.crates-io]
25#defmt = { git="https://github.com/knurling-rs/defmt.git" }
26#defmt-rtt = { git="https://github.com/knurling-rs/defmt.git" }
27
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs
new file mode 100644
index 000000000..9e47fb18a
--- /dev/null
+++ b/examples/stm32u5/src/bin/usb_serial.rs
@@ -0,0 +1,112 @@
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::{bind_interrupts, peripherals, usb_otg, 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
17bind_interrupts!(struct Irqs {
18 OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
19});
20
21#[embassy_executor::main]
22async fn main(_spawner: Spawner) {
23 info!("Hello World!");
24
25 let mut config = Config::default();
26 config.rcc.mux = ClockSrc::PLL1R(PllSrc::HSI16, PllM::Div2, PllN::Mul10, PllClkDiv::NotDivided);
27 //config.rcc.mux = ClockSrc::MSI(MSIRange::Range48mhz);
28 config.rcc.hsi48 = true;
29
30 let p = embassy_stm32::init(config);
31
32 // Create the driver, from the HAL.
33 let mut ep_out_buffer = [0u8; 256];
34 let mut config = embassy_stm32::usb_otg::Config::default();
35 config.vbus_detection = true;
36 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
37
38 // Create embassy-usb Config
39 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
40 config.manufacturer = Some("Embassy");
41 config.product = Some("USB-serial example");
42 config.serial_number = Some("12345678");
43
44 // Required for windows compatibility.
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 control_buf = [0; 64];
57
58 let mut state = State::new();
59
60 let mut builder = Builder::new(
61 driver,
62 config,
63 &mut device_descriptor,
64 &mut config_descriptor,
65 &mut bos_descriptor,
66 &mut control_buf,
67 );
68
69 // Create classes on the builder.
70 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
71
72 // Build the builder.
73 let mut usb = builder.build();
74
75 // Run the USB device.
76 let usb_fut = usb.run();
77
78 // Do stuff with the class!
79 let echo_fut = async {
80 loop {
81 class.wait_connection().await;
82 info!("Connected");
83 let _ = echo(&mut class).await;
84 info!("Disconnected");
85 }
86 };
87
88 // Run everything concurrently.
89 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
90 join(usb_fut, echo_fut).await;
91}
92
93struct Disconnected {}
94
95impl From<EndpointError> for Disconnected {
96 fn from(val: EndpointError) -> Self {
97 match val {
98 EndpointError::BufferOverflow => panic!("Buffer overflow"),
99 EndpointError::Disabled => Disconnected {},
100 }
101 }
102}
103
104async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
105 let mut buf = [0; 64];
106 loop {
107 let n = class.read_packet(&mut buf).await?;
108 let data = &buf[..n];
109 info!("data: {:x}", data);
110 class.write_packet(data).await?;
111 }
112}
diff --git a/examples/stm32wb/.cargo/config.toml b/examples/stm32wb/.cargo/config.toml
index fcf95741a..51c499ee7 100644
--- a/examples/stm32wb/.cargo/config.toml
+++ b/examples/stm32wb/.cargo/config.toml
@@ -1,6 +1,7 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32WB55CCUx with your chip as listed in `probe-run --list-chips` 2# replace STM32WB55CCUx with your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32WB55CCUx --speed 1000 --connect-under-reset" 3# runner = "probe-run --chip STM32WB55RGVx --speed 1000 --connect-under-reset"
4runner = "teleprobe local run --chip STM32WB55RG --elf"
4 5
5[build] 6[build]
6target = "thumbv7em-none-eabihf" 7target = "thumbv7em-none-eabihf"
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index 3b10da0ad..becf2d3fb 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -2,19 +2,47 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32wb-examples" 3name = "embassy-stm32wb-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
10embassy-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", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] }
12embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] }
11 13
12defmt = "0.3" 14defmt = "0.3"
13defmt-rtt = "0.3" 15defmt-rtt = "0.4"
14 16
15cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 17cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
16cortex-m-rt = "0.7.0" 18cortex-m-rt = "0.7.0"
17embedded-hal = "0.2.6" 19embedded-hal = "0.2.6"
18panic-probe = { version = "0.3", features = ["print-defmt"] } 20panic-probe = { version = "0.3", features = ["print-defmt"] }
19futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 21futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
20heapless = { version = "0.7.5", default-features = false } 22heapless = { version = "0.7.5", default-features = false }
23
24
25[features]
26default = ["ble", "mac"]
27mac = ["embassy-stm32-wpan/mac"]
28ble = ["embassy-stm32-wpan/ble"]
29
30[[bin]]
31name = "tl_mbox_ble"
32required-features = ["ble"]
33
34[[bin]]
35name = "tl_mbox_mac"
36required-features = ["mac"]
37
38[[bin]]
39name = "mac_ffd"
40required-features = ["mac"]
41
42[[bin]]
43name = "eddystone_beacon"
44required-features = ["ble"]
45
46[[bin]]
47name = "gatt_server"
48required-features = ["ble"] \ No newline at end of file
diff --git a/examples/stm32wb/build.rs b/examples/stm32wb/build.rs
index 30691aa97..29b3a9b2a 100644
--- a/examples/stm32wb/build.rs
+++ b/examples/stm32wb/build.rs
@@ -1,35 +1,11 @@
1//! This build script copies the `memory.x` file from the crate root into 1use std::error::Error;
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 2
3fn main() -> Result<(), Box<dyn Error>> {
32 println!("cargo:rustc-link-arg-bins=--nmagic"); 4 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x"); 5 println!("cargo:rustc-link-arg-bins=-Tlink.x");
6 println!("cargo:rerun-if-changed=link.x");
7 println!("cargo:rustc-link-arg-bins=-Ttl_mbox.x");
34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); 8 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
9
10 Ok(())
35} 11}
diff --git a/examples/stm32wb/memory.x b/examples/stm32wb/memory.x
deleted file mode 100644
index 2b4dcce34..000000000
--- a/examples/stm32wb/memory.x
+++ /dev/null
@@ -1,41 +0,0 @@
1/*
2 The size of this file must be exactly the same as in other memory_xx.x files.
3 Memory size for STM32WB55xC with 256K FLASH
4*/
5
6MEMORY
7{
8 FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 256K
9 RAM (xrw) : ORIGIN = 0x20000004, LENGTH = 191K
10 RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K
11}
12
13/* Place stack at the end of SRAM1 */
14_stack_start = ORIGIN(RAM) + LENGTH(RAM);
15
16/*
17 * Scatter the mailbox interface memory sections in shared memory
18 */
19SECTIONS {
20 TL_REF_TABLE (NOLOAD) : { *(TL_REF_TABLE) } >RAM_SHARED
21
22 TL_DEVICE_INFO_TABLE 0x2003001c (NOLOAD) : { *(TL_DEVICE_INFO_TABLE) } >RAM_SHARED
23 TL_BLE_TABLE 0x2003003c (NOLOAD) : { *(TL_BLE_TABLE) } >RAM_SHARED
24 TL_THREAD_TABLE 0x2003004c (NOLOAD) : { *(TL_THREAD_TABLE) } >RAM_SHARED
25 TL_SYS_TABLE 0x20030058 (NOLOAD) : { *(TL_SYS_TABLE) } >RAM_SHARED
26 TL_MEM_MANAGER_TABLE 0x20030060 (NOLOAD) : { *(TL_MEM_MANAGER_TABLE) } >RAM_SHARED
27 TL_TRACES_TABLE 0x2003007c (NOLOAD) : { *(TL_TRACES_TABLE) } >RAM_SHARED
28 TL_MAC_802_15_4_TABLE 0x20030080 (NOLOAD) : { *(TL_MAC_802_15_4_TABLE) } >RAM_SHARED
29
30 HCI_ACL_DATA_BUFFER 0x20030a08 (NOLOAD) : { *(HCI_ACL_DATA_BUFFER) } >RAM_SHARED
31 BLE_CMD_BUFFER 0x200308fc (NOLOAD) : { *(BLE_CMD_BUFFER) } >RAM_SHARED
32 BLE_SPARE_EVT_BUF 0x200301a8 (NOLOAD) : { *(BLE_SPARE_EVT_BUF) } >RAM_SHARED
33 SYS_SPARE_EVT_BUF 0x200302b4 (NOLOAD) : { *(SYS_SPARE_EVT_BUF) } >RAM_SHARED
34 EVT_POOL 0x200303c0 (NOLOAD) : { *(EVT_POOL) } >RAM_SHARED
35 SYS_CMD_BUF 0x2003009c (NOLOAD) : { *(SYS_CMD_BUF) } >RAM_SHARED
36 SYSTEM_EVT_QUEUE 0x20030b28 (NOLOAD) : { *(SYSTEM_EVT_QUEUE) } >RAM_SHARED
37 EVT_QUEUE 0x20030b10 (NOLOAD) : { *(EVT_QUEUE) } >RAM_SHARED
38 CS_BUFFER 0x20030b18 (NOLOAD) : { *(CS_BUFFER) } >RAM_SHARED
39 TRACES_EVT_QUEUE 0x20030094 (NOLOAD) : { *(TRACES_EVT_QUEUE) } >RAM_SHARED
40 FREE_BUF_QUEUE 0x2003008c (NOLOAD) : { *(FREE_BUF_QUEUE) } >RAM_SHARED
41}
diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs
new file mode 100644
index 000000000..451bd7d29
--- /dev/null
+++ b/examples/stm32wb/src/bin/eddystone_beacon.rs
@@ -0,0 +1,249 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::time::Duration;
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_stm32::bind_interrupts;
10use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
11use embassy_stm32_wpan::hci::host::uart::UartHci;
12use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType};
13use embassy_stm32_wpan::hci::types::AdvertisingType;
14use embassy_stm32_wpan::hci::vendor::stm32wb::command::gap::{
15 AdvertisingDataType, DiscoverableParameters, GapCommands, Role,
16};
17use embassy_stm32_wpan::hci::vendor::stm32wb::command::gatt::GattCommands;
18use embassy_stm32_wpan::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel};
19use embassy_stm32_wpan::hci::BdAddr;
20use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp;
21use embassy_stm32_wpan::TlMbox;
22use {defmt_rtt as _, panic_probe as _};
23
24bind_interrupts!(struct Irqs{
25 IPCC_C1_RX => ReceiveInterruptHandler;
26 IPCC_C1_TX => TransmitInterruptHandler;
27});
28
29const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7;
30
31#[embassy_executor::main]
32async fn main(_spawner: Spawner) {
33 /*
34 How to make this work:
35
36 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
37 - Download and Install STM32CubeProgrammer.
38 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
39 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
40 - Open STM32CubeProgrammer
41 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
42 - Once complete, click connect to connect to the device.
43 - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
44 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
45 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
46 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
47 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
48 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
49 - Select "Start Wireless Stack".
50 - Disconnect from the device.
51 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
52 - Run this example.
53
54 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
55 */
56
57 let p = embassy_stm32::init(Default::default());
58 info!("Hello World!");
59
60 let config = Config::default();
61 let mut mbox = TlMbox::init(p.IPCC, Irqs, config);
62
63 let sys_event = mbox.sys_subsystem.read().await;
64 info!("sys event: {}", sys_event.payload());
65
66 let _ = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
67
68 info!("resetting BLE...");
69 mbox.ble_subsystem.reset().await;
70 let response = mbox.ble_subsystem.read().await.unwrap();
71 defmt::info!("{}", response);
72
73 info!("config public address...");
74 mbox.ble_subsystem
75 .write_config_data(&ConfigData::public_address(get_bd_addr()).build())
76 .await;
77 let response = mbox.ble_subsystem.read().await.unwrap();
78 defmt::info!("{}", response);
79
80 info!("config random address...");
81 mbox.ble_subsystem
82 .write_config_data(&ConfigData::random_address(get_random_addr()).build())
83 .await;
84 let response = mbox.ble_subsystem.read().await.unwrap();
85 defmt::info!("{}", response);
86
87 info!("config identity root...");
88 mbox.ble_subsystem
89 .write_config_data(&ConfigData::identity_root(&get_irk()).build())
90 .await;
91 let response = mbox.ble_subsystem.read().await.unwrap();
92 defmt::info!("{}", response);
93
94 info!("config encryption root...");
95 mbox.ble_subsystem
96 .write_config_data(&ConfigData::encryption_root(&get_erk()).build())
97 .await;
98 let response = mbox.ble_subsystem.read().await.unwrap();
99 defmt::info!("{}", response);
100
101 info!("config tx power level...");
102 mbox.ble_subsystem.set_tx_power_level(PowerLevel::ZerodBm).await;
103 let response = mbox.ble_subsystem.read().await.unwrap();
104 defmt::info!("{}", response);
105
106 info!("GATT init...");
107 mbox.ble_subsystem.init_gatt().await;
108 let response = mbox.ble_subsystem.read().await.unwrap();
109 defmt::info!("{}", response);
110
111 info!("GAP init...");
112 mbox.ble_subsystem
113 .init_gap(Role::PERIPHERAL, false, BLE_GAP_DEVICE_NAME_LENGTH)
114 .await;
115 let response = mbox.ble_subsystem.read().await.unwrap();
116 defmt::info!("{}", response);
117
118 // info!("set scan response...");
119 // mbox.ble_subsystem.le_set_scan_response_data(&[]).await.unwrap();
120 // let response = mbox.ble_subsystem.read().await.unwrap();
121 // defmt::info!("{}", response);
122
123 info!("set discoverable...");
124 mbox.ble_subsystem
125 .set_discoverable(&DiscoverableParameters {
126 advertising_type: AdvertisingType::NonConnectableUndirected,
127 advertising_interval: Some((Duration::from_millis(250), Duration::from_millis(250))),
128 address_type: OwnAddressType::Public,
129 filter_policy: AdvertisingFilterPolicy::AllowConnectionAndScan,
130 local_name: None,
131 advertising_data: &[],
132 conn_interval: (None, None),
133 })
134 .await
135 .unwrap();
136
137 let response = mbox.ble_subsystem.read().await;
138 defmt::info!("{}", response);
139
140 // remove some advertisement to decrease the packet size
141 info!("delete tx power ad type...");
142 mbox.ble_subsystem
143 .delete_ad_type(AdvertisingDataType::TxPowerLevel)
144 .await;
145 let response = mbox.ble_subsystem.read().await.unwrap();
146 defmt::info!("{}", response);
147
148 info!("delete conn interval ad type...");
149 mbox.ble_subsystem
150 .delete_ad_type(AdvertisingDataType::PeripheralConnectionInterval)
151 .await;
152 let response = mbox.ble_subsystem.read().await.unwrap();
153 defmt::info!("{}", response);
154
155 info!("update advertising data...");
156 mbox.ble_subsystem
157 .update_advertising_data(&eddystone_advertising_data())
158 .await
159 .unwrap();
160 let response = mbox.ble_subsystem.read().await.unwrap();
161 defmt::info!("{}", response);
162
163 info!("update advertising data type...");
164 mbox.ble_subsystem
165 .update_advertising_data(&[3, AdvertisingDataType::UuidCompleteList16 as u8, 0xaa, 0xfe])
166 .await
167 .unwrap();
168 let response = mbox.ble_subsystem.read().await.unwrap();
169 defmt::info!("{}", response);
170
171 info!("update advertising data flags...");
172 mbox.ble_subsystem
173 .update_advertising_data(&[
174 2,
175 AdvertisingDataType::Flags as u8,
176 (0x02 | 0x04) as u8, // BLE general discoverable, without BR/EDR support
177 ])
178 .await
179 .unwrap();
180 let response = mbox.ble_subsystem.read().await.unwrap();
181 defmt::info!("{}", response);
182
183 cortex_m::asm::wfi();
184}
185
186fn get_bd_addr() -> BdAddr {
187 let mut bytes = [0u8; 6];
188
189 let lhci_info = LhciC1DeviceInformationCcrp::new();
190 bytes[0] = (lhci_info.uid64 & 0xff) as u8;
191 bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8;
192 bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8;
193 bytes[3] = lhci_info.device_type_id;
194 bytes[4] = (lhci_info.st_company_id & 0xff) as u8;
195 bytes[5] = (lhci_info.st_company_id >> 8 & 0xff) as u8;
196
197 BdAddr(bytes)
198}
199
200fn get_random_addr() -> BdAddr {
201 let mut bytes = [0u8; 6];
202
203 let lhci_info = LhciC1DeviceInformationCcrp::new();
204 bytes[0] = (lhci_info.uid64 & 0xff) as u8;
205 bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8;
206 bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8;
207 bytes[3] = 0;
208 bytes[4] = 0x6E;
209 bytes[5] = 0xED;
210
211 BdAddr(bytes)
212}
213
214const BLE_CFG_IRK: [u8; 16] = [
215 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
216];
217const BLE_CFG_ERK: [u8; 16] = [
218 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21, 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21,
219];
220
221fn get_irk() -> EncryptionKey {
222 EncryptionKey(BLE_CFG_IRK)
223}
224
225fn get_erk() -> EncryptionKey {
226 EncryptionKey(BLE_CFG_ERK)
227}
228
229fn eddystone_advertising_data() -> [u8; 24] {
230 const EDDYSTONE_URL: &[u8] = b"www.rust-lang.com";
231
232 let mut service_data = [0u8; 24];
233 let url_len = EDDYSTONE_URL.len();
234
235 service_data[0] = 6 + url_len as u8;
236 service_data[1] = AdvertisingDataType::ServiceData as u8;
237
238 // 16-bit eddystone uuid
239 service_data[2] = 0xaa;
240 service_data[3] = 0xFE;
241
242 service_data[4] = 0x10; // URL frame type
243 service_data[5] = 22_i8 as u8; // calibrated TX power at 0m
244 service_data[6] = 0x03; // eddystone url prefix = https
245
246 service_data[7..(7 + url_len)].copy_from_slice(EDDYSTONE_URL);
247
248 service_data
249}
diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs
new file mode 100644
index 000000000..0f6419d45
--- /dev/null
+++ b/examples/stm32wb/src/bin/gatt_server.rs
@@ -0,0 +1,397 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::time::Duration;
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_stm32::bind_interrupts;
10use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
11use embassy_stm32_wpan::hci::event::command::{CommandComplete, ReturnParameters};
12use embassy_stm32_wpan::hci::host::uart::{Packet, UartHci};
13use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType};
14use embassy_stm32_wpan::hci::types::AdvertisingType;
15use embassy_stm32_wpan::hci::vendor::stm32wb::command::gap::{
16 AddressType, AuthenticationRequirements, DiscoverableParameters, GapCommands, IoCapability, LocalName, Pin, Role,
17 SecureConnectionSupport,
18};
19use embassy_stm32_wpan::hci::vendor::stm32wb::command::gatt::{
20 AddCharacteristicParameters, AddServiceParameters, CharacteristicEvent, CharacteristicPermission,
21 CharacteristicProperty, EncryptionKeySize, GattCommands, ServiceType, UpdateCharacteristicValueParameters, Uuid,
22 WriteResponseParameters,
23};
24use embassy_stm32_wpan::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel};
25use embassy_stm32_wpan::hci::vendor::stm32wb::event::{self, AttributeHandle, Stm32Wb5xEvent};
26use embassy_stm32_wpan::hci::{BdAddr, Event};
27use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp;
28use embassy_stm32_wpan::sub::ble::Ble;
29use embassy_stm32_wpan::TlMbox;
30use {defmt_rtt as _, panic_probe as _};
31
32bind_interrupts!(struct Irqs{
33 IPCC_C1_RX => ReceiveInterruptHandler;
34 IPCC_C1_TX => TransmitInterruptHandler;
35});
36
37const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7;
38
39#[embassy_executor::main]
40async fn main(_spawner: Spawner) {
41 /*
42 How to make this work:
43
44 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
45 - Download and Install STM32CubeProgrammer.
46 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
47 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
48 - Open STM32CubeProgrammer
49 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
50 - Once complete, click connect to connect to the device.
51 - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
52 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
53 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
54 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
55 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
56 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
57 - Select "Start Wireless Stack".
58 - Disconnect from the device.
59 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
60 - Run this example.
61
62 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
63 */
64
65 let p = embassy_stm32::init(Default::default());
66 info!("Hello World!");
67
68 let config = Config::default();
69 let mut mbox = TlMbox::init(p.IPCC, Irqs, config);
70
71 let sys_event = mbox.sys_subsystem.read().await;
72 info!("sys event: {}", sys_event.payload());
73
74 let _ = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
75
76 info!("resetting BLE...");
77 mbox.ble_subsystem.reset().await;
78 let response = mbox.ble_subsystem.read().await;
79 defmt::debug!("{}", response);
80
81 info!("config public address...");
82 mbox.ble_subsystem
83 .write_config_data(&ConfigData::public_address(get_bd_addr()).build())
84 .await;
85 let response = mbox.ble_subsystem.read().await;
86 defmt::debug!("{}", response);
87
88 info!("config random address...");
89 mbox.ble_subsystem
90 .write_config_data(&ConfigData::random_address(get_random_addr()).build())
91 .await;
92 let response = mbox.ble_subsystem.read().await;
93 defmt::debug!("{}", response);
94
95 info!("config identity root...");
96 mbox.ble_subsystem
97 .write_config_data(&ConfigData::identity_root(&get_irk()).build())
98 .await;
99 let response = mbox.ble_subsystem.read().await;
100 defmt::debug!("{}", response);
101
102 info!("config encryption root...");
103 mbox.ble_subsystem
104 .write_config_data(&ConfigData::encryption_root(&get_erk()).build())
105 .await;
106 let response = mbox.ble_subsystem.read().await;
107 defmt::debug!("{}", response);
108
109 info!("config tx power level...");
110 mbox.ble_subsystem.set_tx_power_level(PowerLevel::ZerodBm).await;
111 let response = mbox.ble_subsystem.read().await;
112 defmt::debug!("{}", response);
113
114 info!("GATT init...");
115 mbox.ble_subsystem.init_gatt().await;
116 let response = mbox.ble_subsystem.read().await;
117 defmt::debug!("{}", response);
118
119 info!("GAP init...");
120 mbox.ble_subsystem
121 .init_gap(Role::PERIPHERAL, false, BLE_GAP_DEVICE_NAME_LENGTH)
122 .await;
123 let response = mbox.ble_subsystem.read().await;
124 defmt::debug!("{}", response);
125
126 info!("set IO capabilities...");
127 mbox.ble_subsystem.set_io_capability(IoCapability::DisplayConfirm).await;
128 let response = mbox.ble_subsystem.read().await;
129 defmt::debug!("{}", response);
130
131 info!("set authentication requirements...");
132 mbox.ble_subsystem
133 .set_authentication_requirement(&AuthenticationRequirements {
134 bonding_required: false,
135 keypress_notification_support: false,
136 mitm_protection_required: false,
137 encryption_key_size_range: (8, 16),
138 fixed_pin: Pin::Requested,
139 identity_address_type: AddressType::Public,
140 secure_connection_support: SecureConnectionSupport::Optional,
141 })
142 .await
143 .unwrap();
144 let response = mbox.ble_subsystem.read().await;
145 defmt::debug!("{}", response);
146
147 info!("set scan response data...");
148 mbox.ble_subsystem.le_set_scan_response_data(b"TXTX").await.unwrap();
149 let response = mbox.ble_subsystem.read().await;
150 defmt::debug!("{}", response);
151
152 info!("set scan response data...");
153 mbox.ble_subsystem.le_set_scan_response_data(b"TXTX").await.unwrap();
154 let response = mbox.ble_subsystem.read().await;
155 defmt::debug!("{}", response);
156
157 defmt::info!("initializing services and characteristics...");
158 let mut ble_context = init_gatt_services(&mut mbox.ble_subsystem).await.unwrap();
159 defmt::info!("{}", ble_context);
160
161 let discovery_params = DiscoverableParameters {
162 advertising_type: AdvertisingType::ConnectableUndirected,
163 advertising_interval: Some((Duration::from_millis(100), Duration::from_millis(100))),
164 address_type: OwnAddressType::Public,
165 filter_policy: AdvertisingFilterPolicy::AllowConnectionAndScan,
166 local_name: Some(LocalName::Complete(b"TXTX")),
167 advertising_data: &[],
168 conn_interval: (None, None),
169 };
170
171 info!("set discoverable...");
172 mbox.ble_subsystem.set_discoverable(&discovery_params).await.unwrap();
173 let response = mbox.ble_subsystem.read().await;
174 defmt::debug!("{}", response);
175
176 loop {
177 let response = mbox.ble_subsystem.read().await;
178 defmt::debug!("{}", response);
179
180 if let Ok(Packet::Event(event)) = response {
181 match event {
182 Event::LeConnectionComplete(_) => {
183 defmt::info!("connected");
184 }
185 Event::DisconnectionComplete(_) => {
186 defmt::info!("disconnected");
187 ble_context.is_subscribed = false;
188 mbox.ble_subsystem.set_discoverable(&discovery_params).await.unwrap();
189 }
190 Event::Vendor(vendor_event) => match vendor_event {
191 Stm32Wb5xEvent::AttReadPermitRequest(read_req) => {
192 defmt::info!("read request received {}, allowing", read_req);
193 mbox.ble_subsystem.allow_read(read_req.conn_handle).await
194 }
195 Stm32Wb5xEvent::AttWritePermitRequest(write_req) => {
196 defmt::info!("write request received {}, allowing", write_req);
197 mbox.ble_subsystem
198 .write_response(&WriteResponseParameters {
199 conn_handle: write_req.conn_handle,
200 attribute_handle: write_req.attribute_handle,
201 status: Ok(()),
202 value: write_req.value(),
203 })
204 .await
205 .unwrap()
206 }
207 Stm32Wb5xEvent::GattAttributeModified(attribute) => {
208 defmt::info!("{}", ble_context);
209 if attribute.attr_handle.0 == ble_context.chars.notify.0 + 2 {
210 if attribute.data()[0] == 0x01 {
211 defmt::info!("subscribed");
212 ble_context.is_subscribed = true;
213 } else {
214 defmt::info!("unsubscribed");
215 ble_context.is_subscribed = false;
216 }
217 }
218 }
219 _ => {}
220 },
221 _ => {}
222 }
223 }
224 }
225}
226
227fn get_bd_addr() -> BdAddr {
228 let mut bytes = [0u8; 6];
229
230 let lhci_info = LhciC1DeviceInformationCcrp::new();
231 bytes[0] = (lhci_info.uid64 & 0xff) as u8;
232 bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8;
233 bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8;
234 bytes[3] = lhci_info.device_type_id;
235 bytes[4] = (lhci_info.st_company_id & 0xff) as u8;
236 bytes[5] = (lhci_info.st_company_id >> 8 & 0xff) as u8;
237
238 BdAddr(bytes)
239}
240
241fn get_random_addr() -> BdAddr {
242 let mut bytes = [0u8; 6];
243
244 let lhci_info = LhciC1DeviceInformationCcrp::new();
245 bytes[0] = (lhci_info.uid64 & 0xff) as u8;
246 bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8;
247 bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8;
248 bytes[3] = 0;
249 bytes[4] = 0x6E;
250 bytes[5] = 0xED;
251
252 BdAddr(bytes)
253}
254
255const BLE_CFG_IRK: [u8; 16] = [
256 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
257];
258const BLE_CFG_ERK: [u8; 16] = [
259 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21, 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21,
260];
261
262fn get_irk() -> EncryptionKey {
263 EncryptionKey(BLE_CFG_IRK)
264}
265
266fn get_erk() -> EncryptionKey {
267 EncryptionKey(BLE_CFG_ERK)
268}
269
270#[derive(defmt::Format)]
271pub struct BleContext {
272 pub service_handle: AttributeHandle,
273 pub chars: CharHandles,
274 pub is_subscribed: bool,
275}
276
277#[derive(defmt::Format)]
278pub struct CharHandles {
279 pub read: AttributeHandle,
280 pub write: AttributeHandle,
281 pub notify: AttributeHandle,
282}
283
284pub async fn init_gatt_services(ble_subsystem: &mut Ble) -> Result<BleContext, ()> {
285 let service_handle = gatt_add_service(ble_subsystem, Uuid::Uuid16(0x500)).await?;
286
287 let read = gatt_add_char(
288 ble_subsystem,
289 service_handle,
290 Uuid::Uuid16(0x501),
291 CharacteristicProperty::READ,
292 Some(b"Hello from embassy!"),
293 )
294 .await?;
295
296 let write = gatt_add_char(
297 ble_subsystem,
298 service_handle,
299 Uuid::Uuid16(0x502),
300 CharacteristicProperty::WRITE_WITHOUT_RESPONSE | CharacteristicProperty::WRITE | CharacteristicProperty::READ,
301 None,
302 )
303 .await?;
304
305 let notify = gatt_add_char(
306 ble_subsystem,
307 service_handle,
308 Uuid::Uuid16(0x503),
309 CharacteristicProperty::NOTIFY | CharacteristicProperty::READ,
310 None,
311 )
312 .await?;
313
314 Ok(BleContext {
315 service_handle,
316 is_subscribed: false,
317 chars: CharHandles { read, write, notify },
318 })
319}
320
321async fn gatt_add_service(ble_subsystem: &mut Ble, uuid: Uuid) -> Result<AttributeHandle, ()> {
322 ble_subsystem
323 .add_service(&AddServiceParameters {
324 uuid,
325 service_type: ServiceType::Primary,
326 max_attribute_records: 8,
327 })
328 .await;
329 let response = ble_subsystem.read().await;
330 defmt::debug!("{}", response);
331
332 if let Ok(Packet::Event(Event::CommandComplete(CommandComplete {
333 return_params:
334 ReturnParameters::Vendor(event::command::ReturnParameters::GattAddService(event::command::GattService {
335 service_handle,
336 ..
337 })),
338 ..
339 }))) = response
340 {
341 Ok(service_handle)
342 } else {
343 Err(())
344 }
345}
346
347async fn gatt_add_char(
348 ble_subsystem: &mut Ble,
349 service_handle: AttributeHandle,
350 characteristic_uuid: Uuid,
351 characteristic_properties: CharacteristicProperty,
352 default_value: Option<&[u8]>,
353) -> Result<AttributeHandle, ()> {
354 ble_subsystem
355 .add_characteristic(&AddCharacteristicParameters {
356 service_handle,
357 characteristic_uuid,
358 characteristic_properties,
359 characteristic_value_len: 32,
360 security_permissions: CharacteristicPermission::empty(),
361 gatt_event_mask: CharacteristicEvent::all(),
362 encryption_key_size: EncryptionKeySize::with_value(7).unwrap(),
363 is_variable: true,
364 })
365 .await;
366 let response = ble_subsystem.read().await;
367 defmt::debug!("{}", response);
368
369 if let Ok(Packet::Event(Event::CommandComplete(CommandComplete {
370 return_params:
371 ReturnParameters::Vendor(event::command::ReturnParameters::GattAddCharacteristic(
372 event::command::GattCharacteristic {
373 characteristic_handle, ..
374 },
375 )),
376 ..
377 }))) = response
378 {
379 if let Some(value) = default_value {
380 ble_subsystem
381 .update_characteristic_value(&UpdateCharacteristicValueParameters {
382 service_handle,
383 characteristic_handle,
384 offset: 0,
385 value,
386 })
387 .await
388 .unwrap();
389
390 let response = ble_subsystem.read().await;
391 defmt::debug!("{}", response);
392 }
393 Ok(characteristic_handle)
394 } else {
395 Err(())
396 }
397}
diff --git a/examples/stm32wb/src/bin/mac_ffd.rs b/examples/stm32wb/src/bin/mac_ffd.rs
new file mode 100644
index 000000000..bc71e29aa
--- /dev/null
+++ b/examples/stm32wb/src/bin/mac_ffd.rs
@@ -0,0 +1,206 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts;
8use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
9use embassy_stm32_wpan::mac::commands::{AssociateResponse, ResetRequest, SetRequest, StartRequest};
10use embassy_stm32_wpan::mac::event::MacEvent;
11use embassy_stm32_wpan::mac::typedefs::{MacChannel, MacStatus, PanId, PibId, SecurityLevel};
12use embassy_stm32_wpan::sub::mm;
13use embassy_stm32_wpan::TlMbox;
14use {defmt_rtt as _, panic_probe as _};
15
16bind_interrupts!(struct Irqs{
17 IPCC_C1_RX => ReceiveInterruptHandler;
18 IPCC_C1_TX => TransmitInterruptHandler;
19});
20
21#[embassy_executor::task]
22async fn run_mm_queue(memory_manager: mm::MemoryManager) {
23 memory_manager.run_queue().await;
24}
25
26#[embassy_executor::main]
27async fn main(spawner: Spawner) {
28 /*
29 How to make this work:
30
31 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
32 - Download and Install STM32CubeProgrammer.
33 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
34 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
35 - Open STM32CubeProgrammer
36 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
37 - Once complete, click connect to connect to the device.
38 - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
39 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
40 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
41 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
42 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
43 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
44 - Select "Start Wireless Stack".
45 - Disconnect from the device.
46 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
47 - Run this example.
48
49 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
50 */
51
52 let p = embassy_stm32::init(Default::default());
53 info!("Hello World!");
54
55 let config = Config::default();
56 let mbox = TlMbox::init(p.IPCC, Irqs, config);
57
58 spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
59
60 let sys_event = mbox.sys_subsystem.read().await;
61 info!("sys event: {}", sys_event.payload());
62
63 core::mem::drop(sys_event);
64
65 let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
66 info!("initialized mac: {}", result);
67
68 info!("resetting");
69 mbox.mac_subsystem
70 .send_command(&ResetRequest {
71 set_default_pib: true,
72 ..Default::default()
73 })
74 .await
75 .unwrap();
76 {
77 let evt = mbox.mac_subsystem.read().await;
78 defmt::info!("{:#x}", evt.mac_event());
79 }
80
81 info!("setting extended address");
82 let extended_address: u64 = 0xACDE480000000001;
83 mbox.mac_subsystem
84 .send_command(&SetRequest {
85 pib_attribute_ptr: &extended_address as *const _ as *const u8,
86 pib_attribute: PibId::ExtendedAddress,
87 })
88 .await
89 .unwrap();
90 {
91 let evt = mbox.mac_subsystem.read().await;
92 defmt::info!("{:#x}", evt.mac_event());
93 }
94
95 info!("setting short address");
96 let short_address: u16 = 0x1122;
97 mbox.mac_subsystem
98 .send_command(&SetRequest {
99 pib_attribute_ptr: &short_address as *const _ as *const u8,
100 pib_attribute: PibId::ShortAddress,
101 })
102 .await
103 .unwrap();
104 {
105 let evt = mbox.mac_subsystem.read().await;
106 defmt::info!("{:#x}", evt.mac_event());
107 }
108
109 info!("setting association permit");
110 let association_permit: bool = true;
111 mbox.mac_subsystem
112 .send_command(&SetRequest {
113 pib_attribute_ptr: &association_permit as *const _ as *const u8,
114 pib_attribute: PibId::AssociationPermit,
115 })
116 .await
117 .unwrap();
118 {
119 let evt = mbox.mac_subsystem.read().await;
120 defmt::info!("{:#x}", evt.mac_event());
121 }
122
123 info!("setting TX power");
124 let transmit_power: i8 = 2;
125 mbox.mac_subsystem
126 .send_command(&SetRequest {
127 pib_attribute_ptr: &transmit_power as *const _ as *const u8,
128 pib_attribute: PibId::TransmitPower,
129 })
130 .await
131 .unwrap();
132 {
133 let evt = mbox.mac_subsystem.read().await;
134 defmt::info!("{:#x}", evt.mac_event());
135 }
136
137 info!("starting FFD device");
138 mbox.mac_subsystem
139 .send_command(&StartRequest {
140 pan_id: PanId([0x1A, 0xAA]),
141 channel_number: MacChannel::Channel16,
142 beacon_order: 0x0F,
143 superframe_order: 0x0F,
144 pan_coordinator: true,
145 battery_life_extension: false,
146 ..Default::default()
147 })
148 .await
149 .unwrap();
150 {
151 let evt = mbox.mac_subsystem.read().await;
152 defmt::info!("{:#x}", evt.mac_event());
153 }
154
155 info!("setting RX on when idle");
156 let rx_on_while_idle: bool = true;
157 mbox.mac_subsystem
158 .send_command(&SetRequest {
159 pib_attribute_ptr: &rx_on_while_idle as *const _ as *const u8,
160 pib_attribute: PibId::RxOnWhenIdle,
161 })
162 .await
163 .unwrap();
164 {
165 let evt = mbox.mac_subsystem.read().await;
166 defmt::info!("{:#x}", evt.mac_event());
167 }
168
169 loop {
170 let evt = mbox.mac_subsystem.read().await;
171 if let Ok(evt) = evt.mac_event() {
172 defmt::info!("parsed mac event");
173 defmt::info!("{:#x}", evt);
174
175 match evt {
176 MacEvent::MlmeAssociateInd(association) => mbox
177 .mac_subsystem
178 .send_command(&AssociateResponse {
179 device_address: association.device_address,
180 assoc_short_address: [0x33, 0x44],
181 status: MacStatus::Success,
182 security_level: SecurityLevel::Unsecure,
183 ..Default::default()
184 })
185 .await
186 .unwrap(),
187 MacEvent::McpsDataInd(data_ind) => {
188 let payload = data_ind.payload();
189 let ref_payload = b"Hello from embassy!";
190 info!("{}", payload);
191
192 if payload == ref_payload {
193 info!("success");
194 } else {
195 info!("ref payload: {}", ref_payload);
196 }
197 }
198 _ => {
199 defmt::info!("other mac event");
200 }
201 }
202 } else {
203 defmt::info!("failed to parse mac event");
204 }
205 }
206}
diff --git a/examples/stm32wb/src/bin/mac_rfd.rs b/examples/stm32wb/src/bin/mac_rfd.rs
new file mode 100644
index 000000000..7cb401d89
--- /dev/null
+++ b/examples/stm32wb/src/bin/mac_rfd.rs
@@ -0,0 +1,186 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts;
8use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
9use embassy_stm32_wpan::mac::commands::{AssociateRequest, DataRequest, GetRequest, ResetRequest, SetRequest};
10use embassy_stm32_wpan::mac::event::MacEvent;
11use embassy_stm32_wpan::mac::typedefs::{
12 AddressMode, Capabilities, KeyIdMode, MacAddress, MacChannel, PanId, PibId, SecurityLevel,
13};
14use embassy_stm32_wpan::sub::mm;
15use embassy_stm32_wpan::TlMbox;
16use {defmt_rtt as _, panic_probe as _};
17
18bind_interrupts!(struct Irqs{
19 IPCC_C1_RX => ReceiveInterruptHandler;
20 IPCC_C1_TX => TransmitInterruptHandler;
21});
22
23#[embassy_executor::task]
24async fn run_mm_queue(memory_manager: mm::MemoryManager) {
25 memory_manager.run_queue().await;
26}
27
28#[embassy_executor::main]
29async fn main(spawner: Spawner) {
30 /*
31 How to make this work:
32
33 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
34 - Download and Install STM32CubeProgrammer.
35 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
36 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
37 - Open STM32CubeProgrammer
38 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
39 - Once complete, click connect to connect to the device.
40 - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
41 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
42 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
43 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
44 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
45 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
46 - Select "Start Wireless Stack".
47 - Disconnect from the device.
48 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
49 - Run this example.
50
51 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
52 */
53
54 let p = embassy_stm32::init(Default::default());
55 info!("Hello World!");
56
57 let config = Config::default();
58 let mbox = TlMbox::init(p.IPCC, Irqs, config);
59
60 spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
61
62 let sys_event = mbox.sys_subsystem.read().await;
63 info!("sys event: {}", sys_event.payload());
64
65 core::mem::drop(sys_event);
66
67 let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
68 info!("initialized mac: {}", result);
69
70 info!("resetting");
71 mbox.mac_subsystem
72 .send_command(&ResetRequest {
73 set_default_pib: true,
74 ..Default::default()
75 })
76 .await
77 .unwrap();
78 {
79 let evt = mbox.mac_subsystem.read().await;
80 defmt::info!("{:#x}", evt.mac_event());
81 }
82
83 info!("setting extended address");
84 let extended_address: u64 = 0xACDE480000000002;
85 mbox.mac_subsystem
86 .send_command(&SetRequest {
87 pib_attribute_ptr: &extended_address as *const _ as *const u8,
88 pib_attribute: PibId::ExtendedAddress,
89 })
90 .await
91 .unwrap();
92 {
93 let evt = mbox.mac_subsystem.read().await;
94 defmt::info!("{:#x}", evt.mac_event());
95 }
96
97 info!("getting extended address");
98 mbox.mac_subsystem
99 .send_command(&GetRequest {
100 pib_attribute: PibId::ExtendedAddress,
101 ..Default::default()
102 })
103 .await
104 .unwrap();
105
106 {
107 let evt = mbox.mac_subsystem.read().await;
108 info!("{:#x}", evt.mac_event());
109
110 if let Ok(MacEvent::MlmeGetCnf(evt)) = evt.mac_event() {
111 if evt.pib_attribute_value_len == 8 {
112 let value = unsafe { core::ptr::read_unaligned(evt.pib_attribute_value_ptr as *const u64) };
113
114 info!("value {:#x}", value)
115 }
116 }
117 }
118
119 info!("assocation request");
120 let a = AssociateRequest {
121 channel_number: MacChannel::Channel16,
122 channel_page: 0,
123 coord_addr_mode: AddressMode::Short,
124 coord_address: MacAddress { short: [34, 17] },
125 capability_information: Capabilities::ALLOCATE_ADDRESS,
126 coord_pan_id: PanId([0x1A, 0xAA]),
127 security_level: SecurityLevel::Unsecure,
128 key_id_mode: KeyIdMode::Implicite,
129 key_source: [0; 8],
130 key_index: 152,
131 };
132 info!("{}", a);
133 mbox.mac_subsystem.send_command(&a).await.unwrap();
134 let short_addr = {
135 let evt = mbox.mac_subsystem.read().await;
136 info!("{:#x}", evt.mac_event());
137
138 if let Ok(MacEvent::MlmeAssociateCnf(conf)) = evt.mac_event() {
139 conf.assoc_short_address
140 } else {
141 defmt::panic!()
142 }
143 };
144
145 info!("setting short address");
146 mbox.mac_subsystem
147 .send_command(&SetRequest {
148 pib_attribute_ptr: &short_addr as *const _ as *const u8,
149 pib_attribute: PibId::ShortAddress,
150 })
151 .await
152 .unwrap();
153 {
154 let evt = mbox.mac_subsystem.read().await;
155 info!("{:#x}", evt.mac_event());
156 }
157
158 info!("sending data");
159 let data = b"Hello from embassy!";
160 mbox.mac_subsystem
161 .send_command(
162 DataRequest {
163 src_addr_mode: AddressMode::Short,
164 dst_addr_mode: AddressMode::Short,
165 dst_pan_id: PanId([0x1A, 0xAA]),
166 dst_address: MacAddress::BROADCAST,
167 msdu_handle: 0x02,
168 ack_tx: 0x00,
169 gts_tx: false,
170 security_level: SecurityLevel::Unsecure,
171 ..Default::default()
172 }
173 .set_buffer(data),
174 )
175 .await
176 .unwrap();
177 {
178 let evt = mbox.mac_subsystem.read().await;
179 info!("{:#x}", evt.mac_event());
180 }
181
182 loop {
183 let evt = mbox.mac_subsystem.read().await;
184 info!("{:#x}", evt.mac_event());
185 }
186}
diff --git a/examples/stm32wb/src/bin/tl_mbox.rs b/examples/stm32wb/src/bin/tl_mbox.rs
new file mode 100644
index 000000000..9fc4b8aac
--- /dev/null
+++ b/examples/stm32wb/src/bin/tl_mbox.rs
@@ -0,0 +1,76 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts;
8use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
9use embassy_stm32_wpan::TlMbox;
10use embassy_time::{Duration, Timer};
11use {defmt_rtt as _, panic_probe as _};
12
13bind_interrupts!(struct Irqs{
14 IPCC_C1_RX => ReceiveInterruptHandler;
15 IPCC_C1_TX => TransmitInterruptHandler;
16});
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) {
20 /*
21 How to make this work:
22
23 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
24 - Download and Install STM32CubeProgrammer.
25 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
26 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
27 - Open STM32CubeProgrammer
28 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
29 - Once complete, click connect to connect to the device.
30 - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
31 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
32 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
33 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
34 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
35 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
36 - Select "Start Wireless Stack".
37 - Disconnect from the device.
38 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
39 - Run this example.
40
41 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
42 */
43
44 let p = embassy_stm32::init(Default::default());
45 info!("Hello World!");
46
47 let config = Config::default();
48 let mbox = TlMbox::init(p.IPCC, Irqs, config);
49
50 loop {
51 let wireless_fw_info = mbox.sys_subsystem.wireless_fw_info();
52 match wireless_fw_info {
53 None => info!("not yet initialized"),
54 Some(fw_info) => {
55 let version_major = fw_info.version_major();
56 let version_minor = fw_info.version_minor();
57 let subversion = fw_info.subversion();
58
59 let sram2a_size = fw_info.sram2a_size();
60 let sram2b_size = fw_info.sram2b_size();
61
62 info!(
63 "version {}.{}.{} - SRAM2a {} - SRAM2b {}",
64 version_major, version_minor, subversion, sram2a_size, sram2b_size
65 );
66
67 break;
68 }
69 }
70
71 Timer::after(Duration::from_millis(50)).await;
72 }
73
74 info!("Test OK");
75 cortex_m::asm::bkpt();
76}
diff --git a/examples/stm32wb/src/bin/tl_mbox_ble.rs b/examples/stm32wb/src/bin/tl_mbox_ble.rs
new file mode 100644
index 000000000..90349422e
--- /dev/null
+++ b/examples/stm32wb/src/bin/tl_mbox_ble.rs
@@ -0,0 +1,64 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts;
8use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
9use embassy_stm32_wpan::TlMbox;
10use {defmt_rtt as _, panic_probe as _};
11
12bind_interrupts!(struct Irqs{
13 IPCC_C1_RX => ReceiveInterruptHandler;
14 IPCC_C1_TX => TransmitInterruptHandler;
15});
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 /*
20 How to make this work:
21
22 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
23 - Download and Install STM32CubeProgrammer.
24 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
25 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
26 - Open STM32CubeProgrammer
27 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
28 - Once complete, click connect to connect to the device.
29 - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
30 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
31 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
32 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
33 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
34 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
35 - Select "Start Wireless Stack".
36 - Disconnect from the device.
37 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
38 - Run this example.
39
40 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
41 */
42
43 let p = embassy_stm32::init(Default::default());
44 info!("Hello World!");
45
46 let config = Config::default();
47 let mbox = TlMbox::init(p.IPCC, Irqs, config);
48
49 let sys_event = mbox.sys_subsystem.read().await;
50 info!("sys event: {}", sys_event.payload());
51
52 let _ = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
53
54 info!("starting ble...");
55 mbox.ble_subsystem.tl_write(0x0c, &[]).await;
56
57 info!("waiting for ble...");
58 let ble_event = mbox.ble_subsystem.tl_read().await;
59
60 info!("ble event: {}", ble_event.payload());
61
62 info!("Test OK");
63 cortex_m::asm::bkpt();
64}
diff --git a/examples/stm32wb/src/bin/tl_mbox_mac.rs b/examples/stm32wb/src/bin/tl_mbox_mac.rs
new file mode 100644
index 000000000..5931c392b
--- /dev/null
+++ b/examples/stm32wb/src/bin/tl_mbox_mac.rs
@@ -0,0 +1,76 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::bind_interrupts;
8use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
9use embassy_stm32_wpan::sub::mm;
10use embassy_stm32_wpan::TlMbox;
11use {defmt_rtt as _, panic_probe as _};
12
13bind_interrupts!(struct Irqs{
14 IPCC_C1_RX => ReceiveInterruptHandler;
15 IPCC_C1_TX => TransmitInterruptHandler;
16});
17
18#[embassy_executor::task]
19async fn run_mm_queue(memory_manager: mm::MemoryManager) {
20 memory_manager.run_queue().await;
21}
22
23#[embassy_executor::main]
24async fn main(spawner: Spawner) {
25 /*
26 How to make this work:
27
28 - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
29 - Download and Install STM32CubeProgrammer.
30 - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
31 gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
32 - Open STM32CubeProgrammer
33 - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
34 - Once complete, click connect to connect to the device.
35 - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
36 - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
37 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
38 - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
39 stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
40 - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
41 - Select "Start Wireless Stack".
42 - Disconnect from the device.
43 - In the examples folder for stm32wb, modify the memory.x file to match your target device.
44 - Run this example.
45
46 Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
47 */
48
49 let p = embassy_stm32::init(Default::default());
50 info!("Hello World!");
51
52 let config = Config::default();
53 let mbox = TlMbox::init(p.IPCC, Irqs, config);
54
55 spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
56
57 let sys_event = mbox.sys_subsystem.read().await;
58 info!("sys event: {}", sys_event.payload());
59
60 core::mem::drop(sys_event);
61
62 let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
63 info!("initialized mac: {}", result);
64
65 //
66 // info!("starting ble...");
67 // mbox.ble_subsystem.t_write(0x0c, &[]).await;
68 //
69 // info!("waiting for ble...");
70 // let ble_event = mbox.ble_subsystem.tl_read().await;
71 //
72 // info!("ble event: {}", ble_event.payload());
73
74 info!("Test OK");
75 cortex_m::asm::bkpt();
76}
diff --git a/examples/stm32wl/.cargo/config.toml b/examples/stm32wl/.cargo/config.toml
index e395d75b4..ee416fcbc 100644
--- a/examples/stm32wl/.cargo/config.toml
+++ b/examples/stm32wl/.cargo/config.toml
@@ -1,9 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace your chip as listed in `probe-run --list-chips` 2# replace your chip as listed in `probe-rs chip list`
3runner = "probe-run --chip STM32WLE5JCIx" 3runner = "probe-rs run --chip STM32WLE5JCIx"
4 4
5[build] 5[build]
6target = "thumbv7em-none-eabihf" 6target = "thumbv7em-none-eabi"
7 7
8[env] 8[env]
9DEFMT_LOG = "trace" 9DEFMT_LOG = "trace"
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml
index 5f6679f4b..e2c66f456 100644
--- a/examples/stm32wl/Cargo.toml
+++ b/examples/stm32wl/Cargo.toml
@@ -2,24 +2,30 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32wl-examples" 3name = "embassy-stm32wl-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[dependencies] 7[dependencies]
7embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
8embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-32768hz"] } 10embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
10embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "subghz", "unstable-pac", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] }
12embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
11embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] } 13embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] }
12 14lora-phy = { version = "1" }
13lorawan-device = { version = "0.7.1", default-features = false, features = ["async"] } 15lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"] }
14lorawan = { version = "0.7.1", default-features = false, features = ["default-crypto"] } 16lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"] }
15 17
16defmt = "0.3" 18defmt = "0.3"
17defmt-rtt = "0.3" 19defmt-rtt = "0.4"
18 20
19cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
20cortex-m-rt = "0.7.0" 22cortex-m-rt = "0.7.0"
21embedded-hal = "0.2.6" 23embedded-hal = "0.2.6"
22embedded-storage = "0.3.0" 24embedded-storage = "0.3.0"
23panic-probe = { version = "0.3", features = ["print-defmt"] } 25panic-probe = { version = "0.3", features = ["print-defmt"] }
24futures = { version = "0.3.17", default-features = false, features = ["async-await"] } 26futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
25heapless = { version = "0.7.5", default-features = false } 27heapless = { version = "0.7.5", default-features = false }
28chrono = { version = "^0.4", default-features = false }
29
30[patch.crates-io]
31lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "ad289428fd44b02788e2fa2116445cc8f640a265" }
diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs
index eb7489760..5e52d49ec 100644
--- a/examples/stm32wl/src/bin/flash.rs
+++ b/examples/stm32wl/src/bin/flash.rs
@@ -5,7 +5,6 @@
5use defmt::{info, unwrap}; 5use defmt::{info, unwrap};
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::flash::Flash; 7use embassy_stm32::flash::Flash;
8use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
9use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
10 9
11#[embassy_executor::main] 10#[embassy_executor::main]
@@ -15,27 +14,27 @@ async fn main(_spawner: Spawner) {
15 14
16 const ADDR: u32 = 0x36000; 15 const ADDR: u32 = 0x36000;
17 16
18 let mut f = Flash::unlock(p.FLASH); 17 let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region;
19 18
20 info!("Reading..."); 19 info!("Reading...");
21 let mut buf = [0u8; 8]; 20 let mut buf = [0u8; 8];
22 unwrap!(f.read(ADDR, &mut buf)); 21 unwrap!(f.blocking_read(ADDR, &mut buf));
23 info!("Read: {=[u8]:x}", buf); 22 info!("Read: {=[u8]:x}", buf);
24 23
25 info!("Erasing..."); 24 info!("Erasing...");
26 unwrap!(f.erase(ADDR, ADDR + 2048)); 25 unwrap!(f.blocking_erase(ADDR, ADDR + 2048));
27 26
28 info!("Reading..."); 27 info!("Reading...");
29 let mut buf = [0u8; 8]; 28 let mut buf = [0u8; 8];
30 unwrap!(f.read(ADDR, &mut buf)); 29 unwrap!(f.blocking_read(ADDR, &mut buf));
31 info!("Read: {=[u8]:x}", buf); 30 info!("Read: {=[u8]:x}", buf);
32 31
33 info!("Writing..."); 32 info!("Writing...");
34 unwrap!(f.write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); 33 unwrap!(f.blocking_write(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8]));
35 34
36 info!("Reading..."); 35 info!("Reading...");
37 let mut buf = [0u8; 8]; 36 let mut buf = [0u8; 8];
38 unwrap!(f.read(ADDR, &mut buf)); 37 unwrap!(f.blocking_read(ADDR, &mut buf));
39 info!("Read: {=[u8]:x}", buf); 38 info!("Read: {=[u8]:x}", buf);
40 assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]); 39 assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]);
41} 40}
diff --git a/examples/stm32wl/src/bin/lora_lorawan.rs b/examples/stm32wl/src/bin/lora_lorawan.rs
new file mode 100644
index 000000000..805d21418
--- /dev/null
+++ b/examples/stm32wl/src/bin/lora_lorawan.rs
@@ -0,0 +1,80 @@
1//! This example runs on a STM32WL board, which has a builtin Semtech Sx1262 radio.
2//! It demonstrates LoRaWAN join functionality.
3#![no_std]
4#![no_main]
5#![macro_use]
6#![feature(type_alias_impl_trait, async_fn_in_trait)]
7
8use defmt::info;
9use embassy_executor::Spawner;
10use embassy_lora::iv::{InterruptHandler, Stm32wlInterfaceVariant};
11use embassy_lora::LoraTimer;
12use embassy_stm32::gpio::{Level, Output, Pin, Speed};
13use embassy_stm32::rng::Rng;
14use embassy_stm32::spi::Spi;
15use embassy_stm32::{bind_interrupts, pac};
16use embassy_time::Delay;
17use lora_phy::mod_params::*;
18use lora_phy::sx1261_2::SX1261_2;
19use lora_phy::LoRa;
20use lorawan::default_crypto::DefaultFactory as Crypto;
21use lorawan_device::async_device::lora_radio::LoRaRadio;
22use lorawan_device::async_device::{region, Device, JoinMode};
23use {defmt_rtt as _, panic_probe as _};
24
25const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set this appropriately for the region
26
27bind_interrupts!(struct Irqs{
28 SUBGHZ_RADIO => InterruptHandler;
29});
30
31#[embassy_executor::main]
32async fn main(_spawner: Spawner) {
33 let mut config = embassy_stm32::Config::default();
34 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32;
35 config.rcc.enable_lsi = true; // enable RNG
36 let p = embassy_stm32::init(config);
37
38 pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01));
39
40 let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2);
41
42 // Set CTRL1 and CTRL3 for high-power transmission, while CTRL2 acts as an RF switch between tx and rx
43 let _ctrl1 = Output::new(p.PC4.degrade(), Level::Low, Speed::High);
44 let ctrl2 = Output::new(p.PC5.degrade(), Level::High, Speed::High);
45 let _ctrl3 = Output::new(p.PC3.degrade(), Level::High, Speed::High);
46 let iv = Stm32wlInterfaceVariant::new(Irqs, None, Some(ctrl2)).unwrap();
47
48 let mut delay = Delay;
49
50 let lora = {
51 match LoRa::new(SX1261_2::new(BoardType::Stm32wlSx1262, spi, iv), true, &mut delay).await {
52 Ok(l) => l,
53 Err(err) => {
54 info!("Radio error = {}", err);
55 return;
56 }
57 }
58 };
59 let radio = LoRaRadio::new(lora);
60 let region: region::Configuration = region::Configuration::new(LORAWAN_REGION);
61 let mut device: Device<_, Crypto, _, _> = Device::new(region, radio, LoraTimer::new(), Rng::new(p.RNG));
62
63 defmt::info!("Joining LoRaWAN network");
64
65 // TODO: Adjust the EUI and Keys according to your network credentials
66 match device
67 .join(&JoinMode::OTAA {
68 deveui: [0, 0, 0, 0, 0, 0, 0, 0],
69 appeui: [0, 0, 0, 0, 0, 0, 0, 0],
70 appkey: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
71 })
72 .await
73 {
74 Ok(()) => defmt::info!("LoRaWAN network joined"),
75 Err(err) => {
76 info!("Radio error = {}", err);
77 return;
78 }
79 };
80}
diff --git a/examples/stm32wl/src/bin/lora_p2p_receive.rs b/examples/stm32wl/src/bin/lora_p2p_receive.rs
new file mode 100644
index 000000000..d3f051b1c
--- /dev/null
+++ b/examples/stm32wl/src/bin/lora_p2p_receive.rs
@@ -0,0 +1,117 @@
1//! This example runs on the STM32WL board, which has a builtin Semtech Sx1262 radio.
2//! It demonstrates LORA P2P receive functionality in conjunction with the lora_p2p_send example.
3#![no_std]
4#![no_main]
5#![macro_use]
6#![feature(type_alias_impl_trait, async_fn_in_trait)]
7
8use defmt::info;
9use embassy_executor::Spawner;
10use embassy_lora::iv::{InterruptHandler, Stm32wlInterfaceVariant};
11use embassy_stm32::bind_interrupts;
12use embassy_stm32::gpio::{Level, Output, Pin, Speed};
13use embassy_stm32::spi::Spi;
14use embassy_time::{Delay, Duration, Timer};
15use lora_phy::mod_params::*;
16use lora_phy::sx1261_2::SX1261_2;
17use lora_phy::LoRa;
18use {defmt_rtt as _, panic_probe as _};
19
20const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
21
22bind_interrupts!(struct Irqs{
23 SUBGHZ_RADIO => InterruptHandler;
24});
25
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 let mut config = embassy_stm32::Config::default();
29 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32;
30 let p = embassy_stm32::init(config);
31
32 let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2);
33
34 // Set CTRL1 and CTRL3 for high-power transmission, while CTRL2 acts as an RF switch between tx and rx
35 let _ctrl1 = Output::new(p.PC4.degrade(), Level::Low, Speed::High);
36 let ctrl2 = Output::new(p.PC5.degrade(), Level::High, Speed::High);
37 let _ctrl3 = Output::new(p.PC3.degrade(), Level::High, Speed::High);
38 let iv = Stm32wlInterfaceVariant::new(Irqs, None, Some(ctrl2)).unwrap();
39
40 let mut delay = Delay;
41
42 let mut lora = {
43 match LoRa::new(SX1261_2::new(BoardType::Stm32wlSx1262, spi, iv), false, &mut delay).await {
44 Ok(l) => l,
45 Err(err) => {
46 info!("Radio error = {}", err);
47 return;
48 }
49 }
50 };
51
52 let mut debug_indicator = Output::new(p.PB9, Level::Low, Speed::Low);
53 let mut start_indicator = Output::new(p.PB15, Level::Low, Speed::Low);
54
55 start_indicator.set_high();
56 Timer::after(Duration::from_secs(5)).await;
57 start_indicator.set_low();
58
59 let mut receiving_buffer = [00u8; 100];
60
61 let mdltn_params = {
62 match lora.create_modulation_params(
63 SpreadingFactor::_10,
64 Bandwidth::_250KHz,
65 CodingRate::_4_8,
66 LORA_FREQUENCY_IN_HZ,
67 ) {
68 Ok(mp) => mp,
69 Err(err) => {
70 info!("Radio error = {}", err);
71 return;
72 }
73 }
74 };
75
76 let rx_pkt_params = {
77 match lora.create_rx_packet_params(4, false, receiving_buffer.len() as u8, true, false, &mdltn_params) {
78 Ok(pp) => pp,
79 Err(err) => {
80 info!("Radio error = {}", err);
81 return;
82 }
83 }
84 };
85
86 match lora
87 .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, true, false, 0, 0x00ffffffu32)
88 .await
89 {
90 Ok(()) => {}
91 Err(err) => {
92 info!("Radio error = {}", err);
93 return;
94 }
95 };
96
97 loop {
98 receiving_buffer = [00u8; 100];
99 match lora.rx(&rx_pkt_params, &mut receiving_buffer).await {
100 Ok((received_len, _rx_pkt_status)) => {
101 if (received_len == 3)
102 && (receiving_buffer[0] == 0x01u8)
103 && (receiving_buffer[1] == 0x02u8)
104 && (receiving_buffer[2] == 0x03u8)
105 {
106 info!("rx successful");
107 debug_indicator.set_high();
108 Timer::after(Duration::from_secs(5)).await;
109 debug_indicator.set_low();
110 } else {
111 info!("rx unknown packet");
112 }
113 }
114 Err(err) => info!("rx unsuccessful = {}", err),
115 }
116 }
117}
diff --git a/examples/stm32wl/src/bin/lora_p2p_send.rs b/examples/stm32wl/src/bin/lora_p2p_send.rs
new file mode 100644
index 000000000..fc5205c85
--- /dev/null
+++ b/examples/stm32wl/src/bin/lora_p2p_send.rs
@@ -0,0 +1,100 @@
1//! This example runs on a STM32WL board, which has a builtin Semtech Sx1262 radio.
2//! It demonstrates LORA P2P send functionality.
3#![no_std]
4#![no_main]
5#![macro_use]
6#![feature(type_alias_impl_trait, async_fn_in_trait)]
7
8use defmt::info;
9use embassy_executor::Spawner;
10use embassy_lora::iv::{InterruptHandler, Stm32wlInterfaceVariant};
11use embassy_stm32::bind_interrupts;
12use embassy_stm32::gpio::{Level, Output, Pin, Speed};
13use embassy_stm32::spi::Spi;
14use embassy_time::Delay;
15use lora_phy::mod_params::*;
16use lora_phy::sx1261_2::SX1261_2;
17use lora_phy::LoRa;
18use {defmt_rtt as _, panic_probe as _};
19
20const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
21
22bind_interrupts!(struct Irqs{
23 SUBGHZ_RADIO => InterruptHandler;
24});
25
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 let mut config = embassy_stm32::Config::default();
29 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32;
30 let p = embassy_stm32::init(config);
31
32 let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2);
33
34 // Set CTRL1 and CTRL3 for high-power transmission, while CTRL2 acts as an RF switch between tx and rx
35 let _ctrl1 = Output::new(p.PC4.degrade(), Level::Low, Speed::High);
36 let ctrl2 = Output::new(p.PC5.degrade(), Level::High, Speed::High);
37 let _ctrl3 = Output::new(p.PC3.degrade(), Level::High, Speed::High);
38 let iv = Stm32wlInterfaceVariant::new(Irqs, None, Some(ctrl2)).unwrap();
39
40 let mut delay = Delay;
41
42 let mut lora = {
43 match LoRa::new(SX1261_2::new(BoardType::Stm32wlSx1262, spi, iv), false, &mut delay).await {
44 Ok(l) => l,
45 Err(err) => {
46 info!("Radio error = {}", err);
47 return;
48 }
49 }
50 };
51
52 let mdltn_params = {
53 match lora.create_modulation_params(
54 SpreadingFactor::_10,
55 Bandwidth::_250KHz,
56 CodingRate::_4_8,
57 LORA_FREQUENCY_IN_HZ,
58 ) {
59 Ok(mp) => mp,
60 Err(err) => {
61 info!("Radio error = {}", err);
62 return;
63 }
64 }
65 };
66
67 let mut tx_pkt_params = {
68 match lora.create_tx_packet_params(4, false, true, false, &mdltn_params) {
69 Ok(pp) => pp,
70 Err(err) => {
71 info!("Radio error = {}", err);
72 return;
73 }
74 }
75 };
76
77 match lora.prepare_for_tx(&mdltn_params, 20, false).await {
78 Ok(()) => {}
79 Err(err) => {
80 info!("Radio error = {}", err);
81 return;
82 }
83 };
84
85 let buffer = [0x01u8, 0x02u8, 0x03u8];
86 match lora.tx(&mdltn_params, &mut tx_pkt_params, &buffer, 0xffffff).await {
87 Ok(()) => {
88 info!("TX DONE");
89 }
90 Err(err) => {
91 info!("Radio error = {}", err);
92 return;
93 }
94 };
95
96 match lora.sleep(&mut delay).await {
97 Ok(()) => info!("Sleep successful"),
98 Err(err) => info!("Sleep unsuccessful = {}", err),
99 }
100}
diff --git a/examples/stm32wl/src/bin/lorawan.rs b/examples/stm32wl/src/bin/lorawan.rs
deleted file mode 100644
index 7e8a8946d..000000000
--- a/examples/stm32wl/src/bin/lorawan.rs
+++ /dev/null
@@ -1,78 +0,0 @@
1#![no_std]
2#![no_main]
3#![macro_use]
4#![allow(dead_code)]
5#![feature(generic_associated_types)]
6#![feature(type_alias_impl_trait)]
7
8use embassy_executor::Spawner;
9use embassy_lora::stm32wl::*;
10use embassy_lora::LoraTimer;
11use embassy_stm32::dma::NoDma;
12use embassy_stm32::gpio::{Level, Output, Pin, Speed};
13use embassy_stm32::rng::Rng;
14use embassy_stm32::subghz::*;
15use embassy_stm32::{interrupt, pac};
16use lorawan::default_crypto::DefaultFactory as Crypto;
17use lorawan_device::async_device::{region, Device, JoinMode};
18use {defmt_rtt as _, panic_probe as _};
19
20#[embassy_executor::main]
21async fn main(_spawner: Spawner) {
22 let mut config = embassy_stm32::Config::default();
23 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI16;
24 config.rcc.enable_lsi = true;
25 let p = embassy_stm32::init(config);
26
27 unsafe { pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01)) }
28
29 let ctrl1 = Output::new(p.PC3.degrade(), Level::High, Speed::High);
30 let ctrl2 = Output::new(p.PC4.degrade(), Level::High, Speed::High);
31 let ctrl3 = Output::new(p.PC5.degrade(), Level::High, Speed::High);
32 let rfs = RadioSwitch::new(ctrl1, ctrl2, ctrl3);
33
34 let radio = SubGhz::new(p.SUBGHZSPI, p.PA5, p.PA7, p.PA6, NoDma, NoDma);
35
36 let irq = interrupt::take!(SUBGHZ_RADIO);
37 static mut RADIO_STATE: SubGhzState<'static> = SubGhzState::new();
38 let radio = unsafe { SubGhzRadio::new(&mut RADIO_STATE, radio, rfs, irq) };
39
40 let mut region: region::Configuration = region::EU868::default().into();
41
42 // NOTE: This is specific for TTN, as they have a special RX1 delay
43 region.set_receive_delay1(5000);
44
45 let mut device: Device<_, Crypto, _, _> = Device::new(region, radio, LoraTimer, Rng::new(p.RNG));
46
47 // Depending on network, this might be part of JOIN
48 device.set_datarate(region::DR::_0); // SF12
49
50 // device.set_datarate(region::DR::_1); // SF11
51 // device.set_datarate(region::DR::_2); // SF10
52 // device.set_datarate(region::DR::_3); // SF9
53 // device.set_datarate(region::DR::_4); // SF8
54 // device.set_datarate(region::DR::_5); // SF7
55
56 defmt::info!("Joining LoRaWAN network");
57
58 // TODO: Adjust the EUI and Keys according to your network credentials
59 device
60 .join(&JoinMode::OTAA {
61 deveui: [0, 0, 0, 0, 0, 0, 0, 0],
62 appeui: [0, 0, 0, 0, 0, 0, 0, 0],
63 appkey: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
64 })
65 .await
66 .ok()
67 .unwrap();
68 defmt::info!("LoRaWAN network joined");
69
70 let mut rx: [u8; 255] = [0; 255];
71 defmt::info!("Sending 'PING'");
72 let len = device.send_recv(b"PING", &mut rx[..], 1, true).await.ok().unwrap();
73 if len > 0 {
74 defmt::info!("Message sent, received downlink: {:?}", &rx[..len]);
75 } else {
76 defmt::info!("Message sent!");
77 }
78}
diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs
new file mode 100644
index 000000000..d8562fca5
--- /dev/null
+++ b/examples/stm32wl/src/bin/random.rs
@@ -0,0 +1,31 @@
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 pac::RCC.ccipr().modify(|w| {
19 w.set_rngsel(0b01);
20 });
21
22 info!("Hello World!");
23
24 let mut rng = Rng::new(p.RNG);
25
26 let mut buf = [0u8; 16];
27 unwrap!(rng.async_fill_bytes(&mut buf).await);
28 info!("random bytes: {:02x}", buf);
29
30 loop {}
31}
diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs
new file mode 100644
index 000000000..e11825499
--- /dev/null
+++ b/examples/stm32wl/src/bin/rtc.rs
@@ -0,0 +1,43 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use chrono::{NaiveDate, NaiveDateTime};
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_stm32::rcc::{self, ClockSrc};
9use embassy_stm32::rtc::{Rtc, RtcConfig};
10use embassy_stm32::Config;
11use embassy_time::{Duration, Timer};
12use {defmt_rtt as _, panic_probe as _};
13
14#[embassy_executor::main]
15async fn main(_spawner: Spawner) {
16 let p = {
17 let mut config = Config::default();
18 config.rcc.mux = ClockSrc::HSE32;
19 config.rcc.rtc_mux = rcc::RtcClockSource::LSE32;
20 config.rcc.enable_rtc_apb = true;
21 embassy_stm32::init(config)
22 };
23 info!("Hello World!");
24
25 let now = NaiveDate::from_ymd_opt(2020, 5, 15)
26 .unwrap()
27 .and_hms_opt(10, 30, 15)
28 .unwrap();
29
30 let mut rtc = Rtc::new(
31 p.RTC,
32 RtcConfig::default().clock_config(embassy_stm32::rtc::RtcClockSource::LSE),
33 );
34 info!("Got RTC! {:?}", now.timestamp());
35
36 rtc.set_datetime(now.into()).expect("datetime not set");
37
38 // In reality the delay would be much longer
39 Timer::after(Duration::from_millis(20000)).await;
40
41 let then: NaiveDateTime = rtc.now().unwrap().into();
42 info!("Got RTC! {:?}", then.timestamp());
43}
diff --git a/examples/stm32wl/src/bin/subghz.rs b/examples/stm32wl/src/bin/subghz.rs
deleted file mode 100644
index c5e9bb597..000000000
--- a/examples/stm32wl/src/bin/subghz.rs
+++ /dev/null
@@ -1,119 +0,0 @@
1#![no_std]
2#![no_main]
3#![macro_use]
4#![allow(dead_code)]
5#![feature(generic_associated_types)]
6#![feature(type_alias_impl_trait)]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_stm32::dma::NoDma;
11use embassy_stm32::exti::ExtiInput;
12use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
13use embassy_stm32::interrupt;
14use embassy_stm32::interrupt::{Interrupt, InterruptExt};
15use embassy_stm32::subghz::*;
16use embassy_sync::signal::Signal;
17use {defmt_rtt as _, panic_probe as _};
18
19const PING_DATA: &str = "PING";
20const DATA_LEN: u8 = PING_DATA.len() as u8;
21const PING_DATA_BYTES: &[u8] = PING_DATA.as_bytes();
22const PREAMBLE_LEN: u16 = 5 * 8;
23
24const RF_FREQ: RfFreq = RfFreq::from_frequency(867_500_000);
25
26const SYNC_WORD: [u8; 8] = [0x79, 0x80, 0x0C, 0xC0, 0x29, 0x95, 0xF8, 0x4A];
27const SYNC_WORD_LEN: u8 = SYNC_WORD.len() as u8;
28const SYNC_WORD_LEN_BITS: u8 = SYNC_WORD_LEN * 8;
29
30const TX_BUF_OFFSET: u8 = 128;
31const RX_BUF_OFFSET: u8 = 0;
32const LORA_PACKET_PARAMS: LoRaPacketParams = LoRaPacketParams::new()
33 .set_crc_en(true)
34 .set_preamble_len(PREAMBLE_LEN)
35 .set_payload_len(DATA_LEN)
36 .set_invert_iq(false)
37 .set_header_type(HeaderType::Fixed);
38
39const LORA_MOD_PARAMS: LoRaModParams = LoRaModParams::new()
40 .set_bw(LoRaBandwidth::Bw125)
41 .set_cr(CodingRate::Cr45)
42 .set_ldro_en(true)
43 .set_sf(SpreadingFactor::Sf7);
44
45// configuration for +10 dBm output power
46// see table 35 "PA optimal setting and operating modes"
47const PA_CONFIG: PaConfig = PaConfig::new().set_pa_duty_cycle(0x1).set_hp_max(0x0).set_pa(PaSel::Lp);
48
49const TCXO_MODE: TcxoMode = TcxoMode::new()
50 .set_txco_trim(TcxoTrim::Volts1pt7)
51 .set_timeout(Timeout::from_duration_sat(core::time::Duration::from_millis(10)));
52
53const TX_PARAMS: TxParams = TxParams::new().set_power(0x0D).set_ramp_time(RampTime::Micros40);
54
55#[embassy_executor::main]
56async fn main(_spawner: Spawner) {
57 let mut config = embassy_stm32::Config::default();
58 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32;
59 let p = embassy_stm32::init(config);
60
61 let mut led1 = Output::new(p.PB15, Level::High, Speed::Low);
62 let mut led2 = Output::new(p.PB9, Level::Low, Speed::Low);
63 let mut led3 = Output::new(p.PB11, Level::Low, Speed::Low);
64
65 let button = Input::new(p.PA0, Pull::Up);
66 let mut pin = ExtiInput::new(button, p.EXTI0);
67
68 static IRQ_SIGNAL: Signal<()> = Signal::new();
69 let radio_irq = interrupt::take!(SUBGHZ_RADIO);
70 radio_irq.set_handler(|_| {
71 IRQ_SIGNAL.signal(());
72 unsafe { interrupt::SUBGHZ_RADIO::steal() }.disable();
73 });
74
75 let mut radio = SubGhz::new(p.SUBGHZSPI, p.PA5, p.PA7, p.PA6, NoDma, NoDma);
76
77 defmt::info!("Radio ready for use");
78
79 led1.set_low();
80
81 led2.set_high();
82
83 unwrap!(radio.set_standby(StandbyClk::Rc));
84 unwrap!(radio.set_tcxo_mode(&TCXO_MODE));
85 unwrap!(radio.set_standby(StandbyClk::Hse));
86 unwrap!(radio.set_regulator_mode(RegMode::Ldo));
87 unwrap!(radio.set_buffer_base_address(TX_BUF_OFFSET, RX_BUF_OFFSET));
88 unwrap!(radio.set_pa_config(&PA_CONFIG));
89 unwrap!(radio.set_pa_ocp(Ocp::Max60m));
90 unwrap!(radio.set_tx_params(&TX_PARAMS));
91 unwrap!(radio.set_packet_type(PacketType::LoRa));
92 unwrap!(radio.set_lora_sync_word(LoRaSyncWord::Public));
93 unwrap!(radio.set_lora_mod_params(&LORA_MOD_PARAMS));
94 unwrap!(radio.set_lora_packet_params(&LORA_PACKET_PARAMS));
95 unwrap!(radio.calibrate_image(CalibrateImage::ISM_863_870));
96 unwrap!(radio.set_rf_frequency(&RF_FREQ));
97
98 defmt::info!("Status: {:?}", unwrap!(radio.status()));
99
100 led2.set_low();
101
102 loop {
103 pin.wait_for_rising_edge().await;
104 led3.set_high();
105 unwrap!(radio.set_irq_cfg(&CfgIrq::new().irq_enable_all(Irq::TxDone)));
106 unwrap!(radio.write_buffer(TX_BUF_OFFSET, PING_DATA_BYTES));
107 unwrap!(radio.set_tx(Timeout::DISABLED));
108
109 radio_irq.enable();
110 IRQ_SIGNAL.wait().await;
111
112 let (_, irq_status) = unwrap!(radio.irq_status());
113 if irq_status & Irq::TxDone.mask() != 0 {
114 defmt::info!("TX done");
115 }
116 unwrap!(radio.clear_irq_status(irq_status));
117 led3.set_low();
118 }
119}
diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs
new file mode 100644
index 000000000..07b0f9d2c
--- /dev/null
+++ b/examples/stm32wl/src/bin/uart_async.rs
@@ -0,0 +1,63 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_stm32::usart::{Config, InterruptHandler, Uart};
8use embassy_stm32::{bind_interrupts, peripherals};
9use {defmt_rtt as _, panic_probe as _};
10
11bind_interrupts!(struct Irqs{
12 USART1 => InterruptHandler<peripherals::USART1>;
13 LPUART1 => InterruptHandler<peripherals::LPUART1>;
14});
15
16/*
17Pass Incoming data from LPUART1 to USART1
18Example is written for the LoRa-E5 mini v1.0,
19but can be surely changed for your needs.
20*/
21#[embassy_executor::main]
22async fn main(_spawner: Spawner) {
23 let mut config = embassy_stm32::Config::default();
24 config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32;
25 let p = embassy_stm32::init(config);
26
27 defmt::info!("Starting system");
28
29 let mut config1 = Config::default();
30 config1.baudrate = 9600;
31
32 let mut config2 = Config::default();
33 config2.baudrate = 9600;
34
35 //RX/TX connected to USB/UART Bridge on LoRa-E5 mini v1.0
36 let mut usart1 = Uart::new(p.USART1, p.PB7, p.PB6, Irqs, p.DMA1_CH3, p.DMA1_CH4, config1);
37
38 //RX1/TX1 (LPUART) on LoRa-E5 mini v1.0
39 let mut usart2 = Uart::new(p.LPUART1, p.PC0, p.PC1, Irqs, p.DMA1_CH5, p.DMA1_CH6, config2);
40
41 unwrap!(usart1.write(b"Hello Embassy World!\r\n").await);
42 unwrap!(usart2.write(b"Hello Embassy World!\r\n").await);
43
44 let mut buf = [0u8; 300];
45 loop {
46 let result = usart2.read_until_idle(&mut buf).await;
47 match result {
48 Ok(size) => {
49 match usart1.write(&buf[0..size]).await {
50 Ok(()) => {
51 //Write suc.
52 }
53 Err(..) => {
54 //Wasn't able to write
55 }
56 }
57 }
58 Err(_err) => {
59 //Ignore eg. framing errors
60 }
61 }
62 }
63}
diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml
index ea61fb921..3679e3857 100644
--- a/examples/wasm/Cargo.toml
+++ b/examples/wasm/Cargo.toml
@@ -2,14 +2,15 @@
2edition = "2021" 2edition = "2021"
3name = "embassy-wasm-example" 3name = "embassy-wasm-example"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0"
5 6
6[lib] 7[lib]
7crate-type = ["cdylib"] 8crate-type = ["cdylib"]
8 9
9[dependencies] 10[dependencies]
10embassy-sync = { version = "0.1.0", path = "../../embassy-sync", features = ["log"] } 11embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["log"] }
11embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features = ["log", "wasm", "nightly", "integrated-timers"] } 12embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "nightly", "integrated-timers"] }
12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["log", "wasm", "nightly"] } 13embassy-time = { version = "0.1.2", path = "../../embassy-time", features = ["log", "wasm", "nightly"] }
13 14
14wasm-logger = "0.2.0" 15wasm-logger = "0.2.0"
15wasm-bindgen = "0.2" 16wasm-bindgen = "0.2"
diff --git a/examples/wasm/src/lib.rs b/examples/wasm/src/lib.rs
index d44c020b6..edfe8bafc 100644
--- a/examples/wasm/src/lib.rs
+++ b/examples/wasm/src/lib.rs
@@ -1,5 +1,4 @@
1#![feature(type_alias_impl_trait)] 1#![feature(type_alias_impl_trait)]
2#![allow(incomplete_features)]
3 2
4use embassy_executor::Spawner; 3use embassy_executor::Spawner;
5use embassy_time::{Duration, Timer}; 4use embassy_time::{Duration, Timer};