aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorklownfish <[email protected]>2024-09-11 11:55:50 +0200
committerklownfish <[email protected]>2024-09-11 11:55:50 +0200
commitf0a86d1a344eac1528ce8653c573d1fe840b4083 (patch)
tree426b03be0f9306261c8d12e75d58a1fcafcbf2e7
parent0ba91ca555efc75dca603adbb51355c92b2fdb80 (diff)
parent7648d42b7f23a2caad29ed6e16123b088ccdc8b5 (diff)
Merge branch 'main' of github.com:embassy-rs/embassy
-rwxr-xr-x.github/ci/test.sh7
-rwxr-xr-xci.sh58
-rw-r--r--[-rwxr-xr-x]cyw43-firmware/43439A0.binbin230321 -> 231077 bytes
-rw-r--r--cyw43-firmware/43439A0_btfw.binbin0 -> 6164 bytes
-rw-r--r--[-rwxr-xr-x]cyw43-firmware/43439A0_clm.binbin4752 -> 984 bytes
-rw-r--r--cyw43-firmware/README.md11
-rw-r--r--cyw43-pio/CHANGELOG.md17
-rw-r--r--cyw43-pio/Cargo.toml7
-rw-r--r--cyw43-pio/src/lib.rs9
-rw-r--r--cyw43/CHANGELOG.md23
-rw-r--r--cyw43/Cargo.toml14
-rw-r--r--cyw43/src/bluetooth.rs508
-rw-r--r--cyw43/src/bus.rs90
-rw-r--r--cyw43/src/consts.rs381
-rw-r--r--cyw43/src/control.rs249
-rw-r--r--cyw43/src/fmt.rs16
-rw-r--r--cyw43/src/ioctl.rs7
-rw-r--r--cyw43/src/lib.rs91
-rw-r--r--cyw43/src/runner.rs131
-rw-r--r--cyw43/src/structs.rs9
-rw-r--r--cyw43/src/util.rs20
-rw-r--r--docs/examples/basic/Cargo.toml6
-rw-r--r--docs/examples/layer-by-layer/blinky-async/Cargo.toml2
-rw-r--r--docs/pages/basic_application.adoc2
-rw-r--r--docs/pages/embassy_in_the_wild.adoc2
-rw-r--r--docs/pages/faq.adoc17
-rw-r--r--docs/pages/new_project.adoc2
-rw-r--r--docs/pages/nrf.adoc2
-rw-r--r--docs/pages/overview.adoc6
-rw-r--r--docs/pages/sharing_peripherals.adoc10
-rw-r--r--docs/pages/stm32.adoc2
-rw-r--r--docs/pages/time_keeping.adoc4
-rw-r--r--embassy-boot-nrf/Cargo.toml6
-rw-r--r--embassy-boot-nrf/src/fmt.rs16
-rw-r--r--embassy-boot-rp/Cargo.toml9
-rw-r--r--embassy-boot-rp/src/fmt.rs16
-rw-r--r--embassy-boot-stm32/Cargo.toml2
-rw-r--r--embassy-boot-stm32/src/fmt.rs16
-rw-r--r--embassy-boot/Cargo.toml8
-rw-r--r--embassy-boot/src/boot_loader.rs8
-rw-r--r--embassy-boot/src/fmt.rs16
-rw-r--r--embassy-embedded-hal/CHANGELOG.md21
-rw-r--r--embassy-embedded-hal/Cargo.toml4
-rw-r--r--embassy-embedded-hal/src/flash/partition/asynch.rs10
-rw-r--r--embassy-embedded-hal/src/flash/partition/blocking.rs10
-rw-r--r--embassy-executor-macros/Cargo.toml2
-rw-r--r--embassy-executor-macros/src/macros/main.rs2
-rw-r--r--embassy-executor/CHANGELOG.md6
-rw-r--r--embassy-executor/Cargo.toml6
-rw-r--r--embassy-executor/build_common.rs21
-rw-r--r--embassy-executor/src/fmt.rs16
-rw-r--r--embassy-executor/src/lib.rs1
-rw-r--r--embassy-executor/src/raw/waker.rs3
-rw-r--r--embassy-futures/src/fmt.rs16
-rw-r--r--embassy-futures/src/select.rs35
-rw-r--r--embassy-hal-internal/Cargo.toml2
-rw-r--r--embassy-hal-internal/build_common.rs21
-rw-r--r--embassy-hal-internal/src/fmt.rs16
-rw-r--r--embassy-net-adin1110/Cargo.toml4
-rw-r--r--embassy-net-adin1110/README.md2
-rw-r--r--embassy-net-adin1110/src/crc8.rs2
-rw-r--r--embassy-net-adin1110/src/fmt.rs16
-rw-r--r--embassy-net-driver-channel/CHANGELOG.md7
-rw-r--r--embassy-net-driver-channel/Cargo.toml2
-rw-r--r--embassy-net-driver-channel/src/fmt.rs16
-rw-r--r--embassy-net-enc28j60/Cargo.toml2
-rw-r--r--embassy-net-enc28j60/src/fmt.rs16
-rw-r--r--embassy-net-esp-hosted/Cargo.toml4
-rw-r--r--embassy-net-esp-hosted/src/fmt.rs16
-rw-r--r--embassy-net-esp-hosted/src/proto.rs2
-rw-r--r--embassy-net-nrf91/Cargo.toml38
-rw-r--r--embassy-net-nrf91/README.md9
-rw-r--r--embassy-net-nrf91/src/context.rs350
-rw-r--r--embassy-net-nrf91/src/fmt.rs274
-rw-r--r--embassy-net-nrf91/src/lib.rs1046
-rw-r--r--embassy-net-ppp/Cargo.toml2
-rw-r--r--embassy-net-ppp/src/fmt.rs16
-rw-r--r--embassy-net-wiznet/Cargo.toml4
-rw-r--r--embassy-net/Cargo.toml4
-rw-r--r--embassy-net/src/fmt.rs16
-rw-r--r--embassy-net/src/lib.rs23
-rw-r--r--embassy-net/src/tcp.rs37
-rw-r--r--embassy-net/src/udp.rs63
-rw-r--r--embassy-nrf/CHANGELOG.md48
-rw-r--r--embassy-nrf/Cargo.toml25
-rw-r--r--embassy-nrf/src/buffered_uarte.rs53
-rw-r--r--embassy-nrf/src/chips/nrf9120.rs430
-rw-r--r--embassy-nrf/src/fmt.rs16
-rw-r--r--embassy-nrf/src/gpio.rs24
-rw-r--r--embassy-nrf/src/gpiote.rs12
-rw-r--r--embassy-nrf/src/lib.rs69
-rw-r--r--embassy-nrf/src/nvmc.rs8
-rw-r--r--embassy-nrf/src/pdm.rs8
-rw-r--r--embassy-nrf/src/saadc.rs7
-rw-r--r--embassy-nrf/src/wdt.rs13
-rw-r--r--embassy-rp/CHANGELOG.md32
-rw-r--r--embassy-rp/Cargo.toml39
-rw-r--r--embassy-rp/LICENSE-APACHE202
-rw-r--r--embassy-rp/LICENSE-MIT26
-rw-r--r--embassy-rp/README.md2
-rw-r--r--embassy-rp/build.rs18
-rw-r--r--embassy-rp/link-rp.x.in2
-rw-r--r--embassy-rp/src/adc.rs29
-rw-r--r--embassy-rp/src/block.rs1079
-rw-r--r--embassy-rp/src/bootsel.rs4
-rw-r--r--embassy-rp/src/clocks.rs87
-rw-r--r--embassy-rp/src/dma.rs41
-rw-r--r--embassy-rp/src/flash.rs86
-rw-r--r--embassy-rp/src/fmt.rs16
-rw-r--r--embassy-rp/src/gpio.rs78
-rw-r--r--embassy-rp/src/i2c.rs56
-rw-r--r--embassy-rp/src/lib.rs227
-rw-r--r--embassy-rp/src/multicore.rs36
-rw-r--r--embassy-rp/src/otp.rs108
-rw-r--r--embassy-rp/src/pio/mod.rs95
-rw-r--r--embassy-rp/src/pwm.rs47
-rw-r--r--embassy-rp/src/reset.rs2
-rw-r--r--embassy-rp/src/rom_data/mod.rs33
-rw-r--r--embassy-rp/src/rom_data/rp2040.rs (renamed from embassy-rp/src/rom_data.rs)4
-rw-r--r--embassy-rp/src/rom_data/rp235x.rs752
-rw-r--r--embassy-rp/src/spi.rs98
-rw-r--r--embassy-rp/src/time_driver.rs72
-rw-r--r--embassy-rp/src/uart/buffered.rs34
-rw-r--r--embassy-rp/src/uart/mod.rs460
-rw-r--r--embassy-rp/src/usb.rs6
-rw-r--r--embassy-rp/src/watchdog.rs1
-rw-r--r--embassy-stm32-wpan/Cargo.toml6
-rw-r--r--embassy-stm32-wpan/src/fmt.rs16
-rw-r--r--embassy-stm32-wpan/src/mac/commands.rs2
-rw-r--r--embassy-stm32/Cargo.toml139
-rw-r--r--embassy-stm32/build.rs80
-rw-r--r--embassy-stm32/build_common.rs21
-rw-r--r--embassy-stm32/src/adc/f3.rs2
-rw-r--r--embassy-stm32/src/adc/f3_v1_1.rs2
-rw-r--r--embassy-stm32/src/adc/g4.rs66
-rw-r--r--embassy-stm32/src/adc/mod.rs20
-rw-r--r--embassy-stm32/src/can/bxcan/mod.rs4
-rw-r--r--embassy-stm32/src/dma/dma_bdma.rs10
-rw-r--r--embassy-stm32/src/dma/gpdma.rs9
-rw-r--r--embassy-stm32/src/dsihost.rs2
-rw-r--r--embassy-stm32/src/flash/f1f3.rs4
-rw-r--r--embassy-stm32/src/flash/f2.rs142
-rw-r--r--embassy-stm32/src/flash/mod.rs5
-rw-r--r--embassy-stm32/src/fmc.rs40
-rw-r--r--embassy-stm32/src/fmt.rs16
-rw-r--r--embassy-stm32/src/hsem/mod.rs5
-rw-r--r--embassy-stm32/src/lib.rs133
-rw-r--r--embassy-stm32/src/low_power.rs6
-rw-r--r--embassy-stm32/src/lptim/channel.rs18
-rw-r--r--embassy-stm32/src/lptim/mod.rs48
-rw-r--r--embassy-stm32/src/lptim/pwm.rs168
-rw-r--r--embassy-stm32/src/lptim/timer/channel_direction.rs18
-rw-r--r--embassy-stm32/src/lptim/timer/mod.rs133
-rw-r--r--embassy-stm32/src/lptim/timer/prescaler.rs90
-rw-r--r--embassy-stm32/src/opamp.rs18
-rw-r--r--embassy-stm32/src/ospi/mod.rs17
-rw-r--r--embassy-stm32/src/rcc/bd.rs2
-rw-r--r--embassy-stm32/src/rcc/c0.rs1
-rw-r--r--embassy-stm32/src/rcc/f013.rs1
-rw-r--r--embassy-stm32/src/rcc/f247.rs2
-rw-r--r--embassy-stm32/src/rcc/g0.rs2
-rw-r--r--embassy-stm32/src/rcc/g4.rs2
-rw-r--r--embassy-stm32/src/rcc/h.rs3
-rw-r--r--embassy-stm32/src/rcc/l.rs1
-rw-r--r--embassy-stm32/src/rcc/mod.rs29
-rw-r--r--embassy-stm32/src/rcc/u5.rs1
-rw-r--r--embassy-stm32/src/rcc/wba.rs1
-rw-r--r--embassy-stm32/src/rtc/low_power.rs6
-rw-r--r--embassy-stm32/src/rtc/mod.rs2
-rw-r--r--embassy-stm32/src/rtc/v2.rs5
-rw-r--r--embassy-stm32/src/sai/mod.rs19
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs127
-rw-r--r--embassy-stm32/src/spi/mod.rs1
-rw-r--r--embassy-stm32/src/time.rs36
-rw-r--r--embassy-stm32/src/tsc/mod.rs4
-rw-r--r--embassy-stm32/src/ucpd.rs77
-rw-r--r--embassy-stm32/src/usart/buffered.rs32
-rw-r--r--embassy-stm32/src/usart/mod.rs68
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs34
-rw-r--r--embassy-stm32/src/usb/otg.rs49
-rw-r--r--embassy-stm32/src/usb/usb.rs2
-rw-r--r--embassy-sync/CHANGELOG.md2
-rw-r--r--embassy-sync/README.md3
-rw-r--r--embassy-sync/build_common.rs21
-rw-r--r--embassy-sync/src/fmt.rs16
-rw-r--r--embassy-sync/src/lazy_lock.rs152
-rw-r--r--embassy-sync/src/lib.rs1
-rw-r--r--embassy-time-driver/src/lib.rs54
-rw-r--r--embassy-time/CHANGELOG.md7
-rw-r--r--embassy-time/Cargo.toml4
-rw-r--r--embassy-time/src/fmt.rs16
-rw-r--r--embassy-usb-dfu/Cargo.toml6
-rw-r--r--embassy-usb-dfu/src/fmt.rs16
-rw-r--r--embassy-usb-logger/Cargo.toml2
-rw-r--r--embassy-usb-logger/src/lib.rs53
-rw-r--r--embassy-usb-synopsys-otg/src/fmt.rs16
-rw-r--r--embassy-usb-synopsys-otg/src/lib.rs11
-rw-r--r--embassy-usb-synopsys-otg/src/otg_v1.rs12
-rw-r--r--embassy-usb/CHANGELOG.md6
-rw-r--r--embassy-usb/Cargo.toml6
-rw-r--r--embassy-usb/src/descriptor.rs27
-rw-r--r--embassy-usb/src/fmt.rs16
-rw-r--r--embassy-usb/src/lib.rs4
-rw-r--r--embassy-usb/src/msos.rs2
-rw-r--r--examples/boot/application/nrf/Cargo.toml12
-rw-r--r--examples/boot/application/rp/Cargo.toml10
-rw-r--r--examples/boot/application/stm32f3/Cargo.toml6
-rw-r--r--examples/boot/application/stm32f7/Cargo.toml6
-rw-r--r--examples/boot/application/stm32h7/Cargo.toml6
-rw-r--r--examples/boot/application/stm32l0/Cargo.toml6
-rw-r--r--examples/boot/application/stm32l1/Cargo.toml6
-rw-r--r--examples/boot/application/stm32l4/Cargo.toml6
-rw-r--r--examples/boot/application/stm32wb-dfu/Cargo.toml8
-rw-r--r--examples/boot/application/stm32wl/Cargo.toml6
-rw-r--r--examples/boot/application/stm32wl/memory.x11
-rw-r--r--examples/boot/application/stm32wl/src/bin/a.rs8
-rw-r--r--examples/boot/application/stm32wl/src/bin/b.rs8
-rw-r--r--examples/boot/bootloader/rp/Cargo.toml2
-rw-r--r--examples/boot/bootloader/rp/memory.x2
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/Cargo.toml2
-rw-r--r--examples/nrf-rtos-trace/Cargo.toml6
-rw-r--r--examples/nrf51/Cargo.toml6
-rw-r--r--examples/nrf52810/Cargo.toml6
-rw-r--r--examples/nrf52840-rtic/Cargo.toml4
-rw-r--r--examples/nrf52840/Cargo.toml10
-rw-r--r--examples/nrf52840/src/bin/channel.rs4
-rw-r--r--examples/nrf52840/src/bin/channel_sender_receiver.rs4
-rw-r--r--examples/nrf52840/src/bin/ethernet_enc28j60.rs9
-rw-r--r--examples/nrf52840/src/bin/usb_ethernet.rs2
-rw-r--r--examples/nrf52840/src/bin/wifi_esp_hosted.rs9
-rw-r--r--examples/nrf5340/Cargo.toml10
-rw-r--r--examples/nrf9151/ns/.cargo/config.toml9
-rw-r--r--examples/nrf9151/ns/Cargo.toml20
-rw-r--r--examples/nrf9151/ns/README.md4
-rw-r--r--examples/nrf9151/ns/build.rs35
-rw-r--r--examples/nrf9151/ns/flash_tfm.sh2
-rw-r--r--examples/nrf9151/ns/memory.x7
-rw-r--r--examples/nrf9151/ns/src/bin/blinky.rs22
-rw-r--r--examples/nrf9151/ns/src/bin/uart.rs37
-rw-r--r--examples/nrf9151/ns/tfm.hex1543
-rw-r--r--examples/nrf9151/s/.cargo/config.toml8
-rw-r--r--examples/nrf9151/s/Cargo.toml20
-rw-r--r--examples/nrf9151/s/build.rs35
-rw-r--r--examples/nrf9151/s/memory.x5
-rw-r--r--examples/nrf9151/s/src/bin/blinky.rs22
-rw-r--r--examples/nrf9160/.cargo/config.toml4
-rw-r--r--examples/nrf9160/Cargo.toml12
-rw-r--r--examples/nrf9160/memory.x8
-rw-r--r--examples/nrf9160/src/bin/modem_tcp_client.rs204
-rw-r--r--examples/rp/Cargo.toml36
-rw-r--r--examples/rp/src/bin/assign_resources.rs79
-rw-r--r--examples/rp/src/bin/bluetooth.rs150
-rw-r--r--examples/rp/src/bin/ethernet_w5500_multisocket.rs2
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_client.rs4
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_server.rs4
-rw-r--r--examples/rp/src/bin/ethernet_w5500_udp.rs4
-rw-r--r--examples/rp/src/bin/orchestrate_tasks.rs318
-rw-r--r--examples/rp/src/bin/shared_bus.rs115
-rw-r--r--examples/rp/src/bin/sharing.rs150
-rw-r--r--examples/rp/src/bin/uart_buffered_split.rs2
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs9
-rw-r--r--examples/rp/src/bin/usb_hid_mouse.rs7
-rw-r--r--examples/rp/src/bin/wifi_ap_tcp_server.rs8
-rw-r--r--examples/rp/src/bin/wifi_blinky.rs4
-rw-r--r--examples/rp/src/bin/wifi_scan.rs4
-rw-r--r--examples/rp/src/bin/wifi_tcp_server.rs19
-rw-r--r--examples/rp/src/bin/wifi_webrequest.rs13
-rw-r--r--examples/rp23/.cargo/config.toml10
-rw-r--r--examples/rp23/Cargo.toml79
-rw-r--r--examples/rp23/assets/ferris.rawbin0 -> 11008 bytes
-rw-r--r--examples/rp23/build.rs35
-rw-r--r--examples/rp23/memory.x74
-rw-r--r--examples/rp23/src/bin/adc.rs63
-rw-r--r--examples/rp23/src/bin/adc_dma.rs69
-rw-r--r--examples/rp23/src/bin/assign_resources.rs94
-rw-r--r--examples/rp23/src/bin/blinky.rs44
-rw-r--r--examples/rp23/src/bin/blinky_two_channels.rs65
-rw-r--r--examples/rp23/src/bin/blinky_two_tasks.rs64
-rw-r--r--examples/rp23/src/bin/button.rs43
-rw-r--r--examples/rp23/src/bin/debounce.rs95
-rw-r--r--examples/rp23/src/bin/flash.rs140
-rw-r--r--examples/rp23/src/bin/gpio_async.rs55
-rw-r--r--examples/rp23/src/bin/gpout.rs52
-rw-r--r--examples/rp23/src/bin/i2c_async.rs125
-rw-r--r--examples/rp23/src/bin/i2c_async_embassy.rs100
-rw-r--r--examples/rp23/src/bin/i2c_blocking.rs89
-rw-r--r--examples/rp23/src/bin/i2c_slave.rs132
-rw-r--r--examples/rp23/src/bin/interrupt.rs109
-rw-r--r--examples/rp23/src/bin/multicore.rs81
-rw-r--r--examples/rp23/src/bin/multiprio.rs160
-rw-r--r--examples/rp23/src/bin/otp.rs46
-rw-r--r--examples/rp23/src/bin/pio_async.rs145
-rw-r--r--examples/rp23/src/bin/pio_dma.rs98
-rw-r--r--examples/rp23/src/bin/pio_hd44780.rs255
-rw-r--r--examples/rp23/src/bin/pio_i2s.rs140
-rw-r--r--examples/rp23/src/bin/pio_pwm.rs133
-rw-r--r--examples/rp23/src/bin/pio_rotary_encoder.rs95
-rw-r--r--examples/rp23/src/bin/pio_servo.rs223
-rw-r--r--examples/rp23/src/bin/pio_stepper.rs183
-rw-r--r--examples/rp23/src/bin/pio_ws2812.rs176
-rw-r--r--examples/rp23/src/bin/pwm.rs44
-rw-r--r--examples/rp23/src/bin/pwm_input.rs41
-rw-r--r--examples/rp23/src/bin/rosc.rs46
-rw-r--r--examples/rp23/src/bin/shared_bus.rs130
-rw-r--r--examples/rp23/src/bin/sharing.rs165
-rw-r--r--examples/rp23/src/bin/spi.rs61
-rw-r--r--examples/rp23/src/bin/spi_async.rs46
-rw-r--r--examples/rp23/src/bin/spi_display.rs327
-rw-r--r--examples/rp23/src/bin/spi_sdmmc.rs98
-rw-r--r--examples/rp23/src/bin/uart.rs40
-rw-r--r--examples/rp23/src/bin/uart_buffered_split.rs73
-rw-r--r--examples/rp23/src/bin/uart_r503.rs173
-rw-r--r--examples/rp23/src/bin/uart_unidir.rs65
-rw-r--r--examples/rp23/src/bin/usb_webusb.rs170
-rw-r--r--examples/rp23/src/bin/watchdog.rs66
-rw-r--r--examples/rp23/src/bin/zerocopy.rs109
-rw-r--r--examples/std/Cargo.toml4
-rw-r--r--examples/std/src/bin/net.rs7
-rw-r--r--examples/std/src/bin/net_dns.rs7
-rw-r--r--examples/std/src/bin/net_ppp.rs2
-rw-r--r--examples/std/src/bin/net_udp.rs7
-rw-r--r--examples/std/src/bin/tcp_accept.rs7
-rw-r--r--examples/stm32c0/Cargo.toml4
-rw-r--r--examples/stm32f0/Cargo.toml4
-rw-r--r--examples/stm32f1/Cargo.toml6
-rw-r--r--examples/stm32f2/Cargo.toml4
-rw-r--r--examples/stm32f3/Cargo.toml6
-rw-r--r--examples/stm32f3/src/bin/blocking-tsc.rs98
-rw-r--r--examples/stm32f334/Cargo.toml6
-rw-r--r--examples/stm32f4/Cargo.toml8
-rw-r--r--examples/stm32f4/src/bin/eth.rs9
-rw-r--r--examples/stm32f4/src/bin/eth_w5500.rs9
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs9
-rw-r--r--examples/stm32f469/Cargo.toml4
-rw-r--r--examples/stm32f7/Cargo.toml6
-rw-r--r--examples/stm32f7/src/bin/eth.rs9
-rw-r--r--examples/stm32g0/Cargo.toml6
-rw-r--r--examples/stm32g4/Cargo.toml8
-rw-r--r--examples/stm32g4/src/bin/adc_differential.rs47
-rw-r--r--examples/stm32g4/src/bin/adc_oversampling.rs57
-rw-r--r--examples/stm32g4/src/bin/usb_c_pd.rs2
-rw-r--r--examples/stm32h5/Cargo.toml6
-rw-r--r--examples/stm32h5/src/bin/eth.rs9
-rw-r--r--examples/stm32h7/Cargo.toml9
-rw-r--r--examples/stm32h7/src/bin/eth.rs7
-rw-r--r--examples/stm32h7/src/bin/eth_client.rs7
-rw-r--r--examples/stm32h7/src/bin/eth_client_mii.rs7
-rw-r--r--examples/stm32h7/src/bin/sai.rs186
-rw-r--r--examples/stm32h7/src/bin/spi_bdma.rs12
-rw-r--r--examples/stm32h735/Cargo.toml6
-rw-r--r--examples/stm32h755cm4/.cargo/config.toml8
-rw-r--r--examples/stm32h755cm4/Cargo.toml75
-rw-r--r--examples/stm32h755cm4/build.rs35
-rw-r--r--examples/stm32h755cm4/memory.x15
-rw-r--r--examples/stm32h755cm4/src/bin/blinky.rs32
-rw-r--r--examples/stm32h755cm7/.cargo/config.toml8
-rw-r--r--examples/stm32h755cm7/Cargo.toml75
-rw-r--r--examples/stm32h755cm7/build.rs35
-rw-r--r--examples/stm32h755cm7/memory.x15
-rw-r--r--examples/stm32h755cm7/src/bin/blinky.rs54
-rw-r--r--examples/stm32h7rs/Cargo.toml6
-rw-r--r--examples/stm32l0/Cargo.toml4
-rw-r--r--examples/stm32l0/src/bin/async-tsc.rs122
-rw-r--r--examples/stm32l0/src/bin/blocking-tsc.rs116
-rw-r--r--examples/stm32l1/Cargo.toml6
-rw-r--r--examples/stm32l4/Cargo.toml8
-rw-r--r--examples/stm32l4/src/bin/spe_adin1110_http_server.rs9
-rw-r--r--examples/stm32l5/Cargo.toml8
-rw-r--r--examples/stm32l5/src/bin/usb_ethernet.rs9
-rw-r--r--examples/stm32u0/Cargo.toml6
-rw-r--r--examples/stm32u5/Cargo.toml6
-rw-r--r--examples/stm32wb/Cargo.toml4
-rw-r--r--examples/stm32wba/Cargo.toml4
-rw-r--r--examples/stm32wl/Cargo.toml6
-rw-r--r--examples/stm32wl/memory.x15
-rw-r--r--examples/stm32wl/src/bin/blinky.rs8
-rw-r--r--examples/stm32wl/src/bin/button.rs8
-rw-r--r--examples/stm32wl/src/bin/button_exti.rs8
-rw-r--r--examples/stm32wl/src/bin/flash.rs8
-rw-r--r--examples/stm32wl/src/bin/random.rs9
-rw-r--r--examples/stm32wl/src/bin/rtc.rs9
-rw-r--r--examples/stm32wl/src/bin/uart_async.rs9
-rw-r--r--examples/wasm/Cargo.toml5
-rw-r--r--rust-toolchain-nightly.toml2
-rw-r--r--rust-toolchain.toml2
-rw-r--r--tests/nrf/Cargo.toml6
-rw-r--r--tests/nrf/src/bin/ethernet_enc28j60_perf.rs7
-rw-r--r--tests/nrf/src/bin/wifi_esp_hosted_perf.rs2
-rw-r--r--tests/perf-client/Cargo.toml2
-rw-r--r--tests/riscv32/Cargo.toml4
-rw-r--r--tests/rp/Cargo.toml8
-rw-r--r--tests/rp/src/bin/cyw43-perf.rs8
-rw-r--r--tests/rp/src/bin/ethernet_w5100s_perf.rs2
-rw-r--r--tests/rp/src/bin/timer.rs25
-rw-r--r--tests/stm32/Cargo.toml4
-rw-r--r--tests/stm32/src/bin/can.rs2
-rw-r--r--tests/stm32/src/bin/cordic.rs2
-rw-r--r--tests/stm32/src/bin/cryp.rs2
-rw-r--r--tests/stm32/src/bin/dac.rs2
-rw-r--r--tests/stm32/src/bin/dac_l1.rs2
-rw-r--r--tests/stm32/src/bin/eth.rs9
-rw-r--r--tests/stm32/src/bin/fdcan.rs4
-rw-r--r--tests/stm32/src/bin/gpio.rs2
-rw-r--r--tests/stm32/src/bin/hash.rs2
-rw-r--r--tests/stm32/src/bin/rng.rs2
-rw-r--r--tests/stm32/src/bin/rtc.rs2
-rw-r--r--tests/stm32/src/bin/sdmmc.rs2
-rw-r--r--tests/stm32/src/bin/spi.rs2
-rw-r--r--tests/stm32/src/bin/spi_dma.rs2
-rw-r--r--tests/stm32/src/bin/stop.rs2
-rw-r--r--tests/stm32/src/bin/timer.rs2
-rw-r--r--tests/stm32/src/bin/ucpd.rs6
-rw-r--r--tests/stm32/src/bin/usart.rs2
-rw-r--r--tests/stm32/src/bin/usart_dma.rs2
-rw-r--r--tests/stm32/src/bin/usart_rx_ringbuffered.rs2
-rw-r--r--tests/stm32/src/bin/wpan_ble.rs2
-rw-r--r--tests/stm32/src/bin/wpan_mac.rs2
-rw-r--r--tests/stm32/src/common.rs18
418 files changed, 18667 insertions, 1484 deletions
diff --git a/.github/ci/test.sh b/.github/ci/test.sh
index 41da644fc..0de265049 100755
--- a/.github/ci/test.sh
+++ b/.github/ci/test.sh
@@ -8,6 +8,10 @@ export RUSTUP_HOME=/ci/cache/rustup
8export CARGO_HOME=/ci/cache/cargo 8export CARGO_HOME=/ci/cache/cargo
9export CARGO_TARGET_DIR=/ci/cache/target 9export CARGO_TARGET_DIR=/ci/cache/target
10 10
11# needed for "dumb HTTP" transport support
12# used when pointing stm32-metapac to a CI-built one.
13export CARGO_NET_GIT_FETCH_WITH_CLI=true
14
11cargo test --manifest-path ./embassy-futures/Cargo.toml 15cargo test --manifest-path ./embassy-futures/Cargo.toml
12cargo test --manifest-path ./embassy-sync/Cargo.toml 16cargo test --manifest-path ./embassy-sync/Cargo.toml
13cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml 17cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml
@@ -21,7 +25,8 @@ cargo test --manifest-path ./embassy-boot/Cargo.toml --features ed25519-salty
21 25
22cargo test --manifest-path ./embassy-nrf/Cargo.toml --no-default-features --features nrf52840,time-driver-rtc1,gpiote 26cargo test --manifest-path ./embassy-nrf/Cargo.toml --no-default-features --features nrf52840,time-driver-rtc1,gpiote
23 27
24cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver 28cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver,rp2040,_test
29cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver,rp235xa,_test
25 30
26cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f429vg,exti,time-driver-any,exti 31cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f429vg,exti,time-driver-any,exti
27cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f732ze,exti,time-driver-any,exti 32cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f732ze,exti,time-driver-any,exti
diff --git a/ci.sh b/ci.sh
index 8ac9e1ccd..8fef731a4 100755
--- a/ci.sh
+++ b/ci.sh
@@ -2,11 +2,13 @@
2 2
3set -eo pipefail 3set -eo pipefail
4 4
5# check-cfg is stable on rustc 1.79 but not cargo 1.79. 5if ! command -v cargo-batch &> /dev/null; then
6# however, our cargo-batch is currently based on cargo 1.80, which does support check-cfg. 6 echo "cargo-batch could not be found. Install it with the following command:"
7# so, force build.rs scripts to emit check-cfg commands. 7 echo ""
8# when 1.80 hits stable we can make build.rs unconditionally emit check-cfg and remove all this. 8 echo " cargo install --git https://github.com/embassy-rs/cargo-batch cargo --bin cargo-batch --locked"
9export EMBASSY_FORCE_CHECK_CFG=1 9 echo ""
10 exit 1
11fi
10 12
11export RUSTFLAGS=-Dwarnings 13export RUSTFLAGS=-Dwarnings
12export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info 14export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info
@@ -80,10 +82,13 @@ cargo batch \
80 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time,time-driver-rtc1 \ 82 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time,time-driver-rtc1 \
81 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time \ 83 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time \
82 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,time \ 84 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,time \
83 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,defmt \ 85 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,defmt,rp2040 \
84 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,log \ 86 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,log,rp2040 \
85 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,intrinsics \ 87 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,intrinsics,rp2040 \
86 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,qspi-as-gpio \ 88 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,qspi-as-gpio,rp2040 \
89 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,defmt,rp235xa \
90 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,log,rp235xa \
91 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,rp235xa,binary-info \
87 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \ 92 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \
88 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,time \ 93 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,time \
89 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time \ 94 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time \
@@ -171,12 +176,17 @@ cargo batch \
171 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \ 176 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
172 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs' \ 177 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs' \
173 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs' \ 178 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs' \
174 --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features '' \ 179 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs,bluetooth' \
175 --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'overclock' \ 180 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs,bluetooth' \
181 --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040' \
182 --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040,overclock' \
176 --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ 183 --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
177 --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ 184 --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
178 --- build --release --manifest-path embassy-boot-rp/Cargo.toml --target thumbv6m-none-eabi \ 185 --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \
179 --- build --release --manifest-path embassy-boot-stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ 186 --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns \
187 --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns \
188 --- build --release --manifest-path embassy-boot-rp/Cargo.toml --target thumbv6m-none-eabi --features embassy-rp/rp2040 \
189 --- build --release --manifest-path embassy-boot-stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32l496zg \
180 --- build --release --manifest-path docs/examples/basic/Cargo.toml --target thumbv7em-none-eabi \ 190 --- build --release --manifest-path docs/examples/basic/Cargo.toml --target thumbv7em-none-eabi \
181 --- build --release --manifest-path docs/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \ 191 --- build --release --manifest-path docs/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \
182 --- build --release --manifest-path docs/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \ 192 --- build --release --manifest-path docs/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \
@@ -186,8 +196,11 @@ cargo batch \
186 --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \ 196 --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \
187 --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \ 197 --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \
188 --- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9160 \ 198 --- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9160 \
199 --- build --release --manifest-path examples/nrf9151/s/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9151/s \
200 --- build --release --manifest-path examples/nrf9151/ns/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9151/ns \
189 --- build --release --manifest-path examples/nrf51/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/nrf51 \ 201 --- build --release --manifest-path examples/nrf51/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/nrf51 \
190 --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ 202 --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \
203 --- build --release --manifest-path examples/rp23/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/rp23 \
191 --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ 204 --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \
192 --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \ 205 --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \
193 --- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f2 \ 206 --- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f2 \
@@ -202,6 +215,8 @@ cargo batch \
202 --- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32h5 \ 215 --- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32h5 \
203 --- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \ 216 --- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \
204 --- build --release --manifest-path examples/stm32h735/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h735 \ 217 --- build --release --manifest-path examples/stm32h735/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h735 \
218 --- build --release --manifest-path examples/stm32h755cm4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h755cm4 \
219 --- build --release --manifest-path examples/stm32h755cm7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h755cm7 \
205 --- build --release --manifest-path examples/stm32h7rs/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7rs \ 220 --- build --release --manifest-path examples/stm32h7rs/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7rs \
206 --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \ 221 --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \
207 --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \ 222 --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \
@@ -214,6 +229,9 @@ cargo batch \
214 --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wl \ 229 --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wl \
215 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \ 230 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \
216 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \ 231 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \
232 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns,skip-include --out-dir out/examples/boot/nrf9120 \
233 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns,skip-include --out-dir out/examples/boot/nrf9151 \
234 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns,skip-include --out-dir out/examples/boot/nrf9161 \
217 --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \ 235 --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \
218 --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \ 236 --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \
219 --- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f7 \ 237 --- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f7 \
@@ -225,10 +243,13 @@ cargo batch \
225 --- build --release --manifest-path examples/boot/application/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32wb-dfu \ 243 --- build --release --manifest-path examples/boot/application/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32wb-dfu \
226 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ 244 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
227 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ 245 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
246 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \
247 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns \
248 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns \
228 --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \ 249 --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \
229 --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \ 250 --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32l496zg \
230 --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wb55rg \ 251 --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wb55rg \
231 --- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32h747xi-cm7 \ 252 --- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32h743zi \
232 --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \ 253 --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \
233 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \ 254 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \
234 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \ 255 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \
@@ -269,6 +290,9 @@ cargo batch \
269 $BUILD_EXTRA 290 $BUILD_EXTRA
270 291
271 292
293# temporarily disabled, bluepill board got bricked
294rm -rf out/tests/stm32f103c8
295
272rm out/tests/stm32wb55rg/wpan_mac 296rm out/tests/stm32wb55rg/wpan_mac
273rm out/tests/stm32wb55rg/wpan_ble 297rm out/tests/stm32wb55rg/wpan_ble
274 298
@@ -278,8 +302,10 @@ rm out/tests/stm32f207zg/eth
278# doesn't work, gives "noise error", no idea why. usart_dma does pass. 302# doesn't work, gives "noise error", no idea why. usart_dma does pass.
279rm out/tests/stm32u5a5zj/usart 303rm out/tests/stm32u5a5zj/usart
280 304
281# flaky, perhaps bad wire 305# flaky, probably due to bad ringbuffered dma code.
282rm out/tests/stm32l152re/usart_rx_ringbuffered 306rm out/tests/stm32l152re/usart_rx_ringbuffered
307rm out/tests/stm32f207zg/usart_rx_ringbuffered
308rm out/tests/stm32wl55jc/usart_rx_ringbuffered
283 309
284if [[ -z "${TELEPROBE_TOKEN-}" ]]; then 310if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
285 echo No teleprobe token found, skipping running HIL tests 311 echo No teleprobe token found, skipping running HIL tests
diff --git a/cyw43-firmware/43439A0.bin b/cyw43-firmware/43439A0.bin
index 017375277..a05482fe9 100755..100644
--- a/cyw43-firmware/43439A0.bin
+++ b/cyw43-firmware/43439A0.bin
Binary files differ
diff --git a/cyw43-firmware/43439A0_btfw.bin b/cyw43-firmware/43439A0_btfw.bin
new file mode 100644
index 000000000..290ce8ef0
--- /dev/null
+++ b/cyw43-firmware/43439A0_btfw.bin
Binary files differ
diff --git a/cyw43-firmware/43439A0_clm.bin b/cyw43-firmware/43439A0_clm.bin
index 1fedd753a..dc4ee0252 100755..100644
--- a/cyw43-firmware/43439A0_clm.bin
+++ b/cyw43-firmware/43439A0_clm.bin
Binary files differ
diff --git a/cyw43-firmware/README.md b/cyw43-firmware/README.md
index db3d9c9cf..10a6b5d02 100644
--- a/cyw43-firmware/README.md
+++ b/cyw43-firmware/README.md
@@ -1,9 +1,14 @@
1# WiFi firmware 1# WiFi + Bluetooth firmware blobs
2 2
3Firmware obtained from https://github.com/Infineon/wifi-host-driver/tree/master/WiFi_Host_Driver/resources/firmware/COMPONENT_43439 3Firmware obtained from https://github.com/georgerobotics/cyw43-driver/tree/main/firmware
4 4
5Licensed under the [Infineon Permissive Binary License](./LICENSE-permissive-binary-license-1.0.txt) 5Licensed under the [Infineon Permissive Binary License](./LICENSE-permissive-binary-license-1.0.txt)
6 6
7## Changelog 7## Changelog
8 8
9* 2023-07-28: synced with `ad3bad0` - Update 43439 fw from 7.95.55 ot 7.95.62 9* 2023-08-21: synced with `a1dc885` - Update 43439 fw + clm to come from `wb43439A0_7_95_49_00_combined.h` + add Bluetooth firmware
10* 2023-07-28: synced with `ad3bad0` - Update 43439 fw from 7.95.55 to 7.95.62
11
12## Notes
13
14If you update these files, please update the lengths in the `tests/rp/src/bin/cyw43_perf.rs` test (which relies on these files running from RAM).
diff --git a/cyw43-pio/CHANGELOG.md b/cyw43-pio/CHANGELOG.md
new file mode 100644
index 000000000..913f3515a
--- /dev/null
+++ b/cyw43-pio/CHANGELOG.md
@@ -0,0 +1,17 @@
1# Changelog
2
3All notable changes to this project will be documented in this file.
4
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
8## Unreleased
9
10## 0.2.0 - 2024-08-05
11
12- Update to cyw43 0.2.0
13- Update to embassy-rp 0.2.0
14
15## 0.1.0 - 2024-01-11
16
17- First release
diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml
index 157046b18..4e21c255f 100644
--- a/cyw43-pio/Cargo.toml
+++ b/cyw43-pio/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "cyw43-pio" 2name = "cyw43-pio"
3version = "0.1.0" 3version = "0.2.0"
4edition = "2021" 4edition = "2021"
5description = "RP2040 PIO SPI implementation for cyw43" 5description = "RP2040 PIO SPI implementation for cyw43"
6keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] 6keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"]
@@ -15,8 +15,8 @@ documentation = "https://docs.embassy.dev/cyw43-pio"
15overclock = [] 15overclock = []
16 16
17[dependencies] 17[dependencies]
18cyw43 = { version = "0.1.0", path = "../cyw43" } 18cyw43 = { version = "0.2.0", path = "../cyw43" }
19embassy-rp = { version = "0.1.0", path = "../embassy-rp" } 19embassy-rp = { version = "0.2.0", path = "../embassy-rp" }
20pio-proc = "0.2" 20pio-proc = "0.2"
21pio = "0.2.1" 21pio = "0.2.1"
22fixed = "1.23.1" 22fixed = "1.23.1"
@@ -26,3 +26,4 @@ defmt = { version = "0.3", optional = true }
26src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-pio-v$VERSION/cyw43-pio/src/" 26src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-pio-v$VERSION/cyw43-pio/src/"
27src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43-pio/src/" 27src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43-pio/src/"
28target = "thumbv6m-none-eabi" 28target = "thumbv6m-none-eabi"
29features = ["embassy-rp/rp2040"]
diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs
index 8c217b995..40cf63a17 100644
--- a/cyw43-pio/src/lib.rs
+++ b/cyw43-pio/src/lib.rs
@@ -181,7 +181,10 @@ where
181 let read_bits = read.len() * 32 + 32 - 1; 181 let read_bits = read.len() * 32 + 32 - 1;
182 182
183 #[cfg(feature = "defmt")] 183 #[cfg(feature = "defmt")]
184 defmt::trace!("write={} read={}", write_bits, read_bits); 184 defmt::trace!("cmd_read write={} read={}", write_bits, read_bits);
185
186 #[cfg(feature = "defmt")]
187 defmt::trace!("cmd_read cmd = {:02x} len = {}", cmd, read.len());
185 188
186 unsafe { 189 unsafe {
187 instr::set_y(&mut self.sm, read_bits as u32); 190 instr::set_y(&mut self.sm, read_bits as u32);
@@ -201,6 +204,10 @@ where
201 .rx() 204 .rx()
202 .dma_pull(self.dma.reborrow(), slice::from_mut(&mut status)) 205 .dma_pull(self.dma.reborrow(), slice::from_mut(&mut status))
203 .await; 206 .await;
207
208 #[cfg(feature = "defmt")]
209 defmt::trace!("cmd_read cmd = {:02x} len = {} read = {:08x}", cmd, read.len(), read);
210
204 status 211 status
205 } 212 }
206} 213}
diff --git a/cyw43/CHANGELOG.md b/cyw43/CHANGELOG.md
new file mode 100644
index 000000000..1859f7317
--- /dev/null
+++ b/cyw43/CHANGELOG.md
@@ -0,0 +1,23 @@
1# Changelog
2
3All notable changes to this project will be documented in this file.
4
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
8## Unreleased
9
10## 0.2.0 - 2024-08-05
11
12- Update to new versions of embassy-{time,sync}
13- Add more fields to the BssInfo packet struct #2461
14- Extend the Scan API #2282
15- Reuse buf to reduce stack usage #2580
16- Add MAC address getter to cyw43 controller #2818
17- Add function to join WPA2 network with precomputed PSK. #2885
18- Add function to close soft AP. #3042
19- Fixing missing re-export #3211
20
21## 0.1.0 - 2024-01-11
22
23- First release
diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml
index c613698c1..751e59a69 100644
--- a/cyw43/Cargo.toml
+++ b/cyw43/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "cyw43" 2name = "cyw43"
3version = "0.1.0" 3version = "0.2.0"
4edition = "2021" 4edition = "2021"
5description = "Rust driver for the CYW43439 WiFi chip, used in the Raspberry Pi Pico W." 5description = "Rust driver for the CYW43439 WiFi chip, used in the Raspberry Pi Pico W."
6keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] 6keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"]
@@ -10,17 +10,18 @@ repository = "https://github.com/embassy-rs/embassy"
10documentation = "https://docs.embassy.dev/cyw43" 10documentation = "https://docs.embassy.dev/cyw43"
11 11
12[features] 12[features]
13defmt = ["dep:defmt", "heapless/defmt-03", "embassy-time/defmt"] 13defmt = ["dep:defmt", "heapless/defmt-03", "embassy-time/defmt", "bt-hci?/defmt", "embedded-io-async?/defmt-03"]
14log = ["dep:log"] 14log = ["dep:log"]
15bluetooth = ["dep:bt-hci", "dep:embedded-io-async"]
15 16
16# Fetch console logs from the WiFi firmware and forward them to `log` or `defmt`. 17# Fetch console logs from the WiFi firmware and forward them to `log` or `defmt`.
17firmware-logs = [] 18firmware-logs = []
18 19
19[dependencies] 20[dependencies]
20embassy-time = { version = "0.3.1", path = "../embassy-time"} 21embassy-time = { version = "0.3.2", path = "../embassy-time"}
21embassy-sync = { version = "0.6.0", path = "../embassy-sync"} 22embassy-sync = { version = "0.6.0", path = "../embassy-sync"}
22embassy-futures = { version = "0.1.0", path = "../embassy-futures"} 23embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
23embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"} 24embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"}
24 25
25defmt = { version = "0.3", optional = true } 26defmt = { version = "0.3", optional = true }
26log = { version = "0.4.17", optional = true } 27log = { version = "0.4.17", optional = true }
@@ -31,9 +32,12 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
31 32
32embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 33embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
33num_enum = { version = "0.5.7", default-features = false } 34num_enum = { version = "0.5.7", default-features = false }
34
35heapless = "0.8.0" 35heapless = "0.8.0"
36 36
37# Bluetooth deps
38embedded-io-async = { version = "0.6.0", optional = true }
39bt-hci = { version = "0.1.0", optional = true }
40
37[package.metadata.embassy_docs] 41[package.metadata.embassy_docs]
38src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/" 42src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/"
39src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/" 43src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/"
diff --git a/cyw43/src/bluetooth.rs b/cyw43/src/bluetooth.rs
new file mode 100644
index 000000000..f617a8c7e
--- /dev/null
+++ b/cyw43/src/bluetooth.rs
@@ -0,0 +1,508 @@
1use core::cell::RefCell;
2use core::future::Future;
3use core::mem::MaybeUninit;
4
5use bt_hci::transport::WithIndicator;
6use bt_hci::{ControllerToHostPacket, FromHciBytes, HostToControllerPacket, PacketKind, WriteHci};
7use embassy_futures::yield_now;
8use embassy_sync::blocking_mutex::raw::NoopRawMutex;
9use embassy_sync::zerocopy_channel;
10use embassy_time::{Duration, Timer};
11use embedded_hal_1::digital::OutputPin;
12
13use crate::bus::Bus;
14pub use crate::bus::SpiBusCyw43;
15use crate::consts::*;
16use crate::util::round_up;
17use crate::{util, CHIP};
18
19pub(crate) struct BtState {
20 rx: [BtPacketBuf; 4],
21 tx: [BtPacketBuf; 4],
22 inner: MaybeUninit<BtStateInnre<'static>>,
23}
24
25impl BtState {
26 pub const fn new() -> Self {
27 Self {
28 rx: [const { BtPacketBuf::new() }; 4],
29 tx: [const { BtPacketBuf::new() }; 4],
30 inner: MaybeUninit::uninit(),
31 }
32 }
33}
34
35struct BtStateInnre<'d> {
36 rx: zerocopy_channel::Channel<'d, NoopRawMutex, BtPacketBuf>,
37 tx: zerocopy_channel::Channel<'d, NoopRawMutex, BtPacketBuf>,
38}
39
40/// Bluetooth driver.
41pub struct BtDriver<'d> {
42 rx: RefCell<zerocopy_channel::Receiver<'d, NoopRawMutex, BtPacketBuf>>,
43 tx: RefCell<zerocopy_channel::Sender<'d, NoopRawMutex, BtPacketBuf>>,
44}
45
46pub(crate) struct BtRunner<'d> {
47 pub(crate) tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, BtPacketBuf>,
48 rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, BtPacketBuf>,
49
50 // Bluetooth circular buffers
51 addr: u32,
52 h2b_write_pointer: u32,
53 b2h_read_pointer: u32,
54}
55
56const BT_HCI_MTU: usize = 1024;
57
58/// Represents a packet of size MTU.
59pub(crate) struct BtPacketBuf {
60 pub(crate) len: usize,
61 pub(crate) buf: [u8; BT_HCI_MTU],
62}
63
64impl BtPacketBuf {
65 /// Create a new packet buffer.
66 pub const fn new() -> Self {
67 Self {
68 len: 0,
69 buf: [0; BT_HCI_MTU],
70 }
71 }
72}
73
74pub(crate) fn new<'d>(state: &'d mut BtState) -> (BtRunner<'d>, BtDriver<'d>) {
75 // safety: this is a self-referential struct, however:
76 // - it can't move while the `'d` borrow is active.
77 // - when the borrow ends, the dangling references inside the MaybeUninit will never be used again.
78 let state_uninit: *mut MaybeUninit<BtStateInnre<'d>> =
79 (&mut state.inner as *mut MaybeUninit<BtStateInnre<'static>>).cast();
80 let state = unsafe { &mut *state_uninit }.write(BtStateInnre {
81 rx: zerocopy_channel::Channel::new(&mut state.rx[..]),
82 tx: zerocopy_channel::Channel::new(&mut state.tx[..]),
83 });
84
85 let (rx_sender, rx_receiver) = state.rx.split();
86 let (tx_sender, tx_receiver) = state.tx.split();
87
88 (
89 BtRunner {
90 tx_chan: tx_receiver,
91 rx_chan: rx_sender,
92
93 addr: 0,
94 h2b_write_pointer: 0,
95 b2h_read_pointer: 0,
96 },
97 BtDriver {
98 rx: RefCell::new(rx_receiver),
99 tx: RefCell::new(tx_sender),
100 },
101 )
102}
103
104pub(crate) struct CybtFwCb<'a> {
105 pub p_next_line_start: &'a [u8],
106}
107
108pub(crate) struct HexFileData<'a> {
109 pub addr_mode: i32,
110 pub hi_addr: u16,
111 pub dest_addr: u32,
112 pub p_ds: &'a mut [u8],
113}
114
115pub(crate) fn read_firmware_patch_line(p_btfw_cb: &mut CybtFwCb, hfd: &mut HexFileData) -> u32 {
116 let mut abs_base_addr32 = 0;
117
118 loop {
119 let num_bytes = p_btfw_cb.p_next_line_start[0];
120 p_btfw_cb.p_next_line_start = &p_btfw_cb.p_next_line_start[1..];
121
122 let addr = (p_btfw_cb.p_next_line_start[0] as u16) << 8 | p_btfw_cb.p_next_line_start[1] as u16;
123 p_btfw_cb.p_next_line_start = &p_btfw_cb.p_next_line_start[2..];
124
125 let line_type = p_btfw_cb.p_next_line_start[0];
126 p_btfw_cb.p_next_line_start = &p_btfw_cb.p_next_line_start[1..];
127
128 if num_bytes == 0 {
129 break;
130 }
131
132 hfd.p_ds[..num_bytes as usize].copy_from_slice(&p_btfw_cb.p_next_line_start[..num_bytes as usize]);
133 p_btfw_cb.p_next_line_start = &p_btfw_cb.p_next_line_start[num_bytes as usize..];
134
135 match line_type {
136 BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS => {
137 hfd.hi_addr = (hfd.p_ds[0] as u16) << 8 | hfd.p_ds[1] as u16;
138 hfd.addr_mode = BTFW_ADDR_MODE_EXTENDED;
139 }
140 BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS => {
141 hfd.hi_addr = (hfd.p_ds[0] as u16) << 8 | hfd.p_ds[1] as u16;
142 hfd.addr_mode = BTFW_ADDR_MODE_SEGMENT;
143 }
144 BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS => {
145 abs_base_addr32 = (hfd.p_ds[0] as u32) << 24
146 | (hfd.p_ds[1] as u32) << 16
147 | (hfd.p_ds[2] as u32) << 8
148 | hfd.p_ds[3] as u32;
149 hfd.addr_mode = BTFW_ADDR_MODE_LINEAR32;
150 }
151 BTFW_HEX_LINE_TYPE_DATA => {
152 hfd.dest_addr = addr as u32;
153 match hfd.addr_mode {
154 BTFW_ADDR_MODE_EXTENDED => hfd.dest_addr += (hfd.hi_addr as u32) << 16,
155 BTFW_ADDR_MODE_SEGMENT => hfd.dest_addr += (hfd.hi_addr as u32) << 4,
156 BTFW_ADDR_MODE_LINEAR32 => hfd.dest_addr += abs_base_addr32,
157 _ => {}
158 }
159 return num_bytes as u32;
160 }
161 _ => {}
162 }
163 }
164 0
165}
166
167impl<'a> BtRunner<'a> {
168 pub(crate) async fn init_bluetooth(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>, firmware: &[u8]) {
169 trace!("init_bluetooth");
170 bus.bp_write32(CHIP.bluetooth_base_address + BT2WLAN_PWRUP_ADDR, BT2WLAN_PWRUP_WAKE)
171 .await;
172 Timer::after(Duration::from_millis(2)).await;
173 self.upload_bluetooth_firmware(bus, firmware).await;
174 self.wait_bt_ready(bus).await;
175 self.init_bt_buffers(bus).await;
176 self.wait_bt_awake(bus).await;
177 self.bt_set_host_ready(bus).await;
178 self.bt_toggle_intr(bus).await;
179 }
180
181 pub(crate) async fn upload_bluetooth_firmware(
182 &mut self,
183 bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>,
184 firmware: &[u8],
185 ) {
186 // read version
187 let version_length = firmware[0];
188 let _version = &firmware[1..=version_length as usize];
189 // skip version + 1 extra byte as per cybt_shared_bus_driver.c
190 let firmware = &firmware[version_length as usize + 2..];
191 // buffers
192 let mut data_buffer: [u8; 0x100] = [0; 0x100];
193 let mut aligned_data_buffer: [u8; 0x100] = [0; 0x100];
194 // structs
195 let mut btfw_cb = CybtFwCb {
196 p_next_line_start: firmware,
197 };
198 let mut hfd = HexFileData {
199 addr_mode: BTFW_ADDR_MODE_EXTENDED,
200 hi_addr: 0,
201 dest_addr: 0,
202 p_ds: &mut data_buffer,
203 };
204 loop {
205 let num_fw_bytes = read_firmware_patch_line(&mut btfw_cb, &mut hfd);
206 if num_fw_bytes == 0 {
207 break;
208 }
209 let fw_bytes = &hfd.p_ds[0..num_fw_bytes as usize];
210 let mut dest_start_addr = hfd.dest_addr + CHIP.bluetooth_base_address;
211 let mut aligned_data_buffer_index: usize = 0;
212 // pad start
213 if !util::is_aligned(dest_start_addr, 4) {
214 let num_pad_bytes = dest_start_addr % 4;
215 let padded_dest_start_addr = util::round_down(dest_start_addr, 4);
216 let memory_value = bus.bp_read32(padded_dest_start_addr).await;
217 let memory_value_bytes = memory_value.to_le_bytes();
218 // Copy the previous memory value's bytes to the start
219 for i in 0..num_pad_bytes as usize {
220 aligned_data_buffer[aligned_data_buffer_index] = memory_value_bytes[i];
221 aligned_data_buffer_index += 1;
222 }
223 // Copy the firmware bytes after the padding bytes
224 for i in 0..num_fw_bytes as usize {
225 aligned_data_buffer[aligned_data_buffer_index] = fw_bytes[i];
226 aligned_data_buffer_index += 1;
227 }
228 dest_start_addr = padded_dest_start_addr;
229 } else {
230 // Directly copy fw_bytes into aligned_data_buffer if no start padding is required
231 for i in 0..num_fw_bytes as usize {
232 aligned_data_buffer[aligned_data_buffer_index] = fw_bytes[i];
233 aligned_data_buffer_index += 1;
234 }
235 }
236 // pad end
237 let mut dest_end_addr = dest_start_addr + aligned_data_buffer_index as u32;
238 if !util::is_aligned(dest_end_addr, 4) {
239 let offset = dest_end_addr % 4;
240 let num_pad_bytes_end = 4 - offset;
241 let padded_dest_end_addr = util::round_down(dest_end_addr, 4);
242 let memory_value = bus.bp_read32(padded_dest_end_addr).await;
243 let memory_value_bytes = memory_value.to_le_bytes();
244 // Append the necessary memory bytes to pad the end of aligned_data_buffer
245 for i in offset..4 {
246 aligned_data_buffer[aligned_data_buffer_index] = memory_value_bytes[i as usize];
247 aligned_data_buffer_index += 1;
248 }
249 dest_end_addr += num_pad_bytes_end;
250 } else {
251 // pad end alignment not needed
252 }
253 let buffer_to_write = &aligned_data_buffer[0..aligned_data_buffer_index as usize];
254 assert!(dest_start_addr % 4 == 0);
255 assert!(dest_end_addr % 4 == 0);
256 assert!(aligned_data_buffer_index % 4 == 0);
257 bus.bp_write(dest_start_addr, buffer_to_write).await;
258 }
259 }
260
261 pub(crate) async fn wait_bt_ready(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
262 trace!("wait_bt_ready");
263 let mut success = false;
264 for _ in 0..300 {
265 let val = bus.bp_read32(BT_CTRL_REG_ADDR).await;
266 trace!("BT_CTRL_REG_ADDR = {:08x}", val);
267 if val & BTSDIO_REG_FW_RDY_BITMASK != 0 {
268 success = true;
269 break;
270 }
271 Timer::after(Duration::from_millis(1)).await;
272 }
273 assert!(success == true);
274 }
275
276 pub(crate) async fn wait_bt_awake(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
277 trace!("wait_bt_awake");
278 let mut success = false;
279 for _ in 0..300 {
280 let val = bus.bp_read32(BT_CTRL_REG_ADDR).await;
281 trace!("BT_CTRL_REG_ADDR = {:08x}", val);
282 if val & BTSDIO_REG_BT_AWAKE_BITMASK != 0 {
283 success = true;
284 break;
285 }
286 Timer::after(Duration::from_millis(1)).await;
287 }
288 assert!(success == true);
289 }
290
291 pub(crate) async fn bt_set_host_ready(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
292 trace!("bt_set_host_ready");
293 let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await;
294 // TODO: do we need to swap endianness on this read?
295 let new_val = old_val | BTSDIO_REG_SW_RDY_BITMASK;
296 bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
297 }
298
299 // TODO: use this
300 #[allow(dead_code)]
301 pub(crate) async fn bt_set_awake(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>, awake: bool) {
302 trace!("bt_set_awake");
303 let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await;
304 // TODO: do we need to swap endianness on this read?
305 let new_val = if awake {
306 old_val | BTSDIO_REG_WAKE_BT_BITMASK
307 } else {
308 old_val & !BTSDIO_REG_WAKE_BT_BITMASK
309 };
310 bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
311 }
312
313 pub(crate) async fn bt_toggle_intr(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
314 trace!("bt_toggle_intr");
315 let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await;
316 // TODO: do we need to swap endianness on this read?
317 let new_val = old_val ^ BTSDIO_REG_DATA_VALID_BITMASK;
318 bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
319 }
320
321 // TODO: use this
322 #[allow(dead_code)]
323 pub(crate) async fn bt_set_intr(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
324 trace!("bt_set_intr");
325 let old_val = bus.bp_read32(HOST_CTRL_REG_ADDR).await;
326 let new_val = old_val | BTSDIO_REG_DATA_VALID_BITMASK;
327 bus.bp_write32(HOST_CTRL_REG_ADDR, new_val).await;
328 }
329
330 pub(crate) async fn init_bt_buffers(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
331 trace!("init_bt_buffers");
332 self.addr = bus.bp_read32(WLAN_RAM_BASE_REG_ADDR).await;
333 assert!(self.addr != 0);
334 trace!("wlan_ram_base_addr = {:08x}", self.addr);
335 bus.bp_write32(self.addr + BTSDIO_OFFSET_HOST2BT_IN, 0).await;
336 bus.bp_write32(self.addr + BTSDIO_OFFSET_HOST2BT_OUT, 0).await;
337 bus.bp_write32(self.addr + BTSDIO_OFFSET_BT2HOST_IN, 0).await;
338 bus.bp_write32(self.addr + BTSDIO_OFFSET_BT2HOST_OUT, 0).await;
339 }
340
341 async fn bt_bus_request(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
342 // TODO: CYW43_THREAD_ENTER mutex?
343 self.bt_set_awake(bus, true).await;
344 self.wait_bt_awake(bus).await;
345 }
346
347 pub(crate) async fn hci_write(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
348 self.bt_bus_request(bus).await;
349
350 // NOTE(unwrap): we only call this when we do have a packet in the queue.
351 let buf = self.tx_chan.try_receive().unwrap();
352 debug!("HCI tx: {:02x}", crate::fmt::Bytes(&buf.buf[..buf.len]));
353
354 let len = buf.len as u32 - 1; // len doesn't include hci type byte
355 let rounded_len = round_up(len, 4);
356 let total_len = 4 + rounded_len;
357
358 let read_pointer = bus.bp_read32(self.addr + BTSDIO_OFFSET_HOST2BT_OUT).await;
359 let available = read_pointer.wrapping_sub(self.h2b_write_pointer + 4) % BTSDIO_FWBUF_SIZE;
360 if available < total_len {
361 warn!(
362 "bluetooth tx queue full, retrying. len {} available {}",
363 total_len, available
364 );
365 yield_now().await;
366 return;
367 }
368
369 // Build header
370 let mut header = [0u8; 4];
371 header[0] = len as u8;
372 header[1] = (len >> 8) as u8;
373 header[2] = (len >> 16) as u8;
374 header[3] = buf.buf[0]; // HCI type byte
375
376 // Write header
377 let addr = self.addr + BTSDIO_OFFSET_HOST_WRITE_BUF + self.h2b_write_pointer;
378 bus.bp_write(addr, &header).await;
379 self.h2b_write_pointer = (self.h2b_write_pointer + 4) % BTSDIO_FWBUF_SIZE;
380
381 // Write payload.
382 let payload = &buf.buf[1..][..rounded_len as usize];
383 if self.h2b_write_pointer as usize + payload.len() > BTSDIO_FWBUF_SIZE as usize {
384 // wraparound
385 let n = BTSDIO_FWBUF_SIZE - self.h2b_write_pointer;
386 let addr = self.addr + BTSDIO_OFFSET_HOST_WRITE_BUF + self.h2b_write_pointer;
387 bus.bp_write(addr, &payload[..n as usize]).await;
388 let addr = self.addr + BTSDIO_OFFSET_HOST_WRITE_BUF;
389 bus.bp_write(addr, &payload[n as usize..]).await;
390 } else {
391 // no wraparound
392 let addr = self.addr + BTSDIO_OFFSET_HOST_WRITE_BUF + self.h2b_write_pointer;
393 bus.bp_write(addr, payload).await;
394 }
395 self.h2b_write_pointer = (self.h2b_write_pointer + payload.len() as u32) % BTSDIO_FWBUF_SIZE;
396
397 // Update pointer.
398 bus.bp_write32(self.addr + BTSDIO_OFFSET_HOST2BT_IN, self.h2b_write_pointer)
399 .await;
400
401 self.bt_toggle_intr(bus).await;
402
403 self.tx_chan.receive_done();
404 }
405
406 async fn bt_has_work(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) -> bool {
407 let int_status = bus.bp_read32(CHIP.sdiod_core_base_address + SDIO_INT_STATUS).await;
408 if int_status & I_HMB_FC_CHANGE != 0 {
409 bus.bp_write32(
410 CHIP.sdiod_core_base_address + SDIO_INT_STATUS,
411 int_status & I_HMB_FC_CHANGE,
412 )
413 .await;
414 return true;
415 }
416 return false;
417 }
418
419 pub(crate) async fn handle_irq(&mut self, bus: &mut Bus<impl OutputPin, impl SpiBusCyw43>) {
420 if self.bt_has_work(bus).await {
421 loop {
422 // Check if we have data.
423 let write_pointer = bus.bp_read32(self.addr + BTSDIO_OFFSET_BT2HOST_IN).await;
424 let available = write_pointer.wrapping_sub(self.b2h_read_pointer) % BTSDIO_FWBUF_SIZE;
425 if available == 0 {
426 break;
427 }
428
429 // read header
430 let mut header = [0u8; 4];
431 let addr = self.addr + BTSDIO_OFFSET_HOST_READ_BUF + self.b2h_read_pointer;
432 bus.bp_read(addr, &mut header).await;
433
434 // calc length
435 let len = header[0] as u32 | ((header[1]) as u32) << 8 | ((header[2]) as u32) << 16;
436 let rounded_len = round_up(len, 4);
437 if available < 4 + rounded_len {
438 warn!("ringbuf data not enough for a full packet?");
439 break;
440 }
441 self.b2h_read_pointer = (self.b2h_read_pointer + 4) % BTSDIO_FWBUF_SIZE;
442
443 // Obtain a buf from the channel.
444 let buf = self.rx_chan.send().await;
445
446 buf.buf[0] = header[3]; // hci packet type
447 let payload = &mut buf.buf[1..][..rounded_len as usize];
448 if self.b2h_read_pointer as usize + payload.len() > BTSDIO_FWBUF_SIZE as usize {
449 // wraparound
450 let n = BTSDIO_FWBUF_SIZE - self.b2h_read_pointer;
451 let addr = self.addr + BTSDIO_OFFSET_HOST_READ_BUF + self.b2h_read_pointer;
452 bus.bp_read(addr, &mut payload[..n as usize]).await;
453 let addr = self.addr + BTSDIO_OFFSET_HOST_READ_BUF;
454 bus.bp_read(addr, &mut payload[n as usize..]).await;
455 } else {
456 // no wraparound
457 let addr = self.addr + BTSDIO_OFFSET_HOST_READ_BUF + self.b2h_read_pointer;
458 bus.bp_read(addr, payload).await;
459 }
460 self.b2h_read_pointer = (self.b2h_read_pointer + payload.len() as u32) % BTSDIO_FWBUF_SIZE;
461 bus.bp_write32(self.addr + BTSDIO_OFFSET_BT2HOST_OUT, self.b2h_read_pointer)
462 .await;
463
464 buf.len = 1 + len as usize;
465 debug!("HCI rx: {:02x}", crate::fmt::Bytes(&buf.buf[..buf.len]));
466
467 self.rx_chan.send_done();
468
469 self.bt_toggle_intr(bus).await;
470 }
471 }
472 }
473}
474
475impl<'d> embedded_io_async::ErrorType for BtDriver<'d> {
476 type Error = core::convert::Infallible;
477}
478
479impl<'d> bt_hci::transport::Transport for BtDriver<'d> {
480 fn read<'a>(&self, rx: &'a mut [u8]) -> impl Future<Output = Result<ControllerToHostPacket<'a>, Self::Error>> {
481 async {
482 let ch = &mut *self.rx.borrow_mut();
483 let buf = ch.receive().await;
484 let n = buf.len;
485 assert!(n < rx.len());
486 rx[..n].copy_from_slice(&buf.buf[..n]);
487 ch.receive_done();
488
489 let kind = PacketKind::from_hci_bytes_complete(&rx[..1]).unwrap();
490 let (res, _) = ControllerToHostPacket::from_hci_bytes_with_kind(kind, &rx[1..n]).unwrap();
491 Ok(res)
492 }
493 }
494
495 /// Write a complete HCI packet from the tx buffer
496 fn write<T: HostToControllerPacket>(&self, val: &T) -> impl Future<Output = Result<(), Self::Error>> {
497 async {
498 let ch = &mut *self.tx.borrow_mut();
499 let buf = ch.send().await;
500 let buf_len = buf.buf.len();
501 let mut slice = &mut buf.buf[..];
502 WithIndicator::new(val).write_hci(&mut slice).unwrap();
503 buf.len = buf_len - slice.len();
504 ch.send_done();
505 Ok(())
506 }
507 }
508}
diff --git a/cyw43/src/bus.rs b/cyw43/src/bus.rs
index 014109038..8a53484d5 100644
--- a/cyw43/src/bus.rs
+++ b/cyw43/src/bus.rs
@@ -4,7 +4,7 @@ use embedded_hal_1::digital::OutputPin;
4use futures::FutureExt; 4use futures::FutureExt;
5 5
6use crate::consts::*; 6use crate::consts::*;
7use crate::slice8_mut; 7use crate::util::slice8_mut;
8 8
9/// Custom Spi Trait that _only_ supports the bus operation of the cyw43 9/// Custom Spi Trait that _only_ supports the bus operation of the cyw43
10/// Implementors are expected to hold the CS pin low during an operation. 10/// Implementors are expected to hold the CS pin low during an operation.
@@ -48,44 +48,91 @@ where
48 } 48 }
49 } 49 }
50 50
51 pub async fn init(&mut self) { 51 pub async fn init(&mut self, bluetooth_enabled: bool) {
52 // Reset 52 // Reset
53 trace!("WL_REG off/on");
53 self.pwr.set_low().unwrap(); 54 self.pwr.set_low().unwrap();
54 Timer::after_millis(20).await; 55 Timer::after_millis(20).await;
55 self.pwr.set_high().unwrap(); 56 self.pwr.set_high().unwrap();
56 Timer::after_millis(250).await; 57 Timer::after_millis(250).await;
57 58
59 trace!("read REG_BUS_TEST_RO");
58 while self 60 while self
59 .read32_swapped(REG_BUS_TEST_RO) 61 .read32_swapped(FUNC_BUS, REG_BUS_TEST_RO)
60 .inspect(|v| trace!("{:#x}", v)) 62 .inspect(|v| trace!("{:#x}", v))
61 .await 63 .await
62 != FEEDBEAD 64 != FEEDBEAD
63 {} 65 {}
64 66
65 self.write32_swapped(REG_BUS_TEST_RW, TEST_PATTERN).await; 67 trace!("write REG_BUS_TEST_RW");
66 let val = self.read32_swapped(REG_BUS_TEST_RW).await; 68 self.write32_swapped(FUNC_BUS, REG_BUS_TEST_RW, TEST_PATTERN).await;
69 let val = self.read32_swapped(FUNC_BUS, REG_BUS_TEST_RW).await;
67 trace!("{:#x}", val); 70 trace!("{:#x}", val);
68 assert_eq!(val, TEST_PATTERN); 71 assert_eq!(val, TEST_PATTERN);
69 72
70 let val = self.read32_swapped(REG_BUS_CTRL).await; 73 trace!("read REG_BUS_CTRL");
74 let val = self.read32_swapped(FUNC_BUS, REG_BUS_CTRL).await;
71 trace!("{:#010b}", (val & 0xff)); 75 trace!("{:#010b}", (val & 0xff));
72 76
73 // 32-bit word length, little endian (which is the default endianess). 77 // 32-bit word length, little endian (which is the default endianess).
78 // TODO: C library is uint32_t val = WORD_LENGTH_32 | HIGH_SPEED_MODE| ENDIAN_BIG | INTERRUPT_POLARITY_HIGH | WAKE_UP | 0x4 << (8 * SPI_RESPONSE_DELAY) | INTR_WITH_STATUS << (8 * SPI_STATUS_ENABLE);
79 trace!("write REG_BUS_CTRL");
74 self.write32_swapped( 80 self.write32_swapped(
81 FUNC_BUS,
75 REG_BUS_CTRL, 82 REG_BUS_CTRL,
76 WORD_LENGTH_32 | HIGH_SPEED | INTERRUPT_HIGH | WAKE_UP | STATUS_ENABLE | INTERRUPT_WITH_STATUS, 83 WORD_LENGTH_32
84 | HIGH_SPEED
85 | INTERRUPT_POLARITY_HIGH
86 | WAKE_UP
87 | 0x4 << (8 * REG_BUS_RESPONSE_DELAY)
88 | STATUS_ENABLE << (8 * REG_BUS_STATUS_ENABLE)
89 | INTR_WITH_STATUS << (8 * REG_BUS_STATUS_ENABLE),
77 ) 90 )
78 .await; 91 .await;
79 92
93 trace!("read REG_BUS_CTRL");
80 let val = self.read8(FUNC_BUS, REG_BUS_CTRL).await; 94 let val = self.read8(FUNC_BUS, REG_BUS_CTRL).await;
81 trace!("{:#b}", val); 95 trace!("{:#b}", val);
82 96
97 // TODO: C doesn't do this? i doubt it messes anything up
98 trace!("read REG_BUS_TEST_RO");
83 let val = self.read32(FUNC_BUS, REG_BUS_TEST_RO).await; 99 let val = self.read32(FUNC_BUS, REG_BUS_TEST_RO).await;
84 trace!("{:#x}", val); 100 trace!("{:#x}", val);
85 assert_eq!(val, FEEDBEAD); 101 assert_eq!(val, FEEDBEAD);
102
103 // TODO: C doesn't do this? i doubt it messes anything up
104 trace!("read REG_BUS_TEST_RW");
86 let val = self.read32(FUNC_BUS, REG_BUS_TEST_RW).await; 105 let val = self.read32(FUNC_BUS, REG_BUS_TEST_RW).await;
87 trace!("{:#x}", val); 106 trace!("{:#x}", val);
88 assert_eq!(val, TEST_PATTERN); 107 assert_eq!(val, TEST_PATTERN);
108
109 trace!("write SPI_RESP_DELAY_F1 CYW43_BACKPLANE_READ_PAD_LEN_BYTES");
110 self.write8(FUNC_BUS, SPI_RESP_DELAY_F1, WHD_BUS_SPI_BACKPLANE_READ_PADD_SIZE)
111 .await;
112
113 // TODO: Make sure error interrupt bits are clear?
114 // cyw43_write_reg_u8(self, BUS_FUNCTION, SPI_INTERRUPT_REGISTER, DATA_UNAVAILABLE | COMMAND_ERROR | DATA_ERROR | F1_OVERFLOW) != 0)
115 trace!("Make sure error interrupt bits are clear");
116 self.write8(
117 FUNC_BUS,
118 REG_BUS_INTERRUPT,
119 (IRQ_DATA_UNAVAILABLE | IRQ_COMMAND_ERROR | IRQ_DATA_ERROR | IRQ_F1_OVERFLOW) as u8,
120 )
121 .await;
122
123 // Enable a selection of interrupts
124 // TODO: why not all of these F2_F3_FIFO_RD_UNDERFLOW | F2_F3_FIFO_WR_OVERFLOW | COMMAND_ERROR | DATA_ERROR | F2_PACKET_AVAILABLE | F1_OVERFLOW | F1_INTR
125 trace!("enable a selection of interrupts");
126 let mut val = IRQ_F2_F3_FIFO_RD_UNDERFLOW
127 | IRQ_F2_F3_FIFO_WR_OVERFLOW
128 | IRQ_COMMAND_ERROR
129 | IRQ_DATA_ERROR
130 | IRQ_F2_PACKET_AVAILABLE
131 | IRQ_F1_OVERFLOW;
132 if bluetooth_enabled {
133 val = val | IRQ_F1_INTR;
134 }
135 self.write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, val).await;
89 } 136 }
90 137
91 pub async fn wlan_read(&mut self, buf: &mut [u32], len_in_u8: u32) { 138 pub async fn wlan_read(&mut self, buf: &mut [u32], len_in_u8: u32) {
@@ -107,6 +154,8 @@ where
107 154
108 #[allow(unused)] 155 #[allow(unused)]
109 pub async fn bp_read(&mut self, mut addr: u32, mut data: &mut [u8]) { 156 pub async fn bp_read(&mut self, mut addr: u32, mut data: &mut [u8]) {
157 trace!("bp_read addr = {:08x}", addr);
158
110 // It seems the HW force-aligns the addr 159 // It seems the HW force-aligns the addr
111 // to 2 if data.len() >= 2 160 // to 2 if data.len() >= 2
112 // to 4 if data.len() >= 4 161 // to 4 if data.len() >= 4
@@ -140,6 +189,8 @@ where
140 } 189 }
141 190
142 pub async fn bp_write(&mut self, mut addr: u32, mut data: &[u8]) { 191 pub async fn bp_write(&mut self, mut addr: u32, mut data: &[u8]) {
192 trace!("bp_write addr = {:08x}", addr);
193
143 // It seems the HW force-aligns the addr 194 // It seems the HW force-aligns the addr
144 // to 2 if data.len() >= 2 195 // to 2 if data.len() >= 2
145 // to 4 if data.len() >= 4 196 // to 4 if data.len() >= 4
@@ -196,23 +247,32 @@ where
196 } 247 }
197 248
198 async fn backplane_readn(&mut self, addr: u32, len: u32) -> u32 { 249 async fn backplane_readn(&mut self, addr: u32, len: u32) -> u32 {
250 trace!("backplane_readn addr = {:08x} len = {}", addr, len);
251
199 self.backplane_set_window(addr).await; 252 self.backplane_set_window(addr).await;
200 253
201 let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK; 254 let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK;
202 if len == 4 { 255 if len == 4 {
203 bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG 256 bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG;
204 } 257 }
205 self.readn(FUNC_BACKPLANE, bus_addr, len).await 258
259 let val = self.readn(FUNC_BACKPLANE, bus_addr, len).await;
260
261 trace!("backplane_readn addr = {:08x} len = {} val = {:08x}", addr, len, val);
262
263 return val;
206 } 264 }
207 265
208 async fn backplane_writen(&mut self, addr: u32, val: u32, len: u32) { 266 async fn backplane_writen(&mut self, addr: u32, val: u32, len: u32) {
267 trace!("backplane_writen addr = {:08x} len = {} val = {:08x}", addr, len, val);
268
209 self.backplane_set_window(addr).await; 269 self.backplane_set_window(addr).await;
210 270
211 let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK; 271 let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK;
212 if len == 4 { 272 if len == 4 {
213 bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG 273 bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG;
214 } 274 }
215 self.writen(FUNC_BACKPLANE, bus_addr, val, len).await 275 self.writen(FUNC_BACKPLANE, bus_addr, val, len).await;
216 } 276 }
217 277
218 async fn backplane_set_window(&mut self, addr: u32) { 278 async fn backplane_set_window(&mut self, addr: u32) {
@@ -293,8 +353,8 @@ where
293 self.status = self.spi.cmd_write(&[cmd, val]).await; 353 self.status = self.spi.cmd_write(&[cmd, val]).await;
294 } 354 }
295 355
296 async fn read32_swapped(&mut self, addr: u32) -> u32 { 356 async fn read32_swapped(&mut self, func: u32, addr: u32) -> u32 {
297 let cmd = cmd_word(READ, INC_ADDR, FUNC_BUS, addr, 4); 357 let cmd = cmd_word(READ, INC_ADDR, func, addr, 4);
298 let cmd = swap16(cmd); 358 let cmd = swap16(cmd);
299 let mut buf = [0; 1]; 359 let mut buf = [0; 1];
300 360
@@ -303,8 +363,8 @@ where
303 swap16(buf[0]) 363 swap16(buf[0])
304 } 364 }
305 365
306 async fn write32_swapped(&mut self, addr: u32, val: u32) { 366 async fn write32_swapped(&mut self, func: u32, addr: u32, val: u32) {
307 let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BUS, addr, 4); 367 let cmd = cmd_word(WRITE, INC_ADDR, func, addr, 4);
308 let buf = [swap16(cmd), swap16(val)]; 368 let buf = [swap16(cmd), swap16(val)];
309 369
310 self.status = self.spi.cmd_write(&buf).await; 370 self.status = self.spi.cmd_write(&buf).await;
diff --git a/cyw43/src/consts.rs b/cyw43/src/consts.rs
index 4e2836f3b..c3f0dbfd8 100644
--- a/cyw43/src/consts.rs
+++ b/cyw43/src/consts.rs
@@ -5,19 +5,33 @@ pub(crate) const FUNC_BACKPLANE: u32 = 1;
5pub(crate) const FUNC_WLAN: u32 = 2; 5pub(crate) const FUNC_WLAN: u32 = 2;
6pub(crate) const FUNC_BT: u32 = 3; 6pub(crate) const FUNC_BT: u32 = 3;
7 7
8// Register addresses
8pub(crate) const REG_BUS_CTRL: u32 = 0x0; 9pub(crate) const REG_BUS_CTRL: u32 = 0x0;
10pub(crate) const REG_BUS_RESPONSE_DELAY: u32 = 0x1;
11pub(crate) const REG_BUS_STATUS_ENABLE: u32 = 0x2;
9pub(crate) const REG_BUS_INTERRUPT: u32 = 0x04; // 16 bits - Interrupt status 12pub(crate) const REG_BUS_INTERRUPT: u32 = 0x04; // 16 bits - Interrupt status
10pub(crate) const REG_BUS_INTERRUPT_ENABLE: u32 = 0x06; // 16 bits - Interrupt mask 13pub(crate) const REG_BUS_INTERRUPT_ENABLE: u32 = 0x06; // 16 bits - Interrupt mask
11pub(crate) const REG_BUS_STATUS: u32 = 0x8; 14pub(crate) const REG_BUS_STATUS: u32 = 0x8;
12pub(crate) const REG_BUS_TEST_RO: u32 = 0x14; 15pub(crate) const REG_BUS_TEST_RO: u32 = 0x14;
13pub(crate) const REG_BUS_TEST_RW: u32 = 0x18; 16pub(crate) const REG_BUS_TEST_RW: u32 = 0x18;
14pub(crate) const REG_BUS_RESP_DELAY: u32 = 0x1c; 17pub(crate) const REG_BUS_RESP_DELAY: u32 = 0x1c;
18
19// SPI_BUS_CONTROL Bits
15pub(crate) const WORD_LENGTH_32: u32 = 0x1; 20pub(crate) const WORD_LENGTH_32: u32 = 0x1;
21pub(crate) const ENDIAN_BIG: u32 = 0x2;
22pub(crate) const CLOCK_PHASE: u32 = 0x4;
23pub(crate) const CLOCK_POLARITY: u32 = 0x8;
16pub(crate) const HIGH_SPEED: u32 = 0x10; 24pub(crate) const HIGH_SPEED: u32 = 0x10;
17pub(crate) const INTERRUPT_HIGH: u32 = 1 << 5; 25pub(crate) const INTERRUPT_POLARITY_HIGH: u32 = 0x20;
18pub(crate) const WAKE_UP: u32 = 1 << 7; 26pub(crate) const WAKE_UP: u32 = 0x80;
19pub(crate) const STATUS_ENABLE: u32 = 1 << 16; 27
20pub(crate) const INTERRUPT_WITH_STATUS: u32 = 1 << 17; 28// SPI_STATUS_ENABLE bits
29pub(crate) const STATUS_ENABLE: u32 = 0x01;
30pub(crate) const INTR_WITH_STATUS: u32 = 0x02;
31pub(crate) const RESP_DELAY_ALL: u32 = 0x04;
32pub(crate) const DWORD_PKT_LEN_EN: u32 = 0x08;
33pub(crate) const CMD_ERR_CHK_EN: u32 = 0x20;
34pub(crate) const DATA_ERR_CHK_EN: u32 = 0x40;
21 35
22// SPI_STATUS_REGISTER bits 36// SPI_STATUS_REGISTER bits
23pub(crate) const STATUS_DATA_NOT_AVAILABLE: u32 = 0x00000001; 37pub(crate) const STATUS_DATA_NOT_AVAILABLE: u32 = 0x00000001;
@@ -51,6 +65,13 @@ pub(crate) const REG_BACKPLANE_READ_FRAME_BC_HIGH: u32 = 0x1001C;
51pub(crate) const REG_BACKPLANE_WAKEUP_CTRL: u32 = 0x1001E; 65pub(crate) const REG_BACKPLANE_WAKEUP_CTRL: u32 = 0x1001E;
52pub(crate) const REG_BACKPLANE_SLEEP_CSR: u32 = 0x1001F; 66pub(crate) const REG_BACKPLANE_SLEEP_CSR: u32 = 0x1001F;
53 67
68pub(crate) const I_HMB_SW_MASK: u32 = 0x000000f0;
69pub(crate) const I_HMB_FC_CHANGE: u32 = 1 << 5;
70pub(crate) const SDIO_INT_STATUS: u32 = 0x20;
71pub(crate) const SDIO_INT_HOST_MASK: u32 = 0x24;
72
73pub(crate) const SPI_F2_WATERMARK: u8 = 0x20;
74
54pub(crate) const BACKPLANE_WINDOW_SIZE: usize = 0x8000; 75pub(crate) const BACKPLANE_WINDOW_SIZE: usize = 0x8000;
55pub(crate) const BACKPLANE_ADDRESS_MASK: u32 = 0x7FFF; 76pub(crate) const BACKPLANE_ADDRESS_MASK: u32 = 0x7FFF;
56pub(crate) const BACKPLANE_ADDRESS_32BIT_FLAG: u32 = 0x08000; 77pub(crate) const BACKPLANE_ADDRESS_32BIT_FLAG: u32 = 0x08000;
@@ -92,17 +113,6 @@ pub(crate) const IRQ_F1_INTR: u16 = 0x2000;
92pub(crate) const IRQ_F2_INTR: u16 = 0x4000; 113pub(crate) const IRQ_F2_INTR: u16 = 0x4000;
93pub(crate) const IRQ_F3_INTR: u16 = 0x8000; 114pub(crate) const IRQ_F3_INTR: u16 = 0x8000;
94 115
95pub(crate) const IOCTL_CMD_UP: u32 = 2;
96pub(crate) const IOCTL_CMD_DOWN: u32 = 3;
97pub(crate) const IOCTL_CMD_SET_SSID: u32 = 26;
98pub(crate) const IOCTL_CMD_SET_CHANNEL: u32 = 30;
99pub(crate) const IOCTL_CMD_DISASSOC: u32 = 52;
100pub(crate) const IOCTL_CMD_ANTDIV: u32 = 64;
101pub(crate) const IOCTL_CMD_SET_AP: u32 = 118;
102pub(crate) const IOCTL_CMD_SET_VAR: u32 = 263;
103pub(crate) const IOCTL_CMD_GET_VAR: u32 = 262;
104pub(crate) const IOCTL_CMD_SET_PASSPHRASE: u32 = 268;
105
106pub(crate) const CHANNEL_TYPE_CONTROL: u8 = 0; 116pub(crate) const CHANNEL_TYPE_CONTROL: u8 = 0;
107pub(crate) const CHANNEL_TYPE_EVENT: u8 = 1; 117pub(crate) const CHANNEL_TYPE_EVENT: u8 = 1;
108pub(crate) const CHANNEL_TYPE_DATA: u8 = 2; 118pub(crate) const CHANNEL_TYPE_DATA: u8 = 2;
@@ -119,6 +129,44 @@ pub(crate) const WPA2_SECURITY: u32 = 0x00400000;
119pub(crate) const MIN_PSK_LEN: usize = 8; 129pub(crate) const MIN_PSK_LEN: usize = 8;
120pub(crate) const MAX_PSK_LEN: usize = 64; 130pub(crate) const MAX_PSK_LEN: usize = 64;
121 131
132// Bluetooth firmware extraction constants.
133pub(crate) const BTFW_ADDR_MODE_UNKNOWN: i32 = 0;
134pub(crate) const BTFW_ADDR_MODE_EXTENDED: i32 = 1;
135pub(crate) const BTFW_ADDR_MODE_SEGMENT: i32 = 2;
136pub(crate) const BTFW_ADDR_MODE_LINEAR32: i32 = 3;
137
138pub(crate) const BTFW_HEX_LINE_TYPE_DATA: u8 = 0;
139pub(crate) const BTFW_HEX_LINE_TYPE_END_OF_DATA: u8 = 1;
140pub(crate) const BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS: u8 = 2;
141pub(crate) const BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS: u8 = 4;
142pub(crate) const BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS: u8 = 5;
143
144// Bluetooth constants.
145pub(crate) const SPI_RESP_DELAY_F1: u32 = 0x001d;
146pub(crate) const WHD_BUS_SPI_BACKPLANE_READ_PADD_SIZE: u8 = 4;
147
148pub(crate) const BT2WLAN_PWRUP_WAKE: u32 = 3;
149pub(crate) const BT2WLAN_PWRUP_ADDR: u32 = 0x640894;
150
151pub(crate) const BT_CTRL_REG_ADDR: u32 = 0x18000c7c;
152pub(crate) const HOST_CTRL_REG_ADDR: u32 = 0x18000d6c;
153pub(crate) const WLAN_RAM_BASE_REG_ADDR: u32 = 0x18000d68;
154
155pub(crate) const BTSDIO_REG_DATA_VALID_BITMASK: u32 = 1 << 1;
156pub(crate) const BTSDIO_REG_BT_AWAKE_BITMASK: u32 = 1 << 8;
157pub(crate) const BTSDIO_REG_WAKE_BT_BITMASK: u32 = 1 << 17;
158pub(crate) const BTSDIO_REG_SW_RDY_BITMASK: u32 = 1 << 24;
159pub(crate) const BTSDIO_REG_FW_RDY_BITMASK: u32 = 1 << 24;
160
161pub(crate) const BTSDIO_FWBUF_SIZE: u32 = 0x1000;
162pub(crate) const BTSDIO_OFFSET_HOST_WRITE_BUF: u32 = 0;
163pub(crate) const BTSDIO_OFFSET_HOST_READ_BUF: u32 = BTSDIO_FWBUF_SIZE;
164
165pub(crate) const BTSDIO_OFFSET_HOST2BT_IN: u32 = 0x00002000;
166pub(crate) const BTSDIO_OFFSET_HOST2BT_OUT: u32 = 0x00002004;
167pub(crate) const BTSDIO_OFFSET_BT2HOST_IN: u32 = 0x00002008;
168pub(crate) const BTSDIO_OFFSET_BT2HOST_OUT: u32 = 0x0000200C;
169
122// Security type (authentication and encryption types are combined using bit mask) 170// Security type (authentication and encryption types are combined using bit mask)
123#[allow(non_camel_case_types)] 171#[allow(non_camel_case_types)]
124#[derive(Copy, Clone, PartialEq)] 172#[derive(Copy, Clone, PartialEq)]
@@ -317,3 +365,306 @@ impl core::fmt::Display for FormatInterrupt {
317 core::fmt::Debug::fmt(self, f) 365 core::fmt::Debug::fmt(self, f)
318 } 366 }
319} 367}
368
369#[derive(Copy, Clone, Debug)]
370#[cfg_attr(feature = "defmt", derive(defmt::Format))]
371#[repr(u32)]
372pub(crate) enum Ioctl {
373 GetMagic = 0,
374 GetVersion = 1,
375 Up = 2,
376 Down = 3,
377 GetLoop = 4,
378 SetLoop = 5,
379 Dump = 6,
380 GetMsglevel = 7,
381 SetMsglevel = 8,
382 GetPromisc = 9,
383 SetPromisc = 10,
384 GetRate = 12,
385 GetInstance = 14,
386 GetInfra = 19,
387 SetInfra = 20,
388 GetAuth = 21,
389 SetAuth = 22,
390 GetBssid = 23,
391 SetBssid = 24,
392 GetSsid = 25,
393 SetSsid = 26,
394 Restart = 27,
395 GetChannel = 29,
396 SetChannel = 30,
397 GetSrl = 31,
398 SetSrl = 32,
399 GetLrl = 33,
400 SetLrl = 34,
401 GetPlcphdr = 35,
402 SetPlcphdr = 36,
403 GetRadio = 37,
404 SetRadio = 38,
405 GetPhytype = 39,
406 DumpRate = 40,
407 SetRateParams = 41,
408 GetKey = 44,
409 SetKey = 45,
410 GetRegulatory = 46,
411 SetRegulatory = 47,
412 GetPassiveScan = 48,
413 SetPassiveScan = 49,
414 Scan = 50,
415 ScanResults = 51,
416 Disassoc = 52,
417 Reassoc = 53,
418 GetRoamTrigger = 54,
419 SetRoamTrigger = 55,
420 GetRoamDelta = 56,
421 SetRoamDelta = 57,
422 GetRoamScanPeriod = 58,
423 SetRoamScanPeriod = 59,
424 Evm = 60,
425 GetTxant = 61,
426 SetTxant = 62,
427 GetAntdiv = 63,
428 SetAntdiv = 64,
429 GetClosed = 67,
430 SetClosed = 68,
431 GetMaclist = 69,
432 SetMaclist = 70,
433 GetRateset = 71,
434 SetRateset = 72,
435 Longtrain = 74,
436 GetBcnprd = 75,
437 SetBcnprd = 76,
438 GetDtimprd = 77,
439 SetDtimprd = 78,
440 GetSrom = 79,
441 SetSrom = 80,
442 GetWepRestrict = 81,
443 SetWepRestrict = 82,
444 GetCountry = 83,
445 SetCountry = 84,
446 GetPm = 85,
447 SetPm = 86,
448 GetWake = 87,
449 SetWake = 88,
450 GetForcelink = 90,
451 SetForcelink = 91,
452 FreqAccuracy = 92,
453 CarrierSuppress = 93,
454 GetPhyreg = 94,
455 SetPhyreg = 95,
456 GetRadioreg = 96,
457 SetRadioreg = 97,
458 GetRevinfo = 98,
459 GetUcantdiv = 99,
460 SetUcantdiv = 100,
461 RReg = 101,
462 WReg = 102,
463 GetMacmode = 105,
464 SetMacmode = 106,
465 GetMonitor = 107,
466 SetMonitor = 108,
467 GetGmode = 109,
468 SetGmode = 110,
469 GetLegacyErp = 111,
470 SetLegacyErp = 112,
471 GetRxAnt = 113,
472 GetCurrRateset = 114,
473 GetScansuppress = 115,
474 SetScansuppress = 116,
475 GetAp = 117,
476 SetAp = 118,
477 GetEapRestrict = 119,
478 SetEapRestrict = 120,
479 ScbAuthorize = 121,
480 ScbDeauthorize = 122,
481 GetWdslist = 123,
482 SetWdslist = 124,
483 GetAtim = 125,
484 SetAtim = 126,
485 GetRssi = 127,
486 GetPhyantdiv = 128,
487 SetPhyantdiv = 129,
488 ApRxOnly = 130,
489 GetTxPathPwr = 131,
490 SetTxPathPwr = 132,
491 GetWsec = 133,
492 SetWsec = 134,
493 GetPhyNoise = 135,
494 GetBssInfo = 136,
495 GetPktcnts = 137,
496 GetLazywds = 138,
497 SetLazywds = 139,
498 GetBandlist = 140,
499 GetBand = 141,
500 SetBand = 142,
501 ScbDeauthenticate = 143,
502 GetShortslot = 144,
503 GetShortslotOverride = 145,
504 SetShortslotOverride = 146,
505 GetShortslotRestrict = 147,
506 SetShortslotRestrict = 148,
507 GetGmodeProtection = 149,
508 GetGmodeProtectionOverride = 150,
509 SetGmodeProtectionOverride = 151,
510 Upgrade = 152,
511 GetIgnoreBcns = 155,
512 SetIgnoreBcns = 156,
513 GetScbTimeout = 157,
514 SetScbTimeout = 158,
515 GetAssoclist = 159,
516 GetClk = 160,
517 SetClk = 161,
518 GetUp = 162,
519 Out = 163,
520 GetWpaAuth = 164,
521 SetWpaAuth = 165,
522 GetUcflags = 166,
523 SetUcflags = 167,
524 GetPwridx = 168,
525 SetPwridx = 169,
526 GetTssi = 170,
527 GetSupRatesetOverride = 171,
528 SetSupRatesetOverride = 172,
529 GetProtectionControl = 178,
530 SetProtectionControl = 179,
531 GetPhylist = 180,
532 EncryptStrength = 181,
533 DecryptStatus = 182,
534 GetKeySeq = 183,
535 GetScanChannelTime = 184,
536 SetScanChannelTime = 185,
537 GetScanUnassocTime = 186,
538 SetScanUnassocTime = 187,
539 GetScanHomeTime = 188,
540 SetScanHomeTime = 189,
541 GetScanNprobes = 190,
542 SetScanNprobes = 191,
543 GetPrbRespTimeout = 192,
544 SetPrbRespTimeout = 193,
545 GetAtten = 194,
546 SetAtten = 195,
547 GetShmem = 196,
548 SetShmem = 197,
549 SetWsecTest = 200,
550 ScbDeauthenticateForReason = 201,
551 TkipCountermeasures = 202,
552 GetPiomode = 203,
553 SetPiomode = 204,
554 SetAssocPrefer = 205,
555 GetAssocPrefer = 206,
556 SetRoamPrefer = 207,
557 GetRoamPrefer = 208,
558 SetLed = 209,
559 GetLed = 210,
560 GetInterferenceMode = 211,
561 SetInterferenceMode = 212,
562 GetChannelQa = 213,
563 StartChannelQa = 214,
564 GetChannelSel = 215,
565 StartChannelSel = 216,
566 GetValidChannels = 217,
567 GetFakefrag = 218,
568 SetFakefrag = 219,
569 GetPwroutPercentage = 220,
570 SetPwroutPercentage = 221,
571 SetBadFramePreempt = 222,
572 GetBadFramePreempt = 223,
573 SetLeapList = 224,
574 GetLeapList = 225,
575 GetCwmin = 226,
576 SetCwmin = 227,
577 GetCwmax = 228,
578 SetCwmax = 229,
579 GetWet = 230,
580 SetWet = 231,
581 GetPub = 232,
582 GetKeyPrimary = 235,
583 SetKeyPrimary = 236,
584 GetAciArgs = 238,
585 SetAciArgs = 239,
586 UnsetCallback = 240,
587 SetCallback = 241,
588 GetRadar = 242,
589 SetRadar = 243,
590 SetSpectManagment = 244,
591 GetSpectManagment = 245,
592 WdsGetRemoteHwaddr = 246,
593 WdsGetWpaSup = 247,
594 SetCsScanTimer = 248,
595 GetCsScanTimer = 249,
596 MeasureRequest = 250,
597 Init = 251,
598 SendQuiet = 252,
599 Keepalive = 253,
600 SendPwrConstraint = 254,
601 UpgradeStatus = 255,
602 CurrentPwr = 256,
603 GetScanPassiveTime = 257,
604 SetScanPassiveTime = 258,
605 LegacyLinkBehavior = 259,
606 GetChannelsInCountry = 260,
607 GetCountryList = 261,
608 GetVar = 262,
609 SetVar = 263,
610 NvramGet = 264,
611 NvramSet = 265,
612 NvramDump = 266,
613 Reboot = 267,
614 SetWsecPmk = 268,
615 GetAuthMode = 269,
616 SetAuthMode = 270,
617 GetWakeentry = 271,
618 SetWakeentry = 272,
619 NdconfigItem = 273,
620 Nvotpw = 274,
621 Otpw = 275,
622 IovBlockGet = 276,
623 IovModulesGet = 277,
624 SoftReset = 278,
625 GetAllowMode = 279,
626 SetAllowMode = 280,
627 GetDesiredBssid = 281,
628 SetDesiredBssid = 282,
629 DisassocMyap = 283,
630 GetNbands = 284,
631 GetBandstates = 285,
632 GetWlcBssInfo = 286,
633 GetAssocInfo = 287,
634 GetOidPhy = 288,
635 SetOidPhy = 289,
636 SetAssocTime = 290,
637 GetDesiredSsid = 291,
638 GetChanspec = 292,
639 GetAssocState = 293,
640 SetPhyState = 294,
641 GetScanPending = 295,
642 GetScanreqPending = 296,
643 GetPrevRoamReason = 297,
644 SetPrevRoamReason = 298,
645 GetBandstatesPi = 299,
646 GetPhyState = 300,
647 GetBssWpaRsn = 301,
648 GetBssWpa2Rsn = 302,
649 GetBssBcnTs = 303,
650 GetIntDisassoc = 304,
651 SetNumPeers = 305,
652 GetNumBss = 306,
653 GetWsecPmk = 318,
654 GetRandomBytes = 319,
655}
656
657pub(crate) const WSEC_TKIP: u32 = 0x02;
658pub(crate) const WSEC_AES: u32 = 0x04;
659
660pub(crate) const AUTH_OPEN: u32 = 0x00;
661pub(crate) const AUTH_SAE: u32 = 0x03;
662
663pub(crate) const MFP_NONE: u32 = 0;
664pub(crate) const MFP_CAPABLE: u32 = 1;
665pub(crate) const MFP_REQUIRED: u32 = 2;
666
667pub(crate) const WPA_AUTH_DISABLED: u32 = 0x0000;
668pub(crate) const WPA_AUTH_WPA_PSK: u32 = 0x0004;
669pub(crate) const WPA_AUTH_WPA2_PSK: u32 = 0x0080;
670pub(crate) const WPA_AUTH_WPA3_SAE_PSK: u32 = 0x40000;
diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs
index 8944865c1..071ba88e4 100644
--- a/cyw43/src/control.rs
+++ b/cyw43/src/control.rs
@@ -35,16 +35,19 @@ pub struct Control<'a> {
35 ioctl_state: &'a IoctlState, 35 ioctl_state: &'a IoctlState,
36} 36}
37 37
38#[derive(Copy, Clone)] 38#[derive(Copy, Clone, Debug)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))] 39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub enum ScanType { 40pub enum ScanType {
41 Active, 41 Active,
42 Passive, 42 Passive,
43} 43}
44 44
45#[derive(Clone)] 45/// Scan options.
46#[derive(Clone, Debug)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))] 47#[cfg_attr(feature = "defmt", derive(defmt::Format))]
48#[non_exhaustive]
47pub struct ScanOptions { 49pub struct ScanOptions {
50 /// SSID to scan for.
48 pub ssid: Option<heapless::String<32>>, 51 pub ssid: Option<heapless::String<32>>,
49 /// If set to `None`, all APs will be returned. If set to `Some`, only APs 52 /// If set to `None`, all APs will be returned. If set to `Some`, only APs
50 /// with the specified BSSID will be returned. 53 /// with the specified BSSID will be returned.
@@ -72,6 +75,79 @@ impl Default for ScanOptions {
72 } 75 }
73} 76}
74 77
78/// Authentication type, used in [`JoinOptions::auth`].
79#[derive(Copy, Clone, Debug, PartialEq, Eq)]
80#[cfg_attr(feature = "defmt", derive(defmt::Format))]
81pub enum JoinAuth {
82 /// Open network
83 Open,
84 /// WPA only
85 Wpa,
86 /// WPA2 only
87 Wpa2,
88 /// WPA3 only
89 Wpa3,
90 /// WPA2 + WPA3
91 Wpa2Wpa3,
92}
93
94/// Options for [`Control::join`].
95#[derive(Clone, Debug)]
96#[cfg_attr(feature = "defmt", derive(defmt::Format))]
97#[non_exhaustive]
98pub struct JoinOptions<'a> {
99 /// Authentication type. Default `Wpa2Wpa3`.
100 pub auth: JoinAuth,
101 /// Enable TKIP encryption. Default false.
102 pub cipher_tkip: bool,
103 /// Enable AES encryption. Default true.
104 pub cipher_aes: bool,
105 /// Passphrase. Default empty.
106 pub passphrase: &'a [u8],
107 /// If false, `passphrase` is the human-readable passphrase string.
108 /// If true, `passphrase` is the result of applying the PBKDF2 hash to the
109 /// passphrase string. This makes it possible to avoid storing unhashed passwords.
110 ///
111 /// This is not compatible with WPA3.
112 /// Default false.
113 pub passphrase_is_prehashed: bool,
114}
115
116impl<'a> JoinOptions<'a> {
117 /// Create a new `JoinOptions` for joining open networks.
118 pub fn new_open() -> Self {
119 Self {
120 auth: JoinAuth::Open,
121 cipher_tkip: false,
122 cipher_aes: false,
123 passphrase: &[],
124 passphrase_is_prehashed: false,
125 }
126 }
127
128 /// Create a new `JoinOptions` for joining encrypted networks.
129 ///
130 /// Defaults to supporting WPA2+WPA3 with AES only, you may edit
131 /// the returned options to change this.
132 pub fn new(passphrase: &'a [u8]) -> Self {
133 let mut this = Self::default();
134 this.passphrase = passphrase;
135 this
136 }
137}
138
139impl<'a> Default for JoinOptions<'a> {
140 fn default() -> Self {
141 Self {
142 auth: JoinAuth::Wpa2Wpa3,
143 cipher_tkip: false,
144 cipher_aes: true,
145 passphrase: &[],
146 passphrase_is_prehashed: false,
147 }
148 }
149}
150
75impl<'a> Control<'a> { 151impl<'a> Control<'a> {
76 pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a Events, ioctl_state: &'a IoctlState) -> Self { 152 pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a Events, ioctl_state: &'a IoctlState) -> Self {
77 Self { 153 Self {
@@ -81,8 +157,7 @@ impl<'a> Control<'a> {
81 } 157 }
82 } 158 }
83 159
84 /// Initialize WiFi controller. 160 async fn load_clm(&mut self, clm: &[u8]) {
85 pub async fn init(&mut self, clm: &[u8]) {
86 const CHUNK_SIZE: usize = 1024; 161 const CHUNK_SIZE: usize = 1024;
87 162
88 debug!("Downloading CLM..."); 163 debug!("Downloading CLM...");
@@ -108,12 +183,17 @@ impl<'a> Control<'a> {
108 buf[0..8].copy_from_slice(b"clmload\x00"); 183 buf[0..8].copy_from_slice(b"clmload\x00");
109 buf[8..20].copy_from_slice(&header.to_bytes()); 184 buf[8..20].copy_from_slice(&header.to_bytes());
110 buf[20..][..chunk.len()].copy_from_slice(&chunk); 185 buf[20..][..chunk.len()].copy_from_slice(&chunk);
111 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..8 + 12 + chunk.len()]) 186 self.ioctl(IoctlType::Set, Ioctl::SetVar, 0, &mut buf[..8 + 12 + chunk.len()])
112 .await; 187 .await;
113 } 188 }
114 189
115 // check clmload ok 190 // check clmload ok
116 assert_eq!(self.get_iovar_u32("clmload_status").await, 0); 191 assert_eq!(self.get_iovar_u32("clmload_status").await, 0);
192 }
193
194 /// Initialize WiFi controller.
195 pub async fn init(&mut self, clm: &[u8]) {
196 self.load_clm(&clm).await;
117 197
118 debug!("Configuring misc stuff..."); 198 debug!("Configuring misc stuff...");
119 199
@@ -139,7 +219,7 @@ impl<'a> Control<'a> {
139 Timer::after_millis(100).await; 219 Timer::after_millis(100).await;
140 220
141 // Set antenna to chip antenna 221 // Set antenna to chip antenna
142 self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await; 222 self.ioctl_set_u32(Ioctl::SetAntdiv, 0, 0).await;
143 223
144 self.set_iovar_u32("bus:txglom", 0).await; 224 self.set_iovar_u32("bus:txglom", 0).await;
145 Timer::after_millis(100).await; 225 Timer::after_millis(100).await;
@@ -177,24 +257,24 @@ impl<'a> Control<'a> {
177 257
178 Timer::after_millis(100).await; 258 Timer::after_millis(100).await;
179 259
180 self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto 260 self.ioctl_set_u32(Ioctl::SetGmode, 0, 1).await; // SET_GMODE = auto
181 self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any 261 self.ioctl_set_u32(Ioctl::SetBand, 0, 0).await; // SET_BAND = any
182 262
183 Timer::after_millis(100).await; 263 Timer::after_millis(100).await;
184 264
185 self.state_ch.set_hardware_address(HardwareAddress::Ethernet(mac_addr)); 265 self.state_ch.set_hardware_address(HardwareAddress::Ethernet(mac_addr));
186 266
187 debug!("INIT DONE"); 267 debug!("cyw43 control init done");
188 } 268 }
189 269
190 /// Set the WiFi interface up. 270 /// Set the WiFi interface up.
191 async fn up(&mut self) { 271 async fn up(&mut self) {
192 self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await; 272 self.ioctl(IoctlType::Set, Ioctl::Up, 0, &mut []).await;
193 } 273 }
194 274
195 /// Set the interface down. 275 /// Set the interface down.
196 async fn down(&mut self) { 276 async fn down(&mut self) {
197 self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await; 277 self.ioctl(IoctlType::Set, Ioctl::Down, 0, &mut []).await;
198 } 278 }
199 279
200 /// Set power management mode. 280 /// Set power management mode.
@@ -207,49 +287,74 @@ impl<'a> Control<'a> {
207 self.set_iovar_u32("bcn_li_dtim", mode.dtim_period() as u32).await; 287 self.set_iovar_u32("bcn_li_dtim", mode.dtim_period() as u32).await;
208 self.set_iovar_u32("assoc_listen", mode.assoc() as u32).await; 288 self.set_iovar_u32("assoc_listen", mode.assoc() as u32).await;
209 } 289 }
210 self.ioctl_set_u32(86, 0, mode_num).await; 290 self.ioctl_set_u32(Ioctl::SetPm, 0, mode_num).await;
211 } 291 }
212 292
213 /// Join an unprotected network with the provided ssid. 293 /// Join an unprotected network with the provided ssid.
214 pub async fn join_open(&mut self, ssid: &str) -> Result<(), Error> { 294 pub async fn join(&mut self, ssid: &str, options: JoinOptions<'_>) -> Result<(), Error> {
215 self.set_iovar_u32("ampdu_ba_wsize", 8).await; 295 self.set_iovar_u32("ampdu_ba_wsize", 8).await;
216 296
217 self.ioctl_set_u32(134, 0, 0).await; // wsec = open 297 if options.auth == JoinAuth::Open {
218 self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 0).await; 298 self.ioctl_set_u32(Ioctl::SetWsec, 0, 0).await;
219 self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1 299 self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 0).await;
220 self.ioctl_set_u32(22, 0, 0).await; // set_auth = open (0) 300 self.ioctl_set_u32(Ioctl::SetInfra, 0, 1).await;
221 301 self.ioctl_set_u32(Ioctl::SetAuth, 0, 0).await;
222 let mut i = SsidInfo { 302 self.ioctl_set_u32(Ioctl::SetWpaAuth, 0, WPA_AUTH_DISABLED).await;
223 len: ssid.len() as _, 303 } else {
224 ssid: [0; 32], 304 let mut wsec = 0;
225 }; 305 if options.cipher_aes {
226 i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes()); 306 wsec |= WSEC_AES;
307 }
308 if options.cipher_tkip {
309 wsec |= WSEC_TKIP;
310 }
311 self.ioctl_set_u32(Ioctl::SetWsec, 0, wsec).await;
227 312
228 self.wait_for_join(i).await 313 self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await;
229 } 314 self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await;
315 self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await;
230 316
231 /// Join a protected network with the provided ssid and [`PassphraseInfo`]. 317 Timer::after_millis(100).await;
232 async fn join_wpa2_passphrase_info(&mut self, ssid: &str, passphrase_info: &PassphraseInfo) -> Result<(), Error> {
233 self.set_iovar_u32("ampdu_ba_wsize", 8).await;
234 318
235 self.ioctl_set_u32(134, 0, 4).await; // wsec = wpa2 319 let (wpa12, wpa3, auth, mfp, wpa_auth) = match options.auth {
236 self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await; 320 JoinAuth::Open => unreachable!(),
237 self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await; 321 JoinAuth::Wpa => (true, false, AUTH_OPEN, MFP_NONE, WPA_AUTH_WPA_PSK),
238 self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await; 322 JoinAuth::Wpa2 => (true, false, AUTH_OPEN, MFP_CAPABLE, WPA_AUTH_WPA2_PSK),
323 JoinAuth::Wpa3 => (false, true, AUTH_SAE, MFP_REQUIRED, WPA_AUTH_WPA3_SAE_PSK),
324 JoinAuth::Wpa2Wpa3 => (true, true, AUTH_SAE, MFP_CAPABLE, WPA_AUTH_WPA3_SAE_PSK),
325 };
239 326
240 Timer::after_millis(100).await; 327 if wpa12 {
328 let mut flags = 0;
329 if !options.passphrase_is_prehashed {
330 flags |= 1;
331 }
332 let mut pfi = PassphraseInfo {
333 len: options.passphrase.len() as _,
334 flags,
335 passphrase: [0; 64],
336 };
337 pfi.passphrase[..options.passphrase.len()].copy_from_slice(options.passphrase);
338 Timer::after_millis(3).await;
339 self.ioctl(IoctlType::Set, Ioctl::SetWsecPmk, 0, &mut pfi.to_bytes())
340 .await;
341 }
241 342
242 self.ioctl( 343 if wpa3 {
243 IoctlType::Set, 344 let mut pfi = SaePassphraseInfo {
244 IOCTL_CMD_SET_PASSPHRASE, 345 len: options.passphrase.len() as _,
245 0, 346 passphrase: [0; 128],
246 &mut passphrase_info.to_bytes(), 347 };
247 ) 348 pfi.passphrase[..options.passphrase.len()].copy_from_slice(options.passphrase);
248 .await; // WLC_SET_WSEC_PMK 349 Timer::after_millis(3).await;
350 self.set_iovar("sae_password", &pfi.to_bytes()).await;
351 }
249 352
250 self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1 353 self.ioctl_set_u32(Ioctl::SetInfra, 0, 1).await;
251 self.ioctl_set_u32(22, 0, 0).await; // set_auth = 0 (open) 354 self.ioctl_set_u32(Ioctl::SetAuth, 0, auth).await;
252 self.ioctl_set_u32(165, 0, 0x80).await; // set_wpa_auth 355 self.set_iovar_u32("mfp", mfp).await;
356 self.ioctl_set_u32(Ioctl::SetWpaAuth, 0, wpa_auth).await;
357 }
253 358
254 let mut i = SsidInfo { 359 let mut i = SsidInfo {
255 len: ssid.len() as _, 360 len: ssid.len() as _,
@@ -260,37 +365,13 @@ impl<'a> Control<'a> {
260 self.wait_for_join(i).await 365 self.wait_for_join(i).await
261 } 366 }
262 367
263 /// Join a protected network with the provided ssid and passphrase.
264 pub async fn join_wpa2(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> {
265 let mut pfi = PassphraseInfo {
266 len: passphrase.len() as _,
267 flags: 1,
268 passphrase: [0; 64],
269 };
270 pfi.passphrase[..passphrase.len()].copy_from_slice(passphrase.as_bytes());
271 self.join_wpa2_passphrase_info(ssid, &pfi).await
272 }
273
274 /// Join a protected network with the provided ssid and precomputed PSK.
275 pub async fn join_wpa2_psk(&mut self, ssid: &str, psk: &[u8; 32]) -> Result<(), Error> {
276 let mut pfi = PassphraseInfo {
277 len: psk.len() as _,
278 flags: 0,
279 passphrase: [0; 64],
280 };
281 pfi.passphrase[..psk.len()].copy_from_slice(psk);
282 self.join_wpa2_passphrase_info(ssid, &pfi).await
283 }
284
285 async fn wait_for_join(&mut self, i: SsidInfo) -> Result<(), Error> { 368 async fn wait_for_join(&mut self, i: SsidInfo) -> Result<(), Error> {
286 self.events.mask.enable(&[Event::SET_SSID, Event::AUTH]); 369 self.events.mask.enable(&[Event::SET_SSID, Event::AUTH]);
287 let mut subscriber = self.events.queue.subscriber().unwrap(); 370 let mut subscriber = self.events.queue.subscriber().unwrap();
288 // the actual join operation starts here 371 // the actual join operation starts here
289 // we make sure to enable events before so we don't miss any 372 // we make sure to enable events before so we don't miss any
290 373
291 // set_ssid 374 self.ioctl(IoctlType::Set, Ioctl::SetSsid, 0, &mut i.to_bytes()).await;
292 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_SSID, 0, &mut i.to_bytes())
293 .await;
294 375
295 // to complete the join, we wait for a SET_SSID event 376 // to complete the join, we wait for a SET_SSID event
296 // we also save the AUTH status for the user, it may be interesting 377 // we also save the AUTH status for the user, it may be interesting
@@ -351,7 +432,7 @@ impl<'a> Control<'a> {
351 self.up().await; 432 self.up().await;
352 433
353 // Turn on AP mode 434 // Turn on AP mode
354 self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 1).await; 435 self.ioctl_set_u32(Ioctl::SetAp, 0, 1).await;
355 436
356 // Set SSID 437 // Set SSID
357 let mut i = SsidInfoWithIndex { 438 let mut i = SsidInfoWithIndex {
@@ -365,7 +446,7 @@ impl<'a> Control<'a> {
365 self.set_iovar("bsscfg:ssid", &i.to_bytes()).await; 446 self.set_iovar("bsscfg:ssid", &i.to_bytes()).await;
366 447
367 // Set channel number 448 // Set channel number
368 self.ioctl_set_u32(IOCTL_CMD_SET_CHANNEL, 0, channel as u32).await; 449 self.ioctl_set_u32(Ioctl::SetChannel, 0, channel as u32).await;
369 450
370 // Set security 451 // Set security
371 self.set_iovar_u32x2("bsscfg:wsec", 0, (security as u32) & 0xFF).await; 452 self.set_iovar_u32x2("bsscfg:wsec", 0, (security as u32) & 0xFF).await;
@@ -382,7 +463,7 @@ impl<'a> Control<'a> {
382 passphrase: [0; 64], 463 passphrase: [0; 64],
383 }; 464 };
384 pfi.passphrase[..passphrase.as_bytes().len()].copy_from_slice(passphrase.as_bytes()); 465 pfi.passphrase[..passphrase.as_bytes().len()].copy_from_slice(passphrase.as_bytes());
385 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_PASSPHRASE, 0, &mut pfi.to_bytes()) 466 self.ioctl(IoctlType::Set, Ioctl::SetWsecPmk, 0, &mut pfi.to_bytes())
386 .await; 467 .await;
387 } 468 }
388 469
@@ -399,7 +480,7 @@ impl<'a> Control<'a> {
399 self.set_iovar_u32x2("bss", 0, 0).await; // bss = BSS_DOWN 480 self.set_iovar_u32x2("bss", 0, 0).await; // bss = BSS_DOWN
400 481
401 // Turn off AP mode 482 // Turn off AP mode
402 self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 0).await; 483 self.ioctl_set_u32(Ioctl::SetAp, 0, 0).await;
403 484
404 // Temporarily set wifi down 485 // Temporarily set wifi down
405 self.down().await; 486 self.down().await;
@@ -478,11 +559,11 @@ impl<'a> Control<'a> {
478 } 559 }
479 560
480 async fn set_iovar(&mut self, name: &str, val: &[u8]) { 561 async fn set_iovar(&mut self, name: &str, val: &[u8]) {
481 self.set_iovar_v::<64>(name, val).await 562 self.set_iovar_v::<196>(name, val).await
482 } 563 }
483 564
484 async fn set_iovar_v<const BUFSIZE: usize>(&mut self, name: &str, val: &[u8]) { 565 async fn set_iovar_v<const BUFSIZE: usize>(&mut self, name: &str, val: &[u8]) {
485 debug!("set {} = {:02x}", name, Bytes(val)); 566 debug!("iovar set {} = {:02x}", name, Bytes(val));
486 567
487 let mut buf = [0; BUFSIZE]; 568 let mut buf = [0; BUFSIZE];
488 buf[..name.len()].copy_from_slice(name.as_bytes()); 569 buf[..name.len()].copy_from_slice(name.as_bytes());
@@ -490,13 +571,13 @@ impl<'a> Control<'a> {
490 buf[name.len() + 1..][..val.len()].copy_from_slice(val); 571 buf[name.len() + 1..][..val.len()].copy_from_slice(val);
491 572
492 let total_len = name.len() + 1 + val.len(); 573 let total_len = name.len() + 1 + val.len();
493 self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..total_len]) 574 self.ioctl_inner(IoctlType::Set, Ioctl::SetVar, 0, &mut buf[..total_len])
494 .await; 575 .await;
495 } 576 }
496 577
497 // TODO this is not really working, it always returns all zeros. 578 // TODO this is not really working, it always returns all zeros.
498 async fn get_iovar(&mut self, name: &str, res: &mut [u8]) -> usize { 579 async fn get_iovar(&mut self, name: &str, res: &mut [u8]) -> usize {
499 debug!("get {}", name); 580 debug!("iovar get {}", name);
500 581
501 let mut buf = [0; 64]; 582 let mut buf = [0; 64];
502 buf[..name.len()].copy_from_slice(name.as_bytes()); 583 buf[..name.len()].copy_from_slice(name.as_bytes());
@@ -504,7 +585,7 @@ impl<'a> Control<'a> {
504 585
505 let total_len = max(name.len() + 1, res.len()); 586 let total_len = max(name.len() + 1, res.len());
506 let res_len = self 587 let res_len = self
507 .ioctl(IoctlType::Get, IOCTL_CMD_GET_VAR, 0, &mut buf[..total_len]) 588 .ioctl_inner(IoctlType::Get, Ioctl::GetVar, 0, &mut buf[..total_len])
508 .await; 589 .await;
509 590
510 let out_len = min(res.len(), res_len); 591 let out_len = min(res.len(), res_len);
@@ -512,12 +593,20 @@ impl<'a> Control<'a> {
512 out_len 593 out_len
513 } 594 }
514 595
515 async fn ioctl_set_u32(&mut self, cmd: u32, iface: u32, val: u32) { 596 async fn ioctl_set_u32(&mut self, cmd: Ioctl, iface: u32, val: u32) {
516 let mut buf = val.to_le_bytes(); 597 let mut buf = val.to_le_bytes();
517 self.ioctl(IoctlType::Set, cmd, iface, &mut buf).await; 598 self.ioctl(IoctlType::Set, cmd, iface, &mut buf).await;
518 } 599 }
519 600
520 async fn ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { 601 async fn ioctl(&mut self, kind: IoctlType, cmd: Ioctl, iface: u32, buf: &mut [u8]) -> usize {
602 if kind == IoctlType::Set {
603 debug!("ioctl set {:?} iface {} = {:02x}", cmd, iface, Bytes(buf));
604 }
605 let n = self.ioctl_inner(kind, cmd, iface, buf).await;
606 n
607 }
608
609 async fn ioctl_inner(&mut self, kind: IoctlType, cmd: Ioctl, iface: u32, buf: &mut [u8]) -> usize {
521 struct CancelOnDrop<'a>(&'a IoctlState); 610 struct CancelOnDrop<'a>(&'a IoctlState);
522 611
523 impl CancelOnDrop<'_> { 612 impl CancelOnDrop<'_> {
@@ -609,7 +698,7 @@ impl<'a> Control<'a> {
609 } 698 }
610 /// Leave the wifi, with which we are currently associated. 699 /// Leave the wifi, with which we are currently associated.
611 pub async fn leave(&mut self) { 700 pub async fn leave(&mut self) {
612 self.ioctl(IoctlType::Set, IOCTL_CMD_DISASSOC, 0, &mut []).await; 701 self.ioctl(IoctlType::Set, Ioctl::Disassoc, 0, &mut []).await;
613 info!("Disassociated") 702 info!("Disassociated")
614 } 703 }
615 704
diff --git a/cyw43/src/fmt.rs b/cyw43/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/cyw43/src/fmt.rs
+++ b/cyw43/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/cyw43/src/ioctl.rs b/cyw43/src/ioctl.rs
index 61524c274..f8b2d9aba 100644
--- a/cyw43/src/ioctl.rs
+++ b/cyw43/src/ioctl.rs
@@ -4,9 +4,10 @@ use core::task::{Poll, Waker};
4 4
5use embassy_sync::waitqueue::WakerRegistration; 5use embassy_sync::waitqueue::WakerRegistration;
6 6
7use crate::consts::Ioctl;
7use crate::fmt::Bytes; 8use crate::fmt::Bytes;
8 9
9#[derive(Clone, Copy)] 10#[derive(Clone, Copy, PartialEq, Eq)]
10pub enum IoctlType { 11pub enum IoctlType {
11 Get = 0, 12 Get = 0,
12 Set = 2, 13 Set = 2,
@@ -16,7 +17,7 @@ pub enum IoctlType {
16pub struct PendingIoctl { 17pub struct PendingIoctl {
17 pub buf: *mut [u8], 18 pub buf: *mut [u8],
18 pub kind: IoctlType, 19 pub kind: IoctlType,
19 pub cmd: u32, 20 pub cmd: Ioctl,
20 pub iface: u32, 21 pub iface: u32,
21} 22}
22 23
@@ -101,7 +102,7 @@ impl IoctlState {
101 self.state.set(IoctlStateInner::Done { resp_len: 0 }); 102 self.state.set(IoctlStateInner::Done { resp_len: 0 });
102 } 103 }
103 104
104 pub async fn do_ioctl(&self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { 105 pub async fn do_ioctl(&self, kind: IoctlType, cmd: Ioctl, iface: u32, buf: &mut [u8]) -> usize {
105 self.state 106 self.state
106 .set(IoctlStateInner::Pending(PendingIoctl { buf, kind, cmd, iface })); 107 .set(IoctlStateInner::Pending(PendingIoctl { buf, kind, cmd, iface }));
107 self.wake_runner(); 108 self.wake_runner();
diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs
index 19b0cb194..6b71c18e6 100644
--- a/cyw43/src/lib.rs
+++ b/cyw43/src/lib.rs
@@ -8,18 +8,18 @@
8// This mod MUST go first, so that the others see its macros. 8// This mod MUST go first, so that the others see its macros.
9pub(crate) mod fmt; 9pub(crate) mod fmt;
10 10
11#[cfg(feature = "bluetooth")]
12mod bluetooth;
11mod bus; 13mod bus;
12mod consts; 14mod consts;
15mod control;
13mod countries; 16mod countries;
14mod events; 17mod events;
15mod ioctl; 18mod ioctl;
16mod structs;
17
18mod control;
19mod nvram; 19mod nvram;
20mod runner; 20mod runner;
21 21mod structs;
22use core::slice; 22mod util;
23 23
24use embassy_net_driver_channel as ch; 24use embassy_net_driver_channel as ch;
25use embedded_hal_1::digital::OutputPin; 25use embedded_hal_1::digital::OutputPin;
@@ -28,7 +28,9 @@ use ioctl::IoctlState;
28 28
29use crate::bus::Bus; 29use crate::bus::Bus;
30pub use crate::bus::SpiBusCyw43; 30pub use crate::bus::SpiBusCyw43;
31pub use crate::control::{AddMulticastAddressError, Control, Error as ControlError, Scanner}; 31pub use crate::control::{
32 AddMulticastAddressError, Control, Error as ControlError, JoinAuth, JoinOptions, ScanOptions, Scanner,
33};
32pub use crate::runner::Runner; 34pub use crate::runner::Runner;
33pub use crate::structs::BssInfo; 35pub use crate::structs::BssInfo;
34 36
@@ -56,6 +58,7 @@ impl Core {
56struct Chip { 58struct Chip {
57 arm_core_base_address: u32, 59 arm_core_base_address: u32,
58 socsram_base_address: u32, 60 socsram_base_address: u32,
61 bluetooth_base_address: u32,
59 socsram_wrapper_base_address: u32, 62 socsram_wrapper_base_address: u32,
60 sdiod_core_base_address: u32, 63 sdiod_core_base_address: u32,
61 pmu_base_address: u32, 64 pmu_base_address: u32,
@@ -83,6 +86,7 @@ const WRAPPER_REGISTER_OFFSET: u32 = 0x100000;
83const CHIP: Chip = Chip { 86const CHIP: Chip = Chip {
84 arm_core_base_address: 0x18003000 + WRAPPER_REGISTER_OFFSET, 87 arm_core_base_address: 0x18003000 + WRAPPER_REGISTER_OFFSET,
85 socsram_base_address: 0x18004000, 88 socsram_base_address: 0x18004000,
89 bluetooth_base_address: 0x19000000,
86 socsram_wrapper_base_address: 0x18004000 + WRAPPER_REGISTER_OFFSET, 90 socsram_wrapper_base_address: 0x18004000 + WRAPPER_REGISTER_OFFSET,
87 sdiod_core_base_address: 0x18002000, 91 sdiod_core_base_address: 0x18002000,
88 pmu_base_address: 0x18000000, 92 pmu_base_address: 0x18000000,
@@ -107,6 +111,12 @@ const CHIP: Chip = Chip {
107/// Driver state. 111/// Driver state.
108pub struct State { 112pub struct State {
109 ioctl_state: IoctlState, 113 ioctl_state: IoctlState,
114 net: NetState,
115 #[cfg(feature = "bluetooth")]
116 bt: bluetooth::BtState,
117}
118
119struct NetState {
110 ch: ch::State<MTU, 4, 4>, 120 ch: ch::State<MTU, 4, 4>,
111 events: Events, 121 events: Events,
112} 122}
@@ -116,8 +126,12 @@ impl State {
116 pub fn new() -> Self { 126 pub fn new() -> Self {
117 Self { 127 Self {
118 ioctl_state: IoctlState::new(), 128 ioctl_state: IoctlState::new(),
119 ch: ch::State::new(), 129 net: NetState {
120 events: Events::new(), 130 ch: ch::State::new(),
131 events: Events::new(),
132 },
133 #[cfg(feature = "bluetooth")]
134 bt: bluetooth::BtState::new(),
121 } 135 }
122 } 136 }
123} 137}
@@ -225,21 +239,60 @@ where
225 PWR: OutputPin, 239 PWR: OutputPin,
226 SPI: SpiBusCyw43, 240 SPI: SpiBusCyw43,
227{ 241{
228 let (ch_runner, device) = ch::new(&mut state.ch, ch::driver::HardwareAddress::Ethernet([0; 6])); 242 let (ch_runner, device) = ch::new(&mut state.net.ch, ch::driver::HardwareAddress::Ethernet([0; 6]));
229 let state_ch = ch_runner.state_runner(); 243 let state_ch = ch_runner.state_runner();
230 244
231 let mut runner = Runner::new(ch_runner, Bus::new(pwr, spi), &state.ioctl_state, &state.events); 245 let mut runner = Runner::new(
246 ch_runner,
247 Bus::new(pwr, spi),
248 &state.ioctl_state,
249 &state.net.events,
250 #[cfg(feature = "bluetooth")]
251 None,
252 );
232 253
233 runner.init(firmware).await; 254 runner.init(firmware, None).await;
255 let control = Control::new(state_ch, &state.net.events, &state.ioctl_state);
234 256
235 ( 257 (device, control, runner)
236 device,
237 Control::new(state_ch, &state.events, &state.ioctl_state),
238 runner,
239 )
240} 258}
241 259
242fn slice8_mut(x: &mut [u32]) -> &mut [u8] { 260/// Create a new instance of the CYW43 driver.
243 let len = x.len() * 4; 261///
244 unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) } 262/// Returns a handle to the network device, control handle and a runner for driving the low level
263/// stack.
264#[cfg(feature = "bluetooth")]
265pub async fn new_with_bluetooth<'a, PWR, SPI>(
266 state: &'a mut State,
267 pwr: PWR,
268 spi: SPI,
269 wifi_firmware: &[u8],
270 bluetooth_firmware: &[u8],
271) -> (
272 NetDriver<'a>,
273 bluetooth::BtDriver<'a>,
274 Control<'a>,
275 Runner<'a, PWR, SPI>,
276)
277where
278 PWR: OutputPin,
279 SPI: SpiBusCyw43,
280{
281 let (ch_runner, device) = ch::new(&mut state.net.ch, ch::driver::HardwareAddress::Ethernet([0; 6]));
282 let state_ch = ch_runner.state_runner();
283
284 let (bt_runner, bt_driver) = bluetooth::new(&mut state.bt);
285 let mut runner = Runner::new(
286 ch_runner,
287 Bus::new(pwr, spi),
288 &state.ioctl_state,
289 &state.net.events,
290 #[cfg(feature = "bluetooth")]
291 Some(bt_runner),
292 );
293
294 runner.init(wifi_firmware, Some(bluetooth_firmware)).await;
295 let control = Control::new(state_ch, &state.net.events, &state.ioctl_state);
296
297 (device, bt_driver, control, runner)
245} 298}
diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs
index e90316302..77910b281 100644
--- a/cyw43/src/runner.rs
+++ b/cyw43/src/runner.rs
@@ -1,4 +1,4 @@
1use embassy_futures::select::{select3, Either3}; 1use embassy_futures::select::{select4, Either4};
2use embassy_net_driver_channel as ch; 2use embassy_net_driver_channel as ch;
3use embassy_time::{block_for, Duration, Timer}; 3use embassy_time::{block_for, Duration, Timer};
4use embedded_hal_1::digital::OutputPin; 4use embedded_hal_1::digital::OutputPin;
@@ -11,7 +11,8 @@ use crate::fmt::Bytes;
11use crate::ioctl::{IoctlState, IoctlType, PendingIoctl}; 11use crate::ioctl::{IoctlState, IoctlType, PendingIoctl};
12use crate::nvram::NVRAM; 12use crate::nvram::NVRAM;
13use crate::structs::*; 13use crate::structs::*;
14use crate::{events, slice8_mut, Core, CHIP, MTU}; 14use crate::util::slice8_mut;
15use crate::{events, Core, CHIP, MTU};
15 16
16#[cfg(feature = "firmware-logs")] 17#[cfg(feature = "firmware-logs")]
17struct LogState { 18struct LogState {
@@ -36,7 +37,7 @@ impl Default for LogState {
36/// Driver communicating with the WiFi chip. 37/// Driver communicating with the WiFi chip.
37pub struct Runner<'a, PWR, SPI> { 38pub struct Runner<'a, PWR, SPI> {
38 ch: ch::Runner<'a, MTU>, 39 ch: ch::Runner<'a, MTU>,
39 bus: Bus<PWR, SPI>, 40 pub(crate) bus: Bus<PWR, SPI>,
40 41
41 ioctl_state: &'a IoctlState, 42 ioctl_state: &'a IoctlState,
42 ioctl_id: u16, 43 ioctl_id: u16,
@@ -47,6 +48,9 @@ pub struct Runner<'a, PWR, SPI> {
47 48
48 #[cfg(feature = "firmware-logs")] 49 #[cfg(feature = "firmware-logs")]
49 log: LogState, 50 log: LogState,
51
52 #[cfg(feature = "bluetooth")]
53 pub(crate) bt: Option<crate::bluetooth::BtRunner<'a>>,
50} 54}
51 55
52impl<'a, PWR, SPI> Runner<'a, PWR, SPI> 56impl<'a, PWR, SPI> Runner<'a, PWR, SPI>
@@ -59,6 +63,7 @@ where
59 bus: Bus<PWR, SPI>, 63 bus: Bus<PWR, SPI>,
60 ioctl_state: &'a IoctlState, 64 ioctl_state: &'a IoctlState,
61 events: &'a Events, 65 events: &'a Events,
66 #[cfg(feature = "bluetooth")] bt: Option<crate::bluetooth::BtRunner<'a>>,
62 ) -> Self { 67 ) -> Self {
63 Self { 68 Self {
64 ch, 69 ch,
@@ -70,33 +75,52 @@ where
70 events, 75 events,
71 #[cfg(feature = "firmware-logs")] 76 #[cfg(feature = "firmware-logs")]
72 log: LogState::default(), 77 log: LogState::default(),
78 #[cfg(feature = "bluetooth")]
79 bt,
73 } 80 }
74 } 81 }
75 82
76 pub(crate) async fn init(&mut self, firmware: &[u8]) { 83 pub(crate) async fn init(&mut self, wifi_fw: &[u8], bt_fw: Option<&[u8]>) {
77 self.bus.init().await; 84 self.bus.init(bt_fw.is_some()).await;
78 85
79 // Init ALP (Active Low Power) clock 86 // Init ALP (Active Low Power) clock
87 debug!("init alp");
80 self.bus 88 self.bus
81 .write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, BACKPLANE_ALP_AVAIL_REQ) 89 .write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, BACKPLANE_ALP_AVAIL_REQ)
82 .await; 90 .await;
91
92 debug!("set f2 watermark");
93 self.bus
94 .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 0x10)
95 .await;
96 let watermark = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK).await;
97 debug!("watermark = {:02x}", watermark);
98 assert!(watermark == 0x10);
99
83 debug!("waiting for clock..."); 100 debug!("waiting for clock...");
84 while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {} 101 while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {}
85 debug!("clock ok"); 102 debug!("clock ok");
86 103
104 // clear request for ALP
105 debug!("clear request for ALP");
106 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0).await;
107
87 let chip_id = self.bus.bp_read16(0x1800_0000).await; 108 let chip_id = self.bus.bp_read16(0x1800_0000).await;
88 debug!("chip ID: {}", chip_id); 109 debug!("chip ID: {}", chip_id);
89 110
90 // Upload firmware. 111 // Upload firmware.
91 self.core_disable(Core::WLAN).await; 112 self.core_disable(Core::WLAN).await;
113 self.core_disable(Core::SOCSRAM).await; // TODO: is this needed if we reset right after?
92 self.core_reset(Core::SOCSRAM).await; 114 self.core_reset(Core::SOCSRAM).await;
115
116 // this is 4343x specific stuff: Disable remap for SRAM_3
93 self.bus.bp_write32(CHIP.socsram_base_address + 0x10, 3).await; 117 self.bus.bp_write32(CHIP.socsram_base_address + 0x10, 3).await;
94 self.bus.bp_write32(CHIP.socsram_base_address + 0x44, 0).await; 118 self.bus.bp_write32(CHIP.socsram_base_address + 0x44, 0).await;
95 119
96 let ram_addr = CHIP.atcm_ram_base_address; 120 let ram_addr = CHIP.atcm_ram_base_address;
97 121
98 debug!("loading fw"); 122 debug!("loading fw");
99 self.bus.bp_write(ram_addr, firmware).await; 123 self.bus.bp_write(ram_addr, wifi_fw).await;
100 124
101 debug!("loading nvram"); 125 debug!("loading nvram");
102 // Round up to 4 bytes. 126 // Round up to 4 bytes.
@@ -116,10 +140,23 @@ where
116 self.core_reset(Core::WLAN).await; 140 self.core_reset(Core::WLAN).await;
117 assert!(self.core_is_up(Core::WLAN).await); 141 assert!(self.core_is_up(Core::WLAN).await);
118 142
143 // wait until HT clock is available; takes about 29ms
144 debug!("wait for HT clock");
119 while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} 145 while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
120 146
121 // "Set up the interrupt mask and enable interrupts" 147 // "Set up the interrupt mask and enable interrupts"
122 // self.bus.bp_write32(CHIP.sdiod_core_base_address + 0x24, 0xF0).await; 148 debug!("setup interrupt mask");
149 self.bus
150 .bp_write32(CHIP.sdiod_core_base_address + SDIO_INT_HOST_MASK, I_HMB_SW_MASK)
151 .await;
152
153 // Set up the interrupt mask and enable interrupts
154 if bt_fw.is_some() {
155 debug!("bluetooth setup interrupt mask");
156 self.bus
157 .bp_write32(CHIP.sdiod_core_base_address + SDIO_INT_HOST_MASK, I_HMB_FC_CHANGE)
158 .await;
159 }
123 160
124 self.bus 161 self.bus
125 .write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, IRQ_F2_PACKET_AVAILABLE) 162 .write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, IRQ_F2_PACKET_AVAILABLE)
@@ -128,11 +165,11 @@ where
128 // "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped." 165 // "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped."
129 // Sounds scary... 166 // Sounds scary...
130 self.bus 167 self.bus
131 .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 32) 168 .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, SPI_F2_WATERMARK)
132 .await; 169 .await;
133 170
134 // wait for wifi startup 171 // wait for F2 to be ready
135 debug!("waiting for wifi init..."); 172 debug!("waiting for F2 to be ready...");
136 while self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {} 173 while self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {}
137 174
138 // Some random configs related to sleep. 175 // Some random configs related to sleep.
@@ -153,19 +190,27 @@ where
153 */ 190 */
154 191
155 // clear pulls 192 // clear pulls
193 debug!("clear pad pulls");
156 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await; 194 self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await;
157 let _ = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await; 195 let _ = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await;
158 196
159 // start HT clock 197 // start HT clock
160 //self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10).await; 198 self.bus
161 //debug!("waiting for HT clock..."); 199 .write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10)
162 //while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} 200 .await; // SBSDIO_HT_AVAIL_REQ
163 //debug!("clock ok"); 201 debug!("waiting for HT clock...");
202 while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {}
203 debug!("clock ok");
164 204
165 #[cfg(feature = "firmware-logs")] 205 #[cfg(feature = "firmware-logs")]
166 self.log_init().await; 206 self.log_init().await;
167 207
168 debug!("wifi init done"); 208 #[cfg(feature = "bluetooth")]
209 if let Some(bt_fw) = bt_fw {
210 self.bt.as_mut().unwrap().init_bluetooth(&mut self.bus, bt_fw).await;
211 }
212
213 debug!("cyw43 runner init done");
169 } 214 }
170 215
171 #[cfg(feature = "firmware-logs")] 216 #[cfg(feature = "firmware-logs")]
@@ -222,7 +267,7 @@ where
222 } 267 }
223 } 268 }
224 269
225 /// Run the 270 /// Run the CYW43 event handling loop.
226 pub async fn run(mut self) -> ! { 271 pub async fn run(mut self) -> ! {
227 let mut buf = [0; 512]; 272 let mut buf = [0; 512];
228 loop { 273 loop {
@@ -231,11 +276,27 @@ where
231 276
232 if self.has_credit() { 277 if self.has_credit() {
233 let ioctl = self.ioctl_state.wait_pending(); 278 let ioctl = self.ioctl_state.wait_pending();
234 let tx = self.ch.tx_buf(); 279 let wifi_tx = self.ch.tx_buf();
280 #[cfg(feature = "bluetooth")]
281 let bt_tx = async {
282 match &mut self.bt {
283 Some(bt) => bt.tx_chan.receive().await,
284 None => core::future::pending().await,
285 }
286 };
287 #[cfg(not(feature = "bluetooth"))]
288 let bt_tx = core::future::pending::<()>();
289
290 // interrupts aren't working yet for bluetooth. Do busy-polling instead.
291 // Note for this to work `ev` has to go last in the `select()`. It prefers
292 // first futures if they're ready, so other select branches don't get starved.`
293 #[cfg(feature = "bluetooth")]
294 let ev = core::future::ready(());
295 #[cfg(not(feature = "bluetooth"))]
235 let ev = self.bus.wait_for_event(); 296 let ev = self.bus.wait_for_event();
236 297
237 match select3(ioctl, tx, ev).await { 298 match select4(ioctl, wifi_tx, bt_tx, ev).await {
238 Either3::First(PendingIoctl { 299 Either4::First(PendingIoctl {
239 buf: iobuf, 300 buf: iobuf,
240 kind, 301 kind,
241 cmd, 302 cmd,
@@ -244,7 +305,7 @@ where
244 self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }, &mut buf).await; 305 self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }, &mut buf).await;
245 self.check_status(&mut buf).await; 306 self.check_status(&mut buf).await;
246 } 307 }
247 Either3::Second(packet) => { 308 Either4::Second(packet) => {
248 trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); 309 trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)]));
249 310
250 let buf8 = slice8_mut(&mut buf); 311 let buf8 = slice8_mut(&mut buf);
@@ -298,8 +359,19 @@ where
298 self.ch.tx_done(); 359 self.ch.tx_done();
299 self.check_status(&mut buf).await; 360 self.check_status(&mut buf).await;
300 } 361 }
301 Either3::Third(()) => { 362 Either4::Third(_) => {
363 #[cfg(feature = "bluetooth")]
364 self.bt.as_mut().unwrap().hci_write(&mut self.bus).await;
365 }
366 Either4::Fourth(()) => {
302 self.handle_irq(&mut buf).await; 367 self.handle_irq(&mut buf).await;
368
369 // If we do busy-polling, make sure to yield.
370 // `handle_irq` will only do a 32bit read if there's no work to do, which is really fast.
371 // Depending on optimization level, it is possible that the 32-bit read finishes on
372 // first poll, so it never yields and we starve all other tasks.
373 #[cfg(feature = "bluetooth")]
374 embassy_futures::yield_now().await;
303 } 375 }
304 } 376 }
305 } else { 377 } else {
@@ -314,17 +386,24 @@ where
314 async fn handle_irq(&mut self, buf: &mut [u32; 512]) { 386 async fn handle_irq(&mut self, buf: &mut [u32; 512]) {
315 // Receive stuff 387 // Receive stuff
316 let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await; 388 let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await;
317 trace!("irq{}", FormatInterrupt(irq)); 389 if irq != 0 {
390 trace!("irq{}", FormatInterrupt(irq));
391 }
318 392
319 if irq & IRQ_F2_PACKET_AVAILABLE != 0 { 393 if irq & IRQ_F2_PACKET_AVAILABLE != 0 {
320 self.check_status(buf).await; 394 self.check_status(buf).await;
321 } 395 }
322 396
323 if irq & IRQ_DATA_UNAVAILABLE != 0 { 397 if irq & IRQ_DATA_UNAVAILABLE != 0 {
324 // TODO what should we do here? 398 // this seems to be ignorable with no ill effects.
325 warn!("IRQ DATA_UNAVAILABLE, clearing..."); 399 trace!("IRQ DATA_UNAVAILABLE, clearing...");
326 self.bus.write16(FUNC_BUS, REG_BUS_INTERRUPT, 1).await; 400 self.bus.write16(FUNC_BUS, REG_BUS_INTERRUPT, 1).await;
327 } 401 }
402
403 #[cfg(feature = "bluetooth")]
404 if let Some(bt) = &mut self.bt {
405 bt.handle_irq(&mut self.bus).await;
406 }
328 } 407 }
329 408
330 /// Handle F2 events while status register is set 409 /// Handle F2 events while status register is set
@@ -481,7 +560,7 @@ where
481 self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0 560 self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0
482 } 561 }
483 562
484 async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8], buf: &mut [u32; 512]) { 563 async fn send_ioctl(&mut self, kind: IoctlType, cmd: Ioctl, iface: u32, data: &[u8], buf: &mut [u32; 512]) {
485 let buf8 = slice8_mut(buf); 564 let buf8 = slice8_mut(buf);
486 565
487 let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len(); 566 let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len();
@@ -503,7 +582,7 @@ where
503 }; 582 };
504 583
505 let cdc_header = CdcHeader { 584 let cdc_header = CdcHeader {
506 cmd: cmd, 585 cmd: cmd as u32,
507 len: data.len() as _, 586 len: data.len() as _,
508 flags: kind as u16 | (iface as u16) << 12, 587 flags: kind as u16 | (iface as u16) << 12,
509 id: self.ioctl_id, 588 id: self.ioctl_id,
diff --git a/cyw43/src/structs.rs b/cyw43/src/structs.rs
index ae7ef6038..81ae6a98d 100644
--- a/cyw43/src/structs.rs
+++ b/cyw43/src/structs.rs
@@ -397,6 +397,15 @@ impl_bytes!(PassphraseInfo);
397#[derive(Clone, Copy)] 397#[derive(Clone, Copy)]
398#[cfg_attr(feature = "defmt", derive(defmt::Format))] 398#[cfg_attr(feature = "defmt", derive(defmt::Format))]
399#[repr(C)] 399#[repr(C)]
400pub struct SaePassphraseInfo {
401 pub len: u16,
402 pub passphrase: [u8; 128],
403}
404impl_bytes!(SaePassphraseInfo);
405
406#[derive(Clone, Copy)]
407#[cfg_attr(feature = "defmt", derive(defmt::Format))]
408#[repr(C)]
400pub struct SsidInfoWithIndex { 409pub struct SsidInfoWithIndex {
401 pub index: u32, 410 pub index: u32,
402 pub ssid_info: SsidInfo, 411 pub ssid_info: SsidInfo,
diff --git a/cyw43/src/util.rs b/cyw43/src/util.rs
new file mode 100644
index 000000000..a4adbd4ed
--- /dev/null
+++ b/cyw43/src/util.rs
@@ -0,0 +1,20 @@
1#![allow(unused)]
2
3use core::slice;
4
5pub(crate) fn slice8_mut(x: &mut [u32]) -> &mut [u8] {
6 let len = x.len() * 4;
7 unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) }
8}
9
10pub(crate) fn is_aligned(a: u32, x: u32) -> bool {
11 (a & (x - 1)) == 0
12}
13
14pub(crate) fn round_down(x: u32, a: u32) -> u32 {
15 x & !(a - 1)
16}
17
18pub(crate) fn round_up(x: u32, a: u32) -> u32 {
19 ((x + a - 1) / a) * a
20}
diff --git a/docs/examples/basic/Cargo.toml b/docs/examples/basic/Cargo.toml
index e82165032..5d391adf3 100644
--- a/docs/examples/basic/Cargo.toml
+++ b/docs/examples/basic/Cargo.toml
@@ -6,9 +6,9 @@ version = "0.1.0"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7 7
8[dependencies] 8[dependencies]
9embassy-executor = { version = "0.5.0", path = "../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.6.0", path = "../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.1", path = "../../../embassy-time", features = ["defmt"] } 10embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt"] }
11embassy-nrf = { version = "0.1.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } 11embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] }
12 12
13defmt = "0.3" 13defmt = "0.3"
14defmt-rtt = "0.3" 14defmt-rtt = "0.3"
diff --git a/docs/examples/layer-by-layer/blinky-async/Cargo.toml b/docs/examples/layer-by-layer/blinky-async/Cargo.toml
index 64f7e8403..7f8d8af3e 100644
--- a/docs/examples/layer-by-layer/blinky-async/Cargo.toml
+++ b/docs/examples/layer-by-layer/blinky-async/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8cortex-m = "0.7" 8cortex-m = "0.7"
9cortex-m-rt = "0.7" 9cortex-m-rt = "0.7"
10embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"] } 10embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"] }
11embassy-executor = { version = "0.5.0", features = ["arch-cortex-m", "executor-thread"] } 11embassy-executor = { version = "0.6.0", features = ["arch-cortex-m", "executor-thread"] }
12 12
13defmt = "0.3.0" 13defmt = "0.3.0"
14defmt-rtt = "0.3.0" 14defmt-rtt = "0.3.0"
diff --git a/docs/pages/basic_application.adoc b/docs/pages/basic_application.adoc
index 7b4ebda4f..5c4e3e8b3 100644
--- a/docs/pages/basic_application.adoc
+++ b/docs/pages/basic_application.adoc
@@ -4,7 +4,7 @@ So you've got one of the examples running, but what now? Let's go through a simp
4 4
5== Main 5== Main
6 6
7The full example can be found link:https://github.com/embassy-rs/embassy/tree/master/docs/examples/basic[here]. 7The full example can be found link:https://github.com/embassy-rs/embassy/tree/main/docs/examples/basic[here].
8 8
9NOTE: If you’re using VS Code and rust-analyzer to view and edit the examples, you may need to make some changes to `.vscode/settings.json` to tell it which project we’re working on. Follow the instructions commented in that file to get rust-analyzer working correctly. 9NOTE: If you’re using VS Code and rust-analyzer to view and edit the examples, you may need to make some changes to `.vscode/settings.json` to tell it which project we’re working on. Follow the instructions commented in that file to get rust-analyzer working correctly.
10 10
diff --git a/docs/pages/embassy_in_the_wild.adoc b/docs/pages/embassy_in_the_wild.adoc
index 76b1169bd..bb457a869 100644
--- a/docs/pages/embassy_in_the_wild.adoc
+++ b/docs/pages/embassy_in_the_wild.adoc
@@ -2,6 +2,8 @@
2 2
3Here are known examples of real-world projects which make use of Embassy. Feel free to link:https://github.com/embassy-rs/embassy/blob/main/docs/pages/embassy_in_the_wild.adoc[add more]! 3Here are known examples of real-world projects which make use of Embassy. Feel free to link:https://github.com/embassy-rs/embassy/blob/main/docs/pages/embassy_in_the_wild.adoc[add more]!
4 4
5* link:https://github.com/1-rafael-1/pi-pico-alarmclock-rust[A Raspberry Pi Pico W Alarmclock]
6** A hobbyist project building an alarm clock around a Pi Pico W complete with code, components list and enclosure design files.
5* link:https://github.com/haobogu/rmk/[RMK: A feature-rich Rust keyboard firmware] 7* link:https://github.com/haobogu/rmk/[RMK: A feature-rich Rust keyboard firmware]
6** RMK has built-in layer support, wireless(BLE) support, real-time key editing support using vial, and more! 8** RMK has built-in layer support, wireless(BLE) support, real-time key editing support using vial, and more!
7** Targets STM32, RP2040, nRF52 and ESP32 MCUs 9** Targets STM32, RP2040, nRF52 and ESP32 MCUs
diff --git a/docs/pages/faq.adoc b/docs/pages/faq.adoc
index a2f56a539..8eb947b5e 100644
--- a/docs/pages/faq.adoc
+++ b/docs/pages/faq.adoc
@@ -352,8 +352,23 @@ There are two main ways to handle concurrency in Embassy:
352 352
353In general, either of these approaches will work. The main differences of these approaches are: 353In general, either of these approaches will work. The main differences of these approaches are:
354 354
355When using **separate tasks**, each task needs its own RAM allocation, so there's a little overhead for each task, so one task that does three things will likely be a little bit smaller than three tasks that do one thing (not a lot, probably a couple dozen bytes). In contrast, with **multiple futures in one task**, you don't need multiple task allocations, and it will generally be easier to share data, or use borrowed resources, inside of a single task. 355When using **separate tasks**, each task needs its own RAM allocation, so there's a little overhead for each task, so one task that does three things will likely be a little bit smaller than three tasks that do one thing (not a lot, probably a couple dozen bytes). In contrast, with **multiple futures in one task**, you don't need multiple task allocations, and it will generally be easier to share data, or use borrowed resources, inside of a single task.
356An example showcasing some methods for sharing things between tasks link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/sharing.rs[can be found here].
356 357
357But when it comes to "waking" tasks, for example when a data transfer is complete or a button is pressed, it's faster to wake a dedicated task, because that task does not need to check which future is actually ready. `join` and `select` must check ALL of the futures they are managing to see which one (or which ones) are ready to do more work. This is because all Rust executors (like Embassy or Tokio) only have the ability to wake tasks, not specific futures. This means you will use slightly less CPU time juggling futures when using dedicated tasks. 358But when it comes to "waking" tasks, for example when a data transfer is complete or a button is pressed, it's faster to wake a dedicated task, because that task does not need to check which future is actually ready. `join` and `select` must check ALL of the futures they are managing to see which one (or which ones) are ready to do more work. This is because all Rust executors (like Embassy or Tokio) only have the ability to wake tasks, not specific futures. This means you will use slightly less CPU time juggling futures when using dedicated tasks.
358 359
359Practically, there's not a LOT of difference either way - so go with what makes it easier for you and your code first, but there will be some details that are slightly different in each case. 360Practically, there's not a LOT of difference either way - so go with what makes it easier for you and your code first, but there will be some details that are slightly different in each case.
361
362== splitting peripherals resources between tasks
363
364There are two ways to split resources between tasks, either manually assigned or by a convenient macro. See link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/assign_resources.rs[this example]
365
366== My code/driver works in debug mode, but not release mode (or with LTO)
367
368Issues like these while implementing drivers often fall into one of the following general causes, which are a good list of common errors to check for:
369
3701. Some kind of race condition - the faster code means you miss an interrupt or something
3712. Some kind of UB, if you have unsafe code, or something like DMA with fences missing
3723. Some kind of hardware errata, or some hardware misconfiguration like wrong clock speeds
3734. Some issue with an interrupt handler, either enabling, disabling, or re-enabling of interrupts when necessary
3745. Some kind of async issue, like not registering wakers fully before checking flags, or not registering or pending wakers at the right time
diff --git a/docs/pages/new_project.adoc b/docs/pages/new_project.adoc
index 346d9f0f8..821bcbd27 100644
--- a/docs/pages/new_project.adoc
+++ b/docs/pages/new_project.adoc
@@ -1,6 +1,6 @@
1= Starting a new project 1= Starting a new project
2 2
3Once you’ve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project. 3Once you’ve successfully xref:#_getting_started[run some example projects], the next step is to make a standalone Embassy project.
4 4
5== Tools for generating Embassy projects 5== Tools for generating Embassy projects
6 6
diff --git a/docs/pages/nrf.adoc b/docs/pages/nrf.adoc
index 1706087ae..de052b63f 100644
--- a/docs/pages/nrf.adoc
+++ b/docs/pages/nrf.adoc
@@ -1,6 +1,6 @@
1= Embassy nRF HAL 1= Embassy nRF HAL
2 2
3The link:https://github.com/embassy-rs/embassy/tree/master/embassy-nrf[Embassy nRF HAL] is based on the PACs (Peripheral Access Crate) from link:https://github.com/nrf-rs/[nrf-rs]. 3The link:https://github.com/embassy-rs/embassy/tree/main/embassy-nrf[Embassy nRF HAL] is based on the PACs (Peripheral Access Crate) from link:https://github.com/nrf-rs/[nrf-rs].
4 4
5== Timer driver 5== Timer driver
6 6
diff --git a/docs/pages/overview.adoc b/docs/pages/overview.adoc
index 1b9381bfe..2ebc85f6d 100644
--- a/docs/pages/overview.adoc
+++ b/docs/pages/overview.adoc
@@ -48,7 +48,7 @@ link:https://github.com/lora-rs/lora-rs[lora-rs] supports LoRa networking on a w
48link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own. 48link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
49 49
50=== Bootloader and DFU 50=== Bootloader and DFU
51link:https://github.com/embassy-rs/embassy/tree/master/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks. 51link:https://github.com/embassy-rs/embassy/tree/main/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
52 52
53== What is DMA? 53== What is DMA?
54 54
@@ -77,3 +77,7 @@ For more reading material on async Rust and Embassy:
77* link:https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown[Comparsion of FreeRTOS and Embassy] 77* link:https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown[Comparsion of FreeRTOS and Embassy]
78* link:https://dev.to/apollolabsbin/series/20707[Tutorials] 78* link:https://dev.to/apollolabsbin/series/20707[Tutorials]
79* link:https://blog.drogue.io/firmware-updates-part-1/[Firmware Updates with Embassy] 79* link:https://blog.drogue.io/firmware-updates-part-1/[Firmware Updates with Embassy]
80
81Videos:
82
83* link:https://www.youtube.com/watch?v=wni5h5vIPhU[From Zero to Async in Embedded Rust] \ No newline at end of file
diff --git a/docs/pages/sharing_peripherals.adoc b/docs/pages/sharing_peripherals.adoc
index 6bcd56b01..dfb8c1ffe 100644
--- a/docs/pages/sharing_peripherals.adoc
+++ b/docs/pages/sharing_peripherals.adoc
@@ -8,7 +8,7 @@ The following examples shows different ways to use the on-board LED on a Raspber
8 8
9Using mutual exclusion is the simplest way to share a peripheral. 9Using mutual exclusion is the simplest way to share a peripheral.
10 10
11TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here]. 11TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here].
12[,rust] 12[,rust]
13---- 13----
14use defmt::*; 14use defmt::*;
@@ -78,7 +78,7 @@ To indicate that the pin will be set to an Output. The `AnyPin` could have been
78 78
79A channel is another way to ensure exclusive access to a resource. Using a channel is great in the cases where the access can happen at a later point in time, allowing you to enqueue operations and do other things. 79A channel is another way to ensure exclusive access to a resource. Using a channel is great in the cases where the access can happen at a later point in time, allowing you to enqueue operations and do other things.
80 80
81TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here]. 81TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here].
82[,rust] 82[,rust]
83---- 83----
84use defmt::*; 84use defmt::*;
@@ -126,3 +126,9 @@ async fn toggle_led(control: Sender<'static, ThreadModeRawMutex, LedState, 64>,
126 126
127This example replaces the Mutex with a Channel, and uses another task (the main loop) to drive the LED. The advantage of this approach is that only a single task references the peripheral, separating concerns. However, using a Mutex has a lower overhead and might be necessary if you need to ensure 127This example replaces the Mutex with a Channel, and uses another task (the main loop) to drive the LED. The advantage of this approach is that only a single task references the peripheral, separating concerns. However, using a Mutex has a lower overhead and might be necessary if you need to ensure
128that the operation is completed before continuing to do other work in your task. 128that the operation is completed before continuing to do other work in your task.
129
130An example showcasing more methods for sharing link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/sharing.rs[can be found here].
131
132== Sharing an I2C or SPI bus between multiple devices
133
134An example of how to deal with multiple devices sharing a common I2C or SPI bus link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/shared_bus.rs[can be found here].
diff --git a/docs/pages/stm32.adoc b/docs/pages/stm32.adoc
index 7bfc0592b..df139a420 100644
--- a/docs/pages/stm32.adoc
+++ b/docs/pages/stm32.adoc
@@ -1,6 +1,6 @@
1= Embassy STM32 HAL 1= Embassy STM32 HAL
2 2
3The link:https://github.com/embassy-rs/embassy/tree/master/embassy-stm32[Embassy STM32 HAL] is based on the `stm32-metapac` project. 3The link:https://github.com/embassy-rs/embassy/tree/main/embassy-stm32[Embassy STM32 HAL] is based on the `stm32-metapac` project.
4 4
5== The infinite variant problem 5== The infinite variant problem
6 6
diff --git a/docs/pages/time_keeping.adoc b/docs/pages/time_keeping.adoc
index 17492a884..11ddb2b2b 100644
--- a/docs/pages/time_keeping.adoc
+++ b/docs/pages/time_keeping.adoc
@@ -16,7 +16,7 @@ The `embassy::time::Timer` type provides two timing methods.
16 16
17An example of a delay is provided as follows: 17An example of a delay is provided as follows:
18 18
19TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here]. 19TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here].
20[,rust] 20[,rust]
21---- 21----
22use embassy::executor::{task, Executor}; 22use embassy::executor::{task, Executor};
@@ -41,7 +41,7 @@ that expect a generic delay implementation to be provided.
41 41
42An example of how this can be used: 42An example of how this can be used:
43 43
44TIP: Dependencies needed to run this example link:/book/dev/basic_application.html#_the_cargo_toml[can be found here]. 44TIP: Dependencies needed to run this example link:#_the_cargo_toml[can be found here].
45[,rust] 45[,rust]
46---- 46----
47use embassy::executor::{task, Executor}; 47use embassy::executor::{task, Executor};
diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml
index 86bfc21f4..27407ae92 100644
--- a/embassy-boot-nrf/Cargo.toml
+++ b/embassy-boot-nrf/Cargo.toml
@@ -1,7 +1,7 @@
1[package] 1[package]
2edition = "2021" 2edition = "2021"
3name = "embassy-boot-nrf" 3name = "embassy-boot-nrf"
4version = "0.2.0" 4version = "0.3.0"
5description = "Bootloader lib for nRF chips" 5description = "Bootloader lib for nRF chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7repository = "https://github.com/embassy-rs/embassy" 7repository = "https://github.com/embassy-rs/embassy"
@@ -25,8 +25,8 @@ defmt = { version = "0.3", optional = true }
25log = { version = "0.4.17", optional = true } 25log = { version = "0.4.17", optional = true }
26 26
27embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 27embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
28embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", default-features = false } 28embassy-nrf = { version = "0.2.0", path = "../embassy-nrf", default-features = false }
29embassy-boot = { version = "0.2.0", path = "../embassy-boot" } 29embassy-boot = { version = "0.3.0", path = "../embassy-boot" }
30cortex-m = { version = "0.7.6" } 30cortex-m = { version = "0.7.6" }
31cortex-m-rt = { version = "0.7" } 31cortex-m-rt = { version = "0.7" }
32embedded-storage = "0.3.1" 32embedded-storage = "0.3.1"
diff --git a/embassy-boot-nrf/src/fmt.rs b/embassy-boot-nrf/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-boot-nrf/src/fmt.rs
+++ b/embassy-boot-nrf/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml
index 23a8bb549..bf5f34abe 100644
--- a/embassy-boot-rp/Cargo.toml
+++ b/embassy-boot-rp/Cargo.toml
@@ -1,7 +1,7 @@
1[package] 1[package]
2edition = "2021" 2edition = "2021"
3name = "embassy-boot-rp" 3name = "embassy-boot-rp"
4version = "0.2.0" 4version = "0.3.0"
5description = "Bootloader lib for RP2040 chips" 5description = "Bootloader lib for RP2040 chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7repository = "https://github.com/embassy-rs/embassy" 7repository = "https://github.com/embassy-rs/embassy"
@@ -16,6 +16,7 @@ categories = [
16src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-rp-v$VERSION/src/" 16src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-rp-v$VERSION/src/"
17src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot-rp/src/" 17src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-boot-rp/src/"
18target = "thumbv6m-none-eabi" 18target = "thumbv6m-none-eabi"
19features = ["embassy-rp/rp2040"]
19 20
20[lib] 21[lib]
21 22
@@ -24,9 +25,9 @@ defmt = { version = "0.3", optional = true }
24log = { version = "0.4", optional = true } 25log = { version = "0.4", optional = true }
25 26
26embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 27embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
27embassy-rp = { version = "0.1.0", path = "../embassy-rp", default-features = false } 28embassy-rp = { version = "0.2.0", path = "../embassy-rp", default-features = false }
28embassy-boot = { version = "0.2.0", path = "../embassy-boot" } 29embassy-boot = { version = "0.3.0", path = "../embassy-boot" }
29embassy-time = { version = "0.3.1", path = "../embassy-time" } 30embassy-time = { version = "0.3.2", path = "../embassy-time" }
30 31
31cortex-m = { version = "0.7.6" } 32cortex-m = { version = "0.7.6" }
32cortex-m-rt = { version = "0.7" } 33cortex-m-rt = { version = "0.7" }
diff --git a/embassy-boot-rp/src/fmt.rs b/embassy-boot-rp/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-boot-rp/src/fmt.rs
+++ b/embassy-boot-rp/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-boot-stm32/Cargo.toml b/embassy-boot-stm32/Cargo.toml
index 52ad1b463..e4ef9a612 100644
--- a/embassy-boot-stm32/Cargo.toml
+++ b/embassy-boot-stm32/Cargo.toml
@@ -26,7 +26,7 @@ log = { version = "0.4", optional = true }
26 26
27embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 27embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
28embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false } 28embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false }
29embassy-boot = { version = "0.2.0", path = "../embassy-boot" } 29embassy-boot = { version = "0.3.0", path = "../embassy-boot" }
30cortex-m = { version = "0.7.6" } 30cortex-m = { version = "0.7.6" }
31cortex-m-rt = { version = "0.7" } 31cortex-m-rt = { version = "0.7" }
32embedded-storage = "0.3.1" 32embedded-storage = "0.3.1"
diff --git a/embassy-boot-stm32/src/fmt.rs b/embassy-boot-stm32/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-boot-stm32/src/fmt.rs
+++ b/embassy-boot-stm32/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml
index 16dc52bcc..d27fe763e 100644
--- a/embassy-boot/Cargo.toml
+++ b/embassy-boot/Cargo.toml
@@ -1,7 +1,7 @@
1[package] 1[package]
2edition = "2021" 2edition = "2021"
3name = "embassy-boot" 3name = "embassy-boot"
4version = "0.2.0" 4version = "0.3.0"
5description = "A lightweight bootloader supporting firmware updates in a power-fail-safe way, with trial boots and rollbacks." 5description = "A lightweight bootloader supporting firmware updates in a power-fail-safe way, with trial boots and rollbacks."
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7repository = "https://github.com/embassy-rs/embassy" 7repository = "https://github.com/embassy-rs/embassy"
@@ -27,8 +27,8 @@ features = ["defmt"]
27defmt = { version = "0.3", optional = true } 27defmt = { version = "0.3", optional = true }
28digest = "0.10" 28digest = "0.10"
29log = { version = "0.4", optional = true } 29log = { version = "0.4", optional = true }
30ed25519-dalek = { version = "2", default_features = false, features = ["digest"], optional = true } 30ed25519-dalek = { version = "2", default-features = false, features = ["digest"], optional = true }
31embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } 31embassy-embedded-hal = { version = "0.2.0", path = "../embassy-embedded-hal" }
32embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 32embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
33embedded-storage = "0.3.1" 33embedded-storage = "0.3.1"
34embedded-storage-async = { version = "0.4.1" } 34embedded-storage-async = { version = "0.4.1" }
@@ -42,7 +42,7 @@ rand = "0.8"
42futures = { version = "0.3", features = ["executor"] } 42futures = { version = "0.3", features = ["executor"] }
43sha1 = "0.10.5" 43sha1 = "0.10.5"
44critical-section = { version = "1.1.1", features = ["std"] } 44critical-section = { version = "1.1.1", features = ["std"] }
45ed25519-dalek = { version = "2", default_features = false, features = ["std", "rand_core", "digest"] } 45ed25519-dalek = { version = "2", default-features = false, features = ["std", "rand_core", "digest"] }
46 46
47[features] 47[features]
48ed25519-dalek = ["dep:ed25519-dalek", "_verify"] 48ed25519-dalek = ["dep:ed25519-dalek", "_verify"]
diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs
index 789fa34c1..61d61b96e 100644
--- a/embassy-boot/src/boot_loader.rs
+++ b/embassy-boot/src/boot_loader.rs
@@ -236,10 +236,10 @@ impl<ACTIVE: NorFlash, DFU: NorFlash, STATE: NorFlash> BootLoader<ACTIVE, DFU, S
236 /// 236 ///
237 pub fn prepare_boot(&mut self, aligned_buf: &mut [u8]) -> Result<State, BootError> { 237 pub fn prepare_boot(&mut self, aligned_buf: &mut [u8]) -> Result<State, BootError> {
238 const { 238 const {
239 assert!(Self::PAGE_SIZE % ACTIVE::WRITE_SIZE as u32 == 0); 239 core::assert!(Self::PAGE_SIZE % ACTIVE::WRITE_SIZE as u32 == 0);
240 assert!(Self::PAGE_SIZE % ACTIVE::ERASE_SIZE as u32 == 0); 240 core::assert!(Self::PAGE_SIZE % ACTIVE::ERASE_SIZE as u32 == 0);
241 assert!(Self::PAGE_SIZE % DFU::WRITE_SIZE as u32 == 0); 241 core::assert!(Self::PAGE_SIZE % DFU::WRITE_SIZE as u32 == 0);
242 assert!(Self::PAGE_SIZE % DFU::ERASE_SIZE as u32 == 0); 242 core::assert!(Self::PAGE_SIZE % DFU::ERASE_SIZE as u32 == 0);
243 } 243 }
244 244
245 // Ensure we have enough progress pages to store copy progress 245 // Ensure we have enough progress pages to store copy progress
diff --git a/embassy-boot/src/fmt.rs b/embassy-boot/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-boot/src/fmt.rs
+++ b/embassy-boot/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-embedded-hal/CHANGELOG.md b/embassy-embedded-hal/CHANGELOG.md
new file mode 100644
index 000000000..f8e272160
--- /dev/null
+++ b/embassy-embedded-hal/CHANGELOG.md
@@ -0,0 +1,21 @@
1# Changelog for embassy-embedded-hal
2
3All notable changes to this project will be documented in this file.
4
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
8## Unreleased
9
10## 0.2.0 - 2024-08-05
11
12- Add Clone derive to flash Partition in embassy-embedded-hal
13- Add support for all word sizes to async shared spi
14- Add Copy and 'static constraint to Word type in SPI structs
15- Improve flexibility by introducing SPI word size as a generic parameter
16- Allow changing Spi/I2cDeviceWithConfig's config at runtime
17- Impl `MultiwriteNorFlash` for `BlockingAsync`
18
19## 0.1.0 - 2024-01-10
20
21- First release
diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml
index 905439fe7..345dc3420 100644
--- a/embassy-embedded-hal/Cargo.toml
+++ b/embassy-embedded-hal/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-embedded-hal" 2name = "embassy-embedded-hal"
3version = "0.1.0" 3version = "0.2.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "Collection of utilities to use `embedded-hal` and `embedded-storage` traits with Embassy." 6description = "Collection of utilities to use `embedded-hal` and `embedded-storage` traits with Embassy."
@@ -29,7 +29,7 @@ default = ["time"]
29[dependencies] 29[dependencies]
30embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 30embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
31embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 31embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
32embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true } 32embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true }
33embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ 33embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
34 "unproven", 34 "unproven",
35] } 35] }
diff --git a/embassy-embedded-hal/src/flash/partition/asynch.rs b/embassy-embedded-hal/src/flash/partition/asynch.rs
index 5920436dd..1b0c91232 100644
--- a/embassy-embedded-hal/src/flash/partition/asynch.rs
+++ b/embassy-embedded-hal/src/flash/partition/asynch.rs
@@ -18,6 +18,16 @@ pub struct Partition<'a, M: RawMutex, T: NorFlash> {
18 size: u32, 18 size: u32,
19} 19}
20 20
21impl<'a, M: RawMutex, T: NorFlash> Clone for Partition<'a, M, T> {
22 fn clone(&self) -> Self {
23 Self {
24 flash: self.flash,
25 offset: self.offset,
26 size: self.size,
27 }
28 }
29}
30
21impl<'a, M: RawMutex, T: NorFlash> Partition<'a, M, T> { 31impl<'a, M: RawMutex, T: NorFlash> Partition<'a, M, T> {
22 /// Create a new partition 32 /// Create a new partition
23 pub const fn new(flash: &'a Mutex<M, T>, offset: u32, size: u32) -> Self { 33 pub const fn new(flash: &'a Mutex<M, T>, offset: u32, size: u32) -> Self {
diff --git a/embassy-embedded-hal/src/flash/partition/blocking.rs b/embassy-embedded-hal/src/flash/partition/blocking.rs
index 2ddbe3de0..a68df7812 100644
--- a/embassy-embedded-hal/src/flash/partition/blocking.rs
+++ b/embassy-embedded-hal/src/flash/partition/blocking.rs
@@ -19,6 +19,16 @@ pub struct BlockingPartition<'a, M: RawMutex, T: NorFlash> {
19 size: u32, 19 size: u32,
20} 20}
21 21
22impl<'a, M: RawMutex, T: NorFlash> Clone for BlockingPartition<'a, M, T> {
23 fn clone(&self) -> Self {
24 Self {
25 flash: self.flash,
26 offset: self.offset,
27 size: self.size,
28 }
29 }
30}
31
22impl<'a, M: RawMutex, T: NorFlash> BlockingPartition<'a, M, T> { 32impl<'a, M: RawMutex, T: NorFlash> BlockingPartition<'a, M, T> {
23 /// Create a new partition 33 /// Create a new partition
24 pub const fn new(flash: &'a Mutex<M, RefCell<T>>, offset: u32, size: u32) -> Self { 34 pub const fn new(flash: &'a Mutex<M, RefCell<T>>, offset: u32, size: u32) -> Self {
diff --git a/embassy-executor-macros/Cargo.toml b/embassy-executor-macros/Cargo.toml
index 2953e7ccc..218e820ce 100644
--- a/embassy-executor-macros/Cargo.toml
+++ b/embassy-executor-macros/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-executor-macros" 2name = "embassy-executor-macros"
3version = "0.4.1" 3version = "0.5.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "macros for creating the entry point and tasks for embassy-executor" 6description = "macros for creating the entry point and tasks for embassy-executor"
diff --git a/embassy-executor-macros/src/macros/main.rs b/embassy-executor-macros/src/macros/main.rs
index 088e64d1c..26dfa2397 100644
--- a/embassy-executor-macros/src/macros/main.rs
+++ b/embassy-executor-macros/src/macros/main.rs
@@ -70,7 +70,7 @@ pub fn wasm() -> TokenStream {
70 let executor = ::std::boxed::Box::leak(::std::boxed::Box::new(::embassy_executor::Executor::new())); 70 let executor = ::std::boxed::Box::leak(::std::boxed::Box::new(::embassy_executor::Executor::new()));
71 71
72 executor.start(|spawner| { 72 executor.start(|spawner| {
73 spawner.spawn(__embassy_main(spawner)).unwrap(); 73 spawner.must_spawn(__embassy_main(spawner));
74 }); 74 });
75 75
76 Ok(()) 76 Ok(())
diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md
index 77c64fd8e..5582b56ec 100644
--- a/embassy-executor/CHANGELOG.md
+++ b/embassy-executor/CHANGELOG.md
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased 8## Unreleased
9 9
10## 0.6.0 - 2024-08-05
11
12- Add collapse_debuginfo to fmt.rs macros.
13- initial support for avr
14- use nightly waker_getters APIs
15
10## 0.5.0 - 2024-01-11 16## 0.5.0 - 2024-01-11
11 17
12- Updated to `embassy-time-driver 0.1`, `embassy-time-queue-driver 0.1`, compatible with `embassy-time v0.3` and higher. 18- Updated to `embassy-time-driver 0.1`, `embassy-time-queue-driver 0.1`, compatible with `embassy-time v0.3` and higher.
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index 431165cee..01fa28b88 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-executor" 2name = "embassy-executor"
3version = "0.5.0" 3version = "0.6.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "async/await executor designed for embedded usage" 6description = "async/await executor designed for embedded usage"
@@ -33,7 +33,7 @@ defmt = { version = "0.3", optional = true }
33log = { version = "0.4.14", optional = true } 33log = { version = "0.4.14", optional = true }
34rtos-trace = { version = "0.1.2", optional = true } 34rtos-trace = { version = "0.1.2", optional = true }
35 35
36embassy-executor-macros = { version = "0.4.0", path = "../embassy-executor-macros" } 36embassy-executor-macros = { version = "0.5.0", path = "../embassy-executor-macros" }
37embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true } 37embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true }
38embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true } 38embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true }
39critical-section = "1.1" 39critical-section = "1.1"
@@ -79,7 +79,7 @@ arch-cortex-m = ["_arch", "dep:cortex-m"]
79## RISC-V 32 79## RISC-V 32
80arch-riscv32 = ["_arch"] 80arch-riscv32 = ["_arch"]
81## WASM 81## WASM
82arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"] 82arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys", "critical-section/std"]
83## AVR 83## AVR
84arch-avr = ["_arch", "dep:portable-atomic", "dep:avr-device"] 84arch-avr = ["_arch", "dep:portable-atomic", "dep:avr-device"]
85 85
diff --git a/embassy-executor/build_common.rs b/embassy-executor/build_common.rs
index 0487eb3c5..4f24e6d37 100644
--- a/embassy-executor/build_common.rs
+++ b/embassy-executor/build_common.rs
@@ -8,8 +8,6 @@
8 8
9use std::collections::HashSet; 9use std::collections::HashSet;
10use std::env; 10use std::env;
11use std::ffi::OsString;
12use std::process::Command;
13 11
14/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring 12/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
15/// them (`cargo:rust-check-cfg=cfg(X)`). 13/// them (`cargo:rust-check-cfg=cfg(X)`).
@@ -17,7 +15,6 @@ use std::process::Command;
17pub struct CfgSet { 15pub struct CfgSet {
18 enabled: HashSet<String>, 16 enabled: HashSet<String>,
19 declared: HashSet<String>, 17 declared: HashSet<String>,
20 emit_declared: bool,
21} 18}
22 19
23impl CfgSet { 20impl CfgSet {
@@ -25,7 +22,6 @@ impl CfgSet {
25 Self { 22 Self {
26 enabled: HashSet::new(), 23 enabled: HashSet::new(),
27 declared: HashSet::new(), 24 declared: HashSet::new(),
28 emit_declared: is_rustc_nightly(),
29 } 25 }
30 } 26 }
31 27
@@ -49,7 +45,7 @@ impl CfgSet {
49 /// 45 ///
50 /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid. 46 /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
51 pub fn declare(&mut self, cfg: impl AsRef<str>) { 47 pub fn declare(&mut self, cfg: impl AsRef<str>) {
52 if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared { 48 if self.declared.insert(cfg.as_ref().to_owned()) {
53 println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref()); 49 println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
54 } 50 }
55 } 51 }
@@ -69,21 +65,6 @@ impl CfgSet {
69 } 65 }
70} 66}
71 67
72fn is_rustc_nightly() -> bool {
73 if env::var_os("EMBASSY_FORCE_CHECK_CFG").is_some() {
74 return true;
75 }
76
77 let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
78
79 let output = Command::new(rustc)
80 .arg("--version")
81 .output()
82 .expect("failed to run `rustc --version`");
83
84 String::from_utf8_lossy(&output.stdout).contains("nightly")
85}
86
87/// Sets configs that describe the target platform. 68/// Sets configs that describe the target platform.
88pub fn set_target_cfgs(cfgs: &mut CfgSet) { 69pub fn set_target_cfgs(cfgs: &mut CfgSet) {
89 let target = env::var("TARGET").unwrap(); 70 let target = env::var("TARGET").unwrap();
diff --git a/embassy-executor/src/fmt.rs b/embassy-executor/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-executor/src/fmt.rs
+++ b/embassy-executor/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs
index 553ed76d3..6a2e493a2 100644
--- a/embassy-executor/src/lib.rs
+++ b/embassy-executor/src/lib.rs
@@ -1,5 +1,4 @@
1#![cfg_attr(not(any(feature = "arch-std", feature = "arch-wasm")), no_std)] 1#![cfg_attr(not(any(feature = "arch-std", feature = "arch-wasm")), no_std)]
2#![cfg_attr(feature = "nightly", feature(waker_getters))]
3#![allow(clippy::new_without_default)] 2#![allow(clippy::new_without_default)]
4#![doc = include_str!("../README.md")] 3#![doc = include_str!("../README.md")]
5#![warn(missing_docs)] 4#![warn(missing_docs)]
diff --git a/embassy-executor/src/raw/waker.rs b/embassy-executor/src/raw/waker.rs
index 8d3910a25..8bb2cfd05 100644
--- a/embassy-executor/src/raw/waker.rs
+++ b/embassy-executor/src/raw/waker.rs
@@ -50,8 +50,7 @@ pub fn task_from_waker(waker: &Waker) -> TaskRef {
50 50
51 #[cfg(feature = "nightly")] 51 #[cfg(feature = "nightly")]
52 { 52 {
53 let raw_waker = waker.as_raw(); 53 (waker.vtable(), waker.data())
54 (raw_waker.vtable(), raw_waker.data())
55 } 54 }
56 }; 55 };
57 56
diff --git a/embassy-futures/src/fmt.rs b/embassy-futures/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-futures/src/fmt.rs
+++ b/embassy-futures/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-futures/src/select.rs b/embassy-futures/src/select.rs
index 97a81a86d..57f0cb41f 100644
--- a/embassy-futures/src/select.rs
+++ b/embassy-futures/src/select.rs
@@ -237,7 +237,7 @@ impl<Fut: Future, const N: usize> Future for SelectArray<Fut, N> {
237#[derive(Debug)] 237#[derive(Debug)]
238#[must_use = "futures do nothing unless you `.await` or poll them"] 238#[must_use = "futures do nothing unless you `.await` or poll them"]
239pub struct SelectSlice<'a, Fut> { 239pub struct SelectSlice<'a, Fut> {
240 inner: &'a mut [Fut], 240 inner: Pin<&'a mut [Fut]>,
241} 241}
242 242
243/// Creates a new future which will select over a slice of futures. 243/// Creates a new future which will select over a slice of futures.
@@ -247,31 +247,26 @@ pub struct SelectSlice<'a, Fut> {
247/// future that was ready. 247/// future that was ready.
248/// 248///
249/// If the slice is empty, the resulting future will be Pending forever. 249/// If the slice is empty, the resulting future will be Pending forever.
250pub fn select_slice<'a, Fut: Future>(slice: &'a mut [Fut]) -> SelectSlice<'a, Fut> { 250pub fn select_slice<'a, Fut: Future>(slice: Pin<&'a mut [Fut]>) -> SelectSlice<'a, Fut> {
251 SelectSlice { inner: slice } 251 SelectSlice { inner: slice }
252} 252}
253 253
254impl<'a, Fut: Future> Future for SelectSlice<'a, Fut> { 254impl<'a, Fut: Future> Future for SelectSlice<'a, Fut> {
255 type Output = (Fut::Output, usize); 255 type Output = (Fut::Output, usize);
256 256
257 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 257 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
258 // Safety: Since `self` is pinned, `inner` cannot move. Since `inner` cannot move, 258 // Safety: refer to
259 // its elements also cannot move. Therefore it is safe to access `inner` and pin 259 // https://users.rust-lang.org/t/working-with-pinned-slices-are-there-any-structurally-pinning-vec-like-collection-types/50634/2
260 // references to the contained futures. 260 #[inline(always)]
261 let item = unsafe { 261 fn pin_iter<T>(slice: Pin<&mut [T]>) -> impl Iterator<Item = Pin<&mut T>> {
262 self.get_unchecked_mut() 262 unsafe { slice.get_unchecked_mut().iter_mut().map(|v| Pin::new_unchecked(v)) }
263 .inner 263 }
264 .iter_mut() 264 for (i, fut) in pin_iter(self.inner.as_mut()).enumerate() {
265 .enumerate() 265 if let Poll::Ready(res) = fut.poll(cx) {
266 .find_map(|(i, f)| match Pin::new_unchecked(f).poll(cx) { 266 return Poll::Ready((res, i));
267 Poll::Pending => None, 267 }
268 Poll::Ready(e) => Some((i, e)),
269 })
270 };
271
272 match item {
273 Some((idx, res)) => Poll::Ready((res, idx)),
274 None => Poll::Pending,
275 } 268 }
269
270 Poll::Pending
276 } 271 }
277} 272}
diff --git a/embassy-hal-internal/Cargo.toml b/embassy-hal-internal/Cargo.toml
index c5013f365..d5ca95ac2 100644
--- a/embassy-hal-internal/Cargo.toml
+++ b/embassy-hal-internal/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-hal-internal" 2name = "embassy-hal-internal"
3version = "0.1.0" 3version = "0.2.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "Internal implementation details for Embassy HALs. DO NOT USE DIRECTLY." 6description = "Internal implementation details for Embassy HALs. DO NOT USE DIRECTLY."
diff --git a/embassy-hal-internal/build_common.rs b/embassy-hal-internal/build_common.rs
index 0487eb3c5..4f24e6d37 100644
--- a/embassy-hal-internal/build_common.rs
+++ b/embassy-hal-internal/build_common.rs
@@ -8,8 +8,6 @@
8 8
9use std::collections::HashSet; 9use std::collections::HashSet;
10use std::env; 10use std::env;
11use std::ffi::OsString;
12use std::process::Command;
13 11
14/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring 12/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
15/// them (`cargo:rust-check-cfg=cfg(X)`). 13/// them (`cargo:rust-check-cfg=cfg(X)`).
@@ -17,7 +15,6 @@ use std::process::Command;
17pub struct CfgSet { 15pub struct CfgSet {
18 enabled: HashSet<String>, 16 enabled: HashSet<String>,
19 declared: HashSet<String>, 17 declared: HashSet<String>,
20 emit_declared: bool,
21} 18}
22 19
23impl CfgSet { 20impl CfgSet {
@@ -25,7 +22,6 @@ impl CfgSet {
25 Self { 22 Self {
26 enabled: HashSet::new(), 23 enabled: HashSet::new(),
27 declared: HashSet::new(), 24 declared: HashSet::new(),
28 emit_declared: is_rustc_nightly(),
29 } 25 }
30 } 26 }
31 27
@@ -49,7 +45,7 @@ impl CfgSet {
49 /// 45 ///
50 /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid. 46 /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
51 pub fn declare(&mut self, cfg: impl AsRef<str>) { 47 pub fn declare(&mut self, cfg: impl AsRef<str>) {
52 if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared { 48 if self.declared.insert(cfg.as_ref().to_owned()) {
53 println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref()); 49 println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
54 } 50 }
55 } 51 }
@@ -69,21 +65,6 @@ impl CfgSet {
69 } 65 }
70} 66}
71 67
72fn is_rustc_nightly() -> bool {
73 if env::var_os("EMBASSY_FORCE_CHECK_CFG").is_some() {
74 return true;
75 }
76
77 let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
78
79 let output = Command::new(rustc)
80 .arg("--version")
81 .output()
82 .expect("failed to run `rustc --version`");
83
84 String::from_utf8_lossy(&output.stdout).contains("nightly")
85}
86
87/// Sets configs that describe the target platform. 68/// Sets configs that describe the target platform.
88pub fn set_target_cfgs(cfgs: &mut CfgSet) { 69pub fn set_target_cfgs(cfgs: &mut CfgSet) {
89 let target = env::var("TARGET").unwrap(); 70 let target = env::var("TARGET").unwrap();
diff --git a/embassy-hal-internal/src/fmt.rs b/embassy-hal-internal/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-hal-internal/src/fmt.rs
+++ b/embassy-hal-internal/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml
index e75f76b16..0b2a6744d 100644
--- a/embassy-net-adin1110/Cargo.toml
+++ b/embassy-net-adin1110/Cargo.toml
@@ -16,8 +16,8 @@ log = { version = "0.4", default-features = false, optional = true }
16embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 16embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
17embedded-hal-async = { version = "1.0" } 17embedded-hal-async = { version = "1.0" }
18embedded-hal-bus = { version = "0.1", features = ["async"] } 18embedded-hal-bus = { version = "0.1", features = ["async"] }
19embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } 19embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" }
20embassy-time = { version = "0.3.1", path = "../embassy-time" } 20embassy-time = { version = "0.3.2", path = "../embassy-time" }
21embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 21embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
22bitfield = "0.14.0" 22bitfield = "0.14.0"
23 23
diff --git a/embassy-net-adin1110/README.md b/embassy-net-adin1110/README.md
index 39a38960d..0514274b4 100644
--- a/embassy-net-adin1110/README.md
+++ b/embassy-net-adin1110/README.md
@@ -21,7 +21,7 @@ APL can be used in [`intrinsic safety applications/explosion hazardous areas`](h
21 21
22## Supported SPI modes 22## Supported SPI modes
23 23
24`ADIN1110` supports two SPI modes. `Generic` and [`OPEN Alliance 10BASE-T1x MAC-PHY serial interface`](https://opensig.org/download/document/OPEN_Alliance_10BASET1x_MAC-PHY_Serial_Interface_V1.1.pdf) 24`ADIN1110` supports two SPI modes. `Generic` and [`OPEN Alliance 10BASE-T1x MAC-PHY serial interface`](https://opensig.org/wp-content/uploads/2023/12/OPEN_Alliance_10BASET1x_MAC-PHY_Serial_Interface_V1.1.pdf)
25 25
26Both modes support with and without additional CRC. 26Both modes support with and without additional CRC.
27Currently only `Generic` SPI with or without CRC is supported. 27Currently only `Generic` SPI with or without CRC is supported.
diff --git a/embassy-net-adin1110/src/crc8.rs b/embassy-net-adin1110/src/crc8.rs
index 7d20a7401..321983e64 100644
--- a/embassy-net-adin1110/src/crc8.rs
+++ b/embassy-net-adin1110/src/crc8.rs
@@ -16,7 +16,7 @@ const CRC8X_TABLE: [u8; 256] = [
16 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3, 16 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3,
17]; 17];
18 18
19/// Calculate the crc of a pease of data. 19/// Calculate the crc of a piece of data.
20pub fn crc8(data: &[u8]) -> u8 { 20pub fn crc8(data: &[u8]) -> u8 {
21 data.iter().fold(0, |crc, &byte| CRC8X_TABLE[usize::from(byte ^ crc)]) 21 data.iter().fold(0, |crc, &byte| CRC8X_TABLE[usize::from(byte ^ crc)])
22} 22}
diff --git a/embassy-net-adin1110/src/fmt.rs b/embassy-net-adin1110/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-net-adin1110/src/fmt.rs
+++ b/embassy-net-adin1110/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-net-driver-channel/CHANGELOG.md b/embassy-net-driver-channel/CHANGELOG.md
index b04d0a86b..d7af7e55d 100644
--- a/embassy-net-driver-channel/CHANGELOG.md
+++ b/embassy-net-driver-channel/CHANGELOG.md
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 7
8## Unreleased
9
10## 0.3.0 - 2024-08-05
11
12- Add collapse_debuginfo to fmt.rs macros.
13- Update embassy-sync version
14
8## 0.2.0 - 2023-10-18 15## 0.2.0 - 2023-10-18
9 16
10- Update `embassy-net-driver` to v0.2 17- Update `embassy-net-driver` to v0.2
diff --git a/embassy-net-driver-channel/Cargo.toml b/embassy-net-driver-channel/Cargo.toml
index 3bd7d288a..abce9315b 100644
--- a/embassy-net-driver-channel/Cargo.toml
+++ b/embassy-net-driver-channel/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-net-driver-channel" 2name = "embassy-net-driver-channel"
3version = "0.2.0" 3version = "0.3.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "High-level channel-based driver for the `embassy-net` async TCP/IP network stack." 6description = "High-level channel-based driver for the `embassy-net` async TCP/IP network stack."
diff --git a/embassy-net-driver-channel/src/fmt.rs b/embassy-net-driver-channel/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-net-driver-channel/src/fmt.rs
+++ b/embassy-net-driver-channel/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml
index dd7aa031d..cafced4b2 100644
--- a/embassy-net-enc28j60/Cargo.toml
+++ b/embassy-net-enc28j60/Cargo.toml
@@ -13,7 +13,7 @@ documentation = "https://docs.embassy.dev/embassy-net-enc28j60"
13embedded-hal = { version = "1.0" } 13embedded-hal = { version = "1.0" }
14embedded-hal-async = { version = "1.0" } 14embedded-hal-async = { version = "1.0" }
15embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } 15embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
16embassy-time = { version = "0.3.1", path = "../embassy-time" } 16embassy-time = { version = "0.3.2", path = "../embassy-time" }
17embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 17embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
18 18
19defmt = { version = "0.3", optional = true } 19defmt = { version = "0.3", optional = true }
diff --git a/embassy-net-enc28j60/src/fmt.rs b/embassy-net-enc28j60/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-net-enc28j60/src/fmt.rs
+++ b/embassy-net-enc28j60/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml
index 24b7d0806..915eba7a0 100644
--- a/embassy-net-esp-hosted/Cargo.toml
+++ b/embassy-net-esp-hosted/Cargo.toml
@@ -17,10 +17,10 @@ log = [ "dep:log" ]
17defmt = { version = "0.3", optional = true } 17defmt = { version = "0.3", optional = true }
18log = { version = "0.4.14", optional = true } 18log = { version = "0.4.14", optional = true }
19 19
20embassy-time = { version = "0.3.1", path = "../embassy-time" } 20embassy-time = { version = "0.3.2", path = "../embassy-time" }
21embassy-sync = { version = "0.6.0", path = "../embassy-sync"} 21embassy-sync = { version = "0.6.0", path = "../embassy-sync"}
22embassy-futures = { version = "0.1.0", path = "../embassy-futures"} 22embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
23embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"} 23embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"}
24 24
25embedded-hal = { version = "1.0" } 25embedded-hal = { version = "1.0" }
26embedded-hal-async = { version = "1.0" } 26embedded-hal-async = { version = "1.0" }
diff --git a/embassy-net-esp-hosted/src/fmt.rs b/embassy-net-esp-hosted/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-net-esp-hosted/src/fmt.rs
+++ b/embassy-net-esp-hosted/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-net-esp-hosted/src/proto.rs b/embassy-net-esp-hosted/src/proto.rs
index 034d5bf84..089ded677 100644
--- a/embassy-net-esp-hosted/src/proto.rs
+++ b/embassy-net-esp-hosted/src/proto.rs
@@ -1,3 +1,5 @@
1#![allow(unused)]
2
1use heapless::{String, Vec}; 3use heapless::{String, Vec};
2 4
3/// internal supporting structures for CtrlMsg 5/// internal supporting structures for CtrlMsg
diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml
new file mode 100644
index 000000000..07a0c8886
--- /dev/null
+++ b/embassy-net-nrf91/Cargo.toml
@@ -0,0 +1,38 @@
1[package]
2name = "embassy-net-nrf91"
3version = "0.1.0"
4edition = "2021"
5description = "embassy-net driver for Nordic nRF91-series cellular modems"
6keywords = ["embedded", "nrf91", "embassy-net", "cellular"]
7categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"]
8license = "MIT OR Apache-2.0"
9repository = "https://github.com/embassy-rs/embassy"
10documentation = "https://docs.embassy.dev/embassy-net-nrf91"
11
12[features]
13defmt = [ "dep:defmt", "heapless/defmt-03" ]
14log = [ "dep:log" ]
15
16[dependencies]
17defmt = { version = "0.3", optional = true }
18log = { version = "0.4.14", optional = true }
19
20nrf9160-pac = { version = "0.12.0" }
21
22embassy-time = { version = "0.3.1", path = "../embassy-time" }
23embassy-sync = { version = "0.6.0", path = "../embassy-sync"}
24embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
25embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"}
26
27heapless = "0.8"
28embedded-io = "0.6.1"
29at-commands = "0.5.4"
30
31[package.metadata.embassy_docs]
32src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-nrf91-v$VERSION/embassy-net-nrf91/src/"
33src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-nrf91/src/"
34target = "thumbv7em-none-eabi"
35features = ["defmt"]
36
37[package.metadata.docs.rs]
38features = ["defmt"]
diff --git a/embassy-net-nrf91/README.md b/embassy-net-nrf91/README.md
new file mode 100644
index 000000000..30da71787
--- /dev/null
+++ b/embassy-net-nrf91/README.md
@@ -0,0 +1,9 @@
1# nRF91 `embassy-net` integration
2
3[`embassy-net`](https://crates.io/crates/embassy-net) driver for Nordic nRF91-series cellular modems.
4
5See the [`examples`](https://github.com/embassy-rs/embassy/tree/main/examples/nrf9160) directory for usage examples with the nRF9160.
6
7## Interoperability
8
9This crate can run on any executor.
diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs
new file mode 100644
index 000000000..8b45919ef
--- /dev/null
+++ b/embassy-net-nrf91/src/context.rs
@@ -0,0 +1,350 @@
1//! Helper utility to configure a specific modem context.
2use core::net::IpAddr;
3use core::str::FromStr;
4
5use at_commands::builder::CommandBuilder;
6use at_commands::parser::CommandParser;
7use embassy_time::{Duration, Timer};
8use heapless::Vec;
9
10/// Provides a higher level API for controlling a given context.
11pub struct Control<'a> {
12 control: crate::Control<'a>,
13 cid: u8,
14}
15
16/// Configuration for a given context
17pub struct Config<'a> {
18 /// Desired APN address.
19 pub apn: &'a [u8],
20 /// Desired authentication protocol.
21 pub auth_prot: AuthProt,
22 /// Credentials.
23 pub auth: Option<(&'a [u8], &'a [u8])>,
24}
25
26/// Authentication protocol.
27#[derive(Clone, Copy, PartialEq, Debug)]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29#[repr(u8)]
30pub enum AuthProt {
31 /// No authentication.
32 None = 0,
33 /// PAP authentication.
34 Pap = 1,
35 /// CHAP authentication.
36 Chap = 2,
37}
38
39/// Error returned by control.
40#[derive(Clone, Copy, PartialEq, Debug)]
41#[cfg_attr(feature = "defmt", derive(defmt::Format))]
42pub enum Error {
43 /// Not enough space for command.
44 BufferTooSmall,
45 /// Error parsing response from modem.
46 AtParseError,
47 /// Error parsing IP addresses.
48 AddrParseError,
49}
50
51impl From<at_commands::parser::ParseError> for Error {
52 fn from(_: at_commands::parser::ParseError) -> Self {
53 Self::AtParseError
54 }
55}
56
57/// Status of a given context.
58#[derive(PartialEq, Debug)]
59pub struct Status {
60 /// Attached to APN or not.
61 pub attached: bool,
62 /// IP if assigned.
63 pub ip: Option<IpAddr>,
64 /// Gateway if assigned.
65 pub gateway: Option<IpAddr>,
66 /// DNS servers if assigned.
67 pub dns: Vec<IpAddr, 2>,
68}
69
70#[cfg(feature = "defmt")]
71impl defmt::Format for Status {
72 fn format(&self, f: defmt::Formatter<'_>) {
73 defmt::write!(f, "attached: {}", self.attached);
74 if let Some(ip) = &self.ip {
75 defmt::write!(f, ", ip: {}", defmt::Debug2Format(&ip));
76 }
77 }
78}
79
80impl<'a> Control<'a> {
81 /// Create a new instance of a control handle for a given context.
82 ///
83 /// Will wait for the modem to be initialized if not.
84 pub async fn new(control: crate::Control<'a>, cid: u8) -> Self {
85 control.wait_init().await;
86 Self { control, cid }
87 }
88
89 /// Perform a raw AT command
90 pub async fn at_command(&self, req: &[u8], resp: &mut [u8]) -> usize {
91 self.control.at_command(req, resp).await
92 }
93
94 /// Configures the modem with the provided config.
95 ///
96 /// NOTE: This will disconnect the modem from any current APN and should not
97 /// be called if the configuration has not been changed.
98 ///
99 /// After configuring, invoke [`enable()`] to activate the configuration.
100 pub async fn configure(&self, config: &Config<'_>) -> Result<(), Error> {
101 let mut cmd: [u8; 256] = [0; 256];
102 let mut buf: [u8; 256] = [0; 256];
103
104 let op = CommandBuilder::create_set(&mut cmd, true)
105 .named("+CFUN")
106 .with_int_parameter(0)
107 .finish()
108 .map_err(|_| Error::BufferTooSmall)?;
109 let n = self.control.at_command(op, &mut buf).await;
110 CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
111
112 let op = CommandBuilder::create_set(&mut cmd, true)
113 .named("+CGDCONT")
114 .with_int_parameter(self.cid)
115 .with_string_parameter("IP")
116 .with_string_parameter(config.apn)
117 .finish()
118 .map_err(|_| Error::BufferTooSmall)?;
119 let n = self.control.at_command(op, &mut buf).await;
120 // info!("RES1: {}", unsafe { core::str::from_utf8_unchecked(&buf[..n]) });
121 CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
122
123 let mut op = CommandBuilder::create_set(&mut cmd, true)
124 .named("+CGAUTH")
125 .with_int_parameter(self.cid)
126 .with_int_parameter(config.auth_prot as u8);
127 if let Some((username, password)) = config.auth {
128 op = op.with_string_parameter(username).with_string_parameter(password);
129 }
130 let op = op.finish().map_err(|_| Error::BufferTooSmall)?;
131
132 let n = self.control.at_command(op, &mut buf).await;
133 // info!("RES2: {}", unsafe { core::str::from_utf8_unchecked(&buf[..n]) });
134 CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
135
136 Ok(())
137 }
138
139 /// Attach to the PDN
140 pub async fn attach(&self) -> Result<(), Error> {
141 let mut cmd: [u8; 256] = [0; 256];
142 let mut buf: [u8; 256] = [0; 256];
143 let op = CommandBuilder::create_set(&mut cmd, true)
144 .named("+CGATT")
145 .with_int_parameter(1)
146 .finish()
147 .map_err(|_| Error::BufferTooSmall)?;
148 let n = self.control.at_command(op, &mut buf).await;
149 CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
150 Ok(())
151 }
152
153 /// Read current connectivity status for modem.
154 pub async fn detach(&self) -> Result<(), Error> {
155 let mut cmd: [u8; 256] = [0; 256];
156 let mut buf: [u8; 256] = [0; 256];
157 let op = CommandBuilder::create_set(&mut cmd, true)
158 .named("+CGATT")
159 .with_int_parameter(0)
160 .finish()
161 .map_err(|_| Error::BufferTooSmall)?;
162 let n = self.control.at_command(op, &mut buf).await;
163 CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
164 Ok(())
165 }
166
167 async fn attached(&self) -> Result<bool, Error> {
168 let mut cmd: [u8; 256] = [0; 256];
169 let mut buf: [u8; 256] = [0; 256];
170
171 let op = CommandBuilder::create_query(&mut cmd, true)
172 .named("+CGATT")
173 .finish()
174 .map_err(|_| Error::BufferTooSmall)?;
175 let n = self.control.at_command(op, &mut buf).await;
176 let (res,) = CommandParser::parse(&buf[..n])
177 .expect_identifier(b"+CGATT: ")
178 .expect_int_parameter()
179 .expect_identifier(b"\r\nOK")
180 .finish()?;
181 Ok(res == 1)
182 }
183
184 /// Read current connectivity status for modem.
185 pub async fn status(&self) -> Result<Status, Error> {
186 let mut cmd: [u8; 256] = [0; 256];
187 let mut buf: [u8; 256] = [0; 256];
188
189 let op = CommandBuilder::create_query(&mut cmd, true)
190 .named("+CGATT")
191 .finish()
192 .map_err(|_| Error::BufferTooSmall)?;
193 let n = self.control.at_command(op, &mut buf).await;
194 let (res,) = CommandParser::parse(&buf[..n])
195 .expect_identifier(b"+CGATT: ")
196 .expect_int_parameter()
197 .expect_identifier(b"\r\nOK")
198 .finish()?;
199 let attached = res == 1;
200 if !attached {
201 return Ok(Status {
202 attached,
203 ip: None,
204 gateway: None,
205 dns: Vec::new(),
206 });
207 }
208
209 let op = CommandBuilder::create_set(&mut cmd, true)
210 .named("+CGPADDR")
211 .with_int_parameter(self.cid)
212 .finish()
213 .map_err(|_| Error::BufferTooSmall)?;
214 let n = self.control.at_command(op, &mut buf).await;
215 let (_, ip1, _ip2) = CommandParser::parse(&buf[..n])
216 .expect_identifier(b"+CGPADDR: ")
217 .expect_int_parameter()
218 .expect_optional_string_parameter()
219 .expect_optional_string_parameter()
220 .expect_identifier(b"\r\nOK")
221 .finish()?;
222
223 let ip = if let Some(ip) = ip1 {
224 let ip = IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?;
225 Some(ip)
226 } else {
227 None
228 };
229
230 let op = CommandBuilder::create_set(&mut cmd, true)
231 .named("+CGCONTRDP")
232 .with_int_parameter(self.cid)
233 .finish()
234 .map_err(|_| Error::BufferTooSmall)?;
235 let n = self.control.at_command(op, &mut buf).await;
236 let (_cid, _bid, _apn, _mask, gateway, dns1, dns2, _, _, _, _, _mtu) = CommandParser::parse(&buf[..n])
237 .expect_identifier(b"+CGCONTRDP: ")
238 .expect_int_parameter()
239 .expect_optional_int_parameter()
240 .expect_optional_string_parameter()
241 .expect_optional_string_parameter()
242 .expect_optional_string_parameter()
243 .expect_optional_string_parameter()
244 .expect_optional_string_parameter()
245 .expect_optional_int_parameter()
246 .expect_optional_int_parameter()
247 .expect_optional_int_parameter()
248 .expect_optional_int_parameter()
249 .expect_optional_int_parameter()
250 .expect_identifier(b"\r\nOK")
251 .finish()?;
252
253 let gateway = if let Some(ip) = gateway {
254 if ip.is_empty() {
255 None
256 } else {
257 Some(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?)
258 }
259 } else {
260 None
261 };
262
263 let mut dns = Vec::new();
264 if let Some(ip) = dns1 {
265 dns.push(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?)
266 .unwrap();
267 }
268
269 if let Some(ip) = dns2 {
270 dns.push(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?)
271 .unwrap();
272 }
273
274 Ok(Status {
275 attached,
276 ip,
277 gateway,
278 dns,
279 })
280 }
281
282 async fn wait_attached(&self) -> Result<Status, Error> {
283 while !self.attached().await? {
284 Timer::after(Duration::from_secs(1)).await;
285 }
286 let status = self.status().await?;
287 Ok(status)
288 }
289
290 /// Disable modem
291 pub async fn disable(&self) -> Result<(), Error> {
292 let mut cmd: [u8; 256] = [0; 256];
293 let mut buf: [u8; 256] = [0; 256];
294
295 let op = CommandBuilder::create_set(&mut cmd, true)
296 .named("+CFUN")
297 .with_int_parameter(0)
298 .finish()
299 .map_err(|_| Error::BufferTooSmall)?;
300 let n = self.control.at_command(op, &mut buf).await;
301 CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
302
303 Ok(())
304 }
305
306 /// Enable modem
307 pub async fn enable(&self) -> Result<(), Error> {
308 let mut cmd: [u8; 256] = [0; 256];
309 let mut buf: [u8; 256] = [0; 256];
310
311 let op = CommandBuilder::create_set(&mut cmd, true)
312 .named("+CFUN")
313 .with_int_parameter(1)
314 .finish()
315 .map_err(|_| Error::BufferTooSmall)?;
316 let n = self.control.at_command(op, &mut buf).await;
317 CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
318
319 // Make modem survive PDN detaches
320 let op = CommandBuilder::create_set(&mut cmd, true)
321 .named("%XPDNCFG")
322 .with_int_parameter(1)
323 .finish()
324 .map_err(|_| Error::BufferTooSmall)?;
325 let n = self.control.at_command(op, &mut buf).await;
326 CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?;
327 Ok(())
328 }
329
330 /// Run a control loop for this context, ensuring that reaattach is handled.
331 pub async fn run<F: Fn(&Status)>(&self, reattach: F) -> Result<(), Error> {
332 self.enable().await?;
333 let status = self.wait_attached().await?;
334 let mut fd = self.control.open_raw_socket().await;
335 reattach(&status);
336
337 loop {
338 if !self.attached().await? {
339 trace!("detached");
340
341 self.control.close_raw_socket(fd).await;
342 let status = self.wait_attached().await?;
343 trace!("attached");
344 fd = self.control.open_raw_socket().await;
345 reattach(&status);
346 }
347 Timer::after(Duration::from_secs(10)).await;
348 }
349 }
350}
diff --git a/embassy-net-nrf91/src/fmt.rs b/embassy-net-nrf91/src/fmt.rs
new file mode 100644
index 000000000..35b929fde
--- /dev/null
+++ b/embassy-net-nrf91/src/fmt.rs
@@ -0,0 +1,274 @@
1#![macro_use]
2#![allow(unused)]
3
4use core::fmt::{Debug, Display, LowerHex};
5
6#[cfg(all(feature = "defmt", feature = "log"))]
7compile_error!("You may not enable both `defmt` and `log` features.");
8
9#[collapse_debuginfo(yes)]
10macro_rules! assert {
11 ($($x:tt)*) => {
12 {
13 #[cfg(not(feature = "defmt"))]
14 ::core::assert!($($x)*);
15 #[cfg(feature = "defmt")]
16 ::defmt::assert!($($x)*);
17 }
18 };
19}
20
21#[collapse_debuginfo(yes)]
22macro_rules! assert_eq {
23 ($($x:tt)*) => {
24 {
25 #[cfg(not(feature = "defmt"))]
26 ::core::assert_eq!($($x)*);
27 #[cfg(feature = "defmt")]
28 ::defmt::assert_eq!($($x)*);
29 }
30 };
31}
32
33#[collapse_debuginfo(yes)]
34macro_rules! assert_ne {
35 ($($x:tt)*) => {
36 {
37 #[cfg(not(feature = "defmt"))]
38 ::core::assert_ne!($($x)*);
39 #[cfg(feature = "defmt")]
40 ::defmt::assert_ne!($($x)*);
41 }
42 };
43}
44
45#[collapse_debuginfo(yes)]
46macro_rules! debug_assert {
47 ($($x:tt)*) => {
48 {
49 #[cfg(not(feature = "defmt"))]
50 ::core::debug_assert!($($x)*);
51 #[cfg(feature = "defmt")]
52 ::defmt::debug_assert!($($x)*);
53 }
54 };
55}
56
57#[collapse_debuginfo(yes)]
58macro_rules! debug_assert_eq {
59 ($($x:tt)*) => {
60 {
61 #[cfg(not(feature = "defmt"))]
62 ::core::debug_assert_eq!($($x)*);
63 #[cfg(feature = "defmt")]
64 ::defmt::debug_assert_eq!($($x)*);
65 }
66 };
67}
68
69#[collapse_debuginfo(yes)]
70macro_rules! debug_assert_ne {
71 ($($x:tt)*) => {
72 {
73 #[cfg(not(feature = "defmt"))]
74 ::core::debug_assert_ne!($($x)*);
75 #[cfg(feature = "defmt")]
76 ::defmt::debug_assert_ne!($($x)*);
77 }
78 };
79}
80
81#[collapse_debuginfo(yes)]
82macro_rules! todo {
83 ($($x:tt)*) => {
84 {
85 #[cfg(not(feature = "defmt"))]
86 ::core::todo!($($x)*);
87 #[cfg(feature = "defmt")]
88 ::defmt::todo!($($x)*);
89 }
90 };
91}
92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)]
103macro_rules! unreachable {
104 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*)
106 };
107}
108
109#[collapse_debuginfo(yes)]
110macro_rules! panic {
111 ($($x:tt)*) => {
112 {
113 #[cfg(not(feature = "defmt"))]
114 ::core::panic!($($x)*);
115 #[cfg(feature = "defmt")]
116 ::defmt::panic!($($x)*);
117 }
118 };
119}
120
121#[collapse_debuginfo(yes)]
122macro_rules! trace {
123 ($s:literal $(, $x:expr)* $(,)?) => {
124 {
125 #[cfg(feature = "log")]
126 ::log::trace!($s $(, $x)*);
127 #[cfg(feature = "defmt")]
128 ::defmt::trace!($s $(, $x)*);
129 #[cfg(not(any(feature = "log", feature="defmt")))]
130 let _ = ($( & $x ),*);
131 }
132 };
133}
134
135#[collapse_debuginfo(yes)]
136macro_rules! debug {
137 ($s:literal $(, $x:expr)* $(,)?) => {
138 {
139 #[cfg(feature = "log")]
140 ::log::debug!($s $(, $x)*);
141 #[cfg(feature = "defmt")]
142 ::defmt::debug!($s $(, $x)*);
143 #[cfg(not(any(feature = "log", feature="defmt")))]
144 let _ = ($( & $x ),*);
145 }
146 };
147}
148
149#[collapse_debuginfo(yes)]
150macro_rules! info {
151 ($s:literal $(, $x:expr)* $(,)?) => {
152 {
153 #[cfg(feature = "log")]
154 ::log::info!($s $(, $x)*);
155 #[cfg(feature = "defmt")]
156 ::defmt::info!($s $(, $x)*);
157 #[cfg(not(any(feature = "log", feature="defmt")))]
158 let _ = ($( & $x ),*);
159 }
160 };
161}
162
163#[collapse_debuginfo(yes)]
164macro_rules! warn {
165 ($s:literal $(, $x:expr)* $(,)?) => {
166 {
167 #[cfg(feature = "log")]
168 ::log::warn!($s $(, $x)*);
169 #[cfg(feature = "defmt")]
170 ::defmt::warn!($s $(, $x)*);
171 #[cfg(not(any(feature = "log", feature="defmt")))]
172 let _ = ($( & $x ),*);
173 }
174 };
175}
176
177#[collapse_debuginfo(yes)]
178macro_rules! error {
179 ($s:literal $(, $x:expr)* $(,)?) => {
180 {
181 #[cfg(feature = "log")]
182 ::log::error!($s $(, $x)*);
183 #[cfg(feature = "defmt")]
184 ::defmt::error!($s $(, $x)*);
185 #[cfg(not(any(feature = "log", feature="defmt")))]
186 let _ = ($( & $x ),*);
187 }
188 };
189}
190
191#[cfg(feature = "defmt")]
192#[collapse_debuginfo(yes)]
193macro_rules! unwrap {
194 ($($x:tt)*) => {
195 ::defmt::unwrap!($($x)*)
196 };
197}
198
199#[cfg(not(feature = "defmt"))]
200#[collapse_debuginfo(yes)]
201macro_rules! unwrap {
202 ($arg:expr) => {
203 match $crate::fmt::Try::into_result($arg) {
204 ::core::result::Result::Ok(t) => t,
205 ::core::result::Result::Err(e) => {
206 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
207 }
208 }
209 };
210 ($arg:expr, $($msg:expr),+ $(,)? ) => {
211 match $crate::fmt::Try::into_result($arg) {
212 ::core::result::Result::Ok(t) => t,
213 ::core::result::Result::Err(e) => {
214 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
215 }
216 }
217 }
218}
219
220#[derive(Debug, Copy, Clone, Eq, PartialEq)]
221pub struct NoneError;
222
223pub trait Try {
224 type Ok;
225 type Error;
226 fn into_result(self) -> Result<Self::Ok, Self::Error>;
227}
228
229impl<T> Try for Option<T> {
230 type Ok = T;
231 type Error = NoneError;
232
233 #[inline]
234 fn into_result(self) -> Result<T, NoneError> {
235 self.ok_or(NoneError)
236 }
237}
238
239impl<T, E> Try for Result<T, E> {
240 type Ok = T;
241 type Error = E;
242
243 #[inline]
244 fn into_result(self) -> Self {
245 self
246 }
247}
248
249pub(crate) struct Bytes<'a>(pub &'a [u8]);
250
251impl<'a> Debug for Bytes<'a> {
252 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
253 write!(f, "{:#02x?}", self.0)
254 }
255}
256
257impl<'a> Display for Bytes<'a> {
258 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
259 write!(f, "{:#02x?}", self.0)
260 }
261}
262
263impl<'a> LowerHex for Bytes<'a> {
264 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
265 write!(f, "{:#02x?}", self.0)
266 }
267}
268
269#[cfg(feature = "defmt")]
270impl<'a> defmt::Format for Bytes<'a> {
271 fn format(&self, fmt: defmt::Formatter) {
272 defmt::write!(fmt, "{:02x}", self.0)
273 }
274}
diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs
new file mode 100644
index 000000000..60cdc38c6
--- /dev/null
+++ b/embassy-net-nrf91/src/lib.rs
@@ -0,0 +1,1046 @@
1#![no_std]
2#![doc = include_str!("../README.md")]
3#![warn(missing_docs)]
4#![deny(unused_must_use)]
5
6// must be first
7mod fmt;
8
9pub mod context;
10
11use core::cell::RefCell;
12use core::future::poll_fn;
13use core::marker::PhantomData;
14use core::mem::{self, MaybeUninit};
15use core::ptr::{self, addr_of, addr_of_mut, copy_nonoverlapping};
16use core::slice;
17use core::sync::atomic::{compiler_fence, fence, Ordering};
18use core::task::{Poll, Waker};
19
20use embassy_sync::blocking_mutex::raw::NoopRawMutex;
21use embassy_sync::pipe;
22use embassy_sync::waitqueue::{AtomicWaker, WakerRegistration};
23use heapless::Vec;
24use pac::NVIC;
25use {embassy_net_driver_channel as ch, nrf9160_pac as pac};
26
27const RX_SIZE: usize = 8 * 1024;
28const TRACE_SIZE: usize = 16 * 1024;
29const TRACE_BUF: usize = 1024;
30const MTU: usize = 1500;
31
32/// Network driver.
33///
34/// This is the type you have to pass to `embassy-net` when creating the network stack.
35pub type NetDriver<'a> = ch::Device<'a, MTU>;
36
37static WAKER: AtomicWaker = AtomicWaker::new();
38
39/// Call this function on IPC IRQ
40pub fn on_ipc_irq() {
41 let ipc = unsafe { &*pac::IPC_NS::ptr() };
42
43 trace!("irq");
44
45 ipc.inten.write(|w| w);
46 WAKER.wake();
47}
48
49struct Allocator<'a> {
50 start: *mut u8,
51 end: *mut u8,
52 _phantom: PhantomData<&'a mut u8>,
53}
54
55impl<'a> Allocator<'a> {
56 fn alloc_bytes(&mut self, size: usize) -> &'a mut [MaybeUninit<u8>] {
57 // safety: both pointers come from the same allocation.
58 let available_size = unsafe { self.end.offset_from(self.start) } as usize;
59 if size > available_size {
60 panic!("out of memory")
61 }
62
63 // safety: we've checked above this doesn't go out of bounds.
64 let p = self.start;
65 self.start = unsafe { p.add(size) };
66
67 // safety: we've checked the pointer is in-bounds.
68 unsafe { slice::from_raw_parts_mut(p as *mut _, size) }
69 }
70
71 fn alloc<T>(&mut self) -> &'a mut MaybeUninit<T> {
72 let align = mem::align_of::<T>();
73 let size = mem::size_of::<T>();
74
75 let align_size = match (self.start as usize) % align {
76 0 => 0,
77 n => align - n,
78 };
79
80 // safety: both pointers come from the same allocation.
81 let available_size = unsafe { self.end.offset_from(self.start) } as usize;
82 if align_size + size > available_size {
83 panic!("out of memory")
84 }
85
86 // safety: we've checked above this doesn't go out of bounds.
87 let p = unsafe { self.start.add(align_size) };
88 self.start = unsafe { p.add(size) };
89
90 // safety: we've checked the pointer is aligned and in-bounds.
91 unsafe { &mut *(p as *mut _) }
92 }
93}
94
95/// Create a new nRF91 embassy-net driver.
96pub async fn new<'a>(
97 state: &'a mut State,
98 shmem: &'a mut [MaybeUninit<u8>],
99) -> (NetDriver<'a>, Control<'a>, Runner<'a>) {
100 let (n, c, r, _) = new_internal(state, shmem, None).await;
101 (n, c, r)
102}
103
104/// Create a new nRF91 embassy-net driver with trace.
105pub async fn new_with_trace<'a>(
106 state: &'a mut State,
107 shmem: &'a mut [MaybeUninit<u8>],
108 trace_buffer: &'a mut TraceBuffer,
109) -> (NetDriver<'a>, Control<'a>, Runner<'a>, TraceReader<'a>) {
110 let (n, c, r, t) = new_internal(state, shmem, Some(trace_buffer)).await;
111 (n, c, r, t.unwrap())
112}
113
114/// Create a new nRF91 embassy-net driver.
115async fn new_internal<'a>(
116 state: &'a mut State,
117 shmem: &'a mut [MaybeUninit<u8>],
118 trace_buffer: Option<&'a mut TraceBuffer>,
119) -> (NetDriver<'a>, Control<'a>, Runner<'a>, Option<TraceReader<'a>>) {
120 let shmem_len = shmem.len();
121 let shmem_ptr = shmem.as_mut_ptr() as *mut u8;
122
123 const SPU_REGION_SIZE: usize = 8192; // 8kb
124 assert!(shmem_len != 0);
125 assert!(
126 shmem_len % SPU_REGION_SIZE == 0,
127 "shmem length must be a multiple of 8kb"
128 );
129 assert!(
130 (shmem_ptr as usize) % SPU_REGION_SIZE == 0,
131 "shmem length must be a multiple of 8kb"
132 );
133 assert!(
134 (shmem_ptr as usize + shmem_len) < 0x2002_0000,
135 "shmem must be in the lower 128kb of RAM"
136 );
137
138 let spu = unsafe { &*pac::SPU_S::ptr() };
139 debug!("Setting IPC RAM as nonsecure...");
140 let region_start = (shmem_ptr as usize - 0x2000_0000) / SPU_REGION_SIZE;
141 let region_end = region_start + shmem_len / SPU_REGION_SIZE;
142 for i in region_start..region_end {
143 spu.ramregion[i].perm.write(|w| {
144 w.execute().set_bit();
145 w.write().set_bit();
146 w.read().set_bit();
147 w.secattr().clear_bit();
148 w.lock().clear_bit();
149 w
150 })
151 }
152
153 spu.periphid[42].perm.write(|w| w.secattr().non_secure());
154
155 let mut alloc = Allocator {
156 start: shmem_ptr,
157 end: unsafe { shmem_ptr.add(shmem_len) },
158 _phantom: PhantomData,
159 };
160
161 let ipc = unsafe { &*pac::IPC_NS::ptr() };
162 let power = unsafe { &*pac::POWER_S::ptr() };
163
164 let cb: &mut ControlBlock = alloc.alloc().write(unsafe { mem::zeroed() });
165 let rx = alloc.alloc_bytes(RX_SIZE);
166 let trace = alloc.alloc_bytes(TRACE_SIZE);
167
168 cb.version = 0x00010000;
169 cb.rx_base = rx.as_mut_ptr() as _;
170 cb.rx_size = RX_SIZE;
171 cb.control_list_ptr = &mut cb.lists[0];
172 cb.data_list_ptr = &mut cb.lists[1];
173 cb.modem_info_ptr = &mut cb.modem_info;
174 cb.trace_ptr = &mut cb.trace;
175 cb.lists[0].len = LIST_LEN;
176 cb.lists[1].len = LIST_LEN;
177 cb.trace.base = trace.as_mut_ptr() as _;
178 cb.trace.size = TRACE_SIZE;
179
180 ipc.gpmem[0].write(|w| unsafe { w.bits(cb as *mut _ as u32) });
181 ipc.gpmem[1].write(|w| unsafe { w.bits(0) });
182
183 // connect task/event i to channel i
184 for i in 0..8 {
185 ipc.send_cnf[i].write(|w| unsafe { w.bits(1 << i) });
186 ipc.receive_cnf[i].write(|w| unsafe { w.bits(1 << i) });
187 }
188
189 compiler_fence(Ordering::SeqCst);
190
191 // POWER.LTEMODEM.STARTN = 0
192 // The reg is missing in the PAC??
193 let startn = unsafe { (power as *const _ as *mut u32).add(0x610 / 4) };
194 unsafe { startn.write_volatile(0) }
195
196 unsafe { NVIC::unmask(pac::Interrupt::IPC) };
197
198 let state_inner = &*state.inner.write(RefCell::new(StateInner {
199 init: false,
200 init_waker: WakerRegistration::new(),
201 cb,
202 requests: [const { None }; REQ_COUNT],
203 next_req_serial: 0x12345678,
204
205 rx_control_list: ptr::null_mut(),
206 rx_data_list: ptr::null_mut(),
207 rx_seq_no: 0,
208 rx_check: PointerChecker {
209 start: rx.as_mut_ptr() as *mut u8,
210 end: (rx.as_mut_ptr() as *mut u8).wrapping_add(RX_SIZE),
211 },
212
213 tx_seq_no: 0,
214 tx_buf_used: [false; TX_BUF_COUNT],
215
216 trace_chans: Vec::new(),
217 trace_check: PointerChecker {
218 start: trace.as_mut_ptr() as *mut u8,
219 end: (trace.as_mut_ptr() as *mut u8).wrapping_add(TRACE_SIZE),
220 },
221 }));
222
223 let control = Control { state: state_inner };
224
225 let (ch_runner, device) = ch::new(&mut state.ch, ch::driver::HardwareAddress::Ip);
226 let state_ch = ch_runner.state_runner();
227 state_ch.set_link_state(ch::driver::LinkState::Up);
228
229 let (trace_reader, trace_writer) = if let Some(trace) = trace_buffer {
230 let (r, w) = trace.trace.split();
231 (Some(r), Some(w))
232 } else {
233 (None, None)
234 };
235
236 let runner = Runner {
237 ch: ch_runner,
238 state: state_inner,
239 trace_writer,
240 };
241
242 (device, control, runner, trace_reader)
243}
244
245/// State holding modem traces.
246pub struct TraceBuffer {
247 trace: pipe::Pipe<NoopRawMutex, TRACE_BUF>,
248}
249
250/// Represents writer half of the trace buffer.
251pub type TraceWriter<'a> = pipe::Writer<'a, NoopRawMutex, TRACE_BUF>;
252
253/// Represents the reader half of the trace buffer.
254pub type TraceReader<'a> = pipe::Reader<'a, NoopRawMutex, TRACE_BUF>;
255
256impl TraceBuffer {
257 /// Create a new TraceBuffer.
258 pub const fn new() -> Self {
259 Self {
260 trace: pipe::Pipe::new(),
261 }
262 }
263}
264
265/// Shared state for the driver.
266pub struct State {
267 ch: ch::State<MTU, 4, 4>,
268 inner: MaybeUninit<RefCell<StateInner>>,
269}
270
271impl State {
272 /// Create a new State.
273 pub const fn new() -> Self {
274 Self {
275 ch: ch::State::new(),
276 inner: MaybeUninit::uninit(),
277 }
278 }
279}
280
281const TX_BUF_COUNT: usize = 4;
282const TX_BUF_SIZE: usize = 1500;
283
284struct TraceChannelInfo {
285 ptr: *mut TraceChannel,
286 start: *mut u8,
287 end: *mut u8,
288}
289
290const REQ_COUNT: usize = 4;
291
292struct PendingRequest {
293 req_serial: u32,
294 resp_msg: *mut Message,
295 waker: Waker,
296}
297
298#[derive(Copy, Clone, PartialEq, Eq)]
299#[cfg_attr(feature = "defmt", derive(defmt::Format))]
300struct NoFreeBufs;
301
302struct StateInner {
303 init: bool,
304 init_waker: WakerRegistration,
305
306 cb: *mut ControlBlock,
307 requests: [Option<PendingRequest>; REQ_COUNT],
308 next_req_serial: u32,
309
310 rx_control_list: *mut List,
311 rx_data_list: *mut List,
312 rx_seq_no: u16,
313 rx_check: PointerChecker,
314
315 tx_seq_no: u16,
316 tx_buf_used: [bool; TX_BUF_COUNT],
317
318 trace_chans: Vec<TraceChannelInfo, TRACE_CHANNEL_COUNT>,
319 trace_check: PointerChecker,
320}
321
322impl StateInner {
323 fn poll(&mut self, trace_writer: &mut Option<TraceWriter<'_>>, ch: &mut ch::Runner<MTU>) {
324 trace!("poll!");
325 let ipc = unsafe { &*pac::IPC_NS::ptr() };
326
327 if ipc.events_receive[0].read().bits() != 0 {
328 ipc.events_receive[0].reset();
329 trace!("ipc 0");
330 }
331
332 if ipc.events_receive[2].read().bits() != 0 {
333 ipc.events_receive[2].reset();
334 trace!("ipc 2");
335
336 if !self.init {
337 let desc = unsafe { addr_of!((*self.cb).modem_info).read_volatile() };
338 assert_eq!(desc.version, 1);
339
340 self.rx_check.check_mut(desc.control_list_ptr);
341 self.rx_check.check_mut(desc.data_list_ptr);
342
343 self.rx_control_list = desc.control_list_ptr;
344 self.rx_data_list = desc.data_list_ptr;
345 let rx_control_len = unsafe { addr_of!((*self.rx_control_list).len).read_volatile() };
346 let rx_data_len = unsafe { addr_of!((*self.rx_data_list).len).read_volatile() };
347 assert_eq!(rx_control_len, LIST_LEN);
348 assert_eq!(rx_data_len, LIST_LEN);
349 self.init = true;
350
351 debug!("IPC initialized OK!");
352 self.init_waker.wake();
353 }
354 }
355
356 if ipc.events_receive[4].read().bits() != 0 {
357 ipc.events_receive[4].reset();
358 trace!("ipc 4");
359
360 loop {
361 let list = unsafe { &mut *self.rx_control_list };
362 let control_work = self.process(list, true, ch);
363 let list = unsafe { &mut *self.rx_data_list };
364 let data_work = self.process(list, false, ch);
365 if !control_work && !data_work {
366 break;
367 }
368 }
369 }
370
371 if ipc.events_receive[6].read().bits() != 0 {
372 ipc.events_receive[6].reset();
373 trace!("ipc 6");
374 }
375
376 if ipc.events_receive[7].read().bits() != 0 {
377 ipc.events_receive[7].reset();
378 trace!("ipc 7: trace");
379
380 let msg = unsafe { addr_of!((*self.cb).trace.rx_state).read_volatile() };
381 if msg != 0 {
382 trace!("trace msg {}", msg);
383 match msg {
384 0 => unreachable!(),
385 1 => {
386 let ctx = unsafe { addr_of!((*self.cb).trace.rx_ptr).read_volatile() } as *mut TraceContext;
387 debug!("trace init: {:?}", ctx);
388 self.trace_check.check(ctx);
389 let chans = unsafe { addr_of!((*ctx).chans).read_volatile() };
390 for chan_ptr in chans {
391 let chan = self.trace_check.check_read(chan_ptr);
392 self.trace_check.check(chan.start);
393 self.trace_check.check(chan.end);
394 assert!(chan.start < chan.end);
395 self.trace_chans
396 .push(TraceChannelInfo {
397 ptr: chan_ptr,
398 start: chan.start,
399 end: chan.end,
400 })
401 .map_err(|_| ())
402 .unwrap()
403 }
404 }
405 2 => {
406 for chan_info in &self.trace_chans {
407 let read_ptr = unsafe { addr_of!((*chan_info.ptr).read_ptr).read_volatile() };
408 let write_ptr = unsafe { addr_of!((*chan_info.ptr).write_ptr).read_volatile() };
409 assert!(read_ptr >= chan_info.start && read_ptr <= chan_info.end);
410 assert!(write_ptr >= chan_info.start && write_ptr <= chan_info.end);
411 if read_ptr != write_ptr {
412 let id = unsafe { addr_of!((*chan_info.ptr).id).read_volatile() };
413 fence(Ordering::SeqCst); // synchronize volatile accesses with the slice access.
414 if read_ptr < write_ptr {
415 Self::handle_trace(trace_writer, id, unsafe {
416 slice::from_raw_parts(read_ptr, write_ptr.offset_from(read_ptr) as _)
417 });
418 } else {
419 Self::handle_trace(trace_writer, id, unsafe {
420 slice::from_raw_parts(read_ptr, chan_info.end.offset_from(read_ptr) as _)
421 });
422 Self::handle_trace(trace_writer, id, unsafe {
423 slice::from_raw_parts(
424 chan_info.start,
425 write_ptr.offset_from(chan_info.start) as _,
426 )
427 });
428 }
429 fence(Ordering::SeqCst); // synchronize volatile accesses with the slice access.
430 unsafe { addr_of_mut!((*chan_info.ptr).read_ptr).write_volatile(write_ptr) };
431 }
432 }
433 }
434 _ => warn!("unknown trace msg {}", msg),
435 }
436 unsafe { addr_of_mut!((*self.cb).trace.rx_state).write_volatile(0) };
437 }
438 }
439
440 ipc.intenset.write(|w| {
441 w.receive0().set_bit();
442 w.receive2().set_bit();
443 w.receive4().set_bit();
444 w.receive6().set_bit();
445 w.receive7().set_bit();
446 w
447 });
448 }
449
450 fn handle_trace(writer: &mut Option<TraceWriter<'_>>, id: u8, data: &[u8]) {
451 if let Some(writer) = writer {
452 trace!("trace: {} {}", id, data.len());
453 let mut header = [0u8; 5];
454 header[0] = 0xEF;
455 header[1] = 0xBE;
456 header[2..4].copy_from_slice(&(data.len() as u16).to_le_bytes());
457 header[4] = id;
458 writer.try_write(&header).ok();
459 writer.try_write(data).ok();
460 }
461 }
462
463 fn process(&mut self, list: *mut List, is_control: bool, ch: &mut ch::Runner<MTU>) -> bool {
464 let mut did_work = false;
465 for i in 0..LIST_LEN {
466 let item_ptr = unsafe { addr_of_mut!((*list).items[i]) };
467 let preamble = unsafe { addr_of!((*item_ptr).state).read_volatile() };
468 if preamble & 0xFF == 0x01 && preamble >> 16 == self.rx_seq_no as u32 {
469 let msg_ptr = unsafe { addr_of!((*item_ptr).message).read_volatile() };
470 let msg = self.rx_check.check_read(msg_ptr);
471
472 debug!("rx seq {} msg: {:?}", preamble >> 16, msg);
473
474 if is_control {
475 self.handle_control(&msg);
476 } else {
477 self.handle_data(&msg, ch);
478 }
479
480 unsafe { addr_of_mut!((*item_ptr).state).write_volatile(0x03) };
481 self.rx_seq_no = self.rx_seq_no.wrapping_add(1);
482
483 did_work = true;
484 }
485 }
486 did_work
487 }
488
489 fn find_free_message(&mut self, ch: usize) -> Option<usize> {
490 for i in 0..LIST_LEN {
491 let preamble = unsafe { addr_of!((*self.cb).lists[ch].items[i].state).read_volatile() };
492 if matches!(preamble & 0xFF, 0 | 3) {
493 trace!("using tx msg idx {}", i);
494 return Some(i);
495 }
496 }
497 return None;
498 }
499
500 fn find_free_tx_buf(&mut self) -> Option<usize> {
501 for i in 0..TX_BUF_COUNT {
502 if !self.tx_buf_used[i] {
503 trace!("using tx buf idx {}", i);
504 return Some(i);
505 }
506 }
507 return None;
508 }
509
510 fn send_message(&mut self, msg: &mut Message, data: &[u8]) -> Result<(), NoFreeBufs> {
511 if data.is_empty() {
512 msg.data = ptr::null_mut();
513 msg.data_len = 0;
514 } else {
515 assert!(data.len() <= TX_BUF_SIZE);
516 let buf_idx = self.find_free_tx_buf().ok_or(NoFreeBufs)?;
517 let buf = unsafe { addr_of_mut!((*self.cb).tx_bufs[buf_idx]) } as *mut u8;
518 unsafe { copy_nonoverlapping(data.as_ptr(), buf, data.len()) }
519 msg.data = buf;
520 msg.data_len = data.len();
521 self.tx_buf_used[buf_idx] = true;
522
523 fence(Ordering::SeqCst); // synchronize copy_nonoverlapping (non-volatile) with volatile writes below.
524 }
525
526 // TODO free data buf if send_message_raw fails.
527 self.send_message_raw(msg)
528 }
529
530 fn send_message_raw(&mut self, msg: &Message) -> Result<(), NoFreeBufs> {
531 let (ch, ipc_ch) = match msg.channel {
532 1 => (0, 1), // control
533 2 => (1, 3), // data
534 _ => unreachable!(),
535 };
536
537 // allocate a msg.
538 let idx = self.find_free_message(ch).ok_or(NoFreeBufs)?;
539
540 debug!("tx seq {} msg: {:?}", self.tx_seq_no, msg);
541
542 let msg_slot = unsafe { addr_of_mut!((*self.cb).msgs[ch][idx]) };
543 unsafe { msg_slot.write_volatile(*msg) }
544 let list_item = unsafe { addr_of_mut!((*self.cb).lists[ch].items[idx]) };
545 unsafe { addr_of_mut!((*list_item).message).write_volatile(msg_slot) }
546 unsafe { addr_of_mut!((*list_item).state).write_volatile((self.tx_seq_no as u32) << 16 | 0x01) }
547 self.tx_seq_no = self.tx_seq_no.wrapping_add(1);
548
549 let ipc = unsafe { &*pac::IPC_NS::ptr() };
550 ipc.tasks_send[ipc_ch].write(|w| unsafe { w.bits(1) });
551 Ok(())
552 }
553
554 fn handle_control(&mut self, msg: &Message) {
555 match msg.id >> 16 {
556 1 => debug!("control msg: modem ready"),
557 2 => self.handle_control_free(msg.data),
558 _ => warn!("unknown control message id {:08x}", msg.id),
559 }
560 }
561
562 fn handle_control_free(&mut self, ptr: *mut u8) {
563 let base = unsafe { addr_of!((*self.cb).tx_bufs) } as usize;
564 let ptr = ptr as usize;
565
566 if ptr < base {
567 warn!("control free bad pointer {:08x}", ptr);
568 return;
569 }
570
571 let diff = ptr - base;
572 let idx = diff / TX_BUF_SIZE;
573
574 if idx >= TX_BUF_COUNT || idx * TX_BUF_SIZE != diff {
575 warn!("control free bad pointer {:08x}", ptr);
576 return;
577 }
578
579 trace!("control free pointer {:08x} idx {}", ptr, idx);
580 if !self.tx_buf_used[idx] {
581 warn!(
582 "control free pointer {:08x} idx {}: buffer was already free??",
583 ptr, idx
584 );
585 }
586 self.tx_buf_used[idx] = false;
587 }
588
589 fn handle_data(&mut self, msg: &Message, ch: &mut ch::Runner<MTU>) {
590 if !msg.data.is_null() {
591 self.rx_check.check_length(msg.data, msg.data_len);
592 }
593
594 let freed = match msg.id & 0xFFFF {
595 // AT
596 3 => {
597 match msg.id >> 16 {
598 // AT request ack
599 2 => false,
600 // AT response
601 3 => self.handle_resp(msg),
602 // AT notification
603 4 => false,
604 x => {
605 warn!("received unknown AT kind {}", x);
606 false
607 }
608 }
609 }
610 // IP
611 4 => {
612 match msg.id >> 28 {
613 // IP response
614 8 => self.handle_resp(msg),
615 // IP notification
616 9 => match (msg.id >> 16) & 0xFFF {
617 // IP receive notification
618 1 => {
619 if let Some(buf) = ch.try_rx_buf() {
620 let mut len = msg.data_len;
621 if len > buf.len() {
622 warn!("truncating rx'd packet from {} to {} bytes", len, buf.len());
623 len = buf.len();
624 }
625 fence(Ordering::SeqCst); // synchronize volatile accesses with the nonvolatile copy_nonoverlapping.
626 unsafe { ptr::copy_nonoverlapping(msg.data, buf.as_mut_ptr(), len) }
627 fence(Ordering::SeqCst); // synchronize volatile accesses with the nonvolatile copy_nonoverlapping.
628 ch.rx_done(len);
629 }
630 false
631 }
632 _ => false,
633 },
634 x => {
635 warn!("received unknown IP kind {}", x);
636 false
637 }
638 }
639 }
640 x => {
641 warn!("received unknown kind {}", x);
642 false
643 }
644 };
645
646 if !freed {
647 self.send_free(msg);
648 }
649 }
650
651 fn handle_resp(&mut self, msg: &Message) -> bool {
652 let req_serial = u32::from_le_bytes(msg.param[0..4].try_into().unwrap());
653 if req_serial == 0 {
654 return false;
655 }
656
657 for optr in &mut self.requests {
658 if let Some(r) = optr {
659 if r.req_serial == req_serial {
660 let r = optr.take().unwrap();
661 unsafe { r.resp_msg.write(*msg) }
662 r.waker.wake();
663 *optr = None;
664 return true;
665 }
666 }
667 }
668
669 warn!(
670 "resp with id {} serial {} doesn't match any pending req",
671 msg.id, req_serial
672 );
673 false
674 }
675
676 fn send_free(&mut self, msg: &Message) {
677 if msg.data.is_null() {
678 return;
679 }
680
681 let mut free_msg: Message = unsafe { mem::zeroed() };
682 free_msg.channel = 1; // control
683 free_msg.id = 0x20001; // free
684 free_msg.data = msg.data;
685 free_msg.data_len = msg.data_len;
686
687 unwrap!(self.send_message_raw(&free_msg));
688 }
689}
690
691struct PointerChecker {
692 start: *mut u8,
693 end: *mut u8,
694}
695
696impl PointerChecker {
697 // check the pointer is in bounds in the arena, panic otherwise.
698 fn check_length(&self, ptr: *const u8, len: usize) {
699 assert!(ptr as usize >= self.start as usize);
700 let end_ptr = (ptr as usize).checked_add(len).unwrap();
701 assert!(end_ptr <= self.end as usize);
702 }
703
704 // check the pointer is in bounds in the arena, panic otherwise.
705 fn check<T>(&self, ptr: *const T) {
706 assert!(ptr.is_aligned());
707 self.check_length(ptr as *const u8, mem::size_of::<T>());
708 }
709
710 // check the pointer is in bounds in the arena, panic otherwise.
711 fn check_read<T>(&self, ptr: *const T) -> T {
712 self.check(ptr);
713 unsafe { ptr.read_volatile() }
714 }
715
716 // check the pointer is in bounds in the arena, panic otherwise.
717 fn check_mut<T>(&self, ptr: *mut T) {
718 self.check(ptr as *const T)
719 }
720}
721
722/// Control handle for the driver.
723///
724/// You can use this object to control the modem at runtime, such as running AT commands.
725pub struct Control<'a> {
726 state: &'a RefCell<StateInner>,
727}
728
729impl<'a> Control<'a> {
730 /// Wait for modem IPC to be initialized.
731 pub async fn wait_init(&self) {
732 poll_fn(|cx| {
733 let mut state = self.state.borrow_mut();
734 if state.init {
735 return Poll::Ready(());
736 }
737 state.init_waker.register(cx.waker());
738 Poll::Pending
739 })
740 .await
741 }
742
743 async fn request(&self, msg: &mut Message, req_data: &[u8], resp_data: &mut [u8]) -> usize {
744 // get waker
745 let waker = poll_fn(|cx| Poll::Ready(cx.waker().clone())).await;
746
747 // Send request
748 let mut state = self.state.borrow_mut();
749 let mut req_serial = state.next_req_serial;
750 if msg.id & 0xFFFF == 3 {
751 // AT response seems to keep only the lower 8 bits. Others do keep the full 32 bits..??
752 req_serial &= 0xFF;
753 }
754
755 // increment next_req_serial, skip zero because we use it as an "ignore" value.
756 // We have to skip when the *lowest byte* is zero because AT responses.
757 state.next_req_serial = state.next_req_serial.wrapping_add(1);
758 if state.next_req_serial & 0xFF == 0 {
759 state.next_req_serial = state.next_req_serial.wrapping_add(1);
760 }
761
762 msg.param[0..4].copy_from_slice(&req_serial.to_le_bytes());
763 unwrap!(state.send_message(msg, req_data));
764
765 // Setup the pending request state.
766 let (req_slot_idx, req_slot) = state
767 .requests
768 .iter_mut()
769 .enumerate()
770 .find(|(_, x)| x.is_none())
771 .unwrap();
772 msg.id = 0; // zero out id, so when it becomes nonzero we know the req is done.
773 let msg_ptr: *mut Message = msg;
774 *req_slot = Some(PendingRequest {
775 req_serial,
776 resp_msg: msg_ptr,
777 waker,
778 });
779
780 drop(state); // don't borrow state across awaits.
781
782 // On cancel, unregister the request slot.
783 let _drop = OnDrop::new(|| {
784 // Remove request slot.
785 let mut state = self.state.borrow_mut();
786 let slot = &mut state.requests[req_slot_idx];
787 if let Some(s) = slot {
788 if s.req_serial == req_serial {
789 *slot = None;
790 }
791 }
792
793 // If cancelation raced with actually receiving the response,
794 // we own the data, so we have to free it.
795 let msg = unsafe { &mut *msg_ptr };
796 if msg.id != 0 {
797 state.send_free(msg);
798 }
799 });
800 // Wait for response.
801 poll_fn(|_| {
802 // we have to use the raw pointer and not the original reference `msg`
803 // because that'd invalidate the raw ptr that's still stored in `req_slot`.
804 if unsafe { (*msg_ptr).id } != 0 {
805 Poll::Ready(())
806 } else {
807 Poll::Pending
808 }
809 })
810 .await;
811 _drop.defuse();
812
813 if msg.data.is_null() {
814 // no response data.
815 return 0;
816 }
817
818 // Copy response data out, if any.
819 // Pointer was validated in StateInner::handle_data().
820 let mut len = msg.data_len;
821 if len > resp_data.len() {
822 warn!("truncating response data from {} to {}", len, resp_data.len());
823 len = resp_data.len();
824 }
825 fence(Ordering::SeqCst); // synchronize volatile accesses with the nonvolatile copy_nonoverlapping.
826 unsafe { ptr::copy_nonoverlapping(msg.data, resp_data.as_mut_ptr(), len) }
827 fence(Ordering::SeqCst); // synchronize volatile accesses with the nonvolatile copy_nonoverlapping.
828 self.state.borrow_mut().send_free(msg);
829 len
830 }
831
832 /// Run an AT command.
833 ///
834 /// The response is written in `resp` and its length returned.
835 pub async fn at_command(&self, req: &[u8], resp: &mut [u8]) -> usize {
836 let mut msg: Message = unsafe { mem::zeroed() };
837 msg.channel = 2; // data
838 msg.id = 0x0001_0003; // AT command
839 msg.param_len = 4;
840
841 self.request(&mut msg, req, resp).await
842 }
843
844 /// Open the raw socket used for sending/receiving IP packets.
845 ///
846 /// This must be done after `AT+CFUN=1` (?)
847 async fn open_raw_socket(&self) -> u32 {
848 let mut msg: Message = unsafe { mem::zeroed() };
849 msg.channel = 2; // data
850 msg.id = 0x7001_0004; // open socket
851 msg.param_len = 20;
852
853 let param = [
854 0xFF, 0xFF, 0xFF, 0xFF, // req_serial
855 0xFF, 0xFF, 0xFF, 0xFF, // ???
856 0x05, 0x00, 0x00, 0x00, // family
857 0x03, 0x00, 0x00, 0x00, // type
858 0x00, 0x00, 0x00, 0x00, // protocol
859 ];
860 msg.param[..param.len()].copy_from_slice(&param);
861
862 self.request(&mut msg, &[], &mut []).await;
863
864 assert_eq!(msg.id, 0x80010004);
865 assert!(msg.param_len >= 12);
866 let status = u32::from_le_bytes(msg.param[8..12].try_into().unwrap());
867 assert_eq!(status, 0);
868 assert_eq!(msg.param_len, 16);
869 let fd = u32::from_le_bytes(msg.param[12..16].try_into().unwrap());
870 trace!("got FD: {}", fd);
871 fd
872 }
873
874 async fn close_raw_socket(&self, fd: u32) {
875 let mut msg: Message = unsafe { mem::zeroed() };
876 msg.channel = 2; // data
877 msg.id = 0x7009_0004; // close socket
878 msg.param_len = 8;
879 msg.param[4..8].copy_from_slice(&fd.to_le_bytes());
880
881 self.request(&mut msg, &[], &mut []).await;
882
883 assert_eq!(msg.id, 0x80090004);
884 assert!(msg.param_len >= 12);
885 let status = u32::from_le_bytes(msg.param[8..12].try_into().unwrap());
886 assert_eq!(status, 0);
887 }
888}
889
890/// Background runner for the driver.
891pub struct Runner<'a> {
892 ch: ch::Runner<'a, MTU>,
893 state: &'a RefCell<StateInner>,
894 trace_writer: Option<TraceWriter<'a>>,
895}
896
897impl<'a> Runner<'a> {
898 /// Run the driver operation in the background.
899 ///
900 /// You must run this in a background task, concurrently with all network operations.
901 pub async fn run(mut self) -> ! {
902 poll_fn(|cx| {
903 WAKER.register(cx.waker());
904
905 let mut state = self.state.borrow_mut();
906 state.poll(&mut self.trace_writer, &mut self.ch);
907
908 if let Poll::Ready(buf) = self.ch.poll_tx_buf(cx) {
909 let fd = 128u32; // TODO unhardcode
910 let mut msg: Message = unsafe { mem::zeroed() };
911 msg.channel = 2; // data
912 msg.id = 0x7006_0004; // IP send
913 msg.param_len = 12;
914 msg.param[4..8].copy_from_slice(&fd.to_le_bytes());
915 if let Err(e) = state.send_message(&mut msg, buf) {
916 warn!("tx failed: {:?}", e);
917 }
918 self.ch.tx_done();
919 }
920
921 Poll::Pending
922 })
923 .await
924 }
925}
926
927const LIST_LEN: usize = 16;
928
929#[repr(C)]
930struct ControlBlock {
931 version: u32,
932 rx_base: *mut u8,
933 rx_size: usize,
934 control_list_ptr: *mut List,
935 data_list_ptr: *mut List,
936 modem_info_ptr: *mut ModemInfo,
937 trace_ptr: *mut Trace,
938 unk: u32,
939
940 modem_info: ModemInfo,
941 trace: Trace,
942
943 // 0 = control, 1 = data
944 lists: [List; 2],
945 msgs: [[Message; LIST_LEN]; 2],
946
947 tx_bufs: [[u8; TX_BUF_SIZE]; TX_BUF_COUNT],
948}
949
950#[repr(C)]
951struct ModemInfo {
952 version: u32,
953 control_list_ptr: *mut List,
954 data_list_ptr: *mut List,
955 padding: [u32; 5],
956}
957
958#[repr(C)]
959struct Trace {
960 size: usize,
961 base: *mut u8,
962 tx_state: u32,
963 tx_ptr: *mut u8,
964 rx_state: u32,
965 rx_ptr: *mut u8,
966 unk1: u32,
967 unk2: u32,
968}
969
970const TRACE_CHANNEL_COUNT: usize = 3;
971
972#[repr(C)]
973#[cfg_attr(feature = "defmt", derive(defmt::Format))]
974struct TraceContext {
975 unk1: u32,
976 unk2: u32,
977 len: u32,
978 chans: [*mut TraceChannel; TRACE_CHANNEL_COUNT],
979}
980
981#[repr(C)]
982#[cfg_attr(feature = "defmt", derive(defmt::Format))]
983struct TraceChannel {
984 id: u8,
985 unk1: u8,
986 unk2: u8,
987 unk3: u8,
988 write_ptr: *mut u8,
989 read_ptr: *mut u8,
990 start: *mut u8,
991 end: *mut u8,
992}
993
994#[repr(C)]
995struct List {
996 len: usize,
997 items: [ListItem; LIST_LEN],
998}
999
1000#[repr(C)]
1001struct ListItem {
1002 /// top 16 bits: seqno
1003 /// bottom 8 bits:
1004 /// 0x01: sent
1005 /// 0x02: held
1006 /// 0x03: freed
1007 state: u32,
1008 message: *mut Message,
1009}
1010
1011#[repr(C)]
1012#[derive(defmt::Format, Clone, Copy)]
1013struct Message {
1014 id: u32,
1015
1016 /// 1 = control, 2 = data
1017 channel: u8,
1018 unk1: u8,
1019 unk2: u8,
1020 unk3: u8,
1021
1022 data: *mut u8,
1023 data_len: usize,
1024 param_len: usize,
1025 param: [u8; 44],
1026}
1027
1028struct OnDrop<F: FnOnce()> {
1029 f: MaybeUninit<F>,
1030}
1031
1032impl<F: FnOnce()> OnDrop<F> {
1033 pub fn new(f: F) -> Self {
1034 Self { f: MaybeUninit::new(f) }
1035 }
1036
1037 pub fn defuse(self) {
1038 mem::forget(self)
1039 }
1040}
1041
1042impl<F: FnOnce()> Drop for OnDrop<F> {
1043 fn drop(&mut self) {
1044 unsafe { self.f.as_ptr().read()() }
1045 }
1046}
diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml
index cdfafaae1..f6371f955 100644
--- a/embassy-net-ppp/Cargo.toml
+++ b/embassy-net-ppp/Cargo.toml
@@ -18,7 +18,7 @@ defmt = { version = "0.3", optional = true }
18log = { version = "0.4.14", optional = true } 18log = { version = "0.4.14", optional = true }
19 19
20embedded-io-async = { version = "0.6.1" } 20embedded-io-async = { version = "0.6.1" }
21embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } 21embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" }
22embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 22embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
23ppproto = { version = "0.1.2"} 23ppproto = { version = "0.1.2"}
24embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 24embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
diff --git a/embassy-net-ppp/src/fmt.rs b/embassy-net-ppp/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-net-ppp/src/fmt.rs
+++ b/embassy-net-ppp/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml
index b6ce20325..e7fb3f455 100644
--- a/embassy-net-wiznet/Cargo.toml
+++ b/embassy-net-wiznet/Cargo.toml
@@ -12,8 +12,8 @@ documentation = "https://docs.embassy.dev/embassy-net-wiznet"
12[dependencies] 12[dependencies]
13embedded-hal = { version = "1.0" } 13embedded-hal = { version = "1.0" }
14embedded-hal-async = { version = "1.0" } 14embedded-hal-async = { version = "1.0" }
15embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } 15embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" }
16embassy-time = { version = "0.3.1", path = "../embassy-time" } 16embassy-time = { version = "0.3.2", path = "../embassy-time" }
17embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 17embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
18defmt = { version = "0.3", optional = true } 18defmt = { version = "0.3", optional = true }
19 19
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index 15b97af47..28bac485b 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -44,6 +44,8 @@ raw = ["smoltcp/socket-raw"]
44tcp = ["smoltcp/socket-tcp"] 44tcp = ["smoltcp/socket-tcp"]
45## Enable DNS support 45## Enable DNS support
46dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"] 46dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"]
47## Enable mDNS support
48mdns = ["dns", "smoltcp/socket-mdns"]
47## Enable DHCPv4 support 49## Enable DHCPv4 support
48dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"] 50dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"]
49## Enable DHCPv4 support with hostname 51## Enable DHCPv4 support with hostname
@@ -72,7 +74,7 @@ smoltcp = { version = "0.11.0", default-features = false, features = [
72] } 74] }
73 75
74embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } 76embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
75embassy-time = { version = "0.3.1", path = "../embassy-time" } 77embassy-time = { version = "0.3.2", path = "../embassy-time" }
76embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 78embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
77embedded-io-async = { version = "0.6.1" } 79embedded-io-async = { version = "0.6.1" }
78 80
diff --git a/embassy-net/src/fmt.rs b/embassy-net/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-net/src/fmt.rs
+++ b/embassy-net/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index 12f5f30b4..56321cec9 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -34,6 +34,8 @@ use embassy_sync::waitqueue::WakerRegistration;
34use embassy_time::{Instant, Timer}; 34use embassy_time::{Instant, Timer};
35#[allow(unused_imports)] 35#[allow(unused_imports)]
36use heapless::Vec; 36use heapless::Vec;
37#[cfg(feature = "dns")]
38pub use smoltcp::config::DNS_MAX_SERVER_COUNT;
37#[cfg(feature = "igmp")] 39#[cfg(feature = "igmp")]
38pub use smoltcp::iface::MulticastError; 40pub use smoltcp::iface::MulticastError;
39#[allow(unused_imports)] 41#[allow(unused_imports)]
@@ -413,8 +415,11 @@ impl<D: Driver> Stack<D> {
413 /// ## Example 415 /// ## Example
414 /// ```ignore 416 /// ```ignore
415 /// let config = embassy_net::Config::dhcpv4(Default::default()); 417 /// let config = embassy_net::Config::dhcpv4(Default::default());
416 ///// Init network stack 418 /// // Init network stack
417 /// static RESOURCES: StaticCell<embassy_net::StackResources<2> = StaticCell::new(); 419 /// // NOTE: DHCP and DNS need one socket slot if enabled. This is why we're
420 /// // provisioning space for 3 sockets here: one for DHCP, one for DNS, and one for your code (e.g. TCP).
421 /// // If you use more sockets you must increase this. If you don't enable DHCP or DNS you can decrease it.
422 /// static RESOURCES: StaticCell<embassy_net::StackResources<3>> = StaticCell::new();
418 /// static STACK: StaticCell<embassy_net::Stack> = StaticCell::new(); 423 /// static STACK: StaticCell<embassy_net::Stack> = StaticCell::new();
419 /// let stack = &*STACK.init(embassy_net::Stack::new( 424 /// let stack = &*STACK.init(embassy_net::Stack::new(
420 /// device, 425 /// device,
@@ -823,9 +828,17 @@ impl<D: Driver> Inner<D> {
823 828
824 // Apply DNS servers 829 // Apply DNS servers
825 #[cfg(feature = "dns")] 830 #[cfg(feature = "dns")]
826 s.sockets 831 if !dns_servers.is_empty() {
827 .get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket) 832 let count = if dns_servers.len() > DNS_MAX_SERVER_COUNT {
828 .update_servers(&dns_servers[..]); 833 warn!("Number of DNS servers exceeds DNS_MAX_SERVER_COUNT, truncating list.");
834 DNS_MAX_SERVER_COUNT
835 } else {
836 dns_servers.len()
837 };
838 s.sockets
839 .get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket)
840 .update_servers(&dns_servers[..count]);
841 }
829 842
830 self.config_waker.wake(); 843 self.config_waker.wake();
831 } 844 }
diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs
index 74eff9dae..b2e3279cc 100644
--- a/embassy-net/src/tcp.rs
+++ b/embassy-net/src/tcp.rs
@@ -79,6 +79,15 @@ impl<'a> TcpReader<'a> {
79 /// 79 ///
80 /// Returns how many bytes were read, or an error. If no data is available, it waits 80 /// Returns how many bytes were read, or an error. If no data is available, it waits
81 /// until there is at least one byte available. 81 /// until there is at least one byte available.
82 ///
83 /// # Note
84 /// A return value of Ok(0) means that we have read all data and the remote
85 /// side has closed our receive half of the socket. The remote can no longer
86 /// send bytes.
87 ///
88 /// The send half of the socket is still open. If you want to reconnect using
89 /// the socket you split this reader off the send half needs to be closed using
90 /// [`abort()`](TcpSocket::abort).
82 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { 91 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
83 self.io.read(buf).await 92 self.io.read(buf).await
84 } 93 }
@@ -273,6 +282,9 @@ impl<'a> TcpSocket<'a> {
273 /// 282 ///
274 /// Returns how many bytes were read, or an error. If no data is available, it waits 283 /// Returns how many bytes were read, or an error. If no data is available, it waits
275 /// until there is at least one byte available. 284 /// until there is at least one byte available.
285 ///
286 /// A return value of Ok(0) means that the socket was closed and is longer
287 /// able to receive any data.
276 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { 288 pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
277 self.io.read(buf).await 289 self.io.read(buf).await
278 } 290 }
@@ -297,6 +309,10 @@ impl<'a> TcpSocket<'a> {
297 /// 309 ///
298 /// If the timeout is set, the socket will be closed if no data is received for the 310 /// If the timeout is set, the socket will be closed if no data is received for the
299 /// specified duration. 311 /// specified duration.
312 ///
313 /// # Note:
314 /// Set a keep alive interval ([`set_keep_alive`] to prevent timeouts when
315 /// the remote could still respond.
300 pub fn set_timeout(&mut self, duration: Option<Duration>) { 316 pub fn set_timeout(&mut self, duration: Option<Duration>) {
301 self.io 317 self.io
302 .with_mut(|s, _| s.set_timeout(duration.map(duration_to_smoltcp))) 318 .with_mut(|s, _| s.set_timeout(duration.map(duration_to_smoltcp)))
@@ -308,6 +324,9 @@ impl<'a> TcpSocket<'a> {
308 /// the specified duration of inactivity. 324 /// the specified duration of inactivity.
309 /// 325 ///
310 /// If not set, the socket will not send keep-alive packets. 326 /// If not set, the socket will not send keep-alive packets.
327 ///
328 /// By setting a [`timeout`](Self::timeout) larger then the keep alive you
329 /// can detect a remote endpoint that no longer answers.
311 pub fn set_keep_alive(&mut self, interval: Option<Duration>) { 330 pub fn set_keep_alive(&mut self, interval: Option<Duration>) {
312 self.io 331 self.io
313 .with_mut(|s, _| s.set_keep_alive(interval.map(duration_to_smoltcp))) 332 .with_mut(|s, _| s.set_keep_alive(interval.map(duration_to_smoltcp)))
@@ -515,7 +534,7 @@ impl<'d> TcpIo<'d> {
515 async fn flush(&mut self) -> Result<(), Error> { 534 async fn flush(&mut self) -> Result<(), Error> {
516 poll_fn(move |cx| { 535 poll_fn(move |cx| {
517 self.with_mut(|s, _| { 536 self.with_mut(|s, _| {
518 let data_pending = s.send_queue() > 0; 537 let data_pending = (s.send_queue() > 0) && s.state() != tcp::State::Closed;
519 let fin_pending = matches!( 538 let fin_pending = matches!(
520 s.state(), 539 s.state(),
521 tcp::State::FinWait1 | tcp::State::Closing | tcp::State::LastAck 540 tcp::State::FinWait1 | tcp::State::Closing | tcp::State::LastAck
@@ -660,12 +679,25 @@ pub mod client {
660 pub struct TcpClient<'d, D: Driver, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> { 679 pub struct TcpClient<'d, D: Driver, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> {
661 stack: &'d Stack<D>, 680 stack: &'d Stack<D>,
662 state: &'d TcpClientState<N, TX_SZ, RX_SZ>, 681 state: &'d TcpClientState<N, TX_SZ, RX_SZ>,
682 socket_timeout: Option<Duration>,
663 } 683 }
664 684
665 impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpClient<'d, D, N, TX_SZ, RX_SZ> { 685 impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpClient<'d, D, N, TX_SZ, RX_SZ> {
666 /// Create a new `TcpClient`. 686 /// Create a new `TcpClient`.
667 pub fn new(stack: &'d Stack<D>, state: &'d TcpClientState<N, TX_SZ, RX_SZ>) -> Self { 687 pub fn new(stack: &'d Stack<D>, state: &'d TcpClientState<N, TX_SZ, RX_SZ>) -> Self {
668 Self { stack, state } 688 Self {
689 stack,
690 state,
691 socket_timeout: None,
692 }
693 }
694
695 /// Set the timeout for each socket created by this `TcpClient`.
696 ///
697 /// If the timeout is set, the socket will be closed if no data is received for the
698 /// specified duration.
699 pub fn set_timeout(&mut self, timeout: Option<Duration>) {
700 self.socket_timeout = timeout;
669 } 701 }
670 } 702 }
671 703
@@ -691,6 +723,7 @@ pub mod client {
691 }; 723 };
692 let remote_endpoint = (addr, remote.port()); 724 let remote_endpoint = (addr, remote.port());
693 let mut socket = TcpConnection::new(&self.stack, self.state)?; 725 let mut socket = TcpConnection::new(&self.stack, self.state)?;
726 socket.socket.set_timeout(self.socket_timeout.clone());
694 socket 727 socket
695 .socket 728 .socket
696 .connect(remote_endpoint) 729 .connect(remote_endpoint)
diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs
index 6e50c4e01..1d5360187 100644
--- a/embassy-net/src/udp.rs
+++ b/embassy-net/src/udp.rs
@@ -138,6 +138,35 @@ impl<'a> UdpSocket<'a> {
138 }) 138 })
139 } 139 }
140 140
141 /// Receive a datagram with a zero-copy function.
142 ///
143 /// When no datagram is available, this method will return `Poll::Pending` and
144 /// register the current task to be notified when a datagram is received.
145 ///
146 /// When a datagram is received, this method will call the provided function
147 /// with the number of bytes received and the remote endpoint and return
148 /// `Poll::Ready` with the function's returned value.
149 pub async fn recv_from_with<F, R>(&mut self, f: F) -> R
150 where
151 F: FnOnce(&[u8], UdpMetadata) -> R,
152 {
153 let mut f = Some(f);
154 poll_fn(move |cx| {
155 self.with_mut(|s, _| {
156 match s.recv() {
157 Ok((buffer, endpoint)) => Poll::Ready(unwrap!(f.take())(buffer, endpoint)),
158 Err(udp::RecvError::Truncated) => unreachable!(),
159 Err(udp::RecvError::Exhausted) => {
160 // socket buffer is empty wait until at least one byte has arrived
161 s.register_recv_waker(cx.waker());
162 Poll::Pending
163 }
164 }
165 })
166 })
167 .await
168 }
169
141 /// Send a datagram to the specified remote endpoint. 170 /// Send a datagram to the specified remote endpoint.
142 /// 171 ///
143 /// This method will wait until the datagram has been sent. 172 /// This method will wait until the datagram has been sent.
@@ -181,6 +210,40 @@ impl<'a> UdpSocket<'a> {
181 }) 210 })
182 } 211 }
183 212
213 /// Send a datagram to the specified remote endpoint with a zero-copy function.
214 ///
215 /// This method will wait until the buffer can fit the requested size before
216 /// calling the function to fill its contents.
217 ///
218 /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)`
219 pub async fn send_to_with<T, F, R>(&mut self, size: usize, remote_endpoint: T, f: F) -> Result<R, SendError>
220 where
221 T: Into<UdpMetadata> + Copy,
222 F: FnOnce(&mut [u8]) -> R,
223 {
224 let mut f = Some(f);
225 poll_fn(move |cx| {
226 self.with_mut(|s, _| {
227 match s.send(size, remote_endpoint) {
228 Ok(buffer) => Poll::Ready(Ok(unwrap!(f.take())(buffer))),
229 Err(udp::SendError::BufferFull) => {
230 s.register_send_waker(cx.waker());
231 Poll::Pending
232 }
233 Err(udp::SendError::Unaddressable) => {
234 // If no sender/outgoing port is specified, there is not really "no route"
235 if s.endpoint().port == 0 {
236 Poll::Ready(Err(SendError::SocketNotBound))
237 } else {
238 Poll::Ready(Err(SendError::NoRoute))
239 }
240 }
241 }
242 })
243 })
244 .await
245 }
246
184 /// Returns the local endpoint of the socket. 247 /// Returns the local endpoint of the socket.
185 pub fn endpoint(&self) -> IpListenEndpoint { 248 pub fn endpoint(&self) -> IpListenEndpoint {
186 self.with(|s, _| s.endpoint()) 249 self.with(|s, _| s.endpoint())
diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md
index 6f07a8c6d..f8d6ab753 100644
--- a/embassy-nrf/CHANGELOG.md
+++ b/embassy-nrf/CHANGELOG.md
@@ -7,24 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased 8## Unreleased
9 9
10- Drop `sealed` mod 10## 0.2.0 - 2024-08-05
11- nrf52840: Add dcdc voltage parameter to configure REG0 regulator 11
12- radio: Add support for IEEE 802.15.4 and BLE via radio peripheral 12- Support for NRF chips:
13- spim: Reduce trace-level messages ("Copying SPIM tx buffer..") 13 - nrf51
14- uart: Add support for rx- or tx-only BufferedUart 14 - nrf9151
15- uart: Implement splitting Rx/Tx 15- Support for new peripherals:
16- spi: Allow specifying OutputDrive for SPI spins 16 - EGU
17- pdm: Fix gain register value derivation 17 - radio - low-level support for IEEE 802.15.4 and BLE via radio peripheral
18- spim: Implement chunked DMA transfers 18- Peripheral changes:
19- spi: Add bounds checks for EasyDMA buffer size 19 - gpio: Drop GPIO Pin generics (API break)
20- uarte: Add support for handling RX errors 20 - pdm: Fix gain register value derivation
21- nrf51: Implement support for nrf51 chip 21 - pwm:
22- pwm: Expose `duty` method 22 - Expose `duty` method
23- pwm: Fix infinite loop 23 - Expose `pwm::PWM_CLK_HZ` and add `is_enabled` method
24- spi: Add support for configuring bit order for bus 24 - Allow specifying OutputDrive for PWM channels
25- pwm: Expose `pwm::PWM_CLK_HZ` and add `is_enabled` method 25 - Fix infinite loop
26- gpio: Drop GPIO Pin generics (API break) 26 - spim:
27- pwm: Allow specifying OutputDrive for PWM channels 27 - Reduce trace-level messages ("Copying SPIM tx buffer..")
28 - Support configuring bit order for bus
29 - Allow specifying OutputDrive for SPI pins
30 - Add bounds checks for EasyDMA buffer size
31 - Implement chunked DMA transfers
32 - uart:
33 - Add support for rx- or tx-only BufferedUart
34 - Implement splitting Rx/Tx
35 - Add support for handling RX errors
36- Miscellaneous changes:
37 - Add `collapse_debuginfo` to fmt.rs macros.
38 - Drop `sealed` mod
39 - nrf52840: Add dcdc voltage parameter to configure REG0 regulator
28 40
29## 0.1.0 - 2024-01-12 41## 0.1.0 - 2024-01-12
30 42
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 02c3bfbbe..3e66d6886 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-nrf" 2name = "embassy-nrf"
3version = "0.1.0" 3version = "0.2.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers" 6description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers"
@@ -40,6 +40,7 @@ rt = [
40 "nrf5340-app-pac?/rt", 40 "nrf5340-app-pac?/rt",
41 "nrf5340-net-pac?/rt", 41 "nrf5340-net-pac?/rt",
42 "nrf9160-pac?/rt", 42 "nrf9160-pac?/rt",
43 "nrf9120-pac?/rt",
43] 44]
44 45
45## Enable features requiring `embassy-time` 46## Enable features requiring `embassy-time`
@@ -96,9 +97,18 @@ nrf5340-app-ns = ["_nrf5340-app", "_ns"]
96## nRF5340 network core 97## nRF5340 network core
97nrf5340-net = ["_nrf5340-net"] 98nrf5340-net = ["_nrf5340-net"]
98## nRF9160 in Secure mode 99## nRF9160 in Secure mode
99nrf9160-s = ["_nrf9160", "_s"] 100nrf9160-s = ["_nrf9160", "_s", "_nrf91"]
100## nRF9160 in Non-Secure mode 101## nRF9160 in Non-Secure mode
101nrf9160-ns = ["_nrf9160", "_ns"] 102nrf9160-ns = ["_nrf9160", "_ns", "_nrf91"]
103## The nRF9120 is the internal part number for the nRF9161 and nRF9151.
104## nRF9120 in Secure mode
105nrf9120-s = ["_nrf9120", "_s", "_nrf91"]
106nrf9151-s = ["nrf9120-s"]
107nrf9161-s = ["nrf9120-s"]
108## nRF9120 in Non-Secure mode
109nrf9120-ns = ["_nrf9120", "_ns", "_nrf91"]
110nrf9151-ns = ["nrf9120-ns"]
111nrf9161-ns = ["nrf9120-ns"]
102 112
103# Features starting with `_` are for internal use only. They're not intended 113# Features starting with `_` are for internal use only. They're not intended
104# to be enabled by other crates, and are not covered by semver guarantees. 114# to be enabled by other crates, and are not covered by semver guarantees.
@@ -107,8 +117,10 @@ _nrf5340-app = ["_nrf5340", "nrf5340-app-pac"]
107_nrf5340-net = ["_nrf5340", "nrf5340-net-pac"] 117_nrf5340-net = ["_nrf5340", "nrf5340-net-pac"]
108_nrf5340 = ["_gpio-p1", "_dppi"] 118_nrf5340 = ["_gpio-p1", "_dppi"]
109_nrf9160 = ["nrf9160-pac", "_dppi"] 119_nrf9160 = ["nrf9160-pac", "_dppi"]
120_nrf9120 = ["nrf9120-pac", "_dppi"]
110_nrf52 = ["_ppi"] 121_nrf52 = ["_ppi"]
111_nrf51 = ["_ppi"] 122_nrf51 = ["_ppi"]
123_nrf91 = []
112 124
113_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768"] 125_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768"]
114 126
@@ -125,10 +137,10 @@ _nrf52832_anomaly_109 = []
125 137
126[dependencies] 138[dependencies]
127embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } 139embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true }
128embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true } 140embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true }
129embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 141embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
130embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } 142embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
131embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 143embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" }
132embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } 144embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" }
133 145
134embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 146embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
@@ -161,3 +173,4 @@ nrf52840-pac = { version = "0.12.0", optional = true }
161nrf5340-app-pac = { version = "0.12.0", optional = true } 173nrf5340-app-pac = { version = "0.12.0", optional = true }
162nrf5340-net-pac = { version = "0.12.0", optional = true } 174nrf5340-net-pac = { version = "0.12.0", optional = true }
163nrf9160-pac = { version = "0.12.0", optional = true } 175nrf9160-pac = { version = "0.12.0", optional = true }
176nrf9120-pac = { version = "0.12.0", optional = true }
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index 8e4064aaa..6d39597c6 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -219,6 +219,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
219 /// # Panics 219 /// # Panics
220 /// 220 ///
221 /// Panics if `rx_buffer.len()` is odd. 221 /// Panics if `rx_buffer.len()` is odd.
222 #[allow(clippy::too_many_arguments)]
222 pub fn new( 223 pub fn new(
223 uarte: impl Peripheral<P = U> + 'd, 224 uarte: impl Peripheral<P = U> + 'd,
224 timer: impl Peripheral<P = T> + 'd, 225 timer: impl Peripheral<P = T> + 'd,
@@ -254,6 +255,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
254 /// # Panics 255 /// # Panics
255 /// 256 ///
256 /// Panics if `rx_buffer.len()` is odd. 257 /// Panics if `rx_buffer.len()` is odd.
258 #[allow(clippy::too_many_arguments)]
257 pub fn new_with_rtscts( 259 pub fn new_with_rtscts(
258 uarte: impl Peripheral<P = U> + 'd, 260 uarte: impl Peripheral<P = U> + 'd,
259 timer: impl Peripheral<P = T> + 'd, 261 timer: impl Peripheral<P = T> + 'd,
@@ -286,6 +288,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
286 ) 288 )
287 } 289 }
288 290
291 #[allow(clippy::too_many_arguments)]
289 fn new_inner( 292 fn new_inner(
290 peri: PeripheralRef<'d, U>, 293 peri: PeripheralRef<'d, U>,
291 timer: PeripheralRef<'d, T>, 294 timer: PeripheralRef<'d, T>,
@@ -355,6 +358,11 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
355 self.tx.write(buf).await 358 self.tx.write(buf).await
356 } 359 }
357 360
361 /// Try writing a buffer without waiting, returning how many bytes were written.
362 pub fn try_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
363 self.tx.try_write(buf)
364 }
365
358 /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. 366 /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
359 pub async fn flush(&mut self) -> Result<(), Error> { 367 pub async fn flush(&mut self) -> Result<(), Error> {
360 self.tx.flush().await 368 self.tx.flush().await
@@ -479,6 +487,29 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> {
479 .await 487 .await
480 } 488 }
481 489
490 /// Try writing a buffer without waiting, returning how many bytes were written.
491 pub fn try_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
492 //trace!("poll_write: {:?}", buf.len());
493 let s = U::buffered_state();
494 let mut tx = unsafe { s.tx_buf.writer() };
495
496 let tx_buf = tx.push_slice();
497 if tx_buf.is_empty() {
498 return Ok(0);
499 }
500
501 let n = min(tx_buf.len(), buf.len());
502 tx_buf[..n].copy_from_slice(&buf[..n]);
503 tx.push_done(n);
504
505 //trace!("poll_write: queued {:?}", n);
506
507 compiler_fence(Ordering::SeqCst);
508 U::Interrupt::pend();
509
510 Ok(n)
511 }
512
482 /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. 513 /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
483 pub async fn flush(&mut self) -> Result<(), Error> { 514 pub async fn flush(&mut self) -> Result<(), Error> {
484 poll_fn(move |cx| { 515 poll_fn(move |cx| {
@@ -534,6 +565,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
534 /// # Panics 565 /// # Panics
535 /// 566 ///
536 /// Panics if `rx_buffer.len()` is odd. 567 /// Panics if `rx_buffer.len()` is odd.
568 #[allow(clippy::too_many_arguments)]
537 pub fn new( 569 pub fn new(
538 uarte: impl Peripheral<P = U> + 'd, 570 uarte: impl Peripheral<P = U> + 'd,
539 timer: impl Peripheral<P = T> + 'd, 571 timer: impl Peripheral<P = T> + 'd,
@@ -564,6 +596,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
564 /// # Panics 596 /// # Panics
565 /// 597 ///
566 /// Panics if `rx_buffer.len()` is odd. 598 /// Panics if `rx_buffer.len()` is odd.
599 #[allow(clippy::too_many_arguments)]
567 pub fn new_with_rts( 600 pub fn new_with_rts(
568 uarte: impl Peripheral<P = U> + 'd, 601 uarte: impl Peripheral<P = U> + 'd,
569 timer: impl Peripheral<P = T> + 'd, 602 timer: impl Peripheral<P = T> + 'd,
@@ -590,6 +623,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
590 ) 623 )
591 } 624 }
592 625
626 #[allow(clippy::too_many_arguments)]
593 fn new_inner( 627 fn new_inner(
594 peri: PeripheralRef<'d, U>, 628 peri: PeripheralRef<'d, U>,
595 timer: PeripheralRef<'d, T>, 629 timer: PeripheralRef<'d, T>,
@@ -614,6 +648,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
614 this 648 this
615 } 649 }
616 650
651 #[allow(clippy::too_many_arguments)]
617 fn new_innerer( 652 fn new_innerer(
618 peri: PeripheralRef<'d, U>, 653 peri: PeripheralRef<'d, U>,
619 timer: PeripheralRef<'d, T>, 654 timer: PeripheralRef<'d, T>,
@@ -766,6 +801,12 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
766 rx.pop_done(amt); 801 rx.pop_done(amt);
767 U::regs().intenset.write(|w| w.rxstarted().set()); 802 U::regs().intenset.write(|w| w.rxstarted().set());
768 } 803 }
804
805 /// we are ready to read if there is data in the buffer
806 fn read_ready() -> Result<bool, Error> {
807 let state = U::buffered_state();
808 Ok(!state.rx_buf.is_empty())
809 }
769} 810}
770 811
771impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarteRx<'a, U, T> { 812impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarteRx<'a, U, T> {
@@ -827,6 +868,18 @@ mod _embedded_io {
827 } 868 }
828 } 869 }
829 870
871 impl<'d, U: UarteInstance, T: TimerInstance + 'd> embedded_io_async::ReadReady for BufferedUarte<'d, U, T> {
872 fn read_ready(&mut self) -> Result<bool, Self::Error> {
873 BufferedUarteRx::<'d, U, T>::read_ready()
874 }
875 }
876
877 impl<'d, U: UarteInstance, T: TimerInstance + 'd> embedded_io_async::ReadReady for BufferedUarteRx<'d, U, T> {
878 fn read_ready(&mut self) -> Result<bool, Self::Error> {
879 Self::read_ready()
880 }
881 }
882
830 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::BufRead for BufferedUarte<'d, U, T> { 883 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::BufRead for BufferedUarte<'d, U, T> {
831 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { 884 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
832 self.fill_buf().await 885 self.fill_buf().await
diff --git a/embassy-nrf/src/chips/nrf9120.rs b/embassy-nrf/src/chips/nrf9120.rs
new file mode 100644
index 000000000..b53510118
--- /dev/null
+++ b/embassy-nrf/src/chips/nrf9120.rs
@@ -0,0 +1,430 @@
1/// Peripheral Access Crate
2#[allow(unused_imports)]
3#[rustfmt::skip]
4pub mod pac {
5 // The nRF9120 has a secure and non-secure (NS) mode.
6 // To avoid cfg spam, we remove _ns or _s suffixes here.
7
8 pub use nrf9120_pac::NVIC_PRIO_BITS;
9
10 #[cfg(feature="rt")]
11 #[doc(no_inline)]
12 pub use nrf9120_pac::interrupt;
13
14 #[doc(no_inline)]
15 pub use nrf9120_pac::{
16 Interrupt,
17
18 cc_host_rgf_s as cc_host_rgf,
19 clock_ns as clock,
20 cryptocell_s as cryptocell,
21 ctrl_ap_peri_s as ctrl_ap_peri,
22 dppic_ns as dppic,
23 egu0_ns as egu0,
24 ficr_s as ficr,
25 fpu_ns as fpu,
26 gpiote0_s as gpiote,
27 i2s_ns as i2s,
28 ipc_ns as ipc,
29 kmu_ns as kmu,
30 nvmc_ns as nvmc,
31 p0_ns as p0,
32 pdm_ns as pdm,
33 power_ns as power,
34 pwm0_ns as pwm0,
35 regulators_ns as regulators,
36 rtc0_ns as rtc0,
37 saadc_ns as saadc,
38 spim0_ns as spim0,
39 spis0_ns as spis0,
40 spu_s as spu,
41 tad_s as tad,
42 timer0_ns as timer0,
43 twim0_ns as twim0,
44 twis0_ns as twis0,
45 uarte0_ns as uarte0,
46 uicr_s as uicr,
47 vmc_ns as vmc,
48 wdt_ns as wdt,
49 };
50
51 /// Non-Secure mode (NS) peripherals
52 pub mod ns {
53 #[doc(no_inline)]
54 pub use nrf9120_pac::{
55 CLOCK_NS as CLOCK,
56 DPPIC_NS as DPPIC,
57 EGU0_NS as EGU0,
58 EGU1_NS as EGU1,
59 EGU2_NS as EGU2,
60 EGU3_NS as EGU3,
61 EGU4_NS as EGU4,
62 EGU5_NS as EGU5,
63 FPU_NS as FPU,
64 GPIOTE1_NS as GPIOTE1,
65 I2S_NS as I2S,
66 IPC_NS as IPC,
67 KMU_NS as KMU,
68 NVMC_NS as NVMC,
69 P0_NS as P0,
70 PDM_NS as PDM,
71 POWER_NS as POWER,
72 PWM0_NS as PWM0,
73 PWM1_NS as PWM1,
74 PWM2_NS as PWM2,
75 PWM3_NS as PWM3,
76 REGULATORS_NS as REGULATORS,
77 RTC0_NS as RTC0,
78 RTC1_NS as RTC1,
79 SAADC_NS as SAADC,
80 SPIM0_NS as SPIM0,
81 SPIM1_NS as SPIM1,
82 SPIM2_NS as SPIM2,
83 SPIM3_NS as SPIM3,
84 SPIS0_NS as SPIS0,
85 SPIS1_NS as SPIS1,
86 SPIS2_NS as SPIS2,
87 SPIS3_NS as SPIS3,
88 TIMER0_NS as TIMER0,
89 TIMER1_NS as TIMER1,
90 TIMER2_NS as TIMER2,
91 TWIM0_NS as TWIM0,
92 TWIM1_NS as TWIM1,
93 TWIM2_NS as TWIM2,
94 TWIM3_NS as TWIM3,
95 TWIS0_NS as TWIS0,
96 TWIS1_NS as TWIS1,
97 TWIS2_NS as TWIS2,
98 TWIS3_NS as TWIS3,
99 UARTE0_NS as UARTE0,
100 UARTE1_NS as UARTE1,
101 UARTE2_NS as UARTE2,
102 UARTE3_NS as UARTE3,
103 VMC_NS as VMC,
104 WDT_NS as WDT,
105 };
106 }
107
108 /// Secure mode (S) peripherals
109 pub mod s {
110 #[doc(no_inline)]
111 pub use nrf9120_pac::{
112 CC_HOST_RGF_S as CC_HOST_RGF,
113 CLOCK_S as CLOCK,
114 CRYPTOCELL_S as CRYPTOCELL,
115 CTRL_AP_PERI_S as CTRL_AP_PERI,
116 DPPIC_S as DPPIC,
117 EGU0_S as EGU0,
118 EGU1_S as EGU1,
119 EGU2_S as EGU2,
120 EGU3_S as EGU3,
121 EGU4_S as EGU4,
122 EGU5_S as EGU5,
123 FICR_S as FICR,
124 FPU as FPU,
125 GPIOTE0_S as GPIOTE0,
126 I2S_S as I2S,
127 IPC_S as IPC,
128 KMU_S as KMU,
129 NVMC_S as NVMC,
130 P0_S as P0,
131 PDM_S as PDM,
132 POWER_S as POWER,
133 PWM0_S as PWM0,
134 PWM1_S as PWM1,
135 PWM2_S as PWM2,
136 PWM3_S as PWM3,
137 REGULATORS_S as REGULATORS,
138 RTC0_S as RTC0,
139 RTC1_S as RTC1,
140 SAADC_S as SAADC,
141 SPIM0_S as SPIM0,
142 SPIM1_S as SPIM1,
143 SPIM2_S as SPIM2,
144 SPIM3_S as SPIM3,
145 SPIS0_S as SPIS0,
146 SPIS1_S as SPIS1,
147 SPIS2_S as SPIS2,
148 SPIS3_S as SPIS3,
149 SPU_S as SPU,
150 TAD_S as TAD,
151 TIMER0_S as TIMER0,
152 TIMER1_S as TIMER1,
153 TIMER2_S as TIMER2,
154 TWIM0_S as TWIM0,
155 TWIM1_S as TWIM1,
156 TWIM2_S as TWIM2,
157 TWIM3_S as TWIM3,
158 TWIS0_S as TWIS0,
159 TWIS1_S as TWIS1,
160 TWIS2_S as TWIS2,
161 TWIS3_S as TWIS3,
162 UARTE0_S as UARTE0,
163 UARTE1_S as UARTE1,
164 UARTE2_S as UARTE2,
165 UARTE3_S as UARTE3,
166 UICR_S as UICR,
167 VMC_S as VMC,
168 WDT_S as WDT,
169 };
170 }
171
172 #[cfg(feature = "_ns")]
173 pub use ns::*;
174 #[cfg(feature = "_s")]
175 pub use s::*;
176}
177
178/// The maximum buffer size that the EasyDMA can send/recv in one operation.
179pub const EASY_DMA_SIZE: usize = (1 << 13) - 1;
180pub const FORCE_COPY_BUFFER_SIZE: usize = 1024;
181
182pub const FLASH_SIZE: usize = 1024 * 1024;
183
184embassy_hal_internal::peripherals! {
185 // RTC
186 RTC0,
187 RTC1,
188
189 // WDT
190 WDT,
191
192 // NVMC
193 NVMC,
194
195 // UARTE, TWI & SPI
196 SERIAL0,
197 SERIAL1,
198 SERIAL2,
199 SERIAL3,
200
201 // SAADC
202 SAADC,
203
204 // PWM
205 PWM0,
206 PWM1,
207 PWM2,
208 PWM3,
209
210 // TIMER
211 TIMER0,
212 TIMER1,
213 TIMER2,
214
215 // GPIOTE
216 GPIOTE_CH0,
217 GPIOTE_CH1,
218 GPIOTE_CH2,
219 GPIOTE_CH3,
220 GPIOTE_CH4,
221 GPIOTE_CH5,
222 GPIOTE_CH6,
223 GPIOTE_CH7,
224
225 // PPI
226 PPI_CH0,
227 PPI_CH1,
228 PPI_CH2,
229 PPI_CH3,
230 PPI_CH4,
231 PPI_CH5,
232 PPI_CH6,
233 PPI_CH7,
234 PPI_CH8,
235 PPI_CH9,
236 PPI_CH10,
237 PPI_CH11,
238 PPI_CH12,
239 PPI_CH13,
240 PPI_CH14,
241 PPI_CH15,
242
243 PPI_GROUP0,
244 PPI_GROUP1,
245 PPI_GROUP2,
246 PPI_GROUP3,
247 PPI_GROUP4,
248 PPI_GROUP5,
249
250 // GPIO port 0
251 P0_00,
252 P0_01,
253 P0_02,
254 P0_03,
255 P0_04,
256 P0_05,
257 P0_06,
258 P0_07,
259 P0_08,
260 P0_09,
261 P0_10,
262 P0_11,
263 P0_12,
264 P0_13,
265 P0_14,
266 P0_15,
267 P0_16,
268 P0_17,
269 P0_18,
270 P0_19,
271 P0_20,
272 P0_21,
273 P0_22,
274 P0_23,
275 P0_24,
276 P0_25,
277 P0_26,
278 P0_27,
279 P0_28,
280 P0_29,
281 P0_30,
282 P0_31,
283
284 // PDM
285 PDM,
286
287 // EGU
288 EGU0,
289 EGU1,
290 EGU2,
291 EGU3,
292 EGU4,
293 EGU5,
294}
295
296impl_uarte!(SERIAL0, UARTE0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0);
297impl_uarte!(SERIAL1, UARTE1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1);
298impl_uarte!(SERIAL2, UARTE2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2);
299impl_uarte!(SERIAL3, UARTE3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3);
300
301impl_spim!(SERIAL0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0);
302impl_spim!(SERIAL1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1);
303impl_spim!(SERIAL2, SPIM2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2);
304impl_spim!(SERIAL3, SPIM3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3);
305
306impl_spis!(SERIAL0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0);
307impl_spis!(SERIAL1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1);
308impl_spis!(SERIAL2, SPIS2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2);
309impl_spis!(SERIAL3, SPIS3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3);
310
311impl_twim!(SERIAL0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0);
312impl_twim!(SERIAL1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1);
313impl_twim!(SERIAL2, TWIM2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2);
314impl_twim!(SERIAL3, TWIM3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3);
315
316impl_twis!(SERIAL0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0);
317impl_twis!(SERIAL1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1);
318impl_twis!(SERIAL2, TWIS2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2);
319impl_twis!(SERIAL3, TWIS3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3);
320
321impl_pwm!(PWM0, PWM0, PWM0);
322impl_pwm!(PWM1, PWM1, PWM1);
323impl_pwm!(PWM2, PWM2, PWM2);
324impl_pwm!(PWM3, PWM3, PWM3);
325
326impl_pdm!(PDM, PDM, PDM);
327
328impl_timer!(TIMER0, TIMER0, TIMER0);
329impl_timer!(TIMER1, TIMER1, TIMER1);
330impl_timer!(TIMER2, TIMER2, TIMER2);
331
332impl_pin!(P0_00, 0, 0);
333impl_pin!(P0_01, 0, 1);
334impl_pin!(P0_02, 0, 2);
335impl_pin!(P0_03, 0, 3);
336impl_pin!(P0_04, 0, 4);
337impl_pin!(P0_05, 0, 5);
338impl_pin!(P0_06, 0, 6);
339impl_pin!(P0_07, 0, 7);
340impl_pin!(P0_08, 0, 8);
341impl_pin!(P0_09, 0, 9);
342impl_pin!(P0_10, 0, 10);
343impl_pin!(P0_11, 0, 11);
344impl_pin!(P0_12, 0, 12);
345impl_pin!(P0_13, 0, 13);
346impl_pin!(P0_14, 0, 14);
347impl_pin!(P0_15, 0, 15);
348impl_pin!(P0_16, 0, 16);
349impl_pin!(P0_17, 0, 17);
350impl_pin!(P0_18, 0, 18);
351impl_pin!(P0_19, 0, 19);
352impl_pin!(P0_20, 0, 20);
353impl_pin!(P0_21, 0, 21);
354impl_pin!(P0_22, 0, 22);
355impl_pin!(P0_23, 0, 23);
356impl_pin!(P0_24, 0, 24);
357impl_pin!(P0_25, 0, 25);
358impl_pin!(P0_26, 0, 26);
359impl_pin!(P0_27, 0, 27);
360impl_pin!(P0_28, 0, 28);
361impl_pin!(P0_29, 0, 29);
362impl_pin!(P0_30, 0, 30);
363impl_pin!(P0_31, 0, 31);
364
365impl_ppi_channel!(PPI_CH0, 0 => configurable);
366impl_ppi_channel!(PPI_CH1, 1 => configurable);
367impl_ppi_channel!(PPI_CH2, 2 => configurable);
368impl_ppi_channel!(PPI_CH3, 3 => configurable);
369impl_ppi_channel!(PPI_CH4, 4 => configurable);
370impl_ppi_channel!(PPI_CH5, 5 => configurable);
371impl_ppi_channel!(PPI_CH6, 6 => configurable);
372impl_ppi_channel!(PPI_CH7, 7 => configurable);
373impl_ppi_channel!(PPI_CH8, 8 => configurable);
374impl_ppi_channel!(PPI_CH9, 9 => configurable);
375impl_ppi_channel!(PPI_CH10, 10 => configurable);
376impl_ppi_channel!(PPI_CH11, 11 => configurable);
377impl_ppi_channel!(PPI_CH12, 12 => configurable);
378impl_ppi_channel!(PPI_CH13, 13 => configurable);
379impl_ppi_channel!(PPI_CH14, 14 => configurable);
380impl_ppi_channel!(PPI_CH15, 15 => configurable);
381
382impl_saadc_input!(P0_13, ANALOG_INPUT0);
383impl_saadc_input!(P0_14, ANALOG_INPUT1);
384impl_saadc_input!(P0_15, ANALOG_INPUT2);
385impl_saadc_input!(P0_16, ANALOG_INPUT3);
386impl_saadc_input!(P0_17, ANALOG_INPUT4);
387impl_saadc_input!(P0_18, ANALOG_INPUT5);
388impl_saadc_input!(P0_19, ANALOG_INPUT6);
389impl_saadc_input!(P0_20, ANALOG_INPUT7);
390
391impl_egu!(EGU0, EGU0, EGU0);
392impl_egu!(EGU1, EGU1, EGU1);
393impl_egu!(EGU2, EGU2, EGU2);
394impl_egu!(EGU3, EGU3, EGU3);
395impl_egu!(EGU4, EGU4, EGU4);
396impl_egu!(EGU5, EGU5, EGU5);
397
398embassy_hal_internal::interrupt_mod!(
399 SPU,
400 CLOCK_POWER,
401 SPIM0_SPIS0_TWIM0_TWIS0_UARTE0,
402 SPIM1_SPIS1_TWIM1_TWIS1_UARTE1,
403 SPIM2_SPIS2_TWIM2_TWIS2_UARTE2,
404 SPIM3_SPIS3_TWIM3_TWIS3_UARTE3,
405 GPIOTE0,
406 SAADC,
407 TIMER0,
408 TIMER1,
409 TIMER2,
410 RTC0,
411 RTC1,
412 WDT,
413 EGU0,
414 EGU1,
415 EGU2,
416 EGU3,
417 EGU4,
418 EGU5,
419 PWM0,
420 PWM1,
421 PWM2,
422 PDM,
423 PWM3,
424 I2S,
425 IPC,
426 FPU,
427 GPIOTE1,
428 KMU,
429 CRYPTOCELL,
430);
diff --git a/embassy-nrf/src/fmt.rs b/embassy-nrf/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-nrf/src/fmt.rs
+++ b/embassy-nrf/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs
index 7b272dca0..dbc26ea3f 100644
--- a/embassy-nrf/src/gpio.rs
+++ b/embassy-nrf/src/gpio.rs
@@ -534,11 +534,13 @@ mod eh02 {
534 type Error = Infallible; 534 type Error = Infallible;
535 535
536 fn set_high(&mut self) -> Result<(), Self::Error> { 536 fn set_high(&mut self) -> Result<(), Self::Error> {
537 Ok(self.set_high()) 537 self.set_high();
538 Ok(())
538 } 539 }
539 540
540 fn set_low(&mut self) -> Result<(), Self::Error> { 541 fn set_low(&mut self) -> Result<(), Self::Error> {
541 Ok(self.set_low()) 542 self.set_low();
543 Ok(())
542 } 544 }
543 } 545 }
544 546
@@ -580,11 +582,13 @@ mod eh02 {
580 type Error = Infallible; 582 type Error = Infallible;
581 583
582 fn set_high(&mut self) -> Result<(), Self::Error> { 584 fn set_high(&mut self) -> Result<(), Self::Error> {
583 Ok(self.set_high()) 585 self.set_high();
586 Ok(())
584 } 587 }
585 588
586 fn set_low(&mut self) -> Result<(), Self::Error> { 589 fn set_low(&mut self) -> Result<(), Self::Error> {
587 Ok(self.set_low()) 590 self.set_low();
591 Ok(())
588 } 592 }
589 } 593 }
590 594
@@ -628,11 +632,13 @@ impl<'d> embedded_hal_1::digital::ErrorType for Output<'d> {
628 632
629impl<'d> embedded_hal_1::digital::OutputPin for Output<'d> { 633impl<'d> embedded_hal_1::digital::OutputPin for Output<'d> {
630 fn set_high(&mut self) -> Result<(), Self::Error> { 634 fn set_high(&mut self) -> Result<(), Self::Error> {
631 Ok(self.set_high()) 635 self.set_high();
636 Ok(())
632 } 637 }
633 638
634 fn set_low(&mut self) -> Result<(), Self::Error> { 639 fn set_low(&mut self) -> Result<(), Self::Error> {
635 Ok(self.set_low()) 640 self.set_low();
641 Ok(())
636 } 642 }
637} 643}
638 644
@@ -665,11 +671,13 @@ impl<'d> embedded_hal_1::digital::InputPin for Flex<'d> {
665 671
666impl<'d> embedded_hal_1::digital::OutputPin for Flex<'d> { 672impl<'d> embedded_hal_1::digital::OutputPin for Flex<'d> {
667 fn set_high(&mut self) -> Result<(), Self::Error> { 673 fn set_high(&mut self) -> Result<(), Self::Error> {
668 Ok(self.set_high()) 674 self.set_high();
675 Ok(())
669 } 676 }
670 677
671 fn set_low(&mut self) -> Result<(), Self::Error> { 678 fn set_low(&mut self) -> Result<(), Self::Error> {
672 Ok(self.set_low()) 679 self.set_low();
680 Ok(())
673 } 681 }
674} 682}
675 683
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index a74b3157b..9d97c7be9 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -53,9 +53,9 @@ pub enum OutputChannelPolarity {
53 53
54fn regs() -> &'static pac::gpiote::RegisterBlock { 54fn regs() -> &'static pac::gpiote::RegisterBlock {
55 cfg_if::cfg_if! { 55 cfg_if::cfg_if! {
56 if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s"))] { 56 if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s", feature="nrf9120-s"))] {
57 unsafe { &*pac::GPIOTE0::ptr() } 57 unsafe { &*pac::GPIOTE0::ptr() }
58 } else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns"))] { 58 } else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns", feature="nrf9120-ns"))] {
59 unsafe { &*pac::GPIOTE1::ptr() } 59 unsafe { &*pac::GPIOTE1::ptr() }
60 } else { 60 } else {
61 unsafe { &*pac::GPIOTE::ptr() } 61 unsafe { &*pac::GPIOTE::ptr() }
@@ -81,9 +81,9 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
81 } 81 }
82 82
83 // Enable interrupts 83 // Enable interrupts
84 #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))] 84 #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s", feature = "nrf9120-s"))]
85 let irq = interrupt::GPIOTE0; 85 let irq = interrupt::GPIOTE0;
86 #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))] 86 #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns", feature = "nrf9120-ns"))]
87 let irq = interrupt::GPIOTE1; 87 let irq = interrupt::GPIOTE1;
88 #[cfg(any(feature = "_nrf51", feature = "_nrf52", feature = "nrf5340-net"))] 88 #[cfg(any(feature = "_nrf51", feature = "_nrf52", feature = "nrf5340-net"))]
89 let irq = interrupt::GPIOTE; 89 let irq = interrupt::GPIOTE;
@@ -96,14 +96,14 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
96 g.intenset.write(|w| w.port().set()); 96 g.intenset.write(|w| w.port().set());
97} 97}
98 98
99#[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))] 99#[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s", feature = "nrf9120-s"))]
100#[cfg(feature = "rt")] 100#[cfg(feature = "rt")]
101#[interrupt] 101#[interrupt]
102fn GPIOTE0() { 102fn GPIOTE0() {
103 unsafe { handle_gpiote_interrupt() }; 103 unsafe { handle_gpiote_interrupt() };
104} 104}
105 105
106#[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))] 106#[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns", feature = "nrf9120-ns"))]
107#[cfg(feature = "rt")] 107#[cfg(feature = "rt")]
108#[interrupt] 108#[interrupt]
109fn GPIOTE1() { 109fn GPIOTE1() {
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 05b52f687..13623dd1c 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -24,8 +24,36 @@
24 feature = "nrf5340-net", 24 feature = "nrf5340-net",
25 feature = "nrf9160-s", 25 feature = "nrf9160-s",
26 feature = "nrf9160-ns", 26 feature = "nrf9160-ns",
27 feature = "nrf9120-s",
28 feature = "nrf9120-ns",
29 feature = "nrf9151-s",
30 feature = "nrf9151-ns",
31 feature = "nrf9161-s",
32 feature = "nrf9161-ns",
27)))] 33)))]
28compile_error!("No chip feature activated. You must activate exactly one of the following features: nrf52810, nrf52811, nrf52832, nrf52833, nrf52840"); 34compile_error!(
35 "No chip feature activated. You must activate exactly one of the following features:
36 nrf51,
37 nrf52805,
38 nrf52810,
39 nrf52811,
40 nrf52820,
41 nrf52832,
42 nrf52833,
43 nrf52840,
44 nrf5340-app-s,
45 nrf5340-app-ns,
46 nrf5340-net,
47 nrf9160-s,
48 nrf9160-ns,
49 nrf9120-s,
50 nrf9120-ns,
51 nrf9151-s,
52 nrf9151-ns,
53 nrf9161-s,
54 nrf9161-ns,
55 "
56);
29 57
30#[cfg(all(feature = "reset-pin-as-gpio", not(feature = "_nrf52")))] 58#[cfg(all(feature = "reset-pin-as-gpio", not(feature = "_nrf52")))]
31compile_error!("feature `reset-pin-as-gpio` is only valid for nRF52 series chips."); 59compile_error!("feature `reset-pin-as-gpio` is only valid for nRF52 series chips.");
@@ -47,7 +75,7 @@ pub mod gpio;
47pub mod gpiote; 75pub mod gpiote;
48 76
49// TODO: tested on other chips 77// TODO: tested on other chips
50#[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340-app")))] 78#[cfg(not(any(feature = "_nrf91", feature = "_nrf5340-app")))]
51pub mod radio; 79pub mod radio;
52 80
53#[cfg(not(feature = "nrf51"))] 81#[cfg(not(feature = "nrf51"))]
@@ -62,7 +90,7 @@ pub mod nvmc;
62 feature = "nrf52833", 90 feature = "nrf52833",
63 feature = "nrf52840", 91 feature = "nrf52840",
64 feature = "_nrf5340-app", 92 feature = "_nrf5340-app",
65 feature = "_nrf9160" 93 feature = "_nrf91",
66))] 94))]
67pub mod pdm; 95pub mod pdm;
68pub mod ppi; 96pub mod ppi;
@@ -73,11 +101,11 @@ pub mod ppi;
73 feature = "_nrf5340-net" 101 feature = "_nrf5340-net"
74)))] 102)))]
75pub mod pwm; 103pub mod pwm;
76#[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340-net")))] 104#[cfg(not(any(feature = "nrf51", feature = "_nrf91", feature = "_nrf5340-net")))]
77pub mod qdec; 105pub mod qdec;
78#[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))] 106#[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))]
79pub mod qspi; 107pub mod qspi;
80#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf9160")))] 108#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))]
81pub mod rng; 109pub mod rng;
82#[cfg(not(any(feature = "nrf51", feature = "nrf52820", feature = "_nrf5340-net")))] 110#[cfg(not(any(feature = "nrf51", feature = "nrf52820", feature = "_nrf5340-net")))]
83pub mod saadc; 111pub mod saadc;
@@ -85,7 +113,7 @@ pub mod saadc;
85pub mod spim; 113pub mod spim;
86#[cfg(not(feature = "nrf51"))] 114#[cfg(not(feature = "nrf51"))]
87pub mod spis; 115pub mod spis;
88#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 116#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
89pub mod temp; 117pub mod temp;
90pub mod timer; 118pub mod timer;
91#[cfg(not(feature = "nrf51"))] 119#[cfg(not(feature = "nrf51"))]
@@ -116,6 +144,7 @@ pub mod wdt;
116#[cfg_attr(feature = "_nrf5340-app", path = "chips/nrf5340_app.rs")] 144#[cfg_attr(feature = "_nrf5340-app", path = "chips/nrf5340_app.rs")]
117#[cfg_attr(feature = "_nrf5340-net", path = "chips/nrf5340_net.rs")] 145#[cfg_attr(feature = "_nrf5340-net", path = "chips/nrf5340_net.rs")]
118#[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")] 146#[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")]
147#[cfg_attr(feature = "_nrf9120", path = "chips/nrf9120.rs")]
119mod chip; 148mod chip;
120 149
121/// Macro to bind interrupts to handlers. 150/// Macro to bind interrupts to handlers.
@@ -196,15 +225,15 @@ pub mod config {
196 /// Internal RC oscillator 225 /// Internal RC oscillator
197 InternalRC, 226 InternalRC,
198 /// Synthesized from the high frequency clock source. 227 /// Synthesized from the high frequency clock source.
199 #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 228 #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
200 Synthesized, 229 Synthesized,
201 /// External source from xtal. 230 /// External source from xtal.
202 ExternalXtal, 231 ExternalXtal,
203 /// External source from xtal with low swing applied. 232 /// External source from xtal with low swing applied.
204 #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 233 #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
205 ExternalLowSwing, 234 ExternalLowSwing,
206 /// External source from xtal with full swing applied. 235 /// External source from xtal with full swing applied.
207 #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 236 #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
208 ExternalFullSwing, 237 ExternalFullSwing,
209 } 238 }
210 239
@@ -222,7 +251,7 @@ pub mod config {
222 } 251 }
223 252
224 /// Settings for enabling the built in DCDC converters. 253 /// Settings for enabling the built in DCDC converters.
225 #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 254 #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
226 pub struct DcdcConfig { 255 pub struct DcdcConfig {
227 /// Config for the first stage DCDC (VDDH -> VDD), if disabled LDO will be used. 256 /// Config for the first stage DCDC (VDDH -> VDD), if disabled LDO will be used.
228 #[cfg(feature = "nrf52840")] 257 #[cfg(feature = "nrf52840")]
@@ -264,7 +293,7 @@ pub mod config {
264 } 293 }
265 294
266 /// Settings for enabling the built in DCDC converter. 295 /// Settings for enabling the built in DCDC converter.
267 #[cfg(feature = "_nrf9160")] 296 #[cfg(feature = "_nrf91")]
268 pub struct DcdcConfig { 297 pub struct DcdcConfig {
269 /// Config for the main rail, if disabled LDO will be used. 298 /// Config for the main rail, if disabled LDO will be used.
270 pub regmain: bool, 299 pub regmain: bool,
@@ -298,7 +327,7 @@ pub mod config {
298 // xtals if they know they have them. 327 // xtals if they know they have them.
299 hfclk_source: HfclkSource::Internal, 328 hfclk_source: HfclkSource::Internal,
300 lfclk_source: LfclkSource::InternalRC, 329 lfclk_source: LfclkSource::InternalRC,
301 #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 330 #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
302 dcdc: DcdcConfig { 331 dcdc: DcdcConfig {
303 #[cfg(feature = "nrf52840")] 332 #[cfg(feature = "nrf52840")]
304 reg0: false, 333 reg0: false,
@@ -312,7 +341,7 @@ pub mod config {
312 regmain: false, 341 regmain: false,
313 regradio: false, 342 regradio: false,
314 }, 343 },
315 #[cfg(feature = "_nrf9160")] 344 #[cfg(feature = "_nrf91")]
316 dcdc: DcdcConfig { regmain: false }, 345 dcdc: DcdcConfig { regmain: false },
317 #[cfg(feature = "gpiote")] 346 #[cfg(feature = "gpiote")]
318 gpiote_interrupt_priority: crate::interrupt::Priority::P0, 347 gpiote_interrupt_priority: crate::interrupt::Priority::P0,
@@ -329,7 +358,7 @@ pub mod config {
329 } 358 }
330} 359}
331 360
332#[cfg(feature = "_nrf9160")] 361#[cfg(feature = "_nrf91")]
333#[allow(unused)] 362#[allow(unused)]
334mod consts { 363mod consts {
335 pub const UICR_APPROTECT: *mut u32 = 0x00FF8000 as *mut u32; 364 pub const UICR_APPROTECT: *mut u32 = 0x00FF8000 as *mut u32;
@@ -468,7 +497,7 @@ pub fn init(config: config::Config) -> Peripherals {
468 // UICR.APPROTECT = Enabled 497 // UICR.APPROTECT = Enabled
469 let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_ENABLED); 498 let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_ENABLED);
470 needs_reset |= res == WriteResult::Written; 499 needs_reset |= res == WriteResult::Written;
471 #[cfg(any(feature = "_nrf5340-app", feature = "_nrf9160"))] 500 #[cfg(any(feature = "_nrf5340-app", feature = "_nrf91"))]
472 { 501 {
473 let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_ENABLED); 502 let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_ENABLED);
474 needs_reset |= res == WriteResult::Written; 503 needs_reset |= res == WriteResult::Written;
@@ -552,7 +581,7 @@ pub fn init(config: config::Config) -> Peripherals {
552 } 581 }
553 582
554 // Configure LFCLK. 583 // Configure LFCLK.
555 #[cfg(not(any(feature = "nrf51", feature = "_nrf5340", feature = "_nrf9160")))] 584 #[cfg(not(any(feature = "nrf51", feature = "_nrf5340", feature = "_nrf91")))]
556 match config.lfclk_source { 585 match config.lfclk_source {
557 config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()), 586 config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()),
558 config::LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()), 587 config::LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()),
@@ -572,7 +601,7 @@ pub fn init(config: config::Config) -> Peripherals {
572 w 601 w
573 }), 602 }),
574 } 603 }
575 #[cfg(feature = "_nrf9160")] 604 #[cfg(feature = "_nrf91")]
576 match config.lfclk_source { 605 match config.lfclk_source {
577 config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().lfrc()), 606 config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().lfrc()),
578 config::LfclkSource::ExternalXtal => r.lfclksrc.write(|w| w.src().lfxo()), 607 config::LfclkSource::ExternalXtal => r.lfclksrc.write(|w| w.src().lfxo()),
@@ -585,7 +614,7 @@ pub fn init(config: config::Config) -> Peripherals {
585 r.tasks_lfclkstart.write(|w| unsafe { w.bits(1) }); 614 r.tasks_lfclkstart.write(|w| unsafe { w.bits(1) });
586 while r.events_lfclkstarted.read().bits() == 0 {} 615 while r.events_lfclkstarted.read().bits() == 0 {}
587 616
588 #[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 617 #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
589 { 618 {
590 // Setup DCDCs. 619 // Setup DCDCs.
591 let pwr = unsafe { &*pac::POWER::ptr() }; 620 let pwr = unsafe { &*pac::POWER::ptr() };
@@ -597,7 +626,7 @@ pub fn init(config: config::Config) -> Peripherals {
597 pwr.dcdcen.write(|w| w.dcdcen().set_bit()); 626 pwr.dcdcen.write(|w| w.dcdcen().set_bit());
598 } 627 }
599 } 628 }
600 #[cfg(feature = "_nrf9160")] 629 #[cfg(feature = "_nrf91")]
601 { 630 {
602 // Setup DCDC. 631 // Setup DCDC.
603 let reg = unsafe { &*pac::REGULATORS::ptr() }; 632 let reg = unsafe { &*pac::REGULATORS::ptr() };
@@ -629,7 +658,7 @@ pub fn init(config: config::Config) -> Peripherals {
629 time_driver::init(config.time_interrupt_priority); 658 time_driver::init(config.time_interrupt_priority);
630 659
631 // Disable UARTE (enabled by default for some reason) 660 // Disable UARTE (enabled by default for some reason)
632 #[cfg(feature = "_nrf9160")] 661 #[cfg(feature = "_nrf91")]
633 unsafe { 662 unsafe {
634 (*pac::UARTE0::ptr()).enable.write(|w| w.enable().disabled()); 663 (*pac::UARTE0::ptr()).enable.write(|w| w.enable().disabled());
635 (*pac::UARTE1::ptr()).enable.write(|w| w.enable().disabled()); 664 (*pac::UARTE1::ptr()).enable.write(|w| w.enable().disabled());
diff --git a/embassy-nrf/src/nvmc.rs b/embassy-nrf/src/nvmc.rs
index 4f9eda167..9b17e7da0 100644
--- a/embassy-nrf/src/nvmc.rs
+++ b/embassy-nrf/src/nvmc.rs
@@ -60,23 +60,23 @@ impl<'d> Nvmc<'d> {
60 while p.ready.read().ready().is_busy() {} 60 while p.ready.read().ready().is_busy() {}
61 } 61 }
62 62
63 #[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340")))] 63 #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))]
64 fn wait_ready_write(&mut self) { 64 fn wait_ready_write(&mut self) {
65 self.wait_ready(); 65 self.wait_ready();
66 } 66 }
67 67
68 #[cfg(any(feature = "_nrf9160", feature = "_nrf5340"))] 68 #[cfg(any(feature = "_nrf91", feature = "_nrf5340"))]
69 fn wait_ready_write(&mut self) { 69 fn wait_ready_write(&mut self) {
70 let p = Self::regs(); 70 let p = Self::regs();
71 while p.readynext.read().readynext().is_busy() {} 71 while p.readynext.read().readynext().is_busy() {}
72 } 72 }
73 73
74 #[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340")))] 74 #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))]
75 fn erase_page(&mut self, page_addr: u32) { 75 fn erase_page(&mut self, page_addr: u32) {
76 Self::regs().erasepage().write(|w| unsafe { w.bits(page_addr) }); 76 Self::regs().erasepage().write(|w| unsafe { w.bits(page_addr) });
77 } 77 }
78 78
79 #[cfg(any(feature = "_nrf9160", feature = "_nrf5340"))] 79 #[cfg(any(feature = "_nrf91", feature = "_nrf5340"))]
80 fn erase_page(&mut self, page_addr: u32) { 80 fn erase_page(&mut self, page_addr: u32) {
81 let first_page_word = page_addr as *mut u32; 81 let first_page_word = page_addr as *mut u32;
82 unsafe { 82 unsafe {
diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs
index c1501e02e..5160fe3c4 100644
--- a/embassy-nrf/src/pdm.rs
+++ b/embassy-nrf/src/pdm.rs
@@ -21,7 +21,7 @@ pub use crate::pac::pdm::pdmclkctrl::FREQ_A as Frequency;
21 feature = "nrf52840", 21 feature = "nrf52840",
22 feature = "nrf52833", 22 feature = "nrf52833",
23 feature = "_nrf5340-app", 23 feature = "_nrf5340-app",
24 feature = "_nrf9160", 24 feature = "_nrf91",
25))] 25))]
26pub use crate::pac::pdm::ratio::RATIO_A as Ratio; 26pub use crate::pac::pdm::ratio::RATIO_A as Ratio;
27use crate::{interrupt, Peripheral}; 27use crate::{interrupt, Peripheral};
@@ -121,7 +121,7 @@ impl<'d, T: Instance> Pdm<'d, T> {
121 feature = "nrf52840", 121 feature = "nrf52840",
122 feature = "nrf52833", 122 feature = "nrf52833",
123 feature = "_nrf5340-app", 123 feature = "_nrf5340-app",
124 feature = "_nrf9160", 124 feature = "_nrf91",
125 ))] 125 ))]
126 r.ratio.write(|w| w.ratio().variant(config.ratio)); 126 r.ratio.write(|w| w.ratio().variant(config.ratio));
127 r.mode.write(|w| { 127 r.mode.write(|w| {
@@ -374,7 +374,7 @@ pub struct Config {
374 feature = "nrf52840", 374 feature = "nrf52840",
375 feature = "nrf52833", 375 feature = "nrf52833",
376 feature = "_nrf5340-app", 376 feature = "_nrf5340-app",
377 feature = "_nrf9160", 377 feature = "_nrf91",
378 ))] 378 ))]
379 pub ratio: Ratio, 379 pub ratio: Ratio,
380 /// Gain left in dB 380 /// Gain left in dB
@@ -393,7 +393,7 @@ impl Default for Config {
393 feature = "nrf52840", 393 feature = "nrf52840",
394 feature = "nrf52833", 394 feature = "nrf52833",
395 feature = "_nrf5340-app", 395 feature = "_nrf5340-app",
396 feature = "_nrf9160", 396 feature = "_nrf91",
397 ))] 397 ))]
398 ratio: Ratio::RATIO80, 398 ratio: Ratio::RATIO80,
399 gain_left: I7F1::ZERO, 399 gain_left: I7F1::ZERO,
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs
index 17c65fa3e..bbfa9b3b9 100644
--- a/embassy-nrf/src/saadc.rs
+++ b/embassy-nrf/src/saadc.rs
@@ -78,7 +78,8 @@ impl Default for Config {
78 78
79/// Used to configure an individual SAADC peripheral channel. 79/// Used to configure an individual SAADC peripheral channel.
80/// 80///
81/// See the `Default` impl for suitable default values. 81/// Construct using the `single_ended` or `differential` methods. These provide sensible defaults
82/// for the public fields, which can be overridden if required.
82#[non_exhaustive] 83#[non_exhaustive]
83pub struct ChannelConfig<'d> { 84pub struct ChannelConfig<'d> {
84 /// Reference voltage of the SAADC input. 85 /// Reference voltage of the SAADC input.
@@ -722,9 +723,9 @@ macro_rules! impl_saadc_input {
722pub struct VddInput; 723pub struct VddInput;
723 724
724impl_peripheral!(VddInput); 725impl_peripheral!(VddInput);
725#[cfg(not(feature = "_nrf9160"))] 726#[cfg(not(feature = "_nrf91"))]
726impl_saadc_input!(@local, VddInput, VDD); 727impl_saadc_input!(@local, VddInput, VDD);
727#[cfg(feature = "_nrf9160")] 728#[cfg(feature = "_nrf91")]
728impl_saadc_input!(@local, VddInput, VDDGPIO); 729impl_saadc_input!(@local, VddInput, VDDGPIO);
729 730
730/// A dummy `Input` pin implementation for SAADC peripheral sampling from the 731/// A dummy `Input` pin implementation for SAADC peripheral sampling from the
diff --git a/embassy-nrf/src/wdt.rs b/embassy-nrf/src/wdt.rs
index 40a674424..e4cfa3344 100644
--- a/embassy-nrf/src/wdt.rs
+++ b/embassy-nrf/src/wdt.rs
@@ -30,9 +30,9 @@ impl Config {
30 pub fn try_new(_wdt: &peripherals::WDT) -> Option<Self> { 30 pub fn try_new(_wdt: &peripherals::WDT) -> Option<Self> {
31 let r = unsafe { &*WDT::ptr() }; 31 let r = unsafe { &*WDT::ptr() };
32 32
33 #[cfg(not(feature = "_nrf9160"))] 33 #[cfg(not(feature = "_nrf91"))]
34 let runstatus = r.runstatus.read().runstatus().bit(); 34 let runstatus = r.runstatus.read().runstatus().bit();
35 #[cfg(feature = "_nrf9160")] 35 #[cfg(feature = "_nrf91")]
36 let runstatus = r.runstatus.read().runstatuswdt().bit(); 36 let runstatus = r.runstatus.read().runstatuswdt().bit();
37 37
38 if runstatus { 38 if runstatus {
@@ -83,9 +83,9 @@ impl Watchdog {
83 let crv = config.timeout_ticks.max(MIN_TICKS); 83 let crv = config.timeout_ticks.max(MIN_TICKS);
84 let rren = (1u32 << N) - 1; 84 let rren = (1u32 << N) - 1;
85 85
86 #[cfg(not(feature = "_nrf9160"))] 86 #[cfg(not(feature = "_nrf91"))]
87 let runstatus = r.runstatus.read().runstatus().bit(); 87 let runstatus = r.runstatus.read().runstatus().bit();
88 #[cfg(feature = "_nrf9160")] 88 #[cfg(feature = "_nrf91")]
89 let runstatus = r.runstatus.read().runstatuswdt().bit(); 89 let runstatus = r.runstatus.read().runstatuswdt().bit();
90 90
91 if runstatus { 91 if runstatus {
@@ -184,8 +184,9 @@ impl WatchdogHandle {
184 184
185 /// Steal a watchdog handle by index. 185 /// Steal a watchdog handle by index.
186 /// 186 ///
187 /// Safety: watchdog must be initialized, index must be between 0 and N-1 where 187 /// # Safety
188 /// N is the handle count when initializing. 188 /// Watchdog must be initialized and `index` must be between `0` and `N-1`
189 /// where `N` is the handle count when initializing.
189 pub unsafe fn steal(index: u8) -> Self { 190 pub unsafe fn steal(index: u8) -> Self {
190 Self { index } 191 Self { index }
191 } 192 }
diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md
new file mode 100644
index 000000000..7eef64292
--- /dev/null
+++ b/embassy-rp/CHANGELOG.md
@@ -0,0 +1,32 @@
1# Changelog for embassy-rp
2
3All notable changes to this project will be documented in this file.
4
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
8## Unreleased
9
10## 0.2.0 - 2024-08-05
11
12- Add read_to_break_with_count
13- add option to provide your own boot2
14- Add multichannel ADC
15- Add collapse_debuginfo to fmt.rs macros.
16- Use raw slices .len() method instead of unsafe hacks.
17- Add missing word "pin" in rp pwm documentation
18- Add Clone and Copy to Error types
19- fix spinlocks staying locked after reset.
20- wait until read matches for PSM accesses.
21- Remove generics
22- fix drop implementation of BufferedUartRx and BufferedUartTx
23- implement `embedded_storage_async::nor_flash::MultiwriteNorFlash`
24- rp usb: wake ep-wakers after stalling
25- rp usb: add stall implementation
26- Add parameter for enabling pull-up and pull-down in RP PWM input mode
27- rp: remove mod sealed.
28- rename pins data type and the macro
29- rename pwm channels to pwm slices, including in documentation
30- rename the Channel trait to Slice and the PwmPin to PwmChannel
31- i2c: Fix race condition that appears on fast repeated transfers.
32- Add a basic "read to break" function
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 447c96b4d..29a8a3c53 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-rp" 2name = "embassy-rp"
3version = "0.1.0" 3version = "0.2.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "Embassy Hardware Abstraction Layer (HAL) for the Raspberry Pi RP2040 microcontroller" 6description = "Embassy Hardware Abstraction Layer (HAL) for the Raspberry Pi RP2040 microcontroller"
@@ -14,7 +14,9 @@ src_base = "https://github.com/embassy-rs/embassy/blob/embassy-rp-v$VERSION/emba
14src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-rp/src/" 14src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-rp/src/"
15features = ["defmt", "unstable-pac", "time-driver"] 15features = ["defmt", "unstable-pac", "time-driver"]
16flavors = [ 16flavors = [
17 { name = "rp2040", target = "thumbv6m-none-eabi" }, 17 { name = "rp2040", target = "thumbv6m-none-eabi", features = ["rp2040"] },
18 { name = "rp235xa", target = "thumbv8m.main-none-eabihf", features = ["rp235xa"] },
19 { name = "rp235xb", target = "thumbv8m.main-none-eabihf", features = ["rp235xb"] },
18] 20]
19 21
20[package.metadata.docs.rs] 22[package.metadata.docs.rs]
@@ -22,13 +24,13 @@ features = ["defmt", "unstable-pac", "time-driver"]
22 24
23[features] 25[features]
24default = [ "rt" ] 26default = [ "rt" ]
25## Enable the rt feature of [`rp-pac`](https://docs.rs/crates/rp-pac). This brings in the [`cortex-m-rt`](https://docs.rs/cortex-m-rt) crate, which adds startup code and minimal runtime initialization. 27## Enable the rt feature of [`rp-pac`](https://docs.rs/rp-pac). This brings in the [`cortex-m-rt`](https://docs.rs/cortex-m-rt) crate, which adds startup code and minimal runtime initialization.
26rt = [ "rp-pac/rt" ] 28rt = [ "rp-pac/rt" ]
27 29
28## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers. 30## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers.
29defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"] 31defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"]
30 32
31## Configure the critical section crate to use an implementation that is safe for multicore use on rp2040. 33## Configure the [`critical-section`](https://docs.rs/critical-section) crate to use an implementation that is safe for multicore use on rp2040.
32critical-section-impl = ["critical-section/restore-state-u8"] 34critical-section-impl = ["critical-section/restore-state-u8"]
33 35
34## Reexport the PAC for the currently enabled chip at `embassy_rp::pac`. 36## Reexport the PAC for the currently enabled chip at `embassy_rp::pac`.
@@ -88,13 +90,30 @@ boot2-w25x10cl = []
88## ``` 90## ```
89boot2-none = [] 91boot2-none = []
90 92
93## Configure the hal for use with the rp2040
94rp2040 = ["rp-pac/rp2040"]
95_rp235x = ["rp-pac/rp235x"]
96## Configure the hal for use with the rp235xA
97rp235xa = ["_rp235x"]
98## Configure the hal for use with the rp235xB
99rp235xb = ["_rp235x"]
100
101# hack around cortex-m peripherals being wrong when running tests.
102_test = []
103
104## Add a binary-info header block containing picotool-compatible metadata.
105##
106## Takes up a little flash space, but picotool can then report the name of your
107## program and other details.
108binary-info = ["rt", "dep:rp-binary-info", "rp-binary-info?/binary-info"]
109
91[dependencies] 110[dependencies]
92embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 111embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
93embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } 112embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true }
94embassy-time = { version = "0.3.1", path = "../embassy-time" } 113embassy-time = { version = "0.3.2", path = "../embassy-time" }
95embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 114embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
96embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } 115embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] }
97embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 116embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" }
98embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } 117embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" }
99atomic-polyfill = "1.0.1" 118atomic-polyfill = "1.0.1"
100defmt = { version = "0.3", optional = true } 119defmt = { version = "0.3", optional = true }
@@ -112,7 +131,7 @@ embedded-storage-async = { version = "0.4.1" }
112rand_core = "0.6.4" 131rand_core = "0.6.4"
113fixed = "1.23.1" 132fixed = "1.23.1"
114 133
115rp-pac = { version = "6" } 134rp-pac = { git = "https://github.com/embassy-rs/rp-pac.git", rev = "a7f42d25517f7124ad3b4ed492dec8b0f50a0e6c", feature = ["rt"] }
116 135
117embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 136embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
118embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 137embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
@@ -123,7 +142,9 @@ pio-proc = {version= "0.2" }
123pio = {version= "0.2.1" } 142pio = {version= "0.2.1" }
124rp2040-boot2 = "0.3" 143rp2040-boot2 = "0.3"
125document-features = "0.2.7" 144document-features = "0.2.7"
145sha2-const-stable = "0.1"
146rp-binary-info = { version = "0.1.0", optional = true }
126 147
127[dev-dependencies] 148[dev-dependencies]
128embassy-executor = { version = "0.5.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } 149embassy-executor = { version = "0.6.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] }
129static_cell = { version = "2" } 150static_cell = { version = "2" }
diff --git a/embassy-rp/LICENSE-APACHE b/embassy-rp/LICENSE-APACHE
new file mode 100644
index 000000000..48be1263d
--- /dev/null
+++ b/embassy-rp/LICENSE-APACHE
@@ -0,0 +1,202 @@
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
71. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
662. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
733. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
894. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
1305. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
1386. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
1437. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
1538. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
1659. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176END OF TERMS AND CONDITIONS
177
178APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189Copyright (c) Embassy project contributors
190Portions copyright (c) rp-rs organization
191
192Licensed under the Apache License, Version 2.0 (the "License");
193you may not use this file except in compliance with the License.
194You may obtain a copy of the License at
195
196 http://www.apache.org/licenses/LICENSE-2.0
197
198Unless required by applicable law or agreed to in writing, software
199distributed under the License is distributed on an "AS IS" BASIS,
200WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201See the License for the specific language governing permissions and
202limitations under the License.
diff --git a/embassy-rp/LICENSE-MIT b/embassy-rp/LICENSE-MIT
new file mode 100644
index 000000000..f1cfbd5f7
--- /dev/null
+++ b/embassy-rp/LICENSE-MIT
@@ -0,0 +1,26 @@
1Copyright (c) Embassy project contributors
2Portions copyright (c) rp-rs organization
3
4Permission is hereby granted, free of charge, to any
5person obtaining a copy of this software and associated
6documentation files (the "Software"), to deal in the
7Software without restriction, including without
8limitation the rights to use, copy, modify, merge,
9publish, distribute, sublicense, and/or sell copies of
10the Software, and to permit persons to whom the Software
11is furnished to do so, subject to the following
12conditions:
13
14The above copyright notice and this permission notice
15shall be included in all copies or substantial portions
16of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
19ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
20TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
21PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
22SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
25IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26DEALINGS IN THE SOFTWARE.
diff --git a/embassy-rp/README.md b/embassy-rp/README.md
index 8cf7da994..16b189344 100644
--- a/embassy-rp/README.md
+++ b/embassy-rp/README.md
@@ -23,5 +23,5 @@ The `embassy-rp` HAL implements the traits from [embedded-hal](https://crates.io
23 23
24This crate can run on any executor. 24This crate can run on any executor.
25 25
26Optionally, some features requiring [`embassy-time`](https://crates.io/crates/embassy-time) can be activated with the `time` feature. If you enable it, 26Optionally, some features requiring [`embassy-time`](https://crates.io/crates/embassy-time) can be activated with the `time-driver` feature. If you enable it,
27you must link an `embassy-time` driver in your project. 27you must link an `embassy-time` driver in your project.
diff --git a/embassy-rp/build.rs b/embassy-rp/build.rs
index f41ccd220..3216a3826 100644
--- a/embassy-rp/build.rs
+++ b/embassy-rp/build.rs
@@ -4,14 +4,16 @@ use std::io::Write;
4use std::path::PathBuf; 4use std::path::PathBuf;
5 5
6fn main() { 6fn main() {
7 // Put the linker script somewhere the linker can find it 7 if env::var("CARGO_FEATURE_RP2040").is_ok() {
8 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); 8 // Put the linker script somewhere the linker can find it
9 let link_x = include_bytes!("link-rp.x.in"); 9 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
10 let mut f = File::create(out.join("link-rp.x")).unwrap(); 10 let link_x = include_bytes!("link-rp.x.in");
11 f.write_all(link_x).unwrap(); 11 let mut f = File::create(out.join("link-rp.x")).unwrap();
12 f.write_all(link_x).unwrap();
12 13
13 println!("cargo:rustc-link-search={}", out.display()); 14 println!("cargo:rustc-link-search={}", out.display());
14 15
15 println!("cargo:rerun-if-changed=build.rs"); 16 println!("cargo:rerun-if-changed=build.rs");
16 println!("cargo:rerun-if-changed=link-rp.x.in"); 17 println!("cargo:rerun-if-changed=link-rp.x.in");
18 }
17} 19}
diff --git a/embassy-rp/link-rp.x.in b/embassy-rp/link-rp.x.in
index af463f963..1839dda68 100644
--- a/embassy-rp/link-rp.x.in
+++ b/embassy-rp/link-rp.x.in
@@ -5,4 +5,4 @@ SECTIONS {
5 { 5 {
6 KEEP(*(.boot2)); 6 KEEP(*(.boot2));
7 } > BOOT2 7 } > BOOT2
8} \ No newline at end of file 8}
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs
index eb1cc9a66..9582e43c8 100644
--- a/embassy-rp/src/adc.rs
+++ b/embassy-rp/src/adc.rs
@@ -11,6 +11,7 @@ use embassy_sync::waitqueue::AtomicWaker;
11use crate::gpio::{self, AnyPin, Pull, SealedPin as GpioPin}; 11use crate::gpio::{self, AnyPin, Pull, SealedPin as GpioPin};
12use crate::interrupt::typelevel::Binding; 12use crate::interrupt::typelevel::Binding;
13use crate::interrupt::InterruptExt; 13use crate::interrupt::InterruptExt;
14use crate::pac::dma::vals::TreqSel;
14use crate::peripherals::{ADC, ADC_TEMP_SENSOR}; 15use crate::peripherals::{ADC, ADC_TEMP_SENSOR};
15use crate::{dma, interrupt, pac, peripherals, Peripheral, RegExt}; 16use crate::{dma, interrupt, pac, peripherals, Peripheral, RegExt};
16 17
@@ -34,6 +35,8 @@ impl<'p> Channel<'p> {
34 pub fn new_pin(pin: impl Peripheral<P = impl AdcPin + 'p> + 'p, pull: Pull) -> Self { 35 pub fn new_pin(pin: impl Peripheral<P = impl AdcPin + 'p> + 'p, pull: Pull) -> Self {
35 into_ref!(pin); 36 into_ref!(pin);
36 pin.pad_ctrl().modify(|w| { 37 pin.pad_ctrl().modify(|w| {
38 #[cfg(feature = "_rp235x")]
39 w.set_iso(false);
37 // manual says: 40 // manual says:
38 // 41 //
39 // > When using an ADC input shared with a GPIO pin, the pin’s 42 // > When using an ADC input shared with a GPIO pin, the pin’s
@@ -229,7 +232,10 @@ impl<'d> Adc<'d, Async> {
229 div: u16, 232 div: u16,
230 dma: impl Peripheral<P = impl dma::Channel>, 233 dma: impl Peripheral<P = impl dma::Channel>,
231 ) -> Result<(), Error> { 234 ) -> Result<(), Error> {
235 #[cfg(feature = "rp2040")]
232 let mut rrobin = 0_u8; 236 let mut rrobin = 0_u8;
237 #[cfg(feature = "_rp235x")]
238 let mut rrobin = 0_u16;
233 for c in channels { 239 for c in channels {
234 rrobin |= 1 << c; 240 rrobin |= 1 << c;
235 } 241 }
@@ -278,7 +284,7 @@ impl<'d> Adc<'d, Async> {
278 } 284 }
279 let auto_reset = ResetDmaConfig; 285 let auto_reset = ResetDmaConfig;
280 286
281 let dma = unsafe { dma::read(dma, r.fifo().as_ptr() as *const W, buf as *mut [W], 36) }; 287 let dma = unsafe { dma::read(dma, r.fifo().as_ptr() as *const W, buf as *mut [W], TreqSel::ADC) };
282 // start conversions and wait for dma to finish. we can't report errors early 288 // start conversions and wait for dma to finish. we can't report errors early
283 // because there's no interrupt to signal them, and inspecting every element 289 // because there's no interrupt to signal them, and inspecting every element
284 // of the fifo is too costly to do here. 290 // of the fifo is too costly to do here.
@@ -423,10 +429,31 @@ macro_rules! impl_pin {
423 }; 429 };
424} 430}
425 431
432#[cfg(any(feature = "rp235xa", feature = "rp2040"))]
426impl_pin!(PIN_26, 0); 433impl_pin!(PIN_26, 0);
434#[cfg(any(feature = "rp235xa", feature = "rp2040"))]
427impl_pin!(PIN_27, 1); 435impl_pin!(PIN_27, 1);
436#[cfg(any(feature = "rp235xa", feature = "rp2040"))]
428impl_pin!(PIN_28, 2); 437impl_pin!(PIN_28, 2);
438#[cfg(any(feature = "rp235xa", feature = "rp2040"))]
429impl_pin!(PIN_29, 3); 439impl_pin!(PIN_29, 3);
430 440
441#[cfg(feature = "rp235xb")]
442impl_pin!(PIN_40, 0);
443#[cfg(feature = "rp235xb")]
444impl_pin!(PIN_41, 1);
445#[cfg(feature = "rp235xb")]
446impl_pin!(PIN_42, 2);
447#[cfg(feature = "rp235xb")]
448impl_pin!(PIN_43, 3);
449#[cfg(feature = "rp235xb")]
450impl_pin!(PIN_44, 4);
451#[cfg(feature = "rp235xb")]
452impl_pin!(PIN_45, 5);
453#[cfg(feature = "rp235xb")]
454impl_pin!(PIN_46, 6);
455#[cfg(feature = "rp235xb")]
456impl_pin!(PIN_47, 7);
457
431impl SealedAdcChannel for peripherals::ADC_TEMP_SENSOR {} 458impl SealedAdcChannel for peripherals::ADC_TEMP_SENSOR {}
432impl AdcChannel for peripherals::ADC_TEMP_SENSOR {} 459impl AdcChannel for peripherals::ADC_TEMP_SENSOR {}
diff --git a/embassy-rp/src/block.rs b/embassy-rp/src/block.rs
new file mode 100644
index 000000000..a3e1ad925
--- /dev/null
+++ b/embassy-rp/src/block.rs
@@ -0,0 +1,1079 @@
1//! Support for the RP235x Boot ROM's "Block" structures
2//!
3//! Blocks contain pointers, to form Block Loops.
4//!
5//! The `IMAGE_DEF` Block (here the `ImageDef` type) tells the ROM how to boot a
6//! firmware image. The `PARTITION_TABLE` Block (here the `PartitionTable` type)
7//! tells the ROM how to divide the flash space up into partitions.
8
9// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT).
10// Copyright (c) rp-rs organization
11
12// These all have a 1 byte size
13
14/// An item ID for encoding a Vector Table address
15pub const ITEM_1BS_VECTOR_TABLE: u8 = 0x03;
16
17/// An item ID for encoding a Rolling Window Delta
18pub const ITEM_1BS_ROLLING_WINDOW_DELTA: u8 = 0x05;
19
20/// An item ID for encoding a Signature
21pub const ITEM_1BS_SIGNATURE: u8 = 0x09;
22
23/// An item ID for encoding a Salt
24pub const ITEM_1BS_SALT: u8 = 0x0c;
25
26/// An item ID for encoding an Image Type
27pub const ITEM_1BS_IMAGE_TYPE: u8 = 0x42;
28
29/// An item ID for encoding the image's Entry Point
30pub const ITEM_1BS_ENTRY_POINT: u8 = 0x44;
31
32/// An item ID for encoding the definition of a Hash
33pub const ITEM_2BS_HASH_DEF: u8 = 0x47;
34
35/// An item ID for encoding a Version
36pub const ITEM_1BS_VERSION: u8 = 0x48;
37
38/// An item ID for encoding a Hash
39pub const ITEM_1BS_HASH_VALUE: u8 = 0x4b;
40
41// These all have a 2-byte size
42
43/// An item ID for encoding a Load Map
44pub const ITEM_2BS_LOAD_MAP: u8 = 0x06;
45
46/// An item ID for encoding a Partition Table
47pub const ITEM_2BS_PARTITION_TABLE: u8 = 0x0a;
48
49/// An item ID for encoding a placeholder entry that is ignored
50///
51/// Allows a Block to not be empty.
52pub const ITEM_2BS_IGNORED: u8 = 0xfe;
53
54/// An item ID for encoding the special last item in a Block
55///
56/// It records how long the Block is.
57pub const ITEM_2BS_LAST: u8 = 0xff;
58
59// Options for ITEM_1BS_IMAGE_TYPE
60
61/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark an image as invalid
62pub const IMAGE_TYPE_INVALID: u16 = 0x0000;
63
64/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark an image as an executable
65pub const IMAGE_TYPE_EXE: u16 = 0x0001;
66
67/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark an image as data
68pub const IMAGE_TYPE_DATA: u16 = 0x0002;
69
70/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU security mode as unspecified
71pub const IMAGE_TYPE_EXE_TYPE_SECURITY_UNSPECIFIED: u16 = 0x0000;
72
73/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU security mode as Non Secure
74pub const IMAGE_TYPE_EXE_TYPE_SECURITY_NS: u16 = 0x0010;
75
76/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU security mode as Non Secure
77pub const IMAGE_TYPE_EXE_TYPE_SECURITY_S: u16 = 0x0020;
78
79/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU type as Arm
80pub const IMAGE_TYPE_EXE_CPU_ARM: u16 = 0x0000;
81
82/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU type as RISC-V
83pub const IMAGE_TYPE_EXE_CPU_RISCV: u16 = 0x0100;
84
85/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU as an RP2040
86pub const IMAGE_TYPE_EXE_CHIP_RP2040: u16 = 0x0000;
87
88/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the CPU as an RP2350
89pub const IMAGE_TYPE_EXE_CHIP_RP2350: u16 = 0x1000;
90
91/// A [`ITEM_1BS_IMAGE_TYPE`] value bitmask to mark the image as Try Before You Buy.
92///
93/// This means the image must be marked as 'Bought' with the ROM before the
94/// watchdog times out the trial period, otherwise it is erased and the previous
95/// image will be booted.
96pub const IMAGE_TYPE_TBYB: u16 = 0x8000;
97
98/// This is the magic Block Start value.
99///
100/// The Pico-SDK calls it `PICOBIN_BLOCK_MARKER_START`
101const BLOCK_MARKER_START: u32 = 0xffffded3;
102
103/// This is the magic Block END value.
104///
105/// The Pico-SDK calls it `PICOBIN_BLOCK_MARKER_END`
106const BLOCK_MARKER_END: u32 = 0xab123579;
107
108/// An Image Definition has one item in it - an [`ITEM_1BS_IMAGE_TYPE`]
109pub type ImageDef = Block<1>;
110
111/// A Block as understood by the Boot ROM.
112///
113/// This could be an Image Definition, or a Partition Table, or maybe some other
114/// kind of block.
115///
116/// It contains within the special start and end markers the Boot ROM is looking
117/// for.
118#[derive(Debug)]
119#[repr(C)]
120pub struct Block<const N: usize> {
121 marker_start: u32,
122 items: [u32; N],
123 length: u32,
124 offset: *const u32,
125 marker_end: u32,
126}
127
128unsafe impl<const N: usize> Sync for Block<N> {}
129
130impl<const N: usize> Block<N> {
131 /// Construct a new Binary Block, with the given items.
132 ///
133 /// The length, and the Start and End markers are added automatically. The
134 /// Block Loop pointer initially points to itself.
135 pub const fn new(items: [u32; N]) -> Block<N> {
136 Block {
137 marker_start: BLOCK_MARKER_START,
138 items,
139 length: item_last(N as u16),
140 // offset from this block to next block in loop. By default
141 // we form a Block Loop with a single Block in it.
142 offset: core::ptr::null(),
143 marker_end: BLOCK_MARKER_END,
144 }
145 }
146
147 /// Change the Block Loop offset value.
148 ///
149 /// This method isn't that useful because you can't evaluate the difference
150 /// between two pointers in a const context as the addresses aren't assigned
151 /// until long after the const evaluator has run.
152 ///
153 /// If you think you need this method, you might want to set a unique random
154 /// value here and swap it for the real offset as a post-processing step.
155 pub const fn with_offset(self, offset: *const u32) -> Block<N> {
156 Block { offset, ..self }
157 }
158}
159
160impl Block<0> {
161 /// Construct an empty block.
162 pub const fn empty() -> Block<0> {
163 Block::new([])
164 }
165
166 /// Make the block one word larger
167 pub const fn extend(self, word: u32) -> Block<1> {
168 Block::new([word])
169 }
170}
171
172impl Block<1> {
173 /// Make the block one word larger
174 pub const fn extend(self, word: u32) -> Block<2> {
175 Block::new([self.items[0], word])
176 }
177}
178
179impl Block<2> {
180 /// Make the block one word larger
181 pub const fn extend(self, word: u32) -> Block<3> {
182 Block::new([self.items[0], self.items[1], word])
183 }
184}
185
186impl ImageDef {
187 /// Construct a new IMAGE_DEF Block, for an EXE with the given security and
188 /// architecture.
189 pub const fn arch_exe(security: Security, architecture: Architecture) -> Self {
190 Self::new([item_image_type_exe(security, architecture)])
191 }
192
193 /// Construct a new IMAGE_DEF Block, for an EXE with the given security.
194 ///
195 /// The target architecture is taken from the current build target (i.e. Arm
196 /// or RISC-V).
197 pub const fn exe(security: Security) -> Self {
198 if cfg!(all(target_arch = "riscv32", target_os = "none")) {
199 Self::arch_exe(security, Architecture::Riscv)
200 } else {
201 Self::arch_exe(security, Architecture::Arm)
202 }
203 }
204
205 /// Construct a new IMAGE_DEF Block, for a Non-Secure EXE.
206 ///
207 /// The target architecture is taken from the current build target (i.e. Arm
208 /// or RISC-V).
209 pub const fn non_secure_exe() -> Self {
210 Self::exe(Security::NonSecure)
211 }
212
213 /// Construct a new IMAGE_DEF Block, for a Secure EXE.
214 ///
215 /// The target architecture is taken from the current build target (i.e. Arm
216 /// or RISC-V).
217 pub const fn secure_exe() -> Self {
218 Self::exe(Security::Secure)
219 }
220}
221
222/// We make our partition table this fixed size.
223pub const PARTITION_TABLE_MAX_ITEMS: usize = 128;
224
225/// Describes a unpartitioned space
226#[derive(Debug, Clone, PartialEq, Eq, Default)]
227pub struct UnpartitionedSpace {
228 permissions_and_location: u32,
229 permissions_and_flags: u32,
230}
231
232impl UnpartitionedSpace {
233 /// Create a new unpartitioned space.
234 ///
235 /// It defaults to no permissions.
236 pub const fn new() -> Self {
237 Self {
238 permissions_and_location: 0,
239 permissions_and_flags: 0,
240 }
241 }
242
243 /// Create a new unpartition space from run-time values.
244 ///
245 /// Get these from the ROM function `get_partition_table_info` with an argument of `PT_INFO`.
246 pub const fn from_raw(permissions_and_location: u32, permissions_and_flags: u32) -> Self {
247 Self {
248 permissions_and_location,
249 permissions_and_flags,
250 }
251 }
252
253 /// Add a permission
254 pub const fn with_permission(self, permission: Permission) -> Self {
255 Self {
256 permissions_and_flags: self.permissions_and_flags | permission as u32,
257 permissions_and_location: self.permissions_and_location | permission as u32,
258 }
259 }
260
261 /// Set a flag
262 pub const fn with_flag(self, flag: UnpartitionedFlag) -> Self {
263 Self {
264 permissions_and_flags: self.permissions_and_flags | flag as u32,
265 ..self
266 }
267 }
268
269 /// Get the partition start and end
270 ///
271 /// The offsets are in 4 KiB sectors, inclusive.
272 pub fn get_first_last_sectors(&self) -> (u16, u16) {
273 (
274 (self.permissions_and_location & 0x0000_1FFF) as u16,
275 ((self.permissions_and_location >> 13) & 0x0000_1FFF) as u16,
276 )
277 }
278
279 /// Get the partition start and end
280 ///
281 /// The offsets are in bytes, inclusive.
282 pub fn get_first_last_bytes(&self) -> (u32, u32) {
283 let (first, last) = self.get_first_last_sectors();
284 (u32::from(first) * 4096, (u32::from(last) * 4096) + 4095)
285 }
286
287 /// Check if it has a permission
288 pub fn has_permission(&self, permission: Permission) -> bool {
289 let mask = permission as u32;
290 (self.permissions_and_flags & mask) != 0
291 }
292
293 /// Check if the partition has a flag set
294 pub fn has_flag(&self, flag: UnpartitionedFlag) -> bool {
295 let mask = flag as u32;
296 (self.permissions_and_flags & mask) != 0
297 }
298}
299
300impl core::fmt::Display for UnpartitionedSpace {
301 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
302 let (first, last) = self.get_first_last_bytes();
303 write!(
304 f,
305 "{:#010x}..{:#010x} S:{}{} NS:{}{} B:{}{}",
306 first,
307 last,
308 if self.has_permission(Permission::SecureRead) {
309 'R'
310 } else {
311 '_'
312 },
313 if self.has_permission(Permission::SecureWrite) {
314 'W'
315 } else {
316 '_'
317 },
318 if self.has_permission(Permission::NonSecureRead) {
319 'R'
320 } else {
321 '_'
322 },
323 if self.has_permission(Permission::NonSecureWrite) {
324 'W'
325 } else {
326 '_'
327 },
328 if self.has_permission(Permission::BootRead) {
329 'R'
330 } else {
331 '_'
332 },
333 if self.has_permission(Permission::BootWrite) {
334 'W'
335 } else {
336 '_'
337 }
338 )
339 }
340}
341
342/// Describes a Partition
343#[derive(Debug, Clone, PartialEq, Eq)]
344pub struct Partition {
345 permissions_and_location: u32,
346 permissions_and_flags: u32,
347 id: Option<u64>,
348 extra_families: [u32; 4],
349 extra_families_len: usize,
350 name: [u8; 128],
351}
352
353impl Partition {
354 const FLAGS_HAS_ID: u32 = 0b1;
355 const FLAGS_LINK_TYPE_A_PARTITION: u32 = 0b01 << 1;
356 const FLAGS_LINK_TYPE_OWNER: u32 = 0b10 << 1;
357 const FLAGS_LINK_MASK: u32 = 0b111111 << 1;
358 const FLAGS_HAS_NAME: u32 = 0b1 << 12;
359 const FLAGS_HAS_EXTRA_FAMILIES_SHIFT: u8 = 7;
360 const FLAGS_HAS_EXTRA_FAMILIES_MASK: u32 = 0b11 << Self::FLAGS_HAS_EXTRA_FAMILIES_SHIFT;
361
362 /// Create a new partition, with the given start and end sectors.
363 ///
364 /// It defaults to no permissions.
365 pub const fn new(first_sector: u16, last_sector: u16) -> Self {
366 // 0x2000 sectors of 4 KiB is 32 MiB, which is the total XIP area
367 core::assert!(first_sector < 0x2000);
368 core::assert!(last_sector < 0x2000);
369 core::assert!(first_sector <= last_sector);
370 Self {
371 permissions_and_location: (last_sector as u32) << 13 | first_sector as u32,
372 permissions_and_flags: 0,
373 id: None,
374 extra_families: [0; 4],
375 extra_families_len: 0,
376 name: [0; 128],
377 }
378 }
379
380 /// Create a new partition from run-time values.
381 ///
382 /// Get these from the ROM function `get_partition_table_info` with an argument of `PARTITION_LOCATION_AND_FLAGS`.
383 pub const fn from_raw(permissions_and_location: u32, permissions_and_flags: u32) -> Self {
384 Self {
385 permissions_and_location,
386 permissions_and_flags,
387 id: None,
388 extra_families: [0; 4],
389 extra_families_len: 0,
390 name: [0; 128],
391 }
392 }
393
394 /// Add a permission
395 pub const fn with_permission(self, permission: Permission) -> Self {
396 Self {
397 permissions_and_location: self.permissions_and_location | permission as u32,
398 permissions_and_flags: self.permissions_and_flags | permission as u32,
399 ..self
400 }
401 }
402
403 /// Set the name of the partition
404 pub const fn with_name(self, name: &str) -> Self {
405 let mut new_name = [0u8; 128];
406 let name = name.as_bytes();
407 let mut idx = 0;
408 new_name[0] = name.len() as u8;
409 while idx < name.len() {
410 new_name[idx + 1] = name[idx];
411 idx += 1;
412 }
413 Self {
414 name: new_name,
415 permissions_and_flags: self.permissions_and_flags | Self::FLAGS_HAS_NAME,
416 ..self
417 }
418 }
419
420 /// Set the extra families for the partition.
421 ///
422 /// You can supply up to four.
423 pub const fn with_extra_families(self, extra_families: &[u32]) -> Self {
424 core::assert!(extra_families.len() <= 4);
425 let mut new_extra_families = [0u32; 4];
426 let mut idx = 0;
427 while idx < extra_families.len() {
428 new_extra_families[idx] = extra_families[idx];
429 idx += 1;
430 }
431 Self {
432 extra_families: new_extra_families,
433 extra_families_len: extra_families.len(),
434 permissions_and_flags: (self.permissions_and_flags & !Self::FLAGS_HAS_EXTRA_FAMILIES_MASK)
435 | (extra_families.len() as u32) << Self::FLAGS_HAS_EXTRA_FAMILIES_SHIFT,
436 ..self
437 }
438 }
439
440 /// Set the ID
441 pub const fn with_id(self, id: u64) -> Self {
442 Self {
443 id: Some(id),
444 permissions_and_flags: self.permissions_and_flags | Self::FLAGS_HAS_ID,
445 ..self
446 }
447 }
448
449 /// Add a link
450 pub const fn with_link(self, link: Link) -> Self {
451 let mut new_flags = self.permissions_and_flags & !Self::FLAGS_LINK_MASK;
452 match link {
453 Link::Nothing => {}
454 Link::ToA { partition_idx } => {
455 core::assert!(partition_idx < 16);
456 new_flags |= Self::FLAGS_LINK_TYPE_A_PARTITION;
457 new_flags |= (partition_idx as u32) << 3;
458 }
459 Link::ToOwner { partition_idx } => {
460 core::assert!(partition_idx < 16);
461 new_flags |= Self::FLAGS_LINK_TYPE_OWNER;
462 new_flags |= (partition_idx as u32) << 3;
463 }
464 }
465 Self {
466 permissions_and_flags: new_flags,
467 ..self
468 }
469 }
470
471 /// Set a flag
472 pub const fn with_flag(self, flag: PartitionFlag) -> Self {
473 Self {
474 permissions_and_flags: self.permissions_and_flags | flag as u32,
475 ..self
476 }
477 }
478
479 /// Get the partition start and end
480 ///
481 /// The offsets are in 4 KiB sectors, inclusive.
482 pub fn get_first_last_sectors(&self) -> (u16, u16) {
483 (
484 (self.permissions_and_location & 0x0000_1FFF) as u16,
485 ((self.permissions_and_location >> 13) & 0x0000_1FFF) as u16,
486 )
487 }
488
489 /// Get the partition start and end
490 ///
491 /// The offsets are in bytes, inclusive.
492 pub fn get_first_last_bytes(&self) -> (u32, u32) {
493 let (first, last) = self.get_first_last_sectors();
494 (u32::from(first) * 4096, (u32::from(last) * 4096) + 4095)
495 }
496
497 /// Check if it has a permission
498 pub fn has_permission(&self, permission: Permission) -> bool {
499 let mask = permission as u32;
500 (self.permissions_and_flags & mask) != 0
501 }
502
503 /// Get which extra families are allowed in this partition
504 pub fn get_extra_families(&self) -> &[u32] {
505 &self.extra_families[0..self.extra_families_len]
506 }
507
508 /// Get the name of the partition
509 ///
510 /// Returns `None` if there's no name, or the name is not valid UTF-8.
511 pub fn get_name(&self) -> Option<&str> {
512 let len = self.name[0] as usize;
513 if len == 0 {
514 None
515 } else {
516 core::str::from_utf8(&self.name[1..=len]).ok()
517 }
518 }
519
520 /// Get the ID
521 pub fn get_id(&self) -> Option<u64> {
522 self.id
523 }
524
525 /// Check if this partition is linked
526 pub fn get_link(&self) -> Link {
527 if (self.permissions_and_flags & Self::FLAGS_LINK_TYPE_A_PARTITION) != 0 {
528 let partition_idx = ((self.permissions_and_flags >> 3) & 0x0F) as u8;
529 Link::ToA { partition_idx }
530 } else if (self.permissions_and_flags & Self::FLAGS_LINK_TYPE_OWNER) != 0 {
531 let partition_idx = ((self.permissions_and_flags >> 3) & 0x0F) as u8;
532 Link::ToOwner { partition_idx }
533 } else {
534 Link::Nothing
535 }
536 }
537
538 /// Check if the partition has a flag set
539 pub fn has_flag(&self, flag: PartitionFlag) -> bool {
540 let mask = flag as u32;
541 (self.permissions_and_flags & mask) != 0
542 }
543}
544
545impl core::fmt::Display for Partition {
546 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
547 let (first, last) = self.get_first_last_bytes();
548 write!(
549 f,
550 "{:#010x}..{:#010x} S:{}{} NS:{}{} B:{}{}",
551 first,
552 last,
553 if self.has_permission(Permission::SecureRead) {
554 'R'
555 } else {
556 '_'
557 },
558 if self.has_permission(Permission::SecureWrite) {
559 'W'
560 } else {
561 '_'
562 },
563 if self.has_permission(Permission::NonSecureRead) {
564 'R'
565 } else {
566 '_'
567 },
568 if self.has_permission(Permission::NonSecureWrite) {
569 'W'
570 } else {
571 '_'
572 },
573 if self.has_permission(Permission::BootRead) {
574 'R'
575 } else {
576 '_'
577 },
578 if self.has_permission(Permission::BootWrite) {
579 'W'
580 } else {
581 '_'
582 }
583 )
584 }
585}
586
587/// Describes a partition table.
588///
589/// Don't store this as a static - make sure you convert it to a block.
590#[derive(Clone)]
591pub struct PartitionTableBlock {
592 /// This must look like a block, including the 1 word header and the 3 word footer.
593 contents: [u32; PARTITION_TABLE_MAX_ITEMS],
594 /// This value doesn't include the 1 word header or the 3 word footer
595 num_items: usize,
596}
597
598impl PartitionTableBlock {
599 /// Create an empty Block, big enough for a partition table.
600 ///
601 /// At a minimum you need to call [`Self::add_partition_item`].
602 pub const fn new() -> PartitionTableBlock {
603 let mut contents = [0; PARTITION_TABLE_MAX_ITEMS];
604 contents[0] = BLOCK_MARKER_START;
605 contents[1] = item_last(0);
606 contents[2] = 0;
607 contents[3] = BLOCK_MARKER_END;
608 PartitionTableBlock { contents, num_items: 0 }
609 }
610
611 /// Add a partition to the partition table
612 pub const fn add_partition_item(self, unpartitioned: UnpartitionedSpace, partitions: &[Partition]) -> Self {
613 let mut new_table = PartitionTableBlock::new();
614 let mut idx = 0;
615 // copy over old table, with the header but not the footer
616 while idx < self.num_items + 1 {
617 new_table.contents[idx] = self.contents[idx];
618 idx += 1;
619 }
620
621 // 1. add item header space (we fill this in later)
622 let header_idx = idx;
623 new_table.contents[idx] = 0;
624 idx += 1;
625
626 // 2. unpartitioned space flags
627 //
628 // (the location of unpartition space is not recorded here - it is
629 // inferred because the unpartitioned space is where the partitions are
630 // not)
631 new_table.contents[idx] = unpartitioned.permissions_and_flags;
632 idx += 1;
633
634 // 3. partition info
635
636 let mut partition_no = 0;
637 while partition_no < partitions.len() {
638 // a. permissions_and_location (4K units)
639 new_table.contents[idx] = partitions[partition_no].permissions_and_location;
640 idx += 1;
641
642 // b. permissions_and_flags
643 new_table.contents[idx] = partitions[partition_no].permissions_and_flags;
644 idx += 1;
645
646 // c. ID
647 if let Some(id) = partitions[partition_no].id {
648 new_table.contents[idx] = id as u32;
649 new_table.contents[idx + 1] = (id >> 32) as u32;
650 idx += 2;
651 }
652
653 // d. Extra Families
654 let mut extra_families_idx = 0;
655 while extra_families_idx < partitions[partition_no].extra_families_len {
656 new_table.contents[idx] = partitions[partition_no].extra_families[extra_families_idx];
657 idx += 1;
658 extra_families_idx += 1;
659 }
660
661 // e. Name
662 let mut name_idx = 0;
663 while name_idx < partitions[partition_no].name[0] as usize {
664 let name_chunk = [
665 partitions[partition_no].name[name_idx],
666 partitions[partition_no].name[name_idx + 1],
667 partitions[partition_no].name[name_idx + 2],
668 partitions[partition_no].name[name_idx + 3],
669 ];
670 new_table.contents[idx] = u32::from_le_bytes(name_chunk);
671 name_idx += 4;
672 idx += 1;
673 }
674
675 partition_no += 1;
676 }
677
678 let len = idx - header_idx;
679 new_table.contents[header_idx] = item_generic_2bs(partitions.len() as u8, len as u16, ITEM_2BS_PARTITION_TABLE);
680
681 // 7. New Footer
682 new_table.contents[idx] = item_last(idx as u16 - 1);
683 new_table.contents[idx + 1] = 0;
684 new_table.contents[idx + 2] = BLOCK_MARKER_END;
685
686 // ignore the header
687 new_table.num_items = idx - 1;
688 new_table
689 }
690
691 /// Add a version number to the partition table
692 pub const fn with_version(self, major: u16, minor: u16) -> Self {
693 let mut new_table = PartitionTableBlock::new();
694 let mut idx = 0;
695 // copy over old table, with the header but not the footer
696 while idx < self.num_items + 1 {
697 new_table.contents[idx] = self.contents[idx];
698 idx += 1;
699 }
700
701 // 1. add item
702 new_table.contents[idx] = item_generic_2bs(0, 2, ITEM_1BS_VERSION);
703 idx += 1;
704 new_table.contents[idx] = (major as u32) << 16 | minor as u32;
705 idx += 1;
706
707 // 2. New Footer
708 new_table.contents[idx] = item_last(idx as u16 - 1);
709 new_table.contents[idx + 1] = 0;
710 new_table.contents[idx + 2] = BLOCK_MARKER_END;
711
712 // ignore the header
713 new_table.num_items = idx - 1;
714 new_table
715 }
716
717 /// Add a a SHA256 hash of the Block
718 ///
719 /// Adds a `HASH_DEF` covering all the previous items in the Block, and a
720 /// `HASH_VALUE` with a SHA-256 hash of them.
721 pub const fn with_sha256(self) -> Self {
722 let mut new_table = PartitionTableBlock::new();
723 let mut idx = 0;
724 // copy over old table, with the header but not the footer
725 while idx < self.num_items + 1 {
726 new_table.contents[idx] = self.contents[idx];
727 idx += 1;
728 }
729
730 // 1. HASH_DEF says what is hashed
731 new_table.contents[idx] = item_generic_2bs(1, 2, ITEM_2BS_HASH_DEF);
732 idx += 1;
733 // we're hashing all the previous contents - including this line.
734 new_table.contents[idx] = (idx + 1) as u32;
735 idx += 1;
736
737 // calculate hash over prior contents
738 let input = unsafe { core::slice::from_raw_parts(new_table.contents.as_ptr() as *const u8, idx * 4) };
739 let hash: [u8; 32] = sha2_const_stable::Sha256::new().update(input).finalize();
740
741 // 2. HASH_VALUE contains the hash
742 new_table.contents[idx] = item_generic_2bs(0, 9, ITEM_1BS_HASH_VALUE);
743 idx += 1;
744
745 let mut hash_idx = 0;
746 while hash_idx < hash.len() {
747 new_table.contents[idx] = u32::from_le_bytes([
748 hash[hash_idx],
749 hash[hash_idx + 1],
750 hash[hash_idx + 2],
751 hash[hash_idx + 3],
752 ]);
753 idx += 1;
754 hash_idx += 4;
755 }
756
757 // 3. New Footer
758 new_table.contents[idx] = item_last(idx as u16 - 1);
759 new_table.contents[idx + 1] = 0;
760 new_table.contents[idx + 2] = BLOCK_MARKER_END;
761
762 // ignore the header
763 new_table.num_items = idx - 1;
764 new_table
765 }
766}
767
768impl Default for PartitionTableBlock {
769 fn default() -> Self {
770 Self::new()
771 }
772}
773
774/// Flags that a Partition can have
775#[derive(Debug, Copy, Clone, PartialEq, Eq)]
776#[repr(u32)]
777#[allow(missing_docs)]
778pub enum PartitionFlag {
779 NotBootableArm = 1 << 9,
780 NotBootableRiscv = 1 << 10,
781 Uf2DownloadAbNonBootableOwnerAffinity = 1 << 11,
782 Uf2DownloadNoReboot = 1 << 13,
783 AcceptsDefaultFamilyRp2040 = 1 << 14,
784 AcceptsDefaultFamilyData = 1 << 16,
785 AcceptsDefaultFamilyRp2350ArmS = 1 << 17,
786 AcceptsDefaultFamilyRp2350Riscv = 1 << 18,
787 AcceptsDefaultFamilyRp2350ArmNs = 1 << 19,
788}
789
790/// Flags that a Partition can have
791#[derive(Debug, Copy, Clone, PartialEq, Eq)]
792#[repr(u32)]
793#[allow(missing_docs)]
794pub enum UnpartitionedFlag {
795 Uf2DownloadNoReboot = 1 << 13,
796 AcceptsDefaultFamilyRp2040 = 1 << 14,
797 AcceptsDefaultFamilyAbsolute = 1 << 15,
798 AcceptsDefaultFamilyData = 1 << 16,
799 AcceptsDefaultFamilyRp2350ArmS = 1 << 17,
800 AcceptsDefaultFamilyRp2350Riscv = 1 << 18,
801 AcceptsDefaultFamilyRp2350ArmNs = 1 << 19,
802}
803
804/// Kinds of linked partition
805#[derive(Debug, Copy, Clone, PartialEq, Eq)]
806pub enum Link {
807 /// Not linked to anything
808 Nothing,
809 /// This is a B partition - link to our A partition.
810 ToA {
811 /// The index of our matching A partition.
812 partition_idx: u8,
813 },
814 /// Link to the partition that owns this one.
815 ToOwner {
816 /// The idx of our owner
817 partition_idx: u8,
818 },
819}
820
821/// Permissions that a Partition can have
822#[derive(Debug, Copy, Clone, PartialEq, Eq)]
823#[repr(u32)]
824pub enum Permission {
825 /// Can be read in Secure Mode
826 ///
827 /// Corresponds to `PERMISSION_S_R_BITS` in the Pico SDK
828 SecureRead = 1 << 26,
829 /// Can be written in Secure Mode
830 ///
831 /// Corresponds to `PERMISSION_S_W_BITS` in the Pico SDK
832 SecureWrite = 1 << 27,
833 /// Can be read in Non-Secure Mode
834 ///
835 /// Corresponds to `PERMISSION_NS_R_BITS` in the Pico SDK
836 NonSecureRead = 1 << 28,
837 /// Can be written in Non-Secure Mode
838 ///
839 /// Corresponds to `PERMISSION_NS_W_BITS` in the Pico SDK
840 NonSecureWrite = 1 << 29,
841 /// Can be read in Non-Secure Bootloader mode
842 ///
843 /// Corresponds to `PERMISSION_NSBOOT_R_BITS` in the Pico SDK
844 BootRead = 1 << 30,
845 /// Can be written in Non-Secure Bootloader mode
846 ///
847 /// Corresponds to `PERMISSION_NSBOOT_W_BITS` in the Pico SDK
848 BootWrite = 1 << 31,
849}
850
851impl Permission {
852 /// Is this permission bit set this in this bitmask?
853 pub const fn is_in(self, mask: u32) -> bool {
854 (mask & (self as u32)) != 0
855 }
856}
857
858/// The supported RP2350 CPU architectures
859#[derive(Debug, Copy, Clone, PartialEq, Eq)]
860pub enum Architecture {
861 /// Core is in Arm Cortex-M33 mode
862 Arm,
863 /// Core is in RISC-V / Hazard3 mode
864 Riscv,
865}
866
867/// The kinds of Secure Boot we support
868#[derive(Debug, Copy, Clone)]
869pub enum Security {
870 /// Security mode not given
871 Unspecified,
872 /// Start in Non-Secure mode
873 NonSecure,
874 /// Start in Secure mode
875 Secure,
876}
877
878/// Make an item containing a tag, 1 byte length and two extra bytes.
879///
880/// The `command` arg should contain `1BS`
881pub const fn item_generic_1bs(value: u16, length: u8, command: u8) -> u32 {
882 ((value as u32) << 16) | ((length as u32) << 8) | (command as u32)
883}
884
885/// Make an item containing a tag, 2 byte length and one extra byte.
886///
887/// The `command` arg should contain `2BS`
888pub const fn item_generic_2bs(value: u8, length: u16, command: u8) -> u32 {
889 ((value as u32) << 24) | ((length as u32) << 8) | (command as u32)
890}
891
892/// Create Image Type item, of type IGNORED.
893pub const fn item_ignored() -> u32 {
894 item_generic_2bs(0, 1, ITEM_2BS_IGNORED)
895}
896
897/// Create Image Type item, of type INVALID.
898pub const fn item_image_type_invalid() -> u32 {
899 let value = IMAGE_TYPE_INVALID;
900 item_generic_1bs(value, 1, ITEM_1BS_IMAGE_TYPE)
901}
902
903/// Create Image Type item, of type DATA.
904pub const fn item_image_type_data() -> u32 {
905 let value = IMAGE_TYPE_DATA;
906 item_generic_1bs(value, 1, ITEM_1BS_IMAGE_TYPE)
907}
908
909/// Create Image Type item, of type EXE.
910pub const fn item_image_type_exe(security: Security, arch: Architecture) -> u32 {
911 let mut value = IMAGE_TYPE_EXE | IMAGE_TYPE_EXE_CHIP_RP2350;
912
913 match arch {
914 Architecture::Arm => {
915 value |= IMAGE_TYPE_EXE_CPU_ARM;
916 }
917 Architecture::Riscv => {
918 value |= IMAGE_TYPE_EXE_CPU_RISCV;
919 }
920 }
921
922 match security {
923 Security::Unspecified => value |= IMAGE_TYPE_EXE_TYPE_SECURITY_UNSPECIFIED,
924 Security::NonSecure => value |= IMAGE_TYPE_EXE_TYPE_SECURITY_NS,
925 Security::Secure => value |= IMAGE_TYPE_EXE_TYPE_SECURITY_S,
926 }
927
928 item_generic_1bs(value, 1, ITEM_1BS_IMAGE_TYPE)
929}
930
931/// Create a Block Last item.
932pub const fn item_last(length: u16) -> u32 {
933 item_generic_2bs(0, length, ITEM_2BS_LAST)
934}
935
936/// Create a Vector Table item.
937///
938/// This is only allowed on Arm systems.
939pub const fn item_vector_table(table_ptr: u32) -> [u32; 2] {
940 [item_generic_1bs(0, 2, ITEM_1BS_VECTOR_TABLE), table_ptr]
941}
942
943/// Create an Entry Point item.
944pub const fn item_entry_point(entry_point: u32, initial_sp: u32) -> [u32; 3] {
945 [item_generic_1bs(0, 3, ITEM_1BS_ENTRY_POINT), entry_point, initial_sp]
946}
947
948/// Create an Rolling Window item.
949///
950/// The delta is the number of bytes into the image that 0x10000000 should
951/// be mapped.
952pub const fn item_rolling_window(delta: u32) -> [u32; 2] {
953 [item_generic_1bs(0, 3, ITEM_1BS_ROLLING_WINDOW_DELTA), delta]
954}
955
956#[cfg(test)]
957mod test {
958 use super::*;
959
960 /// I used this JSON, with `picotool partition create`:
961 ///
962 /// ```json
963 /// {
964 /// "version": [1, 0],
965 /// "unpartitioned": {
966 /// "families": ["absolute"],
967 /// "permissions": {
968 /// "secure": "rw",
969 /// "nonsecure": "rw",
970 /// "bootloader": "rw"
971 /// }
972 /// },
973 /// "partitions": [
974 /// {
975 /// "name": "A",
976 /// "id": 0,
977 /// "size": "2044K",
978 /// "families": ["rp2350-arm-s", "rp2350-riscv"],
979 /// "permissions": {
980 /// "secure": "rw",
981 /// "nonsecure": "rw",
982 /// "bootloader": "rw"
983 /// }
984 /// },
985 /// {
986 /// "name": "B",
987 /// "id": 1,
988 /// "size": "2044K",
989 /// "families": ["rp2350-arm-s", "rp2350-riscv"],
990 /// "permissions": {
991 /// "secure": "rw",
992 /// "nonsecure": "rw",
993 /// "bootloader": "rw"
994 /// },
995 /// "link": ["a", 0]
996 /// }
997 /// ]
998 /// }
999 /// ```
1000 #[test]
1001 fn make_hashed_partition_table() {
1002 let table = PartitionTableBlock::new()
1003 .add_partition_item(
1004 UnpartitionedSpace::new()
1005 .with_permission(Permission::SecureRead)
1006 .with_permission(Permission::SecureWrite)
1007 .with_permission(Permission::NonSecureRead)
1008 .with_permission(Permission::NonSecureWrite)
1009 .with_permission(Permission::BootRead)
1010 .with_permission(Permission::BootWrite)
1011 .with_flag(UnpartitionedFlag::AcceptsDefaultFamilyAbsolute),
1012 &[
1013 Partition::new(2, 512)
1014 .with_id(0)
1015 .with_flag(PartitionFlag::AcceptsDefaultFamilyRp2350ArmS)
1016 .with_flag(PartitionFlag::AcceptsDefaultFamilyRp2350Riscv)
1017 .with_permission(Permission::SecureRead)
1018 .with_permission(Permission::SecureWrite)
1019 .with_permission(Permission::NonSecureRead)
1020 .with_permission(Permission::NonSecureWrite)
1021 .with_permission(Permission::BootRead)
1022 .with_permission(Permission::BootWrite)
1023 .with_name("A"),
1024 Partition::new(513, 1023)
1025 .with_id(1)
1026 .with_flag(PartitionFlag::AcceptsDefaultFamilyRp2350ArmS)
1027 .with_flag(PartitionFlag::AcceptsDefaultFamilyRp2350Riscv)
1028 .with_link(Link::ToA { partition_idx: 0 })
1029 .with_permission(Permission::SecureRead)
1030 .with_permission(Permission::SecureWrite)
1031 .with_permission(Permission::NonSecureRead)
1032 .with_permission(Permission::NonSecureWrite)
1033 .with_permission(Permission::BootRead)
1034 .with_permission(Permission::BootWrite)
1035 .with_name("B"),
1036 ],
1037 )
1038 .with_version(1, 0)
1039 .with_sha256();
1040 let expected = &[
1041 0xffffded3, // start
1042 0x02000c0a, // Item = PARTITION_TABLE
1043 0xfc008000, // Unpartitioned Space - permissions_and_flags
1044 0xfc400002, // Partition 0 - permissions_and_location (512 * 4096, 2 * 4096)
1045 0xfc061001, // permissions_and_flags HAS_ID | HAS_NAME | ARM-S | RISC-V
1046 0x00000000, // ID
1047 0x00000000, // ID
1048 0x00004101, // Name ("A")
1049 0xfc7fe201, // Partition 1 - permissions_and_location (1023 * 4096, 513 * 4096)
1050 0xfc061003, // permissions_and_flags LINKA(0) | HAS_ID | HAS_NAME | ARM-S | RISC-V
1051 0x00000001, // ID
1052 0x00000000, // ID
1053 0x00004201, // Name ("B")
1054 0x00000248, // Item = Version
1055 0x00010000, // 0, 1
1056 0x01000247, // HASH_DEF with 2 words, and SHA256 hash
1057 0x00000011, // 17 words hashed
1058 0x0000094b, // HASH_VALUE with 9 words
1059 0x1945cdad, // Hash word 0
1060 0x6b5f9773, // Hash word 1
1061 0xe2bf39bd, // Hash word 2
1062 0xb243e599, // Hash word 3
1063 0xab2f0e9a, // Hash word 4
1064 0x4d5d6d0b, // Hash word 5
1065 0xf973050f, // Hash word 6
1066 0x5ab6dadb, // Hash word 7
1067 0x000019ff, // Last Item
1068 0x00000000, // Block Loop Next Offset
1069 0xab123579, // End
1070 ];
1071 core::assert_eq!(
1072 &table.contents[..29],
1073 expected,
1074 "{:#010x?}\n != \n{:#010x?}",
1075 &table.contents[0..29],
1076 expected,
1077 );
1078 }
1079}
diff --git a/embassy-rp/src/bootsel.rs b/embassy-rp/src/bootsel.rs
index 540255ae3..d24ce7bd8 100644
--- a/embassy-rp/src/bootsel.rs
+++ b/embassy-rp/src/bootsel.rs
@@ -57,9 +57,9 @@ mod ram_helpers {
57 "str {val}, [{cs_gpio}, $GPIO_CTRL]", 57 "str {val}, [{cs_gpio}, $GPIO_CTRL]",
58 58
59 // ...then wait for the state to settle... 59 // ...then wait for the state to settle...
60 "1:", // ~4000 cycle delay loop 60 "2:", // ~4000 cycle delay loop
61 "subs {val}, #8", 61 "subs {val}, #8",
62 "bne 1b", 62 "bne 2b",
63 63
64 // ...we can read the current state of bootsel 64 // ...we can read the current state of bootsel
65 "ldr {val}, [{cs_gpio}, $GPIO_STATUS]", 65 "ldr {val}, [{cs_gpio}, $GPIO_STATUS]",
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index d0c6c19bd..ed146844c 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -1,12 +1,17 @@
1//! Clock configuration for the RP2040 1//! Clock configuration for the RP2040
2
3#[cfg(feature = "rp2040")]
2use core::arch::asm; 4use core::arch::asm;
3use core::marker::PhantomData; 5use core::marker::PhantomData;
4use core::sync::atomic::{AtomicU16, AtomicU32, Ordering}; 6#[cfg(feature = "rp2040")]
7use core::sync::atomic::AtomicU16;
8use core::sync::atomic::{AtomicU32, Ordering};
5 9
6use embassy_hal_internal::{into_ref, PeripheralRef}; 10use embassy_hal_internal::{into_ref, PeripheralRef};
7use pac::clocks::vals::*; 11use pac::clocks::vals::*;
8 12
9use crate::gpio::{AnyPin, SealedPin}; 13use crate::gpio::{AnyPin, SealedPin};
14#[cfg(feature = "rp2040")]
10use crate::pac::common::{Reg, RW}; 15use crate::pac::common::{Reg, RW};
11use crate::{pac, reset, Peripheral}; 16use crate::{pac, reset, Peripheral};
12 17
@@ -26,6 +31,7 @@ struct Clocks {
26 // gpin1: AtomicU32, 31 // gpin1: AtomicU32,
27 rosc: AtomicU32, 32 rosc: AtomicU32,
28 peri: AtomicU32, 33 peri: AtomicU32,
34 #[cfg(feature = "rp2040")]
29 rtc: AtomicU16, 35 rtc: AtomicU16,
30} 36}
31 37
@@ -41,6 +47,7 @@ static CLOCKS: Clocks = Clocks {
41 // gpin1: AtomicU32::new(0), 47 // gpin1: AtomicU32::new(0),
42 rosc: AtomicU32::new(0), 48 rosc: AtomicU32::new(0),
43 peri: AtomicU32::new(0), 49 peri: AtomicU32::new(0),
50 #[cfg(feature = "rp2040")]
44 rtc: AtomicU16::new(0), 51 rtc: AtomicU16::new(0),
45}; 52};
46 53
@@ -81,6 +88,7 @@ pub struct ClockConfig {
81 /// ADC clock configuration. 88 /// ADC clock configuration.
82 pub adc_clk: Option<AdcClkConfig>, 89 pub adc_clk: Option<AdcClkConfig>,
83 /// RTC clock configuration. 90 /// RTC clock configuration.
91 #[cfg(feature = "rp2040")]
84 pub rtc_clk: Option<RtcClkConfig>, 92 pub rtc_clk: Option<RtcClkConfig>,
85 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, 93 // gpin0: Option<(u32, Gpin<'static, AnyPin>)>,
86 // gpin1: Option<(u32, Gpin<'static, AnyPin>)>, 94 // gpin1: Option<(u32, Gpin<'static, AnyPin>)>,
@@ -135,6 +143,7 @@ impl ClockConfig {
135 phase: 0, 143 phase: 0,
136 }), 144 }),
137 // CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz 145 // CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz
146 #[cfg(feature = "rp2040")]
138 rtc_clk: Some(RtcClkConfig { 147 rtc_clk: Some(RtcClkConfig {
139 src: RtcClkSrc::PllUsb, 148 src: RtcClkSrc::PllUsb,
140 div_int: 1024, 149 div_int: 1024,
@@ -174,6 +183,7 @@ impl ClockConfig {
174 phase: 0, 183 phase: 0,
175 }), 184 }),
176 // CLK RTC = ROSC (140MHz) / 2986.667969 ≅ 46875Hz 185 // CLK RTC = ROSC (140MHz) / 2986.667969 ≅ 46875Hz
186 #[cfg(feature = "rp2040")]
177 rtc_clk: Some(RtcClkConfig { 187 rtc_clk: Some(RtcClkConfig {
178 src: RtcClkSrc::Rosc, 188 src: RtcClkSrc::Rosc,
179 div_int: 2986, 189 div_int: 2986,
@@ -295,9 +305,17 @@ pub struct SysClkConfig {
295 /// SYS clock source. 305 /// SYS clock source.
296 pub src: SysClkSrc, 306 pub src: SysClkSrc,
297 /// SYS clock divider. 307 /// SYS clock divider.
308 #[cfg(feature = "rp2040")]
298 pub div_int: u32, 309 pub div_int: u32,
299 /// SYS clock fraction. 310 /// SYS clock fraction.
311 #[cfg(feature = "rp2040")]
300 pub div_frac: u8, 312 pub div_frac: u8,
313 /// SYS clock divider.
314 #[cfg(feature = "_rp235x")]
315 pub div_int: u16,
316 /// SYS clock fraction.
317 #[cfg(feature = "_rp235x")]
318 pub div_frac: u16,
301} 319}
302 320
303/// USB clock source. 321/// USB clock source.
@@ -358,6 +376,7 @@ pub struct AdcClkConfig {
358#[repr(u8)] 376#[repr(u8)]
359#[non_exhaustive] 377#[non_exhaustive]
360#[derive(Clone, Copy, Debug, PartialEq, Eq)] 378#[derive(Clone, Copy, Debug, PartialEq, Eq)]
379#[cfg(feature = "rp2040")]
361pub enum RtcClkSrc { 380pub enum RtcClkSrc {
362 /// PLL USB. 381 /// PLL USB.
363 PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB as _, 382 PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB as _,
@@ -372,6 +391,7 @@ pub enum RtcClkSrc {
372} 391}
373 392
374/// RTC clock config. 393/// RTC clock config.
394#[cfg(feature = "rp2040")]
375pub struct RtcClkConfig { 395pub struct RtcClkConfig {
376 /// RTC clock source. 396 /// RTC clock source.
377 pub src: RtcClkSrc, 397 pub src: RtcClkSrc,
@@ -396,10 +416,9 @@ pub(crate) unsafe fn init(config: ClockConfig) {
396 peris.set_pads_qspi(false); 416 peris.set_pads_qspi(false);
397 peris.set_pll_sys(false); 417 peris.set_pll_sys(false);
398 peris.set_pll_usb(false); 418 peris.set_pll_usb(false);
399 // TODO investigate if usb should be unreset here
400 peris.set_usbctrl(false); 419 peris.set_usbctrl(false);
401 peris.set_syscfg(false); 420 peris.set_syscfg(false);
402 peris.set_rtc(false); 421 //peris.set_rtc(false);
403 reset::reset(peris); 422 reset::reset(peris);
404 423
405 // Disable resus that may be enabled from previous software 424 // Disable resus that may be enabled from previous software
@@ -409,9 +428,15 @@ pub(crate) unsafe fn init(config: ClockConfig) {
409 428
410 // Before we touch PLLs, switch sys and ref cleanly away from their aux sources. 429 // Before we touch PLLs, switch sys and ref cleanly away from their aux sources.
411 c.clk_sys_ctrl().modify(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); 430 c.clk_sys_ctrl().modify(|w| w.set_src(ClkSysCtrlSrc::CLK_REF));
431 #[cfg(feature = "rp2040")]
412 while c.clk_sys_selected().read() != 1 {} 432 while c.clk_sys_selected().read() != 1 {}
433 #[cfg(feature = "_rp235x")]
434 while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1) {}
413 c.clk_ref_ctrl().modify(|w| w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH)); 435 c.clk_ref_ctrl().modify(|w| w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH));
436 #[cfg(feature = "rp2040")]
414 while c.clk_ref_selected().read() != 1 {} 437 while c.clk_ref_selected().read() != 1 {}
438 #[cfg(feature = "_rp235x")]
439 while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1) {}
415 440
416 // Reset the PLLs 441 // Reset the PLLs
417 let mut peris = reset::Peripherals(0); 442 let mut peris = reset::Peripherals(0);
@@ -479,15 +504,26 @@ pub(crate) unsafe fn init(config: ClockConfig) {
479 w.set_src(ref_src); 504 w.set_src(ref_src);
480 w.set_auxsrc(ref_aux); 505 w.set_auxsrc(ref_aux);
481 }); 506 });
482 while c.clk_ref_selected().read() != 1 << ref_src as u32 {} 507 #[cfg(feature = "rp2040")]
508 while c.clk_ref_selected().read() != (1 << ref_src as u32) {}
509 #[cfg(feature = "_rp235x")]
510 while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1 << ref_src as u32) {}
483 c.clk_ref_div().write(|w| { 511 c.clk_ref_div().write(|w| {
484 w.set_int(config.ref_clk.div); 512 w.set_int(config.ref_clk.div);
485 }); 513 });
486 514
515 // Configure tick generation on the 2040.
516 #[cfg(feature = "rp2040")]
487 pac::WATCHDOG.tick().write(|w| { 517 pac::WATCHDOG.tick().write(|w| {
488 w.set_cycles((clk_ref_freq / 1_000_000) as u16); 518 w.set_cycles((clk_ref_freq / 1_000_000) as u16);
489 w.set_enable(true); 519 w.set_enable(true);
490 }); 520 });
521 // Configure tick generator on the 2350
522 #[cfg(feature = "_rp235x")]
523 {
524 pac::TICKS.timer0_cycles().write(|w| w.0 = clk_ref_freq / 1_000_000);
525 pac::TICKS.timer0_ctrl().write(|w| w.set_enable(true));
526 }
491 527
492 let (sys_src, sys_aux, clk_sys_freq) = { 528 let (sys_src, sys_aux, clk_sys_freq) = {
493 use {ClkSysCtrlAuxsrc as Aux, ClkSysCtrlSrc as Src}; 529 use {ClkSysCtrlAuxsrc as Aux, ClkSysCtrlSrc as Src};
@@ -500,7 +536,6 @@ pub(crate) unsafe fn init(config: ClockConfig) {
500 // SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq), 536 // SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq),
501 // SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1, gpin1_freq), 537 // SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1, gpin1_freq),
502 }; 538 };
503 assert!(config.sys_clk.div_int <= 0x1000000);
504 let div = config.sys_clk.div_int as u64 * 256 + config.sys_clk.div_frac as u64; 539 let div = config.sys_clk.div_int as u64 * 256 + config.sys_clk.div_frac as u64;
505 (src, aux, ((freq as u64 * 256) / div) as u32) 540 (src, aux, ((freq as u64 * 256) / div) as u32)
506 }; 541 };
@@ -508,13 +543,21 @@ pub(crate) unsafe fn init(config: ClockConfig) {
508 CLOCKS.sys.store(clk_sys_freq, Ordering::Relaxed); 543 CLOCKS.sys.store(clk_sys_freq, Ordering::Relaxed);
509 if sys_src != ClkSysCtrlSrc::CLK_REF { 544 if sys_src != ClkSysCtrlSrc::CLK_REF {
510 c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); 545 c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF));
511 while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF as u32 {} 546 #[cfg(feature = "rp2040")]
547 while c.clk_sys_selected().read() != (1 << ClkSysCtrlSrc::CLK_REF as u32) {}
548 #[cfg(feature = "_rp235x")]
549 while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1 << ClkSysCtrlSrc::CLK_REF as u32) {}
512 } 550 }
513 c.clk_sys_ctrl().write(|w| { 551 c.clk_sys_ctrl().write(|w| {
514 w.set_auxsrc(sys_aux); 552 w.set_auxsrc(sys_aux);
515 w.set_src(sys_src); 553 w.set_src(sys_src);
516 }); 554 });
517 while c.clk_sys_selected().read() != 1 << sys_src as u32 {} 555
556 #[cfg(feature = "rp2040")]
557 while c.clk_sys_selected().read() != (1 << sys_src as u32) {}
558 #[cfg(feature = "_rp235x")]
559 while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1 << sys_src as u32) {}
560
518 c.clk_sys_div().write(|w| { 561 c.clk_sys_div().write(|w| {
519 w.set_int(config.sys_clk.div_int); 562 w.set_int(config.sys_clk.div_int);
520 w.set_frac(config.sys_clk.div_frac); 563 w.set_frac(config.sys_clk.div_frac);
@@ -592,6 +635,8 @@ pub(crate) unsafe fn init(config: ClockConfig) {
592 CLOCKS.adc.store(0, Ordering::Relaxed); 635 CLOCKS.adc.store(0, Ordering::Relaxed);
593 } 636 }
594 637
638 // rp2040 specific clocks
639 #[cfg(feature = "rp2040")]
595 if let Some(conf) = config.rtc_clk { 640 if let Some(conf) = config.rtc_clk {
596 c.clk_rtc_div().write(|w| { 641 c.clk_rtc_div().write(|w| {
597 w.set_int(conf.div_int); 642 w.set_int(conf.div_int);
@@ -621,6 +666,13 @@ pub(crate) unsafe fn init(config: ClockConfig) {
621 CLOCKS.rtc.store(0, Ordering::Relaxed); 666 CLOCKS.rtc.store(0, Ordering::Relaxed);
622 } 667 }
623 668
669 // rp235x specific clocks
670 #[cfg(feature = "_rp235x")]
671 {
672 // TODO hstx clock
673 peris.set_hstx(false);
674 }
675
624 // Peripheral clocks should now all be running 676 // Peripheral clocks should now all be running
625 reset::unreset_wait(peris); 677 reset::unreset_wait(peris);
626} 678}
@@ -709,6 +761,7 @@ pub fn clk_adc_freq() -> u32 {
709} 761}
710 762
711/// RTC clock frequency. 763/// RTC clock frequency.
764#[cfg(feature = "rp2040")]
712pub fn clk_rtc_freq() -> u16 { 765pub fn clk_rtc_freq() -> u16 {
713 CLOCKS.rtc.load(Ordering::Relaxed) 766 CLOCKS.rtc.load(Ordering::Relaxed)
714} 767}
@@ -856,6 +909,7 @@ pub enum GpoutSrc {
856 /// ADC. 909 /// ADC.
857 Adc = ClkGpoutCtrlAuxsrc::CLK_ADC as _, 910 Adc = ClkGpoutCtrlAuxsrc::CLK_ADC as _,
858 /// RTC. 911 /// RTC.
912 #[cfg(feature = "rp2040")]
859 Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _, 913 Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _,
860 /// REF. 914 /// REF.
861 Ref = ClkGpoutCtrlAuxsrc::CLK_REF as _, 915 Ref = ClkGpoutCtrlAuxsrc::CLK_REF as _,
@@ -877,6 +931,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
877 } 931 }
878 932
879 /// Set clock divider. 933 /// Set clock divider.
934 #[cfg(feature = "rp2040")]
880 pub fn set_div(&self, int: u32, frac: u8) { 935 pub fn set_div(&self, int: u32, frac: u8) {
881 let c = pac::CLOCKS; 936 let c = pac::CLOCKS;
882 c.clk_gpout_div(self.gpout.number()).write(|w| { 937 c.clk_gpout_div(self.gpout.number()).write(|w| {
@@ -885,6 +940,16 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
885 }); 940 });
886 } 941 }
887 942
943 /// Set clock divider.
944 #[cfg(feature = "_rp235x")]
945 pub fn set_div(&self, int: u16, frac: u16) {
946 let c = pac::CLOCKS;
947 c.clk_gpout_div(self.gpout.number()).write(|w| {
948 w.set_int(int);
949 w.set_frac(frac);
950 });
951 }
952
888 /// Set clock source. 953 /// Set clock source.
889 pub fn set_src(&self, src: GpoutSrc) { 954 pub fn set_src(&self, src: GpoutSrc) {
890 let c = pac::CLOCKS; 955 let c = pac::CLOCKS;
@@ -924,13 +989,13 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
924 ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(), 989 ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(),
925 ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(), 990 ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(),
926 ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(), 991 ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(),
927 ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq() as _, 992 //ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq() as _,
928 ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(), 993 ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(),
929 _ => unreachable!(), 994 _ => unreachable!(),
930 }; 995 };
931 996
932 let div = c.clk_gpout_div(self.gpout.number()).read(); 997 let div = c.clk_gpout_div(self.gpout.number()).read();
933 let int = if div.int() == 0 { 65536 } else { div.int() } as u64; 998 let int = if div.int() == 0 { 0xFFFF } else { div.int() } as u64;
934 let frac = div.frac() as u64; 999 let frac = div.frac() as u64;
935 1000
936 ((base as u64 * 256) / (int * 256 + frac)) as u32 1001 ((base as u64 * 256) / (int * 256 + frac)) as u32
@@ -987,7 +1052,7 @@ impl rand_core::RngCore for RoscRng {
987/// and can only be exited through resets, dormant-wake GPIO interrupts, 1052/// and can only be exited through resets, dormant-wake GPIO interrupts,
988/// and RTC interrupts. If RTC is clocked from an internal clock source 1053/// and RTC interrupts. If RTC is clocked from an internal clock source
989/// it will be stopped and not function as a wakeup source. 1054/// it will be stopped and not function as a wakeup source.
990#[cfg(target_arch = "arm")] 1055#[cfg(all(target_arch = "arm", feature = "rp2040"))]
991pub fn dormant_sleep() { 1056pub fn dormant_sleep() {
992 struct Set<T: Copy, F: Fn()>(Reg<T, RW>, T, F); 1057 struct Set<T: Copy, F: Fn()>(Reg<T, RW>, T, F);
993 1058
@@ -1107,7 +1172,7 @@ pub fn dormant_sleep() {
1107 coma = in (reg) 0x636f6d61, 1172 coma = in (reg) 0x636f6d61,
1108 ); 1173 );
1109 } else { 1174 } else {
1110 pac::ROSC.dormant().write_value(0x636f6d61); 1175 pac::ROSC.dormant().write_value(rp_pac::rosc::regs::Dormant(0x636f6d61));
1111 } 1176 }
1112 } 1177 }
1113} 1178}
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs
index 8c04b43a1..34abe3e2d 100644
--- a/embassy-rp/src/dma.rs
+++ b/embassy-rp/src/dma.rs
@@ -15,7 +15,7 @@ use crate::{interrupt, pac, peripherals};
15#[cfg(feature = "rt")] 15#[cfg(feature = "rt")]
16#[interrupt] 16#[interrupt]
17fn DMA_IRQ_0() { 17fn DMA_IRQ_0() {
18 let ints0 = pac::DMA.ints0().read().ints0(); 18 let ints0 = pac::DMA.ints(0).read();
19 for channel in 0..CHANNEL_COUNT { 19 for channel in 0..CHANNEL_COUNT {
20 let ctrl_trig = pac::DMA.ch(channel).ctrl_trig().read(); 20 let ctrl_trig = pac::DMA.ch(channel).ctrl_trig().read();
21 if ctrl_trig.ahb_error() { 21 if ctrl_trig.ahb_error() {
@@ -26,14 +26,14 @@ fn DMA_IRQ_0() {
26 CHANNEL_WAKERS[channel].wake(); 26 CHANNEL_WAKERS[channel].wake();
27 } 27 }
28 } 28 }
29 pac::DMA.ints0().write(|w| w.set_ints0(ints0)); 29 pac::DMA.ints(0).write_value(ints0);
30} 30}
31 31
32pub(crate) unsafe fn init() { 32pub(crate) unsafe fn init() {
33 interrupt::DMA_IRQ_0.disable(); 33 interrupt::DMA_IRQ_0.disable();
34 interrupt::DMA_IRQ_0.set_priority(interrupt::Priority::P3); 34 interrupt::DMA_IRQ_0.set_priority(interrupt::Priority::P3);
35 35
36 pac::DMA.inte0().write(|w| w.set_inte0(0xFFFF)); 36 pac::DMA.inte(0).write_value(0xFFFF);
37 37
38 interrupt::DMA_IRQ_0.enable(); 38 interrupt::DMA_IRQ_0.enable();
39} 39}
@@ -45,7 +45,7 @@ pub unsafe fn read<'a, C: Channel, W: Word>(
45 ch: impl Peripheral<P = C> + 'a, 45 ch: impl Peripheral<P = C> + 'a,
46 from: *const W, 46 from: *const W,
47 to: *mut [W], 47 to: *mut [W],
48 dreq: u8, 48 dreq: vals::TreqSel,
49) -> Transfer<'a, C> { 49) -> Transfer<'a, C> {
50 copy_inner( 50 copy_inner(
51 ch, 51 ch,
@@ -66,7 +66,7 @@ pub unsafe fn write<'a, C: Channel, W: Word>(
66 ch: impl Peripheral<P = C> + 'a, 66 ch: impl Peripheral<P = C> + 'a,
67 from: *const [W], 67 from: *const [W],
68 to: *mut W, 68 to: *mut W,
69 dreq: u8, 69 dreq: vals::TreqSel,
70) -> Transfer<'a, C> { 70) -> Transfer<'a, C> {
71 copy_inner( 71 copy_inner(
72 ch, 72 ch,
@@ -90,7 +90,7 @@ pub unsafe fn write_repeated<'a, C: Channel, W: Word>(
90 ch: impl Peripheral<P = C> + 'a, 90 ch: impl Peripheral<P = C> + 'a,
91 to: *mut W, 91 to: *mut W,
92 len: usize, 92 len: usize,
93 dreq: u8, 93 dreq: vals::TreqSel,
94) -> Transfer<'a, C> { 94) -> Transfer<'a, C> {
95 copy_inner( 95 copy_inner(
96 ch, 96 ch,
@@ -123,7 +123,7 @@ pub unsafe fn copy<'a, C: Channel, W: Word>(
123 W::size(), 123 W::size(),
124 true, 124 true,
125 true, 125 true,
126 vals::TreqSel::PERMANENT.0, 126 vals::TreqSel::PERMANENT,
127 ) 127 )
128} 128}
129 129
@@ -135,7 +135,7 @@ fn copy_inner<'a, C: Channel>(
135 data_size: DataSize, 135 data_size: DataSize,
136 incr_read: bool, 136 incr_read: bool,
137 incr_write: bool, 137 incr_write: bool,
138 dreq: u8, 138 dreq: vals::TreqSel,
139) -> Transfer<'a, C> { 139) -> Transfer<'a, C> {
140 into_ref!(ch); 140 into_ref!(ch);
141 141
@@ -143,14 +143,20 @@ fn copy_inner<'a, C: Channel>(
143 143
144 p.read_addr().write_value(from as u32); 144 p.read_addr().write_value(from as u32);
145 p.write_addr().write_value(to as u32); 145 p.write_addr().write_value(to as u32);
146 p.trans_count().write_value(len as u32); 146 #[cfg(feature = "rp2040")]
147 p.trans_count().write(|w| {
148 *w = len as u32;
149 });
150 #[cfg(feature = "_rp235x")]
151 p.trans_count().write(|w| {
152 w.set_mode(0.into());
153 w.set_count(len as u32);
154 });
147 155
148 compiler_fence(Ordering::SeqCst); 156 compiler_fence(Ordering::SeqCst);
149 157
150 p.ctrl_trig().write(|w| { 158 p.ctrl_trig().write(|w| {
151 // TODO: Add all DREQ options to pac vals::TreqSel, and use 159 w.set_treq_sel(dreq);
152 // `set_treq:sel`
153 w.0 = ((dreq as u32) & 0x3f) << 15usize;
154 w.set_data_size(data_size); 160 w.set_data_size(data_size);
155 w.set_incr_read(incr_read); 161 w.set_incr_read(incr_read);
156 w.set_incr_write(incr_write); 162 w.set_incr_write(incr_write);
@@ -202,7 +208,10 @@ impl<'a, C: Channel> Future for Transfer<'a, C> {
202 } 208 }
203} 209}
204 210
211#[cfg(feature = "rp2040")]
205pub(crate) const CHANNEL_COUNT: usize = 12; 212pub(crate) const CHANNEL_COUNT: usize = 12;
213#[cfg(feature = "_rp235x")]
214pub(crate) const CHANNEL_COUNT: usize = 16;
206const NEW_AW: AtomicWaker = AtomicWaker::new(); 215const NEW_AW: AtomicWaker = AtomicWaker::new();
207static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AW; CHANNEL_COUNT]; 216static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AW; CHANNEL_COUNT];
208 217
@@ -297,3 +306,11 @@ channel!(DMA_CH8, 8);
297channel!(DMA_CH9, 9); 306channel!(DMA_CH9, 9);
298channel!(DMA_CH10, 10); 307channel!(DMA_CH10, 10);
299channel!(DMA_CH11, 11); 308channel!(DMA_CH11, 11);
309#[cfg(feature = "_rp235x")]
310channel!(DMA_CH12, 12);
311#[cfg(feature = "_rp235x")]
312channel!(DMA_CH13, 13);
313#[cfg(feature = "_rp235x")]
314channel!(DMA_CH14, 14);
315#[cfg(feature = "_rp235x")]
316channel!(DMA_CH15, 15);
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs
index 6e2a823d8..fbc8b35ec 100644
--- a/embassy-rp/src/flash.rs
+++ b/embassy-rp/src/flash.rs
@@ -17,9 +17,13 @@ use crate::peripherals::FLASH;
17/// Flash base address. 17/// Flash base address.
18pub const FLASH_BASE: *const u32 = 0x10000000 as _; 18pub const FLASH_BASE: *const u32 = 0x10000000 as _;
19 19
20/// Address for xip setup function set up by the 235x bootrom.
21#[cfg(feature = "_rp235x")]
22pub const BOOTROM_BASE: *const u32 = 0x400e0000 as _;
23
20/// If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead. 24/// If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead.
21// TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance. 25// TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance.
22pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram"); 26pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram") | cfg!(feature = "_rp235x");
23 27
24// **NOTE**: 28// **NOTE**:
25// 29//
@@ -97,7 +101,10 @@ impl<'a, 'd, T: Instance, const FLASH_SIZE: usize> Drop for BackgroundRead<'a, '
97 // Errata RP2040-E8: Perform an uncached read to make sure there's not a transfer in 101 // Errata RP2040-E8: Perform an uncached read to make sure there's not a transfer in
98 // flight that might effect an address written to start a new transfer. This stalls 102 // flight that might effect an address written to start a new transfer. This stalls
99 // until after any transfer is complete, so the address will not change anymore. 103 // until after any transfer is complete, so the address will not change anymore.
104 #[cfg(feature = "rp2040")]
100 const XIP_NOCACHE_NOALLOC_BASE: *const u32 = 0x13000000 as *const _; 105 const XIP_NOCACHE_NOALLOC_BASE: *const u32 = 0x13000000 as *const _;
106 #[cfg(feature = "_rp235x")]
107 const XIP_NOCACHE_NOALLOC_BASE: *const u32 = 0x14000000 as *const _;
101 unsafe { 108 unsafe {
102 core::ptr::read_volatile(XIP_NOCACHE_NOALLOC_BASE); 109 core::ptr::read_volatile(XIP_NOCACHE_NOALLOC_BASE);
103 } 110 }
@@ -225,12 +232,14 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI
225 } 232 }
226 233
227 /// Read SPI flash unique ID 234 /// Read SPI flash unique ID
235 #[cfg(feature = "rp2040")]
228 pub fn blocking_unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> { 236 pub fn blocking_unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> {
229 unsafe { in_ram(|| ram_helpers::flash_unique_id(uid))? }; 237 unsafe { in_ram(|| ram_helpers::flash_unique_id(uid))? };
230 Ok(()) 238 Ok(())
231 } 239 }
232 240
233 /// Read SPI flash JEDEC ID 241 /// Read SPI flash JEDEC ID
242 #[cfg(feature = "rp2040")]
234 pub fn blocking_jedec_id(&mut self) -> Result<u32, Error> { 243 pub fn blocking_jedec_id(&mut self) -> Result<u32, Error> {
235 let mut jedec = None; 244 let mut jedec = None;
236 unsafe { 245 unsafe {
@@ -301,8 +310,18 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> {
301 // Use the XIP AUX bus port, rather than the FIFO register access (e.x. 310 // Use the XIP AUX bus port, rather than the FIFO register access (e.x.
302 // pac::XIP_CTRL.stream_fifo().as_ptr()) to avoid DMA stalling on 311 // pac::XIP_CTRL.stream_fifo().as_ptr()) to avoid DMA stalling on
303 // general XIP access. 312 // general XIP access.
313 #[cfg(feature = "rp2040")]
304 const XIP_AUX_BASE: *const u32 = 0x50400000 as *const _; 314 const XIP_AUX_BASE: *const u32 = 0x50400000 as *const _;
305 let transfer = unsafe { crate::dma::read(self.dma.as_mut().unwrap(), XIP_AUX_BASE, data, 37) }; 315 #[cfg(feature = "_rp235x")]
316 const XIP_AUX_BASE: *const u32 = 0x50500000 as *const _;
317 let transfer = unsafe {
318 crate::dma::read(
319 self.dma.as_mut().unwrap(),
320 XIP_AUX_BASE,
321 data,
322 pac::dma::vals::TreqSel::XIP_STREAM,
323 )
324 };
306 325
307 Ok(BackgroundRead { 326 Ok(BackgroundRead {
308 flash: PhantomData, 327 flash: PhantomData,
@@ -505,7 +524,10 @@ mod ram_helpers {
505 pub unsafe fn flash_range_erase(addr: u32, len: u32) { 524 pub unsafe fn flash_range_erase(addr: u32, len: u32) {
506 let mut boot2 = [0u32; 256 / 4]; 525 let mut boot2 = [0u32; 256 / 4];
507 let ptrs = if USE_BOOT2 { 526 let ptrs = if USE_BOOT2 {
527 #[cfg(feature = "rp2040")]
508 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); 528 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
529 #[cfg(feature = "_rp235x")]
530 core::ptr::copy_nonoverlapping(BOOTROM_BASE as *const u8, boot2.as_mut_ptr() as *mut u8, 256);
509 flash_function_pointers_with_boot2(true, false, &boot2) 531 flash_function_pointers_with_boot2(true, false, &boot2)
510 } else { 532 } else {
511 flash_function_pointers(true, false) 533 flash_function_pointers(true, false)
@@ -535,7 +557,10 @@ mod ram_helpers {
535 pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8]) { 557 pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8]) {
536 let mut boot2 = [0u32; 256 / 4]; 558 let mut boot2 = [0u32; 256 / 4];
537 let ptrs = if USE_BOOT2 { 559 let ptrs = if USE_BOOT2 {
560 #[cfg(feature = "rp2040")]
538 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); 561 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
562 #[cfg(feature = "_rp235x")]
563 core::ptr::copy_nonoverlapping(BOOTROM_BASE as *const u8, (boot2).as_mut_ptr() as *mut u8, 256);
539 flash_function_pointers_with_boot2(true, true, &boot2) 564 flash_function_pointers_with_boot2(true, true, &boot2)
540 } else { 565 } else {
541 flash_function_pointers(true, true) 566 flash_function_pointers(true, true)
@@ -570,7 +595,10 @@ mod ram_helpers {
570 pub unsafe fn flash_range_program(addr: u32, data: &[u8]) { 595 pub unsafe fn flash_range_program(addr: u32, data: &[u8]) {
571 let mut boot2 = [0u32; 256 / 4]; 596 let mut boot2 = [0u32; 256 / 4];
572 let ptrs = if USE_BOOT2 { 597 let ptrs = if USE_BOOT2 {
598 #[cfg(feature = "rp2040")]
573 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); 599 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
600 #[cfg(feature = "_rp235x")]
601 core::ptr::copy_nonoverlapping(BOOTROM_BASE as *const u8, boot2.as_mut_ptr() as *mut u8, 256);
574 flash_function_pointers_with_boot2(false, true, &boot2) 602 flash_function_pointers_with_boot2(false, true, &boot2)
575 } else { 603 } else {
576 flash_function_pointers(false, true) 604 flash_function_pointers(false, true)
@@ -597,16 +625,8 @@ mod ram_helpers {
597 /// addr must be aligned to 4096 625 /// addr must be aligned to 4096
598 #[inline(never)] 626 #[inline(never)]
599 #[link_section = ".data.ram_func"] 627 #[link_section = ".data.ram_func"]
628 #[cfg(feature = "rp2040")]
600 unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { 629 unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) {
601 /*
602 Should be equivalent to:
603 rom_data::connect_internal_flash();
604 rom_data::flash_exit_xip();
605 rom_data::flash_range_erase(addr, len, 1 << 31, 0); // if selected
606 rom_data::flash_range_program(addr, data as *const _, len); // if selected
607 rom_data::flash_flush_cache();
608 rom_data::flash_enter_cmd_xip();
609 */
610 #[cfg(target_arch = "arm")] 630 #[cfg(target_arch = "arm")]
611 core::arch::asm!( 631 core::arch::asm!(
612 "mov r8, r0", 632 "mov r8, r0",
@@ -625,18 +645,18 @@ mod ram_helpers {
625 "movs r3, #0", // r3 = 0 645 "movs r3, #0", // r3 = 0
626 "ldr r4, [{ptrs}, #8]", 646 "ldr r4, [{ptrs}, #8]",
627 "cmp r4, #0", 647 "cmp r4, #0",
628 "beq 1f", 648 "beq 2f",
629 "blx r4", // flash_range_erase(addr, len, 1 << 31, 0) 649 "blx r4", // flash_range_erase(addr, len, 1 << 31, 0)
630 "1:", 650 "2:",
631 651
632 "mov r0, r8", // r0 = addr 652 "mov r0, r8", // r0 = addr
633 "mov r1, r9", // r0 = data 653 "mov r1, r9", // r0 = data
634 "mov r2, r10", // r2 = len 654 "mov r2, r10", // r2 = len
635 "ldr r4, [{ptrs}, #12]", 655 "ldr r4, [{ptrs}, #12]",
636 "cmp r4, #0", 656 "cmp r4, #0",
637 "beq 1f", 657 "beq 2f",
638 "blx r4", // flash_range_program(addr, data, len); 658 "blx r4", // flash_range_program(addr, data, len);
639 "1:", 659 "2:",
640 660
641 "ldr r4, [{ptrs}, #16]", 661 "ldr r4, [{ptrs}, #16]",
642 "blx r4", // flash_flush_cache(); 662 "blx r4", // flash_flush_cache();
@@ -659,6 +679,32 @@ mod ram_helpers {
659 ); 679 );
660 } 680 }
661 681
682 /// # Safety
683 ///
684 /// Nothing must access flash while this is running.
685 /// Usually this means:
686 /// - interrupts must be disabled
687 /// - 2nd core must be running code from RAM or ROM with interrupts disabled
688 /// - DMA must not access flash memory
689 /// Length of data must be a multiple of 4096
690 /// addr must be aligned to 4096
691 #[inline(never)]
692 #[link_section = ".data.ram_func"]
693 #[cfg(feature = "_rp235x")]
694 unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) {
695 let data = data.map(|d| d.as_ptr()).unwrap_or(core::ptr::null());
696 ((*ptrs).connect_internal_flash)();
697 ((*ptrs).flash_exit_xip)();
698 if (*ptrs).flash_range_erase.is_some() {
699 ((*ptrs).flash_range_erase.unwrap())(addr, len as usize, 1 << 31, 0);
700 }
701 if (*ptrs).flash_range_program.is_some() {
702 ((*ptrs).flash_range_program.unwrap())(addr, data as *const _, len as usize);
703 }
704 ((*ptrs).flash_flush_cache)();
705 ((*ptrs).flash_enter_cmd_xip)();
706 }
707
662 #[repr(C)] 708 #[repr(C)]
663 struct FlashCommand { 709 struct FlashCommand {
664 cmd_addr: *const u8, 710 cmd_addr: *const u8,
@@ -692,6 +738,7 @@ mod ram_helpers {
692 /// - DMA must not access flash memory 738 /// - DMA must not access flash memory
693 /// 739 ///
694 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) 740 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
741 #[cfg(feature = "rp2040")]
695 pub unsafe fn flash_unique_id(out: &mut [u8]) { 742 pub unsafe fn flash_unique_id(out: &mut [u8]) {
696 let mut boot2 = [0u32; 256 / 4]; 743 let mut boot2 = [0u32; 256 / 4];
697 let ptrs = if USE_BOOT2 { 744 let ptrs = if USE_BOOT2 {
@@ -700,6 +747,7 @@ mod ram_helpers {
700 } else { 747 } else {
701 flash_function_pointers(false, false) 748 flash_function_pointers(false, false)
702 }; 749 };
750
703 // 4B - read unique ID 751 // 4B - read unique ID
704 let cmd = [0x4B]; 752 let cmd = [0x4B];
705 read_flash(&cmd[..], 4, out, &ptrs as *const FlashFunctionPointers); 753 read_flash(&cmd[..], 4, out, &ptrs as *const FlashFunctionPointers);
@@ -720,6 +768,7 @@ mod ram_helpers {
720 /// - DMA must not access flash memory 768 /// - DMA must not access flash memory
721 /// 769 ///
722 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) 770 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
771 #[cfg(feature = "rp2040")]
723 pub unsafe fn flash_jedec_id() -> u32 { 772 pub unsafe fn flash_jedec_id() -> u32 {
724 let mut boot2 = [0u32; 256 / 4]; 773 let mut boot2 = [0u32; 256 / 4];
725 let ptrs = if USE_BOOT2 { 774 let ptrs = if USE_BOOT2 {
@@ -728,6 +777,7 @@ mod ram_helpers {
728 } else { 777 } else {
729 flash_function_pointers(false, false) 778 flash_function_pointers(false, false)
730 }; 779 };
780
731 let mut id = [0u8; 4]; 781 let mut id = [0u8; 4];
732 // 9F - read JEDEC ID 782 // 9F - read JEDEC ID
733 let cmd = [0x9F]; 783 let cmd = [0x9F];
@@ -735,6 +785,7 @@ mod ram_helpers {
735 u32::from_be_bytes(id) 785 u32::from_be_bytes(id)
736 } 786 }
737 787
788 #[cfg(feature = "rp2040")]
738 unsafe fn read_flash(cmd_addr: &[u8], dummy_len: u32, out: &mut [u8], ptrs: *const FlashFunctionPointers) { 789 unsafe fn read_flash(cmd_addr: &[u8], dummy_len: u32, out: &mut [u8], ptrs: *const FlashFunctionPointers) {
739 read_flash_inner( 790 read_flash_inner(
740 FlashCommand { 791 FlashCommand {
@@ -758,6 +809,7 @@ mod ram_helpers {
758 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) 809 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
759 #[inline(never)] 810 #[inline(never)]
760 #[link_section = ".data.ram_func"] 811 #[link_section = ".data.ram_func"]
812 #[cfg(feature = "rp2040")]
761 unsafe fn read_flash_inner(cmd: FlashCommand, ptrs: *const FlashFunctionPointers) { 813 unsafe fn read_flash_inner(cmd: FlashCommand, ptrs: *const FlashFunctionPointers) {
762 #[cfg(target_arch = "arm")] 814 #[cfg(target_arch = "arm")]
763 core::arch::asm!( 815 core::arch::asm!(
@@ -802,12 +854,12 @@ mod ram_helpers {
802 "adds r2, 0x60", // &DR 854 "adds r2, 0x60", // &DR
803 "ldr r0, [r3, #0]", // cmd_addr 855 "ldr r0, [r3, #0]", // cmd_addr
804 "ldr r1, [r3, #4]", // cmd_addr_len 856 "ldr r1, [r3, #4]", // cmd_addr_len
805 "10:", 857 "3:",
806 "ldrb r3, [r0]", 858 "ldrb r3, [r0]",
807 "strb r3, [r2]", // DR 859 "strb r3, [r2]", // DR
808 "adds r0, #1", 860 "adds r0, #1",
809 "subs r1, #1", 861 "subs r1, #1",
810 "bne 10b", 862 "bne 3b",
811 863
812 // Skip any dummy cycles 864 // Skip any dummy cycles
813 "mov r3, r10", // cmd 865 "mov r3, r10", // cmd
diff --git a/embassy-rp/src/fmt.rs b/embassy-rp/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-rp/src/fmt.rs
+++ b/embassy-rp/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index ea87fd9da..d0bb7e574 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -14,7 +14,12 @@ use crate::pac::SIO;
14use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; 14use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
15 15
16const NEW_AW: AtomicWaker = AtomicWaker::new(); 16const NEW_AW: AtomicWaker = AtomicWaker::new();
17
18#[cfg(any(feature = "rp2040", feature = "rp235xa"))]
17const BANK0_PIN_COUNT: usize = 30; 19const BANK0_PIN_COUNT: usize = 30;
20#[cfg(feature = "rp235xb")]
21const BANK0_PIN_COUNT: usize = 48;
22
18static BANK0_WAKERS: [AtomicWaker; BANK0_PIN_COUNT] = [NEW_AW; BANK0_PIN_COUNT]; 23static BANK0_WAKERS: [AtomicWaker; BANK0_PIN_COUNT] = [NEW_AW; BANK0_PIN_COUNT];
19#[cfg(feature = "qspi-as-gpio")] 24#[cfg(feature = "qspi-as-gpio")]
20const QSPI_PIN_COUNT: usize = 6; 25const QSPI_PIN_COUNT: usize = 6;
@@ -178,6 +183,13 @@ impl<'d> Input<'d> {
178 pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<'_> { 183 pub fn dormant_wake(&mut self, cfg: DormantWakeConfig) -> DormantWake<'_> {
179 self.pin.dormant_wake(cfg) 184 self.pin.dormant_wake(cfg)
180 } 185 }
186
187 /// Set the pin's pad isolation
188 #[cfg(feature = "_rp235x")]
189 #[inline]
190 pub fn set_pad_isolation(&mut self, isolate: bool) {
191 self.pin.set_pad_isolation(isolate)
192 }
181} 193}
182 194
183/// Interrupt trigger levels. 195/// Interrupt trigger levels.
@@ -413,6 +425,13 @@ impl<'d> Output<'d> {
413 pub fn toggle(&mut self) { 425 pub fn toggle(&mut self) {
414 self.pin.toggle() 426 self.pin.toggle()
415 } 427 }
428
429 /// Set the pin's pad isolation
430 #[cfg(feature = "_rp235x")]
431 #[inline]
432 pub fn set_pad_isolation(&mut self, isolate: bool) {
433 self.pin.set_pad_isolation(isolate)
434 }
416} 435}
417 436
418/// GPIO output open-drain. 437/// GPIO output open-drain.
@@ -539,6 +558,13 @@ impl<'d> OutputOpenDrain<'d> {
539 pub async fn wait_for_any_edge(&mut self) { 558 pub async fn wait_for_any_edge(&mut self) {
540 self.pin.wait_for_any_edge().await; 559 self.pin.wait_for_any_edge().await;
541 } 560 }
561
562 /// Set the pin's pad isolation
563 #[cfg(feature = "_rp235x")]
564 #[inline]
565 pub fn set_pad_isolation(&mut self, isolate: bool) {
566 self.pin.set_pad_isolation(isolate)
567 }
542} 568}
543 569
544/// GPIO flexible pin. 570/// GPIO flexible pin.
@@ -560,11 +586,16 @@ impl<'d> Flex<'d> {
560 into_ref!(pin); 586 into_ref!(pin);
561 587
562 pin.pad_ctrl().write(|w| { 588 pin.pad_ctrl().write(|w| {
589 #[cfg(feature = "_rp235x")]
590 w.set_iso(false);
563 w.set_ie(true); 591 w.set_ie(true);
564 }); 592 });
565 593
566 pin.gpio().ctrl().write(|w| { 594 pin.gpio().ctrl().write(|w| {
595 #[cfg(feature = "rp2040")]
567 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0 as _); 596 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0 as _);
597 #[cfg(feature = "_rp235x")]
598 w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIOB_PROC_0 as _);
568 }); 599 });
569 600
570 Self { pin: pin.map_into() } 601 Self { pin: pin.map_into() }
@@ -760,6 +791,15 @@ impl<'d> Flex<'d> {
760 cfg, 791 cfg,
761 } 792 }
762 } 793 }
794
795 /// Set the pin's pad isolation
796 #[cfg(feature = "_rp235x")]
797 #[inline]
798 pub fn set_pad_isolation(&mut self, isolate: bool) {
799 self.pin.pad_ctrl().modify(|w| {
800 w.set_iso(isolate);
801 });
802 }
763} 803}
764 804
765impl<'d> Drop for Flex<'d> { 805impl<'d> Drop for Flex<'d> {
@@ -956,6 +996,44 @@ impl_pin!(PIN_27, Bank::Bank0, 27);
956impl_pin!(PIN_28, Bank::Bank0, 28); 996impl_pin!(PIN_28, Bank::Bank0, 28);
957impl_pin!(PIN_29, Bank::Bank0, 29); 997impl_pin!(PIN_29, Bank::Bank0, 29);
958 998
999#[cfg(feature = "rp235xb")]
1000impl_pin!(PIN_30, Bank::Bank0, 30);
1001#[cfg(feature = "rp235xb")]
1002impl_pin!(PIN_31, Bank::Bank0, 31);
1003#[cfg(feature = "rp235xb")]
1004impl_pin!(PIN_32, Bank::Bank0, 32);
1005#[cfg(feature = "rp235xb")]
1006impl_pin!(PIN_33, Bank::Bank0, 33);
1007#[cfg(feature = "rp235xb")]
1008impl_pin!(PIN_34, Bank::Bank0, 34);
1009#[cfg(feature = "rp235xb")]
1010impl_pin!(PIN_35, Bank::Bank0, 35);
1011#[cfg(feature = "rp235xb")]
1012impl_pin!(PIN_36, Bank::Bank0, 36);
1013#[cfg(feature = "rp235xb")]
1014impl_pin!(PIN_37, Bank::Bank0, 37);
1015#[cfg(feature = "rp235xb")]
1016impl_pin!(PIN_38, Bank::Bank0, 38);
1017#[cfg(feature = "rp235xb")]
1018impl_pin!(PIN_39, Bank::Bank0, 39);
1019#[cfg(feature = "rp235xb")]
1020impl_pin!(PIN_40, Bank::Bank0, 40);
1021#[cfg(feature = "rp235xb")]
1022impl_pin!(PIN_41, Bank::Bank0, 41);
1023#[cfg(feature = "rp235xb")]
1024impl_pin!(PIN_42, Bank::Bank0, 42);
1025#[cfg(feature = "rp235xb")]
1026impl_pin!(PIN_43, Bank::Bank0, 43);
1027#[cfg(feature = "rp235xb")]
1028impl_pin!(PIN_44, Bank::Bank0, 44);
1029#[cfg(feature = "rp235xb")]
1030impl_pin!(PIN_45, Bank::Bank0, 45);
1031#[cfg(feature = "rp235xb")]
1032impl_pin!(PIN_46, Bank::Bank0, 46);
1033#[cfg(feature = "rp235xb")]
1034impl_pin!(PIN_47, Bank::Bank0, 47);
1035
1036// TODO rp235x bank1 as gpio support
959#[cfg(feature = "qspi-as-gpio")] 1037#[cfg(feature = "qspi-as-gpio")]
960impl_pin!(PIN_QSPI_SCLK, Bank::Qspi, 0); 1038impl_pin!(PIN_QSPI_SCLK, Bank::Qspi, 0);
961#[cfg(feature = "qspi-as-gpio")] 1039#[cfg(feature = "qspi-as-gpio")]
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index 10d3c86b3..32778215f 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -312,13 +312,13 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
312 } 312 }
313 } 313 }
314 314
315 /// Read from address into buffer using DMA. 315 /// Read from address into buffer asynchronously.
316 pub async fn read_async(&mut self, addr: impl Into<u16>, buffer: &mut [u8]) -> Result<(), Error> { 316 pub async fn read_async(&mut self, addr: impl Into<u16>, buffer: &mut [u8]) -> Result<(), Error> {
317 Self::setup(addr.into())?; 317 Self::setup(addr.into())?;
318 self.read_async_internal(buffer, true, true).await 318 self.read_async_internal(buffer, true, true).await
319 } 319 }
320 320
321 /// Write to address from buffer using DMA. 321 /// Write to address from buffer asynchronously.
322 pub async fn write_async( 322 pub async fn write_async(
323 &mut self, 323 &mut self,
324 addr: impl Into<u16>, 324 addr: impl Into<u16>,
@@ -328,7 +328,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
328 self.write_async_internal(bytes, true).await 328 self.write_async_internal(bytes, true).await
329 } 329 }
330 330
331 /// Write to address from bytes and read from address into buffer using DMA. 331 /// Write to address from bytes and read from address into buffer asynchronously.
332 pub async fn write_read_async( 332 pub async fn write_read_async(
333 &mut self, 333 &mut self,
334 addr: impl Into<u16>, 334 addr: impl Into<u16>,
@@ -363,6 +363,8 @@ where
363{ 363{
364 pin.gpio().ctrl().write(|w| w.set_funcsel(3)); 364 pin.gpio().ctrl().write(|w| w.set_funcsel(3));
365 pin.pad_ctrl().write(|w| { 365 pin.pad_ctrl().write(|w| {
366 #[cfg(feature = "_rp235x")]
367 w.set_iso(false);
366 w.set_schmitt(true); 368 w.set_schmitt(true);
367 w.set_slewfast(false); 369 w.set_slewfast(false);
368 w.set_ie(true); 370 w.set_ie(true);
@@ -779,9 +781,6 @@ pub fn i2c_reserved_addr(addr: u16) -> bool {
779} 781}
780 782
781pub(crate) trait SealedInstance { 783pub(crate) trait SealedInstance {
782 const TX_DREQ: u8;
783 const RX_DREQ: u8;
784
785 fn regs() -> crate::pac::i2c::I2c; 784 fn regs() -> crate::pac::i2c::I2c;
786 fn reset() -> crate::pac::resets::regs::Peripherals; 785 fn reset() -> crate::pac::resets::regs::Peripherals;
787 fn waker() -> &'static AtomicWaker; 786 fn waker() -> &'static AtomicWaker;
@@ -816,11 +815,8 @@ pub trait Instance: SealedInstance {
816} 815}
817 816
818macro_rules! impl_instance { 817macro_rules! impl_instance {
819 ($type:ident, $irq:ident, $reset:ident, $tx_dreq:expr, $rx_dreq:expr) => { 818 ($type:ident, $irq:ident, $reset:ident) => {
820 impl SealedInstance for peripherals::$type { 819 impl SealedInstance for peripherals::$type {
821 const TX_DREQ: u8 = $tx_dreq;
822 const RX_DREQ: u8 = $rx_dreq;
823
824 #[inline] 820 #[inline]
825 fn regs() -> pac::i2c::I2c { 821 fn regs() -> pac::i2c::I2c {
826 pac::$type 822 pac::$type
@@ -846,8 +842,8 @@ macro_rules! impl_instance {
846 }; 842 };
847} 843}
848 844
849impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33); 845impl_instance!(I2C0, I2C0_IRQ, set_i2c0);
850impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35); 846impl_instance!(I2C1, I2C1_IRQ, set_i2c1);
851 847
852/// SDA pin. 848/// SDA pin.
853pub trait SdaPin<T: Instance>: crate::gpio::Pin {} 849pub trait SdaPin<T: Instance>: crate::gpio::Pin {}
@@ -890,3 +886,39 @@ impl_pin!(PIN_26, I2C1, SdaPin);
890impl_pin!(PIN_27, I2C1, SclPin); 886impl_pin!(PIN_27, I2C1, SclPin);
891impl_pin!(PIN_28, I2C0, SdaPin); 887impl_pin!(PIN_28, I2C0, SdaPin);
892impl_pin!(PIN_29, I2C0, SclPin); 888impl_pin!(PIN_29, I2C0, SclPin);
889#[cfg(feature = "rp235xb")]
890impl_pin!(PIN_30, I2C1, SdaPin);
891#[cfg(feature = "rp235xb")]
892impl_pin!(PIN_31, I2C1, SclPin);
893#[cfg(feature = "rp235xb")]
894impl_pin!(PIN_32, I2C0, SdaPin);
895#[cfg(feature = "rp235xb")]
896impl_pin!(PIN_33, I2C0, SclPin);
897#[cfg(feature = "rp235xb")]
898impl_pin!(PIN_34, I2C1, SdaPin);
899#[cfg(feature = "rp235xb")]
900impl_pin!(PIN_35, I2C1, SclPin);
901#[cfg(feature = "rp235xb")]
902impl_pin!(PIN_36, I2C0, SdaPin);
903#[cfg(feature = "rp235xb")]
904impl_pin!(PIN_37, I2C0, SclPin);
905#[cfg(feature = "rp235xb")]
906impl_pin!(PIN_38, I2C1, SdaPin);
907#[cfg(feature = "rp235xb")]
908impl_pin!(PIN_39, I2C1, SclPin);
909#[cfg(feature = "rp235xb")]
910impl_pin!(PIN_40, I2C0, SdaPin);
911#[cfg(feature = "rp235xb")]
912impl_pin!(PIN_41, I2C0, SclPin);
913#[cfg(feature = "rp235xb")]
914impl_pin!(PIN_42, I2C1, SdaPin);
915#[cfg(feature = "rp235xb")]
916impl_pin!(PIN_43, I2C1, SclPin);
917#[cfg(feature = "rp235xb")]
918impl_pin!(PIN_44, I2C0, SdaPin);
919#[cfg(feature = "rp235xb")]
920impl_pin!(PIN_45, I2C0, SclPin);
921#[cfg(feature = "rp235xb")]
922impl_pin!(PIN_46, I2C1, SdaPin);
923#[cfg(feature = "rp235xb")]
924impl_pin!(PIN_47, I2C1, SclPin);
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index 471e7f8b1..c357c14c2 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -9,24 +9,35 @@
9// This mod MUST go first, so that the others see its macros. 9// This mod MUST go first, so that the others see its macros.
10pub(crate) mod fmt; 10pub(crate) mod fmt;
11 11
12#[cfg(feature = "binary-info")]
13pub use rp_binary_info as binary_info;
14
12#[cfg(feature = "critical-section-impl")] 15#[cfg(feature = "critical-section-impl")]
13mod critical_section_impl; 16mod critical_section_impl;
14 17
18#[cfg(feature = "rp2040")]
15mod intrinsics; 19mod intrinsics;
16 20
17pub mod adc; 21pub mod adc;
22#[cfg(feature = "_rp235x")]
23pub mod block;
24#[cfg(feature = "rp2040")]
18pub mod bootsel; 25pub mod bootsel;
19pub mod clocks; 26pub mod clocks;
20pub mod dma; 27pub mod dma;
21pub mod flash; 28pub mod flash;
29#[cfg(feature = "rp2040")]
22mod float; 30mod float;
23pub mod gpio; 31pub mod gpio;
24pub mod i2c; 32pub mod i2c;
25pub mod i2c_slave; 33pub mod i2c_slave;
26pub mod multicore; 34pub mod multicore;
35#[cfg(feature = "_rp235x")]
36pub mod otp;
27pub mod pwm; 37pub mod pwm;
28mod reset; 38mod reset;
29pub mod rom_data; 39pub mod rom_data;
40#[cfg(feature = "rp2040")]
30pub mod rtc; 41pub mod rtc;
31pub mod spi; 42pub mod spi;
32#[cfg(feature = "time-driver")] 43#[cfg(feature = "time-driver")]
@@ -49,6 +60,7 @@ pub(crate) use rp_pac as pac;
49#[cfg(feature = "rt")] 60#[cfg(feature = "rt")]
50pub use crate::pac::NVIC_PRIO_BITS; 61pub use crate::pac::NVIC_PRIO_BITS;
51 62
63#[cfg(feature = "rp2040")]
52embassy_hal_internal::interrupt_mod!( 64embassy_hal_internal::interrupt_mod!(
53 TIMER_IRQ_0, 65 TIMER_IRQ_0,
54 TIMER_IRQ_1, 66 TIMER_IRQ_1,
@@ -84,6 +96,54 @@ embassy_hal_internal::interrupt_mod!(
84 SWI_IRQ_5, 96 SWI_IRQ_5,
85); 97);
86 98
99#[cfg(feature = "_rp235x")]
100embassy_hal_internal::interrupt_mod!(
101 TIMER0_IRQ_0,
102 TIMER0_IRQ_1,
103 TIMER0_IRQ_2,
104 TIMER0_IRQ_3,
105 TIMER1_IRQ_0,
106 TIMER1_IRQ_1,
107 TIMER1_IRQ_2,
108 TIMER1_IRQ_3,
109 PWM_IRQ_WRAP_0,
110 PWM_IRQ_WRAP_1,
111 DMA_IRQ_0,
112 DMA_IRQ_1,
113 USBCTRL_IRQ,
114 PIO0_IRQ_0,
115 PIO0_IRQ_1,
116 PIO1_IRQ_0,
117 PIO1_IRQ_1,
118 PIO2_IRQ_0,
119 PIO2_IRQ_1,
120 IO_IRQ_BANK0,
121 IO_IRQ_BANK0_NS,
122 IO_IRQ_QSPI,
123 IO_IRQ_QSPI_NS,
124 SIO_IRQ_FIFO,
125 SIO_IRQ_BELL,
126 SIO_IRQ_FIFO_NS,
127 SIO_IRQ_BELL_NS,
128 CLOCKS_IRQ,
129 SPI0_IRQ,
130 SPI1_IRQ,
131 UART0_IRQ,
132 UART1_IRQ,
133 ADC_IRQ_FIFO,
134 I2C0_IRQ,
135 I2C1_IRQ,
136 TRNG_IRQ,
137 PLL_SYS_IRQ,
138 PLL_USB_IRQ,
139 SWI_IRQ_0,
140 SWI_IRQ_1,
141 SWI_IRQ_2,
142 SWI_IRQ_3,
143 SWI_IRQ_4,
144 SWI_IRQ_5,
145);
146
87/// Macro to bind interrupts to handlers. 147/// Macro to bind interrupts to handlers.
88/// 148///
89/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) 149/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
@@ -123,6 +183,95 @@ macro_rules! bind_interrupts {
123 }; 183 };
124} 184}
125 185
186#[cfg(feature = "rp2040")]
187embassy_hal_internal::peripherals! {
188 PIN_0,
189 PIN_1,
190 PIN_2,
191 PIN_3,
192 PIN_4,
193 PIN_5,
194 PIN_6,
195 PIN_7,
196 PIN_8,
197 PIN_9,
198 PIN_10,
199 PIN_11,
200 PIN_12,
201 PIN_13,
202 PIN_14,
203 PIN_15,
204 PIN_16,
205 PIN_17,
206 PIN_18,
207 PIN_19,
208 PIN_20,
209 PIN_21,
210 PIN_22,
211 PIN_23,
212 PIN_24,
213 PIN_25,
214 PIN_26,
215 PIN_27,
216 PIN_28,
217 PIN_29,
218 PIN_QSPI_SCLK,
219 PIN_QSPI_SS,
220 PIN_QSPI_SD0,
221 PIN_QSPI_SD1,
222 PIN_QSPI_SD2,
223 PIN_QSPI_SD3,
224
225 UART0,
226 UART1,
227
228 SPI0,
229 SPI1,
230
231 I2C0,
232 I2C1,
233
234 DMA_CH0,
235 DMA_CH1,
236 DMA_CH2,
237 DMA_CH3,
238 DMA_CH4,
239 DMA_CH5,
240 DMA_CH6,
241 DMA_CH7,
242 DMA_CH8,
243 DMA_CH9,
244 DMA_CH10,
245 DMA_CH11,
246
247 PWM_SLICE0,
248 PWM_SLICE1,
249 PWM_SLICE2,
250 PWM_SLICE3,
251 PWM_SLICE4,
252 PWM_SLICE5,
253 PWM_SLICE6,
254 PWM_SLICE7,
255
256 USB,
257
258 RTC,
259
260 FLASH,
261
262 ADC,
263 ADC_TEMP_SENSOR,
264
265 CORE1,
266
267 PIO0,
268 PIO1,
269
270 WATCHDOG,
271 BOOTSEL,
272}
273
274#[cfg(feature = "_rp235x")]
126embassy_hal_internal::peripherals! { 275embassy_hal_internal::peripherals! {
127 PIN_0, 276 PIN_0,
128 PIN_1, 277 PIN_1,
@@ -154,6 +303,42 @@ embassy_hal_internal::peripherals! {
154 PIN_27, 303 PIN_27,
155 PIN_28, 304 PIN_28,
156 PIN_29, 305 PIN_29,
306 #[cfg(feature = "rp235xb")]
307 PIN_30,
308 #[cfg(feature = "rp235xb")]
309 PIN_31,
310 #[cfg(feature = "rp235xb")]
311 PIN_32,
312 #[cfg(feature = "rp235xb")]
313 PIN_33,
314 #[cfg(feature = "rp235xb")]
315 PIN_34,
316 #[cfg(feature = "rp235xb")]
317 PIN_35,
318 #[cfg(feature = "rp235xb")]
319 PIN_36,
320 #[cfg(feature = "rp235xb")]
321 PIN_37,
322 #[cfg(feature = "rp235xb")]
323 PIN_38,
324 #[cfg(feature = "rp235xb")]
325 PIN_39,
326 #[cfg(feature = "rp235xb")]
327 PIN_40,
328 #[cfg(feature = "rp235xb")]
329 PIN_41,
330 #[cfg(feature = "rp235xb")]
331 PIN_42,
332 #[cfg(feature = "rp235xb")]
333 PIN_43,
334 #[cfg(feature = "rp235xb")]
335 PIN_44,
336 #[cfg(feature = "rp235xb")]
337 PIN_45,
338 #[cfg(feature = "rp235xb")]
339 PIN_46,
340 #[cfg(feature = "rp235xb")]
341 PIN_47,
157 PIN_QSPI_SCLK, 342 PIN_QSPI_SCLK,
158 PIN_QSPI_SS, 343 PIN_QSPI_SS,
159 PIN_QSPI_SD0, 344 PIN_QSPI_SD0,
@@ -182,6 +367,10 @@ embassy_hal_internal::peripherals! {
182 DMA_CH9, 367 DMA_CH9,
183 DMA_CH10, 368 DMA_CH10,
184 DMA_CH11, 369 DMA_CH11,
370 DMA_CH12,
371 DMA_CH13,
372 DMA_CH14,
373 DMA_CH15,
185 374
186 PWM_SLICE0, 375 PWM_SLICE0,
187 PWM_SLICE1, 376 PWM_SLICE1,
@@ -191,6 +380,10 @@ embassy_hal_internal::peripherals! {
191 PWM_SLICE5, 380 PWM_SLICE5,
192 PWM_SLICE6, 381 PWM_SLICE6,
193 PWM_SLICE7, 382 PWM_SLICE7,
383 PWM_SLICE8,
384 PWM_SLICE9,
385 PWM_SLICE10,
386 PWM_SLICE11,
194 387
195 USB, 388 USB,
196 389
@@ -205,12 +398,13 @@ embassy_hal_internal::peripherals! {
205 398
206 PIO0, 399 PIO0,
207 PIO1, 400 PIO1,
401 PIO2,
208 402
209 WATCHDOG, 403 WATCHDOG,
210 BOOTSEL, 404 BOOTSEL,
211} 405}
212 406
213#[cfg(not(feature = "boot2-none"))] 407#[cfg(all(not(feature = "boot2-none"), feature = "rp2040"))]
214macro_rules! select_bootloader { 408macro_rules! select_bootloader {
215 ( $( $feature:literal => $loader:ident, )+ default => $default:ident ) => { 409 ( $( $feature:literal => $loader:ident, )+ default => $default:ident ) => {
216 $( 410 $(
@@ -227,7 +421,7 @@ macro_rules! select_bootloader {
227 } 421 }
228} 422}
229 423
230#[cfg(not(feature = "boot2-none"))] 424#[cfg(all(not(feature = "boot2-none"), feature = "rp2040"))]
231select_bootloader! { 425select_bootloader! {
232 "boot2-at25sf128a" => BOOT_LOADER_AT25SF128A, 426 "boot2-at25sf128a" => BOOT_LOADER_AT25SF128A,
233 "boot2-gd25q64cs" => BOOT_LOADER_GD25Q64CS, 427 "boot2-gd25q64cs" => BOOT_LOADER_GD25Q64CS,
@@ -279,6 +473,7 @@ pub fn install_core0_stack_guard() -> Result<(), ()> {
279 unsafe { install_stack_guard(core::ptr::addr_of_mut!(_stack_end)) } 473 unsafe { install_stack_guard(core::ptr::addr_of_mut!(_stack_end)) }
280} 474}
281 475
476#[cfg(all(feature = "rp2040", not(feature = "_test")))]
282#[inline(always)] 477#[inline(always)]
283fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { 478fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> {
284 let core = unsafe { cortex_m::Peripherals::steal() }; 479 let core = unsafe { cortex_m::Peripherals::steal() };
@@ -306,6 +501,32 @@ fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> {
306 Ok(()) 501 Ok(())
307} 502}
308 503
504#[cfg(all(feature = "_rp235x", not(feature = "_test")))]
505#[inline(always)]
506fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> {
507 let core = unsafe { cortex_m::Peripherals::steal() };
508
509 // Fail if MPU is already configured
510 if core.MPU.ctrl.read() != 0 {
511 return Err(());
512 }
513
514 unsafe {
515 core.MPU.ctrl.write(5); // enable mpu with background default map
516 core.MPU.rbar.write(stack_bottom as u32 & !0xff); // set address
517 core.MPU.rlar.write(1); // enable region
518 }
519 Ok(())
520}
521
522// This is to hack around cortex_m defaulting to ARMv7 when building tests,
523// so the compile fails when we try to use ARMv8 peripherals.
524#[cfg(feature = "_test")]
525#[inline(always)]
526fn install_stack_guard(_stack_bottom: *mut usize) -> Result<(), ()> {
527 Ok(())
528}
529
309/// HAL configuration for RP. 530/// HAL configuration for RP.
310pub mod config { 531pub mod config {
311 use crate::clocks::ClockConfig; 532 use crate::clocks::ClockConfig;
@@ -354,7 +575,7 @@ pub fn init(config: config::Config) -> Peripherals {
354 peripherals 575 peripherals
355} 576}
356 577
357#[cfg(feature = "rt")] 578#[cfg(all(feature = "rt", feature = "rp2040"))]
358#[cortex_m_rt::pre_init] 579#[cortex_m_rt::pre_init]
359unsafe fn pre_init() { 580unsafe fn pre_init() {
360 // SIO does not get reset when core0 is reset with either `scb::sys_reset()` or with SWD. 581 // SIO does not get reset when core0 is reset with either `scb::sys_reset()` or with SWD.
diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs
index d9d65694a..9f7d77bf5 100644
--- a/embassy-rp/src/multicore.rs
+++ b/embassy-rp/src/multicore.rs
@@ -84,7 +84,7 @@ impl<const SIZE: usize> Stack<SIZE> {
84 } 84 }
85} 85}
86 86
87#[cfg(feature = "rt")] 87#[cfg(all(feature = "rt", feature = "rp2040"))]
88#[interrupt] 88#[interrupt]
89#[link_section = ".data.ram_func"] 89#[link_section = ".data.ram_func"]
90unsafe fn SIO_IRQ_PROC1() { 90unsafe fn SIO_IRQ_PROC1() {
@@ -109,6 +109,31 @@ unsafe fn SIO_IRQ_PROC1() {
109 } 109 }
110} 110}
111 111
112#[cfg(all(feature = "rt", feature = "_rp235x"))]
113#[interrupt]
114#[link_section = ".data.ram_func"]
115unsafe fn SIO_IRQ_FIFO() {
116 let sio = pac::SIO;
117 // Clear IRQ
118 sio.fifo().st().write(|w| w.set_wof(false));
119
120 while sio.fifo().st().read().vld() {
121 // Pause CORE1 execution and disable interrupts
122 if fifo_read_wfe() == PAUSE_TOKEN {
123 cortex_m::interrupt::disable();
124 // Signal to CORE0 that execution is paused
125 fifo_write(PAUSE_TOKEN);
126 // Wait for `resume` signal from CORE0
127 while fifo_read_wfe() != RESUME_TOKEN {
128 cortex_m::asm::nop();
129 }
130 cortex_m::interrupt::enable();
131 // Signal to CORE0 that execution is resumed
132 fifo_write(RESUME_TOKEN);
133 }
134 }
135}
136
112/// Spawn a function on this core 137/// Spawn a function on this core
113pub fn spawn_core1<F, const SIZE: usize>(_core1: CORE1, stack: &'static mut Stack<SIZE>, entry: F) 138pub fn spawn_core1<F, const SIZE: usize>(_core1: CORE1, stack: &'static mut Stack<SIZE>, entry: F)
114where 139where
@@ -135,7 +160,14 @@ where
135 160
136 IS_CORE1_INIT.store(true, Ordering::Release); 161 IS_CORE1_INIT.store(true, Ordering::Release);
137 // Enable fifo interrupt on CORE1 for `pause` functionality. 162 // Enable fifo interrupt on CORE1 for `pause` functionality.
138 unsafe { interrupt::SIO_IRQ_PROC1.enable() }; 163 #[cfg(feature = "rp2040")]
164 unsafe {
165 interrupt::SIO_IRQ_PROC1.enable()
166 };
167 #[cfg(feature = "_rp235x")]
168 unsafe {
169 interrupt::SIO_IRQ_FIFO.enable()
170 };
139 171
140 entry() 172 entry()
141 } 173 }
diff --git a/embassy-rp/src/otp.rs b/embassy-rp/src/otp.rs
new file mode 100644
index 000000000..cdaf5bded
--- /dev/null
+++ b/embassy-rp/src/otp.rs
@@ -0,0 +1,108 @@
1//! Interface to the RP2350's One Time Programmable Memory
2
3// Credit: taken from `rp-hal` (also licensed Apache+MIT)
4// https://github.com/rp-rs/rp-hal/blob/main/rp235x-hal/src/rom_data.rs
5
6/// The ways in which we can fail to read OTP
7#[derive(Debug, Clone)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9pub enum Error {
10 /// The user passed an invalid index to a function.
11 InvalidIndex,
12 /// The hardware refused to let us read this word, probably due to
13 /// read lock set earlier in the boot process.
14 InvalidPermissions,
15}
16
17/// OTP read address, using automatic Error Correction.
18///
19/// A 32-bit read returns the ECC-corrected data for two neighbouring rows, or
20/// all-ones on permission failure. Only the first 8 KiB is populated.
21pub const OTP_DATA_BASE: *const u32 = 0x4013_0000 as *const u32;
22
23/// OTP read address, without using any automatic Error Correction.
24///
25/// A 32-bit read returns 24-bits of raw data from the OTP word.
26pub const OTP_DATA_RAW_BASE: *const u32 = 0x4013_4000 as *const u32;
27
28/// How many pages in OTP (post error-correction)
29pub const NUM_PAGES: usize = 64;
30
31/// How many rows in one page in OTP (post error-correction)
32pub const NUM_ROWS_PER_PAGE: usize = 64;
33
34/// How many rows in OTP (post error-correction)
35pub const NUM_ROWS: usize = NUM_PAGES * NUM_ROWS_PER_PAGE;
36
37/// Read one ECC protected word from the OTP
38pub fn read_ecc_word(row: usize) -> Result<u16, Error> {
39 if row >= NUM_ROWS {
40 return Err(Error::InvalidIndex);
41 }
42 // First do a raw read to check permissions
43 let _ = read_raw_word(row)?;
44 // One 32-bit read gets us two rows
45 let offset = row >> 1;
46 // # Safety
47 //
48 // We checked this offset was in range already.
49 let value = unsafe { OTP_DATA_BASE.add(offset).read() };
50 if (row & 1) == 0 {
51 Ok(value as u16)
52 } else {
53 Ok((value >> 16) as u16)
54 }
55}
56
57/// Read one raw word from the OTP
58///
59/// You get the 24-bit raw value in the lower part of the 32-bit result.
60pub fn read_raw_word(row: usize) -> Result<u32, Error> {
61 if row >= NUM_ROWS {
62 return Err(Error::InvalidIndex);
63 }
64 // One 32-bit read gets us one row
65 // # Safety
66 //
67 // We checked this offset was in range already.
68 let value = unsafe { OTP_DATA_RAW_BASE.add(row).read() };
69 if value == 0xFFFF_FFFF {
70 Err(Error::InvalidPermissions)
71 } else {
72 Ok(value)
73 }
74}
75
76/// Get the random 64bit chipid from rows 0x0-0x3.
77pub fn get_chipid() -> Result<u64, Error> {
78 let w0 = read_ecc_word(0x000)?.to_be_bytes();
79 let w1 = read_ecc_word(0x001)?.to_be_bytes();
80 let w2 = read_ecc_word(0x002)?.to_be_bytes();
81 let w3 = read_ecc_word(0x003)?.to_be_bytes();
82
83 Ok(u64::from_be_bytes([
84 w3[0], w3[1], w2[0], w2[1], w1[0], w1[1], w0[0], w0[1],
85 ]))
86}
87
88/// Get the 128bit private random number from rows 0x4-0xb.
89///
90/// This ID is not exposed through the USB PICOBOOT GET_INFO command
91/// or the ROM get_sys_info() API. However note that the USB PICOBOOT OTP
92/// access point can read the entirety of page 0, so this value is not
93/// meaningfully private unless the USB PICOBOOT interface is disabled via the
94//// DISABLE_BOOTSEL_USB_PICOBOOT_IFC flag in BOOT_FLAGS0
95pub fn get_private_random_number() -> Result<u128, Error> {
96 let w0 = read_ecc_word(0x004)?.to_be_bytes();
97 let w1 = read_ecc_word(0x005)?.to_be_bytes();
98 let w2 = read_ecc_word(0x006)?.to_be_bytes();
99 let w3 = read_ecc_word(0x007)?.to_be_bytes();
100 let w4 = read_ecc_word(0x008)?.to_be_bytes();
101 let w5 = read_ecc_word(0x009)?.to_be_bytes();
102 let w6 = read_ecc_word(0x00a)?.to_be_bytes();
103 let w7 = read_ecc_word(0x00b)?.to_be_bytes();
104
105 Ok(u128::from_be_bytes([
106 w7[0], w7[1], w6[0], w6[1], w5[0], w5[1], w4[0], w4[1], w3[0], w3[1], w2[0], w2[1], w1[0], w1[1], w0[0], w0[1],
107 ]))
108}
diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs
index 1f7adbda3..68b1d6849 100644
--- a/embassy-rp/src/pio/mod.rs
+++ b/embassy-rp/src/pio/mod.rs
@@ -10,14 +10,11 @@ use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
10use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
11use fixed::types::extra::U8; 11use fixed::types::extra::U8;
12use fixed::FixedU32; 12use fixed::FixedU32;
13use pac::io::vals::Gpio0ctrlFuncsel;
14use pac::pio::vals::SmExecctrlStatusSel;
15use pio::{Program, SideSet, Wrap}; 13use pio::{Program, SideSet, Wrap};
16 14
17use crate::dma::{Channel, Transfer, Word}; 15use crate::dma::{Channel, Transfer, Word};
18use crate::gpio::{self, AnyPin, Drive, Level, Pull, SealedPin, SlewRate}; 16use crate::gpio::{self, AnyPin, Drive, Level, Pull, SealedPin, SlewRate};
19use crate::interrupt::typelevel::{Binding, Handler, Interrupt}; 17use crate::interrupt::typelevel::{Binding, Handler, Interrupt};
20use crate::pac::dma::vals::TreqSel;
21use crate::relocate::RelocatedProgram; 18use crate::relocate::RelocatedProgram;
22use crate::{pac, peripherals, RegExt}; 19use crate::{pac, peripherals, RegExt};
23 20
@@ -355,11 +352,14 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
355 let p = ch.regs(); 352 let p = ch.regs();
356 p.write_addr().write_value(data.as_ptr() as u32); 353 p.write_addr().write_value(data.as_ptr() as u32);
357 p.read_addr().write_value(PIO::PIO.rxf(SM).as_ptr() as u32); 354 p.read_addr().write_value(PIO::PIO.rxf(SM).as_ptr() as u32);
358 p.trans_count().write_value(data.len() as u32); 355 #[cfg(feature = "rp2040")]
356 p.trans_count().write(|w| *w = data.len() as u32);
357 #[cfg(feature = "_rp235x")]
358 p.trans_count().write(|w| w.set_count(data.len() as u32));
359 compiler_fence(Ordering::SeqCst); 359 compiler_fence(Ordering::SeqCst);
360 p.ctrl_trig().write(|w| { 360 p.ctrl_trig().write(|w| {
361 // Set RX DREQ for this statemachine 361 // Set RX DREQ for this statemachine
362 w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4)); 362 w.set_treq_sel(crate::pac::dma::vals::TreqSel::from(pio_no * 8 + SM as u8 + 4));
363 w.set_data_size(W::size()); 363 w.set_data_size(W::size());
364 w.set_chain_to(ch.number()); 364 w.set_chain_to(ch.number());
365 w.set_incr_read(false); 365 w.set_incr_read(false);
@@ -437,11 +437,14 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
437 let p = ch.regs(); 437 let p = ch.regs();
438 p.read_addr().write_value(data.as_ptr() as u32); 438 p.read_addr().write_value(data.as_ptr() as u32);
439 p.write_addr().write_value(PIO::PIO.txf(SM).as_ptr() as u32); 439 p.write_addr().write_value(PIO::PIO.txf(SM).as_ptr() as u32);
440 p.trans_count().write_value(data.len() as u32); 440 #[cfg(feature = "rp2040")]
441 p.trans_count().write(|w| *w = data.len() as u32);
442 #[cfg(feature = "_rp235x")]
443 p.trans_count().write(|w| w.set_count(data.len() as u32));
441 compiler_fence(Ordering::SeqCst); 444 compiler_fence(Ordering::SeqCst);
442 p.ctrl_trig().write(|w| { 445 p.ctrl_trig().write(|w| {
443 // Set TX DREQ for this statemachine 446 // Set TX DREQ for this statemachine
444 w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8)); 447 w.set_treq_sel(crate::pac::dma::vals::TreqSel::from(pio_no * 8 + SM as u8));
445 w.set_data_size(W::size()); 448 w.set_data_size(W::size());
446 w.set_chain_to(ch.number()); 449 w.set_chain_to(ch.number());
447 w.set_incr_read(true); 450 w.set_incr_read(true);
@@ -523,6 +526,39 @@ pub struct PinConfig {
523 pub out_base: u8, 526 pub out_base: u8,
524} 527}
525 528
529/// Comparison level or IRQ index for the MOV x, STATUS instruction.
530#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
531#[cfg_attr(feature = "defmt", derive(defmt::Format))]
532#[cfg(feature = "_rp235x")]
533pub enum StatusN {
534 /// IRQ flag in this PIO block
535 This(u8),
536 /// IRQ flag in the next lower PIO block
537 Lower(u8),
538 /// IRQ flag in the next higher PIO block
539 Higher(u8),
540}
541
542#[cfg(feature = "_rp235x")]
543impl Default for StatusN {
544 fn default() -> Self {
545 Self::This(0)
546 }
547}
548
549#[cfg(feature = "_rp235x")]
550impl Into<crate::pac::pio::vals::ExecctrlStatusN> for StatusN {
551 fn into(self) -> crate::pac::pio::vals::ExecctrlStatusN {
552 let x = match self {
553 StatusN::This(n) => n,
554 StatusN::Lower(n) => n + 0x08,
555 StatusN::Higher(n) => n + 0x10,
556 };
557
558 crate::pac::pio::vals::ExecctrlStatusN(x)
559 }
560}
561
526/// PIO config. 562/// PIO config.
527#[derive(Clone, Copy, Debug)] 563#[derive(Clone, Copy, Debug)]
528pub struct Config<'d, PIO: Instance> { 564pub struct Config<'d, PIO: Instance> {
@@ -537,7 +573,12 @@ pub struct Config<'d, PIO: Instance> {
537 /// Which source to use for checking status. 573 /// Which source to use for checking status.
538 pub status_sel: StatusSource, 574 pub status_sel: StatusSource,
539 /// Status comparison level. 575 /// Status comparison level.
576 #[cfg(feature = "rp2040")]
540 pub status_n: u8, 577 pub status_n: u8,
578 // This cfg probably shouldn't be required, but the SVD for the 2040 doesn't have the enum
579 #[cfg(feature = "_rp235x")]
580 /// Status comparison level.
581 pub status_n: StatusN,
541 exec: ExecConfig, 582 exec: ExecConfig,
542 origin: Option<u8>, 583 origin: Option<u8>,
543 /// Configure FIFO allocation. 584 /// Configure FIFO allocation.
@@ -653,7 +694,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
653 assert!(config.clock_divider <= 65536, "clkdiv must be <= 65536"); 694 assert!(config.clock_divider <= 65536, "clkdiv must be <= 65536");
654 assert!(config.clock_divider >= 1, "clkdiv must be >= 1"); 695 assert!(config.clock_divider >= 1, "clkdiv must be >= 1");
655 assert!(config.out_en_sel < 32, "out_en_sel must be < 32"); 696 assert!(config.out_en_sel < 32, "out_en_sel must be < 32");
656 assert!(config.status_n < 32, "status_n must be < 32"); 697 //assert!(config.status_n < 32, "status_n must be < 32");
657 // sm expects 0 for 32, truncation makes that happen 698 // sm expects 0 for 32, truncation makes that happen
658 assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32"); 699 assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32");
659 assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32"); 700 assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32");
@@ -668,11 +709,17 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
668 w.set_out_sticky(config.out_sticky); 709 w.set_out_sticky(config.out_sticky);
669 w.set_wrap_top(config.exec.wrap_top); 710 w.set_wrap_top(config.exec.wrap_top);
670 w.set_wrap_bottom(config.exec.wrap_bottom); 711 w.set_wrap_bottom(config.exec.wrap_bottom);
712 #[cfg(feature = "_rp235x")]
671 w.set_status_sel(match config.status_sel { 713 w.set_status_sel(match config.status_sel {
672 StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL, 714 StatusSource::TxFifoLevel => pac::pio::vals::ExecctrlStatusSel::TXLEVEL,
673 StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL, 715 StatusSource::RxFifoLevel => pac::pio::vals::ExecctrlStatusSel::RXLEVEL,
674 }); 716 });
675 w.set_status_n(config.status_n); 717 #[cfg(feature = "rp2040")]
718 w.set_status_sel(match config.status_sel {
719 StatusSource::TxFifoLevel => pac::pio::vals::SmExecctrlStatusSel::TXLEVEL,
720 StatusSource::RxFifoLevel => pac::pio::vals::SmExecctrlStatusSel::RXLEVEL,
721 });
722 w.set_status_n(config.status_n.into());
676 }); 723 });
677 sm.shiftctrl().write(|w| { 724 sm.shiftctrl().write(|w| {
678 w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly); 725 w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly);
@@ -1147,7 +1194,7 @@ fn on_pio_drop<PIO: Instance>() {
1147 let state = PIO::state(); 1194 let state = PIO::state();
1148 if state.users.fetch_sub(1, Ordering::AcqRel) == 1 { 1195 if state.users.fetch_sub(1, Ordering::AcqRel) == 1 {
1149 let used_pins = state.used_pins.load(Ordering::Relaxed); 1196 let used_pins = state.used_pins.load(Ordering::Relaxed);
1150 let null = Gpio0ctrlFuncsel::NULL as _; 1197 let null = pac::io::vals::Gpio0ctrlFuncsel::NULL as _;
1151 // we only have 30 pins. don't test the other two since gpio() asserts. 1198 // we only have 30 pins. don't test the other two since gpio() asserts.
1152 for i in 0..30 { 1199 for i in 0..30 {
1153 if used_pins & (1 << i) != 0 { 1200 if used_pins & (1 << i) != 0 {
@@ -1203,6 +1250,8 @@ macro_rules! impl_pio {
1203 1250
1204impl_pio!(PIO0, 0, PIO0, PIO0_0, PIO0_IRQ_0); 1251impl_pio!(PIO0, 0, PIO0, PIO0_0, PIO0_IRQ_0);
1205impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0); 1252impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0);
1253#[cfg(feature = "_rp235x")]
1254impl_pio!(PIO2, 2, PIO2, PIO2_0, PIO2_IRQ_0);
1206 1255
1207/// PIO pin. 1256/// PIO pin.
1208pub trait PioPin: gpio::Pin {} 1257pub trait PioPin: gpio::Pin {}
@@ -1247,3 +1296,25 @@ impl_pio_pin! {
1247 PIN_28, 1296 PIN_28,
1248 PIN_29, 1297 PIN_29,
1249} 1298}
1299
1300#[cfg(feature = "rp235xb")]
1301impl_pio_pin! {
1302 PIN_30,
1303 PIN_31,
1304 PIN_32,
1305 PIN_33,
1306 PIN_34,
1307 PIN_35,
1308 PIN_36,
1309 PIN_37,
1310 PIN_38,
1311 PIN_39,
1312 PIN_40,
1313 PIN_41,
1314 PIN_42,
1315 PIN_43,
1316 PIN_44,
1317 PIN_45,
1318 PIN_46,
1319 PIN_47,
1320}
diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs
index c35e76587..7da3dccb0 100644
--- a/embassy-rp/src/pwm.rs
+++ b/embassy-rp/src/pwm.rs
@@ -110,6 +110,8 @@ impl<'d> Pwm<'d> {
110 if let Some(pin) = &b { 110 if let Some(pin) = &b {
111 pin.gpio().ctrl().write(|w| w.set_funcsel(4)); 111 pin.gpio().ctrl().write(|w| w.set_funcsel(4));
112 pin.pad_ctrl().modify(|w| { 112 pin.pad_ctrl().modify(|w| {
113 #[cfg(feature = "_rp235x")]
114 w.set_iso(false);
113 w.set_pue(b_pull == Pull::Up); 115 w.set_pue(b_pull == Pull::Up);
114 w.set_pde(b_pull == Pull::Down); 116 w.set_pde(b_pull == Pull::Down);
115 }); 117 });
@@ -363,6 +365,15 @@ slice!(PWM_SLICE5, 5);
363slice!(PWM_SLICE6, 6); 365slice!(PWM_SLICE6, 6);
364slice!(PWM_SLICE7, 7); 366slice!(PWM_SLICE7, 7);
365 367
368#[cfg(feature = "_rp235x")]
369slice!(PWM_SLICE8, 8);
370#[cfg(feature = "_rp235x")]
371slice!(PWM_SLICE9, 9);
372#[cfg(feature = "_rp235x")]
373slice!(PWM_SLICE10, 10);
374#[cfg(feature = "_rp235x")]
375slice!(PWM_SLICE11, 11);
376
366/// PWM Channel A. 377/// PWM Channel A.
367pub trait ChannelAPin<T: Slice>: GpioPin {} 378pub trait ChannelAPin<T: Slice>: GpioPin {}
368/// PWM Channel B. 379/// PWM Channel B.
@@ -404,3 +415,39 @@ impl_pin!(PIN_26, PWM_SLICE5, ChannelAPin);
404impl_pin!(PIN_27, PWM_SLICE5, ChannelBPin); 415impl_pin!(PIN_27, PWM_SLICE5, ChannelBPin);
405impl_pin!(PIN_28, PWM_SLICE6, ChannelAPin); 416impl_pin!(PIN_28, PWM_SLICE6, ChannelAPin);
406impl_pin!(PIN_29, PWM_SLICE6, ChannelBPin); 417impl_pin!(PIN_29, PWM_SLICE6, ChannelBPin);
418#[cfg(feature = "rp235xb")]
419impl_pin!(PIN_30, PWM_SLICE7, ChannelAPin);
420#[cfg(feature = "rp235xb")]
421impl_pin!(PIN_31, PWM_SLICE7, ChannelBPin);
422#[cfg(feature = "rp235xb")]
423impl_pin!(PIN_32, PWM_SLICE8, ChannelAPin);
424#[cfg(feature = "rp235xb")]
425impl_pin!(PIN_33, PWM_SLICE8, ChannelBPin);
426#[cfg(feature = "rp235xb")]
427impl_pin!(PIN_34, PWM_SLICE9, ChannelAPin);
428#[cfg(feature = "rp235xb")]
429impl_pin!(PIN_35, PWM_SLICE9, ChannelBPin);
430#[cfg(feature = "rp235xb")]
431impl_pin!(PIN_36, PWM_SLICE10, ChannelAPin);
432#[cfg(feature = "rp235xb")]
433impl_pin!(PIN_37, PWM_SLICE10, ChannelBPin);
434#[cfg(feature = "rp235xb")]
435impl_pin!(PIN_38, PWM_SLICE11, ChannelAPin);
436#[cfg(feature = "rp235xb")]
437impl_pin!(PIN_39, PWM_SLICE11, ChannelBPin);
438#[cfg(feature = "rp235xb")]
439impl_pin!(PIN_40, PWM_SLICE8, ChannelAPin);
440#[cfg(feature = "rp235xb")]
441impl_pin!(PIN_41, PWM_SLICE8, ChannelBPin);
442#[cfg(feature = "rp235xb")]
443impl_pin!(PIN_42, PWM_SLICE9, ChannelAPin);
444#[cfg(feature = "rp235xb")]
445impl_pin!(PIN_43, PWM_SLICE9, ChannelBPin);
446#[cfg(feature = "rp235xb")]
447impl_pin!(PIN_44, PWM_SLICE10, ChannelAPin);
448#[cfg(feature = "rp235xb")]
449impl_pin!(PIN_45, PWM_SLICE10, ChannelBPin);
450#[cfg(feature = "rp235xb")]
451impl_pin!(PIN_46, PWM_SLICE11, ChannelAPin);
452#[cfg(feature = "rp235xb")]
453impl_pin!(PIN_47, PWM_SLICE11, ChannelBPin);
diff --git a/embassy-rp/src/reset.rs b/embassy-rp/src/reset.rs
index 70512fa14..4b9e42483 100644
--- a/embassy-rp/src/reset.rs
+++ b/embassy-rp/src/reset.rs
@@ -2,7 +2,7 @@ pub use pac::resets::regs::Peripherals;
2 2
3use crate::pac; 3use crate::pac;
4 4
5pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff); 5pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ff_ffff);
6 6
7pub(crate) fn reset(peris: Peripherals) { 7pub(crate) fn reset(peris: Peripherals) {
8 pac::RESETS.reset().write_value(peris); 8 pac::RESETS.reset().write_value(peris);
diff --git a/embassy-rp/src/rom_data/mod.rs b/embassy-rp/src/rom_data/mod.rs
new file mode 100644
index 000000000..e5fcf8e3c
--- /dev/null
+++ b/embassy-rp/src/rom_data/mod.rs
@@ -0,0 +1,33 @@
1#![cfg_attr(
2 feature = "rp2040",
3 doc = r"
4//! Functions and data from the RPI Bootrom.
5//!
6//! From the [RP2040 datasheet](https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf), Section 2.8.2.1:
7//!
8//! > The Bootrom contains a number of public functions that provide useful
9//! > RP2040 functionality that might be needed in the absence of any other code
10//! > on the device, as well as highly optimized versions of certain key
11//! > functionality that would otherwise have to take up space in most user
12//! > binaries.
13"
14)]
15#![cfg_attr(
16 feature = "_rp235x",
17 doc = r"
18//! Functions and data from the RPI Bootrom.
19//!
20//! From [Section 5.4](https://rptl.io/rp2350-datasheet#section_bootrom) of the
21//! RP2350 datasheet:
22//!
23//! > Whilst some ROM space is dedicated to the implementation of the boot
24//! > sequence and USB/UART boot interfaces, the bootrom also contains public
25//! > functions that provide useful RP2350 functionality that may be useful for
26//! > any code or runtime running on the device
27"
28)]
29
30#[cfg_attr(feature = "rp2040", path = "rp2040.rs")]
31#[cfg_attr(feature = "_rp235x", path = "rp235x.rs")]
32mod inner;
33pub use inner::*;
diff --git a/embassy-rp/src/rom_data.rs b/embassy-rp/src/rom_data/rp2040.rs
index baebe5b6c..5a74eddd6 100644
--- a/embassy-rp/src/rom_data.rs
+++ b/embassy-rp/src/rom_data/rp2040.rs
@@ -189,7 +189,7 @@ macro_rules! rom_functions {
189 declare_rom_function! { 189 declare_rom_function! {
190 $(#[$outer])* 190 $(#[$outer])*
191 fn $name( $($argname: $ty),* ) -> $ret { 191 fn $name( $($argname: $ty),* ) -> $ret {
192 $crate::rom_data::rom_table_lookup($crate::rom_data::FUNC_TABLE, *$c) 192 $crate::rom_data::inner::rom_table_lookup($crate::rom_data::inner::FUNC_TABLE, *$c)
193 } 193 }
194 } 194 }
195 195
@@ -205,7 +205,7 @@ macro_rules! rom_functions {
205 declare_rom_function! { 205 declare_rom_function! {
206 $(#[$outer])* 206 $(#[$outer])*
207 unsafe fn $name( $($argname: $ty),* ) -> $ret { 207 unsafe fn $name( $($argname: $ty),* ) -> $ret {
208 $crate::rom_data::rom_table_lookup($crate::rom_data::FUNC_TABLE, *$c) 208 $crate::rom_data::inner::rom_table_lookup($crate::rom_data::inner::FUNC_TABLE, *$c)
209 } 209 }
210 } 210 }
211 211
diff --git a/embassy-rp/src/rom_data/rp235x.rs b/embassy-rp/src/rom_data/rp235x.rs
new file mode 100644
index 000000000..b16fee8f7
--- /dev/null
+++ b/embassy-rp/src/rom_data/rp235x.rs
@@ -0,0 +1,752 @@
1//! Functions and data from the RPI Bootrom.
2//!
3//! From [Section 5.4](https://rptl.io/rp2350-datasheet#section_bootrom) of the
4//! RP2350 datasheet:
5//!
6//! > Whilst some ROM space is dedicated to the implementation of the boot
7//! > sequence and USB/UART boot interfaces, the bootrom also contains public
8//! > functions that provide useful RP2350 functionality that may be useful for
9//! > any code or runtime running on the device
10
11// Credit: taken from `rp-hal` (also licensed Apache+MIT)
12// https://github.com/rp-rs/rp-hal/blob/main/rp235x-hal/src/rom_data.rs
13
14/// A bootrom function table code.
15pub type RomFnTableCode = [u8; 2];
16
17/// This function searches for the tag which matches the mask.
18type RomTableLookupFn = unsafe extern "C" fn(code: u32, mask: u32) -> usize;
19
20/// Pointer to the value lookup function supplied by the ROM.
21///
22/// This address is described at `5.5.1. Locating the API Functions`
23#[cfg(all(target_arch = "arm", target_os = "none"))]
24const ROM_TABLE_LOOKUP_A2: *const u16 = 0x0000_0016 as _;
25
26/// Pointer to the value lookup function supplied by the ROM.
27///
28/// This address is described at `5.5.1. Locating the API Functions`
29#[cfg(all(target_arch = "arm", target_os = "none"))]
30const ROM_TABLE_LOOKUP_A1: *const u32 = 0x0000_0018 as _;
31
32/// Pointer to the data lookup function supplied by the ROM.
33///
34/// On Arm, the same function is used to look up code and data.
35#[cfg(all(target_arch = "arm", target_os = "none"))]
36const ROM_DATA_LOOKUP_A2: *const u16 = ROM_TABLE_LOOKUP_A2;
37
38/// Pointer to the data lookup function supplied by the ROM.
39///
40/// On Arm, the same function is used to look up code and data.
41#[cfg(all(target_arch = "arm", target_os = "none"))]
42const ROM_DATA_LOOKUP_A1: *const u32 = ROM_TABLE_LOOKUP_A1;
43
44/// Pointer to the value lookup function supplied by the ROM.
45///
46/// This address is described at `5.5.1. Locating the API Functions`
47#[cfg(not(all(target_arch = "arm", target_os = "none")))]
48const ROM_TABLE_LOOKUP_A2: *const u16 = 0x0000_7DFA as _;
49
50/// Pointer to the value lookup function supplied by the ROM.
51///
52/// This address is described at `5.5.1. Locating the API Functions`
53#[cfg(not(all(target_arch = "arm", target_os = "none")))]
54const ROM_TABLE_LOOKUP_A1: *const u32 = 0x0000_7DF8 as _;
55
56/// Pointer to the data lookup function supplied by the ROM.
57///
58/// On RISC-V, a different function is used to look up data.
59#[cfg(not(all(target_arch = "arm", target_os = "none")))]
60const ROM_DATA_LOOKUP_A2: *const u16 = 0x0000_7DF8 as _;
61
62/// Pointer to the data lookup function supplied by the ROM.
63///
64/// On RISC-V, a different function is used to look up data.
65#[cfg(not(all(target_arch = "arm", target_os = "none")))]
66const ROM_DATA_LOOKUP_A1: *const u32 = 0x0000_7DF4 as _;
67
68/// Address of the version number of the ROM.
69const VERSION_NUMBER: *const u8 = 0x0000_0013 as _;
70
71#[allow(unused)]
72mod rt_flags {
73 pub const FUNC_RISCV: u32 = 0x0001;
74 pub const FUNC_RISCV_FAR: u32 = 0x0003;
75 pub const FUNC_ARM_SEC: u32 = 0x0004;
76 // reserved for 32-bit pointer: 0x0008
77 pub const FUNC_ARM_NONSEC: u32 = 0x0010;
78 // reserved for 32-bit pointer: 0x0020
79 pub const DATA: u32 = 0x0040;
80 // reserved for 32-bit pointer: 0x0080
81 #[cfg(all(target_arch = "arm", target_os = "none"))]
82 pub const FUNC_ARM_SEC_RISCV: u32 = FUNC_ARM_SEC;
83 #[cfg(not(all(target_arch = "arm", target_os = "none")))]
84 pub const FUNC_ARM_SEC_RISCV: u32 = FUNC_RISCV;
85}
86
87/// Retrieve rom content from a table using a code.
88pub fn rom_table_lookup(tag: RomFnTableCode, mask: u32) -> usize {
89 let tag = u16::from_le_bytes(tag) as u32;
90 unsafe {
91 let lookup_func = if rom_version_number() == 1 {
92 ROM_TABLE_LOOKUP_A1.read() as usize
93 } else {
94 ROM_TABLE_LOOKUP_A2.read() as usize
95 };
96 let lookup_func: RomTableLookupFn = core::mem::transmute(lookup_func);
97 lookup_func(tag, mask)
98 }
99}
100
101/// Retrieve rom data content from a table using a code.
102pub fn rom_data_lookup(tag: RomFnTableCode, mask: u32) -> usize {
103 let tag = u16::from_le_bytes(tag) as u32;
104 unsafe {
105 let lookup_func = if rom_version_number() == 1 {
106 ROM_DATA_LOOKUP_A1.read() as usize
107 } else {
108 ROM_DATA_LOOKUP_A2.read() as usize
109 };
110 let lookup_func: RomTableLookupFn = core::mem::transmute(lookup_func);
111 lookup_func(tag, mask)
112 }
113}
114
115macro_rules! declare_rom_function {
116 (
117 $(#[$outer:meta])*
118 fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty
119 $lookup:block
120 ) => {
121 #[doc = r"Additional access for the `"]
122 #[doc = stringify!($name)]
123 #[doc = r"` ROM function."]
124 pub mod $name {
125 /// Retrieve a function pointer.
126 #[cfg(not(feature = "rom-func-cache"))]
127 pub fn ptr() -> extern "C" fn( $($argname: $ty),* ) -> $ret {
128 let p: usize = $lookup;
129 unsafe {
130 let func : extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p);
131 func
132 }
133 }
134
135 /// Retrieve a function pointer.
136 #[cfg(feature = "rom-func-cache")]
137 pub fn ptr() -> extern "C" fn( $($argname: $ty),* ) -> $ret {
138 use core::sync::atomic::{AtomicU16, Ordering};
139
140 // All pointers in the ROM fit in 16 bits, so we don't need a
141 // full width word to store the cached value.
142 static CACHED_PTR: AtomicU16 = AtomicU16::new(0);
143 // This is safe because the lookup will always resolve
144 // to the same value. So even if an interrupt or another
145 // core starts at the same time, it just repeats some
146 // work and eventually writes back the correct value.
147 let p: usize = match CACHED_PTR.load(Ordering::Relaxed) {
148 0 => {
149 let raw: usize = $lookup;
150 CACHED_PTR.store(raw as u16, Ordering::Relaxed);
151 raw
152 },
153 val => val as usize,
154 };
155 unsafe {
156 let func : extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p);
157 func
158 }
159 }
160 }
161
162 $(#[$outer])*
163 pub extern "C" fn $name( $($argname: $ty),* ) -> $ret {
164 $name::ptr()($($argname),*)
165 }
166 };
167
168 (
169 $(#[$outer:meta])*
170 unsafe fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty
171 $lookup:block
172 ) => {
173 #[doc = r"Additional access for the `"]
174 #[doc = stringify!($name)]
175 #[doc = r"` ROM function."]
176 pub mod $name {
177 /// Retrieve a function pointer.
178 #[cfg(not(feature = "rom-func-cache"))]
179 pub fn ptr() -> unsafe extern "C" fn( $($argname: $ty),* ) -> $ret {
180 let p: usize = $lookup;
181 unsafe {
182 let func : unsafe extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p);
183 func
184 }
185 }
186
187 /// Retrieve a function pointer.
188 #[cfg(feature = "rom-func-cache")]
189 pub fn ptr() -> unsafe extern "C" fn( $($argname: $ty),* ) -> $ret {
190 use core::sync::atomic::{AtomicU16, Ordering};
191
192 // All pointers in the ROM fit in 16 bits, so we don't need a
193 // full width word to store the cached value.
194 static CACHED_PTR: AtomicU16 = AtomicU16::new(0);
195 // This is safe because the lookup will always resolve
196 // to the same value. So even if an interrupt or another
197 // core starts at the same time, it just repeats some
198 // work and eventually writes back the correct value.
199 let p: usize = match CACHED_PTR.load(Ordering::Relaxed) {
200 0 => {
201 let raw: usize = $lookup;
202 CACHED_PTR.store(raw as u16, Ordering::Relaxed);
203 raw
204 },
205 val => val as usize,
206 };
207 unsafe {
208 let func : unsafe extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p);
209 func
210 }
211 }
212 }
213
214 $(#[$outer])*
215 /// # Safety
216 ///
217 /// This is a low-level C function. It may be difficult to call safely from
218 /// Rust. If in doubt, check the rp235x datasheet for details and do your own
219 /// safety evaluation.
220 pub unsafe extern "C" fn $name( $($argname: $ty),* ) -> $ret {
221 $name::ptr()($($argname),*)
222 }
223 };
224}
225
226// **************** 5.5.7 Low-level Flash Commands ****************
227
228declare_rom_function! {
229 /// Restore all QSPI pad controls to their default state, and connect the
230 /// QMI peripheral to the QSPI pads.
231 ///
232 /// Supported architectures: ARM-S, RISC-V
233 unsafe fn connect_internal_flash() -> () {
234 crate::rom_data::rom_table_lookup(*b"IF", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
235 }
236}
237
238declare_rom_function! {
239 /// Initialise the QMI for serial operations (direct mode)
240 ///
241 /// Also initialise a basic XIP mode, where the QMI will perform 03h serial
242 /// read commands at low speed (CLKDIV=12) in response to XIP reads.
243 ///
244 /// Then, issue a sequence to the QSPI device on chip select 0, designed to
245 /// return it from continuous read mode ("XIP mode") and/or QPI mode to a
246 /// state where it will accept serial commands. This is necessary after
247 /// system reset to restore the QSPI device to a known state, because
248 /// resetting RP2350 does not reset attached QSPI devices. It is also
249 /// necessary when user code, having already performed some
250 /// continuous-read-mode or QPI-mode accesses, wishes to return the QSPI
251 /// device to a state where it will accept the serial erase and programming
252 /// commands issued by the bootrom’s flash access functions.
253 ///
254 /// If a GPIO for the secondary chip select is configured via FLASH_DEVINFO,
255 /// then the XIP exit sequence is also issued to chip select 1.
256 ///
257 /// The QSPI device should be accessible for XIP reads after calling this
258 /// function; the name flash_exit_xip refers to returning the QSPI device
259 /// from its XIP state to a serial command state.
260 ///
261 /// Supported architectures: ARM-S, RISC-V
262 unsafe fn flash_exit_xip() -> () {
263 crate::rom_data::rom_table_lookup(*b"EX", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
264 }
265}
266
267declare_rom_function! {
268 /// Erase count bytes, starting at addr (offset from start of flash).
269 ///
270 /// Optionally, pass a block erase command e.g. D8h block erase, and the
271 /// size of the block erased by this command — this function will use the
272 /// larger block erase where possible, for much higher erase speed. addr
273 /// must be aligned to a 4096-byte sector, and count must be a multiple of
274 /// 4096 bytes.
275 ///
276 /// This is a low-level flash API, and no validation of the arguments is
277 /// performed. See flash_op() for a higher-level API which checks alignment,
278 /// flash bounds and partition permissions, and can transparently apply a
279 /// runtime-to-storage address translation.
280 ///
281 /// The QSPI device must be in a serial command state before calling this
282 /// API, which can be achieved by calling connect_internal_flash() followed
283 /// by flash_exit_xip(). After the erase, the flash cache should be flushed
284 /// via flash_flush_cache() to ensure the modified flash data is visible to
285 /// cached XIP accesses.
286 ///
287 /// Finally, the original XIP mode should be restored by copying the saved
288 /// XIP setup function from bootram into SRAM, and executing it: the bootrom
289 /// provides a default function which restores the flash mode/clkdiv
290 /// discovered during flash scanning, and user programs can override this
291 /// with their own XIP setup function.
292 ///
293 /// For the duration of the erase operation, QMI is in direct mode (Section
294 /// 12.14.5) and attempting to access XIP from DMA, the debugger or the
295 /// other core will return a bus fault. XIP becomes accessible again once
296 /// the function returns.
297 ///
298 /// Supported architectures: ARM-S, RISC-V
299 unsafe fn flash_range_erase(addr: u32, count: usize, block_size: u32, block_cmd: u8) -> () {
300 crate::rom_data::rom_table_lookup(*b"RE", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
301 }
302}
303
304declare_rom_function! {
305 /// Program data to a range of flash storage addresses starting at addr
306 /// (offset from the start of flash) and count bytes in size.
307 ///
308 /// `addr` must be aligned to a 256-byte boundary, and count must be a
309 /// multiple of 256.
310 ///
311 /// This is a low-level flash API, and no validation of the arguments is
312 /// performed. See flash_op() for a higher-level API which checks alignment,
313 /// flash bounds and partition permissions, and can transparently apply a
314 /// runtime-to-storage address translation.
315 ///
316 /// The QSPI device must be in a serial command state before calling this
317 /// API — see notes on flash_range_erase().
318 ///
319 /// Supported architectures: ARM-S, RISC-V
320 unsafe fn flash_range_program(addr: u32, data: *const u8, count: usize) -> () {
321 crate::rom_data::rom_table_lookup(*b"RP", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
322 }
323}
324
325declare_rom_function! {
326 /// Flush the entire XIP cache, by issuing an invalidate by set/way
327 /// maintenance operation to every cache line (Section 4.4.1).
328 ///
329 /// This ensures that flash program/erase operations are visible to
330 /// subsequent cached XIP reads.
331 ///
332 /// Note that this unpins pinned cache lines, which may interfere with
333 /// cache-as-SRAM use of the XIP cache.
334 ///
335 /// No other operations are performed.
336 ///
337 /// Supported architectures: ARM-S, RISC-V
338 unsafe fn flash_flush_cache() -> () {
339 crate::rom_data::rom_table_lookup(*b"FC", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
340 }
341}
342
343declare_rom_function! {
344 /// Configure the QMI to generate a standard 03h serial read command, with
345 /// 24 address bits, upon each XIP access.
346 ///
347 /// This is a slow XIP configuration, but is widely supported. CLKDIV is set
348 /// to 12. The debugger may call this function to ensure that flash is
349 /// readable following a program/erase operation.
350 ///
351 /// Note that the same setup is performed by flash_exit_xip(), and the
352 /// RP2350 flash program/erase functions do not leave XIP in an inaccessible
353 /// state, so calls to this function are largely redundant. It is provided
354 /// for compatibility with RP2040.
355 ///
356 /// Supported architectures: ARM-S, RISC-V
357 unsafe fn flash_enter_cmd_xip() -> () {
358 crate::rom_data::rom_table_lookup(*b"CX", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
359 }
360}
361
362declare_rom_function! {
363 /// Configure QMI for one of a small menu of XIP read modes supported by the
364 /// bootrom. This mode is configured for both memory windows (both chip
365 /// selects), and the clock divisor is also applied to direct mode.
366 ///
367 /// The available modes are:
368 ///
369 /// * 0: `03h` serial read: serial address, serial data, no wait cycles
370 /// * 1: `0Bh` serial read: serial address, serial data, 8 wait cycles
371 /// * 2: `BBh` dual-IO read: dual address, dual data, 4 wait cycles
372 /// (including MODE bits, which are driven to 0)
373 /// * 3: `EBh` quad-IO read: quad address, quad data, 6 wait cycles
374 /// (including MODE bits, which are driven to 0)
375 ///
376 /// The XIP write command/format are not configured by this function. When
377 /// booting from flash, the bootrom tries each of these modes in turn, from
378 /// 3 down to 0. The first mode that is found to work is remembered, and a
379 /// default XIP setup function is written into bootram that calls this
380 /// function (flash_select_xip_read_mode) with the parameters discovered
381 /// during flash scanning. This can be called at any time to restore the
382 /// flash parameters discovered during flash boot.
383 ///
384 /// All XIP modes configured by the bootrom have an 8-bit serial command
385 /// prefix, so that the flash can remain in a serial command state, meaning
386 /// XIP accesses can be mixed more freely with program/erase serial
387 /// operations. This has a performance penalty, so users can perform their
388 /// own flash setup after flash boot using continuous read mode or QPI mode
389 /// to avoid or alleviate the command prefix cost.
390 ///
391 /// Supported architectures: ARM-S, RISC-V
392 unsafe fn flash_select_xip_read_mode(bootrom_xip_mode: u8, clkdiv: u8) -> () {
393 crate::rom_data::rom_table_lookup(*b"XM", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
394 }
395}
396
397declare_rom_function! {
398 /// Restore the QMI address translation registers, ATRANS0 through ATRANS7,
399 /// to their reset state. This makes the runtime- to-storage address map an
400 /// identity map, i.e. the mapped and unmapped address are equal, and the
401 /// entire space is fully mapped.
402 ///
403 /// See [Section 12.14.4](https://rptl.io/rp2350-datasheet#section_bootrom) of the RP2350
404 /// datasheet.
405 ///
406 /// Supported architectures: ARM-S, RISC-V
407 unsafe fn flash_reset_address_trans() -> () {
408 crate::rom_data::rom_table_lookup(*b"RA", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
409 }
410}
411
412// **************** High-level Flash Commands ****************
413
414declare_rom_function! {
415 /// Applies the address translation currently configured by QMI address
416 /// translation registers, ATRANS0 through ATRANS7.
417 ///
418 /// See [Section 12.14.4](https://rptl.io/rp2350-datasheet#section_bootrom) of the RP2350
419 /// datasheet.
420 ///
421 /// Translating an address outside of the XIP runtime address window, or
422 /// beyond the bounds of an ATRANSx_SIZE field, returns
423 /// BOOTROM_ERROR_INVALID_ADDRESS, which is not a valid flash storage
424 /// address. Otherwise, return the storage address which QMI would access
425 /// when presented with the runtime address addr. This is effectively a
426 /// virtual-to-physical address translation for QMI.
427 ///
428 /// Supported architectures: ARM-S, RISC-V
429 unsafe fn flash_runtime_to_storage_addr(addr: u32) -> i32 {
430 crate::rom_data::rom_table_lookup(*b"FA", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
431 }
432}
433
434declare_rom_function! {
435 /// Non-secure version of [flash_runtime_to_storage_addr()]
436 ///
437 /// Supported architectures: ARM-NS
438 #[cfg(all(target_arch = "arm", target_os = "none"))]
439 unsafe fn flash_runtime_to_storage_addr_ns(addr: u32) -> i32 {
440 crate::rom_data::rom_table_lookup(*b"FA", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC)
441 }
442}
443
444declare_rom_function! {
445 /// Perform a flash read, erase, or program operation.
446 ///
447 /// Erase operations must be sector-aligned (4096 bytes) and sector-
448 /// multiple-sized, and program operations must be page-aligned (256 bytes)
449 /// and page-multiple-sized; misaligned erase and program operations will
450 /// return BOOTROM_ERROR_BAD_ALIGNMENT. The operation — erase, read, program
451 /// — is selected by the CFLASH_OP_BITS bitfield of the flags argument.
452 ///
453 /// See datasheet section 5.5.8.2 for more details.
454 ///
455 /// Supported architectures: ARM-S, RISC-V
456 unsafe fn flash_op(flags: u32, addr: u32, size_bytes: u32, buffer: *mut u8) -> i32 {
457 crate::rom_data::rom_table_lookup(*b"FO", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
458 }
459}
460
461declare_rom_function! {
462 /// Non-secure version of [flash_op()]
463 ///
464 /// Supported architectures: ARM-NS
465 #[cfg(all(target_arch = "arm", target_os = "none"))]
466 unsafe fn flash_op_ns(flags: u32, addr: u32, size_bytes: u32, buffer: *mut u8) -> i32 {
467 crate::rom_data::rom_table_lookup(*b"FO", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC)
468 }
469}
470
471// **************** Security Related Functions ****************
472
473declare_rom_function! {
474 /// Allow or disallow the specific NS API (note all NS APIs default to
475 /// disabled).
476 ///
477 /// See datasheet section 5.5.9.1 for more details.
478 ///
479 /// Supported architectures: ARM-S
480 #[cfg(all(target_arch = "arm", target_os = "none"))]
481 unsafe fn set_ns_api_permission(ns_api_num: u32, allowed: u8) -> i32 {
482 crate::rom_data::rom_table_lookup(*b"SP", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC)
483 }
484}
485
486declare_rom_function! {
487 /// Utility method that can be used by secure ARM code to validate a buffer
488 /// passed to it from Non-secure code.
489 ///
490 /// See datasheet section 5.5.9.2 for more details.
491 ///
492 /// Supported architectures: ARM-S, RISC-V
493 unsafe fn validate_ns_buffer() -> () {
494 crate::rom_data::rom_table_lookup(*b"VB", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
495 }
496}
497
498// **************** Miscellaneous Functions ****************
499
500declare_rom_function! {
501 /// Resets the RP2350 and uses the watchdog facility to restart.
502 ///
503 /// See datasheet section 5.5.10.1 for more details.
504 ///
505 /// Supported architectures: ARM-S, RISC-V
506 fn reboot(flags: u32, delay_ms: u32, p0: u32, p1: u32) -> i32 {
507 crate::rom_data::rom_table_lookup(*b"RB", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
508 }
509}
510
511declare_rom_function! {
512 /// Non-secure version of [reboot()]
513 ///
514 /// Supported architectures: ARM-NS
515 #[cfg(all(target_arch = "arm", target_os = "none"))]
516 fn reboot_ns(flags: u32, delay_ms: u32, p0: u32, p1: u32) -> i32 {
517 crate::rom_data::rom_table_lookup(*b"RB", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC)
518 }
519}
520
521declare_rom_function! {
522 /// Resets internal bootrom state.
523 ///
524 /// See datasheet section 5.5.10.2 for more details.
525 ///
526 /// Supported architectures: ARM-S, RISC-V
527 unsafe fn bootrom_state_reset(flags: u32) -> () {
528 crate::rom_data::rom_table_lookup(*b"SR", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
529 }
530}
531
532declare_rom_function! {
533 /// Set a boot ROM callback.
534 ///
535 /// The only supported callback_number is 0 which sets the callback used for
536 /// the secure_call API.
537 ///
538 /// See datasheet section 5.5.10.3 for more details.
539 ///
540 /// Supported architectures: ARM-S, RISC-V
541 unsafe fn set_rom_callback(callback_number: i32, callback_fn: *const ()) -> i32 {
542 crate::rom_data::rom_table_lookup(*b"RC", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
543 }
544}
545
546// **************** System Information Functions ****************
547
548declare_rom_function! {
549 /// Fills a buffer with various system information.
550 ///
551 /// Note that this API is also used to return information over the PICOBOOT
552 /// interface.
553 ///
554 /// See datasheet section 5.5.11.1 for more details.
555 ///
556 /// Supported architectures: ARM-S, RISC-V
557 unsafe fn get_sys_info(out_buffer: *mut u32, out_buffer_word_size: usize, flags: u32) -> i32 {
558 crate::rom_data::rom_table_lookup(*b"GS", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
559 }
560}
561
562declare_rom_function! {
563 /// Non-secure version of [get_sys_info()]
564 ///
565 /// Supported architectures: ARM-NS
566 #[cfg(all(target_arch = "arm", target_os = "none"))]
567 unsafe fn get_sys_info_ns(out_buffer: *mut u32, out_buffer_word_size: usize, flags: u32) -> i32 {
568 crate::rom_data::rom_table_lookup(*b"GS", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC)
569 }
570}
571
572declare_rom_function! {
573 /// Fills a buffer with information from the partition table.
574 ///
575 /// Note that this API is also used to return information over the PICOBOOT
576 /// interface.
577 ///
578 /// See datasheet section 5.5.11.2 for more details.
579 ///
580 /// Supported architectures: ARM-S, RISC-V
581 unsafe fn get_partition_table_info(out_buffer: *mut u32, out_buffer_word_size: usize, flags_and_partition: u32) -> i32 {
582 crate::rom_data::rom_table_lookup(*b"GP", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
583 }
584}
585
586declare_rom_function! {
587 /// Non-secure version of [get_partition_table_info()]
588 ///
589 /// Supported architectures: ARM-NS
590 #[cfg(all(target_arch = "arm", target_os = "none"))]
591 unsafe fn get_partition_table_info_ns(out_buffer: *mut u32, out_buffer_word_size: usize, flags_and_partition: u32) -> i32 {
592 crate::rom_data::rom_table_lookup(*b"GP", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC)
593 }
594}
595
596declare_rom_function! {
597 /// Loads the current partition table from flash, if present.
598 ///
599 /// See datasheet section 5.5.11.3 for more details.
600 ///
601 /// Supported architectures: ARM-S, RISC-V
602 unsafe fn load_partition_table(workarea_base: *mut u8, workarea_size: usize, force_reload: bool) -> i32 {
603 crate::rom_data::rom_table_lookup(*b"LP", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
604 }
605}
606
607declare_rom_function! {
608 /// Writes data from a buffer into OTP, or reads data from OTP into a buffer.
609 ///
610 /// See datasheet section 5.5.11.4 for more details.
611 ///
612 /// Supported architectures: ARM-S, RISC-V
613 unsafe fn otp_access(buf: *mut u8, buf_len: usize, row_and_flags: u32) -> i32 {
614 crate::rom_data::rom_table_lookup(*b"OA", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
615 }
616}
617
618declare_rom_function! {
619 /// Non-secure version of [otp_access()]
620 ///
621 /// Supported architectures: ARM-NS
622 #[cfg(all(target_arch = "arm", target_os = "none"))]
623 unsafe fn otp_access_ns(buf: *mut u8, buf_len: usize, row_and_flags: u32) -> i32 {
624 crate::rom_data::rom_table_lookup(*b"OA", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC)
625 }
626}
627
628// **************** Boot Related Functions ****************
629
630declare_rom_function! {
631 /// Determines which of the partitions has the "better" IMAGE_DEF. In the
632 /// case of executable images, this is the one that would be booted.
633 ///
634 /// See datasheet section 5.5.12.1 for more details.
635 ///
636 /// Supported architectures: ARM-S, RISC-V
637 unsafe fn pick_ab_parition(workarea_base: *mut u8, workarea_size: usize, partition_a_num: u32) -> i32 {
638 crate::rom_data::rom_table_lookup(*b"AB", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
639 }
640}
641
642declare_rom_function! {
643 /// Searches a memory region for a launchable image, and executes it if
644 /// possible.
645 ///
646 /// See datasheet section 5.5.12.2 for more details.
647 ///
648 /// Supported architectures: ARM-S, RISC-V
649 unsafe fn chain_image(workarea_base: *mut u8, workarea_size: usize, region_base: i32, region_size: u32) -> i32 {
650 crate::rom_data::rom_table_lookup(*b"CI", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
651 }
652}
653
654declare_rom_function! {
655 /// Perform an "explicit" buy of an executable launched via an IMAGE_DEF
656 /// which was "explicit buy" flagged.
657 ///
658 /// See datasheet section 5.5.12.3 for more details.
659 ///
660 /// Supported architectures: ARM-S, RISC-V
661 unsafe fn explicit_buy(buffer: *mut u8, buffer_size: u32) -> i32 {
662 crate::rom_data::rom_table_lookup(*b"EB", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
663 }
664}
665
666declare_rom_function! {
667 /// Not yet documented.
668 ///
669 /// See datasheet section 5.5.12.4 for more details.
670 ///
671 /// Supported architectures: ARM-S, RISC-V
672 unsafe fn get_uf2_target_partition(workarea_base: *mut u8, workarea_size: usize, family_id: u32, partition_out: *mut u32) -> i32 {
673 crate::rom_data::rom_table_lookup(*b"GU", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
674 }
675}
676
677declare_rom_function! {
678 /// Returns: The index of the B partition of partition A if a partition
679 /// table is present and loaded, and there is a partition A with a B
680 /// partition; otherwise returns BOOTROM_ERROR_NOT_FOUND.
681 ///
682 /// See datasheet section 5.5.12.5 for more details.
683 ///
684 /// Supported architectures: ARM-S, RISC-V
685 unsafe fn get_b_partition(partition_a: u32) -> i32 {
686 crate::rom_data::rom_table_lookup(*b"GB", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV)
687 }
688}
689
690// **************** Non-secure-specific Functions ****************
691
692// NB: The "secure_call" function should be here, but it doesn't have a fixed
693// function signature as it is designed to let you bounce into any secure
694// function from non-secure mode.
695
696// **************** RISC-V Functions ****************
697
698declare_rom_function! {
699 /// Set stack for RISC-V bootrom functions to use.
700 ///
701 /// See datasheet section 5.5.14.1 for more details.
702 ///
703 /// Supported architectures: RISC-V
704 #[cfg(not(all(target_arch = "arm", target_os = "none")))]
705 unsafe fn set_bootrom_stack(base_size: *mut u32) -> i32 {
706 crate::rom_data::rom_table_lookup(*b"SS", crate::rom_data::inner::rt_flags::FUNC_RISCV)
707 }
708}
709
710/// The version number of the rom.
711pub fn rom_version_number() -> u8 {
712 unsafe { *VERSION_NUMBER }
713}
714
715/// The 8 most significant hex digits of the Bootrom git revision.
716pub fn git_revision() -> u32 {
717 let ptr = rom_data_lookup(*b"GR", rt_flags::DATA) as *const u32;
718 unsafe { ptr.read() }
719}
720
721/// A pointer to the resident partition table info.
722///
723/// The resident partition table is the subset of the full partition table that
724/// is kept in memory, and used for flash permissions.
725pub fn partition_table_pointer() -> *const u32 {
726 let ptr = rom_data_lookup(*b"PT", rt_flags::DATA) as *const *const u32;
727 unsafe { ptr.read() }
728}
729
730/// Determine if we are in secure mode
731///
732/// Returns `true` if we are in secure mode and `false` if we are in non-secure
733/// mode.
734#[cfg(all(target_arch = "arm", target_os = "none"))]
735pub fn is_secure_mode() -> bool {
736 // Look at the start of ROM, which is always readable
737 #[allow(clippy::zero_ptr)]
738 let rom_base: *mut u32 = 0x0000_0000 as *mut u32;
739 // Use the 'tt' instruction to check the permissions for that address
740 let tt = cortex_m::asm::tt(rom_base);
741 // Is the secure bit set? => secure mode
742 (tt & (1 << 22)) != 0
743}
744
745/// Determine if we are in secure mode
746///
747/// Always returns `false` on RISC-V as it is impossible to determine if
748/// you are in Machine Mode or User Mode by design.
749#[cfg(not(all(target_arch = "arm", target_os = "none")))]
750pub fn is_secure_mode() -> bool {
751 false
752}
diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs
index 1617c144c..b89df74a2 100644
--- a/embassy-rp/src/spi.rs
+++ b/embassy-rp/src/spi.rs
@@ -106,15 +106,55 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
106 106
107 if let Some(pin) = &clk { 107 if let Some(pin) = &clk {
108 pin.gpio().ctrl().write(|w| w.set_funcsel(1)); 108 pin.gpio().ctrl().write(|w| w.set_funcsel(1));
109 pin.pad_ctrl().write(|w| {
110 #[cfg(feature = "_rp235x")]
111 w.set_iso(false);
112 w.set_schmitt(true);
113 w.set_slewfast(false);
114 w.set_ie(true);
115 w.set_od(false);
116 w.set_pue(false);
117 w.set_pde(false);
118 });
109 } 119 }
110 if let Some(pin) = &mosi { 120 if let Some(pin) = &mosi {
111 pin.gpio().ctrl().write(|w| w.set_funcsel(1)); 121 pin.gpio().ctrl().write(|w| w.set_funcsel(1));
122 pin.pad_ctrl().write(|w| {
123 #[cfg(feature = "_rp235x")]
124 w.set_iso(false);
125 w.set_schmitt(true);
126 w.set_slewfast(false);
127 w.set_ie(true);
128 w.set_od(false);
129 w.set_pue(false);
130 w.set_pde(false);
131 });
112 } 132 }
113 if let Some(pin) = &miso { 133 if let Some(pin) = &miso {
114 pin.gpio().ctrl().write(|w| w.set_funcsel(1)); 134 pin.gpio().ctrl().write(|w| w.set_funcsel(1));
135 pin.pad_ctrl().write(|w| {
136 #[cfg(feature = "_rp235x")]
137 w.set_iso(false);
138 w.set_schmitt(true);
139 w.set_slewfast(false);
140 w.set_ie(true);
141 w.set_od(false);
142 w.set_pue(false);
143 w.set_pde(false);
144 });
115 } 145 }
116 if let Some(pin) = &cs { 146 if let Some(pin) = &cs {
117 pin.gpio().ctrl().write(|w| w.set_funcsel(1)); 147 pin.gpio().ctrl().write(|w| w.set_funcsel(1));
148 pin.pad_ctrl().write(|w| {
149 #[cfg(feature = "_rp235x")]
150 w.set_iso(false);
151 w.set_schmitt(true);
152 w.set_slewfast(false);
153 w.set_ie(true);
154 w.set_od(false);
155 w.set_pue(false);
156 w.set_pde(false);
157 });
118 } 158 }
119 Self { 159 Self {
120 inner, 160 inner,
@@ -442,8 +482,8 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
442trait SealedMode {} 482trait SealedMode {}
443 483
444trait SealedInstance { 484trait SealedInstance {
445 const TX_DREQ: u8; 485 const TX_DREQ: pac::dma::vals::TreqSel;
446 const RX_DREQ: u8; 486 const RX_DREQ: pac::dma::vals::TreqSel;
447 487
448 fn regs(&self) -> pac::spi::Spi; 488 fn regs(&self) -> pac::spi::Spi;
449} 489}
@@ -459,8 +499,8 @@ pub trait Instance: SealedInstance {}
459macro_rules! impl_instance { 499macro_rules! impl_instance {
460 ($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { 500 ($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
461 impl SealedInstance for peripherals::$type { 501 impl SealedInstance for peripherals::$type {
462 const TX_DREQ: u8 = $tx_dreq; 502 const TX_DREQ: pac::dma::vals::TreqSel = $tx_dreq;
463 const RX_DREQ: u8 = $rx_dreq; 503 const RX_DREQ: pac::dma::vals::TreqSel = $rx_dreq;
464 504
465 fn regs(&self) -> pac::spi::Spi { 505 fn regs(&self) -> pac::spi::Spi {
466 pac::$type 506 pac::$type
@@ -470,8 +510,18 @@ macro_rules! impl_instance {
470 }; 510 };
471} 511}
472 512
473impl_instance!(SPI0, Spi0, 16, 17); 513impl_instance!(
474impl_instance!(SPI1, Spi1, 18, 19); 514 SPI0,
515 Spi0,
516 pac::dma::vals::TreqSel::SPI0_TX,
517 pac::dma::vals::TreqSel::SPI0_RX
518);
519impl_instance!(
520 SPI1,
521 Spi1,
522 pac::dma::vals::TreqSel::SPI1_TX,
523 pac::dma::vals::TreqSel::SPI1_RX
524);
475 525
476/// CLK pin. 526/// CLK pin.
477pub trait ClkPin<T: Instance>: GpioPin {} 527pub trait ClkPin<T: Instance>: GpioPin {}
@@ -518,6 +568,42 @@ impl_pin!(PIN_26, SPI1, ClkPin);
518impl_pin!(PIN_27, SPI1, MosiPin); 568impl_pin!(PIN_27, SPI1, MosiPin);
519impl_pin!(PIN_28, SPI1, MisoPin); 569impl_pin!(PIN_28, SPI1, MisoPin);
520impl_pin!(PIN_29, SPI1, CsPin); 570impl_pin!(PIN_29, SPI1, CsPin);
571#[cfg(feature = "rp235xb")]
572impl_pin!(PIN_30, SPI1, ClkPin);
573#[cfg(feature = "rp235xb")]
574impl_pin!(PIN_31, SPI1, MosiPin);
575#[cfg(feature = "rp235xb")]
576impl_pin!(PIN_32, SPI0, MisoPin);
577#[cfg(feature = "rp235xb")]
578impl_pin!(PIN_33, SPI0, CsPin);
579#[cfg(feature = "rp235xb")]
580impl_pin!(PIN_34, SPI0, ClkPin);
581#[cfg(feature = "rp235xb")]
582impl_pin!(PIN_35, SPI0, MosiPin);
583#[cfg(feature = "rp235xb")]
584impl_pin!(PIN_36, SPI0, MisoPin);
585#[cfg(feature = "rp235xb")]
586impl_pin!(PIN_37, SPI0, CsPin);
587#[cfg(feature = "rp235xb")]
588impl_pin!(PIN_38, SPI0, ClkPin);
589#[cfg(feature = "rp235xb")]
590impl_pin!(PIN_39, SPI0, MosiPin);
591#[cfg(feature = "rp235xb")]
592impl_pin!(PIN_40, SPI1, MisoPin);
593#[cfg(feature = "rp235xb")]
594impl_pin!(PIN_41, SPI1, CsPin);
595#[cfg(feature = "rp235xb")]
596impl_pin!(PIN_42, SPI1, ClkPin);
597#[cfg(feature = "rp235xb")]
598impl_pin!(PIN_43, SPI1, MosiPin);
599#[cfg(feature = "rp235xb")]
600impl_pin!(PIN_44, SPI1, MisoPin);
601#[cfg(feature = "rp235xb")]
602impl_pin!(PIN_45, SPI1, CsPin);
603#[cfg(feature = "rp235xb")]
604impl_pin!(PIN_46, SPI1, ClkPin);
605#[cfg(feature = "rp235xb")]
606impl_pin!(PIN_47, SPI1, MosiPin);
521 607
522macro_rules! impl_mode { 608macro_rules! impl_mode {
523 ($name:ident) => { 609 ($name:ident) => {
diff --git a/embassy-rp/src/time_driver.rs b/embassy-rp/src/time_driver.rs
index bab1044cb..e5b407a29 100644
--- a/embassy-rp/src/time_driver.rs
+++ b/embassy-rp/src/time_driver.rs
@@ -6,6 +6,10 @@ use critical_section::CriticalSection;
6use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 6use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
7use embassy_sync::blocking_mutex::Mutex; 7use embassy_sync::blocking_mutex::Mutex;
8use embassy_time_driver::{AlarmHandle, Driver}; 8use embassy_time_driver::{AlarmHandle, Driver};
9#[cfg(feature = "rp2040")]
10use pac::TIMER;
11#[cfg(feature = "_rp235x")]
12use pac::TIMER0 as TIMER;
9 13
10use crate::interrupt::InterruptExt; 14use crate::interrupt::InterruptExt;
11use crate::{interrupt, pac}; 15use crate::{interrupt, pac};
@@ -35,9 +39,9 @@ embassy_time_driver::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
35impl Driver for TimerDriver { 39impl Driver for TimerDriver {
36 fn now(&self) -> u64 { 40 fn now(&self) -> u64 {
37 loop { 41 loop {
38 let hi = pac::TIMER.timerawh().read(); 42 let hi = TIMER.timerawh().read();
39 let lo = pac::TIMER.timerawl().read(); 43 let lo = TIMER.timerawl().read();
40 let hi2 = pac::TIMER.timerawh().read(); 44 let hi2 = TIMER.timerawh().read();
41 if hi == hi2 { 45 if hi == hi2 {
42 return (hi as u64) << 32 | (lo as u64); 46 return (hi as u64) << 32 | (lo as u64);
43 } 47 }
@@ -77,13 +81,13 @@ impl Driver for TimerDriver {
77 // Note that we're not checking the high bits at all. This means the irq may fire early 81 // Note that we're not checking the high bits at all. This means the irq may fire early
78 // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire 82 // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire
79 // it is checked if the alarm time has passed. 83 // it is checked if the alarm time has passed.
80 pac::TIMER.alarm(n).write_value(timestamp as u32); 84 TIMER.alarm(n).write_value(timestamp as u32);
81 85
82 let now = self.now(); 86 let now = self.now();
83 if timestamp <= now { 87 if timestamp <= now {
84 // If alarm timestamp has passed the alarm will not fire. 88 // If alarm timestamp has passed the alarm will not fire.
85 // Disarm the alarm and return `false` to indicate that. 89 // Disarm the alarm and return `false` to indicate that.
86 pac::TIMER.armed().write(|w| w.set_armed(1 << n)); 90 TIMER.armed().write(|w| w.set_armed(1 << n));
87 91
88 alarm.timestamp.set(u64::MAX); 92 alarm.timestamp.set(u64::MAX);
89 93
@@ -105,17 +109,17 @@ impl TimerDriver {
105 } else { 109 } else {
106 // Not elapsed, arm it again. 110 // Not elapsed, arm it again.
107 // This can happen if it was set more than 2^32 us in the future. 111 // This can happen if it was set more than 2^32 us in the future.
108 pac::TIMER.alarm(n).write_value(timestamp as u32); 112 TIMER.alarm(n).write_value(timestamp as u32);
109 } 113 }
110 }); 114 });
111 115
112 // clear the irq 116 // clear the irq
113 pac::TIMER.intr().write(|w| w.set_alarm(n, true)); 117 TIMER.intr().write(|w| w.set_alarm(n, true));
114 } 118 }
115 119
116 fn trigger_alarm(&self, n: usize, cs: CriticalSection) { 120 fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
117 // disarm 121 // disarm
118 pac::TIMER.armed().write(|w| w.set_armed(1 << n)); 122 TIMER.armed().write(|w| w.set_armed(1 << n));
119 123
120 let alarm = &self.alarms.borrow(cs)[n]; 124 let alarm = &self.alarms.borrow(cs)[n];
121 alarm.timestamp.set(u64::MAX); 125 alarm.timestamp.set(u64::MAX);
@@ -138,38 +142,72 @@ pub unsafe fn init() {
138 }); 142 });
139 143
140 // enable all irqs 144 // enable all irqs
141 pac::TIMER.inte().write(|w| { 145 TIMER.inte().write(|w| {
142 w.set_alarm(0, true); 146 w.set_alarm(0, true);
143 w.set_alarm(1, true); 147 w.set_alarm(1, true);
144 w.set_alarm(2, true); 148 w.set_alarm(2, true);
145 w.set_alarm(3, true); 149 w.set_alarm(3, true);
146 }); 150 });
147 interrupt::TIMER_IRQ_0.enable(); 151 #[cfg(feature = "rp2040")]
148 interrupt::TIMER_IRQ_1.enable(); 152 {
149 interrupt::TIMER_IRQ_2.enable(); 153 interrupt::TIMER_IRQ_0.enable();
150 interrupt::TIMER_IRQ_3.enable(); 154 interrupt::TIMER_IRQ_1.enable();
155 interrupt::TIMER_IRQ_2.enable();
156 interrupt::TIMER_IRQ_3.enable();
157 }
158 #[cfg(feature = "_rp235x")]
159 {
160 interrupt::TIMER0_IRQ_0.enable();
161 interrupt::TIMER0_IRQ_1.enable();
162 interrupt::TIMER0_IRQ_2.enable();
163 interrupt::TIMER0_IRQ_3.enable();
164 }
151} 165}
152 166
153#[cfg(feature = "rt")] 167#[cfg(all(feature = "rt", feature = "rp2040"))]
154#[interrupt] 168#[interrupt]
155fn TIMER_IRQ_0() { 169fn TIMER_IRQ_0() {
156 DRIVER.check_alarm(0) 170 DRIVER.check_alarm(0)
157} 171}
158 172
159#[cfg(feature = "rt")] 173#[cfg(all(feature = "rt", feature = "rp2040"))]
160#[interrupt] 174#[interrupt]
161fn TIMER_IRQ_1() { 175fn TIMER_IRQ_1() {
162 DRIVER.check_alarm(1) 176 DRIVER.check_alarm(1)
163} 177}
164 178
165#[cfg(feature = "rt")] 179#[cfg(all(feature = "rt", feature = "rp2040"))]
166#[interrupt] 180#[interrupt]
167fn TIMER_IRQ_2() { 181fn TIMER_IRQ_2() {
168 DRIVER.check_alarm(2) 182 DRIVER.check_alarm(2)
169} 183}
170 184
171#[cfg(feature = "rt")] 185#[cfg(all(feature = "rt", feature = "rp2040"))]
172#[interrupt] 186#[interrupt]
173fn TIMER_IRQ_3() { 187fn TIMER_IRQ_3() {
174 DRIVER.check_alarm(3) 188 DRIVER.check_alarm(3)
175} 189}
190
191#[cfg(all(feature = "rt", feature = "_rp235x"))]
192#[interrupt]
193fn TIMER0_IRQ_0() {
194 DRIVER.check_alarm(0)
195}
196
197#[cfg(all(feature = "rt", feature = "_rp235x"))]
198#[interrupt]
199fn TIMER0_IRQ_1() {
200 DRIVER.check_alarm(1)
201}
202
203#[cfg(all(feature = "rt", feature = "_rp235x"))]
204#[interrupt]
205fn TIMER0_IRQ_2() {
206 DRIVER.check_alarm(2)
207}
208
209#[cfg(all(feature = "rt", feature = "_rp235x"))]
210#[interrupt]
211fn TIMER0_IRQ_3() {
212 DRIVER.check_alarm(3)
213}
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
index c94164040..152a432c9 100644
--- a/embassy-rp/src/uart/buffered.rs
+++ b/embassy-rp/src/uart/buffered.rs
@@ -163,9 +163,21 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
163 self.tx.send_break(bits).await 163 self.tx.send_break(bits).await
164 } 164 }
165 165
166 /// sets baudrate on runtime
167 pub fn set_baudrate(&mut self, baudrate: u32) {
168 super::Uart::<'d, T, Async>::set_baudrate_inner(baudrate);
169 }
170
166 /// Split into separate RX and TX handles. 171 /// Split into separate RX and TX handles.
167 pub fn split(self) -> (BufferedUartRx<'d, T>, BufferedUartTx<'d, T>) { 172 pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) {
168 (self.rx, self.tx) 173 (self.tx, self.rx)
174 }
175
176 /// Split the Uart into a transmitter and receiver by mutable reference,
177 /// which is particularly useful when having two tasks correlating to
178 /// transmitting and receiving.
179 pub fn split_ref(&mut self) -> (&mut BufferedUartTx<'d, T>, &mut BufferedUartRx<'d, T>) {
180 (&mut self.tx, &mut self.rx)
169 } 181 }
170} 182}
171 183
@@ -315,6 +327,12 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
315 w.set_rtim(true); 327 w.set_rtim(true);
316 }); 328 });
317 } 329 }
330
331 /// we are ready to read if there is data in the buffer
332 fn read_ready() -> Result<bool, Error> {
333 let state = T::buffered_state();
334 Ok(!state.rx_buf.is_empty())
335 }
318} 336}
319 337
320impl<'d, T: Instance> BufferedUartTx<'d, T> { 338impl<'d, T: Instance> BufferedUartTx<'d, T> {
@@ -621,6 +639,18 @@ impl<'d, T: Instance + 'd> embedded_io_async::Read for BufferedUartRx<'d, T> {
621 } 639 }
622} 640}
623 641
642impl<'d, T: Instance + 'd> embedded_io_async::ReadReady for BufferedUart<'d, T> {
643 fn read_ready(&mut self) -> Result<bool, Self::Error> {
644 BufferedUartRx::<'d, T>::read_ready()
645 }
646}
647
648impl<'d, T: Instance + 'd> embedded_io_async::ReadReady for BufferedUartRx<'d, T> {
649 fn read_ready(&mut self) -> Result<bool, Self::Error> {
650 Self::read_ready()
651 }
652}
653
624impl<'d, T: Instance + 'd> embedded_io_async::BufRead for BufferedUart<'d, T> { 654impl<'d, T: Instance + 'd> embedded_io_async::BufRead for BufferedUart<'d, T> {
625 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { 655 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
626 BufferedUartRx::<'d, T>::fill_buf().await 656 BufferedUartRx::<'d, T>::fill_buf().await
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index 30ece15bd..aba4b792a 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -7,7 +7,7 @@ use atomic_polyfill::{AtomicU16, Ordering};
7use embassy_futures::select::{select, Either}; 7use embassy_futures::select::{select, Either};
8use embassy_hal_internal::{into_ref, PeripheralRef}; 8use embassy_hal_internal::{into_ref, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10use embassy_time::Timer; 10use embassy_time::{Delay, Timer};
11use pac::uart::regs::Uartris; 11use pac::uart::regs::Uartris;
12 12
13use crate::clocks::clk_peri_freq; 13use crate::clocks::clk_peri_freq;
@@ -247,7 +247,7 @@ impl<'d, T: Instance> UartTx<'d, T, Async> {
247 }); 247 });
248 // If we don't assign future to a variable, the data register pointer 248 // If we don't assign future to a variable, the data register pointer
249 // is held across an await and makes the future non-Send. 249 // is held across an await and makes the future non-Send.
250 crate::dma::write(ch, buffer, T::regs().uartdr().as_ptr() as *mut _, T::TX_DREQ) 250 crate::dma::write(ch, buffer, T::regs().uartdr().as_ptr() as *mut _, T::TX_DREQ.into())
251 }; 251 };
252 transfer.await; 252 transfer.await;
253 Ok(()) 253 Ok(())
@@ -422,7 +422,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
422 let transfer = unsafe { 422 let transfer = unsafe {
423 // If we don't assign future to a variable, the data register pointer 423 // If we don't assign future to a variable, the data register pointer
424 // is held across an await and makes the future non-Send. 424 // is held across an await and makes the future non-Send.
425 crate::dma::read(ch, T::regs().uartdr().as_ptr() as *const _, buffer, T::RX_DREQ) 425 crate::dma::read(ch, T::regs().uartdr().as_ptr() as *const _, buffer, T::RX_DREQ.into())
426 }; 426 };
427 427
428 // wait for either the transfer to complete or an error to happen. 428 // wait for either the transfer to complete or an error to happen.
@@ -490,6 +490,36 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
490 /// * The first call to `read_to_break()` will return `Ok(20)`. 490 /// * The first call to `read_to_break()` will return `Ok(20)`.
491 /// * The next call to `read_to_break()` will work as expected 491 /// * The next call to `read_to_break()` will work as expected
492 pub async fn read_to_break(&mut self, buffer: &mut [u8]) -> Result<usize, ReadToBreakError> { 492 pub async fn read_to_break(&mut self, buffer: &mut [u8]) -> Result<usize, ReadToBreakError> {
493 self.read_to_break_with_count(buffer, 0).await
494 }
495
496 /// Read from the UART, waiting for a line break as soon as at least `min_count` bytes have been read.
497 ///
498 /// We read until one of the following occurs:
499 ///
500 /// * We read `buffer.len()` bytes without a line break
501 /// * returns `Err(ReadToBreakError::MissingBreak(buffer.len()))`
502 /// * We read `n > min_count` bytes then a line break occurs
503 /// * returns `Ok(n)`
504 /// * We encounter some error OTHER than a line break
505 /// * returns `Err(ReadToBreakError::Other(error))`
506 ///
507 /// If a line break occurs before `min_count` bytes have been read, the break will be ignored and the read will continue
508 ///
509 /// **NOTE**: you MUST provide a buffer one byte larger than your largest expected
510 /// message to reliably detect the framing on one single call to `read_to_break()`.
511 ///
512 /// * If you expect a message of 20 bytes + line break, and provide a 20-byte buffer:
513 /// * The first call to `read_to_break()` will return `Err(ReadToBreakError::MissingBreak(20))`
514 /// * The next call to `read_to_break()` will immediately return `Ok(0)`, from the "stale" line break
515 /// * If you expect a message of 20 bytes + line break, and provide a 21-byte buffer:
516 /// * The first call to `read_to_break()` will return `Ok(20)`.
517 /// * The next call to `read_to_break()` will work as expected
518 pub async fn read_to_break_with_count(
519 &mut self,
520 buffer: &mut [u8],
521 min_count: usize,
522 ) -> Result<usize, ReadToBreakError> {
493 // clear error flags before we drain the fifo. errors that have accumulated 523 // clear error flags before we drain the fifo. errors that have accumulated
494 // in the flags will also be present in the fifo. 524 // in the flags will also be present in the fifo.
495 T::dma_state().rx_errs.store(0, Ordering::Relaxed); 525 T::dma_state().rx_errs.store(0, Ordering::Relaxed);
@@ -502,7 +532,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
502 532
503 // then drain the fifo. we need to read at most 32 bytes. errors that apply 533 // then drain the fifo. we need to read at most 32 bytes. errors that apply
504 // to fifo bytes will be reported directly. 534 // to fifo bytes will be reported directly.
505 let sbuffer = match { 535 let mut sbuffer = match {
506 let limit = buffer.len().min(32); 536 let limit = buffer.len().min(32);
507 self.drain_fifo(&mut buffer[0..limit]) 537 self.drain_fifo(&mut buffer[0..limit])
508 } { 538 } {
@@ -511,7 +541,13 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
511 // Drained (some/all of the fifo), no room left 541 // Drained (some/all of the fifo), no room left
512 Ok(len) => return Err(ReadToBreakError::MissingBreak(len)), 542 Ok(len) => return Err(ReadToBreakError::MissingBreak(len)),
513 // We got a break WHILE draining the FIFO, return what we did get before the break 543 // We got a break WHILE draining the FIFO, return what we did get before the break
514 Err((i, Error::Break)) => return Ok(i), 544 Err((len, Error::Break)) => {
545 if len < min_count && len < buffer.len() {
546 &mut buffer[len..]
547 } else {
548 return Ok(len);
549 }
550 }
515 // Some other error, just return the error 551 // Some other error, just return the error
516 Err((_i, e)) => return Err(ReadToBreakError::Other(e)), 552 Err((_i, e)) => return Err(ReadToBreakError::Other(e)),
517 }; 553 };
@@ -530,110 +566,123 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
530 reg.set_rxdmae(true); 566 reg.set_rxdmae(true);
531 reg.set_dmaonerr(true); 567 reg.set_dmaonerr(true);
532 }); 568 });
533 let transfer = unsafe {
534 // If we don't assign future to a variable, the data register pointer
535 // is held across an await and makes the future non-Send.
536 crate::dma::read(&mut ch, T::regs().uartdr().as_ptr() as *const _, sbuffer, T::RX_DREQ)
537 };
538
539 // wait for either the transfer to complete or an error to happen.
540 let transfer_result = select(
541 transfer,
542 poll_fn(|cx| {
543 T::dma_state().rx_err_waker.register(cx.waker());
544 match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) {
545 0 => Poll::Pending,
546 e => Poll::Ready(Uartris(e as u32)),
547 }
548 }),
549 )
550 .await;
551
552 // Figure out our error state
553 let errors = match transfer_result {
554 Either::First(()) => {
555 // We're here because the DMA finished, BUT if an error occurred on the LAST
556 // byte, then we may still need to grab the error state!
557 Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32)
558 }
559 Either::Second(e) => {
560 // We're here because we errored, which means this is the error that
561 // was problematic.
562 e
563 }
564 };
565 569
566 if errors.0 == 0 { 570 loop {
567 // No errors? That means we filled the buffer without a line break. 571 let transfer = unsafe {
568 // For THIS function, that's a problem. 572 // If we don't assign future to a variable, the data register pointer
569 return Err(ReadToBreakError::MissingBreak(buffer.len())); 573 // is held across an await and makes the future non-Send.
570 } else if errors.beris() { 574 crate::dma::read(
571 // We got a Line Break! By this point, we've finished/aborted the DMA 575 &mut ch,
572 // transaction, which means that we need to figure out where it left off 576 T::regs().uartdr().as_ptr() as *const _,
573 // by looking at the write_addr. 577 sbuffer,
574 // 578 T::RX_DREQ.into(),
575 // First, we do a sanity check to make sure the write value is within the 579 )
576 // range of DMA we just did. 580 };
577 let sval = buffer.as_ptr() as usize;
578 let eval = sval + buffer.len();
579
580 // This is the address where the DMA would write to next
581 let next_addr = ch.regs().write_addr().read() as usize;
582
583 // If we DON'T end up inside the range, something has gone really wrong.
584 // Note that it's okay that `eval` is one past the end of the slice, as
585 // this is where the write pointer will end up at the end of a full
586 // transfer.
587 if (next_addr < sval) || (next_addr > eval) {
588 unreachable!("UART DMA reported invalid `write_addr`");
589 }
590 581
591 let regs = T::regs(); 582 // wait for either the transfer to complete or an error to happen.
592 let all_full = next_addr == eval; 583 let transfer_result = select(
593 584 transfer,
594 // NOTE: This is off label usage of RSR! See the issue below for 585 poll_fn(|cx| {
595 // why I am not checking if there is an "extra" FIFO byte, and why 586 T::dma_state().rx_err_waker.register(cx.waker());
596 // I am checking RSR directly (it seems to report the status of the LAST 587 match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) {
597 // POPPED value, rather than the NEXT TO POP value like the datasheet 588 0 => Poll::Pending,
598 // suggests!) 589 e => Poll::Ready(Uartris(e as u32)),
599 // 590 }
600 // issue: https://github.com/raspberrypi/pico-feedback/issues/367 591 }),
601 let last_was_break = regs.uartrsr().read().be(); 592 )
602 593 .await;
603 return match (all_full, last_was_break) { 594
604 (true, true) | (false, _) => { 595 // Figure out our error state
605 // We got less than the full amount + a break, or the full amount 596 let errors = match transfer_result {
606 // and the last byte was a break. Subtract the break off by adding one to sval. 597 Either::First(()) => {
607 Ok(next_addr.saturating_sub(1 + sval)) 598 // We're here because the DMA finished, BUT if an error occurred on the LAST
599 // byte, then we may still need to grab the error state!
600 Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32)
608 } 601 }
609 (true, false) => { 602 Either::Second(e) => {
610 // We finished the whole DMA, and the last DMA'd byte was NOT a break 603 // We're here because we errored, which means this is the error that
611 // character. This is an error. 604 // was problematic.
612 // 605 e
613 // NOTE: we COULD potentially return Ok(buffer.len()) here, since we
614 // know a line break occured at SOME POINT after the DMA completed.
615 //
616 // However, we have no way of knowing if there was extra data BEFORE
617 // that line break, so instead return an Err to signal to the caller
618 // that there are "leftovers", and they'll catch the actual line break
619 // on the next call.
620 //
621 // Doing it like this also avoids racyness: now whether you finished
622 // the full read BEFORE the line break occurred or AFTER the line break
623 // occurs, you still get `MissingBreak(buffer.len())` instead of sometimes
624 // getting `Ok(buffer.len())` if you were "late enough" to observe the
625 // line break.
626 Err(ReadToBreakError::MissingBreak(buffer.len()))
627 } 606 }
628 }; 607 };
629 } else if errors.oeris() { 608
630 return Err(ReadToBreakError::Other(Error::Overrun)); 609 if errors.0 == 0 {
631 } else if errors.peris() { 610 // No errors? That means we filled the buffer without a line break.
632 return Err(ReadToBreakError::Other(Error::Parity)); 611 // For THIS function, that's a problem.
633 } else if errors.feris() { 612 return Err(ReadToBreakError::MissingBreak(buffer.len()));
634 return Err(ReadToBreakError::Other(Error::Framing)); 613 } else if errors.beris() {
614 // We got a Line Break! By this point, we've finished/aborted the DMA
615 // transaction, which means that we need to figure out where it left off
616 // by looking at the write_addr.
617 //
618 // First, we do a sanity check to make sure the write value is within the
619 // range of DMA we just did.
620 let sval = buffer.as_ptr() as usize;
621 let eval = sval + buffer.len();
622
623 // This is the address where the DMA would write to next
624 let next_addr = ch.regs().write_addr().read() as usize;
625
626 // If we DON'T end up inside the range, something has gone really wrong.
627 // Note that it's okay that `eval` is one past the end of the slice, as
628 // this is where the write pointer will end up at the end of a full
629 // transfer.
630 if (next_addr < sval) || (next_addr > eval) {
631 unreachable!("UART DMA reported invalid `write_addr`");
632 }
633
634 if (next_addr - sval) < min_count {
635 sbuffer = &mut buffer[(next_addr - sval)..];
636 continue;
637 }
638
639 let regs = T::regs();
640 let all_full = next_addr == eval;
641
642 // NOTE: This is off label usage of RSR! See the issue below for
643 // why I am not checking if there is an "extra" FIFO byte, and why
644 // I am checking RSR directly (it seems to report the status of the LAST
645 // POPPED value, rather than the NEXT TO POP value like the datasheet
646 // suggests!)
647 //
648 // issue: https://github.com/raspberrypi/pico-feedback/issues/367
649 let last_was_break = regs.uartrsr().read().be();
650
651 return match (all_full, last_was_break) {
652 (true, true) | (false, _) => {
653 // We got less than the full amount + a break, or the full amount
654 // and the last byte was a break. Subtract the break off by adding one to sval.
655 Ok(next_addr.saturating_sub(1 + sval))
656 }
657 (true, false) => {
658 // We finished the whole DMA, and the last DMA'd byte was NOT a break
659 // character. This is an error.
660 //
661 // NOTE: we COULD potentially return Ok(buffer.len()) here, since we
662 // know a line break occured at SOME POINT after the DMA completed.
663 //
664 // However, we have no way of knowing if there was extra data BEFORE
665 // that line break, so instead return an Err to signal to the caller
666 // that there are "leftovers", and they'll catch the actual line break
667 // on the next call.
668 //
669 // Doing it like this also avoids racyness: now whether you finished
670 // the full read BEFORE the line break occurred or AFTER the line break
671 // occurs, you still get `MissingBreak(buffer.len())` instead of sometimes
672 // getting `Ok(buffer.len())` if you were "late enough" to observe the
673 // line break.
674 Err(ReadToBreakError::MissingBreak(buffer.len()))
675 }
676 };
677 } else if errors.oeris() {
678 return Err(ReadToBreakError::Other(Error::Overrun));
679 } else if errors.peris() {
680 return Err(ReadToBreakError::Other(Error::Parity));
681 } else if errors.feris() {
682 return Err(ReadToBreakError::Other(Error::Framing));
683 }
684 unreachable!("unrecognized rx error");
635 } 685 }
636 unreachable!("unrecognized rx error");
637 } 686 }
638} 687}
639 688
@@ -786,26 +835,50 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
786 ) { 835 ) {
787 let r = T::regs(); 836 let r = T::regs();
788 if let Some(pin) = &tx { 837 if let Some(pin) = &tx {
838 let funcsel = {
839 let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8;
840 if (pin_number % 4) == 0 {
841 2
842 } else {
843 11
844 }
845 };
789 pin.gpio().ctrl().write(|w| { 846 pin.gpio().ctrl().write(|w| {
790 w.set_funcsel(2); 847 w.set_funcsel(funcsel);
791 w.set_outover(if config.invert_tx { 848 w.set_outover(if config.invert_tx {
792 Outover::INVERT 849 Outover::INVERT
793 } else { 850 } else {
794 Outover::NORMAL 851 Outover::NORMAL
795 }); 852 });
796 }); 853 });
797 pin.pad_ctrl().write(|w| w.set_ie(true)); 854 pin.pad_ctrl().write(|w| {
855 #[cfg(feature = "_rp235x")]
856 w.set_iso(false);
857 w.set_ie(true);
858 });
798 } 859 }
799 if let Some(pin) = &rx { 860 if let Some(pin) = &rx {
861 let funcsel = {
862 let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8;
863 if ((pin_number - 1) % 4) == 0 {
864 2
865 } else {
866 11
867 }
868 };
800 pin.gpio().ctrl().write(|w| { 869 pin.gpio().ctrl().write(|w| {
801 w.set_funcsel(2); 870 w.set_funcsel(funcsel);
802 w.set_inover(if config.invert_rx { 871 w.set_inover(if config.invert_rx {
803 Inover::INVERT 872 Inover::INVERT
804 } else { 873 } else {
805 Inover::NORMAL 874 Inover::NORMAL
806 }); 875 });
807 }); 876 });
808 pin.pad_ctrl().write(|w| w.set_ie(true)); 877 pin.pad_ctrl().write(|w| {
878 #[cfg(feature = "_rp235x")]
879 w.set_iso(false);
880 w.set_ie(true);
881 });
809 } 882 }
810 if let Some(pin) = &cts { 883 if let Some(pin) = &cts {
811 pin.gpio().ctrl().write(|w| { 884 pin.gpio().ctrl().write(|w| {
@@ -816,7 +889,11 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
816 Inover::NORMAL 889 Inover::NORMAL
817 }); 890 });
818 }); 891 });
819 pin.pad_ctrl().write(|w| w.set_ie(true)); 892 pin.pad_ctrl().write(|w| {
893 #[cfg(feature = "_rp235x")]
894 w.set_iso(false);
895 w.set_ie(true);
896 });
820 } 897 }
821 if let Some(pin) = &rts { 898 if let Some(pin) = &rts {
822 pin.gpio().ctrl().write(|w| { 899 pin.gpio().ctrl().write(|w| {
@@ -827,7 +904,11 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
827 Outover::NORMAL 904 Outover::NORMAL
828 }); 905 });
829 }); 906 });
830 pin.pad_ctrl().write(|w| w.set_ie(true)); 907 pin.pad_ctrl().write(|w| {
908 #[cfg(feature = "_rp235x")]
909 w.set_iso(false);
910 w.set_ie(true);
911 });
831 } 912 }
832 913
833 Self::set_baudrate_inner(config.baudrate); 914 Self::set_baudrate_inner(config.baudrate);
@@ -860,6 +941,56 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
860 }); 941 });
861 } 942 }
862 943
944 fn lcr_modify<R>(f: impl FnOnce(&mut crate::pac::uart::regs::UartlcrH) -> R) -> R {
945 let r = T::regs();
946
947 // Notes from PL011 reference manual:
948 //
949 // - Before writing the LCR, if the UART is enabled it needs to be
950 // disabled and any current TX + RX activity has to be completed
951 //
952 // - There is a BUSY flag which waits for the current TX char, but this is
953 // OR'd with TX FIFO !FULL, so not usable when FIFOs are enabled and
954 // potentially nonempty
955 //
956 // - FIFOs can't be set to disabled whilst a character is in progress
957 // (else "FIFO integrity is not guaranteed")
958 //
959 // Combination of these means there is no general way to halt and poll for
960 // end of TX character, if FIFOs may be enabled. Either way, there is no
961 // way to poll for end of RX character.
962 //
963 // So, insert a 15 Baud period delay before changing the settings.
964 // 15 Baud is comfortably higher than start + max data + parity + stop.
965 // Anything else would require API changes to permit a non-enabled UART
966 // state after init() where settings can be changed safely.
967 let clk_base = crate::clocks::clk_peri_freq();
968
969 let cr = r.uartcr().read();
970 if cr.uarten() {
971 r.uartcr().modify(|w| {
972 w.set_uarten(false);
973 w.set_txe(false);
974 w.set_rxe(false);
975 });
976
977 // Note: Maximise precision here. Show working, the compiler will mop this up.
978 // Create a 16.6 fixed-point fractional division ratio; then scale to 32-bits.
979 let mut brdiv_ratio = 64 * r.uartibrd().read().0 + r.uartfbrd().read().0;
980 brdiv_ratio <<= 10;
981 // 3662 is ~(15 * 244.14) where 244.14 is 16e6 / 2^16
982 let scaled_freq = clk_base / 3662;
983 let wait_time_us = brdiv_ratio / scaled_freq;
984 embedded_hal_1::delay::DelayNs::delay_us(&mut Delay, wait_time_us);
985 }
986
987 let res = r.uartlcr_h().modify(f);
988
989 r.uartcr().write_value(cr);
990
991 res
992 }
993
863 /// sets baudrate on runtime 994 /// sets baudrate on runtime
864 pub fn set_baudrate(&mut self, baudrate: u32) { 995 pub fn set_baudrate(&mut self, baudrate: u32) {
865 Self::set_baudrate_inner(baudrate); 996 Self::set_baudrate_inner(baudrate);
@@ -886,9 +1017,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
886 r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd)); 1017 r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
887 r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd)); 1018 r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
888 1019
889 // PL011 needs a (dummy) line control register write to latch in the 1020 Self::lcr_modify(|_| {});
890 // divisors. We don't want to actually change LCR contents here.
891 r.uartlcr_h().modify(|_| {});
892 } 1021 }
893} 1022}
894 1023
@@ -923,6 +1052,13 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
923 pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) { 1052 pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) {
924 (self.tx, self.rx) 1053 (self.tx, self.rx)
925 } 1054 }
1055
1056 /// Split the Uart into a transmitter and receiver by mutable reference,
1057 /// which is particularly useful when having two tasks correlating to
1058 /// transmitting and receiving.
1059 pub fn split_ref(&mut self) -> (&mut UartTx<'d, T, M>, &mut UartRx<'d, T, M>) {
1060 (&mut self.tx, &mut self.rx)
1061 }
926} 1062}
927 1063
928impl<'d, T: Instance> Uart<'d, T, Async> { 1064impl<'d, T: Instance> Uart<'d, T, Async> {
@@ -942,6 +1078,17 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
942 pub async fn read_to_break<'a>(&mut self, buf: &'a mut [u8]) -> Result<usize, ReadToBreakError> { 1078 pub async fn read_to_break<'a>(&mut self, buf: &'a mut [u8]) -> Result<usize, ReadToBreakError> {
943 self.rx.read_to_break(buf).await 1079 self.rx.read_to_break(buf).await
944 } 1080 }
1081
1082 /// Read until the buffer is full or a line break occurs after at least `min_count` bytes have been read.
1083 ///
1084 /// See [`UartRx::read_to_break_with_count()`] for more details
1085 pub async fn read_to_break_with_count<'a>(
1086 &mut self,
1087 buf: &'a mut [u8],
1088 min_count: usize,
1089 ) -> Result<usize, ReadToBreakError> {
1090 self.rx.read_to_break_with_count(buf, min_count).await
1091 }
945} 1092}
946 1093
947impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> { 1094impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> {
@@ -1222,3 +1369,92 @@ impl_pin!(PIN_26, UART1, CtsPin);
1222impl_pin!(PIN_27, UART1, RtsPin); 1369impl_pin!(PIN_27, UART1, RtsPin);
1223impl_pin!(PIN_28, UART0, TxPin); 1370impl_pin!(PIN_28, UART0, TxPin);
1224impl_pin!(PIN_29, UART0, RxPin); 1371impl_pin!(PIN_29, UART0, RxPin);
1372
1373// Additional functions added by all 2350s
1374#[cfg(feature = "_rp235x")]
1375impl_pin!(PIN_2, UART0, TxPin);
1376#[cfg(feature = "_rp235x")]
1377impl_pin!(PIN_3, UART0, RxPin);
1378#[cfg(feature = "_rp235x")]
1379impl_pin!(PIN_6, UART1, TxPin);
1380#[cfg(feature = "_rp235x")]
1381impl_pin!(PIN_7, UART1, RxPin);
1382#[cfg(feature = "_rp235x")]
1383impl_pin!(PIN_10, UART1, TxPin);
1384#[cfg(feature = "_rp235x")]
1385impl_pin!(PIN_11, UART1, RxPin);
1386#[cfg(feature = "_rp235x")]
1387impl_pin!(PIN_14, UART0, TxPin);
1388#[cfg(feature = "_rp235x")]
1389impl_pin!(PIN_15, UART0, RxPin);
1390#[cfg(feature = "_rp235x")]
1391impl_pin!(PIN_18, UART0, TxPin);
1392#[cfg(feature = "_rp235x")]
1393impl_pin!(PIN_19, UART0, RxPin);
1394#[cfg(feature = "_rp235x")]
1395impl_pin!(PIN_22, UART1, TxPin);
1396#[cfg(feature = "_rp235x")]
1397impl_pin!(PIN_23, UART1, RxPin);
1398#[cfg(feature = "_rp235x")]
1399impl_pin!(PIN_26, UART1, TxPin);
1400#[cfg(feature = "_rp235x")]
1401impl_pin!(PIN_27, UART1, RxPin);
1402
1403// Additional pins added by larger 2350 packages.
1404#[cfg(feature = "rp235xb")]
1405impl_pin!(PIN_30, UART0, CtsPin);
1406#[cfg(feature = "rp235xb")]
1407impl_pin!(PIN_31, UART0, RtsPin);
1408#[cfg(feature = "rp235xb")]
1409impl_pin!(PIN_32, UART0, TxPin);
1410#[cfg(feature = "rp235xb")]
1411impl_pin!(PIN_33, UART0, RxPin);
1412#[cfg(feature = "rp235xb")]
1413impl_pin!(PIN_34, UART0, CtsPin);
1414#[cfg(feature = "rp235xb")]
1415impl_pin!(PIN_35, UART0, RtsPin);
1416#[cfg(feature = "rp235xb")]
1417impl_pin!(PIN_36, UART1, TxPin);
1418#[cfg(feature = "rp235xb")]
1419impl_pin!(PIN_37, UART1, RxPin);
1420#[cfg(feature = "rp235xb")]
1421impl_pin!(PIN_38, UART1, CtsPin);
1422#[cfg(feature = "rp235xb")]
1423impl_pin!(PIN_39, UART1, RtsPin);
1424#[cfg(feature = "rp235xb")]
1425impl_pin!(PIN_40, UART1, TxPin);
1426#[cfg(feature = "rp235xb")]
1427impl_pin!(PIN_41, UART1, RxPin);
1428#[cfg(feature = "rp235xb")]
1429impl_pin!(PIN_42, UART1, CtsPin);
1430#[cfg(feature = "rp235xb")]
1431impl_pin!(PIN_43, UART1, RtsPin);
1432#[cfg(feature = "rp235xb")]
1433impl_pin!(PIN_44, UART0, TxPin);
1434#[cfg(feature = "rp235xb")]
1435impl_pin!(PIN_45, UART0, RxPin);
1436#[cfg(feature = "rp235xb")]
1437impl_pin!(PIN_46, UART0, CtsPin);
1438#[cfg(feature = "rp235xb")]
1439impl_pin!(PIN_47, UART0, RtsPin);
1440
1441#[cfg(feature = "rp235xb")]
1442impl_pin!(PIN_30, UART0, TxPin);
1443#[cfg(feature = "rp235xb")]
1444impl_pin!(PIN_31, UART0, RxPin);
1445#[cfg(feature = "rp235xb")]
1446impl_pin!(PIN_34, UART0, TxPin);
1447#[cfg(feature = "rp235xb")]
1448impl_pin!(PIN_35, UART0, RxPin);
1449#[cfg(feature = "rp235xb")]
1450impl_pin!(PIN_38, UART1, TxPin);
1451#[cfg(feature = "rp235xb")]
1452impl_pin!(PIN_39, UART1, RxPin);
1453#[cfg(feature = "rp235xb")]
1454impl_pin!(PIN_42, UART1, TxPin);
1455#[cfg(feature = "rp235xb")]
1456impl_pin!(PIN_43, UART1, RxPin);
1457#[cfg(feature = "rp235xb")]
1458impl_pin!(PIN_46, UART0, TxPin);
1459#[cfg(feature = "rp235xb")]
1460impl_pin!(PIN_47, UART0, RxPin);
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index 512271ae4..20ef881f9 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -28,10 +28,10 @@ pub trait Instance: SealedInstance + 'static {
28 28
29impl crate::usb::SealedInstance for peripherals::USB { 29impl crate::usb::SealedInstance for peripherals::USB {
30 fn regs() -> pac::usb::Usb { 30 fn regs() -> pac::usb::Usb {
31 pac::USBCTRL_REGS 31 pac::USB
32 } 32 }
33 fn dpram() -> crate::pac::usb_dpram::UsbDpram { 33 fn dpram() -> crate::pac::usb_dpram::UsbDpram {
34 pac::USBCTRL_DPRAM 34 pac::USB_DPRAM
35 } 35 }
36} 36}
37 37
@@ -41,7 +41,7 @@ impl crate::usb::Instance for peripherals::USB {
41 41
42const EP_COUNT: usize = 16; 42const EP_COUNT: usize = 16;
43const EP_MEMORY_SIZE: usize = 4096; 43const EP_MEMORY_SIZE: usize = 4096;
44const EP_MEMORY: *mut u8 = pac::USBCTRL_DPRAM.as_ptr() as *mut u8; 44const EP_MEMORY: *mut u8 = pac::USB_DPRAM.as_ptr() as *mut u8;
45 45
46const NEW_AW: AtomicWaker = AtomicWaker::new(); 46const NEW_AW: AtomicWaker = AtomicWaker::new();
47static BUS_WAKER: AtomicWaker = NEW_AW; 47static BUS_WAKER: AtomicWaker = NEW_AW;
diff --git a/embassy-rp/src/watchdog.rs b/embassy-rp/src/watchdog.rs
index 229a306fe..edd48e0e0 100644
--- a/embassy-rp/src/watchdog.rs
+++ b/embassy-rp/src/watchdog.rs
@@ -34,6 +34,7 @@ impl Watchdog {
34 /// 34 ///
35 /// * `cycles` - Total number of tick cycles before the next tick is generated. 35 /// * `cycles` - Total number of tick cycles before the next tick is generated.
36 /// It is expected to be the frequency in MHz of clk_ref. 36 /// It is expected to be the frequency in MHz of clk_ref.
37 #[cfg(feature = "rp2040")]
37 pub fn enable_tick_generation(&mut self, cycles: u8) { 38 pub fn enable_tick_generation(&mut self, cycles: u8) {
38 let watchdog = pac::WATCHDOG; 39 let watchdog = pac::WATCHDOG;
39 watchdog.tick().write(|w| { 40 watchdog.tick().write(|w| {
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index 307b948c1..54dfd39a6 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -21,10 +21,10 @@ features = ["stm32wb55rg"]
21[dependencies] 21[dependencies]
22embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } 22embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" }
23embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 23embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
24embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true } 24embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true }
25embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 25embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
26embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" } 26embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal" }
27embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } 27embassy-embedded-hal = { version = "0.2.0", path = "../embassy-embedded-hal" }
28embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true } 28embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true }
29 29
30defmt = { version = "0.3", optional = true } 30defmt = { version = "0.3", optional = true }
diff --git a/embassy-stm32-wpan/src/fmt.rs b/embassy-stm32-wpan/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-stm32-wpan/src/fmt.rs
+++ b/embassy-stm32-wpan/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-stm32-wpan/src/mac/commands.rs b/embassy-stm32-wpan/src/mac/commands.rs
index 8f6dcbbbc..c97c609c3 100644
--- a/embassy-stm32-wpan/src/mac/commands.rs
+++ b/embassy-stm32-wpan/src/mac/commands.rs
@@ -1,3 +1,5 @@
1#![allow(unused)]
2
1use core::{mem, slice}; 3use core::{mem, slice};
2 4
3use super::opcodes::OpcodeM4ToM0; 5use super::opcodes::OpcodeM4ToM0;
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 523bacb11..3c6484c96 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -43,15 +43,15 @@ rustdoc-args = ["--cfg", "docsrs"]
43 43
44[dependencies] 44[dependencies]
45embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 45embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
46embassy-time = { version = "0.3.1", path = "../embassy-time", optional = true } 46embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true }
47embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } 47embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true }
48embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 48embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
49embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } 49embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] }
50embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } 50embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" }
51embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } 51embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
52embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } 52embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" }
53embassy-usb-synopsys-otg = {version = "0.1.0", path = "../embassy-usb-synopsys-otg" } 53embassy-usb-synopsys-otg = {version = "0.1.0", path = "../embassy-usb-synopsys-otg" }
54embassy-executor = { version = "0.5.0", path = "../embassy-executor", optional = true } 54embassy-executor = { version = "0.6.0", path = "../embassy-executor", optional = true }
55 55
56embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 56embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
57embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 57embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
@@ -72,7 +72,7 @@ rand_core = "0.6.3"
72sdio-host = "0.5.0" 72sdio-host = "0.5.0"
73critical-section = "1.1" 73critical-section = "1.1"
74#stm32-metapac = { version = "15" } 74#stm32-metapac = { version = "15" }
75stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e0cfd165fd8fffaa0df66a35eeca83b228496645" } 75stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364" }
76 76
77vcell = "0.1.3" 77vcell = "0.1.3"
78nb = "1.0.0" 78nb = "1.0.0"
@@ -80,7 +80,7 @@ stm32-fmc = "0.3.0"
80cfg-if = "1.0.0" 80cfg-if = "1.0.0"
81embedded-io = { version = "0.6.0" } 81embedded-io = { version = "0.6.0" }
82embedded-io-async = { version = "0.6.1" } 82embedded-io-async = { version = "0.6.1" }
83chrono = { version = "^0.4", default-features = false, optional = true} 83chrono = { version = "^0.4", default-features = false, optional = true }
84bit_field = "0.10.2" 84bit_field = "0.10.2"
85document-features = "0.2.7" 85document-features = "0.2.7"
86 86
@@ -88,6 +88,8 @@ static_assertions = { version = "1.1" }
88volatile-register = { version = "0.2.1" } 88volatile-register = { version = "0.2.1" }
89bitflags = "2.4.2" 89bitflags = "2.4.2"
90 90
91block-device-driver = { version = "0.2" }
92aligned = "0.4.1"
91 93
92[dev-dependencies] 94[dev-dependencies]
93critical-section = { version = "1.1", features = ["std"] } 95critical-section = { version = "1.1", features = ["std"] }
@@ -97,7 +99,7 @@ proc-macro2 = "1.0.36"
97quote = "1.0.15" 99quote = "1.0.15"
98 100
99#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 101#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
100stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e0cfd165fd8fffaa0df66a35eeca83b228496645", default-features = false, features = ["metadata"] } 102stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364", default-features = false, features = ["metadata"] }
101 103
102[features] 104[features]
103default = ["rt"] 105default = ["rt"]
@@ -181,6 +183,9 @@ split-pc3 = ["_split-pins-enabled"]
181## internal use only 183## internal use only
182_split-pins-enabled = [] 184_split-pins-enabled = []
183 185
186## internal use only
187_dual-core = []
188
184#! ## Chip-selection features 189#! ## Chip-selection features
185#! Select your chip by specifying the model as a feature, e.g. `stm32c011d6`. 190#! Select your chip by specifying the model as a feature, e.g. `stm32c011d6`.
186#! Check the `Cargo.toml` for the latest list of supported chips. 191#! Check the `Cargo.toml` for the latest list of supported chips.
@@ -1004,40 +1009,40 @@ stm32h743xg = [ "stm32-metapac/stm32h743xg" ]
1004stm32h743xi = [ "stm32-metapac/stm32h743xi" ] 1009stm32h743xi = [ "stm32-metapac/stm32h743xi" ]
1005stm32h743zg = [ "stm32-metapac/stm32h743zg" ] 1010stm32h743zg = [ "stm32-metapac/stm32h743zg" ]
1006stm32h743zi = [ "stm32-metapac/stm32h743zi" ] 1011stm32h743zi = [ "stm32-metapac/stm32h743zi" ]
1007stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7" ] 1012stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7", "_dual-core" ]
1008stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4" ] 1013stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4", "_dual-core" ]
1009stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7" ] 1014stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7", "_dual-core" ]
1010stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4" ] 1015stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4", "_dual-core" ]
1011stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7" ] 1016stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7", "_dual-core" ]
1012stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4" ] 1017stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4", "_dual-core" ]
1013stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7" ] 1018stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7", "_dual-core" ]
1014stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4" ] 1019stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4", "_dual-core" ]
1015stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7" ] 1020stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7", "_dual-core" ]
1016stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4" ] 1021stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4", "_dual-core" ]
1017stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7" ] 1022stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7", "_dual-core" ]
1018stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4" ] 1023stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4", "_dual-core" ]
1019stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7" ] 1024stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7", "_dual-core" ]
1020stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4" ] 1025stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4", "_dual-core" ]
1021stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7" ] 1026stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7", "_dual-core" ]
1022stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4" ] 1027stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4", "_dual-core" ]
1023stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7" ] 1028stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7", "_dual-core" ]
1024stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4" ] 1029stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4", "_dual-core" ]
1025stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7" ] 1030stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7", "_dual-core" ]
1026stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4" ] 1031stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4", "_dual-core" ]
1027stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7" ] 1032stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7", "_dual-core" ]
1028stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4" ] 1033stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4", "_dual-core" ]
1029stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7" ] 1034stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7", "_dual-core" ]
1030stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4" ] 1035stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4", "_dual-core" ]
1031stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7" ] 1036stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7", "_dual-core" ]
1032stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4" ] 1037stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4", "_dual-core" ]
1033stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7" ] 1038stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7", "_dual-core" ]
1034stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4" ] 1039stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4", "_dual-core" ]
1035stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7" ] 1040stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7", "_dual-core" ]
1036stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4" ] 1041stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4", "_dual-core" ]
1037stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7" ] 1042stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7", "_dual-core" ]
1038stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4" ] 1043stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4", "_dual-core" ]
1039stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7" ] 1044stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7", "_dual-core" ]
1040stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4" ] 1045stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4", "_dual-core" ]
1041stm32h750ib = [ "stm32-metapac/stm32h750ib" ] 1046stm32h750ib = [ "stm32-metapac/stm32h750ib" ]
1042stm32h750vb = [ "stm32-metapac/stm32h750vb" ] 1047stm32h750vb = [ "stm32-metapac/stm32h750vb" ]
1043stm32h750xb = [ "stm32-metapac/stm32h750xb" ] 1048stm32h750xb = [ "stm32-metapac/stm32h750xb" ]
@@ -1048,24 +1053,24 @@ stm32h753ii = [ "stm32-metapac/stm32h753ii" ]
1048stm32h753vi = [ "stm32-metapac/stm32h753vi" ] 1053stm32h753vi = [ "stm32-metapac/stm32h753vi" ]
1049stm32h753xi = [ "stm32-metapac/stm32h753xi" ] 1054stm32h753xi = [ "stm32-metapac/stm32h753xi" ]
1050stm32h753zi = [ "stm32-metapac/stm32h753zi" ] 1055stm32h753zi = [ "stm32-metapac/stm32h753zi" ]
1051stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7" ] 1056stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7", "_dual-core" ]
1052stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4" ] 1057stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4", "_dual-core" ]
1053stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7" ] 1058stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7", "_dual-core" ]
1054stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4" ] 1059stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4", "_dual-core" ]
1055stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7" ] 1060stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7", "_dual-core" ]
1056stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4" ] 1061stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4", "_dual-core" ]
1057stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7" ] 1062stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7", "_dual-core" ]
1058stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4" ] 1063stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4", "_dual-core" ]
1059stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7" ] 1064stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7", "_dual-core" ]
1060stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4" ] 1065stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4", "_dual-core" ]
1061stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7" ] 1066stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7", "_dual-core" ]
1062stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4" ] 1067stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4", "_dual-core" ]
1063stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7" ] 1068stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7", "_dual-core" ]
1064stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4" ] 1069stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4", "_dual-core" ]
1065stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7" ] 1070stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7", "_dual-core" ]
1066stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4" ] 1071stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4", "_dual-core" ]
1067stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7" ] 1072stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7", "_dual-core" ]
1068stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4" ] 1073stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4", "_dual-core" ]
1069stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag" ] 1074stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag" ]
1070stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai" ] 1075stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai" ]
1071stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig" ] 1076stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig" ]
@@ -1598,14 +1603,14 @@ stm32wba55he = [ "stm32-metapac/stm32wba55he" ]
1598stm32wba55hg = [ "stm32-metapac/stm32wba55hg" ] 1603stm32wba55hg = [ "stm32-metapac/stm32wba55hg" ]
1599stm32wba55ue = [ "stm32-metapac/stm32wba55ue" ] 1604stm32wba55ue = [ "stm32-metapac/stm32wba55ue" ]
1600stm32wba55ug = [ "stm32-metapac/stm32wba55ug" ] 1605stm32wba55ug = [ "stm32-metapac/stm32wba55ug" ]
1601stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4" ] 1606stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4", "_dual-core" ]
1602stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p" ] 1607stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p", "_dual-core" ]
1603stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4" ] 1608stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4", "_dual-core" ]
1604stm32wl54jc-cm0p = [ "stm32-metapac/stm32wl54jc-cm0p" ] 1609stm32wl54jc-cm0p = [ "stm32-metapac/stm32wl54jc-cm0p", "_dual-core" ]
1605stm32wl55cc-cm4 = [ "stm32-metapac/stm32wl55cc-cm4" ] 1610stm32wl55cc-cm4 = [ "stm32-metapac/stm32wl55cc-cm4", "_dual-core" ]
1606stm32wl55cc-cm0p = [ "stm32-metapac/stm32wl55cc-cm0p" ] 1611stm32wl55cc-cm0p = [ "stm32-metapac/stm32wl55cc-cm0p", "_dual-core" ]
1607stm32wl55jc-cm4 = [ "stm32-metapac/stm32wl55jc-cm4" ] 1612stm32wl55jc-cm4 = [ "stm32-metapac/stm32wl55jc-cm4", "_dual-core" ]
1608stm32wl55jc-cm0p = [ "stm32-metapac/stm32wl55jc-cm0p" ] 1613stm32wl55jc-cm0p = [ "stm32-metapac/stm32wl55jc-cm0p", "_dual-core" ]
1609stm32wle4c8 = [ "stm32-metapac/stm32wle4c8" ] 1614stm32wle4c8 = [ "stm32-metapac/stm32wle4c8" ]
1610stm32wle4cb = [ "stm32-metapac/stm32wle4cb" ] 1615stm32wle4cb = [ "stm32-metapac/stm32wle4cb" ]
1611stm32wle4cc = [ "stm32-metapac/stm32wle4cc" ] 1616stm32wle4cc = [ "stm32-metapac/stm32wle4cc" ]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 8457e3a13..19cf193d9 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -480,7 +480,7 @@ fn main() {
480 self.clock_names.insert(name.to_ascii_lowercase()); 480 self.clock_names.insert(name.to_ascii_lowercase());
481 quote!(unsafe { 481 quote!(unsafe {
482 unwrap!( 482 unwrap!(
483 crate::rcc::get_freqs().#clock_name, 483 crate::rcc::get_freqs().#clock_name.to_hertz(),
484 "peripheral '{}' is configured to use the '{}' clock, which is not running. \ 484 "peripheral '{}' is configured to use the '{}' clock, which is not running. \
485 Either enable it in 'config.rcc' or change 'config.rcc.mux' to use another clock", 485 Either enable it in 'config.rcc' or change 'config.rcc.mux' to use another clock",
486 #peripheral, 486 #peripheral,
@@ -713,9 +713,10 @@ fn main() {
713 g.extend(quote! { 713 g.extend(quote! {
714 #[derive(Clone, Copy, Debug)] 714 #[derive(Clone, Copy, Debug)]
715 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 715 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
716 #[repr(C)]
716 pub struct Clocks { 717 pub struct Clocks {
717 #( 718 #(
718 pub #clock_idents: Option<crate::time::Hertz>, 719 pub #clock_idents: crate::time::MaybeHertz,
719 )* 720 )*
720 } 721 }
721 }); 722 });
@@ -732,7 +733,7 @@ fn main() {
732 $($(#[$m])* $k: $v,)* 733 $($(#[$m])* $k: $v,)*
733 }; 734 };
734 crate::rcc::set_freqs(crate::rcc::Clocks { 735 crate::rcc::set_freqs(crate::rcc::Clocks {
735 #( #clock_idents: all.#clock_idents, )* 736 #( #clock_idents: all.#clock_idents.into(), )*
736 }); 737 });
737 } 738 }
738 }; 739 };
@@ -1014,6 +1015,9 @@ fn main() {
1014 (("hrtim", "CHE2"), quote!(crate::hrtim::ChannelEComplementaryPin)), 1015 (("hrtim", "CHE2"), quote!(crate::hrtim::ChannelEComplementaryPin)),
1015 (("hrtim", "CHF1"), quote!(crate::hrtim::ChannelFPin)), 1016 (("hrtim", "CHF1"), quote!(crate::hrtim::ChannelFPin)),
1016 (("hrtim", "CHF2"), quote!(crate::hrtim::ChannelFComplementaryPin)), 1017 (("hrtim", "CHF2"), quote!(crate::hrtim::ChannelFComplementaryPin)),
1018 (("lptim", "CH1"), quote!(crate::lptim::Channel1Pin)),
1019 (("lptim", "CH2"), quote!(crate::lptim::Channel2Pin)),
1020 (("lptim", "OUT"), quote!(crate::lptim::OutputPin)),
1017 (("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)), 1021 (("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)),
1018 (("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)), 1022 (("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)),
1019 (("sdmmc", "D0"), quote!(crate::sdmmc::D0Pin)), 1023 (("sdmmc", "D0"), quote!(crate::sdmmc::D0Pin)),
@@ -1493,6 +1497,36 @@ fn main() {
1493 .flat_map(|p| &p.registers) 1497 .flat_map(|p| &p.registers)
1494 .any(|p| p.kind == "dmamux"); 1498 .any(|p| p.kind == "dmamux");
1495 1499
1500 let mut dma_irqs: BTreeMap<&str, Vec<String>> = BTreeMap::new();
1501
1502 for p in METADATA.peripherals {
1503 if let Some(r) = &p.registers {
1504 if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" || r.kind == "lpdma" {
1505 for irq in p.interrupts {
1506 let ch_name = format!("{}_{}", p.name, irq.signal);
1507 let ch = METADATA.dma_channels.iter().find(|c| c.name == ch_name).unwrap();
1508
1509 // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it.
1510 if has_dmamux && ch.dmamux.is_none() {
1511 continue;
1512 }
1513
1514 dma_irqs.entry(irq.interrupt).or_default().push(ch_name);
1515 }
1516 }
1517 }
1518 }
1519
1520 #[cfg(feature = "_dual-core")]
1521 let mut dma_ch_to_irq: BTreeMap<&str, Vec<String>> = BTreeMap::new();
1522
1523 #[cfg(feature = "_dual-core")]
1524 for (irq, channels) in &dma_irqs {
1525 for channel in channels {
1526 dma_ch_to_irq.entry(channel).or_default().push(irq.to_string());
1527 }
1528 }
1529
1496 for (ch_idx, ch) in METADATA.dma_channels.iter().enumerate() { 1530 for (ch_idx, ch) in METADATA.dma_channels.iter().enumerate() {
1497 // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it. 1531 // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it.
1498 if has_dmamux && ch.dmamux.is_none() { 1532 if has_dmamux && ch.dmamux.is_none() {
@@ -1501,6 +1535,16 @@ fn main() {
1501 1535
1502 let name = format_ident!("{}", ch.name); 1536 let name = format_ident!("{}", ch.name);
1503 let idx = ch_idx as u8; 1537 let idx = ch_idx as u8;
1538 #[cfg(feature = "_dual-core")]
1539 let irq = {
1540 let irq_name = if let Some(x) = &dma_ch_to_irq.get(ch.name) {
1541 format_ident!("{}", x.get(0).unwrap())
1542 } else {
1543 panic!("failed to find dma interrupt")
1544 };
1545 quote!(crate::pac::Interrupt::#irq_name)
1546 };
1547
1504 g.extend(quote!(dma_channel_impl!(#name, #idx);)); 1548 g.extend(quote!(dma_channel_impl!(#name, #idx);));
1505 1549
1506 let dma = format_ident!("{}", ch.dma); 1550 let dma = format_ident!("{}", ch.dma);
@@ -1531,6 +1575,7 @@ fn main() {
1531 None => quote!(), 1575 None => quote!(),
1532 }; 1576 };
1533 1577
1578 #[cfg(not(feature = "_dual-core"))]
1534 dmas.extend(quote! { 1579 dmas.extend(quote! {
1535 crate::dma::ChannelInfo { 1580 crate::dma::ChannelInfo {
1536 dma: #dma_info, 1581 dma: #dma_info,
@@ -1538,31 +1583,20 @@ fn main() {
1538 #dmamux 1583 #dmamux
1539 }, 1584 },
1540 }); 1585 });
1586 #[cfg(feature = "_dual-core")]
1587 dmas.extend(quote! {
1588 crate::dma::ChannelInfo {
1589 dma: #dma_info,
1590 num: #ch_num,
1591 irq: #irq,
1592 #dmamux
1593 },
1594 });
1541 } 1595 }
1542 1596
1543 // ======== 1597 // ========
1544 // Generate DMA IRQs. 1598 // Generate DMA IRQs.
1545 1599
1546 let mut dma_irqs: BTreeMap<&str, Vec<String>> = BTreeMap::new();
1547
1548 for p in METADATA.peripherals {
1549 if let Some(r) = &p.registers {
1550 if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" {
1551 for irq in p.interrupts {
1552 let ch_name = format!("{}_{}", p.name, irq.signal);
1553 let ch = METADATA.dma_channels.iter().find(|c| c.name == ch_name).unwrap();
1554
1555 // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it.
1556 if has_dmamux && ch.dmamux.is_none() {
1557 continue;
1558 }
1559
1560 dma_irqs.entry(irq.interrupt).or_default().push(ch_name);
1561 }
1562 }
1563 }
1564 }
1565
1566 let dma_irqs: TokenStream = dma_irqs 1600 let dma_irqs: TokenStream = dma_irqs
1567 .iter() 1601 .iter()
1568 .map(|(irq, channels)| { 1602 .map(|(irq, channels)| {
diff --git a/embassy-stm32/build_common.rs b/embassy-stm32/build_common.rs
index 0487eb3c5..4f24e6d37 100644
--- a/embassy-stm32/build_common.rs
+++ b/embassy-stm32/build_common.rs
@@ -8,8 +8,6 @@
8 8
9use std::collections::HashSet; 9use std::collections::HashSet;
10use std::env; 10use std::env;
11use std::ffi::OsString;
12use std::process::Command;
13 11
14/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring 12/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
15/// them (`cargo:rust-check-cfg=cfg(X)`). 13/// them (`cargo:rust-check-cfg=cfg(X)`).
@@ -17,7 +15,6 @@ use std::process::Command;
17pub struct CfgSet { 15pub struct CfgSet {
18 enabled: HashSet<String>, 16 enabled: HashSet<String>,
19 declared: HashSet<String>, 17 declared: HashSet<String>,
20 emit_declared: bool,
21} 18}
22 19
23impl CfgSet { 20impl CfgSet {
@@ -25,7 +22,6 @@ impl CfgSet {
25 Self { 22 Self {
26 enabled: HashSet::new(), 23 enabled: HashSet::new(),
27 declared: HashSet::new(), 24 declared: HashSet::new(),
28 emit_declared: is_rustc_nightly(),
29 } 25 }
30 } 26 }
31 27
@@ -49,7 +45,7 @@ impl CfgSet {
49 /// 45 ///
50 /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid. 46 /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
51 pub fn declare(&mut self, cfg: impl AsRef<str>) { 47 pub fn declare(&mut self, cfg: impl AsRef<str>) {
52 if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared { 48 if self.declared.insert(cfg.as_ref().to_owned()) {
53 println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref()); 49 println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
54 } 50 }
55 } 51 }
@@ -69,21 +65,6 @@ impl CfgSet {
69 } 65 }
70} 66}
71 67
72fn is_rustc_nightly() -> bool {
73 if env::var_os("EMBASSY_FORCE_CHECK_CFG").is_some() {
74 return true;
75 }
76
77 let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
78
79 let output = Command::new(rustc)
80 .arg("--version")
81 .output()
82 .expect("failed to run `rustc --version`");
83
84 String::from_utf8_lossy(&output.stdout).contains("nightly")
85}
86
87/// Sets configs that describe the target platform. 68/// Sets configs that describe the target platform.
88pub fn set_target_cfgs(cfgs: &mut CfgSet) { 69pub fn set_target_cfgs(cfgs: &mut CfgSet) {
89 let target = env::var("TARGET").unwrap(); 70 let target = env::var("TARGET").unwrap();
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
index ac88c9742..0ebeb8a9e 100644
--- a/embassy-stm32/src/adc/f3.rs
+++ b/embassy-stm32/src/adc/f3.rs
@@ -42,7 +42,7 @@ impl<T: Instance> super::SealedAdcChannel<T> for Vref {
42impl Vref { 42impl Vref {
43 /// The value that vref would be if vdda was at 3300mv 43 /// The value that vref would be if vdda was at 3300mv
44 pub fn value(&self) -> u16 { 44 pub fn value(&self) -> u16 {
45 crate::pac::VREFINTCAL.data().read().value() 45 crate::pac::VREFINTCAL.data().read()
46 } 46 }
47} 47}
48 48
diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs
index 689c2871d..291a3861e 100644
--- a/embassy-stm32/src/adc/f3_v1_1.rs
+++ b/embassy-stm32/src/adc/f3_v1_1.rs
@@ -74,7 +74,7 @@ impl<T: Instance> super::SealedAdcChannel<T> for Vref<T> {
74impl<T: Instance> Vref<T> { 74impl<T: Instance> Vref<T> {
75 /// The value that vref would be if vdda was at 3000mv 75 /// The value that vref would be if vdda was at 3000mv
76 pub fn calibrated_value(&self) -> u16 { 76 pub fn calibrated_value(&self) -> u16 {
77 crate::pac::VREFINTCAL.data().read().value() 77 crate::pac::VREFINTCAL.data().read()
78 } 78 }
79 79
80 pub async fn calibrate(&mut self, adc: &mut Adc<'_, T>) -> Calibration { 80 pub async fn calibrate(&mut self, adc: &mut Adc<'_, T>) -> Calibration {
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
index c1e584f59..3e9ba8ae2 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -1,5 +1,9 @@
1#[allow(unused)] 1#[allow(unused)]
2#[cfg(stm32h7)]
2use pac::adc::vals::{Adcaldif, Difsel, Exten}; 3use pac::adc::vals::{Adcaldif, Difsel, Exten};
4#[allow(unused)]
5#[cfg(stm32g4)]
6use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs};
3use pac::adccommon::vals::Presc; 7use pac::adccommon::vals::Presc;
4 8
5use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime}; 9use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime};
@@ -228,6 +232,68 @@ impl<'d, T: Instance> Adc<'d, T> {
228 Vbat {} 232 Vbat {}
229 } 233 }
230 234
235 /// Enable differential channel.
236 /// Caution:
237 /// : When configuring the channel “i” in differential input mode, its negative input voltage VINN[i]
238 /// is connected to another channel. As a consequence, this channel is no longer usable in
239 /// single-ended mode or in differential mode and must never be configured to be converted.
240 /// Some channels are shared between ADC1/ADC2/ADC3/ADC4/ADC5: this can make the
241 /// channel on the other ADC unusable. The only exception is when ADC master and the slave
242 /// operate in interleaved mode.
243 #[cfg(stm32g4)]
244 pub fn set_differential_channel(&mut self, ch: usize, enable: bool) {
245 T::regs().cr().modify(|w| w.set_aden(false)); // disable adc
246 T::regs().difsel().modify(|w| {
247 w.set_difsel(
248 ch,
249 if enable {
250 Difsel::DIFFERENTIAL
251 } else {
252 Difsel::SINGLEENDED
253 },
254 );
255 });
256 T::regs().cr().modify(|w| w.set_aden(true));
257 }
258
259 #[cfg(stm32g4)]
260 pub fn set_differential(&mut self, channel: &mut impl AdcChannel<T>, enable: bool) {
261 self.set_differential_channel(channel.channel() as usize, enable);
262 }
263
264 /// Set oversampling shift.
265 #[cfg(stm32g4)]
266 pub fn set_oversampling_shift(&mut self, shift: u8) {
267 T::regs().cfgr2().modify(|reg| reg.set_ovss(shift));
268 }
269
270 /// Set oversampling ratio.
271 #[cfg(stm32g4)]
272 pub fn set_oversampling_ratio(&mut self, ratio: u8) {
273 T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio));
274 }
275
276 /// Enable oversampling in regular mode.
277 #[cfg(stm32g4)]
278 pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) {
279 T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode));
280 T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode));
281 T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
282 }
283
284 // Reads that are not implemented as INJECTED in "blocking_read"
285 // #[cfg(stm32g4)]
286 // pub fn enalble_injected_oversampling_mode(&mut self, enable: bool) {
287 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable));
288 // }
289
290 // #[cfg(stm32g4)]
291 // pub fn enable_oversampling_regular_injected_mode(&mut self, enable: bool) {
292 // // the regularoversampling mode is forced to resumed mode (ROVSM bit ignored),
293 // T::regs().cfgr2().modify(|reg| reg.set_rovse(enable));
294 // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable));
295 // }
296
231 /// Set the ADC sample time. 297 /// Set the ADC sample time.
232 pub fn set_sample_time(&mut self, sample_time: SampleTime) { 298 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
233 self.sample_time = sample_time; 299 self.sample_time = sample_time;
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 8ba586f5c..9bf840f7c 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -2,8 +2,9 @@
2 2
3#![macro_use] 3#![macro_use]
4#![allow(missing_docs)] // TODO 4#![allow(missing_docs)] // TODO
5#![cfg_attr(adc_f3_v2, allow(unused))]
5 6
6#[cfg(not(adc_f3_v2))] 7#[cfg(not(any(adc_f3_v2, adc_u5)))]
7#[cfg_attr(adc_f1, path = "f1.rs")] 8#[cfg_attr(adc_f1, path = "f1.rs")]
8#[cfg_attr(adc_f3, path = "f3.rs")] 9#[cfg_attr(adc_f3, path = "f3.rs")]
9#[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] 10#[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")]
@@ -19,13 +20,16 @@ mod _version;
19use core::marker::PhantomData; 20use core::marker::PhantomData;
20 21
21#[allow(unused)] 22#[allow(unused)]
22#[cfg(not(adc_f3_v2))] 23#[cfg(not(any(adc_f3_v2, adc_u5)))]
23pub use _version::*; 24pub use _version::*;
24#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] 25#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
25use embassy_sync::waitqueue::AtomicWaker; 26use embassy_sync::waitqueue::AtomicWaker;
26 27
27#[cfg(not(any(adc_f1, adc_f3_v2)))] 28#[cfg(not(any(adc_u5)))]
29pub use crate::pac::adc::vals;
30#[cfg(not(any(adc_f1, adc_f3_v2, adc_u5)))]
28pub use crate::pac::adc::vals::Res as Resolution; 31pub use crate::pac::adc::vals::Res as Resolution;
32#[cfg(not(any(adc_u5)))]
29pub use crate::pac::adc::vals::SampleTime; 33pub use crate::pac::adc::vals::SampleTime;
30use crate::peripherals; 34use crate::peripherals;
31 35
@@ -35,7 +39,7 @@ dma_trait!(RxDma, Instance);
35pub struct Adc<'d, T: Instance> { 39pub struct Adc<'d, T: Instance> {
36 #[allow(unused)] 40 #[allow(unused)]
37 adc: crate::PeripheralRef<'d, T>, 41 adc: crate::PeripheralRef<'d, T>,
38 #[cfg(not(any(adc_f3_v2, adc_f3_v1_1)))] 42 #[cfg(not(any(adc_f3_v2, adc_f3_v1_1, adc_u5)))]
39 sample_time: SampleTime, 43 sample_time: SampleTime,
40} 44}
41 45
@@ -56,7 +60,7 @@ impl State {
56trait SealedInstance { 60trait SealedInstance {
57 #[allow(unused)] 61 #[allow(unused)]
58 fn regs() -> crate::pac::adc::Adc; 62 fn regs() -> crate::pac::adc::Adc;
59 #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] 63 #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0, adc_u5)))]
60 #[allow(unused)] 64 #[allow(unused)]
61 fn common_regs() -> crate::pac::adccommon::AdcCommon; 65 fn common_regs() -> crate::pac::adccommon::AdcCommon;
62 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] 66 #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))]
@@ -78,7 +82,7 @@ pub(crate) fn blocking_delay_us(us: u32) {
78 embassy_time::block_for(embassy_time::Duration::from_micros(us as u64)); 82 embassy_time::block_for(embassy_time::Duration::from_micros(us as u64));
79 #[cfg(not(feature = "time"))] 83 #[cfg(not(feature = "time"))]
80 { 84 {
81 let freq = unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 as u64; 85 let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64;
82 let us = us as u64; 86 let us = us as u64;
83 let cycles = freq * us / 1_000_000; 87 let cycles = freq * us / 1_000_000;
84 cortex_m::asm::delay(cycles as u32); 88 cortex_m::asm::delay(cycles as u32);
@@ -164,7 +168,7 @@ foreach_adc!(
164 crate::pac::$inst 168 crate::pac::$inst
165 } 169 }
166 170
167 #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] 171 #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0, adc_u5)))]
168 fn common_regs() -> crate::pac::adccommon::AdcCommon { 172 fn common_regs() -> crate::pac::adccommon::AdcCommon {
169 return crate::pac::$common_inst 173 return crate::pac::$common_inst
170 } 174 }
@@ -201,7 +205,7 @@ macro_rules! impl_adc_pin {
201/// Get the maximum reading value for this resolution. 205/// Get the maximum reading value for this resolution.
202/// 206///
203/// This is `2**n - 1`. 207/// This is `2**n - 1`.
204#[cfg(not(any(adc_f1, adc_f3_v2)))] 208#[cfg(not(any(adc_f1, adc_f3_v2, adc_u5)))]
205pub const fn resolution_to_max_count(res: Resolution) -> u32 { 209pub const fn resolution_to_max_count(res: Resolution) -> u32 {
206 match res { 210 match res {
207 #[cfg(adc_v4)] 211 #[cfg(adc_v4)]
diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs
index 278c93ff4..baa4bee79 100644
--- a/embassy-stm32/src/can/bxcan/mod.rs
+++ b/embassy-stm32/src/can/bxcan/mod.rs
@@ -68,7 +68,6 @@ pub struct SceInterruptHandler<T: Instance> {
68 68
69impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterruptHandler<T> { 69impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterruptHandler<T> {
70 unsafe fn on_interrupt() { 70 unsafe fn on_interrupt() {
71 info!("sce irq");
72 let msr = T::regs().msr(); 71 let msr = T::regs().msr();
73 let msr_val = msr.read(); 72 let msr_val = msr.read();
74 73
@@ -76,9 +75,8 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup
76 msr.modify(|m| m.set_slaki(true)); 75 msr.modify(|m| m.set_slaki(true));
77 T::state().err_waker.wake(); 76 T::state().err_waker.wake();
78 } else if msr_val.erri() { 77 } else if msr_val.erri() {
79 info!("Error interrupt");
80 // Disable the interrupt, but don't acknowledge the error, so that it can be 78 // Disable the interrupt, but don't acknowledge the error, so that it can be
81 // forwarded off the the bus message consumer. If we don't provide some way for 79 // forwarded off the bus message consumer. If we don't provide some way for
82 // downstream code to determine that it has already provided this bus error instance 80 // downstream code to determine that it has already provided this bus error instance
83 // to the bus message consumer, we are doomed to re-provide a single error instance for 81 // to the bus message consumer, we are doomed to re-provide a single error instance for
84 // an indefinite amount of time. 82 // an indefinite amount of time.
diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs
index 8a6aa53a0..df041c4e9 100644
--- a/embassy-stm32/src/dma/dma_bdma.rs
+++ b/embassy-stm32/src/dma/dma_bdma.rs
@@ -15,6 +15,8 @@ use crate::{interrupt, pac};
15pub(crate) struct ChannelInfo { 15pub(crate) struct ChannelInfo {
16 pub(crate) dma: DmaInfo, 16 pub(crate) dma: DmaInfo,
17 pub(crate) num: usize, 17 pub(crate) num: usize,
18 #[cfg(feature = "_dual-core")]
19 pub(crate) irq: pac::Interrupt,
18 #[cfg(dmamux)] 20 #[cfg(dmamux)]
19 pub(crate) dmamux: super::DmamuxInfo, 21 pub(crate) dmamux: super::DmamuxInfo,
20} 22}
@@ -259,10 +261,12 @@ pub(crate) unsafe fn init(
259 foreach_interrupt! { 261 foreach_interrupt! {
260 ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { 262 ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => {
261 crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, dma_priority); 263 crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, dma_priority);
264 #[cfg(not(feature = "_dual-core"))]
262 crate::interrupt::typelevel::$irq::enable(); 265 crate::interrupt::typelevel::$irq::enable();
263 }; 266 };
264 ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => { 267 ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => {
265 crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, bdma_priority); 268 crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, bdma_priority);
269 #[cfg(not(feature = "_dual-core"))]
266 crate::interrupt::typelevel::$irq::enable(); 270 crate::interrupt::typelevel::$irq::enable();
267 }; 271 };
268 } 272 }
@@ -341,6 +345,11 @@ impl AnyChannel {
341 options: TransferOptions, 345 options: TransferOptions,
342 ) { 346 ) {
343 let info = self.info(); 347 let info = self.info();
348 #[cfg(feature = "_dual-core")]
349 {
350 use embassy_hal_internal::interrupt::InterruptExt as _;
351 info.irq.enable();
352 }
344 353
345 #[cfg(dmamux)] 354 #[cfg(dmamux)]
346 super::dmamux::configure_dmamux(&info.dmamux, _request); 355 super::dmamux::configure_dmamux(&info.dmamux, _request);
@@ -768,6 +777,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
768 let dir = Dir::PeripheralToMemory; 777 let dir = Dir::PeripheralToMemory;
769 let data_size = W::size(); 778 let data_size = W::size();
770 779
780 options.half_transfer_ir = true;
771 options.complete_transfer_ir = true; 781 options.complete_transfer_ir = true;
772 options.circular = true; 782 options.circular = true;
773 783
diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs
index 13d5d15be..f9d66ca86 100644
--- a/embassy-stm32/src/dma/gpdma.rs
+++ b/embassy-stm32/src/dma/gpdma.rs
@@ -18,6 +18,8 @@ use crate::pac::gpdma::vals;
18pub(crate) struct ChannelInfo { 18pub(crate) struct ChannelInfo {
19 pub(crate) dma: pac::gpdma::Gpdma, 19 pub(crate) dma: pac::gpdma::Gpdma,
20 pub(crate) num: usize, 20 pub(crate) num: usize,
21 #[cfg(feature = "_dual-core")]
22 pub(crate) irq: pac::Interrupt,
21} 23}
22 24
23/// GPDMA transfer options. 25/// GPDMA transfer options.
@@ -57,6 +59,7 @@ pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: P
57 foreach_interrupt! { 59 foreach_interrupt! {
58 ($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => { 60 ($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => {
59 crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority); 61 crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority);
62 #[cfg(not(feature = "_dual-core"))]
60 crate::interrupt::typelevel::$irq::enable(); 63 crate::interrupt::typelevel::$irq::enable();
61 }; 64 };
62 } 65 }
@@ -67,6 +70,12 @@ impl AnyChannel {
67 /// Safety: Must be called with a matching set of parameters for a valid dma channel 70 /// Safety: Must be called with a matching set of parameters for a valid dma channel
68 pub(crate) unsafe fn on_irq(&self) { 71 pub(crate) unsafe fn on_irq(&self) {
69 let info = self.info(); 72 let info = self.info();
73 #[cfg(feature = "_dual-core")]
74 {
75 use embassy_hal_internal::interrupt::InterruptExt as _;
76 info.irq.enable();
77 }
78
70 let state = &STATE[self.id as usize]; 79 let state = &STATE[self.id as usize];
71 80
72 let ch = info.dma.ch(info.num); 81 let ch = info.dma.ch(info.num);
diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs
index 51f124542..77c3d95c3 100644
--- a/embassy-stm32/src/dsihost.rs
+++ b/embassy-stm32/src/dsihost.rs
@@ -14,7 +14,7 @@ pub fn blocking_delay_ms(ms: u32) {
14 #[cfg(feature = "time")] 14 #[cfg(feature = "time")]
15 embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64)); 15 embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64));
16 #[cfg(not(feature = "time"))] 16 #[cfg(not(feature = "time"))]
17 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 1_000 * ms); 17 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 1_000 * ms);
18} 18}
19 19
20/// PacketTypes extracted from CubeMX 20/// PacketTypes extracted from CubeMX
diff --git a/embassy-stm32/src/flash/f1f3.rs b/embassy-stm32/src/flash/f1f3.rs
index e66842e31..ff7f810ea 100644
--- a/embassy-stm32/src/flash/f1f3.rs
+++ b/embassy-stm32/src/flash/f1f3.rs
@@ -42,9 +42,11 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
42 42
43 // prevents parallelism errors 43 // prevents parallelism errors
44 fence(Ordering::SeqCst); 44 fence(Ordering::SeqCst);
45
46 wait_ready_blocking()?;
45 } 47 }
46 48
47 wait_ready_blocking() 49 Ok(())
48} 50}
49 51
50pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 52pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
diff --git a/embassy-stm32/src/flash/f2.rs b/embassy-stm32/src/flash/f2.rs
new file mode 100644
index 000000000..cdab1fd2d
--- /dev/null
+++ b/embassy-stm32/src/flash/f2.rs
@@ -0,0 +1,142 @@
1use core::ptr::write_volatile;
2use core::sync::atomic::{fence, AtomicBool, Ordering};
3
4use pac::flash::regs::Sr;
5
6use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE};
7use crate::flash::Error;
8use crate::pac;
9
10static DATA_CACHE_WAS_ENABLED: AtomicBool = AtomicBool::new(false);
11
12impl FlashSector {
13 const fn snb(&self) -> u8 {
14 ((self.bank as u8) << 4) + self.index_in_bank
15 }
16}
17
18pub(crate) const fn is_default_layout() -> bool {
19 true
20}
21
22pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] {
23 &FLASH_REGIONS
24}
25
26pub(crate) unsafe fn lock() {
27 pac::FLASH.cr().modify(|w| w.set_lock(true));
28}
29
30pub(crate) unsafe fn unlock() {
31 if pac::FLASH.cr().read().lock() {
32 pac::FLASH.keyr().write_value(0x4567_0123);
33 pac::FLASH.keyr().write_value(0xCDEF_89AB);
34 }
35}
36
37pub(crate) unsafe fn enable_blocking_write() {
38 assert_eq!(0, WRITE_SIZE % 4);
39 save_data_cache_state();
40
41 pac::FLASH.cr().write(|w| {
42 w.set_pg(true);
43 w.set_psize(pac::flash::vals::Psize::PSIZE32);
44 });
45}
46
47pub(crate) unsafe fn disable_blocking_write() {
48 pac::FLASH.cr().write(|w| w.set_pg(false));
49 restore_data_cache_state();
50}
51
52pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
53 write_start(start_address, buf);
54 blocking_wait_ready()
55}
56
57unsafe fn write_start(start_address: u32, buf: &[u8; WRITE_SIZE]) {
58 let mut address = start_address;
59 for val in buf.chunks(4) {
60 write_volatile(address as *mut u32, u32::from_le_bytes(unwrap!(val.try_into())));
61 address += val.len() as u32;
62
63 // prevents parallelism errors
64 fence(Ordering::SeqCst);
65 }
66}
67
68pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
69 save_data_cache_state();
70
71 trace!("Blocking erasing sector number {}", sector.snb());
72
73 pac::FLASH.cr().modify(|w| {
74 w.set_ser(true);
75 w.set_snb(sector.snb())
76 });
77
78 pac::FLASH.cr().modify(|w| {
79 w.set_strt(true);
80 });
81
82 let ret: Result<(), Error> = blocking_wait_ready();
83 clear_all_err();
84 restore_data_cache_state();
85 ret
86}
87
88pub(crate) unsafe fn clear_all_err() {
89 // read and write back the same value.
90 // This clears all "write 1 to clear" bits.
91 pac::FLASH.sr().modify(|_| {});
92}
93
94unsafe fn blocking_wait_ready() -> Result<(), Error> {
95 loop {
96 let sr = pac::FLASH.sr().read();
97
98 if !sr.bsy() {
99 return get_result(sr);
100 }
101 }
102}
103
104fn get_result(sr: Sr) -> Result<(), Error> {
105 if sr.pgserr() {
106 Err(Error::Seq)
107 } else if sr.pgperr() {
108 Err(Error::Parallelism)
109 } else if sr.pgaerr() {
110 Err(Error::Unaligned)
111 } else if sr.wrperr() {
112 Err(Error::Protected)
113 } else {
114 Ok(())
115 }
116}
117
118fn save_data_cache_state() {
119 let dual_bank = unwrap!(get_flash_regions().last()).bank == FlashBank::Bank2;
120 if dual_bank {
121 // Disable data cache during write/erase if there are two banks, see errata 2.2.12
122 let dcen = pac::FLASH.acr().read().dcen();
123 DATA_CACHE_WAS_ENABLED.store(dcen, Ordering::Relaxed);
124 if dcen {
125 pac::FLASH.acr().modify(|w| w.set_dcen(false));
126 }
127 }
128}
129
130fn restore_data_cache_state() {
131 let dual_bank = unwrap!(get_flash_regions().last()).bank == FlashBank::Bank2;
132 if dual_bank {
133 // Restore data cache if it was enabled
134 let dcen = DATA_CACHE_WAS_ENABLED.load(Ordering::Relaxed);
135 if dcen {
136 // Reset data cache before we enable it again
137 pac::FLASH.acr().modify(|w| w.set_dcrst(true));
138 pac::FLASH.acr().modify(|w| w.set_dcrst(false));
139 pac::FLASH.acr().modify(|w| w.set_dcen(true))
140 }
141 }
142}
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index ce2d1a04c..bce638db0 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -94,6 +94,7 @@ pub enum FlashBank {
94#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] 94#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")]
95#[cfg_attr(flash_f0, path = "f0.rs")] 95#[cfg_attr(flash_f0, path = "f0.rs")]
96#[cfg_attr(any(flash_f1, flash_f3), path = "f1f3.rs")] 96#[cfg_attr(any(flash_f1, flash_f3), path = "f1f3.rs")]
97#[cfg_attr(flash_f2, path = "f2.rs")]
97#[cfg_attr(flash_f4, path = "f4.rs")] 98#[cfg_attr(flash_f4, path = "f4.rs")]
98#[cfg_attr(flash_f7, path = "f7.rs")] 99#[cfg_attr(flash_f7, path = "f7.rs")]
99#[cfg_attr(any(flash_g0, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")] 100#[cfg_attr(any(flash_g0, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")]
@@ -104,8 +105,8 @@ pub enum FlashBank {
104#[cfg_attr(flash_u0, path = "u0.rs")] 105#[cfg_attr(flash_u0, path = "u0.rs")]
105#[cfg_attr( 106#[cfg_attr(
106 not(any( 107 not(any(
107 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0, 108 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f2, flash_f3, flash_f4, flash_f7,
108 flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0 109 flash_g0, flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0
109 )), 110 )),
110 path = "other.rs" 111 path = "other.rs"
111)] 112)]
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs
index 7aea466e8..83b49a3dd 100644
--- a/embassy-stm32/src/fmc.rs
+++ b/embassy-stm32/src/fmc.rs
@@ -160,6 +160,26 @@ impl<'d, T: Instance> Fmc<'d, T> {
160 ] 160 ]
161 )); 161 ));
162 162
163 fmc_sdram_constructor!(sdram_a13bits_d32bits_4banks_bank1: (
164 bank: stm32_fmc::SdramTargetBank::Bank1,
165 addr: [
166 (a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin), (a12: A12Pin)
167 ],
168 ba: [(ba0: BA0Pin), (ba1: BA1Pin)],
169 d: [
170 (d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin),
171 (d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin),
172 (d16: D16Pin), (d17: D17Pin), (d18: D18Pin), (d19: D19Pin), (d20: D20Pin), (d21: D21Pin), (d22: D22Pin), (d23: D23Pin),
173 (d24: D24Pin), (d25: D25Pin), (d26: D26Pin), (d27: D27Pin), (d28: D28Pin), (d29: D29Pin), (d30: D30Pin), (d31: D31Pin)
174 ],
175 nbl: [
176 (nbl0: NBL0Pin), (nbl1: NBL1Pin), (nbl2: NBL2Pin), (nbl3: NBL3Pin)
177 ],
178 ctrl: [
179 (sdcke: SDCKE0Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE0Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
180 ]
181 ));
182
163 fmc_sdram_constructor!(sdram_a12bits_d16bits_4banks_bank2: ( 183 fmc_sdram_constructor!(sdram_a12bits_d16bits_4banks_bank2: (
164 bank: stm32_fmc::SdramTargetBank::Bank2, 184 bank: stm32_fmc::SdramTargetBank::Bank2,
165 addr: [ 185 addr: [
@@ -197,6 +217,26 @@ impl<'d, T: Instance> Fmc<'d, T> {
197 (sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin) 217 (sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
198 ] 218 ]
199 )); 219 ));
220
221 fmc_sdram_constructor!(sdram_a13bits_d32bits_4banks_bank2: (
222 bank: stm32_fmc::SdramTargetBank::Bank2,
223 addr: [
224 (a0: A0Pin), (a1: A1Pin), (a2: A2Pin), (a3: A3Pin), (a4: A4Pin), (a5: A5Pin), (a6: A6Pin), (a7: A7Pin), (a8: A8Pin), (a9: A9Pin), (a10: A10Pin), (a11: A11Pin), (a12: A12Pin)
225 ],
226 ba: [(ba0: BA0Pin), (ba1: BA1Pin)],
227 d: [
228 (d0: D0Pin), (d1: D1Pin), (d2: D2Pin), (d3: D3Pin), (d4: D4Pin), (d5: D5Pin), (d6: D6Pin), (d7: D7Pin),
229 (d8: D8Pin), (d9: D9Pin), (d10: D10Pin), (d11: D11Pin), (d12: D12Pin), (d13: D13Pin), (d14: D14Pin), (d15: D15Pin),
230 (d16: D16Pin), (d17: D17Pin), (d18: D18Pin), (d19: D19Pin), (d20: D20Pin), (d21: D21Pin), (d22: D22Pin), (d23: D23Pin),
231 (d24: D24Pin), (d25: D25Pin), (d26: D26Pin), (d27: D27Pin), (d28: D28Pin), (d29: D29Pin), (d30: D30Pin), (d31: D31Pin)
232 ],
233 nbl: [
234 (nbl0: NBL0Pin), (nbl1: NBL1Pin), (nbl2: NBL2Pin), (nbl3: NBL3Pin)
235 ],
236 ctrl: [
237 (sdcke: SDCKE1Pin), (sdclk: SDCLKPin), (sdncas: SDNCASPin), (sdne: SDNE1Pin), (sdnras: SDNRASPin), (sdnwe: SDNWEPin)
238 ]
239 ));
200} 240}
201 241
202trait SealedInstance: crate::rcc::RccPeripheral { 242trait SealedInstance: crate::rcc::RccPeripheral {
diff --git a/embassy-stm32/src/fmt.rs b/embassy-stm32/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-stm32/src/fmt.rs
+++ b/embassy-stm32/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs
index b77a3415b..06ab7a9bc 100644
--- a/embassy-stm32/src/hsem/mod.rs
+++ b/embassy-stm32/src/hsem/mod.rs
@@ -158,6 +158,11 @@ impl<'d, T: Instance> HardwareSemaphore<'d, T> {
158 .modify(|w| w.set_ise(sem_x, enable)); 158 .modify(|w| w.set_ise(sem_x, enable));
159 } 159 }
160 160
161 /// Gets the interrupt flag for the semaphore.
162 pub fn is_interrupt_active(&mut self, core_id: CoreId, sem_x: usize) -> bool {
163 T::regs().isr(core_id_to_index(core_id)).read().isf(sem_x)
164 }
165
161 /// Clears the interrupt flag for the semaphore. 166 /// Clears the interrupt flag for the semaphore.
162 pub fn clear_interrupt(&mut self, core_id: CoreId, sem_x: usize) { 167 pub fn clear_interrupt(&mut self, core_id: CoreId, sem_x: usize) {
163 T::regs() 168 T::regs()
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 95f59360a..451f595e0 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -89,6 +89,8 @@ pub mod i2s;
89pub mod ipcc; 89pub mod ipcc;
90#[cfg(feature = "low-power")] 90#[cfg(feature = "low-power")]
91pub mod low_power; 91pub mod low_power;
92#[cfg(lptim)]
93pub mod lptim;
92#[cfg(ltdc)] 94#[cfg(ltdc)]
93pub mod ltdc; 95pub mod ltdc;
94#[cfg(opamp)] 96#[cfg(opamp)]
@@ -197,6 +199,7 @@ pub use crate::pac::NVIC_PRIO_BITS;
197 199
198/// `embassy-stm32` global configuration. 200/// `embassy-stm32` global configuration.
199#[non_exhaustive] 201#[non_exhaustive]
202#[derive(Clone, Copy)]
200pub struct Config { 203pub struct Config {
201 /// RCC config. 204 /// RCC config.
202 pub rcc: rcc::Config, 205 pub rcc: rcc::Config,
@@ -273,7 +276,137 @@ impl Default for Config {
273/// This returns the peripheral singletons that can be used for creating drivers. 276/// This returns the peripheral singletons that can be used for creating drivers.
274/// 277///
275/// This should only be called once at startup, otherwise it panics. 278/// This should only be called once at startup, otherwise it panics.
279#[cfg(not(feature = "_dual-core"))]
276pub fn init(config: Config) -> Peripherals { 280pub fn init(config: Config) -> Peripherals {
281 init_hw(config)
282}
283
284#[cfg(feature = "_dual-core")]
285mod dual_core {
286 use core::cell::UnsafeCell;
287 use core::mem::MaybeUninit;
288 use core::sync::atomic::{AtomicUsize, Ordering};
289
290 use rcc::Clocks;
291
292 use super::*;
293
294 /// Object containing data that embassy needs to share between cores.
295 ///
296 /// It cannot be initialized by the user. The intended use is:
297 ///
298 /// ```
299 /// #[link_section = ".ram_d3"]
300 /// static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
301 ///
302 /// init_secondary(&SHARED_DATA);
303 /// ```
304 ///
305 /// This static must be placed in the same position for both cores. How and where this is done is left to the user.
306 pub struct SharedData {
307 init_flag: AtomicUsize,
308 clocks: UnsafeCell<MaybeUninit<Clocks>>,
309 config: UnsafeCell<MaybeUninit<Config>>,
310 }
311
312 unsafe impl Sync for SharedData {}
313
314 const INIT_DONE_FLAG: usize = 0xca11ab1e;
315
316 /// Initialize the `embassy-stm32` HAL with the provided configuration.
317 /// This function does the actual initialization of the hardware, in contrast to [init_secondary] or [try_init_secondary].
318 /// Any core can do the init, but it's important only one core does it.
319 ///
320 /// This returns the peripheral singletons that can be used for creating drivers.
321 ///
322 /// This should only be called once at startup, otherwise it panics.
323 ///
324 /// The `shared_data` is used to coordinate the init with the second core. Read the [SharedData] docs
325 /// for more information on its requirements.
326 pub fn init_primary(config: Config, shared_data: &'static MaybeUninit<SharedData>) -> Peripherals {
327 let shared_data = unsafe { shared_data.assume_init_ref() };
328
329 rcc::set_freqs_ptr(shared_data.clocks.get());
330 let p = init_hw(config);
331
332 unsafe { *shared_data.config.get() }.write(config);
333
334 shared_data.init_flag.store(INIT_DONE_FLAG, Ordering::SeqCst);
335
336 p
337 }
338
339 /// Try to initialize the `embassy-stm32` HAL based on the init done by the other core using [init_primary].
340 ///
341 /// This returns the peripheral singletons that can be used for creating drivers if the other core is done with its init.
342 /// If the other core is not done yet, this will return `None`.
343 ///
344 /// This should only be called once at startup, otherwise it may panic.
345 ///
346 /// The `shared_data` is used to coordinate the init with the second core. Read the [SharedData] docs
347 /// for more information on its requirements.
348 pub fn try_init_secondary(shared_data: &'static MaybeUninit<SharedData>) -> Option<Peripherals> {
349 let shared_data = unsafe { shared_data.assume_init_ref() };
350
351 if shared_data.init_flag.load(Ordering::SeqCst) != INIT_DONE_FLAG {
352 return None;
353 }
354
355 // Separate load and store to support the CM0 of the STM32WL
356 shared_data.init_flag.store(0, Ordering::SeqCst);
357
358 Some(init_secondary_hw(shared_data))
359 }
360
361 /// Initialize the `embassy-stm32` HAL based on the init done by the other core using [init_primary].
362 ///
363 /// This returns the peripheral singletons that can be used for creating drivers when the other core is done with its init.
364 /// If the other core is not done yet, this will spinloop wait on it.
365 ///
366 /// This should only be called once at startup, otherwise it may panic.
367 ///
368 /// The `shared_data` is used to coordinate the init with the second core. Read the [SharedData] docs
369 /// for more information on its requirements.
370 pub fn init_secondary(shared_data: &'static MaybeUninit<SharedData>) -> Peripherals {
371 loop {
372 if let Some(p) = try_init_secondary(shared_data) {
373 return p;
374 }
375 }
376 }
377
378 fn init_secondary_hw(shared_data: &'static SharedData) -> Peripherals {
379 rcc::set_freqs_ptr(shared_data.clocks.get());
380
381 let config = unsafe { (*shared_data.config.get()).assume_init() };
382
383 // We use different timers on the different cores, so we have to still initialize one here
384 critical_section::with(|cs| {
385 unsafe {
386 dma::init(
387 cs,
388 #[cfg(bdma)]
389 config.bdma_interrupt_priority,
390 #[cfg(dma)]
391 config.dma_interrupt_priority,
392 #[cfg(gpdma)]
393 config.gpdma_interrupt_priority,
394 )
395 }
396
397 #[cfg(feature = "_time-driver")]
398 // must be after rcc init
399 time_driver::init(cs);
400 });
401
402 Peripherals::take()
403 }
404}
405
406#[cfg(feature = "_dual-core")]
407pub use dual_core::*;
408
409fn init_hw(config: Config) -> Peripherals {
277 critical_section::with(|cs| { 410 critical_section::with(|cs| {
278 let p = Peripherals::take_with_cs(cs); 411 let p = Peripherals::take_with_cs(cs);
279 412
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index 604bdf416..f3e4c6994 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -109,10 +109,10 @@ pub enum StopMode {
109 Stop2, 109 Stop2,
110} 110}
111 111
112#[cfg(stm32l5)] 112#[cfg(any(stm32l4, stm32l5))]
113use stm32_metapac::pwr::vals::Lpms; 113use stm32_metapac::pwr::vals::Lpms;
114 114
115#[cfg(stm32l5)] 115#[cfg(any(stm32l4, stm32l5))]
116impl Into<Lpms> for StopMode { 116impl Into<Lpms> for StopMode {
117 fn into(self) -> Lpms { 117 fn into(self) -> Lpms {
118 match self { 118 match self {
@@ -181,7 +181,7 @@ impl Executor {
181 181
182 #[allow(unused_variables)] 182 #[allow(unused_variables)]
183 fn configure_stop(&mut self, stop_mode: StopMode) { 183 fn configure_stop(&mut self, stop_mode: StopMode) {
184 #[cfg(stm32l5)] 184 #[cfg(any(stm32l4, stm32l5))]
185 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); 185 crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into()));
186 #[cfg(stm32h5)] 186 #[cfg(stm32h5)]
187 crate::pac::PWR.pmcr().modify(|v| { 187 crate::pac::PWR.pmcr().modify(|v| {
diff --git a/embassy-stm32/src/lptim/channel.rs b/embassy-stm32/src/lptim/channel.rs
new file mode 100644
index 000000000..17fc2fb86
--- /dev/null
+++ b/embassy-stm32/src/lptim/channel.rs
@@ -0,0 +1,18 @@
1/// Timer channel.
2#[derive(Clone, Copy)]
3pub enum Channel {
4 /// Channel 1.
5 Ch1,
6 /// Channel 2.
7 Ch2,
8}
9
10impl Channel {
11 /// Get the channel index (0..1)
12 pub fn index(&self) -> usize {
13 match self {
14 Channel::Ch1 => 0,
15 Channel::Ch2 => 1,
16 }
17 }
18}
diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs
new file mode 100644
index 000000000..1649cc5b4
--- /dev/null
+++ b/embassy-stm32/src/lptim/mod.rs
@@ -0,0 +1,48 @@
1//! Low-power timer (LPTIM)
2
3pub mod pwm;
4pub mod timer;
5
6use crate::rcc::RccPeripheral;
7
8/// Timer channel.
9#[cfg(any(lptim_v2a, lptim_v2b))]
10mod channel;
11#[cfg(any(lptim_v2a, lptim_v2b))]
12pub use channel::Channel;
13
14pin_trait!(OutputPin, BasicInstance);
15pin_trait!(Channel1Pin, BasicInstance);
16pin_trait!(Channel2Pin, BasicInstance);
17
18pub(crate) trait SealedInstance: RccPeripheral {
19 fn regs() -> crate::pac::lptim::Lptim;
20}
21pub(crate) trait SealedBasicInstance: RccPeripheral {}
22
23/// LPTIM basic instance trait.
24#[allow(private_bounds)]
25pub trait BasicInstance: SealedBasicInstance + 'static {}
26
27/// LPTIM instance trait.
28#[allow(private_bounds)]
29pub trait Instance: BasicInstance + SealedInstance + 'static {}
30
31foreach_interrupt! {
32 ($inst:ident, lptim, LPTIM, GLOBAL, $irq:ident) => {
33 impl SealedInstance for crate::peripherals::$inst {
34 fn regs() -> crate::pac::lptim::Lptim {
35 crate::pac::$inst
36 }
37 }
38 impl SealedBasicInstance for crate::peripherals::$inst {
39 }
40 impl BasicInstance for crate::peripherals::$inst {}
41 impl Instance for crate::peripherals::$inst {}
42 };
43 ($inst:ident, lptim, LPTIM_BASIC, GLOBAL, $irq:ident) => {
44 impl SealedBasicInstance for crate::peripherals::$inst {
45 }
46 impl BasicInstance for crate::peripherals::$inst {}
47 };
48}
diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs
new file mode 100644
index 000000000..1f43eb6ee
--- /dev/null
+++ b/embassy-stm32/src/lptim/pwm.rs
@@ -0,0 +1,168 @@
1//! PWM driver.
2
3use core::marker::PhantomData;
4
5use embassy_hal_internal::{into_ref, PeripheralRef};
6
7use super::timer::Timer;
8#[cfg(not(any(lptim_v2a, lptim_v2b)))]
9use super::OutputPin;
10#[cfg(any(lptim_v2a, lptim_v2b))]
11use super::{channel::Channel, timer::ChannelDirection, Channel1Pin, Channel2Pin};
12use super::{BasicInstance, Instance};
13use crate::gpio::{AfType, AnyPin, OutputType, Speed};
14use crate::time::Hertz;
15use crate::Peripheral;
16
17/// Output marker type.
18pub enum Output {}
19/// Channel 1 marker type.
20pub enum Ch1 {}
21/// Channel 2 marker type.
22pub enum Ch2 {}
23
24/// PWM pin wrapper.
25///
26/// This wraps a pin to make it usable with PWM.
27pub struct PwmPin<'d, T, C> {
28 _pin: PeripheralRef<'d, AnyPin>,
29 phantom: PhantomData<(T, C)>,
30}
31
32macro_rules! channel_impl {
33 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
34 impl<'d, T: BasicInstance> PwmPin<'d, T, $channel> {
35 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
36 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self {
37 into_ref!(pin);
38 critical_section::with(|_| {
39 pin.set_low();
40 pin.set_as_af(
41 pin.af_num(),
42 AfType::output(OutputType::PushPull, Speed::VeryHigh),
43 );
44 });
45 PwmPin {
46 _pin: pin.map_into(),
47 phantom: PhantomData,
48 }
49 }
50 }
51 };
52}
53
54#[cfg(not(any(lptim_v2a, lptim_v2b)))]
55channel_impl!(new, Output, OutputPin);
56#[cfg(any(lptim_v2a, lptim_v2b))]
57channel_impl!(new_ch1, Ch1, Channel1Pin);
58#[cfg(any(lptim_v2a, lptim_v2b))]
59channel_impl!(new_ch2, Ch2, Channel2Pin);
60
61/// PWM driver.
62pub struct Pwm<'d, T: Instance> {
63 inner: Timer<'d, T>,
64}
65
66#[cfg(not(any(lptim_v2a, lptim_v2b)))]
67impl<'d, T: Instance> Pwm<'d, T> {
68 /// Create a new PWM driver.
69 pub fn new(tim: impl Peripheral<P = T> + 'd, _output_pin: PwmPin<'d, T, Output>, freq: Hertz) -> Self {
70 Self::new_inner(tim, freq)
71 }
72
73 /// Set the duty.
74 ///
75 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
76 pub fn set_duty(&mut self, duty: u16) {
77 assert!(duty <= self.get_max_duty());
78 self.inner.set_compare_value(duty)
79 }
80
81 /// Get the duty.
82 ///
83 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
84 pub fn get_duty(&self) -> u16 {
85 self.inner.get_compare_value()
86 }
87
88 fn post_init(&mut self) {}
89}
90
91#[cfg(any(lptim_v2a, lptim_v2b))]
92impl<'d, T: Instance> Pwm<'d, T> {
93 /// Create a new PWM driver.
94 pub fn new(
95 tim: impl Peripheral<P = T> + 'd,
96 _ch1_pin: Option<PwmPin<'d, T, Ch1>>,
97 _ch2_pin: Option<PwmPin<'d, T, Ch2>>,
98 freq: Hertz,
99 ) -> Self {
100 Self::new_inner(tim, freq)
101 }
102
103 /// Enable the given channel.
104 pub fn enable(&mut self, channel: Channel) {
105 self.inner.enable_channel(channel, true);
106 }
107
108 /// Disable the given channel.
109 pub fn disable(&mut self, channel: Channel) {
110 self.inner.enable_channel(channel, false);
111 }
112
113 /// Check whether given channel is enabled
114 pub fn is_enabled(&self, channel: Channel) -> bool {
115 self.inner.get_channel_enable_state(channel)
116 }
117
118 /// Set the duty for a given channel.
119 ///
120 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
121 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
122 assert!(duty <= self.get_max_duty());
123 self.inner.set_compare_value(channel, duty)
124 }
125
126 /// Get the duty for a given channel.
127 ///
128 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
129 pub fn get_duty(&self, channel: Channel) -> u16 {
130 self.inner.get_compare_value(channel)
131 }
132
133 fn post_init(&mut self) {
134 [Channel::Ch1, Channel::Ch2].iter().for_each(|&channel| {
135 self.inner.set_channel_direction(channel, ChannelDirection::OutputPwm);
136 });
137 }
138}
139
140impl<'d, T: Instance> Pwm<'d, T> {
141 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz) -> Self {
142 let mut this = Self { inner: Timer::new(tim) };
143
144 this.inner.enable();
145 this.set_frequency(freq);
146
147 this.post_init();
148
149 this.inner.continuous_mode_start();
150
151 this
152 }
153
154 /// Set PWM frequency.
155 ///
156 /// Note: when you call this, the max duty value changes, so you will have to
157 /// call `set_duty` on all channels with the duty calculated based on the new max duty.
158 pub fn set_frequency(&mut self, frequency: Hertz) {
159 self.inner.set_frequency(frequency);
160 }
161
162 /// Get max duty value.
163 ///
164 /// This value depends on the configured frequency and the timer's clock rate from RCC.
165 pub fn get_max_duty(&self) -> u16 {
166 self.inner.get_max_compare_value() + 1
167 }
168}
diff --git a/embassy-stm32/src/lptim/timer/channel_direction.rs b/embassy-stm32/src/lptim/timer/channel_direction.rs
new file mode 100644
index 000000000..a38df63cd
--- /dev/null
+++ b/embassy-stm32/src/lptim/timer/channel_direction.rs
@@ -0,0 +1,18 @@
1use crate::pac::lptim::vals;
2
3/// Direction of a low-power timer channel
4pub enum ChannelDirection {
5 /// Use channel as a PWM output
6 OutputPwm,
7 /// Use channel as an input capture
8 InputCapture,
9}
10
11impl From<ChannelDirection> for vals::Ccsel {
12 fn from(direction: ChannelDirection) -> Self {
13 match direction {
14 ChannelDirection::OutputPwm => vals::Ccsel::OUTPUTCOMPARE,
15 ChannelDirection::InputCapture => vals::Ccsel::INPUTCAPTURE,
16 }
17 }
18}
diff --git a/embassy-stm32/src/lptim/timer/mod.rs b/embassy-stm32/src/lptim/timer/mod.rs
new file mode 100644
index 000000000..e62fcab49
--- /dev/null
+++ b/embassy-stm32/src/lptim/timer/mod.rs
@@ -0,0 +1,133 @@
1//! Low-level timer driver.
2mod prescaler;
3
4use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
5
6#[cfg(any(lptim_v2a, lptim_v2b))]
7use super::channel::Channel;
8#[cfg(any(lptim_v2a, lptim_v2b))]
9mod channel_direction;
10#[cfg(any(lptim_v2a, lptim_v2b))]
11pub use channel_direction::ChannelDirection;
12use prescaler::Prescaler;
13
14use super::Instance;
15use crate::rcc;
16use crate::time::Hertz;
17
18/// Low-level timer driver.
19pub struct Timer<'d, T: Instance> {
20 _tim: PeripheralRef<'d, T>,
21}
22
23impl<'d, T: Instance> Timer<'d, T> {
24 /// Create a new timer driver.
25 pub fn new(tim: impl Peripheral<P = T> + 'd) -> Self {
26 into_ref!(tim);
27
28 rcc::enable_and_reset::<T>();
29
30 Self { _tim: tim }
31 }
32
33 /// Enable the timer.
34 pub fn enable(&self) {
35 T::regs().cr().modify(|w| w.set_enable(true));
36 }
37
38 /// Disable the timer.
39 pub fn disable(&self) {
40 T::regs().cr().modify(|w| w.set_enable(false));
41 }
42
43 /// Start the timer in single pulse mode.
44 pub fn single_mode_start(&self) {
45 T::regs().cr().modify(|w| w.set_sngstrt(true));
46 }
47
48 /// Start the timer in continuous mode.
49 pub fn continuous_mode_start(&self) {
50 T::regs().cr().modify(|w| w.set_cntstrt(true));
51 }
52
53 /// Set the frequency of how many times per second the timer counts up to the max value or down to 0.
54 pub fn set_frequency(&self, frequency: Hertz) {
55 let f = frequency.0;
56 assert!(f > 0);
57
58 let pclk_f = T::frequency().0;
59
60 let pclk_ticks_per_timer_period = pclk_f / f;
61
62 let psc = Prescaler::from_ticks(pclk_ticks_per_timer_period);
63 let arr = psc.scale_down(pclk_ticks_per_timer_period);
64
65 T::regs().cfgr().modify(|r| r.set_presc((&psc).into()));
66 T::regs().arr().modify(|r| r.set_arr(arr.into()));
67 }
68
69 /// Get the timer frequency.
70 pub fn get_frequency(&self) -> Hertz {
71 let pclk_f = T::frequency();
72 let arr = T::regs().arr().read().arr();
73 let psc = Prescaler::from(T::regs().cfgr().read().presc());
74
75 pclk_f / psc.scale_up(arr)
76 }
77
78 /// Get the clock frequency of the timer (before prescaler is applied).
79 pub fn get_clock_frequency(&self) -> Hertz {
80 T::frequency()
81 }
82
83 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
84 pub fn get_max_compare_value(&self) -> u16 {
85 T::regs().arr().read().arr()
86 }
87}
88
89#[cfg(any(lptim_v2a, lptim_v2b))]
90impl<'d, T: Instance> Timer<'d, T> {
91 /// Enable/disable a channel.
92 pub fn enable_channel(&self, channel: Channel, enable: bool) {
93 T::regs().ccmr(0).modify(|w| {
94 w.set_cce(channel.index(), enable);
95 });
96 }
97
98 /// Get enable/disable state of a channel
99 pub fn get_channel_enable_state(&self, channel: Channel) -> bool {
100 T::regs().ccmr(0).read().cce(channel.index())
101 }
102
103 /// Set compare value for a channel.
104 pub fn set_compare_value(&self, channel: Channel, value: u16) {
105 T::regs().ccr(channel.index()).modify(|w| w.set_ccr(value));
106 }
107
108 /// Get compare value for a channel.
109 pub fn get_compare_value(&self, channel: Channel) -> u16 {
110 T::regs().ccr(channel.index()).read().ccr()
111 }
112
113 /// Set channel direction.
114 #[cfg(any(lptim_v2a, lptim_v2b))]
115 pub fn set_channel_direction(&self, channel: Channel, direction: ChannelDirection) {
116 T::regs()
117 .ccmr(0)
118 .modify(|w| w.set_ccsel(channel.index(), direction.into()));
119 }
120}
121
122#[cfg(not(any(lptim_v2a, lptim_v2b)))]
123impl<'d, T: Instance> Timer<'d, T> {
124 /// Set compare value for a channel.
125 pub fn set_compare_value(&self, value: u16) {
126 T::regs().cmp().modify(|w| w.set_cmp(value));
127 }
128
129 /// Get compare value for a channel.
130 pub fn get_compare_value(&self) -> u16 {
131 T::regs().cmp().read().cmp()
132 }
133}
diff --git a/embassy-stm32/src/lptim/timer/prescaler.rs b/embassy-stm32/src/lptim/timer/prescaler.rs
new file mode 100644
index 000000000..5d2326faf
--- /dev/null
+++ b/embassy-stm32/src/lptim/timer/prescaler.rs
@@ -0,0 +1,90 @@
1//! Low-level timer driver.
2
3use crate::pac::lptim::vals;
4
5pub enum Prescaler {
6 Div1,
7 Div2,
8 Div4,
9 Div8,
10 Div16,
11 Div32,
12 Div64,
13 Div128,
14}
15
16impl From<&Prescaler> for vals::Presc {
17 fn from(prescaler: &Prescaler) -> Self {
18 match prescaler {
19 Prescaler::Div1 => vals::Presc::DIV1,
20 Prescaler::Div2 => vals::Presc::DIV2,
21 Prescaler::Div4 => vals::Presc::DIV4,
22 Prescaler::Div8 => vals::Presc::DIV8,
23 Prescaler::Div16 => vals::Presc::DIV16,
24 Prescaler::Div32 => vals::Presc::DIV32,
25 Prescaler::Div64 => vals::Presc::DIV64,
26 Prescaler::Div128 => vals::Presc::DIV128,
27 }
28 }
29}
30
31impl From<vals::Presc> for Prescaler {
32 fn from(prescaler: vals::Presc) -> Self {
33 match prescaler {
34 vals::Presc::DIV1 => Prescaler::Div1,
35 vals::Presc::DIV2 => Prescaler::Div2,
36 vals::Presc::DIV4 => Prescaler::Div4,
37 vals::Presc::DIV8 => Prescaler::Div8,
38 vals::Presc::DIV16 => Prescaler::Div16,
39 vals::Presc::DIV32 => Prescaler::Div32,
40 vals::Presc::DIV64 => Prescaler::Div64,
41 vals::Presc::DIV128 => Prescaler::Div128,
42 }
43 }
44}
45
46impl From<&Prescaler> for u32 {
47 fn from(prescaler: &Prescaler) -> Self {
48 match prescaler {
49 Prescaler::Div1 => 1,
50 Prescaler::Div2 => 2,
51 Prescaler::Div4 => 4,
52 Prescaler::Div8 => 8,
53 Prescaler::Div16 => 16,
54 Prescaler::Div32 => 32,
55 Prescaler::Div64 => 64,
56 Prescaler::Div128 => 128,
57 }
58 }
59}
60
61impl From<u32> for Prescaler {
62 fn from(prescaler: u32) -> Self {
63 match prescaler {
64 1 => Prescaler::Div1,
65 2 => Prescaler::Div2,
66 4 => Prescaler::Div4,
67 8 => Prescaler::Div8,
68 16 => Prescaler::Div16,
69 32 => Prescaler::Div32,
70 64 => Prescaler::Div64,
71 128 => Prescaler::Div128,
72 _ => unreachable!(),
73 }
74 }
75}
76
77impl Prescaler {
78 pub fn from_ticks(ticks: u32) -> Self {
79 // We need to scale down to a 16-bit range
80 (ticks >> 16).next_power_of_two().into()
81 }
82
83 pub fn scale_down(&self, ticks: u32) -> u16 {
84 (ticks / u32::from(self)).try_into().unwrap()
85 }
86
87 pub fn scale_up(&self, ticks: u16) -> u32 {
88 u32::from(self) * ticks as u32
89 }
90}
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs
index ca94a573d..c86c18e22 100644
--- a/embassy-stm32/src/opamp.rs
+++ b/embassy-stm32/src/opamp.rs
@@ -45,6 +45,7 @@ pub struct OpAmpOutput<'d, T: Instance> {
45/// OpAmp internal outputs, wired directly to ADC inputs. 45/// OpAmp internal outputs, wired directly to ADC inputs.
46/// 46///
47/// This struct can be used as an ADC input. 47/// This struct can be used as an ADC input.
48#[cfg(opamp_g4)]
48pub struct OpAmpInternalOutput<'d, T: Instance> { 49pub struct OpAmpInternalOutput<'d, T: Instance> {
49 _inner: &'d OpAmp<'d, T>, 50 _inner: &'d OpAmp<'d, T>,
50} 51}
@@ -80,11 +81,11 @@ impl<'d, T: Instance> OpAmp<'d, T> {
80 /// directly used as an ADC input. The opamp will be disabled when the 81 /// directly used as an ADC input. The opamp will be disabled when the
81 /// [`OpAmpOutput`] is dropped. 82 /// [`OpAmpOutput`] is dropped.
82 pub fn buffer_ext( 83 pub fn buffer_ext(
83 &'d mut self, 84 &mut self,
84 in_pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::Pin>, 85 in_pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::Pin>,
85 out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin> + 'd, 86 out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin>,
86 gain: OpAmpGain, 87 gain: OpAmpGain,
87 ) -> OpAmpOutput<'d, T> { 88 ) -> OpAmpOutput<'_, T> {
88 into_ref!(in_pin); 89 into_ref!(in_pin);
89 into_ref!(out_pin); 90 into_ref!(out_pin);
90 in_pin.set_as_analog(); 91 in_pin.set_as_analog();
@@ -119,9 +120,9 @@ impl<'d, T: Instance> OpAmp<'d, T> {
119 /// [`OpAmpOutput`] is dropped. 120 /// [`OpAmpOutput`] is dropped.
120 #[cfg(opamp_g4)] 121 #[cfg(opamp_g4)]
121 pub fn buffer_dac( 122 pub fn buffer_dac(
122 &'d mut self, 123 &mut self,
123 out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin> + 'd, 124 out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin>,
124 ) -> OpAmpOutput<'d, T> { 125 ) -> OpAmpOutput<'_, T> {
125 into_ref!(out_pin); 126 into_ref!(out_pin);
126 out_pin.set_as_analog(); 127 out_pin.set_as_analog();
127 128
@@ -147,10 +148,10 @@ impl<'d, T: Instance> OpAmp<'d, T> {
147 /// The opamp output will be disabled when it is dropped. 148 /// The opamp output will be disabled when it is dropped.
148 #[cfg(opamp_g4)] 149 #[cfg(opamp_g4)]
149 pub fn buffer_int( 150 pub fn buffer_int(
150 &'d mut self, 151 &mut self,
151 pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::Pin>, 152 pin: impl Peripheral<P = impl NonInvertingPin<T> + crate::gpio::Pin>,
152 gain: OpAmpGain, 153 gain: OpAmpGain,
153 ) -> OpAmpInternalOutput<'d, T> { 154 ) -> OpAmpInternalOutput<'_, T> {
154 into_ref!(pin); 155 into_ref!(pin);
155 pin.set_as_analog(); 156 pin.set_as_analog();
156 157
@@ -184,6 +185,7 @@ impl<'d, T: Instance> Drop for OpAmpOutput<'d, T> {
184 } 185 }
185} 186}
186 187
188#[cfg(opamp_g4)]
187impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> { 189impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> {
188 fn drop(&mut self) { 190 fn drop(&mut self) {
189 T::regs().csr().modify(|w| { 191 T::regs().csr().modify(|w| {
diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs
index f6eb0d17c..289bfa672 100644
--- a/embassy-stm32/src/ospi/mod.rs
+++ b/embassy-stm32/src/ospi/mod.rs
@@ -1060,10 +1060,6 @@ pub(crate) trait SealedInstance {
1060 const REGS: Regs; 1060 const REGS: Regs;
1061} 1061}
1062 1062
1063trait SealedWord {
1064 const CONFIG: u8;
1065}
1066
1067/// OSPI instance trait. 1063/// OSPI instance trait.
1068#[allow(private_bounds)] 1064#[allow(private_bounds)]
1069pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {} 1065pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral {}
@@ -1110,17 +1106,14 @@ impl<'d, T: Instance, M: PeriMode> GetConfig for Ospi<'d, T, M> {
1110 1106
1111/// Word sizes usable for OSPI. 1107/// Word sizes usable for OSPI.
1112#[allow(private_bounds)] 1108#[allow(private_bounds)]
1113pub trait Word: word::Word + SealedWord {} 1109pub trait Word: word::Word {}
1114 1110
1115macro_rules! impl_word { 1111macro_rules! impl_word {
1116 ($T:ty, $config:expr) => { 1112 ($T:ty) => {
1117 impl SealedWord for $T {
1118 const CONFIG: u8 = $config;
1119 }
1120 impl Word for $T {} 1113 impl Word for $T {}
1121 }; 1114 };
1122} 1115}
1123 1116
1124impl_word!(u8, 8); 1117impl_word!(u8);
1125impl_word!(u16, 16); 1118impl_word!(u16);
1126impl_word!(u32, 32); 1119impl_word!(u32);
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs
index 4e9c18594..9ccca8a2a 100644
--- a/embassy-stm32/src/rcc/bd.rs
+++ b/embassy-stm32/src/rcc/bd.rs
@@ -16,6 +16,7 @@ pub enum LseMode {
16 Bypass, 16 Bypass,
17} 17}
18 18
19#[derive(Clone, Copy)]
19pub struct LseConfig { 20pub struct LseConfig {
20 pub frequency: Hertz, 21 pub frequency: Hertz,
21 pub mode: LseMode, 22 pub mode: LseMode,
@@ -80,6 +81,7 @@ fn bdcr() -> Reg<Bdcr, RW> {
80 return crate::pac::RCC.csr1(); 81 return crate::pac::RCC.csr1();
81} 82}
82 83
84#[derive(Clone, Copy)]
83pub struct LsConfig { 85pub struct LsConfig {
84 pub rtc: RtcClockSource, 86 pub rtc: RtcClockSource,
85 pub lsi: bool, 87 pub lsi: bool,
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index 5adf37941..6712aedc4 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -37,6 +37,7 @@ pub struct Hsi {
37 37
38/// Clocks configutation 38/// Clocks configutation
39#[non_exhaustive] 39#[non_exhaustive]
40#[derive(Clone, Copy)]
40pub struct Config { 41pub struct Config {
41 /// HSI Configuration 42 /// HSI Configuration
42 pub hsi: Option<Hsi>, 43 pub hsi: Option<Hsi>,
diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs
index 63dc27bdd..60577b213 100644
--- a/embassy-stm32/src/rcc/f013.rs
+++ b/embassy-stm32/src/rcc/f013.rs
@@ -76,6 +76,7 @@ pub enum HrtimClockSource {
76 76
77/// Clocks configutation 77/// Clocks configutation
78#[non_exhaustive] 78#[non_exhaustive]
79#[derive(Clone, Copy)]
79pub struct Config { 80pub struct Config {
80 pub hsi: bool, 81 pub hsi: bool,
81 pub hse: Option<Hse>, 82 pub hse: Option<Hse>,
diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs
index 61f687d30..58056301a 100644
--- a/embassy-stm32/src/rcc/f247.rs
+++ b/embassy-stm32/src/rcc/f247.rs
@@ -63,6 +63,7 @@ pub struct Pll {
63/// Used to calculate flash waitstates. See 63/// Used to calculate flash waitstates. See
64/// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency 64/// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency
65#[cfg(stm32f2)] 65#[cfg(stm32f2)]
66#[derive(Clone, Copy)]
66pub enum VoltageScale { 67pub enum VoltageScale {
67 /// 2.7 to 3.6 V 68 /// 2.7 to 3.6 V
68 Range0, 69 Range0,
@@ -76,6 +77,7 @@ pub enum VoltageScale {
76 77
77/// Configuration of the core clocks 78/// Configuration of the core clocks
78#[non_exhaustive] 79#[non_exhaustive]
80#[derive(Clone, Copy)]
79pub struct Config { 81pub struct Config {
80 pub hsi: bool, 82 pub hsi: bool,
81 pub hse: Option<Hse>, 83 pub hse: Option<Hse>,
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index c2fa0ca39..c53c83b0e 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -33,6 +33,7 @@ pub struct Hse {
33/// Use this struct to configure the PLL source, input frequency, multiplication factor, and output 33/// Use this struct to configure the PLL source, input frequency, multiplication factor, and output
34/// dividers. Be sure to keep check the datasheet for your specific part for the appropriate 34/// dividers. Be sure to keep check the datasheet for your specific part for the appropriate
35/// frequency ranges for each of these settings. 35/// frequency ranges for each of these settings.
36#[derive(Clone, Copy)]
36pub struct Pll { 37pub struct Pll {
37 /// PLL Source clock selection. 38 /// PLL Source clock selection.
38 pub source: PllSource, 39 pub source: PllSource,
@@ -55,6 +56,7 @@ pub struct Pll {
55 56
56/// Clocks configutation 57/// Clocks configutation
57#[non_exhaustive] 58#[non_exhaustive]
59#[derive(Clone, Copy)]
58pub struct Config { 60pub struct Config {
59 /// HSI Enable 61 /// HSI Enable
60 pub hsi: bool, 62 pub hsi: bool,
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index c261c0fed..16561f908 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -32,6 +32,7 @@ pub struct Hse {
32/// Use this struct to configure the PLL source, input frequency, multiplication factor, and output 32/// Use this struct to configure the PLL source, input frequency, multiplication factor, and output
33/// dividers. Be sure to keep check the datasheet for your specific part for the appropriate 33/// dividers. Be sure to keep check the datasheet for your specific part for the appropriate
34/// frequency ranges for each of these settings. 34/// frequency ranges for each of these settings.
35#[derive(Clone, Copy)]
35pub struct Pll { 36pub struct Pll {
36 /// PLL Source clock selection. 37 /// PLL Source clock selection.
37 pub source: PllSource, 38 pub source: PllSource,
@@ -54,6 +55,7 @@ pub struct Pll {
54 55
55/// Clocks configutation 56/// Clocks configutation
56#[non_exhaustive] 57#[non_exhaustive]
58#[derive(Clone, Copy)]
57pub struct Config { 59pub struct Config {
58 /// HSI Enable 60 /// HSI Enable
59 pub hsi: bool, 61 pub hsi: bool,
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index e3c7dd158..376a0b454 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -120,7 +120,7 @@ impl From<TimerPrescaler> for Timpre {
120/// Power supply configuration 120/// Power supply configuration
121/// See RM0433 Rev 4 7.4 121/// See RM0433 Rev 4 7.4
122#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468, pwr_h7rs))] 122#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468, pwr_h7rs))]
123#[derive(PartialEq)] 123#[derive(Clone, Copy, PartialEq)]
124pub enum SupplyConfig { 124pub enum SupplyConfig {
125 /// Default power supply configuration. 125 /// Default power supply configuration.
126 /// V CORE Power Domains are supplied from the LDO according to VOS. 126 /// V CORE Power Domains are supplied from the LDO according to VOS.
@@ -180,6 +180,7 @@ pub enum SMPSSupplyVoltage {
180 180
181/// Configuration of the core clocks 181/// Configuration of the core clocks
182#[non_exhaustive] 182#[non_exhaustive]
183#[derive(Clone, Copy)]
183pub struct Config { 184pub struct Config {
184 pub hsi: Option<HSIPrescaler>, 185 pub hsi: Option<HSIPrescaler>,
185 pub hse: Option<Hse>, 186 pub hse: Option<Hse>,
diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs
index e9266c65b..6120d33be 100644
--- a/embassy-stm32/src/rcc/l.rs
+++ b/embassy-stm32/src/rcc/l.rs
@@ -30,6 +30,7 @@ pub struct Hse {
30} 30}
31 31
32/// Clocks configuration 32/// Clocks configuration
33#[derive(Clone, Copy)]
33pub struct Config { 34pub struct Config {
34 // base clock sources 35 // base clock sources
35 pub msi: Option<MSIRange>, 36 pub msi: Option<MSIRange>,
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 024c63cf5..8022a35a4 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -48,11 +48,22 @@ pub(crate) static mut REFCOUNT_STOP1: u32 = 0;
48/// May be read without a critical section 48/// May be read without a critical section
49pub(crate) static mut REFCOUNT_STOP2: u32 = 0; 49pub(crate) static mut REFCOUNT_STOP2: u32 = 0;
50 50
51#[cfg(not(feature = "_dual-core"))]
51/// Frozen clock frequencies 52/// Frozen clock frequencies
52/// 53///
53/// The existence of this value indicates that the clock configuration can no longer be changed 54/// The existence of this value indicates that the clock configuration can no longer be changed
54static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit(); 55static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit();
55 56
57#[cfg(feature = "_dual-core")]
58static CLOCK_FREQS_PTR: core::sync::atomic::AtomicPtr<MaybeUninit<Clocks>> =
59 core::sync::atomic::AtomicPtr::new(core::ptr::null_mut());
60
61#[cfg(feature = "_dual-core")]
62pub(crate) fn set_freqs_ptr(freqs: *mut MaybeUninit<Clocks>) {
63 CLOCK_FREQS_PTR.store(freqs, core::sync::atomic::Ordering::SeqCst);
64}
65
66#[cfg(not(feature = "_dual-core"))]
56/// Sets the clock frequencies 67/// Sets the clock frequencies
57/// 68///
58/// Safety: Sets a mutable global. 69/// Safety: Sets a mutable global.
@@ -61,11 +72,29 @@ pub(crate) unsafe fn set_freqs(freqs: Clocks) {
61 CLOCK_FREQS = MaybeUninit::new(freqs); 72 CLOCK_FREQS = MaybeUninit::new(freqs);
62} 73}
63 74
75#[cfg(feature = "_dual-core")]
76/// Sets the clock frequencies
77///
78/// Safety: Sets a mutable global.
79pub(crate) unsafe fn set_freqs(freqs: Clocks) {
80 debug!("rcc: {:?}", freqs);
81 CLOCK_FREQS_PTR
82 .load(core::sync::atomic::Ordering::SeqCst)
83 .write(MaybeUninit::new(freqs));
84}
85
86#[cfg(not(feature = "_dual-core"))]
64/// Safety: Reads a mutable global. 87/// Safety: Reads a mutable global.
65pub(crate) unsafe fn get_freqs() -> &'static Clocks { 88pub(crate) unsafe fn get_freqs() -> &'static Clocks {
66 CLOCK_FREQS.assume_init_ref() 89 CLOCK_FREQS.assume_init_ref()
67} 90}
68 91
92#[cfg(feature = "_dual-core")]
93/// Safety: Reads a mutable global.
94pub(crate) unsafe fn get_freqs() -> &'static Clocks {
95 unwrap!(CLOCK_FREQS_PTR.load(core::sync::atomic::Ordering::SeqCst).as_ref()).assume_init_ref()
96}
97
69pub(crate) trait SealedRccPeripheral { 98pub(crate) trait SealedRccPeripheral {
70 fn frequency() -> Hertz; 99 fn frequency() -> Hertz;
71 const RCC_INFO: RccInfo; 100 const RCC_INFO: RccInfo;
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index d6331f512..28545ca51 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -59,6 +59,7 @@ pub struct Pll {
59 pub divr: Option<PllDiv>, 59 pub divr: Option<PllDiv>,
60} 60}
61 61
62#[derive(Clone, Copy)]
62pub struct Config { 63pub struct Config {
63 // base clock sources 64 // base clock sources
64 pub msi: Option<MSIRange>, 65 pub msi: Option<MSIRange>,
diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs
index 8e1779d7c..1fee648d4 100644
--- a/embassy-stm32/src/rcc/wba.rs
+++ b/embassy-stm32/src/rcc/wba.rs
@@ -15,6 +15,7 @@ pub struct Hse {
15} 15}
16 16
17/// Clocks configuration 17/// Clocks configuration
18#[derive(Clone, Copy)]
18pub struct Config { 19pub struct Config {
19 // base clock sources 20 // base clock sources
20 pub hsi: bool, 21 pub hsi: bool,
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs
index a4ff1acbc..875eaa639 100644
--- a/embassy-stm32/src/rtc/low_power.rs
+++ b/embassy-stm32/src/rtc/low_power.rs
@@ -65,7 +65,7 @@ pub(crate) enum WakeupPrescaler {
65 Div16 = 16, 65 Div16 = 16,
66} 66}
67 67
68#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))] 68#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0))]
69impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel { 69impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
70 fn from(val: WakeupPrescaler) -> Self { 70 fn from(val: WakeupPrescaler) -> Self {
71 use crate::pac::rtc::vals::Wucksel; 71 use crate::pac::rtc::vals::Wucksel;
@@ -79,7 +79,7 @@ impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
79 } 79 }
80} 80}
81 81
82#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))] 82#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0))]
83impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler { 83impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
84 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { 84 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
85 use crate::pac::rtc::vals::Wucksel; 85 use crate::pac::rtc::vals::Wucksel;
@@ -132,7 +132,7 @@ impl Rtc {
132 132
133 // Panic if the rcc mod knows we're not using low-power rtc 133 // Panic if the rcc mod knows we're not using low-power rtc
134 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] 134 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
135 unsafe { crate::rcc::get_freqs() }.rtc.unwrap(); 135 unsafe { crate::rcc::get_freqs() }.rtc.to_hertz().unwrap();
136 136
137 let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64); 137 let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64);
138 let rtc_hz = Self::frequency().0 as u64; 138 let rtc_hz = Self::frequency().0 as u64;
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index a7f70b153..fe57cfe66 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -168,7 +168,7 @@ impl Rtc {
168 168
169 fn frequency() -> Hertz { 169 fn frequency() -> Hertz {
170 let freqs = unsafe { crate::rcc::get_freqs() }; 170 let freqs = unsafe { crate::rcc::get_freqs() };
171 freqs.rtc.unwrap() 171 freqs.rtc.to_hertz().unwrap()
172 } 172 }
173 173
174 /// Acquire a [`RtcTimeProvider`] instance. 174 /// Acquire a [`RtcTimeProvider`] instance.
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index cdc1cb299..5d9025bbe 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -131,10 +131,13 @@ impl SealedInstance for crate::peripherals::RTC {
131 #[cfg(all(feature = "low-power", stm32f4))] 131 #[cfg(all(feature = "low-power", stm32f4))]
132 const EXTI_WAKEUP_LINE: usize = 22; 132 const EXTI_WAKEUP_LINE: usize = 22;
133 133
134 #[cfg(all(feature = "low-power", stm32l4))]
135 const EXTI_WAKEUP_LINE: usize = 20;
136
134 #[cfg(all(feature = "low-power", stm32l0))] 137 #[cfg(all(feature = "low-power", stm32l0))]
135 const EXTI_WAKEUP_LINE: usize = 20; 138 const EXTI_WAKEUP_LINE: usize = 20;
136 139
137 #[cfg(all(feature = "low-power", stm32f4))] 140 #[cfg(all(feature = "low-power", any(stm32f4, stm32l4)))]
138 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; 141 type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
139 142
140 #[cfg(all(feature = "low-power", stm32l0))] 143 #[cfg(all(feature = "low-power", stm32l0))]
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
index c48d81b5f..63f48ace0 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -661,12 +661,12 @@ fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AfType, AfType) {
661 //sd is defined by tx/rx mode 661 //sd is defined by tx/rx mode
662 match tx_rx { 662 match tx_rx {
663 TxRx::Transmitter => AfType::output(OutputType::PushPull, Speed::VeryHigh), 663 TxRx::Transmitter => AfType::output(OutputType::PushPull, Speed::VeryHigh),
664 TxRx::Receiver => AfType::input(Pull::None), 664 TxRx::Receiver => AfType::input(Pull::Down), // Ensure mute level when no input is connected.
665 }, 665 },
666 //clocks (mclk, sck and fs) are defined by master/slave 666 //clocks (mclk, sck and fs) are defined by master/slave
667 match mode { 667 match mode {
668 Mode::Master => AfType::output(OutputType::PushPull, Speed::VeryHigh), 668 Mode::Master => AfType::output(OutputType::PushPull, Speed::VeryHigh),
669 Mode::Slave => AfType::input(Pull::None), 669 Mode::Slave => AfType::input(Pull::Down), // Ensure no clocks when no input is connected.
670 }, 670 },
671 ) 671 )
672} 672}
@@ -987,6 +987,21 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
987 ch.cr2().modify(|w| w.set_mute(value)); 987 ch.cr2().modify(|w| w.set_mute(value));
988 } 988 }
989 989
990 /// Determine the mute state of the receiver.
991 ///
992 /// Clears the mute state flag in the status register.
993 pub fn is_muted(&self) -> Result<bool, Error> {
994 match &self.ring_buffer {
995 RingBuffer::Readable(_) => {
996 let ch = T::REGS.ch(self.sub_block as usize);
997 let mute_state = ch.sr().read().mutedet();
998 ch.clrfr().write(|w| w.set_cmutedet(true));
999 Ok(mute_state)
1000 }
1001 _ => Err(Error::NotAReceiver),
1002 }
1003 }
1004
990 /// Write data to the SAI ringbuffer. 1005 /// Write data to the SAI ringbuffer.
991 /// 1006 ///
992 /// This appends the data to the buffer and returns immediately. The 1007 /// This appends the data to the buffer and returns immediately. The
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index ee5539518..ed344c412 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -94,6 +94,34 @@ impl DerefMut for DataBlock {
94 } 94 }
95} 95}
96 96
97/// Command Block buffer for SDMMC command transfers.
98///
99/// This is a 16-word array, exposed so that DMA commpatible memory can be used if required.
100#[derive(Debug, Clone, PartialEq, Eq)]
101#[cfg_attr(feature = "defmt", derive(defmt::Format))]
102pub struct CmdBlock(pub [u32; 16]);
103
104impl CmdBlock {
105 /// Creates a new instance of CmdBlock
106 pub const fn new() -> Self {
107 Self([0u32; 16])
108 }
109}
110
111impl Deref for CmdBlock {
112 type Target = [u32; 16];
113
114 fn deref(&self) -> &Self::Target {
115 &self.0
116 }
117}
118
119impl DerefMut for CmdBlock {
120 fn deref_mut(&mut self) -> &mut Self::Target {
121 &mut self.0
122 }
123}
124
97/// Errors 125/// Errors
98#[non_exhaustive] 126#[non_exhaustive]
99#[derive(Debug, Copy, Clone, PartialEq, Eq)] 127#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -292,6 +320,10 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> {
292 signalling: Signalling, 320 signalling: Signalling,
293 /// Card 321 /// Card
294 card: Option<Card>, 322 card: Option<Card>,
323
324 /// An optional buffer to be used for commands
325 /// This should be used if there are special memory location requirements for dma
326 cmd_block: Option<&'d mut CmdBlock>,
295} 327}
296 328
297const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh); 329const CLK_AF: AfType = AfType::output(OutputType::PushPull, Speed::VeryHigh);
@@ -495,6 +527,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
495 clock: SD_INIT_FREQ, 527 clock: SD_INIT_FREQ,
496 signalling: Default::default(), 528 signalling: Default::default(),
497 card: None, 529 card: None,
530 cmd_block: None,
498 } 531 }
499 } 532 }
500 533
@@ -531,8 +564,10 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
531 /// # Safety 564 /// # Safety
532 /// 565 ///
533 /// `buffer` must be valid for the whole transfer and word aligned 566 /// `buffer` must be valid for the whole transfer and word aligned
567 #[allow(unused_variables)]
534 fn prepare_datapath_read<'a>( 568 fn prepare_datapath_read<'a>(
535 &'a mut self, 569 config: &Config,
570 dma: &'a mut PeripheralRef<'d, Dma>,
536 buffer: &'a mut [u32], 571 buffer: &'a mut [u32],
537 length_bytes: u32, 572 length_bytes: u32,
538 block_size: u8, 573 block_size: u8,
@@ -544,15 +579,14 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
544 Self::wait_idle(); 579 Self::wait_idle();
545 Self::clear_interrupt_flags(); 580 Self::clear_interrupt_flags();
546 581
547 regs.dtimer() 582 regs.dtimer().write(|w| w.set_datatime(config.data_transfer_timeout));
548 .write(|w| w.set_datatime(self.config.data_transfer_timeout));
549 regs.dlenr().write(|w| w.set_datalength(length_bytes)); 583 regs.dlenr().write(|w| w.set_datalength(length_bytes));
550 584
551 #[cfg(sdmmc_v1)] 585 #[cfg(sdmmc_v1)]
552 let transfer = unsafe { 586 let transfer = unsafe {
553 let request = self.dma.request(); 587 let request = dma.request();
554 Transfer::new_read( 588 Transfer::new_read(
555 &mut self.dma, 589 dma,
556 request, 590 request,
557 regs.fifor().as_ptr() as *mut u32, 591 regs.fifor().as_ptr() as *mut u32,
558 buffer, 592 buffer,
@@ -692,13 +726,16 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
692 Signalling::SDR12 => 0xFF_FF00, 726 Signalling::SDR12 => 0xFF_FF00,
693 }; 727 };
694 728
695 let mut status = [0u32; 16]; 729 let status = match self.cmd_block.as_deref_mut() {
730 Some(x) => x,
731 None => &mut CmdBlock::new(),
732 };
696 733
697 // Arm `OnDrop` after the buffer, so it will be dropped first 734 // Arm `OnDrop` after the buffer, so it will be dropped first
698 let regs = T::regs(); 735 let regs = T::regs();
699 let on_drop = OnDrop::new(|| Self::on_drop()); 736 let on_drop = OnDrop::new(|| Self::on_drop());
700 737
701 let transfer = self.prepare_datapath_read(&mut status, 64, 6); 738 let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6);
702 InterruptHandler::<T>::data_interrupts(true); 739 InterruptHandler::<T>::data_interrupts(true);
703 Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6 740 Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6
704 741
@@ -770,16 +807,21 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
770 let card = self.card.as_mut().ok_or(Error::NoCard)?; 807 let card = self.card.as_mut().ok_or(Error::NoCard)?;
771 let rca = card.rca; 808 let rca = card.rca;
772 809
810 let cmd_block = match self.cmd_block.as_deref_mut() {
811 Some(x) => x,
812 None => &mut CmdBlock::new(),
813 };
814
773 Self::cmd(Cmd::set_block_length(64), false)?; // CMD16 815 Self::cmd(Cmd::set_block_length(64), false)?; // CMD16
774 Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP 816 Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP
775 817
776 let mut status = [0u32; 16]; 818 let status = cmd_block;
777 819
778 // Arm `OnDrop` after the buffer, so it will be dropped first 820 // Arm `OnDrop` after the buffer, so it will be dropped first
779 let regs = T::regs(); 821 let regs = T::regs();
780 let on_drop = OnDrop::new(|| Self::on_drop()); 822 let on_drop = OnDrop::new(|| Self::on_drop());
781 823
782 let transfer = self.prepare_datapath_read(&mut status, 64, 6); 824 let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6);
783 InterruptHandler::<T>::data_interrupts(true); 825 InterruptHandler::<T>::data_interrupts(true);
784 Self::cmd(Cmd::card_status(0), true)?; 826 Self::cmd(Cmd::card_status(0), true)?;
785 827
@@ -813,7 +855,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
813 for byte in status.iter_mut() { 855 for byte in status.iter_mut() {
814 *byte = u32::from_be(*byte); 856 *byte = u32::from_be(*byte);
815 } 857 }
816 self.card.as_mut().unwrap().status = status.into(); 858 self.card.as_mut().unwrap().status = status.0.into();
817 } 859 }
818 res 860 res
819 } 861 }
@@ -872,13 +914,17 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
872 Self::cmd(Cmd::set_block_length(8), false)?; // CMD16 914 Self::cmd(Cmd::set_block_length(8), false)?; // CMD16
873 Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; 915 Self::cmd(Cmd::app_cmd(card.rca << 16), false)?;
874 916
875 let mut scr = [0u32; 2]; 917 let cmd_block = match self.cmd_block.as_deref_mut() {
918 Some(x) => x,
919 None => &mut CmdBlock::new(),
920 };
921 let scr = &mut cmd_block.0[..2];
876 922
877 // Arm `OnDrop` after the buffer, so it will be dropped first 923 // Arm `OnDrop` after the buffer, so it will be dropped first
878 let regs = T::regs(); 924 let regs = T::regs();
879 let on_drop = OnDrop::new(|| Self::on_drop()); 925 let on_drop = OnDrop::new(|| Self::on_drop());
880 926
881 let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3); 927 let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, scr, 8, 3);
882 InterruptHandler::<T>::data_interrupts(true); 928 InterruptHandler::<T>::data_interrupts(true);
883 Self::cmd(Cmd::cmd51(), true)?; 929 Self::cmd(Cmd::cmd51(), true)?;
884 930
@@ -910,7 +956,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
910 drop(transfer); 956 drop(transfer);
911 957
912 unsafe { 958 unsafe {
913 let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]); 959 let scr_bytes = &*(&scr as *const _ as *const [u8; 8]);
914 card.scr = SCR(u64::from_be_bytes(*scr_bytes)); 960 card.scr = SCR(u64::from_be_bytes(*scr_bytes));
915 } 961 }
916 } 962 }
@@ -1002,8 +1048,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1002 Self::stop_datapath(); 1048 Self::stop_datapath();
1003 } 1049 }
1004 1050
1005 /// Initializes card (if present) and sets the bus at the 1051 /// Initializes card (if present) and sets the bus at the specified frequency.
1006 /// specified frequency.
1007 pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { 1052 pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> {
1008 let regs = T::regs(); 1053 let regs = T::regs();
1009 let ker_ck = T::frequency(); 1054 let ker_ck = T::frequency();
@@ -1143,6 +1188,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1143 } 1188 }
1144 } 1189 }
1145 } 1190 }
1191
1146 // Read status after signalling change 1192 // Read status after signalling change
1147 self.read_sd_status().await?; 1193 self.read_sd_status().await?;
1148 1194
@@ -1168,7 +1214,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1168 let regs = T::regs(); 1214 let regs = T::regs();
1169 let on_drop = OnDrop::new(|| Self::on_drop()); 1215 let on_drop = OnDrop::new(|| Self::on_drop());
1170 1216
1171 let transfer = self.prepare_datapath_read(buffer, 512, 9); 1217 let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, buffer, 512, 9);
1172 InterruptHandler::<T>::data_interrupts(true); 1218 InterruptHandler::<T>::data_interrupts(true);
1173 Self::cmd(Cmd::read_single_block(address), true)?; 1219 Self::cmd(Cmd::read_single_block(address), true)?;
1174 1220
@@ -1291,6 +1337,14 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
1291 pub fn clock(&self) -> Hertz { 1337 pub fn clock(&self) -> Hertz {
1292 self.clock 1338 self.clock
1293 } 1339 }
1340
1341 /// Set a specific cmd buffer rather than using the default stack allocated one.
1342 /// This is required if stack RAM cannot be used with DMA and usually manifests
1343 /// itself as an indefinite wait on a dma transfer because the dma peripheral
1344 /// cannot access the memory.
1345 pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) {
1346 self.cmd_block = Some(cmd_block)
1347 }
1294} 1348}
1295 1349
1296impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> { 1350impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> {
@@ -1457,3 +1511,44 @@ foreach_peripheral!(
1457 } 1511 }
1458 }; 1512 };
1459); 1513);
1514
1515impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> block_device_driver::BlockDevice<512> for Sdmmc<'d, T, Dma> {
1516 type Error = Error;
1517 type Align = aligned::A4;
1518
1519 async fn read(
1520 &mut self,
1521 mut block_address: u32,
1522 buf: &mut [aligned::Aligned<Self::Align, [u8; 512]>],
1523 ) -> Result<(), Self::Error> {
1524 // FIXME/TODO because of missing read_blocks multiple we have to do this one block at a time
1525 for block in buf.iter_mut() {
1526 // safety aligned by block device
1527 let block = unsafe { &mut *(block as *mut _ as *mut crate::sdmmc::DataBlock) };
1528 self.read_block(block_address, block).await?;
1529 block_address += 1;
1530 }
1531
1532 Ok(())
1533 }
1534
1535 async fn write(
1536 &mut self,
1537 mut block_address: u32,
1538 buf: &[aligned::Aligned<Self::Align, [u8; 512]>],
1539 ) -> Result<(), Self::Error> {
1540 // FIXME/TODO because of missing read_blocks multiple we have to do this one block at a time
1541 for block in buf.iter() {
1542 // safety aligned by block device
1543 let block = unsafe { &*(block as *const _ as *const crate::sdmmc::DataBlock) };
1544 self.write_block(block_address, block).await?;
1545 block_address += 1;
1546 }
1547
1548 Ok(())
1549 }
1550
1551 async fn size(&mut self) -> Result<u64, Self::Error> {
1552 Ok(self.card()?.size())
1553 }
1554}
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 656676d9f..20718147a 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -1282,6 +1282,7 @@ pub(crate) struct Info {
1282struct State {} 1282struct State {}
1283 1283
1284impl State { 1284impl State {
1285 #[allow(unused)]
1285 const fn new() -> Self { 1286 const fn new() -> Self {
1286 Self {} 1287 Self {}
1287 } 1288 }
diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs
index 17690aefc..802ff41ce 100644
--- a/embassy-stm32/src/time.rs
+++ b/embassy-stm32/src/time.rs
@@ -87,3 +87,39 @@ impl Div<Hertz> for Hertz {
87 self.0 / rhs.0 87 self.0 / rhs.0
88 } 88 }
89} 89}
90
91#[repr(C)]
92#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug, Default)]
93#[cfg_attr(feature = "defmt", derive(defmt::Format))]
94/// A variant on [Hertz] that acts as an `Option<Hertz>` that is smaller and repr C.
95///
96/// An `Option<Hertz>` can be `.into()`'d into this type and back.
97/// The only restriction is that that [Hertz] cannot have the value 0 since that's
98/// seen as the `None` variant.
99pub struct MaybeHertz(u32);
100
101impl MaybeHertz {
102 /// Same as calling the `.into()` function, but without type inference.
103 pub fn to_hertz(self) -> Option<Hertz> {
104 self.into()
105 }
106}
107
108impl From<Option<Hertz>> for MaybeHertz {
109 fn from(value: Option<Hertz>) -> Self {
110 match value {
111 Some(Hertz(0)) => panic!("Hertz cannot be 0"),
112 Some(Hertz(val)) => Self(val),
113 None => Self(0),
114 }
115 }
116}
117
118impl From<MaybeHertz> for Option<Hertz> {
119 fn from(value: MaybeHertz) -> Self {
120 match value {
121 MaybeHertz(0) => None,
122 MaybeHertz(val) => Some(Hertz(val)),
123 }
124 }
125}
diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index 5cb58e918..17240e6bc 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -40,7 +40,7 @@
40//! g7.set_io2(context.PE3, PinType::Sample); 40//! g7.set_io2(context.PE3, PinType::Sample);
41//! g7.set_io3(context.PE4, PinType::Channel); 41//! g7.set_io3(context.PE4, PinType::Channel);
42//! 42//!
43//! let mut touch_controller = tsc::Tsc::new( 43//! let mut touch_controller = tsc::Tsc::new_blocking(
44//! context.TSC, 44//! context.TSC,
45//! Some(g1), 45//! Some(g1),
46//! Some(g2), 46//! Some(g2),
@@ -188,7 +188,7 @@ pub struct Config {
188 pub spread_spectrum_prescaler: bool, 188 pub spread_spectrum_prescaler: bool,
189 /// Selects AHB clock divider used to generate pulse generator clk 189 /// Selects AHB clock divider used to generate pulse generator clk
190 pub pulse_generator_prescaler: PGPrescalerDivider, 190 pub pulse_generator_prescaler: PGPrescalerDivider,
191 /// Maximum number of charge tranfer pulses that can be generated before error 191 /// Maximum number of charge transfer pulses that can be generated before error
192 pub max_count_value: MaxCount, 192 pub max_count_value: MaxCount,
193 /// Defines config of all IOs when no ongoing acquisition 193 /// Defines config of all IOs when no ongoing acquisition
194 pub io_default_mode: bool, 194 pub io_default_mode: bool,
diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs
index 40aea75cb..ee0a2c7c1 100644
--- a/embassy-stm32/src/ucpd.rs
+++ b/embassy-stm32/src/ucpd.rs
@@ -27,7 +27,7 @@ use crate::dma::{ChannelAndRequest, TransferOptions};
27use crate::interrupt; 27use crate::interrupt;
28use crate::interrupt::typelevel::Interrupt; 28use crate::interrupt::typelevel::Interrupt;
29use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; 29use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode};
30pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState}; 30pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, Rxordset, TypecVstateCc as CcVState};
31use crate::rcc::{self, RccPeripheral}; 31use crate::rcc::{self, RccPeripheral};
32 32
33pub(crate) fn init( 33pub(crate) fn init(
@@ -86,6 +86,34 @@ pub enum CcPull {
86 Source3_0A, 86 Source3_0A,
87} 87}
88 88
89/// UCPD configuration
90#[non_exhaustive]
91#[derive(Copy, Clone, Debug)]
92pub struct Config {
93 /// Receive SOP packets
94 pub sop: bool,
95 /// Receive SOP' packets
96 pub sop_prime: bool,
97 /// Receive SOP'' packets
98 pub sop_double_prime: bool,
99 /// Receive SOP'_Debug packets
100 pub sop_prime_debug: bool,
101 /// Receive SOP''_Debug packets
102 pub sop_double_prime_debug: bool,
103}
104
105impl Default for Config {
106 fn default() -> Self {
107 Self {
108 sop: true,
109 sop_prime: false,
110 sop_double_prime: false,
111 sop_prime_debug: false,
112 sop_double_prime_debug: false,
113 }
114 }
115}
116
89/// UCPD driver. 117/// UCPD driver.
90pub struct Ucpd<'d, T: Instance> { 118pub struct Ucpd<'d, T: Instance> {
91 cc_phy: CcPhy<'d, T>, 119 cc_phy: CcPhy<'d, T>,
@@ -98,6 +126,7 @@ impl<'d, T: Instance> Ucpd<'d, T> {
98 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 126 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
99 cc1: impl Peripheral<P = impl Cc1Pin<T>> + 'd, 127 cc1: impl Peripheral<P = impl Cc1Pin<T>> + 'd,
100 cc2: impl Peripheral<P = impl Cc2Pin<T>> + 'd, 128 cc2: impl Peripheral<P = impl Cc2Pin<T>> + 'd,
129 config: Config,
101 ) -> Self { 130 ) -> Self {
102 into_ref!(cc1, cc2); 131 into_ref!(cc1, cc2);
103 cc1.set_as_analog(); 132 cc1.set_as_analog();
@@ -129,9 +158,15 @@ impl<'d, T: Instance> Ucpd<'d, T> {
129 // 1.75us * 17 = ~30us 158 // 1.75us * 17 = ~30us
130 w.set_ifrgap(17 - 1); 159 w.set_ifrgap(17 - 1);
131 160
132 // TODO: Currently only hard reset and SOP messages can be received.
133 // UNDOCUMENTED: This register can only be written while UCPDEN=0 (found by testing). 161 // UNDOCUMENTED: This register can only be written while UCPDEN=0 (found by testing).
134 w.set_rxordseten(0b1001); 162 let rxordset = (config.sop as u16) << 0
163 | (config.sop_prime as u16) << 1
164 | (config.sop_double_prime as u16) << 2
165 // Hard reset
166 | 0x1 << 3
167 | (config.sop_prime_debug as u16) << 4
168 | (config.sop_double_prime_debug as u16) << 5;
169 w.set_rxordseten(rxordset);
135 170
136 // Enable DMA 171 // Enable DMA
137 w.set_txdmaen(true); 172 w.set_txdmaen(true);
@@ -288,6 +323,22 @@ impl<'d, T: Instance> CcPhy<'d, T> {
288 } 323 }
289} 324}
290 325
326/// Receive SOP.
327#[derive(Debug, Clone, Copy)]
328#[cfg_attr(feature = "defmt", derive(defmt::Format))]
329pub enum Sop {
330 /// SOP
331 Sop,
332 /// SOP'
333 SopPrime,
334 /// SOP''
335 SopDoublePrime,
336 /// SOP'_Debug
337 SopPrimeDebug,
338 /// SOP''_Debug
339 SopDoublePrimeDebug,
340}
341
291/// Receive Error. 342/// Receive Error.
292#[derive(Debug, Clone, Copy)] 343#[derive(Debug, Clone, Copy)]
293#[cfg_attr(feature = "defmt", derive(defmt::Format))] 344#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -340,6 +391,13 @@ impl<'d, T: Instance> PdPhy<'d, T> {
340 /// 391 ///
341 /// Returns the number of received bytes or an error. 392 /// Returns the number of received bytes or an error.
342 pub async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, RxError> { 393 pub async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
394 self.receive_with_sop(buf).await.map(|(_sop, size)| size)
395 }
396
397 /// Receives SOP and a PD message into the provided buffer.
398 ///
399 /// Returns the start of packet type and number of received bytes or an error.
400 pub async fn receive_with_sop(&mut self, buf: &mut [u8]) -> Result<(Sop, usize), RxError> {
343 let r = T::REGS; 401 let r = T::REGS;
344 402
345 let dma = unsafe { 403 let dma = unsafe {
@@ -388,7 +446,18 @@ impl<'d, T: Instance> PdPhy<'d, T> {
388 } 446 }
389 } 447 }
390 448
391 Ok(r.rx_payszr().read().rxpaysz().into()) 449 let sop = match r.rx_ordsetr().read().rxordset() {
450 Rxordset::SOP => Sop::Sop,
451 Rxordset::SOPPRIME => Sop::SopPrime,
452 Rxordset::SOPDOUBLEPRIME => Sop::SopDoublePrime,
453 Rxordset::SOPPRIMEDEBUG => Sop::SopPrimeDebug,
454 Rxordset::SOPDOUBLEPRIMEDEBUG => Sop::SopDoublePrimeDebug,
455 Rxordset::CABLERESET => return Err(RxError::HardReset),
456 // Extension headers are not supported
457 _ => unreachable!(),
458 };
459
460 Ok((sop, r.rx_payszr().read().rxpaysz().into()))
392 } 461 }
393 462
394 fn enable_rx_interrupt(enable: bool) { 463 fn enable_rx_interrupt(enable: bool) {
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 33bc009a8..86f56eb7c 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -12,8 +12,8 @@ use embassy_sync::waitqueue::AtomicWaker;
12#[cfg(not(any(usart_v1, usart_v2)))] 12#[cfg(not(any(usart_v1, usart_v2)))]
13use super::DePin; 13use super::DePin;
14use super::{ 14use super::{
15 clear_interrupt_flags, configure, rdr, reconfigure, sr, tdr, Config, ConfigError, CtsPin, Error, Info, Instance, 15 clear_interrupt_flags, configure, rdr, reconfigure, send_break, sr, tdr, Config, ConfigError, CtsPin, Error, Info,
16 Regs, RtsPin, RxPin, TxPin, 16 Instance, Regs, RtsPin, RxPin, TxPin,
17}; 17};
18use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 18use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
19use crate::interrupt::{self, InterruptExt}; 19use crate::interrupt::{self, InterruptExt};
@@ -359,6 +359,11 @@ impl<'d> BufferedUart<'d> {
359 359
360 Ok(()) 360 Ok(())
361 } 361 }
362
363 /// Send break character
364 pub fn send_break(&self) {
365 self.tx.send_break()
366 }
362} 367}
363 368
364impl<'d> BufferedUartRx<'d> { 369impl<'d> BufferedUartRx<'d> {
@@ -436,6 +441,12 @@ impl<'d> BufferedUartRx<'d> {
436 } 441 }
437 } 442 }
438 443
444 /// we are ready to read if there is data in the buffer
445 fn read_ready(&mut self) -> Result<bool, Error> {
446 let state = self.state;
447 Ok(!state.rx_buf.is_empty())
448 }
449
439 /// Reconfigure the driver 450 /// Reconfigure the driver
440 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 451 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
441 reconfigure(self.info, self.kernel_clock, config)?; 452 reconfigure(self.info, self.kernel_clock, config)?;
@@ -532,6 +543,11 @@ impl<'d> BufferedUartTx<'d> {
532 543
533 Ok(()) 544 Ok(())
534 } 545 }
546
547 /// Send break character
548 pub fn send_break(&self) {
549 send_break(&self.info.regs);
550 }
535} 551}
536 552
537impl<'d> Drop for BufferedUartRx<'d> { 553impl<'d> Drop for BufferedUartRx<'d> {
@@ -610,6 +626,18 @@ impl<'d> embedded_io_async::Read for BufferedUartRx<'d> {
610 } 626 }
611} 627}
612 628
629impl<'d> embedded_io_async::ReadReady for BufferedUart<'d> {
630 fn read_ready(&mut self) -> Result<bool, Self::Error> {
631 BufferedUartRx::<'d>::read_ready(&mut self.rx)
632 }
633}
634
635impl<'d> embedded_io_async::ReadReady for BufferedUartRx<'d> {
636 fn read_ready(&mut self) -> Result<bool, Self::Error> {
637 Self::read_ready(self)
638 }
639}
640
613impl<'d> embedded_io_async::BufRead for BufferedUart<'d> { 641impl<'d> embedded_io_async::BufRead for BufferedUart<'d> {
614 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { 642 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
615 self.rx.fill_buf().await 643 self.rx.fill_buf().await
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 7ed3793a1..e7f2f890a 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -14,7 +14,7 @@ use embassy_sync::waitqueue::AtomicWaker;
14use futures_util::future::{select, Either}; 14use futures_util::future::{select, Either};
15 15
16use crate::dma::ChannelAndRequest; 16use crate::dma::ChannelAndRequest;
17use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; 17use crate::gpio::{self, AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed};
18use crate::interrupt::typelevel::Interrupt as _; 18use crate::interrupt::typelevel::Interrupt as _;
19use crate::interrupt::{self, Interrupt, InterruptExt}; 19use crate::interrupt::{self, Interrupt, InterruptExt};
20use crate::mode::{Async, Blocking, Mode}; 20use crate::mode::{Async, Blocking, Mode};
@@ -211,6 +211,30 @@ impl Default for Config {
211 } 211 }
212} 212}
213 213
214#[derive(Clone, Copy, PartialEq, Eq, Debug)]
215#[cfg_attr(feature = "defmt", derive(defmt::Format))]
216/// Half duplex IO mode
217pub enum HalfDuplexConfig {
218 /// Push pull allows for faster baudrates, may require series resistor
219 PushPull,
220 /// Open drain output using external pull up resistor
221 OpenDrainExternal,
222 #[cfg(not(gpio_v1))]
223 /// Open drain output using internal pull up resistor
224 OpenDrainInternal,
225}
226
227impl HalfDuplexConfig {
228 fn af_type(self) -> gpio::AfType {
229 match self {
230 HalfDuplexConfig::PushPull => AfType::output(OutputType::PushPull, Speed::Medium),
231 HalfDuplexConfig::OpenDrainExternal => AfType::output(OutputType::OpenDrain, Speed::Medium),
232 #[cfg(not(gpio_v1))]
233 HalfDuplexConfig::OpenDrainInternal => AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up),
234 }
235 }
236}
237
214/// Serial error 238/// Serial error
215#[derive(Debug, Eq, PartialEq, Copy, Clone)] 239#[derive(Debug, Eq, PartialEq, Copy, Clone)]
216#[cfg_attr(feature = "defmt", derive(defmt::Format))] 240#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -496,6 +520,11 @@ impl<'d, M: Mode> UartTx<'d, M> {
496 pub fn blocking_flush(&mut self) -> Result<(), Error> { 520 pub fn blocking_flush(&mut self) -> Result<(), Error> {
497 blocking_flush(self.info) 521 blocking_flush(self.info)
498 } 522 }
523
524 /// Send break character
525 pub fn send_break(&self) {
526 send_break(&self.info.regs);
527 }
499} 528}
500 529
501fn blocking_flush(info: &Info) -> Result<(), Error> { 530fn blocking_flush(info: &Info) -> Result<(), Error> {
@@ -510,6 +539,21 @@ fn blocking_flush(info: &Info) -> Result<(), Error> {
510 Ok(()) 539 Ok(())
511} 540}
512 541
542/// Send break character
543pub fn send_break(regs: &Regs) {
544 // Busy wait until previous break has been sent
545 #[cfg(any(usart_v1, usart_v2))]
546 while regs.cr1().read().sbk() {}
547 #[cfg(any(usart_v3, usart_v4))]
548 while regs.isr().read().sbkf() {}
549
550 // Send break right after completing the current character transmission
551 #[cfg(any(usart_v1, usart_v2))]
552 regs.cr1().modify(|w| w.set_sbk(true));
553 #[cfg(any(usart_v3, usart_v4))]
554 regs.rqr().write(|w| w.set_sbkrq(true));
555}
556
513impl<'d> UartRx<'d, Async> { 557impl<'d> UartRx<'d, Async> {
514 /// Create a new rx-only UART with no hardware flow control. 558 /// Create a new rx-only UART with no hardware flow control.
515 /// 559 ///
@@ -1029,8 +1073,9 @@ impl<'d> Uart<'d, Async> {
1029 /// (when it is available for your chip). There is no functional difference between these methods, as both 1073 /// (when it is available for your chip). There is no functional difference between these methods, as both
1030 /// allow bidirectional communication. 1074 /// allow bidirectional communication.
1031 /// 1075 ///
1032 /// The pin is always released when no data is transmitted. Thus, it acts as a standard 1076 /// The TX pin is always released when no data is transmitted. Thus, it acts as a standard
1033 /// I/O in idle or in reception. 1077 /// I/O in idle or in reception. It means that the I/O must be configured so that TX is
1078 /// configured as alternate function open-drain with an external pull-up
1034 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict 1079 /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict
1035 /// on the line must be managed by software (for instance by using a centralized arbiter). 1080 /// on the line must be managed by software (for instance by using a centralized arbiter).
1036 #[doc(alias("HDSEL"))] 1081 #[doc(alias("HDSEL"))]
@@ -1041,6 +1086,7 @@ impl<'d> Uart<'d, Async> {
1041 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 1086 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
1042 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 1087 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
1043 mut config: Config, 1088 mut config: Config,
1089 half_duplex: HalfDuplexConfig,
1044 ) -> Result<Self, ConfigError> { 1090 ) -> Result<Self, ConfigError> {
1045 #[cfg(not(any(usart_v1, usart_v2)))] 1091 #[cfg(not(any(usart_v1, usart_v2)))]
1046 { 1092 {
@@ -1051,7 +1097,7 @@ impl<'d> Uart<'d, Async> {
1051 Self::new_inner( 1097 Self::new_inner(
1052 peri, 1098 peri,
1053 None, 1099 None,
1054 new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), 1100 new_pin!(tx, half_duplex.af_type()),
1055 None, 1101 None,
1056 None, 1102 None,
1057 None, 1103 None,
@@ -1079,6 +1125,7 @@ impl<'d> Uart<'d, Async> {
1079 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 1125 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
1080 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 1126 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
1081 mut config: Config, 1127 mut config: Config,
1128 half_duplex: HalfDuplexConfig,
1082 ) -> Result<Self, ConfigError> { 1129 ) -> Result<Self, ConfigError> {
1083 config.swap_rx_tx = true; 1130 config.swap_rx_tx = true;
1084 config.half_duplex = true; 1131 config.half_duplex = true;
@@ -1087,7 +1134,7 @@ impl<'d> Uart<'d, Async> {
1087 peri, 1134 peri,
1088 None, 1135 None,
1089 None, 1136 None,
1090 new_pin!(rx, AfType::output(OutputType::PushPull, Speed::Medium)), 1137 new_pin!(rx, half_duplex.af_type()),
1091 None, 1138 None,
1092 None, 1139 None,
1093 new_dma!(tx_dma), 1140 new_dma!(tx_dma),
@@ -1192,6 +1239,7 @@ impl<'d> Uart<'d, Blocking> {
1192 peri: impl Peripheral<P = T> + 'd, 1239 peri: impl Peripheral<P = T> + 'd,
1193 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 1240 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
1194 mut config: Config, 1241 mut config: Config,
1242 half_duplex: HalfDuplexConfig,
1195 ) -> Result<Self, ConfigError> { 1243 ) -> Result<Self, ConfigError> {
1196 #[cfg(not(any(usart_v1, usart_v2)))] 1244 #[cfg(not(any(usart_v1, usart_v2)))]
1197 { 1245 {
@@ -1202,7 +1250,7 @@ impl<'d> Uart<'d, Blocking> {
1202 Self::new_inner( 1250 Self::new_inner(
1203 peri, 1251 peri,
1204 None, 1252 None,
1205 new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), 1253 new_pin!(tx, half_duplex.af_type()),
1206 None, 1254 None,
1207 None, 1255 None,
1208 None, 1256 None,
@@ -1227,6 +1275,7 @@ impl<'d> Uart<'d, Blocking> {
1227 peri: impl Peripheral<P = T> + 'd, 1275 peri: impl Peripheral<P = T> + 'd,
1228 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 1276 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
1229 mut config: Config, 1277 mut config: Config,
1278 half_duplex: HalfDuplexConfig,
1230 ) -> Result<Self, ConfigError> { 1279 ) -> Result<Self, ConfigError> {
1231 config.swap_rx_tx = true; 1280 config.swap_rx_tx = true;
1232 config.half_duplex = true; 1281 config.half_duplex = true;
@@ -1235,7 +1284,7 @@ impl<'d> Uart<'d, Blocking> {
1235 peri, 1284 peri,
1236 None, 1285 None,
1237 None, 1286 None,
1238 new_pin!(rx, AfType::output(OutputType::PushPull, Speed::Medium)), 1287 new_pin!(rx, half_duplex.af_type()),
1239 None, 1288 None,
1240 None, 1289 None,
1241 None, 1290 None,
@@ -1336,6 +1385,11 @@ impl<'d, M: Mode> Uart<'d, M> {
1336 pub fn split(self) -> (UartTx<'d, M>, UartRx<'d, M>) { 1385 pub fn split(self) -> (UartTx<'d, M>, UartRx<'d, M>) {
1337 (self.tx, self.rx) 1386 (self.tx, self.rx)
1338 } 1387 }
1388
1389 /// Send break character
1390 pub fn send_break(&self) {
1391 self.tx.send_break();
1392 }
1339} 1393}
1340 1394
1341fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(), ConfigError> { 1395fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(), ConfigError> {
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 8cf75933a..b0652046c 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -184,20 +184,6 @@ impl<'d> RingBufferedUartRx<'d> {
184 async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> { 184 async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> {
185 compiler_fence(Ordering::SeqCst); 185 compiler_fence(Ordering::SeqCst);
186 186
187 let mut dma_init = false;
188 // Future which completes when there is dma is half full or full
189 let dma = poll_fn(|cx| {
190 self.ring_buf.set_waker(cx.waker());
191
192 let status = match dma_init {
193 false => Poll::Pending,
194 true => Poll::Ready(()),
195 };
196
197 dma_init = true;
198 status
199 });
200
201 // Future which completes when idle line is detected 187 // Future which completes when idle line is detected
202 let s = self.state; 188 let s = self.state;
203 let uart = poll_fn(|cx| { 189 let uart = poll_fn(|cx| {
@@ -219,9 +205,23 @@ impl<'d> RingBufferedUartRx<'d> {
219 } 205 }
220 }); 206 });
221 207
222 match select(dma, uart).await { 208 let mut dma_init = false;
223 Either::Left(((), _)) => Ok(()), 209 // Future which completes when there is dma is half full or full
224 Either::Right((result, _)) => result, 210 let dma = poll_fn(|cx| {
211 self.ring_buf.set_waker(cx.waker());
212
213 let status = match dma_init {
214 false => Poll::Pending,
215 true => Poll::Ready(()),
216 };
217
218 dma_init = true;
219 status
220 });
221
222 match select(uart, dma).await {
223 Either::Left((result, _)) => result,
224 Either::Right(((), _)) => Ok(()),
225 } 225 }
226 } 226 }
227} 227}
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs
index 8ee8dcc36..e27b164e4 100644
--- a/embassy-stm32/src/usb/otg.rs
+++ b/embassy-stm32/src/usb/otg.rs
@@ -97,6 +97,55 @@ impl<'d, T: Instance> Driver<'d, T> {
97 } 97 }
98 } 98 }
99 99
100 /// Initializes USB OTG peripheral with external Full-speed PHY (usually, a High-speed PHY in Full-speed mode).
101 ///
102 /// # Arguments
103 ///
104 /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
105 /// Must be large enough to fit all OUT endpoint max packet sizes.
106 /// Endpoint allocation will fail if it is too small.
107 pub fn new_fs_ulpi(
108 _peri: impl Peripheral<P = T> + 'd,
109 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
110 ulpi_clk: impl Peripheral<P = impl UlpiClkPin<T>> + 'd,
111 ulpi_dir: impl Peripheral<P = impl UlpiDirPin<T>> + 'd,
112 ulpi_nxt: impl Peripheral<P = impl UlpiNxtPin<T>> + 'd,
113 ulpi_stp: impl Peripheral<P = impl UlpiStpPin<T>> + 'd,
114 ulpi_d0: impl Peripheral<P = impl UlpiD0Pin<T>> + 'd,
115 ulpi_d1: impl Peripheral<P = impl UlpiD1Pin<T>> + 'd,
116 ulpi_d2: impl Peripheral<P = impl UlpiD2Pin<T>> + 'd,
117 ulpi_d3: impl Peripheral<P = impl UlpiD3Pin<T>> + 'd,
118 ulpi_d4: impl Peripheral<P = impl UlpiD4Pin<T>> + 'd,
119 ulpi_d5: impl Peripheral<P = impl UlpiD5Pin<T>> + 'd,
120 ulpi_d6: impl Peripheral<P = impl UlpiD6Pin<T>> + 'd,
121 ulpi_d7: impl Peripheral<P = impl UlpiD7Pin<T>> + 'd,
122 ep_out_buffer: &'d mut [u8],
123 config: Config,
124 ) -> Self {
125 config_ulpi_pins!(
126 ulpi_clk, ulpi_dir, ulpi_nxt, ulpi_stp, ulpi_d0, ulpi_d1, ulpi_d2, ulpi_d3, ulpi_d4, ulpi_d5, ulpi_d6,
127 ulpi_d7
128 );
129
130 let regs = T::regs();
131
132 let instance = OtgInstance {
133 regs: T::regs(),
134 state: T::state(),
135 fifo_depth_words: T::FIFO_DEPTH_WORDS,
136 extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS,
137 endpoint_count: T::ENDPOINT_COUNT,
138 phy_type: PhyType::ExternalFullSpeed,
139 quirk_setup_late_cnak: quirk_setup_late_cnak(regs),
140 calculate_trdt_fn: calculate_trdt::<T>,
141 };
142
143 Self {
144 inner: OtgDriver::new(ep_out_buffer, instance, config),
145 phantom: PhantomData,
146 }
147 }
148
100 /// Initializes USB OTG peripheral with external High-Speed PHY. 149 /// Initializes USB OTG peripheral with external High-Speed PHY.
101 /// 150 ///
102 /// # Arguments 151 /// # Arguments
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 1d9d19a73..9384c8688 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -270,7 +270,7 @@ impl<'d, T: Instance> Driver<'d, T> {
270 #[cfg(feature = "time")] 270 #[cfg(feature = "time")]
271 embassy_time::block_for(embassy_time::Duration::from_millis(100)); 271 embassy_time::block_for(embassy_time::Duration::from_millis(100));
272 #[cfg(not(feature = "time"))] 272 #[cfg(not(feature = "time"))]
273 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 10); 273 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 10);
274 274
275 #[cfg(not(usb_v4))] 275 #[cfg(not(usb_v4))]
276 regs.btable().write(|w| w.set_btable(0)); 276 regs.btable().write(|w| w.set_btable(0));
diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md
index a283adc0c..8f2d26fe0 100644
--- a/embassy-sync/CHANGELOG.md
+++ b/embassy-sync/CHANGELOG.md
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased 8## Unreleased
9 9
10- Add LazyLock sync primitive.
11
10## 0.6.0 - 2024-05-29 12## 0.6.0 - 2024-05-29
11 13
12- Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `Channel`. 14- Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `Channel`.
diff --git a/embassy-sync/README.md b/embassy-sync/README.md
index 2c1c0cf68..97a663d6d 100644
--- a/embassy-sync/README.md
+++ b/embassy-sync/README.md
@@ -5,7 +5,7 @@ An [Embassy](https://embassy.dev) project.
5Synchronization primitives and data structures with async support: 5Synchronization primitives and data structures with async support:
6 6
7- [`Channel`](channel::Channel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. 7- [`Channel`](channel::Channel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer.
8- [`PriorityChannel`](channel::priority::PriorityChannel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. Higher priority items are shifted to the front of the channel. 8- [`PriorityChannel`](channel::priority_channel::PriorityChannel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. Higher priority items are shifted to the front of the channel.
9- [`PubSubChannel`](pubsub::PubSubChannel) - A broadcast channel (publish-subscribe) channel. Each message is received by all consumers. 9- [`PubSubChannel`](pubsub::PubSubChannel) - A broadcast channel (publish-subscribe) channel. Each message is received by all consumers.
10- [`Signal`](signal::Signal) - Signalling latest value to a single consumer. 10- [`Signal`](signal::Signal) - Signalling latest value to a single consumer.
11- [`Mutex`](mutex::Mutex) - Mutex for synchronizing state between asynchronous tasks. 11- [`Mutex`](mutex::Mutex) - Mutex for synchronizing state between asynchronous tasks.
@@ -13,6 +13,7 @@ Synchronization primitives and data structures with async support:
13- [`WakerRegistration`](waitqueue::WakerRegistration) - Utility to register and wake a `Waker`. 13- [`WakerRegistration`](waitqueue::WakerRegistration) - Utility to register and wake a `Waker`.
14- [`AtomicWaker`](waitqueue::AtomicWaker) - A variant of `WakerRegistration` accessible using a non-mut API. 14- [`AtomicWaker`](waitqueue::AtomicWaker) - A variant of `WakerRegistration` accessible using a non-mut API.
15- [`MultiWakerRegistration`](waitqueue::MultiWakerRegistration) - Utility registering and waking multiple `Waker`'s. 15- [`MultiWakerRegistration`](waitqueue::MultiWakerRegistration) - Utility registering and waking multiple `Waker`'s.
16- [`LazyLock`](lazy_lock::LazyLock) - A value which is initialized on the first access
16 17
17## Interoperability 18## Interoperability
18 19
diff --git a/embassy-sync/build_common.rs b/embassy-sync/build_common.rs
index 0487eb3c5..4f24e6d37 100644
--- a/embassy-sync/build_common.rs
+++ b/embassy-sync/build_common.rs
@@ -8,8 +8,6 @@
8 8
9use std::collections::HashSet; 9use std::collections::HashSet;
10use std::env; 10use std::env;
11use std::ffi::OsString;
12use std::process::Command;
13 11
14/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring 12/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
15/// them (`cargo:rust-check-cfg=cfg(X)`). 13/// them (`cargo:rust-check-cfg=cfg(X)`).
@@ -17,7 +15,6 @@ use std::process::Command;
17pub struct CfgSet { 15pub struct CfgSet {
18 enabled: HashSet<String>, 16 enabled: HashSet<String>,
19 declared: HashSet<String>, 17 declared: HashSet<String>,
20 emit_declared: bool,
21} 18}
22 19
23impl CfgSet { 20impl CfgSet {
@@ -25,7 +22,6 @@ impl CfgSet {
25 Self { 22 Self {
26 enabled: HashSet::new(), 23 enabled: HashSet::new(),
27 declared: HashSet::new(), 24 declared: HashSet::new(),
28 emit_declared: is_rustc_nightly(),
29 } 25 }
30 } 26 }
31 27
@@ -49,7 +45,7 @@ impl CfgSet {
49 /// 45 ///
50 /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid. 46 /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
51 pub fn declare(&mut self, cfg: impl AsRef<str>) { 47 pub fn declare(&mut self, cfg: impl AsRef<str>) {
52 if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared { 48 if self.declared.insert(cfg.as_ref().to_owned()) {
53 println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref()); 49 println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
54 } 50 }
55 } 51 }
@@ -69,21 +65,6 @@ impl CfgSet {
69 } 65 }
70} 66}
71 67
72fn is_rustc_nightly() -> bool {
73 if env::var_os("EMBASSY_FORCE_CHECK_CFG").is_some() {
74 return true;
75 }
76
77 let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
78
79 let output = Command::new(rustc)
80 .arg("--version")
81 .output()
82 .expect("failed to run `rustc --version`");
83
84 String::from_utf8_lossy(&output.stdout).contains("nightly")
85}
86
87/// Sets configs that describe the target platform. 68/// Sets configs that describe the target platform.
88pub fn set_target_cfgs(cfgs: &mut CfgSet) { 69pub fn set_target_cfgs(cfgs: &mut CfgSet) {
89 let target = env::var("TARGET").unwrap(); 70 let target = env::var("TARGET").unwrap();
diff --git a/embassy-sync/src/fmt.rs b/embassy-sync/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-sync/src/fmt.rs
+++ b/embassy-sync/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-sync/src/lazy_lock.rs b/embassy-sync/src/lazy_lock.rs
new file mode 100644
index 000000000..18e3c2019
--- /dev/null
+++ b/embassy-sync/src/lazy_lock.rs
@@ -0,0 +1,152 @@
1//! Synchronization primitive for initializing a value once, allowing others to get a reference to the value.
2
3use core::cell::UnsafeCell;
4use core::mem::ManuallyDrop;
5use core::sync::atomic::{AtomicBool, Ordering};
6
7/// The `LazyLock` is a synchronization primitive that allows for
8/// initializing a value once, and allowing others to obtain a
9/// reference to the value. This is useful for lazy initialization of
10/// a static value.
11///
12/// # Example
13/// ```
14/// use futures_executor::block_on;
15/// use embassy_sync::lazy_lock::LazyLock;
16///
17/// // Define a static value that will be lazily initialized
18/// // at runtime at the first access.
19/// static VALUE: LazyLock<u32> = LazyLock::new(|| 20);
20///
21/// let reference = VALUE.get();
22/// assert_eq!(reference, &20);
23/// ```
24pub struct LazyLock<T, F = fn() -> T> {
25 init: AtomicBool,
26 data: UnsafeCell<Data<T, F>>,
27}
28
29union Data<T, F> {
30 value: ManuallyDrop<T>,
31 f: ManuallyDrop<F>,
32}
33
34unsafe impl<T, F> Sync for LazyLock<T, F> {}
35
36impl<T, F: FnOnce() -> T> LazyLock<T, F> {
37 /// Create a new uninitialized `StaticLock`.
38 pub const fn new(init_fn: F) -> Self {
39 Self {
40 init: AtomicBool::new(false),
41 data: UnsafeCell::new(Data {
42 f: ManuallyDrop::new(init_fn),
43 }),
44 }
45 }
46
47 /// Get a reference to the underlying value, initializing it if it
48 /// has not been done already.
49 #[inline]
50 pub fn get(&self) -> &T {
51 self.ensure_init_fast();
52 unsafe { &(*self.data.get()).value }
53 }
54
55 /// Consume the `LazyLock`, returning the underlying value. The
56 /// initialization function will be called if it has not been
57 /// already.
58 #[inline]
59 pub fn into_inner(self) -> T {
60 self.ensure_init_fast();
61 let this = ManuallyDrop::new(self);
62 let data = unsafe { core::ptr::read(&this.data) }.into_inner();
63
64 ManuallyDrop::into_inner(unsafe { data.value })
65 }
66
67 /// Initialize the `LazyLock` if it has not been initialized yet.
68 /// This function is a fast track to [`Self::ensure_init`]
69 /// which does not require a critical section in most cases when
70 /// the value has been initialized already.
71 /// When this function returns, `self.data` is guaranteed to be
72 /// initialized and visible on the current core.
73 #[inline]
74 fn ensure_init_fast(&self) {
75 if !self.init.load(Ordering::Acquire) {
76 self.ensure_init();
77 }
78 }
79
80 /// Initialize the `LazyLock` if it has not been initialized yet.
81 /// When this function returns, `self.data` is guaranteed to be
82 /// initialized and visible on the current core.
83 fn ensure_init(&self) {
84 critical_section::with(|_| {
85 if !self.init.load(Ordering::Acquire) {
86 let data = unsafe { &mut *self.data.get() };
87 let f = unsafe { ManuallyDrop::take(&mut data.f) };
88 let value = f();
89 data.value = ManuallyDrop::new(value);
90
91 self.init.store(true, Ordering::Release);
92 }
93 });
94 }
95}
96
97impl<T, F> Drop for LazyLock<T, F> {
98 fn drop(&mut self) {
99 if self.init.load(Ordering::Acquire) {
100 unsafe { ManuallyDrop::drop(&mut self.data.get_mut().value) };
101 } else {
102 unsafe { ManuallyDrop::drop(&mut self.data.get_mut().f) };
103 }
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use core::sync::atomic::{AtomicU32, Ordering};
110
111 use super::*;
112
113 #[test]
114 fn test_lazy_lock() {
115 static VALUE: LazyLock<u32> = LazyLock::new(|| 20);
116 let reference = VALUE.get();
117 assert_eq!(reference, &20);
118 }
119 #[test]
120 fn test_lazy_lock_into_inner() {
121 let lazy: LazyLock<u32> = LazyLock::new(|| 20);
122 let value = lazy.into_inner();
123 assert_eq!(value, 20);
124 }
125
126 static DROP_CHECKER: AtomicU32 = AtomicU32::new(0);
127 struct DropCheck;
128
129 impl Drop for DropCheck {
130 fn drop(&mut self) {
131 DROP_CHECKER.fetch_add(1, Ordering::Acquire);
132 }
133 }
134
135 #[test]
136 fn test_lazy_drop() {
137 let lazy: LazyLock<DropCheck> = LazyLock::new(|| DropCheck);
138 assert_eq!(DROP_CHECKER.load(Ordering::Acquire), 0);
139 lazy.get();
140 drop(lazy);
141 assert_eq!(DROP_CHECKER.load(Ordering::Acquire), 1);
142
143 let dropper = DropCheck;
144 let lazy_fn: LazyLock<u32, _> = LazyLock::new(move || {
145 let _a = dropper;
146 20
147 });
148 assert_eq!(DROP_CHECKER.load(Ordering::Acquire), 1);
149 drop(lazy_fn);
150 assert_eq!(DROP_CHECKER.load(Ordering::Acquire), 2);
151 }
152}
diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs
index a5eee8d02..014bf1d06 100644
--- a/embassy-sync/src/lib.rs
+++ b/embassy-sync/src/lib.rs
@@ -12,6 +12,7 @@ mod ring_buffer;
12 12
13pub mod blocking_mutex; 13pub mod blocking_mutex;
14pub mod channel; 14pub mod channel;
15pub mod lazy_lock;
15pub mod mutex; 16pub mod mutex;
16pub mod once_lock; 17pub mod once_lock;
17pub mod pipe; 18pub mod pipe;
diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs
index 565597935..8000a9dcb 100644
--- a/embassy-time-driver/src/lib.rs
+++ b/embassy-time-driver/src/lib.rs
@@ -98,7 +98,7 @@ pub trait Driver: Send + Sync + 'static {
98 /// 98 ///
99 /// Implementations MUST ensure that: 99 /// Implementations MUST ensure that:
100 /// - This is guaranteed to be monotonic, i.e. a call to now() will always return 100 /// - This is guaranteed to be monotonic, i.e. a call to now() will always return
101 /// a greater or equal value than earler calls. Time can't "roll backwards". 101 /// a greater or equal value than earlier calls. Time can't "roll backwards".
102 /// - It "never" overflows. It must not overflow in a sufficiently long time frame, say 102 /// - It "never" overflows. It must not overflow in a sufficiently long time frame, say
103 /// in 10_000 years (Human civilization is likely to already have self-destructed 103 /// in 10_000 years (Human civilization is likely to already have self-destructed
104 /// 10_000 years from now.). This means if your hardware only has 16bit/32bit timers 104 /// 10_000 years from now.). This means if your hardware only has 16bit/32bit timers
@@ -113,24 +113,52 @@ pub trait Driver: Send + Sync + 'static {
113 /// It is UB to make the alarm fire before setting a callback. 113 /// It is UB to make the alarm fire before setting a callback.
114 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle>; 114 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle>;
115 115
116 /// Sets the callback function to be called when the alarm triggers. 116 /// Set the callback function to be called when the alarm triggers.
117 /// The callback may be called from any context (interrupt or thread mode). 117 /// The callback may be called from any context (interrupt or thread mode).
118 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()); 118 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ());
119 119
120 /// Sets an alarm at the given timestamp. When the current timestamp reaches the alarm 120 /// Set an alarm at the given timestamp.
121 /// timestamp, the provided callback function will be called.
122 /// 121 ///
123 /// The `Driver` implementation should guarantee that the alarm callback is never called synchronously from `set_alarm`. 122 /// ## Behavior
124 /// Rather - if `timestamp` is already in the past - `false` should be returned and alarm should not be set,
125 /// or alternatively, the driver should return `true` and arrange to call the alarm callback as soon as possible, but not synchronously.
126 /// There is a rare third possibility that the alarm was barely in the future, and by the time it was enabled, it had slipped into the
127 /// past. This is can be detected by double-checking that the alarm is still in the future after enabling it; if it isn't, `false`
128 /// should also be returned to indicate that the callback may have been called already by the alarm, but it is not guaranteed, so the
129 /// caller should also call the callback, just like in the more common `false` case. (Note: This requires idempotency of the callback.)
130 /// 123 ///
131 /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp. 124 /// If `timestamp` is in the future, `set_alarm` schedules calling the callback function
125 /// at that time, and returns `true`.
132 /// 126 ///
133 /// Only one alarm can be active at a time for each AlarmHandle. This overwrites any previously-set alarm if any. 127 /// If `timestamp` is in the past, `set_alarm` has two allowed behaviors. Implementations can pick whether to:
128 ///
129 /// - Schedule calling the callback function "immediately", as if the requested timestamp was "now+epsilon" and return `true`, or
130 /// - Not schedule the callback, and return `false`.
131 ///
132 /// Callers must ensure to behave correctly with either behavior.
133 ///
134 /// When callback is called, it is guaranteed that `now()` will return a value greater than or equal to `timestamp`.
135 ///
136 /// ## Reentrancy
137 ///
138 /// Calling the callback from `set_alarm` synchronously is not allowed. If the implementation chooses the first option above,
139 /// it must still call the callback from another context (i.e. an interrupt handler or background thread), it's not allowed
140 /// to call it synchronously in the context `set_alarm` is running.
141 ///
142 /// The reason for the above is callers are explicitly permitted to do both of:
143 /// - Lock a mutex in the alarm callback.
144 /// - Call `set_alarm` while having that mutex locked.
145 ///
146 /// If `set_alarm` called the callback synchronously, it'd cause a deadlock or panic because it'd cause the
147 /// mutex to be locked twice reentrantly in the same context.
148 ///
149 /// ## Overwriting alarms
150 ///
151 /// Only one alarm can be active at a time for each `AlarmHandle`. This overwrites any previously-set alarm if any.
152 ///
153 /// ## Unsetting the alarm
154 ///
155 /// There is no `unset_alarm` API. Instead, callers can call `set_alarm` with `timestamp` set to `u64::MAX`.
156 ///
157 /// This allows for more efficient implementations, since they don't need to distinguish between the "alarm set" and
158 /// "alarm not set" cases, thanks to the fact "Alarm set for u64::MAX" is effectively equivalent for "alarm not set".
159 ///
160 /// This means implementations need to be careful to avoid timestamp overflows. The recommendation is to make `timestamp`
161 /// be in the same units as hardware ticks to avoid any conversions, which makes avoiding overflow easier.
134 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool; 162 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool;
135} 163}
136 164
diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md
index 75e17fd63..3b4d93387 100644
--- a/embassy-time/CHANGELOG.md
+++ b/embassy-time/CHANGELOG.md
@@ -7,7 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased 8## Unreleased
9 9
10## 0.4.0 - 2024-01-11 10## 0.3.2 - 2024-08-05
11
12- Implement with_timeout()/with_deadline() method style call on Future
13- Add collapse_debuginfo to fmt.rs macros.
14
15## 0.3.1 - 2024-01-11
11 16
12- Add with\_deadline convenience function and example 17- Add with\_deadline convenience function and example
13- Implement Clone for Delay 18- Implement Clone for Delay
diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml
index 5d5bd8b23..c3b4e4e3a 100644
--- a/embassy-time/Cargo.toml
+++ b/embassy-time/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-time" 2name = "embassy-time"
3version = "0.3.1" 3version = "0.3.2"
4edition = "2021" 4edition = "2021"
5description = "Instant and Duration for embedded no-std systems, with async timer support" 5description = "Instant and Duration for embedded no-std systems, with async timer support"
6repository = "https://github.com/embassy-rs/embassy" 6repository = "https://github.com/embassy-rs/embassy"
@@ -431,4 +431,4 @@ wasm-timer = { version = "0.2.5", optional = true }
431[dev-dependencies] 431[dev-dependencies]
432serial_test = "0.9" 432serial_test = "0.9"
433critical-section = { version = "1.1", features = ["std"] } 433critical-section = { version = "1.1", features = ["std"] }
434embassy-executor = { version = "0.5.0", path = "../embassy-executor" } 434embassy-executor = { version = "0.6.0", path = "../embassy-executor" }
diff --git a/embassy-time/src/fmt.rs b/embassy-time/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-time/src/fmt.rs
+++ b/embassy-time/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml
index 968fbec74..481b2699a 100644
--- a/embassy-usb-dfu/Cargo.toml
+++ b/embassy-usb-dfu/Cargo.toml
@@ -31,11 +31,11 @@ log = { version = "0.4.17", optional = true }
31 31
32bitflags = "2.4.1" 32bitflags = "2.4.1"
33cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } 33cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true }
34embassy-boot = { version = "0.2.0", path = "../embassy-boot" } 34embassy-boot = { version = "0.3.0", path = "../embassy-boot" }
35embassy-futures = { version = "0.1.1", path = "../embassy-futures" } 35embassy-futures = { version = "0.1.1", path = "../embassy-futures" }
36embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 36embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
37embassy-time = { version = "0.3.1", path = "../embassy-time" } 37embassy-time = { version = "0.3.2", path = "../embassy-time" }
38embassy-usb = { version = "0.2.0", path = "../embassy-usb", default-features = false } 38embassy-usb = { version = "0.3.0", path = "../embassy-usb", default-features = false }
39embedded-storage = { version = "0.3.1" } 39embedded-storage = { version = "0.3.1" }
40esp32c3-hal = { version = "0.13.0", optional = true, default-features = false } 40esp32c3-hal = { version = "0.13.0", optional = true, default-features = false }
41 41
diff --git a/embassy-usb-dfu/src/fmt.rs b/embassy-usb-dfu/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-usb-dfu/src/fmt.rs
+++ b/embassy-usb-dfu/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-usb-logger/Cargo.toml b/embassy-usb-logger/Cargo.toml
index 62b4ee723..d796e5d8e 100644
--- a/embassy-usb-logger/Cargo.toml
+++ b/embassy-usb-logger/Cargo.toml
@@ -15,7 +15,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-l
15target = "thumbv7em-none-eabi" 15target = "thumbv7em-none-eabi"
16 16
17[dependencies] 17[dependencies]
18embassy-usb = { version = "0.2.0", path = "../embassy-usb" } 18embassy-usb = { version = "0.3.0", path = "../embassy-usb" }
19embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 19embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
20embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 20embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
21log = "0.4" 21log = "0.4"
diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs
index 34d1ca663..11188b4ef 100644
--- a/embassy-usb-logger/src/lib.rs
+++ b/embassy-usb-logger/src/lib.rs
@@ -41,12 +41,24 @@ pub const MAX_PACKET_SIZE: u8 = 64;
41/// The logger handle, which contains a pipe with configurable size for buffering log messages. 41/// The logger handle, which contains a pipe with configurable size for buffering log messages.
42pub struct UsbLogger<const N: usize> { 42pub struct UsbLogger<const N: usize> {
43 buffer: Pipe<CS, N>, 43 buffer: Pipe<CS, N>,
44 custom_style: Option<fn(&Record, &mut Writer<'_, N>) -> ()>,
44} 45}
45 46
46impl<const N: usize> UsbLogger<N> { 47impl<const N: usize> UsbLogger<N> {
47 /// Create a new logger instance. 48 /// Create a new logger instance.
48 pub const fn new() -> Self { 49 pub const fn new() -> Self {
49 Self { buffer: Pipe::new() } 50 Self {
51 buffer: Pipe::new(),
52 custom_style: None,
53 }
54 }
55
56 /// Create a new logger instance with a custom formatter.
57 pub const fn with_custom_style(custom_style: fn(&Record, &mut Writer<'_, N>) -> ()) -> Self {
58 Self {
59 buffer: Pipe::new(),
60 custom_style: Some(custom_style),
61 }
50 } 62 }
51 63
52 /// Run the USB logger using the state and USB driver. Never returns. 64 /// Run the USB logger using the state and USB driver. Never returns.
@@ -137,14 +149,19 @@ impl<const N: usize> log::Log for UsbLogger<N> {
137 149
138 fn log(&self, record: &Record) { 150 fn log(&self, record: &Record) {
139 if self.enabled(record.metadata()) { 151 if self.enabled(record.metadata()) {
140 let _ = write!(Writer(&self.buffer), "{}\r\n", record.args()); 152 if let Some(custom_style) = self.custom_style {
153 custom_style(record, &mut Writer(&self.buffer));
154 } else {
155 let _ = write!(Writer(&self.buffer), "{}\r\n", record.args());
156 }
141 } 157 }
142 } 158 }
143 159
144 fn flush(&self) {} 160 fn flush(&self) {}
145} 161}
146 162
147struct Writer<'d, const N: usize>(&'d Pipe<CS, N>); 163/// A writer that writes to the USB logger buffer.
164pub struct Writer<'d, const N: usize>(&'d Pipe<CS, N>);
148 165
149impl<'d, const N: usize> core::fmt::Write for Writer<'d, N> { 166impl<'d, const N: usize> core::fmt::Write for Writer<'d, N> {
150 fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { 167 fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
@@ -210,3 +227,33 @@ macro_rules! with_class {
210 LOGGER.create_future_from_class($p) 227 LOGGER.create_future_from_class($p)
211 }}; 228 }};
212} 229}
230
231/// Initialize the USB serial logger from a serial class and return the future to run it.
232/// This version of the macro allows for a custom style function to be passed in.
233/// The custom style function will be called for each log record and is responsible for writing the log message to the buffer.
234///
235/// Arguments specify the buffer size, log level, the serial class and the custom style function, respectively.
236///
237/// # Usage
238///
239/// ```
240/// let log_fut = embassy_usb_logger::with_custom_style!(1024, log::LevelFilter::Info, logger_class, |record, writer| {
241/// use core::fmt::Write;
242/// let level = record.level().as_str();
243/// write!(writer, "[{level}] {}\r\n", record.args()).unwrap();
244/// });
245/// ```
246///
247/// # Safety
248///
249/// This macro should only be invoked only once since it is setting the global logging state of the application.
250#[macro_export]
251macro_rules! with_custom_style {
252 ( $x:expr, $l:expr, $p:ident, $s:expr ) => {{
253 static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::with_custom_style($s);
254 unsafe {
255 let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l));
256 }
257 LOGGER.create_future_from_class($p)
258 }};
259}
diff --git a/embassy-usb-synopsys-otg/src/fmt.rs b/embassy-usb-synopsys-otg/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-usb-synopsys-otg/src/fmt.rs
+++ b/embassy-usb-synopsys-otg/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs
index b90e059f6..5fb82db42 100644
--- a/embassy-usb-synopsys-otg/src/lib.rs
+++ b/embassy-usb-synopsys-otg/src/lib.rs
@@ -179,6 +179,8 @@ pub enum PhyType {
179 /// 179 ///
180 /// Available on a few STM32 chips. 180 /// Available on a few STM32 chips.
181 InternalHighSpeed, 181 InternalHighSpeed,
182 /// External ULPI Full-Speed PHY (or High-Speed PHY in Full-Speed mode)
183 ExternalFullSpeed,
182 /// External ULPI High-Speed PHY 184 /// External ULPI High-Speed PHY
183 ExternalHighSpeed, 185 ExternalHighSpeed,
184} 186}
@@ -188,14 +190,14 @@ impl PhyType {
188 pub fn internal(&self) -> bool { 190 pub fn internal(&self) -> bool {
189 match self { 191 match self {
190 PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true, 192 PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true,
191 PhyType::ExternalHighSpeed => false, 193 PhyType::ExternalHighSpeed | PhyType::ExternalFullSpeed => false,
192 } 194 }
193 } 195 }
194 196
195 /// Get whether this PHY is any of the high-speed types. 197 /// Get whether this PHY is any of the high-speed types.
196 pub fn high_speed(&self) -> bool { 198 pub fn high_speed(&self) -> bool {
197 match self { 199 match self {
198 PhyType::InternalFullSpeed => false, 200 PhyType::InternalFullSpeed | PhyType::ExternalFullSpeed => false,
199 PhyType::ExternalHighSpeed | PhyType::InternalHighSpeed => true, 201 PhyType::ExternalHighSpeed | PhyType::InternalHighSpeed => true,
200 } 202 }
201 } 203 }
@@ -204,6 +206,7 @@ impl PhyType {
204 match self { 206 match self {
205 PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL, 207 PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL,
206 PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED, 208 PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED,
209 PhyType::ExternalFullSpeed => vals::Dspd::FULL_SPEED_EXTERNAL,
207 PhyType::ExternalHighSpeed => vals::Dspd::HIGH_SPEED, 210 PhyType::ExternalHighSpeed => vals::Dspd::HIGH_SPEED,
208 } 211 }
209 } 212 }
@@ -382,8 +385,8 @@ impl<'d, const MAX_EP_COUNT: usize> Driver<'d, MAX_EP_COUNT> {
382 } 385 }
383 386
384 let eps = match D::dir() { 387 let eps = match D::dir() {
385 Direction::Out => &mut self.ep_out, 388 Direction::Out => &mut self.ep_out[..self.instance.endpoint_count],
386 Direction::In => &mut self.ep_in, 389 Direction::In => &mut self.ep_in[..self.instance.endpoint_count],
387 }; 390 };
388 391
389 // Find free endpoint slot 392 // Find free endpoint slot
diff --git a/embassy-usb-synopsys-otg/src/otg_v1.rs b/embassy-usb-synopsys-otg/src/otg_v1.rs
index 111bc4a63..a8530980c 100644
--- a/embassy-usb-synopsys-otg/src/otg_v1.rs
+++ b/embassy-usb-synopsys-otg/src/otg_v1.rs
@@ -272,6 +272,12 @@ impl Otg {
272 assert!(n < 12usize); 272 assert!(n < 12usize);
273 unsafe { Reg::from_ptr(self.ptr.add(0x0510usize + n * 32usize) as _) } 273 unsafe { Reg::from_ptr(self.ptr.add(0x0510usize + n * 32usize) as _) }
274 } 274 }
275 #[doc = "Host channel DMA address register"]
276 #[inline(always)]
277 pub const fn hcdma(self, n: usize) -> Reg<u32, RW> {
278 assert!(n < 12usize);
279 unsafe { Reg::from_ptr(self.ptr.add(0x0514usize + n * 32usize) as _) }
280 }
275 #[doc = "Device configuration register"] 281 #[doc = "Device configuration register"]
276 #[inline(always)] 282 #[inline(always)]
277 pub const fn dcfg(self) -> Reg<regs::Dcfg, RW> { 283 pub const fn dcfg(self) -> Reg<regs::Dcfg, RW> {
@@ -364,6 +370,12 @@ impl Otg {
364 assert!(n < 16usize); 370 assert!(n < 16usize);
365 unsafe { Reg::from_ptr(self.ptr.add(0x0b10usize + n * 32usize) as _) } 371 unsafe { Reg::from_ptr(self.ptr.add(0x0b10usize + n * 32usize) as _) }
366 } 372 }
373 #[doc = "Device OUT/IN endpoint DMA address register"]
374 #[inline(always)]
375 pub const fn doepdma(self, n: usize) -> Reg<u32, RW> {
376 assert!(n < 16usize);
377 unsafe { Reg::from_ptr(self.ptr.add(0x0b14usize + n * 32usize) as _) }
378 }
367 #[doc = "Power and clock gating control register"] 379 #[doc = "Power and clock gating control register"]
368 #[inline(always)] 380 #[inline(always)]
369 pub const fn pcgcctl(self) -> Reg<regs::Pcgcctl, RW> { 381 pub const fn pcgcctl(self) -> Reg<regs::Pcgcctl, RW> {
diff --git a/embassy-usb/CHANGELOG.md b/embassy-usb/CHANGELOG.md
index 5f665ed25..efdda96fb 100644
--- a/embassy-usb/CHANGELOG.md
+++ b/embassy-usb/CHANGELOG.md
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased 8## Unreleased
9 9
10## 0.3.0 - 2024-08-05
11
12- bump usbd-hid from 0.7.0 to 0.8.1
13- Add collapse_debuginfo to fmt.rs macros.
14- update embassy-sync dependency
15
10## 0.2.0 - 2024-05-20 16## 0.2.0 - 2024-05-20
11 17
12- [#2862](https://github.com/embassy-rs/embassy/pull/2862) WebUSB implementation by @chmanie 18- [#2862](https://github.com/embassy-rs/embassy/pull/2862) WebUSB implementation by @chmanie
diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml
index 191ed0a6a..e310d8bae 100644
--- a/embassy-usb/Cargo.toml
+++ b/embassy-usb/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-usb" 2name = "embassy-usb"
3version = "0.2.0" 3version = "0.3.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "Async USB device stack for embedded devices in Rust." 6description = "Async USB device stack for embedded devices in Rust."
@@ -49,12 +49,12 @@ max-handler-count-8 = []
49embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 49embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
50embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } 50embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" }
51embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 51embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
52embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" } 52embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" }
53 53
54defmt = { version = "0.3", optional = true } 54defmt = { version = "0.3", optional = true }
55log = { version = "0.4.14", optional = true } 55log = { version = "0.4.14", optional = true }
56heapless = "0.8" 56heapless = "0.8"
57 57
58# for HID 58# for HID
59usbd-hid = { version = "0.7.0", optional = true } 59usbd-hid = { version = "0.8.1", optional = true }
60ssmarshal = { version = "1.0", default-features = false, optional = true } 60ssmarshal = { version = "1.0", default-features = false, optional = true }
diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs
index eb3d1f53a..c4d79e39f 100644
--- a/embassy-usb/src/descriptor.rs
+++ b/embassy-usb/src/descriptor.rs
@@ -13,6 +13,8 @@ pub mod descriptor_type {
13 pub const STRING: u8 = 3; 13 pub const STRING: u8 = 3;
14 pub const INTERFACE: u8 = 4; 14 pub const INTERFACE: u8 = 4;
15 pub const ENDPOINT: u8 = 5; 15 pub const ENDPOINT: u8 = 5;
16 pub const DEVICE_QUALIFIER: u8 = 6;
17 pub const OTHER_SPEED_CONFIGURATION: u8 = 7;
16 pub const IAD: u8 = 11; 18 pub const IAD: u8 = 11;
17 pub const BOS: u8 = 15; 19 pub const BOS: u8 = 15;
18 pub const CAPABILITY: u8 = 16; 20 pub const CAPABILITY: u8 = 16;
@@ -272,6 +274,25 @@ pub(crate) fn device_descriptor(config: &Config) -> [u8; 18] {
272 ] 274 ]
273} 275}
274 276
277/// Create a new Device Qualifier Descriptor array.
278///
279/// All device qualifier descriptors are always 10 bytes, so there's no need for
280/// a variable-length buffer or DescriptorWriter.
281pub(crate) fn device_qualifier_descriptor(config: &Config) -> [u8; 10] {
282 [
283 10, // bLength
284 0x06, // bDescriptorType
285 0x10,
286 0x02, // bcdUSB 2.1
287 config.device_class, // bDeviceClass
288 config.device_sub_class, // bDeviceSubClass
289 config.device_protocol, // bDeviceProtocol
290 config.max_packet_size_0, // bMaxPacketSize0
291 1, // bNumConfigurations
292 0, // Reserved
293 ]
294}
295
275/// A writer for Binary Object Store descriptor. 296/// A writer for Binary Object Store descriptor.
276pub struct BosWriter<'a> { 297pub struct BosWriter<'a> {
277 pub(crate) writer: DescriptorWriter<'a>, 298 pub(crate) writer: DescriptorWriter<'a>,
@@ -287,6 +308,9 @@ impl<'a> BosWriter<'a> {
287 } 308 }
288 309
289 pub(crate) fn bos(&mut self) { 310 pub(crate) fn bos(&mut self) {
311 if (self.writer.buf.len() - self.writer.position) < 5 {
312 return;
313 }
290 self.num_caps_mark = Some(self.writer.position + 4); 314 self.num_caps_mark = Some(self.writer.position + 4);
291 self.writer.write( 315 self.writer.write(
292 descriptor_type::BOS, 316 descriptor_type::BOS,
@@ -329,6 +353,9 @@ impl<'a> BosWriter<'a> {
329 } 353 }
330 354
331 pub(crate) fn end_bos(&mut self) { 355 pub(crate) fn end_bos(&mut self) {
356 if self.writer.position == 0 {
357 return;
358 }
332 self.num_caps_mark = None; 359 self.num_caps_mark = None;
333 let position = self.writer.position as u16; 360 let position = self.writer.position as u16;
334 self.writer.buf[2..4].copy_from_slice(&position.to_le_bytes()); 361 self.writer.buf[2..4].copy_from_slice(&position.to_le_bytes());
diff --git a/embassy-usb/src/fmt.rs b/embassy-usb/src/fmt.rs
index 35b929fde..8ca61bc39 100644
--- a/embassy-usb/src/fmt.rs
+++ b/embassy-usb/src/fmt.rs
@@ -90,19 +90,15 @@ macro_rules! todo {
90 }; 90 };
91} 91}
92 92
93#[cfg(not(feature = "defmt"))]
94#[collapse_debuginfo(yes)]
95macro_rules! unreachable {
96 ($($x:tt)*) => {
97 ::core::unreachable!($($x)*)
98 };
99}
100
101#[cfg(feature = "defmt")]
102#[collapse_debuginfo(yes)] 93#[collapse_debuginfo(yes)]
103macro_rules! unreachable { 94macro_rules! unreachable {
104 ($($x:tt)*) => { 95 ($($x:tt)*) => {
105 ::defmt::unreachable!($($x)*) 96 {
97 #[cfg(not(feature = "defmt"))]
98 ::core::unreachable!($($x)*);
99 #[cfg(feature = "defmt")]
100 ::defmt::unreachable!($($x)*);
101 }
106 }; 102 };
107} 103}
108 104
diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs
index d58950838..a5478ca0e 100644
--- a/embassy-usb/src/lib.rs
+++ b/embassy-usb/src/lib.rs
@@ -190,6 +190,7 @@ struct Inner<'d, D: Driver<'d>> {
190 190
191 config: Config<'d>, 191 config: Config<'d>,
192 device_descriptor: [u8; 18], 192 device_descriptor: [u8; 18],
193 device_qualifier_descriptor: [u8; 10],
193 config_descriptor: &'d [u8], 194 config_descriptor: &'d [u8],
194 bos_descriptor: &'d [u8], 195 bos_descriptor: &'d [u8],
195 msos_descriptor: crate::msos::MsOsDescriptorSet<'d>, 196 msos_descriptor: crate::msos::MsOsDescriptorSet<'d>,
@@ -225,6 +226,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
225 // This prevent further allocation by consuming the driver. 226 // This prevent further allocation by consuming the driver.
226 let (bus, control) = driver.start(config.max_packet_size_0 as u16); 227 let (bus, control) = driver.start(config.max_packet_size_0 as u16);
227 let device_descriptor = descriptor::device_descriptor(&config); 228 let device_descriptor = descriptor::device_descriptor(&config);
229 let device_qualifier_descriptor = descriptor::device_qualifier_descriptor(&config);
228 230
229 Self { 231 Self {
230 control_buf, 232 control_buf,
@@ -233,6 +235,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
233 bus, 235 bus,
234 config, 236 config,
235 device_descriptor, 237 device_descriptor,
238 device_qualifier_descriptor,
236 config_descriptor, 239 config_descriptor,
237 bos_descriptor, 240 bos_descriptor,
238 msos_descriptor, 241 msos_descriptor,
@@ -764,6 +767,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> {
764 } 767 }
765 } 768 }
766 } 769 }
770 descriptor_type::DEVICE_QUALIFIER => InResponse::Accepted(&self.device_qualifier_descriptor),
767 _ => InResponse::Rejected, 771 _ => InResponse::Rejected,
768 } 772 }
769 } 773 }
diff --git a/embassy-usb/src/msos.rs b/embassy-usb/src/msos.rs
index 25936d084..9f4e1a57b 100644
--- a/embassy-usb/src/msos.rs
+++ b/embassy-usb/src/msos.rs
@@ -278,6 +278,7 @@ pub enum DescriptorType {
278 278
279/// Table 5. Descriptor set information structure. 279/// Table 5. Descriptor set information structure.
280#[allow(non_snake_case)] 280#[allow(non_snake_case)]
281#[allow(unused)]
281#[repr(C, packed(1))] 282#[repr(C, packed(1))]
282pub struct DescriptorSetInformation { 283pub struct DescriptorSetInformation {
283 dwWindowsVersion: u32, 284 dwWindowsVersion: u32,
@@ -288,6 +289,7 @@ pub struct DescriptorSetInformation {
288 289
289/// Table 4. Microsoft OS 2.0 platform capability descriptor header. 290/// Table 4. Microsoft OS 2.0 platform capability descriptor header.
290#[allow(non_snake_case)] 291#[allow(non_snake_case)]
292#[allow(unused)]
291#[repr(C, packed(1))] 293#[repr(C, packed(1))]
292pub struct PlatformDescriptor { 294pub struct PlatformDescriptor {
293 bLength: u8, 295 bLength: u8,
diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml
index dbbe0fddc..93e49faef 100644
--- a/examples/boot/application/nrf/Cargo.toml
+++ b/examples/boot/application/nrf/Cargo.toml
@@ -6,12 +6,12 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] }
11embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } 11embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] }
12embassy-boot = { version = "0.2.0", path = "../../../../embassy-boot", features = [] } 12embassy-boot = { version = "0.3.0", path = "../../../../embassy-boot", features = [] }
13embassy-boot-nrf = { version = "0.2.0", path = "../../../../embassy-boot-nrf", features = [] } 13embassy-boot-nrf = { version = "0.3.0", path = "../../../../embassy-boot-nrf", features = [] }
14embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 14embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
15 15
16defmt = { version = "0.3", optional = true } 16defmt = { version = "0.3", optional = true }
17defmt-rtt = { version = "0.4", optional = true } 17defmt-rtt = { version = "0.4", optional = true }
diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml
index d4341e8f6..8bb8afdfe 100644
--- a/examples/boot/application/rp/Cargo.toml
+++ b/examples/boot/application/rp/Cargo.toml
@@ -6,11 +6,11 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] }
11embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] } 11embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] }
12embassy-boot-rp = { version = "0.2.0", path = "../../../../embassy-boot-rp", features = [] } 12embassy-boot-rp = { version = "0.3.0", path = "../../../../embassy-boot-rp", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = "0.3" 15defmt = "0.3"
16defmt-rtt = "0.4" 16defmt-rtt = "0.4"
diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml
index c203ffc9f..1c2934298 100644
--- a/examples/boot/application/stm32f3/Cargo.toml
+++ b/examples/boot/application/stm32f3/Cargo.toml
@@ -6,11 +6,11 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml
index ed13eab65..09e34c7df 100644
--- a/examples/boot/application/stm32f7/Cargo.toml
+++ b/examples/boot/application/stm32f7/Cargo.toml
@@ -6,11 +6,11 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml
index f25e9815d..5e7f4d5e7 100644
--- a/examples/boot/application/stm32h7/Cargo.toml
+++ b/examples/boot/application/stm32h7/Cargo.toml
@@ -6,11 +6,11 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml
index c1a47dfe4..60fdcfafb 100644
--- a/examples/boot/application/stm32l0/Cargo.toml
+++ b/examples/boot/application/stm32l0/Cargo.toml
@@ -6,11 +6,11 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml
index 1e83d3113..fe3ab2c04 100644
--- a/examples/boot/application/stm32l1/Cargo.toml
+++ b/examples/boot/application/stm32l1/Cargo.toml
@@ -6,11 +6,11 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml
index bca292681..169856358 100644
--- a/examples/boot/application/stm32l4/Cargo.toml
+++ b/examples/boot/application/stm32l4/Cargo.toml
@@ -6,11 +6,11 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml
index 0484e6ceb..7cef8fe0d 100644
--- a/examples/boot/application/stm32wb-dfu/Cargo.toml
+++ b/examples/boot/application/stm32wb-dfu/Cargo.toml
@@ -6,12 +6,12 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14embassy-usb = { version = "0.2.0", path = "../../../../embassy-usb" } 14embassy-usb = { version = "0.3.0", path = "../../../../embassy-usb" }
15embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] } 15embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] }
16 16
17defmt = { version = "0.3", optional = true } 17defmt = { version = "0.3", optional = true }
diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml
index b785a1968..860a835a9 100644
--- a/examples/boot/application/stm32wl/Cargo.toml
+++ b/examples/boot/application/stm32wl/Cargo.toml
@@ -6,11 +6,11 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] }
10embassy-time = { version = "0.3.1", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" }
14 14
15defmt = { version = "0.3", optional = true } 15defmt = { version = "0.3", optional = true }
16defmt-rtt = { version = "0.4", optional = true } 16defmt-rtt = { version = "0.4", optional = true }
diff --git a/examples/boot/application/stm32wl/memory.x b/examples/boot/application/stm32wl/memory.x
index e1d4e7fa8..20109e37e 100644
--- a/examples/boot/application/stm32wl/memory.x
+++ b/examples/boot/application/stm32wl/memory.x
@@ -5,7 +5,8 @@ MEMORY
5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K 5 BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K
6 FLASH : ORIGIN = 0x08008000, LENGTH = 64K 6 FLASH : ORIGIN = 0x08008000, LENGTH = 64K
7 DFU : ORIGIN = 0x08018000, LENGTH = 68K 7 DFU : ORIGIN = 0x08018000, LENGTH = 68K
8 RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K 8 SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128
9 RAM (rwx) : ORIGIN = 0x20000080, LENGTH = 32K - 128
9} 10}
10 11
11__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER); 12__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER);
@@ -13,3 +14,11 @@ __bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - O
13 14
14__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOTLOADER); 15__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOTLOADER);
15__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOTLOADER); 16__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOTLOADER);
17
18SECTIONS
19{
20 .shared_data :
21 {
22 *(.shared_data)
23 } > SHARED_RAM
24}
diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs
index 9f4f0b238..127de0237 100644
--- a/examples/boot/application/stm32wl/src/bin/a.rs
+++ b/examples/boot/application/stm32wl/src/bin/a.rs
@@ -1,6 +1,8 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem::MaybeUninit;
5
4#[cfg(feature = "defmt")] 6#[cfg(feature = "defmt")]
5use defmt_rtt::*; 7use defmt_rtt::*;
6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; 8use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
@@ -9,6 +11,7 @@ use embassy_executor::Spawner;
9use embassy_stm32::exti::ExtiInput; 11use embassy_stm32::exti::ExtiInput;
10use embassy_stm32::flash::{Flash, WRITE_SIZE}; 12use embassy_stm32::flash::{Flash, WRITE_SIZE};
11use embassy_stm32::gpio::{Level, Output, Pull, Speed}; 13use embassy_stm32::gpio::{Level, Output, Pull, Speed};
14use embassy_stm32::SharedData;
12use embassy_sync::mutex::Mutex; 15use embassy_sync::mutex::Mutex;
13use panic_reset as _; 16use panic_reset as _;
14 17
@@ -17,9 +20,12 @@ static APP_B: &[u8] = &[0, 1, 2, 3];
17#[cfg(not(feature = "skip-include"))] 20#[cfg(not(feature = "skip-include"))]
18static APP_B: &[u8] = include_bytes!("../../b.bin"); 21static APP_B: &[u8] = include_bytes!("../../b.bin");
19 22
23#[link_section = ".shared_data"]
24static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
25
20#[embassy_executor::main] 26#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 27async fn main(_spawner: Spawner) {
22 let p = embassy_stm32::init(Default::default()); 28 let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA);
23 let flash = Flash::new_blocking(p.FLASH); 29 let flash = Flash::new_blocking(p.FLASH);
24 let flash = Mutex::new(BlockingAsync::new(flash)); 30 let flash = Mutex::new(BlockingAsync::new(flash));
25 31
diff --git a/examples/boot/application/stm32wl/src/bin/b.rs b/examples/boot/application/stm32wl/src/bin/b.rs
index e954d8b91..768dadf8b 100644
--- a/examples/boot/application/stm32wl/src/bin/b.rs
+++ b/examples/boot/application/stm32wl/src/bin/b.rs
@@ -1,16 +1,22 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem::MaybeUninit;
5
4#[cfg(feature = "defmt")] 6#[cfg(feature = "defmt")]
5use defmt_rtt::*; 7use defmt_rtt::*;
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed}; 9use embassy_stm32::gpio::{Level, Output, Speed};
10use embassy_stm32::SharedData;
8use embassy_time::Timer; 11use embassy_time::Timer;
9use panic_reset as _; 12use panic_reset as _;
10 13
14#[link_section = ".shared_data"]
15static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
16
11#[embassy_executor::main] 17#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 18async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default()); 19 let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA);
14 let mut led = Output::new(p.PB15, Level::High, Speed::Low); 20 let mut led = Output::new(p.PB15, Level::High, Speed::Low);
15 21
16 loop { 22 loop {
diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml
index c15c980ca..9df396e5e 100644
--- a/examples/boot/bootloader/rp/Cargo.toml
+++ b/examples/boot/bootloader/rp/Cargo.toml
@@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
9defmt = { version = "0.3", optional = true } 9defmt = { version = "0.3", optional = true }
10defmt-rtt = { version = "0.4", optional = true } 10defmt-rtt = { version = "0.4", optional = true }
11 11
12embassy-rp = { path = "../../../../embassy-rp", features = [] } 12embassy-rp = { path = "../../../../embassy-rp", features = ["rp2040"] }
13embassy-boot-rp = { path = "../../../../embassy-boot-rp" } 13embassy-boot-rp = { path = "../../../../embassy-boot-rp" }
14embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } 14embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" }
15embassy-time = { path = "../../../../embassy-time", features = [] } 15embassy-time = { path = "../../../../embassy-time", features = [] }
diff --git a/examples/boot/bootloader/rp/memory.x b/examples/boot/bootloader/rp/memory.x
index c3b54976e..88b5bbb15 100644
--- a/examples/boot/bootloader/rp/memory.x
+++ b/examples/boot/bootloader/rp/memory.x
@@ -2,7 +2,7 @@ MEMORY
2{ 2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */ 3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 4 BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
5 FLASH : ORIGIN = 0x10000100, LENGTH = 24K 5 FLASH : ORIGIN = 0x10000100, LENGTH = 24K - 0x100
6 BOOTLOADER_STATE : ORIGIN = 0x10006000, LENGTH = 4K 6 BOOTLOADER_STATE : ORIGIN = 0x10006000, LENGTH = 4K
7 ACTIVE : ORIGIN = 0x10007000, LENGTH = 512K 7 ACTIVE : ORIGIN = 0x10007000, LENGTH = 512K
8 DFU : ORIGIN = 0x10087000, LENGTH = 516K 8 DFU : ORIGIN = 0x10087000, LENGTH = 516K
diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
index 9950ed7b6..050b672ce 100644
--- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
+++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
@@ -18,7 +18,7 @@ embedded-storage = "0.3.1"
18embedded-storage-async = "0.4.0" 18embedded-storage-async = "0.4.0"
19cfg-if = "1.0.0" 19cfg-if = "1.0.0"
20embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["dfu", "cortex-m"] } 20embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["dfu", "cortex-m"] }
21embassy-usb = { version = "0.2.0", path = "../../../../embassy-usb", default-features = false } 21embassy-usb = { version = "0.3.0", path = "../../../../embassy-usb", default-features = false }
22embassy-futures = { version = "0.1.1", path = "../../../../embassy-futures" } 22embassy-futures = { version = "0.1.1", path = "../../../../embassy-futures" }
23 23
24[features] 24[features]
diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml
index 70a89bb30..98a678815 100644
--- a/examples/nrf-rtos-trace/Cargo.toml
+++ b/examples/nrf-rtos-trace/Cargo.toml
@@ -16,9 +16,9 @@ log = [
16 16
17[dependencies] 17[dependencies]
18embassy-sync = { version = "0.6.0", path = "../../embassy-sync" } 18embassy-sync = { version = "0.6.0", path = "../../embassy-sync" }
19embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } 19embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] }
20embassy-time = { version = "0.3.1", path = "../../embassy-time" } 20embassy-time = { version = "0.3.2", path = "../../embassy-time" }
21embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } 21embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
22 22
23cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 23cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
24cortex-m-rt = "0.7.0" 24cortex-m-rt = "0.7.0"
diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml
index c52256d8e..93a19bea7 100644
--- a/examples/nrf51/Cargo.toml
+++ b/examples/nrf51/Cargo.toml
@@ -5,9 +5,9 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 8embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 9embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } 10embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] }
11 11
12defmt = "0.3" 12defmt = "0.3"
13defmt-rtt = "0.4" 13defmt-rtt = "0.4"
diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml
index 2031b253f..0e3e81c3f 100644
--- a/examples/nrf52810/Cargo.toml
+++ b/examples/nrf52810/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
9embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
11embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 12embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
13 13
14defmt = "0.3" 14defmt = "0.3"
15defmt-rtt = "0.4" 15defmt-rtt = "0.4"
diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml
index 731cee843..7fae7aefc 100644
--- a/examples/nrf52840-rtic/Cargo.toml
+++ b/examples/nrf52840-rtic/Cargo.toml
@@ -9,8 +9,8 @@ rtic = { version = "2", features = ["thumbv7-backend"] }
9 9
10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
11embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 11embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "generic-queue"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "generic-queue"] }
13embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 13embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
14 14
15defmt = "0.3" 15defmt = "0.3"
16defmt-rtt = "0.4" 16defmt-rtt = "0.4"
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index 000857821..17fa6234d 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -7,11 +7,11 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
9embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
11embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 12embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
14embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
15embedded-io = { version = "0.6.0", features = ["defmt-03"] } 15embedded-io = { version = "0.6.0", features = ["defmt-03"] }
16embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 16embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
17embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } 17embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] }
@@ -27,7 +27,7 @@ cortex-m-rt = "0.7.0"
27panic-probe = { version = "0.3", features = ["print-defmt"] } 27panic-probe = { version = "0.3", features = ["print-defmt"] }
28rand = { version = "0.8.4", default-features = false } 28rand = { version = "0.8.4", default-features = false }
29embedded-storage = "0.3.1" 29embedded-storage = "0.3.1"
30usbd-hid = "0.7.0" 30usbd-hid = "0.8.1"
31serde = { version = "1.0.136", default-features = false } 31serde = { version = "1.0.136", default-features = false }
32embedded-hal = { version = "1.0" } 32embedded-hal = { version = "1.0" }
33embedded-hal-async = { version = "1.0" } 33embedded-hal-async = { version = "1.0" }
diff --git a/examples/nrf52840/src/bin/channel.rs b/examples/nrf52840/src/bin/channel.rs
index 7fcea9dbd..e06ba1c73 100644
--- a/examples/nrf52840/src/bin/channel.rs
+++ b/examples/nrf52840/src/bin/channel.rs
@@ -35,8 +35,8 @@ async fn main(spawner: Spawner) {
35 35
36 loop { 36 loop {
37 match CHANNEL.receive().await { 37 match CHANNEL.receive().await {
38 LedState::On => led.set_high(), 38 LedState::On => led.set_low(),
39 LedState::Off => led.set_low(), 39 LedState::Off => led.set_high(),
40 } 40 }
41 } 41 }
42} 42}
diff --git a/examples/nrf52840/src/bin/channel_sender_receiver.rs b/examples/nrf52840/src/bin/channel_sender_receiver.rs
index 3095a04ec..29f70f91c 100644
--- a/examples/nrf52840/src/bin/channel_sender_receiver.rs
+++ b/examples/nrf52840/src/bin/channel_sender_receiver.rs
@@ -33,8 +33,8 @@ async fn recv_task(led: AnyPin, receiver: Receiver<'static, NoopRawMutex, LedSta
33 33
34 loop { 34 loop {
35 match receiver.receive().await { 35 match receiver.receive().await {
36 LedState::On => led.set_high(), 36 LedState::On => led.set_low(),
37 LedState::Off => led.set_low(), 37 LedState::Off => led.set_high(),
38 } 38 }
39 } 39 }
40} 40}
diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs
index 279f32edc..94cf09c88 100644
--- a/examples/nrf52840/src/bin/ethernet_enc28j60.rs
+++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs
@@ -66,16 +66,11 @@ async fn main(spawner: Spawner) {
66 let seed = u64::from_le_bytes(seed); 66 let seed = u64::from_le_bytes(seed);
67 67
68 // Init network stack 68 // Init network stack
69 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 69 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
70 static STACK: StaticCell< 70 static STACK: StaticCell<
71 Stack<Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>>, 71 Stack<Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>>,
72 > = StaticCell::new(); 72 > = StaticCell::new();
73 let stack = STACK.init(Stack::new( 73 let stack = STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
74 device,
75 config,
76 RESOURCES.init(StackResources::<2>::new()),
77 seed,
78 ));
79 74
80 unwrap!(spawner.spawn(net_task(stack))); 75 unwrap!(spawner.spawn(net_task(stack)));
81 76
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs
index a7e5c2668..e56b215e3 100644
--- a/examples/nrf52840/src/bin/usb_ethernet.rs
+++ b/examples/nrf52840/src/bin/usb_ethernet.rs
@@ -115,7 +115,7 @@ async fn main(spawner: Spawner) {
115 let seed = u64::from_le_bytes(seed); 115 let seed = u64::from_le_bytes(seed);
116 116
117 // Init network stack 117 // Init network stack
118 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 118 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
119 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new(); 119 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new();
120 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); 120 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
121 121
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
index 00bd50081..a3b69a99b 100644
--- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs
+++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
@@ -89,14 +89,9 @@ async fn main(spawner: Spawner) {
89 let seed = u64::from_le_bytes(seed); 89 let seed = u64::from_le_bytes(seed);
90 90
91 // Init network stack 91 // Init network stack
92 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 92 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
93 static STACK: StaticCell<Stack<hosted::NetDriver<'static>>> = StaticCell::new(); 93 static STACK: StaticCell<Stack<hosted::NetDriver<'static>>> = StaticCell::new();
94 let stack = &*STACK.init(Stack::new( 94 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
95 device,
96 config,
97 RESOURCES.init(StackResources::<2>::new()),
98 seed,
99 ));
100 95
101 unwrap!(spawner.spawn(net_task(stack))); 96 unwrap!(spawner.spawn(net_task(stack)));
102 97
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml
index 02f6190f0..0da85be07 100644
--- a/examples/nrf5340/Cargo.toml
+++ b/examples/nrf5340/Cargo.toml
@@ -7,11 +7,11 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
9embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
11embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } 12embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] }
13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
14embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
15embedded-io-async = { version = "0.6.1" } 15embedded-io-async = { version = "0.6.1" }
16 16
17defmt = "0.3" 17defmt = "0.3"
@@ -23,7 +23,7 @@ cortex-m-rt = "0.7.0"
23panic-probe = { version = "0.3", features = ["print-defmt"] } 23panic-probe = { version = "0.3", features = ["print-defmt"] }
24rand = { version = "0.8.4", default-features = false } 24rand = { version = "0.8.4", default-features = false }
25embedded-storage = "0.3.1" 25embedded-storage = "0.3.1"
26usbd-hid = "0.7.0" 26usbd-hid = "0.8.1"
27serde = { version = "1.0.136", default-features = false } 27serde = { version = "1.0.136", default-features = false }
28 28
29[profile.release] 29[profile.release]
diff --git a/examples/nrf9151/ns/.cargo/config.toml b/examples/nrf9151/ns/.cargo/config.toml
new file mode 100644
index 000000000..1444b0cd1
--- /dev/null
+++ b/examples/nrf9151/ns/.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 nRF9160_xxAA"
4
5[build]
6target = "thumbv8m.main-none-eabihf"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml
new file mode 100644
index 000000000..17fe27b67
--- /dev/null
+++ b/examples/nrf9151/ns/Cargo.toml
@@ -0,0 +1,20 @@
1[package]
2edition = "2021"
3name = "embassy-nrf9151-non-secure-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-executor = { version = "0.6.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
11
12defmt = "0.3"
13defmt-rtt = "0.4"
14
15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
16cortex-m-rt = "0.7.0"
17panic-probe = { version = "0.3", features = ["print-defmt"] }
18
19[profile.release]
20debug = 2
diff --git a/examples/nrf9151/ns/README.md b/examples/nrf9151/ns/README.md
new file mode 100644
index 000000000..a3f81d24e
--- /dev/null
+++ b/examples/nrf9151/ns/README.md
@@ -0,0 +1,4 @@
1You must flash the TFM before running any non-secure examples. The TFM
2configures the secure and non-secure execution environments and then loads the
3non-secure application. A reference TFM is included, and you can use the
4provided helper script to flash it.
diff --git a/examples/nrf9151/ns/build.rs b/examples/nrf9151/ns/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/nrf9151/ns/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/nrf9151/ns/flash_tfm.sh b/examples/nrf9151/ns/flash_tfm.sh
new file mode 100644
index 000000000..29e4e0ed5
--- /dev/null
+++ b/examples/nrf9151/ns/flash_tfm.sh
@@ -0,0 +1,2 @@
1nrfjprog --family NRF91 --recover
2nrfjprog --family NRF91 --chiperase --verify --program tfm.hex
diff --git a/examples/nrf9151/ns/memory.x b/examples/nrf9151/ns/memory.x
new file mode 100644
index 000000000..8d7b66fcc
--- /dev/null
+++ b/examples/nrf9151/ns/memory.x
@@ -0,0 +1,7 @@
1MEMORY
2{
3 /* Trusted Firmware-M (TF-M) is flashed at the start */
4 FLASH : ORIGIN = 0x00008000, LENGTH = 0xf8000
5 RAM (rwx) : ORIGIN = 0x2000C568, LENGTH = 0x33a98
6}
7
diff --git a/examples/nrf9151/ns/src/bin/blinky.rs b/examples/nrf9151/ns/src/bin/blinky.rs
new file mode 100644
index 000000000..7457a95a3
--- /dev/null
+++ b/examples/nrf9151/ns/src/bin/blinky.rs
@@ -0,0 +1,22 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_nrf::gpio::{Level, Output, OutputDrive};
6use embassy_time::Timer;
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = embassy_nrf::init(Default::default());
12 let mut led = Output::new(p.P0_00, Level::Low, OutputDrive::Standard);
13
14 loop {
15 led.set_high();
16 defmt::info!("high");
17 Timer::after_millis(500).await;
18 led.set_low();
19 defmt::info!("low");
20 Timer::after_millis(1000).await;
21 }
22}
diff --git a/examples/nrf9151/ns/src/bin/uart.rs b/examples/nrf9151/ns/src/bin/uart.rs
new file mode 100644
index 000000000..2220dccfb
--- /dev/null
+++ b/examples/nrf9151/ns/src/bin/uart.rs
@@ -0,0 +1,37 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_nrf::{bind_interrupts, peripherals, uarte};
7use {defmt_rtt as _, panic_probe as _};
8
9bind_interrupts!(struct Irqs {
10 SPIM0_SPIS0_TWIM0_TWIS0_UARTE0 => uarte::InterruptHandler<peripherals::SERIAL0>;
11});
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = embassy_nrf::init(Default::default());
16 let mut config = uarte::Config::default();
17 config.parity = uarte::Parity::EXCLUDED;
18 config.baudrate = uarte::Baudrate::BAUD115200;
19
20 let mut uart = uarte::Uarte::new(p.SERIAL0, Irqs, p.P0_26, p.P0_27, config);
21
22 info!("uarte initialized!");
23
24 // Message must be in SRAM
25 let mut buf = [0; 8];
26 buf.copy_from_slice(b"Hello!\r\n");
27
28 unwrap!(uart.write(&buf).await);
29 info!("wrote hello in uart!");
30
31 loop {
32 info!("reading...");
33 unwrap!(uart.read(&mut buf).await);
34 info!("writing...");
35 unwrap!(uart.write(&buf).await);
36 }
37}
diff --git a/examples/nrf9151/ns/tfm.hex b/examples/nrf9151/ns/tfm.hex
new file mode 100644
index 000000000..9864a1849
--- /dev/null
+++ b/examples/nrf9151/ns/tfm.hex
@@ -0,0 +1,1543 @@
1:10000000F80B0020690600000D070000255A0000CB
2:10001000455A0000655A0000A55A0000855A0000A4
3:100020000000000000000000000000001D2700008C
4:100030000D070000000000000D0700000D07000084
5:10004000000000000000000000000000F13200008D
6:10005000000000000D07000000000000000000008C
7:100060000D0700000D0700000D0700000D07000040
8:10007000000000000D0700000D0700000D07000044
9:100080000D0700000D070000000000000000000048
10:100090000D0700000D070000000000000000000038
11:1000A0000D07000000000000000000000D07000028
12:1000B0000D0700000D0700000D0700000D070000F0
13:1000C0000D0700000D0700000D0700000D070000E0
14:1000D0000D070000000000000D07000000000000F8
15:1000E0000D070000000000000D07000000000000E8
16:1000F0000D070000000000000000000000000000EC
17:10010000000000000D0700000000000000000000DB
18:1001100000000000000000000000000000000000DF
19:10012000000000000D0700000000000000000000BB
20:1001300000000000000000000000000000000000BF
21:100140000D07000000015F5F00000000FE0B0000D3
22:10015000F9270000800600000000000000000000F9
23:10016000000000000000000000000000401200201D
24:100170000000000001015F5F030100001F0100009B
25:1001800085040000000000000000000001000000E5
26:10019000010000000000000000000000000000005E
27:1001A0000000000070000000CC5E00008000000035
28:1001B000000F000001000000D102000001015F5F9C
29:1001C000040100001F010000F30500000000000012
30:1001D000000000000000000001000000000000001E
31:1001E000000000000000000000000000D75E0000DA
32:1001F000400000000507000001000000DF040000CF
33:1002000038B50025054C29462046D4F80024C4F80A
34:10021000045405F0B0FCC4F8005438BD200C002094
35:1002200013B511460022CDE9002242680346382A60
36:10023000046844D194F82820022A19D01AB900F091
37:1002400047F902B010BD21482468D0F80404013AEF
38:10025000CDE90040082A35D8DFE802F0050A0E1380
39:10026000181D22272C006A46184600F02EF9E8E7F0
40:10027000184600F018F9E4E76A46184600F016F947
41:10028000DFE76A46184600F00BF9DAE76A461846D7
42:1002900000F00FF9D5E76A46184600F00DF9D0E7EF
43:1002A0006A46184600F00BF9CBE76A46184600F09C
44:1002B00009F9C6E76A46184600F00EF9C1E76FF083
45:1002C0008000BEE76FF08500BBE700BF200C002078
46:1002D0002DE9F04F05680446A1B0002D40F0AA803A
47:1002E0002022294602A805F046FC12AF202229460A
48:1002F0000AA805F040FC38222946384605F03BFCA8
49:10030000E26904F11C039846B2B10426E26A04F1E2
50:100310002C03EAB10425EEB96FF08306304621B014
51:10032000BDE8F08F002EF1D053F8041D3246013E97
52:100330000029F7D01646E9E70326F5E7002DEAD0B5
53:1003400053F8041D2A46013D0029F7D01546E2E77F
54:100350000325F5E738233A460021606805F048FC9C
55:100360003828D9D14FF00109CDE90270334F0DF192
56:10037000080A04F1100B4E45D7F800141CD10DF1FA
57:1003800028094B46002008EB850EC64533D108B13D
58:10039000C7F80014A3683146C7F804340AAA2B46EC
59:1003A00002A8FFF73DFF00270646BD4209F10809F4
60:1003B00038D1FFF725FFB1E75BF8043FC1F5806254
61:1003C000D81C20F00300904204D9FFF719FF6FF00A
62:1003D0008C06A3E70844CA19C7F8000449466068B8
63:1003E000019205F005FC019ACAF80C0009F1010917
64:1003F0004AF8082FBFE758F804CFC1F5806A0CF11E
65:10040000030222F00302524503F1080305D87818CD
66:1004100043E9020C11440120B7E70028D5D0C7F802
67:100420000014D2E7394659E90223606805F0F5FB6C
68:100430000137BAE76FF0850670E700BF200C002097
69:1004400008B528220021024805F095FB002008BDD0
70:100450002810002010B5044C0F222046034905F057
71:1004600065FB204610BD00BF51100020F6050000BE
72:1004700008B50121024803F011FB002008BD00BFB0
73:100480005010002008B5FFF7DBFF40B9FFF7E2FF8F
74:10049000FFF7EEFF18B9BDE8084003F06DBB08BDDB
75:1004A0006FF0850070476FF0850070476FF0850032
76:1004B00070476FF0850070476FF0850070476FF0F0
77:1004C000850070476FF0850070476FF085007047BA
78:1004D000D1E9000103F030BB6FF085007047F0B543
79:1004E00003680546B3F57D7FA7B007D040F2F5322B
80:1004F000934207D06FF0850027B0F0BD01F08EFC6D
81:100500000020F9E700243C22214607A8CDE9024457
82:10051000CDE90444069405F02EFB3C22214617A8A1
83:10052000169405F028FBEA69019405F11C0302B357
84:100530000426EA6A05F12C033AB30424731E012B46
85:1005400052D8012C50D80423002168680DEB030217
86:1005500005F04EFB04281AD06FF08000CCE7002E87
87:10056000E7D053F8041D3246013E0029F7D0164665
88:10057000DFE70326F5E7002CE0D053F8041D224600
89:10058000013C0029F7D01446D8E70324F5E7022EF2
90:1005900016D16E69402E29D806AF33463A4601215E
91:1005A000686805F025FB8642D6D1CDE9027602A91E
92:1005B00044B92246019801F01AFE044620469BE702
93:1005C0000021F5E72B6A402BC6D816AACDE90423F3
94:1005D000019804AA01F00BFEDDE904230446002182
95:1005E000686805F01AFBE9E7012085E76FF08900EC
96:1005F00082E7002070474D62656420544C532033DD
97:100600002E352E3000000000000000000000000029
98:1006100000000000000000000000000000000000DA
99:100620005431000001000000407C000080100020D8
100:100630004A000000407C0000200C00200000000068
101:10064000407C0000000C002000000000A8110020E9
102:10065000C4050000200C002018010000000C002040
103:100660000800000002F07ABC08B572B61E4A1F4BA3
104:100670009A601F4B83F309881E4B83F30A8883F328
105:100680000B881D4B16A1D1E90001C3E9000100F060
106:1006900089F81A4B1A498B4212D30020194B1A4978
107:1006A0008B4218D303F06AF8186850F82240586853
108:1006B00040F82240013298688242F5D30C33EAE7D1
109:1006C0000022F8E71C6844F8220001325C68A2426C
110:1006D000F8D30833E4E70022F8E700BFAFF3008067
111:1006E000A5EDF5FEA5EDF5FE0000000000ED00E033
112:1006F000F80B002000040020F80B00202806000062
113:100700004C0600004C06000064060000EFF3088071
114:10071000EFF309812DE9F00F6B46724600F038F9CE
115:1007200008B0FFF79FFFFEE708B5EFF31083012B3A
116:100730000C4A07D1126ABFF34F8F511C4A424A41FB
117:10074000104608BD01F0BEFB00B172B6126ABFF3DD
118:100750004F8F531C5A425A4101F0B4FB0028EFD08E
119:1007600062B6EDE70080FF0008B5EFF31083012BC0
120:100770000B4A06D1D269BFF34F8F02F00102104637
121:1007800008BD01F09FFB00B172B6D269BFF34F8F75
122:1007900002F0010201F096FB0028F0D062B6EEE70D
123:1007A0000080FF006F4A10B5D2F8D03043F002034A
124:1007B000C2F8D03001F086FB30B14FF05023002258
125:1007C000C3F81421C3F8182101F08BFB28B10122D2
126:1007D000654BC3F8382AC3F878254FF47F02D2F866
127:1007E0003031D2F83421BFF34F8FC3F30B03092B01
128:1007F00005D1012A1EBF01225B4BC3F8782501F009
129:1008000070FB18B10E22594BC3F8E42E01F05AFBCD
130:1008100030B10022544BC3F80C270122C3F8102733
131:100820000022D30003F57F03D3F80013BFF34F8FEB
132:10083000013108D0D3F800130132D3F80433B2F5F4
133:10084000807F0B60EDD1EFF31084FFF78DFF002860
134:100850004DD0BFF34F8F464BD3F80024012AFBD174
135:10086000C3F80425D3F80024012AFBD1012C03D0BE
136:1008700001F028FB00B172B6FFF776FF58B13D4A90
137:10088000D36923F00103D361BFF34F8F384AD2F805
138:100890000034012BFBD1FFF747FF68B1354A136ADB
139:1008A00023F0FF0343F020031362BFF34F8F304A5E
140:1008B000D2F80034012BFBD1012C03D001F002FB54
141:1008C00000B162B600222A4BC3F80425D3F80024F5
142:1008D000012AFBD1BFF34F8F2249274BCA6802F48C
143:1008E000E0621343CB60BFF34F8F00BFFDE7FFF71C
144:1008F0001BFF0028ADD11B4AD2F88C3043F4406373
145:10090000C2F88C304FF47F03D3F83021D3F8343160
146:10091000BFF34F8FC2F30B02092A16D1013B022B02
147:1009200002D8164AD35C83B1124815490368104AAD
148:100930008B420CBF5A230023C2F8103EC36A8B427D
149:100940000CBF5A230023C2F8003E064AD2F8883072
150:1009500043F47003C2F88830BFF34F8FBFF36F8F3B
151:1009600010BD00BF00ED00E00040005000A00350AB
152:10097000009003500080FF000400FA05C43300001B
153:10098000FA50FA507C22014905F0D0B8DC1800205A
154:1009900038B51D46374B384C5B68C3F308032360FA
155:1009A000EFF30383C4E901206365C2F3801302F00F
156:1009B0000C020C2AE16038D10BB9EFF389812022B7
157:1009C0002E48216105F0B2F825B1202229462C4895
158:1009D00005F0ACF8274B9A6AA265D96AE165986B75
159:1009E000206602F400406066586BA06602F080004A
160:1009F000E0669A62D962D3F8E4202267D3F8E8105F
161:100A0000616702F04001A167C3F8E42000F06AF8D2
162:100A10000E211C4801F077FA2268D31E042B1CD843
163:100A2000DFE803F0090F1215180013B9EFF38881FE
164:100A3000C5E70146C3E70C211348BDE8384001F083
165:100A400062BA12211148F8E70B211148F5E70D2190
166:100A50001048F2E70E211048EFE70F2A98BF142143
167:100A6000BDE8384089BF25210C480D48103A01F0F7
168:100A7000F5BB00BF00ED00E0DC180020F0180020FE
169:100A800010190020C7330000D5330000E133000007
170:100A9000F3330000FE3300000B3400001934000073
171:100AA0002D3400002DE9F34106460F460C4DD5F8D4
172:100AB0002C80C04710F00104FBD1394630466B69E9
173:100AC000984740B9C047C307FCD42B6A019302B0D2
174:100AD000BDE8F0411847204602B0BDE8F08100BFF4
175:100AE0005434000010B5094C0020A36898472369CE
176:100AF00002209847A46A4FF4E1310120A047234621
177:100B0000BDE8104001211520184700BF54340000F3
178:100B100010B5044C002023699847E368BDE81040F5
179:100B2000184700BF54340000064B82B018680023F9
180:100B300082B262F30F03000C60F31F43184602B049
181:100B4000704700BF9C340000014B1869704700BF1C
182:100B500084100020014B5869704700BF84100020AA
183:100B600038B50C4D0C4695F8203013B94FF0FF30D6
184:100B700038BD0A460146284600F06CFF064B9842F5
185:100B800005D00B3B9842F1D100206C61F0E76FF08B
186:100B90000100EDE7841000200B00AD0BF0B51B4EFB
187:100BA000054696F820300C4691B01BB94FF0FF3047
188:100BB00011B0F0BD00F06043B3F1005F21D100231C
189:100BC0000A460146304600F031FC114B98421AD0DB
190:100BD0000B3B9842EAD1346111E0A71B402F28BF9C
191:100BE0004027A9193A46684604F0A0FF39466846EE
192:100BF000FFF7D4FF0028DBD14036B442EDD8002007
193:100C0000D6E70026F9E76FF00100D1E78410002055
194:100C10000B00AD0BC3B2012B10B540F096804DF622
195:100C2000C023994270D028D8B1F5615F6FD011D838
196:100C3000B1F5965F6DD008D8B1F5966F6BD0B1F570
197:100C4000166F6BD06FF007005DE0B1F5165FF9D15C
198:100C5000454B33E047F61223994262D007D8B1F5ED
199:100C6000964F61D0B1F5E14FECD1404B26E0B1F5A4
200:100C7000164FE7D14FF41D0320E03D4B994255D06C
201:100C800011D8B1F5E13F54D007D8B1F5614F53D039
202:100C9000B1F5963FD6D1374B10E0B1F5613FD1D1D8
203:100CA0004FF06C730AE0B1F5612F48D0324B994296
204:100CB00048D0B1F5E12FC5D14FF0E86310F4E06FF3
205:100CC00046D110F4404103D0B1F5804F43D11021FB
206:100CD00010F4405203D0B2F5805F3FD10E2210F4E1
207:100CE000403003D0B0F5403F3BD10120234C20766B
208:100CF0006276E361A1760A4324681043C4F8243580
209:100D0000C4F86C05002010BD4FF46503D6E71C4BFA
210:100D1000D4E71C4BD2E74FF49E23CFE74FF41D23BB
211:100D2000CCE74FF40003C9E7174BC7E74FF08063E8
212:100D3000C4E74FF0EB73C1E74FF46B03BEE74FF02E
213:100D40007063BBE74FF08053B8E76FF00300DAE75A
214:100D50006FF00800D7E76FF00A00D4E76FF00900E2
215:100D6000D1E76FF00B00CEE70050270000C0750000
216:100D700090D0030000903A0140420F008410002000
217:100D800000F03A0000B0130000A04E0010B5114C66
218:100D9000204600F0D5FD0021206884F8201000F0E6
219:100DA00047FF226842F30732002A11DB0121530971
220:100DB0009B0003F1604303F56143D3F8800202F026
221:100DC0001F0201FA02F20243C3F88022D3F88032F4
222:100DD000002010BD8410002010B5264C0021206892
223:100DE0008EB000F017FF226842F30732002A12DBB0
224:100DF000012053099B0003F1604303F56143D3F8DD
225:100E0000801202F01F0200FA02F221EA0202C3F885
226:100E10008022D3F880322422002105A804F0ABFE02
227:100E2000D4E902124FF0FF33CDE90133CDE90333AA
228:100E30004FF0EB730B93072301A88DF8363001F0C8
229:100E400080F8014600220B4800F03AFA0A4B98421B
230:100E50000DD10C9B002023831B0CA3760B9BC4E9B4
231:100E60000400E361012384F820300EB010BD6FF060
232:100E70000100FAE7841000200000AD0B7FB50025CB
233:100E80000C46C0F808511646D0F80821D0F80022C8
234:100E900022F02002C0F80022104AC0F8082301F016
235:100EA000A0F8A560256104F14C03D3E8EF1F21F4FD
236:100EB0007F0121F47041C3E8E21F002AF5D110221E
237:100EC0002946684604F057FE042368468DF8003032
238:100ED0000196D4E90013984704B070BD10020A00CF
239:100EE00000F01F03400909D1074A02EB8303D3F83E
240:100EF0000012064A0A40C3F80022704700228033DD
241:100F000052F82330FFDE00BF00258450F0F8FCFFCC
242:100F10002DE9F04F804690F804A05020664F0E4611
243:100F200000FB0A70416885B049B113F0020304D098
244:100F3000836B002B00F0B2800123009300E000914E
245:100F40004FF0500909FB0A73DB6CD90600F1A6804B
246:100F50004FF0010BB3180293029BB34200F0A7803D
247:100F600006F06043039398F80450D8F8004009FB5A
248:100F700005739A6B9AB9039BB3F1005F40F09980B7
249:100F8000019200F0A1FD09FB0572D16C204601F031
250:100F9000010100F0F4FF28B900F09EFDE3E7012312
251:100FA0000193EEE7516C33460029BCBFD4F84C15D1
252:100FB0005164019A42B109FB05713078D1E90E23E1
253:100FC000D054D1E90E3213441BB1C4F84435C4F8EF
254:100FD00048B50022C4F82021D4F82011C4F85821C3
255:100FE000D4F85811C4F85021D4F850210822C4F87C
256:100FF0000025009AE2B14FF48003C4F80433C4F82A
257:1010000008B000F069FD502303FB0A725168002903
258:101010004BD1D26C120748D503FB0A734C33D3E88B
259:10102000EF1F21F00801C3E8E21F002A36D0F6E7DF
260:10103000C4F808B0019300F04FFD09FB0572D16CB4
261:10104000019B01F001012046019300F098FF8446C6
262:10105000019BD4F84C05D4F84425BCF1000F0DD108
263:101060009342F0D005EB850507EB0515D1B100F0F3
264:101070002BFD2946204600F0F9FFC2E705EB850568
265:10108000934207EB0515F1D10028EFD100F01CFDCC
266:101090002946204600F0EAFF00F01EFD074805B093
267:1010A000BDE8F08FC4F80CB0E1E7013654E704481E
268:1010B000F5E70448F3E700BF581900200800AD0B1E
269:1010C0000000AD0B0400AD0B430904D10123034A1A
270:1010D00083409360704700239B60FFDE00258450AF
271:1010E00000F01F0340090BD1084A02EB8302D2F83B
272:1010F0000012074B0B4043F00303C2F80032704765
273:101100000022803352F82330FFDE00BF00258450D8
274:10111000F0F8FCFF2DE9F84391F8303005460C4615
275:1011200090F804800F6853BB5023DFF85091781C6F
276:1011300003FB0893DE6C46F00072DA6404D0384694
277:10114000FFF7C2FFFFF7CCFF6068411C01D0FFF73B
278:10115000C7FE94F82C30012B11D1502303FB0893C8
279:10116000E06846F02066421CDE6401D0FFF7B8FE5E
280:10117000A068431C03D0FFF7A7FFFFF7B1FF94F867
281:101180002F0038B950223D4B02FB0833DA6C42F095
282:101190008072DA6494F82CC094F82D1094F82EE044
283:1011A000A26A2B6841EA0C01E668D4E90198C3F809
284:1011B00024254EEA0102C3F86C2550B9BCF1010F99
285:1011C000C3F80C75C3F8149504BFC3F80885C3F8B9
286:1011D0001065D3F8682503F26458012A08BFDA6065
287:1011E000D3F86425012A13D1082149F64046244F3B
288:1011F000C3F8001547F001075A60D8F800309BBBD0
289:101200002B68D3F88024C3F880240022C3F800257B
290:1012100000212B6894F83220C3F81011D3F8100184
291:10122000C3F82011D3F82001C3F82411D3F8240106
292:10123000C3F84411D3F84401C3F85811D3F8581136
293:1012400043F307335201002BD2B212DB0D49C81809
294:1012500080F800230122580903F01F0302FA03F368
295:1012600041F82030BDE8F8834020B847013EC4D1A2
296:10127000C6E7054903F00F03CA54F3E758190020E5
297:10128000A034000000E100E014ED00E000F01F03D6
298:1012900040090BD1084A02EB8302D2F80012074B37
299:1012A0000B4043F00203C2F8003270470022803343
300:1012B00052F82330FFDE00BF00258450F0F8FCFF19
301:1012C0002DE9F3479046502290F80490514C02FBD0
302:1012D00009FA04EB0A070D4697F84810064600295C
303:1012E00040F0858009EB890004EB001004F043FC1A
304:1012F0002B69AA6944F80A306B69BB6302B1013AF1
305:10130000502303FB0943DA632A6A042A81BFEA698E
306:101310009A610022DA6195F83130B8F1000F37D0C8
307:1013200083F001073F0233B1502303FB0943DA6C1A
308:1013300042F00102DA64502303FB09440123C4F89C
309:10134000048084F848303468D4F84C2112BB294614
310:101350003046FFF7DFFE0822002334688DF807309F
311:10136000C4F800250DF10702C4F84425C4F8483537
312:1013700001230A25A360E360D4F85831002B38D14B
313:10138000254B402043F001039847013DF4D128E06C
314:101390004746C8E708224FF06409C4F80025636097
315:1013A0001D4B43F0010AD4F84431F3B9D4F8243189
316:1013B000DBB94FF42070D047B9F10109F3D14B46A6
317:1013C0000022C4F84C21D4F84C11C4F81021D4F8F0
318:1013D0001011C4F84421D4F84411C4F80025002B9E
319:1013E000B5D10E4802B0BDE8F0870123E8E70C480C
320:1013F000F8E70023C4F820319845D4F82021C4F838
321:101400000035084B08BF00231F4333680648C3F864
322:101410000473E7E758190020A03400000100AD0B69
323:101420000C00AD0B10020A000000AD0B2DE9F047D7
324:1014300084460F469E4616460579002A51D04FF045
325:10144000500ADFF8BC80D0F800900AFB058ADAF871
326:10145000044074B96BB9DAF82C50002D43D1CAF8A6
327:101460002C20FFF755FD0446CAF82C502046BDE855
328:10147000F0871EF0030F07D0734632463946BDE8A9
329:10148000F0476046FFF744BD07F06043B3F1005FEB
330:101490004FF0500414D104FB058400F015FBE26A00
331:1014A0001AB1134C00F018FBE0E7C4E90A7605EB2B
332:1014B0008505484608EB051100F0E3FD0D4CF1E70A
333:1014C00004FB0584A36B83B100F0FEFAE36A002BF2
334:1014D000E7D1E36C012243F00203C4E90A76E36436
335:1014E000E5E7054CC2E7024CC0E7044CBEE700BF8D
336:1014F0000B00AD0B0000AD0B0600AD0B0A00AD0BF1
337:10150000581900202DE9F84350230679284D046826
338:1015100003FB0653D4F80473DA6AC4F8087322B9DB
339:101520002448C4F80473BDE8F88306EB860005F18F
340:101530004C024FEA001802EB0012D2E8EFCF4CF059
341:10154000080CC2E8E0CF0028F7D10122E26031B3F5
342:10155000D96C01EA02094946204600F010FD002836
343:10156000FAD000F0B1FAB9F1000F1CD1D4F8203153
344:1015700053B10123E360D4F85831002BFBD020464F
345:1015800005EB080100F072FD00F0A6FA0023C4F894
346:101590002031D4F82021502202FB0655EB62064888
347:1015A000C4F80473BFE7D4F85831002BE7D1EBE758
348:1015B000581900200500AD0B0000AD0B2DE9F843D4
349:1015C00090F80480484F08EB8806360106F14C0578
350:1015D00004683D44D5E8EF3F43F48052C5E8E02F6E
351:1015E0000028F7D1DB047BD4480705D5502303FB43
352:1015F00008739B69002B75D03C4B3E44C4F80833FC
353:101600000823C4F800350023C4F81031D4F81021A1
354:10161000C4F84C31D4F84C21C4F844310A03D4F84E
355:1016200044318B0303F4804302F400524903134313
356:1016300001F400410B43D5E8EF2F1A43C5E8E12F31
357:101640000029F8D14FF0500909FB0879D9F8083082
358:10165000BBB9D9F8043063B9D5E8EF3F23F47F0371
359:1016600023F47043C5E8E23F002AF5D12048BDE8E5
360:10167000F8830321304600F08FFCD9F80830002BA6
361:10168000EAD0D4F80433590713D5502303FB087369
362:101690005A6872B1DB6C1A030BD5D5E8EF3F23F41F
363:1016A0000023C5E8E23F002AF7D10621304600F0CA
364:1016B00073FC502303FB0873DB6CDB0401D40D487F
365:1016C000D5E7D4F84C310BB901232360502303FB39
366:1016D00008735B68002BF2D0044BC4F80433EEE7C8
367:1016E0000548C4E70548C2E75819002010020A005F
368:1016F0000200AD0B0000AD0B0B00AD0B0800AD0BF5
369:101700002DE9F84F056801F06043D5F804A3B3F163
370:10171000005F90F804B089461746C5F808A37CD14D
371:101720005023404E03FB0B639A6852B15B68002B59
372:101730005ED1D5F81021002A5AD0C5F81031D5F85D
373:101740001031502404FB0B64E269C4E90297002ABB
374:101750003CD00BEB8B0897424FEA081824D24FF08D
375:10176000000B3A46A1694846C4E902BB04F0DEF921
376:10177000E269A069D21BC119E26104F0A1F96368B2
377:101780006BB1B04449463A46404600F016FCE36C63
378:10179000990404D55A4641462846FFF76FFB224874
379:1017A000C5F804A3BDE8F88F4846A16904F0BEF966
380:1017B000E36963620023E3611C4B9844D8E8EF3F80
381:1017C00043F40023C8E8E23F002AF7D1502303FB8B
382:1017D0000B63586ADA689968DB6C121A0144C5F821
383:1017E0003415C5F83825DA04D9D501232B60D6E79E
384:1017F000502303FB0B6633698BB9F36CC5F8349542
385:101800005B04C6E90497C5F83875C8D5D5F8003229
386:1018100043F02003C5F80032C1E70548C0E705489A
387:10182000BEE700BF581900200000AD0BA41900202E
388:101830000A00AD0B0B00AD0B50232DE9F0413C4DE0
389:1018400090F80480046803FB0853DB6CD4F80002B2
390:1018500003F48223B3F5805F68D1D4F80463C4F83D
391:10186000086309B9830656D4D4F8003223F0200364
392:10187000C4F800324FF4842308EB8801090101F118
393:101880004C072F44D7E8EF0F1843C7E8EC0FBCF123
394:10189000000FF7D12AB9502303FB08535B68002BD4
395:1018A00041D1244BC4F8083301236360D4F8443198
396:1018B000002BFBD00023C4F84C31D4F84C21C4F8E1
397:1018C0001031D4F81021C4F84431D4F844315023F5
398:1018D00003FB0853DA6C12F400421FD1DA61204690
399:1018E00000F07FFB502303FB08550023AB602B6106
400:1018F000D7E8EF3F23F47F0323F47043C7E8E23FC8
401:10190000002AF5D126F4202626F404760A48C4F8E5
402:101910000463BDE8F0814FF48033ADE720462944ED
403:1019200000F071FBDBE701236360EFE70348F0E7BA
404:101930005819002010020A000000AD0B0500AD0B85
405:101940002DE9F8432F4A03680679C3F8082343F3C7
406:101950000733002B04460DDB01215A0903F01F0356
407:10196000994002F12003284A42F82310BFF34F8F19
408:10197000BFF36F8F012220461146FFF75DFF012163
409:101980002046FFF7BFFD50212279204D236801FB3F
410:101990000252D46CD3F80C05E201D3F81495D3F8B5
411:1019A0000875D3F8108509D54FF0FF32C3F80C2520
412:1019B000C3F81425C3F80825C3F81025A30116D5CC
413:1019C000411C01D0FFF762FCB9F1FF3F02D048464D
414:1019D000FFF75CFC22010AD5B8F1FF3F02D0404678
415:1019E000FFF754FC7B1C02D03846FFF74FFC502316
416:1019F000002203FB0653DA6483F848205A60BDE8EE
417:101A0000F88300BF10034A0000E100E058190020ED
418:101A100010B5502402790B4B04FB02335B686BB9A1
419:101A20000368D3F810211AB9D3F80025082A07D083
420:101A300011B1D3F83C350B60034810BD0348FCE7F7
421:101A40000348FAE7581900200000AD0B0800AD0B61
422:101A50000B00AD0BF7B505461646FFF751FE164BCA
423:101A60000446984222D1032128462F79FFF7A6FD8C
424:101A7000124B984201D0A0421BD15022104B02FBC6
425:101A800007335B6893B90C4C284601A9FFF7C0FFE8
426:101A9000A042F9D1019BB34207D301222846114647
427:101AA00003B0BDE8F040FFF7C7BE064C204603B0C8
428:101AB000F0BD0446FAE700BF0000AD0B0B00AD0B14
429:101AC000581900200800AD0B72B6024A13680133A2
430:101AD00013607047A8190020034A1368013B136084
431:101AE00003B962B6704700BFA81900200722024B55
432:101AF000C3F80423704700BF00300050084BD3F8F0
433:101B00000801D3F80021003818BF012080000AB175
434:101B100040F00100D3F804310BB140F002007047EF
435:101B2000003000500022074BC3F80021D3F8001109
436:101B3000C3F80421D3F80411C3F80821D3F80831FD
437:101B4000704700BF0030005000231720094A03F5FA
438:101B5000C0710133202B42F82100F8D10023172057
439:101B6000044A03F5E0710133202B42F82100F8D13B
440:101B7000704700BF0030005010B59DF80840C00B02
441:101B800043EA0423064CC90B43EA0213884200D9F6
442:101B900010BDC2B202F5C07244F822300130F5E740
443:101BA0000030005010B59DF8084000F1604043EA55
444:101BB000042301F16041074C400B490B43EA021337
445:101BC000884200D910BDC2B202F5E07244F822305A
446:101BD0000130F5E700300050C0F30E03C3F50043B9
447:101BE000B3FA83F3C3F11B03064AC0F3C730DBB279
448:101BF00040F4807043F48073C2F80005C2F80435E5
449:101C0000704700BF0030005043030148184470473C
450:101C1000FF1FF81F054BC0F30730090241F03001E8
451:101C200000F5007043F82010704700BF00300050EE
452:101C3000044BC0F30730090200F5007043F8201090
453:101C4000704700BF00300050003A18BF0122003931
454:101C500018BF012103688900074841EA420118635F
455:101C600059605A6842F001025A60BFF34F8FBFF3C8
456:101C70006F8F0020704700BF04AAFF0008B5FFF770
457:101C80003DFF044B162118600348BDE8084000F0F2
458:101C90003AB900BFEC1F0020A63400000C22014915
459:101CA00003F044BFEC1F002010B501F006FB044612
460:101CB00090B901F097FF044680B90A4A2E21D368F3
461:101CC000094823F008031B041B0C43F0BF6343F4D3
462:101CD0000033D36000F017F9204610BD45F22354BD
463:101CE000FAE700BF00ED00E0BC340000024B1860D2
464:101CF000024B002019607047FC1F0020F81F0020D5
465:101D00001FB5374C426923685A6282699A62C26978
466:101D1000DA62026A1A63426A5A63826A9A63C26A20
467:101D2000DA63026B1A64426B5A60826B9A60C26B10
468:101D3000DA60026C1A61426C5A61826C9A61C26C00
469:101D4000DA61026D1A62826D5A65C26D9A65026F20
470:101D5000DA65026E1A66826E5A66426F9A66EFF311
471:101D600088825A64EFF389829A644268DA64EFF3F6
472:101D700094821A65026801A81A67FFF78FFF23682B
473:101D8000019ADA6601221A70164B1C686408640016
474:101D90002046214622462346B7EE000AF7EE000A07
475:101DA000B7EE001AF7EE001AB7EE002AF7EE002A97
476:101DB000B7EE003AF7EE003AB7EE004AF7EE004A07
477:101DC000B7EE005AF7EE005AB7EE006AF7EE006A77
478:101DD000B7EE007AF7EE007A03F081FF04B010BD91
479:101DE000FC1F0020F81F002000B5A1B001A8FEF7DD
480:101DF000C9FD029B63B15B060AD4019B23F0020379
481:101E0000052B05D1044B1B6813B101A8FFF778FF20
482:101E100021B05DF804FB00BFF81F0020BFF34F8F17
483:101E20000549064BCA6802F4E0621343CB60BFF376
484:101E30004F8F00BFFDE700BF00ED00E00400FA0592
485:101E400038B543680C2B30D14B68042B2DD14FF0A3
486:101E5000FF3304680D6821682B6031B3A26822B398
487:101E60000623012001F081F9F8B96168104B99420D
488:101E70000DD9A2680F485318834202D9F43883421F
489:101E800010D8206803F052FE0020286038BD0A4BAD
490:101E900099420AD9A26809488B188342F1D90730C0
491:101EA000814202D906488342EBD90220EEE700BF07
492:101EB000FF01FF002C02FF002F01FF003801FF008F
493:101EC0004C01FF004FF47F03D3F83001D3F83431D5
494:101ED000BFF34F8FC0F30B00A0F1090358425841E4
495:101EE00070474FF47F02D2F83031D2F83401BFF39B
496:101EF0004F8FC3F30B03092B03D1431E58425841A4
497:101F0000704700207047FEF7CDBD012070476FF08D
498:101F100003007047002382B00193019802B070471C
499:101F20006FF003007047002382B00193019802B064
500:101F30007047022814BF6FF0030000207047FEF7BF
501:101F40002DBE30B501EB8202914200D130BD51F877
502:101F5000044B04F07F037F2B4FEA144408BF4FF07B
503:101F6000FF33032CF0D8DFE804F002040608036016
504:101F7000EAE74360E8E78360E6E7C360E4E7034637
505:101F8000D0F8580130B931B9D3F82001003818BF62
506:101F9000012070470120704730B504460D4685B0DA
507:101FA00010220021684603F0E6FDD4E900136846DC
508:101FB0008DF80050984705B030BD7FB504460E46F9
509:101FC000154600211022684603F0D5FD012368461E
510:101FD0008DF80030CDE90165D4E90013984704B0CD
511:101FE00070BD10B50446FFF76FFDD4F8583133B11A
512:101FF000D4F8043313F4800308BFC4F80035BDE8F7
513:102000001040FFF769BD70B50D4604460522AA21B0
514:10201000D0F83C65A86903F0AEFD0522AB69C4F8B1
515:102020003435C4F838250022C4F81021D4F8101132
516:102030000121E162D4F810110029FBD0C4F84C2131
517:10204000D4F84C11C4F81021D4F81021D4F83C2550
518:102050009642EA6109D15A1E043312F8011FAA29D7
519:1020600003D19A42F9D10023EB6170BDD0F8583109
520:1020700033B1CB6CC3F30032DB0458BFC0F800258A
521:10208000704770B5CE6C0D4606F001010446FFF7AF
522:1020900076FF38B94FF4800346F00406EE64C4F8C6
523:1020A000043370BDD5E90A365AB1296CEA6B761A49
524:1020B000964228BF164619443246A86B03F036FDF7
525:1020C000AB6B4FF0FF326A641BB1C4F84435C4F8FF
526:1020D00048650023C4F82031D4F82021C4F85831D1
527:1020E000D4F85821C4F85031D4F850310823C4F83A
528:1020F00000354FF48003C4F804330123A360D0E714
529:10210000C0037047C00300F5FF407F3070470020D8
530:1021100070471F2070474FF40040704700F57F4024
531:10212000C03040037047402070475F2070474FF435
532:10213000005070474B6830B513F01F052DD1026871
533:102140000C681068C0F30720844226D2506855609E
534:1021500094600C7C23F01F0304F001041C438B7C6F
535:10216000DB0003F018031C434B7C5B0003F0060309
536:102170002343D3608B68013B23F01F04CB685B00D3
537:1021800003F00E03234343F0010313615060BFF3D8
538:102190004F8FBFF36F8F284630BD0120FCE70368E7
539:1021A00000205A68C9B258609960D86018615A60B6
540:1021B000704770B50546002403681E68C6F30726FD
541:1021C000B44201D1002070BD21462846FFF7E7FF49
542:1021D0000134F5E70020704708B5FFF705FE72B639
543:1021E00020BFFDE7002070470020704770470B4676
544:1021F00070B5114618B1032806D0032070BD1846EB
545:10220000BDE87040FFF71CBE5A68082A01D00220C2
546:10221000F4E74C68042CFAD11D684FF0FF330E68C8
547:10222000296833600029F2D06B68002BEFD0262399
548:102230007422012000F099FF0028E8D122462323D0
549:102240000120696800F091FF04460028DFD1D5E93C
550:102250000001FFF74BFD30602046CFE730B50C465C
551:10226000154685B038B139B1FFF74DFE041E03DACB
552:10227000204605B030BD044640F60D23ADF80E30C3
553:1022800009230B4901A805F00F028A5C2D091A5495
554:10229000013B012BF7D147F630030C21ADF8043098
555:1022A000FFF731FE0028B4BF04462418E0E700BF62
556:1022B000EA34000008B5194B83F30A88184800F087
557:1022C000E7FF40BBFFF7F0FC28BBFFF783FF10BB25
558:1022D000FFF788FFD8B9FFF789FF00F067FA3521CB
559:1022E0001048FFF710FE17210F48FFF70CFE1821CA
560:1022F0000E48FFF708FE00F03FFC21210C48FFF7D5
561:1023000002FE00F03FFA00F0CDFE002008BDFFF70E
562:102310006BFF0028DFD000F021FEEEE70004002074
563:10232000AC190020FA3400002F35000046350000BB
564:102330005E3500002DE9F04F93B00093574B814676
565:10234000D3F800B00BB2002B0D461646C1F302685D
566:10235000C1F3024A04DA6FF0800013B0BDE8F08FD9
567:102360008B42C36001D10020F7E708EB0A03042B7E
568:10237000F1D8CC0F64014FEAC80731463A46DBF882
569:10238000080044F0020300F0F0FE01460028E2D10C
570:10239000202202A803F0EFFB3A46314602A84FEA9A
571:1023A000CA0603F0C3FB32460099DBF8080044F08C
572:1023B000060300F0DAFE07460028CCD101462022B1
573:1023C0000AA803F0D8FB324600990AA802AE03F02F
574:1023D000ADFB33460137B84514D91A46BC460DE06B
575:1023E000D2F808E0D16818687144884203D259686D
576:1023F00008448645AFD30CF1010C0832C445EFD137
577:102400000833E7E715F0006F18BF202409F118071B
578:1024100007EB880844F00203474513D1202C26D14E
579:10242000002D02DBC5F3C0456C0109F128050AAE99
580:1024300005EB8A0A44F0060455451AD1009BC9F8F9
581:102440007C3090E77268DBF8080056F8081B0193AF
582:1024500000F08BFE00287FF47EAF56F8042C019B21
583:1024600047F8042F56F8082C38633A62D4E7002462
584:10247000DBE77268234656F8081BDBF8080000F01B
585:1024800074FE00287FF467AF56F8043C45F8043F1B
586:1024900056F8083C28642B63CEE700BFB019002033
587:1024A0002DE9F0411F461A4B0D461646D3F8008021
588:1024B00000F051FF044608B900F050FDE368002B1E
589:1024C00001DA00F04BFD032D01D900F047FD04EBCC
590:1024D0008504E569E36CED1A16D006233A463146C9
591:1024E000D8F8080000F041FE08B100F037FDBD4209
592:1024F00028BF3D46E36CE16B2A461944304603F0A1
593:1025000015FBE36C2B44E3642846BDE8F08100BF73
594:10251000B01900202DE9F0411D461A4B0F46164612
595:10252000D3F8008000F017FF044608B900F016FD4C
596:10253000E368002B01DA00F011FD032F01D900F050
597:102540000DFD04EB8704E36AE26E9B1AAB4201D2F5
598:1025500000F004FD02232A463146D8F8080000F0B6
599:1025600004FE08B100F0FAFCE36EE06D2A46314645
600:10257000184403F0DBFAE36E00202B44E366BDE869
601:10258000F08100BFB01900202DE9F04105464FF061
602:1025900001080E4E0E4B37685C681CB92846376040
603:1025A000BDE8F0812268936813F400700CD1A36930
604:1025B000012B09D0D368346023B19847002801DA91
605:1025C00000F0CCFCC4F81880246AE6E7B0190020BB
606:1025D000B419002038B5044610B96FF0800038BD3A
607:1025E0008368002BF9D01A68002AF6D05D68002DA8
608:1025F000F3D00B4BE861A8691D6020B92B68DB683C
609:1026000053B90123AB61A36804F10C001B681B697B
610:10261000984701232360E2E798470028F1DADCE7D6
611:10262000B01900204268024B08461A60704700BF8C
612:10263000B0190020002330B505680446AA68C0E937
613:10264000063312F4406F85B01CD012F4006202D041
614:1026500000F0C2F90246A96A2B6968460B440731AB
615:1026600023F0070321F00701CDE9021300930023B3
616:1026700005490193EB6800F09FFA684600F04EFEB2
617:10268000024B1C6005B030BD89250000B019002048
618:1026900001F00C0370B50C2B0CBF154605464A061D
619:1026A0000C461ED58B0658BF2835AB6913F8026C53
620:1026B00084F00803C3F3C003C6F38012934201D031
621:1026C00000F04CFC16F0A00F1ED176B1032E17D0EF
622:1026D00032461C210E48FFF7C1FD6FF083032B60CB
623:1026E0000CE000F03BFC2026E2E700F03BFB044658
624:1026F000FEF70EFA2146074800F00AFE204670BD9C
625:10270000284600F03FFAF9E732461F210248E2E787
626:102710007F350000F80B00209B350000EFF30880A8
627:102720007146EFF30982EFF30B830CB406B4FFF7A5
628:10273000AFFF8646009900F0080001F00801401A3A
629:1027400002DC12DB04B070471EF020031CBF2DE931
630:10275000F00FBDF1080D0A4C254626462746A04637
631:10276000A146A246A34630B4704704B030BC1EF068
632:1027700020031CBF1DF1080DBDE8F00F04B0704729
633:10278000A5EDF5FE084BDA6882F07F4282F47F0205
634:1027900042F48042DA6000221A765A76DA76DA77E4
635:1027A000602283F82220704700ED00E0114BD3F83F
636:1027B000882042F47002C3F88820BFF34F8FBFF324
637:1027C0006F8FD3F88C2042F44062C3F88C20D3F88A
638:1027D000342242F08042C3F83422D3F8342242F04B
639:1027E0003C42C3F834224FF0E022D36843F4200384
640:1027F000D360704700ED00E0009A164B9A4227D153
641:1028000001229043014641EC100B41EC110B41ECCD
642:10281000120B41EC130B41EC140B41EC150B41EC8A
643:10282000160B41EC170BEFF3148222F0040282F333
644:102830001488BFF36F8F02460346044605460646DA
645:10284000074680468146824683468446864604473C
646:10285000FEE70000A5EDF5FE2DE9F041044618B9AC
647:1028600043F6DA30BDE8F0810029F9D0836800250D
648:1028700013F4406F14BF01230023134F43F00203EE
649:10288000DFF848800B6000F13006236AAB4201D8C4
650:102890000020E7E71421A369E26906EB830301FB4B
651:1028A00002330C226A4399188968090709D59B5895
652:1028B000BB4201D04345D3D1186810B10121FFF7C5
653:1028C000A9F90135E1E700BFB4100020AC100020E9
654:1028D00070B5324C86B03248FFF76BFC2368012597
655:1028E0005A1C01932F4B2260DA681B694FF4407623
656:1028F000039300232A4801A902920495ADF81460BD
657:102900008DF81630FFF716FC18B143F6DA3006B032
658:1029100070BD23688DF816005A1C0193224B204885
659:102920000293224B01A9CDE903352260ADF8146072
660:10293000FFF700FC0028E8D123688DF816005A1C28
661:1029400001931B4B164802931A4B01A9CDE903359D
662:102950002260ADF81460FFF7EDFB0028D5D12368A5
663:102960008DF816005A1C0193134B0D480293134B1C
664:1029700001A903930223049340F201132260ADF8EE
665:102980001430FFF7D7FB04460028BED12A4629465B
666:102990000348FFF759F92046B9E700BFBC190020EA
667:1029A000A81000202C36000060360000005F0000F8
668:1029B0002006000020060000000C0020200C002053
669:1029C000014B1868704700BF2C360000014B1B6894
670:1029D000186870472C360000014B1B685868704718
671:1029E0002C36000008B5FFF749F9FFF79BF80A4BB2
672:1029F0005A68103AD3B2120609D401215A0903F0D9
673:102A00001F03994002F16003044A42F82310BDE815
674:102A1000084000F0A3BA00BF00ED00E000E100E0D4
675:102A20000020034BD8765A6A42F470225A627047EB
676:102A300000ED00E00349044BCA68002092B2134342
677:102A4000CB60704700ED00E00800FA0500224FF06F
678:102A5000FF300D4B02F1A0010132102A43F8210092
679:102A6000F8D1D3F88022002022F00802C3F8802297
680:102A7000D3F88022D3F8802222F40072C3F8802297
681:102A8000D3F88032704700BF00E100E008B5FFF7DF
682:102A90002DF80822024BC3F880211A60002008BDDF
683:102AA00000E100E0064BD3F8D02022F00102C3F889
684:102AB000D020D3F8D02042F00202C3F8D0207047D3
685:102AC00000ED00E037B50124FFF73EF8134D224634
686:102AD000052347F6FF7100200094FFF74DF82246CA
687:102AE00007234FF000500E490094FFF75BF8D5E93B
688:102AF0000101072300220094FFF73EF8072300227C
689:102B0000084909480094FFF74DF82969E868013938
690:102B1000FFF762F8002003B030BD00BF2C36000084
691:102B2000FF7F0020FFFF03200080002038B5002435
692:102B30000E4D002155F8040B0134FFF779F81C2CD9
693:102B4000F7D10020012240F20111094BC3F88004A3
694:102B5000C3F88424C3F8C004C3F8C424054AC2F8E7
695:102B600040154FF48072C3F8402438BDBC350000D6
696:102B700000300050009003500122014B1A60704752
697:102B8000C019002010B50446094B228918686168F5
698:102B90000623806800F0E9FA28B9064B1B68012B70
699:102BA00001D100F087F86FF08603236010BD00BFED
700:102BB000B0190020C01900202DE9F84305461E4633
701:102BC0000068134B9046AA68A0F1080440E902335C
702:102BD000503890420F4601D200F0C0F9A4F14809E4
703:102BE00048220021484602F0C6FF002344E907338B
704:102BF00044F8143C4FF0807344F8043C6FF0020337
705:102C000044E9036744F8208CC5E90093BDE8F883E4
706:102C1000A5EDF5FE30B5094C024661680023084673
707:102C200040B105686D68954205D11BB1826860604E
708:102C30009A60816030BD03468068F1E7441A002045
709:102C400038B504462AB10B689B68DB0512D5002015
710:102C500038BD0B4B1D680DB900F080F900222B68C0
711:102C600099692C338A4203D053F8040FA04204D14F
712:102C70009142ECD16FF0FC00EAE70132F2E700BFCD
713:102C8000B019002070B504460E46154600213022CA
714:102C90000C3002F070FF064B20461B68A660636094
715:102CA000656100F001FA00232061236070BD00BF60
716:102CB000B0190020044B1B681BB11B680BB158688E
717:102CC00070474FF0FF307047B0190020064B10B529
718:102CD0001C680CB900F042F923689B6813F4406F3C
719:102CE00014BF0120002010BDB01900202DE9F843C9
720:102CF000904607460C46FFF7E9FF024624B96FF0FD
721:102D000080042046BDE8F8836300F8D5144B04F036
722:102D10001F0153F82150002DF1D02B682946586827
723:102D2000FFF78EFFB0B9C4F30721284600F001FB7E
724:102D300004460028E3D1EFF3108972B600F0C1F920
725:102D4000064689F3108840B142462946FFF79AFFAC
726:102D50003E60D6E76FF08104D3E76FF08204D0E7DE
727:102D6000C41900202DE9F04100F0AAF90023134E08
728:102D7000134F73607B6000F0E5F8DFF84880304661
729:102D800000F022F80446A8B139468023424600F0FC
730:102D90007FF80546204600F011FB206804F1080189
731:102DA000FFF75AFD08B100F0D9F829462046FFF791
732:102DB00041FCE4E7BDE8F04100F071B9B41900202E
733:102DC000441A0020C4190020F8B5054608B900F0DF
734:102DD000C5F82A4E346814F1290F4CD8284B1968CD
735:102DE00004F128038B4246D2236AA26903EB430312
736:102DF0000C321344606AE269024402EB820213441B
737:102E00009B00E31801D2994201D200F0A7F8236891
738:102E10001C4A1B0C1B04934201D000F09FF823882E
739:102E2000B3F5817F01D300F099F86368002B01DAD4
740:102E300000F094F8144A176807F124031360134A4A
741:102E40001268934201D900F089F8236AA26903EB62
742:102E500043030C32616A1344E2693C600A4402EBAA
743:102E600082021344326802EB83026B6832603B6279
744:102E70006F603846F8BD0027FBE700BFC410002094
745:102E80004836000000005F5FC0100020443600009C
746:102E90002DE9F74F0F4690460646009300B109B959
747:102EA00000F05CF8D6F800A0DAF818200AF1300338
748:102EB00003EB820BDAF81C40204B1D6854B10C2246
749:102EC00002FB04541C601E4B1B689C4201D900F09D
750:102ED00045F82C4625464FF00009DAF81C204A45F3
751:102EE00000D91CB9002003B0BDE8F08F142303FB08
752:102EF00009B20023C5E900269268AB60930516D598
753:102F0000B8F1000F02D0009B802B03D0019200F09B
754:102F100025F8019A12F0E00FD0B202D158F8202023
755:102F20001AB1019000F01AF8019848F820507A6818
756:102F300009F10109AA607D600C35CEE7BC100020C4
757:102F40004036000008B5FFF73BFD034B9860FFF7E4
758:102F50003DFD80F3888808BD00ED02E0FFF73CB935
759:102F60008230012808B506D8FFF7B0FE18B9BDE8D1
760:102F70000840FFF7F3BF08BDF8B506460D4600F060
761:102F8000EAF9044608B9FFF7E9FFA7680FB9FFF7A8
762:102F9000E5FFE368991C20D05A1C21D1A5B315F197
763:102FA000820F13D102232360EFF3108672B62946F5
764:102FB0002046FFF737FB054686F310882368022B6F
765:102FC00024D1204600F086F82846F8BD15F1830F7D
766:102FD000EAD0FFF7C3FF0025E6E702232360FAE704
767:102FE000002BF6DB204600F0DAF93B689B689B0576
768:102FF00001D50223236015F1810FD5D16369002B20
769:10300000D2DBFFF7ABFFCFE73546F4E700232360C1
770:10301000DAE708B5FFF7E0F86FF0830008BD2DE9A7
771:10302000F3410E46174698460546FFF74FFE00F05F
772:10303000A6F92946024601A8FFF758FE044660B9E2
773:1030400043463A4631460198FFF774F9044640B1C9
774:103050006B0002D5019800F03DF8204602B0BDE8B3
775:10306000F0810198FFF7B6FA0446F6E740F2011046
776:10307000704770B50546FFF729FE06462846FFF75C
777:10308000C9FD044608B9002070BD014632462846F5
778:10309000FFF7D6FD0028F6D12368D868F4E76FF073
779:1030A0000200704700DF70474FF480507047B0F562
780:1030B000805F03D1EFF30B808038704700207047AA
781:1030C0007047EFF30B8000F1800383F30B887047A8
782:1030D00000207047EFF30B83803B83F30B8870472E
783:1030E00080EA0000E1EE100A00EE100A00EE900AFD
784:1030F00001EE100A01EE900A02EE100A02EE900AAA
785:1031000003EE100A03EE900A04EE100A04EE900A91
786:1031100005EE100A05EE900A06EE100A06EE900A79
787:1031200007EE100A07EE900A08EE100A08EE900A61
788:1031300009EE100A09EE900A0AEE100A0AEE900A49
789:103140000BEE100A0BEE900A0CEE100A0CEE900A31
790:103150000DEE100A0DEE900A0EEE100A0EEE900A19
791:103160000FEE100A0FEE900A70472DE9F0410E465F
792:103170001546002A4AD0C4074BD480F00204C4F399
793:103180004004A40003F00602062A4AD144F00104D8
794:1031900022462946304602F077FBB8BB46E800F2EB
795:1031A00005EB0608100E120208F1FF3747E800F39E
796:1031B0004FEA136166D51B0264D5884262D046E8A7
797:1031C00000F547E800F7FEF7A2FF2D0E85424FEA13
798:1031D000176734D3FEF79DFF874230D82846FEF7A5
799:1031E00091FF2246C6F101010144304602F04CFB3A
800:1031F000002847D00135AF4218D83846FEF780FF87
801:103200002246A8EB000102F03FFBD8B30020BDE846
802:10321000F081EFF39484A40004F0040444F0120459
803:10322000B0E7990731D544F00804B1E72846FEF726
804:1032300067FF0646FEF76FFF22460146D5E7FEF719
805:1032400072FF85421ED3FEF770FF87421AD82846C8
806:10325000FEF7DAFC2246C6F101010144304602F0D5
807:1032600013FB78B10135AF4203D83846FEF756FF5D
808:10327000C6E72846FEF752FF0646FEF758FF2246ED
809:103280000146EBE76FF07F00C1E74CF2DA20BEE7C2
810:1032900010B50446FFF706FCFFF714FC10B143F627
811:1032A000DA3010BDFFF742FC0028F8D1FFF710FB21
812:1032B0000028F4D102232360F3E708B5FFF7B0FB41
813:1032C00010B143F6DA3008BDFFF7B4FB0028F8D19F
814:1032D00000F01CF80028F4D162B6FDF703FCFFF7FC
815:1032E000B5FB0028EDD1FFF7D1FB0028EBD0E8E7D4
816:1032F000EFF30880EFF309812DE9F00F6B4672467A
817:10330000FDF746FB08B0FFF76DFBFEE700207047B6
818:1033100004460D46FFF7E4FEA54628470368283318
819:1033200083F30988836883F30B88BFF36F8F40684A
820:10333000704703689A68DB6812F4806F05D18B428E
821:103340002CBF00206FF0FA0070478B420CBF0020AA
822:103350006FF0FA00704710B5FFF7A9FE0446FFF7BB
823:10336000B7FE50B9FFF7A6FCA3685B681B685B68F3
824:10337000834218BF0024204610BD0024FBE738B567
825:10338000054648B100F01BF8B5EBD07F044601D0EC
826:10339000FFF7E4FD204638BDFFF78CFCF4E700237F
827:1033A00010B500F1280252F8041F19B1C16F146C56
828:1033B00019444C600833202BF5D110BD70474FF0F5
829:1033C000FF307047000001464154414C20455252A5
830:1033D0004F523A2000486172644661756C740D0A60
831:1033E000004D656D4D616E616765206661756C7439
832:1033F0000D0A004275734661756C740D0A005573B1
833:103400006167654661756C740D0A0053656375727A
834:10341000654661756C740D0A005265736572766558
835:103420006420457863657074696F6E2000506C612C
836:1034300074666F726D2065787465726E616C206958
837:103440006E7465727275707420284952516E293AF3
838:1034500020000000290B00000B1F0000D90D000008
839:103460008D0D0000331F00003F1F0000610B0000A6
840:103470000F1F0000490B0000550B0000150C000049
841:10348000151F0000211F0000271F00001D00000065
842:10349000100004001C0002001100060003020202DA
843:1034A0000338FDD87047506C6174666F726D2045AB
844:1034B0007863657074696F6E3A0D0A00416C6C2018
845:1034C00070696E732068617665206265656E206341
846:1034D0006F6E66696775726564206173206E6F6ECA
847:1034E0002D7365637572650D0A00303132333435E2
848:1034F000363738394142434445461B5B313B333410
849:103500006D5B536563205468726561645D2053652B
850:103510006375726520696D61676520696E6974699C
851:10352000616C697A696E67211B5B306D0D0A00540E
852:10353000462D4D20466C6F6174204142493A204827
853:103540006172640D0A004C617A7920737461636B57
854:10355000696E6720656E61626C65640D0A001B5BB5
855:10356000313B33346D426F6F74696E672054462D62
856:103570004D2076322E302E301B5B306D0D0A0055FB
857:103580006E6B6E6F776E2053504D205356432072F2
858:1035900065717565737465643A2000556E6B6E6F66
859:1035A000776E20535643206E756D6265722072658A
860:1035B000717565737465643A200000000040005026
861:1035C000005000500080005000A0005000B000509B
862:1035D00000E0005000F000500000015000100150C9
863:1035E0000040015000500150007001500080015017
864:1035F00000B0015000C0015000D0015000E0015067
865:1036000000F0015000000250001002500020025053
866:103610000030025000400250006002500080025012
867:1036200000A002500090035000258450008000004C
868:1036300000800000FFFF0F00007C00000080000001
869:0C3640002C1200201412002000020000D8
870:10366000009A204B9A4208D110B502F0A7FA02F056
871:10367000A9F906BC96460C46744702F0E3FA009A94
872:10368000184B9A4208D110B502F0A4FA02F09AF948
873:1036900006BC96460C46744702F0D4FA0CB4029A63
874:1036A000104B9A420CD14FF0004319430CBC10B59B
875:1036B00000F09EF802F086F906BC96460C46744768
876:1036C00002F0C0FA009A074B9A4202D106490868F4
877:1036D000744702F0B7FA009A024B9A4200D174473D
878:1036E00002F0B0FAA5EDF5FE801000200348044B6F
879:1036F000834202D0034B03B118477047A811002042
880:10370000A8110020000000000548064B1B1AD90F25
881:1037100001EBA301491002D0034B03B118477047D6
882:10372000A8110020A81100200000000010B5064CD0
883:10373000237843B9FFF7DAFF044B13B10448AFF322
884:1037400000800123237010BDC0180020000000007D
885:10375000EC5E000008B5044B1BB104490448AFF30C
886:103760000080BDE80840CFE700000000C41800203A
887:10377000EC5E0000A3F5803A704700BF174B002BAA
888:1037800008BF134B9D46FFF7F5FF00218B460F4600
889:103790001348144A121A02F0EEF90E4B002B00D017
890:1037A00098470D4B002B00D09847002000210400C3
891:1037B0000D000D48002802D00C48AFF3008002F045
892:1037C000DBF820002900FEF775FD02F0C1F800BF0C
893:1037D000000008000000000000000000F80B0020BE
894:1037E000A8110020B8280020000000000000000000
895:1037F0002DE9F84304460D4616461F46EFF30583B0
896:10380000C3F308030BB1FFF7A9FBDFF834903B4685
897:10381000204632462946D9F80080FFF700FCD9F847
898:1038200000300446984506D0DB6901461869BDE8BA
899:10383000F843FFF7A1BBFFF793FB2046BDE8F883F1
900:10384000B019002001680E4A0346914215D1C169A2
901:10385000A2F11022A2F1EF1291420ED18268012A48
902:103860000BD8C26812B101698A4206D0586928B1E2
903:103870009B691B1A5842584170470120704700BF8E
904:1038800055AA00FF0D4B70B59E68A6B13046FFF7F4
905:10389000D9FF044678B9F3686BB935690DB920468C
906:1038A00070BD2846FFF7CEFF28B9EB68B34202D1BE
907:1038B0002E462D69F2E70124F1E700BF4C1A0020E3
908:1038C0002DE9F041394E3468F368D4B1B468C4B11D
909:1038D000002861D000295FD001FB00F5B5FBF0F0B6
910:1038E000884259D1291D57D8AA070DD025F00302C7
911:1038F00004321C4603E0616891424FD2A469002C57
912:10390000F9D12046BDE8F0812A46F2E7891A232939
913:1039100004F12007D4E9050C1AD80123A360A0B153
914:10392000C0F818C0A36903B158610023C4E9053386
915:103930003369DB0702D5FFF7A5FFA0BB2A460021AC
916:1039400038463C4602F017F9DBE7C6F80CC0E9E759
917:1039500002F1200804EB08032039C3E9011E2169A4
918:10396000DFF84CE0DC60196144F808E0AEF1102E9D
919:10397000AEF1EF1EC3F81CE001B1CB60C3E9050C4A
920:1039800040B18361996901B14B6101212361C4E9AF
921:103990000121CAE7F360F5E70024B2E7D4F808E0B4
922:1039A000BEF1000FB2D0012001F0D2FF4C1A00206E
923:1039B00055AA00FFF8B5054600283AD0364E3368C0
924:1039C000002B36D0B268002A33D0834203D8726805
925:1039D0001344984202D3012001F0BAFFA0F1200461
926:1039E0002046FFF72FFF0028F5D155F8183C012B92
927:1039F000F1D145F8180C55E90570DFB1BB68CBB9BA
928:103A000055F81C2C7B68203213447B60386100B170
929:103A1000C76020220021204602F0ADF8386908B1C5
930:103A200083682BB333699B0703D5FFF72BFF00286F
931:103A3000D1D1F8BD40B3836833BB42686368134497
932:103A4000203363600369D4E90521236192B9B9B9D0
933:103A5000426981696261A161A2B19461A26902B106
934:103A6000546103B1DC602022002102F084F8D9E720
935:103A70003C46E2E79161A1690029E9D04A61E7E7A4
936:103A8000F160F8E7F460E9E7F36845F8083C03B152
937:103A90005C61F460C6E700BF4C1A002038B50D46E3
938:103AA000142200210446124802F065F81149124818
939:103AB00000F02CF8232D1AD914F003031FBF043D86
940:103AC000ED18C3F10403E4182A460021204602F051
941:103AD00052F8074B094AC3E900459C602260A2F1F5
942:103AE0001022203DA2F1EF126560E261DC6038BD7A
943:103AF0004C1A0020B5390000C138000055AA00FF5B
944:103B0000014B1B68184700BFC8100020024B18600B
945:103B1000024B002019607047CC100020C810002014
946:103B200010B50A46044619B1024B00211B6898479C
947:103B300010BD00BFD0100020054B0A46197819B1FE
948:103B40000146181D02F0B8B86FF08800704700BF3A
949:103B5000601A002010B5074C00F032F8204602F041
950:103B6000BCF8201F0821FFF7DBFFBDE8104002F082
951:103B7000A0B800BF641A002070B50C4D2B787BB93B
952:103B800002F095F8044670B90126281D6E7002F007
953:103B900091F8044638B900F00BF8044618B92E70B5
954:103BA0000024204670BDFFF7D5FFFAE7601A002019
955:103BB0000122024B002083F880257047681A0020FC
956:103BC000F8B5074C2025264601272046276202F03B
957:103BD0005DF8013D04F12C04F7D186F88055F8BD5D
958:103BE000681A002010B50C4C236813B10B4B1B68EE
959:103BF0002BB900F089FC30B90122084B1A6001236F
960:103C00002360002010BD0138062801D9044810BDEA
961:103C1000044B53F8200010BD042000200020002099
962:103C2000FE8FFFFF545D0000144B2DE9F043002888
963:103C300014BF04461C46124F236883B0BB4219D000
964:103C400016460D4620464FF4147104F1040900F0A5
965:103C500047F804F58E78484600F0CEF8404600F06C
966:103C600019FA2B464A4640460649009600F034FBB6
967:103C700008B92760002003B0BDE8F08308200020C9
968:103C8000A5BCC95A7D3E000070B50D4C1D460028EC
969:103C900014BF064626460B4B306882B098420DD1C1
970:103CA00006F58E70002633460096144600F03EFB63
971:103CB000002818BF34462C6002B070BD0248FBE7F4
972:103CC00008200020A5BCC95AE88FFFFF38B131B1E8
973:103CD000002201440346013081421A70FAD1704734
974:103CE00038B131B1002201440346013088421A70D4
975:103CF000FAD170472DE9F043202B1D460646884631
976:103D000091468BB026D8DBB202AF8DF80480B04666
977:103D100058F8041B8DF8053021B9404601F038F9F8
978:103D2000044640B9012302224046336001A901F054
979:103D300043F9044638B138462021FFF7D1FF204629
980:103D40000BB0BDE8F0832A464946404601F034F9FD
981:103D50000446F0E702AF1946104600233A4601F048
982:103D6000B1FA04460028E6D12023B9461D46CCE727
983:103D70002DE9F041D0F8F830A6B0002BD8BF02AE44
984:103D800031DD05460027D0F80C4102AEA4F1010850
985:103D90009022D5F8FC403146D0F8000101AB0197E4
986:103DA000B8FA88F8A0474FEA5818044620B9019B92
987:103DB00053B9B8F1000F16D030469021FFF790FFAD
988:103DC000204626B0BDE8F081014632462846FFF77E
989:103DD00091FF58B9D5F80431019A1344C5F804315C
990:103DE000B8F1000FE8D16FF03C04E5E70446204647
991:103DF00026B0BDE8F08100BF70B50025044614224E
992:103E000004F588762946C0F8F850FC3001F0B3FE7E
993:103E100008222946304601F0AEFE144B30461B689E
994:103E20009847204640F8045B01F098F8104B304664
995:103E30001B689847C8B9D4F8F830AB420FDC03EBE5
996:103E4000830204EB82022021C2F800010120C2E9B2
997:103E5000421008490133C2F8FC10C4F8F830064B90
998:103E60003046BDE870401B68184770BDF010002058
999:103E7000EC100020614E0000E81000202DE9F04712
1000:103E8000202A88B07AD83F4B00F5887904461B6811
1001:103E900048461746884698470546F8B940F2011645
1002:103EA000D4F8F830002B65D02046FFF761FF0546B7
1003:103EB00038B9D4F8F830002B14DC013EF2D16FF0A1
1004:103EC0003B056E4620213046FFF70AFF2E4B484641
1005:103ED0001B689847002818BF6FF01D05284608B0DA
1006:103EE000BDE8F087D4E94132934203D3D4F80C21E2
1007:103EF000012A02D0013ED7D1E1E71F2BFAD96E4645
1008:103F000001462022304604F1040A01F034FE314615
1009:103F1000504601F07BF805460028D3D1504601F009
1010:103F200031F8504601F01AF82946504601F030F8B1
1011:103F300005460028C6D150462022314601F03CF803
1012:103F400005460028BED1034632462021304601F006
1013:103F5000B9F905460028B5D1D4F8F8303A46002B17
1014:103F6000C8BF002340463146C8BFC4F8043101F041
1015:103F7000DDFDA7E76FF03F056E46A3E76FF03B0559
1016:103F8000ACE700BFEC100020E810002070B590B046
1017:103F900000287AD03E4C0D46402236210646204667
1018:103FA00001F0E9FD40225C21A01801F0E4FD2B1D89
1019:103FB000A34203D904F144039D4252D32B682268E3
1020:103FC000534023602B68226C534023646B68626803
1021:103FD000534063606B68626C53406364AB68A26873
1022:103FE0005340A360AB68A26C5340A364EB68E268E3
1023:103FF0005340E360EB68E26C5340E3642B69226951
1024:1040000053402361226D2B695340236562696B69BC
1025:10401000534063616B69626D53406365AB69A2692C
1026:104020005340A361AB69A26D5340A365EB69E2699C
1027:104030005340E361EB69E26D5340E3650021304694
1028:1040400000F0A6FF044628B940223046104900F08F
1029:10405000B3FF044640216846FFF742FE204610B0F9
1030:1040600070BD631E04F13F01013D1F3415F8010FBF
1031:1040700013F8012F42401A7011F8012F2878A3423B
1032:1040800082EA00020A70F1D1D8E76FF07304E5E725
1033:104090005822002010B54FF49A720021044601F016
1034:1040A0006AFD42F21072044BC4F8202104F59670A8
1035:1040B0001B68BDE810401847F01000202DE9F04FB4
1036:1040C00004468846914695B0002900F0A780002A52
1037:1040D0000CBF0126022600238DF80C30002C00F0C6
1038:1040E0009F80DFF844A104AF0AF1400B0021204675
1039:1040F00000F04EFF034648B1384620210193FFF7F8
1040:10410000EFFD019B184615B0BDE8F08F40225146E7
1041:10411000204600F051FF03460028EDD104F1F405DC
1042:1041200020222946204600F047FF03460028E3D11D
1043:104130000122204603A900F03FFF03460028DBD1FF
1044:10414000022E62D020460CA900F060FF0346002832
1045:10415000D2D10146204600F01BFF03460028CBD1F8
1046:1041600040225946204600F027FF03460028C3D1CD
1047:10417000202220460CA900F01FFF03460028BBD1D7
1048:104180003946204600F042FF03460028B4D13946A4
1049:104190002046FFF7FBFE03460028ADD1202229462A
1050:1041A000204600F009FF03460028A5D120460CA9AF
1051:1041B00000F02CFF034600289ED10146204600F067
1052:1041C000E7FE0346002897D140225946204600F0DA
1053:1041D000F3FE034600288FD1202220460CA900F0D0
1054:1041E000EBFE0346002887D12946204600F00EFF4B
1055:1041F0000346002880D19DF80C200132D2B2B24291
1056:104200008DF80C20FFF472AF76E74A46414620460F
1057:1042100000F0D2FE0346002894D06DE701265AE74D
1058:104220006FF0730304AF67E7582200202DE9F041D7
1059:104230000446884615461F46D0F81801E0B013B171
1060:1042400000EB40004008B5F5807F3ED82844B0F52B
1061:10425000C07F3AD84FF4C0720021684601F08BFC51
1062:104260006946D4F82431D4F81821D4F828019847A5
1063:1042700070BBD4F8186157B1D4E9493072080DEB1E
1064:104280000601984720BBD4F8183106EB5306B8F165
1065:10429000000F00D08DB9324669462046FFF70EFF69
1066:1042A000054610B90123C4F8143131466846FFF7BA
1067:1042B00017FD284660B0BDE8F0810DEB06004146D1
1068:1042C0002A462E4401F032FCE5E76FF00405F0E7E2
1069:1042D0006FF00805EDE700BF2DE9F047044604F153
1070:1042E000F4050F4691461E46DDF8208000F036FEAC
1071:1042F00029462046FFF74AFE08B1BDE8F087284668
1072:104300002022012101F037FCD4F81831C4F82471BF
1073:10431000C4F8289113B92023C4F818314246314615
1074:104320002046BDE8F0470123FFF780BFB2F5806F5C
1075:1043300000F295802DE9F04F89B09A46129BB3F5B3
1076:10434000807F00F29080D0F82431164604460F4654
1077:104350004BB3D0F81C31012B05D0D0F81421D0F884
1078:1043600020319A421FDD514600232046129AFFF762
1079:104370005DFF014698B900231293002E5ED0DFF84E
1080:10438000EC9009F1400B0021204600F001FE202EA8
1081:104390003546014628BF202504F1F40890B10846AF
1082:1043A00009B0BDE8F08FBAF1000FE6D0129B002BE8
1083:1043B000E1D051461A462046FFF780FE014600280C
1084:1043C000DBD0ECE749464022204600F0F5FD0146EF
1085:1043D0000028E4D141462022204600F0EDFD0146B0
1086:1043E0000028DCD16946204600F010FE0146002876
1087:1043F000D5D1204600F0CCFD01460028CFD159464A
1088:104400004022204600F0D8FD01460028C7D1694669
1089:104410002022204600F0D0FD01460028BFD14146B1
1090:10442000204600F0F3FD01460028B8D138462A4660
1091:10443000414601F07BFB761B2F44A4D15146204618
1092:10444000129AFFF73BFE01460028A8D10846D4F88F
1093:1044500014310133C4F8143109B0BDE8F08F6FF0A6
1094:104460000201084670476FF0040198E758220020C7
1095:10447000002130B58DB0282202A8019101F07BFB0C
1096:1044800002A800F047FF044610B120460DB030BD31
1097:10449000174D4FF0FF31286800F042F9044620B173
1098:1044A000144800F0D3F9012C18D0002000F068F96E
1099:1044B000D0B9114A02A901A800F0C4FC04460120A9
1100:1044C00000F05EF960B9286800F032F90028DCD00D
1101:1044D0000A4800F0BBF920460DB030BD0524F2E7D4
1102:1044E000074800F0B3F9EEE7064800F0AFF9E0E75F
1103:1044F000D4100020705D0000D8220020C85D0000AC
1104:10450000A85D0000885D000030B583B000F05CF865
1105:1045100028B100F0ABF80324204603B030BD00F012
1106:1045200077F8D8B900F02CF9E0B9224CD4F8283942
1107:104530001B0EF02B0AD1D4F8242A1F4B9A4231D0FB
1108:1045400000F044F8072400F091F8E5E7062400F0B5
1109:104550003DF800F08BF8204603B030BD042420461F
1110:1045600003B030BD00F032F800F080F8FFF780FFB4
1111:10457000044698B9114D2B68002BCDD10246014657
1112:10458000FFF752FB50B968220D4901ABFFF77CFBE6
1113:1045900020B920460B4B2B6003B030BD05242046CC
1114:1045A00003B030BD012000F0EBF80028DAD1C4F8E8
1115:1045B0000C0ADBE7001084500000E020F824002003
1116:1045C000FC2400205AEA5A5A002070470020704705
1117:1045D000430504D54FF0FF32034BC3F80821024BCB
1118:1045E000C3F8080A704700BF00108450014BC3F89D
1119:1045F000040A70470010845008B100F06BB84FF403
1120:104600007500704708B100F04FB84FF4750070475F
1121:1046100010B5114800F070F800B110BD0F4800F05F
1122:104620006BF80028F9D10E4C204600F065F8002800
1123:10463000F3D10C4B0C481C6000F05EF801460028DA
1124:10464000EBD100F02DF8044608B1204610BD00F073
1125:1046500079F82046FAE700BFE4100020E0100020BF
1126:10466000DC100020D4100020D810002008B5084825
1127:1046700000F04CF8074800F049F8074800F046F809
1128:10468000064800F043F8BDE8084000F00BB800BF52
1129:10469000E4100020E0100020DC100020D8100020E2
1130:1046A00000207047704700BF024610B4084CD4F891
1131:1046B000003A1342FBD021B1D4F804310B60C4F8A6
1132:1046C0000831034B0020C3F8082A5DF8044B7047FB
1133:1046D00000108450044AD2F8003A1842FBD0C2F8C5
1134:1046E000080A0020704700BF0010845001F0E8B9AC
1135:1046F0000A46002101F03FBA08B5034B02681B6867
1136:1047000010689847002008BD1011002008B5034B21
1137:1047100002685B6810689847002008BD10110020EF
1138:10472000024B02689B681068184700BF10110020F8
1139:1047300008B5034B0268DB6810689847002008BD85
1140:104740001011002070B5094C094D2069AB689847DD
1141:1047500018B1084B08485B6898470021074AEB6886
1142:1047600011602069BDE87040184700BFFC100020B0
1143:1047700010110020F4100020E05D000064250020EE
1144:10478000F8B51A4D1A4E0446B26828699047E8B940
1145:10479000184F3B684CB1A3B1012B19D0013B3B60D2
1146:1047A0002869F36898470020F8BD43B90121124AEF
1147:1047B000C2F800151149D1F81029002AFBD10133A4
1148:1047C0003B60F368286998470020F8BD0C48F8BDA5
1149:1047D0000A4AD2F81039002BFBD1074A6FF07E400D
1150:1047E000C2F80035FFF702FF3B68D7E7FC10002056
1151:1047F0001011002064250020000084500010845017
1152:10480000E98FFFFF014B1B68184700BF1011002004
1153:10481000014B9B68184700BF10110020014BDB685B
1154:10482000184700BF10110020BFF34F8F0549064BFA
1155:10483000CA6802F4E0621343CB60BFF34F8F00BF3E
1156:10484000FDE700BF00ED00E00400FA0530B44FF0D2
1157:10485000FE320025074B084C08494968C3F800247C
1158:10486000C3F80424C3F80824C3F80C24C4F8005582
1159:1048700030BC08470010845000008450F410002021
1160:1048800010B5044650B1636813F0685F05D0064A5E
1161:10489000934202D000236260236010BD034B0448A2
1162:1048A0005B689847EFE700BF2C5F5CA9F41000201D
1163:1048B000005E0000C8B143680D4A934213D013F064
1164:1048C000685F0ED0012350E8002F194640E8001C15
1165:1048D0009CF0000FF7D1012AF5D0BFF35F8F0020C5
1166:1048E000704704487047044870476FF4E0407047D1
1167:1048F0002C5F5CA9E98FFFFFEA8FFFFF034680B1C1
1168:10490000426809498A420AD012F0685F05D0BFF3B5
1169:104910005F8F002210461A607047044870470448B1
1170:1049200070476FF4E04070472C5F5CA9E98FFFFF90
1171:10493000EA8FFFFF10B5044620B10023034A23602D
1172:10494000626010BD0248FFF781FFF6E73A00003AC7
1173:10495000285E00002DE9F047002878D00C46002999
1174:1049600075D01D46002B72D007461AB101220023D4
1175:104970002A6003602B68002B64D02946204600F093
1176:10498000B7FD804600285FD12146286800F096FDDB
1177:104990008046002858D12B68082B6CD0042B6DD092
1178:1049A000A3F10209B9FA89F94FEA59190121354EE3
1179:1049B000C6F8C411C6F84011C6F8C411636AC6F837
1180:1049C0003031D6F830219342F6D14FF0000A4FF043
1181:1049D000FF30C6F82CA1FFF7FBFD6FF01B0350461C
1182:1049E000C6F80031FFF702FEC6F80C91D6F8040AAB
1183:1049F00040F48060FFF7FAFD0A23C6F83831089BBF
1184:104A0000012B29D02369204AA2FB03231B09626AD8
1185:104A1000404602FB03F303EB43031A4ADB039B0903
1186:104A2000C2F8D8310123C2F82C313B682A6823F040
1187:104A30007F4343EA02633B602A6843EA02233B6008
1188:104A4000BDE8F087DFF844804046BDE8F087DFF836
1189:104A500040804046BDE8F0874FF47F03D3F80C2C2C
1190:104A6000013206D0D3F80C3C074AA2FB03231B09F2
1191:104A7000CDE71623CBE74FF0030997E74FF0020984
1192:104A800094E700BF00108450ABAAAAAA310CF10031
1193:104A9000350CF10058B34B1EB3F5047F27D230B567
1194:104AA0004FF0000ECD00744671464B0901F01F0C0B
1195:104AB00050F82330BCF11F0F23FA0CF306D003F09B
1196:104AC000010319B901211C468E46EEE79C4201F113
1197:104AD000010106D01C464FF0010EA942E5D100208D
1198:104AE00030BD0EF1010E9645F7D1024830BD0148A8
1199:104AF000704700BF360CF100C0B32DE9F0434C1EE7
1200:104B0000B4F5047F1DD2E3B1DAB100252E46A846E4
1201:104B10002C46CF0003F1FF394FEA541C04F01F0E5E
1202:104B200050F82C10BEF11F0F21FA0EFC0CD00CF027
1203:104B3000010C4CB90126E04634463546ECE7964276
1204:104B400016D90C48BDE8F083AB420BD0C44508BF72
1205:104B50000136A945F3D001350134BC42DCD1002037
1206:104B6000BDE8F0830125E0462E46F5E70148704791
1207:104B70001D46F1E7370CF1002DE9F04F91B0834667
1208:104B8000DDE91B460D46002E6ED10F691C60002327
1209:104B90001A990B60002A00F02F819D4B6A6AD3F8A6
1210:104BA0003811D3F830319A4269D10A2967D19BF87C
1211:104BB0000330089304F10803079304230593954BEE
1212:104BC000934CA3FB07239B0803EB4303A7EB43038F
1213:104BD000039306971A9B069E1E60002E00F0EA8043
1214:104BE00000F096FC00230993BBF1000F00F0D58084
1215:104BF00098464FF0010ADDF81C90002D00F0CD80A2
1216:104C0000089B002B3DD0284608A900F071FC002825
1217:104C100039D0814B984220D0089B082B00F0E480CB
1218:104C200000225B000893294608AB58460092FFF724
1219:104C300091FE7A4B984200F0D38070B9DBF80020E7
1220:104C4000130A03F47F03134323F07F43CBF80030B0
1221:104C5000059B013B0593BDD10020039000F058FC5B
1222:104C6000039811B0BDE8F08F4FF47F01D1F80C0C20
1223:104C700001300CBF4FF40477D1F80C7C86E768480C
1224:104C8000EBE76648C5E72946089800F017FC0028BE
1225:104C9000BFD1089B082B00F0A980042B00F0A9804D
1226:104CA000A3F10203B3FA83F35B090493C4F8C4A12C
1227:104CB000C4F840A1C4F8C4A16B6AC4F83031D4F878
1228:104CC00030219342F6D100234FF0FF30C4F82C314D
1229:104CD000FFF77EFC002318466FF01B03C4F8003179
1230:104CE000FFF784FC049B4B4FC4F80C31D4F8040A42
1231:104CF00040F48060FFF77AFC0A23C4F838312B694E
1232:104D000009A8A7FB03236A6A1B0902FB03F303EB51
1233:104D10004303DB039B09C4F8D831C4F82CA1DBF8AA
1234:104D20000030089923F07F420B0243EA01631343EA
1235:104D3000CBF8003000F0B2FB099B03F01A030343E9
1236:104D40007FF46AAFA7FB0637D4F81431B8EB970F9E
1237:104D50000A93D4F818310B93D4F81C310C93D4F87F
1238:104D600020310D93D4F824310E93D4F828310F93C9
1239:104D700001D1039B9BB9484618220AA9183EFFF7A8
1240:104D8000B5FC09F1180908F101089EB100F0C0FB5B
1241:104D900000230993002D7FF433AF224839E74846BA
1242:104DA0001A46F61A0AA9994408F10108FFF79EFC71
1243:104DB000002EEBD1069F079E6A6939463046FFF701
1244:104DC00069FEAA6940B94FF4806339463046FFF75F
1245:104DD00093FE00283FF440AF00231A9A136018E7AF
1246:104DE0002B6A002B3FF439AF0F4836E703230493B7
1247:104DF0005CE70223049359E70122294658460096AE
1248:104E000008ABFFF7A7FD00283FF4D4AE25E700BFAD
1249:104E100000108450ABAAAAAA020CF100310CF100D8
1250:104E2000300CF100350CF100320CF10030B4DDE94A
1251:104E3000023402940024049DCDE9035430BCFFF7F2
1252:104E40009BBE00BF30B51546012487B005AB00936B
1253:104E50000022CDE9015404ABFFF78EFE07B030BD50
1254:104E6000F0B587B0002966D01E46002B63D01446EB
1255:104E7000002A60D0314F0D4638684FF0FF31FFF700
1256:104E80004FFC00284DD10020FFF77AFC002844D1C8
1257:104E90002B4800F03FFAD8B101204FF0FF35FFF763
1258:104EA0006FFC002835D14FF408712648FEF70EFF3D
1259:104EB00004212548FEF70AFF21482821FEF706FFB6
1260:104EC0003868FFF735FC00282FD1284607B0F0BD21
1261:104ED0001C4A0346029205AA019204AA039000927A
1262:104EE000174902461848FFF7A1FF03460028D3D10F
1263:104EF00028461D46059B22469C4228BF1A46049917
1264:104F000032600831FFF7F2FB0120FFF739FC00287F
1265:104F1000C9D00E48FFF79AFCC5E70D48FFF796FC8D
1266:104F2000B6E70C48FFF792FCADE70B48FFF78EFCA5
1267:104F3000284607B0F0BD4FF0FF35C6E7D41000207B
1268:104F40007C250020A425002078250020A85D0000F5
1269:104F5000885D0000705D00004C5E000010B50446E6
1270:104F600028B12046BDE81040F421FFF7C1BB04483A
1271:104F7000FFF76CFC2046BDE81040F421FFF7B8BBFA
1272:104F8000645E000010B1F421FEF7A0BE704700BFC0
1273:104F900008B521B1012908D06FF0360008BD012104
1274:104FA00000F058F80028F7D108BD022100F052F8AF
1275:104FB0000028F9D0F0E700BF30B505468818B0F5F5
1276:104FC000801F0B461446A1B001D8802A0CD9B3F536
1277:104FD000801F17D922461946284600F07DF804465E
1278:104FE00084B9204621B030BD6846FFF77FFB2246DA
1279:104FF0006946284600F070F8802104466846FFF7AD
1280:1050000077FBEDE76FF03604EBE700BF70B5E8B172
1281:105010000E46D9B1044600F031F80546B0B9236810
1282:10502000012B0BD0022B01D0284670BD1C2230462C
1283:1050300004F10801FFF75AFB284670BD20223046D4
1284:1050400004F10801FFF752FB284670BD6FF03605EA
1285:10505000EAE700BF78B138B50D46F0210446FFF706
1286:1050600047FB402320462560E36500F091FA0038B5
1287:1050700018BF012038BD0120704700BFF0B5056E94
1288:10508000A5B0044604AEE5B90023012701933046DC
1289:105090006760294602AA009300F046FA10B1012089
1290:1050A00025B0F0BD2A46204602A900F099FA002852
1291:1050B000F5D1204600F0AAFB0028F0D1206625B0EB
1292:1050C000F0BD802D2A46304628BF802204F16401BD
1293:1050D000FFF70CFB256ED7E7002800F0AE802DE926
1294:1050E000F04F1446A5B0002A3DD00F46002949D004
1295:1050F000B2F5803F0546006E20D34FF6FF7805F1EC
1296:10510000640AEB6D1A1AB2FBF3F103FB1122002AB9
1297:1051100065D18342B9464FF6FF7672D0B6FBF3FBFA
1298:1051200003FB0BFBBBF1000F30D1002E45D1A4F5E2
1299:105130007F44FF3CB4F5803F4744E2D2EA6D161A43
1300:10514000B6FBF2F302FB1366A64228BF2646002EEA
1301:1051500075D1824200F08D80B4FBF2F602FB06F6B8
1302:105160002EB9002C79D1002025B0BDE8F08F0023A6
1303:1051700031463846CDE9003302AA00F0D5F90028BF
1304:1051800000F09580012025B0BDE8F08F002359463E
1305:105190004846CDE9003302AA00F0C6F90028F1D153
1306:1051A0005A46284602A900F01BFA0028EAD1A6EBCD
1307:1051B0000B06286ED944002EB9D019304946324624
1308:1051C00005EB8000FFF792FAA4F57F44286EFF3CC0
1309:1051D0003044B4F5803F4744286692D2AEE742455A
1310:1051E00028BF4246164639465044FFF77FFA286EDC
1311:1051F000EB6D3044834207EB06092866A8EB0606F0
1312:105200008CD1802B28BF802351461A4604A8FFF773
1313:105210006DFA0023E96D02AACDE9003304A800F07D
1314:1052200083F90028AED12846EA6D02A900F0D8F92A
1315:105230000028A7D1EB6D286670E70120704705F1C3
1316:105240006403394632461844FFF750FA286EEA6D77
1317:105250003044A41B374428667BE72B6E2246193363
1318:1052600005EB83003946FFF741FA2B6E23442B668A
1319:1052700079E7802A28BF802205F1640104A8FFF79E
1320:1052800035FA0023E96D04A8CDE9003302AA00F045
1321:105290004BF900287FF476AF2846EA6D02A900F0AA
1322:1052A0009FF900287FF46EAFEA6D286654E7324616
1323:1052B000284602A900F094F900287FF463AF374430
1324:1052C000A41B4EE7F8B51C460546114816460F4686
1325:1052D000FFF744FE21460E48FFF75AFE044620B170
1326:1052E0000B48FFF74FFE2046F8BD3A4629460848CE
1327:1052F000FFF762FE04460028F2D131460448FFF76A
1328:1053000085FE04460248FFF73DFE2046F8BD00BF7B
1329:10531000C42700201C2370B582B001A90546019363
1330:1053200000F032F8044638B9019B1C2B07D0144C0E
1331:105330001C212846FFF7DCF9204602B070BDD5E9F4
1332:105340000112131E18BF0123003918BF01210126C5
1333:1053500028689B00EA6843EA4103002818BF43F02D
1334:105360000103EE612AB9C5E90834002BE4D1054CEC
1335:10537000DEE7204643F00803C5E9083402B070BDFB
1336:10538000370CF0000E0CF0000346002866D0002910
1337:1053900064D00A681C2A61D14FF47F023B49D2F8DD
1338:1053A000100C88425CD0D2F8101C013158D0D2F8D1
1339:1053B000101C4FF47F021960D2F8140C3449884253
1340:1053C00060D0D2F8141C01315CD0D2F8141C4FF418
1341:1053D0007F025960D2F8181C11F5947F4FD0D2F893
1342:1053E000181C01314BD0D2F8181C4FF47F02996081
1343:1053F000D2F81C0C274988423ED0D2F81C1C01313F
1344:105400003AD0D2F81C1C4FF47F02D960D2F8001CAD
1345:1054100070312FD0D2F8001C01312BD0D2F8001CF3
1346:105420004FF47F021961D2F8041CAF3120D0D2F8BA
1347:10543000041C01311CD0D2F8041C4FF47F025961C6
1348:10544000D2F8080C144988420DD0D2F8081C01315A
1349:1054500009D0D2F8082C00209A61704701207047CB
1350:1054600040F6FC01A5E740F2373200209A61704710
1351:105470005121E2E79021D3E742F60411C3E740F659
1352:10548000D861B2E742F2D001A1E700BFFCF8FFFF0C
1353:10549000D020FFFF0429FFFF37F3FFFF014608B5C7
1354:1054A0004FF48060FFF7AEF80022034BC3F8C82129
1355:1054B000C3F82C2108BD00BF001084500138072814
1356:1054C00005D8DFE800F0100E040A040404060748BB
1357:1054D0007047CB6800204B6270478B6800204B629E
1358:1054E00070474B68F6E70B68F4E700BF310CF1003A
1359:1054F0000B6802E0082B0B6006D8026A13424FEAE1
1360:105500004303F7D00020704700487047310CF1008A
1361:105510000022044B4FF48060C3F82C21C3F8C4214F
1362:10552000FFF756B800108450F0B5002483B0B0F1F6
1363:10553000005F8DF8074025D38C468444BCF1804F32
1364:1055400004461FD817461D4601220DF1070300F03F
1365:1055500097F90646B0B99DF80730099A3C603B714F
1366:1055600092B14DB10246089928460DF1070300F0AB
1367:1055700087F938B99DF807303046099A15601371DC
1368:1055800003B0F0BD4FF47506304603B0F0BD00BF68
1369:10559000D8B108B50368012B04D0022B0FD043B15A
1370:1055A0000B4808BD20220B490830FFF79FF8002068
1371:1055B00008BD142208490830FFF798F8F7E72022C1
1372:1055C00006490830FFF792F8F1E74FF4730070478F
1373:1055D0000100F300745E0000B45E0000945E000001
1374:1055E0002DE9F843002900F0F9800446002800F076
1375:1055F000F98003680F469046002B00F0C380013B02
1376:10560000012B00F2D7804FF0FF3178484FF00209AC
1377:10561000FFF786F8002840F0BF800020FFF7B0F8C1
1378:105620000646002840F0C280714AD2F81C39002B8F
1379:10563000FBD16F4DD5F8203C002BFBD14FF0FF3054
1380:10564000FEF7C6FFD5F8040A20F04000FEF7CEFFB3
1381:1056500001230722C5F81838C5F80029C5F8C43752
1382:10566000A36CC5F8CC37E36CC5F8D037C5F8C09744
1383:1056700023685BB1013B012B18D8636AC5F85C361F
1384:10568000236AC5F85836E369C5F85436A269584B01
1385:10569000C3F850266269C3F84C262269C3F848262D
1386:1056A000E268C3F84426A268C3F84026504AD2F8FC
1387:1056B0001039002BFBD1B8F1000F5FD06368402098
1388:1056C000012B08BFC2F884363A68494BC3F8282C2E
1389:1056D000C3F82C8CFEF790FF0646454AD2F81039E5
1390:1056E000002BFBD1424AD2F8203C002BFBD123688F
1391:1056F0005BB1013B012B18D8D2F85C366362D2F85B
1392:1057000058362362D2F85436E361394BD3F8502629
1393:10571000A261D3F84C266261D3F848262261D3F8FF
1394:105720004426E260D3F84036A36000230121304ACA
1395:10573000D2F8CC07A064D2F8D007E064C2F8C4174E
1396:10574000C2F88436C2F8C837D2F81039002BFBD122
1397:10575000C2F81838002E3BD1254BD3F8040A40F08C
1398:105760004000FEF743FF0120FFF70AF860BB1F4827
1399:10577000FEF7DEFF10BB3046BDE8F8830423C2F815
1400:10578000C837AAE74FF0FF3118484FF00109FEF77C
1401:10579000C7FF00283FF441AF1648FFF757F8002035
1402:1057A000FEF7EEFF064600283FF43EAF1248FFF733
1403:1057B0004DF839E7114E3046BDE8F8831048FFF741
1404:1057C00045F83046BDE8F8830E48FFF73FF8CEE7CE
1405:1057D000102104F10800FEF78BFFBDE70A4E3046AA
1406:1057E000BDE8F8834FF47306C5E700BFE41000205E
1407:1057F00000108450705D0000885D00000100F3001F
1408:10580000C85D0000A85D00000300F300A0B30346DC
1409:1058100070B4D0E90240D3E9041226BA05BA0CBA32
1410:1058200010BAC3E90440D3E90612986A09BAC3E979
1411:10583000026512BA996100BAD3E9084125BA0CBAD7
1412:10584000C3E90725D3E90B12C3E9094009BAD86BAC
1413:1058500012BAD962D3E90D4125BAC3E90C250CBAB5
1414:1058600000BAD3E9101209BA12BAC3E90E4019649A
1415:1058700000205A6470BC70474FF47300704700BF3B
1416:1058800000201870704700BF431810B501D21F2ABE
1417:1058900001D9002010BD013902F014030144102B7E
1418:1058A00080EA01043CD009DC8BB1042BF1D11F2C20
1419:1058B00040E840F315D941E840F10EE0142BE8D15F
1420:1058C0001F2C40E8C0F30CD941E8C0F105E01F2CC3
1421:1058D00040E800F305D941E800F11C460B468C4234
1422:1058E000D7D122F01402013A0A2AD2D801A151F8E4
1423:1058F00022F000BF435900003D5900002F5900001D
1424:1059000093580000935800009358000093580000EB
1425:105910004959000043590000375900002F59000031
1426:105920001F2C40E880F3DCD941E880F1D5E713F47F
1427:10593000001FAFD1ADE713F4801FFAE75B02A9D5D2
1428:10594000A7E713F4002FF4E713F4802FF1E700BF6B
1429:1059500008B5074B044613B10021AFF30080054B97
1430:105960001868836A03B19847204600F029F800BF01
1431:1059700000000000C85E000070B50D4D00260D4C03
1432:10598000641BA410A64209D10B4D00260B4C00F05D
1433:10599000D5F9641BA410A64205D170BD55F8043B8F
1434:1059A00001369847EEE755F8043B01369847F2E791
1435:1059B000A0110020A0110020A0110020A41100209F
1436:1059C000FEE700BFB7EE000AF7EE000AB7EE001AD6
1437:1059D000F7EE001AB7EE002AF7EE002AB7EE003A0B
1438:1059E000F7EE003AB7EE004AF7EE004AB7EE005A7B
1439:1059F000F7EE005AB7EE006AF7EE006AB7EE007AEB
1440:105A0000F7EE007AF1EE10CA40F29F01CFF20001EA
1441:105A10003CEA010CE1EE10CA002383F300887047D2
1442:105A2000FDF79CBAEFF30880EFF309812DE9F00F41
1443:105A30006B467246FAF7ACFF08B0FFF7F1FFFEE7DE
1444:105A4000FDF78CBAEFF30880EFF309812DE9F00F31
1445:105A50006B467246FAF79CFF08B0FFF7F1FFFEE7CE
1446:105A6000FDF77CBAEFF30880EFF309812DE9F00F21
1447:105A70006B467246FAF78CFF08B0FFF7F1FFFEE7BE
1448:105A8000FDF76CBAEFF30880EFF309812DE9F00F11
1449:105A90006B467246FAF77CFF08B0FFF7F1FFFEE7AE
1450:105AA000FDF75CBAEFF30880EFF309812DE9F00F01
1451:105AB0006B467246FAF76CFF08B0FFF7F1FFFEE79E
1452:105AC000814270B40546144602D370BC00F02EB873
1453:105AD000821821443CB141EA020313F003030FD1C1
1454:105AE000E018032812D86FF00300A30843430020F6
1455:105AF00019441A442344984210D1284670BC704778
1456:105B000011F8013D013C02F8013DE3E7581850F857
1457:105B1000046C981840F8046C043BE1E70C1A14F884
1458:105B2000016C141A04F8016C0130E4E770B5044606
1459:105B30003AB141EA040313F003030CD1D518032D45
1460:105B40000FD822F003031C441944002302F003027F
1461:105B500093420CD170BD11F8013B013A04F8013BAE
1462:105B6000E6E7CD1A2E68E51A2E60043BE6E75D5C99
1463:105B7000E5540133ECE7F0B5044662B922F00303C3
1464:105B8000234402F003021A44934214D1F0BD04F8F6
1465:105B9000011B013AF1E7A307F9D115460B0443EACB
1466:105BA00001630B4343EA01231619032DE6D9771B42
1467:105BB0003B60043DF9E703F8011BE5E708B5EFF3A7
1468:105BC0000583C3F308030BB1FDF7C8F9BDE808402E
1469:105BD000FDF74CBA10B50446EFF30583C3F3080391
1470:105BE0000BB1FDF7BBF92046BDE81040FDF741BA07
1471:105BF0002DE9F04104460D4616461F46EFF3058396
1472:105C0000C3F308030BB1FDF7A9F93B463246294619
1473:105C10002046BDE8F041FCF743BC2DE9F0410446C5
1474:105C20000D4616461F46EFF30583C3F308030BB179
1475:105C3000FDF794F93B46324629462046BDE8F0413F
1476:105C4000FCF768BC08B5EFF30583C3F308030BB199
1477:105C5000FDF784F9BDE80840FDF7DBB90020704787
1478:105C6000704710B5044608B1FDF75AFF2046BDE85D
1479:105C70001040FDF745BF10B50446406A10B1A16A57
1480:105C8000FFF7EFFF0020C4E9090010BD38B5044656
1481:105C9000FFF7F1FF236A2C22012B0CBF05466FF0A2
1482:105CA000960500212046FFF766FF284638BD0020F4
1483:105CB000704770470020704713B5002001AB1446B1
1484:105CC000FDF7E2FF30B9019BA34218BF6FF09300CC
1485:105CD00002B010BD6FF09200FAE7002070472DE986
1486:105CE000E04F2746A046A146A246A346A4462DED76
1487:105CF000108B4FF0000545EC185B45EC195A45EC4C
1488:105D00001A5A45EC1B5A45EC1C5A45EC1D5A45ECF9
1489:105D10001E5A45EC1F5AF1EE105A4FF66076C0F647
1490:105D2000FF763540E1EE105A84F30088254626467A
1491:105D3000A447BDEC108BBDE8E08F0000F8B500BFB4
1492:105D4000F8BC08BC9E467047F8B500BFF8BC08BC5C
1493:105D50009E467047FF8FFFFFFF8FFFFFFE8FFFFF05
1494:105D6000FE8FFFFFFD8FFFFFFC8FFFFFFC8FFFFF0C
1495:105D70004661696C20746F2061637175697265207A
1496:105D80006D757465780A00004661696C20746F2037
1497:105D9000696E63726561736520504D20636F756E27
1498:105DA0007465720A000000004661696C20746F20FF
1499:105DB000646563726561736520504D20636F756E15
1500:105DC0007465720A000000004661696C20746F20DF
1501:105DD00072656C65617365206D757465780A000085
1502:105DE000436F756C64206E6F74206C6F636B2070F2
1503:105DF0006F7765722073617665206D7574657800C4
1504:105E00006D757465785F667265652063616C6C653D
1505:105E1000642077697468204E554C4C207061726123
1506:105E20006D6574657200000043616E277420696EB1
1507:105E3000697469616C697A65206D757465782C2068
1508:105E4000776173204E554C4C0D0A00004661696C19
1509:105E500020746F20756E6C6F636B206D7574657840
1510:105E60000A0000000A637478206973204E554C4C78
1511:105E70000A00000067E6096A85AE67BB72F36E3CF4
1512:105E80003AF54FA57F520E518C68059BABD9831F05
1513:105E900019CDE05BD89E05C107D57C3617DD703083
1514:105EA00039590EF7310BC0FF11155868A78FF964E7
1515:105EB000A44FFABE0123456789ABCDEFFEDCBA984B
1516:105EC00076543210F0E1D2C34011002054464D5FA9
1517:105ED00043525950544F0054464D5F504C41544624
1518:105EE0004F524D5F53455256494345000000000054
1519:105EF00000000000000000000000000000000000A2
1520:107C00007FE97FE9FBF72CBD7FE97FE9FBF737BD13
1521:107C10007FE97FE9FBF75FBD7FE97FE9FBF752BDB5
1522:107C20007FE97FE9FBF73ABD00000000000000009B
1523:107C30000000000000000000000000000000000044
1524:107C40007AFFFFFF00900050000000008C3400001D
1525:107C50000400000000000000000000000000000020
1526:107C6000000000000000000090ED00E000A00350C4
1527:107C70007FA60350009000506F9500501412002012
1528:107C8000A811002044010000615C00005D5C000060
1529:107C9000775B0000DC1000200C1100200411002094
1530:107CA00000110020FC1000201D48000011480000B9
1531:107CB000054800000000000029480000381100209D
1532:107CC00030110020281100200000000020110020A9
1533:107CD0003549000081480000B5480000FD4800001B
1534:107CE000682500203A00003A6C2500203A00003A4E
1535:107CF000702500203A00003A742500203A00003A2E
1536:107D00000000000000000000000000000000000073
1537:107D10000000000000000000000000000000000063
1538:107D20000000000000000000000000000000000053
1539:107D30000000000000000000000000000000000043
1540:107D40000000000000000000000000000000000033
1541:107D50000000000000000000000000000000000023
1542:087D6000553700002D3700002B
1543:00000001FF
diff --git a/examples/nrf9151/s/.cargo/config.toml b/examples/nrf9151/s/.cargo/config.toml
new file mode 100644
index 000000000..f64c63966
--- /dev/null
+++ b/examples/nrf9151/s/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2runner = "probe-rs run --chip nRF9160_xxAA"
3
4[build]
5target = "thumbv8m.main-none-eabihf"
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml
new file mode 100644
index 000000000..7253fc4be
--- /dev/null
+++ b/examples/nrf9151/s/Cargo.toml
@@ -0,0 +1,20 @@
1[package]
2edition = "2021"
3name = "embassy-nrf9151-secure-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8embassy-executor = { version = "0.6.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
11
12defmt = "0.3"
13defmt-rtt = "0.4"
14
15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
16cortex-m-rt = "0.7.0"
17panic-probe = { version = "0.3", features = ["print-defmt"] }
18
19[profile.release]
20debug = 2
diff --git a/examples/nrf9151/s/build.rs b/examples/nrf9151/s/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/nrf9151/s/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/nrf9151/s/memory.x b/examples/nrf9151/s/memory.x
new file mode 100644
index 000000000..4c7d4ebf0
--- /dev/null
+++ b/examples/nrf9151/s/memory.x
@@ -0,0 +1,5 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
4 RAM : ORIGIN = 0x20018000, LENGTH = 160K
5}
diff --git a/examples/nrf9151/s/src/bin/blinky.rs b/examples/nrf9151/s/src/bin/blinky.rs
new file mode 100644
index 000000000..7457a95a3
--- /dev/null
+++ b/examples/nrf9151/s/src/bin/blinky.rs
@@ -0,0 +1,22 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_nrf::gpio::{Level, Output, OutputDrive};
6use embassy_time::Timer;
7use {defmt_rtt as _, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = embassy_nrf::init(Default::default());
12 let mut led = Output::new(p.P0_00, Level::Low, OutputDrive::Standard);
13
14 loop {
15 led.set_high();
16 defmt::info!("high");
17 Timer::after_millis(500).await;
18 led.set_low();
19 defmt::info!("low");
20 Timer::after_millis(1000).await;
21 }
22}
diff --git a/examples/nrf9160/.cargo/config.toml b/examples/nrf9160/.cargo/config.toml
index 1444b0cd1..6072b8595 100644
--- a/examples/nrf9160/.cargo/config.toml
+++ b/examples/nrf9160/.cargo/config.toml
@@ -1,6 +1,6 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list` 2# runner = "probe-rs run --chip nRF9160_xxAA"
3runner = "probe-rs run --chip nRF9160_xxAA" 3runner = [ "probe-rs", "run", "--chip=nRF9160_xxAA", "--always-print-stacktrace", "--log-format={t} {[{L}]%bold} {s} {{c} {ff}:{l:1}%dimmed}" ]
4 4
5[build] 5[build]
6target = "thumbv8m.main-none-eabihf" 6target = "thumbv8m.main-none-eabihf"
diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml
index 2ff692b24..9aeb99317 100644
--- a/examples/nrf9160/Cargo.toml
+++ b/examples/nrf9160/Cargo.toml
@@ -5,16 +5,22 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 8embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
9embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 9embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 10embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
11embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] }
12embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] }
11 13
12defmt = "0.3" 14defmt = "0.3"
13defmt-rtt = "0.4" 15defmt-rtt = "0.4"
14 16
17heapless = "0.8"
15cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 18cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
16cortex-m-rt = "0.7.0" 19cortex-m-rt = "0.7.0"
17panic-probe = { version = "0.3", features = ["print-defmt"] } 20panic-probe = { version = "0.3", features = ["print-defmt"] }
21static_cell = { version = "2" }
22embedded-io = "0.6.1"
23embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
18 24
19[profile.release] 25[profile.release]
20debug = 2 26debug = 2
diff --git a/examples/nrf9160/memory.x b/examples/nrf9160/memory.x
index 4c7d4ebf0..e33498773 100644
--- a/examples/nrf9160/memory.x
+++ b/examples/nrf9160/memory.x
@@ -1,5 +1,9 @@
1MEMORY 1MEMORY
2{ 2{
3 FLASH : ORIGIN = 0x00000000, LENGTH = 1024K 3 FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
4 RAM : ORIGIN = 0x20018000, LENGTH = 160K 4 RAM : ORIGIN = 0x20010000, LENGTH = 192K
5 IPC : ORIGIN = 0x20000000, LENGTH = 64K
5} 6}
7
8PROVIDE(__start_ipc = ORIGIN(IPC));
9PROVIDE(__end_ipc = ORIGIN(IPC) + LENGTH(IPC));
diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs
new file mode 100644
index 000000000..5335b6b51
--- /dev/null
+++ b/examples/nrf9160/src/bin/modem_tcp_client.rs
@@ -0,0 +1,204 @@
1#![no_std]
2#![no_main]
3
4use core::mem::MaybeUninit;
5use core::net::IpAddr;
6use core::ptr::addr_of_mut;
7use core::slice;
8use core::str::FromStr;
9
10use defmt::{info, unwrap, warn};
11use embassy_executor::Spawner;
12use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources};
13use embassy_net_nrf91::context::Status;
14use embassy_net_nrf91::{context, Runner, State, TraceBuffer, TraceReader};
15use embassy_nrf::buffered_uarte::{self, BufferedUarteTx};
16use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin};
17use embassy_nrf::uarte::Baudrate;
18use embassy_nrf::{bind_interrupts, interrupt, peripherals, uarte};
19use embassy_time::{Duration, Timer};
20use embedded_io_async::Write;
21use heapless::Vec;
22use static_cell::StaticCell;
23use {defmt_rtt as _, panic_probe as _};
24
25#[interrupt]
26fn IPC() {
27 embassy_net_nrf91::on_ipc_irq();
28}
29
30bind_interrupts!(struct Irqs {
31 UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => buffered_uarte::InterruptHandler<peripherals::SERIAL0>;
32});
33
34#[embassy_executor::task]
35async fn trace_task(mut uart: BufferedUarteTx<'static, peripherals::SERIAL0>, reader: TraceReader<'static>) -> ! {
36 let mut rx = [0u8; 1024];
37 loop {
38 let n = reader.read(&mut rx[..]).await;
39 unwrap!(uart.write_all(&rx[..n]).await);
40 }
41}
42
43#[embassy_executor::task]
44async fn modem_task(runner: Runner<'static>) -> ! {
45 runner.run().await
46}
47
48#[embassy_executor::task]
49async fn net_task(stack: &'static Stack<embassy_net_nrf91::NetDriver<'static>>) -> ! {
50 stack.run().await
51}
52
53#[embassy_executor::task]
54async fn control_task(
55 control: &'static context::Control<'static>,
56 config: context::Config<'static>,
57 stack: &'static Stack<embassy_net_nrf91::NetDriver<'static>>,
58) {
59 unwrap!(control.configure(&config).await);
60 unwrap!(
61 control
62 .run(|status| {
63 stack.set_config_v4(status_to_config(status));
64 })
65 .await
66 );
67}
68
69fn status_to_config(status: &Status) -> embassy_net::ConfigV4 {
70 let Some(IpAddr::V4(addr)) = status.ip else {
71 panic!("Unexpected IP address");
72 };
73 let addr = Ipv4Address(addr.octets());
74
75 let gateway = if let Some(IpAddr::V4(addr)) = status.gateway {
76 Some(Ipv4Address(addr.octets()))
77 } else {
78 None
79 };
80
81 let mut dns_servers = Vec::new();
82 for dns in status.dns.iter() {
83 if let IpAddr::V4(ip) = dns {
84 unwrap!(dns_servers.push(Ipv4Address(ip.octets())));
85 }
86 }
87
88 embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 {
89 address: Ipv4Cidr::new(addr, 32),
90 gateway,
91 dns_servers,
92 })
93}
94
95#[embassy_executor::task]
96async fn blink_task(pin: AnyPin) {
97 let mut led = Output::new(pin, Level::Low, OutputDrive::Standard);
98 loop {
99 led.set_high();
100 Timer::after_millis(1000).await;
101 led.set_low();
102 Timer::after_millis(1000).await;
103 }
104}
105
106extern "C" {
107 static __start_ipc: u8;
108 static __end_ipc: u8;
109}
110
111#[embassy_executor::main]
112async fn main(spawner: Spawner) {
113 let p = embassy_nrf::init(Default::default());
114
115 info!("Hello World!");
116
117 unwrap!(spawner.spawn(blink_task(p.P0_02.degrade())));
118
119 let ipc_mem = unsafe {
120 let ipc_start = &__start_ipc as *const u8 as *mut MaybeUninit<u8>;
121 let ipc_end = &__end_ipc as *const u8 as *mut MaybeUninit<u8>;
122 let ipc_len = ipc_end.offset_from(ipc_start) as usize;
123 slice::from_raw_parts_mut(ipc_start, ipc_len)
124 };
125
126 static mut TRACE_BUF: [u8; 4096] = [0u8; 4096];
127 let mut config = uarte::Config::default();
128 config.baudrate = Baudrate::BAUD1M;
129 let uart = BufferedUarteTx::new(
130 //let trace_uart = BufferedUarteTx::new(
131 unsafe { peripherals::SERIAL0::steal() },
132 Irqs,
133 unsafe { peripherals::P0_01::steal() },
134 //unsafe { peripherals::P0_14::steal() },
135 config,
136 unsafe { &mut *addr_of_mut!(TRACE_BUF) },
137 );
138
139 static STATE: StaticCell<State> = StaticCell::new();
140 static TRACE: StaticCell<TraceBuffer> = StaticCell::new();
141 let (device, control, runner, tracer) =
142 embassy_net_nrf91::new_with_trace(STATE.init(State::new()), ipc_mem, TRACE.init(TraceBuffer::new())).await;
143 unwrap!(spawner.spawn(modem_task(runner)));
144 unwrap!(spawner.spawn(trace_task(uart, tracer)));
145
146 let config = embassy_net::Config::default();
147
148 // Generate "random" seed. nRF91 has no RNG, TODO figure out something...
149 let seed = 123456;
150
151 // Init network stack
152 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
153 static STACK: StaticCell<Stack<embassy_net_nrf91::NetDriver<'static>>> = StaticCell::new();
154 let stack = &*STACK.init(Stack::new(
155 device,
156 config,
157 RESOURCES.init(StackResources::<2>::new()),
158 seed,
159 ));
160
161 unwrap!(spawner.spawn(net_task(stack)));
162
163 static CONTROL: StaticCell<context::Control<'static>> = StaticCell::new();
164 let control = CONTROL.init(context::Control::new(control, 0).await);
165
166 unwrap!(spawner.spawn(control_task(
167 control,
168 context::Config {
169 apn: b"iot.nat.es",
170 auth_prot: context::AuthProt::Pap,
171 auth: Some((b"orange", b"orange")),
172 },
173 stack
174 )));
175
176 stack.wait_config_up().await;
177
178 let mut rx_buffer = [0; 4096];
179 let mut tx_buffer = [0; 4096];
180 loop {
181 let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
182 socket.set_timeout(Some(Duration::from_secs(10)));
183
184 info!("Connecting...");
185 let host_addr = embassy_net::Ipv4Address::from_str("45.79.112.203").unwrap();
186 if let Err(e) = socket.connect((host_addr, 4242)).await {
187 warn!("connect error: {:?}", e);
188 Timer::after_secs(10).await;
189 continue;
190 }
191 info!("Connected to {:?}", socket.remote_endpoint());
192
193 let msg = b"Hello world!\n";
194 for _ in 0..10 {
195 if let Err(e) = socket.write_all(msg).await {
196 warn!("write error: {:?}", e);
197 break;
198 }
199 info!("txd: {}", core::str::from_utf8(msg).unwrap());
200 Timer::after_secs(1).await;
201 }
202 Timer::after_secs(4).await;
203 }
204}
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 9bd403f02..04b4c6317 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -6,18 +6,18 @@ license = "MIT OR Apache-2.0"
6 6
7 7
8[dependencies] 8[dependencies]
9embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] } 9embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] } 13embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] }
14embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } 15embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] }
16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } 16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
18embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } 18embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" }
19cyw43 = { version = "0.1.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } 19cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs", "bluetooth"] }
20cyw43-pio = { version = "0.1.0", path = "../../cyw43-pio", features = ["defmt", "overclock"] } 20cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt"] }
21 21
22defmt = "0.3" 22defmt = "0.3"
23defmt-rtt = "0.4" 23defmt-rtt = "0.4"
@@ -29,6 +29,9 @@ reqwless = { version = "0.12.0", features = ["defmt",]}
29serde = { version = "1.0.203", default-features = false, features = ["derive"] } 29serde = { version = "1.0.203", default-features = false, features = ["derive"] }
30serde-json-core = "0.5.1" 30serde-json-core = "0.5.1"
31 31
32# for assign resources example
33assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "94ad10e2729afdf0fd5a77cd12e68409a982f58a" }
34
32#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 35#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
33cortex-m = { version = "0.7.6", features = ["inline-asm"] } 36cortex-m = { version = "0.7.6", features = ["inline-asm"] }
34cortex-m-rt = "0.7.0" 37cortex-m-rt = "0.7.0"
@@ -41,14 +44,14 @@ display-interface = "0.4.1"
41byte-slice-cast = { version = "1.2.0", default-features = false } 44byte-slice-cast = { version = "1.2.0", default-features = false }
42smart-leds = "0.3.0" 45smart-leds = "0.3.0"
43heapless = "0.8" 46heapless = "0.8"
44usbd-hid = "0.7.0" 47usbd-hid = "0.8.1"
45 48
46embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 49embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
47embedded-hal-async = "1.0" 50embedded-hal-async = "1.0"
48embedded-hal-bus = { version = "0.1", features = ["async"] } 51embedded-hal-bus = { version = "0.1", features = ["async"] }
49embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 52embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
50embedded-storage = { version = "0.3" } 53embedded-storage = { version = "0.3" }
51static_cell = "2" 54static_cell = "2.1"
52portable-atomic = { version = "1.5", features = ["critical-section"] } 55portable-atomic = { version = "1.5", features = ["critical-section"] }
53log = "0.4" 56log = "0.4"
54pio-proc = "0.2" 57pio-proc = "0.2"
@@ -56,9 +59,24 @@ pio = "0.2.1"
56rand = { version = "0.8.5", default-features = false } 59rand = { version = "0.8.5", default-features = false }
57embedded-sdmmc = "0.7.0" 60embedded-sdmmc = "0.7.0"
58 61
62bt-hci = { version = "0.1.0", default-features = false, features = ["defmt"] }
63trouble-host = { version = "0.1.0", features = ["defmt", "gatt"] }
64
59[profile.release] 65[profile.release]
60debug = 2 66debug = 2
67lto = true
68opt-level = 'z'
61 69
62[profile.dev] 70[profile.dev]
71debug = 2
63lto = true 72lto = true
64opt-level = "z" 73opt-level = "z"
74
75[patch.crates-io]
76trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" }
77embassy-executor = { path = "../../embassy-executor" }
78embassy-sync = { path = "../../embassy-sync" }
79embassy-futures = { path = "../../embassy-futures" }
80embassy-time = { path = "../../embassy-time" }
81embassy-time-driver = { path = "../../embassy-time-driver" }
82embassy-embedded-hal = { path = "../../embassy-embedded-hal" }
diff --git a/examples/rp/src/bin/assign_resources.rs b/examples/rp/src/bin/assign_resources.rs
new file mode 100644
index 000000000..ff6eff4a2
--- /dev/null
+++ b/examples/rp/src/bin/assign_resources.rs
@@ -0,0 +1,79 @@
1//! This example demonstrates how to assign resources to multiple tasks by splitting up the peripherals.
2//! It is not about sharing the same resources between tasks, see sharing.rs for that or head to https://embassy.dev/book/#_sharing_peripherals_between_tasks)
3//! Of course splitting up resources and sharing resources can be combined, yet this example is only about splitting up resources.
4//!
5//! There are basically two ways we demonstrate here:
6//! 1) Assigning resources to a task by passing parts of the peripherals
7//! 2) Assigning resources to a task by passing a struct with the split up peripherals, using the assign-resources macro
8//!
9//! using four LEDs on Pins 10, 11, 20 and 21
10
11#![no_std]
12#![no_main]
13
14use assign_resources::assign_resources;
15use defmt::*;
16use embassy_executor::Spawner;
17use embassy_rp::gpio::{Level, Output};
18use embassy_rp::peripherals::{self, PIN_20, PIN_21};
19use embassy_time::Timer;
20use {defmt_rtt as _, panic_probe as _};
21
22#[embassy_executor::main]
23async fn main(spawner: Spawner) {
24 // initialize the peripherals
25 let p = embassy_rp::init(Default::default());
26
27 // 1) Assigning a resource to a task by passing parts of the peripherals.
28 spawner
29 .spawn(double_blinky_manually_assigned(spawner, p.PIN_20, p.PIN_21))
30 .unwrap();
31
32 // 2) Using the assign-resources macro to assign resources to a task.
33 // we perform the split, see further below for the definition of the resources struct
34 let r = split_resources!(p);
35 // and then we can use them
36 spawner.spawn(double_blinky_macro_assigned(spawner, r.leds)).unwrap();
37}
38
39// 1) Assigning a resource to a task by passing parts of the peripherals.
40#[embassy_executor::task]
41async fn double_blinky_manually_assigned(_spawner: Spawner, pin_20: PIN_20, pin_21: PIN_21) {
42 let mut led_20 = Output::new(pin_20, Level::Low);
43 let mut led_21 = Output::new(pin_21, Level::High);
44
45 loop {
46 info!("toggling leds");
47 led_20.toggle();
48 led_21.toggle();
49 Timer::after_secs(1).await;
50 }
51}
52
53// 2) Using the assign-resources macro to assign resources to a task.
54// first we define the resources we want to assign to the task using the assign_resources! macro
55// basically this will split up the peripherals struct into smaller structs, that we define here
56// naming is up to you, make sure your future self understands what you did here
57assign_resources! {
58 leds: Leds{
59 led_10: PIN_10,
60 led_11: PIN_11,
61 }
62 // add more resources to more structs if needed, for example defining one struct for each task
63}
64// this could be done in another file and imported here, but for the sake of simplicity we do it here
65// see https://github.com/adamgreig/assign-resources for more information
66
67// 2) Using the split resources in a task
68#[embassy_executor::task]
69async fn double_blinky_macro_assigned(_spawner: Spawner, r: Leds) {
70 let mut led_10 = Output::new(r.led_10, Level::Low);
71 let mut led_11 = Output::new(r.led_11, Level::High);
72
73 loop {
74 info!("toggling leds");
75 led_10.toggle();
76 led_11.toggle();
77 Timer::after_secs(1).await;
78 }
79}
diff --git a/examples/rp/src/bin/bluetooth.rs b/examples/rp/src/bin/bluetooth.rs
new file mode 100644
index 000000000..7524e7929
--- /dev/null
+++ b/examples/rp/src/bin/bluetooth.rs
@@ -0,0 +1,150 @@
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
8use bt_hci::controller::ExternalController;
9use cyw43_pio::PioSpi;
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_futures::join::join3;
13use embassy_rp::bind_interrupts;
14use embassy_rp::gpio::{Level, Output};
15use embassy_rp::peripherals::{DMA_CH0, PIO0};
16use embassy_rp::pio::{InterruptHandler, Pio};
17use embassy_sync::blocking_mutex::raw::NoopRawMutex;
18use embassy_time::{Duration, Timer};
19use static_cell::StaticCell;
20use trouble_host::advertise::{AdStructure, Advertisement, BR_EDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE};
21use trouble_host::attribute::{AttributeTable, CharacteristicProp, Service, Uuid};
22use trouble_host::gatt::GattEvent;
23use trouble_host::{Address, BleHost, BleHostResources, PacketQos};
24use {defmt_rtt as _, embassy_time as _, panic_probe as _};
25
26bind_interrupts!(struct Irqs {
27 PIO0_IRQ_0 => InterruptHandler<PIO0>;
28});
29
30#[embassy_executor::task]
31async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
32 runner.run().await
33}
34
35#[embassy_executor::main]
36async fn main(spawner: Spawner) {
37 let p = embassy_rp::init(Default::default());
38 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
39 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
40 let btfw = include_bytes!("../../../../cyw43-firmware/43439A0_btfw.bin");
41
42 // To make flashing faster for development, you may want to flash the firmwares independently
43 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
44 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
45 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
46 // probe-rs download 43439A0_btfw.bin --format bin --chip RP2040 --base-address 0x10141400
47 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
48 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
49 //let btfw = unsafe { core::slice::from_raw_parts(0x10141400 as *const u8, 6164) };
50
51 let pwr = Output::new(p.PIN_23, Level::Low);
52 let cs = Output::new(p.PIN_25, Level::High);
53 let mut pio = Pio::new(p.PIO0, Irqs);
54 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
55
56 static STATE: StaticCell<cyw43::State> = StaticCell::new();
57 let state = STATE.init(cyw43::State::new());
58 let (_net_device, bt_device, mut control, runner) = cyw43::new_with_bluetooth(state, pwr, spi, fw, btfw).await;
59 unwrap!(spawner.spawn(cyw43_task(runner)));
60 control.init(clm).await;
61
62 let controller: ExternalController<_, 10> = ExternalController::new(bt_device);
63 static HOST_RESOURCES: StaticCell<BleHostResources<4, 32, 27>> = StaticCell::new();
64 let host_resources = HOST_RESOURCES.init(BleHostResources::new(PacketQos::None));
65
66 let mut ble: BleHost<'_, _> = BleHost::new(controller, host_resources);
67
68 ble.set_random_address(Address::random([0xff, 0x9f, 0x1a, 0x05, 0xe4, 0xff]));
69 let mut table: AttributeTable<'_, NoopRawMutex, 10> = AttributeTable::new();
70
71 // Generic Access Service (mandatory)
72 let id = b"Pico W Bluetooth";
73 let appearance = [0x80, 0x07];
74 let mut bat_level = [0; 1];
75 let handle = {
76 let mut svc = table.add_service(Service::new(0x1800));
77 let _ = svc.add_characteristic_ro(0x2a00, id);
78 let _ = svc.add_characteristic_ro(0x2a01, &appearance[..]);
79 svc.build();
80
81 // Generic attribute service (mandatory)
82 table.add_service(Service::new(0x1801));
83
84 // Battery service
85 let mut svc = table.add_service(Service::new(0x180f));
86
87 svc.add_characteristic(
88 0x2a19,
89 &[CharacteristicProp::Read, CharacteristicProp::Notify],
90 &mut bat_level,
91 )
92 .build()
93 };
94
95 let mut adv_data = [0; 31];
96 AdStructure::encode_slice(
97 &[
98 AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED),
99 AdStructure::ServiceUuids16(&[Uuid::Uuid16([0x0f, 0x18])]),
100 AdStructure::CompleteLocalName(b"Pico W Bluetooth"),
101 ],
102 &mut adv_data[..],
103 )
104 .unwrap();
105
106 let server = ble.gatt_server(&table);
107
108 info!("Starting advertising and GATT service");
109 let _ = join3(
110 ble.run(),
111 async {
112 loop {
113 match server.next().await {
114 Ok(GattEvent::Write { handle, connection: _ }) => {
115 let _ = table.get(handle, |value| {
116 info!("Write event. Value written: {:?}", value);
117 });
118 }
119 Ok(GattEvent::Read { .. }) => {
120 info!("Read event");
121 }
122 Err(e) => {
123 error!("Error processing GATT events: {:?}", e);
124 }
125 }
126 }
127 },
128 async {
129 let mut advertiser = ble
130 .advertise(
131 &Default::default(),
132 Advertisement::ConnectableScannableUndirected {
133 adv_data: &adv_data[..],
134 scan_data: &[],
135 },
136 )
137 .await
138 .unwrap();
139 let conn = advertiser.accept().await.unwrap();
140 // Keep connection alive
141 let mut tick: u8 = 0;
142 loop {
143 Timer::after(Duration::from_secs(10)).await;
144 tick += 1;
145 server.notify(handle, &conn, &[tick]).await.unwrap();
146 }
147 },
148 )
149 .await;
150}
diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
index def26b53d..aaa035a72 100644
--- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs
+++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
@@ -76,7 +76,7 @@ async fn main(spawner: Spawner) {
76 let stack = &*STACK.init(Stack::new( 76 let stack = &*STACK.init(Stack::new(
77 device, 77 device,
78 embassy_net::Config::dhcpv4(Default::default()), 78 embassy_net::Config::dhcpv4(Default::default()),
79 RESOURCES.init(StackResources::<3>::new()), 79 RESOURCES.init(StackResources::new()),
80 seed, 80 seed,
81 )); 81 ));
82 82
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
index 6c4a78361..8e96a114c 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
@@ -75,11 +75,11 @@ async fn main(spawner: Spawner) {
75 75
76 // Init network stack 76 // Init network stack
77 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new(); 77 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
78 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 78 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
79 let stack = &*STACK.init(Stack::new( 79 let stack = &*STACK.init(Stack::new(
80 device, 80 device,
81 embassy_net::Config::dhcpv4(Default::default()), 81 embassy_net::Config::dhcpv4(Default::default()),
82 RESOURCES.init(StackResources::<2>::new()), 82 RESOURCES.init(StackResources::new()),
83 seed, 83 seed,
84 )); 84 ));
85 85
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
index 30a3a7463..40736bf3c 100644
--- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
@@ -74,11 +74,11 @@ async fn main(spawner: Spawner) {
74 74
75 // Init network stack 75 // Init network stack
76 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new(); 76 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
77 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 77 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
78 let stack = &*STACK.init(Stack::new( 78 let stack = &*STACK.init(Stack::new(
79 device, 79 device,
80 embassy_net::Config::dhcpv4(Default::default()), 80 embassy_net::Config::dhcpv4(Default::default()),
81 RESOURCES.init(StackResources::<2>::new()), 81 RESOURCES.init(StackResources::new()),
82 seed, 82 seed,
83 )); 83 ));
84 84
diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs
index 1613ed887..c79f01538 100644
--- a/examples/rp/src/bin/ethernet_w5500_udp.rs
+++ b/examples/rp/src/bin/ethernet_w5500_udp.rs
@@ -72,11 +72,11 @@ async fn main(spawner: Spawner) {
72 72
73 // Init network stack 73 // Init network stack
74 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new(); 74 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
75 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 75 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
76 let stack = &*STACK.init(Stack::new( 76 let stack = &*STACK.init(Stack::new(
77 device, 77 device,
78 embassy_net::Config::dhcpv4(Default::default()), 78 embassy_net::Config::dhcpv4(Default::default()),
79 RESOURCES.init(StackResources::<2>::new()), 79 RESOURCES.init(StackResources::new()),
80 seed, 80 seed,
81 )); 81 ));
82 82
diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs
new file mode 100644
index 000000000..0e21d5833
--- /dev/null
+++ b/examples/rp/src/bin/orchestrate_tasks.rs
@@ -0,0 +1,318 @@
1//! This example demonstrates some approaches to communicate between tasks in order to orchestrate the state of the system.
2//!
3//! We demonstrate how to:
4//! - use a channel to send messages between tasks, in this case here in order to have one task control the state of the system.
5//! - use a signal to terminate a task.
6//! - use command channels to send commands to another task.
7//! - use different ways to receive messages, from a straightforwar awaiting on one channel to a more complex awaiting on multiple futures.
8//!
9//! There are more patterns to orchestrate tasks, this is just one example.
10//!
11//! We will use these tasks to generate example "state information":
12//! - a task that generates random numbers in intervals of 60s
13//! - a task that generates random numbers in intervals of 30s
14//! - a task that generates random numbers in intervals of 90s
15//! - a task that notifies about being attached/disattached from usb power
16//! - a task that measures vsys voltage in intervals of 30s
17//! - a task that consumes the state information and reacts to it
18
19#![no_std]
20#![no_main]
21
22use assign_resources::assign_resources;
23use defmt::*;
24use embassy_executor::Spawner;
25use embassy_futures::select::{select, Either};
26use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler};
27use embassy_rp::clocks::RoscRng;
28use embassy_rp::gpio::{Input, Pull};
29use embassy_rp::{bind_interrupts, peripherals};
30use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
31use embassy_sync::{channel, signal};
32use embassy_time::{Duration, Timer};
33use rand::RngCore;
34use {defmt_rtt as _, panic_probe as _};
35
36// This is just some preparation, see example `assign_resources.rs` for more information on this. We prep the rresources that we will be using in different tasks.
37// **Note**: This will not work with a board that has a wifi chip, because the wifi chip uses pins 24 and 29 for its own purposes. A way around this in software
38// is not trivial, at least if you intend to use wifi, too. Workaround is to wire from vsys and vbus pins to appropriate pins on the board through a voltage divider. Then use those pins.
39// For this example it will not matter much, the concept of what we are showing remains valid.
40assign_resources! {
41 vsys: Vsys {
42 adc: ADC,
43 pin_29: PIN_29,
44 },
45 vbus: Vbus {
46 pin_24: PIN_24,
47 },
48}
49
50bind_interrupts!(struct Irqs {
51 ADC_IRQ_FIFO => InterruptHandler;
52});
53
54/// This is the type of Events that we will send from the worker tasks to the orchestrating task.
55enum Events {
56 UsbPowered(bool),
57 VsysVoltage(f32),
58 FirstRandomSeed(u32),
59 SecondRandomSeed(u32),
60 ThirdRandomSeed(u32),
61 ResetFirstRandomSeed,
62}
63
64/// This is the type of Commands that we will send from the orchestrating task to the worker tasks.
65/// Note that we are lazy here and only have one command, you might want to have more.
66enum Commands {
67 /// This command will stop the appropriate worker task
68 Stop,
69}
70
71/// This is the state of the system, we will use this to orchestrate the system. This is a simple example, in a real world application this would be more complex.
72#[derive(Default, Debug, Clone, Format)]
73struct State {
74 usb_powered: bool,
75 vsys_voltage: f32,
76 first_random_seed: u32,
77 second_random_seed: u32,
78 third_random_seed: u32,
79 times_we_got_first_random_seed: u8,
80 maximum_times_we_want_first_random_seed: u8,
81}
82
83impl State {
84 fn new() -> Self {
85 Self {
86 usb_powered: false,
87 vsys_voltage: 0.0,
88 first_random_seed: 0,
89 second_random_seed: 0,
90 third_random_seed: 0,
91 times_we_got_first_random_seed: 0,
92 maximum_times_we_want_first_random_seed: 3,
93 }
94 }
95}
96
97/// Channel for the events that we want the orchestrator to react to, all state events are of the type Enum Events.
98/// We use a channel with an arbitrary size of 10, the precise size of the queue depends on your use case. This depends on how many events we
99/// expect to be generated in a given time frame and how fast the orchestrator can react to them. And then if we rather want the senders to wait for
100/// new slots in the queue or if we want the orchestrator to have a backlog of events to process. In this case here we expect to always be enough slots
101/// in the queue, so the worker tasks can in all nominal cases send their events and continue with their work without waiting.
102/// For the events we - in this case here - do not want to loose any events, so a channel is a good choice. See embassy_sync docs for other options.
103static EVENT_CHANNEL: channel::Channel<CriticalSectionRawMutex, Events, 10> = channel::Channel::new();
104
105/// Signal for stopping the first random signal task. We use a signal here, because we need no queue. It is suffiient to have one signal active.
106static STOP_FIRST_RANDOM_SIGNAL: signal::Signal<CriticalSectionRawMutex, Commands> = signal::Signal::new();
107
108/// Channel for the state that we want the consumer task to react to. We use a channel here, because we want to have a queue of state changes, although
109/// we want the queue to be of size 1, because we want to finish rwacting to the state change before the next one comes in. This is just a design choice
110/// and depends on your use case.
111static CONSUMER_CHANNEL: channel::Channel<CriticalSectionRawMutex, State, 1> = channel::Channel::new();
112
113// And now we can put all this into use
114
115/// This is the main task, that will not do very much besides spawning the other tasks. This is a design choice, you could do the
116/// orchestrating here. This is to show that we do not need a main loop here, the system will run indefinitely as long as at least one task is running.
117#[embassy_executor::main]
118async fn main(spawner: Spawner) {
119 // initialize the peripherals
120 let p = embassy_rp::init(Default::default());
121 // split the resources, for convenience - see above
122 let r = split_resources! {p};
123
124 // spawn the tasks
125 spawner.spawn(orchestrate(spawner)).unwrap();
126 spawner.spawn(random_60s(spawner)).unwrap();
127 spawner.spawn(random_90s(spawner)).unwrap();
128 spawner.spawn(usb_power(spawner, r.vbus)).unwrap();
129 spawner.spawn(vsys_voltage(spawner, r.vsys)).unwrap();
130 spawner.spawn(consumer(spawner)).unwrap();
131}
132
133/// This is the task handling the system state and orchestrating the other tasks. WEe can regard this as the "main loop" of the system.
134#[embassy_executor::task]
135async fn orchestrate(_spawner: Spawner) {
136 let mut state = State::new();
137
138 // we need to have a receiver for the events
139 let receiver = EVENT_CHANNEL.receiver();
140
141 // and we need a sender for the consumer task
142 let state_sender = CONSUMER_CHANNEL.sender();
143
144 loop {
145 // we await on the receiver, this will block until a new event is available
146 // as an alternative to this, we could also await on multiple channels, this would block until at least one of the channels has an event
147 // see the embassy_futures docs: https://docs.embassy.dev/embassy-futures/git/default/select/index.html
148 // The task random_30s does a select, if you want to have a look at that.
149 // Another reason to use select may also be that we want to have a timeout, so we can react to the absence of events within a time frame.
150 // We keep it simple here.
151 let event = receiver.receive().await;
152
153 // react to the events
154 match event {
155 Events::UsbPowered(usb_powered) => {
156 // update the state and/or react to the event here
157 state.usb_powered = usb_powered;
158 info!("Usb powered: {}", usb_powered);
159 }
160 Events::VsysVoltage(voltage) => {
161 // update the state and/or react to the event here
162 state.vsys_voltage = voltage;
163 info!("Vsys voltage: {}", voltage);
164 }
165 Events::FirstRandomSeed(seed) => {
166 // update the state and/or react to the event here
167 state.first_random_seed = seed;
168 // here we change some meta state, we count how many times we got the first random seed
169 state.times_we_got_first_random_seed += 1;
170 info!(
171 "First random seed: {}, and that was iteration {} of receiving this.",
172 seed, &state.times_we_got_first_random_seed
173 );
174 }
175 Events::SecondRandomSeed(seed) => {
176 // update the state and/or react to the event here
177 state.second_random_seed = seed;
178 info!("Second random seed: {}", seed);
179 }
180 Events::ThirdRandomSeed(seed) => {
181 // update the state and/or react to the event here
182 state.third_random_seed = seed;
183 info!("Third random seed: {}", seed);
184 }
185 Events::ResetFirstRandomSeed => {
186 // update the state and/or react to the event here
187 state.times_we_got_first_random_seed = 0;
188 state.first_random_seed = 0;
189 info!("Resetting the first random seed counter");
190 }
191 }
192 // we now have an altered state
193 // there is a crate for detecting field changes on crates.io (https://crates.io/crates/fieldset) that might be useful here
194 // for now we just keep it simple
195
196 // we send the state to the consumer task
197 // since the channel has a size of 1, this will block until the consumer task has received the state, which is what we want here in this example
198 // **Note:** It is bad design to send too much data between tasks, with no clear definition of what "too much" is. In this example we send the
199 // whole state, in a real world application you might want to send only the data, that is relevant to the consumer task AND only when it has changed.
200 // We keep it simple here.
201 state_sender.send(state.clone()).await;
202 }
203}
204
205/// This task will consume the state information and react to it. This is a simple example, in a real world application this would be more complex
206/// and we could have multiple consumer tasks, each reacting to different parts of the state.
207#[embassy_executor::task]
208async fn consumer(spawner: Spawner) {
209 // we need to have a receiver for the state
210 let receiver = CONSUMER_CHANNEL.receiver();
211 let sender = EVENT_CHANNEL.sender();
212 loop {
213 // we await on the receiver, this will block until a new state is available
214 let state = receiver.receive().await;
215 // react to the state, in this case here we just log it
216 info!("The consumer has reveived this state: {:?}", &state);
217
218 // here we react to the state, in this case here we want to start or stop the first random signal task depending on the state of the system
219 match state.times_we_got_first_random_seed {
220 max if max == state.maximum_times_we_want_first_random_seed => {
221 info!("Stopping the first random signal task");
222 // we send a command to the task
223 STOP_FIRST_RANDOM_SIGNAL.signal(Commands::Stop);
224 // we notify the orchestrator that we have sent the command
225 sender.send(Events::ResetFirstRandomSeed).await;
226 }
227 0 => {
228 // we start the task, which presents us with an interesting problem, because we may return here before the task has started
229 // here we just try and log if the task has started, in a real world application you might want to handle this more gracefully
230 info!("Starting the first random signal task");
231 match spawner.spawn(random_30s(spawner)) {
232 Ok(_) => info!("Successfully spawned random_30s task"),
233 Err(e) => info!("Failed to spawn random_30s task: {:?}", e),
234 }
235 }
236 _ => {}
237 }
238 }
239}
240
241/// This task will generate random numbers in intervals of 30s
242/// The task will terminate after it has received a command signal to stop, see the orchestrate task for that.
243/// Note that we are not spawning this task from main, as we will show how such a task can be spawned and closed dynamically.
244#[embassy_executor::task]
245async fn random_30s(_spawner: Spawner) {
246 let mut rng = RoscRng;
247 let sender = EVENT_CHANNEL.sender();
248 loop {
249 // we either await on the timer or the signal, whichever comes first.
250 let futures = select(Timer::after(Duration::from_secs(30)), STOP_FIRST_RANDOM_SIGNAL.wait()).await;
251 match futures {
252 Either::First(_) => {
253 // we received are operating on the timer
254 info!("30s are up, generating random number");
255 let random_number = rng.next_u32();
256 sender.send(Events::FirstRandomSeed(random_number)).await;
257 }
258 Either::Second(_) => {
259 // we received the signal to stop
260 info!("Received signal to stop, goodbye!");
261 break;
262 }
263 }
264 }
265}
266
267/// This task will generate random numbers in intervals of 60s
268#[embassy_executor::task]
269async fn random_60s(_spawner: Spawner) {
270 let mut rng = RoscRng;
271 let sender = EVENT_CHANNEL.sender();
272 loop {
273 Timer::after(Duration::from_secs(60)).await;
274 let random_number = rng.next_u32();
275 sender.send(Events::SecondRandomSeed(random_number)).await;
276 }
277}
278
279/// This task will generate random numbers in intervals of 90s
280#[embassy_executor::task]
281async fn random_90s(_spawner: Spawner) {
282 let mut rng = RoscRng;
283 let sender = EVENT_CHANNEL.sender();
284 loop {
285 Timer::after(Duration::from_secs(90)).await;
286 let random_number = rng.next_u32();
287 sender.send(Events::ThirdRandomSeed(random_number)).await;
288 }
289}
290
291/// This task will notify if we are connected to usb power
292#[embassy_executor::task]
293pub async fn usb_power(_spawner: Spawner, r: Vbus) {
294 let mut vbus_in = Input::new(r.pin_24, Pull::None);
295 let sender = EVENT_CHANNEL.sender();
296 loop {
297 sender.send(Events::UsbPowered(vbus_in.is_high())).await;
298 vbus_in.wait_for_any_edge().await;
299 }
300}
301
302/// This task will measure the vsys voltage in intervals of 30s
303#[embassy_executor::task]
304pub async fn vsys_voltage(_spawner: Spawner, r: Vsys) {
305 let mut adc = Adc::new(r.adc, Irqs, Config::default());
306 let vsys_in = r.pin_29;
307 let mut channel = Channel::new_pin(vsys_in, Pull::None);
308 let sender = EVENT_CHANNEL.sender();
309 loop {
310 // read the adc value
311 let adc_value = adc.read(&mut channel).await.unwrap();
312 // convert the adc value to voltage.
313 // 3.3 is the reference voltage, 3.0 is the factor for the inbuilt voltage divider and 4096 is the resolution of the adc
314 let voltage = (adc_value as f32) * 3.3 * 3.0 / 4096.0;
315 sender.send(Events::VsysVoltage(voltage)).await;
316 Timer::after(Duration::from_secs(30)).await;
317 }
318}
diff --git a/examples/rp/src/bin/shared_bus.rs b/examples/rp/src/bin/shared_bus.rs
new file mode 100644
index 000000000..c6cb5d64c
--- /dev/null
+++ b/examples/rp/src/bin/shared_bus.rs
@@ -0,0 +1,115 @@
1//! This example shows how to share (async) I2C and SPI buses between multiple devices.
2
3#![no_std]
4#![no_main]
5
6use defmt::*;
7use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice;
8use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice;
9use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts;
11use embassy_rp::gpio::{AnyPin, Level, Output};
12use embassy_rp::i2c::{self, I2c, InterruptHandler};
13use embassy_rp::peripherals::{I2C1, SPI1};
14use embassy_rp::spi::{self, Spi};
15use embassy_sync::blocking_mutex::raw::NoopRawMutex;
16use embassy_sync::mutex::Mutex;
17use embassy_time::Timer;
18use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _};
20
21type Spi1Bus = Mutex<NoopRawMutex, Spi<'static, SPI1, spi::Async>>;
22type I2c1Bus = Mutex<NoopRawMutex, I2c<'static, I2C1, i2c::Async>>;
23
24bind_interrupts!(struct Irqs {
25 I2C1_IRQ => InterruptHandler<I2C1>;
26});
27
28#[embassy_executor::main]
29async fn main(spawner: Spawner) {
30 let p = embassy_rp::init(Default::default());
31 info!("Here we go!");
32
33 // Shared I2C bus
34 let i2c = I2c::new_async(p.I2C1, p.PIN_15, p.PIN_14, Irqs, i2c::Config::default());
35 static I2C_BUS: StaticCell<I2c1Bus> = StaticCell::new();
36 let i2c_bus = I2C_BUS.init(Mutex::new(i2c));
37
38 spawner.must_spawn(i2c_task_a(i2c_bus));
39 spawner.must_spawn(i2c_task_b(i2c_bus));
40
41 // Shared SPI bus
42 let spi_cfg = spi::Config::default();
43 let spi = Spi::new(p.SPI1, p.PIN_10, p.PIN_11, p.PIN_12, p.DMA_CH0, p.DMA_CH1, spi_cfg);
44 static SPI_BUS: StaticCell<Spi1Bus> = StaticCell::new();
45 let spi_bus = SPI_BUS.init(Mutex::new(spi));
46
47 // Chip select pins for the SPI devices
48 let cs_a = Output::new(AnyPin::from(p.PIN_0), Level::High);
49 let cs_b = Output::new(AnyPin::from(p.PIN_1), Level::High);
50
51 spawner.must_spawn(spi_task_a(spi_bus, cs_a));
52 spawner.must_spawn(spi_task_b(spi_bus, cs_b));
53}
54
55#[embassy_executor::task]
56async fn i2c_task_a(i2c_bus: &'static I2c1Bus) {
57 let i2c_dev = I2cDevice::new(i2c_bus);
58 let _sensor = DummyI2cDeviceDriver::new(i2c_dev, 0xC0);
59 loop {
60 info!("i2c task A");
61 Timer::after_secs(1).await;
62 }
63}
64
65#[embassy_executor::task]
66async fn i2c_task_b(i2c_bus: &'static I2c1Bus) {
67 let i2c_dev = I2cDevice::new(i2c_bus);
68 let _sensor = DummyI2cDeviceDriver::new(i2c_dev, 0xDE);
69 loop {
70 info!("i2c task B");
71 Timer::after_secs(1).await;
72 }
73}
74
75#[embassy_executor::task]
76async fn spi_task_a(spi_bus: &'static Spi1Bus, cs: Output<'static>) {
77 let spi_dev = SpiDevice::new(spi_bus, cs);
78 let _sensor = DummySpiDeviceDriver::new(spi_dev);
79 loop {
80 info!("spi task A");
81 Timer::after_secs(1).await;
82 }
83}
84
85#[embassy_executor::task]
86async fn spi_task_b(spi_bus: &'static Spi1Bus, cs: Output<'static>) {
87 let spi_dev = SpiDevice::new(spi_bus, cs);
88 let _sensor = DummySpiDeviceDriver::new(spi_dev);
89 loop {
90 info!("spi task B");
91 Timer::after_secs(1).await;
92 }
93}
94
95// Dummy I2C device driver, using `embedded-hal-async`
96struct DummyI2cDeviceDriver<I2C: embedded_hal_async::i2c::I2c> {
97 _i2c: I2C,
98}
99
100impl<I2C: embedded_hal_async::i2c::I2c> DummyI2cDeviceDriver<I2C> {
101 fn new(i2c_dev: I2C, _address: u8) -> Self {
102 Self { _i2c: i2c_dev }
103 }
104}
105
106// Dummy SPI device driver, using `embedded-hal-async`
107struct DummySpiDeviceDriver<SPI: embedded_hal_async::spi::SpiDevice> {
108 _spi: SPI,
109}
110
111impl<SPI: embedded_hal_async::spi::SpiDevice> DummySpiDeviceDriver<SPI> {
112 fn new(spi_dev: SPI) -> Self {
113 Self { _spi: spi_dev }
114 }
115}
diff --git a/examples/rp/src/bin/sharing.rs b/examples/rp/src/bin/sharing.rs
new file mode 100644
index 000000000..5416e20ce
--- /dev/null
+++ b/examples/rp/src/bin/sharing.rs
@@ -0,0 +1,150 @@
1//! This example shows some common strategies for sharing resources between tasks.
2//!
3//! We demonstrate five different ways of sharing, covering different use cases:
4//! - Atomics: This method is used for simple values, such as bool and u8..u32
5//! - Blocking Mutex: This is used for sharing non-async things, using Cell/RefCell for interior mutability.
6//! - Async Mutex: This is used for sharing async resources, where you need to hold the lock across await points.
7//! The async Mutex has interior mutability built-in, so no RefCell is needed.
8//! - Cell: For sharing Copy types between tasks running on the same executor.
9//! - RefCell: When you want &mut access to a value shared between tasks running on the same executor.
10//!
11//! More information: https://embassy.dev/book/#_sharing_peripherals_between_tasks
12
13#![no_std]
14#![no_main]
15
16use core::cell::{Cell, RefCell};
17use core::sync::atomic::{AtomicU32, Ordering};
18
19use cortex_m_rt::entry;
20use defmt::info;
21use embassy_executor::{Executor, InterruptExecutor};
22use embassy_rp::clocks::RoscRng;
23use embassy_rp::interrupt::{InterruptExt, Priority};
24use embassy_rp::peripherals::UART0;
25use embassy_rp::uart::{self, InterruptHandler, UartTx};
26use embassy_rp::{bind_interrupts, interrupt};
27use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
28use embassy_sync::{blocking_mutex, mutex};
29use embassy_time::{Duration, Ticker};
30use rand::RngCore;
31use static_cell::{ConstStaticCell, StaticCell};
32use {defmt_rtt as _, panic_probe as _};
33
34type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>;
35
36struct MyType {
37 inner: u32,
38}
39
40static EXECUTOR_HI: InterruptExecutor = InterruptExecutor::new();
41static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
42
43// Use Atomics for simple values
44static ATOMIC: AtomicU32 = AtomicU32::new(0);
45
46// Use blocking Mutex with Cell/RefCell for sharing non-async things
47static MUTEX_BLOCKING: blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<MyType>> =
48 blocking_mutex::Mutex::new(RefCell::new(MyType { inner: 0 }));
49
50bind_interrupts!(struct Irqs {
51 UART0_IRQ => InterruptHandler<UART0>;
52});
53
54#[interrupt]
55unsafe fn SWI_IRQ_0() {
56 EXECUTOR_HI.on_interrupt()
57}
58
59#[entry]
60fn main() -> ! {
61 let p = embassy_rp::init(Default::default());
62 info!("Here we go!");
63
64 let uart = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, uart::Config::default());
65 // Use the async Mutex for sharing async things (built-in interior mutability)
66 static UART: StaticCell<UartAsyncMutex> = StaticCell::new();
67 let uart = UART.init(mutex::Mutex::new(uart));
68
69 // High-priority executor: runs in interrupt mode
70 interrupt::SWI_IRQ_0.set_priority(Priority::P3);
71 let spawner = EXECUTOR_HI.start(interrupt::SWI_IRQ_0);
72 spawner.must_spawn(task_a(uart));
73
74 // Low priority executor: runs in thread mode
75 let executor = EXECUTOR_LOW.init(Executor::new());
76 executor.run(|spawner| {
77 // No Mutex needed when sharing between tasks running on the same executor
78
79 // Use Cell for Copy-types
80 static CELL: ConstStaticCell<Cell<[u8; 4]>> = ConstStaticCell::new(Cell::new([0; 4]));
81 let cell = CELL.take();
82
83 // Use RefCell for &mut access
84 static REF_CELL: ConstStaticCell<RefCell<MyType>> = ConstStaticCell::new(RefCell::new(MyType { inner: 0 }));
85 let ref_cell = REF_CELL.take();
86
87 spawner.must_spawn(task_b(uart, cell, ref_cell));
88 spawner.must_spawn(task_c(cell, ref_cell));
89 });
90}
91
92#[embassy_executor::task]
93async fn task_a(uart: &'static UartAsyncMutex) {
94 let mut ticker = Ticker::every(Duration::from_secs(1));
95 loop {
96 let random = RoscRng.next_u32();
97
98 {
99 let mut uart = uart.lock().await;
100 uart.write(b"task a").await.unwrap();
101 // The uart lock is released when it goes out of scope
102 }
103
104 ATOMIC.store(random, Ordering::Relaxed);
105
106 MUTEX_BLOCKING.lock(|x| x.borrow_mut().inner = random);
107
108 ticker.next().await;
109 }
110}
111
112#[embassy_executor::task]
113async fn task_b(uart: &'static UartAsyncMutex, cell: &'static Cell<[u8; 4]>, ref_cell: &'static RefCell<MyType>) {
114 let mut ticker = Ticker::every(Duration::from_secs(1));
115 loop {
116 let random = RoscRng.next_u32();
117
118 uart.lock().await.write(b"task b").await.unwrap();
119
120 cell.set(random.to_be_bytes());
121
122 ref_cell.borrow_mut().inner = random;
123
124 ticker.next().await;
125 }
126}
127
128#[embassy_executor::task]
129async fn task_c(cell: &'static Cell<[u8; 4]>, ref_cell: &'static RefCell<MyType>) {
130 let mut ticker = Ticker::every(Duration::from_secs(1));
131 loop {
132 info!("=======================");
133
134 let atomic_val = ATOMIC.load(Ordering::Relaxed);
135 info!("atomic: {}", atomic_val);
136
137 MUTEX_BLOCKING.lock(|x| {
138 let val = x.borrow().inner;
139 info!("blocking mutex: {}", val);
140 });
141
142 let cell_val = cell.get();
143 info!("cell: {:?}", cell_val);
144
145 let ref_cell_val = ref_cell.borrow().inner;
146 info!("ref_cell: {:?}", ref_cell_val);
147
148 ticker.next().await;
149 }
150}
diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs
index fac61aa04..468d2b61a 100644
--- a/examples/rp/src/bin/uart_buffered_split.rs
+++ b/examples/rp/src/bin/uart_buffered_split.rs
@@ -31,7 +31,7 @@ async fn main(spawner: Spawner) {
31 static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); 31 static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new();
32 let rx_buf = &mut RX_BUF.init([0; 16])[..]; 32 let rx_buf = &mut RX_BUF.init([0; 16])[..];
33 let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default()); 33 let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default());
34 let (rx, mut tx) = uart.split(); 34 let (mut tx, rx) = uart.split();
35 35
36 unwrap!(spawner.spawn(reader(rx))); 36 unwrap!(spawner.spawn(reader(rx)));
37 37
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
index 22dc88d28..03c510f37 100644
--- a/examples/rp/src/bin/usb_ethernet.rs
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -109,13 +109,8 @@ async fn main(spawner: Spawner) {
109 109
110 // Init network stack 110 // Init network stack
111 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new(); 111 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new();
112 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 112 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
113 let stack = &*STACK.init(Stack::new( 113 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
114 device,
115 config,
116 RESOURCES.init(StackResources::<2>::new()),
117 seed,
118 ));
119 114
120 unwrap!(spawner.spawn(net_task(stack))); 115 unwrap!(spawner.spawn(net_task(stack)));
121 116
diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs
index cce344fb0..5ee650910 100644
--- a/examples/rp/src/bin/usb_hid_mouse.rs
+++ b/examples/rp/src/bin/usb_hid_mouse.rs
@@ -8,7 +8,6 @@ use embassy_executor::Spawner;
8use embassy_futures::join::join; 8use embassy_futures::join::join;
9use embassy_rp::bind_interrupts; 9use embassy_rp::bind_interrupts;
10use embassy_rp::clocks::RoscRng; 10use embassy_rp::clocks::RoscRng;
11use embassy_rp::gpio::{Input, Pull};
12use embassy_rp::peripherals::USB; 11use embassy_rp::peripherals::USB;
13use embassy_rp::usb::{Driver, InterruptHandler}; 12use embassy_rp::usb::{Driver, InterruptHandler};
14use embassy_time::Timer; 13use embassy_time::Timer;
@@ -75,12 +74,6 @@ async fn main(_spawner: Spawner) {
75 // Run the USB device. 74 // Run the USB device.
76 let usb_fut = usb.run(); 75 let usb_fut = usb.run();
77 76
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 // Enable the schmitt trigger to slightly debounce.
82 signal_pin.set_schmitt(true);
83
84 let (reader, mut writer) = hid.split(); 77 let (reader, mut writer) = hid.split();
85 78
86 // Do stuff with the class! 79 // Do stuff with the class!
diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs
index 4fc2690e3..00f404a9b 100644
--- a/examples/rp/src/bin/wifi_ap_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs
@@ -28,7 +28,7 @@ bind_interrupts!(struct Irqs {
28}); 28});
29 29
30#[embassy_executor::task] 30#[embassy_executor::task]
31async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { 31async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
32 runner.run().await 32 runner.run().await
33} 33}
34 34
@@ -62,7 +62,7 @@ async fn main(spawner: Spawner) {
62 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 62 static STATE: StaticCell<cyw43::State> = StaticCell::new();
63 let state = STATE.init(cyw43::State::new()); 63 let state = STATE.init(cyw43::State::new());
64 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 64 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
65 unwrap!(spawner.spawn(wifi_task(runner))); 65 unwrap!(spawner.spawn(cyw43_task(runner)));
66 66
67 control.init(clm).await; 67 control.init(clm).await;
68 control 68 control
@@ -81,11 +81,11 @@ async fn main(spawner: Spawner) {
81 81
82 // Init network stack 82 // Init network stack
83 static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new(); 83 static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new();
84 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 84 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
85 let stack = &*STACK.init(Stack::new( 85 let stack = &*STACK.init(Stack::new(
86 net_device, 86 net_device,
87 config, 87 config,
88 RESOURCES.init(StackResources::<2>::new()), 88 RESOURCES.init(StackResources::new()),
89 seed, 89 seed,
90 )); 90 ));
91 91
diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs
index 471349639..04a61bbd5 100644
--- a/examples/rp/src/bin/wifi_blinky.rs
+++ b/examples/rp/src/bin/wifi_blinky.rs
@@ -21,7 +21,7 @@ bind_interrupts!(struct Irqs {
21}); 21});
22 22
23#[embassy_executor::task] 23#[embassy_executor::task]
24async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { 24async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
25 runner.run().await 25 runner.run().await
26} 26}
27 27
@@ -46,7 +46,7 @@ async fn main(spawner: Spawner) {
46 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 46 static STATE: StaticCell<cyw43::State> = StaticCell::new();
47 let state = STATE.init(cyw43::State::new()); 47 let state = STATE.init(cyw43::State::new());
48 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 48 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
49 unwrap!(spawner.spawn(wifi_task(runner))); 49 unwrap!(spawner.spawn(cyw43_task(runner)));
50 50
51 control.init(clm).await; 51 control.init(clm).await;
52 control 52 control
diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs
index 5f4c848a2..ab3529112 100644
--- a/examples/rp/src/bin/wifi_scan.rs
+++ b/examples/rp/src/bin/wifi_scan.rs
@@ -23,7 +23,7 @@ bind_interrupts!(struct Irqs {
23}); 23});
24 24
25#[embassy_executor::task] 25#[embassy_executor::task]
26async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { 26async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
27 runner.run().await 27 runner.run().await
28} 28}
29 29
@@ -56,7 +56,7 @@ async fn main(spawner: Spawner) {
56 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 56 static STATE: StaticCell<cyw43::State> = StaticCell::new();
57 let state = STATE.init(cyw43::State::new()); 57 let state = STATE.init(cyw43::State::new());
58 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 58 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
59 unwrap!(spawner.spawn(wifi_task(runner))); 59 unwrap!(spawner.spawn(cyw43_task(runner)));
60 60
61 control.init(clm).await; 61 control.init(clm).await;
62 control 62 control
diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs
index 5575df677..b2950d98a 100644
--- a/examples/rp/src/bin/wifi_tcp_server.rs
+++ b/examples/rp/src/bin/wifi_tcp_server.rs
@@ -7,6 +7,7 @@
7 7
8use core::str::from_utf8; 8use core::str::from_utf8;
9 9
10use cyw43::JoinOptions;
10use cyw43_pio::PioSpi; 11use cyw43_pio::PioSpi;
11use defmt::*; 12use defmt::*;
12use embassy_executor::Spawner; 13use embassy_executor::Spawner;
@@ -27,11 +28,11 @@ bind_interrupts!(struct Irqs {
27 PIO0_IRQ_0 => InterruptHandler<PIO0>; 28 PIO0_IRQ_0 => InterruptHandler<PIO0>;
28}); 29});
29 30
30const WIFI_NETWORK: &str = "EmbassyTest"; 31const WIFI_NETWORK: &str = "LadronDeWifi";
31const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; 32const WIFI_PASSWORD: &str = "MBfcaedHmyRFE4kaQ1O5SsY8";
32 33
33#[embassy_executor::task] 34#[embassy_executor::task]
34async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { 35async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
35 runner.run().await 36 runner.run().await
36} 37}
37 38
@@ -65,7 +66,7 @@ async fn main(spawner: Spawner) {
65 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 66 static STATE: StaticCell<cyw43::State> = StaticCell::new();
66 let state = STATE.init(cyw43::State::new()); 67 let state = STATE.init(cyw43::State::new());
67 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 68 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
68 unwrap!(spawner.spawn(wifi_task(runner))); 69 unwrap!(spawner.spawn(cyw43_task(runner)));
69 70
70 control.init(clm).await; 71 control.init(clm).await;
71 control 72 control
@@ -84,19 +85,21 @@ async fn main(spawner: Spawner) {
84 85
85 // Init network stack 86 // Init network stack
86 static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new(); 87 static STACK: StaticCell<Stack<cyw43::NetDriver<'static>>> = StaticCell::new();
87 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 88 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
88 let stack = &*STACK.init(Stack::new( 89 let stack = &*STACK.init(Stack::new(
89 net_device, 90 net_device,
90 config, 91 config,
91 RESOURCES.init(StackResources::<2>::new()), 92 RESOURCES.init(StackResources::new()),
92 seed, 93 seed,
93 )); 94 ));
94 95
95 unwrap!(spawner.spawn(net_task(stack))); 96 unwrap!(spawner.spawn(net_task(stack)));
96 97
97 loop { 98 loop {
98 //control.join_open(WIFI_NETWORK).await; 99 match control
99 match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await { 100 .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes()))
101 .await
102 {
100 Ok(_) => break, 103 Ok(_) => break,
101 Err(err) => { 104 Err(err) => {
102 info!("join failed with status={}", err.status); 105 info!("join failed with status={}", err.status);
diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs
index 70b6f0949..b43be8905 100644
--- a/examples/rp/src/bin/wifi_webrequest.rs
+++ b/examples/rp/src/bin/wifi_webrequest.rs
@@ -7,6 +7,7 @@
7 7
8use core::str::from_utf8; 8use core::str::from_utf8;
9 9
10use cyw43::JoinOptions;
10use cyw43_pio::PioSpi; 11use cyw43_pio::PioSpi;
11use defmt::*; 12use defmt::*;
12use embassy_executor::Spawner; 13use embassy_executor::Spawner;
@@ -34,7 +35,7 @@ const WIFI_NETWORK: &str = "ssid"; // change to your network SSID
34const WIFI_PASSWORD: &str = "pwd"; // change to your network password 35const WIFI_PASSWORD: &str = "pwd"; // change to your network password
35 36
36#[embassy_executor::task] 37#[embassy_executor::task]
37async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { 38async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
38 runner.run().await 39 runner.run().await
39} 40}
40 41
@@ -67,7 +68,7 @@ async fn main(spawner: Spawner) {
67 static STATE: StaticCell<cyw43::State> = StaticCell::new(); 68 static STATE: StaticCell<cyw43::State> = StaticCell::new();
68 let state = STATE.init(cyw43::State::new()); 69 let state = STATE.init(cyw43::State::new());
69 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; 70 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
70 unwrap!(spawner.spawn(wifi_task(runner))); 71 unwrap!(spawner.spawn(cyw43_task(runner)));
71 72
72 control.init(clm).await; 73 control.init(clm).await;
73 control 74 control
@@ -91,15 +92,17 @@ async fn main(spawner: Spawner) {
91 let stack = &*STACK.init(Stack::new( 92 let stack = &*STACK.init(Stack::new(
92 net_device, 93 net_device,
93 config, 94 config,
94 RESOURCES.init(StackResources::<5>::new()), 95 RESOURCES.init(StackResources::new()),
95 seed, 96 seed,
96 )); 97 ));
97 98
98 unwrap!(spawner.spawn(net_task(stack))); 99 unwrap!(spawner.spawn(net_task(stack)));
99 100
100 loop { 101 loop {
101 //match control.join_open(WIFI_NETWORK).await { // for open networks 102 match control
102 match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await { 103 .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes()))
104 .await
105 {
103 Ok(_) => break, 106 Ok(_) => break,
104 Err(err) => { 107 Err(err) => {
105 info!("join failed with status={}", err.status); 108 info!("join failed with status={}", err.status);
diff --git a/examples/rp23/.cargo/config.toml b/examples/rp23/.cargo/config.toml
new file mode 100644
index 000000000..9a92b1ce2
--- /dev/null
+++ b/examples/rp23/.cargo/config.toml
@@ -0,0 +1,10 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2#runner = "probe-rs run --chip RP2040"
3#runner = "elf2uf2-rs -d"
4runner = "picotool load -u -v -x -t elf"
5
6[build]
7target = "thumbv8m.main-none-eabihf"
8
9[env]
10DEFMT_LOG = "debug"
diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml
new file mode 100644
index 000000000..087f6fd69
--- /dev/null
+++ b/examples/rp23/Cargo.toml
@@ -0,0 +1,79 @@
1[package]
2edition = "2021"
3name = "embassy-rp2350-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7
8[dependencies]
9embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
13embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] }
14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] }
16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
18embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" }
19cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs", "bluetooth"] }
20cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt"] }
21
22defmt = "0.3"
23defmt-rtt = "0.4"
24fixed = "1.23.1"
25fixed-macro = "1.2"
26
27# for web request example
28reqwless = { version = "0.12.0", features = ["defmt",]}
29serde = { version = "1.0.203", default-features = false, features = ["derive"] }
30serde-json-core = "0.5.1"
31
32# for assign resources example
33assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "94ad10e2729afdf0fd5a77cd12e68409a982f58a" }
34
35#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
36cortex-m = { version = "0.7.6", features = ["inline-asm"] }
37cortex-m-rt = "0.7.0"
38critical-section = "1.1"
39panic-probe = { version = "0.3", features = ["print-defmt"] }
40display-interface-spi = "0.4.1"
41embedded-graphics = "0.7.1"
42st7789 = "0.6.1"
43display-interface = "0.4.1"
44byte-slice-cast = { version = "1.2.0", default-features = false }
45smart-leds = "0.3.0"
46heapless = "0.8"
47usbd-hid = "0.8.1"
48
49embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
50embedded-hal-async = "1.0"
51embedded-hal-bus = { version = "0.1", features = ["async"] }
52embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
53embedded-storage = { version = "0.3" }
54static_cell = "2.1"
55portable-atomic = { version = "1.5", features = ["critical-section"] }
56log = "0.4"
57pio-proc = "0.2"
58pio = "0.2.1"
59rand = { version = "0.8.5", default-features = false }
60embedded-sdmmc = "0.7.0"
61
62bt-hci = { version = "0.1.0", default-features = false, features = ["defmt"] }
63trouble-host = { version = "0.1.0", features = ["defmt", "gatt"] }
64
65[profile.release]
66debug = 2
67
68[profile.dev]
69lto = true
70opt-level = "z"
71
72[patch.crates-io]
73trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" }
74embassy-executor = { path = "../../embassy-executor" }
75embassy-sync = { path = "../../embassy-sync" }
76embassy-futures = { path = "../../embassy-futures" }
77embassy-time = { path = "../../embassy-time" }
78embassy-time-driver = { path = "../../embassy-time-driver" }
79embassy-embedded-hal = { path = "../../embassy-embedded-hal" }
diff --git a/examples/rp23/assets/ferris.raw b/examples/rp23/assets/ferris.raw
new file mode 100644
index 000000000..9733889c5
--- /dev/null
+++ b/examples/rp23/assets/ferris.raw
Binary files differ
diff --git a/examples/rp23/build.rs b/examples/rp23/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/rp23/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/rp23/memory.x b/examples/rp23/memory.x
new file mode 100644
index 000000000..777492062
--- /dev/null
+++ b/examples/rp23/memory.x
@@ -0,0 +1,74 @@
1MEMORY {
2 /*
3 * The RP2350 has either external or internal flash.
4 *
5 * 2 MiB is a safe default here, although a Pico 2 has 4 MiB.
6 */
7 FLASH : ORIGIN = 0x10000000, LENGTH = 2048K
8 /*
9 * RAM consists of 8 banks, SRAM0-SRAM7, with a striped mapping.
10 * This is usually good for performance, as it distributes load on
11 * those banks evenly.
12 */
13 RAM : ORIGIN = 0x20000000, LENGTH = 512K
14 /*
15 * RAM banks 8 and 9 use a direct mapping. They can be used to have
16 * memory areas dedicated for some specific job, improving predictability
17 * of access times.
18 * Example: Separate stacks for core0 and core1.
19 */
20 SRAM4 : ORIGIN = 0x20080000, LENGTH = 4K
21 SRAM5 : ORIGIN = 0x20081000, LENGTH = 4K
22}
23
24SECTIONS {
25 /* ### Boot ROM info
26 *
27 * Goes after .vector_table, to keep it in the first 4K of flash
28 * where the Boot ROM (and picotool) can find it
29 */
30 .start_block : ALIGN(4)
31 {
32 __start_block_addr = .;
33 KEEP(*(.start_block));
34 } > FLASH
35
36} INSERT AFTER .vector_table;
37
38/* move .text to start /after/ the boot info */
39_stext = ADDR(.start_block) + SIZEOF(.start_block);
40
41SECTIONS {
42 /* ### Picotool 'Binary Info' Entries
43 *
44 * Picotool looks through this block (as we have pointers to it in our
45 * header) to find interesting information.
46 */
47 .bi_entries : ALIGN(4)
48 {
49 /* We put this in the header */
50 __bi_entries_start = .;
51 /* Here are the entries */
52 KEEP(*(.bi_entries));
53 /* Keep this block a nice round size */
54 . = ALIGN(4);
55 /* We put this in the header */
56 __bi_entries_end = .;
57 } > FLASH
58} INSERT AFTER .text;
59
60SECTIONS {
61 /* ### Boot ROM extra info
62 *
63 * Goes after everything in our program, so it can contain a signature.
64 */
65 .end_block : ALIGN(4)
66 {
67 __end_block_addr = .;
68 KEEP(*(.end_block));
69 } > FLASH
70
71} INSERT AFTER .uninit;
72
73PROVIDE(start_to_end = __end_block_addr - __start_block_addr);
74PROVIDE(end_to_start = __start_block_addr - __end_block_addr);
diff --git a/examples/rp23/src/bin/adc.rs b/examples/rp23/src/bin/adc.rs
new file mode 100644
index 000000000..d1f053d39
--- /dev/null
+++ b/examples/rp23/src/bin/adc.rs
@@ -0,0 +1,63 @@
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
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler};
10use embassy_rp::bind_interrupts;
11use embassy_rp::block::ImageDef;
12use embassy_rp::gpio::Pull;
13use embassy_time::Timer;
14use {defmt_rtt as _, panic_probe as _};
15
16#[link_section = ".start_block"]
17#[used]
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
19
20// Program metadata for `picotool info`
21#[link_section = ".bi_entries"]
22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"example"),
25 embassy_rp::binary_info::rp_cargo_version!(),
26 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
27 embassy_rp::binary_info::rp_program_build_attribute!(),
28];
29
30bind_interrupts!(struct Irqs {
31 ADC_IRQ_FIFO => InterruptHandler;
32});
33
34#[embassy_executor::main]
35async fn main(_spawner: Spawner) {
36 let p = embassy_rp::init(Default::default());
37 let mut adc = Adc::new(p.ADC, Irqs, Config::default());
38
39 let mut p26 = Channel::new_pin(p.PIN_26, Pull::None);
40 let mut p27 = Channel::new_pin(p.PIN_27, Pull::None);
41 let mut p28 = Channel::new_pin(p.PIN_28, Pull::None);
42 let mut ts = Channel::new_temp_sensor(p.ADC_TEMP_SENSOR);
43
44 loop {
45 let level = adc.read(&mut p26).await.unwrap();
46 info!("Pin 26 ADC: {}", level);
47 let level = adc.read(&mut p27).await.unwrap();
48 info!("Pin 27 ADC: {}", level);
49 let level = adc.read(&mut p28).await.unwrap();
50 info!("Pin 28 ADC: {}", level);
51 let temp = adc.read(&mut ts).await.unwrap();
52 info!("Temp: {} degrees", convert_to_celsius(temp));
53 Timer::after_secs(1).await;
54 }
55}
56
57fn convert_to_celsius(raw_temp: u16) -> f32 {
58 // According to chapter 4.9.5. Temperature Sensor in RP2040 datasheet
59 let temp = 27.0 - (raw_temp as f32 * 3.3 / 4096.0 - 0.706) / 0.001721;
60 let sign = if temp < 0.0 { -1.0 } else { 1.0 };
61 let rounded_temp_x10: i16 = ((temp * 10.0) + 0.5 * sign) as i16;
62 (rounded_temp_x10 as f32) / 10.0
63}
diff --git a/examples/rp23/src/bin/adc_dma.rs b/examples/rp23/src/bin/adc_dma.rs
new file mode 100644
index 000000000..5046e5530
--- /dev/null
+++ b/examples/rp23/src/bin/adc_dma.rs
@@ -0,0 +1,69 @@
1//! This example shows how to use the RP2040 ADC with DMA, both single- and multichannel reads.
2//! For multichannel, the samples are interleaved in the buffer:
3//! `[ch1, ch2, ch3, ch4, ch1, ch2, ch3, ch4, ...]`
4#![no_std]
5#![no_main]
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler};
10use embassy_rp::bind_interrupts;
11use embassy_rp::block::ImageDef;
12use embassy_rp::gpio::Pull;
13use embassy_time::{Duration, Ticker};
14use {defmt_rtt as _, panic_probe as _};
15
16#[link_section = ".start_block"]
17#[used]
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
19
20// Program metadata for `picotool info`
21#[link_section = ".bi_entries"]
22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"example"),
25 embassy_rp::binary_info::rp_cargo_version!(),
26 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
27 embassy_rp::binary_info::rp_program_build_attribute!(),
28];
29
30bind_interrupts!(struct Irqs {
31 ADC_IRQ_FIFO => InterruptHandler;
32});
33
34#[embassy_executor::main]
35async fn main(_spawner: Spawner) {
36 let p = embassy_rp::init(Default::default());
37 info!("Here we go!");
38
39 let mut adc = Adc::new(p.ADC, Irqs, Config::default());
40 let mut dma = p.DMA_CH0;
41 let mut pin = Channel::new_pin(p.PIN_26, Pull::Up);
42 let mut pins = [
43 Channel::new_pin(p.PIN_27, Pull::Down),
44 Channel::new_pin(p.PIN_28, Pull::None),
45 Channel::new_pin(p.PIN_29, Pull::Up),
46 Channel::new_temp_sensor(p.ADC_TEMP_SENSOR),
47 ];
48
49 const BLOCK_SIZE: usize = 100;
50 const NUM_CHANNELS: usize = 4;
51 let mut ticker = Ticker::every(Duration::from_secs(1));
52 loop {
53 // Read 100 samples from a single channel
54 let mut buf = [0_u16; BLOCK_SIZE];
55 let div = 479; // 100kHz sample rate (48Mhz / 100kHz - 1)
56 adc.read_many(&mut pin, &mut buf, div, &mut dma).await.unwrap();
57 info!("single: {:?} ...etc", buf[..8]);
58
59 // Read 100 samples from 4 channels interleaved
60 let mut buf = [0_u16; { BLOCK_SIZE * NUM_CHANNELS }];
61 let div = 119; // 100kHz sample rate (48Mhz / 100kHz * 4ch - 1)
62 adc.read_many_multichannel(&mut pins, &mut buf, div, &mut dma)
63 .await
64 .unwrap();
65 info!("multi: {:?} ...etc", buf[..NUM_CHANNELS * 2]);
66
67 ticker.next().await;
68 }
69}
diff --git a/examples/rp23/src/bin/assign_resources.rs b/examples/rp23/src/bin/assign_resources.rs
new file mode 100644
index 000000000..2f9783917
--- /dev/null
+++ b/examples/rp23/src/bin/assign_resources.rs
@@ -0,0 +1,94 @@
1//! This example demonstrates how to assign resources to multiple tasks by splitting up the peripherals.
2//! It is not about sharing the same resources between tasks, see sharing.rs for that or head to https://embassy.dev/book/#_sharing_peripherals_between_tasks)
3//! Of course splitting up resources and sharing resources can be combined, yet this example is only about splitting up resources.
4//!
5//! There are basically two ways we demonstrate here:
6//! 1) Assigning resources to a task by passing parts of the peripherals
7//! 2) Assigning resources to a task by passing a struct with the split up peripherals, using the assign-resources macro
8//!
9//! using four LEDs on Pins 10, 11, 20 and 21
10
11#![no_std]
12#![no_main]
13
14use assign_resources::assign_resources;
15use defmt::*;
16use embassy_executor::Spawner;
17use embassy_rp::block::ImageDef;
18use embassy_rp::gpio::{Level, Output};
19use embassy_rp::peripherals::{self, PIN_20, PIN_21};
20use embassy_time::Timer;
21use {defmt_rtt as _, panic_probe as _};
22
23#[link_section = ".start_block"]
24#[used]
25pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
26
27// Program metadata for `picotool info`
28#[link_section = ".bi_entries"]
29#[used]
30pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
31 embassy_rp::binary_info::rp_program_name!(c"example"),
32 embassy_rp::binary_info::rp_cargo_version!(),
33 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
34 embassy_rp::binary_info::rp_program_build_attribute!(),
35];
36
37#[embassy_executor::main]
38async fn main(spawner: Spawner) {
39 // initialize the peripherals
40 let p = embassy_rp::init(Default::default());
41
42 // 1) Assigning a resource to a task by passing parts of the peripherals.
43 spawner
44 .spawn(double_blinky_manually_assigned(spawner, p.PIN_20, p.PIN_21))
45 .unwrap();
46
47 // 2) Using the assign-resources macro to assign resources to a task.
48 // we perform the split, see further below for the definition of the resources struct
49 let r = split_resources!(p);
50 // and then we can use them
51 spawner.spawn(double_blinky_macro_assigned(spawner, r.leds)).unwrap();
52}
53
54// 1) Assigning a resource to a task by passing parts of the peripherals.
55#[embassy_executor::task]
56async fn double_blinky_manually_assigned(_spawner: Spawner, pin_20: PIN_20, pin_21: PIN_21) {
57 let mut led_20 = Output::new(pin_20, Level::Low);
58 let mut led_21 = Output::new(pin_21, Level::High);
59
60 loop {
61 info!("toggling leds");
62 led_20.toggle();
63 led_21.toggle();
64 Timer::after_secs(1).await;
65 }
66}
67
68// 2) Using the assign-resources macro to assign resources to a task.
69// first we define the resources we want to assign to the task using the assign_resources! macro
70// basically this will split up the peripherals struct into smaller structs, that we define here
71// naming is up to you, make sure your future self understands what you did here
72assign_resources! {
73 leds: Leds{
74 led_10: PIN_10,
75 led_11: PIN_11,
76 }
77 // add more resources to more structs if needed, for example defining one struct for each task
78}
79// this could be done in another file and imported here, but for the sake of simplicity we do it here
80// see https://github.com/adamgreig/assign-resources for more information
81
82// 2) Using the split resources in a task
83#[embassy_executor::task]
84async fn double_blinky_macro_assigned(_spawner: Spawner, r: Leds) {
85 let mut led_10 = Output::new(r.led_10, Level::Low);
86 let mut led_11 = Output::new(r.led_11, Level::High);
87
88 loop {
89 info!("toggling leds");
90 led_10.toggle();
91 led_11.toggle();
92 Timer::after_secs(1).await;
93 }
94}
diff --git a/examples/rp23/src/bin/blinky.rs b/examples/rp23/src/bin/blinky.rs
new file mode 100644
index 000000000..9e45679c8
--- /dev/null
+++ b/examples/rp23/src/bin/blinky.rs
@@ -0,0 +1,44 @@
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
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::gpio;
12use embassy_time::Timer;
13use gpio::{Level, Output};
14use {defmt_rtt as _, panic_probe as _};
15
16#[link_section = ".start_block"]
17#[used]
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
19
20// Program metadata for `picotool info`
21#[link_section = ".bi_entries"]
22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"example"),
25 embassy_rp::binary_info::rp_cargo_version!(),
26 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
27 embassy_rp::binary_info::rp_program_build_attribute!(),
28];
29
30#[embassy_executor::main]
31async fn main(_spawner: Spawner) {
32 let p = embassy_rp::init(Default::default());
33 let mut led = Output::new(p.PIN_2, Level::Low);
34
35 loop {
36 info!("led on!");
37 led.set_high();
38 Timer::after_millis(250).await;
39
40 info!("led off!");
41 led.set_low();
42 Timer::after_millis(250).await;
43 }
44}
diff --git a/examples/rp23/src/bin/blinky_two_channels.rs b/examples/rp23/src/bin/blinky_two_channels.rs
new file mode 100644
index 000000000..87fc58bbc
--- /dev/null
+++ b/examples/rp23/src/bin/blinky_two_channels.rs
@@ -0,0 +1,65 @@
1#![no_std]
2#![no_main]
3/// This example demonstrates how to access a given pin from more than one embassy task
4/// The on-board LED is toggled by two tasks with slightly different periods, leading to the
5/// apparent duty cycle of the LED increasing, then decreasing, linearly. The phenomenon is similar
6/// to interference and the 'beats' you can hear if you play two frequencies close to one another
7/// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats)
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::gpio;
12use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
13use embassy_sync::channel::{Channel, Sender};
14use embassy_time::{Duration, Ticker};
15use gpio::{AnyPin, Level, Output};
16use {defmt_rtt as _, panic_probe as _};
17
18#[link_section = ".start_block"]
19#[used]
20pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
21
22// Program metadata for `picotool info`
23#[link_section = ".bi_entries"]
24#[used]
25pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
26 embassy_rp::binary_info::rp_program_name!(c"example"),
27 embassy_rp::binary_info::rp_cargo_version!(),
28 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
29 embassy_rp::binary_info::rp_program_build_attribute!(),
30];
31
32enum LedState {
33 Toggle,
34}
35static CHANNEL: Channel<ThreadModeRawMutex, LedState, 64> = Channel::new();
36
37#[embassy_executor::main]
38async fn main(spawner: Spawner) {
39 let p = embassy_rp::init(Default::default());
40 let mut led = Output::new(AnyPin::from(p.PIN_25), Level::High);
41
42 let dt = 100 * 1_000_000;
43 let k = 1.003;
44
45 unwrap!(spawner.spawn(toggle_led(CHANNEL.sender(), Duration::from_nanos(dt))));
46 unwrap!(spawner.spawn(toggle_led(
47 CHANNEL.sender(),
48 Duration::from_nanos((dt as f64 * k) as u64)
49 )));
50
51 loop {
52 match CHANNEL.receive().await {
53 LedState::Toggle => led.toggle(),
54 }
55 }
56}
57
58#[embassy_executor::task(pool_size = 2)]
59async fn toggle_led(control: Sender<'static, ThreadModeRawMutex, LedState, 64>, delay: Duration) {
60 let mut ticker = Ticker::every(delay);
61 loop {
62 control.send(LedState::Toggle).await;
63 ticker.next().await;
64 }
65}
diff --git a/examples/rp23/src/bin/blinky_two_tasks.rs b/examples/rp23/src/bin/blinky_two_tasks.rs
new file mode 100644
index 000000000..40236c53b
--- /dev/null
+++ b/examples/rp23/src/bin/blinky_two_tasks.rs
@@ -0,0 +1,64 @@
1#![no_std]
2#![no_main]
3/// This example demonstrates how to access a given pin from more than one embassy task
4/// The on-board LED is toggled by two tasks with slightly different periods, leading to the
5/// apparent duty cycle of the LED increasing, then decreasing, linearly. The phenomenon is similar
6/// to interference and the 'beats' you can hear if you play two frequencies close to one another
7/// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats)
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::gpio;
12use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
13use embassy_sync::mutex::Mutex;
14use embassy_time::{Duration, Ticker};
15use gpio::{AnyPin, Level, Output};
16use {defmt_rtt as _, panic_probe as _};
17
18#[link_section = ".start_block"]
19#[used]
20pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
21
22// Program metadata for `picotool info`
23#[link_section = ".bi_entries"]
24#[used]
25pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
26 embassy_rp::binary_info::rp_program_name!(c"example"),
27 embassy_rp::binary_info::rp_cargo_version!(),
28 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
29 embassy_rp::binary_info::rp_program_build_attribute!(),
30];
31
32type LedType = Mutex<ThreadModeRawMutex, Option<Output<'static>>>;
33static LED: LedType = Mutex::new(None);
34
35#[embassy_executor::main]
36async fn main(spawner: Spawner) {
37 let p = embassy_rp::init(Default::default());
38 // set the content of the global LED reference to the real LED pin
39 let led = Output::new(AnyPin::from(p.PIN_25), Level::High);
40 // inner scope is so that once the mutex is written to, the MutexGuard is dropped, thus the
41 // Mutex is released
42 {
43 *(LED.lock().await) = Some(led);
44 }
45 let dt = 100 * 1_000_000;
46 let k = 1.003;
47
48 unwrap!(spawner.spawn(toggle_led(&LED, Duration::from_nanos(dt))));
49 unwrap!(spawner.spawn(toggle_led(&LED, Duration::from_nanos((dt as f64 * k) as u64))));
50}
51
52#[embassy_executor::task(pool_size = 2)]
53async fn toggle_led(led: &'static LedType, delay: Duration) {
54 let mut ticker = Ticker::every(delay);
55 loop {
56 {
57 let mut led_unlocked = led.lock().await;
58 if let Some(pin_ref) = led_unlocked.as_mut() {
59 pin_ref.toggle();
60 }
61 }
62 ticker.next().await;
63 }
64}
diff --git a/examples/rp23/src/bin/button.rs b/examples/rp23/src/bin/button.rs
new file mode 100644
index 000000000..fb067a370
--- /dev/null
+++ b/examples/rp23/src/bin/button.rs
@@ -0,0 +1,43 @@
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
5#![no_std]
6#![no_main]
7
8use embassy_executor::Spawner;
9use embassy_rp::block::ImageDef;
10use embassy_rp::gpio::{Input, Level, Output, Pull};
11use {defmt_rtt as _, panic_probe as _};
12
13#[link_section = ".start_block"]
14#[used]
15pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
16
17// Program metadata for `picotool info`
18#[link_section = ".bi_entries"]
19#[used]
20pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
21 embassy_rp::binary_info::rp_program_name!(c"example"),
22 embassy_rp::binary_info::rp_cargo_version!(),
23 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
24 embassy_rp::binary_info::rp_program_build_attribute!(),
25];
26
27#[embassy_executor::main]
28async fn main(_spawner: Spawner) {
29 let p = embassy_rp::init(Default::default());
30 let mut led = Output::new(p.PIN_25, Level::Low);
31
32 // Use PIN_28, Pin34 on J0 for RP Pico, as a input.
33 // You need to add your own button.
34 let button = Input::new(p.PIN_28, Pull::Up);
35
36 loop {
37 if button.is_high() {
38 led.set_high();
39 } else {
40 led.set_low();
41 }
42 }
43}
diff --git a/examples/rp23/src/bin/debounce.rs b/examples/rp23/src/bin/debounce.rs
new file mode 100644
index 000000000..e672521ec
--- /dev/null
+++ b/examples/rp23/src/bin/debounce.rs
@@ -0,0 +1,95 @@
1//! This example shows the ease of debouncing a button with async rust.
2//! Hook up a button or switch between pin 9 and ground.
3
4#![no_std]
5#![no_main]
6
7use defmt::info;
8use embassy_executor::Spawner;
9use embassy_rp::block::ImageDef;
10use embassy_rp::gpio::{Input, Level, Pull};
11use embassy_time::{with_deadline, Duration, Instant, Timer};
12use {defmt_rtt as _, panic_probe as _};
13
14#[link_section = ".start_block"]
15#[used]
16pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
17
18// Program metadata for `picotool info`
19#[link_section = ".bi_entries"]
20#[used]
21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
22 embassy_rp::binary_info::rp_program_name!(c"example"),
23 embassy_rp::binary_info::rp_cargo_version!(),
24 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
25 embassy_rp::binary_info::rp_program_build_attribute!(),
26];
27
28pub struct Debouncer<'a> {
29 input: Input<'a>,
30 debounce: Duration,
31}
32
33impl<'a> Debouncer<'a> {
34 pub fn new(input: Input<'a>, debounce: Duration) -> Self {
35 Self { input, debounce }
36 }
37
38 pub async fn debounce(&mut self) -> Level {
39 loop {
40 let l1 = self.input.get_level();
41
42 self.input.wait_for_any_edge().await;
43
44 Timer::after(self.debounce).await;
45
46 let l2 = self.input.get_level();
47 if l1 != l2 {
48 break l2;
49 }
50 }
51 }
52}
53
54#[embassy_executor::main]
55async fn main(_spawner: Spawner) {
56 let p = embassy_rp::init(Default::default());
57 let mut btn = Debouncer::new(Input::new(p.PIN_9, Pull::Up), Duration::from_millis(20));
58
59 info!("Debounce Demo");
60
61 loop {
62 // button pressed
63 btn.debounce().await;
64 let start = Instant::now();
65 info!("Button Press");
66
67 match with_deadline(start + Duration::from_secs(1), btn.debounce()).await {
68 // Button Released < 1s
69 Ok(_) => {
70 info!("Button pressed for: {}ms", start.elapsed().as_millis());
71 continue;
72 }
73 // button held for > 1s
74 Err(_) => {
75 info!("Button Held");
76 }
77 }
78
79 match with_deadline(start + Duration::from_secs(5), btn.debounce()).await {
80 // Button released <5s
81 Ok(_) => {
82 info!("Button pressed for: {}ms", start.elapsed().as_millis());
83 continue;
84 }
85 // button held for > >5s
86 Err(_) => {
87 info!("Button Long Held");
88 }
89 }
90
91 // wait for button release before handling another press
92 btn.debounce().await;
93 info!("Button pressed for: {}ms", start.elapsed().as_millis());
94 }
95}
diff --git a/examples/rp23/src/bin/flash.rs b/examples/rp23/src/bin/flash.rs
new file mode 100644
index 000000000..84011e394
--- /dev/null
+++ b/examples/rp23/src/bin/flash.rs
@@ -0,0 +1,140 @@
1//! This example test the flash connected to the RP2040 chip.
2
3#![no_std]
4#![no_main]
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_rp::block::ImageDef;
9use embassy_rp::flash::{Async, ERASE_SIZE, FLASH_BASE};
10use embassy_rp::peripherals::FLASH;
11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _};
13
14#[link_section = ".start_block"]
15#[used]
16pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
17
18// Program metadata for `picotool info`
19#[link_section = ".bi_entries"]
20#[used]
21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
22 embassy_rp::binary_info::rp_program_name!(c"example"),
23 embassy_rp::binary_info::rp_cargo_version!(),
24 embassy_rp::binary_info::rp_program_description!(c"Flash"),
25 embassy_rp::binary_info::rp_program_build_attribute!(),
26];
27
28const ADDR_OFFSET: u32 = 0x100000;
29const FLASH_SIZE: usize = 2 * 1024 * 1024;
30
31#[embassy_executor::main]
32async fn main(_spawner: Spawner) {
33 let p = embassy_rp::init(Default::default());
34 info!("Hello World!");
35
36 // add some delay to give an attached debug probe time to parse the
37 // defmt RTT header. Reading that header might touch flash memory, which
38 // interferes with flash write operations.
39 // https://github.com/knurling-rs/defmt/pull/683
40 Timer::after_millis(10).await;
41
42 let mut flash = embassy_rp::flash::Flash::<_, Async, FLASH_SIZE>::new(p.FLASH, p.DMA_CH0);
43
44 erase_write_sector(&mut flash, 0x00);
45
46 multiwrite_bytes(&mut flash, ERASE_SIZE as u32);
47
48 background_read(&mut flash, (ERASE_SIZE * 2) as u32).await;
49
50 info!("Flash Works!");
51}
52
53fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) {
54 info!(">>>> [multiwrite_bytes]");
55 let mut read_buf = [0u8; ERASE_SIZE];
56 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf));
57
58 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
59 info!("Contents start with {=[u8]}", read_buf[0..4]);
60
61 defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
62
63 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf));
64 info!("Contents after erase starts with {=[u8]}", read_buf[0..4]);
65 if read_buf.iter().any(|x| *x != 0xFF) {
66 defmt::panic!("unexpected");
67 }
68
69 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, &[0x01]));
70 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 1, &[0x02]));
71 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 2, &[0x03]));
72 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset + 3, &[0x04]));
73
74 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf));
75 info!("Contents after write starts with {=[u8]}", read_buf[0..4]);
76 if read_buf[0..4] != [0x01, 0x02, 0x03, 0x04] {
77 defmt::panic!("unexpected");
78 }
79}
80
81fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) {
82 info!(">>>> [erase_write_sector]");
83 let mut buf = [0u8; ERASE_SIZE];
84 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf));
85
86 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
87 info!("Contents start with {=[u8]}", buf[0..4]);
88
89 defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
90
91 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf));
92 info!("Contents after erase starts with {=[u8]}", buf[0..4]);
93 if buf.iter().any(|x| *x != 0xFF) {
94 defmt::panic!("unexpected");
95 }
96
97 for b in buf.iter_mut() {
98 *b = 0xDA;
99 }
100
101 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, &buf));
102
103 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut buf));
104 info!("Contents after write starts with {=[u8]}", buf[0..4]);
105 if buf.iter().any(|x| *x != 0xDA) {
106 defmt::panic!("unexpected");
107 }
108}
109
110async fn background_read(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) {
111 info!(">>>> [background_read]");
112
113 let mut buf = [0u32; 8];
114 defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await;
115
116 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
117 info!("Contents start with {=u32:x}", buf[0]);
118
119 defmt::unwrap!(flash.blocking_erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
120
121 defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await;
122 info!("Contents after erase starts with {=u32:x}", buf[0]);
123 if buf.iter().any(|x| *x != 0xFFFFFFFF) {
124 defmt::panic!("unexpected");
125 }
126
127 for b in buf.iter_mut() {
128 *b = 0xDABA1234;
129 }
130
131 defmt::unwrap!(flash.blocking_write(ADDR_OFFSET + offset, unsafe {
132 core::slice::from_raw_parts(buf.as_ptr() as *const u8, buf.len() * 4)
133 }));
134
135 defmt::unwrap!(flash.background_read(ADDR_OFFSET + offset, &mut buf)).await;
136 info!("Contents after write starts with {=u32:x}", buf[0]);
137 if buf.iter().any(|x| *x != 0xDABA1234) {
138 defmt::panic!("unexpected");
139 }
140}
diff --git a/examples/rp23/src/bin/gpio_async.rs b/examples/rp23/src/bin/gpio_async.rs
new file mode 100644
index 000000000..ff12367bf
--- /dev/null
+++ b/examples/rp23/src/bin/gpio_async.rs
@@ -0,0 +1,55 @@
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
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::gpio;
12use embassy_time::Timer;
13use gpio::{Input, Level, Output, Pull};
14use {defmt_rtt as _, panic_probe as _};
15
16#[link_section = ".start_block"]
17#[used]
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
19
20// Program metadata for `picotool info`
21#[link_section = ".bi_entries"]
22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"example"),
25 embassy_rp::binary_info::rp_cargo_version!(),
26 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
27 embassy_rp::binary_info::rp_program_build_attribute!(),
28];
29
30/// It requires an external signal to be manually triggered on PIN 16. For
31/// example, this could be accomplished using an external power source with a
32/// button so that it is possible to toggle the signal from low to high.
33///
34/// This example will begin with turning on the LED on the board and wait for a
35/// high signal on PIN 16. Once the high event/signal occurs the program will
36/// continue and turn off the LED, and then wait for 2 seconds before completing
37/// the loop and starting over again.
38#[embassy_executor::main]
39async fn main(_spawner: Spawner) {
40 let p = embassy_rp::init(Default::default());
41 let mut led = Output::new(p.PIN_25, Level::Low);
42 let mut async_input = Input::new(p.PIN_16, Pull::None);
43
44 loop {
45 info!("wait_for_high. Turn on LED");
46 led.set_high();
47
48 async_input.wait_for_high().await;
49
50 info!("done wait_for_high. Turn off LED");
51 led.set_low();
52
53 Timer::after_secs(2).await;
54 }
55}
diff --git a/examples/rp23/src/bin/gpout.rs b/examples/rp23/src/bin/gpout.rs
new file mode 100644
index 000000000..d2ee55197
--- /dev/null
+++ b/examples/rp23/src/bin/gpout.rs
@@ -0,0 +1,52 @@
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
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::clocks;
12use embassy_time::Timer;
13use {defmt_rtt as _, panic_probe as _};
14
15#[link_section = ".start_block"]
16#[used]
17pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
18
19// Program metadata for `picotool info`
20#[link_section = ".bi_entries"]
21#[used]
22pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
23 embassy_rp::binary_info::rp_program_name!(c"example"),
24 embassy_rp::binary_info::rp_cargo_version!(),
25 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
26 embassy_rp::binary_info::rp_program_build_attribute!(),
27];
28
29#[embassy_executor::main]
30async fn main(_spawner: Spawner) {
31 let p = embassy_rp::init(Default::default());
32
33 let gpout3 = clocks::Gpout::new(p.PIN_25);
34 gpout3.set_div(1000, 0);
35 gpout3.enable();
36
37 loop {
38 gpout3.set_src(clocks::GpoutSrc::Sys);
39 info!(
40 "Pin 25 is now outputing CLK_SYS/1000, should be toggling at {}",
41 gpout3.get_freq()
42 );
43 Timer::after_secs(2).await;
44
45 gpout3.set_src(clocks::GpoutSrc::Ref);
46 info!(
47 "Pin 25 is now outputing CLK_REF/1000, should be toggling at {}",
48 gpout3.get_freq()
49 );
50 Timer::after_secs(2).await;
51 }
52}
diff --git a/examples/rp23/src/bin/i2c_async.rs b/examples/rp23/src/bin/i2c_async.rs
new file mode 100644
index 000000000..c8d918b56
--- /dev/null
+++ b/examples/rp23/src/bin/i2c_async.rs
@@ -0,0 +1,125 @@
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
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_rp::bind_interrupts;
12use embassy_rp::block::ImageDef;
13use embassy_rp::i2c::{self, Config, InterruptHandler};
14use embassy_rp::peripherals::I2C1;
15use embassy_time::Timer;
16use embedded_hal_async::i2c::I2c;
17use {defmt_rtt as _, panic_probe as _};
18
19#[link_section = ".start_block"]
20#[used]
21pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
22
23// Program metadata for `picotool info`
24#[link_section = ".bi_entries"]
25#[used]
26pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
27 embassy_rp::binary_info::rp_program_name!(c"example"),
28 embassy_rp::binary_info::rp_cargo_version!(),
29 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
30 embassy_rp::binary_info::rp_program_build_attribute!(),
31];
32
33bind_interrupts!(struct Irqs {
34 I2C1_IRQ => InterruptHandler<I2C1>;
35});
36
37#[allow(dead_code)]
38mod mcp23017 {
39 pub const ADDR: u8 = 0x20; // default addr
40
41 macro_rules! mcpregs {
42 ($($name:ident : $val:expr),* $(,)?) => {
43 $(
44 pub const $name: u8 = $val;
45 )*
46
47 pub fn regname(reg: u8) -> &'static str {
48 match reg {
49 $(
50 $val => stringify!($name),
51 )*
52 _ => panic!("bad reg"),
53 }
54 }
55 }
56 }
57
58 // These are correct for IOCON.BANK=0
59 mcpregs! {
60 IODIRA: 0x00,
61 IPOLA: 0x02,
62 GPINTENA: 0x04,
63 DEFVALA: 0x06,
64 INTCONA: 0x08,
65 IOCONA: 0x0A,
66 GPPUA: 0x0C,
67 INTFA: 0x0E,
68 INTCAPA: 0x10,
69 GPIOA: 0x12,
70 OLATA: 0x14,
71 IODIRB: 0x01,
72 IPOLB: 0x03,
73 GPINTENB: 0x05,
74 DEFVALB: 0x07,
75 INTCONB: 0x09,
76 IOCONB: 0x0B,
77 GPPUB: 0x0D,
78 INTFB: 0x0F,
79 INTCAPB: 0x11,
80 GPIOB: 0x13,
81 OLATB: 0x15,
82 }
83}
84
85#[embassy_executor::main]
86async fn main(_spawner: Spawner) {
87 let p = embassy_rp::init(Default::default());
88
89 let sda = p.PIN_14;
90 let scl = p.PIN_15;
91
92 info!("set up i2c ");
93 let mut i2c = i2c::I2c::new_async(p.I2C1, scl, sda, Irqs, Config::default());
94
95 use mcp23017::*;
96
97 info!("init mcp23017 config for IxpandO");
98 // init - a outputs, b inputs
99 i2c.write(ADDR, &[IODIRA, 0x00]).await.unwrap();
100 i2c.write(ADDR, &[IODIRB, 0xff]).await.unwrap();
101 i2c.write(ADDR, &[GPPUB, 0xff]).await.unwrap(); // pullups
102
103 let mut val = 1;
104 loop {
105 let mut portb = [0];
106
107 i2c.write_read(mcp23017::ADDR, &[GPIOB], &mut portb).await.unwrap();
108 info!("portb = {:02x}", portb[0]);
109 i2c.write(mcp23017::ADDR, &[GPIOA, val | portb[0]]).await.unwrap();
110 val = val.rotate_left(1);
111
112 // get a register dump
113 info!("getting register dump");
114 let mut regs = [0; 22];
115 i2c.write_read(ADDR, &[0], &mut regs).await.unwrap();
116 // always get the regdump but only display it if portb'0 is set
117 if portb[0] & 1 != 0 {
118 for (idx, reg) in regs.into_iter().enumerate() {
119 info!("{} => {:02x}", regname(idx as u8), reg);
120 }
121 }
122
123 Timer::after_millis(100).await;
124 }
125}
diff --git a/examples/rp23/src/bin/i2c_async_embassy.rs b/examples/rp23/src/bin/i2c_async_embassy.rs
new file mode 100644
index 000000000..cce0abcde
--- /dev/null
+++ b/examples/rp23/src/bin/i2c_async_embassy.rs
@@ -0,0 +1,100 @@
1//! This example shows how to communicate asynchronous using i2c with external chip.
2//!
3//! It's using embassy's functions directly instead of traits from embedded_hal_async::i2c::I2c.
4//! While most of i2c devices are addressed using 7 bits, an extension allows 10 bits too.
5
6#![no_std]
7#![no_main]
8
9use defmt::*;
10use embassy_rp::block::ImageDef;
11use embassy_rp::i2c::InterruptHandler;
12use {defmt_rtt as _, panic_probe as _};
13
14#[link_section = ".start_block"]
15#[used]
16pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
17
18// Program metadata for `picotool info`
19#[link_section = ".bi_entries"]
20#[used]
21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
22 embassy_rp::binary_info::rp_program_name!(c"example"),
23 embassy_rp::binary_info::rp_cargo_version!(),
24 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
25 embassy_rp::binary_info::rp_program_build_attribute!(),
26];
27
28// Our anonymous hypotetical temperature sensor could be:
29// a 12-bit sensor, with 100ms startup time, range of -40*C - 125*C, and precision 0.25*C
30// It requires no configuration or calibration, works with all i2c bus speeds,
31// never stretches clock or does anything complicated. Replies with one u16.
32// It requires only one write to take it out of suspend mode, and stays on.
33// Often result would be just on 12 bits, but here we'll simplify it to 16.
34
35enum UncomplicatedSensorId {
36 A(UncomplicatedSensorU8),
37 B(UncomplicatedSensorU16),
38}
39enum UncomplicatedSensorU8 {
40 First = 0x48,
41}
42enum UncomplicatedSensorU16 {
43 Other = 0x0049,
44}
45
46impl Into<u16> for UncomplicatedSensorU16 {
47 fn into(self) -> u16 {
48 self as u16
49 }
50}
51impl Into<u16> for UncomplicatedSensorU8 {
52 fn into(self) -> u16 {
53 0x48
54 }
55}
56impl From<UncomplicatedSensorId> for u16 {
57 fn from(t: UncomplicatedSensorId) -> Self {
58 match t {
59 UncomplicatedSensorId::A(x) => x.into(),
60 UncomplicatedSensorId::B(x) => x.into(),
61 }
62 }
63}
64
65embassy_rp::bind_interrupts!(struct Irqs {
66 I2C1_IRQ => InterruptHandler<embassy_rp::peripherals::I2C1>;
67});
68
69#[embassy_executor::main]
70async fn main(_task_spawner: embassy_executor::Spawner) {
71 let p = embassy_rp::init(Default::default());
72 let sda = p.PIN_14;
73 let scl = p.PIN_15;
74 let config = embassy_rp::i2c::Config::default();
75 let mut bus = embassy_rp::i2c::I2c::new_async(p.I2C1, scl, sda, Irqs, config);
76
77 const WAKEYWAKEY: u16 = 0xBABE;
78 let mut result: [u8; 2] = [0, 0];
79 // wait for sensors to initialize
80 embassy_time::Timer::after(embassy_time::Duration::from_millis(100)).await;
81
82 let _res_1 = bus
83 .write_async(UncomplicatedSensorU8::First, WAKEYWAKEY.to_be_bytes())
84 .await;
85 let _res_2 = bus
86 .write_async(UncomplicatedSensorU16::Other, WAKEYWAKEY.to_be_bytes())
87 .await;
88
89 loop {
90 let s1 = UncomplicatedSensorId::A(UncomplicatedSensorU8::First);
91 let s2 = UncomplicatedSensorId::B(UncomplicatedSensorU16::Other);
92 let sensors = [s1, s2];
93 for sensor in sensors {
94 if bus.read_async(sensor, &mut result).await.is_ok() {
95 info!("Result {}", u16::from_be_bytes(result.into()));
96 }
97 }
98 embassy_time::Timer::after(embassy_time::Duration::from_millis(200)).await;
99 }
100}
diff --git a/examples/rp23/src/bin/i2c_blocking.rs b/examples/rp23/src/bin/i2c_blocking.rs
new file mode 100644
index 000000000..85c33bf0d
--- /dev/null
+++ b/examples/rp23/src/bin/i2c_blocking.rs
@@ -0,0 +1,89 @@
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
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_rp::block::ImageDef;
12use embassy_rp::i2c::{self, Config};
13use embassy_time::Timer;
14use embedded_hal_1::i2c::I2c;
15use {defmt_rtt as _, panic_probe as _};
16
17#[link_section = ".start_block"]
18#[used]
19pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
20
21// Program metadata for `picotool info`
22#[link_section = ".bi_entries"]
23#[used]
24pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
25 embassy_rp::binary_info::rp_program_name!(c"example"),
26 embassy_rp::binary_info::rp_cargo_version!(),
27 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
28 embassy_rp::binary_info::rp_program_build_attribute!(),
29];
30
31#[allow(dead_code)]
32mod mcp23017 {
33 pub const ADDR: u8 = 0x20; // default addr
34
35 pub const IODIRA: u8 = 0x00;
36 pub const IPOLA: u8 = 0x02;
37 pub const GPINTENA: u8 = 0x04;
38 pub const DEFVALA: u8 = 0x06;
39 pub const INTCONA: u8 = 0x08;
40 pub const IOCONA: u8 = 0x0A;
41 pub const GPPUA: u8 = 0x0C;
42 pub const INTFA: u8 = 0x0E;
43 pub const INTCAPA: u8 = 0x10;
44 pub const GPIOA: u8 = 0x12;
45 pub const OLATA: u8 = 0x14;
46 pub const IODIRB: u8 = 0x01;
47 pub const IPOLB: u8 = 0x03;
48 pub const GPINTENB: u8 = 0x05;
49 pub const DEFVALB: u8 = 0x07;
50 pub const INTCONB: u8 = 0x09;
51 pub const IOCONB: u8 = 0x0B;
52 pub const GPPUB: u8 = 0x0D;
53 pub const INTFB: u8 = 0x0F;
54 pub const INTCAPB: u8 = 0x11;
55 pub const GPIOB: u8 = 0x13;
56 pub const OLATB: u8 = 0x15;
57}
58
59#[embassy_executor::main]
60async fn main(_spawner: Spawner) {
61 let p = embassy_rp::init(Default::default());
62
63 let sda = p.PIN_14;
64 let scl = p.PIN_15;
65
66 info!("set up i2c ");
67 let mut i2c = i2c::I2c::new_blocking(p.I2C1, scl, sda, Config::default());
68
69 use mcp23017::*;
70
71 info!("init mcp23017 config for IxpandO");
72 // init - a outputs, b inputs
73 i2c.write(ADDR, &[IODIRA, 0x00]).unwrap();
74 i2c.write(ADDR, &[IODIRB, 0xff]).unwrap();
75 i2c.write(ADDR, &[GPPUB, 0xff]).unwrap(); // pullups
76
77 let mut val = 0xaa;
78 loop {
79 let mut portb = [0];
80
81 i2c.write(mcp23017::ADDR, &[GPIOA, val]).unwrap();
82 i2c.write_read(mcp23017::ADDR, &[GPIOB], &mut portb).unwrap();
83
84 info!("portb = {:02x}", portb[0]);
85 val = !val;
86
87 Timer::after_secs(1).await;
88 }
89}
diff --git a/examples/rp23/src/bin/i2c_slave.rs b/examples/rp23/src/bin/i2c_slave.rs
new file mode 100644
index 000000000..fb5f3cda1
--- /dev/null
+++ b/examples/rp23/src/bin/i2c_slave.rs
@@ -0,0 +1,132 @@
1//! This example shows how to use the 2040 as an i2c slave.
2#![no_std]
3#![no_main]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_rp::block::ImageDef;
8use embassy_rp::peripherals::{I2C0, I2C1};
9use embassy_rp::{bind_interrupts, i2c, i2c_slave};
10use embassy_time::Timer;
11use embedded_hal_async::i2c::I2c;
12use {defmt_rtt as _, panic_probe as _};
13
14#[link_section = ".start_block"]
15#[used]
16pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
17
18// Program metadata for `picotool info`
19#[link_section = ".bi_entries"]
20#[used]
21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
22 embassy_rp::binary_info::rp_program_name!(c"example"),
23 embassy_rp::binary_info::rp_cargo_version!(),
24 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
25 embassy_rp::binary_info::rp_program_build_attribute!(),
26];
27
28bind_interrupts!(struct Irqs {
29 I2C0_IRQ => i2c::InterruptHandler<I2C0>;
30 I2C1_IRQ => i2c::InterruptHandler<I2C1>;
31});
32
33const DEV_ADDR: u8 = 0x42;
34
35#[embassy_executor::task]
36async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
37 info!("Device start");
38
39 let mut state = 0;
40
41 loop {
42 let mut buf = [0u8; 128];
43 match dev.listen(&mut buf).await {
44 Ok(i2c_slave::Command::GeneralCall(len)) => info!("Device received general call write: {}", buf[..len]),
45 Ok(i2c_slave::Command::Read) => loop {
46 match dev.respond_to_read(&[state]).await {
47 Ok(x) => match x {
48 i2c_slave::ReadStatus::Done => break,
49 i2c_slave::ReadStatus::NeedMoreBytes => (),
50 i2c_slave::ReadStatus::LeftoverBytes(x) => {
51 info!("tried to write {} extra bytes", x);
52 break;
53 }
54 },
55 Err(e) => error!("error while responding {}", e),
56 }
57 },
58 Ok(i2c_slave::Command::Write(len)) => info!("Device received write: {}", buf[..len]),
59 Ok(i2c_slave::Command::WriteRead(len)) => {
60 info!("device received write read: {:x}", buf[..len]);
61 match buf[0] {
62 // Set the state
63 0xC2 => {
64 state = buf[1];
65 match dev.respond_and_fill(&[state], 0x00).await {
66 Ok(read_status) => info!("response read status {}", read_status),
67 Err(e) => error!("error while responding {}", e),
68 }
69 }
70 // Reset State
71 0xC8 => {
72 state = 0;
73 match dev.respond_and_fill(&[state], 0x00).await {
74 Ok(read_status) => info!("response read status {}", read_status),
75 Err(e) => error!("error while responding {}", e),
76 }
77 }
78 x => error!("Invalid Write Read {:x}", x),
79 }
80 }
81 Err(e) => error!("{}", e),
82 }
83 }
84}
85
86#[embassy_executor::task]
87async fn controller_task(mut con: i2c::I2c<'static, I2C0, i2c::Async>) {
88 info!("Controller start");
89
90 loop {
91 let mut resp_buff = [0u8; 2];
92 for i in 0..10 {
93 match con.write_read(DEV_ADDR, &[0xC2, i], &mut resp_buff).await {
94 Ok(_) => info!("write_read response: {}", resp_buff),
95 Err(e) => error!("Error writing {}", e),
96 }
97
98 Timer::after_millis(100).await;
99 }
100 match con.read(DEV_ADDR, &mut resp_buff).await {
101 Ok(_) => info!("read response: {}", resp_buff),
102 Err(e) => error!("Error writing {}", e),
103 }
104 match con.write_read(DEV_ADDR, &[0xC8], &mut resp_buff).await {
105 Ok(_) => info!("write_read response: {}", resp_buff),
106 Err(e) => error!("Error writing {}", e),
107 }
108 Timer::after_millis(100).await;
109 }
110}
111
112#[embassy_executor::main]
113async fn main(spawner: Spawner) {
114 let p = embassy_rp::init(Default::default());
115 info!("Hello World!");
116
117 let d_sda = p.PIN_3;
118 let d_scl = p.PIN_2;
119 let mut config = i2c_slave::Config::default();
120 config.addr = DEV_ADDR as u16;
121 let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config);
122
123 unwrap!(spawner.spawn(device_task(device)));
124
125 let c_sda = p.PIN_1;
126 let c_scl = p.PIN_0;
127 let mut config = i2c::Config::default();
128 config.frequency = 1_000_000;
129 let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config);
130
131 unwrap!(spawner.spawn(controller_task(controller)));
132}
diff --git a/examples/rp23/src/bin/interrupt.rs b/examples/rp23/src/bin/interrupt.rs
new file mode 100644
index 000000000..ee3d9bfe7
--- /dev/null
+++ b/examples/rp23/src/bin/interrupt.rs
@@ -0,0 +1,109 @@
1//! This example shows how you can use raw interrupt handlers alongside embassy.
2//! The example also showcases some of the options available for sharing resources/data.
3//!
4//! In the example, an ADC reading is triggered every time the PWM wraps around.
5//! The sample data is sent down a channel, to be processed inside a low priority task.
6//! The processed data is then used to adjust the PWM duty cycle, once every second.
7
8#![no_std]
9#![no_main]
10
11use core::cell::{Cell, RefCell};
12
13use defmt::*;
14use embassy_executor::Spawner;
15use embassy_rp::adc::{self, Adc, Blocking};
16use embassy_rp::block::ImageDef;
17use embassy_rp::gpio::Pull;
18use embassy_rp::interrupt;
19use embassy_rp::pwm::{Config, Pwm};
20use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
21use embassy_sync::blocking_mutex::Mutex;
22use embassy_sync::channel::Channel;
23use embassy_time::{Duration, Ticker};
24use portable_atomic::{AtomicU32, Ordering};
25use static_cell::StaticCell;
26use {defmt_rtt as _, panic_probe as _};
27
28#[link_section = ".start_block"]
29#[used]
30pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
31
32// Program metadata for `picotool info`
33#[link_section = ".bi_entries"]
34#[used]
35pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
36 embassy_rp::binary_info::rp_program_name!(c"example"),
37 embassy_rp::binary_info::rp_cargo_version!(),
38 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
39 embassy_rp::binary_info::rp_program_build_attribute!(),
40];
41
42static COUNTER: AtomicU32 = AtomicU32::new(0);
43static PWM: Mutex<CriticalSectionRawMutex, RefCell<Option<Pwm>>> = Mutex::new(RefCell::new(None));
44static ADC: Mutex<CriticalSectionRawMutex, RefCell<Option<(Adc<Blocking>, adc::Channel)>>> =
45 Mutex::new(RefCell::new(None));
46static ADC_VALUES: Channel<CriticalSectionRawMutex, u16, 2048> = Channel::new();
47
48#[embassy_executor::main]
49async fn main(spawner: Spawner) {
50 embassy_rp::pac::SIO.spinlock(31).write_value(1);
51 let p = embassy_rp::init(Default::default());
52
53 let adc = Adc::new_blocking(p.ADC, Default::default());
54 let p26 = adc::Channel::new_pin(p.PIN_26, Pull::None);
55 ADC.lock(|a| a.borrow_mut().replace((adc, p26)));
56
57 let pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, Default::default());
58 PWM.lock(|p| p.borrow_mut().replace(pwm));
59
60 // Enable the interrupt for pwm slice 4
61 embassy_rp::pac::PWM.irq0_inte().modify(|w| w.set_ch4(true));
62 unsafe {
63 cortex_m::peripheral::NVIC::unmask(interrupt::PWM_IRQ_WRAP_0);
64 }
65
66 // Tasks require their resources to have 'static lifetime
67 // No Mutex needed when sharing within the same executor/prio level
68 static AVG: StaticCell<Cell<u32>> = StaticCell::new();
69 let avg = AVG.init(Default::default());
70 spawner.must_spawn(processing(avg));
71
72 let mut ticker = Ticker::every(Duration::from_secs(1));
73 loop {
74 ticker.next().await;
75 let freq = COUNTER.swap(0, Ordering::Relaxed);
76 info!("pwm freq: {:?} Hz", freq);
77 info!("adc average: {:?}", avg.get());
78
79 // Update the pwm duty cycle, based on the averaged adc reading
80 let mut config = Config::default();
81 config.compare_b = ((avg.get() as f32 / 4095.0) * config.top as f32) as _;
82 PWM.lock(|p| p.borrow_mut().as_mut().unwrap().set_config(&config));
83 }
84}
85
86#[embassy_executor::task]
87async fn processing(avg: &'static Cell<u32>) {
88 let mut buffer: heapless::HistoryBuffer<u16, 100> = Default::default();
89 loop {
90 let val = ADC_VALUES.receive().await;
91 buffer.write(val);
92 let sum: u32 = buffer.iter().map(|x| *x as u32).sum();
93 avg.set(sum / buffer.len() as u32);
94 }
95}
96
97#[interrupt]
98fn PWM_IRQ_WRAP_0() {
99 critical_section::with(|cs| {
100 let mut adc = ADC.borrow(cs).borrow_mut();
101 let (adc, p26) = adc.as_mut().unwrap();
102 let val = adc.blocking_read(p26).unwrap();
103 ADC_VALUES.try_send(val).ok();
104
105 // Clear the interrupt, so we don't immediately re-enter this irq handler
106 PWM.borrow(cs).borrow_mut().as_mut().unwrap().clear_wrapped();
107 });
108 COUNTER.fetch_add(1, Ordering::Relaxed);
109}
diff --git a/examples/rp23/src/bin/multicore.rs b/examples/rp23/src/bin/multicore.rs
new file mode 100644
index 000000000..9ab43d7a5
--- /dev/null
+++ b/examples/rp23/src/bin/multicore.rs
@@ -0,0 +1,81 @@
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
8use defmt::*;
9use embassy_executor::Executor;
10use embassy_rp::block::ImageDef;
11use embassy_rp::gpio::{Level, Output};
12use embassy_rp::multicore::{spawn_core1, Stack};
13use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
14use embassy_sync::channel::Channel;
15use embassy_time::Timer;
16use static_cell::StaticCell;
17use {defmt_rtt as _, panic_probe as _};
18
19#[link_section = ".start_block"]
20#[used]
21pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
22
23// Program metadata for `picotool info`
24#[link_section = ".bi_entries"]
25#[used]
26pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
27 embassy_rp::binary_info::rp_program_name!(c"example"),
28 embassy_rp::binary_info::rp_cargo_version!(),
29 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
30 embassy_rp::binary_info::rp_program_build_attribute!(),
31];
32
33static mut CORE1_STACK: Stack<4096> = Stack::new();
34static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
35static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
36static CHANNEL: Channel<CriticalSectionRawMutex, LedState, 1> = Channel::new();
37
38enum LedState {
39 On,
40 Off,
41}
42
43#[cortex_m_rt::entry]
44fn main() -> ! {
45 let p = embassy_rp::init(Default::default());
46 let led = Output::new(p.PIN_25, Level::Low);
47
48 spawn_core1(
49 p.CORE1,
50 unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) },
51 move || {
52 let executor1 = EXECUTOR1.init(Executor::new());
53 executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(led))));
54 },
55 );
56
57 let executor0 = EXECUTOR0.init(Executor::new());
58 executor0.run(|spawner| unwrap!(spawner.spawn(core0_task())));
59}
60
61#[embassy_executor::task]
62async fn core0_task() {
63 info!("Hello from core 0");
64 loop {
65 CHANNEL.send(LedState::On).await;
66 Timer::after_millis(100).await;
67 CHANNEL.send(LedState::Off).await;
68 Timer::after_millis(400).await;
69 }
70}
71
72#[embassy_executor::task]
73async fn core1_task(mut led: Output<'static>) {
74 info!("Hello from core 1");
75 loop {
76 match CHANNEL.receive().await {
77 LedState::On => led.set_high(),
78 LedState::Off => led.set_low(),
79 }
80 }
81}
diff --git a/examples/rp23/src/bin/multiprio.rs b/examples/rp23/src/bin/multiprio.rs
new file mode 100644
index 000000000..27cd3656e
--- /dev/null
+++ b/examples/rp23/src/bin/multiprio.rs
@@ -0,0 +1,160 @@
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
59use cortex_m_rt::entry;
60use defmt::{info, unwrap};
61use embassy_executor::{Executor, InterruptExecutor};
62use embassy_rp::block::ImageDef;
63use embassy_rp::interrupt;
64use embassy_rp::interrupt::{InterruptExt, Priority};
65use embassy_time::{Instant, Timer, TICK_HZ};
66use static_cell::StaticCell;
67use {defmt_rtt as _, panic_probe as _};
68
69#[link_section = ".start_block"]
70#[used]
71pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
72
73// Program metadata for `picotool info`
74#[link_section = ".bi_entries"]
75#[used]
76pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
77 embassy_rp::binary_info::rp_program_name!(c"example"),
78 embassy_rp::binary_info::rp_cargo_version!(),
79 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
80 embassy_rp::binary_info::rp_program_build_attribute!(),
81];
82
83#[embassy_executor::task]
84async fn run_high() {
85 loop {
86 info!(" [high] tick!");
87 Timer::after_ticks(673740).await;
88 }
89}
90
91#[embassy_executor::task]
92async fn run_med() {
93 loop {
94 let start = Instant::now();
95 info!(" [med] Starting long computation");
96
97 // Spin-wait to simulate a long CPU computation
98 embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second
99
100 let end = Instant::now();
101 let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ;
102 info!(" [med] done in {} ms", ms);
103
104 Timer::after_ticks(53421).await;
105 }
106}
107
108#[embassy_executor::task]
109async fn run_low() {
110 loop {
111 let start = Instant::now();
112 info!("[low] Starting long computation");
113
114 // Spin-wait to simulate a long CPU computation
115 embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds
116
117 let end = Instant::now();
118 let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ;
119 info!("[low] done in {} ms", ms);
120
121 Timer::after_ticks(82983).await;
122 }
123}
124
125static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
126static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
127static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
128
129#[interrupt]
130unsafe fn SWI_IRQ_1() {
131 EXECUTOR_HIGH.on_interrupt()
132}
133
134#[interrupt]
135unsafe fn SWI_IRQ_0() {
136 EXECUTOR_MED.on_interrupt()
137}
138
139#[entry]
140fn main() -> ! {
141 info!("Hello World!");
142
143 let _p = embassy_rp::init(Default::default());
144
145 // High-priority executor: SWI_IRQ_1, priority level 2
146 interrupt::SWI_IRQ_1.set_priority(Priority::P2);
147 let spawner = EXECUTOR_HIGH.start(interrupt::SWI_IRQ_1);
148 unwrap!(spawner.spawn(run_high()));
149
150 // Medium-priority executor: SWI_IRQ_0, priority level 3
151 interrupt::SWI_IRQ_0.set_priority(Priority::P3);
152 let spawner = EXECUTOR_MED.start(interrupt::SWI_IRQ_0);
153 unwrap!(spawner.spawn(run_med()));
154
155 // Low priority executor: runs in thread mode, using WFE/SEV
156 let executor = EXECUTOR_LOW.init(Executor::new());
157 executor.run(|spawner| {
158 unwrap!(spawner.spawn(run_low()));
159 });
160}
diff --git a/examples/rp23/src/bin/otp.rs b/examples/rp23/src/bin/otp.rs
new file mode 100644
index 000000000..106e514ca
--- /dev/null
+++ b/examples/rp23/src/bin/otp.rs
@@ -0,0 +1,46 @@
1//! This example shows reading the OTP constants on the RP235x.
2
3#![no_std]
4#![no_main]
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_rp::block::ImageDef;
9use embassy_rp::otp;
10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _};
12
13#[link_section = ".start_block"]
14#[used]
15pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
16
17// Program metadata for `picotool info`
18#[link_section = ".bi_entries"]
19#[used]
20pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
21 embassy_rp::binary_info::rp_program_name!(c"OTP Read Example"),
22 embassy_rp::binary_info::rp_cargo_version!(),
23 embassy_rp::binary_info::rp_program_description!(c"OTP Read Example"),
24 embassy_rp::binary_info::rp_program_build_attribute!(),
25];
26
27#[embassy_executor::main]
28async fn main(_spawner: Spawner) {
29 let _ = embassy_rp::init(Default::default());
30 //
31 // add some delay to give an attached debug probe time to parse the
32 // defmt RTT header. Reading that header might touch flash memory, which
33 // interferes with flash write operations.
34 // https://github.com/knurling-rs/defmt/pull/683
35 Timer::after_millis(10).await;
36
37 let chip_id = unwrap!(otp::get_chipid());
38 info!("Unique id:{:X}", chip_id);
39
40 let private_rand = unwrap!(otp::get_private_random_number());
41 info!("Private Rand:{:X}", private_rand);
42
43 loop {
44 Timer::after_secs(1).await;
45 }
46}
diff --git a/examples/rp23/src/bin/pio_async.rs b/examples/rp23/src/bin/pio_async.rs
new file mode 100644
index 000000000..231afc80e
--- /dev/null
+++ b/examples/rp23/src/bin/pio_async.rs
@@ -0,0 +1,145 @@
1//! This example shows powerful PIO module in the RP2040 chip.
2
3#![no_std]
4#![no_main]
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_rp::bind_interrupts;
8use embassy_rp::block::ImageDef;
9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine};
11use fixed::traits::ToFixed;
12use fixed_macro::types::U56F8;
13use {defmt_rtt as _, panic_probe as _};
14
15#[link_section = ".start_block"]
16#[used]
17pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
18
19// Program metadata for `picotool info`
20#[link_section = ".bi_entries"]
21#[used]
22pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
23 embassy_rp::binary_info::rp_program_name!(c"example"),
24 embassy_rp::binary_info::rp_cargo_version!(),
25 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
26 embassy_rp::binary_info::rp_program_build_attribute!(),
27];
28
29bind_interrupts!(struct Irqs {
30 PIO0_IRQ_0 => InterruptHandler<PIO0>;
31});
32
33fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) {
34 // Setup sm0
35
36 // Send data serially to pin
37 let prg = pio_proc::pio_asm!(
38 ".origin 16",
39 "set pindirs, 1",
40 ".wrap_target",
41 "out pins,1 [19]",
42 ".wrap",
43 );
44
45 let mut cfg = Config::default();
46 cfg.use_program(&pio.load_program(&prg.program), &[]);
47 let out_pin = pio.make_pio_pin(pin);
48 cfg.set_out_pins(&[&out_pin]);
49 cfg.set_set_pins(&[&out_pin]);
50 cfg.clock_divider = (U56F8!(125_000_000) / 20 / 200).to_fixed();
51 cfg.shift_out.auto_fill = true;
52 sm.set_config(&cfg);
53}
54
55#[embassy_executor::task]
56async fn pio_task_sm0(mut sm: StateMachine<'static, PIO0, 0>) {
57 sm.set_enable(true);
58
59 let mut v = 0x0f0caffa;
60 loop {
61 sm.tx().wait_push(v).await;
62 v ^= 0xffff;
63 info!("Pushed {:032b} to FIFO", v);
64 }
65}
66
67fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 1>) {
68 // Setupm sm1
69
70 // Read 0b10101 repeatedly until ISR is full
71 let prg = pio_proc::pio_asm!(
72 //
73 ".origin 8",
74 "set x, 0x15",
75 ".wrap_target",
76 "in x, 5 [31]",
77 ".wrap",
78 );
79
80 let mut cfg = Config::default();
81 cfg.use_program(&pio.load_program(&prg.program), &[]);
82 cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed();
83 cfg.shift_in.auto_fill = true;
84 cfg.shift_in.direction = ShiftDirection::Right;
85 sm.set_config(&cfg);
86}
87
88#[embassy_executor::task]
89async fn pio_task_sm1(mut sm: StateMachine<'static, PIO0, 1>) {
90 sm.set_enable(true);
91 loop {
92 let rx = sm.rx().wait_pull().await;
93 info!("Pulled {:032b} from FIFO", rx);
94 }
95}
96
97fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 2>) {
98 // Setup sm2
99
100 // Repeatedly trigger IRQ 3
101 let prg = pio_proc::pio_asm!(
102 ".origin 0",
103 ".wrap_target",
104 "set x,10",
105 "delay:",
106 "jmp x-- delay [15]",
107 "irq 3 [15]",
108 ".wrap",
109 );
110 let mut cfg = Config::default();
111 cfg.use_program(&pio.load_program(&prg.program), &[]);
112 cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed();
113 sm.set_config(&cfg);
114}
115
116#[embassy_executor::task]
117async fn pio_task_sm2(mut irq: Irq<'static, PIO0, 3>, mut sm: StateMachine<'static, PIO0, 2>) {
118 sm.set_enable(true);
119 loop {
120 irq.wait().await;
121 info!("IRQ trigged");
122 }
123}
124
125#[embassy_executor::main]
126async fn main(spawner: Spawner) {
127 let p = embassy_rp::init(Default::default());
128 let pio = p.PIO0;
129
130 let Pio {
131 mut common,
132 irq3,
133 mut sm0,
134 mut sm1,
135 mut sm2,
136 ..
137 } = Pio::new(pio, Irqs);
138
139 setup_pio_task_sm0(&mut common, &mut sm0, p.PIN_0);
140 setup_pio_task_sm1(&mut common, &mut sm1);
141 setup_pio_task_sm2(&mut common, &mut sm2);
142 spawner.spawn(pio_task_sm0(sm0)).unwrap();
143 spawner.spawn(pio_task_sm1(sm1)).unwrap();
144 spawner.spawn(pio_task_sm2(irq3, sm2)).unwrap();
145}
diff --git a/examples/rp23/src/bin/pio_dma.rs b/examples/rp23/src/bin/pio_dma.rs
new file mode 100644
index 000000000..60fbcb83a
--- /dev/null
+++ b/examples/rp23/src/bin/pio_dma.rs
@@ -0,0 +1,98 @@
1//! This example shows powerful PIO module in the RP2040 chip.
2
3#![no_std]
4#![no_main]
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_futures::join::join;
8use embassy_rp::block::ImageDef;
9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection};
11use embassy_rp::{bind_interrupts, Peripheral};
12use fixed::traits::ToFixed;
13use fixed_macro::types::U56F8;
14use {defmt_rtt as _, panic_probe as _};
15
16#[link_section = ".start_block"]
17#[used]
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
19
20// Program metadata for `picotool info`
21#[link_section = ".bi_entries"]
22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"example"),
25 embassy_rp::binary_info::rp_cargo_version!(),
26 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
27 embassy_rp::binary_info::rp_program_build_attribute!(),
28];
29
30bind_interrupts!(struct Irqs {
31 PIO0_IRQ_0 => InterruptHandler<PIO0>;
32});
33
34fn swap_nibbles(v: u32) -> u32 {
35 let v = (v & 0x0f0f_0f0f) << 4 | (v & 0xf0f0_f0f0) >> 4;
36 let v = (v & 0x00ff_00ff) << 8 | (v & 0xff00_ff00) >> 8;
37 (v & 0x0000_ffff) << 16 | (v & 0xffff_0000) >> 16
38}
39
40#[embassy_executor::main]
41async fn main(_spawner: Spawner) {
42 let p = embassy_rp::init(Default::default());
43 let pio = p.PIO0;
44 let Pio {
45 mut common,
46 sm0: mut sm,
47 ..
48 } = Pio::new(pio, Irqs);
49
50 let prg = pio_proc::pio_asm!(
51 ".origin 0",
52 "set pindirs,1",
53 ".wrap_target",
54 "set y,7",
55 "loop:",
56 "out x,4",
57 "in x,4",
58 "jmp y--, loop",
59 ".wrap",
60 );
61
62 let mut cfg = Config::default();
63 cfg.use_program(&common.load_program(&prg.program), &[]);
64 cfg.clock_divider = (U56F8!(125_000_000) / U56F8!(10_000)).to_fixed();
65 cfg.shift_in = ShiftConfig {
66 auto_fill: true,
67 threshold: 32,
68 direction: ShiftDirection::Left,
69 };
70 cfg.shift_out = ShiftConfig {
71 auto_fill: true,
72 threshold: 32,
73 direction: ShiftDirection::Right,
74 };
75
76 sm.set_config(&cfg);
77 sm.set_enable(true);
78
79 let mut dma_out_ref = p.DMA_CH0.into_ref();
80 let mut dma_in_ref = p.DMA_CH1.into_ref();
81 let mut dout = [0x12345678u32; 29];
82 for i in 1..dout.len() {
83 dout[i] = (dout[i - 1] & 0x0fff_ffff) * 13 + 7;
84 }
85 let mut din = [0u32; 29];
86 loop {
87 let (rx, tx) = sm.rx_tx();
88 join(
89 tx.dma_push(dma_out_ref.reborrow(), &dout),
90 rx.dma_pull(dma_in_ref.reborrow(), &mut din),
91 )
92 .await;
93 for i in 0..din.len() {
94 assert_eq!(din[i], swap_nibbles(dout[i]));
95 }
96 info!("Swapped {} words", dout.len());
97 }
98}
diff --git a/examples/rp23/src/bin/pio_hd44780.rs b/examples/rp23/src/bin/pio_hd44780.rs
new file mode 100644
index 000000000..92aa858f9
--- /dev/null
+++ b/examples/rp23/src/bin/pio_hd44780.rs
@@ -0,0 +1,255 @@
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
7use core::fmt::Write;
8
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
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::{bind_interrupts, into_ref, Peripheral, PeripheralRef};
18use embassy_time::{Instant, Timer};
19use {defmt_rtt as _, panic_probe as _};
20
21#[link_section = ".start_block"]
22#[used]
23pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
24
25// Program metadata for `picotool info`
26#[link_section = ".bi_entries"]
27#[used]
28pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
29 embassy_rp::binary_info::rp_program_name!(c"example"),
30 embassy_rp::binary_info::rp_cargo_version!(),
31 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
32 embassy_rp::binary_info::rp_program_build_attribute!(),
33];
34
35bind_interrupts!(pub struct Irqs {
36 PIO0_IRQ_0 => InterruptHandler<PIO0>;
37});
38
39#[embassy_executor::main]
40async fn main(_spawner: Spawner) {
41 // this test assumes a 2x16 HD44780 display attached as follow:
42 // rs = PIN0
43 // rw = PIN1
44 // e = PIN2
45 // db4 = PIN3
46 // db5 = PIN4
47 // db6 = PIN5
48 // db7 = PIN6
49 // additionally a pwm signal for a bias voltage charge pump is provided on pin 15,
50 // allowing direct connection of the display to the RP2040 without level shifters.
51 let p = embassy_rp::init(Default::default());
52
53 let _pwm = Pwm::new_output_b(p.PWM_SLICE7, p.PIN_15, {
54 let mut c = pwm::Config::default();
55 c.divider = 125.into();
56 c.top = 100;
57 c.compare_b = 50;
58 c
59 });
60
61 let mut hd = HD44780::new(
62 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,
63 )
64 .await;
65
66 loop {
67 struct Buf<const N: usize>([u8; N], usize);
68 impl<const N: usize> Write for Buf<N> {
69 fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
70 for b in s.as_bytes() {
71 if self.1 >= N {
72 return Err(core::fmt::Error);
73 }
74 self.0[self.1] = *b;
75 self.1 += 1;
76 }
77 Ok(())
78 }
79 }
80 let mut buf = Buf([0; 16], 0);
81 write!(buf, "up {}s", Instant::now().as_micros() as f32 / 1e6).unwrap();
82 hd.add_line(&buf.0[0..buf.1]).await;
83 Timer::after_secs(1).await;
84 }
85}
86
87pub struct HD44780<'l> {
88 dma: PeripheralRef<'l, AnyChannel>,
89 sm: StateMachine<'l, PIO0, 0>,
90
91 buf: [u8; 40],
92}
93
94impl<'l> HD44780<'l> {
95 pub async fn new(
96 pio: impl Peripheral<P = PIO0> + 'l,
97 irq: Irqs,
98 dma: impl Peripheral<P = impl Channel> + 'l,
99 rs: impl PioPin,
100 rw: impl PioPin,
101 e: impl PioPin,
102 db4: impl PioPin,
103 db5: impl PioPin,
104 db6: impl PioPin,
105 db7: impl PioPin,
106 ) -> HD44780<'l> {
107 into_ref!(dma);
108
109 let Pio {
110 mut common,
111 mut irq0,
112 mut sm0,
113 ..
114 } = Pio::new(pio, irq);
115
116 // takes command words (<wait:24> <command:4> <0:4>)
117 let prg = pio_proc::pio_asm!(
118 r#"
119 .side_set 1 opt
120 .origin 20
121
122 loop:
123 out x, 24
124 delay:
125 jmp x--, delay
126 out pins, 4 side 1
127 out null, 4 side 0
128 jmp !osre, loop
129 irq 0
130 "#,
131 );
132
133 let rs = common.make_pio_pin(rs);
134 let rw = common.make_pio_pin(rw);
135 let e = common.make_pio_pin(e);
136 let db4 = common.make_pio_pin(db4);
137 let db5 = common.make_pio_pin(db5);
138 let db6 = common.make_pio_pin(db6);
139 let db7 = common.make_pio_pin(db7);
140
141 sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]);
142
143 let mut cfg = Config::default();
144 cfg.use_program(&common.load_program(&prg.program), &[&e]);
145 cfg.clock_divider = 125u8.into();
146 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
147 cfg.shift_out = ShiftConfig {
148 auto_fill: true,
149 direction: ShiftDirection::Left,
150 threshold: 32,
151 };
152 cfg.fifo_join = FifoJoin::TxOnly;
153 sm0.set_config(&cfg);
154
155 sm0.set_enable(true);
156 // init to 8 bit thrice
157 sm0.tx().push((50000 << 8) | 0x30);
158 sm0.tx().push((5000 << 8) | 0x30);
159 sm0.tx().push((200 << 8) | 0x30);
160 // init 4 bit
161 sm0.tx().push((200 << 8) | 0x20);
162 // set font and lines
163 sm0.tx().push((50 << 8) | 0x20);
164 sm0.tx().push(0b1100_0000);
165
166 irq0.wait().await;
167 sm0.set_enable(false);
168
169 // takes command sequences (<rs:1> <count:7>, data...)
170 // many side sets are only there to free up a delay bit!
171 let prg = pio_proc::pio_asm!(
172 r#"
173 .origin 27
174 .side_set 1
175
176 .wrap_target
177 pull side 0
178 out x 1 side 0 ; !rs
179 out y 7 side 0 ; #data - 1
180
181 ; rs/rw to e: >= 60ns
182 ; e high time: >= 500ns
183 ; e low time: >= 500ns
184 ; read data valid after e falling: ~5ns
185 ; write data hold after e falling: ~10ns
186
187 loop:
188 pull side 0
189 jmp !x data side 0
190 command:
191 set pins 0b00 side 0
192 jmp shift side 0
193 data:
194 set pins 0b01 side 0
195 shift:
196 out pins 4 side 1 [9]
197 nop side 0 [9]
198 out pins 4 side 1 [9]
199 mov osr null side 0 [7]
200 out pindirs 4 side 0
201 set pins 0b10 side 0
202 busy:
203 nop side 1 [9]
204 jmp pin more side 0 [9]
205 mov osr ~osr side 1 [9]
206 nop side 0 [4]
207 out pindirs 4 side 0
208 jmp y-- loop side 0
209 .wrap
210 more:
211 nop side 1 [9]
212 jmp busy side 0 [9]
213 "#
214 );
215
216 let mut cfg = Config::default();
217 cfg.use_program(&common.load_program(&prg.program), &[&e]);
218 cfg.clock_divider = 8u8.into(); // ~64ns/insn
219 cfg.set_jmp_pin(&db7);
220 cfg.set_set_pins(&[&rs, &rw]);
221 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
222 cfg.shift_out.direction = ShiftDirection::Left;
223 cfg.fifo_join = FifoJoin::TxOnly;
224 sm0.set_config(&cfg);
225
226 sm0.set_enable(true);
227
228 // display on and cursor on and blinking, reset display
229 sm0.tx().dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await;
230
231 Self {
232 dma: dma.map_into(),
233 sm: sm0,
234 buf: [0x20; 40],
235 }
236 }
237
238 pub async fn add_line(&mut self, s: &[u8]) {
239 // move cursor to 0:0, prepare 16 characters
240 self.buf[..3].copy_from_slice(&[0x80, 0x80, 15]);
241 // move line 2 up
242 self.buf.copy_within(22..38, 3);
243 // move cursor to 1:0, prepare 16 characters
244 self.buf[19..22].copy_from_slice(&[0x80, 0xc0, 15]);
245 // file line 2 with spaces
246 self.buf[22..38].fill(0x20);
247 // copy input line
248 let len = s.len().min(16);
249 self.buf[22..22 + len].copy_from_slice(&s[0..len]);
250 // set cursor to 1:15
251 self.buf[38..].copy_from_slice(&[0x80, 0xcf]);
252
253 self.sm.tx().dma_push(self.dma.reborrow(), &self.buf).await;
254 }
255}
diff --git a/examples/rp23/src/bin/pio_i2s.rs b/examples/rp23/src/bin/pio_i2s.rs
new file mode 100644
index 000000000..d6d2d0ade
--- /dev/null
+++ b/examples/rp23/src/bin/pio_i2s.rs
@@ -0,0 +1,140 @@
1//! This example shows generating audio and sending it to a connected i2s DAC using the PIO
2//! module of the RP2040.
3//!
4//! Connect the i2s DAC as follows:
5//! bclk : GPIO 18
6//! lrc : GPIO 19
7//! din : GPIO 20
8//! Then hold down the boot select button to trigger a rising triangle waveform.
9
10#![no_std]
11#![no_main]
12
13use core::mem;
14
15use embassy_executor::Spawner;
16use embassy_rp::block::ImageDef;
17use embassy_rp::peripherals::PIO0;
18use embassy_rp::pio::{Config, FifoJoin, InterruptHandler, Pio, ShiftConfig, ShiftDirection};
19use embassy_rp::{bind_interrupts, Peripheral};
20use fixed::traits::ToFixed;
21use static_cell::StaticCell;
22use {defmt_rtt as _, panic_probe as _};
23
24#[link_section = ".start_block"]
25#[used]
26pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
27
28// Program metadata for `picotool info`
29#[link_section = ".bi_entries"]
30#[used]
31pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
32 embassy_rp::binary_info::rp_program_name!(c"example"),
33 embassy_rp::binary_info::rp_cargo_version!(),
34 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
35 embassy_rp::binary_info::rp_program_build_attribute!(),
36];
37
38bind_interrupts!(struct Irqs {
39 PIO0_IRQ_0 => InterruptHandler<PIO0>;
40});
41
42const SAMPLE_RATE: u32 = 48_000;
43
44#[embassy_executor::main]
45async fn main(_spawner: Spawner) {
46 let p = embassy_rp::init(Default::default());
47
48 // Setup pio state machine for i2s output
49 let mut pio = Pio::new(p.PIO0, Irqs);
50
51 #[rustfmt::skip]
52 let pio_program = pio_proc::pio_asm!(
53 ".side_set 2",
54 " set x, 14 side 0b01", // side 0bWB - W = Word Clock, B = Bit Clock
55 "left_data:",
56 " out pins, 1 side 0b00",
57 " jmp x-- left_data side 0b01",
58 " out pins 1 side 0b10",
59 " set x, 14 side 0b11",
60 "right_data:",
61 " out pins 1 side 0b10",
62 " jmp x-- right_data side 0b11",
63 " out pins 1 side 0b00",
64 );
65
66 let bit_clock_pin = p.PIN_18;
67 let left_right_clock_pin = p.PIN_19;
68 let data_pin = p.PIN_20;
69
70 let data_pin = pio.common.make_pio_pin(data_pin);
71 let bit_clock_pin = pio.common.make_pio_pin(bit_clock_pin);
72 let left_right_clock_pin = pio.common.make_pio_pin(left_right_clock_pin);
73
74 let cfg = {
75 let mut cfg = Config::default();
76 cfg.use_program(
77 &pio.common.load_program(&pio_program.program),
78 &[&bit_clock_pin, &left_right_clock_pin],
79 );
80 cfg.set_out_pins(&[&data_pin]);
81 const BIT_DEPTH: u32 = 16;
82 const CHANNELS: u32 = 2;
83 let clock_frequency = SAMPLE_RATE * BIT_DEPTH * CHANNELS;
84 cfg.clock_divider = (125_000_000. / clock_frequency as f64 / 2.).to_fixed();
85 cfg.shift_out = ShiftConfig {
86 threshold: 32,
87 direction: ShiftDirection::Left,
88 auto_fill: true,
89 };
90 // join fifos to have twice the time to start the next dma transfer
91 cfg.fifo_join = FifoJoin::TxOnly;
92 cfg
93 };
94 pio.sm0.set_config(&cfg);
95 pio.sm0.set_pin_dirs(
96 embassy_rp::pio::Direction::Out,
97 &[&data_pin, &left_right_clock_pin, &bit_clock_pin],
98 );
99
100 // create two audio buffers (back and front) which will take turns being
101 // filled with new audio data and being sent to the pio fifo using dma
102 const BUFFER_SIZE: usize = 960;
103 static DMA_BUFFER: StaticCell<[u32; BUFFER_SIZE * 2]> = StaticCell::new();
104 let dma_buffer = DMA_BUFFER.init_with(|| [0u32; BUFFER_SIZE * 2]);
105 let (mut back_buffer, mut front_buffer) = dma_buffer.split_at_mut(BUFFER_SIZE);
106
107 // start pio state machine
108 pio.sm0.set_enable(true);
109 let tx = pio.sm0.tx();
110 let mut dma_ref = p.DMA_CH0.into_ref();
111
112 let mut fade_value: i32 = 0;
113 let mut phase: i32 = 0;
114
115 loop {
116 // trigger transfer of front buffer data to the pio fifo
117 // but don't await the returned future, yet
118 let dma_future = tx.dma_push(dma_ref.reborrow(), front_buffer);
119
120 // fade in audio
121 let fade_target = i32::MAX;
122
123 // fill back buffer with fresh audio samples before awaiting the dma future
124 for s in back_buffer.iter_mut() {
125 // exponential approach of fade_value => fade_target
126 fade_value += (fade_target - fade_value) >> 14;
127 // generate triangle wave with amplitude and frequency based on fade value
128 phase = (phase + (fade_value >> 22)) & 0xffff;
129 let triangle_sample = (phase as i16 as i32).abs() - 16384;
130 let sample = (triangle_sample * (fade_value >> 15)) >> 16;
131 // duplicate mono sample into lower and upper half of dma word
132 *s = (sample as u16 as u32) * 0x10001;
133 }
134
135 // now await the dma future. once the dma finishes, the next buffer needs to be queued
136 // within DMA_DEPTH / SAMPLE_RATE = 8 / 48000 seconds = 166us
137 dma_future.await;
138 mem::swap(&mut back_buffer, &mut front_buffer);
139 }
140}
diff --git a/examples/rp23/src/bin/pio_pwm.rs b/examples/rp23/src/bin/pio_pwm.rs
new file mode 100644
index 000000000..587f91ac3
--- /dev/null
+++ b/examples/rp23/src/bin/pio_pwm.rs
@@ -0,0 +1,133 @@
1//! This example shows how to create a pwm using the PIO module in the RP2040 chip.
2
3#![no_std]
4#![no_main]
5use core::time::Duration;
6
7use embassy_executor::Spawner;
8use embassy_rp::block::ImageDef;
9use embassy_rp::gpio::Level;
10use embassy_rp::peripherals::PIO0;
11use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine};
12use embassy_rp::{bind_interrupts, clocks};
13use embassy_time::Timer;
14use pio::InstructionOperands;
15use {defmt_rtt as _, panic_probe as _};
16
17#[link_section = ".start_block"]
18#[used]
19pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
20
21// Program metadata for `picotool info`
22#[link_section = ".bi_entries"]
23#[used]
24pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
25 embassy_rp::binary_info::rp_program_name!(c"example"),
26 embassy_rp::binary_info::rp_cargo_version!(),
27 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
28 embassy_rp::binary_info::rp_program_build_attribute!(),
29];
30
31const REFRESH_INTERVAL: u64 = 20000;
32
33bind_interrupts!(struct Irqs {
34 PIO0_IRQ_0 => InterruptHandler<PIO0>;
35});
36
37pub fn to_pio_cycles(duration: Duration) -> u32 {
38 (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow
39}
40
41pub struct PwmPio<'d, T: Instance, const SM: usize> {
42 sm: StateMachine<'d, T, SM>,
43}
44
45impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> {
46 pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self {
47 let prg = pio_proc::pio_asm!(
48 ".side_set 1 opt"
49 "pull noblock side 0"
50 "mov x, osr"
51 "mov y, isr"
52 "countloop:"
53 "jmp x!=y noset"
54 "jmp skip side 1"
55 "noset:"
56 "nop"
57 "skip:"
58 "jmp y-- countloop"
59 );
60
61 pio.load_program(&prg.program);
62 let pin = pio.make_pio_pin(pin);
63 sm.set_pins(Level::High, &[&pin]);
64 sm.set_pin_dirs(Direction::Out, &[&pin]);
65
66 let mut cfg = Config::default();
67 cfg.use_program(&pio.load_program(&prg.program), &[&pin]);
68
69 sm.set_config(&cfg);
70
71 Self { sm }
72 }
73
74 pub fn start(&mut self) {
75 self.sm.set_enable(true);
76 }
77
78 pub fn stop(&mut self) {
79 self.sm.set_enable(false);
80 }
81
82 pub fn set_period(&mut self, duration: Duration) {
83 let is_enabled = self.sm.is_enabled();
84 while !self.sm.tx().empty() {} // Make sure that the queue is empty
85 self.sm.set_enable(false);
86 self.sm.tx().push(to_pio_cycles(duration));
87 unsafe {
88 self.sm.exec_instr(
89 InstructionOperands::PULL {
90 if_empty: false,
91 block: false,
92 }
93 .encode(),
94 );
95 self.sm.exec_instr(
96 InstructionOperands::OUT {
97 destination: ::pio::OutDestination::ISR,
98 bit_count: 32,
99 }
100 .encode(),
101 );
102 };
103 if is_enabled {
104 self.sm.set_enable(true) // Enable if previously enabled
105 }
106 }
107
108 pub fn set_level(&mut self, level: u32) {
109 self.sm.tx().push(level);
110 }
111
112 pub fn write(&mut self, duration: Duration) {
113 self.set_level(to_pio_cycles(duration));
114 }
115}
116
117#[embassy_executor::main]
118async fn main(_spawner: Spawner) {
119 let p = embassy_rp::init(Default::default());
120 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
121
122 // Note that PIN_25 is the led pin on the Pico
123 let mut pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_25);
124 pwm_pio.set_period(Duration::from_micros(REFRESH_INTERVAL));
125 pwm_pio.start();
126
127 let mut duration = 0;
128 loop {
129 duration = (duration + 1) % 1000;
130 pwm_pio.write(Duration::from_micros(duration));
131 Timer::after_millis(1).await;
132 }
133}
diff --git a/examples/rp23/src/bin/pio_rotary_encoder.rs b/examples/rp23/src/bin/pio_rotary_encoder.rs
new file mode 100644
index 000000000..c147351e8
--- /dev/null
+++ b/examples/rp23/src/bin/pio_rotary_encoder.rs
@@ -0,0 +1,95 @@
1//! This example shows how to use the PIO module in the RP2040 to read a quadrature rotary encoder.
2
3#![no_std]
4#![no_main]
5
6use defmt::info;
7use embassy_executor::Spawner;
8use embassy_rp::block::ImageDef;
9use embassy_rp::gpio::Pull;
10use embassy_rp::peripherals::PIO0;
11use embassy_rp::{bind_interrupts, pio};
12use fixed::traits::ToFixed;
13use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine};
14use {defmt_rtt as _, panic_probe as _};
15
16#[link_section = ".start_block"]
17#[used]
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
19
20// Program metadata for `picotool info`
21#[link_section = ".bi_entries"]
22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"example"),
25 embassy_rp::binary_info::rp_cargo_version!(),
26 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
27 embassy_rp::binary_info::rp_program_build_attribute!(),
28];
29
30bind_interrupts!(struct Irqs {
31 PIO0_IRQ_0 => InterruptHandler<PIO0>;
32});
33
34pub struct PioEncoder<'d, T: Instance, const SM: usize> {
35 sm: StateMachine<'d, T, SM>,
36}
37
38impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> {
39 pub fn new(
40 pio: &mut Common<'d, T>,
41 mut sm: StateMachine<'d, T, SM>,
42 pin_a: impl PioPin,
43 pin_b: impl PioPin,
44 ) -> Self {
45 let mut pin_a = pio.make_pio_pin(pin_a);
46 let mut pin_b = pio.make_pio_pin(pin_b);
47 pin_a.set_pull(Pull::Up);
48 pin_b.set_pull(Pull::Up);
49 sm.set_pin_dirs(pio::Direction::In, &[&pin_a, &pin_b]);
50
51 let prg = pio_proc::pio_asm!("wait 1 pin 1", "wait 0 pin 1", "in pins, 2", "push",);
52
53 let mut cfg = Config::default();
54 cfg.set_in_pins(&[&pin_a, &pin_b]);
55 cfg.fifo_join = FifoJoin::RxOnly;
56 cfg.shift_in.direction = ShiftDirection::Left;
57 cfg.clock_divider = 10_000.to_fixed();
58 cfg.use_program(&pio.load_program(&prg.program), &[]);
59 sm.set_config(&cfg);
60 sm.set_enable(true);
61 Self { sm }
62 }
63
64 pub async fn read(&mut self) -> Direction {
65 loop {
66 match self.sm.rx().wait_pull().await {
67 0 => return Direction::CounterClockwise,
68 1 => return Direction::Clockwise,
69 _ => {}
70 }
71 }
72 }
73}
74
75pub enum Direction {
76 Clockwise,
77 CounterClockwise,
78}
79
80#[embassy_executor::main]
81async fn main(_spawner: Spawner) {
82 let p = embassy_rp::init(Default::default());
83 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
84
85 let mut encoder = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5);
86
87 let mut count = 0;
88 loop {
89 info!("Count: {}", count);
90 count += match encoder.read().await {
91 Direction::Clockwise => 1,
92 Direction::CounterClockwise => -1,
93 };
94 }
95}
diff --git a/examples/rp23/src/bin/pio_servo.rs b/examples/rp23/src/bin/pio_servo.rs
new file mode 100644
index 000000000..5e8714178
--- /dev/null
+++ b/examples/rp23/src/bin/pio_servo.rs
@@ -0,0 +1,223 @@
1//! This example shows how to create a pwm using the PIO module in the RP2040 chip.
2
3#![no_std]
4#![no_main]
5use core::time::Duration;
6
7use embassy_executor::Spawner;
8use embassy_rp::block::ImageDef;
9use embassy_rp::gpio::Level;
10use embassy_rp::peripherals::PIO0;
11use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine};
12use embassy_rp::{bind_interrupts, clocks};
13use embassy_time::Timer;
14use pio::InstructionOperands;
15use {defmt_rtt as _, panic_probe as _};
16
17#[link_section = ".start_block"]
18#[used]
19pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
20
21// Program metadata for `picotool info`
22#[link_section = ".bi_entries"]
23#[used]
24pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
25 embassy_rp::binary_info::rp_program_name!(c"example"),
26 embassy_rp::binary_info::rp_cargo_version!(),
27 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
28 embassy_rp::binary_info::rp_program_build_attribute!(),
29];
30
31const DEFAULT_MIN_PULSE_WIDTH: u64 = 1000; // uncalibrated default, the shortest duty cycle sent to a servo
32const DEFAULT_MAX_PULSE_WIDTH: u64 = 2000; // uncalibrated default, the longest duty cycle sent to a servo
33const DEFAULT_MAX_DEGREE_ROTATION: u64 = 160; // 160 degrees is typical
34const REFRESH_INTERVAL: u64 = 20000; // The period of each cycle
35
36bind_interrupts!(struct Irqs {
37 PIO0_IRQ_0 => InterruptHandler<PIO0>;
38});
39
40pub fn to_pio_cycles(duration: Duration) -> u32 {
41 (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow
42}
43
44pub struct PwmPio<'d, T: Instance, const SM: usize> {
45 sm: StateMachine<'d, T, SM>,
46}
47
48impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> {
49 pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self {
50 let prg = pio_proc::pio_asm!(
51 ".side_set 1 opt"
52 "pull noblock side 0"
53 "mov x, osr"
54 "mov y, isr"
55 "countloop:"
56 "jmp x!=y noset"
57 "jmp skip side 1"
58 "noset:"
59 "nop"
60 "skip:"
61 "jmp y-- countloop"
62 );
63
64 pio.load_program(&prg.program);
65 let pin = pio.make_pio_pin(pin);
66 sm.set_pins(Level::High, &[&pin]);
67 sm.set_pin_dirs(Direction::Out, &[&pin]);
68
69 let mut cfg = Config::default();
70 cfg.use_program(&pio.load_program(&prg.program), &[&pin]);
71
72 sm.set_config(&cfg);
73
74 Self { sm }
75 }
76
77 pub fn start(&mut self) {
78 self.sm.set_enable(true);
79 }
80
81 pub fn stop(&mut self) {
82 self.sm.set_enable(false);
83 }
84
85 pub fn set_period(&mut self, duration: Duration) {
86 let is_enabled = self.sm.is_enabled();
87 while !self.sm.tx().empty() {} // Make sure that the queue is empty
88 self.sm.set_enable(false);
89 self.sm.tx().push(to_pio_cycles(duration));
90 unsafe {
91 self.sm.exec_instr(
92 InstructionOperands::PULL {
93 if_empty: false,
94 block: false,
95 }
96 .encode(),
97 );
98 self.sm.exec_instr(
99 InstructionOperands::OUT {
100 destination: ::pio::OutDestination::ISR,
101 bit_count: 32,
102 }
103 .encode(),
104 );
105 };
106 if is_enabled {
107 self.sm.set_enable(true) // Enable if previously enabled
108 }
109 }
110
111 pub fn set_level(&mut self, level: u32) {
112 self.sm.tx().push(level);
113 }
114
115 pub fn write(&mut self, duration: Duration) {
116 self.set_level(to_pio_cycles(duration));
117 }
118}
119
120pub struct ServoBuilder<'d, T: Instance, const SM: usize> {
121 pwm: PwmPio<'d, T, SM>,
122 period: Duration,
123 min_pulse_width: Duration,
124 max_pulse_width: Duration,
125 max_degree_rotation: u64,
126}
127
128impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> {
129 pub fn new(pwm: PwmPio<'d, T, SM>) -> Self {
130 Self {
131 pwm,
132 period: Duration::from_micros(REFRESH_INTERVAL),
133 min_pulse_width: Duration::from_micros(DEFAULT_MIN_PULSE_WIDTH),
134 max_pulse_width: Duration::from_micros(DEFAULT_MAX_PULSE_WIDTH),
135 max_degree_rotation: DEFAULT_MAX_DEGREE_ROTATION,
136 }
137 }
138
139 pub fn set_period(mut self, duration: Duration) -> Self {
140 self.period = duration;
141 self
142 }
143
144 pub fn set_min_pulse_width(mut self, duration: Duration) -> Self {
145 self.min_pulse_width = duration;
146 self
147 }
148
149 pub fn set_max_pulse_width(mut self, duration: Duration) -> Self {
150 self.max_pulse_width = duration;
151 self
152 }
153
154 pub fn set_max_degree_rotation(mut self, degree: u64) -> Self {
155 self.max_degree_rotation = degree;
156 self
157 }
158
159 pub fn build(mut self) -> Servo<'d, T, SM> {
160 self.pwm.set_period(self.period);
161 Servo {
162 pwm: self.pwm,
163 min_pulse_width: self.min_pulse_width,
164 max_pulse_width: self.max_pulse_width,
165 max_degree_rotation: self.max_degree_rotation,
166 }
167 }
168}
169
170pub struct Servo<'d, T: Instance, const SM: usize> {
171 pwm: PwmPio<'d, T, SM>,
172 min_pulse_width: Duration,
173 max_pulse_width: Duration,
174 max_degree_rotation: u64,
175}
176
177impl<'d, T: Instance, const SM: usize> Servo<'d, T, SM> {
178 pub fn start(&mut self) {
179 self.pwm.start();
180 }
181
182 pub fn stop(&mut self) {
183 self.pwm.stop();
184 }
185
186 pub fn write_time(&mut self, duration: Duration) {
187 self.pwm.write(duration);
188 }
189
190 pub fn rotate(&mut self, degree: u64) {
191 let degree_per_nano_second = (self.max_pulse_width.as_nanos() as u64 - self.min_pulse_width.as_nanos() as u64)
192 / self.max_degree_rotation;
193 let mut duration =
194 Duration::from_nanos(degree * degree_per_nano_second + self.min_pulse_width.as_nanos() as u64);
195 if self.max_pulse_width < duration {
196 duration = self.max_pulse_width;
197 }
198
199 self.pwm.write(duration);
200 }
201}
202
203#[embassy_executor::main]
204async fn main(_spawner: Spawner) {
205 let p = embassy_rp::init(Default::default());
206 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
207
208 let pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_1);
209 let mut servo = ServoBuilder::new(pwm_pio)
210 .set_max_degree_rotation(120) // Example of adjusting values for MG996R servo
211 .set_min_pulse_width(Duration::from_micros(350)) // This value was detemined by a rough experiment.
212 .set_max_pulse_width(Duration::from_micros(2600)) // Along with this value.
213 .build();
214
215 servo.start();
216
217 let mut degree = 0;
218 loop {
219 degree = (degree + 1) % 120;
220 servo.rotate(degree);
221 Timer::after_millis(50).await;
222 }
223}
diff --git a/examples/rp23/src/bin/pio_stepper.rs b/examples/rp23/src/bin/pio_stepper.rs
new file mode 100644
index 000000000..24785443b
--- /dev/null
+++ b/examples/rp23/src/bin/pio_stepper.rs
@@ -0,0 +1,183 @@
1//! This example shows how to use the PIO module in the RP2040 to implement a stepper motor driver
2//! for a 5-wire stepper such as the 28BYJ-48. You can halt an ongoing rotation by dropping the future.
3
4#![no_std]
5#![no_main]
6use core::mem::{self, MaybeUninit};
7
8use defmt::info;
9use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts;
11use embassy_rp::block::ImageDef;
12use embassy_rp::peripherals::PIO0;
13use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Irq, Pio, PioPin, StateMachine};
14use embassy_time::{with_timeout, Duration, Timer};
15use fixed::traits::ToFixed;
16use fixed::types::extra::U8;
17use fixed::FixedU32;
18use {defmt_rtt as _, panic_probe as _};
19
20#[link_section = ".start_block"]
21#[used]
22pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
23
24// Program metadata for `picotool info`
25#[link_section = ".bi_entries"]
26#[used]
27pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
28 embassy_rp::binary_info::rp_program_name!(c"example"),
29 embassy_rp::binary_info::rp_cargo_version!(),
30 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
31 embassy_rp::binary_info::rp_program_build_attribute!(),
32];
33
34bind_interrupts!(struct Irqs {
35 PIO0_IRQ_0 => InterruptHandler<PIO0>;
36});
37
38pub struct PioStepper<'d, T: Instance, const SM: usize> {
39 irq: Irq<'d, T, SM>,
40 sm: StateMachine<'d, T, SM>,
41}
42
43impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> {
44 pub fn new(
45 pio: &mut Common<'d, T>,
46 mut sm: StateMachine<'d, T, SM>,
47 irq: Irq<'d, T, SM>,
48 pin0: impl PioPin,
49 pin1: impl PioPin,
50 pin2: impl PioPin,
51 pin3: impl PioPin,
52 ) -> Self {
53 let prg = pio_proc::pio_asm!(
54 "pull block",
55 "mov x, osr",
56 "pull block",
57 "mov y, osr",
58 "jmp !x end",
59 "loop:",
60 "jmp !osre step",
61 "mov osr, y",
62 "step:",
63 "out pins, 4 [31]"
64 "jmp x-- loop",
65 "end:",
66 "irq 0 rel"
67 );
68 let pin0 = pio.make_pio_pin(pin0);
69 let pin1 = pio.make_pio_pin(pin1);
70 let pin2 = pio.make_pio_pin(pin2);
71 let pin3 = pio.make_pio_pin(pin3);
72 sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]);
73 let mut cfg = Config::default();
74 cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]);
75 cfg.clock_divider = (125_000_000 / (100 * 136)).to_fixed();
76 cfg.use_program(&pio.load_program(&prg.program), &[]);
77 sm.set_config(&cfg);
78 sm.set_enable(true);
79 Self { irq, sm }
80 }
81
82 // Set pulse frequency
83 pub fn set_frequency(&mut self, freq: u32) {
84 let clock_divider: FixedU32<U8> = (125_000_000 / (freq * 136)).to_fixed();
85 assert!(clock_divider <= 65536, "clkdiv must be <= 65536");
86 assert!(clock_divider >= 1, "clkdiv must be >= 1");
87 self.sm.set_clock_divider(clock_divider);
88 self.sm.clkdiv_restart();
89 }
90
91 // Full step, one phase
92 pub async fn step(&mut self, steps: i32) {
93 if steps > 0 {
94 self.run(steps, 0b1000_0100_0010_0001_1000_0100_0010_0001).await
95 } else {
96 self.run(-steps, 0b0001_0010_0100_1000_0001_0010_0100_1000).await
97 }
98 }
99
100 // Full step, two phase
101 pub async fn step2(&mut self, steps: i32) {
102 if steps > 0 {
103 self.run(steps, 0b1001_1100_0110_0011_1001_1100_0110_0011).await
104 } else {
105 self.run(-steps, 0b0011_0110_1100_1001_0011_0110_1100_1001).await
106 }
107 }
108
109 // Half step
110 pub async fn step_half(&mut self, steps: i32) {
111 if steps > 0 {
112 self.run(steps, 0b1001_1000_1100_0100_0110_0010_0011_0001).await
113 } else {
114 self.run(-steps, 0b0001_0011_0010_0110_0100_1100_1000_1001).await
115 }
116 }
117
118 async fn run(&mut self, steps: i32, pattern: u32) {
119 self.sm.tx().wait_push(steps as u32).await;
120 self.sm.tx().wait_push(pattern).await;
121 let drop = OnDrop::new(|| {
122 self.sm.clear_fifos();
123 unsafe {
124 self.sm.exec_instr(
125 pio::InstructionOperands::JMP {
126 address: 0,
127 condition: pio::JmpCondition::Always,
128 }
129 .encode(),
130 );
131 }
132 });
133 self.irq.wait().await;
134 drop.defuse();
135 }
136}
137
138struct OnDrop<F: FnOnce()> {
139 f: MaybeUninit<F>,
140}
141
142impl<F: FnOnce()> OnDrop<F> {
143 pub fn new(f: F) -> Self {
144 Self { f: MaybeUninit::new(f) }
145 }
146
147 pub fn defuse(self) {
148 mem::forget(self)
149 }
150}
151
152impl<F: FnOnce()> Drop for OnDrop<F> {
153 fn drop(&mut self) {
154 unsafe { self.f.as_ptr().read()() }
155 }
156}
157
158#[embassy_executor::main]
159async fn main(_spawner: Spawner) {
160 let p = embassy_rp::init(Default::default());
161 let Pio {
162 mut common, irq0, sm0, ..
163 } = Pio::new(p.PIO0, Irqs);
164
165 let mut stepper = PioStepper::new(&mut common, sm0, irq0, p.PIN_4, p.PIN_5, p.PIN_6, p.PIN_7);
166 stepper.set_frequency(120);
167 loop {
168 info!("CW full steps");
169 stepper.step(1000).await;
170
171 info!("CCW full steps, drop after 1 sec");
172 if let Err(_) = with_timeout(Duration::from_secs(1), stepper.step(i32::MIN)).await {
173 info!("Time's up!");
174 Timer::after(Duration::from_secs(1)).await;
175 }
176
177 info!("CW half steps");
178 stepper.step_half(1000).await;
179
180 info!("CCW half steps");
181 stepper.step_half(-1000).await;
182 }
183}
diff --git a/examples/rp23/src/bin/pio_ws2812.rs b/examples/rp23/src/bin/pio_ws2812.rs
new file mode 100644
index 000000000..00fe5e396
--- /dev/null
+++ b/examples/rp23/src/bin/pio_ws2812.rs
@@ -0,0 +1,176 @@
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
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::block::ImageDef;
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::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef};
16use embassy_time::{Duration, Ticker, Timer};
17use fixed::types::U24F8;
18use fixed_macro::fixed;
19use smart_leds::RGB8;
20use {defmt_rtt as _, panic_probe as _};
21
22#[link_section = ".start_block"]
23#[used]
24pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
25
26// Program metadata for `picotool info`
27#[link_section = ".bi_entries"]
28#[used]
29pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
30 embassy_rp::binary_info::rp_program_name!(c"example"),
31 embassy_rp::binary_info::rp_cargo_version!(),
32 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
33 embassy_rp::binary_info::rp_program_build_attribute!(),
34];
35
36bind_interrupts!(struct Irqs {
37 PIO0_IRQ_0 => InterruptHandler<PIO0>;
38});
39
40pub struct Ws2812<'d, P: Instance, const S: usize, const N: usize> {
41 dma: PeripheralRef<'d, AnyChannel>,
42 sm: StateMachine<'d, P, S>,
43}
44
45impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> {
46 pub fn new(
47 pio: &mut Common<'d, P>,
48 mut sm: StateMachine<'d, P, S>,
49 dma: impl Peripheral<P = impl Channel> + 'd,
50 pin: impl PioPin,
51 ) -> Self {
52 into_ref!(dma);
53
54 // Setup sm0
55
56 // prepare the PIO program
57 let side_set = pio::SideSet::new(false, 1, false);
58 let mut a: pio::Assembler<32> = pio::Assembler::new_with_side_set(side_set);
59
60 const T1: u8 = 2; // start bit
61 const T2: u8 = 5; // data bit
62 const T3: u8 = 3; // stop bit
63 const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32;
64
65 let mut wrap_target = a.label();
66 let mut wrap_source = a.label();
67 let mut do_zero = a.label();
68 a.set_with_side_set(pio::SetDestination::PINDIRS, 1, 0);
69 a.bind(&mut wrap_target);
70 // Do stop bit
71 a.out_with_delay_and_side_set(pio::OutDestination::X, 1, T3 - 1, 0);
72 // Do start bit
73 a.jmp_with_delay_and_side_set(pio::JmpCondition::XIsZero, &mut do_zero, T1 - 1, 1);
74 // Do data bit = 1
75 a.jmp_with_delay_and_side_set(pio::JmpCondition::Always, &mut wrap_target, T2 - 1, 1);
76 a.bind(&mut do_zero);
77 // Do data bit = 0
78 a.nop_with_delay_and_side_set(T2 - 1, 0);
79 a.bind(&mut wrap_source);
80
81 let prg = a.assemble_with_wrap(wrap_source, wrap_target);
82 let mut cfg = Config::default();
83
84 // Pin config
85 let out_pin = pio.make_pio_pin(pin);
86 cfg.set_out_pins(&[&out_pin]);
87 cfg.set_set_pins(&[&out_pin]);
88
89 cfg.use_program(&pio.load_program(&prg), &[&out_pin]);
90
91 // Clock config, measured in kHz to avoid overflows
92 // TODO CLOCK_FREQ should come from embassy_rp
93 let clock_freq = U24F8::from_num(clocks::clk_sys_freq() / 1000);
94 let ws2812_freq = fixed!(800: U24F8);
95 let bit_freq = ws2812_freq * CYCLES_PER_BIT;
96 cfg.clock_divider = clock_freq / bit_freq;
97
98 // FIFO config
99 cfg.fifo_join = FifoJoin::TxOnly;
100 cfg.shift_out = ShiftConfig {
101 auto_fill: true,
102 threshold: 24,
103 direction: ShiftDirection::Left,
104 };
105
106 sm.set_config(&cfg);
107 sm.set_enable(true);
108
109 Self {
110 dma: dma.map_into(),
111 sm,
112 }
113 }
114
115 pub async fn write(&mut self, colors: &[RGB8; N]) {
116 // Precompute the word bytes from the colors
117 let mut words = [0u32; N];
118 for i in 0..N {
119 let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8);
120 words[i] = word;
121 }
122
123 // DMA transfer
124 self.sm.tx().dma_push(self.dma.reborrow(), &words).await;
125
126 Timer::after_micros(55).await;
127 }
128}
129
130/// Input a value 0 to 255 to get a color value
131/// The colours are a transition r - g - b - back to r.
132fn wheel(mut wheel_pos: u8) -> RGB8 {
133 wheel_pos = 255 - wheel_pos;
134 if wheel_pos < 85 {
135 return (255 - wheel_pos * 3, 0, wheel_pos * 3).into();
136 }
137 if wheel_pos < 170 {
138 wheel_pos -= 85;
139 return (0, wheel_pos * 3, 255 - wheel_pos * 3).into();
140 }
141 wheel_pos -= 170;
142 (wheel_pos * 3, 255 - wheel_pos * 3, 0).into()
143}
144
145#[embassy_executor::main]
146async fn main(_spawner: Spawner) {
147 info!("Start");
148 let p = embassy_rp::init(Default::default());
149
150 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
151
152 // This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit
153 // feather boards for the 2040 both have one built in.
154 const NUM_LEDS: usize = 1;
155 let mut data = [RGB8::default(); NUM_LEDS];
156
157 // Common neopixel pins:
158 // Thing plus: 8
159 // Adafruit Feather: 16; Adafruit Feather+RFM95: 4
160 let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16);
161
162 // Loop forever making RGB values and pushing them out to the WS2812.
163 let mut ticker = Ticker::every(Duration::from_millis(10));
164 loop {
165 for j in 0..(256 * 5) {
166 debug!("New Colors:");
167 for i in 0..NUM_LEDS {
168 data[i] = wheel((((i * 256) as u16 / NUM_LEDS as u16 + j as u16) & 255) as u8);
169 debug!("R: {} G: {} B: {}", data[i].r, data[i].g, data[i].b);
170 }
171 ws2812.write(&data).await;
172
173 ticker.next().await;
174 }
175 }
176}
diff --git a/examples/rp23/src/bin/pwm.rs b/examples/rp23/src/bin/pwm.rs
new file mode 100644
index 000000000..bfc2c6f67
--- /dev/null
+++ b/examples/rp23/src/bin/pwm.rs
@@ -0,0 +1,44 @@
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
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::pwm::{Config, Pwm};
12use embassy_time::Timer;
13use {defmt_rtt as _, panic_probe as _};
14
15#[link_section = ".start_block"]
16#[used]
17pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
18
19// Program metadata for `picotool info`
20#[link_section = ".bi_entries"]
21#[used]
22pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
23 embassy_rp::binary_info::rp_program_name!(c"example"),
24 embassy_rp::binary_info::rp_cargo_version!(),
25 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
26 embassy_rp::binary_info::rp_program_build_attribute!(),
27];
28
29#[embassy_executor::main]
30async fn main(_spawner: Spawner) {
31 let p = embassy_rp::init(Default::default());
32
33 let mut c: Config = Default::default();
34 c.top = 0x8000;
35 c.compare_b = 8;
36 let mut pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, c.clone());
37
38 loop {
39 info!("current LED duty cycle: {}/32768", c.compare_b);
40 Timer::after_secs(1).await;
41 c.compare_b = c.compare_b.rotate_left(4);
42 pwm.set_config(&c);
43 }
44}
diff --git a/examples/rp23/src/bin/pwm_input.rs b/examples/rp23/src/bin/pwm_input.rs
new file mode 100644
index 000000000..b65f2778b
--- /dev/null
+++ b/examples/rp23/src/bin/pwm_input.rs
@@ -0,0 +1,41 @@
1//! This example shows how to use the PWM module to measure the frequency of an input signal.
2
3#![no_std]
4#![no_main]
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_rp::block::ImageDef;
9use embassy_rp::gpio::Pull;
10use embassy_rp::pwm::{Config, InputMode, Pwm};
11use embassy_time::{Duration, Ticker};
12use {defmt_rtt as _, panic_probe as _};
13
14#[link_section = ".start_block"]
15#[used]
16pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
17
18// Program metadata for `picotool info`
19#[link_section = ".bi_entries"]
20#[used]
21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
22 embassy_rp::binary_info::rp_program_name!(c"example"),
23 embassy_rp::binary_info::rp_cargo_version!(),
24 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
25 embassy_rp::binary_info::rp_program_build_attribute!(),
26];
27
28#[embassy_executor::main]
29async fn main(_spawner: Spawner) {
30 let p = embassy_rp::init(Default::default());
31
32 let cfg: Config = Default::default();
33 let pwm = Pwm::new_input(p.PWM_SLICE2, p.PIN_5, Pull::None, InputMode::RisingEdge, cfg);
34
35 let mut ticker = Ticker::every(Duration::from_secs(1));
36 loop {
37 info!("Input frequency: {} Hz", pwm.counter());
38 pwm.set_counter(0);
39 ticker.next().await;
40 }
41}
diff --git a/examples/rp23/src/bin/rosc.rs b/examples/rp23/src/bin/rosc.rs
new file mode 100644
index 000000000..f65b236b1
--- /dev/null
+++ b/examples/rp23/src/bin/rosc.rs
@@ -0,0 +1,46 @@
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
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::{clocks, gpio};
12use embassy_time::Timer;
13use gpio::{Level, Output};
14use {defmt_rtt as _, panic_probe as _};
15
16#[link_section = ".start_block"]
17#[used]
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
19
20// Program metadata for `picotool info`
21#[link_section = ".bi_entries"]
22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"example"),
25 embassy_rp::binary_info::rp_cargo_version!(),
26 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
27 embassy_rp::binary_info::rp_program_build_attribute!(),
28];
29
30#[embassy_executor::main]
31async fn main(_spawner: Spawner) {
32 let mut config = embassy_rp::config::Config::default();
33 config.clocks = clocks::ClockConfig::rosc();
34 let p = embassy_rp::init(config);
35 let mut led = Output::new(p.PIN_25, Level::Low);
36
37 loop {
38 info!("led on!");
39 led.set_high();
40 Timer::after_secs(1).await;
41
42 info!("led off!");
43 led.set_low();
44 Timer::after_secs(1).await;
45 }
46}
diff --git a/examples/rp23/src/bin/shared_bus.rs b/examples/rp23/src/bin/shared_bus.rs
new file mode 100644
index 000000000..b3fde13e3
--- /dev/null
+++ b/examples/rp23/src/bin/shared_bus.rs
@@ -0,0 +1,130 @@
1//! This example shows how to share (async) I2C and SPI buses between multiple devices.
2
3#![no_std]
4#![no_main]
5
6use defmt::*;
7use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice;
8use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice;
9use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts;
11use embassy_rp::block::ImageDef;
12use embassy_rp::gpio::{AnyPin, Level, Output};
13use embassy_rp::i2c::{self, I2c, InterruptHandler};
14use embassy_rp::peripherals::{I2C1, SPI1};
15use embassy_rp::spi::{self, Spi};
16use embassy_sync::blocking_mutex::raw::NoopRawMutex;
17use embassy_sync::mutex::Mutex;
18use embassy_time::Timer;
19use static_cell::StaticCell;
20use {defmt_rtt as _, panic_probe as _};
21
22#[link_section = ".start_block"]
23#[used]
24pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
25
26// Program metadata for `picotool info`
27#[link_section = ".bi_entries"]
28#[used]
29pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
30 embassy_rp::binary_info::rp_program_name!(c"example"),
31 embassy_rp::binary_info::rp_cargo_version!(),
32 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
33 embassy_rp::binary_info::rp_program_build_attribute!(),
34];
35
36type Spi1Bus = Mutex<NoopRawMutex, Spi<'static, SPI1, spi::Async>>;
37type I2c1Bus = Mutex<NoopRawMutex, I2c<'static, I2C1, i2c::Async>>;
38
39bind_interrupts!(struct Irqs {
40 I2C1_IRQ => InterruptHandler<I2C1>;
41});
42
43#[embassy_executor::main]
44async fn main(spawner: Spawner) {
45 let p = embassy_rp::init(Default::default());
46 info!("Here we go!");
47
48 // Shared I2C bus
49 let i2c = I2c::new_async(p.I2C1, p.PIN_15, p.PIN_14, Irqs, i2c::Config::default());
50 static I2C_BUS: StaticCell<I2c1Bus> = StaticCell::new();
51 let i2c_bus = I2C_BUS.init(Mutex::new(i2c));
52
53 spawner.must_spawn(i2c_task_a(i2c_bus));
54 spawner.must_spawn(i2c_task_b(i2c_bus));
55
56 // Shared SPI bus
57 let spi_cfg = spi::Config::default();
58 let spi = Spi::new(p.SPI1, p.PIN_10, p.PIN_11, p.PIN_12, p.DMA_CH0, p.DMA_CH1, spi_cfg);
59 static SPI_BUS: StaticCell<Spi1Bus> = StaticCell::new();
60 let spi_bus = SPI_BUS.init(Mutex::new(spi));
61
62 // Chip select pins for the SPI devices
63 let cs_a = Output::new(AnyPin::from(p.PIN_0), Level::High);
64 let cs_b = Output::new(AnyPin::from(p.PIN_1), Level::High);
65
66 spawner.must_spawn(spi_task_a(spi_bus, cs_a));
67 spawner.must_spawn(spi_task_b(spi_bus, cs_b));
68}
69
70#[embassy_executor::task]
71async fn i2c_task_a(i2c_bus: &'static I2c1Bus) {
72 let i2c_dev = I2cDevice::new(i2c_bus);
73 let _sensor = DummyI2cDeviceDriver::new(i2c_dev, 0xC0);
74 loop {
75 info!("i2c task A");
76 Timer::after_secs(1).await;
77 }
78}
79
80#[embassy_executor::task]
81async fn i2c_task_b(i2c_bus: &'static I2c1Bus) {
82 let i2c_dev = I2cDevice::new(i2c_bus);
83 let _sensor = DummyI2cDeviceDriver::new(i2c_dev, 0xDE);
84 loop {
85 info!("i2c task B");
86 Timer::after_secs(1).await;
87 }
88}
89
90#[embassy_executor::task]
91async fn spi_task_a(spi_bus: &'static Spi1Bus, cs: Output<'static>) {
92 let spi_dev = SpiDevice::new(spi_bus, cs);
93 let _sensor = DummySpiDeviceDriver::new(spi_dev);
94 loop {
95 info!("spi task A");
96 Timer::after_secs(1).await;
97 }
98}
99
100#[embassy_executor::task]
101async fn spi_task_b(spi_bus: &'static Spi1Bus, cs: Output<'static>) {
102 let spi_dev = SpiDevice::new(spi_bus, cs);
103 let _sensor = DummySpiDeviceDriver::new(spi_dev);
104 loop {
105 info!("spi task B");
106 Timer::after_secs(1).await;
107 }
108}
109
110// Dummy I2C device driver, using `embedded-hal-async`
111struct DummyI2cDeviceDriver<I2C: embedded_hal_async::i2c::I2c> {
112 _i2c: I2C,
113}
114
115impl<I2C: embedded_hal_async::i2c::I2c> DummyI2cDeviceDriver<I2C> {
116 fn new(i2c_dev: I2C, _address: u8) -> Self {
117 Self { _i2c: i2c_dev }
118 }
119}
120
121// Dummy SPI device driver, using `embedded-hal-async`
122struct DummySpiDeviceDriver<SPI: embedded_hal_async::spi::SpiDevice> {
123 _spi: SPI,
124}
125
126impl<SPI: embedded_hal_async::spi::SpiDevice> DummySpiDeviceDriver<SPI> {
127 fn new(spi_dev: SPI) -> Self {
128 Self { _spi: spi_dev }
129 }
130}
diff --git a/examples/rp23/src/bin/sharing.rs b/examples/rp23/src/bin/sharing.rs
new file mode 100644
index 000000000..4a3301cfd
--- /dev/null
+++ b/examples/rp23/src/bin/sharing.rs
@@ -0,0 +1,165 @@
1//! This example shows some common strategies for sharing resources between tasks.
2//!
3//! We demonstrate five different ways of sharing, covering different use cases:
4//! - Atomics: This method is used for simple values, such as bool and u8..u32
5//! - Blocking Mutex: This is used for sharing non-async things, using Cell/RefCell for interior mutability.
6//! - Async Mutex: This is used for sharing async resources, where you need to hold the lock across await points.
7//! The async Mutex has interior mutability built-in, so no RefCell is needed.
8//! - Cell: For sharing Copy types between tasks running on the same executor.
9//! - RefCell: When you want &mut access to a value shared between tasks running on the same executor.
10//!
11//! More information: https://embassy.dev/book/#_sharing_peripherals_between_tasks
12
13#![no_std]
14#![no_main]
15
16use core::cell::{Cell, RefCell};
17use core::sync::atomic::{AtomicU32, Ordering};
18
19use cortex_m_rt::entry;
20use defmt::info;
21use embassy_executor::{Executor, InterruptExecutor};
22use embassy_rp::block::ImageDef;
23use embassy_rp::clocks::RoscRng;
24use embassy_rp::interrupt::{InterruptExt, Priority};
25use embassy_rp::peripherals::UART0;
26use embassy_rp::uart::{self, InterruptHandler, UartTx};
27use embassy_rp::{bind_interrupts, interrupt};
28use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
29use embassy_sync::{blocking_mutex, mutex};
30use embassy_time::{Duration, Ticker};
31use rand::RngCore;
32use static_cell::{ConstStaticCell, StaticCell};
33use {defmt_rtt as _, panic_probe as _};
34
35#[link_section = ".start_block"]
36#[used]
37pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
38
39// Program metadata for `picotool info`
40#[link_section = ".bi_entries"]
41#[used]
42pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
43 embassy_rp::binary_info::rp_program_name!(c"example"),
44 embassy_rp::binary_info::rp_cargo_version!(),
45 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
46 embassy_rp::binary_info::rp_program_build_attribute!(),
47];
48
49type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>;
50
51struct MyType {
52 inner: u32,
53}
54
55static EXECUTOR_HI: InterruptExecutor = InterruptExecutor::new();
56static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
57
58// Use Atomics for simple values
59static ATOMIC: AtomicU32 = AtomicU32::new(0);
60
61// Use blocking Mutex with Cell/RefCell for sharing non-async things
62static MUTEX_BLOCKING: blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<MyType>> =
63 blocking_mutex::Mutex::new(RefCell::new(MyType { inner: 0 }));
64
65bind_interrupts!(struct Irqs {
66 UART0_IRQ => InterruptHandler<UART0>;
67});
68
69#[interrupt]
70unsafe fn SWI_IRQ_0() {
71 EXECUTOR_HI.on_interrupt()
72}
73
74#[entry]
75fn main() -> ! {
76 let p = embassy_rp::init(Default::default());
77 info!("Here we go!");
78
79 let uart = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, uart::Config::default());
80 // Use the async Mutex for sharing async things (built-in interior mutability)
81 static UART: StaticCell<UartAsyncMutex> = StaticCell::new();
82 let uart = UART.init(mutex::Mutex::new(uart));
83
84 // High-priority executor: runs in interrupt mode
85 interrupt::SWI_IRQ_0.set_priority(Priority::P3);
86 let spawner = EXECUTOR_HI.start(interrupt::SWI_IRQ_0);
87 spawner.must_spawn(task_a(uart));
88
89 // Low priority executor: runs in thread mode
90 let executor = EXECUTOR_LOW.init(Executor::new());
91 executor.run(|spawner| {
92 // No Mutex needed when sharing between tasks running on the same executor
93
94 // Use Cell for Copy-types
95 static CELL: ConstStaticCell<Cell<[u8; 4]>> = ConstStaticCell::new(Cell::new([0; 4]));
96 let cell = CELL.take();
97
98 // Use RefCell for &mut access
99 static REF_CELL: ConstStaticCell<RefCell<MyType>> = ConstStaticCell::new(RefCell::new(MyType { inner: 0 }));
100 let ref_cell = REF_CELL.take();
101
102 spawner.must_spawn(task_b(uart, cell, ref_cell));
103 spawner.must_spawn(task_c(cell, ref_cell));
104 });
105}
106
107#[embassy_executor::task]
108async fn task_a(uart: &'static UartAsyncMutex) {
109 let mut ticker = Ticker::every(Duration::from_secs(1));
110 loop {
111 let random = RoscRng.next_u32();
112
113 {
114 let mut uart = uart.lock().await;
115 uart.write(b"task a").await.unwrap();
116 // The uart lock is released when it goes out of scope
117 }
118
119 ATOMIC.store(random, Ordering::Relaxed);
120
121 MUTEX_BLOCKING.lock(|x| x.borrow_mut().inner = random);
122
123 ticker.next().await;
124 }
125}
126
127#[embassy_executor::task]
128async fn task_b(uart: &'static UartAsyncMutex, cell: &'static Cell<[u8; 4]>, ref_cell: &'static RefCell<MyType>) {
129 let mut ticker = Ticker::every(Duration::from_secs(1));
130 loop {
131 let random = RoscRng.next_u32();
132
133 uart.lock().await.write(b"task b").await.unwrap();
134
135 cell.set(random.to_be_bytes());
136
137 ref_cell.borrow_mut().inner = random;
138
139 ticker.next().await;
140 }
141}
142
143#[embassy_executor::task]
144async fn task_c(cell: &'static Cell<[u8; 4]>, ref_cell: &'static RefCell<MyType>) {
145 let mut ticker = Ticker::every(Duration::from_secs(1));
146 loop {
147 info!("=======================");
148
149 let atomic_val = ATOMIC.load(Ordering::Relaxed);
150 info!("atomic: {}", atomic_val);
151
152 MUTEX_BLOCKING.lock(|x| {
153 let val = x.borrow().inner;
154 info!("blocking mutex: {}", val);
155 });
156
157 let cell_val = cell.get();
158 info!("cell: {:?}", cell_val);
159
160 let ref_cell_val = ref_cell.borrow().inner;
161 info!("ref_cell: {:?}", ref_cell_val);
162
163 ticker.next().await;
164 }
165}
diff --git a/examples/rp23/src/bin/spi.rs b/examples/rp23/src/bin/spi.rs
new file mode 100644
index 000000000..924873e60
--- /dev/null
+++ b/examples/rp23/src/bin/spi.rs
@@ -0,0 +1,61 @@
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
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
11use embassy_rp::spi::Spi;
12use embassy_rp::{gpio, spi};
13use gpio::{Level, Output};
14use {defmt_rtt as _, panic_probe as _};
15
16#[link_section = ".start_block"]
17#[used]
18pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
19
20// Program metadata for `picotool info`
21#[link_section = ".bi_entries"]
22#[used]
23pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
24 embassy_rp::binary_info::rp_program_name!(c"example"),
25 embassy_rp::binary_info::rp_cargo_version!(),
26 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
27 embassy_rp::binary_info::rp_program_build_attribute!(),
28];
29
30#[embassy_executor::main]
31async fn main(_spawner: Spawner) {
32 let p = embassy_rp::init(Default::default());
33 info!("Hello World!");
34
35 // Example for resistive touch sensor in Waveshare Pico-ResTouch
36
37 let miso = p.PIN_12;
38 let mosi = p.PIN_11;
39 let clk = p.PIN_10;
40 let touch_cs = p.PIN_16;
41
42 // create SPI
43 let mut config = spi::Config::default();
44 config.frequency = 2_000_000;
45 let mut spi = Spi::new_blocking(p.SPI1, clk, mosi, miso, config);
46
47 // Configure CS
48 let mut cs = Output::new(touch_cs, Level::Low);
49
50 loop {
51 cs.set_low();
52 let mut buf = [0x90, 0x00, 0x00, 0xd0, 0x00, 0x00];
53 spi.blocking_transfer_in_place(&mut buf).unwrap();
54 cs.set_high();
55
56 let x = (buf[1] as u32) << 5 | (buf[2] as u32) >> 3;
57 let y = (buf[4] as u32) << 5 | (buf[5] as u32) >> 3;
58
59 info!("touch: {=u32} {=u32}", x, y);
60 }
61}
diff --git a/examples/rp23/src/bin/spi_async.rs b/examples/rp23/src/bin/spi_async.rs
new file mode 100644
index 000000000..4a74f991c
--- /dev/null
+++ b/examples/rp23/src/bin/spi_async.rs
@@ -0,0 +1,46 @@
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
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::block::ImageDef;
10use embassy_rp::spi::{Config, Spi};
11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _};
13
14#[link_section = ".start_block"]
15#[used]
16pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
17
18// Program metadata for `picotool info`
19#[link_section = ".bi_entries"]
20#[used]
21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
22 embassy_rp::binary_info::rp_program_name!(c"example"),
23 embassy_rp::binary_info::rp_cargo_version!(),
24 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
25 embassy_rp::binary_info::rp_program_build_attribute!(),
26];
27
28#[embassy_executor::main]
29async fn main(_spawner: Spawner) {
30 let p = embassy_rp::init(Default::default());
31 info!("Hello World!");
32
33 let miso = p.PIN_12;
34 let mosi = p.PIN_11;
35 let clk = p.PIN_10;
36
37 let mut spi = Spi::new(p.SPI1, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default());
38
39 loop {
40 let tx_buf = [1_u8, 2, 3, 4, 5, 6];
41 let mut rx_buf = [0_u8; 6];
42 spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
43 info!("{:?}", rx_buf);
44 Timer::after_secs(1).await;
45 }
46}
diff --git a/examples/rp23/src/bin/spi_display.rs b/examples/rp23/src/bin/spi_display.rs
new file mode 100644
index 000000000..71dd84658
--- /dev/null
+++ b/examples/rp23/src/bin/spi_display.rs
@@ -0,0 +1,327 @@
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
6#![no_std]
7#![no_main]
8
9use core::cell::RefCell;
10
11use defmt::*;
12use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig;
13use embassy_executor::Spawner;
14use embassy_rp::block::ImageDef;
15use embassy_rp::gpio::{Level, Output};
16use embassy_rp::spi;
17use embassy_rp::spi::{Blocking, Spi};
18use embassy_sync::blocking_mutex::raw::NoopRawMutex;
19use embassy_sync::blocking_mutex::Mutex;
20use embassy_time::Delay;
21use embedded_graphics::image::{Image, ImageRawLE};
22use embedded_graphics::mono_font::ascii::FONT_10X20;
23use embedded_graphics::mono_font::MonoTextStyle;
24use embedded_graphics::pixelcolor::Rgb565;
25use embedded_graphics::prelude::*;
26use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle};
27use embedded_graphics::text::Text;
28use st7789::{Orientation, ST7789};
29use {defmt_rtt as _, panic_probe as _};
30
31#[link_section = ".start_block"]
32#[used]
33pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
34
35// Program metadata for `picotool info`
36#[link_section = ".bi_entries"]
37#[used]
38pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
39 embassy_rp::binary_info::rp_program_name!(c"example"),
40 embassy_rp::binary_info::rp_cargo_version!(),
41 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
42 embassy_rp::binary_info::rp_program_build_attribute!(),
43];
44
45use crate::my_display_interface::SPIDeviceInterface;
46use crate::touch::Touch;
47
48const DISPLAY_FREQ: u32 = 64_000_000;
49const TOUCH_FREQ: u32 = 200_000;
50
51#[embassy_executor::main]
52async fn main(_spawner: Spawner) {
53 let p = embassy_rp::init(Default::default());
54 info!("Hello World!");
55
56 let bl = p.PIN_13;
57 let rst = p.PIN_15;
58 let display_cs = p.PIN_9;
59 let dcx = p.PIN_8;
60 let miso = p.PIN_12;
61 let mosi = p.PIN_11;
62 let clk = p.PIN_10;
63 let touch_cs = p.PIN_16;
64 //let touch_irq = p.PIN_17;
65
66 // create SPI
67 let mut display_config = spi::Config::default();
68 display_config.frequency = DISPLAY_FREQ;
69 display_config.phase = spi::Phase::CaptureOnSecondTransition;
70 display_config.polarity = spi::Polarity::IdleHigh;
71 let mut touch_config = spi::Config::default();
72 touch_config.frequency = TOUCH_FREQ;
73 touch_config.phase = spi::Phase::CaptureOnSecondTransition;
74 touch_config.polarity = spi::Polarity::IdleHigh;
75
76 let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone());
77 let spi_bus: Mutex<NoopRawMutex, _> = Mutex::new(RefCell::new(spi));
78
79 let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config);
80 let touch_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(touch_cs, Level::High), touch_config);
81
82 let mut touch = Touch::new(touch_spi);
83
84 let dcx = Output::new(dcx, Level::Low);
85 let rst = Output::new(rst, Level::Low);
86 // dcx: 0 = command, 1 = data
87
88 // Enable LCD backlight
89 let _bl = Output::new(bl, Level::High);
90
91 // display interface abstraction from SPI and DC
92 let di = SPIDeviceInterface::new(display_spi, dcx);
93
94 // create driver
95 let mut display = ST7789::new(di, rst, 240, 320);
96
97 // initialize
98 display.init(&mut Delay).unwrap();
99
100 // set default orientation
101 display.set_orientation(Orientation::Landscape).unwrap();
102
103 display.clear(Rgb565::BLACK).unwrap();
104
105 let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86);
106 let ferris = Image::new(&raw_image_data, Point::new(34, 68));
107
108 // Display the image
109 ferris.draw(&mut display).unwrap();
110
111 let style = MonoTextStyle::new(&FONT_10X20, Rgb565::GREEN);
112 Text::new(
113 "Hello embedded_graphics \n + embassy + RP2040!",
114 Point::new(20, 200),
115 style,
116 )
117 .draw(&mut display)
118 .unwrap();
119
120 loop {
121 if let Some((x, y)) = touch.read() {
122 let style = PrimitiveStyleBuilder::new().fill_color(Rgb565::BLUE).build();
123
124 Rectangle::new(Point::new(x - 1, y - 1), Size::new(3, 3))
125 .into_styled(style)
126 .draw(&mut display)
127 .unwrap();
128 }
129 }
130}
131
132/// Driver for the XPT2046 resistive touchscreen sensor
133mod touch {
134 use embedded_hal_1::spi::{Operation, SpiDevice};
135
136 struct Calibration {
137 x1: i32,
138 x2: i32,
139 y1: i32,
140 y2: i32,
141 sx: i32,
142 sy: i32,
143 }
144
145 const CALIBRATION: Calibration = Calibration {
146 x1: 3880,
147 x2: 340,
148 y1: 262,
149 y2: 3850,
150 sx: 320,
151 sy: 240,
152 };
153
154 pub struct Touch<SPI: SpiDevice> {
155 spi: SPI,
156 }
157
158 impl<SPI> Touch<SPI>
159 where
160 SPI: SpiDevice,
161 {
162 pub fn new(spi: SPI) -> Self {
163 Self { spi }
164 }
165
166 pub fn read(&mut self) -> Option<(i32, i32)> {
167 let mut x = [0; 2];
168 let mut y = [0; 2];
169 self.spi
170 .transaction(&mut [
171 Operation::Write(&[0x90]),
172 Operation::Read(&mut x),
173 Operation::Write(&[0xd0]),
174 Operation::Read(&mut y),
175 ])
176 .unwrap();
177
178 let x = (u16::from_be_bytes(x) >> 3) as i32;
179 let y = (u16::from_be_bytes(y) >> 3) as i32;
180
181 let cal = &CALIBRATION;
182
183 let x = ((x - cal.x1) * cal.sx / (cal.x2 - cal.x1)).clamp(0, cal.sx);
184 let y = ((y - cal.y1) * cal.sy / (cal.y2 - cal.y1)).clamp(0, cal.sy);
185 if x == 0 && y == 0 {
186 None
187 } else {
188 Some((x, y))
189 }
190 }
191 }
192}
193
194mod my_display_interface {
195 use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand};
196 use embedded_hal_1::digital::OutputPin;
197 use embedded_hal_1::spi::SpiDevice;
198
199 /// SPI display interface.
200 ///
201 /// This combines the SPI peripheral and a data/command pin
202 pub struct SPIDeviceInterface<SPI, DC> {
203 spi: SPI,
204 dc: DC,
205 }
206
207 impl<SPI, DC> SPIDeviceInterface<SPI, DC>
208 where
209 SPI: SpiDevice,
210 DC: OutputPin,
211 {
212 /// Create new SPI interface for communciation with a display driver
213 pub fn new(spi: SPI, dc: DC) -> Self {
214 Self { spi, dc }
215 }
216 }
217
218 impl<SPI, DC> WriteOnlyDataCommand for SPIDeviceInterface<SPI, DC>
219 where
220 SPI: SpiDevice,
221 DC: OutputPin,
222 {
223 fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> {
224 // 1 = data, 0 = command
225 self.dc.set_low().map_err(|_| DisplayError::DCError)?;
226
227 send_u8(&mut self.spi, cmds).map_err(|_| DisplayError::BusWriteError)?;
228 Ok(())
229 }
230
231 fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> {
232 // 1 = data, 0 = command
233 self.dc.set_high().map_err(|_| DisplayError::DCError)?;
234
235 send_u8(&mut self.spi, buf).map_err(|_| DisplayError::BusWriteError)?;
236 Ok(())
237 }
238 }
239
240 fn send_u8<T: SpiDevice>(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> {
241 match words {
242 DataFormat::U8(slice) => spi.write(slice),
243 DataFormat::U16(slice) => {
244 use byte_slice_cast::*;
245 spi.write(slice.as_byte_slice())
246 }
247 DataFormat::U16LE(slice) => {
248 use byte_slice_cast::*;
249 for v in slice.as_mut() {
250 *v = v.to_le();
251 }
252 spi.write(slice.as_byte_slice())
253 }
254 DataFormat::U16BE(slice) => {
255 use byte_slice_cast::*;
256 for v in slice.as_mut() {
257 *v = v.to_be();
258 }
259 spi.write(slice.as_byte_slice())
260 }
261 DataFormat::U8Iter(iter) => {
262 let mut buf = [0; 32];
263 let mut i = 0;
264
265 for v in iter.into_iter() {
266 buf[i] = v;
267 i += 1;
268
269 if i == buf.len() {
270 spi.write(&buf)?;
271 i = 0;
272 }
273 }
274
275 if i > 0 {
276 spi.write(&buf[..i])?;
277 }
278
279 Ok(())
280 }
281 DataFormat::U16LEIter(iter) => {
282 use byte_slice_cast::*;
283 let mut buf = [0; 32];
284 let mut i = 0;
285
286 for v in iter.map(u16::to_le) {
287 buf[i] = v;
288 i += 1;
289
290 if i == buf.len() {
291 spi.write(&buf.as_byte_slice())?;
292 i = 0;
293 }
294 }
295
296 if i > 0 {
297 spi.write(&buf[..i].as_byte_slice())?;
298 }
299
300 Ok(())
301 }
302 DataFormat::U16BEIter(iter) => {
303 use byte_slice_cast::*;
304 let mut buf = [0; 64];
305 let mut i = 0;
306 let len = buf.len();
307
308 for v in iter.map(u16::to_be) {
309 buf[i] = v;
310 i += 1;
311
312 if i == len {
313 spi.write(&buf.as_byte_slice())?;
314 i = 0;
315 }
316 }
317
318 if i > 0 {
319 spi.write(&buf[..i].as_byte_slice())?;
320 }
321
322 Ok(())
323 }
324 _ => unimplemented!(),
325 }
326 }
327}
diff --git a/examples/rp23/src/bin/spi_sdmmc.rs b/examples/rp23/src/bin/spi_sdmmc.rs
new file mode 100644
index 000000000..dabf41ab8
--- /dev/null
+++ b/examples/rp23/src/bin/spi_sdmmc.rs
@@ -0,0 +1,98 @@
1//! This example shows how to use `embedded-sdmmc` with the RP2040 chip, over SPI.
2//!
3//! The example will attempt to read a file `MY_FILE.TXT` from the root directory
4//! of the SD card and print its contents.
5
6#![no_std]
7#![no_main]
8
9use defmt::*;
10use embassy_embedded_hal::SetConfig;
11use embassy_executor::Spawner;
12use embassy_rp::block::ImageDef;
13use embassy_rp::spi::Spi;
14use embassy_rp::{gpio, spi};
15use embedded_hal_bus::spi::ExclusiveDevice;
16use embedded_sdmmc::sdcard::{DummyCsPin, SdCard};
17use gpio::{Level, Output};
18use {defmt_rtt as _, panic_probe as _};
19
20#[link_section = ".start_block"]
21#[used]
22pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
23
24// Program metadata for `picotool info`
25#[link_section = ".bi_entries"]
26#[used]
27pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
28 embassy_rp::binary_info::rp_program_name!(c"example"),
29 embassy_rp::binary_info::rp_cargo_version!(),
30 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
31 embassy_rp::binary_info::rp_program_build_attribute!(),
32];
33
34struct DummyTimesource();
35
36impl embedded_sdmmc::TimeSource for DummyTimesource {
37 fn get_timestamp(&self) -> embedded_sdmmc::Timestamp {
38 embedded_sdmmc::Timestamp {
39 year_since_1970: 0,
40 zero_indexed_month: 0,
41 zero_indexed_day: 0,
42 hours: 0,
43 minutes: 0,
44 seconds: 0,
45 }
46 }
47}
48
49#[embassy_executor::main]
50async fn main(_spawner: Spawner) {
51 embassy_rp::pac::SIO.spinlock(31).write_value(1);
52 let p = embassy_rp::init(Default::default());
53
54 // SPI clock needs to be running at <= 400kHz during initialization
55 let mut config = spi::Config::default();
56 config.frequency = 400_000;
57 let spi = Spi::new_blocking(p.SPI1, p.PIN_10, p.PIN_11, p.PIN_12, config);
58 // Use a dummy cs pin here, for embedded-hal SpiDevice compatibility reasons
59 let spi_dev = ExclusiveDevice::new_no_delay(spi, DummyCsPin);
60 // Real cs pin
61 let cs = Output::new(p.PIN_16, Level::High);
62
63 let sdcard = SdCard::new(spi_dev, cs, embassy_time::Delay);
64 info!("Card size is {} bytes", sdcard.num_bytes().unwrap());
65
66 // Now that the card is initialized, the SPI clock can go faster
67 let mut config = spi::Config::default();
68 config.frequency = 16_000_000;
69 sdcard.spi(|dev| dev.bus_mut().set_config(&config)).ok();
70
71 // Now let's look for volumes (also known as partitions) on our block device.
72 // To do this we need a Volume Manager. It will take ownership of the block device.
73 let mut volume_mgr = embedded_sdmmc::VolumeManager::new(sdcard, DummyTimesource());
74
75 // Try and access Volume 0 (i.e. the first partition).
76 // The volume object holds information about the filesystem on that volume.
77 let mut volume0 = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0)).unwrap();
78 info!("Volume 0: {:?}", defmt::Debug2Format(&volume0));
79
80 // Open the root directory (mutably borrows from the volume).
81 let mut root_dir = volume0.open_root_dir().unwrap();
82
83 // Open a file called "MY_FILE.TXT" in the root directory
84 // This mutably borrows the directory.
85 let mut my_file = root_dir
86 .open_file_in_dir("MY_FILE.TXT", embedded_sdmmc::Mode::ReadOnly)
87 .unwrap();
88
89 // Print the contents of the file
90 while !my_file.is_eof() {
91 let mut buf = [0u8; 32];
92 if let Ok(n) = my_file.read(&mut buf) {
93 info!("{:a}", buf[..n]);
94 }
95 }
96
97 loop {}
98}
diff --git a/examples/rp23/src/bin/uart.rs b/examples/rp23/src/bin/uart.rs
new file mode 100644
index 000000000..0ffe0b293
--- /dev/null
+++ b/examples/rp23/src/bin/uart.rs
@@ -0,0 +1,40 @@
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
7#![no_std]
8#![no_main]
9
10use embassy_executor::Spawner;
11use embassy_rp::block::ImageDef;
12use embassy_rp::uart;
13use {defmt_rtt as _, panic_probe as _};
14
15#[link_section = ".start_block"]
16#[used]
17pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
18
19// Program metadata for `picotool info`
20#[link_section = ".bi_entries"]
21#[used]
22pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
23 embassy_rp::binary_info::rp_program_name!(c"example"),
24 embassy_rp::binary_info::rp_cargo_version!(),
25 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
26 embassy_rp::binary_info::rp_program_build_attribute!(),
27];
28
29#[embassy_executor::main]
30async fn main(_spawner: Spawner) {
31 let p = embassy_rp::init(Default::default());
32 let config = uart::Config::default();
33 let mut uart = uart::Uart::new_blocking(p.UART1, p.PIN_4, p.PIN_5, config);
34 uart.blocking_write("Hello World!\r\n".as_bytes()).unwrap();
35
36 loop {
37 uart.blocking_write("hello there!\r\n".as_bytes()).unwrap();
38 cortex_m::asm::delay(1_000_000);
39 }
40}
diff --git a/examples/rp23/src/bin/uart_buffered_split.rs b/examples/rp23/src/bin/uart_buffered_split.rs
new file mode 100644
index 000000000..4e69a20c4
--- /dev/null
+++ b/examples/rp23/src/bin/uart_buffered_split.rs
@@ -0,0 +1,73 @@
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
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_rp::bind_interrupts;
13use embassy_rp::block::ImageDef;
14use embassy_rp::peripherals::UART0;
15use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config};
16use embassy_time::Timer;
17use embedded_io_async::{Read, Write};
18use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _};
20
21#[link_section = ".start_block"]
22#[used]
23pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
24
25// Program metadata for `picotool info`
26#[link_section = ".bi_entries"]
27#[used]
28pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
29 embassy_rp::binary_info::rp_program_name!(c"example"),
30 embassy_rp::binary_info::rp_cargo_version!(),
31 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
32 embassy_rp::binary_info::rp_program_build_attribute!(),
33];
34
35bind_interrupts!(struct Irqs {
36 UART0_IRQ => BufferedInterruptHandler<UART0>;
37});
38
39#[embassy_executor::main]
40async fn main(spawner: Spawner) {
41 let p = embassy_rp::init(Default::default());
42 let (tx_pin, rx_pin, uart) = (p.PIN_0, p.PIN_1, p.UART0);
43
44 static TX_BUF: StaticCell<[u8; 16]> = StaticCell::new();
45 let tx_buf = &mut TX_BUF.init([0; 16])[..];
46 static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new();
47 let rx_buf = &mut RX_BUF.init([0; 16])[..];
48 let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default());
49 let (mut tx, rx) = uart.split();
50
51 unwrap!(spawner.spawn(reader(rx)));
52
53 info!("Writing...");
54 loop {
55 let data = [
56 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,
57 29, 30, 31,
58 ];
59 info!("TX {:?}", data);
60 tx.write_all(&data).await.unwrap();
61 Timer::after_secs(1).await;
62 }
63}
64
65#[embassy_executor::task]
66async fn reader(mut rx: BufferedUartRx<'static, UART0>) {
67 info!("Reading...");
68 loop {
69 let mut buf = [0; 31];
70 rx.read_exact(&mut buf).await.unwrap();
71 info!("RX {:?}", buf);
72 }
73}
diff --git a/examples/rp23/src/bin/uart_r503.rs b/examples/rp23/src/bin/uart_r503.rs
new file mode 100644
index 000000000..5ac8839e3
--- /dev/null
+++ b/examples/rp23/src/bin/uart_r503.rs
@@ -0,0 +1,173 @@
1#![no_std]
2#![no_main]
3
4use defmt::{debug, error, info};
5use embassy_executor::Spawner;
6use embassy_rp::bind_interrupts;
7use embassy_rp::block::ImageDef;
8use embassy_rp::peripherals::UART0;
9use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart};
10use embassy_time::{with_timeout, Duration, Timer};
11use heapless::Vec;
12use {defmt_rtt as _, panic_probe as _};
13
14#[link_section = ".start_block"]
15#[used]
16pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
17
18// Program metadata for `picotool info`
19#[link_section = ".bi_entries"]
20#[used]
21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
22 embassy_rp::binary_info::rp_program_name!(c"example"),
23 embassy_rp::binary_info::rp_cargo_version!(),
24 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
25 embassy_rp::binary_info::rp_program_build_attribute!(),
26];
27
28bind_interrupts!(pub struct Irqs {
29 UART0_IRQ => UARTInterruptHandler<UART0>;
30});
31
32const START: u16 = 0xEF01;
33const ADDRESS: u32 = 0xFFFFFFFF;
34
35// ================================================================================
36
37// Data package format
38// Name Length Description
39// ==========================================================================================================
40// Start 2 bytes Fixed value of 0xEF01; High byte transferred first.
41// Address 4 bytes Default value is 0xFFFFFFFF, which can be modified by command.
42// High byte transferred first and at wrong adder value, module
43// will reject to transfer.
44// PID 1 byte 01H Command packet;
45// 02H Data packet; Data packet shall not appear alone in executing
46// processs, must follow command packet or acknowledge packet.
47// 07H Acknowledge packet;
48// 08H End of Data packet.
49// LENGTH 2 bytes Refers to the length of package content (command packets and data packets)
50// plus the length of Checksum (2 bytes). Unit is byte. Max length is 256 bytes.
51// And high byte is transferred first.
52// DATA - It can be commands, data, command’s parameters, acknowledge result, etc.
53// (fingerprint character value, template are all deemed as data);
54// SUM 2 bytes The arithmetic sum of package identifier, package length and all package
55// contens. Overflowing bits are omitted. high byte is transferred first.
56
57// ================================================================================
58
59// Checksum is calculated on 'length (2 bytes) + data (??)'.
60fn compute_checksum(buf: Vec<u8, 32>) -> u16 {
61 let mut checksum = 0u16;
62
63 let check_end = buf.len();
64 let checked_bytes = &buf[6..check_end];
65 for byte in checked_bytes {
66 checksum += (*byte) as u16;
67 }
68 return checksum;
69}
70
71#[embassy_executor::main]
72async fn main(_spawner: Spawner) {
73 info!("Start");
74
75 let p = embassy_rp::init(Default::default());
76
77 // Initialize the fingerprint scanner.
78 let mut config = Config::default();
79 config.baudrate = 57600;
80 config.stop_bits = StopBits::STOP1;
81 config.data_bits = DataBits::DataBits8;
82 config.parity = Parity::ParityNone;
83
84 let (uart, tx_pin, tx_dma, rx_pin, rx_dma) = (p.UART0, p.PIN_16, p.DMA_CH0, p.PIN_17, p.DMA_CH1);
85 let uart = Uart::new(uart, tx_pin, rx_pin, Irqs, tx_dma, rx_dma, config);
86 let (mut tx, mut rx) = uart.split();
87
88 let mut vec_buf: Vec<u8, 32> = heapless::Vec::new();
89 let mut data: Vec<u8, 32> = heapless::Vec::new();
90
91 let mut speeds: Vec<u8, 3> = heapless::Vec::new();
92 let _ = speeds.push(0xC8); // Slow
93 let _ = speeds.push(0x20); // Medium
94 let _ = speeds.push(0x02); // Fast
95
96 // Cycle through the three colours Red, Blue and Purple forever.
97 loop {
98 for colour in 1..=3 {
99 for speed in &speeds {
100 // Set the data first, because the length is dependent on that.
101 // However, we write the length bits before we do the data.
102 data.clear();
103 let _ = data.push(0x01); // ctrl=Breathing light
104 let _ = data.push(*speed);
105 let _ = data.push(colour as u8); // colour=Red, Blue, Purple
106 let _ = data.push(0x00); // times=Infinite
107
108 // Clear buffers
109 vec_buf.clear();
110
111 // START
112 let _ = vec_buf.extend_from_slice(&START.to_be_bytes()[..]);
113
114 // ADDRESS
115 let _ = vec_buf.extend_from_slice(&ADDRESS.to_be_bytes()[..]);
116
117 // PID
118 let _ = vec_buf.extend_from_slice(&[0x01]);
119
120 // LENGTH
121 let len: u16 = (1 + data.len() + 2).try_into().unwrap();
122 let _ = vec_buf.extend_from_slice(&len.to_be_bytes()[..]);
123
124 // COMMAND
125 let _ = vec_buf.push(0x35); // Command: AuraLedConfig
126
127 // DATA
128 let _ = vec_buf.extend_from_slice(&data);
129
130 // SUM
131 let chk = compute_checksum(vec_buf.clone());
132 let _ = vec_buf.extend_from_slice(&chk.to_be_bytes()[..]);
133
134 // =====
135
136 // Send command buffer.
137 let data_write: [u8; 16] = vec_buf.clone().into_array().unwrap();
138 debug!(" write='{:?}'", data_write[..]);
139 match tx.write(&data_write).await {
140 Ok(..) => info!("Write successful."),
141 Err(e) => error!("Write error: {:?}", e),
142 }
143
144 // =====
145
146 // Read command buffer.
147 let mut read_buf: [u8; 1] = [0; 1]; // Can only read one byte at a time!
148 let mut data_read: Vec<u8, 32> = heapless::Vec::new(); // Save buffer.
149
150 info!("Attempting read.");
151 loop {
152 // Some commands, like `Img2Tz()` needs longer, but we hard-code this to 200ms
153 // for this command.
154 match with_timeout(Duration::from_millis(200), rx.read(&mut read_buf)).await {
155 Ok(..) => {
156 // Extract and save read byte.
157 debug!(" r='{=u8:#04x}H' ({:03}D)", read_buf[0], read_buf[0]);
158 let _ = data_read.push(read_buf[0]).unwrap();
159 }
160 Err(..) => break, // TimeoutError -> Ignore.
161 }
162 }
163 info!("Read successful");
164 debug!(" read='{:?}'", data_read[..]);
165
166 Timer::after_secs(3).await;
167 info!("Changing speed.");
168 }
169
170 info!("Changing colour.");
171 }
172 }
173}
diff --git a/examples/rp23/src/bin/uart_unidir.rs b/examples/rp23/src/bin/uart_unidir.rs
new file mode 100644
index 000000000..988e44a79
--- /dev/null
+++ b/examples/rp23/src/bin/uart_unidir.rs
@@ -0,0 +1,65 @@
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
11use defmt::*;
12use embassy_executor::Spawner;
13use embassy_rp::bind_interrupts;
14use embassy_rp::block::ImageDef;
15use embassy_rp::peripherals::UART1;
16use embassy_rp::uart::{Async, Config, InterruptHandler, UartRx, UartTx};
17use embassy_time::Timer;
18use {defmt_rtt as _, panic_probe as _};
19
20#[link_section = ".start_block"]
21#[used]
22pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
23
24// Program metadata for `picotool info`
25#[link_section = ".bi_entries"]
26#[used]
27pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
28 embassy_rp::binary_info::rp_program_name!(c"example"),
29 embassy_rp::binary_info::rp_cargo_version!(),
30 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
31 embassy_rp::binary_info::rp_program_build_attribute!(),
32];
33
34bind_interrupts!(struct Irqs {
35 UART1_IRQ => InterruptHandler<UART1>;
36});
37
38#[embassy_executor::main]
39async fn main(spawner: Spawner) {
40 let p = embassy_rp::init(Default::default());
41
42 let mut uart_tx = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, Config::default());
43 let uart_rx = UartRx::new(p.UART1, p.PIN_5, Irqs, p.DMA_CH1, Config::default());
44
45 unwrap!(spawner.spawn(reader(uart_rx)));
46
47 info!("Writing...");
48 loop {
49 let data = [1u8, 2, 3, 4, 5, 6, 7, 8];
50 info!("TX {:?}", data);
51 uart_tx.write(&data).await.unwrap();
52 Timer::after_secs(1).await;
53 }
54}
55
56#[embassy_executor::task]
57async fn reader(mut rx: UartRx<'static, UART1, Async>) {
58 info!("Reading...");
59 loop {
60 // read a total of 4 transmissions (32 / 8) and then print the result
61 let mut buf = [0; 32];
62 rx.read(&mut buf).await.unwrap();
63 info!("RX {:?}", buf);
64 }
65}
diff --git a/examples/rp23/src/bin/usb_webusb.rs b/examples/rp23/src/bin/usb_webusb.rs
new file mode 100644
index 000000000..3ade2226b
--- /dev/null
+++ b/examples/rp23/src/bin/usb_webusb.rs
@@ -0,0 +1,170 @@
1//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip.
2//!
3//! This creates a WebUSB capable device that echoes data back to the host.
4//!
5//! To test this in the browser (ideally host this on localhost:8080, to test the landing page
6//! feature):
7//! ```js
8//! (async () => {
9//! const device = await navigator.usb.requestDevice({ filters: [{ vendorId: 0xf569 }] });
10//! await device.open();
11//! await device.claimInterface(1);
12//! device.transferIn(1, 64).then(data => console.log(data));
13//! await device.transferOut(1, new Uint8Array([1,2,3]));
14//! })();
15//! ```
16
17#![no_std]
18#![no_main]
19
20use defmt::info;
21use embassy_executor::Spawner;
22use embassy_futures::join::join;
23use embassy_rp::bind_interrupts;
24use embassy_rp::block::ImageDef;
25use embassy_rp::peripherals::USB;
26use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler};
27use embassy_usb::class::web_usb::{Config as WebUsbConfig, State, Url, WebUsb};
28use embassy_usb::driver::{Driver, Endpoint, EndpointIn, EndpointOut};
29use embassy_usb::msos::{self, windows_version};
30use embassy_usb::{Builder, Config};
31use {defmt_rtt as _, panic_probe as _};
32
33#[link_section = ".start_block"]
34#[used]
35pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
36
37// Program metadata for `picotool info`
38#[link_section = ".bi_entries"]
39#[used]
40pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
41 embassy_rp::binary_info::rp_program_name!(c"example"),
42 embassy_rp::binary_info::rp_cargo_version!(),
43 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
44 embassy_rp::binary_info::rp_program_build_attribute!(),
45];
46
47bind_interrupts!(struct Irqs {
48 USBCTRL_IRQ => InterruptHandler<USB>;
49});
50
51// This is a randomly generated GUID to allow clients on Windows to find our device
52const DEVICE_INTERFACE_GUIDS: &[&str] = &["{AFB9A6FB-30BA-44BC-9232-806CFC875321}"];
53
54#[embassy_executor::main]
55async fn main(_spawner: Spawner) {
56 let p = embassy_rp::init(Default::default());
57
58 // Create the driver, from the HAL.
59 let driver = UsbDriver::new(p.USB, Irqs);
60
61 // Create embassy-usb Config
62 let mut config = Config::new(0xf569, 0x0001);
63 config.manufacturer = Some("Embassy");
64 config.product = Some("WebUSB example");
65 config.serial_number = Some("12345678");
66 config.max_power = 100;
67 config.max_packet_size_0 = 64;
68
69 // Required for windows compatibility.
70 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
71 config.device_class = 0xff;
72 config.device_sub_class = 0x00;
73 config.device_protocol = 0x00;
74
75 // Create embassy-usb DeviceBuilder using the driver and config.
76 // It needs some buffers for building the descriptors.
77 let mut config_descriptor = [0; 256];
78 let mut bos_descriptor = [0; 256];
79 let mut control_buf = [0; 64];
80 let mut msos_descriptor = [0; 256];
81
82 let webusb_config = WebUsbConfig {
83 max_packet_size: 64,
84 vendor_code: 1,
85 // If defined, shows a landing page which the device manufacturer would like the user to visit in order to control their device. Suggest the user to navigate to this URL when the device is connected.
86 landing_url: Some(Url::new("http://localhost:8080")),
87 };
88
89 let mut state = State::new();
90
91 let mut builder = Builder::new(
92 driver,
93 config,
94 &mut config_descriptor,
95 &mut bos_descriptor,
96 &mut msos_descriptor,
97 &mut control_buf,
98 );
99
100 // Add the Microsoft OS Descriptor (MSOS/MOD) descriptor.
101 // We tell Windows that this entire device is compatible with the "WINUSB" feature,
102 // which causes it to use the built-in WinUSB driver automatically, which in turn
103 // can be used by libusb/rusb software without needing a custom driver or INF file.
104 // In principle you might want to call msos_feature() just on a specific function,
105 // if your device also has other functions that still use standard class drivers.
106 builder.msos_descriptor(windows_version::WIN8_1, 0);
107 builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", ""));
108 builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new(
109 "DeviceInterfaceGUIDs",
110 msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
111 ));
112
113 // Create classes on the builder (WebUSB just needs some setup, but doesn't return anything)
114 WebUsb::configure(&mut builder, &mut state, &webusb_config);
115 // Create some USB bulk endpoints for testing.
116 let mut endpoints = WebEndpoints::new(&mut builder, &webusb_config);
117
118 // Build the builder.
119 let mut usb = builder.build();
120
121 // Run the USB device.
122 let usb_fut = usb.run();
123
124 // Do some WebUSB transfers.
125 let webusb_fut = async {
126 loop {
127 endpoints.wait_connected().await;
128 info!("Connected");
129 endpoints.echo().await;
130 }
131 };
132
133 // Run everything concurrently.
134 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
135 join(usb_fut, webusb_fut).await;
136}
137
138struct WebEndpoints<'d, D: Driver<'d>> {
139 write_ep: D::EndpointIn,
140 read_ep: D::EndpointOut,
141}
142
143impl<'d, D: Driver<'d>> WebEndpoints<'d, D> {
144 fn new(builder: &mut Builder<'d, D>, config: &'d WebUsbConfig<'d>) -> Self {
145 let mut func = builder.function(0xff, 0x00, 0x00);
146 let mut iface = func.interface();
147 let mut alt = iface.alt_setting(0xff, 0x00, 0x00, None);
148
149 let write_ep = alt.endpoint_bulk_in(config.max_packet_size);
150 let read_ep = alt.endpoint_bulk_out(config.max_packet_size);
151
152 WebEndpoints { write_ep, read_ep }
153 }
154
155 // Wait until the device's endpoints are enabled.
156 async fn wait_connected(&mut self) {
157 self.read_ep.wait_enabled().await
158 }
159
160 // Echo data back to the host.
161 async fn echo(&mut self) {
162 let mut buf = [0; 64];
163 loop {
164 let n = self.read_ep.read(&mut buf).await.unwrap();
165 let data = &buf[..n];
166 info!("Data read: {:x}", data);
167 self.write_ep.write(data).await.unwrap();
168 }
169 }
170}
diff --git a/examples/rp23/src/bin/watchdog.rs b/examples/rp23/src/bin/watchdog.rs
new file mode 100644
index 000000000..a901c1164
--- /dev/null
+++ b/examples/rp23/src/bin/watchdog.rs
@@ -0,0 +1,66 @@
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
8use defmt::info;
9use embassy_executor::Spawner;
10use embassy_rp::block::ImageDef;
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#[link_section = ".start_block"]
18#[used]
19pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
20
21// Program metadata for `picotool info`
22#[link_section = ".bi_entries"]
23#[used]
24pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
25 embassy_rp::binary_info::rp_program_name!(c"example"),
26 embassy_rp::binary_info::rp_cargo_version!(),
27 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
28 embassy_rp::binary_info::rp_program_build_attribute!(),
29];
30
31#[embassy_executor::main]
32async fn main(_spawner: Spawner) {
33 let p = embassy_rp::init(Default::default());
34 info!("Hello world!");
35
36 let mut watchdog = Watchdog::new(p.WATCHDOG);
37 let mut led = Output::new(p.PIN_25, Level::Low);
38
39 // Set the LED high for 2 seconds so we know when we're about to start the watchdog
40 led.set_high();
41 Timer::after_secs(2).await;
42
43 // Set to watchdog to reset if it's not fed within 1.05 seconds, and start it
44 watchdog.start(Duration::from_millis(1_050));
45 info!("Started the watchdog timer");
46
47 // Blink once a second for 5 seconds, feed the watchdog timer once a second to avoid a reset
48 for _ in 1..=5 {
49 led.set_low();
50 Timer::after_millis(500).await;
51 led.set_high();
52 Timer::after_millis(500).await;
53 info!("Feeding watchdog");
54 watchdog.feed();
55 }
56
57 info!("Stopped feeding, device will reset in 1.05 seconds");
58 // Blink 10 times per second, not feeding the watchdog.
59 // The processor should reset in 1.05 seconds.
60 loop {
61 led.set_low();
62 Timer::after_millis(100).await;
63 led.set_high();
64 Timer::after_millis(100).await;
65 }
66}
diff --git a/examples/rp23/src/bin/zerocopy.rs b/examples/rp23/src/bin/zerocopy.rs
new file mode 100644
index 000000000..86fca6f12
--- /dev/null
+++ b/examples/rp23/src/bin/zerocopy.rs
@@ -0,0 +1,109 @@
1//! This example shows how to use `zerocopy_channel` from `embassy_sync` for
2//! sending large values between two tasks without copying.
3//! The example also shows how to use the RP2040 ADC with DMA.
4#![no_std]
5#![no_main]
6
7use core::sync::atomic::{AtomicU16, Ordering};
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler};
12use embassy_rp::bind_interrupts;
13use embassy_rp::block::ImageDef;
14use embassy_rp::gpio::Pull;
15use embassy_rp::peripherals::DMA_CH0;
16use embassy_sync::blocking_mutex::raw::NoopRawMutex;
17use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender};
18use embassy_time::{Duration, Ticker, Timer};
19use static_cell::StaticCell;
20use {defmt_rtt as _, panic_probe as _};
21
22#[link_section = ".start_block"]
23#[used]
24pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
25
26// Program metadata for `picotool info`
27#[link_section = ".bi_entries"]
28#[used]
29pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
30 embassy_rp::binary_info::rp_program_name!(c"example"),
31 embassy_rp::binary_info::rp_cargo_version!(),
32 embassy_rp::binary_info::rp_program_description!(c"Blinky"),
33 embassy_rp::binary_info::rp_program_build_attribute!(),
34];
35
36type SampleBuffer = [u16; 512];
37
38bind_interrupts!(struct Irqs {
39 ADC_IRQ_FIFO => InterruptHandler;
40});
41
42const BLOCK_SIZE: usize = 512;
43const NUM_BLOCKS: usize = 2;
44static MAX: AtomicU16 = AtomicU16::new(0);
45
46struct AdcParts {
47 adc: Adc<'static, Async>,
48 pin: adc::Channel<'static>,
49 dma: DMA_CH0,
50}
51
52#[embassy_executor::main]
53async fn main(spawner: Spawner) {
54 let p = embassy_rp::init(Default::default());
55 info!("Here we go!");
56
57 let adc_parts = AdcParts {
58 adc: Adc::new(p.ADC, Irqs, Config::default()),
59 pin: adc::Channel::new_pin(p.PIN_29, Pull::None),
60 dma: p.DMA_CH0,
61 };
62
63 static BUF: StaticCell<[SampleBuffer; NUM_BLOCKS]> = StaticCell::new();
64 let buf = BUF.init([[0; BLOCK_SIZE]; NUM_BLOCKS]);
65
66 static CHANNEL: StaticCell<Channel<'_, NoopRawMutex, SampleBuffer>> = StaticCell::new();
67 let channel = CHANNEL.init(Channel::new(buf));
68 let (sender, receiver) = channel.split();
69
70 spawner.must_spawn(consumer(receiver));
71 spawner.must_spawn(producer(sender, adc_parts));
72
73 let mut ticker = Ticker::every(Duration::from_secs(1));
74 loop {
75 ticker.next().await;
76 let max = MAX.load(Ordering::Relaxed);
77 info!("latest block's max value: {:?}", max);
78 }
79}
80
81#[embassy_executor::task]
82async fn producer(mut sender: Sender<'static, NoopRawMutex, SampleBuffer>, mut adc: AdcParts) {
83 loop {
84 // Obtain a free buffer from the channel
85 let buf = sender.send().await;
86
87 // Fill it with data
88 adc.adc.read_many(&mut adc.pin, buf, 1, &mut adc.dma).await.unwrap();
89
90 // Notify the channel that the buffer is now ready to be received
91 sender.send_done();
92 }
93}
94
95#[embassy_executor::task]
96async fn consumer(mut receiver: Receiver<'static, NoopRawMutex, SampleBuffer>) {
97 loop {
98 // Receive a buffer from the channel
99 let buf = receiver.receive().await;
100
101 // Simulate using the data, while the producer is filling up the next buffer
102 Timer::after_micros(1000).await;
103 let max = buf.iter().max().unwrap();
104 MAX.store(*max, Ordering::Relaxed);
105
106 // Notify the channel that the buffer is now ready to be reused
107 receiver.receive_done();
108 }
109}
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml
index 58ea894f3..87491b1d2 100644
--- a/examples/std/Cargo.toml
+++ b/examples/std/Cargo.toml
@@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } 8embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] }
9embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] }
10embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["log", "std", ] } 10embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "std", ] }
11embassy-net = { version = "0.4.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } 11embassy-net = { version = "0.4.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] }
12embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } 12embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" }
13embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]} 13embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]}
diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs
index 59813d8cb..310e7264d 100644
--- a/examples/std/src/bin/net.rs
+++ b/examples/std/src/bin/net.rs
@@ -52,12 +52,7 @@ async fn main_task(spawner: Spawner) {
52 // Init network stack 52 // Init network stack
53 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new(); 53 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
54 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 54 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
55 let stack = &*STACK.init(Stack::new( 55 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
56 device,
57 config,
58 RESOURCES.init(StackResources::<3>::new()),
59 seed,
60 ));
61 56
62 // Launch network task 57 // Launch network task
63 spawner.spawn(net_task(stack)).unwrap(); 58 spawner.spawn(net_task(stack)).unwrap();
diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs
index 3b6a3de37..c9615ef35 100644
--- a/examples/std/src/bin/net_dns.rs
+++ b/examples/std/src/bin/net_dns.rs
@@ -51,12 +51,7 @@ async fn main_task(spawner: Spawner) {
51 // Init network stack 51 // Init network stack
52 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new(); 52 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
53 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 53 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
54 let stack: &Stack<_> = &*STACK.init(Stack::new( 54 let stack: &Stack<_> = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
55 device,
56 config,
57 RESOURCES.init(StackResources::<3>::new()),
58 seed,
59 ));
60 55
61 // Launch network task 56 // Launch network task
62 spawner.spawn(net_task(stack)).unwrap(); 57 spawner.spawn(net_task(stack)).unwrap();
diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs
index 9ec0ea91f..c5c27c4a3 100644
--- a/examples/std/src/bin/net_ppp.rs
+++ b/examples/std/src/bin/net_ppp.rs
@@ -102,7 +102,7 @@ async fn main_task(spawner: Spawner) {
102 let stack = &*STACK.init(Stack::new( 102 let stack = &*STACK.init(Stack::new(
103 device, 103 device,
104 Config::default(), // don't configure IP yet 104 Config::default(), // don't configure IP yet
105 RESOURCES.init(StackResources::<3>::new()), 105 RESOURCES.init(StackResources::new()),
106 seed, 106 seed,
107 )); 107 ));
108 108
diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs
index bee91990d..b2ba4915a 100644
--- a/examples/std/src/bin/net_udp.rs
+++ b/examples/std/src/bin/net_udp.rs
@@ -50,12 +50,7 @@ async fn main_task(spawner: Spawner) {
50 // Init network stack 50 // Init network stack
51 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new(); 51 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
52 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 52 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
53 let stack = &*STACK.init(Stack::new( 53 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
54 device,
55 config,
56 RESOURCES.init(StackResources::<3>::new()),
57 seed,
58 ));
59 54
60 // Launch network task 55 // Launch network task
61 spawner.spawn(net_task(stack)).unwrap(); 56 spawner.spawn(net_task(stack)).unwrap();
diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs
index e8b6eaa6c..39b29a449 100644
--- a/examples/std/src/bin/tcp_accept.rs
+++ b/examples/std/src/bin/tcp_accept.rs
@@ -64,12 +64,7 @@ async fn main_task(spawner: Spawner) {
64 // Init network stack 64 // Init network stack
65 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new(); 65 static STACK: StaticCell<Stack<TunTapDevice>> = StaticCell::new();
66 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 66 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
67 let stack = &*STACK.init(Stack::new( 67 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
68 device,
69 config,
70 RESOURCES.init(StackResources::<3>::new()),
71 seed,
72 ));
73 68
74 // Launch network task 69 // Launch network task
75 spawner.spawn(net_task(stack)).unwrap(); 70 spawner.spawn(net_task(stack)).unwrap();
diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml
index 331046a80..9102467eb 100644
--- a/examples/stm32c0/Cargo.toml
+++ b/examples/stm32c0/Cargo.toml
@@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0"
8# Change stm32c031c6 to your chip name, if necessary. 8# Change stm32c031c6 to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "0.3"
15defmt-rtt = "0.4" 15defmt-rtt = "0.4"
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml
index 15fb55ca7..724efdaff 100644
--- a/examples/stm32f0/Cargo.toml
+++ b/examples/stm32f0/Cargo.toml
@@ -13,8 +13,8 @@ defmt = "0.3"
13defmt-rtt = "0.4" 13defmt-rtt = "0.4"
14panic-probe = { version = "0.3", features = ["print-defmt"] } 14panic-probe = { version = "0.3", features = ["print-defmt"] }
15embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 15embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
16embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 16embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
17embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 17embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
18static_cell = "2" 18static_cell = "2"
19portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } 19portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] }
20 20
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index 38b615795..0084651a3 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0"
8# Change stm32f103c8 to your chip name, if necessary. 8# Change stm32f103c8 to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15 15
16defmt = "0.3" 16defmt = "0.3"
diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml
index ec9b54920..60eb0eb93 100644
--- a/examples/stm32f2/Cargo.toml
+++ b/examples/stm32f2/Cargo.toml
@@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0"
8# Change stm32f207zg to your chip name, if necessary. 8# Change stm32f207zg to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "0.3"
15defmt-rtt = "0.4" 15defmt-rtt = "0.4"
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml
index 62c0fed16..7fda410d9 100644
--- a/examples/stm32f3/Cargo.toml
+++ b/examples/stm32f3/Cargo.toml
@@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0"
8# Change stm32f303ze to your chip name, if necessary. 8# Change stm32f303ze to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15 15
16defmt = "0.3" 16defmt = "0.3"
diff --git a/examples/stm32f3/src/bin/blocking-tsc.rs b/examples/stm32f3/src/bin/blocking-tsc.rs
new file mode 100644
index 000000000..5c8dac94f
--- /dev/null
+++ b/examples/stm32f3/src/bin/blocking-tsc.rs
@@ -0,0 +1,98 @@
1// Example of polling TSC (Touch Sensing Controller) that lights an LED when touch is detected.
2//
3// Suggested physical setup on STM32F303ZE Nucleo board:
4// - Connect a 1000pF capacitor between pin A0 and GND. This is your sampling capacitor.
5// - Connect one end of a 1K resistor to pin A1 and leave the other end loose.
6// The loose end will act as touch sensor which will register your touch.
7//
8// Troubleshooting the setup:
9// - If no touch seems to be registered, then try to disconnect the sampling capacitor from GND momentarily,
10// now the led should light up. Next try using a different value for the sampling capacitor.
11// Also experiment with increasing the values for `ct_pulse_high_length`, `ct_pulse_low_length`, `pulse_generator_prescaler`, `max_count_value` and `discharge_delay`.
12//
13// All configuration values and sampling capacitor value have been determined experimentally.
14// Suitable configuration and discharge delay values are highly dependent on the value of the sample capacitor. For example, a shorter discharge delay can be used with smaller capacitor values.
15//
16#![no_std]
17#![no_main]
18
19use defmt::*;
20use embassy_stm32::gpio::{Level, Output, Speed};
21use embassy_stm32::tsc::{self, *};
22use embassy_time::Timer;
23use {defmt_rtt as _, panic_probe as _};
24
25/// This example is written for the nucleo-stm32f303ze, with a stm32f303ze chip.
26///
27/// Make sure you check/update the following (whether you use the F303ZE or another board):
28///
29/// * [ ] Update .cargo/config.toml with the correct `probe-rs run --chip STM32F303ZETx`chip name.
30/// * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature, for F303ZE it should be `stm32f303ze`.
31/// * [ ] If your board has a special clock or power configuration, make sure that it is
32/// set up appropriately.
33/// * [ ] If your board has different pin mapping, update any pin numbers or peripherals
34/// to match your schematic
35///
36/// If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
37///
38/// * Which example you are trying to run
39/// * Which chip and board you are using
40///
41/// Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
42#[embassy_executor::main]
43async fn main(_spawner: embassy_executor::Spawner) {
44 let device_config = embassy_stm32::Config::default();
45 let context = embassy_stm32::init(device_config);
46
47 let tsc_conf = Config {
48 ct_pulse_high_length: ChargeTransferPulseCycle::_8,
49 ct_pulse_low_length: ChargeTransferPulseCycle::_8,
50 spread_spectrum: false,
51 spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
52 spread_spectrum_prescaler: false,
53 pulse_generator_prescaler: PGPrescalerDivider::_32,
54 max_count_value: MaxCount::_255,
55 io_default_mode: false,
56 synchro_pin_polarity: false,
57 acquisition_mode: false,
58 max_count_interrupt: false,
59 channel_ios: TscIOPin::Group1Io1.into(),
60 shield_ios: 0, // no shield
61 sampling_ios: TscIOPin::Group1Io2.into(),
62 };
63
64 let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new();
65 g1.set_io1(context.PA0, PinType::Sample);
66 g1.set_io2(context.PA1, PinType::Channel);
67
68 let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, Some(g1), None, None, None, None, None, tsc_conf);
69
70 // LED2 on the STM32F303ZE nucleo-board
71 let mut led = Output::new(context.PB7, Level::High, Speed::Low);
72
73 // smaller sample capacitor discharge faster and can be used with shorter delay.
74 let discharge_delay = 5; // ms
75
76 // the interval at which the loop polls for new touch sensor values
77 let polling_interval = 100; // ms
78
79 info!("polling for touch");
80 loop {
81 touch_controller.start();
82 touch_controller.poll_for_acquisition();
83 touch_controller.discharge_io(true);
84 Timer::after_millis(discharge_delay).await;
85
86 let grp1_status = touch_controller.group_get_status(Group::One);
87 match grp1_status {
88 GroupStatus::Complete => {
89 let group_one_val = touch_controller.group_get_value(Group::One);
90 info!("{}", group_one_val);
91 led.set_high();
92 }
93 GroupStatus::Ongoing => led.set_low(),
94 }
95
96 Timer::after_millis(polling_interval).await;
97 }
98}
diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml
index 84c44a7b7..1cc0a97da 100644
--- a/examples/stm32f334/Cargo.toml
+++ b/examples/stm32f334/Cargo.toml
@@ -6,10 +6,10 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
12embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
14 14
15defmt = "0.3" 15defmt = "0.3"
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index d909c7e68..b85361596 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0"
8# Change stm32f429zi to your chip name, if necessary. 8# Change stm32f429zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt" ] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] }
14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } 14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] }
15embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } 15embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
@@ -30,7 +30,7 @@ heapless = { version = "0.8", default-features = false }
30nb = "1.0.0" 30nb = "1.0.0"
31embedded-storage = "0.3.1" 31embedded-storage = "0.3.1"
32micromath = "2.0.0" 32micromath = "2.0.0"
33usbd-hid = "0.7.0" 33usbd-hid = "0.8.1"
34static_cell = "2" 34static_cell = "2"
35chrono = { version = "^0.4", default-features = false} 35chrono = { version = "^0.4", default-features = false}
36 36
diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs
index 648c45bbd..9388c64bf 100644
--- a/examples/stm32f4/src/bin/eth.rs
+++ b/examples/stm32f4/src/bin/eth.rs
@@ -89,13 +89,8 @@ async fn main(spawner: Spawner) -> ! {
89 89
90 // Init network stack 90 // Init network stack
91 static STACK: StaticCell<Stack<Device>> = StaticCell::new(); 91 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
92 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 92 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
93 let stack = &*STACK.init(Stack::new( 93 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
94 device,
95 config,
96 RESOURCES.init(StackResources::<2>::new()),
97 seed,
98 ));
99 94
100 // Launch network task 95 // Launch network task
101 unwrap!(spawner.spawn(net_task(stack))); 96 unwrap!(spawner.spawn(net_task(stack)));
diff --git a/examples/stm32f4/src/bin/eth_w5500.rs b/examples/stm32f4/src/bin/eth_w5500.rs
index 3c770a873..5c3c6c3ba 100644
--- a/examples/stm32f4/src/bin/eth_w5500.rs
+++ b/examples/stm32f4/src/bin/eth_w5500.rs
@@ -93,13 +93,8 @@ async fn main(spawner: Spawner) -> ! {
93 //}); 93 //});
94 94
95 static STACK: StaticCell<Stack<Device>> = StaticCell::new(); 95 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
96 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 96 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
97 let stack = &*STACK.init(Stack::new( 97 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
98 device,
99 config,
100 RESOURCES.init(StackResources::<2>::new()),
101 seed,
102 ));
103 98
104 // Launch network task 99 // Launch network task
105 unwrap!(spawner.spawn(net_task(stack))); 100 unwrap!(spawner.spawn(net_task(stack)));
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
index b398c35da..94e51c338 100644
--- a/examples/stm32f4/src/bin/usb_ethernet.rs
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -145,13 +145,8 @@ async fn main(spawner: Spawner) {
145 145
146 // Init network stack 146 // Init network stack
147 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new(); 147 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new();
148 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 148 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
149 let stack = &*STACK.init(Stack::new( 149 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
150 device,
151 config,
152 RESOURCES.init(StackResources::<2>::new()),
153 seed,
154 ));
155 150
156 unwrap!(spawner.spawn(net_task(stack))); 151 unwrap!(spawner.spawn(net_task(stack)));
157 152
diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml
index 634f13f4e..6a5bd0b29 100644
--- a/examples/stm32f469/Cargo.toml
+++ b/examples/stm32f469/Cargo.toml
@@ -7,8 +7,8 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Specific examples only for stm32f469 8# Specific examples only for stm32f469
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] }
10embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
11embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
12 12
13defmt = "0.3" 13defmt = "0.3"
14defmt-rtt = "0.4" 14defmt-rtt = "0.4"
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index 7fc7d6f42..8c591ebd2 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -8,11 +8,11 @@ license = "MIT OR Apache-2.0"
8# Change stm32f777zi to your chip name, if necessary. 8# Change stm32f777zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
14embedded-io-async = { version = "0.6.1" } 14embedded-io-async = { version = "0.6.1" }
15embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
17 17
18defmt = "0.3" 18defmt = "0.3"
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs
index 41e2a6061..2fd10c8fb 100644
--- a/examples/stm32f7/src/bin/eth.rs
+++ b/examples/stm32f7/src/bin/eth.rs
@@ -90,13 +90,8 @@ async fn main(spawner: Spawner) -> ! {
90 90
91 // Init network stack 91 // Init network stack
92 static STACK: StaticCell<Stack<Device>> = StaticCell::new(); 92 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
93 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 93 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
94 let stack = &*STACK.init(Stack::new( 94 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
95 device,
96 config,
97 RESOURCES.init(StackResources::<2>::new()),
98 seed,
99 ));
100 95
101 // Launch network task 96 // Launch network task
102 unwrap!(spawner.spawn(net_task(stack))); 97 unwrap!(spawner.spawn(net_task(stack)));
diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml
index b9d710ca7..a50074ce0 100644
--- a/examples/stm32g0/Cargo.toml
+++ b/examples/stm32g0/Cargo.toml
@@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0"
8# Change stm32g0b1re to your chip name, if necessary. 8# Change stm32g0b1re to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.2.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15 15
16defmt = "0.3" 16defmt = "0.3"
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index ac6010f5f..2768147a1 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -8,11 +8,11 @@ license = "MIT OR Apache-2.0"
8# Change stm32g491re to your chip name, if necessary. 8# Change stm32g491re to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15usbd-hid = "0.7.0" 15usbd-hid = "0.8.1"
16 16
17defmt = "0.3" 17defmt = "0.3"
18defmt-rtt = "0.4" 18defmt-rtt = "0.4"
diff --git a/examples/stm32g4/src/bin/adc_differential.rs b/examples/stm32g4/src/bin/adc_differential.rs
new file mode 100644
index 000000000..78d071d45
--- /dev/null
+++ b/examples/stm32g4/src/bin/adc_differential.rs
@@ -0,0 +1,47 @@
1//! adc differential mode example
2//!
3//! This example uses adc1 in differential mode
4//! p:pa0 n:pa1
5
6#![no_std]
7#![no_main]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_stm32::adc::{Adc, SampleTime};
12use embassy_stm32::Config;
13use embassy_time::Timer;
14use {defmt_rtt as _, panic_probe as _};
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut config = Config::default();
19 {
20 use embassy_stm32::rcc::*;
21 config.rcc.pll = Some(Pll {
22 source: PllSource::HSI,
23 prediv: PllPreDiv::DIV4,
24 mul: PllMul::MUL85,
25 divp: None,
26 divq: None,
27 // Main system clock at 170 MHz
28 divr: Some(PllRDiv::DIV2),
29 });
30 config.rcc.mux.adc12sel = mux::Adcsel::SYS;
31 config.rcc.sys = Sysclk::PLL1_R;
32 }
33 let mut p = embassy_stm32::init(config);
34
35 let mut adc = Adc::new(p.ADC1);
36 adc.set_sample_time(SampleTime::CYCLES247_5);
37 adc.set_differential(&mut p.PA0, true); //p:pa0,n:pa1
38
39 // can also use
40 // adc.set_differential_channel(1, true);
41 info!("adc initialized");
42 loop {
43 let measured = adc.blocking_read(&mut p.PA0);
44 info!("data: {}", measured);
45 Timer::after_millis(500).await;
46 }
47}
diff --git a/examples/stm32g4/src/bin/adc_oversampling.rs b/examples/stm32g4/src/bin/adc_oversampling.rs
new file mode 100644
index 000000000..d31eb20f8
--- /dev/null
+++ b/examples/stm32g4/src/bin/adc_oversampling.rs
@@ -0,0 +1,57 @@
1//! adc oversampling example
2//!
3//! This example uses adc oversampling to achieve 16bit data
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_stm32::adc::vals::{Rovsm, Trovs};
11use embassy_stm32::adc::{Adc, SampleTime};
12use embassy_stm32::Config;
13use embassy_time::Timer;
14use {defmt_rtt as _, panic_probe as _};
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut config = Config::default();
19 {
20 use embassy_stm32::rcc::*;
21 config.rcc.pll = Some(Pll {
22 source: PllSource::HSI,
23 prediv: PllPreDiv::DIV4,
24 mul: PllMul::MUL85,
25 divp: None,
26 divq: None,
27 // Main system clock at 170 MHz
28 divr: Some(PllRDiv::DIV2),
29 });
30 config.rcc.mux.adc12sel = mux::Adcsel::SYS;
31 config.rcc.sys = Sysclk::PLL1_R;
32 }
33 let mut p = embassy_stm32::init(config);
34
35 let mut adc = Adc::new(p.ADC1);
36 adc.set_sample_time(SampleTime::CYCLES6_5);
37 // From https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
38 // page652 Oversampler
39 // Table 172. Maximum output results vs N and M. Grayed values indicates truncation
40 // 0x00 oversampling ratio X2
41 // 0x01 oversampling ratio X4
42 // 0x02 oversampling ratio X8
43 // 0x03 oversampling ratio X16
44 // 0x04 oversampling ratio X32
45 // 0x05 oversampling ratio X64
46 // 0x06 oversampling ratio X128
47 // 0x07 oversampling ratio X256
48 adc.set_oversampling_ratio(0x03); // ratio X3
49 adc.set_oversampling_shift(0b0000); // no shift
50 adc.enable_regular_oversampling_mode(Rovsm::RESUMED, Trovs::AUTOMATIC, true);
51
52 loop {
53 let measured = adc.blocking_read(&mut p.PA0);
54 info!("data: 0x{:X}", measured); //max 0xFFF0 -> 65520
55 Timer::after_millis(500).await;
56 }
57}
diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs
index 7caea634f..2e87d3931 100644
--- a/examples/stm32g4/src/bin/usb_c_pd.rs
+++ b/examples/stm32g4/src/bin/usb_c_pd.rs
@@ -55,7 +55,7 @@ async fn main(_spawner: Spawner) {
55 55
56 info!("Hello World!"); 56 info!("Hello World!");
57 57
58 let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB6, p.PB4); 58 let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB6, p.PB4, Default::default());
59 ucpd.cc_phy().set_pull(CcPull::Sink); 59 ucpd.cc_phy().set_pull(CcPull::Sink);
60 60
61 info!("Waiting for USB connection..."); 61 info!("Waiting for USB connection...");
diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml
index 59d3a9759..30b1d2be9 100644
--- a/examples/stm32h5/Cargo.toml
+++ b/examples/stm32h5/Cargo.toml
@@ -8,10 +8,10 @@ license = "MIT OR Apache-2.0"
8# Change stm32h563zi to your chip name, if necessary. 8# Change stm32h563zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } 13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] }
14embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
16 16
17defmt = "0.3" 17defmt = "0.3"
diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs
index 2370656e6..65cfad8c9 100644
--- a/examples/stm32h5/src/bin/eth.rs
+++ b/examples/stm32h5/src/bin/eth.rs
@@ -93,13 +93,8 @@ async fn main(spawner: Spawner) -> ! {
93 93
94 // Init network stack 94 // Init network stack
95 static STACK: StaticCell<Stack<Device>> = StaticCell::new(); 95 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
96 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 96 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
97 let stack = &*STACK.init(Stack::new( 97 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
98 device,
99 config,
100 RESOURCES.init(StackResources::<2>::new()),
101 seed,
102 ));
103 98
104 // Launch network task 99 // Launch network task
105 unwrap!(spawner.spawn(net_task(&stack))); 100 unwrap!(spawner.spawn(net_task(&stack)));
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index 0584f3916..13fce7dc7 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -8,11 +8,11 @@ license = "MIT OR Apache-2.0"
8# Change stm32h743bi to your chip name, if necessary. 8# Change stm32h743bi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 11embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
12embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 12embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
13embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } 14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
15embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
17 17
18defmt = "0.3" 18defmt = "0.3"
@@ -34,6 +34,7 @@ stm32-fmc = "0.3.0"
34embedded-storage = "0.3.1" 34embedded-storage = "0.3.1"
35static_cell = "2" 35static_cell = "2"
36chrono = { version = "^0.4", default-features = false } 36chrono = { version = "^0.4", default-features = false }
37grounded = "0.2.0"
37 38
38# cargo build/run 39# cargo build/run
39[profile.dev] 40[profile.dev]
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index 7c7964ecd..b2f8ed91e 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -93,12 +93,7 @@ async fn main(spawner: Spawner) -> ! {
93 // Init network stack 93 // Init network stack
94 static STACK: StaticCell<Stack<Device>> = StaticCell::new(); 94 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
95 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 95 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
96 let stack = &*STACK.init(Stack::new( 96 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
97 device,
98 config,
99 RESOURCES.init(StackResources::<3>::new()),
100 seed,
101 ));
102 97
103 // Launch network task 98 // Launch network task
104 unwrap!(spawner.spawn(net_task(&stack))); 99 unwrap!(spawner.spawn(net_task(&stack)));
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index 0639fb99f..274c24ab1 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -93,12 +93,7 @@ async fn main(spawner: Spawner) -> ! {
93 // Init network stack 93 // Init network stack
94 static STACK: StaticCell<Stack<Device>> = StaticCell::new(); 94 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
95 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 95 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
96 let stack = &*STACK.init(Stack::new( 96 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
97 device,
98 config,
99 RESOURCES.init(StackResources::<3>::new()),
100 seed,
101 ));
102 97
103 // Launch network task 98 // Launch network task
104 unwrap!(spawner.spawn(net_task(stack))); 99 unwrap!(spawner.spawn(net_task(stack)));
diff --git a/examples/stm32h7/src/bin/eth_client_mii.rs b/examples/stm32h7/src/bin/eth_client_mii.rs
index 9a52e8d3b..aa6544f41 100644
--- a/examples/stm32h7/src/bin/eth_client_mii.rs
+++ b/examples/stm32h7/src/bin/eth_client_mii.rs
@@ -99,12 +99,7 @@ async fn main(spawner: Spawner) -> ! {
99 // Init network stack 99 // Init network stack
100 static STACK: StaticCell<Stack<Device>> = StaticCell::new(); 100 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
101 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new(); 101 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
102 let stack = &*STACK.init(Stack::new( 102 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
103 device,
104 config,
105 RESOURCES.init(StackResources::<3>::new()),
106 seed,
107 ));
108 103
109 // Launch network task 104 // Launch network task
110 unwrap!(spawner.spawn(net_task(stack))); 105 unwrap!(spawner.spawn(net_task(stack)));
diff --git a/examples/stm32h7/src/bin/sai.rs b/examples/stm32h7/src/bin/sai.rs
new file mode 100644
index 000000000..f6735e235
--- /dev/null
+++ b/examples/stm32h7/src/bin/sai.rs
@@ -0,0 +1,186 @@
1//! Daisy Seed rev.7(with PCM3060 codec)
2//! https://electro-smith.com/products/daisy-seed
3#![no_std]
4#![no_main]
5
6use embassy_executor::Spawner;
7use grounded::uninit::GroundedArrayCell;
8use hal::rcc::*;
9use hal::sai::*;
10use hal::time::Hertz;
11use {defmt_rtt as _, embassy_stm32 as hal, panic_probe as _};
12
13const BLOCK_LENGTH: usize = 32; // 32 samples
14const HALF_DMA_BUFFER_LENGTH: usize = BLOCK_LENGTH * 2; // 2 channels
15const DMA_BUFFER_LENGTH: usize = HALF_DMA_BUFFER_LENGTH * 2; // 2 half-blocks
16const SAMPLE_RATE: u32 = 48000;
17
18//DMA buffer must be in special region. Refer https://embassy.dev/book/#_stm32_bdma_only_working_out_of_some_ram_regions
19#[link_section = ".sram1_bss"]
20static mut TX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit();
21#[link_section = ".sram1_bss"]
22static mut RX_BUFFER: GroundedArrayCell<u32, DMA_BUFFER_LENGTH> = GroundedArrayCell::uninit();
23
24#[embassy_executor::main]
25async fn main(_spawner: Spawner) {
26 let mut config = hal::Config::default();
27 config.rcc.pll1 = Some(Pll {
28 source: PllSource::HSE,
29 prediv: PllPreDiv::DIV4,
30 mul: PllMul::MUL200,
31 divp: Some(PllDiv::DIV2),
32 divq: Some(PllDiv::DIV5),
33 divr: Some(PllDiv::DIV2),
34 });
35 config.rcc.pll3 = Some(Pll {
36 source: PllSource::HSE,
37 prediv: PllPreDiv::DIV6,
38 mul: PllMul::MUL295,
39 divp: Some(PllDiv::DIV16),
40 divq: Some(PllDiv::DIV4),
41 divr: Some(PllDiv::DIV32),
42 });
43 config.rcc.sys = Sysclk::PLL1_P;
44 config.rcc.mux.sai1sel = hal::pac::rcc::vals::Saisel::PLL3_P;
45 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
46 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
47 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
48 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
49 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
50 config.rcc.hse = Some(Hse {
51 freq: Hertz::mhz(16),
52 mode: HseMode::Oscillator,
53 });
54
55 let p = hal::init(config);
56
57 let (sub_block_tx, sub_block_rx) = hal::sai::split_subblocks(p.SAI1);
58 let kernel_clock = hal::rcc::frequency::<hal::peripherals::SAI1>().0;
59 let mclk_div = mclk_div_from_u8((kernel_clock / (SAMPLE_RATE * 256)) as u8);
60
61 let mut tx_config = hal::sai::Config::default();
62 tx_config.mode = Mode::Master;
63 tx_config.tx_rx = TxRx::Transmitter;
64 tx_config.sync_output = true;
65 tx_config.clock_strobe = ClockStrobe::Falling;
66 tx_config.master_clock_divider = mclk_div;
67 tx_config.stereo_mono = StereoMono::Stereo;
68 tx_config.data_size = DataSize::Data24;
69 tx_config.bit_order = BitOrder::MsbFirst;
70 tx_config.frame_sync_polarity = FrameSyncPolarity::ActiveHigh;
71 tx_config.frame_sync_offset = FrameSyncOffset::OnFirstBit;
72 tx_config.frame_length = 64;
73 tx_config.frame_sync_active_level_length = embassy_stm32::sai::word::U7(32);
74 tx_config.fifo_threshold = FifoThreshold::Quarter;
75
76 let mut rx_config = tx_config.clone();
77 rx_config.mode = Mode::Slave;
78 rx_config.tx_rx = TxRx::Receiver;
79 rx_config.sync_input = SyncInput::Internal;
80 rx_config.clock_strobe = ClockStrobe::Rising;
81 rx_config.sync_output = false;
82
83 let tx_buffer: &mut [u32] = unsafe {
84 TX_BUFFER.initialize_all_copied(0);
85 let (ptr, len) = TX_BUFFER.get_ptr_len();
86 core::slice::from_raw_parts_mut(ptr, len)
87 };
88
89 let mut sai_transmitter = Sai::new_asynchronous_with_mclk(
90 sub_block_tx,
91 p.PE5,
92 p.PE6,
93 p.PE4,
94 p.PE2,
95 p.DMA1_CH0,
96 tx_buffer,
97 tx_config,
98 );
99
100 let rx_buffer: &mut [u32] = unsafe {
101 RX_BUFFER.initialize_all_copied(0);
102 let (ptr, len) = RX_BUFFER.get_ptr_len();
103 core::slice::from_raw_parts_mut(ptr, len)
104 };
105
106 let mut sai_receiver = Sai::new_synchronous(sub_block_rx, p.PE3, p.DMA1_CH1, rx_buffer, rx_config);
107
108 sai_receiver.start();
109 sai_transmitter.start();
110
111 let mut buf = [0u32; HALF_DMA_BUFFER_LENGTH];
112
113 loop {
114 sai_receiver.read(&mut buf).await.unwrap();
115 sai_transmitter.write(&buf).await.unwrap();
116 }
117}
118
119const fn mclk_div_from_u8(v: u8) -> MasterClockDivider {
120 match v {
121 1 => MasterClockDivider::Div1,
122 2 => MasterClockDivider::Div2,
123 3 => MasterClockDivider::Div3,
124 4 => MasterClockDivider::Div4,
125 5 => MasterClockDivider::Div5,
126 6 => MasterClockDivider::Div6,
127 7 => MasterClockDivider::Div7,
128 8 => MasterClockDivider::Div8,
129 9 => MasterClockDivider::Div9,
130 10 => MasterClockDivider::Div10,
131 11 => MasterClockDivider::Div11,
132 12 => MasterClockDivider::Div12,
133 13 => MasterClockDivider::Div13,
134 14 => MasterClockDivider::Div14,
135 15 => MasterClockDivider::Div15,
136 16 => MasterClockDivider::Div16,
137 17 => MasterClockDivider::Div17,
138 18 => MasterClockDivider::Div18,
139 19 => MasterClockDivider::Div19,
140 20 => MasterClockDivider::Div20,
141 21 => MasterClockDivider::Div21,
142 22 => MasterClockDivider::Div22,
143 23 => MasterClockDivider::Div23,
144 24 => MasterClockDivider::Div24,
145 25 => MasterClockDivider::Div25,
146 26 => MasterClockDivider::Div26,
147 27 => MasterClockDivider::Div27,
148 28 => MasterClockDivider::Div28,
149 29 => MasterClockDivider::Div29,
150 30 => MasterClockDivider::Div30,
151 31 => MasterClockDivider::Div31,
152 32 => MasterClockDivider::Div32,
153 33 => MasterClockDivider::Div33,
154 34 => MasterClockDivider::Div34,
155 35 => MasterClockDivider::Div35,
156 36 => MasterClockDivider::Div36,
157 37 => MasterClockDivider::Div37,
158 38 => MasterClockDivider::Div38,
159 39 => MasterClockDivider::Div39,
160 40 => MasterClockDivider::Div40,
161 41 => MasterClockDivider::Div41,
162 42 => MasterClockDivider::Div42,
163 43 => MasterClockDivider::Div43,
164 44 => MasterClockDivider::Div44,
165 45 => MasterClockDivider::Div45,
166 46 => MasterClockDivider::Div46,
167 47 => MasterClockDivider::Div47,
168 48 => MasterClockDivider::Div48,
169 49 => MasterClockDivider::Div49,
170 50 => MasterClockDivider::Div50,
171 51 => MasterClockDivider::Div51,
172 52 => MasterClockDivider::Div52,
173 53 => MasterClockDivider::Div53,
174 54 => MasterClockDivider::Div54,
175 55 => MasterClockDivider::Div55,
176 56 => MasterClockDivider::Div56,
177 57 => MasterClockDivider::Div57,
178 58 => MasterClockDivider::Div58,
179 59 => MasterClockDivider::Div59,
180 60 => MasterClockDivider::Div60,
181 61 => MasterClockDivider::Div61,
182 62 => MasterClockDivider::Div62,
183 63 => MasterClockDivider::Div63,
184 _ => panic!(),
185 }
186}
diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs
index b2e941078..43fb6b41c 100644
--- a/examples/stm32h7/src/bin/spi_bdma.rs
+++ b/examples/stm32h7/src/bin/spi_bdma.rs
@@ -10,18 +10,24 @@ use embassy_executor::Executor;
10use embassy_stm32::mode::Async; 10use embassy_stm32::mode::Async;
11use embassy_stm32::time::mhz; 11use embassy_stm32::time::mhz;
12use embassy_stm32::{spi, Config}; 12use embassy_stm32::{spi, Config};
13use grounded::uninit::GroundedArrayCell;
13use heapless::String; 14use heapless::String;
14use static_cell::StaticCell; 15use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _}; 16use {defmt_rtt as _, panic_probe as _};
16 17
17// Defined in memory.x 18// Defined in memory.x
18#[link_section = ".ram_d3"] 19#[link_section = ".ram_d3"]
19static mut RAM_D3: [u8; 64 * 1024] = [0u8; 64 * 1024]; 20static mut RAM_D3: GroundedArrayCell<u8, 256> = GroundedArrayCell::uninit();
20 21
21#[embassy_executor::task] 22#[embassy_executor::task]
22async fn main_task(mut spi: spi::Spi<'static, Async>) { 23async fn main_task(mut spi: spi::Spi<'static, Async>) {
23 let read_buffer = unsafe { &mut RAM_D3[0..128] }; 24 let (read_buffer, write_buffer) = unsafe {
24 let write_buffer = unsafe { &mut RAM_D3[128..256] }; 25 RAM_D3.initialize_all_copied(0);
26 (
27 RAM_D3.get_subslice_mut_unchecked(0, 128),
28 RAM_D3.get_subslice_mut_unchecked(128, 128),
29 )
30 };
25 31
26 for n in 0u32.. { 32 for n in 0u32.. {
27 let mut write: String<128> = String::new(); 33 let mut write: String<128> = String::new();
diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml
index fc21cc894..93e9575b6 100644
--- a/examples/stm32h735/Cargo.toml
+++ b/examples/stm32h735/Cargo.toml
@@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } 8embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
9embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 10embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
14 14
15defmt = "0.3" 15defmt = "0.3"
diff --git a/examples/stm32h755cm4/.cargo/config.toml b/examples/stm32h755cm4/.cargo/config.toml
new file mode 100644
index 000000000..193e6bbc3
--- /dev/null
+++ b/examples/stm32h755cm4/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.thumbv7em-none-eabihf]
2runner = 'probe-rs run --chip STM32H755ZITx --catch-hardfault --always-print-stacktrace'
3
4[build]
5target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml
new file mode 100644
index 000000000..7a42fbdaa
--- /dev/null
+++ b/examples/stm32h755cm4/Cargo.toml
@@ -0,0 +1,75 @@
1[package]
2edition = "2021"
3name = "embassy-stm32h755cm4-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8# Change stm32h755zi-cm4 to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
12embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
13embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
15embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
17
18defmt = "0.3"
19defmt-rtt = "0.4"
20
21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
22cortex-m-rt = "0.7.0"
23embedded-hal = "0.2.6"
24embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
25embedded-hal-async = { version = "1.0" }
26embedded-nal-async = { version = "0.7.1" }
27embedded-io-async = { version = "0.6.1" }
28panic-probe = { version = "0.3", features = ["print-defmt"] }
29heapless = { version = "0.8", default-features = false }
30rand_core = "0.6.3"
31critical-section = "1.1"
32micromath = "2.0.0"
33stm32-fmc = "0.3.0"
34embedded-storage = "0.3.1"
35static_cell = "2"
36chrono = { version = "^0.4", default-features = false }
37grounded = "0.2.0"
38
39# cargo build/run
40[profile.dev]
41codegen-units = 1
42debug = 2
43debug-assertions = true # <-
44incremental = false
45opt-level = 3 # <-
46overflow-checks = true # <-
47
48# cargo test
49[profile.test]
50codegen-units = 1
51debug = 2
52debug-assertions = true # <-
53incremental = false
54opt-level = 3 # <-
55overflow-checks = true # <-
56
57# cargo build/run --release
58[profile.release]
59codegen-units = 1
60debug = 2
61debug-assertions = false # <-
62incremental = false
63lto = 'fat'
64opt-level = 3 # <-
65overflow-checks = false # <-
66
67# cargo test --release
68[profile.bench]
69codegen-units = 1
70debug = 2
71debug-assertions = false # <-
72incremental = false
73lto = 'fat'
74opt-level = 3 # <-
75overflow-checks = false # <-
diff --git a/examples/stm32h755cm4/build.rs b/examples/stm32h755cm4/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/stm32h755cm4/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/stm32h755cm4/memory.x b/examples/stm32h755cm4/memory.x
new file mode 100644
index 000000000..7d60354e3
--- /dev/null
+++ b/examples/stm32h755cm4/memory.x
@@ -0,0 +1,15 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x08100000, LENGTH = 1024K /* BANK_2 */
4 RAM : ORIGIN = 0x10000000, LENGTH = 128K /* SRAM1 */
5 RAM_D3 : ORIGIN = 0x38000000, LENGTH = 64K /* SRAM4 */
6}
7
8SECTIONS
9{
10 .ram_d3 :
11 {
12 *(.ram_d3.shared_data)
13 *(.ram_d3)
14 } > RAM_D3
15} \ No newline at end of file
diff --git a/examples/stm32h755cm4/src/bin/blinky.rs b/examples/stm32h755cm4/src/bin/blinky.rs
new file mode 100644
index 000000000..b5c547839
--- /dev/null
+++ b/examples/stm32h755cm4/src/bin/blinky.rs
@@ -0,0 +1,32 @@
1#![no_std]
2#![no_main]
3
4use core::mem::MaybeUninit;
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_stm32::gpio::{Level, Output, Speed};
9use embassy_stm32::SharedData;
10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _};
12
13#[link_section = ".ram_d3.shared_data"]
14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let p = embassy_stm32::init_secondary(&SHARED_DATA);
19 info!("Hello World!");
20
21 let mut led = Output::new(p.PE1, Level::High, Speed::Low);
22
23 loop {
24 info!("high");
25 led.set_high();
26 Timer::after_millis(250).await;
27
28 info!("low");
29 led.set_low();
30 Timer::after_millis(250).await;
31 }
32}
diff --git a/examples/stm32h755cm7/.cargo/config.toml b/examples/stm32h755cm7/.cargo/config.toml
new file mode 100644
index 000000000..193e6bbc3
--- /dev/null
+++ b/examples/stm32h755cm7/.cargo/config.toml
@@ -0,0 +1,8 @@
1[target.thumbv7em-none-eabihf]
2runner = 'probe-rs run --chip STM32H755ZITx --catch-hardfault --always-print-stacktrace'
3
4[build]
5target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
6
7[env]
8DEFMT_LOG = "trace"
diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml
new file mode 100644
index 000000000..4f0f69c3f
--- /dev/null
+++ b/examples/stm32h755cm7/Cargo.toml
@@ -0,0 +1,75 @@
1[package]
2edition = "2021"
3name = "embassy-stm32h755cm7-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6
7[dependencies]
8# Change stm32h743bi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
12embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
13embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
15embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
16embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
17
18defmt = "0.3"
19defmt-rtt = "0.4"
20
21cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
22cortex-m-rt = "0.7.0"
23embedded-hal = "0.2.6"
24embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
25embedded-hal-async = { version = "1.0" }
26embedded-nal-async = { version = "0.7.1" }
27embedded-io-async = { version = "0.6.1" }
28panic-probe = { version = "0.3", features = ["print-defmt"] }
29heapless = { version = "0.8", default-features = false }
30rand_core = "0.6.3"
31critical-section = "1.1"
32micromath = "2.0.0"
33stm32-fmc = "0.3.0"
34embedded-storage = "0.3.1"
35static_cell = "2"
36chrono = { version = "^0.4", default-features = false }
37grounded = "0.2.0"
38
39# cargo build/run
40[profile.dev]
41codegen-units = 1
42debug = 2
43debug-assertions = true # <-
44incremental = false
45opt-level = 3 # <-
46overflow-checks = true # <-
47
48# cargo test
49[profile.test]
50codegen-units = 1
51debug = 2
52debug-assertions = true # <-
53incremental = false
54opt-level = 3 # <-
55overflow-checks = true # <-
56
57# cargo build/run --release
58[profile.release]
59codegen-units = 1
60debug = 2
61debug-assertions = false # <-
62incremental = false
63lto = 'fat'
64opt-level = 3 # <-
65overflow-checks = false # <-
66
67# cargo test --release
68[profile.bench]
69codegen-units = 1
70debug = 2
71debug-assertions = false # <-
72incremental = false
73lto = 'fat'
74opt-level = 3 # <-
75overflow-checks = false # <-
diff --git a/examples/stm32h755cm7/build.rs b/examples/stm32h755cm7/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/stm32h755cm7/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/stm32h755cm7/memory.x b/examples/stm32h755cm7/memory.x
new file mode 100644
index 000000000..ef884796a
--- /dev/null
+++ b/examples/stm32h755cm7/memory.x
@@ -0,0 +1,15 @@
1MEMORY
2{
3 FLASH : ORIGIN = 0x08000000, LENGTH = 1024K /* BANK_1 */
4 RAM : ORIGIN = 0x24000000, LENGTH = 512K /* AXIRAM */
5 RAM_D3 : ORIGIN = 0x38000000, LENGTH = 64K /* SRAM4 */
6}
7
8SECTIONS
9{
10 .ram_d3 :
11 {
12 *(.ram_d3.shared_data)
13 *(.ram_d3)
14 } > RAM_D3
15} \ No newline at end of file
diff --git a/examples/stm32h755cm7/src/bin/blinky.rs b/examples/stm32h755cm7/src/bin/blinky.rs
new file mode 100644
index 000000000..94d2226c0
--- /dev/null
+++ b/examples/stm32h755cm7/src/bin/blinky.rs
@@ -0,0 +1,54 @@
1#![no_std]
2#![no_main]
3
4use core::mem::MaybeUninit;
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_stm32::gpio::{Level, Output, Speed};
9use embassy_stm32::SharedData;
10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _};
12
13#[link_section = ".ram_d3.shared_data"]
14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut config = embassy_stm32::Config::default();
19 {
20 use embassy_stm32::rcc::*;
21 config.rcc.hsi = Some(HSIPrescaler::DIV1);
22 config.rcc.csi = true;
23 config.rcc.pll1 = Some(Pll {
24 source: PllSource::HSI,
25 prediv: PllPreDiv::DIV4,
26 mul: PllMul::MUL50,
27 divp: Some(PllDiv::DIV2),
28 divq: Some(PllDiv::DIV8), // 100mhz
29 divr: None,
30 });
31 config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz
32 config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
33 config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
34 config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
35 config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
36 config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
37 config.rcc.voltage_scale = VoltageScale::Scale1;
38 config.rcc.supply_config = SupplyConfig::DirectSMPS;
39 }
40 let p = embassy_stm32::init_primary(config, &SHARED_DATA);
41 info!("Hello World!");
42
43 let mut led = Output::new(p.PB14, Level::High, Speed::Low);
44
45 loop {
46 info!("high");
47 led.set_high();
48 Timer::after_millis(500).await;
49
50 info!("low");
51 led.set_low();
52 Timer::after_millis(500).await;
53 }
54}
diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml
index 13d33320f..f97dfd722 100644
--- a/examples/stm32h7rs/Cargo.toml
+++ b/examples/stm32h7rs/Cargo.toml
@@ -8,10 +8,10 @@ license = "MIT OR Apache-2.0"
8# Change stm32h743bi to your chip name, if necessary. 8# Change stm32h743bi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } 13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
14embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
16 16
17defmt = "0.3" 17defmt = "0.3"
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index 5b0519ac4..2577f19e0 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0"
8# Change stm32l072cz to your chip name, if necessary. 8# Change stm32l072cz to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "unstable-pac", "time-driver-any", "exti", "memory-x"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "0.3"
15defmt-rtt = "0.4" 15defmt-rtt = "0.4"
diff --git a/examples/stm32l0/src/bin/async-tsc.rs b/examples/stm32l0/src/bin/async-tsc.rs
new file mode 100644
index 000000000..c40b86af9
--- /dev/null
+++ b/examples/stm32l0/src/bin/async-tsc.rs
@@ -0,0 +1,122 @@
1// Example of async TSC (Touch Sensing Controller) that lights an LED when touch is detected.
2//
3// Suggested physical setup on STM32L073RZ Nucleo board:
4// - Connect a 1000pF capacitor between pin A0 and GND. This is your sampling capacitor.
5// - Connect one end of a 1K resistor to pin A1 and leave the other end loose.
6// The loose end will act as touch sensor which will register your touch.
7//
8// Troubleshooting the setup:
9// - If no touch seems to be registered, then try to disconnect the sampling capacitor from GND momentarily,
10// now the led should light up. Next try using a different value for the sampling capacitor.
11// Also experiment with increasing the values for `ct_pulse_high_length`, `ct_pulse_low_length`, `pulse_generator_prescaler`, `max_count_value` and `discharge_delay`.
12//
13// All configuration values and sampling capacitor value have been determined experimentally.
14// Suitable configuration and discharge delay values are highly dependent on the value of the sample capacitor. For example, a shorter discharge delay can be used with smaller capacitor values.
15//
16#![no_std]
17#![no_main]
18
19use defmt::*;
20use embassy_stm32::bind_interrupts;
21use embassy_stm32::gpio::{Level, Output, Speed};
22use embassy_stm32::tsc::{self, *};
23use embassy_time::Timer;
24use {defmt_rtt as _, panic_probe as _};
25
26bind_interrupts!(struct Irqs {
27 TSC => InterruptHandler<embassy_stm32::peripherals::TSC>;
28});
29
30#[cortex_m_rt::exception]
31unsafe fn HardFault(_: &cortex_m_rt::ExceptionFrame) -> ! {
32 cortex_m::peripheral::SCB::sys_reset();
33}
34
35/// This example is written for the nucleo-stm32l073rz, with a stm32l073rz chip.
36///
37/// Make sure you check/update the following (whether you use the L073RZ or another board):
38///
39/// * [ ] Update .cargo/config.toml with the correct `probe-rs run --chip STM32L073RZTx`chip name.
40/// * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature, for L073RZ it should be `stm32l073rz`.
41/// * [ ] If your board has a special clock or power configuration, make sure that it is
42/// set up appropriately.
43/// * [ ] If your board has different pin mapping, update any pin numbers or peripherals
44/// to match your schematic
45///
46/// If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
47///
48/// * Which example you are trying to run
49/// * Which chip and board you are using
50///
51/// Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
52#[embassy_executor::main]
53async fn main(_spawner: embassy_executor::Spawner) {
54 let device_config = embassy_stm32::Config::default();
55 let context = embassy_stm32::init(device_config);
56
57 let config = tsc::Config {
58 ct_pulse_high_length: ChargeTransferPulseCycle::_4,
59 ct_pulse_low_length: ChargeTransferPulseCycle::_4,
60 spread_spectrum: false,
61 spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
62 spread_spectrum_prescaler: false,
63 pulse_generator_prescaler: PGPrescalerDivider::_16,
64 max_count_value: MaxCount::_255,
65 io_default_mode: false,
66 synchro_pin_polarity: false,
67 acquisition_mode: false,
68 max_count_interrupt: false,
69 channel_ios: TscIOPin::Group1Io1.into(),
70 shield_ios: 0, // no shield
71 sampling_ios: TscIOPin::Group1Io2.into(),
72 };
73
74 let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new();
75 g1.set_io1(context.PA0, PinType::Sample);
76 g1.set_io2(context.PA1, PinType::Channel);
77
78 let mut touch_controller = tsc::Tsc::new_async(
79 context.TSC,
80 Some(g1),
81 None,
82 None,
83 None,
84 None,
85 None,
86 None,
87 None,
88 config,
89 Irqs,
90 );
91
92 // Check if TSC is ready
93 if touch_controller.get_state() != State::Ready {
94 info!("TSC not ready!");
95 loop {} // Halt execution
96 }
97 info!("TSC initialized successfully");
98
99 // LED2 on the STM32L073RZ nucleo-board (PA5)
100 let mut led = Output::new(context.PA5, Level::High, Speed::Low);
101
102 // smaller sample capacitor discharge faster and can be used with shorter delay.
103 let discharge_delay = 5; // ms
104
105 info!("Starting touch_controller interface");
106 loop {
107 touch_controller.start();
108 touch_controller.pend_for_acquisition().await;
109 touch_controller.discharge_io(true);
110 Timer::after_millis(discharge_delay).await;
111
112 let grp1_status = touch_controller.group_get_status(Group::One);
113 match grp1_status {
114 GroupStatus::Complete => {
115 let group_one_val = touch_controller.group_get_value(Group::One);
116 info!("{}", group_one_val);
117 led.set_high();
118 }
119 GroupStatus::Ongoing => led.set_low(),
120 }
121 }
122}
diff --git a/examples/stm32l0/src/bin/blocking-tsc.rs b/examples/stm32l0/src/bin/blocking-tsc.rs
new file mode 100644
index 000000000..7e4f40946
--- /dev/null
+++ b/examples/stm32l0/src/bin/blocking-tsc.rs
@@ -0,0 +1,116 @@
1// Example of polling TSC (Touch Sensing Controller) that lights an LED when touch is detected.
2//
3// Suggested physical setup on STM32L073RZ Nucleo board:
4// - Connect a 1000pF capacitor between pin A0 and GND. This is your sampling capacitor.
5// - Connect one end of a 1K resistor to pin A1 and leave the other end loose.
6// The loose end will act as touch sensor which will register your touch.
7//
8// Troubleshooting the setup:
9// - If no touch seems to be registered, then try to disconnect the sampling capacitor from GND momentarily,
10// now the led should light up. Next try using a different value for the sampling capacitor.
11// Also experiment with increasing the values for `ct_pulse_high_length`, `ct_pulse_low_length`, `pulse_generator_prescaler`, `max_count_value` and `discharge_delay`.
12//
13// All configuration values and sampling capacitor value have been determined experimentally.
14// Suitable configuration and discharge delay values are highly dependent on the value of the sample capacitor. For example, a shorter discharge delay can be used with smaller capacitor values.
15//
16#![no_std]
17#![no_main]
18
19use defmt::*;
20use embassy_stm32::gpio::{Level, Output, Speed};
21use embassy_stm32::tsc::{self, *};
22use embassy_time::Timer;
23use {defmt_rtt as _, panic_probe as _};
24
25/// This example is written for the nucleo-stm32l073rz, with a stm32l073rz chip.
26///
27/// Make sure you check/update the following (whether you use the L073RZ or another board):
28///
29/// * [ ] Update .cargo/config.toml with the correct `probe-rs run --chip STM32L073RZTx`chip name.
30/// * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature, for L073RZ it should be `stm32l073rz`.
31/// * [ ] If your board has a special clock or power configuration, make sure that it is
32/// set up appropriately.
33/// * [ ] If your board has different pin mapping, update any pin numbers or peripherals
34/// to match your schematic
35///
36/// If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
37///
38/// * Which example you are trying to run
39/// * Which chip and board you are using
40///
41/// Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
42#[embassy_executor::main]
43async fn main(_spawner: embassy_executor::Spawner) {
44 let device_config = embassy_stm32::Config::default();
45 let context = embassy_stm32::init(device_config);
46
47 let tsc_conf = Config {
48 ct_pulse_high_length: ChargeTransferPulseCycle::_4,
49 ct_pulse_low_length: ChargeTransferPulseCycle::_4,
50 spread_spectrum: false,
51 spread_spectrum_deviation: SSDeviation::new(2).unwrap(),
52 spread_spectrum_prescaler: false,
53 pulse_generator_prescaler: PGPrescalerDivider::_16,
54 max_count_value: MaxCount::_255,
55 io_default_mode: false,
56 synchro_pin_polarity: false,
57 acquisition_mode: false,
58 max_count_interrupt: false,
59 channel_ios: TscIOPin::Group1Io1.into(),
60 shield_ios: 0, // no shield
61 sampling_ios: TscIOPin::Group1Io2.into(),
62 };
63
64 let mut g1: PinGroup<embassy_stm32::peripherals::TSC, G1> = PinGroup::new();
65 g1.set_io1(context.PA0, PinType::Sample);
66 g1.set_io2(context.PA1, PinType::Channel);
67
68 let mut touch_controller = tsc::Tsc::new_blocking(
69 context.TSC,
70 Some(g1),
71 None,
72 None,
73 None,
74 None,
75 None,
76 None,
77 None,
78 tsc_conf,
79 );
80
81 // Check if TSC is ready
82 if touch_controller.get_state() != State::Ready {
83 info!("TSC not ready!");
84 loop {} // Halt execution
85 }
86 info!("TSC initialized successfully");
87
88 // LED2 on the STM32L073RZ nucleo-board (PA5)
89 let mut led = Output::new(context.PA5, Level::High, Speed::Low);
90
91 // smaller sample capacitor discharge faster and can be used with shorter delay.
92 let discharge_delay = 5; // ms
93
94 // the interval at which the loop polls for new touch sensor values
95 let polling_interval = 100; // ms
96
97 info!("polling for touch");
98 loop {
99 touch_controller.start();
100 touch_controller.poll_for_acquisition();
101 touch_controller.discharge_io(true);
102 Timer::after_millis(discharge_delay).await;
103
104 let grp1_status = touch_controller.group_get_status(Group::One);
105 match grp1_status {
106 GroupStatus::Complete => {
107 let group_one_val = touch_controller.group_get_value(Group::One);
108 info!("{}", group_one_val);
109 led.set_high();
110 }
111 GroupStatus::Ongoing => led.set_low(),
112 }
113
114 Timer::after_millis(polling_interval).await;
115 }
116}
diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml
index 9e4ceac6a..062044f32 100644
--- a/examples/stm32l1/Cargo.toml
+++ b/examples/stm32l1/Cargo.toml
@@ -6,10 +6,10 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
10embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] }
12embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
14 14
15defmt = "0.3" 15defmt = "0.3"
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index de2b2bd4d..c5478b17b 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -8,10 +8,10 @@ license = "MIT OR Apache-2.0"
8# Change stm32l4s5vi to your chip name, if necessary. 8# Change stm32l4s5vi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
14embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
15embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } 15embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" }
16embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } 16embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] }
17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 17embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
index 33149144c..bd633cecb 100644
--- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
+++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs
@@ -207,13 +207,8 @@ async fn main(spawner: Spawner) {
207 207
208 // Init network stack 208 // Init network stack
209 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new(); 209 static STACK: StaticCell<Stack<Device<'static>>> = StaticCell::new();
210 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 210 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
211 let stack = &*STACK.init(Stack::new( 211 let stack = &*STACK.init(Stack::new(device, ip_cfg, RESOURCES.init(StackResources::new()), seed));
212 device,
213 ip_cfg,
214 RESOURCES.init(StackResources::<2>::new()),
215 seed,
216 ));
217 212
218 // Launch network task 213 // Launch network task
219 unwrap!(spawner.spawn(net_task(stack))); 214 unwrap!(spawner.spawn(net_task(stack)));
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index e4a3c8e9c..16c184de2 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -8,12 +8,12 @@ license = "MIT OR Apache-2.0"
8# Change stm32l552ze to your chip name, if necessary. 8# Change stm32l552ze to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 15embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
16usbd-hid = "0.7.0" 16usbd-hid = "0.8.1"
17 17
18defmt = "0.3" 18defmt = "0.3"
19defmt-rtt = "0.4" 19defmt-rtt = "0.4"
diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs
index 7f73fd677..d02bac91d 100644
--- a/examples/stm32l5/src/bin/usb_ethernet.rs
+++ b/examples/stm32l5/src/bin/usb_ethernet.rs
@@ -122,13 +122,8 @@ async fn main(spawner: Spawner) {
122 122
123 // Init network stack 123 // Init network stack
124 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new(); 124 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new();
125 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 125 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
126 let stack = &*STACK.init(Stack::new( 126 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
127 device,
128 config,
129 RESOURCES.init(StackResources::<2>::new()),
130 seed,
131 ));
132 127
133 unwrap!(spawner.spawn(net_task(stack))); 128 unwrap!(spawner.spawn(net_task(stack)));
134 129
diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml
index afeb4dc34..2e890cdb5 100644
--- a/examples/stm32u0/Cargo.toml
+++ b/examples/stm32u0/Cargo.toml
@@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0"
8# Change stm32u083rc to your chip name, if necessary. 8# Change stm32u083rc to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.2.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15 15
16defmt = "0.3" 16defmt = "0.3"
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml
index d0134b972..20d64c6f7 100644
--- a/examples/stm32u5/Cargo.toml
+++ b/examples/stm32u5/Cargo.toml
@@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0"
8# Change stm32u585ai to your chip name, if necessary. 8# Change stm32u585ai to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15 15
16defmt = "0.3" 16defmt = "0.3"
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index c3a11b14b..1e1a0efe2 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -9,8 +9,8 @@ license = "MIT OR Apache-2.0"
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] }
10embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } 10embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] }
11embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 11embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
12embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 12embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
13embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } 14embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true }
15 15
16defmt = "0.3" 16defmt = "0.3"
diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml
index dc788e15b..401281c0b 100644
--- a/examples/stm32wba/Cargo.toml
+++ b/examples/stm32wba/Cargo.toml
@@ -7,8 +7,8 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } 8embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] }
9embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
11embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
12embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } 12embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true }
13 13
14defmt = "0.3" 14defmt = "0.3"
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml
index 3ea7d0cbe..46af5218c 100644
--- a/examples/stm32wl/Cargo.toml
+++ b/examples/stm32wl/Cargo.toml
@@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0"
8# Change stm32wl55jc-cm4 to your chip name, if necessary. 8# Change stm32wl55jc-cm4 to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] }
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
14 14
15defmt = "0.3" 15defmt = "0.3"
16defmt-rtt = "0.4" 16defmt-rtt = "0.4"
diff --git a/examples/stm32wl/memory.x b/examples/stm32wl/memory.x
new file mode 100644
index 000000000..4590867a8
--- /dev/null
+++ b/examples/stm32wl/memory.x
@@ -0,0 +1,15 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 FLASH : ORIGIN = 0x08000000, LENGTH = 256K
5 SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128
6 RAM (rwx) : ORIGIN = 0x20000080, LENGTH = 64K - 128
7}
8
9SECTIONS
10{
11 .shared_data :
12 {
13 *(.shared_data)
14 } > SHARED_RAM
15}
diff --git a/examples/stm32wl/src/bin/blinky.rs b/examples/stm32wl/src/bin/blinky.rs
index 347bd093f..ce7d0ec58 100644
--- a/examples/stm32wl/src/bin/blinky.rs
+++ b/examples/stm32wl/src/bin/blinky.rs
@@ -1,15 +1,21 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem::MaybeUninit;
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Speed}; 8use embassy_stm32::gpio::{Level, Output, Speed};
9use embassy_stm32::SharedData;
7use embassy_time::Timer; 10use embassy_time::Timer;
8use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
9 12
13#[link_section = ".shared_data"]
14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
15
10#[embassy_executor::main] 16#[embassy_executor::main]
11async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA);
13 info!("Hello World!"); 19 info!("Hello World!");
14 20
15 let mut led = Output::new(p.PB15, Level::High, Speed::Low); 21 let mut led = Output::new(p.PB15, Level::High, Speed::Low);
diff --git a/examples/stm32wl/src/bin/button.rs b/examples/stm32wl/src/bin/button.rs
index eccd211e2..8b5204479 100644
--- a/examples/stm32wl/src/bin/button.rs
+++ b/examples/stm32wl/src/bin/button.rs
@@ -1,16 +1,22 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem::MaybeUninit;
5
4use cortex_m_rt::entry; 6use cortex_m_rt::entry;
5use defmt::*; 7use defmt::*;
6use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 8use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed};
9use embassy_stm32::SharedData;
7use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
8 11
12#[link_section = ".shared_data"]
13static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
14
9#[entry] 15#[entry]
10fn main() -> ! { 16fn main() -> ! {
11 info!("Hello World!"); 17 info!("Hello World!");
12 18
13 let p = embassy_stm32::init(Default::default()); 19 let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA);
14 20
15 let button = Input::new(p.PA0, Pull::Up); 21 let button = Input::new(p.PA0, Pull::Up);
16 let mut led1 = Output::new(p.PB15, Level::High, Speed::Low); 22 let mut led1 = Output::new(p.PB15, Level::High, Speed::Low);
diff --git a/examples/stm32wl/src/bin/button_exti.rs b/examples/stm32wl/src/bin/button_exti.rs
index 27d5330bd..8dd1a6a5e 100644
--- a/examples/stm32wl/src/bin/button_exti.rs
+++ b/examples/stm32wl/src/bin/button_exti.rs
@@ -1,15 +1,21 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem::MaybeUninit;
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_stm32::exti::ExtiInput; 8use embassy_stm32::exti::ExtiInput;
7use embassy_stm32::gpio::Pull; 9use embassy_stm32::gpio::Pull;
10use embassy_stm32::SharedData;
8use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
9 12
13#[link_section = ".shared_data"]
14static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
15
10#[embassy_executor::main] 16#[embassy_executor::main]
11async fn main(_spawner: Spawner) { 17async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default()); 18 let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA);
13 info!("Hello World!"); 19 info!("Hello World!");
14 20
15 let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Up); 21 let mut button = ExtiInput::new(p.PA0, p.EXTI0, Pull::Up);
diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs
index 0b7417c01..147f5d293 100644
--- a/examples/stm32wl/src/bin/flash.rs
+++ b/examples/stm32wl/src/bin/flash.rs
@@ -1,14 +1,20 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem::MaybeUninit;
5
4use defmt::{info, unwrap}; 6use defmt::{info, unwrap};
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_stm32::flash::Flash; 8use embassy_stm32::flash::Flash;
9use embassy_stm32::SharedData;
7use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
8 11
12#[link_section = ".shared_data"]
13static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
14
9#[embassy_executor::main] 15#[embassy_executor::main]
10async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
11 let p = embassy_stm32::init(Default::default()); 17 let p = embassy_stm32::init_primary(Default::default(), &SHARED_DATA);
12 info!("Hello Flash!"); 18 info!("Hello Flash!");
13 19
14 const ADDR: u32 = 0x36000; 20 const ADDR: u32 = 0x36000;
diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs
index 8e9fe02b2..df2ed0054 100644
--- a/examples/stm32wl/src/bin/random.rs
+++ b/examples/stm32wl/src/bin/random.rs
@@ -1,17 +1,22 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem::MaybeUninit;
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_stm32::rng::{self, Rng}; 8use embassy_stm32::rng::{self, Rng};
7use embassy_stm32::time::Hertz; 9use embassy_stm32::time::Hertz;
8use embassy_stm32::{bind_interrupts, peripherals}; 10use embassy_stm32::{bind_interrupts, peripherals, SharedData};
9use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
10 12
11bind_interrupts!(struct Irqs{ 13bind_interrupts!(struct Irqs{
12 RNG => rng::InterruptHandler<peripherals::RNG>; 14 RNG => rng::InterruptHandler<peripherals::RNG>;
13}); 15});
14 16
17#[link_section = ".shared_data"]
18static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
19
15#[embassy_executor::main] 20#[embassy_executor::main]
16async fn main(_spawner: Spawner) { 21async fn main(_spawner: Spawner) {
17 let mut config = embassy_stm32::Config::default(); 22 let mut config = embassy_stm32::Config::default();
@@ -32,7 +37,7 @@ async fn main(_spawner: Spawner) {
32 divr: Some(PllRDiv::DIV2), // sysclk 48Mhz clock (32 / 2 * 6 / 2) 37 divr: Some(PllRDiv::DIV2), // sysclk 48Mhz clock (32 / 2 * 6 / 2)
33 }); 38 });
34 } 39 }
35 let p = embassy_stm32::init(config); 40 let p = embassy_stm32::init_primary(config, &SHARED_DATA);
36 41
37 info!("Hello World!"); 42 info!("Hello World!");
38 43
diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs
index cf7d6d220..69a9ddc4c 100644
--- a/examples/stm32wl/src/bin/rtc.rs
+++ b/examples/stm32wl/src/bin/rtc.rs
@@ -1,15 +1,20 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem::MaybeUninit;
5
4use chrono::{NaiveDate, NaiveDateTime}; 6use chrono::{NaiveDate, NaiveDateTime};
5use defmt::*; 7use defmt::*;
6use embassy_executor::Spawner; 8use embassy_executor::Spawner;
7use embassy_stm32::rtc::{Rtc, RtcConfig}; 9use embassy_stm32::rtc::{Rtc, RtcConfig};
8use embassy_stm32::time::Hertz; 10use embassy_stm32::time::Hertz;
9use embassy_stm32::Config; 11use embassy_stm32::{Config, SharedData};
10use embassy_time::Timer; 12use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
12 14
15#[link_section = ".shared_data"]
16static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
17
13#[embassy_executor::main] 18#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 19async fn main(_spawner: Spawner) {
15 let mut config = Config::default(); 20 let mut config = Config::default();
@@ -31,7 +36,7 @@ async fn main(_spawner: Spawner) {
31 divr: Some(PllRDiv::DIV2), // sysclk 48Mhz clock (32 / 2 * 6 / 2) 36 divr: Some(PllRDiv::DIV2), // sysclk 48Mhz clock (32 / 2 * 6 / 2)
32 }); 37 });
33 } 38 }
34 let p = embassy_stm32::init(config); 39 let p = embassy_stm32::init_primary(config, &SHARED_DATA);
35 info!("Hello World!"); 40 info!("Hello World!");
36 41
37 let now = NaiveDate::from_ymd_opt(2020, 5, 15) 42 let now = NaiveDate::from_ymd_opt(2020, 5, 15)
diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs
index 3637243a0..ece9b9201 100644
--- a/examples/stm32wl/src/bin/uart_async.rs
+++ b/examples/stm32wl/src/bin/uart_async.rs
@@ -1,10 +1,12 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem::MaybeUninit;
5
4use defmt::*; 6use defmt::*;
5use embassy_executor::Spawner; 7use embassy_executor::Spawner;
6use embassy_stm32::usart::{Config, InterruptHandler, Uart}; 8use embassy_stm32::usart::{Config, InterruptHandler, Uart};
7use embassy_stm32::{bind_interrupts, peripherals}; 9use embassy_stm32::{bind_interrupts, peripherals, SharedData};
8use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
9 11
10bind_interrupts!(struct Irqs{ 12bind_interrupts!(struct Irqs{
@@ -12,6 +14,9 @@ bind_interrupts!(struct Irqs{
12 LPUART1 => InterruptHandler<peripherals::LPUART1>; 14 LPUART1 => InterruptHandler<peripherals::LPUART1>;
13}); 15});
14 16
17#[link_section = ".shared_data"]
18static SHARED_DATA: MaybeUninit<SharedData> = MaybeUninit::uninit();
19
15/* 20/*
16Pass Incoming data from LPUART1 to USART1 21Pass Incoming data from LPUART1 to USART1
17Example is written for the LoRa-E5 mini v1.0, 22Example is written for the LoRa-E5 mini v1.0,
@@ -21,7 +26,7 @@ but can be surely changed for your needs.
21async fn main(_spawner: Spawner) { 26async fn main(_spawner: Spawner) {
22 let mut config = embassy_stm32::Config::default(); 27 let mut config = embassy_stm32::Config::default();
23 config.rcc.sys = embassy_stm32::rcc::Sysclk::HSE; 28 config.rcc.sys = embassy_stm32::rcc::Sysclk::HSE;
24 let p = embassy_stm32::init(config); 29 let p = embassy_stm32::init_primary(config, &SHARED_DATA);
25 30
26 defmt::info!("Starting system"); 31 defmt::info!("Starting system");
27 32
diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml
index 9d7acc175..75de079b7 100644
--- a/examples/wasm/Cargo.toml
+++ b/examples/wasm/Cargo.toml
@@ -9,14 +9,13 @@ crate-type = ["cdylib"]
9 9
10[dependencies] 10[dependencies]
11embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } 11embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] }
12embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } 12embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] }
13embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["log", "wasm", ] } 13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "wasm", ] }
14 14
15wasm-logger = "0.2.0" 15wasm-logger = "0.2.0"
16wasm-bindgen = "0.2" 16wasm-bindgen = "0.2"
17web-sys = { version = "0.3", features = ["Document", "Element", "HtmlElement", "Node", "Window" ] } 17web-sys = { version = "0.3", features = ["Document", "Element", "HtmlElement", "Node", "Window" ] }
18log = "0.4.11" 18log = "0.4.11"
19critical-section = { version = "1.1", features = ["std"] }
20 19
21[profile.release] 20[profile.release]
22debug = 2 21debug = 2
diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml
index d965d67dd..0b10d7194 100644
--- a/rust-toolchain-nightly.toml
+++ b/rust-toolchain-nightly.toml
@@ -1,5 +1,5 @@
1[toolchain] 1[toolchain]
2channel = "nightly-2024-06-18" 2channel = "nightly-2024-09-06"
3components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] 3components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ]
4targets = [ 4targets = [
5 "thumbv7em-none-eabi", 5 "thumbv7em-none-eabi",
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index 037fc5c6a..80acb3b5e 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,5 +1,5 @@
1[toolchain] 1[toolchain]
2channel = "1.79" 2channel = "1.81"
3components = [ "rust-src", "rustfmt", "llvm-tools" ] 3components = [ "rust-src", "rustfmt", "llvm-tools" ]
4targets = [ 4targets = [
5 "thumbv7em-none-eabi", 5 "thumbv7em-none-eabi",
diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml
index c714e8f7e..f666634d5 100644
--- a/tests/nrf/Cargo.toml
+++ b/tests/nrf/Cargo.toml
@@ -9,9 +9,9 @@ teleprobe-meta = "1"
9 9
10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
11embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt", ] } 11embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt", ] }
12embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] } 12embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] }
13embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
14embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } 14embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] }
15embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 15embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
16embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } 16embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] }
17embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } 17embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] }
diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
index 5f4220b1e..304754c0e 100644
--- a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
+++ b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
@@ -67,12 +67,7 @@ async fn main(spawner: Spawner) {
67 // Init network stack 67 // Init network stack
68 static STACK: StaticCell<Stack<MyDriver>> = StaticCell::new(); 68 static STACK: StaticCell<Stack<MyDriver>> = StaticCell::new();
69 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 69 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
70 let stack = &*STACK.init(Stack::new( 70 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
71 device,
72 config,
73 RESOURCES.init(StackResources::<2>::new()),
74 seed,
75 ));
76 71
77 unwrap!(spawner.spawn(net_task(stack))); 72 unwrap!(spawner.spawn(net_task(stack)));
78 73
diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
index a6c93c8a6..6632442f1 100644
--- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
+++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
@@ -91,7 +91,7 @@ async fn main(spawner: Spawner) {
91 let stack = &*STACK.init(Stack::new( 91 let stack = &*STACK.init(Stack::new(
92 device, 92 device,
93 Config::dhcpv4(Default::default()), 93 Config::dhcpv4(Default::default()),
94 RESOURCES.init(StackResources::<2>::new()), 94 RESOURCES.init(StackResources::new()),
95 seed, 95 seed,
96 )); 96 ));
97 97
diff --git a/tests/perf-client/Cargo.toml b/tests/perf-client/Cargo.toml
index 6ecc2d5e1..eb2a33a30 100644
--- a/tests/perf-client/Cargo.toml
+++ b/tests/perf-client/Cargo.toml
@@ -5,6 +5,6 @@ edition = "2021"
5 5
6[dependencies] 6[dependencies]
7embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] } 7embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] }
8embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", ] } 8embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] }
9embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 9embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
10defmt = "0.3.0" 10defmt = "0.3.0"
diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml
index 4f1d3e5c6..ae2b0e180 100644
--- a/tests/riscv32/Cargo.toml
+++ b/tests/riscv32/Cargo.toml
@@ -7,8 +7,8 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8critical-section = { version = "1.1.1", features = ["restore-state-bool"] } 8critical-section = { version = "1.1.1", features = ["restore-state-bool"] }
9embassy-sync = { version = "0.6.0", path = "../../embassy-sync" } 9embassy-sync = { version = "0.6.0", path = "../../embassy-sync" }
10embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] } 10embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] }
11embassy-time = { version = "0.3.1", path = "../../embassy-time" } 11embassy-time = { version = "0.3.2", path = "../../embassy-time" }
12embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 12embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
13 13
14riscv-rt = "0.12.2" 14riscv-rt = "0.12.2"
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index 45050ee0e..12f1ec3ce 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -8,13 +8,13 @@ license = "MIT OR Apache-2.0"
8teleprobe-meta = "1.1" 8teleprobe-meta = "1.1"
9 9
10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", ] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] }
13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } 13embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } 15embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] }
16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } 16embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] }
17embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal/"} 17embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal/"}
18cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } 18cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] }
19cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } 19cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] }
20perf-client = { path = "../perf-client" } 20perf-client = { path = "../perf-client" }
diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs
index 53c84e711..11c8aa58c 100644
--- a/tests/rp/src/bin/cyw43-perf.rs
+++ b/tests/rp/src/bin/cyw43-perf.rs
@@ -2,6 +2,7 @@
2#![no_main] 2#![no_main]
3teleprobe_meta::target!(b"rpi-pico"); 3teleprobe_meta::target!(b"rpi-pico");
4 4
5use cyw43::JoinOptions;
5use cyw43_pio::PioSpi; 6use cyw43_pio::PioSpi;
6use defmt::{panic, *}; 7use defmt::{panic, *};
7use embassy_executor::Spawner; 8use embassy_executor::Spawner;
@@ -74,14 +75,17 @@ async fn main(spawner: Spawner) {
74 let stack = &*STACK.init(Stack::new( 75 let stack = &*STACK.init(Stack::new(
75 net_device, 76 net_device,
76 Config::dhcpv4(Default::default()), 77 Config::dhcpv4(Default::default()),
77 RESOURCES.init(StackResources::<2>::new()), 78 RESOURCES.init(StackResources::new()),
78 seed, 79 seed,
79 )); 80 ));
80 81
81 unwrap!(spawner.spawn(net_task(stack))); 82 unwrap!(spawner.spawn(net_task(stack)));
82 83
83 loop { 84 loop {
84 match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await { 85 match control
86 .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes()))
87 .await
88 {
85 Ok(_) => break, 89 Ok(_) => break,
86 Err(err) => { 90 Err(err) => {
87 panic!("join failed with status={}", err.status); 91 panic!("join failed with status={}", err.status);
diff --git a/tests/rp/src/bin/ethernet_w5100s_perf.rs b/tests/rp/src/bin/ethernet_w5100s_perf.rs
index 4b04571bd..f15f33743 100644
--- a/tests/rp/src/bin/ethernet_w5100s_perf.rs
+++ b/tests/rp/src/bin/ethernet_w5100s_perf.rs
@@ -72,7 +72,7 @@ async fn main(spawner: Spawner) {
72 let stack = &*STACK.init(Stack::new( 72 let stack = &*STACK.init(Stack::new(
73 device, 73 device,
74 embassy_net::Config::dhcpv4(Default::default()), 74 embassy_net::Config::dhcpv4(Default::default()),
75 RESOURCES.init(StackResources::<2>::new()), 75 RESOURCES.init(StackResources::new()),
76 seed, 76 seed,
77 )); 77 ));
78 78
diff --git a/tests/rp/src/bin/timer.rs b/tests/rp/src/bin/timer.rs
new file mode 100644
index 000000000..be9242144
--- /dev/null
+++ b/tests/rp/src/bin/timer.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3teleprobe_meta::target!(b"rpi-pico");
4
5use defmt::{assert, *};
6use embassy_executor::Spawner;
7use embassy_time::{Instant, Timer};
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let _p = embassy_rp::init(Default::default());
13 info!("Hello World!");
14
15 let start = Instant::now();
16 Timer::after_millis(100).await;
17 let end = Instant::now();
18 let ms = (end - start).as_millis();
19 info!("slept for {} ms", ms);
20 assert!(ms >= 99);
21 assert!(ms < 110);
22
23 info!("Test OK");
24 cortex_m::asm::bkpt();
25}
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index f94814e70..2eac636e5 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -60,8 +60,8 @@ cm0 = ["portable-atomic/unsafe-assume-single-core"]
60teleprobe-meta = "1" 60teleprobe-meta = "1"
61 61
62embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } 62embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] }
63embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 63embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
64embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } 64embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] }
65embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } 65embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] }
66embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 66embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
67embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } 67embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] }
diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs
index ba8a33e34..85a5f8d83 100644
--- a/tests/stm32/src/bin/can.rs
+++ b/tests/stm32/src/bin/can.rs
@@ -27,7 +27,7 @@ bind_interrupts!(struct Irqs {
27 27
28#[embassy_executor::main] 28#[embassy_executor::main]
29async fn main(_spawner: Spawner) { 29async fn main(_spawner: Spawner) {
30 let p = embassy_stm32::init(config()); 30 let p = init();
31 info!("Hello World!"); 31 info!("Hello World!");
32 32
33 let options = TestOptions { 33 let options = TestOptions {
diff --git a/tests/stm32/src/bin/cordic.rs b/tests/stm32/src/bin/cordic.rs
index e09226de8..879ad56b6 100644
--- a/tests/stm32/src/bin/cordic.rs
+++ b/tests/stm32/src/bin/cordic.rs
@@ -29,7 +29,7 @@ const OUTPUT_LENGTH: usize = (INPUT_U32_COUNT - 1) * 2;
29 29
30#[embassy_executor::main] 30#[embassy_executor::main]
31async fn main(_spawner: Spawner) { 31async fn main(_spawner: Spawner) {
32 let dp = embassy_stm32::init(config()); 32 let dp = init();
33 33
34 // 34 //
35 // use RNG generate random Q1.31 value 35 // use RNG generate random Q1.31 value
diff --git a/tests/stm32/src/bin/cryp.rs b/tests/stm32/src/bin/cryp.rs
index 60778bdaa..028775ac8 100644
--- a/tests/stm32/src/bin/cryp.rs
+++ b/tests/stm32/src/bin/cryp.rs
@@ -20,7 +20,7 @@ bind_interrupts!(struct Irqs {
20 20
21#[embassy_executor::main] 21#[embassy_executor::main]
22async fn main(_spawner: Spawner) { 22async fn main(_spawner: Spawner) {
23 let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); 23 let p: embassy_stm32::Peripherals = init();
24 24
25 const PAYLOAD1: &[u8] = b"payload data 1 ;zdfhzdfhS;GKJASBDG;ASKDJBAL,zdfhzdfhzdfhzdfhvljhb,jhbjhb,sdhsdghsdhsfhsghzdfhzdfhzdfhzdfdhsdthsthsdhsgaadfhhgkdgfuoyguoft6783567"; 25 const PAYLOAD1: &[u8] = b"payload data 1 ;zdfhzdfhS;GKJASBDG;ASKDJBAL,zdfhzdfhzdfhzdfhvljhb,jhbjhb,sdhsdghsdhsfhsghzdfhzdfhzdfhzdfdhsdthsthsdhsgaadfhhgkdgfuoyguoft6783567";
26 const PAYLOAD2: &[u8] = b"payload data 2 ;SKEzdfhzdfhzbhgvljhb,jhbjhb,sdhsdghsdhsfhsghshsfhshstsdthadfhsdfjhsfgjsfgjxfgjzdhgDFghSDGHjtfjtjszftjzsdtjhstdsdhsdhsdhsdhsdthsthsdhsgfh"; 26 const PAYLOAD2: &[u8] = b"payload data 2 ;SKEzdfhzdfhzbhgvljhb,jhbjhb,sdhsdghsdhsfhsghshsfhshstsdthadfhsdfjhsfgjsfgjxfgjzdhgDFghSDGHjtfjtjszftjzsdtjhstdsdhsdhsdhsdhsdthsthsdhsgfh";
diff --git a/tests/stm32/src/bin/dac.rs b/tests/stm32/src/bin/dac.rs
index 86a68c530..88e661525 100644
--- a/tests/stm32/src/bin/dac.rs
+++ b/tests/stm32/src/bin/dac.rs
@@ -20,7 +20,7 @@ use {defmt_rtt as _, panic_probe as _};
20#[embassy_executor::main] 20#[embassy_executor::main]
21async fn main(_spawner: Spawner) { 21async fn main(_spawner: Spawner) {
22 // Initialize the board and obtain a Peripherals instance 22 // Initialize the board and obtain a Peripherals instance
23 let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); 23 let p: embassy_stm32::Peripherals = init();
24 24
25 let adc = peri!(p, ADC); 25 let adc = peri!(p, ADC);
26 let dac = peri!(p, DAC); 26 let dac = peri!(p, DAC);
diff --git a/tests/stm32/src/bin/dac_l1.rs b/tests/stm32/src/bin/dac_l1.rs
index d5e9c9722..925db617d 100644
--- a/tests/stm32/src/bin/dac_l1.rs
+++ b/tests/stm32/src/bin/dac_l1.rs
@@ -25,7 +25,7 @@ bind_interrupts!(struct Irqs {
25#[embassy_executor::main] 25#[embassy_executor::main]
26async fn main(_spawner: Spawner) { 26async fn main(_spawner: Spawner) {
27 // Initialize the board and obtain a Peripherals instance 27 // Initialize the board and obtain a Peripherals instance
28 let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); 28 let p: embassy_stm32::Peripherals = init();
29 29
30 let adc = peri!(p, ADC); 30 let adc = peri!(p, ADC);
31 let dac = peri!(p, DAC); 31 let dac = peri!(p, DAC);
diff --git a/tests/stm32/src/bin/eth.rs b/tests/stm32/src/bin/eth.rs
index 7c02f0354..9da514881 100644
--- a/tests/stm32/src/bin/eth.rs
+++ b/tests/stm32/src/bin/eth.rs
@@ -38,7 +38,7 @@ async fn net_task(stack: &'static Stack<Device>) -> ! {
38 38
39#[embassy_executor::main] 39#[embassy_executor::main]
40async fn main(spawner: Spawner) { 40async fn main(spawner: Spawner) {
41 let p = embassy_stm32::init(config()); 41 let p = init();
42 info!("Hello World!"); 42 info!("Hello World!");
43 43
44 // Generate random seed. 44 // Generate random seed.
@@ -101,12 +101,7 @@ async fn main(spawner: Spawner) {
101 // Init network stack 101 // Init network stack
102 static STACK: StaticCell<Stack<Device>> = StaticCell::new(); 102 static STACK: StaticCell<Stack<Device>> = StaticCell::new();
103 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 103 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new();
104 let stack = &*STACK.init(Stack::new( 104 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
105 device,
106 config,
107 RESOURCES.init(StackResources::<2>::new()),
108 seed,
109 ));
110 105
111 // Launch network task 106 // Launch network task
112 unwrap!(spawner.spawn(net_task(&stack))); 107 unwrap!(spawner.spawn(net_task(&stack)));
diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs
index bc2b7edd4..83d7eca85 100644
--- a/tests/stm32/src/bin/fdcan.rs
+++ b/tests/stm32/src/bin/fdcan.rs
@@ -102,10 +102,10 @@ fn options() -> (Config, TestOptions) {
102 102
103#[embassy_executor::main] 103#[embassy_executor::main]
104async fn main(_spawner: Spawner) { 104async fn main(_spawner: Spawner) {
105 //let peripherals = embassy_stm32::init(config()); 105 //let peripherals = init();
106 106
107 let (config, options) = options(); 107 let (config, options) = options();
108 let peripherals = embassy_stm32::init(config); 108 let peripherals = init_with_config(config);
109 109
110 let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1); 110 let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1);
111 let mut can2 = can::CanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2); 111 let mut can2 = can::CanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2);
diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs
index 1d1018c5c..4a2584b4e 100644
--- a/tests/stm32/src/bin/gpio.rs
+++ b/tests/stm32/src/bin/gpio.rs
@@ -10,7 +10,7 @@ use embassy_stm32::gpio::{Flex, Input, Level, Output, OutputOpenDrain, Pull, Spe
10 10
11#[embassy_executor::main] 11#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 12async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(config()); 13 let p = init();
14 info!("Hello World!"); 14 info!("Hello World!");
15 15
16 // Arduino pins D0 and D1 16 // Arduino pins D0 and D1
diff --git a/tests/stm32/src/bin/hash.rs b/tests/stm32/src/bin/hash.rs
index 5f54ea435..bdb3c9a69 100644
--- a/tests/stm32/src/bin/hash.rs
+++ b/tests/stm32/src/bin/hash.rs
@@ -35,7 +35,7 @@ bind_interrupts!(struct Irqs {
35 35
36#[embassy_executor::main] 36#[embassy_executor::main]
37async fn main(_spawner: Spawner) { 37async fn main(_spawner: Spawner) {
38 let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); 38 let p: embassy_stm32::Peripherals = init();
39 let mut hw_hasher = Hash::new(p.HASH, NoDma, Irqs); 39 let mut hw_hasher = Hash::new(p.HASH, NoDma, Irqs);
40 40
41 let test_1: &[u8] = b"as;dfhaslfhas;oifvnasd;nifvnhasd;nifvhndlkfghsd;nvfnahssdfgsdafgsasdfasdfasdfasdfasdfghjklmnbvcalskdjghalskdjgfbaslkdjfgbalskdjgbalskdjbdfhsdfhsfghsfghfgh"; 41 let test_1: &[u8] = b"as;dfhaslfhas;oifvnasd;nifvnhasd;nifvhndlkfghsd;nvfnahssdfgsdafgsasdfasdfasdfasdfasdfghjklmnbvcalskdjghalskdjgfbaslkdjfgbalskdjgbalskdjbdfhsdfhsfghsfghfgh";
diff --git a/tests/stm32/src/bin/rng.rs b/tests/stm32/src/bin/rng.rs
index 15ef4fb60..8438353a8 100644
--- a/tests/stm32/src/bin/rng.rs
+++ b/tests/stm32/src/bin/rng.rs
@@ -41,7 +41,7 @@ bind_interrupts!(struct Irqs {
41 41
42#[embassy_executor::main] 42#[embassy_executor::main]
43async fn main(_spawner: Spawner) { 43async fn main(_spawner: Spawner) {
44 let p: embassy_stm32::Peripherals = embassy_stm32::init(config()); 44 let p: embassy_stm32::Peripherals = init();
45 45
46 let mut rng = Rng::new(p.RNG, Irqs); 46 let mut rng = Rng::new(p.RNG, Irqs);
47 47
diff --git a/tests/stm32/src/bin/rtc.rs b/tests/stm32/src/bin/rtc.rs
index c04d616ac..5fe98d807 100644
--- a/tests/stm32/src/bin/rtc.rs
+++ b/tests/stm32/src/bin/rtc.rs
@@ -18,7 +18,7 @@ async fn main(_spawner: Spawner) {
18 let mut config = config(); 18 let mut config = config();
19 config.rcc.ls = LsConfig::default_lse(); 19 config.rcc.ls = LsConfig::default_lse();
20 20
21 let p = embassy_stm32::init(config); 21 let p = init_with_config(config);
22 info!("Hello World!"); 22 info!("Hello World!");
23 23
24 let now = NaiveDate::from_ymd_opt(2020, 5, 15) 24 let now = NaiveDate::from_ymd_opt(2020, 5, 15)
diff --git a/tests/stm32/src/bin/sdmmc.rs b/tests/stm32/src/bin/sdmmc.rs
index 54f55d2d6..a6bc117c0 100644
--- a/tests/stm32/src/bin/sdmmc.rs
+++ b/tests/stm32/src/bin/sdmmc.rs
@@ -20,7 +20,7 @@ bind_interrupts!(struct Irqs {
20async fn main(_spawner: Spawner) { 20async fn main(_spawner: Spawner) {
21 info!("Hello World!"); 21 info!("Hello World!");
22 22
23 let p = embassy_stm32::init(config()); 23 let p = init();
24 24
25 let (mut sdmmc, mut dma, mut clk, mut cmd, mut d0, mut d1, mut d2, mut d3) = 25 let (mut sdmmc, mut dma, mut clk, mut cmd, mut d0, mut d1, mut d2, mut d3) =
26 (p.SDIO, p.DMA2_CH3, p.PC12, p.PD2, p.PC8, p.PC9, p.PC10, p.PC11); 26 (p.SDIO, p.DMA2_CH3, p.PC12, p.PD2, p.PC8, p.PC9, p.PC10, p.PC11);
diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs
index 0ffd0f653..53d44a94a 100644
--- a/tests/stm32/src/bin/spi.rs
+++ b/tests/stm32/src/bin/spi.rs
@@ -12,7 +12,7 @@ use embassy_stm32::time::Hertz;
12 12
13#[embassy_executor::main] 13#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
15 let p = embassy_stm32::init(config()); 15 let p = init();
16 info!("Hello World!"); 16 info!("Hello World!");
17 17
18 let mut spi_peri = peri!(p, SPI); 18 let mut spi_peri = peri!(p, SPI);
diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs
index fd26d3f71..a1cbc0ed1 100644
--- a/tests/stm32/src/bin/spi_dma.rs
+++ b/tests/stm32/src/bin/spi_dma.rs
@@ -12,7 +12,7 @@ use embassy_stm32::time::Hertz;
12 12
13#[embassy_executor::main] 13#[embassy_executor::main]
14async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
15 let p = embassy_stm32::init(config()); 15 let p = init();
16 info!("Hello World!"); 16 info!("Hello World!");
17 17
18 let mut spi_peri = peri!(p, SPI); 18 let mut spi_peri = peri!(p, SPI);
diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs
index c1106bb2f..772bc527c 100644
--- a/tests/stm32/src/bin/stop.rs
+++ b/tests/stm32/src/bin/stop.rs
@@ -58,7 +58,7 @@ async fn async_main(spawner: Spawner) {
58 config.rcc.hsi = Some(HSIPrescaler::DIV4); // 64 MHz HSI will need a /4 58 config.rcc.hsi = Some(HSIPrescaler::DIV4); // 64 MHz HSI will need a /4
59 } 59 }
60 60
61 let p = embassy_stm32::init(config); 61 let p = init_with_config(config);
62 info!("Hello World!"); 62 info!("Hello World!");
63 63
64 let now = NaiveDate::from_ymd_opt(2020, 5, 15) 64 let now = NaiveDate::from_ymd_opt(2020, 5, 15)
diff --git a/tests/stm32/src/bin/timer.rs b/tests/stm32/src/bin/timer.rs
index d86f54ad2..8719e7670 100644
--- a/tests/stm32/src/bin/timer.rs
+++ b/tests/stm32/src/bin/timer.rs
@@ -10,7 +10,7 @@ use embassy_time::{Instant, Timer};
10 10
11#[embassy_executor::main] 11#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 12async fn main(_spawner: Spawner) {
13 let _p = embassy_stm32::init(config()); 13 let _p = init();
14 info!("Hello World!"); 14 info!("Hello World!");
15 15
16 let start = Instant::now(); 16 let start = Instant::now();
diff --git a/tests/stm32/src/bin/ucpd.rs b/tests/stm32/src/bin/ucpd.rs
index c09334ec8..bd7b35d6b 100644
--- a/tests/stm32/src/bin/ucpd.rs
+++ b/tests/stm32/src/bin/ucpd.rs
@@ -102,12 +102,12 @@ async fn sink(
102 102
103#[embassy_executor::main] 103#[embassy_executor::main]
104async fn main(_spawner: Spawner) { 104async fn main(_spawner: Spawner) {
105 let p = embassy_stm32::init(config()); 105 let p = init();
106 info!("Hello World!"); 106 info!("Hello World!");
107 107
108 // Wire between PD0 and PA8 108 // Wire between PD0 and PA8
109 let ucpd1 = Ucpd::new(p.UCPD1, Irqs {}, p.PA8, p.PB15); 109 let ucpd1 = Ucpd::new(p.UCPD1, Irqs {}, p.PA8, p.PB15, Default::default());
110 let ucpd2 = Ucpd::new(p.UCPD2, Irqs {}, p.PD0, p.PD2); 110 let ucpd2 = Ucpd::new(p.UCPD2, Irqs {}, p.PD0, p.PD2, Default::default());
111 111
112 join( 112 join(
113 source(ucpd1, p.DMA1_CH1, p.DMA1_CH2), 113 source(ucpd1, p.DMA1_CH1, p.DMA1_CH2),
diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs
index a6e34674d..53da30fff 100644
--- a/tests/stm32/src/bin/usart.rs
+++ b/tests/stm32/src/bin/usart.rs
@@ -11,7 +11,7 @@ use embassy_time::{block_for, Duration, Instant};
11 11
12#[embassy_executor::main] 12#[embassy_executor::main]
13async fn main(_spawner: Spawner) { 13async fn main(_spawner: Spawner) {
14 let p = embassy_stm32::init(config()); 14 let p = init();
15 info!("Hello World!"); 15 info!("Hello World!");
16 16
17 // Arduino pins D0 and D1 17 // Arduino pins D0 and D1
diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs
index 24e2b2896..266b81809 100644
--- a/tests/stm32/src/bin/usart_dma.rs
+++ b/tests/stm32/src/bin/usart_dma.rs
@@ -11,7 +11,7 @@ use embassy_stm32::usart::{Config, Uart};
11 11
12#[embassy_executor::main] 12#[embassy_executor::main]
13async fn main(_spawner: Spawner) { 13async fn main(_spawner: Spawner) {
14 let p = embassy_stm32::init(config()); 14 let p = init();
15 info!("Hello World!"); 15 info!("Hello World!");
16 16
17 // Arduino pins D0 and D1 17 // Arduino pins D0 and D1
diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs
index ea1e52358..98c7ef312 100644
--- a/tests/stm32/src/bin/usart_rx_ringbuffered.rs
+++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs
@@ -18,7 +18,7 @@ const DMA_BUF_SIZE: usize = 256;
18 18
19#[embassy_executor::main] 19#[embassy_executor::main]
20async fn main(spawner: Spawner) { 20async fn main(spawner: Spawner) {
21 let p = embassy_stm32::init(config()); 21 let p = init();
22 info!("Hello World!"); 22 info!("Hello World!");
23 23
24 // Arduino pins D0 and D1 24 // Arduino pins D0 and D1
diff --git a/tests/stm32/src/bin/wpan_ble.rs b/tests/stm32/src/bin/wpan_ble.rs
index 82a540d45..fde1dfa9b 100644
--- a/tests/stm32/src/bin/wpan_ble.rs
+++ b/tests/stm32/src/bin/wpan_ble.rs
@@ -41,7 +41,7 @@ async fn main(spawner: Spawner) {
41 let mut config = config(); 41 let mut config = config();
42 config.rcc = WPAN_DEFAULT; 42 config.rcc = WPAN_DEFAULT;
43 43
44 let p = embassy_stm32::init(config); 44 let p = init_with_config(config);
45 info!("Hello World!"); 45 info!("Hello World!");
46 46
47 let config = Config::default(); 47 let config = Config::default();
diff --git a/tests/stm32/src/bin/wpan_mac.rs b/tests/stm32/src/bin/wpan_mac.rs
index fe53b8786..b65ace40f 100644
--- a/tests/stm32/src/bin/wpan_mac.rs
+++ b/tests/stm32/src/bin/wpan_mac.rs
@@ -34,7 +34,7 @@ async fn main(spawner: Spawner) {
34 let mut config = config(); 34 let mut config = config();
35 config.rcc = WPAN_DEFAULT; 35 config.rcc = WPAN_DEFAULT;
36 36
37 let p = embassy_stm32::init(config); 37 let p = init_with_config(config);
38 info!("Hello World!"); 38 info!("Hello World!");
39 39
40 let config = Config::default(); 40 let config = Config::default();
diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs
index 4e0231858..935a41ed2 100644
--- a/tests/stm32/src/common.rs
+++ b/tests/stm32/src/common.rs
@@ -699,3 +699,21 @@ pub fn config() -> Config {
699 699
700 config 700 config
701} 701}
702
703#[allow(unused)]
704pub fn init() -> embassy_stm32::Peripherals {
705 init_with_config(config())
706}
707
708#[allow(unused)]
709pub fn init_with_config(config: Config) -> embassy_stm32::Peripherals {
710 #[cfg(any(feature = "stm32wl55jc", feature = "stm32h755zi"))]
711 {
712 // Not in shared memory, but we're not running the second core, so it's fine
713 static SHARED_DATA: core::mem::MaybeUninit<embassy_stm32::SharedData> = core::mem::MaybeUninit::uninit();
714 embassy_stm32::init_primary(config, &SHARED_DATA)
715 }
716
717 #[cfg(not(any(feature = "stm32wl55jc", feature = "stm32h755zi")))]
718 embassy_stm32::init(config)
719}